Implement new criterion 'window_type = normal|dialog|utility|toolbar|splash|menu|dropdown_menu|popup_menu|tooltip'

fixes #1658
This commit is contained in:
Ingo Bürk 2015-04-18 21:09:03 +02:00
parent 7e424b2d71
commit 550c0ec318
13 changed files with 142 additions and 24 deletions

View File

@ -1508,6 +1508,10 @@ instance::
Compares the window instance (the first part of WM_CLASS)
window_role::
Compares the window role (WM_WINDOW_ROLE).
window_type::
Compare the window type (_NET_WM_WINDOW_TYPE). Possible values are
+normal+, +dialog+, +utility+, +toolbar+, +splash+, +menu+, +dropdown_menu+,
+popup_menu+ and +toolti+.
id::
Compares the X11 window ID, which you can get via +xwininfo+ for example.
title::

View File

@ -7,11 +7,16 @@ xmacro(_NET_WM_STATE_DEMANDS_ATTENTION)
xmacro(_NET_WM_STATE_MODAL)
xmacro(_NET_WM_STATE)
xmacro(_NET_WM_WINDOW_TYPE)
xmacro(_NET_WM_WINDOW_TYPE_NORMAL)
xmacro(_NET_WM_WINDOW_TYPE_DOCK)
xmacro(_NET_WM_WINDOW_TYPE_DIALOG)
xmacro(_NET_WM_WINDOW_TYPE_UTILITY)
xmacro(_NET_WM_WINDOW_TYPE_TOOLBAR)
xmacro(_NET_WM_WINDOW_TYPE_SPLASH)
xmacro(_NET_WM_WINDOW_TYPE_MENU)
xmacro(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU)
xmacro(_NET_WM_WINDOW_TYPE_POPUP_MENU)
xmacro(_NET_WM_WINDOW_TYPE_TOOLTIP)
xmacro(_NET_WM_DESKTOP)
xmacro(_NET_WM_STRUT_PARTIAL)
xmacro(_NET_CLIENT_LIST)

View File

