Better detect windows that want floating
Patch status: needinfo
Patch by Kernc
Long description:
Windows matching certain criteria are floated by default. Currently, only windows of type DIALOG, UTILITY, TOOLBAR, or SPLASH were floated. This patch introduces more robust detection of what windows should be floated. Besides aforementioned types, also NORMAL windows are floated if they are either of fixed size, modal, or marked as skipping pager or taskbar, as are all other (EWMH) window types except DESKTOP and DOCK. Closes ticket #1182.
To apply this patch, use:
curl http://cr.i3wm.org/patch/421/raw.patch | git am
b/include/atoms.xmacro
25 |
@@ -3,13 +3,16 @@ xmacro(_NET_SUPPORTING_WM_CHECK) |
26 |
xmacro(_NET_WM_NAME) |
27 |
xmacro(_NET_WM_STATE_FULLSCREEN) |
28 |
xmacro(_NET_WM_STATE_DEMANDS_ATTENTION) |
29 |
+xmacro(_NET_WM_STATE_MODAL) |
30 |
+xmacro(_NET_WM_STATE_SKIP_PAGER) |
31 |
+xmacro(_NET_WM_STATE_SKIP_TASKBAR) |
32 |
xmacro(_NET_WM_STATE) |
33 |
xmacro(_NET_WM_WINDOW_TYPE) |
34 |
xmacro(_NET_WM_WINDOW_TYPE_DOCK) |
35 |
xmacro(_NET_WM_WINDOW_TYPE_DIALOG) |
36 |
xmacro(_NET_WM_WINDOW_TYPE_UTILITY) |
37 |
-xmacro(_NET_WM_WINDOW_TYPE_TOOLBAR) |
38 |
-xmacro(_NET_WM_WINDOW_TYPE_SPLASH) |
39 |
+xmacro(_NET_WM_WINDOW_TYPE_DESKTOP) |
40 |
+xmacro(_NET_WM_WINDOW_TYPE_NORMAL) |
41 |
xmacro(_NET_WM_DESKTOP) |
42 |
xmacro(_NET_WM_STRUT_PARTIAL) |
43 |
xmacro(_NET_CLIENT_LIST_STACKING) |
b/include/xcb_compat.h
48 |
@@ -19,9 +19,11 @@ |
49 |
#define XCB_ICCCM_WM_STATE_NORMAL XCB_WM_STATE_NORMAL |
50 |
#define XCB_ICCCM_WM_STATE_WITHDRAWN XCB_WM_STATE_WITHDRAWN |
51 |
#define xcb_icccm_get_wm_size_hints_from_reply xcb_get_wm_size_hints_from_reply |
52 |
+#define xcb_icccm_get_wm_size_hints_reply xcb_get_wm_size_hints_reply |
53 |
#define xcb_icccm_get_wm_normal_hints_reply xcb_get_wm_normal_hints_reply |
54 |
#define xcb_icccm_get_wm_normal_hints_unchecked xcb_get_wm_normal_hints_unchecked |
55 |
#define XCB_ICCCM_SIZE_HINT_P_MIN_SIZE XCB_SIZE_HINT_P_MIN_SIZE |
56 |
+#define XCB_ICCCM_SIZE_HINT_P_MAX_SIZE XCB_SIZE_HINT_P_MAX_SIZE |
57 |
#define XCB_ICCCM_SIZE_HINT_P_RESIZE_INC XCB_SIZE_HINT_P_RESIZE_INC |
58 |
#define XCB_ICCCM_SIZE_HINT_BASE_SIZE XCB_SIZE_HINT_BASE_SIZE |
59 |
#define XCB_ICCCM_SIZE_HINT_P_ASPECT XCB_SIZE_HINT_P_ASPECT |
b/src/manage.c
64 |
@@ -105,6 +105,41 @@ static void ipc_send_window_new_event(Con *con) { |
65 |
} |
66 |
|
67 |
/* |
68 |
+ * Hint whether window should be floating by default or not. |
69 |
+ * |
70 |
+ */ |
71 |
+static bool is_window_of_floating_type(xcb_window_t window, |
72 |
+ xcb_get_property_reply_t *type_reply, |
73 |
+ xcb_get_property_reply_t *state_reply) { |
74 |
+ /* Never float desktop or docks. */ |
75 |
+ if (xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_DOCK) || |
76 |
+ xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_DESKTOP)) |
77 |
+ return false; |
78 |
+ |
79 |
+ /* Only float normal windows if they are either of fixed size, modal, |
80 |
+ * or marked as skip taskbar/pager. */ |
81 |
+ if (xcb_get_property_value_length(type_reply) == 0 || /* type not specified => NORMAL */ |
82 |
+ xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_NORMAL)) { |
83 |
+ xcb_size_hints_t size_hints; |
84 |
+ if (xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_MODAL) || |
85 |
+ xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_SKIP_PAGER) || |
86 |
+ xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_SKIP_TASKBAR) || |
87 |
+ (xcb_icccm_get_wm_size_hints_reply(conn, xcb_icccm_get_wm_normal_hints_unchecked(conn, window), &size_hints, NULL) && |
88 |
+ size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE && |
89 |
+ size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE && |
90 |
+ size_hints.min_width == size_hints.max_width && |
91 |
+ size_hints.min_height == size_hints.max_height)) |
92 |
+ return true; |
93 |
+ return false; |
94 |
+ } |
95 |
+ |
96 |
+ /* Other windows are floating. Some are typically override_redirect |
97 |
+ * windows (and thus not even managed), but not necessarily. See: |
98 |
+ * http://standards.freedesktop.org/wm-spec/latest/ar01s05.html#idp1333344 */ |
99 |
+ return true; |
100 |
+} |
101 |
+ |
102 |
+/* |
103 |
* Do some sanity checks and then reparent the window. |
104 |
* |
105 |
*/ |
106 |
@@ -238,8 +273,8 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki |
107 |
/* Where to start searching for a container that swallows the new one? */ |
108 |
Con *search_at = croot; |
109 |
|
110 |
- xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, wm_type_cookie, NULL); |
111 |
- if (xcb_reply_contains_atom(reply, A__NET_WM_WINDOW_TYPE_DOCK)) { |
112 |
+ xcb_get_property_reply_t *type_reply = xcb_get_property_reply(conn, wm_type_cookie, NULL); |
113 |
+ if (xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_DOCK)) { |
114 |
LOG("This window is of type dock\n"); |
115 |
Output *output = get_output_containing(geom->x, geom->y); |
116 |
if (output != NULL) { |
117 |
@@ -358,8 +393,6 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki |
118 |
con_toggle_fullscreen(nc, CF_OUTPUT); |
119 |
} |
120 |
|
121 |
- FREE(state_reply); |
122 |
- |
123 |
if (fs == NULL) { |
124 |
DLOG("Not in fullscreen mode, focusing\n"); |
125 |
if (!cwindow->dock) { |
126 |
@@ -392,15 +425,13 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki |
127 |
|
128 |
/* set floating if necessary */ |
129 |
bool want_floating = false; |
130 |
- if (xcb_reply_contains_atom(reply, A__NET_WM_WINDOW_TYPE_DIALOG) || |
131 |
- xcb_reply_contains_atom(reply, A__NET_WM_WINDOW_TYPE_UTILITY) || |
132 |
- xcb_reply_contains_atom(reply, A__NET_WM_WINDOW_TYPE_TOOLBAR) || |
133 |
- xcb_reply_contains_atom(reply, A__NET_WM_WINDOW_TYPE_SPLASH)) { |
134 |
- LOG("This window is a dialog window, setting floating\n"); |
135 |
+ if (is_window_of_floating_type(window, type_reply, state_reply)) { |
136 |
+ LOG("This window is of a floating window type, setting floating\n"); |
137 |
want_floating = true; |
138 |
} |
139 |
|
140 |
- FREE(reply); |
141 |
+ FREE(state_reply); |
142 |
+ FREE(type_reply); |
143 |
|
144 |
if (cwindow->transient_for != XCB_NONE || |
145 |
(cwindow->leader != XCB_NONE && |