• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • kdeui
  • widgets
kmenubar.cpp
Go to the documentation of this file.
1/* This file is part of the KDE libraries
2 Copyright (C) 1997, 1998, 1999, 2000 Sven Radej (radej@kde.org)
3 Copyright (C) 1997, 1998, 1999, 2000 Matthias Ettrich (ettrich@kde.org)
4 Copyright (C) 1999, 2000 Daniel "Mosfet" Duley (mosfet@kde.org)
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20 */
21
22
23#include "kmenubar.h"
24
25#include <config.h>
26
27#include <stdio.h>
28
29#include <QtCore/QObject>
30#include <QtCore/QTimer>
31#include <QtGui/QActionEvent>
32#include <QtGui/QDesktopWidget>
33#include <QtGui/QMenuItem>
34#include <QtGui/QPainter>
35#include <QtGui/QStyle>
36#include <QtGui/QStyleOptionMenuItem>
37
38#include <kconfig.h>
39#include <kglobalsettings.h>
40#include <kapplication.h>
41#include <kglobal.h>
42#include <kdebug.h>
43#include <kmanagerselection.h>
44#include <kconfiggroup.h>
45#include <kwindowsystem.h>
46
47#ifdef Q_WS_X11
48#include <qx11info_x11.h>
49
50#include <X11/Xlib.h>
51#include <X11/Xutil.h>
52#include <X11/Xatom.h>
53#endif
54
55/*
56
57 Toplevel menubar (not for the fallback size handling done by itself):
58 - should not alter position or set strut
59 - every toplevel must have at most one matching topmenu
60 - embedder won't allow shrinking below a certain size
61 - must have WM_TRANSIENT_FOR pointing the its mainwindow
62 - the exception is desktop's menubar, which can be transient for root window
63 because of using root window as the desktop window
64 - Fitts' Law
65
66*/
67
68static int block_resize = 0;
69
70class KMenuBar::KMenuBarPrivate
71{
72public:
73 KMenuBarPrivate()
74 : forcedTopLevel( false ),
75 topLevel( false ),
76 wasTopLevel( false ),
77#ifdef Q_WS_X11
78 selection( NULL ),
79#endif
80 min_size( 0, 0 )
81 {
82 }
83 ~KMenuBarPrivate()
84 {
85#ifdef Q_WS_X11
86 delete selection;
87#endif
88 }
89 int frameStyle; // only valid in toplevel mode
90 int lineWidth; // dtto
91 int margin; // dtto
92 bool fallback_mode : 1; // dtto
93
94 bool forcedTopLevel : 1;
95 bool topLevel : 1;
96 bool wasTopLevel : 1; // when TLW is fullscreen, remember state
97
98#ifdef Q_WS_X11
99 KSelectionWatcher* selection;
100#endif
101 QTimer selection_timer;
102 QSize min_size;
103 static Atom makeSelectionAtom();
104};
105
106#ifdef Q_WS_X11
107static Atom selection_atom = None;
108static Atom msg_type_atom = None;
109
110static
111void initAtoms()
112{
113 char nm[ 100 ];
114 sprintf( nm, "_KDE_TOPMENU_OWNER_S%d", DefaultScreen( QX11Info::display()));
115 char nm2[] = "_KDE_TOPMENU_MINSIZE";
116 char* names[ 2 ] = { nm, nm2 };
117 Atom atoms[ 2 ];
118 XInternAtoms( QX11Info::display(), names, 2, False, atoms );
119 selection_atom = atoms[ 0 ];
120 msg_type_atom = atoms[ 1 ];
121}
122#endif
123
124Atom KMenuBar::KMenuBarPrivate::makeSelectionAtom()
125{
126#ifdef Q_WS_X11
127 if( selection_atom == None )
128 initAtoms();
129 return selection_atom;
130#else
131 return 0;
132#endif
133}
134
135KMenuBar::KMenuBar(QWidget *parent)
136 : QMenuBar(parent), d(new KMenuBarPrivate)
137{
138 connect( &d->selection_timer, SIGNAL(timeout()),
139 this, SLOT(selectionTimeout()));
140
141 connect( qApp->desktop(), SIGNAL(resized(int)), SLOT(updateFallbackSize()));
142
143 // toolbarAppearanceChanged(int) is sent when changing macstyle
144 connect( KGlobalSettings::self(), SIGNAL(toolbarAppearanceChanged(int)),
145 this, SLOT(slotReadConfig()));
146
147 slotReadConfig();
148}
149
150KMenuBar::~KMenuBar()
151{
152 delete d;
153}
154
155void KMenuBar::setTopLevelMenu(bool top_level)
156{
157 d->forcedTopLevel = top_level;
158 setTopLevelMenuInternal( top_level );
159}
160
161void KMenuBar::setTopLevelMenuInternal(bool top_level)
162{
163 if (d->forcedTopLevel)
164 top_level = true;
165
166 d->wasTopLevel = top_level;
167 if( parentWidget()
168 && parentWidget()->topLevelWidget()->isFullScreen())
169 top_level = false;
170
171 if ( isTopLevelMenu() == top_level )
172 return;
173 d->topLevel = top_level;
174 if ( isTopLevelMenu() )
175 {
176#ifdef Q_WS_X11
177 d->selection = new KSelectionWatcher( KMenuBarPrivate::makeSelectionAtom(),
178 DefaultScreen( QX11Info::display()));
179 connect( d->selection, SIGNAL(newOwner(Window)),
180 this, SLOT(updateFallbackSize()));
181 connect( d->selection, SIGNAL(lostOwner()),
182 this, SLOT(updateFallbackSize()));
183#endif
184 d->frameStyle = 0; //frameStyle();
185 d->lineWidth = 0; //lineWidth();
186 d->margin = 0; //margin();
187 d->fallback_mode = false;
188 bool wasShown = !isHidden();
189 setParent(parentWidget(), Qt::Window | Qt::Tool | Qt::FramelessWindowHint);
190 setGeometry(0,0,width(),height());
191#ifdef Q_WS_X11
192 KWindowSystem::setType( winId(), NET::TopMenu );
193#endif
194 if( parentWidget())
195 KWindowSystem::setMainWindow( this, parentWidget()->topLevelWidget()->winId());
196 //QMenuBar::setFrameStyle( NoFrame );
197 //QMenuBar::setLineWidth( 0 );
198 //QMenuBar::setMargin( 0 );
199 updateFallbackSize();
200 d->min_size = QSize( 0, 0 );
201 if( parentWidget() && !parentWidget()->isTopLevel())
202 setVisible( parentWidget()->isVisible());
203 else if ( wasShown )
204 show();
205 } else
206 {
207#ifdef Q_WS_X11
208 delete d->selection;
209 d->selection = NULL;
210#endif
211 setAttribute(Qt::WA_NoSystemBackground, false);
212 setBackgroundRole(QPalette::Button);
213 setFrameStyle( d->frameStyle );
214 setLineWidth( d->lineWidth );
215 setMargin( d->margin );
216 setMinimumSize( 0, 0 );
217 setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
218 updateMenuBarSize();
219 if ( parentWidget() )
220 setParent( parentWidget() );
221 }
222}
223
224bool KMenuBar::isTopLevelMenu() const
225{
226 return d->topLevel;
227}
228
229
230void KMenuBar::slotReadConfig()
231{
232 KConfigGroup cg( KGlobal::config(), "KDE" );
233 setTopLevelMenuInternal( cg.readEntry( "macStyle", false ) );
234}
235
236bool KMenuBar::eventFilter(QObject *obj, QEvent *ev)
237{
238 if ( d->topLevel )
239 {
240 if ( parentWidget() && obj == parentWidget()->topLevelWidget() )
241 {
242 if( ev->type() == QEvent::Resize )
243 return false; // ignore resizing of parent, QMenuBar would try to adjust size
244#ifdef QT3_SUPPORT
245 if ( ev->type() == QEvent::Accel || ev->type() == QEvent::AccelAvailable )
246 {
247 if ( QApplication::sendEvent( topLevelWidget(), ev ) )
248 return true;
249 }
250#endif
251 /* FIXME QEvent::ShowFullScreen is no more
252 if(ev->type() == QEvent::ShowFullScreen )
253 // will update the state properly
254 setTopLevelMenuInternal( d->topLevel );
255 */
256 }
257 if( parentWidget() && obj == parentWidget() && ev->type() == QEvent::ParentChange )
258 {
259 KWindowSystem::setMainWindow( this, parentWidget()->topLevelWidget()->winId());
260 setVisible( parentWidget()->isTopLevel() || parentWidget()->isVisible());
261 }
262 if( parentWidget() && !parentWidget()->isTopLevel() && obj == parentWidget())
263 { // if the parent is not toplevel, KMenuBar needs to match its visibility status
264 if( ev->type() == QEvent::Show )
265 {
266 KWindowSystem::setMainWindow( this, parentWidget()->topLevelWidget()->winId());
267 show();
268 }
269 if( ev->type() == QEvent::Hide )
270 hide();
271 }
272 }
273 else
274 {
275 if( parentWidget() && obj == parentWidget()->topLevelWidget())
276 {
277 if( ev->type() == QEvent::WindowStateChange
278 && !parentWidget()->topLevelWidget()->isFullScreen() )
279 setTopLevelMenuInternal( d->wasTopLevel );
280 }
281 }
282 return QMenuBar::eventFilter( obj, ev );
283}
284
285
286void KMenuBar::updateFallbackSize()
287{
288 if( !d->topLevel )
289 return;
290#ifdef Q_WS_X11
291 if( d->selection->owner() != None )
292#endif
293 { // somebody is managing us, don't mess anything, undo changes
294 // done in fallback mode if needed
295 d->selection_timer.stop();
296 if( d->fallback_mode )
297 {
298 d->fallback_mode = false;
299 KWindowSystem::setStrut( winId(), 0, 0, 0, 0 );
300 setMinimumSize( 0, 0 );
301 setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
302 updateMenuBarSize();
303 }
304 return;
305 }
306 if( d->selection_timer.isActive())
307 return;
308 d->selection_timer.setInterval(100);
309 d->selection_timer.setSingleShot(true);
310 d->selection_timer.start();
311}
312
313void KMenuBar::selectionTimeout()
314{ // nobody is managing us, handle resizing
315 if ( d->topLevel )
316 {
317 d->fallback_mode = true; // KMenuBar is handling its position itself
318 KConfigGroup xineramaConfig(KGlobal::config(),"Xinerama");
319 int screen = xineramaConfig.readEntry("MenubarScreen",
320 QApplication::desktop()->screenNumber(QPoint(0,0)) );
321 QRect area = QApplication::desktop()->screenGeometry(screen);
322 int margin = 0;
323 move(area.left() - margin, area.top() - margin);
324 setFixedSize(area.width() + 2* margin , heightForWidth( area.width() + 2 * margin ) );
325#ifdef Q_WS_X11
326 int strut_height = height() - margin;
327 if( strut_height < 0 )
328 strut_height = 0;
329 KWindowSystem::setStrut( winId(), 0, 0, strut_height, 0 );
330#endif
331 }
332}
333
334void KMenuBar::resizeEvent( QResizeEvent *e )
335{
336 if( e->spontaneous() && d->topLevel && !d->fallback_mode )
337 {
338 ++block_resize; // do not respond with configure request to ConfigureNotify event
339 QMenuBar::resizeEvent(e); // to avoid possible infinite loop
340 --block_resize;
341 }
342 else
343 QMenuBar::resizeEvent(e);
344}
345
346void KMenuBar::setGeometry( const QRect& r )
347{
348 setGeometry( r.x(), r.y(), r.width(), r.height() );
349}
350
351void KMenuBar::setGeometry( int x, int y, int w, int h )
352{
353 if( block_resize > 0 )
354 {
355 move( x, y );
356 return;
357 }
358 checkSize( w, h );
359 if( geometry() != QRect( x, y, w, h ))
360 QMenuBar::setGeometry( x, y, w, h );
361}
362
363void KMenuBar::resize( int w, int h )
364{
365 if( block_resize > 0 )
366 return;
367 checkSize( w, h );
368 if( size() != QSize( w, h ))
369 QMenuBar::resize( w, h );
370// kDebug() << "RS:" << w << ":" << h << ":" << width() << ":" << height() << ":" << minimumWidth() << ":" << minimumHeight();
371}
372
373void KMenuBar::resize( const QSize& s )
374{
375 QMenuBar::resize( s );
376}
377
378void KMenuBar::checkSize( int& w, int& h )
379{
380 if( !d->topLevel || d->fallback_mode )
381 return;
382 QSize s = sizeHint();
383 w = s.width();
384 h = s.height();
385 // This is not done as setMinimumSize(), because that would set the minimum
386 // size in WM_NORMAL_HINTS, and KWin would not allow changing to smaller size
387 // anymore
388 w = qMax( w, d->min_size.width());
389 h = qMax( h, d->min_size.height());
390}
391
392// QMenuBar's sizeHint() gives wrong size (insufficient width), which causes wrapping in the kicker applet
393QSize KMenuBar::sizeHint() const
394{
395 if( !d->topLevel || block_resize > 0 )
396 return QMenuBar::sizeHint();
397 // Since QMenuBar::sizeHint() may indirectly call resize(),
398 // avoid infinite recursion.
399 ++block_resize;
400 // find the minimum useful height, and enlarge the width until the menu fits in that height (one row)
401 int h = heightForWidth( 1000000 );
402 int w = QMenuBar::sizeHint().width();
403 // optimization - don't call heightForWidth() too many times
404 while( heightForWidth( w + 12 ) > h )
405 w += 12;
406 while( heightForWidth( w + 4 ) > h )
407 w += 4;
408 while( heightForWidth( w ) > h )
409 ++w;
410 --block_resize;
411 return QSize( w, h );
412}
413
414#ifdef Q_WS_X11
415bool KMenuBar::x11Event( XEvent* ev )
416{
417 if( ev->type == ClientMessage && ev->xclient.message_type == msg_type_atom
418 && ev->xclient.window == winId())
419 {
420 // QMenuBar is trying really hard to keep the size it deems right.
421 // Forcing minimum size and blocking resizing to match parent size
422 // in checkResizingToParent() seem to be the only way to make
423 // KMenuBar keep the size it wants
424 d->min_size = QSize( ev->xclient.data.l[ 1 ], ev->xclient.data.l[ 2 ] );
425// kDebug() << "MINSIZE:" << d->min_size;
426 updateMenuBarSize();
427 return true;
428 }
429 return QMenuBar::x11Event( ev );
430}
431#endif
432
433void KMenuBar::updateMenuBarSize()
434 {
435 //menuContentsChanged(); // trigger invalidating calculated size
436 resize( sizeHint()); // and resize to preferred size
437 }
438
439void KMenuBar::setFrameStyle( int style )
440{
441 if( d->topLevel )
442 d->frameStyle = style;
443// else
444// QMenuBar::setFrameStyle( style );
445}
446
447void KMenuBar::setLineWidth( int width )
448{
449 if( d->topLevel )
450 d->lineWidth = width;
451// else
452// QMenuBar::setLineWidth( width );
453}
454
455void KMenuBar::setMargin( int margin )
456{
457 if( d->topLevel )
458 d->margin = margin;
459// else
460// QMenuBar::setMargin( margin );
461}
462
463void KMenuBar::closeEvent( QCloseEvent* e )
464{
465 if( d->topLevel )
466 e->ignore(); // mainly for the fallback mode
467 else
468 QMenuBar::closeEvent( e );
469}
470
471void KMenuBar::paintEvent( QPaintEvent* pe )
472{
473 // Closes the BR77113
474 // We need to overload this method to paint only the menu items
475 // This way when the KMenuBar is embedded in the menu applet it
476 // integrates correctly.
477 //
478 // Background mode and origin are set so late because of styles
479 // using the polish() method to modify these settings.
480 //
481 // Of course this hack can safely be removed when real transparency
482 // will be available
483
484// if( !d->topLevel )
485 {
486 QMenuBar::paintEvent(pe);
487 }
488#if 0
489 else
490 {
491 QPainter p(this);
492 bool up_enabled = isUpdatesEnabled();
493 Qt::BackgroundMode bg_mode = backgroundMode();
494 BackgroundOrigin bg_origin = backgroundOrigin();
495
496 setUpdatesEnabled(false);
497 setBackgroundMode(Qt::X11ParentRelative);
498 setBackgroundOrigin(WindowOrigin);
499
500 p.eraseRect( rect() );
501 erase();
502
503 QColorGroup g = colorGroup();
504 bool e;
505
506 for ( int i=0; i<(int)count(); i++ )
507 {
508 QMenuItem *mi = findItem( idAt( i ) );
509
510 if ( !mi->text().isEmpty() || !mi->icon().isNull() )
511 {
512 QRect r = itemRect(i);
513 if(r.isEmpty() || !mi->isVisible())
514 continue;
515
516 e = mi->isEnabled() && mi->isVisible();
517 if ( e )
518 g = isEnabled() ? ( isActiveWindow() ? palette().active() :
519 palette().inactive() ) : palette().disabled();
520 else
521 g = palette().disabled();
522
523 bool item_active = ( activeAction() == mi );
524
525 p.setClipRect(r);
526
527 if( item_active )
528 {
529 QStyleOptionMenuItem miOpt;
530 miOpt.init(this);
531 miOpt.rect = r;
532 miOpt.text = mi->text();
533 miOpt.icon = mi->icon();
534 miOpt.palette = g;
535
536 QStyle::State flags = QStyle::State_None;
537 if (isEnabled() && e)
538 flags |= QStyle::State_Enabled;
539 if ( item_active )
540 flags |= QStyle::State_Active;
541 if ( item_active && actItemDown )
542 flags |= QStyle::State_Down;
543 flags |= QStyle::State_HasFocus;
544
545 mi->state = flags;
546
547
548 style()->drawControl(QStyle::CE_MenuBarItem, &miOpt, &p, this);
549 }
550 else
551 {
552 style()->drawItem(p, r, Qt::AlignCenter | Qt::AlignVCenter | Qt::TextShowMnemonic,
553 g, e, mi->pixmap(), mi->text());
554 }
555 }
556 }
557
558 setBackgroundOrigin(bg_origin);
559 setBackgroundMode(bg_mode);
560 setUpdatesEnabled(up_enabled);
561 }
562#endif
563}
564
565#include "kmenubar.moc"
KConfigGroup
KConfigGroup::readEntry
QString readEntry(const char *key, const char *aDefault=0) const
KGlobalSettings::self
static KGlobalSettings * self()
Return the KGlobalSettings singleton.
Definition: kglobalsettings.cpp:188
KMenuBar::setTopLevelMenu
void setTopLevelMenu(bool top_level=true)
This controls whether or not this menubar will be a top-level bar similar to the way Macintosh handle...
Definition: kmenubar.cpp:155
KMenuBar::setGeometry
virtual void setGeometry(const QRect &r)
Definition: kmenubar.cpp:346
KMenuBar::sizeHint
virtual QSize sizeHint() const
Definition: kmenubar.cpp:393
KMenuBar::eventFilter
virtual bool eventFilter(QObject *, QEvent *)
Definition: kmenubar.cpp:236
KMenuBar::slotReadConfig
void slotReadConfig()
Definition: kmenubar.cpp:230
KMenuBar::paintEvent
virtual void paintEvent(QPaintEvent *)
Definition: kmenubar.cpp:471
KMenuBar::KMenuBar
KMenuBar(QWidget *parent=0)
Definition: kmenubar.cpp:135
KMenuBar::isTopLevelMenu
bool isTopLevelMenu() const
Is our menubar a top-level (Macintosh style) menubar?
Definition: kmenubar.cpp:224
KMenuBar::resize
virtual void resize(int w, int h)
Definition: kmenubar.cpp:363
KMenuBar::resizeEvent
virtual void resizeEvent(QResizeEvent *)
Definition: kmenubar.cpp:334
KMenuBar::x11Event
virtual bool x11Event(XEvent *)
Definition: kmenubar.cpp:415
KMenuBar::closeEvent
virtual void closeEvent(QCloseEvent *)
Definition: kmenubar.cpp:463
KMenuBar::setLineWidth
virtual void setLineWidth(int)
Definition: kmenubar.cpp:447
KMenuBar::setFrameStyle
virtual void setFrameStyle(int)
Definition: kmenubar.cpp:439
KMenuBar::~KMenuBar
~KMenuBar()
Definition: kmenubar.cpp:150
KMenuBar::setMargin
virtual void setMargin(int)
Definition: kmenubar.cpp:455
KSelectionWatcher
This class implements watching manager selections, as described in the ICCCM section 2....
Definition: kmanagerselection.h:157
KWindowSystem::setType
static void setType(WId win, NET::WindowType windowType)
Sets the type of window win to windowType.
Definition: kwindowsystem_mac.cpp:473
KWindowSystem::setMainWindow
static void setMainWindow(QWidget *subwindow, WId mainwindow)
Sets the parent window of subwindow to be mainwindow.
Definition: kwindowsystem_mac.cpp:412
KWindowSystem::setStrut
static void setStrut(WId win, int left, int right, int top, int bottom)
Convenience function for setExtendedStrut() that automatically makes struts as wide/high as the scree...
Definition: kwindowsystem_mac.cpp:591
NET::TopMenu
@ TopMenu
indicates a toplevel menu (AKA macmenu).
Definition: netwm_def.h:345
QMenuBar
QObject
QWidget
kapplication.h
Atom
unsigned long Atom
Definition: kapplication.h:40
kconfig.h
kconfiggroup.h
kdebug.h
kglobal.h
kglobalsettings.h
timeout
int timeout
kmanagerselection.h
block_resize
static int block_resize
Definition: kmenubar.cpp:68
selection_atom
static Atom selection_atom
Definition: kmenubar.cpp:107
msg_type_atom
static Atom msg_type_atom
Definition: kmenubar.cpp:108
initAtoms
static void initAtoms()
Definition: kmenubar.cpp:111
kmenubar.h
kwindowsystem.h
KGlobal::config
KSharedConfigPtr config()
None
None
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal