Merge branch 'backport' into work
[dana/openbox.git] / openbox / screen.c
index 79008e7..09d5003 100644 (file)
@@ -20,8 +20,6 @@
 #include "debug.h"
 #include "openbox.h"
 #include "dock.h"
-#include "xerror.h"
-#include "prop.h"
 #include "grab.h"
 #include "startupnotify.h"
 #include "moveresize.h"
 #include "event.h"
 #include "focus.h"
 #include "popup.h"
-#include "extensions.h"
+#include "hooks.h"
 #include "render/render.h"
 #include "gettext.h"
+#include "obt/display.h"
+#include "obt/prop.h"
+#include "obt/mainloop.h"
 
 #include <X11/Xlib.h>
 #ifdef HAVE_UNISTD_H
                         ButtonPressMask | ButtonReleaseMask)
 
 static gboolean screen_validate_layout(ObDesktopLayout *l);
-static gboolean replace_wm();
-static void     screen_tell_ksplash();
-
-guint    screen_num_desktops;
-guint    screen_num_monitors;
-guint    screen_desktop;
-guint    screen_last_desktop;
-Size     screen_physical_size;
-gboolean screen_showing_desktop;
+static gboolean replace_wm(void);
+static void     screen_tell_ksplash(void);
+static void     screen_fallback_focus(void);
+
+guint           screen_num_desktops;
+guint           screen_num_monitors;
+guint           screen_desktop;
+guint           screen_last_desktop;
+gboolean        screen_showing_desktop;
 ObDesktopLayout screen_desktop_layout;
-gchar  **screen_desktop_names;
-Window   screen_support_win;
-Time     screen_desktop_user_time = CurrentTime;
-
-/*! An array of desktops, holding array of areas per monitor */
+gchar         **screen_desktop_names;
+Window          screen_support_win;
+Time            screen_desktop_user_time = CurrentTime;
+
+static Size     screen_physical_size;
+static guint    screen_old_desktop;
+static gboolean screen_desktop_timeout = TRUE;
+/*! An array of desktops, holding an array of areas per monitor */
 static Rect  *monitor_area = NULL;
 /*! An array of desktops, holding an array of struts */
 static GSList *struts_top = NULL;
@@ -73,9 +77,13 @@ static GSList *struts_left = NULL;
 static GSList *struts_right = NULL;
 static GSList *struts_bottom = NULL;
 
-static ObPagerPopup *desktop_cycle_popup;
+static ObPagerPopup **desktop_popup;
+
+/*! The number of microseconds that you need to be on a desktop before it will
+  replace the remembered "last desktop" */
+#define REMEMBER_LAST_DESKTOP_TIME 750000
 
-static gboolean replace_wm()
+static gboolean replace_wm(void)
 {
     gchar *wm_sn;
     Atom wm_sn_atom;
@@ -83,10 +91,10 @@ static gboolean replace_wm()
     Time timestamp;
 
     wm_sn = g_strdup_printf("WM_S%d", ob_screen);
-    wm_sn_atom = XInternAtom(ob_display, wm_sn, FALSE);
+    wm_sn_atom = XInternAtom(obt_display, wm_sn, FALSE);
     g_free(wm_sn);
 
-    current_wm_sn_owner = XGetSelectionOwner(ob_display, wm_sn_atom);
+    current_wm_sn_owner = XGetSelectionOwner(obt_display, wm_sn_atom);
     if (current_wm_sn_owner == screen_support_win)
         current_wm_sn_owner = None;
     if (current_wm_sn_owner) {
@@ -95,24 +103,23 @@ static gboolean replace_wm()
                       ob_screen);
             return FALSE;
         }
-        xerror_set_ignore(TRUE);
-        xerror_occured = FALSE;
+        obt_display_ignore_errors(TRUE);
 
         /* We want to find out when the current selection owner dies */
-        XSelectInput(ob_display, current_wm_sn_owner, StructureNotifyMask);
-        XSync(ob_display, FALSE);
+        XSelectInput(obt_display, current_wm_sn_owner, StructureNotifyMask);
+        XSync(obt_display, FALSE);
 
-        xerror_set_ignore(FALSE);
-        if (xerror_occured)
+        obt_display_ignore_errors(FALSE);
+        if (obt_display_error_occured)
             current_wm_sn_owner = None;
     }
 
     timestamp = event_get_server_time();
 
