[Xfce4-commits] <xfwm4:master> Add new keyboard shortcut to switch between windows of the same application, add new keyboard shortcut to switch between windows of different applications only, add new option "cycle_apps_only" to switch between regular toplevels only (avoiding dialogs - This option coupled with the new shortcut allows for faster window selection through keyboard)

Olivier Fourdan fourdan at xfce.org
Wed Sep 9 20:50:03 CEST 2009


Updating branch refs/heads/master
         to 9166f38e438cabae41f020b477091d36004495f0 (commit)
       from 03d73957a4dd5deb9a024ec1d80a43262df261be (commit)

commit 9166f38e438cabae41f020b477091d36004495f0
Author: Olivier Fourdan <fourdan at xfce.org>
Date:   Wed Sep 9 14:01:01 2009 +0200

    Add new keyboard shortcut to switch between windows of the same application, add new keyboard shortcut to switch between windows of different applications only, add new option "cycle_apps_only" to switch between regular toplevels only (avoiding dialogs - This option coupled with the new shortcut allows for faster window selection through keyboard)

 NEWS                              |    9 ++-
 defaults/defaults                 |    1 +
 settings-dialogs/xfwm4-settings.c |    2 +
 src/client.h                      |   14 ++-
 src/cycle.c                       |  221 ++++++++++++++++++++++++++++--------
 src/cycle.h                       |    3 +-
 src/events.c                      |   26 ++++-
 src/focus.c                       |   32 +++--
 src/focus.h                       |   11 +-
 src/netwm.c                       |    3 -
 src/settings.c                    |    5 +
 src/settings.h                    |    3 +
 src/stacking.c                    |    2 +-
 src/tabwin.c                      |   63 +++--------
 src/tabwin.h                      |    7 +-
 src/transients.c                  |   30 +++++
 src/transients.h                  |    6 +
 src/workspaces.c                  |    2 +-
 18 files changed, 310 insertions(+), 130 deletions(-)

