]> Dogcows Code - chaz/openbox/blobdiff - openbox/focus.c
make em saveunder
[chaz/openbox] / openbox / focus.c
index 16ab571e9c1928fbaa48fc3601d3e58ee2e41efc..947c05be00793dcea194db96732f443e0781c82e 100644 (file)
 #include "focus.h"
 #include "stacking.h"
 #include "popup.h"
+#include "render/render.h"
 
 #include <X11/Xlib.h>
 #include <glib.h>
 #include <assert.h>
 
-ObClient *focus_client;
+ObClient *focus_client, *focus_hilite;
 GList **focus_order; /* these lists are created when screen_startup
                         sets the number of desktops */
 ObClient *focus_cycle_target;
 
+struct {
+    InternalWindow top;
+    InternalWindow left;
+    InternalWindow right;
+    InternalWindow bottom;
+} focus_indicator;
+
+RrAppearance *a_focus_indicator;
+RrColor *color_white;
+
 static ObIconPopup *focus_cycle_popup;
 
 static void focus_cycle_destructor(ObClient *client, gpointer data)
@@ -49,15 +60,72 @@ static void focus_cycle_destructor(ObClient *client, gpointer data)
         focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE);
 }
 
+static Window createWindow(Window parent, unsigned long mask,
+                          XSetWindowAttributes *attrib)
+{
+    return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
+                        RrDepth(ob_rr_inst), InputOutput,
+                         RrVisual(ob_rr_inst), mask, attrib);
+                       
+}
+
 void focus_startup(gboolean reconfig)
 {
     focus_cycle_popup = icon_popup_new(TRUE);
 
     if (!reconfig) {
+        XSetWindowAttributes attr;
+
         client_add_destructor(focus_cycle_destructor, NULL);
 
         /* start with nothing focused */
         focus_set_client(NULL);
+
+        focus_indicator.top.obwin.type = Window_Internal;
+        focus_indicator.left.obwin.type = Window_Internal;
+        focus_indicator.right.obwin.type = Window_Internal;
+        focus_indicator.bottom.obwin.type = Window_Internal;
+
+        attr.save_under = True;
+        attr.override_redirect = True;
+        attr.background_pixel = BlackPixel(ob_display, ob_screen);
+        focus_indicator.top.win =
+            createWindow(RootWindow(ob_display, ob_screen),
+                         CWOverrideRedirect | CWBackPixel | CWSaveUnder,
+                         &attr);
+        focus_indicator.left.win =
+            createWindow(RootWindow(ob_display, ob_screen),
+                         CWOverrideRedirect | CWBackPixel | CWSaveUnder,
+                         &attr);
+        focus_indicator.right.win =
+            createWindow(RootWindow(ob_display, ob_screen),
+                         CWOverrideRedirect | CWBackPixel | CWSaveUnder,
+                         &attr);
+        focus_indicator.bottom.win =
+            createWindow(RootWindow(ob_display, ob_screen),
+                         CWOverrideRedirect | CWBackPixel | CWSaveUnder,
+                         &attr);
+
+        stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.top));
+        stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.left));
+        stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.right));
+        stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.bottom));
+
+        color_white = RrColorNew(ob_rr_inst, 0xff, 0xff, 0xff);
+
+        a_focus_indicator = RrAppearanceNew(ob_rr_inst, 4);
+        a_focus_indicator->surface.grad = RR_SURFACE_SOLID;
+        a_focus_indicator->surface.relief = RR_RELIEF_FLAT;
+        a_focus_indicator->surface.primary = RrColorNew(ob_rr_inst,
+                                                        0, 0, 0);
+        a_focus_indicator->texture[0].type = RR_TEXTURE_LINE_ART;
+        a_focus_indicator->texture[0].data.lineart.color = color_white;
+        a_focus_indicator->texture[1].type = RR_TEXTURE_LINE_ART;
+        a_focus_indicator->texture[1].data.lineart.color = color_white;
+        a_focus_indicator->texture[2].type = RR_TEXTURE_LINE_ART;
+        a_focus_indicator->texture[2].data.lineart.color = color_white;
+        a_focus_indicator->texture[3].type = RR_TEXTURE_LINE_ART;
+        a_focus_indicator->texture[3].data.lineart.color = color_white;
     }
 }
 
