]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
set the defaults for typed windows in client_get_all:
[chaz/openbox] / openbox / client.c
index bc3c6f0d76bb17bca9646245b7035e333230e95d..5677f62779f729eee35c505064ac94fc56f1dfa0 100644 (file)
 #define CLIENT_NOPROPAGATEMASK (ButtonPressMask | ButtonReleaseMask | \
                                ButtonMotionMask)
 
+typedef struct
+{
+    ObClientDestructor func;
+    gpointer data;
+} Destructor;
+
 GList      *client_list        = NULL;
 GSList     *client_destructors = NULL;
 
@@ -81,14 +87,26 @@ void client_shutdown(gboolean reconfig)
 {
 }
 
-void client_add_destructor(GDestroyNotify func)
+void client_add_destructor(ObClientDestructor func, gpointer data)
 {
-    client_destructors = g_slist_prepend(client_destructors, (gpointer)func);
+    Destructor *d = g_new(Destructor, 1);
+    d->func = func;
+    d->data = data;
+    client_destructors = g_slist_prepend(client_destructors, d);
 }
 
-void client_remove_destructor(GDestroyNotify func)
+void client_remove_destructor(ObClientDestructor func)
 {
-    client_destructors = g_slist_remove(client_destructors, (gpointer)func);
+    GSList *it;
+
+    for (it = client_destructors; it; it = g_slist_next(it)) {
+        Destructor *d = it->data;
+        if (d->func == func) {
+            g_free(d);
+            client_destructors = g_slist_delete_link(client_destructors, it);
+            break;
+        }
+    }
 }
 
 void client_set_list()
@@ -341,7 +359,17 @@ void client_manage(Window window)
        a window maps since its not based on an action from the user like
        clicking a window to activate is. so keep the new window out of the way
        but do focus it. */
-    if (activate) client_focus(self);
+    if (activate) {
+        /* if using focus_delay, stop the timer now so that focus doesn't go
+           moving on us */
+        event_halt_focus_delay();
+
+        client_focus(self);
+        /* since focus can change the stacking orders, if we focus the window
+           then the standard raise it gets is not enough, we need to queue one
+           for after the focus change takes place */
+        client_raise(self);
+    }
 
     /* client_activate does this but we aret using it so we have to do it
        here as well */
