• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

kmenubar.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
00020     */
00021 
00022 
00023 #include "kmenubar.h"
00024 
00025 #include <config.h>
00026 
00027 #include <stdio.h>
00028 
00029 #include <QtCore/QObject>
00030 #include <QtCore/QTimer>
00031 #include <QtGui/QActionEvent>
00032 #include <QtGui/QDesktopWidget>
00033 #include <QtGui/QMenuItem>
00034 #include <QtGui/QPainter>
00035 #include <QtGui/QStyle>
00036 #include <QtGui/QStyleOptionMenuItem>
00037 
00038 #include <kconfig.h>
00039 #include <kglobalsettings.h>
00040 #include <kapplication.h>
00041 #include <kglobal.h>
00042 #include <kdebug.h>
00043 #include <kmanagerselection.h>
00044 #include <kconfiggroup.h>
00045 #include <kwindowsystem.h>
00046 
00047 #ifdef Q_WS_X11
00048 #include <qx11info_x11.h>
00049 
00050 #include <X11/Xlib.h>
00051 #include <X11/Xutil.h>
00052 #include <X11/Xatom.h>
00053 #endif
00054 
00055 /*
00056 
00057  Toplevel menubar (not for the fallback size handling done by itself):
00058  - should not alter position or set strut
00059  - every toplevel must have at most one matching topmenu
00060  - embedder won't allow shrinking below a certain size
00061  - must have WM_TRANSIENT_FOR pointing the its mainwindow
00062      - the exception is desktop's menubar, which can be transient for root window
00063        because of using root window as the desktop window
00064  - Fitts' Law
00065 
00066 */
00067 
00068 static int block_resize = 0;
00069 
00070 class KMenuBar::KMenuBarPrivate
00071 {
00072 public:
00073     KMenuBarPrivate()
00074     :   forcedTopLevel( false ),
00075         topLevel( false ),
00076         wasTopLevel( false ),
00077 #ifdef Q_WS_X11
00078         selection( NULL ),
00079 #endif
00080             min_size( 0, 0 )
00081     {
00082     }
00083     ~KMenuBarPrivate()
00084         {
00085 #ifdef Q_WS_X11
00086         delete selection;
00087 #endif
00088         }
00089     int frameStyle; // only valid in toplevel mode
00090     int lineWidth;  // dtto
00091     int margin;     // dtto
00092     bool fallback_mode : 1; // dtto
00093 
00094     bool forcedTopLevel : 1;
00095     bool topLevel : 1;
00096     bool wasTopLevel : 1; // when TLW is fullscreen, remember state
00097 
00098 #ifdef Q_WS_X11
00099     KSelectionWatcher* selection;
00100 #endif
00101     QTimer selection_timer;
00102     QSize min_size;
00103     static Atom makeSelectionAtom();
00104 };
00105 
00106 #ifdef Q_WS_X11
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( QX11Info::display()));
00115     char nm2[] = "_KDE_TOPMENU_MINSIZE";
00116     char* names[ 2 ] = { nm, nm2 };
00117     Atom atoms[ 2 ];
00118     XInternAtoms( QX11Info::display(), 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 #ifdef Q_WS_X11
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)
00136     : QMenuBar(parent), d(new KMenuBarPrivate)
00137 {
00138     connect( &d->selection_timer, SIGNAL( timeout()),
00139         this, SLOT( selectionTimeout()));
00140 
00141     connect( qApp->desktop(), SIGNAL( resized( int )), SLOT( updateFallbackSize()));
00142 
00143     // toolbarAppearanceChanged(int) is sent when changing macstyle
00144     connect( KGlobalSettings::self(), SIGNAL(toolbarAppearanceChanged(int)),
00145         this, SLOT(slotReadConfig()));
00146 
00147     slotReadConfig();
00148 }
00149 
00150 KMenuBar::~KMenuBar()
00151 {
00152   delete d;
00153 }
00154 
00155 void KMenuBar::setTopLevelMenu(bool top_level)
00156 {
00157   d->forcedTopLevel = top_level;
00158   setTopLevelMenuInternal( top_level );
00159 }
00160 
00161 void KMenuBar::setTopLevelMenuInternal(bool top_level)
00162 {
00163   if (d->forcedTopLevel)
00164     top_level = true;
00165 
00166   d->wasTopLevel = top_level;
00167   if( parentWidget()
00168       && parentWidget()->topLevelWidget()->isFullScreen())
00169     top_level = false;
00170 
00171   if ( isTopLevelMenu() == top_level )
00172     return;
00173   d->topLevel = top_level;
00174   if ( isTopLevelMenu() )
00175   {
00176 #ifdef Q_WS_X11
00177       d->selection = new KSelectionWatcher( KMenuBarPrivate::makeSelectionAtom(),
00178           DefaultScreen( QX11Info::display()));
00179       connect( d->selection, SIGNAL( newOwner( Window )),
00180           this, SLOT( updateFallbackSize()));
00181       connect( d->selection, SIGNAL( lostOwner()),
00182           this, SLOT( updateFallbackSize()));
00183 #endif
00184       d->frameStyle = 0; //frameStyle();
00185       d->lineWidth = 0; //lineWidth();
00186       d->margin = 0; //margin();
00187       d->fallback_mode = false;
00188       bool wasShown = !isHidden();
00189       setParent(parentWidget(), Qt::Window | Qt::Tool | Qt::FramelessWindowHint);
00190       setGeometry(0,0,width(),height());
00191 #ifdef Q_WS_X11
00192       KWindowSystem::setType( winId(), NET::TopMenu );
00193 #endif
00194       if( parentWidget())
00195           KWindowSystem::setMainWindow( this, parentWidget()->topLevelWidget()->winId());
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           setVisible( 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       setAttribute(Qt::WA_NoSystemBackground, false);
00212       setBackgroundRole(QPalette::Button);
00213       setFrameStyle( d->frameStyle );
00214       setLineWidth( d->lineWidth );
00215       setMargin( d->margin );
00216       setMinimumSize( 0, 0 );
00217       setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00218       updateMenuBarSize();
00219       if ( parentWidget() )
00220           setParent( parentWidget() );
00221   }
00222 }
00223 
00224 bool KMenuBar::isTopLevelMenu() const
00225 {
00226   return d->topLevel;
00227 }
00228 
00229 
00230 void KMenuBar::slotReadConfig()
00231 {
00232   KConfigGroup cg( KGlobal::config(), "KDE" );
00233   setTopLevelMenuInternal( cg.readEntry( "macStyle", false ) );
00234 }
00235 
00236 bool KMenuBar::eventFilter(QObject *obj, QEvent *ev)
00237 {
00238     if ( d->topLevel )
00239     {
00240     if ( parentWidget() && obj == parentWidget()->topLevelWidget()  )
00241         {
00242         if( ev->type() == QEvent::Resize )
00243         return false; // ignore resizing of parent, QMenuBar would try to adjust size
00244 #ifdef QT3_SUPPORT
00245         if ( ev->type() == QEvent::Accel || ev->type() == QEvent::AccelAvailable )
00246             {
00247         if ( QApplication::sendEvent( topLevelWidget(), ev ) )
00248             return true;
00249         }
00250 #endif
00251             /* FIXME QEvent::ShowFullScreen is no more
00252             if(ev->type() == QEvent::ShowFullScreen )
00253                 // will update the state properly
00254                 setTopLevelMenuInternal( d->topLevel );
00255             */
00256         }
00257         if( parentWidget() && obj == parentWidget() && ev->type() == QEvent::ParentChange )
00258             {
00259             KWindowSystem::setMainWindow( this, parentWidget()->topLevelWidget()->winId());
00260             setVisible( parentWidget()->isTopLevel() || parentWidget()->isVisible());
00261             }
00262         if( parentWidget() && !parentWidget()->isTopLevel() && obj == parentWidget())
00263         { // if the parent is not toplevel, KMenuBar needs to match its visibility status
00264             if( ev->type() == QEvent::Show )
00265                 {
00266                 KWindowSystem::setMainWindow( this, parentWidget()->topLevelWidget()->winId());
00267                 show();
00268                 }
00269             if( ev->type() == QEvent::Hide )
00270                 hide();
00271     }
00272     }
00273     else
00274     {
00275         if( parentWidget() && obj == parentWidget()->topLevelWidget())
00276         {
00277             if( ev->type() == QEvent::WindowStateChange
00278                 && !parentWidget()->topLevelWidget()->isFullScreen() )
00279                 setTopLevelMenuInternal( d->wasTopLevel );
00280         }
00281     }
00282     return QMenuBar::eventFilter( obj, ev );
00283 }
00284 
00285 
00286 void KMenuBar::updateFallbackSize()
00287 {
00288     if( !d->topLevel )
00289     return;
00290 #ifdef Q_WS_X11
00291     if( d->selection->owner() != None )
00292 #endif
00293     { // somebody is managing us, don't mess anything, undo changes
00294       // done in fallback mode if needed
00295         d->selection_timer.stop();
00296         if( d->fallback_mode )
00297         {
00298             d->fallback_mode = false;
00299 //            KWindowSystem::setStrut( winId(), 0, 0, 0, 0 ); KWin will set strut as it will see fit
00300             setMinimumSize( 0, 0 );
00301             setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00302             updateMenuBarSize();
00303         }
00304     return;
00305     }
00306     if( d->selection_timer.isActive())
00307     return;
00308     d->selection_timer.setInterval(100);
00309     d->selection_timer.setSingleShot(true);
00310     d->selection_timer.start();
00311 }
00312 
00313 void KMenuBar::selectionTimeout()
00314 { // nobody is managing us, handle resizing
00315     if ( d->topLevel )
00316     {
00317         d->fallback_mode = true; // KMenuBar is handling its position itself
00318         KConfigGroup xineramaConfig(KGlobal::config(),"Xinerama");
00319         int screen = xineramaConfig.readEntry("MenubarScreen",
00320             QApplication::desktop()->screenNumber(QPoint(0,0)) );
00321         QRect area = QApplication::desktop()->screenGeometry(screen);
00322         int margin = 0;
00323     move(area.left() - margin, area.top() - margin);
00324         setFixedSize(area.width() + 2* margin , heightForWidth( area.width() + 2 * margin ) );
00325 #ifdef Q_WS_X11
00326         int strut_height = height() - margin;
00327         if( strut_height < 0 )
00328             strut_height = 0;
00329         KWindowSystem::setStrut( winId(), 0, 0, strut_height, 0 );
00330 #endif
00331     }
00332 }
00333 
00334 void KMenuBar::resizeEvent( QResizeEvent *e )
00335 {
00336     if( e->spontaneous() && d->topLevel && !d->fallback_mode )
00337         {
00338         ++block_resize; // do not respond with configure request to ConfigureNotify event
00339         QMenuBar::resizeEvent(e); // to avoid possible infinite loop
00340         --block_resize;
00341         }
00342     else
00343         QMenuBar::resizeEvent(e);
00344 }
00345 
00346 void KMenuBar::setGeometry( const QRect& r )
00347 {
00348     setGeometry( r.x(), r.y(), r.width(), r.height() );
00349 }
00350 
00351 void KMenuBar::setGeometry( int x, int y, int w, int h )
00352 {
00353     if( block_resize > 0 )
00354     {
00355     move( x, y );
00356     return;
00357     }
00358     checkSize( w, h );
00359     if( geometry() != QRect( x, y, w, h ))
00360         QMenuBar::setGeometry( x, y, w, h );
00361 }
00362 
00363 void KMenuBar::resize( int w, int h )
00364 {
00365     if( block_resize > 0 )
00366     return;
00367     checkSize( w, h );
00368     if( size() != QSize( w, h ))
00369         QMenuBar::resize( w, h );
00370 //    kDebug() << "RS:" << w << ":" << h << ":" << width() << ":" << height() << ":" << minimumWidth() << ":" << minimumHeight();
00371 }
00372 
00373 void KMenuBar::resize( const QSize& s )
00374 {
00375     QMenuBar::resize( s );
00376 }
00377 
00378 void KMenuBar::checkSize( int& w, int& h )
00379 {
00380     if( !d->topLevel || d->fallback_mode )
00381     return;
00382     QSize s = sizeHint();
00383     w = s.width();
00384     h = s.height();
00385     // This is not done as setMinimumSize(), because that would set the minimum
00386     // size in WM_NORMAL_HINTS, and KWin would not allow changing to smaller size
00387     // anymore
00388     w = qMax( w, d->min_size.width());
00389     h = qMax( h, d->min_size.height());
00390 }
00391 
00392 // QMenuBar's sizeHint() gives wrong size (insufficient width), which causes wrapping in the kicker applet
00393 QSize KMenuBar::sizeHint() const
00394 {
00395     if( !d->topLevel || block_resize > 0 )
00396         return QMenuBar::sizeHint();
00397     // Since QMenuBar::sizeHint() may indirectly call resize(),
00398     // avoid infinite recursion.
00399     ++block_resize;
00400     // find the minimum useful height, and enlarge the width until the menu fits in that height (one row)
00401     int h = heightForWidth( 1000000 );
00402     int w = QMenuBar::sizeHint().width();
00403     // optimization - don't call heightForWidth() too many times
00404     while( heightForWidth( w + 12 ) > h )
00405         w += 12;
00406     while( heightForWidth( w + 4 ) > h )
00407         w += 4;
00408     while( heightForWidth( w ) > h )
00409         ++w;
00410     --block_resize;
00411     return QSize( w, h );
00412 }
00413 
00414 #ifdef Q_WS_X11
00415 bool KMenuBar::x11Event( XEvent* ev )
00416 {
00417     if( ev->type == ClientMessage && ev->xclient.message_type == msg_type_atom
00418         && ev->xclient.window == winId())
00419     {
00420         // QMenuBar is trying really hard to keep the size it deems right.
00421         // Forcing minimum size and blocking resizing to match parent size
00422         // in checkResizingToParent() seem to be the only way to make
00423         // KMenuBar keep the size it wants
00424     d->min_size = QSize( ev->xclient.data.l[ 1 ], ev->xclient.data.l[ 2 ] );
00425 //        kDebug() << "MINSIZE:" << d->min_size;
00426         updateMenuBarSize();
00427     return true;
00428     }
00429     return QMenuBar::x11Event( ev );
00430 }
00431 #endif
00432 
00433 void KMenuBar::updateMenuBarSize()
00434     {
00435     //menuContentsChanged(); // trigger invalidating calculated size
00436     resize( sizeHint());   // and resize to preferred size
00437     }
00438 
00439 void KMenuBar::setFrameStyle( int style )
00440 {
00441     if( d->topLevel )
00442     d->frameStyle = style;
00443 //     else
00444 //  QMenuBar::setFrameStyle( style );
00445 }
00446 
00447 void KMenuBar::setLineWidth( int width )
00448 {
00449     if( d->topLevel )
00450     d->lineWidth = width;
00451 //     else
00452 //  QMenuBar::setLineWidth( width );
00453 }
00454 
00455 void KMenuBar::setMargin( int margin )
00456 {
00457     if( d->topLevel )
00458     d->margin = margin;
00459 //     else
00460 //  QMenuBar::setMargin( margin );
00461 }
00462 
00463 void KMenuBar::closeEvent( QCloseEvent* e )
00464 {
00465     if( d->topLevel )
00466         e->ignore(); // mainly for the fallback mode
00467     else
00468         QMenuBar::closeEvent( e );
00469 }
00470 
00471 void KMenuBar::paintEvent( QPaintEvent* pe )
00472 {
00473     // Closes the BR77113
00474     // We need to overload this method to paint only the menu items
00475     // This way when the KMenuBar is embedded in the menu applet it
00476     // integrates correctly.
00477     //
00478     // Background mode and origin are set so late because of styles
00479     // using the polish() method to modify these settings.
00480     //
00481     // Of course this hack can safely be removed when real transparency
00482     // will be available
00483 
00484 //    if( !d->topLevel )
00485     {
00486         QMenuBar::paintEvent(pe);
00487     }
00488 #if 0
00489     else
00490     {
00491         QPainter p(this);
00492         bool up_enabled = isUpdatesEnabled();
00493         Qt::BackgroundMode bg_mode = backgroundMode();
00494         BackgroundOrigin bg_origin = backgroundOrigin();
00495 
00496         setUpdatesEnabled(false);
00497         setBackgroundMode(Qt::X11ParentRelative);
00498         setBackgroundOrigin(WindowOrigin);
00499 
00500     p.eraseRect( rect() );
00501     erase();
00502 
00503         QColorGroup g = colorGroup();
00504         bool e;
00505 
00506         for ( int i=0; i<(int)count(); i++ )
00507         {
00508             QMenuItem *mi = findItem( idAt( i ) );
00509 
00510             if ( !mi->text().isEmpty() || !mi->icon().isNull() )
00511             {
00512                 QRect r = itemRect(i);
00513                 if(r.isEmpty() || !mi->isVisible())
00514                     continue;
00515 
00516                 e = mi->isEnabled() && mi->isVisible();
00517                 if ( e )
00518                     g = isEnabled() ? ( isActiveWindow() ? palette().active() :
00519                                         palette().inactive() ) : palette().disabled();
00520                 else
00521                     g = palette().disabled();
00522 
00523                 bool item_active = ( activeAction() ==  mi );
00524 
00525                 p.setClipRect(r);
00526 
00527                 if( item_active )
00528                 {
00529                     QStyleOptionMenuItem miOpt;
00530                     miOpt.init(this);
00531                     miOpt.rect = r;
00532                     miOpt.text = mi->text();
00533                     miOpt.icon = mi->icon();
00534                     miOpt.palette = g;
00535 
00536                     QStyle::State flags = QStyle::State_None;
00537                     if (isEnabled() && e)
00538                         flags |= QStyle::State_Enabled;
00539                     if ( item_active )
00540                         flags |= QStyle::State_Active;
00541                     if ( item_active && actItemDown )
00542                         flags |= QStyle::State_Down;
00543                     flags |= QStyle::State_HasFocus;
00544 
00545                     mi->state = flags;
00546 
00547 
00548                     style()->drawControl(QStyle::CE_MenuBarItem, &miOpt, &p, this);
00549                 }
00550                 else
00551                 {
00552                     style()->drawItem(p, r, Qt::AlignCenter | Qt::AlignVCenter | Qt::TextShowMnemonic,
00553                                      g, e, mi->pixmap(), mi->text());
00554                 }
00555             }
00556         }
00557 
00558         setBackgroundOrigin(bg_origin);
00559         setBackgroundMode(bg_mode);
00560         setUpdatesEnabled(up_enabled);
00561     }
00562 #endif
00563 }
00564 
00565 #include "kmenubar.moc"

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal