* xcb.c: Communicating with X
*
*/
+#include "common.h"
+
#include <xcb/xcb.h>
#include <xcb/xkb.h>
#include <xcb/xproto.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb_cursor.h>
-#ifdef XCB_COMPAT
-#include "xcb_compat.h"
-#endif
-
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sanitizer/lsan_interface.h>
#endif
-#include "common.h"
#include "libi3.h"
/** This is the equivalent of XC_left_ptr. I’m not sure why xcb doesn’t have a
/*
* Handle a button press event (i.e. a mouse click on one of our bars).
- * We determine, whether the click occured on a workspace button or if the scroll-
+ * We determine, whether the click occurred on a workspace button or if the scroll-
* wheel was used and change the workspace appropriately
*
*/
if (op == SYSTEM_TRAY_REQUEST_DOCK) {
xcb_window_t client = event->data.data32[2];
- /* Listen for PropertyNotify events to get the most recent value of
- * the XEMBED_MAPPED atom, also listen for UnmapNotify events */
mask = XCB_CW_EVENT_MASK;
- values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE |
- XCB_EVENT_MASK_STRUCTURE_NOTIFY;
- xcb_change_window_attributes(xcb_connection,
- client,
- mask,
- values);
+
+ /* Needed to get the most recent value of XEMBED_MAPPED. */
+ values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
+ /* Needed for UnmapNotify events. */
+ values[0] |= XCB_EVENT_MASK_STRUCTURE_NOTIFY;
+ /* Needed because some tray applications (e.g., VLC) use
+ * override_redirect which causes no ConfigureRequest to be sent. */
+ values[0] |= XCB_EVENT_MASK_RESIZE_REDIRECT;
+
+ xcb_change_window_attributes(xcb_connection, client, mask, values);
/* Request the _XEMBED_INFO property. The XEMBED specification
* (which is referred by the tray specification) says this *has* to
break;
}
- /* Check whether any "tray_output primary" was defined for this bar. */
- bool contains_primary = false;
- TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) {
- if (strcasecmp("primary", tray_output->output) == 0) {
- contains_primary = true;
- break;
- }
- }
-
- /* In case of tray_output == primary and there is no primary output
- * configured, we fall back to the first available output. We do the
- * same if no tray_output was specified. */
- if (output == NULL && (contains_primary || TAILQ_EMPTY(&(config.tray_outputs)))) {
+ /* If no tray_output has been specified, we fall back to the first
+ * available output. */
+ if (output == NULL && TAILQ_EMPTY(&(config.tray_outputs))) {
SLIST_FOREACH(walk, outputs, slist) {
if (!walk->active)
continue;
break;
}
}
+
if (output == NULL) {
ELOG("No output found\n");
return;
ev->type = atoms[_XEMBED];
ev->format = 32;
ev->data.data32[0] = XCB_CURRENT_TIME;
- ev->data.data32[1] = atoms[XEMBED_EMBEDDED_NOTIFY];
+ ev->data.data32[1] = XEMBED_EMBEDDED_NOTIFY;
ev->data.data32[2] = output->bar.id;
ev->data.data32[3] = xe_version;
xcb_send_event(xcb_connection,
}
/*
- * Handle ConfigureRequests by denying them and sending the client a
- * ConfigureNotify with its actual size.
+ * If a tray client attempts to change its size we deny the request and respond
+ * by telling it its actual size.
*
*/
-static void handle_configure_request(xcb_configure_request_event_t *event) {
- DLOG("ConfigureRequest for window = %08x\n", event->window);
-
+static void handle_configuration_change(xcb_window_t window) {
trayclient *trayclient;
i3_output *output;
SLIST_FOREACH(output, outputs, slist) {
continue;
clients++;
- if (trayclient->win != event->window)
+ if (trayclient->win != window)
continue;
xcb_rectangle_t rect;
rect.height = icon_size;
DLOG("This is a tray window. x = %d\n", rect.x);
- fake_configure_notify(xcb_connection, rect, event->window, 0);
+ fake_configure_notify(xcb_connection, rect, window, 0);
return;
}
}
DLOG("WARNING: Could not find corresponding tray window.\n");
}
+static void handle_configure_request(xcb_configure_request_event_t *event) {
+ DLOG("ConfigureRequest for window = %08x\n", event->window);
+ handle_configuration_change(event->window);
+}
+
+static void handle_resize_request(xcb_resize_request_event_t *event) {
+ DLOG("ResizeRequest for window = %08x\n", event->window);
+ handle_configuration_change(event->window);
+}
+
/*
* This function is called immediately before the main loop locks. We flush xcb
* then (and only then)
DLOG("received an xkb event\n");
xcb_xkb_state_notify_event_t *state = (xcb_xkb_state_notify_event_t *)event;
- if (state->xkbType == XCB_XKB_STATE_NOTIFY) {
+ if (state->xkbType == XCB_XKB_STATE_NOTIFY && config.modifier != XCB_NONE) {
int modstate = state->mods & config.modifier;
#define DLOGMOD(modmask, status) \
case XCB_CONFIGURE_REQUEST:
/* ConfigureRequest, sent by a tray child */
handle_configure_request((xcb_configure_request_event_t *)event);
+ case XCB_RESIZE_REQUEST:
+ /* ResizeRequest sent by a tray child using override_redirect. */
+ handle_resize_request((xcb_resize_request_event_t *)event);
break;
}
free(event);
}
/* Unless "tray_output none" was specified, we need to initialize the tray. */
- const char *first = (TAILQ_EMPTY(&(config.tray_outputs))) ? SLIST_FIRST(outputs)->name : TAILQ_FIRST(&(config.tray_outputs))->output;
- if (!tray_configured && strcasecmp(first, "none") != 0) {
- /* We do a sanity check here to ensure that this i3bar instance actually handles
- * the output on which the tray should appear. For example,
- * consider tray_output == [VGA-1], but output == [HDMI-1]. */
+ bool no_tray = false;
+ if (!(TAILQ_EMPTY(&(config.tray_outputs)))) {
+ no_tray = strcasecmp(TAILQ_FIRST(&(config.tray_outputs))->output, "none") == 0;
+ }
+ /*
+ * There are three scenarios in which we need to initialize the tray:
+ * 1. A specific output was listed in tray_outputs which is also
+ * in the list of outputs managed by this bar.
+ * 2. No tray_output directive was specified. In this case, we
+ * use the first available output.
+ * 3. 'tray_output primary' was specified. In this case we use the
+ * primary output.
+ *
+ * Three scenarios in which we specifically don't want to
+ * initialize the tray are:
+ * 1. 'tray_output none' was specified.
+ * 2. A specific output was listed as a tray_output, but is not
+ * one of the outputs managed by this bar. For example, consider
+ * tray_outputs == [VGA-1], but outputs == [HDMI-1].
+ * 3. 'tray_output primary' was specified and no output in the list
+ * is primary.
+ */
+ if (!tray_configured && !no_tray) {
/* If no tray_output was specified, we go ahead and initialize the tray as
* we will be using the first available output. */
- if (TAILQ_EMPTY(&(config.tray_outputs)))
+ if (TAILQ_EMPTY(&(config.tray_outputs))) {
init_tray();
+ }
/* If one or more tray_output assignments were specified, we ensure that at least one of
* them is actually an output managed by this instance. */