- for (it = focus_order; it; it = g_list_next(it))
- if (allow_refocus || it->data != old) {
- ObClient *c = it->data;
- /* fallback focus to a window if:
- 1. it is actually focusable, cuz if it's not then we're sending
- focus off to nothing. this includes if it is visible right now
- 2. it is on the current desktop. this ignores omnipresent
- windows, which are problematic in their own rite.
- 3. it is a normal type window, don't fall back onto a dock or
- a splashscreen or a desktop window (save the desktop as a
- backup fallback though)
- */
- if (client_can_focus(c))
- {
- if (c->desktop == screen_desktop && client_normal(c)) {
- ob_debug_type(OB_DEBUG_FOCUS, "found in focus order\n");
- return it->data;
- } else if (c->type == OB_CLIENT_TYPE_DESKTOP &&
- desktop == NULL)
- desktop = c;
- }
- }
-
- /* as a last resort fallback to the desktop window if there is one.
- (if there's more than one, then the one most recently focused.)
- */
- ob_debug_type(OB_DEBUG_FOCUS, "found desktop: \n", !!desktop);
- return desktop;
-}
-
-ObClient* focus_fallback(gboolean allow_refocus)
-{
- ObClient *new;
- ObClient *old;
-
- old = focus_client;
- new = focus_fallback_target(allow_refocus, focus_client);
-
- /* send focus somewhere if it is moving or if it was NULL before,
- in which case it may not even be on the screen */
- if (!old || new != old) {
- /* unfocus any focused clients.. they can be focused by Pointer events
- and such, and then when we try focus them, we won't get a FocusIn
- event at all for them. */
- focus_nothing();
-
- if (new) {
- client_focus(new);
- /* remember that we tried to send focus here */
- focus_tried = new;
- }
- }
-
- return new;
-}
-
-void focus_nothing()
-{
- /* Install our own colormap */
- if (focus_client != NULL) {
- screen_install_colormap(focus_client, FALSE);
- screen_install_colormap(NULL, TRUE);
- }
-
- focus_client = NULL;
- focus_tried = NULL; /* focus isn't "trying" to go anywhere now */
-
- /* when nothing will be focused, send focus to the backup target */
- XSetInputFocus(ob_display, screen_support_win, RevertToPointerRoot,
- event_curtime);
-}
-
-static gchar *popup_get_name(ObClient *c, ObClient **nametarget)
-{
- ObClient *p;
- gchar *title = NULL;
- const gchar *desk = NULL;
- gchar *ret;
-
- /* find our highest direct parent, including non-normal windows */
- for (p = c; p->transient_for && p->transient_for != OB_TRAN_GROUP;
- p = p->transient_for);
-
- if (c->desktop != DESKTOP_ALL && c->desktop != screen_desktop)
- desk = screen_desktop_names[c->desktop];
-
- /* use the transient's parent's title/icon if we don't have one */
- if (p != c && !strcmp("", (c->iconic ? c->icon_title : c->title)))
- title = g_strdup(p->iconic ? p->icon_title : p->title);
-
- if (title == NULL)
- title = g_strdup(c->iconic ? c->icon_title : c->title);
-
- if (desk)
- ret = g_strdup_printf("%s [%s]", title, desk);
- else {
- ret = title;
- title = NULL;
- }
- g_free(title);
-
- /* set this only if we're returning true and they asked for it */
- if (ret && nametarget) *nametarget = p;
- return ret;
-}
-
-static void popup_cycle(ObClient *c, gboolean show,
- gboolean all_desktops, gboolean dock_windows,
- gboolean desktop_windows)
-{
- gchar *showtext = NULL;
- ObClient *showtarget;
-
- if (!show) {
- icon_popup_hide(focus_cycle_popup);
- return;
- }
-
- /* do this stuff only when the dialog is first showing */
- if (!focus_cycle_popup->popup->mapped &&
- !focus_cycle_popup->popup->delay_mapped)
- {
- Rect *a;
- gchar **names;
- GList *targets = NULL, *it;
- gint n = 0, i;
-
- /* position the popup */
- a = screen_physical_area_monitor(0);
- icon_popup_position(focus_cycle_popup, CenterGravity,
- a->x + a->width / 2, a->y + a->height / 2);
- icon_popup_height(focus_cycle_popup, POPUP_HEIGHT);
- icon_popup_min_width(focus_cycle_popup, POPUP_WIDTH);
- icon_popup_max_width(focus_cycle_popup,
- MAX(a->width/3, POPUP_WIDTH));
-
-
- /* make its width to be the width of all the possible titles */
-
- /* build a list of all the valid focus targets */
- for (it = focus_order; it; it = g_list_next(it)) {
- ObClient *ft = it->data;
- if (valid_focus_target(ft, all_desktops, dock_windows
- , desktop_windows))
- {
- targets = g_list_prepend(targets, ft);
- ++n;
- }
- }
- /* make it null terminated so we can use g_strfreev */
- names = g_new(char*, n+1);
- for (it = targets, i = 0; it; it = g_list_next(it), ++i) {
- ObClient *ft = it->data, *t;
- names[i] = popup_get_name(ft, &t);
-
- /* little optimization.. save this text and client, so we dont
- have to get it again */
- if (ft == c) {
- showtext = g_strdup(names[i]);
- showtarget = t;
- }
- }
- names[n] = NULL;
-
- icon_popup_text_width_to_strings(focus_cycle_popup, names, n);
- g_strfreev(names);
- }
-
-
- if (!showtext) showtext = popup_get_name(c, &showtarget);
- icon_popup_show(focus_cycle_popup, showtext,
- client_icon(showtarget, 48, 48));
- g_free(showtext);
-}
-
-static void focus_cycle_destroy_notify(ObClient *client, gpointer data)
-{
- /* end cycling if the target disappears. CurrentTime is fine, time won't
- be used
- */
- if (focus_cycle_target == client)
- focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE);
-}
-
-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);
-
- /* kill enter events cause by this unmapping */
- event_ignore_queued_enters();
- } else {
- /*
- if (focus_cycle_target)
- frame_adjust_focus(focus_cycle_target->frame, FALSE);
- frame_adjust_focus(focus_cycle_target->frame, TRUE);