Skip to content

Instantly share code, notes, and snippets.

@woodensquares
Last active January 29, 2019 16:38
Show Gist options
  • Save woodensquares/9b5c7d3e186c5d49540f29c81d688e1e to your computer and use it in GitHub Desktop.
Save woodensquares/9b5c7d3e186c5d49540f29c81d688e1e to your computer and use it in GitHub Desktop.
diff --git a/include/xcb.h b/include/xcb.h
index b7eed2c..c51adf4 100644
--- a/include/xcb.h
+++ b/include/xcb.h
@@ -51,6 +51,7 @@
ConfigureNotify */ \
XCB_EVENT_MASK_POINTER_MOTION | \
XCB_EVENT_MASK_PROPERTY_CHANGE | \
+ XCB_EVENT_MASK_LEAVE_WINDOW | \
XCB_EVENT_MASK_ENTER_WINDOW)
#define xmacro(atom) xcb_atom_t A_##atom;
diff --git a/src/handlers.c b/src/handlers.c
index 2991d7c..07e2a7a 100644
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -22,6 +22,7 @@
int randr_base = -1;
int xkb_base = -1;
int xkb_current_group;
+extern uint8_t previous_screen;
/* After mapping/unmapping windows, a notify event is generated. However, we don’t want it,
since it’d trigger an infinite loop of switching between the different windows when
@@ -122,13 +123,28 @@ static void check_crossing_screen_boundary(uint32_t x, uint32_t y) {
* When the user moves the mouse pointer onto a window, this callback gets called.
*
*/
+static void handle_leave_notify(xcb_enter_notify_event_t *event) {
+ DLOG("leave_notify for %08x, mode = %d, detail %d, serial %d, focus %d\n",
+ event->event, event->mode, event->detail, event->sequence,
+ event->same_screen_focus);
+
+ if (event->mode != XCB_NOTIFY_MODE_NORMAL) {
+ DLOG("This was not a normal notify, ignoring\n");
+ return;
+ }
+
+ /* When leaving we don't care about the previous value */
+ previous_screen = event->same_screen_focus;
+ return;
+}
+
static void handle_enter_notify(xcb_enter_notify_event_t *event) {
Con *con;
-
last_timestamp = event->time;
- DLOG("enter_notify for %08x, mode = %d, detail %d, serial %d\n",
- event->event, event->mode, event->detail, event->sequence);
+ DLOG("enter_notify for %08x, mode = %d, detail %d, serial %d, focus %d\n",
+ event->event, event->mode, event->detail, event->sequence,
+ event->same_screen_focus);
DLOG("coordinates %d, %d\n", event->event_x, event->event_y);
if (event->mode != XCB_NOTIFY_MODE_NORMAL) {
DLOG("This was not a normal notify, ignoring\n");
@@ -141,6 +157,18 @@ static void handle_enter_notify(xcb_enter_notify_event_t *event) {
return;
}
+ bool refresh = false;
+ if (event->same_screen_focus != previous_screen) {
+ /* Note we should not skip on previous_screen being
+ * UINT8_MAX because we don't want the first display
+ * switch to be missed (say we have i3 on :0.0 and :0.1,
+ * the :0.1 i3 will not get an event in general until
+ * the first time the user tries to use it, since the
+ * mouse pointer is likely on :0.0 to start with */
+ DLOG("The user changed screens\n");
+ refresh = true;
+ }
+
bool enter_child = false;
/* Get container by frame or by child window */
if ((con = con_by_frame_id(event->event)) == NULL) {
@@ -152,6 +180,15 @@ static void handle_enter_notify(xcb_enter_notify_event_t *event) {
if (con == NULL) {
DLOG("Getting screen at %d x %d\n", event->root_x, event->root_y);
check_crossing_screen_boundary(event->root_x, event->root_y);
+
+ if (refresh && ! config.disable_focus_follows_mouse) {
+ /* The user entered the root window coming from another X
+ * screen, this means that the above will not have called
+ * tree_render (leaving the keyboard focus on the other
+ * screen) let's focus a rerender.
+ */
+ tree_render();
+ }
return;
}
@@ -185,20 +222,24 @@ static void handle_enter_notify(xcb_enter_notify_event_t *event) {
if (config.disable_focus_follows_mouse)
return;
- /* if this container is already focused, there is nothing to do. */
- if (con == focused)
+ /* if this container is already focused, there is nothing to do
+ * unless we have switched screens.
+ */
+ if (con == focused && !refresh)
return;
- /* Get the currently focused workspace to check if the focus change also
- * involves changing workspaces. If so, we need to call workspace_show() to
- * correctly update state and send the IPC event. */
+ /* Get the currently focused workspace to check if the focus change
+ * also involves changing workspaces. If so, or if we switched
+ * screens, we need to call workspace_show() to correctly update
+ * state and send the IPC event. */
Con *ws = con_get_workspace(con);
- if (ws != con_get_workspace(focused))
+ if (ws != con_get_workspace(focused) || refresh)
workspace_show(ws);
focused_id = XCB_NONE;
con_focus(con_descend_focused(con));
tree_render();
+ previous_screen = event->same_screen_focus;
return;
}
@@ -1454,6 +1495,10 @@ void handle_event(int type, xcb_generic_event_t *event) {
handle_enter_notify((xcb_enter_notify_event_t *)event);
break;
+ case XCB_LEAVE_NOTIFY:
+ handle_leave_notify((xcb_enter_notify_event_t *)event);
+ break;
+
/* Client message are sent to the root window. The only interesting
* client message for us is _NET_WM_STATE, we honour
* _NET_WM_STATE_FULLSCREEN and _NET_WM_STATE_DEMANDS_ATTENTION */
diff --git a/src/main.c b/src/main.c
index b2ce17d..d14567d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -37,6 +37,7 @@ int listen_fds;
static struct ev_check *xcb_check;
extern Con *focused;
+extern uint8_t previous_screen;
char **start_argv;
@@ -474,6 +475,7 @@ int main(int argc, char *argv[]) {
root_screen = xcb_aux_get_screen(conn, conn_screen);
root = root_screen->root;
+ previous_screen = UINT8_MAX;
/* Place requests for the atoms we need as soon as possible */
#define xmacro(atom) \
diff --git a/src/tree.c b/src/tree.c
index e848a6a..9220493 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -13,6 +13,7 @@
struct Con *croot;
struct Con *focused;
+uint8_t previous_screen;
struct all_cons_head all_cons = TAILQ_HEAD_INITIALIZER(all_cons);
@rommac100
Copy link

If you don't mind me asking how do you implement this into i3? I have the same problem of using multiple XScreens and multiple i3 sessions. Thanks.

@rickithadi
Copy link

Having the same problem. Are you having to recompile i3? Using more than one X screen seems to cause i3 to not work properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment