diff options
-rw-r--r-- | NEWS | 9 | ||||
-rw-r--r-- | defaults/defaults | 1 | ||||
-rw-r--r-- | settings-dialogs/xfwm4-settings.c | 2 | ||||
-rw-r--r-- | src/client.h | 14 | ||||
-rw-r--r-- | src/cycle.c | 221 | ||||
-rw-r--r-- | src/cycle.h | 3 | ||||
-rw-r--r-- | src/events.c | 26 | ||||
-rw-r--r-- | src/focus.c | 32 | ||||
-rw-r--r-- | src/focus.h | 11 | ||||
-rw-r--r-- | src/netwm.c | 3 | ||||
-rw-r--r-- | src/settings.c | 5 | ||||
-rw-r--r-- | src/settings.h | 3 | ||||
-rw-r--r-- | src/stacking.c | 2 | ||||
-rw-r--r-- | src/tabwin.c | 63 | ||||
-rw-r--r-- | src/tabwin.h | 7 | ||||
-rw-r--r-- | src/transients.c | 30 | ||||
-rw-r--r-- | src/transients.h | 6 | ||||
-rw-r--r-- | src/workspaces.c | 2 |
18 files changed, 310 insertions, 130 deletions
@@ -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; } |