• 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 
00046 #ifdef Q_WS_X11
00047 #include <kwindowsystem.h>
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     if ( kapp )
00144         // toolbarAppearanceChanged(int) is sent when changing macstyle
00145         connect( KGlobalSettings::self(), 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( QX11Info::display()));
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 = 0; //frameStyle();
00186       d->lineWidth = 0; //lineWidth();
00187       d->margin = 0; //margin();
00188       d->fallback_mode = false;
00189       bool wasShown = !isHidden();
00190       setParent(parentWidget(), Qt::Window | Qt::Tool | Qt::FramelessWindowHint);
00191       setGeometry(0,0,width(),height());
00192 #ifdef Q_WS_X11
00193       KWindowSystem::setType( winId(), NET::TopMenu );
00194       if( parentWidget())
00195           XSetTransientForHint( QX11Info::display(), winId(), parentWidget()->topLevelWidget()->winId());
00196 #endif
00197       //QMenuBar::setFrameStyle( NoFrame );
00198       //QMenuBar::setLineWidth( 0 );
00199       //QMenuBar::setMargin( 0 );
00200       updateFallbackSize();
00201       d->min_size = QSize( 0, 0 );
00202       if( parentWidget() && !parentWidget()->isTopLevel())
00203           setVisible( parentWidget()->isVisible());
00204       else if ( wasShown )
00205           show();
00206   } else
00207   {
00208 #ifdef Q_WS_X11
00209       delete d->selection;
00210       d->selection = NULL;
00211 #endif
00212       setAttribute(Qt::WA_NoSystemBackground, false);
00213       setBackgroundRole(QPalette::Button);
00214       setFrameStyle( d->frameStyle );
00215       setLineWidth( d->lineWidth );
00216       setMargin( d->margin );
00217       setMinimumSize( 0, 0 );
00218       setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00219       updateMenuBarSize();
00220       if ( parentWidget() )
00221           setParent( parentWidget() );
00222   }
00223 }
00224 
00225 bool KMenuBar::isTopLevelMenu() const
00226 {
00227   return d->topLevel;
00228 }
00229 
00230 
00231 void KMenuBar::slotReadConfig()
00232 {
00233   KConfigGroup cg( KGlobal::config(), "KDE" );
00234   setTopLevelMenuInternal( cg.readEntry( "macStyle", false ) );
00235 }
00236 
00237 bool KMenuBar::eventFilter(QObject *obj, QEvent *ev)
00238 {
00239     if ( d->topLevel )
00240     {
00241     if ( parentWidget() && obj == parentWidget()->topLevelWidget()  )
00242         {
00243         if( ev->type() == QEvent::Resize )
00244         return false; // ignore resizing of parent, QMenuBar would try to adjust size
00245 #ifdef QT3_SUPPORT
00246         if ( ev->type() == QEvent::Accel || ev->type() == QEvent::AccelAvailable )
00247             {
00248         if ( QApplication::sendEvent( topLevelWidget(), ev ) )
00249             return true;
00250         }
00251 #endif
00252             /* FIXME QEvent::ShowFullScreen is no more
00253             if(ev->type() == QEvent::ShowFullScreen )
00254                 // will update the state properly
00255                 setTopLevelMenuInternal( d->topLevel );
00256             */
00257         }
00258         if( parentWidget() && obj == parentWidget() && ev->type() == QEvent::ParentChange )
00259             {
00260 #ifdef Q_WS_X11
00261             XSetTransientForHint( QX11Info::display(), winId(), parentWidget()->topLevelWidget()->winId());
00262 #else
00263             //TODO: WIN32?
00264 #endif
00265             setVisible( 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( QX11Info::display(), 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( ev->type() == QEvent::WindowStateChange
00287                 && !parentWidget()->topLevelWidget()->isFullScreen() )
00288                 setTopLevelMenuInternal( d->wasTopLevel );
00289         }
00290     }
00291     return QMenuBar::eventFilter( obj, ev );
00292 }
00293 
00294 
00295 void KMenuBar::updateFallbackSize()
00296 {
00297     if( !d->topLevel )
00298     return;
00299 #ifdef Q_WS_X11
00300     if( d->selection->owner() != None )
00301 #endif
00302     { // somebody is managing us, don't mess anything, undo changes
00303       // done in fallback mode if needed
00304         d->selection_timer.stop();
00305         if( d->fallback_mode )
00306         {
00307             d->fallback_mode = false;
00308 //            KWindowSystem::setStrut( winId(), 0, 0, 0, 0 ); KWin will set strut as it will see fit
00309             setMinimumSize( 0, 0 );
00310             setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00311             updateMenuBarSize();
00312         }
00313     return;
00314     }
00315     if( d->selection_timer.isActive())
00316     return;
00317     d->selection_timer.setInterval(100);
00318     d->selection_timer.setSingleShot(true);
00319     d->selection_timer.start();
00320 }
00321 
00322 void KMenuBar::selectionTimeout()
00323 { // nobody is managing us, handle resizing
00324     if ( d->topLevel )
00325     {
00326         d->fallback_mode = true; // KMenuBar is handling its position itself
00327         KConfigGroup xineramaConfig(KGlobal::config(),"Xinerama");
00328         int screen = xineramaConfig.readEntry("MenubarScreen",
00329             QApplication::desktop()->screenNumber(QPoint(0,0)) );
00330         QRect area = QApplication::desktop()->screenGeometry(screen);
00331         int margin = 0;
00332     move(area.left() - margin, area.top() - margin);
00333         setFixedSize(area.width() + 2* margin , heightForWidth( area.width() + 2 * margin ) );
00334 #ifdef Q_WS_X11
00335         int strut_height = height() - margin;
00336         if( strut_height < 0 )
00337             strut_height = 0;
00338         KWindowSystem::setStrut( winId(), 0, 0, strut_height, 0 );
00339 #endif
00340     }
00341 }
00342 
00343 void KMenuBar::resizeEvent( QResizeEvent *e )
00344 {
00345     if( e->spontaneous() && d->topLevel && !d->fallback_mode )
00346         {
00347         ++block_resize; // do not respond with configure request to ConfigureNotify event
00348         QMenuBar::resizeEvent(e); // to avoid possible infinite loop
00349         --block_resize;
00350         }
00351     else
00352         QMenuBar::resizeEvent(e);
00353 }
00354 
00355 void KMenuBar::setGeometry( const QRect& r )
00356 {
00357     setGeometry( r.x(), r.y(), r.width(), r.height() );
00358 }
00359 
00360 void KMenuBar::setGeometry( int x, int y, int w, int h )
00361 {
00362     if( block_resize > 0 )
00363     {
00364     move( x, y );
00365     return;
00366     }
00367     checkSize( w, h );
00368     if( geometry() != QRect( x, y, w, h ))
00369         QMenuBar::setGeometry( x, y, w, h );
00370 }
00371 
00372 void KMenuBar::resize( int w, int h )
00373 {
00374     if( block_resize > 0 )
00375     return;
00376     checkSize( w, h );
00377     if( size() != QSize( w, h ))
00378         QMenuBar::resize( w, h );
00379 //    kDebug() << "RS:" << w << ":" << h << ":" << width() << ":" << height() << ":" << minimumWidth() << ":" << minimumHeight();
00380 }
00381 
00382 void KMenuBar::resize( const QSize& s )
00383 {
00384     QMenuBar::resize( s );
00385 }
00386 
00387 void KMenuBar::checkSize( int& w, int& h )
00388 {
00389     if( !d->topLevel || d->fallback_mode )
00390     return;
00391     QSize s = sizeHint();
00392     w = s.width();
00393     h = s.height();
00394     // This is not done as setMinimumSize(), because that would set the minimum
00395     // size in WM_NORMAL_HINTS, and KWin would not allow changing to smaller size
00396     // anymore
00397     w = qMax( w, d->min_size.width());
00398     h = qMax( h, d->min_size.height());
00399 }
00400 
00401 // QMenuBar's sizeHint() gives wrong size (insufficient width), which causes wrapping in the kicker applet
00402 QSize KMenuBar::sizeHint() const
00403 {
00404     if( !d->topLevel || block_resize > 0 )
00405         return QMenuBar::sizeHint();
00406     // Since QMenuBar::sizeHint() may indirectly call resize(),
00407     // avoid infinite recursion.
00408     ++block_resize;
00409     // find the minimum useful height, and enlarge the width until the menu fits in that height (one row)
00410     int h = heightForWidth( 1000000 );
00411     int w = QMenuBar::sizeHint().width();
00412     // optimization - don't call heightForWidth() too many times
00413     while( heightForWidth( w + 12 ) > h )
00414         w += 12;
00415     while( heightForWidth( w + 4 ) > h )
00416         w += 4;
00417     while( heightForWidth( w ) > h )
00418         ++w;
00419     --block_resize;
00420     return QSize( w, h );
00421 }
00422 
00423 #ifdef Q_WS_X11
00424 bool KMenuBar::x11Event( XEvent* ev )
00425 {
00426     if( ev->type == ClientMessage && ev->xclient.message_type == msg_type_atom
00427         && ev->xclient.window == winId())
00428     {
00429         // QMenuBar is trying really hard to keep the size it deems right.
00430         // Forcing minimum size and blocking resizing to match parent size
00431         // in checkResizingToParent() seem to be the only way to make
00432         // KMenuBar keep the size it wants
00433     d->min_size = QSize( ev->xclient.data.l[ 1 ], ev->xclient.data.l[ 2 ] );
00434 //        kDebug() << "MINSIZE:" << d->min_size;
00435         updateMenuBarSize();
00436     return true;
00437     }
00438     return QMenuBar::x11Event( ev );
00439 }
00440 #endif
00441 
00442 void KMenuBar::updateMenuBarSize()
00443     {
00444     //menuContentsChanged(); // trigger invalidating calculated size
00445     resize( sizeHint());   // and resize to preferred size
00446     }
00447 
00448 void KMenuBar::setFrameStyle( int style )
00449 {
00450     if( d->topLevel )
00451     d->frameStyle = style;
00452 //     else
00453 //  QMenuBar::setFrameStyle( style );
00454 }
00455 
00456 void KMenuBar::setLineWidth( int width )
00457 {
00458     if( d->topLevel )
00459     d->lineWidth = width;
00460 //     else
00461 //  QMenuBar::setLineWidth( width );
00462 }
00463 
00464 void KMenuBar::setMargin( int margin )
00465 {
00466     if( d->topLevel )
00467     d->margin = margin;
00468 //     else
00469 //  QMenuBar::setMargin( margin );
00470 }
00471 
00472 void KMenuBar::closeEvent( QCloseEvent* e )
00473 {
00474     if( d->topLevel )
00475         e->ignore(); // mainly for the fallback mode
00476     else
00477         QMenuBar::closeEvent( e );
00478 }
00479 
00480 void KMenuBar::paintEvent( QPaintEvent* pe )
00481 {
00482     // Closes the BR77113
00483     // We need to overload this method to paint only the menu items
00484     // This way when the KMenuBar is embedded in the menu applet it
00485     // integrates correctly.
00486     //
00487     // Background mode and origin are set so late because of styles
00488     // using the polish() method to modify these settings.
00489     //
00490     // Of course this hack can safely be removed when real transparency
00491     // will be available
00492 
00493 //    if( !d->topLevel )
00494     {
00495         QMenuBar::paintEvent(pe);
00496     }
00497 #if 0
00498     else
00499     {
00500         QPainter p(this);
00501         bool up_enabled = isUpdatesEnabled();
00502         Qt::BackgroundMode bg_mode = backgroundMode();
00503         BackgroundOrigin bg_origin = backgroundOrigin();
00504 
00505         setUpdatesEnabled(false);
00506         setBackgroundMode(Qt::X11ParentRelative);
00507         setBackgroundOrigin(WindowOrigin);
00508 
00509     p.eraseRect( rect() );
00510     erase();
00511 
00512         QColorGroup g = colorGroup();
00513         bool e;
00514 
00515         for ( int i=0; i<(int)count(); i++ )
00516         {
00517             QMenuItem *mi = findItem( idAt( i ) );
00518 
00519             if ( !mi->text().isEmpty() || !mi->icon().isNull() )
00520             {
00521                 QRect r = itemRect(i);
00522                 if(r.isEmpty() || !mi->isVisible())
00523                     continue;
00524 
00525                 e = mi->isEnabled() && mi->isVisible();
00526                 if ( e )
00527                     g = isEnabled() ? ( isActiveWindow() ? palette().active() :
00528                                         palette().inactive() ) : palette().disabled();
00529                 else
00530                     g = palette().disabled();
00531 
00532                 bool item_active = ( activeAction() ==  mi );
00533 
00534                 p.setClipRect(r);
00535 
00536                 if( item_active )
00537                 {
00538                     QStyleOptionMenuItem miOpt;
00539                     miOpt.init(this);
00540                     miOpt.rect = r;
00541                     miOpt.text = mi->text();
00542                     miOpt.icon = mi->icon();
00543                     miOpt.palette = g;
00544 
00545                     QStyle::State flags = QStyle::State_None;
00546                     if (isEnabled() && e)
00547                         flags |= QStyle::State_Enabled;
00548                     if ( item_active )
00549                         flags |= QStyle::State_Active;
00550                     if ( item_active && actItemDown )
00551                         flags |= QStyle::State_Down;
00552                     flags |= QStyle::State_HasFocus;
00553 
00554                     mi->state = flags;
00555 
00556 
00557                     style()->drawControl(QStyle::CE_MenuBarItem, &miOpt, &p, this);
00558                 }
00559                 else
00560                 {
00561                     style()->drawItem(p, r, Qt::AlignCenter | Qt::AlignVCenter | Qt::TextShowMnemonic,
00562                                      g, e, mi->pixmap(), mi->text());
00563                 }
00564             }
00565         }
00566 
00567         setBackgroundOrigin(bg_origin);
00568         setBackgroundMode(bg_mode);
00569         setUpdatesEnabled(up_enabled);
00570     }
00571 #endif
00572 }
00573 
00574 #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.4
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