]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
add <underMouse> focus option
[chaz/openbox] / openbox / client.c
index 39cd27dca466f420d2cd101306622f055d0a72fb..9b4932a0fe2f1c940db314166b04a2982ccab68c 100644 (file)
@@ -78,7 +78,8 @@ 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);
+static void client_apply_startup_state(ObClient *self,
+                                       gint x, gint y, gint w, gint h);
 static void client_restore_session_state(ObClient *self);
 static gboolean client_restore_session_stacking(ObClient *self);
 static ObAppSettings *client_get_settings_state(ObClient *self);
@@ -240,7 +241,8 @@ void client_manage(Window window)
     XWMHints *wmhint;
     gboolean activate = FALSE;
     ObAppSettings *settings;
-    gint placex, placey;
+    gint placex, placey, placew, placeh;
+    gboolean transient = FALSE;
 
     grab_server(TRUE);
 
@@ -277,7 +279,7 @@ void client_manage(Window window)
         XFree(wmhint);
     }
 
-    ob_debug("Managing window: %lx\n", window);
+    ob_debug("Managing window: 0x%lx\n", window);
 
     /* choose the events we want to receive on the CLIENT window */
     attrib_set.event_mask = CLIENT_EVENTMASK;
@@ -317,11 +319,11 @@ void client_manage(Window window)
        settings for other uses too. the returned settings is a shallow copy,
        that needs to be freed with g_free(). */
     settings = client_get_settings_state(self);
-    /* the session should get the last say thought */
+    /* the session should get the last say though */
     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);
+    client_setup_decor_and_functions(self, FALSE);
 
     {
         Time t = sn_app_started(self->startup_id, self->class);
@@ -347,15 +349,19 @@ void client_manage(Window window)
          client_search_focus_tree_full(self)) &&
         /* this checks for focus=false for the window */
         (!settings || settings->focus != 0) &&
-        /* note the check against Type_Normal/Dialog, not client_normal(self),
-           which would also include other types. in this case we want more
-           strict rules for focus */
+        /* note the check against type Normal/Dialog/Utility,
+           not client_normal(self), which would also include other types.
+           in this case we want more strict rules for focus */
         (self->type == OB_CLIENT_TYPE_NORMAL ||
+         self->type == OB_CLIENT_TYPE_UTILITY ||
          self->type == OB_CLIENT_TYPE_DIALOG))
     {
         activate = TRUE;
     }
 
+    /* remove the client's border */
+    XSetWindowBorderWidth(ob_display, self->window, 0);
+
     /* adjust the frame to the client's size before showing or placing
        the window */
     frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
@@ -364,18 +370,18 @@ void client_manage(Window window)
     /* where the frame was placed is where the window was originally */
     placex = self->area.x;
     placey = self->area.y;
+    placew = self->area.width;
+    placeh = self->area.height;
 
     /* figure out placement for the window if the window is new */
     if (ob_state() == OB_STATE_RUNNING) {
-        gboolean transient;
-
         ob_debug("Positioned: %s @ %d %d\n",
                  (!self->positioned ? "no" :
                   (self->positioned == PPosition ? "program specified" :
                    (self->positioned == USPosition ? "user specified" :
                     (self->positioned == (PPosition | USPosition) ?
                      "program + user specified" :
-                     "BADNESS !?")))), self->area.x, self->area.y);
+                     "BADNESS !?")))), placex, placey);
 
         ob_debug("Sized: %s @ %d %d\n",
                  (!self->sized ? "no" :
@@ -383,37 +389,14 @@ void client_manage(Window window)
                    (self->sized == USSize ? "user specified" :
                     (self->sized == (PSize | USSize) ?
                      "program + user specified" :
-                     "BADNESS !?")))), self->area.width, self->area.height);
+                     "BADNESS !?")))), placew, placeh);
 
+        /* splash screens are also returned as TRUE for transient,
+           and so will be forced on screen below */
         transient = place_client(self, &placex, &placey, settings);
 
