diff options
Diffstat (limited to 'vcl/unx')
-rw-r--r-- | vcl/unx/gtk/window/gtkframe.cxx | 202 | ||||
-rw-r--r-- | vcl/unx/gtk/window/gtksalmenu.cxx | 241 |
2 files changed, 256 insertions, 187 deletions
diff --git a/vcl/unx/gtk/window/gtkframe.cxx b/vcl/unx/gtk/window/gtkframe.cxx index 82011ca594f4..6fcc542fc3d6 100644 --- a/vcl/unx/gtk/window/gtkframe.cxx +++ b/vcl/unx/gtk/window/gtkframe.cxx @@ -22,6 +22,9 @@ #include <unx/gtk/gtkdata.hxx> #include <unx/gtk/gtkinst.hxx> #include <unx/gtk/gtkgdi.hxx> +#include <unx/gtk/glomenu.h> +#include <unx/gtk/gloactiongroup.h> +#include <unx/gtk/gtksalmenu.hxx> #include <vcl/keycodes.hxx> #include <unx/wmadaptor.hxx> #include <unx/sm.hxx> @@ -36,6 +39,7 @@ #include <unx/x11/xlimits.hxx> #endif +#include <gtk/gtk.h> #include <tools/prex.h> #include <X11/Xatom.h> #include <gdk/gdkx.h> @@ -94,6 +98,7 @@ using namespace com::sun::star; int GtkSalFrame::m_nFloats = 0; +static GDBusConnection* pSessionBus = NULL; static sal_uInt16 GetKeyModCode( guint state ) { sal_uInt16 nCode = 0; @@ -473,6 +478,177 @@ GtkSalFrame::GtkSalFrame( SystemParentData* pSysData ) Init( pSysData ); } +static void +gdk_x11_window_set_utf8_property (GdkWindow *window, + const gchar *name, + const gchar *value) +{ + GdkDisplay* display = gdk_window_get_display (window); + + if (value != NULL) + { + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (window), + gdk_x11_get_xatom_by_name_for_display (display, name), + gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8, + PropModeReplace, (guchar *)value, strlen (value)); + } + else + { + XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (window), + gdk_x11_get_xatom_by_name_for_display (display, name)); + } +} + +// AppMenu watch functions. + + +static void +on_registrar_available (GDBusConnection * /*connection*/, + const gchar * /*name*/, + const gchar * /*name_owner*/, + gpointer user_data) +{ + SolarMutexGuard aGuard; + GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( user_data ); + GtkSalMenu* pSalMenu = static_cast< GtkSalMenu* >( pSalFrame->GetMenu() ); + + if ( pSalMenu != NULL ) + { + MenuBar* pMenuBar = static_cast< MenuBar* >( pSalMenu->GetMenu() ); + + GtkWidget *pWidget = pSalFrame->getWindow(); + GdkWindow *gdkWindow = gtk_widget_get_window( pWidget ); + + if ( gdkWindow != NULL ) + { + GMenuModel* pMenuModel = G_MENU_MODEL( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" ) ); + GActionGroup* pActionGroup = G_ACTION_GROUP( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-action-group" ) ); + + XLIB_Window windowId = GDK_WINDOW_XID( gdkWindow ); + + gchar* aDBusPath = g_strdup_printf("/window/%lu", windowId); + gchar* aDBusWindowPath = g_strdup_printf( "/window/%lu", windowId ); + gchar* aDBusMenubarPath = g_strdup_printf( "/window/%lu/menus/menubar", windowId ); + + // Get a DBus session connection. + if(!pSessionBus) + pSessionBus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + + if( pSessionBus == NULL ) + return; + + if ( aDBusMenubarPath != NULL && pMenuModel != NULL && !pSalMenu->mbGdkDisposed) + pSalMenu->mnMenuExportId = g_dbus_connection_export_menu_model (pSessionBus, aDBusMenubarPath, pMenuModel, NULL); + + if ( aDBusPath != NULL && pActionGroup != NULL && !pSalMenu->mbGdkDisposed) + pSalMenu->mnAGExportId = g_dbus_connection_export_action_group( pSessionBus, aDBusPath, pActionGroup, NULL); + + // Set window properties. + gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_UNIQUE_BUS_NAME", g_dbus_connection_get_unique_name( pSessionBus ) ); + gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_APPLICATION_OBJECT_PATH", "" ); + gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_WINDOW_OBJECT_PATH", aDBusWindowPath ); + gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_MENUBAR_OBJECT_PATH", aDBusMenubarPath ); + + g_free( aDBusPath ); + g_free( aDBusWindowPath ); + g_free( aDBusMenubarPath ); + + bDBusIsAvailable = sal_True; + + if ( pMenuBar && !pSalMenu->mbGdkDisposed) + { + pMenuBar->SetDisplayable( sal_False ); + } + } + } + + 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) +{ + pSessionBus = NULL; + GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( user_data ); + GtkSalMenu* pSalMenu = static_cast< GtkSalMenu* >( pSalFrame->GetMenu() ); + + if ( pSalMenu ) { + MenuBar* pMenuBar = static_cast< MenuBar* >( pSalMenu->GetMenu() ); + + bDBusIsAvailable = sal_False; + pMenuBar->SetDisplayable( sal_True ); + } + + return; +} + +static void ObjectDestroyedNotify( gpointer data ) +{ + if ( data ) { + g_object_unref( data ); + } +} + +void GtkSalFrame::EnsureAppMenuWatch() +{ + if(m_nWatcherId) + return; + GObject* pWindow = G_OBJECT(gtk_widget_get_window( GTK_WIDGET(getWindow()) )); + if(!pWindow) + return; + g_object_set_data_full( + pWindow, + "g-lo-menubar", + G_MENU_MODEL(g_lo_menu_new()), + ObjectDestroyedNotify); + g_object_set_data_full( + pWindow, + "g-lo-action-group", + G_ACTION_GROUP(g_lo_action_group_new( reinterpret_cast<gpointer>(this))), + ObjectDestroyedNotify); + // Publish the menu only if AppMenu registrar is available. + m_nWatcherId = g_bus_watch_name(G_BUS_TYPE_SESSION, + "com.canonical.AppMenu.Registrar", + G_BUS_NAME_WATCHER_FLAGS_NONE, + on_registrar_available, + on_registrar_unavailable, + reinterpret_cast<gpointer>(this), + NULL); +} + +struct DisposeData +{ + GLOActionGroup* m_pActionGroup; + GLOMenu* m_pMenu; + guint m_nActionGroupExportId; + guint m_nMenuExportId; + guint m_nWatcherId; +}; + +static int dispose_menudata(gpointer data) +{ + SolarMutexGuard aGuard; + DisposeData* pDisposeData = reinterpret_cast<DisposeData*>(data); + if(pDisposeData->m_nWatcherId) + g_bus_unwatch_name( pDisposeData->m_nWatcherId ); + if(pSessionBus) + { + //g_dbus_connection_unexport_action_group (pSessionBus, pDisposeData->m_nActionGroupExportId); + //g_dbus_connection_unexport_menu_model (pSessionBus, pDisposeData->m_nMenuExportId); + } + if(pDisposeData->m_pActionGroup) + g_lo_action_group_clear( pDisposeData->m_pActionGroup ); + if(pDisposeData->m_pMenu) + g_lo_menu_remove( pDisposeData->m_pMenu, 0 ); + g_slice_free(DisposeData, pDisposeData); + return FALSE; +} + GtkSalFrame::~GtkSalFrame() { for( unsigned int i = 0; i < SAL_N_ELEMENTS(m_aGraphics); ++i ) @@ -524,8 +700,21 @@ GtkSalFrame::~GtkSalFrame() if( m_pForeignTopLevel ) g_object_unref( G_OBJECT( m_pForeignTopLevel) ); - if ( m_nWatcherId > 0 ) - g_bus_unwatch_name( m_nWatcherId ); + DisposeData* pDisposeData = g_slice_new(DisposeData); + if(m_pWindow) + { + pDisposeData->m_pActionGroup = G_LO_ACTION_GROUP( g_object_get_data( G_OBJECT( m_pWindow ), "g-lo-action-group" ) ); + pDisposeData->m_pMenu = G_LO_MENU( g_object_get_data( G_OBJECT( m_pWindow ), "g-lo-menubar" ) ); + } + else + { + pDisposeData->m_pActionGroup = NULL; + pDisposeData->m_pMenu = NULL; + } + //pDisposeData->m_nActionGroupExportId = mnAGExportId; + //pDisposeData->m_nMenuExportId = mnMenuExportId; + pDisposeData->m_nWatcherId = m_nWatcherId; + g_timeout_add(0, &dispose_menudata, pDisposeData); } void GtkSalFrame::moveWindow( long nX, long nY ) @@ -1286,6 +1475,10 @@ void GtkSalFrame::SetIcon( sal_uInt16 nIcon ) void GtkSalFrame::SetMenu( SalMenu* pSalMenu ) { + if(m_pSalMenu) + { + static_cast<GtkSalMenu*>(m_pSalMenu)->DisconnectFrame(); + } m_pSalMenu = pSalMenu; } @@ -1298,11 +1491,6 @@ void GtkSalFrame::DrawMenuBar() { } -void GtkSalFrame::SetWatcherId( sal_uInt32 watcherId ) -{ - m_nWatcherId = watcherId; -} - void GtkSalFrame::Center() { long nX, nY; diff --git a/vcl/unx/gtk/window/gtksalmenu.cxx b/vcl/unx/gtk/window/gtksalmenu.cxx index 60942a5dc218..bb896feb8d09 100644 --- a/vcl/unx/gtk/window/gtksalmenu.cxx +++ b/vcl/unx/gtk/window/gtksalmenu.cxx @@ -50,6 +50,31 @@ static gchar* GetCommandForSpecialItem( GtkSalMenuItem* pSalMenuItem ) return aCommand; } +// FIXME: Check for missing keys. Maybe translating keycodes would be safer... +rtl::OUString GetGtkKeyName( rtl::OUString keyName ) +{ + rtl::OUString aGtkKeyName(""); + + sal_Int32 nIndex = 0; + + do + { + rtl::OUString token = keyName.getToken( 0, '+', nIndex ); + + if ( token == "Ctrl" ) { + aGtkKeyName += "<Control>"; + } else if ( token == "Alt" ) { + aGtkKeyName += "<Alt>"; + } else if ( token == "Shift" ) { + aGtkKeyName += "<Shift>"; + } else { + aGtkKeyName += token; + } + } while ( nIndex >= 0 ); + + return aGtkKeyName; +} + static void UpdateNativeMenu2( GtkSalMenu *pMenu ) { if ( pMenu == NULL ) @@ -276,141 +301,7 @@ void ObjectDestroyedNotify( gpointer data ) } } -void -gdk_x11_window_set_utf8_property (GdkWindow *window, - const gchar *name, - const gchar *value) -{ - GdkDisplay *display; - - //if (!WINDOW_IS_TOPLEVEL (window)) - //return; - - display = gdk_window_get_display (window); - - if (value != NULL) - { - XChangeProperty (GDK_DISPLAY_XDISPLAY (display), - GDK_WINDOW_XID (window), - gdk_x11_get_xatom_by_name_for_display (display, name), - gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8, - PropModeReplace, (guchar *)value, strlen (value)); - } - else - { - XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), - GDK_WINDOW_XID (window), - gdk_x11_get_xatom_by_name_for_display (display, name)); - } -} - -// FIXME: Check for missing keys. Maybe translating keycodes would be safer... -rtl::OUString GetGtkKeyName( rtl::OUString keyName ) -{ - rtl::OUString aGtkKeyName(""); - - sal_Int32 nIndex = 0; - - do - { - rtl::OUString token = keyName.getToken( 0, '+', nIndex ); - - if ( token == "Ctrl" ) { - aGtkKeyName += "<Control>"; - } else if ( token == "Alt" ) { - aGtkKeyName += "<Alt>"; - } else if ( token == "Shift" ) { - aGtkKeyName += "<Shift>"; - } else { - aGtkKeyName += token; - } - } while ( nIndex >= 0 ); - - return aGtkKeyName; -} - -// AppMenu watch functions. - -static sal_Bool bDBusIsAvailable = sal_False; - -static void -on_registrar_available (GDBusConnection * /*connection*/, - const gchar * /*name*/, - const gchar * /*name_owner*/, - gpointer user_data) -{ - GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( user_data ); - GtkSalMenu* pSalMenu = static_cast< GtkSalMenu* >( pSalFrame->GetMenu() ); - - if ( pSalMenu != NULL ) - { - MenuBar* pMenuBar = static_cast< MenuBar* >( pSalMenu->GetMenu() ); - - GtkWidget *pWidget = pSalFrame->getWindow(); - GdkWindow *gdkWindow = gtk_widget_get_window( pWidget ); - - if ( gdkWindow != NULL ) - { - GMenuModel* pMenuModel = G_MENU_MODEL( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" ) ); - GActionGroup* pActionGroup = G_ACTION_GROUP( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-action-group" ) ); - - XLIB_Window windowId = GDK_WINDOW_XID( gdkWindow ); - - gchar* aDBusPath = g_strdup_printf("/window/%lu", windowId); - gchar* aDBusWindowPath = g_strdup_printf( "/window/%lu", windowId ); - gchar* aDBusMenubarPath = g_strdup_printf( "/window/%lu/menus/menubar", windowId ); - - // Get a DBus session connection. - GDBusConnection* pSessionBus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); - - if( pSessionBus == NULL ) - return; - - // Publish the menu. - if ( aDBusMenubarPath != NULL && pMenuModel != NULL ) - g_dbus_connection_export_menu_model (pSessionBus, aDBusMenubarPath, pMenuModel, NULL); - - if ( aDBusPath != NULL && pActionGroup != NULL ) - g_dbus_connection_export_action_group( pSessionBus, aDBusPath, pActionGroup, NULL); - - // Set window properties. - gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_UNIQUE_BUS_NAME", g_dbus_connection_get_unique_name( pSessionBus ) ); - gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_APPLICATION_OBJECT_PATH", "" ); - gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_WINDOW_OBJECT_PATH", aDBusWindowPath ); - gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_MENUBAR_OBJECT_PATH", aDBusMenubarPath ); - - g_free( aDBusPath ); - g_free( aDBusWindowPath ); - g_free( aDBusMenubarPath ); - - bDBusIsAvailable = sal_True; - - if ( pMenuBar ) - pMenuBar->SetDisplayable( sal_False ); - } - } - - 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) -{ - GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( user_data ); - GtkSalMenu* pSalMenu = static_cast< GtkSalMenu* >( pSalFrame->GetMenu() ); - if ( pSalMenu ) { - MenuBar* pMenuBar = static_cast< MenuBar* >( pSalMenu->GetMenu() ); - - bDBusIsAvailable = sal_False; - pMenuBar->SetDisplayable( sal_True ); - } - - return; -} /* * GtkSalMenu @@ -424,7 +315,10 @@ GtkSalMenu::GtkSalMenu( sal_Bool bMenuBar ) : mpFrame( NULL ), mWatcherId( 0 ), mpMenuModel( NULL ), - mpActionGroup( NULL ) + mpActionGroup( NULL ), + mnMenuExportId( 0 ), + mnAGExportId( 0 ), + mbGdkDisposed( false ) { } @@ -434,14 +328,6 @@ GtkSalMenu::~GtkSalMenu() // g_source_remove_by_user_data( this ); ((GtkSalFrame*) mpFrame)->SetMenu( NULL ); - - if ( mpActionGroup ) { - g_lo_action_group_clear( G_LO_ACTION_GROUP( mpActionGroup ) ); - } - - if ( mpMenuModel ) { - g_lo_menu_remove( G_LO_MENU( mpMenuModel ), 0 ); - } } maItems.clear(); @@ -483,45 +369,31 @@ void GtkSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsig void GtkSalMenu::SetFrame( const SalFrame* pFrame ) { + SolarMutexGuard aGuard; mpFrame = static_cast< const GtkSalFrame* >( pFrame ); - - ( ( GtkSalFrame* ) mpFrame )->SetMenu( this ); - - GtkWidget *widget = GTK_WIDGET( mpFrame->getWindow() ); - - GdkWindow *gdkWindow = gtk_widget_get_window( widget ); - - if ( gdkWindow != NULL ) { - mpMenuModel = G_MENU_MODEL( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" ) ); - mpActionGroup = G_ACTION_GROUP( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-action-group" ) ); - - if ( mpMenuModel == NULL && mpActionGroup == NULL ) { - mpMenuModel = G_MENU_MODEL( g_lo_menu_new() ); - mpActionGroup = G_ACTION_GROUP( g_lo_action_group_new( ( gpointer ) mpFrame ) ); - - g_object_set_data_full( G_OBJECT( gdkWindow ), "g-lo-menubar", mpMenuModel, ObjectDestroyedNotify ); - g_object_set_data_full( G_OBJECT( gdkWindow ), "g-lo-action-group", mpActionGroup, ObjectDestroyedNotify ); - - // Publish the menu only if AppMenu registrar is available. - guint nWatcherId = g_bus_watch_name (G_BUS_TYPE_SESSION, - "com.canonical.AppMenu.Registrar", - G_BUS_NAME_WATCHER_FLAGS_NONE, - on_registrar_available, - on_registrar_unavailable, - (gpointer) mpFrame, - NULL); - - ( ( GtkSalFrame* ) mpFrame )->SetWatcherId( nWatcherId ); - } - - // Generate the main menu structure. - GenerateMenu( this ); -// UpdateNativeMenu2( this ); - - // Refresh the menu every second. - // This code is a workaround until required modifications in Gtk+ are available. -// g_timeout_add_seconds( 1, GenerateMenu, this ); + GtkSalFrame* pFrameNonConst = const_cast<GtkSalFrame*>(mpFrame); + if(pFrameNonConst->GetMenu()) + { + GtkSalMenu* pOldMenu = static_cast< GtkSalMenu*>(pFrameNonConst->GetMenu()); + pOldMenu->DisconnectFrame(); } + pFrameNonConst->SetMenu( this ); + GObject* pWindow = G_OBJECT(gtk_widget_get_window( GTK_WIDGET(pFrameNonConst->getWindow()) )); + if ( !pWindow ) + return; + + // if we had a menu on the GtkSalMenu we have to free it as we generate a + // full menu anyway and we might need to reuse an existing model and + // actiongroup + if(mpMenuModel) + g_lo_menu_remove(G_LO_MENU(mpMenuModel), 0); + if(mpActionGroup) + g_lo_action_group_clear( G_LO_ACTION_GROUP(mpActionGroup) ); + pFrameNonConst->EnsureAppMenuWatch(); + mpMenuModel = G_MENU_MODEL( g_object_get_data( G_OBJECT( pWindow ), "g-lo-menubar" ) ); + mpActionGroup = G_ACTION_GROUP( g_object_get_data( G_OBJECT( pWindow ), "g-lo-action-group" ) ); + // Generate the main menu structure. + GenerateMenu( this ); } const GtkSalFrame* GtkSalMenu::GetFrame() const @@ -534,6 +406,7 @@ const GtkSalFrame* GtkSalMenu::GetFrame() const void GtkSalMenu::NativeCheckItem( unsigned nSection, unsigned nItemPos, MenuItemBits bits, gboolean bCheck ) { + SolarMutexGuard aGuard; if ( mpActionGroup == NULL ) return; @@ -568,6 +441,7 @@ void GtkSalMenu::NativeCheckItem( unsigned nSection, unsigned nItemPos, MenuItem void GtkSalMenu::NativeSetEnableItem( gchar* aCommand, gboolean bEnable ) { + SolarMutexGuard aGuard; GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( mpActionGroup ); if ( g_action_group_get_action_enabled( G_ACTION_GROUP( pActionGroup ), aCommand ) != bEnable ) @@ -576,6 +450,7 @@ void GtkSalMenu::NativeSetEnableItem( gchar* aCommand, gboolean bEnable ) void GtkSalMenu::NativeSetItemText( unsigned nSection, unsigned nItemPos, const rtl::OUString& rText ) { + SolarMutexGuard aGuard; // Replace the '~' character with '_'. rtl::OUString aText = rText.replace( '~', '_' ); rtl::OString aConvertedText = OUStringToOString( aText, RTL_TEXTENCODING_UTF8 ); @@ -592,6 +467,7 @@ void GtkSalMenu::NativeSetItemText( unsigned nSection, unsigned nItemPos, const void GtkSalMenu::NativeSetAccelerator( unsigned nSection, unsigned nItemPos, const KeyCode& rKeyCode, const rtl::OUString& rKeyName ) { + SolarMutexGuard aGuard; if ( rKeyName.isEmpty() ) return; @@ -614,6 +490,7 @@ void GtkSalMenu::NativeSetItemCommand( unsigned nSection, gboolean bChecked, gboolean bIsSubmenu ) { + SolarMutexGuard aGuard; GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( mpActionGroup ); GVariant *pTarget = NULL; @@ -669,6 +546,7 @@ void GtkSalMenu::NativeSetItemCommand( unsigned nSection, GtkSalMenu* GtkSalMenu::GetMenuForItemCommand( gchar* aCommand, gboolean bGetSubmenu ) { + SolarMutexGuard aGuard; GtkSalMenu* pMenu = NULL; for ( sal_uInt16 nPos = 0; nPos < maItems.size(); nPos++ ) @@ -698,6 +576,7 @@ GtkSalMenu* GtkSalMenu::GetMenuForItemCommand( gchar* aCommand, gboolean bGetSub void GtkSalMenu::DispatchCommand( gint itemId, const gchar *aCommand ) { + SolarMutexGuard aGuard; // Only the menubar is allowed to dispatch commands. if ( mbMenuBar != TRUE ) return; @@ -712,6 +591,7 @@ void GtkSalMenu::DispatchCommand( gint itemId, const gchar *aCommand ) void GtkSalMenu::Activate( const gchar* aMenuCommand ) { + SolarMutexGuard aGuard; if ( mbMenuBar != TRUE ) return; @@ -725,6 +605,7 @@ void GtkSalMenu::Activate( const gchar* aMenuCommand ) void GtkSalMenu::Deactivate( const gchar* aMenuCommand ) { + SolarMutexGuard aGuard; if ( mbMenuBar != TRUE ) return; |