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.
26 #include "startupnotify.h"
27 #include "moveresize.h"
36 #include "extensions.h"
37 #include "render/render.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 | ButtonMotionMask)
53 guint screen_num_desktops
;
54 guint screen_num_monitors
;
56 guint screen_last_desktop
;
57 Size screen_physical_size
;
58 gboolean screen_showing_desktop
;
59 DesktopLayout screen_desktop_layout
;
60 gchar
**screen_desktop_names
;
61 Window screen_support_win
;
62 Time screen_desktop_user_time
= CurrentTime
;
64 static Rect
**area
; /* array of desktop holding array of xinerama areas */
65 static Rect
*monitor_area
;
67 static ObPagerPopup
*desktop_cycle_popup
;
69 static gboolean
replace_wm()
73 Window current_wm_sn_owner
;
76 wm_sn
= g_strdup_printf("WM_S%d", ob_screen
);
77 wm_sn_atom
= XInternAtom(ob_display
, wm_sn
, FALSE
);
80 current_wm_sn_owner
= XGetSelectionOwner(ob_display
, wm_sn_atom
);
81 if (current_wm_sn_owner
== screen_support_win
)
82 current_wm_sn_owner
= None
;
83 if (current_wm_sn_owner
) {
85 g_message(_("A window manager is already running on screen %d"),
89 xerror_set_ignore(TRUE
);
90 xerror_occured
= FALSE
;
92 /* We want to find out when the current selection owner dies */
93 XSelectInput(ob_display
, current_wm_sn_owner
, StructureNotifyMask
);
94 XSync(ob_display
, FALSE
);
96 xerror_set_ignore(FALSE
);
98 current_wm_sn_owner
= None
;
102 /* Generate a timestamp */
105 XSelectInput(ob_display
, screen_support_win
, PropertyChangeMask
);
107 XChangeProperty(ob_display
, screen_support_win
,
108 prop_atoms
.wm_class
, prop_atoms
.string
,
109 8, PropModeAppend
, NULL
, 0);
110 XWindowEvent(ob_display
, screen_support_win
,
111 PropertyChangeMask
, &event
);
113 XSelectInput(ob_display
, screen_support_win
, NoEventMask
);
115 timestamp
= event
.xproperty
.time
;
118 XSetSelectionOwner(ob_display
, wm_sn_atom
, screen_support_win
,
121 if (XGetSelectionOwner(ob_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(ob_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 prop_message(RootWindow(ob_display
, ob_screen
), prop_atoms
.manager
,
150 timestamp
, wm_sn_atom
, screen_support_win
, 0,
151 SubstructureNotifyMask
);
156 gboolean
screen_annex(const gchar
*program_name
)
158 XSetWindowAttributes attrib
;
161 Atom
*prop_atoms_start
, *wm_supported_pos
;
164 /* create the netwm support window */
165 attrib
.override_redirect
= TRUE
;
166 screen_support_win
= XCreateWindow(ob_display
,
167 RootWindow(ob_display
, ob_screen
),
169 CopyFromParent
, InputOutput
,
171 CWOverrideRedirect
, &attrib
);
172 XMapWindow(ob_display
, screen_support_win
);
173 XLowerWindow(ob_display
, screen_support_win
);
176 XDestroyWindow(ob_display
, screen_support_win
);
180 xerror_set_ignore(TRUE
);
181 xerror_occured
= FALSE
;
182 XSelectInput(ob_display
, RootWindow(ob_display
, ob_screen
),
184 xerror_set_ignore(FALSE
);
185 if (xerror_occured
) {
186 g_message(_("A window manager is already running on screen %d"),
189 XDestroyWindow(ob_display
, screen_support_win
);
194 screen_set_root_cursor();
196 /* set the OPENBOX_PID hint */
198 PROP_SET32(RootWindow(ob_display
, ob_screen
),
199 openbox_pid
, cardinal
, pid
);
201 /* set supporting window */
202 PROP_SET32(RootWindow(ob_display
, ob_screen
),
203 net_supporting_wm_check
, window
, screen_support_win
);
205 /* set properties on the supporting window */
206 PROP_SETS(screen_support_win
, net_wm_name
, program_name
);
207 PROP_SET32(screen_support_win
, net_supporting_wm_check
,
208 window
, screen_support_win
);
210 /* set the _NET_SUPPORTED_ATOMS hint */
212 /* this is all the atoms after net_supported in the prop_atoms struct */
213 prop_atoms_start
= (Atom
*)&prop_atoms
;
214 wm_supported_pos
= (Atom
*)&(prop_atoms
.net_supported
);
215 num_support
= sizeof(prop_atoms
) / sizeof(Atom
) -
216 (wm_supported_pos
- prop_atoms_start
) - 1;
218 supported
= g_new(gulong
, num_support
);
219 supported
[i
++] = prop_atoms
.net_supporting_wm_check
;
220 supported
[i
++] = prop_atoms
.net_wm_full_placement
;
221 supported
[i
++] = prop_atoms
.net_current_desktop
;
222 supported
[i
++] = prop_atoms
.net_number_of_desktops
;
223 supported
[i
++] = prop_atoms
.net_desktop_geometry
;
224 supported
[i
++] = prop_atoms
.net_desktop_viewport
;
225 supported
[i
++] = prop_atoms
.net_active_window
;
226 supported
[i
++] = prop_atoms
.net_workarea
;
227 supported
[i
++] = prop_atoms
.net_client_list
;
228 supported
[i
++] = prop_atoms
.net_client_list_stacking
;
229 supported
[i
++] = prop_atoms
.net_desktop_names
;
230 supported
[i
++] = prop_atoms
.net_close_window
;
231 supported
[i
++] = prop_atoms
.net_desktop_layout
;
232 supported
[i
++] = prop_atoms
.net_showing_desktop
;
233 supported
[i
++] = prop_atoms
.net_wm_name
;
234 supported
[i
++] = prop_atoms
.net_wm_visible_name
;
235 supported
[i
++] = prop_atoms
.net_wm_icon_name
;
236 supported
[i
++] = prop_atoms
.net_wm_visible_icon_name
;
237 supported
[i
++] = prop_atoms
.net_wm_desktop
;
238 supported
[i
++] = prop_atoms
.net_wm_strut
;
239 supported
[i
++] = prop_atoms
.net_wm_strut_partial
;
240 supported
[i
++] = prop_atoms
.net_wm_icon
;
241 supported
[i
++] = prop_atoms
.net_wm_icon_geometry
;
242 supported
[i
++] = prop_atoms
.net_wm_window_type
;
243 supported
[i
++] = prop_atoms
.net_wm_window_type_desktop
;
244 supported
[i
++] = prop_atoms
.net_wm_window_type_dock
;
245 supported
[i
++] = prop_atoms
.net_wm_window_type_toolbar
;
246 supported
[i
++] = prop_atoms
.net_wm_window_type_menu
;
247 supported
[i
++] = prop_atoms
.net_wm_window_type_utility
;
248 supported
[i
++] = prop_atoms
.net_wm_window_type_splash
;
249 supported
[i
++] = prop_atoms
.net_wm_window_type_dialog
;
250 supported
[i
++] = prop_atoms
.net_wm_window_type_normal
;
251 supported
[i
++] = prop_atoms
.net_wm_allowed_actions
;
252 supported
[i
++] = prop_atoms
.net_wm_action_move
;
253 supported
[i
++] = prop_atoms
.net_wm_action_resize
;
254 supported
[i
++] = prop_atoms
.net_wm_action_minimize
;
255 supported
[i
++] = prop_atoms
.net_wm_action_shade
;
256 supported
[i
++] = prop_atoms
.net_wm_action_maximize_horz
;
257 supported
[i
++] = prop_atoms
.net_wm_action_maximize_vert
;
258 supported
[i
++] = prop_atoms
.net_wm_action_fullscreen
;
259 supported
[i
++] = prop_atoms
.net_wm_action_change_desktop
;
260 supported
[i
++] = prop_atoms
.net_wm_action_close
;
261 supported
[i
++] = prop_atoms
.net_wm_state
;
262 supported
[i
++] = prop_atoms
.net_wm_state_modal
;
263 supported
[i
++] = prop_atoms
.net_wm_state_maximized_vert
;
264 supported
[i
++] = prop_atoms
.net_wm_state_maximized_horz
;
265 supported
[i
++] = prop_atoms
.net_wm_state_shaded
;
266 supported
[i
++] = prop_atoms
.net_wm_state_skip_taskbar
;
267 supported
[i
++] = prop_atoms
.net_wm_state_skip_pager
;
268 supported
[i
++] = prop_atoms
.net_wm_state_hidden
;
269 supported
[i
++] = prop_atoms
.net_wm_state_fullscreen
;
270 supported
[i
++] = prop_atoms
.net_wm_state_above
;
271 supported
[i
++] = prop_atoms
.net_wm_state_below
;
272 supported
[i
++] = prop_atoms
.net_wm_state_demands_attention
;
273 supported
[i
++] = prop_atoms
.net_moveresize_window
;
274 supported
[i
++] = prop_atoms
.net_wm_moveresize
;
275 supported
[i
++] = prop_atoms
.net_wm_user_time
;
276 supported
[i
++] = prop_atoms
.net_frame_extents
;
277 supported
[i
++] = prop_atoms
.net_startup_id
;
279 supported
[i
++] = prop_atoms
.net_wm_sync_request
;
280 supported
[i
++] = prop_atoms
.net_wm_sync_request_counter
;
283 supported
[i
++] = prop_atoms
.kde_wm_change_state
;
284 supported
[i
++] = prop_atoms
.kde_net_wm_frame_strut
;
285 supported
[i
++] = prop_atoms
.kde_net_wm_window_type_override
;
287 supported
[i
++] = prop_atoms
.openbox_wm_state_undecorated
;
288 supported
[i
++] = prop_atoms
.openbox_pid
;
289 supported
[i
++] = prop_atoms
.openbox_config
;
290 supported
[i
++] = prop_atoms
.openbox_control
;
291 g_assert(i
== num_support
);
293 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
294 net_supported
, atom
, supported
, num_support
);
300 void screen_startup(gboolean reconfig
)
307 desktop_cycle_popup
= pager_popup_new(FALSE
);
308 pager_popup_height(desktop_cycle_popup
, POPUP_HEIGHT
);
313 /* get the initial size */
316 /* get the desktop names */
317 numnames
= g_slist_length(config_desktops_names
);
318 names
= g_new(gchar
*, numnames
+ 1);
319 names
[numnames
] = NULL
;
320 for (i
= 0, it
= config_desktops_names
; it
; ++i
, it
= g_slist_next(it
))
321 names
[i
] = g_strdup(it
->data
);
323 /* set the root window property */
324 PROP_SETSS(RootWindow(ob_display
, ob_screen
), net_desktop_names
,names
);
328 /* set the number of desktops */
329 screen_num_desktops
= 0;
330 screen_set_num_desktops(config_desktops_num
);
332 /* start on the current desktop when a wm was already running */
333 if (PROP_GET32(RootWindow(ob_display
, ob_screen
),
334 net_current_desktop
, cardinal
, &d
) &&
335 d
< screen_num_desktops
)
337 screen_set_desktop(d
, FALSE
);
338 } else if (session_desktop
>= 0)
339 screen_set_desktop(MIN((guint
)session_desktop
,
340 screen_num_desktops
), FALSE
);
342 screen_set_desktop(MIN(config_screen_firstdesk
,
343 screen_num_desktops
) - 1, FALSE
);
345 /* don't start in showing-desktop mode */
346 screen_showing_desktop
= FALSE
;
347 PROP_SET32(RootWindow(ob_display
, ob_screen
),
348 net_showing_desktop
, cardinal
, screen_showing_desktop
);
350 screen_update_layout();
353 void screen_shutdown(gboolean reconfig
)
357 pager_popup_free(desktop_cycle_popup
);
362 XSelectInput(ob_display
, RootWindow(ob_display
, ob_screen
),
365 /* we're not running here no more! */
366 PROP_ERASE(RootWindow(ob_display
, ob_screen
), openbox_pid
);
368 PROP_ERASE(RootWindow(ob_display
, ob_screen
), net_supported
);
369 /* don't keep this mode */
370 PROP_ERASE(RootWindow(ob_display
, ob_screen
), net_showing_desktop
);
372 XDestroyWindow(ob_display
, screen_support_win
);
374 g_strfreev(screen_desktop_names
);
375 screen_desktop_names
= NULL
;
377 for (r
= area
; *r
; ++r
)
385 static gint oldw
= 0, oldh
= 0;
390 w
= WidthOfScreen(ScreenOfDisplay(ob_display
, ob_screen
));
391 h
= HeightOfScreen(ScreenOfDisplay(ob_display
, ob_screen
));
393 if (w
== oldw
&& h
== oldh
) return;
397 /* Set the _NET_DESKTOP_GEOMETRY hint */
398 screen_physical_size
.width
= geometry
[0] = w
;
399 screen_physical_size
.height
= geometry
[1] = h
;
400 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
401 net_desktop_geometry
, cardinal
, geometry
, 2);
403 if (ob_state() == OB_STATE_STARTING
)
406 screen_update_areas();
409 for (it
= client_list
; it
; it
= g_list_next(it
))
410 client_move_onscreen(it
->data
, FALSE
);
413 void screen_set_num_desktops(guint num
)
421 if (screen_num_desktops
== num
) return;
423 old
= screen_num_desktops
;
424 screen_num_desktops
= num
;
425 PROP_SET32(RootWindow(ob_display
, ob_screen
),
426 net_number_of_desktops
, cardinal
, num
);
428 /* set the viewport hint */
429 viewport
= g_new0(gulong
, num
* 2);
430 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
431 net_desktop_viewport
, cardinal
, viewport
, num
* 2);
434 /* the number of rows/columns will differ */
435 screen_update_layout();
437 /* move windows on desktops that will no longer exist! */
438 for (it
= client_list
; it
; it
= g_list_next(it
)) {
439 ObClient
*c
= it
->data
;
440 if (c
->desktop
>= num
&& c
->desktop
!= DESKTOP_ALL
)
441 client_set_desktop(c
, num
- 1, FALSE
);
444 /* change our struts/area to match (after moving windows) */
445 screen_update_areas();
447 /* may be some unnamed desktops that we need to fill in with names
448 (after updating the areas so the popup can resize) */
449 screen_update_desktop_names();
451 /* change our desktop if we're on one that no longer exists! */
452 if (screen_desktop
>= screen_num_desktops
)
453 screen_set_desktop(num
- 1, TRUE
);
456 void screen_set_desktop(guint num
, gboolean dofocus
)
462 g_assert(num
< screen_num_desktops
);
464 old
= screen_desktop
;
465 screen_desktop
= num
;
466 PROP_SET32(RootWindow(ob_display
, ob_screen
),
467 net_current_desktop
, cardinal
, num
);
469 if (old
== num
) return;
471 screen_last_desktop
= old
;
473 ob_debug("Moving to desktop %d\n", num
+1);
475 if (moveresize_client
)
476 client_set_desktop(moveresize_client
, num
, TRUE
);
478 /* show windows before hiding the rest to lessen the enter/leave events */
480 /* show windows from top to bottom */
481 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
482 if (WINDOW_IS_CLIENT(it
->data
)) {
483 ObClient
*c
= it
->data
;
488 /* have to try focus here because when you leave an empty desktop
489 there is no focus out to watch for
491 do this before hiding the windows so if helper windows are coming
492 with us, they don't get hidden
494 if (dofocus
&& (c
= focus_fallback_target(TRUE
, focus_client
))) {
495 /* only do the flicker reducing stuff ahead of time if we are going
496 to call xsetinputfocus on the window ourselves. otherwise there is
497 no guarantee the window will actually take focus.. */
499 /* do this here so that if you switch desktops to a window with
500 helper windows then the helper windows won't flash */
501 client_bring_helper_windows(c
);
502 /* reduce flicker by hiliting now rather than waiting for the
503 server FocusIn event */
504 frame_adjust_focus(c
->frame
, TRUE
);
509 /* hide windows from bottom to top */
510 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
511 if (WINDOW_IS_CLIENT(it
->data
)) {
512 ObClient
*c
= it
->data
;
517 event_ignore_queued_enters();
519 if (event_curtime
!= CurrentTime
)
520 screen_desktop_user_time
= event_curtime
;
523 static void get_row_col(guint d
, guint
*r
, guint
*c
)
525 switch (screen_desktop_layout
.orientation
) {
526 case OB_ORIENTATION_HORZ
:
527 switch (screen_desktop_layout
.start_corner
) {
528 case OB_CORNER_TOPLEFT
:
529 *r
= d
/ screen_desktop_layout
.columns
;
530 *c
= d
% screen_desktop_layout
.columns
;
532 case OB_CORNER_BOTTOMLEFT
:
533 *r
= screen_desktop_layout
.rows
- 1 -
534 d
/ screen_desktop_layout
.columns
;
535 *c
= d
% screen_desktop_layout
.columns
;
537 case OB_CORNER_TOPRIGHT
:
538 *r
= d
/ screen_desktop_layout
.columns
;
539 *c
= screen_desktop_layout
.columns
- 1 -
540 d
% screen_desktop_layout
.columns
;
542 case OB_CORNER_BOTTOMRIGHT
:
543 *r
= screen_desktop_layout
.rows
- 1 -
544 d
/ screen_desktop_layout
.columns
;
545 *c
= screen_desktop_layout
.columns
- 1 -
546 d
% screen_desktop_layout
.columns
;
550 case OB_ORIENTATION_VERT
:
551 switch (screen_desktop_layout
.start_corner
) {
552 case OB_CORNER_TOPLEFT
:
553 *r
= d
% screen_desktop_layout
.rows
;
554 *c
= d
/ screen_desktop_layout
.rows
;
556 case OB_CORNER_BOTTOMLEFT
:
557 *r
= screen_desktop_layout
.rows
- 1 -
558 d
% screen_desktop_layout
.rows
;
559 *c
= d
/ screen_desktop_layout
.rows
;
561 case OB_CORNER_TOPRIGHT
:
562 *r
= d
% screen_desktop_layout
.rows
;
563 *c
= screen_desktop_layout
.columns
- 1 -
564 d
/ screen_desktop_layout
.rows
;
566 case OB_CORNER_BOTTOMRIGHT
:
567 *r
= screen_desktop_layout
.rows
- 1 -
568 d
% screen_desktop_layout
.rows
;
569 *c
= screen_desktop_layout
.columns
- 1 -
570 d
/ screen_desktop_layout
.rows
;
577 static guint
translate_row_col(guint r
, guint c
)
579 switch (screen_desktop_layout
.orientation
) {
580 case OB_ORIENTATION_HORZ
:
581 switch (screen_desktop_layout
.start_corner
) {
582 case OB_CORNER_TOPLEFT
:
583 return r
% screen_desktop_layout
.rows
*
584 screen_desktop_layout
.columns
+
585 c
% screen_desktop_layout
.columns
;
586 case OB_CORNER_BOTTOMLEFT
:
587 return (screen_desktop_layout
.rows
- 1 -
588 r
% screen_desktop_layout
.rows
) *
589 screen_desktop_layout
.columns
+
590 c
% screen_desktop_layout
.columns
;
591 case OB_CORNER_TOPRIGHT
:
592 return r
% screen_desktop_layout
.rows
*
593 screen_desktop_layout
.columns
+
594 (screen_desktop_layout
.columns
- 1 -
595 c
% screen_desktop_layout
.columns
);
596 case OB_CORNER_BOTTOMRIGHT
:
597 return (screen_desktop_layout
.rows
- 1 -
598 r
% screen_desktop_layout
.rows
) *
599 screen_desktop_layout
.columns
+
600 (screen_desktop_layout
.columns
- 1 -
601 c
% screen_desktop_layout
.columns
);
603 case OB_ORIENTATION_VERT
:
604 switch (screen_desktop_layout
.start_corner
) {
605 case OB_CORNER_TOPLEFT
:
606 return c
% screen_desktop_layout
.columns
*
607 screen_desktop_layout
.rows
+
608 r
% screen_desktop_layout
.rows
;
609 case OB_CORNER_BOTTOMLEFT
:
610 return c
% screen_desktop_layout
.columns
*
611 screen_desktop_layout
.rows
+
612 (screen_desktop_layout
.rows
- 1 -
613 r
% screen_desktop_layout
.rows
);
614 case OB_CORNER_TOPRIGHT
:
615 return (screen_desktop_layout
.columns
- 1 -
616 c
% screen_desktop_layout
.columns
) *
617 screen_desktop_layout
.rows
+
618 r
% screen_desktop_layout
.rows
;
619 case OB_CORNER_BOTTOMRIGHT
:
620 return (screen_desktop_layout
.columns
- 1 -
621 c
% screen_desktop_layout
.columns
) *
622 screen_desktop_layout
.rows
+
623 (screen_desktop_layout
.rows
- 1 -
624 r
% screen_desktop_layout
.rows
);
627 g_assert_not_reached();
631 void screen_desktop_popup(guint d
, gboolean show
)
636 pager_popup_hide(desktop_cycle_popup
);
638 a
= screen_physical_area_monitor(0);
639 pager_popup_position(desktop_cycle_popup
, CenterGravity
,
640 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
641 pager_popup_max_width(desktop_cycle_popup
,
642 MAX(a
->width
/3, POPUP_WIDTH
));
643 pager_popup_show(desktop_cycle_popup
, screen_desktop_names
[d
], d
);
647 guint
screen_cycle_desktop(ObDirection dir
, gboolean wrap
, gboolean linear
,
648 gboolean dialog
, gboolean done
, gboolean cancel
)
654 if ((cancel
|| done
) && dialog
)
655 goto show_cycle_dialog
;
657 get_row_col(d
, &r
, &c
);
661 case OB_DIRECTION_EAST
:
662 if (d
< screen_num_desktops
- 1)
667 case OB_DIRECTION_WEST
:
671 d
= screen_num_desktops
- 1;
675 return screen_desktop
;
679 case OB_DIRECTION_EAST
:
681 if (c
>= screen_desktop_layout
.columns
) {
686 goto show_cycle_dialog
;
689 d
= translate_row_col(r
, c
);
690 if (d
>= screen_num_desktops
) {
695 goto show_cycle_dialog
;
699 case OB_DIRECTION_WEST
:
701 if (c
>= screen_desktop_layout
.columns
) {
703 c
= screen_desktop_layout
.columns
- 1;
706 goto show_cycle_dialog
;
709 d
= translate_row_col(r
, c
);
710 if (d
>= screen_num_desktops
) {
715 goto show_cycle_dialog
;
719 case OB_DIRECTION_SOUTH
:
721 if (r
>= screen_desktop_layout
.rows
) {
726 goto show_cycle_dialog
;
729 d
= translate_row_col(r
, c
);
730 if (d
>= screen_num_desktops
) {
735 goto show_cycle_dialog
;
739 case OB_DIRECTION_NORTH
:
741 if (r
>= screen_desktop_layout
.rows
) {
743 r
= screen_desktop_layout
.rows
- 1;
746 goto show_cycle_dialog
;
749 d
= translate_row_col(r
, c
);
750 if (d
>= screen_num_desktops
) {
755 goto show_cycle_dialog
;
761 return d
= screen_desktop
;
764 d
= translate_row_col(r
, c
);
768 if (dialog
&& !cancel
&& !done
) {
769 screen_desktop_popup(d
, TRUE
);
771 screen_desktop_popup(0, FALSE
);
775 void screen_update_layout()
777 ObOrientation orient
;
783 gboolean valid
= FALSE
;
785 if (PROP_GETA32(RootWindow(ob_display
, ob_screen
),
786 net_desktop_layout
, cardinal
, &data
, &num
)) {
787 if (num
== 3 || num
== 4) {
789 if (data
[0] == prop_atoms
.net_wm_orientation_vert
)
790 orient
= OB_ORIENTATION_VERT
;
791 else if (data
[0] == prop_atoms
.net_wm_orientation_horz
)
792 orient
= OB_ORIENTATION_HORZ
;
794 goto screen_update_layout_bail
;
797 corner
= OB_CORNER_TOPLEFT
;
799 if (data
[3] == prop_atoms
.net_wm_topleft
)
800 corner
= OB_CORNER_TOPLEFT
;
801 else if (data
[3] == prop_atoms
.net_wm_topright
)
802 corner
= OB_CORNER_TOPRIGHT
;
803 else if (data
[3] == prop_atoms
.net_wm_bottomright
)
804 corner
= OB_CORNER_BOTTOMRIGHT
;
805 else if (data
[3] == prop_atoms
.net_wm_bottomleft
)
806 corner
= OB_CORNER_BOTTOMLEFT
;
808 goto screen_update_layout_bail
;
814 /* fill in a zero rows/columns */
815 if ((cols
== 0 && rows
== 0)) { /* both 0's is bad data.. */
816 goto screen_update_layout_bail
;
819 cols
= screen_num_desktops
/ rows
;
820 if (rows
* cols
< screen_num_desktops
)
822 if (rows
* cols
>= screen_num_desktops
+ cols
)
824 } else if (rows
== 0) {
825 rows
= screen_num_desktops
/ cols
;
826 if (cols
* rows
< screen_num_desktops
)
828 if (cols
* rows
>= screen_num_desktops
+ rows
)
833 /* bounds checking */
834 if (orient
== OB_ORIENTATION_HORZ
) {
835 cols
= MIN(screen_num_desktops
, cols
);
836 rows
= MIN(rows
, (screen_num_desktops
+ cols
- 1) / cols
);
837 cols
= screen_num_desktops
/ rows
+
838 !!(screen_num_desktops
% rows
);
840 rows
= MIN(screen_num_desktops
, rows
);
841 cols
= MIN(cols
, (screen_num_desktops
+ rows
- 1) / rows
);
842 rows
= screen_num_desktops
/ cols
+
843 !!(screen_num_desktops
% cols
);
848 screen_update_layout_bail
:
854 orient
= OB_ORIENTATION_HORZ
;
855 corner
= OB_CORNER_TOPLEFT
;
857 cols
= screen_num_desktops
;
860 screen_desktop_layout
.orientation
= orient
;
861 screen_desktop_layout
.start_corner
= corner
;
862 screen_desktop_layout
.rows
= rows
;
863 screen_desktop_layout
.columns
= cols
;
866 void screen_update_desktop_names()
870 /* empty the array */
871 g_strfreev(screen_desktop_names
);
872 screen_desktop_names
= NULL
;
874 if (PROP_GETSS(RootWindow(ob_display
, ob_screen
),
875 net_desktop_names
, utf8
, &screen_desktop_names
))
876 for (i
= 0; screen_desktop_names
[i
] && i
< screen_num_desktops
; ++i
);
879 if (i
< screen_num_desktops
) {
880 screen_desktop_names
= g_renew(gchar
*, screen_desktop_names
,
881 screen_num_desktops
+ 1);
882 screen_desktop_names
[screen_num_desktops
] = NULL
;
883 for (; i
< screen_num_desktops
; ++i
)
884 screen_desktop_names
[i
] = g_strdup_printf("desktop %i", i
+ 1);
887 /* resize the pager for these names */
888 pager_popup_text_width_to_strings(desktop_cycle_popup
,
889 screen_desktop_names
,
890 screen_num_desktops
);
893 void screen_show_desktop(gboolean show
, gboolean restore_focus
)
897 if (show
== screen_showing_desktop
) return; /* no change */
899 screen_showing_desktop
= show
;
903 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
904 if (WINDOW_IS_CLIENT(it
->data
)) {
905 ObClient
*client
= it
->data
;
906 client_showhide(client
);
911 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
912 if (WINDOW_IS_CLIENT(it
->data
)) {
913 ObClient
*client
= it
->data
;
914 client_showhide(client
);
921 for (it
= focus_order
; it
; it
= g_list_next(it
)) {
922 ObClient
*c
= it
->data
;
923 if (c
->type
== OB_CLIENT_TYPE_DESKTOP
&&
924 (c
->desktop
== screen_desktop
|| c
->desktop
== DESKTOP_ALL
) &&
925 client_focus(it
->data
))
928 } else if (restore_focus
) {
931 /* use NULL for the "old" argument because the desktop was focused
932 and we don't want to fallback to the desktop by default */
933 if ((c
= focus_fallback_target(TRUE
, NULL
)))
937 show
= !!show
; /* make it boolean */
938 PROP_SET32(RootWindow(ob_display
, ob_screen
),
939 net_showing_desktop
, cardinal
, show
);
942 void screen_install_colormap(ObClient
*client
, gboolean install
)
944 if (client
== NULL
) {
946 XInstallColormap(RrDisplay(ob_rr_inst
), RrColormap(ob_rr_inst
));
948 XUninstallColormap(RrDisplay(ob_rr_inst
), RrColormap(ob_rr_inst
));
950 xerror_set_ignore(TRUE
);
952 if (client
->colormap
!= None
)
953 XInstallColormap(RrDisplay(ob_rr_inst
), client
->colormap
);
955 XUninstallColormap(RrDisplay(ob_rr_inst
), client
->colormap
);
956 xerror_set_ignore(FALSE
);
961 screen_area_add_strut_left(const StrutPartial
*s
, const Rect
*monitor_area
,
962 gint edge
, Strut
*ret
)
965 ((s
->left_end
<= s
->left_start
) ||
966 (RECT_TOP(*monitor_area
) < s
->left_end
&&
967 RECT_BOTTOM(*monitor_area
) > s
->left_start
)))
968 ret
->left
= MAX(ret
->left
, edge
);
972 screen_area_add_strut_top(const StrutPartial
*s
, const Rect
*monitor_area
,
973 gint edge
, Strut
*ret
)
976 ((s
->top_end
<= s
->top_start
) ||
977 (RECT_LEFT(*monitor_area
) < s
->top_end
&&
978 RECT_RIGHT(*monitor_area
) > s
->top_start
)))
979 ret
->top
= MAX(ret
->top
, edge
);
983 screen_area_add_strut_right(const StrutPartial
*s
, const Rect
*monitor_area
,
984 gint edge
, Strut
*ret
)
987 ((s
->right_end
<= s
->right_start
) ||
988 (RECT_TOP(*monitor_area
) < s
->right_end
&&
989 RECT_BOTTOM(*monitor_area
) > s
->right_start
)))
990 ret
->right
= MAX(ret
->right
, edge
);
994 screen_area_add_strut_bottom(const StrutPartial
*s
, const Rect
*monitor_area
,
995 gint edge
, Strut
*ret
)
998 ((s
->bottom_end
<= s
->bottom_start
) ||
999 (RECT_LEFT(*monitor_area
) < s
->bottom_end
&&
1000 RECT_RIGHT(*monitor_area
) > s
->bottom_start
)))
1001 ret
->bottom
= MAX(ret
->bottom
, edge
);
1004 void screen_update_areas()
1011 g_free(monitor_area
);
1012 extensions_xinerama_screens(&monitor_area
, &screen_num_monitors
);
1015 for (i
= 0; area
[i
]; ++i
)
1020 area
= g_new(Rect
*, screen_num_desktops
+ 2);
1021 for (i
= 0; i
< screen_num_desktops
+ 1; ++i
)
1022 area
[i
] = g_new0(Rect
, screen_num_monitors
+ 1);
1025 dims
= g_new(gulong
, 4 * screen_num_desktops
);
1027 for (i
= 0; i
< screen_num_desktops
+ 1; ++i
) {
1031 struts
= g_new0(Strut
, screen_num_monitors
);
1033 /* calc the xinerama areas */
1034 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1035 area
[i
][x
] = monitor_area
[x
];
1037 l
= monitor_area
[x
].x
;
1038 t
= monitor_area
[x
].y
;
1039 r
= monitor_area
[x
].x
+ monitor_area
[x
].width
- 1;
1040 b
= monitor_area
[x
].y
+ monitor_area
[x
].height
- 1;
1042 l
= MIN(l
, monitor_area
[x
].x
);
1043 t
= MIN(t
, monitor_area
[x
].y
);
1044 r
= MAX(r
, monitor_area
[x
].x
+ monitor_area
[x
].width
- 1);
1045 b
= MAX(b
, monitor_area
[x
].y
+ monitor_area
[x
].height
- 1);
1048 RECT_SET(area
[i
][x
], l
, t
, r
- l
+ 1, b
- t
+ 1);
1050 /* apply the struts */
1052 /* find the left-most xin heads, i do this in 2 loops :| */
1054 for (x
= 1; x
< screen_num_monitors
; ++x
)
1055 o
= MIN(o
, area
[i
][x
].x
);
1057 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1058 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1059 ObClient
*c
= it
->data
;
1060 screen_area_add_strut_left(&c
->strut
,
1062 o
+ c
->strut
.left
- area
[i
][x
].x
,
1065 screen_area_add_strut_left(&dock_strut
,
1067 o
+ dock_strut
.left
- area
[i
][x
].x
,
1070 area
[i
][x
].x
+= struts
[x
].left
;
1071 area
[i
][x
].width
-= struts
[x
].left
;
1074 /* find the top-most xin heads, i do this in 2 loops :| */
1076 for (x
= 1; x
< screen_num_monitors
; ++x
)
1077 o
= MIN(o
, area
[i
][x
].y
);
1079 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1080 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1081 ObClient
*c
= it
->data
;
1082 screen_area_add_strut_top(&c
->strut
,
1084 o
+ c
->strut
.top
- area
[i
][x
].y
,
1087 screen_area_add_strut_top(&dock_strut
,
1089 o
+ dock_strut
.top
- area
[i
][x
].y
,
1092 area
[i
][x
].y
+= struts
[x
].top
;
1093 area
[i
][x
].height
-= struts
[x
].top
;
1096 /* find the right-most xin heads, i do this in 2 loops :| */
1097 o
= area
[i
][0].x
+ area
[i
][0].width
- 1;
1098 for (x
= 1; x
< screen_num_monitors
; ++x
)
1099 o
= MAX(o
, area
[i
][x
].x
+ area
[i
][x
].width
- 1);
1101 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1102 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1103 ObClient
*c
= it
->data
;
1104 screen_area_add_strut_right(&c
->strut
,
1107 area
[i
][x
].width
- 1) -
1108 (o
- c
->strut
.right
),
1111 screen_area_add_strut_right(&dock_strut
,
1114 area
[i
][x
].width
- 1) -
1115 (o
- dock_strut
.right
),
1118 area
[i
][x
].width
-= struts
[x
].right
;
1121 /* find the bottom-most xin heads, i do this in 2 loops :| */
1122 o
= area
[i
][0].y
+ area
[i
][0].height
- 1;
1123 for (x
= 1; x
< screen_num_monitors
; ++x
)
1124 o
= MAX(o
, area
[i
][x
].y
+ area
[i
][x
].height
- 1);
1126 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1127 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1128 ObClient
*c
= it
->data
;
1129 screen_area_add_strut_bottom(&c
->strut
,
1132 area
[i
][x
].height
- 1) - \
1133 (o
- c
->strut
.bottom
),
1136 screen_area_add_strut_bottom(&dock_strut
,
1139 area
[i
][x
].height
- 1) - \
1140 (o
- dock_strut
.bottom
),
1143 area
[i
][x
].height
-= struts
[x
].bottom
;
1146 l
= RECT_LEFT(area
[i
][0]);
1147 t
= RECT_TOP(area
[i
][0]);
1148 r
= RECT_RIGHT(area
[i
][0]);
1149 b
= RECT_BOTTOM(area
[i
][0]);
1150 for (x
= 1; x
< screen_num_monitors
; ++x
) {
1151 l
= MIN(l
, RECT_LEFT(area
[i
][x
]));
1152 t
= MIN(l
, RECT_TOP(area
[i
][x
]));
1153 r
= MAX(r
, RECT_RIGHT(area
[i
][x
]));
1154 b
= MAX(b
, RECT_BOTTOM(area
[i
][x
]));
1156 RECT_SET(area
[i
][screen_num_monitors
], l
, t
,
1157 r
- l
+ 1, b
- t
+ 1);
1159 /* XXX optimize when this is run? */
1161 /* the area has changed, adjust all the maximized
1163 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1164 ObClient
*c
= it
->data
;
1165 if (i
< screen_num_desktops
) {
1166 if (c
->desktop
== i
)
1167 client_reconfigure(c
);
1168 } else if (c
->desktop
== DESKTOP_ALL
)
1169 client_reconfigure(c
);
1171 if (i
< screen_num_desktops
) {
1172 /* don't set these for the 'all desktops' area */
1173 dims
[(i
* 4) + 0] = area
[i
][screen_num_monitors
].x
;
1174 dims
[(i
* 4) + 1] = area
[i
][screen_num_monitors
].y
;
1175 dims
[(i
* 4) + 2] = area
[i
][screen_num_monitors
].width
;
1176 dims
[(i
* 4) + 3] = area
[i
][screen_num_monitors
].height
;
1182 PROP_SETA32(RootWindow(ob_display
, ob_screen
), net_workarea
, cardinal
,
1183 dims
, 4 * screen_num_desktops
);
1188 Rect
*screen_area(guint desktop
)
1190 return screen_area_monitor(desktop
, screen_num_monitors
);
1193 Rect
*screen_area_monitor(guint desktop
, guint head
)
1195 if (head
> screen_num_monitors
)
1197 if (desktop
>= screen_num_desktops
) {
1198 if (desktop
== DESKTOP_ALL
)
1199 return &area
[screen_num_desktops
][head
];
1202 return &area
[desktop
][head
];
1205 guint
screen_find_monitor(Rect
*search
)
1211 for (i
= 0; i
< screen_num_monitors
; ++i
) {
1212 Rect
*area
= screen_physical_area_monitor(i
);
1213 if (RECT_INTERSECTS_RECT(*area
, *search
)) {
1217 RECT_SET_INTERSECTION(r
, *area
, *search
);
1218 v
= r
.width
* r
.height
;
1229 Rect
*screen_physical_area()
1231 return screen_physical_area_monitor(screen_num_monitors
);
1234 Rect
*screen_physical_area_monitor(guint head
)
1236 if (head
> screen_num_monitors
)
1238 return &monitor_area
[head
];
1241 void screen_set_root_cursor()
1243 if (sn_app_starting())
1244 XDefineCursor(ob_display
, RootWindow(ob_display
, ob_screen
),
1245 ob_cursor(OB_CURSOR_BUSY
));
1247 XDefineCursor(ob_display
, RootWindow(ob_display
, ob_screen
),
1248 ob_cursor(OB_CURSOR_POINTER
));
1251 gboolean
screen_pointer_pos(gint
*x
, gint
*y
)
1258 ret
= !!XQueryPointer(ob_display
, RootWindow(ob_display
, ob_screen
),
1259 &w
, &w
, x
, y
, &i
, &i
, &u
);
1261 for (i
= 0; i
< ScreenCount(ob_display
); ++i
)
1263 if (XQueryPointer(ob_display
, RootWindow(ob_display
, i
),
1264 &w
, &w
, x
, y
, &i
, &i
, &u
))