1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 screen.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
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 See the COPYING file for a copy of the GNU General Public License.
24 #include "startupnotify.h"
25 #include "moveresize.h"
34 #include "render/render.h"
36 #include "obt/display.h"
38 #include "obt/mainloop.h"
42 # include <sys/types.h>
47 /*! The event mask to grab on the root window */
48 #define ROOT_EVENTMASK (StructureNotifyMask | PropertyChangeMask | \
49 EnterWindowMask | LeaveWindowMask | \
50 SubstructureRedirectMask | FocusChangeMask | \
51 ButtonPressMask | ButtonReleaseMask)
53 static gboolean
screen_validate_layout(ObDesktopLayout
*l
);
54 static gboolean
replace_wm(void);
55 static void screen_tell_ksplash(void);
56 static void screen_fallback_focus(void);
58 guint screen_num_desktops
;
59 guint screen_num_monitors
;
61 guint screen_last_desktop
= 1;
62 gboolean screen_showing_desktop
;
63 ObDesktopLayout screen_desktop_layout
;
64 gchar
**screen_desktop_names
;
65 Window screen_support_win
;
66 Time screen_desktop_user_time
= CurrentTime
;
68 static Size screen_physical_size
;
69 static guint screen_old_desktop
;
70 static gboolean screen_desktop_timeout
= TRUE
;
71 /*! An array of desktops, holding array of areas per monitor */
72 static Rect
*monitor_area
= NULL
;
73 /*! An array of desktops, holding an array of struts */
74 static GSList
*struts_top
= NULL
;
75 static GSList
*struts_left
= NULL
;
76 static GSList
*struts_right
= NULL
;
77 static GSList
*struts_bottom
= NULL
;
79 static ObPagerPopup
*desktop_popup
;
81 /*! The number of microseconds that you need to be on a desktop before it will
82 replace the remembered "last desktop" */
83 #define REMEMBER_LAST_DESKTOP_TIME 750000
85 static gboolean
replace_wm(void)
89 Window current_wm_sn_owner
;
92 wm_sn
= g_strdup_printf("WM_S%d", ob_screen
);
93 wm_sn_atom
= XInternAtom(obt_display
, wm_sn
, FALSE
);
96 current_wm_sn_owner
= XGetSelectionOwner(obt_display
, wm_sn_atom
);
97 if (current_wm_sn_owner
== screen_support_win
)
98 current_wm_sn_owner
= None
;
99 if (current_wm_sn_owner
) {
100 if (!ob_replace_wm
) {
101 g_message(_("A window manager is already running on screen %d"),
105 obt_display_ignore_errors(TRUE
);
107 /* We want to find out when the current selection owner dies */
108 XSelectInput(obt_display
, current_wm_sn_owner
, StructureNotifyMask
);
109 XSync(obt_display
, FALSE
);
111 obt_display_ignore_errors(FALSE
);
112 if (obt_display_error_occured
)
113 current_wm_sn_owner
= None
;
116 timestamp
= event_get_server_time();
118 XSetSelectionOwner(obt_display
, wm_sn_atom
, screen_support_win
,
121 if (XGetSelectionOwner(obt_display
, wm_sn_atom
) != screen_support_win
) {
122 g_message(_("Could not acquire window manager selection on screen %d"),
127 /* Wait for old window manager to go away */
128 if (current_wm_sn_owner
) {
131 const gulong timeout
= G_USEC_PER_SEC
* 15; /* wait for 15s max */
133 while (wait
< timeout
) {
134 if (XCheckWindowEvent(obt_display
, current_wm_sn_owner
,
135 StructureNotifyMask
, &event
) &&
136 event
.type
== DestroyNotify
)
138 g_usleep(G_USEC_PER_SEC
/ 10);
139 wait
+= G_USEC_PER_SEC
/ 10;
142 if (wait
>= timeout
) {
143 g_message(_("The WM on screen %d is not exiting"), ob_screen
);
148 /* Send client message indicating that we are now the WM */
149 obt_prop_message(ob_screen
, obt_root(ob_screen
), OBT_PROP_ATOM(MANAGER
),
150 timestamp
, wm_sn_atom
, screen_support_win
, 0, 0,
151 SubstructureNotifyMask
);
156 gboolean
screen_annex(void)
158 XSetWindowAttributes attrib
;
163 /* create the netwm support window */
164 attrib
.override_redirect
= TRUE
;
165 attrib
.event_mask
= PropertyChangeMask
;
166 screen_support_win
= XCreateWindow(obt_display
, obt_root(ob_screen
),
168 CopyFromParent
, InputOutput
,
170 CWEventMask
| CWOverrideRedirect
,
172 XMapWindow(obt_display
, screen_support_win
);
173 XLowerWindow(obt_display
, screen_support_win
);
176 XDestroyWindow(obt_display
, screen_support_win
);
180 obt_display_ignore_errors(TRUE
);
181 XSelectInput(obt_display
, obt_root(ob_screen
), ROOT_EVENTMASK
);
182 obt_display_ignore_errors(FALSE
);
183 if (obt_display_error_occured
) {
184 g_message(_("A window manager is already running on screen %d"),
187 XDestroyWindow(obt_display
, screen_support_win
);
191 screen_set_root_cursor();
193 /* set the OPENBOX_PID hint */
195 OBT_PROP_SET32(obt_root(ob_screen
), OPENBOX_PID
, CARDINAL
, pid
);
197 /* set supporting window */
198 OBT_PROP_SET32(obt_root(ob_screen
),
199 NET_SUPPORTING_WM_CHECK
, WINDOW
, screen_support_win
);
201 /* set properties on the supporting window */
202 OBT_PROP_SETS(screen_support_win
, NET_WM_NAME
, utf8
, "Openbox");
203 OBT_PROP_SET32(screen_support_win
, NET_SUPPORTING_WM_CHECK
,
204 WINDOW
, screen_support_win
);
206 /* set the _NET_SUPPORTED_ATOMS hint */
208 /* this is all the atoms after NET_SUPPORTED in the ObtPropAtoms enum */
209 num_support
= OBT_PROP_NUM_ATOMS
- OBT_PROP_NET_SUPPORTED
- 1;
211 supported
= g_new(gulong
, num_support
);
212 supported
[i
++] = OBT_PROP_ATOM(NET_SUPPORTING_WM_CHECK
);
213 supported
[i
++] = OBT_PROP_ATOM(NET_WM_FULL_PLACEMENT
);
214 supported
[i
++] = OBT_PROP_ATOM(NET_CURRENT_DESKTOP
);
215 supported
[i
++] = OBT_PROP_ATOM(NET_NUMBER_OF_DESKTOPS
);
216 supported
[i
++] = OBT_PROP_ATOM(NET_DESKTOP_GEOMETRY
);
217 supported
[i
++] = OBT_PROP_ATOM(NET_DESKTOP_VIEWPORT
);
218 supported
[i
++] = OBT_PROP_ATOM(NET_ACTIVE_WINDOW
);
219 supported
[i
++] = OBT_PROP_ATOM(NET_WORKAREA
);
220 supported
[i
++] = OBT_PROP_ATOM(NET_CLIENT_LIST
);
221 supported
[i
++] = OBT_PROP_ATOM(NET_CLIENT_LIST_STACKING
);
222 supported
[i
++] = OBT_PROP_ATOM(NET_DESKTOP_NAMES
);
223 supported
[i
++] = OBT_PROP_ATOM(NET_CLOSE_WINDOW
);
224 supported
[i
++] = OBT_PROP_ATOM(NET_DESKTOP_LAYOUT
);
225 supported
[i
++] = OBT_PROP_ATOM(NET_SHOWING_DESKTOP
);
226 supported
[i
++] = OBT_PROP_ATOM(NET_WM_NAME
);
227 supported
[i
++] = OBT_PROP_ATOM(NET_WM_VISIBLE_NAME
);
228 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ICON_NAME
);
229 supported
[i
++] = OBT_PROP_ATOM(NET_WM_VISIBLE_ICON_NAME
);
230 supported
[i
++] = OBT_PROP_ATOM(NET_WM_DESKTOP
);
231 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STRUT
);
232 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STRUT_PARTIAL
);
233 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ICON
);
234 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ICON_GEOMETRY
);
235 supported
[i
++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE
);
236 supported
[i
++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DESKTOP
);
237 supported
[i
++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DOCK
);
238 supported
[i
++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_TOOLBAR
);
239 supported
[i
++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_MENU
);
240 supported
[i
++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_UTILITY
);
241 supported
[i
++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_SPLASH
);
242 supported
[i
++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DIALOG
);
243 supported
[i
++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_NORMAL
);
244 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ALLOWED_ACTIONS
);
245 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ACTION_MOVE
);
246 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ACTION_RESIZE
);
247 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ACTION_MINIMIZE
);
248 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ACTION_SHADE
);
249 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ACTION_MAXIMIZE_HORZ
);
250 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ACTION_MAXIMIZE_VERT
);
251 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ACTION_FULLSCREEN
);
252 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ACTION_CHANGE_DESKTOP
);
253 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ACTION_CLOSE
);
254 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ACTION_ABOVE
);
255 supported
[i
++] = OBT_PROP_ATOM(NET_WM_ACTION_BELOW
);
256 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STATE
);
257 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STATE_MODAL
);
258 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT
);
259 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ
);
260 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STATE_SHADED
);
261 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR
);
262 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER
);
263 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STATE_HIDDEN
);
264 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN
);
265 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STATE_ABOVE
);
266 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STATE_BELOW
);
267 supported
[i
++] = OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION
);
268 supported
[i
++] = OBT_PROP_ATOM(NET_MOVERESIZE_WINDOW
);
269 supported
[i
++] = OBT_PROP_ATOM(NET_WM_MOVERESIZE
);
270 supported
[i
++] = OBT_PROP_ATOM(NET_WM_USER_TIME
);
272 supported[i++] = OBT_PROP_ATOM(NET_WM_USER_TIME_WINDOW);
274 supported
[i
++] = OBT_PROP_ATOM(NET_FRAME_EXTENTS
);
275 supported
[i
++] = OBT_PROP_ATOM(NET_REQUEST_FRAME_EXTENTS
);
276 supported
[i
++] = OBT_PROP_ATOM(NET_RESTACK_WINDOW
);
277 supported
[i
++] = OBT_PROP_ATOM(NET_STARTUP_ID
);
279 supported
[i
++] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST
);
280 supported
[i
++] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST_COUNTER
);
282 supported
[i
++] = OBT_PROP_ATOM(NET_WM_PID
);
283 supported
[i
++] = OBT_PROP_ATOM(NET_WM_PING
);
285 supported
[i
++] = OBT_PROP_ATOM(KDE_WM_CHANGE_STATE
);
286 supported
[i
++] = OBT_PROP_ATOM(KDE_NET_WM_FRAME_STRUT
);
287 supported
[i
++] = OBT_PROP_ATOM(KDE_NET_WM_WINDOW_TYPE_OVERRIDE
);
289 supported
[i
++] = OBT_PROP_ATOM(OB_WM_ACTION_UNDECORATE
);
290 supported
[i
++] = OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED
);
291 supported
[i
++] = OBT_PROP_ATOM(OPENBOX_PID
);
292 supported
[i
++] = OBT_PROP_ATOM(OB_THEME
);
293 supported
[i
++] = OBT_PROP_ATOM(OB_CONTROL
);
294 g_assert(i
== num_support
);
296 OBT_PROP_SETA32(obt_root(ob_screen
),
297 NET_SUPPORTED
, ATOM
, supported
, num_support
);
300 screen_tell_ksplash();
305 static void screen_tell_ksplash(void)
310 argv
= g_new(gchar
*, 6);
311 argv
[0] = g_strdup("dcop");
312 argv
[1] = g_strdup("ksplash");
313 argv
[2] = g_strdup("ksplash");
314 argv
[3] = g_strdup("upAndRunning(QString)");
315 argv
[4] = g_strdup("wm started");
318 /* tell ksplash through the dcop server command line interface */
319 g_spawn_async(NULL
, argv
, NULL
,
320 G_SPAWN_SEARCH_PATH
| G_SPAWN_DO_NOT_REAP_CHILD
|
321 G_SPAWN_STDERR_TO_DEV_NULL
| G_SPAWN_STDOUT_TO_DEV_NULL
,
322 NULL
, NULL
, NULL
, NULL
);
325 /* i'm not sure why we do this, kwin does it, but ksplash doesn't seem to
326 hear it anyways. perhaps it is for old ksplash. or new ksplash. or
327 something. oh well. */
328 e
.xclient
.type
= ClientMessage
;
329 e
.xclient
.display
= obt_display
;
330 e
.xclient
.window
= obt_root(ob_screen
);
331 e
.xclient
.message_type
=
332 XInternAtom(obt_display
, "_KDE_SPLASH_PROGRESS", False
);
333 e
.xclient
.format
= 8;
334 strcpy(e
.xclient
.data
.b
, "wm started");
335 XSendEvent(obt_display
, obt_root(ob_screen
),
336 False
, SubstructureNotifyMask
, &e
);
339 void screen_startup(gboolean reconfig
)
341 gchar
**names
= NULL
;
343 gboolean namesexist
= FALSE
;
345 desktop_popup
= pager_popup_new();
346 pager_popup_height(desktop_popup
, POPUP_HEIGHT
);
349 /* update the pager popup's width */
350 pager_popup_text_width_to_strings(desktop_popup
,
351 screen_desktop_names
,
352 screen_num_desktops
);
356 /* get the initial size */
359 /* have names already been set for the desktops? */
360 if (OBT_PROP_GETSS(obt_root(ob_screen
), NET_DESKTOP_NAMES
, utf8
, &names
)) {
365 /* if names don't exist and we have session names, set those.
366 do this stuff BEFORE setting the number of desktops, because that
367 will create default names for them
369 if (!namesexist
&& session_desktop_names
!= NULL
) {
373 /* get the desktop names */
374 numnames
= g_slist_length(session_desktop_names
);
375 names
= g_new(gchar
*, numnames
+ 1);
376 names
[numnames
] = NULL
;
377 for (i
= 0, it
= session_desktop_names
; it
; ++i
, it
= g_slist_next(it
))
378 names
[i
] = g_strdup(it
->data
);
380 /* set the root window property */
381 OBT_PROP_SETSS(obt_root(ob_screen
),
382 NET_DESKTOP_NAMES
, utf8
, (const gchar
**)names
);
387 /* set the number of desktops, if it's not already set.
389 this will also set the default names from the config file up for
390 desktops that don't have names yet */
391 screen_num_desktops
= 0;
392 if (OBT_PROP_GET32(obt_root(ob_screen
),
393 NET_NUMBER_OF_DESKTOPS
, CARDINAL
, &d
))
394 screen_set_num_desktops(d
);
395 /* restore from session if possible */
396 else if (session_num_desktops
)
397 screen_set_num_desktops(session_num_desktops
);
399 screen_set_num_desktops(config_desktops_num
);
401 screen_desktop
= screen_num_desktops
; /* something invalid */
402 /* start on the current desktop when a wm was already running */
403 if (OBT_PROP_GET32(obt_root(ob_screen
),
404 NET_CURRENT_DESKTOP
, CARDINAL
, &d
) &&
405 d
< screen_num_desktops
)
407 screen_set_desktop(d
, FALSE
);
408 } else if (session_desktop
>= 0)
409 screen_set_desktop(MIN((guint
)session_desktop
,
410 screen_num_desktops
), FALSE
);
412 screen_set_desktop(MIN(config_screen_firstdesk
,
413 screen_num_desktops
) - 1, FALSE
);
414 screen_last_desktop
= screen_desktop
;
416 /* don't start in showing-desktop mode */
417 screen_showing_desktop
= FALSE
;
418 OBT_PROP_SET32(obt_root(ob_screen
),
419 NET_SHOWING_DESKTOP
, CARDINAL
, screen_showing_desktop
);
421 if (session_desktop_layout_present
&&
422 screen_validate_layout(&session_desktop_layout
))
424 screen_desktop_layout
= session_desktop_layout
;
427 screen_update_layout();
430 void screen_shutdown(gboolean reconfig
)
432 pager_popup_free(desktop_popup
);
437 XSelectInput(obt_display
, obt_root(ob_screen
), NoEventMask
);
439 /* we're not running here no more! */
440 OBT_PROP_ERASE(obt_root(ob_screen
), OPENBOX_PID
);
442 OBT_PROP_ERASE(obt_root(ob_screen
), NET_SUPPORTED
);
443 /* don't keep this mode */
444 OBT_PROP_ERASE(obt_root(ob_screen
), NET_SHOWING_DESKTOP
);
446 XDestroyWindow(obt_display
, screen_support_win
);
448 g_strfreev(screen_desktop_names
);
449 screen_desktop_names
= NULL
;
452 void screen_resize(void)
454 static gint oldw
= 0, oldh
= 0;
459 w
= WidthOfScreen(ScreenOfDisplay(obt_display
, ob_screen
));
460 h
= HeightOfScreen(ScreenOfDisplay(obt_display
, ob_screen
));
462 if (w
== oldw
&& h
== oldh
) return;
466 /* Set the _NET_DESKTOP_GEOMETRY hint */
467 screen_physical_size
.width
= geometry
[0] = w
;
468 screen_physical_size
.height
= geometry
[1] = h
;
469 OBT_PROP_SETA32(obt_root(ob_screen
),
470 NET_DESKTOP_GEOMETRY
, CARDINAL
, geometry
, 2);
472 if (ob_state() == OB_STATE_STARTING
)
475 screen_update_areas();
478 for (it
= client_list
; it
; it
= g_list_next(it
))
479 client_move_onscreen(it
->data
, FALSE
);
482 void screen_set_num_desktops(guint num
)
486 GList
*it
, *stacking_copy
;
490 if (screen_num_desktops
== num
) return;
492 old
= screen_num_desktops
;
493 screen_num_desktops
= num
;
494 OBT_PROP_SET32(obt_root(ob_screen
), NET_NUMBER_OF_DESKTOPS
, CARDINAL
, num
);
496 /* set the viewport hint */
497 viewport
= g_new0(gulong
, num
* 2);
498 OBT_PROP_SETA32(obt_root(ob_screen
),
499 NET_DESKTOP_VIEWPORT
, CARDINAL
, viewport
, num
* 2);
502 /* the number of rows/columns will differ */
503 screen_update_layout();
505 /* move windows on desktops that will no longer exist!
506 make a copy of the list cuz we're changing it */
507 stacking_copy
= g_list_copy(stacking_list
);
508 for (it
= g_list_last(stacking_copy
); it
; it
= g_list_previous(it
)) {
509 if (WINDOW_IS_CLIENT(it
->data
)) {
510 ObClient
*c
= it
->data
;
511 if (c
->desktop
!= DESKTOP_ALL
&& c
->desktop
>= num
)
512 client_set_desktop(c
, num
- 1, FALSE
, TRUE
);
513 /* raise all the windows that are on the current desktop which
515 else if (screen_desktop
== num
- 1 &&
516 (c
->desktop
== DESKTOP_ALL
||
517 c
->desktop
== screen_desktop
))
518 stacking_raise(CLIENT_AS_WINDOW(c
));
522 /* change our struts/area to match (after moving windows) */
523 screen_update_areas();
525 /* may be some unnamed desktops that we need to fill in with names
526 (after updating the areas so the popup can resize) */
527 screen_update_desktop_names();
529 /* change our desktop if we're on one that no longer exists! */
530 if (screen_desktop
>= screen_num_desktops
)
531 screen_set_desktop(num
- 1, TRUE
);
534 static void screen_fallback_focus(void)
539 /* only allow omnipresent windows to get focus on desktop change if
540 an omnipresent window is already focused (it'll keep focus probably, but
541 maybe not depending on mouse-focus options) */
542 allow_omni
= focus_client
&& (client_normal(focus_client
) &&
543 focus_client
->desktop
== DESKTOP_ALL
);
545 /* the client moved there already so don't move focus. prevent flicker
546 on sendtodesktop + follow */
547 if (focus_client
&& focus_client
->desktop
== screen_desktop
)
550 /* have to try focus here because when you leave an empty desktop
551 there is no focus out to watch for. also, we have different rules
552 here. we always allow it to look under the mouse pointer if
553 config_focus_last is FALSE
555 do this before hiding the windows so if helper windows are coming
556 with us, they don't get hidden
558 if ((c
= focus_fallback(TRUE
, !config_focus_last
, allow_omni
,
561 /* only do the flicker reducing stuff ahead of time if we are going
562 to call xsetinputfocus on the window ourselves. otherwise there is
563 no guarantee the window will actually take focus.. */
565 /* reduce flicker by hiliting now rather than waiting for the
566 server FocusIn event */
567 frame_adjust_focus(c
->frame
, TRUE
);
568 /* do this here so that if you switch desktops to a window with
569 helper windows then the helper windows won't flash */
570 client_bring_helper_windows(c
);
575 static gboolean
last_desktop_func(gpointer data
)
577 screen_desktop_timeout
= TRUE
;
581 void screen_set_desktop(guint num
, gboolean dofocus
)
587 g_assert(num
< screen_num_desktops
);
589 previous
= screen_desktop
;
590 screen_desktop
= num
;
592 if (previous
== num
) return;
594 OBT_PROP_SET32(obt_root(ob_screen
), NET_CURRENT_DESKTOP
, CARDINAL
, num
);
596 /* This whole thing decides when/how to save the screen_last_desktop so
597 that it can be restored later if you want */
598 if (screen_desktop_timeout
) {
599 /* If screen_desktop_timeout is true, then we've been on this desktop
600 long enough and we can save it as the last desktop. */
602 /* save the "last desktop" as the "old desktop" */
603 screen_old_desktop
= screen_last_desktop
;
604 /* save the desktop we're coming from as the "last desktop" */
605 screen_last_desktop
= previous
;
608 /* If screen_desktop_timeout is false, then we just got to this desktop
609 and we are moving away again. */
611 if (screen_desktop
== screen_last_desktop
) {
612 /* If we are moving to the "last desktop" .. */
613 if (previous
== screen_old_desktop
) {
614 /* .. from the "old desktop", change the last desktop to
615 be where we are coming from */
616 screen_last_desktop
= screen_old_desktop
;
618 else if (screen_last_desktop
== screen_old_desktop
) {
619 /* .. and also to the "old desktop", change the "last
620 desktop" to be where we are coming from */
621 screen_last_desktop
= previous
;
624 /* .. from some other desktop, then set the "last desktop" to
625 be the saved "old desktop", i.e. where we were before the
627 screen_last_desktop
= screen_old_desktop
;
631 /* If we are moving to any desktop besides the "last desktop"..
632 (this is the normal case) */
633 if (screen_desktop
== screen_old_desktop
) {
634 /* If moving to the "old desktop", which is not the
635 "last desktop", don't save anything */
637 else if (previous
== screen_old_desktop
) {
638 /* If moving from the "old desktop", and not to the
639 "last desktop", don't save anything */
641 else if (screen_last_desktop
== screen_old_desktop
) {
642 /* If the "last desktop" is the same as "old desktop" and
643 you're not moving to the "last desktop" then save where
644 we're coming from as the "last desktop" */
645 screen_last_desktop
= previous
;
648 /* If the "last desktop" is different from the "old desktop"
649 and you're not moving to the "last desktop", then don't save
654 screen_desktop_timeout
= FALSE
;
655 obt_main_loop_timeout_remove(ob_main_loop
, last_desktop_func
);
656 obt_main_loop_timeout_add(ob_main_loop
, REMEMBER_LAST_DESKTOP_TIME
,
657 last_desktop_func
, NULL
, NULL
, NULL
);
659 ob_debug("Moving to desktop %d\n", num
+1);
661 /* ignore enter events caused by the move */
662 ignore_start
= event_start_ignore_all_enters();
664 if (moveresize_client
)
665 client_set_desktop(moveresize_client
, num
, TRUE
, FALSE
);
667 /* show windows before hiding the rest to lessen the enter/leave events */
669 /* show windows from top to bottom */
670 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
671 if (WINDOW_IS_CLIENT(it
->data
)) {
672 ObClient
*c
= it
->data
;
677 if (dofocus
) screen_fallback_focus();
679 /* hide windows from bottom to top */
680 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
681 if (WINDOW_IS_CLIENT(it
->data
)) {
682 ObClient
*c
= it
->data
;
687 event_end_ignore_all_enters(ignore_start
);
689 if (event_curtime
!= CurrentTime
)
690 screen_desktop_user_time
= event_curtime
;
692 if (ob_state() == OB_STATE_RUNNING
)
693 screen_show_desktop_popup(screen_desktop
);
696 void screen_add_desktop(gboolean current
)
700 /* ignore enter events caused by this */
701 ignore_start
= event_start_ignore_all_enters();
703 screen_set_num_desktops(screen_num_desktops
+1);
705 /* move all the clients over */
709 for (it
= client_list
; it
; it
= g_list_next(it
)) {
710 ObClient
*c
= it
->data
;
711 if (c
->desktop
!= DESKTOP_ALL
&& c
->desktop
>= screen_desktop
&&
712 /* don't move direct children, they'll be moved with their
713 parent - which will have to be on the same desktop */
714 !client_direct_parent(c
))
716 ob_debug("moving window %s\n", c
->title
);
717 client_set_desktop(c
, c
->desktop
+1, FALSE
, TRUE
);
722 event_end_ignore_all_enters(ignore_start
);
725 void screen_remove_desktop(gboolean current
)
727 guint rmdesktop
, movedesktop
;
728 GList
*it
, *stacking_copy
;
731 if (screen_num_desktops
<= 1) return;
733 /* ignore enter events caused by this */
734 ignore_start
= event_start_ignore_all_enters();
736 /* what desktop are we removing and moving to? */
738 rmdesktop
= screen_desktop
;
740 rmdesktop
= screen_num_desktops
- 1;
741 if (rmdesktop
< screen_num_desktops
- 1)
742 movedesktop
= rmdesktop
+ 1;
744 movedesktop
= rmdesktop
;
746 /* make a copy of the list cuz we're changing it */
747 stacking_copy
= g_list_copy(stacking_list
);
748 for (it
= g_list_last(stacking_copy
); it
; it
= g_list_previous(it
)) {
749 if (WINDOW_IS_CLIENT(it
->data
)) {
750 ObClient
*c
= it
->data
;
751 guint d
= c
->desktop
;
752 if (d
!= DESKTOP_ALL
&& d
>= movedesktop
&&
753 /* don't move direct children, they'll be moved with their
754 parent - which will have to be on the same desktop */
755 !client_direct_parent(c
))
757 ob_debug("moving window %s\n", c
->title
);
758 client_set_desktop(c
, c
->desktop
- 1, TRUE
, TRUE
);
760 /* raise all the windows that are on the current desktop which
762 if ((screen_desktop
== rmdesktop
- 1 ||
763 screen_desktop
== rmdesktop
) &&
764 (d
== DESKTOP_ALL
|| d
== screen_desktop
))
766 stacking_raise(CLIENT_AS_WINDOW(c
));
767 ob_debug("raising window %s\n", c
->title
);
772 /* fallback focus like we're changing desktops */
773 if (screen_desktop
< screen_num_desktops
- 1) {
774 screen_fallback_focus();
775 ob_debug("fake desktop change\n");
778 screen_set_num_desktops(screen_num_desktops
-1);
780 event_end_ignore_all_enters(ignore_start
);
783 static void get_row_col(guint d
, guint
*r
, guint
*c
)
785 switch (screen_desktop_layout
.orientation
) {
786 case OB_ORIENTATION_HORZ
:
787 switch (screen_desktop_layout
.start_corner
) {
788 case OB_CORNER_TOPLEFT
:
789 *r
= d
/ screen_desktop_layout
.columns
;
790 *c
= d
% screen_desktop_layout
.columns
;
792 case OB_CORNER_BOTTOMLEFT
:
793 *r
= screen_desktop_layout
.rows
- 1 -
794 d
/ screen_desktop_layout
.columns
;
795 *c
= d
% screen_desktop_layout
.columns
;
797 case OB_CORNER_TOPRIGHT
:
798 *r
= d
/ screen_desktop_layout
.columns
;
799 *c
= screen_desktop_layout
.columns
- 1 -
800 d
% screen_desktop_layout
.columns
;
802 case OB_CORNER_BOTTOMRIGHT
:
803 *r
= screen_desktop_layout
.rows
- 1 -
804 d
/ screen_desktop_layout
.columns
;
805 *c
= screen_desktop_layout
.columns
- 1 -
806 d
% screen_desktop_layout
.columns
;
810 case OB_ORIENTATION_VERT
:
811 switch (screen_desktop_layout
.start_corner
) {
812 case OB_CORNER_TOPLEFT
:
813 *r
= d
% screen_desktop_layout
.rows
;
814 *c
= d
/ screen_desktop_layout
.rows
;
816 case OB_CORNER_BOTTOMLEFT
:
817 *r
= screen_desktop_layout
.rows
- 1 -
818 d
% screen_desktop_layout
.rows
;
819 *c
= d
/ screen_desktop_layout
.rows
;
821 case OB_CORNER_TOPRIGHT
:
822 *r
= d
% screen_desktop_layout
.rows
;
823 *c
= screen_desktop_layout
.columns
- 1 -
824 d
/ screen_desktop_layout
.rows
;
826 case OB_CORNER_BOTTOMRIGHT
:
827 *r
= screen_desktop_layout
.rows
- 1 -
828 d
% screen_desktop_layout
.rows
;
829 *c
= screen_desktop_layout
.columns
- 1 -
830 d
/ screen_desktop_layout
.rows
;
837 static guint
translate_row_col(guint r
, guint c
)
839 switch (screen_desktop_layout
.orientation
) {
840 case OB_ORIENTATION_HORZ
:
841 switch (screen_desktop_layout
.start_corner
) {
842 case OB_CORNER_TOPLEFT
:
843 return r
% screen_desktop_layout
.rows
*
844 screen_desktop_layout
.columns
+
845 c
% screen_desktop_layout
.columns
;
846 case OB_CORNER_BOTTOMLEFT
:
847 return (screen_desktop_layout
.rows
- 1 -
848 r
% screen_desktop_layout
.rows
) *
849 screen_desktop_layout
.columns
+
850 c
% screen_desktop_layout
.columns
;
851 case OB_CORNER_TOPRIGHT
:
852 return r
% screen_desktop_layout
.rows
*
853 screen_desktop_layout
.columns
+
854 (screen_desktop_layout
.columns
- 1 -
855 c
% screen_desktop_layout
.columns
);
856 case OB_CORNER_BOTTOMRIGHT
:
857 return (screen_desktop_layout
.rows
- 1 -
858 r
% screen_desktop_layout
.rows
) *
859 screen_desktop_layout
.columns
+
860 (screen_desktop_layout
.columns
- 1 -
861 c
% screen_desktop_layout
.columns
);
863 case OB_ORIENTATION_VERT
:
864 switch (screen_desktop_layout
.start_corner
) {
865 case OB_CORNER_TOPLEFT
:
866 return c
% screen_desktop_layout
.columns
*
867 screen_desktop_layout
.rows
+
868 r
% screen_desktop_layout
.rows
;
869 case OB_CORNER_BOTTOMLEFT
:
870 return c
% screen_desktop_layout
.columns
*
871 screen_desktop_layout
.rows
+
872 (screen_desktop_layout
.rows
- 1 -
873 r
% screen_desktop_layout
.rows
);
874 case OB_CORNER_TOPRIGHT
:
875 return (screen_desktop_layout
.columns
- 1 -
876 c
% screen_desktop_layout
.columns
) *
877 screen_desktop_layout
.rows
+
878 r
% screen_desktop_layout
.rows
;
879 case OB_CORNER_BOTTOMRIGHT
:
880 return (screen_desktop_layout
.columns
- 1 -
881 c
% screen_desktop_layout
.columns
) *
882 screen_desktop_layout
.rows
+
883 (screen_desktop_layout
.rows
- 1 -
884 r
% screen_desktop_layout
.rows
);
887 g_assert_not_reached();
891 static gboolean
hide_desktop_popup_func(gpointer data
)
893 pager_popup_hide(desktop_popup
);
894 return FALSE
; /* don't repeat */
897 void screen_show_desktop_popup(guint d
)
901 /* 0 means don't show the popup */
902 if (!config_desktop_popup_time
) return;
904 a
= screen_physical_area_active();
905 pager_popup_position(desktop_popup
, CenterGravity
,
906 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
907 pager_popup_icon_size_multiplier(desktop_popup
,
908 (screen_desktop_layout
.columns
/
909 screen_desktop_layout
.rows
) / 2,
910 (screen_desktop_layout
.rows
/
911 screen_desktop_layout
.columns
) / 2);
912 pager_popup_max_width(desktop_popup
,
913 MAX(a
->width
/3, POPUP_WIDTH
));
914 pager_popup_show(desktop_popup
, screen_desktop_names
[d
], d
);
916 obt_main_loop_timeout_remove(ob_main_loop
, hide_desktop_popup_func
);
917 obt_main_loop_timeout_add(ob_main_loop
, config_desktop_popup_time
* 1000,
918 hide_desktop_popup_func
, NULL
, NULL
, NULL
);
922 void screen_hide_desktop_popup(void)
924 obt_main_loop_timeout_remove(ob_main_loop
, hide_desktop_popup_func
);
925 pager_popup_hide(desktop_popup
);
928 guint
screen_find_desktop(guint from
, ObDirection dir
,
929 gboolean wrap
, gboolean linear
)
935 get_row_col(d
, &r
, &c
);
938 case OB_DIRECTION_EAST
:
939 if (d
< screen_num_desktops
- 1)
946 case OB_DIRECTION_WEST
:
950 d
= screen_num_desktops
- 1;
955 g_assert_not_reached();
960 case OB_DIRECTION_EAST
:
962 if (c
>= screen_desktop_layout
.columns
) {
968 d
= translate_row_col(r
, c
);
969 if (d
>= screen_num_desktops
) {
976 case OB_DIRECTION_WEST
:
978 if (c
>= screen_desktop_layout
.columns
) {
980 c
= screen_desktop_layout
.columns
- 1;
984 d
= translate_row_col(r
, c
);
985 if (d
>= screen_num_desktops
) {
992 case OB_DIRECTION_SOUTH
:
994 if (r
>= screen_desktop_layout
.rows
) {
1000 d
= translate_row_col(r
, c
);
1001 if (d
>= screen_num_desktops
) {
1008 case OB_DIRECTION_NORTH
:
1010 if (r
>= screen_desktop_layout
.rows
) {
1012 r
= screen_desktop_layout
.rows
- 1;
1016 d
= translate_row_col(r
, c
);
1017 if (d
>= screen_num_desktops
) {
1025 g_assert_not_reached();
1029 d
= translate_row_col(r
, c
);
1034 static gboolean
screen_validate_layout(ObDesktopLayout
*l
)
1036 if (l
->columns
== 0 && l
->rows
== 0) /* both 0's is bad data.. */
1039 /* fill in a zero rows/columns */
1040 if (l
->columns
== 0) {
1041 l
->columns
= screen_num_desktops
/ l
->rows
;
1042 if (l
->rows
* l
->columns
< screen_num_desktops
)
1044 if (l
->rows
* l
->columns
>= screen_num_desktops
+ l
->columns
)
1046 } else if (l
->rows
== 0) {
1047 l
->rows
= screen_num_desktops
/ l
->columns
;
1048 if (l
->columns
* l
->rows
< screen_num_desktops
)
1050 if (l
->columns
* l
->rows
>= screen_num_desktops
+ l
->rows
)
1054 /* bounds checking */
1055 if (l
->orientation
== OB_ORIENTATION_HORZ
) {
1056 l
->columns
= MIN(screen_num_desktops
, l
->columns
);
1057 l
->rows
= MIN(l
->rows
,
1058 (screen_num_desktops
+ l
->columns
- 1) / l
->columns
);
1059 l
->columns
= screen_num_desktops
/ l
->rows
+
1060 !!(screen_num_desktops
% l
->rows
);
1062 l
->rows
= MIN(screen_num_desktops
, l
->rows
);
1063 l
->columns
= MIN(l
->columns
,
1064 (screen_num_desktops
+ l
->rows
- 1) / l
->rows
);
1065 l
->rows
= screen_num_desktops
/ l
->columns
+
1066 !!(screen_num_desktops
% l
->columns
);
1071 void screen_update_layout(void)
1078 screen_desktop_layout
.orientation
= OB_ORIENTATION_HORZ
;
1079 screen_desktop_layout
.start_corner
= OB_CORNER_TOPLEFT
;
1080 screen_desktop_layout
.rows
= 1;
1081 screen_desktop_layout
.columns
= screen_num_desktops
;
1083 if (OBT_PROP_GETA32(obt_root(ob_screen
),
1084 NET_DESKTOP_LAYOUT
, CARDINAL
, &data
, &num
)) {
1085 if (num
== 3 || num
== 4) {
1087 if (data
[0] == OBT_PROP_ATOM(NET_WM_ORIENTATION_VERT
))
1088 l
.orientation
= OB_ORIENTATION_VERT
;
1089 else if (data
[0] == OBT_PROP_ATOM(NET_WM_ORIENTATION_HORZ
))
1090 l
.orientation
= OB_ORIENTATION_HORZ
;
1095 l
.start_corner
= OB_CORNER_TOPLEFT
;
1097 if (data
[3] == OBT_PROP_ATOM(NET_WM_TOPLEFT
))
1098 l
.start_corner
= OB_CORNER_TOPLEFT
;
1099 else if (data
[3] == OBT_PROP_ATOM(NET_WM_TOPRIGHT
))
1100 l
.start_corner
= OB_CORNER_TOPRIGHT
;
1101 else if (data
[3] == OBT_PROP_ATOM(NET_WM_BOTTOMRIGHT
))
1102 l
.start_corner
= OB_CORNER_BOTTOMRIGHT
;
1103 else if (data
[3] == OBT_PROP_ATOM(NET_WM_BOTTOMLEFT
))
1104 l
.start_corner
= OB_CORNER_BOTTOMLEFT
;
1109 l
.columns
= data
[1];
1112 if (screen_validate_layout(&l
))
1113 screen_desktop_layout
= l
;
1120 void screen_update_desktop_names(void)
1124 /* empty the array */
1125 g_strfreev(screen_desktop_names
);
1126 screen_desktop_names
= NULL
;
1128 if (OBT_PROP_GETSS(obt_root(ob_screen
),
1129 NET_DESKTOP_NAMES
, utf8
, &screen_desktop_names
))
1130 for (i
= 0; screen_desktop_names
[i
] && i
< screen_num_desktops
; ++i
);
1133 if (i
< screen_num_desktops
) {
1136 screen_desktop_names
= g_renew(gchar
*, screen_desktop_names
,
1137 screen_num_desktops
+ 1);
1138 screen_desktop_names
[screen_num_desktops
] = NULL
;
1140 it
= g_slist_nth(config_desktops_names
, i
);
1142 for (; i
< screen_num_desktops
; ++i
) {
1143 if (it
&& ((char*)it
->data
)[0]) /* not empty */
1144 /* use the names from the config file when possible */
1145 screen_desktop_names
[i
] = g_strdup(it
->data
);
1147 /* make up a nice name if it's not though */
1148 screen_desktop_names
[i
] = g_strdup_printf(_("desktop %i"),
1150 if (it
) it
= g_slist_next(it
);
1153 /* if we changed any names, then set the root property so we can
1154 all agree on the names */
1155 OBT_PROP_SETSS(obt_root(ob_screen
), NET_DESKTOP_NAMES
,
1156 utf8
, (const gchar
**)screen_desktop_names
);
1159 /* resize the pager for these names */
1160 pager_popup_text_width_to_strings(desktop_popup
,
1161 screen_desktop_names
,
1162 screen_num_desktops
);
1165 void screen_show_desktop(gboolean show
, ObClient
*show_only
)
1169 if (show
== screen_showing_desktop
) return; /* no change */
1171 screen_showing_desktop
= show
;
1174 /* hide windows bottom to top */
1175 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
1176 if (WINDOW_IS_CLIENT(it
->data
)) {
1177 ObClient
*client
= it
->data
;
1178 client_showhide(client
);
1183 /* restore windows top to bottom */
1184 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
1185 if (WINDOW_IS_CLIENT(it
->data
)) {
1186 ObClient
*client
= it
->data
;
1187 if (client_should_show(client
)) {
1188 if (!show_only
|| client
== show_only
)
1189 client_show(client
);
1191 client_iconify(client
, TRUE
, FALSE
, TRUE
);
1198 /* focus the desktop */
1199 for (it
= focus_order
; it
; it
= g_list_next(it
)) {
1200 ObClient
*c
= it
->data
;
1201 if (c
->type
== OB_CLIENT_TYPE_DESKTOP
&&
1202 (c
->desktop
== screen_desktop
|| c
->desktop
== DESKTOP_ALL
) &&
1203 client_focus(it
->data
))
1207 else if (!show_only
) {
1210 if ((c
= focus_fallback(TRUE
, FALSE
, TRUE
, FALSE
))) {
1211 /* only do the flicker reducing stuff ahead of time if we are going
1212 to call xsetinputfocus on the window ourselves. otherwise there
1213 is no guarantee the window will actually take focus.. */
1215 /* reduce flicker by hiliting now rather than waiting for the
1216 server FocusIn event */
1217 frame_adjust_focus(c
->frame
, TRUE
);
1222 show
= !!show
; /* make it boolean */
1223 OBT_PROP_SET32(obt_root(ob_screen
), NET_SHOWING_DESKTOP
, CARDINAL
, show
);
1226 void screen_install_colormap(ObClient
*client
, gboolean install
)
1228 if (client
== NULL
|| client
->colormap
== None
) {
1230 XInstallColormap(obt_display
, RrColormap(ob_rr_inst
));
1232 XUninstallColormap(obt_display
, RrColormap(ob_rr_inst
));
1234 obt_display_ignore_errors(TRUE
);
1236 XInstallColormap(obt_display
, client
->colormap
);
1238 XUninstallColormap(obt_display
, client
->colormap
);
1239 obt_display_ignore_errors(FALSE
);
1243 #define STRUT_LEFT_ON_MONITOR(s, i) \
1244 (RANGES_INTERSECT(s->left_start, s->left_end - s->left_start + 1, \
1245 monitor_area[i].y, monitor_area[i].height))
1246 #define STRUT_RIGHT_ON_MONITOR(s, i) \
1247 (RANGES_INTERSECT(s->right_start, s->right_end - s->right_start + 1, \
1248 monitor_area[i].y, monitor_area[i].height))
1249 #define STRUT_TOP_ON_MONITOR(s, i) \
1250 (RANGES_INTERSECT(s->top_start, s->top_end - s->top_start + 1, \
1251 monitor_area[i].x, monitor_area[i].width))
1252 #define STRUT_BOTTOM_ON_MONITOR(s, i) \
1253 (RANGES_INTERSECT(s->bottom_start, s->bottom_end - s->bottom_start + 1, \
1254 monitor_area[i].x, monitor_area[i].width))
1258 StrutPartial
*strut
;
1261 #define RESET_STRUT_LIST(sl) \
1262 (g_slist_free(sl), sl = NULL)
1264 #define ADD_STRUT_TO_LIST(sl, d, s) \
1266 ObScreenStrut *ss = g_new(ObScreenStrut, 1); \
1269 sl = g_slist_prepend(sl, ss); \
1272 #define VALIDATE_STRUTS(sl, side, max) \
1275 for (it = sl; it; it = g_slist_next(it)) { \
1276 ObScreenStrut *ss = it->data; \
1277 ss->strut->side = MIN(max, ss->strut->side); \
1281 static void get_xinerama_screens(Rect
**xin_areas
, guint
*nxin
)
1286 if (ob_debug_xinerama
) {
1287 g_print("Using fake xinerama !\n");
1288 gint w
= WidthOfScreen(ScreenOfDisplay(obt_display
, ob_screen
));
1289 gint h
= HeightOfScreen(ScreenOfDisplay(obt_display
, ob_screen
));
1291 *xin_areas
= g_new(Rect
, *nxin
+ 1);
1292 RECT_SET((*xin_areas
)[0], 0, 0, w
/2, h
);
1293 RECT_SET((*xin_areas
)[1], w
/2, 0, w
-(w
/2), h
);
1296 else if (obt_display_extension_xinerama
) {
1299 XineramaScreenInfo
*info
= XineramaQueryScreens(obt_display
, &n
);
1301 *xin_areas
= g_new(Rect
, *nxin
+ 1);
1302 for (i
= 0; i
< *nxin
; ++i
)
1303 RECT_SET((*xin_areas
)[i
], info
[i
].x_org
, info
[i
].y_org
,
1304 info
[i
].width
, info
[i
].height
);
1310 *xin_areas
= g_new(Rect
, *nxin
+ 1);
1311 RECT_SET((*xin_areas
)[0], 0, 0,
1312 WidthOfScreen(ScreenOfDisplay(obt_display
, ob_screen
)),
1313 HeightOfScreen(ScreenOfDisplay(obt_display
, ob_screen
)));
1316 /* returns one extra with the total area in it */
1317 l
= (*xin_areas
)[0].x
;
1318 t
= (*xin_areas
)[0].y
;
1319 r
= (*xin_areas
)[0].x
+ (*xin_areas
)[0].width
- 1;
1320 b
= (*xin_areas
)[0].y
+ (*xin_areas
)[0].height
- 1;
1321 for (i
= 1; i
< *nxin
; ++i
) {
1322 l
= MIN(l
, (*xin_areas
)[i
].x
);
1323 t
= MIN(l
, (*xin_areas
)[i
].y
);
1324 r
= MAX(r
, (*xin_areas
)[i
].x
+ (*xin_areas
)[i
].width
- 1);
1325 b
= MAX(b
, (*xin_areas
)[i
].y
+ (*xin_areas
)[i
].height
- 1);
1327 RECT_SET((*xin_areas
)[*nxin
], l
, t
, r
- l
+ 1, b
- t
+ 1);
1330 void screen_update_areas(void)
1337 g_free(monitor_area
);
1338 get_xinerama_screens(&monitor_area
, &screen_num_monitors
);
1340 /* set up the user-specified margins */
1341 config_margins
.top_start
= RECT_LEFT(monitor_area
[screen_num_monitors
]);
1342 config_margins
.top_end
= RECT_RIGHT(monitor_area
[screen_num_monitors
]);
1343 config_margins
.bottom_start
= RECT_LEFT(monitor_area
[screen_num_monitors
]);
1344 config_margins
.bottom_end
= RECT_RIGHT(monitor_area
[screen_num_monitors
]);
1345 config_margins
.left_start
= RECT_TOP(monitor_area
[screen_num_monitors
]);
1346 config_margins
.left_end
= RECT_BOTTOM(monitor_area
[screen_num_monitors
]);
1347 config_margins
.right_start
= RECT_TOP(monitor_area
[screen_num_monitors
]);
1348 config_margins
.right_end
= RECT_BOTTOM(monitor_area
[screen_num_monitors
]);
1350 dims
= g_new(gulong
, 4 * screen_num_desktops
* screen_num_monitors
);
1352 RESET_STRUT_LIST(struts_left
);
1353 RESET_STRUT_LIST(struts_top
);
1354 RESET_STRUT_LIST(struts_right
);
1355 RESET_STRUT_LIST(struts_bottom
);
1357 /* collect the struts */
1358 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1359 ObClient
*c
= it
->data
;
1361 ADD_STRUT_TO_LIST(struts_left
, c
->desktop
, &c
->strut
);
1363 ADD_STRUT_TO_LIST(struts_top
, c
->desktop
, &c
->strut
);
1365 ADD_STRUT_TO_LIST(struts_right
, c
->desktop
, &c
->strut
);
1366 if (c
->strut
.bottom
)
1367 ADD_STRUT_TO_LIST(struts_bottom
, c
->desktop
, &c
->strut
);
1369 if (dock_strut
.left
)
1370 ADD_STRUT_TO_LIST(struts_left
, DESKTOP_ALL
, &dock_strut
);
1372 ADD_STRUT_TO_LIST(struts_top
, DESKTOP_ALL
, &dock_strut
);
1373 if (dock_strut
.right
)
1374 ADD_STRUT_TO_LIST(struts_right
, DESKTOP_ALL
, &dock_strut
);
1375 if (dock_strut
.bottom
)
1376 ADD_STRUT_TO_LIST(struts_bottom
, DESKTOP_ALL
, &dock_strut
);
1378 if (config_margins
.left
)
1379 ADD_STRUT_TO_LIST(struts_left
, DESKTOP_ALL
, &config_margins
);
1380 if (config_margins
.top
)
1381 ADD_STRUT_TO_LIST(struts_top
, DESKTOP_ALL
, &config_margins
);
1382 if (config_margins
.right
)
1383 ADD_STRUT_TO_LIST(struts_right
, DESKTOP_ALL
, &config_margins
);
1384 if (config_margins
.bottom
)
1385 ADD_STRUT_TO_LIST(struts_bottom
, DESKTOP_ALL
, &config_margins
);
1387 VALIDATE_STRUTS(struts_left
, left
,
1388 monitor_area
[screen_num_monitors
].width
/ 2);
1389 VALIDATE_STRUTS(struts_right
, right
,
1390 monitor_area
[screen_num_monitors
].width
/ 2);
1391 VALIDATE_STRUTS(struts_top
, top
,
1392 monitor_area
[screen_num_monitors
].height
/ 2);
1393 VALIDATE_STRUTS(struts_bottom
, bottom
,
1394 monitor_area
[screen_num_monitors
].height
/ 2);
1396 /* set up the work areas to be full screen */
1397 for (i
= 0; i
< screen_num_monitors
; ++i
)
1398 for (j
= 0; j
< screen_num_desktops
; ++j
) {
1399 dims
[(i
* screen_num_desktops
+ j
) * 4+0] = monitor_area
[i
].x
;
1400 dims
[(i
* screen_num_desktops
+ j
) * 4+1] = monitor_area
[i
].y
;
1401 dims
[(i
* screen_num_desktops
+ j
) * 4+2] = monitor_area
[i
].width
;
1402 dims
[(i
* screen_num_desktops
+ j
) * 4+3] = monitor_area
[i
].height
;
1405 /* calculate the work areas from the struts */
1406 for (i
= 0; i
< screen_num_monitors
; ++i
)
1407 for (j
= 0; j
< screen_num_desktops
; ++j
) {
1408 gint l
= 0, r
= 0, t
= 0, b
= 0;
1410 /* only add the strut to the area if it touches the monitor */
1412 for (sit
= struts_left
; sit
; sit
= g_slist_next(sit
)) {
1413 ObScreenStrut
*s
= sit
->data
;
1414 if ((s
->desktop
== j
|| s
->desktop
== DESKTOP_ALL
) &&
1415 STRUT_LEFT_ON_MONITOR(s
->strut
, i
))
1416 l
= MAX(l
, s
->strut
->left
);
1418 for (sit
= struts_top
; sit
; sit
= g_slist_next(sit
)) {
1419 ObScreenStrut
*s
= sit
->data
;
1420 if ((s
->desktop
== j
|| s
->desktop
== DESKTOP_ALL
) &&
1421 STRUT_TOP_ON_MONITOR(s
->strut
, i
))
1422 t
= MAX(t
, s
->strut
->top
);
1424 for (sit
= struts_right
; sit
; sit
= g_slist_next(sit
)) {
1425 ObScreenStrut
*s
= sit
->data
;
1426 if ((s
->desktop
== j
|| s
->desktop
== DESKTOP_ALL
) &&
1427 STRUT_RIGHT_ON_MONITOR(s
->strut
, i
))
1428 r
= MAX(r
, s
->strut
->right
);
1430 for (sit
= struts_bottom
; sit
; sit
= g_slist_next(sit
)) {
1431 ObScreenStrut
*s
= sit
->data
;
1432 if ((s
->desktop
== j
|| s
->desktop
== DESKTOP_ALL
) &&
1433 STRUT_BOTTOM_ON_MONITOR(s
->strut
, i
))
1434 b
= MAX(b
, s
->strut
->bottom
);
1437 /* based on these margins, set the work area for the
1439 dims
[(i
* screen_num_desktops
+ j
) * 4 + 0] += l
;
1440 dims
[(i
* screen_num_desktops
+ j
) * 4 + 1] += t
;
1441 dims
[(i
* screen_num_desktops
+ j
) * 4 + 2] -= l
+ r
;
1442 dims
[(i
* screen_num_desktops
+ j
) * 4 + 3] -= t
+ b
;
1445 /* all the work areas are not used here, only the ones for the first
1447 OBT_PROP_SETA32(obt_root(ob_screen
), NET_WORKAREA
, CARDINAL
,
1448 dims
, 4 * screen_num_desktops
);
1450 /* the area has changed, adjust all the windows if they need it */
1451 for (it
= client_list
; it
; it
= g_list_next(it
))
1452 client_reconfigure(it
->data
, FALSE
);
1458 Rect
* screen_area_all_monitors(guint desktop
)
1463 a
= screen_area_monitor(desktop
, 0);
1465 /* combine all the monitors together */
1466 for (i
= 1; i
< screen_num_monitors
; ++i
) {
1467 Rect
*m
= screen_area_monitor(desktop
, i
);
1470 l
= MIN(RECT_LEFT(*a
), RECT_LEFT(*m
));
1471 t
= MIN(RECT_TOP(*a
), RECT_TOP(*m
));
1472 r
= MAX(RECT_RIGHT(*a
), RECT_RIGHT(*m
));
1473 b
= MAX(RECT_BOTTOM(*a
), RECT_BOTTOM(*m
));
1475 RECT_SET(*a
, l
, t
, r
- l
+ 1, b
- t
+ 1);
1484 #define STRUT_LEFT_IN_SEARCH(s, search) \
1485 (RANGES_INTERSECT(search->y, search->height, \
1486 s->left_start, s->left_end - s->left_start + 1))
1487 #define STRUT_RIGHT_IN_SEARCH(s, search) \
1488 (RANGES_INTERSECT(search->y, search->height, \
1489 s->right_start, s->right_end - s->right_start + 1))
1490 #define STRUT_TOP_IN_SEARCH(s, search) \
1491 (RANGES_INTERSECT(search->x, search->width, \
1492 s->top_start, s->top_end - s->top_start + 1))
1493 #define STRUT_BOTTOM_IN_SEARCH(s, search) \
1494 (RANGES_INTERSECT(search->x, search->width, \
1495 s->bottom_start, s->bottom_end - s->bottom_start + 1))
1497 #define STRUT_LEFT_IGNORE(s, us, search) \
1498 (head == SCREEN_AREA_ALL_MONITORS && us && \
1499 RECT_LEFT(monitor_area[i]) + s->left > RECT_LEFT(*search))
1500 #define STRUT_RIGHT_IGNORE(s, us, search) \
1501 (head == SCREEN_AREA_ALL_MONITORS && us && \
1502 RECT_RIGHT(monitor_area[i]) - s->right < RECT_RIGHT(*search))
1503 #define STRUT_TOP_IGNORE(s, us, search) \
1504 (head == SCREEN_AREA_ALL_MONITORS && us && \
1505 RECT_TOP(monitor_area[i]) + s->top > RECT_TOP(*search))
1506 #define STRUT_BOTTOM_IGNORE(s, us, search) \
1507 (head == SCREEN_AREA_ALL_MONITORS && us && \
1508 RECT_BOTTOM(monitor_area[i]) - s->bottom < RECT_BOTTOM(*search))
1510 Rect
* screen_area(guint desktop
, guint head
, Rect
*search
)
1514 gint l
, r
, t
, b
, al
, ar
, at
, ab
;
1516 gboolean us
= search
!= NULL
; /* user provided search */
1518 g_assert(desktop
< screen_num_desktops
|| desktop
== DESKTOP_ALL
);
1519 g_assert(head
< screen_num_monitors
|| head
== SCREEN_AREA_ONE_MONITOR
||
1520 head
== SCREEN_AREA_ALL_MONITORS
);
1521 g_assert(!(head
== SCREEN_AREA_ONE_MONITOR
&& search
== NULL
));
1523 /* find any struts for this monitor
1524 which will be affecting the search area.
1527 /* search everything if search is null */
1529 if (head
< screen_num_monitors
) search
= &monitor_area
[head
];
1530 else search
= &monitor_area
[screen_num_monitors
];
1532 if (head
== SCREEN_AREA_ONE_MONITOR
) head
= screen_find_monitor(search
);
1534 /* al is "all left" meaning the furthest left you can get, l is our
1535 "working left" meaning our current strut edge which we're calculating
1538 /* only include monitors which the search area lines up with */
1539 if (RECT_INTERSECTS_RECT(monitor_area
[screen_num_monitors
], *search
)) {
1540 al
= l
= RECT_RIGHT(monitor_area
[screen_num_monitors
]);
1541 at
= t
= RECT_BOTTOM(monitor_area
[screen_num_monitors
]);
1542 ar
= r
= RECT_LEFT(monitor_area
[screen_num_monitors
]);
1543 ab
= b
= RECT_TOP(monitor_area
[screen_num_monitors
]);
1544 for (i
= 0; i
< screen_num_monitors
; ++i
) {
1545 /* add the monitor if applicable */
1546 if (RANGES_INTERSECT(search
->x
, search
->width
,
1547 monitor_area
[i
].x
, monitor_area
[i
].width
))
1549 at
= t
= MIN(t
, RECT_TOP(monitor_area
[i
]));
1550 ab
= b
= MAX(b
, RECT_BOTTOM(monitor_area
[i
]));
1552 if (RANGES_INTERSECT(search
->y
, search
->height
,
1553 monitor_area
[i
].y
, monitor_area
[i
].height
))
1555 al
= l
= MIN(l
, RECT_LEFT(monitor_area
[i
]));
1556 ar
= r
= MAX(r
, RECT_RIGHT(monitor_area
[i
]));
1560 al
= l
= RECT_LEFT(monitor_area
[screen_num_monitors
]);
1561 at
= t
= RECT_TOP(monitor_area
[screen_num_monitors
]);
1562 ar
= r
= RECT_RIGHT(monitor_area
[screen_num_monitors
]);
1563 ab
= b
= RECT_BOTTOM(monitor_area
[screen_num_monitors
]);
1566 for (d
= 0; d
< screen_num_desktops
; ++d
) {
1567 if (d
!= desktop
&& desktop
!= DESKTOP_ALL
) continue;
1569 for (i
= 0; i
< screen_num_monitors
; ++i
) {
1570 if (head
!= SCREEN_AREA_ALL_MONITORS
&& head
!= i
) continue;
1572 for (it
= struts_left
; it
; it
= g_slist_next(it
)) {
1573 ObScreenStrut
*s
= it
->data
;
1574 if ((s
->desktop
== d
|| s
->desktop
== DESKTOP_ALL
) &&
1575 STRUT_LEFT_IN_SEARCH(s
->strut
, search
) &&
1576 !STRUT_LEFT_IGNORE(s
->strut
, us
, search
))
1577 l
= MAX(l
, al
+ s
->strut
->left
);
1579 for (it
= struts_top
; it
; it
= g_slist_next(it
)) {
1580 ObScreenStrut
*s
= it
->data
;
1581 if ((s
->desktop
== d
|| s
->desktop
== DESKTOP_ALL
) &&
1582 STRUT_TOP_IN_SEARCH(s
->strut
, search
) &&
1583 !STRUT_TOP_IGNORE(s
->strut
, us
, search
))
1584 t
= MAX(t
, at
+ s
->strut
->top
);
1586 for (it
= struts_right
; it
; it
= g_slist_next(it
)) {
1587 ObScreenStrut
*s
= it
->data
;
1588 if ((s
->desktop
== d
|| s
->desktop
== DESKTOP_ALL
) &&
1589 STRUT_RIGHT_IN_SEARCH(s
->strut
, search
) &&
1590 !STRUT_RIGHT_IGNORE(s
->strut
, us
, search
))
1591 r
= MIN(r
, ar
- s
->strut
->right
);
1593 for (it
= struts_bottom
; it
; it
= g_slist_next(it
)) {
1594 ObScreenStrut
*s
= it
->data
;
1595 if ((s
->desktop
== d
|| s
->desktop
== DESKTOP_ALL
) &&
1596 STRUT_BOTTOM_IN_SEARCH(s
->strut
, search
) &&
1597 !STRUT_BOTTOM_IGNORE(s
->strut
, us
, search
))
1598 b
= MIN(b
, ab
- s
->strut
->bottom
);
1601 /* limit to this monitor */
1603 l
= MAX(l
, RECT_LEFT(monitor_area
[i
]));
1604 t
= MAX(t
, RECT_TOP(monitor_area
[i
]));
1605 r
= MIN(r
, RECT_RIGHT(monitor_area
[i
]));
1606 b
= MIN(b
, RECT_BOTTOM(monitor_area
[i
]));
1614 a
->width
= r
- l
+ 1;
1615 a
->height
= b
- t
+ 1;
1619 guint
screen_find_monitor(Rect
*search
)
1622 guint most
= screen_num_monitors
;
1625 for (i
= 0; i
< screen_num_monitors
; ++i
) {
1626 Rect
*area
= screen_physical_area_monitor(i
);
1627 if (RECT_INTERSECTS_RECT(*area
, *search
)) {
1631 RECT_SET_INTERSECTION(r
, *area
, *search
);
1632 v
= r
.width
* r
.height
;
1644 Rect
* screen_physical_area_all_monitors(void)
1646 return screen_physical_area_monitor(screen_num_monitors
);
1649 Rect
* screen_physical_area_monitor(guint head
)
1652 g_assert(head
<= screen_num_monitors
);
1655 *a
= monitor_area
[head
];
1659 gboolean
screen_physical_area_monitor_contains(guint head
, Rect
*search
)
1661 g_assert(head
<= screen_num_monitors
);
1663 return RECT_INTERSECTS_RECT(monitor_area
[head
], *search
);
1666 Rect
* screen_physical_area_active(void)
1671 if (moveresize_client
)
1672 a
= screen_physical_area_monitor(client_monitor(focus_client
));
1673 else if (focus_client
)
1674 a
= screen_physical_area_monitor(client_monitor(focus_client
));
1677 if (screen_pointer_pos(&x
, &y
))
1678 RECT_SET(mon
, x
, y
, 1, 1);
1680 RECT_SET(mon
, 0, 0, 1, 1);
1681 a
= screen_physical_area_monitor(screen_find_monitor(&mon
));
1686 void screen_set_root_cursor(void)
1688 if (sn_app_starting())
1689 XDefineCursor(obt_display
, obt_root(ob_screen
),
1690 ob_cursor(OB_CURSOR_BUSYPOINTER
));
1692 XDefineCursor(obt_display
, obt_root(ob_screen
),
1693 ob_cursor(OB_CURSOR_POINTER
));
1696 gboolean
screen_pointer_pos(gint
*x
, gint
*y
)
1703 ret
= !!XQueryPointer(obt_display
, obt_root(ob_screen
),
1704 &w
, &w
, x
, y
, &i
, &i
, &u
);
1706 for (i
= 0; i
< ScreenCount(obt_display
); ++i
)
1708 if (XQueryPointer(obt_display
, obt_root(i
),
1709 &w
, &w
, x
, y
, &i
, &i
, &u
))