[Libreoffice-commits] core.git: 3 commits - include/vcl vcl/inc vcl/source vcl/unx

Caolán McNamara caolanm at redhat.com
Wed May 11 11:09:38 UTC 2016


 include/vcl/taskpanelist.hxx        |    1 
 vcl/inc/salmenu.hxx                 |    3 
 vcl/inc/unx/gtk/gloactiongroup.h    |    2 
 vcl/inc/unx/gtk/gtkframe.hxx        |    1 
 vcl/inc/unx/gtk/gtksalmenu.hxx      |    6 +
 vcl/source/window/menu.cxx          |   21 ++++-
 vcl/source/window/menubarwindow.cxx |    9 ++
 vcl/source/window/taskpanelist.cxx  |    7 +
 vcl/unx/gtk/gloactiongroup.cxx      |    6 -
 vcl/unx/gtk/gtksalframe.cxx         |    2 
 vcl/unx/gtk/gtksalmenu.cxx          |  132 ++++++++++++++++++++++++++++--------
 vcl/unx/gtk3/gtk3gtkframe.cxx       |    2 
 12 files changed, 150 insertions(+), 42 deletions(-)

New commits:
commit 43896bcbea44aa92ee80ee7ba6cb39f5f514c751
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Tue May 10 16:21:17 2016 +0100

    Resolves: tdf#99709 native gtk3 menubar isn't accessible with F6
    
    Change-Id: If772231e824e71c327103e147e3eef69e82339f6

diff --git a/include/vcl/taskpanelist.hxx b/include/vcl/taskpanelist.hxx
index fd04365..e1b908d 100644
--- a/include/vcl/taskpanelist.hxx
+++ b/include/vcl/taskpanelist.hxx
@@ -41,6 +41,7 @@ public:
     void AddWindow( vcl::Window *pWindow );
     void RemoveWindow( vcl::Window *pWindow );
     bool HandleKeyEvent(const KeyEvent& rKeyEvent);
+    static bool IsCycleKey(const vcl::KeyCode& rKeyCode);
 };
 
 #endif
diff --git a/vcl/inc/salmenu.hxx b/vcl/inc/salmenu.hxx
index 6457d9a..a792356 100644
--- a/vcl/inc/salmenu.hxx
+++ b/vcl/inc/salmenu.hxx
@@ -81,6 +81,7 @@ public:
     virtual void Update() {}
 
     virtual bool CanGetFocus() const { return false; }
+    virtual bool TakeFocus() { return false; }
 
     // TODO: implement show/hide for the Win/Mac VCL native backends
     virtual void ShowItem( unsigned nPos, bool bShow ) { EnableItem( nPos, bShow ); }
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 38b6c1b..7c0803b 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -370,6 +370,7 @@ public:
     static GdkDisplay*     getGdkDisplay();
     GtkWidget*  getWindow() const { return m_pWindow; }
     GtkFixed*   getFixedContainer() const { return m_pFixedContainer; }
+    GtkEventBox* getEventBox() const { return m_pEventBox; }
     GtkWidget*  getMouseEventWidget() const;
 #if GTK_CHECK_VERSION(3,0,0)
     GtkGrid*    getTopLevelGridWidget() const { return m_pTopLevelGrid; }
diff --git a/vcl/inc/unx/gtk/gtksalmenu.hxx b/vcl/inc/unx/gtk/gtksalmenu.hxx
index 966b7f8..8469659 100644
--- a/vcl/inc/unx/gtk/gtksalmenu.hxx
+++ b/vcl/inc/unx/gtk/gtksalmenu.hxx
@@ -47,6 +47,8 @@ private:
 
     bool                            mbMenuBar;
     bool                            mbNeedsUpdate;
+    bool                            mbReturnFocusToDocument;
+    GtkWidget*                      mpMenuBarContainerWidget;
     GtkWidget*                      mpMenuBarWidget;
     GtkWidget*                      mpCloseButton;
     Menu*                           mpVCLMenu;
@@ -115,9 +117,13 @@ public:
 
     void CreateMenuBarWidget();
     void DestroyMenuBarWidget();
