~ubuntu-branches/ubuntu/saucy/openbox/saucy-proposed

« back to all changes in this revision

Viewing changes to .pc/clever-rectangle-picking.patch/openbox/screen.c

  • Committer: Package Import Robot
  • Author(s): Julien Lavergne
  • Date: 2013-08-29 00:47:27 UTC
  • mfrom: (1.1.12)
  • Revision ID: package-import@ubuntu.com-20130829004727-isarfdp00eoloeeq
Tags: 3.5.2-0ubuntu1
* New upstream release. 
* debian/control & debian/*.install:
 - Update SONAME number.
* debian/*.symbols:
 - Update.
* debian/patches:
 - 04_xsession.desktop_translation.patch: Refresh.
 - 01_rc.xml.patch: Refresh.
 - 05_simplify_gnome_session.patch: Refresh.
 - 07_fix_xml_load_file.patch: Refresh.
 - 90_fix_link_obt.patch: Remove, merged upstream.
 - 675991_fix_crash_from_gtk3_apps.patch: Remove, merged upstream.
 - 666676_wrong_undecorated_window_placement.patch: Remove, merged upstream.
 - clever-rectangle-picking.patch: Remove, merged upstream.
 - use-nearest-monitor.patch: Remove, merged upstream.
 - 704724_fix_refers-to-autostart.sh.patch: Remove, merged upstream.
 - 91_fix_loose_focus.patch: Remove, merged upstream.
 - openbox-3.5.0-title-matching.patch: Refresh.
 - openbox-3.5.0-which-2.20.patch: Refresh.
 - 658081_fix_kde_menu.patch: Remove, merged upstream.
 - add_automake1.11_support.patch: Remove, merged upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 "grab.h"
24
 
#include "startupnotify.h"
25
 
#include "moveresize.h"
26
 
#include "config.h"
27
 
#include "screen.h"
28
 
#include "client.h"
29
 
#include "session.h"
30
 
#include "frame.h"
31
 
#include "event.h"
32
 
#include "focus.h"
33
 
#include "focus_cycle.h"
34
 
#include "popup.h"
35
 
#include "version.h"
36
 
#include "obrender/render.h"
37
 
#include "gettext.h"
38
 
#include "obt/display.h"
39
 
#include "obt/xqueue.h"
40
 
#include "obt/prop.h"
41
 
 
42
 
#include <X11/Xlib.h>
43
 
#ifdef HAVE_UNISTD_H
44
 
#  include <sys/types.h>
45
 
#  include <unistd.h>
46
 
#endif
47
 
#include <assert.h>
48
 
 
49
 
/*! The event mask to grab on the root window */
50
 
#define ROOT_EVENTMASK (StructureNotifyMask | PropertyChangeMask | \
51
 
                        EnterWindowMask | LeaveWindowMask | \
52
 
                        SubstructureRedirectMask | FocusChangeMask | \
53
 
                        ButtonPressMask | ButtonReleaseMask)
54
 
 
55
 
static gboolean screen_validate_layout(ObDesktopLayout *l);
56
 
static gboolean replace_wm(void);
57
 
static void     screen_tell_ksplash(void);
58
 
static void     screen_fallback_focus(void);
59
 
 
60
 
guint           screen_num_desktops;
61
 
guint           screen_num_monitors;
62
 
guint           screen_desktop;
63
 
guint           screen_last_desktop;
64
 
gboolean        screen_showing_desktop;
65
 
ObDesktopLayout screen_desktop_layout;
66
 
gchar         **screen_desktop_names;
67
 
Window          screen_support_win;
68
 
Time            screen_desktop_user_time = CurrentTime;
69
 
 
70
 
static Size     screen_physical_size;
71
 
static guint    screen_old_desktop;
72
 
static gboolean screen_desktop_timeout = TRUE;
73
 
static guint    screen_desktop_timer = 0;
74
 
/*! An array of desktops, holding an array of areas per monitor */
75
 
static Rect  *monitor_area = NULL;
76
 
/*! An array of desktops, holding an array of struts */
77
 
static GSList *struts_top = NULL;
78
 
static GSList *struts_left = NULL;
79
 
static GSList *struts_right = NULL;
80
 
static GSList *struts_bottom = NULL;
81
 
 
82
 
static ObPagerPopup *desktop_popup;
83
 
static guint         desktop_popup_timer = 0;
84
 
static gboolean      desktop_popup_perm;
85
 
 
86
 
/*! The number of microseconds that you need to be on a desktop before it will
87
 
  replace the remembered "last desktop" */
88
 
#define REMEMBER_LAST_DESKTOP_TIME 750
89
 
 
90
 
static gboolean replace_wm(void)
91
 
{
92
 
    gchar *wm_sn;
93
 
    Atom wm_sn_atom;
94
 
    Window current_wm_sn_owner;
95
 
    Time timestamp;
96
 
 
97
 
    wm_sn = g_strdup_printf("WM_S%d", ob_screen);
98
 
    wm_sn_atom = XInternAtom(obt_display, wm_sn, FALSE);
99
 
    g_free(wm_sn);
100
 
 
101
 
    current_wm_sn_owner = XGetSelectionOwner(obt_display, wm_sn_atom);
102
 
    if (current_wm_sn_owner == screen_support_win)
103
 
        current_wm_sn_owner = None;
104
 
    if (current_wm_sn_owner) {
105
 
        if (!ob_replace_wm) {
106
 
            g_message(_("A window manager is already running on screen %d"),
107
 
                      ob_screen);
108
 
            return FALSE;
109
 
        }
110
 
        obt_display_ignore_errors(TRUE);
111
 
 
112
 
        /* We want to find out when the current selection owner dies */
113
 
        XSelectInput(obt_display, current_wm_sn_owner, StructureNotifyMask);
114
 
        XSync(obt_display, FALSE);
115
 
 
116
 
        obt_display_ignore_errors(FALSE);
117
 
        if (obt_display_error_occured)
118
 
            current_wm_sn_owner = None;
119
 
    }
120
 
 
121
 
    timestamp = event_time();
122
 
 
123
 
    XSetSelectionOwner(obt_display, wm_sn_atom, screen_support_win,
124
 
                       timestamp);
125
 
 
126
 
    if (XGetSelectionOwner(obt_display, wm_sn_atom) != screen_support_win) {
127
 
        g_message(_("Could not acquire window manager selection on screen %d"),
128
 
                  ob_screen);
129
 
        return FALSE;
130
 
    }
131
 
 
132
 
    /* Wait for old window manager to go away */
133
 
    if (current_wm_sn_owner) {
134
 
      gulong wait = 0;
135
 
      const gulong timeout = G_USEC_PER_SEC * 15; /* wait for 15s max */
136
 
      ObtXQueueWindowType wt;
137
 
 
138
 
      wt.window = current_wm_sn_owner;
139
 
      wt.type = DestroyNotify;
140
 
 
141
 
      while (wait < timeout) {
142
 
          /* Checks the local queue and incoming events for this event */
143
 
          if (xqueue_exists_local(xqueue_match_window_type, &wt))
144
 
              break;
145
 
          g_usleep(G_USEC_PER_SEC / 10);
146
 
          wait += G_USEC_PER_SEC / 10;
147
 
      }
148
 
 
149
 
      if (wait >= timeout) {
150
 
          g_message(_("The WM on screen %d is not exiting"), ob_screen);
151
 
          return FALSE;
152
 
      }
153
 
    }
154
 
 
155
 
    /* Send client message indicating that we are now the WM */
156
 
    obt_prop_message(ob_screen, obt_root(ob_screen), OBT_PROP_ATOM(MANAGER),
157
 
                     timestamp, wm_sn_atom, screen_support_win, 0, 0,
158
 
                     SubstructureNotifyMask);
159
 
 
160
 
    return TRUE;
161
 
}
162
 
 
163
 
gboolean screen_annex(void)
164
 
{
165
 
    XSetWindowAttributes attrib;
166
 
    pid_t pid;
167
 
    gint i, num_support;
168
 
    gulong *supported;
169
 
 
170
 
    /* create the netwm support window */
171
 
    attrib.override_redirect = TRUE;
172
 
    attrib.event_mask = PropertyChangeMask;
173
 
    screen_support_win = XCreateWindow(obt_display, obt_root(ob_screen),
174
 
                                       -100, -100, 1, 1, 0,
175
 
                                       CopyFromParent, InputOutput,
176
 
                                       CopyFromParent,
177
 
                                       CWEventMask | CWOverrideRedirect,
178
 
                                       &attrib);
179
 
    XMapWindow(obt_display, screen_support_win);
180
 
    XLowerWindow(obt_display, screen_support_win);
181
 
 
182
 
    if (!replace_wm()) {
183
 
        XDestroyWindow(obt_display, screen_support_win);
184
 
        return FALSE;
185
 
    }
186
 
 
187
 
    obt_display_ignore_errors(TRUE);
188
 
    XSelectInput(obt_display, obt_root(ob_screen), ROOT_EVENTMASK);
189
 
    obt_display_ignore_errors(FALSE);
190
 
    if (obt_display_error_occured) {
191
 
        g_message(_("A window manager is already running on screen %d"),
192
 
                  ob_screen);
193
 
 
194
 
        XDestroyWindow(obt_display, screen_support_win);
195
 
        return FALSE;
196
 
    }
197
 
 
198
 
    screen_set_root_cursor();
199
 
 
200
 
    /* set the OPENBOX_PID hint */
201
 
    pid = getpid();
202
 
    OBT_PROP_SET32(obt_root(ob_screen), OPENBOX_PID, CARDINAL, pid);
203
 
 
204
 
    /* set supporting window */
205
 
    OBT_PROP_SET32(obt_root(ob_screen),
206
 
                   NET_SUPPORTING_WM_CHECK, WINDOW, screen_support_win);
207
 
 
208
 
    /* set properties on the supporting window */
209
 
    OBT_PROP_SETS(screen_support_win, NET_WM_NAME, "Openbox");
210
 
    OBT_PROP_SET32(screen_support_win, NET_SUPPORTING_WM_CHECK,
211
 
                   WINDOW, screen_support_win);
212
 
 
213
 
    /* set the _NET_SUPPORTED_ATOMS hint */
214
 
 
215
 
    /* this is all the atoms after NET_SUPPORTED in the ObtPropAtoms enum */
216
 
    num_support = OBT_PROP_NUM_ATOMS - OBT_PROP_NET_SUPPORTED - 1;
217
 
    i = 0;
218
 
    supported = g_new(gulong, num_support);
219
 
    supported[i++] = OBT_PROP_ATOM(NET_SUPPORTING_WM_CHECK);
220
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_FULL_PLACEMENT);
221
 
    supported[i++] = OBT_PROP_ATOM(NET_CURRENT_DESKTOP);
