diff options
Diffstat (limited to 'kicker/applets/menu')
-rw-r--r-- | kicker/applets/menu/Makefile.am | 20 | ||||
-rw-r--r-- | kicker/applets/menu/menuapplet.cpp | 511 | ||||
-rw-r--r-- | kicker/applets/menu/menuapplet.desktop | 128 | ||||
-rw-r--r-- | kicker/applets/menu/menuapplet.h | 258 |
4 files changed, 917 insertions, 0 deletions
diff --git a/kicker/applets/menu/Makefile.am b/kicker/applets/menu/Makefile.am new file mode 100644 index 000000000..5bfaeee18 --- /dev/null +++ b/kicker/applets/menu/Makefile.am @@ -0,0 +1,20 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = menu_panelapplet.la + +menu_panelapplet_la_SOURCES = menuapplet.cpp menuapplet.skel + +noinst_HEADERS = menuapplet.h + +menu_panelapplet_la_METASOURCES = AUTO + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = menuapplet.desktop + +EXTRA_DIST = $(lnk_DATA) + +menu_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +menu_panelapplet_la_LIBADD = $(LIB_KDEUI) + +messages: + $(XGETTEXT) *.cpp *.h -o $(podir)/kmenuapplet.pot diff --git a/kicker/applets/menu/menuapplet.cpp b/kicker/applets/menu/menuapplet.cpp new file mode 100644 index 000000000..ae10614c6 --- /dev/null +++ b/kicker/applets/menu/menuapplet.cpp @@ -0,0 +1,511 @@ +/***************************************************************** + +Copyright (c) 2002 Siegfried Nijssen <snijssen@liacs.nl> +Copyright (c) 2003 Lubos Lunak <l.lunak@suse.cz> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#define _MENUAPPLET_CPP_ + +#include "menuapplet.h" + +#include <qlayout.h> +#include <qtooltip.h> +#include <qvariant.h> // avoid X11 #define's + +#include <kapplication.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kwin.h> +#include <kwinmodule.h> + +#include <netwm.h> + +#include <X11/Xlib.h> + +/* + + KMenuBar from KDE3.1 and older won't work very well with this applet. + This is because QMenuBar tries really hard to keep its preffered size, + se even if the X window for the menubar has the size enforced by this + applet, Qt thinks it has the size Qt wants. This results in parts + of the menubar not being repainted. Also, old KMenuBar always forced + with to be the width of the screen, so even if the menubar has only + few entries, this applet will still indicate the menubar doesn't + fit completely in it. There's no way to fix this, besides upgrading + to KDE3.2. + +*/ + + +extern Time qt_x_time; + +extern "C" +{ + KDE_EXPORT KPanelApplet* init( QWidget* parent_P, const QString& configFile_P ) + { + KGlobal::locale()->insertCatalogue("kmenuapplet"); + return new KickerMenuApplet::Applet( configFile_P, parent_P ); + } +} + +namespace KickerMenuApplet +{ + +static const int MOVE_DIFF = 100; // size increment for left/right menu moving +static const int GROW_WIDTH = 10; // width of grow buttons + +const long SUPPORTED_WINDOW_TYPES = NET::NormalMask | NET::DesktopMask | NET::DockMask + | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask + | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask; + +Applet::Applet( const QString& configFile_P, QWidget* parent_P ) + : KPanelApplet( configFile_P, Normal, 0, parent_P, "menuapplet" ), + DCOPObject( "menuapplet" ), + module( NULL ), + active_menu( NULL ), + selection( NULL ), + selection_watcher( NULL ), + desktop_menu( false ), + topEdgeOffset( 0 ) + { + setBackgroundOrigin(AncestorOrigin); + dcopclient.registerAs( "menuapplet", false ); + // toolbarAppearanceChanged(int) is sent when changing macstyle + connect( kapp, SIGNAL( toolbarAppearanceChanged( int )), + this, SLOT( readSettings())); + claimSelection(); + readSettings(); + updateTopEdgeOffset(); + } + +Applet::~Applet() + { + lostSelection(); // release all menu's before really loosing the selection + delete selection; + delete selection_watcher; + delete module; + KGlobal::locale()->removeCatalogue("kmenuapplet"); + } + +void Applet::windowAdded( WId w_P ) + { + NETWinInfo info( qt_xdisplay(), w_P, qt_xrootwin(), NET::WMWindowType ); + if( info.windowType( SUPPORTED_WINDOW_TYPES ) != NET::TopMenu ) + return; +// kdDebug() << "embedding:" << w_P << endl; + Window transient_for = KWin::transientFor( w_P ); + if( transient_for == None ) + return; + MenuEmbed* embed; + if( transient_for == qt_xrootwin()) + { + embed = new MenuEmbed( transient_for, true, this ); + } + else + { + KWin::WindowInfo info2 = KWin::windowInfo( transient_for, NET::WMWindowType ); + embed = new MenuEmbed( transient_for, + info2.windowType( SUPPORTED_WINDOW_TYPES ) == NET::Desktop, this ); + } + embed->hide(); + embed->move( 0, -topEdgeOffset ); + embed->resize( embed->width(), height() + topEdgeOffset ); + embed->embed( w_P ); + if( embed->embeddedWinId() == None ) + { + delete embed; + return; + } + menus.append( embed ); + // in case the app mapped its menu after its mainwindow, check which menu should be shown + activeWindowChanged( module->activeWindow()); + } + +// - if the active window has its topmenu -> show the menu +// - if desktop menu is enabled (i.e. explicitly in kdesktop) : +// - show it +// - otherwise show nothing +void Applet::activeWindowChanged( WId w_P ) + { +// kdDebug() << "active:" << w_P << endl; + for( WId window = w_P; + window != None; + window = tryTransientFor( window )) + { + for( QValueList< MenuEmbed* >::ConstIterator it = menus.begin(); + it != menus.end(); + ++it ) + { + if( window == (*it)->mainWindow()) + { + activateMenu( *it ); + return; + } + } + } +// kdDebug() << "no active" << endl; + // No menu for active window found - if desktop menu + // (in kdesktoprc) is enabled, use kdesktop's menu instead of none. + bool try_desktop = desktop_menu; + if( !try_desktop && w_P != None ) + { // also use the desktop menu if the active window is desktop + KWin::WindowInfo info = KWin::windowInfo( w_P, NET::WMWindowType ); + if( info.windowType( SUPPORTED_WINDOW_TYPES ) == NET::Desktop ) + try_desktop = true; + } + if( try_desktop ) + { + for( QValueList< MenuEmbed* >::ConstIterator it = menus.begin(); + it != menus.end(); + ++it ) + { + if( (*it)->isDesktopMenu()) + { + activateMenu( *it ); + return; + } + } + } + activateMenu( NULL ); + } + +void Applet::activateMenu( MenuEmbed* embed_P ) + { + if( embed_P != active_menu ) + { +// kdDebug() << "activate:" << embed_P << endl; + if( active_menu != NULL ) + active_menu->hide(); + active_menu = embed_P; + if( active_menu != NULL ) + { + active_menu->show(); + //if (embed->isDesktopMenu()) + { + active_menu->setMinimumSize( width(), height() + topEdgeOffset ); + } + } + emit updateLayout(); + } + + setBackground(); + } + +void Applet::updateMenuGeometry( MenuEmbed* embed ) + { + if( embed == active_menu ) + emit updateLayout(); + } + +// If there's no menu for the window, try finding menu for its mainwindow +// (where the window's WM_TRANSIENT_FOR property points). +// If the window is modal (_NET_WM_STATE_MODAL), stop. +WId Applet::tryTransientFor( WId w_P ) + { + KWin::WindowInfo info = KWin::windowInfo( w_P, NET::WMState ); + if( info.state() & NET::Modal ) + return None; + WId ret = KWin::transientFor( w_P ); + if( ret == qt_xrootwin()) + ret = None; + return ret; + } + +void Applet::menuLost( MenuEmbed* embed ) + { + for( QValueList< MenuEmbed* >::Iterator it = menus.begin(); + it != menus.end(); + ++it ) + { + if( *it == embed ) + { + menus.remove( it ); + embed->deleteLater(); +// kdDebug() << "deleting:" << (*it)->mainWindow() << endl; + if( embed == active_menu ) + { + active_menu = NULL; + // trigger selecting new active menu + activeWindowChanged( module->activeWindow()); + } + return; + } + } + } + +void Applet::positionChange( Position ) + { + updateTopEdgeOffset(); + } + +// Detect mouse movement at the top screen edge also if the menubar +// has a popup open - in such case, Qt has a grab, and this avoids +// Kicker's FittsLawFrame. Therefore move the menubar a bit higher, +// so that it actually is positioned exactly at the screen edge +// (i.e. at a negative y coordinate within this applet, due to +// Kicker's frame). +void Applet::updateTopEdgeOffset() + { + QPoint p = topLevelWidget()->mapToGlobal( QPoint( 0, 0 )); + if( p.y() <= 2 ) // 2 = work also when running in appletproxy + topEdgeOffset = mapToGlobal( QPoint( 0, 0 )).y() - p.y(); + else + topEdgeOffset = 0; + if( active_menu != NULL ) + active_menu->move( active_menu->x(), -topEdgeOffset ); + } + +void Applet::paletteChange(const QPalette & /* oldPalette */) +{ + setBackground(); +} + +void Applet::moveEvent( QMoveEvent* ) +{ + setBackground(); +} + +void Applet::setBackground() +{ + if (active_menu) + active_menu->setBackground(); +} + +void Applet::claimSelection() + { + assert( selection == NULL ); + selection = new KSelectionOwner( makeSelectionAtom(), DefaultScreen( qt_xdisplay())); +// force taking the selection, but don't kill previous owner + if( selection->claim( true, false )) + { + delete selection_watcher; + selection_watcher = NULL; + connect( selection, SIGNAL( lostOwnership()), SLOT( lostSelection())); + module = new KWinModule; + connect( module, SIGNAL( windowAdded( WId )), this, SLOT( windowAdded( WId ))); + connect( module, SIGNAL( activeWindowChanged( WId )), + this, SLOT( activeWindowChanged( WId ))); + QValueList< WId > windows = module->windows(); + for( QValueList< WId >::ConstIterator it = windows.begin(); + it != windows.end(); + ++it ) + windowAdded( *it ); + activeWindowChanged( module->activeWindow()); + } + else + lostSelection(); + } + +void Applet::lostSelection() + { + if( selection == NULL ) + return; +// kdDebug() << "lost selection" << endl; + for( QValueList< MenuEmbed* >::ConstIterator it = menus.begin(); + it != menus.end(); + ++it ) + delete (*it); // delete all MenuEmbed's = release all menus + menus.clear(); + active_menu = NULL; + if( selection_watcher == NULL ) + { + selection_watcher = new KSelectionWatcher( makeSelectionAtom(), DefaultScreen( qt_xdisplay())); + connect( selection_watcher, SIGNAL( lostOwner()), this, SLOT( claimSelection())); + } + delete module; + module = NULL; + selection->deleteLater(); + selection = NULL; + // selection_watcher stays + } + +void Applet::readSettings() + { + KConfig cfg( "kdesktoprc", true ); + cfg.setGroup( "Menubar" ); + desktop_menu = cfg.readBoolEntry( "ShowMenubar", false ); + cfg.setGroup( "KDE" ); + if( cfg.readBoolEntry( "macStyle", false ) || desktop_menu ) + QToolTip::remove( this ); + else + QToolTip::add( this, i18n( + "You do not appear to have enabled the standalone menubar; " + "enable it in the Behavior control module for desktop." )); + if( !isDisabled() && active_menu == NULL ) + activeWindowChanged( module->activeWindow()); //enforce desktop_menu + } + +void Applet::configure() + { + readSettings(); + } + +int Applet::widthForHeight( int ) const + { + if (active_menu) + return active_menu->width(); + return 0; // we're stretch applet + } + +int Applet::heightForWidth( int ) const + { + // *shrug* running this applet in vertical mode is a bad idea anyway + return 50; + } + +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( qt_xdisplay())); + char nm2[] = "_KDE_TOPMENU_MINSIZE"; + char* names[ 2 ] = { nm, nm2 }; + Atom atoms[ 2 ]; + XInternAtoms( qt_xdisplay(), names, 2, False, atoms ); + selection_atom = atoms[ 0 ]; + msg_type_atom = atoms[ 1 ]; + } + +Atom Applet::makeSelectionAtom() + { + if( selection_atom == None ) + initAtoms(); + return selection_atom; + } + +MenuEmbed::MenuEmbed( WId mainwindow_P, bool desktop_P, + QWidget* parent_P, const char* name_P ) + : QXEmbed( parent_P, name_P ), + main_window( mainwindow_P ), + desktop( desktop_P ) + { + setAutoDelete( false ); + } + +void MenuEmbed::windowChanged( WId w_P ) + { + if( w_P == None ) + static_cast< Applet* >( parent())->menuLost( this ); + } + +bool MenuEmbed::x11Event( XEvent* ev_P ) + { + if( ev_P->type == ConfigureRequest + && ev_P->xconfigurerequest.window == embeddedWinId() + && ev_P->xconfigurerequest.value_mask & ( CWWidth | CWHeight )) + { + XConfigureRequestEvent& ev = ev_P->xconfigurerequest; + QSize new_size = size(); + if( ev.value_mask & CWWidth ) + new_size.setWidth( ev.width ); + if( ev.value_mask & CWHeight ) + new_size.setHeight( ev.height ); + // resize when the embedded window resizes (still obey min size) +// kdDebug() << "RES:" << embeddedWinId() << ":" << ev.width << ":" << ev.height << endl; + if( ev.width != width() || ev.height != height()) + { + resize( ev.width, ev.height ); + static_cast< Applet* >( parent())->updateMenuGeometry( this ); + } + sendSyntheticConfigureNotifyEvent(); +// int x, y; +// unsigned int w, h, d, b; +// Window root; +// XGetGeometry( qt_xdisplay(), embeddedWinId(), &root, &x, &y, &w, &h, &b, &d ); +// kdDebug() << "RES3:" << width() << ":" << height() << ":" << w << ":" << h << endl; + return true; + } + return QXEmbed::x11Event( ev_P ); + } + +void MenuEmbed::sendSyntheticConfigureNotifyEvent() +{ + QPoint globalPos = mapToGlobal(QPoint(0,0)); + if (embeddedWinId()) { + XConfigureEvent c; + memset(&c, 0, sizeof(c)); + c.type = ConfigureNotify; + c.display = qt_xdisplay(); + c.send_event = True; + c.event = embeddedWinId(); + c.window = winId(); + c.x = globalPos.x(); + c.y = globalPos.y(); + c.width = width(); + c.height = height(); + c.border_width = 0; + c.above = None; + c.override_redirect = 0; + XSendEvent(qt_xdisplay(), c.event, true, StructureNotifyMask, (XEvent*)&c); + } +} + +void MenuEmbed::setMinimumSize( int w, int h ) +{ + QXEmbed::setMinimumSize( w, h ); + // tell the menubar also the allowed minimum size + // the applet won't allow resizing to smaller size + if( embeddedWinId() != None ) + { +// kdDebug() << "RES2:" << width() << ":" << height() << ":" << minimumWidth() << ":" << minimumHeight() << endl; + XEvent ev; + ev.xclient.display = qt_xdisplay(); + ev.xclient.type = ClientMessage; + ev.xclient.window = embeddedWinId(); + assert( msg_type_atom != None ); + ev.xclient.message_type = msg_type_atom; + ev.xclient.format = 32; + ev.xclient.data.l[0] = qt_x_time; + ev.xclient.data.l[1] = minimumWidth(); + ev.xclient.data.l[2] = minimumHeight(); + ev.xclient.data.l[3] = 0; + ev.xclient.data.l[4] = 0; + XSendEvent( qt_xdisplay(), embeddedWinId(), False, NoEventMask, &ev ); + } +} + +void MenuEmbed::setBackground() +{ + const QPixmap *pbg = parentWidget()->backgroundPixmap(); + + if (pbg) + { + QPixmap bg(width(), height()); + bg.fill(parentWidget(), pos()); + setPaletteBackgroundPixmap(bg); + setBackgroundOrigin(WidgetOrigin); + } + else + unsetPalette(); + + hide(); + show(); + //XClearArea(x11Display(), embeddedWinId(), 0, 0, 0, 0, True); +} + +} // namespace + +#include "menuapplet.moc" diff --git a/kicker/applets/menu/menuapplet.desktop b/kicker/applets/menu/menuapplet.desktop new file mode 100644 index 000000000..741c2ae29 --- /dev/null +++ b/kicker/applets/menu/menuapplet.desktop @@ -0,0 +1,128 @@ +[Desktop Entry] +Hidden=true +Type=Plugin +Name=Menu +Name[af]=Kieslys +Name[ar]=قائمة +Name[be]=Меню +Name[bg]=Меню +Name[bn]=মেনু +Name[br]=Meuziad +Name[bs]=Meni +Name[ca]=Menú +Name[cs]=Nabídka +Name[cy]=Dewislen +Name[de]=Menü +Name[el]=Μενού +Name[eo]=Menuo +Name[es]=Menú +Name[et]=Menüü +Name[eu]=Menua +Name[fa]=گزینگان +Name[fi]=Valikko +Name[ga]=Roghchlár +Name[he]=תפריט +Name[hi]=मेन्यू +Name[hr]=Izbornik +Name[hu]=Menü +Name[is]=Valmynd +Name[ja]=メニュー +Name[ka]=მენიუ +Name[kk]=Мәзір +Name[km]=ម៉ឺនុយ +Name[lt]=Meniu +Name[lv]=Izvēlne +Name[mk]=Мени +Name[mn]=Цэс +Name[nb]=Meny +Name[nds]=Menü +Name[ne]=मेनु +Name[nn]=Meny +Name[pa]=ਮੇਨੂ +Name[ro]=Meniu +Name[ru]=Меню +Name[rw]=Ibikubiyemo +Name[sl]=Meni +Name[sr]=Мени +Name[sr@Latn]=Meni +Name[sv]=Meny +Name[ta]=பட்டி +Name[te]=పట్టి +Name[tg]=Меню +Name[th]=เมนู +Name[tr]=Menü +Name[tt]=Saylaq +Name[uk]=Меню +Name[uz]=Menyu +Name[uz@cyrillic]=Меню +Name[vi]=Thực đơn +Name[wa]=Dressêye +Name[zh_CN]=菜单 +Name[zh_TW]=選單 +Comment=Applet embedding standalone menubars +Comment[ar]=بريمج يضمّن أشرطة قوائم منفردة بذاتها +Comment[be]=Аплет з убудаваным меню +Comment[bg]=Системен панел за вграждане на самостоятелни менюта +Comment[bn]=আলাদা মেনুবার ধারণ করার উপযোগী অ্যাপলেট +Comment[bs]=Applet koji uvezuje samostalne menije +Comment[ca]=Un applet encastat estàndard per a les barres de menú +Comment[cs]=Applet pohlcující samostatné lišty s nabídkami +Comment[csb]=Aplet zbiérający ùwòlnioné lëstwë menu +Comment[cy]=Rhaglennig sy'n mewn-adeiladu bariau dewislen unigol +Comment[da]=Applet der indlejrer alenestående menulinjer +Comment[de]=Programm zur Einbettung einzelner Menüleisten +Comment[el]=Μικροεφαρμογή που ενσωματώνει αυτόνομες γραμμές μενού +Comment[eo]=Aplikaĵeniganta solfunkcia menuzono +Comment[es]=Una miniaplicación que incluye barras de menú autónomas +Comment[et]=Aplett, mis põimib endasse isseisvaid menüüribasid +Comment[eu]=Menu-barrak txertaturik dituen appleta +Comment[fa]=میله گزینگان خوداتکای نهفتۀ برنامک +Comment[fi]=Sovelma, joka pystyy upottamaan yksittäisiä valikkorivejä +Comment[fr]=Une applet intégrant les barres de menu externes +Comment[fy]=Een applet die lossteande menubalken ynslút +Comment[gl]=Barras de menu estándar con incrustamento de applets +Comment[he]=שורת תפריטים משובצת יישומונים העומדת בפני עצמה +Comment[hi]=ऐपलेट एम्बेडिंग स्टैंडअलोन मेन्यूबार्स +Comment[hr]=Samostalne trake izbornika s ugrađenim apletima +Comment[hu]=Kisalkalmazásokat tartalmazni képes önálló menüsorok +Comment[is]=Smáforrit sem byggir inn sjálfstæðar valmyndastikur +Comment[it]=Applet per inglobare le barre dei menu +Comment[ja]=単独のメニューバーに組み込むアプレット +Comment[ka]=აპლეტი, რომელიც ამატებს ავტონომიურ პანელებს +Comment[kk]=Бөлек мәзір панельдерді құру апплеті +Comment[km]=របារម៉ឺនុយនៅតែឯងដែលបង្កប់ក្នុងអាប់ភ្លេត +Comment[lt]=Įskiepis, rodantis atskiras meniu dalis +Comment[lv]=Sīklietotne, kas iegulda pastāvīgas izvēlnes +Comment[mk]=Аплет кој ги вгнездува самостојните менија +Comment[ms]=Menu bar tersendiri pembenaman aplet +Comment[mt]=Applet li fiha menubars indipendenti +Comment[nb]=Et panelprogram som bygger inn frittstående menylinjer +Comment[nds]=Lüttprogramm för't Inbetten vun enkelte Warktüüchbalkens +Comment[ne]=एप्लेट सम्मिलित गर्ने स्ट्यान्डअलोन मेनुपट्टी +Comment[nl]=Een applet die losstaande menubalken insluit +Comment[nn]=Eit panelprogram som kan innehalda frittståande menylinjer +Comment[pa]=ਇੱਕਲੀ ਮੇਨੂਪੱਟੀ ਐਪਲਿਟ +Comment[pl]=Aplet zbierający uwolnione paski menu +Comment[pt]=Uma 'applet' que incorpora barras de menu autónomas +Comment[pt_BR]=Mini-aplicativo para embutir barras de menu ao painel +Comment[ro]=O miniaplicație ce înglobează bare de meniu +Comment[ru]=Аплет, встраивающий автономные панели меню +Comment[rw]=Apuleti zifitemo umwanya-ibikubiyemo wigenga +Comment[se]=Prográmmaš mii vuojuha oktanas fálloholggaid +Comment[sk]=Applet pre samostatné pruhy menu +Comment[sl]=Vstavek, ki vključuje samostojne menijske vrstice +Comment[sr]=Аплет за уграђивање самосталних менија +Comment[sr@Latn]=Aplet za ugrađivanje samostalnih menija +Comment[sv]=Miniprogram för inbäddning av fristående menyer +Comment[ta]=குறுநிரல் பொதிந்த தனியான மெனுபட்டிகள் +Comment[th]=แอพเพล็ตสำหรับฝังแถบเมนูลงพาเนล +Comment[tr]=Yalnız menü çubuklarını gömen uygulamacık +Comment[tt]=Ayırım torğan saylaq-tirälär berläşterüçe applet +Comment[uk]=Аплет вбудовних окремих смужок меню +Comment[vi]=Tiểu ứng dụng nhúng các thanh thực đơn đứng riêng +Comment[wa]=Aplikete po fé ravaler des bårs di dressêye totes seules +Comment[zh_CN]=嵌入独立菜单栏的小程序 +Comment[zh_TW]=單獨置於面板中的選單列 + +X-KDE-Library=menu_panelapplet +X-KDE-UniqueApplet=true diff --git a/kicker/applets/menu/menuapplet.h b/kicker/applets/menu/menuapplet.h new file mode 100644 index 000000000..8374e897b --- /dev/null +++ b/kicker/applets/menu/menuapplet.h @@ -0,0 +1,258 @@ +/***************************************************************** + +Copyright (c) 2002 Siegfried Nijssen <snijssen@liacs.nl> +Copyright (c) 2003 Lubos Lunak <l.lunak@suse.cz> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _MENUAPPLET_H_ +#define _MENUAPPLET_H_ + +#include <assert.h> + +#include <qvaluelist.h> +#include <qevent.h> +#include <qxembed.h> + +#include <kpanelapplet.h> +#include <kmanagerselection.h> + +#include <dcopobject.h> +#include <dcopclient.h> + +#include <karrowbutton.h> + +class KWinModule; + +namespace KickerMenuApplet +{ + +class MenuEmbed; + +/** + * @short A central menu bar + * + * @description All status change, such as when an window is activated, + * a new window popped up, etc, is received via @ref KWin::WindowInfo and @ref + * NETWinInfo. Status changes for X selections are done via KSelectionWatcher. + * + * How it works in broad terms: KickerMenuApplet gets notified as soon a window + * changes(a new pops up etc.) and accordingly updates the list @ref menus, + * which contains all known menus. When a new window gains focus, it looks up the + * correct MenuEmbed in @ref menus, and then switches to that one. + * + * The documentation is a bit rusty -- read it with a critical eye. + * + * @author Siegfried Nijssen <snijssen@liacs.nl> + * @author Lubos Lunak <l.lunak@suse.cz> + */ + +class Applet : public KPanelApplet, public DCOPObject +{ + Q_OBJECT + K_DCOP + +k_dcop: + + /** + * Called by the Kicker configuration(KCM). Does in turn call + * readSettings(). + */ + ASYNC configure(); + +public: + Applet( const QString& configFile, QWidget *parent ); + virtual ~Applet(); + virtual int widthForHeight( int height ) const; + virtual int heightForWidth( int width ) const; + + /** + * Looks up @param embed in @ref menus, and removes it. + */ + void menuLost( MenuEmbed* embed ); + void updateMenuGeometry( MenuEmbed* embed ); + void setBackground(); + +protected: + + virtual void paletteChange(const QPalette& ); + virtual void positionChange( Position p ); + virtual void moveEvent(QMoveEvent *); + +private slots: + + /** + * Called each time a window is added. When the selection is + * initially claimed, it is called for every window. It does the big + * work, and does the embedding with MenuEmbed. + */ + void windowAdded( WId w ); + + /** + * Finds @p w's menubar in @see menus, and then activates it. + * + * @param w the activated window. + */ + void activeWindowChanged( WId w ); + + /** + * Called when the selection(selection_atom) is lost. Deletes the + * embedded menus, and starts listening for the selection again. + * + */ + void lostSelection(); + + /** + * Reads whether a central menu bar should be used or not, basically. + */ + void readSettings(); + void claimSelection(); + +private: + + /** + * Returns true if the selection is Not owned. That is, the menu applet + * isn't "running" and is listening for the selection to be released. + */ + bool isDisabled() const; + + WId tryTransientFor( WId w ); + + /** + * Does some sanity checks, and then sets active_menu to @param embed. + */ + void activateMenu( MenuEmbed* embed ); + + /** + * Creates msg_type_atom and selection_atom, and returns the latter. + */ + static Atom makeSelectionAtom(); + void updateTopEdgeOffset(); + KWinModule* module; + + /** + * List of all known menus. + */ + QValueList< MenuEmbed* > menus; + + /** + * A pointer to the current active menu, which is member + * of @ref menus. + */ + MenuEmbed* active_menu; + + KSelectionOwner* selection; + + /** + * Only the messenger. Dispatches signals to claimSelection(). + */ + KSelectionWatcher* selection_watcher; + + /** + * Whether the Desktop menu should be used, when a window + * with no menu is used. + */ + bool desktop_menu; + DCOPClient dcopclient; + + /** + * The distance to the top of the screen. + */ + int topEdgeOffset; +}; + +/** + * + * @author Siegfried Nijssen <snijssen@liacs.nl> + * @author Lubos Lunak <l.lunak@suse.cz> + */ +class MenuEmbed + : public QXEmbed +{ + Q_OBJECT + +public: + + /** + * Default constructor + * + * @param mainwindow window ID for the window to be plugged + * @param desktop true if @p mainwindow is the desktop + */ + MenuEmbed( WId mainwindow, bool desktop, + QWidget* parent = NULL, const char* name = NULL ); + + void setBackground(); + + /** + * @returns the window ID for the handled window. + */ + WId mainWindow() const; + + /** + */ + bool isDesktopMenu() const; + virtual void setMinimumSize( int w, int h ); + void setMinimumSize( const QSize& s ) { setMinimumSize( s.width(), s.height()); } + +protected: + + /** + * When @p w is None, that is the embedded window was lost, it calls + * menuLost() such that the this is deleted from @ref menus list. + */ + virtual void windowChanged( WId w ); + + virtual bool x11Event( XEvent* ev ); + +private: + + void sendSyntheticConfigureNotifyEvent(); + WId main_window; + + /** + * If the window is the desktop window. + */ + bool desktop; +}; + +inline +bool Applet::isDisabled() const +{ + assert( ( selection == NULL && selection_watcher != NULL ) + || ( selection != NULL && selection_watcher == NULL )); + return selection == NULL; +} + +inline +WId MenuEmbed::mainWindow() const +{ + return main_window; +} + +inline +bool MenuEmbed::isDesktopMenu() const +{ + return desktop; +} + +} // namespace + +#endif |