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() Atoms::Atoms()
{ {
//TODO use XInternAtoms instead to avoid roundtrips const int max = 20;
wm_protocols = XInternAtom(qt_xdisplay(), "WM_PROTOCOLS", FALSE); Atom* atoms[max];
wm_delete_window = XInternAtom(qt_xdisplay(), "WM_DELETE_WINDOW", FALSE); char* names[max];
wm_take_focus = XInternAtom(qt_xdisplay(), "WM_TAKE_FOCUS", FALSE); 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 // compatibility
kwm_win_icon = XInternAtom(qt_xdisplay(), "KWM_WIN_ICON", FALSE); atoms[n] = &kwm_win_icon;
kwm_running = XInternAtom(qt_xdisplay(), "KWM_RUNNING", FALSE); names[n++] = "KWM_WIN_ICON";
// compatibility
net_number_of_desktops = XInternAtom(qt_xdisplay(), "_NET_NUMBER_OF_DESKTOPS", False); atoms[n] = &kwm_running;
net_current_desktop = XInternAtom(qt_xdisplay(), "_NET_CURRENT_DESKTOP", False); names[n++] = "KWM_RUNNING";
net_active_window = XInternAtom(qt_xdisplay(), "_NET_ACTIVE_WINDOW", False);
atoms[n] = &net_number_of_desktops;
net_client_list = XInternAtom(qt_xdisplay(), "_NET_CLIENT_LIST", False); names[n++] = "_NET_NUMBER_OF_DESKTOPS";
net_client_list_stacking = XInternAtom(qt_xdisplay(), "_NET_CLIENT_LIST_STACKIN", False);
net_kde_docking_windows = XInternAtom(qt_xdisplay(), "_NET_KDE_DOCKING_WINDOWS", False); 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];
} }

View file

