]> Dogcows Code - chaz/openbox/blob - openbox/screen.c
reset the pager popup's size after reconfigure
[chaz/openbox] / openbox / screen.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 screen.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
6
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.
11
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.
16
17 See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "debug.h"
21 #include "openbox.h"
22 #include "dock.h"
23 #include "xerror.h"
24 #include "prop.h"
25 #include "grab.h"
26 #include "startupnotify.h"
27 #include "moveresize.h"
28 #include "config.h"
29 #include "screen.h"
30 #include "client.h"
31 #include "session.h"
32 #include "frame.h"
33 #include "event.h"
34 #include "focus.h"
35 #include "popup.h"
36 #include "extensions.h"
37 #include "render/render.h"
38 #include "gettext.h"
39
40 #include <X11/Xlib.h>
41 #ifdef HAVE_UNISTD_H
42 # include <sys/types.h>
43 # include <unistd.h>
44 #endif
45 #include <assert.h>
46
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)
52
53 guint screen_num_desktops;
54 guint screen_num_monitors;
55 guint screen_desktop;
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;
63
64 static Rect **area; /* array of desktop holding array of xinerama areas */
65 static Rect *monitor_area;
66
67 static ObPagerPopup *desktop_cycle_popup;
68
69 static gboolean replace_wm()
70 {
71 gchar *wm_sn;
72 Atom wm_sn_atom;
73 Window current_wm_sn_owner;
74 Time timestamp;
75
76 wm_sn = g_strdup_printf("WM_S%d", ob_screen);
77 wm_sn_atom = XInternAtom(ob_display, wm_sn, FALSE);
78 g_free(wm_sn);
79
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) {
84 if (!ob_replace_wm) {
85 g_message(_("A window manager is already running on screen %d"),
86 ob_screen);
87 return FALSE;
88 }
89 xerror_set_ignore(TRUE);
90 xerror_occured = FALSE;
91
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);
95
96 xerror_set_ignore(FALSE);
97 if (xerror_occured)
98 current_wm_sn_owner = None;
99 }
100
101 {
102 /* Generate a timestamp */
103 XEvent event;
104
105 XSelectInput(ob_display, screen_support_win, PropertyChangeMask);
106
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);
112
113 XSelectInput(ob_display, screen_support_win, NoEventMask);
114
115 timestamp = event.xproperty.time;
116 }
117
118 XSetSelectionOwner(ob_display, wm_sn_atom, screen_support_win,
119 timestamp);
120
121 if (XGetSelectionOwner(ob_display, wm_sn_atom) != screen_support_win) {
122 g_message(_("Could not acquire window manager selection on screen %d"),
123 ob_screen);
124 return FALSE;
125 }
126
127 /* Wait for old window manager to go away */
128 if (current_wm_sn_owner) {
129 XEvent event;
130 gulong wait = 0;
131 const gulong timeout = G_USEC_PER_SEC * 15; /* wait for 15s max */
132
133 while (wait < timeout) {
134 if (XCheckWindowEvent(ob_display, current_wm_sn_owner,
135 StructureNotifyMask, &event) &&
136 event.type == DestroyNotify)
137 break;
138 g_usleep(G_USEC_PER_SEC / 10);
139 wait += G_USEC_PER_SEC / 10;
140 }
141
142 if (wait >= timeout) {
143 g_message(_("The WM on screen %d is not exiting"), ob_screen);
144 return FALSE;
145 }
146 }
147
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);
152
153 return TRUE;
154 }
155
156 gboolean screen_annex(const gchar *program_name)
157 {
158 XSetWindowAttributes attrib;
159 pid_t pid;
160 gint i, num_support;
161 Atom *prop_atoms_start, *wm_supported_pos;
162 gulong *supported;
163
164 /* create the netwm support window */
165 attrib.override_redirect = TRUE;
166 screen_support_win = XCreateWindow(ob_display,
167 RootWindow(ob_display, ob_screen),
168 -100, -100, 1, 1, 0,
169 CopyFromParent, InputOutput,
170 CopyFromParent,
171 CWOverrideRedirect, &attrib);
172 XMapWindow(ob_display, screen_support_win);
173 XLowerWindow(ob_display, screen_support_win);
174
175 if (!replace_wm()) {
176 XDestroyWindow(ob_display, screen_support_win);
177 return FALSE;
178 }
179
180 xerror_set_ignore(TRUE);
181 xerror_occured = FALSE;
182 XSelectInput(ob_display, RootWindow(ob_display, ob_screen),
183 ROOT_EVENTMASK);
184 xerror_set_ignore(FALSE);
185 if (xerror_occured) {
186 g_message(_("A window manager is already running on screen %d"),
187 ob_screen);
188
189 XDestroyWindow(ob_display, screen_support_win);
190 return FALSE;
191 }
192
193
194 screen_set_root_cursor();
195
196 /* set the OPENBOX_PID hint */
197 pid = getpid();
198 PROP_SET32(RootWindow(ob_display, ob_screen),
199 openbox_pid, cardinal, pid);
200
201 /* set supporting window */
202 PROP_SET32(RootWindow(ob_display, ob_screen),
203 net_supporting_wm_check, window, screen_support_win);
204
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);
209
210 /* set the _NET_SUPPORTED_ATOMS hint */
211
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;
217 i = 0;
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_action_above;
262 supported[i++] = prop_atoms.net_wm_action_below;
263 supported[i++] = prop_atoms.net_wm_state;
264 supported[i++] = prop_atoms.net_wm_state_modal;
265 supported[i++] = prop_atoms.net_wm_state_maximized_vert;
266 supported[i++] = prop_atoms.net_wm_state_maximized_horz;
267 supported[i++] = prop_atoms.net_wm_state_shaded;
268 supported[i++] = prop_atoms.net_wm_state_skip_taskbar;
269 supported[i++] = prop_atoms.net_wm_state_skip_pager;
270 supported[i++] = prop_atoms.net_wm_state_hidden;
271 supported[i++] = prop_atoms.net_wm_state_fullscreen;
272 supported[i++] = prop_atoms.net_wm_state_above;
273 supported[i++] = prop_atoms.net_wm_state_below;
274 supported[i++] = prop_atoms.net_wm_state_demands_attention;
275 supported[i++] = prop_atoms.net_moveresize_window;
276 supported[i++] = prop_atoms.net_wm_moveresize;
277 supported[i++] = prop_atoms.net_wm_user_time;
278 supported[i++] = prop_atoms.net_wm_user_time_window;
279 supported[i++] = prop_atoms.net_frame_extents;
280 supported[i++] = prop_atoms.net_request_frame_extents;
281 supported[i++] = prop_atoms.net_restack_window;
282 supported[i++] = prop_atoms.net_startup_id;
283 #ifdef SYNC
284 supported[i++] = prop_atoms.net_wm_sync_request;
285 supported[i++] = prop_atoms.net_wm_sync_request_counter;
286 #endif
287
288 supported[i++] = prop_atoms.kde_wm_change_state;
289 supported[i++] = prop_atoms.kde_net_wm_frame_strut;
290 supported[i++] = prop_atoms.kde_net_wm_window_type_override;
291
292 supported[i++] = prop_atoms.openbox_wm_state_undecorated;
293 supported[i++] = prop_atoms.openbox_pid;
294 supported[i++] = prop_atoms.openbox_config;
295 supported[i++] = prop_atoms.openbox_control;
296 g_assert(i == num_support);
297
298 PROP_SETA32(RootWindow(ob_display, ob_screen),
299 net_supported, atom, supported, num_support);
300 g_free(supported);
301
302 return TRUE;
303 }
304
305 void screen_startup(gboolean reconfig)
306 {
307 guint i, numnames;
308 gchar **names;
309 GSList *it;
310 guint32 d;
311
312 desktop_cycle_popup = pager_popup_new(FALSE);
313 pager_popup_height(desktop_cycle_popup, POPUP_HEIGHT);
314
315 if (reconfig) {
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);
320 return;
321 }
322
323 /* get the initial size */
324 screen_resize();
325
326 /* get the desktop names */
327 numnames = g_slist_length(config_desktops_names);
328 names = g_new(gchar*, numnames + 1);
329 names[numnames] = NULL;
330 for (i = 0, it = config_desktops_names; it; ++i, it = g_slist_next(it))
331 names[i] = g_strdup(it->data);
332
333 /* set the root window property */
334 PROP_SETSS(RootWindow(ob_display, ob_screen), net_desktop_names,names);
335
336 g_strfreev(names);
337
338 /* set the number of desktops */
339 screen_num_desktops = 0;
340 screen_set_num_desktops(config_desktops_num);
341
342 /* start on the current desktop when a wm was already running */
343 if (PROP_GET32(RootWindow(ob_display, ob_screen),
344 net_current_desktop, cardinal, &d) &&
345 d < screen_num_desktops)
346 {
347 screen_set_desktop(d, FALSE);
348 } else if (session_desktop >= 0)
349 screen_set_desktop(MIN((guint)session_desktop,
350 screen_num_desktops), FALSE);
351 else
352 screen_set_desktop(MIN(config_screen_firstdesk,
353 screen_num_desktops) - 1, FALSE);
354
355 /* don't start in showing-desktop mode */
356 screen_showing_desktop = FALSE;
357 PROP_SET32(RootWindow(ob_display, ob_screen),
358 net_showing_desktop, cardinal, screen_showing_desktop);
359
360 screen_update_layout();
361 }
362
363 void screen_shutdown(gboolean reconfig)
364 {
365 Rect **r;
366
367 pager_popup_free(desktop_cycle_popup);
368
369 if (reconfig)
370 return;
371
372 XSelectInput(ob_display, RootWindow(ob_display, ob_screen),
373 NoEventMask);
374
375 /* we're not running here no more! */
376 PROP_ERASE(RootWindow(ob_display, ob_screen), openbox_pid);
377 /* not without us */
378 PROP_ERASE(RootWindow(ob_display, ob_screen), net_supported);
379 /* don't keep this mode */
380 PROP_ERASE(RootWindow(ob_display, ob_screen), net_showing_desktop);
381
382 XDestroyWindow(ob_display, screen_support_win);
383
384 g_strfreev(screen_desktop_names);
385 screen_desktop_names = NULL;
386
387 for (r = area; *r; ++r)
388 g_free(*r);
389 g_free(area);
390 area = NULL;
391 }
392
393 void screen_resize()
394 {
395 static gint oldw = 0, oldh = 0;
396 gint w, h;
397 GList *it;
398 gulong geometry[2];
399
400 w = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen));
401 h = HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen));
402
403 if (w == oldw && h == oldh) return;
404
405 oldw = w; oldh = h;
406
407 /* Set the _NET_DESKTOP_GEOMETRY hint */
408 screen_physical_size.width = geometry[0] = w;
409 screen_physical_size.height = geometry[1] = h;
410 PROP_SETA32(RootWindow(ob_display, ob_screen),
411 net_desktop_geometry, cardinal, geometry, 2);
412
413 if (ob_state() == OB_STATE_STARTING)
414 return;
415
416 screen_update_areas();
417 dock_configure();
418
419 for (it = client_list; it; it = g_list_next(it))
420 client_move_onscreen(it->data, FALSE);
421 }
422
423 void screen_set_num_desktops(guint num)
424 {
425 guint old;
426 gulong *viewport;
427 GList *it;
428
429 g_assert(num > 0);
430
431 if (screen_num_desktops == num) return;
432
433 old = screen_num_desktops;
434 screen_num_desktops = num;
435 PROP_SET32(RootWindow(ob_display, ob_screen),
436 net_number_of_desktops, cardinal, num);
437
438 /* set the viewport hint */
439 viewport = g_new0(gulong, num * 2);
440 PROP_SETA32(RootWindow(ob_display, ob_screen),
441 net_desktop_viewport, cardinal, viewport, num * 2);
442 g_free(viewport);
443
444 /* the number of rows/columns will differ */
445 screen_update_layout();
446
447 /* move windows on desktops that will no longer exist! */
448 for (it = client_list; it; it = g_list_next(it)) {
449 ObClient *c = it->data;
450 if (c->desktop >= num && c->desktop != DESKTOP_ALL)
451 client_set_desktop(c, num - 1, FALSE);
452 }
453
454 /* change our struts/area to match (after moving windows) */
455 screen_update_areas();
456
457 /* may be some unnamed desktops that we need to fill in with names
458 (after updating the areas so the popup can resize) */
459 screen_update_desktop_names();
460
461 /* change our desktop if we're on one that no longer exists! */
462 if (screen_desktop >= screen_num_desktops)
463 screen_set_desktop(num - 1, TRUE);
464 }
465
466 void screen_set_desktop(guint num, gboolean dofocus)
467 {
468 ObClient *c;
469 GList *it;
470 guint old;
471
472 g_assert(num < screen_num_desktops);
473
474 old = screen_desktop;
475 screen_desktop = num;
476 PROP_SET32(RootWindow(ob_display, ob_screen),
477 net_current_desktop, cardinal, num);
478
479 if (old == num) return;
480
481 screen_last_desktop = old;
482
483 ob_debug("Moving to desktop %d\n", num+1);
484
485 if (moveresize_client)
486 client_set_desktop(moveresize_client, num, TRUE);
487
488 /* show windows before hiding the rest to lessen the enter/leave events */
489
490 /* show windows from top to bottom */
491 for (it = stacking_list; it; it = g_list_next(it)) {
492 if (WINDOW_IS_CLIENT(it->data)) {
493 ObClient *c = it->data;
494 client_show(c);
495 }
496 }
497
498 /* have to try focus here because when you leave an empty desktop
499 there is no focus out to watch for
500
501 do this before hiding the windows so if helper windows are coming
502 with us, they don't get hidden
503 */
504 if (dofocus && (c = focus_fallback(TRUE))) {
505 /* only do the flicker reducing stuff ahead of time if we are going
506 to call xsetinputfocus on the window ourselves. otherwise there is
507 no guarantee the window will actually take focus.. */
508 if (c->can_focus) {
509 /* do this here so that if you switch desktops to a window with
510 helper windows then the helper windows won't flash */
511 client_bring_helper_windows(c);
512 /* reduce flicker by hiliting now rather than waiting for the
513 server FocusIn event */
514 frame_adjust_focus(c->frame, TRUE);
515 }
516 }
517
518 /* hide windows from bottom to top */
519 for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
520 if (WINDOW_IS_CLIENT(it->data)) {
521 ObClient *c = it->data;
522 client_hide(c);
523 }
524 }
525
526 event_ignore_queued_enters();
527
528 if (event_curtime != CurrentTime)
529 screen_desktop_user_time = event_curtime;
530 }
531
532 static void get_row_col(guint d, guint *r, guint *c)
533 {
534 switch (screen_desktop_layout.orientation) {
535 case OB_ORIENTATION_HORZ:
536 switch (screen_desktop_layout.start_corner) {
537 case OB_CORNER_TOPLEFT:
538 *r = d / screen_desktop_layout.columns;
539 *c = d % screen_desktop_layout.columns;
540 break;
541 case OB_CORNER_BOTTOMLEFT:
542 *r = screen_desktop_layout.rows - 1 -
543 d / screen_desktop_layout.columns;
544 *c = d % screen_desktop_layout.columns;
545 break;
546 case OB_CORNER_TOPRIGHT:
547 *r = d / screen_desktop_layout.columns;
548 *c = screen_desktop_layout.columns - 1 -
549 d % screen_desktop_layout.columns;
550 break;
551 case OB_CORNER_BOTTOMRIGHT:
552 *r = screen_desktop_layout.rows - 1 -
553 d / screen_desktop_layout.columns;
554 *c = screen_desktop_layout.columns - 1 -
555 d % screen_desktop_layout.columns;
556 break;
557 }
558 break;
559 case OB_ORIENTATION_VERT:
560 switch (screen_desktop_layout.start_corner) {
561 case OB_CORNER_TOPLEFT:
562 *r = d % screen_desktop_layout.rows;
563 *c = d / screen_desktop_layout.rows;
564 break;
565 case OB_CORNER_BOTTOMLEFT:
566 *r = screen_desktop_layout.rows - 1 -
567 d % screen_desktop_layout.rows;
568 *c = d / screen_desktop_layout.rows;
569 break;
570 case OB_CORNER_TOPRIGHT:
571 *r = d % screen_desktop_layout.rows;
572 *c = screen_desktop_layout.columns - 1 -
573 d / screen_desktop_layout.rows;
574 break;
575 case OB_CORNER_BOTTOMRIGHT:
576 *r = screen_desktop_layout.rows - 1 -
577 d % screen_desktop_layout.rows;
578 *c = screen_desktop_layout.columns - 1 -
579 d / screen_desktop_layout.rows;
580 break;
581 }
582 break;
583 }
584 }
585
586 static guint translate_row_col(guint r, guint c)
587 {
588 switch (screen_desktop_layout.orientation) {
589 case OB_ORIENTATION_HORZ:
590 switch (screen_desktop_layout.start_corner) {
591 case OB_CORNER_TOPLEFT:
592 return r % screen_desktop_layout.rows *
593 screen_desktop_layout.columns +
594 c % screen_desktop_layout.columns;
595 case OB_CORNER_BOTTOMLEFT:
596 return (screen_desktop_layout.rows - 1 -
597 r % screen_desktop_layout.rows) *
598 screen_desktop_layout.columns +
599 c % screen_desktop_layout.columns;
600 case OB_CORNER_TOPRIGHT:
601 return r % screen_desktop_layout.rows *
602 screen_desktop_layout.columns +
603 (screen_desktop_layout.columns - 1 -
604 c % screen_desktop_layout.columns);
605 case OB_CORNER_BOTTOMRIGHT:
606 return (screen_desktop_layout.rows - 1 -
607 r % screen_desktop_layout.rows) *
608 screen_desktop_layout.columns +
609 (screen_desktop_layout.columns - 1 -
610 c % screen_desktop_layout.columns);
611 }
612 case OB_ORIENTATION_VERT:
613 switch (screen_desktop_layout.start_corner) {
614 case OB_CORNER_TOPLEFT:
615 return c % screen_desktop_layout.columns *
616 screen_desktop_layout.rows +
617 r % screen_desktop_layout.rows;
618 case OB_CORNER_BOTTOMLEFT:
619 return c % screen_desktop_layout.columns *
620 screen_desktop_layout.rows +
621 (screen_desktop_layout.rows - 1 -
622 r % screen_desktop_layout.rows);
623 case OB_CORNER_TOPRIGHT:
624 return (screen_desktop_layout.columns - 1 -
625 c % screen_desktop_layout.columns) *
626 screen_desktop_layout.rows +
627 r % screen_desktop_layout.rows;
628 case OB_CORNER_BOTTOMRIGHT:
629 return (screen_desktop_layout.columns - 1 -
630 c % screen_desktop_layout.columns) *
631 screen_desktop_layout.rows +
632 (screen_desktop_layout.rows - 1 -
633 r % screen_desktop_layout.rows);
634 }
635 }
636 g_assert_not_reached();
637 return 0;
638 }
639
640 void screen_desktop_popup(guint d, gboolean show)
641 {
642 Rect *a;
643
644 if (!show) {
645 pager_popup_hide(desktop_cycle_popup);
646 } else {
647 a = screen_physical_area_monitor(0);
648 pager_popup_position(desktop_cycle_popup, CenterGravity,
649 a->x + a->width / 2, a->y + a->height / 2);
650 pager_popup_icon_size_multiplier(desktop_cycle_popup,
651 (screen_desktop_layout.columns /
652 screen_desktop_layout.rows) / 2,
653 (screen_desktop_layout.rows/
654 screen_desktop_layout.columns) / 2);
655 pager_popup_max_width(desktop_cycle_popup,
656 MAX(a->width/3, POPUP_WIDTH));
657 pager_popup_show(desktop_cycle_popup, screen_desktop_names[d], d);
658 }
659 }
660
661 guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear,
662 gboolean dialog, gboolean done, gboolean cancel)
663 {
664 guint r, c;
665 static guint d = (guint)-1;
666 guint ret;
667
668 if (d == (guint)-1)
669 d = screen_desktop;
670
671 if ((cancel || done) && dialog)
672 goto show_cycle_dialog;
673
674 get_row_col(d, &r, &c);
675
676 if (linear) {
677 switch (dir) {
678 case OB_DIRECTION_EAST:
679 if (d < screen_num_desktops - 1)
680 ++d;
681 else if (wrap)
682 d = 0;
683 break;
684 case OB_DIRECTION_WEST:
685 if (d > 0)
686 --d;
687 else if (wrap)
688 d = screen_num_desktops - 1;
689 break;
690 default:
691 assert(0);
692 return screen_desktop;
693 }
694 } else {
695 switch (dir) {
696 case OB_DIRECTION_EAST:
697 ++c;
698 if (c >= screen_desktop_layout.columns) {
699 if (wrap) {
700 c = 0;
701 } else {
702 d = screen_desktop;
703 goto show_cycle_dialog;
704 }
705 }
706 d = translate_row_col(r, c);
707 if (d >= screen_num_desktops) {
708 if (wrap) {
709 ++c;
710 } else {
711 d = screen_desktop;
712 goto show_cycle_dialog;
713 }
714 }
715 break;
716 case OB_DIRECTION_WEST:
717 --c;
718 if (c >= screen_desktop_layout.columns) {
719 if (wrap) {
720 c = screen_desktop_layout.columns - 1;
721 } else {
722 d = screen_desktop;
723 goto show_cycle_dialog;
724 }
725 }
726 d = translate_row_col(r, c);
727 if (d >= screen_num_desktops) {
728 if (wrap) {
729 --c;
730 } else {
731 d = screen_desktop;
732 goto show_cycle_dialog;
733 }
734 }
735 break;
736 case OB_DIRECTION_SOUTH:
737 ++r;
738 if (r >= screen_desktop_layout.rows) {
739 if (wrap) {
740 r = 0;
741 } else {
742 d = screen_desktop;
743 goto show_cycle_dialog;
744 }
745 }
746 d = translate_row_col(r, c);
747 if (d >= screen_num_desktops) {
748 if (wrap) {
749 ++r;
750 } else {
751 d = screen_desktop;
752 goto show_cycle_dialog;
753 }
754 }
755 break;
756 case OB_DIRECTION_NORTH:
757 --r;
758 if (r >= screen_desktop_layout.rows) {
759 if (wrap) {
760 r = screen_desktop_layout.rows - 1;
761 } else {
762 d = screen_desktop;
763 goto show_cycle_dialog;
764 }
765 }
766 d = translate_row_col(r, c);
767 if (d >= screen_num_desktops) {
768 if (wrap) {
769 --r;
770 } else {
771 d = screen_desktop;
772 goto show_cycle_dialog;
773 }
774 }
775 break;
776 default:
777 assert(0);
778 return d = screen_desktop;
779 }
780
781 d = translate_row_col(r, c);
782 }
783
784 show_cycle_dialog:
785 if (dialog && !cancel && !done) {
786 screen_desktop_popup(d, TRUE);
787 } else
788 screen_desktop_popup(0, FALSE);
789 ret = d;
790
791 if (!dialog || cancel || done)
792 d = (guint)-1;
793
794 return ret;
795 }
796
797 void screen_update_layout()
798 {
799 ObOrientation orient;
800 ObCorner corner;
801 guint rows;
802 guint cols;
803 guint32 *data;
804 guint num;
805 gboolean valid = FALSE;
806
807 if (PROP_GETA32(RootWindow(ob_display, ob_screen),
808 net_desktop_layout, cardinal, &data, &num)) {
809 if (num == 3 || num == 4) {
810
811 if (data[0] == prop_atoms.net_wm_orientation_vert)
812 orient = OB_ORIENTATION_VERT;
813 else if (data[0] == prop_atoms.net_wm_orientation_horz)
814 orient = OB_ORIENTATION_HORZ;
815 else
816 goto screen_update_layout_bail;
817
818 if (num < 4)
819 corner = OB_CORNER_TOPLEFT;
820 else {
821 if (data[3] == prop_atoms.net_wm_topleft)
822 corner = OB_CORNER_TOPLEFT;
823 else if (data[3] == prop_atoms.net_wm_topright)
824 corner = OB_CORNER_TOPRIGHT;
825 else if (data[3] == prop_atoms.net_wm_bottomright)
826 corner = OB_CORNER_BOTTOMRIGHT;
827 else if (data[3] == prop_atoms.net_wm_bottomleft)
828 corner = OB_CORNER_BOTTOMLEFT;
829 else
830 goto screen_update_layout_bail;
831 }
832
833 cols = data[1];
834 rows = data[2];
835
836 /* fill in a zero rows/columns */
837 if ((cols == 0 && rows == 0)) { /* both 0's is bad data.. */
838 goto screen_update_layout_bail;
839 } else {
840 if (cols == 0) {
841 cols = screen_num_desktops / rows;
842 if (rows * cols < screen_num_desktops)
843 cols++;
844 if (rows * cols >= screen_num_desktops + cols)
845 rows--;
846 } else if (rows == 0) {
847 rows = screen_num_desktops / cols;
848 if (cols * rows < screen_num_desktops)
849 rows++;
850 if (cols * rows >= screen_num_desktops + rows)
851 cols--;
852 }
853 }
854
855 /* bounds checking */
856 if (orient == OB_ORIENTATION_HORZ) {
857 cols = MIN(screen_num_desktops, cols);
858 rows = MIN(rows, (screen_num_desktops + cols - 1) / cols);
859 cols = screen_num_desktops / rows +
860 !!(screen_num_desktops % rows);
861 } else {
862 rows = MIN(screen_num_desktops, rows);
863 cols = MIN(cols, (screen_num_desktops + rows - 1) / rows);
864 rows = screen_num_desktops / cols +
865 !!(screen_num_desktops % cols);
866 }
867
868 valid = TRUE;
869 }
870 screen_update_layout_bail:
871 g_free(data);
872 }
873
874 if (!valid) {
875 /* defaults */
876 orient = OB_ORIENTATION_HORZ;
877 corner = OB_CORNER_TOPLEFT;
878 rows = 1;
879 cols = screen_num_desktops;
880 }
881
882 screen_desktop_layout.orientation = orient;
883 screen_desktop_layout.start_corner = corner;
884 screen_desktop_layout.rows = rows;
885 screen_desktop_layout.columns = cols;
886 }
887
888 void screen_update_desktop_names()
889 {
890 guint i;
891
892 /* empty the array */
893 g_strfreev(screen_desktop_names);
894 screen_desktop_names = NULL;
895
896 if (PROP_GETSS(RootWindow(ob_display, ob_screen),
897 net_desktop_names, utf8, &screen_desktop_names))
898 for (i = 0; screen_desktop_names[i] && i < screen_num_desktops; ++i);
899 else
900 i = 0;
901 if (i < screen_num_desktops) {
902 screen_desktop_names = g_renew(gchar*, screen_desktop_names,
903 screen_num_desktops + 1);
904 screen_desktop_names[screen_num_desktops] = NULL;
905 for (; i < screen_num_desktops; ++i)
906 screen_desktop_names[i] = g_strdup_printf("desktop %i", i + 1);
907 }
908
909 /* resize the pager for these names */
910 pager_popup_text_width_to_strings(desktop_cycle_popup,
911 screen_desktop_names,
912 screen_num_desktops);
913 }
914
915 void screen_show_desktop(gboolean show, ObClient *show_only)
916 {
917 GList *it;
918
919 if (show == screen_showing_desktop) return; /* no change */
920
921 screen_showing_desktop = show;
922
923 if (show) {
924 /* hide windows bottom to top */
925 for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
926 if (WINDOW_IS_CLIENT(it->data)) {
927 ObClient *client = it->data;
928 client_showhide(client);
929 }
930 }
931 }
932 else {
933 /* restore windows top to bottom */
934 for (it = stacking_list; it; it = g_list_next(it)) {
935 if (WINDOW_IS_CLIENT(it->data)) {
936 ObClient *client = it->data;
937 if (client_should_show(client)) {
938 if (!show_only || client == show_only)
939 client_show(client);
940 else
941 client_iconify(client, TRUE, FALSE, TRUE);
942 }
943 }
944 }
945 }
946
947 if (show) {
948 /* focus the desktop */
949 for (it = focus_order; it; it = g_list_next(it)) {
950 ObClient *c = it->data;
951 if (c->type == OB_CLIENT_TYPE_DESKTOP &&
952 (c->desktop == screen_desktop || c->desktop == DESKTOP_ALL) &&
953 client_focus(it->data))
954 break;
955 }
956 }
957 else if (!show_only) {
958 ObClient *c;
959
960 if ((c = focus_fallback(TRUE))) {
961 /* only do the flicker reducing stuff ahead of time if we are going
962 to call xsetinputfocus on the window ourselves. otherwise there
963 is no guarantee the window will actually take focus.. */
964 if (c->can_focus) {
965 /* reduce flicker by hiliting now rather than waiting for the
966 server FocusIn event */
967 frame_adjust_focus(c->frame, TRUE);
968 }
969 }
970 }
971
972 show = !!show; /* make it boolean */
973 PROP_SET32(RootWindow(ob_display, ob_screen),
974 net_showing_desktop, cardinal, show);
975 }
976
977 void screen_install_colormap(ObClient *client, gboolean install)
978 {
979 if (client == NULL) {
980 if (install)
981 XInstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst));
982 else
983 XUninstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst));
984 } else {
985 xerror_set_ignore(TRUE);
986 if (install) {
987 if (client->colormap != None)
988 XInstallColormap(RrDisplay(ob_rr_inst), client->colormap);
989 } else
990 XUninstallColormap(RrDisplay(ob_rr_inst), client->colormap);
991 xerror_set_ignore(FALSE);
992 }
993 }
994
995 static inline void
996 screen_area_add_strut_left(const StrutPartial *s, const Rect *monitor_area,
997 gint edge, Strut *ret)
998 {
999 if (s->left &&
1000 ((s->left_end <= s->left_start) ||
1001 (RECT_TOP(*monitor_area) < s->left_end &&
1002 RECT_BOTTOM(*monitor_area) > s->left_start)))
1003 ret->left = MAX(ret->left, edge);
1004 }
1005
1006 static inline void
1007 screen_area_add_strut_top(const StrutPartial *s, const Rect *monitor_area,
1008 gint edge, Strut *ret)
1009 {
1010 if (s->top &&
1011 ((s->top_end <= s->top_start) ||
1012 (RECT_LEFT(*monitor_area) < s->top_end &&
1013 RECT_RIGHT(*monitor_area) > s->top_start)))
1014 ret->top = MAX(ret->top, edge);
1015 }
1016
1017 static inline void
1018 screen_area_add_strut_right(const StrutPartial *s, const Rect *monitor_area,
1019 gint edge, Strut *ret)
1020 {
1021 if (s->right &&
1022 ((s->right_end <= s->right_start) ||
1023 (RECT_TOP(*monitor_area) < s->right_end &&
1024 RECT_BOTTOM(*monitor_area) > s->right_start)))
1025 ret->right = MAX(ret->right, edge);
1026 }
1027
1028 static inline void
1029 screen_area_add_strut_bottom(const StrutPartial *s, const Rect *monitor_area,
1030 gint edge, Strut *ret)
1031 {
1032 if (s->bottom &&
1033 ((s->bottom_end <= s->bottom_start) ||
1034 (RECT_LEFT(*monitor_area) < s->bottom_end &&
1035 RECT_RIGHT(*monitor_area) > s->bottom_start)))
1036 ret->bottom = MAX(ret->bottom, edge);
1037 }
1038
1039 void screen_update_areas()
1040 {
1041 guint i, x;
1042 gulong *dims;
1043 GList *it;
1044 gint o;
1045
1046 g_free(monitor_area);
1047 extensions_xinerama_screens(&monitor_area, &screen_num_monitors);
1048
1049 if (area) {
1050 for (i = 0; area[i]; ++i)
1051 g_free(area[i]);
1052 g_free(area);
1053 }
1054
1055 area = g_new(Rect*, screen_num_desktops + 2);
1056 for (i = 0; i < screen_num_desktops + 1; ++i)
1057 area[i] = g_new0(Rect, screen_num_monitors + 1);
1058 area[i] = NULL;
1059
1060 dims = g_new(gulong, 4 * screen_num_desktops);
1061
1062 for (i = 0; i < screen_num_desktops + 1; ++i) {
1063 Strut *struts;
1064 gint l, r, t, b;
1065
1066 struts = g_new0(Strut, screen_num_monitors);
1067
1068 /* calc the xinerama areas */
1069 for (x = 0; x < screen_num_monitors; ++x) {
1070 area[i][x] = monitor_area[x];
1071 if (x == 0) {
1072 l = monitor_area[x].x;
1073 t = monitor_area[x].y;
1074 r = monitor_area[x].x + monitor_area[x].width - 1;
1075 b = monitor_area[x].y + monitor_area[x].height - 1;
1076 } else {
1077 l = MIN(l, monitor_area[x].x);
1078 t = MIN(t, monitor_area[x].y);
1079 r = MAX(r, monitor_area[x].x + monitor_area[x].width - 1);
1080 b = MAX(b, monitor_area[x].y + monitor_area[x].height - 1);
1081 }
1082 }
1083 RECT_SET(area[i][x], l, t, r - l + 1, b - t + 1);
1084
1085 /* apply the struts */
1086
1087 /* find the left-most xin heads, i do this in 2 loops :| */
1088 o = area[i][0].x;
1089 for (x = 1; x < screen_num_monitors; ++x)
1090 o = MIN(o, area[i][x].x);
1091
1092 for (x = 0; x < screen_num_monitors; ++x) {
1093 for (it = client_list; it; it = g_list_next(it)) {
1094 ObClient *c = it->data;
1095 screen_area_add_strut_left(&c->strut,
1096 &monitor_area[x],
1097 o + c->strut.left - area[i][x].x,
1098 &struts[x]);
1099 }
1100 screen_area_add_strut_left(&dock_strut,
1101 &monitor_area[x],
1102 o + dock_strut.left - area[i][x].x,
1103 &struts[x]);
1104
1105 area[i][x].x += struts[x].left;
1106 area[i][x].width -= struts[x].left;
1107 }
1108
1109 /* find the top-most xin heads, i do this in 2 loops :| */
1110 o = area[i][0].y;
1111 for (x = 1; x < screen_num_monitors; ++x)
1112 o = MIN(o, area[i][x].y);
1113
1114 for (x = 0; x < screen_num_monitors; ++x) {
1115 for (it = client_list; it; it = g_list_next(it)) {
1116 ObClient *c = it->data;
1117 screen_area_add_strut_top(&c->strut,
1118 &monitor_area[x],
1119 o + c->strut.top - area[i][x].y,
1120 &struts[x]);
1121 }
1122 screen_area_add_strut_top(&dock_strut,
1123 &monitor_area[x],
1124 o + dock_strut.top - area[i][x].y,
1125 &struts[x]);
1126
1127 area[i][x].y += struts[x].top;
1128 area[i][x].height -= struts[x].top;
1129 }
1130
1131 /* find the right-most xin heads, i do this in 2 loops :| */
1132 o = area[i][0].x + area[i][0].width - 1;
1133 for (x = 1; x < screen_num_monitors; ++x)
1134 o = MAX(o, area[i][x].x + area[i][x].width - 1);
1135
1136 for (x = 0; x < screen_num_monitors; ++x) {
1137 for (it = client_list; it; it = g_list_next(it)) {
1138 ObClient *c = it->data;
1139 screen_area_add_strut_right(&c->strut,
1140 &monitor_area[x],
1141 (area[i][x].x +
1142 area[i][x].width - 1) -
1143 (o - c->strut.right),
1144 &struts[x]);
1145 }
1146 screen_area_add_strut_right(&dock_strut,
1147 &monitor_area[x],
1148 (area[i][x].x +
1149 area[i][x].width - 1) -
1150 (o - dock_strut.right),
1151 &struts[x]);
1152
1153 area[i][x].width -= struts[x].right;
1154 }
1155
1156 /* find the bottom-most xin heads, i do this in 2 loops :| */
1157 o = area[i][0].y + area[i][0].height - 1;
1158 for (x = 1; x < screen_num_monitors; ++x)
1159 o = MAX(o, area[i][x].y + area[i][x].height - 1);
1160
1161 for (x = 0; x < screen_num_monitors; ++x) {
1162 for (it = client_list; it; it = g_list_next(it)) {
1163 ObClient *c = it->data;
1164 screen_area_add_strut_bottom(&c->strut,
1165 &monitor_area[x],
1166 (area[i][x].y +
1167 area[i][x].height - 1) - \
1168 (o - c->strut.bottom),
1169 &struts[x]);
1170 }
1171 screen_area_add_strut_bottom(&dock_strut,
1172 &monitor_area[x],
1173 (area[i][x].y +
1174 area[i][x].height - 1) - \
1175 (o - dock_strut.bottom),
1176 &struts[x]);
1177
1178 area[i][x].height -= struts[x].bottom;
1179 }
1180
1181 l = RECT_LEFT(area[i][0]);
1182 t = RECT_TOP(area[i][0]);
1183 r = RECT_RIGHT(area[i][0]);
1184 b = RECT_BOTTOM(area[i][0]);
1185 for (x = 1; x < screen_num_monitors; ++x) {
1186 l = MIN(l, RECT_LEFT(area[i][x]));
1187 t = MIN(l, RECT_TOP(area[i][x]));
1188 r = MAX(r, RECT_RIGHT(area[i][x]));
1189 b = MAX(b, RECT_BOTTOM(area[i][x]));
1190 }
1191 RECT_SET(area[i][screen_num_monitors], l, t,
1192 r - l + 1, b - t + 1);
1193
1194 /* XXX optimize when this is run? */
1195
1196 /* the area has changed, adjust all the maximized
1197 windows */
1198 for (it = client_list; it; it = g_list_next(it)) {
1199 ObClient *c = it->data;
1200 if (i < screen_num_desktops) {
1201 if (c->desktop == i)
1202 client_reconfigure(c);
1203 } else if (c->desktop == DESKTOP_ALL)
1204 client_reconfigure(c);
1205 }
1206 if (i < screen_num_desktops) {
1207 /* don't set these for the 'all desktops' area */
1208 dims[(i * 4) + 0] = area[i][screen_num_monitors].x;
1209 dims[(i * 4) + 1] = area[i][screen_num_monitors].y;
1210 dims[(i * 4) + 2] = area[i][screen_num_monitors].width;
1211 dims[(i * 4) + 3] = area[i][screen_num_monitors].height;
1212 }
1213
1214 g_free(struts);
1215 }
1216
1217 PROP_SETA32(RootWindow(ob_display, ob_screen), net_workarea, cardinal,
1218 dims, 4 * screen_num_desktops);
1219
1220 g_free(dims);
1221 }
1222
1223 Rect *screen_area(guint desktop)
1224 {
1225 return screen_area_monitor(desktop, screen_num_monitors);
1226 }
1227
1228 Rect *screen_area_monitor(guint desktop, guint head)
1229 {
1230 if (head > screen_num_monitors)
1231 return NULL;
1232 if (desktop >= screen_num_desktops) {
1233 if (desktop == DESKTOP_ALL)
1234 return &area[screen_num_desktops][head];
1235 return NULL;
1236 }
1237 return &area[desktop][head];
1238 }
1239
1240 guint screen_find_monitor(Rect *search)
1241 {
1242 guint i;
1243 guint most = 0;
1244 guint mostv = 0;
1245
1246 for (i = 0; i < screen_num_monitors; ++i) {
1247 Rect *area = screen_physical_area_monitor(i);
1248 if (RECT_INTERSECTS_RECT(*area, *search)) {
1249 Rect r;
1250 guint v;
1251
1252 RECT_SET_INTERSECTION(r, *area, *search);
1253 v = r.width * r.height;
1254
1255 if (v > mostv) {
1256 mostv = v;
1257 most = i;
1258 }
1259 }
1260 }
1261 return most;
1262 }
1263
1264 Rect *screen_physical_area()
1265 {
1266 return screen_physical_area_monitor(screen_num_monitors);
1267 }
1268
1269 Rect *screen_physical_area_monitor(guint head)
1270 {
1271 if (head > screen_num_monitors)
1272 return NULL;
1273 return &monitor_area[head];
1274 }
1275
1276 void screen_set_root_cursor()
1277 {
1278 if (sn_app_starting())
1279 XDefineCursor(ob_display, RootWindow(ob_display, ob_screen),
1280 ob_cursor(OB_CURSOR_BUSY));
1281 else
1282 XDefineCursor(ob_display, RootWindow(ob_display, ob_screen),
1283 ob_cursor(OB_CURSOR_POINTER));
1284 }
1285
1286 gboolean screen_pointer_pos(gint *x, gint *y)
1287 {
1288 Window w;
1289 gint i;
1290 guint u;
1291 gboolean ret;
1292
1293 ret = !!XQueryPointer(ob_display, RootWindow(ob_display, ob_screen),
1294 &w, &w, x, y, &i, &i, &u);
1295 if (!ret) {
1296 for (i = 0; i < ScreenCount(ob_display); ++i)
1297 if (i != ob_screen)
1298 if (XQueryPointer(ob_display, RootWindow(ob_display, i),
1299 &w, &w, x, y, &i, &i, &u))
1300 break;
1301 }
1302 return ret;
1303 }
This page took 0.090316 seconds and 5 git commands to generate.