+    gboolean SignalKey(GdkEventKey* pEvent);
+    void ReturnFocus();
 
     virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, FloatWinPopupFlags nFlags) override;
     virtual void ShowCloseButton(bool bShow) override;
+    virtual bool CanGetFocus() const override;
+    virtual bool TakeFocus() override;
 };
 
 class GtkSalMenuItem : public SalMenuItem
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
index 810525b..096faee 100644
--- a/vcl/source/window/menu.cxx
+++ b/vcl/source/window/menu.cxx
@@ -2597,13 +2597,24 @@ void MenuBar::ImplDestroy( MenuBar* pMenu, bool bDelete )
 
 bool MenuBar::ImplHandleKeyEvent( const KeyEvent& rKEvent )
 {
-    bool bDone = false;
+    // No keyboard processing when our menubar is invisible
+    if (!IsDisplayable())
+        return false;
 
-    // No keyboard processing when system handles the menu or our menubar is invisible
-    if( !IsDisplayable() ||
-        ( ImplGetSalMenu() && ImplGetSalMenu()->VisibleMenuBar() ) )
-        return bDone;
+    // No keyboard processing when system handles the menu.
+    SalMenu *pNativeMenu = ImplGetSalMenu();
+    if (pNativeMenu && pNativeMenu->VisibleMenuBar())
+    {
+        // Except when the event is the F6 cycle pane event and we can put our
+        // focus into it (i.e. the gtk3 menubar case but not the mac/unity case
+        // where its not part of the application window)
+        if (!TaskPaneList::IsCycleKey(rKEvent.GetKeyCode()))
+            return false;
+        if (!pNativeMenu->CanGetFocus())
+            return false;
+    }
 
+    bool bDone = false;
     // check for enabled, if this method is called from another window...
     vcl::Window* pWin = ImplGetWindow();
     if (pWin && pWin->IsEnabled() && pWin->IsInputEnabled()  && !pWin->IsInModalMode())
diff --git a/vcl/source/window/menubarwindow.cxx b/vcl/source/window/menubarwindow.cxx
index ac84120..16d3af5 100644
--- a/vcl/source/window/menubarwindow.cxx
+++ b/vcl/source/window/menubarwindow.cxx
@@ -1078,6 +1078,10 @@ void MenuBarWindow::LoseFocus()
 
 void MenuBarWindow::GetFocus()
 {
+    SalMenu *pNativeMenu = pMenu ? pMenu->ImplGetSalMenu() : nullptr;
+    if (pNativeMenu && pNativeMenu->TakeFocus())
+        return;
+
     if ( nHighlightedItem == ITEMPOS_INVALID )
     {
         mbAutoPopup = false;    // do not open menu when activated by focus handling like taskpane cycling
diff --git a/vcl/source/window/taskpanelist.cxx b/vcl/source/window/taskpanelist.cxx
index 3b9a3d9..4e995a5 100644
--- a/vcl/source/window/taskpanelist.cxx
+++ b/vcl/source/window/taskpanelist.cxx
@@ -146,6 +146,11 @@ bool TaskPaneList::IsInList( vcl::Window *pWindow )
         return false;
 }
 
+bool TaskPaneList::IsCycleKey(const vcl::KeyCode& rKeyCode)
+{
+    return rKeyCode.GetCode() == KEY_F6 && !rKeyCode.IsMod2(); // F6
+}
+
 bool TaskPaneList::HandleKeyEvent(const KeyEvent& rKeyEvent)
 {
 
@@ -160,7 +165,7 @@ bool TaskPaneList::HandleKeyEvent(const KeyEvent& rKeyEvent)
     // and the shortcut conflicts with tab-control shortcut ), it is no more supported
     vcl::KeyCode aKeyCode = rKeyEvent.GetKeyCode();
     bool bForward = !aKeyCode.IsShift();
-    if( aKeyCode.GetCode() == KEY_F6 && ! aKeyCode.IsMod2() ) // F6
+    if (TaskPaneList::IsCycleKey(aKeyCode))
     {
         bool bSplitterOnly = aKeyCode.IsMod1() && aKeyCode.IsShift();
 
diff --git a/vcl/unx/gtk/gtksalmenu.cxx b/vcl/unx/gtk/gtksalmenu.cxx
index 3f1a7fb..4145afa 100644
--- a/vcl/unx/gtk/gtksalmenu.cxx
+++ b/vcl/unx/gtk/gtksalmenu.cxx
@@ -417,6 +417,8 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const Rectangle& rRec
 GtkSalMenu::GtkSalMenu( bool bMenuBar ) :
     mbMenuBar( bMenuBar ),
     mbNeedsUpdate( false ),
+    mbReturnFocusToDocument( false ),
+    mpMenuBarContainerWidget( nullptr ),
     mpMenuBarWidget( nullptr ),
     mpCloseButton( nullptr ),
     mpVCLMenu( nullptr ),
@@ -576,63 +578,139 @@ void GtkSalMenu::ShowCloseButton(bool bShow)
     gtk_widget_set_valign(mpCloseButton, GTK_ALIGN_CENTER);
 
     gtk_container_add(GTK_CONTAINER(mpCloseButton), image);
-    gtk_grid_attach(GTK_GRID(mpMenuBarWidget), GTK_WIDGET(mpCloseButton), 1, 0, 1, 1);
+    gtk_grid_attach(GTK_GRID(mpMenuBarContainerWidget), GTK_WIDGET(mpCloseButton), 1, 0, 1, 1);
     gtk_widget_show_all(mpCloseButton);
 #else
     (void)bShow;
-    (void)mpMenuBarWidget;
+    (void)mpMenuBarContainerWidget;
     (void)mpCloseButton;
 #endif
 }
 
+//Typically when the menubar is deactivated we want the focus to return
+//to where it came from. If the menubar was activated because of F6
+//moving focus into the associated VCL menubar then on pressing ESC
+//or any other normal reason for deactivation we want focus to return
+//to the document, defininitely not still stuck in the associated
+//VCL menubar. But if F6 is pressed while the menubar is activated
+//we want to pass that F6 back to the VCL menubar which will move
+//focus to the next pane by itself.
+void GtkSalMenu::ReturnFocus()
+{
+    if (!mbReturnFocusToDocument)
+        gtk_widget_grab_focus(GTK_WIDGET(mpFrame->getEventBox()));
+    else
+        mpFrame->GetWindow()->GrabFocusToDocument();
+    mbReturnFocusToDocument = false;
+}
+
+gboolean GtkSalMenu::SignalKey(GdkEventKey* pEvent)
+{
+    if (pEvent->keyval == GDK_F6)
+    {
+        mbReturnFocusToDocument = false;
+        gtk_menu_shell_cancel(GTK_MENU_SHELL(mpMenuBarWidget));
+        //because we return false here, the keypress will continue
+        //to propogate and in the case that vcl focus is in
+        //the vcl menubar then that will also process F6 and move
+        //to the next pane
+    }
+    return false;
+}
+
+//The GtkSalMenu is owner by a Vcl Menu/MenuBar. In the menubar
+//case the vcl menubar is present and "visible", but with a 0 height
+//so it not apparent. Normally it acts as though it is not there when
+//a Native menubar is active. If we return true here, then for keyboard
+//activation and traversal with F6 through panes then the vcl menubar
+//acts as though it *is* present and we translate its take focus and F6
+//traversal key events into the gtk menubar equivalents.
+bool GtkSalMenu::CanGetFocus() const
+{
+    return mpMenuBarWidget != nullptr;
+}
+
+bool GtkSalMenu::TakeFocus()
+{
+    if (!mpMenuBarWidget)
+        return false;
+
+    //Send a keyboard event to the gtk menubar to let it know it has been
+    //activated via the keyboard. Doesn't do anything except cause the gtk
+    //menubar "keyboard_mode" member to get set to true, so typically mnemonics
+    //are shown which will serve as indication that the menubar has focus
+    //(given that we wnt to show it with no menus popped down)
+    GdkEvent *event = gdk_event_new(GDK_KEY_PRESS);
+    event->key.window = GDK_WINDOW(g_object_ref(gtk_widget_get_window(mpMenuBarWidget)));
+    event->key.send_event = TRUE;
+    event->key.time = gtk_get_current_event_time();
+    event->key.state = 0;
+    event->key.keyval = 0;
+    event->key.length = 0;
+    event->key.string = nullptr;
+    event->key.hardware_keycode = 0;
+    event->key.group = 0;
+    event->key.is_modifier = false;
+    gtk_widget_event(mpMenuBarWidget, event);
+    gdk_event_free(event);
+
+    //this pairing results in a menubar with keyboard focus with no menus
+    //auto-popped down
+    gtk_menu_shell_select_first(GTK_MENU_SHELL(mpMenuBarWidget), false);
+    gtk_menu_shell_deselect(GTK_MENU_SHELL(mpMenuBarWidget));
+    mbReturnFocusToDocument = true;
+    return true;
+}
+
 #if GTK_CHECK_VERSION(3,0,0)
-//hack-around https://bugzilla.gnome.org/show_bug.cgi?id=762756
-static void ReturnFocus(GtkMenuShell *, gpointer pWidget)
+
+static void MenuBarReturnFocus(GtkMenuShell*, gpointer menu)
 {
-    GtkWidget* pTopLevel = static_cast<GtkWidget*>(pWidget);
-    GdkWindow *window = gtk_widget_get_window(pTopLevel);
-    GdkEvent *fevent = gdk_event_new(GDK_FOCUS_CHANGE);
+    GtkSalMenu* pMenu = static_cast<GtkSalMenu*>(menu);
+    pMenu->ReturnFocus();
+}
 
-    fevent->focus_change.type = GDK_FOCUS_CHANGE;
-    fevent->focus_change.window = GDK_WINDOW(g_object_ref(window));
-    fevent->focus_change.in = static_cast<gint16>(TRUE);
-    gtk_widget_send_focus_change(pTopLevel, fevent);
-    gdk_event_free(fevent);
+static gboolean MenuBarSignalKey(GtkWidget*, GdkEventKey* pEvent, gpointer menu)
+{
+    GtkSalMenu* pMenu = static_cast<GtkSalMenu*>(menu);
+    return pMenu->SignalKey(pEvent);
 }
+
 #endif
 
 void GtkSalMenu::CreateMenuBarWidget()
 {
 #if GTK_CHECK_VERSION(3,0,0)
     GtkGrid* pGrid = mpFrame->getTopLevelGridWidget();
-    mpMenuBarWidget = gtk_grid_new();
+    mpMenuBarContainerWidget = gtk_grid_new();
 
-    gtk_widget_set_hexpand(GTK_WIDGET(mpMenuBarWidget), true);
+    gtk_widget_set_hexpand(GTK_WIDGET(mpMenuBarContainerWidget), true);
     gtk_grid_insert_row(pGrid, 0);
-    gtk_grid_attach(pGrid, mpMenuBarWidget, 0, 0, 1, 1);
+    gtk_grid_attach(pGrid, mpMenuBarContainerWidget, 0, 0, 1, 1);
 
-    GtkWidget *pMenuBarWidget = gtk_menu_bar_new_from_model(mpMenuModel);
-    gtk_widget_insert_action_group(pMenuBarWidget, "win", mpActionGroup);
-    gtk_widget_set_hexpand(GTK_WIDGET(pMenuBarWidget), true);
-    gtk_grid_attach(GTK_GRID(mpMenuBarWidget), pMenuBarWidget, 0, 0, 1, 1);
-    g_signal_connect(G_OBJECT(pMenuBarWidget), "deactivate", G_CALLBACK(ReturnFocus), mpFrame->getWindow());
+    mpMenuBarWidget = gtk_menu_bar_new_from_model(mpMenuModel);
+    gtk_widget_insert_action_group(mpMenuBarWidget, "win", mpActionGroup);
+    gtk_widget_set_hexpand(GTK_WIDGET(mpMenuBarWidget), true);
+    gtk_grid_attach(GTK_GRID(mpMenuBarContainerWidget), mpMenuBarWidget, 0, 0, 1, 1);
+    g_signal_connect(G_OBJECT(mpMenuBarWidget), "deactivate", G_CALLBACK(MenuBarReturnFocus), this);
+    g_signal_connect(G_OBJECT(mpMenuBarWidget), "key-press-event", G_CALLBACK(MenuBarSignalKey), this);
 
-    gtk_widget_show_all(mpMenuBarWidget);
+    gtk_widget_show_all(mpMenuBarContainerWidget);
 #else
-    (void)mpMenuBarWidget;
+    (void)mpMenuBarContainerWidget;
 #endif
 }
 
 void GtkSalMenu::DestroyMenuBarWidget()
 {
 #if GTK_CHECK_VERSION(3,0,0)
-    if (mpMenuBarWidget)
+    if (mpMenuBarContainerWidget)
     {
-        gtk_widget_destroy(mpMenuBarWidget);
-        mpMenuBarWidget = nullptr;
+        gtk_widget_destroy(mpMenuBarContainerWidget);
+        mpMenuBarContainerWidget = nullptr;
     }
 #else
-    (void)mpMenuBarWidget;
+    (void)mpMenuBarContainerWidget;
 #endif
 }
 
commit fac124afd23b23c648900d14c41881dc246f5e0e
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Tue May 10 14:56:54 2016 +0100

    make this cunning more explicit
    
    Change-Id: Ie461646e076da4aa4b144c68e0e08c0424474ad8

diff --git a/vcl/inc/salmenu.hxx b/vcl/inc/salmenu.hxx
index 0145547..6457d9a 100644
--- a/vcl/inc/salmenu.hxx
+++ b/vcl/inc/salmenu.hxx
@@ -80,6 +80,8 @@ public:
     virtual void RemoveMenuBarButton( sal_uInt16 nId );
     virtual void Update() {}
 
+    virtual bool CanGetFocus() const { return false; }
+
     // TODO: implement show/hide for the Win/Mac VCL native backends
     virtual void ShowItem( unsigned nPos, bool bShow ) { EnableItem( nPos, bShow ); }
 
diff --git a/vcl/source/window/menubarwindow.cxx b/vcl/source/window/menubarwindow.cxx
index 4b72e0b..ac84120 100644
--- a/vcl/source/window/menubarwindow.cxx
+++ b/vcl/source/window/menubarwindow.cxx
@@ -1180,10 +1180,13 @@ bool MenuBarWindow::HandleMenuButtonEvent( sal_uInt16 i_nButtonId )
 
 bool MenuBarWindow::CanGetFocus() const
 {
-    /* #i83908# do not use the menubar if it is native and invisible
+    /* #i83908# do not use the menubar if it is native or invisible
        this relies on MenuBar::ImplCreate setting the height of the menubar
        to 0 in this case
     */
+    SalMenu *pNativeMenu = pMenu ? pMenu->ImplGetSalMenu() : nullptr;
+    if (pNativeMenu && pNativeMenu->VisibleMenuBar())
+        return pNativeMenu->CanGetFocus();
     return GetSizePixel().Height() > 0;
 }
 
commit ab30f3367686f37c18a5c11e3621e29e37b11409
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed May 11 10:41:31 2016 +0100

    gtk[3]: the frame argument is now unused
    
    Change-Id: Ib9989545495a8682d7cac97c02ab73d7c622aecf

diff --git a/vcl/inc/unx/gtk/gloactiongroup.h b/vcl/inc/unx/gtk/gloactiongroup.h
index 4fbab01..97d9db8 100644
--- a/vcl/inc/unx/gtk/gloactiongroup.h
+++ b/vcl/inc/unx/gtk/gloactiongroup.h
@@ -42,7 +42,7 @@ struct GLOActionGroupClass
 
 GType               g_lo_action_group_get_type              (void) G_GNUC_CONST;
 
-GLOActionGroup *    g_lo_action_group_new                   (gpointer           frame);
+GLOActionGroup *    g_lo_action_group_new                   (void);
 
 void                g_lo_action_group_set_top_menu          (GLOActionGroup     *group,
                                                              gpointer           top_menu);
diff --git a/vcl/unx/gtk/gloactiongroup.cxx b/vcl/unx/gtk/gloactiongroup.cxx
index 00b0ccc..fe946f0 100644
--- a/vcl/unx/gtk/gloactiongroup.cxx
+++ b/vcl/unx/gtk/gloactiongroup.cxx
@@ -100,7 +100,6 @@ g_lo_action_class_init (GLOActionClass *klass)
 struct GLOActionGroupPrivate
 {
     GHashTable  *table;    /* string -> GLOAction */
-    GtkSalFrame *frame;    /* Frame to which GActionGroup is associated. */
 };
 
 static void g_lo_action_group_iface_init (GActionGroupInterface *);
@@ -318,7 +317,6 @@ g_lo_action_group_init (GLOActionGroup *group)
                                                  GLOActionGroupPrivate);
     group->priv->table = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                   g_free, g_object_unref);
-    group->priv->frame = nullptr;
 }
 
 static void