@@ -402,8 +430,8 @@ void client_unmanage(ObClient *self)
     screen_update_areas();
 
     for (it = client_destructors; it; it = g_slist_next(it)) {
-        GDestroyNotify func = (GDestroyNotify) it->data;
-        func(self);
+        Destructor *d = it->data;
+        d->func(self, d->data);
     }
         
     if (focus_client == self) {
@@ -473,9 +501,9 @@ void client_unmanage(ObClient *self)
     /* free all data allocated in the client struct */
     g_slist_free(self->transients);
     for (j = 0; j < self->nicons; ++j)
-       g_free(self->icons[j].data);
+        g_free(self->icons[j].data);
     if (self->nicons > 0)
-       g_free(self->icons);
+        g_free(self->icons);
     g_free(self->title);
     g_free(self->icon_title);
     g_free(self->name);
@@ -508,8 +536,9 @@ static void client_restore_session_state(ObClient *self)
     RECT_SET(self->area, self->session->x, self->session->y,
              self->session->w, self->session->h);
     self->positioned = TRUE;
-    XResizeWindow(ob_display, self->window,
-                  self->session->w, self->session->h);
+    if (self->session->w > 0 && self->session->h > 0)
+        XResizeWindow(ob_display, self->window,
+                      self->session->w, self->session->h);
 
     self->desktop = (self->session->desktop == DESKTOP_ALL ?
                      self->session->desktop :
@@ -686,6 +715,18 @@ static void client_get_all(ObClient *self)
     client_get_mwm_hints(self);
     client_get_type(self);/* this can change the mwmhints for special cases */
 
+    {
+        /* a couple type-based defaults for new windows */
+
+        /* 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);
 
     client_get_gravity(self); /* get the attribute gravity */
@@ -927,36 +968,36 @@ void client_get_type(ObClient *self)
     self->type = -1;
   
     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 (val[i] == prop_atoms.net_wm_window_type_desktop)
-               self->type = OB_CLIENT_TYPE_DESKTOP;
-           else if (val[i] == prop_atoms.net_wm_window_type_dock)
-               self->type = OB_CLIENT_TYPE_DOCK;
-           else if (val[i] == prop_atoms.net_wm_window_type_toolbar)
-               self->type = OB_CLIENT_TYPE_TOOLBAR;
-           else if (val[i] == prop_atoms.net_wm_window_type_menu)
-               self->type = OB_CLIENT_TYPE_MENU;
-           else if (val[i] == prop_atoms.net_wm_window_type_utility)
-               self->type = OB_CLIENT_TYPE_UTILITY;
-           else if (val[i] == prop_atoms.net_wm_window_type_splash)
-               self->type = OB_CLIENT_TYPE_SPLASH;
-           else if (val[i] == prop_atoms.net_wm_window_type_dialog)
-               self->type = OB_CLIENT_TYPE_DIALOG;
-           else if (val[i] == prop_atoms.net_wm_window_type_normal)
-               self->type = OB_CLIENT_TYPE_NORMAL;
-           else if (val[i] == prop_atoms.kde_net_wm_window_type_override) {
-               /* prevent this window from getting any decor or
-                  functionality */
-               self->mwmhints.flags &= (OB_MWM_FLAG_FUNCTIONS |
-                                        OB_MWM_FLAG_DECORATIONS);
-               self->mwmhints.decorations = 0;
-               self->mwmhints.functions = 0;
-           }
-           if (self->type != (ObClientType) -1)
-               break; /* grab the first legit type */
-       }
-       g_free(val);
+        /* use the first value that we know about in the array */
+        for (i = 0; i < num; ++i) {
+            if (val[i] == prop_atoms.net_wm_window_type_desktop)
+                self->type = OB_CLIENT_TYPE_DESKTOP;
+            else if (val[i] == prop_atoms.net_wm_window_type_dock)
+                self->type = OB_CLIENT_TYPE_DOCK;
+            else if (val[i] == prop_atoms.net_wm_window_type_toolbar)
+                self->type = OB_CLIENT_TYPE_TOOLBAR;
+            else if (val[i] == prop_atoms.net_wm_window_type_menu)
+                self->type = OB_CLIENT_TYPE_MENU;
+            else if (val[i] == prop_atoms.net_wm_window_type_utility)
+                self->type = OB_CLIENT_TYPE_UTILITY;
+            else if (val[i] == prop_atoms.net_wm_window_type_splash)
+                self->type = OB_CLIENT_TYPE_SPLASH;
+            else if (val[i] == prop_atoms.net_wm_window_type_dialog)
+                self->type = OB_CLIENT_TYPE_DIALOG;
+            else if (val[i] == prop_atoms.net_wm_window_type_normal)
+                self->type = OB_CLIENT_TYPE_NORMAL;
+            else if (val[i] == prop_atoms.kde_net_wm_window_type_override) {
+                /* prevent this window from getting any decor or
+                   functionality */
+                self->mwmhints.flags &= (OB_MWM_FLAG_FUNCTIONS |
+                                         OB_MWM_FLAG_DECORATIONS);
+                self->mwmhints.decorations = 0;
+                self->mwmhints.functions = 0;
+            }
+            if (self->type != (ObClientType) -1)
+                break; /* grab the first legit type */
+        }
+        g_free(val);
     }
     
     if (self->type == (ObClientType) -1) {
@@ -1067,78 +1108,76 @@ void client_setup_decor_and_functions(ObClient *self)
          OB_FRAME_DECOR_ALLDESKTOPS |
          OB_FRAME_DECOR_ICONIFY |
          OB_FRAME_DECOR_MAXIMIZE |
-         OB_FRAME_DECOR_SHADE);
+         OB_FRAME_DECOR_SHADE |
+         OB_FRAME_DECOR_CLOSE);
     self->functions =
         (OB_CLIENT_FUNC_RESIZE |
          OB_CLIENT_FUNC_MOVE |
          OB_CLIENT_FUNC_ICONIFY |
          OB_CLIENT_FUNC_MAXIMIZE |
-         OB_CLIENT_FUNC_SHADE);
-    if (self->delete_window) {
-       self->functions |= OB_CLIENT_FUNC_CLOSE;
-        self->decorations |= OB_FRAME_DECOR_CLOSE;
-    }
+         OB_CLIENT_FUNC_SHADE |
+         OB_CLIENT_FUNC_CLOSE);
 
     if (!(self->min_size.width < self->max_size.width ||
-         self->min_size.height < self->max_size.height))
-       self->functions &= ~OB_CLIENT_FUNC_RESIZE;
+          self->min_size.height < self->max_size.height))
+        self->functions &= ~OB_CLIENT_FUNC_RESIZE;
 
     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 */
