- if (!first) first = focus_client;
-
- if (linear) list = client_list;
- else list = focus_order[screen_desktop];
-
- start = it = g_list_find(list, focus_client);
- if (!start) /* switched desktops or something? */
- start = it = forward ? g_list_last(list) : g_list_first(list);
- if (!start) goto done_cycle;
-
- do {
- if (forward) {
- it = it->next;
- if (it == NULL) it = list;
- } else {
- it = it->prev;
- if (it == NULL) it = g_list_last(list);
- }
- ft = client_focus_target(it->data);
- if (ft == it->data && focus_client != ft && client_focusable(ft)) {
- if (client_focus(ft)) {
- noreorder++; /* avoid reordering the focus_order */
- break;
- }
- }
- } while (it != start);
- return;
-
-done_cycle:
- t = NULL;
- first = NULL;
- g_list_free(order);
- order = NULL;
+ return FALSE;
+}
+
+gboolean focus_valid_target(ObClient *ft,
+ gboolean helper_windows,
+ gboolean iconic_windows,
+ gboolean all_desktops,
+ gboolean dock_windows,
+ gboolean desktop_windows)
+{
+ gboolean ok = FALSE;
+
+ /* it's on this desktop unless you want all desktops.
+
+ do this check first because it will usually filter out the most
+ windows */
+ ok = (all_desktops || ft->desktop == screen_desktop ||
+ ft->desktop == DESKTOP_ALL);
+
+ /* the window can receive focus somehow */
+ ok = ok && (ft->can_focus || ft->focus_notify);
+
+ /* the window is not iconic, or we're allowed to go to iconic ones */
+ ok = ok && (iconic_windows || !ft->iconic);
+
+ /* it's the right type of window */
+ if (dock_windows || desktop_windows)
+ ok = ok && ((dock_windows && ft->type == OB_CLIENT_TYPE_DOCK) ||
+ (desktop_windows && ft->type == OB_CLIENT_TYPE_DESKTOP));
+ /* modal windows are important and can always get focus if they are
+ visible and stuff, so don't change 'ok' based on their type */
+ else if (!ft->modal)
+ /* normal non-helper windows are valid targets */
+ ok = ok &&
+ ((client_normal(ft) && !client_helper(ft))
+ ||
+ /* helper windows are valid targets if... */
+ (client_helper(ft) &&
+ /* ...a window in its group already has focus and we want to
+ include helper windows ... */
+ ((focus_client && ft->group == focus_client->group &&
+ helper_windows) ||
+ /* ... or if there are no other windows in its group
+ that can be focused instead */
+ !focus_target_has_siblings(ft, iconic_windows, all_desktops))));
+
+ /* it's not set to skip the taskbar (but this only applies to normal typed
+ windows, and is overridden if the window is modal) */
+ ok = ok && (ft->type != OB_CLIENT_TYPE_NORMAL ||
+ ft->modal ||
+ !ft->skip_taskbar);
+
+ /* it's not going to just send focus off somewhere else (modal window),
+ unless that modal window is not one of our valid targets, then let
+ you choose this window and bring the modal one here */
+ {
+ ObClient *cft = client_focus_target(ft);
+ ok = ok && (ft == cft || !focus_valid_target(cft,
+ TRUE,
+ iconic_windows,
+ all_desktops,
+ dock_windows,
+ desktop_windows));
+ }
+
+ return ok;