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