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