00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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 <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
00058
00059
00060
00061
00062
00063
00064
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;
00090 int lineWidth;
00091 int margin;
00092 bool fallback_mode : 1;
00093
00094 bool forcedTopLevel : 1;
00095 bool topLevel : 1;
00096 bool wasTopLevel : 1;
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
00144 connect( KGlobalSettings::self(), SIGNAL(toolbarAppearanceChanged(int)),
00145 this, SLOT(slotReadConfig()));
00146
00147 slotReadConfig();
00148 }
00149
00150 KMenuBar::~KMenuBar()
00151 {
00152 delete d;
00153 }
00154
00155 void KMenuBar::setTopLevelMenu(bool top_level)
00156 {
00157 d->forcedTopLevel = top_level;
00158 setTopLevelMenuInternal( top_level );
00159 }
00160
00161 void KMenuBar::setTopLevelMenuInternal(bool top_level)
00162 {
00163 if (d->forcedTopLevel)
00164 top_level = true;
00165
00166 d->wasTopLevel = top_level;
00167 if( parentWidget()
00168 && parentWidget()->topLevelWidget()->isFullScreen())
00169 top_level = false;
00170
00171 if ( isTopLevelMenu() == top_level )
00172 return;
00173 d->topLevel = top_level;
00174 if ( isTopLevelMenu() )
00175 {
00176 #ifdef Q_WS_X11
00177 d->selection = new KSelectionWatcher( KMenuBarPrivate::makeSelectionAtom(),
00178 DefaultScreen( QX11Info::display()));
00179 connect( d->selection, SIGNAL( newOwner( Window )),
00180 this, SLOT( updateFallbackSize()));
00181 connect( d->selection, SIGNAL( lostOwner()),
00182 this, SLOT( updateFallbackSize()));
00183 #endif
00184 d->frameStyle = 0;
00185 d->lineWidth = 0;
00186 d->margin = 0;
00187 d->fallback_mode = false;
00188 bool wasShown = !isHidden();
00189 setParent(parentWidget(), Qt::Window | Qt::Tool | Qt::FramelessWindowHint);
00190 setGeometry(0,0,width(),height());
00191 #ifdef Q_WS_X11
00192 KWindowSystem::setType( winId(), NET::TopMenu );
00193 #endif
00194 if( parentWidget())
00195 KWindowSystem::setMainWindow( this, parentWidget()->topLevelWidget()->winId());
00196
00197
00198
00199 updateFallbackSize();
00200 d->min_size = QSize( 0, 0 );
00201 if( parentWidget() && !parentWidget()->isTopLevel())
00202 setVisible( 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 setAttribute(Qt::WA_NoSystemBackground, false);
00212 setBackgroundRole(QPalette::Button);
00213 setFrameStyle( d->frameStyle );
00214 setLineWidth( d->lineWidth );
00215 setMargin( d->margin );
00216 setMinimumSize( 0, 0 );
00217 setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00218 updateMenuBarSize();
00219 if ( parentWidget() )
00220 setParent( parentWidget() );
00221 }
00222 }
00223
00224 bool KMenuBar::isTopLevelMenu() const
00225 {
00226 return d->topLevel;
00227 }
00228
00229
00230 void KMenuBar::slotReadConfig()
00231 {
00232 KConfigGroup cg( KGlobal::config(), "KDE" );
00233 setTopLevelMenuInternal( cg.readEntry( "macStyle", false ) );
00234 }
00235
00236 bool KMenuBar::eventFilter(QObject *obj, QEvent *ev)
00237 {
00238 if ( d->topLevel )
00239 {
00240 if ( parentWidget() && obj == parentWidget()->topLevelWidget() )
00241 {
00242 if( ev->type() == QEvent::Resize )
00243 return false;
00244 #ifdef QT3_SUPPORT
00245 if ( ev->type() == QEvent::Accel || ev->type() == QEvent::AccelAvailable )
00246 {
00247 if ( QApplication::sendEvent( topLevelWidget(), ev ) )
00248 return true;
00249 }
00250 #endif
00251
00252
00253
00254
00255
00256 }
00257 if( parentWidget() && obj == parentWidget() && ev->type() == QEvent::ParentChange )
00258 {
00259 KWindowSystem::setMainWindow( this, parentWidget()->topLevelWidget()->winId());
00260 setVisible( parentWidget()->isTopLevel() || parentWidget()->isVisible());
00261 }
00262 if( parentWidget() && !parentWidget()->isTopLevel() && obj == parentWidget())
00263 {
00264 if( ev->type() == QEvent::Show )
00265 {
00266 KWindowSystem::setMainWindow( this, parentWidget()->topLevelWidget()->winId());
00267 show();
00268 }
00269 if( ev->type() == QEvent::Hide )
00270 hide();
00271 }
00272 }
00273 else
00274 {
00275 if( parentWidget() && obj == parentWidget()->topLevelWidget())
00276 {
00277 if( ev->type() == QEvent::WindowStateChange
00278 && !parentWidget()->topLevelWidget()->isFullScreen() )
00279 setTopLevelMenuInternal( d->wasTopLevel );
00280 }
00281 }
00282 return QMenuBar::eventFilter( obj, ev );
00283 }
00284
00285
00286 void KMenuBar::updateFallbackSize()
00287 {
00288 if( !d->topLevel )
00289 return;
00290 #ifdef Q_WS_X11
00291 if( d->selection->owner() != None )
00292 #endif
00293 {
00294
00295 d->selection_timer.stop();
00296 if( d->fallback_mode )
00297 {
00298 d->fallback_mode = false;
00299
00300 setMinimumSize( 0, 0 );
00301 setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00302 updateMenuBarSize();
00303 }
00304 return;
00305 }
00306 if( d->selection_timer.isActive())
00307 return;
00308 d->selection_timer.setInterval(100);
00309 d->selection_timer.setSingleShot(true);
00310 d->selection_timer.start();
00311 }
00312
00313 void KMenuBar::selectionTimeout()
00314 {
00315 if ( d->topLevel )
00316 {
00317 d->fallback_mode = true;
00318 KConfigGroup xineramaConfig(KGlobal::config(),"Xinerama");
00319 int screen = xineramaConfig.readEntry("MenubarScreen",
00320 QApplication::desktop()->screenNumber(QPoint(0,0)) );
00321 QRect area = QApplication::desktop()->screenGeometry(screen);
00322 int margin = 0;
00323 move(area.left() - margin, area.top() - margin);
00324 setFixedSize(area.width() + 2* margin , heightForWidth( area.width() + 2 * margin ) );
00325 #ifdef Q_WS_X11
00326 int strut_height = height() - margin;
00327 if( strut_height < 0 )
00328 strut_height = 0;
00329 KWindowSystem::setStrut( winId(), 0, 0, strut_height, 0 );
00330 #endif
00331 }
00332 }
00333
00334 void KMenuBar::resizeEvent( QResizeEvent *e )
00335 {
00336 if( e->spontaneous() && d->topLevel && !d->fallback_mode )
00337 {
00338 ++block_resize;
00339 QMenuBar::resizeEvent(e);
00340 --block_resize;
00341 }
00342 else
00343 QMenuBar::resizeEvent(e);
00344 }
00345
00346 void KMenuBar::setGeometry( const QRect& r )
00347 {
00348 setGeometry( r.x(), r.y(), r.width(), r.height() );
00349 }
00350
00351 void KMenuBar::setGeometry( int x, int y, int w, int h )
00352 {
00353 if( block_resize > 0 )
00354 {
00355 move( x, y );
00356 return;
00357 }
00358 checkSize( w, h );
00359 if( geometry() != QRect( x, y, w, h ))
00360 QMenuBar::setGeometry( x, y, w, h );
00361 }
00362
00363 void KMenuBar::resize( int w, int h )
00364 {
00365 if( block_resize > 0 )
00366 return;
00367 checkSize( w, h );
00368 if( size() != QSize( w, h ))
00369 QMenuBar::resize( w, h );
00370
00371 }
00372
00373 void KMenuBar::resize( const QSize& s )
00374 {
00375 QMenuBar::resize( s );
00376 }
00377
00378 void KMenuBar::checkSize( int& w, int& h )
00379 {
00380 if( !d->topLevel || d->fallback_mode )
00381 return;
00382 QSize s = sizeHint();
00383 w = s.width();
00384 h = s.height();
00385
00386
00387
00388 w = qMax( w, d->min_size.width());
00389 h = qMax( h, d->min_size.height());
00390 }
00391
00392
00393 QSize KMenuBar::sizeHint() const
00394 {
00395 if( !d->topLevel || block_resize > 0 )
00396 return QMenuBar::sizeHint();
00397
00398
00399 ++block_resize;
00400
00401 int h = heightForWidth( 1000000 );
00402 int w = QMenuBar::sizeHint().width();
00403
00404 while( heightForWidth( w + 12 ) > h )
00405 w += 12;
00406 while( heightForWidth( w + 4 ) > h )
00407 w += 4;
00408 while( heightForWidth( w ) > h )
00409 ++w;
00410 --block_resize;
00411 return QSize( w, h );
00412 }
00413
00414 #ifdef Q_WS_X11
00415 bool KMenuBar::x11Event( XEvent* ev )
00416 {
00417 if( ev->type == ClientMessage && ev->xclient.message_type == msg_type_atom
00418 && ev->xclient.window == winId())
00419 {
00420
00421
00422
00423
00424 d->min_size = QSize( ev->xclient.data.l[ 1 ], ev->xclient.data.l[ 2 ] );
00425
00426 updateMenuBarSize();
00427 return true;
00428 }
00429 return QMenuBar::x11Event( ev );
00430 }
00431 #endif
00432
00433 void KMenuBar::updateMenuBarSize()
00434 {
00435
00436 resize( sizeHint());
00437 }
00438
00439 void KMenuBar::setFrameStyle( int style )
00440 {
00441 if( d->topLevel )
00442 d->frameStyle = style;
00443
00444
00445 }
00446
00447 void KMenuBar::setLineWidth( int width )
00448 {
00449 if( d->topLevel )
00450 d->lineWidth = width;
00451
00452
00453 }
00454
00455 void KMenuBar::setMargin( int margin )
00456 {
00457 if( d->topLevel )
00458 d->margin = margin;
00459
00460
00461 }
00462
00463 void KMenuBar::closeEvent( QCloseEvent* e )
00464 {
00465 if( d->topLevel )
00466 e->ignore();
00467 else
00468 QMenuBar::closeEvent( e );
00469 }
00470
00471 void KMenuBar::paintEvent( QPaintEvent* pe )
00472 {
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485 {
00486 QMenuBar::paintEvent(pe);
00487 }
00488 #if 0
00489 else
00490 {
00491 QPainter p(this);
00492 bool up_enabled = isUpdatesEnabled();
00493 Qt::BackgroundMode bg_mode = backgroundMode();
00494 BackgroundOrigin bg_origin = backgroundOrigin();
00495
00496 setUpdatesEnabled(false);
00497 setBackgroundMode(Qt::X11ParentRelative);
00498 setBackgroundOrigin(WindowOrigin);
00499
00500 p.eraseRect( rect() );
00501 erase();
00502
00503 QColorGroup g = colorGroup();
00504 bool e;
00505
00506 for ( int i=0; i<(int)count(); i++ )
00507 {
00508 QMenuItem *mi = findItem( idAt( i ) );
00509
00510 if ( !mi->text().isEmpty() || !mi->icon().isNull() )
00511 {
00512 QRect r = itemRect(i);
00513 if(r.isEmpty() || !mi->isVisible())
00514 continue;
00515
00516 e = mi->isEnabled() && mi->isVisible();
00517 if ( e )
00518 g = isEnabled() ? ( isActiveWindow() ? palette().active() :
00519 palette().inactive() ) : palette().disabled();
00520 else
00521 g = palette().disabled();
00522
00523 bool item_active = ( activeAction() == mi );
00524
00525 p.setClipRect(r);
00526
00527 if( item_active )
00528 {
00529 QStyleOptionMenuItem miOpt;
00530 miOpt.init(this);
00531 miOpt.rect = r;
00532 miOpt.text = mi->text();
00533 miOpt.icon = mi->icon();
00534 miOpt.palette = g;
00535
00536 QStyle::State flags = QStyle::State_None;
00537 if (isEnabled() && e)
00538 flags |= QStyle::State_Enabled;
00539 if ( item_active )
00540 flags |= QStyle::State_Active;
00541 if ( item_active && actItemDown )
00542 flags |= QStyle::State_Down;
00543 flags |= QStyle::State_HasFocus;
00544
00545 mi->state = flags;
00546
00547
00548 style()->drawControl(QStyle::CE_MenuBarItem, &miOpt, &p, this);
00549 }
00550 else
00551 {
00552 style()->drawItem(p, r, Qt::AlignCenter | Qt::AlignVCenter | Qt::TextShowMnemonic,
00553 g, e, mi->pixmap(), mi->text());
00554 }
00555 }
00556 }
00557
00558 setBackgroundOrigin(bg_origin);
00559 setBackgroundMode(bg_mode);
00560 setUpdatesEnabled(up_enabled);
00561 }
00562 #endif
00563 }
00564
00565 #include "kmenubar.moc"