@@ -76,6 +144,15 @@ void focus_shutdown(gboolean reconfig)
 
         /* reset focus to root */
         XSetInputFocus(ob_display, PointerRoot, RevertToNone, event_lasttime);
+
+        RrColorFree(color_white);
+
+        RrAppearanceFree(a_focus_indicator);
+
+        XDestroyWindow(ob_display, focus_indicator.top.win);
+        XDestroyWindow(ob_display, focus_indicator.left.win);
+        XDestroyWindow(ob_display, focus_indicator.right.win);
+        XDestroyWindow(ob_display, focus_indicator.bottom.win);
     }
 }
 
@@ -131,15 +208,6 @@ void focus_set_client(ObClient *client)
     }
 }
 
-static gboolean focus_under_pointer()
-{
-    ObClient *c;
-
-    if ((c = client_under_pointer()))
-        return client_normal(c) && client_focus(c);
-    return FALSE;
-}
-
 /* finds the first transient that isn't 'skip' and ensure's that client_normal
  is true for it */
 static ObClient *find_transient_recursive(ObClient *c, ObClient *top, ObClient *skip)
@@ -156,31 +224,29 @@ static ObClient *find_transient_recursive(ObClient *c, ObClient *top, ObClient *
     return NULL;
 }
 
-static gboolean focus_fallback_transient(ObClient *top, ObClient *old)
+static ObClient* focus_fallback_transient(ObClient *top, ObClient *old)
 {
     ObClient *target = find_transient_recursive(top, top, old);
     if (!target) {
         /* make sure client_normal is true always */
         if (!client_normal(top))
-            return FALSE;
+            return NULL;
         target = top; /* no transient, keep the top */
     }
-    return client_focus(target);
+    if (client_can_focus(target))
+        return target;
+    else
+        return NULL;
 }
 
-void focus_fallback(ObFocusFallbackType type)
+ObClient* focus_fallback_target(ObFocusFallbackType type)
 {
     GList *it;
     ObClient *old = NULL;
+    ObClient *target = NULL;
 
     old = focus_client;
 
-    /* unfocus any focused clients.. they can be focused by Pointer events
-       and such, and then when I try focus them, I won't get a FocusIn event
-       at all for them.
-    */
-    focus_set_client(NULL);
-
     if (type == OB_FOCUS_FALLBACK_UNFOCUSING && old) {
         if (old->transient_for) {
             gboolean trans = FALSE;
@@ -188,16 +254,14 @@ void focus_fallback(ObFocusFallbackType type)
             if (!config_focus_follow)
                 trans = TRUE;
             else {
-                ObClient *c;
-
-                if ((c = client_under_pointer()) &&
-                    client_search_transient(client_search_top_transient(c),
-                                            old))
+                if ((target = client_under_pointer()) &&
+                    client_search_transient
+                    (client_search_top_transient(target), old))
+                {
                     trans = TRUE;
+                }
             }
 
-            g_message("trans %d", trans);
-
             /* try for transient relations */
             if (trans) {
                 if (old->transient_for == OB_TRAN_GROUP) {
@@ -206,20 +270,24 @@ void focus_fallback(ObFocusFallbackType type)
 
                         for (sit = old->group->members; sit; sit = sit->next)
                             if (sit->data == it->data)
-                                if (focus_fallback_transient(sit->data, old))
-                                    return;
+                                if ((target =
+                                     focus_fallback_transient(sit->data, old)))
+                                    return target;
                     }
                 } else {
-                    if (focus_fallback_transient(old->transient_for, old))
-                        return;
+                    if ((target =
+                         focus_fallback_transient(old->transient_for, old)))
+                        return target;
                 }
             }
         }
     }
 
-    if (config_focus_follow)
-        if (focus_under_pointer())
-            return;
+    if (config_focus_follow) {
+        if ((target = client_under_pointer()))
+            if (client_normal(target) && client_can_focus(target))
+                return target;
+    }
 
 #if 0
         /* try for group relations */