-    XSetSelectionOwner(ob_display, wm_sn_atom, screen_support_win,
+    XSetSelectionOwner(obt_display, wm_sn_atom, screen_support_win,
                        timestamp);
 
-    if (XGetSelectionOwner(ob_display, wm_sn_atom) != screen_support_win) {
+    if (XGetSelectionOwner(obt_display, wm_sn_atom) != screen_support_win) {
         g_message(_("Could not acquire window manager selection on screen %d"),
                   ob_screen);
         return FALSE;
@@ -125,7 +132,7 @@ static gboolean replace_wm()
       const gulong timeout = G_USEC_PER_SEC * 15; /* wait for 15s max */
 
       while (wait < timeout) {
-          if (XCheckWindowEvent(ob_display, current_wm_sn_owner,
+          if (XCheckWindowEvent(obt_display, current_wm_sn_owner,
                                 StructureNotifyMask, &event) &&
               event.type == DestroyNotify)
               break;
@@ -140,49 +147,45 @@ static gboolean replace_wm()
     }
 
     /* Send client message indicating that we are now the WM */
-    prop_message(RootWindow(ob_display, ob_screen), prop_atoms.manager,
-                 timestamp, wm_sn_atom, screen_support_win, 0,
-                 SubstructureNotifyMask);
+    obt_prop_message(ob_screen, obt_root(ob_screen), OBT_PROP_ATOM(MANAGER),
+                     timestamp, wm_sn_atom, screen_support_win, 0, 0,
+                     SubstructureNotifyMask);
 
     return TRUE;
 }
 
-gboolean screen_annex()
+gboolean screen_annex(void)
 {
     XSetWindowAttributes attrib;
     pid_t pid;
     gint i, num_support;
-    Atom *prop_atoms_start, *wm_supported_pos;
     gulong *supported;
 
     /* create the netwm support window */
     attrib.override_redirect = TRUE;
     attrib.event_mask = PropertyChangeMask;
-    screen_support_win = XCreateWindow(ob_display,
-                                       RootWindow(ob_display, ob_screen),
+    screen_support_win = XCreateWindow(obt_display, obt_root(ob_screen),
                                        -100, -100, 1, 1, 0,
                                        CopyFromParent, InputOutput,
                                        CopyFromParent,
                                        CWEventMask | CWOverrideRedirect,
                                        &attrib);
-    XMapWindow(ob_display, screen_support_win);
-    XLowerWindow(ob_display, screen_support_win);
+    XMapWindow(obt_display, screen_support_win);
+    XLowerWindow(obt_display, screen_support_win);
 
     if (!replace_wm()) {
-        XDestroyWindow(ob_display, screen_support_win);
+        XDestroyWindow(obt_display, screen_support_win);
         return FALSE;
     }
 
-    xerror_set_ignore(TRUE);
-    xerror_occured = FALSE;
-    XSelectInput(ob_display, RootWindow(ob_display, ob_screen),
-                 ROOT_EVENTMASK);
-    xerror_set_ignore(FALSE);
-    if (xerror_occured) {
+    obt_display_ignore_errors(TRUE);
+    XSelectInput(obt_display, obt_root(ob_screen), ROOT_EVENTMASK);
+    obt_display_ignore_errors(FALSE);
+    if (obt_display_error_occured) {
         g_message(_("A window manager is already running on screen %d"),
                   ob_screen);
 
-        XDestroyWindow(ob_display, screen_support_win);
+        XDestroyWindow(obt_display, screen_support_win);
         return FALSE;
     }
 
@@ -190,111 +193,110 @@ gboolean screen_annex()
 
     /* set the OPENBOX_PID hint */
     pid = getpid();
-    PROP_SET32(RootWindow(ob_display, ob_screen),
-               openbox_pid, cardinal, pid);
+    OBT_PROP_SET32(obt_root(ob_screen), OPENBOX_PID, CARDINAL, pid);
 
     /* set supporting window */
-    PROP_SET32(RootWindow(ob_display, ob_screen),
-               net_supporting_wm_check, window, screen_support_win);
+    OBT_PROP_SET32(obt_root(ob_screen),
+                   NET_SUPPORTING_WM_CHECK, WINDOW, screen_support_win);
 
     /* set properties on the supporting window */
-    PROP_SETS(screen_support_win, net_wm_name, "Openbox");
-    PROP_SET32(screen_support_win, net_supporting_wm_check,
-               window, screen_support_win);
+    OBT_PROP_SETS(screen_support_win, NET_WM_NAME, utf8, "Openbox");
+    OBT_PROP_SET32(screen_support_win, NET_SUPPORTING_WM_CHECK,
+                   WINDOW, screen_support_win);
 
     /* set the _NET_SUPPORTED_ATOMS hint */
 
-    /* this is all the atoms after net_supported in the prop_atoms struct */
-    prop_atoms_start = (Atom*)&prop_atoms;
-    wm_supported_pos = (Atom*)&(prop_atoms.net_supported);
-    num_support = sizeof(prop_atoms) / sizeof(Atom) -
-        (wm_supported_pos - prop_atoms_start) - 1;
+    /* this is all the atoms after NET_SUPPORTED in the ObtPropAtoms enum */
+    num_support = OBT_PROP_NUM_ATOMS - OBT_PROP_NET_SUPPORTED - 1;
     i = 0;
     supported = g_new(gulong, num_support);
-    supported[i++] = prop_atoms.net_supporting_wm_check;
-    supported[i++] = prop_atoms.net_wm_full_placement;
-    supported[i++] = prop_atoms.net_current_desktop;
-    supported[i++] = prop_atoms.net_number_of_desktops;
-    supported[i++] = prop_atoms.net_desktop_geometry;
-    supported[i++] = prop_atoms.net_desktop_viewport;
-    supported[i++] = prop_atoms.net_active_window;
-    supported[i++] = prop_atoms.net_workarea;
-    supported[i++] = prop_atoms.net_client_list;
-    supported[i++] = prop_atoms.net_client_list_stacking;
-    supported[i++] = prop_atoms.net_desktop_names;
-    supported[i++] = prop_atoms.net_close_window;
-    supported[i++] = prop_atoms.net_desktop_layout;
-    supported[i++] = prop_atoms.net_showing_desktop;
-    supported[i++] = prop_atoms.net_wm_name;
-    supported[i++] = prop_atoms.net_wm_visible_name;
-    supported[i++] = prop_atoms.net_wm_icon_name;
-    supported[i++] = prop_atoms.net_wm_visible_icon_name;
-    supported[i++] = prop_atoms.net_wm_desktop;
-    supported[i++] = prop_atoms.net_wm_strut;
-    supported[i++] = prop_atoms.net_wm_strut_partial;
-    supported[i++] = prop_atoms.net_wm_icon;
-    supported[i++] = prop_atoms.net_wm_icon_geometry;
-    supported[i++] = prop_atoms.net_wm_window_type;
-    supported[i++] = prop_atoms.net_wm_window_type_desktop;
-    supported[i++] = prop_atoms.net_wm_window_type_dock;
-    supported[i++] = prop_atoms.net_wm_window_type_toolbar;
-    supported[i++] = prop_atoms.net_wm_window_type_menu;
-    supported[i++] = prop_atoms.net_wm_window_type_utility;
-    supported[i++] = prop_atoms.net_wm_window_type_splash;
-    supported[i++] = prop_atoms.net_wm_window_type_dialog;
-    supported[i++] = prop_atoms.net_wm_window_type_normal;
-    supported[i++] = prop_atoms.net_wm_allowed_actions;
-    supported[i++] = prop_atoms.net_wm_action_move;
-    supported[i++] = prop_atoms.net_wm_action_resize;
-    supported[i++] = prop_atoms.net_wm_action_minimize;
-    supported[i++] = prop_atoms.net_wm_action_shade;
-    supported[i++] = prop_atoms.net_wm_action_maximize_horz;
-    supported[i++] = prop_atoms.net_wm_action_maximize_vert;
-    supported[i++] = prop_atoms.net_wm_action_fullscreen;
-    supported[i++] = prop_atoms.net_wm_action_change_desktop;
-    supported[i++] = prop_atoms.net_wm_action_close;
-    supported[i++] = prop_atoms.net_wm_action_above;
-    supported[i++] = prop_atoms.net_wm_action_below;
-    supported[i++] = prop_atoms.net_wm_state;
-    supported[i++] = prop_atoms.net_wm_state_modal;
-    supported[i++] = prop_atoms.net_wm_state_maximized_vert;
-    supported[i++] = prop_atoms.net_wm_state_maximized_horz;
-    supported[i++] = prop_atoms.net_wm_state_shaded;
-    supported[i++] = prop_atoms.net_wm_state_skip_taskbar;
-    supported[i++] = prop_atoms.net_wm_state_skip_pager;
-    supported[i++] = prop_atoms.net_wm_state_hidden;
-    supported[i++] = prop_atoms.net_wm_state_fullscreen;
-    supported[i++] = prop_atoms.net_wm_state_above;
-    supported[i++] = prop_atoms.net_wm_state_below;
-    supported[i++] = prop_atoms.net_wm_state_demands_attention;
-    supported[i++] = prop_atoms.net_moveresize_window;
-    supported[i++] = prop_atoms.net_wm_moveresize;
-    supported[i++] = prop_atoms.net_wm_user_time;
+    supported[i++] = OBT_PROP_ATOM(NET_SUPPORTING_WM_CHECK);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_FULL_PLACEMENT);
+    supported[i++] = OBT_PROP_ATOM(NET_CURRENT_DESKTOP);
+    supported[i++] = OBT_PROP_ATOM(NET_NUMBER_OF_DESKTOPS);
+    supported[i++] = OBT_PROP_ATOM(NET_DESKTOP_GEOMETRY);
+    supported[i++] = OBT_PROP_ATOM(NET_DESKTOP_VIEWPORT);
+    supported[i++] = OBT_PROP_ATOM(NET_ACTIVE_WINDOW);
+    supported[i++] = OBT_PROP_ATOM(NET_WORKAREA);
+    supported[i++] = OBT_PROP_ATOM(NET_CLIENT_LIST);
+    supported[i++] = OBT_PROP_ATOM(NET_CLIENT_LIST_STACKING);
+    supported[i++] = OBT_PROP_ATOM(NET_DESKTOP_NAMES);
+    supported[i++] = OBT_PROP_ATOM(NET_CLOSE_WINDOW);
+    supported[i++] = OBT_PROP_ATOM(NET_DESKTOP_LAYOUT);
+    supported[i++] = OBT_PROP_ATOM(NET_SHOWING_DESKTOP);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_NAME);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_VISIBLE_NAME);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ICON_NAME);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_VISIBLE_ICON_NAME);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_DESKTOP);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STRUT);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STRUT_PARTIAL);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ICON);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ICON_GEOMETRY);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DESKTOP);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DOCK);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_TOOLBAR);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_MENU);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_UTILITY);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_SPLASH);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DIALOG);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_NORMAL);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ALLOWED_ACTIONS);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MOVE);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_RESIZE);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MINIMIZE);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_SHADE);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MAXIMIZE_HORZ);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MAXIMIZE_VERT);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_FULLSCREEN);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_CHANGE_DESKTOP);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_CLOSE);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_ABOVE);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_BELOW);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_MODAL);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_SHADED);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_HIDDEN);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_ABOVE);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_BELOW);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION);
+    supported[i++] = OBT_PROP_ATOM(NET_MOVERESIZE_WINDOW);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_MOVERESIZE);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_USER_TIME);
 /*
-    supported[i++] = prop_atoms.net_wm_user_time_window;
+    supported[i++] = OBT_PROP_ATOM(NET_WM_USER_TIME_WINDOW);
 */
