diff options
author | Alberto Ruiz <alberto.ruiz@codethink.co.uk> | 2011-03-31 19:49:02 +0200 |
---|---|---|
committer | Bjoern Michaelsen <bjoern.michaelsen@canonical.com> | 2011-03-31 21:05:22 +0200 |
commit | ec176090c881c6d6b85606c6711ed621c5af7531 (patch) | |
tree | e1f158b151746f207c59c2939e898b1c625af407 | |
parent | 9d306a777bbd79169bd61108ab89a097223ce9b8 (diff) |
initial import of lomenubar
* from http://bazaar.launchpad.net/~lo-menubar-team/lo-menubar/trunk/changes
* fixed indent to keep git hooks happy, otherwise a vanilla copy
-rw-r--r-- | framework/source/lomenubar/AwtKeyToDbusmenuString.cxx | 145 | ||||
-rw-r--r-- | framework/source/lomenubar/AwtKeyToDbusmenuString.h | 33 | ||||
-rw-r--r-- | framework/source/lomenubar/DesktopJob.cxx | 157 | ||||
-rw-r--r-- | framework/source/lomenubar/DesktopJob.h | 90 | ||||
-rw-r--r-- | framework/source/lomenubar/FrameHelper.cxx | 826 | ||||
-rw-r--r-- | framework/source/lomenubar/FrameHelper.h | 139 | ||||
-rw-r--r-- | framework/source/lomenubar/FrameJob.cxx | 393 | ||||
-rw-r--r-- | framework/source/lomenubar/FrameJob.h | 101 | ||||
-rw-r--r-- | framework/source/lomenubar/MenuItemInfo.cxx | 103 | ||||
-rw-r--r-- | framework/source/lomenubar/MenuItemInfo.h | 54 | ||||
-rw-r--r-- | framework/source/lomenubar/MenuItemStatusListener.cxx | 82 | ||||
-rw-r--r-- | framework/source/lomenubar/MenuItemStatusListener.h | 35 | ||||
-rw-r--r-- | framework/source/lomenubar/exports.cxx | 119 |
13 files changed, 2277 insertions, 0 deletions
diff --git a/framework/source/lomenubar/AwtKeyToDbusmenuString.cxx b/framework/source/lomenubar/AwtKeyToDbusmenuString.cxx new file mode 100644 index 0000000000..4fd377db75 --- /dev/null +++ b/framework/source/lomenubar/AwtKeyToDbusmenuString.cxx @@ -0,0 +1,145 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * A LibreOffice extension to send the menubar structure through DBusMenu + * + * Copyright 2011 Canonical, Ltd. + * Authors: + * Alberto Ruiz <alberto.ruiz@codethink.co.uk> + * + * This program is free software: you can redistribute it and/or modify it under + * the the GNU Lesser General Public License version 3, as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable + * version of the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#define XK_MISCELLANY +#define XK_LATIN1 +#define XK_PUBLISHING + +#include <X11/Xlib.h> +#include <X11/keysymdef.h> + +#include <glib.h> + +#include <com/sun/star/awt/Key.hpp> + +using namespace ::com::sun::star; + +KeySym MapAwtToXKey (guint16 aKeyCode); + +gchar* +AwtKeyToDbusmenuString (guint16 aKeyCode) +{ + KeySym code = (KeySym)0; + + if (!aKeyCode) + return NULL; + + //We try the consecutive ranges first, if the code is not there + //we use MapAwtToXKey(), se below + if (aKeyCode >= awt::Key::A && aKeyCode <= awt::Key::Z) + code = (KeySym)aKeyCode - (KeySym)awt::Key::A + XK_A; + else if (aKeyCode >= awt::Key::F1 && aKeyCode <= awt::Key::F26) + code = (KeySym)aKeyCode - (KeySym)awt::Key::F1 + XK_F1; + else if (aKeyCode >= awt::Key::NUM0 && aKeyCode <= awt::Key::NUM9) + code = (KeySym)aKeyCode - (KeySym)awt::Key::NUM0 + XK_0; + else + code = MapAwtToXKey (aKeyCode); + + if (code == 0) + return NULL; + + return XKeysymToString (code);; +} + + +//This is a 1-1 mapper between com::sun::star::awt:Key values and X11 KeySyms +//note that some symbols are missing +KeySym +MapAwtToXKey (guint16 aKeyCode) +{ + switch (aKeyCode) + { + case awt::Key::UP: + return XK_Up; + case awt::Key::DOWN: + return XK_Down; + case awt::Key::LEFT: + return XK_Left; + case awt::Key::RIGHT: + return XK_Right; + case awt::Key::HOME: + return XK_Home; + case awt::Key::END: + return XK_End; + case awt::Key::PAGEUP: + return XK_Page_Up; + case awt::Key::PAGEDOWN: + return XK_Page_Down; + case awt::Key::RETURN: + return XK_Return; + case awt::Key::ESCAPE: + return XK_Escape; + case awt::Key::TAB: + return XK_Tab; + case awt::Key::BACKSPACE: + return XK_BackSpace; + case awt::Key::SPACE: + return XK_space; + case awt::Key::INSERT: + return XK_Insert; + case awt::Key::DELETE: + return XK_Delete; + case awt::Key::ADD: + return XK_plus; + case awt::Key::SUBTRACT: + return XK_minus; + case awt::Key::MULTIPLY: + return XK_asterisk; + case awt::Key::DIVIDE: + return XK_slash; + case awt::Key::POINT: + return XK_period; + case awt::Key::COMMA: + return XK_comma; + case awt::Key::LESS: + return XK_less; + case awt::Key::GREATER: + return XK_greater; + case awt::Key::EQUAL: + return XK_equal; + case awt::Key::UNDO: + return XK_Undo; + case awt::Key::REPEAT: + return XK_Redo; + case awt::Key::FIND: + return XK_Find; + case awt::Key::DECIMAL: + return XK_decimalpoint; + case awt::Key::TILDE: + return XK_asciitilde; + case awt::Key::QUOTELEFT: + return XK_leftsinglequotemark; + //Sun keys and other unsupported symbols + case awt::Key::OPEN: + case awt::Key::CUT: + case awt::Key::COPY: + case awt::Key::PASTE: + case awt::Key::PROPERTIES: + case awt::Key::FRONT: + case awt::Key::CONTEXTMENU: + case awt::Key::HELP: + case awt::Key::MENU: + default: + return 0; + } +} diff --git a/framework/source/lomenubar/AwtKeyToDbusmenuString.h b/framework/source/lomenubar/AwtKeyToDbusmenuString.h new file mode 100644 index 0000000000..acedc908ac --- /dev/null +++ b/framework/source/lomenubar/AwtKeyToDbusmenuString.h @@ -0,0 +1,33 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * A LibreOffice extension to send the menubar structure through DBusMenu + * + * Copyright 2011 Canonical, Ltd. + * Authors: + * Alberto Ruiz <alberto.ruiz@codethink.co.uk> + * + * This program is free software: you can redistribute it and/or modify it under + * the the GNU Lesser General Public License version 3, as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable + * version of the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef __AWT_KEY_TO_DBUSMENU_STRING_H__ +#define __AWT_KEY_TO_DBUSMENU_STRING_H__ +#include <X11/X.h> +#include <glib.h> + +gchar* +AwtKeyToDbusmenuString (guint16 aKeyCode); + + +#endif //__AWT_KEY_TO_DBUSMENU_STRING_H__ diff --git a/framework/source/lomenubar/DesktopJob.cxx b/framework/source/lomenubar/DesktopJob.cxx new file mode 100644 index 0000000000..1ac56c2f5a --- /dev/null +++ b/framework/source/lomenubar/DesktopJob.cxx @@ -0,0 +1,157 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * A LibreOffice extension to send the menubar structure through DBusMenu + * + * Copyright 2011 Canonical, Ltd. + * Authors: + * Alberto Ruiz <alberto.ruiz@codethink.co.uk> + * + * This program is free software: you can redistribute it and/or modify it under + * the the GNU Lesser General Public License version 3, as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable + * version of the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#include "DesktopJob.h" +#include "FrameJob.h" + +#include <gio/gio.h> +#include <libdbusmenu-glib/server.h> + +#include <rtl/process.h> +#include <osl/diagnose.h> +#include <cppuhelper/implbase1.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/XEventBroadcaster.hpp> +#include <com/sun/star/document/XEventListener.hpp> +#include <com/sun/star/document/EventObject.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/frame/XFramesSupplier.hpp> +#include <com/sun/star/frame/XFrameActionListener.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XLayoutManager.hpp> + +using rtl::OUString; +using com::sun::star::beans::XPropertySet; +using com::sun::star::beans::NamedValue; +using com::sun::star::document::XEventListener; +using com::sun::star::document::XEventBroadcaster; +using com::sun::star::frame::XFrame; +using com::sun::star::frame::XFramesSupplier; +using com::sun::star::frame::XFrameActionListener; +using com::sun::star::frame::XModel; +using com::sun::star::frame::XLayoutManager; +using com::sun::star::frame::FrameActionEvent; +using com::sun::star::frame::XFrameActionListener; +using com::sun::star::lang::IllegalArgumentException; +using com::sun::star::lang::XMultiServiceFactory; +using com::sun::star::lang::EventObject; +using com::sun::star::uno::Any; +using com::sun::star::uno::Exception; +using com::sun::star::uno::Reference; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::uno::XInterface; + +//-------------------------- D-Bus Callbacks ---------------------------------- +static void +on_bus (GDBusConnection * connection, + const gchar * name, + gpointer user_data) +{ + //TODO: Should we actually do something here? + return; +} + +static void +name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data) +{ + g_error ("Unable to get name '%s' on DBus", name); + return; +} + +// --------------------------- DesktopJob ---------------------------------- +Any SAL_CALL DesktopJob::execute( const Sequence< NamedValue >& aArguments ) + throw ( IllegalArgumentException, Exception, RuntimeException ) +{ + g_type_init (); + + g_bus_own_name(G_BUS_TYPE_SESSION, + LIBREOFFICE_BUSNAME, + G_BUS_NAME_OWNER_FLAGS_NONE, + on_bus, + NULL, + name_lost, + NULL, + NULL); + + return Any (); +} + +OUString +DesktopJob_getImplementationName () + throw (RuntimeException) +{ + return OUString ( RTL_CONSTASCII_USTRINGPARAM ( DESKTOPJOB_IMPLEMENTATION_NAME ) ); +} + +sal_Bool SAL_CALL +DesktopJob_supportsService( const OUString& ServiceName ) + throw (RuntimeException) +{ + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( DESKTOPJOB_SERVICE_NAME ) ); +} + +Sequence< OUString > SAL_CALL +DesktopJob_getSupportedServiceNames( ) + throw (RuntimeException) +{ + Sequence < OUString > aRet(1); + OUString* pArray = aRet.getArray(); + pArray[0] = OUString ( RTL_CONSTASCII_USTRINGPARAM ( DESKTOPJOB_SERVICE_NAME ) ); + return aRet; +} + +Reference< XInterface > SAL_CALL +DesktopJob_createInstance( const Reference< XMultiServiceFactory > & rSMgr) + throw( Exception ) +{ + return (cppu::OWeakObject*) new DesktopJob(rSMgr); +} + +// XServiceInfo +OUString SAL_CALL +DesktopJob::getImplementationName() + throw (RuntimeException) +{ + return DesktopJob_getImplementationName(); +} + +sal_Bool SAL_CALL +DesktopJob::supportsService( const OUString& rServiceName ) + throw (RuntimeException) +{ + return DesktopJob_supportsService( rServiceName ); +} + +Sequence< OUString > SAL_CALL +DesktopJob::getSupportedServiceNames() + throw (RuntimeException) +{ + return DesktopJob_getSupportedServiceNames(); +} diff --git a/framework/source/lomenubar/DesktopJob.h b/framework/source/lomenubar/DesktopJob.h new file mode 100644 index 0000000000..9dd3024a05 --- /dev/null +++ b/framework/source/lomenubar/DesktopJob.h @@ -0,0 +1,90 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * A LibreOffice extension to send the menubar structure through DBusMenu + * + * Copyright 2011 Canonical, Ltd. + * Authors: + * Alberto Ruiz <alberto.ruiz@codethink.co.uk> + * + * This program is free software: you can redistribute it and/or modify it under + * the the GNU Lesser General Public License version 3, as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable + * version of the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef __DESKTOP_JOB_H__ +#define __DESKTOP_JOB_H__ + +#include <glib.h> +#include <libdbusmenu-glib/menuitem.h> + +#include <com/sun/star/task/XJob.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/implbase2.hxx> + +#define LIBREOFFICE_BUSNAME "org.libreoffice.dbusmenu" +#define DESKTOPJOB_IMPLEMENTATION_NAME "org.libreoffice.desktop.AppMenuJob" +#define DESKTOPJOB_SERVICE_NAME "org.libreoffice.desktop.AppMenuJob" + +namespace css = ::com::sun::star; +using css::uno::Reference; +using css::uno::Sequence; +using css::uno::Any; +using css::uno::Exception; +using css::uno::RuntimeException; +using css::lang::IllegalArgumentException; + +class DesktopJob : public cppu::WeakImplHelper2 < css::task::XJob, css::lang::XServiceInfo > +{ + private: + Reference< css::lang::XMultiServiceFactory > mxMSF; + + public: + DesktopJob( const Reference< css::lang::XMultiServiceFactory > &rxMSF) + : mxMSF( rxMSF ) {} + + virtual ~DesktopJob() {} + + // XJob + virtual Any SAL_CALL execute(const css::uno::Sequence< css::beans::NamedValue >& Arguments) + throw (IllegalArgumentException, Exception, RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() + throw (RuntimeException); + + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw (RuntimeException); + + virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() + throw (RuntimeException); +}; + + +::rtl::OUString +DesktopJob_getImplementationName() + throw ( RuntimeException ); + +sal_Bool SAL_CALL +DesktopJob_supportsService( const ::rtl::OUString& ServiceName ) + throw ( RuntimeException ); + +Sequence< ::rtl::OUString > SAL_CALL +DesktopJob_getSupportedServiceNames() + throw ( RuntimeException ); + +Reference< css::uno::XInterface > +SAL_CALL DesktopJob_createInstance( const css::uno::Reference< css::lang::XMultiServiceFactory > & rSMgr) + throw ( Exception ); + +#endif //__DESKTOP_JOB_H__ + diff --git a/framework/source/lomenubar/FrameHelper.cxx b/framework/source/lomenubar/FrameHelper.cxx new file mode 100644 index 0000000000..4c4550e3dd --- /dev/null +++ b/framework/source/lomenubar/FrameHelper.cxx @@ -0,0 +1,826 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * A LibreOffice extension to send the menubar structure through DBusMenu + * + * Copyright 2011 Canonical, Ltd. + * Authors: + * Alberto Ruiz <alberto.ruiz@codethink.co.uk> + * + * This program is free software: you can redistribute it and/or modify it under + * the the GNU Lesser General Public License version 3, as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable + * version of the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#include "FrameHelper.h" +#include "AwtKeyToDbusmenuString.h" +#include "MenuItemInfo.h" +#include "MenuItemStatusListener.h" + +#include <com/sun/star/awt/KeyEvent.hpp> +#include <com/sun/star/awt/SystemDependentXWindow.hpp> +#include <com/sun/star/awt/XSystemDependentWindowPeer.hpp> +#include <com/sun/star/awt/XWindow2.hpp> +#include <com/sun/star/awt/Key.hpp> +#include <com/sun/star/awt/KeyModifier.hpp> +#include <com/sun/star/awt/MenuEvent.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/awt/XPopupMenu.hpp> +#include <com/sun/star/awt/XMenuExtended.hpp> +#include <com/sun/star/awt/XMenuListener.hpp> +#include <com/sun/star/awt/XPopupMenuExtended.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/XDispatchHelper.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XLayoutManager.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XModuleManager.hpp> +#include <com/sun/star/frame/XPopupMenuController.hpp> +#include <com/sun/star/frame/FrameAction.hpp> +#include <com/sun/star/frame/FrameActionEvent.hpp> +#include <com/sun/star/lang/SystemDependent.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/util/URL.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/ui/XUIElement.hpp> +#include <com/sun/star/ui/XUIConfigurationManager.hpp> +#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/XAcceleratorConfiguration.hpp> +#include <com/sun/star/ui/XModuleUIConfigurationManagerSupplier.hpp> +#include <rtl/process.h> + +#include <gio/gio.h> +#include <libdbusmenu-glib/client.h> +#include <libdbusmenu-gtk/menuitem.h> + +using rtl::OUString; +using rtl::OString; +using rtl::OUStringToOString; + +using namespace ::com::sun::star; + +using com::sun::star::awt::KeyEvent; +using com::sun::star::awt::MenuEvent; +using com::sun::star::awt::SystemDependentXWindow; +using com::sun::star::awt::XMenuListener; +using com::sun::star::awt::XMenuExtended; +using com::sun::star::awt::XMenuListener; +using com::sun::star::awt::MenuEvent; +using com::sun::star::awt::XPopupMenu; +using com::sun::star::awt::XPopupMenuExtended; +using com::sun::star::awt::XSystemDependentWindowPeer; +using com::sun::star::awt::XWindow2; +using com::sun::star::beans::XPropertySet; +using com::sun::star::beans::PropertyValue; +using com::sun::star::container::XNameAccess; +using com::sun::star::container::NoSuchElementException; +using com::sun::star::frame::XController; +using com::sun::star::frame::XComponentLoader; +using com::sun::star::frame::XDispatch; +using com::sun::star::frame::XDispatchProvider; +using com::sun::star::frame::XDispatchHelper; +using com::sun::star::frame::XModel; +using com::sun::star::frame::XModuleManager; +using com::sun::star::frame::XLayoutManager; +using com::sun::star::frame::XPopupMenuController; +using com::sun::star::lang::SystemDependent::SYSTEM_XWINDOW; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::XInterface; +using com::sun::star::ui::XUIElement; +using com::sun::star::ui::XUIConfigurationManager; +using com::sun::star::ui::XUIConfigurationManagerSupplier; +using com::sun::star::ui::XAcceleratorConfiguration; +using com::sun::star::ui::XModuleUIConfigurationManagerSupplier; +using com::sun::star::util::URL; +using com::sun::star::util::XURLTransformer; + +// ------------------------ Item callbacks --------------------------- +// Item activated. It distpatches the command associated to a given menu item. +void +item_activated (DbusmenuMenuitem *item, guint timestamp, gpointer user_data) +{ + FrameHelper *helper = (FrameHelper*)user_data; + OUString command = OUString::createFromAscii(dbusmenu_menuitem_property_get (item, "CommandURL")); + helper->dispatchCommand (command); +} + +// Rebuilds the submenu +gboolean +item_about_to_show (DbusmenuMenuitem *item, gpointer user_data) +{ + //Get the XMenu interface for the MenuBar UIElement + FrameHelper *helper = (FrameHelper*)user_data; + Reference < XFrame > xFrame = helper->getFrame (); + Reference< XPropertySet > frameProps (xFrame, UNO_QUERY); + Reference < XLayoutManager > xLayoutManager(frameProps->getPropertyValue(OUString::createFromAscii("LayoutManager")), + UNO_QUERY); + Reference < XUIElement > menuBar(xLayoutManager->getElement (OUString::createFromAscii("private:resource/menubar/menubar")), + UNO_QUERY); + Reference < XPropertySet > menuPropSet (menuBar, UNO_QUERY); + + if (!menuPropSet.is ()) + { + return FALSE; + } + + Reference < XMenu > xMenu(menuPropSet->getPropertyValue(OUString::createFromAscii("XMenuBar")), + UNO_QUERY); + if (!xMenu.is()) + { + return FALSE; + } + + //Find xMenu for the first level item + Reference < XMenu > xSubMenu; + Reference < XMenuExtended > xMenuEx (xMenu, UNO_QUERY); + guint16 root_count = xMenu->getItemCount(); + for (guint16 i = 0; i<root_count ;i++) + { + + guint16 id = xMenu->getItemId (i); + if (id == 0) + continue; + + OUString command = xMenuEx->getCommand (id); + + //We must find the element with the same command URL + if (! OUString::createFromAscii (dbusmenu_menuitem_property_get (item, "CommandURL")).equals (command)) + continue; + + Reference <XPopupMenu> subPopup (xMenu->getPopupMenu (id), UNO_QUERY); + xSubMenu = Reference <XMenu> (subPopup, UNO_QUERY); + break; + } + + //We only do this for toplevel items + if (xSubMenu.is ()) + { + helper->rebuildMenu (xSubMenu, item); + return FALSE; + } + + //If it is not a toplevel item we stop trying to rebuild + return TRUE; +} + +void +destroy_menuitem (gpointer data) +{ + g_object_unref (G_OBJECT (data)); +} + +void +destroy_menu_item_info (gpointer data) +{ + delete (MenuItemInfo*)data; +} + +// ------------------------ FrameHelper Class ------------------------------- +FrameHelper::FrameHelper(const Reference< XMultiServiceFactory >& rServiceManager, + const Reference< XFrame >& xFrame, + DbusmenuServer* server) +{ + xMSF = rServiceManager; + this->xFrame = xFrame; + this->server = server; + + //Get xUICommands database (to retrieve labels, see FrameJob::getLabelFromCommandURL ()) + Reference < XNameAccess > xNameAccess (xMSF->createInstance(OUString::createFromAscii("com.sun.star.frame.UICommandDescription")), + UNO_QUERY); + xMM = Reference < XModuleManager> (xMSF->createInstance(OUString::createFromAscii("com.sun.star.frame.ModuleManager")), + UNO_QUERY); + xNameAccess->getByName(xMM->identify(xFrame)) >>= xUICommands; + + xdp = Reference < XDispatchProvider > (xFrame, UNO_QUERY); + xTrans = Reference < XURLTransformer > (xMSF->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY); + + xSL = (XStatusListener*)new MenuItemStatusListener (this); + + // This initializes the shortcut database + getAcceleratorConfigurations (xFrame->getController()->getModel (), xMM); + + // This information is needed for the dynamic submenus + xPCF = Reference < XMultiComponentFactory > (xMSF->createInstance(OUString::createFromAscii("com.sun.star.frame.PopupMenuControllerFactory")), + UNO_QUERY); + + + // This is a hash table that maps Command URLs to MenuItemInfo classes + // to cache command information + commandsInfo = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + destroy_menu_item_info); + + // These are the arguments needed for the XPopupMenuController + args = Sequence < Any > (2); + PropertyValue item; + + item.Name = OUString::createFromAscii("ModuleName"); + item.Value <<= xMM->identify (xFrame); + args[0] <<= item; + + item.Name = OUString::createFromAscii("Frame"); + item.Value <<= xFrame; + args[1] <<= item; + + root = NULL; + watcher_set = FALSE; + + //This variable prevents the helper from being disconnected from the frame + //for special cases of component dettaching like print preview + blockDetach = FALSE; +} + +void SAL_CALL +FrameHelper::disposing (const EventObject& aEvent) throw (RuntimeException) +{} + +FrameHelper::~FrameHelper() +{ + if (server) + g_object_unref (server); + + if (watcher_set) + g_bus_unwatch_name (watcher); + + g_hash_table_destroy (commandsInfo); +} + +void +FrameHelper::setRootItem (DbusmenuMenuitem *root) +{ + this->root = root; +} + +void +FrameHelper::setRegistrarWatcher (guint watcher) +{ + watcher_set = TRUE; + this->watcher = watcher; +} + +void +FrameHelper::setServer (DbusmenuServer *server) +{ + this->server = server; +} + +//Getters +Reference < XFrame > +FrameHelper::getFrame () +{ + return xFrame; +} + +XStatusListener* +FrameHelper::getStatusListener () +{ + return xSL; +} + +GHashTable* +FrameHelper::getCommandsInfo () +{ + return commandsInfo; +} + +unsigned long +FrameHelper::getXID () +{ + Reference< XSystemDependentWindowPeer > xWin( xFrame->getContainerWindow(), UNO_QUERY ); + + if (!xWin.is()) + return 0; + + sal_Int8 processID[16]; + rtl_getGlobalProcessId( (sal_uInt8*)processID ); + Sequence <signed char> pidSeq (processID, 16); + + SystemDependentXWindow xWindow; + xWin->getWindowHandle (pidSeq, SYSTEM_XWINDOW) >>= xWindow; + + return xWindow.WindowHandle; +} + +void SAL_CALL +FrameHelper::frameAction(const FrameActionEvent& action) throw (RuntimeException) +{ + //If theh component is detached from the frame, remove this action listener, + //it is then disposed and destroyed by the frame. We deregister the window + //from the AppMenu Registrar + + //This is a special case, .uno:printPreview detaches the component but we are + //not actually switching to another document. + if (blockDetach) + { + blockDetach = TRUE; + return; + } + + if (action.Action == frame::FrameAction_COMPONENT_DETACHING) + { + GError *error = NULL; + + + xFrame->removeFrameActionListener (this); + Reference< XPropertySet > frameProps (xFrame, UNO_QUERY); + Reference < XLayoutManager > xLayoutManager(frameProps->getPropertyValue(OUString::createFromAscii("LayoutManager")), + UNO_QUERY); + xLayoutManager->showElement (OUString::createFromAscii("private:resource/menubar/menubar")); + + unsigned long xid = getXID(); + + GDBusProxy *proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "com.canonical.AppMenu.Registrar", + "/com/canonical/AppMenu/Registrar", + "com.canonical.AppMenu.Registrar", + NULL, + &error); + if (error) + { + g_warning ("Couldn't get /com/canonical/AppMenu/Registrar proxy"); + g_error_free (error); + return; + } + + //TODO: Check if window is registered already + g_dbus_proxy_call_sync (proxy, + "UnregisterWindow", + g_variant_new ("(u)", (guint32)xid), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + + if (error) + { + g_warning ("Couldn't call /com/canonical/AppMenu/Registrar.UnregisterWindow"); + g_error_free (error); + } + + if (server) + { + g_object_unref (server); + server = NULL; + root = NULL; + } + + if (watcher_set) + { + g_bus_unwatch_name (watcher); + watcher_set = FALSE; + } + + return; + } +} + +//This function rebuilds (or builds from scratch) a DbusmenuMenuitem structure +//from a given pair of XMenu/Dbusmenuitem. +void +FrameHelper::rebuildMenu (Reference < XMenu > xMenu, + DbusmenuMenuitem *parent) +{ + g_return_if_fail (parent != NULL); + GList *items = dbusmenu_menuitem_get_children (parent); + guint nitems = g_list_length (items); //number of available Dbusmenuitems + guint16 count = xMenu->getItemCount (); //number of real menu items + + // One item does not represent always the same command. + // We do this for performance reasons, as it's really hard to match a command with + // a single dbusmenuitem given the lack of information provided by the status listener + if (count > nitems) + { + // Add enough Dbusmenuitems to replicate all + for (guint16 i = 0; i < (count - nitems); i++) + { + DbusmenuMenuitem *item = dbusmenu_menuitem_new (); + dbusmenu_menuitem_child_append (parent, item); + g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(item_activated), this); + } + items = dbusmenu_menuitem_get_children (parent); + } + if (count < nitems) + { + // If there is an excess of Dbusmenuitems we make them invisible + for (guint16 i = nitems - 1; i >= count; i--) + { + DbusmenuMenuitem *item = DBUSMENU_MENUITEM (g_list_nth_data(items, i)); + dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); + } + } + + for (guint16 i = 0; i<count; i++) + { + Reference < XMenuExtended > xMenuEx (xMenu, UNO_QUERY); + guint16 id = xMenu->getItemId (i); + OUString oUCommand = xMenuEx->getCommand (id); + OString command = OUStringToOString (oUCommand, RTL_TEXTENCODING_ASCII_US); + + DbusmenuMenuitem *item = DBUSMENU_MENUITEM(g_list_nth_data(items, i)); + + if (!item) + continue; + + if (!DBUSMENU_IS_MENUITEM (item)) + continue; + + // We drop the WindowList, doesn't work properly and it's useless anyhow + if (oUCommand.equals (OUString::createFromAscii (".uno:WindowList"))) + continue; + + //We set the default properties (in case it was not visible or a separator) + dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_DEFAULT); + dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); + + if (id == 0) + { + dbusmenu_menuitem_property_set (item, "CommandURL", "slot:0"); + dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); + //Getting rid of any possible children + g_list_free_full (dbusmenu_menuitem_take_children (item), destroy_menuitem); + continue; + } + + //Setting the command + dbusmenu_menuitem_property_set (item, "CommandURL", command.getStr()); + + //Getting a shortcut + KeyEvent kev = findShortcutForCommand (oUCommand); + + if (kev.KeyCode != 0) //KeyCode must have a value + { + GVariantBuilder builder; + const gchar* keystring = AwtKeyToDbusmenuString(kev.KeyCode); + + g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); + + //We map KeyEvent.Modifiers with Dbusmenu modifiers strings + if (awt::KeyModifier::SHIFT & kev.Modifiers) + g_variant_builder_add(&builder, "s", DBUSMENU_MENUITEM_SHORTCUT_SHIFT); + if (awt::KeyModifier::MOD2 & kev.Modifiers) + g_variant_builder_add(&builder, "s", DBUSMENU_MENUITEM_SHORTCUT_ALT); + if (awt::KeyModifier::MOD1 & kev.Modifiers || awt::KeyModifier::MOD3 & kev.Modifiers) + g_variant_builder_add(&builder, "s", DBUSMENU_MENUITEM_SHORTCUT_CONTROL); + + g_variant_builder_add(&builder, "s", keystring); + + GVariant * inside = g_variant_builder_end(&builder); + g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); + g_variant_builder_add_value(&builder, inside); + + GVariant * outsidevariant = g_variant_builder_end(&builder); + dbusmenu_menuitem_property_set_variant(item, DBUSMENU_MENUITEM_PROP_SHORTCUT, outsidevariant); + } + + // Lookup for a MenuItemInfo object for this menuitem, create one if it doesn't exist + // this object caches the values that change on status updates. + MenuItemInfo* commInfo = (MenuItemInfo*)g_hash_table_lookup (commandsInfo, (gconstpointer)command.getStr()); + if (!commInfo) + { + commInfo = new MenuItemInfo (); + g_hash_table_insert (commandsInfo, g_strdup (command.getStr()), commInfo); + + OUString oULabel = getLabelFromCommandURL(oUCommand); + if (oULabel.getLength() == 0) + { + oULabel = xMenu->getItemText (id); + } + + //Replace tilde with underscore for Dbusmenu Alt accelerators + oULabel = oULabel.replace ((sal_Unicode)0x007e, (sal_Unicode)0x005f); + // GLib behaves better than OUStringToOString wrt encoding transformation + gchar* label = g_utf16_to_utf8 (oULabel.getStr(), + oULabel.getLength(), + NULL, NULL, NULL); + commInfo->setLabel (label); + g_free (label); + } + + //Update the check state directly from the data, this is more reliable + Reference < XPopupMenu > popUp (xMenu, UNO_QUERY); + if (popUp.is() && popUp->isItemChecked (id)) + { + commInfo->setCheckState (DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED); + } + + dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_LABEL, commInfo->getLabel ()); + dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, commInfo->getEnabled ()); + + //TODO: Find a selection of which commands are radio toggle type + if (commInfo->getCheckState () != DBUSMENU_MENUITEM_TOGGLE_STATE_UNKNOWN) + { + dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, commInfo->getCheckType ()); + dbusmenu_menuitem_property_set_int (item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, commInfo->getCheckState ()); + } + + // Adding status listener + URL commandURL; + commandURL.Complete = oUCommand; + xTrans->parseStrict (commandURL); + + Reference < XDispatch > xDispatch = xdp->queryDispatch (commandURL, OUString(), 0); + if (xDispatch.is()) + xDispatch->addStatusListener (xSL, commandURL); + + Reference < XPopupMenu > subPopMenu (xMenu->getPopupMenu (id), UNO_QUERY); + + //Some menus do not provide the information available through the normal XMenu interface, + //we need to access that info through a special XPopupMenuController + if (isSpecialSubmenu (oUCommand)) + { + Reference < XPropertySet > xMSFProps (xMSF, UNO_QUERY); + Reference <XComponentContext> xContext (xMSFProps->getPropertyValue (OUString::createFromAscii ("DefaultContext")), + UNO_QUERY); + + Reference < XPopupMenuController > xRFC (xPCF->createInstanceWithArgumentsAndContext(oUCommand, + args, + xContext), + UNO_QUERY); + + Reference < XPopupMenu > xPO (xMSF->createInstance(OUString::createFromAscii ("stardiv.Toolkit.VCLXPopupMenu")), + UNO_QUERY); + + if (xRFC.is () && xPO.is ()) + { + xRFC->setPopupMenu (xPO); + xRFC->updatePopupMenu (); + Reference < XMenu > subMenu (xPO, UNO_QUERY); + rebuildMenu (subMenu, item); + } + else if (subPopMenu.is ()) + { + Reference <XMenu> subMenu (subPopMenu, UNO_QUERY); + rebuildMenu (subMenu, item); + } + } + + // Introspect submenus + else if (subPopMenu.is ()) + { + Reference <XMenu> subMenu (subPopMenu, UNO_QUERY); + g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW, G_CALLBACK(item_about_to_show), this); + rebuildMenu (subMenu, item); + } + else + { + //Getting rid of any possible children + g_list_free_full (dbusmenu_menuitem_take_children (item), destroy_menuitem); + } + } + + return; +} + +//Gets the menu item Label given a CommandURL +//This is a work around for bug: https://bugs.freedesktop.org/show_bug.cgi?id=34127 +OUString +FrameHelper::getLabelFromCommandURL (OUString commandURL) +{ + OUString label; + + Sequence < PropertyValue > commandProps; + + if (commandURL.getLength () < 1) + return label; + + if (!xUICommands.is()) + return label; + + try + { + xUICommands->getByName (commandURL) >>= commandProps; + } + catch (com::sun::star::container::NoSuchElementException e) + { + return label; + } + + for (sal_Int32 i = 0; i < commandProps.getLength(); i++) + { + if ( commandProps[i].Name.equalsAsciiL (RTL_CONSTASCII_STRINGPARAM ("Label"))) + { + commandProps[i].Value >>= label; + label = label.replace ((sal_Unicode)0x007e, (sal_Unicode)0x005f); + //break; + } + } + + return label; +} + +//This method is a facility to bootstrap the Dbusmenuitem strcuture from the menubar +void +FrameHelper::rebuildMenuFromRoot () +{ + Reference < XFrame > xFrame = getFrame (); + Reference < XPropertySet > frameProps (xFrame, UNO_QUERY); + Reference < XLayoutManager > xLayoutManager (frameProps->getPropertyValue(OUString::createFromAscii("LayoutManager")), + UNO_QUERY); + Reference < XUIElement > menuBar (xLayoutManager->getElement (OUString::createFromAscii("private:resource/menubar/menubar")), + UNO_QUERY); + Reference < XPropertySet > menuPropSet (menuBar, UNO_QUERY); + + if (!menuPropSet.is ()) + return; + + Reference < XMenu > xMenu (menuPropSet->getPropertyValue(OUString::createFromAscii("XMenuBar")), + UNO_QUERY); + if (!xMenu.is ()) + return; + + rebuildMenu (xMenu, root); +} + +//Some menus are special, this is the list of them +gboolean +FrameHelper::isSpecialSubmenu (OUString command) +{ + const gchar * specialSubmenus[11] = {".uno:CharFontName", + ".uno:FontHeight", + ".uno:ObjectMenue", + ".uno:InsertPageHeader", + ".uno:InsertPageFooter", + ".uno:ChangeControlType", + ".uno:AvailableToolbars", + ".uno:ScriptOrganizer", + ".uno:RecentFileList", + ".uno:AddDirect", + ".uno:AutoPilotMenu"}; + + for (gint i = 0; i < 11; i++) + { + if (command.equals (OUString::createFromAscii (specialSubmenus[i]))) + return TRUE; + } + return FALSE; +} + +void +FrameHelper::dispatchCommand (OUString command) +{ + OUString target = OUString::createFromAscii (""); + Reference < XDispatchHelper > xdh (xMSF->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.DispatchHelper"))), + UNO_QUERY); + + //g_debug ("%s", OUStringToOString (command, RTL_TEXTENCODING_ASCII_US).getStr()); + + // This is a special case, we don't want the helper to be disconnected from the frame + // when PrintPreview dettaches. See the frameAction method. + if (command.equals (OUString::createFromAscii (".uno:PrintPreview"))) + { + blockDetach = TRUE; + } + + // This is a special case for the recentfilelist + if (command.matchAsciiL ("vnd.sun.star.popup:RecentFileList", 33, 0)) + { + target = OUString::createFromAscii ("_default"); + + Reference < XPropertySet > xMSFProps (xMSF, UNO_QUERY); + Reference <XComponentContext> xContext (xMSFProps->getPropertyValue (OUString::createFromAscii ("DefaultContext")), + UNO_QUERY); + Reference < XPopupMenuController > xRFC (xPCF->createInstanceWithArgumentsAndContext(OUString::createFromAscii (".uno:RecentFileList"), + args, + xContext), + UNO_QUERY); + Reference < XMenuListener > xML (xRFC, UNO_QUERY); + + Reference < XPopupMenu > xPO (xMSF->createInstance(OUString::createFromAscii ("stardiv.Toolkit.VCLXPopupMenu")), + UNO_QUERY); + + if (xRFC.is () && xPO.is ()) + { + xRFC->setPopupMenu (xPO); + xRFC->updatePopupMenu (); + Reference < XMenu > subMenu (xPO, UNO_QUERY); + Reference < XMenuExtended > subMenuEx (xPO, UNO_QUERY); + + //We need to find the item idd + for (int i = 0; i < subMenu->getItemCount (); i++) + { + int id = subMenu->getItemId (i); + + if (subMenuEx->getCommand (id).equals (command)) + { + MenuEvent mev; + mev.MenuId = id; + + xML->select (mev); + } + } + } + + return; + } + + if (command.matchAsciiL ("private:factory/", 16, 0)) + target = OUString::createFromAscii ("_blank"); + + xdh->executeDispatch (Reference < XDispatchProvider > (xFrame, UNO_QUERY), + command, + target, + 0, + Sequence < PropertyValue > ()); +} + +//Set all the accelerator configuration sources +void +FrameHelper::getAcceleratorConfigurations (Reference < XModel > xModel, + Reference < XModuleManager> xModuleManager) +{ + //Get document shortcut database + Reference< XUIConfigurationManagerSupplier > docUISupplier(xModel, UNO_QUERY); + Reference< XUIConfigurationManager > docUIManager = docUISupplier->getUIConfigurationManager(); + Reference< XAcceleratorConfiguration > docAccelConf(docUIManager->getShortCutManager(), UNO_QUERY); + this->docAccelConf = docAccelConf; + + //Get module shurtcut database + Reference< XModuleUIConfigurationManagerSupplier > modUISupplier(xMSF->createInstance(OUString::createFromAscii("com.sun.star.ui.ModuleUIConfigurationManagerSupplier")), + UNO_QUERY); + Reference< XUIConfigurationManager > modUIManager = modUISupplier->getUIConfigurationManager(xModuleManager->identify(xFrame)); + Reference< XAcceleratorConfiguration > modAccelConf(modUIManager->getShortCutManager(), UNO_QUERY); + this->modAccelConf = modAccelConf; + + //Get global shortcut database + Reference< XAcceleratorConfiguration > globAccelConf(xMSF->createInstance(OUString::createFromAscii("com.sun.star.ui.GlobalAcceleratorConfiguration")), + UNO_QUERY); + this->globAccelConf = globAccelConf; +} + + +//This function finds a KeyEvent with the shortcut information for each command +KeyEvent +FrameHelper::findShortcutForCommand (OUString command) + +{ + KeyEvent kev; + + Sequence < OUString > commands (1); + commands[0] = command; + + try + { + Sequence < Any > evs = docAccelConf->getPreferredKeyEventsForCommandList (commands); + + for (int j = 0; j < evs.getLength (); j++) + { + KeyEvent ev; + if (evs[j] >>= ev) + return ev; + } + } + catch (...) + {} + try + { + Sequence < Any > evs = modAccelConf->getPreferredKeyEventsForCommandList (commands); + + for (int j = 0; j < evs.getLength (); j++) + { + KeyEvent ev; + if (evs[j] >>= ev) + return ev; + } + } + catch (...) + {} + try + { + Sequence < Any > evs = globAccelConf->getPreferredKeyEventsForCommandList (commands); + + for (int j = 0; j < evs.getLength (); j++) + { + KeyEvent ev; + if (evs[j] >>= ev) + return ev; + } + } + catch (...) + {} + + //NOTE: For some reason this item does not return its shortcut. Setting manually: + if (command.equals (OUString::createFromAscii (".uno:HelpIndex"))) + { + kev.KeyCode = awt::Key::F1; + } + + return kev; +} diff --git a/framework/source/lomenubar/FrameHelper.h b/framework/source/lomenubar/FrameHelper.h new file mode 100644 index 0000000000..d3e00c6400 --- /dev/null +++ b/framework/source/lomenubar/FrameHelper.h @@ -0,0 +1,139 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * A LibreOffice extension to send the menubar structure through DBusMenu + * + * Copyright 2011 Canonical, Ltd. + * Authors: + * Alberto Ruiz <alberto.ruiz@codethink.co.uk> + * + * This program is free software: you can redistribute it and/or modify it under + * the the GNU Lesser General Public License version 3, as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable + * version of the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef __FRAME_HELPER_H__ +#define __FRAME_HELPER_H__ + +#include <com/sun/star/awt/KeyEvent.hpp> +#include <com/sun/star/awt/XMenu.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/XFramesSupplier.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/frame/XFrameActionListener.hpp> +#include <com/sun/star/frame/XStatusListener.hpp> +#include <com/sun/star/frame/FrameAction.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XModuleManager.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <cppuhelper/implbase1.hxx> +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/ui/XAcceleratorConfiguration.hpp> + +#include <libdbusmenu-glib/server.h> +#include <libdbusmenu-glib/menuitem.h> + +using com::sun::star::awt::KeyEvent; +using com::sun::star::awt::XMenu; +using com::sun::star::beans::PropertyValue; +using com::sun::star::container::XNameAccess; +using com::sun::star::frame::FrameActionEvent; +using com::sun::star::frame::XFrame; +using com::sun::star::frame::XFramesSupplier; +using com::sun::star::frame::XFrameActionListener; +using com::sun::star::frame::XStatusListener; +using com::sun::star::frame::XDispatchProvider; +using com::sun::star::frame::XModuleManager; +using com::sun::star::frame::XModel; +using com::sun::star::lang::EventObject; +using com::sun::star::lang::XMultiServiceFactory; +using com::sun::star::lang::XMultiComponentFactory; +using com::sun::star::uno::Any; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::RuntimeException; +using com::sun::star::util::XURLTransformer; +using com::sun::star::ui::XAcceleratorConfiguration; +using rtl::OUString; + +/* This class is a helper in charge of closing the dbusmenu server when a frame is closed, + * and also allows the menuitem callbacks to dispatch commands. + */ + +class FrameHelper : public cppu::WeakImplHelper1 < XFrameActionListener > +{ + private: + Reference < XFrame > xFrame; + Reference < XMultiServiceFactory > xMSF; + Reference < XNameAccess > xUICommands; + DbusmenuServer *server; + DbusmenuMenuitem *root; + gboolean watcher_set; + guint watcher; + XStatusListener *xSL; + Reference < XURLTransformer > xTrans; + Reference < XDispatchProvider > xdp; + GHashTable *commandsInfo; + gboolean blockDetach; + + //These object/methods are used to recreate dynamic popupmenus + Reference < XMultiComponentFactory > xPCF; + Reference < XModuleManager> xMM; + Sequence < Any > args; + + gboolean isSpecialSubmenu (OUString command); + + //This is to build the shortcut database + Reference< XAcceleratorConfiguration > docAccelConf; + Reference< XAcceleratorConfiguration > modAccelConf; + Reference< XAcceleratorConfiguration > globAccelConf; + + void getAcceleratorConfigurations (Reference < XModel >, + Reference < XModuleManager>); + + KeyEvent findShortcutForCommand (OUString); + + public: + FrameHelper(const Reference< XMultiServiceFactory >&, + const Reference< XFrame >&, + DbusmenuServer*); + + virtual ~FrameHelper(); + virtual void SAL_CALL frameAction(const FrameActionEvent& action) + throw (RuntimeException); + + virtual void SAL_CALL disposing(const EventObject& aEvent) + throw (RuntimeException); + + //Setters + void setRootItem (DbusmenuMenuitem *); + void setRegistrarWatcher (guint watcher); + void setServer (DbusmenuServer *); + + //Getters + Reference < XFrame > getFrame (); + unsigned long getXID (); + GHashTable* getCommandsInfo (); + XStatusListener* getStatusListener (); + ::rtl::OUString getLabelFromCommandURL (::rtl::OUString); + + //Menu Related actions + void dispatchCommand (OUString); + void rebuildMenu (Reference < XMenu >, DbusmenuMenuitem*); + void rebuildMenuFromRoot (); + void populateWindowList (DbusmenuMenuitem *); +}; +#endif // __FRAME_HELPER_H__ diff --git a/framework/source/lomenubar/FrameJob.cxx b/framework/source/lomenubar/FrameJob.cxx new file mode 100644 index 0000000000..7e84d6c911 --- /dev/null +++ b/framework/source/lomenubar/FrameJob.cxx @@ -0,0 +1,393 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * A LibreOffice extension to send the menubar structure through DBusMenu + * + * Copyright 2011 Canonical, Ltd. + * Authors: + * Alberto Ruiz <alberto.ruiz@codethink.co.uk> + * + * This program is free software: you can redistribute it and/or modify it under + * the the GNU Lesser General Public License version 3, as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable + * version of the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#include "FrameJob.h" +#include "DesktopJob.h" +#include "FrameHelper.h" + +#define OBJ_PATH_PREFIX "/com/canonical/menu/" + +#include <com/sun/star/awt/XSystemDependentWindowPeer.hpp> +#include <com/sun/star/awt/SystemDependentXWindow.hpp> +#include <com/sun/star/awt/XMenu.hpp> +#include <com/sun/star/awt/XMenuExtended.hpp> +#include <com/sun/star/awt/XMenuBar.hpp> +#include <com/sun/star/awt/XPopupMenu.hpp> +#include <com/sun/star/awt/XPopupMenuExtended.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/NoSuchElementException.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/document/XEventBroadcaster.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/frame/XLayoutManager.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/XDispatchHelper.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XFrameActionListener.hpp> +#include <com/sun/star/frame/XStatusListener.hpp> +#include <com/sun/star/frame/FrameAction.hpp> +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/lang/SystemDependent.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/ui/XUIConfigurationManager.hpp> +#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/XUIElementSettings.hpp> +#include <com/sun/star/ui/XUIElement.hpp> +#include <com/sun/star/ui/XModuleUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/util/URL.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> + +#include <iostream> +#include <fstream> + +#include <gio/gio.h> +#include <libdbusmenu-glib/server.h> +#include <libdbusmenu-glib/client.h> + +#include <rtl/process.h> +#include <osl/diagnose.h> + +using rtl::OUString; +using rtl::OString; +using rtl::OUStringToOString; + +using com::sun::star::awt::KeyEvent; +using com::sun::star::awt::SystemDependentXWindow; +using com::sun::star::awt::XMenu; +using com::sun::star::awt::XMenuExtended; +using com::sun::star::awt::XPopupMenu; +using com::sun::star::awt::XPopupMenuExtended; +using com::sun::star::awt::XMenuBar; +using com::sun::star::awt::XSystemDependentWindowPeer; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::WeakReference; +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Exception; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::XInterface; +using com::sun::star::lang::IllegalArgumentException; +using com::sun::star::lang::XMultiServiceFactory; +using com::sun::star::lang::SystemDependent::SYSTEM_XWINDOW; +using com::sun::star::lang::EventObject; +using com::sun::star::beans::NamedValue; +using com::sun::star::beans::PropertyValue; +using com::sun::star::beans::XPropertySet; +using com::sun::star::document::XEventBroadcaster; +using com::sun::star::frame::XFrame; +using com::sun::star::frame::XFrameActionListener; +using com::sun::star::frame::FrameActionEvent; +using com::sun::star::frame::XController; +using com::sun::star::frame::XLayoutManager; +using com::sun::star::frame::XModel; +using com::sun::star::frame::XModuleManager; +using com::sun::star::frame::XDispatch; +using com::sun::star::frame::XDispatchProvider; +using com::sun::star::frame::XDispatchHelper; +using com::sun::star::frame::XStatusListener; +using com::sun::star::frame::FeatureStateEvent; +using com::sun::star::ui::XUIElement; +using com::sun::star::ui::XUIElementSettings; +using com::sun::star::ui::XUIConfigurationManagerSupplier; +using com::sun::star::ui::XUIConfigurationManager; +using com::sun::star::ui::XModuleUIConfigurationManagerSupplier; +using com::sun::star::ui::XAcceleratorConfiguration; +using com::sun::star::util::URL; +using com::sun::star::util::XURLTransformer; +using com::sun::star::container::XIndexContainer; +using com::sun::star::container::XIndexAccess; +using com::sun::star::container::XNameAccess; +using com::sun::star::container::NoSuchElementException; + + +// This is a helper utility to transform an xid to a /com/canonical/menu/<XID> +// DBUS object path +OString +xid_to_object_path (unsigned long xid) +{ + + GString *xid_str = g_string_new (""); + g_string_printf (xid_str, "%d", (guint32)xid); + OString object_path = OUStringToOString (OUString::createFromAscii (OBJ_PATH_PREFIX).concat (OUString::createFromAscii(xid_str->str)), + RTL_TEXTENCODING_ASCII_US); + g_string_free (xid_str, TRUE); + return object_path; +} + +//-------------------------- GObject callbacks -------------------------------// +//This is called when a registrar becomes available. It registers the hides the menubar. +static void +on_registrar_available (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + GError *error = NULL; + GDBusProxy *proxy; + + FrameHelper *helper = (FrameHelper*)user_data; + unsigned long xid = helper->getXID(); + + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "com.canonical.AppMenu.Registrar", + "/com/canonical/AppMenu/Registrar", + "com.canonical.AppMenu.Registrar", + NULL, + &error); + if (error) + { + g_warning ("Couldn't get /com/canonical/AppMenu/Registrar proxy"); + return; + } + + + //TODO: Check if window is registered already + g_dbus_proxy_call_sync (proxy, + "RegisterWindow", + g_variant_new ("(uo)", + (guint32)xid, + xid_to_object_path (xid).getStr()), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + + if (error) + { + g_warning ("Couldn't call /com/canonical/AppMenu/Registrar.RegisterWindow"); + return; + } + + //Hide menubar + Reference < XFrame > xFrame = helper->getFrame (); + Reference< XPropertySet > frameProps (xFrame, UNO_QUERY); + Reference < XLayoutManager > xLayoutManager(frameProps->getPropertyValue(OUString::createFromAscii("LayoutManager")), + UNO_QUERY); + xLayoutManager->hideElement (OUString::createFromAscii("private:resource/menubar/menubar")); + + return; +} + +//This is called when the registrar becomes unavailable. It shows the menubar. +static void +on_registrar_unavailable (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + //TODO: Unregister window? + + // Show menubar + FrameHelper *helper = (FrameHelper*)user_data; + Reference < XFrame > xFrame = helper->getFrame (); + Reference< XPropertySet > frameProps (xFrame, UNO_QUERY); + Reference < XLayoutManager > xLayoutManager(frameProps->getPropertyValue(OUString::createFromAscii("LayoutManager")), + UNO_QUERY); + xLayoutManager->showElement (OUString::createFromAscii("private:resource/menubar/menubar")); + return; +} +// ------------------------------- FrameJob -------------------------------------------- +Any SAL_CALL FrameJob::execute( const Sequence< NamedValue >& aArguments ) + throw ( IllegalArgumentException, Exception, RuntimeException ) +{ + Sequence< NamedValue > lEnv; + Reference< XModel > xModel; + sal_Int32 len = aArguments.getLength(); + + for (int i = 0; i<len; i++) + { + if (aArguments[i].Name.equalsAscii("Environment")) + { + aArguments[i].Value >>= lEnv; + break; + } + } + + len = lEnv.getLength (); + for (int i = 0; i<len; i++) + { + if (lEnv[i].Name.equalsAscii("Model")) + { + lEnv[i].Value >>= xModel; + } + } + + //If we didn't get the model we have to quit + if (!xModel.is()) + return Any(); + + + Reference< XController > xController( xModel->getCurrentController(), UNO_QUERY); + if (!xController.is()) + return Any(); + + xFrame = Reference< XFrame > ( xController->getFrame(), UNO_QUERY); + if (!xFrame.is ()) + return Any(); + + exportMenus (xFrame); + return Any(); +} + +// This function crates a DbusmenuServer and starts the watcher for the AppMenu Registrar bus name +void +FrameJob::exportMenus (Reference < XFrame > xFrame) +{ + //Set the xFrame for this object + + this->xFrame = xFrame; + + //Create dbusmenu server object path string + DbusmenuServer *server = dbusmenu_server_new (xid_to_object_path(getXID (xFrame)).getStr()); + + + Reference< XPropertySet > frameProps (xFrame, UNO_QUERY); + Reference < XLayoutManager > xLayoutManager(frameProps->getPropertyValue(OUString::createFromAscii("LayoutManager")), + UNO_QUERY); + if (!xLayoutManager.is()) + { + g_object_unref (server); + return; + } + + Reference < XUIElement > menuBar(xLayoutManager->getElement (OUString::createFromAscii("private:resource/menubar/menubar")), + UNO_QUERY); + Reference < XPropertySet > menuPropSet (menuBar, UNO_QUERY); + + if (!menuPropSet.is()) + { + g_object_unref (server); + return; + } + + Reference < XMenu > xMenu (menuPropSet->getPropertyValue(OUString::createFromAscii("XMenuBar")), + UNO_QUERY); + + if (!xMenu.is ()) + { + g_object_unref (server); + return; + } + + //Create a new frame helper to close the server when needed + FrameHelper *helper = new FrameHelper (mxMSF, xFrame, server); + xFrame->addFrameActionListener (Reference < XFrameActionListener > (helper)); + + //Populate dbusmenu items and start the server + DbusmenuMenuitem *root = getRootMenuitem (xMenu, (gpointer)helper); + dbusmenu_server_set_root (server, root); + + //Listen to the availability of the registrar + guint watcher = g_bus_watch_name (G_BUS_TYPE_SESSION, + "com.canonical.AppMenu.Registrar", + G_BUS_NAME_WATCHER_FLAGS_NONE, + on_registrar_available, + on_registrar_unavailable, + helper, + NULL); + helper->setRegistrarWatcher (watcher); +} + + +//Gets the XID for a given XFrame +unsigned long +FrameJob::getXID (css::uno::Reference < css::frame::XFrame > xFrame) +{ + Reference< XSystemDependentWindowPeer > xWin( xFrame->getContainerWindow(), UNO_QUERY); + + if (!xWin.is()) + return 0; + + sal_Int8 processID[16]; + rtl_getGlobalProcessId( (sal_uInt8*)processID ); + Sequence <signed char> pidSeq (processID, 16); + + SystemDependentXWindow xWindow; + xWin->getWindowHandle (pidSeq, SYSTEM_XWINDOW) >>= xWindow; + + return xWindow.WindowHandle; +} + +// Builds a Dbusmenuitem structure from an XMenu object +DbusmenuMenuitem* +FrameJob::getRootMenuitem (Reference < XMenu > xMenu, gpointer helper) +{ + + DbusmenuMenuitem *root = dbusmenu_menuitem_new_with_id (0); + ((FrameHelper*)helper)->setRootItem(root); + ((FrameHelper*)helper)->rebuildMenu (xMenu, root); + + return root; +} + +// XJob +OUString FrameJob_getImplementationName () + throw (RuntimeException) +{ + return OUString ( RTL_CONSTASCII_USTRINGPARAM ( FRAMEJOB_IMPLEMENTATION_NAME ) ); +} + +sal_Bool SAL_CALL FrameJob_supportsService( const OUString& ServiceName ) + throw (RuntimeException) +{ + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( FRAMEJOB_SERVICE_NAME ) ); +} + +Sequence< OUString > SAL_CALL FrameJob_getSupportedServiceNames( ) + throw (RuntimeException) +{ + Sequence < OUString > aRet(1); + OUString* pArray = aRet.getArray(); + pArray[0] = OUString ( RTL_CONSTASCII_USTRINGPARAM ( FRAMEJOB_SERVICE_NAME ) ); + return aRet; +} + +Reference< XInterface > SAL_CALL FrameJob_createInstance( const Reference< XMultiServiceFactory > & rSMgr) + throw( Exception ) +{ + return (cppu::OWeakObject*) new FrameJob(rSMgr); +} + +// XServiceInfo +OUString SAL_CALL FrameJob::getImplementationName() + throw (RuntimeException) +{ + return FrameJob_getImplementationName(); +} + +sal_Bool SAL_CALL FrameJob::supportsService( const OUString& rServiceName ) + throw (RuntimeException) +{ + return FrameJob_supportsService( rServiceName ); +} + +Sequence< OUString > SAL_CALL FrameJob::getSupportedServiceNames() + throw (RuntimeException) +{ + return FrameJob_getSupportedServiceNames(); +} + diff --git a/framework/source/lomenubar/FrameJob.h b/framework/source/lomenubar/FrameJob.h new file mode 100644 index 0000000000..d209a0966f --- /dev/null +++ b/framework/source/lomenubar/FrameJob.h @@ -0,0 +1,101 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * A LibreOffice extension to send the menubar structure through DBusMenu + * + * Copyright 2011 Canonical, Ltd. + * Authors: + * Alberto Ruiz <alberto.ruiz@codethink.co.uk> + * + * This program is free software: you can redistribute it and/or modify it under + * the the GNU Lesser General Public License version 3, as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable + * version of the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef __FRAME_JOB_HXX__ +#define __MRAME_JOB_HXX__ + +#include <com/sun/star/task/XJob.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/implbase2.hxx> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XModuleManager.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/ui/XAcceleratorConfiguration.hpp> +#include <com/sun/star/awt/XMenu.hpp> +#include <com/sun/star/awt/KeyEvent.hpp> + +#include <glib.h> +#include <libdbusmenu-glib/menuitem.h> + +#define FRAMEJOB_IMPLEMENTATION_NAME "com.sun.star.comp.Office.MyJob" +#define FRAMEJOB_SERVICE_NAME "com.sun.star.task.Job" + +namespace css = ::com::sun::star; +using css::uno::Reference; + +class FrameJob : public cppu::WeakImplHelper2 < css::task::XJob, css::lang::XServiceInfo > +{ + private: + Reference < css::lang::XMultiServiceFactory > mxMSF; + Reference < css::container::XNameAccess > xUICommands; + Reference < css::frame::XFrame > xFrame; + + unsigned long xid; + + //Private methods + unsigned long getXID (Reference < css::frame::XFrame >); + DbusmenuMenuitem* getRootMenuitem (Reference < css::awt::XMenu >, + gpointer); + + public: + FrameJob( const css::uno::Reference< css::lang::XMultiServiceFactory > &rxMSF) + : mxMSF( rxMSF ) {}; + + void exportMenus (Reference < css::frame::XFrame > xFrame); + + virtual ~FrameJob() {} + + // XJob + virtual css::uno::Any SAL_CALL execute(const css::uno::Sequence< css::beans::NamedValue >& Arguments) + throw (css::lang::IllegalArgumentException, css::uno::Exception, css::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() + throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw (css::uno::RuntimeException); + + virtual css::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() + throw (css::uno::RuntimeException); +}; + + +::rtl::OUString FrameJob_getImplementationName() + throw ( css::uno::RuntimeException ); + +sal_Bool SAL_CALL FrameJob_supportsService( const ::rtl::OUString& ServiceName ) + throw ( css::uno::RuntimeException ); + +css::uno::Sequence< ::rtl::OUString > SAL_CALL FrameJob_getSupportedServiceNames() + throw ( css::uno::RuntimeException ); + +css::uno::Reference< css::uno::XInterface > +SAL_CALL FrameJob_createInstance( const css::uno::Reference< css::lang::XMultiServiceFactory > & rSMgr) + throw ( css::uno::Exception ); + +#endif + diff --git a/framework/source/lomenubar/MenuItemInfo.cxx b/framework/source/lomenubar/MenuItemInfo.cxx new file mode 100644 index 0000000000..eab5c5bc75 --- /dev/null +++ b/framework/source/lomenubar/MenuItemInfo.cxx @@ -0,0 +1,103 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * A LibreOffice extension to send the menubar structure through DBusMenu + * + * Copyright 2011 Canonical, Ltd. + * Authors: + * Alberto Ruiz <alberto.ruiz@codethink.co.uk> + * + * This program is free software: you can redistribute it and/or modify it under + * the the GNU Lesser General Public License version 3, as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable + * version of the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#include "MenuItemInfo.h" +#include <libdbusmenu-gtk/menuitem.h> + +MenuItemInfo::MenuItemInfo () +{ + label = NULL; + check_state = DBUSMENU_MENUITEM_TOGGLE_STATE_UNKNOWN; + check_type = (gchar*)DBUSMENU_MENUITEM_TOGGLE_CHECK; + + is_visible = TRUE; + is_enabled = TRUE; +} + +MenuItemInfo::~MenuItemInfo () +{ + if (label) + g_free(label); +} + +//Setters +void +MenuItemInfo::setLabel (gchar* label) +{ + this->label = g_strdup (label); +} + +void +MenuItemInfo::setEnabled (gboolean is_enabled) +{ + this->is_enabled = is_enabled; +} + +void +MenuItemInfo::setCheckState (gint check_state) +{ + this->check_state = check_state; +} + +void +MenuItemInfo::setCheckType (const gchar* check_type) +{ + this->check_type = (gchar*)check_type; +} + +void +MenuItemInfo::setVisible (gboolean is_visible) +{ + this->is_visible = is_visible; +} + +//Getters +gchar* +MenuItemInfo::getLabel () +{ + return label; +} + +gboolean +MenuItemInfo::getEnabled () +{ + return is_enabled; +} + +gint +MenuItemInfo::getCheckState () +{ + return check_state; +} + +const gchar* +MenuItemInfo::getCheckType () +{ + return check_type; +} + +gboolean +MenuItemInfo::getVisible () +{ + return is_visible; +} diff --git a/framework/source/lomenubar/MenuItemInfo.h b/framework/source/lomenubar/MenuItemInfo.h new file mode 100644 index 0000000000..9239625f58 --- /dev/null +++ b/framework/source/lomenubar/MenuItemInfo.h @@ -0,0 +1,54 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * A LibreOffice extension to send the menubar structure through DBusMenu + * + * Copyright 2011 Canonical, Ltd. + * Authors: + * Alberto Ruiz <alberto.ruiz@codethink.co.uk> + * + * This program is free software: you can redistribute it and/or modify it under + * the the GNU Lesser General Public License version 3, as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable + * version of the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef __MENU_ITEM_INFO_H__ +#define __MENU_ITEM_INFO_H__ +#include <glib.h> + +// This is used in a hash table with commandurls as keys +class MenuItemInfo { + gchar* label; //Label text in UTF-8 with tildes subst by underscores + gint check_state; + gchar* check_type; + gboolean is_enabled; + gboolean is_visible; + + public: + MenuItemInfo (); + ~MenuItemInfo (); + + //Setters + void setLabel (gchar* label); + void setEnabled (gboolean is_enabled); + void setCheckState (gint check_state); + void setCheckType (const gchar* check_type); + void setVisible (gboolean is_visible); + + //Getters + gchar* getLabel (); + gboolean getEnabled (); + gint getCheckState (); + const gchar* getCheckType (); + gboolean getVisible (); +}; +#endif // __MENU_ITEM_INFO_H__ diff --git a/framework/source/lomenubar/MenuItemStatusListener.cxx b/framework/source/lomenubar/MenuItemStatusListener.cxx new file mode 100644 index 0000000000..68ca3de8d4 --- /dev/null +++ b/framework/source/lomenubar/MenuItemStatusListener.cxx @@ -0,0 +1,82 @@ +#include "MenuItemStatusListener.h" +#include "MenuItemInfo.h" + +#include <com/sun/star/frame/status/Visibility.hpp> + +using com::sun::star::frame::status::Visibility; + +MenuItemStatusListener::MenuItemStatusListener (FrameHelper *helper) +{ + if (!helper) throw ("FrameHelper cannot be NULL"); + this->helper = helper; +} + +void SAL_CALL +MenuItemStatusListener::statusChanged(const FeatureStateEvent& Event) + throw (RuntimeException) +{ + sal_Bool isChecked; + Visibility visible; + OUString url = Event.FeatureURL.Complete; + OUString oULabel; + + gchar* c_url = g_utf16_to_utf8 (url.getStr(), + url.getLength(), + NULL, NULL, NULL); + + GHashTable *commandsInfo = helper->getCommandsInfo (); + MenuItemInfo *info = (MenuItemInfo*)g_hash_table_lookup (commandsInfo, (gpointer)c_url); + if (!info) + { + info = new MenuItemInfo (); + g_hash_table_insert (commandsInfo, c_url, info); + + //Set the default label + oULabel = helper->getLabelFromCommandURL(url); + // Replace tilde with underscore for Dbusmenu Alt accelerators + oULabel = oULabel.replace ((sal_Unicode)0x007e, (sal_Unicode)0x005f); + + // GLib behaves better than OUStringToOString wrt encoding transformation + gchar* label = g_utf16_to_utf8 (oULabel.getStr(), + oULabel.getLength(), + NULL, NULL, NULL); + info->setLabel (label); + g_free (label); + } + else + { + //Since we're not introducing it in the hash table, we get rid of this string + g_free (c_url); + } + + //We set the enabled/disabled state + info->setEnabled ((gboolean)Event.IsEnabled); + + //We find out what the new state is by casting + + //For some reason, URLs can slip through as labels, we make sure + //this doesn't happen. + if ((Event.State >>= oULabel) && + !oULabel.matchAsciiL ("private:", 8, 0) && + !oULabel.matchAsciiL (".uno:", 5, 0) && + !oULabel.matchAsciiL ("slot:", 5, 0) && + !oULabel.matchAsciiL ("service:", 8, 0) && + !oULabel.matchAsciiL (".cmd:", 5, 0) && + !oULabel.matchAsciiL ("macro:///", 5, 0)) + { + oULabel = oULabel.replace ((sal_Unicode)0x007e, (sal_Unicode)0x005f); + gchar* label = g_utf16_to_utf8 (oULabel.getStr(), + oULabel.getLength(), + NULL, NULL, NULL); + info->setLabel (label); + g_free (label); + } + else if (Event.State >>= isChecked) + { + info->setCheckState (isChecked); + } + else if (Event.State >>= visible) + { + info->setVisible (visible.bVisible); + } +} diff --git a/framework/source/lomenubar/MenuItemStatusListener.h b/framework/source/lomenubar/MenuItemStatusListener.h new file mode 100644 index 0000000000..56cf5e8332 --- /dev/null +++ b/framework/source/lomenubar/MenuItemStatusListener.h @@ -0,0 +1,35 @@ +#ifndef __MENU_ITEM_STATUS_LISTENER_H__ +#define __MENU_ITEM_STATUS_LISTENER_H__ + +#include "FrameHelper.h" + +#include <glib.h> + +#include <com/sun/star/frame/XStatusListener.hpp> +#include <cppuhelper/implbase1.hxx> + +#include <rtl/process.h> + +using com::sun::star::frame::FeatureStateEvent; +using com::sun::star::frame::XStatusListener; +using com::sun::star::lang::EventObject; + +// This class listens for changes in each menuitem and notifies FrameHelper about it +class MenuItemStatusListener : public cppu::WeakImplHelper1 < XStatusListener > +{ + private: + guint16 id; + FrameHelper *helper; + + public: + MenuItemStatusListener (FrameHelper *helper); + ~MenuItemStatusListener () {} + + virtual void SAL_CALL + statusChanged(const FeatureStateEvent& Event) + throw (RuntimeException); + + virtual void SAL_CALL disposing(const EventObject& aEvent) + throw (RuntimeException) {} +}; +#endif diff --git a/framework/source/lomenubar/exports.cxx b/framework/source/lomenubar/exports.cxx new file mode 100644 index 0000000000..e581a2c55c --- /dev/null +++ b/framework/source/lomenubar/exports.cxx @@ -0,0 +1,119 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * A LibreOffice extension to send the menubar structure through DBusMenu + * + * Copyright 2011 Canonical, Ltd. + * Authors: + * Alberto Ruiz <alberto.ruiz@codethink.co.uk> + * + * This program is free software: you can redistribute it and/or modify it under + * the the GNU Lesser General Public License version 3, as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable + * version of the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#include <stdio.h> + +#include <osl/mutex.hxx> +#include <osl/thread.h> +#include <cppuhelper/factory.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/types.h> + +#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_ +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#endif + +#include "DesktopJob.h" +#include "FrameJob.h" + +namespace css = ::com::sun::star; + +static void writeInfo(const css::uno::Reference< css::registry::XRegistryKey >& xRegistryKey , + const char* pImplementationName, + const char* pServiceName ) +{ + ::rtl::OUStringBuffer sKey(256); + sKey.append (::rtl::OUString::createFromAscii(pImplementationName)); + sKey.appendAscii("/UNO/SERVICES/"); + sKey.append (::rtl::OUString::createFromAscii(pServiceName)); + + xRegistryKey->createKey(sKey.makeStringAndClear()); +} + +extern "C" +{ +//================================================================================================== +SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment(const sal_Char** ppEnvTypeName, + uno_Environment** ppEnv ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + + +//================================================================================================== +SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL component_writeInfo(void* pServiceManager, + void* pRegistryKey ) +{ + if (!pRegistryKey) + return sal_False; + + try + { + css::uno::Reference< css::registry::XRegistryKey > xKey(reinterpret_cast< css::registry::XRegistryKey* >(pRegistryKey), css::uno::UNO_QUERY); + + writeInfo( xKey, DESKTOPJOB_IMPLEMENTATION_NAME, DESKTOPJOB_SERVICE_NAME); + writeInfo( xKey, FRAMEJOB_IMPLEMENTATION_NAME, FRAMEJOB_SERVICE_NAME); + + return sal_True; + } + catch(const css::registry::InvalidRegistryException&) + { OSL_ENSURE( sal_False, "### InvalidRegistryException!" ); } + + return sal_False; +} + +//================================================================================================== +SAL_DLLPUBLIC_EXPORT void* SAL_CALL component_getFactory(const sal_Char* pImplName , + void* pServiceManager, + void* pRegistryKey ) +{ + if ( !pServiceManager || !pImplName ) + return 0; + + css::uno::Reference< css::lang::XSingleServiceFactory > xFactory ; + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR (reinterpret_cast< css::lang::XMultiServiceFactory* >(pServiceManager), css::uno::UNO_QUERY); + ::rtl::OUString sImplName = ::rtl::OUString::createFromAscii(pImplName); + + if (sImplName.equalsAscii(DESKTOPJOB_IMPLEMENTATION_NAME)) + { + css::uno::Sequence< ::rtl::OUString > lNames(1); + lNames[0] = ::rtl::OUString::createFromAscii(DESKTOPJOB_IMPLEMENTATION_NAME); + xFactory = ::cppu::createSingleFactory(xSMGR, sImplName, DesktopJob_createInstance, lNames); + } + if (sImplName.equalsAscii(FRAMEJOB_IMPLEMENTATION_NAME)) + { + css::uno::Sequence< ::rtl::OUString > lNames(1); + lNames[0] = ::rtl::OUString::createFromAscii(FRAMEJOB_IMPLEMENTATION_NAME); + xFactory = ::cppu::createSingleFactory(xSMGR, sImplName, FrameJob_createInstance, lNames); + } + + + if (!xFactory.is()) + return 0; + + xFactory->acquire(); + return xFactory.get(); +} + +} // extern C |