]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
option to make dragging and findedge ignore windows on lower layers
[chaz/openbox] / openbox / client.c
index 30bceae596787706e024eaffd351aec0e816c7ae..bc1ccc0e6ca2483747a16d9303d3a32a114a2c21 100644 (file)
@@ -1,19 +1,20 @@
 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
-client.c for the Openbox window manager
-Copyright (c) 2003        Ben Jansens
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-See the COPYING file for a copy of the GNU General Public License.
+   
+   client.c for the Openbox window manager
+   Copyright (c) 2004        Mikael Magnusson
+   Copyright (c) 2003        Ben Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
 */
 
 #include "client.h"
@@ -45,10 +46,10 @@ See the COPYING file for a copy of the GNU General Public License.
 
 /*! The event mask to grab on client windows */
 #define CLIENT_EVENTMASK (PropertyChangeMask | FocusChangeMask | \
-                         StructureNotifyMask)
+                          StructureNotifyMask)
 
 #define CLIENT_NOPROPAGATEMASK (ButtonPressMask | ButtonReleaseMask | \
-                               ButtonMotionMask)
+                                ButtonMotionMask)
 
 typedef struct
 {
@@ -119,7 +120,7 @@ void client_set_list()
     if (size > 0) {
         windows = g_new(Window, size);
         win_it = windows;
-        for (it = client_list; it != NULL; it = it->next, ++win_it)
+        for (it = client_list; it; it = g_list_next(it), ++win_it)
             *win_it = ((ObClient*)it->data)->window;
     } else
         windows = NULL;
@@ -134,17 +135,17 @@ void client_set_list()
 }
 
 /*
-  void client_foreach_transient(ObClient *self, ObClientForeachFunc func, void *data)
+  void client_foreach_transient(ObClient *self, ObClientForeachFunc func, gpointer data)
   {
   GSList *it;
 
-  for (it = self->transients; it; it = it->next) {
+  for (it = self->transients; it; it = g_slist_next(it)) {
   if (!func(it->data, data)) return;
   client_foreach_transient(it->data, func, data);
   }
   }
 
-  void client_foreach_ancestor(ObClient *self, ObClientForeachFunc func, void *data)
+  void client_foreach_ancestor(ObClient *self, ObClientForeachFunc func, gpointer data)
   {
   if (self->transient_for) {
   if (self->transient_for != OB_TRAN_GROUP) {
@@ -153,7 +154,7 @@ void client_set_list()
   } else {
   GSList *it;
 
-  for (it = self->group->members; it; it = it->next)
+  for (it = self->group->members; it; it = g_slist_next(it))
   if (it->data != self &&
   !((ObClient*)it->data)->transient_for) {
   if (!func(it->data, data)) return;
@@ -269,6 +270,10 @@ void client_manage(Window window)
 
     sn_app_started(self->class);
 
+    /* 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);
+
     client_change_state(self);
 
     /* remove the client's border (and adjust re gravity) */
@@ -287,9 +292,6 @@ void client_manage(Window window)
 
     client_apply_startup_state(self);
 
-    /* update the focus lists */
-    focus_order_add_new(self);
-
     stacking_add(CLIENT_AS_WINDOW(self));
     client_restore_session_stacking(self);
 
