]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
use the right list in client_add_hide_notify, rename destructor to destroy_notify...
[chaz/openbox] / openbox / client.c
index 3f3f161de016c79126136d3eb84491f4d8a09a5a..73696c897518dd98fce6f51df139dc7a16a21bfb 100644 (file)
@@ -64,21 +64,19 @@ typedef struct
 
 GList            *client_list          = NULL;
 
-static GSList *client_destructors      = NULL;
+static GSList *client_destroy_notifies = NULL;
+static GSList *client_hide_notifies    = NULL;
 
-static void client_get_all(ObClient *self);
+static void client_get_all(ObClient *self, gboolean real);
 static void client_toggle_border(ObClient *self, gboolean show);
 static void client_get_startup_id(ObClient *self);
 static void client_get_session_ids(ObClient *self);
 static void client_get_area(ObClient *self);
 static void client_get_desktop(ObClient *self);
 static void client_get_state(ObClient *self);
-static void client_get_layer(ObClient *self);
 static void client_get_shaped(ObClient *self);
 static void client_get_mwm_hints(ObClient *self);
-static void client_get_gravity(ObClient *self);
 static void client_get_colormap(ObClient *self);
-static void client_get_transientness(ObClient *self);
 static void client_change_allowed_actions(ObClient *self);
 static void client_change_state(ObClient *self);
 static void client_change_wm_state(ObClient *self);
@@ -94,6 +92,7 @@ static void client_present(ObClient *self, gboolean here, gboolean raise);
 static GSList *client_search_all_top_parents_internal(ObClient *self,
                                                       gboolean bylayer,
                                                       ObStackingLayer layer);
+static void client_call_notifies(ObClient *self, GSList *list);
 
 void client_startup(gboolean reconfig)
 {
@@ -107,23 +106,57 @@ void client_shutdown(gboolean reconfig)
     if (reconfig) return;
 }
 
-void client_add_destructor(ObClientCallback func, gpointer data)
+static void client_call_notifies(ObClient *self, GSList *list)
+{
+    GSList *it;
+
+    for (it = list; it; it = g_slist_next(it)) {
+        ClientCallback *d = it->data;
+        d->func(self, d->data);
+    }
+}
+
+void client_add_destroy_notify(ObClientCallback func, gpointer data)
+{
+    ClientCallback *d = g_new(ClientCallback, 1);
+    d->func = func;
+    d->data = data;
+    client_destroy_notifies = g_slist_prepend(client_destroy_notifies, d);
+}
+
+void client_remove_destroy_notify(ObClientCallback func)
+{
+    GSList *it;
+
+    for (it = client_destroy_notifies; it; it = g_slist_next(it)) {
+        ClientCallback *d = it->data;
+        if (d->func == func) {
+            g_free(d);
+            client_destroy_notifies =
+                g_slist_delete_link(client_destroy_notifies, it);
+            break;
+        }
+    }
+}
+
+void client_add_hide_notify(ObClientCallback func, gpointer data)
 {
     ClientCallback *d = g_new(ClientCallback, 1);
     d->func = func;
     d->data = data;
-    client_destructors = g_slist_prepend(client_destructors, d);
+    client_hide_notifies = g_slist_prepend(client_hide_notifies, d);
 }
 
