]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
set the defaults for typed windows in client_get_all:
[chaz/openbox] / openbox / client.c
index 725416bb922d4a59e14e576f2b4a49375d245199..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 */
@@ -401,6 +429,25 @@ void client_unmanage(ObClient *self)
        influence */
     screen_update_areas();
 
+    for (it = client_destructors; it; it = g_slist_next(it)) {
+        Destructor *d = it->data;
+        d->func(self, d->data);
+    }
+        
+    if (focus_client == self) {
+        XEvent e;
+
+        /* focus the last focused window on the desktop, and ignore enter
+           events from the unmap so it doesnt mess with the focus */
+        while (XCheckTypedEvent(ob_display, EnterNotify, &e));
+        /* remove these flags so we don't end up getting focused in the
+           fallback! */
+        self->can_focus = FALSE;
+        self->focus_notify = FALSE;
+        self->modal = FALSE;
+        client_unfocus(self);
+    }
+
     /* tell our parent(s) that we're gone */
     if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */
         GSList *it;
@@ -410,8 +457,8 @@ void client_unmanage(ObClient *self)
                 ((ObClient*)it->data)->transients =
                     g_slist_remove(((ObClient*)it->data)->transients, self);
     } else if (self->transient_for) {        /* transient of window */
-       self->transient_for->transients =
-           g_slist_remove(self->transient_for->transients, self);
+        self->transient_for->transients =
+            g_slist_remove(self->transient_for->transients, self);
     }
 
     /* tell our transients that we're gone */
@@ -422,20 +469,6 @@ void client_unmanage(ObClient *self)
         }
     }
 
-    for (it = client_destructors; it; it = g_slist_next(it)) {
-        GDestroyNotify func = (GDestroyNotify) it->data;
-        func(self);
-    }
-        
-    if (focus_client == self) {
-        XEvent e;
-
-        /* focus the last focused window on the desktop, and ignore enter
-           events from the unmap so it doesnt mess with the focus */
-        while (XCheckTypedEvent(ob_display, EnterNotify, &e));
-        client_unfocus(self);
-    }
-
     /* remove from its group */
     if (self->group) {
         group_remove(self->group, self);
@@ -468,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);
@@ -503,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 :
@@ -681,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 */
@@ -824,7 +870,7 @@ void client_update_transient_for(ObClient *self)
     ObClient *target = NULL;
 
     if (XGetTransientForHint(ob_display, self->window, &t)) {
-       self->transient = TRUE;
+        self->transient = TRUE;
         if (t != self->window) { /* cant be transient to itself! */
             target = g_hash_table_lookup(window_map, &t);
             /* if this happens then we need to check for it*/
@@ -840,14 +886,15 @@ void client_update_transient_for(ObClient *self)
                    group */
                 if (t == self->group->leader ||
                     t == None ||
-                    t == RootWindow(ob_display, ob_screen)) {
+                    t == RootWindow(ob_display, ob_screen))
+                {
                     /* window is a transient for its group! */
                     target = OB_TRAN_GROUP;
                 }
             }
         }
     } else
-       self->transient = FALSE;
+        self->transient = FALSE;
 
     /* if anything has changed... */
     if (target != self->transient_for) {
@@ -921,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) {
@@ -1061,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))
@@ -1155,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);
@@ -1176,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;
-        }
     }
 }
 
@@ -1196,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);
@@ -1217,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;
     }
 }
 
@@ -1278,6 +1316,18 @@ void client_update_wmhints(ObClient *self)
                 for (it = self->group->members; it; it = it->next)
                     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) {
+                        ObClient *c = it->data;
+
+                        if (c != self && !c->transient_for)
+                            c->transients = g_slist_remove(c->transients,
+                                                           self);
+                    }
+                }
+
                 group_remove(self->group, self);
                 self->group = NULL;
             }
@@ -1333,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)))
@@ -1369,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);
 
@@ -1480,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;
@@ -1520,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) {
@@ -1565,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)
@@ -1670,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;
@@ -1721,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;
@@ -1739,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)
@@ -1927,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;
@@ -2163,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;
 
@@ -2238,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
@@ -2289,7 +2364,7 @@ void client_set_desktop_recursive(ObClient *self,
             client_showhide(self);
         /* raise if it was not already on the desktop */
         if (old != DESKTOP_ALL)
-            stacking_raise(CLIENT_AS_WINDOW(self));
+            client_raise(self);
         screen_update_areas();
 
         /* add to the new desktop(s) */
@@ -2492,7 +2567,7 @@ ObClient *client_focus_target(ObClient *self)
     ObClient *child;
      
     /* if we have a modal child, then focus it, not us */
-    child = client_search_modal_child(self);
+    child = client_search_modal_child(client_search_top_transient(self));
     if (child) return child;
     return self;
 }
@@ -2507,28 +2582,25 @@ 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))
-       return FALSE;
+    if (!(self->can_focus || self->focus_notify))
+        return FALSE;
 
     /* do a check to see if the window has already been unmapped or destroyed
        do this intelligently while watching out for unmaps we've generated
        (ignore_unmaps > 0) */
     if (XCheckTypedWindowEvent(ob_display, self->window,
-                              DestroyNotify, &ev)) {
-       XPutBackEvent(ob_display, &ev);
-       return FALSE;
+                               DestroyNotify, &ev)) {
+        XPutBackEvent(ob_display, &ev);
+        return FALSE;
     }
     while (XCheckTypedWindowEvent(ob_display, self->window,
-                                 UnmapNotify, &ev)) {
-       if (self->ignore_unmaps) {
-           self->ignore_unmaps--;
-       } else {
-           XPutBackEvent(ob_display, &ev);
-           return FALSE;
-       }
+                                  UnmapNotify, &ev)) {
+        if (self->ignore_unmaps) {
+            self->ignore_unmaps--;
+        } else {
+            XPutBackEvent(ob_display, &ev);
+            return FALSE;
+        }
     }
 
     return TRUE;
@@ -2602,7 +2674,7 @@ void client_activate(ObClient *self, gboolean here)
     if (client_normal(self) && screen_showing_desktop)
         screen_show_desktop(FALSE);
     if (self->iconic)
-        client_iconify(self, FALSE, FALSE);
+        client_iconify(self, FALSE, here);
     if (self->desktop != DESKTOP_ALL &&
         self->desktop != screen_desktop) {
         if (here)
@@ -2615,7 +2687,24 @@ void client_activate(ObClient *self, gboolean here)
         return;
     if (self->shaded)
         client_shade(self, FALSE);
-    action_run_string("Focus", self);
+
+    client_focus(self);
+
+    /* we do this an action here. this is rather important. this is because
+       we want the results from the focus change to take place BEFORE we go
+       about raising the window. when a fullscreen window loses focus, we need
+       this or else the raise wont be able to raise above the to-lose-focus
+       fullscreen window. */
+    client_raise(self);
+}
+
+void client_raise(ObClient *self)
+{
+    action_run_string("Raise", self);
+}
+
+void client_lower(ObClient *self)
+{
     action_run_string("Raise", self);
 }
 
@@ -2624,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)) {
@@ -2647,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) 
 {
@@ -2792,6 +2915,8 @@ ObClient *client_search_top_transient(ObClient *self)
         } else {
             GSList *it;
 
+            g_assert(self->group);
+
             for (it = self->group->members; it; it = it->next) {
                 ObClient *c = it->data;
 
@@ -3077,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;
@@ -3087,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.055955 seconds and 4 git commands to generate.