Merge pull request #1665 from Airblader/feature-1658
Added criterion 'window_type'
This commit is contained in:
commit
67ec2333ee
|
@ -1511,6 +1511,10 @@ instance::
|
||||||
Compares the window instance (the first part of WM_CLASS)
|
Compares the window instance (the first part of WM_CLASS)
|
||||||
window_role::
|
window_role::
|
||||||
Compares the window role (WM_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::
|
id::
|
||||||
Compares the X11 window ID, which you can get via +xwininfo+ for example.
|
Compares the X11 window ID, which you can get via +xwininfo+ for example.
|
||||||
title::
|
title::
|
||||||
|
|
|
@ -7,11 +7,16 @@ xmacro(_NET_WM_STATE_DEMANDS_ATTENTION)
|
||||||
xmacro(_NET_WM_STATE_MODAL)
|
xmacro(_NET_WM_STATE_MODAL)
|
||||||
xmacro(_NET_WM_STATE)
|
xmacro(_NET_WM_STATE)
|
||||||
xmacro(_NET_WM_WINDOW_TYPE)
|
xmacro(_NET_WM_WINDOW_TYPE)
|
||||||
|
xmacro(_NET_WM_WINDOW_TYPE_NORMAL)
|
||||||
xmacro(_NET_WM_WINDOW_TYPE_DOCK)
|
xmacro(_NET_WM_WINDOW_TYPE_DOCK)
|
||||||
xmacro(_NET_WM_WINDOW_TYPE_DIALOG)
|
xmacro(_NET_WM_WINDOW_TYPE_DIALOG)
|
||||||
xmacro(_NET_WM_WINDOW_TYPE_UTILITY)
|
xmacro(_NET_WM_WINDOW_TYPE_UTILITY)
|
||||||
xmacro(_NET_WM_WINDOW_TYPE_TOOLBAR)
|
xmacro(_NET_WM_WINDOW_TYPE_TOOLBAR)
|
||||||
xmacro(_NET_WM_WINDOW_TYPE_SPLASH)
|
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_DESKTOP)
|
||||||
xmacro(_NET_WM_STRUT_PARTIAL)
|
xmacro(_NET_WM_STRUT_PARTIAL)
|
||||||
xmacro(_NET_CLIENT_LIST)
|
xmacro(_NET_CLIENT_LIST)
|
||||||
|
|
|
@ -382,6 +382,9 @@ struct Window {
|
||||||
* default will be 'accepts focus'. */
|
* default will be 'accepts focus'. */
|
||||||
bool doesnt_accept_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 */
|
/** Whether the window says it is a dock window */
|
||||||
enum { W_NODOCK = 0,
|
enum { W_NODOCK = 0,
|
||||||
W_DOCK_TOP = 1,
|
W_DOCK_TOP = 1,
|
||||||
|
@ -412,6 +415,7 @@ struct Match {
|
||||||
struct regex *instance;
|
struct regex *instance;
|
||||||
struct regex *mark;
|
struct regex *mark;
|
||||||
struct regex *window_role;
|
struct regex *window_role;
|
||||||
|
xcb_atom_t window_type;
|
||||||
enum {
|
enum {
|
||||||
U_DONTCHECK = -1,
|
U_DONTCHECK = -1,
|
||||||
U_LATEST = 0,
|
U_LATEST = 0,
|
||||||
|
|
|
@ -56,6 +56,12 @@ void window_update_strut_partial(i3Window *win, xcb_get_property_reply_t *prop);
|
||||||
*/
|
*/
|
||||||
void window_update_role(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt);
|
void window_update_role(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the _NET_WM_WINDOW_TYPE property.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void window_update_type(i3Window *window, xcb_get_property_reply_t *reply);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the WM_HINTS (we only care about the input focus handling part).
|
* Updates the WM_HINTS (we only care about the input focus handling part).
|
||||||
*
|
*
|
||||||
|
|
|
@ -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);
|
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);
|
bool xcb_reply_contains_atom(xcb_get_property_reply_t *prop, xcb_atom_t atom);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -41,14 +41,15 @@ state INITIAL:
|
||||||
'bar' -> BAR
|
'bar' -> BAR
|
||||||
|
|
||||||
state CRITERIA:
|
state CRITERIA:
|
||||||
ctype = 'class' -> CRITERION
|
ctype = 'class' -> CRITERION
|
||||||
ctype = 'instance' -> CRITERION
|
ctype = 'instance' -> CRITERION
|
||||||
ctype = 'window_role' -> CRITERION
|
ctype = 'window_role' -> CRITERION
|
||||||
ctype = 'con_id' -> CRITERION
|
ctype = 'con_id' -> CRITERION
|
||||||
ctype = 'id' -> CRITERION
|
ctype = 'id' -> CRITERION
|
||||||
ctype = 'con_mark' -> CRITERION
|
ctype = 'window_type' -> CRITERION
|
||||||
ctype = 'title' -> CRITERION
|
ctype = 'con_mark' -> CRITERION
|
||||||
ctype = 'urgent' -> CRITERION
|
ctype = 'title' -> CRITERION
|
||||||
|
ctype = 'urgent' -> CRITERION
|
||||||
']' -> call cmd_criteria_match_windows(); INITIAL
|
']' -> call cmd_criteria_match_windows(); INITIAL
|
||||||
|
|
||||||
state CRITERION:
|
state CRITERION:
|
||||||
|
|
|
@ -167,6 +167,7 @@ state CRITERIA:
|
||||||
ctype = 'window_role' -> CRITERION
|
ctype = 'window_role' -> CRITERION
|
||||||
ctype = 'con_id' -> CRITERION
|
ctype = 'con_id' -> CRITERION
|
||||||
ctype = 'id' -> CRITERION
|
ctype = 'id' -> CRITERION
|
||||||
|
ctype = 'window_type' -> CRITERION
|
||||||
ctype = 'con_mark' -> CRITERION
|
ctype = 'con_mark' -> CRITERION
|
||||||
ctype = 'title' -> CRITERION
|
ctype = 'title' -> CRITERION
|
||||||
ctype = 'urgent' -> CRITERION
|
ctype = 'urgent' -> CRITERION
|
||||||
|
|
|
@ -363,6 +363,31 @@ void cmd_criteria_add(I3_CMD, char *ctype, char *cvalue) {
|
||||||
return;
|
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) {
|
if (strcmp(ctype, "con_mark") == 0) {
|
||||||
current_match->mark = regex_new(cvalue);
|
current_match->mark = regex_new(cvalue);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -89,6 +89,31 @@ CFGFUN(criteria_add, const char *ctype, const char *cvalue) {
|
||||||
return;
|
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) {
|
if (strcmp(ctype, "con_mark") == 0) {
|
||||||
current_match->mark = regex_new(cvalue);
|
current_match->mark = regex_new(cvalue);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -234,6 +234,6 @@ void ewmh_setup_hints(void) {
|
||||||
/* I’m not entirely sure if we need to keep _NET_WM_NAME on root. */
|
/* I’m 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");
|
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 */
|
/* 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, 24, supported_atoms);
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 29, supported_atoms);
|
||||||
}
|
}
|
||||||
|
|
|
@ -892,15 +892,15 @@ static void handle_client_message(xcb_client_message_event_t *event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
bool handle_window_type(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
||||||
int handle_window_type(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
xcb_atom_t atom, xcb_get_property_reply_t *reply) {
|
||||||
xcb_atom_t atom, xcb_get_property_reply_t *property) {
|
Con *con;
|
||||||
/* TODO: Implement this one. To do this, implement a little test program which sleep(1)s
|
if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
|
||||||
before changing this property. */
|
return false;
|
||||||
ELOG("_NET_WM_WINDOW_TYPE changed, this is not yet implemented.\n");
|
|
||||||
return 0;
|
window_update_type(con->window, reply);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handles the size hints set by a window, but currently only the part necessary for displaying
|
* Handles the size hints set by a window, but currently only the part necessary for displaying
|
||||||
|
@ -1264,7 +1264,8 @@ static struct property_handler_t property_handlers[] = {
|
||||||
{0, UINT_MAX, handle_transient_for},
|
{0, UINT_MAX, handle_transient_for},
|
||||||
{0, 128, handle_windowrole_change},
|
{0, 128, handle_windowrole_change},
|
||||||
{0, 128, handle_class_change},
|
{0, 128, handle_class_change},
|
||||||
{0, UINT_MAX, handle_strut_partial_change}};
|
{0, UINT_MAX, handle_strut_partial_change},
|
||||||
|
{0, UINT_MAX, handle_window_type}};
|
||||||
#define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))
|
#define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1284,6 +1285,7 @@ void property_handlers_init(void) {
|
||||||
property_handlers[6].atom = A_WM_WINDOW_ROLE;
|
property_handlers[6].atom = A_WM_WINDOW_ROLE;
|
||||||
property_handlers[7].atom = XCB_ATOM_WM_CLASS;
|
property_handlers[7].atom = XCB_ATOM_WM_CLASS;
|
||||||
property_handlers[8].atom = A__NET_WM_STRUT_PARTIAL;
|
property_handlers[8].atom = A__NET_WM_STRUT_PARTIAL;
|
||||||
|
property_handlers[9].atom = A__NET_WM_WINDOW_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) {
|
static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) {
|
||||||
|
|
40
src/main.c
40
src/main.c
|
@ -474,6 +474,12 @@ int main(int argc, char *argv[]) {
|
||||||
root_screen = xcb_aux_get_screen(conn, conn_screen);
|
root_screen = xcb_aux_get_screen(conn, conn_screen);
|
||||||
root = root_screen->root;
|
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
|
/* By default, we use the same depth and visual as the root window, which
|
||||||
* usually is TrueColor (24 bit depth) and the corresponding visual.
|
* usually is TrueColor (24 bit depth) and the corresponding visual.
|
||||||
* However, we also check if a 32 bit depth and visual are available (for
|
* 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_get_geometry_cookie_t gcookie = xcb_get_geometry(conn, root);
|
||||||
xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(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);
|
load_configuration(conn, override_configpath, false);
|
||||||
|
|
||||||
if (config.ipc_socket_path == NULL) {
|
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);
|
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();
|
xcursor_load_cursors();
|
||||||
|
|
||||||
/* Set a cursor for the root window (otherwise the root window will show no
|
/* 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();
|
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();
|
property_handlers_init();
|
||||||
|
|
||||||
ewmh_setup_hints();
|
ewmh_setup_hints();
|
||||||
|
|
|
@ -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 */
|
/* check if the window needs WM_TAKE_FOCUS */
|
||||||
cwindow->needs_take_focus = window_supports_protocol(cwindow->id, A_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? */
|
/* Where to start searching for a container that swallows the new one? */
|
||||||
Con *search_at = croot;
|
Con *search_at = croot;
|
||||||
|
|
||||||
|
|
15
src/match.c
15
src/match.c
|
@ -27,8 +27,10 @@
|
||||||
*/
|
*/
|
||||||
void match_init(Match *match) {
|
void match_init(Match *match) {
|
||||||
memset(match, 0, sizeof(Match));
|
memset(match, 0, sizeof(Match));
|
||||||
match->dock = -1;
|
match->dock = M_DONTCHECK;
|
||||||
match->urgent = U_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->window_role == NULL &&
|
||||||
match->urgent == U_DONTCHECK &&
|
match->urgent == U_DONTCHECK &&
|
||||||
match->id == XCB_NONE &&
|
match->id == XCB_NONE &&
|
||||||
|
match->window_type == UINT32_MAX &&
|
||||||
match->con_id == NULL &&
|
match->con_id == NULL &&
|
||||||
match->dock == -1 &&
|
match->dock == -1 &&
|
||||||
match->floating == M_ANY);
|
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;
|
Con *con = NULL;
|
||||||
if (match->urgent == U_LATEST) {
|
if (match->urgent == U_LATEST) {
|
||||||
/* if the window isn't urgent, no sense in searching */
|
/* 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");
|
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) ||
|
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_BOTTOM && match->dock == M_DOCK_BOTTOM) ||
|
||||||
((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&
|
((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&
|
||||||
|
|
17
src/window.c
17
src/window.c
|
@ -232,6 +232,23 @@ void window_update_role(i3Window *win, xcb_get_property_reply_t *prop, bool befo
|
||||||
free(prop);
|
free(prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Updates the _NET_WM_WINDOW_TYPE property.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void window_update_type(i3Window *window, xcb_get_property_reply_t *reply) {
|
||||||
|
xcb_atom_t new_type = xcb_get_preferred_window_type(reply);
|
||||||
|
if (new_type == XCB_NONE) {
|
||||||
|
DLOG("cannot read _NET_WM_WINDOW_TYPE from window.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->window_type = new_type;
|
||||||
|
LOG("_NET_WM_WINDOW_TYPE changed to %i", window->window_type);
|
||||||
|
|
||||||
|
run_assignments(window);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Updates the WM_HINTS (we only care about the input focus handling part).
|
* Updates the WM_HINTS (we only care about the input focus handling part).
|
||||||
*
|
*
|
||||||
|
|
29
src/xcb.c
29
src/xcb.c
|
@ -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);
|
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.
|
* Returns true if the given reply contains the given atom.
|
||||||
*
|
*
|
||||||
|
|
|
@ -287,9 +287,6 @@ exit_gracefully($pid);
|
||||||
# 8: check that the role criterion works properly
|
# 8: check that the role criterion works properly
|
||||||
##############################################################
|
##############################################################
|
||||||
|
|
||||||
# this configuration is broken because "asdf" is not a valid integer
|
|
||||||
# the for_window should therefore recognize this error and don’t add the
|
|
||||||
# assignment
|
|
||||||
$config = <<EOT;
|
$config = <<EOT;
|
||||||
# i3 config file (v4)
|
# i3 config file (v4)
|
||||||
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||||
|
@ -329,9 +326,6 @@ exit_gracefully($pid);
|
||||||
# *after* the window has been mapped
|
# *after* the window has been mapped
|
||||||
##############################################################
|
##############################################################
|
||||||
|
|
||||||
# this configuration is broken because "asdf" is not a valid integer
|
|
||||||
# the for_window should therefore recognize this error and don’t add the
|
|
||||||
# assignment
|
|
||||||
$config = <<EOT;
|
$config = <<EOT;
|
||||||
# i3 config file (v4)
|
# i3 config file (v4)
|
||||||
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||||
|
@ -370,5 +364,77 @@ is($content[0]->{border}, 'none', 'no border (window_role 2)');
|
||||||
|
|
||||||
exit_gracefully($pid);
|
exit_gracefully($pid);
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
# 10: check that the criterion 'window_type' works
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
# test all window types
|
||||||
|
my %window_types = (
|
||||||
|
'normal' => '_NET_WM_WINDOW_TYPE_NORMAL',
|
||||||
|
'dialog' => '_NET_WM_WINDOW_TYPE_DIALOG',
|
||||||
|
'utility' => '_NET_WM_WINDOW_TYPE_UTILITY',
|
||||||
|
'toolbar' => '_NET_WM_WINDOW_TYPE_TOOLBAR',
|
||||||
|
'splash' => '_NET_WM_WINDOW_TYPE_SPLASH',
|
||||||
|
'menu' => '_NET_WM_WINDOW_TYPE_MENU',
|
||||||
|
'dropdown_menu' => '_NET_WM_WINDOW_TYPE_DROPDOWN_MENU',
|
||||||
|
'popup_menu' => '_NET_WM_WINDOW_TYPE_POPUP_MENU',
|
||||||
|
'tooltip' => '_NET_WM_WINDOW_TYPE_TOOLTIP'
|
||||||
|
);
|
||||||
|
|
||||||
|
while (my ($window_type, $atom) = each %window_types) {
|
||||||
|
|
||||||
|
$config = <<"EOT";
|
||||||
|
# i3 config file (v4)
|
||||||
|
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||||
|
for_window [window_type="$window_type"] floating enable, mark branded
|
||||||
|
EOT
|
||||||
|
|
||||||
|
$pid = launch_with_config($config);
|
||||||
|
$tmp = fresh_workspace;
|
||||||
|
|
||||||
|
$window = open_window(window_type => $x->atom(name => $atom));
|
||||||
|
|
||||||
|
my @nodes = @{get_ws($tmp)->{floating_nodes}};
|
||||||
|
cmp_ok(@nodes, '==', 1, 'one floating container on this workspace');
|
||||||
|
is($nodes[0]->{nodes}[0]->{mark}, 'branded', "mark set (window_type = $atom)");
|
||||||
|
|
||||||
|
exit_gracefully($pid);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
# 11: check that the criterion 'window_type' works if the
|
||||||
|
# _NET_WM_WINDOW_TYPE is changed after managing.
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
while (my ($window_type, $atom) = each %window_types) {
|
||||||
|
|
||||||
|
$config = <<"EOT";
|
||||||
|
# i3 config file (v4)
|
||||||
|
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||||
|
for_window [window_type="$window_type"] floating enable, mark branded
|
||||||
|
EOT
|
||||||
|
|
||||||
|
$pid = launch_with_config($config);
|
||||||
|
$tmp = fresh_workspace;
|
||||||
|
|
||||||
|
$window = open_window();
|
||||||
|
|
||||||
|
my $atomname = $x->atom(name => '_NET_WM_WINDOW_TYPE');
|
||||||
|
my $atomtype = $x->atom(name => 'ATOM');
|
||||||
|
$x->change_property(PROP_MODE_REPLACE, $window->id, $atomname->id, $atomtype->id,
|
||||||
|
32, 1, pack('L1', $x->atom(name => $atom)->id));
|
||||||
|
$x->flush;
|
||||||
|
sync_with_i3;
|
||||||
|
|
||||||
|
my @nodes = @{get_ws($tmp)->{floating_nodes}};
|
||||||
|
cmp_ok(@nodes, '==', 1, 'one floating container on this workspace');
|
||||||
|
is($nodes[0]->{nodes}[0]->{mark}, 'branded', "mark set (window_type = $atom)");
|
||||||
|
|
||||||
|
exit_gracefully($pid);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
|
||||||
done_testing;
|
done_testing;
|
||||||
|
|
|
@ -18,20 +18,61 @@
|
||||||
# Bug still in: 4.8-16-g6888a1f
|
# Bug still in: 4.8-16-g6888a1f
|
||||||
use i3test;
|
use i3test;
|
||||||
|
|
||||||
my $ws = fresh_workspace;
|
my ($ws, $win1, $win2, $win3, $ws_con);
|
||||||
|
|
||||||
my $win1 = open_window;
|
###############################################################################
|
||||||
my $win2 = open_window;
|
# Tets moving with 'id' criterion.
|
||||||
my $win3 = open_window;
|
###############################################################################
|
||||||
|
|
||||||
|
$ws = fresh_workspace;
|
||||||
|
|
||||||
|
$win1 = open_window;
|
||||||
|
$win2 = open_window;
|
||||||
|
$win3 = open_window;
|
||||||
|
|
||||||
# move win1 from the left to the right
|
# move win1 from the left to the right
|
||||||
cmd '[id="' . $win1->{id} . '"] move right';
|
cmd '[id="' . $win1->{id} . '"] move right';
|
||||||
|
|
||||||
# now they should be switched, with win2 still being focused
|
# now they should be switched, with win2 still being focused
|
||||||
my $ws_con = get_ws($ws);
|
$ws_con = get_ws($ws);
|
||||||
|
|
||||||
# win2 should be on the left
|
# win2 should be on the left
|
||||||
is($ws_con->{nodes}[0]->{window}, $win2->{id}, 'the `move [direction]` command should work with criteria');
|
is($ws_con->{nodes}[0]->{window}, $win2->{id}, 'the `move [direction]` command should work with criteria');
|
||||||
is($x->input_focus, $win3->{id}, 'it should not disturb focus');
|
is($x->input_focus, $win3->{id}, 'it should not disturb focus');
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Tets moving with 'window_type' criterion.
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# test all window types
|
||||||
|
my %window_types = (
|
||||||
|
'normal' => '_NET_WM_WINDOW_TYPE_NORMAL',
|
||||||
|
'dialog' => '_NET_WM_WINDOW_TYPE_DIALOG',
|
||||||
|
'utility' => '_NET_WM_WINDOW_TYPE_UTILITY',
|
||||||
|
'toolbar' => '_NET_WM_WINDOW_TYPE_TOOLBAR',
|
||||||
|
'splash' => '_NET_WM_WINDOW_TYPE_SPLASH',
|
||||||
|
'menu' => '_NET_WM_WINDOW_TYPE_MENU',
|
||||||
|
'dropdown_menu' => '_NET_WM_WINDOW_TYPE_DROPDOWN_MENU',
|
||||||
|
'popup_menu' => '_NET_WM_WINDOW_TYPE_POPUP_MENU',
|
||||||
|
'tooltip' => '_NET_WM_WINDOW_TYPE_TOOLTIP'
|
||||||
|
);
|
||||||
|
|
||||||
|
while (my ($window_type, $atom) = each %window_types) {
|
||||||
|
|
||||||
|
$ws = fresh_workspace;
|
||||||
|
|
||||||
|
$win1 = open_window(window_type => $x->atom(name => $atom));
|
||||||
|
$win2 = open_window;
|
||||||
|
$win3 = open_window;
|
||||||
|
|
||||||
|
cmd '[window_type="' . $window_type . '"] move right';
|
||||||
|
|
||||||
|
$ws_con = get_ws($ws);
|
||||||
|
is($ws_con->{nodes}[0]->{window}, $win2->{id}, 'the `move [direction]` command should work with window_type = ' . $window_type);
|
||||||
|
is($x->input_focus, $win3->{id}, 'it should not disturb focus');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
done_testing;
|
done_testing;
|
||||||
|
|
Loading…
Reference in New Issue