-        /* if the window isn't user-positioned, then make it fit inside
-           the visible screen area on its monitor.
-
-           the monitor is chosen by place_client! */
-        if (!(self->sized & USSize)) {
-            /* make a copy to modify */
-            Rect a = *screen_area_monitor(self->desktop, client_monitor(self));
-
-            /* shrink by the frame's area */
-            a.width -= self->frame->size.left + self->frame->size.right;
-            a.height -= self->frame->size.top + self->frame->size.bottom;
-
-            /* fit the window inside the area */
-            self->area.width = MIN(self->area.width, a.width);
-            self->area.height = MIN(self->area.height, a.height);
-
-            ob_debug("setting window size to %dx%d\n",
-                     self->area.width, self->area.height);
-
-            /* adjust the frame to the client's new size */
-            frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
-            frame_adjust_client_area(self->frame);
-        }
-
         /* make sure the window is visible. */
-        client_find_onscreen(self, &placex, &placey,
-                             self->area.width, self->area.height,
+        client_find_onscreen(self, &placex, &placey, placew, placeh,
                              /* non-normal clients has less rules, and
                                 windows that are being restored from a
                                 session do also. we can assume you want
@@ -423,42 +406,64 @@ void client_manage(Window window)
                                 place.c or by the user are allowed partially
                                 off-screen and on xinerama divides (ie,
                                 it is up to the placement routines to avoid
-                                the xinerama divides) */
+                                the xinerama divides)
+
+                                splash screens get "transient" set to TRUE by
+                                the place_client call
+                             */
                              transient ||
-                             (((self->positioned & PPosition) &&
-                               !(self->positioned & USPosition)) &&
+                             (!(self->positioned & USPosition) &&
                               client_normal(self) &&
                               !self->session));
     }
 
-    ob_debug("placing window 0x%x at %d, %d with size %d x %d\n",
-             self->window, placex, placey,
-             self->area.width, self->area.height);
-    if (self->session)
-        ob_debug("  but session requested %d %d instead, overriding\n",
-                 self->session->x, self->session->y);
+    /* if the window isn't user-sized, then make it fit inside
+       the visible screen area on its monitor. Use basically the same rules
+       for forcing the window on screen in the client_find_onscreen call.
 
-    /* do this after the window is placed, so the premax/prefullscreen numbers
-       won't be all wacko!!
-       also, this moves the window to the position where it has been placed
+       do this after place_client, it chooses the monitor!
+
+       splash screens get "transient" set to TRUE by
+       the place_client call
     */
