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_wm_user_time_window
;
277 supported
[i
++] = prop_atoms
.net_frame_extents
;
278 supported
[i
++] = prop_atoms
.net_request_frame_extents
;
279 supported
[i
++] = prop_atoms
.net_startup_id
;
281 supported
[i
++] = prop_atoms
.net_wm_sync_request
;
282 supported
[i
++] = prop_atoms
.net_wm_sync_request_counter
;
285 supported
[i
++] = prop_atoms
.kde_wm_change_state
;
286 supported
[i
++] = prop_atoms
.kde_net_wm_frame_strut
;
287 supported
[i
++] = prop_atoms
.kde_net_wm_window_type_override
;
289 supported
[i
++] = prop_atoms
.openbox_wm_state_undecorated
;
290 supported
[i
++] = prop_atoms
.openbox_pid
;
291 supported
[i
++] = prop_atoms
.openbox_config
;
292 supported
[i
++] = prop_atoms
.openbox_control
;
293 g_assert(i
== num_support
);
295 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
296 net_supported
, atom
, supported
, num_support
);
302 void screen_startup(gboolean reconfig
)
309 desktop_cycle_popup
= pager_popup_new(FALSE
);
310 pager_popup_height(desktop_cycle_popup
, POPUP_HEIGHT
);
315 /* get the initial size */
318 /* get the desktop names */
319 numnames
= g_slist_length(config_desktops_names
);
320 names
= g_new(gchar
*, numnames
+ 1);
321 names
[numnames
] = NULL
;
322 for (i
= 0, it
= config_desktops_names
; it
; ++i
, it
= g_slist_next(it
))
323 names
[i
] = g_strdup(it
->data
);
325 /* set the root window property */
326 PROP_SETSS(RootWindow(ob_display
, ob_screen
), net_desktop_names
,names
);
330 /* set the number of desktops */
331 screen_num_desktops
= 0;
332 screen_set_num_desktops(config_desktops_num
);
334 /* start on the current desktop when a wm was already running */
335 if (PROP_GET32(RootWindow(ob_display
, ob_screen
),
336 net_current_desktop
, cardinal
, &d
) &&
337 d
< screen_num_desktops
)
339 screen_set_desktop(d
, FALSE
);
340 } else if (session_desktop
>= 0)
341 screen_set_desktop(MIN((guint
)session_desktop
,
342 screen_num_desktops
), FALSE
);
344 screen_set_desktop(MIN(config_screen_firstdesk
,
345 screen_num_desktops
) - 1, FALSE
);
347 /* don't start in showing-desktop mode */
348 screen_showing_desktop
= FALSE
;
349 PROP_SET32(RootWindow(ob_display
, ob_screen
),
350 net_showing_desktop
, cardinal
, screen_showing_desktop
);
352 screen_update_layout();
355 void screen_shutdown(gboolean reconfig
)
359 pager_popup_free(desktop_cycle_popup
);
364 XSelectInput(ob_display
, RootWindow(ob_display
, ob_screen
),
367 /* we're not running here no more! */
368 PROP_ERASE(RootWindow(ob_display
, ob_screen
), openbox_pid
);
370 PROP_ERASE(RootWindow(ob_display
, ob_screen
), net_supported
);
371 /* don't keep this mode */
372 PROP_ERASE(RootWindow(ob_display
, ob_screen
), net_showing_desktop
);
374 XDestroyWindow(ob_display
, screen_support_win
);
376 g_strfreev(screen_desktop_names
);
377 screen_desktop_names
= NULL
;
379 for (r
= area
; *r
; ++r
)
387 static gint oldw
= 0, oldh
= 0;
392 w
= WidthOfScreen(ScreenOfDisplay(ob_display
, ob_screen
));
393 h
= HeightOfScreen(ScreenOfDisplay(ob_display
, ob_screen
));
395 if (w
== oldw
&& h
== oldh
) return;
399 /* Set the _NET_DESKTOP_GEOMETRY hint */
400 screen_physical_size
.width
= geometry
[0] = w
;
401 screen_physical_size
.height
= geometry
[1] = h
;
402 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
403 net_desktop_geometry
, cardinal
, geometry
, 2);
405 if (ob_state() == OB_STATE_STARTING
)
408 screen_update_areas();
411 for (it
= client_list
; it
; it
= g_list_next(it
))
412 client_move_onscreen(it
->data
, FALSE
);
415 void screen_set_num_desktops(guint num
)
423 if (screen_num_desktops
== num
) return;
425 old
= screen_num_desktops
;
426 screen_num_desktops
= num
;
427 PROP_SET32(RootWindow(ob_display
, ob_screen
),
428 net_number_of_desktops
, cardinal
, num
);
430 /* set the viewport hint */
431 viewport
= g_new0(gulong
, num
* 2);
432 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
433 net_desktop_viewport
, cardinal
, viewport
, num
* 2);
436 /* the number of rows/columns will differ */
437 screen_update_layout();
439 /* move windows on desktops that will no longer exist! */
440 for (it
= client_list
; it
; it
= g_list_next(it
)) {
441 ObClient
*c
= it
->data
;
442 if (c
->desktop
>= num
&& c
->desktop
!= DESKTOP_ALL
)
443 client_set_desktop(c
, num
- 1, FALSE
);
446 /* change our struts/area to match (after moving windows) */
447 screen_update_areas();
449 /* may be some unnamed desktops that we need to fill in with names
450 (after updating the areas so the popup can resize) */
451 screen_update_desktop_names();
453 /* change our desktop if we're on one that no longer exists! */
454 if (screen_desktop
>= screen_num_desktops
)
455 screen_set_desktop(num
- 1, TRUE
);
458 void screen_set_desktop(guint num
, gboolean dofocus
)
464 g_assert(num
< screen_num_desktops
);
466 old
= screen_desktop
;
467 screen_desktop
= num
;
468 PROP_SET32(RootWindow(ob_display
, ob_screen
),
469 net_current_desktop
, cardinal
, num
);
471 if (old
== num
) return;
473 screen_last_desktop
= old
;
475 ob_debug("Moving to desktop %d\n", num
+1);
477 if (moveresize_client
)
478 client_set_desktop(moveresize_client
, num
, TRUE
);
480 /* show windows before hiding the rest to lessen the enter/leave events */
482 /* show windows from top to bottom */
483 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
484 if (WINDOW_IS_CLIENT(it
->data
)) {
485 ObClient
*c
= it
->data
;
490 /* have to try focus here because when you leave an empty desktop
491 there is no focus out to watch for
493 do this before hiding the windows so if helper windows are coming
494 with us, they don't get hidden
496 if (dofocus
&& (c
= focus_fallback_target(TRUE
, focus_client
))) {
497 /* only do the flicker reducing stuff ahead of time if we are going
498 to call xsetinputfocus on the window ourselves. otherwise there is
499 no guarantee the window will actually take focus.. */
501 /* do this here so that if you switch desktops to a window with
502 helper windows then the helper windows won't flash */
503 client_bring_helper_windows(c
);
504 /* reduce flicker by hiliting now rather than waiting for the
505 server FocusIn event */
506 frame_adjust_focus(c
->frame
, TRUE
);
511 /* hide windows from bottom to top */
512 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
513 if (WINDOW_IS_CLIENT(it
->data
)) {
514 ObClient
*c
= it
->data
;
519 event_ignore_queued_enters();
521 if (event_curtime
!= CurrentTime
)
522 screen_desktop_user_time
= event_curtime
;
525 static void get_row_col(guint d
, guint
*r
, guint
*c
)
527 switch (screen_desktop_layout
.orientation
) {
528 case OB_ORIENTATION_HORZ
:
529 switch (screen_desktop_layout
.start_corner
) {
530 case OB_CORNER_TOPLEFT
:
531 *r
= d
/ screen_desktop_layout
.columns
;
532 *c
= d
% screen_desktop_layout
.columns
;
534 case OB_CORNER_BOTTOMLEFT
:
535 *r
= screen_desktop_layout
.rows
- 1 -
536 d
/ screen_desktop_layout
.columns
;
537 *c
= d
% screen_desktop_layout
.columns
;
539 case OB_CORNER_TOPRIGHT
:
540 *r
= d
/ screen_desktop_layout
.columns
;
541 *c
= screen_desktop_layout
.columns
- 1 -
542 d
% screen_desktop_layout
.columns
;
544 case OB_CORNER_BOTTOMRIGHT
:
545 *r
= screen_desktop_layout
.rows
- 1 -
546 d
/ screen_desktop_layout
.columns
;
547 *c
= screen_desktop_layout
.columns
- 1 -
548 d
% screen_desktop_layout
.columns
;
552 case OB_ORIENTATION_VERT
:
553 switch (screen_desktop_layout
.start_corner
) {
554 case OB_CORNER_TOPLEFT
:
555 *r
= d
% screen_desktop_layout
.rows
;
556 *c
= d
/ screen_desktop_layout
.rows
;
558 case OB_CORNER_BOTTOMLEFT
:
559 *r
= screen_desktop_layout
.rows
- 1 -
560 d
% screen_desktop_layout
.rows
;
561 *c
= d
/ screen_desktop_layout
.rows
;
563 case OB_CORNER_TOPRIGHT
:
564 *r
= d
% screen_desktop_layout
.rows
;
565 *c
= screen_desktop_layout
.columns
- 1 -
566 d
/ screen_desktop_layout
.rows
;
568 case OB_CORNER_BOTTOMRIGHT
:
569 *r
= screen_desktop_layout
.rows
- 1 -
570 d
% screen_desktop_layout
.rows
;
571 *c
= screen_desktop_layout
.columns
- 1 -
572 d
/ screen_desktop_layout
.rows
;
579 static guint
translate_row_col(guint r
, guint c
)
581 switch (screen_desktop_layout
.orientation
) {
582 case OB_ORIENTATION_HORZ
:
583 switch (screen_desktop_layout
.start_corner
) {
584 case OB_CORNER_TOPLEFT
:
585 return r
% screen_desktop_layout
.rows
*
586 screen_desktop_layout
.columns
+
587 c
% screen_desktop_layout
.columns
;
588 case OB_CORNER_BOTTOMLEFT
:
589 return (screen_desktop_layout
.rows
- 1 -
590 r
% screen_desktop_layout
.rows
) *
591 screen_desktop_layout
.columns
+
592 c
% screen_desktop_layout
.columns
;
593 case OB_CORNER_TOPRIGHT
:
594 return r
% screen_desktop_layout
.rows
*
595 screen_desktop_layout
.columns
+
596 (screen_desktop_layout
.columns
- 1 -
597 c
% screen_desktop_layout
.columns
);
598 case OB_CORNER_BOTTOMRIGHT
:
599 return (screen_desktop_layout
.rows
- 1 -
600 r
% screen_desktop_layout
.rows
) *
601 screen_desktop_layout
.columns
+
602 (screen_desktop_layout
.columns
- 1 -
603 c
% screen_desktop_layout
.columns
);
605 case OB_ORIENTATION_VERT
:
606 switch (screen_desktop_layout
.start_corner
) {
607 case OB_CORNER_TOPLEFT
:
608 return c
% screen_desktop_layout
.columns
*
609 screen_desktop_layout
.rows
+
610 r
% screen_desktop_layout
.rows
;
611 case OB_CORNER_BOTTOMLEFT
:
612 return c
% screen_desktop_layout
.columns
*
613 screen_desktop_layout
.rows
+
614 (screen_desktop_layout
.rows
- 1 -
615 r
% screen_desktop_layout
.rows
);
616 case OB_CORNER_TOPRIGHT
:
617 return (screen_desktop_layout
.columns
- 1 -
618 c
% screen_desktop_layout
.columns
) *
619 screen_desktop_layout
.rows
+
620 r
% screen_desktop_layout
.rows
;
621 case OB_CORNER_BOTTOMRIGHT
:
622 return (screen_desktop_layout
.columns
- 1 -
623 c
% screen_desktop_layout
.columns
) *
624 screen_desktop_layout
.rows
+
625 (screen_desktop_layout
.rows
- 1 -
626 r
% screen_desktop_layout
.rows
);
629 g_assert_not_reached();
633 void screen_desktop_popup(guint d
, gboolean show
)
638 pager_popup_hide(desktop_cycle_popup
);
640 a
= screen_physical_area_monitor(0);
641 pager_popup_position(desktop_cycle_popup
, CenterGravity
,
642 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
643 pager_popup_max_width(desktop_cycle_popup
,
644 MAX(a
->width
/3, POPUP_WIDTH
));
645 pager_popup_show(desktop_cycle_popup
, screen_desktop_names
[d
], d
);
649 guint
screen_cycle_desktop(ObDirection dir
, gboolean wrap
, gboolean linear
,
650 gboolean dialog
, gboolean done
, gboolean cancel
)
656 if ((cancel
|| done
) && dialog
)
657 goto show_cycle_dialog
;
659 get_row_col(d
, &r
, &c
);
663 case OB_DIRECTION_EAST
:
664 if (d
< screen_num_desktops
- 1)
669 case OB_DIRECTION_WEST
:
673 d
= screen_num_desktops
- 1;
677 return screen_desktop
;
681 case OB_DIRECTION_EAST
:
683 if (c
>= screen_desktop_layout
.columns
) {
688 goto show_cycle_dialog
;
691 d
= translate_row_col(r
, c
);
692 if (d
>= screen_num_desktops
) {
697 goto show_cycle_dialog
;
701 case OB_DIRECTION_WEST
:
703 if (c
>= screen_desktop_layout
.columns
) {
705 c
= screen_desktop_layout
.columns
- 1;
708 goto show_cycle_dialog
;
711 d
= translate_row_col(r
, c
);
712 if (d
>= screen_num_desktops
) {
717 goto show_cycle_dialog
;
721 case OB_DIRECTION_SOUTH
:
723 if (r
>= screen_desktop_layout
.rows
) {
728 goto show_cycle_dialog
;
731 d
= translate_row_col(r
, c
);
732 if (d
>= screen_num_desktops
) {
737 goto show_cycle_dialog
;
741 case OB_DIRECTION_NORTH
:
743 if (r
>= screen_desktop_layout
.rows
) {
745 r
= screen_desktop_layout
.rows
- 1;
748 goto show_cycle_dialog
;
751 d
= translate_row_col(r
, c
);
752 if (d
>= screen_num_desktops
) {
757 goto show_cycle_dialog
;
763 return d
= screen_desktop
;
766 d
= translate_row_col(r
, c
);
770 if (dialog
&& !cancel
&& !done
) {
771 screen_desktop_popup(d
, TRUE
);
773 screen_desktop_popup(0, FALSE
);
777 void screen_update_layout()
779 ObOrientation orient
;
785 gboolean valid
= FALSE
;
787 if (PROP_GETA32(RootWindow(ob_display
, ob_screen
),
788 net_desktop_layout
, cardinal
, &data
, &num
)) {
789 if (num
== 3 || num
== 4) {
791 if (data
[0] == prop_atoms
.net_wm_orientation_vert
)
792 orient
= OB_ORIENTATION_VERT
;
793 else if (data
[0] == prop_atoms
.net_wm_orientation_horz
)
794 orient
= OB_ORIENTATION_HORZ
;
796 goto screen_update_layout_bail
;
799 corner
= OB_CORNER_TOPLEFT
;
801 if (data
[3] == prop_atoms
.net_wm_topleft
)
802 corner
= OB_CORNER_TOPLEFT
;
803 else if (data
[3] == prop_atoms
.net_wm_topright
)
804 corner
= OB_CORNER_TOPRIGHT
;
805 else if (data
[3] == prop_atoms
.net_wm_bottomright
)
806 corner
= OB_CORNER_BOTTOMRIGHT
;
807 else if (data
[3] == prop_atoms
.net_wm_bottomleft
)
808 corner
= OB_CORNER_BOTTOMLEFT
;
810 goto screen_update_layout_bail
;
816 /* fill in a zero rows/columns */
817 if ((cols
== 0 && rows
== 0)) { /* both 0's is bad data.. */
818 goto screen_update_layout_bail
;
821 cols
= screen_num_desktops
/ rows
;
822 if (rows
* cols
< screen_num_desktops
)
824 if (rows
* cols
>= screen_num_desktops
+ cols
)
826 } else if (rows
== 0) {
827 rows
= screen_num_desktops
/ cols
;
828 if (cols
* rows
< screen_num_desktops
)
830 if (cols
* rows
>= screen_num_desktops
+ rows
)
835 /* bounds checking */
836 if (orient
== OB_ORIENTATION_HORZ
) {
837 cols
= MIN(screen_num_desktops
, cols
);
838 rows
= MIN(rows
, (screen_num_desktops
+ cols
- 1) / cols
);
839 cols
= screen_num_desktops
/ rows
+
840 !!(screen_num_desktops
% rows
);
842 rows
= MIN(screen_num_desktops
, rows
);
843 cols
= MIN(cols
, (screen_num_desktops
+ rows
- 1) / rows
);
844 rows
= screen_num_desktops
/ cols
+
845 !!(screen_num_desktops
% cols
);
850 screen_update_layout_bail
:
856 orient
= OB_ORIENTATION_HORZ
;
857 corner
= OB_CORNER_TOPLEFT
;
859 cols
= screen_num_desktops
;
862 screen_desktop_layout
.orientation
= orient
;
863 screen_desktop_layout
.start_corner
= corner
;
864 screen_desktop_layout
.rows
= rows
;
865 screen_desktop_layout
.columns
= cols
;
868 void screen_update_desktop_names()
872 /* empty the array */
873 g_strfreev(screen_desktop_names
);
874 screen_desktop_names
= NULL
;
876 if (PROP_GETSS(RootWindow(ob_display
, ob_screen
),
877 net_desktop_names
, utf8
, &screen_desktop_names
))
878 for (i
= 0; screen_desktop_names
[i
] && i
< screen_num_desktops
; ++i
);
881 if (i
< screen_num_desktops
) {
882 screen_desktop_names
= g_renew(gchar
*, screen_desktop_names
,
883 screen_num_desktops
+ 1);
884 screen_desktop_names
[screen_num_desktops
] = NULL
;
885 for (; i
< screen_num_desktops
; ++i
)
886 screen_desktop_names
[i
] = g_strdup_printf("desktop %i", i
+ 1);
889 /* resize the pager for these names */
890 pager_popup_text_width_to_strings(desktop_cycle_popup
,
891 screen_desktop_names
,
892 screen_num_desktops
);
895 void screen_show_desktop(gboolean show
, gboolean restore_focus
)
899 if (show
== screen_showing_desktop
) return; /* no change */
901 screen_showing_desktop
= show
;
905 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
906 if (WINDOW_IS_CLIENT(it
->data
)) {
907 ObClient
*client
= it
->data
;
908 client_showhide(client
);
913 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
914 if (WINDOW_IS_CLIENT(it
->data
)) {
915 ObClient
*client
= it
->data
;
916 client_showhide(client
);
923 for (it
= focus_order
; it
; it
= g_list_next(it
)) {
924 ObClient
*c
= it
->data
;
925 if (c
->type
== OB_CLIENT_TYPE_DESKTOP
&&
926 (c
->desktop
== screen_desktop
|| c
->desktop
== DESKTOP_ALL
) &&
927 client_focus(it
->data
))
930 } else if (restore_focus
) {
933 /* use NULL for the "old" argument because the desktop was focused
934 and we don't want to fallback to the desktop by default */
935 if ((c
= focus_fallback_target(TRUE
, NULL
)))
939 show
= !!show
; /* make it boolean */
940 PROP_SET32(RootWindow(ob_display
, ob_screen
),
941 net_showing_desktop
, cardinal
, show
);
944 void screen_install_colormap(ObClient
*client
, gboolean install
)
946 if (client
== NULL
) {
948 XInstallColormap(RrDisplay(ob_rr_inst
), RrColormap(ob_rr_inst
));
950 XUninstallColormap(RrDisplay(ob_rr_inst
), RrColormap(ob_rr_inst
));
952 xerror_set_ignore(TRUE
);
954 if (client
->colormap
!= None
)
955 XInstallColormap(RrDisplay(ob_rr_inst
), client
->colormap
);
957 XUninstallColormap(RrDisplay(ob_rr_inst
), client
->colormap
);
958 xerror_set_ignore(FALSE
);
963 screen_area_add_strut_left(const StrutPartial
*s
, const Rect
*monitor_area
,
964 gint edge
, Strut
*ret
)
967 ((s
->left_end
<= s
->left_start
) ||
968 (RECT_TOP(*monitor_area
) < s
->left_end
&&
969 RECT_BOTTOM(*monitor_area
) > s
->left_start
)))
970 ret
->left
= MAX(ret
->left
, edge
);
974 screen_area_add_strut_top(const StrutPartial
*s
, const Rect
*monitor_area
,
975 gint edge
, Strut
*ret
)
978 ((s
->top_end
<= s
->top_start
) ||
979 (RECT_LEFT(*monitor_area
) < s
->top_end
&&
980 RECT_RIGHT(*monitor_area
) > s
->top_start
)))
981 ret
->top
= MAX(ret
->top
, edge
);
985 screen_area_add_strut_right(const StrutPartial
*s
, const Rect
*monitor_area
,
986 gint edge
, Strut
*ret
)
989 ((s
->right_end
<= s
->right_start
) ||
990 (RECT_TOP(*monitor_area
) < s
->right_end
&&
991 RECT_BOTTOM(*monitor_area
) > s
->right_start
)))
992 ret
->right
= MAX(ret
->right
, edge
);
996 screen_area_add_strut_bottom(const StrutPartial
*s
, const Rect
*monitor_area
,
997 gint edge
, Strut
*ret
)
1000 ((s
->bottom_end
<= s
->bottom_start
) ||
1001 (RECT_LEFT(*monitor_area
) < s
->bottom_end
&&
1002 RECT_RIGHT(*monitor_area
) > s
->bottom_start
)))
1003 ret
->bottom
= MAX(ret
->bottom
, edge
);
1006 void screen_update_areas()
1013 g_free(monitor_area
);
1014 extensions_xinerama_screens(&monitor_area
, &screen_num_monitors
);
1017 for (i
= 0; area
[i
]; ++i
)
1022 area
= g_new(Rect
*, screen_num_desktops
+ 2);
1023 for (i
= 0; i
< screen_num_desktops
+ 1; ++i
)
1024 area
[i
] = g_new0(Rect
, screen_num_monitors
+ 1);
1027 dims
= g_new(gulong
, 4 * screen_num_desktops
);
1029 for (i
= 0; i
< screen_num_desktops
+ 1; ++i
) {
1033 struts
= g_new0(Strut
, screen_num_monitors
);
1035 /* calc the xinerama areas */
1036 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1037 area
[i
][x
] = monitor_area
[x
];
1039 l
= monitor_area
[x
].x
;
1040 t
= monitor_area
[x
].y
;
1041 r
= monitor_area
[x
].x
+ monitor_area
[x
].width
- 1;
1042 b
= monitor_area
[x
].y
+ monitor_area
[x
].height
- 1;
1044 l
= MIN(l
, monitor_area
[x
].x
);
1045 t
= MIN(t
, monitor_area
[x
].y
);
1046 r
= MAX(r
, monitor_area
[x
].x
+ monitor_area
[x
].width
- 1);
1047 b
= MAX(b
, monitor_area
[x
].y
+ monitor_area
[x
].height
- 1);
1050 RECT_SET(area
[i
][x
], l
, t
, r
- l
+ 1, b
- t
+ 1);
1052 /* apply the struts */
1054 /* find the left-most xin heads, i do this in 2 loops :| */
1056 for (x
= 1; x
< screen_num_monitors
; ++x
)
1057 o
= MIN(o
, area
[i
][x
].x
);
1059 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1060 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1061 ObClient
*c
= it
->data
;
1062 screen_area_add_strut_left(&c
->strut
,
1064 o
+ c
->strut
.left
- area
[i
][x
].x
,
1067 screen_area_add_strut_left(&dock_strut
,
1069 o
+ dock_strut
.left
- area
[i
][x
].x
,
1072 area
[i
][x
].x
+= struts
[x
].left
;
1073 area
[i
][x
].width
-= struts
[x
].left
;
1076 /* find the top-most xin heads, i do this in 2 loops :| */
1078 for (x
= 1; x
< screen_num_monitors
; ++x
)
1079 o
= MIN(o
, area
[i
][x
].y
);
1081 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1082 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1083 ObClient
*c
= it
->data
;
1084 screen_area_add_strut_top(&c
->strut
,
1086 o
+ c
->strut
.top
- area
[i
][x
].y
,
1089 screen_area_add_strut_top(&dock_strut
,
1091 o
+ dock_strut
.top
- area
[i
][x
].y
,
1094 area
[i
][x
].y
+= struts
[x
].top
;
1095 area
[i
][x
].height
-= struts
[x
].top
;
1098 /* find the right-most xin heads, i do this in 2 loops :| */
1099 o
= area
[i
][0].x
+ area
[i
][0].width
- 1;
1100 for (x
= 1; x
< screen_num_monitors
; ++x
)
1101 o
= MAX(o
, area
[i
][x
].x
+ area
[i
][x
].width
- 1);
1103 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1104 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1105 ObClient
*c
= it
->data
;
1106 screen_area_add_strut_right(&c
->strut
,
1109 area
[i
][x
].width
- 1) -
1110 (o
- c
->strut
.right
),
1113 screen_area_add_strut_right(&dock_strut
,
1116 area
[i
][x
].width
- 1) -
1117 (o
- dock_strut
.right
),
1120 area
[i
][x
].width
-= struts
[x
].right
;
1123 /* find the bottom-most xin heads, i do this in 2 loops :| */
1124 o
= area
[i
][0].y
+ area
[i
][0].height
- 1;
1125 for (x
= 1; x
< screen_num_monitors
; ++x
)
1126 o
= MAX(o
, area
[i
][x
].y
+ area
[i
][x
].height
- 1);
1128 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1129 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1130 ObClient
*c
= it
->data
;
1131 screen_area_add_strut_bottom(&c
->strut
,
1134 area
[i
][x
].height
- 1) - \
1135 (o
- c
->strut
.bottom
),
1138 screen_area_add_strut_bottom(&dock_strut
,
1141 area
[i
][x
].height
- 1) - \
1142 (o
- dock_strut
.bottom
),
1145 area
[i
][x
].height
-= struts
[x
].bottom
;
1148 l
= RECT_LEFT(area
[i
][0]);
1149 t
= RECT_TOP(area
[i
][0]);
1150 r
= RECT_RIGHT(area
[i
][0]);
1151 b
= RECT_BOTTOM(area
[i
][0]);
1152 for (x
= 1; x
< screen_num_monitors
; ++x
) {
1153 l
= MIN(l
, RECT_LEFT(area
[i
][x
]));
1154 t
= MIN(l
, RECT_TOP(area
[i
][x
]));
1155 r
= MAX(r
, RECT_RIGHT(area
[i
][x
]));
1156 b
= MAX(b
, RECT_BOTTOM(area
[i
][x
]));
1158 RECT_SET(area
[i
][screen_num_monitors
], l
, t
,
1159 r
- l
+ 1, b
- t
+ 1);
1161 /* XXX optimize when this is run? */
1163 /* the area has changed, adjust all the maximized
1165 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1166 ObClient
*c
= it
->data
;
1167 if (i
< screen_num_desktops
) {
1168 if (c
->desktop
== i
)
1169 client_reconfigure(c
);
1170 } else if (c
->desktop
== DESKTOP_ALL
)
1171 client_reconfigure(c
);
1173 if (i
< screen_num_desktops
) {
1174 /* don't set these for the 'all desktops' area */
1175 dims
[(i
* 4) + 0] = area
[i
][screen_num_monitors
].x
;
1176 dims
[(i
* 4) + 1] = area
[i
][screen_num_monitors
].y
;
1177 dims
[(i
* 4) + 2] = area
[i
][screen_num_monitors
].width
;
1178 dims
[(i
* 4) + 3] = area
[i
][screen_num_monitors
].height
;
1184 PROP_SETA32(RootWindow(ob_display
, ob_screen
), net_workarea
, cardinal
,
1185 dims
, 4 * screen_num_desktops
);
1190 Rect
*screen_area(guint desktop
)
1192 return screen_area_monitor(desktop
, screen_num_monitors
);
1195 Rect
*screen_area_monitor(guint desktop
, guint head
)
1197 if (head
> screen_num_monitors
)
1199 if (desktop
>= screen_num_desktops
) {
1200 if (desktop
== DESKTOP_ALL
)
1201 return &area
[screen_num_desktops
][head
];
1204 return &area
[desktop
][head
];
1207 guint
screen_find_monitor(Rect
*search
)
1213 for (i
= 0; i
< screen_num_monitors
; ++i
) {
1214 Rect
*area
= screen_physical_area_monitor(i
);
1215 if (RECT_INTERSECTS_RECT(*area
, *search
)) {
1219 RECT_SET_INTERSECTION(r
, *area
, *search
);
1220 v
= r
.width
* r
.height
;
1231 Rect
*screen_physical_area()
1233 return screen_physical_area_monitor(screen_num_monitors
);
1236 Rect
*screen_physical_area_monitor(guint head
)
1238 if (head
> screen_num_monitors
)
1240 return &monitor_area
[head
];
1243 void screen_set_root_cursor()
1245 if (sn_app_starting())
1246 XDefineCursor(ob_display
, RootWindow(ob_display
, ob_screen
),
1247 ob_cursor(OB_CURSOR_BUSY
));
1249 XDefineCursor(ob_display
, RootWindow(ob_display
, ob_screen
),
1250 ob_cursor(OB_CURSOR_POINTER
));
1253 gboolean
screen_pointer_pos(gint
*x
, gint
*y
)
1260 ret
= !!XQueryPointer(ob_display
, RootWindow(ob_display
, ob_screen
),
1261 &w
, &w
, x
, y
, &i
, &i
, &u
);
1263 for (i
= 0; i
< ScreenCount(ob_display
); ++i
)
1265 if (XQueryPointer(ob_display
, RootWindow(ob_display
, i
),
1266 &w
, &w
, x
, y
, &i
, &i
, &u
))