-       self->functions |= OB_CLIENT_FUNC_FULLSCREEN;
-       break;
+        /* normal windows retain all of the possible decorations and
+           functionality, and are the only windows that you can fullscreen */
+        self->functions |= OB_CLIENT_FUNC_FULLSCREEN;
+        break;
 
     case OB_CLIENT_TYPE_DIALOG:
     case OB_CLIENT_TYPE_UTILITY:
-       /* these windows cannot be maximized */
-       self->functions &= ~OB_CLIENT_FUNC_MAXIMIZE;
-       break;
+        /* these windows cannot be maximized */
+        self->functions &= ~OB_CLIENT_FUNC_MAXIMIZE;
+        break;
 
     case OB_CLIENT_TYPE_MENU:
     case OB_CLIENT_TYPE_TOOLBAR:
-       /* these windows get less functionality */
-       self->functions &= ~(OB_CLIENT_FUNC_ICONIFY | OB_CLIENT_FUNC_RESIZE);
-       break;
+        /* these windows get less functionality */
+        self->functions &= ~(OB_CLIENT_FUNC_ICONIFY | OB_CLIENT_FUNC_RESIZE);
+        break;
 
     case OB_CLIENT_TYPE_DESKTOP:
     case OB_CLIENT_TYPE_DOCK:
     case OB_CLIENT_TYPE_SPLASH:
