1 /* wmspec.c-- support for the wm-spec Hints
3 * Window Maker window manager
5 * Copyright (c) 1998-2003 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * This file needs to be checked for all calls to XGetWindowProperty() and
27 * proper checks need to be made on the returned values. Only checking for
28 * return to be Success is not enough. -Dan
34 #include <X11/Xatom.h>
37 #include <WINGs/WUtil.h>
38 #include "WindowMaker.h"
41 #include "workspace.h"
50 #include "properties.h"
53 /* Root Window Properties */
54 static Atom net_supported
;
55 static Atom net_client_list
;
56 static Atom net_client_list_stacking
;
57 static Atom net_number_of_desktops
;
58 static Atom net_desktop_geometry
;
59 static Atom net_desktop_viewport
;
60 static Atom net_current_desktop
;
61 static Atom net_desktop_names
;
62 static Atom net_active_window
;
63 static Atom net_workarea
;
64 static Atom net_supporting_wm_check
;
65 static Atom net_virtual_roots
; /* N/A */
66 static Atom net_desktop_layout
; /* XXX */
67 static Atom net_showing_desktop
;
69 /* Other Root Window Messages */
70 static Atom net_close_window
;
71 static Atom net_moveresize_window
; /* TODO */
72 static Atom net_wm_moveresize
; /* TODO */
74 /* Application Window Properties */
75 static Atom net_wm_name
;
76 static Atom net_wm_visible_name
; /* TODO (unnecessary?) */
77 static Atom net_wm_icon_name
;
78 static Atom net_wm_visible_icon_name
; /* TODO (unnecessary?) */
79 static Atom net_wm_desktop
;
81 static Atom net_wm_fullscreen_monitors
;
83 static Atom net_wm_window_type
;
84 static Atom net_wm_window_type_desktop
;
85 static Atom net_wm_window_type_dock
;
86 static Atom net_wm_window_type_toolbar
;
87 static Atom net_wm_window_type_menu
;
88 static Atom net_wm_window_type_utility
;
89 static Atom net_wm_window_type_splash
;
90 static Atom net_wm_window_type_dialog
;
91 static Atom net_wm_window_type_dropdown_menu
;
92 static Atom net_wm_window_type_popup_menu
;
93 static Atom net_wm_window_type_tooltip
;
94 static Atom net_wm_window_type_notification
;
95 static Atom net_wm_window_type_combo
;
96 static Atom net_wm_window_type_dnd
;
97 static Atom net_wm_window_type_normal
;
98 static Atom net_wm_state
;
99 static Atom net_wm_state_modal
; /* XXX: what is this?!? */
100 static Atom net_wm_state_sticky
;
101 static Atom net_wm_state_maximized_vert
;
102 static Atom net_wm_state_maximized_horz
;
103 static Atom net_wm_state_shaded
;
104 static Atom net_wm_state_skip_taskbar
;
105 static Atom net_wm_state_skip_pager
;
106 static Atom net_wm_state_hidden
;
107 static Atom net_wm_state_fullscreen
;
108 static Atom net_wm_state_above
;
109 static Atom net_wm_state_below
;
110 static Atom net_wm_state_focused
;
111 static Atom net_wm_allowed_actions
;
112 static Atom net_wm_action_move
;
113 static Atom net_wm_action_resize
;
114 static Atom net_wm_action_minimize
;
115 static Atom net_wm_action_shade
;
116 static Atom net_wm_action_stick
;
117 static Atom net_wm_action_maximize_horz
;
118 static Atom net_wm_action_maximize_vert
;
119 static Atom net_wm_action_fullscreen
;
120 static Atom net_wm_action_change_desktop
;
121 static Atom net_wm_action_close
;
122 static Atom net_wm_strut
;
123 static Atom net_wm_strut_partial
; /* TODO: doesn't really fit into the current strut scheme */
124 static Atom net_wm_icon_geometry
; /* FIXME: should work together with net_wm_handled_icons, gnome-panel-2.2.0.1 doesn't use _NET_WM_HANDLED_ICONS, thus present situation. */
125 static Atom net_wm_icon
;
126 static Atom net_wm_pid
; /* TODO */
127 static Atom net_wm_handled_icons
; /* FIXME: see net_wm_icon_geometry */
128 static Atom net_wm_window_opacity
;
130 static Atom net_frame_extents
;
132 /* Window Manager Protocols */
133 static Atom net_wm_ping
; /* TODO */
135 static Atom utf8_string
;
142 static atomitem_t atomNames
[] = {
143 {"_NET_SUPPORTED", &net_supported
},
144 {"_NET_CLIENT_LIST", &net_client_list
},
145 {"_NET_CLIENT_LIST_STACKING", &net_client_list_stacking
},
146 {"_NET_NUMBER_OF_DESKTOPS", &net_number_of_desktops
},
147 {"_NET_DESKTOP_GEOMETRY", &net_desktop_geometry
},
148 {"_NET_DESKTOP_VIEWPORT", &net_desktop_viewport
},
149 {"_NET_CURRENT_DESKTOP", &net_current_desktop
},
150 {"_NET_DESKTOP_NAMES", &net_desktop_names
},
151 {"_NET_ACTIVE_WINDOW", &net_active_window
},
152 {"_NET_WORKAREA", &net_workarea
},
153 {"_NET_SUPPORTING_WM_CHECK", &net_supporting_wm_check
},
154 {"_NET_VIRTUAL_ROOTS", &net_virtual_roots
},
155 {"_NET_DESKTOP_LAYOUT", &net_desktop_layout
},
156 {"_NET_SHOWING_DESKTOP", &net_showing_desktop
},
158 {"_NET_CLOSE_WINDOW", &net_close_window
},
159 {"_NET_MOVERESIZE_WINDOW", &net_moveresize_window
},
160 {"_NET_WM_MOVERESIZE", &net_wm_moveresize
},
162 {"_NET_WM_NAME", &net_wm_name
},
163 {"_NET_WM_VISIBLE_NAME", &net_wm_visible_name
},
164 {"_NET_WM_ICON_NAME", &net_wm_icon_name
},
165 {"_NET_WM_VISIBLE_ICON_NAME", &net_wm_visible_icon_name
},
166 {"_NET_WM_DESKTOP", &net_wm_desktop
},
168 {"_NET_WM_FULLSCREEN_MONITORS", &net_wm_fullscreen_monitors
},
170 {"_NET_WM_WINDOW_TYPE", &net_wm_window_type
},
171 {"_NET_WM_WINDOW_TYPE_DESKTOP", &net_wm_window_type_desktop
},
172 {"_NET_WM_WINDOW_TYPE_DOCK", &net_wm_window_type_dock
},
173 {"_NET_WM_WINDOW_TYPE_TOOLBAR", &net_wm_window_type_toolbar
},
174 {"_NET_WM_WINDOW_TYPE_MENU", &net_wm_window_type_menu
},
175 {"_NET_WM_WINDOW_TYPE_UTILITY", &net_wm_window_type_utility
},
176 {"_NET_WM_WINDOW_TYPE_SPLASH", &net_wm_window_type_splash
},
177 {"_NET_WM_WINDOW_TYPE_DIALOG", &net_wm_window_type_dialog
},
178 {"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", &net_wm_window_type_dropdown_menu
},
179 {"_NET_WM_WINDOW_TYPE_POPUP_MENU", &net_wm_window_type_popup_menu
},
180 {"_NET_WM_WINDOW_TYPE_TOOLTIP", &net_wm_window_type_tooltip
},
181 {"_NET_WM_WINDOW_TYPE_NOTIFICATION", &net_wm_window_type_notification
},
182 {"_NET_WM_WINDOW_TYPE_COMBO", &net_wm_window_type_combo
},
183 {"_NET_WM_WINDOW_TYPE_DND", &net_wm_window_type_dnd
},
184 {"_NET_WM_WINDOW_TYPE_NORMAL", &net_wm_window_type_normal
},
185 {"_NET_WM_STATE", &net_wm_state
},
186 {"_NET_WM_STATE_MODAL", &net_wm_state_modal
},
187 {"_NET_WM_STATE_STICKY", &net_wm_state_sticky
},
188 {"_NET_WM_STATE_MAXIMIZED_VERT", &net_wm_state_maximized_vert
},
189 {"_NET_WM_STATE_MAXIMIZED_HORZ", &net_wm_state_maximized_horz
},
190 {"_NET_WM_STATE_SHADED", &net_wm_state_shaded
},
191 {"_NET_WM_STATE_SKIP_TASKBAR", &net_wm_state_skip_taskbar
},
192 {"_NET_WM_STATE_SKIP_PAGER", &net_wm_state_skip_pager
},
193 {"_NET_WM_STATE_HIDDEN", &net_wm_state_hidden
},
194 {"_NET_WM_STATE_FULLSCREEN", &net_wm_state_fullscreen
},
195 {"_NET_WM_STATE_ABOVE", &net_wm_state_above
},
196 {"_NET_WM_STATE_BELOW", &net_wm_state_below
},
197 {"_NET_WM_STATE_FOCUSED", &net_wm_state_focused
},
198 {"_NET_WM_ALLOWED_ACTIONS", &net_wm_allowed_actions
},
199 {"_NET_WM_ACTION_MOVE", &net_wm_action_move
},
200 {"_NET_WM_ACTION_RESIZE", &net_wm_action_resize
},
201 {"_NET_WM_ACTION_MINIMIZE", &net_wm_action_minimize
},
202 {"_NET_WM_ACTION_SHADE", &net_wm_action_shade
},
203 {"_NET_WM_ACTION_STICK", &net_wm_action_stick
},
204 {"_NET_WM_ACTION_MAXIMIZE_HORZ", &net_wm_action_maximize_horz
},
205 {"_NET_WM_ACTION_MAXIMIZE_VERT", &net_wm_action_maximize_vert
},
206 {"_NET_WM_ACTION_FULLSCREEN", &net_wm_action_fullscreen
},
207 {"_NET_WM_ACTION_CHANGE_DESKTOP", &net_wm_action_change_desktop
},
208 {"_NET_WM_ACTION_CLOSE", &net_wm_action_close
},
209 {"_NET_WM_STRUT", &net_wm_strut
},
210 {"_NET_WM_STRUT_PARTIAL", &net_wm_strut_partial
},
211 {"_NET_WM_ICON_GEOMETRY", &net_wm_icon_geometry
},
212 {"_NET_WM_ICON", &net_wm_icon
},
213 {"_NET_WM_PID", &net_wm_pid
},
214 {"_NET_WM_HANDLED_ICONS", &net_wm_handled_icons
},
215 {"_NET_WM_WINDOW_OPACITY", &net_wm_window_opacity
},
217 {"_NET_FRAME_EXTENTS", &net_frame_extents
},
219 {"_NET_WM_PING", &net_wm_ping
},
221 {"UTF8_STRING", &utf8_string
},
224 #define _NET_WM_STATE_ADD 1
225 #define _NET_WM_STATE_TOGGLE 2
229 * These constant provide information on the kind of window move/resize when
230 * it is initiated by the application instead of by WindowMaker. They are
231 * parameter for the client message _NET_WM_MOVERESIZE, as defined by the
232 * FreeDesktop wm-spec standard:
233 * http://standards.freedesktop.org/wm-spec/1.5/ar01s04.html
235 * Today, WindowMaker does not support this at all (the corresponding Atom
236 * is not added to the list in setSupportedHints), probably because there is
237 * nothing it needs to do about it, the application is assumed to know what
238 * it is doing, and WindowMaker won't get in the way.
240 * The definition of the constants (taken from the standard) are disabled to
241 * avoid a spurious warning (-Wunused-macros).
243 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
244 #define _NET_WM_MOVERESIZE_SIZE_TOP 1
245 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
246 #define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
247 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
248 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
249 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
250 #define _NET_WM_MOVERESIZE_SIZE_LEFT 7
251 #define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */
252 #define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */
253 #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
256 static void observer(void *self
, WMNotification
*notif
);
257 static void wsobserver(void *self
, WMNotification
*notif
);
259 static void updateClientList(WScreen
*scr
);
260 static void updateClientListStacking(WScreen
*scr
, WWindow
*);
262 static void updateWorkspaceNames(WScreen
*scr
);
263 static void updateCurrentWorkspace(WScreen
*scr
);
264 static void updateWorkspaceCount(WScreen
*scr
);
265 static void wNETWMShowingDesktop(WScreen
*scr
, Bool show
);
267 typedef struct NetData
{
269 WReservedArea
*strut
;
270 WWindow
**show_desktop
;
273 static void setSupportedHints(WScreen
*scr
)
275 Atom atom
[wlengthof(atomNames
)];
278 /* set supported hints list */
279 /* XXX: extend this !!! */
281 atom
[i
++] = net_client_list
;
282 atom
[i
++] = net_client_list_stacking
;
283 atom
[i
++] = net_number_of_desktops
;
284 atom
[i
++] = net_desktop_geometry
;
285 atom
[i
++] = net_desktop_viewport
;
286 atom
[i
++] = net_current_desktop
;
287 atom
[i
++] = net_desktop_names
;
288 atom
[i
++] = net_active_window
;
289 atom
[i
++] = net_workarea
;
290 atom
[i
++] = net_supporting_wm_check
;
291 atom
[i
++] = net_showing_desktop
;
293 atom
[i
++] = net_wm_moveresize
;
295 atom
[i
++] = net_wm_desktop
;
297 atom
[i
++] = net_wm_fullscreen_monitors
;
299 atom
[i
++] = net_wm_window_type
;
300 atom
[i
++] = net_wm_window_type_desktop
;
301 atom
[i
++] = net_wm_window_type_dock
;
302 atom
[i
++] = net_wm_window_type_toolbar
;
303 atom
[i
++] = net_wm_window_type_menu
;
304 atom
[i
++] = net_wm_window_type_utility
;
305 atom
[i
++] = net_wm_window_type_splash
;
306 atom
[i
++] = net_wm_window_type_dialog
;
307 atom
[i
++] = net_wm_window_type_dropdown_menu
;
308 atom
[i
++] = net_wm_window_type_popup_menu
;
309 atom
[i
++] = net_wm_window_type_tooltip
;
310 atom
[i
++] = net_wm_window_type_notification
;
311 atom
[i
++] = net_wm_window_type_combo
;
312 atom
[i
++] = net_wm_window_type_dnd
;
313 atom
[i
++] = net_wm_window_type_normal
;
315 atom
[i
++] = net_wm_state
;
316 /* atom[i++] = net_wm_state_modal; *//* XXX: not sure where/when to use it. */
317 atom
[i
++] = net_wm_state_sticky
;
318 atom
[i
++] = net_wm_state_shaded
;
319 atom
[i
++] = net_wm_state_maximized_horz
;
320 atom
[i
++] = net_wm_state_maximized_vert
;
321 atom
[i
++] = net_wm_state_skip_taskbar
;
322 atom
[i
++] = net_wm_state_skip_pager
;
323 atom
[i
++] = net_wm_state_hidden
;
324 atom
[i
++] = net_wm_state_fullscreen
;
325 atom
[i
++] = net_wm_state_above
;
326 atom
[i
++] = net_wm_state_below
;
327 atom
[i
++] = net_wm_state_focused
;
329 atom
[i
++] = net_wm_allowed_actions
;
330 atom
[i
++] = net_wm_action_move
;
331 atom
[i
++] = net_wm_action_resize
;
332 atom
[i
++] = net_wm_action_minimize
;
333 atom
[i
++] = net_wm_action_shade
;
334 atom
[i
++] = net_wm_action_stick
;
335 atom
[i
++] = net_wm_action_maximize_horz
;
336 atom
[i
++] = net_wm_action_maximize_vert
;
337 atom
[i
++] = net_wm_action_fullscreen
;
338 atom
[i
++] = net_wm_action_change_desktop
;
339 atom
[i
++] = net_wm_action_close
;
341 atom
[i
++] = net_wm_strut
;
342 atom
[i
++] = net_wm_icon_geometry
;
343 atom
[i
++] = net_wm_icon
;
344 atom
[i
++] = net_wm_handled_icons
;
345 atom
[i
++] = net_wm_window_opacity
;
347 atom
[i
++] = net_frame_extents
;
349 atom
[i
++] = net_wm_name
;
350 atom
[i
++] = net_wm_icon_name
;
352 XChangeProperty(dpy
, scr
->root_win
, net_supported
, XA_ATOM
, 32, PropModeReplace
, (unsigned char *)atom
, i
);
354 /* set supporting wm hint */
355 XChangeProperty(dpy
, scr
->root_win
, net_supporting_wm_check
, XA_WINDOW
, 32,
356 PropModeReplace
, (unsigned char *)&scr
->info_window
, 1);
358 XChangeProperty(dpy
, scr
->info_window
, net_supporting_wm_check
, XA_WINDOW
,
359 32, PropModeReplace
, (unsigned char *)&scr
->info_window
, 1);
362 void wNETWMUpdateDesktop(WScreen
*scr
)
364 long *views
, sizes
[2];
367 if (scr
->workspace_count
== 0)
370 count
= scr
->workspace_count
* 2;
371 views
= wmalloc(sizeof(long) * count
);
372 sizes
[0] = scr
->scr_width
;
373 sizes
[1] = scr
->scr_height
;
375 for (i
= 0; i
< scr
->workspace_count
; i
++) {
376 views
[2 * i
+ 0] = 0;
377 views
[2 * i
+ 1] = 0;
380 XChangeProperty(dpy
, scr
->root_win
, net_desktop_geometry
, XA_CARDINAL
, 32,
381 PropModeReplace
, (unsigned char *)sizes
, 2);
383 XChangeProperty(dpy
, scr
->root_win
, net_desktop_viewport
, XA_CARDINAL
, 32,
384 PropModeReplace
, (unsigned char *)views
, count
);
389 int wNETWMGetCurrentDesktopFromHint(WScreen
*scr
)
394 prop
= PropGetCheckProperty(scr
->root_win
, net_current_desktop
, XA_CARDINAL
, 0, 1, &count
);
396 int desktop
= *(long *)prop
;
403 static RImage
*makeRImageFromARGBData(unsigned long *data
)
405 int size
, width
, height
, i
;
407 unsigned char *imgdata
;
412 size
= width
* height
;
417 image
= RCreateImage(width
, height
, True
);
419 for (imgdata
= image
->data
, i
= 2; i
< size
+ 2; i
++, imgdata
+= 4) {
421 imgdata
[3] = (pixel
>> 24) & 0xff; /* A */
422 imgdata
[0] = (pixel
>> 16) & 0xff; /* R */
423 imgdata
[1] = (pixel
>> 8) & 0xff; /* G */
424 imgdata
[2] = (pixel
>> 0) & 0xff; /* B */
430 /* Find the best icon to be used by Window Maker for appicon/miniwindows. */
431 static RImage
*findBestIcon(unsigned long *data
, unsigned long items
)
439 RImage
*src_image
, *ret_image
;
442 if (wPreferences
.enforce_icon_margin
) {
444 /* better use only 75% of icon_size. For 64x64 this means 48x48
445 * This leaves room around the icon for the miniwindow title and
446 * results in better overall aesthetics -Dan */
447 wanted
= (int)((double)wPreferences
.icon_size
* 0.75 + 0.5);
449 /* the size should be a multiple of 4 */
450 wanted
= (wanted
>> 2) << 2;
454 /* This is the "old" approach, which tries to find the largest
455 * icon that still fits into icon_size. */
456 wanted
= wPreferences
.icon_size
;
460 /* try to find an icon which is close to the wanted size, but not larger */
462 best_d
= wanted
* wanted
* 2;
463 for (i
= 0L; i
< items
- 1;) {
465 /* get the current icon's size */
467 sy
= (int)data
[i
+ 1];
468 if ((sx
< 1) || (sy
< 1))
472 /* check the size difference if it's not too large */
473 if ((sx
<= wanted
) && (sy
<= wanted
)) {
476 d
= (dx
* dx
) + (dy
* dy
);
486 /* if an icon has been found, no transformation is needed */
488 return makeRImageFromARGBData(icon
);
490 /* We need to scale down an icon. Find the largest one, for it usually
491 * looks better to scale down a large image by a large scale than a
492 * small image by a small scale. */
494 for (i
= 0L; i
< items
- 1;) {
495 size
= (int)data
[i
] * (int)data
[i
+ 1];
498 if (size
> largest
) {
505 /* give up if there's no icon to work with */
509 /* create a scaled down version of the icon */
510 src_image
= makeRImageFromARGBData(icon
);
511 if (src_image
->width
> src_image
->height
) {
512 f
= (double)wanted
/ (double)src_image
->width
;
513 ret_image
= RScaleImage(src_image
, wanted
, (int)(f
* (double)(src_image
->height
)));
515 f
= (double)wanted
/ (double)src_image
->height
;
516 ret_image
= RScaleImage(src_image
, (int)(f
* (double)src_image
->width
), wanted
);
518 RReleaseImage(src_image
);
522 RImage
*get_window_image_from_x11(Window window
)
527 unsigned long items
, rest
;
528 unsigned long *property
;
530 /* Get the icon from X11 Window */
531 if (XGetWindowProperty(dpy
, window
, net_wm_icon
, 0L, LONG_MAX
,
532 False
, XA_CARDINAL
, &type
, &format
, &items
, &rest
,
533 (unsigned char **)&property
) != Success
|| !property
)
536 if (type
!= XA_CARDINAL
|| format
!= 32 || items
< 2) {
541 /* Find the best icon */
542 image
= findBestIcon(property
, items
);
547 /* Resize the image to the correct value */
548 image
= wIconValidateIconSize(image
, wPreferences
.icon_size
);
553 static void updateIconImage(WWindow
*wwin
)
555 /* Remove the icon image from X11 */
556 if (wwin
->net_icon_image
)
557 RReleaseImage(wwin
->net_icon_image
);
559 /* Save the icon in the X11 icon */
560 wwin
->net_icon_image
= get_window_image_from_x11(wwin
->client_win
);
562 /* Refresh the Window Icon */
564 wIconUpdate(wwin
->icon
);
566 /* Refresh the application icon */
567 WApplication
*app
= wApplicationOf(wwin
->main_window
);
568 if (app
&& app
->app_icon
) {
569 wIconUpdate(app
->app_icon
->icon
);
570 wAppIconPaint(app
->app_icon
);
574 static void updateWindowOpacity(WWindow
*wwin
)
578 unsigned long items
, rest
;
579 unsigned long *property
;
584 /* We don't care about this ourselves, but other programs need us to copy
585 * this to the frame window. */
586 if (XGetWindowProperty(dpy
, wwin
->client_win
, net_wm_window_opacity
, 0L, 1L,
587 False
, XA_CARDINAL
, &type
, &format
, &items
, &rest
,
588 (unsigned char **)&property
) != Success
)
592 XDeleteProperty(dpy
, wwin
->frame
->core
->window
, net_wm_window_opacity
);
593 } else if (type
== XA_CARDINAL
&& format
== 32 && items
== 1 && property
) {
594 XChangeProperty(dpy
, wwin
->frame
->core
->window
, net_wm_window_opacity
,
595 XA_CARDINAL
, 32, PropModeReplace
, (unsigned char *)property
, 1L);
602 static void updateShowDesktop(WScreen
*scr
, Bool show
)
606 foo
= (show
== True
);
607 XChangeProperty(dpy
, scr
->root_win
, net_showing_desktop
, XA_CARDINAL
, 32,
608 PropModeReplace
, (unsigned char *)&foo
, 1);
611 static void wNETWMShowingDesktop(WScreen
*scr
, Bool show
)
613 if (show
&& scr
->netdata
->show_desktop
== NULL
) {
614 WWindow
*tmp
, **wins
;
617 wins
= (WWindow
**) wmalloc(sizeof(WWindow
*) * (scr
->window_count
+ 1));
619 tmp
= scr
->focused_window
;
621 if (!tmp
->flags
.hidden
&& !tmp
->flags
.miniaturized
&& !WFLAGP(tmp
, skip_window_list
)) {
624 tmp
->flags
.skip_next_animation
= 1;
625 tmp
->flags
.net_show_desktop
= 1;
633 scr
->netdata
->show_desktop
= wins
;
634 updateShowDesktop(scr
, True
);
635 } else if (scr
->netdata
->show_desktop
!= NULL
) {
636 /* FIXME: get rid of workspace flashing ! */
637 int ws
= scr
->current_workspace
;
639 for (tmp
= scr
->netdata
->show_desktop
; *tmp
; ++tmp
) {
640 wDeiconifyWindow(*tmp
);
641 (*tmp
)->flags
.net_show_desktop
= 0;
643 if (ws
!= scr
->current_workspace
)
644 wWorkspaceChange(scr
, ws
);
645 wfree(scr
->netdata
->show_desktop
);
646 scr
->netdata
->show_desktop
= NULL
;
647 updateShowDesktop(scr
, False
);
651 void wNETWMInitStuff(WScreen
*scr
)
657 wmessage("wNETWMInitStuff");
660 #ifdef HAVE_XINTERNATOMS
662 Atom atoms
[wlengthof(atomNames
)];
663 char *names
[wlengthof(atomNames
)];
665 for (i
= 0; i
< wlengthof(atomNames
); ++i
)
666 names
[i
] = atomNames
[i
].name
;
668 XInternAtoms(dpy
, &names
[0], wlengthof(atomNames
), False
, atoms
);
669 for (i
= 0; i
< wlengthof(atomNames
); ++i
)
670 *atomNames
[i
].atom
= atoms
[i
];
674 for (i
= 0; i
< wlengthof(atomNames
); i
++)
675 *atomNames
[i
].atom
= XInternAtom(dpy
, atomNames
[i
].name
, False
);
678 data
= wmalloc(sizeof(NetData
));
681 data
->show_desktop
= NULL
;
685 setSupportedHints(scr
);
687 WMAddNotificationObserver(observer
, data
, WMNManaged
, NULL
);
688 WMAddNotificationObserver(observer
, data
, WMNUnmanaged
, NULL
);
689 WMAddNotificationObserver(observer
, data
, WMNChangedWorkspace
, NULL
);
690 WMAddNotificationObserver(observer
, data
, WMNChangedState
, NULL
);
691 WMAddNotificationObserver(observer
, data
, WMNChangedFocus
, NULL
);
692 WMAddNotificationObserver(observer
, data
, WMNChangedStacking
, NULL
);
693 WMAddNotificationObserver(observer
, data
, WMNChangedName
, NULL
);
695 WMAddNotificationObserver(wsobserver
, data
, WMNWorkspaceCreated
, NULL
);
696 WMAddNotificationObserver(wsobserver
, data
, WMNWorkspaceDestroyed
, NULL
);
697 WMAddNotificationObserver(wsobserver
, data
, WMNWorkspaceChanged
, NULL
);
698 WMAddNotificationObserver(wsobserver
, data
, WMNWorkspaceNameChanged
, NULL
);
700 updateClientList(scr
);
701 updateClientListStacking(scr
, NULL
);
702 updateWorkspaceCount(scr
);
703 updateWorkspaceNames(scr
);
704 updateShowDesktop(scr
, False
);
706 wScreenUpdateUsableArea(scr
);
709 void wNETWMCleanup(WScreen
*scr
)
713 for (i
= 0; i
< wlengthof(atomNames
); i
++)
714 XDeleteProperty(dpy
, scr
->root_win
, *atomNames
[i
].atom
);
717 void wNETWMUpdateActions(WWindow
*wwin
, Bool del
)
719 Atom action
[10]; /* nr of actions atoms defined */
723 XDeleteProperty(dpy
, wwin
->client_win
, net_wm_allowed_actions
);
727 if (IS_MOVABLE(wwin
))
728 action
[i
++] = net_wm_action_move
;
730 if (IS_RESIZABLE(wwin
))
731 action
[i
++] = net_wm_action_resize
;
733 if (!WFLAGP(wwin
, no_miniaturizable
))
734 action
[i
++] = net_wm_action_minimize
;
736 if (!WFLAGP(wwin
, no_shadeable
))
737 action
[i
++] = net_wm_action_shade
;
739 /* if (!WFLAGP(wwin, no_stickable)) */
740 action
[i
++] = net_wm_action_stick
;
742 /* if (!(WFLAGP(wwin, no_maximizeable) & MAX_HORIZONTAL)) */
743 if (IS_RESIZABLE(wwin
))
744 action
[i
++] = net_wm_action_maximize_horz
;
746 /* if (!(WFLAGP(wwin, no_maximizeable) & MAX_VERTICAL)) */
747 if (IS_RESIZABLE(wwin
))
748 action
[i
++] = net_wm_action_maximize_vert
;
750 /* if (!WFLAGP(wwin, no_fullscreen)) */
751 action
[i
++] = net_wm_action_fullscreen
;
753 /* if (!WFLAGP(wwin, no_change_desktop)) */
754 action
[i
++] = net_wm_action_change_desktop
;
756 if (!WFLAGP(wwin
, no_closable
))
757 action
[i
++] = net_wm_action_close
;
759 XChangeProperty(dpy
, wwin
->client_win
, net_wm_allowed_actions
,
760 XA_ATOM
, 32, PropModeReplace
, (unsigned char *)action
, i
);
763 void wNETWMUpdateWorkarea(WScreen
*scr
)
769 /* If the _NET_xxx were not initialised, it not necessary to do anything */
773 if (!scr
->usableArea
) {
774 /* If we don't have any info, we fall back on using the complete screen area */
777 total_usable
.x2
= scr
->scr_width
;
778 total_usable
.y2
= scr
->scr_height
;
784 * the _NET_WORKAREA is supposed to contain the total area of the screen that
785 * is usable, so we merge the areas from all xrandr sub-screens
787 total_usable
= scr
->usableArea
[0];
789 for (i
= 1; i
< wXineramaHeads(scr
); i
++) {
790 /* The merge is not subtle because _NET_WORKAREA does not need more */
791 if (scr
->usableArea
[i
].x1
< total_usable
.x1
)
792 total_usable
.x1
= scr
->usableArea
[i
].x1
;
794 if (scr
->usableArea
[i
].y1
< total_usable
.y1
)
795 total_usable
.y1
= scr
->usableArea
[i
].y1
;
797 if (scr
->usableArea
[i
].x2
> total_usable
.x2
)
798 total_usable
.x2
= scr
->usableArea
[i
].x2
;
800 if (scr
->usableArea
[i
].y2
> total_usable
.y2
)
801 total_usable
.y2
= scr
->usableArea
[i
].y2
;
806 /* We are expected to repeat the information for each workspace */
807 if (scr
->workspace_count
== 0)
810 nb_workspace
= scr
->workspace_count
;
813 long property_value
[nb_workspace
* 4];
816 for (i
= 0; i
< nb_workspace
; i
++) {
817 property_value
[4 * i
+ 0] = total_usable
.x1
;
818 property_value
[4 * i
+ 1] = total_usable
.y1
;
819 property_value
[4 * i
+ 2] = total_usable
.x2
- total_usable
.x1
;
820 property_value
[4 * i
+ 3] = total_usable
.y2
- total_usable
.y1
;
823 XChangeProperty(dpy
, scr
->root_win
, net_workarea
, XA_CARDINAL
, 32, PropModeReplace
,
824 (unsigned char *) property_value
, nb_workspace
* 4);
828 Bool
wNETWMGetUsableArea(WScreen
*scr
, int head
, WArea
*area
)
833 if (!scr
->netdata
|| !scr
->netdata
->strut
)
836 area
->x1
= area
->y1
= area
->x2
= area
->y2
= 0;
838 for (cur
= scr
->netdata
->strut
; cur
; cur
= cur
->next
) {
839 WWindow
*wwin
= wWindowFor(cur
->window
);
840 if (wWindowTouchesHead(wwin
, head
)) {
841 if (cur
->area
.x1
> area
->x1
)
842 area
->x1
= cur
->area
.x1
;
843 if (cur
->area
.y1
> area
->y1
)
844 area
->y1
= cur
->area
.y1
;
845 if (cur
->area
.x2
> area
->x2
)
846 area
->x2
= cur
->area
.x2
;
847 if (cur
->area
.y2
> area
->y2
)
848 area
->y2
= cur
->area
.y2
;
852 if (area
->x1
== 0 && area
->x2
== 0 && area
->y1
== 0 && area
->y2
== 0)
855 rect
= wGetRectForHead(scr
, head
);
857 /* NOTE(gryf): calculation for the reserved area should be preformed for
858 * current head, but area, which comes form _NET_WM_STRUT, has to be
859 * calculated relative to entire screen size, i.e. suppose we have three
860 * heads arranged like this:
862 * ╔════════════════════════╗
867 * ╟────────────────────────╫───────────╢
868 * ╠════════════════════════╬═══════════╝
874 * ╟────────────────────────╢
875 * ╚════════════════════════╝
877 * where head 0 have resolution 1920x1080, head 1: 1920x1200 and head 2
878 * 800x600, so the screen size in this arrangement will be 2720x2280 (1920
879 * + 800) x (1080 + 1200).
881 * Bottom line represents some 3rd party panel, which sets properties in
882 * _NET_WM_STRUT_PARTIAL and optionally _NET_WM_STRUT.
884 * By coincidence, coordinates x1 and y1 from left and top are the same as
885 * the original data which came from _NET_WM_STRUT, since they meaning
886 * distance from the edge, so we leave it as-is, otherwise if they have 0
887 * value, we need to set right head position.
890 /* optional reserved space from left */
891 if (area
->x1
== 0) area
->x1
= rect
.pos
.x
;
893 /* optional reserved space from top */
894 if (area
->y1
== 0) area
->y1
= rect
.pos
.y
;
896 /* optional reserved space from right */
898 area
->x2
= rect
.pos
.x
+ rect
.size
.width
;
900 area
->x2
= scr
->scr_width
- area
->x2
;
902 /* optional reserved space from bottom */
904 area
->y2
= rect
.pos
.y
+ rect
.size
.height
;
906 area
->y2
= scr
->scr_height
- area
->y2
;
911 static void updateClientList(WScreen
*scr
)
917 windows
= (Window
*) wmalloc(sizeof(Window
) * (scr
->window_count
+ 1));
920 wwin
= scr
->focused_window
;
922 windows
[count
++] = wwin
->client_win
;
925 XChangeProperty(dpy
, scr
->root_win
, net_client_list
, XA_WINDOW
, 32,
926 PropModeReplace
, (unsigned char *)windows
, count
);
932 static void updateClientListStacking(WScreen
*scr
, WWindow
*wwin_excl
)
935 Window
*client_list
, *client_list_reverse
;
940 /* update client list */
941 i
= scr
->window_count
+ 1;
942 client_list
= (Window
*) wmalloc(sizeof(Window
) * i
);
943 client_list_reverse
= (Window
*) wmalloc(sizeof(Window
) * i
);
946 WM_ETARETI_BAG(scr
->stacking_list
, tmp
, iter
) {
948 wwin
= wWindowFor(tmp
->window
);
949 /* wwin_excl is a window to exclude from the list
950 (e.g. it's now unmanaged) */
951 if (wwin
&& (wwin
!= wwin_excl
))
952 client_list
[client_count
++] = wwin
->client_win
;
953 tmp
= tmp
->stacking
->under
;
957 for (i
= 0; i
< client_count
; i
++) {
958 Window w
= client_list
[client_count
- i
- 1];
959 client_list_reverse
[i
] = w
;
962 XChangeProperty(dpy
, scr
->root_win
, net_client_list_stacking
, XA_WINDOW
, 32,
963 PropModeReplace
, (unsigned char *)client_list_reverse
, client_count
);
966 wfree(client_list_reverse
);
971 static void updateWorkspaceCount(WScreen
*scr
)
975 count
= scr
->workspace_count
;
977 XChangeProperty(dpy
, scr
->root_win
, net_number_of_desktops
, XA_CARDINAL
,
978 32, PropModeReplace
, (unsigned char *)&count
, 1);
981 static void updateCurrentWorkspace(WScreen
*scr
)
985 count
= scr
->current_workspace
;
987 XChangeProperty(dpy
, scr
->root_win
, net_current_desktop
, XA_CARDINAL
, 32,
988 PropModeReplace
, (unsigned char *)&count
, 1);
991 static void updateWorkspaceNames(WScreen
*scr
)
993 char buf
[MAX_WORKSPACES
* (MAX_WORKSPACENAME_WIDTH
+ 1)], *pos
;
994 unsigned int i
, len
, curr_size
;
998 for (i
= 0; i
< scr
->workspace_count
; i
++) {
999 curr_size
= strlen(scr
->workspaces
[i
]->name
);
1000 strncpy(pos
, scr
->workspaces
[i
]->name
, sizeof(pos
) - 1);
1001 pos
+= (curr_size
+ 1);
1002 len
+= (curr_size
+ 1);
1005 XChangeProperty(dpy
, scr
->root_win
, net_desktop_names
, utf8_string
, 8,
1006 PropModeReplace
, (unsigned char *)buf
, len
);
1009 static void updateFocusHint(WScreen
*scr
)
1013 if (!scr
->focused_window
|| !scr
->focused_window
->flags
.focused
)
1016 window
= scr
->focused_window
->client_win
;
1018 XChangeProperty(dpy
, scr
->root_win
, net_active_window
, XA_WINDOW
, 32,
1019 PropModeReplace
, (unsigned char *)&window
, 1);
1022 static void updateWorkspaceHint(WWindow
*wwin
, Bool fake
, Bool del
)
1027 XDeleteProperty(dpy
, wwin
->client_win
, net_wm_desktop
);
1029 l
= ((fake
|| IS_OMNIPRESENT(wwin
)) ? -1 : wwin
->frame
->workspace
);
1030 XChangeProperty(dpy
, wwin
->client_win
, net_wm_desktop
, XA_CARDINAL
,
1031 32, PropModeReplace
, (unsigned char *)&l
, 1);
1035 static void updateStateHint(WWindow
*wwin
, Bool changedWorkspace
, Bool del
)
1038 XDeleteProperty(dpy
, wwin
->client_win
, net_wm_state
);
1040 XDeleteProperty(dpy
, wwin
->client_win
, net_wm_fullscreen_monitors
);
1043 Atom state
[15]; /* nr of defined state atoms */
1046 if (changedWorkspace
|| (wPreferences
.sticky_icons
&& !IS_OMNIPRESENT(wwin
)))
1047 updateWorkspaceHint(wwin
, False
, False
);
1049 if (IS_OMNIPRESENT(wwin
))
1050 state
[i
++] = net_wm_state_sticky
;
1051 if (wwin
->flags
.shaded
)
1052 state
[i
++] = net_wm_state_shaded
;
1053 if (wwin
->flags
.maximized
& MAX_HORIZONTAL
)
1054 state
[i
++] = net_wm_state_maximized_horz
;
1055 if (wwin
->flags
.maximized
& MAX_VERTICAL
)
1056 state
[i
++] = net_wm_state_maximized_vert
;
1057 if (WFLAGP(wwin
, skip_window_list
))
1058 state
[i
++] = net_wm_state_skip_taskbar
;
1059 if (wwin
->flags
.net_skip_pager
)
1060 state
[i
++] = net_wm_state_skip_pager
;
1061 if ((wwin
->flags
.hidden
|| wwin
->flags
.miniaturized
) && !wwin
->flags
.net_show_desktop
) {
1062 state
[i
++] = net_wm_state_hidden
;
1063 state
[i
++] = net_wm_state_skip_pager
;
1065 if (wwin
->flags
.miniaturized
&& wPreferences
.sticky_icons
) {
1066 if (!IS_OMNIPRESENT(wwin
))
1067 updateWorkspaceHint(wwin
, True
, False
);
1068 state
[i
++] = net_wm_state_sticky
;
1071 if (WFLAGP(wwin
, sunken
))
1072 state
[i
++] = net_wm_state_below
;
1073 if (WFLAGP(wwin
, floating
))
1074 state
[i
++] = net_wm_state_above
;
1075 if (wwin
->flags
.fullscreen
)
1076 state
[i
++] = net_wm_state_fullscreen
;
1077 if (wwin
->flags
.focused
)
1078 state
[i
++] = net_wm_state_focused
;
1080 XChangeProperty(dpy
, wwin
->client_win
, net_wm_state
, XA_ATOM
, 32,
1081 PropModeReplace
, (unsigned char *)state
, i
);
1084 if (wwin
->flags
.fullscreen
&& (wwin
->flags
.fullscreen_monitors
[0] != -1)) {
1085 unsigned long data
[4];
1087 data
[0] = wwin
->flags
.fullscreen_monitors
[0];
1088 data
[1] = wwin
->flags
.fullscreen_monitors
[1];
1089 data
[2] = wwin
->flags
.fullscreen_monitors
[2];
1090 data
[3] = wwin
->flags
.fullscreen_monitors
[3];
1092 XChangeProperty(dpy
, wwin
->client_win
, net_wm_fullscreen_monitors
, XA_CARDINAL
, 32,
1093 PropModeReplace
, (unsigned char *)data
, 4);
1099 static Bool
updateStrut(WScreen
*scr
, Window w
, Bool adding
)
1101 WReservedArea
*area
;
1102 Bool hasState
= False
;
1107 unsigned long nitems_ret
, bytes_after_ret
;
1110 if ((XGetWindowProperty(dpy
, w
, net_wm_strut
, 0, 4, False
,
1111 XA_CARDINAL
, &type_ret
, &fmt_ret
, &nitems_ret
,
1112 &bytes_after_ret
, (unsigned char **)&data
) == Success
&& data
) ||
1113 ((XGetWindowProperty(dpy
, w
, net_wm_strut_partial
, 0, 12, False
,
1114 XA_CARDINAL
, &type_ret
, &fmt_ret
, &nitems_ret
,
1115 &bytes_after_ret
, (unsigned char **)&data
) == Success
&& data
))) {
1117 /* XXX: This is strictly incorrect in the case of net_wm_strut_partial...
1118 * Discard the start and end properties from the partial strut and treat it as
1119 * a (deprecated) strut.
1120 * This means we are marking the whole width or height of the screen as
1121 * reserved, which is not necessarily what the strut defines. However for the
1122 * purposes of determining placement or maximization it's probably good enough.
1124 area
= (WReservedArea
*) wmalloc(sizeof(WReservedArea
));
1125 area
->area
.x1
= data
[0];
1126 area
->area
.x2
= data
[1];
1127 area
->area
.y1
= data
[2];
1128 area
->area
.y2
= data
[3];
1132 area
->next
= scr
->netdata
->strut
;
1133 scr
->netdata
->strut
= area
;
1140 area
= scr
->netdata
->strut
;
1143 if (area
->window
== w
) {
1144 scr
->netdata
->strut
= area
->next
;
1148 while (area
->next
&& area
->next
->window
!= w
)
1152 WReservedArea
*next
;
1154 next
= area
->next
->next
;
1167 static int getWindowLayer(WWindow
*wwin
)
1169 int layer
= WMNormalLevel
;
1171 if (wwin
->type
== net_wm_window_type_desktop
) {
1172 layer
= WMDesktopLevel
;
1173 } else if (wwin
->type
== net_wm_window_type_dock
) {
1174 layer
= WMDockLevel
;
1175 } else if (wwin
->type
== net_wm_window_type_toolbar
) {
1176 layer
= WMMainMenuLevel
;
1177 } else if (wwin
->type
== net_wm_window_type_menu
) {
1178 layer
= WMSubmenuLevel
;
1179 } else if (wwin
->type
== net_wm_window_type_utility
) {
1180 } else if (wwin
->type
== net_wm_window_type_splash
) {
1181 } else if (wwin
->type
== net_wm_window_type_dialog
) {
1182 if (wwin
->transient_for
) {
1183 WWindow
*parent
= wWindowFor(wwin
->transient_for
);
1184 if (parent
&& parent
->flags
.fullscreen
)
1185 layer
= WMFullscreenLevel
;
1187 /* //layer = WMPopUpLevel; // this seems a bad idea -Dan */
1188 } else if (wwin
->type
== net_wm_window_type_dropdown_menu
) {
1189 layer
= WMSubmenuLevel
;
1190 } else if (wwin
->type
== net_wm_window_type_popup_menu
) {
1191 layer
= WMSubmenuLevel
;
1192 } else if (wwin
->type
== net_wm_window_type_tooltip
) {
1193 } else if (wwin
->type
== net_wm_window_type_notification
) {
1194 layer
= WMPopUpLevel
;
1195 } else if (wwin
->type
== net_wm_window_type_combo
) {
1196 layer
= WMSubmenuLevel
;
1197 } else if (wwin
->type
== net_wm_window_type_dnd
) {
1198 } else if (wwin
->type
== net_wm_window_type_normal
) {
1201 if (wwin
->client_flags
.sunken
&& WMSunkenLevel
< layer
)
1202 layer
= WMSunkenLevel
;
1203 if (wwin
->client_flags
.floating
&& WMFloatingLevel
> layer
)
1204 layer
= WMFloatingLevel
;
1209 static void doStateAtom(WWindow
*wwin
, Atom state
, int set
, Bool init
)
1211 if (state
== net_wm_state_sticky
) {
1212 if (set
== _NET_WM_STATE_TOGGLE
)
1213 set
= !IS_OMNIPRESENT(wwin
);
1215 if (set
!= wwin
->flags
.omnipresent
)
1216 wWindowSetOmnipresent(wwin
, set
);
1218 } else if (state
== net_wm_state_shaded
) {
1219 if (set
== _NET_WM_STATE_TOGGLE
)
1220 set
= !wwin
->flags
.shaded
;
1223 wwin
->flags
.shaded
= set
;
1228 wUnshadeWindow(wwin
);
1230 } else if (state
== net_wm_state_skip_taskbar
) {
1231 if (set
== _NET_WM_STATE_TOGGLE
)
1232 set
= !wwin
->client_flags
.skip_window_list
;
1234 wwin
->client_flags
.skip_window_list
= set
;
1235 } else if (state
== net_wm_state_skip_pager
) {
1236 if (set
== _NET_WM_STATE_TOGGLE
)
1237 set
= !wwin
->flags
.net_skip_pager
;
1239 wwin
->flags
.net_skip_pager
= set
;
1240 } else if (state
== net_wm_state_maximized_vert
) {
1241 if (set
== _NET_WM_STATE_TOGGLE
)
1242 set
= !(wwin
->flags
.maximized
& MAX_VERTICAL
);
1245 wwin
->flags
.maximized
|= (set
? MAX_VERTICAL
: 0);
1248 wMaximizeWindow(wwin
, wwin
->flags
.maximized
| MAX_VERTICAL
,
1249 wGetHeadForWindow(wwin
));
1251 wMaximizeWindow(wwin
, wwin
->flags
.maximized
& ~MAX_VERTICAL
,
1252 wGetHeadForWindow(wwin
));
1254 } else if (state
== net_wm_state_maximized_horz
) {
1255 if (set
== _NET_WM_STATE_TOGGLE
)
1256 set
= !(wwin
->flags
.maximized
& MAX_HORIZONTAL
);
1259 wwin
->flags
.maximized
|= (set
? MAX_HORIZONTAL
: 0);
1262 wMaximizeWindow(wwin
, wwin
->flags
.maximized
| MAX_HORIZONTAL
,
1263 wGetHeadForWindow(wwin
));
1265 wMaximizeWindow(wwin
, wwin
->flags
.maximized
& ~MAX_HORIZONTAL
,
1266 wGetHeadForWindow(wwin
));
1268 } else if (state
== net_wm_state_hidden
) {
1269 if (set
== _NET_WM_STATE_TOGGLE
)
1270 set
= !(wwin
->flags
.miniaturized
);
1273 wwin
->flags
.miniaturized
= set
;
1276 wIconifyWindow(wwin
);
1278 wDeiconifyWindow(wwin
);
1280 } else if (state
== net_wm_state_fullscreen
) {
1281 if (set
== _NET_WM_STATE_TOGGLE
)
1282 set
= !(wwin
->flags
.fullscreen
);
1285 wwin
->flags
.fullscreen
= set
;
1288 wFullscreenWindow(wwin
);
1290 wUnfullscreenWindow(wwin
);
1291 wwin
->flags
.fullscreen_monitors
[0] = -1;
1294 } else if (state
== net_wm_state_above
) {
1295 if (set
== _NET_WM_STATE_TOGGLE
)
1296 set
= !(wwin
->client_flags
.floating
);
1299 wwin
->client_flags
.floating
= set
;
1301 wwin
->client_flags
.floating
= set
;
1302 ChangeStackingLevel(wwin
->frame
->core
, getWindowLayer(wwin
));
1305 } else if (state
== net_wm_state_below
) {
1306 if (set
== _NET_WM_STATE_TOGGLE
)
1307 set
= !(wwin
->client_flags
.sunken
);
1310 wwin
->client_flags
.sunken
= set
;
1312 wwin
->client_flags
.sunken
= set
;
1313 ChangeStackingLevel(wwin
->frame
->core
, getWindowLayer(wwin
));
1318 wmessage("doStateAtom unknown atom %s set %d", XGetAtomName(dpy
, state
), set
);
1323 static void removeIcon(WWindow
*wwin
)
1325 if (wwin
->icon
== NULL
)
1327 if (wwin
->flags
.miniaturized
&& wwin
->icon
->mapped
) {
1328 XUnmapWindow(dpy
, wwin
->icon
->core
->window
);
1329 RemoveFromStackList(wwin
->icon
->core
);
1330 wIconDestroy(wwin
->icon
);
1335 static Bool
handleWindowType(WWindow
*wwin
, Atom type
, int *layer
)
1339 if (type
== net_wm_window_type_desktop
) {
1340 wwin
->client_flags
.no_titlebar
= 1;
1341 wwin
->client_flags
.no_resizable
= 1;
1342 wwin
->client_flags
.no_miniaturizable
= 1;
1343 wwin
->client_flags
.no_border
= 1;
1344 wwin
->client_flags
.no_resizebar
= 1;
1345 wwin
->client_flags
.no_shadeable
= 1;
1346 wwin
->client_flags
.no_movable
= 1;
1347 wwin
->client_flags
.omnipresent
= 1;
1348 wwin
->client_flags
.skip_window_list
= 1;
1349 wwin
->client_flags
.skip_switchpanel
= 1;
1350 wwin
->client_flags
.dont_move_off
= 1;
1351 wwin
->client_flags
.no_appicon
= 1;
1352 wwin
->flags
.net_skip_pager
= 1;
1355 } else if (type
== net_wm_window_type_dock
) {
1356 wwin
->client_flags
.no_titlebar
= 1;
1357 wwin
->client_flags
.no_resizable
= 1;
1358 wwin
->client_flags
.no_miniaturizable
= 1;
1359 wwin
->client_flags
.no_border
= 1; /* XXX: really not a single decoration. */
1360 wwin
->client_flags
.no_resizebar
= 1;
1361 wwin
->client_flags
.no_shadeable
= 1;
1362 wwin
->client_flags
.no_movable
= 1;
1363 wwin
->client_flags
.omnipresent
= 1;
1364 wwin
->client_flags
.skip_window_list
= 1;
1365 wwin
->client_flags
.skip_switchpanel
= 1;
1366 wwin
->client_flags
.dont_move_off
= 1;
1367 wwin
->flags
.net_skip_pager
= 1;
1368 } else if (type
== net_wm_window_type_toolbar
||
1369 type
== net_wm_window_type_menu
) {
1370 wwin
->client_flags
.no_resizable
= 1;
1371 wwin
->client_flags
.no_miniaturizable
= 1;
1372 wwin
->client_flags
.no_resizebar
= 1;
1373 wwin
->client_flags
.no_shadeable
= 1;
1374 wwin
->client_flags
.skip_window_list
= 1;
1375 wwin
->client_flags
.skip_switchpanel
= 1;
1376 wwin
->client_flags
.dont_move_off
= 1;
1377 wwin
->client_flags
.no_appicon
= 1;
1378 } else if (type
== net_wm_window_type_dropdown_menu
||
1379 type
== net_wm_window_type_popup_menu
||
1380 type
== net_wm_window_type_combo
) {
1381 wwin
->client_flags
.no_titlebar
= 1;
1382 wwin
->client_flags
.no_resizable
= 1;
1383 wwin
->client_flags
.no_miniaturizable
= 1;
1384 wwin
->client_flags
.no_resizebar
= 1;
1385 wwin
->client_flags
.no_shadeable
= 1;
1386 wwin
->client_flags
.skip_window_list
= 1;
1387 wwin
->client_flags
.skip_switchpanel
= 1;
1388 wwin
->client_flags
.dont_move_off
= 1;
1389 wwin
->client_flags
.no_appicon
= 1;
1390 } else if (type
== net_wm_window_type_utility
) {
1391 wwin
->client_flags
.no_appicon
= 1;
1392 } else if (type
== net_wm_window_type_splash
) {
1393 wwin
->client_flags
.no_titlebar
= 1;
1394 wwin
->client_flags
.no_resizable
= 1;
1395 wwin
->client_flags
.no_miniaturizable
= 1;
1396 wwin
->client_flags
.no_resizebar
= 1;
1397 wwin
->client_flags
.no_shadeable
= 1;
1398 wwin
->client_flags
.no_movable
= 1;
1399 wwin
->client_flags
.skip_window_list
= 1;
1400 wwin
->client_flags
.skip_switchpanel
= 1;
1401 wwin
->client_flags
.dont_move_off
= 1;
1402 wwin
->client_flags
.no_appicon
= 1;
1403 wwin
->flags
.net_skip_pager
= 1;
1404 } else if (type
== net_wm_window_type_dialog
) {
1405 /* These also seem a bad idea in our context -Dan
1406 // wwin->client_flags.skip_window_list = 1;
1407 // wwin->client_flags.no_appicon = 1;
1409 } else if (wwin
->type
== net_wm_window_type_tooltip
) {
1410 wwin
->client_flags
.no_titlebar
= 1;
1411 wwin
->client_flags
.no_resizable
= 1;
1412 wwin
->client_flags
.no_miniaturizable
= 1;
1413 wwin
->client_flags
.no_resizebar
= 1;
1414 wwin
->client_flags
.no_shadeable
= 1;
1415 wwin
->client_flags
.no_movable
= 1;
1416 wwin
->client_flags
.skip_window_list
= 1;
1417 wwin
->client_flags
.skip_switchpanel
= 1;
1418 wwin
->client_flags
.dont_move_off
= 1;
1419 wwin
->client_flags
.no_appicon
= 1;
1420 wwin
->client_flags
.no_focusable
= 1;
1421 wwin
->flags
.net_skip_pager
= 1;
1422 } else if (wwin
->type
== net_wm_window_type_notification
) {
1423 wwin
->client_flags
.no_titlebar
= 1;
1424 wwin
->client_flags
.no_resizable
= 1;
1425 wwin
->client_flags
.no_miniaturizable
= 1;
1426 wwin
->client_flags
.no_border
= 1;
1427 wwin
->client_flags
.no_resizebar
= 1;
1428 wwin
->client_flags
.no_shadeable
= 1;
1429 wwin
->client_flags
.no_movable
= 1;
1430 wwin
->client_flags
.omnipresent
= 1;
1431 wwin
->client_flags
.skip_window_list
= 1;
1432 wwin
->client_flags
.skip_switchpanel
= 1;
1433 wwin
->client_flags
.dont_move_off
= 1;
1434 wwin
->client_flags
.no_hide_others
= 1;
1435 wwin
->client_flags
.no_appicon
= 1;
1436 wwin
->client_flags
.no_focusable
= 1;
1437 wwin
->flags
.net_skip_pager
= 1;
1438 } else if (wwin
->type
== net_wm_window_type_dnd
) {
1439 wwin
->client_flags
.no_titlebar
= 1;
1440 wwin
->client_flags
.no_resizable
= 1;
1441 wwin
->client_flags
.no_miniaturizable
= 1;
1442 wwin
->client_flags
.no_border
= 1;
1443 wwin
->client_flags
.no_resizebar
= 1;
1444 wwin
->client_flags
.no_shadeable
= 1;
1445 wwin
->client_flags
.no_movable
= 1;
1446 wwin
->client_flags
.skip_window_list
= 1;
1447 wwin
->client_flags
.skip_switchpanel
= 1;
1448 wwin
->client_flags
.dont_move_off
= 1;
1449 wwin
->client_flags
.no_appicon
= 1;
1450 wwin
->flags
.net_skip_pager
= 1;
1451 } else if (type
== net_wm_window_type_normal
) {
1456 /* Restore decoration if the user has enabled the
1457 * IgnoreDecorationChanges option */
1458 if (WFLAGP(wwin
, ignore_decoration_changes
)) {
1459 wwin
->client_flags
.no_titlebar
= 0;
1460 wwin
->client_flags
.no_resizable
= 0;
1461 wwin
->client_flags
.no_miniaturizable
= 0;
1462 wwin
->client_flags
.no_resizebar
= 0;
1463 wwin
->client_flags
.no_border
= 0;
1464 wwin
->client_flags
.no_movable
= 0;
1468 *layer
= getWindowLayer(wwin
);
1473 void wNETWMPositionSplash(WWindow
*wwin
, int *x
, int *y
, int width
, int height
)
1475 if (wwin
->type
== net_wm_window_type_splash
) {
1476 WScreen
*scr
= wwin
->screen_ptr
;
1477 WMRect rect
= wGetRectForHead(scr
, wGetHeadForPointerLocation(scr
));
1478 *x
= rect
.pos
.x
+ (rect
.size
.width
- width
) / 2;
1479 *y
= rect
.pos
.y
+ (rect
.size
.height
- height
) / 2;
1483 static void updateWindowType(WWindow
*wwin
)
1487 int layer
= INT_MIN
; //illegal level
1488 unsigned long nitems_ret
, bytes_after_ret
;
1491 if (XGetWindowProperty(dpy
, wwin
->client_win
, net_wm_window_type
, 0, 1,
1492 False
, XA_ATOM
, &type_ret
, &fmt_ret
, &nitems_ret
,
1493 &bytes_after_ret
, (unsigned char **)&data
) == Success
&& data
) {
1496 Atom
*type
= (Atom
*) data
;
1497 for (i
= 0; i
< nitems_ret
; ++i
) {
1498 if (handleWindowType(wwin
, type
[i
], &layer
))
1504 if (wwin
->frame
!= NULL
) {
1505 if (layer
!= INT_MIN
)
1506 ChangeStackingLevel(wwin
->frame
->core
, layer
);
1507 wwin
->frame
->flags
.need_texture_change
= 1;
1508 wWindowConfigureBorders(wwin
);
1509 wFrameWindowPaint(wwin
->frame
);
1510 wNETWMUpdateActions(wwin
, False
);
1514 void wNETWMCheckClientHints(WWindow
*wwin
, int *layer
, int *workspace
)
1518 unsigned long nitems_ret
, bytes_after_ret
;
1521 if (XGetWindowProperty(dpy
, wwin
->client_win
, net_wm_desktop
, 0, 1, False
,
1522 XA_CARDINAL
, &type_ret
, &fmt_ret
, &nitems_ret
,
1523 &bytes_after_ret
, (unsigned char **)&data
) == Success
&& data
) {
1525 long desktop
= *data
;
1529 wwin
->client_flags
.omnipresent
= 1;
1531 *workspace
= desktop
;
1534 if (XGetWindowProperty(dpy
, wwin
->client_win
, net_wm_state
, 0, 1, False
,
1535 XA_ATOM
, &type_ret
, &fmt_ret
, &nitems_ret
,
1536 &bytes_after_ret
, (unsigned char **)&data
) == Success
&& data
) {
1538 Atom
*state
= (Atom
*) data
;
1539 for (i
= 0; i
< nitems_ret
; ++i
)
1540 doStateAtom(wwin
, state
[i
], _NET_WM_STATE_ADD
, True
);
1545 if (XGetWindowProperty(dpy
, wwin
->client_win
, net_wm_window_type
, 0, 1, False
,
1546 XA_ATOM
, &type_ret
, &fmt_ret
, &nitems_ret
,
1547 &bytes_after_ret
, (unsigned char **)&data
) == Success
&& data
) {
1549 Atom
*type
= (Atom
*) data
;
1550 for (i
= 0; i
< nitems_ret
; ++i
) {
1551 if (handleWindowType(wwin
, type
[i
], layer
))
1557 wNETWMUpdateActions(wwin
, False
);
1558 updateStrut(wwin
->screen_ptr
, wwin
->client_win
, False
);
1559 updateStrut(wwin
->screen_ptr
, wwin
->client_win
, True
);
1561 wScreenUpdateUsableArea(wwin
->screen_ptr
);
1564 static Bool
updateNetIconInfo(WWindow
*wwin
)
1568 unsigned long nitems_ret
, bytes_after_ret
;
1570 Bool hasState
= False
;
1571 Bool old_state
= wwin
->flags
.net_handle_icon
;
1573 if (XGetWindowProperty(dpy
, wwin
->client_win
, net_wm_handled_icons
, 0, 1, False
,
1574 XA_CARDINAL
, &type_ret
, &fmt_ret
, &nitems_ret
,
1575 &bytes_after_ret
, (unsigned char **)&data
) == Success
&& data
) {
1576 long handled
= *data
;
1577 wwin
->flags
.net_handle_icon
= (handled
!= 0);
1582 wwin
->flags
.net_handle_icon
= False
;
1585 if (XGetWindowProperty(dpy
, wwin
->client_win
, net_wm_icon_geometry
, 0, 4, False
,
1586 XA_CARDINAL
, &type_ret
, &fmt_ret
, &nitems_ret
,
1587 &bytes_after_ret
, (unsigned char **)&data
) == Success
&& data
) {
1590 if (wwin
->flags
.net_handle_icon
)
1592 wwin
->flags
.net_handle_icon
= True
;
1595 wwin
->icon_x
= data
[0];
1596 wwin
->icon_y
= data
[1];
1597 wwin
->icon_w
= data
[2];
1598 wwin
->icon_h
= data
[3];
1605 wwin
->flags
.net_handle_icon
= False
;
1608 if (wwin
->flags
.miniaturized
&& old_state
!= wwin
->flags
.net_handle_icon
) {
1609 if (wwin
->flags
.net_handle_icon
) {
1612 wwin
->flags
.miniaturized
= False
;
1613 wwin
->flags
.skip_next_animation
= True
;
1614 wIconifyWindow(wwin
);
1621 void wNETWMCheckInitialClientState(WWindow
*wwin
)
1624 wmessage("wNETWMCheckInitialClientState");
1627 wNETWMShowingDesktop(wwin
->screen_ptr
, False
);
1629 updateWindowType(wwin
);
1630 updateNetIconInfo(wwin
);
1631 updateIconImage(wwin
);
1634 void wNETWMCheckInitialFrameState(WWindow
*wwin
)
1637 wmessage("wNETWMCheckInitialFrameState");
1640 updateWindowOpacity(wwin
);
1643 static void handleDesktopNames(WScreen
*scr
)
1645 unsigned long nitems_ret
, bytes_after_ret
;
1646 char *data
, *names
[32];
1650 if (XGetWindowProperty(dpy
, scr
->root_win
, net_desktop_names
, 0, 1, False
,
1651 utf8_string
, &type_ret
, &fmt_ret
, &nitems_ret
,
1652 &bytes_after_ret
, (unsigned char **)&data
) != Success
)
1658 if (type_ret
!= utf8_string
|| fmt_ret
!= 8)
1663 for (i
= 0; i
< nitems_ret
; i
++) {
1666 names
[n
] = &data
[i
];
1667 } else if (*names
[n
] == 0) {
1668 names
[n
] = &data
[i
];
1669 wWorkspaceRename(scr
, n
, names
[n
]);
1674 Bool
wNETWMProcessClientMessage(XClientMessageEvent
*event
)
1680 wmessage("processClientMessage type %s", XGetAtomName(dpy
, event
->message_type
));
1683 scr
= wScreenForWindow(event
->window
);
1685 /* generic client messages */
1686 if (event
->message_type
== net_current_desktop
) {
1687 wWorkspaceChange(scr
, event
->data
.l
[0]);
1690 } else if (event
->message_type
== net_number_of_desktops
) {
1693 value
= event
->data
.l
[0];
1694 if (value
> scr
->workspace_count
) {
1695 wWorkspaceMake(scr
, value
- scr
->workspace_count
);
1696 } else if (value
< scr
->workspace_count
) {
1698 Bool rebuild
= False
;
1700 for (i
= scr
->workspace_count
- 1; i
>= value
; i
--) {
1701 if (!wWorkspaceDelete(scr
, i
)) {
1708 updateWorkspaceCount(scr
);
1712 } else if (event
->message_type
== net_showing_desktop
) {
1713 wNETWMShowingDesktop(scr
, event
->data
.l
[0]);
1716 } else if (event
->message_type
== net_desktop_names
) {
1717 handleDesktopNames(scr
);
1722 /* window specific client messages */
1724 wwin
= wWindowFor(event
->window
);
1728 if (event
->message_type
== net_active_window
) {
1730 * Satisfy a client's focus request only if
1731 * - request comes from a pager, or
1732 * - it's explicitly allowed in Advanced Options, or
1733 * - giving the client the focus does not cause a change in
1734 * the active workspace (XXX: or the active head if Xinerama)
1736 if (wwin
->frame
->workspace
== wwin
->screen_ptr
->current_workspace
/* No workspace change */
1737 || event
->data
.l
[0] == 2 /* Requested by pager */
1738 || WFLAGP(wwin
, focus_across_wksp
) /* Explicitly allowed */) {
1739 wNETWMShowingDesktop(wwin
->screen_ptr
, False
);
1740 wMakeWindowVisible(wwin
);
1744 } else if (event
->message_type
== net_close_window
) {
1745 if (!WFLAGP(wwin
, no_closable
)) {
1746 if (wwin
->protocols
.DELETE_WINDOW
)
1747 wClientSendProtocol(wwin
, w_global
.atom
.wm
.delete_window
,
1748 w_global
.timestamp
.last_event
);
1752 } else if (event
->message_type
== net_wm_state
) {
1753 int maximized
= wwin
->flags
.maximized
;
1754 long set
= event
->data
.l
[0];
1757 wmessage("net_wm_state set %ld a1 %s a2 %s", set
,
1758 XGetAtomName(dpy
, event
->data
.l
[1]), XGetAtomName(dpy
, event
->data
.l
[2]));
1761 doStateAtom(wwin
, (Atom
) event
->data
.l
[1], set
, False
);
1762 if (event
->data
.l
[2])
1763 doStateAtom(wwin
, (Atom
) event
->data
.l
[2], set
, False
);
1765 if (wwin
->flags
.maximized
!= maximized
) {
1766 if (!wwin
->flags
.maximized
) {
1767 wwin
->flags
.maximized
= maximized
;
1768 wUnmaximizeWindow(wwin
);
1770 wMaximizeWindow(wwin
, wwin
->flags
.maximized
,
1771 wGetHeadForWindow(wwin
));
1774 updateStateHint(wwin
, False
, False
);
1777 } else if (event
->message_type
== net_wm_handled_icons
|| event
->message_type
== net_wm_icon_geometry
) {
1778 updateNetIconInfo(wwin
);
1781 } else if (event
->message_type
== net_wm_desktop
) {
1782 long desktop
= event
->data
.l
[0];
1784 if (desktop
== -1) {
1785 wWindowSetOmnipresent(wwin
, True
);
1787 if (IS_OMNIPRESENT(wwin
))
1788 wWindowSetOmnipresent(wwin
, False
);
1789 wWindowChangeWorkspace(wwin
, desktop
);
1794 } else if (event
->message_type
== net_wm_fullscreen_monitors
) {
1795 unsigned long top
, bottom
, left
, right
, src_indication
;
1797 top
= event
->data
.l
[0];
1798 bottom
= event
->data
.l
[1];
1799 left
= event
->data
.l
[2];
1800 right
= event
->data
.l
[3];
1801 src_indication
= event
->data
.l
[4];
1803 if (src_indication
> 1)
1804 wwarning("_NET_WM_FULLSCREEN_MONITORS source indication %ld not supported", src_indication
);
1806 wFullscreenMonitorsWindow(wwin
, top
, bottom
, left
, right
);
1814 wmessage("processClientMessage unsupported type %s", XGetAtomName(dpy
, event
->message_type
));
1819 void wNETWMCheckClientHintChange(WWindow
*wwin
, XPropertyEvent
*event
)
1822 wmessage("clientHintChange type %s", XGetAtomName(dpy
, event
->atom
));
1825 if (event
->atom
== net_wm_strut
|| event
->atom
== net_wm_strut_partial
) {
1826 updateStrut(wwin
->screen_ptr
, wwin
->client_win
, False
);
1827 updateStrut(wwin
->screen_ptr
, wwin
->client_win
, True
);
1828 wScreenUpdateUsableArea(wwin
->screen_ptr
);
1829 } else if (event
->atom
== net_wm_handled_icons
|| event
->atom
== net_wm_icon_geometry
) {
1830 updateNetIconInfo(wwin
);
1831 } else if (event
->atom
== net_wm_window_type
) {
1832 updateWindowType(wwin
);
1833 } else if (event
->atom
== net_wm_name
) {
1834 char *name
= wNETWMGetWindowName(wwin
->client_win
);
1835 wWindowUpdateName(wwin
, name
);
1838 } else if (event
->atom
== net_wm_icon_name
) {
1840 wIconChangeTitle(wwin
->icon
, wwin
);
1841 wIconPaint(wwin
->icon
);
1843 } else if (event
->atom
== net_wm_icon
) {
1844 updateIconImage(wwin
);
1845 } else if (event
->atom
== net_wm_window_opacity
) {
1846 updateWindowOpacity(wwin
);
1850 int wNETWMGetPidForWindow(Window window
)
1854 unsigned long nitems_ret
, bytes_after_ret
;
1858 if (XGetWindowProperty(dpy
, window
, net_wm_pid
, 0, 1, False
,
1859 XA_CARDINAL
, &type_ret
, &fmt_ret
, &nitems_ret
,
1860 &bytes_after_ret
, (unsigned char **)&data
) == Success
&& data
) {
1870 char *wNETWMGetWindowName(Window window
)
1876 name
= (char *)PropGetCheckProperty(window
, net_wm_name
, utf8_string
, 0, 0, &size
);
1878 ret
= wstrndup(name
, size
);
1887 char *wNETWMGetIconName(Window window
)
1893 name
= (char *)PropGetCheckProperty(window
, net_wm_icon_name
, utf8_string
, 0, 0, &size
);
1895 ret
= wstrndup(name
, size
);
1904 static void observer(void *self
, WMNotification
*notif
)
1906 WWindow
*wwin
= (WWindow
*) WMGetNotificationObject(notif
);
1907 const char *name
= WMGetNotificationName(notif
);
1908 void *data
= WMGetNotificationClientData(notif
);
1909 NetData
*ndata
= (NetData
*) self
;
1911 if (strcmp(name
, WMNManaged
) == 0 && wwin
) {
1912 updateClientList(wwin
->screen_ptr
);
1913 updateClientListStacking(wwin
->screen_ptr
, NULL
);
1914 updateStateHint(wwin
, True
, False
);
1916 updateStrut(wwin
->screen_ptr
, wwin
->client_win
, False
);
1917 updateStrut(wwin
->screen_ptr
, wwin
->client_win
, True
);
1918 wScreenUpdateUsableArea(wwin
->screen_ptr
);
1919 } else if (strcmp(name
, WMNUnmanaged
) == 0 && wwin
) {
1920 updateClientList(wwin
->screen_ptr
);
1921 updateClientListStacking(wwin
->screen_ptr
, wwin
);
1922 updateWorkspaceHint(wwin
, False
, True
);
1923 updateStateHint(wwin
, False
, True
);
1924 wNETWMUpdateActions(wwin
, True
);
1926 updateStrut(wwin
->screen_ptr
, wwin
->client_win
, False
);
1927 wScreenUpdateUsableArea(wwin
->screen_ptr
);
1928 } else if (strcmp(name
, WMNResetStacking
) == 0 && wwin
) {
1929 updateClientListStacking(wwin
->screen_ptr
, NULL
);
1930 updateStateHint(wwin
, False
, False
);
1931 } else if (strcmp(name
, WMNChangedStacking
) == 0 && wwin
) {
1932 updateClientListStacking(wwin
->screen_ptr
, NULL
);
1933 updateStateHint(wwin
, False
, False
);
1934 } else if (strcmp(name
, WMNChangedFocus
) == 0 && wwin
) {
1935 updateFocusHint(ndata
->scr
);
1936 updateStateHint(wwin
, False
, False
);
1937 } else if (strcmp(name
, WMNChangedWorkspace
) == 0 && wwin
) {
1938 updateWorkspaceHint(wwin
, False
, False
);
1939 updateStateHint(wwin
, True
, False
);
1940 } else if (strcmp(name
, WMNChangedState
) == 0 && wwin
) {
1941 updateStateHint(wwin
, !strcmp(data
, "omnipresent"), False
);
1945 static void wsobserver(void *self
, WMNotification
*notif
)
1947 WScreen
*scr
= (WScreen
*) WMGetNotificationObject(notif
);
1948 const char *name
= WMGetNotificationName(notif
);
1950 /* Parameter not used, but tell the compiler that it is ok */
1953 if (strcmp(name
, WMNWorkspaceCreated
) == 0) {
1954 updateWorkspaceCount(scr
);
1955 updateWorkspaceNames(scr
);
1956 wNETWMUpdateWorkarea(scr
);
1957 } else if (strcmp(name
, WMNWorkspaceDestroyed
) == 0) {
1958 updateWorkspaceCount(scr
);
1959 updateWorkspaceNames(scr
);
1960 wNETWMUpdateWorkarea(scr
);
1961 } else if (strcmp(name
, WMNWorkspaceChanged
) == 0) {
1962 updateCurrentWorkspace(scr
);
1963 } else if (strcmp(name
, WMNWorkspaceNameChanged
) == 0) {
1964 updateWorkspaceNames(scr
);
1968 void wNETFrameExtents(WWindow
*wwin
)
1970 long extents
[4] = { 0, 0, 0, 0 };
1972 /* The extents array describes dimensions which are not
1973 * part of the client window. In our case that means
1974 * widths of the border and heights of the titlebar and resizebar.
1981 if (wwin
->frame
->titlebar
)
1982 extents
[2] = wwin
->frame
->titlebar
->height
;
1983 if (wwin
->frame
->resizebar
)
1984 extents
[3] = wwin
->frame
->resizebar
->height
;
1985 if (HAS_BORDER(wwin
)) {
1986 extents
[0] += wwin
->screen_ptr
->frame_border_width
;
1987 extents
[1] += wwin
->screen_ptr
->frame_border_width
;
1988 extents
[2] += wwin
->screen_ptr
->frame_border_width
;
1989 extents
[3] += wwin
->screen_ptr
->frame_border_width
;
1992 XChangeProperty(dpy
, wwin
->client_win
, net_frame_extents
, XA_CARDINAL
, 32, PropModeReplace
, (unsigned char *) extents
, 4);
1995 void wNETCleanupFrameExtents(WWindow
*wwin
)
1997 XDeleteProperty(dpy
, wwin
->client_win
, net_frame_extents
);