@ -378,6 +378,9 @@ struct Window {
* default will be 'accepts focus'. */
bool doesnt_accept_focus;
/** The _NET_WM_WINDOW_TYPE for this window. */
xcb_atom_t window_type;
/** Whether the window says it is a dock window */
enum { W_NODOCK = 0,
W_DOCK_TOP = 1,
@ -408,6 +411,7 @@ struct Match {
struct regex *instance;
struct regex *mark;
struct regex *window_role;
xcb_atom_t window_type;
enum {
U_DONTCHECK = -1,
U_LATEST = 0,

View File

@ -108,6 +108,16 @@ void xcb_raise_window(xcb_connection_t *conn, xcb_window_t window);
*/
void xcb_set_window_rect(xcb_connection_t *conn, xcb_window_t window, Rect r);
/**
* Returns the first supported _NET_WM_WINDOW_TYPE atom.
*
*/
xcb_atom_t xcb_get_preferred_window_type(xcb_get_property_reply_t *reply);
/**
* Returns true if the given reply contains the given data.
*
*/
bool xcb_reply_contains_atom(xcb_get_property_reply_t *prop, xcb_atom_t atom);
/**

View File

@ -49,6 +49,7 @@ state CRITERIA:
ctype = 'con_mark' -> CRITERION
ctype = 'title' -> CRITERION
ctype = 'urgent' -> CRITERION
ctype = 'window_type' -> CRITERION
']' -> call cmd_criteria_match_windows(); INITIAL
state CRITERION:

View File

@ -167,6 +167,7 @@ state CRITERIA:
ctype = 'window_role' -> CRITERION
ctype = 'con_id' -> CRITERION
ctype = 'id' -> CRITERION
ctype = 'window_type' -> CRITERION
ctype = 'con_mark' -> CRITERION
ctype = 'title' -> CRITERION
ctype = 'urgent' -> CRITERION

View File

@ -363,6 +363,31 @@ void cmd_criteria_add(I3_CMD, char *ctype, char *cvalue) {
return;
}
if (strcmp(ctype, "window_type") == 0) {
if (strcasecmp(cvalue, "normal") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_NORMAL;
else if (strcasecmp(cvalue, "dialog") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_DIALOG;
else if (strcasecmp(cvalue, "utility") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_UTILITY;
else if (strcasecmp(cvalue, "toolbar") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLBAR;
else if (strcasecmp(cvalue, "splash") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_SPLASH;
else if (strcasecmp(cvalue, "menu") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_MENU;
else if (strcasecmp(cvalue, "dropdown_menu") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
else if (strcasecmp(cvalue, "popup_menu") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_POPUP_MENU;
else if (strcasecmp(cvalue, "tooltip") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLTIP;
else
ELOG("unknown window_type value \"%s\"\n", cvalue);
return;
}
if (strcmp(ctype, "con_mark") == 0) {
current_match->mark = regex_new(cvalue);
return;

View File

@ -89,6 +89,31 @@ CFGFUN(criteria_add, const char *ctype, const char *cvalue) {
return;
}
if (strcmp(ctype, "window_type") == 0) {
if (strcasecmp(cvalue, "normal") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_NORMAL;
else if (strcasecmp(cvalue, "dialog") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_DIALOG;
else if (strcasecmp(cvalue, "utility") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_UTILITY;
else if (strcasecmp(cvalue, "toolbar") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLBAR;
else if (strcasecmp(cvalue, "splash") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_SPLASH;
else if (strcasecmp(cvalue, "menu") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_MENU;
else if (strcasecmp(cvalue, "dropdown_menu") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
else if (strcasecmp(cvalue, "popup_menu") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_POPUP_MENU;
else if (strcasecmp(cvalue, "tooltip") == 0)
current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLTIP;
else
ELOG("unknown window_type value \"%s\"\n", cvalue);
return;
}
if (strcmp(ctype, "con_mark") == 0) {
current_match->mark = regex_new(cvalue);
return;

View File

@ -234,6 +234,6 @@ void ewmh_setup_hints(void) {
/* Im not entirely sure if we need to keep _NET_WM_NAME on root. */
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3");
/* only send the first 24 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 24, supported_atoms);
/* only send the first 29 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 29, supported_atoms);
}

View File

@ -474,6 +474,12 @@ int main(int argc, char *argv[]) {
root_screen = xcb_aux_get_screen(conn, conn_screen);
root = root_screen->root;
/* Place requests for the atoms we need as soon as possible */
#define xmacro(atom) \
xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
#include "atoms.xmacro"
#undef xmacro
/* By default, we use the same depth and visual as the root window, which
* usually is TrueColor (24 bit depth) and the corresponding visual.
* However, we also check if a 32 bit depth and visual are available (for
@ -491,6 +497,20 @@ int main(int argc, char *argv[]) {
xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(conn, root);
xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(conn, root);
/* Setup NetWM atoms */
#define xmacro(name) \
do { \
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name##_cookie, NULL); \
if (!reply) { \
ELOG("Could not get atom " #name "\n"); \
exit(-1); \
} \
A_##name = reply->atom; \
free(reply); \
} while (0);
#include "atoms.xmacro"
#undef xmacro
load_configuration(conn, override_configpath, false);
if (config.ipc_socket_path == NULL) {
@ -512,12 +532,6 @@ int main(int argc, char *argv[]) {
}
DLOG("root geometry reply: (%d, %d) %d x %d\n", greply->x, greply->y, greply->width, greply->height);
/* Place requests for the atoms we need as soon as possible */
#define xmacro(atom) \
xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
#include "atoms.xmacro"
#undef xmacro
xcursor_load_cursors();
/* Set a cursor for the root window (otherwise the root window will show no
@ -547,20 +561,6 @@ int main(int argc, char *argv[]) {
restore_connect();
/* Setup NetWM atoms */
#define xmacro(name) \
do { \
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name##_cookie, NULL); \
if (!reply) { \
ELOG("Could not get atom " #name "\n"); \
exit(-1); \
} \
A_##name = reply->atom; \
free(reply); \
} while (0);
#include "atoms.xmacro"
#undef xmacro
property_handlers_init();
ewmh_setup_hints();

View File

@ -210,6 +210,9 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
/* check if the window needs WM_TAKE_FOCUS */
cwindow->needs_take_focus = window_supports_protocol(cwindow->id, A_WM_TAKE_FOCUS);
/* read the preferred _NET_WM_WINDOW_TYPE atom */
cwindow->window_type = xcb_get_preferred_window_type(type_reply);
/* Where to start searching for a container that swallows the new one? */
Con *search_at = croot;

View File

@ -27,8 +27,10 @@
*/
void match_init(Match *match) {
memset(match, 0, sizeof(Match));
match->dock = -1;
match->dock = M_DONTCHECK;
match->urgent = U_DONTCHECK;
/* we use this as the placeholder value for "not set". */
match->window_type = UINT32_MAX;
}
/*
@ -48,6 +50,7 @@ bool match_is_empty(Match *match) {
match->window_role == NULL &&
match->urgent == U_DONTCHECK &&
match->id == XCB_NONE &&
match->window_type == UINT32_MAX &&
match->con_id == NULL &&
match->dock == -1 &&
match->floating == M_ANY);
@ -129,6 +132,14 @@ bool match_matches_window(Match *match, i3Window *window) {
}
}
if (match->window_type != UINT32_MAX) {
if (window->window_type == match->window_type) {
LOG("window_type matches (%i)\n", match->window_type);
} else {
return false;
}
}
Con *con = NULL;
if (match->urgent == U_LATEST) {
/* if the window isn't urgent, no sense in searching */
@ -161,7 +172,7 @@ bool match_matches_window(Match *match, i3Window *window) {
LOG("urgent matches oldest\n");
}
if (match->dock != -1) {
if (match->dock != M_DONTCHECK) {
if ((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
(window->dock == W_DOCK_BOTTOM && match->dock == M_DOCK_BOTTOM) ||
((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&

View File

@ -154,6 +154,35 @@ void xcb_set_window_rect(xcb_connection_t *conn, xcb_window_t window, Rect r) {
add_ignore_event(cookie.sequence, -1);
}
/*
* Returns the first supported _NET_WM_WINDOW_TYPE atom.
*
*/
xcb_atom_t xcb_get_preferred_window_type(xcb_get_property_reply_t *reply) {
if (reply == NULL || xcb_get_property_value_length(reply) == 0)
return XCB_NONE;
xcb_atom_t *atoms;
if ((atoms = xcb_get_property_value(reply)) == NULL)
return XCB_NONE;
for (int i = 0; i < xcb_get_property_value_length(reply) / (reply->format / 8); i++) {
if (atoms[i] == A__NET_WM_WINDOW_TYPE_NORMAL ||
atoms[i] == A__NET_WM_WINDOW_TYPE_DIALOG ||
atoms[i] == A__NET_WM_WINDOW_TYPE_UTILITY ||
atoms[i] == A__NET_WM_WINDOW_TYPE_TOOLBAR ||
atoms[i] == A__NET_WM_WINDOW_TYPE_SPLASH ||
atoms[i] == A__NET_WM_WINDOW_TYPE_MENU ||
atoms[i] == A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU ||
atoms[i] == A__NET_WM_WINDOW_TYPE_POPUP_MENU ||
atoms[i] == A__NET_WM_WINDOW_TYPE_TOOLTIP) {
return atoms[i];
}
}
return XCB_NONE;
}
/*
* Returns true if the given reply contains the given atom.
*