-    client_apply_startup_state(self);
+    if (transient ||
+        (!(self->sized & USSize) &&
+         client_normal(self) &&
+         !self->session))
+    {
+        /* make a copy to modify */
+        Rect a = *screen_area_monitor(self->desktop, client_monitor(self));
 
-    /* move the client to its placed position, or it it's already there,
-       generate a ConfigureNotify telling the client where it is.
+        /* shrink by the frame's area */
+        a.width -= self->frame->size.left + self->frame->size.right;
+        a.height -= self->frame->size.top + self->frame->size.bottom;
 
-       do this after adjusting the frame. otherwise it gets all weird and
-       clients don't work right
+        /* fit the window inside the area */
+        if (placew > a.width || self->area.height > a.height) {
+            placew = MIN(self->area.width, a.width);
+            placeh = MIN(self->area.height, a.height);
 
-       also do this after applying the startup state so maximize and fullscreen
-       will get the right sizes and positions if the client is starting with
-       those states
-    */
-    client_configure(self, placex, placey,
-                     self->area.width, self->area.height,
-                     self->border_width,
-                     FALSE, TRUE);
+            ob_debug("setting window size to %dx%d\n",
+                     self->area.width, self->area.height);
+        }
+    }
+
+
+    ob_debug("placing window 0x%x at %d, %d with size %d x %d. "
+             "some restrictions may apply\n",
+             self->window, placex, placey, placew, placeh);
+    if (self->session)
+        ob_debug("  but session requested %d, %d  %d x %d instead, "
+                 "overriding\n",
+                 self->session->x, self->session->y,
+                 self->session->w, self->session->h);
+
+    /* do this after the window is placed, so the premax/prefullscreen numbers
+       won't be all wacko!!
 
+       this also places the window
+    */
+    client_apply_startup_state(self, placex, placey, placew, placeh);
 
     if (activate) {
         guint32 last_time = focus_client ?
@@ -497,7 +502,7 @@ void client_manage(Window window)
                is ambiguous (either the current focus target doesn't have
                a timestamp, or they are the same (we probably inherited it
                from them) */
-            else if (self->transient_for != NULL &&
+            else if (client_has_parent(self) &&
                      (!last_time || self->user_time == last_time))
             {
                 activate = FALSE;
@@ -575,7 +580,7 @@ void client_manage(Window window)
     g_free(settings);
 
     ob_debug("Managed window 0x%lx plate 0x%x (%s)\n",
-             window, self->frame->plate, self->class);
+             window, self->frame->window, self->class);
 
     return;
 }
@@ -598,7 +603,7 @@ ObClient *client_fake_manage(Window window)
        uses too. this returns a shallow copy that needs to be freed */
     settings = client_get_settings_state(self);
 
-    client_setup_decor_and_functions(self);
+    client_setup_decor_and_functions(self, FALSE);
 
     /* create the decoration frame for the client window and adjust its size */
     self->frame = frame_new(self);
@@ -626,7 +631,7 @@ void client_unmanage(ObClient *self)
     GSList *it;
 
     ob_debug("Unmanaging window: 0x%x plate 0x%x (%s) (%s)\n",
-             self->window, self->frame->plate,
+             self->window, self->frame->window,
              self->class, self->title ? self->title : "");
 
     g_assert(self != NULL);
@@ -639,9 +644,11 @@ 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 */
-    event_ignore_all_queued_enters();
+    if (!client_focused(self) || !config_focus_under_mouse) {
+        /* ignore enter events from the unmap so it doesnt mess with the
+           focus */
+        event_ignore_all_queued_enters();
+    }
 
     mouse_grab_for_client(self, FALSE);
 
@@ -718,6 +725,9 @@ void client_unmanage(ObClient *self)
         self->functions = OB_CLIENT_FUNC_MOVE | OB_CLIENT_FUNC_RESIZE;
         self->decorations = 0; /* unmanaged windows have no decor */
 
+        /* give the client its border back */
+        XSetWindowBorderWidth(ob_display, self->window, self->border_width);
+
         client_move_resize(self, a.x, a.y, a.width, a.height);
     }
 
@@ -1108,8 +1118,8 @@ static void client_get_area(ObClient *self)
     POINT_SET(self->root_pos, wattrib.x, wattrib.y);
     self->border_width = wattrib.border_width;
 
-    ob_debug("client area: %d %d  %d %d\n", wattrib.x, wattrib.y,
-             wattrib.width, wattrib.height);
+    ob_debug("client area: %d %d  %d %d  bw %d\n", wattrib.x, wattrib.y,
+             wattrib.width, wattrib.height, wattrib.border_width);
 }
 
 static void client_get_desktop(ObClient *self)
@@ -1121,13 +1131,16 @@ static void client_get_desktop(ObClient *self)
             self->desktop = screen_num_desktops - 1;
         else
             self->desktop = d;