-void client_remove_destructor(ObClientCallback func)
+void client_remove_hide_notify(ObClientCallback func)
 {
     GSList *it;
 
-    for (it = client_destructors; it; it = g_slist_next(it)) {
+    for (it = client_hide_notifies; it; it = g_slist_next(it)) {
         ClientCallback *d = it->data;
         if (d->func == func) {
             g_free(d);
-            client_destructors = g_slist_delete_link(client_destructors, it);
+            client_hide_notifies =
+                g_slist_delete_link(client_hide_notifies, it);
             break;
         }
     }
@@ -236,8 +269,8 @@ void client_manage(Window window)
 
     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 */
+    /* 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))
     {
@@ -277,7 +310,6 @@ void client_manage(Window window)
     XChangeWindowAttributes(ob_display, window,
                             CWEventMask|CWDontPropagate, &attrib_set);
 
-
     /* create the ObClient struct, and populate it from the hints on the
        window */
     self = g_new0(ObClient, 1);
@@ -286,47 +318,52 @@ void client_manage(Window window)
 
     /* non-zero defaults */
     self->wmstate = WithdrawnState; /* make sure it gets updated first time */
-    self->layer = -1;
+    self->gravity = NorthWestGravity;
     self->desktop = screen_num_desktops; /* always an invalid value */
     self->user_time = focus_client ? focus_client->user_time : CurrentTime;
 
-    client_get_all(self);
-    /* per-app settings override stuff, and return the settings for other
-       uses too */
+    /* get all the stuff off the window */
+    client_get_all(self, TRUE);
+
+    /* specify that if we exit, the window should not be destroyed and
+       should be reparented back to root automatically */
+    XChangeSaveSet(ob_display, window, SetModeInsert);
+
+    /* create the decoration frame for the client window */
+    self->frame = frame_new(self);
+
+    frame_grab_client(self->frame);
+
+    /* we've grabbed everything and set everything that we need to at mapping
+       time now */
+    grab_server(FALSE);
+
+    /* per-app settings override stuff from client_get_all, and return the
+       settings for other uses too */
     settings = client_get_settings_state(self);
-    /* the session should get the last say */
+    /* the session should get the last say thought */
     client_restore_session_state(self);
 
-    client_calc_layer(self);
+    /* now we have all of the window's information so we can set this up */
+    client_setup_decor_and_functions(self);
 
+    /* remove the client's border (and adjust re gravity) */
+    client_toggle_border(self, FALSE);
+     
     {
         Time t = sn_app_started(self->startup_id, self->class);
         if (t) self->user_time = t;
     }
 
-    /* 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);
-
-    /* remove the client's border (and adjust re gravity) */
-    client_toggle_border(self, FALSE);
-     
-    /* specify that if we exit, the window should not be destroyed and should
-       be reparented back to root automatically */
-    XChangeSaveSet(ob_display, window, SetModeInsert);
-
-    /* create the decoration frame for the client window */
-    self->frame = frame_new(self);
-
-    frame_grab_client(self->frame, self);
-
     /* do this after we have a frame.. it uses the frame to help determine the
        WM_STATE to apply. */
     client_change_state(self);
 
-    grab_server(FALSE);
+    /* add ourselves to the focus order */
+    focus_order_add_new(self);
 
-    stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
+    /* do this to add ourselves to the stacking list in a non-intrusive way */
+    client_calc_layer(self);
 
     /* focus the new window? */
     if (ob_state() != OB_STATE_STARTING &&
@@ -454,19 +491,17 @@ void client_manage(Window window)
            raised to the top. Legacy begets legacy I guess?
         */
         if (!client_restore_session_stacking(self))
-            client_raise(self);
+            stacking_raise(CLIENT_AS_WINDOW(self));
     }
 
+    /* adjust the frame to the client's size before showing the window */
+    frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
+
     /* this has to happen before we try focus the window, but we want it to
        happen after the client's stacking has been determined or it looks bad
     */
     client_show(self);
 
-    /* use client_focus instead of client_activate cuz client_activate does
-       stuff like switch desktops etc and I'm not interested in all that when
-       a window maps since its not based on an action from the user like
-       clicking a window to activate it. so keep the new window out of the way
-       but do focus it. */
     if (activate) {
         gboolean stacked = client_restore_session_stacking(self);
         client_present(self, FALSE, !stacked);
@@ -484,6 +519,34 @@ void client_manage(Window window)
     client_set_list();
 
     ob_debug("Managed window 0x%lx (%s)\n", window, self->class);
+
+    return;
+}
+
+
+ObClient *client_fake_manage(Window window)
+{
+    ObClient *self;
+    ObAppSettings *settings;
+
+    ob_debug("Pretend-managing window: %lx\n", window);
+
+    /* do this minimal stuff to figure out the client's decorations */
+
+    self = g_new0(ObClient, 1);
+    self->window = window;
+
+    client_get_all(self, FALSE);
+    /* per-app settings override stuff, and return the settings for other
+       uses too */
+    settings = client_get_settings_state(self);
+
+    client_setup_decor_and_functions(self);
+
+    /* create the decoration frame for the client window and adjust its size */
+    self->frame = frame_new(self);
+    frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
+    return self;
 }
 
 void client_unmanage_all()
@@ -497,8 +560,8 @@ void client_unmanage(ObClient *self)
     guint j;
     GSList *it;
 
-    ob_debug("Unmanaging window: %lx (%s) (%s)\n", self->window, self->class,
-             self->title ? self->title : "");
+    ob_debug("Unmanaging window: %lx (%s) (%s)\n", self->window,
+             self->class, self->title ? self->title : "");
 
     g_assert(self != NULL);
 
@@ -510,7 +573,8 @@ void client_unmanage(ObClient *self)
     /* flush to send the hide to the server quickly */
     XFlush(ob_display);
 
-    /* ignore enter events from the unmap so it doesnt mess with the focus */
+    /* ignore enter events from the unmap so it doesnt mess with the
+       focus */
     event_ignore_queued_enters();
 
     mouse_grab_for_client(self, FALSE);
@@ -537,17 +601,14 @@ void client_unmanage(ObClient *self)
     if (STRUT_EXISTS(self->strut))
         screen_update_areas();
 
-    for (it = client_destructors; it; it = g_slist_next(it)) {
-        ClientCallback *d = it->data;
-        d->func(self, d->data);
-    }
+    client_call_notifies(self, client_destroy_notifies);
 
     /* tell our parent(s) that we're gone */
     if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */
         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);
+                    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);
@@ -569,7 +630,12 @@ void client_unmanage(ObClient *self)
 
     /* restore the window's original geometry so it is not lost */
     {
-        Rect a = self->area;
+        Rect a;
+
+        /* give the client its border back */
+        client_toggle_border(self, TRUE);
+
+        a = self->area;
 
         if (self->fullscreen)
             a = self->pre_fullscreen_area;
@@ -584,9 +650,6 @@ void client_unmanage(ObClient *self)
             }
         }
 
