00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef INCLUDE_MENUITEM_DEF
00024 #define INCLUDE_MENUITEM_DEF
00025 #endif
00026
00027 #include "config.h"
00028 #include <qevent.h>
00029 #include <qobjectlist.h>
00030 #include <qaccel.h>
00031 #include <qpainter.h>
00032 #include <qstyle.h>
00033 #include <qtimer.h>
00034
00035 #include <kconfig.h>
00036 #include <kglobalsettings.h>
00037 #include <kmenubar.h>
00038 #include <kapplication.h>
00039 #include <kglobal.h>
00040 #include <kdebug.h>
00041 #include <kmanagerselection.h>
00042
00043 #ifdef Q_WS_X11
00044 #include <kwin.h>
00045 #include <kwinmodule.h>
00046 #include <qxembed.h>
00047
00048 #include <X11/Xlib.h>
00049 #include <X11/Xutil.h>
00050 #include <X11/Xatom.h>
00051 #endif
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 class KMenuBar::KMenuBarPrivate
00067 {
00068 public:
00069 KMenuBarPrivate()
00070 : forcedTopLevel( false ),
00071 topLevel( false ),
00072 wasTopLevel( false ),
00073 #ifdef Q_WS_X11
00074 selection( NULL ),
00075 #endif
00076 min_size( 0, 0 )
00077 {
00078 }
00079 ~KMenuBarPrivate()
00080 {
00081 #ifdef Q_WS_X11
00082 delete selection;
00083 #endif
00084 }
00085 bool forcedTopLevel;
00086 bool topLevel;
00087 bool wasTopLevel;
00088 int frameStyle;
00089 int lineWidth;
00090 int margin;
00091 bool fallback_mode;
00092 #ifdef Q_WS_X11
00093 KSelectionWatcher* selection;
00094 #endif
00095 QTimer selection_timer;
00096 QSize min_size;
00097 static Atom makeSelectionAtom();
00098 };
00099
00100 #ifdef Q_WS_X11
00101 static Atom selection_atom = None;
00102 static Atom msg_type_atom = None;
00103
00104 static
00105 void initAtoms()
00106 {
00107 char nm[ 100 ];
00108 sprintf( nm, "_KDE_TOPMENU_OWNER_S%d", DefaultScreen( qt_xdisplay()));
00109 char nm2[] = "_KDE_TOPMENU_MINSIZE";
00110 char* names[ 2 ] = { nm, nm2 };
00111 Atom atoms[ 2 ];
00112 XInternAtoms( qt_xdisplay(), names, 2, False, atoms );
00113 selection_atom = atoms[ 0 ];
00114 msg_type_atom = atoms[ 1 ];
00115 }
00116 #endif
00117
00118 Atom KMenuBar::KMenuBarPrivate::makeSelectionAtom()
00119 {
00120 #ifdef Q_WS_X11
00121 if( selection_atom == None )
00122 initAtoms();
00123 return selection_atom;
00124 #else
00125 return 0;
00126 #endif
00127 }
00128
00129 KMenuBar::KMenuBar(QWidget *parent, const char *name)
00130 : QMenuBar(parent, name)
00131 {
00132 #ifdef Q_WS_X11
00133 QXEmbed::initialize();
00134 #endif
00135 d = new KMenuBarPrivate;
00136 connect( &d->selection_timer, SIGNAL( timeout()),
00137 this, SLOT( selectionTimeout()));
00138
00139 #if (QT_VERSION-0 >= 0x030200) // XRANDR support
00140 connect( qApp->desktop(), SIGNAL( resized( int )), SLOT( updateFallbackSize()));
00141 #endif
00142
00143 if ( kapp )
00144
00145 connect( kapp, 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( qt_xdisplay()));
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 = frameStyle();
00186 d->lineWidth = lineWidth();
00187 d->margin = margin();
00188 d->fallback_mode = false;
00189 bool wasShown = !isHidden();
00190 reparent( parentWidget(), WType_TopLevel | WStyle_Tool | WStyle_Customize | WStyle_NoBorder, QPoint(0,0), false );
00191 #ifdef Q_WS_X11
00192 KWin::setType( winId(), NET::TopMenu );
00193 if( parentWidget())
00194 XSetTransientForHint( qt_xdisplay(), winId(), parentWidget()->topLevelWidget()->winId());
00195 #endif
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 setShown( 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 setBackgroundMode( PaletteButton );
00212 setFrameStyle( d->frameStyle );
00213 setLineWidth( d->lineWidth );
00214 setMargin( d->margin );
00215 setMinimumSize( 0, 0 );
00216 setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00217 updateMenuBarSize();
00218 if ( parentWidget() )
00219 reparent( parentWidget(), QPoint(0,0), !isHidden());
00220 }
00221 }
00222
00223 bool KMenuBar::isTopLevelMenu() const
00224 {
00225 return d->topLevel;
00226 }
00227
00228
00229 void KMenuBar::show()
00230 {
00231 QMenuBar::show();
00232 }
00233
00234 void KMenuBar::slotReadConfig()
00235 {
00236 KConfig *config = KGlobal::config();
00237 KConfigGroupSaver saver( config, "KDE" );
00238 setTopLevelMenuInternal( config->readBoolEntry( "macStyle", false ) );
00239 }
00240
00241 bool KMenuBar::eventFilter(QObject *obj, QEvent *ev)
00242 {
00243 if ( d->topLevel )
00244 {
00245 if ( parentWidget() && obj == parentWidget()->topLevelWidget() )
00246 {
00247 if( ev->type() == QEvent::Resize )
00248 return false;
00249 if ( ev->type() == QEvent::Accel || ev->type() == QEvent::AccelAvailable )
00250 {
00251 if ( QApplication::sendEvent( topLevelWidget(), ev ) )
00252 return true;
00253 }
00254 if(ev->type() == QEvent::ShowFullScreen )
00255
00256 setTopLevelMenuInternal( d->topLevel );
00257 }
00258 if( parentWidget() && obj == parentWidget() && ev->type() == QEvent::Reparent )
00259 {
00260 #ifdef Q_WS_X11
00261 XSetTransientForHint( qt_xdisplay(), winId(), parentWidget()->topLevelWidget()->winId());
00262 #else
00263
00264 #endif
00265 setShown( parentWidget()->isTopLevel() || parentWidget()->isVisible());
00266 }
00267 if( parentWidget() && !parentWidget()->isTopLevel() && obj == parentWidget())
00268 {
00269 if( ev->type() == QEvent::Show )
00270 {
00271 #ifdef Q_WS_X11
00272 XSetTransientForHint( qt_xdisplay(), winId(), parentWidget()->topLevelWidget()->winId());
00273 #else
00274
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 QT_VERSION >= 0x030300
00287 if( ev->type() == QEvent::WindowStateChange
00288 #else
00289 if( ( ev->type() == QEvent::ShowNormal || ev->type() == QEvent::ShowMaximized )
00290 #endif
00291 && !parentWidget()->topLevelWidget()->isFullScreen() )
00292 setTopLevelMenuInternal( d->wasTopLevel );
00293 }
00294 }
00295 return QMenuBar::eventFilter( obj, ev );
00296 }
00297
00298
00299 void KMenuBar::showEvent( QShowEvent *e )
00300 {
00301 QMenuBar::showEvent(e);
00302 }
00303
00304 void KMenuBar::updateFallbackSize()
00305 {
00306 if( !d->topLevel )
00307 return;
00308 #ifdef Q_WS_X11
00309 if( d->selection->owner() != None )
00310 #endif
00311 {
00312
00313 d->selection_timer.stop();
00314 if( d->fallback_mode )
00315 {
00316 d->fallback_mode = false;
00317
00318 setMinimumSize( 0, 0 );
00319 setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00320 updateMenuBarSize();
00321 }
00322 return;
00323 }
00324 if( d->selection_timer.isActive())
00325 return;
00326 d->selection_timer.start( 100, true );
00327 }
00328
00329 void KMenuBar::selectionTimeout()
00330 {
00331 if ( d->topLevel )
00332 {
00333 d->fallback_mode = true;
00334 KConfigGroup xineramaConfig(KGlobal::config(),"Xinerama");
00335 int screen = xineramaConfig.readNumEntry("MenubarScreen",
00336 QApplication::desktop()->screenNumber(QPoint(0,0)) );
00337 QRect area = QApplication::desktop()->screenGeometry(screen);
00338 #if QT_VERSION < 0x030200
00339 int margin = frameWidth() + 2;
00340 #else // hopefully I'll manage to persuade TT on Fitts' Law for QMenuBar for Qt-3.2
00341 int margin = 0;
00342 #endif
00343 move(area.left() - margin, area.top() - margin);
00344 setFixedSize(area.width() + 2* margin , heightForWidth( area.width() + 2 * margin ) );
00345 #ifdef Q_WS_X11
00346 int strut_height = height() - margin;
00347 if( strut_height < 0 )
00348 strut_height = 0;
00349 KWin::setStrut( winId(), 0, 0, strut_height, 0 );
00350 #endif
00351 }
00352 }
00353
00354 int KMenuBar::block_resize = 0;
00355
00356 void KMenuBar::resizeEvent( QResizeEvent *e )
00357 {
00358 if( e->spontaneous() && d->topLevel && !d->fallback_mode )
00359 {
00360 ++block_resize;
00361 QMenuBar::resizeEvent(e);
00362 --block_resize;
00363 }
00364 else
00365 QMenuBar::resizeEvent(e);
00366 }
00367
00368 void KMenuBar::setGeometry( const QRect& r )
00369 {
00370 setGeometry( r.x(), r.y(), r.width(), r.height() );
00371 }
00372
00373 void KMenuBar::setGeometry( int x, int y, int w, int h )
00374 {
00375 if( block_resize > 0 )
00376 {
00377 move( x, y );
00378 return;
00379 }
00380 checkSize( w, h );
00381 if( geometry() != QRect( x, y, w, h ))
00382 QMenuBar::setGeometry( x, y, w, h );
00383 }
00384
00385 void KMenuBar::resize( int w, int h )
00386 {
00387 if( block_resize > 0 )
00388 return;
00389 checkSize( w, h );
00390 if( size() != QSize( w, h ))
00391 QMenuBar::resize( w, h );
00392
00393 }
00394
00395 void KMenuBar::checkSize( int& w, int& h )
00396 {
00397 if( !d->topLevel || d->fallback_mode )
00398 return;
00399 QSize s = sizeHint();
00400 w = s.width();
00401 h = s.height();
00402
00403
00404
00405 w = KMAX( w, d->min_size.width());
00406 h = KMAX( h, d->min_size.height());
00407 }
00408
00409
00410 QSize KMenuBar::sizeHint() const
00411 {
00412 if( !d->topLevel || block_resize > 0 )
00413 return QMenuBar::sizeHint();
00414
00415
00416 ++block_resize;
00417
00418 int h = heightForWidth( 1000000 );
00419 int w = QMenuBar::sizeHint().width();
00420
00421 while( heightForWidth( w + 12 ) > h )
00422 w += 12;
00423 while( heightForWidth( w + 4 ) > h )
00424 w += 4;
00425 while( heightForWidth( w ) > h )
00426 ++w;
00427 --block_resize;
00428 return QSize( w, h );
00429 }
00430
00431 #ifdef Q_WS_X11
00432 bool KMenuBar::x11Event( XEvent* ev )
00433 {
00434 if( ev->type == ClientMessage && ev->xclient.message_type == msg_type_atom
00435 && ev->xclient.window == winId())
00436 {
00437
00438
00439
00440
00441 d->min_size = QSize( ev->xclient.data.l[ 1 ], ev->xclient.data.l[ 2 ] );
00442
00443 updateMenuBarSize();
00444 return true;
00445 }
00446 return QMenuBar::x11Event( ev );
00447 }
00448 #endif
00449
00450 void KMenuBar::updateMenuBarSize()
00451 {
00452 menuContentsChanged();
00453 resize( sizeHint());
00454 }
00455
00456 void KMenuBar::setFrameStyle( int style )
00457 {
00458 if( d->topLevel )
00459 d->frameStyle = style;
00460 else
00461 QMenuBar::setFrameStyle( style );
00462 }
00463
00464 void KMenuBar::setLineWidth( int width )
00465 {
00466 if( d->topLevel )
00467 d->lineWidth = width;
00468 else
00469 QMenuBar::setLineWidth( width );
00470 }
00471
00472 void KMenuBar::setMargin( int margin )
00473 {
00474 if( d->topLevel )
00475 d->margin = margin;
00476 else
00477 QMenuBar::setMargin( margin );
00478 }
00479
00480 void KMenuBar::closeEvent( QCloseEvent* e )
00481 {
00482 if( d->topLevel )
00483 e->ignore();
00484 else
00485 QMenuBar::closeEvent( e );
00486 }
00487
00488 void KMenuBar::drawContents( QPainter* p )
00489 {
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 if( !d->topLevel )
00502 {
00503 QMenuBar::drawContents(p);
00504 }
00505 else
00506 {
00507 bool up_enabled = isUpdatesEnabled();
00508 BackgroundMode bg_mode = backgroundMode();
00509 BackgroundOrigin bg_origin = backgroundOrigin();
00510
00511 setUpdatesEnabled(false);
00512 setBackgroundMode(X11ParentRelative);
00513 setBackgroundOrigin(WindowOrigin);
00514
00515 p->eraseRect( rect() );
00516 erase();
00517
00518 QColorGroup g = colorGroup();
00519 bool e;
00520
00521 for ( int i=0; i<(int)count(); i++ )
00522 {
00523 QMenuItem *mi = findItem( idAt( i ) );
00524
00525 if ( !mi->text().isNull() || mi->pixmap() )
00526 {
00527 QRect r = itemRect(i);
00528 if(r.isEmpty() || !mi->isVisible())
00529 continue;
00530
00531 e = mi->isEnabledAndVisible();
00532 if ( e )
00533 g = isEnabled() ? ( isActiveWindow() ? palette().active() :
00534 palette().inactive() ) : palette().disabled();
00535 else
00536 g = palette().disabled();
00537
00538 bool item_active = ( actItem == i );
00539
00540 p->setClipRect(r);
00541
00542 if( item_active )
00543 {
00544 QStyle::SFlags flags = QStyle::Style_Default;
00545 if (isEnabled() && e)
00546 flags |= QStyle::Style_Enabled;
00547 if ( item_active )
00548 flags |= QStyle::Style_Active;
00549 if ( item_active && actItemDown )
00550 flags |= QStyle::Style_Down;
00551 flags |= QStyle::Style_HasFocus;
00552
00553 style().drawControl(QStyle::CE_MenuBarItem, p, this,
00554 r, g, flags, QStyleOption(mi));
00555 }
00556 else
00557 {
00558 style().drawItem(p, r, AlignCenter | AlignVCenter | ShowPrefix,
00559 g, e, mi->pixmap(), mi->text());
00560 }
00561 }
00562 }
00563
00564 setBackgroundOrigin(bg_origin);
00565 setBackgroundMode(bg_mode);
00566 setUpdatesEnabled(up_enabled);
00567 }
00568 }
00569
00570 void KMenuBar::virtual_hook( int, void* )
00571 { }
00572
00573 #include "kmenubar.moc"