@@ -341,11 +339,9 @@ g_lo_action_group_iface_init (GActionGroupInterface *iface)
 }
 
 GLOActionGroup *
-g_lo_action_group_new (gpointer frame)
+g_lo_action_group_new()
 {
     GLOActionGroup* group = G_LO_ACTION_GROUP (g_object_new (G_TYPE_LO_ACTION_GROUP, nullptr));
-    group->priv->frame = static_cast< GtkSalFrame* > (frame);
-
     return group;
 }
 
diff --git a/vcl/unx/gtk/gtksalframe.cxx b/vcl/unx/gtk/gtksalframe.cxx
index 7e118f0..83e8836 100644
--- a/vcl/unx/gtk/gtksalframe.cxx
+++ b/vcl/unx/gtk/gtksalframe.cxx
@@ -583,7 +583,7 @@ gboolean ensure_dbus_setup( gpointer data )
 
         // Create menu model and action group attached to this frame.
         GMenuModel* pMenuModel = G_MENU_MODEL( g_lo_menu_new() );
-        GActionGroup* pActionGroup = reinterpret_cast<GActionGroup*>(g_lo_action_group_new( static_cast< gpointer >( pSalFrame ) ));
+        GActionGroup* pActionGroup = reinterpret_cast<GActionGroup*>(g_lo_action_group_new());
 
         // Generate menu paths.
         ::Window windowId = GDK_WINDOW_XID( gdkWindow );
