400 lines
14 KiB
C++
400 lines
14 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* 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.hxx"
|
|
#include "DesktopJob.hxx"
|
|
#include "FrameHelper.hxx"
|
|
|
|
#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>
|
|
//#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
|
#include <libdbusmenu-glib/server.h>
|
|
#include <libdbusmenu-glib/client.h>
|
|
#pragma GCC diagnostic error "-Wignored-qualifiers"
|
|
//#pragma GCC diagnostic pop
|
|
|
|
#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(RTL_CONSTASCII_USTRINGPARAM("LayoutManager"))),
|
|
UNO_QUERY);
|
|
xLayoutManager->hideElement (OUString(RTL_CONSTASCII_USTRINGPARAM("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(RTL_CONSTASCII_USTRINGPARAM("LayoutManager"))),
|
|
UNO_QUERY);
|
|
xLayoutManager->showElement (OUString(RTL_CONSTASCII_USTRINGPARAM("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();
|
|
|
|
m_xFrame = Reference< XFrame > ( xController->getFrame(), UNO_QUERY);
|
|
if (!m_xFrame.is ())
|
|
return Any();
|
|
|
|
exportMenus (m_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->m_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(RTL_CONSTASCII_USTRINGPARAM("LayoutManager"))),
|
|
UNO_QUERY);
|
|
if (!xLayoutManager.is())
|
|
{
|
|
g_object_unref (server);
|
|
return;
|
|
}
|
|
|
|
Reference < XUIElement > menuBar(xLayoutManager->getElement (OUString(RTL_CONSTASCII_USTRINGPARAM("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(RTL_CONSTASCII_USTRINGPARAM("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 (m_xMSF, 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();
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|