-        /* give the client its border back */
-        client_toggle_border(self, TRUE);
-
         self->fullscreen = self->max_horz = self->max_vert = FALSE;
         self->decorations = 0; /* unmanaged windows have no decor */
 
@@ -594,7 +657,8 @@ void client_unmanage(ObClient *self)
     }
 
     /* reparent the window out of the frame, and free the frame */
-    frame_release_client(self->frame, self);
+    frame_release_client(self->frame);
+    frame_free(self->frame);
     self->frame = NULL;
 
     if (ob_state() != OB_STATE_EXITING) {
@@ -604,11 +668,15 @@ void client_unmanage(ObClient *self)
         PROP_ERASE(self->window, net_wm_state);
         PROP_ERASE(self->window, wm_state);
     } else {
-        /* if we're left in an unmapped state, the client wont be mapped. this
-           is bad, since we will no longer be managing the window on restart */
+        /* if we're left in an unmapped state, the client wont be mapped.
+           this is bad, since we will no longer be managing the window on
+           restart */
         XMapWindow(ob_display, self->window);
     }
 
+    /* update the list hints */
+    client_set_list();
+
     ob_debug("Unmanaged window 0x%lx\n", self->window);
 
     /* free all data allocated in the client struct */
@@ -626,9 +694,14 @@ void client_unmanage(ObClient *self)
     g_free(self->client_machine);
     g_free(self->sm_client_id);
     g_free(self);
-     
-    /* update the list hints */
-    client_set_list();
+}
+
+void client_fake_unmanage(ObClient *self)
+{
+    /* this is all that got allocated to get the decorations */
+
+    frame_free(self->frame);
+    g_free(self);
 }
 
 static ObAppSettings *client_get_settings_state(ObClient *self)
@@ -949,35 +1022,42 @@ static void client_toggle_border(ObClient *self, gboolean show)
 }
 
 