222
 
    supported[i++] = OBT_PROP_ATOM(NET_NUMBER_OF_DESKTOPS);
223
 
    supported[i++] = OBT_PROP_ATOM(NET_DESKTOP_GEOMETRY);
224
 
    supported[i++] = OBT_PROP_ATOM(NET_DESKTOP_VIEWPORT);
225
 
    supported[i++] = OBT_PROP_ATOM(NET_ACTIVE_WINDOW);
226
 
    supported[i++] = OBT_PROP_ATOM(NET_WORKAREA);
227
 
    supported[i++] = OBT_PROP_ATOM(NET_CLIENT_LIST);
228
 
    supported[i++] = OBT_PROP_ATOM(NET_CLIENT_LIST_STACKING);
229
 
    supported[i++] = OBT_PROP_ATOM(NET_DESKTOP_NAMES);
230
 
    supported[i++] = OBT_PROP_ATOM(NET_CLOSE_WINDOW);
231
 
    supported[i++] = OBT_PROP_ATOM(NET_DESKTOP_LAYOUT);
232
 
    supported[i++] = OBT_PROP_ATOM(NET_SHOWING_DESKTOP);
233
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_NAME);
234
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_VISIBLE_NAME);
235
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ICON_NAME);
236
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_VISIBLE_ICON_NAME);
237
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_DESKTOP);
238
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STRUT);
239
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STRUT_PARTIAL);
240
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ICON);
241
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ICON_GEOMETRY);
242
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE);
243
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DESKTOP);
244
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DOCK);
245
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_TOOLBAR);
246
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_MENU);
247
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_UTILITY);
248
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_SPLASH);
249
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DIALOG);
250
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_NORMAL);
251
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ALLOWED_ACTIONS);
252
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MOVE);
253
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_RESIZE);
254
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MINIMIZE);
255
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_SHADE);
256
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MAXIMIZE_HORZ);
257
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MAXIMIZE_VERT);
258
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_FULLSCREEN);
259
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_CHANGE_DESKTOP);
260
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_CLOSE);
261
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_ABOVE);
262
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_BELOW);
263
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE);
264
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_MODAL);
265
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT);
266
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ);
267
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_SHADED);
268
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR);
269
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER);
270
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_HIDDEN);
271
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN);
272
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_ABOVE);
273
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_BELOW);
274
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION);
275
 
    supported[i++] = OBT_PROP_ATOM(NET_MOVERESIZE_WINDOW);
276
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_MOVERESIZE);
277
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_USER_TIME);
278
 
/*
279
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_USER_TIME_WINDOW);
280
 
*/
281
 
    supported[i++] = OBT_PROP_ATOM(NET_FRAME_EXTENTS);
282
 
    supported[i++] = OBT_PROP_ATOM(NET_REQUEST_FRAME_EXTENTS);
283
 
    supported[i++] = OBT_PROP_ATOM(NET_RESTACK_WINDOW);
284
 
    supported[i++] = OBT_PROP_ATOM(NET_STARTUP_ID);
285
 
#ifdef SYNC
286
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST);
287
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST_COUNTER);
288
 
#endif
289
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_PID);
290
 
    supported[i++] = OBT_PROP_ATOM(NET_WM_PING);
291
 
 
292
 
    supported[i++] = OBT_PROP_ATOM(KDE_WM_CHANGE_STATE);
293
 
    supported[i++] = OBT_PROP_ATOM(KDE_NET_WM_FRAME_STRUT);
294
 
    supported[i++] = OBT_PROP_ATOM(KDE_NET_WM_WINDOW_TYPE_OVERRIDE);
295
 
 
296
 
    supported[i++] = OBT_PROP_ATOM(OB_WM_ACTION_UNDECORATE);
297
 
    supported[i++] = OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED);
298
 
    supported[i++] = OBT_PROP_ATOM(OPENBOX_PID);
299
 
    supported[i++] = OBT_PROP_ATOM(OB_THEME);
300
 
    supported[i++] = OBT_PROP_ATOM(OB_CONFIG_FILE);
301
 
    supported[i++] = OBT_PROP_ATOM(OB_CONTROL);
302
 
    supported[i++] = OBT_PROP_ATOM(OB_VERSION);
303
 
    supported[i++] = OBT_PROP_ATOM(OB_APP_ROLE);
304
 
    supported[i++] = OBT_PROP_ATOM(OB_APP_TITLE);
305
 
    supported[i++] = OBT_PROP_ATOM(OB_APP_NAME);
306
 
    supported[i++] = OBT_PROP_ATOM(OB_APP_CLASS);
307
 
    supported[i++] = OBT_PROP_ATOM(OB_APP_TYPE);
308
 
    g_assert(i == num_support);
309
 
 
310
 
    OBT_PROP_SETA32(obt_root(ob_screen),
311
 
                    NET_SUPPORTED, ATOM, supported, num_support);
312
 
    g_free(supported);
313
 
 
314
 
    OBT_PROP_SETS(RootWindow(obt_display, ob_screen), OB_VERSION,
315
 
                  OPENBOX_VERSION);
316
 
 
317
 
    screen_tell_ksplash();
318
 
 
319
 
    return TRUE;
320
 
}
321
 
 
322
 
static void screen_tell_ksplash(void)
323
 
{
324
 
    XEvent e;
325
 
    char **argv;
326
 
 
327
 
    argv = g_new(gchar*, 6);
328
 
    argv[0] = g_strdup("dcop");
329
 
    argv[1] = g_strdup("ksplash");
330
 
    argv[2] = g_strdup("ksplash");
331
 
    argv[3] = g_strdup("upAndRunning(QString)");
332
 
    argv[4] = g_strdup("wm started");
333
 
    argv[5] = NULL;
334
 
 
335
 
    /* tell ksplash through the dcop server command line interface */
336
 
    g_spawn_async(NULL, argv, NULL,
337
 
                  G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD |
338
 
                  G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_STDOUT_TO_DEV_NULL,
339
 
                  NULL, NULL, NULL, NULL);
340
 
    g_strfreev(argv);
341
 
 
342
 
    /* i'm not sure why we do this, kwin does it, but ksplash doesn't seem to
343
 
       hear it anyways. perhaps it is for old ksplash. or new ksplash. or
344
 
       something. oh well. */
345
 
    e.xclient.type = ClientMessage;
346
 
    e.xclient.display = obt_display;
347
 
    e.xclient.window = obt_root(ob_screen);
348
 
    e.xclient.message_type =
349
 
        XInternAtom(obt_display, "_KDE_SPLASH_PROGRESS", False);
350
 
    e.xclient.format = 8;
351
 
    strcpy(e.xclient.data.b, "wm started");
352
 
    XSendEvent(obt_display, obt_root(ob_screen),
353
 
               False, SubstructureNotifyMask, &e);
354
 
}
355
 
 
356
 
void screen_startup(gboolean reconfig)
357
 
{
358
 
    gchar **names = NULL;
359
 
    guint32 d;
360
 
    gboolean namesexist = FALSE;
361
 
 
362
 
    desktop_popup = pager_popup_new();
363
 
    desktop_popup_perm = FALSE;
364
 
    pager_popup_height(desktop_popup, POPUP_HEIGHT);
365
 
 
366
 
    if (reconfig) {
367
 
        /* update the pager popup's width */
368
 
        pager_popup_text_width_to_strings(desktop_popup,
369
 
                                          screen_desktop_names,
370
 
                                          screen_num_desktops);
371
 
        return;
372
 
    }
373
 
 
374
 
    /* get the initial size */
375
 
    screen_resize();
376
 
 
377
 
    /* have names already been set for the desktops? */
378
 
    if (OBT_PROP_GETSS_UTF8(obt_root(ob_screen), NET_DESKTOP_NAMES, &names)) {
379
 
        g_strfreev(names);
380
 
        namesexist = TRUE;
381
 
    }
382
 
 
383
 
    /* if names don't exist and we have session names, set those.
384
 
       do this stuff BEFORE setting the number of desktops, because that
385
 
       will create default names for them
386
 
    */
387
 
    if (!namesexist && session_desktop_names != NULL) {
388
 
        guint i, numnames;
389
 
        GSList *it;
390
 
 
391
 
        /* get the desktop names */
392
 
        numnames = g_slist_length(session_desktop_names);
393
 
        names = g_new(gchar*, numnames + 1);
394
 
        names[numnames] = NULL;
395
 
        for (i = 0, it = session_desktop_names; it; ++i, it = g_slist_next(it))
396
 
            names[i] = g_strdup(it->data);
397
 
 
398
 
        /* set the root window property */
399
 
        OBT_PROP_SETSS(obt_root(ob_screen),
400
 
                       NET_DESKTOP_NAMES, (const gchar*const*)names);
401
 
 
402
 
        g_strfreev(names);
403
 
    }
404
 
 
405
 
    /* set the number of desktops, if it's not already set.
406
 
 
407
 
       this will also set the default names from the config file up for
408
 
       desktops that don't have names yet */
409
 
    screen_num_desktops = 0;
410
 
    if (OBT_PROP_GET32(obt_root(ob_screen),
411
 
                       NET_NUMBER_OF_DESKTOPS, CARDINAL, &d))
412
 
    {
413
 
        if (d != config_desktops_num) {
414
 
            /* TRANSLATORS: If you need to specify a different order of the
415
 
               arguments, you can use %1$d for the first one and %2$d for the
416
 
               second one. For example,
417
 
               "The current session has %2$d desktops, but Openbox is configured for %1$d ..." */
418
 
            g_warning(ngettext("Openbox is configured for %d desktop, but the current session has %d.  Overriding the Openbox configuration.", "Openbox is configured for %d desktops, but the current session has %d.  Overriding the Openbox configuration.", config_desktops_num),
419
 
                      config_desktops_num, d);
420
 
        }
421
 
        screen_set_num_desktops(d);
422
 
    }
423
 
    /* restore from session if possible */
424
 
    else if (session_num_desktops)
425
 
        screen_set_num_desktops(session_num_desktops);
426
 
    else
427
 
        screen_set_num_desktops(config_desktops_num);
428
 
 
429
 
    screen_desktop = screen_num_desktops;  /* something invalid */
430
 
    /* start on the current desktop when a wm was already running */
431
 
    if (OBT_PROP_GET32(obt_root(ob_screen),
432
 
                       NET_CURRENT_DESKTOP, CARDINAL, &d) &&
433
 
        d < screen_num_desktops)
434
 
    {
435
 
        screen_set_desktop(d, FALSE);
436
 
    } else if (session_desktop >= 0)
437
 
        screen_set_desktop(MIN((guint)session_desktop,
438
 
                               screen_num_desktops), FALSE);
439
 
    else
440
 
        screen_set_desktop(MIN(config_screen_firstdesk,
441
 
                               screen_num_desktops) - 1, FALSE);
442
 
    screen_last_desktop = screen_desktop;
443
 
 
444
 
    /* don't start in showing-desktop mode */
445
 
    screen_showing_desktop = FALSE;
446
 
    OBT_PROP_SET32(obt_root(ob_screen),
447
 
                   NET_SHOWING_DESKTOP, CARDINAL, screen_showing_desktop);
448
 
 
449
 
    if (session_desktop_layout_present &&
450
 
        screen_validate_layout(&session_desktop_layout))
451
 
    {
452
 
        screen_desktop_layout = session_desktop_layout;
453
 
    }
454
 
    else
455
 
        screen_update_layout();
456
 
}
457
 
 
458
 
