summaryrefslogtreecommitdiffstats
path: root/kicker/kicker/core/menumanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kicker/kicker/core/menumanager.cpp')
-rw-r--r--kicker/kicker/core/menumanager.cpp272
1 files changed, 272 insertions, 0 deletions
diff --git a/kicker/kicker/core/menumanager.cpp b/kicker/kicker/core/menumanager.cpp
new file mode 100644
index 000000000..ba07b39c7
--- /dev/null
+++ b/kicker/kicker/core/menumanager.cpp
@@ -0,0 +1,272 @@
+/*****************************************************************
+
+Copyright (c) 1996-2000 the kicker authors. See file AUTHORS.
+
+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.
+
+******************************************************************/
+
+#include <qcursor.h>
+#include <qpixmap.h>
+#include <qtimer.h>
+
+#include <kapplication.h>
+#include <dcopclient.h>
+
+#include "client_mnu.h"
+#include "container_extension.h"
+#include "global.h"
+#include "k_mnu.h"
+#include "kicker.h"
+#include "panelbutton.h"
+
+#include "menumanager.h"
+#include "menumanager.moc"
+
+// Why MenuManager doesn't use KStaticDeleter
+// MenuManager gets created before the ExtensionManager
+// So using KStaticDeleter results in MenuManager getting
+// deleted before ExtensionManager, which means also the panels
+// which means also the K Menu buttons. K Menu buttons call
+// MenuManager in their dtor, so if MenuManager is already gone
+// then every KButton will cause it to be reconstructed.
+// So we rely on Kicker to delete MenuManager on the way out
+// ensuring it's the last thing to go.
+MenuManager* MenuManager::m_self = 0;
+
+MenuManager* MenuManager::the()
+{
+ if (!m_self)
+ {
+ m_self = new MenuManager();
+ }
+
+ return m_self;
+}
+
+MenuManager::MenuManager(QObject *parent)
+ : QObject(parent, "MenuManager"), DCOPObject("MenuManager")
+{
+ m_kmenu = new PanelKMenu;
+ kapp->dcopClient()->setNotifications(true);
+ connect(kapp->dcopClient(), SIGNAL(applicationRemoved(const QCString&)),
+ this, SLOT(applicationRemoved(const QCString&)));
+}
+
+MenuManager::~MenuManager()
+{
+ if (this == m_self)
+ {
+ m_self = 0;
+ }
+
+ delete m_kmenu;
+}
+
+void MenuManager::slotSetKMenuItemActive()
+{
+ m_kmenu->selectFirstItem();
+}
+
+void MenuManager::showKMenu()
+{
+ m_kmenu->showMenu();
+}
+
+void MenuManager::popupKMenu(const QPoint &p)
+{
+// kdDebug(1210) << "popupKMenu()" << endl;
+ if (m_kmenu->isVisible())
+ {
+ m_kmenu->hide();
+ }
+ else if (p.isNull())
+ {
+ m_kmenu->popup(QCursor::pos());
+ }
+ else
+ {
+ m_kmenu->popup( p );
+ }
+}
+
+void MenuManager::registerKButton(PanelPopupButton *button)
+{
+ if (!button)
+ {
+ return;
+ }
+
+ m_kbuttons.append(button);
+}
+
+void MenuManager::unregisterKButton(PanelPopupButton *button)
+{
+ m_kbuttons.remove(button);
+}
+
+PanelPopupButton* MenuManager::findKButtonFor(QPopupMenu* menu)
+{
+ KButtonList::const_iterator itEnd = m_kbuttons.constEnd();
+ for (KButtonList::const_iterator it = m_kbuttons.constBegin(); it != itEnd; ++it)
+ {
+ if ((*it)->popup() == menu)
+ {
+ return *it;
+ }
+ }
+
+ return 0;
+}
+
+void MenuManager::kmenuAccelActivated()
+{
+ if (m_kmenu->isVisible())
+ {
+ m_kmenu->hide();
+ return;
+ }
+
+ m_kmenu->initialize();
+
+ if (m_kbuttons.isEmpty())
+ {
+ // no button to use, make it behave like a desktop menu
+ QPoint p;
+ // Popup the K-menu at the center of the screen.
+ QDesktopWidget* desktop = KApplication::desktop();
+ QRect r = desktop->screenGeometry(desktop->screenNumber(QCursor::pos()));
+ // kMenu->rect() is not valid before showing, use sizeHint()
+ p = r.center() - QRect( QPoint( 0, 0 ), m_kmenu->sizeHint()).center();
+ m_kmenu->popup(p);
+
+ // when the cursor is in the area where the menu pops up,
+ // the item under the cursor gets selected. The single shot
+ // avoids this from happening by allowing the item to be selected
+ // when the event loop is enterred, and then resetting it.
+ QTimer::singleShot(0, this, SLOT(slotSetKMenuItemActive()));
+ }
+ else
+ {
+ // We need the kmenu's size to place it at the right position.
+ // We cannot rely on the popup menu's current size(), if it wasn't
+ // shown before, so we resize it here according to its sizeHint().
+ const QSize size = m_kmenu->sizeHint();
+ m_kmenu->resize(size.width(),size.height());
+
+ PanelPopupButton* button = findKButtonFor(m_kmenu);
+
+ // let's unhide the panel while we're at it. traverse the widget
+ // hierarchy until we find the panel, if any
+ QObject* menuParent = button->parent();
+ while (menuParent)
+ {
+ ExtensionContainer* ext = dynamic_cast<ExtensionContainer*>(menuParent);
+
+ if (ext)
+ {
+ ext->unhideIfHidden();
+ // make sure it's unhidden before we use it to figure out
+ // where to popup
+ qApp->processEvents();
+ break;
+ }
+
+ menuParent = menuParent->parent();
+ }
+
+ button->showMenu();
+ }
+}
+
+QCString MenuManager::createMenu(QPixmap icon, QString text)
+{
+ static int menucount = 0;
+ menucount++;
+ QCString name;
+ name.sprintf("kickerclientmenu-%d", menucount );
+ KickerClientMenu* p = new KickerClientMenu( 0, name );
+ clientmenus.append(p);
+ m_kmenu->initialize();
+ p->text = text;
+ p->icon = icon;
+ p->idInParentMenu = m_kmenu->insertClientMenu( p );
+ p->createdBy = kapp->dcopClient()->senderId();
+ m_kmenu->adjustSize();
+ return name;
+}
+
+void MenuManager::removeMenu(QCString menu)
+{
+ bool iterate = true;
+ ClientMenuList::iterator it = clientmenus.begin();
+ for (; it != clientmenus.end(); iterate ? ++it : it)
+ {
+ iterate = true;
+ KickerClientMenu* m = *it;
+ if (m->objId() == menu)
+ {
+ m_kmenu->removeClientMenu(m->idInParentMenu);
+ it = clientmenus.erase(it);
+ iterate = false;
+ }
+ }
+ m_kmenu->adjustSize();
+}
+
+
+void MenuManager::applicationRemoved(const QCString& appRemoved)
+{
+ bool iterate = true;
+ ClientMenuList::iterator it = clientmenus.begin();
+ for (; it != clientmenus.end(); iterate ? ++it : it)
+ {
+ iterate = true;
+ KickerClientMenu* m = *it;
+ if (m->createdBy == appRemoved)
+ {
+ m_kmenu->removeClientMenu(m->idInParentMenu);
+ it = clientmenus.erase(it);
+ iterate = false;
+ }
+ }
+ m_kmenu->adjustSize();
+}
+
+bool MenuManager::process(const QCString &fun, const QByteArray &data,
+ QCString &replyType, QByteArray &replyData)
+{
+ if ( fun == "createMenu(QPixmap,QString)" ) {
+ QDataStream dataStream( data, IO_ReadOnly );
+ QPixmap icon;
+ QString text;
+ dataStream >> icon >> text;
+ QDataStream reply( replyData, IO_WriteOnly );
+ reply << createMenu( icon, text );
+ replyType = "QCString";
+ return true;
+ } else if ( fun == "removeMenu(QCString)" ) {
+ QDataStream dataStream( data, IO_ReadOnly );
+ QCString menu;
+ dataStream >> menu;
+ removeMenu( menu );
+ replyType = "void";
+ return true;
+ }
+ return false;
+}