-    supported[i++] = prop_atoms.net_frame_extents;
-    supported[i++] = prop_atoms.net_request_frame_extents;
-    supported[i++] = prop_atoms.net_restack_window;
-    supported[i++] = prop_atoms.net_startup_id;
+    supported[i++] = OBT_PROP_ATOM(NET_FRAME_EXTENTS);
+    supported[i++] = OBT_PROP_ATOM(NET_REQUEST_FRAME_EXTENTS);
+    supported[i++] = OBT_PROP_ATOM(NET_RESTACK_WINDOW);
+    supported[i++] = OBT_PROP_ATOM(NET_STARTUP_ID);
 #ifdef SYNC
-    supported[i++] = prop_atoms.net_wm_sync_request;
-    supported[i++] = prop_atoms.net_wm_sync_request_counter;
+    supported[i++] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST_COUNTER);
 #endif
-
-    supported[i++] = prop_atoms.kde_wm_change_state;
-    supported[i++] = prop_atoms.kde_net_wm_frame_strut;
-    supported[i++] = prop_atoms.kde_net_wm_window_type_override;
-
-    supported[i++] = prop_atoms.ob_wm_action_undecorate;
-    supported[i++] = prop_atoms.ob_wm_state_undecorated;
-    supported[i++] = prop_atoms.openbox_pid;
-    supported[i++] = prop_atoms.ob_theme;
-    supported[i++] = prop_atoms.ob_control;
+    supported[i++] = OBT_PROP_ATOM(NET_WM_PID);
+    supported[i++] = OBT_PROP_ATOM(NET_WM_PING);
+
+    supported[i++] = OBT_PROP_ATOM(KDE_WM_CHANGE_STATE);
+    supported[i++] = OBT_PROP_ATOM(KDE_NET_WM_FRAME_STRUT);
+    supported[i++] = OBT_PROP_ATOM(KDE_NET_WM_WINDOW_TYPE_OVERRIDE);
+
+    supported[i++] = OBT_PROP_ATOM(OB_WM_ACTION_UNDECORATE);
+    supported[i++] = OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED);
+    supported[i++] = OBT_PROP_ATOM(OPENBOX_PID);
+    supported[i++] = OBT_PROP_ATOM(OB_THEME);
+    supported[i++] = OBT_PROP_ATOM(OB_CONFIG_FILE);
+    supported[i++] = OBT_PROP_ATOM(OB_CONTROL);
     g_assert(i == num_support);
 
-    PROP_SETA32(RootWindow(ob_display, ob_screen),
-                net_supported, atom, supported, num_support);
+    OBT_PROP_SETA32(obt_root(ob_screen),
+                    NET_SUPPORTED, ATOM, supported, num_support);
     g_free(supported);
 
     screen_tell_ksplash();
@@ -302,7 +304,7 @@ gboolean screen_annex()
     return TRUE;
 }
 
-static void screen_tell_ksplash()
+static void screen_tell_ksplash(void)
 {
     XEvent e;
     char **argv;
@@ -326,14 +328,14 @@ static void screen_tell_ksplash()
        hear it anyways. perhaps it is for old ksplash. or new ksplash. or
        something. oh well. */
     e.xclient.type = ClientMessage;
-    e.xclient.display = ob_display;
-    e.xclient.window = RootWindow(ob_display, ob_screen);
+    e.xclient.display = obt_display;
+    e.xclient.window = obt_root(ob_screen);
     e.xclient.message_type =
-        XInternAtom(ob_display, "_KDE_SPLASH_PROGRESS", False );
+        XInternAtom(obt_display, "_KDE_SPLASH_PROGRESS", False);
     e.xclient.format = 8;
     strcpy(e.xclient.data.b, "wm started");
-    XSendEvent(ob_display, RootWindow(ob_display, ob_screen),
-               False, SubstructureNotifyMask, &e );
+    XSendEvent(obt_display, obt_root(ob_screen),
+               False, SubstructureNotifyMask, &e);
 }
 
 void screen_startup(gboolean reconfig)
@@ -342,24 +344,29 @@ void screen_startup(gboolean reconfig)
     guint32 d;
     gboolean namesexist = FALSE;
 
-    desktop_cycle_popup = pager_popup_new(FALSE);
-    pager_popup_height(desktop_cycle_popup, POPUP_HEIGHT);
-
     if (reconfig) {
-        /* update the pager popup's width */
-        pager_popup_text_width_to_strings(desktop_cycle_popup,
-                                          screen_desktop_names,
-                                          screen_num_desktops);
+        guint i;
+        desktop_popup = g_new(ObPagerPopup*, screen_num_monitors);
+        for (i = 0; i < screen_num_monitors; i++) {
+            desktop_popup[i] = pager_popup_new();
+            pager_popup_height(desktop_popup[i], POPUP_HEIGHT);
+
+            /* update the pager popup's width */
+            pager_popup_text_width_to_strings(desktop_popup[i],
+                                              screen_desktop_names,
+                                              screen_num_desktops);
+        }
+
         return;
+    } else {
+        desktop_popup = NULL;
     }
 
     /* get the initial size */
     screen_resize();
 
     /* have names already been set for the desktops? */