void screen_shutdown(gboolean reconfig)
459
 
{
460
 
    pager_popup_free(desktop_popup);
461
 
 
462
 
    if (reconfig)
463
 
        return;
464
 
 
465
 
    XSelectInput(obt_display, obt_root(ob_screen), NoEventMask);
466
 
 
467
 
    /* we're not running here no more! */
468
 
    OBT_PROP_ERASE(obt_root(ob_screen), OPENBOX_PID);
469
 
    /* not without us */
470
 
    OBT_PROP_ERASE(obt_root(ob_screen), NET_SUPPORTED);
471
 
    /* don't keep this mode */
472
 
    OBT_PROP_ERASE(obt_root(ob_screen), NET_SHOWING_DESKTOP);
473
 
 
474
 
    XDestroyWindow(obt_display, screen_support_win);
475
 
 
476
 
    g_strfreev(screen_desktop_names);
477
 
    screen_desktop_names = NULL;
478
 
}
479
 
 
480
 
void screen_resize(void)
481
 
{
482
 
    static gint oldw = 0, oldh = 0;
483
 
    gint w, h;
484
 
    GList *it;
485
 
    gulong geometry[2];
486
 
 
487
 
    w = WidthOfScreen(ScreenOfDisplay(obt_display, ob_screen));
488
 
    h = HeightOfScreen(ScreenOfDisplay(obt_display, ob_screen));
489
 
 
490
 
    if (w == oldw && h == oldh) return;
491
 
 
492
 
    oldw = w; oldh = h;
493
 
 
494
 
    /* Set the _NET_DESKTOP_GEOMETRY hint */
495
 
    screen_physical_size.width = geometry[0] = w;
496
 
    screen_physical_size.height = geometry[1] = h;
497
 
    OBT_PROP_SETA32(obt_root(ob_screen),
498
 
                    NET_DESKTOP_GEOMETRY, CARDINAL, geometry, 2);
499
 
 
500
 
    if (ob_state() != OB_STATE_RUNNING)
501
 
        return;
502
 
 
503
 
    /* this calls screen_update_areas(), which we need ! */
504
 
    dock_configure();
505
 
 
506
 
    if (oldw)
507
 
        for (it = client_list; it; it = g_list_next(it))
508
 
            client_move_onscreen(it->data, FALSE);
509
 
}
510
 
 
511
 
void screen_set_num_desktops(guint num)
512
 
{
513
 
    gulong *viewport;
514
 
    GList *it, *stacking_copy;
515
 
 
516
 
    g_assert(num > 0);
517
 
 
518
 
    if (screen_num_desktops == num) return;
519
 
 
520
 
    screen_num_desktops = num;
521
 
    OBT_PROP_SET32(obt_root(ob_screen), NET_NUMBER_OF_DESKTOPS, CARDINAL, num);
522
 
 
523
 
    /* set the viewport hint */
524
 
    viewport = g_new0(gulong, num * 2);
525
 
    OBT_PROP_SETA32(obt_root(ob_screen),
526
 
                    NET_DESKTOP_VIEWPORT, CARDINAL, viewport, num * 2);
527
 
    g_free(viewport);
528
 
 
529
 
    /* the number of rows/columns will differ */
530
 
    screen_update_layout();
531
 
 
532
 
    /* move windows on desktops that will no longer exist!
533
 
       make a copy of the list cuz we're changing it */
534
 
    stacking_copy = g_list_copy(stacking_list);
535
 
    for (it = g_list_last(stacking_copy); it; it = g_list_previous(it)) {
536
 
        if (WINDOW_IS_CLIENT(it->data)) {
537
 
            ObClient *c = it->data;
538
 
            if (c->desktop != DESKTOP_ALL && c->desktop >= num)
539
 
                client_set_desktop(c, num - 1, FALSE, TRUE);
540
 
            /* raise all the windows that are on the current desktop which
541
 
               is being merged */
542
 
            else if (screen_desktop == num - 1 &&
543
 
                     (c->desktop == DESKTOP_ALL ||
544
 
                      c->desktop == screen_desktop))
545
 
                stacking_raise(CLIENT_AS_WINDOW(c));
546
 
        }
547
 
    }
548
 
    g_list_free(stacking_copy);
549
 
 
550
 
    /* change our struts/area to match (after moving windows) */
551
 
    screen_update_areas();
552
 
 
553
 
    /* may be some unnamed desktops that we need to fill in with names
554
 
       (after updating the areas so the popup can resize) */
555
 
    screen_update_desktop_names();
556
 
 
557
 
    /* change our desktop if we're on one that no longer exists! */
558
 
    if (screen_desktop >= screen_num_desktops)
559
 
        screen_set_desktop(num - 1, TRUE);
560
 
}
561
 
 
562
 
static void screen_fallback_focus(void)
563
 
{
564
 
    ObClient *c;
565
 
    gboolean allow_omni;
566
 
 
567
 
    /* only allow omnipresent windows to get focus on desktop change if
568
 
       an omnipresent window is already focused (it'll keep focus probably, but
569
 
       maybe not depending on mouse-focus options) */
570
 
    allow_omni = focus_client && (client_normal(focus_client) &&
571
 
                                  focus_client->desktop == DESKTOP_ALL);
572
 
 
573
 
    /* the client moved there already so don't move focus. prevent flicker
574
 
       on sendtodesktop + follow */
575
 
    if (focus_client && focus_client->desktop == screen_desktop)
576
 
        return;
577
 
 
578
 
    /* have to try focus here because when you leave an empty desktop
579
 
       there is no focus out to watch for. also, we have different rules
580
 
       here. we always allow it to look under the mouse pointer if
581
 
       config_focus_last is FALSE
582
 
 
583
 
       do this before hiding the windows so if helper windows are coming
584
 
       with us, they don't get hidden
585
 
    */
586
 
    if ((c = focus_fallback(TRUE, !config_focus_last, allow_omni,
587
 
                            !allow_omni)))
588
 
    {
589
 
        /* only do the flicker reducing stuff ahead of time if we are going
590
 
           to call xsetinputfocus on the window ourselves. otherwise there is
591
 
           no guarantee the window will actually take focus.. */
592
 
        if (c->can_focus) {
593
 
            /* reduce flicker by hiliting now rather than waiting for the
594
 
               server FocusIn event */
595
 
            frame_adjust_focus(c->frame, TRUE);
596
 
            /* do this here so that if you switch desktops to a window with
597
 
               helper windows then the helper windows won't flash */
598
 
            client_bring_helper_windows(c);
599
 
        }
600
 
    }
601
 
}
602
 
 
603
 
static gboolean last_desktop_func(gpointer data)
604
 
{
605
 
    screen_desktop_timeout = TRUE;
606
 
    screen_desktop_timer = 0;
607
 
    return FALSE; /* don't repeat */
608
 
}
609
 
 
610
 
void screen_set_desktop(guint num, gboolean dofocus)
611
 
