]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
show a popup with the focus target while cycling
[chaz/openbox] / openbox / client.c
index 1b1fedad7b944e63270abdc3203026aec7a5149c..68e1e09886d4d6d09aa1de0a047c5af8c9355669 100644 (file)
@@ -9,6 +9,7 @@
 #include "focus.h"
 #include "stacking.h"
 #include "dispatch.h"
+#include "group.h"
 
 #include <glib.h>
 #include <X11/Xutil.h>
@@ -37,6 +38,7 @@ static void client_get_gravity(Client *self);
 static void client_showhide(Client *self);
 static void client_change_allowed_actions(Client *self);
 static void client_change_state(Client *self);
+static void client_move_onscreen(Client *self);
 static Client *search_focus_tree(Client *node, Client *skip);
 static void client_apply_startup_state(Client *self);
 static Client *search_modal_tree(Client *node, Client *skip);
@@ -142,7 +144,7 @@ void client_manage_all()
 
 void client_manage(Window window)
 {
-    Client *client;
+    Client *self;
     XEvent e;
     XWindowAttributes attrib;
     XSetWindowAttributes attrib_set;
@@ -180,6 +182,7 @@ void client_manage(Window window)
        XFree(wmhint);
     }
 */
+    g_message("Managing window: %lx", window);
 
     /* choose the events we want to receive on the CLIENT window */
     attrib_set.event_mask = CLIENT_EVENTMASK;
@@ -190,57 +193,60 @@ void client_manage(Window window)
 
     /* create the Client struct, and populate it from the hints on the
        window */
-    client = g_new(Client, 1);
-    client->window = window;
-    client_get_all(client);
+    self = g_new(Client, 1);
+    self->window = window;
+    client_get_all(self);
 
     /* remove the client's border (and adjust re gravity) */
-    client_toggle_border(client, FALSE);
+    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 */
-    client->frame = engine_frame_new();
+    self->frame = engine_frame_new();
 
-    engine_frame_grab_client(client->frame, client);
+    engine_frame_grab_client(self->frame, self);
 
-    client_apply_startup_state(client);
+    client_apply_startup_state(self);
 
     grab_server(FALSE);
      
-    client_list = g_list_append(client_list, client);
-    stacking_list = g_list_append(stacking_list, client);
-    g_assert(!g_hash_table_lookup(client_map, &client->window));
-    g_hash_table_insert(client_map, &client->window, client);
+    client_list = g_list_append(client_list, self);
+    stacking_list = g_list_append(stacking_list, self);
+    g_assert(!g_hash_table_lookup(client_map, &self->window));
+    g_hash_table_insert(client_map, &self->window, self);
 
     /* update the focus lists */
-    if (client->desktop == DESKTOP_ALL) {
+    if (self->desktop == DESKTOP_ALL) {
         for (i = 0; i < screen_num_desktops; ++i)
-            focus_order[i] = g_list_append(focus_order[i], client);
+            focus_order[i] = g_list_append(focus_order[i], self);
     } else {
-        i = client->desktop;
-        focus_order[i] = g_list_append(focus_order[i], client);
+        i = self->desktop;
+        focus_order[i] = g_list_append(focus_order[i], self);
     }
 
-    stacking_raise(client);
+    stacking_raise(self);
 
     screen_update_struts();
 
-    dispatch_client(Event_Client_New, client, 0, 0);
+    dispatch_client(Event_Client_New, self, 0, 0);
 
-    client_showhide(client);
+    client_showhide(self);
 
-    dispatch_client(Event_Client_Mapped, client, 0, 0);
+    dispatch_client(Event_Client_Mapped, self, 0, 0);
 
     if (ob_state != State_Starting && focus_new)
-        client_focus(client);
+        client_focus(self);
 
     /* update the list hints */
     client_set_list();
 
-/*    g_message("Managed window 0x%lx", window);*/
+    /* make sure the window is visible */
+    client_move_onscreen(self);
+
+    g_message("Managed window 0x%lx", window);
 }
 
 void client_unmanage_all()
@@ -249,93 +255,135 @@ void client_unmanage_all()
        client_unmanage(client_list->data);
 }
 
