]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
check them startupnotify-provided wmclass against both parts of a window's wm_class...
[chaz/openbox] / openbox / client.c
index ffc0488f4083b08c9a76bb0ffe5ca2350d3dc000..0a0d1ffc6765f886a6a78ab85f8e817798942330 100644 (file)
@@ -1,5 +1,5 @@
 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-   
+
    client.c for the Openbox window manager
    Copyright (c) 2006        Mikael Magnusson
    Copyright (c) 2003-2007   Dana Jansens
    client.c for the Openbox window manager
    Copyright (c) 2006        Mikael Magnusson
    Copyright (c) 2003-2007   Dana Jansens
@@ -24,6 +24,7 @@
 #include "xerror.h"
 #include "screen.h"
 #include "moveresize.h"
 #include "xerror.h"
 #include "screen.h"
 #include "moveresize.h"
+#include "ping.h"
 #include "place.h"
 #include "prop.h"
 #include "extensions.h"
 #include "place.h"
 #include "prop.h"
 #include "extensions.h"
@@ -32,7 +33,6 @@
 #include "event.h"
 #include "grab.h"
 #include "focus.h"
 #include "event.h"
 #include "grab.h"
 #include "focus.h"
-#include "propwin.h"
 #include "stacking.h"
 #include "openbox.h"
 #include "group.h"
 #include "stacking.h"
 #include "openbox.h"
 #include "group.h"
 #include "keyboard.h"
 #include "mouse.h"
 #include "render/render.h"
 #include "keyboard.h"
 #include "mouse.h"
 #include "render/render.h"
+#include "gettext.h"
 
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
 
 
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
 
+#ifdef HAVE_SIGNAL_H
+#  include <signal.h> /* for kill() */
+#endif
+
 #include <glib.h>
 #include <X11/Xutil.h>
 
 #include <glib.h>
 #include <X11/Xutil.h>
 
@@ -75,6 +80,10 @@ static void client_get_state(ObClient *self);
 static void client_get_shaped(ObClient *self);
 static void client_get_mwm_hints(ObClient *self);
 static void client_get_colormap(ObClient *self);
 static void client_get_shaped(ObClient *self);
 static void client_get_mwm_hints(ObClient *self);
 static void client_get_colormap(ObClient *self);
+static void client_set_desktop_recursive(ObClient *self,
+                                         guint target,
+                                         gboolean donthide,
+                                         gboolean dontraise);
 static void client_change_allowed_actions(ObClient *self);
 static void client_change_state(ObClient *self);
 static void client_change_wm_state(ObClient *self);
 static void client_change_allowed_actions(ObClient *self);
 static void client_change_state(ObClient *self);
 static void client_change_wm_state(ObClient *self);
@@ -94,6 +103,7 @@ static GSList *client_search_all_top_parents_internal(ObClient *self,
                                                       gboolean bylayer,
                                                       ObStackingLayer layer);
 static void client_call_notifies(ObClient *self, GSList *list);
                                                       gboolean bylayer,
                                                       ObStackingLayer layer);
 static void client_call_notifies(ObClient *self, GSList *list);
+static void client_ping_event(ObClient *self, gboolean dead);
 
 
 void client_startup(gboolean reconfig)
 
 
 void client_startup(gboolean reconfig)
@@ -141,7 +151,7 @@ void client_remove_destroy_notify(ObClientCallback func)
     }
 }
 
     }
 }
 
-void client_set_list()
+void client_set_list(void)
 {
     Window *windows, *win_it;
     GList *it;
 {
     Window *windows, *win_it;
     GList *it;
@@ -165,7 +175,7 @@ void client_set_list()
     stacking_set_list();
 }
 
     stacking_set_list();
 }
 
-void client_manage_all()
+void client_manage_all(void)
 {
     guint i, j, nchild;
     Window w, *children;
 {
     guint i, j, nchild;
     Window w, *children;
@@ -213,8 +223,9 @@ void client_manage(Window window)
     XWMHints *wmhint;
     gboolean activate = FALSE;
     ObAppSettings *settings;
     XWMHints *wmhint;
     gboolean activate = FALSE;
     ObAppSettings *settings;
-    gint placex, placey, placew, placeh;
     gboolean transient = FALSE;
     gboolean transient = FALSE;
+    Rect place, *monitor;
+    Time launch_time, map_time;
 
     grab_server(TRUE);
 
 
     grab_server(TRUE);
 
@@ -237,7 +248,7 @@ void client_manage(Window window)
         grab_server(FALSE);
         return; /* don't manage it */
     }
         grab_server(FALSE);
         return; /* don't manage it */
     }
-  
+
     /* is the window a docking app */
     if ((wmhint = XGetWMHints(ob_display, window))) {
         if ((wmhint->flags & StateHint) &&
     /* is the window a docking app */
     if ((wmhint = XGetWMHints(ob_display, window))) {
         if ((wmhint->flags & StateHint) &&
@@ -253,6 +264,8 @@ void client_manage(Window window)
 
     ob_debug("Managing window: 0x%lx\n", window);
 
 
     ob_debug("Managing window: 0x%lx\n", window);
 
+    map_time = event_get_server_time();
+
     /* choose the events we want to receive on the CLIENT window */
     attrib_set.event_mask = CLIENT_EVENTMASK;
     attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK;
     /* choose the events we want to receive on the CLIENT window */
     attrib_set.event_mask = CLIENT_EVENTMASK;
     attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK;
@@ -269,7 +282,6 @@ void client_manage(Window window)
     self->wmstate = WithdrawnState; /* make sure it gets updated first time */
     self->gravity = NorthWestGravity;
     self->desktop = screen_num_desktops; /* always an invalid value */
     self->wmstate = WithdrawnState; /* make sure it gets updated first time */
     self->gravity = NorthWestGravity;
     self->desktop = screen_num_desktops; /* always an invalid value */
-    self->user_time = focus_client ? focus_client->user_time : CurrentTime;
 
     /* get all the stuff off the window */
     client_get_all(self, TRUE);
 
     /* get all the stuff off the window */
     client_get_all(self, TRUE);
@@ -300,10 +312,8 @@ void client_manage(Window window)
     /* now we have all of the window's information so we can set this up */
     client_setup_decor_and_functions(self, FALSE);
 
     /* now we have all of the window's information so we can set this up */
     client_setup_decor_and_functions(self, FALSE);
 
-    {
-        Time t = sn_app_started(self->startup_id, self->class);
-        if (t) self->user_time = t;
-    }
+    /* tell startup notification that this app started */
+    launch_time = sn_app_started(self->startup_id, self->class, self->name);
 
     /* do this after we have a frame.. it uses the frame to help determine the
        WM_STATE to apply. */
 
     /* do this after we have a frame.. it uses the frame to help determine the
        WM_STATE to apply. */
@@ -337,10 +347,8 @@ void client_manage(Window window)
     frame_adjust_client_area(self->frame);
 
     /* where the frame was placed is where the window was originally */
     frame_adjust_client_area(self->frame);
 
     /* where the frame was placed is where the window was originally */
-    placex = self->area.x;
-    placey = self->area.y;
-    placew = self->area.width;
-    placeh = self->area.height;
+    place = self->area;
+    monitor = screen_physical_area_monitor(screen_find_monitor(&place));
 
     /* figure out placement for the window if the window is new */
     if (ob_state() == OB_STATE_RUNNING) {
 
     /* figure out placement for the window if the window is new */
     if (ob_state() == OB_STATE_RUNNING) {
@@ -350,7 +358,7 @@ void client_manage(Window window)
                    (self->positioned == USPosition ? "user specified" :
                     (self->positioned == (PPosition | USPosition) ?
                      "program + user specified" :
                    (self->positioned == USPosition ? "user specified" :
                     (self->positioned == (PPosition | USPosition) ?
                      "program + user specified" :
-                     "BADNESS !?")))), placex, placey);
+                     "BADNESS !?")))), place.x, place.y);
 
         ob_debug("Sized: %s @ %d %d\n",
                  (!self->sized ? "no" :
 
         ob_debug("Sized: %s @ %d %d\n",
                  (!self->sized ? "no" :
@@ -358,14 +366,15 @@ void client_manage(Window window)
                    (self->sized == USSize ? "user specified" :
                     (self->sized == (PSize | USSize) ?
                      "program + user specified" :
                    (self->sized == USSize ? "user specified" :
                     (self->sized == (PSize | USSize) ?
                      "program + user specified" :
-                     "BADNESS !?")))), placew, placeh);
+                     "BADNESS !?")))), place.width, place.height);
 
         /* splash screens are also returned as TRUE for transient,
            and so will be forced on screen below */
 
         /* splash screens are also returned as TRUE for transient,
            and so will be forced on screen below */
