Skip to content

Input focus

Sergii edited this page Dec 4, 2018 · 26 revisions

This page is dedicated to description of input focus management problems, findings and my vision of solutions.

Points of interest

There are several user actions which triggers focus switch:

  1. Window open (including application's start) or close (including application's quit). [actions.c: wSetFocusTo()] [event.c: handleMapRequest(), handleMapNotify(), handleUnmapNotify(), handleDestroyNotify()]
  2. Click on desired window titlebar. [actions.c: wSetFocusTo()]
  3. Click inside desired window. [actions.c: wSetFocusTo()]
  4. Double-click on application icon (in Dock or Icon Yard). [dock.c: iconDblClick(); appicon.c: iconDblClick()]
  5. Switch between applications with 'Cmd-Tab' key equivalent. [cycling.c: ]
  6. Miniaturize/deminiaturize window (with mouse or keyboard).
  7. Hide/unhide application (with mouse or keyboard).
  8. Workspace switch.

Focus Handling Concepts

Here I describe desired behaviour of focus management part of Workspace Window Manager.

GNUstep GUI backend (gnustep-back) part

Sources/x11/XGServerEvent.m

  • (NSEvent *)_handleTakeFocusAtom:(XEvent)xEvent forContext:(NSGraphicsContext *)gcontext

Process ButtonPress event

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;
                }
              }
          }

Window Manager of Workspace

WApplication (application.h)

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.

Description of some field inside struct WApplication {}

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().

New GNUstep application handling by WM

On application start wApplicationCreate() is called:

  • creates wapp->windows array
  • adds wwin to this array
  • saved wwin to wapp->menu_win if it's main menu (normally it is)

When new window opens (MapRequest/MapNotify, event.c) wApplicationAdd() is called:

  • adds wwin into wapp->windows array
  • wapp->refcount++

When window is closed (UnmapNotify, event.c) and window is not main menu wApplicationRemoveWindow() is called:

  • removes wwin from wapp->windows array
  • wapp->refcount--

When application quits (DestroyNotify, event.c):

  • several calls to wApplicationRemoveWindow() is performed
  • wApplicationDestroy() is called:
    • wUnmanageWindow() for wapp->menu_win is called
    • wapp->windows array destroyed
    • wapp->refcount--
    • wapp is freed