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