{
612
 
    GList *it;
613
 
    guint previous;
614
 
    gulong ignore_start;
615
 
 
616
 
    g_assert(num < screen_num_desktops);
617
 
 
618
 
    previous = screen_desktop;
619
 
    screen_desktop = num;
620
 
 
621
 
    if (previous == num) return;
622
 
 
623
 
    OBT_PROP_SET32(obt_root(ob_screen), NET_CURRENT_DESKTOP, CARDINAL, num);
624
 
 
625
 
    /* This whole thing decides when/how to save the screen_last_desktop so
626
 
       that it can be restored later if you want */
627
 
    if (screen_desktop_timeout) {
628
 
        /* If screen_desktop_timeout is true, then we've been on this desktop
629
 
           long enough and we can save it as the last desktop. */
630
 
 
631
 
        if (screen_last_desktop == previous)
632
 
            /* this is the startup state only */
633
 
            screen_old_desktop = screen_desktop;
634
 
        else {
635
 
            /* save the "last desktop" as the "old desktop" */
636
 
            screen_old_desktop = screen_last_desktop;
637
 
            /* save the desktop we're coming from as the "last desktop" */
638
 
            screen_last_desktop = previous;
639
 
        }
640
 
    }
641
 
    else {
642
 
        /* If screen_desktop_timeout is false, then we just got to this desktop
643
 
           and we are moving away again. */
644
 
 
645
 
        if (screen_desktop == screen_last_desktop) {
646
 
            /* If we are moving to the "last desktop" .. */
647
 
            if (previous == screen_old_desktop) {
648
 
                /* .. from the "old desktop", change the last desktop to
649
 
                   be where we are coming from */
650
 
                screen_last_desktop = screen_old_desktop;
651
 
            }
652
 
            else if (screen_last_desktop == screen_old_desktop) {
653
 
                /* .. and also to the "old desktop", change the "last
654
 
                   desktop" to be where we are coming from */
655
 
                screen_last_desktop = previous;
656
 
            }
657
 
            else {
658
 
                /* .. from some other desktop, then set the "last desktop" to
659
 
                   be the saved "old desktop", i.e. where we were before the
660
 
                   "last desktop" */
661
 
                screen_last_desktop = screen_old_desktop;
662
 
            }
663
 
        }
664
 
        else {
665
 
            /* If we are moving to any desktop besides the "last desktop"..
666
 
               (this is the normal case) */
667
 
            if (screen_desktop == screen_old_desktop) {
668
 
                /* If moving to the "old desktop", which is not the
669
 
                   "last desktop", don't save anything */
670
 
            }
671
 
            else if (previous == screen_old_desktop) {
672
 
                /* If moving from the "old desktop", and not to the
673
 
                   "last desktop", don't save anything */
674
 
            }
675
 
            else if (screen_last_desktop == screen_old_desktop) {
676
 
                /* If the "last desktop" is the same as "old desktop" and
677
 
                   you're not moving to the "last desktop" then save where
678
 
                   we're coming from as the "last desktop" */
679
 
                screen_last_desktop = previous;
680
 
            }
681
 
            else {
682
 
                /* If the "last desktop" is different from the "old desktop"
683
 
                   and you're not moving to the "last desktop", then don't save
684
 
                   anything */
685
 
            }
686
 
        }
687
 
    }
688
 
    screen_desktop_timeout = FALSE;
689
 
    if (screen_desktop_timer) g_source_remove(screen_desktop_timer);
690
 
    screen_desktop_timer = g_timeout_add(REMEMBER_LAST_DESKTOP_TIME,
691
 
                                         last_desktop_func, NULL);
692
 
 
693
 
    ob_debug("Moving to desktop %d", num+1);
694
 
 
695
 
    if (ob_state() == OB_STATE_RUNNING)
696
 
        screen_show_desktop_popup(screen_desktop, FALSE);
697
 
 
698
 
    /* ignore enter events caused by the move */
699
 
    ignore_start = event_start_ignore_all_enters();
700
 
 
701
 
    if (moveresize_client)
702
 
        client_set_desktop(moveresize_client, num, TRUE, FALSE);
703
 
 
704
 
    /* show windows before hiding the rest to lessen the enter/leave events */
705
 
 
706
 
    /* show windows from top to bottom */
707
 
    for (it = stacking_list; it; it = g_list_next(it)) {
708
 
        if (WINDOW_IS_CLIENT(it->data)) {
709
 
            ObClient *c = it->data;
710
 
            client_show(c);
711
 
        }
712
 
    }
713
 
 
714
 
    if (dofocus) screen_fallback_focus();
715
 
 
716
 
    /* hide windows from bottom to top */
717
 
    for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
718
 
        if (WINDOW_IS_CLIENT(it->data)) {
719
 
            ObClient *c = it->data;
720
 
            if (client_hide(c)) {
721
 
                if (c == focus_client) {
722
 
                    /* c was focused and we didn't do fallback clearly so make
723
 
                       sure openbox doesnt still consider the window focused.
724
 
                       this happens when using NextWindow with allDesktops,
725
 
                       since it doesnt want to move focus on desktop change,
726
 
                       but the focus is not going to stay with the current
727
 
                       window, which has now disappeared.
728
 
                       only do this if the client was actually hidden,
729
 
                       otherwise it can keep focus. */
730
 
                    focus_set_client(NULL);
731
 
                }
732
 
            }
733
 
        }
734
 
    }
735
 
 
736
 
    focus_cycle_addremove(NULL, TRUE);
737
 
 
738
 
    event_end_ignore_all_enters(ignore_start);
739
 
 
740
 
    if (event_source_time() != CurrentTime)
741
 
        screen_desktop_user_time = event_source_time();
742
 
}
743
 
 
744
 
void screen_add_desktop(gboolean current)
745
 
{
746
 
    gulong ignore_start;
747
 
 
748
 
    /* ignore enter events caused by this */
749
 
    ignore_start = event_start_ignore_all_enters();
750
 
 
751
 
    screen_set_num_desktops(screen_num_desktops+1);
752
 
 
753
 
    /* move all the clients over */
754
 
    if (current) {
755
 
        GList *it;
756
 
 
757
 
        for (it = client_list; it; it = g_list_next(it)) {
758
 
            ObClient *c = it->data;
759
 
            if (c->desktop != DESKTOP_ALL && c->desktop >= screen_desktop &&
760
 
                /* don't move direct children, they'll be moved with their
761
 
                   parent - which will have to be on the same desktop */
762
 
                !client_direct_parent(c))
763
 
            {
764
 
                ob_debug("moving window %s", c->title);
765
 
                client_set_desktop(c, c->desktop+1, FALSE, TRUE);
766
 
            }
767
 
        }
768
 
    }
769
 
 
770
 
    event_end_ignore_all_enters(ignore_start);
771
 
}
772
 
 
773
 
void screen_remove_desktop(gboolean current)
774
 
{
775
 
    guint rmdesktop, movedesktop;
776
 
    GList *it, *stacking_copy;
777
 
    gulong ignore_start;
778
 
 
779
 
    if (screen_num_desktops <= 1) return;
780
 
 
781
 
    /* ignore enter events caused by this */
782
 
    ignore_start = event_start_ignore_all_enters();
783
 
 
784
 
    /* what desktop are we removing and moving to? */
785
 
    if (current)
786
 
        rmdesktop = screen_desktop;
787
 
    else
788
 
        rmdesktop = screen_num_desktops - 1;
789
 
    if (rmdesktop < screen_num_desktops - 1)
790
 
        movedesktop = rmdesktop + 1;
791
 
    else
792
 
        movedesktop = rmdesktop;
793
 
 
794
 
    /* make a copy of the list cuz we're changing it */
795
 
    stacking_copy = g_list_copy(stacking_list);
796
 
    for (it = g_list_last(stacking_copy); it; it = g_list_previous(it)) {
797
 
        if (WINDOW_IS_CLIENT(it->data)) {
798
 
            ObClient *c = it->data;
799
 
            guint d = c->desktop;
800
 
            if (d != DESKTOP_ALL && d >= movedesktop &&
801
 
                /* don't move direct children, they'll be moved with their
802
 
                   parent - which will have to be on the same desktop */
803
 
                !client_direct_parent(c))
804
 
            {
805
 
                ob_debug("moving window %s", c->title);
806
 
                client_set_desktop(c, c->desktop - 1, TRUE, TRUE);
807
 
            }
808
 
            /* raise all the windows that are on the current desktop which
809
 
               is being merged */
810
 
            if ((screen_desktop == rmdesktop - 1 ||
811
 
                 screen_desktop == rmdesktop) &&
812
 
                (d == DESKTOP_ALL || d == screen_desktop))
813
 
            {
814
 
                stacking_raise(CLIENT_AS_WINDOW(c));
815
 
                ob_debug("raising window %s", c->title);
816
 
            }
817
 
        }
818
 
    }
819
 
    g_list_free(stacking_copy);
820
 
 
821
 
    /* fallback focus like we're changing desktops */
822
 
    if (screen_desktop < screen_num_desktops - 1) {
823
 
        screen_fallback_focus();
824
 
        ob_debug("fake desktop change");
825
 
    }
826
 
 
827
 
    screen_set_num_desktops(screen_num_desktops-1);
828
 
 
829
 
    event_end_ignore_all_enters(ignore_start);
830
 
}
831
 
 
832
 
static void get_row_col(guint d, guint *r, guint *c)
833
 
{
834
 
    switch (screen_desktop_layout.orientation) {
835
 
    case OB_ORIENTATION_HORZ:
836
 
        switch (screen_desktop_layout.start_corner) {
837
 
        case OB_CORNER_TOPLEFT:
838
 
            *r = d / screen_desktop_layout.columns;
839
 
            *c = d % screen_desktop_layout.columns;
840
 
            break;
841
 
        case OB_CORNER_BOTTOMLEFT:
842
 
            *r = screen_desktop_layout.rows - 1 -
843
 
                d / screen_desktop_layout.columns;
844
 
            *c = d % screen_desktop_layout.columns;
845
 
            break;
846
 
        case OB_CORNER_TOPRIGHT:
847
 
            *r = d / screen_desktop_layout.columns;
848
 
            *c = screen_desktop_layout.columns - 1 -
849
 
                d % screen_desktop_layout.columns;
850
 
            break;
851
 
        case OB_CORNER_BOTTOMRIGHT:
852
 
            *r = screen_desktop_layout.rows - 1 -
853
 
                d / screen_desktop_layout.columns;
854
 
            *c = screen_desktop_layout.columns - 1 -
855
 
                d % screen_desktop_layout.columns;
856
 
            break;
857
 
        }
858
 
        break;
859
 
    case OB_ORIENTATION_VERT:
860
 
        switch (screen_desktop_layout.start_corner) {
861
 
        case OB_CORNER_TOPLEFT:
862
 
            *r = d % screen_desktop_layout.rows;
863
 
            *c = d / screen_desktop_layout.rows;
864
 
            break;
865
 
        case OB_CORNER_BOTTOMLEFT:
866
 
            *r = screen_desktop_layout.rows - 1 -
867
 
                d % screen_desktop_layout.rows;
868
 
            *c = d / screen_desktop_layout.rows;
869
 
            break;
870
 
        case OB_CORNER_TOPRIGHT:
871
 
            *r = d % screen_desktop_layout.rows;
872
 
            *c = screen_desktop_layout.columns - 1 -
873
 
                d / screen_desktop_layout.rows;
874
 
            break;
875
 
        case OB_CORNER_BOTTOMRIGHT:
876
 
            *r = screen_desktop_layout.rows - 1 -
877
 
                d % screen_desktop_layout.rows;
878
 
            *c = screen_desktop_layout.columns - 1 -
879
 
                d / screen_desktop_layout.rows;
880
 
            break;
881
 
        }
882
 
        break;
883
 
    }
884
 
}
885
 
 
886
 
static guint translate_row_col(guint r, guint c)
887
 
