+/*
+ * When the user moves the mouse but does not change the active window
+ * (e.g. when having no windows opened but moving mouse on the root screen
+ * and crossing virtual screen boundaries), this callback gets called.
+ *
+ */
+int handle_motion_notify(void *ignored, xcb_connection_t *conn, xcb_motion_notify_event_t *event) {
+ LOG("pointer motion notify, getting screen at %d x %d\n", event->root_x, event->root_y);
+
+ check_crossing_screen_boundary(event->root_x, event->root_y);
+
+ return 1;
+}
+
+/*
+ * Called when the keyboard mapping changes (for example by using Xmodmap),
+ * we need to update our key bindings then (re-translate symbols).
+ *
+ */
+int handle_mapping_notify(void *ignored, xcb_connection_t *conn, xcb_mapping_notify_event_t *event) {
+ LOG("\n\nmapping notify\n\n");
+
+ if (event->request != XCB_MAPPING_KEYBOARD &&
+ event->request != XCB_MAPPING_MODIFIER)
+ return 0;
+
+ xcb_refresh_keyboard_mapping(keysyms, event);
+
+ xcb_get_numlock_mask(conn);
+
+ ungrab_all_keys(conn);
+ LOG("Re-grabbing...\n");
+ grab_all_keys(conn);
+ LOG("Done\n");
+
+ return 0;
+}
+
+/*
+ * Checks if the button press was on a stack window, handles focus setting and returns true
+ * if so, or false otherwise.
+ *
+ */
+static bool button_press_stackwin(xcb_connection_t *conn, xcb_button_press_event_t *event) {
+ struct Stack_Window *stack_win;
+ SLIST_FOREACH(stack_win, &stack_wins, stack_windows) {
+ if (stack_win->window != event->event)
+ continue;
+
+ /* A stack window was clicked, we check if it was button4 or button5
+ which are scroll up / scroll down. */
+ if (event->detail == XCB_BUTTON_INDEX_4 || event->detail == XCB_BUTTON_INDEX_5) {
+ direction_t direction = (event->detail == XCB_BUTTON_INDEX_4 ? D_UP : D_DOWN);
+ focus_window_in_container(conn, CUR_CELL, direction);
+ return true;
+ }
+
+ /* It was no scrolling, so we calculate the destination client by
+ dividing the Y position of the event through the height of a window
+ decoration and then set the focus to this client. */
+ i3Font *font = load_font(conn, config.font);
+ int decoration_height = (font->height + 2 + 2);
+ int destination = (event->event_y / decoration_height),
+ c = 0;
+ Client *client;
+
+ LOG("Click on stack_win for client %d\n", destination);
+ CIRCLEQ_FOREACH(client, &(stack_win->container->clients), clients)
+ if (c++ == destination) {
+ set_focus(conn, client, true);
+ return true;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Checks if the button press was on a bar, switches to the workspace and returns true
+ * if so, or false otherwise.
+ *
+ */
+static bool button_press_bar(xcb_connection_t *conn, xcb_button_press_event_t *event) {
+ i3Screen *screen;
+ TAILQ_FOREACH(screen, virtual_screens, screens) {
+ if (screen->bar != event->event)
+ continue;
+
+ LOG("Click on a bar\n");
+
+ /* Check if the button was one of button4 or button5 (scroll up / scroll down) */
+ if (event->detail == XCB_BUTTON_INDEX_4 || event->detail == XCB_BUTTON_INDEX_5) {
+ int add = (event->detail == XCB_BUTTON_INDEX_4 ? -1 : 1);
+ for (int i = c_ws->num + add; (i >= 0) && (i < 10); i += add)
+ if (workspaces[i].screen == screen) {
+ show_workspace(conn, i+1);
+ return true;
+ }
+ return true;
+ }
+ int drawn = 0;
+ /* Because workspaces can be on different screens, we need to loop
+ through all of them and decide to count it based on its ->screen */
+ for (int i = 0; i < 10; i++) {
+ if (workspaces[i].screen != screen)
+ continue;
+ LOG("Checking if click was on workspace %d with drawn = %d, tw = %d\n",
+ i, drawn, workspaces[i].text_width);
+ if (event->event_x > (drawn + 1) &&
+ event->event_x <= (drawn + 1 + workspaces[i].text_width + 5 + 5)) {
+ show_workspace(conn, i+1);
+ return true;
+ }
+
+ drawn += workspaces[i].text_width + 5 + 5 + 2;
+ }
+ return true;
+ }
+
+ return false;
+}
+