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:
Matthias Ettrich 1999-11-28 20:10:58 +00:00
parent da39e14d75
commit bd1e4878ba
8 changed files with 184 additions and 56 deletions

View file

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

View file

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

View file

@ -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,7 +1519,8 @@ void Client::getWindowProtocols(){
*/
void Client::takeFocus()
{
XSetInputFocus( qt_xdisplay(), win, RevertToPointerRoot, CurrentTime );
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 )

View file

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

View file

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

View file

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

View file

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

View file

@ -98,6 +98,7 @@ public:
void makeFullScreen( Client* );
bool iconifyMeansWithdraw( Client* );
void iconifyOrDeiconifyTransientsOf( Client* );
public slots:
void setCurrentDesktop( int new_desktop );