Experimental support for #36065 (dragging from a window shouldn't raise it).

Needs a Qt patch.

svn path=/trunk/kdebase/kwin/; revision=304194
This commit is contained in:
Luboš Luňák 2004-04-16 10:23:42 +00:00
parent 1f628f4a5b
commit f701524d4e
11 changed files with 165 additions and 71 deletions

View file

@ -297,45 +297,65 @@ void Workspace::activateClient( Client* c, bool force )
\sa Workspace::activateClient() \sa Workspace::activateClient()
*/ */
void Workspace::requestFocus( Client* c, bool force ) void Workspace::requestFocus( Client* c, bool force )
{ // the 'if( c == active_client ) return;' optimization mustn't be done here {
takeActivity( c, ActivityFocus | ( force ? ActivityFocusForce : 0 ), false);
}
void Workspace::takeActivity( Client* c, int flags, bool handled )
{
// the 'if( c == active_client ) return;' optimization mustn't be done here
if (!focusChangeEnabled() && ( c != active_client) ) if (!focusChangeEnabled() && ( c != active_client) )
return; flags &= ~ActivityFocus;
//TODO will be different for non-root clients. (subclassing?)
if ( !c ) if ( !c )
{ {
focusToNull(); focusToNull();
return; return;
} }
if( !c->isOnCurrentDesktop()) // shouldn't happen, call activateClient() if needed if( flags & ActivityFocus )
{ {
kdWarning( 1212 ) << "requestFocus: not on current desktop" << endl; Client* modal = c->findModal();
return; if( modal != NULL && modal != c )
{
if( !modal->isOnDesktop( c->desktop()))
modal->setDesktop( c->desktop());
// if the click was inside the window (i.e. handled is set),
// but it has a modal, there's no need to use handled mode, because
// the modal doesn't get the click anyway
// raising of the original window needs to be still done
if( flags & ActivityRaise )
raiseClient( c );
flags &= ~ActivityRaise;
c = modal;
handled = false;
}
} }
if ( !( flags & ActivityFocusForce ) && ( c->isTopMenu() || c->isDock() || c->isSplash()) )
Client* modal = c->findModal(); flags &= ~ActivityFocus; // toplevel menus and dock windows don't take focus if not forced
if( modal != NULL && modal != c ) if( c->isShade())
{
if( !modal->isOnDesktop( c->desktop())) // move the modal to client's desktop
modal->setDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop());
requestFocus( modal, force );
return;
}
if ( c->isShown( false ) )
{
c->takeFocus( force, Allowed );
should_get_focus.append( c );
focus_chain.remove( c );
if ( c->wantsTabFocus() )
focus_chain.append( c );
}
else if ( c->isShade() && c->wantsInput())
{ {
if( c->wantsInput() && ( flags & ActivityFocus ))
{
// client cannot accept focus, but at least the window should be active (window menu, et. al. ) // client cannot accept focus, but at least the window should be active (window menu, et. al. )
c->setActive( true ); c->setActive( true );
focusToNull(); focusToNull();
}
flags &= ~ActivityFocus;
handled = false; // no point, can't get clicks
} }
if( !c->isShown( true )) // shouldn't happen, call activateClient() if needed
{
kdWarning( 1212 ) << "takeActivity: not shown" << endl;
return;
}
c->takeActivity( flags, handled, Allowed );
}
void Workspace::handleActivityRaise( Client* c, Time timestamp )
{
if( last_restack == CurrentTime || timestampCompare( timestamp, last_restack ) >= 0 )
raiseClient( c );
} }
/*! /*!
@ -415,6 +435,10 @@ void Workspace::gotFocusIn( const Client* c )
} }
} }
void Workspace::setShouldGetFocus( Client* c )
{
should_get_focus.append( c );
}
// focus_in -> the window got FocusIn event // focus_in -> the window got FocusIn event
// session_active -> the window was active when saving session // session_active -> the window was active when saving session

View file

@ -18,7 +18,7 @@ namespace KWinInternal
Atoms::Atoms() Atoms::Atoms()
{ {
const int max = 20; const int max = 50;
Atom* atoms[max]; Atom* atoms[max];
char* names[max]; char* names[max];
Atom atoms_return[max]; Atom atoms_return[max];
@ -61,6 +61,9 @@ Atoms::Atoms()
atoms[n] = &kde_system_tray_embedding; atoms[n] = &kde_system_tray_embedding;
names[n++] = (char*) "_KDE_SYSTEM_TRAY_EMBEDDING"; names[n++] = (char*) "_KDE_SYSTEM_TRAY_EMBEDDING";
atoms[n] = &net_wm_take_activity;
names[n++] = (char*) "_NET_WM_TAKE_ACTIVITY";
Atom fake; Atom fake;
atoms[n] = &fake; atoms[n] = &fake;

View file

@ -36,6 +36,7 @@ class Atoms
Atom net_wm_user_time; Atom net_wm_user_time;
Atom kde_net_wm_user_creation_time; Atom kde_net_wm_user_creation_time;
Atom kde_system_tray_embedding; Atom kde_system_tray_embedding;
Atom net_wm_take_activity;
}; };

View file

@ -128,6 +128,7 @@ Client::Client( Workspace *ws )
Pdeletewindow = 0; Pdeletewindow = 0;
Ptakefocus = 0; Ptakefocus = 0;
Ptakeactivity = 0;
Pcontexthelp = 0; Pcontexthelp = 0;
Pping = 0; Pping = 0;
input = FALSE; input = FALSE;
@ -871,7 +872,7 @@ void Client::rawHide()
workspace()->clientHidden( this ); workspace()->clientHidden( this );
} }
static void sendClientMessage(Window w, Atom a, long x) void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long data2, long data3)
{ {
XEvent ev; XEvent ev;
long mask; long mask;
@ -881,8 +882,11 @@ static void sendClientMessage(Window w, Atom a, long x)
ev.xclient.window = w; ev.xclient.window = w;
ev.xclient.message_type = a; ev.xclient.message_type = a;
ev.xclient.format = 32; ev.xclient.format = 32;
ev.xclient.data.l[0] = x; ev.xclient.data.l[0] = protocol;
ev.xclient.data.l[1] = qt_x_time; ev.xclient.data.l[1] = qt_x_time;
ev.xclient.data.l[2] = data1;
ev.xclient.data.l[3] = data2;
ev.xclient.data.l[4] = data3;
mask = 0L; mask = 0L;
if (w == qt_xrootwin()) if (w == qt_xrootwin())
mask = SubstructureRedirectMask; /* magic! */ mask = SubstructureRedirectMask; /* magic! */
@ -1101,15 +1105,43 @@ bool Client::isOnCurrentDesktop() const
return isOnDesktop( workspace()->currentDesktop()); return isOnDesktop( workspace()->currentDesktop());
} }
/*! // performs activation and/or raising of the window
Puts the focus on this window. Clients should never calls this void Client::takeActivity( int flags, bool handled, allowed_t )
themselves, instead they should use Workspace::requestFocus().
*/
void Client::takeFocus( bool force, allowed_t )
{ {
if ( !force && ( isTopMenu() || isDock() || isSplash()) ) if( !handled || !Ptakeactivity )
return; // toplevel menus and dock windows don't take focus if not forced {
if( flags & ActivityFocus )
takeFocus( Allowed );
if( flags & ActivityRaise )
workspace()->raiseClient( this );
return;
}
#ifndef NDEBUG
static Time previous_activity_timestamp;
static Client* previous_client;
if( previous_activity_timestamp == qt_x_time && previous_client != this )
{
kdWarning( 1212 ) << "Repeated use of the same X timestamp for activity" << endl;
kdDebug( 1212 ) << kdBacktrace() << endl;
}
previous_activity_timestamp = qt_x_time;
previous_client = this;
#endif
int flg = 0;
if( flags & ActivityFocus )
{
flg |= 1 << 0;
workspace()->setShouldGetFocus( this );
}
if( flags & ActivityRaise )
flg |= 1 << 1;
sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_take_activity, flg );
}
// performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS
void Client::takeFocus( allowed_t )
{
#ifndef NDEBUG #ifndef NDEBUG
static Time previous_focus_timestamp; static Time previous_focus_timestamp;
static Client* previous_client; static Client* previous_client;
@ -1127,6 +1159,7 @@ void Client::takeFocus( bool force, allowed_t )
} }
if ( Ptakefocus ) if ( Ptakefocus )
sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus); sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
workspace()->setShouldGetFocus( this );
} }
/*! /*!
@ -1299,6 +1332,7 @@ void Client::getWindowProtocols()
Pdeletewindow = 0; Pdeletewindow = 0;
Ptakefocus = 0; Ptakefocus = 0;
Ptakeactivity = 0;
Pcontexthelp = 0; Pcontexthelp = 0;
Pping = 0; Pping = 0;
@ -1309,6 +1343,8 @@ void Client::getWindowProtocols()
Pdeletewindow = 1; Pdeletewindow = 1;
else if (p[i] == atoms->wm_take_focus) else if (p[i] == atoms->wm_take_focus)
Ptakefocus = 1; Ptakefocus = 1;
else if (p[i] == atoms->net_wm_take_activity)
Ptakeactivity = 1;
else if (p[i] == atoms->net_wm_context_help) else if (p[i] == atoms->net_wm_context_help)
Pcontexthelp = 1; Pcontexthelp = 1;
else if (p[i] == atoms->net_wm_ping) else if (p[i] == atoms->net_wm_ping)
@ -1462,7 +1498,7 @@ bool Client::wantsTabFocus() const
bool Client::wantsInput() const bool Client::wantsInput() const
{ {
return input; return input || Ptakefocus;
} }
/*! /*!
@ -1647,10 +1683,9 @@ void Client::updateAllowedActions( bool force )
void Client::autoRaise() void Client::autoRaise()
{ {
workspace()->raiseClient( this ); workspace()->raiseClient( this );
delete autoRaiseTimer; cancelAutoRaise();
autoRaiseTimer = 0;
} }
void Client::cancelAutoRaise() void Client::cancelAutoRaise()
{ {
delete autoRaiseTimer; delete autoRaiseTimer;

View file

@ -186,7 +186,8 @@ class Client : public QObject, public KDecorationDefines
bool isResizable() const; bool isResizable() const;
bool isCloseable() const; // may be closed by the user (may have a close button) bool isCloseable() const; // may be closed by the user (may have a close button)
void takeFocus( bool force, allowed_t ); void takeActivity( int flags, bool handled, allowed_t ); // takes ActivityFlags as arg (in utils.h)
void takeFocus( allowed_t );
void demandAttention( bool set = true ); void demandAttention( bool set = true );
void setMask( const QRegion& r, int mode = X::Unsorted ); void setMask( const QRegion& r, int mode = X::Unsorted );
@ -215,7 +216,7 @@ class Client : public QObject, public KDecorationDefines
bool providesContextHelp() const; bool providesContextHelp() const;
bool performMouseCommand( Options::MouseCommand, QPoint globalPos ); bool performMouseCommand( Options::MouseCommand, QPoint globalPos, bool handled = false );
QCString windowRole() const; QCString windowRole() const;
QCString sessionId(); QCString sessionId();
@ -366,6 +367,8 @@ private slots:
void pingWindow(); void pingWindow();
void killProcess( bool ask, Time timestamp = CurrentTime ); void killProcess( bool ask, Time timestamp = CurrentTime );
void updateUrgency(); void updateUrgency();
static void sendClientMessage( Window w, Atom a, Atom protocol,
long data1 = 0, long data2 = 0, long data3 = 0 );
void embedClient( Window w, const XWindowAttributes &attr ); void embedClient( Window w, const XWindowAttributes &attr );
void detectNoBorder(); void detectNoBorder();
@ -430,6 +433,7 @@ private slots:
uint original_skip_taskbar :1; // unaffected by KWin uint original_skip_taskbar :1; // unaffected by KWin
uint Pdeletewindow :1; // does the window understand the DeleteWindow protocol? uint Pdeletewindow :1; // does the window understand the DeleteWindow protocol?
uint Ptakefocus :1;// does the window understand the TakeFocus protocol? uint Ptakefocus :1;// does the window understand the TakeFocus protocol?
uint Ptakeactivity : 1; // does it support _NET_WM_TAKE_ACTIVITY
uint Pcontexthelp : 1; // does the window understand the ContextHelp protocol? uint Pcontexthelp : 1; // does the window understand the ContextHelp protocol?
uint Pping : 1; // does it support _NET_WM_PING? uint Pping : 1; // does it support _NET_WM_PING?
uint input :1; // does the window want input in its wm_hints uint input :1; // does the window want input in its wm_hints

View file

@ -110,8 +110,8 @@ void RootInfo::changeActiveWindow( Window w, NET::RequestSource src, Time timest
{ {
if( timestamp == CurrentTime ) if( timestamp == CurrentTime )
timestamp = c->userTime(); timestamp = c->userTime();
if( src == NET::FromUnknown ) if( src != NET::FromApplication && src != NET::FromActivity && src != FromTool )
src = NET::FromTool; // KWIN_FOCUS, use qt_x_time as timestamp? src = NET::FromTool;
if( src == NET::FromTool ) if( src == NET::FromTool )
workspace->activateClient( c ); workspace->activateClient( c );
else // NET::FromApplication else // NET::FromApplication
@ -131,6 +131,21 @@ void RootInfo::changeActiveWindow( Window w, NET::RequestSource src, Time timest
} }
} }
void RootInfo::restackWindow( Window w, RequestSource src, Window above, int detail, Time timestamp )
{
if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
{
if( timestamp == CurrentTime )
timestamp = c->userTime();
if( src != NET::FromApplication && src != NET::FromActivity && src != FromTool )
src = NET::FromTool;
if( src == NET::FromActivity )
workspace->handleActivityRaise( c, timestamp );
else
c->restackWindow( above, detail, src, timestamp, true );
}
}
void RootInfo::closeWindow(Window w) void RootInfo::closeWindow(Window w)
{ {
Client* c = workspace->findClient( WindowMatchPredicate( w )); Client* c = workspace->findClient( WindowMatchPredicate( w ));
@ -161,12 +176,6 @@ void RootInfo::gotPing( Window w, Time timestamp )
c->gotPing( timestamp ); c->gotPing( timestamp );
} }
void RootInfo::restackWindow( Window w, RequestSource source, Window above, int detail, Time timestamp )
{
if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
c->restackWindow( above, detail, source, timestamp, true );
}
// **************************************** // ****************************************
// Workspace // Workspace
// **************************************** // ****************************************
@ -1089,15 +1098,9 @@ bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, in
return true; return true;
} }
if ( isActive() && w == wrapperId()
&& ( options->clickRaise && !bModKeyHeld ) )
{
if ( button < 4 ) // exclude wheel
autoRaise();
}
Options::MouseCommand com = Options::MouseNothing; Options::MouseCommand com = Options::MouseNothing;
bool was_action = false; bool was_action = false;
bool perform_handled = false;
if ( bModKeyHeld ) if ( bModKeyHeld )
{ {
was_action = true; was_action = true;
@ -1119,6 +1122,7 @@ bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, in
if( !isActive() && w == wrapperId()) if( !isActive() && w == wrapperId())
{ {
was_action = true; was_action = true;
perform_handled = true;
switch (button) switch (button)
{ {
case Button1: case Button1:
@ -1134,10 +1138,18 @@ bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, in
com = Options::MouseActivateAndPassClick; com = Options::MouseActivateAndPassClick;
} }
} }
// active inner window
if( isActive() && w == wrapperId()
&& options->clickRaise && button < 4 ) // exclude wheel
{
com = Options::MouseActivateAndPassClick;
was_action = true;
perform_handled = true;
}
} }
if( was_action ) if( was_action )
{ {
bool replay = performMouseCommand( com, QPoint( x_root, y_root) ); bool replay = performMouseCommand( com, QPoint( x_root, y_root), perform_handled );
if ( isSpecialWindow() && !isOverride()) if ( isSpecialWindow() && !isOverride())
replay = TRUE; replay = TRUE;

View file

@ -72,6 +72,8 @@ License. See the file "COPYING" for the exact licensing terms.
#include "group.h" #include "group.h"
#include <kdebug.h> #include <kdebug.h>
extern Time qt_x_time;
namespace KWinInternal namespace KWinInternal
{ {
@ -337,7 +339,10 @@ void Workspace::raiseClient( Client* c )
unconstrained_stacking_order.append( c ); unconstrained_stacking_order.append( c );
if( !c->isSpecialWindow()) if( !c->isSpecialWindow())
{
most_recently_raised = c; most_recently_raised = c;
last_restack = qt_x_time;
}
} }
void Workspace::raiseClientWithinApplication( Client* c ) void Workspace::raiseClientWithinApplication( Client* c )

View file

@ -292,7 +292,7 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
/*! /*!
Performs a mouse command on this client (see options.h) Performs a mouse command on this client (see options.h)
*/ */
bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPos) bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPos, bool handled )
{ {
bool replay = FALSE; bool replay = FALSE;
switch (command) switch (command)
@ -316,8 +316,7 @@ bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPo
break; break;
case Options::MouseActivateAndRaise: case Options::MouseActivateAndRaise:
replay = isActive(); // for clickraise mode replay = isActive(); // for clickraise mode
workspace()->requestFocus( this ); workspace()->takeActivity( this, ActivityFocus | ActivityRaise, handled && replay );
workspace()->raiseClient( this );
break; break;
case Options::MouseActivateAndLower: case Options::MouseActivateAndLower:
workspace()->requestFocus( this ); workspace()->requestFocus( this );
@ -325,15 +324,14 @@ bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPo
break; break;
case Options::MouseActivate: case Options::MouseActivate:
replay = isActive(); // for clickraise mode replay = isActive(); // for clickraise mode
workspace()->requestFocus( this ); workspace()->takeActivity( this, ActivityFocus, handled && replay );
break; break;
case Options::MouseActivateRaiseAndPassClick: case Options::MouseActivateRaiseAndPassClick:
workspace()->requestFocus( this ); workspace()->takeActivity( this, ActivityFocus | ActivityRaise, handled );
workspace()->raiseClient( this );
replay = TRUE; replay = TRUE;
break; break;
case Options::MouseActivateAndPassClick: case Options::MouseActivateAndPassClick:
workspace()->requestFocus( this ); workspace()->takeActivity( this, ActivityFocus, handled );
replay = TRUE; replay = TRUE;
break; break;
case Options::MouseActivateRaiseAndMove: case Options::MouseActivateRaiseAndMove:

View file

@ -66,6 +66,14 @@ inline void operator++( Layer& lay )
lay = static_cast< Layer >( lay + 1 ); lay = static_cast< Layer >( lay + 1 );
} }
// for Client::takeActivity()
enum ActivityFlags
{
ActivityFocus = 1 << 0, // focus the window
ActivityFocusForce = 1 << 1, // focus even if Dock etc.
ActivityRaise = 1 << 2 // raise the window
};
// Some KWin classes, mainly Client and Workspace, are very tighly coupled, // Some KWin classes, mainly Client and Workspace, are very tighly coupled,
// and some of the methods of one class may be called only from speficic places. // and some of the methods of one class may be called only from speficic places.
// Those methods have additional allowed_t argument. If you pass Allowed // Those methods have additional allowed_t argument. If you pass Allowed

