]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
why did they change again?
[chaz/openbox] / openbox / client.c
index 9ed6fd60998331e95502ea6d189fbddcfb4e36c6..39bd94d5e530917a8eb056fc8c33da2eca73fded 100644 (file)
@@ -64,7 +64,8 @@ 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, gboolean real);
 static void client_toggle_border(ObClient *self, gboolean show);
@@ -79,7 +80,7 @@ static void client_get_colormap(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);
-static void client_apply_startup_state(ObClient *self, gint x, gint y);
+static void client_apply_startup_state(ObClient *self);
 static void client_restore_session_state(ObClient *self);
 static gboolean client_restore_session_stacking(ObClient *self);
 static ObAppSettings *client_get_settings_state(ObClient *self);
@@ -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_notifies(ObClient *self, GSList *list);
 
 void client_startup(gboolean reconfig)
 {
@@ -104,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;
         }
     }
@@ -229,7 +265,6 @@ void client_manage(Window window)
     XWMHints *wmhint;
     gboolean activate = FALSE;
     ObAppSettings *settings;
-    gint newx, newy;
 
     grab_server(TRUE);
 
@@ -347,20 +382,21 @@ void client_manage(Window window)
         activate = TRUE;
     }
 
-    /* get the current position */
-    newx = self->area.x;
-    newy = self->area.y;
-
     /* figure out placement for the window */
     if (ob_state() == OB_STATE_RUNNING) {
         gboolean transient;
 
-        transient = place_client(self, &newx, &newy, settings);
+        ob_debug("Positioned: %s @ %d %d\n",
+                 (!self->positioned ? "no" :
+                  (self->positioned == PPosition ? "program specified" :
+                   (self->positioned == USPosition ? "user specified" :
+                    "BADNESS !?"))), self->area.x, self->area.y);
+
+        transient = place_client(self, &self->area.x, &self->area.y, settings);
 
         /* make sure the window is visible. */
-        client_find_onscreen(self, &newx, &newy,
-                             self->area.width,
-                             self->area.height,
+        client_find_onscreen(self, &self->area.x, &self->area.y,
+                             self->area.width, self->area.height,
                              /* non-normal clients has less rules, and
                                 windows that are being restored from a
                                 session do also. we can assume you want
@@ -383,12 +419,18 @@ void client_manage(Window window)
        also, this moves the window to the position where it has been placed
     */
     ob_debug("placing window 0x%x at %d, %d with size %d x %d\n",
-             self->window, newx, newy, self->area.width, self->area.height);
+             self->window, self->area.x, self->area.y,
+             self->area.width, self->area.height);
     if (self->session)
-        ob_debug("session requested %d %d\n",
+        ob_debug("  but session requested %d %d instead, overriding\n",
                  self->session->x, self->session->y);
 
-    client_apply_startup_state(self, newx, newy);
+    /* generate a ConfigureNotify telling the client where it is */
+    client_configure_full(self, self->area.x, self->area.y,
+                          self->area.width, self->area.height,
+                          FALSE, TRUE);
+
+    client_apply_startup_state(self);
 
     mouse_grab_for_client(self, TRUE);
 
@@ -460,17 +502,13 @@ void client_manage(Window window)
 
     /* adjust the frame to the client's size before showing the window */
     frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
+    frame_adjust_client_area(self->frame);
 
     /* 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);
@@ -570,10 +608,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_notifies(self, client_destroy_notifies);
 
     /* tell our parent(s) that we're gone */
     if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */
@@ -1015,6 +1050,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);
@@ -1040,7 +1078,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);
@@ -1230,19 +1267,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);
     }
             
 
@@ -1314,7 +1366,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)
@@ -1546,7 +1600,9 @@ void client_setup_decor_and_functions(ObClient *self)
          OB_CLIENT_FUNC_ICONIFY |
          OB_CLIENT_FUNC_MAXIMIZE |
          OB_CLIENT_FUNC_SHADE |
-         OB_CLIENT_FUNC_CLOSE);
+         OB_CLIENT_FUNC_CLOSE |
+         OB_CLIENT_FUNC_BELOW |
+         OB_CLIENT_FUNC_ABOVE);
 
     if (!(self->min_size.width < self->max_size.width ||
           self->min_size.height < self->max_size.height))
@@ -1578,10 +1634,15 @@ void client_setup_decor_and_functions(ObClient *self)
         self->functions = OB_CLIENT_FUNC_MOVE;
 
     case OB_CLIENT_TYPE_DESKTOP:
-    case OB_CLIENT_TYPE_DOCK:
         /* these windows are not manipulated by the window manager */
         self->decorations = 0;
         self->functions = 0;
+
+    case OB_CLIENT_TYPE_DOCK:
+        /* these windows are not manipulated by the window manager, but they
+           can set below layer which has a special meaning */
+        self->decorations = 0;
+        self->functions = OB_CLIENT_FUNC_BELOW;
         break;
     }
 
