summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS9
-rw-r--r--defaults/defaults1
-rw-r--r--settings-dialogs/xfwm4-settings.c2
-rw-r--r--src/client.h14
-rw-r--r--src/cycle.c221
-rw-r--r--src/cycle.h3
-rw-r--r--src/events.c26
-rw-r--r--src/focus.c32
-rw-r--r--src/focus.h11
-rw-r--r--src/netwm.c3
-rw-r--r--src/settings.c5
-rw-r--r--src/settings.h3
-rw-r--r--src/stacking.c2
-rw-r--r--src/tabwin.c63
-rw-r--r--src/tabwin.h7
-rw-r--r--src/transients.c30
-rw-r--r--src/transients.h6
-rw-r--r--src/workspaces.c2
18 files changed, 310 insertions, 130 deletions
diff --git a/NEWS b/NEWS
index c5ea73335..dcdc59c69 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@cliffjolly.com>)
+- Implement prelinminary support for snap on resize (patch by Clifford Jolly
+ <cliff@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 ca36e9b09..9b1f89293 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 f8a0ca45a..9cf089a3d 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 58e0e51a9..954b74b1c 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 a4cfac978..c00457421 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 37ab51a9d..8a53bf9fb 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 fc8417b18..99f56f33f 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 5fd0dd09c..32dabe570 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 bc130b69b..7a3df1856 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 1f127ae1b..276a8a826 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 a83723508..a1129aec9 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 2c1c4316d..db1995e0b 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 a2a0e7123..3b3bcc3b5 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 07652b442..eac619f3f 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 8e9d6cf33..32d70eb57 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 2604b5c6c..9b4694656 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 29f6effd1..0f270258d 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 85415b7a4..65f4df775 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;
}