Let's have something more useful in KWin's README than a statement
that it's KWin. For example an explanation how to handle problems with focus stealing prevention, and hopefully more to come later. svn path=/trunk/kdebase/kwin/; revision=253547
This commit is contained in:
parent
89cd9ee65b
commit
bfcadaa3de
1 changed files with 182 additions and 53 deletions
235
README
235
README
|
@ -1,60 +1,189 @@
|
|||
This is KWin, kwm next generation.
|
||||
|
||||
This README is meant as an explanation of various window manager related
|
||||
mechanisms that application developers need to be aware of. As some of these
|
||||
concepts may be difficult to understand for people not having the required
|
||||
background knowledge (since sometimes it's difficult even for people who
|
||||
do have the knowledge), the mechanisms are first briefly explained, and
|
||||
then an example of fixing the various problems is given.
|
||||
|
||||
For comments, questions, suggestions and whatever use the kwin@kde.org
|
||||
mailing list.
|
||||
|
||||
|
||||
/*!
|
||||
Different focus policies:
|
||||
<ul>
|
||||
Table of contents:
|
||||
==================
|
||||
|
||||
<li>ClickToFocus - Clicking into a window activates it. This is
|
||||
also the default.
|
||||
|
||||
<li>FocusFollowsMouse - Moving the mouse pointer actively onto a
|
||||
normal window activates it. For convenience, the desktop and
|
||||
windows on the dock are excluded. They require clicking.
|
||||
|
||||
<li>FocusUnderMouse - The window that happens to be under the
|
||||
mouse pointer becomes active. The invariant is: no window can
|
||||
have focus that is not under the mouse. This also means that
|
||||
Alt-Tab won't work properly and popup dialogs are usually
|
||||
usable with the keyboard. Note that the desktop and windows on
|
||||
the dock are excluded for convenience. They get focus only when
|
||||
clicking on it.
|
||||
|
||||
<li>FocusStrictlyUnderMouse - this is even worse than
|
||||
FocusUnderMouse. Only the window under the mouse pointer is
|
||||
active. If the mouse points nowhere, nothing has the focus. If
|
||||
the mouse points onto the desktop, the desktop has focus. The
|
||||
same holds for windows on the dock.
|
||||
|
||||
Note that FocusUnderMouse and FocusStrictlyUnderMouse are not
|
||||
particularly useful. They are only provided for old-fashioned
|
||||
die-hard UNIX people ;-)
|
||||
|
||||
</ul>
|
||||
*/
|
||||
FocusPolicy=ClickToFocus | FocusFollowsMouse | FocusUnderMouse | FocusStrictlyUnderMouse
|
||||
- Window relations
|
||||
- how to make the window manager know which windows belong together
|
||||
- Focus stealing prevention
|
||||
- how to solve cases where focus stealing prevention doesn't work
|
||||
properly automatically
|
||||
|
||||
|
||||
/**
|
||||
Different Alt-Tab-Styles:
|
||||
<ul>
|
||||
|
||||
<li> KDE - the recommended KDE style. Alt-Tab opens a nice icon
|
||||
box that makes it easy to select the window you want to tab
|
||||
to. The order automatically adjusts to the most recently used
|
||||
windows. Note that KDE style does not work with the
|
||||
FocusUnderMouse and FocusStrictlyUnderMouse focus
|
||||
policies. Choose ClickToFocus or FocusFollowsMouse instead.
|
||||
|
||||
<li> CDE - the old-fashion CDE style. Alt-Tab cycles between
|
||||
the windows in static order. The current window gets raised,
|
||||
the previous window gets lowered.
|
||||
|
||||
</ul>
|
||||
*/
|
||||
AltTabStyle=KDE | CDE
|
||||
|
||||
|
||||
Have fun,
|
||||
Window relations:
|
||||
=================
|
||||
|
||||
Matthias Ettrich <ettrich@kde.org>
|
||||
(For now, this explanation of window relations is mainly meant for
|
||||
focus stealing prevention. To be extended later.)
|
||||
|
||||
All windows created by an application should be organized in a tree
|
||||
with the root being the application's main window. Note that this is about
|
||||
toplevel windows, not widgets inside the windows. For example, if you
|
||||
have KWrite running, with a torn-off toolbar (i.e. a standalone toolbar),
|
||||
a file save dialog open, and the file save dialog showing a dialog
|
||||
for creating a directory, the window hiearchy should look like this:
|
||||
|
||||
|
||||
KWrite mainwindow
|
||||
/ \
|
||||
/ \
|
||||
file save dialog torn-off toolbar
|
||||
\
|
||||
\
|
||||
create directory dialog
|
||||
|
||||
Each subwindow (i.e. all except for the KWrite mainwindow) points to its
|
||||
main window (which in turn may have another main window, as in the case
|
||||
of the file save dialog). When the window manager knows these relations,
|
||||
it can better arrange the windows (keeping subwindows above their
|
||||
main windows, preventing activation of a main window of a modal dialog,
|
||||
and similar). Failing to provide this information to the window manager
|
||||
may have various results, for example having dialogs positioned below
|
||||
the main window,
|
||||
|
||||
The window property used by subwindows to point to their mainwindows is
|
||||
called WM_TRANSIENT_FOR. It can be seen by running
|
||||
'xprop | grep WM_TRANSIENT_FOR' and clicking on a window. If the property
|
||||
is not present, the window does not (claim to) have any mainwindow.
|
||||
If the property is present, it's value is the window id of its main window;
|
||||
window id of any window can be found out by running 'xwininfo'. A window
|
||||
having WM_TRANSIENT_FOR poiting to another window is said to be transient
|
||||
for that window.
|
||||
|
||||
In some cases, the WM_TRANSIENT_FOR property may not point to any other
|
||||
existing window, having value of 0, or pointing to the screen number
|
||||
('xwininfo -root'). These special values mean that the window is transient
|
||||
for all other windows in its window group. This should be used only
|
||||
in rare cases, everytime a specific main window is known, WM_TRANSIENT_FOR
|
||||
should be pointing to it instead of using one of these special values.
|
||||
(The explanation why is beyond the scope of this document - just accept it
|
||||
as a fact.)
|
||||
|
||||
With Qt, the WM_TRANSIENT_FOR property is set by Qt automatically, based
|
||||
on the toplevel widget's parent. If the toplevel widget is of a normal
|
||||
type (i.e. not a dialog, toolbar, etc.), Qt doesn't set WM_TRANSIENT_FOR
|
||||
on it. For special widgets, such as dialogs, WM_TRANSIENT_FOR is set
|
||||
to point to the widget's parent, if it has a specific parent, otherwise
|
||||
WM_TRANSIENT_FOR points to the root window.
|
||||
|
||||
As already said above, WM_TRANSIENT_FOR poiting to the root window should
|
||||
be usually avoided, so everytime the widget's main widget is known, the widget
|
||||
should get it passed as a parent in its constructor.
|
||||
(TODO KDialog etc. classes should not have a default argument for the parent
|
||||
argument, and comments like 'just pass 0 as the parent' should go.)
|
||||
|
||||
|
||||
|
||||
Focus stealing prevention:
|
||||
==========================
|
||||
|
||||
Since KDE3.2 KWin has a feature called focus stealing prevention. As the name
|
||||
suggests, it prevents unexpected changes of focus. With older versions of KWin,
|
||||
if any application opened a new dialog, it became active, and
|
||||
if the application's main window was on another virtual desktop, also
|
||||
the virtual desktop was changed. This was annoying, and also sometimes led
|
||||
to dialogs mistakenly being closed because they received keyboard input that
|
||||
was meant for the previously active window.
|
||||
|
||||
The basic principle of focus stealing prevention is that the window with most
|
||||
recent user activity wins. Any window of an application will become active
|
||||
when being shown only if this application was the most recently used one.
|
||||
KWin itself, and some of the related kdecore classes should take care
|
||||
of the common cases, so usually there's no need for any special handling
|
||||
in applications. Qt/KDE applications, that is. Applications using other
|
||||
toolkits should in most cases work fine too. If they don't support
|
||||
the window property _NET_WM_USER_TIME, the window manager may fail to detect
|
||||
the user timestamp properly, resulting either in other windows becoming active
|
||||
while the user works with this application, or this application may sometimes
|
||||
steal focus (this second case should be very rare though).
|
||||
|
||||
There are also cases where KDE applications needs special handling. The two
|
||||
most common cases are when windows relations are not setup properly to make
|
||||
KWin realize that they belong to the same application, and when the user
|
||||
activity is not represented by manipulating with the application windows
|
||||
themselves.
|
||||
|
||||
Also note that focus stealing prevention implemented in the window manager
|
||||
can only help with focus stealing between different applications.
|
||||
If an application itself suddenly pops up a dialog, KWin cannot do anything about
|
||||
it, and its the application's job to handle this case.
|
||||
|
||||
|
||||
Window relations:
|
||||
-----------------
|
||||
|
||||
The common case here is when a dialog is shown for an application, but this
|
||||
dialog is not provided by the application itself, but by some other process.
|
||||
For example, dialogs with warnings about accepted cookies are provided
|
||||
by KCookieJar, instead of being shown by Konqueror. In the normal case,
|
||||
from KWin's point of view the cookie dialog would be an attempt of another
|
||||
application to show a dialog, and KWin wouldn't allow activation of this
|
||||
window.
|
||||
|
||||
The solution is to tell the window manager about the relation between
|
||||
the Konqueror main window and the cookie dialog, by making the dialog
|
||||
point to the mainwindow. Note that this is not special to focus stealing
|
||||
prevention, subwindows such as dialogs, toolbars and similar should always
|
||||
point to their mainwindow. See the section on window relations for full
|
||||
description.
|
||||
|
||||
The WM_TRANSIENT_FOR property that's set on dialogs to point to their
|
||||
mainwindow should in the cookie dialog case point to the Konqueror window
|
||||
for which it has been shown. This is solved in kcookiejar by including
|
||||
the window id in the DCOP call. When the cookie dialog is shown, its
|
||||
WM_TRANSIENT_FOR property is manually set using the XSetTransientForHint()
|
||||
call (see kdelibs/kioslave/http/kcookiejar/kcookiewin.cpp). The arguments
|
||||
to XSetTransientForHint() call are the X display (i.e. qt_xdisplay()),
|
||||
the window id on which the WM_TRANSIENT_FOR property is to be set
|
||||
(i.e. use QWidget::winId()), and the window id of the mainwindow.
|
||||
|
||||
|
||||
Simple short HOWTO:
|
||||
|
||||
To put it simply: Let's say you have a daemon application that has
|
||||
DCOP call "showDialog( QString text )", and when this is called, it shows
|
||||
a dialog with the given text. This won't work properly with focus stealing
|
||||
prevention. The DCOP call should be changed to
|
||||
"showDialog( QString text, long id )". The caller should pass something like
|
||||
myMainWindow->winId() as the second argument. In the daemon, before
|
||||
the dialog is shown, a call to XSetTransientHint() should be added:
|
||||
|
||||
XSetTransientForHint( qt_xdisplay(), dialog->winId(), id_of_mainwindow );
|
||||
|
||||
That's it.
|
||||
|
||||
Non-standard user activity:
|
||||
---------------------------
|
||||
|
||||
The most common case in KDE will be DCOP calls. For example, KDesktop's DCOP
|
||||
call "KDesktopIface popupExecuteCommand". Executing this DCOP call e.g.
|
||||
from Konsole as 'dcop kdesktop KDesktopIface popupExecuteCommand" will lead
|
||||
to showing the minicli, but the last user activity timestamp gained from events
|
||||
sent by X server will be older than user activity timestamp of Konsole, and
|
||||
would normally result in minicli not being active. Therefore, before showing
|
||||
the minicli, kdesktop needs to call KApplication::updateUserTimestamp().
|
||||
|
||||
However, this shouldn't be done with all DCOP calls. If a DCOP call is not
|
||||
a result of direct user action, calling KApplication::updateUserTimestamp()
|
||||
would lead to focus stealing. For example, let's assume for a moment
|
||||
that KMail would use this DCOP call in case it detects the modem is not
|
||||
connected, allowing to you to start KPPP or whatever tool you use. If KMail
|
||||
would be configured to check mail every 10 minutes, this would lead to minicli
|
||||
possibly suddenly showing up at every check. Basically, doing the above change
|
||||
to kdesktop's minicli means that the popupExecuteCommand() DCOP call is only
|
||||
for user scripting. (TODO write about focus transferring?)
|
||||
|
||||
Simply said, KApplication::updateUserTimestamp() should be called only
|
||||
as a result of user action. Unfortunately, I'm not aware of any universal
|
||||
way how to handle this, so every case will have to be considered separately.
|
||||
|
|
Loading…
Reference in a new issue