X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fhandlers.c;h=6e6626a9671f275f7a51141b42857fabfb8ced75;hb=2f992f5c0ed75452a61b19d6c118e5f5f3ba67e9;hp=7dd73acbd7d4925b05d0d4ed97f1089d25fb0dfd;hpb=055bd18142ebab2499d443be17a23b2c9e1df31f;p=i3%2Fi3 diff --git a/src/handlers.c b/src/handlers.c index 7dd73acb..6e6626a9 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -28,30 +28,6 @@ void add_ignore_event(const int sequence) { SLIST_INSERT_HEAD(&ignore_events, event, ignore_events); } -/* - * Unignores the given sequence. Called when unmap events (generated by - * reparenting) should be ignored and the unmap event actually happens, in - * order to not ignore too many unmap events (leading to ghost window - * decorations). - * - */ -static void unignore_event(const int sequence) { - struct Ignore_Event *event; - for (event = SLIST_FIRST(&ignore_events); - event != SLIST_END(&ignore_events); - event = SLIST_NEXT(event, ignore_events)) { - if (event->sequence != sequence) - continue; - - DLOG("Unignoring sequence number %d\n", sequence); - struct Ignore_Event *save = event; - event = SLIST_NEXT(event, ignore_events); - SLIST_REMOVE(&ignore_events, save, Ignore_Event, ignore_events); - free(save); - break; - } -} - /* * Checks if the given sequence is ignored and returns true if so. * @@ -126,8 +102,6 @@ int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_ return 1; } -#if 0 - /* * Called with coordinates of an enter_notify event or motion_notify event * to check if the user crossed virtual screen boundaries and adjust the @@ -135,41 +109,30 @@ int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_ * */ static void check_crossing_screen_boundary(uint32_t x, uint32_t y) { - Output *output; + Output *output; - if ((output = get_output_containing(x, y)) == NULL) { - ELOG("ERROR: No such screen\n"); - return; - } - if (output == c_ws->output) - return; - - c_ws->current_row = current_row; - c_ws->current_col = current_col; - c_ws = output->current_workspace; - current_row = c_ws->current_row; - current_col = c_ws->current_col; - DLOG("We're now on output %p\n", output); - - /* While usually this function is only called when the user switches - * to a different output using his mouse (and thus the output is - * empty), it may be that the following race condition occurs: - * 1) the user actives a new output (say VGA1). - * 2) the cursor is sent to the first pixel of the new VGA1, thus - * generating an enter_notify for the screen (the enter_notify - * is not yet received by i3). - * 3) i3 requeries screen configuration and maps a workspace onto the - * new output. - * 4) the enter_notify event arrives and c_ws is set to the new - * workspace but the existing windows on the new workspace are not - * focused. - * - * Therefore, we re-set the focus here to be sure it’s correct. */ - Client *first_client = SLIST_FIRST(&(c_ws->focus_stack)); - if (first_client != NULL) - set_focus(global_conn, first_client, true); + /* If the user disable focus follows mouse, we have nothing to do here */ + if (config.disable_focus_follows_mouse) + return; + + if ((output = get_output_containing(x, y)) == NULL) { + ELOG("ERROR: No such screen\n"); + return; + } + + if (output->con == NULL) { + ELOG("ERROR: The screen is not recognized by i3 (no container associated)\n"); + return; + } + + /* Focus the output on which the user moved his cursor */ + Con *old_focused = focused; + con_focus(con_descend_focused(output_get_content(output->con))); + + /* If the focus changed, we re-render to get updated decorations */ + if (old_focused != focused) + tree_render(); } -#endif /* * When the user moves the mouse pointer onto a window, this callback gets called. @@ -191,19 +154,27 @@ int handle_enter_notify(void *ignored, xcb_connection_t *conn, if (event_is_ignored(event->sequence)) return 1; + bool enter_child = false; /* Get container by frame or by child window */ - if ((con = con_by_frame_id(event->event)) == NULL) + if ((con = con_by_frame_id(event->event)) == NULL) { con = con_by_window_id(event->event); + enter_child = true; + } /* If not, then the user moved his cursor to the root window. In that case, we adjust c_ws */ 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); + check_crossing_screen_boundary(event->root_x, event->root_y); + return 1; + } + + if (con->parent->type == CT_DOCKAREA) { + DLOG("Ignoring, this is a dock client\n"); return 1; } /* see if the user entered the window on a certain window decoration */ - int layout = con->layout; + int layout = (enter_child ? con->parent->layout : con->layout); Con *child; TAILQ_FOREACH(child, &(con->nodes_head), nodes) if (rect_contains(child->deco_rect, event->event_x, event->event_y)) { @@ -231,16 +202,12 @@ int handle_enter_notify(void *ignored, xcb_connection_t *conn, if (config.disable_focus_follows_mouse) return 1; - Con *next = con; - while (!TAILQ_EMPTY(&(next->focus_head))) - next = TAILQ_FIRST(&(next->focus_head)); - con_focus(next); - x_push_changes(croot); + con_focus(con_descend_focused(con)); + tree_render(); return 1; } -#if 0 /* * When the user moves the mouse but does not change the active window @@ -249,14 +216,39 @@ int handle_enter_notify(void *ignored, xcb_connection_t *conn, * */ int handle_motion_notify(void *ignored, xcb_connection_t *conn, xcb_motion_notify_event_t *event) { - /* Skip events where the pointer was over a child window, we are only - * interested in events on the root window. */ - if (event->child != 0) - return 1; + /* Skip events where the pointer was over a child window, we are only + * interested in events on the root window. */ + if (event->child != 0) + return 1; + Con *con; + if ((con = con_by_frame_id(event->event)) == NULL) { check_crossing_screen_boundary(event->root_x, event->root_y); + return 1; + } + + if (config.disable_focus_follows_mouse) + return 1; + + if (con->layout != L_DEFAULT) + return 1; + /* see over which rect the user is */ + Con *current; + TAILQ_FOREACH(current, &(con->nodes_head), nodes) { + if (!rect_contains(current->deco_rect, event->event_x, event->event_y)) + continue; + + /* We found the rect, let’s see if this window is focused */ + if (TAILQ_FIRST(&(con->focus_head)) == current) + return 1; + + con_focus(current); + x_push_changes(croot); return 1; + } + + return 1; } /* @@ -265,23 +257,22 @@ int handle_motion_notify(void *ignored, xcb_connection_t *conn, xcb_motion_notif * */ int handle_mapping_notify(void *ignored, xcb_connection_t *conn, xcb_mapping_notify_event_t *event) { - if (event->request != XCB_MAPPING_KEYBOARD && - event->request != XCB_MAPPING_MODIFIER) - return 0; + if (event->request != XCB_MAPPING_KEYBOARD && + event->request != XCB_MAPPING_MODIFIER) + return 0; - DLOG("Received mapping_notify for keyboard or modifier mapping, re-grabbing keys\n"); - xcb_refresh_keyboard_mapping(keysyms, event); + DLOG("Received mapping_notify for keyboard or modifier mapping, re-grabbing keys\n"); + xcb_refresh_keyboard_mapping(keysyms, event); - xcb_get_numlock_mask(conn); + xcb_get_numlock_mask(conn); - ungrab_all_keys(conn); - translate_keysyms(); - grab_all_keys(conn, false); + ungrab_all_keys(conn); + translate_keysyms(); + grab_all_keys(conn, false); - return 0; + return 0; } -#endif /* * A new window appeared on the screen (=was mapped), so let’s manage it. * @@ -321,8 +312,8 @@ int handle_configure_request(void *prophs, xcb_connection_t *conn, xcb_configure int c = 0; #define COPY_MASK_MEMBER(mask_member, event_member) do { \ if (event->value_mask & mask_member) { \ - mask |= mask_member; \ - values[c++] = event->event_member; \ + mask |= mask_member; \ + values[c++] = event->event_member; \ } \ } while (0) @@ -342,11 +333,15 @@ int handle_configure_request(void *prophs, xcb_connection_t *conn, xcb_configure DLOG("Configure request!\n"); if (con_is_floating(con) && con_is_leaf(con)) { + /* find the height for the decorations */ + int deco_height = config.font.height + 5; /* we actually need to apply the size/position changes to the *parent* * container */ Rect bsr = con_border_style_rect(con); - if (con->border_style == BS_NORMAL) - bsr.height -= 17; + if (con->border_style == BS_NORMAL) { + bsr.y += deco_height; + bsr.height -= deco_height; + } con = con->parent; DLOG("Container is a floating leaf node, will do that.\n"); if (event->value_mask & XCB_CONFIG_WINDOW_X) { @@ -368,6 +363,8 @@ int handle_configure_request(void *prophs, xcb_connection_t *conn, xcb_configure tree_render(); } + fake_absolute_configure_notify(con); + return 1; #if 0 /* Dock clients can be reconfigured in their height */ @@ -416,6 +413,7 @@ int handle_configure_event(void *prophs, xcb_connection_t *conn, xcb_configure_n return 1; } +#endif /* * Gets triggered upon a RandR screen change event, that is when the user @@ -424,15 +422,14 @@ int handle_configure_event(void *prophs, xcb_connection_t *conn, xcb_configure_n */ int handle_screen_change(void *prophs, xcb_connection_t *conn, xcb_generic_event_t *e) { - DLOG("RandR screen change\n"); + DLOG("RandR screen change\n"); - randr_query_outputs(conn); + randr_query_outputs(); - ipc_send_event("output", I3_IPC_EVENT_OUTPUT, "{\"change\":\"unspecified\"}"); + ipc_send_event("output", I3_IPC_EVENT_OUTPUT, "{\"change\":\"unspecified\"}"); - return 1; + return 1; } -#endif /* * Our window decorations were unmapped. That means, the window will be killed @@ -441,8 +438,6 @@ int handle_screen_change(void *prophs, xcb_connection_t *conn, */ int handle_unmap_notify_event(void *data, xcb_connection_t *conn, xcb_unmap_notify_event_t *event) { - bool ignored = event_is_ignored(event->sequence); - /* FIXME: we cannot ignore this sequence because more UnmapNotifys with the same sequence * numbers but different window IDs may follow */ /* we need to ignore EnterNotify events which will be generated because a @@ -450,14 +445,24 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *conn, xcb_unmap_noti //add_ignore_event(event->sequence); DLOG("UnmapNotify for 0x%08x (received from 0x%08x), serial %d\n", event->window, event->event, event->sequence); - if (ignored) { - DLOG("Ignoring UnmapNotify (generated by reparenting)\n"); - unignore_event(event->sequence); - return 1; - } Con *con = con_by_window_id(event->window); if (con == NULL) { - LOG("Not a managed window, ignoring\n"); + /* This could also be an UnmapNotify for the frame. We need to + * decrement the ignore_unmap counter. */ + con = con_by_frame_id(event->window); + if (con == NULL) { + LOG("Not a managed window, ignoring UnmapNotify event\n"); + return 1; + } + if (con->ignore_unmap > 0) + con->ignore_unmap--; + DLOG("ignore_unmap = %d for frame of container %p\n", con->ignore_unmap, con); + return 1; + } + + if (con->ignore_unmap > 0) { + DLOG("ignore_unmap = %d, dec\n", con->ignore_unmap); + con->ignore_unmap--; return 1; } @@ -595,50 +600,25 @@ int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t * return 1; } + if (parent->window) + x_draw_decoration(parent); + TAILQ_FOREACH(con, &(parent->nodes_head), nodes) { - LOG("expose for con %p / %s\n", con, con->name); + DLOG("expose for con %p / %s\n", con, con->name); if (con->window) x_draw_decoration(con); } - xcb_flush(conn); - - return 1; -#if 0 - else { - uint32_t background_color; - if (client->urgent) - background_color = config.client.urgent.background; - /* Distinguish if the window is currently focused… */ - else if (CUR_CELL != NULL && CUR_CELL->currently_focused == client) - background_color = config.client.focused.background; - /* …or if it is the focused window in a not focused container */ - else background_color = config.client.focused_inactive.background; - - /* Set foreground color to current focused color, line width to 2 */ - uint32_t values[] = {background_color, 2}; - xcb_change_gc(conn, client->titlegc, XCB_GC_FOREGROUND | XCB_GC_LINE_WIDTH, values); - - /* Draw the border, the ±1 is for line width = 2 */ - xcb_point_t points[] = {{1, 0}, /* left upper edge */ - {1, client->rect.height-1}, /* left bottom edge */ - {client->rect.width-1, client->rect.height-1}, /* right bottom edge */ - {client->rect.width-1, 0}}; /* right upper edge */ - xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, client->frame, client->titlegc, 4, points); - - /* Draw a black background */ - xcb_change_gc_single(conn, client->titlegc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#000000")); - if (client->titlebar_position == TITLEBAR_OFF && !client->borderless) { - xcb_rectangle_t crect = {1, 0, client->rect.width - (1 + 1), client->rect.height - 1}; - xcb_poly_fill_rectangle(conn, client->frame, client->titlegc, 1, &crect); - } else { - xcb_rectangle_t crect = {2, 0, client->rect.width - (2 + 2), client->rect.height - 2}; - xcb_poly_fill_rectangle(conn, client->frame, client->titlegc, 1, &crect); - } + /* We also need to render the decorations of other Cons nearby the Con + * itself to not get overlapping decorations */ + TAILQ_FOREACH(con, &(parent->parent->nodes_head), nodes) { + DLOG("expose for con %p / %s\n", con, con->name); + if (con->window) + x_draw_decoration(con); } xcb_flush(conn); + return 1; -#endif } /* @@ -648,12 +628,18 @@ int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t * int handle_client_message(void *data, xcb_connection_t *conn, xcb_client_message_event_t *event) { LOG("ClientMessage for window 0x%08x\n", event->window); if (event->type == atoms[_NET_WM_STATE]) { - if (event->format != 32 || event->data.data32[1] != atoms[_NET_WM_STATE_FULLSCREEN]) + if (event->format != 32 || event->data.data32[1] != atoms[_NET_WM_STATE_FULLSCREEN]) { + DLOG("atom in clientmessage is %d, fullscreen is %d\n", + event->data.data32[1], atoms[_NET_WM_STATE_FULLSCREEN]); + DLOG("not about fullscreen atom\n"); return 0; + } Con *con = con_by_window_id(event->window); - if (con == NULL) + if (con == NULL) { + DLOG("Could not get window for client message\n"); return 0; + } /* Check if the fullscreen state should be toggled */ if ((con->fullscreen_mode != CF_NONE && @@ -661,8 +647,10 @@ int handle_client_message(void *data, xcb_connection_t *conn, xcb_client_message event->data.data32[0] == _NET_WM_STATE_TOGGLE)) || (con->fullscreen_mode == CF_NONE && (event->data.data32[0] == _NET_WM_STATE_ADD || - event->data.data32[0] == _NET_WM_STATE_TOGGLE))) - con_toggle_fullscreen(con); + event->data.data32[0] == _NET_WM_STATE_TOGGLE))) { + DLOG("toggling fullscreen\n"); + con_toggle_fullscreen(con); + } tree_render(); x_push_changes(croot); @@ -751,7 +739,6 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_w con->base_height = base_height; DLOG("client's base_height changed to %d\n", base_height); DLOG("client's base_width changed to %d\n", base_width); - changed = true; } /* If no aspect ratio was set or if it was invalid, we ignore the hints */