-        transient = place_client(self, &placex, &placey, settings);
+        transient = place_client(self, &place.x, &place.y, settings);
 
         /* make sure the window is visible. */
 
         /* make sure the window is visible. */
-        client_find_onscreen(self, &placex, &placey, placew, placeh,
+        client_find_onscreen(self, &place.x, &place.y,
+                             place.width, place.height,
                              /* non-normal clients has less rules, and
                                 windows that are being restored from a
                                 session do also. we can assume you want
                              /* non-normal clients has less rules, and
                                 windows that are being restored from a
                                 session do also. we can assume you want
@@ -382,9 +391,16 @@ void client_manage(Window window)
                              */
                              ob_state() == OB_STATE_RUNNING &&
                              (transient ||
                              */
                              ob_state() == OB_STATE_RUNNING &&
                              (transient ||
-                              (!(self->positioned & USPosition) &&
+                              (!((self->positioned & USPosition) ||
+                                 (settings && settings->pos_given)) &&
                                client_normal(self) &&
                                client_normal(self) &&
-                               !self->session)));
+                               !self->session &&
+                               /* don't move oldschool fullscreen windows to
+                                  fit inside the struts (fixes Acroread, which
+                                  makes its fullscreen window fit the screen
+                                  but it is not USSize'd or USPosition'd) */
+                               !(self->decorations == 0 &&
+                                 RECT_EQUAL(place, *monitor)))));
     }
 
     /* if the window isn't user-sized, then make it fit inside
     }
 
     /* if the window isn't user-sized, then make it fit inside
@@ -400,34 +416,34 @@ void client_manage(Window window)
         (transient ||
          (!(self->sized & USSize || self->positioned & USPosition) &&
           client_normal(self) &&
         (transient ||
          (!(self->sized & USSize || self->positioned & USPosition) &&
           client_normal(self) &&
-          !self->session)))
+          !self->session &&
+          /* don't shrink oldschool fullscreen windows to fit inside the
+             struts (fixes Acroread, which makes its fullscreen window
+             fit the screen but it is not USSize'd or USPosition'd) */
+          !(self->decorations == 0 && RECT_EQUAL(place, *monitor)))))
     {
     {
-        Rect placer;
+        Rect *a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &place);
 
 
-        RECT_SET(placer, placex, placey, placew, placeh);
-        frame_rect_to_frame(self->frame, &placer);
+        /* get the size of the frame */
+        place.width += self->frame->size.left + self->frame->size.right;
+        place.height += self->frame->size.top + self->frame->size.bottom;
 
 
-        Rect *a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &placer);
+        /* fit the window inside the area */
+        place.width = MIN(place.width, a->width);
+        place.height = MIN(place.height, a->height);
 
 
-        /* shrink by the frame's area */
-        a->width -= self->frame->size.left + self->frame->size.right;
-        a->height -= self->frame->size.top + self->frame->size.bottom;
+        ob_debug("setting window size to %dx%d\n", place.width, place.height);
 
 
-        /* fit the window inside the area */
-        if (placew > a->width || self->area.height > a->height) {
-            placew = MIN(self->area.width, a->width);
-            placeh = MIN(self->area.height, a->height);
+        /* get the size of the client back */
+        place.width -= self->frame->size.left + self->frame->size.right;
+        place.height -= self->frame->size.top + self->frame->size.bottom;
 
 
-            ob_debug("setting window size to %dx%d\n",
-                     self->area.width, self->area.height);
-        }
         g_free(a);
     }
 
         g_free(a);
     }
 
