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_startup_id
;
280 supported
[i
++] = prop_atoms
.net_wm_sync_request
;
281 supported
[i
++] = prop_atoms
.net_wm_sync_request_counter
;
284 supported
[i
++] = prop_atoms
.kde_wm_change_state
;
285 supported
[i
++] = prop_atoms
.kde_net_wm_frame_strut
;
286 supported
[i
++] = prop_atoms
.kde_net_wm_window_type_override
;
288 supported
[i
++] = prop_atoms
.openbox_wm_state_undecorated
;
289 supported
[i
++] = prop_atoms
.openbox_pid
;
290 supported
[i
++] = prop_atoms
.openbox_config
;
291 supported
[i
++] = prop_atoms
.openbox_control
;
292 g_assert(i
== num_support
);
294 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
295 net_supported
, atom
, supported
, num_support
);
301 void screen_startup(gboolean reconfig
)
308 desktop_cycle_popup
= pager_popup_new(FALSE
);
309 pager_popup_height(desktop_cycle_popup
, POPUP_HEIGHT
);
314 /* get the initial size */
317 /* get the desktop names */
318 numnames
= g_slist_length(config_desktops_names
);
319 names
= g_new(gchar
*, numnames
+ 1);
320 names
[numnames
] = NULL
;
321 for (i
= 0, it
= config_desktops_names
; it
; ++i
, it
= g_slist_next(it
))
322 names
[i
] = g_strdup(it
->data
);
324 /* set the root window property */
325 PROP_SETSS(RootWindow(ob_display
, ob_screen
), net_desktop_names
,names
);
329 /* set the number of desktops */
330 screen_num_desktops
= 0;
331 screen_set_num_desktops(config_desktops_num
);
333 /* start on the current desktop when a wm was already running */
334 if (PROP_GET32(RootWindow(ob_display
, ob_screen
),
335 net_current_desktop
, cardinal
, &d
) &&
336 d
< screen_num_desktops
)
338 screen_set_desktop(d
, FALSE
);
339 } else if (session_desktop
>= 0)
340 screen_set_desktop(MIN((guint
)session_desktop
,
341 screen_num_desktops
), FALSE
);
343 screen_set_desktop(MIN(config_screen_firstdesk
,
344 screen_num_desktops
) - 1, FALSE
);
346 /* don't start in showing-desktop mode */
347 screen_showing_desktop
= FALSE
;
348 PROP_SET32(RootWindow(ob_display
, ob_screen
),
349 net_showing_desktop
, cardinal
, screen_showing_desktop
);
351 screen_update_layout();
354 void screen_shutdown(gboolean reconfig
)
358 pager_popup_free(desktop_cycle_popup
);
363 XSelectInput(ob_display
, RootWindow(ob_display
, ob_screen
),
366 /* we're not running here no more! */
367 PROP_ERASE(RootWindow(ob_display
, ob_screen
), openbox_pid
);
369 PROP_ERASE(RootWindow(ob_display
, ob_screen
), net_supported
);
370 /* don't keep this mode */
371 PROP_ERASE(RootWindow(ob_display
, ob_screen
), net_showing_desktop
);
373 XDestroyWindow(ob_display
, screen_support_win
);
375 g_strfreev(screen_desktop_names
);
376 screen_desktop_names
= NULL
;
378 for (r
= area
; *r
; ++r
)
386 static gint oldw
= 0, oldh
= 0;
391 w
= WidthOfScreen(ScreenOfDisplay(ob_display
, ob_screen
));
392 h
= HeightOfScreen(ScreenOfDisplay(ob_display
, ob_screen
));
394 if (w
== oldw
&& h
== oldh
) return;
398 /* Set the _NET_DESKTOP_GEOMETRY hint */
399 screen_physical_size
.width
= geometry
[0] = w
;
400 screen_physical_size
.height
= geometry
[1] = h
;
401 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
402 net_desktop_geometry
, cardinal
, geometry
, 2);
404 if (ob_state() == OB_STATE_STARTING
)
407 screen_update_areas();
410 for (it
= client_list
; it
; it
= g_list_next(it
))
411 client_move_onscreen(it
->data
, FALSE
);
414 void screen_set_num_desktops(guint num
)
422 if (screen_num_desktops
== num
) return;
424 old
= screen_num_desktops
;
425 screen_num_desktops
= num
;
426 PROP_SET32(RootWindow(ob_display
, ob_screen
),
427 net_number_of_desktops
, cardinal
, num
);
429 /* set the viewport hint */
430 viewport
= g_new0(gulong
, num
* 2);
431 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
432 net_desktop_viewport
, cardinal
, viewport
, num
* 2);
435 /* the number of rows/columns will differ */
436 screen_update_layout();
438 /* move windows on desktops that will no longer exist! */
439 for (it
= client_list
; it
; it
= g_list_next(it
)) {
440 ObClient
*c
= it
->data
;
441 if (c
->desktop
>= num
&& c
->desktop
!= DESKTOP_ALL
)
442 client_set_desktop(c
, num
- 1, FALSE
);
445 /* change our struts/area to match (after moving windows) */
446 screen_update_areas();
448 /* may be some unnamed desktops that we need to fill in with names
449 (after updating the areas so the popup can resize) */
450 screen_update_desktop_names();
452 /* change our desktop if we're on one that no longer exists! */
453 if (screen_desktop
>= screen_num_desktops
)
454 screen_set_desktop(num
- 1, TRUE
);
457 void screen_set_desktop(guint num
, gboolean dofocus
)
463 g_assert(num
< screen_num_desktops
);
465 old
= screen_desktop
;
466 screen_desktop
= num
;
467 PROP_SET32(RootWindow(ob_display
, ob_screen
),
468 net_current_desktop
, cardinal
, num
);
470 if (old
== num
) return;
472 screen_last_desktop
= old
;
474 ob_debug("Moving to desktop %d\n", num
+1);
476 if (moveresize_client
)
477 client_set_desktop(moveresize_client
, num
, TRUE
);
479 /* show windows before hiding the rest to lessen the enter/leave events */
481 /* show windows from top to bottom */
482 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
483 if (WINDOW_IS_CLIENT(it
->data
)) {
484 ObClient
*c
= it
->data
;
489 /* have to try focus here because when you leave an empty desktop
490 there is no focus out to watch for
492 do this before hiding the windows so if helper windows are coming
493 with us, they don't get hidden
495 if (dofocus
&& (c
= focus_fallback_target(TRUE
, focus_client
))) {
496 /* only do the flicker reducing stuff ahead of time if we are going
497 to call xsetinputfocus on the window ourselves. otherwise there is
498 no guarantee the window will actually take focus.. */
500 /* do this here so that if you switch desktops to a window with
501 helper windows then the helper windows won't flash */
502 client_bring_helper_windows(c
);
503 /* reduce flicker by hiliting now rather than waiting for the
504 server FocusIn event */
505 frame_adjust_focus(c
->frame
, TRUE
);
510 /* hide windows from bottom to top */
511 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
512 if (WINDOW_IS_CLIENT(it
->data
)) {
513 ObClient
*c
= it
->data
;
518 event_ignore_queued_enters();
520 if (event_curtime
!= CurrentTime
)
521 screen_desktop_user_time
= event_curtime
;
524 static void get_row_col(guint d
, guint
*r
, guint
*c
)
526 switch (screen_desktop_layout
.orientation
) {
527 case OB_ORIENTATION_HORZ
:
528 switch (screen_desktop_layout
.start_corner
) {
529 case OB_CORNER_TOPLEFT
:
530 *r
= d
/ screen_desktop_layout
.columns
;
531 *c
= d
% screen_desktop_layout
.columns
;
533 case OB_CORNER_BOTTOMLEFT
:
534 *r
= screen_desktop_layout
.rows
- 1 -
535 d
/ screen_desktop_layout
.columns
;
536 *c
= d
% screen_desktop_layout
.columns
;
538 case OB_CORNER_TOPRIGHT
:
539 *r
= d
/ screen_desktop_layout
.columns
;
540 *c
= screen_desktop_layout
.columns
- 1 -
541 d
% screen_desktop_layout
.columns
;
543 case OB_CORNER_BOTTOMRIGHT
:
544 *r
= screen_desktop_layout
.rows
- 1 -
545 d
/ screen_desktop_layout
.columns
;
546 *c
= screen_desktop_layout
.columns
- 1 -
547 d
% screen_desktop_layout
.columns
;
551 case OB_ORIENTATION_VERT
:
552 switch (screen_desktop_layout
.start_corner
) {
553 case OB_CORNER_TOPLEFT
:
554 *r
= d
% screen_desktop_layout
.rows
;
555 *c
= d
/ screen_desktop_layout
.rows
;
557 case OB_CORNER_BOTTOMLEFT
:
558 *r
= screen_desktop_layout
.rows
- 1 -
559 d
% screen_desktop_layout
.rows
;
560 *c
= d
/ screen_desktop_layout
.rows
;
562 case OB_CORNER_TOPRIGHT
:
563 *r
= d
% screen_desktop_layout
.rows
;
564 *c
= screen_desktop_layout
.columns
- 1 -
565 d
/ screen_desktop_layout
.rows
;
567 case OB_CORNER_BOTTOMRIGHT
:
568 *r
= screen_desktop_layout
.rows
- 1 -
569 d
% screen_desktop_layout
.rows
;
570 *c
= screen_desktop_layout
.columns
- 1 -
571 d
/ screen_desktop_layout
.rows
;
578 static guint
translate_row_col(guint r
, guint c
)
580 switch (screen_desktop_layout
.orientation
) {
581 case OB_ORIENTATION_HORZ
:
582 switch (screen_desktop_layout
.start_corner
) {
583 case OB_CORNER_TOPLEFT
:
584 return r
% screen_desktop_layout
.rows
*
585 screen_desktop_layout
.columns
+
586 c
% screen_desktop_layout
.columns
;
587 case OB_CORNER_BOTTOMLEFT
:
588 return (screen_desktop_layout
.rows
- 1 -
589 r
% screen_desktop_layout
.rows
) *
590 screen_desktop_layout
.columns
+
591 c
% screen_desktop_layout
.columns
;
592 case OB_CORNER_TOPRIGHT
:
593 return r
% screen_desktop_layout
.rows
*
594 screen_desktop_layout
.columns
+
595 (screen_desktop_layout
.columns
- 1 -
596 c
% screen_desktop_layout
.columns
);
597 case OB_CORNER_BOTTOMRIGHT
:
598 return (screen_desktop_layout
.rows
- 1 -
599 r
% screen_desktop_layout
.rows
) *
600 screen_desktop_layout
.columns
+
601 (screen_desktop_layout
.columns
- 1 -
602 c
% screen_desktop_layout
.columns
);
604 case OB_ORIENTATION_VERT
:
605 switch (screen_desktop_layout
.start_corner
) {
606 case OB_CORNER_TOPLEFT
:
607 return c
% screen_desktop_layout
.columns
*
608 screen_desktop_layout
.rows
+
609 r
% screen_desktop_layout
.rows
;
610 case OB_CORNER_BOTTOMLEFT
:
611 return c
% screen_desktop_layout
.columns
*
612 screen_desktop_layout
.rows
+
613 (screen_desktop_layout
.rows
- 1 -
614 r
% screen_desktop_layout
.rows
);
615 case OB_CORNER_TOPRIGHT
:
616 return (screen_desktop_layout
.columns
- 1 -
617 c
% screen_desktop_layout
.columns
) *
618 screen_desktop_layout
.rows
+
619 r
% screen_desktop_layout
.rows
;
620 case OB_CORNER_BOTTOMRIGHT
:
621 return (screen_desktop_layout
.columns
- 1 -
622 c
% screen_desktop_layout
.columns
) *
623 screen_desktop_layout
.rows
+
624 (screen_desktop_layout
.rows
- 1 -
625 r
% screen_desktop_layout
.rows
);
628 g_assert_not_reached();
632 void screen_desktop_popup(guint d
, gboolean show
)
637 pager_popup_hide(desktop_cycle_popup
);
639 a
= screen_physical_area_monitor(0);
640 pager_popup_position(desktop_cycle_popup
, CenterGravity
,
641 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
642 pager_popup_max_width(desktop_cycle_popup
,
643 MAX(a
->width
/3, POPUP_WIDTH
));
644 pager_popup_show(desktop_cycle_popup
, screen_desktop_names
[d
], d
);
648 guint
screen_cycle_desktop(ObDirection dir
, gboolean wrap
, gboolean linear
,
649 gboolean dialog
, gboolean done
, gboolean cancel
)
655 if ((cancel
|| done
) && dialog
)
656 goto show_cycle_dialog
;
658 get_row_col(d
, &r
, &c
);
662 case OB_DIRECTION_EAST
:
663 if (d
< screen_num_desktops
- 1)
668 case OB_DIRECTION_WEST
:
672 d
= screen_num_desktops
- 1;
676 return screen_desktop
;
680 case OB_DIRECTION_EAST
:
682 if (c
>= screen_desktop_layout
.columns
) {
687 goto show_cycle_dialog
;
690 d
= translate_row_col(r
, c
);
691 if (d
>= screen_num_desktops
) {
696 goto show_cycle_dialog
;
700 case OB_DIRECTION_WEST
:
702 if (c
>= screen_desktop_layout
.columns
) {
704 c
= screen_desktop_layout
.columns
- 1;
707 goto show_cycle_dialog
;
710 d
= translate_row_col(r
, c
);
711 if (d
>= screen_num_desktops
) {
716 goto show_cycle_dialog
;
720 case OB_DIRECTION_SOUTH
:
722 if (r
>= screen_desktop_layout
.rows
) {
727 goto show_cycle_dialog
;
730 d
= translate_row_col(r
, c
);
731 if (d
>= screen_num_desktops
) {
736 goto show_cycle_dialog
;
740 case OB_DIRECTION_NORTH
:
742 if (r
>= screen_desktop_layout
.rows
) {
744 r
= screen_desktop_layout
.rows
- 1;
747 goto show_cycle_dialog
;
750 d
= translate_row_col(r
, c
);
751 if (d
>= screen_num_desktops
) {
756 goto show_cycle_dialog
;
762 return d
= screen_desktop
;
765 d
= translate_row_col(r
, c
);
769 if (dialog
&& !cancel
&& !done
) {
770 screen_desktop_popup(d
, TRUE
);
772 screen_desktop_popup(0, FALSE
);
776 void screen_update_layout()
778 ObOrientation orient
;
784 gboolean valid
= FALSE
;
786 if (PROP_GETA32(RootWindow(ob_display
, ob_screen
),
787 net_desktop_layout
, cardinal
, &data
, &num
)) {
788 if (num
== 3 || num
== 4) {
790 if (data
[0] == prop_atoms
.net_wm_orientation_vert
)
791 orient
= OB_ORIENTATION_VERT
;
792 else if (data
[0] == prop_atoms
.net_wm_orientation_horz
)
793 orient
= OB_ORIENTATION_HORZ
;
795 goto screen_update_layout_bail
;
798 corner
= OB_CORNER_TOPLEFT
;
800 if (data
[3] == prop_atoms
.net_wm_topleft
)
801 corner
= OB_CORNER_TOPLEFT
;
802 else if (data
[3] == prop_atoms
.net_wm_topright
)
803 corner
= OB_CORNER_TOPRIGHT
;
804 else if (data
[3] == prop_atoms
.net_wm_bottomright
)
805 corner
= OB_CORNER_BOTTOMRIGHT
;
806 else if (data
[3] == prop_atoms
.net_wm_bottomleft
)
807 corner
= OB_CORNER_BOTTOMLEFT
;
809 goto screen_update_layout_bail
;
815 /* fill in a zero rows/columns */
816 if ((cols
== 0 && rows
== 0)) { /* both 0's is bad data.. */
817 goto screen_update_layout_bail
;
820 cols
= screen_num_desktops
/ rows
;
821 if (rows
* cols
< screen_num_desktops
)
823 if (rows
* cols
>= screen_num_desktops
+ cols
)
825 } else if (rows
== 0) {
826 rows
= screen_num_desktops
/ cols
;
827 if (cols
* rows
< screen_num_desktops
)
829 if (cols
* rows
>= screen_num_desktops
+ rows
)
834 /* bounds checking */
835 if (orient
== OB_ORIENTATION_HORZ
) {
836 cols
= MIN(screen_num_desktops
, cols
);
837 rows
= MIN(rows
, (screen_num_desktops
+ cols
- 1) / cols
);
838 cols
= screen_num_desktops
/ rows
+
839 !!(screen_num_desktops
% rows
);
841 rows
= MIN(screen_num_desktops
, rows
);
842 cols
= MIN(cols
, (screen_num_desktops
+ rows
- 1) / rows
);
843 rows
= screen_num_desktops
/ cols
+
844 !!(screen_num_desktops
% cols
);
849 screen_update_layout_bail
:
855 orient
= OB_ORIENTATION_HORZ
;
856 corner
= OB_CORNER_TOPLEFT
;
858 cols
= screen_num_desktops
;
861 screen_desktop_layout
.orientation
= orient
;
862 screen_desktop_layout
.start_corner
= corner
;
863 screen_desktop_layout
.rows
= rows
;
864 screen_desktop_layout
.columns
= cols
;
867 void screen_update_desktop_names()
871 /* empty the array */
872 g_strfreev(screen_desktop_names
);
873 screen_desktop_names
= NULL
;
875 if (PROP_GETSS(RootWindow(ob_display
, ob_screen
),
876 net_desktop_names
, utf8
, &screen_desktop_names
))
877 for (i
= 0; screen_desktop_names
[i
] && i
< screen_num_desktops
; ++i
);
880 if (i
< screen_num_desktops
) {
881 screen_desktop_names
= g_renew(gchar
*, screen_desktop_names
,
882 screen_num_desktops
+ 1);
883 screen_desktop_names
[screen_num_desktops
] = NULL
;
884 for (; i
< screen_num_desktops
; ++i
)
885 screen_desktop_names
[i
] = g_strdup_printf("desktop %i", i
+ 1);
888 /* resize the pager for these names */
889 pager_popup_text_width_to_strings(desktop_cycle_popup
,
890 screen_desktop_names
,
891 screen_num_desktops
);
894 void screen_show_desktop(gboolean show
, gboolean restore_focus
)
898 if (show
== screen_showing_desktop
) return; /* no change */
900 screen_showing_desktop
= show
;
904 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
905 if (WINDOW_IS_CLIENT(it
->data
)) {
906 ObClient
*client
= it
->data
;
907 client_showhide(client
);
912 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
913 if (WINDOW_IS_CLIENT(it
->data
)) {
914 ObClient
*client
= it
->data
;
915 client_showhide(client
);
922 for (it
= focus_order
; it
; it
= g_list_next(it
)) {
923 ObClient
*c
= it
->data
;
924 if (c
->type
== OB_CLIENT_TYPE_DESKTOP
&&
925 (c
->desktop
== screen_desktop
|| c
->desktop
== DESKTOP_ALL
) &&
926 client_focus(it
->data
))
929 } else if (restore_focus
) {
932 /* use NULL for the "old" argument because the desktop was focused
933 and we don't want to fallback to the desktop by default */
934 if ((c
= focus_fallback_target(TRUE
, NULL
)))
938 show
= !!show
; /* make it boolean */
939 PROP_SET32(RootWindow(ob_display
, ob_screen
),
940 net_showing_desktop
, cardinal
, show
);
943 void screen_install_colormap(ObClient
*client
, gboolean install
)
945 if (client
== NULL
) {
947 XInstallColormap(RrDisplay(ob_rr_inst
), RrColormap(ob_rr_inst
));
949 XUninstallColormap(RrDisplay(ob_rr_inst
), RrColormap(ob_rr_inst
));
951 xerror_set_ignore(TRUE
);
953 if (client
->colormap
!= None
)
954 XInstallColormap(RrDisplay(ob_rr_inst
), client
->colormap
);
956 XUninstallColormap(RrDisplay(ob_rr_inst
), client
->colormap
);
957 xerror_set_ignore(FALSE
);
962 screen_area_add_strut_left(const StrutPartial
*s
, const Rect
*monitor_area
,
963 gint edge
, Strut
*ret
)
966 ((s
->left_end
<= s
->left_start
) ||
967 (RECT_TOP(*monitor_area
) < s
->left_end
&&
968 RECT_BOTTOM(*monitor_area
) > s
->left_start
)))
969 ret
->left
= MAX(ret
->left
, edge
);
973 screen_area_add_strut_top(const StrutPartial
*s
, const Rect
*monitor_area
,
974 gint edge
, Strut
*ret
)
977 ((s
->top_end
<= s
->top_start
) ||
978 (RECT_LEFT(*monitor_area
) < s
->top_end
&&
979 RECT_RIGHT(*monitor_area
) > s
->top_start
)))
980 ret
->top
= MAX(ret
->top
, edge
);
984 screen_area_add_strut_right(const StrutPartial
*s
, const Rect
*monitor_area
,
985 gint edge
, Strut
*ret
)
988 ((s
->right_end
<= s
->right_start
) ||
989 (RECT_TOP(*monitor_area
) < s
->right_end
&&
990 RECT_BOTTOM(*monitor_area
) > s
->right_start
)))
991 ret
->right
= MAX(ret
->right
, edge
);
995 screen_area_add_strut_bottom(const StrutPartial
*s
, const Rect
*monitor_area
,
996 gint edge
, Strut
*ret
)
999 ((s
->bottom_end
<= s
->bottom_start
) ||
1000 (RECT_LEFT(*monitor_area
) < s
->bottom_end
&&
1001 RECT_RIGHT(*monitor_area
) > s
->bottom_start
)))
1002 ret
->bottom
= MAX(ret
->bottom
, edge
);
1005 void screen_update_areas()
1012 g_free(monitor_area
);
1013 extensions_xinerama_screens(&monitor_area
, &screen_num_monitors
);
1016 for (i
= 0; area
[i
]; ++i
)
1021 area
= g_new(Rect
*, screen_num_desktops
+ 2);
1022 for (i
= 0; i
< screen_num_desktops
+ 1; ++i
)
1023 area
[i
] = g_new0(Rect
, screen_num_monitors
+ 1);
1026 dims
= g_new(gulong
, 4 * screen_num_desktops
);
1028 for (i
= 0; i
< screen_num_desktops
+ 1; ++i
) {
1032 struts
= g_new0(Strut
, screen_num_monitors
);
1034 /* calc the xinerama areas */
1035 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1036 area
[i
][x
] = monitor_area
[x
];
1038 l
= monitor_area
[x
].x
;
1039 t
= monitor_area
[x
].y
;
1040 r
= monitor_area
[x
].x
+ monitor_area
[x
].width
- 1;
1041 b
= monitor_area
[x
].y
+ monitor_area
[x
].height
- 1;
1043 l
= MIN(l
, monitor_area
[x
].x
);
1044 t
= MIN(t
, monitor_area
[x
].y
);
1045 r
= MAX(r
, monitor_area
[x
].x
+ monitor_area
[x
].width
- 1);
1046 b
= MAX(b
, monitor_area
[x
].y
+ monitor_area
[x
].height
- 1);
1049 RECT_SET(area
[i
][x
], l
, t
, r
- l
+ 1, b
- t
+ 1);
1051 /* apply the struts */
1053 /* find the left-most xin heads, i do this in 2 loops :| */
1055 for (x
= 1; x
< screen_num_monitors
; ++x
)
1056 o
= MIN(o
, area
[i
][x
].x
);
1058 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1059 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1060 ObClient
*c
= it
->data
;
1061 screen_area_add_strut_left(&c
->strut
,
1063 o
+ c
->strut
.left
- area
[i
][x
].x
,
1066 screen_area_add_strut_left(&dock_strut
,
1068 o
+ dock_strut
.left
- area
[i
][x
].x
,
1071 area
[i
][x
].x
+= struts
[x
].left
;
1072 area
[i
][x
].width
-= struts
[x
].left
;
1075 /* find the top-most xin heads, i do this in 2 loops :| */
1077 for (x
= 1; x
< screen_num_monitors
; ++x
)
1078 o
= MIN(o
, area
[i
][x
].y
);
1080 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1081 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1082 ObClient
*c
= it
->data
;
1083 screen_area_add_strut_top(&c
->strut
,
1085 o
+ c
->strut
.top
- area
[i
][x
].y
,
1088 screen_area_add_strut_top(&dock_strut
,
1090 o
+ dock_strut
.top
- area
[i
][x
].y
,
1093 area
[i
][x
].y
+= struts
[x
].top
;
1094 area
[i
][x
].height
-= struts
[x
].top
;
1097 /* find the right-most xin heads, i do this in 2 loops :| */
1098 o
= area
[i
][0].x
+ area
[i
][0].width
- 1;
1099 for (x
= 1; x
< screen_num_monitors
; ++x
)
1100 o
= MAX(o
, area
[i
][x
].x
+ area
[i
][x
].width
- 1);
1102 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1103 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1104 ObClient
*c
= it
->data
;
1105 screen_area_add_strut_right(&c
->strut
,
1108 area
[i
][x
].width
- 1) -
1109 (o
- c
->strut
.right
),
1112 screen_area_add_strut_right(&dock_strut
,
1115 area
[i
][x
].width
- 1) -
1116 (o
- dock_strut
.right
),
1119 area
[i
][x
].width
-= struts
[x
].right
;
1122 /* find the bottom-most xin heads, i do this in 2 loops :| */
1123 o
= area
[i
][0].y
+ area
[i
][0].height
- 1;
1124 for (x
= 1; x
< screen_num_monitors
; ++x
)
1125 o
= MAX(o
, area
[i
][x
].y
+ area
[i
][x
].height
- 1);
1127 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1128 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1129 ObClient
*c
= it
->data
;
1130 screen_area_add_strut_bottom(&c
->strut
,
1133 area
[i
][x
].height
- 1) - \
1134 (o
- c
->strut
.bottom
),
1137 screen_area_add_strut_bottom(&dock_strut
,
1140 area
[i
][x
].height
- 1) - \
1141 (o
- dock_strut
.bottom
),
1144 area
[i
][x
].height
-= struts
[x
].bottom
;
1147 l
= RECT_LEFT(area
[i
][0]);
1148 t
= RECT_TOP(area
[i
][0]);
1149 r
= RECT_RIGHT(area
[i
][0]);
1150 b
= RECT_BOTTOM(area
[i
][0]);
1151 for (x
= 1; x
< screen_num_monitors
; ++x
) {
1152 l
= MIN(l
, RECT_LEFT(area
[i
][x
]));
1153 t
= MIN(l
, RECT_TOP(area
[i
][x
]));
1154 r
= MAX(r
, RECT_RIGHT(area
[i
][x
]));
1155 b
= MAX(b
, RECT_BOTTOM(area
[i
][x
]));
1157 RECT_SET(area
[i
][screen_num_monitors
], l
, t
,
1158 r
- l
+ 1, b
- t
+ 1);
1160 /* XXX optimize when this is run? */
1162 /* the area has changed, adjust all the maximized
1164 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1165 ObClient
*c
= it
->data
;
1166 if (i
< screen_num_desktops
) {
1167 if (c
->desktop
== i
)
1168 client_reconfigure(c
);
1169 } else if (c
->desktop
== DESKTOP_ALL
)
1170 client_reconfigure(c
);
1172 if (i
< screen_num_desktops
) {
1173 /* don't set these for the 'all desktops' area */
1174 dims
[(i
* 4) + 0] = area
[i
][screen_num_monitors
].x
;
1175 dims
[(i
* 4) + 1] = area
[i
][screen_num_monitors
].y
;
1176 dims
[(i
* 4) + 2] = area
[i
][screen_num_monitors
].width
;
1177 dims
[(i
* 4) + 3] = area
[i
][screen_num_monitors
].height
;
1183 PROP_SETA32(RootWindow(ob_display
, ob_screen
), net_workarea
, cardinal
,
1184 dims
, 4 * screen_num_desktops
);
1189 Rect
*screen_area(guint desktop
)
1191 return screen_area_monitor(desktop
, screen_num_monitors
);
1194 Rect
*screen_area_monitor(guint desktop
, guint head
)
1196 if (head
> screen_num_monitors
)
1198 if (desktop
>= screen_num_desktops
) {
1199 if (desktop
== DESKTOP_ALL
)
1200 return &area
[screen_num_desktops
][head
];
1203 return &area
[desktop
][head
];
1206 guint
screen_find_monitor(Rect
*search
)
1212 for (i
= 0; i
< screen_num_monitors
; ++i
) {
1213 Rect
*area
= screen_physical_area_monitor(i
);
1214 if (RECT_INTERSECTS_RECT(*area
, *search
)) {
1218 RECT_SET_INTERSECTION(r
, *area
, *search
);
1219 v
= r
.width
* r
.height
;
1230 Rect
*screen_physical_area()
1232 return screen_physical_area_monitor(screen_num_monitors
);
1235 Rect
*screen_physical_area_monitor(guint head
)
1237 if (head
> screen_num_monitors
)
1239 return &monitor_area
[head
];
1242 void screen_set_root_cursor()
1244 if (sn_app_starting())
1245 XDefineCursor(ob_display
, RootWindow(ob_display
, ob_screen
),
1246 ob_cursor(OB_CURSOR_BUSY
));
1248 XDefineCursor(ob_display
, RootWindow(ob_display
, ob_screen
),
1249 ob_cursor(OB_CURSOR_POINTER
));
1252 gboolean
screen_pointer_pos(gint
*x
, gint
*y
)
1259 ret
= !!XQueryPointer(ob_display
, RootWindow(ob_display
, ob_screen
),
1260 &w
, &w
, x
, y
, &i
, &i
, &u
);
1262 for (i
= 0; i
< ScreenCount(ob_display
); ++i
)
1264 if (XQueryPointer(ob_display
, RootWindow(ob_display
, i
),
1265 &w
, &w
, x
, y
, &i
, &i
, &u
))