-
Notifications
You must be signed in to change notification settings - Fork 71
Input focus
This page is dedicated to description of input focus management problems, findings and my vision of solutions.
There are several user actions which triggers focus switch:
- Window open (including application's start) or close (including application's quit). [actions.c: wSetFocusTo()] [event.c: handleMapRequest(), handleMapNotify(), handleUnmapNotify(), handleDestroyNotify()]
- Click on desired window titlebar. [actions.c: wSetFocusTo()]
- Click inside desired window. [actions.c: wSetFocusTo()]
- Double-click on application icon (in Dock or Icon Yard). [dock.c: iconDblClick(); appicon.c: iconDblClick()]
- Switch between applications with 'Cmd-Tab' key equivalent. [cycling.c: ]
- Miniaturize/deminiaturize window (with mouse or keyboard).
- Hide/unhide application (with mouse or keyboard).
- Workspace switch.
Here I describe desired behavior of focus management part of Workspace Window Manager (WM).
In X11 world it's normal to pass focus management functions to window manager. X11 applications are responsible for window creation/destroying and providing hints to window manager if particular window can receive input focus. When window appears on screen window manager starts managing window to perform its duties. When window is withdrawn from screen, window manager stops management of this window (drops information about window meta data).
GNUstep applications are special because they have special window: main menu. When GNUstep application deactivates it hides main menu (and vice versa: main menu appears on screen when application becomes active). From window manager perspective window becomes withdrawn from screen (unmapped). So window manager stops managing such windows.
Essential part of communicating with window manager resides in Sources/x11/XGServerEvent.m file of GUI backend (gnustep-back). To make things work right focus management should be intact in window manager and in GNUstep application GUI backend.
- (NSEvent *)_handleTakeFocusAtom:(XEvent)xEvent forContext:(NSGraphicsContext *)gcontext
if (generic.flags.useWindowMakerIcons == 1)
{
/*
* We must hand over control of our icon/miniwindow
* to Window Maker.
*/
if ((cWin->win_attrs.window_style
& (NSMiniWindowMask | NSIconWindowMask)) != 0
&& eventType == NSLeftMouseDown /*&& clickCount == 1*/)
{
if (cWin->parent == None)
break;
xEvent.xbutton.window = cWin->parent;
XUngrabPointer(dpy, CurrentTime);
XSendEvent(dpy, cWin->parent, True, ButtonPressMask, &xEvent);
XFlush(dpy);
if (clickCount != 2) {
break;
}
}
}
Every running application has WApplication instance. Normal X11 application exists only if at least one window was mapped.
WApplication instance for registered application should contain defined:
- app_icon - appplication icon
- windows - list of windows (at least one) which belongs to application
- menu_win for GNUstep application
GNUstep application minimal appearance is appicon and menu. For focus handling/switching tasks menu_win
must be set to make correct focus switching.
main_window
- this is the invisible window that identifies application as a group of windows. Also it's called as "group leader". Every WWindow and WAppIcon contains field Window main_window
. That's how application icon, menu and windows/panels can be identified as single application.
main_window_desc
- generated WWindow structure for main_window
. So main_window
can be used as managed WWindow.
last_focused
- should be set to last window of application that has focus before FocusOut, hide, workspace switch events. Set in wSetFocusTo()
.
last_workspace
- contains workspace number of last_focused window workspace. If, for exmaple, application has 2 windows on different workspaces, double-click on appicon should: switch to workspace where last_focused window resides, set focus to that window (activate application). Set in wSetFocusTo()
.
On application start wApplicationCreate() is called:
- creates wapp->windows array
- adds
wwin
to this array - saved
wwin
towapp->menu_win
if it's main menu (normally it is)
When new window opens (MapRequest/MapNotify, event.c) wApplicationAdd() is called:
- adds
wwin
intowapp->windows
array wapp->refcount++
When window is closed (UnmapNotify, event.c) and window is not main menu wApplicationRemoveWindow()
is called:
- removes
wwin
fromwapp->windows
array wapp->refcount--
When application quits (DestroyNotify, event.c):
- several calls to
wApplicationRemoveWindow()
is performed -
wApplicationDestroy()
is called:-
wUnmanageWindow()
forwapp->menu_win
is called -
wapp->windows
array destroyed wapp->refcount--
-
wapp
is freed
-
Copyright (c) Sergii Stoian