-       /* none of these windows are manipulated by the window manager */
-       self->decorations = 0;
-       self->functions = 0;
-       break;
+        /* none of these windows are manipulated by the window manager */
+        self->decorations = 0;
+        self->functions = 0;
+        break;
     }
 
     /* Mwm Hints are applied subtractively to what has already been chosen for
        decor and functionality */
     if (self->mwmhints.flags & OB_MWM_FLAG_DECORATIONS) {
-       if (! (self->mwmhints.decorations & OB_MWM_DECOR_ALL)) {
-           if (! ((self->mwmhints.decorations & OB_MWM_DECOR_HANDLE) ||
+        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;
-       }
+                self->decorations = 0;
+        }
     }
 
     if (self->mwmhints.flags & OB_MWM_FLAG_FUNCTIONS) {
-       if (! (self->mwmhints.functions & OB_MWM_FUNC_ALL)) {
-           if (! (self->mwmhints.functions & OB_MWM_FUNC_RESIZE))
-               self->functions &= ~OB_CLIENT_FUNC_RESIZE;
-           if (! (self->mwmhints.functions & OB_MWM_FUNC_MOVE))
-               self->functions &= ~OB_CLIENT_FUNC_MOVE;
+        if (! (self->mwmhints.functions & OB_MWM_FUNC_ALL)) {
+            if (! (self->mwmhints.functions & OB_MWM_FUNC_RESIZE))
+                self->functions &= ~OB_CLIENT_FUNC_RESIZE;
+            if (! (self->mwmhints.functions & OB_MWM_FUNC_MOVE))
+                self->functions &= ~OB_CLIENT_FUNC_MOVE;
             /* dont let mwm hints kill any buttons
-           if (! (self->mwmhints.functions & OB_MWM_FUNC_ICONIFY))
-               self->functions &= ~OB_CLIENT_FUNC_ICONIFY;
-           if (! (self->mwmhints.functions & OB_MWM_FUNC_MAXIMIZE))
-               self->functions &= ~OB_CLIENT_FUNC_MAXIMIZE;
+               if (! (self->mwmhints.functions & OB_MWM_FUNC_ICONIFY))
+               self->functions &= ~OB_CLIENT_FUNC_ICONIFY;
+               if (! (self->mwmhints.functions & OB_MWM_FUNC_MAXIMIZE))
+               self->functions &= ~OB_CLIENT_FUNC_MAXIMIZE;
             */
-           /* dont let mwm hints kill the close button
-              if (! (self->mwmhints.functions & MwmFunc_Close))
-              self->functions &= ~OB_CLIENT_FUNC_CLOSE; */
-       }
+            /* 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))
@@ -1161,20 +1200,20 @@ void client_setup_decor_and_functions(ObClient *self)
         self->decorations &= ~OB_FRAME_DECOR_HANDLE;
 
     /* finally, the user can have requested no decorations, which overrides
-       everything */
+       everything (but doesnt give it a border if it doesnt have one) */
     if (self->undecorated)
-        self->decorations = OB_FRAME_DECOR_BORDER;
+        self->decorations &= OB_FRAME_DECOR_BORDER;
 
     /* if we don't have a titlebar, then we cannot shade! */
     if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
-       self->functions &= ~OB_CLIENT_FUNC_SHADE;
+        self->functions &= ~OB_CLIENT_FUNC_SHADE;
 
     /* now we need to check against rules for the client's current state */
     if (self->fullscreen) {
-       self->functions &= (OB_CLIENT_FUNC_CLOSE |
+        self->functions &= (OB_CLIENT_FUNC_CLOSE |
                             OB_CLIENT_FUNC_FULLSCREEN |
                             OB_CLIENT_FUNC_ICONIFY);
-       self->decorations = 0;
+        self->decorations = 0;
     }
 
     client_change_allowed_actions(self);
@@ -1182,13 +1221,6 @@ void client_setup_decor_and_functions(ObClient *self)
     if (self->frame) {
         /* adjust the client's decorations, etc. */
         client_reconfigure(self);
-    } else {
-        /* this makes sure that these windows appear on all desktops */
-        if (self->type == OB_CLIENT_TYPE_DESKTOP &&
-            self->desktop != DESKTOP_ALL)
-        {
-            self->desktop = DESKTOP_ALL;
-        }
     }
 }
 
@@ -1202,20 +1234,20 @@ static void client_change_allowed_actions(ObClient *self)
         actions[num++] = prop_atoms.net_wm_action_change_desktop;
 
     if (self->functions & OB_CLIENT_FUNC_SHADE)
-       actions[num++] = prop_atoms.net_wm_action_shade;
+        actions[num++] = prop_atoms.net_wm_action_shade;
     if (self->functions & OB_CLIENT_FUNC_CLOSE)
-       actions[num++] = prop_atoms.net_wm_action_close;
+        actions[num++] = prop_atoms.net_wm_action_close;
     if (self->functions & OB_CLIENT_FUNC_MOVE)
-       actions[num++] = prop_atoms.net_wm_action_move;
+        actions[num++] = prop_atoms.net_wm_action_move;
     if (self->functions & OB_CLIENT_FUNC_ICONIFY)
-       actions[num++] = prop_atoms.net_wm_action_minimize;
+        actions[num++] = prop_atoms.net_wm_action_minimize;
     if (self->functions & OB_CLIENT_FUNC_RESIZE)
-       actions[num++] = prop_atoms.net_wm_action_resize;
+        actions[num++] = prop_atoms.net_wm_action_resize;
     if (self->functions & OB_CLIENT_FUNC_FULLSCREEN)
-       actions[num++] = prop_atoms.net_wm_action_fullscreen;
+        actions[num++] = prop_atoms.net_wm_action_fullscreen;
     if (self->functions & OB_CLIENT_FUNC_MAXIMIZE) {
-       actions[num++] = prop_atoms.net_wm_action_maximize_horz;
-       actions[num++] = prop_atoms.net_wm_action_maximize_vert;
+        actions[num++] = prop_atoms.net_wm_action_maximize_horz;
+        actions[num++] = prop_atoms.net_wm_action_maximize_vert;
     }
 
     PROP_SETA32(self->window, net_wm_allowed_actions, atom, actions, num);
@@ -1223,21 +1255,21 @@ static void client_change_allowed_actions(ObClient *self)
     /* make sure the window isn't breaking any rules now */
 
     if (!(self->functions & OB_CLIENT_FUNC_SHADE) && self->shaded) {
-       if (self->frame) client_shade(self, FALSE);
-       else self->shaded = FALSE;
+        if (self->frame) client_shade(self, FALSE);
+        else self->shaded = FALSE;
     }
     if (!(self->functions & OB_CLIENT_FUNC_ICONIFY) && self->iconic) {
-       if (self->frame) client_iconify(self, FALSE, TRUE);
-       else self->iconic = FALSE;
+        if (self->frame) client_iconify(self, FALSE, TRUE);
+        else self->iconic = FALSE;
     }
     if (!(self->functions & OB_CLIENT_FUNC_FULLSCREEN) && self->fullscreen) {
-       if (self->frame) client_fullscreen(self, FALSE, TRUE);
-       else self->fullscreen = FALSE;
+        if (self->frame) client_fullscreen(self, FALSE, TRUE);
+        else self->fullscreen = FALSE;
     }
     if (!(self->functions & OB_CLIENT_FUNC_MAXIMIZE) && (self->max_horz ||
                                                          self->max_vert)) {
-       if (self->frame) client_maximize(self, FALSE, 0, TRUE);
-       else self->max_vert = self->max_horz = FALSE;
+        if (self->frame) client_maximize(self, FALSE, 0, TRUE);
+        else self->max_vert = self->max_horz = FALSE;
     }
 }
 
@@ -1351,9 +1383,9 @@ void client_update_title(ObClient *self)
      
     /* 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))
-           data = g_strdup("Unnamed Window");
+        /* try old x stuff */
+        if (!PROP_GETS(self->window, wm_name, locale, &data))
+            data = g_strdup("Unnamed Window");
 
     /* did the title change? then reset the title_count */
     if (old_title && 0 != strncmp(old_title, data, strlen(data)))
@@ -1387,7 +1419,7 @@ void client_update_title(ObClient *self)
     self->title = data;
 
     if (self->frame)
-       frame_adjust_title(self->frame);
+        frame_adjust_title(self->frame);
 
     g_free(old_title);
 
@@ -1498,35 +1530,35 @@ void client_update_icons(ObClient *self)
     guint w, h, i, j;
 
     for (i = 0; i < self->nicons; ++i)
-       g_free(self->icons[i].data);
+        g_free(self->icons[i].data);
     if (self->nicons > 0)
-       g_free(self->icons);
+        g_free(self->icons);
     self->nicons = 0;
 
     if (PROP_GETA32(self->window, net_wm_icon, cardinal, &data, &num)) {
-       /* figure out how many valid icons are in here */
-       i = 0;
-       while (num - i > 2) {
-           w = data[i++];
-           h = data[i++];
-           i += w * h;
-           if (i > num || w*h == 0) break;
-           ++self->nicons;
-       }
+        /* figure out how many valid icons are in here */
+        i = 0;
+        while (num - i > 2) {
+            w = data[i++];
+            h = data[i++];
+            i += w * h;
+            if (i > num || w*h == 0) break;
+            ++self->nicons;
+        }
 
-       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) {
             guint x, y, t;
 
-           w = self->icons[j].width = data[i++];
-           h = self->icons[j].height = data[i++];
+            w = self->icons[j].width = data[i++];
+            h = self->icons[j].height = data[i++];
 
             if (w*h == 0) continue;
 
-           self->icons[j].data = g_new(RrPixel32, w * h);
+            self->icons[j].data = g_new(RrPixel32, w * h);
             for (x = 0, y = 0, t = 0; t < w * h; ++t, ++x, ++i) {
                 if (x >= w) {
                     x = 0;
@@ -1538,10 +1570,10 @@ void client_update_icons(ObClient *self)
                     (((data[i] >> 8) & 0xff) << RrDefaultGreenOffset) +
                     (((data[i] >> 0) & 0xff) << RrDefaultBlueOffset);
             }
-           g_assert(i <= num);
-       }
+            g_assert(i <= num);
+        }
 
-       g_free(data);
+        g_free(data);
     } else if (PROP_GETA32(self->window, kwm_win_icon,
                            kwm_win_icon, &data, &num)) {
         if (num == 2) {
@@ -1583,18 +1615,8 @@ void client_update_icons(ObClient *self)
         }
     }
 
-    if (!self->nicons) {
-        self->nicons++;
-        self->icons = g_new(ObClientIcon, self->nicons);
-        self->icons[self->nicons-1].width = 48;
-        self->icons[self->nicons-1].height = 48;
-        self->icons[self->nicons-1].data = g_memdup(ob_rr_theme->def_win_icon,
-                                                    sizeof(RrPixel32)
-                                                    * 48 * 48);
-    }
-
     if (self->frame)
-       frame_adjust_icon(self->frame);
+        frame_adjust_icon(self->frame);
 }
 
 static void client_change_state(ObClient *self)
