kdeui Library API Documentation

kmenubar.cpp

00001 /*
00002 
00003     Copyright (C) 1997, 1998, 1999, 2000  Sven Radej (radej@kde.org)
00004     Copyright (C) 1997, 1998, 1999, 2000 Matthias Ettrich (ettrich@kde.org)
00005     Copyright (C) 1999, 2000 Daniel "Mosfet" Duley (mosfet@kde.org)
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Library General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Library General Public License for more details.
00016 
00017     You should have received a copy of the GNU Library General Public License
00018     along with this library; see the file COPYING.LIB.  If not, write to
00019     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020     Boston, MA 02111-1307, USA.
00021     */
00022 
00023 
00024 #ifndef INCLUDE_MENUITEM_DEF
00025 #define INCLUDE_MENUITEM_DEF
00026 #endif
00027 
00028 #include "config.h"
00029 #include <qevent.h>
00030 #include <qobjectlist.h>
00031 #include <qaccel.h>
00032 
00033 #include <kconfig.h>
00034 #include <kglobalsettings.h>
00035 #include <kmenubar.h>
00036 #include <kapplication.h>
00037 
00038 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00039 #include <kwin.h> // schroder
00040 #include <kwinmodule.h> // schroder
00041 #endif
00042 
00043 #include <kglobal.h>
00044 #include <kdebug.h>
00045 
00046 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00047 #include <qxembed.h> // schroder
00048 #endif
00049 
00050 #include <kmanagerselection.h>
00051 #include <qtimer.h>
00052 
00053 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00054 #include <X11/Xlib.h> // schroder
00055 #include <X11/Xutil.h> // schroder
00056 #include <X11/Xatom.h> // schroder
00057 #endif
00058 
00059 /*
00060 
00061  Toplevel menubar (not for the fallback size handling done by itself):
00062  - should not alter position or set strut
00063  - every toplevel must have at most one matching topmenu
00064  - embedder won't allow shrinking below a certain size
00065  - must have WM_TRANSIENT_FOR pointing the its mainwindow
00066      - the exception is desktop's menubar, which can be transient for root window
00067        because of using root window as the desktop window
00068  - Fitts' Law
00069 
00070 */
00071 
00072 class KMenuBar::KMenuBarPrivate
00073 {
00074 public:
00075     KMenuBarPrivate()
00076     :   forcedTopLevel( false ),
00077         topLevel( false ),
00078         wasTopLevel( false ),
00079 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00080         selection( NULL ),
00081 #endif
00082             min_size( 0, 0 )
00083     {
00084     }
00085     ~KMenuBarPrivate()
00086         {
00087 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00088         delete selection;
00089 #endif
00090         }
00091     bool forcedTopLevel;
00092     bool topLevel;
00093     bool wasTopLevel; // when TLW is fullscreen, remember state
00094     int frameStyle; // only valid in toplevel mode
00095     int lineWidth;  // dtto
00096     int margin;     // dtto
00097     bool fallback_mode; // dtto
00098 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00099     KSelectionWatcher* selection;
00100 #endif
00101     QTimer selection_timer;
00102     QSize min_size;
00103     static Atom makeSelectionAtom();
00104 };
00105 
00106 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00107 static Atom selection_atom = None;
00108 static Atom msg_type_atom = None;
00109 
00110 static
00111 void initAtoms()
00112 {
00113     char nm[ 100 ];
00114     sprintf( nm, "_KDE_TOPMENU_OWNER_S%d", DefaultScreen( qt_xdisplay()));
00115     char nm2[] = "_KDE_TOPMENU_MINSIZE";
00116     char* names[ 2 ] = { nm, nm2 };
00117     Atom atoms[ 2 ];
00118     XInternAtoms( qt_xdisplay(), names, 2, False, atoms );
00119     selection_atom = atoms[ 0 ];
00120     msg_type_atom = atoms[ 1 ];
00121 }
00122 #endif
00123 
00124 Atom KMenuBar::KMenuBarPrivate::makeSelectionAtom()
00125 {
00126 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00127     if( selection_atom == None )
00128     initAtoms();
00129     return selection_atom;
00130 #else
00131     return 0;
00132 #endif
00133 }
00134 
00135 KMenuBar::KMenuBar(QWidget *parent, const char *name)
00136   : QMenuBar(parent, name)
00137 {
00138 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00139     QXEmbed::initialize();
00140 #endif
00141     d = new KMenuBarPrivate;
00142     connect( &d->selection_timer, SIGNAL( timeout()),
00143         this, SLOT( selectionTimeout()));
00144 
00145 #if (QT_VERSION-0 >= 0x030200) // XRANDR support
00146     connect( qApp->desktop(), SIGNAL( resized( int )), SLOT( updateFallbackSize()));
00147 #endif
00148 
00149     if ( kapp )
00150         // toolbarAppearanceChanged(int) is sent when changing macstyle
00151         connect( kapp, SIGNAL(toolbarAppearanceChanged(int)),
00152             this, SLOT(slotReadConfig()));
00153 
00154     slotReadConfig();
00155 }
00156 
00157 KMenuBar::~KMenuBar()
00158 {
00159   delete d;
00160 }
00161 
00162 void KMenuBar::setTopLevelMenu(bool top_level)
00163 {
00164   d->forcedTopLevel = top_level;
00165   setTopLevelMenuInternal( top_level );
00166 }
00167 
00168 void KMenuBar::setTopLevelMenuInternal(bool top_level)
00169 {
00170   if (d->forcedTopLevel)
00171     top_level = true;
00172 
00173   d->wasTopLevel = top_level;
00174   if( parentWidget()
00175       && parentWidget()->topLevelWidget()->isFullScreen())
00176     top_level = false;
00177 
00178   if ( isTopLevelMenu() == top_level )
00179     return;
00180   d->topLevel = top_level;
00181   if ( isTopLevelMenu() )
00182   {
00183 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00184       d->selection = new KSelectionWatcher( KMenuBarPrivate::makeSelectionAtom(),
00185           DefaultScreen( qt_xdisplay()));
00186       connect( d->selection, SIGNAL( newOwner( Window )),
00187           this, SLOT( updateFallbackSize()));
00188       connect( d->selection, SIGNAL( lostOwner()),
00189           this, SLOT( updateFallbackSize()));
00190 #endif
00191       d->frameStyle = frameStyle();
00192       d->lineWidth = lineWidth();
00193       d->margin = margin();
00194       d->fallback_mode = false;
00195       bool wasShown = !isHidden();
00196       reparent( parentWidget(), WType_TopLevel | WStyle_Tool | WStyle_Customize | WStyle_NoBorder, QPoint(0,0), false );
00197 #if defined Q_WS_X11 && ! defined K_WS_QTONLY //FIXME
00198       KWin::setType( winId(), NET::TopMenu );
00199 #endif
00200       QMenuBar::setFrameStyle( NoFrame );
00201       QMenuBar::setLineWidth( 0 );
00202       QMenuBar::setMargin( 0 );
00203       updateFallbackSize();
00204       d->min_size = QSize( 0, 0 );
00205       if ( wasShown )
00206           show();
00207   } else
00208   {
00209 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00210       delete d->selection;
00211       d->selection = NULL;
00212 #endif
00213       setBackgroundMode( PaletteButton );
00214       setFrameStyle( d->frameStyle );
00215       setLineWidth( d->lineWidth );
00216       setMargin( d->margin );
00217       setMinimumSize( 0, 0 );
00218       setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00219       menuContentsChanged(); // trigger invalidating calculated size
00220       resize( sizeHint());   // and resize to preferred size
00221       if ( parentWidget() )
00222           reparent( parentWidget(), QPoint(0,0), !isHidden());
00223   }
00224 }
00225 
00226 bool KMenuBar::isTopLevelMenu() const
00227 {
00228   return d->topLevel;
00229 }
00230 
00231 // KDE4 remove
00232 void KMenuBar::show()
00233 {
00234     QMenuBar::show();
00235 }
00236 
00237 void KMenuBar::slotReadConfig()
00238 {
00239   KConfig *config = KGlobal::config();
00240   KConfigGroupSaver saver( config, "KDE" );
00241   setTopLevelMenuInternal( config->readBoolEntry( "macStyle", false ) );
00242 }
00243 
00244 bool KMenuBar::eventFilter(QObject *obj, QEvent *ev)
00245 {
00246     if ( d->topLevel )
00247     {
00248     if ( parentWidget() && obj == parentWidget()->topLevelWidget()  )
00249         {
00250         if( ev->type() == QEvent::Resize )
00251         return false; // ignore resizing of parent, QMenuBar would try to adjust size
00252         if ( ev->type() == QEvent::Accel || ev->type() == QEvent::AccelAvailable )
00253             {
00254         if ( QApplication::sendEvent( topLevelWidget(), ev ) )
00255             return true;
00256         }
00257             if(ev->type() == QEvent::ShowFullScreen )
00258                 // will update the state properly
00259                 setTopLevelMenuInternal( d->topLevel );
00260     }
00261     }
00262     else
00263     {
00264         if( parentWidget() && obj == parentWidget()->topLevelWidget())
00265         {
00266 #if QT_VERSION >= 0x030300
00267             if( ev->type() == QEvent::WindowStateChange
00268 #else
00269             if( ( ev->type() == QEvent::ShowNormal || ev->type() == QEvent::ShowMaximized )
00270 #endif
00271                 && !parentWidget()->topLevelWidget()->isFullScreen() )
00272                 setTopLevelMenuInternal( d->wasTopLevel );
00273         }
00274     }
00275     return QMenuBar::eventFilter( obj, ev );
00276 }
00277 
00278 // KDE4 remove
00279 void KMenuBar::showEvent( QShowEvent *e )
00280 {
00281     QMenuBar::showEvent(e);
00282 }
00283 
00284 void KMenuBar::updateFallbackSize()
00285 {
00286 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00287     if( !d->topLevel )
00288     return;
00289     if( d->selection->owner() != None )
00290     { // somebody is managing us, don't mess anything, undo changes
00291       // done in fallback mode if needed
00292         d->selection_timer.stop();
00293         if( d->fallback_mode )
00294         {
00295             d->fallback_mode = false;
00296 //            KWin::setStrut( winId(), 0, 0, 0, 0 ); KWin will set strut as it will see fit
00297 #endif
00298             setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00299             menuContentsChanged();
00300             resize( sizeHint());
00301 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00302         }
00303     return;
00304     }
00305     if( d->selection_timer.isActive())
00306     return;
00307     d->selection_timer.start( 100, true );
00308 #endif
00309 }
00310 
00311 void KMenuBar::selectionTimeout()
00312 { // nobody is managing us, handle resizing
00313     if ( d->topLevel )
00314     {
00315         d->fallback_mode = true; // KMenuBar is handling its position itself
00316         KConfigGroup xineramaConfig(KGlobal::config(),"Xinerama");
00317         int screen = xineramaConfig.readNumEntry("MenubarScreen",
00318             QApplication::desktop()->screenNumber(QPoint(0,0)) );
00319         QRect area = QApplication::desktop()->screenGeometry(screen);
00320 #if QT_VERSION < 0x030200
00321         int margin = frameWidth() + 2;
00322 #else  // hopefully I'll manage to persuade TT on Fitts' Law for QMenuBar for Qt-3.2
00323         int margin = 0;
00324 #endif
00325     move(area.left() - margin, area.top() - margin); 
00326         setFixedSize(area.width() + 2* margin , heightForWidth( area.width() + 2 * margin ) );
00327 #if defined Q_WS_X11 && ! defined K_WS_QTONLY //FIXME
00328         int strut_height = height() - margin;
00329         if( strut_height < 0 )
00330             strut_height = 0;
00331         KWin::setStrut( winId(), 0, 0, strut_height, 0 );
00332 #endif
00333     }
00334 }
00335 
00336 int KMenuBar::block_resize = 0;
00337 
00338 void KMenuBar::resizeEvent( QResizeEvent *e )
00339 {
00340     if( e->spontaneous() && d->topLevel && !d->fallback_mode )
00341         {
00342         ++block_resize; // do not respond with configure request to ConfigureNotify event
00343         QMenuBar::resizeEvent(e); // to avoid possible infinite loop
00344         --block_resize;
00345         }
00346     else
00347         QMenuBar::resizeEvent(e);
00348 }
00349 
00350 void KMenuBar::setGeometry( const QRect& r )
00351 {
00352     setGeometry( r.x(), r.y(), r.width(), r.height() );
00353 }
00354 
00355 void KMenuBar::setGeometry( int x, int y, int w, int h )
00356 {
00357     if( block_resize > 0 )
00358     {
00359     move( x, y );
00360     return;
00361     }
00362     checkSize( w, h );
00363     if( geometry() != QRect( x, y, w, h ))
00364         QMenuBar::setGeometry( x, y, w, h );
00365 }
00366 
00367 void KMenuBar::resize( int w, int h )
00368 {
00369     if( block_resize > 0 )
00370     return;
00371     checkSize( w, h );
00372     if( size() != QSize( w, h ))
00373         QMenuBar::resize( w, h );
00374 //    kdDebug() << "RS:" << w << ":" << h << ":" << width() << ":" << height() << ":" << minimumWidth() << ":" << minimumHeight() << endl;
00375 }
00376 
00377 void KMenuBar::checkSize( int& w, int& h )
00378 {
00379 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00380     if( !d->topLevel || d->fallback_mode )
00381     return;
00382 #endif
00383     if( parentWidget() && parentWidget()->width() == w )
00384     { // Menubar is possibly being attempted to be resized to match
00385       // mainwindow size. Resize to sizeHint() instead. Since
00386       // sizeHint() may indirectly call resize(), avoid infinite
00387       // recursion.
00388     ++block_resize;
00389     QSize s = sizeHint();
00390     w = s.width();
00391     h = s.height();
00392     --block_resize;
00393     }
00394     // This is not done as setMinimumSize(), becase that would set the minimum
00395     // size in WM_NORMAL_HINTS, and KWin would not allow changing to smaller size
00396     // anymore
00397     w = KMAX( w, d->min_size.width());
00398     h = KMAX( h, d->min_size.height());
00399 }
00400 
00401 bool KMenuBar::x11Event( XEvent* ev )
00402 {
00403 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00404     if( ev->type == ClientMessage && ev->xclient.message_type == msg_type_atom
00405         && ev->xclient.window == winId())
00406     {
00407         // QMenuBar is trying really hard to keep the size it deems right.
00408         // Forcing minimum size and blocking resizing to match parent size
00409         // in checkResizingToParent() seem to be the only way to make
00410         // KMenuBar keep the size it wants
00411     d->min_size = QSize( ev->xclient.data.l[ 1 ], ev->xclient.data.l[ 2 ] );
00412 //        kdDebug() << "MINSIZE:" << d->min_size << endl;
00413         menuContentsChanged();
00414         resize( sizeHint());
00415     return true;
00416     }
00417 #endif
00418     return QMenuBar::x11Event( ev );
00419 }
00420 
00421 void KMenuBar::setFrameStyle( int style )
00422 {
00423     if( d->topLevel )
00424     d->frameStyle = style;
00425     else
00426     QMenuBar::setFrameStyle( style );
00427 }
00428 
00429 void KMenuBar::setLineWidth( int width )
00430 {
00431     if( d->topLevel )
00432     d->lineWidth = width;
00433     else
00434     QMenuBar::setLineWidth( width );
00435 }
00436 
00437 void KMenuBar::setMargin( int margin )
00438 {
00439     if( d->topLevel )
00440     d->margin = margin;
00441     else
00442     QMenuBar::setMargin( margin );
00443 }
00444 
00445 void KMenuBar::closeEvent( QCloseEvent* e )
00446 {
00447     if( d->topLevel )
00448         e->ignore(); // mainly for the fallback mode 
00449     else
00450         QMenuBar::closeEvent( e );
00451 }
00452 
00453 void KMenuBar::virtual_hook( int, void* )
00454 { /*BASE::virtual_hook( id, data );*/ }
00455 
00456 #include "kmenubar.moc"
KDE Logo
This file is part of the documentation for kdeui Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun May 16 22:02:06 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003