-static void client_get_all(ObClient *self)
+static void client_get_all(ObClient *self, gboolean real)
 {
+    /* this is needed for the frame to set itself up */
     client_get_area(self);
+
+    /* these things can change the decor and functions of the window */
+
     client_get_mwm_hints(self);
+    /* this can change the mwmhints for special cases */
+    client_get_type_and_transientness(self);
+    client_get_state(self);
+    client_update_normal_hints(self);
 
-    /* The transient-ness of a window is used to pick a type, but the type can
-       also affect transiency.
+    /* get the session related properties, these can change decorations
+       from per-app settings */
+    client_get_session_ids(self);
 
-       Dialogs are always made transients for their group if they have one.
+    /* now we got everything that can affect the decorations */
+    if (!real)
+        return;
 
-       I also have made non-application type windows be transients for their
-       group (eg utility windows).
-    */
-    client_get_transientness(self);
-    client_get_type(self);/* this can change the mwmhints for special cases */
-    client_get_state(self);
+    /* get this early so we have it for debugging */
+    client_update_title(self);
+
+    client_update_protocols(self);
 
     client_update_wmhints(self);
     /* this may have already been called from client_update_wmhints */
     if (self->transient_for == NULL)
         client_update_transient_for(self);
+
     client_get_startup_id(self);
     client_get_desktop(self);/* uses transient data/group/startup id if a
                                 desktop is not specified */
     client_get_shaped(self);
 
-    client_get_layer(self); /* if layer hasn't been specified, get it from
-                               other sources if possible */
-
     {
         /* a couple type-based defaults for new windows */
 
@@ -985,26 +1065,12 @@ static void client_get_all(ObClient *self)
         if (self->type == OB_CLIENT_TYPE_DESKTOP)
             self->desktop = DESKTOP_ALL;
     }
-
-    client_update_protocols(self);
-
-    client_get_gravity(self); /* get the attribute gravity */
-    client_update_normal_hints(self); /* this may override the attribute
-                                         gravity */
-
-    /* got the type, the mwmhints, the protocols, and the normal hints
-       (min/max sizes), so we're ready to set up the decorations/functions */
-    client_setup_decor_and_functions(self);
   
 #ifdef SYNC
     client_update_sync_request_counter(self);
 #endif
 
-    /* get the session related properties */
-    client_get_session_ids(self);
-
     client_get_colormap(self);
-    client_update_title(self);
     client_update_strut(self);
     client_update_icons(self);
     client_update_user_time_window(self);
@@ -1078,41 +1144,6 @@ static void client_get_desktop(ObClient *self)
     }
 }
 
-static void client_get_layer(ObClient *self)
-{
-    if (!(self->above || self->below)) {
-        if (self->group) {
-            /* apply stuff from the group */
-            GSList *it;
-            gint layer = -2;
-
-            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))
-                {
-                    layer = MAX(layer,
-                                (c->above ? 1 : (c->below ? -1 : 0)));
-                }
-            }
-            switch (layer) {
-            case -1:
-                self->below = TRUE;
-                break;
-            case -2:
-            case 0:
-                break;
-            case 1:
-                self->above = TRUE;
-                break;
-            default:
-                g_assert_not_reached();
-                break;
-            }
-        }
-    }
-}
-
 static void client_get_state(ObClient *self)
 {
     guint32 *state;
@@ -1170,20 +1201,12 @@ static void client_get_shaped(ObClient *self)
 #endif
 }
 
-void client_get_transientness(ObClient *self)
-{
-    Window t;
-    if (XGetTransientForHint(ob_display, self->window, &t))
-        self->transient = TRUE;
-}
-
 void client_update_transient_for(ObClient *self)
 {
     Window t = None;
     ObClient *target = NULL;
 
     if (XGetTransientForHint(ob_display, self->window, &t)) {
-        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*/
@@ -1220,16 +1243,8 @@ void client_update_transient_for(ObClient *self)
                 }
             }
         }
-    } else if (self->type == OB_CLIENT_TYPE_DIALOG ||
-               self->type == OB_CLIENT_TYPE_TOOLBAR ||
-               self->type == OB_CLIENT_TYPE_MENU ||
-               self->type == OB_CLIENT_TYPE_UTILITY)
-    {
-        self->transient = TRUE;
-        if (self->group)
-            target = OB_TRAN_GROUP;
-    } else
-        self->transient = FALSE;
+    } else if (self->transient && self->group)
+        target = OB_TRAN_GROUP;
 
     client_update_transient_tree(self, self->group, self->group,
                                  self->transient_for, target);