{
888
 
    switch (screen_desktop_layout.orientation) {
889
 
    case OB_ORIENTATION_HORZ:
890
 
        switch (screen_desktop_layout.start_corner) {
891
 
        case OB_CORNER_TOPLEFT:
892
 
            return r % screen_desktop_layout.rows *
893
 
                screen_desktop_layout.columns +
894
 
                c % screen_desktop_layout.columns;
895
 
        case OB_CORNER_BOTTOMLEFT:
896
 
            return (screen_desktop_layout.rows - 1 -
897
 
                    r % screen_desktop_layout.rows) *
898
 
                screen_desktop_layout.columns +
899
 
                c % screen_desktop_layout.columns;
900
 
        case OB_CORNER_TOPRIGHT:
901
 
            return r % screen_desktop_layout.rows *
902
 
                screen_desktop_layout.columns +
903
 
                (screen_desktop_layout.columns - 1 -
904
 
                 c % screen_desktop_layout.columns);
905
 
        case OB_CORNER_BOTTOMRIGHT:
906
 
            return (screen_desktop_layout.rows - 1 -
907
 
                    r % screen_desktop_layout.rows) *
908
 
                screen_desktop_layout.columns +
909
 
                (screen_desktop_layout.columns - 1 -
910
 
                 c % screen_desktop_layout.columns);
911
 
        }
912
 
    case OB_ORIENTATION_VERT:
913
 
        switch (screen_desktop_layout.start_corner) {
914
 
        case OB_CORNER_TOPLEFT:
915
 
            return c % screen_desktop_layout.columns *
916
 
                screen_desktop_layout.rows +
917
 
                r % screen_desktop_layout.rows;
918
 
        case OB_CORNER_BOTTOMLEFT:
919
 
            return c % screen_desktop_layout.columns *
920
 
                screen_desktop_layout.rows +
921
 
                (screen_desktop_layout.rows - 1 -
922
 
                 r % screen_desktop_layout.rows);
923
 
        case OB_CORNER_TOPRIGHT:
924
 
            return (screen_desktop_layout.columns - 1 -
925
 
                    c % screen_desktop_layout.columns) *
926
 
                screen_desktop_layout.rows +
927
 
                r % screen_desktop_layout.rows;
928
 
        case OB_CORNER_BOTTOMRIGHT:
929
 
            return (screen_desktop_layout.columns - 1 -
930
 
                    c % screen_desktop_layout.columns) *
931
 
                screen_desktop_layout.rows +
932
 
                (screen_desktop_layout.rows - 1 -
933
 
                 r % screen_desktop_layout.rows);
934
 
        }
935
 
    }
936
 
    g_assert_not_reached();
937
 
    return 0;
938
 
}
939
 
 
940
 
static gboolean hide_desktop_popup_func(gpointer data)
941
 
{
942
 
    pager_popup_hide(desktop_popup);
943
 
    desktop_popup_timer = 0;
944
 
    return FALSE; /* don't repeat */
945
 
}
946
 
 
947
 
void screen_show_desktop_popup(guint d, gboolean perm)
948
 
{
949
 
    const Rect *a;
950
 
 
951
 
    /* 0 means don't show the popup */
952
 
    if (!config_desktop_popup_time) return;
953
 
 
954
 
    a = screen_physical_area_primary(FALSE);
955
 
    pager_popup_position(desktop_popup, CenterGravity,
956
 
                         a->x + a->width / 2, a->y + a->height / 2);
957
 
    pager_popup_icon_size_multiplier(desktop_popup,
958
 
                                     (screen_desktop_layout.columns /
959
 
                                      screen_desktop_layout.rows) / 2,
960
 
                                     (screen_desktop_layout.rows/
961
 
                                      screen_desktop_layout.columns) / 2);
962
 
    pager_popup_max_width(desktop_popup,
963
 
                          MAX(a->width/3, POPUP_WIDTH));
964
 
    pager_popup_show(desktop_popup, screen_desktop_names[d], d);
965
 
 
966
 
    if (desktop_popup_timer) g_source_remove(desktop_popup_timer);
967
 
    desktop_popup_timer = 0;
968
 
    if (!perm && !desktop_popup_perm)
969
 
        /* only hide if its not already being show permanently */
970
 
        desktop_popup_timer = g_timeout_add(config_desktop_popup_time,
971
 
                                            hide_desktop_popup_func,
972
 
                                            desktop_popup);
973
 
    if (perm)
974
 
        desktop_popup_perm = TRUE;
975
 
}
976
 
 
977
 
void screen_hide_desktop_popup(void)
978
 
{
979
 
    if (desktop_popup_timer) g_source_remove(desktop_popup_timer);
980
 
    desktop_popup_timer = 0;
981
 
    pager_popup_hide(desktop_popup);
982
 
    desktop_popup_perm = FALSE;
983
 
}
984
 
 
985
 
guint screen_find_desktop(guint from, ObDirection dir,
986
 
                          gboolean wrap, gboolean linear)
987
 
{
988
 
    guint r, c;
989
 
    guint d;
990
 
 
991
 
    d = from;
992
 
    get_row_col(d, &r, &c);
993
 
    if (linear) {
994
 
        switch (dir) {
995
 
        case OB_DIRECTION_EAST:
996
 
            if (d < screen_num_desktops - 1)
997
 
                ++d;
998
 
            else if (wrap)
999
 
                d = 0;
1000
 
            else
1001
 
                return from;
1002
 
            break;
1003
 
        case OB_DIRECTION_WEST:
1004
 
            if (d > 0)
1005
 
                --d;
1006
 
            else if (wrap)
1007
 
                d = screen_num_desktops - 1;
1008
 
            else
1009
 
                return from;
1010
 
            break;
1011
 
        default:
1012
 
            g_assert_not_reached();
1013
 
            return from;
1014
 
        }
1015
 
    } else {
1016
 
        switch (dir) {
1017
 
        case OB_DIRECTION_EAST:
1018
 
            ++c;
1019
 
            if (c >= screen_desktop_layout.columns) {
1020
 
                if (wrap)
1021
 
                    c = 0;
1022
 
                else
1023
 
                    return from;
1024
 
            }
1025
 
            d = translate_row_col(r, c);
1026
 
            if (d >= screen_num_desktops) {
1027
 
                if (wrap)
1028
 
                    ++c;
1029
 
                else
1030
 
                    return from;
1031
 
            }
1032
 
            break;
1033
 
        case OB_DIRECTION_WEST:
1034
 
            --c;
1035
 
            if (c >= screen_desktop_layout.columns) {
1036
 
                if (wrap)
1037
 
                    c = screen_desktop_layout.columns - 1;
1038
 
                else
1039
 
                    return from;
1040
 
            }
1041
 
            d = translate_row_col(r, c);
1042
 
            if (d >= screen_num_desktops) {
1043
 
                if (wrap)
1044
 
                    --c;
1045
 
                else
1046
 
                    return from;
1047
 
            }
1048
 
            break;
1049
 
        case OB_DIRECTION_SOUTH:
1050
 
            ++r;
1051
 
            if (r >= screen_desktop_layout.rows) {
1052
 
                if (wrap)
1053
 
                    r = 0;
1054
 
                else
1055
 
                    return from;
1056
 
            }
1057
 
            d = translate_row_col(r, c);
1058
 
            if (d >= screen_num_desktops) {
1059
 
                if (wrap)
1060
 
                    ++r;
1061
 
                else
1062
 
                    return from;
1063
 
            }
1064
 
            break;
1065
 
        case OB_DIRECTION_NORTH:
1066
 
            --r;
1067
 
            if (r >= screen_desktop_layout.rows) {
1068
 
                if (wrap)
1069
 
                    r = screen_desktop_layout.rows - 1;
1070
 
                else
1071
 
                    return from;
1072
 
            }
1073
 
            d = translate_row_col(r, c);
1074
 
            if (d >= screen_num_desktops) {
1075
 
                if (wrap)
1076
 
                    --r;
1077
 
                else
1078
 
                    return from;
1079
 
            }
1080
 
            break;
1081
 
        default:
1082
 
            g_assert_not_reached();
1083
 
            return from;
1084
 
        }
1085
 
 
1086
 
        d = translate_row_col(r, c);
1087
 
    }
1088
 
    return d;
1089
 
}
1090
 
 
1091
 
static gboolean screen_validate_layout(ObDesktopLayout *l)
1092
 
{
1093
 
    if (l->columns == 0 && l->rows == 0) /* both 0's is bad data.. */
1094
 
        return FALSE;
1095
 
 
1096
 
    /* fill in a zero rows/columns */
1097
 
    if (l->columns == 0) {
1098
 
        l->columns = screen_num_desktops / l->rows;
1099
 
        if (l->rows * l->columns < screen_num_desktops)
1100
 
            l->columns++;
1101
 
        if (l->rows * l->columns >= screen_num_desktops + l->columns)
1102
 
            l->rows--;
1103
 
    } else if (l->rows == 0) {
1104
 
        l->rows = screen_num_desktops / l->columns;
1105
 
        if (l->columns * l->rows < screen_num_desktops)
1106
 
            l->rows++;
1107
 
        if (l->columns * l->rows >= screen_num_desktops + l->rows)
1108
 
            l->columns--;
1109
 
    }
1110
 
 
1111
 
    /* bounds checking */
1112
 
    if (l->orientation == OB_ORIENTATION_HORZ) {
1113
 
        l->columns = MIN(screen_num_desktops, l->columns);
1114
 
        l->rows = MIN(l->rows,
1115
 
                      (screen_num_desktops + l->columns - 1) / l->columns);
1116
 
        l->columns = screen_num_desktops / l->rows +
1117
 
            !!(screen_num_desktops % l->rows);
1118
 
    } else {
1119
 
        l->rows = MIN(screen_num_desktops, l->rows);
1120
 
        l->columns = MIN(l->columns,
1121
 
                         (screen_num_desktops + l->rows - 1) / l->rows);
1122
 
        l->rows = screen_num_desktops / l->columns +
1123
 
            !!(screen_num_desktops % l->columns);
1124
 
    }
1125
 
    return TRUE;
1126
 
}
1127
 
 
1128
 
void screen_update_layout(void)
1129
 
 
1130
 
