# kdeui Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# kmenubar.cpp

    00001 /* This file is part of the KDE libraries
    00002     Copyright (C) 1997, 1998, 1999, 2000  Sven Radej (radej@kde.org)
    00003     Copyright (C) 1997, 1998, 1999, 2000 Matthias Ettrich (ettrich@kde.org)
    00004     Copyright (C) 1999, 2000 Daniel "Mosfet" Duley (mosfet@kde.org)
    00005
    00006     This library is free software; you can redistribute it and/or
    00007     modify it under the terms of the GNU Library General Public
    00008     License as published by the Free Software Foundation; either
    00009     version 2 of the License, or (at your option) any later version.
    00010
    00011     This library is distributed in the hope that it will be useful,
    00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00014     Library General Public License for more details.
    00015
    00016     You should have received a copy of the GNU Library General Public License
    00017     along with this library; see the file COPYING.LIB.  If not, write to
    00018     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00019     Boston, MA 02111-1307, USA.
    00020     */
    00021
    00022
    00023 #ifndef INCLUDE_MENUITEM_DEF
    00024 #define INCLUDE_MENUITEM_DEF
    00025 #endif
    00026
    00027 #include "config.h"
    00028 #include <qevent.h>
    00029 #include <qobjectlist.h>
    00030 #include <qaccel.h>
    00031 #include <qpainter.h>
    00032 #include <qstyle.h>
    00033 #include <qtimer.h>
    00034
    00035 #include <kconfig.h>
    00036 #include <kglobalsettings.h>
    00037 #include <kmenubar.h>
    00038 #include <kapplication.h>
    00039 #include <kglobal.h>
    00040 #include <kdebug.h>
    00041 #include <kmanagerselection.h>
    00042
    00043 #ifdef Q_WS_X11
    00044 #include <kwin.h>
    00045 #include <kwinmodule.h>
    00046 #include <qxembed.h>
    00047
    00048 #include <X11/Xlib.h>
    00049 #include <X11/Xutil.h>
    00050 #include <X11/Xatom.h>
    00051 #endif
    00052
    00053 /*
    00054
    00055  Toplevel menubar (not for the fallback size handling done by itself):
    00056  - should not alter position or set strut
    00057  - every toplevel must have at most one matching topmenu
    00058  - embedder won't allow shrinking below a certain size
    00059  - must have WM_TRANSIENT_FOR pointing the its mainwindow
    00060      - the exception is desktop's menubar, which can be transient for root window
    00061        because of using root window as the desktop window
    00062  - Fitts' Law
    00063
    00064 */
    00065
    00066 class KMenuBar::KMenuBarPrivate
    00067 {
    00068 public:
    00069     KMenuBarPrivate()
    00070     :   forcedTopLevel( false ),
    00071         topLevel( false ),
    00072         wasTopLevel( false ),
    00073 #ifdef Q_WS_X11
    00074         selection( NULL ),
    00075 #endif
    00076             min_size( 0, 0 )
    00077     {
    00078     }
    00079     ~KMenuBarPrivate()
    00080         {
    00081 #ifdef Q_WS_X11
    00082         delete selection;
    00083 #endif
    00084         }
    00085     bool forcedTopLevel;
    00086     bool topLevel;
    00087     bool wasTopLevel; // when TLW is fullscreen, remember state
    00088     int frameStyle; // only valid in toplevel mode
    00089     int lineWidth;  // dtto
    00090     int margin;     // dtto
    00091     bool fallback_mode; // dtto
    00092 #ifdef Q_WS_X11
    00093     KSelectionWatcher* selection;
    00094 #endif
    00095     QTimer selection_timer;
    00096     QSize min_size;
    00097     static Atom makeSelectionAtom();
    00098 };
    00099
    00100 #ifdef Q_WS_X11
    00101 static Atom selection_atom = None;
    00102 static Atom msg_type_atom = None;
    00103
    00104 static
    00105 void initAtoms()
    00106 {
    00107     char nm[ 100 ];
    00108     sprintf( nm, "_KDE_TOPMENU_OWNER_S%d", DefaultScreen( qt_xdisplay()));
    00109     char nm2[] = "_KDE_TOPMENU_MINSIZE";
    00110     char* names[ 2 ] = { nm, nm2 };
    00111     Atom atoms[ 2 ];
    00112     XInternAtoms( qt_xdisplay(), names, 2, False, atoms );
    00113     selection_atom = atoms[ 0 ];
    00114     msg_type_atom = atoms[ 1 ];
    00115 }
    00116 #endif
    00117
    00118 Atom KMenuBar::KMenuBarPrivate::makeSelectionAtom()
    00119 {
    00120 #ifdef Q_WS_X11
    00121     if( selection_atom == None )
    00122     initAtoms();
    00123     return selection_atom;
    00124 #else
    00125     return 0;
    00126 #endif
    00127 }
    00128
    00129 KMenuBar::KMenuBar(QWidget *parent, const char *name)
    00130   : QMenuBar(parent, name)
    00131 {
    00132 #ifdef Q_WS_X11
    00133     QXEmbed::initialize();
    00134 #endif
    00135     d = new KMenuBarPrivate;
    00136     connect( &d->selection_timer, SIGNAL( timeout()),
    00137         this, SLOT( selectionTimeout()));
    00138
    00139 #if (QT_VERSION-0 >= 0x030200) // XRANDR support
    00140     connect( qApp->desktop(), SIGNAL( resized( int )), SLOT( updateFallbackSize()));
    00141 #endif
    00142
    00143     if ( kapp )
    00144         // toolbarAppearanceChanged(int) is sent when changing macstyle
    00145         connect( kapp, SIGNAL(toolbarAppearanceChanged(int)),
    00146             this, SLOT(slotReadConfig()));
    00147
    00148     slotReadConfig();
    00149 }
    00150
    00151 KMenuBar::~KMenuBar()
    00152 {
    00153   delete d;
    00154 }
    00155
    00156 void KMenuBar::setTopLevelMenu(bool top_level)
    00157 {
    00158   d->forcedTopLevel = top_level;
    00159   setTopLevelMenuInternal( top_level );
    00160 }
    00161
    00162 void KMenuBar::setTopLevelMenuInternal(bool top_level)
    00163 {
    00164   if (d->forcedTopLevel)
    00165     top_level = true;
    00166
    00167   d->wasTopLevel = top_level;
    00168   if( parentWidget()
    00169       && parentWidget()->topLevelWidget()->isFullScreen())
    00170     top_level = false;
    00171
    00172   if ( isTopLevelMenu() == top_level )
    00173     return;
    00174   d->topLevel = top_level;
    00175   if ( isTopLevelMenu() )
    00176   {
    00177 #ifdef Q_WS_X11
    00178       d->selection = new KSelectionWatcher( KMenuBarPrivate::makeSelectionAtom(),
    00179           DefaultScreen( qt_xdisplay()));
    00180       connect( d->selection, SIGNAL( newOwner( Window )),
    00181           this, SLOT( updateFallbackSize()));
    00182       connect( d->selection, SIGNAL( lostOwner()),
    00183           this, SLOT( updateFallbackSize()));
    00184 #endif
    00185       d->frameStyle = frameStyle();
    00186       d->lineWidth = lineWidth();
    00187       d->margin = margin();
    00188       d->fallback_mode = false;
    00189       bool wasShown = !isHidden();
    00190       reparent( parentWidget(), WType_TopLevel | WStyle_Tool | WStyle_Customize | WStyle_NoBorder, QPoint(0,0), false );
    00191 #ifdef Q_WS_X11
    00192       KWin::setType( winId(), NET::TopMenu );
    00193       if( parentWidget())
    00194           XSetTransientForHint( qt_xdisplay(), winId(), parentWidget()->topLevelWidget()->winId());
    00195 #endif
    00196       QMenuBar::setFrameStyle( NoFrame );
    00197       QMenuBar::setLineWidth( 0 );
    00198       QMenuBar::setMargin( 0 );
    00199       updateFallbackSize();
    00200       d->min_size = QSize( 0, 0 );
    00201       if( parentWidget() && !parentWidget()->isTopLevel())
    00202           setShown( parentWidget()->isVisible());
    00203       else if ( wasShown )
    00204           show();
    00205   } else
    00206   {
    00207 #ifdef Q_WS_X11
    00208       delete d->selection;
    00209       d->selection = NULL;
    00210 #endif
    00211       setBackgroundMode( PaletteButton );
    00212       setFrameStyle( d->frameStyle );
    00213       setLineWidth( d->lineWidth );
    00214       setMargin( d->margin );
    00215       setMinimumSize( 0, 0 );
    00216       setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
    00217       updateMenuBarSize();
    00218       if ( parentWidget() )
    00219           reparent( parentWidget(), QPoint(0,0), !isHidden());
    00220   }
    00221 }
    00222
    00223 bool KMenuBar::isTopLevelMenu() const
    00224 {
    00225   return d->topLevel;
    00226 }
    00227
    00228 // KDE4 remove
    00229 void KMenuBar::show()
    00230 {
    00231     QMenuBar::show();
    00232 }
    00233
    00234 void KMenuBar::slotReadConfig()
    00235 {
    00236   KConfig *config = KGlobal::config();
    00237   KConfigGroupSaver saver( config, "KDE" );
    00238   setTopLevelMenuInternal( config->readBoolEntry( "macStyle", false ) );
    00239 }
    00240
    00241 bool KMenuBar::eventFilter(QObject *obj, QEvent *ev)
    00242 {
    00243     if ( d->topLevel )
    00244     {
    00245     if ( parentWidget() && obj == parentWidget()->topLevelWidget()  )
    00246         {
    00247         if( ev->type() == QEvent::Resize )
    00248         return false; // ignore resizing of parent, QMenuBar would try to adjust size
    00249         if ( ev->type() == QEvent::Accel || ev->type() == QEvent::AccelAvailable )
    00250             {
    00251         if ( QApplication::sendEvent( topLevelWidget(), ev ) )
    00252             return true;
    00253         }
    00254             if(ev->type() == QEvent::ShowFullScreen )
    00255                 // will update the state properly
    00256                 setTopLevelMenuInternal( d->topLevel );
    00257         }
    00258         if( parentWidget() && obj == parentWidget() && ev->type() == QEvent::Reparent )
    00259             {
    00260 #ifdef Q_WS_X11
    00261             XSetTransientForHint( qt_xdisplay(), winId(), parentWidget()->topLevelWidget()->winId());
    00262 #else
    00263             //TODO: WIN32?
    00264 #endif
    00265             setShown( parentWidget()->isTopLevel() || parentWidget()->isVisible());
    00266             }
    00267         if( parentWidget() && !parentWidget()->isTopLevel() && obj == parentWidget())
    00268         { // if the parent is not toplevel, KMenuBar needs to match its visibility status
    00269             if( ev->type() == QEvent::Show )
    00270                 {
    00271 #ifdef Q_WS_X11
    00272                 XSetTransientForHint( qt_xdisplay(), winId(), parentWidget()->topLevelWidget()->winId());
    00273 #else
    00274                 //TODO: WIN32?
    00275 #endif
    00276                 show();
    00277                 }
    00278             if( ev->type() == QEvent::Hide )
    00279                 hide();
    00280     }
    00281     }
    00282     else
    00283     {
    00284         if( parentWidget() && obj == parentWidget()->topLevelWidget())
    00285         {
    00286 #if QT_VERSION >= 0x030300
    00287             if( ev->type() == QEvent::WindowStateChange
    00288 #else
    00289             if( ( ev->type() == QEvent::ShowNormal || ev->type() == QEvent::ShowMaximized )
    00290 #endif
    00291                 && !parentWidget()->topLevelWidget()->isFullScreen() )
    00292                 setTopLevelMenuInternal( d->wasTopLevel );
    00293         }
    00294     }
    00295     return QMenuBar::eventFilter( obj, ev );
    00296 }
    00297
    00298 // KDE4 remove
    00299 void KMenuBar::showEvent( QShowEvent *e )
    00300 {
    00301     QMenuBar::showEvent(e);
    00302 }
    00303
    00304 void KMenuBar::updateFallbackSize()
    00305 {
    00306     if( !d->topLevel )
    00307     return;
    00308 #ifdef Q_WS_X11
    00309     if( d->selection->owner() != None )
    00310 #endif
    00311     { // somebody is managing us, don't mess anything, undo changes
    00312       // done in fallback mode if needed
    00313         d->selection_timer.stop();
    00314         if( d->fallback_mode )
    00315         {
    00316             d->fallback_mode = false;
    00317 //            KWin::setStrut( winId(), 0, 0, 0, 0 ); KWin will set strut as it will see fit
    00318             setMinimumSize( 0, 0 );
    00319             setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
    00320             updateMenuBarSize();
    00321         }
    00322     return;
    00323     }
    00324     if( d->selection_timer.isActive())
    00325     return;
    00326     d->selection_timer.start( 100, true );
    00327 }
    00328
    00329 void KMenuBar::selectionTimeout()
    00330 { // nobody is managing us, handle resizing
    00331     if ( d->topLevel )
    00332     {
    00333         d->fallback_mode = true; // KMenuBar is handling its position itself
    00334         KConfigGroup xineramaConfig(KGlobal::config(),"Xinerama");
    00335         int screen = xineramaConfig.readNumEntry("MenubarScreen",
    00336             QApplication::desktop()->screenNumber(QPoint(0,0)) );
    00337         QRect area = QApplication::desktop()->screenGeometry(screen);
    00338 #if QT_VERSION < 0x030200
    00339         int margin = frameWidth() + 2;
    00340 #else  // hopefully I'll manage to persuade TT on Fitts' Law for QMenuBar for Qt-3.2
    00341         int margin = 0;
    00342 #endif
    00343     move(area.left() - margin, area.top() - margin);
    00344         setFixedSize(area.width() + 2* margin , heightForWidth( area.width() + 2 * margin ) );
    00345 #ifdef Q_WS_X11
    00346         int strut_height = height() - margin;
    00347         if( strut_height < 0 )
    00348             strut_height = 0;
    00349         KWin::setStrut( winId(), 0, 0, strut_height, 0 );
    00350 #endif
    00351     }
    00352 }
    00353
    00354 int KMenuBar::block_resize = 0;
    00355
    00356 void KMenuBar::resizeEvent( QResizeEvent *e )
    00357 {
    00358     if( e->spontaneous() && d->topLevel && !d->fallback_mode )
    00359         {
    00360         ++block_resize; // do not respond with configure request to ConfigureNotify event
    00361         QMenuBar::resizeEvent(e); // to avoid possible infinite loop
    00362         --block_resize;
    00363         }
    00364     else
    00365         QMenuBar::resizeEvent(e);
    00366 }
    00367
    00368 void KMenuBar::setGeometry( const QRect& r )
    00369 {
    00370     setGeometry( r.x(), r.y(), r.width(), r.height() );
    00371 }
    00372
    00373 void KMenuBar::setGeometry( int x, int y, int w, int h )
    00374 {
    00375     if( block_resize > 0 )
    00376     {
    00377     move( x, y );
    00378     return;
    00379     }
    00380     checkSize( w, h );
    00381     if( geometry() != QRect( x, y, w, h ))
    00382         QMenuBar::setGeometry( x, y, w, h );
    00383 }
    00384
    00385 void KMenuBar::resize( int w, int h )
    00386 {
    00387     if( block_resize > 0 )
    00388     return;
    00389     checkSize( w, h );
    00390     if( size() != QSize( w, h ))
    00391         QMenuBar::resize( w, h );
    00392 //    kdDebug() << "RS:" << w << ":" << h << ":" << width() << ":" << height() << ":" << minimumWidth() << ":" << minimumHeight() << endl;
    00393 }
    00394
    00395 void KMenuBar::checkSize( int& w, int& h )
    00396 {
    00397     if( !d->topLevel || d->fallback_mode )
    00398     return;
    00399     QSize s = sizeHint();
    00400     w = s.width();
    00401     h = s.height();
    00402     // This is not done as setMinimumSize(), because that would set the minimum
    00403     // size in WM_NORMAL_HINTS, and KWin would not allow changing to smaller size
    00404     // anymore
    00405     w = KMAX( w, d->min_size.width());
    00406     h = KMAX( h, d->min_size.height());
    00407 }
    00408
    00409 // QMenuBar's sizeHint() gives wrong size (insufficient width), which causes wrapping in the kicker applet
    00410 QSize KMenuBar::sizeHint() const
    00411 {
    00412     if( !d->topLevel || block_resize > 0 )
    00413         return QMenuBar::sizeHint();
    00414     // Since QMenuBar::sizeHint() may indirectly call resize(),
    00415     // avoid infinite recursion.
    00416     ++block_resize;
    00417     // find the minimum useful height, and enlarge the width until the menu fits in that height (one row)
    00418     int h = heightForWidth( 1000000 );
    00419     int w = QMenuBar::sizeHint().width();
    00420     // optimization - don't call heightForWidth() too many times
    00421     while( heightForWidth( w + 12 ) > h )
    00422         w += 12;
    00423     while( heightForWidth( w + 4 ) > h )
    00424         w += 4;
    00425     while( heightForWidth( w ) > h )
    00426         ++w;
    00427     --block_resize;
    00428     return QSize( w, h );
    00429 }
    00430
    00431 #ifdef Q_WS_X11
    00432 bool KMenuBar::x11Event( XEvent* ev )
    00433 {
    00434     if( ev->type == ClientMessage && ev->xclient.message_type == msg_type_atom
    00435         && ev->xclient.window == winId())
    00436     {
    00437         // QMenuBar is trying really hard to keep the size it deems right.
    00438         // Forcing minimum size and blocking resizing to match parent size
    00439         // in checkResizingToParent() seem to be the only way to make
    00440         // KMenuBar keep the size it wants
    00441     d->min_size = QSize( ev->xclient.data.l[ 1 ], ev->xclient.data.l[ 2 ] );
    00442 //        kdDebug() << "MINSIZE:" << d->min_size << endl;
    00443         updateMenuBarSize();
    00444     return true;
    00445     }
    00446     return QMenuBar::x11Event( ev );
    00447 }
    00448 #endif
    00449
    00450 void KMenuBar::updateMenuBarSize()
    00451     {
    00452     menuContentsChanged(); // trigger invalidating calculated size
    00453     resize( sizeHint());   // and resize to preferred size
    00454     }
    00455
    00456 void KMenuBar::setFrameStyle( int style )
    00457 {
    00458     if( d->topLevel )
    00459     d->frameStyle = style;
    00460     else
    00461     QMenuBar::setFrameStyle( style );
    00462 }
    00463
    00464 void KMenuBar::setLineWidth( int width )
    00465 {
    00466     if( d->topLevel )
    00467     d->lineWidth = width;
    00468     else
    00469     QMenuBar::setLineWidth( width );
    00470 }
    00471
    00472 void KMenuBar::setMargin( int margin )
    00473 {
    00474     if( d->topLevel )
    00475     d->margin = margin;
    00476     else
    00477     QMenuBar::setMargin( margin );
    00478 }
    00479
    00480 void KMenuBar::closeEvent( QCloseEvent* e )
    00481 {
    00482     if( d->topLevel )
    00483         e->ignore(); // mainly for the fallback mode
    00484     else
    00485         QMenuBar::closeEvent( e );
    00486 }
    00487
    00488 void KMenuBar::drawContents( QPainter* p )
    00489 {
    00490     // Closes the BR77113
    00491     // We need to overload this method to paint only the menu items
    00492     // This way when the KMenuBar is embedded in the menu applet it
    00493     // integrates correctly.
    00494     //
    00495     // Background mode and origin are set so late because of styles
    00496     // using the polish() method to modify these settings.
    00497     //
    00498     // Of course this hack can safely be removed when real transparency
    00499     // will be available
    00500
    00501     if( !d->topLevel )
    00502     {
    00503         QMenuBar::drawContents(p);
    00504     }
    00505     else
    00506     {
    00507         bool up_enabled = isUpdatesEnabled();
    00508         BackgroundMode bg_mode = backgroundMode();
    00509         BackgroundOrigin bg_origin = backgroundOrigin();
    00510
    00511         setUpdatesEnabled(false);
    00512         setBackgroundMode(X11ParentRelative);
    00513         setBackgroundOrigin(WindowOrigin);
    00514
    00515     p->eraseRect( rect() );
    00516     erase();
    00517
    00518         QColorGroup g = colorGroup();
    00519         bool e;
    00520
    00521         for ( int i=0; i<(int)count(); i++ )
    00522         {
    00523             QMenuItem *mi = findItem( idAt( i ) );
    00524
    00525             if ( !mi->text().isNull() || mi->pixmap() )
    00526             {
    00527                 QRect r = itemRect(i);
    00528                 if(r.isEmpty() || !mi->isVisible())
    00529                     continue;
    00530
    00531                 e = mi->isEnabledAndVisible();
    00532                 if ( e )
    00533                     g = isEnabled() ? ( isActiveWindow() ? palette().active() :
    00534                                         palette().inactive() ) : palette().disabled();
    00535                 else
    00536                     g = palette().disabled();
    00537
    00538                 bool item_active = ( actItem ==  i );
    00539
    00540                 p->setClipRect(r);
    00541
    00542                 if( item_active )
    00543                 {
    00544                     QStyle::SFlags flags = QStyle::Style_Default;
    00545                     if (isEnabled() && e)
    00546                         flags |= QStyle::Style_Enabled;
    00547                     if ( item_active )
    00548                         flags |= QStyle::Style_Active;
    00549                     if ( item_active && actItemDown )
    00550                         flags |= QStyle::Style_Down;
    00551                     flags |= QStyle::Style_HasFocus;
    00552
    00553                     style().drawControl(QStyle::CE_MenuBarItem, p, this,
    00554                                         r, g, flags, QStyleOption(mi));
    00555                 }
    00556                 else
    00557                 {
    00558                     style().drawItem(p, r, AlignCenter | AlignVCenter | ShowPrefix,
    00559                                      g, e, mi->pixmap(), mi->text());
    00560                 }
    00561             }
    00562         }
    00563
    00564         setBackgroundOrigin(bg_origin);
    00565         setBackgroundMode(bg_mode);
    00566         setUpdatesEnabled(up_enabled);
    00567     }
    00568 }
    00569
    00570 void KMenuBar::virtual_hook( int, void* )
    00571 { /*BASE::virtual_hook( id, data );*/ }
    00572
    00573 #include "kmenubar.moc"

This file is part of the documentation for kdeui Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:20:19 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003