diff --git a/NEWS b/NEWS
index c5ea733..dcdc59c 100644
--- a/NEWS
+++ b/NEWS
@@ -4,11 +4,18 @@
   when another window is activated (Bug #3551)
 - Do not clear the show desktop flag upon activation of
   already visible windows
-- Implement prelinminary support for snap on resize (patch by Clifford Jolly <cliff at cliffjolly.com>)
+- Implement prelinminary support for snap on resize (patch by Clifford Jolly
+  <cliff at cliffjolly.com>)
 - Fix mixed RTL/LTR text not rendering properly in title and tabwin
 - Place windows on top of stack even when not focused in focus follow mouse
 - Fix opacity for newly mapped window not focused by default (bug #5706)
 - Display an app switcher window per physical monitor (bug #5229)
+- Add new keyboard shortcut to switch between windows of the same application
+- Add new keyboard shortcut to switch between windows of different applications
+  only.
+- Add new option "cycle_apps_only" to switch between regular toplevels only 
+  (avoiding dialogs - This option coupled with the new shortcut allows for
+  faster window selection through keyboard)
 
 4.6.1
 =====
diff --git a/defaults/defaults b/defaults/defaults
index ca36e9b..9b1f892 100644
--- a/defaults/defaults
+++ b/defaults/defaults
@@ -7,6 +7,7 @@ button_offset=0
 button_spacing=0
 click_to_focus=true
 cycle_draw_frame=true
+cycle_apps_only=true
 cycle_hidden=true
 cycle_minimum=true
 cycle_workspaces=false
diff --git a/settings-dialogs/xfwm4-settings.c b/settings-dialogs/xfwm4-settings.c
index f8a0ca4..9cf089a 100644
--- a/settings-dialogs/xfwm4-settings.c
+++ b/settings-dialogs/xfwm4-settings.c
@@ -242,6 +242,8 @@ static const ShortcutTemplate shortcut_values[] = {
   { N_("Cancel"), "cancel_key", NULL },
   { N_("Cycle windows"), "cycle_windows_key", NULL },
   { N_("Cycle windows (Reverse)"), "cycle_reverse_windows_key", NULL },
+  { N_("Switch window for same application"), "switch_window_key", NULL },
+  { N_("Switch application"), "switch_application_key", NULL },
   { N_("Close window"), "close_window_key", NULL },
   { N_("Maximize window horizontally"), "maximize_horiz_key", NULL },
   { N_("Maximize window vertically"), "maximize_vert_key", NULL },
diff --git a/src/client.h b/src/client.h
index 58e0e51..954b74b 100644
--- a/src/client.h
+++ b/src/client.h
@@ -66,12 +66,14 @@
 #define CFG_NOTIFY                      (1<<2)
 #define CFG_FORCE_REDRAW                (1<<3)
 
-#define INCLUDE_HIDDEN                  (1<<0)
-#define INCLUDE_SHADED                  (1<<1)
-#define INCLUDE_ALL_WORKSPACES          (1<<2)
-#define INCLUDE_SKIP_FOCUS              (1<<3)
-#define INCLUDE_SKIP_PAGER              (1<<4)
-#define INCLUDE_SKIP_TASKBAR            (1<<5)
+#define SEARCH_INCLUDE_HIDDEN           (1<<0)
+#define SEARCH_INCLUDE_SHADED           (1<<1)
+#define SEARCH_INCLUDE_ALL_WORKSPACES   (1<<2)
+#define SEARCH_INCLUDE_SKIP_FOCUS       (1<<3)
+#define SEARCH_INCLUDE_SKIP_PAGER       (1<<4)
+#define SEARCH_INCLUDE_SKIP_TASKBAR     (1<<5)
+#define SEARCH_SAME_APPLICATION         (1<<6)
+#define SEARCH_DIFFERENT_APPLICATION    (1<<7)
 
 #define NO_UPDATE_FLAG                  0
 #define UPDATE_BUTTON_GRABS             (1<<0)
diff --git a/src/cycle.c b/src/cycle.c
index a4cfac9..c004574 100644
--- a/src/cycle.c
+++ b/src/cycle.c
@@ -54,9 +54,104 @@ struct _ClientCycleData
     Client *c;
     Tabwin *tabwin;
     Window wireframe;
-    int cycle_range;
 };
 
+#if 0
+static gint
+clientCompareApp (gconstpointer a, gconstpointer b)
+{
+    return !clientSameApplication ((Client *) a, (Client *) b);
+}
+#endif
+
+static guint
+clientGetCycleRange (ScreenInfo *screen_info)
+{
+    guint range;
+
+    g_return_val_if_fail (screen_info != NULL, 0);
+    TRACE ("entering clientGetCycleRange");
+
+    range = 0;
+    if (screen_info->params->cycle_hidden)
+    {
+        range |= SEARCH_INCLUDE_HIDDEN;
+    }
+    if (!screen_info->params->cycle_minimum)
+    {
+        range |= SEARCH_INCLUDE_SKIP_TASKBAR | SEARCH_INCLUDE_SKIP_PAGER;
+    }
+    if (screen_info->params->cycle_workspaces)
+    {
+        range |= SEARCH_INCLUDE_ALL_WORKSPACES;
+    }
+
+    return range;
+}
+
+static GList *
+clientCycleCreateList (Client *c)
+{
+    ScreenInfo *screen_info;
+    Client *c2;
+    guint range;
+    GList *clients;
+    int i;
+
+    g_return_val_if_fail (c, NULL);
+    TRACE ("entering clientCycleCreateList");
+
+    screen_info = c->screen_info;
+    range = clientGetCycleRange (screen_info);
+    clients = NULL;
+
+    for (c2 = c, i = 0; c && i < screen_info->client_count; i++, c2 = c2->next)
+    {
+        if (!clientSelectMask (c2, NULL, range,
+             screen_info->params->cycle_apps_only ? WINDOW_NORMAL : WINDOW_REGULAR_FOCUSABLE))
+            continue;
+#if 0
+        if (screen_info->params->cycle_apps_only)
+        {
+            /*
+             *  For apps only cycling, it's a tad more complicated
+             * - We want only regular windows (no dialog or anything else)
+             * - We don't want a window from the same application to be
+             *   in the list.
+             */
+            if (c2->type != WINDOW_NORMAL)
+                continue;
+            if (g_list_find_custom (clients, c2, clientCompareApp))
+                continue;
+        }
+#endif
+        TRACE ("clientCycleCreateList: adding %s", c2->name);
+        clients = g_list_append (clients, c2);
+    }
+
+    return clients;
+}
+
+static void
+clientCycleFocusAndRaise (Client *c)
+{
+    ScreenInfo *screen_info;
+    DisplayInfo *display_info;
+    Client *sibling;
+
+    g_return_if_fail (c != NULL);
+    TRACE ("entering clientFocusAndRaise");
+
+    screen_info = c->screen_info;
+    display_info = screen_info->display_info;
+
+    sibling = clientGetTransientFor(c);
+    clientRaise (sibling, None);
+    clientShow (sibling, TRUE);
+    clientSetFocus (screen_info, c, myDisplayGetCurrentTime (display_info), NO_FOCUS_FLAG);
+    clientSetLastRaise (c);
+}
+
 static eventFilterStatus
 clientCycleEventFilter (XEvent * xevent, gpointer data)
 {
@@ -197,6 +292,8 @@ clientCycle (Client * c, XKeyEvent * ev)
     ScreenInfo *screen_info;
     DisplayInfo *display_info;
     ClientCycleData passdata;
+    GList *clients, *selected;
+    guint cycle_range;
     gboolean g1, g2;
     int key;
 
@@ -206,6 +303,12 @@ clientCycle (Client * c, XKeyEvent * ev)
     screen_info = c->screen_info;
     display_info = screen_info->display_info;
 
+    clients = clientCycleCreateList (c);
+    if (!clients)
+    {
+        return;
+    }
+
     g1 = myScreenGrabKeyboard (screen_info, ev->time);
     g2 = myScreenGrabPointer (screen_info, LeaveWindowMask,  None, ev->time);
 
@@ -216,65 +319,42 @@ clientCycle (Client * c, XKeyEvent * ev)
         gdk_beep ();
         myScreenUngrabKeyboard (screen_info, CurrentTime);
         myScreenUngrabPointer (screen_info, CurrentTime);
+        g_list_free (clients);
 
         return;
     }
-
-    if (screen_info->params->cycle_hidden)
-    {
-        passdata.cycle_range = INCLUDE_HIDDEN;
-    }
-    else
-    {
-        passdata.cycle_range = 0;
-    }
-    if (!screen_info->params->cycle_minimum)
-    {
-        passdata.cycle_range |= INCLUDE_SKIP_TASKBAR | INCLUDE_SKIP_PAGER;
-    }
-    if (screen_info->params->cycle_workspaces)
-    {
-        passdata.cycle_range |= INCLUDE_ALL_WORKSPACES;
-    }
+    cycle_range = clientGetCycleRange (screen_info);
     key = myScreenGetKeyPressed (screen_info, ev);
+
     if (key == KEY_CYCLE_REVERSE_WINDOWS)
     {
-        passdata.c = clientGetPrevious (c, passdata.cycle_range);
+        selected = g_list_last (clients);
     }
     else
     {
-        passdata.c = clientGetNext (c, passdata.cycle_range);
+        selected = g_list_next (clients);
     }
+    passdata.c = (Client *) selected->data;
     passdata.wireframe = None;
 
-    /* If there is one single client, and if it's eligible for focus, use it */
-    if ((passdata.c == NULL) && (c != clientGetFocus()) &&
-        clientSelectMask (c, passdata.cycle_range, WINDOW_REGULAR_FOCUSABLE))
+    TRACE ("entering cycle loop");
+    if (screen_info->params->cycle_draw_frame)
     {
-        passdata.c = c;
+        passdata.wireframe = wireframeCreate (passdata.c);
     }
-
-    if (passdata.c)
+    passdata.tabwin = tabwinCreate (&clients, selected, screen_info->params->cycle_workspaces);
+    eventFilterPush (display_info->xfilter, clientCycleEventFilter, &passdata);
+    gtk_main ();
+    eventFilterPop (display_info->xfilter);
+    TRACE ("leaving cycle loop");
+    tabwinDestroy (passdata.tabwin);
+    g_free (passdata.tabwin);
+    g_list_free (clients);
+    if (passdata.wireframe)
     {
-        TRACE ("entering cycle loop");
-        if (screen_info->params->cycle_draw_frame)
-        {
-            passdata.wireframe = wireframeCreate (passdata.c);
-        }
-        passdata.tabwin = tabwinCreate (c, passdata.c, passdata.cycle_range,
-                                        screen_info->params->cycle_workspaces);
-        eventFilterPush (display_info->xfilter, clientCycleEventFilter, &passdata);
-        gtk_main ();
-        eventFilterPop (display_info->xfilter);
-        TRACE ("leaving cycle loop");
-        tabwinDestroy (passdata.tabwin);
-        g_free (passdata.tabwin);
-        if (passdata.wireframe)
-        {
-            wireframeDelete (screen_info, passdata.wireframe);
-        }
-        updateXserverTime (display_info);
+        wireframeDelete (screen_info, passdata.wireframe);
     }
+    updateXserverTime (display_info);
 
     if (passdata.c)
     {
@@ -301,11 +381,7 @@ clientCycle (Client * c, XKeyEvent * ev)
             workspaceSwitch (screen_info, workspace, c, FALSE, myDisplayGetCurrentTime (display_info));
         }
 
-        sibling = clientGetTransientFor(c);
-        clientRaise (sibling, None);
-        clientShow (sibling, TRUE);
-        clientSetFocus (screen_info, c, myDisplayGetCurrentTime (display_info), NO_FOCUS_FLAG);
-        clientSetLastRaise (c);
+        clientCycleFocusAndRaise (c);
     }
 
     /*
@@ -315,3 +391,50 @@ clientCycle (Client * c, XKeyEvent * ev)
     myScreenUngrabKeyboard (screen_info, CurrentTime);
     myScreenUngrabPointer (screen_info, CurrentTime);
 }
+
+gboolean
+clientSwitchWindow (void)
+{
+    Client *focus, *new;
+    guint range;
+
+    focus = clientGetFocus();
+    if (!focus)
+    {
+        return FALSE;
+    }
+
+    range = clientGetCycleRange (focus->screen_info);
+    new = clientGetPrevious(focus, range | SEARCH_SAME_APPLICATION, WINDOW_REGULAR_FOCUSABLE);
+    if (new)
+    {
+        clientCycleFocusAndRaise (new);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+gboolean
+clientSwitchApp (void)
+{
+    Client *focus, *new;
+    guint range;
+
+    TRACE ("entering clientSwitchApp");
+
+    focus = clientGetFocus();
+    if (!focus)
+    {
+        return FALSE;
+    }
+
+    range = clientGetCycleRange (focus->screen_info);
+    /* We do not want dialogs, just toplevel app windows here */
+    new = clientGetPrevious(focus, range | SEARCH_DIFFERENT_APPLICATION, WINDOW_NORMAL);
+    if (new)
+    {
+        clientCycleFocusAndRaise (new);
+        return TRUE;
+    }
+    return FALSE;
+}
diff --git a/src/cycle.h b/src/cycle.h
index 37ab51a..8a53bf9 100644
--- a/src/cycle.h
+++ b/src/cycle.h
@@ -36,5 +36,6 @@
 
 void                     clientCycle                            (Client *,
                                                                  XKeyEvent *);
-
+gboolean                 clientCycleWindow                      (void);
+gboolean                 clientCycleApp                         (void);
 #endif /* INC_CYCLE_H */
diff --git a/src/events.c b/src/events.c
index fc8417b..99f56f3 100644
--- a/src/events.c
+++ b/src/events.c
@@ -500,6 +500,16 @@ handleKeyPress (DisplayInfo *display_info, XKeyEvent * ev)
 
     switch (key)
     {
+        case KEY_SWITCH_WINDOW:
+            handled = TRUE;
+            XAllowEvents (display_info->dpy, AsyncKeyboard, ev->time);
+            clientSwitchWindow ();
+            break;
+        case KEY_SWITCH_APPLICATION:
+            handled = TRUE;
+            XAllowEvents (display_info->dpy, AsyncKeyboard, ev->time);
+            clientSwitchApp ();
+            break;
         case KEY_NEXT_WORKSPACE:
             status = EVENT_FILTER_REMOVE;
             handled = TRUE;
@@ -919,19 +929,29 @@ handleButtonPress (DisplayInfo *display_info, XButtonEvent * ev)
         win = ev->subwindow;
         screen_info = c->screen_info;
 
-        if ((ev->button == Button1) && (screen_info->params->easy_click) && (state == screen_info->params->easy_click))
+        if ((ev->button == Button1) && (state) && (state == screen_info->params->easy_click))
         {
             button1Action (c, ev);
         }
-        else if ((ev->button == Button2) && (screen_info->params->easy_click) && (state == screen_info->params->easy_click))
+        else if ((ev->button == Button2) && (state) && (state == screen_info->params->easy_click))
         {
             clientLower (c, None);
         }
-        else if ((ev->button == Button3) && (screen_info->params->easy_click) && (state == screen_info->params->easy_click))
+        else if ((ev->button == Button3) && (state) && (state == screen_info->params->easy_click))
         {
             part = edgeGetPart (c, ev);
             edgeButton (c, part, ev);
         }
+#if 0   /* Binding the alt+scroll wheel to switch app/window is not handy, disabling for now */
+        else if ((ev->button == Button4) && (state) && (state == screen_info->params->easy_click))
+        {
+            clientSwitchWindow ();
+        }
+        else if ((ev->button == Button5) && (state) && (state == screen_info->params->easy_click))
+        {
+            clientSwitchApp ();
+        }
+#endif
         else if (WIN_IS_BUTTON (win))
         {
             if (ev->button <= Button3)
diff --git a/src/focus.c b/src/focus.c
index 5fd0dd0..32dabe5 100644
--- a/src/focus.c
+++ b/src/focus.c
@@ -106,7 +106,7 @@ clientGetTopMostFocusable (ScreenInfo *screen_info, int layer, GList * exclude_l
             }
             else if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
             {
-                if (clientSelectMask (c, 0, WINDOW_REGULAR_FOCUSABLE))
+                if (clientSelectMask (c, NULL, 0, WINDOW_REGULAR_FOCUSABLE))
                 {
                     top_client.prefered = c;
                 }
@@ -246,30 +246,36 @@ clientFocusNew(Client * c)
 }
 
 gboolean
-clientSelectMask (Client * c, int mask, int type)
+clientSelectMask (Client * c, Client *other, guint mask, guint type)
 {
     g_return_val_if_fail (c != NULL, FALSE);
     TRACE ("entering clientSelectMask");
 
-    if ((!clientAcceptFocus (c)) && !(mask & INCLUDE_SKIP_FOCUS))
+    if ((mask & SEARCH_SAME_APPLICATION) && !clientSameApplication (c, other))
     {
         return FALSE;
     }
-    if (FLAG_TEST (c->flags, CLIENT_FLAG_ICONIFIED) && !(mask & INCLUDE_HIDDEN))
+    if ((mask & SEARCH_DIFFERENT_APPLICATION) && clientSameApplication (c, other))
     {
         return FALSE;
     }
-    if (FLAG_TEST (c->flags, CLIENT_FLAG_SKIP_PAGER)
-        && !(mask & INCLUDE_SKIP_PAGER))
+    if (!(mask & SEARCH_INCLUDE_SKIP_FOCUS) && !clientAcceptFocus (c))
     {
         return FALSE;
     }
-    if (FLAG_TEST (c->flags, CLIENT_FLAG_SKIP_TASKBAR)
-        && !(mask & INCLUDE_SKIP_TASKBAR))
+    if (!(mask & SEARCH_INCLUDE_HIDDEN) && FLAG_TEST (c->flags, CLIENT_FLAG_ICONIFIED))
     {
         return FALSE;
     }
-    if ((c->win_workspace != c->screen_info->current_ws) && !(mask & INCLUDE_ALL_WORKSPACES))
+    if (!(mask & SEARCH_INCLUDE_SKIP_PAGER) && FLAG_TEST (c->flags, CLIENT_FLAG_SKIP_PAGER))
+    {
+        return FALSE;
+    }
+    if (!(mask & SEARCH_INCLUDE_SKIP_TASKBAR) && FLAG_TEST (c->flags, CLIENT_FLAG_SKIP_TASKBAR))
+    {
+        return FALSE;
+    }
+    if (!(mask & SEARCH_INCLUDE_ALL_WORKSPACES) && (c->win_workspace != c->screen_info->current_ws))
     {
         return FALSE;
     }
@@ -282,7 +288,7 @@ clientSelectMask (Client * c, int mask, int type)
 }
 
 Client *
-clientGetNext (Client * c, int mask)
+clientGetNext (Client * c, guint mask, guint type)
 {
     Client *c2;
     unsigned int i;
@@ -295,7 +301,7 @@ clientGetNext (Client * c, int mask)
         for (c2 = c->next, i = 0; (c2) && (i < screen_info->client_count - 1);
             c2 = c2->next, i++)
         {
-            if (clientSelectMask (c2, mask, WINDOW_REGULAR_FOCUSABLE))
+            if (clientSelectMask (c2, c, mask, type))
             {
                 return c2;
             }
@@ -305,7 +311,7 @@ clientGetNext (Client * c, int mask)
 }
 
 Client *
-clientGetPrevious (Client * c, int mask)
+clientGetPrevious (Client * c, guint mask, guint type)
 {
     Client *c2;
     unsigned int i;
@@ -318,7 +324,7 @@ clientGetPrevious (Client * c, int mask)
         for (c2 = c->prev, i = 0; (c2) && (i < screen_info->client_count);
             c2 = c2->prev, i++)
         {
-            if (clientSelectMask (c2, mask, WINDOW_REGULAR_FOCUSABLE))
+            if (clientSelectMask (c2, c, mask, type))
             {
                 return c2;
             }
diff --git a/src/focus.h b/src/focus.h
index bc130b6..7a3df18 100644
--- a/src/focus.h
+++ b/src/focus.h
@@ -45,12 +45,15 @@ void                     clientFocusTop                         (ScreenInfo *,
                                                                  guint32);
 gboolean                 clientFocusNew                         (Client *);
 gboolean                 clientSelectMask                       (Client *,
-                                                                 int,
-                                                                 int);
+                                                                 Client *,
+                                                                 guint,
+                                                                 guint);
 Client                  *clientGetNext                          (Client *,
-                                                                 int);
+                                                                 guint,
+                                                                 guint);
 Client                  *clientGetPrevious                      (Client *,
-                                                                 int);
+                                                                 guint,
+                                                                 guint);
 void                     clientPassFocus                        (ScreenInfo *,
                                                                  Client *,
                                                                  GList *);
diff --git a/src/netwm.c b/src/netwm.c
index 1f127ae..276a8a8 100644
--- a/src/netwm.c
+++ b/src/netwm.c
@@ -792,9 +792,6 @@ clientGetNetWmType (Client * c)
             case WIN_LAYER_DOCK:
                 c->type_atom = display_info->atoms[NET_WM_WINDOW_TYPE_DOCK];
                 break;
-            case WIN_LAYER_NORMAL:
-                c->type_atom = display_info->atoms[NET_WM_WINDOW_TYPE_NORMAL];
-                break;
             default:
                 if (c->transient_for != None)
                 {
diff --git a/src/settings.c b/src/settings.c
index a837235..a1129ae 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -602,6 +602,8 @@ loadKeyBindings (ScreenInfo *screen_info)
     parseShortcut (screen_info, KEY_SHADE_WINDOW, "shade_window_key", shortcuts);
     parseShortcut (screen_info, KEY_SHOW_DESKTOP, "show_desktop_key", shortcuts);
     parseShortcut (screen_info, KEY_STICK_WINDOW, "stick_window_key", shortcuts);
+    parseShortcut (screen_info, KEY_SWITCH_APPLICATION, "switch_application_key", shortcuts);
+    parseShortcut (screen_info, KEY_SWITCH_WINDOW, "switch_window_key", shortcuts);
     parseShortcut (screen_info, KEY_TOGGLE_ABOVE, "above_key", shortcuts);
     parseShortcut (screen_info, KEY_TOGGLE_FULLSCREEN, "fullscreen_key", shortcuts);
     parseShortcut (screen_info, KEY_UP_WORKSPACE, "up_workspace_key", shortcuts);
@@ -661,6 +663,7 @@ loadSettings (ScreenInfo *screen_info)
         {"button_spacing", NULL, G_TYPE_INT, TRUE},
         {"click_to_focus", NULL, G_TYPE_BOOLEAN, TRUE},
         {"focus_delay", NULL, G_TYPE_INT, TRUE},
+        {"cycle_apps_only", NULL, G_TYPE_BOOLEAN, TRUE},
         {"cycle_draw_frame", NULL, G_TYPE_BOOLEAN, TRUE},
         {"cycle_hidden", NULL, G_TYPE_BOOLEAN, TRUE},
         {"cycle_minimum", NULL, G_TYPE_BOOLEAN, TRUE},
@@ -742,6 +745,8 @@ loadSettings (ScreenInfo *screen_info)
         getBoolValue ("box_move", rc);
     screen_info->params->click_to_focus =
         getBoolValue ("click_to_focus", rc);
+    screen_info->params->cycle_apps_only =
+        getBoolValue ("cycle_apps_only", rc);
     screen_info->params->cycle_minimum =
         getBoolValue ("cycle_minimum", rc);
     screen_info->params->cycle_draw_frame =
diff --git a/src/settings.h b/src/settings.h
index 2c1c431..db1995e 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -97,6 +97,8 @@ enum
     KEY_SHADE_WINDOW,
     KEY_SHOW_DESKTOP,
     KEY_STICK_WINDOW,
+    KEY_SWITCH_APPLICATION,
+    KEY_SWITCH_WINDOW,
     KEY_TOGGLE_ABOVE,
     KEY_TOGGLE_FULLSCREEN,
     KEY_UP_WORKSPACE,
@@ -194,6 +196,7 @@ struct _XfwmParams
     gboolean box_move;
     gboolean box_resize;
     gboolean click_to_focus;
+    gboolean cycle_apps_only;
     gboolean cycle_draw_frame;
     gboolean cycle_hidden;
     gboolean cycle_minimum;
diff --git a/src/stacking.c b/src/stacking.c
index a2a0e71..3b3bcc3 100644
--- a/src/stacking.c
+++ b/src/stacking.c
@@ -264,7 +264,7 @@ clientAtPosition (ScreenInfo *screen_info, int x, int y, GList * exclude_list)
         if ((frameX (c2) <= x) && (frameX (c2) + frameWidth (c2) >= x)
             && (frameY (c2) <= y) && (frameY (c2) + frameHeight (c2) >= y))
         {
-            if (clientSelectMask (c2, INCLUDE_SKIP_PAGER | INCLUDE_SKIP_TASKBAR, WINDOW_REGULAR_FOCUSABLE)
+            if (clientSelectMask (c2, NULL, SEARCH_INCLUDE_SKIP_PAGER | SEARCH_INCLUDE_SKIP_TASKBAR, WINDOW_REGULAR_FOCUSABLE)
                 && !g_list_find (exclude_list, (gconstpointer) c2))
             {
                 c = c2;
diff --git a/src/tabwin.c b/src/tabwin.c
index 07652b4..eac619f 100644
--- a/src/tabwin.c
+++ b/src/tabwin.c
@@ -211,35 +211,6 @@ createWindowIcon (Client *c)
     return icon;
 }
 
-static GList *
-createClientlist (Tabwin *tabwin, Client *clients, Client *selected, unsigned int cycle_range)
-{
-    ScreenInfo *screen_info;
-    Client *c;
-    int i;
-
-    g_return_val_if_fail (clients, NULL);
-    TRACE ("entering createClientlist");
-
-    screen_info = clients->screen_info;
-    for (c = clients, i = 0; c && i < screen_info->client_count; i++, c = c->next)
-    {
-        if (!clientSelectMask (c, cycle_range, WINDOW_REGULAR_FOCUSABLE))
-            continue;
-        TRACE ("createClientlist: adding %s", c->name);
-        tabwin->clients = g_list_append (tabwin->clients, c);
-        tabwin->client_count++;
-        if (c == selected)
-        {
-            TRACE ("createClientlist: selected %s", c->name);
-            /* Use last entry added to the list */
-            tabwin->selected = g_list_last (tabwin->clients);
-        }
-    }
-
-    return tabwin->clients;
-}
-
 static GtkWidget *
 createWindowlist (ScreenInfo *screen_info, TabwinWidget *tbw)
 {
@@ -267,7 +238,7 @@ createWindowlist (ScreenInfo *screen_info, TabwinWidget *tbw)
     windowlist = gtk_table_new (tbw->grid_rows, tbw->grid_cols, FALSE);
 
     /* pack the client icons */
-    for (clients = t->clients; clients; clients = g_list_next (clients))
+    for (clients = *t->clients; clients; clients = g_list_next (clients))
     {
         c = (Client *) clients->data;
         TRACE ("createWindowlist: adding %s", c->name);
@@ -412,23 +383,25 @@ tabwinCreateWidget (Tabwin *tabwin, ScreenInfo *screen_info, gint monitor_num)
 }
 
 Tabwin *
-tabwinCreate (Client *clients, Client *selected, unsigned int cycle_range, gboolean display_workspace)
+tabwinCreate (GList **clients, GList *selected, gboolean display_workspace)
 {
     ScreenInfo *screen_info;
+    Client *c;
     Tabwin *tabwin;
     int num_monitors, i;
 
     g_return_val_if_fail (selected, NULL);
     g_return_val_if_fail (clients, NULL);
+    g_return_val_if_fail (*clients, NULL);
 
     TRACE ("entering tabwinCreate");
-
+    c = (Client *) selected->data;
     tabwin = g_new0 (Tabwin, 1);
-    screen_info = selected->screen_info;
+    screen_info = c->screen_info;
     tabwin->display_workspace = display_workspace;
-    tabwin->clients = NULL;
-    tabwin->client_count = 0;
-    createClientlist (tabwin, clients, selected, cycle_range);
+    tabwin->clients = clients;
+    tabwin->selected = selected;
+    tabwin->client_count = g_list_length (*clients);
     tabwin->tabwins = NULL;
     num_monitors = gdk_screen_get_n_monitors (screen_info->gscr);
     for (i = 0; i < num_monitors; i++)
@@ -464,13 +437,13 @@ tabwinRemoveClient (Tabwin *t, Client *c)
     g_return_val_if_fail (c != NULL, NULL);
     TRACE ("entering tabwinRemoveClient");
 
-    if (!t->clients)
+    if (!*t->clients)
     {
         return NULL;
     }
 
     /* First, remove the client from our own client list */
-    for (clients = t->clients; clients; clients = g_list_next (clients))
+    for (clients = *t->clients; clients; clients = g_list_next (clients))
     {
         if (clients->data == c)
         {
@@ -478,7 +451,7 @@ tabwinRemoveClient (Tabwin *t, Client *c)
             {
                 tabwinSelectNext (t);
             }
-            t->clients = g_list_delete_link (t->clients, clients);
+            *t->clients = g_list_delete_link (*t->clients, clients);
             break;
         }
     }
@@ -515,7 +488,7 @@ tabwinSelectNext (Tabwin *t)
     next = g_list_next(t->selected);
     if (!next)
     {
-        next = t->clients;
+        next = *t->clients;
         g_return_val_if_fail (next != NULL, NULL);
     }
     t->selected = next;
@@ -550,7 +523,7 @@ tabwinSelectPrev (Tabwin *t)
     prev = g_list_previous (t->selected);
     if (!prev)
     {
-        prev = g_list_last (t->clients);
+        prev = g_list_last (*t->clients);
         g_return_val_if_fail (prev != NULL, NULL);
     }
     t->selected = prev;
@@ -574,12 +547,15 @@ tabwinSelectPrev (Tabwin *t)
 Client *
 tabwinGetHead (Tabwin *t)
 {
+    GList *head;
+
     g_return_val_if_fail (t != NULL, NULL);
     TRACE ("entering tabwinGetHead");
 
-    if (t->clients)
+    head = *t->clients;
+    if (head)
     {
-        return (Client *)  t->clients->data;
+        return (Client *)  head->data;
     }
 
     return NULL;
@@ -603,5 +579,4 @@ tabwinDestroy (Tabwin *t)
         g_free (tbw);
     }
     g_list_free (t->tabwins);
-    g_list_free (t->clients);
 }
diff --git a/src/tabwin.h b/src/tabwin.h
index 8e9d6cf..32d70eb 100644
--- a/src/tabwin.h
+++ b/src/tabwin.h
@@ -37,7 +37,7 @@ typedef struct _TabwinWidget TabwinWidget;
 struct _Tabwin
 {
     GList *tabwins;
-    GList *clients;
+    GList **clients;
     GList *selected;
     guint client_count;
     gboolean display_workspace;
@@ -63,9 +63,8 @@ struct _TabwinWidget
     gint grid_rows;
 };
 
-Tabwin                  *tabwinCreate                           (Client *,
-                                                                 Client *,
-                                                                 unsigned int,
+Tabwin                  *tabwinCreate                           (GList **,
+                                                                 GList *,
                                                                  gboolean);
 Client                  *tabwinGetSelected                      (Tabwin *);
 Client                  *tabwinSelectNext                       (Tabwin *);
diff --git a/src/transients.c b/src/transients.c
index 2604b5c..9b46946 100644
--- a/src/transients.c
+++ b/src/transients.c
@@ -98,6 +98,21 @@ clientSameGroup (Client * c1, Client * c2)
 }
 
 gboolean
+clientSameLeader (Client * c1, Client * c2)
+{
+    g_return_val_if_fail (c1 != NULL, FALSE);
+    g_return_val_if_fail (c2 != NULL, FALSE);
+
+    TRACE ("entering clientSameLeader");
+
+    return ((c1 != c2) &&
+            (((c1->client_leader != None) &&
+              (c1->client_leader == c2->client_leader)) ||
+             (c1->client_leader == c2->window) ||
+             (c2->client_leader == c1->window)));
+}
+
+gboolean
 clientIsTransientFor (Client * c1, Client * c2)
 {
     g_return_val_if_fail (c1 != NULL, FALSE);
@@ -416,3 +431,18 @@ clientCheckTransientWindow (Client *c, Window w)
     g_list_free (transients);
     return TRUE;
 }
+
+gboolean
+clientSameApplication (Client *c1, Client *c2)
+{
+    g_return_val_if_fail (c1 != NULL, FALSE);
+    g_return_val_if_fail (c2 != NULL, FALSE);
+
+    return (clientIsTransientOrModalFor (c1, c2) ||
+            clientIsTransientOrModalFor (c2, c1) ||
+            clientSameGroup (c1, c2) ||
+            clientSameLeader (c1, c2) ||
+            (c1->pid != 0 && c1->pid == c2->pid &&
+             c1->hostname && c2->hostname &&
+             !g_strcasecmp (c1->hostname, c2->hostname)));
+}
diff --git a/src/transients.h b/src/transients.h
index 29f6eff..0f27025 100644
--- a/src/transients.h
+++ b/src/transients.h
@@ -37,6 +37,10 @@ gboolean                 clientIsTransientOrModal               (Client *);
 gboolean                 clientIsValidTransientOrModal          (Client *);
 gboolean                 clientSameGroup                        (Client *,
                                                                  Client *);
+gboolean                 clientSameLeader                        (Client *,
+                                                                 Client *);
+gboolean                 clientSameApplication                  (Client *,
+                                                                 Client *);
 gboolean                 clientIsTransientFor                   (Client *,
                                                                  Client *);
 gboolean                 clientIsModalFor                       (Client *,
@@ -54,4 +58,6 @@ GList                   *clientListTransient                    (Client *);
 GList                   *clientListTransientOrModal             (Client *);
 gboolean                 clientCheckTransientWindow             (Client *,
                                                                  Window);
+gboolean                 clientSameApplication                  (Client *,
+                                                                 Client *);
 #endif /* INC_TRANSIENTS_H */
diff --git a/src/workspaces.c b/src/workspaces.c
index 85415b7..65f4df7 100644
--- a/src/workspaces.c
+++ b/src/workspaces.c
@@ -352,7 +352,7 @@ workspaceSwitch (ScreenInfo *screen_info, int new_ws, Client * c2, gboolean upda
 
         if (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
         {
-            if ((!new_focus) && (c == previous) && clientSelectMask (c, 0, WINDOW_REGULAR_FOCUSABLE))
+            if ((!new_focus) && (c == previous) && clientSelectMask (c, NULL, 0, WINDOW_REGULAR_FOCUSABLE))
             {
                 new_focus = c;
             }



More information about the Xfce4-commits mailing list