View file

@ -69,6 +69,7 @@ Workspace::Workspace( bool restore )
last_active_client (0), last_active_client (0),
most_recently_raised (0), most_recently_raised (0),
movingClient(0), movingClient(0),
last_restack (CurrentTime),
was_user_interaction (false), was_user_interaction (false),
session_saving (false), session_saving (false),
control_grab (false), control_grab (false),

View file

@ -80,11 +80,6 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
template< typename T1, typename T2 > void forEachClient( T1 procedure, T2 predicate ); template< typename T1, typename T2 > void forEachClient( T1 procedure, T2 predicate );
template< typename T > void forEachClient( T procedure ); template< typename T > void forEachClient( T procedure );
Group* findGroup( Window leader ) const;
void addGroup( Group* group, allowed_t );
void removeGroup( Group* group, allowed_t );
Group* findClientLeaderGroup( const Client* c ) const;
QRect clientArea( clientAreaOption, const QPoint& p, int desktop ) const; QRect clientArea( clientAreaOption, const QPoint& p, int desktop ) const;
QRect clientArea( clientAreaOption, const Client* c ) const; QRect clientArea( clientAreaOption, const Client* c ) const;
@ -109,13 +104,15 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
// stealing prevention code. // stealing prevention code.
Client* mostRecentlyActivatedClient() const; Client* mostRecentlyActivatedClient() const;
void setActiveClient( Client*, allowed_t );
void activateClient( Client*, bool force = FALSE ); void activateClient( Client*, bool force = FALSE );
void requestFocus( Client* c, bool force = FALSE ); void requestFocus( Client* c, bool force = FALSE );
void takeActivity( Client* c, int flags, bool handled ); // flags are ActivityFlags
void handleActivityRaise( Client* c, Time timestamp );
bool allowClientActivation( const Client* c, Time time = -1U, bool focus_in = false, bool allowClientActivation( const Client* c, Time time = -1U, bool focus_in = false,
bool session_active = false ); bool session_active = false );
void restoreFocus(); void restoreFocus();
void gotFocusIn( const Client* ); void gotFocusIn( const Client* );
void setShouldGetFocus( Client* );
bool fakeRequestedActivity( Client* c ); bool fakeRequestedActivity( Client* c );
void unfakeActivity( Client* c ); void unfakeActivity( Client* c );
void activateNextClient( Client* c ); void activateNextClient( Client* c );
@ -218,6 +215,11 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
// only called from Client::destroyClient() or Client::releaseWindow() // only called from Client::destroyClient() or Client::releaseWindow()
void removeClient( Client*, allowed_t ); void removeClient( Client*, allowed_t );
void setActiveClient( Client*, allowed_t );
Group* findGroup( Window leader ) const;
void addGroup( Group* group, allowed_t );
void removeGroup( Group* group, allowed_t );
Group* findClientLeaderGroup( const Client* c ) const;
bool checkStartupNotification( Window w, KStartupInfoData& data ); bool checkStartupNotification( Window w, KStartupInfoData& data );
@ -424,6 +426,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
Client* last_active_client; Client* last_active_client;
Client* most_recently_raised; // used _only_ by raiseOrLowerClient() Client* most_recently_raised; // used _only_ by raiseOrLowerClient()
Client* movingClient; Client* movingClient;
Time last_restack;
ClientList clients; ClientList clients;
ClientList desktops; ClientList desktops;