/* These are only relevant for XKB, which we only need for grabbing modifiers */
int xkb_base;
-int mod_pressed = 0;
+bool mod_pressed = 0;
/* Event watchers, to interact with the user */
ev_prepare *xcb_prep;
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_RUN_COMMAND, binding->command);
+ if (execute_custom_command(event->detail, event_is_release)) {
return;
}
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);
+ /* Forward the request to i3 via the IPC interface so that all pending
+ * IPC messages are guaranteed to be handled. */
+ char *payload = NULL;
+ sasprintf(&payload, "{\"rnd\":%d, \"window\":%d}", rnd, window);
+ i3_send_msg(I3_IPC_MESSAGE_TYPE_SYNC, payload);
+ free(payload);
} else if (event->type == atoms[_NET_SYSTEM_TRAY_OPCODE] &&
event->format == 32) {
DLOG("_NET_SYSTEM_TRAY_OPCODE received\n");
DLOG("received an xkb event\n");
xcb_xkb_state_notify_event_t *state = (xcb_xkb_state_notify_event_t *)event;
+ const uint32_t mod = (config.modifier & 0xFFFF);
+ mod_pressed = (mod != 0 && (state->mods & mod) == mod);
if (state->xkbType == XCB_XKB_STATE_NOTIFY && config.modifier != XCB_NONE) {
- int modstate = state->mods & config.modifier;
-
-#define DLOGMOD(modmask, status) \
- do { \
- switch (modmask) { \
- case ShiftMask: \
- DLOG("ShiftMask got " #status "!\n"); \
- break; \
- case ControlMask: \
- DLOG("ControlMask got " #status "!\n"); \
- break; \
- case Mod1Mask: \
- DLOG("Mod1Mask got " #status "!\n"); \
- break; \
- case Mod2Mask: \
- DLOG("Mod2Mask got " #status "!\n"); \
- break; \
- case Mod3Mask: \
- DLOG("Mod3Mask got " #status "!\n"); \
- break; \
- case Mod4Mask: \
- DLOG("Mod4Mask got " #status "!\n"); \
- break; \
- case Mod5Mask: \
- DLOG("Mod5Mask got " #status "!\n"); \
- break; \
- } \
- } while (0)
-
- if (modstate != mod_pressed) {
- if (modstate == 0) {
- DLOGMOD(config.modifier, released);
- if (!activated_mode)
- hide_bars();
- } else {
- DLOGMOD(config.modifier, pressed);
- activated_mode = false;
- unhide_bars();
- }
- mod_pressed = modstate;
+ if (mod_pressed) {
+ activated_mode = false;
+ unhide_bars();
+ } else if (!activated_mode) {
+ hide_bars();
}
-#undef DLOGMOD
}
free(event);
}
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);
*
*/
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();
* */
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. */