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()
*/
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

View file

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

View file

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

View file

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

View file

@ -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

View file

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

View file

@ -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 )

View file

@ -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:

View file

@ -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

View file

@ -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),

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