@@ -1688,7 +1710,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->below) l = OB_STACKING_LAYER_TOP;
+        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;
     }
     else if (self->above) l = OB_STACKING_LAYER_ABOVE;
@@ -1739,7 +1762,7 @@ gboolean client_should_show(ObClient *self)
 {
     if (self->iconic) return FALSE;
     else if (!(self->desktop == screen_desktop ||
-              self->desktop == DESKTOP_ALL)) return FALSE;
+               self->desktop == DESKTOP_ALL)) return FALSE;
     else if (client_normal(self) && screen_showing_desktop) return FALSE;
     
     return TRUE;
@@ -1757,7 +1780,7 @@ static void client_showhide(ObClient *self)
 gboolean client_normal(ObClient *self) {
     return ! (self->type == OB_CLIENT_TYPE_DESKTOP ||
               self->type == OB_CLIENT_TYPE_DOCK ||
-             self->type == OB_CLIENT_TYPE_SPLASH);
+              self->type == OB_CLIENT_TYPE_SPLASH);
 }
 
 static void client_apply_startup_state(ObClient *self)
@@ -1945,27 +1968,46 @@ void client_configure_full(ObClient *self, ObCorner anchor,
         h -= self->base_size.height;
 
         if (self->min_ratio)
-            if (h * self->min_ratio > w) h = (int)(w / self->min_ratio);
+            if (h * self->min_ratio > w) {
+                h = (int)(w / self->min_ratio);
+
+                /* you cannot resize to nothing */
+                if (h < 1) {
+                    h = 1;
+                    w = (int)(h * self->min_ratio);
+                }
+            }
         if (self->max_ratio)
-            if (h * self->max_ratio < w) h = (int)(w / self->max_ratio);
+            if (h * self->max_ratio < w) {
+                h = (int)(w / self->max_ratio);
+
+                /* you cannot resize to nothing */
+                if (h < 1) {
+                    h = 1;
+                    w = (int)(h * self->min_ratio);
+                }
+            }
 
         w += self->base_size.width;
         h += self->base_size.height;
     }
 
