diff --git a/src/client.c b/src/client.c index ef043c189abcee1743951973f72ba19bcca57d8e..ed0cbad785028d223a4fde9f8a83972208d54857 100644 --- a/src/client.c +++ b/src/client.c @@ -2597,12 +2597,10 @@ clientActivate (Client *c, guint32 timestamp, gboolean source_is_application) workspaceSwitch (screen_info, c->win_workspace, NULL, FALSE, timestamp); } } + clientShow (ancestor, TRUE); - if (c != ancestor || !screen_info->params->click_to_focus) - { - clientRaise (ancestor, None); - clientSetLastRaise (c); - } + clientRaise (c, None); + if (!source_is_application || screen_info->params->click_to_focus || (c->type & WINDOW_TYPE_DONT_FOCUS)) { /* diff --git a/src/stacking.c b/src/stacking.c index 2239ac734fcbd23d9e6d55ae0481133291001cdb..185127ad69145e6f83e98fb884c814eb55f4caba 100644 --- a/src/stacking.c +++ b/src/stacking.c @@ -164,7 +164,7 @@ gboolean clientIsTopMost (Client *c) { ScreenInfo *screen_info; - GList *list, *list2; + GList *list, *l2; Client *c2; g_return_val_if_fail (c != NULL, FALSE); @@ -176,15 +176,15 @@ clientIsTopMost (Client *c) list = g_list_find (screen_info->windows_stack, (gconstpointer) c); if (list) { - list2 = g_list_next (list); - while (list2) + l2 = g_list_next (list); + while (l2) { - c2 = (Client *) list2->data; + c2 = (Client *) l2->data; if (FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_VISIBLE) && (c2->win_layer == c->win_layer)) { return FALSE; } - list2 = g_list_next (list2); + l2 = g_list_next (l2); } } return TRUE; @@ -279,163 +279,179 @@ clientAtPosition (ScreenInfo *screen_info, int x, int y, GList * exclude_list) return c; } -void -clientRaise (Client * c, Window wsibling) +static void +clientRaiseInternal (Client * c, Client * client_sibling) { ScreenInfo *screen_info; - DisplayInfo *display_info; - Client *c2, *c3, *client_sibling; + Client *c2, *c3; + GList *l1, *l2; GList *transients; - GList *sibling; - GList *list1, *list2; GList *windows_stack_copy; - - g_return_if_fail (c != NULL); - - TRACE ("client \"%s\" (0x%lx) above (0x%lx)", c->name, c->window, wsibling); + GList *sibling; screen_info = c->screen_info; - display_info = screen_info->display_info; - client_sibling = NULL; transients = NULL; + + /* Copy the existing window stack temporarily as reference */ + windows_stack_copy = g_list_copy (screen_info->windows_stack); + screen_info->windows_stack = g_list_remove (screen_info->windows_stack, (gconstpointer) c); sibling = NULL; - if (c == screen_info->last_raise) + if (client_sibling) { - TRACE ("client \"%s\" (0x%lx) already raised", c->name, c->window); - return; + /* If there is one, look for its place in the list */ + sibling = g_list_find (screen_info->windows_stack, (gconstpointer) client_sibling); + /* Place the raised window just before it */ + screen_info->windows_stack = g_list_insert_before (screen_info->windows_stack, sibling, c); } - - /* - * If the raised window is the one that has focus, fine, we can - * release the grab we have on it since there is no use for it - * anymore. - * - * However, if the raised window is not the focused one, then we - * end up with some kind of indermination, so we need to regrab - * the buttons for the user to be able to raise or focus the window - * by clicking inside. - */ - - if (g_list_length (screen_info->windows_stack) < 1) + else { - return; + /* There will be no window on top of the raised window, so place it at the end of list */ + screen_info->windows_stack = g_list_append (screen_info->windows_stack, c); } - - if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MANAGED)) + /* Now, look for transients, transients of transients, etc. */ + for (l1 = windows_stack_copy; l1; l1 = g_list_next (l1)) { - /* Copy the existing window stack temporarily as reference */ - windows_stack_copy = g_list_copy (screen_info->windows_stack); - /* Search for the window that will be just on top of the raised window */ - if (wsibling) + c2 = (Client *) l1->data; + if (c2) { - c2 = myDisplayGetClientFromWindow (display_info, wsibling, SEARCH_FRAME | SEARCH_WINDOW); - if (c2) + if ((c2 != c) && clientIsTransientOrModalFor (c2, c) && (c2->win_layer <= c->win_layer)) { - sibling = g_list_find (screen_info->windows_stack, (gconstpointer) c2); + transients = g_list_append (transients, c2); if (sibling) { - list1 = g_list_next (sibling); - if (list1) + /* Make sure client_sibling is not c2 otherwise we create a circular linked list */ + if (client_sibling != c2) { - client_sibling = (Client *) list1->data; - /* Do not place window under higher layers though */ - if ((client_sibling) && (client_sibling->win_layer < c->win_layer)) - { - client_sibling = NULL; - } - } - } - } - } - if (!client_sibling) - { - client_sibling = clientGetNextTopMost (screen_info, c->win_layer, c); - } - screen_info->windows_stack = g_list_remove (screen_info->windows_stack, (gconstpointer) c); - if (client_sibling) - { - /* If there is one, look for its place in the list */ - sibling = g_list_find (screen_info->windows_stack, (gconstpointer) client_sibling); - /* Place the raised window just before it */ - screen_info->windows_stack = g_list_insert_before (screen_info->windows_stack, sibling, c); - } - else - { - /* There will be no window on top of the raised window, so place it at the end of list */ - screen_info->windows_stack = g_list_append (screen_info->windows_stack, c); - } - /* Now, look for transients, transients of transients, etc. */ - for (list1 = windows_stack_copy; list1; list1 = g_list_next (list1)) - { - c2 = (Client *) list1->data; - if (c2) - { - if ((c2 != c) && clientIsTransientOrModalFor (c2, c) && (c2->win_layer <= c->win_layer)) - { - transients = g_list_append (transients, c2); - if (sibling) - { - /* Make sure client_sibling is not c2 otherwise we create a circular linked list */ - if (client_sibling != c2) - { - /* Place the transient window just before sibling */ - screen_info->windows_stack = g_list_remove (screen_info->windows_stack, (gconstpointer) c2); - screen_info->windows_stack = g_list_insert_before (screen_info->windows_stack, sibling, c2); - } - } - else - { - /* There will be no window on top of the transient window, so place it at the end of list */ + /* Place the transient window just before sibling */ screen_info->windows_stack = g_list_remove (screen_info->windows_stack, (gconstpointer) c2); - screen_info->windows_stack = g_list_append (screen_info->windows_stack, c2); + screen_info->windows_stack = g_list_insert_before (screen_info->windows_stack, sibling, c2); } } else { - for (list2 = transients; list2; list2 = g_list_next (list2)) + /* There will be no window on top of the transient window, so place it at the end of list */ + screen_info->windows_stack = g_list_remove (screen_info->windows_stack, (gconstpointer) c2); + screen_info->windows_stack = g_list_append (screen_info->windows_stack, c2); + } + } + else + { + for (l2 = transients; l2; l2 = g_list_next (l2)) + { + c3 = (Client *) l2->data; + if ((c3 != c2) && clientIsTransientOrModalFor (c2, c3)) { - c3 = (Client *) list2->data; - if ((c3 != c2) && clientIsTransientOrModalFor (c2, c3)) + transients = g_list_append (transients, c2); + if (sibling) { - transients = g_list_append (transients, c2); - if (sibling) - { - /* Again, make sure client_sibling is not c2 to avoid a circular linked list */ - if (client_sibling != c2) - { - /* Place the transient window just before sibling */ - screen_info->windows_stack = g_list_remove (screen_info->windows_stack, (gconstpointer) c2); - screen_info->windows_stack = g_list_insert_before (screen_info->windows_stack, sibling, c2); - } - } - else + /* Again, make sure client_sibling is not c2 to avoid a circular linked list */ + if (client_sibling != c2) { - /* There will be no window on top of the transient window, so place it at the end of list */ + /* Place the transient window just before sibling */ screen_info->windows_stack = g_list_remove (screen_info->windows_stack, (gconstpointer) c2); - screen_info->windows_stack = g_list_append (screen_info->windows_stack, c2); + screen_info->windows_stack = g_list_insert_before (screen_info->windows_stack, sibling, c2); } - break; } + else + { + /* There will be no window on top of the transient window, so place it at the end of list */ + screen_info->windows_stack = g_list_remove (screen_info->windows_stack, (gconstpointer) c2); + screen_info->windows_stack = g_list_append (screen_info->windows_stack, c2); + } + break; } } } } - if (transients) - { - g_list_free (transients); - } - if (windows_stack_copy) + } + + if (transients) + { + g_list_free (transients); + } + + if (windows_stack_copy) + { + g_list_free (windows_stack_copy); + } +} + +void +clientRaise (Client * c, Window wsibling) +{ + ScreenInfo *screen_info; + DisplayInfo *display_info; + Client *ancestor; + Client *client_sibling; + Client *c2; + GList *sibling; + GList *above_sibling; + + g_return_if_fail (c != NULL); + + TRACE ("client \"%s\" (0x%lx) above (0x%lx)", c->name, c->window, wsibling); + + if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MANAGED)) + { + return; + } + + screen_info = c->screen_info; + display_info = screen_info->display_info; + + if (c == screen_info->last_raise) + { + TRACE ("client \"%s\" (0x%lx) already raised", c->name, c->window); + return; + } + + if (g_list_length (screen_info->windows_stack) < 2) + { + return; + } + + /* Search for the window that will be just on top of the raised window */ + if (wsibling) + { + c2 = myDisplayGetClientFromWindow (display_info, wsibling, SEARCH_FRAME | SEARCH_WINDOW); + if (c2) { - g_list_free (windows_stack_copy); + sibling = g_list_find (screen_info->windows_stack, (gconstpointer) c2); + if (sibling) + { + above_sibling = g_list_next (sibling); + if (above_sibling) + { + client_sibling = (Client *) above_sibling->data; + /* Do not place window under higher layers though */ + if ((client_sibling) && (client_sibling->win_layer < c->win_layer)) + { + client_sibling = NULL; + } + } + } } - /* Now, screen_info->windows_stack contains the correct window stack - We still need to tell the X Server to reflect the changes - */ - clientApplyStackList (screen_info); - clientSetNetClientList (c->screen_info, display_info->atoms[NET_CLIENT_LIST_STACKING], screen_info->windows_stack); - screen_info->last_raise = c; } + + if (!client_sibling) + { + client_sibling = clientGetNextTopMost (screen_info, c->win_layer, c); + } + + ancestor = clientGetTransientFor(c); + clientRaiseInternal (ancestor, client_sibling); + if (ancestor != c) + { + clientRaiseInternal (c, client_sibling); + } + + /* Now, screen_info->windows_stack contains the correct window stack + We still need to tell the X Server to reflect the changes + */ + clientApplyStackList (screen_info); + clientSetNetClientList (screen_info, display_info->atoms[NET_CLIENT_LIST_STACKING], screen_info->windows_stack); + screen_info->last_raise = c; } void @@ -452,82 +468,87 @@ clientLower (Client * c, Window wsibling) TRACE ("client \"%s\" (0x%lx) below (0x%lx)", c->name, c->window, wsibling); + if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MANAGED)) + { + return; + } + screen_info = c->screen_info; display_info = screen_info->display_info; client_sibling = NULL; sibling = NULL; c2 = NULL; - if (g_list_length (screen_info->windows_stack) < 1) + if (g_list_length (screen_info->windows_stack) < 2) { return; } - if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MANAGED)) + if (clientIsTransientOrModalForGroup (c)) { - if (clientIsTransientOrModalForGroup (c)) - { - client_sibling = clientGetTopMostForGroup (c); - } - else if (clientIsTransient (c)) - { - client_sibling = clientGetTransient (c); - } - else if (wsibling) + client_sibling = clientGetTopMostForGroup (c); + } + else if (clientIsTransient (c)) + { + client_sibling = clientGetTransient (c); + } + else if (wsibling) + { + c2 = myDisplayGetClientFromWindow (display_info, wsibling, SEARCH_FRAME | SEARCH_WINDOW); + if (c2) { - c2 = myDisplayGetClientFromWindow (display_info, wsibling, SEARCH_FRAME | SEARCH_WINDOW); - if (c2) + sibling = g_list_find (screen_info->windows_stack, (gconstpointer) c2); + if (sibling) { - sibling = g_list_find (screen_info->windows_stack, (gconstpointer) c2); - if (sibling) + list = g_list_previous (sibling); + if (list) { - list = g_list_previous (sibling); - if (list) + client_sibling = (Client *) list->data; + /* Do not place window above lower layers though */ + if ((client_sibling) && (client_sibling->win_layer > c->win_layer)) { - client_sibling = (Client *) list->data; - /* Do not place window above lower layers though */ - if ((client_sibling) && (client_sibling->win_layer > c->win_layer)) - { - client_sibling = NULL; - } + client_sibling = NULL; } } } } - if ((!client_sibling) || - (client_sibling && (client_sibling->win_layer < c->win_layer))) - { - client_sibling = clientGetBottomMost (screen_info, c->win_layer, c); - } - if (client_sibling != c) + } + + if ((!client_sibling) || + (client_sibling && (client_sibling->win_layer < c->win_layer))) + { + client_sibling = clientGetBottomMost (screen_info, c->win_layer, c); + } + + if (client_sibling != c) + { + screen_info->windows_stack = g_list_remove (screen_info->windows_stack, (gconstpointer) c); + /* Paranoid check to avoid circular linked list */ + if (client_sibling) { - screen_info->windows_stack = g_list_remove (screen_info->windows_stack, (gconstpointer) c); - /* Paranoid check to avoid circular linked list */ - if (client_sibling) - { - sibling = g_list_find (screen_info->windows_stack, (gconstpointer) client_sibling); - position = g_list_position (screen_info->windows_stack, sibling) + 1; + sibling = g_list_find (screen_info->windows_stack, (gconstpointer) client_sibling); + position = g_list_position (screen_info->windows_stack, sibling) + 1; - screen_info->windows_stack = g_list_insert (screen_info->windows_stack, c, position); - TRACE ("lowest client is \"%s\" (0x%lx) at position %i", - client_sibling->name, client_sibling->window, position); - } - else - { - screen_info->windows_stack = g_list_prepend (screen_info->windows_stack, c); - } + screen_info->windows_stack = g_list_insert (screen_info->windows_stack, c, position); + TRACE ("lowest client is \"%s\" (0x%lx) at position %i", + client_sibling->name, client_sibling->window, position); } - /* Now, screen_info->windows_stack contains the correct window stack - We still need to tell the X Server to reflect the changes - */ - clientApplyStackList (screen_info); - clientSetNetClientList (screen_info, display_info->atoms[NET_CLIENT_LIST_STACKING], screen_info->windows_stack); - clientPassFocus (screen_info, c, NULL); - if (screen_info->last_raise == c) + else { - screen_info->last_raise = NULL; + screen_info->windows_stack = g_list_prepend (screen_info->windows_stack, c); } } + + /* Now, screen_info->windows_stack contains the correct window stack + We still need to tell the X Server to reflect the changes + */ + clientApplyStackList (screen_info); + clientSetNetClientList (screen_info, display_info->atoms[NET_CLIENT_LIST_STACKING], screen_info->windows_stack); + clientPassFocus (screen_info, c, NULL); + if (screen_info->last_raise == c) + { + screen_info->last_raise = NULL; + } } gboolean diff --git a/src/transients.c b/src/transients.c index 5e1844eb6022249c7412a3609029bf82fbde7391..48cd7c297b02a3eb0e5ded2939497f0b9c983b53 100644 --- a/src/transients.c +++ b/src/transients.c @@ -315,36 +315,52 @@ clientGetModalFor (Client * c) return NULL; } +/* Find the deepest parent of that window */ Client * clientGetTransientFor (Client * c) { ScreenInfo *screen_info; - Client *latest_transient; + Client *first_parent; Client *c2; - GList *list; + GList *l1, *l2; + GList *parents; g_return_val_if_fail (c != NULL, NULL); TRACE ("client \"%s\" (0x%lx)", c->name, c->window); - latest_transient = c; + first_parent = c; + parents = g_list_append (NULL, c); + screen_info = c->screen_info; - for (list = g_list_last(screen_info->windows_stack); list; list = g_list_previous (list)) + for (l1 = g_list_last(screen_info->windows_stack); l1; l1 = g_list_previous (l1)) { - if (!clientIsTransient (latest_transient)) + Client *c2 = (Client *) l1->data; + if (c2 == c) { - break; + continue; } - c2 = (Client *) list->data; - if (c2) + + if (clientIsTransientFor (c, c2)) { - if (clientIsTransientFor (latest_transient, c2)) + parents = g_list_append (parents, c2); + first_parent = c2; + } + else + { + for (l2 = parents; l2; l2 = g_list_next (l2)) { - latest_transient = c2; + Client *c3 = (Client *) l2->data; + if ((c3 != c2) && clientIsTransientFor (c3, c2)) + { + parents = g_list_append (parents, c2); + first_parent = c2; + } } } } + g_list_free (parents); - return latest_transient; + return first_parent; } /* Build a GList of clients that have a transient relationship */ @@ -354,17 +370,17 @@ clientListTransient (Client * c) ScreenInfo *screen_info; Client *c2, *c3; GList *transients; - GList *list1, *list2; + GList *l1, *l2; g_return_val_if_fail (c != NULL, NULL); TRACE ("client \"%s\" (0x%lx)", c->name, c->window); - transients = NULL; + transients = g_list_append (NULL, c); + screen_info = c->screen_info; - transients = g_list_append (transients, c); - for (list1 = screen_info->windows_stack; list1; list1 = g_list_next (list1)) + for (l1 = screen_info->windows_stack; l1; l1 = g_list_next (l1)) { - c2 = (Client *) list1->data; + c2 = (Client *) l1->data; if (c2 != c) { if (clientIsTransientFor (c2, c)) @@ -373,10 +389,9 @@ clientListTransient (Client * c) } else { - for (list2 = transients; list2; - list2 = g_list_next (list2)) + for (l2 = transients; l2; l2 = g_list_next (l2)) { - c3 = (Client *) list2->data; + c3 = (Client *) l2->data; if ((c3 != c2) && clientIsTransientFor (c2, c3)) { transients = g_list_append (transients, c2); @@ -396,17 +411,17 @@ clientListTransientOrModal (Client * c) ScreenInfo *screen_info; Client *c2, *c3; GList *transients; - GList *list1, *list2; + GList *l1, *l2; g_return_val_if_fail (c != NULL, NULL); TRACE ("client \"%s\" (0x%lx)", c->name, c->window); + transients = g_list_append (NULL, c); + screen_info = c->screen_info; - transients = NULL; - transients = g_list_append (transients, c); - for (list1 = screen_info->windows_stack; list1; list1 = g_list_next (list1)) + for (l1 = screen_info->windows_stack; l1; l1 = g_list_next (l1)) { - c2 = (Client *) list1->data; + c2 = (Client *) l1->data; if (c2 != c) { if (clientIsTransientOrModalFor (c2, c)) @@ -415,10 +430,9 @@ clientListTransientOrModal (Client * c) } else { - for (list2 = transients; list2; - list2 = g_list_next (list2)) + for (l2 = transients; l2; l2 = g_list_next (l2)) { - c3 = (Client *) list2->data; + c3 = (Client *) l2->data; if ((c3 != c2) && clientIsTransientOrModalFor (c2, c3)) { transients = g_list_append (transients, c2);