+        ob_debug("client requested desktop 0x%x\n", self->desktop); 
     } else {
         gboolean trdesk = FALSE;
 
         if (self->transient_for) {
             if (self->transient_for != OB_TRAN_GROUP) {
-                self->desktop = self->transient_for->desktop;
-                trdesk = TRUE;
+                if (self->transient_for->desktop != DESKTOP_ALL) {
+                    self->desktop = self->transient_for->desktop;
+                    trdesk = TRUE;
+                }
             } else {
                 /* if all the group is on one desktop, then open it on the
                    same desktop */
@@ -1533,7 +1546,16 @@ void client_get_colormap(ObClient *self)
 
 void client_update_colormap(ObClient *self, Colormap colormap)
 {
-    self->colormap = colormap;
+    if (colormap == self->colormap) return;
+
+    ob_debug("Setting client %s colormap: 0x%x\n", self->title, colormap);
+
+    if (client_focused(self)) {
+        screen_install_colormap(self, FALSE); /* uninstall old one */
+        self->colormap = colormap;
+        screen_install_colormap(self, FALSE); /* install new one */
+    } else
+        self->colormap = colormap;
 }
 
 void client_update_normal_hints(ObClient *self)
@@ -1583,9 +1605,7 @@ void client_update_normal_hints(ObClient *self)
     }
 }
 
-/*! This needs to be followed by a call to client_configure to make
-  the changes show */
-void client_setup_decor_and_functions(ObClient *self)
+void client_setup_decor_and_functions(ObClient *self, gboolean reconfig)
 {
     /* start with everything (cept fullscreen) */
     self->decorations =
@@ -1741,6 +1761,9 @@ void client_setup_decor_and_functions(ObClient *self)
     }
 
     client_change_allowed_actions(self);
+
+    if (reconfig)
+        client_reconfigure(self);
 }
 
 static void client_change_allowed_actions(ObClient *self)
@@ -1800,12 +1823,9 @@ static void client_change_allowed_actions(ObClient *self)
 
 void client_reconfigure(ObClient *self)
 {
-    /* by making this pass FALSE for user, we avoid the emacs event storm where
-       every configurenotify causes an update in its normal hints, i think this
-       is generally what we want anyways... */
     client_configure(self, self->area.x, self->area.y,
                      self->area.width, self->area.height,
-                     self->border_width, FALSE, TRUE);
+                     FALSE, TRUE);
 }
 
 void client_update_wmhints(ObClient *self)
@@ -2292,7 +2312,7 @@ static void client_change_wm_state(ObClient *self)
 
 static void client_change_state(ObClient *self)
 {
-    gulong netstate[11];
+    gulong netstate[12];
     guint num;
 
     num = 0;
@@ -2345,27 +2365,44 @@ ObClient *client_search_focus_tree_full(ObClient *self)
             return client_search_focus_tree_full(self->transient_for);
         } else {
             GSList *it;
-            gboolean recursed = FALSE;
         
-            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)))
-                        return c;
-                    recursed = TRUE;
+            for (it = self->group->members; it; it = g_slist_next(it)) {
+                if (it->data != self) {
+                    ObClient *c = it->data;
+
+                    if (client_focused(c)) return c;
+                    if ((c = client_search_focus_tree(it->data))) return c;
                 }
-            if (recursed)
-                return NULL;
+            }
         }
     }
 
-    /* this function checks the whole tree, the client_search_focus_tree~
+    /* this function checks the whole tree, the client_search_focus_tree
        does not, so we need to check this window */
     if (client_focused(self))
         return self;
     return client_search_focus_tree(self);
 }
 
+gboolean client_has_parent(ObClient *self)
+{
+    if (self->transient_for) {
+        if (self->transient_for != OB_TRAN_GROUP) {
+            if (client_normal(self->transient_for))
+                return TRUE;
+        }
+        else if (self->group) {
+            GSList *it;
+
+            for (it = self->group->members; it; it = g_slist_next(it)) {
+                if (it->data != self && client_normal(it->data))
+                    return TRUE;
+            }
+        }
+    }
+    return FALSE;
+}
+
 static ObStackingLayer calc_layer(ObClient *self)
 {
     ObStackingLayer l;
@@ -2520,45 +2557,70 @@ gboolean client_enter_focusable(ObClient *self)
 }
 
 
