/* Event watchers, to interact with the user */
ev_prepare *xcb_prep;
-ev_check *xcb_chk;
ev_io *xcb_io;
ev_io *xkb_io;
xcb_flush(xcb_connection);
}
+static bool execute_custom_command(xcb_keycode_t input_code, bool event_is_release) {
+ binding_t *binding;
+ TAILQ_FOREACH(binding, &(config.bindings), bindings) {
+ if ((binding->input_code != input_code) || (binding->release != event_is_release))
+ continue;
+
+ i3_send_msg(I3_IPC_MESSAGE_TYPE_RUN_COMMAND, binding->command);
+ return true;
+ }
+ return false;
+}
+
/*
* Handle a button press event (i.e. a mouse click on one of our bars).
* We determine, whether the click occurred on a workspace button or if the scroll-
return;
}
- int32_t x = event->event_x >= 0 ? event->event_x : 0;
-
DLOG("Got button %d\n", event->detail);
+ /* During button release events, only check for custom commands. */
+ const bool event_is_release = (event->response_type & ~0x80) == XCB_BUTTON_RELEASE;
+ if (event_is_release) {
+ execute_custom_command(event->detail, event_is_release);
+ return;
+ }
+
+ int32_t x = event->event_x >= 0 ? event->event_x : 0;
int workspace_width = 0;
i3_ws *cur_ws = NULL, *clicked_ws = NULL, *ws_walk;
block_x += render->width + render->x_offset + render->x_append + get_sep_offset(block) + sep_offset_remainder;
if (statusline_x <= block_x && statusline_x >= last_block_x) {
- send_block_clicked(event->detail, block->name, block->instance, event->root_x, event->root_y);
+ send_block_clicked(event->detail, block->name, block->instance,
+ event->root_x, event->root_y, statusline_x - last_block_x, event->event_y, block_x - last_block_x, bar_height);
return;
}
/* If a custom command was specified for this mouse button, it overrides
* the default behavior. */
- binding_t *binding;
- TAILQ_FOREACH(binding, &(config.bindings), bindings) {
- if (binding->input_code != event->detail)
- continue;
-
- i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, binding->command);
+ if (execute_custom_command(event->detail, event_is_release)) {
return;
}
return;
}
switch (event->detail) {
- case 4:
+ case XCB_BUTTON_SCROLL_UP:
+ case XCB_BUTTON_SCROLL_LEFT:
/* Mouse wheel up. We select the previous ws, if any.
* If there is no more workspace, don’t even send the workspace
* command, otherwise (with workspace auto_back_and_forth) we’d end
cur_ws = TAILQ_PREV(cur_ws, ws_head, tailq);
break;
- case 5:
+ case XCB_BUTTON_SCROLL_DOWN:
+ case XCB_BUTTON_SCROLL_RIGHT:
/* Mouse wheel down. We select the next ws, if any.
* If there is no more workspace, don’t even send the workspace
* command, otherwise (with workspace auto_back_and_forth) we’d end
buffer[outpos] = utf8_name[inpos];
}
buffer[outpos] = '"';
- i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, buffer);
+ i3_send_msg(I3_IPC_MESSAGE_TYPE_RUN_COMMAND, buffer);
free(buffer);
}
*
*/
static void handle_client_message(xcb_client_message_event_t *event) {
- if (event->type == atoms[_NET_SYSTEM_TRAY_OPCODE] &&
- event->format == 32) {
+ if (event->type == atoms[I3_SYNC]) {
+ xcb_window_t window = event->data.data32[0];
+ uint32_t rnd = event->data.data32[1];
+ DLOG("[i3 sync protocol] Forwarding random value %d, X11 window 0x%08x to i3\n", rnd, window);
+
+ void *reply = scalloc(32, 1);
+ xcb_client_message_event_t *ev = reply;
+
+ ev->response_type = XCB_CLIENT_MESSAGE;
+ ev->window = window;
+ ev->type = atoms[I3_SYNC];
+ ev->format = 32;
+ ev->data.data32[0] = window;
+ ev->data.data32[1] = rnd;
+
+ xcb_send_event(conn, false, xcb_root, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (char *)ev);
+ xcb_flush(conn);
+ free(reply);
+ } else if (event->type == atoms[_NET_SYSTEM_TRAY_OPCODE] &&
+ event->format == 32) {
DLOG("_NET_SYSTEM_TRAY_OPCODE received\n");
/* event->data.data32[0] is the timestamp */
uint32_t op = event->data.data32[1];
* client to finish the protocol. After this event is received, there is no
* further interaction with the tray client.
*
- * See: http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html
+ * See: https://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html
*
*/
static void handle_destroy_notify(xcb_destroy_notify_event_t *event) {
}
/*
- * This function is called immediately before the main loop locks. We flush xcb
- * then (and only then)
+ * This function is called immediately before the main loop locks. We check for
+ * events from X11, handle them, then flush our outgoing queue.
*
*/
void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revents) {
- xcb_flush(xcb_connection);
-}
-
-/*
- * This function is called immediately after the main loop locks, so when one
- * of the watchers registered an event.
- * We check whether an X-Event arrived and handle it.
- *
- */
-void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) {
xcb_generic_event_t *event;
if (xcb_connection_has_error(xcb_connection)) {
handle_visibility_notify((xcb_visibility_notify_event_t *)event);
break;
case XCB_EXPOSE:
- /* Expose-events happen, when the window needs to be redrawn */
- redraw_bars();
+ if (((xcb_expose_event_t *)event)->count == 0) {
+ /* Expose-events happen, when the window needs to be redrawn */
+ redraw_bars();
+ }
+
break;
+ case XCB_BUTTON_RELEASE:
case XCB_BUTTON_PRESS:
/* Button press events are mouse buttons clicked on one of our bars */
handle_button((xcb_button_press_event_t *)event);
case XCB_CONFIGURE_REQUEST:
/* ConfigureRequest, sent by a tray child */
handle_configure_request((xcb_configure_request_event_t *)event);
+ break;
case XCB_RESIZE_REQUEST:
/* ResizeRequest sent by a tray child using override_redirect. */
handle_resize_request((xcb_resize_request_event_t *)event);
}
free(event);
}
+
+ xcb_flush(xcb_connection);
}
/*
/* The various watchers to communicate with xcb */
xcb_io = smalloc(sizeof(ev_io));
xcb_prep = smalloc(sizeof(ev_prepare));
- xcb_chk = smalloc(sizeof(ev_check));
ev_io_init(xcb_io, &xcb_io_cb, xcb_get_file_descriptor(xcb_connection), EV_READ);
ev_prepare_init(xcb_prep, &xcb_prep_cb);
- ev_check_init(xcb_chk, &xcb_chk_cb);
ev_io_start(main_loop, xcb_io);
ev_prepare_start(main_loop, xcb_prep);
- ev_check_start(main_loop, xcb_chk);
/* Now we get the atoms and save them in a nice data structure */
get_atoms();
*
*/
void clean_xcb(void) {
- i3_output *o_walk;
- free_workspaces();
- SLIST_FOREACH(o_walk, outputs, slist) {
- destroy_window(o_walk);
- FREE(o_walk->trayclients);
- FREE(o_walk->workspaces);
- FREE(o_walk->name);
- }
- FREE_SLIST(outputs, i3_output);
- FREE(outputs);
+ free_outputs();
free_font();
xcb_aux_sync(xcb_connection);
xcb_disconnect(xcb_connection);
- ev_check_stop(main_loop, xcb_chk);
ev_prepare_stop(main_loop, xcb_prep);
ev_io_stop(main_loop, xcb_io);
- FREE(xcb_chk);
FREE(xcb_prep);
FREE(xcb_io);
}
* */
values[3] = XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
- XCB_EVENT_MASK_BUTTON_PRESS;
+ XCB_EVENT_MASK_BUTTON_PRESS |
+ XCB_EVENT_MASK_BUTTON_RELEASE;
if (config.hide_on_modifier == M_DOCK) {
/* If the bar is normally visible, catch visibility change events to suspend
* the status process when the bar is obscured by full-screened windows. */