-    if (PROP_GETSS(RootWindow(ob_display, ob_screen),
-                   net_desktop_names, utf8, &names))
-    {
+    if (OBT_PROP_GETSS(obt_root(ob_screen), NET_DESKTOP_NAMES, utf8, &names)) {
         g_strfreev(names);
         namesexist = TRUE;
     }
@@ -380,7 +387,8 @@ void screen_startup(gboolean reconfig)
             names[i] = g_strdup(it->data);
 
         /* set the root window property */
-        PROP_SETSS(RootWindow(ob_display, ob_screen), net_desktop_names,names);
+        OBT_PROP_SETSS(obt_root(ob_screen),
+                       NET_DESKTOP_NAMES, utf8, (const gchar**)names);
 
         g_strfreev(names);
     }
@@ -390,9 +398,19 @@ void screen_startup(gboolean reconfig)
        this will also set the default names from the config file up for
        desktops that don't have names yet */
     screen_num_desktops = 0;
-    if (PROP_GET32(RootWindow(ob_display, ob_screen),
-                   net_number_of_desktops, cardinal, &d))
+    if (OBT_PROP_GET32(obt_root(ob_screen),
+                       NET_NUMBER_OF_DESKTOPS, CARDINAL, &d))
+    {
+        if (d != config_desktops_num) {
+            /* TRANSLATORS: If you need to specify a different order of the
+               arguments, you can use %1$d for the first one and %2$d for the
+               second one. For example,
+               "The current session has %2$d desktops, but Openbox is configured for %1$d ..." */
+            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),
+                      config_desktops_num, d);
+        }
         screen_set_num_desktops(d);
+    }
     /* restore from session if possible */
     else if (session_num_desktops)
         screen_set_num_desktops(session_num_desktops);
@@ -401,8 +419,8 @@ void screen_startup(gboolean reconfig)
 
     screen_desktop = screen_num_desktops;  /* something invalid */
     /* start on the current desktop when a wm was already running */
-    if (PROP_GET32(RootWindow(ob_display, ob_screen),
-                   net_current_desktop, cardinal, &d) &&
+    if (OBT_PROP_GET32(obt_root(ob_screen),
+                       NET_CURRENT_DESKTOP, CARDINAL, &d) &&
         d < screen_num_desktops)
     {
         screen_set_desktop(d, FALSE);
@@ -416,8 +434,8 @@ void screen_startup(gboolean reconfig)
 
     /* don't start in showing-desktop mode */
     screen_showing_desktop = FALSE;
-    PROP_SET32(RootWindow(ob_display, ob_screen),
-               net_showing_desktop, cardinal, screen_showing_desktop);
+    OBT_PROP_SET32(obt_root(ob_screen),
+                   NET_SHOWING_DESKTOP, CARDINAL, screen_showing_desktop);
 
     if (session_desktop_layout_present &&
         screen_validate_layout(&session_desktop_layout))
@@ -430,36 +448,40 @@ void screen_startup(gboolean reconfig)
 
 void screen_shutdown(gboolean reconfig)
 {
-    pager_popup_free(desktop_cycle_popup);
+    guint i;
+
+    for (i = 0; i < screen_num_monitors; i++) {
+        pager_popup_free(desktop_popup[i]);
+    }
+    g_free(desktop_popup);
 
     if (reconfig)
         return;
 
-    XSelectInput(ob_display, RootWindow(ob_display, ob_screen),
-                 NoEventMask);
+    XSelectInput(obt_display, obt_root(ob_screen), NoEventMask);
 
     /* we're not running here no more! */
-    PROP_ERASE(RootWindow(ob_display, ob_screen), openbox_pid);
+    OBT_PROP_ERASE(obt_root(ob_screen), OPENBOX_PID);
     /* not without us */
-    PROP_ERASE(RootWindow(ob_display, ob_screen), net_supported);
+    OBT_PROP_ERASE(obt_root(ob_screen), NET_SUPPORTED);
     /* don't keep this mode */
-    PROP_ERASE(RootWindow(ob_display, ob_screen), net_showing_desktop);
+    OBT_PROP_ERASE(obt_root(ob_screen), NET_SHOWING_DESKTOP);
 
-    XDestroyWindow(ob_display, screen_support_win);
+    XDestroyWindow(obt_display, screen_support_win);
 
     g_strfreev(screen_desktop_names);
     screen_desktop_names = NULL;
 }
 
-void screen_resize()
+void screen_resize(void)
 {
     static gint oldw = 0, oldh = 0;
     gint w, h;
     GList *it;
     gulong geometry[2];
 
-    w = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen));
-    h = HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen));
+    w = WidthOfScreen(ScreenOfDisplay(obt_display, ob_screen));
+    h = HeightOfScreen(ScreenOfDisplay(obt_display, ob_screen));
 
     if (w == oldw && h == oldh) return;
 
@@ -468,10 +490,10 @@ void screen_resize()
     /* Set the _NET_DESKTOP_GEOMETRY hint */
     screen_physical_size.width = geometry[0] = w;
     screen_physical_size.height = geometry[1] = h;
-    PROP_SETA32(RootWindow(ob_display, ob_screen),
-                net_desktop_geometry, cardinal, geometry, 2);
+    OBT_PROP_SETA32(obt_root(ob_screen),
+                    NET_DESKTOP_GEOMETRY, CARDINAL, geometry, 2);
 
-    if (ob_state() == OB_STATE_STARTING)
+    if (ob_state() != OB_STATE_RUNNING)
         return;
 
     screen_update_areas();
@@ -493,13 +515,12 @@ void screen_set_num_desktops(guint num)
 
     old = screen_num_desktops;
     screen_num_desktops = num;
-    PROP_SET32(RootWindow(ob_display, ob_screen),
-               net_number_of_desktops, cardinal, num);
+    OBT_PROP_SET32(obt_root(ob_screen), NET_NUMBER_OF_DESKTOPS, CARDINAL, num);
 
     /* set the viewport hint */
     viewport = g_new0(gulong, num * 2);
-    PROP_SETA32(RootWindow(ob_display, ob_screen),
-                net_desktop_viewport, cardinal, viewport, num * 2);
+    OBT_PROP_SETA32(obt_root(ob_screen),
+                    NET_DESKTOP_VIEWPORT, CARDINAL, viewport, num * 2);
     g_free(viewport);
 
     /* the number of rows/columns will differ */
@@ -521,12 +542,13 @@ void screen_set_num_desktops(guint num)
                 stacking_raise(CLIENT_AS_WINDOW(c));
         }
     }
+    g_list_free(stacking_copy);
 
     /* change our struts/area to match (after moving windows) */
     screen_update_areas();
 
     /* may be some unnamed desktops that we need to fill in with names
-     (after updating the areas so the popup can resize) */
+       (after updating the areas so the popup can resize) */
     screen_update_desktop_names();
 
     /* change our desktop if we're on one that no longer exists! */