-
     ob_debug("placing window 0x%x at %d, %d with size %d x %d. "
              "some restrictions may apply\n",
     ob_debug("placing window 0x%x at %d, %d with size %d x %d. "
              "some restrictions may apply\n",
-             self->window, placex, placey, placew, placeh);
+             self->window, place.x, place.y, place.width, place.height);
     if (self->session)
         ob_debug("  but session requested %d, %d  %d x %d instead, "
                  "overriding\n",
     if (self->session)
         ob_debug("  but session requested %d, %d  %d x %d instead, "
                  "overriding\n",
@@ -439,25 +455,42 @@ void client_manage(Window window)
 
        this also places the window
     */
 
        this also places the window
     */
-    client_apply_startup_state(self, placex, placey, placew, placeh);
+    client_apply_startup_state(self, place.x, place.y,
+                               place.width, place.height);
 
 
+    g_free(monitor);
+    monitor = NULL;
+
+    ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s\n",
+                  activate ? "yes" : "no");
     if (activate) {
     if (activate) {
-        guint32 last_time = focus_client ?
-            focus_client->user_time : CurrentTime;
+        gboolean raise = FALSE;
 
         /* This is focus stealing prevention */
         ob_debug_type(OB_DEBUG_FOCUS,
 
         /* This is focus stealing prevention */
         ob_debug_type(OB_DEBUG_FOCUS,
-                      "Want to focus new window 0x%x with time %u "
-                      "(last time %u)\n",
-                      self->window, self->user_time, last_time);
+                      "Want to focus new window 0x%x at time %u "
+                      "launched at %u (last user interaction time %u)\n",
+                      self->window, map_time, launch_time,
+                      event_last_user_time);
+
+        if (menu_frame_visible || moveresize_in_progress) {
+            activate = FALSE;
+            raise = TRUE;
+            ob_debug_type(OB_DEBUG_FOCUS,
+                          "Not focusing the window because the user is inside "
+                          "an Openbox menu or is move/resizing a window and "
+                          "we don't want to interrupt them\n");
+        }
 
         /* if it's on another desktop */
 
         /* if it's on another desktop */
-        if (!(self->desktop == screen_desktop || self->desktop == DESKTOP_ALL)
-            && /* the timestamp is from before you changed desktops */
-            self->user_time && screen_desktop_user_time &&
-            !event_time_after(self->user_time, screen_desktop_user_time))
+        else if (!(self->desktop == screen_desktop ||
+                   self->desktop == DESKTOP_ALL) &&
+                 /* the timestamp is from before you changed desktops */
+                 launch_time && screen_desktop_user_time &&
+                 !event_time_after(launch_time, screen_desktop_user_time))
         {
             activate = FALSE;
         {
             activate = FALSE;
+            raise = TRUE;
             ob_debug_type(OB_DEBUG_FOCUS,
                           "Not focusing the window because its on another "
                           "desktop\n");
             ob_debug_type(OB_DEBUG_FOCUS,
                           "Not focusing the window because its on another "
                           "desktop\n");
@@ -466,26 +499,25 @@ void client_manage(Window window)
         else if (focus_client && client_search_focus_tree_full(self) == NULL &&
                  client_search_focus_group_full(self) == NULL)
         {
         else if (focus_client && client_search_focus_tree_full(self) == NULL &&
                  client_search_focus_group_full(self) == NULL)
         {
-            /* If time stamp is old, don't steal focus */
-            if (self->user_time && last_time &&
-                !event_time_after(self->user_time, last_time))
+            /* If the user is working in another window right now, then don't
+               steal focus */
+            if (event_last_user_time && launch_time &&
+                event_time_after(event_last_user_time, launch_time) &&
+                event_last_user_time != launch_time &&
+                event_time_after(event_last_user_time,
+                                 map_time - OB_EVENT_USER_TIME_DELAY))
             {
                 activate = FALSE;
                 ob_debug_type(OB_DEBUG_FOCUS,
             {
                 activate = FALSE;
                 ob_debug_type(OB_DEBUG_FOCUS,
-                              "Not focusing the window because the time is "
-                              "too old\n");
+                              "Not focusing the window because the user is "
+                              "working in another window\n");
             }
             }
-            /* If its a transient (and parents aren't focused) and the time
-               is ambiguous (either the current focus target doesn't have
-               a timestamp, or they are the same (we probably inherited it
-               from them) */
-            else if (client_has_parent(self) &&
-                     (!last_time || self->user_time == last_time))
-            {
+            /* If its a transient (and its parents aren't focused) */
+            else if (client_has_parent(self)) {
                 activate = FALSE;
                 ob_debug_type(OB_DEBUG_FOCUS,
                               "Not focusing the window because it is a "
                 activate = FALSE;
                 ob_debug_type(OB_DEBUG_FOCUS,
                               "Not focusing the window because it is a "
-                              "transient, and the time is very ambiguous\n");
+                              "transient, and its relatives aren't focused\n");
             }
             /* Don't steal focus from globally active clients.
                I stole this idea from KWin. It seems nice.
             }
             /* Don't steal focus from globally active clients.
                I stole this idea from KWin. It seems nice.
@@ -502,20 +534,33 @@ void client_manage(Window window)
                anyway */
             else if (client_focus_target(self) != self) {
                 activate = FALSE;
                anyway */
             else if (client_focus_target(self) != self) {
                 activate = FALSE;
+                raise = TRUE;
                 ob_debug_type(OB_DEBUG_FOCUS,
                               "Not focusing the window because another window "
                               "would get the focus anyway\n");
             }
                 ob_debug_type(OB_DEBUG_FOCUS,
                               "Not focusing the window because another window "
                               "would get the focus anyway\n");
             }
+            else if (!(self->desktop == screen_desktop ||
+                       self->desktop == DESKTOP_ALL))
+            {
+                activate = FALSE;
+                raise = TRUE;
+                ob_debug_type(OB_DEBUG_FOCUS,
+                              "Not focusing the window because it is on "
+                              "another desktop and no relatives are focused ");
+            }
         }
 
         if (!activate) {
             ob_debug_type(OB_DEBUG_FOCUS,
         }
 
         if (!activate) {
             ob_debug_type(OB_DEBUG_FOCUS,
-                          "Focus stealing prevention activated for %s with "
-                          "time %u (last time %u)\n",
-                          self->title, self->user_time, last_time);
+                          "Focus stealing prevention activated for %s at "
+                          "time %u (last user interactioon time %u)\n",
+                          self->title, map_time, event_last_user_time);
             /* if the client isn't focused, then hilite it so the user
                knows it is there */
             client_hilite(self, TRUE);
             /* if the client isn't focused, then hilite it so the user
                knows it is there */
             client_hilite(self, TRUE);
+            /* we may want to raise it even tho we're not activating it */
+            if (raise && !client_restore_session_stacking(self))
+                stacking_raise(CLIENT_AS_WINDOW(self));
         }
     }
     else {
         }
     }
     else {
@@ -562,6 +607,15 @@ void client_manage(Window window)
     /* update the list hints */
     client_set_list();
 
     /* update the list hints */
     client_set_list();
 
+    /* watch for when the application stops responding.  only do this for
+       normal windows, i.e. windows which have titlebars and close buttons 
+       and things like that.
+       we don't need to stop pinging on unmanage, because it will be handled
+       automatically by the destroy callback!
+    */
+    if (self->ping && client_normal(self))
+        ping_start(self, client_ping_event);
+
     /* free the ObAppSettings shallow copy */
     g_free(settings);
 
     /* free the ObAppSettings shallow copy */
     g_free(settings);
 
@@ -596,7 +650,7 @@ ObClient *client_fake_manage(Window window)
     frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
 
     ob_debug("gave extents left %d right %d top %d bottom %d\n",
     frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
 
     ob_debug("gave extents left %d right %d top %d bottom %d\n",
-             self->frame->size.left, self->frame->size.right, 
+             self->frame->size.left, self->frame->size.right,
              self->frame->size.top, self->frame->size.bottom);
 
     /* free the ObAppSettings shallow copy */
              self->frame->size.top, self->frame->size.bottom);
 
     /* free the ObAppSettings shallow copy */
@@ -605,7 +659,7 @@ ObClient *client_fake_manage(Window window)
     return self;
 }
 
     return self;
 }
 
-void client_unmanage_all()
+void client_unmanage_all(void)
 {
     while (client_list != NULL)
         client_unmanage(client_list->data);
 {
     while (client_list != NULL)
         client_unmanage(client_list->data);
@@ -643,9 +697,6 @@ void client_unmanage(ObClient *self)
     /* remove the window from our save set */
     XChangeSaveSet(ob_display, self->window, SetModeDelete);
 
     /* remove the window from our save set */
     XChangeSaveSet(ob_display, self->window, SetModeDelete);
 
-    /* kill the property windows */
-    propwin_remove(self->user_time_window, OB_PROPWIN_USER_TIME, self);
-
     /* update the focus lists */
     focus_order_remove(self);
     if (client_focused(self)) {
     /* update the focus lists */
     focus_order_remove(self);
     if (client_focused(self)) {
@@ -731,6 +782,11 @@ void client_unmanage(ObClient *self)
         XMapWindow(ob_display, self->window);
     }
 
         XMapWindow(ob_display, self->window);
     }
 
+    /* these should not be left on the window ever.  other window managers
+       don't necessarily use them and it will mess them up (like compiz) */
+    PROP_ERASE(self->window, net_wm_visible_name);
+    PROP_ERASE(self->window, net_wm_visible_icon_name);
+
     /* update the list hints */
     client_set_list();
 
     /* update the list hints */
     client_set_list();
 
@@ -983,10 +1039,15 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
     for (i = 0; i < screen_num_monitors; ++i) {
         Rect *a;
 
     for (i = 0; i < screen_num_monitors; ++i) {
         Rect *a;
 
-        if (!screen_physical_area_monitor_contains(i, &desired))
-            continue;
+        if (!screen_physical_area_monitor_contains(i, &desired)) {
+            if (i < screen_num_monitors - 1)
+                continue;
 
 
-        a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &desired);
+            /* the window is not inside any monitor! so just use the first
+               one */
+            a = screen_area(self->desktop, 0, NULL);
+        } else
+            a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &desired);
 
         /* This makes sure windows aren't entirely outside of the screen so you
            can't see them at all.
 
         /* This makes sure windows aren't entirely outside of the screen so you
            can't see them at all.
@@ -1003,7 +1064,7 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
             if (!self->strut.left && *x + fw*9/10 - 1 < a->x)
                 *x = a->x - fw*9/10;
             if (!self->strut.top && *y + fh*9/10 - 1 < a->y)
             if (!self->strut.left && *x + fw*9/10 - 1 < a->x)
                 *x = a->x - fw*9/10;
             if (!self->strut.top && *y + fh*9/10 - 1 < a->y)
-                *y = a->y - fw*9/10;
+                *y = a->y - fh*9/10;
         }
 
         /* This here doesn't let windows even a pixel outside the
         }
 
         /* This here doesn't let windows even a pixel outside the
@@ -1072,7 +1133,7 @@ static void client_get_all(ObClient *self, gboolean real)
         if (self->type == OB_CLIENT_TYPE_DESKTOP)
             self->desktop = DESKTOP_ALL;
     }
         if (self->type == OB_CLIENT_TYPE_DESKTOP)
             self->desktop = DESKTOP_ALL;
     }
-  
+
 #ifdef SYNC
     client_update_sync_request_counter(self);
 #endif
 #ifdef SYNC
     client_update_sync_request_counter(self);
 #endif
@@ -1080,9 +1141,6 @@ static void client_get_all(ObClient *self, gboolean real)
     client_get_colormap(self);
     client_update_strut(self);
     client_update_icons(self);
     client_get_colormap(self);
     client_update_strut(self);
     client_update_icons(self);
-    client_update_user_time_window(self);
-    if (!self->user_time_window) /* check if this would have been called */
-        client_update_user_time(self);
     client_update_icon_geometry(self);
 }
 
     client_update_icon_geometry(self);
 }
 
@@ -1098,7 +1156,7 @@ static void client_get_area(ObClient *self)
 {
     XWindowAttributes wattrib;
     Status ret;
 {
     XWindowAttributes wattrib;
     Status ret;
-  
+
     ret = XGetWindowAttributes(ob_display, self->window, &wattrib);
     g_assert(ret != BadWindow);
 
     ret = XGetWindowAttributes(ob_display, self->window, &wattrib);
     g_assert(ret != BadWindow);
 
@@ -1119,7 +1177,7 @@ static void client_get_desktop(ObClient *self)
             self->desktop = screen_num_desktops - 1;
         else
             self->desktop = d;
             self->desktop = screen_num_desktops - 1;
         else
             self->desktop = d;
-        ob_debug("client requested desktop 0x%x\n", self->desktop); 
+        ob_debug("client requested desktop 0x%x\n", self->desktop);
     } else {
         GSList *it;
         gboolean first = TRUE;
     } else {
         GSList *it;
         gboolean first = TRUE;
@@ -1166,7 +1224,7 @@ static void client_get_state(ObClient *self)
 {
     guint32 *state;
     guint num;
 {
     guint32 *state;
     guint num;
-  
+
     if (PROP_GETA32(self->window, net_wm_state, atom, &state, &num)) {
         gulong i;
         for (i = 0; i < num; ++i) {
     if (PROP_GETA32(self->window, net_wm_state, atom, &state, &num)) {
         gulong i;
         for (i = 0; i < num; ++i) {
@@ -1249,7 +1307,7 @@ void client_update_transient_for(ObClient *self)
                                  self->transient_for_group, trangroup,
                                  client_direct_parent(self), target);
     self->transient_for_group = trangroup;
                                  self->transient_for_group, trangroup,
                                  client_direct_parent(self), target);
     self->transient_for_group = trangroup;
-                          
+
 }
 
 static void client_update_transient_tree(ObClient *self,
 }
 
 static void client_update_transient_tree(ObClient *self,
@@ -1337,7 +1395,7 @@ static void client_update_transient_tree(ObClient *self,
        C is transient for B
        A can't be transient for C or we have a cycle
     */
        C is transient for B
        A can't be transient for C or we have a cycle
     */
-    if (!newgtran &&
+    if (!newgtran && newgroup &&
         (!newparent ||
          !client_search_top_direct_parent(newparent)->transient_for_group) &&
         client_normal(self))
         (!newparent ||
          !client_search_top_direct_parent(newparent)->transient_for_group) &&
         client_normal(self))
@@ -1395,7 +1453,7 @@ void client_get_type_and_transientness(ObClient *self)
 
     self->type = -1;
     self->transient = FALSE;
 
     self->type = -1;
     self->transient = FALSE;
-  
+
     if (PROP_GETA32(self->window, net_wm_window_type, atom, &val, &num)) {
         /* use the first value that we know about in the array */
         for (i = 0; i < num; ++i) {
     if (PROP_GETA32(self->window, net_wm_window_type, atom, &val, &num)) {
         /* use the first value that we know about in the array */
         for (i = 0; i < num; ++i) {
@@ -1431,7 +1489,7 @@ void client_get_type_and_transientness(ObClient *self)
 
     if (XGetTransientForHint(ob_display, self->window, &t))
         self->transient = TRUE;
 
     if (XGetTransientForHint(ob_display, self->window, &t))
         self->transient = TRUE;
-            
+
     if (self->type == (ObClientType) -1) {
         /*the window type hint was not set, which means we either classify
           ourself as a normal window or a dialog, depending on if we are a
     if (self->type == (ObClientType) -1) {
         /*the window type hint was not set, which means we either classify
           ourself as a normal window or a dialog, depending on if we are a
@@ -1469,8 +1527,12 @@ void client_update_protocols(ObClient *self)
                 /* if this protocol is requested, then the window will be
                    notified whenever we want it to receive focus */
                 self->focus_notify = TRUE;
                 /* if this protocol is requested, then the window will be
                    notified whenever we want it to receive focus */
                 self->focus_notify = TRUE;
+            else if (proto[i] == prop_atoms.net_wm_ping)
+                /* if this protocol is requested, then the window will allow
+                   pings to determine if it is still alive */
+                self->ping = TRUE;
 #ifdef SYNC
 #ifdef SYNC
-            else if (proto[i] == prop_atoms.net_wm_sync_request) 
+            else if (proto[i] == prop_atoms.net_wm_sync_request)
                 /* if this protocol is requested, then resizing the
                    window will be synchronized between the frame and the
                    client */
                 /* if this protocol is requested, then resizing the
                    window will be synchronized between the frame and the
                    client */
@@ -1493,7 +1555,7 @@ void client_update_sync_request_counter(ObClient *self)
 }
 #endif
 
 }
 #endif
 
-void client_get_colormap(ObClient *self)
+static void client_get_colormap(ObClient *self)
 {
     XWindowAttributes wa;
 
 {
     XWindowAttributes wa;
 
@@ -1550,13 +1612,13 @@ void client_update_normal_hints(ObClient *self)
 
         if (size.flags & PMinSize)
             SIZE_SET(self->min_size, size.min_width, size.min_height);
 
         if (size.flags & PMinSize)
             SIZE_SET(self->min_size, size.min_width, size.min_height);
-    
+
         if (size.flags & PMaxSize)
             SIZE_SET(self->max_size, size.max_width, size.max_height);
         if (size.flags & PMaxSize)
             SIZE_SET(self->max_size, size.max_width, size.max_height);
-    
+
         if (size.flags & PBaseSize)
             SIZE_SET(self->base_size, size.base_width, size.base_height);
         if (size.flags & PBaseSize)
             SIZE_SET(self->base_size, size.base_width, size.base_height);
-    
+
         if (size.flags & PResizeInc && size.width_inc && size.height_inc)
             SIZE_SET(self->size_inc, size.width_inc, size.height_inc);
 
         if (size.flags & PResizeInc && size.width_inc && size.height_inc)
             SIZE_SET(self->size_inc, size.width_inc, size.height_inc);
 
@@ -1603,11 +1665,16 @@ void client_setup_decor_and_functions(ObClient *self, gboolean reconfig)
     switch (self->type) {
     case OB_CLIENT_TYPE_NORMAL:
         /* normal windows retain all of the possible decorations and
     switch (self->type) {
     case OB_CLIENT_TYPE_NORMAL:
         /* normal windows retain all of the possible decorations and
-           functionality, and are the only windows that you can fullscreen */
+           functionality, and can be fullscreen */
         self->functions |= OB_CLIENT_FUNC_FULLSCREEN;
         break;
 
     case OB_CLIENT_TYPE_DIALOG:
         self->functions |= OB_CLIENT_FUNC_FULLSCREEN;
         break;
 
     case OB_CLIENT_TYPE_DIALOG:
+        /* sometimes apps make dialog windows fullscreen for some reason (for
+           e.g. kpdf does this..) */
+        self->functions |= OB_CLIENT_FUNC_FULLSCREEN;
+        break;
+
     case OB_CLIENT_TYPE_UTILITY:
         /* these windows don't have anything added or removed by default */
         break;
     case OB_CLIENT_TYPE_UTILITY:
         /* these windows don't have anything added or removed by default */
         break;
@@ -1790,7 +1857,7 @@ void client_update_wmhints(ObClient *self)
 
     /* assume a window takes input if it doesnt specify */
     self->can_focus = TRUE;
 
     /* assume a window takes input if it doesnt specify */
     self->can_focus = TRUE;
-  
+
     if ((hints = XGetWMHints(ob_display, self->window)) != NULL) {
         gboolean ur;
 
     if ((hints = XGetWMHints(ob_display, self->window)) != NULL) {
         gboolean ur;
 
@@ -1877,17 +1944,17 @@ void client_update_title(ObClient *self)
     gchar *visible = NULL;
 
     g_free(self->title);
     gchar *visible = NULL;
 
     g_free(self->title);
-     
+
     /* try netwm */
     if (!PROP_GETS(self->window, net_wm_name, utf8, &data)) {
         /* try old x stuff */
         if (!(PROP_GETS(self->window, wm_name, locale, &data)
               || PROP_GETS(self->window, wm_name, utf8, &data))) {
             if (self->transient) {
     /* try netwm */
     if (!PROP_GETS(self->window, net_wm_name, utf8, &data)) {
         /* try old x stuff */
         if (!(PROP_GETS(self->window, wm_name, locale, &data)
               || PROP_GETS(self->window, wm_name, utf8, &data))) {
             if (self->transient) {
-                /*
-                  GNOME alert windows are not given titles:
-                  http://developer.gnome.org/projects/gup/hig/draft_hig_new/windows-alert.html
-                */
+    /*
+    GNOME alert windows are not given titles:
+    http://developer.gnome.org/projects/gup/hig/draft_hig_new/windows-alert.html
+    */
                 data = g_strdup("");
             } else
                 data = g_strdup("Unnamed Window");
                 data = g_strdup("");
             } else
                 data = g_strdup("Unnamed Window");
@@ -1900,6 +1967,15 @@ void client_update_title(ObClient *self)
     } else
         visible = data;
 
     } else
         visible = data;
 
+    if (self->not_responding) {
+        data = visible;
+        if (self->close_tried_term)
+            visible = g_strdup_printf("%s - [%s]", data, _("Killing..."));
+        else
+            visible = g_strdup_printf("%s - [%s]", data, _("Not Responding"));
+        g_free(data);
+    }
+
     PROP_SETS(self->window, net_wm_visible_name, visible);
     self->title = visible;
 
     PROP_SETS(self->window, net_wm_visible_name, visible);
     self->title = visible;
 
@@ -1923,6 +1999,15 @@ void client_update_title(ObClient *self)
     } else
         visible = data;
 
     } else
         visible = data;
 
+    if (self->not_responding) {
+        data = visible;
+        if (self->close_tried_term)
+            visible = g_strdup_printf("%s - [%s]", data, _("Killing..."));
+        else
+            visible = g_strdup_printf("%s - [%s]", data, _("Not Responding"));
+        g_free(data);
+    }
+
     PROP_SETS(self->window, net_wm_visible_icon_name, visible);
     self->icon_title = visible;
 }
     PROP_SETS(self->window, net_wm_visible_icon_name, visible);
     self->icon_title = visible;
 }
@@ -2005,7 +2090,7 @@ void client_update_icons(ObClient *self)
         }
 
         self->icons = g_new(ObClientIcon, self->nicons);
         }
 
         self->icons = g_new(ObClientIcon, self->nicons);
-    
+
         /* store the icons */
         i = 0;
         for (j = 0; j < self->nicons; ++j) {
         /* store the icons */
         i = 0;
         for (j = 0; j < self->nicons; ++j) {
@@ -2062,7 +2147,7 @@ void client_update_icons(ObClient *self)
        or removes it entirely, it's not very likely it is going to set one
        right away afterwards
 
        or removes it entirely, it's not very likely it is going to set one
        right away afterwards
 
-       if it has parents, then one of them will have an icon already 
+       if it has parents, then one of them will have an icon already
     */
     if (self->nicons == 0 && !self->parents) {
         RrPixel32 *icon = ob_rr_theme->def_win_icon;
     */
     if (self->nicons == 0 && !self->parents) {
         RrPixel32 *icon = ob_rr_theme->def_win_icon;
@@ -2083,62 +2168,6 @@ void client_update_icons(ObClient *self)
         frame_adjust_icon(self->frame);
 }
 
         frame_adjust_icon(self->frame);
 }
 
-void client_update_user_time(ObClient *self)
-{
-    guint32 time;
-    gboolean got = FALSE;
-
-    if (self->user_time_window)
-        got = PROP_GET32(self->user_time_window,
-                         net_wm_user_time, cardinal, &time);
-    if (!got)
-        got = PROP_GET32(self->window, net_wm_user_time, cardinal, &time);
-
-    if (got) {
-        /* we set this every time, not just when it grows, because in practice
-           sometimes time goes backwards! (ntpdate.. yay....) so.. if it goes
-           backward we don't want all windows to stop focusing. we'll just
-           assume noone is setting times older than the last one, cuz that
-           would be pretty stupid anyways
-        */
-        self->user_time = time;
-
-        /*ob_debug("window %s user time %u\n", self->title, time);*/
-    }
-}
-
-void client_update_user_time_window(ObClient *self)
-{
-    guint32 w;
-
-    if (!PROP_GET32(self->window, net_wm_user_time_window, window, &w))
-        w = None;
-
-    if (w != self->user_time_window) {
-        /* remove the old window */
-        propwin_remove(self->user_time_window, OB_PROPWIN_USER_TIME, self);
-        self->user_time_window = None;
-
-        if (self->group && self->group->leader == w) {
-            ob_debug_type(OB_DEBUG_APP_BUGS, "Window is setting its "
-                          "_NET_WM_USER_TYPE_WINDOW to its group leader\n");
-            /* do it anyways..? */
-        }
-        else if (w == self->window) {
-            ob_debug_type(OB_DEBUG_APP_BUGS, "Window is setting its "
-                          "_NET_WM_USER_TIME_WINDOW to itself\n");
-            w = None; /* don't do it */
-        }
-
-        /* add the new window */
-        propwin_add(w, OB_PROPWIN_USER_TIME, self);
-        self->user_time_window = w;
-
-        /* and update from it */
-        client_update_user_time(self);
-    }
-}
-
 void client_update_icon_geometry(ObClient *self)
 {
     guint num;
 void client_update_icon_geometry(ObClient *self)
 {
     guint num;
@@ -2239,6 +2268,7 @@ static void client_get_session_ids(ObClient *self)
 
     if (got) {
         gchar localhost[128];
 
     if (got) {
         gchar localhost[128];
+        guint32 pid;
 
         gethostname(localhost, 127);
         localhost[127] = '\0';
 
         gethostname(localhost, 127);
         localhost[127] = '\0';
@@ -2246,6 +2276,11 @@ static void client_get_session_ids(ObClient *self)
             self->client_machine = s;
         else
             g_free(s);
             self->client_machine = s;
         else
             g_free(s);
+
+        /* see if it has the PID set too (the PID requires that the
+           WM_CLIENT_MACHINE be set) */
+        if (PROP_GET32(self->window, net_wm_pid, cardinal, &pid))
+            self->pid = pid;
     }
 }
 
     }
 }
 
@@ -2436,7 +2471,7 @@ gboolean client_should_show(ObClient *self)
         return FALSE;
     if (self->desktop == screen_desktop || self->desktop == DESKTOP_ALL)
         return TRUE;
         return FALSE;
     if (self->desktop == screen_desktop || self->desktop == DESKTOP_ALL)
         return TRUE;
-    
+
     return FALSE;
 }
 
     return FALSE;
 }
 
@@ -2580,7 +2615,7 @@ static void client_apply_startup_state(ObClient *self,
         client_shade(self, TRUE);
     if (demands_attention)
         client_hilite(self, TRUE);
         client_shade(self, TRUE);
     if (demands_attention)
         client_hilite(self, TRUE);
-  
+
     if (max_vert && max_horz)
         client_maximize(self, TRUE, 0);
     else if (max_vert)
     if (max_vert && max_horz)
         client_maximize(self, TRUE, 0);
     else if (max_vert)
@@ -2782,7 +2817,7 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h,
         /* you cannot resize to nothing */
         if (basew + *w < 1) *w = 1 - basew;
         if (baseh + *h < 1) *h = 1 - baseh;
         /* you cannot resize to nothing */
         if (basew + *w < 1) *w = 1 - basew;
         if (baseh + *h < 1) *h = 1 - baseh;
-  
+
         /* save the logical size */
         *logicalw = incw > 1 ? *w : *w + basew;
         *logicalh = inch > 1 ? *h : *h + baseh;
         /* save the logical size */
         *logicalw = incw > 1 ? *w : *w + basew;
         *logicalh = inch > 1 ? *h : *h + baseh;
@@ -3097,7 +3132,7 @@ void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk,
 void client_maximize(ObClient *self, gboolean max, gint dir)
 {
     gint x, y, w, h;
 void client_maximize(ObClient *self, gboolean max, gint dir)
 {
     gint x, y, w, h;
-     
+
     g_assert(dir == 0 || dir == 1 || dir == 2);
     if (!(self->functions & OB_CLIENT_FUNC_MAXIMIZE)) return; /* can't */
 
     g_assert(dir == 0 || dir == 1 || dir == 2);
     if (!(self->functions & OB_CLIENT_FUNC_MAXIMIZE)) return; /* can't */
 
@@ -3175,41 +3210,58 @@ void client_shade(ObClient *self, gboolean shade)
     frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
 }
 
     frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
 }
 
-void client_close(ObClient *self)
+static void client_ping_event(ObClient *self, gboolean dead)
 {
 {
-    XEvent ce;
+    self->not_responding = dead;
+    client_update_title(self);
+
+    if (!dead) {
+        /* try kill it nicely the first time again, if it started responding
+           at some point */
+        self->close_tried_term = FALSE;
+    }
+}
 
 
+void client_close(ObClient *self)
+{
     if (!(self->functions & OB_CLIENT_FUNC_CLOSE)) return;
 
     /* in the case that the client provides no means to requesting that it
        close, we just kill it */
     if (!self->delete_window)
     if (!(self->functions & OB_CLIENT_FUNC_CLOSE)) return;
 
     /* in the case that the client provides no means to requesting that it
        close, we just kill it */
     if (!self->delete_window)
+        /* don't use client_kill(), we should only kill based on PID in
+           response to a lack of PING replies */
+        XKillClient(ob_display, self->window);
+    else if (self->not_responding)
         client_kill(self);
         client_kill(self);
-    
-    /*
-      XXX: itd be cool to do timeouts and shit here for killing the client's
-      process off
-      like... if the window is around after 5 seconds, then the close button
-      turns a nice red, and if this function is called again, the client is
-      explicitly killed.
-    */
-
-    ce.xclient.type = ClientMessage;
-    ce.xclient.message_type =  prop_atoms.wm_protocols;
-    ce.xclient.display = ob_display;
-    ce.xclient.window = self->window;
-    ce.xclient.format = 32;
-    ce.xclient.data.l[0] = prop_atoms.wm_delete_window;
-    ce.xclient.data.l[1] = event_curtime;
-    ce.xclient.data.l[2] = 0l;
-    ce.xclient.data.l[3] = 0l;
-    ce.xclient.data.l[4] = 0l;
-    XSendEvent(ob_display, self->window, FALSE, NoEventMask, &ce);
+    else
+        /* request the client to close with WM_DELETE_WINDOW */
+        PROP_MSG_TO(self->window, self->window, wm_protocols,
+                    prop_atoms.wm_delete_window, event_curtime, 0, 0, 0,
+                    NoEventMask);
 }
 
 void client_kill(ObClient *self)
 {
 }
 
 void client_kill(ObClient *self)
 {
-    XKillClient(ob_display, self->window);
+    if (!self->client_machine && self->pid) {
+        /* running on the local host */
+        if (!self->close_tried_term) {
+            ob_debug("killing window 0x%x with pid %lu, with SIGTERM\n",
+                     self->window, self->pid);
+            kill(self->pid, SIGTERM);
+            self->close_tried_term = TRUE;
+
+            /* show that we're trying to kill it */
+            client_update_title(self);
+        }
+        else {
+            ob_debug("killing window 0x%x with pid %lu, with SIGKILL\n",
+                     self->window, self->pid);
+            kill(self->pid, SIGKILL); /* kill -9 */
+        }
+    }
+    else
+        XKillClient(ob_display, self->window);
 }
 
 void client_hilite(ObClient *self, gboolean hilite)
 }
 
 void client_hilite(ObClient *self, gboolean hilite)
@@ -3228,10 +3280,10 @@ void client_hilite(ObClient *self, gboolean hilite)
     }
 }
 
     }
 }
 
-void client_set_desktop_recursive(ObClient *self,
-                                  guint target,
-                                  gboolean donthide,
-                                  gboolean dontraise)
+static void client_set_desktop_recursive(ObClient *self,
+                                         guint target,
+                                         gboolean donthide,
+                                         gboolean dontraise)
 {
     guint old;
     GSList *it;
 {
     guint old;
     GSList *it;
@@ -3287,7 +3339,7 @@ ObClient *client_search_modal_child(ObClient *self)
 {
     GSList *it;
     ObClient *ret;
 {
     GSList *it;
     ObClient *ret;
-  
+
     for (it = self->transients; it; it = g_slist_next(it)) {
         ObClient *c = it->data;
         if ((ret = client_search_modal_child(c))) return ret;
     for (it = self->transients; it; it = g_slist_next(it)) {
         ObClient *c = it->data;
         if ((ret = client_search_modal_child(c))) return ret;
@@ -3298,7 +3350,7 @@ ObClient *client_search_modal_child(ObClient *self)
 
 gboolean client_validate(ObClient *self)
 {
 
 gboolean client_validate(ObClient *self)
 {
-    XEvent e; 
+    XEvent e;
 
     XSync(ob_display, FALSE); /* get all events on the server */
 
 
     XSync(ob_display, FALSE); /* get all events on the server */
 
@@ -3314,7 +3366,7 @@ gboolean client_validate(ObClient *self)
 void client_set_wm_state(ObClient *self, glong state)
 {
     if (state == self->wmstate) return; /* no change */
 void client_set_wm_state(ObClient *self, glong state)
 {
     if (state == self->wmstate) return; /* no change */
-  
+
     switch (state) {
     case IconicState:
         client_iconify(self, TRUE, TRUE, FALSE);
     switch (state) {
     case IconicState:
         client_iconify(self, TRUE, TRUE, FALSE);
@@ -3343,11 +3395,11 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
           action == prop_atoms.net_wm_state_remove ||
           action == prop_atoms.net_wm_state_toggle))
         /* an invalid action was passed to the client message, ignore it */
           action == prop_atoms.net_wm_state_remove ||
           action == prop_atoms.net_wm_state_toggle))
         /* an invalid action was passed to the client message, ignore it */
-        return; 
+        return;
 
     for (i = 0; i < 2; ++i) {
         Atom state = i == 0 ? data1 : data2;
 
     for (i = 0; i < 2; ++i) {
         Atom state = i == 0 ? data1 : data2;
-    
+
         if (!state) continue;
 
         /* if toggling, then pick whether we're adding or removing */
         if (!state) continue;
 
         /* if toggling, then pick whether we're adding or removing */
@@ -3394,7 +3446,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
                 action = undecorated ? prop_atoms.net_wm_state_remove :
                     prop_atoms.net_wm_state_add;
         }
                 action = undecorated ? prop_atoms.net_wm_state_remove :
                     prop_atoms.net_wm_state_add;
         }
-    
+
         if (action == prop_atoms.net_wm_state_add) {
             if (state == prop_atoms.net_wm_state_modal) {
                 modal = TRUE;
         if (action == prop_atoms.net_wm_state_add) {
             if (state == prop_atoms.net_wm_state_modal) {
                 modal = TRUE;
@@ -3620,34 +3672,7 @@ static void client_present(ObClient *self, gboolean here, gboolean raise,
 void client_activate(ObClient *self, gboolean here, gboolean raise,
                      gboolean unshade, gboolean user)
 {
 void client_activate(ObClient *self, gboolean here, gboolean raise,
                      gboolean unshade, gboolean user)
 {
-    guint32 last_time = focus_client ? focus_client->user_time : CurrentTime;
-    gboolean allow = FALSE;
-
-    /* if the currently focused app doesn't set a user_time, then it can't
-       benefit from any focus stealing prevention.
-
-       if the timestamp is missing in the request then let it go through
-       even if it is source=app, because EVERY APPLICATION DOES THIS because
-       GTK IS VERY BUGGY AND HARDCODES source=application... WHY!?
-    */
-    if (!last_time || !event_curtime)
-        allow = TRUE;
-    /* otherwise, if they didn't give a time stamp or if it is too old, they
-       don't get focus */
-    else
-        allow = event_time_after(event_curtime, last_time);
-
-    ob_debug_type(OB_DEBUG_FOCUS,
-                  "Want to activate window 0x%x with time %u (last time %u), "
-                  "source=%s allowing? %d\n",
-                  self->window, event_curtime, last_time,
-                  (user ? "user" : "application"), allow);
-
-    if (allow)
-        client_present(self, here, raise, unshade);
-    else
-        /* don't focus it but tell the user it wants attention */
-        client_hilite(self, TRUE);
+    client_present(self, here, raise, unshade);
 }
 
 static void client_bring_windows_recursive(ObClient *self,
 }
 
 static void client_bring_windows_recursive(ObClient *self,
@@ -3703,7 +3728,7 @@ static ObClientIcon* client_icon_recursive(ObClient *self, gint w, gint h)
             if ((parent = client_icon_recursive(c, w, h)))
                 break;
         }
             if ((parent = client_icon_recursive(c, w, h)))
                 break;
         }
-        
+
         return parent;
     }
 
         return parent;
     }
 
@@ -3757,7 +3782,7 @@ void client_set_layer(ObClient *self, gint layer)
 void client_set_undecorated(ObClient *self, gboolean undecorated)
 {
     if (self->undecorated != undecorated &&
 void client_set_undecorated(ObClient *self, gboolean undecorated)
 {
     if (self->undecorated != undecorated &&
-        /* don't let it undecorate if the function is missing, but let 
+        /* don't let it undecorate if the function is missing, but let
            it redecorate */
         (self->functions & OB_CLIENT_FUNC_UNDECORATE || !undecorated))
     {
            it redecorate */
         (self->functions & OB_CLIENT_FUNC_UNDECORATE || !undecorated))
     {
@@ -3777,7 +3802,7 @@ ObClient *client_direct_parent(ObClient *self)
     if (!self->parents) return NULL;
     if (self->transient_for_group) return NULL;
     return self->parents->data;
     if (!self->parents) return NULL;
     if (self->transient_for_group) return NULL;
     return self->parents->data;
-}                        
+}
 
 ObClient *client_search_top_direct_parent(ObClient *self)
 {
 
 ObClient *client_search_top_direct_parent(ObClient *self)
 {
@@ -3792,7 +3817,7 @@ static GSList *client_search_all_top_parents_internal(ObClient *self,
 {
     GSList *ret;
     ObClient *p;
 {
     GSList *ret;
     ObClient *p;
-    
+
     /* move up the direct transient chain as far as possible */
     while ((p = client_direct_parent(self)) &&
            (!bylayer || p->layer == layer))
     /* move up the direct transient chain as far as possible */
     while ((p = client_direct_parent(self)) &&
            (!bylayer || p->layer == layer))
@@ -3849,6 +3874,111 @@ ObClient *client_search_transient(ObClient *self, ObClient *search)
     return NULL;
 }
 
     return NULL;
 }
 
+static void detect_edge(Rect area, ObDirection dir,
+                        gint my_head, gint my_size,
+                        gint my_edge_start, gint my_edge_size,
+                        gint *dest, gboolean *near_edge)
+{
+    gint edge_start, edge_size, head, tail;
+    gboolean skip_head = FALSE, skip_tail = FALSE;
+
+    switch (dir) {
+        case OB_DIRECTION_NORTH:
+        case OB_DIRECTION_SOUTH:
+            edge_start = area.x;
+            edge_size = area.width;
+            break;
+        case OB_DIRECTION_EAST:
+        case OB_DIRECTION_WEST:
+            edge_start = area.y;
+            edge_size = area.height;
+            break;
+        default:
+            g_assert_not_reached();
+    }
+
+    /* do we collide with this window? */
+    if (!RANGES_INTERSECT(my_edge_start, my_edge_size,
+                edge_start, edge_size))
+        return;
+
+    switch (dir) {
+        case OB_DIRECTION_NORTH:
+            head = RECT_BOTTOM(area);
+            tail = RECT_TOP(area);
+            break;
+        case OB_DIRECTION_SOUTH:
+            head = RECT_TOP(area);
+            tail = RECT_BOTTOM(area);
+            break;
+        case OB_DIRECTION_WEST:
+            head = RECT_RIGHT(area);
+            tail = RECT_LEFT(area);
+            break;
+        case OB_DIRECTION_EAST:
+            head = RECT_LEFT(area);
+            tail = RECT_RIGHT(area);
+            break;
+        default:
+            g_assert_not_reached();
+    }
+    switch (dir) {
+        case OB_DIRECTION_NORTH:
+        case OB_DIRECTION_WEST:
+            /* check if our window is past the head of this window */
+            if (my_head <= head + 1)
+                skip_head = TRUE;
+            /* check if our window's tail is past the tail of this window */
+            if (my_head + my_size - 1 <= tail)
+                skip_tail = TRUE;
+            /* check if the head of this window is closer than the previously
+               chosen edge (take into account that the previously chosen
+               edge might have been a tail, not a head) */
+            if (head + (*near_edge ? 0 : my_size) < *dest)
+                skip_head = TRUE;
+            /* check if the tail of this window is closer than the previously
+               chosen edge (take into account that the previously chosen
+               edge might have been a head, not a tail) */
+            if (tail - (!*near_edge ? 0 : my_size) < *dest)
+                skip_tail = TRUE;
+            break;
+        case OB_DIRECTION_SOUTH:
+        case OB_DIRECTION_EAST:
+            /* check if our window is past the head of this window */
+            if (my_head >= head - 1)
+                skip_head = TRUE;
+            /* check if our window's tail is past the tail of this window */
+            if (my_head - my_size + 1 >= tail)
+                skip_tail = TRUE;
+            /* check if the head of this window is closer than the previously
+               chosen edge (take into account that the previously chosen
+               edge might have been a tail, not a head) */
+            if (head - (*near_edge ? 0 : my_size) > *dest)
+                skip_head = TRUE;
+            /* check if the tail of this window is closer than the previously
+               chosen edge (take into account that the previously chosen
+               edge might have been a head, not a tail) */
+            if (tail + (!*near_edge ? 0 : my_size) > *dest)
+                skip_tail = TRUE;
+            break;
+        default:
+            g_assert_not_reached();
+    }
+
+    ob_debug("my head %d size %d\n", my_head, my_size);
+    ob_debug("head %d tail %d deest %d\n", head, tail, *dest);
+    if (!skip_head) {
+        ob_debug("using near edge %d\n", head);
+        *dest = head;
+        *near_edge = TRUE;
+    }
+    else if (!skip_tail) {
+        ob_debug("using far edge %d\n", tail);
+        *dest = tail;
+        *near_edge = FALSE;
+    }
+}
+
 void client_find_edge_directional(ObClient *self, ObDirection dir,
                                   gint my_head, gint my_size,
                                   gint my_edge_start, gint my_edge_size,
 void client_find_edge_directional(ObClient *self, ObDirection dir,
                                   gint my_head, gint my_size,
                                   gint my_edge_start, gint my_edge_size,
@@ -3856,6 +3986,7 @@ void client_find_edge_directional(ObClient *self, ObDirection dir,
 {
     GList *it;
     Rect *a, *mon;
 {
     GList *it;
     Rect *a, *mon;
+    Rect dock_area;
     gint edge;
 
     a = screen_area(self->desktop, SCREEN_AREA_ALL_MONITORS,
     gint edge;
 
     a = screen_area(self->desktop, SCREEN_AREA_ALL_MONITORS,
@@ -3863,27 +3994,27 @@ void client_find_edge_directional(ObClient *self, ObDirection dir,
     mon = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR,
                       &self->frame->area);
 
     mon = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR,
                       &self->frame->area);
 
-    switch(dir) {
+    switch (dir) {
     case OB_DIRECTION_NORTH:
     case OB_DIRECTION_NORTH:
-        if (my_head >= RECT_TOP(*mon))
+        if (my_head >= RECT_TOP(*mon) + 1)
             edge = RECT_TOP(*mon) - 1;
         else
             edge = RECT_TOP(*a) - 1;
         break;
     case OB_DIRECTION_SOUTH:
             edge = RECT_TOP(*mon) - 1;
         else
             edge = RECT_TOP(*a) - 1;
         break;
     case OB_DIRECTION_SOUTH:
-        if (my_head <= RECT_BOTTOM(*mon))
+        if (my_head <= RECT_BOTTOM(*mon) - 1)
             edge = RECT_BOTTOM(*mon) + 1;
         else
             edge = RECT_BOTTOM(*a) + 1;
         break;
     case OB_DIRECTION_EAST:
             edge = RECT_BOTTOM(*mon) + 1;
         else
             edge = RECT_BOTTOM(*a) + 1;
         break;
     case OB_DIRECTION_EAST:
-        if (my_head <= RECT_RIGHT(*mon))
+        if (my_head <= RECT_RIGHT(*mon) - 1)
             edge = RECT_RIGHT(*mon) + 1;
         else
             edge = RECT_RIGHT(*a) + 1;
         break;
     case OB_DIRECTION_WEST:
             edge = RECT_RIGHT(*mon) + 1;
         else
             edge = RECT_RIGHT(*a) + 1;
         break;
     case OB_DIRECTION_WEST:
-        if (my_head >= RECT_LEFT(*mon))
+        if (my_head >= RECT_LEFT(*mon) + 1)
             edge = RECT_LEFT(*mon) - 1;
         else
             edge = RECT_LEFT(*a) - 1;
             edge = RECT_LEFT(*mon) - 1;
         else
             edge = RECT_LEFT(*a) - 1;
@@ -3895,10 +4026,8 @@ void client_find_edge_directional(ObClient *self, ObDirection dir,
     *dest = edge;
     *near_edge = TRUE;
 
     *dest = edge;
     *near_edge = TRUE;
 
-    for(it = client_list; it; it = g_list_next(it)) {
+    for (it = client_list; it; it = g_list_next(it)) {
         ObClient *cur = it->data;
         ObClient *cur = it->data;
-        gint edge_start, edge_size, head, tail;
-        gboolean skip_head = FALSE, skip_tail = FALSE;
 
         /* skip windows to not bump into */
         if (cur == self)
 
         /* skip windows to not bump into */
         if (cur == self)
@@ -3911,87 +4040,14 @@ void client_find_edge_directional(ObClient *self, ObDirection dir,
 
         ob_debug("trying window %s\n", cur->title);
 
 
         ob_debug("trying window %s\n", cur->title);
 
-        switch(dir) {
-        case OB_DIRECTION_NORTH:
-        case OB_DIRECTION_SOUTH:
-            edge_start = cur->frame->area.x;
-            edge_size = cur->frame->area.width;
-            break;
-        case OB_DIRECTION_EAST:
-        case OB_DIRECTION_WEST:
-            edge_start = cur->frame->area.y;
-            edge_size = cur->frame->area.height;
-            break;
-        default:
-            g_assert_not_reached();
-        }
-
-        /* do we collide with this window? */
-        if (!RANGES_INTERSECT(my_edge_start, my_edge_size,
-                              edge_start, edge_size))
-            continue;
-
-        switch(dir) {
-        case OB_DIRECTION_NORTH:
-            head = RECT_BOTTOM(cur->frame->area);
-            tail = RECT_TOP(cur->frame->area);
-            break;
-        case OB_DIRECTION_SOUTH:
-            head = RECT_TOP(cur->frame->area);
-            tail = RECT_BOTTOM(cur->frame->area);
-            break;
-        case OB_DIRECTION_EAST:
-            head = RECT_LEFT(cur->frame->area);
-            tail = RECT_RIGHT(cur->frame->area);
-            break;
-        case OB_DIRECTION_WEST:
-            head = RECT_RIGHT(cur->frame->area);
-            tail = RECT_LEFT(cur->frame->area);
-            break;
-        default:
-            g_assert_not_reached();
-        }
-
-        switch(dir) {
-        case OB_DIRECTION_NORTH:
-        case OB_DIRECTION_WEST:
-            if (my_head <= head + 1)
-                skip_head = TRUE;
-            if (my_head + my_size - 1 <= tail + 1)
-                skip_tail = TRUE;
-            if (head < *dest)
-                skip_head = TRUE;
-            if (tail - my_size < *dest)
-                skip_tail = TRUE;
-            break;
-        case OB_DIRECTION_SOUTH:
-        case OB_DIRECTION_EAST:
-            if (my_head >= head - 1)
-                skip_head = TRUE;
-            if (my_head - my_size + 1 >= tail - 1)
-                skip_tail = TRUE;
-            if (head > *dest)
-                skip_head = TRUE;
-            if (tail + my_size > *dest)
-                skip_tail = TRUE;
-            break;
-        default:
-            g_assert_not_reached();
-        }
-
-        ob_debug("my head %d size %d\n", my_head, my_size);
-        ob_debug("head %d tail %d deest %d\n", head, tail, *dest);
-        if (!skip_head) {
-            ob_debug("using near edge %d\n", head);
-            *dest = head;
-            *near_edge = TRUE;
-        }
-        else if (!skip_tail) {
-            ob_debug("using far edge %d\n", tail);
-            *dest = tail;
-            *near_edge = FALSE;
-        }
+        detect_edge(cur->frame->area, dir, my_head, my_size, my_edge_start,
+                    my_edge_size, dest, near_edge);
     }
     }
+    dock_get_area(&dock_area);
+    detect_edge(dock_area, dir, my_head, my_size, my_edge_start,
+                my_edge_size, dest, near_edge);
+    g_free(a);
+    g_free(mon);
 }
 
 void client_find_move_directional(ObClient *self, ObDirection dir,
 }
 
 void client_find_move_directional(ObClient *self, ObDirection dir,
@@ -4065,36 +4121,36 @@ void client_find_resize_directional(ObClient *self, ObDirection side,
                                     gboolean grow,
                                     gint *x, gint *y, gint *w, gint *h)
 {
                                     gboolean grow,
                                     gint *x, gint *y, gint *w, gint *h)
 {
-    gint head, size;
+    gint head;
     gint e, e_start, e_size, delta;
     gboolean near;
     ObDirection dir;
 
     switch (side) {
     case OB_DIRECTION_EAST:
     gint e, e_start, e_size, delta;
     gboolean near;
     ObDirection dir;
 
     switch (side) {
     case OB_DIRECTION_EAST:
-        head = RECT_RIGHT(self->frame->area) + (self->size_inc.width - 1);
-        size = self->frame->area.width;
+        head = RECT_RIGHT(self->frame->area) +
+            (self->size_inc.width - 1) * (grow ? 1 : -1);
         e_start = RECT_TOP(self->frame->area);
         e_size = self->frame->area.height;
         dir = grow ? OB_DIRECTION_EAST : OB_DIRECTION_WEST;
         break;
     case OB_DIRECTION_WEST:
         e_start = RECT_TOP(self->frame->area);
         e_size = self->frame->area.height;
         dir = grow ? OB_DIRECTION_EAST : OB_DIRECTION_WEST;
         break;
     case OB_DIRECTION_WEST:
-        head = RECT_LEFT(self->frame->area) - (self->size_inc.width - 1);
-        size = self->frame->area.width;
+        head = RECT_LEFT(self->frame->area) -
+            (self->size_inc.width - 1) * (grow ? 1 : -1);
         e_start = RECT_TOP(self->frame->area);
         e_size = self->frame->area.height;
         dir = grow ? OB_DIRECTION_WEST : OB_DIRECTION_EAST;
         break;
     case OB_DIRECTION_NORTH:
         e_start = RECT_TOP(self->frame->area);
         e_size = self->frame->area.height;
         dir = grow ? OB_DIRECTION_WEST : OB_DIRECTION_EAST;
         break;
     case OB_DIRECTION_NORTH:
-        head = RECT_TOP(self->frame->area) - (self->size_inc.height - 1);
-        size = self->frame->area.height;
+        head = RECT_TOP(self->frame->area) -
+            (self->size_inc.height - 1) * (grow ? 1 : -1);
         e_start = RECT_LEFT(self->frame->area);
         e_size = self->frame->area.width;
         dir = grow ? OB_DIRECTION_NORTH : OB_DIRECTION_SOUTH;
         break;
     case OB_DIRECTION_SOUTH:
         e_start = RECT_LEFT(self->frame->area);
         e_size = self->frame->area.width;
         dir = grow ? OB_DIRECTION_NORTH : OB_DIRECTION_SOUTH;
         break;
     case OB_DIRECTION_SOUTH:
-        head = RECT_BOTTOM(self->frame->area) + (self->size_inc.height - 1);
-        size = self->frame->area.height;
+        head = RECT_BOTTOM(self->frame->area) +
+            (self->size_inc.height - 1) * (grow ? 1 : -1);
         e_start = RECT_LEFT(self->frame->area);
         e_size = self->frame->area.width;
         dir = grow ? OB_DIRECTION_SOUTH : OB_DIRECTION_NORTH;
         e_start = RECT_LEFT(self->frame->area);
         e_size = self->frame->area.width;
         dir = grow ? OB_DIRECTION_SOUTH : OB_DIRECTION_NORTH;
@@ -4103,32 +4159,34 @@ void client_find_resize_directional(ObClient *self, ObDirection side,
         g_assert_not_reached();
     }
 
         g_assert_not_reached();
     }
 
-    client_find_edge_directional(self, dir, head, size,
+    ob_debug("head %d dir %d\n", head, dir);
+    client_find_edge_directional(self, dir, head, 1,
                                  e_start, e_size, &e, &near);
                                  e_start, e_size, &e, &near);
+    ob_debug("edge %d\n", e);
     *x = self->frame->area.x;
     *y = self->frame->area.y;
     *w = self->frame->area.width;
     *h = self->frame->area.height;
     switch (side) {
     case OB_DIRECTION_EAST:
     *x = self->frame->area.x;
     *y = self->frame->area.y;
     *w = self->frame->area.width;
     *h = self->frame->area.height;
     switch (side) {
     case OB_DIRECTION_EAST:
-        if (near) --e;
+        if (grow == near) --e;
         delta = e - RECT_RIGHT(self->frame->area);
         *w += delta;
         break;
     case OB_DIRECTION_WEST:
         delta = e - RECT_RIGHT(self->frame->area);
         *w += delta;
         break;
     case OB_DIRECTION_WEST:
-        if (near) ++e;
+        if (grow == near) ++e;
         delta = RECT_LEFT(self->frame->area) - e;
         *x -= delta;
         *w += delta;
         break;
     case OB_DIRECTION_NORTH:
         delta = RECT_LEFT(self->frame->area) - e;
         *x -= delta;
         *w += delta;
         break;
     case OB_DIRECTION_NORTH:
-        if (near) ++e;
+        if (grow == near) ++e;
         delta = RECT_TOP(self->frame->area) - e;
         *y -= delta;
         *h += delta;
         break;
     case OB_DIRECTION_SOUTH:
         delta = RECT_TOP(self->frame->area) - e;
         *y -= delta;
         *h += delta;
         break;
     case OB_DIRECTION_SOUTH:
-        if (near) --e;
+        if (grow == near) --e;
         delta = e - RECT_BOTTOM(self->frame->area);
         *h += delta;
         break;
         delta = e - RECT_BOTTOM(self->frame->area);
         *h += delta;
         break;
@@ -4140,7 +4198,7 @@ void client_find_resize_directional(ObClient *self, ObDirection side,
     *h -= self->frame->size.top + self->frame->size.bottom;
 }
 
     *h -= self->frame->size.top + self->frame->size.bottom;
 }
 
-ObClient* client_under_pointer()
+ObClient* client_under_pointer(void)
 {
     gint x, y;
     GList *it;
 {
     gint x, y;
     GList *it;
@@ -4173,30 +4231,3 @@ gboolean client_has_group_siblings(ObClient *self)
 {
     return self->group && self->group->members->next;
 }
 {
     return self->group && self->group->members->next;
 }
-
-ObClientIcon *client_thumbnail(ObClient *self, gint wantw, gint wanth)
-{
-    ObClientIcon *ret;
-    RrPixel32 *data;
-    gint w, h;
-
-    if (!self->frame->pixmap) return NULL;
-    if (!RrPixmapToRGBA(ob_rr_inst, self->frame->pixmap, None, &w, &h, &data))
-        return NULL;
-
-    /* resize the thumbnail (within aspect ratio) to the given sizes */
-
-    ret = g_new(ObClientIcon, 1);
-    ret->data = data;
-    ret->width = w;
-    ret->height = h;
-    return ret;
-}
-
-void clienticon_free(ObClientIcon *ci)
-{
-    if (ci) {
-        g_free(ci->data);
-        g_free(ci);
-    }
-}
This page took 0.055757 seconds and 4 git commands to generate.