diff --git a/src/client.c b/src/client.c index 33f31ad87c642e0b851171189c67dbfad2714a7b..f385fe4a446671ceb20d85f878e492fe7edafdf6 100644 --- a/src/client.c +++ b/src/client.c @@ -2564,6 +2564,7 @@ void clientFrameAll() Client *new_focus; Window w1, w2, *wins = NULL; XWindowAttributes attr; + XEvent an_event; TRACE("entering clientFrameAll"); @@ -2586,6 +2587,10 @@ void clientFrameAll() clientFrame(wins[i], TRUE); } } + XSync(dpy, FALSE); + /* Just get rid of EnterNotify events caused by reparenting */ + while(XCheckTypedEvent(dpy, EnterNotify, &an_event)) + ; MyXUngrabServer(); if(wins) { @@ -2663,6 +2668,42 @@ Client *clientGetFromWindow(Window w, int mode) return NULL; } +Client *clientAtPosition(int x, int y, Client * exclude) +{ + /* This function does the same as XQueryPointer but w/out the race + conditions caused by querying the X server + */ + GSList *reverse = NULL; + GSList *windows_stack_copy = NULL; + GSList *list_of_windows = NULL; + GSList *index; + Client *c = NULL; + Client *c2 = NULL; + + TRACE("entering clientAtPos"); + + windows_stack_copy = g_slist_copy(windows_stack); + list_of_windows = g_slist_reverse(windows_stack_copy); + for(index = list_of_windows; index; index = g_slist_next(index)) + { + c2 = (Client *) index->data; + if (clientSelectMask(c2, 0) && (c2 != exclude)) + { + if ((frameX(c2) < x) && (frameX(c2) + frameWidth(c2) > x) && (frameY(c2) < y) && (frameY(c2) + frameHeight(c2) > y)) + { + c = c2; + break; + } + } + } + if(windows_stack_copy) + { + g_slist_free(windows_stack_copy); + } + + return c; +} + static inline gboolean clientSelectMask(Client * c, int mask) { gboolean okay = TRUE; @@ -2757,7 +2798,9 @@ void clientPassFocus(Client * c) GSList *list_of_windows = NULL; Client *new_focus = NULL; Client *c2; - unsigned int i; + Window dr, window; + int rx, ry, wx, wy; + unsigned int i, mask; TRACE("entering clientPassFocus"); @@ -2766,16 +2809,23 @@ void clientPassFocus(Client * c) return; } - list_of_windows = clientListTransients(c); - for(c2 = c->next, i = 0; (c2) && (i < client_count); c2 = c2->next, i++) + if (params.click_to_focus) { - if (clientSelectMask(c2, 0) && !g_slist_find(list_of_windows, (gconstpointer) c2)) + list_of_windows = clientListTransients(c); + for(c2 = c->next, i = 0; (c2) && (i < client_count); c2 = c2->next, i++) { - new_focus = c2; - break; + if (clientSelectMask(c2, 0) && !g_slist_find(list_of_windows, (gconstpointer) c2)) + { + new_focus = c2; + break; + } } + g_slist_free(list_of_windows); + } + else if (XQueryPointer(dpy, root, &dr, &window, &rx, &ry, &wx, &wy, &mask)) + { + new_focus = clientAtPosition(rx, ry, c); } - g_slist_free(list_of_windows); if (!new_focus) { new_focus = clientGetTopMostFocusable(c->win_layer, c); diff --git a/src/client.h b/src/client.h index 5edaebade1bfdb7fc412ad57d466b18746f8267d..9991ea5527281965bff80a99bf6ab4acfdf711d6 100644 --- a/src/client.h +++ b/src/client.h @@ -246,6 +246,7 @@ void clientUpdateAllFrames(gboolean); void clientGrabKeys(Client *); void clientUngrabKeys(Client *); Client *clientGetFromWindow(Window, int); +Client *clientAtPosition(int, int, Client *); Client *clientGetNext(Client *, int); void clientPassFocus(Client *); void clientShow(Client *, gboolean); diff --git a/src/workspaces.c b/src/workspaces.c index f5f455b8bc775d8f9fd022c08d3b014e5b583fd0..4757e0bce1e9d9864583430604fe290498a39dca 100644 --- a/src/workspaces.c +++ b/src/workspaces.c @@ -36,10 +36,13 @@ void workspaceSwitch(int new_ws, Client * c2) { - Client *c, *f = NULL; + Client *c, *new_focus = NULL; Client *previous; GSList *list_of_windows; GSList *index; + Window dr, window; + int rx, ry, wx, wy; + unsigned int mask; unsigned long data[1]; XEvent an_event; @@ -66,19 +69,6 @@ void workspaceSwitch(int new_ws, Client * c2) } previous = clientGetFocus(); - if(previous) - { - CLIENT_FLAG_SET(previous, CLIENT_FLAG_FOCUS); - if(CLIENT_FLAG_TEST(previous, CLIENT_FLAG_STICKY) || (previous == c2)) - { - f = previous; - } - else - { - clientSetFocus(c2, FALSE); - } - } - list_of_windows = clientGetStackList(); /* First pass */ for(index = list_of_windows; index; index = g_slist_next(index)) @@ -86,6 +76,11 @@ void workspaceSwitch(int new_ws, Client * c2) c = (Client *) index->data; if(CLIENT_FLAG_TEST_AND_NOT(c, CLIENT_FLAG_VISIBLE, CLIENT_FLAG_STICKY) && !clientIsTransient(c) && ((c->win_workspace != new_ws))) { + if (c == previous) + { + CLIENT_FLAG_SET(previous, CLIENT_FLAG_FOCUS); + clientSetFocus(NULL, FALSE); + } clientHide(c, new_ws, FALSE); } } @@ -98,18 +93,23 @@ void workspaceSwitch(int new_ws, Client * c2) if(CLIENT_FLAG_TEST(c, CLIENT_FLAG_STICKY | CLIENT_FLAG_VISIBLE)) { clientSetWorkspace(c, new_ws, TRUE); + if(c == previous) + { + new_focus = c; + } + CLIENT_FLAG_UNSET(c, CLIENT_FLAG_FOCUS); } - else + else if((c->win_workspace == new_ws) && !CLIENT_FLAG_TEST(c, CLIENT_FLAG_HIDDEN)) { - if((c->win_workspace == new_ws) && !clientIsTransient(c) && !CLIENT_FLAG_TEST(c, CLIENT_FLAG_HIDDEN)) + if (!clientIsTransient(c)) { clientShow(c, FALSE); - if((!f) && CLIENT_FLAG_TEST(c, CLIENT_FLAG_FOCUS)) - { - f = c; - } - CLIENT_FLAG_UNSET(c, CLIENT_FLAG_FOCUS); } + if((!new_focus) && CLIENT_FLAG_TEST(c, CLIENT_FLAG_FOCUS)) + { + new_focus = c; + } + CLIENT_FLAG_UNSET(c, CLIENT_FLAG_FOCUS); } } @@ -123,14 +123,22 @@ void workspaceSwitch(int new_ws, Client * c2) data[0] = new_ws; XChangeProperty(dpy, root, net_current_desktop, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); workspaceUpdateArea(margins, gnome_margins); - /* Just get rid of EnterNotify events when using focus follow mouse */ XSync(dpy, FALSE); - if(!params.click_to_focus) + if(!(params.click_to_focus)) { + /* Just get rid of EnterNotify events when using focus follow mouse */ while(XCheckTypedEvent(dpy, EnterNotify, &an_event)) ; + if (!(c2) && (XQueryPointer(dpy, root, &dr, &window, &rx, &ry, &wx, &wy, &mask))) + { + c = clientAtPosition(rx, ry, NULL); + if (c) + { + new_focus = c; + } + } } - clientSetFocus(f, TRUE); + clientSetFocus(new_focus, TRUE); } void workspaceSetCount(int count)