@@ -534,44 +556,11 @@ void screen_set_num_desktops(guint num)
         screen_set_desktop(num - 1, TRUE);
 }
 
-void screen_set_desktop(guint num, gboolean dofocus)
+static void screen_fallback_focus(void)
 {
     ObClient *c;
-    GList *it;
-    guint old;
-    gulong ignore_start;
     gboolean allow_omni;
 
-    g_assert(num < screen_num_desktops);
-
-    old = screen_desktop;
-    screen_desktop = num;
-
-    if (old == num) return;
-
-    PROP_SET32(RootWindow(ob_display, ob_screen),
-               net_current_desktop, cardinal, num);
-
-    screen_last_desktop = old;
-
-    ob_debug("Moving to desktop %d\n", num+1);
-
-    /* ignore enter events caused by the move */
-    ignore_start = event_start_ignore_all_enters();
-
-    if (moveresize_client)
-        client_set_desktop(moveresize_client, num, TRUE, FALSE);
-
-    /* show windows before hiding the rest to lessen the enter/leave events */
-
-    /* show windows from top to bottom */
-    for (it = stacking_list; it; it = g_list_next(it)) {
-        if (WINDOW_IS_CLIENT(it->data)) {
-            ObClient *c = it->data;
-            client_show(c);
-        }
-    }
-
     /* only allow omnipresent windows to get focus on desktop change if
        an omnipresent window is already focused (it'll keep focus probably, but
        maybe not depending on mouse-focus options) */
@@ -581,7 +570,7 @@ void screen_set_desktop(guint num, gboolean dofocus)
     /* the client moved there already so don't move focus. prevent flicker
        on sendtodesktop + follow */
     if (focus_client && focus_client->desktop == screen_desktop)
-        dofocus = FALSE;
+        return;
 
     /* have to try focus here because when you leave an empty desktop
        there is no focus out to watch for. also, we have different rules
@@ -591,7 +580,8 @@ void screen_set_desktop(guint num, gboolean dofocus)
        do this before hiding the windows so if helper windows are coming
        with us, they don't get hidden
     */
-    if (dofocus && (c = focus_fallback(TRUE, !config_focus_last, allow_omni)))
+    if ((c = focus_fallback(TRUE, !config_focus_last, allow_omni,
+                            !allow_omni)))
     {
         /* only do the flicker reducing stuff ahead of time if we are going
            to call xsetinputfocus on the window ourselves. otherwise there is
@@ -605,6 +595,119 @@ void screen_set_desktop(guint num, gboolean dofocus)
             client_bring_helper_windows(c);
         }
     }
+}
+
+static gboolean last_desktop_func(gpointer data)
+{
+    screen_desktop_timeout = TRUE;
+    return FALSE;
+}
+
+void screen_set_desktop(guint num, gboolean dofocus)
+{
+    GList *it;
+    guint previous;
+    gulong ignore_start;
+
+    g_assert(num < screen_num_desktops);
+
+    previous = screen_desktop;
+    screen_desktop = num;
+
+    if (previous == num) return;
+
+    OBT_PROP_SET32(obt_root(ob_screen), NET_CURRENT_DESKTOP, CARDINAL, num);
+
+    /* This whole thing decides when/how to save the screen_last_desktop so
+       that it can be restored later if you want */
+    if (screen_desktop_timeout) {
+        /* If screen_desktop_timeout is true, then we've been on this desktop
+           long enough and we can save it as the last desktop. */
+
+        if (screen_last_desktop == previous)
+            /* this is the startup state only */
+            screen_old_desktop = screen_desktop;
+        else {
+            /* save the "last desktop" as the "old desktop" */
+            screen_old_desktop = screen_last_desktop;
+            /* save the desktop we're coming from as the "last desktop" */
+            screen_last_desktop = previous;
+        }
+    }
+    else {
+        /* If screen_desktop_timeout is false, then we just got to this desktop
+           and we are moving away again. */
+
+        if (screen_desktop == screen_last_desktop) {
+            /* If we are moving to the "last desktop" .. */
+            if (previous == screen_old_desktop) {
+                /* .. from the "old desktop", change the last desktop to
+                   be where we are coming from */
+                screen_last_desktop = screen_old_desktop;
+            }
+            else if (screen_last_desktop == screen_old_desktop) {
+                /* .. and also to the "old desktop", change the "last
+                   desktop" to be where we are coming from */
+                screen_last_desktop = previous;
+            }
+            else {
+                /* .. from some other desktop, then set the "last desktop" to
+                   be the saved "old desktop", i.e. where we were before the
+                   "last desktop" */
+                screen_last_desktop = screen_old_desktop;
+            }
+        }
+        else {
+            /* If we are moving to any desktop besides the "last desktop"..
+               (this is the normal case) */
+            if (screen_desktop == screen_old_desktop) {
+                /* If moving to the "old desktop", which is not the
+                   "last desktop", don't save anything */
+            }
+            else if (previous == screen_old_desktop) {
+                /* If moving from the "old desktop", and not to the
+                   "last desktop", don't save anything */
+            }
+            else if (screen_last_desktop == screen_old_desktop) {
+                /* If the "last desktop" is the same as "old desktop" and
+                   you're not moving to the "last desktop" then save where
+                   we're coming from as the "last desktop" */
+                screen_last_desktop = previous;
+            }
+            else {
+                /* If the "last desktop" is different from the "old desktop"
+                   and you're not moving to the "last desktop", then don't save
+                   anything */
+            }
+        }
+    }
+    screen_desktop_timeout = FALSE;
+    obt_main_loop_timeout_remove(ob_main_loop, last_desktop_func);
+    obt_main_loop_timeout_add(ob_main_loop, REMEMBER_LAST_DESKTOP_TIME,
+                              last_desktop_func, NULL, NULL, NULL);
+
+    ob_debug("Moving to desktop %d", num+1);
+
+    if (ob_state() == OB_STATE_RUNNING)
+        screen_show_desktop_popup(screen_desktop);
+
+    /* ignore enter events caused by the move */
+    ignore_start = event_start_ignore_all_enters();
+
+    if (moveresize_client)
+        client_set_desktop(moveresize_client, num, TRUE, FALSE);
+
+    /* show windows before hiding the rest to lessen the enter/leave events */
+
+    /* show windows from top to bottom */
+    for (it = stacking_list; it; it = g_list_next(it)) {
+        if (WINDOW_IS_CLIENT(it->data)) {
+            ObClient *c = it->data;
+            client_show(c);
+        }
+    }
+
+    if (dofocus) screen_fallback_focus();
 
     /* hide windows from bottom to top */
     for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
@@ -618,10 +721,17 @@ void screen_set_desktop(guint num, gboolean dofocus)
 
     if (event_curtime != CurrentTime)
         screen_desktop_user_time = event_curtime;
+
+    hooks_queue(OB_HOOK_SCREEN_DESK_CHANGE, NULL);
 }
 
 void screen_add_desktop(gboolean current)
 {
+    gulong ignore_start;
+
+    /* ignore enter events caused by this */
+    ignore_start = event_start_ignore_all_enters();
+
     screen_set_num_desktops(screen_num_desktops+1);
 
     /* move all the clients over */
@@ -635,20 +745,26 @@ void screen_add_desktop(gboolean current)
                    parent - which will have to be on the same desktop */
                 !client_direct_parent(c))
             {
-                ob_debug("moving window %s\n", c->title);
+                ob_debug("moving window %s", c->title);
                 client_set_desktop(c, c->desktop+1, FALSE, TRUE);
             }
         }
     }
