[Libreoffice-commits] core.git: vcl/unx

Caolán McNamara caolanm at redhat.com
Sat Dec 5 12:37:34 PST 2015


 vcl/unx/gtk3/gtk3gtkframe.cxx | 4506 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 4505 insertions(+), 1 deletion(-)

New commits:
commit cd58b8a69ee9c5d5be90852e09f1ca5b5971d54b
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Fri Dec 4 10:51:18 2015 +0000

    gtk3: copy the gtk/gtk3 frame before splitting for the two versions
    
    Change-Id: Iac9f3087fc36fb284a3edd0062cfbaf3580c4097
    Reviewed-on: https://gerrit.libreoffice.org/20393
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
index 26d1a07..66b2d39 100644
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
@@ -5,8 +5,4512 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <unx/gtk/gtkframe.hxx>
+#include <unx/gtk/gtkdata.hxx>
+#include <unx/gtk/gtkinst.hxx>
+#include <unx/gtk/gtkgdi.hxx>
+#include <vcl/help.hxx>
+#include <vcl/keycodes.hxx>
+#include <vcl/layout.hxx>
+#include <unx/wmadaptor.hxx>
+#include <unx/sm.hxx>
+#include <unx/salbmp.h>
+#include <generic/genprn.h>
+#include <generic/geninst.h>
+#include <headless/svpgdi.hxx>
+#include <osl/file.hxx>
+#include <rtl/bootstrap.hxx>
+#include <rtl/process.h>
+#include <vcl/floatwin.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <vcl/settings.hxx>
+
+#if !GTK_CHECK_VERSION(3,0,0)
+#  include <unx/x11/xlimits.hxx>
+#endif
+#if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
+#  include <unx/gtk/gtksalmenu.hxx>
+#endif
+#if defined ENABLE_GMENU_INTEGRATION // defined in gtksalmenu.hxx above
+#  include <unx/gtk/hudawareness.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <prex.h>
+#include <X11/Xatom.h>
+#include <gdk/gdkx.h>
+#include <postx.h>
+
+#include <dlfcn.h>
+#include <vcl/salbtype.hxx>
+#include <impbmp.hxx>
+#include <svids.hrc>
+#include <sal/macros.h>
+
+#include <basegfx/range/b2ibox.hxx>
+#include <basegfx/vector/b2ivector.hxx>
+
+#include <algorithm>
+#include <glib/gprintf.h>
+
+#if OSL_DEBUG_LEVEL > 1
+#  include <cstdio>
+#endif
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+
+#if GTK_CHECK_VERSION(3,0,0)
+#  include <gdk/gdkkeysyms-compat.h>
+#endif
+
+#include <config_folders.h>
+
+#if GTK_CHECK_VERSION(3,0,0)
+#define IS_WIDGET_REALIZED gtk_widget_get_realized
+#define IS_WIDGET_MAPPED   gtk_widget_get_mapped
+#else
+#define IS_WIDGET_REALIZED GTK_WIDGET_REALIZED
+#define IS_WIDGET_MAPPED   GTK_WIDGET_MAPPED
+#endif
+
+#ifndef GDK_IS_X11_DISPLAY
+#define GDK_IS_X11_DISPLAY(foo) (true)
+#endif
+
+
+using namespace com::sun::star;
+
+int GtkSalFrame::m_nFloats = 0;
+
+#if defined ENABLE_GMENU_INTEGRATION
+static GDBusConnection* pSessionBus = nullptr;
+#endif
+
+static sal_uInt16 GetKeyModCode( guint state )
+{
+    sal_uInt16 nCode = 0;
+    if( (state & GDK_SHIFT_MASK) )
+        nCode |= KEY_SHIFT;
+    if( (state & GDK_CONTROL_MASK) )
+        nCode |= KEY_MOD1;
+    if( (state & GDK_MOD1_MASK) )
+        nCode |= KEY_MOD2;
+
+    // Map Meta/Super keys to MOD3 modifier on all Unix systems
+    // except Mac OS X
+    if ( (state & GDK_META_MASK ) || ( state & GDK_SUPER_MASK ) )
+        nCode |= KEY_MOD3;
+    return nCode;
+}
+
+static sal_uInt16 GetMouseModCode( guint state )
+{
+    sal_uInt16 nCode = GetKeyModCode( state );
+    if( (state & GDK_BUTTON1_MASK) )
+        nCode |= MOUSE_LEFT;
+    if( (state & GDK_BUTTON2_MASK) )
+        nCode |= MOUSE_MIDDLE;
+    if( (state & GDK_BUTTON3_MASK) )
+        nCode |= MOUSE_RIGHT;
+
+    return nCode;
+}
+
+static sal_uInt16 GetKeyCode( guint keyval )
+{
+    sal_uInt16 nCode = 0;
+    if( keyval >= GDK_0 && keyval <= GDK_9 )
+        nCode = KEY_0 + (keyval-GDK_0);
+    else if( keyval >= GDK_KP_0 && keyval <= GDK_KP_9 )
+        nCode = KEY_0 + (keyval-GDK_KP_0);
+    else if( keyval >= GDK_A && keyval <= GDK_Z )
+        nCode = KEY_A + (keyval-GDK_A );
+    else if( keyval >= GDK_a && keyval <= GDK_z )
+        nCode = KEY_A + (keyval-GDK_a );
+    else if( keyval >= GDK_F1 && keyval <= GDK_F26 )
+    {
+#if !GTK_CHECK_VERSION(3,0,0)
+        if( GetGtkSalData()->GetGtkDisplay()->IsNumLockFromXS() )
+        {
+            nCode = KEY_F1 + (keyval-GDK_F1);
+        }
+        else
+#endif
+        {
+            switch( keyval )
+            {
+                // - - - - - Sun keyboard, see vcl/unx/source/app/saldisp.cxx
+                case GDK_L2:
+#if !GTK_CHECK_VERSION(3,0,0)
+                    if( GetGtkSalData()->GetGtkDisplay()->GetServerVendor() == vendor_sun )
+                        nCode = KEY_REPEAT;
+                    else
+#endif
+                        nCode = KEY_F12;
+                    break;
+                case GDK_L3:            nCode = KEY_PROPERTIES; break;
+                case GDK_L4:            nCode = KEY_UNDO;       break;
+                case GDK_L6:            nCode = KEY_COPY;       break; // KEY_F16
+                case GDK_L8:            nCode = KEY_PASTE;      break; // KEY_F18
+                case GDK_L10:           nCode = KEY_CUT;        break; // KEY_F20
+                default:
+                    nCode = KEY_F1 + (keyval-GDK_F1);           break;
+            }
+        }
+    }
+    else
+    {
+        switch( keyval )
+        {
+            case GDK_KP_Down:
+            case GDK_Down:          nCode = KEY_DOWN;       break;
+            case GDK_KP_Up:
+            case GDK_Up:            nCode = KEY_UP;         break;
+            case GDK_KP_Left:
+            case GDK_Left:          nCode = KEY_LEFT;       break;
+            case GDK_KP_Right:
+            case GDK_Right:         nCode = KEY_RIGHT;      break;
+            case GDK_KP_Begin:
+            case GDK_KP_Home:
+            case GDK_Begin:
+            case GDK_Home:          nCode = KEY_HOME;       break;
+            case GDK_KP_End:
+            case GDK_End:           nCode = KEY_END;        break;
+            case GDK_KP_Page_Up:
+            case GDK_Page_Up:       nCode = KEY_PAGEUP;     break;
+            case GDK_KP_Page_Down:
+            case GDK_Page_Down:     nCode = KEY_PAGEDOWN;   break;
+            case GDK_KP_Enter:
+            case GDK_Return:        nCode = KEY_RETURN;     break;
+            case GDK_Escape:        nCode = KEY_ESCAPE;     break;
+            case GDK_ISO_Left_Tab:
+            case GDK_KP_Tab:
+            case GDK_Tab:           nCode = KEY_TAB;        break;
+            case GDK_BackSpace:     nCode = KEY_BACKSPACE;  break;
+            case GDK_KP_Space:
+            case GDK_space:         nCode = KEY_SPACE;      break;
+            case GDK_KP_Insert:
+            case GDK_Insert:        nCode = KEY_INSERT;     break;
+            case GDK_KP_Delete:
+            case GDK_Delete:        nCode = KEY_DELETE;     break;
+            case GDK_plus:
+            case GDK_KP_Add:        nCode = KEY_ADD;        break;
+            case GDK_minus:
+            case GDK_KP_Subtract:   nCode = KEY_SUBTRACT;   break;
+            case GDK_asterisk:
+            case GDK_KP_Multiply:   nCode = KEY_MULTIPLY;   break;
+            case GDK_slash:
+            case GDK_KP_Divide:     nCode = KEY_DIVIDE;     break;
+            case GDK_period:        nCode = KEY_POINT;      break;
+            case GDK_decimalpoint:  nCode = KEY_POINT;      break;
+            case GDK_comma:         nCode = KEY_COMMA;      break;
+            case GDK_less:          nCode = KEY_LESS;       break;
+            case GDK_greater:       nCode = KEY_GREATER;    break;
+            case GDK_KP_Equal:
+            case GDK_equal:         nCode = KEY_EQUAL;      break;
+            case GDK_Find:          nCode = KEY_FIND;       break;
+            case GDK_Menu:          nCode = KEY_CONTEXTMENU;break;
+            case GDK_Help:          nCode = KEY_HELP;       break;
+            case GDK_Undo:          nCode = KEY_UNDO;       break;
+            case GDK_Redo:          nCode = KEY_REPEAT;     break;
+            case GDK_KP_Decimal:
+            case GDK_KP_Separator:  nCode = KEY_DECIMAL;    break;
+            case GDK_asciitilde:    nCode = KEY_TILDE;      break;
+            case GDK_leftsinglequotemark:
+            case GDK_quoteleft: nCode = KEY_QUOTELEFT;      break;
+            case GDK_bracketleft:  nCode = KEY_BRACKETLEFT;  break;
+            case GDK_bracketright: nCode = KEY_BRACKETRIGHT; break;
+            case GDK_semicolon:    nCode = KEY_SEMICOLON;   break;
+            case GDK_quoteright:   nCode = KEY_QUOTERIGHT;  break;
+            // some special cases, also see saldisp.cxx
+            // - - - - - - - - - - - - -  Apollo - - - - - - - - - - - - - 0x1000
+            case 0x1000FF02: // apXK_Copy
+                nCode = KEY_COPY;
+                break;
+            case 0x1000FF03: // apXK_Cut
+                nCode = KEY_CUT;
+                break;
+            case 0x1000FF04: // apXK_Paste
+                nCode = KEY_PASTE;
+                break;
+            case 0x1000FF14: // apXK_Repeat
+                nCode = KEY_REPEAT;
+                break;
+            // Exit, Save
+            // - - - - - - - - - - - - - - D E C - - - - - - - - - - - - - 0x1000
+            case 0x1000FF00:
+                nCode = KEY_DELETE;
+                break;
+            // - - - - - - - - - - - - - -  H P  - - - - - - - - - - - - - 0x1000
+            case 0x1000FF73: // hpXK_DeleteChar
+                nCode = KEY_DELETE;
+                break;
+            case 0x1000FF74: // hpXK_BackTab
+            case 0x1000FF75: // hpXK_KP_BackTab
+                nCode = KEY_TAB;
+                break;
+            // - - - - - - - - - - - - - - I B M - - - - - - - - - - - - -
+            // - - - - - - - - - - - - - - O S F - - - - - - - - - - - - - 0x1004
+            case 0x1004FF02: // osfXK_Copy
+                nCode = KEY_COPY;
+                break;
+            case 0x1004FF03: // osfXK_Cut
+                nCode = KEY_CUT;
+                break;
+            case 0x1004FF04: // osfXK_Paste
+                nCode = KEY_PASTE;
+                break;
+            case 0x1004FF07: // osfXK_BackTab
+                nCode = KEY_TAB;
+                break;
+            case 0x1004FF08: // osfXK_BackSpace
+                nCode = KEY_BACKSPACE;
+                break;
+            case 0x1004FF1B: // osfXK_Escape
+                nCode = KEY_ESCAPE;
+                break;
+            // Up, Down, Left, Right, PageUp, PageDown
+            // - - - - - - - - - - - - - - S C O - - - - - - - - - - - - -
+            // - - - - - - - - - - - - - - S G I - - - - - - - - - - - - - 0x1007
+            // - - - - - - - - - - - - - - S N I - - - - - - - - - - - - -
+            // - - - - - - - - - - - - - - S U N - - - - - - - - - - - - - 0x1005
+            case 0x1005FF10: // SunXK_F36
+                nCode = KEY_F11;
+                break;
+            case 0x1005FF11: // SunXK_F37
+                nCode = KEY_F12;
+                break;
+            case 0x1005FF70: // SunXK_Props
+                nCode = KEY_PROPERTIES;
+                break;
+            case 0x1005FF71: // SunXK_Front
+                nCode = KEY_FRONT;
+                break;
+            case 0x1005FF72: // SunXK_Copy
+                nCode = KEY_COPY;
+                break;
+            case 0x1005FF73: // SunXK_Open
+                nCode = KEY_OPEN;
+                break;
+            case 0x1005FF74: // SunXK_Paste
+                nCode = KEY_PASTE;
+                break;
+            case 0x1005FF75: // SunXK_Cut
+                nCode = KEY_CUT;
+                break;
+        }
+    }
+
+    return nCode;
+}
+
+static guint GetKeyValFor(GdkKeymap* pKeyMap, guint16 hardware_keycode, guint8 group)
+{
+    guint updated_keyval = 0;
+    gdk_keymap_translate_keyboard_state(pKeyMap, hardware_keycode,
+        (GdkModifierType)0, group, &updated_keyval, nullptr, nullptr, nullptr);
+    return updated_keyval;
+}
+
+// F10 means either KEY_F10 or KEY_MENU, which has to be decided
+// in the independent part.
+struct KeyAlternate
+{
+    sal_uInt16          nKeyCode;
+    sal_Unicode     nCharCode;
+    KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
+    KeyAlternate( sal_uInt16 nKey, sal_Unicode nChar = 0 ) : nKeyCode( nKey ), nCharCode( nChar ) {}
+};
+
+inline KeyAlternate
+GetAlternateKeyCode( const sal_uInt16 nKeyCode )
+{
+    KeyAlternate aAlternate;
+
+    switch( nKeyCode )
+    {
+        case KEY_F10: aAlternate = KeyAlternate( KEY_MENU );break;
+        case KEY_F24: aAlternate = KeyAlternate( KEY_SUBTRACT, '-' );break;
+    }
+
+    return aAlternate;
+}
+
+#if GTK_CHECK_VERSION(3,0,0)
+
+namespace {
+/// Decouple SalFrame lifetime from damagetracker lifetime
+struct DamageTracker : public basebmp::IBitmapDeviceDamageTracker
+{
+    DamageTracker(GtkSalFrame& rFrame) : m_rFrame(rFrame)
+    {}
+
+    virtual ~DamageTracker() {}
+
+    virtual void damaged(const basegfx::B2IBox& rDamageRect) const override
+    {
+        m_rFrame.damaged(rDamageRect);
+    }
+
+    GtkSalFrame& m_rFrame;
+};
+}
+
+static bool dumpframes = false;
+#endif
+
+void GtkSalFrame::doKeyCallback( guint state,
+                                 guint keyval,
+                                 guint16 hardware_keycode,
+                                 guint8 group,
+                                 guint32 time,
+                                 sal_Unicode aOrigCode,
+                                 bool bDown,
+                                 bool bSendRelease
+                                 )
+{
+    SalKeyEvent aEvent;
+
+    aEvent.mnTime           = time;
+    aEvent.mnCharCode       = aOrigCode;
+    aEvent.mnRepeat         = 0;
+
+    vcl::DeletionListener aDel( this );
+
+#if GTK_CHECK_VERSION(3,0,0)
+#if 0
+    // shift-zero forces a re-draw and event is swallowed
+    if (keyval == GDK_0)
+    {
+        fprintf( stderr, "force widget_queue_draw\n");
+        gtk_widget_queue_draw(GTK_WIDGET(m_pFixedContainer));
+        return;
+    }
+    else if (keyval == GDK_1)
+    {
+        fprintf( stderr, "force repaint all\n");
+        TriggerPaintEvent();
+        return;
+    }
+    else if (keyval == GDK_2)
+    {
+        dumpframes = !dumpframes;
+        fprintf(stderr, "toggle dump frames to %d\n", dumpframes);
+        return;
+    }
+#endif
+#endif
+
+    /*
+     *  #i42122# translate all keys with Ctrl and/or Alt to group 0 else
+     *  shortcuts (e.g. Ctrl-o) will not work but be inserted by the
+     *  application
+     *
+     *  #i52338# do this for all keys that the independent part has no key code
+     *  for
+     *
+     *  fdo#41169 rather than use group 0, detect if there is a group which can
+     *  be used to input Latin text and use that if possible
+     */
+    aEvent.mnCode = GetKeyCode( keyval );
+    if( aEvent.mnCode == 0 )
+    {
+        gint best_group = SAL_MAX_INT32;
+
+        // Try and find Latin layout
+        GdkKeymap* keymap = gdk_keymap_get_default();
+        GdkKeymapKey *keys;
+        gint n_keys;
+        if (gdk_keymap_get_entries_for_keyval(keymap, GDK_A, &keys, &n_keys))
+        {
+            // Find the lowest group that supports Latin layout
+            for (gint i = 0; i < n_keys; ++i)
+            {
+                if (keys[i].level != 0 && keys[i].level != 1)
+                    continue;
+                best_group = std::min(best_group, keys[i].group);
+                if (best_group == 0)
+                    break;
+            }
+            g_free(keys);
+        }
+
+        //Unavailable, go with original group then I suppose
+        if (best_group == SAL_MAX_INT32)
+            best_group = group;
+
+        guint updated_keyval = GetKeyValFor(keymap, hardware_keycode, best_group);
+        aEvent.mnCode = GetKeyCode(updated_keyval);
+    }
+
+    aEvent.mnCode   |= GetKeyModCode( state );
+
+    if( bDown )
+    {
+        bool bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
+        // #i46889# copy AlternateKeyCode handling from generic plugin
+        if( ! bHandled )
+        {
+            KeyAlternate aAlternate = GetAlternateKeyCode( aEvent.mnCode );
+            if( aAlternate.nKeyCode )
+            {
+                aEvent.mnCode = aAlternate.nKeyCode;
+                if( aAlternate.nCharCode )
+                    aEvent.mnCharCode = aAlternate.nCharCode;
+                CallCallback( SALEVENT_KEYINPUT, &aEvent );
+            }
+        }
+        if( bSendRelease && ! aDel.isDeleted() )
+        {
+            CallCallback( SALEVENT_KEYUP, &aEvent );
+        }
+    }
+    else
+        CallCallback( SALEVENT_KEYUP, &aEvent );
+}
+
+GtkSalFrame::GtkSalFrame( SalFrame* pParent, SalFrameStyleFlags nStyle )
+    : m_nXScreen( getDisplay()->GetDefaultXScreen() )
+    , m_pGraphics(nullptr)
+    , m_bGraphics(false)
+{
+    getDisplay()->registerFrame( this );
+    m_bDefaultPos       = true;
+    m_bDefaultSize      = ( (nStyle & SalFrameStyleFlags::SIZEABLE) && ! pParent );
+    m_bWindowIsGtkPlug  = false;
+#if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
+    m_pLastSyncedDbusMenu = nullptr;
+#endif
+    Init( pParent, nStyle );
+}
+
+GtkSalFrame::GtkSalFrame( SystemParentData* pSysData )
+    : m_nXScreen( getDisplay()->GetDefaultXScreen() )
+    , m_pGraphics(nullptr)
+    , m_bGraphics(false)
+{
+    getDisplay()->registerFrame( this );
+    // permanently ignore errors from our unruly children ...
+    GetGenericData()->ErrorTrapPush();
+    m_bDefaultPos       = true;
+    m_bDefaultSize      = true;
+#if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
+    m_pLastSyncedDbusMenu = nullptr;
+#endif
+    Init( pSysData );
+}
+
+#ifdef ENABLE_GMENU_INTEGRATION
+
+static void
+gdk_x11_window_set_utf8_property  (GdkWindow *window,
+                                   const gchar *name,
+                                   const gchar *value)
+{
+#if !GTK_CHECK_VERSION(3,0,0)
+  GdkDisplay* display = gdk_window_get_display (window);
+
+  if (value != nullptr)
+    {
+      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, reinterpret_cast<guchar const *>(value), strlen (value));
+    }
+  else
+    {
+      XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
+                       GDK_WINDOW_XID (window),
+                       gdk_x11_get_xatom_by_name_for_display (display, name));
+    }
+#endif
+}
+
+// AppMenu watch functions.
+
+static void ObjectDestroyedNotify( gpointer data )
+{
+    if ( data ) {
+        g_object_unref( data );
+    }
+}
+
+#if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
+void GtkSalFrame::EnsureDbusMenuSynced()
+{
+    GtkSalMenu* pSalMenu = static_cast<GtkSalMenu*>(GetMenu());
+    if(m_pLastSyncedDbusMenu != pSalMenu) {
+        m_pLastSyncedDbusMenu = pSalMenu;
+        static_cast<GtkSalMenu*>(pSalMenu)->Activate();
+    }
+}
+#endif
+
+static void hud_activated( gboolean hud_active, gpointer user_data )
+{
+    if ( hud_active )
+    {
+        SolarMutexGuard aGuard;
+        GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( user_data );
+        GtkSalMenu* pSalMenu = reinterpret_cast< GtkSalMenu* >( pSalFrame->GetMenu() );
+
+        if ( pSalMenu )
+            pSalMenu->UpdateFull();
+    }
+}
+
+static void activate_uno(GSimpleAction *action, GVariant*, gpointer)
+{
+    uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+
+    uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext );
+
+    uno::Reference < css::frame::XFrame > xFrame(xDesktop->getActiveFrame());
+    if (!xFrame.is())
+        xFrame.set(xDesktop, uno::UNO_QUERY);
+
+    if (!xFrame.is())
+        return;
+
+    uno::Reference< css::frame::XDispatchProvider > xDispatchProvider(xFrame, uno::UNO_QUERY);
+    if (!xDispatchProvider.is())
+        return;
+
+    gchar *strval = nullptr;
+    g_object_get(action, "name", &strval, NULL);
+    if (!strval)
+        return;
+
+    if (strcmp(strval, "New") == 0)
+    {
+        uno::Reference<frame::XModuleManager2> xModuleManager(frame::ModuleManager::create(xContext));
+        OUString aModuleId(xModuleManager->identify(xFrame));
+        if (aModuleId.isEmpty())
+            return;
+
+        comphelper::SequenceAsHashMap lModuleDescription(xModuleManager->getByName(aModuleId));
+        OUString sFactoryService;
+        lModuleDescription[OUString("ooSetupFactoryEmptyDocumentURL")] >>= sFactoryService;
+        if (sFactoryService.isEmpty())
+            return;
+
+        uno::Sequence < css::beans::PropertyValue > args(0);
+        xDesktop->loadComponentFromURL(sFactoryService, "_blank", 0, args);
+        return;
+    }
+
+    OUString sCommand(".uno:");
+    sCommand += OUString(strval, strlen(strval), RTL_TEXTENCODING_UTF8);
+    g_free(strval);
+
+    css::util::URL aCommand;
+    aCommand.Complete = sCommand;
+    uno::Reference< css::util::XURLTransformer > xParser = css::util::URLTransformer::create(xContext);
+    xParser->parseStrict(aCommand);
+
+    uno::Reference< css::frame::XDispatch > xDisp = xDispatchProvider->queryDispatch(aCommand, OUString(), 0);
+
+    if (!xDisp.is())
+        return;
+
+    xDisp->dispatch(aCommand, css::uno::Sequence< css::beans::PropertyValue >());
+}
+
+static const GActionEntry app_entries[] = {
+  { "OptionsTreeDialog", activate_uno, nullptr, nullptr, nullptr, {0} },
+  { "About", activate_uno, nullptr, nullptr, nullptr, {0} },
+  { "HelpIndex", activate_uno, nullptr, nullptr, nullptr, {0} },
+  { "Quit", activate_uno, nullptr, nullptr, nullptr, {0} },
+  { "New", activate_uno, nullptr, nullptr, nullptr, {0} }
+};
+
+gboolean ensure_dbus_setup( gpointer data )
+{
+    GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( data );
+    GdkWindow* gdkWindow = widget_get_window( pSalFrame->getWindow() );
+
+    if ( gdkWindow != nullptr && g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" ) == nullptr )
+    {
+        // Get a DBus session connection.
+        if(!pSessionBus)
+            pSessionBus = g_bus_get_sync (G_BUS_TYPE_SESSION, nullptr, nullptr);
+        if( !pSessionBus )
+        {
+            return FALSE;
+        }
+
+        // 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 ) ));
+
+        // Generate menu paths.
+        ::Window windowId = GDK_WINDOW_XID( gdkWindow );
+        gchar* aDBusWindowPath = g_strdup_printf( "/org/libreoffice/window/%lu", windowId );
+        gchar* aDBusMenubarPath = g_strdup_printf( "/org/libreoffice/window/%lu/menus/menubar", windowId );
+
+        // Set window properties.
+        g_object_set_data_full( G_OBJECT( gdkWindow ), "g-lo-menubar", pMenuModel, ObjectDestroyedNotify );
+        g_object_set_data_full( G_OBJECT( gdkWindow ), "g-lo-action-group", pActionGroup, ObjectDestroyedNotify );
+
+        gdk_x11_window_set_utf8_property( gdkWindow, "_GTK_APPLICATION_ID", "org.libreoffice" );
+        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", "/org/libreoffice" );
+        gdk_x11_window_set_utf8_property( gdkWindow, "_GTK_WINDOW_OBJECT_PATH", aDBusWindowPath );
+        gdk_x11_window_set_utf8_property( gdkWindow, "_GTK_MENUBAR_OBJECT_PATH", aDBusMenubarPath );
+
+        // Publish the menu model and the action group.
+        SAL_INFO("vcl.unity", "exporting menu model at " << pMenuModel << " for window " << windowId);
+        pSalFrame->m_nMenuExportId = g_dbus_connection_export_menu_model (pSessionBus, aDBusMenubarPath, pMenuModel, nullptr);
+        SAL_INFO("vcl.unity", "exporting action group at " << pActionGroup << " for window " << windowId);
+        pSalFrame->m_nActionGroupExportId = g_dbus_connection_export_action_group( pSessionBus, aDBusWindowPath, pActionGroup, nullptr);
+        pSalFrame->m_nHudAwarenessId = hud_awareness_register( pSessionBus, aDBusMenubarPath, hud_activated, pSalFrame, nullptr, nullptr );
+
+        // fdo#70885 we don't want app menu under Unity
+        bool bDesktopIsUnity = (SalGetDesktopEnvironment() == "UNITY");
+
+        if (!bDesktopIsUnity)
+            gdk_x11_window_set_utf8_property( gdkWindow, "_GTK_APP_MENU_OBJECT_PATH", "/org/libreoffice/menus/appmenu" );
+
+        //app menu, to-do translations, block normal menus when active, honor use appmenu settings
+        ResMgr* pMgr = ImplGetResMgr();
+        if( pMgr && !bDesktopIsUnity )
+        {
+            GMenu *menu = g_menu_new ();
+            GMenuItem* item;
+
+            GMenu *firstsubmenu = g_menu_new ();
+
+            OString sNew(OUStringToOString(ResId(SV_BUTTONTEXT_NEW, *pMgr).toString(),
+                RTL_TEXTENCODING_UTF8).replaceFirst("~", "_"));
+
+            item = g_menu_item_new(sNew.getStr(), "app.New");
+            g_menu_append_item( firstsubmenu, item );
+            g_object_unref(item);
+
+            g_menu_append_section( menu, nullptr, G_MENU_MODEL(firstsubmenu));
+            g_object_unref(firstsubmenu);
+
+            GMenu *secondsubmenu = g_menu_new ();
+
+            OString sPreferences(OUStringToOString(ResId(SV_STDTEXT_PREFERENCES, *pMgr).toString(),
+                RTL_TEXTENCODING_UTF8).replaceFirst("~", "_"));
+
+            item = g_menu_item_new(sPreferences.getStr(), "app.OptionsTreeDialog");
+            g_menu_append_item( secondsubmenu, item );
+            g_object_unref(item);
+
+            g_menu_append_section( menu, nullptr, G_MENU_MODEL(secondsubmenu));
+            g_object_unref(secondsubmenu);
+
+            GMenu *thirdsubmenu = g_menu_new ();
+
+            OString sHelp(OUStringToOString(ResId(SV_BUTTONTEXT_HELP, *pMgr).toString(),
+                RTL_TEXTENCODING_UTF8).replaceFirst("~", "_"));
+
+            item = g_menu_item_new(sHelp.getStr(), "app.HelpIndex");
+            g_menu_append_item( thirdsubmenu, item );
+            g_object_unref(item);
+
+            OString sAbout(OUStringToOString(ResId(SV_STDTEXT_ABOUT, *pMgr).toString(),
+                RTL_TEXTENCODING_UTF8).replaceFirst("~", "_"));
+
+            item = g_menu_item_new(sAbout.getStr(), "app.About");
+            g_menu_append_item( thirdsubmenu, item );
+            g_object_unref(item);
+
+            OString sQuit(OUStringToOString(ResId(SV_MENU_MAC_QUITAPP, *pMgr).toString(),
+                RTL_TEXTENCODING_UTF8).replaceFirst("~", "_"));
+
+            item = g_menu_item_new(sQuit.getStr(), "app.Quit");
+            g_menu_append_item( thirdsubmenu, item );
+            g_object_unref(item);
+            g_menu_append_section( menu, nullptr, G_MENU_MODEL(thirdsubmenu));
+            g_object_unref(thirdsubmenu);
+
+            GSimpleActionGroup *group = g_simple_action_group_new ();
+#if GLIB_CHECK_VERSION(2,38,0) // g_simple_action_group_add_entries is deprecated since 2.38
+            g_action_map_add_action_entries (G_ACTION_MAP (group), app_entries, G_N_ELEMENTS (app_entries), nullptr);
+#else
+            g_simple_action_group_add_entries (group, app_entries, G_N_ELEMENTS (app_entries), NULL);
+#endif
+            GActionGroup* pAppActionGroup = G_ACTION_GROUP(group);
+
+            pSalFrame->m_nAppActionGroupExportId = g_dbus_connection_export_action_group( pSessionBus, "/org/libreoffice", pAppActionGroup, nullptr);
+            g_object_unref(pAppActionGroup);
+            pSalFrame->m_nAppMenuExportId = g_dbus_connection_export_menu_model (pSessionBus, "/org/libreoffice/menus/appmenu", G_MENU_MODEL (menu), nullptr);
+            g_object_unref(menu);
+        }
+
+        g_free( aDBusMenubarPath );
+        g_free( aDBusWindowPath );
+    }
+
+    return FALSE;
+}
+
+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 );
+
+    SalMenu* pSalMenu = pSalFrame->GetMenu();
+
+    if ( pSalMenu != nullptr )
+    {
+        GtkSalMenu* pGtkSalMenu = static_cast<GtkSalMenu*>(pSalMenu);
+        pGtkSalMenu->Display( true );
+        pGtkSalMenu->UpdateFull();
+    }
+}
+
+// This is called when the registrar becomes unavailable. It shows the menubar.
+void on_registrar_unavailable( GDBusConnection * /*connection*/,
+                               const gchar     * /*name*/,
+                               gpointer         user_data )
+{
+    SolarMutexGuard aGuard;
+
+    SAL_INFO("vcl.unity", "on_registrar_unavailable");
+
+    //pSessionBus = NULL;
+    GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( user_data );
+
+    SalMenu* pSalMenu = pSalFrame->GetMenu();
+
+    if ( pSalMenu ) {
+        GtkSalMenu* pGtkSalMenu = static_cast< GtkSalMenu* >( pSalMenu );
+        pGtkSalMenu->Display( false );
+    }
+}
+#endif
+
+void GtkSalFrame::EnsureAppMenuWatch()
+{
+#ifdef ENABLE_GMENU_INTEGRATION
+    if ( !m_nWatcherId )
+    {
+        // Get a DBus session connection.
+        if ( pSessionBus == nullptr )
+        {
+            pSessionBus = g_bus_get_sync( G_BUS_TYPE_SESSION, nullptr, nullptr );
+
+            if ( pSessionBus == nullptr )
+                return;
+        }
+
+        // Publish the menu only if AppMenu registrar is available.
+        m_nWatcherId = g_bus_watch_name_on_connection( pSessionBus,
+                                                       "com.canonical.AppMenu.Registrar",
+                                                       G_BUS_NAME_WATCHER_FLAGS_NONE,
+                                                       on_registrar_available,
+                                                       on_registrar_unavailable,
+                                                       static_cast<GtkSalFrame*>(this),
+                                                       nullptr );
+    }
+
+    //ensure_dbus_setup( this );
+#else
+    (void) this; // loplugin:staticmethods
+#endif
+}
+
+void GtkSalFrame::InvalidateGraphics()
+{
+    if( m_pGraphics )
+    {
+#if !GTK_CHECK_VERSION(3,0,0)
+        m_pGraphics->SetDrawable( None, m_nXScreen );
+        m_pGraphics->SetWindow(nullptr);
+#endif
+        m_bGraphics = false;
+    }
+}
+
+GtkSalFrame::~GtkSalFrame()
+{
+    InvalidateGraphics();
+
+    if( m_pParent )
+        m_pParent->m_aChildren.remove( this );
+
+    getDisplay()->deregisterFrame( this );
+
+    if( m_pRegion )
+    {
+#if GTK_CHECK_VERSION(3,0,0)
+        cairo_region_destroy( m_pRegion );
+#else
+        gdk_region_destroy( m_pRegion );
+#endif
+    }
+
+#if !GTK_CHECK_VERSION(3,0,0)
+    if( m_hBackgroundPixmap )
+    {
+        XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
+                                    widget_get_xid(m_pWindow),
+                                    None );
+        XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap );
+    }
+#endif
+
+    delete m_pIMHandler;
+
+    GtkWidget *pEventWidget = getMouseEventWidget();
+    for (auto handler_id : m_aMouseSignalIds)
+        g_signal_handler_disconnect(G_OBJECT(pEventWidget), handler_id);
+    if( m_pFixedContainer )
+        gtk_widget_destroy( GTK_WIDGET( m_pFixedContainer ) );
+    if( m_pEventBox )
+        gtk_widget_destroy( GTK_WIDGET(m_pEventBox) );
+    {
+        SolarMutexGuard aGuard;
+#if defined ENABLE_GMENU_INTEGRATION
+        if(m_nWatcherId)
+            g_bus_unwatch_name(m_nWatcherId);
+#endif
+        if( m_pWindow )
+        {
+            g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", nullptr );
+
+#if defined ENABLE_GMENU_INTEGRATION
+            if ( pSessionBus )
+            {
+                if ( m_nHudAwarenessId )
+                    hud_awareness_unregister( pSessionBus, m_nHudAwarenessId );
+                if ( m_nMenuExportId )
+                    g_dbus_connection_unexport_menu_model( pSessionBus, m_nMenuExportId );
+                if ( m_nAppMenuExportId )
+                    g_dbus_connection_unexport_menu_model( pSessionBus, m_nAppMenuExportId );
+                if ( m_nActionGroupExportId )
+                    g_dbus_connection_unexport_action_group( pSessionBus, m_nActionGroupExportId );
+                if ( m_nAppActionGroupExportId )
+                    g_dbus_connection_unexport_action_group( pSessionBus, m_nAppActionGroupExportId );
+            }
+#endif
+            gtk_widget_destroy( m_pWindow );
+        }
+    }
+    if( m_pForeignParent )
+        g_object_unref( G_OBJECT( m_pForeignParent ) );
+    if( m_pForeignTopLevel )
+        g_object_unref( G_OBJECT( m_pForeignTopLevel) );
+
+    delete m_pGraphics;
+    m_pGraphics = nullptr;
+}
+
+void GtkSalFrame::moveWindow( long nX, long nY )
+{
+    if( isChild( false ) )
+    {
+        if( m_pParent )
+            gtk_fixed_move( m_pParent->getFixedContainer(),
+                            m_pWindow,
+                            nX - m_pParent->maGeometry.nX, nY - m_pParent->maGeometry.nY );
+    }
+    else
+        gtk_window_move( GTK_WINDOW(m_pWindow), nX, nY );
+}
+
+void GtkSalFrame::widget_set_size_request(long nWidth, long nHeight)
+{
+#if !GTK_CHECK_VERSION(3,0,0)
+    gint nOrigwidth, nOrigheight;
+    gtk_window_get_size(GTK_WINDOW(m_pWindow), &nOrigwidth, &nOrigheight);
+    if (nWidth > nOrigwidth || nHeight > nOrigheight)
+    {
+        m_bPaintsBlocked = true;
+    }
+    gtk_widget_set_size_request(m_pWindow, nWidth, nHeight );
+#else
+    gtk_widget_set_size_request(GTK_WIDGET(m_pFixedContainer), nWidth, nHeight );
+#endif
+}
+
+void GtkSalFrame::window_resize(long nWidth, long nHeight)
+{
+#if !GTK_CHECK_VERSION(3,0,0)
+    gint nOrigwidth, nOrigheight;
+    gtk_window_get_size(GTK_WINDOW(m_pWindow), &nOrigwidth, &nOrigheight);
+    if (nWidth > nOrigwidth || nHeight > nOrigheight)
+    {
+        m_bPaintsBlocked = true;
+    }
+#endif
+    gtk_window_resize(GTK_WINDOW(m_pWindow), nWidth, nHeight);
+}
+
+void GtkSalFrame::resizeWindow( long nWidth, long nHeight )
+{
+    if( isChild( false ) )
+    {
+        widget_set_size_request(nWidth, nHeight);
+    }
+    else if( ! isChild( true, false ) )
+        window_resize(nWidth, nHeight);
+}
+
+#if GTK_CHECK_VERSION(3,2,0)
+
+static void
+ooo_fixed_class_init(GtkFixedClass *klass)
+{
+    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+    widget_class->get_accessible = ooo_fixed_get_accessible;
+}
+
+#endif
+
+/*
+ * Always use a sub-class of GtkFixed we can tag for a11y. This allows us to
+ * utilize GAIL for the toplevel window and toolkit implementation incl.
+ * key event listener support ..
+ */
+
+GType
+ooo_fixed_get_type()
+{
+    static GType type = 0;
+
+    if (!type) {
+        static const GTypeInfo tinfo =
+        {
+            sizeof (GtkFixedClass),
+            nullptr,      /* base init */
+            nullptr,  /* base finalize */
+#if GTK_CHECK_VERSION(3,2,0)
+            reinterpret_cast<GClassInitFunc>(ooo_fixed_class_init), /* class init */
+#else
+            nullptr,     /* class init */
+#endif
+            nullptr, /* class finalize */
+            nullptr,                      /* class data */
+            sizeof (GtkFixed),         /* instance size */
+            0,                         /* nb preallocs */
+            nullptr,  /* instance init */
+            nullptr                       /* value table */
+        };
+
+        type = g_type_register_static( GTK_TYPE_FIXED, "OOoFixed",
+                                       &tinfo, (GTypeFlags) 0);
+    }
+
+    return type;
+}
+
+void GtkSalFrame::updateScreenNumber()
+{
+    int nScreen = 0;
+    GdkScreen *pScreen = gtk_widget_get_screen( m_pWindow );
+    if( pScreen )
+        nScreen = getDisplay()->getSystem()->getScreenMonitorIdx( pScreen, maGeometry.nX, maGeometry.nY );
+    maGeometry.nDisplayScreenNumber = nScreen;
+}
+
+GtkWidget *GtkSalFrame::getMouseEventWidget() const
+{
+#if GTK_CHECK_VERSION(3,0,0)
+    return GTK_WIDGET(m_pEventBox);
+#else
+    return m_pWindow;
+#endif
+}
+
+void GtkSalFrame::InitCommon()
+{
+#if GTK_CHECK_VERSION(3,0,0)
+    m_pEventBox = GTK_EVENT_BOX(gtk_event_box_new());
+    gtk_widget_add_events( GTK_WIDGET(m_pEventBox),
+                           GDK_ALL_EVENTS_MASK );
+    gtk_container_add( GTK_CONTAINER(m_pWindow), GTK_WIDGET(m_pEventBox) );
+
+    // add the fixed container child,
+    // fixed is needed since we have to position plugin windows
+    m_pFixedContainer = GTK_FIXED(g_object_new( ooo_fixed_get_type(), nullptr ));
+    gtk_container_add( GTK_CONTAINER(m_pEventBox), GTK_WIDGET(m_pFixedContainer) );
+#else
+    m_pEventBox = nullptr;
+    // add the fixed container child,
+    // fixed is needed since we have to position plugin windows
+    m_pFixedContainer = GTK_FIXED(g_object_new( ooo_fixed_get_type(), nullptr ));
+    gtk_container_add( GTK_CONTAINER(m_pWindow), GTK_WIDGET(m_pFixedContainer) );
+#endif
+
+    GtkWidget *pEventWidget = getMouseEventWidget();
+
+    gtk_widget_set_app_paintable(GTK_WIDGET(m_pFixedContainer), true);
+    /*non-X11 displays won't show anything at all without double-buffering
+      enabled*/
+    if (GDK_IS_X11_DISPLAY(getGdkDisplay()))
+        gtk_widget_set_double_buffered(GTK_WIDGET(m_pFixedContainer), false);
+    gtk_widget_set_redraw_on_allocate(GTK_WIDGET(m_pFixedContainer), false);
+
+
+    // connect signals
+    g_signal_connect( G_OBJECT(m_pWindow), "style-set", G_CALLBACK(signalStyleSet), this );
+    m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "button-press-event", G_CALLBACK(signalButton), this ));
+    m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "motion-notify-event", G_CALLBACK(signalMotion), this ));
+    m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "button-release-event", G_CALLBACK(signalButton), this ));
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect( G_OBJECT(m_pFixedContainer), "draw", G_CALLBACK(signalDraw), this );
+    g_signal_connect( G_OBJECT(m_pFixedContainer), "size-allocate", G_CALLBACK(sizeAllocated), this );
+#if GTK_CHECK_VERSION(3,14,0)
+    GtkGesture *pSwipe = gtk_gesture_swipe_new(pEventWidget);
+    g_signal_connect(pSwipe, "swipe", G_CALLBACK(gestureSwipe), this);
+    gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER (pSwipe), GTK_PHASE_TARGET);
+    g_object_weak_ref(G_OBJECT(pEventWidget), reinterpret_cast<GWeakNotify>(g_object_unref), pSwipe);
+
+    GtkGesture *pLongPress = gtk_gesture_long_press_new(pEventWidget);
+    g_signal_connect(pLongPress, "pressed", G_CALLBACK(gestureLongPress), this);
+    gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER (pLongPress), GTK_PHASE_TARGET);
+    g_object_weak_ref(G_OBJECT(pEventWidget), reinterpret_cast<GWeakNotify>(g_object_unref), pLongPress);
+
+#endif
+
+#else
+    g_signal_connect( G_OBJECT(m_pFixedContainer), "expose-event", G_CALLBACK(signalExpose), this );
+#endif
+    g_signal_connect( G_OBJECT(m_pWindow), "focus-in-event", G_CALLBACK(signalFocus), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "focus-out-event", G_CALLBACK(signalFocus), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "map-event", G_CALLBACK(signalMap), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "unmap-event", G_CALLBACK(signalUnmap), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "configure-event", G_CALLBACK(signalConfigure), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "key-press-event", G_CALLBACK(signalKey), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "key-release-event", G_CALLBACK(signalKey), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "delete-event", G_CALLBACK(signalDelete), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "window-state-event", G_CALLBACK(signalWindowState), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "scroll-event", G_CALLBACK(signalScroll), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "leave-notify-event", G_CALLBACK(signalCrossing), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "enter-notify-event", G_CALLBACK(signalCrossing), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "visibility-notify-event", G_CALLBACK(signalVisibility), this );
+    g_signal_connect( G_OBJECT(m_pWindow), "destroy", G_CALLBACK(signalDestroy), this );
+
+    // init members
+    m_pCurrentCursor    = nullptr;
+    m_nKeyModifiers     = 0;
+    m_bFullscreen       = false;
+    m_bSpanMonitorsWhenFullscreen = false;
+    m_nState            = GDK_WINDOW_STATE_WITHDRAWN;
+    m_nVisibility       = GDK_VISIBILITY_FULLY_OBSCURED;
+    m_bSendModChangeOnRelease = false;
+    m_pIMHandler        = nullptr;
+    m_hBackgroundPixmap = None;
+    m_nExtStyle         = 0;
+    m_pRegion           = nullptr;
+    m_ePointerStyle     = static_cast<PointerStyle>(0xffff);
+    m_bSetFocusOnMap    = false;
+    m_pSalMenu          = nullptr;
+    m_nWatcherId        = 0;
+    m_nMenuExportId     = 0;
+    m_nAppMenuExportId  = 0;
+    m_nActionGroupExportId = 0;
+    m_nAppActionGroupExportId = 0;
+    m_nHudAwarenessId   = 0;
+
+    gtk_widget_add_events( m_pWindow,
+                           GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+                           GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
+                           GDK_VISIBILITY_NOTIFY_MASK | GDK_SCROLL_MASK
+                           );
+
+    // show the widgets
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_widget_show_all( GTK_WIDGET(m_pEventBox) );
+#else
+    gtk_widget_show_all( GTK_WIDGET(m_pFixedContainer) );
+#endif
+
+    // realize the window, we need an XWindow id
+    gtk_widget_realize( m_pWindow );
+
+    //system data
+    m_aSystemData.nSize         = sizeof( SystemEnvData );
+#if !GTK_CHECK_VERSION(3,0,0)
+    GtkSalDisplay* pDisp = GetGtkSalData()->GetGtkDisplay();
+    m_aSystemData.pDisplay      = pDisp->GetDisplay();
+    m_aSystemData.pVisual       = pDisp->GetVisual( m_nXScreen ).GetVisual();
+    m_aSystemData.nDepth        = pDisp->GetVisual( m_nXScreen ).GetDepth();
+    m_aSystemData.aColormap     = pDisp->GetColormap( m_nXScreen ).GetXColormap();
+    m_aSystemData.aWindow       = widget_get_xid(m_pWindow);
+    m_aSystemData.aShellWindow  = m_aSystemData.aWindow;
+#else
+    static int nWindow = 0;
+    m_aSystemData.aWindow       = nWindow;
+    m_aSystemData.aShellWindow  = nWindow;
+    ++nWindow;
+#endif
+    m_aSystemData.pSalFrame     = this;
+    m_aSystemData.pWidget       = m_pWindow;
+    m_aSystemData.nScreen       = m_nXScreen.getXScreen();
+    m_aSystemData.pAppContext   = nullptr;
+    m_aSystemData.pShellWidget  = m_aSystemData.pWidget;
+
+    m_bGraphics = false;
+    m_pGraphics = nullptr;
+
+    // fake an initial geometry, gets updated via configure event or SetPosSize
+    if( m_bDefaultPos || m_bDefaultSize )
+    {
+        Size aDefSize = calcDefaultSize();
+        maGeometry.nX                   = -1;
+        maGeometry.nY                   = -1;
+        maGeometry.nWidth               = aDefSize.Width();
+        maGeometry.nHeight              = aDefSize.Height();
+        if( m_pParent )
+        {
+            // approximation
+            maGeometry.nTopDecoration       = m_pParent->maGeometry.nTopDecoration;
+            maGeometry.nBottomDecoration    = m_pParent->maGeometry.nBottomDecoration;
+            maGeometry.nLeftDecoration      = m_pParent->maGeometry.nLeftDecoration;
+            maGeometry.nRightDecoration     = m_pParent->maGeometry.nRightDecoration;
+        }
+        else
+        {
+            maGeometry.nTopDecoration       = 0;
+            maGeometry.nBottomDecoration    = 0;
+            maGeometry.nLeftDecoration      = 0;
+            maGeometry.nRightDecoration     = 0;
+        }
+    }
+    else
+    {
+        resizeWindow( maGeometry.nWidth, maGeometry.nHeight );
+        moveWindow( maGeometry.nX, maGeometry.nY );
+    }
+    updateScreenNumber();
+
+    SetIcon(1);
+
+#if !GTK_CHECK_VERSION(3,0,0)
+    m_nWorkArea = pDisp->getWMAdaptor()->getCurrentWorkArea();
+    /* #i64117# gtk sets a nice background pixmap
+    *  but we actually don't really want that, so save
+    *  some time on the Xserver as well as prevent
+    *  some paint issues
+    */
+    XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
+                                widget_get_xid(m_pWindow),
+                                m_hBackgroundPixmap );
+#endif
+}
+
+/*  Sadly gtk_window_set_accept_focus exists only since gtk 2.4
+ *  for achieving the same effect we will remove the WM_TAKE_FOCUS
+ *  protocol from the window and set the input hint to false.
+ *  But gtk_window_set_accept_focus needs to be called before
+ *  window realization whereas the removal obviously can only happen
+ *  after realization.
  */
 