-static void client_apply_startup_state(ObClient *self)
+static void client_apply_startup_state(ObClient *self,
+                                       gint x, gint y, gint w, gint h)
 {
-    /* set the desktop hint, to make sure that it always exists */
-    PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop);
+    /* save the states that we are going to apply */
+    gboolean iconic = self->iconic;
+    gboolean fullscreen = self->fullscreen;
+    gboolean undecorated = self->undecorated;
+    gboolean shaded = self->shaded;
+    gboolean demands_attention = self->demands_attention;
+    gboolean max_horz = self->max_horz;
+    gboolean max_vert = self->max_vert;
+    Rect oldarea;
+    gint l;
+
+    /* turn them all off in the client, so they won't affect the window
+       being placed */
+    self->iconic = self->fullscreen = self->undecorated = self->shaded =
+        self->demands_attention = self->max_horz = self->max_vert = FALSE;
+
+    /* move the client to its placed position, or it it's already there,
+       generate a ConfigureNotify telling the client where it is.
 
-    /* these are in a carefully crafted order.. */
+       do this after adjusting the frame. otherwise it gets all weird and
+       clients don't work right
+
+       do this before applying the states so they have the correct
+       pre-max/pre-fullscreen values
+    */
+    client_try_configure(self, &x, &y, &w, &h, &l, &l, FALSE);
+    ob_debug("placed window 0x%x at %d, %d with size %d x %d\n",
+             self->window, self->area.x, self->area.y,
+             self->area.width, self->area.height);
+    oldarea = self->area;              /* save the area */
+    RECT_SET(self->area, x, y, w, h);  /* put where it should be for the premax stuff */
 
-    if (self->iconic) {
-        self->iconic = FALSE;
+    /* apply the states. these are in a carefully crafted order.. */
+
+    if (iconic)
         client_iconify(self, TRUE, FALSE, TRUE);
-    }
-    if (self->fullscreen) {
-        self->fullscreen = FALSE;
+    if (fullscreen)
         client_fullscreen(self, TRUE);
-    }
-    if (self->undecorated) {
-        self->undecorated = FALSE;
+    if (undecorated)
         client_set_undecorated(self, TRUE);
-    }
-    if (self->shaded) {
-        self->shaded = FALSE;
+    if (shaded)
         client_shade(self, TRUE);
-    }
-    if (self->demands_attention) {
-        self->demands_attention = FALSE;
+    if (demands_attention)
         client_hilite(self, TRUE);
-    }
   
-    if (self->max_vert && self->max_horz) {
-        self->max_vert = self->max_horz = FALSE;
+    if (max_vert && max_horz)
         client_maximize(self, TRUE, 0);
-    } else if (self->max_vert) {
-        self->max_vert = FALSE;
+    else if (max_vert)
         client_maximize(self, TRUE, 2);
-    } else if (self->max_horz) {
-        self->max_horz = FALSE;
+    else if (max_horz)
         client_maximize(self, TRUE, 1);
+
+    /* if the window hasn't been configured yet, then do so now */
+    if (!fullscreen && !max_vert && !max_horz) {
+        self->area = oldarea;
+        client_configure(self, x, y, w, h, FALSE, TRUE);
     }
 
+    /* set the desktop hint, to make sure that it always exists */
+    PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop);
+
     /* nothing to do for the other states:
        skip_taskbar
        skip_pager
@@ -2781,7 +2843,7 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h,
 }
 
 
-void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b,
+void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
                       gboolean user, gboolean final)
 {
     gint oldw, oldh;
@@ -2801,14 +2863,12 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b,
         SIZE_SET(self->logical_size, logicalw, logicalh);
 
     /* figure out if we moved or resized or what */
-    moved = x != self->area.x || y != self->area.y;
-    resized = w != self->area.width || h != self->area.height ||
-        b != self->border_width;
+    moved = (x != self->area.x || y != self->area.y);
+    resized = (w != self->area.width || h != self->area.height);
 
     oldw = self->area.width;
     oldh = self->area.height;
     RECT_SET(self->area, x, y, w, h);