@@ -1626,7 +1687,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) &&
@@ -1671,7 +1732,7 @@ void client_setup_decor_and_functions(ObClient *self)
 
 static void client_change_allowed_actions(ObClient *self)
 {
-    gulong actions[9];
+    gulong actions[11];
     gint num = 0;
 
     /* desktop windows are kept on all desktops */
@@ -1694,6 +1755,10 @@ static void client_change_allowed_actions(ObClient *self)
         actions[num++] = prop_atoms.net_wm_action_maximize_horz;
         actions[num++] = prop_atoms.net_wm_action_maximize_vert;
     }
+    if (self->functions & OB_CLIENT_FUNC_ABOVE)
+        actions[num++] = prop_atoms.net_wm_action_above;
+    if (self->functions & OB_CLIENT_FUNC_BELOW)
+        actions[num++] = prop_atoms.net_wm_action_below;
 
     PROP_SETA32(self->window, net_wm_allowed_actions, atom, actions, num);
 
@@ -2369,6 +2434,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
@@ -2386,6 +2453,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
@@ -2424,17 +2493,8 @@ gboolean client_enter_focusable(ObClient *self)
 }
 
 
-static void client_apply_startup_state(ObClient *self, gint x, gint y)
+static void client_apply_startup_state(ObClient *self)
 {
-    gboolean pos = FALSE; /* has the window's position been configured? */
-    gint ox, oy;
-
-    /* save the position, and set self->area for these to use */
-    ox = self->area.x;
-    oy = self->area.y;
-    self->area.x = x;
-    self->area.y = y;
-
     /* set the desktop hint, to make sure that it always exists */
     PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop);
 
@@ -2447,7 +2507,6 @@ static void client_apply_startup_state(ObClient *self, gint x, gint y)
     if (self->fullscreen) {
         self->fullscreen = FALSE;
         client_fullscreen(self, TRUE);
-        pos = TRUE;
     }
     if (self->undecorated) {
         self->undecorated = FALSE;
@@ -2465,27 +2524,12 @@ static void client_apply_startup_state(ObClient *self, gint x, gint y)
     if (self->max_vert && self->max_horz) {
         self->max_vert = self->max_horz = FALSE;
         client_maximize(self, TRUE, 0);
-        pos = TRUE;
     } else if (self->max_vert) {
         self->max_vert = FALSE;
         client_maximize(self, TRUE, 2);
-        pos = TRUE;
     } else if (self->max_horz) {
         self->max_horz = FALSE;
         client_maximize(self, TRUE, 1);
-        pos = TRUE;
-    }
-
-    /* if the client didn't get positioned yet, then do so now.
-       call client_move even if the window is not being moved anywhere, because
-       when we reparent it and decorate it, it is getting moved and we need to
-       be telling it so with a ConfigureNotify event.
-    */
-    if (!pos) {
-        /* use the saved position */
-        self->area.x = ox;
-        self->area.y = oy;
-        client_move(self, x, y);
     }
 
     /* nothing to do for the other states:
@@ -2699,8 +2743,9 @@ void client_configure_full(ObClient *self, gint x, gint y, gint w, gint h,
                                     (resized && config_resize_redraw))));
 
     /* if the client is enlarging, then resize the client before the frame */
-    if (send_resize_client && user && (w > oldw || h > oldh)) {
-        XResizeWindow(ob_display, self->window, MAX(w, oldw), MAX(h, oldh));
+    if (send_resize_client && (w > oldw || h > oldh)) {
+        XResizeWindow(ob_display, self->window,
+                      MAX(w, oldw), MAX(h, oldh));
         /* resize the plate to show the client padding color underneath */
         frame_adjust_client_area(self->frame);
     }
@@ -2742,11 +2787,12 @@ void client_configure_full(ObClient *self, gint x, gint y, gint w, gint h,
     }
 
     /* if the client is shrinking, then resize the frame before the client */
-    if (send_resize_client && (!user || (w <= oldw || h <= oldh))) {
+    if (send_resize_client && (w <= oldw || h <= oldh)) {
         /* resize the plate to show the client padding color underneath */
         frame_adjust_client_area(self->frame);
 
-        XResizeWindow(ob_display, self->window, w, h);
+        if (send_resize_client)
+            XResizeWindow(ob_display, self->window, w, h);
     }
 
     XFlush(ob_display);
@@ -3346,6 +3392,16 @@ gboolean client_focus(ObClient *self)
                   "Focusing client \"%s\" at time %u\n",
                   self->title, event_curtime);
 
+    /* if there is a grab going on, then we need to cancel it. if we move
+       focus during the grab, applications will get NotifyWhileGrabbed events
+       and ignore them !
+
+       actions should not rely on being able to move focus during an
+       interactive grab.
+    */
+    if (keyboard_interactively_grabbed())
+        keyboard_interactive_cancel();
+
     if (self->can_focus) {
         /* This can cause a BadMatch error with CurrentTime, or if an app
            passed in a bad time for _NET_WM_ACTIVE_WINDOW. */
@@ -3691,7 +3747,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.030962 seconds and 4 git commands to generate.