i3bar: properly handle the _XEMBED_INFO property
This commit is contained in:
parent
7df43989c9
commit
737cd10bdf
|
@ -9,8 +9,9 @@
|
||||||
#ifndef COMMON_H_
|
#ifndef COMMON_H_
|
||||||
#define COMMON_H_
|
#define COMMON_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
typedef struct rect_t rect;
|
typedef struct rect_t rect;
|
||||||
typedef int bool;
|
|
||||||
|
|
||||||
struct ev_loop* main_loop;
|
struct ev_loop* main_loop;
|
||||||
char *statusline;
|
char *statusline;
|
||||||
|
|
|
@ -17,6 +17,7 @@ TAILQ_HEAD(tc_head, trayclient);
|
||||||
|
|
||||||
struct trayclient {
|
struct trayclient {
|
||||||
xcb_window_t win; /* The window ID of the tray client */
|
xcb_window_t win; /* The window ID of the tray client */
|
||||||
|
bool mapped; /* Whether this window is mapped */
|
||||||
|
|
||||||
TAILQ_ENTRY(trayclient) tailq; /* Pointer for the TAILQ-Macro */
|
TAILQ_ENTRY(trayclient) tailq; /* Pointer for the TAILQ-Macro */
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,11 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
//#include "outputs.h"
|
//#include "outputs.h"
|
||||||
|
|
||||||
|
#define SYSTEM_TRAY_REQUEST_DOCK 0
|
||||||
|
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
|
||||||
|
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
|
||||||
|
#define XEMBED_MAPPED (1 << 0)
|
||||||
|
|
||||||
struct xcb_color_strings_t {
|
struct xcb_color_strings_t {
|
||||||
char *bar_fg;
|
char *bar_fg;
|
||||||
char *bar_bg;
|
char *bar_bg;
|
||||||
|
|
|
@ -8,4 +8,5 @@ ATOM_DO(_NET_SYSTEM_TRAY_ORIENTATION)
|
||||||
ATOM_DO(_NET_SYSTEM_TRAY_VISUAL)
|
ATOM_DO(_NET_SYSTEM_TRAY_VISUAL)
|
||||||
ATOM_DO(CARDINAL)
|
ATOM_DO(CARDINAL)
|
||||||
ATOM_DO(_NET_SYSTEM_TRAY_OPCODE)
|
ATOM_DO(_NET_SYSTEM_TRAY_OPCODE)
|
||||||
|
ATOM_DO(_XEMBED_INFO)
|
||||||
#undef ATOM_DO
|
#undef ATOM_DO
|
||||||
|
|
|
@ -43,7 +43,7 @@ static int outputs_null_cb(void *params_) {
|
||||||
* Parse a boolean value (active)
|
* Parse a boolean value (active)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int outputs_boolean_cb(void *params_, bool val) {
|
static int outputs_boolean_cb(void *params_, int val) {
|
||||||
struct outputs_json_params *params = (struct outputs_json_params*) params_;
|
struct outputs_json_params *params = (struct outputs_json_params*) params_;
|
||||||
|
|
||||||
if (strcmp(params->cur_key, "active")) {
|
if (strcmp(params->cur_key, "active")) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ struct workspaces_json_params {
|
||||||
* Parse a boolean value (visible, focused, urgent)
|
* Parse a boolean value (visible, focused, urgent)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int workspaces_boolean_cb(void *params_, bool val) {
|
static int workspaces_boolean_cb(void *params_, int val) {
|
||||||
struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
|
struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
|
||||||
|
|
||||||
if (!strcmp(params->cur_key, "visible")) {
|
if (!strcmp(params->cur_key, "visible")) {
|
||||||
|
|
133
i3bar/src/xcb.c
133
i3bar/src/xcb.c
|
@ -416,11 +416,48 @@ void handle_client_message(xcb_client_message_event_t* event) {
|
||||||
DLOG("_NET_SYSTEM_TRAY_OPCODE received\n");
|
DLOG("_NET_SYSTEM_TRAY_OPCODE received\n");
|
||||||
/* event->data.data32[0] is the timestamp */
|
/* event->data.data32[0] is the timestamp */
|
||||||
uint32_t op = event->data.data32[1];
|
uint32_t op = event->data.data32[1];
|
||||||
#define SYSTEM_TRAY_REQUEST_DOCK 0
|
uint32_t mask;
|
||||||
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
|
uint32_t values[2];
|
||||||
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
|
|
||||||
if (op == SYSTEM_TRAY_REQUEST_DOCK) {
|
if (op == SYSTEM_TRAY_REQUEST_DOCK) {
|
||||||
xcb_window_t client = event->data.data32[2];
|
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);
|
||||||
|
|
||||||
|
/* Request the _XEMBED_INFO property. The XEMBED specification
|
||||||
|
* (which is referred by the tray specification) says this *has* to
|
||||||
|
* be set, but VLC does not set it… */
|
||||||
|
bool map_it = true;
|
||||||
|
xcb_get_property_cookie_t xembedc;
|
||||||
|
xembedc = xcb_get_property_unchecked(xcb_connection,
|
||||||
|
0,
|
||||||
|
client,
|
||||||
|
atoms[_XEMBED_INFO],
|
||||||
|
XCB_GET_PROPERTY_TYPE_ANY,
|
||||||
|
0,
|
||||||
|
2 * 32);
|
||||||
|
|
||||||
|
xcb_get_property_reply_t *xembedr = xcb_get_property_reply(xcb_connection,
|
||||||
|
xembedc,
|
||||||
|
NULL);
|
||||||
|
if (xembedr != NULL && xembedr->length != 0) {
|
||||||
|
DLOG("xembed format = %d, len = %d\n", xembedr->format, xembedr->length);
|
||||||
|
uint32_t *xembed = xcb_get_property_value(xembedr);
|
||||||
|
DLOG("xembed version = %d\n", xembed[0]);
|
||||||
|
DLOG("xembed flags = %d\n", xembed[1]);
|
||||||
|
map_it = ((xembed[1] & XEMBED_MAPPED) == XEMBED_MAPPED);
|
||||||
|
free(xembedr);
|
||||||
|
} else {
|
||||||
|
ELOG("Window %08x violates the XEMBED protocol, _XEMBED_INFO not set\n", client);
|
||||||
|
}
|
||||||
|
|
||||||
DLOG("X window %08x requested docking\n", client);
|
DLOG("X window %08x requested docking\n", client);
|
||||||
i3_output *walk, *output;
|
i3_output *walk, *output;
|
||||||
SLIST_FOREACH(walk, outputs, slist) {
|
SLIST_FOREACH(walk, outputs, slist) {
|
||||||
|
@ -439,25 +476,23 @@ void handle_client_message(xcb_client_message_event_t* event) {
|
||||||
* Tray icons may be assigned any size by the system tray, and
|
* Tray icons may be assigned any size by the system tray, and
|
||||||
* should do their best to cope with any size effectively
|
* should do their best to cope with any size effectively
|
||||||
*/
|
*/
|
||||||
uint32_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
|
mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
|
||||||
uint32_t values[] = { font_height, font_height };
|
values[0] = font_height;
|
||||||
|
values[1] = font_height;
|
||||||
xcb_configure_window(xcb_connection,
|
xcb_configure_window(xcb_connection,
|
||||||
client,
|
client,
|
||||||
mask,
|
mask,
|
||||||
values);
|
values);
|
||||||
|
|
||||||
/* Listen for PropertyNotify events to get the most recent value of
|
if (map_it) {
|
||||||
* the XEMBED_MAPPED atom, also listen for UnmapNotify events */
|
DLOG("Mapping dock client\n");
|
||||||
mask = XCB_CW_EVENT_MASK;
|
xcb_map_window(xcb_connection, client);
|
||||||
values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE |
|
} else {
|
||||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY;
|
DLOG("Not mapping dock client yet\n");
|
||||||
xcb_change_window_attributes(xcb_connection,
|
}
|
||||||
client,
|
|
||||||
mask,
|
|
||||||
values);
|
|
||||||
xcb_map_window(xcb_connection, client);
|
|
||||||
trayclient *tc = malloc(sizeof(trayclient));
|
trayclient *tc = malloc(sizeof(trayclient));
|
||||||
tc->win = client;
|
tc->win = client;
|
||||||
|
tc->mapped = map_it;
|
||||||
TAILQ_INSERT_TAIL(output->trayclients, tc, tailq);
|
TAILQ_INSERT_TAIL(output->trayclients, tc, tailq);
|
||||||
|
|
||||||
/* Trigger an update to copy the statusline text to the appropriate
|
/* Trigger an update to copy the statusline text to the appropriate
|
||||||
|
@ -492,6 +527,68 @@ void handle_unmap_notify(xcb_unmap_notify_event_t* event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_property_notify(xcb_property_notify_event_t *event) {
|
||||||
|
DLOG("PropertyNotify\n");
|
||||||
|
if (event->atom == atoms[_XEMBED_INFO] &&
|
||||||
|
event->state == XCB_PROPERTY_NEW_VALUE) {
|
||||||
|
DLOG("xembed_info updated\n");
|
||||||
|
trayclient *trayclient = NULL, *walk;
|
||||||
|
i3_output *output;
|
||||||
|
SLIST_FOREACH(output, outputs, slist) {
|
||||||
|
if (!output->active)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(walk, output->trayclients, tailq) {
|
||||||
|
if (walk->win != event->window)
|
||||||
|
continue;
|
||||||
|
trayclient = walk;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trayclient)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!trayclient) {
|
||||||
|
ELOG("PropertyNotify received for unknown window %08x\n",
|
||||||
|
event->window);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xcb_get_property_cookie_t xembedc;
|
||||||
|
xembedc = xcb_get_property_unchecked(xcb_connection,
|
||||||
|
0,
|
||||||
|
trayclient->win,
|
||||||
|
atoms[_XEMBED_INFO],
|
||||||
|
XCB_GET_PROPERTY_TYPE_ANY,
|
||||||
|
0,
|
||||||
|
2 * 32);
|
||||||
|
|
||||||
|
xcb_get_property_reply_t *xembedr = xcb_get_property_reply(xcb_connection,
|
||||||
|
xembedc,
|
||||||
|
NULL);
|
||||||
|
if (xembedr == NULL || xembedr->length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DLOG("xembed format = %d, len = %d\n", xembedr->format, xembedr->length);
|
||||||
|
uint32_t *xembed = xcb_get_property_value(xembedr);
|
||||||
|
DLOG("xembed version = %d\n", xembed[0]);
|
||||||
|
DLOG("xembed flags = %d\n", xembed[1]);
|
||||||
|
bool map_it = ((xembed[1] & XEMBED_MAPPED) == XEMBED_MAPPED);
|
||||||
|
DLOG("map-state now %d\n", map_it);
|
||||||
|
if (trayclient->mapped && !map_it) {
|
||||||
|
/* need to unmap the window */
|
||||||
|
xcb_unmap_window(xcb_connection, trayclient->win);
|
||||||
|
trayclient->mapped = map_it;
|
||||||
|
draw_bars();
|
||||||
|
} else if (!trayclient->mapped && map_it) {
|
||||||
|
/* need to map the window */
|
||||||
|
xcb_map_window(xcb_connection, trayclient->win);
|
||||||
|
trayclient->mapped = map_it;
|
||||||
|
draw_bars();
|
||||||
|
}
|
||||||
|
free(xembedr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is called immediately before the main loop locks. We flush xcb
|
* This function is called immediately before the main loop locks. We flush xcb
|
||||||
* then (and only then)
|
* then (and only then)
|
||||||
|
@ -531,6 +628,10 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) {
|
||||||
/* UnmapNotifies are received when a tray window unmaps itself */
|
/* UnmapNotifies are received when a tray window unmaps itself */
|
||||||
handle_unmap_notify((xcb_unmap_notify_event_t*) event);
|
handle_unmap_notify((xcb_unmap_notify_event_t*) event);
|
||||||
break;
|
break;
|
||||||
|
case XCB_PROPERTY_NOTIFY:
|
||||||
|
/* PropertyNotify */
|
||||||
|
handle_property_notify((xcb_property_notify_event_t*) event);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
FREE(event);
|
FREE(event);
|
||||||
}
|
}
|
||||||
|
@ -1126,6 +1227,8 @@ void draw_bars() {
|
||||||
trayclient *trayclient;
|
trayclient *trayclient;
|
||||||
int traypx = 0;
|
int traypx = 0;
|
||||||
TAILQ_FOREACH(trayclient, outputs_walk->trayclients, tailq) {
|
TAILQ_FOREACH(trayclient, outputs_walk->trayclients, tailq) {
|
||||||
|
if (!trayclient->mapped)
|
||||||
|
continue;
|
||||||
/* We assume the tray icons are quadratic (we use the font
|
/* We assume the tray icons are quadratic (we use the font
|
||||||
* *height* as *width* of the icons) because we configured them
|
* *height* as *width* of the icons) because we configured them
|
||||||
* like this. */
|
* like this. */
|
||||||
|
|
Loading…
Reference in New Issue