{
1131
 
    ObDesktopLayout l;
1132
 
    guint32 *data;
1133
 
    guint num;
1134
 
 
1135
 
    screen_desktop_layout.orientation = OB_ORIENTATION_HORZ;
1136
 
    screen_desktop_layout.start_corner = OB_CORNER_TOPLEFT;
1137
 
    screen_desktop_layout.rows = 1;
1138
 
    screen_desktop_layout.columns = screen_num_desktops;
1139
 
 
1140
 
    if (OBT_PROP_GETA32(obt_root(ob_screen),
1141
 
                        NET_DESKTOP_LAYOUT, CARDINAL, &data, &num)) {
1142
 
        if (num == 3 || num == 4) {
1143
 
 
1144
 
            if (data[0] == OBT_PROP_ATOM(NET_WM_ORIENTATION_VERT))
1145
 
                l.orientation = OB_ORIENTATION_VERT;
1146
 
            else if (data[0] == OBT_PROP_ATOM(NET_WM_ORIENTATION_HORZ))
1147
 
                l.orientation = OB_ORIENTATION_HORZ;
1148
 
            else
1149
 
                return;
1150
 
 
1151
 
            if (num < 4)
1152
 
                l.start_corner = OB_CORNER_TOPLEFT;
1153
 
            else {
1154
 
                if (data[3] == OBT_PROP_ATOM(NET_WM_TOPLEFT))
1155
 
                    l.start_corner = OB_CORNER_TOPLEFT;
1156
 
                else if (data[3] == OBT_PROP_ATOM(NET_WM_TOPRIGHT))
1157
 
                    l.start_corner = OB_CORNER_TOPRIGHT;
1158
 
                else if (data[3] == OBT_PROP_ATOM(NET_WM_BOTTOMRIGHT))
1159
 
                    l.start_corner = OB_CORNER_BOTTOMRIGHT;
1160
 
                else if (data[3] == OBT_PROP_ATOM(NET_WM_BOTTOMLEFT))
1161
 
                    l.start_corner = OB_CORNER_BOTTOMLEFT;
1162
 
                else
1163
 
                    return;
1164
 
            }
1165
 
 
1166
 
            l.columns = data[1];
1167
 
            l.rows = data[2];
1168
 
 
1169
 
            if (screen_validate_layout(&l))
1170
 
                screen_desktop_layout = l;
1171
 
 
1172
 
            g_free(data);
1173
 
        }
1174
 
    }
1175
 
}
1176
 
 
1177
 
void screen_update_desktop_names(void)
1178
 
{
1179
 
    guint i;
1180
 
 
1181
 
    /* empty the array */
1182
 
    g_strfreev(screen_desktop_names);
1183
 
    screen_desktop_names = NULL;
1184
 
 
1185
 
    if (OBT_PROP_GETSS(obt_root(ob_screen),
1186
 
                       NET_DESKTOP_NAMES, &screen_desktop_names))
1187
 
        for (i = 0; screen_desktop_names[i] && i < screen_num_desktops; ++i);
1188
 
    else
1189
 
        i = 0;
1190
 
    if (i < screen_num_desktops) {
1191
 
        GSList *it;
1192
 
 
1193
 
        screen_desktop_names = g_renew(gchar*, screen_desktop_names,
1194
 
                                       screen_num_desktops + 1);
1195
 
        screen_desktop_names[screen_num_desktops] = NULL;
1196
 
 
1197
 
        it = g_slist_nth(config_desktops_names, i);
1198
 
 
1199
 
        for (; i < screen_num_desktops; ++i) {
1200
 
            if (it && ((char*)it->data)[0]) /* not empty */
1201
 
                /* use the names from the config file when possible */
1202
 
                screen_desktop_names[i] = g_strdup(it->data);
1203
 
            else
1204
 
                /* make up a nice name if it's not though */
1205
 
                screen_desktop_names[i] = g_strdup_printf(_("desktop %i"),
1206
 
                                                          i + 1);
1207
 
            if (it) it = g_slist_next(it);
1208
 
        }
1209
 
 
1210
 
        /* if we changed any names, then set the root property so we can
1211
 
           all agree on the names */
1212
 
        OBT_PROP_SETSS(obt_root(ob_screen), NET_DESKTOP_NAMES,
1213
 
                       (const gchar*const*)screen_desktop_names);
1214
 
    }
1215
 
 
1216
 
    /* resize the pager for these names */
1217
 
    pager_popup_text_width_to_strings(desktop_popup,
1218
 
                                      screen_desktop_names,
1219
 
                                      screen_num_desktops);
1220
 
}
1221
 
 
1222
 
void screen_show_desktop(gboolean show, ObClient *show_only)
1223
 
{
1224
 
    GList *it;
1225
 
 
1226
 
    if (show == screen_showing_desktop) return; /* no change */
1227
 
 
1228
 
    screen_showing_desktop = show;
1229
 
 
1230
 
    if (show) {
1231
 
        /* hide windows bottom to top */
1232
 
        for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
1233
 
            if (WINDOW_IS_CLIENT(it->data)) {
1234
 
                ObClient *client = it->data;
1235
 
                client_showhide(client);
1236
 
            }
1237
 
        }
1238
 
    }
1239
 
    else {
1240
 
        /* restore windows top to bottom */
1241
 
        for (it = stacking_list; it; it = g_list_next(it)) {
1242
 
            if (WINDOW_IS_CLIENT(it->data)) {
1243
 
                ObClient *client = it->data;
1244
 
                if (client_should_show(client)) {
1245
 
                    if (!show_only || client == show_only)
1246
 
                        client_show(client);
1247
 
                    else
1248
 
                        client_iconify(client, TRUE, FALSE, TRUE);
1249
 
                }
1250
 
            }
1251
 
        }
1252
 
    }
1253
 
 
1254
 
    if (show) {
1255
 
        /* focus the desktop */
1256
 
        for (it = focus_order; it; it = g_list_next(it)) {
1257
 
            ObClient *c = it->data;
1258
 
            if (c->type == OB_CLIENT_TYPE_DESKTOP &&
1259
 
                (c->desktop == screen_desktop || c->desktop == DESKTOP_ALL) &&
1260
 
                client_focus(it->data))
1261
 
                break;
1262
 
        }
1263
 
    }
1264
 
    else if (!show_only) {
1265
 
        ObClient *c;
1266
 
 
1267
 
        if ((c = focus_fallback(TRUE, FALSE, TRUE, FALSE))) {
1268
 
            /* only do the flicker reducing stuff ahead of time if we are going
1269
 
               to call xsetinputfocus on the window ourselves. otherwise there
1270
 
               is no guarantee the window will actually take focus.. */
1271
 
            if (c->can_focus) {
1272
 
                /* reduce flicker by hiliting now rather than waiting for the
1273
 
                   server FocusIn event */
1274
 
                frame_adjust_focus(c->frame, TRUE);
1275
 
            }
1276
 
        }
1277
 
    }
1278
 
 
1279
 
    show = !!show; /* make it boolean */
1280
 
    OBT_PROP_SET32(obt_root(ob_screen), NET_SHOWING_DESKTOP, CARDINAL, show);
1281
 
}
1282
 
 
1283
 
void screen_install_colormap(ObClient *client, gboolean install)
1284
 
{
1285
 
    if (client == NULL || client->colormap == None) {
1286
 
        if (install)
1287
 
            XInstallColormap(obt_display, RrColormap(ob_rr_inst));
1288
 
        else
1289
 
            XUninstallColormap(obt_display, RrColormap(ob_rr_inst));
1290
 
    } else {
1291
 
        obt_display_ignore_errors(TRUE);
1292
 
        if (install)
1293
 
            XInstallColormap(obt_display, client->colormap);
1294
 
        else
1295
 
            XUninstallColormap(obt_display, client->colormap);
1296
 
        obt_display_ignore_errors(FALSE);
1297
 
    }
1298
 
}
1299
 
 
1300
 
typedef struct {
1301
 
    guint desktop;
1302
 
    StrutPartial *strut;
1303
 
} ObScreenStrut;
1304
 
 
1305
 
#define RESET_STRUT_LIST(sl) \
1306
 
    while (sl) { \
1307
 
        g_slice_free(ObScreenStrut, (sl)->data); \
1308
 
        sl = g_slist_delete_link(sl, sl); \
1309
 
    }
1310
 
 
1311
 
#define ADD_STRUT_TO_LIST(sl, d, s) \
1312
 
{ \
1313
 
    ObScreenStrut *ss = g_slice_new(ObScreenStrut); \
1314
 
    ss->desktop = d; \
1315
 
    ss->strut = s;  \
1316
 
    sl = g_slist_prepend(sl, ss); \
1317
 
}
1318
 
 
1319
 
#define VALIDATE_STRUTS(sl, side, max) \
1320
 
{ \
1321
 
    GSList *it; \
1322
 
    for (it = sl; it; it = g_slist_next(it)) { \
1323
 
      ObScreenStrut *ss = it->data; \
1324
 
      ss->strut->side = MIN(max, ss->strut->side); \
1325
 
    } \
1326
 
}
1327
 
 
1328
 
static void get_xinerama_screens(Rect **xin_areas, guint *nxin)
1329
 
{
1330
 
    guint i;
1331
 
    gint n, l, r, t, b;
1332
 
#ifdef XINERAMA
1333
 
    XineramaScreenInfo *info;
1334
 
#endif
1335
 
 
1336
 
    if (ob_debug_xinerama) {
1337
 
        gint w = WidthOfScreen(ScreenOfDisplay(obt_display, ob_screen));
1338
 
        gint h = HeightOfScreen(ScreenOfDisplay(obt_display, ob_screen));
1339
 
        *nxin = 2;
1340
 
        *xin_areas = g_new(Rect, *nxin + 1);
1341
 
        RECT_SET((*xin_areas)[0], 0, 0, w/2, h);
1342
 
        RECT_SET((*xin_areas)[1], w/2, 0, w-(w/2), h);
1343
 
    }
1344
 
#ifdef XINERAMA
1345
 
    else if (obt_display_extension_xinerama &&
1346
 
             (info = XineramaQueryScreens(obt_display, &n))) {
1347
 
        *nxin = n;
1348
 
        *xin_areas = g_new(Rect, *nxin + 1);
1349
 
        for (i = 0; i < *nxin; ++i)
1350
 
            RECT_SET((*xin_areas)[i], info[i].x_org, info[i].y_org,
1351
 
                     info[i].width, info[i].height);
1352
 
        XFree(info);
1353
 
    }
1354
 
#endif
1355
 
    else {
1356
 
        *nxin = 1;
1357
 
        *xin_areas = g_new(Rect, *nxin + 1);
1358
 
        RECT_SET((*xin_areas)[0], 0, 0,
1359
 
                 WidthOfScreen(ScreenOfDisplay(obt_display, ob_screen)),
1360
 
                 HeightOfScreen(ScreenOfDisplay(obt_display, ob_screen)));
1361
 
    }
1362
 
 
1363
 
    /* returns one extra with the total area in it */
1364
 
    l = (*xin_areas)[0].x;
1365
 
    t = (*xin_areas)[0].y;
1366
 
    r = (*xin_areas)[0].x + (*xin_areas)[0].width - 1;
1367
 
    b = (*xin_areas)[0].y + (*xin_areas)[0].height - 1;
1368
 
    for (i = 1; i < *nxin; ++i) {
1369
 
        l = MIN(l, (*xin_areas)[i].x);
1370
 
        t = MIN(l, (*xin_areas)[i].y);
1371
 
        r = MAX(r, (*xin_areas)[i].x + (*xin_areas)[i].width - 1);
1372
 
        b = MAX(b, (*xin_areas)[i].y + (*xin_areas)[i].height - 1);
1373
 
    }
1374
 
    RECT_SET((*xin_areas)[*nxin], l, t, r - l + 1, b - t + 1);
1375
 
}
1376
 
 
1377
 