@@ -1245,19 +1260,34 @@ static void client_update_transient_tree(ObClient *self,
     GSList *it, *next;
     ObClient *c;
 
+    /* * *
+      Group transient windows are not allowed to have other group
+      transient windows as their children.
+      * * */
+
+
     /* No change has occured */
     if (oldgroup == newgroup && oldparent == newparent) return;
 
     /** Remove the client from the transient tree wherever it has changed **/
 
     /* If the window is becoming a direct transient for a window in its group
-       then that window can't be a child of this window anymore */
+       then any group transients which were our children and are now becoming
+       our parents need to stop being our children.
+
+       Group transients can't be children of group transients already, but
+       we could have any number of direct parents above up, any of which could
+       be transient for the group, and we need to remove it from our children.
+    */
     if (oldparent != newparent &&
         newparent != NULL && newparent != OB_TRAN_GROUP &&
-        newparent->transient_for == OB_TRAN_GROUP &&
         newgroup != NULL && newgroup == oldgroup)
     {
-        self->transients = g_slist_remove(self->transients, newparent);
+        ObClient *look = newparent;
+        do {
+            self->transients = g_slist_remove(self->transients, look);
+            look = look->transient_for;
+        } while (look != NULL && look != OB_TRAN_GROUP);
     }
             
 
@@ -1329,7 +1359,9 @@ static void client_update_transient_tree(ObClient *self,
 
        WARNING: Cyclical transient-ness is possible. For e.g. if:
        A is transient for the group
-       B is a member of the group and transient for A
+       B is transient for A
+       C is transient for B
+       A can't be transient for C or we have a cycle
     */
     if (oldgroup != newgroup && newgroup != NULL &&
         newparent != OB_TRAN_GROUP)
@@ -1364,12 +1396,14 @@ static void client_get_mwm_hints(ObClient *self)
     }
 }
 
-void client_get_type(ObClient *self)
+void client_get_type_and_transientness(ObClient *self)
 {
     guint num, i;
     guint32 *val;
+    Window t;
 
     self->type = -1;
+    self->transient = FALSE;
   
     if (PROP_GETA32(self->window, net_wm_window_type, atom, &val, &num)) {
         /* use the first value that we know about in the array */
@@ -1403,7 +1437,10 @@ void client_get_type(ObClient *self)
         }
         g_free(val);
     }
-    
+
+    if (XGetTransientForHint(ob_display, self->window, &t))
+        self->transient = TRUE;
+            
     if (self->type == (ObClientType) -1) {
         /*the window type hint was not set, which means we either classify
           ourself as a normal window or a dialog, depending on if we are a
@@ -1413,6 +1450,15 @@ void client_get_type(ObClient *self)
         else
             self->type = OB_CLIENT_TYPE_NORMAL;
     }
+
+    /* then, based on our type, we can update our transientness.. */
+    if (self->type == OB_CLIENT_TYPE_DIALOG ||
+        self->type == OB_CLIENT_TYPE_TOOLBAR ||
+        self->type == OB_CLIENT_TYPE_MENU ||
+        self->type == OB_CLIENT_TYPE_UTILITY)
+    {
+        self->transient = TRUE;
+    }
 }
 
 void client_update_protocols(ObClient *self)
@@ -1456,16 +1502,6 @@ void client_update_sync_request_counter(ObClient *self)
 }
 #endif
 