@@ -230,23 +298,31 @@ void focus_fallback(ObFocusFallbackType type)
                 for (sit = old->group->members; sit; sit = sit->next)
                     if (sit->data == it->data)
                         if (sit->data != old && client_normal(sit->data))
-                            if (client_can_focus(sit->data)) {
-                                gboolean r = client_focus(sit->data);
-                                assert(r);
-                                return;
-                            }
+                            if (client_can_focus(sit->data))
+                                return sit->data;
         }
 #endif
 
     for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
         if (type != OB_FOCUS_FALLBACK_UNFOCUSING || it->data != old)
-            if (client_normal(it->data) && client_can_focus(it->data)) {
-                gboolean r = client_focus(it->data);
-                assert(r);
-                return;
-            }
+            if (client_normal(it->data) && client_can_focus(it->data))
+                return it->data;
 
-    /* nothing to focus, and already set it to none above */
+    return NULL;
+}
+
+void focus_fallback(ObFocusFallbackType type)
+{
+    ObClient *new;
+
+    /* unfocus any focused clients.. they can be focused by Pointer events
+       and such, and then when I try focus them, I won't get a FocusIn event
+       at all for them.
+    */
+    focus_set_client(NULL);
+
+    if ((new = focus_fallback_target(type)))
+        client_focus(new);
 }
 
 static void popup_cycle(ObClient *c, gboolean show)
@@ -289,13 +365,152 @@ static void popup_cycle(ObClient *c, gboolean show)
     }
 }
 