@@ -313,7 +315,7 @@ void client_manage(Window window)
             if (self->group) {
                 GSList *it;
 
-                for (it = self->group->members; it; it = it->next)
+                for (it = self->group->members; it; it = g_slist_next(it))
                 {
                     if (client_focused(it->data))
                     {
@@ -414,6 +416,10 @@ void client_unmanage(ObClient *self)
     keyboard_grab_for_client(self, FALSE);
     mouse_grab_for_client(self, FALSE);
 
+    /* potentially fix focusLast */
+    if (config_focus_last)
+        grab_pointer(TRUE, OB_CURSOR_NONE);
+
     /* remove the window from our save set */
     XChangeSaveSet(ob_display, self->window, SetModeDelete);
 
@@ -456,7 +462,7 @@ void client_unmanage(ObClient *self)
     if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */
         GSList *it;
 
-        for (it = self->group->members; it; it = it->next)
+        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);
@@ -466,7 +472,7 @@ void client_unmanage(ObClient *self)
     }
 
     /* tell our transients that we're gone */
-    for (it = self->transients; it != NULL; it = it->next) {
+    for (it = self->transients; it; it = g_slist_next(it)) {
         if (((ObClient*)it->data)->transient_for != OB_TRAN_GROUP) {
             ((ObClient*)it->data)->transient_for = NULL;
             client_calc_layer(it->data);
@@ -517,6 +523,9 @@ void client_unmanage(ObClient *self)
      
     /* update the list hints */
     client_set_list();
+
+    if (config_focus_last)
+        grab_pointer(FALSE, OB_CURSOR_NONE);
 }
 
 static void client_urgent_notify(ObClient *self)
@@ -714,22 +723,24 @@ static void client_get_all(ObClient *self)
     client_update_wmhints(self);
     client_get_startup_id(self);
     client_get_desktop(self);
-    client_get_state(self);
     client_get_shaped(self);
 
     client_get_mwm_hints(self);
     client_get_type(self);/* this can change the mwmhints for special cases */
 
+    /* The transient hint is used to pick a type, but the type can also affect
+       transiency (dialogs are always made transients). This is Havoc's idea,
+       but it is needed to make some apps work right (eg tsclient). */
+    client_update_transient_for(self);
+
+    client_get_state(self);
+
     {
         /* 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);
@@ -788,7 +799,7 @@ static void client_get_desktop(ObClient *self)
             } else {
                 GSList *it;
 
-                for (it = self->group->members; it; it = it->next)
+                for (it = self->group->members; it; it = g_slist_next(it))
                     if (it->data != self &&
                         !((ObClient*)it->data)->transient_for) {
                         self->desktop = ((ObClient*)it->data)->desktop;
@@ -858,7 +869,7 @@ static void client_get_state(ObClient *self)
             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))
+                    client_normal(self) && client_normal(c))
                 {
                     layer = MAX(layer,
                                 (c->above ? 1 : (c->below ? -1 : 0)));
@@ -930,6 +941,9 @@ void client_update_transient_for(ObClient *self)
                 }
             }
         }
+    } else if (self->type == OB_CLIENT_TYPE_DIALOG && self->group) {
+        self->transient = TRUE;
+        target = OB_TRAN_GROUP;
     } else
         self->transient = FALSE;
 
@@ -1219,7 +1233,7 @@ void client_setup_decor_and_functions(ObClient *self)
             /* 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))
@@ -1243,8 +1257,12 @@ void client_setup_decor_and_functions(ObClient *self)
 
     /* finally, the user can have requested no decorations, which overrides
        everything (but doesnt give it a border if it doesnt have one) */
-    if (self->undecorated)
-        self->decorations &= OB_FRAME_DECOR_BORDER;
+    if (self->undecorated) {
+        if (config_theme_keepborder)
+            self->decorations &= OB_FRAME_DECOR_BORDER;
+        else
+            self->decorations = 0;
+    }
 
     /* if we don't have a titlebar, then we cannot shade! */
     if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
@@ -1355,13 +1373,15 @@ void client_update_wmhints(ObClient *self)
             /* remove from the old group if there was one */
             if (self->group != NULL) {
                 /* remove transients of the group */
-                for (it = self->group->members; it; it = it->next)
+                for (it = self->group->members; it; it = g_slist_next(it))
                     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) {
+                    for (it = self->group->members; it;
+                         it = g_slist_next(it))
+                    {
                         ObClient *c = it->data;
 
                         if (c != self && !c->transient_for)
@@ -1381,7 +1401,9 @@ void client_update_wmhints(ObClient *self)
                 if (!self->transient_for) {
                     /* add other transients of the group that are already
                        set up */
-                    for (it = self->group->members; it; it = it->next) {
+                    for (it = self->group->members; it;
+                         it = g_slist_next(it))
+                    {
                         ObClient *c = it->data;
                         if (c != self && c->transient_for == OB_TRAN_GROUP)
                             self->transients =
@@ -1427,7 +1449,12 @@ void client_update_title(ObClient *self)
     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");
+            // http://developer.gnome.org/projects/gup/hig/draft_hig_new/windows-alert.html
+            if (self->transient) {
+                data = g_strdup("");
+                goto no_number;
+            } else
+                data = g_strdup("Unnamed Window");
 
     /* did the title change? then reset the title_count */
     if (old_title && 0 != strncmp(old_title, data, strlen(data)))
@@ -1435,7 +1462,7 @@ void client_update_title(ObClient *self)
 
     /* look for duplicates and append a number */
     nums = 0;
-    for (it = client_list; it; it = it->next)
+    for (it = client_list; it; it = g_list_next(it))
         if (it->data != self) {
             ObClient *c = it->data;
             if (0 == strncmp(c->title, data, strlen(data)))
@@ -1457,7 +1484,7 @@ void client_update_title(ObClient *self)
     }
 
     PROP_SETS(self->window, net_wm_visible_name, data);
-
+no_number:
     self->title = data;
 
     if (self->frame)
@@ -1716,7 +1743,7 @@ ObClient *client_search_focus_tree(ObClient *self)
     GSList *it;
     ObClient *ret;
 
-    for (it = self->transients; it != NULL; it = it->next) {
+    for (it = self->transients; it; it = g_slist_next(it)) {
         if (client_focused(it->data)) return it->data;
         if ((ret = client_search_focus_tree(it->data))) return ret;
     }
@@ -1732,7 +1759,7 @@ ObClient *client_search_focus_tree_full(ObClient *self)
             GSList *it;
             gboolean recursed = FALSE;
         
-            for (it = self->group->members; it; it = it->next)
+            for (it = self->group->members; it; it = g_slist_next(it))
                 if (!((ObClient*)it->data)->transient_for) {
                     ObClient *c;
                     if ((c = client_search_focus_tree_full(it->data)))
@@ -1763,7 +1790,7 @@ static ObStackingLayer calc_layer(ObClient *self)
     else if (self->type == OB_CLIENT_TYPE_DOCK) {
         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 l = OB_STACKING_LAYER_DOCK_NORMAL;
     }
     else if (self->above) l = OB_STACKING_LAYER_ABOVE;
     else if (self->below) l = OB_STACKING_LAYER_BELOW;
@@ -1782,7 +1809,7 @@ static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
     own = calc_layer(self);
     self->layer = l > own ? l : own;
 
-    for (it = self->transients; it; it = it->next)
+    for (it = self->transients; it; it = g_slist_next(it))
         client_calc_layer_recursive(it->data, orig,
                                     l, raised ? raised : l != old);
 
@@ -2036,26 +2063,28 @@ void client_configure_full(ObClient *self, ObCorner anchor,
         w -= self->base_size.width;
         h -= self->base_size.height;
 
-        if (self->min_ratio)
-            if (h * self->min_ratio > w) {
-                h = (gint)(w / self->min_ratio);
+        if (!self->fullscreen) {
+            if (self->min_ratio)
+                if (h * self->min_ratio > w) {
+                    h = (gint)(w / self->min_ratio);
 
-                /* you cannot resize to nothing */
-                if (h < 1) {
-                    h = 1;
-                    w = (gint)(h * self->min_ratio);
+                    /* you cannot resize to nothing */
+                    if (h < 1) {
+                        h = 1;
+                        w = (gint)(h * self->min_ratio);
+                    }
                 }
-            }
-        if (self->max_ratio)
-            if (h * self->max_ratio < w) {
-                h = (gint)(w / self->max_ratio);
-
-                /* you cannot resize to nothing */
-                if (h < 1) {
-                    h = 1;
-                    w = (gint)(h * self->min_ratio);
+            if (self->max_ratio)
+                if (h * self->max_ratio < w) {
+                    h = (gint)(w / self->max_ratio);
+
+                    /* you cannot resize to nothing */
+                    if (h < 1) {
+                        h = 1;
+                        w = (gint)(h * self->min_ratio);
+                    }
                 }
-            }
+        }
 
         w += self->base_size.width;
         h += self->base_size.height;
@@ -2091,9 +2120,9 @@ void client_configure_full(ObClient *self, ObCorner anchor,
        resizing in redraw mode */
     send_resize_client = ((!user && resized) ||
                           (user && (final ||
-                                    (resized && config_redraw_resize))));
+                                    (resized && config_resize_redraw))));
 
-    /* if the client is enlarging, the resize the client before the frame */
+    /* 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));
 
@@ -2245,7 +2274,7 @@ static void client_iconify_recursive(ObClient *self,
     }
 
     /* iconify all transients */
-    for (it = self->transients; it != NULL; it = it->next)
+    for (it = self->transients; it; it = g_slist_next(it))
         if (it->data != self) client_iconify_recursive(it->data,
                                                        iconic, curdesk);
 }
@@ -2437,7 +2466,7 @@ void client_set_desktop_recursive(ObClient *self,
     }
 
     /* move all transients */
-    for (it = self->transients; it != NULL; it = it->next)
+    for (it = self->transients; it; it = g_slist_next(it))
         if (it->data != self) client_set_desktop_recursive(it->data,
                                                            target, donthide);
 }
@@ -2453,7 +2482,7 @@ ObClient *client_search_modal_child(ObClient *self)
     GSList *it;
     ObClient *ret;
   
-    for (it = self->transients; it != NULL; it = it->next) {
+    for (it = self->transients; it; it = g_slist_next(it)) {
         ObClient *c = it->data;
         if ((ret = client_search_modal_child(c))) return ret;
         if (c->modal) return c;
@@ -2565,7 +2594,9 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
                 fullscreen = TRUE;
             } else if (state == prop_atoms.net_wm_state_above) {
                 self->above = TRUE;
+                self->below = FALSE;
             } else if (state == prop_atoms.net_wm_state_below) {
+                self->above = FALSE;
                 self->below = TRUE;
             } else if (state == prop_atoms.ob_wm_state_undecorated) {
                 undecorated = TRUE;
@@ -2773,7 +2804,7 @@ void client_raise(ObClient *self)
 
 void client_lower(ObClient *self)
 {
-    action_run_string("Raise", self);
+    action_run_string("Lower", self);
 }
 
 gboolean client_focused(ObClient *self)
@@ -2858,7 +2889,7 @@ ObClient *client_find_directional(ObClient *c, ObDirection dir)
     best_score = -1;
     best_client = NULL;
 
-    for(it = g_list_first(client_list); it; it = it->next) {
+    for(it = g_list_first(client_list); it; it = g_list_next(it)) {
         cur = it->data;
 
         /* the currently selected window isn't interesting */
@@ -2866,7 +2897,10 @@ ObClient *client_find_directional(ObClient *c, ObDirection dir)
             continue;
         if (!client_normal(cur))
             continue;
-        if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+        /* using c->desktop instead of screen_desktop doesn't work if the
+         * current window was omnipresent, hope this doesn't have any other
+         * side effects */
+        if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
             continue;
         if(cur->iconic)
             continue;
@@ -2995,7 +3029,7 @@ ObClient *client_search_top_transient(ObClient *self)
 
             g_assert(self->group);
 
-            for (it = self->group->members; it; it = it->next) {
+            for (it = self->group->members; it; it = g_slist_next(it)) {
                 ObClient *c = it->data;
 
                 /* checking transient_for prevents infinate loops! */
@@ -3019,7 +3053,7 @@ ObClient *client_search_focus_parent(ObClient *self)
         } else {
             GSList *it;
 
-            for (it = self->group->members; it; it = it->next) {
+            for (it = self->group->members; it; it = g_slist_next(it)) {
                 ObClient *c = it->data;
 
                 /* checking transient_for prevents infinate loops! */
@@ -3042,7 +3076,7 @@ ObClient *client_search_parent(ObClient *self, ObClient *search)
         } else {
             GSList *it;
 
-            for (it = self->group->members; it; it = it->next) {
+            for (it = self->group->members; it; it = g_slist_next(it)) {
                 ObClient *c = it->data;
 
                 /* checking transient_for prevents infinate loops! */
@@ -3105,7 +3139,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
         /* default: top of screen */
         dest = a->y;
 
-        for(it = g_list_first(client_list); it; it = it->next) {
+        for(it = client_list; it; it = g_list_next(it)) {
             gint his_edge_start, his_edge_end, his_offset;
             ObClient *cur = it->data;
 
@@ -3113,10 +3147,12 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
                 continue;
             if(!client_normal(cur))
                 continue;
-            if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+            if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
                 continue;
             if(cur->iconic)
                 continue;
+            if(cur->layer < c->layer && !config_resist_layers_below)
+                continue;
 
             his_edge_start = cur->frame->area.x;
             his_edge_end = cur->frame->area.x + cur->frame->area.width;
@@ -3146,7 +3182,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
         /* default: bottom of screen */
         dest = a->y + a->height;
 
-        for(it = g_list_first(client_list); it; it = it->next) {
+        for(it = client_list; it; it = g_list_next(it)) {
             gint his_edge_start, his_edge_end, his_offset;
             ObClient *cur = it->data;
 
@@ -3154,10 +3190,12 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
                 continue;
             if(!client_normal(cur))
                 continue;
-            if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+            if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
                 continue;
             if(cur->iconic)
                 continue;
+            if(cur->layer < c->layer && !config_resist_layers_below)
+                continue;
 
             his_edge_start = cur->frame->area.x;
             his_edge_end = cur->frame->area.x + cur->frame->area.width;
@@ -3188,7 +3226,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
         /* default: leftmost egde of screen */
         dest = a->x;
 
-        for(it = g_list_first(client_list); it; it = it->next) {
+        for(it = client_list; it; it = g_list_next(it)) {
             gint his_edge_start, his_edge_end, his_offset;
             ObClient *cur = it->data;
 
@@ -3196,10 +3234,12 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
                 continue;
             if(!client_normal(cur))
                 continue;
-            if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+            if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
                 continue;
             if(cur->iconic)
                 continue;
+            if(cur->layer < c->layer && !config_resist_layers_below)
+                continue;
 
             his_edge_start = cur->frame->area.y;
             his_edge_end = cur->frame->area.y + cur->frame->area.height;
@@ -3230,7 +3270,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
         /* default: rightmost edge of screen */
         dest = a->x + a->width;
 
-        for(it = g_list_first(client_list); it; it = it->next) {
+        for(it = client_list; it; it = g_list_next(it)) {
             gint his_edge_start, his_edge_end, his_offset;
             ObClient *cur = it->data;
 
@@ -3238,10 +3278,12 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
                 continue;
             if(!client_normal(cur))
                 continue;
-            if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+            if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
                 continue;
             if(cur->iconic)
                 continue;
+            if(cur->layer < c->layer && !config_resist_layers_below)
+                continue;
 
             his_edge_start = cur->frame->area.y;
             his_edge_end = cur->frame->area.y + cur->frame->area.height;
@@ -3281,7 +3323,7 @@ ObClient* client_under_pointer()
     ObClient *ret = NULL;
 
     if (screen_pointer_pos(&x, &y)) {
-        for (it = stacking_list; it != NULL; it = it->next) {
+        for (it = stacking_list; it; it = g_list_next(it)) {
             if (WINDOW_IS_CLIENT(it->data)) {
                 ObClient *c = WINDOW_AS_CLIENT(it->data);
                 if (c->frame->visible &&
This page took 0.038889 seconds and 4 git commands to generate.