]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
make startup notification a little more robust. obconf is just broken, between
[chaz/openbox] / openbox / client.c
index 30bceae596787706e024eaffd351aec0e816c7ae..5441dbd91f219d335f49f1aed1fb46a5cec7fcc4 100644 (file)
@@ -1,19 +1,20 @@
 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
-client.c for the Openbox window manager
-Copyright (c) 2003        Ben Jansens
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-See the COPYING file for a copy of the GNU General Public License.
+   
+   client.c for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   Copyright (c) 2003        Ben Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
 */
 
 #include "client.h"
@@ -45,10 +46,10 @@ See the COPYING file for a copy of the GNU General Public License.
 
 /*! The event mask to grab on client windows */
 #define CLIENT_EVENTMASK (PropertyChangeMask | FocusChangeMask | \
-                         StructureNotifyMask)
+                          StructureNotifyMask)
 
 #define CLIENT_NOPROPAGATEMASK (ButtonPressMask | ButtonReleaseMask | \
-                               ButtonMotionMask)
+                                ButtonMotionMask)
 
 typedef struct
 {
@@ -119,13 +120,13 @@ void client_set_list()
     if (size > 0) {
         windows = g_new(Window, size);
         win_it = windows;
-        for (it = client_list; it != NULL; it = it->next, ++win_it)
+        for (it = client_list; it; it = g_list_next(it), ++win_it)
             *win_it = ((ObClient*)it->data)->window;
     } else
         windows = NULL;
 
     PROP_SETA32(RootWindow(ob_display, ob_screen),
-                net_client_list, window, (guint32*)windows, size);
+                net_client_list, window, (gulong*)windows, size);
 
     if (windows)
         g_free(windows);
