kwindowlistmenu.cpp

00001 /*****************************************************************
00002 
00003 Copyright (c) 2000 Matthias Elter <elter@kde.org>
00004                    Matthias Ettrich <ettrich@kde.org>
00005 
00006 Permission is hereby granted, free of charge, to any person obtaining a copy
00007 of this software and associated documentation files (the "Software"), to deal
00008 in the Software without restriction, including without limitation the rights
00009 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00010 copies of the Software, and to permit persons to whom the Software is
00011 furnished to do so, subject to the following conditions:
00012 
00013 The above copyright notice and this permission notice shall be included in
00014 all copies or substantial portions of the Software.
00015 
00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00019 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00020 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00021 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00022 
00023 ******************************************************************/
00024 
00025 #include <qglobal.h>
00026 
00027 #ifdef Q_WS_X11
00028 
00029 #include "config.h"
00030 #include <qpainter.h>
00031 #include <qvaluelist.h>
00032 
00033 #include <kwin.h> 
00034 #include <kwinmodule.h> 
00035 
00036 #include <klocale.h>
00037 #include <kstringhandler.h>
00038 
00039 #include <netwm.h> 
00040 #include <kapplication.h>
00041 #include <kstyle.h>
00042 #include <dcopclient.h>
00043 
00044 #undef Bool
00045 #include "kwindowlistmenu.h"
00046 #include "kwindowlistmenu.moc"
00047 
00048 // helper class
00049 namespace
00050 {
00051 class NameSortedInfoList : public QPtrList<KWin::WindowInfo>
00052 {
00053 public:
00054     NameSortedInfoList() { setAutoDelete(true); };
00055     ~NameSortedInfoList() {};
00056 
00057 private:
00058     int compareItems( QPtrCollection::Item s1, QPtrCollection::Item s2 );
00059 };
00060 
00061 int NameSortedInfoList::compareItems( QPtrCollection::Item s1, QPtrCollection::Item s2 )
00062 {
00063     KWin::WindowInfo *i1 = static_cast<KWin::WindowInfo *>(s1);
00064     KWin::WindowInfo *i2 = static_cast<KWin::WindowInfo *>(s2);
00065     QString title1, title2;
00066     if (i1)
00067         title1 = i1->visibleNameWithState().lower();
00068     if (i2)
00069         title2 = i2->visibleNameWithState().lower();
00070     return title1.compare(title2);
00071 }
00072 
00073 } // namespace
00074 
00075 KWindowListMenu::KWindowListMenu(QWidget *parent, const char *name)
00076   : KPopupMenu(parent, name)
00077 {
00078     kwin_module = new KWinModule(this);
00079 
00080     connect(this, SIGNAL(activated(int)), SLOT(slotExec(int)));
00081 }
00082 
00083 KWindowListMenu::~KWindowListMenu()
00084 {
00085 
00086 }
00087 
00088 static bool standaloneDialog( const KWin::WindowInfo* info, const NameSortedInfoList& list )
00089 {
00090     WId group = info->groupLeader();
00091     if( group == 0 )
00092     {
00093         return info->transientFor() == qt_xrootwin();
00094     }
00095     for( QPtrListIterator< KWin::WindowInfo > it( list );
00096          it.current() != NULL;
00097          ++it )
00098         if( (*it)->groupLeader() == group )
00099             return false;
00100     return true;
00101 }
00102 
00103 void KWindowListMenu::init()
00104 {
00105     int i, d;
00106     i = 0;
00107 
00108     int nd = kwin_module->numberOfDesktops();
00109     int cd = kwin_module->currentDesktop();
00110     WId active_window = kwin_module->activeWindow();
00111 
00112     // Make sure the popup is not too wide, otherwise clicking in the middle of kdesktop
00113     // wouldn't leave any place for the popup, and release would activate some menu entry.    
00114     int maxwidth = kapp->desktop()->screenGeometry( this ).width() / 2 - 100;
00115 
00116     clear();
00117     map.clear();
00118 
00119     int unclutter = insertItem( i18n("Unclutter Windows"),
00120                                 this, SLOT( slotUnclutterWindows() ) );
00121     int cascade = insertItem( i18n("Cascade Windows"),
00122                               this, SLOT( slotCascadeWindows() ) );
00123 
00124     // if we only have one desktop we won't be showing titles, so put a separator in
00125     if (nd == 1)
00126     {
00127         insertSeparator();
00128     }
00129 
00130 
00131     QValueList<KWin::WindowInfo> windows;
00132     for (QValueList<WId>::ConstIterator it = kwin_module->windows().begin();
00133          it != kwin_module->windows().end(); ++it) {
00134          windows.append( KWin::windowInfo( *it, NET::WMDesktop ));
00135     }
00136     bool show_all_desktops_group = ( nd > 1 );
00137     for (d = 1; d <= nd + (show_all_desktops_group ? 1 : 0); d++) {
00138         bool on_all_desktops = ( d > nd );
00139     int items = 0;
00140 
00141     if (!active_window && d == cd)
00142         setItemChecked(1000 + d, true);
00143 
00144         NameSortedInfoList list;
00145         list.setAutoDelete(true);
00146 
00147     for (QValueList<KWin::WindowInfo>::ConstIterator it = windows.begin();
00148              it != windows.end(); ++it) {
00149         if (((*it).desktop() == d) || (on_all_desktops && (*it).onAllDesktops())
00150                 || (!show_all_desktops_group && (*it).onAllDesktops())) {
00151             list.inSort(new KWin::WindowInfo( (*it).win(),
00152                     NET::WMVisibleName | NET::WMState | NET::XAWMState | NET::WMWindowType,
00153                     NET::WM2GroupLeader | NET::WM2TransientFor ));
00154             }
00155         }
00156 
00157         for (KWin::WindowInfo* info = list.first(); info; info = list.next(), ++i)
00158         {
00159             QString itemText = KStringHandler::cPixelSqueeze(info->visibleNameWithState(), fontMetrics(), maxwidth);
00160             NET::WindowType windowType = info->windowType( NET::NormalMask | NET::DesktopMask
00161                 | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
00162                 | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
00163             if ( (windowType == NET::Normal || windowType == NET::Unknown
00164                     || (windowType == NET::Dialog && standaloneDialog( info, list )))
00165                 && !(info->state() & NET::SkipTaskbar) ) {
00166                 QPixmap pm = KWin::icon(info->win(), 16, 16, true );
00167                 items++;
00168 
00169                 // ok, we have items on this desktop, let's show the title
00170                 if ( items == 1 && nd > 1 )
00171                 {
00172                     if( !on_all_desktops )
00173                         insertTitle(kwin_module->desktopName( d ), 1000 + d);
00174                     else
00175                         insertTitle(i18n("On All Desktops"), 2000 );
00176                 }
00177 
00178                 // Avoid creating unwanted accelerators.
00179                 itemText.replace('&', QString::fromLatin1("&&"));
00180                 insertItem( pm, itemText, i);
00181                 map.insert(i, info->win());
00182                 if (info->win() == active_window)
00183                     setItemChecked(i, true);
00184             }
00185         }
00186 
00187         if (d == cd)
00188         {
00189             setItemEnabled(unclutter, items > 0);
00190             setItemEnabled(cascade, items > 0);
00191         }
00192     }
00193 
00194     // no windows?
00195     if (i == 0)
00196     {
00197         if (nd > 1)
00198         {
00199             // because we don't have any titles, nor a separator
00200             insertSeparator();
00201         }
00202 
00203         setItemEnabled(insertItem(i18n("No Windows")), false);
00204     }
00205 }
00206 
00207 void KWindowListMenu::slotExec(int id)
00208 {
00209     if (id == 2000)
00210         ; // do nothing
00211     else if (id > 1000)
00212         KWin::setCurrentDesktop(id - 1000);
00213     else if ( id >= 0 )
00214     KWin::forceActiveWindow(map[id]);
00215 }
00216 
00217 // This popup is much more useful from keyboard if it has the active
00218 // window active by default - however, QPopupMenu tries hard to resist.
00219 // QPopupMenu::popup() resets the active item, so this needs to be
00220 // called after popup().
00221 void KWindowListMenu::selectActiveWindow()
00222 {
00223     for( unsigned int i = 0;
00224          i < count();
00225          ++i )
00226         if( isItemChecked( idAt( i )))
00227             {
00228             setActiveItem( i );
00229             break;
00230             }
00231 }
00232 
00233 void KWindowListMenu::slotUnclutterWindows()
00234 {
00235     kapp->dcopClient()->send("kwin", "KWinInterface", "unclutterDesktop()", "");
00236 }
00237 
00238 void KWindowListMenu::slotCascadeWindows()
00239 {
00240     kapp->dcopClient()->send("kwin", "KWinInterface", "cascadeDesktop()", "");
00241 }
00242 
00243 void KWindowListMenu::virtual_hook( int id, void* data )
00244 { KPopupMenu::virtual_hook( id, data ); }
00245 
00246 #endif // Q_WS_X11
00247 
KDE Home | KDE Accessibility Home | Description of Access Keys