diff --git a/client.cpp b/client.cpp index 286a712af0..2ecc7cd753 100644 --- a/client.cpp +++ b/client.cpp @@ -450,6 +450,7 @@ bool WindowWrapper::x11Event( XEvent * e) if ( ((Client*)parentWidget())->windowType() != NET::Normal && ((Client*)parentWidget())->windowType() != NET::Dialog && + ((Client*)parentWidget())->windowType() != NET::Menu && ((Client*)parentWidget())->windowType() != NET::Override ) replay = TRUE; @@ -776,7 +777,7 @@ bool Client::manage( bool isMapped, bool doNotShow, bool isInitial ) // assume window wants to be visible on the current desktop desk = workspace()->currentDesktop(); } else if ( !isMapped && !doNotShow && desk != workspace()->currentDesktop() - && !isMenu() ) { + && !isTopMenu() ) { //window didn't specify any specific desktop but will appear //somewhere else. This happens for example with "save data?" //dialogs on shutdown. Switch to the respective desktop in @@ -1260,7 +1261,7 @@ bool Client::configureRequest( XConfigureRequestEvent& e ) switch (stack_mode){ case Above: case TopIf: - if ( isMenu() && mainClient() != this ) + if ( isTopMenu() && mainClient() != this ) break; // in this case, we already do the raise workspace()->raiseClient( this ); break; @@ -2165,7 +2166,7 @@ bool Client::x11Event( XEvent * e) return TRUE; if ( options->autoRaise && !isDesktop() && - !isDock() && !isMenu() && workspace()->focusChangeEnabled() && + !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() && workspace()->topClientOnDesktop() != this ) { delete autoRaiseTimer; autoRaiseTimer = new QTimer( this ); @@ -2173,7 +2174,7 @@ bool Client::x11Event( XEvent * e) autoRaiseTimer->start( options->autoRaiseInterval, TRUE ); } - if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isMenu() ) ) + if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isTopMenu() ) ) return TRUE; workspace()->requestFocus( this ); @@ -2502,8 +2503,8 @@ void Client::getWindowProtocols(){ */ void Client::takeFocus( bool force ) { - if ( !force && ( isMenu() || isDock() ) ) - return; // menus and dock windows don't take focus if not forced + if ( !force && ( isTopMenu() || isDock() ) ) + return; // toplevel menus and dock windows don't take focus if not forced if ( input ) { // Matthias Ettrich says to comment it so that we avoid two consecutive setActive @@ -2933,6 +2934,18 @@ NET::WindowType Client::windowType() const NET::WindowType wt = info->windowType(); if ( wt == NET::Unknown ) wt = NET::Normal; + if ( wt == NET::Menu ) { + Window dummy1; + int x, y; + unsigned int width, height, dummy2, dummy3; + XGetGeometry( qt_xdisplay(), window(), &dummy1, &x, &y, &width, &height, + &dummy2, &dummy3 ); + // ugly hack to support the times when NET::Menu meant NET::TopMenu + // if it's as wide as the screen, not very high and has its upper-left + // corner a bit above the screen's upper-left cornet, it's a topmenu + if( x == 0 && y < 0 && y > -10 && height < 100 && int(width) == geometry().width()) + wt = NET::TopMenu; + } return wt; } @@ -2955,7 +2968,8 @@ bool Client::wantsInput() const bool Client::isMovable() const { return may_move && - ( windowType() == NET::Normal || windowType() == NET::Dialog || windowType() == NET::Toolbar ) && + ( windowType() == NET::Normal || windowType() == NET::Dialog || windowType() == NET::Toolbar + || windowType() == NET::Menu ) && ( !isMaximized() || ( options->moveResizeMaximizedWindows || max_mode != MaximizeFull ) ); } @@ -2969,9 +2983,9 @@ bool Client::isDock() const return windowType() == NET::Dock; } -bool Client::isMenu() const +bool Client::isTopMenu() const { - return windowType() == NET::Menu; + return windowType() == NET::TopMenu; } diff --git a/plugins.cpp b/plugins.cpp index 58a313bfe0..4d7118b630 100644 --- a/plugins.cpp +++ b/plugins.cpp @@ -28,7 +28,8 @@ const char* defaultPlugin = "kwin_default"; PluginMgr::PluginMgr() : QObject() { - alloc_ptr = NULL; + create_ptr = NULL; + old_create_ptr = NULL; library = 0; pluginStr = "kwin_undefined"; @@ -61,14 +62,15 @@ void PluginMgr::updatePlugin() } } -Client* PluginMgr::allocateClient(Workspace *ws, WId w, bool tool) +Client* PluginMgr::createClient(Workspace *ws, WId w, NET::WindowType type) { + if (create_ptr) // prefer the newer function which accepts exact window type + return(create_ptr(ws, w, type)); + if (old_create_ptr) + return(old_create_ptr(ws, w, type == NET::Tool || type == NET::Menu)); // We are guaranteed to have a plugin loaded, // otherwise, kwin exits during loadPlugin - but verify anyway - if (alloc_ptr) - return(alloc_ptr(ws, w, tool)); - else - return NULL; + return NULL; } // returns true if plugin was loaded successfully @@ -115,10 +117,15 @@ bool PluginMgr::loadPlugin(QString nameStr) if (init_func) ((void (*)())init_func)(); - void *alloc_func = library->symbol("allocate"); - if(alloc_func) { - alloc_ptr = (Client* (*)(Workspace *ws, WId w, int tool))alloc_func; - } else { + void* create_func = library->symbol("create"); + if(create_func) { + create_ptr = (Client* (*)(Workspace *ws, WId w, NET::WindowType, NET::WindowType))create_func; + } + create_func = library->symbol("allocate"); + if(create_func) { + old_create_ptr = (Client* (*)(Workspace *ws, WId w, int tool))create_func; + } + if(!create_ptr && !old_create_ptr) { kdWarning() << "KWin: The library " << path << " is not a KWin plugin." << endl; library->unload(); exit(1); diff --git a/plugins.h b/plugins.h index 08b66cd831..da798900ff 100644 --- a/plugins.h +++ b/plugins.h @@ -8,6 +8,7 @@ Copyright (C) 1999, 2000 Daniel M. Duley #include #include +#include class QFileInfo; class KLibrary; @@ -23,7 +24,7 @@ class PluginMgr : public QObject public: PluginMgr(); ~PluginMgr(); - Client *allocateClient(Workspace *ws, WId w, bool tool); + Client *createClient(Workspace *ws, WId w, NET::WindowType type); bool loadPlugin(QString name); QString currentPlugin() { return pluginStr; } public slots: @@ -32,7 +33,8 @@ signals: void resetAllClients(); protected: void shutdownKWin(const QString& error_msg); - Client* (*alloc_ptr)(Workspace *ws, WId w, int tool); + Client* (*create_ptr)(Workspace *ws, WId w, NET::WindowType type); + Client* (*old_create_ptr)(Workspace *ws, WId w, int tool); KLibrary *library; QString pluginStr; }; diff --git a/workspace.cpp b/workspace.cpp index 0695cfc7f8..1b39b94bfe 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -224,6 +224,7 @@ Client* Workspace::clientFactory( WId w ) return new NoBorderClient( this, w ); switch ( ni.windowType() ) { + // when adding new window types, add a fallback for them in PluginMgr::createClient() case NET::Desktop: { XLowerWindow( qt_xdisplay(), w ); @@ -232,9 +233,6 @@ Client* Workspace::clientFactory( WId w ) return c; } - case NET::Tool: - return ( mgr->allocateClient( this, w, true ) ); - case NET::Dock: { Client * c = new NoBorderClient( this, w ); @@ -242,12 +240,27 @@ Client* Workspace::clientFactory( WId w ) return c; } - case NET::Menu: + case NET::TopMenu: return new NoBorderClient( this, w ); case NET::Override: return new NoBorderClient( this, w); + case NET::Menu: + { + Window dummy1; + int x, y; + unsigned int width, height, dummy2, dummy3; + XGetGeometry( qt_xdisplay(), w, &dummy1, &x, &y, &width, &height, + &dummy2, &dummy3 ); + // ugly hack to support the times when NET::Menu meant NET::TopMenu + // if it's as wide as the screen, not very high and has its upper-left + // corner a bit above the screen's upper-left cornet, it's a topmenu + if( x == 0 && y < 0 && y > -10 && height < 100 && int(width) == geometry().width()) + return new NoBorderClient( this, w ); + // fall through + } + case NET::Tool: default: break; } @@ -255,7 +268,7 @@ Client* Workspace::clientFactory( WId w ) if ( Shape::hasShape( w ) ){ return new NoBorderClient( this, w ); } - return ( mgr->allocateClient( this, w, false ) ); + return ( mgr->createClient( this, w, ni.windowType()) ); } Workspace *Workspace::_self = 0; @@ -1391,7 +1404,7 @@ void Workspace::setActiveClient( Client* c ) Client* menubar = 0; bool has_full_screen = false; for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) { - if ( (*it)->isMenu() && (*it)->mainClient() == main ) { + if ( (*it)->isTopMenu() && (*it)->mainClient() == main ) { menubar = *it; } if ( (*it)->isVisible() && (*it)->isFullScreen() && @@ -1404,7 +1417,7 @@ void Workspace::setActiveClient( Client* c ) // Find the menubar of the desktop if ( desktops.isEmpty() ) { for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) { - if ( (*it)->isMenu() && (*it)->mainClient() == (*it) ) { + if ( (*it)->isTopMenu() && (*it)->mainClient() == (*it) ) { menubar = *it; break; } @@ -1413,7 +1426,7 @@ void Workspace::setActiveClient( Client* c ) else { for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) { - if ( (*it)->isMenu() && (*it)->mainClient()->isDesktop() ) { + if ( (*it)->isTopMenu() && (*it)->mainClient()->isDesktop() ) { menubar = *it; break; } @@ -1429,7 +1442,7 @@ void Workspace::setActiveClient( Client* c ) // ... then hide the other ones. Avoids flickers. for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) { - if ( (*it)->isMenu() && (*it) != menubar ) + if ( (*it)->isTopMenu() && (*it) != menubar ) (*it)->hide(); } @@ -1471,12 +1484,12 @@ void Workspace::activateClient( Client* c, bool force ) void Workspace::iconifyOrDeiconifyTransientsOf( Client* c ) { if ( c->isIconified() || c->isShade() ) { - bool exclude_menu = !c->isIconified(); + bool exclude_topmenu = !c->isIconified(); for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) { if ( (*it)->transientFor() == c->window() && !(*it)->isIconified() && !(*it)->isShade() - && ( !exclude_menu || !(*it)->isMenu() ) ) { + && ( !exclude_topmenu || !(*it)->isTopMenu() ) ) { (*it)->setMappingState( XIconicState ); (*it)->hide(); iconifyOrDeiconifyTransientsOf( (*it) ); @@ -2820,7 +2833,7 @@ void Workspace::killWindowAtPosition(int x, int y) Client *client = (*it); if ( client->frameGeometry().contains(QPoint(x, y)) && client->isOnDesktop( currentDesktop() ) && - !client->isMenu() && !client->isDesktop() && + !client->isTopMenu() && !client->isDesktop() && !client->isIconified() ) { client->killWindow(); return;