-static void client_get_gravity(ObClient *self)
-{
-    XWindowAttributes wattrib;
-    Status ret;
-
-    ret = XGetWindowAttributes(ob_display, self->window, &wattrib);
-    g_assert(ret != BadWindow);
-    self->gravity = wattrib.win_gravity;
-}
-
 void client_get_colormap(ObClient *self)
 {
     XWindowAttributes wa;
@@ -1637,7 +1673,7 @@ void client_setup_decor_and_functions(ObClient *self)
     if (!(self->functions & OB_CLIENT_FUNC_ICONIFY))
         self->decorations &= ~OB_FRAME_DECOR_ICONIFY;
     if (!(self->functions & OB_CLIENT_FUNC_RESIZE))
-        self->decorations &= ~OB_FRAME_DECOR_GRIPS;
+        self->decorations &= ~(OB_FRAME_DECOR_GRIPS | OB_FRAME_DECOR_HANDLE);
 
     /* can't maximize without moving/resizing */
     if (!((self->functions & OB_CLIENT_FUNC_MAXIMIZE) &&
@@ -1649,7 +1685,7 @@ void client_setup_decor_and_functions(ObClient *self)
 
     /* kill the handle on fully maxed windows */
     if (self->max_vert && self->max_horz)
-        self->decorations &= ~OB_FRAME_DECOR_HANDLE;
+        self->decorations &= ~(OB_FRAME_DECOR_HANDLE | OB_FRAME_DECOR_GRIPS);
 
     /* finally, the user can have requested no decorations, which overrides
        everything (but doesnt give it a border if it doesnt have one) */
@@ -1715,7 +1751,7 @@ static void client_change_allowed_actions(ObClient *self)
         else self->shaded = FALSE;
     }
     if (!(self->functions & OB_CLIENT_FUNC_ICONIFY) && self->iconic) {
-        if (self->frame) client_iconify(self, FALSE, TRUE);
+        if (self->frame) client_iconify(self, FALSE, TRUE, FALSE);
         else self->iconic = FALSE;
     }
     if (!(self->functions & OB_CLIENT_FUNC_FULLSCREEN) && self->fullscreen) {
@@ -2184,6 +2220,8 @@ static void client_get_session_ids(ObClient *self)
         localhost[127] = '\0';
         if (strcmp(localhost, s) != 0)
             self->client_machine = s;
+        else
+            g_free(s);
     }
 }
 
@@ -2315,7 +2353,7 @@ static ObStackingLayer calc_layer(ObClient *self)
 }
 
 static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
-                                        ObStackingLayer min, gboolean raised)
+                                        ObStackingLayer min)
 {
     ObStackingLayer old, own;
     GSList *it;
@@ -2324,16 +2362,14 @@ static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
     own = calc_layer(self);
     self->layer = MAX(own, min);
 
+    if (self->layer != old) {
+        stacking_remove(CLIENT_AS_WINDOW(self));
+        stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
+    }
+
     for (it = self->transients; it; it = g_slist_next(it))
         client_calc_layer_recursive(it->data, orig,
-                                    self->layer,
-                                    raised ? raised : self->layer != old);
-
-    if (!raised && self->layer != old)
-        if (orig->frame) { /* only restack if the original window is managed */
-            stacking_remove(CLIENT_AS_WINDOW(self));
-            stacking_add(CLIENT_AS_WINDOW(self));
-        }
+                                    self->layer);
 }
 
 void client_calc_layer(ObClient *self)
@@ -2347,7 +2383,7 @@ void client_calc_layer(ObClient *self)
     it = client_search_all_top_parents(self);
 
     for (; it; it = g_slist_next(it))
-        client_calc_layer_recursive(it->data, orig, 0, FALSE);
+        client_calc_layer_recursive(it->data, orig, 0);
 }
 
 gboolean client_should_show(ObClient *self)