+    g_assert(w > 0);
+    g_assert(h > 0);
+
     switch (anchor) {
     case OB_CORNER_TOPLEFT:
-       break;
+        break;
     case OB_CORNER_TOPRIGHT:
-       x -= w - self->area.width;
-       break;
+        x -= w - self->area.width;
+        break;
     case OB_CORNER_BOTTOMLEFT:
-       y -= h - self->area.height;
-       break;
+        y -= h - self->area.height;
+        break;
     case OB_CORNER_BOTTOMRIGHT:
-       x -= w - self->area.width;
-       y -= h - self->area.height;
-       break;
+        x -= w - self->area.width;
+        y -= h - self->area.height;
+        break;
     }
 
     moved = x != self->area.x || y != self->area.y;
@@ -2181,8 +2223,18 @@ void client_maximize(ObClient *self, gboolean max, int dir, gboolean savearea)
     h = self->area.height;
 
     if (max) {
-        if (savearea)
-            self->pre_max_area = self->area;
+        if (savearea) {
+            if ((dir == 0 || dir == 1) && !self->max_horz) { /* horz */
+                RECT_SET(self->pre_max_area,
+                         self->area.x, self->pre_max_area.y,
+                         self->area.width, self->pre_max_area.height);
+            }
+            if ((dir == 0 || dir == 2) && !self->max_vert) { /* vert */
+                RECT_SET(self->pre_max_area,
+                         self->pre_max_area.x, self->area.y,
+                         self->pre_max_area.width, self->area.height);
+            }
+        }
     } else {
         Rect *a;
 
@@ -2256,6 +2308,11 @@ 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)
+        client_kill(self);
+    
     /*
       XXX: itd be cool to do timeouts and shit here for killing the client's
       process off
@@ -2525,10 +2582,7 @@ gboolean client_can_focus(ObClient *self)
     if (!self->frame->visible)
         return FALSE;
 
-    if (!((self->can_focus || self->focus_notify) &&
-          (self->desktop == screen_desktop ||
-           self->desktop == DESKTOP_ALL) &&
-          !self->iconic))
+    if (!(self->can_focus || self->focus_notify))
         return FALSE;
 
     /* do a check to see if the window has already been unmapped or destroyed
@@ -2659,13 +2713,34 @@ gboolean client_focused(ObClient *self)
     return self == focus_client;
 }
 
-ObClientIcon *client_icon(ObClient *self, int w, int h)
+static ObClientIcon* client_icon_recursive(ObClient *self, int w, int h)
 {
     guint i;
     /* si is the smallest image >= req */
     /* li is the largest image < req */
     unsigned long size, smallest = 0xffffffff, largest = 0, si = 0, li = 0;
 