+
+    event_end_ignore_all_enters(ignore_start);
 }
 
 void screen_remove_desktop(gboolean current)
 {
     guint rmdesktop, movedesktop;
     GList *it, *stacking_copy;
+    gulong ignore_start;
 
     if (screen_num_desktops <= 1) return;
 
+    /* ignore enter events caused by this */
+    ignore_start = event_start_ignore_all_enters();
+
     /* what desktop are we removing and moving to? */
     if (current)
         rmdesktop = screen_desktop;
@@ -670,7 +786,7 @@ void screen_remove_desktop(gboolean current)
                    parent - which will have to be on the same desktop */
                 !client_direct_parent(c))
             {
-                ob_debug("moving window %s\n", c->title);
+                ob_debug("moving window %s", c->title);
                 client_set_desktop(c, c->desktop - 1, TRUE, TRUE);
             }
             /* raise all the windows that are on the current desktop which
@@ -680,20 +796,21 @@ void screen_remove_desktop(gboolean current)
                 (d == DESKTOP_ALL || d == screen_desktop))
             {
                 stacking_raise(CLIENT_AS_WINDOW(c));
-                ob_debug("raising window %s\n", c->title);
+                ob_debug("raising window %s", c->title);
             }
         }
     }
+    g_list_free(stacking_copy);
 
-    /* act like we're changing desktops */
+    /* fallback focus like we're changing desktops */
     if (screen_desktop < screen_num_desktops - 1) {
-        gint d = screen_desktop;
-        screen_desktop = screen_last_desktop;
-        screen_set_desktop(d, TRUE);
-        ob_debug("fake desktop change\n");
+        screen_fallback_focus();
+        ob_debug("fake desktop change");
     }
 
     screen_set_num_desktops(screen_num_desktops-1);
+
+    event_end_ignore_all_enters(ignore_start);
 }
 
 static void get_row_col(guint d, guint *r, guint *c)
@@ -804,24 +921,53 @@ static guint translate_row_col(guint r, guint c)
     return 0;
 }
 