diff --git a/vcl/unx/gtk/gtksalmenu.cxx b/vcl/unx/gtk/gtksalmenu.cxx
index b6deecf..3f1a7fb 100644
--- a/vcl/unx/gtk/gtksalmenu.cxx
+++ b/vcl/unx/gtk/gtksalmenu.cxx
@@ -368,7 +368,7 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const Rectangle& rRec
     Point aPos = FloatingWindow::ImplCalcPos(pWin, rRect, nFlags, nArrangeIndex);
     aPos = FloatingWindow::ImplConvertToAbsPos(xParent, aPos);
 
-    GLOActionGroup* pActionGroup = g_lo_action_group_new(static_cast<gpointer>(mpFrame));
+    GLOActionGroup* pActionGroup = g_lo_action_group_new();
     mpActionGroup = G_ACTION_GROUP(pActionGroup);
     mpMenuModel = G_MENU_MODEL(g_lo_menu_new());
     // Generate the main menu structure, populates mpMenuModel
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
index ada90e7..36754f9 100644
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
@@ -587,7 +587,7 @@ gboolean ensure_dbus_setup( gpointer data )
 
         // Create menu model and action group attached to this frame.
         GMenuModel* pMenuModel = G_MENU_MODEL( g_lo_menu_new() );
-        GActionGroup* pActionGroup = reinterpret_cast<GActionGroup*>(g_lo_action_group_new( static_cast< gpointer >( pSalFrame ) ));
+        GActionGroup* pActionGroup = reinterpret_cast<GActionGroup*>(g_lo_action_group_new());
 
         // Generate menu paths.
         sal_uIntPtr windowId = pSalFrame->GetNativeWindowHandle(pSalFrame->getWindow());


More information about the Libreoffice-commits mailing list