+void focus_cycle_draw_indicator()
+{
+    if (!focus_cycle_target) {
+        XUnmapWindow(ob_display, focus_indicator.top.win);
+        XUnmapWindow(ob_display, focus_indicator.left.win);
+        XUnmapWindow(ob_display, focus_indicator.right.win);
+        XUnmapWindow(ob_display, focus_indicator.bottom.win);
+    } else {
+        /*
+          if (focus_cycle_target)
+              frame_adjust_focus(focus_cycle_target->frame, FALSE);
+          frame_adjust_focus(focus_cycle_target->frame, TRUE);
+        */
+        int x, y, w, h;
+        int wt, wl, wr, wb;
+
+        wt = wl = wr = wb = MAX(3,
+                                ob_rr_theme->handle_height +
+                                ob_rr_theme->bwidth * 2);
+
+        x = focus_cycle_target->frame->area.x;
+        y = focus_cycle_target->frame->area.y;
+        w = focus_cycle_target->frame->area.width;
+        h = wt;
+
+        XMoveResizeWindow(ob_display, focus_indicator.top.win,
+                          x, y, w, h);
+        a_focus_indicator->texture[0].data.lineart.x1 = 0;
+        a_focus_indicator->texture[0].data.lineart.y1 = h-1;
+        a_focus_indicator->texture[0].data.lineart.x2 = 0;
+        a_focus_indicator->texture[0].data.lineart.y2 = 0;
+        a_focus_indicator->texture[1].data.lineart.x1 = 0;
+        a_focus_indicator->texture[1].data.lineart.y1 = 0;
+        a_focus_indicator->texture[1].data.lineart.x2 = w-1;
+        a_focus_indicator->texture[1].data.lineart.y2 = 0;
+        a_focus_indicator->texture[2].data.lineart.x1 = w-1;
+        a_focus_indicator->texture[2].data.lineart.y1 = 0;
+        a_focus_indicator->texture[2].data.lineart.x2 = w-1;
+        a_focus_indicator->texture[2].data.lineart.y2 = h-1;
+        a_focus_indicator->texture[3].data.lineart.x1 = (wl-1);
+        a_focus_indicator->texture[3].data.lineart.y1 = h-1;
+        a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
+        a_focus_indicator->texture[3].data.lineart.y2 = h-1;
+        RrPaint(a_focus_indicator, focus_indicator.top.win,
+                w, h);
+
+        x = focus_cycle_target->frame->area.x;
+        y = focus_cycle_target->frame->area.y;
+        w = wl;
+        h = focus_cycle_target->frame->area.height;
+
+        XMoveResizeWindow(ob_display, focus_indicator.left.win,
+                          x, y, w, h);
+        a_focus_indicator->texture[0].data.lineart.x1 = w-1;
+        a_focus_indicator->texture[0].data.lineart.y1 = 0;
+        a_focus_indicator->texture[0].data.lineart.x2 = 0;
+        a_focus_indicator->texture[0].data.lineart.y2 = 0;
+        a_focus_indicator->texture[1].data.lineart.x1 = 0;
+        a_focus_indicator->texture[1].data.lineart.y1 = 0;
+        a_focus_indicator->texture[1].data.lineart.x2 = 0;
+        a_focus_indicator->texture[1].data.lineart.y2 = h-1;
+        a_focus_indicator->texture[2].data.lineart.x1 = 0;
+        a_focus_indicator->texture[2].data.lineart.y1 = h-1;
+        a_focus_indicator->texture[2].data.lineart.x2 = w-1;
+        a_focus_indicator->texture[2].data.lineart.y2 = h-1;
+        a_focus_indicator->texture[3].data.lineart.x1 = w-1;
+        a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
+        a_focus_indicator->texture[3].data.lineart.x2 = w-1;
+        a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
+        RrPaint(a_focus_indicator, focus_indicator.left.win,
+                w, h);
+
+        x = focus_cycle_target->frame->area.x +
+            focus_cycle_target->frame->area.width - wr;
+        y = focus_cycle_target->frame->area.y;
+        w = wr;
+        h = focus_cycle_target->frame->area.height ;
+
+        XMoveResizeWindow(ob_display, focus_indicator.right.win,
+                          x, y, w, h);
+        a_focus_indicator->texture[0].data.lineart.x1 = 0;
+        a_focus_indicator->texture[0].data.lineart.y1 = 0;
+        a_focus_indicator->texture[0].data.lineart.x2 = w-1;
+        a_focus_indicator->texture[0].data.lineart.y2 = 0;
+        a_focus_indicator->texture[1].data.lineart.x1 = w-1;
+        a_focus_indicator->texture[1].data.lineart.y1 = 0;
+        a_focus_indicator->texture[1].data.lineart.x2 = w-1;
+        a_focus_indicator->texture[1].data.lineart.y2 = h-1;
+        a_focus_indicator->texture[2].data.lineart.x1 = w-1;
+        a_focus_indicator->texture[2].data.lineart.y1 = h-1;
+        a_focus_indicator->texture[2].data.lineart.x2 = 0;
+        a_focus_indicator->texture[2].data.lineart.y2 = h-1;
+        a_focus_indicator->texture[3].data.lineart.x1 = 0;
+        a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
+        a_focus_indicator->texture[3].data.lineart.x2 = 0;
+        a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
+        RrPaint(a_focus_indicator, focus_indicator.right.win,
+                w, h);
+
+        x = focus_cycle_target->frame->area.x;
+        y = focus_cycle_target->frame->area.y +
+            focus_cycle_target->frame->area.height - wb;
+        w = focus_cycle_target->frame->area.width;
+        h = wb;
+
+        XMoveResizeWindow(ob_display, focus_indicator.bottom.win,
+                          x, y, w, h);
+        a_focus_indicator->texture[0].data.lineart.x1 = 0;
+        a_focus_indicator->texture[0].data.lineart.y1 = 0;
+        a_focus_indicator->texture[0].data.lineart.x2 = 0;
+        a_focus_indicator->texture[0].data.lineart.y2 = h-1;
+        a_focus_indicator->texture[1].data.lineart.x1 = 0;
+        a_focus_indicator->texture[1].data.lineart.y1 = h-1;
+        a_focus_indicator->texture[1].data.lineart.x2 = w-1;
+        a_focus_indicator->texture[1].data.lineart.y2 = h-1;
+        a_focus_indicator->texture[2].data.lineart.x1 = w-1;
+        a_focus_indicator->texture[2].data.lineart.y1 = h-1;
+        a_focus_indicator->texture[2].data.lineart.x2 = w-1;
+        a_focus_indicator->texture[2].data.lineart.y2 = 0;
+        a_focus_indicator->texture[3].data.lineart.x1 = wl-1;
+        a_focus_indicator->texture[3].data.lineart.y1 = 0;
+        a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
+        a_focus_indicator->texture[3].data.lineart.y2 = 0;
+        RrPaint(a_focus_indicator, focus_indicator.bottom.win,
+                w, h);
+
+        XMapWindow(ob_display, focus_indicator.top.win);
+        XMapWindow(ob_display, focus_indicator.left.win);
+        XMapWindow(ob_display, focus_indicator.right.win);
+        XMapWindow(ob_display, focus_indicator.bottom.win);
+    }
+}
+
 static gboolean valid_focus_target(ObClient *ft)
 {
     /* we don't use client_can_focus here, because that doesn't let you
        focus an iconic window, but we want to be able to, so we just check
        if the focus flags on the window allow it, and its on the current
        desktop */
-    return (!ft->transients && client_normal(ft) &&
+    return ((ft->type == OB_CLIENT_TYPE_NORMAL ||
+             ft->type == OB_CLIENT_TYPE_DIALOG ||
+             (!client_has_group_siblings(ft) &&
+              (ft->type == OB_CLIENT_TYPE_TOOLBAR ||
+               ft->type == OB_CLIENT_TYPE_MENU ||
+               ft->type == OB_CLIENT_TYPE_UTILITY))) &&
+            !ft->transients &&
             ((ft->can_focus || ft->focus_notify) &&
              !ft->skip_taskbar &&
              (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL)));
@@ -311,15 +526,10 @@ void focus_cycle(gboolean forward, gboolean linear,
     ObClient *ft = NULL;
 
     if (cancel) {
-        if (focus_cycle_target)
-            frame_adjust_focus(focus_cycle_target->frame, FALSE);
-        if (focus_client)
-            frame_adjust_focus(focus_client->frame, TRUE);
         focus_cycle_target = NULL;
         goto done_cycle;
-    } else if (done && dialog) {
+    } else if (done)
         goto done_cycle;
-    }
 
     if (!focus_order[screen_desktop])
         goto done_cycle;
@@ -346,10 +556,8 @@ void focus_cycle(gboolean forward, gboolean linear,
         ft = it->data;
         if (valid_focus_target(ft)) {
             if (ft != focus_cycle_target) { /* prevents flicker */
-                if (focus_cycle_target)
-                    frame_adjust_focus(focus_cycle_target->frame, FALSE);
                 focus_cycle_target = ft;
-                frame_adjust_focus(focus_cycle_target->frame, TRUE);
+                focus_cycle_draw_indicator();
             }
             popup_cycle(ft, dialog);
             return;
@@ -366,6 +574,7 @@ done_cycle:
     g_list_free(order);
     order = NULL;
 
+    focus_cycle_draw_indicator();
     popup_cycle(ft, FALSE);
 
     return;
@@ -378,15 +587,10 @@ void focus_directional_cycle(ObDirection dir,
     ObClient *ft = NULL;
 
     if (cancel) {
-        if (focus_cycle_target)
-            frame_adjust_focus(focus_cycle_target->frame, FALSE);
-        if (focus_client)
-            frame_adjust_focus(focus_client->frame, TRUE);
         focus_cycle_target = NULL;
         goto done_cycle;
-    } else if (done && dialog) {
+    } else if (done)
         goto done_cycle;
-    }
 
     if (!focus_order[screen_desktop])
         goto done_cycle;
@@ -406,10 +610,8 @@ void focus_directional_cycle(ObDirection dir,
         
     if (ft) {
         if (ft != focus_cycle_target) {/* prevents flicker */
-            if (focus_cycle_target)
-                frame_adjust_focus(focus_cycle_target->frame, FALSE);
             focus_cycle_target = ft;
-            frame_adjust_focus(focus_cycle_target->frame, TRUE);
+            focus_cycle_draw_indicator();
         }
     }
     if (focus_cycle_target) {
@@ -426,6 +628,7 @@ done_cycle:
     first = NULL;
     focus_cycle_target = NULL;
 
+    focus_cycle_draw_indicator();
     popup_cycle(ft, FALSE);
 
     return;
This page took 0.034245 seconds and 4 git commands to generate.