-void screen_desktop_popup(guint d, gboolean show)
+static gboolean hide_desktop_popup_func(gpointer data)
+{
+    guint i;
+
+    for (i = 0; i < screen_num_monitors; i++) {
+        pager_popup_hide(desktop_popup[i]);
+    }
+    return FALSE; /* don't repeat */
+}
+
+void screen_show_desktop_popup(guint d)
 {
     Rect *a;
+    guint i;
 
-    if (!show) {
-        pager_popup_hide(desktop_cycle_popup);
-    } else {
-        a = screen_physical_area_active();
-        pager_popup_position(desktop_cycle_popup, CenterGravity,
+    /* 0 means don't show the popup */
+    if (!config_desktop_popup_time) return;
+
+    for (i = 0; i < screen_num_monitors; i++) {
+        a = screen_physical_area_monitor(i);
+        pager_popup_position(desktop_popup[i], CenterGravity,
                              a->x + a->width / 2, a->y + a->height / 2);
-        pager_popup_icon_size_multiplier(desktop_cycle_popup,
+        pager_popup_icon_size_multiplier(desktop_popup[i],
                                          (screen_desktop_layout.columns /
                                           screen_desktop_layout.rows) / 2,
                                          (screen_desktop_layout.rows/
                                           screen_desktop_layout.columns) / 2);
-        pager_popup_max_width(desktop_cycle_popup,
+        pager_popup_max_width(desktop_popup[i],
                               MAX(a->width/3, POPUP_WIDTH));
-        pager_popup_show(desktop_cycle_popup, screen_desktop_names[d], d);
+        pager_popup_show(desktop_popup[i], screen_desktop_names[d], d);
+
+        obt_main_loop_timeout_remove(ob_main_loop, hide_desktop_popup_func);
+        obt_main_loop_timeout_add(ob_main_loop, config_desktop_popup_time * 1000,
+                                  hide_desktop_popup_func, desktop_popup[i],
+                                  g_direct_equal, NULL);
+        g_free(a);
+    }
+}
+
+void screen_hide_desktop_popup(void)
+{
+    guint i;
+
+    for (i = 0; i < screen_num_monitors; i++) {
+        obt_main_loop_timeout_remove_data(ob_main_loop, hide_desktop_popup_func,
+                                          desktop_popup[i], FALSE);
+        pager_popup_hide(desktop_popup[i]);
     }
 }
 
@@ -931,30 +1077,6 @@ guint screen_find_desktop(guint from, ObDirection dir,
     return d;
 }
 
-guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear,
-                           gboolean dialog, gboolean done, gboolean cancel)
-{
-    static guint d = (guint)-1;
-    guint ret;
-
-    if (d == (guint)-1)
-        d = screen_desktop;
-
-    if ((!cancel && !done) || !dialog)
-        d = screen_find_desktop(d, dir, wrap, linear);
-
-    if (dialog && !cancel && !done)
-        screen_desktop_popup(d, TRUE);
-    else
-        screen_desktop_popup(0, FALSE);
-    ret = d;
-
-    if (!dialog || cancel || done)
-        d = (guint)-1;
-
-    return ret;
-}
-
 static gboolean screen_validate_layout(ObDesktopLayout *l)
 {
     if (l->columns == 0 && l->rows == 0) /* both 0's is bad data.. */
@@ -992,7 +1114,7 @@ static gboolean screen_validate_layout(ObDesktopLayout *l)
     return TRUE;
 }
 
-void screen_update_layout()
+void screen_update_layout(void)
 
 {
     ObDesktopLayout l;
@@ -1004,13 +1126,13 @@ void screen_update_layout()
     screen_desktop_layout.rows = 1;
     screen_desktop_layout.columns = screen_num_desktops;
 
-    if (PROP_GETA32(RootWindow(ob_display, ob_screen),
-                    net_desktop_layout, cardinal, &data, &num)) {
+    if (OBT_PROP_GETA32(obt_root(ob_screen),
+                        NET_DESKTOP_LAYOUT, CARDINAL, &data, &num)) {
         if (num == 3 || num == 4) {
 
-            if (data[0] == prop_atoms.net_wm_orientation_vert)
+            if (data[0] == OBT_PROP_ATOM(NET_WM_ORIENTATION_VERT))
                 l.orientation = OB_ORIENTATION_VERT;
-            else if (data[0] == prop_atoms.net_wm_orientation_horz)
+            else if (data[0] == OBT_PROP_ATOM(NET_WM_ORIENTATION_HORZ))
                 l.orientation = OB_ORIENTATION_HORZ;
             else
                 return;
@@ -1018,13 +1140,13 @@ void screen_update_layout()
             if (num < 4)
                 l.start_corner = OB_CORNER_TOPLEFT;
             else {
-                if (data[3] == prop_atoms.net_wm_topleft)
+                if (data[3] == OBT_PROP_ATOM(NET_WM_TOPLEFT))
                     l.start_corner = OB_CORNER_TOPLEFT;
-                else if (data[3] == prop_atoms.net_wm_topright)
+                else if (data[3] == OBT_PROP_ATOM(NET_WM_TOPRIGHT))
                     l.start_corner = OB_CORNER_TOPRIGHT;
-                else if (data[3] == prop_atoms.net_wm_bottomright)
+                else if (data[3] == OBT_PROP_ATOM(NET_WM_BOTTOMRIGHT))
                     l.start_corner = OB_CORNER_BOTTOMRIGHT;
-                else if (data[3] == prop_atoms.net_wm_bottomleft)
+                else if (data[3] == OBT_PROP_ATOM(NET_WM_BOTTOMLEFT))
                     l.start_corner = OB_CORNER_BOTTOMLEFT;
                 else
                     return;
@@ -1041,7 +1163,7 @@ void screen_update_layout()
     }
 }
 
-void screen_update_desktop_names()
+void screen_update_desktop_names(void)
 {
     guint i;
 
@@ -1049,8 +1171,8 @@ void screen_update_desktop_names()
     g_strfreev(screen_desktop_names);
     screen_desktop_names = NULL;
 
-    if (PROP_GETSS(RootWindow(ob_display, ob_screen),
-                   net_desktop_names, utf8, &screen_desktop_names))
+    if (OBT_PROP_GETSS(obt_root(ob_screen),
+                       NET_DESKTOP_NAMES, utf8, &screen_desktop_names))
         for (i = 0; screen_desktop_names[i] && i < screen_num_desktops; ++i);
     else
         i = 0;
@@ -1076,14 +1198,16 @@ void screen_update_desktop_names()
 
         /* if we changed any names, then set the root property so we can
            all agree on the names */
-        PROP_SETSS(RootWindow(ob_display, ob_screen), net_desktop_names,
-                   screen_desktop_names);
+        OBT_PROP_SETSS(obt_root(ob_screen), NET_DESKTOP_NAMES,
+                       utf8, (const gchar**)screen_desktop_names);
     }
 
     /* resize the pager for these names */
-    pager_popup_text_width_to_strings(desktop_cycle_popup,
-                                      screen_desktop_names,
-                                      screen_num_desktops);
+    for (i = 0; i < screen_num_monitors; i++) {
+        pager_popup_text_width_to_strings(desktop_popup[i],
+                                          screen_desktop_names,
+                                          screen_num_desktops);
+    }
 }
 
 void screen_show_desktop(gboolean show, ObClient *show_only)
@@ -1131,7 +1255,7 @@ void screen_show_desktop(gboolean show, ObClient *show_only)
     else if (!show_only) {
         ObClient *c;
 
-        if ((c = focus_fallback(TRUE, FALSE, TRUE))) {
+        if ((c = focus_fallback(TRUE, FALSE, TRUE, FALSE))) {
             /* only do the flicker reducing stuff ahead of time if we are going
                to call xsetinputfocus on the window ourselves. otherwise there
                is no guarantee the window will actually take focus.. */
@@ -1144,24 +1268,23 @@ void screen_show_desktop(gboolean show, ObClient *show_only)
     }
 
     show = !!show; /* make it boolean */
-    PROP_SET32(RootWindow(ob_display, ob_screen),
-               net_showing_desktop, cardinal, show);
+    OBT_PROP_SET32(obt_root(ob_screen), NET_SHOWING_DESKTOP, CARDINAL, show);
 }
 
 void screen_install_colormap(ObClient *client, gboolean install)
 {
     if (client == NULL || client->colormap == None) {
         if (install)
-            XInstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst));
+            XInstallColormap(obt_display, RrColormap(ob_rr_inst));
         else
-            XUninstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst));
+            XUninstallColormap(obt_display, RrColormap(ob_rr_inst));
     } else {
-        xerror_set_ignore(TRUE);
+        obt_display_ignore_errors(TRUE);
         if (install)
-            XInstallColormap(RrDisplay(ob_rr_inst), client->colormap);
+            XInstallColormap(obt_display, client->colormap);
         else
-            XUninstallColormap(RrDisplay(ob_rr_inst), client->colormap);
-        xerror_set_ignore(FALSE);
+            XUninstallColormap(obt_display, client->colormap);
+        obt_display_ignore_errors(FALSE);
     }
 }
 
@@ -1203,7 +1326,56 @@ typedef struct {
     } \
 }
 
-void screen_update_areas()
+static void get_xinerama_screens(Rect **xin_areas, guint *nxin)
+{
+    guint i;
+    gint n, l, r, t, b;
+#ifdef XINERAMA
+    XineramaScreenInfo *info;
+#endif
+
+    if (ob_debug_xinerama) {
+        gint w = WidthOfScreen(ScreenOfDisplay(obt_display, ob_screen));
+        gint h = HeightOfScreen(ScreenOfDisplay(obt_display, ob_screen));
+        *nxin = 2;
+        *xin_areas = g_new(Rect, *nxin + 1);
+        RECT_SET((*xin_areas)[0], 0, 0, w/2, h);
+        RECT_SET((*xin_areas)[1], w/2, 0, w-(w/2), h);
+    }
+#ifdef XINERAMA
+    else if (obt_display_extension_xinerama &&
+             (info = XineramaQueryScreens(obt_display, &n))) {
+        *nxin = n;
+        *xin_areas = g_new(Rect, *nxin + 1);
+        for (i = 0; i < *nxin; ++i)
+            RECT_SET((*xin_areas)[i], info[i].x_org, info[i].y_org,
+                     info[i].width, info[i].height);
+        XFree(info);
+    }
+#endif
+    else {
+        *nxin = 1;
+        *xin_areas = g_new(Rect, *nxin + 1);
+        RECT_SET((*xin_areas)[0], 0, 0,
+                 WidthOfScreen(ScreenOfDisplay(obt_display, ob_screen)),
+                 HeightOfScreen(ScreenOfDisplay(obt_display, ob_screen)));
+    }
+
+    /* returns one extra with the total area in it */
+    l = (*xin_areas)[0].x;
+    t = (*xin_areas)[0].y;
+    r = (*xin_areas)[0].x + (*xin_areas)[0].width - 1;
+    b = (*xin_areas)[0].y + (*xin_areas)[0].height - 1;
+    for (i = 1; i < *nxin; ++i) {
+        l = MIN(l, (*xin_areas)[i].x);
+        t = MIN(l, (*xin_areas)[i].y);
+        r = MAX(r, (*xin_areas)[i].x + (*xin_areas)[i].width - 1);
+        b = MAX(b, (*xin_areas)[i].y + (*xin_areas)[i].height - 1);
+    }
+    RECT_SET((*xin_areas)[*nxin], l, t, r - l + 1, b - t + 1);
+}
+
+void screen_update_areas(void)
 {
     guint i, j;
     gulong *dims;
@@ -1211,7 +1383,21 @@ void screen_update_areas()
     GSList *sit;
 
     g_free(monitor_area);
-    extensions_xinerama_screens(&monitor_area, &screen_num_monitors);
+    get_xinerama_screens(&monitor_area, &screen_num_monitors);
+
+    if (!desktop_popup) {
+        desktop_popup = g_new(ObPagerPopup*, screen_num_monitors);
+        for (i = 0; i < screen_num_monitors; i++) {
+            desktop_popup[i] = pager_popup_new();
+            pager_popup_height(desktop_popup[i], POPUP_HEIGHT);
+
+            if (screen_desktop_names)
+                /* update the pager popup's width */
+                pager_popup_text_width_to_strings(desktop_popup[i],
+                                                  screen_desktop_names,
+                                                  screen_num_desktops);
+        }
+    }
 
     /* set up the user-specified margins */
     config_margins.top_start = RECT_LEFT(monitor_area[screen_num_monitors]);
@@ -1310,6 +1496,15 @@ void screen_update_areas()
                     b = MAX(b, s->strut->bottom);
             }
 
+            if (l) l += RECT_LEFT  (monitor_area[screen_num_monitors])
+                        - RECT_LEFT  (monitor_area[i]);
+            if (t) t += RECT_TOP   (monitor_area[screen_num_monitors])
+                        - RECT_TOP   (monitor_area[i]);
+            if (r) r -= RECT_RIGHT (monitor_area[screen_num_monitors])
+                        - RECT_RIGHT (monitor_area[i]);
+            if (b) b -= RECT_BOTTOM(monitor_area[screen_num_monitors])
+                        - RECT_BOTTOM(monitor_area[i]);
+
             /* based on these margins, set the work area for the
                monitor/desktop */
             dims[(i * screen_num_desktops + j) * 4 + 0] += l;
@@ -1320,8 +1515,8 @@ void screen_update_areas()
 
     /* all the work areas are not used here, only the ones for the first
        monitor are */
-    PROP_SETA32(RootWindow(ob_display, ob_screen), net_workarea, cardinal,
-                dims, 4 * screen_num_desktops);
+    OBT_PROP_SETA32(obt_root(ob_screen), NET_WORKAREA, CARDINAL,
+                    dims, 4 * screen_num_desktops);
 
     /* the area has changed, adjust all the windows if they need it */
     for (it = client_list; it; it = g_list_next(it))
@@ -1450,28 +1645,32 @@ Rect* screen_area(guint desktop, guint head, Rect *search)
                 if ((s->desktop == d || s->desktop == DESKTOP_ALL) &&
                     STRUT_LEFT_IN_SEARCH(s->strut, search) &&
                     !STRUT_LEFT_IGNORE(s->strut, us, search))
-                    l = MAX(l, al + s->strut->left);
+                    l = MAX(l, RECT_LEFT(monitor_area[screen_num_monitors])
+                               + s->strut->left);
             }
             for (it = struts_top; it; it = g_slist_next(it)) {
                 ObScreenStrut *s = it->data;
                 if ((s->desktop == d || s->desktop == DESKTOP_ALL) &&
                     STRUT_TOP_IN_SEARCH(s->strut, search) &&
                     !STRUT_TOP_IGNORE(s->strut, us, search))
-                    t = MAX(t, at + s->strut->top);
+                    t = MAX(t, RECT_TOP(monitor_area[screen_num_monitors])
+                               + s->strut->top);
             }
             for (it = struts_right; it; it = g_slist_next(it)) {
                 ObScreenStrut *s = it->data;
                 if ((s->desktop == d || s->desktop == DESKTOP_ALL) &&
                     STRUT_RIGHT_IN_SEARCH(s->strut, search) &&
                     !STRUT_RIGHT_IGNORE(s->strut, us, search))
-                    r = MIN(r, ar - s->strut->right);
+                    r = MIN(r, RECT_RIGHT(monitor_area[screen_num_monitors])
+                               - s->strut->right);
             }
             for (it = struts_bottom; it; it = g_slist_next(it)) {
                 ObScreenStrut *s = it->data;
                 if ((s->desktop == d || s->desktop == DESKTOP_ALL) &&
                     STRUT_BOTTOM_IN_SEARCH(s->strut, search) &&
                     !STRUT_BOTTOM_IGNORE(s->strut, us, search))
-                    b = MIN(b, ab - s->strut->bottom);
+                    b = MIN(b, RECT_BOTTOM(monitor_area[screen_num_monitors])
+                               - s->strut->bottom);
             }
 
             /* limit to this monitor */