-#include "../gtk/gtksalframe.cxx"
+#if !GTK_CHECK_VERSION(3,0,0)
+extern "C" {
+    typedef void(*setAcceptFn)( GtkWindow*, gboolean );
+    static setAcceptFn p_gtk_window_set_accept_focus = nullptr;
+    static bool bGetAcceptFocusFn = true;
+
+    typedef void(*setUserTimeFn)( GdkWindow*, guint32 );
+    static setUserTimeFn p_gdk_x11_window_set_user_time = nullptr;
+    static bool bGetSetUserTimeFn = true;
+}
+#endif
+
+static void lcl_set_accept_focus( GtkWindow* pWindow, gboolean bAccept, bool bBeforeRealize )
+{
+#if !GTK_CHECK_VERSION(3,0,0)
+    if( bGetAcceptFocusFn )
+    {
+        bGetAcceptFocusFn = false;
+        p_gtk_window_set_accept_focus = reinterpret_cast<setAcceptFn>(osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_window_set_accept_focus" ));
+    }
+    if( p_gtk_window_set_accept_focus && bBeforeRealize )
+        p_gtk_window_set_accept_focus( pWindow, bAccept );
+    else if( ! bBeforeRealize )
+    {
+        Display* pDisplay = GetGtkSalData()->GetGtkDisplay()->GetDisplay();
+        ::Window aWindow = widget_get_xid(GTK_WIDGET(pWindow));
+        XWMHints* pHints = XGetWMHints( pDisplay, aWindow );
+        if( ! pHints )
+        {
+            pHints = XAllocWMHints();
+            pHints->flags = 0;
+        }
+        pHints->flags |= InputHint;
+        pHints->input = bAccept ? True : False;
+        XSetWMHints( pDisplay, aWindow, pHints );
+        XFree( pHints );
+
+        if (GetGtkSalData()->GetGtkDisplay()->getWMAdaptor()->getWindowManagerName() == "compiz")
+            return;
+
+        /*  remove WM_TAKE_FOCUS protocol; this would usually be the
+         *  right thing, but gtk handles it internally whereas we
+         *  want to handle it ourselves (as to sometimes not get
+         *  the focus)
+         */
+        Atom* pProtocols = nullptr;
+        int nProtocols = 0;
+        XGetWMProtocols( pDisplay,
+                         aWindow,
+                         &pProtocols, &nProtocols );
+        if( pProtocols )
+        {
+            bool bSet = false;
+            Atom nTakeFocus = XInternAtom( pDisplay, "WM_TAKE_FOCUS", True );
+            if( nTakeFocus )
+            {
+                for( int i = 0; i < nProtocols; i++ )
+                {
+                    if( pProtocols[i] == nTakeFocus )
+                    {
+                        for( int n = i; n < nProtocols-1; n++ )
+                            pProtocols[n] = pProtocols[n+1];
+                        nProtocols--;
+                        i--;
+                        bSet = true;
+                    }
+                }
+            }
+            if( bSet )
+                XSetWMProtocols( pDisplay, aWindow, pProtocols, nProtocols );
+            XFree( pProtocols );
+        }
+    }
+#else
+    gtk_window_set_accept_focus(pWindow, bAccept);
+    (void)bBeforeRealize;
+#endif
+}
+
+#if !GTK_CHECK_VERSION(3,0,0)
+static void lcl_set_user_time( GtkWindow* i_pWindow, guint32 i_nTime )
+{
+    if( bGetSetUserTimeFn )
+    {
+        bGetSetUserTimeFn = false;
+        p_gdk_x11_window_set_user_time = reinterpret_cast<setUserTimeFn>(osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_x11_window_set_user_time" ));
+    }
+    bool bSet = false;
+    if( p_gdk_x11_window_set_user_time )
+    {
+        GdkWindow* pWin = widget_get_window(GTK_WIDGET(i_pWindow));
+        if( pWin ) // only if the window is realized.
+        {
+            p_gdk_x11_window_set_user_time( pWin, i_nTime );
+            bSet = true;
+        }
+    }
+    if( !bSet )
+    {
+        Display* pDisplay = GetGtkSalData()->GetGtkDisplay()->GetDisplay();
+        Atom nUserTime = XInternAtom( pDisplay, "_NET_WM_USER_TIME", True );
+        if( nUserTime )
+        {
+            XChangeProperty( pDisplay, widget_get_xid(GTK_WIDGET(i_pWindow)),
+                             nUserTime, XA_CARDINAL, 32,
+                             PropModeReplace, reinterpret_cast<unsigned char*>(&i_nTime), 1 );
+        }
+    }
+};
+#endif
+
+GtkSalFrame *GtkSalFrame::getFromWindow( GtkWindow *pWindow )
+{
+    return static_cast<GtkSalFrame *>(g_object_get_data( G_OBJECT( pWindow ), "SalFrame" ));
+}
+
+void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle )
+{
+    if( nStyle & SalFrameStyleFlags::DEFAULT ) // ensure default style
+    {
+        nStyle |= SalFrameStyleFlags::MOVEABLE | SalFrameStyleFlags::SIZEABLE | SalFrameStyleFlags::CLOSEABLE;
+        nStyle &= ~SalFrameStyleFlags::FLOAT;
+    }
+
+    m_pParent = static_cast<GtkSalFrame*>(pParent);
+    m_pForeignParent = nullptr;
+    m_aForeignParentWindow = None;
+    m_pForeignTopLevel = nullptr;
+    m_aForeignTopLevelWindow = None;
+    m_nStyle = nStyle;
+
+    GtkWindowType eWinType = (  (nStyle & SalFrameStyleFlags::FLOAT) &&
+                              ! (nStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION|
+                                           SalFrameStyleFlags::FLOAT_FOCUSABLE))
+                              )
+        ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL;
+
+    if( nStyle & SalFrameStyleFlags::SYSTEMCHILD )
+    {
+        m_pWindow = gtk_event_box_new();
+        if( m_pParent )
+        {
+            // insert into container
+            gtk_fixed_put( m_pParent->getFixedContainer(),
+                           m_pWindow, 0, 0 );
+
+        }
+    }
+    else
+    {
+        m_pWindow = gtk_widget_new( GTK_TYPE_WINDOW, "type", eWinType,
+                                    "visible", FALSE, NULL );
+    }
+    g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", this );
+    g_object_set_data( G_OBJECT( m_pWindow ), "libo-version", const_cast<char *>(LIBO_VERSION_DOTTED));
+
+    // force wm class hint
+    m_nExtStyle = ~0;
+    if (m_pParent)
+        m_sWMClass = m_pParent->m_sWMClass;
+    SetExtendedFrameStyle( 0 );
+
+    if( m_pParent && m_pParent->m_pWindow && ! isChild() )
+        gtk_window_set_screen( GTK_WINDOW(m_pWindow), gtk_window_get_screen( GTK_WINDOW(m_pParent->m_pWindow) ) );
+
+    if (m_pParent)
+    {
+        if (!(m_pParent->m_nStyle & SalFrameStyleFlags::PLUG))
+            gtk_window_set_transient_for( GTK_WINDOW(m_pWindow), GTK_WINDOW(m_pParent->m_pWindow) );
+        m_pParent->m_aChildren.push_back( this );
+    }
+
+    InitCommon();
+
+    // set window type
+    bool bDecoHandling =
+        ! isChild() &&
+        ( ! (nStyle & SalFrameStyleFlags::FLOAT) ||
+          (nStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION|SalFrameStyleFlags::FLOAT_FOCUSABLE) ) );
+
+    if( bDecoHandling )
+    {
+        GdkWindowTypeHint eType = GDK_WINDOW_TYPE_HINT_NORMAL;
+        if( (nStyle & SalFrameStyleFlags::DIALOG) && m_pParent != nullptr )
+            eType = GDK_WINDOW_TYPE_HINT_DIALOG;
+        if( (nStyle & SalFrameStyleFlags::INTRO) )
+        {
+            gtk_window_set_role( GTK_WINDOW(m_pWindow), "splashscreen" );
+            eType = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN;
+        }
+        else if( (nStyle & SalFrameStyleFlags::TOOLWINDOW ) )
+        {
+            eType = GDK_WINDOW_TYPE_HINT_UTILITY;
+            gtk_window_set_skip_taskbar_hint( GTK_WINDOW(m_pWindow), true );
+        }
+        else if( (nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) )
+        {
+            eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
+            lcl_set_accept_focus( GTK_WINDOW(m_pWindow), false, true );
+        }
+        else if( (nStyle & SalFrameStyleFlags::FLOAT_FOCUSABLE) )
+        {
+            eType = GDK_WINDOW_TYPE_HINT_UTILITY;
+        }
+#if !GTK_CHECK_VERSION(3,0,0)
+        if( (nStyle & SalFrameStyleFlags::PARTIAL_FULLSCREEN )
+            && getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+        {
+            eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
+            gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), true );
+        }
+#endif
+        gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), eType );
+        gtk_window_set_gravity( GTK_WINDOW(m_pWindow), GDK_GRAVITY_STATIC );
+    }
+    else if( (nStyle & SalFrameStyleFlags::FLOAT) )
+        gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), GDK_WINDOW_TYPE_HINT_POPUP_MENU );
+
+    if( eWinType == GTK_WINDOW_TOPLEVEL )
+    {
+#ifdef ENABLE_GMENU_INTEGRATION
+        // Enable DBus native menu if available.
+        ensure_dbus_setup( this );
+#endif
+
+#if !GTK_CHECK_VERSION(3,0,0)
+        guint32 nUserTime = 0;
+        if( (nStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION|SalFrameStyleFlags::TOOLWINDOW)) == SalFrameStyleFlags::NONE )
+        {
+            nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
+        }
+        lcl_set_user_time(GTK_WINDOW(m_pWindow), nUserTime);
+#endif
+    }
+
+    if( bDecoHandling )
+    {
+        gtk_window_set_resizable( GTK_WINDOW(m_pWindow), bool(nStyle & SalFrameStyleFlags::SIZEABLE) );
+        if( ( (nStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION)) ) )
+            lcl_set_accept_focus( GTK_WINDOW(m_pWindow), false, false );
+    }
+}
+
+GdkNativeWindow GtkSalFrame::findTopLevelSystemWindow( GdkNativeWindow aWindow )
+{
+#if !GTK_CHECK_VERSION(3,0,0)
+    ::Window aRoot, aParent;
+    ::Window* pChildren;
+    unsigned int nChildren;
+    bool bBreak = false;
+    do
+    {
+        pChildren = nullptr;
+        nChildren = 0;
+        aParent = aRoot = None;
+        XQueryTree( getDisplay()->GetDisplay(), aWindow,
+                    &aRoot, &aParent, &pChildren, &nChildren );
+        XFree( pChildren );
+        if( aParent != aRoot )
+            aWindow = aParent;
+        int nCount = 0;
+        Atom* pProps = XListProperties( getDisplay()->GetDisplay(),
+                                        aWindow,
+                                        &nCount );
+        for( int i = 0; i < nCount && ! bBreak; ++i )
+            bBreak = (pProps[i] == XA_WM_HINTS);
+        if( pProps )
+            XFree( pProps );
+    } while( aParent != aRoot && ! bBreak );
+
+    return aWindow;
+#else
+    (void)aWindow;
+    //FIXME: no findToplevelSystemWindow
+    return 0;
+#endif
+}
+
+void GtkSalFrame::Init( SystemParentData* pSysData )
+{
+    m_pParent = nullptr;
+    m_aForeignParentWindow = (GdkNativeWindow)pSysData->aWindow;
+    m_pForeignParent = nullptr;
+    m_aForeignTopLevelWindow = findTopLevelSystemWindow( (GdkNativeWindow)pSysData->aWindow );
+    m_pForeignTopLevel = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignTopLevelWindow );
+    gdk_window_set_events( m_pForeignTopLevel, GDK_STRUCTURE_MASK );
+
+    if( pSysData->nSize > sizeof(pSysData->nSize)+sizeof(pSysData->aWindow) && pSysData->bXEmbedSupport )
+    {
+#if GTK_CHECK_VERSION(3,0,0)
+        m_pWindow = gtk_plug_new_for_display( getGdkDisplay(), pSysData->aWindow );
+#else
+        m_pWindow = gtk_plug_new( pSysData->aWindow );
+#endif
+        m_bWindowIsGtkPlug  = true;
+        widget_set_can_default( m_pWindow, true );
+        widget_set_can_focus( m_pWindow, true );
+        gtk_widget_set_sensitive( m_pWindow, true );
+    }
+    else
+    {
+        m_pWindow = gtk_window_new( GTK_WINDOW_POPUP );
+        m_bWindowIsGtkPlug  = false;
+    }
+    m_nStyle = SalFrameStyleFlags::PLUG;
+    InitCommon();
+
+    m_pForeignParent = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignParentWindow );
+    gdk_window_set_events( m_pForeignParent, GDK_STRUCTURE_MASK );
+
+#if !GTK_CHECK_VERSION(3,0,0)
+    int x_ret, y_ret;
+    unsigned int w, h, bw, d;
+    ::Window aRoot;
+    XGetGeometry( getDisplay()->GetDisplay(), pSysData->aWindow,
+                  &aRoot, &x_ret, &y_ret, &w, &h, &bw, &d );
+    maGeometry.nWidth   = w;
+    maGeometry.nHeight  = h;
+    window_resize(w, h);
+    gtk_window_move( GTK_WINDOW(m_pWindow), 0, 0 );
+    if( ! m_bWindowIsGtkPlug )
+    {
+        XReparentWindow( getDisplay()->GetDisplay(),
+                         widget_get_xid(m_pWindow),
+                         (::Window)pSysData->aWindow,
+                         0, 0 );
+    }
+#else
+    //FIXME: Handling embedded windows, is going to be fun ...
+#endif
+}
+
+void GtkSalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
+{
+#if !GTK_CHECK_VERSION(3,0,0)
+    XEvent aEvent;
+
+    memset( &aEvent, 0, sizeof(aEvent) );
+    aEvent.xclient.window = m_aForeignParentWindow;
+    aEvent.xclient.type = ClientMessage;
+    aEvent.xclient.message_type = getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED );
+    aEvent.xclient.format = 32;
+    aEvent.xclient.data.l[0] = i_nTimeCode ? i_nTimeCode : CurrentTime;
+    aEvent.xclient.data.l[1] = 3; // XEMBED_REQUEST_FOCUS
+    aEvent.xclient.data.l[2] = 0;
+    aEvent.xclient.data.l[3] = 0;
+    aEvent.xclient.data.l[4] = 0;
+
+    GetGenericData()->ErrorTrapPush();
+    XSendEvent( getDisplay()->GetDisplay(),
+                m_aForeignParentWindow,
+                False, NoEventMask, &aEvent );
+    GetGenericData()->ErrorTrapPop();
+#else
+    (void) this; // loplugin:staticmethods
+    (void)i_nTimeCode;
+    //FIXME: no askForXEmbedFocus for gtk3 yet
+#endif
+}
+
+void GtkSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
+{
+    if( nStyle != m_nExtStyle && ! isChild() )
+    {
+        m_nExtStyle = nStyle;
+        updateWMClass();
+    }
+}
+
+SalGraphics* GtkSalFrame::AcquireGraphics()
+{
+    if( m_bGraphics )
+        return nullptr;
+
+    if( !m_pGraphics )
+    {
+#if GTK_CHECK_VERSION(3,0,0)
+        m_pGraphics = new GtkSalGraphics( this, m_pWindow );
+        if( !m_aFrame.get() )
+        {
+            AllocateFrame();
+            TriggerPaintEvent();
+        }
+        m_pGraphics->setDevice( m_aFrame );
+#else // common case:
+        m_pGraphics = new GtkSalGraphics( this, m_pWindow, m_nXScreen );
+#endif
+    }
+    m_bGraphics = true;
+    return m_pGraphics;
+}
+
+void GtkSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
+{
+    (void) pGraphics;
+    assert( pGraphics == m_pGraphics );
+    m_bGraphics = false;
+}
+
+bool GtkSalFrame::PostEvent(ImplSVEvent* pData)
+{
+    getDisplay()->SendInternalEvent( this, pData );
+    return true;
+}
+
+void GtkSalFrame::SetTitle( const OUString& rTitle )
+{
+    m_aTitle = rTitle;
+    if( m_pWindow && ! isChild() )
+        gtk_window_set_title( GTK_WINDOW(m_pWindow), OUStringToOString( rTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
+}
+
+void GtkSalFrame::SetIcon( sal_uInt16 nIcon )
+{
+    if( (m_nStyle & (SalFrameStyleFlags::PLUG|SalFrameStyleFlags::SYSTEMCHILD|SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::INTRO|SalFrameStyleFlags::OWNERDRAWDECORATION))
+        || ! m_pWindow )
+        return;
+
+    gchar* appicon;
+
+    if (nIcon == SV_ICON_ID_TEXT)
+        appicon = g_strdup ("libreoffice-writer");
+    else if (nIcon == SV_ICON_ID_SPREADSHEET)
+        appicon = g_strdup ("libreoffice-calc");
+    else if (nIcon == SV_ICON_ID_DRAWING)
+        appicon = g_strdup ("libreoffice-draw");
+    else if (nIcon == SV_ICON_ID_PRESENTATION)
+        appicon = g_strdup ("libreoffice-impress");
+    else if (nIcon == SV_ICON_ID_DATABASE)
+        appicon = g_strdup ("libreoffice-base");
+    else if (nIcon == SV_ICON_ID_FORMULA)
+        appicon = g_strdup ("libreoffice-math");
+    else
+        appicon = g_strdup ("libreoffice-main");
+
+    gtk_window_set_icon_name (GTK_WINDOW (m_pWindow), appicon);
+}
+
+void GtkSalFrame::SetMenu( SalMenu* pSalMenu )
+{
+//    if(m_pSalMenu)
+//    {
+//        static_cast<GtkSalMenu*>(m_pSalMenu)->DisconnectFrame();
+//    }
+    m_pSalMenu = pSalMenu;
+}
+
+SalMenu* GtkSalFrame::GetMenu()
+{
+    return m_pSalMenu;
+}
+
+void GtkSalFrame::DrawMenuBar()
+{
+}
+
+void GtkSalFrame::Center()
+{
+    long nX, nY;
+
+    if( m_pParent )
+    {
+        nX = ((long)m_pParent->maGeometry.nWidth - (long)maGeometry.nWidth)/2;
+        nY = ((long)m_pParent->maGeometry.nHeight - (long)maGeometry.nHeight)/2;
+    }
+    else
+    {
+        GdkScreen *pScreen = nullptr;
+        gint px, py;
+        GdkModifierType nMask;
+        gdk_display_get_pointer( getGdkDisplay(), &pScreen, &px, &py, &nMask );
+        if( !pScreen )
+            pScreen = gtk_widget_get_screen( m_pWindow );
+
+        gint nMonitor;
+        nMonitor = gdk_screen_get_monitor_at_point( pScreen, px, py );
+
+        GdkRectangle aMonitor;
+        gdk_screen_get_monitor_geometry( pScreen, nMonitor, &aMonitor );
+
+        nX = aMonitor.x + (aMonitor.width - (long)maGeometry.nWidth)/2;
+        nY = aMonitor.y + (aMonitor.height - (long)maGeometry.nHeight)/2;
+    }
+    SetPosSize( nX, nY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
+}
+
+Size GtkSalFrame::calcDefaultSize()
+{
+    return bestmaxFrameSizeForScreenSize(getDisplay()->GetScreenSize(GetDisplayScreen()));
+}
+
+void GtkSalFrame::SetDefaultSize()
+{
+    Size aDefSize = calcDefaultSize();
+
+    SetPosSize( 0, 0, aDefSize.Width(), aDefSize.Height(),
+                SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+
+    if( (m_nStyle & SalFrameStyleFlags::DEFAULT) && m_pWindow )
+        gtk_window_maximize( GTK_WINDOW(m_pWindow) );
+}
+
+static void initClientId()
+{
+#if !GTK_CHECK_VERSION(3,0,0)
+    static bool bOnce = false;
+    if (!bOnce)
+    {
+        bOnce = true;
+        const OString& rID = SessionManagerClient::getSessionID();
+        if (!rID.isEmpty())
+            gdk_set_sm_client_id(rID.getStr());
+    }
+#else
+    // No session management support for gtk3+ - this is now legacy.
+#endif
+}
+
+void GtkSalFrame::Show( bool bVisible, bool bNoActivate )
+{
+    if( m_pWindow )
+    {
+#if !GTK_CHECK_VERSION(3,0,0)
+        if( m_pParent && (m_pParent->m_nStyle & SalFrameStyleFlags::PARTIAL_FULLSCREEN)
+            && getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+            gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), bVisible );
+#endif
+        if( bVisible )
+        {
+            initClientId();
+            getDisplay()->startupNotificationCompleted();
+
+            if( m_bDefaultPos )
+                Center();
+            if( m_bDefaultSize )
+                SetDefaultSize();
+            setMinMaxSize();
+
+#if !GTK_CHECK_VERSION(3,0,0)
+            // #i45160# switch to desktop where a dialog with parent will appear
+            if( m_pParent && m_pParent->m_nWorkArea != m_nWorkArea && IS_WIDGET_MAPPED(m_pParent->m_pWindow) )
+                getDisplay()->getWMAdaptor()->switchToWorkArea( m_pParent->m_nWorkArea );
+#endif
+
+            if( isFloatGrabWindow() &&
+                m_pParent &&
+                m_nFloats == 0 &&
+                ! getDisplay()->GetCaptureFrame() )
+            {
+                /* #i63086#
+                 * outsmart Metacity's "focus:mouse" mode
+                 * which insists on taking the focus from the document
+                 * to the new float. Grab focus to parent frame BEFORE
+                 * showing the float (cannot grab it to the float
+                 * before show).
+                 */
+                 m_pParent->grabPointer( true, true );
+            }
+
+#if !GTK_CHECK_VERSION(3,0,0)
+            guint32 nUserTime = 0;
+            if( ! bNoActivate && !(m_nStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION|SalFrameStyleFlags::TOOLWINDOW)) )
+                nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
+
+            //For these floating windows we don't want the main window to lose focus, and metacity has...
+            // metacity-2.24.0/src/core/window.c
+
+            //  if ((focus_window != NULL) && XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time))
+            //      "compare" window focus prevented by other activity
+
+            //  where "compare" is this window
+
+            //  which leads to...
+
+            // /* This happens for error dialogs or alerts; these need to remain on
+            // * top, but it would be confusing to have its ancestor remain
+            // * focused.
+            // */
+            // if (meta_window_is_ancestor_of_transient (focus_window, window))
+            //          "The focus window %s is an ancestor of the newly mapped "
+            //         "window %s which isn't being focused.  Unfocusing the "
+            //          "ancestor.\n",
+
+            // i.e. having a time < that of the toplevel frame means that the toplevel frame gets unfocused.
+            // awesome.
+            if( nUserTime == 0 )
+            {
+                nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
+            }
+            lcl_set_user_time(GTK_WINDOW(m_pWindow), nUserTime );
+#endif
+
+            if( ! bNoActivate && (m_nStyle & SalFrameStyleFlags::TOOLWINDOW) )
+                m_bSetFocusOnMap = true;
+
+            gtk_widget_show( m_pWindow );
+
+            if( isFloatGrabWindow() )
+            {
+                m_nFloats++;
+                if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 1 )
+                {
+                    grabPointer(true, true);
+                    GtkSalFrame *pKeyboardFrame = m_pParent ? m_pParent : this;
+                    pKeyboardFrame->grabKeyboard(true);
+                }
+                // #i44068# reset parent's IM context
+                if( m_pParent )
+                    m_pParent->EndExtTextInput(EndExtTextInputFlags::NONE);
+            }
+            if( m_bWindowIsGtkPlug )
+                askForXEmbedFocus( 0 );
+        }
+        else
+        {
+            if( isFloatGrabWindow() )
+            {
+                m_nFloats--;
+                if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 0)
+                {
+                    GtkSalFrame *pKeyboardFrame = m_pParent ? m_pParent : this;
+                    pKeyboardFrame->grabKeyboard(false);
+                    grabPointer(false);
+                }
+            }
+            gtk_widget_hide( m_pWindow );
+            if( m_pIMHandler )
+                m_pIMHandler->focusChanged( false );
+            // flush here; there may be a very seldom race between
+            // the display connection used for clipboard and our connection
+            Flush();
+        }
+        CallCallback( SALEVENT_RESIZE, nullptr );
+        TriggerPaintEvent();
+    }
+}
+
+void GtkSalFrame::setMinMaxSize()
+{
+    /*  #i34504# metacity (and possibly others) do not treat
+     *  _NET_WM_STATE_FULLSCREEN and max_width/height independently;
+     *  whether they should is undefined. So don't set the max size hint
+     *  for a full screen window.
+    */
+    if( m_pWindow && ! isChild() )
+    {
+        GdkGeometry aGeo;
+        int aHints = 0;
+        if( m_nStyle & SalFrameStyleFlags::SIZEABLE )
+        {
+            if( m_aMinSize.Width() && m_aMinSize.Height() && ! m_bFullscreen )
+            {
+                aGeo.min_width  = m_aMinSize.Width();
+                aGeo.min_height = m_aMinSize.Height();
+                aHints |= GDK_HINT_MIN_SIZE;
+            }
+            if( m_aMaxSize.Width() && m_aMaxSize.Height() && ! m_bFullscreen )
+            {
+                aGeo.max_width  = m_aMaxSize.Width();
+                aGeo.max_height = m_aMaxSize.Height();
+                aHints |= GDK_HINT_MAX_SIZE;
+            }
+        }
+        else
+        {
+            if( ! m_bFullscreen )
+            {
+                aGeo.min_width = maGeometry.nWidth;
+                aGeo.min_height = maGeometry.nHeight;
+                aHints |= GDK_HINT_MIN_SIZE;
+
+                aGeo.max_width = maGeometry.nWidth;
+                aGeo.max_height = maGeometry.nHeight;
+                aHints |= GDK_HINT_MAX_SIZE;
+            }
+        }
+        if( m_bFullscreen && m_aMaxSize.Width() && m_aMaxSize.Height() )
+        {
+            aGeo.max_width = m_aMaxSize.Width();
+            aGeo.max_height = m_aMaxSize.Height();
+            aHints |= GDK_HINT_MAX_SIZE;
+        }
+        if( aHints )
+        {
+            gtk_window_set_geometry_hints( GTK_WINDOW(m_pWindow),
+                                           nullptr,
+                                           &aGeo,
+                                           GdkWindowHints( aHints ) );
+        }
+    }
+}
+
+void GtkSalFrame::SetMaxClientSize( long nWidth, long nHeight )
+{
+    if( ! isChild() )
+    {
+        m_aMaxSize = Size( nWidth, nHeight );
+        // Show does a setMinMaxSize
+        if( IS_WIDGET_MAPPED( m_pWindow ) )
+            setMinMaxSize();
+    }
+}
+void GtkSalFrame::SetMinClientSize( long nWidth, long nHeight )
+{
+    if( ! isChild() )
+    {
+        m_aMinSize = Size( nWidth, nHeight );
+        if( m_pWindow )
+        {
+            widget_set_size_request(nWidth, nHeight );
+            // Show does a setMinMaxSize
+            if( IS_WIDGET_MAPPED( m_pWindow ) )
+                setMinMaxSize();
+        }
+    }
+}
+
+// FIXME: we should really be an SvpSalFrame sub-class, and
+// share their AllocateFrame !
+void GtkSalFrame::AllocateFrame()
+{
+#if GTK_CHECK_VERSION(3,0,0)
+    basegfx::B2IVector aFrameSize( maGeometry.nWidth, maGeometry.nHeight );
+    if( ! m_aFrame.get() || m_aFrame->getSize() != aFrameSize )
+    {
+        if( aFrameSize.getX() == 0 )
+            aFrameSize.setX( 1 );
+        if( aFrameSize.getY() == 0 )
+            aFrameSize.setY( 1 );
+        m_aFrame = basebmp::createBitmapDevice(aFrameSize, true, SVP_CAIRO_FORMAT);
+        assert(cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, aFrameSize.getX()) ==
+               m_aFrame->getScanlineStride());
+        m_aFrame->setDamageTracker(
+            basebmp::IBitmapDeviceDamageTrackerSharedPtr(new DamageTracker(*this)) );
+        SAL_INFO("vcl.gtk3", "allocated m_aFrame size of " << maGeometry.nWidth << " x " << maGeometry.nHeight);
+
+#if OSL_DEBUG_LEVEL > 0 // set background to orange
+        m_aFrame->clear( basebmp::Color( 255, 127, 0 ) );
+#endif
+
+        if( m_pGraphics )
+            m_pGraphics->setDevice( m_aFrame );
+    }
+#endif
+}
+
+void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
+{
+    if( !m_pWindow || isChild( true, false ) )
+        return;
+
+    bool bSized = false, bMoved = false;
+
+    if( (nFlags & ( SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT )) &&
+        (nWidth > 0 && nHeight > 0 ) // sometimes stupid things happen
+            )
+    {
+        m_bDefaultSize = false;
+
+        if( (unsigned long)nWidth != maGeometry.nWidth || (unsigned long)nHeight != maGeometry.nHeight )
+            bSized = true;
+        maGeometry.nWidth   = nWidth;
+        maGeometry.nHeight  = nHeight;
+
+        if( isChild( false ) )
+            widget_set_size_request(nWidth, nHeight);
+        else if( ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) )
+            window_resize(nWidth, nHeight);
+        setMinMaxSize();
+    }
+    else if( m_bDefaultSize )
+        SetDefaultSize();
+
+    m_bDefaultSize = false;
+
+    if( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) )
+    {
+        if( m_pParent )
+        {
+            if( AllSettings::GetLayoutRTL() )
+                nX = m_pParent->maGeometry.nWidth-maGeometry.nWidth-1-nX;
+            nX += m_pParent->maGeometry.nX;
+            nY += m_pParent->maGeometry.nY;
+        }
+
+        if( nX != maGeometry.nX || nY != maGeometry.nY )
+            bMoved = true;
+        maGeometry.nX = nX;
+        maGeometry.nY = nY;
+
+        m_bDefaultPos = false;
+
+        moveWindow( maGeometry.nX, maGeometry.nY );
+
+        updateScreenNumber();
+    }
+    else if( m_bDefaultPos )
+        Center();
+
+    m_bDefaultPos = false;
+
+    if( bSized )
+        AllocateFrame();
+
+    if( bSized && ! bMoved )
+        CallCallback( SALEVENT_RESIZE, nullptr );
+    else if( bMoved && ! bSized )
+        CallCallback( SALEVENT_MOVE, nullptr );
+    else if( bMoved && bSized )
+        CallCallback( SALEVENT_MOVERESIZE, nullptr );
+
+    if (bSized)
+        TriggerPaintEvent();
+}
+
+void GtkSalFrame::GetClientSize( long& rWidth, long& rHeight )
+{
+    if( m_pWindow && !(m_nState & GDK_WINDOW_STATE_ICONIFIED) )
+    {
+        rWidth = maGeometry.nWidth;
+        rHeight = maGeometry.nHeight;
+    }
+    else
+        rWidth = rHeight = 0;
+}
+
+void GtkSalFrame::GetWorkArea( Rectangle& rRect )
+{
+#if !GTK_CHECK_VERSION(3,0,0)
+    rRect = GetGtkSalData()->GetGtkDisplay()->getWMAdaptor()->getWorkArea( 0 );
+#else
+    GdkScreen  *pScreen = gtk_window_get_screen(GTK_WINDOW(m_pWindow));
+    Rectangle aRetRect;
+    int max = gdk_screen_get_n_monitors (pScreen);
+    for (int i = 0; i < max; ++i)
+    {
+        GdkRectangle aRect;
+        gdk_screen_get_monitor_workarea(pScreen, i, &aRect);
+        Rectangle aMonitorRect(aRect.x, aRect.y, aRect.x+aRect.width, aRect.y+aRect.height);
+        aRetRect.Union(aMonitorRect);
+    }
+    rRect = aRetRect;
+#endif
+}
+
+SalFrame* GtkSalFrame::GetParent() const
+{
+    return m_pParent;
+}
+
+void GtkSalFrame::SetWindowState( const SalFrameState* pState )
+{
+    if( ! m_pWindow || ! pState || isChild( true, false ) )
+        return;
+
+    const sal_uLong nMaxGeometryMask =
+        WINDOWSTATE_MASK_X | WINDOWSTATE_MASK_Y |
+        WINDOWSTATE_MASK_WIDTH | WINDOWSTATE_MASK_HEIGHT |
+        WINDOWSTATE_MASK_MAXIMIZED_X | WINDOWSTATE_MASK_MAXIMIZED_Y |
+        WINDOWSTATE_MASK_MAXIMIZED_WIDTH | WINDOWSTATE_MASK_MAXIMIZED_HEIGHT;
+
+    if( (pState->mnMask & WINDOWSTATE_MASK_STATE) &&
+        ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) &&
+        (pState->mnState & WINDOWSTATE_STATE_MAXIMIZED) &&
+        (pState->mnMask & nMaxGeometryMask) == nMaxGeometryMask )
+    {
+        resizeWindow( pState->mnWidth, pState->mnHeight );
+        moveWindow( pState->mnX, pState->mnY );
+        m_bDefaultPos = m_bDefaultSize = false;
+
+        maGeometry.nX       = pState->mnMaximizedX;
+        maGeometry.nY       = pState->mnMaximizedY;
+        maGeometry.nWidth   = pState->mnMaximizedWidth;
+        maGeometry.nHeight  = pState->mnMaximizedHeight;
+        updateScreenNumber();
+
+        m_nState = GdkWindowState( m_nState | GDK_WINDOW_STATE_MAXIMIZED );
+        m_aRestorePosSize = Rectangle( Point( pState->mnX, pState->mnY ),
+                                       Size( pState->mnWidth, pState->mnHeight ) );
+        CallCallback( SALEVENT_RESIZE, nullptr );
+    }
+    else if( pState->mnMask & (WINDOWSTATE_MASK_X | WINDOWSTATE_MASK_Y |
+                               WINDOWSTATE_MASK_WIDTH | WINDOWSTATE_MASK_HEIGHT ) )
+    {
+        sal_uInt16 nPosSizeFlags = 0;
+        long nX         = pState->mnX - (m_pParent ? m_pParent->maGeometry.nX : 0);
+        long nY         = pState->mnY - (m_pParent ? m_pParent->maGeometry.nY : 0);
+        if( pState->mnMask & WINDOWSTATE_MASK_X )
+            nPosSizeFlags |= SAL_FRAME_POSSIZE_X;
+        else
+            nX = maGeometry.nX - (m_pParent ? m_pParent->maGeometry.nX : 0);
+        if( pState->mnMask & WINDOWSTATE_MASK_Y )
+            nPosSizeFlags |= SAL_FRAME_POSSIZE_Y;
+        else
+            nY = maGeometry.nY - (m_pParent ? m_pParent->maGeometry.nY : 0);
+        if( pState->mnMask & WINDOWSTATE_MASK_WIDTH )
+            nPosSizeFlags |= SAL_FRAME_POSSIZE_WIDTH;
+        if( pState->mnMask & WINDOWSTATE_MASK_HEIGHT )
+            nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT;
+        SetPosSize( nX, nY, pState->mnWidth, pState->mnHeight, nPosSizeFlags );
+    }
+    if( pState->mnMask & WINDOWSTATE_MASK_STATE && ! isChild() )
+    {
+        if( pState->mnState & WINDOWSTATE_STATE_MAXIMIZED )
+            gtk_window_maximize( GTK_WINDOW(m_pWindow) );
+        else
+            gtk_window_unmaximize( GTK_WINDOW(m_pWindow) );
+        /* #i42379# there is no rollup state in GDK; and rolled up windows are
+        *  (probably depending on the WM) reported as iconified. If we iconify a
+        *  window here that was e.g. a dialog, then it will be unmapped but still
+        *  not be displayed in the task list, so it's an iconified window that
+        *  the user cannot get out of this state. So do not set the iconified state
+        *  on windows with a parent (that is transient frames) since these tend
+        *  to not be represented in an icon task list.
+        */
+        if( (pState->mnState & WINDOWSTATE_STATE_MINIMIZED)
+            && ! m_pParent )
+            gtk_window_iconify( GTK_WINDOW(m_pWindow) );
+        else
+            gtk_window_deiconify( GTK_WINDOW(m_pWindow) );
+    }
+    TriggerPaintEvent();
+}
+
+bool GtkSalFrame::GetWindowState( SalFrameState* pState )
+{
+    pState->mnState = WINDOWSTATE_STATE_NORMAL;
+    pState->mnMask  = WINDOWSTATE_MASK_STATE;
+    // rollup ? gtk 2.2 does not seem to support the shaded state
+    if( (m_nState & GDK_WINDOW_STATE_ICONIFIED) )
+        pState->mnState |= WINDOWSTATE_STATE_MINIMIZED;
+    if( m_nState & GDK_WINDOW_STATE_MAXIMIZED )
+    {
+        pState->mnState |= WINDOWSTATE_STATE_MAXIMIZED;
+        pState->mnX                 = m_aRestorePosSize.Left();
+        pState->mnY                 = m_aRestorePosSize.Top();
+        pState->mnWidth             = m_aRestorePosSize.GetWidth();
+        pState->mnHeight            = m_aRestorePosSize.GetHeight();
+        pState->mnMaximizedX        = maGeometry.nX;
+        pState->mnMaximizedY        = maGeometry.nY;
+        pState->mnMaximizedWidth    = maGeometry.nWidth;
+        pState->mnMaximizedHeight   = maGeometry.nHeight;
+        pState->mnMask  |= WINDOWSTATE_MASK_MAXIMIZED_X          |
+                           WINDOWSTATE_MASK_MAXIMIZED_Y          |
+                           WINDOWSTATE_MASK_MAXIMIZED_WIDTH      |
+                           WINDOWSTATE_MASK_MAXIMIZED_HEIGHT;
+    }
+    else
+    {
+        pState->mnX         = maGeometry.nX;
+        pState->mnY         = maGeometry.nY;
+        pState->mnWidth     = maGeometry.nWidth;
+        pState->mnHeight    = maGeometry.nHeight;
+    }
+    pState->mnMask  |= WINDOWSTATE_MASK_X            |
+                       WINDOWSTATE_MASK_Y            |
+                       WINDOWSTATE_MASK_WIDTH        |
+                       WINDOWSTATE_MASK_HEIGHT;
+
+    return true;
+}
+
+typedef enum {
+    SET_RETAIN_SIZE,
+    SET_FULLSCREEN,
+    SET_UN_FULLSCREEN
+} SetType;
+
+void GtkSalFrame::SetScreen( unsigned int nNewScreen, int eType, Rectangle *pSize )
+{
+    if( !m_pWindow )
+        return;
+
+    if (maGeometry.nDisplayScreenNumber == nNewScreen && eType == SET_RETAIN_SIZE)
+        return;
+
+    GdkScreen *pScreen = nullptr;
+    GdkRectangle aNewMonitor;
+
+    bool bSpanAllScreens = nNewScreen == (unsigned int)-1;
+    m_bSpanMonitorsWhenFullscreen = bSpanAllScreens && getDisplay()->getSystem()->GetDisplayScreenCount() > 1;
+
+    if (m_bSpanMonitorsWhenFullscreen)   //span all screens
+    {
+        pScreen = gtk_widget_get_screen( m_pWindow );
+        aNewMonitor.x = 0;
+        aNewMonitor.y = 0;
+        aNewMonitor.width = gdk_screen_get_width(pScreen);
+        aNewMonitor.height = gdk_screen_get_height(pScreen);
+    }
+    else
+    {
+        gint nMonitor;
+        bool bSameMonitor = false;
+
+        if (!bSpanAllScreens)
+        {
+            pScreen = getDisplay()->getSystem()->getScreenMonitorFromIdx( nNewScreen, nMonitor );
+            if (!pScreen)
+            {
+                g_warning ("Attempt to move GtkSalFrame to invalid screen %d => "
+                           "fallback to current\n", nNewScreen);
+            }
+        }
+
+        if (!pScreen)
+        {
+            pScreen = gtk_widget_get_screen( m_pWindow );
+            bSameMonitor = true;
+        }
+
+        // Heavy lifting, need to move screen ...
+        if( pScreen != gtk_widget_get_screen( m_pWindow ))
+            gtk_window_set_screen( GTK_WINDOW( m_pWindow ), pScreen );
+
+        gint nOldMonitor = gdk_screen_get_monitor_at_window(
+                                pScreen, widget_get_window( m_pWindow ) );
+        if (bSameMonitor)
+            nMonitor = nOldMonitor;
+
+    #if OSL_DEBUG_LEVEL > 1
+        if( nMonitor == nOldMonitor )
+            g_warning( "An apparently pointless SetScreen - should we elide it ?" );
+    #endif
+
+        GdkRectangle aOldMonitor;
+        gdk_screen_get_monitor_geometry( pScreen, nOldMonitor, &aOldMonitor );
+        gdk_screen_get_monitor_geometry( pScreen, nMonitor, &aNewMonitor );
+
+        maGeometry.nX = aNewMonitor.x + maGeometry.nX - aOldMonitor.x;
+        maGeometry.nY = aNewMonitor.y + maGeometry.nY - aOldMonitor.y;
+    }
+
+    bool bResize = false;
+    bool bVisible = IS_WIDGET_MAPPED( m_pWindow );
+    if( bVisible )
+        Show( false );
+
+    if( eType == SET_FULLSCREEN )
+    {
+        maGeometry.nX = aNewMonitor.x;
+        maGeometry.nY = aNewMonitor.y;
+        maGeometry.nWidth = aNewMonitor.width;
+        maGeometry.nHeight = aNewMonitor.height;
+        m_nStyle |= SalFrameStyleFlags::PARTIAL_FULLSCREEN;
+        bResize = true;
+
+        // #i110881# for the benefit of compiz set a max size here
+        // else setting to fullscreen fails for unknown reasons
+        m_aMaxSize.Width() = aNewMonitor.width;
+        m_aMaxSize.Height() = aNewMonitor.height;
+    }
+
+    if( pSize && eType == SET_UN_FULLSCREEN )
+    {
+        maGeometry.nX = pSize->Left();
+        maGeometry.nY = pSize->Top();
+        maGeometry.nWidth = pSize->GetWidth();
+        maGeometry.nHeight = pSize->GetHeight();
+        m_nStyle &= ~SalFrameStyleFlags::PARTIAL_FULLSCREEN;
+        bResize = true;
+    }
+
+    if (bResize)
+    {
+        // temporarily re-sizeable
+        if( !(m_nStyle & SalFrameStyleFlags::SIZEABLE) )
+            gtk_window_set_resizable( GTK_WINDOW(m_pWindow), TRUE );
+        window_resize(maGeometry.nWidth, maGeometry.nHeight);
+        //I wonder if we should instead leave maGeometry alone and rely on
+        //configure-event to trigger signalConfigure and set it there
+        AllocateFrame();
+        TriggerPaintEvent();
+    }
+
+    gtk_window_move( GTK_WINDOW( m_pWindow ), maGeometry.nX, maGeometry.nY );
+
+#if !GTK_CHECK_VERSION(3,0,0)
+    // _NET_WM_STATE_FULLSCREEN (Metacity <-> KWin)
+   if( ! getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+#endif
+    {
+#if GTK_CHECK_VERSION(3,8,0)
+        gdk_window_set_fullscreen_mode( widget_get_window(m_pWindow), m_bSpanMonitorsWhenFullscreen
+            ? GDK_FULLSCREEN_ON_ALL_MONITORS : GDK_FULLSCREEN_ON_CURRENT_MONITOR );
+#endif
+        if( eType == SET_FULLSCREEN )
+            gtk_window_fullscreen( GTK_WINDOW( m_pWindow ) );
+        else if( eType == SET_UN_FULLSCREEN )
+            gtk_window_unfullscreen( GTK_WINDOW( m_pWindow ) );
+    }
+
+    if( eType == SET_UN_FULLSCREEN &&
+        !(m_nStyle & SalFrameStyleFlags::SIZEABLE) )
+        gtk_window_set_resizable( GTK_WINDOW( m_pWindow ), FALSE );
+
+    // FIXME: we should really let gtk+ handle our widget hierarchy ...
+    if( m_pParent && gtk_widget_get_screen( m_pParent->m_pWindow ) != pScreen )
+        SetParent( nullptr );
+    std::list< GtkSalFrame* > aChildren = m_aChildren;
+    for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
+        (*it)->SetScreen( nNewScreen, SET_RETAIN_SIZE );
+
+    m_bDefaultPos = m_bDefaultSize = false;
+    updateScreenNumber();
+    CallCallback( SALEVENT_MOVERESIZE, nullptr );
+
+    if( bVisible )
+        Show( true );
+}
+
+void GtkSalFrame::SetScreenNumber( unsigned int nNewScreen )
+{
+    SetScreen( nNewScreen, SET_RETAIN_SIZE );
+}
+
+void GtkSalFrame::updateWMClass()
+{
+    OString aResClass = OUStringToOString(m_sWMClass, RTL_TEXTENCODING_ASCII_US);
+    const char *pResClass = !aResClass.isEmpty() ? aResClass.getStr() :
+                                                    SalGenericSystem::getFrameClassName();
+    Display *display;
+
+    if (!getDisplay()->IsX11Display())
+        return;
+
+#if GTK_CHECK_VERSION(3,0,0)
+    display = GDK_DISPLAY_XDISPLAY(getGdkDisplay());
+#else
+    display = getDisplay()->GetDisplay();
+#endif
+
+    if( IS_WIDGET_REALIZED( m_pWindow ) )
+    {
+        XClassHint* pClass = XAllocClassHint();
+        OString aResName = SalGenericSystem::getFrameResName();
+        pClass->res_name  = const_cast<char*>(aResName.getStr());
+        pClass->res_class = const_cast<char*>(pResClass);
+        XSetClassHint( display,
+                       widget_get_xid(m_pWindow),
+                       pClass );
+        XFree( pClass );
+    }
+}
+
+void GtkSalFrame::SetApplicationID( const OUString &rWMClass )
+{
+    if( rWMClass != m_sWMClass && ! isChild() )
+    {
+        m_sWMClass = rWMClass;
+        updateWMClass();
+
+        for( std::list< GtkSalFrame* >::iterator it = m_aChildren.begin(); it != m_aChildren.end(); ++it )
+            (*it)->SetApplicationID(rWMClass);
+    }
+}
+
+void GtkSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nScreen )
+{
+    m_bFullscreen = bFullScreen;
+
+    if( !m_pWindow || isChild() )
+        return;
+
+    if( bFullScreen )
+    {
+        m_aRestorePosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
+                                       Size( maGeometry.nWidth, maGeometry.nHeight ) );
+        SetScreen( nScreen, SET_FULLSCREEN );
+    }
+    else
+    {
+        SetScreen( nScreen, SET_UN_FULLSCREEN,
+                   !m_aRestorePosSize.IsEmpty() ? &m_aRestorePosSize : nullptr );
+        m_aRestorePosSize = Rectangle();
+    }
+}
+
+void GtkSalFrame::StartPresentation( bool bStart )
+{
+    boost::optional<guint> aWindow;
+    boost::optional<Display*> aDisplay;
+    if( getDisplay()->IsX11Display() )
+    {
+        aWindow = widget_get_xid(m_pWindow);
+        aDisplay = GDK_DISPLAY_XDISPLAY( getGdkDisplay() );
+    }
+
+    m_ScreenSaverInhibitor.inhibit( bStart,
+                                    "presentation",
+                                    getDisplay()->IsX11Display(),
+                                    aWindow,
+                                    aDisplay );
+}
+
+void GtkSalFrame::SetAlwaysOnTop( bool bOnTop )
+{
+    if( m_pWindow )
+        gtk_window_set_keep_above( GTK_WINDOW( m_pWindow ), bOnTop );
+}
+
+void GtkSalFrame::ToTop( sal_uInt16 nFlags )
+{
+    if( m_pWindow )
+    {
+        if( isChild( false ) )
+            gtk_widget_grab_focus( m_pWindow );
+        else if( IS_WIDGET_MAPPED( m_pWindow ) )
+        {
+            if( ! (nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY) )
+                gtk_window_present( GTK_WINDOW(m_pWindow) );
+            else
+            {
+#if !GTK_CHECK_VERSION(3,0,0)
+                guint32 nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
+#else
+                guint32 nUserTime = GDK_CURRENT_TIME;
+#endif
+                gdk_window_focus( widget_get_window(m_pWindow), nUserTime );
+            }
+#if !GTK_CHECK_VERSION(3,0,0)
+            /*  need to do an XSetInputFocus here because
+             *  gdk_window_focus will ask a EWMH compliant WM to put the focus
+             *  to our window - which it of course won't since our input hint
+             *  is set to false.
+             */
+            if( (m_nStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION|SalFrameStyleFlags::FLOAT_FOCUSABLE)) )
+            {
+                // sad but true: this can cause an XError, we need to catch that
+                // to do this we need to synchronize with the XServer
+                GetGenericData()->ErrorTrapPush();
+                XSetInputFocus( getDisplay()->GetDisplay(), widget_get_xid(m_pWindow), RevertToParent, CurrentTime );
+                // fdo#46687 - an XSync should not be necessary - but for some reason it is.
+                XSync( getDisplay()->GetDisplay(), False );
+                GetGenericData()->ErrorTrapPop();
+            }
+#endif
+        }
+        else
+        {
+            if( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
+                gtk_window_present( GTK_WINDOW(m_pWindow) );
+        }
+    }
+}
+
+void GtkSalFrame::SetPointer( PointerStyle ePointerStyle )
+{
+    if( m_pWindow && ePointerStyle != m_ePointerStyle )
+    {
+        m_ePointerStyle = ePointerStyle;
+        GdkCursor *pCursor = getDisplay()->getCursor( ePointerStyle );
+        gdk_window_set_cursor( widget_get_window(m_pWindow), pCursor );
+        m_pCurrentCursor = pCursor;
+
+        // #i80791# use grabPointer the same way as CaptureMouse, respective float grab
+        if( getDisplay()->MouseCaptured( this ) )
+            grabPointer( true );
+        else if( m_nFloats > 0 )
+            grabPointer( true, true );
+    }
+}
+
+void GtkSalFrame::grabPointer( bool bGrab, bool bOwnerEvents )
+{
+    static const char* pEnv = getenv( "SAL_NO_MOUSEGRABS" );
+    if (pEnv && *pEnv)
+        return;
+
+    if (!m_pWindow)
+        return;
+
+    const int nMask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
+
+#if GTK_CHECK_VERSION(3,0,0)
+    GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(getGdkDisplay());
+    GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager);
+    if (bGrab)
+        gdk_device_grab(pPointer, widget_get_window(getMouseEventWidget()), GDK_OWNERSHIP_NONE, bOwnerEvents, (GdkEventMask) nMask, m_pCurrentCursor, GDK_CURRENT_TIME);
+    else
+        gdk_device_ungrab(pPointer, GDK_CURRENT_TIME);
+#else
+    if( bGrab )
+    {
+        bool bUseGdkGrab = true;
+        const std::list< SalFrame* >& rFrames = getDisplay()->getFrames();
+        for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+        {
+            const GtkSalFrame* pFrame = static_cast< const GtkSalFrame* >(*it);
+            if( pFrame->m_bWindowIsGtkPlug )
+            {
+                bUseGdkGrab = false;
+                break;
+            }
+        }
+        if( bUseGdkGrab )
+        {
+            gdk_pointer_grab( widget_get_window( m_pWindow ), bOwnerEvents,
+                              (GdkEventMask) nMask, nullptr, m_pCurrentCursor,
+                              GDK_CURRENT_TIME );
+        }
+        else
+        {
+            // FIXME: for some unknown reason gdk_pointer_grab does not
+            // really produce owner events for GtkPlug windows
+            // the cause is yet unknown
+
+            // this is of course a bad hack, especially as we cannot
+            // set the right cursor this way
+            XGrabPointer( getDisplay()->GetDisplay(),
+                          widget_get_xid( m_pWindow ),
+                          bOwnerEvents,
+                          PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+                          GrabModeAsync,
+                          GrabModeAsync,
+                          None,
+                          None,
+                          CurrentTime
+                );
+        }
+    }
+    else
+    {
+        // Two GdkDisplays may be open
+        gdk_display_pointer_ungrab( getGdkDisplay(), GDK_CURRENT_TIME);
+    }
+#endif
+}
+
+void GtkSalFrame::grabKeyboard( bool bGrab )
+{
+    static const char* pEnv = getenv("SAL_NO_MOUSEGRABS"); // let's not introduce a special var for this
+    if (pEnv && *pEnv)
+        return;
+
+    if (!m_pWindow)
+        return;
+
+#if GTK_CHECK_VERSION(3,0,0)
+    GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(getGdkDisplay());
+    GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager);
+    GdkDevice* pKeyboard = gdk_device_get_associated_device(pPointer);
+    if (bGrab)
+    {
+        gdk_device_grab(pKeyboard, widget_get_window(m_pWindow), GDK_OWNERSHIP_NONE,
+                        true, (GdkEventMask)(GDK_KEY_PRESS | GDK_KEY_RELEASE), nullptr, GDK_CURRENT_TIME);
+    }
+    else
+    {
+        gdk_device_ungrab(pKeyboard, GDK_CURRENT_TIME);
+    }
+#else
+    if( bGrab )
+    {
+        gdk_keyboard_grab(widget_get_window(m_pWindow), true,
+                          GDK_CURRENT_TIME);
+    }
+    else
+    {
+        gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+    }
+#endif
+}
+
+void GtkSalFrame::CaptureMouse( bool bCapture )
+{
+    getDisplay()->CaptureMouse( bCapture ? this : nullptr );
+}
+
+void GtkSalFrame::SetPointerPos( long nX, long nY )
+{
+    GtkSalFrame* pFrame = this;
+    while( pFrame && pFrame->isChild( false ) )
+        pFrame = pFrame->m_pParent;
+    if( ! pFrame )
+        return;
+
+    GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(pFrame->m_pWindow) );
+    GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
+
+    /* when the application tries to center the mouse in the dialog the
+     * window isn't mapped already. So use coordinates relative to the root window.
+     */
+    unsigned int nWindowLeft = maGeometry.nX + nX;
+    unsigned int nWindowTop  = maGeometry.nY + nY;
+
+    XWarpPointer( GDK_DISPLAY_XDISPLAY (pDisplay), None,
+                  GDK_WINDOW_XID (gdk_screen_get_root_window( pScreen ) ),
+                  0, 0, 0, 0, nWindowLeft, nWindowTop);
+    // #i38648# ask for the next motion hint
+    gint x, y;
+    GdkModifierType mask;
+    gdk_window_get_pointer( widget_get_window(pFrame->m_pWindow) , &x, &y, &mask );
+}
+
+void GtkSalFrame::Flush()
+{
+#if GTK_CHECK_VERSION(3,0,0)
+    gdk_display_flush( getGdkDisplay() );
+#else
+    XFlush (GDK_DISPLAY_XDISPLAY (getGdkDisplay()));
+#endif
+}
+
+#ifndef GDK_Open
+#define GDK_Open 0x1008ff6b
+#endif
+#ifndef GDK_Paste
+#define GDK_Paste 0x1008ff6d
+#endif
+#ifndef GDK_Copy
+#define GDK_Copy 0x1008ff57
+#endif
+#ifndef GDK_Cut
+#define GDK_Cut 0x1008ff58
+#endif
+
+void GtkSalFrame::KeyCodeToGdkKey(const vcl::KeyCode& rKeyCode,
+    guint* pGdkKeyCode, GdkModifierType *pGdkModifiers)
+{
+    if ( pGdkKeyCode == nullptr || pGdkModifiers == nullptr )
+        return;
+
+    // Get GDK key modifiers
+    GdkModifierType nModifiers = (GdkModifierType) 0;
+
+    if ( rKeyCode.IsShift() )
+        nModifiers = (GdkModifierType) ( nModifiers | GDK_SHIFT_MASK );
+
+    if ( rKeyCode.IsMod1() )
+        nModifiers = (GdkModifierType) ( nModifiers | GDK_CONTROL_MASK );
+
+    if ( rKeyCode.IsMod2() )
+        nModifiers = (GdkModifierType) ( nModifiers | GDK_MOD1_MASK );
+
+    *pGdkModifiers = nModifiers;
+
+    // Get GDK keycode.
+    guint nKeyCode = 0;
+
+    guint nCode = rKeyCode.GetCode();
+
+    if ( nCode >= KEY_0 && nCode <= KEY_9 )
+        nKeyCode = ( nCode - KEY_0 ) + GDK_0;
+    else if ( nCode >= KEY_A && nCode <= KEY_Z )
+        nKeyCode = ( nCode - KEY_A ) + GDK_A;
+    else if ( nCode >= KEY_F1 && nCode <= KEY_F26 )
+        nKeyCode = ( nCode - KEY_F1 ) + GDK_F1;
+    else
+    {
+        switch( nCode )
+        {
+        case KEY_DOWN:          nKeyCode = GDK_Down;            break;
+        case KEY_UP:            nKeyCode = GDK_Up;              break;
+        case KEY_LEFT:          nKeyCode = GDK_Left;            break;
+        case KEY_RIGHT:         nKeyCode = GDK_Right;           break;
+        case KEY_HOME:          nKeyCode = GDK_Home;            break;
+        case KEY_END:           nKeyCode = GDK_End;             break;
+        case KEY_PAGEUP:        nKeyCode = GDK_Page_Up;         break;
+        case KEY_PAGEDOWN:      nKeyCode = GDK_Page_Down;       break;
+        case KEY_RETURN:        nKeyCode = GDK_Return;          break;
+        case KEY_ESCAPE:        nKeyCode = GDK_Escape;          break;
+        case KEY_TAB:           nKeyCode = GDK_Tab;             break;
+        case KEY_BACKSPACE:     nKeyCode = GDK_BackSpace;       break;
+        case KEY_SPACE:         nKeyCode = GDK_space;           break;
+        case KEY_INSERT:        nKeyCode = GDK_Insert;          break;
+        case KEY_DELETE:        nKeyCode = GDK_Delete;          break;
+        case KEY_ADD:           nKeyCode = GDK_plus;            break;
+        case KEY_SUBTRACT:      nKeyCode = GDK_minus;           break;
+        case KEY_MULTIPLY:      nKeyCode = GDK_asterisk;        break;
+        case KEY_DIVIDE:        nKeyCode = GDK_slash;           break;
+        case KEY_POINT:         nKeyCode = GDK_period;          break;
+        case KEY_COMMA:         nKeyCode = GDK_comma;           break;
+        case KEY_LESS:          nKeyCode = GDK_less;            break;
+        case KEY_GREATER:       nKeyCode = GDK_greater;         break;
+        case KEY_EQUAL:         nKeyCode = GDK_equal;           break;
+        case KEY_FIND:          nKeyCode = GDK_Find;            break;
+        case KEY_CONTEXTMENU:   nKeyCode = GDK_Menu;            break;
+        case KEY_HELP:          nKeyCode = GDK_Help;            break;
+        case KEY_UNDO:          nKeyCode = GDK_Undo;            break;
+        case KEY_REPEAT:        nKeyCode = GDK_Redo;            break;
+        case KEY_DECIMAL:       nKeyCode = GDK_KP_Decimal;      break;
+        case KEY_TILDE:         nKeyCode = GDK_asciitilde;      break;
+        case KEY_QUOTELEFT:     nKeyCode = GDK_quoteleft;       break;
+        case KEY_BRACKETLEFT:   nKeyCode = GDK_bracketleft;     break;
+        case KEY_BRACKETRIGHT:  nKeyCode = GDK_bracketright;    break;
+        case KEY_SEMICOLON:     nKeyCode = GDK_semicolon;       break;
+        case KEY_QUOTERIGHT:    nKeyCode = GDK_quoteright;      break;
+
+        // Special cases
+        case KEY_COPY:          nKeyCode = GDK_Copy;            break;
+        case KEY_CUT:           nKeyCode = GDK_Cut;             break;

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list