@@ -134,17 +135,17 @@ void client_set_list()
 }
 
 /*
-  void client_foreach_transient(ObClient *self, ObClientForeachFunc func, void *data)
+  void client_foreach_transient(ObClient *self, ObClientForeachFunc func, gpointer data)
   {
   GSList *it;
 
-  for (it = self->transients; it; it = it->next) {
+  for (it = self->transients; it; it = g_slist_next(it)) {
   if (!func(it->data, data)) return;
   client_foreach_transient(it->data, func, data);
   }
   }
 
-  void client_foreach_ancestor(ObClient *self, ObClientForeachFunc func, void *data)
+  void client_foreach_ancestor(ObClient *self, ObClientForeachFunc func, gpointer data)
   {
   if (self->transient_for) {
   if (self->transient_for != OB_TRAN_GROUP) {
@@ -153,7 +154,7 @@ void client_set_list()
   } else {
   GSList *it;
 
-  for (it = self->group->members; it; it = it->next)
+  for (it = self->group->members; it; it = g_slist_next(it))
   if (it->data != self &&
   !((ObClient*)it->data)->transient_for) {
   if (!func(it->data, data)) return;
@@ -203,6 +204,33 @@ void client_manage_all()
     XFree(children);
 }
 
+static ObAppSettings *get_settings(ObClient *client)
+{
+    GSList *a = config_per_app_settings;
+
+    while (a) {
+        ObAppSettings *app = (ObAppSettings *) a->data;
+        
+        if (
+            (app->name && !app->class && !strcmp(app->name, client->name))
+            || (app->class && !app->name && !strcmp(app->class, client->class))
+            || (app->class && app->name && !strcmp(app->class, client->class)
+                && !strcmp(app->name, client->name))
+            ) {
+            ob_debug("Window matching: %s\n", app->name);
+            /* Match if no role was specified in the per app setting, or if the
+             * string matches the beginning of the role, since apps like to set
+             * the role to things like browser-window-23c4b2f */
+            if (!app->role
+                || !strncmp(app->role, client->role, strlen(app->role)))
+                return app;
+        }
+
+        a = a->next;
+    }
+    return NULL;
+}
+
 void client_manage(Window window)
 {
     ObClient *self;
@@ -211,13 +239,15 @@ void client_manage(Window window)
     XSetWindowAttributes attrib_set;
     XWMHints *wmhint;
     gboolean activate = FALSE;
+    ObAppSettings *settings;
 
     grab_server(TRUE);
 
     /* check if it has already been unmapped by the time we started mapping
        the grab does a sync so we don't have to here */
     if (XCheckTypedWindowEvent(ob_display, window, DestroyNotify, &e) ||
-        XCheckTypedWindowEvent(ob_display, window, UnmapNotify, &e)) {
+        XCheckTypedWindowEvent(ob_display, window, UnmapNotify, &e))
+    {
         XPutBackEvent(ob_display, &e);
 
         grab_server(FALSE);
@@ -226,7 +256,8 @@ void client_manage(Window window)
 
     /* make sure it isn't an override-redirect window */
     if (!XGetWindowAttributes(ob_display, window, &attrib) ||
-        attrib.override_redirect) {
+        attrib.override_redirect)
+    {
         grab_server(FALSE);
         return; /* don't manage it */
     }
@@ -234,7 +265,8 @@ void client_manage(Window window)
     /* is the window a docking app */
     if ((wmhint = XGetWMHints(ob_display, window))) {
         if ((wmhint->flags & StateHint) &&
-            wmhint->initial_state == WithdrawnState) {
+            wmhint->initial_state == WithdrawnState)
+        {
             dock_add(window, wmhint);
             grab_server(FALSE);
             XFree(wmhint);
@@ -267,7 +299,11 @@ void client_manage(Window window)
     client_get_all(self);
     client_restore_session_state(self);
 
-    sn_app_started(self->class);
+    sn_app_started(self->startup_id, self->class);
+
+    /* update the focus lists, do this before the call to change_state or
+       it can end up in the list twice! */
+    focus_order_add_new(self);
 
     client_change_state(self);
 
@@ -279,7 +315,7 @@ void client_manage(Window window)
     XChangeSaveSet(ob_display, window, SetModeInsert);
 
     /* create the decoration frame for the client window */
-    self->frame = frame_new();
+    self->frame = frame_new(self);
 
     frame_grab_client(self->frame, self);
 
@@ -287,21 +323,68 @@ void client_manage(Window window)
 
     client_apply_startup_state(self);
 
-    /* update the focus lists */
-    focus_order_add_new(self);
+    /* get and set application level settings */
+    settings = get_settings(self);
 
     stacking_add(CLIENT_AS_WINDOW(self));
     client_restore_session_stacking(self);
 
+    if (settings) {
+        /* Don't worry, we won't actually both shade and undecorate the
+         * window when push comes to shove. */
+        if (settings->shade != -1)
+            client_shade(self, !!settings->shade);
+        if (settings->decor != -1)
+            client_set_undecorated(self, !settings->decor);
+        if (settings->iconic != -1)
+            client_iconify(self, !!settings->iconic, FALSE);
+        if (settings->skip_pager != -1) {
+            self->skip_pager = !!settings->skip_pager;
+            client_change_state(self);
+        }
+        if (settings->skip_taskbar != -1) {
+            self->skip_taskbar = !!settings->skip_taskbar;
+            client_change_state(self);
+        }
+
+        /* 1 && -1 shouldn't be possible by the code in config.c */
+        if (settings->max_vert == 1 && settings->max_horz == 1)
+            client_maximize(self, TRUE, 0, TRUE);
+        else if (settings->max_vert == 0 && settings->max_horz == 0)
+            client_maximize(self, FALSE, 0, TRUE);
+        else if (settings->max_vert == 1 && settings->max_horz == 0) {
+            client_maximize(self, TRUE, 2, TRUE);
+            client_maximize(self, FALSE, 1, TRUE);
+        } else if (settings->max_vert == 0 && settings->max_horz == 1) {
+            client_maximize(self, TRUE, 1, TRUE);
+            client_maximize(self, FALSE, 2, TRUE);
+        }
+
+        if (settings->fullscreen != -1)
+            client_fullscreen(self, !!settings->fullscreen, TRUE);
+
+        if (settings->desktop < screen_num_desktops
+            || settings->desktop == DESKTOP_ALL)
+            client_set_desktop(self, settings->desktop, TRUE);
+
+        if (settings->layer > -2 && settings->layer < 2)
+            client_set_layer(self, settings->layer);
+
+    }
+
     /* focus the new window? */
     if (ob_state() != OB_STATE_STARTING &&
-        (config_focus_new || client_search_focus_parent(self)) &&
+        /* this means focus=true for window is same as config_focus_new=true */
+        ((config_focus_new || (settings && settings->focus == 1)) ||
+         client_search_focus_parent(self)) &&
+        /* this checks for focus=false for the window */
+        (!settings || settings->focus != 0) &&
         /* note the check against Type_Normal/Dialog, not client_normal(self),
            which would also include other types. in this case we want more
            strict rules for focus */
         (self->type == OB_CLIENT_TYPE_NORMAL ||
          self->type == OB_CLIENT_TYPE_DIALOG))
-    {        
+    {
         activate = TRUE;
 #if 0
         if (self->desktop != screen_desktop) {
@@ -313,7 +396,7 @@ void client_manage(Window window)
             if (self->group) {
                 GSList *it;
 
-                for (it = self->group->members; it; it = it->next)
+                for (it = self->group->members; it; it = g_slist_next(it))
                 {
                     if (client_focused(it->data))
                     {
@@ -339,23 +422,36 @@ void client_manage(Window window)
     if (ob_state() == OB_STATE_RUNNING) {
         gint x = self->area.x, ox = x;
         gint y = self->area.y, oy = y;
+        gboolean transient;
 
-        place_client(self, &x, &y);
+        transient = place_client(self, &x, &y, settings);
 
-        /* make sure the window is visible */
+        /* make sure the window is visible. */
         client_find_onscreen(self, &x, &y,
                              self->frame->area.width,
                              self->frame->area.height,
                              /* non-normal clients has less rules, and
-                                windows that are being restored from a session
-                                do also. we can assume you want it back where
-                                you saved it */
-                             client_normal(self) && !self->session);
-
-        if (x != ox || y != oy)
+                                windows that are being restored from a
+                                session do also. we can assume you want
+                                it back where you saved it. Clients saying
+                                they placed themselves are subjected to
+                                harder rules, ones that are placed by
+                                place.c or by the user are allowed partially
+                                off-screen and on xinerama divides (ie,
+                                it is up to the placement routines to avoid
+                                the xinerama divides) */
+                             transient ||
+                             (((self->positioned & PPosition) &&
+                               !(self->positioned & USPosition)) &&
+                              client_normal(self) &&
+                              !self->session));
+        if (x != ox || y != oy)         
             client_move(self, x, y);
     }
 
+    keyboard_grab_for_client(self, TRUE);
+    mouse_grab_for_client(self, TRUE);
+
     client_showhide(self);
 
     /* use client_focus instead of client_activate cuz client_activate does
@@ -385,14 +481,12 @@ void client_manage(Window window)
     g_hash_table_insert(window_map, &self->window, self);
 
     /* this has to happen after we're in the client_list */
-    screen_update_areas();
+    if (STRUT_EXISTS(self->strut))
+        screen_update_areas();
 
     /* update the list hints */
     client_set_list();
 
-    keyboard_grab_for_client(self, TRUE);
-    mouse_grab_for_client(self, TRUE);
-
     ob_debug("Managed window 0x%lx (%s)\n", window, self->class);
 }
 
@@ -414,6 +508,10 @@ void client_unmanage(ObClient *self)
     keyboard_grab_for_client(self, FALSE);
     mouse_grab_for_client(self, FALSE);
 
+    /* potentially fix focusLast */
+    if (config_focus_last)
+        grab_pointer(TRUE, OB_CURSOR_NONE);
+
     /* remove the window from our save set */
     XChangeSaveSet(ob_display, self->window, SetModeDelete);
 
@@ -431,7 +529,8 @@ void client_unmanage(ObClient *self)
 
     /* once the client is out of the list, update the struts to remove it's
        influence */
-    screen_update_areas();
+    if (STRUT_EXISTS(self->strut))
+        screen_update_areas();
 
     for (it = client_destructors; it; it = g_slist_next(it)) {
         Destructor *d = it->data;
@@ -454,9 +553,7 @@ void client_unmanage(ObClient *self)
 
     /* tell our parent(s) that we're gone */
     if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */
-        GSList *it;
-
-        for (it = self->group->members; it; it = it->next)
+        for (it = self->group->members; it; it = g_slist_next(it))
             if (it->data != self)
                 ((ObClient*)it->data)->transients =
                     g_slist_remove(((ObClient*)it->data)->transients, self);
@@ -466,7 +563,7 @@ void client_unmanage(ObClient *self)
     }
 
     /* tell our transients that we're gone */
-    for (it = self->transients; it != NULL; it = it->next) {
+    for (it = self->transients; it; it = g_slist_next(it)) {
         if (((ObClient*)it->data)->transient_for != OB_TRAN_GROUP) {
             ((ObClient*)it->data)->transient_for = NULL;
             client_calc_layer(it->data);
@@ -517,6 +614,9 @@ void client_unmanage(ObClient *self)
      
     /* update the list hints */
     client_set_list();
+
+    if (config_focus_last)
+        grab_pointer(FALSE, OB_CURSOR_NONE);
 }
 
 static void client_urgent_notify(ObClient *self)
@@ -537,7 +637,7 @@ static void client_restore_session_state(ObClient *self)
     self->session = it->data;
 
     RECT_SET_POINT(self->area, self->session->x, self->session->y);
-    self->positioned = TRUE;
+    self->positioned = PPosition;
     if (self->session->w > 0)
         self->area.width = self->session->w;
     if (self->session->h > 0)
@@ -604,24 +704,39 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
                                                 would be */
 
     /* XXX watch for xinerama dead areas */
-
-    a = screen_area(self->desktop);
+    /* This makes sure windows aren't entirely outside of the screen so you
+       can't see them at all.
+       It makes sure 10% of the window is on the screen at least. At don't let
+       it move itself off the top of the screen, which would hide the titlebar
+       on you. (The user can still do this if they want too, it's only limiting
+       the application.
+    */
     if (client_normal(self)) {
-        if (!self->strut.right && *x >= a->x + a->width - 1)
-            *x = a->x + a->width - self->frame->area.width;
-        if (!self->strut.bottom && *y >= a->y + a->height - 1)
-            *y = a->y + a->height - self->frame->area.height;
-        if (!self->strut.left && *x + self->frame->area.width - 1 < a->x)
-            *x = a->x;
-        if (!self->strut.top && *y + self->frame->area.height - 1 < a->y)
-            *y = a->y;
-    }
-
+        a = screen_area(self->desktop);
+        if (!self->strut.right &&
+            *x + self->frame->area.width/10 >= a->x + a->width - 1)
+            *x = a->x + a->width - self->frame->area.width/10;
+        if (!self->strut.bottom &&
+            *y + self->frame->area.height/10 >= a->y + a->height - 1)
+            *y = a->y + a->height - self->frame->area.height/10;
+        if (!self->strut.left && *x + self->frame->area.width*9/10 - 1 < a->x)
+            *x = a->x - self->frame->area.width*9/10;
+        if (!self->strut.top && *y + self->frame->area.height*9/10 - 1 < a->y)
+            *y = a->y - self->frame->area.width*9/10;
+    }
+
+    /* This here doesn't let windows even a pixel outside the screen,
+     * when called from client_manage, programs placing themselves are
+     * forced completely onscreen, while things like
+     * xterm -geometry resolution-width/2 will work fine. Trying to
+     * place it completely offscreen will be handled in the above code.
+     * Sorry for this confused comment, i am tired. */
     if (rude) {
-        /* this is my MOZILLA BITCHSLAP. oh ya it fucking feels good.
-           Java can suck it too. */
-
-        /* dont let windows map/move into the strut unless they
+        /* avoid the xinerama monitor divide while we're at it,
+         * remember to fix the placement stuff to avoid it also and
+         * then remove this XXX */
+        a = screen_area_monitor(self->desktop, client_monitor(self));
+        /* dont let windows map into the strut unless they
            are bigger than the available area */
         if (w <= a->width) {
             if (!self->strut.left && *x < a->x) *x = a->x;
@@ -710,15 +825,23 @@ static void client_toggle_border(ObClient *self, gboolean show)
 static void client_get_all(ObClient *self)
 {
     client_get_area(self);
+    client_get_mwm_hints(self);
+
+    /* The transient hint is used to pick a type, but the type can also affect
+       transiency (dialogs are always made transients of their group if they
+       have one). This is Havoc's idea, but it is needed to make some apps
+       work right (eg tsclient). */
+    client_update_transient_for(self);
+    client_get_type(self);/* this can change the mwmhints for special cases */
     client_update_transient_for(self);
+
     client_update_wmhints(self);
     client_get_startup_id(self);
-    client_get_desktop(self);
-    client_get_state(self);
+    client_get_desktop(self);/* uses transient data/group/startup id if a
+                                desktop is not specified */
     client_get_shaped(self);
 
-    client_get_mwm_hints(self);
-    client_get_type(self);/* this can change the mwmhints for special cases */
+    client_get_state(self);
 
     {
         /* a couple type-based defaults for new windows */
@@ -726,10 +849,6 @@ static void client_get_all(ObClient *self)
         /* this makes sure that these windows appear on all desktops */
         if (self->type == OB_CLIENT_TYPE_DESKTOP)
             self->desktop = DESKTOP_ALL;
-
-        /* dock windows default to ABOVE */
-        if (self->type == OB_CLIENT_TYPE_DOCK && !self->below)
-            self->above = TRUE;
     }
 
     client_update_protocols(self);
@@ -788,7 +907,7 @@ static void client_get_desktop(ObClient *self)
             } else {
                 GSList *it;
 
-                for (it = self->group->members; it; it = it->next)
+                for (it = self->group->members; it; it = g_slist_next(it))
                     if (it->data != self &&
                         !((ObClient*)it->data)->transient_for) {
                         self->desktop = ((ObClient*)it->data)->desktop;
@@ -858,7 +977,7 @@ static void client_get_state(ObClient *self)
             for (it = self->group->members; it; it = g_slist_next(it)) {
                 ObClient *c = it->data;
                 if (c != self && !client_search_transient(self, c) &&
-                    client_normal(self) == client_normal(c))
+                    client_normal(self) && client_normal(c))
                 {
                     layer = MAX(layer,
                                 (c->above ? 1 : (c->below ? -1 : 0)));
@@ -917,7 +1036,13 @@ void client_update_transient_for(ObClient *self)
                    a dockapp, for example */
                 target = NULL;
             }
-            
+
+#if 0 
+/* we used to do this, but it violates the ICCCM and causes problems because
+   toolkits seem to set transient_for = root rather arbitrarily (eg kicker's
+   config dialogs), so it is being removed. the ewmh provides other ways to
+   make things transient for their group. -dana
+*/
             if (!target && self->group) {
                 /* not transient to a client, see if it is transient for a
                    group */
@@ -929,7 +1054,12 @@ void client_update_transient_for(ObClient *self)
                     target = OB_TRAN_GROUP;
                 }
             }
+#endif
+
         }
+    } else if (self->type == OB_CLIENT_TYPE_DIALOG && self->group) {
+        self->transient = TRUE;
+        target = OB_TRAN_GROUP;
     } else
         self->transient = FALSE;
 
@@ -1099,7 +1229,7 @@ void client_update_normal_hints(ObClient *self)
         /* normal windows can't request placement! har har
         if (!client_normal(self))
         */
-        self->positioned = !!(size.flags & (PPosition|USPosition));
+        self->positioned = (size.flags & (PPosition|USPosition));
 
         if (size.flags & PWinGravity) {
             self->gravity = size.win_gravity;
@@ -1133,7 +1263,7 @@ void client_update_normal_hints(ObClient *self)
         if (size.flags & PBaseSize)
             SIZE_SET(self->base_size, size.base_width, size.base_height);
     
-        if (size.flags & PResizeInc)
+        if (size.flags & PResizeInc && size.width_inc && size.height_inc)
             SIZE_SET(self->size_inc, size.width_inc, size.height_inc);
     }
 }
@@ -1143,7 +1273,7 @@ void client_setup_decor_and_functions(ObClient *self)
     /* start with everything (cept fullscreen) */
     self->decorations =
         (OB_FRAME_DECOR_TITLEBAR |
-         (ob_rr_theme->show_handle ? OB_FRAME_DECOR_HANDLE : 0) |
+         OB_FRAME_DECOR_HANDLE |
          OB_FRAME_DECOR_GRIPS |
          OB_FRAME_DECOR_BORDER |
          OB_FRAME_DECOR_ICON |
@@ -1198,9 +1328,15 @@ void client_setup_decor_and_functions(ObClient *self)
         if (! (self->mwmhints.decorations & OB_MWM_DECOR_ALL)) {
             if (! ((self->mwmhints.decorations & OB_MWM_DECOR_HANDLE) ||
                    (self->mwmhints.decorations & OB_MWM_DECOR_TITLE)))
+            {
                 /* if the mwm hints request no handle or title, then all
-                   decorations are disabled */
-                self->decorations = 0;
+                   decorations are disabled, but keep the border if that's
+                   specified */
+                if (self->mwmhints.decorations & OB_MWM_DECOR_BORDER)
+                    self->decorations = OB_FRAME_DECOR_BORDER;
+                else
+                    self->decorations = 0;
+            }
         }
     }
 
@@ -1219,7 +1355,7 @@ void client_setup_decor_and_functions(ObClient *self)
             /* dont let mwm hints kill the close button
                if (! (self->mwmhints.functions & MwmFunc_Close))
                self->functions &= ~OB_CLIENT_FUNC_CLOSE; */
-           }
+        }
     }
 
     if (!(self->functions & OB_CLIENT_FUNC_SHADE))
@@ -1243,8 +1379,12 @@ void client_setup_decor_and_functions(ObClient *self)
 
     /* finally, the user can have requested no decorations, which overrides
        everything (but doesnt give it a border if it doesnt have one) */
-    if (self->undecorated)
-        self->decorations &= OB_FRAME_DECOR_BORDER;
+    if (self->undecorated) {
+        if (config_theme_keepborder)
+            self->decorations &= OB_FRAME_DECOR_BORDER;
+        else
+            self->decorations = 0;
+    }
 
     /* if we don't have a titlebar, then we cannot shade! */
     if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
@@ -1268,7 +1408,7 @@ void client_setup_decor_and_functions(ObClient *self)
 
 static void client_change_allowed_actions(ObClient *self)
 {
-    guint32 actions[9];
+    gulong actions[9];
     gint num = 0;
 
     /* desktop windows are kept on all desktops */
@@ -1355,13 +1495,15 @@ void client_update_wmhints(ObClient *self)
             /* remove from the old group if there was one */
             if (self->group != NULL) {
                 /* remove transients of the group */
-                for (it = self->group->members; it; it = it->next)
+                for (it = self->group->members; it; it = g_slist_next(it))
                     self->transients = g_slist_remove(self->transients,
                                                       it->data);
 
                 /* remove myself from parents in the group */
                 if (self->transient_for == OB_TRAN_GROUP) {
-                    for (it = self->group->members; it; it = it->next) {
+                    for (it = self->group->members; it;
+                         it = g_slist_next(it))
+                    {
                         ObClient *c = it->data;
 
                         if (c != self && !c->transient_for)
@@ -1381,7 +1523,9 @@ void client_update_wmhints(ObClient *self)
                 if (!self->transient_for) {
                     /* add other transients of the group that are already
                        set up */
-                    for (it = self->group->members; it; it = it->next) {
+                    for (it = self->group->members; it;
+                         it = g_slist_next(it))
+                    {
                         ObClient *c = it->data;
                         if (c != self && c->transient_for == OB_TRAN_GROUP)
                             self->transients =
@@ -1424,40 +1568,65 @@ void client_update_title(ObClient *self)
     old_title = self->title;
      
     /* try netwm */
-    if (!PROP_GETS(self->window, net_wm_name, utf8, &data))
+    if (!PROP_GETS(self->window, net_wm_name, utf8, &data)) {
         /* try old x stuff */
-        if (!PROP_GETS(self->window, wm_name, locale, &data))
-            data = g_strdup("Unnamed Window");
+        if (!(PROP_GETS(self->window, wm_name, locale, &data)
+              || PROP_GETS(self->window, wm_name, utf8, &data))) {
+            // http://developer.gnome.org/projects/gup/hig/draft_hig_new/windows-alert.html
+            if (self->transient) {
+                data = g_strdup("");
+                goto no_number;
+            } else
+                data = g_strdup("Unnamed Window");
+        }
+    }
 
-    /* did the title change? then reset the title_count */
-    if (old_title && 0 != strncmp(old_title, data, strlen(data)))
-        self->title_count = 1;
+    if (config_title_number) {
 
-    /* look for duplicates and append a number */
-    nums = 0;
-    for (it = client_list; it; it = it->next)
-        if (it->data != self) {
-            ObClient *c = it->data;
-            if (0 == strncmp(c->title, data, strlen(data)))
-                nums |= 1 << c->title_count;
-        }
-    /* find first free number */
-    for (i = 1; i <= 32; ++i)
-        if (!(nums & (1 << i))) {
-            if (self->title_count == 1 || i == 1)
-                self->title_count = i;
-            break;
+        /* did the title change? then reset the title_count */
+        if (old_title && 0 != strncmp(old_title, data, strlen(data)))
+            self->title_count = 1;
+
+        /* look for duplicates and append a number */
+        nums = 0;
+        for (it = client_list; it; it = g_list_next(it))
+            if (it->data != self) {
+                ObClient *c = it->data;
+
+                if (c->title_count == 1) {
+                    if (!strcmp(c->title, data))
+                        nums |= 1 << c->title_count;
+                } else {
+                    size_t len;
+                    gchar *end;
+
+                    /* find the beginning of our " - [%u]", this relies on
+                     that syntax being used */
+                    end = strrchr(c->title, '-') - 1; 
+                    len = end - c->title;
+                    if (!strncmp(c->title, data, len))
+                        nums |= 1 << c->title_count;
+                }
+            }
+        /* find first free number */
+        for (i = 1; i <= 32; ++i)
+            if (!(nums & (1 << i))) {
+                if (self->title_count == 1 || i == 1)
+                    self->title_count = i;
+                break;
+            }
+        /* dont display the number for the first window */
+        if (self->title_count > 1) {
+            gchar *ndata;
+            ndata = g_strdup_printf("%s - [%u]", data, self->title_count);
+            g_free(data);
+            data = ndata;
         }
-    /* dont display the number for the first window */
-    if (self->title_count > 1) {
-        gchar *ndata;
-        ndata = g_strdup_printf("%s - [%u]", data, self->title_count);
-        g_free(data);
-        data = ndata;
-    }
+    } else
+        self->title_count = 1;
 
+no_number:
     PROP_SETS(self->window, net_wm_visible_name, data);
-
     self->title = data;
 
     if (self->frame)
@@ -1473,19 +1642,20 @@ void client_update_title(ObClient *self)
     /* try netwm */
     if (!PROP_GETS(self->window, net_wm_icon_name, utf8, &data))
         /* try old x stuff */
-        if (!PROP_GETS(self->window, wm_icon_name, locale, &data)) {
+        if (!(PROP_GETS(self->window, wm_icon_name, locale, &data)
+              || PROP_GETS(self->window, wm_icon_name, utf8, &data))) {
             data = g_strdup(self->title);
             read_title = FALSE;
         }
 
-    /* append the title count, dont display the number for the first window */
+    /* append the title count, dont display the number for the first window.
+     * We don't need to check for config_title_number here since title_count
+     * is not set above 1 then. */
     if (read_title && self->title_count > 1) {
-        gchar *vdata, *ndata;
-        ndata = g_strdup_printf(" - [%u]", self->title_count);
-        vdata = g_strconcat(data, ndata, NULL);
-        g_free(ndata);
+        gchar *newdata;
+        newdata = g_strdup_printf("%s - [%u]", data, self->title_count);
         g_free(data);
-        data = vdata;
+        data = newdata;
     }
 
     PROP_SETS(self->window, net_wm_visible_icon_name, data);
@@ -1672,8 +1842,8 @@ void client_update_icons(ObClient *self)
 
 static void client_change_state(ObClient *self)
 {
-    guint32 state[2];
-    guint32 netstate[11];
+    gulong state[2];
+    gulong netstate[11];
     guint num;
 
     state[0] = self->wmstate;
@@ -1716,7 +1886,7 @@ ObClient *client_search_focus_tree(ObClient *self)
     GSList *it;
     ObClient *ret;
 
-    for (it = self->transients; it != NULL; it = it->next) {
+    for (it = self->transients; it; it = g_slist_next(it)) {
         if (client_focused(it->data)) return it->data;
         if ((ret = client_search_focus_tree(it->data))) return ret;
     }
@@ -1732,7 +1902,7 @@ ObClient *client_search_focus_tree_full(ObClient *self)
             GSList *it;
             gboolean recursed = FALSE;
         
-            for (it = self->group->members; it; it = it->next)
+            for (it = self->group->members; it; it = g_slist_next(it))
                 if (!((ObClient*)it->data)->transient_for) {
                     ObClient *c;
                     if ((c = client_search_focus_tree_full(it->data)))
@@ -1761,9 +1931,8 @@ static ObStackingLayer calc_layer(ObClient *self)
     else if (self->type == OB_CLIENT_TYPE_DESKTOP)
         l = OB_STACKING_LAYER_DESKTOP;
     else if (self->type == OB_CLIENT_TYPE_DOCK) {
-        if (self->above) l = OB_STACKING_LAYER_DOCK_ABOVE;
-        else if (self->below) l = OB_STACKING_LAYER_DOCK_BELOW;
-        else l = OB_STACKING_LAYER_NORMAL;
+        if (self->below) l = OB_STACKING_LAYER_NORMAL;
+        else l = OB_STACKING_LAYER_ABOVE;
     }
     else if (self->above) l = OB_STACKING_LAYER_ABOVE;
     else if (self->below) l = OB_STACKING_LAYER_BELOW;
@@ -1782,7 +1951,7 @@ static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
     own = calc_layer(self);
     self->layer = l > own ? l : own;
 
-    for (it = self->transients; it; it = it->next)
+    for (it = self->transients; it; it = g_slist_next(it))
         client_calc_layer_recursive(it->data, orig,
                                     l, raised ? raised : l != old);
 
@@ -1918,35 +2087,16 @@ void client_configure_full(ObClient *self, ObCorner anchor,
 
     /* set the size and position if fullscreen */
     if (self->fullscreen) {
-#ifdef VIDMODE
-        gint dot;
-        XF86VidModeModeLine mode;
-#endif
         Rect *a;
         guint i;
 
         i = client_monitor(self);
         a = screen_physical_area_monitor(i);
 
-#ifdef VIDMODE
-        if (i == 0 && /* primary head */
-            extensions_vidmode &&
-            XF86VidModeGetViewPort(ob_display, ob_screen, &x, &y) &&
-            /* get the mode last so the mode.privsize isnt freed incorrectly */
-            XF86VidModeGetModeLine(ob_display, ob_screen, &dot, &mode)) {
-            x += a->x;
-            y += a->y;
-            w = mode.hdisplay;
-            h = mode.vdisplay;
-            if (mode.privsize) XFree(mode.private);
-        } else
-#endif
-        {
-            x = a->x;
-            y = a->y;
-            w = a->width;
-            h = a->height;
-        }
+        x = a->x;
+        y = a->y;
+        w = a->width;
+        h = a->height;
 
         user = FALSE; /* ignore that increment etc shit when in fullscreen */
     } else {
@@ -2036,26 +2186,28 @@ void client_configure_full(ObClient *self, ObCorner anchor,
         w -= self->base_size.width;
         h -= self->base_size.height;
 
-        if (self->min_ratio)
-            if (h * self->min_ratio > w) {
-                h = (gint)(w / self->min_ratio);
+        if (!self->fullscreen) {
+            if (self->min_ratio)
+                if (h * self->min_ratio > w) {
+                    h = (gint)(w / self->min_ratio);
 
-                /* you cannot resize to nothing */
-                if (h < 1) {
-                    h = 1;
-                    w = (gint)(h * self->min_ratio);
+                    /* you cannot resize to nothing */
+                    if (h < 1) {
+                        h = 1;
+                        w = (gint)(h * self->min_ratio);
+                    }
                 }
-            }
-        if (self->max_ratio)
-            if (h * self->max_ratio < w) {
-                h = (gint)(w / self->max_ratio);
-
-                /* you cannot resize to nothing */
-                if (h < 1) {
-                    h = 1;
-                    w = (gint)(h * self->min_ratio);
+            if (self->max_ratio)
+                if (h * self->max_ratio < w) {
+                    h = (gint)(w / self->max_ratio);
+
+                    /* you cannot resize to nothing */
+                    if (h < 1) {
+                        h = 1;
+                        w = (gint)(h * self->min_ratio);
+                    }
                 }
-            }
+        }
 
         w += self->base_size.width;
         h += self->base_size.height;
@@ -2091,9 +2243,9 @@ void client_configure_full(ObClient *self, ObCorner anchor,
        resizing in redraw mode */
     send_resize_client = ((!user && resized) ||
                           (user && (final ||
-                                    (resized && config_redraw_resize))));
+                                    (resized && config_resize_redraw))));
 
-    /* if the client is enlarging, the resize the client before the frame */
+    /* if the client is enlarging, then resize the client before the frame */
     if (send_resize_client && user && (w > oldw || h > oldh))
         XResizeWindow(ob_display, self->window, MAX(w, oldw), MAX(h, oldh));
 
@@ -2228,12 +2380,6 @@ static void client_iconify_recursive(ObClient *self,
             focus_order_remove(self);
             focus_order_add_new(self);
 
-            /* this is here cuz with the VIDMODE extension, the viewport can
-               change while a fullscreen window is iconic, and when it
-               uniconifies, it would be nice if it did so to the new position
-               of the viewport */
-            client_reconfigure(self);
-
             changed = TRUE;
         }
     }
@@ -2241,11 +2387,12 @@ static void client_iconify_recursive(ObClient *self,
     if (changed) {
         client_change_state(self);
         client_showhide(self);
-        screen_update_areas();
+        if (STRUT_EXISTS(self->strut))
+            screen_update_areas();
     }
 
     /* iconify all transients */
-    for (it = self->transients; it != NULL; it = it->next)
+    for (it = self->transients; it; it = g_slist_next(it))
         if (it->data != self) client_iconify_recursive(it->data,
                                                        iconic, curdesk);
 }
@@ -2389,7 +2536,7 @@ void client_close(ObClient *self)
     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_lasttime;
+    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;
@@ -2427,7 +2574,8 @@ void client_set_desktop_recursive(ObClient *self,
         /* raise if it was not already on the desktop */
         if (old != DESKTOP_ALL)
             client_raise(self);
-        screen_update_areas();
+        if (STRUT_EXISTS(self->strut))
+            screen_update_areas();
 
         /* add to the new desktop(s) */
         if (config_focus_new)
@@ -2437,7 +2585,7 @@ void client_set_desktop_recursive(ObClient *self,
     }
 
     /* move all transients */
-    for (it = self->transients; it != NULL; it = it->next)
+    for (it = self->transients; it; it = g_slist_next(it))
         if (it->data != self) client_set_desktop_recursive(it->data,
                                                            target, donthide);
 }
@@ -2453,7 +2601,7 @@ ObClient *client_search_modal_child(ObClient *self)
     GSList *it;
     ObClient *ret;
   
-    for (it = self->transients; it != NULL; it = it->next) {
+    for (it = self->transients; it; it = g_slist_next(it)) {
         ObClient *c = it->data;
         if ((ret = client_search_modal_child(c))) return ret;
         if (c->modal) return c;
@@ -2498,6 +2646,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
     gboolean max_horz = self->max_horz;
     gboolean max_vert = self->max_vert;
     gboolean modal = self->modal;
+    gboolean iconic = self->iconic;
     gint i;
 
     if (!(action == prop_atoms.net_wm_state_add ||
@@ -2533,6 +2682,10 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
                 action = self->skip_pager ?
                     prop_atoms.net_wm_state_remove :
                     prop_atoms.net_wm_state_add;
+            else if (state == prop_atoms.net_wm_state_hidden)
+                action = self->iconic ?
+                    prop_atoms.net_wm_state_remove :
+                    prop_atoms.net_wm_state_add;
             else if (state == prop_atoms.net_wm_state_fullscreen)
                 action = fullscreen ?
                     prop_atoms.net_wm_state_remove :
@@ -2561,11 +2714,15 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
                 self->skip_taskbar = TRUE;
             } else if (state == prop_atoms.net_wm_state_skip_pager) {
                 self->skip_pager = TRUE;
+            } else if (state == prop_atoms.net_wm_state_hidden) {
+                iconic = TRUE;
             } else if (state == prop_atoms.net_wm_state_fullscreen) {
                 fullscreen = TRUE;
             } else if (state == prop_atoms.net_wm_state_above) {
                 self->above = TRUE;
+                self->below = FALSE;
             } else if (state == prop_atoms.net_wm_state_below) {
+                self->above = FALSE;
                 self->below = TRUE;
             } else if (state == prop_atoms.ob_wm_state_undecorated) {
                 undecorated = TRUE;
@@ -2584,6 +2741,8 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
                 self->skip_taskbar = FALSE;
             } else if (state == prop_atoms.net_wm_state_skip_pager) {
                 self->skip_pager = FALSE;
+            } else if (state == prop_atoms.net_wm_state_hidden) {
+                iconic = FALSE;
             } else if (state == prop_atoms.net_wm_state_fullscreen) {
                 fullscreen = FALSE;
             } else if (state == prop_atoms.net_wm_state_above) {
@@ -2626,6 +2785,9 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
            transients needs to change */
         client_raise(self);
     }
+    if (iconic != self->iconic)
+        client_iconify(self, iconic, FALSE);
+
     client_calc_layer(self);
     client_change_state(self); /* change the hint to reflect these changes */
 }
@@ -2696,7 +2858,7 @@ gboolean client_focus(ObClient *self)
            #799. So now it is RevertToNone again.
         */
         XSetInputFocus(ob_display, self->window, RevertToNone,
-                       event_lasttime);
+                       event_curtime);
     }
 
     if (self->focus_notify) {
@@ -2707,7 +2869,7 @@ gboolean client_focus(ObClient *self)
         ce.xclient.window = self->window;
         ce.xclient.format = 32;
         ce.xclient.data.l[0] = prop_atoms.wm_take_focus;
-        ce.xclient.data.l[1] = event_lasttime;
+        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;
@@ -2717,7 +2879,7 @@ gboolean client_focus(ObClient *self)
 #ifdef DEBUG_FOCUS
     ob_debug("%sively focusing %lx at %d\n",
              (self->can_focus ? "act" : "pass"),
-             self->window, (gint) event_lasttime);
+             self->window, (gint) event_curtime);
 #endif
 
     /* Cause the FocusIn to come back to us. Important for desktop switches,
@@ -2727,18 +2889,23 @@ gboolean client_focus(ObClient *self)
     return TRUE;
 }
 
+/* Used when the current client is closed, focus_last will then prevent
+ * focus from going to the mouse pointer */
 void client_unfocus(ObClient *self)
 {
     if (focus_client == self) {
 #ifdef DEBUG_FOCUS
         ob_debug("client_unfocus for %lx\n", self->window);
 #endif
-        focus_fallback(OB_FOCUS_FALLBACK_UNFOCUSING);
+        focus_fallback(OB_FOCUS_FALLBACK_CLOSED);
     }
 }
 
-void client_activate(ObClient *self, gboolean here)
+void client_activate(ObClient *self, gboolean here, gboolean user)
 {
+    /* XXX do some stuff here if user is false to determine if we really want
+       to activate it or not (a parent or group member is currently active) */
+
     if (client_normal(self) && screen_showing_desktop)
         screen_show_desktop(FALSE);
     if (self->iconic)
@@ -2773,7 +2940,7 @@ void client_raise(ObClient *self)
 
 void client_lower(ObClient *self)
 {
-    action_run_string("Raise", self);
+    action_run_string("Lower", self);
 }
 
 gboolean client_focused(ObClient *self)
@@ -2858,7 +3025,7 @@ ObClient *client_find_directional(ObClient *c, ObDirection dir)
     best_score = -1;
     best_client = NULL;
 
-    for(it = g_list_first(client_list); it; it = it->next) {
+    for(it = g_list_first(client_list); it; it = g_list_next(it)) {
         cur = it->data;
 
         /* the currently selected window isn't interesting */
@@ -2866,12 +3033,15 @@ ObClient *client_find_directional(ObClient *c, ObDirection dir)
             continue;
         if (!client_normal(cur))
             continue;
-        if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+        /* using c->desktop instead of screen_desktop doesn't work if the
+         * current window was omnipresent, hope this doesn't have any other
+         * side effects */
+        if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
             continue;
         if(cur->iconic)
             continue;
-        if(client_focus_target(cur) == cur &&
-           !(cur->can_focus || cur->focus_notify))
+        if(!(client_focus_target(cur) == cur &&
+             client_can_focus(cur)))
             continue;
 
         /* find the centre coords of this window, from the
@@ -2956,10 +3126,20 @@ void client_set_undecorated(ObClient *self, gboolean undecorated)
     if (self->undecorated != undecorated) {
         self->undecorated = undecorated;
         client_setup_decor_and_functions(self);
+        /* Make sure the client knows it might have moved. Maybe there is a
+         * better way of doing this so only one client_configure is sent, but
+         * since 125 of these are sent per second when moving the window (with
+         * user = FALSE) i doubt it matters much.
+         */
+        client_configure(self, OB_CORNER_TOPLEFT, self->area.x, self->area.y,
+                         self->area.width, self->area.height, TRUE, TRUE);
         client_change_state(self); /* reflect this in the state hints */
     }
 }
 
+/* Determines which physical monitor a client is on by calculating the
+   area of the part of the client on each monitor.  The number of the
+   monitor containing the greatest area of the client is returned.*/
 guint client_monitor(ObClient *self)
 {
     guint i;
@@ -2995,7 +3175,7 @@ ObClient *client_search_top_transient(ObClient *self)
 
             g_assert(self->group);
 
-            for (it = self->group->members; it; it = it->next) {
+            for (it = self->group->members; it; it = g_slist_next(it)) {
                 ObClient *c = it->data;
 
                 /* checking transient_for prevents infinate loops! */
@@ -3019,7 +3199,7 @@ ObClient *client_search_focus_parent(ObClient *self)
         } else {
             GSList *it;
 
-            for (it = self->group->members; it; it = it->next) {
+            for (it = self->group->members; it; it = g_slist_next(it)) {
                 ObClient *c = it->data;
 
                 /* checking transient_for prevents infinate loops! */
@@ -3042,7 +3222,7 @@ ObClient *client_search_parent(ObClient *self, ObClient *search)
         } else {
             GSList *it;
 
-            for (it = self->group->members; it; it = it->next) {
+            for (it = self->group->members; it; it = g_slist_next(it)) {
                 ObClient *c = it->data;
 
                 /* checking transient_for prevents infinate loops! */
@@ -3080,88 +3260,100 @@ void client_update_sm_client_id(ObClient *self)
                   &self->sm_client_id);
 }
 
+#define WANT_EDGE(cur, c) \
+            if(cur == c)                                                      \
+                continue;                                                     \
+            if(!client_normal(cur))                                   \
+                continue;                                                     \
+            if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL) \
+                continue;                                                     \
+            if(cur->iconic)                                                   \
+                continue;                                                     \
+            if(cur->layer < c->layer && !config_resist_layers_below)          \
+                continue;
+
+#define HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) \
+            if ((his_edge_start >= my_edge_start && \
+                 his_edge_start <= my_edge_end) ||  \
+                (my_edge_start >= his_edge_start && \
+                 my_edge_start <= his_edge_end))    \
+                dest = his_offset;
+
 /* finds the nearest edge in the given direction from the current client
  * note to self: the edge is the -frame- edge (the actual one), not the
  * client edge.
  */
-gint client_directional_edge_search(ObClient *c, ObDirection dir)
+gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang)
 {
-    gint dest;
+    gint dest, monitor_dest;
     gint my_edge_start, my_edge_end, my_offset;
     GList *it;
-    Rect *a;
+    Rect *a, *monitor;
     
     if(!client_list)
         return -1;
 
     a = screen_area(c->desktop);
+    monitor = screen_area_monitor(c->desktop, client_monitor(c));
 
     switch(dir) {
     case OB_DIRECTION_NORTH:
         my_edge_start = c->frame->area.x;
         my_edge_end = c->frame->area.x + c->frame->area.width;
-        my_offset = c->frame->area.y;
+        my_offset = c->frame->area.y + (hang ? c->frame->area.height : 0);
         
         /* default: top of screen */
-        dest = a->y;
-
-        for(it = g_list_first(client_list); it; it = it->next) {
+        dest = a->y + (hang ? c->frame->area.height : 0);
+        monitor_dest = monitor->y + (hang ? c->frame->area.height : 0);
+        /* if the monitor edge comes before the screen edge, */
+        /* use that as the destination instead. (For xinerama) */
+        if (monitor_dest != dest && my_offset > monitor_dest)
+            dest = monitor_dest; 
+
+        for(it = client_list; it && my_offset != dest; it = g_list_next(it)) {
             gint his_edge_start, his_edge_end, his_offset;
             ObClient *cur = it->data;
 
-            if(cur == c)
-                continue;
-            if(!client_normal(cur))
-                continue;
-            if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
-                continue;
-            if(cur->iconic)
-                continue;
+            WANT_EDGE(cur, c)
 
             his_edge_start = cur->frame->area.x;
             his_edge_end = cur->frame->area.x + cur->frame->area.width;
-            his_offset = cur->frame->area.y + cur->frame->area.height;
+            his_offset = cur->frame->area.y + 
+                         (hang ? 0 : cur->frame->area.height);
 
             if(his_offset + 1 > my_offset)
                 continue;
 
             if(his_offset < dest)
                 continue;
-            
-            if(his_edge_start >= my_edge_start &&
-               his_edge_start <= my_edge_end)
-                dest = his_offset;
-
-            if(my_edge_start >= his_edge_start &&
-               my_edge_start <= his_edge_end)
-                dest = his_offset;
 
+            HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end)
         }
         break;
     case OB_DIRECTION_SOUTH:
         my_edge_start = c->frame->area.x;
         my_edge_end = c->frame->area.x + c->frame->area.width;
-        my_offset = c->frame->area.y + c->frame->area.height;
+        my_offset = c->frame->area.y + (hang ? 0 : c->frame->area.height);
 
         /* default: bottom of screen */
-        dest = a->y + a->height;
-
-        for(it = g_list_first(client_list); it; it = it->next) {
+        dest = a->y + a->height - (hang ? c->frame->area.height : 0);
+        monitor_dest = monitor->y + monitor->height -
+                       (hang ? c->frame->area.height : 0);
+        /* if the monitor edge comes before the screen edge, */
+        /* use that as the destination instead. (For xinerama) */
+        if (monitor_dest != dest && my_offset < monitor_dest)
+            dest = monitor_dest; 
+
+        for(it = client_list; it && my_offset != dest; it = g_list_next(it)) {
             gint his_edge_start, his_edge_end, his_offset;
             ObClient *cur = it->data;
 
-            if(cur == c)
-                continue;
-            if(!client_normal(cur))
-                continue;
-            if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
-                continue;
-            if(cur->iconic)
-                continue;
+            WANT_EDGE(cur, c)
 
             his_edge_start = cur->frame->area.x;
             his_edge_end = cur->frame->area.x + cur->frame->area.width;
-            his_offset = cur->frame->area.y;
+            his_offset = cur->frame->area.y +
+                         (hang ? cur->frame->area.height : 0);
 
 
             if(his_offset - 1 < my_offset)
@@ -3169,98 +3361,75 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
             
             if(his_offset > dest)
                 continue;
-            
-            if(his_edge_start >= my_edge_start &&
-               his_edge_start <= my_edge_end)
-                dest = his_offset;
-
-            if(my_edge_start >= his_edge_start &&
-               my_edge_start <= his_edge_end)
-                dest = his_offset;
 
+            HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end)
         }
         break;
     case OB_DIRECTION_WEST:
         my_edge_start = c->frame->area.y;
         my_edge_end = c->frame->area.y + c->frame->area.height;
-        my_offset = c->frame->area.x;
+        my_offset = c->frame->area.x + (hang ? c->frame->area.width : 0);
 
         /* default: leftmost egde of screen */
-        dest = a->x;
-
-        for(it = g_list_first(client_list); it; it = it->next) {
+        dest = a->x + (hang ? c->frame->area.width : 0);
+        monitor_dest = monitor->x + (hang ? c->frame->area.width : 0);
+        /* if the monitor edge comes before the screen edge, */
+        /* use that as the destination instead. (For xinerama) */
+        if (monitor_dest != dest && my_offset > monitor_dest)
+            dest = monitor_dest;            
+
+        for(it = client_list; it && my_offset != dest; it = g_list_next(it)) {
             gint his_edge_start, his_edge_end, his_offset;
             ObClient *cur = it->data;
 
-            if(cur == c)
-                continue;
-            if(!client_normal(cur))
-                continue;
-            if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
-                continue;
-            if(cur->iconic)
-                continue;
+            WANT_EDGE(cur, c)
 
             his_edge_start = cur->frame->area.y;
             his_edge_end = cur->frame->area.y + cur->frame->area.height;
-            his_offset = cur->frame->area.x + cur->frame->area.width;
+            his_offset = cur->frame->area.x +
+                         (hang ? 0 : cur->frame->area.width);
 
             if(his_offset + 1 > my_offset)
                 continue;
-            
+
             if(his_offset < dest)
                 continue;
-            
-            if(his_edge_start >= my_edge_start &&
-               his_edge_start <= my_edge_end)
-                dest = his_offset;
-
-            if(my_edge_start >= his_edge_start &&
-               my_edge_start <= his_edge_end)
-                dest = his_offset;
-                
 
+            HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end)
         }
-        break;
+       break;
     case OB_DIRECTION_EAST:
         my_edge_start = c->frame->area.y;
         my_edge_end = c->frame->area.y + c->frame->area.height;
-        my_offset = c->frame->area.x + c->frame->area.width;
+        my_offset = c->frame->area.x + (hang ? 0 : c->frame->area.width);
         
         /* default: rightmost edge of screen */
-        dest = a->x + a->width;
-
-        for(it = g_list_first(client_list); it; it = it->next) {
+        dest = a->x + a->width - (hang ? c->frame->area.width : 0);
+        monitor_dest = monitor->x + monitor->width -
+                       (hang ? c->frame->area.width : 0);
+        /* if the monitor edge comes before the screen edge, */
+        /* use that as the destination instead. (For xinerama) */
+        if (monitor_dest != dest && my_offset < monitor_dest)
+            dest = monitor_dest;            
+
+        for(it = client_list; it && my_offset != dest; it = g_list_next(it)) {
             gint his_edge_start, his_edge_end, his_offset;
             ObClient *cur = it->data;
 
-            if(cur == c)
-                continue;
-            if(!client_normal(cur))
-                continue;
-            if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
-                continue;
-            if(cur->iconic)
-                continue;
+            WANT_EDGE(cur, c)
 
             his_edge_start = cur->frame->area.y;
             his_edge_end = cur->frame->area.y + cur->frame->area.height;
-            his_offset = cur->frame->area.x;
+            his_offset = cur->frame->area.x +
+                         (hang ? cur->frame->area.width : 0);
 
             if(his_offset - 1 < my_offset)
                 continue;
             
             if(his_offset > dest)
                 continue;
-            
-            if(his_edge_start >= my_edge_start &&
-               his_edge_start <= my_edge_end)
-                dest = his_offset;
-
-            if(my_edge_start >= his_edge_start &&
-               my_edge_start <= his_edge_end)
-                dest = his_offset;
 
+            HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end)
         }
         break;
     case OB_DIRECTION_NORTHEAST:
@@ -3270,6 +3439,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
         /* not implemented */
     default:
         g_assert_not_reached();
+        dest = 0; /* suppress warning */
     }
     return dest;
 }
@@ -3281,7 +3451,7 @@ ObClient* client_under_pointer()
     ObClient *ret = NULL;
 
     if (screen_pointer_pos(&x, &y)) {
-        for (it = stacking_list; it != NULL; it = it->next) {
+        for (it = stacking_list; it; it = g_list_next(it)) {
             if (WINDOW_IS_CLIENT(it->data)) {
                 ObClient *c = WINDOW_AS_CLIENT(it->data);
                 if (c->frame->visible &&
This page took 0.058286 seconds and 4 git commands to generate.