void screen_update_areas(void)
1378
 
{
1379
 
    guint i;
1380
 
    gulong *dims;
1381
 
    GList *it, *onscreen;
1382
 
 
1383
 
    /* collect the clients that are on screen */
1384
 
    onscreen = NULL;
1385
 
    for (it = client_list; it; it = g_list_next(it)) {
1386
 
        if (client_monitor(it->data) != screen_num_monitors)
1387
 
            onscreen = g_list_prepend(onscreen, it->data);
1388
 
    }
1389
 
 
1390
 
    g_free(monitor_area);
1391
 
    get_xinerama_screens(&monitor_area, &screen_num_monitors);
1392
 
 
1393
 
    /* set up the user-specified margins */
1394
 
    config_margins.top_start = RECT_LEFT(monitor_area[screen_num_monitors]);
1395
 
    config_margins.top_end = RECT_RIGHT(monitor_area[screen_num_monitors]);
1396
 
    config_margins.bottom_start = RECT_LEFT(monitor_area[screen_num_monitors]);
1397
 
    config_margins.bottom_end = RECT_RIGHT(monitor_area[screen_num_monitors]);
1398
 
    config_margins.left_start = RECT_TOP(monitor_area[screen_num_monitors]);
1399
 
    config_margins.left_end = RECT_BOTTOM(monitor_area[screen_num_monitors]);
1400
 
    config_margins.right_start = RECT_TOP(monitor_area[screen_num_monitors]);
1401
 
    config_margins.right_end = RECT_BOTTOM(monitor_area[screen_num_monitors]);
1402
 
 
1403
 
    RESET_STRUT_LIST(struts_left);
1404
 
    RESET_STRUT_LIST(struts_top);
1405
 
    RESET_STRUT_LIST(struts_right);
1406
 
    RESET_STRUT_LIST(struts_bottom);
1407
 
 
1408
 
    /* collect the struts */
1409
 
    for (it = client_list; it; it = g_list_next(it)) {
1410
 
        ObClient *c = it->data;
1411
 
        if (c->strut.left)
1412
 
            ADD_STRUT_TO_LIST(struts_left, c->desktop, &c->strut);
1413
 
        if (c->strut.top)
1414
 
            ADD_STRUT_TO_LIST(struts_top, c->desktop, &c->strut);
1415
 
        if (c->strut.right)
1416
 
            ADD_STRUT_TO_LIST(struts_right, c->desktop, &c->strut);
1417
 
        if (c->strut.bottom)
1418
 
            ADD_STRUT_TO_LIST(struts_bottom, c->desktop, &c->strut);
1419
 
    }
1420
 
    if (dock_strut.left)
1421
 
        ADD_STRUT_TO_LIST(struts_left, DESKTOP_ALL, &dock_strut);
1422
 
    if (dock_strut.top)
1423
 
        ADD_STRUT_TO_LIST(struts_top, DESKTOP_ALL, &dock_strut);
1424
 
    if (dock_strut.right)
1425
 
        ADD_STRUT_TO_LIST(struts_right, DESKTOP_ALL, &dock_strut);
1426
 
    if (dock_strut.bottom)
1427
 
        ADD_STRUT_TO_LIST(struts_bottom, DESKTOP_ALL, &dock_strut);
1428
 
 
1429
 
    if (config_margins.left)
1430
 
        ADD_STRUT_TO_LIST(struts_left, DESKTOP_ALL, &config_margins);
1431
 
    if (config_margins.top)
1432
 
        ADD_STRUT_TO_LIST(struts_top, DESKTOP_ALL, &config_margins);
1433
 
    if (config_margins.right)
1434
 
        ADD_STRUT_TO_LIST(struts_right, DESKTOP_ALL, &config_margins);
1435
 
    if (config_margins.bottom)
1436
 
        ADD_STRUT_TO_LIST(struts_bottom, DESKTOP_ALL, &config_margins);
1437
 
 
1438
 
    VALIDATE_STRUTS(struts_left, left,
1439
 
                    monitor_area[screen_num_monitors].width / 2);
1440
 
    VALIDATE_STRUTS(struts_right, right,
1441
 
                    monitor_area[screen_num_monitors].width / 2);
1442
 
    VALIDATE_STRUTS(struts_top, top,
1443
 
                    monitor_area[screen_num_monitors].height / 2);
1444
 
    VALIDATE_STRUTS(struts_bottom, bottom,
1445
 
                    monitor_area[screen_num_monitors].height / 2);
1446
 
 
1447
 
    dims = g_new(gulong, 4 * screen_num_desktops);
1448
 
    for (i = 0; i < screen_num_desktops; ++i) {
1449
 
        Rect *area = screen_area(i, SCREEN_AREA_ALL_MONITORS, NULL);
1450
 
        dims[i*4+0] = area->x;
1451
 
        dims[i*4+1] = area->y;
1452
 
        dims[i*4+2] = area->width;
1453
 
        dims[i*4+3] = area->height;
1454
 
        g_slice_free(Rect, area);
1455
 
    }
1456
 
 
1457
 
    /* set the legacy workarea hint to the union of all the monitors */
1458
 
    OBT_PROP_SETA32(obt_root(ob_screen), NET_WORKAREA, CARDINAL,
1459
 
                    dims, 4 * screen_num_desktops);
1460
 
 
1461
 
    /* the area has changed, adjust all the windows if they need it */
1462
 
    for (it = onscreen; it; it = g_list_next(it))
1463
 
        client_reconfigure(it->data, FALSE);
1464
 
 
1465
 
    g_free(dims);
1466
 
}
1467
 
 
1468
 
#if 0
1469
 
Rect* screen_area_all_monitors(guint desktop)
1470
 
{
1471
 
    guint i;
1472
 
    Rect *a;
1473
 
 
1474
 
    a = screen_area_monitor(desktop, 0);
1475
 
 
1476
 
    /* combine all the monitors together */
1477
 
    for (i = 1; i < screen_num_monitors; ++i) {
1478
 
        Rect *m = screen_area_monitor(desktop, i);
1479
 
        gint l, r, t, b;
1480
 
 
1481
 
        l = MIN(RECT_LEFT(*a), RECT_LEFT(*m));
1482
 
        t = MIN(RECT_TOP(*a), RECT_TOP(*m));
1483
 
        r = MAX(RECT_RIGHT(*a), RECT_RIGHT(*m));
1484
 
        b = MAX(RECT_BOTTOM(*a), RECT_BOTTOM(*m));
1485
 
 
1486
 
        RECT_SET(*a, l, t, r - l + 1, b - t + 1);
1487
 
 
1488
 
        g_free(m);
1489
 
    }
1490
 
 
1491
 
    return a;
1492
 
}
1493
 
#endif
1494
 
 
1495
 
#define STRUT_LEFT_IN_SEARCH(s, search) \
1496
 
    (RANGES_INTERSECT(search->y, search->height, \
1497
 
                      s->left_start, s->left_end - s->left_start + 1))
1498
 
#define STRUT_RIGHT_IN_SEARCH(s, search) \
1499
 
    (RANGES_INTERSECT(search->y, search->height, \
1500
 
                      s->right_start, s->right_end - s->right_start + 1))
1501
 
#define STRUT_TOP_IN_SEARCH(s, search) \
1502
 
    (RANGES_INTERSECT(search->x, search->width, \
1503
 
                      s->top_start, s->top_end - s->top_start + 1))
1504
 
#define STRUT_BOTTOM_IN_SEARCH(s, search) \
1505
 
    (RANGES_INTERSECT(search->x, search->width, \
1506
 
                      s->bottom_start, s->bottom_end - s->bottom_start + 1))
1507
 
 
1508
 
#define STRUT_LEFT_IGNORE(s, us, search) \
1509
 
    (head == SCREEN_AREA_ALL_MONITORS && us && \
1510
 
     RECT_LEFT(monitor_area[i]) + s->left > RECT_LEFT(*search))
1511
 
#define STRUT_RIGHT_IGNORE(s, us, search) \
1512
 
    (head == SCREEN_AREA_ALL_MONITORS && us && \
1513
 
     RECT_RIGHT(monitor_area[i]) - s->right < RECT_RIGHT(*search))
1514
 
#define STRUT_TOP_IGNORE(s, us, search) \
1515
 
    (head == SCREEN_AREA_ALL_MONITORS && us && \
1516
 
     RECT_TOP(monitor_area[i]) + s->top > RECT_TOP(*search))
1517
 
#define STRUT_BOTTOM_IGNORE(s, us, search) \
1518
 
    (head == SCREEN_AREA_ALL_MONITORS && us && \
1519
 
     RECT_BOTTOM(monitor_area[i]) - s->bottom < RECT_BOTTOM(*search))
1520
 
 
1521
 
Rect* screen_area(guint desktop, guint head, Rect *search)
1522
 