-void client_unmanage(Client *client)
+void client_unmanage(Client *self)
 {
     guint i;
     int j;
     GSList *it;
 
-/*    g_message("Unmanaging window: %lx", client->window);*/
+    g_message("Unmanaging window: %lx", self->window);
 
-    dispatch_client(Event_Client_Destroy, client, 0, 0);
-    g_assert(client != NULL);
+    dispatch_client(Event_Client_Destroy, self, 0, 0);
+    g_assert(self != NULL);
 
     /* remove the window from our save set */
-    XChangeSaveSet(ob_display, client->window, SetModeDelete);
+    XChangeSaveSet(ob_display, self->window, SetModeDelete);
 
     /* we dont want events no more */
-    XSelectInput(ob_display, client->window, NoEventMask);
+    XSelectInput(ob_display, self->window, NoEventMask);
 
-    engine_frame_hide(client->frame);
+    engine_frame_hide(self->frame);
 
-    client_list = g_list_remove(client_list, client);
-    stacking_list = g_list_remove(stacking_list, client);
-    g_hash_table_remove(client_map, &client->window);
+    client_list = g_list_remove(client_list, self);
+    stacking_list = g_list_remove(stacking_list, self);
+    g_hash_table_remove(client_map, &self->window);
 
     /* update the focus lists */
-    if (client->desktop == DESKTOP_ALL) {
+    if (self->desktop == DESKTOP_ALL) {
         for (i = 0; i < screen_num_desktops; ++i)
-            focus_order[i] = g_list_remove(focus_order[i], client);
+            focus_order[i] = g_list_remove(focus_order[i], self);
     } else {
-        i = client->desktop;
-        focus_order[i] = g_list_remove(focus_order[i], client);
+        i = self->desktop;
+        focus_order[i] = g_list_remove(focus_order[i], self);
     }
 
     /* once the client is out of the list, update the struts to remove it's
        influence */
     screen_update_struts();
 
-    /* tell our parent that we're gone */
-    if (client->transient_for != NULL)
-       client->transient_for->transients =
-           g_slist_remove(client->transient_for->transients, client);
+    /* tell our parent(s) that we're gone */
+    if (self->transient_for == TRAN_GROUP) { /* transient of group */
+        GSList *it;
+
+        for (it = self->group->members; it; it = it->next)
+            if (it->data != self)
+                ((Client*)it->data)->transients =
+                    g_slist_remove(((Client*)it->data)->transients, self);
+    } else if (self->transient_for) {        /* transient of window */
+       self->transient_for->transients =
+           g_slist_remove(self->transient_for->transients, self);
+    }
 
     /* tell our transients that we're gone */
-    for (it = client->transients; it != NULL; it = it->next) {
-       ((Client*)it->data)->transient_for = NULL;
-       client_calc_layer(it->data);
+    for (it = self->transients; it != NULL; it = it->next) {
+        if (((Client*)it->data)->transient_for != TRAN_GROUP) {
+            ((Client*)it->data)->transient_for = NULL;
+            client_calc_layer(it->data);
+        }
+    }
+
+    focus_fallback(FALSE);
+
+    /* remove from its group */
+    if (self->group) {
+        group_remove(self->group, self);
+        self->group = NULL;
     }
 
     /* dispatch the unmapped event */
-    dispatch_client(Event_Client_Unmapped, client, 0, 0);
-    g_assert(client != NULL);
+    dispatch_client(Event_Client_Unmapped, self, 0, 0);
+    g_assert(self != NULL);
 
     /* give the client its border back */
-    client_toggle_border(client, TRUE);
+    client_toggle_border(self, TRUE);
 
     /* reparent the window out of the frame, and free the frame */
-    engine_frame_release_client(client->frame, client);
-    client->frame = NULL;
+    engine_frame_release_client(self->frame, self);
+    self->frame = NULL;
      
     if (ob_state != State_Exiting) {
        /* these values should not be persisted across a window
           unmapping/mapping */
-       prop_erase(client->window, prop_atoms.net_wm_desktop);
-       prop_erase(client->window, prop_atoms.net_wm_state);
+       prop_erase(self->window, prop_atoms.net_wm_desktop);
+       prop_erase(self->window, prop_atoms.net_wm_state);
     } else {
        /* if we're left in an iconic state, the client wont be mapped. this is
           bad, since we will no longer be managing the window on restart */
-       if (client->iconic)
-           XMapWindow(ob_display, client->window);
+       if (self->iconic)
+           XMapWindow(ob_display, self->window);
     }
 
+    g_message("Unmanaged window 0x%lx", self->window);
+
     /* free all data allocated in the client struct */
-    g_slist_free(client->transients);
-    for (j = 0; j < client->nicons; ++j)
-       g_free(client->icons[j].data);
-    if (client->nicons > 0)
-       g_free(client->icons);
-    g_free(client->title);
-    g_free(client->icon_title);
-    g_free(client->name);
-    g_free(client->class);
-    g_free(client->role);
-    g_free(client);
+    g_slist_free(self->transients);
+    for (j = 0; j < self->nicons; ++j)
+       g_free(self->icons[j].data);
+    if (self->nicons > 0)
+       g_free(self->icons);
+    g_free(self->title);
+    g_free(self->icon_title);
+    g_free(self->name);
+    g_free(self->class);
+    g_free(self->role);
+    g_free(self);
      
     /* update the list hints */
     client_set_list();
 }
 
+static void client_move_onscreen(Client *self)
+{
+    Rect *a;
+    int x = self->frame->area.x, y = self->frame->area.y;
+
+    a = screen_area(self->desktop);
+    if (x >= a->x + a->width - 1)
+        x = a->x + a->width - self->frame->area.width;
+    if (y >= a->y + a->height - 1)
+        y = a->y + a->height - self->frame->area.height;
+    if (x + self->frame->area.width - 1 < a->x)
+        x = a->x;
+    if (y + self->frame->area.height - 1< a->y)
+        y = a->y;
+
+    frame_frame_gravity(self->frame, &x, &y); /* get where the client
+                                              should be */
+    client_configure(self , Corner_TopLeft, x, y,
+                     self->area.width, self->area.height,
+                     TRUE, TRUE);
+}
+
 static void client_toggle_border(Client *self, gboolean show)
 {
     /* adjust our idea of where the client is, based on its border. When the
@@ -420,7 +468,7 @@ static void client_get_all(Client *self)
     self->urgent = FALSE;
     self->positioned = FALSE;
     self->disabled_decorations = 0;
-    self->group = None;
+    self->group = NULL;
     self->nicons = 0;
 
     client_get_area(self);
@@ -555,15 +603,14 @@ void client_update_transient_for(Client *self)
        c = g_hash_table_lookup(client_map, &t);
        g_assert(c != self);/* if this happens then we need to check for it*/
 
-       if (!c /*XXX: && _group*/) {
+       if (!c && self->group) {
            /* not transient to a client, see if it is transient for a
               group */
-           if (/*t == _group->leader() || */
+           if (t == self->group->leader ||
                t == None ||
                t == ob_root) {
                /* window is a transient for its group! */
-               /* XXX: for now this is treated as non-transient.
-                  this needs to be fixed! */
+                c = TRAN_GROUP;
            }
        }
     } else
@@ -571,15 +618,33 @@ void client_update_transient_for(Client *self)
 
     /* if anything has changed... */
     if (c != self->transient_for) {
-       if (self->transient_for)
+       if (self->transient_for == TRAN_GROUP) { /* transient of group */
+            GSList *it;
+
+           /* remove from old parents */
+            for (it = self->group->members; it; it = it->next)
+                if (it->data != self)
+                    ((Client*)it->data)->transients =
+                        g_slist_remove(((Client*)it->data)->transients, self);
+        } else if (self->transient_for != NULL) { /* transient of window */
            /* remove from old parent */
            self->transient_for->transients =
                 g_slist_remove(self->transient_for->transients, self);
+        }
        self->transient_for = c;
-       if (self->transient_for)
+       if (self->transient_for == TRAN_GROUP) { /* transient of group */
+            GSList *it;
+
+           /* add to new parents */
+            for (it = self->group->members; it; it = it->next)
+                if (it->data != self)
+                    ((Client*)it->data)->transients =
+                        g_slist_append(((Client*)it->data)->transients, self);
+        } else if (self->transient_for != NULL) { /* transient of window */
            /* add to new parent */
            self->transient_for->transients =
                 g_slist_append(self->transient_for->transients, self);
+        }
     }
 }
 
@@ -939,14 +1004,22 @@ void client_update_wmhints(Client *self)
        if (hints->flags & XUrgencyHint)
            ur = TRUE;
 
-       if (hints->flags & WindowGroupHint) {
-           if (hints->window_group != self->group) {
-               /* XXX: remove from the old group if there was one */
-               self->group = hints->window_group;
-               /* XXX: do stuff with the group */
-           }
-       } else /* no group! */
-           self->group = None;
+       if (!(hints->flags & WindowGroupHint))
+            hints->window_group = None; /* no group */
+        /* did the group state change? */
+        if (hints->window_group != (self->group ? self->group->leader : None)){
+            /* remove from the old group if there was one */
+            if (self->group != NULL)
+                group_remove(self->group, self);
+            if (hints->window_group != None)
+                self->group = group_add(hints->window_group, self);
+
+            /* because the self->transient flag wont change from this call,
+               we don't need to update the window's type and such, only its
+               transient_for, and the transients lists of other windows in the
+               group may be affected */
+            client_update_transient_for(self);
+        }
 
        if (hints->flags & IconPixmapHint) {
            client_update_kwm_icon(self);
@@ -1212,7 +1285,7 @@ void client_calc_layer(Client *self)
     /* are we fullscreen, or do we have a fullscreen transient parent? */
     c = self;
     fs = FALSE;
-    while (c) {
+    while (c && c != TRAN_GROUP) { /* XXX do smthng with the TRAN_GROUP case?*/
        if (c->fullscreen) {
            fs = TRUE;
            break;
@@ -1554,6 +1627,14 @@ void client_iconify(Client *self, gboolean iconic, gboolean curdesk)
 
     dispatch_client(iconic ? Event_Client_Unmapped : Event_Client_Mapped,
                     self, 0, 0);
+
+    /* iconify all transients */
+    if (self->transients) {
+        GSList *it;
+
+        for (it = self->transients; it != NULL; it = it->next)
+            if (it->data != self) client_iconify(it->data, iconic, curdesk);
+    }
 }
 
 void client_maximize(Client *self, gboolean max, int dir, gboolean savearea)
@@ -1984,7 +2065,9 @@ gboolean client_focus(Client *self)
        XSendEvent(ob_display, self->window, FALSE, NoEventMask, &ce);
     }
 
+#ifdef DEBUG_FOCUS
     g_message("focusing %lx", self->window);
+#endif
 
     /* Cause the FocusIn to come back to us. Important for desktop switches,
        since otherwise we'll have no FocusIn on the queue and send it off to
This page took 0.038042 seconds and 4 git commands to generate.