add prop.[ch] to the libobt, but they are not used yet. add a global obt_display...
[dana/openbox.git] / openbox / screen.c
index 7516cfd..e8a175d 100644 (file)
@@ -20,7 +20,6 @@
 #include "debug.h"
 #include "openbox.h"
 #include "dock.h"
-#include "xerror.h"
 #include "prop.h"
 #include "grab.h"
 #include "startupnotify.h"
@@ -34,9 +33,9 @@
 #include "event.h"
 #include "focus.h"
 #include "popup.h"
-#include "extensions.h"
 #include "render/render.h"
 #include "gettext.h"
+#include "obt/display.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();
-static void     screen_fallback_focus();
+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;
-Size     screen_physical_size;
+guint    screen_last_desktop = 1;
 gboolean screen_showing_desktop;
 ObDesktopLayout screen_desktop_layout;
 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 array of areas per monitor */
 static Rect  *monitor_area = NULL;
 /*! An array of desktops, holding an array of struts */
@@ -77,7 +78,11 @@ static GSList *struts_bottom = NULL;
 
 static ObPagerPopup *desktop_popup;
 
-static gboolean replace_wm()
+/*! 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(void)
 {
     gchar *wm_sn;
     Atom wm_sn_atom;
@@ -97,15 +102,14 @@ 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);
 
-        xerror_set_ignore(FALSE);
-        if (xerror_occured)
+        obt_display_ignore_errors(FALSE);
+        if (obt_display_error_occured)
             current_wm_sn_owner = None;
     }
 
@@ -149,7 +153,7 @@ static gboolean replace_wm()
     return TRUE;
 }
 
-gboolean screen_annex()
+gboolean screen_annex(void)
 {
     XSetWindowAttributes attrib;
     pid_t pid;
@@ -175,12 +179,11 @@ gboolean screen_annex()
         return FALSE;
     }
 
-    xerror_set_ignore(TRUE);
-    xerror_occured = FALSE;
+    obt_display_ignore_errors(TRUE);
     XSelectInput(ob_display, RootWindow(ob_display, ob_screen),
                  ROOT_EVENTMASK);
-    xerror_set_ignore(FALSE);
-    if (xerror_occured) {
+    obt_display_ignore_errors(FALSE);
+    if (obt_display_error_occured) {
         g_message(_("A window manager is already running on screen %d"),
                   ob_screen);
 
@@ -283,6 +286,8 @@ gboolean screen_annex()
     supported[i++] = prop_atoms.net_wm_sync_request;
     supported[i++] = prop_atoms.net_wm_sync_request_counter;
 #endif
+    supported[i++] = prop_atoms.net_wm_pid;
+    supported[i++] = prop_atoms.net_wm_ping;
 
     supported[i++] = prop_atoms.kde_wm_change_state;
     supported[i++] = prop_atoms.kde_net_wm_frame_strut;
@@ -304,7 +309,7 @@ gboolean screen_annex()
     return TRUE;
 }
 
-static void screen_tell_ksplash()
+static void screen_tell_ksplash(void)
 {
     XEvent e;
     char **argv;
@@ -344,7 +349,7 @@ void screen_startup(gboolean reconfig)
     guint32 d;
     gboolean namesexist = FALSE;
 
-    desktop_popup = pager_popup_new(FALSE);
+    desktop_popup = pager_popup_new();
     pager_popup_height(desktop_popup, POPUP_HEIGHT);
 
     if (reconfig) {
@@ -453,7 +458,7 @@ void screen_shutdown(gboolean reconfig)
     screen_desktop_names = NULL;
 }
 
-void screen_resize()
+void screen_resize(void)
 {
     static gint oldw = 0, oldh = 0;
     gint w, h;
@@ -536,7 +541,7 @@ void screen_set_num_desktops(guint num)
         screen_set_desktop(num - 1, TRUE);
 }
 
-static void screen_fallback_focus()
+static void screen_fallback_focus(void)
 {
     ObClient *c;
     gboolean allow_omni;
@@ -577,23 +582,90 @@ static void screen_fallback_focus()
     }
 }
 
+static gboolean last_desktop_func(gpointer data)
+{
+    screen_desktop_timeout = TRUE;
+    return FALSE;
+}
+
 void screen_set_desktop(guint num, gboolean dofocus)
 {
     GList *it;
-    guint old;
+    guint previous;
     gulong ignore_start;
 
     g_assert(num < screen_num_desktops);
 
-    old = screen_desktop;
+    previous = screen_desktop;
     screen_desktop = num;
 
-    if (old == num) return;
+    if (previous == num) return;
 
     PROP_SET32(RootWindow(ob_display, ob_screen),
                net_current_desktop, cardinal, num);
 
-    screen_last_desktop = old;
+    /* 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. */
+
+        /* 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;
+    ob_main_loop_timeout_remove(ob_main_loop, last_desktop_func);
+    ob_main_loop_timeout_add(ob_main_loop, REMEMBER_LAST_DESKTOP_TIME,
+                             last_desktop_func, NULL, NULL, NULL);
 
     ob_debug("Moving to desktop %d\n", num+1);
 
@@ -858,7 +930,7 @@ void screen_show_desktop_popup(guint d)
     g_free(a);
 }
 
-void screen_hide_desktop_popup()
+void screen_hide_desktop_popup(void)
 {
     ob_main_loop_timeout_remove(ob_main_loop, hide_desktop_popup_func);
     pager_popup_hide(desktop_popup);
@@ -1007,7 +1079,7 @@ static gboolean screen_validate_layout(ObDesktopLayout *l)
     return TRUE;
 }
 
-void screen_update_layout()
+void screen_update_layout(void)
 
 {
     ObDesktopLayout l;
@@ -1056,7 +1128,7 @@ void screen_update_layout()
     }
 }
 
-void screen_update_desktop_names()
+void screen_update_desktop_names(void)
 {
     guint i;
 
@@ -1167,16 +1239,16 @@ 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(ob_display, RrColormap(ob_rr_inst));
         else
-            XUninstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst));
+            XUninstallColormap(ob_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(ob_display, client->colormap);
         else
-            XUninstallColormap(RrDisplay(ob_rr_inst), client->colormap);
-        xerror_set_ignore(FALSE);
+            XUninstallColormap(ob_display, client->colormap);
+        obt_display_ignore_errors(FALSE);
     }
 }
 
@@ -1218,7 +1290,56 @@ typedef struct {
     } \
 }
 
-void screen_update_areas()
+static void get_xinerama_screens(Rect **xin_areas, guint *nxin)
+{
+    guint i;
+    gint l, r, t, b;
+
+    if (ob_debug_xinerama) {
+        g_print("Using fake xinerama !\n");
+        gint w = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen));
+        gint h = HeightOfScreen(ScreenOfDisplay(ob_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) {
+        guint i;
+        gint n;
+        XineramaScreenInfo *info = XineramaQueryScreens(ob_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(ob_display, ob_screen)),
+                 HeightOfScreen(ScreenOfDisplay(ob_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;
@@ -1226,7 +1347,7 @@ 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);
 
     /* set up the user-specified margins */
     config_margins.top_start = RECT_LEFT(monitor_area[screen_num_monitors]);
@@ -1510,7 +1631,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) {
@@ -1532,7 +1653,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);
 }
@@ -1554,7 +1675,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;
@@ -1574,7 +1695,7 @@ 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),