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