@ -9,6 +9,7 @@ public:
Atom wm_protocols; Atom wm_protocols;
Atom wm_delete_window; Atom wm_delete_window;
Atom wm_take_focus; Atom wm_take_focus;
Atom wm_change_state;
Atom kwm_win_icon; // compatibility Atom kwm_win_icon; // compatibility
Atom kwm_running; 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_shape = FALSE;
is_sticky = FALSE; is_sticky = FALSE;
getIcons(); getWMHints();
getWindowProtocols(); getWindowProtocols();
getWmNormalHints(); // get xSizeHint getWmNormalHints(); // get xSizeHint
fetchName(); fetchName();
@ -481,6 +481,8 @@ bool Client::windowEvent( XEvent * e)
break; break;
case ReparentNotify: case ReparentNotify:
break; break;
case ClientMessage:
return clientMessage( e->xclient );
default: default:
break; break;
} }
@ -632,13 +634,13 @@ bool Client::propertyNotify( XPropertyEvent& e )
transient_for = None; transient_for = None;
break; break;
case XA_WM_HINTS: case XA_WM_HINTS:
getIcons(); getWMHints();
break; break;
default: default:
if ( e.atom == atoms->wm_protocols ) if ( e.atom == atoms->wm_protocols )
getWindowProtocols(); getWindowProtocols();
else if ( e.atom == atoms->kwm_win_icon ) { else if ( e.atom == atoms->kwm_win_icon ) {
getIcons(); getWMHints(); // for the icons
} }
break; 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 Auxiliary function to inform the client about the current window
configuration. configuration.
@ -1125,6 +1145,7 @@ void Client::iconify()
setMappingState( IconicState ); setMappingState( IconicState );
hide(); hide();
// TODO animation (virtual function) // TODO animation (virtual function)
workspace()->iconifyOrDeiconifyTransientsOf( this );
} }
void Client::closeWindow() void Client::closeWindow()
@ -1458,12 +1479,20 @@ void Client::setDesktop( int desktop)
KWM::moveToDesktop( win, desk );//##### compatibility KWM::moveToDesktop( win, desk );//##### compatibility
} }
void Client::getIcons() void Client::getWMHints()
{ {
icon_pix = KWM::icon( win, 32, 32 ); // TODO sizes from workspace icon_pix = KWM::icon( win, 32, 32 ); // TODO sizes from workspace
miniicon_pix = KWM::miniIcon( win, 16, 16 ); miniicon_pix = KWM::miniIcon( win, 16, 16 );
if ( !isWithdrawn() ) if ( !isWithdrawn() )
iconChange(); iconChange();
input = TRUE;
XWMHints *hints = XGetWMHints(qt_xdisplay(), win );
if ( hints ) {
if ( hints->flags & InputHint )
input = hints->input;
XFree((char*)hints);
}
} }
void Client::getWindowProtocols(){ void Client::getWindowProtocols(){
@ -1490,7 +1519,8 @@ void Client::getWindowProtocols(){
*/ */
void Client::takeFocus() void Client::takeFocus()
{ {
XSetInputFocus( qt_xdisplay(), win, RevertToPointerRoot, CurrentTime ); if ( input )
XSetInputFocus( qt_xdisplay(), win, RevertToPointerRoot, CurrentTime );
if ( Ptakefocus ) if ( Ptakefocus )
sendClientMessage(win, atoms->wm_protocols, atoms->wm_take_focus); 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 ) NoBorderClient::NoBorderClient( Workspace *ws, WId w, QWidget *parent, const char *name )
: Client( ws, w, parent, name ) : Client( ws, w, parent, name )

View file

@ -20,7 +20,7 @@ public:
WindowWrapper( WId w, Client *parent=0, const char* name=0); WindowWrapper( WId w, Client *parent=0, const char* name=0);
~WindowWrapper(); ~WindowWrapper();
inline WId window() const; WId window() const;
void releaseWindow(); void releaseWindow();
void invalidateWindow(); void invalidateWindow();
QSize sizeHint() const; QSize sizeHint() const;
@ -56,12 +56,14 @@ public:
Client( Workspace *ws, WId w, QWidget *parent=0, const char *name=0, WFlags f = 0); Client( Workspace *ws, WId w, QWidget *parent=0, const char *name=0, WFlags f = 0);
~Client(); ~Client();
inline WId window() const; WId window() const;
inline WindowWrapper* windowWrapper() const; WindowWrapper* windowWrapper() const;
inline Workspace* workspace() const; Workspace* workspace() const;
void releaseWindow(); void releaseWindow();
void invalidateWindow(); void invalidateWindow();
inline WId transientFor() const; WId transientFor() const;
bool isTransient() const;
Client* mainClient();
virtual bool windowEvent( XEvent * ); virtual bool windowEvent( XEvent * );
@ -81,8 +83,8 @@ public:
int maximumWidth() const; int maximumWidth() const;
int maximumHeight() const; int maximumHeight() const;
inline QPixmap icon() const; QPixmap icon() const;
inline QPixmap miniIcon() const; QPixmap miniIcon() const;
// is the window in withdrawn state? // is the window in withdrawn state?
@ -98,7 +100,7 @@ public:
return state == NormalState; return state == NormalState;
} }
inline bool isActive() const; bool isActive() const;
void setActive( bool ); void setActive( bool );
int desktop() const; int desktop() const;
@ -108,10 +110,10 @@ public:
bool isShade() const; bool isShade() const;
virtual void setShade( bool ); virtual void setShade( bool );
inline bool isMaximized() const; bool isMaximized() const;
enum MaximizeMode { MaximizeVertical, MaximizeHorizontal, MaximizeFull }; enum MaximizeMode { MaximizeVertical, MaximizeHorizontal, MaximizeFull };
inline bool isSticky() const; bool isSticky() const;
void setSticky( bool ); void setSticky( bool );
void takeFocus(); void takeFocus();
@ -183,6 +185,7 @@ protected:
bool unmapNotify( XUnmapEvent& e ); bool unmapNotify( XUnmapEvent& e );
bool configureRequest( XConfigureRequestEvent& e ); bool configureRequest( XConfigureRequestEvent& e );
bool propertyNotify( XPropertyEvent& e ); bool propertyNotify( XPropertyEvent& e );
bool clientMessage( XClientMessageEvent& e );
private: private:
QSize sizeForWindowSize( const QSize&, bool ignore_height = FALSE ) const; QSize sizeForWindowSize( const QSize&, bool ignore_height = FALSE ) const;
@ -217,10 +220,11 @@ private:
WId transient_for; WId transient_for;
bool is_sticky; bool is_sticky;
bool is_shape; bool is_shape;
void getIcons(); void getWMHints();
void getWindowProtocols(); void getWindowProtocols();
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 input :1; // does the window want input in its wm_hints
uint mapped :1; // keeps track of our visiblity within the asynchronous event flow uint mapped :1; // keeps track of our visiblity within the asynchronous event flow
QPixmap icon_pix; QPixmap icon_pix;
QPixmap miniicon_pix; QPixmap miniicon_pix;
@ -248,6 +252,13 @@ inline WId Client::transientFor() const
return transient_for; return transient_for;
} }
inline bool Client::isTransient() const
{
return transient_for != 0;
}
inline int Client::mappingState() const inline int Client::mappingState() const
{ {
return state; return state;

View file

@ -32,7 +32,7 @@ static QPixmap* dis_menu_pix = 0;
static bool pixmaps_created = FALSE; static bool pixmaps_created = FALSE;
static void create_pixmaps(); static void create_pixmaps();
QPixmap* kwin_get_menu_pix_hack() QPixmap* kwin_get_menu_pix_hack()
{ {
create_pixmaps(); create_pixmaps();
return menu_pix; return menu_pix;
@ -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 : button[1]->setIconSet(isSticky() ? isActive() ? *pindown_pix : *dis_pindown_pix :
isActive() ? *pinup_pix : *dis_pinup_pix ); isActive() ? *pinup_pix : *dis_pinup_pix );
connect( button[1], SIGNAL( clicked() ), this, ( SLOT( toggleSticky() ) ) ); connect( button[1], SIGNAL( clicked() ), this, ( SLOT( toggleSticky() ) ) );
button[1]->hide(); // no sticky button[1]->hide(); // no sticky for now
button[2]->hide(); button[2]->hide();
button[3]->setIconSet(isActive() ? *minimize_pix : *dis_minimize_pix); button[3]->setIconSet(isActive() ? *minimize_pix : *dis_minimize_pix);
@ -250,7 +250,14 @@ StdClient::StdClient( Workspace *ws, WId w, QWidget *parent, const char *name )
connect( button[4], SIGNAL( clicked(int) ), this, ( SLOT( maxButtonClicked(int) ) ) ); connect( button[4], SIGNAL( clicked(int) ), this, ( SLOT( maxButtonClicked(int) ) ) );
button[5]->setIconSet(isActive() ? *close_pix : *dis_close_pix); button[5]->setIconSet(isActive() ? *close_pix : *dis_close_pix);
connect( button[5], SIGNAL( clicked() ), this, ( SLOT( closeWindow() ) ) ); 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) void StdClient::activeChange(bool on)

View file

@ -51,8 +51,8 @@ void TabBox::reset()
QFontMetrics fm( fontMetrics() ); QFontMetrics fm( fontMetrics() );
int cw = 0; int cw = 0;
while ( c ) { 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 ) if ( client == c )
clients.prepend( c ); clients.prepend( c );
else else
@ -94,8 +94,11 @@ void TabBox::nextPrev( bool next)
else else
client = workspace()->previousClient(client); client = workspace()->previousClient(client);
} while (client != sign && client && } while (client != sign && client &&
!options_traverse_all && ( !options_traverse_all && !client->isOnDesktop(workspace()->currentDesktop()) )
!client->isOnDesktop(workspace()->currentDesktop())); ||
( client->isIconified() && client->mainClient() != client )
);
if (!options_traverse_all && client if (!options_traverse_all && client
&& !client->isOnDesktop(workspace()->currentDesktop())) && !client->isOnDesktop(workspace()->currentDesktop()))

View file

@ -747,10 +747,31 @@ void Workspace::activateClient( Client* c)
} }
raiseClient( c ); raiseClient( c );
c->show(); c->show();
iconifyOrDeiconifyTransientsOf( c );
if ( options->focusPolicyIsReasonable() ) if ( options->focusPolicyIsReasonable() )
requestFocus( c ); 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 Tries to activate the client by asking X for the input focus. This
@ -1346,17 +1367,11 @@ void Workspace::setNumberOfDesktops( int n )
*/ */
bool Workspace::clientMessage( XClientMessageEvent msg ) bool Workspace::clientMessage( XClientMessageEvent msg )
{ {
if ( msg.message_type == atoms->net_active_window ) { if ( msg.message_type == atoms->net_current_desktop ) {
Client * c = findClient( msg.data.l[0] );
if ( c ) {
activateClient( c );
return TRUE;
}
} else if ( msg.message_type == atoms->net_current_desktop ) {
setCurrentDesktop( msg.data.l[0] ); setCurrentDesktop( msg.data.l[0] );
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
@ -1525,6 +1540,15 @@ void Workspace::sendToDesktop( int desk )
popup_client->setDesktop( desk ); popup_client->setDesktop( desk );
popup_client->hide(); 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() void Workspace::slotWindowOperations()
@ -1555,24 +1579,24 @@ QPoint Workspace::adjustClientPosition( Client* c, QPoint pos )
if (options->windowSnapZone() || options->borderSnapZone()) { if (options->windowSnapZone() || options->borderSnapZone()) {
int snap; //snap trigger int snap; //snap trigger
QRect maxRect = clientArea(); QRect maxRect = clientArea();
int xmin = maxRect.left(); int xmin = maxRect.left();
int xmax = maxRect.right(); //desk size int xmax = maxRect.right(); //desk size
int ymin = maxRect.top(); int ymin = maxRect.top();
int ymax = maxRect.bottom(); int ymax = maxRect.bottom();
int cx, cy, rx, ry, cw, ch; //these don't change int cx, cy, rx, ry, cw, ch; //these don't change
int nx, ny; //buffers int nx, ny; //buffers
int deltaX = xmax, deltaY = ymax; //minimum distance to other clients int deltaX = xmax, deltaY = ymax; //minimum distance to other clients
int lx, ly, lrx, lry; //coords and size for the comparison client, l int lx, ly, lrx, lry; //coords and size for the comparison client, l
nx = cx = pos.x(); nx = cx = pos.x();
ny = cy = pos.y(); ny = cy = pos.y();
rx = cx + (cw = c->width()); rx = cx + (cw = c->width());
ry = cy + (ch = c->height()); ry = cy + (ch = c->height());
// border snap // border snap
snap = options->borderSnapZone(); snap = options->borderSnapZone();
if (snap) { if (snap) {
@ -1584,7 +1608,7 @@ QPoint Workspace::adjustClientPosition( Client* c, QPoint pos )
deltaX = abs(xmax-rx); deltaX = abs(xmax-rx);
nx = xmax - cw; nx = xmax - cw;
} }
if ( QABS(cy-ymin) < snap ){ if ( QABS(cy-ymin) < snap ){
deltaY = QABS(cy-ymin); deltaY = QABS(cy-ymin);
ny = ymin; ny = ymin;
@ -1594,7 +1618,7 @@ QPoint Workspace::adjustClientPosition( Client* c, QPoint pos )
ny = ymax - ch; ny = ymax - ch;
} }
} }
// windows snap // windows snap
snap = options->windowSnapZone(); snap = options->windowSnapZone();
if (snap) { if (snap) {
@ -1607,7 +1631,7 @@ QPoint Workspace::adjustClientPosition( Client* c, QPoint pos )
ly = (*l)->y(); ly = (*l)->y();
lrx = lx + (*l)->width(); lrx = lx + (*l)->width();
lry = ly + (*l)->height(); lry = ly + (*l)->height();
if( ( ( cy <= lry ) && ( cy >= ly ) ) || if( ( ( cy <= lry ) && ( cy >= ly ) ) ||
( ( ry >= ly ) && ( ry <= lry ) ) || ( ( ry >= ly ) && ( ry <= lry ) ) ||
( ( ly >= cy ) && ( lry <= ry ) ) ) { ( ( ly >= cy ) && ( lry <= ry ) ) ) {
@ -1622,7 +1646,7 @@ QPoint Workspace::adjustClientPosition( Client* c, QPoint pos )
nx = lx - cw; nx = lx - cw;
} }
} }
if( ( ( cx <= lrx ) && ( cx >= lx ) ) || if( ( ( cx <= lrx ) && ( cx >= lx ) ) ||
( ( rx >= lx ) && ( rx <= lrx ) ) || ( ( rx >= lx ) && ( rx <= lrx ) ) ||
( ( lx >= cx ) && ( lrx <= rx ) ) ) { ( ( lx >= cx ) && ( lrx <= rx ) ) ) {

View file

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