@@ -1495,7 +1694,7 @@ Rect* screen_area(guint desktop, guint head, Rect *search)
 guint screen_find_monitor(Rect *search)
 {
     guint i;
-    guint most = 0;
+    guint most = screen_num_monitors;
     guint mostv = 0;
 
     for (i = 0; i < screen_num_monitors; ++i) {
@@ -1517,7 +1716,7 @@ guint screen_find_monitor(Rect *search)
     return most;
 }
 
-Rect* screen_physical_area_all_monitors()
+Rect* screen_physical_area_all_monitors(void)
 {
     return screen_physical_area_monitor(screen_num_monitors);
 }
@@ -1539,7 +1738,7 @@ gboolean screen_physical_area_monitor_contains(guint head, Rect *search)
     return RECT_INTERSECTS_RECT(monitor_area[head], *search);
 }
 
-Rect* screen_physical_area_active()
+Rect* screen_physical_area_active(void)
 {
     Rect *a;
     gint x, y;
@@ -1559,13 +1758,13 @@ Rect* screen_physical_area_active()
     return a;
 }
 
-void screen_set_root_cursor()
+void screen_set_root_cursor(void)
 {
     if (sn_app_starting())
-        XDefineCursor(ob_display, RootWindow(ob_display, ob_screen),
+        XDefineCursor(obt_display, obt_root(ob_screen),
                       ob_cursor(OB_CURSOR_BUSYPOINTER));
     else
-        XDefineCursor(ob_display, RootWindow(ob_display, ob_screen),
+        XDefineCursor(obt_display, obt_root(ob_screen),
                       ob_cursor(OB_CURSOR_POINTER));
 }
 
@@ -1576,12 +1775,12 @@ gboolean screen_pointer_pos(gint *x, gint *y)
     guint u;
     gboolean ret;
 
-    ret = !!XQueryPointer(ob_display, RootWindow(ob_display, ob_screen),
+    ret = !!XQueryPointer(obt_display, obt_root(ob_screen),
                           &w, &w, x, y, &i, &i, &u);
     if (!ret) {
-        for (i = 0; i < ScreenCount(ob_display); ++i)
+        for (i = 0; i < ScreenCount(obt_display); ++i)
             if (i != ob_screen)
-                if (XQueryPointer(ob_display, RootWindow(ob_display, i),
+                if (XQueryPointer(obt_display, obt_root(i),
                                   &w, &w, x, y, &i, &i, &u))
                     break;
     }