second half of the "avoid stealing focus if possible" fix

svn path=/trunk/kdebase/kwin/; revision=139642
This commit is contained in:
Matthias Ettrich 2002-02-28 22:11:43 +00:00
parent 7d50916939
commit e34a6ee283
7 changed files with 182 additions and 109 deletions

View file

@ -45,6 +45,9 @@ Atoms::Atoms()
atoms[n] = &kde_wm_change_state;
names[n++] = (char *) "_KDE_WM_CHANGE_STATE";
atoms[n] = &kde_net_user_time;
names[n++] = (char *) "_KDE_NET_USER_TIME";
Atom fake;
atoms[n] = &fake;
names[n++] = (char *) "_DT_SM_WINDOW_INFO";

View file

@ -23,6 +23,7 @@ public:
Atom motif_wm_hints;
Atom net_wm_context_help;
Atom kde_wm_change_state;
Atom kde_net_user_time;
};

View file

@ -103,10 +103,15 @@ public:
// to resolve them properly
extern Atom qt_wm_state;
extern Time kwin_time;
extern Time qt_x_time;
extern Atom qt_window_role;
extern Atom qt_sm_client_id;
static int nullErrorHandler(Display *, XErrorEvent *)
{
return 0;
}
using namespace KWinInternal;
static bool resizeHorizontalDirectionFixed = FALSE;
@ -157,7 +162,7 @@ static void sendClientMessage(Window w, Atom a, long x){
ev.xclient.message_type = a;
ev.xclient.format = 32;
ev.xclient.data.l[0] = x;
ev.xclient.data.l[1] = kwin_time;
ev.xclient.data.l[1] = qt_x_time;
mask = 0L;
if (w == qt_xrootwin())
mask = SubstructureRedirectMask; /* magic! */
@ -399,24 +404,24 @@ void WindowWrapper::releaseWindow()
bool WindowWrapper::x11Event( XEvent * e)
{
switch ( e->type ) {
case ButtonPress:
{
uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ?
KKeyNative::modX(KKey::WIN) :
KKeyNative::modX(KKey::ALT);
bool bModKeyHeld = e->xbutton.state & keyModX;
case ButtonPress: {
((Client*)parentWidget())->updateUserTime();
uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ?
KKeyNative::modX(KKey::WIN) :
KKeyNative::modX(KKey::ALT);
bool bModKeyHeld = e->xbutton.state & keyModX;
if ( ((Client*)parentWidget())->isActive()
&& ( options->focusPolicy != Options::ClickToFocus
&& options->clickRaise && !bModKeyHeld ) ) {
if ( e->xbutton.button < 4 ) // exclude wheel
((Client*)parentWidget())->autoRaise();
ungrabButton( winId(), None );
}
if ( ((Client*)parentWidget())->isActive()
&& ( options->focusPolicy != Options::ClickToFocus
&& options->clickRaise && !bModKeyHeld ) ) {
if ( e->xbutton.button < 4 ) // exclude wheel
((Client*)parentWidget())->autoRaise();
ungrabButton( winId(), None );
}
Options::MouseCommand com = Options::MouseNothing;
if ( bModKeyHeld ){
switch (e->xbutton.button) {
Options::MouseCommand com = Options::MouseNothing;
if ( bModKeyHeld ){
switch (e->xbutton.button) {
case Button1:
com = options->commandAll1();
break;
@ -426,9 +431,9 @@ bool WindowWrapper::x11Event( XEvent * e)
case Button3:
com = options->commandAll3();
break;
}
} else {
switch (e->xbutton.button) {
}
} else {
switch (e->xbutton.button) {
case Button1:
com = options->commandWindow1();
break;
@ -440,22 +445,21 @@ bool WindowWrapper::x11Event( XEvent * e)
break;
default:
com = Options::MouseActivateAndPassClick;
}
}
bool replay = ( (Client*)parentWidget() )->performMouseCommand( com,
QPoint( e->xbutton.x_root, e->xbutton.y_root) );
}
}
bool replay = ( (Client*)parentWidget() )->performMouseCommand( com,
QPoint( e->xbutton.x_root, e->xbutton.y_root) );
if ( ((Client*)parentWidget())->windowType() != NET::Normal &&
((Client*)parentWidget())->windowType() != NET::Dialog &&
((Client*)parentWidget())->windowType() != NET::Override )
replay = TRUE;
if ( ((Client*)parentWidget())->windowType() != NET::Normal &&
((Client*)parentWidget())->windowType() != NET::Dialog &&
((Client*)parentWidget())->windowType() != NET::Override )
replay = TRUE;
XAllowEvents(qt_xdisplay(), replay? ReplayPointer : SyncPointer, CurrentTime ); //kwin_time);
return TRUE;
}
break;
XAllowEvents(qt_xdisplay(), replay? ReplayPointer : SyncPointer, CurrentTime ); //qt_x_time);
return TRUE;
} break;
case ButtonRelease:
XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //kwin_time);
XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time);
break;
default:
break;
@ -490,7 +494,8 @@ Client::Client( Workspace *ws, WId w, QWidget *parent, const char *name, WFlags
NET::WMWindowType |
NET::WMStrut |
NET::WMName |
NET::WMIconGeometry
NET::WMIconGeometry |
NET::WMPid
;
info = new WinInfo( this, qt_xdisplay(), win, qt_xrootwin(), properties );
@ -826,10 +831,23 @@ bool Client::manage( bool isMapped, bool doNotShow, bool isInitial )
if ( isMapped ) {
show();
} else {
workspace()->raiseClient( this ); // ensure constrains
show();
if ( options->focusPolicyIsReasonable() && wantsTabFocus() )
workspace()->requestFocus( this );
// we only raise (and potentially activate) new clients if
// the user does not actively work in the currently active
// client. We can safely drop the activation when the
// NET_KDE_USER_TIME of the currently active client is
// defined and more recent than the one of the new client
// (which we set ourselves in CreateNotify in
// workspace.cpp)
Client* ac = workspace()->activeClient();
if ( ac && ac->userTime() <= userTime() ) {
workspace()->raiseClient( this );
show();
if ( options->focusPolicyIsReasonable() && wantsTabFocus() )
workspace()->requestFocus( this );
} else {
workspace()->stackClientUnderActive( this );
show();
}
}
}
@ -840,6 +858,46 @@ bool Client::manage( bool isMapped, bool doNotShow, bool isInitial )
}
/*!
Updates the user time on the client window. This is called inside
kwin for every action with the window that qualifies for user
interaction (clicking on it, activate it externally, etc.).
*/
void Client::updateUserTime()
{
if ( window() ) {
timeval tv;
gettimeofday( &tv, NULL );
unsigned long now = tv.tv_sec * 10 + tv.tv_usec / 100000;
XChangeProperty(qt_xdisplay(), window(),
atoms->kde_net_user_time, XA_CARDINAL,
32, PropModeReplace, (unsigned char *)&now, 1);
}
}
unsigned long Client::userTime()
{
unsigned long result = 0;
Atom type;
int format, status;
unsigned long nitems = 0;
unsigned long extra = 0;
unsigned char *data = 0;
XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
status = XGetWindowProperty( qt_xdisplay(), window(),
atoms->kde_net_user_time,
0, 10000, FALSE, XA_CARDINAL, &type, &format,
&nitems, &extra, &data );
XSetErrorHandler(oldHandler);
if (status == Success ) {
if (data && nitems > 0)
result = *((long*) data);
XFree(data);
}
return result;
}
/*!
Gets the client's normal WM hints and reconfigures itself respectively.
*/
@ -1611,7 +1669,7 @@ void Client::mouseMoveEvent( QMouseEvent * e)
break;
}
}
workspace()->clientMoved(globalPos, kwin_time);
workspace()->clientMoved(globalPos, qt_x_time);
// QApplication::syncX(); // process our own configure events synchronously.
}
@ -2061,7 +2119,10 @@ void Client::gravitate( bool invert )
*/
bool Client::x11Event( XEvent * e)
{
if ( e->type == EnterNotify && ( e->xcrossing.mode == NotifyNormal || e->xcrossing.mode == NotifyUngrab ) ) {
if ( e->type == EnterNotify &&
( e->xcrossing.mode == NotifyNormal ||
( !options->focusPolicyIsReasonable() &&
e->xcrossing.mode == NotifyUngrab ) ) ) {
if (options->shadeHover && isShade() && !isDesktop()) {
delete shadeHoverTimer;
@ -2073,8 +2134,9 @@ bool Client::x11Event( XEvent * e)
if ( options->focusPolicy == Options::ClickToFocus )
return TRUE;
if ( options->autoRaise && !isDesktop() && !isDock() && !isMenu() && workspace()->focusChangeEnabled()
&& workspace()->topClientOnDesktop() != this ) {
if ( options->autoRaise && !isDesktop() &&
!isDock() && !isMenu() && workspace()->focusChangeEnabled() &&
workspace()->topClientOnDesktop() != this ) {
delete autoRaiseTimer;
autoRaiseTimer = new QTimer( this );
connect( autoRaiseTimer, SIGNAL( timeout() ), this, SLOT( autoRaise() ) );
@ -2420,7 +2482,7 @@ void Client::takeFocus( bool force )
// Qt may delay the mapping which may cause XSetInputFocus to fail, force show window
QApplication::sendPostedEvents( windowWrapper(), QEvent::ShowWindowRequest );
XSetInputFocus( qt_xdisplay(), win, RevertToPointerRoot, kwin_time );
XSetInputFocus( qt_xdisplay(), win, RevertToPointerRoot, qt_x_time );
}
if ( Ptakefocus )
sendClientMessage(win, atoms->wm_protocols, atoms->wm_take_focus);
@ -2650,11 +2712,6 @@ void Client::keyPressEvent( uint key_code )
QCursor::setPos( pos );
}
static int nullErrorHandler(Display *, XErrorEvent *)
{
return 0;
}
static QCString getStringProperty(WId w, Atom prop, char separator=0)
{
Atom type;

View file

@ -211,6 +211,8 @@ public:
void keyPressEvent( uint key_code );
void updateUserTime();
public slots:
void iconify();
void closeWindow();
@ -276,6 +278,8 @@ private:
void fetchName();
void gravitate( bool invert );
unsigned long userTime();
void startMoveResize();
void stopMoveResize();

View file

@ -43,8 +43,7 @@ Options* options;
Atoms* atoms;
extern Time qt_x_time; // workaround for Qt < 2.3.2
Time kwin_time = CurrentTime;
extern Time qt_x_time;
int kwin_screen_number = -1;
static bool initting = FALSE;
@ -88,7 +87,7 @@ int x11ErrorHandler(Display *d, XErrorEvent *e){
}
/*!
Updates kwin_time by receiving a current timestamp from the server.
Updates qt_x_time by receiving a current timestamp from the server.
Use this function only when really necessary. Keep in mind that it's
a roundtrip to the X-Server.
@ -103,8 +102,7 @@ void kwin_updateTime()
PropModeAppend, (unsigned char*) &data, 1);
XEvent ev;
XWindowEvent( qt_xdisplay(), w->winId(), PropertyChangeMask, &ev );
kwin_time = ev.xproperty.time;
qt_x_time = kwin_time;
qt_x_time = ev.xproperty.time;
}
@ -143,36 +141,10 @@ Application::~Application()
}
bool Application::x11EventFilter( XEvent *e )
{
switch ( e->type ) {
case ButtonPress:
case ButtonRelease:
kwin_time = e->xbutton.time;
qt_x_time = kwin_time; // workaround for Qt < 2.3.2
break;
case MotionNotify:
kwin_time = e->xmotion.time;
qt_x_time = kwin_time; // workaround for Qt < 2.3.2
break;
case KeyPress:
case KeyRelease:
kwin_time = e->xkey.time;
qt_x_time = kwin_time; // workaround for Qt < 2.3.2
break;
case PropertyNotify:
kwin_time = e->xproperty.time;
qt_x_time = kwin_time; // workaround for Qt < 2.3.2
break;
case EnterNotify:
case LeaveNotify:
kwin_time = e->xcrossing.time;
qt_x_time = kwin_time; // workaround for Qt < 2.3.2
default:
break;
}
if ( Workspace::self()->workspaceEvent( e ) )
if ( Workspace::self()->workspaceEvent( e ) )
return TRUE;
return KApplication::x11EventFilter( e );
}

View file

@ -46,6 +46,7 @@ Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
#include <X11/keysymdef.h>
#include <X11/extensions/shape.h>
#include <X11/cursorfont.h>
#include <sys/time.h>
const int XIconicState = IconicState;
#undef IconicState
@ -142,7 +143,7 @@ QString Workspace::desktopName( int desk )
return QString::fromUtf8( rootInfo->desktopName( desk ) );
}
extern Time kwin_time;
extern Time qt_x_time;
extern void kwin_updateTime();
// used to store the return values of
@ -511,7 +512,7 @@ bool Workspace::workspaceEvent( XEvent * e )
{
if ( mouse_emulation && e->type == ButtonPress || e->type == ButtonRelease ) {
mouse_emulation = FALSE;
XUngrabKeyboard( qt_xdisplay(), kwin_time );
XUngrabKeyboard( qt_xdisplay(), qt_x_time );
}
if ( e->type == PropertyNotify || e->type == ClientMessage ) {
@ -532,8 +533,8 @@ bool Workspace::workspaceEvent( XEvent * e )
switch (e->type) {
case ButtonPress:
if ( tab_grab || control_grab ) {
XUngrabKeyboard(qt_xdisplay(), kwin_time);
XUngrabPointer( qt_xdisplay(), kwin_time);
XUngrabKeyboard(qt_xdisplay(), qt_x_time);
XUngrabPointer( qt_xdisplay(), qt_x_time);
tab_box->hide();
keys->setEnabled( true );
tab_grab = control_grab = false;
@ -542,6 +543,18 @@ bool Workspace::workspaceEvent( XEvent * e )
case ButtonRelease:
case MotionNotify:
break;
case CreateNotify:
if ( e->xcreatewindow.parent == root &&
!QWidget::find( e->xcreatewindow.window) ) {
timeval tv;
gettimeofday( &tv, NULL );
unsigned long now = tv.tv_sec * 10 + tv.tv_usec / 100000;
XChangeProperty(qt_xdisplay(), e->xcreatewindow.window,
atoms->kde_net_user_time, XA_CARDINAL,
32, PropModeReplace, (unsigned char *)&now, 1);
}
break;
case UnmapNotify:
// this is special due to
// SubstructureNotifyMask. e->xany.window is the window the
@ -854,7 +867,7 @@ void Workspace::slotWalkThroughWindows()
if ( tab_grab || control_grab )
return;
if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable() ) {
//XUngrabKeyboard(qt_xdisplay(), kwin_time); // need that because of accelerator raw mode
//XUngrabKeyboard(qt_xdisplay(), qt_x_time); // need that because of accelerator raw mode
// CDE style raise / lower
CDEWalkThroughWindows( true );
} else {
@ -956,14 +969,14 @@ bool Workspace::startKDEWalkThroughWindows()
ButtonMotionMask | EnterWindowMask |
LeaveWindowMask | PointerMotionMask),
GrabModeAsync, GrabModeAsync,
None, None, kwin_time ) != GrabSuccess ) {
None, None, qt_x_time ) != GrabSuccess ) {
return FALSE;
}
if ( XGrabKeyboard(qt_xdisplay(),
root, FALSE,
GrabModeAsync, GrabModeAsync,
kwin_time) != GrabSuccess ) {
XUngrabPointer( qt_xdisplay(), kwin_time);
qt_x_time) != GrabSuccess ) {
XUngrabPointer( qt_xdisplay(), qt_x_time);
return FALSE;
}
tab_grab = TRUE;
@ -980,14 +993,14 @@ bool Workspace::startWalkThroughDesktops( int mode )
ButtonMotionMask | EnterWindowMask |
LeaveWindowMask | PointerMotionMask),
GrabModeAsync, GrabModeAsync,
None, None, kwin_time ) != GrabSuccess ) {
None, None, qt_x_time ) != GrabSuccess ) {
return FALSE;
}
if ( XGrabKeyboard(qt_xdisplay(),
root, FALSE,
GrabModeAsync, GrabModeAsync,
kwin_time) != GrabSuccess ) {
XUngrabPointer( qt_xdisplay(), kwin_time);
qt_x_time) != GrabSuccess ) {
XUngrabPointer( qt_xdisplay(), qt_x_time);
return FALSE;
}
control_grab = TRUE;
@ -1113,8 +1126,8 @@ bool Workspace::keyPress(XKeyEvent& ev)
if (control_grab || tab_grab){
if ((keyQt & 0xffff) == Qt::Key_Escape){
XUngrabKeyboard(qt_xdisplay(), kwin_time);
XUngrabPointer( qt_xdisplay(), kwin_time);
XUngrabKeyboard(qt_xdisplay(), qt_x_time);
XUngrabPointer( qt_xdisplay(), qt_x_time);
tab_box->hide();
keys->setEnabled( true );
tab_grab = FALSE;
@ -1167,8 +1180,8 @@ bool Workspace::keyRelease(XKeyEvent& ev)
if( !release )
return FALSE;
if (tab_grab){
XUngrabPointer( qt_xdisplay(), kwin_time);
XUngrabKeyboard(qt_xdisplay(), kwin_time);
XUngrabPointer( qt_xdisplay(), qt_x_time);
XUngrabKeyboard(qt_xdisplay(), qt_x_time);
tab_box->hide();
keys->setEnabled( true );
tab_grab = false;
@ -1177,8 +1190,8 @@ bool Workspace::keyRelease(XKeyEvent& ev)
}
}
if (control_grab){
XUngrabPointer( qt_xdisplay(), kwin_time);
XUngrabKeyboard(qt_xdisplay(), kwin_time);
XUngrabPointer( qt_xdisplay(), qt_x_time);
XUngrabKeyboard(qt_xdisplay(), qt_x_time);
tab_box->hide();
keys->setEnabled( true );
control_grab = False;
@ -1394,6 +1407,7 @@ void Workspace::activateClient( Client* c, bool force )
if (!c->isOnDesktop(currentDesktop()) ) {
setCurrentDesktop( c->desktop() );
}
c->updateUserTime();
}
@ -2079,7 +2093,6 @@ void Workspace::lowerClient( Client* c )
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
new_stack[i++] = (*it)->winId();
}
// XRaiseWindow(qt_xdisplay(), new_stack[0]);
XRestackWindows(qt_xdisplay(), new_stack, i);
delete [] new_stack;
@ -2166,7 +2179,6 @@ void Workspace::raiseClient( Client* c )
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
new_stack[i++] = (*it)->winId();
}
// XRaiseWindow(qt_xdisplay(), new_stack[0]);
XRestackWindows(qt_xdisplay(), new_stack, i);
delete [] new_stack;
@ -2179,6 +2191,29 @@ void Workspace::raiseClient( Client* c )
raiseElectricBorders();
}
void Workspace::stackClientUnderActive( Client* c )
{
if ( !active_client || !c || active_client == c )
return;
ClientList::Iterator it = stacking_order.find( active_client );
if ( it == stacking_order.end() )
return;
stacking_order.remove( c );
stacking_order.insert( it, c );
stacking_order = constrainedStackingOrder( stacking_order );
Window* new_stack = new Window[ stacking_order.count() + 1 ];
int i = 0;
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
new_stack[i++] = (*it)->winId();
}
XRestackWindows(qt_xdisplay(), new_stack, i);
delete [] new_stack;
propagateClients( TRUE );
}
void Workspace::raiseOrLowerClient( Client *c)
{
if (!c) return;
@ -2264,7 +2299,7 @@ void Workspace::focusToNull(){
InputOnly, CopyFromParent, mask, &attr);
XMapWindow(qt_xdisplay(), null_focus_window);
}
XSetInputFocus(qt_xdisplay(), null_focus_window, RevertToPointerRoot, kwin_time );
XSetInputFocus(qt_xdisplay(), null_focus_window, RevertToPointerRoot, qt_x_time );
if( !block_focus )
setActiveClient( NULL );
}
@ -2987,7 +3022,7 @@ void Workspace::slotMouseEmulation()
{
if ( mouse_emulation ) {
XUngrabKeyboard(qt_xdisplay(), kwin_time);
XUngrabKeyboard(qt_xdisplay(), qt_x_time);
mouse_emulation = FALSE;
return;
}
@ -2995,7 +3030,7 @@ void Workspace::slotMouseEmulation()
if ( XGrabKeyboard(qt_xdisplay(),
root, FALSE,
GrabModeAsync, GrabModeAsync,
kwin_time) == GrabSuccess ) {
qt_x_time) == GrabSuccess ) {
mouse_emulation = TRUE;
mouse_emulation_state = 0;
mouse_emulation_window = 0;
@ -3365,7 +3400,7 @@ unsigned int Workspace::sendFakedMouseEvent( QPoint pos, WId w, MouseEmulation t
e.window = w;
e.root = qt_xrootwin();
e.subwindow = w;
e.time = kwin_time;
e.time = qt_x_time;
e.x = x;
e.y = y;
e.x_root = pos.x();
@ -3379,7 +3414,7 @@ unsigned int Workspace::sendFakedMouseEvent( QPoint pos, WId w, MouseEmulation t
e.window = w;
e.root = qt_xrootwin();
e.subwindow = w;
e.time = kwin_time;
e.time = qt_x_time;
e.x = x;
e.y = y;
e.x_root = pos.x();
@ -3495,7 +3530,7 @@ bool Workspace::keyPressMouseEmulation( XKeyEvent& ev )
}
// fall through
case XK_Escape:
XUngrabKeyboard(qt_xdisplay(), kwin_time);
XUngrabKeyboard(qt_xdisplay(), qt_x_time);
mouse_emulation = FALSE;
return TRUE;
default:
@ -3657,7 +3692,7 @@ void Workspace::storeLegacySession( KConfig* config )
ev.xclient.message_type = atoms->wm_protocols;
ev.xclient.format = 32;
ev.xclient.data.l[0] = atoms->wm_save_yourself;
ev.xclient.data.l[1] = kwin_time;
ev.xclient.data.l[1] = qt_x_time;
XSelectInput(newdisplay, w, PropertyChangeMask|StructureNotifyMask);
XSendEvent(newdisplay, w, False, 0, &ev);
}
@ -4126,7 +4161,7 @@ void Workspace::focusEnsurance()
if ( !last_active_client )
last_active_client = topClientOnDesktop();
if ( last_active_client && last_active_client->isVisible() ) {
kwin_time = CurrentTime;
qt_x_time = CurrentTime;
requestFocus( last_active_client );
}
}

View file

@ -163,6 +163,7 @@ public:
QPoint adjustClientPosition( Client* c, QPoint pos );
void raiseClient( Client* c );
void lowerClient( Client* c );
void stackClientUnderActive( Client* );
void raiseOrLowerClient( Client * );
void reconfigure();