-    self->border_width = b;
 
     /* for app-requested resizes, always resize if 'resized' is true.
        for user-requested ones, only resize if final is true, or when
@@ -2820,9 +2880,8 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b,
     /* if the client is enlarging, then resize the client before the frame */
     if (send_resize_client && (w > oldw || h > oldh)) {
         XMoveResizeWindow(ob_display, self->window,
-                          -self->border_width, -self->border_width,
+                          self->frame->size.left, self->frame->size.top,
                           MAX(w, oldw), MAX(h, oldh));
-        /* resize the plate to show the client padding color underneath */
         frame_adjust_client_area(self->frame);
     }
 
@@ -2841,7 +2900,20 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b,
     if (fmoved || fresized)
         frame_adjust_area(self->frame, fmoved, fresized, FALSE);
 
-    if ((!user || (user && final)) && !resized)
+    /* This is kinda tricky and should not be changed.. let me explain!
+
+       When user = FALSE, then the request is coming from the application
+       itself, and we are more strict about when to send a synthetic
+       ConfigureNotify.  We strictly follow the rules of the ICCCM sec 4.1.5
+       in this case.
+
+       When user = TRUE, then the request is coming from "us", like when we
+       maximize a window or sometihng.  In this case we are more lenient.  We
+       used to follow the same rules as above, but _Java_ Swing can't handle
+       this. So just to appease Swing, when user = TRUE, we always send
+       a synthetic ConfigureNotify to give the window its root coordinates.
+    */
+    if ((!user && !resized) || (user && final))
     {
         XEvent event;
 
@@ -2867,21 +2939,21 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b,
         event.xconfigure.width = w;
         event.xconfigure.height = h;
         event.xconfigure.border_width = self->border_width;
-        event.xconfigure.above = self->frame->plate;
+        event.xconfigure.above = None;
         event.xconfigure.override_redirect = FALSE;
         XSendEvent(event.xconfigure.display, event.xconfigure.window,
                    FALSE, StructureNotifyMask, &event);
     }
 
-    /* if the client is shrinking, then resize the frame before the client */
+    /* if the client is shrinking, then resize the frame before the client.
+
+       both of these resize sections may run, because the top one only resizes
+       in the direction that is growing
+     */
     if (send_resize_client && (w <= oldw || h <= oldh)) {
-        /* resize the plate to show the client padding color underneath */
         frame_adjust_client_area(self->frame);
-
-        if (send_resize_client)
-            XMoveResizeWindow(ob_display, self->window,
-                              -self->border_width, -self->border_width,
-                              w, h);
+        XMoveResizeWindow(ob_display, self->window,
+                          self->frame->size.left, self->frame->size.top, w, h);
     }
 
     XFlush(ob_display);
@@ -2927,8 +2999,7 @@ void client_fullscreen(ObClient *self, gboolean fs)
         RECT_SET(self->pre_fullscreen_area, 0, 0, 0, 0);
     }
 
-    client_setup_decor_and_functions(self);
-
+    client_setup_decor_and_functions(self, FALSE);
     client_move_resize(self, x, y, w, h);
 
     /* and adjust our layer/stacking. do this after resizing the window,
@@ -3072,8 +3143,7 @@ void client_maximize(ObClient *self, gboolean max, gint dir)
 
     client_change_state(self); /* change the state hints on the client */
 
-    client_setup_decor_and_functions(self);
-
+    client_setup_decor_and_functions(self, FALSE);
     client_move_resize(self, x, y, w, h);
 }
 
@@ -3178,8 +3248,7 @@ void client_set_desktop_recursive(ObClient *self,
                 client_set_desktop_recursive(it->data, target, donthide);
 }
 