{
1523
 
    Rect *a;
1524
 
    GSList *it;
1525
 
    gint l, r, t, b;
1526
 
    guint i, d;
1527
 
    gboolean us = search != NULL; /* user provided search */
1528
 
 
1529
 
    g_assert(desktop < screen_num_desktops || desktop == DESKTOP_ALL);
1530
 
    g_assert(head < screen_num_monitors || head == SCREEN_AREA_ONE_MONITOR ||
1531
 
             head == SCREEN_AREA_ALL_MONITORS);
1532
 
    g_assert(!(head == SCREEN_AREA_ONE_MONITOR && search == NULL));
1533
 
 
1534
 
    /* find any struts for this monitor
1535
 
       which will be affecting the search area.
1536
 
    */
1537
 
 
1538
 
    /* search everything if search is null */
1539
 
    if (!search) {
1540
 
        if (head < screen_num_monitors) search = &monitor_area[head];
1541
 
        else search = &monitor_area[screen_num_monitors];
1542
 
    }
1543
 
    if (head == SCREEN_AREA_ONE_MONITOR) head = screen_find_monitor(search);
1544
 
 
1545
 
    /* al is "all left" meaning the furthest left you can get, l is our
1546
 
       "working left" meaning our current strut edge which we're calculating
1547
 
    */
1548
 
 
1549
 
    /* only include monitors which the search area lines up with */
1550
 
    if (RECT_INTERSECTS_RECT(monitor_area[screen_num_monitors], *search)) {
1551
 
        l = RECT_RIGHT(monitor_area[screen_num_monitors]);
1552
 
        t = RECT_BOTTOM(monitor_area[screen_num_monitors]);
1553
 
        r = RECT_LEFT(monitor_area[screen_num_monitors]);
1554
 
        b = RECT_TOP(monitor_area[screen_num_monitors]);
1555
 
        for (i = 0; i < screen_num_monitors; ++i) {
1556
 
            /* add the monitor if applicable */
1557
 
            if (RANGES_INTERSECT(search->x, search->width,
1558
 
                                 monitor_area[i].x, monitor_area[i].width))
1559
 
            {
1560
 
                t = MIN(t, RECT_TOP(monitor_area[i]));
1561
 
                b = MAX(b, RECT_BOTTOM(monitor_area[i]));
1562
 
            }
1563
 
            if (RANGES_INTERSECT(search->y, search->height,
1564
 
                                 monitor_area[i].y, monitor_area[i].height))
1565
 
            {
1566
 
                l = MIN(l, RECT_LEFT(monitor_area[i]));
1567
 
                r = MAX(r, RECT_RIGHT(monitor_area[i]));
1568
 
            }
1569
 
        }
1570
 
    } else {
1571
 
        l = RECT_LEFT(monitor_area[screen_num_monitors]);
1572
 
        t = RECT_TOP(monitor_area[screen_num_monitors]);
1573
 
        r = RECT_RIGHT(monitor_area[screen_num_monitors]);
1574
 
        b = RECT_BOTTOM(monitor_area[screen_num_monitors]);
1575
 
    }
1576
 
 
1577
 
    for (d = 0; d < screen_num_desktops; ++d) {
1578
 
        if (d != desktop && desktop != DESKTOP_ALL) continue;
1579
 
 
1580
 
        for (i = 0; i < screen_num_monitors; ++i) {
1581
 
            if (head != SCREEN_AREA_ALL_MONITORS && head != i) continue;
1582
 
 
1583
 
            for (it = struts_left; it; it = g_slist_next(it)) {
1584
 
                ObScreenStrut *s = it->data;
1585
 
                if ((s->desktop == d || s->desktop == DESKTOP_ALL) &&
1586
 
                    STRUT_LEFT_IN_SEARCH(s->strut, search) &&
1587
 
                    !STRUT_LEFT_IGNORE(s->strut, us, search))
1588
 
                    l = MAX(l, RECT_LEFT(monitor_area[screen_num_monitors])
1589
 
                               + s->strut->left);
1590
 
            }
1591
 
            for (it = struts_top; it; it = g_slist_next(it)) {
1592
 
                ObScreenStrut *s = it->data;
1593
 
                if ((s->desktop == d || s->desktop == DESKTOP_ALL) &&
1594
 
                    STRUT_TOP_IN_SEARCH(s->strut, search) &&
1595
 
                    !STRUT_TOP_IGNORE(s->strut, us, search))
1596
 
                    t = MAX(t, RECT_TOP(monitor_area[screen_num_monitors])
1597
 
                               + s->strut->top);
1598
 
            }
1599
 
            for (it = struts_right; it; it = g_slist_next(it)) {
1600
 
                ObScreenStrut *s = it->data;
1601
 
                if ((s->desktop == d || s->desktop == DESKTOP_ALL) &&
1602
 
                    STRUT_RIGHT_IN_SEARCH(s->strut, search) &&
1603
 
                    !STRUT_RIGHT_IGNORE(s->strut, us, search))
1604
 
                    r = MIN(r, RECT_RIGHT(monitor_area[screen_num_monitors])
1605
 
                               - s->strut->right);
1606
 
            }
1607
 
            for (it = struts_bottom; it; it = g_slist_next(it)) {
1608
 
                ObScreenStrut *s = it->data;
1609
 
                if ((s->desktop == d || s->desktop == DESKTOP_ALL) &&
1610
 
                    STRUT_BOTTOM_IN_SEARCH(s->strut, search) &&
1611
 
                    !STRUT_BOTTOM_IGNORE(s->strut, us, search))
1612
 
                    b = MIN(b, RECT_BOTTOM(monitor_area[screen_num_monitors])
1613
 
                               - s->strut->bottom);
1614
 
            }
1615
 
 
1616
 
            /* limit to this monitor */
1617
 
            if (head == i) {
1618
 
                l = MAX(l, RECT_LEFT(monitor_area[i]));
1619
 
                t = MAX(t, RECT_TOP(monitor_area[i]));
1620
 
                r = MIN(r, RECT_RIGHT(monitor_area[i]));
1621
 
                b = MIN(b, RECT_BOTTOM(monitor_area[i]));
1622
 
            }
1623
 
        }
1624
 
    }
1625
 
 
1626
 
    a = g_slice_new(Rect);
1627
 
    a->x = l;
1628
 
    a->y = t;
1629
 
    a->width = r - l + 1;
1630
 
    a->height = b - t + 1;
1631
 
    return a;
1632
 
}
1633
 
 
1634
 
guint screen_find_monitor(const Rect *search)
1635
 
{
1636
 
    guint i;
1637
 
    guint most = screen_num_monitors;
1638
 
    guint mostv = 0;
1639
 
 
1640
 
    for (i = 0; i < screen_num_monitors; ++i) {
1641
 
        const Rect *area = screen_physical_area_monitor(i);
1642
 
        if (RECT_INTERSECTS_RECT(*area, *search)) {
1643
 
            Rect r;
1644
 
            guint v;
1645
 
 
1646
 
            RECT_SET_INTERSECTION(r, *area, *search);
1647
 
            v = r.width * r.height;
1648
 
 
1649
 
            if (v > mostv) {
1650
 
                mostv = v;
1651
 
                most = i;
1652
 
            }
1653
 
        }
1654
 
    }
1655
 
    return most < screen_num_monitors ? most : screen_monitor_primary(FALSE);
1656
 
}
1657
 
 
1658
 
const Rect* screen_physical_area_all_monitors(void)
1659
 
{
1660
 
    return screen_physical_area_monitor(screen_num_monitors);
1661
 
}
1662
 
 
1663
 
const Rect* screen_physical_area_monitor(guint head)
1664
 
{
1665
 
    g_assert(head <= screen_num_monitors);
1666
 
 
1667
 
    return &monitor_area[head];
1668
 
}
1669
 
 
1670
 
gboolean screen_physical_area_monitor_contains(guint head, Rect *search)
1671
 
{
1672
 
    g_assert(head <= screen_num_monitors);
1673
 
    g_assert(search);
1674
 
    return RECT_INTERSECTS_RECT(monitor_area[head], *search);
1675
 
}
1676
 
 
1677
 
guint screen_monitor_active(void)
1678
 
{
1679
 
    if (moveresize_client)
1680
 
        return client_monitor(moveresize_client);
1681
 
    else if (focus_client)
1682
 
        return client_monitor(focus_client);
1683
 
    else
1684
 
        return screen_monitor_pointer();
1685
 
}
1686
 
 
1687
 
const Rect* screen_physical_area_active(void)
1688
 
{
1689
 
    return screen_physical_area_monitor(screen_monitor_active());
1690
 
}
1691
 
 
1692
 
guint screen_monitor_primary(gboolean fixed)
1693
 
{
1694
 
    if (config_primary_monitor_index > 0) {
1695
 
        if (config_primary_monitor_index-1 < screen_num_monitors)
1696
 
            return config_primary_monitor_index - 1;
1697
 
        else
1698
 
            return 0;
1699
 
    }
1700
 
    else if (fixed)
1701
 
        return 0;
1702
 
    else if (config_primary_monitor == OB_PLACE_MONITOR_ACTIVE)
1703
 
        return screen_monitor_active();
1704
 
    else /* config_primary_monitor == OB_PLACE_MONITOR_MOUSE */
1705
 
        return screen_monitor_pointer();
1706
 
}
1707
 
 
1708
 
const Rect* screen_physical_area_primary(gboolean fixed)
1709
 
{
1710
 
    return screen_physical_area_monitor(screen_monitor_primary(fixed));
1711
 
}
1712
 
 
1713
 
void screen_set_root_cursor(void)
1714
 
{
1715
 
    if (sn_app_starting())
1716
 
        XDefineCursor(obt_display, obt_root(ob_screen),
1717
 
                      ob_cursor(OB_CURSOR_BUSYPOINTER));
1718
 
    else
1719
 
        XDefineCursor(obt_display, obt_root(ob_screen),
1720
 
                      ob_cursor(OB_CURSOR_POINTER));
1721
 
}
1722
 
 
1723
 
guint screen_find_monitor_point(guint x, guint y)
1724
 
{
1725
 
    Rect mon;
1726
 
    RECT_SET(mon, x, y, 1, 1);
1727
 
    return screen_find_monitor(&mon);
1728
 
}
1729
 
 
1730
 
guint screen_monitor_pointer()
1731
 
{
1732
 
    gint x, y;
1733
 
    if (!screen_pointer_pos(&x, &y))
1734
 
        x = y = 0;
1735
 
    return screen_find_monitor_point(x, y);
1736
 
}
1737
 
 
1738
 
gboolean screen_pointer_pos(gint *x, gint *y)
1739
 
{
1740
 
    Window w;
1741
 
    gint i;
1742
 
    guint u;
1743
 
    gboolean ret;
1744
 
 
1745
 
    ret = !!XQueryPointer(obt_display, obt_root(ob_screen),
1746
 
                          &w, &w, x, y, &i, &i, &u);
1747
 
    if (!ret) {
1748
 
        for (i = 0; i < ScreenCount(obt_display); ++i)
1749
 
            if (i != ob_screen)
1750
 
                if (XQueryPointer(obt_display, obt_root(i),
1751
 
                                  &w, &w, x, y, &i, &i, &u))
1752
 
                    break;
1753
 
    }
1754
 
    return ret;
1755
 
}
1756
 
 
1757
 
gboolean screen_compare_desktops(guint a, guint b)
1758
 
{
1759
 
    if (a == DESKTOP_ALL)
1760
 
        a = screen_desktop;
1761
 
    if (b == DESKTOP_ALL)
1762
 
        b = screen_desktop;
1763
 
    return a == b;
1764
 
}