summaryrefslogtreecommitdiffstats
path: root/tdeui/tdemenubar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdeui/tdemenubar.cpp')
-rw-r--r--tdeui/tdemenubar.cpp571
1 files changed, 571 insertions, 0 deletions
diff --git a/tdeui/tdemenubar.cpp b/tdeui/tdemenubar.cpp
new file mode 100644
index 000000000..0a5fe0188
--- /dev/null
+++ b/tdeui/tdemenubar.cpp
@@ -0,0 +1,571 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997, 1998, 1999, 2000 Sven Radej (radej@kde.org)
+ Copyright (C) 1997, 1998, 1999, 2000 Matthias Ettrich (ettrich@kde.org)
+ Copyright (C) 1999, 2000 Daniel "Mosfet" Duley (mosfet@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef INCLUDE_MENUITEM_DEF
+#define INCLUDE_MENUITEM_DEF
+#endif
+
+#include "config.h"
+#include <tqevent.h>
+#include <tqobjectlist.h>
+#include <tqaccel.h>
+#include <tqpainter.h>
+#include <tqstyle.h>
+#include <tqtimer.h>
+
+#include <tdeconfig.h>
+#include <tdeglobalsettings.h>
+#include <tdemenubar.h>
+#include <tdeapplication.h>
+#include <tdeglobal.h>
+#include <kdebug.h>
+#include <kmanagerselection.h>
+
+#ifdef Q_WS_X11
+#include <twin.h>
+#include <twinmodule.h>
+#include <qxembed.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+
+#ifndef None
+#define None 0L
+#endif
+#endif
+
+/*
+
+ Toplevel menubar (not for the fallback size handling done by itself):
+ - should not alter position or set strut
+ - every toplevel must have at most one matching topmenu
+ - embedder won't allow shrinking below a certain size
+ - must have WM_TRANSIENT_FOR pointing the its mainwindow
+ - the exception is desktop's menubar, which can be transient for root window
+ because of using root window as the desktop window
+ - Fitts' Law
+
+*/
+
+class KMenuBar::KMenuBarPrivate
+{
+public:
+ KMenuBarPrivate()
+ : forcedTopLevel( false ),
+ topLevel( false ),
+ wasTopLevel( false ),
+#ifdef Q_WS_X11
+ selection( NULL ),
+#endif
+ min_size( 0, 0 )
+ {
+ }
+ ~KMenuBarPrivate()
+ {
+#ifdef Q_WS_X11
+ delete selection;
+#endif
+ }
+ bool forcedTopLevel;
+ bool topLevel;
+ bool wasTopLevel; // when TLW is fullscreen, remember state
+ int frameStyle; // only valid in toplevel mode
+ int lineWidth; // dtto
+ int margin; // dtto
+ bool fallback_mode; // dtto
+#ifdef Q_WS_X11
+ TDESelectionWatcher* selection;
+#endif
+ TQTimer selection_timer;
+ TQSize min_size;
+ static Atom makeSelectionAtom();
+};
+
+#ifdef Q_WS_X11
+static Atom selection_atom = None;
+static Atom msg_type_atom = None;
+
+static
+void initAtoms()
+{
+ char nm[ 100 ];
+ sprintf( nm, "_KDE_TOPMENU_OWNER_S%d", DefaultScreen( tqt_xdisplay()));
+ char nm2[] = "_KDE_TOPMENU_MINSIZE";
+ char* names[ 2 ] = { nm, nm2 };
+ Atom atoms[ 2 ];
+ XInternAtoms( tqt_xdisplay(), names, 2, False, atoms );
+ selection_atom = atoms[ 0 ];
+ msg_type_atom = atoms[ 1 ];
+}
+#endif
+
+Atom KMenuBar::KMenuBarPrivate::makeSelectionAtom()
+{
+#ifdef Q_WS_X11
+ if( selection_atom == None )
+ initAtoms();
+ return selection_atom;
+#else
+ return 0;
+#endif
+}
+
+KMenuBar::KMenuBar(TQWidget *parent, const char *name)
+ : TQMenuBar(parent, name)
+{
+#ifdef Q_WS_X11
+ QXEmbed::initialize();
+#endif
+ d = new KMenuBarPrivate;
+ connect( &d->selection_timer, TQT_SIGNAL( timeout()),
+ this, TQT_SLOT( selectionTimeout()));
+
+ connect( tqApp->desktop(), TQT_SIGNAL( resized( int )), TQT_SLOT( updateFallbackSize()));
+
+ if ( kapp )
+ // toolbarAppearanceChanged(int) is sent when changing macstyle
+ connect( kapp, TQT_SIGNAL(toolbarAppearanceChanged(int)),
+ this, TQT_SLOT(slotReadConfig()));
+
+ slotReadConfig();
+}
+
+KMenuBar::~KMenuBar()
+{
+ delete d;
+}
+
+void KMenuBar::setTopLevelMenu(bool top_level)
+{
+ d->forcedTopLevel = top_level;
+ setTopLevelMenuInternal( top_level );
+}
+
+void KMenuBar::setTopLevelMenuInternal(bool top_level)
+{
+ if (d->forcedTopLevel)
+ top_level = true;
+
+ d->wasTopLevel = top_level;
+ if( parentWidget()
+ && parentWidget()->topLevelWidget()->isFullScreen())
+ top_level = false;
+
+ if ( isTopLevelMenu() == top_level )
+ return;
+ d->topLevel = top_level;
+ if ( isTopLevelMenu() )
+ {
+#ifdef Q_WS_X11
+ d->selection = new TDESelectionWatcher( KMenuBarPrivate::makeSelectionAtom(),
+ DefaultScreen( tqt_xdisplay()));
+ connect( d->selection, TQT_SIGNAL( newOwner( Window )),
+ this, TQT_SLOT( updateFallbackSize()));
+ connect( d->selection, TQT_SIGNAL( lostOwner()),
+ this, TQT_SLOT( updateFallbackSize()));
+#endif
+ d->frameStyle = frameStyle();
+ d->lineWidth = lineWidth();
+ d->margin = margin();
+ d->fallback_mode = false;
+ bool wasShown = !isHidden();
+ reparent( parentWidget(), (WFlags)(WType_TopLevel | WStyle_Tool | WStyle_Customize | WStyle_NoBorder), TQPoint(0,0), false );
+#ifdef Q_WS_X11
+ KWin::setType( winId(), NET::TopMenu );
+ if( parentWidget())
+ XSetTransientForHint( tqt_xdisplay(), winId(), parentWidget()->topLevelWidget()->winId());
+#endif
+ TQMenuBar::setFrameStyle( NoFrame );
+ TQMenuBar::setLineWidth( 0 );
+ TQMenuBar::setMargin( 0 );
+ updateFallbackSize();
+ d->min_size = TQSize( 0, 0 );
+ if( parentWidget() && !parentWidget()->isTopLevel())
+ setShown( parentWidget()->isVisible());
+ else if ( wasShown )
+ show();
+ } else
+ {
+#ifdef Q_WS_X11
+ delete d->selection;
+ d->selection = NULL;
+#endif
+ setBackgroundMode( PaletteButton );
+ setFrameStyle( d->frameStyle );
+ setLineWidth( d->lineWidth );
+ setMargin( d->margin );
+ setMinimumSize( 0, 0 );
+ setMaximumSize( TQWIDGETSIZE_MAX, TQWIDGETSIZE_MAX );
+ updateMenuBarSize();
+ if ( parentWidget() )
+ reparent( parentWidget(), TQPoint(0,0), !isHidden());
+ }
+}
+
+bool KMenuBar::isTopLevelMenu() const
+{
+ return d->topLevel;
+}
+
+// KDE4 remove
+void KMenuBar::show()
+{
+ TQMenuBar::show();
+}
+
+void KMenuBar::slotReadConfig()
+{
+ TDEConfig *config = TDEGlobal::config();
+ TDEConfigGroupSaver saver( config, "KDE" );
+ setTopLevelMenuInternal( config->readBoolEntry( "macStyle", false ) );
+}
+
+bool KMenuBar::eventFilter(TQObject *obj, TQEvent *ev)
+{
+ if ( d->topLevel )
+ {
+ if ( parentWidget() && TQT_BASE_OBJECT(obj) == TQT_BASE_OBJECT(parentWidget()->topLevelWidget()) )
+ {
+ if( ev->type() == TQEvent::Resize )
+ return false; // ignore resizing of parent, TQMenuBar would try to adjust size
+ if ( ev->type() == TQEvent::Accel || ev->type() == TQEvent::AccelAvailable )
+ {
+ if ( TQApplication::sendEvent( topLevelWidget(), ev ) )
+ return true;
+ }
+ if(ev->type() == TQEvent::ShowFullScreen )
+ // will update the state properly
+ setTopLevelMenuInternal( d->topLevel );
+ }
+ if( parentWidget() && TQT_BASE_OBJECT(obj) == TQT_BASE_OBJECT(parentWidget()) && ev->type() == TQEvent::Reparent )
+ {
+#ifdef Q_WS_X11
+ XSetTransientForHint( tqt_xdisplay(), winId(), parentWidget()->topLevelWidget()->winId());
+#else
+ //TODO: WIN32?
+#endif
+ setShown( parentWidget()->isTopLevel() || parentWidget()->isVisible());
+ }
+ if( parentWidget() && !parentWidget()->isTopLevel() && TQT_BASE_OBJECT(obj) == TQT_BASE_OBJECT(parentWidget()))
+ { // if the parent is not toplevel, KMenuBar needs to match its visibility status
+ if( ev->type() == TQEvent::Show )
+ {
+#ifdef Q_WS_X11
+ XSetTransientForHint( tqt_xdisplay(), winId(), parentWidget()->topLevelWidget()->winId());
+#else
+ //TODO: WIN32?
+#endif
+ show();
+ }
+ if( ev->type() == TQEvent::Hide )
+ hide();
+ }
+ }
+ else
+ {
+ if( parentWidget() && TQT_BASE_OBJECT(obj) == TQT_BASE_OBJECT(parentWidget()->topLevelWidget()))
+ {
+ if( ev->type() == TQEvent::WindowStateChange
+ && !parentWidget()->topLevelWidget()->isFullScreen() )
+ setTopLevelMenuInternal( d->wasTopLevel );
+ }
+ }
+ return TQMenuBar::eventFilter( obj, ev );
+}
+
+// KDE4 remove
+void KMenuBar::showEvent( TQShowEvent *e )
+{
+ TQMenuBar::showEvent(e);
+}
+
+void KMenuBar::updateFallbackSize()
+{
+ if( !d->topLevel )
+ return;
+#ifdef Q_WS_X11
+ if( d->selection->owner() != None )
+#endif
+ { // somebody is managing us, don't mess anything, undo changes
+ // done in fallback mode if needed
+ d->selection_timer.stop();
+ if( d->fallback_mode )
+ {
+ d->fallback_mode = false;
+ KWin::setStrut( winId(), 0, 0, 0, 0 );
+ setMinimumSize( 0, 0 );
+ setMaximumSize( TQWIDGETSIZE_MAX, TQWIDGETSIZE_MAX );
+ updateMenuBarSize();
+ }
+ return;
+ }
+ if( d->selection_timer.isActive())
+ return;
+ d->selection_timer.start( 100, true );
+}
+
+void KMenuBar::selectionTimeout()
+{ // nobody is managing us, handle resizing
+ if ( d->topLevel )
+ {
+ d->fallback_mode = true; // KMenuBar is handling its position itself
+ TDEConfigGroup xineramaConfig(TDEGlobal::config(),"Xinerama");
+ int screen = xineramaConfig.readNumEntry("MenubarScreen",
+ TQApplication::desktop()->screenNumber(TQPoint(0,0)) );
+ TQRect area;
+ if (kapp->desktop()->numScreens() < 2)
+ area = kapp->desktop()->geometry();
+ else
+ area = kapp->desktop()->screenGeometry(screen);
+ int margin = 0;
+ move(area.left() - margin, area.top() - margin);
+ setFixedSize(area.width() + 2* margin , heightForWidth( area.width() + 2 * margin ) );
+#ifdef Q_WS_X11
+ int strut_height = height() - margin;
+ if( strut_height < 0 )
+ strut_height = 0;
+ KWin::setStrut( winId(), 0, 0, strut_height, 0 );
+#endif
+ }
+}
+
+int KMenuBar::block_resize = 0;
+
+void KMenuBar::resizeEvent( TQResizeEvent *e )
+{
+ if( e->spontaneous() && d->topLevel && !d->fallback_mode )
+ {
+ ++block_resize; // do not respond with configure request to ConfigureNotify event
+ TQMenuBar::resizeEvent(e); // to avoid possible infinite loop
+ --block_resize;
+ }
+ else
+ TQMenuBar::resizeEvent(e);
+}
+
+void KMenuBar::setGeometry( const TQRect& r )
+{
+ setGeometry( r.x(), r.y(), r.width(), r.height() );
+}
+
+void KMenuBar::setGeometry( int x, int y, int w, int h )
+{
+ if( block_resize > 0 )
+ {
+ move( x, y );
+ return;
+ }
+ checkSize( w, h );
+ if( geometry() != TQRect( x, y, w, h ))
+ TQMenuBar::setGeometry( x, y, w, h );
+}
+
+void KMenuBar::resize( int w, int h )
+{
+ if( block_resize > 0 )
+ return;
+ checkSize( w, h );
+ if( size() != TQSize( w, h ))
+ TQMenuBar::resize( w, h );
+// kdDebug() << "RS:" << w << ":" << h << ":" << width() << ":" << height() << ":" << minimumWidth() << ":" << minimumHeight() << endl;
+}
+
+void KMenuBar::checkSize( int& w, int& h )
+{
+ if( !d->topLevel || d->fallback_mode )
+ return;
+ TQSize s = sizeHint();
+ w = s.width();
+ h = s.height();
+ // This is not done as setMinimumSize(), because that would set the minimum
+ // size in WM_NORMAL_HINTS, and KWin would not allow changing to smaller size
+ // anymore
+ w = KMAX( w, d->min_size.width());
+ h = KMAX( h, d->min_size.height());
+}
+
+// QMenuBar's sizeHint() gives wrong size (insufficient width), which causes wrapping in the kicker applet
+TQSize KMenuBar::sizeHint() const
+{
+ if( !d->topLevel || block_resize > 0 )
+ return TQMenuBar::sizeHint();
+ // Since TQMenuBar::sizeHint() may indirectly call resize(),
+ // avoid infinite recursion.
+ ++block_resize;
+ // find the minimum useful height, and enlarge the width until the menu fits in that height (one row)
+ int h = heightForWidth( 1000000 );
+ int w = TQMenuBar::sizeHint().width();
+ // optimization - don't call heightForWidth() too many times
+ while( heightForWidth( w + 12 ) > h )
+ w += 12;
+ while( heightForWidth( w + 4 ) > h )
+ w += 4;
+ while( heightForWidth( w ) > h )
+ ++w;
+ --block_resize;
+ return TQSize( w, h );
+}
+
+#ifdef Q_WS_X11
+bool KMenuBar::x11Event( XEvent* ev )
+{
+ if( ev->type == ClientMessage && ev->xclient.message_type == msg_type_atom
+ && ev->xclient.window == winId())
+ {
+ // TQMenuBar is trying really hard to keep the size it deems right.
+ // Forcing minimum size and blocking resizing to match parent size
+ // in checkResizingToParent() seem to be the only way to make
+ // KMenuBar keep the size it wants
+ d->min_size = TQSize( ev->xclient.data.l[ 1 ], ev->xclient.data.l[ 2 ] );
+// kdDebug() << "MINSIZE:" << d->min_size << endl;
+ updateMenuBarSize();
+ return true;
+ }
+ return TQMenuBar::x11Event( ev );
+}
+#endif
+
+void KMenuBar::updateMenuBarSize()
+ {
+ menuContentsChanged(); // trigger invalidating calculated size
+ resize( sizeHint()); // and resize to preferred size
+ }
+
+void KMenuBar::setFrameStyle( int style )
+{
+ if( d->topLevel )
+ d->frameStyle = style;
+ else
+ TQMenuBar::setFrameStyle( style );
+}
+
+void KMenuBar::setLineWidth( int width )
+{
+ if( d->topLevel )
+ d->lineWidth = width;
+ else
+ TQMenuBar::setLineWidth( width );
+}
+
+void KMenuBar::setMargin( int margin )
+{
+ if( d->topLevel )
+ d->margin = margin;
+ else
+ TQMenuBar::setMargin( margin );
+}
+
+void KMenuBar::closeEvent( TQCloseEvent* e )
+{
+ if( d->topLevel )
+ e->ignore(); // mainly for the fallback mode
+ else
+ TQMenuBar::closeEvent( e );
+}
+
+void KMenuBar::drawContents( TQPainter* p )
+{
+ // Closes the BR77113
+ // We need to overload this method to paint only the menu items
+ // This way when the KMenuBar is embedded in the menu applet it
+ // integrates correctly.
+ //
+ // Background mode and origin are set so late because of styles
+ // using the polish() method to modify these settings.
+ //
+ // Of course this hack can safely be removed when real transparency
+ // will be available
+
+ if( !d->topLevel )
+ {
+ TQMenuBar::drawContents(p);
+ }
+ else
+ {
+ bool up_enabled = isUpdatesEnabled();
+ BackgroundMode bg_mode = backgroundMode();
+ BackgroundOrigin bg_origin = backgroundOrigin();
+
+ setUpdatesEnabled(false);
+ setBackgroundMode(X11ParentRelative);
+ setBackgroundOrigin(WindowOrigin);
+
+ p->eraseRect( rect() );
+ erase();
+
+ TQColorGroup g = colorGroup();
+ bool e;
+
+ for ( int i=0; i<(int)count(); i++ )
+ {
+ TQMenuItem *mi = findItem( idAt( i ) );
+
+ if ( !mi->text().isNull() || mi->pixmap() )
+ {
+ TQRect r = itemRect(i);
+ if(r.isEmpty() || !mi->isVisible())
+ continue;
+
+ e = mi->isEnabledAndVisible();
+ if ( e )
+ g = isEnabled() ? ( isActiveWindow() ? palette().active() :
+ palette().inactive() ) : palette().disabled();
+ else
+ g = palette().disabled();
+
+ bool item_active = ( actItem == i );
+
+ p->setClipRect(r);
+
+ if( item_active )
+ {
+ TQStyle::SFlags flags = TQStyle::Style_Default;
+ if (isEnabled() && e)
+ flags |= TQStyle::Style_Enabled;
+ if ( item_active )
+ flags |= TQStyle::Style_Active;
+ if ( item_active && actItemDown )
+ flags |= TQStyle::Style_Down;
+ flags |= TQStyle::Style_HasFocus;
+
+ style().drawControl(TQStyle::CE_MenuBarItem, p, this,
+ r, g, flags, TQStyleOption(mi));
+ }
+ else
+ {
+ style().drawItem(p, r, AlignCenter | AlignVCenter | ShowPrefix,
+ g, e, mi->pixmap(), mi->text());
+ }
+ }
+ }
+
+ setBackgroundOrigin(bg_origin);
+ setBackgroundMode(bg_mode);
+ setUpdatesEnabled(up_enabled);
+ }
+}
+
+void KMenuBar::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "tdemenubar.moc"