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 connect( qApp->desktop(), SIGNAL( resized( int )), SLOT( updateKMenubarSize())); 00157 slotReadConfig(); 00158 } 00159 00160 KMenuBar::~KMenuBar() 00161 { 00162 delete d; 00163 } 00164 00165 void KMenuBar::setTopLevelMenu(bool top_level) 00166 { 00167 d->forcedTopLevel = top_level; 00168 setTopLevelMenuInternal( top_level ); 00169 } 00170 00171 void KMenuBar::setTopLevelMenuInternal(bool top_level) 00172 { 00173 if (d->forcedTopLevel) 00174 top_level = true; 00175 00176 d->wasTopLevel = top_level; 00177 if( parentWidget() 00178 && parentWidget()->topLevelWidget()->isFullScreen()) 00179 top_level = false; 00180 00181 if ( isTopLevelMenu() == top_level ) 00182 return; 00183 d->topLevel = top_level; 00184 if ( isTopLevelMenu() ) 00185 { 00186 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00187 d->selection = new KSelectionWatcher( KMenuBarPrivate::makeSelectionAtom(), 00188 DefaultScreen( qt_xdisplay())); 00189 connect( d->selection, SIGNAL( newOwner( Window )), 00190 this, SLOT( updateFallbackSize())); 00191 connect( d->selection, SIGNAL( lostOwner()), 00192 this, SLOT( updateFallbackSize())); 00193 #endif 00194 d->frameStyle = frameStyle(); 00195 d->lineWidth = lineWidth(); 00196 d->margin = margin(); 00197 d->fallback_mode = false; 00198 bool wasShown = !isHidden(); 00199 reparent( parentWidget(), WType_TopLevel | WStyle_Tool | WStyle_Customize | WStyle_NoBorder, QPoint(0,0), false ); 00200 #if defined Q_WS_X11 && ! defined K_WS_QTONLY //FIXME 00201 KWin::setType( winId(), NET::TopMenu ); 00202 if( parentWidget()) 00203 XSetTransientForHint( qt_xdisplay(), winId(), parentWidget()->topLevelWidget()->winId()); 00204 #endif 00205 QMenuBar::setFrameStyle( NoFrame ); 00206 QMenuBar::setLineWidth( 0 ); 00207 QMenuBar::setMargin( 0 ); 00208 updateFallbackSize(); 00209 d->min_size = QSize( 0, 0 ); 00210 if( parentWidget() && !parentWidget()->isTopLevel()) 00211 setShown( parentWidget()->isVisible()); 00212 else if ( wasShown ) 00213 show(); 00214 } else 00215 { 00216 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00217 delete d->selection; 00218 d->selection = NULL; 00219 #endif 00220 setBackgroundMode( PaletteButton ); 00221 setFrameStyle( d->frameStyle ); 00222 setLineWidth( d->lineWidth ); 00223 setMargin( d->margin ); 00224 setMinimumSize( 0, 0 ); 00225 setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX ); 00226 updateMenuBarSize(); 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 setMinimumSize( 0, 0 ); 00320 setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX ); 00321 updateMenuBarSize(); 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(), because 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 updateMenuBarSize(); 00435 return true; 00436 } 00437 #endif 00438 return QMenuBar::x11Event( ev ); 00439 } 00440 00441 void KMenuBar::updateMenuBarSize() 00442 { 00443 menuContentsChanged(); // trigger invalidating calculated size 00444 resize( sizeHint()); // and resize to preferred size 00445 } 00446 00447 void KMenuBar::setFrameStyle( int style ) 00448 { 00449 if( d->topLevel ) 00450 d->frameStyle = style; 00451 else 00452 QMenuBar::setFrameStyle( style ); 00453 } 00454 00455 void KMenuBar::setLineWidth( int width ) 00456 { 00457 if( d->topLevel ) 00458 d->lineWidth = width; 00459 else 00460 QMenuBar::setLineWidth( width ); 00461 } 00462 00463 void KMenuBar::setMargin( int margin ) 00464 { 00465 if( d->topLevel ) 00466 d->margin = margin; 00467 else 00468 QMenuBar::setMargin( margin ); 00469 } 00470 00471 void KMenuBar::closeEvent( QCloseEvent* e ) 00472 { 00473 if( d->topLevel ) 00474 e->ignore(); // mainly for the fallback mode 00475 else 00476 QMenuBar::closeEvent( e ); 00477 } 00478 00479 void KMenuBar::drawContents( QPainter* p ) 00480 { 00481 // Closes the BR77113 00482 // We need to overload this method to paint only the menu items 00483 // This way when the KMenuBar is embedded in the menu applet it 00484 // integrates correctly. 00485 // 00486 // Background mode and origin are set so late because of styles 00487 // using the polish() method to modify these settings. 00488 // 00489 // Of course this hack can safely be removed when real transparency 00490 // will be available 00491 00492 if( !d->topLevel ) 00493 { 00494 QMenuBar::drawContents(p); 00495 } 00496 else 00497 { 00498 bool up_enabled = isUpdatesEnabled(); 00499 BackgroundMode bg_mode = backgroundMode(); 00500 BackgroundOrigin bg_origin = backgroundOrigin(); 00501 00502 setUpdatesEnabled(false); 00503 setBackgroundMode(X11ParentRelative); 00504 setBackgroundOrigin(WindowOrigin); 00505 00506 p->eraseRect( rect() ); 00507 erase(); 00508 00509 QColorGroup g = colorGroup(); 00510 bool e; 00511 00512 for ( int i=0; i<(int)count(); i++ ) 00513 { 00514 QMenuItem *mi = findItem( idAt( i ) ); 00515 00516 if ( !mi->text().isNull() || mi->pixmap() ) 00517 { 00518 QRect r = itemRect(i); 00519 if(r.isEmpty() || !mi->isVisible()) 00520 continue; 00521 00522 e = mi->isEnabledAndVisible(); 00523 if ( e ) 00524 g = isEnabled() ? ( isActiveWindow() ? palette().active() : 00525 palette().inactive() ) : palette().disabled(); 00526 else 00527 g = palette().disabled(); 00528 00529 bool item_active = ( actItem == i ); 00530 00531 p->setClipRect(r); 00532 00533 if( item_active ) 00534 { 00535 QStyle::SFlags flags = QStyle::Style_Default; 00536 if (isEnabled() && e) 00537 flags |= QStyle::Style_Enabled; 00538 if ( item_active ) 00539 flags |= QStyle::Style_Active; 00540 if ( item_active && actItemDown ) 00541 flags |= QStyle::Style_Down; 00542 flags |= QStyle::Style_HasFocus; 00543 00544 style().drawControl(QStyle::CE_MenuBarItem, p, this, 00545 r, g, flags, QStyleOption(mi)); 00546 } 00547 else 00548 { 00549 style().drawItem(p, r, AlignCenter | AlignVCenter | ShowPrefix, 00550 g, e, mi->pixmap(), mi->text()); 00551 } 00552 } 00553 } 00554 00555 setBackgroundOrigin(bg_origin); 00556 setBackgroundMode(bg_mode); 00557 setUpdatesEnabled(up_enabled); 00558 } 00559 } 00560 00561 void KMenuBar::virtual_hook( int, void* ) 00562 { /*BASE::virtual_hook( id, data );*/ } 00563 00564 #include "kmenubar.moc"
KDE Logo
This file is part of the documentation for kdeui Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:27:30 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003