* 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
uint32_t center_x = x - sep_offset;
if (config.separator_symbol == NULL) {
/* Draw a classic one pixel, vertical separator. */
- draw_util_rectangle(xcb_connection, &output->statusline_buffer, sep_fg,
+ draw_util_rectangle(&output->statusline_buffer, sep_fg,
center_x,
logical_px(sep_voff_px),
logical_px(1),
struct status_block *block;
color_t bar_color = (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg);
- draw_util_clear_surface(xcb_connection, &output->statusline_buffer, bar_color);
+ draw_util_clear_surface(&output->statusline_buffer, bar_color);
/* Use unsigned integer wraparound to clip off the left side.
* For example, if clip_left is 75, then x will start at the very large
}
/* Draw the border. */
- draw_util_rectangle(xcb_connection, &output->statusline_buffer, border_color,
+ draw_util_rectangle(&output->statusline_buffer, border_color,
x, logical_px(1),
full_render_width,
bar_height - logical_px(2));
/* Draw the background. */
- draw_util_rectangle(xcb_connection, &output->statusline_buffer, bg_color,
+ draw_util_rectangle(&output->statusline_buffer, bg_color,
x + border_width,
logical_px(1) + border_width,
full_render_width - 2 * border_width,
/*
* 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
*
*/
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
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
DLOG("checking output %s\n", walk->name);
trayclient *trayclient;
TAILQ_FOREACH(trayclient, walk->trayclients, tailq) {
- if (trayclient->win != event->window)
+ if (trayclient->win != event->window) {
continue;
+ }
DLOG("Removing tray client with window ID %08x\n", event->window);
TAILQ_REMOVE(walk->trayclients, trayclient, tailq);
+ FREE(trayclient);
/* Trigger an update, we now have more space for the statusline */
configure_trayclients();
}
/*
- * 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)
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_PRESS:
/* Button press events are mouse buttons clicked on one of our bars */
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);
/* We remove the trayclient right here. We might receive an UnmapNotify
* event afterwards, but better safe than sorry. */
TAILQ_REMOVE(output->trayclients, trayclient, tailq);
+ FREE(trayclient);
}
/* Fake a DestroyNotify so that Qt re-adds tray icons.
bool use_focus_colors = output_has_focus(outputs_walk);
/* First things first: clear the backbuffer */
- draw_util_clear_surface(xcb_connection, &(outputs_walk->buffer),
- (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg));
+ draw_util_clear_surface(&(outputs_walk->buffer), (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg));
if (!config.disable_ws) {
i3_ws *ws_walk;
}
/* Draw the border of the button. */
- draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), border_color,
+ draw_util_rectangle(&(outputs_walk->buffer), border_color,
workspace_width,
logical_px(1),
ws_walk->name_width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1),
font.height + 2 * logical_px(ws_voff_px) - 2 * logical_px(1));
/* Draw the inside of the button. */
- draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), bg_color,
+ draw_util_rectangle(&(outputs_walk->buffer), bg_color,
workspace_width + logical_px(1),
2 * logical_px(1),
ws_walk->name_width + 2 * logical_px(ws_hoff_px),
color_t fg_color = colors.binding_mode_fg;
color_t bg_color = colors.binding_mode_bg;
- draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), colors.binding_mode_border,
+ draw_util_rectangle(&(outputs_walk->buffer), colors.binding_mode_border,
workspace_width,
logical_px(1),
binding.width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1),
font.height + 2 * logical_px(ws_voff_px) - 2 * logical_px(1));
- draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), bg_color,
+ draw_util_rectangle(&(outputs_walk->buffer), bg_color,
workspace_width + logical_px(1),
2 * logical_px(1),
binding.width + 2 * logical_px(ws_hoff_px),
int x_dest = outputs_walk->rect.w - tray_width - logical_px(sb_hoff_px) - visible_statusline_width;
draw_statusline(outputs_walk, clip_left, use_focus_colors, use_short_text);
- draw_util_copy_surface(xcb_connection, &outputs_walk->statusline_buffer, &outputs_walk->buffer, 0, 0,
+ draw_util_copy_surface(&outputs_walk->statusline_buffer, &outputs_walk->buffer, 0, 0,
x_dest, 0, visible_statusline_width, (int16_t)bar_height);
outputs_walk->statusline_width = statusline_width;
continue;
}
- draw_util_copy_surface(xcb_connection, &(outputs_walk->buffer), &(outputs_walk->bar), 0, 0,
+ draw_util_copy_surface(&(outputs_walk->buffer), &(outputs_walk->bar), 0, 0,
0, 0, outputs_walk->rect.w, outputs_walk->rect.h);
xcb_flush(xcb_connection);
}