@@ -2380,6 +2416,8 @@ void client_hide(ObClient *self)
 {
     if (!client_should_show(self)) {
         frame_hide(self->frame);
+
+        client_call_notifies(self, client_hide_notifies);
     }
 
     /* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it
@@ -2397,6 +2435,8 @@ void client_showhide(ObClient *self)
     }
     else {
         frame_hide(self->frame);
+
+        client_call_notifies(self, client_hide_notifies);
     }
 
     /* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it
@@ -2453,7 +2493,7 @@ static void client_apply_startup_state(ObClient *self, gint x, gint y)
 
     if (self->iconic) {
         self->iconic = FALSE;
-        client_iconify(self, TRUE, FALSE);
+        client_iconify(self, TRUE, FALSE, TRUE);
     }
     if (self->fullscreen) {
         self->fullscreen = FALSE;
@@ -2678,12 +2718,11 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h,
 
 
 void client_configure_full(ObClient *self, gint x, gint y, gint w, gint h,
-                           gboolean user, gboolean final,
-                           gboolean force_reply)
+                           gboolean user, gboolean final)
 {
-    gint oldw, oldh, oldrx, oldry;
+    gint oldw, oldh;
     gboolean send_resize_client;
-    gboolean moved = FALSE, resized = FALSE, rootmoved = FALSE;
+    gboolean moved = FALSE, resized = FALSE;
     guint fdecor = self->frame->decorations;
     gboolean fhorz = self->frame->max_horz;
     gint logicalw, logicalh;
@@ -2723,17 +2762,7 @@ void client_configure_full(ObClient *self, gint x, gint y, gint w, gint h,
     if (moved || resized)
         frame_adjust_area(self->frame, moved, resized, FALSE);
 
-    /* find the client's position relative to the root window */
-    oldrx = self->root_pos.x;
-    oldry = self->root_pos.y;
-    rootmoved = (oldrx != (signed)(self->frame->area.x +
-                                   self->frame->size.left -
-                                   self->border_width) ||
-                 oldry != (signed)(self->frame->area.y +
-                                   self->frame->size.top -
-                                   self->border_width));
-
-    if (force_reply || ((!user || (user && final)) && rootmoved))
+    if ((!user || (user && final)) && !resized)
     {
         XEvent event;
 
@@ -2748,6 +2777,9 @@ void client_configure_full(ObClient *self, gint x, gint y, gint w, gint h,
         event.xconfigure.event = self->window;
         event.xconfigure.window = self->window;
 
+        ob_debug("Sending ConfigureNotify to %s for %d,%d %dx%d\n",
+                 self->title, self->root_pos.x, self->root_pos.y, w, h);
+
         /* root window real coords */
         event.xconfigure.x = self->root_pos.x;
         event.xconfigure.y = self->root_pos.y;
@@ -2828,7 +2860,8 @@ void client_fullscreen(ObClient *self, gboolean fs)
 }
 
 static void client_iconify_recursive(ObClient *self,
-                                     gboolean iconic, gboolean curdesk)
+                                     gboolean iconic, gboolean curdesk,
+                                     gboolean hide_animation)
 {
     GSList *it;
     gboolean changed = FALSE;
@@ -2868,7 +2901,7 @@ static void client_iconify_recursive(ObClient *self,
 
     if (changed) {
         client_change_state(self);
-        if (ob_state() != OB_STATE_STARTING && config_animate_iconify)
+        if (config_animate_iconify && !hide_animation)
             frame_begin_iconify_animation(self->frame, iconic);
         /* do this after starting the animation so it doesn't flash */
         client_showhide(self);
@@ -2879,15 +2912,17 @@ static void client_iconify_recursive(ObClient *self,
     for (it = self->transients; it; it = g_slist_next(it))
         if (it->data != self)
             if (client_is_direct_child(self, it->data) || !iconic)
-                client_iconify_recursive(it->data, iconic, curdesk);
+                client_iconify_recursive(it->data, iconic, curdesk,
+                                         hide_animation);
 }
 
-void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk)
+void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk,
+                    gboolean hide_animation)
 {
     if (self->functions & OB_CLIENT_FUNC_ICONIFY || !iconic) {
         /* move up the transient chain as far as possible first */
         self = client_search_top_normal_parent(self);
-        client_iconify_recursive(self, iconic, curdesk);
+        client_iconify_recursive(self, iconic, curdesk, hide_animation);
     }
 }
 
@@ -3060,7 +3095,7 @@ void client_set_desktop_recursive(ObClient *self,
             client_showhide(self);
         /* raise if it was not already on the desktop */
         if (old != DESKTOP_ALL)
-            client_raise(self);
+            stacking_raise(CLIENT_AS_WINDOW(self));
         if (STRUT_EXISTS(self->strut))
             screen_update_areas();
     }
@@ -3121,10 +3156,10 @@ void client_set_wm_state(ObClient *self, glong state)
   
     switch (state) {
     case IconicState:
-        client_iconify(self, TRUE, TRUE);
+        client_iconify(self, TRUE, TRUE, FALSE);
         break;
     case NormalState:
-        client_iconify(self, FALSE, TRUE);
+        client_iconify(self, FALSE, TRUE, FALSE);
         break;
     }
 }
@@ -3285,10 +3320,10 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
         self->modal = modal;
         /* when a window changes modality, then its stacking order with its
            transients needs to change */
-        client_raise(self);
+        stacking_raise(CLIENT_AS_WINDOW(self));
     }
     if (iconic != self->iconic)