+    if (!self->nicons) {
+        ObClientIcon *parent = NULL;
+
+        if (self->transient_for) {
+            if (self->transient_for != OB_TRAN_GROUP)
+                parent = client_icon_recursive(self->transient_for, w, h);
+            else {
+                GSList *it;
+                for (it = self->group->members; it; it = g_slist_next(it)) {
+                    ObClient *c = it->data;
+                    if (c != self && !c->transient_for) {
+                        if ((parent = client_icon_recursive(c, w, h)))
+                            break;
+                    }
+                }
+            }
+        }
+        
+        return parent;
+    }
+
     for (i = 0; i < self->nicons; ++i) {
         size = self->icons[i].width * self->icons[i].height;
         if (size < smallest && size >= (unsigned)(w * h)) {
@@ -2682,6 +2757,19 @@ ObClientIcon *client_icon(ObClient *self, int w, int h)
     return &self->icons[li];
 }
 
+const ObClientIcon* client_icon(ObClient *self, int w, int h)
+{
+    ObClientIcon *ret;
+    static ObClientIcon deficon;
+
+    if (!(ret = client_icon_recursive(self, w, h))) {
+        deficon.width = deficon.height = 48;
+        deficon.data = ob_rr_theme->def_win_icon;
+        ret = &deficon;
+    }
+    return ret;
+}
+
 /* this be mostly ripped from fvwm */
 ObClient *client_find_directional(ObClient *c, ObDirection dir) 
 {
@@ -3114,7 +3202,7 @@ ObClient* client_under_pointer()
         for (it = stacking_list; it != NULL; it = it->next) {
             if (WINDOW_IS_CLIENT(it->data)) {
                 ObClient *c = WINDOW_AS_CLIENT(it->data);
-                if (c->desktop == screen_desktop &&
+                if (c->frame->visible &&
                     RECT_CONTAINS(c->frame->area, x, y)) {
                     ret = c;
                     break;
@@ -3124,3 +3212,8 @@ ObClient* client_under_pointer()
     }
     return ret;
 }
+
+gboolean client_has_group_siblings(ObClient *self)
+{
+    return self->group && self->group->members->next;
+}
This page took 0.044671 seconds and 4 git commands to generate.