keep transients together, support various input modes, handle
wm_change_state messages properly svn path=/trunk/kdebase/kwin/; revision=35353
This commit is contained in:
parent
da39e14d75
commit
bd1e4878ba
8 changed files with 184 additions and 56 deletions
58
atoms.cpp
58
atoms.cpp
|
@ -4,21 +4,53 @@
|
|||
Atoms::Atoms()
|
||||
{
|
||||
|
||||
//TODO use XInternAtoms instead to avoid roundtrips
|
||||
wm_protocols = XInternAtom(qt_xdisplay(), "WM_PROTOCOLS", FALSE);
|
||||
wm_delete_window = XInternAtom(qt_xdisplay(), "WM_DELETE_WINDOW", FALSE);
|
||||
wm_take_focus = XInternAtom(qt_xdisplay(), "WM_TAKE_FOCUS", FALSE);
|
||||
const int max = 20;
|
||||
Atom* atoms[max];
|
||||
char* names[max];
|
||||
Atom atoms_return[max];
|
||||
int n = 0;
|
||||
|
||||
atoms[n] = &wm_protocols;
|
||||
names[n++] = "WM_PROTOCOLS";
|
||||
|
||||
atoms[n] = &wm_delete_window;
|
||||
names[n++] = "WM_DELETE_WINDOW";
|
||||
|
||||
atoms[n] = &wm_take_focus;
|
||||
names[n++] = "WM_TAKE_FOCUS";
|
||||
|
||||
atoms[n] = &wm_change_state;
|
||||
names[n++] = "WM_CHANGE_STATE";
|
||||
|
||||
// compatibility
|
||||
kwm_win_icon = XInternAtom(qt_xdisplay(), "KWM_WIN_ICON", FALSE);
|
||||
kwm_running = XInternAtom(qt_xdisplay(), "KWM_RUNNING", FALSE);
|
||||
atoms[n] = &kwm_win_icon;
|
||||
names[n++] = "KWM_WIN_ICON";
|
||||
|
||||
// compatibility
|
||||
atoms[n] = &kwm_running;
|
||||
names[n++] = "KWM_RUNNING";
|
||||
|
||||
atoms[n] = &net_number_of_desktops;
|
||||
names[n++] = "_NET_NUMBER_OF_DESKTOPS";
|
||||
|
||||
atoms[n] = &net_current_desktop;
|
||||
names[n++] = "_NET_CURRENT_DESKTOP";
|
||||
|
||||
atoms[n] = &net_active_window;
|
||||
names[n++] = "_NET_ACTIVE_WINDOW";
|
||||
|
||||
atoms[n] = &net_client_list;
|
||||
names[n++] = "_NET_CLIENT_LIST";
|
||||
|
||||
atoms[n] = &net_client_list_stacking;
|
||||
names[n++] = "_NET_CLIENT_LIST_STACKING";
|
||||
|
||||
atoms[n] = &net_kde_docking_windows;
|
||||
names[n++] = "_NET_KDE_DOCKING_WINDOWS";
|
||||
|
||||
XInternAtoms( qt_xdisplay(), names, n, FALSE, atoms_return );
|
||||
for (int i = 0; i < n; i++ )
|
||||
*atoms[i] = atoms_return[i];
|
||||
|
||||
|
||||
net_number_of_desktops = XInternAtom(qt_xdisplay(), "_NET_NUMBER_OF_DESKTOPS", False);
|
||||
net_current_desktop = XInternAtom(qt_xdisplay(), "_NET_CURRENT_DESKTOP", False);
|
||||
net_active_window = XInternAtom(qt_xdisplay(), "_NET_ACTIVE_WINDOW", False);
|
||||
|
||||
net_client_list = XInternAtom(qt_xdisplay(), "_NET_CLIENT_LIST", False);
|
||||
net_client_list_stacking = XInternAtom(qt_xdisplay(), "_NET_CLIENT_LIST_STACKIN", False);
|
||||
net_kde_docking_windows = XInternAtom(qt_xdisplay(), "_NET_KDE_DOCKING_WINDOWS", False);
|
||||
}
|
||||
|
|
1
atoms.h
1
atoms.h
|
@ -9,6 +9,7 @@ public:
|
|||
Atom wm_protocols;
|
||||
Atom wm_delete_window;
|
||||
Atom wm_take_focus;
|
||||
Atom wm_change_state;
|
||||
Atom kwm_win_icon; // compatibility
|
||||
Atom kwm_running;
|
||||
|
||||
|
|
57
client.cpp
57
client.cpp
|
@ -289,7 +289,7 @@ Client::Client( Workspace *ws, WId w, QWidget *parent, const char *name, WFlags
|
|||
is_shape = FALSE;
|
||||
is_sticky = FALSE;
|
||||
|
||||
getIcons();
|
||||
getWMHints();
|
||||
getWindowProtocols();
|
||||
getWmNormalHints(); // get xSizeHint
|
||||
fetchName();
|
||||
|
@ -481,6 +481,8 @@ bool Client::windowEvent( XEvent * e)
|
|||
break;
|
||||
case ReparentNotify:
|
||||
break;
|
||||
case ClientMessage:
|
||||
return clientMessage( e->xclient );
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -632,13 +634,13 @@ bool Client::propertyNotify( XPropertyEvent& e )
|
|||
transient_for = None;
|
||||
break;
|
||||
case XA_WM_HINTS:
|
||||
getIcons();
|
||||
getWMHints();
|
||||
break;
|
||||
default:
|
||||
if ( e.atom == atoms->wm_protocols )
|
||||
getWindowProtocols();
|
||||
else if ( e.atom == atoms->kwm_win_icon ) {
|
||||
getIcons();
|
||||
getWMHints(); // for the icons
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -647,6 +649,24 @@ bool Client::propertyNotify( XPropertyEvent& e )
|
|||
}
|
||||
|
||||
|
||||
/*!
|
||||
Handles client messages for the client window
|
||||
*/
|
||||
bool Client::clientMessage( XClientMessageEvent& e )
|
||||
{
|
||||
if ( e.message_type == atoms->wm_change_state) {
|
||||
if ( e.data.l[0] == IconicState && isNormal() )
|
||||
iconify();
|
||||
return TRUE;
|
||||
} else if ( e.message_type == atoms->net_active_window ) {
|
||||
workspace()->activateClient( this );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Auxiliary function to inform the client about the current window
|
||||
configuration.
|
||||
|
@ -1125,6 +1145,7 @@ void Client::iconify()
|
|||
setMappingState( IconicState );
|
||||
hide();
|
||||
// TODO animation (virtual function)
|
||||
workspace()->iconifyOrDeiconifyTransientsOf( this );
|
||||
}
|
||||
|
||||
void Client::closeWindow()
|
||||
|
@ -1458,12 +1479,20 @@ void Client::setDesktop( int desktop)
|
|||
KWM::moveToDesktop( win, desk );//##### compatibility
|
||||
}
|
||||
|
||||
void Client::getIcons()
|
||||
void Client::getWMHints()
|
||||
{
|
||||
icon_pix = KWM::icon( win, 32, 32 ); // TODO sizes from workspace
|
||||
miniicon_pix = KWM::miniIcon( win, 16, 16 );
|
||||
if ( !isWithdrawn() )
|
||||
iconChange();
|
||||
|
||||
input = TRUE;
|
||||
XWMHints *hints = XGetWMHints(qt_xdisplay(), win );
|
||||
if ( hints ) {
|
||||
if ( hints->flags & InputHint )
|
||||
input = hints->input;
|
||||
XFree((char*)hints);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::getWindowProtocols(){
|
||||
|
@ -1490,6 +1519,7 @@ void Client::getWindowProtocols(){
|
|||
*/
|
||||
void Client::takeFocus()
|
||||
{
|
||||
if ( input )
|
||||
XSetInputFocus( qt_xdisplay(), win, RevertToPointerRoot, CurrentTime );
|
||||
if ( Ptakefocus )
|
||||
sendClientMessage(win, atoms->wm_protocols, atoms->wm_take_focus);
|
||||
|
@ -1505,6 +1535,25 @@ void Client::setMask( const QRegion & reg)
|
|||
}
|
||||
|
||||
|
||||
/*!
|
||||
Returns the main client. For normal windows, this is the window
|
||||
itself. For transient windows, it is the parent.
|
||||
|
||||
*/
|
||||
Client* Client::mainClient()
|
||||
{
|
||||
if ( !isTransient() )
|
||||
return this;
|
||||
ClientList saveset;
|
||||
Client* c = this;
|
||||
do {
|
||||
saveset.append( c );
|
||||
c = workspace()->findClient( c->transientFor() );
|
||||
} while ( c && c->isTransient() && !saveset.contains( c ) );
|
||||
|
||||
return c?c:this;
|
||||
}
|
||||
|
||||
|
||||
NoBorderClient::NoBorderClient( Workspace *ws, WId w, QWidget *parent, const char *name )
|
||||
: Client( ws, w, parent, name )
|
||||
|
|
33
client.h
33
client.h
|
@ -20,7 +20,7 @@ public:
|
|||
WindowWrapper( WId w, Client *parent=0, const char* name=0);
|
||||
~WindowWrapper();
|
||||
|
||||
inline WId window() const;
|
||||
WId window() const;
|
||||
void releaseWindow();
|
||||
void invalidateWindow();
|
||||
QSize sizeHint() const;
|
||||
|
@ -56,12 +56,14 @@ public:
|
|||
Client( Workspace *ws, WId w, QWidget *parent=0, const char *name=0, WFlags f = 0);
|
||||
~Client();
|
||||
|
||||
inline WId window() const;
|
||||
inline WindowWrapper* windowWrapper() const;
|
||||
inline Workspace* workspace() const;
|
||||
WId window() const;
|
||||
WindowWrapper* windowWrapper() const;
|
||||
Workspace* workspace() const;
|
||||
void releaseWindow();
|
||||
void invalidateWindow();
|
||||
inline WId transientFor() const;
|
||||
WId transientFor() const;
|
||||
bool isTransient() const;
|
||||
Client* mainClient();
|
||||
|
||||
virtual bool windowEvent( XEvent * );
|
||||
|
||||
|
@ -81,8 +83,8 @@ public:
|
|||
int maximumWidth() const;
|
||||
int maximumHeight() const;
|
||||
|
||||
inline QPixmap icon() const;
|
||||
inline QPixmap miniIcon() const;
|
||||
QPixmap icon() const;
|
||||
QPixmap miniIcon() const;
|
||||
|
||||
|
||||
// is the window in withdrawn state?
|
||||
|
@ -98,7 +100,7 @@ public:
|
|||
return state == NormalState;
|
||||
}
|
||||
|
||||
inline bool isActive() const;
|
||||
bool isActive() const;
|
||||
void setActive( bool );
|
||||
|
||||
int desktop() const;
|
||||
|
@ -108,10 +110,10 @@ public:
|
|||
bool isShade() const;
|
||||
virtual void setShade( bool );
|
||||
|
||||
inline bool isMaximized() const;
|
||||
bool isMaximized() const;
|
||||
enum MaximizeMode { MaximizeVertical, MaximizeHorizontal, MaximizeFull };
|
||||
|
||||
inline bool isSticky() const;
|
||||
bool isSticky() const;
|
||||
void setSticky( bool );
|
||||
|
||||
void takeFocus();
|
||||
|
@ -183,6 +185,7 @@ protected:
|
|||
bool unmapNotify( XUnmapEvent& e );
|
||||
bool configureRequest( XConfigureRequestEvent& e );
|
||||
bool propertyNotify( XPropertyEvent& e );
|
||||
bool clientMessage( XClientMessageEvent& e );
|
||||
|
||||
private:
|
||||
QSize sizeForWindowSize( const QSize&, bool ignore_height = FALSE ) const;
|
||||
|
@ -217,10 +220,11 @@ private:
|
|||
WId transient_for;
|
||||
bool is_sticky;
|
||||
bool is_shape;
|
||||
void getIcons();
|
||||
void getWMHints();
|
||||
void getWindowProtocols();
|
||||
uint Pdeletewindow :1; // does the window understand the DeleteWindow protocol?
|
||||
uint Ptakefocus :1;// does the window understand the TakeFocus protocol?
|
||||
uint input :1; // does the window want input in its wm_hints
|
||||
uint mapped :1; // keeps track of our visiblity within the asynchronous event flow
|
||||
QPixmap icon_pix;
|
||||
QPixmap miniicon_pix;
|
||||
|
@ -248,6 +252,13 @@ inline WId Client::transientFor() const
|
|||
return transient_for;
|
||||
}
|
||||
|
||||
inline bool Client::isTransient() const
|
||||
{
|
||||
return transient_for != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline int Client::mappingState() const
|
||||
{
|
||||
return state;
|
||||
|
|
|
@ -241,7 +241,7 @@ StdClient::StdClient( Workspace *ws, WId w, QWidget *parent, const char *name )
|
|||
button[1]->setIconSet(isSticky() ? isActive() ? *pindown_pix : *dis_pindown_pix :
|
||||
isActive() ? *pinup_pix : *dis_pinup_pix );
|
||||
connect( button[1], SIGNAL( clicked() ), this, ( SLOT( toggleSticky() ) ) );
|
||||
button[1]->hide(); // no sticky
|
||||
button[1]->hide(); // no sticky for now
|
||||
button[2]->hide();
|
||||
|
||||
button[3]->setIconSet(isActive() ? *minimize_pix : *dis_minimize_pix);
|
||||
|
@ -251,6 +251,13 @@ StdClient::StdClient( Workspace *ws, WId w, QWidget *parent, const char *name )
|
|||
button[5]->setIconSet(isActive() ? *close_pix : *dis_close_pix);
|
||||
connect( button[5], SIGNAL( clicked() ), this, ( SLOT( closeWindow() ) ) );
|
||||
|
||||
if ( isTransient() ) {
|
||||
// lighter decoration for transient windows
|
||||
button[1]->hide();
|
||||
button[2]->hide();
|
||||
button[3]->hide();
|
||||
button[4]->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void StdClient::activeChange(bool on)
|
||||
|
|
11
tabbox.cpp
11
tabbox.cpp
|
@ -51,8 +51,8 @@ void TabBox::reset()
|
|||
QFontMetrics fm( fontMetrics() );
|
||||
int cw = 0;
|
||||
while ( c ) {
|
||||
// TODO consider options_traverse_all
|
||||
if ( options_traverse_all ||c->isOnDesktop(workspace()->currentDesktop()) ) {
|
||||
if ( (options_traverse_all ||c->isOnDesktop(workspace()->currentDesktop()))
|
||||
&& (!c->isIconified() || c->mainClient() == c ) ) {
|
||||
if ( client == c )
|
||||
clients.prepend( c );
|
||||
else
|
||||
|
@ -94,8 +94,11 @@ void TabBox::nextPrev( bool next)
|
|||
else
|
||||
client = workspace()->previousClient(client);
|
||||
} while (client != sign && client &&
|
||||
!options_traverse_all &&
|
||||
!client->isOnDesktop(workspace()->currentDesktop()));
|
||||
( !options_traverse_all && !client->isOnDesktop(workspace()->currentDesktop()) )
|
||||
||
|
||||
( client->isIconified() && client->mainClient() != client )
|
||||
);
|
||||
|
||||
|
||||
if (!options_traverse_all && client
|
||||
&& !client->isOnDesktop(workspace()->currentDesktop()))
|
||||
|
|
|
@ -747,10 +747,31 @@ void Workspace::activateClient( Client* c)
|
|||
}
|
||||
raiseClient( c );
|
||||
c->show();
|
||||
iconifyOrDeiconifyTransientsOf( c );
|
||||
if ( options->focusPolicyIsReasonable() )
|
||||
requestFocus( c );
|
||||
}
|
||||
|
||||
void Workspace::iconifyOrDeiconifyTransientsOf( Client* c )
|
||||
{
|
||||
if ( c->isIconified() ) {
|
||||
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
||||
if ( (*it)->transientFor() == c->window() && !(*it)->isIconified() ) {
|
||||
(*it)->setMappingState( IconicState );
|
||||
(*it)->hide();
|
||||
iconifyOrDeiconifyTransientsOf( (*it) );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
||||
if ( (*it)->transientFor() == c->window() && !(*it)->isVisible() ) {
|
||||
(*it)->show();
|
||||
iconifyOrDeiconifyTransientsOf( (*it) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Tries to activate the client by asking X for the input focus. This
|
||||
|
@ -1346,13 +1367,7 @@ void Workspace::setNumberOfDesktops( int n )
|
|||
*/
|
||||
bool Workspace::clientMessage( XClientMessageEvent msg )
|
||||
{
|
||||
if ( msg.message_type == atoms->net_active_window ) {
|
||||
Client * c = findClient( msg.data.l[0] );
|
||||
if ( c ) {
|
||||
activateClient( c );
|
||||
return TRUE;
|
||||
}
|
||||
} else if ( msg.message_type == atoms->net_current_desktop ) {
|
||||
if ( msg.message_type == atoms->net_current_desktop ) {
|
||||
setCurrentDesktop( msg.data.l[0] );
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1525,6 +1540,15 @@ void Workspace::sendToDesktop( int desk )
|
|||
|
||||
popup_client->setDesktop( desk );
|
||||
popup_client->hide();
|
||||
|
||||
Client* old = popup_client;
|
||||
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
||||
if ( (*it)->transientFor() == popup_client->window() ) {
|
||||
popup_client = *it;
|
||||
sendToDesktop( desk );
|
||||
popup_client = old;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace::slotWindowOperations()
|
||||
|
|
|
@ -98,6 +98,7 @@ public:
|
|||
void makeFullScreen( Client* );
|
||||
|
||||
bool iconifyMeansWithdraw( Client* );
|
||||
void iconifyOrDeiconifyTransientsOf( Client* );
|
||||
|
||||
public slots:
|
||||
void setCurrentDesktop( int new_desktop );
|
||||
|
|
Loading…
Reference in a new issue