2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2009 Kim Woelders
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies of the Software, its documentation and marketing & publicity
14 * materials, and acknowledgment shall be given in the documentation, materials
15 * and software packages that this Software was used.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 #include "desktops.h" /* FIXME - Should not be here */
37 #define EwinListFocusRaise(ewin) EobjListFocusRaise(EoObj(ewin))
39 static char focus_inhibit = 1;
40 static char focus_is_set = 0;
41 static char click_pending_update_grabs = 0;
42 static int focus_pending_why = 0;
43 static EWin *focus_pending_ewin = NULL;
44 static EWin *focus_pending_new = NULL;
45 static EWin *focus_pending_raise = NULL;
46 static Timer *focus_timer_autoraise = NULL;
53 if (focus_inhibit > 0)
61 if (EDebug(EDBUG_TYPE_FOCUS))
62 Eprintf("FocusEnable inhibit=%d\n", focus_inhibit);
66 * Return !0 if it is OK to focus ewin.
69 FocusEwinValid(EWin * ewin, int want_on_screen, int click, int want_visible)
75 Eprintf("FocusEwinValid %#lx %s: st=%d sh=%d inh=%d cl=%d(%d) vis=%d(%d)\n",
76 EwinGetClientXwin(ewin), EwinGetTitle(ewin),
77 ewin->state.state, EoIsShown(ewin), ewin->state.inhibit_focus,
78 click, ewin->props.focusclick, want_visible, ewin->state.visibility);
81 if (ewin->state.inhibit_focus)
84 if (!EwinIsMapped(ewin) || !EoIsShown(ewin))
87 if (ewin->props.focusclick && !click)
90 if (want_visible && ewin->state.visibility == VisibilityFullyObscured)
93 return !want_on_screen || EwinIsOnScreen(ewin);
97 * Return the ewin to focus after entering area or losing focused window.
100 FocusEwinSelect(void)
102 EWin *const *lst, *ewin;
105 switch (Conf.focus.mode)
108 case MODE_FOCUS_POINTER:
109 ewin = GetEwinPointerInClient();
110 if (ewin && !FocusEwinValid(ewin, 1, 0, 0))
114 case MODE_FOCUS_SLOPPY:
115 ewin = GetEwinPointerInClient();
116 if (ewin && FocusEwinValid(ewin, 1, 0, 0))
120 case MODE_FOCUS_CLICK:
125 lst = EwinListFocusGet(&num);
126 for (i = 0; i < num; i++)
128 if (!FocusEwinValid(lst[i], 1, 0, 0) ||
129 lst[i]->props.skip_focuslist)
141 AutoraiseTimeout(void *data)
143 EWin *ewin = (EWin *) data;
145 if (Conf.focus.mode == MODE_FOCUS_CLICK)
148 if (EwinFindByPtr(ewin)) /* May be gone */
152 focus_timer_autoraise = NULL;
157 FocusRaisePending(void)
159 EWin *ewin = focus_pending_raise;
162 /* The focusing cycle ends when no more modifiers are depressed */
164 EQueryPointer(NULL, NULL, NULL, NULL, &mask);
165 if ((mask & Mode.masks.mod_key_mask) != 0)
168 if (EwinFindByPtr(ewin)) /* May be gone */
169 EwinListFocusRaise(ewin);
171 GrabKeyboardRelease();
173 focus_pending_raise = NULL;
177 * dir > 0: Focus previously focused window
178 * else : Focus least recently focused window
181 FocusCycleEwin(int dir)
187 lst = EwinListFocusGet(&num);
191 dir = (dir > 0) ? 1 : -1;
193 for (j = 0; j < num; j++)
195 if (lst[j] == Mode.focuswin)
198 for (i = 1; i < num; i++)
200 ewin = lst[(j + i * dir + num) % num];
201 if (!FocusEwinValid(ewin, 1, 0, 0) || ewin->props.skip_focuslist)
203 FocusToEWin(ewin, FOCUS_PREV);
209 ClickGrabsSet(EWin * ewin)
213 if ((Conf.focus.clickraises && !EwinListStackIsRaised(ewin)) ||
214 (!ewin->state.active && !ewin->state.inhibit_focus))
219 if (!ewin->state.click_grab_isset)
221 GrabButtonSet(AnyButton, AnyModifier, EwinGetContainerWin(ewin),
222 ButtonPressMask, ECSR_PGRAB, 1);
223 if (EDebug(EDBUG_TYPE_GRABS))
224 Eprintf("ClickGrabsSet: %#lx set %s\n",
225 EwinGetClientXwin(ewin), EwinGetTitle(ewin));
226 ewin->state.click_grab_isset = 1;
231 if (ewin->state.click_grab_isset)
233 GrabButtonRelease(AnyButton, AnyModifier,
234 EwinGetContainerWin(ewin));
235 if (EDebug(EDBUG_TYPE_GRABS))
236 Eprintf("ClickGrabsSet: %#lx unset %s\n",
237 EwinGetClientXwin(ewin), EwinGetTitle(ewin));
238 ewin->state.click_grab_isset = 0;
244 FocusEwinSetActive(EWin * ewin, int active)
246 if (ewin->state.active == (unsigned)active)
249 ewin->state.active = active;
250 EwinBorderUpdateState(ewin);
251 EwinUpdateOpacity(ewin);
253 if (active && ewin->state.attention)
255 ewin->state.attention = 0;
256 HintsSetWindowState(ewin);
261 doClickGrabsUpdate(void)
263 EWin *const *lst, *ewin;
266 lst = EwinListGetAll(&num);
267 for (i = 0; i < num; i++)
272 click_pending_update_grabs = 0;
276 ClickGrabsUpdate(void)
278 click_pending_update_grabs = 1;
282 doFocusToEwin(EWin * ewin, int why)
285 int do_raise = 0, do_warp = 0;
290 if (EDebug(EDBUG_TYPE_FOCUS))
291 Eprintf("doFocusToEWin %#lx %s why=%d\n",
292 (ewin) ? EwinGetClientXwin(ewin) : 0,
293 (ewin) ? EwinGetTitle(ewin) : "None", why);
299 if (Conf.focus.raise_on_next)
301 if (Conf.focus.warp_on_next)
307 case FOCUS_LEAVE: /* Unused */
309 if (ewin && ewin == Mode.focuswin)
311 if (ewin == NULL) /* Unfocus */
313 if (!FocusEwinValid(ewin, 1, why == FOCUS_CLICK, 0))
318 case FOCUS_DESK_ENTER:
319 ewin = FocusEwinSelect();
322 case FOCUS_DESK_LEAVE:
326 if (ewin == Mode.focuswin)
330 case FOCUS_EWIN_UNMAP:
333 ewin = FocusEwinSelect();
334 if (ewin == Mode.focuswin)
339 if (Conf.focus.all_new_windows_get_focus)
341 else if (Mode.place.doing_manual)
344 if (ewin->props.focus_when_mapped)
347 if (EwinIsTransient(ewin))
349 if (Conf.focus.new_transients_get_focus)
353 else if (Conf.focus.new_transients_get_focus_if_group_focused)
357 ewin2 = EwinFindByClient(EwinGetTransientFor(ewin));
358 if ((ewin2) && (Mode.focuswin == ewin2))
363 DeskGotoByEwin(ewin);
368 if (!FocusEwinValid(ewin, 1, 0, 0))
373 if (ewin == Mode.focuswin && focus_is_set)
376 /* Check if ewin is a valid focus window target */
381 /* NB! ewin != NULL */
383 if (why != FOCUS_CLICK && ewin->props.focusclick)
386 if (Conf.autoraise.enable)
388 TIMER_DEL(focus_timer_autoraise);
390 if (Conf.focus.mode != MODE_FOCUS_CLICK)
391 TIMER_ADD(focus_timer_autoraise, 0.001 * Conf.autoraise.delay,
392 AutoraiseTimeout, ewin);
398 if (Conf.focus.warp_always)
407 GrabKeyboardSet(VROOT); /* Causes idler to be called on KeyRelease */
408 focus_pending_raise = ewin;
410 case FOCUS_DESK_ENTER:
411 if (Conf.focus.mode == MODE_FOCUS_CLICK)
415 EwinListFocusRaise(ewin);
419 SoundPlay(SOUND_FOCUS_SET);
424 /* Unset old focus window (if any) highlighting */
426 FocusEwinSetActive(Mode.focuswin, 0);
429 /* Quit if pointer is not on our screen */
430 if (!EQueryPointer(NULL, NULL, NULL, NULL, NULL))
432 Mode.focuswin = NULL;
436 /* Set new focus window (if any) highlighting */
437 Mode.focuswin = ewin;
439 FocusEwinSetActive(Mode.focuswin, 1);
441 if (why == FOCUS_DESK_LEAVE)
449 FocusToEWin(EWin * ewin, int why)
451 if (EDebug(EDBUG_TYPE_FOCUS))
452 Eprintf("FocusToEWin(%d) %#lx %s why=%d\n", focus_inhibit,
453 (ewin) ? EwinGetClientXwin(ewin) : 0,
454 (ewin) ? EwinGetTitle(ewin) : "None", why);
459 if (!FocusEwinValid(ewin, 0, 0, 0))
461 focus_pending_new = ewin;
462 focus_pending_why = why;
463 focus_pending_ewin = ewin;
467 if (ewin && !FocusEwinValid(ewin, 0, why == FOCUS_CLICK, 0))
469 focus_pending_why = why;
470 focus_pending_ewin = ewin;
473 case FOCUS_EWIN_UNMAP:
474 focus_pending_why = why;
475 focus_pending_ewin = NULL;
476 if (ewin == Mode.focuswin)
478 Mode.focuswin = NULL;
481 FocusEwinSetActive(ewin, 0);
483 if (ewin == focus_pending_new)
484 focus_pending_new = NULL;
492 if (focus_pending_new && Conf.focus.all_new_windows_get_focus)
493 doFocusToEwin(focus_pending_new, FOCUS_EWIN_NEW);
495 doFocusToEwin(focus_pending_ewin, focus_pending_why);
496 focus_pending_why = 0;
497 focus_pending_ewin = focus_pending_new = NULL;
501 FocusNewDeskBegin(void)
503 /* Freeze keyboard */
504 XGrabKeyboard(disp, WinGetXwin(VROOT), False, GrabModeAsync,
505 GrabModeSync, CurrentTime);
507 focus_pending_new = NULL;
508 doFocusToEwin(NULL, FOCUS_DESK_LEAVE);
514 FocusToEWin(NULL, FOCUS_DESK_ENTER);
516 /* Unfreeze keyboard */
517 XUngrabKeyboard(disp, CurrentTime);
521 FocusCheckScreen(void)
523 if (EQueryPointer(NULL, NULL, NULL, NULL, NULL))
524 return; /* On screen */
526 FocusToEWin(NULL, FOCUS_DESK_LEAVE);
532 /* Start focusing windows */
535 FocusToEWin(NULL, FOCUS_INIT);
538 /* Enable window placement features */
539 Mode.place.enable_features++;
548 * Focus event handlers
552 FocusHandleEnter(EWin * ewin, XEvent * ev)
554 Window win = ev->xcrossing.window;
556 Mode.mouse_over_ewin = ewin;
560 /* Entering root may mean entering this screen */
561 if (win == WinGetXwin(VROOT) &&
562 (ev->xcrossing.mode == NotifyNormal &&
563 ev->xcrossing.detail != NotifyInferior))
565 FocusToEWin(NULL, FOCUS_DESK_ENTER);
570 if (ev->xcrossing.mode == NotifyUngrab &&
571 ev->xcrossing.detail == NotifyNonlinearVirtual)
574 switch (Conf.focus.mode)
577 case MODE_FOCUS_CLICK:
579 case MODE_FOCUS_SLOPPY:
580 if (FocusEwinValid(ewin, 1, 0, 0))
581 FocusToEWin(ewin, FOCUS_ENTER);
583 case MODE_FOCUS_POINTER:
584 if (!ewin || FocusEwinValid(ewin, 1, 0, 0))
585 FocusToEWin(ewin, FOCUS_ENTER);
591 FocusHandleLeave(EWin * ewin __UNUSED__, XEvent * ev)
593 Window win = ev->xcrossing.window;
595 /* Leaving root may mean entering other screen */
596 if (win == WinGetXwin(VROOT) &&
597 (ev->xcrossing.mode == NotifyNormal &&
598 ev->xcrossing.detail != NotifyInferior))
599 FocusToEWin(NULL, FOCUS_DESK_LEAVE);
603 FocusHandleChange(EWin * ewin __UNUSED__, XEvent * ev __UNUSED__)
606 if (ewin == Mode.focuswin && ev->type == FocusOut)
607 Eprintf("??? Lost focus: %s\n", EwinGetTitle(ewin));
612 FocusHandleClick(EWin * ewin, Win win)
614 if (Conf.focus.clickraises)
617 FocusToEWin(ewin, FOCUS_CLICK);
619 /* Allow click to pass thorugh */
620 if (EDebug(EDBUG_TYPE_GRABS))
621 Eprintf("FocusHandleClick %#lx %#lx\n", WinGetXwin(win),
622 EwinGetContainerXwin(ewin));
623 if (win == EwinGetContainerWin(ewin))
626 XAllowEvents(disp, ReplayPointer, CurrentTime);
633 * Configuration dialog
635 static int tmp_focus;
636 static char tmp_clickalways;
637 static char tmp_new_focus;
638 static char tmp_popup_focus;
639 static char tmp_owner_popup_focus;
640 static char tmp_raise_focus;
641 static char tmp_warp_focus;
642 static char tmp_warp_always;
644 static char tmp_display_warp;
645 static char tmp_warp_after_focus;
646 static char tmp_raise_after_focus;
647 static char tmp_showsticky;
648 static char tmp_showshaded;
649 static char tmp_showiconified;
650 static char tmp_showalldesks;
651 static char tmp_warpfocused;
652 static int tmp_warp_icon_mode;
655 CB_ConfigureFocus(Dialog * d __UNUSED__, int val, void *data __UNUSED__)
659 Conf.focus.mode = tmp_focus;
660 Conf.focus.all_new_windows_get_focus = tmp_new_focus;
661 Conf.focus.new_transients_get_focus = tmp_popup_focus;
662 Conf.focus.new_transients_get_focus_if_group_focused =
663 tmp_owner_popup_focus;
664 Conf.focus.raise_on_next = tmp_raise_focus;
665 Conf.focus.warp_on_next = tmp_warp_focus;
666 Conf.focus.warp_always = tmp_warp_always;
668 Conf.warplist.enable = tmp_display_warp;
669 Conf.warplist.warp_on_select = tmp_warp_after_focus;
670 Conf.warplist.raise_on_select = tmp_raise_after_focus;
671 Conf.warplist.showsticky = tmp_showsticky;
672 Conf.warplist.showshaded = tmp_showshaded;
673 Conf.warplist.showiconified = tmp_showiconified;
674 Conf.warplist.showalldesks = tmp_showalldesks;
675 Conf.warplist.warpfocused = tmp_warpfocused;
676 Conf.warplist.icon_mode = tmp_warp_icon_mode;
678 Conf.focus.clickraises = tmp_clickalways;
685 _DlgFillFocus(Dialog * d __UNUSED__, DItem * table, void *data __UNUSED__)
687 DItem *di, *radio, *radio2;
689 tmp_focus = Conf.focus.mode;
690 tmp_new_focus = Conf.focus.all_new_windows_get_focus;
691 tmp_popup_focus = Conf.focus.new_transients_get_focus;
692 tmp_owner_popup_focus = Conf.focus.new_transients_get_focus_if_group_focused;
693 tmp_raise_focus = Conf.focus.raise_on_next;
694 tmp_warp_focus = Conf.focus.warp_on_next;
695 tmp_warp_always = Conf.focus.warp_always;
697 tmp_raise_after_focus = Conf.warplist.raise_on_select;
698 tmp_warp_after_focus = Conf.warplist.warp_on_select;
699 tmp_display_warp = Conf.warplist.enable;
700 tmp_showsticky = Conf.warplist.showsticky;
701 tmp_showshaded = Conf.warplist.showshaded;
702 tmp_showiconified = Conf.warplist.showiconified;
703 tmp_showalldesks = Conf.warplist.showalldesks;
704 tmp_warpfocused = Conf.warplist.warpfocused;
705 tmp_warp_icon_mode = Conf.warplist.icon_mode;
707 tmp_clickalways = Conf.focus.clickraises;
709 DialogItemTableSetOptions(table, 2, 0, 0, 0);
711 radio = di = DialogAddItem(table, DITEM_RADIOBUTTON);
712 DialogItemSetColSpan(di, 2);
713 DialogItemSetText(di, _("Focus follows pointer"));
714 DialogItemRadioButtonSetFirst(di, radio);
715 DialogItemRadioButtonGroupSetVal(di, 0);
717 di = DialogAddItem(table, DITEM_RADIOBUTTON);
718 DialogItemSetColSpan(di, 2);
719 DialogItemSetText(di, _("Focus follows pointer sloppily"));
720 DialogItemRadioButtonSetFirst(di, radio);
721 DialogItemRadioButtonGroupSetVal(di, 1);
723 di = DialogAddItem(table, DITEM_RADIOBUTTON);
724 DialogItemSetColSpan(di, 2);
725 DialogItemSetText(di, _("Focus follows mouse clicks"));
726 DialogItemRadioButtonSetFirst(di, radio);
727 DialogItemRadioButtonGroupSetVal(di, 2);
728 DialogItemRadioButtonGroupSetValPtr(radio, &tmp_focus);
730 di = DialogAddItem(table, DITEM_SEPARATOR);
731 DialogItemSetColSpan(di, 2);
733 di = DialogAddItem(table, DITEM_CHECKBUTTON);
734 DialogItemSetColSpan(di, 2);
735 DialogItemSetText(di, _("Clicking in a window always raises it"));
736 DialogItemCheckButtonSetPtr(di, &tmp_clickalways);
738 di = DialogAddItem(table, DITEM_SEPARATOR);
739 DialogItemSetColSpan(di, 2);
741 di = DialogAddItem(table, DITEM_CHECKBUTTON);
742 DialogItemSetColSpan(di, 2);
743 DialogItemSetText(di, _("All new windows first get the focus"));
744 DialogItemCheckButtonSetPtr(di, &tmp_new_focus);
746 di = DialogAddItem(table, DITEM_CHECKBUTTON);
747 DialogItemSetColSpan(di, 2);
748 DialogItemSetText(di, _("Only new dialog windows get the focus"));
749 DialogItemCheckButtonSetPtr(di, &tmp_popup_focus);
751 di = DialogAddItem(table, DITEM_CHECKBUTTON);
752 DialogItemSetColSpan(di, 2);
753 DialogItemSetText(di,
755 ("Only new dialogs whose owner is focused get the focus"));
756 DialogItemCheckButtonSetPtr(di, &tmp_owner_popup_focus);
758 di = DialogAddItem(table, DITEM_CHECKBUTTON);
759 DialogItemSetColSpan(di, 2);
760 DialogItemSetText(di, _("Raise windows while switching focus"));
761 DialogItemCheckButtonSetPtr(di, &tmp_raise_focus);
763 di = DialogAddItem(table, DITEM_CHECKBUTTON);
764 DialogItemSetColSpan(di, 2);
765 DialogItemSetText(di,
766 _("Send mouse pointer to window while switching focus"));
767 DialogItemCheckButtonSetPtr(di, &tmp_warp_focus);
769 di = DialogAddItem(table, DITEM_CHECKBUTTON);
770 DialogItemSetColSpan(di, 2);
771 DialogItemSetText(di,
772 _("Always send mouse pointer to window on focus switch"));
773 DialogItemCheckButtonSetPtr(di, &tmp_warp_always);
775 di = DialogAddItem(table, DITEM_SEPARATOR);
776 DialogItemSetColSpan(di, 2);
778 di = DialogAddItem(table, DITEM_CHECKBUTTON);
779 DialogItemSetColSpan(di, 2);
780 DialogItemSetText(di, _("Display and use focus list"));
781 DialogItemCheckButtonSetPtr(di, &tmp_display_warp);
783 di = DialogAddItem(table, DITEM_CHECKBUTTON);
784 DialogItemSetColSpan(di, 2);
785 DialogItemSetText(di, _("Include sticky windows in focus list"));
786 DialogItemCheckButtonSetPtr(di, &tmp_showsticky);
788 di = DialogAddItem(table, DITEM_CHECKBUTTON);
789 DialogItemSetColSpan(di, 2);
790 DialogItemSetText(di, _("Include shaded windows in focus list"));
791 DialogItemCheckButtonSetPtr(di, &tmp_showshaded);
793 di = DialogAddItem(table, DITEM_CHECKBUTTON);
794 DialogItemSetColSpan(di, 2);
795 DialogItemSetText(di, _("Include iconified windows in focus list"));
796 DialogItemCheckButtonSetPtr(di, &tmp_showiconified);
798 di = DialogAddItem(table, DITEM_CHECKBUTTON);
799 DialogItemSetColSpan(di, 2);
800 DialogItemSetText(di, _("Include windows on other desks in focus list"));
801 DialogItemCheckButtonSetPtr(di, &tmp_showalldesks);
803 di = DialogAddItem(table, DITEM_CHECKBUTTON);
804 DialogItemSetColSpan(di, 2);
805 DialogItemSetText(di, _("Focus windows while switching"));
806 DialogItemCheckButtonSetPtr(di, &tmp_warpfocused);
808 di = DialogAddItem(table, DITEM_CHECKBUTTON);
809 DialogItemSetColSpan(di, 2);
810 DialogItemSetText(di, _("Raise windows after focus switch"));
811 DialogItemCheckButtonSetPtr(di, &tmp_raise_after_focus);
813 di = DialogAddItem(table, DITEM_CHECKBUTTON);
814 DialogItemSetColSpan(di, 2);
815 DialogItemSetText(di, _("Send mouse pointer to window after focus switch"));
816 DialogItemCheckButtonSetPtr(di, &tmp_warp_after_focus);
818 di = DialogAddItem(table, DITEM_SEPARATOR);
819 DialogItemSetColSpan(di, 2);
821 di = DialogAddItem(table, DITEM_TEXT);
822 DialogItemSetColSpan(di, 2);
823 DialogItemSetText(di,
825 ("Focuslist image display policy (if one operation fails, try the next):"));
827 radio2 = di = DialogAddItem(table, DITEM_RADIOBUTTON);
828 DialogItemSetColSpan(di, 2);
829 DialogItemSetText(di, _("First E Icon, then App Icon"));
830 DialogItemRadioButtonSetFirst(di, radio2);
831 DialogItemRadioButtonGroupSetVal(di, 3);
833 di = DialogAddItem(table, DITEM_RADIOBUTTON);
834 DialogItemSetColSpan(di, 2);
835 DialogItemSetText(di, _("First App Icon, then E Icon"));
836 DialogItemRadioButtonSetFirst(di, radio2);
837 DialogItemRadioButtonGroupSetVal(di, 4);
839 di = DialogAddItem(table, DITEM_RADIOBUTTON);
840 DialogItemSetColSpan(di, 2);
841 DialogItemSetText(di, _("None"));
842 DialogItemRadioButtonSetFirst(di, radio2);
843 DialogItemRadioButtonGroupSetVal(di, 0);
844 DialogItemRadioButtonGroupSetValPtr(radio2, &tmp_warp_icon_mode);
847 const DialogDef DlgFocus = {
850 N_("Focus Settings"),
851 SOUND_SETTINGS_FOCUS,
853 N_("Enlightenment Focus\n" "Settings Dialog\n"),
855 DLG_OAC, CB_ConfigureFocus,
857 #endif /* ENABLE_DIALOGS */
864 FocusInitTimeout(void *data __UNUSED__)
871 _FocusIdler(void *data __UNUSED__)
873 if (!focus_inhibit && focus_pending_why)
875 if (click_pending_update_grabs)
876 doClickGrabsUpdate();
877 if (focus_pending_raise)
882 FocusSighan(int sig, void *prm __UNUSED__)
884 Timer *focus_init_timer;
889 /* Delay focusing a bit to allow things to settle down */
890 IdlerAdd(_FocusIdler, NULL);
891 TIMER_ADD(focus_init_timer, 0.5, FocusInitTimeout, NULL);
901 FocusIpc(const char *params)
904 char cmd[128], prm[4096];
907 cmd[0] = prm[0] = '\0';
912 sscanf(p, "%100s %4000s %n", cmd, prm, &len);
916 if (!p || cmd[0] == '?')
920 ewin = GetFocusEwin();
922 IpcPrintf("Focused: %#lx\n", EwinGetClientXwin(ewin));
924 IpcPrintf("Focused: none\n");
926 else if (!strncmp(cmd, "mode", 2))
928 int mode = Conf.focus.mode;
930 if (!strcmp(prm, "click"))
932 mode = MODE_FOCUS_CLICK;
933 Mode.grabs.pointer_grab_active = 1;
935 else if (!strcmp(prm, "clicknograb"))
937 mode = MODE_FOCUS_CLICK;
938 Mode.grabs.pointer_grab_active = 0;
940 else if (!strcmp(prm, "pointer"))
942 mode = MODE_FOCUS_POINTER;
944 else if (!strcmp(prm, "sloppy"))
946 mode = MODE_FOCUS_SLOPPY;
948 else if (!strcmp(prm, "?"))
950 if (Conf.focus.mode == MODE_FOCUS_CLICK)
952 if (Mode.grabs.pointer_grab_active)
957 else if (Conf.focus.mode == MODE_FOCUS_SLOPPY)
959 else if (Conf.focus.mode == MODE_FOCUS_POINTER)
963 IpcPrintf("Focus Mode: %s\n", p);
967 IpcPrintf("Error: unknown focus type\n");
969 if (Conf.focus.mode != mode)
971 Conf.focus.mode = mode;
976 else if (!strncmp(cmd, "next", 2))
978 /* Focus previously focused window */
979 if (Conf.warplist.enable)
984 else if (!strncmp(cmd, "prev", 2))
986 /* Focus least recently focused window */
987 if (Conf.warplist.enable)
994 static const IpcItem FocusIpcArray[] = {
999 " focus ? Show focus info\n"
1000 " focus mode Set focus mode. Modes:\n"
1001 " click: The traditional click-to-focus mode.\n"
1002 " clicknograb: A similar focus mode, but without the grabbing of the click\n"
1003 " (you cannot click anywhere in a window to focus it)\n"
1004 " pointer: The focus will follow the mouse pointer\n"
1005 " sloppy: The focus follows the mouse, but when over the desktop background\n"
1006 " the last window does not lose the focus\n"}
1009 #define N_IPC_FUNCS (sizeof(FocusIpcArray)/sizeof(IpcItem))
1011 static const CfgItem FocusCfgItems[] = {
1012 CFG_ITEM_INT(Conf.focus, mode, MODE_FOCUS_SLOPPY),
1013 CFG_ITEM_BOOL(Conf.focus, clickraises, 1),
1014 CFG_ITEM_BOOL(Conf.focus, transientsfollowleader, 1),
1015 CFG_ITEM_BOOL(Conf.focus, switchfortransientmap, 1),
1016 CFG_ITEM_BOOL(Conf.focus, all_new_windows_get_focus, 0),
1017 CFG_ITEM_BOOL(Conf.focus, new_transients_get_focus, 0),
1018 CFG_ITEM_BOOL(Conf.focus, new_transients_get_focus_if_group_focused, 1),
1019 CFG_ITEM_BOOL(Conf.focus, raise_on_next, 1),
1020 CFG_ITEM_BOOL(Conf.focus, warp_on_next, 0),
1021 CFG_ITEM_BOOL(Conf.focus, warp_always, 0),
1023 CFG_ITEM_BOOL(Conf, autoraise.enable, 0),
1024 CFG_ITEM_INT(Conf, autoraise.delay, 500),
1026 #define N_CFG_ITEMS (sizeof(FocusCfgItems)/sizeof(CfgItem))
1031 extern const EModule ModFocus;
1032 const EModule ModFocus = {
1035 {N_IPC_FUNCS, FocusIpcArray},
1036 {N_CFG_ITEMS, FocusCfgItems}