-void client_set_desktop(ObClient *self, guint target,
-                        gboolean donthide)
+void client_set_desktop(ObClient *self, guint target, gboolean donthide)
 {
     self = client_search_top_normal_parent(self);
     client_set_desktop_recursive(self, target, donthide);
@@ -3440,6 +3509,10 @@ gboolean client_can_focus(ObClient *self)
 
 gboolean client_focus(ObClient *self)
 {
+    /* we might not focus this window, so if we have modal children which would
+       be focused instead, bring them to this desktop */
+    client_bring_modal_windows(self);
+
     /* choose the correct target */
     self = client_focus_target(self);
 
@@ -3448,12 +3521,14 @@ gboolean client_focus(ObClient *self)
             /* update the focus lists */
             focus_order_to_top(self);
         }
+        ob_debug_type(OB_DEBUG_FOCUS,
+                      "Client %s can't be focused\n", self->title);
         return FALSE;
     }
 
     ob_debug_type(OB_DEBUG_FOCUS,
-                  "Focusing client \"%s\" at time %u\n",
-                  self->title, event_curtime);
+                  "Focusing client \"%s\" (0x%x) at time %u\n",
+                  self->title, self->window, 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
@@ -3491,6 +3566,7 @@ gboolean client_focus(ObClient *self)
 
     xerror_set_ignore(FALSE);
 
+    ob_debug_type(OB_DEBUG_FOCUS, "Error focusing? %d\n", xerror_occured);
     return !xerror_occured;
 }
 
@@ -3558,24 +3634,38 @@ void client_activate(ObClient *self, gboolean here, gboolean user)
         client_hilite(self, TRUE);
 }
 
-static void client_bring_helper_windows_recursive(ObClient *self,
-                                                  guint desktop)
+static void client_bring_windows_recursive(ObClient *self,
+                                           guint desktop,
+                                           gboolean helpers,
+                                           gboolean modals,
+                                           gboolean iconic)
 {
     GSList *it;
 
     for (it = self->transients; it; it = g_slist_next(it))
-        client_bring_helper_windows_recursive(it->data, desktop);
+        client_bring_windows_recursive(it->data, desktop,
+                                       helpers, modals, iconic);
 
-    if (client_helper(self) &&
-        self->desktop != desktop && self->desktop != DESKTOP_ALL)
+    if (((helpers && client_helper(self)) ||
+         (modals && self->modal)) &&
+        ((self->desktop != desktop && self->desktop != DESKTOP_ALL) ||
+         (iconic && self->iconic)))
     {
-        client_set_desktop(self, desktop, FALSE);
+        if (iconic && self->iconic)
+            client_iconify(self, FALSE, TRUE, FALSE);
+        else
+            client_set_desktop(self, desktop, FALSE);
     }
 }
 
 void client_bring_helper_windows(ObClient *self)
 {
-    client_bring_helper_windows_recursive(self, self->desktop);
+    client_bring_windows_recursive(self, self->desktop, TRUE, FALSE, FALSE);
+}
+
+void client_bring_modal_windows(ObClient *self)
+{
+    client_bring_windows_recursive(self, self->desktop, FALSE, TRUE, TRUE);
 }
 
 gboolean client_focused(ObClient *self)
@@ -3664,8 +3754,7 @@ void client_set_undecorated(ObClient *self, gboolean undecorated)
         (self->functions & OB_CLIENT_FUNC_UNDECORATE || !undecorated))
     {
         self->undecorated = undecorated;
-        client_setup_decor_and_functions(self);
-        client_reconfigure(self); /* show the lack of decorations */
+        client_setup_decor_and_functions(self, TRUE);
         client_change_state(self); /* reflect this in the state hints */
     }
 }
@@ -3789,13 +3878,12 @@ ObClient *client_search_transient(ObClient *self, ObClient *search)
 }
 
 #define WANT_EDGE(cur, c) \
-            if(cur == c)                                                      \
-                continue;                                                     \
-            if(!client_normal(cur))                                           \
+            if (cur == c)                                                     \
                 continue;                                                     \
-            if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL) \
+            if (c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL &&  \
+                cur->desktop != screen_desktop)                               \
                 continue;                                                     \
-            if(cur->iconic)                                                   \
+            if (cur->iconic)                                                  \
                 continue;
 
 #define HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) \
This page took 0.0410779999999999 seconds and 4 git commands to generate.