-        client_iconify(self, iconic, FALSE);
+        client_iconify(self, iconic, FALSE, FALSE);
 
     if (demands_attention != self->demands_attention)
         client_hilite(self, demands_attention);
@@ -3411,9 +3446,9 @@ static void client_present(ObClient *self, gboolean here, gboolean raise)
     event_halt_focus_delay();
 
     if (client_normal(self) && screen_showing_desktop)
-        screen_show_desktop(FALSE, FALSE);
+        screen_show_desktop(FALSE, self);
     if (self->iconic)
-        client_iconify(self, FALSE, here);
+        client_iconify(self, FALSE, here, FALSE);
     if (self->desktop != DESKTOP_ALL &&
         self->desktop != screen_desktop)
     {
@@ -3427,17 +3462,10 @@ static void client_present(ObClient *self, gboolean here, gboolean raise)
         return;
     if (self->shaded)
         client_shade(self, FALSE);
+    if (raise)
+        stacking_raise(CLIENT_AS_WINDOW(self));
 
     client_focus(self);
-
-    if (raise) {
-        /* we do this as 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_activate(ObClient *self, gboolean here, gboolean user)
@@ -3493,16 +3521,6 @@ void client_bring_helper_windows(ObClient *self)
     client_bring_helper_windows_recursive(self, self->desktop);
 }
 
-void client_raise(ObClient *self)
-{
-    action_run_string("Raise", self, CurrentTime);
-}
-
-void client_lower(ObClient *self)
-{
-    action_run_string("Lower", self, CurrentTime);
-}
-
 gboolean client_focused(ObClient *self)
 {
     return self == focus_client;
@@ -3511,9 +3529,7 @@ gboolean client_focused(ObClient *self)
 static ObClientIcon* client_icon_recursive(ObClient *self, gint w, gint h)
 {
     guint i;
-    /* si is the smallest image >= req */
-    /* li is the largest image < req */
-    gulong size, smallest = 0xffffffff, largest = 0, si = 0, li = 0;
+    gulong min_diff, min_i;
 
     if (!self->nicons) {
         ObClientIcon *parent = NULL;
@@ -3536,20 +3552,23 @@ static ObClientIcon* client_icon_recursive(ObClient *self, gint w, gint h)
         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)) {
-            smallest = size;
-            si = i;
-        }
-        if (size > largest && size <= (unsigned)(w * h)) {
-            largest = size;
-            li = i;
+    /* some kind of crappy approximation to find the icon closest in size to
+       what we requested, but icons are generally all the same ratio as
+       eachother so it's good enough. */
+
+    min_diff = ABS(self->icons[0].width - w) + ABS(self->icons[0].height - h);
+    min_i = 0;
+
+    for (i = 1; i < self->nicons; ++i) {
+        gulong diff;
+
+        diff = ABS(self->icons[0].width - w) + ABS(self->icons[0].height - h);
+        if (diff < min_diff) {
+            min_diff = diff;
+            min_i = i;
         }
     }
-    if (largest == 0) /* didnt find one smaller than the requested size */
-        return &self->icons[si];
-    return &self->icons[li];
+    return &self->icons[min_i];
 }
 
 const ObClientIcon* client_icon(ObClient *self, gint w, gint h)
@@ -3723,7 +3742,7 @@ ObClient *client_search_transient(ObClient *self, ObClient *search)
                 continue;                                                     \
             if(cur->iconic)                                                   \
                 continue;                                                     \
-            if(cur->layer < c->layer && !config_resist_layers_below)          \
+            if(cur->layer == c->layer)                                        \
                 continue;
 
 #define HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) \
This page took 0.044032 seconds and 4 git commands to generate.