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:
parent
1f628f4a5b
commit
f701524d4e
11 changed files with 165 additions and 71 deletions
|
@ -297,45 +297,65 @@ void Workspace::activateClient( Client* c, bool force )
|
|||
\sa Workspace::activateClient()
|
||||
*/
|
||||
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) )
|
||||
return;
|
||||
flags &= ~ActivityFocus;
|
||||
|
||||
//TODO will be different for non-root clients. (subclassing?)
|
||||
if ( !c )
|
||||
{
|
||||
focusToNull();
|
||||
return;
|
||||
}
|
||||
|
||||
if( !c->isOnCurrentDesktop()) // shouldn't happen, call activateClient() if needed
|
||||
if( flags & ActivityFocus )
|
||||
{
|
||||
kdWarning( 1212 ) << "requestFocus: not on current desktop" << endl;
|
||||
return;
|
||||
Client* modal = c->findModal();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Client* modal = c->findModal();
|
||||
if( modal != NULL && modal != c )
|
||||
{
|
||||
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 ( !( flags & ActivityFocusForce ) && ( c->isTopMenu() || c->isDock() || c->isSplash()) )
|
||||
flags &= ~ActivityFocus; // toplevel menus and dock windows don't take focus if not forced
|
||||
if( c->isShade())
|
||||
{
|
||||
if( c->wantsInput() && ( flags & ActivityFocus ))
|
||||
{
|
||||
// client cannot accept focus, but at least the window should be active (window menu, et. al. )
|
||||
c->setActive( true );
|
||||
focusToNull();
|
||||
c->setActive( true );
|
||||
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
|
||||
// session_active -> the window was active when saving session
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace KWinInternal
|
|||
Atoms::Atoms()
|
||||
{
|
||||
|
||||
const int max = 20;
|
||||
const int max = 50;
|
||||
Atom* atoms[max];
|
||||
char* names[max];
|
||||
Atom atoms_return[max];
|
||||
|
@ -61,6 +61,9 @@ Atoms::Atoms()
|
|||
|
||||
atoms[n] = &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;
|
||||
atoms[n] = &fake;
|
||||
|
|
1
atoms.h
1
atoms.h
|
@ -36,6 +36,7 @@ class Atoms
|
|||
Atom net_wm_user_time;
|
||||
Atom kde_net_wm_user_creation_time;
|
||||
Atom kde_system_tray_embedding;
|
||||
Atom net_wm_take_activity;
|
||||
};
|
||||
|
||||
|
||||
|
|
61
client.cpp
61
client.cpp
|
@ -128,6 +128,7 @@ Client::Client( Workspace *ws )
|
|||
|
||||
Pdeletewindow = 0;
|
||||
Ptakefocus = 0;
|
||||
Ptakeactivity = 0;
|
||||
Pcontexthelp = 0;
|
||||
Pping = 0;
|
||||
input = FALSE;
|
||||
|
@ -871,7 +872,7 @@ void Client::rawHide()
|
|||
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;
|
||||
long mask;
|
||||
|
@ -881,8 +882,11 @@ static void sendClientMessage(Window w, Atom a, long x)
|
|||
ev.xclient.window = w;
|
||||
ev.xclient.message_type = a;
|
||||
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[2] = data1;
|
||||
ev.xclient.data.l[3] = data2;
|
||||
ev.xclient.data.l[4] = data3;
|
||||
mask = 0L;
|
||||
if (w == qt_xrootwin())
|
||||
mask = SubstructureRedirectMask; /* magic! */
|
||||
|
@ -1101,15 +1105,43 @@ bool Client::isOnCurrentDesktop() const
|
|||
return isOnDesktop( workspace()->currentDesktop());
|
||||
}
|
||||
|
||||
/*!
|
||||
Puts the focus on this window. Clients should never calls this
|
||||
themselves, instead they should use Workspace::requestFocus().
|
||||
*/
|
||||
void Client::takeFocus( bool force, allowed_t )
|
||||
// performs activation and/or raising of the window
|
||||
void Client::takeActivity( int flags, bool handled, allowed_t )
|
||||
{
|
||||
if ( !force && ( isTopMenu() || isDock() || isSplash()) )
|
||||
return; // toplevel menus and dock windows don't take focus if not forced
|
||||
if( !handled || !Ptakeactivity )
|
||||
{
|
||||
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
|
||||
static Time previous_focus_timestamp;
|
||||
static Client* previous_client;
|
||||
|
@ -1127,6 +1159,7 @@ void Client::takeFocus( bool force, allowed_t )
|
|||
}
|
||||
if ( Ptakefocus )
|
||||
sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
|
||||
workspace()->setShouldGetFocus( this );
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1299,6 +1332,7 @@ void Client::getWindowProtocols()
|
|||
|
||||
Pdeletewindow = 0;
|
||||
Ptakefocus = 0;
|
||||
Ptakeactivity = 0;
|
||||
Pcontexthelp = 0;
|
||||
Pping = 0;
|
||||
|
||||
|
@ -1309,6 +1343,8 @@ void Client::getWindowProtocols()
|
|||
Pdeletewindow = 1;
|
||||
else if (p[i] == atoms->wm_take_focus)
|
||||
Ptakefocus = 1;
|
||||
else if (p[i] == atoms->net_wm_take_activity)
|
||||
Ptakeactivity = 1;
|
||||
else if (p[i] == atoms->net_wm_context_help)
|
||||
Pcontexthelp = 1;
|
||||
else if (p[i] == atoms->net_wm_ping)
|
||||
|
@ -1462,7 +1498,7 @@ bool Client::wantsTabFocus() const
|
|||
|
||||
bool Client::wantsInput() const
|
||||
{
|
||||
return input;
|
||||
return input || Ptakefocus;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1647,10 +1683,9 @@ void Client::updateAllowedActions( bool force )
|
|||
void Client::autoRaise()
|
||||
{
|
||||
workspace()->raiseClient( this );
|
||||
delete autoRaiseTimer;
|
||||
autoRaiseTimer = 0;
|
||||
cancelAutoRaise();
|
||||
}
|
||||
|
||||
|
||||
void Client::cancelAutoRaise()
|
||||
{
|
||||
delete autoRaiseTimer;
|
||||
|
|
8
client.h
8
client.h
|
@ -186,7 +186,8 @@ class Client : public QObject, public KDecorationDefines
|
|||
bool isResizable() const;
|
||||
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 setMask( const QRegion& r, int mode = X::Unsorted );
|
||||
|
@ -215,7 +216,7 @@ class Client : public QObject, public KDecorationDefines
|
|||
|
||||
bool providesContextHelp() const;
|
||||
|
||||
bool performMouseCommand( Options::MouseCommand, QPoint globalPos );
|
||||
bool performMouseCommand( Options::MouseCommand, QPoint globalPos, bool handled = false );
|
||||
|
||||
QCString windowRole() const;
|
||||
QCString sessionId();
|
||||
|
@ -366,6 +367,8 @@ private slots:
|
|||
void pingWindow();
|
||||
void killProcess( bool ask, Time timestamp = CurrentTime );
|
||||
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 detectNoBorder();
|
||||
|
@ -430,6 +433,7 @@ private slots:
|
|||
uint original_skip_taskbar :1; // unaffected by KWin
|
||||
uint Pdeletewindow :1; // does the window understand the DeleteWindow 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 Pping : 1; // does it support _NET_WM_PING?
|
||||
uint input :1; // does the window want input in its wm_hints
|
||||
|
|
44
events.cpp
44
events.cpp
|
@ -110,8 +110,8 @@ void RootInfo::changeActiveWindow( Window w, NET::RequestSource src, Time timest
|
|||
{
|
||||
if( timestamp == CurrentTime )
|
||||
timestamp = c->userTime();
|
||||
if( src == NET::FromUnknown )
|
||||
src = NET::FromTool; // KWIN_FOCUS, use qt_x_time as timestamp?
|
||||
if( src != NET::FromApplication && src != NET::FromActivity && src != FromTool )
|
||||
src = NET::FromTool;
|
||||
if( src == NET::FromTool )
|
||||
workspace->activateClient( c );
|
||||
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)
|
||||
{
|
||||
Client* c = workspace->findClient( WindowMatchPredicate( w ));
|
||||
|
@ -161,12 +176,6 @@ void RootInfo::gotPing( Window w, Time 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
|
||||
// ****************************************
|
||||
|
@ -1089,15 +1098,9 @@ bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, in
|
|||
return true;
|
||||
}
|
||||
|
||||
if ( isActive() && w == wrapperId()
|
||||
&& ( options->clickRaise && !bModKeyHeld ) )
|
||||
{
|
||||
if ( button < 4 ) // exclude wheel
|
||||
autoRaise();
|
||||
}
|
||||
|
||||
Options::MouseCommand com = Options::MouseNothing;
|
||||
bool was_action = false;
|
||||
bool perform_handled = false;
|
||||
if ( bModKeyHeld )
|
||||
{
|
||||
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())
|
||||
{
|
||||
was_action = true;
|
||||
perform_handled = true;
|
||||
switch (button)
|
||||
{
|
||||
case Button1:
|
||||
|
@ -1134,10 +1138,18 @@ bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, in
|
|||
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 )
|
||||
{
|
||||
bool replay = performMouseCommand( com, QPoint( x_root, y_root) );
|
||||
bool replay = performMouseCommand( com, QPoint( x_root, y_root), perform_handled );
|
||||
|
||||
if ( isSpecialWindow() && !isOverride())
|
||||
replay = TRUE;
|
||||
|
|
|
@ -72,6 +72,8 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#include "group.h"
|
||||
#include <kdebug.h>
|
||||
|
||||
extern Time qt_x_time;
|
||||
|
||||
namespace KWinInternal
|
||||
{
|
||||
|
||||
|
@ -337,7 +339,10 @@ void Workspace::raiseClient( Client* c )
|
|||
unconstrained_stacking_order.append( c );
|
||||
|
||||
if( !c->isSpecialWindow())
|
||||
{
|
||||
most_recently_raised = c;
|
||||
last_restack = qt_x_time;
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace::raiseClientWithinApplication( Client* c )
|
||||
|
|
|
@ -292,7 +292,7 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
|
|||
/*!
|
||||
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;
|
||||
switch (command)
|
||||
|
@ -316,8 +316,7 @@ bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPo
|
|||
break;
|
||||
case Options::MouseActivateAndRaise:
|
||||
replay = isActive(); // for clickraise mode
|
||||
workspace()->requestFocus( this );
|
||||
workspace()->raiseClient( this );
|
||||
workspace()->takeActivity( this, ActivityFocus | ActivityRaise, handled && replay );
|
||||
break;
|
||||
case Options::MouseActivateAndLower:
|
||||
workspace()->requestFocus( this );
|
||||
|
@ -325,15 +324,14 @@ bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPo
|
|||
break;
|
||||
case Options::MouseActivate:
|
||||
replay = isActive(); // for clickraise mode
|
||||
workspace()->requestFocus( this );
|
||||
workspace()->takeActivity( this, ActivityFocus, handled && replay );
|
||||
break;
|
||||
case Options::MouseActivateRaiseAndPassClick:
|
||||
workspace()->requestFocus( this );
|
||||
workspace()->raiseClient( this );
|
||||
workspace()->takeActivity( this, ActivityFocus | ActivityRaise, handled );
|
||||
replay = TRUE;
|
||||
break;
|
||||
case Options::MouseActivateAndPassClick:
|
||||
workspace()->requestFocus( this );
|
||||
workspace()->takeActivity( this, ActivityFocus, handled );
|
||||
replay = TRUE;
|
||||
break;
|
||||
case Options::MouseActivateRaiseAndMove:
|
||||
|
|
8
utils.h
8
utils.h
|
@ -66,6 +66,14 @@ inline void operator++( Layer& lay )
|
|||
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,
|
||||
// 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
|
||||
|
|
|
@ -69,6 +69,7 @@ Workspace::Workspace( bool restore )
|
|||
last_active_client (0),
|
||||
most_recently_raised (0),
|
||||
movingClient(0),
|
||||
last_restack (CurrentTime),
|
||||
was_user_interaction (false),
|
||||
session_saving (false),
|
||||
control_grab (false),
|
||||
|
|
15
workspace.h
15
workspace.h
|
@ -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 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 Client* c ) const;
|
||||
|
||||
|
@ -109,13 +104,15 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
|
|||
// stealing prevention code.
|
||||
Client* mostRecentlyActivatedClient() const;
|
||||
|
||||
void setActiveClient( Client*, allowed_t );
|
||||
void activateClient( Client*, 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 session_active = false );
|
||||
void restoreFocus();
|
||||
void gotFocusIn( const Client* );
|
||||
void setShouldGetFocus( Client* );
|
||||
bool fakeRequestedActivity( Client* c );
|
||||
void unfakeActivity( 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()
|
||||
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 );
|
||||
|
||||
|
@ -424,6 +426,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
|
|||
Client* last_active_client;
|
||||
Client* most_recently_raised; // used _only_ by raiseOrLowerClient()
|
||||
Client* movingClient;
|
||||
Time last_restack;
|
||||
|
||||
ClientList clients;
|
||||
ClientList desktops;
|
||||
|
|
Loading…
Reference in a new issue