]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
when i said it handled both cases, i was mistaken, so use a callback for each case.
[chaz/openbox] / openbox / client.c
index f41c7558140062b53dee565ebaffb9b69a1283a1..112b8d8b900623ed1dcf53772a1d801e9909a446 100644 (file)
@@ -65,6 +65,7 @@ typedef struct
 GList            *client_list          = NULL;
 
 static GSList *client_destructors      = NULL;
+static GSList *client_hide_notifies    = NULL;
 
 static void client_get_all(ObClient *self, gboolean real);
 static void client_toggle_border(ObClient *self, gboolean show);
@@ -91,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_callbacks(ObClient *self, GSList *list);
 
 void client_startup(gboolean reconfig)
 {
@@ -104,6 +106,16 @@ void client_shutdown(gboolean reconfig)
     if (reconfig) return;
 }
 
+static void client_call_callbacks(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_destructor(ObClientCallback func, gpointer data)
 {
     ClientCallback *d = g_new(ClientCallback, 1);
@@ -126,6 +138,29 @@ void client_remove_destructor(ObClientCallback func)
     }
 }
 
+void client_add_hide_notify(ObClientCallback func, gpointer data)
+{
+    ClientCallback *d = g_new(ClientCallback, 1);
+    d->func = func;
+    d->data = data;
+    client_hide_notifies = g_slist_prepend(client_destructors, d);
+}
+
+void client_remove_hide_notify(ObClientCallback func)
+{
+    GSList *it;
+
+    for (it = client_hide_notifies; it; it = g_slist_next(it)) {
+        ClientCallback *d = it->data;
+        if (d->func == func) {
+            g_free(d);
+            client_hide_notifies =
+                g_slist_delete_link(client_hide_notifies, it);
+            break;
+        }
+    }
+}
+
 void client_set_list()
 {
     Window *windows, *win_it;
@@ -282,30 +317,13 @@ void client_manage(Window window)
 
     /* non-zero defaults */
     self->wmstate = WithdrawnState; /* make sure it gets updated first time */
+    self->gravity = NorthWestGravity;
     self->desktop = screen_num_desktops; /* always an invalid value */
     self->user_time = focus_client ? focus_client->user_time : CurrentTime;
 
+    /* get all the stuff off the window */
     client_get_all(self, TRUE);
-    /* per-app settings override stuff, and return the settings for other
-       uses too */
-    settings = client_get_settings_state(self);
-    /* the session should get the last say */
-    client_restore_session_state(self);
 
-    client_setup_decor_and_functions(self);
-
-    {
-        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);
@@ -315,11 +333,33 @@ void client_manage(Window window)
 
     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 thought */
+    client_restore_session_state(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;
+    }
+
     /* 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);
 
     /* do this to add ourselves to the stacking list in a non-intrusive way */
     client_calc_layer(self);
@@ -453,16 +493,14 @@ void client_manage(Window window)
             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);
@@ -562,10 +600,7 @@ 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_callbacks(self, client_destructors);
 
     /* tell our parent(s) that we're gone */
     if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */
@@ -594,7 +629,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;
@@ -609,9 +649,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 */
 
@@ -1005,6 +1042,9 @@ static void client_get_all(ObClient *self, gboolean real)
     if (!real)
         return;
 
+    /* get this early so we have it for debugging */
+    client_update_title(self);
+
     client_update_protocols(self);
 
     client_update_wmhints(self);
@@ -1030,7 +1070,6 @@ static void client_get_all(ObClient *self, gboolean real)
 #endif
 
     client_get_colormap(self);
-    client_update_title(self);
     client_update_strut(self);
     client_update_icons(self);
     client_update_user_time_window(self);
@@ -1220,19 +1259,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);
     }
             
 
@@ -1304,7 +1358,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)
@@ -1616,7 +1672,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) &&
@@ -2359,6 +2415,8 @@ void client_hide(ObClient *self)
 {
     if (!client_should_show(self)) {
         frame_hide(self->frame);
+
+        client_call_callbacks(self, client_hide_notifies);
     }
 
     /* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it
@@ -2376,6 +2434,8 @@ void client_showhide(ObClient *self)
     }
     else {
         frame_hide(self->frame);
+
+        client_call_callbacks(self, client_hide_notifies);
     }
 
     /* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it
@@ -2657,12 +2717,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;
@@ -2702,17 +2761,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;
 
@@ -2727,6 +2776,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;
@@ -3476,9 +3528,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;
@@ -3501,20 +3551,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)
@@ -3688,7 +3741,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.028936 seconds and 4 git commands to generate.