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 ObDesktopLayout 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()
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
);
193 screen_set_root_cursor();
195 /* set the OPENBOX_PID hint */
197 PROP_SET32(RootWindow(ob_display
, ob_screen
),
198 openbox_pid
, cardinal
, pid
);
200 /* set supporting window */
201 PROP_SET32(RootWindow(ob_display
, ob_screen
),
202 net_supporting_wm_check
, window
, screen_support_win
);
204 /* set properties on the supporting window */
205 PROP_SETS(screen_support_win
, net_wm_name
, "Openbox");
206 PROP_SET32(screen_support_win
, net_supporting_wm_check
,
207 window
, screen_support_win
);
209 /* set the _NET_SUPPORTED_ATOMS hint */
211 /* this is all the atoms after net_supported in the prop_atoms struct */
212 prop_atoms_start
= (Atom
*)&prop_atoms
;
213 wm_supported_pos
= (Atom
*)&(prop_atoms
.net_supported
);
214 num_support
= sizeof(prop_atoms
) / sizeof(Atom
) -
215 (wm_supported_pos
- prop_atoms_start
) - 1;
217 supported
= g_new(gulong
, num_support
);
218 supported
[i
++] = prop_atoms
.net_supporting_wm_check
;
219 supported
[i
++] = prop_atoms
.net_wm_full_placement
;
220 supported
[i
++] = prop_atoms
.net_current_desktop
;
221 supported
[i
++] = prop_atoms
.net_number_of_desktops
;
222 supported
[i
++] = prop_atoms
.net_desktop_geometry
;
223 supported
[i
++] = prop_atoms
.net_desktop_viewport
;
224 supported
[i
++] = prop_atoms
.net_active_window
;
225 supported
[i
++] = prop_atoms
.net_workarea
;
226 supported
[i
++] = prop_atoms
.net_client_list
;
227 supported
[i
++] = prop_atoms
.net_client_list_stacking
;
228 supported
[i
++] = prop_atoms
.net_desktop_names
;
229 supported
[i
++] = prop_atoms
.net_close_window
;
230 supported
[i
++] = prop_atoms
.net_desktop_layout
;
231 supported
[i
++] = prop_atoms
.net_showing_desktop
;
232 supported
[i
++] = prop_atoms
.net_wm_name
;
233 supported
[i
++] = prop_atoms
.net_wm_visible_name
;
234 supported
[i
++] = prop_atoms
.net_wm_icon_name
;
235 supported
[i
++] = prop_atoms
.net_wm_visible_icon_name
;
236 supported
[i
++] = prop_atoms
.net_wm_desktop
;
237 supported
[i
++] = prop_atoms
.net_wm_strut
;
238 supported
[i
++] = prop_atoms
.net_wm_strut_partial
;
239 supported
[i
++] = prop_atoms
.net_wm_icon
;
240 supported
[i
++] = prop_atoms
.net_wm_icon_geometry
;
241 supported
[i
++] = prop_atoms
.net_wm_window_type
;
242 supported
[i
++] = prop_atoms
.net_wm_window_type_desktop
;
243 supported
[i
++] = prop_atoms
.net_wm_window_type_dock
;
244 supported
[i
++] = prop_atoms
.net_wm_window_type_toolbar
;
245 supported
[i
++] = prop_atoms
.net_wm_window_type_menu
;
246 supported
[i
++] = prop_atoms
.net_wm_window_type_utility
;
247 supported
[i
++] = prop_atoms
.net_wm_window_type_splash
;
248 supported
[i
++] = prop_atoms
.net_wm_window_type_dialog
;
249 supported
[i
++] = prop_atoms
.net_wm_window_type_normal
;
250 supported
[i
++] = prop_atoms
.net_wm_allowed_actions
;
251 supported
[i
++] = prop_atoms
.net_wm_action_move
;
252 supported
[i
++] = prop_atoms
.net_wm_action_resize
;
253 supported
[i
++] = prop_atoms
.net_wm_action_minimize
;
254 supported
[i
++] = prop_atoms
.net_wm_action_shade
;
255 supported
[i
++] = prop_atoms
.net_wm_action_maximize_horz
;
256 supported
[i
++] = prop_atoms
.net_wm_action_maximize_vert
;
257 supported
[i
++] = prop_atoms
.net_wm_action_fullscreen
;
258 supported
[i
++] = prop_atoms
.net_wm_action_change_desktop
;
259 supported
[i
++] = prop_atoms
.net_wm_action_close
;
260 supported
[i
++] = prop_atoms
.net_wm_action_above
;
261 supported
[i
++] = prop_atoms
.net_wm_action_below
;
262 supported
[i
++] = prop_atoms
.net_wm_state
;
263 supported
[i
++] = prop_atoms
.net_wm_state_modal
;
264 supported
[i
++] = prop_atoms
.net_wm_state_maximized_vert
;
265 supported
[i
++] = prop_atoms
.net_wm_state_maximized_horz
;
266 supported
[i
++] = prop_atoms
.net_wm_state_shaded
;
267 supported
[i
++] = prop_atoms
.net_wm_state_skip_taskbar
;
268 supported
[i
++] = prop_atoms
.net_wm_state_skip_pager
;
269 supported
[i
++] = prop_atoms
.net_wm_state_hidden
;
270 supported
[i
++] = prop_atoms
.net_wm_state_fullscreen
;
271 supported
[i
++] = prop_atoms
.net_wm_state_above
;
272 supported
[i
++] = prop_atoms
.net_wm_state_below
;
273 supported
[i
++] = prop_atoms
.net_wm_state_demands_attention
;
274 supported
[i
++] = prop_atoms
.net_moveresize_window
;
275 supported
[i
++] = prop_atoms
.net_wm_moveresize
;
276 supported
[i
++] = prop_atoms
.net_wm_user_time
;
277 supported
[i
++] = prop_atoms
.net_wm_user_time_window
;
278 supported
[i
++] = prop_atoms
.net_frame_extents
;
279 supported
[i
++] = prop_atoms
.net_request_frame_extents
;
280 supported
[i
++] = prop_atoms
.net_restack_window
;
281 supported
[i
++] = prop_atoms
.net_startup_id
;
283 supported
[i
++] = prop_atoms
.net_wm_sync_request
;
284 supported
[i
++] = prop_atoms
.net_wm_sync_request_counter
;
287 supported
[i
++] = prop_atoms
.kde_wm_change_state
;
288 supported
[i
++] = prop_atoms
.kde_net_wm_frame_strut
;
289 supported
[i
++] = prop_atoms
.kde_net_wm_window_type_override
;
291 supported
[i
++] = prop_atoms
.ob_wm_action_undecorate
;
292 supported
[i
++] = prop_atoms
.ob_wm_state_undecorated
;
293 supported
[i
++] = prop_atoms
.openbox_pid
;
294 supported
[i
++] = prop_atoms
.ob_config
;
295 supported
[i
++] = prop_atoms
.ob_control
;
296 g_assert(i
== num_support
);
298 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
299 net_supported
, atom
, supported
, num_support
);
305 void screen_startup(gboolean reconfig
)
309 GSList
*it
, *namelist
;
312 desktop_cycle_popup
= pager_popup_new(FALSE
);
313 pager_popup_height(desktop_cycle_popup
, POPUP_HEIGHT
);
316 /* update the pager popup's width */
317 pager_popup_text_width_to_strings(desktop_cycle_popup
,
318 screen_desktop_names
,
319 screen_num_desktops
);
323 /* get the initial size */
326 /* get the desktop names */
327 namelist
= session_desktop_names
?
328 session_desktop_names
: config_desktops_names
;
329 numnames
= g_slist_length(namelist
);
330 names
= g_new(gchar
*, numnames
+ 1);
331 names
[numnames
] = NULL
;
332 for (i
= 0, it
= namelist
; it
; ++i
, it
= g_slist_next(it
))
333 names
[i
] = g_strdup(it
->data
);
335 /* set the root window property */
336 PROP_SETSS(RootWindow(ob_display
, ob_screen
), net_desktop_names
,names
);
340 /* set the number of desktops */
341 screen_num_desktops
= 0;
342 if (session_num_desktops
)
343 screen_set_num_desktops(session_num_desktops
);
345 screen_set_num_desktops(config_desktops_num
);
347 /* start on the current desktop when a wm was already running */
348 if (PROP_GET32(RootWindow(ob_display
, ob_screen
),
349 net_current_desktop
, cardinal
, &d
) &&
350 d
< screen_num_desktops
)
352 screen_set_desktop(d
, FALSE
);
353 } else if (session_desktop
>= 0)
354 screen_set_desktop(MIN((guint
)session_desktop
,
355 screen_num_desktops
), FALSE
);
357 screen_set_desktop(MIN(config_screen_firstdesk
,
358 screen_num_desktops
) - 1, FALSE
);
360 /* don't start in showing-desktop mode */
361 screen_showing_desktop
= FALSE
;
362 PROP_SET32(RootWindow(ob_display
, ob_screen
),
363 net_showing_desktop
, cardinal
, screen_showing_desktop
);
365 if (session_desktop_layout_present
)
366 screen_desktop_layout
= session_desktop_layout
;
368 screen_update_layout();
371 void screen_shutdown(gboolean reconfig
)
375 pager_popup_free(desktop_cycle_popup
);
380 XSelectInput(ob_display
, RootWindow(ob_display
, ob_screen
),
383 /* we're not running here no more! */
384 PROP_ERASE(RootWindow(ob_display
, ob_screen
), openbox_pid
);
386 PROP_ERASE(RootWindow(ob_display
, ob_screen
), net_supported
);
387 /* don't keep this mode */
388 PROP_ERASE(RootWindow(ob_display
, ob_screen
), net_showing_desktop
);
390 XDestroyWindow(ob_display
, screen_support_win
);
392 g_strfreev(screen_desktop_names
);
393 screen_desktop_names
= NULL
;
395 for (r
= area
; *r
; ++r
)
403 static gint oldw
= 0, oldh
= 0;
408 w
= WidthOfScreen(ScreenOfDisplay(ob_display
, ob_screen
));
409 h
= HeightOfScreen(ScreenOfDisplay(ob_display
, ob_screen
));
411 if (w
== oldw
&& h
== oldh
) return;
415 /* Set the _NET_DESKTOP_GEOMETRY hint */
416 screen_physical_size
.width
= geometry
[0] = w
;
417 screen_physical_size
.height
= geometry
[1] = h
;
418 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
419 net_desktop_geometry
, cardinal
, geometry
, 2);
421 if (ob_state() == OB_STATE_STARTING
)
424 screen_update_areas();
427 for (it
= client_list
; it
; it
= g_list_next(it
))
428 client_move_onscreen(it
->data
, FALSE
);
431 void screen_set_num_desktops(guint num
)
439 if (screen_num_desktops
== num
) return;
441 old
= screen_num_desktops
;
442 screen_num_desktops
= num
;
443 PROP_SET32(RootWindow(ob_display
, ob_screen
),
444 net_number_of_desktops
, cardinal
, num
);
446 /* set the viewport hint */
447 viewport
= g_new0(gulong
, num
* 2);
448 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
449 net_desktop_viewport
, cardinal
, viewport
, num
* 2);
452 /* the number of rows/columns will differ */
453 screen_update_layout();
455 /* move windows on desktops that will no longer exist! */
456 for (it
= client_list
; it
; it
= g_list_next(it
)) {
457 ObClient
*c
= it
->data
;
458 if (c
->desktop
>= num
&& c
->desktop
!= DESKTOP_ALL
)
459 client_set_desktop(c
, num
- 1, FALSE
);
462 /* change our struts/area to match (after moving windows) */
463 screen_update_areas();
465 /* may be some unnamed desktops that we need to fill in with names
466 (after updating the areas so the popup can resize) */
467 screen_update_desktop_names();
469 /* change our desktop if we're on one that no longer exists! */
470 if (screen_desktop
>= screen_num_desktops
)
471 screen_set_desktop(num
- 1, TRUE
);
474 void screen_set_desktop(guint num
, gboolean dofocus
)
480 g_assert(num
< screen_num_desktops
);
482 old
= screen_desktop
;
483 screen_desktop
= num
;
484 PROP_SET32(RootWindow(ob_display
, ob_screen
),
485 net_current_desktop
, cardinal
, num
);
487 if (old
== num
) return;
489 screen_last_desktop
= old
;
491 ob_debug("Moving to desktop %d\n", num
+1);
493 if (moveresize_client
)
494 client_set_desktop(moveresize_client
, num
, TRUE
);
496 /* show windows before hiding the rest to lessen the enter/leave events */
498 /* show windows from top to bottom */
499 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
500 if (WINDOW_IS_CLIENT(it
->data
)) {
501 ObClient
*c
= it
->data
;
506 /* have to try focus here because when you leave an empty desktop
507 there is no focus out to watch for
509 do this before hiding the windows so if helper windows are coming
510 with us, they don't get hidden
512 if (dofocus
&& (c
= focus_fallback(TRUE
))) {
513 /* only do the flicker reducing stuff ahead of time if we are going
514 to call xsetinputfocus on the window ourselves. otherwise there is
515 no guarantee the window will actually take focus.. */
517 /* reduce flicker by hiliting now rather than waiting for the
518 server FocusIn event */
519 frame_adjust_focus(c
->frame
, TRUE
);
520 /* do this here so that if you switch desktops to a window with
521 helper windows then the helper windows won't flash */
522 client_bring_helper_windows(c
);
526 /* hide windows from bottom to top */
527 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
528 if (WINDOW_IS_CLIENT(it
->data
)) {
529 ObClient
*c
= it
->data
;
534 event_ignore_all_queued_enters();
536 if (event_curtime
!= CurrentTime
)
537 screen_desktop_user_time
= event_curtime
;
540 static void get_row_col(guint d
, guint
*r
, guint
*c
)
542 switch (screen_desktop_layout
.orientation
) {
543 case OB_ORIENTATION_HORZ
:
544 switch (screen_desktop_layout
.start_corner
) {
545 case OB_CORNER_TOPLEFT
:
546 *r
= d
/ screen_desktop_layout
.columns
;
547 *c
= d
% screen_desktop_layout
.columns
;
549 case OB_CORNER_BOTTOMLEFT
:
550 *r
= screen_desktop_layout
.rows
- 1 -
551 d
/ screen_desktop_layout
.columns
;
552 *c
= d
% screen_desktop_layout
.columns
;
554 case OB_CORNER_TOPRIGHT
:
555 *r
= d
/ screen_desktop_layout
.columns
;
556 *c
= screen_desktop_layout
.columns
- 1 -
557 d
% screen_desktop_layout
.columns
;
559 case OB_CORNER_BOTTOMRIGHT
:
560 *r
= screen_desktop_layout
.rows
- 1 -
561 d
/ screen_desktop_layout
.columns
;
562 *c
= screen_desktop_layout
.columns
- 1 -
563 d
% screen_desktop_layout
.columns
;
567 case OB_ORIENTATION_VERT
:
568 switch (screen_desktop_layout
.start_corner
) {
569 case OB_CORNER_TOPLEFT
:
570 *r
= d
% screen_desktop_layout
.rows
;
571 *c
= d
/ screen_desktop_layout
.rows
;
573 case OB_CORNER_BOTTOMLEFT
:
574 *r
= screen_desktop_layout
.rows
- 1 -
575 d
% screen_desktop_layout
.rows
;
576 *c
= d
/ screen_desktop_layout
.rows
;
578 case OB_CORNER_TOPRIGHT
:
579 *r
= d
% screen_desktop_layout
.rows
;
580 *c
= screen_desktop_layout
.columns
- 1 -
581 d
/ screen_desktop_layout
.rows
;
583 case OB_CORNER_BOTTOMRIGHT
:
584 *r
= screen_desktop_layout
.rows
- 1 -
585 d
% screen_desktop_layout
.rows
;
586 *c
= screen_desktop_layout
.columns
- 1 -
587 d
/ screen_desktop_layout
.rows
;
594 static guint
translate_row_col(guint r
, guint c
)
596 switch (screen_desktop_layout
.orientation
) {
597 case OB_ORIENTATION_HORZ
:
598 switch (screen_desktop_layout
.start_corner
) {
599 case OB_CORNER_TOPLEFT
:
600 return r
% screen_desktop_layout
.rows
*
601 screen_desktop_layout
.columns
+
602 c
% screen_desktop_layout
.columns
;
603 case OB_CORNER_BOTTOMLEFT
:
604 return (screen_desktop_layout
.rows
- 1 -
605 r
% screen_desktop_layout
.rows
) *
606 screen_desktop_layout
.columns
+
607 c
% screen_desktop_layout
.columns
;
608 case OB_CORNER_TOPRIGHT
:
609 return r
% screen_desktop_layout
.rows
*
610 screen_desktop_layout
.columns
+
611 (screen_desktop_layout
.columns
- 1 -
612 c
% screen_desktop_layout
.columns
);
613 case OB_CORNER_BOTTOMRIGHT
:
614 return (screen_desktop_layout
.rows
- 1 -
615 r
% screen_desktop_layout
.rows
) *
616 screen_desktop_layout
.columns
+
617 (screen_desktop_layout
.columns
- 1 -
618 c
% screen_desktop_layout
.columns
);
620 case OB_ORIENTATION_VERT
:
621 switch (screen_desktop_layout
.start_corner
) {
622 case OB_CORNER_TOPLEFT
:
623 return c
% screen_desktop_layout
.columns
*
624 screen_desktop_layout
.rows
+
625 r
% screen_desktop_layout
.rows
;
626 case OB_CORNER_BOTTOMLEFT
:
627 return c
% screen_desktop_layout
.columns
*
628 screen_desktop_layout
.rows
+
629 (screen_desktop_layout
.rows
- 1 -
630 r
% screen_desktop_layout
.rows
);
631 case OB_CORNER_TOPRIGHT
:
632 return (screen_desktop_layout
.columns
- 1 -
633 c
% screen_desktop_layout
.columns
) *
634 screen_desktop_layout
.rows
+
635 r
% screen_desktop_layout
.rows
;
636 case OB_CORNER_BOTTOMRIGHT
:
637 return (screen_desktop_layout
.columns
- 1 -
638 c
% screen_desktop_layout
.columns
) *
639 screen_desktop_layout
.rows
+
640 (screen_desktop_layout
.rows
- 1 -
641 r
% screen_desktop_layout
.rows
);
644 g_assert_not_reached();
648 void screen_desktop_popup(guint d
, gboolean show
)
653 pager_popup_hide(desktop_cycle_popup
);
655 a
= screen_physical_area_monitor(0);
656 pager_popup_position(desktop_cycle_popup
, CenterGravity
,
657 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
658 pager_popup_icon_size_multiplier(desktop_cycle_popup
,
659 (screen_desktop_layout
.columns
/
660 screen_desktop_layout
.rows
) / 2,
661 (screen_desktop_layout
.rows
/
662 screen_desktop_layout
.columns
) / 2);
663 pager_popup_max_width(desktop_cycle_popup
,
664 MAX(a
->width
/3, POPUP_WIDTH
));
665 pager_popup_show(desktop_cycle_popup
, screen_desktop_names
[d
], d
);
669 guint
screen_cycle_desktop(ObDirection dir
, gboolean wrap
, gboolean linear
,
670 gboolean dialog
, gboolean done
, gboolean cancel
)
673 static guint d
= (guint
)-1;
679 if ((cancel
|| done
) && dialog
)
680 goto show_cycle_dialog
;
683 get_row_col(d
, &r
, &c
);
687 case OB_DIRECTION_EAST
:
688 if (d
< screen_num_desktops
- 1)
693 case OB_DIRECTION_WEST
:
697 d
= screen_num_desktops
- 1;
701 return screen_desktop
;
705 case OB_DIRECTION_EAST
:
707 if (c
>= screen_desktop_layout
.columns
) {
711 goto show_cycle_dialog
;
713 d
= translate_row_col(r
, c
);
714 if (d
>= screen_num_desktops
) {
719 goto show_cycle_dialog
;
723 case OB_DIRECTION_WEST
:
725 if (c
>= screen_desktop_layout
.columns
) {
727 c
= screen_desktop_layout
.columns
- 1;
729 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_SOUTH
:
743 if (r
>= screen_desktop_layout
.rows
) {
747 goto show_cycle_dialog
;
749 d
= translate_row_col(r
, c
);
750 if (d
>= screen_num_desktops
) {
755 goto show_cycle_dialog
;
759 case OB_DIRECTION_NORTH
:
761 if (r
>= screen_desktop_layout
.rows
) {
763 r
= screen_desktop_layout
.rows
- 1;
765 goto show_cycle_dialog
;
767 d
= translate_row_col(r
, c
);
768 if (d
>= screen_num_desktops
) {
773 goto show_cycle_dialog
;
779 return d
= screen_desktop
;
782 d
= translate_row_col(r
, c
);
786 if (dialog
&& !cancel
&& !done
) {
787 screen_desktop_popup(d
, TRUE
);
789 screen_desktop_popup(0, FALSE
);
792 if (!dialog
|| cancel
|| done
)
798 void screen_update_layout()
800 ObOrientation orient
;
806 gboolean valid
= FALSE
;
808 if (PROP_GETA32(RootWindow(ob_display
, ob_screen
),
809 net_desktop_layout
, cardinal
, &data
, &num
)) {
810 if (num
== 3 || num
== 4) {
812 if (data
[0] == prop_atoms
.net_wm_orientation_vert
)
813 orient
= OB_ORIENTATION_VERT
;
814 else if (data
[0] == prop_atoms
.net_wm_orientation_horz
)
815 orient
= OB_ORIENTATION_HORZ
;
817 goto screen_update_layout_bail
;
820 corner
= OB_CORNER_TOPLEFT
;
822 if (data
[3] == prop_atoms
.net_wm_topleft
)
823 corner
= OB_CORNER_TOPLEFT
;
824 else if (data
[3] == prop_atoms
.net_wm_topright
)
825 corner
= OB_CORNER_TOPRIGHT
;
826 else if (data
[3] == prop_atoms
.net_wm_bottomright
)
827 corner
= OB_CORNER_BOTTOMRIGHT
;
828 else if (data
[3] == prop_atoms
.net_wm_bottomleft
)
829 corner
= OB_CORNER_BOTTOMLEFT
;
831 goto screen_update_layout_bail
;
837 /* fill in a zero rows/columns */
838 if ((cols
== 0 && rows
== 0)) { /* both 0's is bad data.. */
839 goto screen_update_layout_bail
;
842 cols
= screen_num_desktops
/ rows
;
843 if (rows
* cols
< screen_num_desktops
)
845 if (rows
* cols
>= screen_num_desktops
+ cols
)
847 } else if (rows
== 0) {
848 rows
= screen_num_desktops
/ cols
;
849 if (cols
* rows
< screen_num_desktops
)
851 if (cols
* rows
>= screen_num_desktops
+ rows
)
856 /* bounds checking */
857 if (orient
== OB_ORIENTATION_HORZ
) {
858 cols
= MIN(screen_num_desktops
, cols
);
859 rows
= MIN(rows
, (screen_num_desktops
+ cols
- 1) / cols
);
860 cols
= screen_num_desktops
/ rows
+
861 !!(screen_num_desktops
% rows
);
863 rows
= MIN(screen_num_desktops
, rows
);
864 cols
= MIN(cols
, (screen_num_desktops
+ rows
- 1) / rows
);
865 rows
= screen_num_desktops
/ cols
+
866 !!(screen_num_desktops
% cols
);
871 screen_update_layout_bail
:
877 orient
= OB_ORIENTATION_HORZ
;
878 corner
= OB_CORNER_TOPLEFT
;
880 cols
= screen_num_desktops
;
883 screen_desktop_layout
.orientation
= orient
;
884 screen_desktop_layout
.start_corner
= corner
;
885 screen_desktop_layout
.rows
= rows
;
886 screen_desktop_layout
.columns
= cols
;
889 void screen_update_desktop_names()
893 /* empty the array */
894 g_strfreev(screen_desktop_names
);
895 screen_desktop_names
= NULL
;
897 if (PROP_GETSS(RootWindow(ob_display
, ob_screen
),
898 net_desktop_names
, utf8
, &screen_desktop_names
))
899 for (i
= 0; screen_desktop_names
[i
] && i
< screen_num_desktops
; ++i
);
902 if (i
< screen_num_desktops
) {
903 screen_desktop_names
= g_renew(gchar
*, screen_desktop_names
,
904 screen_num_desktops
+ 1);
905 screen_desktop_names
[screen_num_desktops
] = NULL
;
906 for (; i
< screen_num_desktops
; ++i
)
907 screen_desktop_names
[i
] = g_strdup_printf("desktop %i", i
+ 1);
910 /* resize the pager for these names */
911 pager_popup_text_width_to_strings(desktop_cycle_popup
,
912 screen_desktop_names
,
913 screen_num_desktops
);
916 void screen_show_desktop(gboolean show
, ObClient
*show_only
)
920 if (show
== screen_showing_desktop
) return; /* no change */
922 screen_showing_desktop
= show
;
925 /* hide windows bottom to top */
926 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
927 if (WINDOW_IS_CLIENT(it
->data
)) {
928 ObClient
*client
= it
->data
;
929 client_showhide(client
);
934 /* restore windows top to bottom */
935 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
936 if (WINDOW_IS_CLIENT(it
->data
)) {
937 ObClient
*client
= it
->data
;
938 if (client_should_show(client
)) {
939 if (!show_only
|| client
== show_only
)
942 client_iconify(client
, TRUE
, FALSE
, TRUE
);
949 /* focus the desktop */
950 for (it
= focus_order
; it
; it
= g_list_next(it
)) {
951 ObClient
*c
= it
->data
;
952 if (c
->type
== OB_CLIENT_TYPE_DESKTOP
&&
953 (c
->desktop
== screen_desktop
|| c
->desktop
== DESKTOP_ALL
) &&
954 client_focus(it
->data
))
958 else if (!show_only
) {
961 if ((c
= focus_fallback(TRUE
))) {
962 /* only do the flicker reducing stuff ahead of time if we are going
963 to call xsetinputfocus on the window ourselves. otherwise there
964 is no guarantee the window will actually take focus.. */
966 /* reduce flicker by hiliting now rather than waiting for the
967 server FocusIn event */
968 frame_adjust_focus(c
->frame
, TRUE
);
973 show
= !!show
; /* make it boolean */
974 PROP_SET32(RootWindow(ob_display
, ob_screen
),
975 net_showing_desktop
, cardinal
, show
);
978 void screen_install_colormap(ObClient
*client
, gboolean install
)
980 if (client
== NULL
) {
982 XInstallColormap(RrDisplay(ob_rr_inst
), RrColormap(ob_rr_inst
));
984 XUninstallColormap(RrDisplay(ob_rr_inst
), RrColormap(ob_rr_inst
));
986 xerror_set_ignore(TRUE
);
988 if (client
->colormap
!= None
)
989 XInstallColormap(RrDisplay(ob_rr_inst
), client
->colormap
);
991 XUninstallColormap(RrDisplay(ob_rr_inst
), client
->colormap
);
992 xerror_set_ignore(FALSE
);
997 screen_area_add_strut_left(const StrutPartial
*s
, const Rect
*monitor_area
,
998 gint edge
, Strut
*ret
)
1001 ((s
->left_end
<= s
->left_start
) ||
1002 (RECT_TOP(*monitor_area
) < s
->left_end
&&
1003 RECT_BOTTOM(*monitor_area
) > s
->left_start
)))
1004 ret
->left
= MAX(ret
->left
, edge
);
1008 screen_area_add_strut_top(const StrutPartial
*s
, const Rect
*monitor_area
,
1009 gint edge
, Strut
*ret
)
1012 ((s
->top_end
<= s
->top_start
) ||
1013 (RECT_LEFT(*monitor_area
) < s
->top_end
&&
1014 RECT_RIGHT(*monitor_area
) > s
->top_start
)))
1015 ret
->top
= MAX(ret
->top
, edge
);
1019 screen_area_add_strut_right(const StrutPartial
*s
, const Rect
*monitor_area
,
1020 gint edge
, Strut
*ret
)
1023 ((s
->right_end
<= s
->right_start
) ||
1024 (RECT_TOP(*monitor_area
) < s
->right_end
&&
1025 RECT_BOTTOM(*monitor_area
) > s
->right_start
)))
1026 ret
->right
= MAX(ret
->right
, edge
);
1030 screen_area_add_strut_bottom(const StrutPartial
*s
, const Rect
*monitor_area
,
1031 gint edge
, Strut
*ret
)
1034 ((s
->bottom_end
<= s
->bottom_start
) ||
1035 (RECT_LEFT(*monitor_area
) < s
->bottom_end
&&
1036 RECT_RIGHT(*monitor_area
) > s
->bottom_start
)))
1037 ret
->bottom
= MAX(ret
->bottom
, edge
);
1040 void screen_update_areas()
1047 g_free(monitor_area
);
1048 extensions_xinerama_screens(&monitor_area
, &screen_num_monitors
);
1051 for (i
= 0; area
[i
]; ++i
)
1056 area
= g_new(Rect
*, screen_num_desktops
+ 2);
1057 for (i
= 0; i
< screen_num_desktops
+ 1; ++i
)
1058 area
[i
] = g_new0(Rect
, screen_num_monitors
+ 1);
1061 dims
= g_new(gulong
, 4 * screen_num_desktops
);
1063 for (i
= 0; i
< screen_num_desktops
+ 1; ++i
) {
1067 struts
= g_new0(Strut
, screen_num_monitors
);
1069 /* calc the xinerama areas */
1070 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1071 area
[i
][x
] = monitor_area
[x
];
1073 l
= monitor_area
[x
].x
;
1074 t
= monitor_area
[x
].y
;
1075 r
= monitor_area
[x
].x
+ monitor_area
[x
].width
- 1;
1076 b
= monitor_area
[x
].y
+ monitor_area
[x
].height
- 1;
1078 l
= MIN(l
, monitor_area
[x
].x
);
1079 t
= MIN(t
, monitor_area
[x
].y
);
1080 r
= MAX(r
, monitor_area
[x
].x
+ monitor_area
[x
].width
- 1);
1081 b
= MAX(b
, monitor_area
[x
].y
+ monitor_area
[x
].height
- 1);
1084 RECT_SET(area
[i
][x
], l
, t
, r
- l
+ 1, b
- t
+ 1);
1086 /* apply the struts */
1088 /* find the left-most xin heads, i do this in 2 loops :| */
1090 for (x
= 1; x
< screen_num_monitors
; ++x
)
1091 o
= MIN(o
, area
[i
][x
].x
);
1093 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1094 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1095 ObClient
*c
= it
->data
;
1096 screen_area_add_strut_left(&c
->strut
,
1098 o
+ c
->strut
.left
- area
[i
][x
].x
,
1101 screen_area_add_strut_left(&dock_strut
,
1103 o
+ dock_strut
.left
- area
[i
][x
].x
,
1106 area
[i
][x
].x
+= struts
[x
].left
;
1107 area
[i
][x
].width
-= struts
[x
].left
;
1110 /* find the top-most xin heads, i do this in 2 loops :| */
1112 for (x
= 1; x
< screen_num_monitors
; ++x
)
1113 o
= MIN(o
, area
[i
][x
].y
);
1115 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1116 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1117 ObClient
*c
= it
->data
;
1118 screen_area_add_strut_top(&c
->strut
,
1120 o
+ c
->strut
.top
- area
[i
][x
].y
,
1123 screen_area_add_strut_top(&dock_strut
,
1125 o
+ dock_strut
.top
- area
[i
][x
].y
,
1128 area
[i
][x
].y
+= struts
[x
].top
;
1129 area
[i
][x
].height
-= struts
[x
].top
;
1132 /* find the right-most xin heads, i do this in 2 loops :| */
1133 o
= area
[i
][0].x
+ area
[i
][0].width
- 1;
1134 for (x
= 1; x
< screen_num_monitors
; ++x
)
1135 o
= MAX(o
, area
[i
][x
].x
+ area
[i
][x
].width
- 1);
1137 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1138 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1139 ObClient
*c
= it
->data
;
1140 screen_area_add_strut_right(&c
->strut
,
1143 area
[i
][x
].width
- 1) -
1144 (o
- c
->strut
.right
),
1147 screen_area_add_strut_right(&dock_strut
,
1150 area
[i
][x
].width
- 1) -
1151 (o
- dock_strut
.right
),
1154 area
[i
][x
].width
-= struts
[x
].right
;
1157 /* find the bottom-most xin heads, i do this in 2 loops :| */
1158 o
= area
[i
][0].y
+ area
[i
][0].height
- 1;
1159 for (x
= 1; x
< screen_num_monitors
; ++x
)
1160 o
= MAX(o
, area
[i
][x
].y
+ area
[i
][x
].height
- 1);
1162 for (x
= 0; x
< screen_num_monitors
; ++x
) {
1163 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1164 ObClient
*c
= it
->data
;
1165 screen_area_add_strut_bottom(&c
->strut
,
1168 area
[i
][x
].height
- 1) - \
1169 (o
- c
->strut
.bottom
),
1172 screen_area_add_strut_bottom(&dock_strut
,
1175 area
[i
][x
].height
- 1) - \
1176 (o
- dock_strut
.bottom
),
1179 area
[i
][x
].height
-= struts
[x
].bottom
;
1182 l
= RECT_LEFT(area
[i
][0]);
1183 t
= RECT_TOP(area
[i
][0]);
1184 r
= RECT_RIGHT(area
[i
][0]);
1185 b
= RECT_BOTTOM(area
[i
][0]);
1186 for (x
= 1; x
< screen_num_monitors
; ++x
) {
1187 l
= MIN(l
, RECT_LEFT(area
[i
][x
]));
1188 t
= MIN(l
, RECT_TOP(area
[i
][x
]));
1189 r
= MAX(r
, RECT_RIGHT(area
[i
][x
]));
1190 b
= MAX(b
, RECT_BOTTOM(area
[i
][x
]));
1192 RECT_SET(area
[i
][screen_num_monitors
], l
, t
,
1193 r
- l
+ 1, b
- t
+ 1);
1195 /* XXX optimize when this is run? */
1197 /* the area has changed, adjust all the maximized
1199 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1200 ObClient
*c
= it
->data
;
1201 if (i
< screen_num_desktops
) {
1202 if (c
->desktop
== i
)
1203 client_reconfigure(c
);
1204 } else if (c
->desktop
== DESKTOP_ALL
)
1205 client_reconfigure(c
);
1207 if (i
< screen_num_desktops
) {
1208 /* don't set these for the 'all desktops' area */
1209 dims
[(i
* 4) + 0] = area
[i
][screen_num_monitors
].x
;
1210 dims
[(i
* 4) + 1] = area
[i
][screen_num_monitors
].y
;
1211 dims
[(i
* 4) + 2] = area
[i
][screen_num_monitors
].width
;
1212 dims
[(i
* 4) + 3] = area
[i
][screen_num_monitors
].height
;
1218 PROP_SETA32(RootWindow(ob_display
, ob_screen
), net_workarea
, cardinal
,
1219 dims
, 4 * screen_num_desktops
);
1224 Rect
*screen_area(guint desktop
)
1226 return screen_area_monitor(desktop
, screen_num_monitors
);
1229 Rect
*screen_area_monitor(guint desktop
, guint head
)
1231 if (head
> screen_num_monitors
)
1233 if (desktop
>= screen_num_desktops
) {
1234 if (desktop
== DESKTOP_ALL
)
1235 return &area
[screen_num_desktops
][head
];
1238 return &area
[desktop
][head
];
1241 guint
screen_find_monitor(Rect
*search
)
1247 for (i
= 0; i
< screen_num_monitors
; ++i
) {
1248 Rect
*area
= screen_physical_area_monitor(i
);
1249 if (RECT_INTERSECTS_RECT(*area
, *search
)) {
1253 RECT_SET_INTERSECTION(r
, *area
, *search
);
1254 v
= r
.width
* r
.height
;
1265 Rect
*screen_physical_area()
1267 return screen_physical_area_monitor(screen_num_monitors
);
1270 Rect
*screen_physical_area_monitor(guint head
)
1272 if (head
> screen_num_monitors
)
1274 return &monitor_area
[head
];
1277 void screen_set_root_cursor()
1279 if (sn_app_starting())
1280 XDefineCursor(ob_display
, RootWindow(ob_display
, ob_screen
),
1281 ob_cursor(OB_CURSOR_BUSYPOINTER
));
1283 XDefineCursor(ob_display
, RootWindow(ob_display
, ob_screen
),
1284 ob_cursor(OB_CURSOR_POINTER
));
1287 gboolean
screen_pointer_pos(gint
*x
, gint
*y
)
1294 ret
= !!XQueryPointer(ob_display
, RootWindow(ob_display
, ob_screen
),
1295 &w
, &w
, x
, y
, &i
, &i
, &u
);
1297 for (i
= 0; i
< ScreenCount(ob_display
); ++i
)
1299 if (XQueryPointer(ob_display
, RootWindow(ob_display
, i
),
1300 &w
, &w
, x
, y
, &i
, &i
, &u
))