From a95302af9fabfc9a4e6b5d2983b9f75645f47438 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
Date: Wed, 9 Dec 2015 15:33:06 +0000
Subject: [PATCH] move things around a little to make backporting easier
Change-Id: I0fa86b4b524056f7a9fac228062401ea1ec2ca25
---
vcl/Library_vclplug_gtk.mk | 2 +-
vcl/Library_vclplug_gtk3.mk | 2 +-
vcl/inc/unx/gtk/gtkframe.hxx | 1 -
vcl/unx/gtk/gtksalframe.cxx | 4883 ++++++++++++++++++++++++++++++++++
vcl/unx/gtk/window/gtksalframe.cxx | 4883 ----------------------------------
vcl/unx/gtk3/app/gtk3gtkinst.cxx | 641 -----
vcl/unx/gtk3/gtk3gtkframe.cxx | 3803 ++++++++++++++++++++++++++
vcl/unx/gtk3/gtk3gtkinst.cxx | 641 +++++
vcl/unx/gtk3/window/gtk3gtkframe.cxx | 12 -
9 files changed, 9329 insertions(+), 5539 deletions(-)
create mode 100644 vcl/unx/gtk/gtksalframe.cxx
delete mode 100644 vcl/unx/gtk/window/gtksalframe.cxx
delete mode 100644 vcl/unx/gtk3/app/gtk3gtkinst.cxx
create mode 100644 vcl/unx/gtk3/gtk3gtkframe.cxx
create mode 100644 vcl/unx/gtk3/gtk3gtkinst.cxx
delete mode 100644 vcl/unx/gtk3/window/gtk3gtkframe.cxx
diff --git a/vcl/Library_vclplug_gtk.mk b/vcl/Library_vclplug_gtk.mk
index ec7f2f8..6d10d5c 100644
--- a/vcl/Library_vclplug_gtk.mk
+++ b/vcl/Library_vclplug_gtk.mk
@@ -100,7 +100,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_gtk,\
vcl/unx/gtk/app/gtkinst \
vcl/unx/gtk/app/gtksys \
vcl/unx/gtk/gdi/salnativewidgets-gtk \
- vcl/unx/gtk/window/gtksalframe \
+ vcl/unx/gtk/gtksalframe \
vcl/unx/gtk/window/gtkobject \
vcl/unx/gtk/fpicker/resourceprovider \
vcl/unx/gtk/fpicker/SalGtkPicker \
diff --git a/vcl/Library_vclplug_gtk3.mk b/vcl/Library_vclplug_gtk3.mk
index 515a81c..222c9d6 100644
--- a/vcl/Library_vclplug_gtk3.mk
+++ b/vcl/Library_vclplug_gtk3.mk
@@ -99,7 +99,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_gtk3,\
vcl/unx/gtk3/a11y/gtk3atkwindow \
vcl/unx/gtk3/a11y/gtk3atkwrapper \
vcl/unx/gtk3/app/gtk3gtkdata \
- vcl/unx/gtk3/app/gtk3gtkinst \
+ vcl/unx/gtk3/gtk3gtkinst \
vcl/unx/gtk3/app/gtk3gtksys \
vcl/unx/gtk3/app/gtk3fpicker \
vcl/unx/gtk3/gdi/cairo_gtk3_cairo \
@@ -107,7 +107,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_gtk3,\
vcl/unx/gtk3/gdi/gtk3gtkprintwrapper \
vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk \
vcl/unx/gtk3/gdi/gtk3salprn-gtk \
- vcl/unx/gtk3/window/gtk3gtkframe \
+ vcl/unx/gtk3/gtk3gtkframe \
vcl/unx/gtk3/window/gtk3gtkobject \
vcl/unx/gtk3/window/gtk3gtksalmenu \
vcl/unx/gtk3/window/gtk3glomenu \
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 4594249..0fb5da7 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -240,7 +240,6 @@ class GtkSalFrame : public SalFrame, public X11WindowProvider
static void signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer );
#if GTK_CHECK_VERSION(3,0,0)
static gboolean signalDraw( GtkWidget*, cairo_t *cr, gpointer );
- static void signalFlagsChanged( GtkWidget*, GtkStateFlags, gpointer );
static void sizeAllocated(GtkWidget*, GdkRectangle *pAllocation, gpointer frame);
#if GTK_CHECK_VERSION(3,14,0)
static void gestureSwipe(GtkGestureSwipe* gesture, gdouble velocity_x, gdouble velocity_y, gpointer frame);
diff --git a/vcl/unx/gtk/gtksalframe.cxx b/vcl/unx/gtk/gtksalframe.cxx
new file mode 100644
index 0000000..9e03f14
--- /dev/null
+++ b/vcl/unx/gtk/gtksalframe.cxx
@@ -0,0 +1,4883 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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 <vcl/bitmapex.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
+
+#ifdef ENABLE_DBUS
+#include <dbus/dbus-glib.h>
+
+#define GSM_DBUS_SERVICE "org.gnome.SessionManager"
+#define GSM_DBUS_PATH "/org/gnome/SessionManager"
+#define GSM_DBUS_INTERFACE "org.gnome.SessionManager"
+#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
+
+#if !GTK_CHECK_VERSION(3,0,0)
+#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 = NULL;
+#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, NULL, NULL, NULL);
+ 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 SAL_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 (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 AlternatKeyCode 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;
+ bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
+ }
+ }
+ if( bSendRelease && ! aDel.isDeleted() )
+ {
+ CallCallback( SALEVENT_KEYUP, &aEvent );
+ }
+ }
+ else
+ CallCallback( SALEVENT_KEYUP, &aEvent );
+}
+
+GtkSalFrame::GraphicsHolder::~GraphicsHolder()
+{
+ delete pGraphics;
+}
+
+GtkSalFrame::GtkSalFrame( SalFrame* pParent, sal_uLong nStyle )
+ : m_nXScreen( getDisplay()->GetDefaultXScreen() )
+{
+ getDisplay()->registerFrame( this );
+ m_bDefaultPos = true;
+ m_bDefaultSize = ( (nStyle & SAL_FRAME_STYLE_SIZEABLE) && ! pParent );
+ m_bWindowIsGtkPlug = false;
+#if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
+ m_pLastSyncedDbusMenu = NULL;
+#endif
+ Init( pParent, nStyle );
+}
+
+GtkSalFrame::GtkSalFrame( SystemParentData* pSysData )
+ : m_nXScreen( getDisplay()->GetDefaultXScreen() )
+{
+ 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 = NULL;
+#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 != NULL)
+ {
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_WINDOW_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, name),
+ gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+ PropModeReplace, 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 = uno::Reference < css::frame::XFrame >(xDesktop, uno::UNO_QUERY);
+
+ if (!xFrame.is())
+ return;
+
+ uno::Reference< css::frame::XDispatchProvider > xDispatchProvider(xFrame, uno::UNO_QUERY);
+ if (!xDispatchProvider.is())
+ return;
+
+ gchar *strval = NULL;
+ 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, OUString("_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, NULL, NULL, NULL, {0} },
+ { "About", activate_uno, NULL, NULL, NULL, {0} },
+ { "HelpIndex", activate_uno, NULL, NULL, NULL, {0} },
+ { "Quit", activate_uno, NULL, NULL, NULL, {0} },
+ { "New", activate_uno, NULL, NULL, NULL, {0} }
+};
+
+gboolean ensure_dbus_setup( gpointer data )
+{
+ GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( data );
+ GdkWindow* gdkWindow = widget_get_window( pSalFrame->getWindow() );
+
+ if ( gdkWindow != NULL && g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" ) == NULL )
+ {
+ // Get a DBus session connection.
+ if(!pSessionBus)
+ pSessionBus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+ 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, NULL);
+ SAL_INFO("vcl.unity", "exporting action group at " << pActionGroup << " for window " << windowId);
+ pSalFrame->m_nActionGroupExportId = g_dbus_connection_export_action_group( pSessionBus, aDBusWindowPath, pActionGroup, NULL);
+ pSalFrame->m_nHudAwarenessId = hud_awareness_register( pSessionBus, aDBusMenubarPath, hud_activated, pSalFrame, NULL, NULL );
+
+ // 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, NULL, 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, NULL, 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, NULL, 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), NULL);
+#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, NULL);
+ g_object_unref(pAppActionGroup);
+ pSalFrame->m_nAppMenuExportId = g_dbus_connection_export_menu_model (pSessionBus, "/org/libreoffice/menus/appmenu", G_MENU_MODEL (menu), NULL);
+ 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 != NULL )
+ {
+ 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 == NULL )
+ {
+ pSessionBus = g_bus_get_sync( G_BUS_TYPE_SESSION, NULL, NULL );
+
+ if ( pSessionBus == NULL )
+ 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),
+ NULL );
+ }
+
+ //ensure_dbus_setup( this );
+#else
+ (void) this; // loplugin:staticmethods
+#endif
+}
+
+void GtkSalFrame::InvalidateGraphics()
+{
+ for (unsigned int i = 0; i < SAL_N_ELEMENTS(m_aGraphics); ++i)
+ {
+ if( !m_aGraphics[i].pGraphics )
+ continue;
+#if !GTK_CHECK_VERSION(3,0,0)
+ m_aGraphics[i].pGraphics->SetDrawable( None, m_nXScreen );
+ m_aGraphics[i].pGraphics->SetWindow(NULL);
+#endif
+ m_aGraphics[i].bInUse = 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
+
+ if( m_pIMHandler )
+ 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", NULL );
+
+#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) );
+}
+
+void GtkSalFrame::moveWindow( long nX, long nY )
+{
+ if( isChild( false, true ) )
+ {
+ 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, true ) )
+ {
+ 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 */
+ NULL, /* class data */
+ sizeof (GtkFixed), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) NULL, /* instance init */
+ NULL /* 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(), NULL ));
+ gtk_container_add( GTK_CONTAINER(m_pEventBox), GTK_WIDGET(m_pFixedContainer) );
+#else
+ m_pEventBox = 0;
+ // 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(), NULL ));
+ 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 );
+// g_signal_connect( G_OBJECT(m_pWindow), "state-flags-changed", G_CALLBACK(signalFlagsChanged), 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 = NULL;
+ m_nKeyModifiers = 0;
+ m_bFullscreen = false;
+ m_bSpanMonitorsWhenFullscreen = false;
+ m_nState = GDK_WINDOW_STATE_WITHDRAWN;
+ m_nVisibility = GDK_VISIBILITY_FULLY_OBSCURED;
+#if GTK_CHECK_VERSION(3,0,0)
+ m_nLastScrollEventTime = GDK_CURRENT_TIME;
+#endif
+ m_bSendModChangeOnRelease = false;
+ m_pIMHandler = NULL;
+ m_hBackgroundPixmap = None;
+ m_nSavedScreenSaverTimeout = 0;
+ m_nGSMCookie = 0;
+ m_nExtStyle = 0;
+ m_pRegion = NULL;
+ m_ePointerStyle = static_cast<PointerStyle>(0xffff);
+ m_bSetFocusOnMap = false;
+ m_pSalMenu = NULL;
+ 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 = NULL;
+ m_aSystemData.pShellWidget = m_aSystemData.pWidget;
+
+ // 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.
+ */
+
+#if !GTK_CHECK_VERSION(3,0,0)
+extern "C" {
+ typedef void(*setAcceptFn)( GtkWindow*, gboolean );
+ static setAcceptFn p_gtk_window_set_accept_focus = NULL;
+ static bool bGetAcceptFocusFn = true;
+
+ typedef void(*setUserTimeFn)( GdkWindow*, guint32 );
+ static setUserTimeFn p_gdk_x11_window_set_user_time = NULL;
+ 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 = NULL;
+ 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, sal_uLong nStyle )
+{
+ if( nStyle & SAL_FRAME_STYLE_DEFAULT ) // ensure default style
+ {
+ nStyle |= SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE;
+ nStyle &= ~SAL_FRAME_STYLE_FLOAT;
+ }
+
+ m_pParent = static_cast<GtkSalFrame*>(pParent);
+ m_pForeignParent = NULL;
+ m_aForeignParentWindow = None;
+ m_pForeignTopLevel = NULL;
+ m_aForeignTopLevelWindow = None;
+ m_nStyle = nStyle;
+
+ GtkWindowType eWinType = ( (nStyle & SAL_FRAME_STYLE_FLOAT) &&
+ ! (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|
+ SAL_FRAME_STYLE_FLOAT_FOCUSABLE))
+ )
+ ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL;
+
+ if( nStyle & SAL_FRAME_STYLE_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", (gpointer)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 & SAL_FRAME_STYLE_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 & SAL_FRAME_STYLE_FLOAT) ||
+ (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE) ) );
+
+ if( bDecoHandling )
+ {
+ GdkWindowTypeHint eType = GDK_WINDOW_TYPE_HINT_NORMAL;
+ if( (nStyle & SAL_FRAME_STYLE_DIALOG) && m_pParent != 0 )
+ eType = GDK_WINDOW_TYPE_HINT_DIALOG;
+ if( (nStyle & SAL_FRAME_STYLE_INTRO) )
+ {
+ gtk_window_set_role( GTK_WINDOW(m_pWindow), "splashscreen" );
+ eType = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN;
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_TOOLWINDOW ) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_UTILITY;
+ gtk_window_set_skip_taskbar_hint( GTK_WINDOW(m_pWindow), true );
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
+ lcl_set_accept_focus( GTK_WINDOW(m_pWindow), false, true );
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_UTILITY;
+ }
+#if !GTK_CHECK_VERSION(3,0,0)
+ if( (nStyle & SAL_FRAME_STYLE_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 & SAL_FRAME_STYLE_FLOAT) )
+ {
+ gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), GDK_WINDOW_TYPE_HINT_POPUP_MENU );
+ }
+
+#if !GTK_CHECK_VERSION(3,0,0)
+ if( eWinType == GTK_WINDOW_TOPLEVEL )
+ {
+#ifdef ENABLE_GMENU_INTEGRATION
+ // Enable DBus native menu if available.
+ ensure_dbus_setup( this );
+#endif
+
+ guint32 nUserTime = 0;
+ if( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
+ {
+ 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), (nStyle & SAL_FRAME_STYLE_SIZEABLE) != 0 );
+ if( ( (nStyle & (SAL_FRAME_STYLE_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 = NULL;
+ 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 = NULL;
+ m_aForeignParentWindow = (GdkNativeWindow)pSysData->aWindow;
+ m_pForeignParent = NULL;
+ 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 = SAL_FRAME_STYLE_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_pWindow )
+ {
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( ! m_aGraphics[i].bInUse )
+ {
+ m_aGraphics[i].bInUse = true;
+ if( ! m_aGraphics[i].pGraphics )
+ {
+#if GTK_CHECK_VERSION(3,0,0)
+ m_aGraphics[i].pGraphics = new GtkSalGraphics( this, m_pWindow );
+ if( !m_aFrame.get() )
+ {
+ AllocateFrame();
+ TriggerPaintEvent();
+ }
+ m_aGraphics[i].pGraphics->setDevice( m_aFrame );
+#else // common case:
+ m_aGraphics[i].pGraphics = new GtkSalGraphics( this, m_pWindow, m_nXScreen );
+#endif
+ }
+ return m_aGraphics[i].pGraphics;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void GtkSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
+{
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( m_aGraphics[i].pGraphics == pGraphics )
+ {
+ m_aGraphics[i].bInUse = false;
+ break;
+ }
+ }
+}
+
+bool GtkSalFrame::PostEvent( void* 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() );
+}
+
+static inline sal_uInt8 *
+getRow( BitmapBuffer *pBuffer, sal_uLong nRow )
+{
+ if( BMP_SCANLINE_ADJUSTMENT( pBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ return pBuffer->mpBits + nRow * pBuffer->mnScanlineSize;
+ else
+ return pBuffer->mpBits + ( pBuffer->mnHeight - nRow - 1 ) * pBuffer->mnScanlineSize;
+}
+
+static GdkPixbuf *
+bitmapToPixbuf( SalBitmap *pSalBitmap, SalBitmap *pSalAlpha )
+{
+ g_return_val_if_fail( pSalBitmap != NULL, NULL );
+ g_return_val_if_fail( pSalAlpha != NULL, NULL );
+
+ BitmapBuffer *pBitmap = pSalBitmap->AcquireBuffer( BITMAP_READ_ACCESS );
+ g_return_val_if_fail( pBitmap != NULL, NULL );
+ g_return_val_if_fail( pBitmap->mnBitCount == 24 || pBitmap->mnBitCount == 32, NULL );
+
+ BitmapBuffer *pAlpha = pSalAlpha->AcquireBuffer( BITMAP_READ_ACCESS );
+ g_return_val_if_fail( pAlpha != NULL, NULL );
+ g_return_val_if_fail( pAlpha->mnBitCount == 8, NULL );
+
+ Size aSize = pSalBitmap->GetSize();
+ g_return_val_if_fail( pSalAlpha->GetSize() == aSize, NULL );
+
+ int nX, nY;
+ guchar *pPixbufData = static_cast<guchar *>(g_malloc (4 * aSize.Width() * aSize.Height() ));
+ guchar *pDestData = pPixbufData;
+
+ for( nY = 0; nY < pBitmap->mnHeight; nY++ )
+ {
+ sal_uInt8 *pData = getRow( pBitmap, nY );
+ sal_uInt8 *pAlphaData = getRow( pAlpha, nY );
+
+ for( nX = 0; nX < pBitmap->mnWidth; nX++ )
+ {
+ BitmapColor aColor;
+ if (pBitmap->mnFormat == BMP_FORMAT_24BIT_TC_BGR)
+ {
+ aColor = BitmapColor(pData[2], pData[1], pData[0]);
+ pData += 3;
+ }
+ else if (pBitmap->mnFormat == BMP_FORMAT_24BIT_TC_RGB)
+ {
+ aColor = BitmapColor(pData[0], pData[1], pData[2]);
+ pData += 3;
+ }
+ else
+ {
+ pBitmap->maColorMask.GetColorFor32Bit(aColor, pData);
+ pData += 4;
+ }
+ *pDestData++ = aColor.GetRed();
+ *pDestData++ = aColor.GetGreen();
+ *pDestData++ = aColor.GetBlue();
+ *pDestData++ = 255 - *pAlphaData++;
+ }
+ }
+
+ pSalBitmap->ReleaseBuffer( pBitmap, BITMAP_READ_ACCESS );
+ pSalAlpha->ReleaseBuffer( pAlpha, BITMAP_READ_ACCESS );
+
+ return gdk_pixbuf_new_from_data( pPixbufData,
+ GDK_COLORSPACE_RGB, true, 8,
+ aSize.Width(), aSize.Height(),
+ aSize.Width() * 4,
+ reinterpret_cast<GdkPixbufDestroyNotify>(g_free),
+ NULL );
+}
+
+void GtkSalFrame::SetIcon( sal_uInt16 nIcon )
+{
+ if( (m_nStyle & (SAL_FRAME_STYLE_PLUG|SAL_FRAME_STYLE_SYSTEMCHILD|SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_INTRO|SAL_FRAME_STYLE_OWNERDRAWDECORATION))
+ || ! m_pWindow )
+ return;
+
+ if( !ImplGetResMgr() )
+ return;
+
+ GdkPixbuf *pBuf;
+ GList *pIcons = NULL;
+
+ sal_uInt16 nOffsets[2] = { SV_ICON_SMALL_START, SV_ICON_LARGE_START };
+ sal_uInt16 nIndex;
+
+ for( nIndex = 0; nIndex < sizeof(nOffsets)/ sizeof(sal_uInt16); nIndex++ )
+ {
+ // #i44723# workaround gcc temporary problem
+ ResId aResId( nOffsets[nIndex] + nIcon, *ImplGetResMgr() );
+ BitmapEx aIcon( aResId );
+
+ // #i81083# convert to 24bit/8bit alpha bitmap
+ Bitmap aBmp = aIcon.GetBitmap();
+ if( aBmp.GetBitCount() != 24 || ! aIcon.IsAlpha() )
+ {
+ if( aBmp.GetBitCount() != 24 )
+ aBmp.Convert( BMP_CONVERSION_24BIT );
+ AlphaMask aMask;
+ if( ! aIcon.IsAlpha() )
+ {
+ switch( aIcon.GetTransparentType() )
+ {
+ case TRANSPARENT_NONE:
+ {
+ sal_uInt8 nTrans = 0;
+ aMask = AlphaMask( aBmp.GetSizePixel(), &nTrans );
+ }
+ break;
+ case TRANSPARENT_COLOR:
+ aMask = AlphaMask( aBmp.CreateMask( aIcon.GetTransparentColor() ) );
+ break;
+ case TRANSPARENT_BITMAP:
+ aMask = AlphaMask( aIcon.GetMask() );
+ break;
+ default:
+ OSL_FAIL( "unhandled transparent type" );
+ break;
+ }
+ }
+ else
+ aMask = aIcon.GetAlpha();
+ aIcon = BitmapEx( aBmp, aMask );
+ }
+
+ ImpBitmap *pIconImpBitmap = aIcon.ImplGetBitmapImpBitmap();
+ ImpBitmap *pIconImpMask = aIcon.ImplGetMaskImpBitmap();
+
+ if( pIconImpBitmap && pIconImpMask )
+ {
+ SalBitmap *pIconBitmap =
+ pIconImpBitmap->ImplGetSalBitmap();
+ SalBitmap *pIconMask =
+ pIconImpMask->ImplGetSalBitmap();
+
+ if( ( pBuf = bitmapToPixbuf( pIconBitmap, pIconMask ) ) )
+ pIcons = g_list_prepend( pIcons, pBuf );
+ }
+ }
+
+ gtk_window_set_icon_list( GTK_WINDOW(m_pWindow), pIcons );
+
+ g_list_foreach( pIcons, reinterpret_cast<GFunc>(g_object_unref), NULL );
+ g_list_free( pIcons );
+}
+
+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 = NULL;
+ 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 & SAL_FRAME_STYLE_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 & SAL_FRAME_STYLE_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 & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
+ 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 & SAL_FRAME_STYLE_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(0);
+ }
+ 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, NULL );
+ 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 & SAL_FRAME_STYLE_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),
+ NULL,
+ &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,
+ basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRX);
+ 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
+
+ // update device in existing graphics
+ for( unsigned int i = 0; i < SAL_N_ELEMENTS( m_aGraphics ); ++i )
+ {
+ if( !m_aGraphics[i].pGraphics )
+ continue;
+ m_aGraphics[i].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, true ) )
+ 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, NULL );
+ else if( bMoved && ! bSized )
+ CallCallback( SALEVENT_MOVE, NULL );
+ else if( bMoved && bSized )
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+
+ 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, NULL );
+ }
+ 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 = NULL;
+ 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 |= SAL_FRAME_STYLE_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 &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
+ bResize = true;
+ }
+
+ if (bResize)
+ {
+ // temporarily re-sizeable
+ if( !(m_nStyle & SAL_FRAME_STYLE_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 & SAL_FRAME_STYLE_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( NULL );
+ 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, NULL );
+
+ 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 : NULL );
+ m_aRestorePosSize = Rectangle();
+ }
+}
+
+/* definitions from xautolock.c (pl15) */
+#define XAUTOLOCK_DISABLE 1
+#define XAUTOLOCK_ENABLE 2
+
+void GtkSalFrame::setAutoLock( bool bLock )
+{
+ if( isChild() || !getDisplay()->IsX11Display() )
+ return;
+
+ GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(m_pWindow) );
+ GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
+ GdkWindow *pRootWin = gdk_screen_get_root_window( pScreen );
+
+ Atom nAtom = XInternAtom( GDK_DISPLAY_XDISPLAY( pDisplay ),
+ "XAUTOLOCK_MESSAGE", False );
+
+ int nMessage = bLock ? XAUTOLOCK_ENABLE : XAUTOLOCK_DISABLE;
+
+ XChangeProperty( GDK_DISPLAY_XDISPLAY( pDisplay ),
+ GDK_WINDOW_XID( pRootWin ),
+ nAtom, XA_INTEGER,
+ 8, PropModeReplace,
+ reinterpret_cast<unsigned char*>(&nMessage),
+ sizeof( nMessage ) );
+}
+
+#ifdef ENABLE_DBUS
+/** cookie is returned as an unsigned integer */
+static guint
+dbus_inhibit_gsm (const gchar *appname,
+ const gchar *reason,
+ guint xid)
+{
+ gboolean res;
+ guint cookie;
+ GError *error = NULL;
+ DBusGProxy *proxy = NULL;
+
+ /* get the DBUS session connection */
+ DBusGConnection *session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (error != NULL) {
+ g_debug ("DBUS cannot connect : %s", error->message);
+ g_error_free (error);
+ return -1;
+ }
+
+ /* get the proxy with gnome-session-manager */
+ proxy = dbus_g_proxy_new_for_name (session_connection,
+ GSM_DBUS_SERVICE,
+ GSM_DBUS_PATH,
+ GSM_DBUS_INTERFACE);
+ if (proxy == NULL) {
+ g_debug ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
+ return -1;
+ }
+
+ res = dbus_g_proxy_call (proxy,
+ "Inhibit", &error,
+ G_TYPE_STRING, appname,
+ G_TYPE_UINT, xid,
+ G_TYPE_STRING, reason,
+ G_TYPE_UINT, 8, //Inhibit the session being marked as idle
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &cookie,
+ G_TYPE_INVALID);
+
+ /* check the return value */
+ if (! res) {
+ cookie = -1;
+ g_debug ("Inhibit method failed");
+ }
+
+ /* check the error value */
+ if (error != NULL) {
+ g_debug ("Inhibit problem : %s", error->message);
+ g_error_free (error);
+ cookie = -1;
+ }
+
+ g_object_unref (G_OBJECT (proxy));
+ return cookie;
+}
+
+static void
+dbus_uninhibit_gsm (guint cookie)
+{
+ gboolean res;
+ GError *error = NULL;
+ DBusGProxy *proxy = NULL;
+ DBusGConnection *session_connection = NULL;
+
+ if (cookie == guint(-1)) {
+ g_debug ("Invalid cookie");
+ return;
+ }
+
+ /* get the DBUS session connection */
+ session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (error) {
+ g_debug ("DBUS cannot connect : %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ /* get the proxy with gnome-session-manager */
+ proxy = dbus_g_proxy_new_for_name (session_connection,
+ GSM_DBUS_SERVICE,
+ GSM_DBUS_PATH,
+ GSM_DBUS_INTERFACE);
+ if (proxy == NULL) {
+ g_debug ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
+ return;
+ }
+
+ res = dbus_g_proxy_call (proxy,
+ "Uninhibit",
+ &error,
+ G_TYPE_UINT, cookie,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ /* check the return value */
+ if (! res) {
+ g_debug ("Uninhibit method failed");
+ }
+
+ /* check the error value */
+ if (error != NULL) {
+ g_debug ("Uninhibit problem : %s", error->message);
+ g_error_free (error);
+ cookie = -1;
+ }
+ g_object_unref (G_OBJECT (proxy));
+}
+#endif
+
+void GtkSalFrame::StartPresentation( bool bStart )
+{
+ setAutoLock( !bStart );
+
+ if( !getDisplay()->IsX11Display() )
+ return;
+
+#if !GTK_CHECK_VERSION(3,0,0)
+ Display *pDisplay = GDK_DISPLAY_XDISPLAY( getGdkDisplay() );
+
+ int nTimeout, nInterval, bPreferBlanking, bAllowExposures;
+ XGetScreenSaver( pDisplay, &nTimeout, &nInterval,
+ &bPreferBlanking, &bAllowExposures );
+#endif
+ if( bStart )
+ {
+#if !GTK_CHECK_VERSION(3,0,0)
+ if ( nTimeout )
+ {
+ m_nSavedScreenSaverTimeout = nTimeout;
+ XResetScreenSaver( pDisplay );
+ XSetScreenSaver( pDisplay, 0, nInterval,
+ bPreferBlanking, bAllowExposures );
+ }
+#endif
+#ifdef ENABLE_DBUS
+ m_nGSMCookie = dbus_inhibit_gsm(g_get_application_name(), "presentation",
+ widget_get_xid(m_pWindow));
+#endif
+ }
+ else
+ {
+#if !GTK_CHECK_VERSION(3,0,0)
+ if( m_nSavedScreenSaverTimeout )
+ XSetScreenSaver( pDisplay, m_nSavedScreenSaverTimeout,
+ nInterval, bPreferBlanking,
+ bAllowExposures );
+#endif
+ m_nSavedScreenSaverTimeout = 0;
+#ifdef ENABLE_DBUS
+ dbus_uninhibit_gsm(m_nGSMCookie);
+#endif
+ }
+}
+
+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, true ) )
+ 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 & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_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, false );
+ 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, NULL, 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 )
+{
+ 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), NULL, 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 : NULL );
+}
+
+void GtkSalFrame::SetPointerPos( long nX, long nY )
+{
+ GtkSalFrame* pFrame = this;
+ while( pFrame && pFrame->isChild( false, true ) )
+ 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
+}
+
+void GtkSalFrame::Sync()
+{
+ gdk_display_sync( getGdkDisplay() );
+}
+
+#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 == NULL || pGdkModifiers == NULL )
+ 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;
+ case KEY_PASTE: nKeyCode = GDK_Paste; break;
+ case KEY_OPEN: nKeyCode = GDK_Open; break;
+ }
+ }
+
+ *pGdkKeyCode = nKeyCode;
+}
+
+OUString GtkSalFrame::GetKeyName( sal_uInt16 nKeyCode )
+{
+#if !GTK_CHECK_VERSION(3,0,0)
+ return getDisplay()->GetKeyName( nKeyCode );
+#else
+ guint nGtkKeyCode;
+ GdkModifierType nGtkModifiers;
+ KeyCodeToGdkKey(nKeyCode, &nGtkKeyCode, &nGtkModifiers );
+
+ gchar* pName = gtk_accelerator_get_label(nGtkKeyCode, nGtkModifiers);
+ OUString aRet(pName, rtl_str_getLength(pName), RTL_TEXTENCODING_UTF8);
+ g_free(pName);
+ return aRet;
+#endif
+}
+
+GdkDisplay *GtkSalFrame::getGdkDisplay()
+{
+ return GetGtkSalData()->GetGdkDisplay();
+}
+
+GtkSalDisplay *GtkSalFrame::getDisplay()
+{
+ return GetGtkSalData()->GetGtkDisplay();
+}
+
+SalFrame::SalPointerState GtkSalFrame::GetPointerState()
+{
+ SalPointerState aState;
+ GdkScreen* pScreen;
+ gint x, y;
+ GdkModifierType aMask;
+ gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
+ aState.maPos = Point( x - maGeometry.nX, y - maGeometry.nY );
+ aState.mnState = GetMouseModCode( aMask );
+ return aState;
+}
+
+KeyIndicatorState GtkSalFrame::GetIndicatorState()
+{
+#if !GTK_CHECK_VERSION(3,0,0)
+ return GetGtkSalData()->GetGtkDisplay()->GetIndicatorState();
+#else
+ KeyIndicatorState nState = KeyIndicatorState::NONE;
+
+ GdkKeymap *pKeyMap = gdk_keymap_get_for_display(getGdkDisplay());
+
+ if (gdk_keymap_get_caps_lock_state(pKeyMap))
+ nState |= KeyIndicatorState::CAPSLOCK;
+ if (gdk_keymap_get_num_lock_state(pKeyMap))
+ nState |= KeyIndicatorState::NUMLOCK;
+#if GTK_CHECK_VERSION(3,18,0)
+ if (gdk_keymap_get_scroll_lock_state(pKeyMap))
+ nState |= KeyIndicatorState::SCROLLLOCK;
+#endif
+ return nState;
+#endif
+}
+
+void GtkSalFrame::SimulateKeyPress( sal_uInt16 nKeyCode )
+{
+#if !GTK_CHECK_VERSION(3,0,0)
+ GetGtkSalData()->GetGtkDisplay()->SimulateKeyPress(nKeyCode);
+#else
+ g_warning ("missing simulate keypress %d", nKeyCode);
+#endif
+}
+
+void GtkSalFrame::SetInputContext( SalInputContext* pContext )
+{
+ if( ! pContext )
+ return;
+
+ if( ! (pContext->mnOptions & InputContextFlags::Text) )
+ return;
+
+ // create a new im context
+ if( ! m_pIMHandler )
+ m_pIMHandler = new IMHandler( this );
+}
+
+void GtkSalFrame::EndExtTextInput( sal_uInt16 nFlags )
+{
+ if( m_pIMHandler )
+ m_pIMHandler->endExtTextInput( nFlags );
+}
+
+bool GtkSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& )
+{
+ // not supported yet
+ return false;
+}
+
+LanguageType GtkSalFrame::GetInputLanguage()
+{
+ return LANGUAGE_DONTKNOW;
+}
+
+void GtkSalFrame::UpdateSettings( AllSettings& rSettings )
+{
+ if( ! m_pWindow )
+ return;
+
+ GtkSalGraphics* pGraphics = static_cast<GtkSalGraphics*>(m_aGraphics[0].pGraphics);
+ bool bFreeGraphics = false;
+ if( ! pGraphics )
+ {
+ pGraphics = static_cast<GtkSalGraphics*>(AcquireGraphics());
+ if ( !pGraphics )
+ {
+ SAL_WARN("vcl", "Could not get graphics - unable to update settings");
+ return;
+ }
+ bFreeGraphics = true;
+ }
+
+ pGraphics->updateSettings( rSettings );
+
+ if( bFreeGraphics )
+ ReleaseGraphics( pGraphics );
+}
+
+void GtkSalFrame::Beep()
+{
+ gdk_display_beep( getGdkDisplay() );
+}
+
+const SystemEnvData* GtkSalFrame::GetSystemData() const
+{
+ return &m_aSystemData;
+}
+
+void GtkSalFrame::SetParent( SalFrame* pNewParent )
+{
+ if( m_pParent )
+ m_pParent->m_aChildren.remove( this );
+ m_pParent = static_cast<GtkSalFrame*>(pNewParent);
+ if( m_pParent )
+ m_pParent->m_aChildren.push_back( this );
+ if( ! isChild() )
+ gtk_window_set_transient_for( GTK_WINDOW(m_pWindow),
+ (m_pParent && ! m_pParent->isChild(true,false)) ? GTK_WINDOW(m_pParent->m_pWindow) : NULL
+ );
+}
+
+#if !GTK_CHECK_VERSION(3,0,0)
+
+void GtkSalFrame::createNewWindow( ::Window aNewParent, bool bXEmbed, SalX11Screen nXScreen )
+{
+ bool bWasVisible = m_pWindow && IS_WIDGET_MAPPED(m_pWindow);
+ if( bWasVisible )
+ Show( false );
+
+ if( (int)nXScreen.getXScreen() >= getDisplay()->GetXScreenCount() )
+ nXScreen = m_nXScreen;
+
+ SystemParentData aParentData;
+ aParentData.aWindow = aNewParent;
+ aParentData.bXEmbedSupport = bXEmbed;
+ if( aNewParent == None )
+ {
+ aNewParent = getDisplay()->GetRootWindow(nXScreen);
+ aParentData.aWindow = None;
+ aParentData.bXEmbedSupport = false;
+ }
+ else
+ {
+ // is new parent a root window ?
+ Display* pDisp = getDisplay()->GetDisplay();
+ int nScreens = getDisplay()->GetXScreenCount();
+ for( int i = 0; i < nScreens; i++ )
+ {
+ if( aNewParent == RootWindow( pDisp, i ) )
+ {
+ nXScreen = SalX11Screen( i );
+ aParentData.aWindow = None;
+ aParentData.bXEmbedSupport = false;
+ break;
+ }
+ }
+ }
+
+ // free xrender resources
+ for( unsigned int i = 0; i < SAL_N_ELEMENTS(m_aGraphics); i++ )
+ if( m_aGraphics[i].bInUse )
+ m_aGraphics[i].pGraphics->SetDrawable( None, m_nXScreen );
+
+ // first deinit frame
+ if( m_pIMHandler )
+ {
+ delete m_pIMHandler;
+ m_pIMHandler = NULL;
+ }
+ if( m_pRegion )
+ {
+ gdk_region_destroy( m_pRegion );
+ }
+
+ 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) );
+ if( m_pWindow )
+ 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 ) );
+
+ // init new window
+ m_bDefaultPos = m_bDefaultSize = false;
+ if( aParentData.aWindow != None )
+ {
+ m_nStyle |= SAL_FRAME_STYLE_PLUG;
+ Init( &aParentData );
+ }
+ else
+ {
+ m_nStyle &= ~SAL_FRAME_STYLE_PLUG;
+ Init( (m_pParent && m_pParent->m_nXScreen == m_nXScreen) ? m_pParent : NULL, m_nStyle );
+ }
+
+ // update graphics
+ for( unsigned int i = 0; i < SAL_N_ELEMENTS(m_aGraphics); i++ )
+ {
+ if( m_aGraphics[i].bInUse )
+ {
+ m_aGraphics[i].pGraphics->SetDrawable( widget_get_xid(m_pWindow), m_nXScreen );
+ m_aGraphics[i].pGraphics->SetWindow( m_pWindow );
+ }
+ }
+
+ if( ! m_aTitle.isEmpty() )
+ SetTitle( m_aTitle );
+
+ if( bWasVisible )
+ Show( true );
+
+ std::list< GtkSalFrame* > aChildren = m_aChildren;
+ m_aChildren.clear();
+ for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
+ (*it)->createNewWindow( None, false, m_nXScreen );
+
+ // FIXME: SalObjects
+}
+#endif
+
+bool GtkSalFrame::SetPluginParent( SystemParentData* pSysParent )
+{
+#if !GTK_CHECK_VERSION(3,0,0)
+ GetGenericData()->ErrorTrapPush(); // permanantly ignore unruly children's errors
+ createNewWindow( pSysParent->aWindow, (pSysParent->nSize > sizeof(long)) && pSysParent->bXEmbedSupport, m_nXScreen );
+ return true;
+#else
+ (void)pSysParent;
+ //FIXME: no SetPluginParent impl. for gtk3
+ return false;
+#endif
+}
+
+void GtkSalFrame::ResetClipRegion()
+{
+ if( m_pWindow )
+ gdk_window_shape_combine_region( widget_get_window( m_pWindow ), NULL, 0, 0 );
+}
+
+void GtkSalFrame::BeginSetClipRegion( sal_uLong )
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ if( m_pRegion )
+ cairo_region_destroy( m_pRegion );
+ m_pRegion = cairo_region_create();
+#else
+ if( m_pRegion )
+ gdk_region_destroy( m_pRegion );
+ m_pRegion = gdk_region_new();
+#endif
+}
+
+void GtkSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( m_pRegion )
+ {
+ GdkRectangle aRect;
+ aRect.x = nX;
+ aRect.y = nY;
+ aRect.width = nWidth;
+ aRect.height = nHeight;
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_region_union_rectangle( m_pRegion, &aRect );
+#else
+ gdk_region_union_with_rect( m_pRegion, &aRect );
+#endif
+ }
+}
+
+void GtkSalFrame::EndSetClipRegion()
+{
+ if( m_pWindow && m_pRegion )
+ gdk_window_shape_combine_region( widget_get_window(m_pWindow), m_pRegion, 0, 0 );
+}
+
+#if !GTK_CHECK_VERSION(3,0,0)
+bool GtkSalFrame::Dispatch( const XEvent* pEvent )
+{
+ bool bContinueDispatch = true;
+
+ if( pEvent->type == PropertyNotify )
+ {
+ vcl_sal::WMAdaptor* pAdaptor = getDisplay()->getWMAdaptor();
+ Atom nDesktopAtom = pAdaptor->getAtom( vcl_sal::WMAdaptor::NET_WM_DESKTOP );
+ if( pEvent->xproperty.atom == nDesktopAtom &&
+ pEvent->xproperty.state == PropertyNewValue )
+ {
+ m_nWorkArea = pAdaptor->getWindowWorkArea( widget_get_xid(m_pWindow) );
+ }
+ }
+ else if( pEvent->type == ConfigureNotify )
+ {
+ if( m_pForeignParent && pEvent->xconfigure.window == m_aForeignParentWindow )
+ {
+ bContinueDispatch = false;
+ gtk_window_resize( GTK_WINDOW(m_pWindow), pEvent->xconfigure.width, pEvent->xconfigure.height );
+ if( ( sal::static_int_cast< int >(maGeometry.nWidth) !=
+ pEvent->xconfigure.width ) ||
+ ( sal::static_int_cast< int >(maGeometry.nHeight) !=
+ pEvent->xconfigure.height ) )
+ {
+ maGeometry.nWidth = pEvent->xconfigure.width;
+ maGeometry.nHeight = pEvent->xconfigure.height;
+ setMinMaxSize();
+ getDisplay()->SendInternalEvent( this, NULL, SALEVENT_RESIZE );
+ }
+ }
+ else if( m_pForeignTopLevel && pEvent->xconfigure.window == m_aForeignTopLevelWindow )
+ {
+ bContinueDispatch = false;
+ // update position
+ int x = 0, y = 0;
+ ::Window aChild;
+ XTranslateCoordinates( getDisplay()->GetDisplay(),
+ widget_get_xid(m_pWindow),
+ getDisplay()->GetRootWindow( getDisplay()->GetDefaultXScreen() ),
+ 0, 0,
+ &x, &y,
+ &aChild );
+ if( x != maGeometry.nX || y != maGeometry.nY )
+ {
+ maGeometry.nX = x;
+ maGeometry.nY = y;
+ getDisplay()->SendInternalEvent( this, NULL, SALEVENT_MOVE );
+ }
+ }
+ }
+ else if( pEvent->type == ClientMessage &&
+ pEvent->xclient.message_type == getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED ) &&
+ pEvent->xclient.window == widget_get_xid(m_pWindow) &&
+ m_bWindowIsGtkPlug
+ )
+ {
+ // FIXME: this should not be necessary, GtkPlug should do this
+ // transparently for us
+ if( pEvent->xclient.data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
+ pEvent->xclient.data.l[1] == 2 // XEMBED_WINDOW_DEACTIVATE
+ )
+ {
+ GdkEventFocus aEvent;
+ aEvent.type = GDK_FOCUS_CHANGE;
+ aEvent.window = widget_get_window( m_pWindow );
+ aEvent.send_event = gint8(TRUE);
+ aEvent.in = gint16(pEvent->xclient.data.l[1] == 1);
+ signalFocus( m_pWindow, &aEvent, this );
+ }
+ }
+
+ return bContinueDispatch;
+}
+#endif
+
+gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ SalMouseEvent aEvent;
+ sal_uInt16 nEventType = 0;
+ switch( pEvent->type )
+ {
+ case GDK_BUTTON_PRESS:
+ nEventType = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+ case GDK_BUTTON_RELEASE:
+ nEventType = SALEVENT_MOUSEBUTTONUP;
+ break;
+ default:
+ return false;
+ }
+ switch( pEvent->button )
+ {
+ case 1: aEvent.mnButton = MOUSE_LEFT; break;
+ case 2: aEvent.mnButton = MOUSE_MIDDLE; break;
+ case 3: aEvent.mnButton = MOUSE_RIGHT; break;
+ default: return false;
+ }
+ aEvent.mnTime = pEvent->time;
+ aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
+ aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
+ aEvent.mnCode = GetMouseModCode( pEvent->state );
+
+ bool bClosePopups = false;
+ if( pEvent->type == GDK_BUTTON_PRESS &&
+ (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) == 0
+ )
+ {
+ if( m_nFloats > 0 )
+ {
+ // close popups if user clicks outside our application
+ gint x, y;
+ bClosePopups = (gdk_display_get_window_at_pointer( GtkSalFrame::getGdkDisplay(), &x, &y ) == NULL);
+ }
+ /* #i30306# release implicit pointer grab if no popups are open; else
+ * Drag cannot grab the pointer and will fail.
+ */
+ if( m_nFloats < 1 || bClosePopups )
+ gdk_display_pointer_ungrab( GtkSalFrame::getGdkDisplay(), GDK_CURRENT_TIME );
+ }
+
+ if( pThis->m_bWindowIsGtkPlug &&
+ pEvent->type == GDK_BUTTON_PRESS &&
+ pEvent->button == 1 )
+ {
+ pThis->askForXEmbedFocus( pEvent->time );
+ }
+
+ // --- RTL --- (mirror mouse pos)
+ if( AllSettings::GetLayoutRTL() )
+ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+
+ vcl::DeletionListener aDel( pThis );
+
+ pThis->CallCallback( nEventType, &aEvent );
+
+ if( ! aDel.isDeleted() )
+ {
+ if( bClosePopups )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maWinData.mpFirstFloat )
+ {
+ static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
+ if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FloatWinPopupFlags::NoAppFocusClose) && !(pEnv && *pEnv) )
+ pSVData->maWinData.mpFirstFloat->EndPopupMode( FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll );
+ }
+ }
+
+ if( ! aDel.isDeleted() )
+ {
+ int frame_x = (int)(pEvent->x_root - pEvent->x);
+ int frame_y = (int)(pEvent->y_root - pEvent->y);
+ if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
+ {
+ pThis->maGeometry.nX = frame_x;
+ pThis->maGeometry.nY = frame_y;
+ pThis->CallCallback( SALEVENT_MOVE, NULL );
+ }
+ }
+ }
+
+ return true;
+}
+
+#if GTK_CHECK_VERSION(3,0,0)
+void GtkSalFrame::signalFlagsChanged( GtkWidget* , GtkStateFlags state, gpointer frame )
+{
+ //TO-DO: This isn't as helpful as I'd like it to be. The color selector puts the main
+ //windows into the backdrop, disabling everything, and the floating navigator window
+ //is also problematic.
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ bool bOldBackDrop = state & GTK_STATE_FLAG_BACKDROP;
+ bool bNewBackDrop = (gtk_widget_get_state_flags(GTK_WIDGET(pThis->m_pWindow)) & GTK_STATE_FLAG_BACKDROP);
+ if (bNewBackDrop && !bOldBackDrop)
+ {
+ pThis->GetWindow()->Disable();
+ }
+ else if (bOldBackDrop && !bNewBackDrop)
+ {
+ pThis->GetWindow()->Enable();
+ }
+}
+#endif
+
+gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEvent* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ GdkEventScroll* pSEvent = reinterpret_cast<GdkEventScroll*>(pEvent);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ // gnome#726878 check for duplicate legacy scroll event
+ if (pSEvent->direction != GDK_SCROLL_SMOOTH &&
+ pThis->m_nLastScrollEventTime == pSEvent->time)
+ {
+ return true;
+ }
+#endif
+
+ SalWheelMouseEvent aEvent;
+
+ aEvent.mnTime = pSEvent->time;
+ aEvent.mnX = (sal_uLong)pSEvent->x;
+ aEvent.mnY = (sal_uLong)pSEvent->y;
+ aEvent.mnCode = GetMouseModCode( pSEvent->state );
+ aEvent.mnScrollLines = 3;
+
+ switch (pSEvent->direction)
+ {
+#if GTK_CHECK_VERSION(3,0,0)
+ case GDK_SCROLL_SMOOTH:
+ {
+ double delta_x, delta_y;
+ gdk_event_get_scroll_deltas(pEvent, &delta_x, &delta_y);
+ //pick the bigger one I guess
+ aEvent.mbHorz = fabs(delta_x) > fabs(delta_y);
+ if (aEvent.mbHorz)
+ aEvent.mnDelta = -delta_x;
+ else
+ aEvent.mnDelta = -delta_y;
+ aEvent.mnScrollLines = 1;
+ pThis->m_nLastScrollEventTime = pSEvent->time;
+ break;
+ }
+#endif
+ case GDK_SCROLL_UP:
+ aEvent.mnDelta = 120;
+ aEvent.mbHorz = false;
+ break;
+ case GDK_SCROLL_DOWN:
+ aEvent.mnDelta = -120;
+ aEvent.mbHorz = false;
+ break;
+ case GDK_SCROLL_LEFT:
+ aEvent.mbHorz = true;
+ aEvent.mnDelta = 120;
+ break;
+ case GDK_SCROLL_RIGHT:
+ aEvent.mnDelta = -120;
+ aEvent.mbHorz = true;
+ break;
+ };
+
+ aEvent.mnNotchDelta = aEvent.mnDelta < 0 ? -1 : 1;
+
+ // --- RTL --- (mirror mouse pos)
+ if( AllSettings::GetLayoutRTL() )
+ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+
+ pThis->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+
+ return true;
+}
+
+#if GTK_CHECK_VERSION(3,14,0)
+void GtkSalFrame::gestureSwipe(GtkGestureSwipe* gesture, gdouble velocity_x, gdouble velocity_y, gpointer frame)
+{
+ gdouble x, y;
+ GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
+ //I feel I want the first point of the sequence, not the last point which
+ //the docs say this gives, but for the moment assume we start and end
+ //within the same vcl window
+ if (gtk_gesture_get_point(GTK_GESTURE(gesture), sequence, &x, &y))
+ {
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ SalSwipeEvent aEvent;
+ aEvent.mnVelocityX = velocity_x;
+ aEvent.mnVelocityY = velocity_y;
+ aEvent.mnX = x;
+ aEvent.mnY = y;
+
+ pThis->CallCallback(SALEVENT_SWIPE, &aEvent);
+ }
+}
+
+void GtkSalFrame::gestureLongPress(GtkGestureLongPress* gesture, gpointer frame)
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ if(pThis)
+ {
+ SalLongPressEvent aEvent;
+
+ gdouble x, y;
+ GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
+ gtk_gesture_get_point(GTK_GESTURE(gesture), sequence, &x, &y);
+ aEvent.mnX = x;
+ aEvent.mnY = y;
+
+ pThis->CallCallback(SALEVENT_LONGPRESS, &aEvent);
+ }
+}
+
+#endif
+
+gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ SalMouseEvent aEvent;
+ aEvent.mnTime = pEvent->time;
+ aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
+ aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
+ aEvent.mnCode = GetMouseModCode( pEvent->state );
+ aEvent.mnButton = 0;
+
+ // --- RTL --- (mirror mouse pos)
+ if( AllSettings::GetLayoutRTL() )
+ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+
+ vcl::DeletionListener aDel( pThis );
+
+ pThis->CallCallback( SALEVENT_MOUSEMOVE, &aEvent );
+
+ if( ! aDel.isDeleted() )
+ {
+ int frame_x = (int)(pEvent->x_root - pEvent->x);
+ int frame_y = (int)(pEvent->y_root - pEvent->y);
+ if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
+ {
+ pThis->maGeometry.nX = frame_x;
+ pThis->maGeometry.nY = frame_y;
+ pThis->CallCallback( SALEVENT_MOVE, NULL );
+ }
+
+ if( ! aDel.isDeleted() )
+ {
+ // ask for the next hint
+ gint x, y;
+ GdkModifierType mask;
+ gdk_window_get_pointer( widget_get_window(GTK_WIDGET(pThis->m_pWindow)), &x, &y, &mask );
+ }
+ }
+
+ return true;
+}
+
+gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ SalMouseEvent aEvent;
+ aEvent.mnTime = pEvent->time;
+ aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
+ aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
+ aEvent.mnCode = GetMouseModCode( pEvent->state );
+ aEvent.mnButton = 0;
+
+ pThis->CallCallback( (pEvent->type == GDK_ENTER_NOTIFY) ? SALEVENT_MOUSEMOVE : SALEVENT_MOUSELEAVE, &aEvent );
+
+ return true;
+}
+
+#if GTK_CHECK_VERSION(3,0,0)
+
+cairo_t* GtkSalFrame::getCairoContext() const
+{
+ cairo_t* cr = SvpSalGraphics::createCairoContext(m_aFrame);
+ assert(cr);
+ return cr;
+}
+
+void GtkSalFrame::damaged (const basegfx::B2IBox& rDamageRect)
+{
+#if OSL_DEBUG_LEVEL > 1
+ long long area = rDamageRect.getWidth() * rDamageRect.getHeight();
+ if( area > 32 * 1024 )
+ {
+ fprintf( stderr, "bitmap damaged %d %d (%dx%d) area %lld widget\n",
+ (int) rDamageRect.getMinX(),
+ (int) rDamageRect.getMinY(),
+ (int) rDamageRect.getWidth(),
+ (int) rDamageRect.getHeight(),
+ area );
+ }
+#endif
+
+ if (dumpframes)
+ {
+ static int frame;
+ OString tmp("/tmp/frame" + OString::number(frame++) + ".png");
+ cairo_t* cr = getCairoContext();
+ cairo_surface_write_to_png(cairo_get_target(cr), tmp.getStr());
+ cairo_destroy(cr);
+ }
+
+ gtk_widget_queue_draw_area(GTK_WIDGET(m_pFixedContainer),
+ rDamageRect.getMinX(),
+ rDamageRect.getMinY(),
+ rDamageRect.getWidth(),
+ rDamageRect.getHeight());
+}
+
+// blit our backing basebmp buffer to the target cairo context cr
+gboolean GtkSalFrame::signalDraw( GtkWidget*, cairo_t *cr, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ cairo_save(cr);
+
+ cairo_t* source = pThis->getCairoContext();
+ cairo_surface_t *pSurface = cairo_get_target(source);
+
+ cairo_set_operator( cr, CAIRO_OPERATOR_OVER );
+ cairo_set_source_surface(cr, pSurface, 0, 0);
+ cairo_paint(cr);
+
+ cairo_destroy(source);
+
+ cairo_restore(cr);
+
+ cairo_surface_flush(cairo_get_target(cr));
+
+ return false;
+}
+
+void GtkSalFrame::sizeAllocated(GtkWidget*, GdkRectangle *pAllocation, gpointer frame)
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ bool bSized = false;
+
+ if( pThis->m_bFullscreen || (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)) == SAL_FRAME_STYLE_SIZEABLE )
+ {
+ if( pAllocation->width != (int)pThis->maGeometry.nWidth || pAllocation->height != (int)pThis->maGeometry.nHeight )
+ {
+ bSized = true;
+ pThis->maGeometry.nWidth = pAllocation->width;
+ pThis->maGeometry.nHeight = pAllocation->height;
+ }
+ }
+
+ if( bSized )
+ {
+ pThis->AllocateFrame();
+ pThis->CallCallback( SALEVENT_RESIZE, nullptr );
+ pThis->TriggerPaintEvent();
+ }
+}
+
+gboolean GtkSalFrame::signalConfigure(GtkWidget*, GdkEventConfigure* pEvent, gpointer frame)
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ pThis->m_bPaintsBlocked = false;
+
+ bool bMoved = false;
+ int x = pEvent->x, y = pEvent->y;
+
+ /* HACK: during sizing/moving a toolbar pThis->maGeometry is actually
+ * already exact; even worse: due to the asynchronicity of configure
+ * events the borderwindow which would evaluate this event
+ * would size/move based on wrong data if we would actually evaluate
+ * this event. So let's swallow it.
+ */
+ if( (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
+ GtkSalFrame::getDisplay()->GetCaptureFrame() == pThis )
+ return false;
+
+ /* #i31785# claims we cannot trust the x,y members of the event;
+ * they are e.g. not set correctly on maximize/demaximize;
+ * yet the gdkdisplay-x11.c code handling configure_events has
+ * done this XTranslateCoordinates work since the day ~zero.
+ */
+ if( x != pThis->maGeometry.nX || y != pThis->maGeometry.nY )
+ {
+ bMoved = true;
+ pThis->maGeometry.nX = x;
+ pThis->maGeometry.nY = y;
+ }
+
+ // update decoration hints
+ if( ! (pThis->m_nStyle & SAL_FRAME_STYLE_PLUG) )
+ {
+ GdkRectangle aRect;
+ gdk_window_get_frame_extents( widget_get_window(GTK_WIDGET(pThis->m_pWindow)), &aRect );
+ pThis->maGeometry.nTopDecoration = y - aRect.y;
+ pThis->maGeometry.nBottomDecoration = aRect.y + aRect.height - y - pEvent->height;
+ pThis->maGeometry.nLeftDecoration = x - aRect.x;
+ pThis->maGeometry.nRightDecoration = aRect.x + aRect.width - x - pEvent->width;
+ }
+ else
+ {
+ pThis->maGeometry.nTopDecoration =
+ pThis->maGeometry.nBottomDecoration =
+ pThis->maGeometry.nLeftDecoration =
+ pThis->maGeometry.nRightDecoration = 0;
+ }
+
+ pThis->updateScreenNumber();
+
+ if (bMoved)
+ pThis->CallCallback(SALEVENT_MOVE, nullptr);
+
+ return false;
+}
+#else
+gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ pThis->m_bPaintsBlocked = false;
+
+ struct SalPaintEvent aEvent( pEvent->area.x, pEvent->area.y, pEvent->area.width, pEvent->area.height );
+
+ pThis->CallCallback( SALEVENT_PAINT, &aEvent );
+
+ return false;
+}
+
+gboolean GtkSalFrame::signalConfigure( GtkWidget*, GdkEventConfigure* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ pThis->m_bPaintsBlocked = false;
+
+ bool bMoved = false, bSized = false;
+ int x = pEvent->x, y = pEvent->y;
+
+ /* HACK: during sizing/moving a toolbar pThis->maGeometry is actually
+ * already exact; even worse: due to the asynchronicity of configure
+ * events the borderwindow which would evaluate this event
+ * would size/move based on wrong data if we would actually evaluate
+ * this event. So let's swallow it.
+ */
+ if( (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
+ GtkSalFrame::getDisplay()->GetCaptureFrame() == pThis )
+ return false;
+
+ /* #i31785# claims we cannot trust the x,y members of the event;
+ * they are e.g. not set correctly on maximize/demaximize;
+ * yet the gdkdisplay-x11.c code handling configure_events has
+ * done this XTranslateCoordinates work since the day ~zero.
+ */
+ if( x != pThis->maGeometry.nX || y != pThis->maGeometry.nY )
+ {
+ bMoved = true;
+ pThis->maGeometry.nX = x;
+ pThis->maGeometry.nY = y;
+ }
+ /* #i86302#
+ * for non sizeable windows we set the min and max hint for the window manager to
+ * achieve correct sizing. However this is asynchronous and e.g. on Compiz
+ * it sometimes happens that the window gets resized to another size (some default)
+ * if we update the size here, subsequent setMinMaxSize will use this wrong size
+ * - which is not good since the window manager will now size the window back to this
+ * wrong size at some point.
+ */
+ if( pThis->m_bFullscreen || (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)) == SAL_FRAME_STYLE_SIZEABLE )
+ {
+ if( pEvent->width != (int)pThis->maGeometry.nWidth || pEvent->height != (int)pThis->maGeometry.nHeight )
+ {
+ bSized = true;
+ pThis->maGeometry.nWidth = pEvent->width;
+ pThis->maGeometry.nHeight = pEvent->height;
+ }
+ }
+
+ // update decoration hints
+ if( ! (pThis->m_nStyle & SAL_FRAME_STYLE_PLUG) )
+ {
+ GdkRectangle aRect;
+ gdk_window_get_frame_extents( widget_get_window(GTK_WIDGET(pThis->m_pWindow)), &aRect );
+ pThis->maGeometry.nTopDecoration = y - aRect.y;
+ pThis->maGeometry.nBottomDecoration = aRect.y + aRect.height - y - pEvent->height;
+ pThis->maGeometry.nLeftDecoration = x - aRect.x;
+ pThis->maGeometry.nRightDecoration = aRect.x + aRect.width - x - pEvent->width;
+ }
+ else
+ {
+ pThis->maGeometry.nTopDecoration =
+ pThis->maGeometry.nBottomDecoration =
+ pThis->maGeometry.nLeftDecoration =
+ pThis->maGeometry.nRightDecoration = 0;
+ }
+
+ pThis->updateScreenNumber();
+ if( bSized )
+ pThis->AllocateFrame();
+
+ if( bMoved && bSized )
+ pThis->CallCallback( SALEVENT_MOVERESIZE, nullptr );
+ else if( bMoved )
+ pThis->CallCallback( SALEVENT_MOVE, nullptr );
+ else if( bSized )
+ pThis->CallCallback( SALEVENT_RESIZE, nullptr );
+
+ if (bSized)
+ pThis->TriggerPaintEvent();
+ return false;
+}
+
+#endif // GTK_CHECK_VERSION(3,0,0)
+
+void GtkSalFrame::TriggerPaintEvent()
+{
+ //Under gtk2 we can basically paint directly into the XWindow and on
+ //additional "expose-event" events we can re-render the missing pieces
+ //
+ //Under gtk3 we have to keep our own buffer up to date and flush it into
+ //the given cairo context on "draw". So we emit a paint event on
+ //opportune resize trigger events to initially fill our backbuffer and then
+ //keep it up to date with our direct paints and tell gtk those regions
+ //have changed and then blit them into the provided cairo context when
+ //we get the "draw"
+ //
+ //The other alternative was to always paint everything on "draw", but
+ //that duplicates the amount of drawing and is hideously slow
+#if GTK_CHECK_VERSION(3,0,0)
+ SAL_INFO("vcl.gtk3", "force painting" << 0 << "," << 0 << " " << maGeometry.nWidth << "x" << maGeometry.nHeight);
+ SalPaintEvent aPaintEvt(0, 0, maGeometry.nWidth, maGeometry.nHeight, true);
+ CallCallback(SALEVENT_PAINT, &aPaintEvt);
+ gtk_widget_queue_draw(GTK_WIDGET(m_pFixedContainer));
+#endif
+}
+
+gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ SalGenericInstance *pSalInstance =
+ static_cast< SalGenericInstance* >(GetSalData()->m_pInstance);
+
+ // check if printers have changed (analogous to salframe focus handler)
+ pSalInstance->updatePrinterUpdate();
+
+ if( !pEvent->in )
+ {
+ pThis->m_nKeyModifiers = 0;
+ pThis->m_bSendModChangeOnRelease = false;
+ }
+
+ if( pThis->m_pIMHandler )
+ pThis->m_pIMHandler->focusChanged( pEvent->in );
+
+ // ask for changed printers like generic implementation
+ if( pEvent->in && pSalInstance->isPrinterInit() )
+ pSalInstance->updatePrinterUpdate();
+
+ // FIXME: find out who the hell steals the focus from our frame
+ // while we have the pointer grabbed, this should not come from
+ // the window manager. Is this an event that was still queued ?
+ // The focus does not seem to get set inside our process
+
+ // in the meantime do not propagate focus get/lose if floats are open
+ if( m_nFloats == 0 )
+ pThis->CallCallback( pEvent->in ? SALEVENT_GETFOCUS : SALEVENT_LOSEFOCUS, NULL );
+
+ return false;
+}
+
+#if !GTK_CHECK_VERSION(3,8,0)
+static OString getDisplayString()
+{
+ int nParams = rtl_getAppCommandArgCount();
+ OUString aParam;
+ for( int i = 0; i < nParams; i++ )
+ {
+ rtl_getAppCommandArg( i, &aParam.pData );
+ if( i < nParams-1 && (aParam == "-display" || aParam == "--display" ) )
+ {
+ rtl_getAppCommandArg( i+1, &aParam.pData );
+ return OUStringToOString( aParam, osl_getThreadTextEncoding() );
+ }
+ }
+ return OString();
+}
+#endif
+
+gboolean GtkSalFrame::signalMap( GtkWidget *pWidget, GdkEvent*, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+#if !GTK_CHECK_VERSION(3,8,0)
+ //Spawn off a helper program that will attempt to set this fullscreen
+ //window to span all displays.
+ if (pThis->m_bFullscreen && pThis->m_bSpanMonitorsWhenFullscreen)
+ {
+ GdkWindow* gdkwin = widget_get_window(pThis->m_pWindow);
+ if (gdkwin)
+ {
+ OUString sProgramURL( "$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER "/xid-fullscreen-on-all-monitors");
+ rtl::Bootstrap::expandMacros(sProgramURL);
+ OUString sProgram;
+ if (osl::FileBase::getSystemPathFromFileURL(sProgramURL, sProgram) == osl::File::E_None)
+ {
+ OString sFinalProgram(OUStringToOString(sProgram, osl_getThreadTextEncoding())
+ + " " + OString::number((int)GDK_WINDOW_XID(gdkwin)));
+ OString sDisplay(getDisplayString());
+ if (!sDisplay.isEmpty())
+ {
+ sFinalProgram += "--display " + sDisplay;
+ }
+ int returnValue = system(sFinalProgram.getStr());
+ (void)returnValue;
+ }
+ }
+ }
+#endif
+
+ bool bSetFocus = pThis->m_bSetFocusOnMap;
+ pThis->m_bSetFocusOnMap = false;
+
+#if !GTK_CHECK_VERSION(3,0,0)
+ if( bSetFocus )
+ {
+ GetGenericData()->ErrorTrapPush();
+ XSetInputFocus( GtkSalFrame::getDisplay()->GetDisplay(),
+ widget_get_xid(pWidget),
+ RevertToParent, CurrentTime );
+ XSync( GtkSalFrame::getDisplay()->GetDisplay(), False );
+ GetGenericData()->ErrorTrapPop();
+ }
+#else
+ (void)pWidget; (void)bSetFocus;
+ //FIXME: no set input focus ...
+#endif
+
+ pThis->CallCallback( SALEVENT_RESIZE, NULL );
+ pThis->TriggerPaintEvent();
+
+ return false;
+}
+
+gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ pThis->CallCallback( SALEVENT_RESIZE, NULL );
+
+ return false;
+}
+
+gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ vcl::DeletionListener aDel( pThis );
+
+ if( pThis->m_pIMHandler )
+ {
+ if( pThis->m_pIMHandler->handleKeyEvent( pEvent ) )
+ return true;
+ }
+
+ // handle modifiers
+ if( pEvent->keyval == GDK_Shift_L || pEvent->keyval == GDK_Shift_R ||
+ pEvent->keyval == GDK_Control_L || pEvent->keyval == GDK_Control_R ||
+ pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ||
+ pEvent->keyval == GDK_Meta_L || pEvent->keyval == GDK_Meta_R ||
+ pEvent->keyval == GDK_Super_L || pEvent->keyval == GDK_Super_R )
+ {
+ SalKeyModEvent aModEvt;
+
+ sal_uInt16 nModCode = GetKeyModCode( pEvent->state );
+
+ aModEvt.mnModKeyCode = 0; // emit no MODKEYCHANGE events
+ if( pEvent->type == GDK_KEY_PRESS && !pThis->m_nKeyModifiers )
+ pThis->m_bSendModChangeOnRelease = true;
+
+ else if( pEvent->type == GDK_KEY_RELEASE &&
+ pThis->m_bSendModChangeOnRelease )
+ {
+ aModEvt.mnModKeyCode = pThis->m_nKeyModifiers;
+ pThis->m_nKeyModifiers = 0;
+ }
+
+ sal_uInt16 nExtModMask = 0;
+ sal_uInt16 nModMask = 0;
+ // pressing just the ctrl key leads to a keysym of XK_Control but
+ // the event state does not contain ControlMask. In the release
+ // event its the other way round: it does contain the Control mask.
+ // The modifier mode therefore has to be adapted manually.
+ switch( pEvent->keyval )
+ {
+ case GDK_Control_L:
+ nExtModMask = MODKEY_LMOD1;
+ nModMask = KEY_MOD1;
+ break;
+ case GDK_Control_R:
+ nExtModMask = MODKEY_RMOD1;
+ nModMask = KEY_MOD1;
+ break;
+ case GDK_Alt_L:
+ nExtModMask = MODKEY_LMOD2;
+ nModMask = KEY_MOD2;
+ break;
+ case GDK_Alt_R:
+ nExtModMask = MODKEY_RMOD2;
+ nModMask = KEY_MOD2;
+ break;
+ case GDK_Shift_L:
+ nExtModMask = MODKEY_LSHIFT;
+ nModMask = KEY_SHIFT;
+ break;
+ case GDK_Shift_R:
+ nExtModMask = MODKEY_RSHIFT;
+ nModMask = KEY_SHIFT;
+ break;
+ // Map Meta/Super to MOD3 modifier on all Unix systems
+ // except Mac OS X
+ case GDK_Meta_L:
+ case GDK_Super_L:
+ nExtModMask = MODKEY_LMOD3;
+ nModMask = KEY_MOD3;
+ break;
+ case GDK_Meta_R:
+ case GDK_Super_R:
+ nExtModMask = MODKEY_RMOD3;
+ nModMask = KEY_MOD3;
+ break;
+ }
+ if( pEvent->type == GDK_KEY_RELEASE )
+ {
+ nModCode &= ~nModMask;
+ pThis->m_nKeyModifiers &= ~nExtModMask;
+ }
+ else
+ {
+ nModCode |= nModMask;
+ pThis->m_nKeyModifiers |= nExtModMask;
+ }
+
+ aModEvt.mnCode = nModCode;
+ aModEvt.mnTime = pEvent->time;
+
+ pThis->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
+
+ }
+ else
+ {
+ pThis->doKeyCallback( pEvent->state,
+ pEvent->keyval,
+ pEvent->hardware_keycode,
+ pEvent->group,
+ pEvent->time,
+ sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )),
+ (pEvent->type == GDK_KEY_PRESS),
+ false );
+ if( ! aDel.isDeleted() )
+ pThis->m_bSendModChangeOnRelease = false;
+ }
+
+ if( !aDel.isDeleted() && pThis->m_pIMHandler )
+ pThis->m_pIMHandler->updateIMSpotLocation();
+
+ return true;
+}
+
+gboolean GtkSalFrame::signalDelete( GtkWidget*, GdkEvent*, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ //If we went into the backdrop we disabled the toplevel window, if we
+ //receive a delete here, re-enable so we can process it
+ bool bBackDrop = (gtk_widget_get_state_flags(GTK_WIDGET(pThis->m_pWindow)) & GTK_STATE_FLAG_BACKDROP);
+ if (bBackDrop)
+ pThis->GetWindow()->Enable();
+#endif
+
+ pThis->CallCallback( SALEVENT_CLOSE, NULL );
+
+ return true;
+}
+
+void GtkSalFrame::signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ // every frame gets an initial style set on creation
+ // do not post these as the whole application tends to
+ // redraw itself to adjust to the new style
+ // where there IS no new style resulting in tremendous unnecessary flickering
+ if( pPrevious != NULL )
+ {
+ // signalStyleSet does NOT usually have the gdk lock
+ // so post user event to safely dispatch the SALEVENT_SETTINGSCHANGED
+ // note: settings changed for multiple frames is avoided in winproc.cxx ImplHandleSettings
+ GtkSalFrame::getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_SETTINGSCHANGED );
+ GtkSalFrame::getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_FONTCHANGED );
+ }
+
+#if !GTK_CHECK_VERSION(3,0,0)
+ /* #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
+ */
+ GdkWindow* pWin = widget_get_window(GTK_WIDGET(pThis->getWindow()));
+ if( pWin )
+ {
+ ::Window aWin = GDK_WINDOW_XWINDOW(pWin);
+ if( aWin != None )
+ XSetWindowBackgroundPixmap( GtkSalFrame::getDisplay()->GetDisplay(),
+ aWin,
+ pThis->m_hBackgroundPixmap );
+ }
+ if( ! pThis->m_pParent )
+ {
+ // signalize theme changed for NWF caches
+ // FIXME: should be called only once for a style change
+ GtkSalGraphics::bThemeChanged = true;
+ }
+#endif
+}
+
+gboolean GtkSalFrame::signalWindowState( GtkWidget*, GdkEvent* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ if( (pThis->m_nState & GDK_WINDOW_STATE_ICONIFIED) != (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED ) )
+ {
+ GtkSalFrame::getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_RESIZE );
+ pThis->TriggerPaintEvent();
+ }
+
+ if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) &&
+ ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) )
+ {
+ pThis->m_aRestorePosSize =
+ Rectangle( Point( pThis->maGeometry.nX, pThis->maGeometry.nY ),
+ Size( pThis->maGeometry.nWidth, pThis->maGeometry.nHeight ) );
+ }
+ pThis->m_nState = pEvent->window_state.new_window_state;
+
+ #if OSL_DEBUG_LEVEL > 1
+ if( (pEvent->window_state.changed_mask & GDK_WINDOW_STATE_FULLSCREEN) )
+ {
+ fprintf( stderr, "window %p %s full screen state\n",
+ pThis,
+ (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_FULLSCREEN) ? "enters" : "leaves");
+ }
+ #endif
+
+ return false;
+}
+
+gboolean GtkSalFrame::signalVisibility( GtkWidget*, GdkEventVisibility* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ pThis->m_nVisibility = pEvent->state;
+ return true;
+}
+
+void GtkSalFrame::signalDestroy( GtkWidget* pObj, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ if( pObj == pThis->m_pWindow )
+ {
+ pThis->m_pFixedContainer = NULL;
+ pThis->m_pEventBox = NULL;
+ pThis->m_pWindow = NULL;
+ pThis->InvalidateGraphics();
+ }
+}
+
+// GtkSalFrame::IMHandler
+
+GtkSalFrame::IMHandler::IMHandler( GtkSalFrame* pFrame )
+: m_pFrame(pFrame),
+ m_nPrevKeyPresses( 0 ),
+ m_pIMContext( NULL ),
+ m_bFocused( true ),
+ m_bPreeditJustChanged( false )
+{
+ m_aInputEvent.mpTextAttr = NULL;
+ createIMContext();
+}
+
+GtkSalFrame::IMHandler::~IMHandler()
+{
+ // cancel an eventual event posted to begin preedit again
+ GtkSalFrame::getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ deleteIMContext();
+}
+
+void GtkSalFrame::IMHandler::createIMContext()
+{
+ if( ! m_pIMContext )
+ {
+ m_pIMContext = gtk_im_multicontext_new ();
+ g_signal_connect( m_pIMContext, "commit",
+ G_CALLBACK (signalIMCommit), this );
+ g_signal_connect( m_pIMContext, "preedit_changed",
+ G_CALLBACK (signalIMPreeditChanged), this );
+ g_signal_connect( m_pIMContext, "retrieve_surrounding",
+ G_CALLBACK (signalIMRetrieveSurrounding), this );
+ g_signal_connect( m_pIMContext, "delete_surrounding",
+ G_CALLBACK (signalIMDeleteSurrounding), this );
+ g_signal_connect( m_pIMContext, "preedit_start",
+ G_CALLBACK (signalIMPreeditStart), this );
+ g_signal_connect( m_pIMContext, "preedit_end",
+ G_CALLBACK (signalIMPreeditEnd), this );
+
+ GetGenericData()->ErrorTrapPush();
+ gtk_im_context_set_client_window( m_pIMContext, widget_get_window(GTK_WIDGET(m_pFrame->m_pWindow)) );
+ gtk_im_context_focus_in( m_pIMContext );
+ GetGenericData()->ErrorTrapPop();
+ m_bFocused = true;
+ }
+}
+
+void GtkSalFrame::IMHandler::deleteIMContext()
+{
+ if( m_pIMContext )
+ {
+ // first give IC a chance to deinitialize
+ GetGenericData()->ErrorTrapPush();
+ gtk_im_context_set_client_window( m_pIMContext, NULL );
+ GetGenericData()->ErrorTrapPop();
+ // destroy old IC
+ g_object_unref( m_pIMContext );
+ m_pIMContext = NULL;
+ }
+}
+
+void GtkSalFrame::IMHandler::doCallEndExtTextInput()
+{
+ m_aInputEvent.mpTextAttr = NULL;
+ m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
+}
+
+void GtkSalFrame::IMHandler::updateIMSpotLocation()
+{
+ SalExtTextInputPosEvent aPosEvent;
+ m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent );
+ GdkRectangle aArea;
+ aArea.x = aPosEvent.mnX;
+ aArea.y = aPosEvent.mnY;
+ aArea.width = aPosEvent.mnWidth;
+ aArea.height = aPosEvent.mnHeight;
+ GetGenericData()->ErrorTrapPush();
+ gtk_im_context_set_cursor_location( m_pIMContext, &aArea );
+ GetGenericData()->ErrorTrapPop();
+}
+
+void GtkSalFrame::IMHandler::sendEmptyCommit()
+{
+ vcl::DeletionListener aDel( m_pFrame );
+
+ SalExtTextInputEvent aEmptyEv;
+ aEmptyEv.mnTime = 0;
+ aEmptyEv.mpTextAttr = 0;
+ aEmptyEv.maText.clear();
+ aEmptyEv.mnCursorPos = 0;
+ aEmptyEv.mnCursorFlags = 0;
+ aEmptyEv.mbOnlyCursor = False;
+ m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv );
+ if( ! aDel.isDeleted() )
+ m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
+}
+
+void GtkSalFrame::IMHandler::endExtTextInput( sal_uInt16 /*nFlags*/ )
+{
+ gtk_im_context_reset ( m_pIMContext );
+
+ if( m_aInputEvent.mpTextAttr )
+ {
+ vcl::DeletionListener aDel( m_pFrame );
+ // delete preedit in sal (commit an empty string)
+ sendEmptyCommit();
+ if( ! aDel.isDeleted() )
+ {
+ // mark previous preedit state again (will e.g. be sent at focus gain)
+ m_aInputEvent.mpTextAttr = &m_aInputFlags[0];
+ if( m_bFocused )
+ {
+ // begin preedit again
+ GtkSalFrame::getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ }
+ }
+ }
+}
+
+void GtkSalFrame::IMHandler::focusChanged( bool bFocusIn )
+{
+ m_bFocused = bFocusIn;
+ if( bFocusIn )
+ {
+ GetGenericData()->ErrorTrapPush();
+ gtk_im_context_focus_in( m_pIMContext );
+ GetGenericData()->ErrorTrapPop();
+ if( m_aInputEvent.mpTextAttr )
+ {
+ sendEmptyCommit();
+ // begin preedit again
+ GtkSalFrame::getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ }
+ }
+ else
+ {
+ GetGenericData()->ErrorTrapPush();
+ gtk_im_context_focus_out( m_pIMContext );
+ GetGenericData()->ErrorTrapPop();
+ // cancel an eventual event posted to begin preedit again
+ GtkSalFrame::getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ }
+}
+
+bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent )
+{
+ vcl::DeletionListener aDel( m_pFrame );
+
+ if( pEvent->type == GDK_KEY_PRESS )
+ {
+ // Add this key press event to the list of previous key presses
+ // to which we compare key release events. If a later key release
+ // event has a matching key press event in this list, we swallow
+ // the key release because some GTK Input Methods don't swallow it
+ // for us.
+ m_aPrevKeyPresses.push_back( PreviousKeyPress(pEvent) );
+ m_nPrevKeyPresses++;
+
+ // Also pop off the earliest key press event if there are more than 10
+ // already.
+ while (m_nPrevKeyPresses > 10)
+ {
+ m_aPrevKeyPresses.pop_front();
+ m_nPrevKeyPresses--;
+ }
+
+ GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
+
+ // #i51353# update spot location on every key input since we cannot
+ // know which key may activate a preedit choice window
+ updateIMSpotLocation();
+ if( aDel.isDeleted() )
+ return true;
+
+ gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
+ g_object_unref( pRef );
+
+ if( aDel.isDeleted() )
+ return true;
+
+ m_bPreeditJustChanged = false;
+
+ if( bResult )
+ return true;
+ else
+ {
+ DBG_ASSERT( m_nPrevKeyPresses > 0, "key press has vanished !" );
+ if( ! m_aPrevKeyPresses.empty() ) // sanity check
+ {
+ // event was not swallowed, do not filter a following
+ // key release event
+ // note: this relies on gtk_im_context_filter_keypress
+ // returning without calling a handler (in the "not swallowed"
+ // case ) which might change the previous key press list so
+ // we would pop the wrong event here
+ m_aPrevKeyPresses.pop_back();
+ m_nPrevKeyPresses--;
+ }
+ }
+ }
+
+ // Determine if we got an earlier key press event corresponding to this key release
+ if (pEvent->type == GDK_KEY_RELEASE)
+ {
+ GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
+ gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
+ g_object_unref( pRef );
+
+ if( aDel.isDeleted() )
+ return true;
+
+ m_bPreeditJustChanged = false;
+
+ std::list<PreviousKeyPress>::iterator iter = m_aPrevKeyPresses.begin();
+ std::list<PreviousKeyPress>::iterator iter_end = m_aPrevKeyPresses.end();
+ while (iter != iter_end)
+ {
+ // If we found a corresponding previous key press event, swallow the release
+ // and remove the earlier key press from our list
+ if (*iter == pEvent)
+ {
+ m_aPrevKeyPresses.erase(iter);
+ m_nPrevKeyPresses--;
+ return true;
+ }
+ ++iter;
+ }
+
+ if( bResult )
+ return true;
+ }
+
+ return false;
+}
+
+/* FIXME:
+* #122282# still more hacking: some IMEs never start a preedit but simply commit
+* in this case we cannot commit a single character. Workaround: do not do the
+* single key hack for enter or space if the unicode committed does not match
+*/
+
+static bool checkSingleKeyCommitHack( guint keyval, sal_Unicode cCode )
+{
+ bool bRet = true;
+ switch( keyval )
+ {
+ case GDK_KP_Enter:
+ case GDK_Return:
+ if( cCode != '\n' && cCode != '\r' )
+ bRet = false;
+ break;
+ case GDK_space:
+ case GDK_KP_Space:
+ if( cCode != ' ' )
+ bRet = false;
+ break;
+ default:
+ break;
+ }
+ return bRet;
+}
+
+void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* pContext, gchar* pText, gpointer im_handler )
+{
+ GtkSalFrame::IMHandler* pThis = static_cast<GtkSalFrame::IMHandler*>(im_handler);
+
+ SolarMutexGuard aGuard;
+ vcl::DeletionListener aDel( pThis->m_pFrame );
+ {
+ const bool bWasPreedit =
+ (pThis->m_aInputEvent.mpTextAttr != 0) ||
+ pThis->m_bPreeditJustChanged;
+
+ pThis->m_aInputEvent.mnTime = 0;
+ pThis->m_aInputEvent.mpTextAttr = 0;
+ pThis->m_aInputEvent.maText = OUString( pText, strlen(pText), RTL_TEXTENCODING_UTF8 );
+ pThis->m_aInputEvent.mnCursorPos = pThis->m_aInputEvent.maText.getLength();
+ pThis->m_aInputEvent.mnCursorFlags = 0;
+ pThis->m_aInputEvent.mbOnlyCursor = False;
+
+ pThis->m_aInputFlags.clear();
+
+ /* necessary HACK: all keyboard input comes in here as soon as a IMContext is set
+ * which is logical and consequent. But since even simple input like
+ * <space> comes through the commit signal instead of signalKey
+ * and all kinds of windows only implement KeyInput (e.g. PushButtons,
+ * RadioButtons and a lot of other Controls), will send a single
+ * KeyInput/KeyUp sequence instead of an ExtText event if there
+ * never was a preedit and the text is only one character.
+ *
+ * In this case there the last ExtText event must have been
+ * SALEVENT_ENDEXTTEXTINPUT, either because of a regular commit
+ * or because there never was a preedit.
+ */
+ bool bSingleCommit = false;
+ if( ! bWasPreedit
+ && pThis->m_aInputEvent.maText.getLength() == 1
+ && ! pThis->m_aPrevKeyPresses.empty()
+ )
+ {
+ const PreviousKeyPress& rKP = pThis->m_aPrevKeyPresses.back();
+ sal_Unicode aOrigCode = pThis->m_aInputEvent.maText[0];
+
+ if( checkSingleKeyCommitHack( rKP.keyval, aOrigCode ) )
+ {
+ pThis->m_pFrame->doKeyCallback( rKP.state, rKP.keyval, rKP.hardware_keycode, rKP.group, rKP.time, aOrigCode, true, true );
+ bSingleCommit = true;
+ }
+ }
+ if( ! bSingleCommit )
+ {
+ pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
+ if( ! aDel.isDeleted() )
+ pThis->doCallEndExtTextInput();
+ }
+ if( ! aDel.isDeleted() )
+ {
+ // reset input event
+ pThis->m_aInputEvent.maText.clear();
+ pThis->m_aInputEvent.mnCursorPos = 0;
+ pThis->updateIMSpotLocation();
+ }
+ }
+#ifdef SOLARIS
+ // #i51356# workaround a solaris IIIMP bug
+ // in case of partial commits the preedit changed signal
+ // and commit signal come in wrong order
+ if( ! aDel.isDeleted() )
+ signalIMPreeditChanged( pContext, im_handler );
+#else
+ (void) pContext;
+#endif
+}
+
+void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext*, gpointer im_handler )
+{
+ GtkSalFrame::IMHandler* pThis = static_cast<GtkSalFrame::IMHandler*>(im_handler);
+
+ char* pText = NULL;
+ PangoAttrList* pAttrs = NULL;
+ gint nCursorPos = 0;
+
+ gtk_im_context_get_preedit_string( pThis->m_pIMContext,
+ &pText,
+ &pAttrs,
+ &nCursorPos );
+ if( pText && ! *pText ) // empty string
+ {
+ // change from nothing to nothing -> do not start preedit
+ // e.g. this will activate input into a calc cell without
+ // user input
+ if( pThis->m_aInputEvent.maText.getLength() == 0 )
+ {
+ g_free( pText );
+ pango_attr_list_unref( pAttrs );
+ return;
+ }
+ }
+
+ pThis->m_bPreeditJustChanged = true;
+
+ bool bEndPreedit = (!pText || !*pText) && pThis->m_aInputEvent.mpTextAttr != NULL;
+ pThis->m_aInputEvent.mnTime = 0;
+ pThis->m_aInputEvent.maText = pText ? OUString( pText, strlen(pText), RTL_TEXTENCODING_UTF8 ) : OUString();
+ pThis->m_aInputEvent.mnCursorPos = nCursorPos;
+ pThis->m_aInputEvent.mnCursorFlags = 0;
+ pThis->m_aInputEvent.mbOnlyCursor = False;
+
+ pThis->m_aInputFlags = std::vector<sal_uInt16>( std::max( 1, (int)pThis->m_aInputEvent.maText.getLength() ), 0 );
+
+ PangoAttrIterator *iter = pango_attr_list_get_iterator(pAttrs);
+ do
+ {
+ GSList *attr_list = NULL;
+ GSList *tmp_list = NULL;
+ gint start, end;
+ guint sal_attr = 0;
+
+ pango_attr_iterator_range (iter, &start, &end);
+ if (end == G_MAXINT)
+ end = pText ? strlen (pText) : 0;
+ if (end == start)
+ continue;
+
+ start = g_utf8_pointer_to_offset (pText, pText + start);
+ end = g_utf8_pointer_to_offset (pText, pText + end);
+
+ tmp_list = attr_list = pango_attr_iterator_get_attrs (iter);
+ while (tmp_list)
+ {
+ PangoAttribute *pango_attr = static_cast<PangoAttribute *>(tmp_list->data);
+
+ switch (pango_attr->klass->type)
+ {
+ case PANGO_ATTR_BACKGROUND:
+ sal_attr |= (EXTTEXTINPUT_ATTR_HIGHLIGHT | EXTTEXTINPUT_CURSOR_INVISIBLE);
+ break;
+ case PANGO_ATTR_UNDERLINE:
+ sal_attr |= EXTTEXTINPUT_ATTR_UNDERLINE;
+ break;
+ case PANGO_ATTR_STRIKETHROUGH:
+ sal_attr |= EXTTEXTINPUT_ATTR_REDTEXT;
+ break;
+ default:
+ break;
+ }
+ pango_attribute_destroy (pango_attr);
+ tmp_list = tmp_list->next;
+ }
+ if (sal_attr == 0)
+ sal_attr |= EXTTEXTINPUT_ATTR_UNDERLINE;
+ g_slist_free (attr_list);
+
+ // Set the sal attributes on our text
+ for (int i = start; i < end; ++i)
+ {
+ SAL_WARN_IF(i >= static_cast<int>(pThis->m_aInputFlags.size()),
+ "vcl.gtk", "pango attrib out of range. Broken range: "
+ << start << "," << end << " Legal range: 0,"
+ << pThis->m_aInputFlags.size());
+ if (i >= static_cast<int>(pThis->m_aInputFlags.size()))
+ continue;
+ pThis->m_aInputFlags[i] |= sal_attr;
+ }
+ } while (pango_attr_iterator_next (iter));
+ pango_attr_iterator_destroy(iter);
+
+ pThis->m_aInputEvent.mpTextAttr = &pThis->m_aInputFlags[0];
+
+ g_free( pText );
+ pango_attr_list_unref( pAttrs );
+
+ SolarMutexGuard aGuard;
+ vcl::DeletionListener aDel( pThis->m_pFrame );
+
+ pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
+ if( bEndPreedit && ! aDel.isDeleted() )
+ pThis->doCallEndExtTextInput();
+ if( ! aDel.isDeleted() )
+ pThis->updateIMSpotLocation();
+}
+
+void GtkSalFrame::IMHandler::signalIMPreeditStart( GtkIMContext*, gpointer /*im_handler*/ )
+{
+}
+
+void GtkSalFrame::IMHandler::signalIMPreeditEnd( GtkIMContext*, gpointer im_handler )
+{
+ GtkSalFrame::IMHandler* pThis = static_cast<GtkSalFrame::IMHandler*>(im_handler);
+
+ pThis->m_bPreeditJustChanged = true;
+
+ SolarMutexGuard aGuard;
+ vcl::DeletionListener aDel( pThis->m_pFrame );
+ pThis->doCallEndExtTextInput();
+ if( ! aDel.isDeleted() )
+ pThis->updateIMSpotLocation();
+}
+
+uno::Reference<accessibility::XAccessibleEditableText>
+ FindFocus(uno::Reference< accessibility::XAccessibleContext > xContext)
+{
+ if (!xContext.is())
+ uno::Reference< accessibility::XAccessibleEditableText >();
+
+ uno::Reference<accessibility::XAccessibleStateSet> xState = xContext->getAccessibleStateSet();
+ if (xState.is())
+ {
+ if (xState->contains(accessibility::AccessibleStateType::FOCUSED))
+ return uno::Reference<accessibility::XAccessibleEditableText>(xContext, uno::UNO_QUERY);
+ }
+
+ for (sal_Int32 i = 0; i < xContext->getAccessibleChildCount(); ++i)
+ {
+ uno::Reference< accessibility::XAccessible > xChild = xContext->getAccessibleChild(i);
+ if (!xChild.is())
+ continue;
+ uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext();
+ if (!xChildContext.is())
+ continue;
+ uno::Reference< accessibility::XAccessibleEditableText > xText = FindFocus(xChildContext);
+ if (xText.is())
+ return xText;
+ }
+ return uno::Reference< accessibility::XAccessibleEditableText >();
+}
+
+static uno::Reference<accessibility::XAccessibleEditableText> lcl_GetxText(vcl::Window *pFocusWin)
+{
+ uno::Reference<accessibility::XAccessibleEditableText> xText;
+ try
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible( pFocusWin->GetAccessible( true ) );
+ if (xAccessible.is())
+ xText = FindFocus(xAccessible->getAccessibleContext());
+ }
+ catch(const uno::Exception& e)
+ {
+ SAL_WARN( "vcl.gtk", "Exception in getting input method surrounding text: " << e.Message);
+ }
+ return xText;
+}
+
+gboolean GtkSalFrame::IMHandler::signalIMRetrieveSurrounding( GtkIMContext* pContext, gpointer /*im_handler*/ )
+{
+ vcl::Window *pFocusWin = Application::GetFocusWindow();
+ if (!pFocusWin)
+ return true;
+
+ uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText(pFocusWin);
+ if (xText.is())
+ {
+ sal_Int32 nPosition = xText->getCaretPosition();
+ OUString sAllText = xText->getText();
+ OString sUTF = OUStringToOString(sAllText, RTL_TEXTENCODING_UTF8);
+ OUString sCursorText(sAllText.copy(0, nPosition));
+ gtk_im_context_set_surrounding(pContext, sUTF.getStr(), sUTF.getLength(),
+ OUStringToOString(sCursorText, RTL_TEXTENCODING_UTF8).getLength());
+ return true;
+ }
+
+ return false;
+}
+
+gboolean GtkSalFrame::IMHandler::signalIMDeleteSurrounding( GtkIMContext*, gint offset, gint nchars,
+ gpointer /*im_handler*/ )
+{
+ vcl::Window *pFocusWin = Application::GetFocusWindow();
+ if (!pFocusWin)
+ return true;
+
+ uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText(pFocusWin);
+ if (xText.is())
+ {
+ sal_Int32 nPosition = xText->getCaretPosition();
+ // #i111768# range checking
+ sal_Int32 nDeletePos = nPosition + offset;
+ sal_Int32 nDeleteEnd = nDeletePos + nchars;
+ if (nDeletePos < 0)
+ nDeletePos = 0;
+ if (nDeleteEnd < 0)
+ nDeleteEnd = 0;
+ if (nDeleteEnd > xText->getCharacterCount())
+ nDeleteEnd = xText->getCharacterCount();
+
+ xText->deleteText(nDeletePos, nDeleteEnd);
+ //tdf91641 adjust cursor if deleted chars shift it forward (normal case)
+ if (nDeletePos < nPosition)
+ {
+ if (nDeleteEnd <= nPosition)
+ nPosition = nPosition - (nDeleteEnd - nDeletePos);
+ else
+ nPosition = nDeletePos;
+
+ if (xText->getCharacterCount() >= nPosition)
+ xText->setCaretPosition( nPosition );
+ }
+ return true;
+ }
+
+ return false;
+}
+
+Size GtkSalDisplay::GetScreenSize( int nDisplayScreen )
+{
+ Rectangle aRect = m_pSys->GetDisplayScreenPosSizePixel( nDisplayScreen );
+ return Size( aRect.GetWidth(), aRect.GetHeight() );
+}
+
+Window GtkSalFrame::GetX11Window()
+{
+ return widget_get_xid(m_pWindow);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk/window/gtksalframe.cxx b/vcl/unx/gtk/window/gtksalframe.cxx
deleted file mode 100644
index 9e03f14..0000000
--- a/vcl/unx/gtk/window/gtksalframe.cxx
+++ /dev/null
@@ -1,4883 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * 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 <vcl/bitmapex.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
-
-#ifdef ENABLE_DBUS
-#include <dbus/dbus-glib.h>
-
-#define GSM_DBUS_SERVICE "org.gnome.SessionManager"
-#define GSM_DBUS_PATH "/org/gnome/SessionManager"
-#define GSM_DBUS_INTERFACE "org.gnome.SessionManager"
-#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
-
-#if !GTK_CHECK_VERSION(3,0,0)
-#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 = NULL;
-#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, NULL, NULL, NULL);
- 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 SAL_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 (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 AlternatKeyCode 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;
- bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
- }
- }
- if( bSendRelease && ! aDel.isDeleted() )
- {
- CallCallback( SALEVENT_KEYUP, &aEvent );
- }
- }
- else
- CallCallback( SALEVENT_KEYUP, &aEvent );
-}
-
-GtkSalFrame::GraphicsHolder::~GraphicsHolder()
-{
- delete pGraphics;
-}
-
-GtkSalFrame::GtkSalFrame( SalFrame* pParent, sal_uLong nStyle )
- : m_nXScreen( getDisplay()->GetDefaultXScreen() )
-{
- getDisplay()->registerFrame( this );
- m_bDefaultPos = true;
- m_bDefaultSize = ( (nStyle & SAL_FRAME_STYLE_SIZEABLE) && ! pParent );
- m_bWindowIsGtkPlug = false;
-#if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
- m_pLastSyncedDbusMenu = NULL;
-#endif
- Init( pParent, nStyle );
-}
-
-GtkSalFrame::GtkSalFrame( SystemParentData* pSysData )
- : m_nXScreen( getDisplay()->GetDefaultXScreen() )
-{
- 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 = NULL;
-#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 != NULL)
- {
- XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
- GDK_WINDOW_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, name),
- gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
- PropModeReplace, 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 = uno::Reference < css::frame::XFrame >(xDesktop, uno::UNO_QUERY);
-
- if (!xFrame.is())
- return;
-
- uno::Reference< css::frame::XDispatchProvider > xDispatchProvider(xFrame, uno::UNO_QUERY);
- if (!xDispatchProvider.is())
- return;
-
- gchar *strval = NULL;
- 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, OUString("_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, NULL, NULL, NULL, {0} },
- { "About", activate_uno, NULL, NULL, NULL, {0} },
- { "HelpIndex", activate_uno, NULL, NULL, NULL, {0} },
- { "Quit", activate_uno, NULL, NULL, NULL, {0} },
- { "New", activate_uno, NULL, NULL, NULL, {0} }
-};
-
-gboolean ensure_dbus_setup( gpointer data )
-{
- GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( data );
- GdkWindow* gdkWindow = widget_get_window( pSalFrame->getWindow() );
-
- if ( gdkWindow != NULL && g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" ) == NULL )
- {
- // Get a DBus session connection.
- if(!pSessionBus)
- pSessionBus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
- 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, NULL);
- SAL_INFO("vcl.unity", "exporting action group at " << pActionGroup << " for window " << windowId);
- pSalFrame->m_nActionGroupExportId = g_dbus_connection_export_action_group( pSessionBus, aDBusWindowPath, pActionGroup, NULL);
- pSalFrame->m_nHudAwarenessId = hud_awareness_register( pSessionBus, aDBusMenubarPath, hud_activated, pSalFrame, NULL, NULL );
-
- // 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, NULL, 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, NULL, 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, NULL, 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), NULL);
-#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, NULL);
- g_object_unref(pAppActionGroup);
- pSalFrame->m_nAppMenuExportId = g_dbus_connection_export_menu_model (pSessionBus, "/org/libreoffice/menus/appmenu", G_MENU_MODEL (menu), NULL);
- 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 != NULL )
- {
- 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 == NULL )
- {
- pSessionBus = g_bus_get_sync( G_BUS_TYPE_SESSION, NULL, NULL );
-
- if ( pSessionBus == NULL )
- 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),
- NULL );
- }
-
- //ensure_dbus_setup( this );
-#else
- (void) this; // loplugin:staticmethods
-#endif
-}
-
-void GtkSalFrame::InvalidateGraphics()
-{
- for (unsigned int i = 0; i < SAL_N_ELEMENTS(m_aGraphics); ++i)
- {
- if( !m_aGraphics[i].pGraphics )
- continue;
-#if !GTK_CHECK_VERSION(3,0,0)
- m_aGraphics[i].pGraphics->SetDrawable( None, m_nXScreen );
- m_aGraphics[i].pGraphics->SetWindow(NULL);
-#endif
- m_aGraphics[i].bInUse = 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
-
- if( m_pIMHandler )
- 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", NULL );
-
-#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) );
-}
-
-void GtkSalFrame::moveWindow( long nX, long nY )
-{
- if( isChild( false, true ) )
- {
- 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, true ) )
- {
- 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 */
- NULL, /* class data */
- sizeof (GtkFixed), /* instance size */
- 0, /* nb preallocs */
- (GInstanceInitFunc) NULL, /* instance init */
- NULL /* 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(), NULL ));
- gtk_container_add( GTK_CONTAINER(m_pEventBox), GTK_WIDGET(m_pFixedContainer) );
-#else
- m_pEventBox = 0;
- // 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(), NULL ));
- 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 );
-// g_signal_connect( G_OBJECT(m_pWindow), "state-flags-changed", G_CALLBACK(signalFlagsChanged), 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 = NULL;
- m_nKeyModifiers = 0;
- m_bFullscreen = false;
- m_bSpanMonitorsWhenFullscreen = false;
- m_nState = GDK_WINDOW_STATE_WITHDRAWN;
- m_nVisibility = GDK_VISIBILITY_FULLY_OBSCURED;
-#if GTK_CHECK_VERSION(3,0,0)
- m_nLastScrollEventTime = GDK_CURRENT_TIME;
-#endif
- m_bSendModChangeOnRelease = false;
- m_pIMHandler = NULL;
- m_hBackgroundPixmap = None;
- m_nSavedScreenSaverTimeout = 0;
- m_nGSMCookie = 0;
- m_nExtStyle = 0;
- m_pRegion = NULL;
- m_ePointerStyle = static_cast<PointerStyle>(0xffff);
- m_bSetFocusOnMap = false;
- m_pSalMenu = NULL;
- 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 = NULL;
- m_aSystemData.pShellWidget = m_aSystemData.pWidget;
-
- // 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.
- */
-
-#if !GTK_CHECK_VERSION(3,0,0)
-extern "C" {
- typedef void(*setAcceptFn)( GtkWindow*, gboolean );
- static setAcceptFn p_gtk_window_set_accept_focus = NULL;
- static bool bGetAcceptFocusFn = true;
-
- typedef void(*setUserTimeFn)( GdkWindow*, guint32 );
- static setUserTimeFn p_gdk_x11_window_set_user_time = NULL;
- 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 = NULL;
- 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, sal_uLong nStyle )
-{
- if( nStyle & SAL_FRAME_STYLE_DEFAULT ) // ensure default style
- {
- nStyle |= SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE;
- nStyle &= ~SAL_FRAME_STYLE_FLOAT;
- }
-
- m_pParent = static_cast<GtkSalFrame*>(pParent);
- m_pForeignParent = NULL;
- m_aForeignParentWindow = None;
- m_pForeignTopLevel = NULL;
- m_aForeignTopLevelWindow = None;
- m_nStyle = nStyle;
-
- GtkWindowType eWinType = ( (nStyle & SAL_FRAME_STYLE_FLOAT) &&
- ! (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|
- SAL_FRAME_STYLE_FLOAT_FOCUSABLE))
- )
- ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL;
-
- if( nStyle & SAL_FRAME_STYLE_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", (gpointer)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 & SAL_FRAME_STYLE_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 & SAL_FRAME_STYLE_FLOAT) ||
- (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE) ) );
-
- if( bDecoHandling )
- {
- GdkWindowTypeHint eType = GDK_WINDOW_TYPE_HINT_NORMAL;
- if( (nStyle & SAL_FRAME_STYLE_DIALOG) && m_pParent != 0 )
- eType = GDK_WINDOW_TYPE_HINT_DIALOG;
- if( (nStyle & SAL_FRAME_STYLE_INTRO) )
- {
- gtk_window_set_role( GTK_WINDOW(m_pWindow), "splashscreen" );
- eType = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN;
- }
- else if( (nStyle & SAL_FRAME_STYLE_TOOLWINDOW ) )
- {
- eType = GDK_WINDOW_TYPE_HINT_UTILITY;
- gtk_window_set_skip_taskbar_hint( GTK_WINDOW(m_pWindow), true );
- }
- else if( (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
- {
- eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
- lcl_set_accept_focus( GTK_WINDOW(m_pWindow), false, true );
- }
- else if( (nStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
- {
- eType = GDK_WINDOW_TYPE_HINT_UTILITY;
- }
-#if !GTK_CHECK_VERSION(3,0,0)
- if( (nStyle & SAL_FRAME_STYLE_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 & SAL_FRAME_STYLE_FLOAT) )
- {
- gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), GDK_WINDOW_TYPE_HINT_POPUP_MENU );
- }
-
-#if !GTK_CHECK_VERSION(3,0,0)
- if( eWinType == GTK_WINDOW_TOPLEVEL )
- {
-#ifdef ENABLE_GMENU_INTEGRATION
- // Enable DBus native menu if available.
- ensure_dbus_setup( this );
-#endif
-
- guint32 nUserTime = 0;
- if( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
- {
- 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), (nStyle & SAL_FRAME_STYLE_SIZEABLE) != 0 );
- if( ( (nStyle & (SAL_FRAME_STYLE_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 = NULL;
- 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 = NULL;
- m_aForeignParentWindow = (GdkNativeWindow)pSysData->aWindow;
- m_pForeignParent = NULL;
- 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 = SAL_FRAME_STYLE_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_pWindow )
- {
- for( int i = 0; i < nMaxGraphics; i++ )
- {
- if( ! m_aGraphics[i].bInUse )
- {
- m_aGraphics[i].bInUse = true;
- if( ! m_aGraphics[i].pGraphics )
- {
-#if GTK_CHECK_VERSION(3,0,0)
- m_aGraphics[i].pGraphics = new GtkSalGraphics( this, m_pWindow );
- if( !m_aFrame.get() )
- {
- AllocateFrame();
- TriggerPaintEvent();
- }
- m_aGraphics[i].pGraphics->setDevice( m_aFrame );
-#else // common case:
- m_aGraphics[i].pGraphics = new GtkSalGraphics( this, m_pWindow, m_nXScreen );
-#endif
- }
- return m_aGraphics[i].pGraphics;
- }
- }
- }
-
- return NULL;
-}
-
-void GtkSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
-{
- for( int i = 0; i < nMaxGraphics; i++ )
- {
- if( m_aGraphics[i].pGraphics == pGraphics )
- {
- m_aGraphics[i].bInUse = false;
- break;
- }
- }
-}
-
-bool GtkSalFrame::PostEvent( void* 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() );
-}
-
-static inline sal_uInt8 *
-getRow( BitmapBuffer *pBuffer, sal_uLong nRow )
-{
- if( BMP_SCANLINE_ADJUSTMENT( pBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
- return pBuffer->mpBits + nRow * pBuffer->mnScanlineSize;
- else
- return pBuffer->mpBits + ( pBuffer->mnHeight - nRow - 1 ) * pBuffer->mnScanlineSize;
-}
-
-static GdkPixbuf *
-bitmapToPixbuf( SalBitmap *pSalBitmap, SalBitmap *pSalAlpha )
-{
- g_return_val_if_fail( pSalBitmap != NULL, NULL );
- g_return_val_if_fail( pSalAlpha != NULL, NULL );
-
- BitmapBuffer *pBitmap = pSalBitmap->AcquireBuffer( BITMAP_READ_ACCESS );
- g_return_val_if_fail( pBitmap != NULL, NULL );
- g_return_val_if_fail( pBitmap->mnBitCount == 24 || pBitmap->mnBitCount == 32, NULL );
-
- BitmapBuffer *pAlpha = pSalAlpha->AcquireBuffer( BITMAP_READ_ACCESS );
- g_return_val_if_fail( pAlpha != NULL, NULL );
- g_return_val_if_fail( pAlpha->mnBitCount == 8, NULL );
-
- Size aSize = pSalBitmap->GetSize();
- g_return_val_if_fail( pSalAlpha->GetSize() == aSize, NULL );
-
- int nX, nY;
- guchar *pPixbufData = static_cast<guchar *>(g_malloc (4 * aSize.Width() * aSize.Height() ));
- guchar *pDestData = pPixbufData;
-
- for( nY = 0; nY < pBitmap->mnHeight; nY++ )
- {
- sal_uInt8 *pData = getRow( pBitmap, nY );
- sal_uInt8 *pAlphaData = getRow( pAlpha, nY );
-
- for( nX = 0; nX < pBitmap->mnWidth; nX++ )
- {
- BitmapColor aColor;
- if (pBitmap->mnFormat == BMP_FORMAT_24BIT_TC_BGR)
- {
- aColor = BitmapColor(pData[2], pData[1], pData[0]);
- pData += 3;
- }
- else if (pBitmap->mnFormat == BMP_FORMAT_24BIT_TC_RGB)
- {
- aColor = BitmapColor(pData[0], pData[1], pData[2]);
- pData += 3;
- }
- else
- {
- pBitmap->maColorMask.GetColorFor32Bit(aColor, pData);
- pData += 4;
- }
- *pDestData++ = aColor.GetRed();
- *pDestData++ = aColor.GetGreen();
- *pDestData++ = aColor.GetBlue();
- *pDestData++ = 255 - *pAlphaData++;
- }
- }
-
- pSalBitmap->ReleaseBuffer( pBitmap, BITMAP_READ_ACCESS );
- pSalAlpha->ReleaseBuffer( pAlpha, BITMAP_READ_ACCESS );
-
- return gdk_pixbuf_new_from_data( pPixbufData,
- GDK_COLORSPACE_RGB, true, 8,
- aSize.Width(), aSize.Height(),
- aSize.Width() * 4,
- reinterpret_cast<GdkPixbufDestroyNotify>(g_free),
- NULL );
-}
-
-void GtkSalFrame::SetIcon( sal_uInt16 nIcon )
-{
- if( (m_nStyle & (SAL_FRAME_STYLE_PLUG|SAL_FRAME_STYLE_SYSTEMCHILD|SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_INTRO|SAL_FRAME_STYLE_OWNERDRAWDECORATION))
- || ! m_pWindow )
- return;
-
- if( !ImplGetResMgr() )
- return;
-
- GdkPixbuf *pBuf;
- GList *pIcons = NULL;
-
- sal_uInt16 nOffsets[2] = { SV_ICON_SMALL_START, SV_ICON_LARGE_START };
- sal_uInt16 nIndex;
-
- for( nIndex = 0; nIndex < sizeof(nOffsets)/ sizeof(sal_uInt16); nIndex++ )
- {
- // #i44723# workaround gcc temporary problem
- ResId aResId( nOffsets[nIndex] + nIcon, *ImplGetResMgr() );
- BitmapEx aIcon( aResId );
-
- // #i81083# convert to 24bit/8bit alpha bitmap
- Bitmap aBmp = aIcon.GetBitmap();
- if( aBmp.GetBitCount() != 24 || ! aIcon.IsAlpha() )
- {
- if( aBmp.GetBitCount() != 24 )
- aBmp.Convert( BMP_CONVERSION_24BIT );
- AlphaMask aMask;
- if( ! aIcon.IsAlpha() )
- {
- switch( aIcon.GetTransparentType() )
- {
- case TRANSPARENT_NONE:
- {
- sal_uInt8 nTrans = 0;
- aMask = AlphaMask( aBmp.GetSizePixel(), &nTrans );
- }
- break;
- case TRANSPARENT_COLOR:
- aMask = AlphaMask( aBmp.CreateMask( aIcon.GetTransparentColor() ) );
- break;
- case TRANSPARENT_BITMAP:
- aMask = AlphaMask( aIcon.GetMask() );
- break;
- default:
- OSL_FAIL( "unhandled transparent type" );
- break;
- }
- }
- else
- aMask = aIcon.GetAlpha();
- aIcon = BitmapEx( aBmp, aMask );
- }
-
- ImpBitmap *pIconImpBitmap = aIcon.ImplGetBitmapImpBitmap();
- ImpBitmap *pIconImpMask = aIcon.ImplGetMaskImpBitmap();
-
- if( pIconImpBitmap && pIconImpMask )
- {
- SalBitmap *pIconBitmap =
- pIconImpBitmap->ImplGetSalBitmap();
- SalBitmap *pIconMask =
- pIconImpMask->ImplGetSalBitmap();
-
- if( ( pBuf = bitmapToPixbuf( pIconBitmap, pIconMask ) ) )
- pIcons = g_list_prepend( pIcons, pBuf );
- }
- }
-
- gtk_window_set_icon_list( GTK_WINDOW(m_pWindow), pIcons );
-
- g_list_foreach( pIcons, reinterpret_cast<GFunc>(g_object_unref), NULL );
- g_list_free( pIcons );
-}
-
-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 = NULL;
- 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 & SAL_FRAME_STYLE_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 & SAL_FRAME_STYLE_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 & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
- 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 & SAL_FRAME_STYLE_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(0);
- }
- 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, NULL );
- 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 & SAL_FRAME_STYLE_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),
- NULL,
- &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,
- basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRX);
- 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
-
- // update device in existing graphics
- for( unsigned int i = 0; i < SAL_N_ELEMENTS( m_aGraphics ); ++i )
- {
- if( !m_aGraphics[i].pGraphics )
- continue;
- m_aGraphics[i].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, true ) )
- 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, NULL );
- else if( bMoved && ! bSized )
- CallCallback( SALEVENT_MOVE, NULL );
- else if( bMoved && bSized )
- CallCallback( SALEVENT_MOVERESIZE, NULL );
-
- 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, NULL );
- }
- 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 = NULL;
- 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 |= SAL_FRAME_STYLE_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 &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
- bResize = true;
- }
-
- if (bResize)
- {
- // temporarily re-sizeable
- if( !(m_nStyle & SAL_FRAME_STYLE_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 & SAL_FRAME_STYLE_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( NULL );
- 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, NULL );
-
- 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 : NULL );
- m_aRestorePosSize = Rectangle();
- }
-}
-
-/* definitions from xautolock.c (pl15) */
-#define XAUTOLOCK_DISABLE 1
-#define XAUTOLOCK_ENABLE 2
-
-void GtkSalFrame::setAutoLock( bool bLock )
-{
- if( isChild() || !getDisplay()->IsX11Display() )
- return;
-
- GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(m_pWindow) );
- GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
- GdkWindow *pRootWin = gdk_screen_get_root_window( pScreen );
-
- Atom nAtom = XInternAtom( GDK_DISPLAY_XDISPLAY( pDisplay ),
- "XAUTOLOCK_MESSAGE", False );
-
- int nMessage = bLock ? XAUTOLOCK_ENABLE : XAUTOLOCK_DISABLE;
-
- XChangeProperty( GDK_DISPLAY_XDISPLAY( pDisplay ),
- GDK_WINDOW_XID( pRootWin ),
- nAtom, XA_INTEGER,
- 8, PropModeReplace,
- reinterpret_cast<unsigned char*>(&nMessage),
- sizeof( nMessage ) );
-}
-
-#ifdef ENABLE_DBUS
-/** cookie is returned as an unsigned integer */
-static guint
-dbus_inhibit_gsm (const gchar *appname,
- const gchar *reason,
- guint xid)
-{
- gboolean res;
- guint cookie;
- GError *error = NULL;
- DBusGProxy *proxy = NULL;
-
- /* get the DBUS session connection */
- DBusGConnection *session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
- if (error != NULL) {
- g_debug ("DBUS cannot connect : %s", error->message);
- g_error_free (error);
- return -1;
- }
-
- /* get the proxy with gnome-session-manager */
- proxy = dbus_g_proxy_new_for_name (session_connection,
- GSM_DBUS_SERVICE,
- GSM_DBUS_PATH,
- GSM_DBUS_INTERFACE);
- if (proxy == NULL) {
- g_debug ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
- return -1;
- }
-
- res = dbus_g_proxy_call (proxy,
- "Inhibit", &error,
- G_TYPE_STRING, appname,
- G_TYPE_UINT, xid,
- G_TYPE_STRING, reason,
- G_TYPE_UINT, 8, //Inhibit the session being marked as idle
- G_TYPE_INVALID,
- G_TYPE_UINT, &cookie,
- G_TYPE_INVALID);
-
- /* check the return value */
- if (! res) {
- cookie = -1;
- g_debug ("Inhibit method failed");
- }
-
- /* check the error value */
- if (error != NULL) {
- g_debug ("Inhibit problem : %s", error->message);
- g_error_free (error);
- cookie = -1;
- }
-
- g_object_unref (G_OBJECT (proxy));
- return cookie;
-}
-
-static void
-dbus_uninhibit_gsm (guint cookie)
-{
- gboolean res;
- GError *error = NULL;
- DBusGProxy *proxy = NULL;
- DBusGConnection *session_connection = NULL;
-
- if (cookie == guint(-1)) {
- g_debug ("Invalid cookie");
- return;
- }
-
- /* get the DBUS session connection */
- session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
- if (error) {
- g_debug ("DBUS cannot connect : %s", error->message);
- g_error_free (error);
- return;
- }
-
- /* get the proxy with gnome-session-manager */
- proxy = dbus_g_proxy_new_for_name (session_connection,
- GSM_DBUS_SERVICE,
- GSM_DBUS_PATH,
- GSM_DBUS_INTERFACE);
- if (proxy == NULL) {
- g_debug ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
- return;
- }
-
- res = dbus_g_proxy_call (proxy,
- "Uninhibit",
- &error,
- G_TYPE_UINT, cookie,
- G_TYPE_INVALID,
- G_TYPE_INVALID);
-
- /* check the return value */
- if (! res) {
- g_debug ("Uninhibit method failed");
- }
-
- /* check the error value */
- if (error != NULL) {
- g_debug ("Uninhibit problem : %s", error->message);
- g_error_free (error);
- cookie = -1;
- }
- g_object_unref (G_OBJECT (proxy));
-}
-#endif
-
-void GtkSalFrame::StartPresentation( bool bStart )
-{
- setAutoLock( !bStart );
-
- if( !getDisplay()->IsX11Display() )
- return;
-
-#if !GTK_CHECK_VERSION(3,0,0)
- Display *pDisplay = GDK_DISPLAY_XDISPLAY( getGdkDisplay() );
-
- int nTimeout, nInterval, bPreferBlanking, bAllowExposures;
- XGetScreenSaver( pDisplay, &nTimeout, &nInterval,
- &bPreferBlanking, &bAllowExposures );
-#endif
- if( bStart )
- {
-#if !GTK_CHECK_VERSION(3,0,0)
- if ( nTimeout )
- {
- m_nSavedScreenSaverTimeout = nTimeout;
- XResetScreenSaver( pDisplay );
- XSetScreenSaver( pDisplay, 0, nInterval,
- bPreferBlanking, bAllowExposures );
- }
-#endif
-#ifdef ENABLE_DBUS
- m_nGSMCookie = dbus_inhibit_gsm(g_get_application_name(), "presentation",
- widget_get_xid(m_pWindow));
-#endif
- }
- else
- {
-#if !GTK_CHECK_VERSION(3,0,0)
- if( m_nSavedScreenSaverTimeout )
- XSetScreenSaver( pDisplay, m_nSavedScreenSaverTimeout,
- nInterval, bPreferBlanking,
- bAllowExposures );
-#endif
- m_nSavedScreenSaverTimeout = 0;
-#ifdef ENABLE_DBUS
- dbus_uninhibit_gsm(m_nGSMCookie);
-#endif
- }
-}
-
-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, true ) )
- 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 & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_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, false );
- 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, NULL, 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 )
-{
- 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), NULL, 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 : NULL );
-}
-
-void GtkSalFrame::SetPointerPos( long nX, long nY )
-{
- GtkSalFrame* pFrame = this;
- while( pFrame && pFrame->isChild( false, true ) )
- 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
-}
-
-void GtkSalFrame::Sync()
-{
- gdk_display_sync( getGdkDisplay() );
-}
-
-#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 == NULL || pGdkModifiers == NULL )
- 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;
- case KEY_PASTE: nKeyCode = GDK_Paste; break;
- case KEY_OPEN: nKeyCode = GDK_Open; break;
- }
- }
-
- *pGdkKeyCode = nKeyCode;
-}
-
-OUString GtkSalFrame::GetKeyName( sal_uInt16 nKeyCode )
-{
-#if !GTK_CHECK_VERSION(3,0,0)
- return getDisplay()->GetKeyName( nKeyCode );
-#else
- guint nGtkKeyCode;
- GdkModifierType nGtkModifiers;
- KeyCodeToGdkKey(nKeyCode, &nGtkKeyCode, &nGtkModifiers );
-
- gchar* pName = gtk_accelerator_get_label(nGtkKeyCode, nGtkModifiers);
- OUString aRet(pName, rtl_str_getLength(pName), RTL_TEXTENCODING_UTF8);
- g_free(pName);
- return aRet;
-#endif
-}
-
-GdkDisplay *GtkSalFrame::getGdkDisplay()
-{
- return GetGtkSalData()->GetGdkDisplay();
-}
-
-GtkSalDisplay *GtkSalFrame::getDisplay()
-{
- return GetGtkSalData()->GetGtkDisplay();
-}
-
-SalFrame::SalPointerState GtkSalFrame::GetPointerState()
-{
- SalPointerState aState;
- GdkScreen* pScreen;
- gint x, y;
- GdkModifierType aMask;
- gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
- aState.maPos = Point( x - maGeometry.nX, y - maGeometry.nY );
- aState.mnState = GetMouseModCode( aMask );
- return aState;
-}
-
-KeyIndicatorState GtkSalFrame::GetIndicatorState()
-{
-#if !GTK_CHECK_VERSION(3,0,0)
- return GetGtkSalData()->GetGtkDisplay()->GetIndicatorState();
-#else
- KeyIndicatorState nState = KeyIndicatorState::NONE;
-
- GdkKeymap *pKeyMap = gdk_keymap_get_for_display(getGdkDisplay());
-
- if (gdk_keymap_get_caps_lock_state(pKeyMap))
- nState |= KeyIndicatorState::CAPSLOCK;
- if (gdk_keymap_get_num_lock_state(pKeyMap))
- nState |= KeyIndicatorState::NUMLOCK;
-#if GTK_CHECK_VERSION(3,18,0)
- if (gdk_keymap_get_scroll_lock_state(pKeyMap))
- nState |= KeyIndicatorState::SCROLLLOCK;
-#endif
- return nState;
-#endif
-}
-
-void GtkSalFrame::SimulateKeyPress( sal_uInt16 nKeyCode )
-{
-#if !GTK_CHECK_VERSION(3,0,0)
- GetGtkSalData()->GetGtkDisplay()->SimulateKeyPress(nKeyCode);
-#else
- g_warning ("missing simulate keypress %d", nKeyCode);
-#endif
-}
-
-void GtkSalFrame::SetInputContext( SalInputContext* pContext )
-{
- if( ! pContext )
- return;
-
- if( ! (pContext->mnOptions & InputContextFlags::Text) )
- return;
-
- // create a new im context
- if( ! m_pIMHandler )
- m_pIMHandler = new IMHandler( this );
-}
-
-void GtkSalFrame::EndExtTextInput( sal_uInt16 nFlags )
-{
- if( m_pIMHandler )
- m_pIMHandler->endExtTextInput( nFlags );
-}
-
-bool GtkSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& )
-{
- // not supported yet
- return false;
-}
-
-LanguageType GtkSalFrame::GetInputLanguage()
-{
- return LANGUAGE_DONTKNOW;
-}
-
-void GtkSalFrame::UpdateSettings( AllSettings& rSettings )
-{
- if( ! m_pWindow )
- return;
-
- GtkSalGraphics* pGraphics = static_cast<GtkSalGraphics*>(m_aGraphics[0].pGraphics);
- bool bFreeGraphics = false;
- if( ! pGraphics )
- {
- pGraphics = static_cast<GtkSalGraphics*>(AcquireGraphics());
- if ( !pGraphics )
- {
- SAL_WARN("vcl", "Could not get graphics - unable to update settings");
- return;
- }
- bFreeGraphics = true;
- }
-
- pGraphics->updateSettings( rSettings );
-
- if( bFreeGraphics )
- ReleaseGraphics( pGraphics );
-}
-
-void GtkSalFrame::Beep()
-{
- gdk_display_beep( getGdkDisplay() );
-}
-
-const SystemEnvData* GtkSalFrame::GetSystemData() const
-{
- return &m_aSystemData;
-}
-
-void GtkSalFrame::SetParent( SalFrame* pNewParent )
-{
- if( m_pParent )
- m_pParent->m_aChildren.remove( this );
- m_pParent = static_cast<GtkSalFrame*>(pNewParent);
- if( m_pParent )
- m_pParent->m_aChildren.push_back( this );
- if( ! isChild() )
- gtk_window_set_transient_for( GTK_WINDOW(m_pWindow),
- (m_pParent && ! m_pParent->isChild(true,false)) ? GTK_WINDOW(m_pParent->m_pWindow) : NULL
- );
-}
-
-#if !GTK_CHECK_VERSION(3,0,0)
-
-void GtkSalFrame::createNewWindow( ::Window aNewParent, bool bXEmbed, SalX11Screen nXScreen )
-{
- bool bWasVisible = m_pWindow && IS_WIDGET_MAPPED(m_pWindow);
- if( bWasVisible )
- Show( false );
-
- if( (int)nXScreen.getXScreen() >= getDisplay()->GetXScreenCount() )
- nXScreen = m_nXScreen;
-
- SystemParentData aParentData;
- aParentData.aWindow = aNewParent;
- aParentData.bXEmbedSupport = bXEmbed;
- if( aNewParent == None )
- {
- aNewParent = getDisplay()->GetRootWindow(nXScreen);
- aParentData.aWindow = None;
- aParentData.bXEmbedSupport = false;
- }
- else
- {
- // is new parent a root window ?
- Display* pDisp = getDisplay()->GetDisplay();
- int nScreens = getDisplay()->GetXScreenCount();
- for( int i = 0; i < nScreens; i++ )
- {
- if( aNewParent == RootWindow( pDisp, i ) )
- {
- nXScreen = SalX11Screen( i );
- aParentData.aWindow = None;
- aParentData.bXEmbedSupport = false;
- break;
- }
- }
- }
-
- // free xrender resources
- for( unsigned int i = 0; i < SAL_N_ELEMENTS(m_aGraphics); i++ )
- if( m_aGraphics[i].bInUse )
- m_aGraphics[i].pGraphics->SetDrawable( None, m_nXScreen );
-
- // first deinit frame
- if( m_pIMHandler )
- {
- delete m_pIMHandler;
- m_pIMHandler = NULL;
- }
- if( m_pRegion )
- {
- gdk_region_destroy( m_pRegion );
- }
-
- 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) );
- if( m_pWindow )
- 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 ) );
-
- // init new window
- m_bDefaultPos = m_bDefaultSize = false;
- if( aParentData.aWindow != None )
- {
- m_nStyle |= SAL_FRAME_STYLE_PLUG;
- Init( &aParentData );
- }
- else
- {
- m_nStyle &= ~SAL_FRAME_STYLE_PLUG;
- Init( (m_pParent && m_pParent->m_nXScreen == m_nXScreen) ? m_pParent : NULL, m_nStyle );
- }
-
- // update graphics
- for( unsigned int i = 0; i < SAL_N_ELEMENTS(m_aGraphics); i++ )
- {
- if( m_aGraphics[i].bInUse )
- {
- m_aGraphics[i].pGraphics->SetDrawable( widget_get_xid(m_pWindow), m_nXScreen );
- m_aGraphics[i].pGraphics->SetWindow( m_pWindow );
- }
- }
-
- if( ! m_aTitle.isEmpty() )
- SetTitle( m_aTitle );
-
- if( bWasVisible )
- Show( true );
-
- std::list< GtkSalFrame* > aChildren = m_aChildren;
- m_aChildren.clear();
- for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
- (*it)->createNewWindow( None, false, m_nXScreen );
-
- // FIXME: SalObjects
-}
-#endif
-
-bool GtkSalFrame::SetPluginParent( SystemParentData* pSysParent )
-{
-#if !GTK_CHECK_VERSION(3,0,0)
- GetGenericData()->ErrorTrapPush(); // permanantly ignore unruly children's errors
- createNewWindow( pSysParent->aWindow, (pSysParent->nSize > sizeof(long)) && pSysParent->bXEmbedSupport, m_nXScreen );
- return true;
-#else
- (void)pSysParent;
- //FIXME: no SetPluginParent impl. for gtk3
- return false;
-#endif
-}
-
-void GtkSalFrame::ResetClipRegion()
-{
- if( m_pWindow )
- gdk_window_shape_combine_region( widget_get_window( m_pWindow ), NULL, 0, 0 );
-}
-
-void GtkSalFrame::BeginSetClipRegion( sal_uLong )
-{
-#if GTK_CHECK_VERSION(3,0,0)
- if( m_pRegion )
- cairo_region_destroy( m_pRegion );
- m_pRegion = cairo_region_create();
-#else
- if( m_pRegion )
- gdk_region_destroy( m_pRegion );
- m_pRegion = gdk_region_new();
-#endif
-}
-
-void GtkSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
-{
- if( m_pRegion )
- {
- GdkRectangle aRect;
- aRect.x = nX;
- aRect.y = nY;
- aRect.width = nWidth;
- aRect.height = nHeight;
-#if GTK_CHECK_VERSION(3,0,0)
- cairo_region_union_rectangle( m_pRegion, &aRect );
-#else
- gdk_region_union_with_rect( m_pRegion, &aRect );
-#endif
- }
-}
-
-void GtkSalFrame::EndSetClipRegion()
-{
- if( m_pWindow && m_pRegion )
- gdk_window_shape_combine_region( widget_get_window(m_pWindow), m_pRegion, 0, 0 );
-}
-
-#if !GTK_CHECK_VERSION(3,0,0)
-bool GtkSalFrame::Dispatch( const XEvent* pEvent )
-{
- bool bContinueDispatch = true;
-
- if( pEvent->type == PropertyNotify )
- {
- vcl_sal::WMAdaptor* pAdaptor = getDisplay()->getWMAdaptor();
- Atom nDesktopAtom = pAdaptor->getAtom( vcl_sal::WMAdaptor::NET_WM_DESKTOP );
- if( pEvent->xproperty.atom == nDesktopAtom &&
- pEvent->xproperty.state == PropertyNewValue )
- {
- m_nWorkArea = pAdaptor->getWindowWorkArea( widget_get_xid(m_pWindow) );
- }
- }
- else if( pEvent->type == ConfigureNotify )
- {
- if( m_pForeignParent && pEvent->xconfigure.window == m_aForeignParentWindow )
- {
- bContinueDispatch = false;
- gtk_window_resize( GTK_WINDOW(m_pWindow), pEvent->xconfigure.width, pEvent->xconfigure.height );
- if( ( sal::static_int_cast< int >(maGeometry.nWidth) !=
- pEvent->xconfigure.width ) ||
- ( sal::static_int_cast< int >(maGeometry.nHeight) !=
- pEvent->xconfigure.height ) )
- {
- maGeometry.nWidth = pEvent->xconfigure.width;
- maGeometry.nHeight = pEvent->xconfigure.height;
- setMinMaxSize();
- getDisplay()->SendInternalEvent( this, NULL, SALEVENT_RESIZE );
- }
- }
- else if( m_pForeignTopLevel && pEvent->xconfigure.window == m_aForeignTopLevelWindow )
- {
- bContinueDispatch = false;
- // update position
- int x = 0, y = 0;
- ::Window aChild;
- XTranslateCoordinates( getDisplay()->GetDisplay(),
- widget_get_xid(m_pWindow),
- getDisplay()->GetRootWindow( getDisplay()->GetDefaultXScreen() ),
- 0, 0,
- &x, &y,
- &aChild );
- if( x != maGeometry.nX || y != maGeometry.nY )
- {
- maGeometry.nX = x;
- maGeometry.nY = y;
- getDisplay()->SendInternalEvent( this, NULL, SALEVENT_MOVE );
- }
- }
- }
- else if( pEvent->type == ClientMessage &&
- pEvent->xclient.message_type == getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED ) &&
- pEvent->xclient.window == widget_get_xid(m_pWindow) &&
- m_bWindowIsGtkPlug
- )
- {
- // FIXME: this should not be necessary, GtkPlug should do this
- // transparently for us
- if( pEvent->xclient.data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
- pEvent->xclient.data.l[1] == 2 // XEMBED_WINDOW_DEACTIVATE
- )
- {
- GdkEventFocus aEvent;
- aEvent.type = GDK_FOCUS_CHANGE;
- aEvent.window = widget_get_window( m_pWindow );
- aEvent.send_event = gint8(TRUE);
- aEvent.in = gint16(pEvent->xclient.data.l[1] == 1);
- signalFocus( m_pWindow, &aEvent, this );
- }
- }
-
- return bContinueDispatch;
-}
-#endif
-
-gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
- SalMouseEvent aEvent;
- sal_uInt16 nEventType = 0;
- switch( pEvent->type )
- {
- case GDK_BUTTON_PRESS:
- nEventType = SALEVENT_MOUSEBUTTONDOWN;
- break;
- case GDK_BUTTON_RELEASE:
- nEventType = SALEVENT_MOUSEBUTTONUP;
- break;
- default:
- return false;
- }
- switch( pEvent->button )
- {
- case 1: aEvent.mnButton = MOUSE_LEFT; break;
- case 2: aEvent.mnButton = MOUSE_MIDDLE; break;
- case 3: aEvent.mnButton = MOUSE_RIGHT; break;
- default: return false;
- }
- aEvent.mnTime = pEvent->time;
- aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
- aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
- aEvent.mnCode = GetMouseModCode( pEvent->state );
-
- bool bClosePopups = false;
- if( pEvent->type == GDK_BUTTON_PRESS &&
- (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) == 0
- )
- {
- if( m_nFloats > 0 )
- {
- // close popups if user clicks outside our application
- gint x, y;
- bClosePopups = (gdk_display_get_window_at_pointer( GtkSalFrame::getGdkDisplay(), &x, &y ) == NULL);
- }
- /* #i30306# release implicit pointer grab if no popups are open; else
- * Drag cannot grab the pointer and will fail.
- */
- if( m_nFloats < 1 || bClosePopups )
- gdk_display_pointer_ungrab( GtkSalFrame::getGdkDisplay(), GDK_CURRENT_TIME );
- }
-
- if( pThis->m_bWindowIsGtkPlug &&
- pEvent->type == GDK_BUTTON_PRESS &&
- pEvent->button == 1 )
- {
- pThis->askForXEmbedFocus( pEvent->time );
- }
-
- // --- RTL --- (mirror mouse pos)
- if( AllSettings::GetLayoutRTL() )
- aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
-
- vcl::DeletionListener aDel( pThis );
-
- pThis->CallCallback( nEventType, &aEvent );
-
- if( ! aDel.isDeleted() )
- {
- if( bClosePopups )
- {
- ImplSVData* pSVData = ImplGetSVData();
- if ( pSVData->maWinData.mpFirstFloat )
- {
- static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
- if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FloatWinPopupFlags::NoAppFocusClose) && !(pEnv && *pEnv) )
- pSVData->maWinData.mpFirstFloat->EndPopupMode( FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll );
- }
- }
-
- if( ! aDel.isDeleted() )
- {
- int frame_x = (int)(pEvent->x_root - pEvent->x);
- int frame_y = (int)(pEvent->y_root - pEvent->y);
- if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
- {
- pThis->maGeometry.nX = frame_x;
- pThis->maGeometry.nY = frame_y;
- pThis->CallCallback( SALEVENT_MOVE, NULL );
- }
- }
- }
-
- return true;
-}
-
-#if GTK_CHECK_VERSION(3,0,0)
-void GtkSalFrame::signalFlagsChanged( GtkWidget* , GtkStateFlags state, gpointer frame )
-{
- //TO-DO: This isn't as helpful as I'd like it to be. The color selector puts the main
- //windows into the backdrop, disabling everything, and the floating navigator window
- //is also problematic.
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
- bool bOldBackDrop = state & GTK_STATE_FLAG_BACKDROP;
- bool bNewBackDrop = (gtk_widget_get_state_flags(GTK_WIDGET(pThis->m_pWindow)) & GTK_STATE_FLAG_BACKDROP);
- if (bNewBackDrop && !bOldBackDrop)
- {
- pThis->GetWindow()->Disable();
- }
- else if (bOldBackDrop && !bNewBackDrop)
- {
- pThis->GetWindow()->Enable();
- }
-}
-#endif
-
-gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEvent* pEvent, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
- GdkEventScroll* pSEvent = reinterpret_cast<GdkEventScroll*>(pEvent);
-
-#if GTK_CHECK_VERSION(3,0,0)
- // gnome#726878 check for duplicate legacy scroll event
- if (pSEvent->direction != GDK_SCROLL_SMOOTH &&
- pThis->m_nLastScrollEventTime == pSEvent->time)
- {
- return true;
- }
-#endif
-
- SalWheelMouseEvent aEvent;
-
- aEvent.mnTime = pSEvent->time;
- aEvent.mnX = (sal_uLong)pSEvent->x;
- aEvent.mnY = (sal_uLong)pSEvent->y;
- aEvent.mnCode = GetMouseModCode( pSEvent->state );
- aEvent.mnScrollLines = 3;
-
- switch (pSEvent->direction)
- {
-#if GTK_CHECK_VERSION(3,0,0)
- case GDK_SCROLL_SMOOTH:
- {
- double delta_x, delta_y;
- gdk_event_get_scroll_deltas(pEvent, &delta_x, &delta_y);
- //pick the bigger one I guess
- aEvent.mbHorz = fabs(delta_x) > fabs(delta_y);
- if (aEvent.mbHorz)
- aEvent.mnDelta = -delta_x;
- else
- aEvent.mnDelta = -delta_y;
- aEvent.mnScrollLines = 1;
- pThis->m_nLastScrollEventTime = pSEvent->time;
- break;
- }
-#endif
- case GDK_SCROLL_UP:
- aEvent.mnDelta = 120;
- aEvent.mbHorz = false;
- break;
- case GDK_SCROLL_DOWN:
- aEvent.mnDelta = -120;
- aEvent.mbHorz = false;
- break;
- case GDK_SCROLL_LEFT:
- aEvent.mbHorz = true;
- aEvent.mnDelta = 120;
- break;
- case GDK_SCROLL_RIGHT:
- aEvent.mnDelta = -120;
- aEvent.mbHorz = true;
- break;
- };
-
- aEvent.mnNotchDelta = aEvent.mnDelta < 0 ? -1 : 1;
-
- // --- RTL --- (mirror mouse pos)
- if( AllSettings::GetLayoutRTL() )
- aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
-
- pThis->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
-
- return true;
-}
-
-#if GTK_CHECK_VERSION(3,14,0)
-void GtkSalFrame::gestureSwipe(GtkGestureSwipe* gesture, gdouble velocity_x, gdouble velocity_y, gpointer frame)
-{
- gdouble x, y;
- GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
- //I feel I want the first point of the sequence, not the last point which
- //the docs say this gives, but for the moment assume we start and end
- //within the same vcl window
- if (gtk_gesture_get_point(GTK_GESTURE(gesture), sequence, &x, &y))
- {
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
- SalSwipeEvent aEvent;
- aEvent.mnVelocityX = velocity_x;
- aEvent.mnVelocityY = velocity_y;
- aEvent.mnX = x;
- aEvent.mnY = y;
-
- pThis->CallCallback(SALEVENT_SWIPE, &aEvent);
- }
-}
-
-void GtkSalFrame::gestureLongPress(GtkGestureLongPress* gesture, gpointer frame)
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
- if(pThis)
- {
- SalLongPressEvent aEvent;
-
- gdouble x, y;
- GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
- gtk_gesture_get_point(GTK_GESTURE(gesture), sequence, &x, &y);
- aEvent.mnX = x;
- aEvent.mnY = y;
-
- pThis->CallCallback(SALEVENT_LONGPRESS, &aEvent);
- }
-}
-
-#endif
-
-gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
- SalMouseEvent aEvent;
- aEvent.mnTime = pEvent->time;
- aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
- aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
- aEvent.mnCode = GetMouseModCode( pEvent->state );
- aEvent.mnButton = 0;
-
- // --- RTL --- (mirror mouse pos)
- if( AllSettings::GetLayoutRTL() )
- aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
-
- vcl::DeletionListener aDel( pThis );
-
- pThis->CallCallback( SALEVENT_MOUSEMOVE, &aEvent );
-
- if( ! aDel.isDeleted() )
- {
- int frame_x = (int)(pEvent->x_root - pEvent->x);
- int frame_y = (int)(pEvent->y_root - pEvent->y);
- if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
- {
- pThis->maGeometry.nX = frame_x;
- pThis->maGeometry.nY = frame_y;
- pThis->CallCallback( SALEVENT_MOVE, NULL );
- }
-
- if( ! aDel.isDeleted() )
- {
- // ask for the next hint
- gint x, y;
- GdkModifierType mask;
- gdk_window_get_pointer( widget_get_window(GTK_WIDGET(pThis->m_pWindow)), &x, &y, &mask );
- }
- }
-
- return true;
-}
-
-gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
- SalMouseEvent aEvent;
- aEvent.mnTime = pEvent->time;
- aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
- aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
- aEvent.mnCode = GetMouseModCode( pEvent->state );
- aEvent.mnButton = 0;
-
- pThis->CallCallback( (pEvent->type == GDK_ENTER_NOTIFY) ? SALEVENT_MOUSEMOVE : SALEVENT_MOUSELEAVE, &aEvent );
-
- return true;
-}
-
-#if GTK_CHECK_VERSION(3,0,0)
-
-cairo_t* GtkSalFrame::getCairoContext() const
-{
- cairo_t* cr = SvpSalGraphics::createCairoContext(m_aFrame);
- assert(cr);
- return cr;
-}
-
-void GtkSalFrame::damaged (const basegfx::B2IBox& rDamageRect)
-{
-#if OSL_DEBUG_LEVEL > 1
- long long area = rDamageRect.getWidth() * rDamageRect.getHeight();
- if( area > 32 * 1024 )
- {
- fprintf( stderr, "bitmap damaged %d %d (%dx%d) area %lld widget\n",
- (int) rDamageRect.getMinX(),
- (int) rDamageRect.getMinY(),
- (int) rDamageRect.getWidth(),
- (int) rDamageRect.getHeight(),
- area );
- }
-#endif
-
- if (dumpframes)
- {
- static int frame;
- OString tmp("/tmp/frame" + OString::number(frame++) + ".png");
- cairo_t* cr = getCairoContext();
- cairo_surface_write_to_png(cairo_get_target(cr), tmp.getStr());
- cairo_destroy(cr);
- }
-
- gtk_widget_queue_draw_area(GTK_WIDGET(m_pFixedContainer),
- rDamageRect.getMinX(),
- rDamageRect.getMinY(),
- rDamageRect.getWidth(),
- rDamageRect.getHeight());
-}
-
-// blit our backing basebmp buffer to the target cairo context cr
-gboolean GtkSalFrame::signalDraw( GtkWidget*, cairo_t *cr, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
- cairo_save(cr);
-
- cairo_t* source = pThis->getCairoContext();
- cairo_surface_t *pSurface = cairo_get_target(source);
-
- cairo_set_operator( cr, CAIRO_OPERATOR_OVER );
- cairo_set_source_surface(cr, pSurface, 0, 0);
- cairo_paint(cr);
-
- cairo_destroy(source);
-
- cairo_restore(cr);
-
- cairo_surface_flush(cairo_get_target(cr));
-
- return false;
-}
-
-void GtkSalFrame::sizeAllocated(GtkWidget*, GdkRectangle *pAllocation, gpointer frame)
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
- bool bSized = false;
-
- if( pThis->m_bFullscreen || (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)) == SAL_FRAME_STYLE_SIZEABLE )
- {
- if( pAllocation->width != (int)pThis->maGeometry.nWidth || pAllocation->height != (int)pThis->maGeometry.nHeight )
- {
- bSized = true;
- pThis->maGeometry.nWidth = pAllocation->width;
- pThis->maGeometry.nHeight = pAllocation->height;
- }
- }
-
- if( bSized )
- {
- pThis->AllocateFrame();
- pThis->CallCallback( SALEVENT_RESIZE, nullptr );
- pThis->TriggerPaintEvent();
- }
-}
-
-gboolean GtkSalFrame::signalConfigure(GtkWidget*, GdkEventConfigure* pEvent, gpointer frame)
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
- pThis->m_bPaintsBlocked = false;
-
- bool bMoved = false;
- int x = pEvent->x, y = pEvent->y;
-
- /* HACK: during sizing/moving a toolbar pThis->maGeometry is actually
- * already exact; even worse: due to the asynchronicity of configure
- * events the borderwindow which would evaluate this event
- * would size/move based on wrong data if we would actually evaluate
- * this event. So let's swallow it.
- */
- if( (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
- GtkSalFrame::getDisplay()->GetCaptureFrame() == pThis )
- return false;
-
- /* #i31785# claims we cannot trust the x,y members of the event;
- * they are e.g. not set correctly on maximize/demaximize;
- * yet the gdkdisplay-x11.c code handling configure_events has
- * done this XTranslateCoordinates work since the day ~zero.
- */
- if( x != pThis->maGeometry.nX || y != pThis->maGeometry.nY )
- {
- bMoved = true;
- pThis->maGeometry.nX = x;
- pThis->maGeometry.nY = y;
- }
-
- // update decoration hints
- if( ! (pThis->m_nStyle & SAL_FRAME_STYLE_PLUG) )
- {
- GdkRectangle aRect;
- gdk_window_get_frame_extents( widget_get_window(GTK_WIDGET(pThis->m_pWindow)), &aRect );
- pThis->maGeometry.nTopDecoration = y - aRect.y;
- pThis->maGeometry.nBottomDecoration = aRect.y + aRect.height - y - pEvent->height;
- pThis->maGeometry.nLeftDecoration = x - aRect.x;
- pThis->maGeometry.nRightDecoration = aRect.x + aRect.width - x - pEvent->width;
- }
- else
- {
- pThis->maGeometry.nTopDecoration =
- pThis->maGeometry.nBottomDecoration =
- pThis->maGeometry.nLeftDecoration =
- pThis->maGeometry.nRightDecoration = 0;
- }
-
- pThis->updateScreenNumber();
-
- if (bMoved)
- pThis->CallCallback(SALEVENT_MOVE, nullptr);
-
- return false;
-}
-#else
-gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
- pThis->m_bPaintsBlocked = false;
-
- struct SalPaintEvent aEvent( pEvent->area.x, pEvent->area.y, pEvent->area.width, pEvent->area.height );
-
- pThis->CallCallback( SALEVENT_PAINT, &aEvent );
-
- return false;
-}
-
-gboolean GtkSalFrame::signalConfigure( GtkWidget*, GdkEventConfigure* pEvent, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
- pThis->m_bPaintsBlocked = false;
-
- bool bMoved = false, bSized = false;
- int x = pEvent->x, y = pEvent->y;
-
- /* HACK: during sizing/moving a toolbar pThis->maGeometry is actually
- * already exact; even worse: due to the asynchronicity of configure
- * events the borderwindow which would evaluate this event
- * would size/move based on wrong data if we would actually evaluate
- * this event. So let's swallow it.
- */
- if( (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
- GtkSalFrame::getDisplay()->GetCaptureFrame() == pThis )
- return false;
-
- /* #i31785# claims we cannot trust the x,y members of the event;
- * they are e.g. not set correctly on maximize/demaximize;
- * yet the gdkdisplay-x11.c code handling configure_events has
- * done this XTranslateCoordinates work since the day ~zero.
- */
- if( x != pThis->maGeometry.nX || y != pThis->maGeometry.nY )
- {
- bMoved = true;
- pThis->maGeometry.nX = x;
- pThis->maGeometry.nY = y;
- }
- /* #i86302#
- * for non sizeable windows we set the min and max hint for the window manager to
- * achieve correct sizing. However this is asynchronous and e.g. on Compiz
- * it sometimes happens that the window gets resized to another size (some default)
- * if we update the size here, subsequent setMinMaxSize will use this wrong size
- * - which is not good since the window manager will now size the window back to this
- * wrong size at some point.
- */
- if( pThis->m_bFullscreen || (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)) == SAL_FRAME_STYLE_SIZEABLE )
- {
- if( pEvent->width != (int)pThis->maGeometry.nWidth || pEvent->height != (int)pThis->maGeometry.nHeight )
- {
- bSized = true;
- pThis->maGeometry.nWidth = pEvent->width;
- pThis->maGeometry.nHeight = pEvent->height;
- }
- }
-
- // update decoration hints
- if( ! (pThis->m_nStyle & SAL_FRAME_STYLE_PLUG) )
- {
- GdkRectangle aRect;
- gdk_window_get_frame_extents( widget_get_window(GTK_WIDGET(pThis->m_pWindow)), &aRect );
- pThis->maGeometry.nTopDecoration = y - aRect.y;
- pThis->maGeometry.nBottomDecoration = aRect.y + aRect.height - y - pEvent->height;
- pThis->maGeometry.nLeftDecoration = x - aRect.x;
- pThis->maGeometry.nRightDecoration = aRect.x + aRect.width - x - pEvent->width;
- }
- else
- {
- pThis->maGeometry.nTopDecoration =
- pThis->maGeometry.nBottomDecoration =
- pThis->maGeometry.nLeftDecoration =
- pThis->maGeometry.nRightDecoration = 0;
- }
-
- pThis->updateScreenNumber();
- if( bSized )
- pThis->AllocateFrame();
-
- if( bMoved && bSized )
- pThis->CallCallback( SALEVENT_MOVERESIZE, nullptr );
- else if( bMoved )
- pThis->CallCallback( SALEVENT_MOVE, nullptr );
- else if( bSized )
- pThis->CallCallback( SALEVENT_RESIZE, nullptr );
-
- if (bSized)
- pThis->TriggerPaintEvent();
- return false;
-}
-
-#endif // GTK_CHECK_VERSION(3,0,0)
-
-void GtkSalFrame::TriggerPaintEvent()
-{
- //Under gtk2 we can basically paint directly into the XWindow and on
- //additional "expose-event" events we can re-render the missing pieces
- //
- //Under gtk3 we have to keep our own buffer up to date and flush it into
- //the given cairo context on "draw". So we emit a paint event on
- //opportune resize trigger events to initially fill our backbuffer and then
- //keep it up to date with our direct paints and tell gtk those regions
- //have changed and then blit them into the provided cairo context when
- //we get the "draw"
- //
- //The other alternative was to always paint everything on "draw", but
- //that duplicates the amount of drawing and is hideously slow
-#if GTK_CHECK_VERSION(3,0,0)
- SAL_INFO("vcl.gtk3", "force painting" << 0 << "," << 0 << " " << maGeometry.nWidth << "x" << maGeometry.nHeight);
- SalPaintEvent aPaintEvt(0, 0, maGeometry.nWidth, maGeometry.nHeight, true);
- CallCallback(SALEVENT_PAINT, &aPaintEvt);
- gtk_widget_queue_draw(GTK_WIDGET(m_pFixedContainer));
-#endif
-}
-
-gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
- SalGenericInstance *pSalInstance =
- static_cast< SalGenericInstance* >(GetSalData()->m_pInstance);
-
- // check if printers have changed (analogous to salframe focus handler)
- pSalInstance->updatePrinterUpdate();
-
- if( !pEvent->in )
- {
- pThis->m_nKeyModifiers = 0;
- pThis->m_bSendModChangeOnRelease = false;
- }
-
- if( pThis->m_pIMHandler )
- pThis->m_pIMHandler->focusChanged( pEvent->in );
-
- // ask for changed printers like generic implementation
- if( pEvent->in && pSalInstance->isPrinterInit() )
- pSalInstance->updatePrinterUpdate();
-
- // FIXME: find out who the hell steals the focus from our frame
- // while we have the pointer grabbed, this should not come from
- // the window manager. Is this an event that was still queued ?
- // The focus does not seem to get set inside our process
-
- // in the meantime do not propagate focus get/lose if floats are open
- if( m_nFloats == 0 )
- pThis->CallCallback( pEvent->in ? SALEVENT_GETFOCUS : SALEVENT_LOSEFOCUS, NULL );
-
- return false;
-}
-
-#if !GTK_CHECK_VERSION(3,8,0)
-static OString getDisplayString()
-{
- int nParams = rtl_getAppCommandArgCount();
- OUString aParam;
- for( int i = 0; i < nParams; i++ )
- {
- rtl_getAppCommandArg( i, &aParam.pData );
- if( i < nParams-1 && (aParam == "-display" || aParam == "--display" ) )
- {
- rtl_getAppCommandArg( i+1, &aParam.pData );
- return OUStringToOString( aParam, osl_getThreadTextEncoding() );
- }
- }
- return OString();
-}
-#endif
-
-gboolean GtkSalFrame::signalMap( GtkWidget *pWidget, GdkEvent*, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
-#if !GTK_CHECK_VERSION(3,8,0)
- //Spawn off a helper program that will attempt to set this fullscreen
- //window to span all displays.
- if (pThis->m_bFullscreen && pThis->m_bSpanMonitorsWhenFullscreen)
- {
- GdkWindow* gdkwin = widget_get_window(pThis->m_pWindow);
- if (gdkwin)
- {
- OUString sProgramURL( "$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER "/xid-fullscreen-on-all-monitors");
- rtl::Bootstrap::expandMacros(sProgramURL);
- OUString sProgram;
- if (osl::FileBase::getSystemPathFromFileURL(sProgramURL, sProgram) == osl::File::E_None)
- {
- OString sFinalProgram(OUStringToOString(sProgram, osl_getThreadTextEncoding())
- + " " + OString::number((int)GDK_WINDOW_XID(gdkwin)));
- OString sDisplay(getDisplayString());
- if (!sDisplay.isEmpty())
- {
- sFinalProgram += "--display " + sDisplay;
- }
- int returnValue = system(sFinalProgram.getStr());
- (void)returnValue;
- }
- }
- }
-#endif
-
- bool bSetFocus = pThis->m_bSetFocusOnMap;
- pThis->m_bSetFocusOnMap = false;
-
-#if !GTK_CHECK_VERSION(3,0,0)
- if( bSetFocus )
- {
- GetGenericData()->ErrorTrapPush();
- XSetInputFocus( GtkSalFrame::getDisplay()->GetDisplay(),
- widget_get_xid(pWidget),
- RevertToParent, CurrentTime );
- XSync( GtkSalFrame::getDisplay()->GetDisplay(), False );
- GetGenericData()->ErrorTrapPop();
- }
-#else
- (void)pWidget; (void)bSetFocus;
- //FIXME: no set input focus ...
-#endif
-
- pThis->CallCallback( SALEVENT_RESIZE, NULL );
- pThis->TriggerPaintEvent();
-
- return false;
-}
-
-gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
- pThis->CallCallback( SALEVENT_RESIZE, NULL );
-
- return false;
-}
-
-gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
- vcl::DeletionListener aDel( pThis );
-
- if( pThis->m_pIMHandler )
- {
- if( pThis->m_pIMHandler->handleKeyEvent( pEvent ) )
- return true;
- }
-
- // handle modifiers
- if( pEvent->keyval == GDK_Shift_L || pEvent->keyval == GDK_Shift_R ||
- pEvent->keyval == GDK_Control_L || pEvent->keyval == GDK_Control_R ||
- pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ||
- pEvent->keyval == GDK_Meta_L || pEvent->keyval == GDK_Meta_R ||
- pEvent->keyval == GDK_Super_L || pEvent->keyval == GDK_Super_R )
- {
- SalKeyModEvent aModEvt;
-
- sal_uInt16 nModCode = GetKeyModCode( pEvent->state );
-
- aModEvt.mnModKeyCode = 0; // emit no MODKEYCHANGE events
- if( pEvent->type == GDK_KEY_PRESS && !pThis->m_nKeyModifiers )
- pThis->m_bSendModChangeOnRelease = true;
-
- else if( pEvent->type == GDK_KEY_RELEASE &&
- pThis->m_bSendModChangeOnRelease )
- {
- aModEvt.mnModKeyCode = pThis->m_nKeyModifiers;
- pThis->m_nKeyModifiers = 0;
- }
-
- sal_uInt16 nExtModMask = 0;
- sal_uInt16 nModMask = 0;
- // pressing just the ctrl key leads to a keysym of XK_Control but
- // the event state does not contain ControlMask. In the release
- // event its the other way round: it does contain the Control mask.
- // The modifier mode therefore has to be adapted manually.
- switch( pEvent->keyval )
- {
- case GDK_Control_L:
- nExtModMask = MODKEY_LMOD1;
- nModMask = KEY_MOD1;
- break;
- case GDK_Control_R:
- nExtModMask = MODKEY_RMOD1;
- nModMask = KEY_MOD1;
- break;
- case GDK_Alt_L:
- nExtModMask = MODKEY_LMOD2;
- nModMask = KEY_MOD2;
- break;
- case GDK_Alt_R:
- nExtModMask = MODKEY_RMOD2;
- nModMask = KEY_MOD2;
- break;
- case GDK_Shift_L:
- nExtModMask = MODKEY_LSHIFT;
- nModMask = KEY_SHIFT;
- break;
- case GDK_Shift_R:
- nExtModMask = MODKEY_RSHIFT;
- nModMask = KEY_SHIFT;
- break;
- // Map Meta/Super to MOD3 modifier on all Unix systems
- // except Mac OS X
- case GDK_Meta_L:
- case GDK_Super_L:
- nExtModMask = MODKEY_LMOD3;
- nModMask = KEY_MOD3;
- break;
- case GDK_Meta_R:
- case GDK_Super_R:
- nExtModMask = MODKEY_RMOD3;
- nModMask = KEY_MOD3;
- break;
- }
- if( pEvent->type == GDK_KEY_RELEASE )
- {
- nModCode &= ~nModMask;
- pThis->m_nKeyModifiers &= ~nExtModMask;
- }
- else
- {
- nModCode |= nModMask;
- pThis->m_nKeyModifiers |= nExtModMask;
- }
-
- aModEvt.mnCode = nModCode;
- aModEvt.mnTime = pEvent->time;
-
- pThis->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
-
- }
- else
- {
- pThis->doKeyCallback( pEvent->state,
- pEvent->keyval,
- pEvent->hardware_keycode,
- pEvent->group,
- pEvent->time,
- sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )),
- (pEvent->type == GDK_KEY_PRESS),
- false );
- if( ! aDel.isDeleted() )
- pThis->m_bSendModChangeOnRelease = false;
- }
-
- if( !aDel.isDeleted() && pThis->m_pIMHandler )
- pThis->m_pIMHandler->updateIMSpotLocation();
-
- return true;
-}
-
-gboolean GtkSalFrame::signalDelete( GtkWidget*, GdkEvent*, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
-#if GTK_CHECK_VERSION(3,0,0)
- //If we went into the backdrop we disabled the toplevel window, if we
- //receive a delete here, re-enable so we can process it
- bool bBackDrop = (gtk_widget_get_state_flags(GTK_WIDGET(pThis->m_pWindow)) & GTK_STATE_FLAG_BACKDROP);
- if (bBackDrop)
- pThis->GetWindow()->Enable();
-#endif
-
- pThis->CallCallback( SALEVENT_CLOSE, NULL );
-
- return true;
-}
-
-void GtkSalFrame::signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
-
- // every frame gets an initial style set on creation
- // do not post these as the whole application tends to
- // redraw itself to adjust to the new style
- // where there IS no new style resulting in tremendous unnecessary flickering
- if( pPrevious != NULL )
- {
- // signalStyleSet does NOT usually have the gdk lock
- // so post user event to safely dispatch the SALEVENT_SETTINGSCHANGED
- // note: settings changed for multiple frames is avoided in winproc.cxx ImplHandleSettings
- GtkSalFrame::getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_SETTINGSCHANGED );
- GtkSalFrame::getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_FONTCHANGED );
- }
-
-#if !GTK_CHECK_VERSION(3,0,0)
- /* #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
- */
- GdkWindow* pWin = widget_get_window(GTK_WIDGET(pThis->getWindow()));
- if( pWin )
- {
- ::Window aWin = GDK_WINDOW_XWINDOW(pWin);
- if( aWin != None )
- XSetWindowBackgroundPixmap( GtkSalFrame::getDisplay()->GetDisplay(),
- aWin,
- pThis->m_hBackgroundPixmap );
- }
- if( ! pThis->m_pParent )
- {
- // signalize theme changed for NWF caches
- // FIXME: should be called only once for a style change
- GtkSalGraphics::bThemeChanged = true;
- }
-#endif
-}
-
-gboolean GtkSalFrame::signalWindowState( GtkWidget*, GdkEvent* pEvent, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
- if( (pThis->m_nState & GDK_WINDOW_STATE_ICONIFIED) != (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED ) )
- {
- GtkSalFrame::getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_RESIZE );
- pThis->TriggerPaintEvent();
- }
-
- if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) &&
- ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) )
- {
- pThis->m_aRestorePosSize =
- Rectangle( Point( pThis->maGeometry.nX, pThis->maGeometry.nY ),
- Size( pThis->maGeometry.nWidth, pThis->maGeometry.nHeight ) );
- }
- pThis->m_nState = pEvent->window_state.new_window_state;
-
- #if OSL_DEBUG_LEVEL > 1
- if( (pEvent->window_state.changed_mask & GDK_WINDOW_STATE_FULLSCREEN) )
- {
- fprintf( stderr, "window %p %s full screen state\n",
- pThis,
- (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_FULLSCREEN) ? "enters" : "leaves");
- }
- #endif
-
- return false;
-}
-
-gboolean GtkSalFrame::signalVisibility( GtkWidget*, GdkEventVisibility* pEvent, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
- pThis->m_nVisibility = pEvent->state;
- return true;
-}
-
-void GtkSalFrame::signalDestroy( GtkWidget* pObj, gpointer frame )
-{
- GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
- if( pObj == pThis->m_pWindow )
- {
- pThis->m_pFixedContainer = NULL;
- pThis->m_pEventBox = NULL;
- pThis->m_pWindow = NULL;
- pThis->InvalidateGraphics();
- }
-}
-
-// GtkSalFrame::IMHandler
-
-GtkSalFrame::IMHandler::IMHandler( GtkSalFrame* pFrame )
-: m_pFrame(pFrame),
- m_nPrevKeyPresses( 0 ),
- m_pIMContext( NULL ),
- m_bFocused( true ),
- m_bPreeditJustChanged( false )
-{
- m_aInputEvent.mpTextAttr = NULL;
- createIMContext();
-}
-
-GtkSalFrame::IMHandler::~IMHandler()
-{
- // cancel an eventual event posted to begin preedit again
- GtkSalFrame::getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
- deleteIMContext();
-}
-
-void GtkSalFrame::IMHandler::createIMContext()
-{
- if( ! m_pIMContext )
- {
- m_pIMContext = gtk_im_multicontext_new ();
- g_signal_connect( m_pIMContext, "commit",
- G_CALLBACK (signalIMCommit), this );
- g_signal_connect( m_pIMContext, "preedit_changed",
- G_CALLBACK (signalIMPreeditChanged), this );
- g_signal_connect( m_pIMContext, "retrieve_surrounding",
- G_CALLBACK (signalIMRetrieveSurrounding), this );
- g_signal_connect( m_pIMContext, "delete_surrounding",
- G_CALLBACK (signalIMDeleteSurrounding), this );
- g_signal_connect( m_pIMContext, "preedit_start",
- G_CALLBACK (signalIMPreeditStart), this );
- g_signal_connect( m_pIMContext, "preedit_end",
- G_CALLBACK (signalIMPreeditEnd), this );
-
- GetGenericData()->ErrorTrapPush();
- gtk_im_context_set_client_window( m_pIMContext, widget_get_window(GTK_WIDGET(m_pFrame->m_pWindow)) );
- gtk_im_context_focus_in( m_pIMContext );
- GetGenericData()->ErrorTrapPop();
- m_bFocused = true;
- }
-}
-
-void GtkSalFrame::IMHandler::deleteIMContext()
-{
- if( m_pIMContext )
- {
- // first give IC a chance to deinitialize
- GetGenericData()->ErrorTrapPush();
- gtk_im_context_set_client_window( m_pIMContext, NULL );
- GetGenericData()->ErrorTrapPop();
- // destroy old IC
- g_object_unref( m_pIMContext );
- m_pIMContext = NULL;
- }
-}
-
-void GtkSalFrame::IMHandler::doCallEndExtTextInput()
-{
- m_aInputEvent.mpTextAttr = NULL;
- m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
-}
-
-void GtkSalFrame::IMHandler::updateIMSpotLocation()
-{
- SalExtTextInputPosEvent aPosEvent;
- m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent );
- GdkRectangle aArea;
- aArea.x = aPosEvent.mnX;
- aArea.y = aPosEvent.mnY;
- aArea.width = aPosEvent.mnWidth;
- aArea.height = aPosEvent.mnHeight;
- GetGenericData()->ErrorTrapPush();
- gtk_im_context_set_cursor_location( m_pIMContext, &aArea );
- GetGenericData()->ErrorTrapPop();
-}
-
-void GtkSalFrame::IMHandler::sendEmptyCommit()
-{
- vcl::DeletionListener aDel( m_pFrame );
-
- SalExtTextInputEvent aEmptyEv;
- aEmptyEv.mnTime = 0;
- aEmptyEv.mpTextAttr = 0;
- aEmptyEv.maText.clear();
- aEmptyEv.mnCursorPos = 0;
- aEmptyEv.mnCursorFlags = 0;
- aEmptyEv.mbOnlyCursor = False;
- m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv );
- if( ! aDel.isDeleted() )
- m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
-}
-
-void GtkSalFrame::IMHandler::endExtTextInput( sal_uInt16 /*nFlags*/ )
-{
- gtk_im_context_reset ( m_pIMContext );
-
- if( m_aInputEvent.mpTextAttr )
- {
- vcl::DeletionListener aDel( m_pFrame );
- // delete preedit in sal (commit an empty string)
- sendEmptyCommit();
- if( ! aDel.isDeleted() )
- {
- // mark previous preedit state again (will e.g. be sent at focus gain)
- m_aInputEvent.mpTextAttr = &m_aInputFlags[0];
- if( m_bFocused )
- {
- // begin preedit again
- GtkSalFrame::getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
- }
- }
- }
-}
-
-void GtkSalFrame::IMHandler::focusChanged( bool bFocusIn )
-{
- m_bFocused = bFocusIn;
- if( bFocusIn )
- {
- GetGenericData()->ErrorTrapPush();
- gtk_im_context_focus_in( m_pIMContext );
- GetGenericData()->ErrorTrapPop();
- if( m_aInputEvent.mpTextAttr )
- {
- sendEmptyCommit();
- // begin preedit again
- GtkSalFrame::getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
- }
- }
- else
- {
- GetGenericData()->ErrorTrapPush();
- gtk_im_context_focus_out( m_pIMContext );
- GetGenericData()->ErrorTrapPop();
- // cancel an eventual event posted to begin preedit again
- GtkSalFrame::getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
- }
-}
-
-bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent )
-{
- vcl::DeletionListener aDel( m_pFrame );
-
- if( pEvent->type == GDK_KEY_PRESS )
- {
- // Add this key press event to the list of previous key presses
- // to which we compare key release events. If a later key release
- // event has a matching key press event in this list, we swallow
- // the key release because some GTK Input Methods don't swallow it
- // for us.
- m_aPrevKeyPresses.push_back( PreviousKeyPress(pEvent) );
- m_nPrevKeyPresses++;
-
- // Also pop off the earliest key press event if there are more than 10
- // already.
- while (m_nPrevKeyPresses > 10)
- {
- m_aPrevKeyPresses.pop_front();
- m_nPrevKeyPresses--;
- }
-
- GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
-
- // #i51353# update spot location on every key input since we cannot
- // know which key may activate a preedit choice window
- updateIMSpotLocation();
- if( aDel.isDeleted() )
- return true;
-
- gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
- g_object_unref( pRef );
-
- if( aDel.isDeleted() )
- return true;
-
- m_bPreeditJustChanged = false;
-
- if( bResult )
- return true;
- else
- {
- DBG_ASSERT( m_nPrevKeyPresses > 0, "key press has vanished !" );
- if( ! m_aPrevKeyPresses.empty() ) // sanity check
- {
- // event was not swallowed, do not filter a following
- // key release event
- // note: this relies on gtk_im_context_filter_keypress
- // returning without calling a handler (in the "not swallowed"
- // case ) which might change the previous key press list so
- // we would pop the wrong event here
- m_aPrevKeyPresses.pop_back();
- m_nPrevKeyPresses--;
- }
- }
- }
-
- // Determine if we got an earlier key press event corresponding to this key release
- if (pEvent->type == GDK_KEY_RELEASE)
- {
- GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
- gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
- g_object_unref( pRef );
-
- if( aDel.isDeleted() )
- return true;
-
- m_bPreeditJustChanged = false;
-
- std::list<PreviousKeyPress>::iterator iter = m_aPrevKeyPresses.begin();
- std::list<PreviousKeyPress>::iterator iter_end = m_aPrevKeyPresses.end();
- while (iter != iter_end)
- {
- // If we found a corresponding previous key press event, swallow the release
- // and remove the earlier key press from our list
- if (*iter == pEvent)
- {
- m_aPrevKeyPresses.erase(iter);
- m_nPrevKeyPresses--;
- return true;
- }
- ++iter;
- }
-
- if( bResult )
- return true;
- }
-
- return false;
-}
-
-/* FIXME:
-* #122282# still more hacking: some IMEs never start a preedit but simply commit
-* in this case we cannot commit a single character. Workaround: do not do the
-* single key hack for enter or space if the unicode committed does not match
-*/
-
-static bool checkSingleKeyCommitHack( guint keyval, sal_Unicode cCode )
-{
- bool bRet = true;
- switch( keyval )
- {
- case GDK_KP_Enter:
- case GDK_Return:
- if( cCode != '\n' && cCode != '\r' )
- bRet = false;
- break;
- case GDK_space:
- case GDK_KP_Space:
- if( cCode != ' ' )
- bRet = false;
- break;
- default:
- break;
- }
- return bRet;
-}
-
-void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* pContext, gchar* pText, gpointer im_handler )
-{
- GtkSalFrame::IMHandler* pThis = static_cast<GtkSalFrame::IMHandler*>(im_handler);
-
- SolarMutexGuard aGuard;
- vcl::DeletionListener aDel( pThis->m_pFrame );
- {
- const bool bWasPreedit =
- (pThis->m_aInputEvent.mpTextAttr != 0) ||
- pThis->m_bPreeditJustChanged;
-
- pThis->m_aInputEvent.mnTime = 0;
- pThis->m_aInputEvent.mpTextAttr = 0;
- pThis->m_aInputEvent.maText = OUString( pText, strlen(pText), RTL_TEXTENCODING_UTF8 );
- pThis->m_aInputEvent.mnCursorPos = pThis->m_aInputEvent.maText.getLength();
- pThis->m_aInputEvent.mnCursorFlags = 0;
- pThis->m_aInputEvent.mbOnlyCursor = False;
-
- pThis->m_aInputFlags.clear();
-
- /* necessary HACK: all keyboard input comes in here as soon as a IMContext is set
- * which is logical and consequent. But since even simple input like
- * <space> comes through the commit signal instead of signalKey
- * and all kinds of windows only implement KeyInput (e.g. PushButtons,
- * RadioButtons and a lot of other Controls), will send a single
- * KeyInput/KeyUp sequence instead of an ExtText event if there
- * never was a preedit and the text is only one character.
- *
- * In this case there the last ExtText event must have been
- * SALEVENT_ENDEXTTEXTINPUT, either because of a regular commit
- * or because there never was a preedit.
- */
- bool bSingleCommit = false;
- if( ! bWasPreedit
- && pThis->m_aInputEvent.maText.getLength() == 1
- && ! pThis->m_aPrevKeyPresses.empty()
- )
- {
- const PreviousKeyPress& rKP = pThis->m_aPrevKeyPresses.back();
- sal_Unicode aOrigCode = pThis->m_aInputEvent.maText[0];
-
- if( checkSingleKeyCommitHack( rKP.keyval, aOrigCode ) )
- {
- pThis->m_pFrame->doKeyCallback( rKP.state, rKP.keyval, rKP.hardware_keycode, rKP.group, rKP.time, aOrigCode, true, true );
- bSingleCommit = true;
- }
- }
- if( ! bSingleCommit )
- {
- pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
- if( ! aDel.isDeleted() )
- pThis->doCallEndExtTextInput();
- }
- if( ! aDel.isDeleted() )
- {
- // reset input event
- pThis->m_aInputEvent.maText.clear();
- pThis->m_aInputEvent.mnCursorPos = 0;
- pThis->updateIMSpotLocation();
- }
- }
-#ifdef SOLARIS
- // #i51356# workaround a solaris IIIMP bug
- // in case of partial commits the preedit changed signal
- // and commit signal come in wrong order
- if( ! aDel.isDeleted() )
- signalIMPreeditChanged( pContext, im_handler );
-#else
- (void) pContext;
-#endif
-}
-
-void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext*, gpointer im_handler )
-{
- GtkSalFrame::IMHandler* pThis = static_cast<GtkSalFrame::IMHandler*>(im_handler);
-
- char* pText = NULL;
- PangoAttrList* pAttrs = NULL;
- gint nCursorPos = 0;
-
- gtk_im_context_get_preedit_string( pThis->m_pIMContext,
- &pText,
- &pAttrs,
- &nCursorPos );
- if( pText && ! *pText ) // empty string
- {
- // change from nothing to nothing -> do not start preedit
- // e.g. this will activate input into a calc cell without
- // user input
- if( pThis->m_aInputEvent.maText.getLength() == 0 )
- {
- g_free( pText );
- pango_attr_list_unref( pAttrs );
- return;
- }
- }
-
- pThis->m_bPreeditJustChanged = true;
-
- bool bEndPreedit = (!pText || !*pText) && pThis->m_aInputEvent.mpTextAttr != NULL;
- pThis->m_aInputEvent.mnTime = 0;
- pThis->m_aInputEvent.maText = pText ? OUString( pText, strlen(pText), RTL_TEXTENCODING_UTF8 ) : OUString();
- pThis->m_aInputEvent.mnCursorPos = nCursorPos;
- pThis->m_aInputEvent.mnCursorFlags = 0;
- pThis->m_aInputEvent.mbOnlyCursor = False;
-
- pThis->m_aInputFlags = std::vector<sal_uInt16>( std::max( 1, (int)pThis->m_aInputEvent.maText.getLength() ), 0 );
-
- PangoAttrIterator *iter = pango_attr_list_get_iterator(pAttrs);
- do
- {
- GSList *attr_list = NULL;
- GSList *tmp_list = NULL;
- gint start, end;
- guint sal_attr = 0;
-
- pango_attr_iterator_range (iter, &start, &end);
- if (end == G_MAXINT)
- end = pText ? strlen (pText) : 0;
- if (end == start)
- continue;
-
- start = g_utf8_pointer_to_offset (pText, pText + start);
- end = g_utf8_pointer_to_offset (pText, pText + end);
-
- tmp_list = attr_list = pango_attr_iterator_get_attrs (iter);
- while (tmp_list)
- {
- PangoAttribute *pango_attr = static_cast<PangoAttribute *>(tmp_list->data);
-
- switch (pango_attr->klass->type)
- {
- case PANGO_ATTR_BACKGROUND:
- sal_attr |= (EXTTEXTINPUT_ATTR_HIGHLIGHT | EXTTEXTINPUT_CURSOR_INVISIBLE);
- break;
- case PANGO_ATTR_UNDERLINE:
- sal_attr |= EXTTEXTINPUT_ATTR_UNDERLINE;
- break;
- case PANGO_ATTR_STRIKETHROUGH:
- sal_attr |= EXTTEXTINPUT_ATTR_REDTEXT;
- break;
- default:
- break;
- }
- pango_attribute_destroy (pango_attr);
- tmp_list = tmp_list->next;
- }
- if (sal_attr == 0)
- sal_attr |= EXTTEXTINPUT_ATTR_UNDERLINE;
- g_slist_free (attr_list);
-
- // Set the sal attributes on our text
- for (int i = start; i < end; ++i)
- {
- SAL_WARN_IF(i >= static_cast<int>(pThis->m_aInputFlags.size()),
- "vcl.gtk", "pango attrib out of range. Broken range: "
- << start << "," << end << " Legal range: 0,"
- << pThis->m_aInputFlags.size());
- if (i >= static_cast<int>(pThis->m_aInputFlags.size()))
- continue;
- pThis->m_aInputFlags[i] |= sal_attr;
- }
- } while (pango_attr_iterator_next (iter));
- pango_attr_iterator_destroy(iter);
-
- pThis->m_aInputEvent.mpTextAttr = &pThis->m_aInputFlags[0];
-
- g_free( pText );
- pango_attr_list_unref( pAttrs );
-
- SolarMutexGuard aGuard;
- vcl::DeletionListener aDel( pThis->m_pFrame );
-
- pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
- if( bEndPreedit && ! aDel.isDeleted() )
- pThis->doCallEndExtTextInput();
- if( ! aDel.isDeleted() )
- pThis->updateIMSpotLocation();
-}
-
-void GtkSalFrame::IMHandler::signalIMPreeditStart( GtkIMContext*, gpointer /*im_handler*/ )
-{
-}
-
-void GtkSalFrame::IMHandler::signalIMPreeditEnd( GtkIMContext*, gpointer im_handler )
-{
- GtkSalFrame::IMHandler* pThis = static_cast<GtkSalFrame::IMHandler*>(im_handler);
-
- pThis->m_bPreeditJustChanged = true;
-
- SolarMutexGuard aGuard;
- vcl::DeletionListener aDel( pThis->m_pFrame );
- pThis->doCallEndExtTextInput();
- if( ! aDel.isDeleted() )
- pThis->updateIMSpotLocation();
-}
-
-uno::Reference<accessibility::XAccessibleEditableText>
- FindFocus(uno::Reference< accessibility::XAccessibleContext > xContext)
-{
- if (!xContext.is())
- uno::Reference< accessibility::XAccessibleEditableText >();
-
- uno::Reference<accessibility::XAccessibleStateSet> xState = xContext->getAccessibleStateSet();
- if (xState.is())
- {
- if (xState->contains(accessibility::AccessibleStateType::FOCUSED))
- return uno::Reference<accessibility::XAccessibleEditableText>(xContext, uno::UNO_QUERY);
- }
-
- for (sal_Int32 i = 0; i < xContext->getAccessibleChildCount(); ++i)
- {
- uno::Reference< accessibility::XAccessible > xChild = xContext->getAccessibleChild(i);
- if (!xChild.is())
- continue;
- uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext();
- if (!xChildContext.is())
- continue;
- uno::Reference< accessibility::XAccessibleEditableText > xText = FindFocus(xChildContext);
- if (xText.is())
- return xText;
- }
- return uno::Reference< accessibility::XAccessibleEditableText >();
-}
-
-static uno::Reference<accessibility::XAccessibleEditableText> lcl_GetxText(vcl::Window *pFocusWin)
-{
- uno::Reference<accessibility::XAccessibleEditableText> xText;
- try
- {
- uno::Reference< accessibility::XAccessible > xAccessible( pFocusWin->GetAccessible( true ) );
- if (xAccessible.is())
- xText = FindFocus(xAccessible->getAccessibleContext());
- }
- catch(const uno::Exception& e)
- {
- SAL_WARN( "vcl.gtk", "Exception in getting input method surrounding text: " << e.Message);
- }
- return xText;
-}
-
-gboolean GtkSalFrame::IMHandler::signalIMRetrieveSurrounding( GtkIMContext* pContext, gpointer /*im_handler*/ )
-{
- vcl::Window *pFocusWin = Application::GetFocusWindow();
- if (!pFocusWin)
- return true;
-
- uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText(pFocusWin);
- if (xText.is())
- {
- sal_Int32 nPosition = xText->getCaretPosition();
- OUString sAllText = xText->getText();
- OString sUTF = OUStringToOString(sAllText, RTL_TEXTENCODING_UTF8);
- OUString sCursorText(sAllText.copy(0, nPosition));
- gtk_im_context_set_surrounding(pContext, sUTF.getStr(), sUTF.getLength(),
- OUStringToOString(sCursorText, RTL_TEXTENCODING_UTF8).getLength());
- return true;
- }
-
- return false;
-}
-
-gboolean GtkSalFrame::IMHandler::signalIMDeleteSurrounding( GtkIMContext*, gint offset, gint nchars,
- gpointer /*im_handler*/ )
-{
- vcl::Window *pFocusWin = Application::GetFocusWindow();
- if (!pFocusWin)
- return true;
-
- uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText(pFocusWin);
- if (xText.is())
- {
- sal_Int32 nPosition = xText->getCaretPosition();
- // #i111768# range checking
- sal_Int32 nDeletePos = nPosition + offset;
- sal_Int32 nDeleteEnd = nDeletePos + nchars;
- if (nDeletePos < 0)
- nDeletePos = 0;
- if (nDeleteEnd < 0)
- nDeleteEnd = 0;
- if (nDeleteEnd > xText->getCharacterCount())
- nDeleteEnd = xText->getCharacterCount();
-
- xText->deleteText(nDeletePos, nDeleteEnd);
- //tdf91641 adjust cursor if deleted chars shift it forward (normal case)
- if (nDeletePos < nPosition)
- {
- if (nDeleteEnd <= nPosition)
- nPosition = nPosition - (nDeleteEnd - nDeletePos);
- else
- nPosition = nDeletePos;
-
- if (xText->getCharacterCount() >= nPosition)
- xText->setCaretPosition( nPosition );
- }
- return true;
- }
-
- return false;
-}
-
-Size GtkSalDisplay::GetScreenSize( int nDisplayScreen )
-{
- Rectangle aRect = m_pSys->GetDisplayScreenPosSizePixel( nDisplayScreen );
- return Size( aRect.GetWidth(), aRect.GetHeight() );
-}
-
-Window GtkSalFrame::GetX11Window()
-{
- return widget_get_xid(m_pWindow);
-}
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk3/app/gtk3gtkinst.cxx b/vcl/unx/gtk3/app/gtk3gtkinst.cxx
deleted file mode 100644
index 5716058..0000000
--- a/vcl/unx/gtk3/app/gtk3gtkinst.cxx
+++ /dev/null
@@ -1,641 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * 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/.
- */
-
-#include "../../gtk/app/gtkinst.cxx"
-
-#include <com/sun/star/lang/XMultiServiceFactory.hpp>
-#include "com/sun/star/lang/XServiceInfo.hpp"
-#include "com/sun/star/lang/XSingleServiceFactory.hpp"
-#include "com/sun/star/lang/XInitialization.hpp"
-#include "com/sun/star/lang/DisposedException.hpp"
-#include "com/sun/star/datatransfer/XTransferable.hpp"
-#include "com/sun/star/datatransfer/clipboard/XClipboard.hpp"
-#include "com/sun/star/datatransfer/clipboard/XClipboardEx.hpp"
-#include "com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp"
-#include "com/sun/star/datatransfer/clipboard/XClipboardListener.hpp"
-#include "com/sun/star/datatransfer/clipboard/XSystemClipboard.hpp"
-#include "com/sun/star/datatransfer/dnd/XDragSource.hpp"
-#include "com/sun/star/datatransfer/dnd/XDropTarget.hpp"
-#include "com/sun/star/datatransfer/dnd/DNDConstants.hpp"
-#include <comphelper/processfactory.hxx>
-#include <comphelper/sequence.hxx>
-#include "cppuhelper/compbase.hxx"
-#include "cppuhelper/implbase1.hxx"
-#include <cppuhelper/supportsservice.hxx>
-
-using namespace com::sun::star;
-using namespace com::sun::star::uno;
-using namespace com::sun::star::lang;
-
-namespace
-{
- struct TypeEntry
- {
- const char* pNativeType; // string corresponding to nAtom for the case of nAtom being uninitialized
- const char* pType; // Mime encoding on our side
- };
-
- static TypeEntry aConversionTab[] =
- {
- { "ISO10646-1", "text/plain;charset=utf-16" },
- { "UTF8_STRING", "text/plain;charset=utf-8" },
- { "UTF-8", "text/plain;charset=utf-8" },
- { "text/plain;charset=UTF-8", "text/plain;charset=utf-8" },
- // ISO encodings
- { "ISO8859-2", "text/plain;charset=iso8859-2" },
- { "ISO8859-3", "text/plain;charset=iso8859-3" },
- { "ISO8859-4", "text/plain;charset=iso8859-4" },
- { "ISO8859-5", "text/plain;charset=iso8859-5" },
- { "ISO8859-6", "text/plain;charset=iso8859-6" },
- { "ISO8859-7", "text/plain;charset=iso8859-7" },
- { "ISO8859-8", "text/plain;charset=iso8859-8" },
- { "ISO8859-9", "text/plain;charset=iso8859-9" },
- { "ISO8859-10", "text/plain;charset=iso8859-10" },
- { "ISO8859-13", "text/plain;charset=iso8859-13" },
- { "ISO8859-14", "text/plain;charset=iso8859-14" },
- { "ISO8859-15", "text/plain;charset=iso8859-15" },
- // asian encodings
- { "JISX0201.1976-0", "text/plain;charset=jisx0201.1976-0" },
- { "JISX0208.1983-0", "text/plain;charset=jisx0208.1983-0" },
- { "JISX0208.1990-0", "text/plain;charset=jisx0208.1990-0" },
- { "JISX0212.1990-0", "text/plain;charset=jisx0212.1990-0" },
- { "GB2312.1980-0", "text/plain;charset=gb2312.1980-0" },
- { "KSC5601.1992-0", "text/plain;charset=ksc5601.1992-0" },
- // eastern european encodings
- { "KOI8-R", "text/plain;charset=koi8-r" },
- { "KOI8-U", "text/plain;charset=koi8-u" },
- // String (== iso8859-1)
- { "STRING", "text/plain;charset=iso8859-1" },
- // special for compound text
- { "COMPOUND_TEXT", "text/plain;charset=compound_text" },
-
- // PIXMAP
- { "PIXMAP", "image/bmp" }
- };
-
- class DataFlavorEq : public std::unary_function<const css::datatransfer::DataFlavor&, bool>
- {
- private:
- const css::datatransfer::DataFlavor& m_rData;
- public:
- explicit DataFlavorEq(const css::datatransfer::DataFlavor& rData) : m_rData(rData) {}
- bool operator() (const css::datatransfer::DataFlavor& rData) const
- {
- return rData.MimeType == m_rData.MimeType &&
- rData.DataType == m_rData.DataType;
- }
- };
-}
-
-class GtkTransferable : public ::cppu::WeakImplHelper1 <
- css::datatransfer::XTransferable >
-{
-private:
- GdkAtom m_nSelection;
- std::map<OUString, GdkAtom> m_aMimeTypeToAtom;
-public:
-
- GtkTransferable(GdkAtom nSelection)
- : m_nSelection(nSelection)
- {
- }
-
- /*
- * XTransferable
- */
-
- virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor)
- throw(css::datatransfer::UnsupportedFlavorException,
- css::io::IOException,
- css::uno::RuntimeException, std::exception
- ) SAL_OVERRIDE
- {
- GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
- if (rFlavor.MimeType == "text/plain;charset=utf-16")
- {
- OUString aStr;
- gchar *pText = gtk_clipboard_wait_for_text(clipboard);
- if (pText)
- aStr = OUString(pText, rtl_str_getLength(pText), RTL_TEXTENCODING_UTF8);
- g_free(pText);
- css::uno::Any aRet;
- aRet <<= aStr.replaceAll("\r\n", "\n");
- return aRet;
- }
-
- auto it = m_aMimeTypeToAtom.find(rFlavor.MimeType);
- if (it == m_aMimeTypeToAtom.end())
- return css::uno::Any();
-
- css::uno::Any aRet;
- GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard,
- it->second);
- gint length;
- const guchar *rawdata = gtk_selection_data_get_data_with_length(data,
- &length);
- Sequence<sal_Int8> aSeq(reinterpret_cast<const sal_Int8*>(rawdata), length);
- gtk_selection_data_free(data);
- aRet <<= aSeq;
- return aRet;
- }
-
- std::vector<css::datatransfer::DataFlavor> getTransferDataFlavorsAsVector()
- {
- std::vector<css::datatransfer::DataFlavor> aVector;
-
- GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
-
- GdkAtom *targets;
- gint n_targets;
- if (gtk_clipboard_wait_for_targets(clipboard, &targets, &n_targets))
- {
- bool bHaveText = false, bHaveUTF16 = false;
-
- for (gint i = 0; i < n_targets; ++i)
- {
- gchar* pName = gdk_atom_name(targets[i]);
- const char* pFinalName = pName;
- css::datatransfer::DataFlavor aFlavor;
-
- for (size_t j = 0; j < SAL_N_ELEMENTS(aConversionTab); ++j)
- {
- if (rtl_str_compare(pName, aConversionTab[j].pNativeType) == 0)
- {
- pFinalName = aConversionTab[j].pType;
- break;
- }
- }
-
- aFlavor.MimeType = OUString(pFinalName,
- rtl_str_getLength(pFinalName),
- RTL_TEXTENCODING_UTF8);
-
- m_aMimeTypeToAtom[aFlavor.MimeType] = targets[i];
-
- aFlavor.DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
-
- sal_Int32 nIndex(0);
- if (aFlavor.MimeType.getToken(0, ';', nIndex) == "text/plain")
- {
- bHaveText = true;
- OUString aToken(aFlavor.MimeType.getToken(0, ';', nIndex));
- if (aToken == "charset=utf-16")
- {
- bHaveUTF16 = true;
- aFlavor.DataType = cppu::UnoType<OUString>::get();
- }
- }
- aVector.push_back(aFlavor);
- g_free(pName);
- }
-
- g_free(targets);
-
- //If we have text, but no UTF-16 format which is basically the only
- //text-format LibreOffice supports for cnp then claim we do and we
- //will convert on demand
- if (bHaveText && !bHaveUTF16)
- {
- css::datatransfer::DataFlavor aFlavor;
- aFlavor.MimeType = "text/plain;charset=utf-16";
- aFlavor.DataType = cppu::UnoType<OUString>::get();
- aVector.push_back(aFlavor);
- }
- }
-
- return aVector;
- }
-
- virtual css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors()
- throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE
- {
- return comphelper::containerToSequence(getTransferDataFlavorsAsVector());
- }
-
- virtual sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor)
- throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE
- {
- const std::vector<css::datatransfer::DataFlavor> aAll =
- getTransferDataFlavorsAsVector();
-
- return std::find_if(aAll.begin(), aAll.end(), DataFlavorEq(rFlavor)) != aAll.end();
- }
-};
-
-//We want to use gtk_clipboard_get_owner own owner-change to distinguish between
-//us gaining the clipboard ownership vs losing it. To do that we need to use
-//gtk_clipboard_set_with_owner and to do that we need a GObject, so define
-//one here for that purpose and just give it a VclGtkClipboard* member
-class VclGtkClipboard;
-
-typedef struct _ClipboardOwner ClipboardOwner;
-typedef struct _ClipboardOwnerClass ClipboardOwnerClass;
-
-struct _ClipboardOwner
-{
- GObject parent_instance;
-
- /* instance members */
- VclGtkClipboard* m_pThis;
-};
-
-struct _ClipboardOwnerClass
-{
- GObjectClass parent_class;
-
- /* class members */
-};
-
-#define CLIPBOARD_OWNER_OBJECT (clipboard_owner_get_type ())
-#define CLIPBOARD_OWNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLIPBOARD_OWNER_OBJECT, ClipboardOwner))
-
-#ifdef __GNUC__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-function"
-#endif
-G_DEFINE_TYPE(ClipboardOwner, clipboard_owner, G_TYPE_OBJECT);
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
-
-static void clipboard_owner_class_init (ClipboardOwnerClass *)
-{
-}
-
-static void clipboard_owner_init(ClipboardOwner *)
-{
-}
-
-class VclGtkClipboard :
- public cppu::WeakComponentImplHelper<
- datatransfer::clipboard::XSystemClipboard,
- XServiceInfo>
-{
- GdkAtom m_nSelection;
- osl::Mutex m_aMutex;
- ClipboardOwner* m_pOwner;
- gulong m_nOwnerChangedSignalId;
- Reference<css::datatransfer::XTransferable> m_aContents;
- Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner;
- std::list< Reference<css::datatransfer::clipboard::XClipboardListener> > m_aListeners;
- std::vector<GtkTargetEntry> m_aGtkTargets;
- std::vector<css::datatransfer::DataFlavor> m_aInfoToFlavor;
-
-public:
-
- VclGtkClipboard(GdkAtom nSelection);
- virtual ~VclGtkClipboard();
-
- /*
- * XServiceInfo
- */
-
- virtual OUString SAL_CALL getImplementationName() throw( RuntimeException, std::exception ) SAL_OVERRIDE;
- virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw( RuntimeException, std::exception ) SAL_OVERRIDE;
- virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw( RuntimeException, std::exception ) SAL_OVERRIDE;
-
- static OUString getImplementationName_static();
- static Sequence< OUString > getSupportedServiceNames_static();
-
- /*
- * XClipboard
- */
-
- virtual Reference< css::datatransfer::XTransferable > SAL_CALL getContents()
- throw(RuntimeException, std::exception) SAL_OVERRIDE;
-
- virtual void SAL_CALL setContents(
- const Reference< css::datatransfer::XTransferable >& xTrans,
- const Reference< css::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner )
- throw(RuntimeException, std::exception) SAL_OVERRIDE;
-
- virtual OUString SAL_CALL getName()
- throw(RuntimeException, std::exception) SAL_OVERRIDE;
-
- /*
- * XClipboardEx
- */
-
- virtual sal_Int8 SAL_CALL getRenderingCapabilities()
- throw(RuntimeException, std::exception) SAL_OVERRIDE;
-
- /*
- * XClipboardNotifier
- */
- virtual void SAL_CALL addClipboardListener(
- const Reference< css::datatransfer::clipboard::XClipboardListener >& listener )
- throw(RuntimeException, std::exception) SAL_OVERRIDE;
-
- virtual void SAL_CALL removeClipboardListener(
- const Reference< css::datatransfer::clipboard::XClipboardListener >& listener )
- throw(RuntimeException, std::exception) SAL_OVERRIDE;
-
- void ClipboardGet(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info);
- void ClipboardClear(GtkClipboard *clipboard);
- void OwnerChanged(GtkClipboard *clipboard, GdkEvent *event);
-private:
- GtkTargetEntry makeGtkTargetEntry(const css::datatransfer::DataFlavor& rFlavor);
-};
-
-OUString VclGtkClipboard::getImplementationName_static()
-{
- return OUString( "com.sun.star.datatransfer.VclGtkClipboard" );
-}
-
-Sequence< OUString > VclGtkClipboard::getSupportedServiceNames_static()
-{
- Sequence< OUString > aRet(1);
- aRet[0] = "com.sun.star.datatransfer.clipboard.SystemClipboard";
- return aRet;
-}
-
-OUString VclGtkClipboard::getImplementationName() throw( RuntimeException, std::exception )
-{
- return getImplementationName_static();
-}
-
-Sequence< OUString > VclGtkClipboard::getSupportedServiceNames() throw( RuntimeException, std::exception )
-{
- return getSupportedServiceNames_static();
-}
-
-sal_Bool VclGtkClipboard::supportsService( const OUString& ServiceName ) throw( RuntimeException, std::exception )
-{
- return cppu::supportsService(this, ServiceName);
-}
-
-Reference< css::datatransfer::XTransferable > VclGtkClipboard::getContents() throw( RuntimeException, std::exception )
-{
- if (G_OBJECT(m_pOwner) != gtk_clipboard_get_owner(gtk_clipboard_get(m_nSelection)) &&
- !m_aContents.is())
- {
- //tdf#93887 This is the system clipboard/selection. We fetch it when we are not
- //the owner of the clipboard and have not already fetched it.
- m_aContents = new GtkTransferable(m_nSelection);
- }
- return m_aContents;
-}
-
-void VclGtkClipboard::ClipboardGet(GtkClipboard* /*clipboard*/, GtkSelectionData *selection_data,
- guint info)
-{
- if (!m_aContents.is())
- return;
-
- GdkAtom type(gdk_atom_intern(OUStringToOString(m_aInfoToFlavor[info].MimeType,
- RTL_TEXTENCODING_UTF8).getStr(),
- false));
-
- css::datatransfer::DataFlavor aFlavor(m_aInfoToFlavor[info]);
- if (aFlavor.MimeType == "UTF8_STRING" || aFlavor.MimeType == "STRING")
- aFlavor.MimeType = "text/plain;charset=utf-8";
-
- Sequence<sal_Int8> aData;
- Any aValue;
-
- try
- {
- aValue = m_aContents->getTransferData(aFlavor);
- }
- catch(...)
- {
- }
-
- if (aValue.getValueTypeClass() == TypeClass_STRING)
- {
- OUString aString;
- aValue >>= aString;
- aData = Sequence< sal_Int8 >( reinterpret_cast<sal_Int8 const *>(aString.getStr()), aString.getLength() * sizeof( sal_Unicode ) );
- }
- else if (aValue.getValueType() == cppu::UnoType<Sequence< sal_Int8 >>::get())
- {
- aValue >>= aData;
- }
- else if (aFlavor.MimeType == "text/plain;charset=utf-8")
- {
- //didn't have utf-8, try utf-16 and convert
- aFlavor.MimeType = "text/plain;charset=utf-16";
- aFlavor.DataType = cppu::UnoType<OUString>::get();
- try
- {
- aValue = m_aContents->getTransferData(aFlavor);
- }
- catch(...)
- {
- }
- OUString aString;
- aValue >>= aString;
- OString aUTF8String(OUStringToOString(aString, RTL_TEXTENCODING_UTF8));
- gtk_selection_data_set(selection_data, type, 8,
- reinterpret_cast<const guchar *>(aUTF8String.getStr()),
- aUTF8String.getLength());
- return;
- }
-
- gtk_selection_data_set(selection_data, type, 8,
- reinterpret_cast<const guchar *>(aData.getArray()),
- aData.getLength());
-}
-
-void VclGtkClipboard::OwnerChanged(GtkClipboard* clipboard, GdkEvent* /*event*/)
-{
- if (G_OBJECT(m_pOwner) != gtk_clipboard_get_owner(clipboard))
- {
- //null out m_aContents to return control to the system-one which
- //will be retrieved if getContents is called again
- setContents(Reference<css::datatransfer::XTransferable>(),
- Reference<css::datatransfer::clipboard::XClipboardOwner>());
- }
-}
-
-void VclGtkClipboard::ClipboardClear(GtkClipboard * /*clipboard*/)
-{
- for (auto &a : m_aGtkTargets)
- free(a.target);
- m_aGtkTargets.clear();
-}
-
-GtkTargetEntry VclGtkClipboard::makeGtkTargetEntry(const css::datatransfer::DataFlavor& rFlavor)
-{
- GtkTargetEntry aEntry;
- aEntry.target =
- g_strdup(OUStringToOString(rFlavor.MimeType, RTL_TEXTENCODING_UTF8).getStr());
- aEntry.flags = 0;
- auto it = std::find_if(m_aInfoToFlavor.begin(), m_aInfoToFlavor.end(),
- DataFlavorEq(rFlavor));
- if (it != m_aInfoToFlavor.end())
- aEntry.info = std::distance(m_aInfoToFlavor.begin(), it);
- else
- {
- aEntry.info = m_aInfoToFlavor.size();
- m_aInfoToFlavor.push_back(rFlavor);
- }
- return aEntry;
-}
-
-namespace
-{
- void ClipboardGetFunc(GtkClipboard *clipboard, GtkSelectionData *selection_data,
- guint info,
- gpointer user_data_or_owner)
- {
- VclGtkClipboard* pThis = CLIPBOARD_OWNER(user_data_or_owner)->m_pThis;
- pThis->ClipboardGet(clipboard, selection_data, info);
- }
-
- void ClipboardClearFunc(GtkClipboard *clipboard, gpointer user_data_or_owner)
- {
- VclGtkClipboard* pThis = CLIPBOARD_OWNER(user_data_or_owner)->m_pThis;
- pThis->ClipboardClear(clipboard);
- }
-
- void handle_owner_change(GtkClipboard *clipboard, GdkEvent *event, gpointer user_data)
- {
- VclGtkClipboard* pThis = static_cast<VclGtkClipboard*>(user_data);
- pThis->OwnerChanged(clipboard, event);
- }
-}
-
-VclGtkClipboard::VclGtkClipboard(GdkAtom nSelection)
- : cppu::WeakComponentImplHelper<datatransfer::clipboard::XSystemClipboard, XServiceInfo>
- (m_aMutex)
- , m_nSelection(nSelection)
-{
- GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
- m_nOwnerChangedSignalId = g_signal_connect(clipboard, "owner-change",
- G_CALLBACK(handle_owner_change), this);
- m_pOwner = CLIPBOARD_OWNER(g_object_new(CLIPBOARD_OWNER_OBJECT, NULL));
- m_pOwner->m_pThis = this;
-}
-
-VclGtkClipboard::~VclGtkClipboard()
-{
- GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
- g_signal_handler_disconnect(clipboard, m_nOwnerChangedSignalId);
- g_object_unref(m_pOwner);
-}
-
-void VclGtkClipboard::setContents(
- const Reference< css::datatransfer::XTransferable >& xTrans,
- const Reference< css::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner )
- throw( RuntimeException, std::exception )
-{
- osl::ClearableMutexGuard aGuard( m_aMutex );
- Reference< datatransfer::clipboard::XClipboardOwner > xOldOwner( m_aOwner );
- Reference< datatransfer::XTransferable > xOldContents( m_aContents );
- m_aContents = xTrans;
- m_aOwner = xClipboardOwner;
-
- std::list< Reference< datatransfer::clipboard::XClipboardListener > > xListeners( m_aListeners );
- datatransfer::clipboard::ClipboardEvent aEv;
-
- if (m_aContents.is())
- {
- css::uno::Sequence<css::datatransfer::DataFlavor> aFormats = xTrans->getTransferDataFlavors();
- std::vector<GtkTargetEntry> aGtkTargets;
- bool bHaveText(false), bHaveUTF8(false);
- for (int i = 0; i < aFormats.getLength(); ++i)
- {
- const css::datatransfer::DataFlavor& rFlavor = aFormats[i];
-
- sal_Int32 nIndex(0);
- if (rFlavor.MimeType.getToken(0, ';', nIndex) == "text/plain")
- {
- bHaveText = true;
- OUString aToken(rFlavor.MimeType.getToken(0, ';', nIndex));
- if (aToken == "charset=utf-8")
- {
- bHaveUTF8 = true;
- }
- }
- GtkTargetEntry aEntry(makeGtkTargetEntry(rFlavor));
- aGtkTargets.push_back(aEntry);
- }
-
- if (bHaveText)
- {
- css::datatransfer::DataFlavor aFlavor;
- aFlavor.DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
- if (!bHaveUTF8)
- {
- aFlavor.MimeType = "text/plain;charset=utf-8";
- aGtkTargets.push_back(makeGtkTargetEntry(aFlavor));
- }
- aFlavor.MimeType = "UTF8_STRING";
- aGtkTargets.push_back(makeGtkTargetEntry(aFlavor));
- aFlavor.MimeType = "STRING";
- aGtkTargets.push_back(makeGtkTargetEntry(aFlavor));
- }
-
- //if there was a previous gtk_clipboard_set_with_data call then
- //ClipboardClearFunc will be called now
- GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
- //use with_owner with m_pOwner so we can distinguish in handle_owner_change
- //if we have gained or lost ownership of the clipboard
- gtk_clipboard_set_with_owner(clipboard, aGtkTargets.data(), aGtkTargets.size(),
- ClipboardGetFunc, ClipboardClearFunc, G_OBJECT(m_pOwner));
- m_aGtkTargets = aGtkTargets;
- }
-
- aEv.Contents = getContents();
-
- aGuard.clear();
-
- if( xOldOwner.is() && xOldOwner != xClipboardOwner )
- xOldOwner->lostOwnership( this, xOldContents );
- for( std::list< Reference< datatransfer::clipboard::XClipboardListener > >::iterator it =
- xListeners.begin(); it != xListeners.end() ; ++it )
- {
- (*it)->changedContents( aEv );
- }
-}
-
-OUString VclGtkClipboard::getName() throw( RuntimeException, std::exception )
-{
- return OUString( "CLIPBOARD" );
-}
-
-sal_Int8 VclGtkClipboard::getRenderingCapabilities() throw( RuntimeException, std::exception )
-{
- return 0;
-}
-
-void VclGtkClipboard::addClipboardListener( const Reference< datatransfer::clipboard::XClipboardListener >& listener )
- throw( RuntimeException, std::exception )
-{
- osl::ClearableMutexGuard aGuard( m_aMutex );
-
- m_aListeners.push_back( listener );
-}
-
-void VclGtkClipboard::removeClipboardListener( const Reference< datatransfer::clipboard::XClipboardListener >& listener )
- throw( RuntimeException, std::exception )
-{
- osl::ClearableMutexGuard aGuard( m_aMutex );
-
- m_aListeners.remove( listener );
-}
-
-Reference< XInterface > GtkInstance::CreateClipboard(const Sequence< Any >& arguments)
-{
- OUString sel;
- if (arguments.getLength() == 0) {
- sel = "CLIPBOARD";
- } else if (arguments.getLength() != 1 || !(arguments[0] >>= sel)) {
- throw css::lang::IllegalArgumentException(
- "bad GtkInstance::CreateClipboard arguments",
- css::uno::Reference<css::uno::XInterface>(), -1);
- }
-
- GdkAtom nSelection = (sel == "CLIPBOARD") ? GDK_SELECTION_CLIPBOARD : GDK_SELECTION_PRIMARY;
-
- return Reference< XInterface >( static_cast<cppu::OWeakObject *>(new VclGtkClipboard(nSelection)) );
-}
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
new file mode 100644
index 0000000..dcfebbf
--- /dev/null
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
@@ -0,0 +1,3805 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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 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 <vcl/bitmapex.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>
+
+#include <gdk/gdkkeysyms-compat.h>
+
+#ifdef ENABLE_DBUS
+#include <dbus/dbus-glib.h>
+
+#define GSM_DBUS_SERVICE "org.gnome.SessionManager"
+#define GSM_DBUS_PATH "/org/gnome/SessionManager"
+#define GSM_DBUS_INTERFACE "org.gnome.SessionManager"
+#endif
+
+#include <config_folders.h>
+
+#define IS_WIDGET_REALIZED gtk_widget_get_realized
+#define IS_WIDGET_MAPPED gtk_widget_get_mapped
+
+using namespace com::sun::star;
+
+int GtkSalFrame::m_nFloats = 0;
+
+#if defined ENABLE_GMENU_INTEGRATION
+static GDBusConnection* pSessionBus = NULL;
+#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 )
+ {
+ switch( keyval )
+ {
+ // - - - - - Sun keyboard, see vcl/unx/source/app/saldisp.cxx
+ case GDK_L2:
+ 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, NULL, NULL, NULL);
+ 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;
+}
+
+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 SAL_OVERRIDE
+ {
+ m_rFrame.damaged(rDamageRect);
+ }
+
+ GtkSalFrame& m_rFrame;
+};
+}
+
+static bool dumpframes = false;
+
+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 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 (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
+
+ /*
+ * #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 AlternatKeyCode 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;
+ bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
+ }
+ }
+ if( bSendRelease && ! aDel.isDeleted() )
+ {
+ CallCallback( SALEVENT_KEYUP, &aEvent );
+ }
+ }
+ else
+ CallCallback( SALEVENT_KEYUP, &aEvent );
+}
+
+GtkSalFrame::GraphicsHolder::~GraphicsHolder()
+{
+ delete pGraphics;
+}
+
+GtkSalFrame::GtkSalFrame( SalFrame* pParent, sal_uLong nStyle )
+ : m_nXScreen( getDisplay()->GetDefaultXScreen() )
+{
+ getDisplay()->registerFrame( this );
+ m_bDefaultPos = true;
+ m_bDefaultSize = ( (nStyle & SAL_FRAME_STYLE_SIZEABLE) && ! pParent );
+ m_bWindowIsGtkPlug = false;
+#if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
+ m_pLastSyncedDbusMenu = NULL;
+#endif
+ Init( pParent, nStyle );
+}
+
+GtkSalFrame::GtkSalFrame( SystemParentData* pSysData )
+ : m_nXScreen( getDisplay()->GetDefaultXScreen() )
+{
+ 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 = NULL;
+#endif
+ Init( pSysData );
+}
+
+#ifdef ENABLE_GMENU_INTEGRATION
+
+static void
+gdk_x11_window_set_utf8_property (GdkWindow *window,
+ const gchar *name,
+ const gchar *value)
+{
+}
+
+// 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 = uno::Reference < css::frame::XFrame >(xDesktop, uno::UNO_QUERY);
+
+ if (!xFrame.is())
+ return;
+
+ uno::Reference< css::frame::XDispatchProvider > xDispatchProvider(xFrame, uno::UNO_QUERY);
+ if (!xDispatchProvider.is())
+ return;
+
+ gchar *strval = NULL;
+ 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, OUString("_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, NULL, NULL, NULL, {0} },
+ { "About", activate_uno, NULL, NULL, NULL, {0} },
+ { "HelpIndex", activate_uno, NULL, NULL, NULL, {0} },
+ { "Quit", activate_uno, NULL, NULL, NULL, {0} },
+ { "New", activate_uno, NULL, NULL, NULL, {0} }
+};
+
+gboolean ensure_dbus_setup( gpointer data )
+{
+ GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( data );
+ GdkWindow* gdkWindow = widget_get_window( pSalFrame->getWindow() );
+
+ if ( gdkWindow != NULL && g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" ) == NULL )
+ {
+ // Get a DBus session connection.
+ if(!pSessionBus)
+ pSessionBus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+ 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, NULL);
+ SAL_INFO("vcl.unity", "exporting action group at " << pActionGroup << " for window " << windowId);
+ pSalFrame->m_nActionGroupExportId = g_dbus_connection_export_action_group( pSessionBus, aDBusWindowPath, pActionGroup, NULL);
+ pSalFrame->m_nHudAwarenessId = hud_awareness_register( pSessionBus, aDBusMenubarPath, hud_activated, pSalFrame, NULL, NULL );
+
+ // 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, NULL, 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, NULL, 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, NULL, 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), NULL);
+#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, NULL);
+ g_object_unref(pAppActionGroup);
+ pSalFrame->m_nAppMenuExportId = g_dbus_connection_export_menu_model (pSessionBus, "/org/libreoffice/menus/appmenu", G_MENU_MODEL (menu), NULL);
+ 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 != NULL )
+ {
+ 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 == NULL )
+ {
+ pSessionBus = g_bus_get_sync( G_BUS_TYPE_SESSION, NULL, NULL );
+
+ if ( pSessionBus == NULL )
+ 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),
+ NULL );
+ }
+
+ //ensure_dbus_setup( this );
+#else
+ (void) this; // loplugin:staticmethods
+#endif
+}
+
+void GtkSalFrame::InvalidateGraphics()
+{
+ for (unsigned int i = 0; i < SAL_N_ELEMENTS(m_aGraphics); ++i)
+ {
+ if( !m_aGraphics[i].pGraphics )
+ continue;
+ m_aGraphics[i].bInUse = false;
+ }
+}
+
+GtkSalFrame::~GtkSalFrame()
+{
+ InvalidateGraphics();
+
+ if( m_pParent )
+ m_pParent->m_aChildren.remove( this );
+
+ getDisplay()->deregisterFrame( this );
+
+ if( m_pRegion )
+ {
+ cairo_region_destroy( m_pRegion );
+ }
+
+ 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", NULL );
+
+#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) );
+}
+
+void GtkSalFrame::moveWindow( long nX, long nY )
+{
+ if( isChild( false, true ) )
+ {
+ 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)
+{
+ gtk_widget_set_size_request(GTK_WIDGET(m_pFixedContainer), nWidth, nHeight );
+}
+
+void GtkSalFrame::window_resize(long nWidth, long nHeight)
+{
+ gtk_window_resize(GTK_WINDOW(m_pWindow), nWidth, nHeight);
+}
+
+void GtkSalFrame::resizeWindow( long nWidth, long nHeight )
+{
+ if( isChild( false, true ) )
+ {
+ widget_set_size_request(nWidth, nHeight);
+ }
+ else if( ! isChild( true, false ) )
+ window_resize(nWidth, nHeight);
+}
+
+static void
+ooo_fixed_class_init(GtkFixedClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+ widget_class->get_accessible = ooo_fixed_get_accessible;
+}
+
+/*
+ * 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 */
+ reinterpret_cast<GClassInitFunc>(ooo_fixed_class_init), /* class init */
+ nullptr, /* class finalize */
+ NULL, /* class data */
+ sizeof (GtkFixed), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) NULL, /* instance init */
+ NULL /* 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
+{
+ return GTK_WIDGET(m_pEventBox);
+}
+
+void GtkSalFrame::InitCommon()
+{
+ 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(), NULL ));
+ gtk_container_add( GTK_CONTAINER(m_pEventBox), GTK_WIDGET(m_pFixedContainer) );
+
+ 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 ));
+ 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 );
+ 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);
+
+ 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 = NULL;
+ m_nKeyModifiers = 0;
+ m_bFullscreen = false;
+ m_bSpanMonitorsWhenFullscreen = false;
+ m_nState = GDK_WINDOW_STATE_WITHDRAWN;
+ m_nVisibility = GDK_VISIBILITY_FULLY_OBSCURED;
+ m_nLastScrollEventTime = GDK_CURRENT_TIME;
+ m_bSendModChangeOnRelease = false;
+ m_pIMHandler = NULL;
+ m_hBackgroundPixmap = None;
+ m_nSavedScreenSaverTimeout = 0;
+ m_nGSMCookie = 0;
+ m_nExtStyle = 0;
+ m_pRegion = NULL;
+ m_ePointerStyle = static_cast<PointerStyle>(0xffff);
+ m_bSetFocusOnMap = false;
+ m_pSalMenu = NULL;
+ 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
+ gtk_widget_show_all( GTK_WIDGET(m_pEventBox) );
+
+ // realize the window, we need an XWindow id
+ gtk_widget_realize( m_pWindow );
+
+ //system data
+ m_aSystemData.nSize = sizeof( SystemEnvData );
+ static int nWindow = 0;
+ m_aSystemData.aWindow = nWindow;
+ m_aSystemData.aShellWindow = nWindow;
+ ++nWindow;
+ m_aSystemData.pSalFrame = this;
+ m_aSystemData.pWidget = m_pWindow;
+ m_aSystemData.nScreen = m_nXScreen.getXScreen();
+ m_aSystemData.pAppContext = NULL;
+ m_aSystemData.pShellWidget = m_aSystemData.pWidget;
+
+ // 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;
+ }
+ }
+ updateScreenNumber();
+
+ SetIcon(1);
+
+}
+
+GtkSalFrame *GtkSalFrame::getFromWindow( GtkWindow *pWindow )
+{
+ return static_cast<GtkSalFrame *>(g_object_get_data( G_OBJECT( pWindow ), "SalFrame" ));
+}
+
+void GtkSalFrame::Init( SalFrame* pParent, sal_uLong nStyle )
+{
+ if( nStyle & SAL_FRAME_STYLE_DEFAULT ) // ensure default style
+ {
+ nStyle |= SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE;
+ nStyle &= ~SAL_FRAME_STYLE_FLOAT;
+ }
+
+ m_pParent = static_cast<GtkSalFrame*>(pParent);
+ m_pForeignParent = NULL;
+ m_aForeignParentWindow = None;
+ m_pForeignTopLevel = NULL;
+ m_aForeignTopLevelWindow = None;
+ m_nStyle = nStyle;
+
+ GtkWindowType eWinType = ( (nStyle & SAL_FRAME_STYLE_FLOAT) &&
+ ! (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|
+ SAL_FRAME_STYLE_FLOAT_FOCUSABLE))
+ )
+ ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL;
+
+ if( nStyle & SAL_FRAME_STYLE_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", (gpointer)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 & SAL_FRAME_STYLE_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 & SAL_FRAME_STYLE_FLOAT) ||
+ (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE) ) );
+
+ if( bDecoHandling )
+ {
+ GdkWindowTypeHint eType = GDK_WINDOW_TYPE_HINT_NORMAL;
+ if( (nStyle & SAL_FRAME_STYLE_DIALOG) && m_pParent != 0 )
+ eType = GDK_WINDOW_TYPE_HINT_DIALOG;
+ if( (nStyle & SAL_FRAME_STYLE_INTRO) )
+ {
+ gtk_window_set_role( GTK_WINDOW(m_pWindow), "splashscreen" );
+ eType = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN;
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_TOOLWINDOW ) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_UTILITY;
+ gtk_window_set_skip_taskbar_hint( GTK_WINDOW(m_pWindow), true );
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
+ gtk_window_set_accept_focus(GTK_WINDOW(m_pWindow), false);
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_UTILITY;
+ }
+ gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), eType );
+ gtk_window_set_gravity( GTK_WINDOW(m_pWindow), GDK_GRAVITY_STATIC );
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_FLOAT) )
+ {
+ gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), GDK_WINDOW_TYPE_HINT_POPUP_MENU );
+ }
+
+ if( bDecoHandling )
+ {
+ gtk_window_set_resizable( GTK_WINDOW(m_pWindow), (nStyle & SAL_FRAME_STYLE_SIZEABLE) != 0 );
+ if( ( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION)) ) )
+ gtk_window_set_accept_focus(GTK_WINDOW(m_pWindow), false);
+ }
+}
+
+GdkNativeWindow GtkSalFrame::findTopLevelSystemWindow( GdkNativeWindow aWindow )
+{
+ (void)aWindow;
+ //FIXME: no findToplevelSystemWindow
+ return 0;
+}
+
+void GtkSalFrame::Init( SystemParentData* pSysData )
+{
+ m_pParent = NULL;
+ m_aForeignParentWindow = (GdkNativeWindow)pSysData->aWindow;
+ m_pForeignParent = NULL;
+ 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 )
+ {
+ m_pWindow = gtk_plug_new_for_display( getGdkDisplay(), pSysData->aWindow );
+ 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 = SAL_FRAME_STYLE_PLUG;
+ InitCommon();
+
+ m_pForeignParent = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignParentWindow );
+ gdk_window_set_events( m_pForeignParent, GDK_STRUCTURE_MASK );
+
+ //FIXME: Handling embedded windows, is going to be fun ...
+}
+
+void GtkSalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
+{
+ (void) this; // loplugin:staticmethods
+ (void)i_nTimeCode;
+ //FIXME: no askForXEmbedFocus for gtk3 yet
+}
+
+void GtkSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
+{
+ if( nStyle != m_nExtStyle && ! isChild() )
+ {
+ m_nExtStyle = nStyle;
+ updateWMClass();
+ }
+}
+
+SalGraphics* GtkSalFrame::AcquireGraphics()
+{
+ if( m_pWindow )
+ {
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( ! m_aGraphics[i].bInUse )
+ {
+ m_aGraphics[i].bInUse = true;
+ if( ! m_aGraphics[i].pGraphics )
+ {
+ m_aGraphics[i].pGraphics = new GtkSalGraphics( this, m_pWindow );
+ if( !m_aFrame.get() )
+ {
+ AllocateFrame();
+ TriggerPaintEvent();
+ }
+ m_aGraphics[i].pGraphics->setDevice( m_aFrame );
+ }
+ return m_aGraphics[i].pGraphics;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void GtkSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
+{
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( m_aGraphics[i].pGraphics == pGraphics )
+ {
+ m_aGraphics[i].bInUse = false;
+ break;
+ }
+ }
+}
+
+bool GtkSalFrame::PostEvent( void* 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() );
+}
+
+static inline sal_uInt8 *
+getRow( BitmapBuffer *pBuffer, sal_uLong nRow )
+{
+ if( BMP_SCANLINE_ADJUSTMENT( pBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ return pBuffer->mpBits + nRow * pBuffer->mnScanlineSize;
+ else
+ return pBuffer->mpBits + ( pBuffer->mnHeight - nRow - 1 ) * pBuffer->mnScanlineSize;
+}
+
+static GdkPixbuf *
+bitmapToPixbuf( SalBitmap *pSalBitmap, SalBitmap *pSalAlpha )
+{
+ g_return_val_if_fail( pSalBitmap != NULL, NULL );
+ g_return_val_if_fail( pSalAlpha != NULL, NULL );
+
+ BitmapBuffer *pBitmap = pSalBitmap->AcquireBuffer( BITMAP_READ_ACCESS );
+ g_return_val_if_fail( pBitmap != NULL, NULL );
+ g_return_val_if_fail( pBitmap->mnBitCount == 24 || pBitmap->mnBitCount == 32, NULL );
+
+ BitmapBuffer *pAlpha = pSalAlpha->AcquireBuffer( BITMAP_READ_ACCESS );
+ g_return_val_if_fail( pAlpha != NULL, NULL );
+ g_return_val_if_fail( pAlpha->mnBitCount == 8, NULL );
+
+ Size aSize = pSalBitmap->GetSize();
+ g_return_val_if_fail( pSalAlpha->GetSize() == aSize, NULL );
+
+ int nX, nY;
+ guchar *pPixbufData = static_cast<guchar *>(g_malloc (4 * aSize.Width() * aSize.Height() ));
+ guchar *pDestData = pPixbufData;
+
+ for( nY = 0; nY < pBitmap->mnHeight; nY++ )
+ {
+ sal_uInt8 *pData = getRow( pBitmap, nY );
+ sal_uInt8 *pAlphaData = getRow( pAlpha, nY );
+
+ for( nX = 0; nX < pBitmap->mnWidth; nX++ )
+ {
+ BitmapColor aColor;
+ if (pBitmap->mnFormat == BMP_FORMAT_24BIT_TC_BGR)
+ {
+ aColor = BitmapColor(pData[2], pData[1], pData[0]);
+ pData += 3;
+ }
+ else if (pBitmap->mnFormat == BMP_FORMAT_24BIT_TC_RGB)
+ {
+ aColor = BitmapColor(pData[0], pData[1], pData[2]);
+ pData += 3;
+ }
+ else
+ {
+ pBitmap->maColorMask.GetColorFor32Bit(aColor, pData);
+ pData += 4;
+ }
+ *pDestData++ = aColor.GetRed();
+ *pDestData++ = aColor.GetGreen();
+ *pDestData++ = aColor.GetBlue();
+ *pDestData++ = 255 - *pAlphaData++;
+ }
+ }
+
+ pSalBitmap->ReleaseBuffer( pBitmap, BITMAP_READ_ACCESS );
+ pSalAlpha->ReleaseBuffer( pAlpha, BITMAP_READ_ACCESS );
+
+ return gdk_pixbuf_new_from_data( pPixbufData,
+ GDK_COLORSPACE_RGB, true, 8,
+ aSize.Width(), aSize.Height(),
+ aSize.Width() * 4,
+ reinterpret_cast<GdkPixbufDestroyNotify>(g_free),
+ NULL );
+}
+
+void GtkSalFrame::SetIcon( sal_uInt16 nIcon )
+{
+ if( (m_nStyle & (SAL_FRAME_STYLE_PLUG|SAL_FRAME_STYLE_SYSTEMCHILD|SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_INTRO|SAL_FRAME_STYLE_OWNERDRAWDECORATION))
+ || ! m_pWindow )
+ return;
+
+ if( !ImplGetResMgr() )
+ return;
+
+ GdkPixbuf *pBuf;
+ GList *pIcons = NULL;
+
+ sal_uInt16 nOffsets[2] = { SV_ICON_SMALL_START, SV_ICON_LARGE_START };
+ sal_uInt16 nIndex;
+
+ for( nIndex = 0; nIndex < sizeof(nOffsets)/ sizeof(sal_uInt16); nIndex++ )
+ {
+ // #i44723# workaround gcc temporary problem
+ ResId aResId( nOffsets[nIndex] + nIcon, *ImplGetResMgr() );
+ BitmapEx aIcon( aResId );
+
+ // #i81083# convert to 24bit/8bit alpha bitmap
+ Bitmap aBmp = aIcon.GetBitmap();
+ if( aBmp.GetBitCount() != 24 || ! aIcon.IsAlpha() )
+ {
+ if( aBmp.GetBitCount() != 24 )
+ aBmp.Convert( BMP_CONVERSION_24BIT );
+ AlphaMask aMask;
+ if( ! aIcon.IsAlpha() )
+ {
+ switch( aIcon.GetTransparentType() )
+ {
+ case TRANSPARENT_NONE:
+ {
+ sal_uInt8 nTrans = 0;
+ aMask = AlphaMask( aBmp.GetSizePixel(), &nTrans );
+ }
+ break;
+ case TRANSPARENT_COLOR:
+ aMask = AlphaMask( aBmp.CreateMask( aIcon.GetTransparentColor() ) );
+ break;
+ case TRANSPARENT_BITMAP:
+ aMask = AlphaMask( aIcon.GetMask() );
+ break;
+ default:
+ OSL_FAIL( "unhandled transparent type" );
+ break;
+ }
+ }
+ else
+ aMask = aIcon.GetAlpha();
+ aIcon = BitmapEx( aBmp, aMask );
+ }
+
+ ImpBitmap *pIconImpBitmap = aIcon.ImplGetBitmapImpBitmap();
+ ImpBitmap *pIconImpMask = aIcon.ImplGetMaskImpBitmap();
+
+ if( pIconImpBitmap && pIconImpMask )
+ {
+ SalBitmap *pIconBitmap =
+ pIconImpBitmap->ImplGetSalBitmap();
+ SalBitmap *pIconMask =
+ pIconImpMask->ImplGetSalBitmap();
+
+ if( ( pBuf = bitmapToPixbuf( pIconBitmap, pIconMask ) ) )
+ pIcons = g_list_prepend( pIcons, pBuf );
+ }
+ }
+
+ gtk_window_set_icon_list( GTK_WINDOW(m_pWindow), pIcons );
+
+ g_list_foreach( pIcons, reinterpret_cast<GFunc>(g_object_unref), NULL );
+ g_list_free( pIcons );
+}
+
+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()
+{
+ if (m_pParent)
+ gtk_window_set_position(GTK_WINDOW(m_pWindow), GTK_WIN_POS_CENTER_ON_PARENT);
+ else
+ gtk_window_set_position(GTK_WINDOW(m_pWindow), GTK_WIN_POS_CENTER);
+}
+
+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 & SAL_FRAME_STYLE_DEFAULT) && m_pWindow )
+ gtk_window_maximize( GTK_WINDOW(m_pWindow) );
+}
+
+static void initClientId()
+{
+ // No session management support for gtk3+ - this is now legacy.
+}
+
+void GtkSalFrame::Show( bool bVisible, bool bNoActivate )
+{
+ if( m_pWindow )
+ {
+ if( bVisible )
+ {
+ initClientId();
+ getDisplay()->startupNotificationCompleted();
+
+ if( m_bDefaultPos )
+ Center();
+ if( m_bDefaultSize )
+ SetDefaultSize();
+ setMinMaxSize();
+
+ 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( ! bNoActivate && (m_nStyle & SAL_FRAME_STYLE_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(0);
+ }
+ 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();
+ }
+ }
+}
+
+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 & SAL_FRAME_STYLE_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;
+ }
+ }
+ 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),
+ NULL,
+ &aGeo,
+ GdkWindowHints( aHints ) );
+ }
+ }
+}
+
+void GtkSalFrame::SetMaxClientSize( long nWidth, long nHeight )
+{
+ if( ! isChild() )
+ {
+ m_aMaxSize = Size( nWidth, nHeight );
+ setMinMaxSize();
+ }
+}
+void GtkSalFrame::SetMinClientSize( long nWidth, long nHeight )
+{
+ if( ! isChild() )
+ {
+ m_aMinSize = Size( nWidth, nHeight );
+ if( m_pWindow )
+ {
+ widget_set_size_request(nWidth, nHeight );
+ setMinMaxSize();
+ }
+ }
+}
+
+// FIXME: we should really be an SvpSalFrame sub-class, and
+// share their AllocateFrame !
+void GtkSalFrame::AllocateFrame()
+{
+ 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,
+ basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRX);
+ 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
+
+ // update device in existing graphics
+ for( unsigned int i = 0; i < SAL_N_ELEMENTS( m_aGraphics ); ++i )
+ {
+ if( !m_aGraphics[i].pGraphics )
+ continue;
+ m_aGraphics[i].pGraphics->setDevice( m_aFrame );
+ }
+ }
+}
+
+void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
+{
+ if( !m_pWindow || isChild( true, false ) )
+ return;
+
+ if( (nFlags & ( SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT )) &&
+ (nWidth > 0 && nHeight > 0 ) // sometimes stupid things happen
+ )
+ {
+ m_bDefaultSize = false;
+
+ if( isChild( false, true ) )
+ 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;
+ }
+
+ m_bDefaultPos = false;
+
+ moveWindow(nX, nY);
+
+ updateScreenNumber();
+ }
+ else if( m_bDefaultPos )
+ Center();
+
+ m_bDefaultPos = false;
+}
+
+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 )
+{
+ 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;
+}
+
+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;
+
+ updateScreenNumber();
+
+ m_nState = GdkWindowState( m_nState | GDK_WINDOW_STATE_MAXIMIZED );
+ m_aRestorePosSize = Rectangle( Point( pState->mnX, pState->mnY ),
+ Size( pState->mnWidth, pState->mnHeight ) );
+ }
+ 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;
+
+ int nX = maGeometry.nX, nY = maGeometry.nY,
+ nWidth = maGeometry.nWidth, nHeight = maGeometry.nHeight;
+ GdkScreen *pScreen = NULL;
+ 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 );
+
+ nX = aNewMonitor.x + maGeometry.nX - aOldMonitor.x;
+ 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 )
+ {
+ nX = aNewMonitor.x;
+ nY = aNewMonitor.y;
+ nWidth = aNewMonitor.width;
+ nHeight = aNewMonitor.height;
+ m_nStyle |= SAL_FRAME_STYLE_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 )
+ {
+ nX = pSize->Left();
+ nY = pSize->Top();
+ nWidth = pSize->GetWidth();
+ nHeight = pSize->GetHeight();
+ m_nStyle &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
+ bResize = true;
+ }
+
+ if (bResize)
+ {
+ // temporarily re-sizeable
+ if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
+ gtk_window_set_resizable( GTK_WINDOW(m_pWindow), TRUE );
+ window_resize(nWidth, nHeight);
+ }
+
+ gtk_window_move(GTK_WINDOW(m_pWindow), nX, nY);
+
+ {
+ gdk_window_set_fullscreen_mode( widget_get_window(m_pWindow), m_bSpanMonitorsWhenFullscreen
+ ? GDK_FULLSCREEN_ON_ALL_MONITORS : GDK_FULLSCREEN_ON_CURRENT_MONITOR );
+ 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 & SAL_FRAME_STYLE_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( NULL );
+ 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();
+
+ 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;
+
+ display = GDK_DISPLAY_XDISPLAY(getGdkDisplay());
+
+ 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 : NULL );
+ m_aRestorePosSize = Rectangle();
+ }
+}
+
+/* definitions from xautolock.c (pl15) */
+#define XAUTOLOCK_DISABLE 1
+#define XAUTOLOCK_ENABLE 2
+
+void GtkSalFrame::setAutoLock( bool bLock )
+{
+ if( isChild() || !getDisplay()->IsX11Display() )
+ return;
+
+ GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(m_pWindow) );
+ GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
+ GdkWindow *pRootWin = gdk_screen_get_root_window( pScreen );
+
+ Atom nAtom = XInternAtom( GDK_DISPLAY_XDISPLAY( pDisplay ),
+ "XAUTOLOCK_MESSAGE", False );
+
+ int nMessage = bLock ? XAUTOLOCK_ENABLE : XAUTOLOCK_DISABLE;
+
+ XChangeProperty( GDK_DISPLAY_XDISPLAY( pDisplay ),
+ GDK_WINDOW_XID( pRootWin ),
+ nAtom, XA_INTEGER,
+ 8, PropModeReplace,
+ reinterpret_cast<unsigned char*>(&nMessage),
+ sizeof( nMessage ) );
+}
+
+#ifdef ENABLE_DBUS
+/** cookie is returned as an unsigned integer */
+static guint
+dbus_inhibit_gsm (const gchar *appname,
+ const gchar *reason,
+ guint xid)
+{
+ gboolean res;
+ guint cookie;
+ GError *error = NULL;
+ DBusGProxy *proxy = NULL;
+
+ /* get the DBUS session connection */
+ DBusGConnection *session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (error != NULL) {
+ g_debug ("DBUS cannot connect : %s", error->message);
+ g_error_free (error);
+ return -1;
+ }
+
+ /* get the proxy with gnome-session-manager */
+ proxy = dbus_g_proxy_new_for_name (session_connection,
+ GSM_DBUS_SERVICE,
+ GSM_DBUS_PATH,
+ GSM_DBUS_INTERFACE);
+ if (proxy == NULL) {
+ g_debug ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
+ return -1;
+ }
+
+ res = dbus_g_proxy_call (proxy,
+ "Inhibit", &error,
+ G_TYPE_STRING, appname,
+ G_TYPE_UINT, xid,
+ G_TYPE_STRING, reason,
+ G_TYPE_UINT, 8, //Inhibit the session being marked as idle
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &cookie,
+ G_TYPE_INVALID);
+
+ /* check the return value */
+ if (! res) {
+ cookie = -1;
+ g_debug ("Inhibit method failed");
+ }
+
+ /* check the error value */
+ if (error != NULL) {
+ g_debug ("Inhibit problem : %s", error->message);
+ g_error_free (error);
+ cookie = -1;
+ }
+
+ g_object_unref (G_OBJECT (proxy));
+ return cookie;
+}
+
+static void
+dbus_uninhibit_gsm (guint cookie)
+{
+ gboolean res;
+ GError *error = NULL;
+ DBusGProxy *proxy = NULL;
+ DBusGConnection *session_connection = NULL;
+
+ if (cookie == guint(-1)) {
+ g_debug ("Invalid cookie");
+ return;
+ }
+
+ /* get the DBUS session connection */
+ session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (error) {
+ g_debug ("DBUS cannot connect : %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ /* get the proxy with gnome-session-manager */
+ proxy = dbus_g_proxy_new_for_name (session_connection,
+ GSM_DBUS_SERVICE,
+ GSM_DBUS_PATH,
+ GSM_DBUS_INTERFACE);
+ if (proxy == NULL) {
+ g_debug ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
+ return;
+ }
+
+ res = dbus_g_proxy_call (proxy,
+ "Uninhibit",
+ &error,
+ G_TYPE_UINT, cookie,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ /* check the return value */
+ if (! res) {
+ g_debug ("Uninhibit method failed");
+ }
+
+ /* check the error value */
+ if (error != NULL) {
+ g_debug ("Uninhibit problem : %s", error->message);
+ g_error_free (error);
+ cookie = -1;
+ }
+ g_object_unref (G_OBJECT (proxy));
+}
+#endif
+
+void GtkSalFrame::StartPresentation( bool bStart )
+{
+ setAutoLock( !bStart );
+
+ if( !getDisplay()->IsX11Display() )
+ return;
+
+ if( bStart )
+ {
+#ifdef ENABLE_DBUS
+ m_nGSMCookie = dbus_inhibit_gsm(g_get_application_name(), "presentation",
+ widget_get_xid(m_pWindow));
+#endif
+ }
+ else
+ {
+ m_nSavedScreenSaverTimeout = 0;
+#ifdef ENABLE_DBUS
+ dbus_uninhibit_gsm(m_nGSMCookie);
+#endif
+ }
+}
+
+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, true ) )
+ 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
+ {
+ guint32 nUserTime = GDK_CURRENT_TIME;
+ gdk_window_focus( widget_get_window(m_pWindow), nUserTime );
+ }
+ }
+ 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, false );
+ 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);
+
+ 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);
+}
+
+void GtkSalFrame::grabKeyboard( bool bGrab )
+{
+ if (!m_pWindow)
+ return;
+
+ 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), NULL, GDK_CURRENT_TIME);
+ }
+ else
+ {
+ gdk_device_ungrab(pKeyboard, GDK_CURRENT_TIME);
+ }
+}
+
+void GtkSalFrame::CaptureMouse( bool bCapture )
+{
+ getDisplay()->CaptureMouse( bCapture ? this : NULL );
+}
+
+void GtkSalFrame::SetPointerPos( long nX, long nY )
+{
+ GtkSalFrame* pFrame = this;
+ while( pFrame && pFrame->isChild( false, true ) )
+ 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()
+{
+ gdk_display_flush( getGdkDisplay() );
+}
+
+void GtkSalFrame::Sync()
+{
+ gdk_display_sync( getGdkDisplay() );
+}
+
+#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 == NULL || pGdkModifiers == NULL )
+ 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;
+ case KEY_PASTE: nKeyCode = GDK_Paste; break;
+ case KEY_OPEN: nKeyCode = GDK_Open; break;
+ }
+ }
+
+ *pGdkKeyCode = nKeyCode;
+}
+
+OUString GtkSalFrame::GetKeyName( sal_uInt16 nKeyCode )
+{
+ guint nGtkKeyCode;
+ GdkModifierType nGtkModifiers;
+ KeyCodeToGdkKey(nKeyCode, &nGtkKeyCode, &nGtkModifiers );
+
+ gchar* pName = gtk_accelerator_get_label(nGtkKeyCode, nGtkModifiers);
+ OUString aRet(pName, rtl_str_getLength(pName), RTL_TEXTENCODING_UTF8);
+ g_free(pName);
+ return aRet;
+}
+
+GdkDisplay *GtkSalFrame::getGdkDisplay()
+{
+ return GetGtkSalData()->GetGdkDisplay();
+}
+
+GtkSalDisplay *GtkSalFrame::getDisplay()
+{
+ return GetGtkSalData()->GetGtkDisplay();
+}
+
+SalFrame::SalPointerState GtkSalFrame::GetPointerState()
+{
+ SalPointerState aState;
+ GdkScreen* pScreen;
+ gint x, y;
+ GdkModifierType aMask;
+ gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
+ aState.maPos = Point( x - maGeometry.nX, y - maGeometry.nY );
+ aState.mnState = GetMouseModCode( aMask );
+ return aState;
+}
+
+KeyIndicatorState GtkSalFrame::GetIndicatorState()
+{
+ KeyIndicatorState nState = KeyIndicatorState::NONE;
+
+ GdkKeymap *pKeyMap = gdk_keymap_get_for_display(getGdkDisplay());
+
+ if (gdk_keymap_get_caps_lock_state(pKeyMap))
+ nState |= KeyIndicatorState::CAPSLOCK;
+ if (gdk_keymap_get_num_lock_state(pKeyMap))
+ nState |= KeyIndicatorState::NUMLOCK;
+#if GTK_CHECK_VERSION(3,18,0)
+ if (gdk_keymap_get_scroll_lock_state(pKeyMap))
+ nState |= KeyIndicatorState::SCROLLLOCK;
+#endif
+ return nState;
+}
+
+void GtkSalFrame::SimulateKeyPress( sal_uInt16 nKeyCode )
+{
+ g_warning ("missing simulate keypress %d", nKeyCode);
+}
+
+void GtkSalFrame::SetInputContext( SalInputContext* pContext )
+{
+ if( ! pContext )
+ return;
+
+ if( ! (pContext->mnOptions & InputContextFlags::Text) )
+ return;
+
+ // create a new im context
+ if( ! m_pIMHandler )
+ m_pIMHandler = new IMHandler( this );
+}
+
+void GtkSalFrame::EndExtTextInput( sal_uInt16 nFlags )
+{
+ if( m_pIMHandler )
+ m_pIMHandler->endExtTextInput( nFlags );
+}
+
+bool GtkSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& )
+{
+ // not supported yet
+ return false;
+}
+
+LanguageType GtkSalFrame::GetInputLanguage()
+{
+ return LANGUAGE_DONTKNOW;
+}
+
+void GtkSalFrame::UpdateSettings( AllSettings& rSettings )
+{
+ if( ! m_pWindow )
+ return;
+
+ GtkSalGraphics* pGraphics = static_cast<GtkSalGraphics*>(m_aGraphics[0].pGraphics);
+ bool bFreeGraphics = false;
+ if( ! pGraphics )
+ {
+ pGraphics = static_cast<GtkSalGraphics*>(AcquireGraphics());
+ if ( !pGraphics )
+ {
+ SAL_WARN("vcl", "Could not get graphics - unable to update settings");
+ return;
+ }
+ bFreeGraphics = true;
+ }
+
+ pGraphics->updateSettings( rSettings );
+
+ if( bFreeGraphics )
+ ReleaseGraphics( pGraphics );
+}
+
+void GtkSalFrame::Beep()
+{
+ gdk_display_beep( getGdkDisplay() );
+}
+
+const SystemEnvData* GtkSalFrame::GetSystemData() const
+{
+ return &m_aSystemData;
+}
+
+void GtkSalFrame::SetParent( SalFrame* pNewParent )
+{
+ if( m_pParent )
+ m_pParent->m_aChildren.remove( this );
+ m_pParent = static_cast<GtkSalFrame*>(pNewParent);
+ if( m_pParent )
+ m_pParent->m_aChildren.push_back( this );
+ if( ! isChild() )
+ gtk_window_set_transient_for( GTK_WINDOW(m_pWindow),
+ (m_pParent && ! m_pParent->isChild(true,false)) ? GTK_WINDOW(m_pParent->m_pWindow) : NULL
+ );
+}
+
+bool GtkSalFrame::SetPluginParent( SystemParentData* pSysParent )
+{
+ (void)pSysParent;
+ //FIXME: no SetPluginParent impl. for gtk3
+ return false;
+}
+
+void GtkSalFrame::ResetClipRegion()
+{
+ if( m_pWindow )
+ gdk_window_shape_combine_region( widget_get_window( m_pWindow ), NULL, 0, 0 );
+}
+
+void GtkSalFrame::BeginSetClipRegion( sal_uLong )
+{
+ if( m_pRegion )
+ cairo_region_destroy( m_pRegion );
+ m_pRegion = cairo_region_create();
+}
+
+void GtkSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( m_pRegion )
+ {
+ GdkRectangle aRect;
+ aRect.x = nX;
+ aRect.y = nY;
+ aRect.width = nWidth;
+ aRect.height = nHeight;
+ cairo_region_union_rectangle( m_pRegion, &aRect );
+ }
+}
+
+void GtkSalFrame::EndSetClipRegion()
+{
+ if( m_pWindow && m_pRegion )
+ gdk_window_shape_combine_region( widget_get_window(m_pWindow), m_pRegion, 0, 0 );
+}
+
+gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ SalMouseEvent aEvent;
+ sal_uInt16 nEventType = 0;
+ switch( pEvent->type )
+ {
+ case GDK_BUTTON_PRESS:
+ nEventType = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+ case GDK_BUTTON_RELEASE:
+ nEventType = SALEVENT_MOUSEBUTTONUP;
+ break;
+ default:
+ return false;
+ }
+ switch( pEvent->button )
+ {
+ case 1: aEvent.mnButton = MOUSE_LEFT; break;
+ case 2: aEvent.mnButton = MOUSE_MIDDLE; break;
+ case 3: aEvent.mnButton = MOUSE_RIGHT; break;
+ default: return false;
+ }
+ aEvent.mnTime = pEvent->time;
+ aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
+ aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
+ aEvent.mnCode = GetMouseModCode( pEvent->state );
+
+ bool bClosePopups = false;
+ if( pEvent->type == GDK_BUTTON_PRESS &&
+ (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) == 0
+ )
+ {
+ if( m_nFloats > 0 )
+ {
+ // close popups if user clicks outside our application
+ gint x, y;
+ bClosePopups = (gdk_display_get_window_at_pointer( GtkSalFrame::getGdkDisplay(), &x, &y ) == NULL);
+ }
+ /* #i30306# release implicit pointer grab if no popups are open; else
+ * Drag cannot grab the pointer and will fail.
+ */
+ if( m_nFloats < 1 || bClosePopups )
+ gdk_display_pointer_ungrab( GtkSalFrame::getGdkDisplay(), GDK_CURRENT_TIME );
+ }
+
+ if( pThis->m_bWindowIsGtkPlug &&
+ pEvent->type == GDK_BUTTON_PRESS &&
+ pEvent->button == 1 )
+ {
+ pThis->askForXEmbedFocus( pEvent->time );
+ }
+
+ // --- RTL --- (mirror mouse pos)
+ if( AllSettings::GetLayoutRTL() )
+ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+
+ vcl::DeletionListener aDel( pThis );
+
+ pThis->CallCallback( nEventType, &aEvent );
+
+ if( ! aDel.isDeleted() )
+ {
+ if( bClosePopups )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maWinData.mpFirstFloat )
+ {
+ static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
+ if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FloatWinPopupFlags::NoAppFocusClose) && !(pEnv && *pEnv) )
+ pSVData->maWinData.mpFirstFloat->EndPopupMode( FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll );
+ }
+ }
+
+ if( ! aDel.isDeleted() )
+ {
+ int frame_x = (int)(pEvent->x_root - pEvent->x);
+ int frame_y = (int)(pEvent->y_root - pEvent->y);
+ if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
+ {
+ pThis->maGeometry.nX = frame_x;
+ pThis->maGeometry.nY = frame_y;
+ pThis->CallCallback( SALEVENT_MOVE, NULL );
+ }
+ }
+ }
+
+ return true;
+}
+
+gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEvent* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ GdkEventScroll* pSEvent = reinterpret_cast<GdkEventScroll*>(pEvent);
+
+ // gnome#726878 check for duplicate legacy scroll event
+ if (pSEvent->direction != GDK_SCROLL_SMOOTH &&
+ pThis->m_nLastScrollEventTime == pSEvent->time)
+ {
+ return true;
+ }
+
+ SalWheelMouseEvent aEvent;
+
+ aEvent.mnTime = pSEvent->time;
+ aEvent.mnX = (sal_uLong)pSEvent->x;
+ aEvent.mnY = (sal_uLong)pSEvent->y;
+ aEvent.mnCode = GetMouseModCode( pSEvent->state );
+ aEvent.mnScrollLines = 3;
+
+ switch (pSEvent->direction)
+ {
+ case GDK_SCROLL_SMOOTH:
+ {
+ double delta_x, delta_y;
+ gdk_event_get_scroll_deltas(pEvent, &delta_x, &delta_y);
+ //pick the bigger one I guess
+ aEvent.mbHorz = fabs(delta_x) > fabs(delta_y);
+ if (aEvent.mbHorz)
+ aEvent.mnDelta = -delta_x;
+ else
+ aEvent.mnDelta = -delta_y;
+ aEvent.mnScrollLines = 1;
+ pThis->m_nLastScrollEventTime = pSEvent->time;
+ break;
+ }
+ case GDK_SCROLL_UP:
+ aEvent.mnDelta = 120;
+ aEvent.mbHorz = false;
+ break;
+ case GDK_SCROLL_DOWN:
+ aEvent.mnDelta = -120;
+ aEvent.mbHorz = false;
+ break;
+ case GDK_SCROLL_LEFT:
+ aEvent.mbHorz = true;
+ aEvent.mnDelta = 120;
+ break;
+ case GDK_SCROLL_RIGHT:
+ aEvent.mnDelta = -120;
+ aEvent.mbHorz = true;
+ break;
+ };
+
+ aEvent.mnNotchDelta = aEvent.mnDelta < 0 ? -1 : 1;
+
+ // --- RTL --- (mirror mouse pos)
+ if( AllSettings::GetLayoutRTL() )
+ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+
+ pThis->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+
+ return true;
+}
+
+void GtkSalFrame::gestureSwipe(GtkGestureSwipe* gesture, gdouble velocity_x, gdouble velocity_y, gpointer frame)
+{
+ gdouble x, y;
+ GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
+ //I feel I want the first point of the sequence, not the last point which
+ //the docs say this gives, but for the moment assume we start and end
+ //within the same vcl window
+ if (gtk_gesture_get_point(GTK_GESTURE(gesture), sequence, &x, &y))
+ {
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ SalSwipeEvent aEvent;
+ aEvent.mnVelocityX = velocity_x;
+ aEvent.mnVelocityY = velocity_y;
+ aEvent.mnX = x;
+ aEvent.mnY = y;
+
+ pThis->CallCallback(SALEVENT_SWIPE, &aEvent);
+ }
+}
+
+void GtkSalFrame::gestureLongPress(GtkGestureLongPress* gesture, gpointer frame)
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ if(pThis)
+ {
+ SalLongPressEvent aEvent;
+
+ gdouble x, y;
+ GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
+ gtk_gesture_get_point(GTK_GESTURE(gesture), sequence, &x, &y);
+ aEvent.mnX = x;
+ aEvent.mnY = y;
+
+ pThis->CallCallback(SALEVENT_LONGPRESS, &aEvent);
+ }
+}
+
+gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ SalMouseEvent aEvent;
+ aEvent.mnTime = pEvent->time;
+ aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
+ aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
+ aEvent.mnCode = GetMouseModCode( pEvent->state );
+ aEvent.mnButton = 0;
+
+ // --- RTL --- (mirror mouse pos)
+ if( AllSettings::GetLayoutRTL() )
+ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+
+ vcl::DeletionListener aDel( pThis );
+
+ pThis->CallCallback( SALEVENT_MOUSEMOVE, &aEvent );
+
+ if( ! aDel.isDeleted() )
+ {
+ int frame_x = (int)(pEvent->x_root - pEvent->x);
+ int frame_y = (int)(pEvent->y_root - pEvent->y);
+ if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
+ {
+ pThis->maGeometry.nX = frame_x;
+ pThis->maGeometry.nY = frame_y;
+ pThis->CallCallback( SALEVENT_MOVE, NULL );
+ }
+
+ if( ! aDel.isDeleted() )
+ {
+ // ask for the next hint
+ gint x, y;
+ GdkModifierType mask;
+ gdk_window_get_pointer( widget_get_window(GTK_WIDGET(pThis->m_pWindow)), &x, &y, &mask );
+ }
+ }
+
+ return true;
+}
+
+gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ SalMouseEvent aEvent;
+ aEvent.mnTime = pEvent->time;
+ aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
+ aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
+ aEvent.mnCode = GetMouseModCode( pEvent->state );
+ aEvent.mnButton = 0;
+
+ pThis->CallCallback( (pEvent->type == GDK_ENTER_NOTIFY) ? SALEVENT_MOUSEMOVE : SALEVENT_MOUSELEAVE, &aEvent );
+
+ return true;
+}
+
+cairo_t* GtkSalFrame::getCairoContext() const
+{
+ cairo_t* cr = SvpSalGraphics::createCairoContext(m_aFrame);
+ assert(cr);
+ return cr;
+}
+
+void GtkSalFrame::damaged (const basegfx::B2IBox& rDamageRect)
+{
+#if OSL_DEBUG_LEVEL > 1
+ long long area = rDamageRect.getWidth() * rDamageRect.getHeight();
+ if( area > 32 * 1024 )
+ {
+ fprintf( stderr, "bitmap damaged %d %d (%dx%d) area %lld widget\n",
+ (int) rDamageRect.getMinX(),
+ (int) rDamageRect.getMinY(),
+ (int) rDamageRect.getWidth(),
+ (int) rDamageRect.getHeight(),
+ area );
+ }
+#endif
+
+ if (dumpframes)
+ {
+ static int frame;
+ OString tmp("/tmp/frame" + OString::number(frame++) + ".png");
+ cairo_t* cr = getCairoContext();
+ cairo_surface_write_to_png(cairo_get_target(cr), tmp.getStr());
+ cairo_destroy(cr);
+ }
+
+ gtk_widget_queue_draw_area(GTK_WIDGET(m_pFixedContainer),
+ rDamageRect.getMinX(),
+ rDamageRect.getMinY(),
+ rDamageRect.getWidth(),
+ rDamageRect.getHeight());
+}
+
+// blit our backing basebmp buffer to the target cairo context cr
+gboolean GtkSalFrame::signalDraw( GtkWidget*, cairo_t *cr, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ cairo_save(cr);
+
+ cairo_t* source = pThis->getCairoContext();
+ cairo_surface_t *pSurface = cairo_get_target(source);
+
+ cairo_set_operator( cr, CAIRO_OPERATOR_OVER );
+ cairo_set_source_surface(cr, pSurface, 0, 0);
+ cairo_paint(cr);
+
+ cairo_destroy(source);
+
+ cairo_restore(cr);
+
+ cairo_surface_flush(cairo_get_target(cr));
+
+ return false;
+}
+
+void GtkSalFrame::sizeAllocated(GtkWidget*, GdkRectangle *pAllocation, gpointer frame)
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ pThis->maGeometry.nWidth = pAllocation->width;
+ pThis->maGeometry.nHeight = pAllocation->height;
+ pThis->AllocateFrame();
+ pThis->CallCallback( SALEVENT_RESIZE, nullptr );
+ pThis->TriggerPaintEvent();
+}
+
+gboolean GtkSalFrame::signalConfigure(GtkWidget*, GdkEventConfigure* pEvent, gpointer frame)
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ bool bMoved = false;
+ int x = pEvent->x, y = pEvent->y;
+
+ /* #i31785# claims we cannot trust the x,y members of the event;
+ * they are e.g. not set correctly on maximize/demaximize;
+ * yet the gdkdisplay-x11.c code handling configure_events has
+ * done this XTranslateCoordinates work since the day ~zero.
+ */
+ if( x != pThis->maGeometry.nX || y != pThis->maGeometry.nY )
+ {
+ bMoved = true;
+ pThis->maGeometry.nX = x;
+ pThis->maGeometry.nY = y;
+ }
+
+ // update decoration hints
+ GdkRectangle aRect;
+ gdk_window_get_frame_extents( widget_get_window(GTK_WIDGET(pThis->m_pWindow)), &aRect );
+ pThis->maGeometry.nTopDecoration = y - aRect.y;
+ pThis->maGeometry.nBottomDecoration = aRect.y + aRect.height - y - pEvent->height;
+ pThis->maGeometry.nLeftDecoration = x - aRect.x;
+ pThis->maGeometry.nRightDecoration = aRect.x + aRect.width - x - pEvent->width;
+
+ pThis->updateScreenNumber();
+
+ if (bMoved)
+ pThis->CallCallback(SALEVENT_MOVE, nullptr);
+
+ return false;
+}
+
+void GtkSalFrame::TriggerPaintEvent()
+{
+ //Under gtk2 we can basically paint directly into the XWindow and on
+ //additional "expose-event" events we can re-render the missing pieces
+ //
+ //Under gtk3 we have to keep our own buffer up to date and flush it into
+ //the given cairo context on "draw". So we emit a paint event on
+ //opportune resize trigger events to initially fill our backbuffer and then
+ //keep it up to date with our direct paints and tell gtk those regions
+ //have changed and then blit them into the provided cairo context when
+ //we get the "draw"
+ //
+ //The other alternative was to always paint everything on "draw", but
+ //that duplicates the amount of drawing and is hideously slow
+ SAL_INFO("vcl.gtk3", "force painting" << 0 << "," << 0 << " " << maGeometry.nWidth << "x" << maGeometry.nHeight);
+ SalPaintEvent aPaintEvt(0, 0, maGeometry.nWidth, maGeometry.nHeight, true);
+ CallCallback(SALEVENT_PAINT, &aPaintEvt);
+ gtk_widget_queue_draw(GTK_WIDGET(m_pFixedContainer));
+}
+
+gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ SalGenericInstance *pSalInstance =
+ static_cast< SalGenericInstance* >(GetSalData()->m_pInstance);
+
+ // check if printers have changed (analogous to salframe focus handler)
+ pSalInstance->updatePrinterUpdate();
+
+ if( !pEvent->in )
+ {
+ pThis->m_nKeyModifiers = 0;
+ pThis->m_bSendModChangeOnRelease = false;
+ }
+
+ if( pThis->m_pIMHandler )
+ pThis->m_pIMHandler->focusChanged( pEvent->in );
+
+ // ask for changed printers like generic implementation
+ if( pEvent->in && pSalInstance->isPrinterInit() )
+ pSalInstance->updatePrinterUpdate();
+
+ // FIXME: find out who the hell steals the focus from our frame
+ // while we have the pointer grabbed, this should not come from
+ // the window manager. Is this an event that was still queued ?
+ // The focus does not seem to get set inside our process
+
+ // in the meantime do not propagate focus get/lose if floats are open
+ if( m_nFloats == 0 )
+ pThis->CallCallback( pEvent->in ? SALEVENT_GETFOCUS : SALEVENT_LOSEFOCUS, NULL );
+
+ return false;
+}
+
+gboolean GtkSalFrame::signalMap( GtkWidget *pWidget, GdkEvent*, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ bool bSetFocus = pThis->m_bSetFocusOnMap;
+ pThis->m_bSetFocusOnMap = false;
+
+ (void)pWidget; (void)bSetFocus;
+ //FIXME: no set input focus ...
+
+ pThis->CallCallback( SALEVENT_RESIZE, NULL );
+ pThis->TriggerPaintEvent();
+
+ return false;
+}
+
+gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ pThis->CallCallback( SALEVENT_RESIZE, NULL );
+
+ return false;
+}
+
+gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ vcl::DeletionListener aDel( pThis );
+
+ if( pThis->m_pIMHandler )
+ {
+ if( pThis->m_pIMHandler->handleKeyEvent( pEvent ) )
+ return true;
+ }
+
+ // handle modifiers
+ if( pEvent->keyval == GDK_Shift_L || pEvent->keyval == GDK_Shift_R ||
+ pEvent->keyval == GDK_Control_L || pEvent->keyval == GDK_Control_R ||
+ pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ||
+ pEvent->keyval == GDK_Meta_L || pEvent->keyval == GDK_Meta_R ||
+ pEvent->keyval == GDK_Super_L || pEvent->keyval == GDK_Super_R )
+ {
+ SalKeyModEvent aModEvt;
+
+ sal_uInt16 nModCode = GetKeyModCode( pEvent->state );
+
+ aModEvt.mnModKeyCode = 0; // emit no MODKEYCHANGE events
+ if( pEvent->type == GDK_KEY_PRESS && !pThis->m_nKeyModifiers )
+ pThis->m_bSendModChangeOnRelease = true;
+
+ else if( pEvent->type == GDK_KEY_RELEASE &&
+ pThis->m_bSendModChangeOnRelease )
+ {
+ aModEvt.mnModKeyCode = pThis->m_nKeyModifiers;
+ pThis->m_nKeyModifiers = 0;
+ }
+
+ sal_uInt16 nExtModMask = 0;
+ sal_uInt16 nModMask = 0;
+ // pressing just the ctrl key leads to a keysym of XK_Control but
+ // the event state does not contain ControlMask. In the release
+ // event its the other way round: it does contain the Control mask.
+ // The modifier mode therefore has to be adapted manually.
+ switch( pEvent->keyval )
+ {
+ case GDK_Control_L:
+ nExtModMask = MODKEY_LMOD1;
+ nModMask = KEY_MOD1;
+ break;
+ case GDK_Control_R:
+ nExtModMask = MODKEY_RMOD1;
+ nModMask = KEY_MOD1;
+ break;
+ case GDK_Alt_L:
+ nExtModMask = MODKEY_LMOD2;
+ nModMask = KEY_MOD2;
+ break;
+ case GDK_Alt_R:
+ nExtModMask = MODKEY_RMOD2;
+ nModMask = KEY_MOD2;
+ break;
+ case GDK_Shift_L:
+ nExtModMask = MODKEY_LSHIFT;
+ nModMask = KEY_SHIFT;
+ break;
+ case GDK_Shift_R:
+ nExtModMask = MODKEY_RSHIFT;
+ nModMask = KEY_SHIFT;
+ break;
+ // Map Meta/Super to MOD3 modifier on all Unix systems
+ // except Mac OS X
+ case GDK_Meta_L:
+ case GDK_Super_L:
+ nExtModMask = MODKEY_LMOD3;
+ nModMask = KEY_MOD3;
+ break;
+ case GDK_Meta_R:
+ case GDK_Super_R:
+ nExtModMask = MODKEY_RMOD3;
+ nModMask = KEY_MOD3;
+ break;
+ }
+ if( pEvent->type == GDK_KEY_RELEASE )
+ {
+ nModCode &= ~nModMask;
+ pThis->m_nKeyModifiers &= ~nExtModMask;
+ }
+ else
+ {
+ nModCode |= nModMask;
+ pThis->m_nKeyModifiers |= nExtModMask;
+ }
+
+ aModEvt.mnCode = nModCode;
+ aModEvt.mnTime = pEvent->time;
+
+ pThis->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
+
+ }
+ else
+ {
+ pThis->doKeyCallback( pEvent->state,
+ pEvent->keyval,
+ pEvent->hardware_keycode,
+ pEvent->group,
+ pEvent->time,
+ sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )),
+ (pEvent->type == GDK_KEY_PRESS),
+ false );
+ if( ! aDel.isDeleted() )
+ pThis->m_bSendModChangeOnRelease = false;
+ }
+
+ if( !aDel.isDeleted() && pThis->m_pIMHandler )
+ pThis->m_pIMHandler->updateIMSpotLocation();
+
+ return true;
+}
+
+gboolean GtkSalFrame::signalDelete( GtkWidget*, GdkEvent*, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ pThis->CallCallback( SALEVENT_CLOSE, NULL );
+
+ return true;
+}
+
+void GtkSalFrame::signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ // every frame gets an initial style set on creation
+ // do not post these as the whole application tends to
+ // redraw itself to adjust to the new style
+ // where there IS no new style resulting in tremendous unnecessary flickering
+ if( pPrevious != NULL )
+ {
+ // signalStyleSet does NOT usually have the gdk lock
+ // so post user event to safely dispatch the SALEVENT_SETTINGSCHANGED
+ // note: settings changed for multiple frames is avoided in winproc.cxx ImplHandleSettings
+ GtkSalFrame::getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_SETTINGSCHANGED );
+ GtkSalFrame::getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_FONTCHANGED );
+ }
+}
+
+gboolean GtkSalFrame::signalWindowState( GtkWidget*, GdkEvent* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ if( (pThis->m_nState & GDK_WINDOW_STATE_ICONIFIED) != (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED ) )
+ {
+ GtkSalFrame::getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_RESIZE );
+ pThis->TriggerPaintEvent();
+ }
+
+ if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) &&
+ ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) )
+ {
+ pThis->m_aRestorePosSize =
+ Rectangle( Point( pThis->maGeometry.nX, pThis->maGeometry.nY ),
+ Size( pThis->maGeometry.nWidth, pThis->maGeometry.nHeight ) );
+ }
+ pThis->m_nState = pEvent->window_state.new_window_state;
+
+ #if OSL_DEBUG_LEVEL > 1
+ if( (pEvent->window_state.changed_mask & GDK_WINDOW_STATE_FULLSCREEN) )
+ {
+ fprintf( stderr, "window %p %s full screen state\n",
+ pThis,
+ (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_FULLSCREEN) ? "enters" : "leaves");
+ }
+ #endif
+
+ return false;
+}
+
+gboolean GtkSalFrame::signalVisibility( GtkWidget*, GdkEventVisibility* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ pThis->m_nVisibility = pEvent->state;
+ return true;
+}
+
+void GtkSalFrame::signalDestroy( GtkWidget* pObj, gpointer frame )
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ if( pObj == pThis->m_pWindow )
+ {
+ pThis->m_pFixedContainer = NULL;
+ pThis->m_pEventBox = NULL;
+ pThis->m_pWindow = NULL;
+ pThis->InvalidateGraphics();
+ }
+}
+
+// GtkSalFrame::IMHandler
+
+GtkSalFrame::IMHandler::IMHandler( GtkSalFrame* pFrame )
+: m_pFrame(pFrame),
+ m_nPrevKeyPresses( 0 ),
+ m_pIMContext( NULL ),
+ m_bFocused( true ),
+ m_bPreeditJustChanged( false )
+{
+ m_aInputEvent.mpTextAttr = NULL;
+ createIMContext();
+}
+
+GtkSalFrame::IMHandler::~IMHandler()
+{
+ // cancel an eventual event posted to begin preedit again
+ GtkSalFrame::getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ deleteIMContext();
+}
+
+void GtkSalFrame::IMHandler::createIMContext()
+{
+ if( ! m_pIMContext )
+ {
+ m_pIMContext = gtk_im_multicontext_new ();
+ g_signal_connect( m_pIMContext, "commit",
+ G_CALLBACK (signalIMCommit), this );
+ g_signal_connect( m_pIMContext, "preedit_changed",
+ G_CALLBACK (signalIMPreeditChanged), this );
+ g_signal_connect( m_pIMContext, "retrieve_surrounding",
+ G_CALLBACK (signalIMRetrieveSurrounding), this );
+ g_signal_connect( m_pIMContext, "delete_surrounding",
+ G_CALLBACK (signalIMDeleteSurrounding), this );
+ g_signal_connect( m_pIMContext, "preedit_start",
+ G_CALLBACK (signalIMPreeditStart), this );
+ g_signal_connect( m_pIMContext, "preedit_end",
+ G_CALLBACK (signalIMPreeditEnd), this );
+
+ GetGenericData()->ErrorTrapPush();
+ gtk_im_context_set_client_window( m_pIMContext, widget_get_window(GTK_WIDGET(m_pFrame->m_pWindow)) );
+ gtk_im_context_focus_in( m_pIMContext );
+ GetGenericData()->ErrorTrapPop();
+ m_bFocused = true;
+ }
+}
+
+void GtkSalFrame::IMHandler::deleteIMContext()
+{
+ if( m_pIMContext )
+ {
+ // first give IC a chance to deinitialize
+ GetGenericData()->ErrorTrapPush();
+ gtk_im_context_set_client_window( m_pIMContext, NULL );
+ GetGenericData()->ErrorTrapPop();
+ // destroy old IC
+ g_object_unref( m_pIMContext );
+ m_pIMContext = NULL;
+ }
+}
+
+void GtkSalFrame::IMHandler::doCallEndExtTextInput()
+{
+ m_aInputEvent.mpTextAttr = NULL;
+ m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
+}
+
+void GtkSalFrame::IMHandler::updateIMSpotLocation()
+{
+ SalExtTextInputPosEvent aPosEvent;
+ m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent );
+ GdkRectangle aArea;
+ aArea.x = aPosEvent.mnX;
+ aArea.y = aPosEvent.mnY;
+ aArea.width = aPosEvent.mnWidth;
+ aArea.height = aPosEvent.mnHeight;
+ GetGenericData()->ErrorTrapPush();
+ gtk_im_context_set_cursor_location( m_pIMContext, &aArea );
+ GetGenericData()->ErrorTrapPop();
+}
+
+void GtkSalFrame::IMHandler::sendEmptyCommit()
+{
+ vcl::DeletionListener aDel( m_pFrame );
+
+ SalExtTextInputEvent aEmptyEv;
+ aEmptyEv.mnTime = 0;
+ aEmptyEv.mpTextAttr = 0;
+ aEmptyEv.maText.clear();
+ aEmptyEv.mnCursorPos = 0;
+ aEmptyEv.mnCursorFlags = 0;
+ aEmptyEv.mbOnlyCursor = False;
+ m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv );
+ if( ! aDel.isDeleted() )
+ m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
+}
+
+void GtkSalFrame::IMHandler::endExtTextInput( sal_uInt16 /*nFlags*/ )
+{
+ gtk_im_context_reset ( m_pIMContext );
+
+ if( m_aInputEvent.mpTextAttr )
+ {
+ vcl::DeletionListener aDel( m_pFrame );
+ // delete preedit in sal (commit an empty string)
+ sendEmptyCommit();
+ if( ! aDel.isDeleted() )
+ {
+ // mark previous preedit state again (will e.g. be sent at focus gain)
+ m_aInputEvent.mpTextAttr = &m_aInputFlags[0];
+ if( m_bFocused )
+ {
+ // begin preedit again
+ GtkSalFrame::getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ }
+ }
+ }
+}
+
+void GtkSalFrame::IMHandler::focusChanged( bool bFocusIn )
+{
+ m_bFocused = bFocusIn;
+ if( bFocusIn )
+ {
+ GetGenericData()->ErrorTrapPush();
+ gtk_im_context_focus_in( m_pIMContext );
+ GetGenericData()->ErrorTrapPop();
+ if( m_aInputEvent.mpTextAttr )
+ {
+ sendEmptyCommit();
+ // begin preedit again
+ GtkSalFrame::getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ }
+ }
+ else
+ {
+ GetGenericData()->ErrorTrapPush();
+ gtk_im_context_focus_out( m_pIMContext );
+ GetGenericData()->ErrorTrapPop();
+ // cancel an eventual event posted to begin preedit again
+ GtkSalFrame::getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ }
+}
+
+bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent )
+{
+ vcl::DeletionListener aDel( m_pFrame );
+
+ if( pEvent->type == GDK_KEY_PRESS )
+ {
+ // Add this key press event to the list of previous key presses
+ // to which we compare key release events. If a later key release
+ // event has a matching key press event in this list, we swallow
+ // the key release because some GTK Input Methods don't swallow it
+ // for us.
+ m_aPrevKeyPresses.push_back( PreviousKeyPress(pEvent) );
+ m_nPrevKeyPresses++;
+
+ // Also pop off the earliest key press event if there are more than 10
+ // already.
+ while (m_nPrevKeyPresses > 10)
+ {
+ m_aPrevKeyPresses.pop_front();
+ m_nPrevKeyPresses--;
+ }
+
+ GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
+
+ // #i51353# update spot location on every key input since we cannot
+ // know which key may activate a preedit choice window
+ updateIMSpotLocation();
+ if( aDel.isDeleted() )
+ return true;
+
+ gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
+ g_object_unref( pRef );
+
+ if( aDel.isDeleted() )
+ return true;
+
+ m_bPreeditJustChanged = false;
+
+ if( bResult )
+ return true;
+ else
+ {
+ DBG_ASSERT( m_nPrevKeyPresses > 0, "key press has vanished !" );
+ if( ! m_aPrevKeyPresses.empty() ) // sanity check
+ {
+ // event was not swallowed, do not filter a following
+ // key release event
+ // note: this relies on gtk_im_context_filter_keypress
+ // returning without calling a handler (in the "not swallowed"
+ // case ) which might change the previous key press list so
+ // we would pop the wrong event here
+ m_aPrevKeyPresses.pop_back();
+ m_nPrevKeyPresses--;
+ }
+ }
+ }
+
+ // Determine if we got an earlier key press event corresponding to this key release
+ if (pEvent->type == GDK_KEY_RELEASE)
+ {
+ GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
+ gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
+ g_object_unref( pRef );
+
+ if( aDel.isDeleted() )
+ return true;
+
+ m_bPreeditJustChanged = false;
+
+ std::list<PreviousKeyPress>::iterator iter = m_aPrevKeyPresses.begin();
+ std::list<PreviousKeyPress>::iterator iter_end = m_aPrevKeyPresses.end();
+ while (iter != iter_end)
+ {
+ // If we found a corresponding previous key press event, swallow the release
+ // and remove the earlier key press from our list
+ if (*iter == pEvent)
+ {
+ m_aPrevKeyPresses.erase(iter);
+ m_nPrevKeyPresses--;
+ return true;
+ }
+ ++iter;
+ }
+
+ if( bResult )
+ return true;
+ }
+
+ return false;
+}
+
+/* FIXME:
+* #122282# still more hacking: some IMEs never start a preedit but simply commit
+* in this case we cannot commit a single character. Workaround: do not do the
+* single key hack for enter or space if the unicode committed does not match
+*/
+
+static bool checkSingleKeyCommitHack( guint keyval, sal_Unicode cCode )
+{
+ bool bRet = true;
+ switch( keyval )
+ {
+ case GDK_KP_Enter:
+ case GDK_Return:
+ if( cCode != '\n' && cCode != '\r' )
+ bRet = false;
+ break;
+ case GDK_space:
+ case GDK_KP_Space:
+ if( cCode != ' ' )
+ bRet = false;
+ break;
+ default:
+ break;
+ }
+ return bRet;
+}
+
+void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* pContext, gchar* pText, gpointer im_handler )
+{
+ GtkSalFrame::IMHandler* pThis = static_cast<GtkSalFrame::IMHandler*>(im_handler);
+
+ SolarMutexGuard aGuard;
+ vcl::DeletionListener aDel( pThis->m_pFrame );
+ {
+ const bool bWasPreedit =
+ (pThis->m_aInputEvent.mpTextAttr != 0) ||
+ pThis->m_bPreeditJustChanged;
+
+ pThis->m_aInputEvent.mnTime = 0;
+ pThis->m_aInputEvent.mpTextAttr = 0;
+ pThis->m_aInputEvent.maText = OUString( pText, strlen(pText), RTL_TEXTENCODING_UTF8 );
+ pThis->m_aInputEvent.mnCursorPos = pThis->m_aInputEvent.maText.getLength();
+ pThis->m_aInputEvent.mnCursorFlags = 0;
+ pThis->m_aInputEvent.mbOnlyCursor = False;
+
+ pThis->m_aInputFlags.clear();
+
+ /* necessary HACK: all keyboard input comes in here as soon as a IMContext is set
+ * which is logical and consequent. But since even simple input like
+ * <space> comes through the commit signal instead of signalKey
+ * and all kinds of windows only implement KeyInput (e.g. PushButtons,
+ * RadioButtons and a lot of other Controls), will send a single
+ * KeyInput/KeyUp sequence instead of an ExtText event if there
+ * never was a preedit and the text is only one character.
+ *
+ * In this case there the last ExtText event must have been
+ * SALEVENT_ENDEXTTEXTINPUT, either because of a regular commit
+ * or because there never was a preedit.
+ */
+ bool bSingleCommit = false;
+ if( ! bWasPreedit
+ && pThis->m_aInputEvent.maText.getLength() == 1
+ && ! pThis->m_aPrevKeyPresses.empty()
+ )
+ {
+ const PreviousKeyPress& rKP = pThis->m_aPrevKeyPresses.back();
+ sal_Unicode aOrigCode = pThis->m_aInputEvent.maText[0];
+
+ if( checkSingleKeyCommitHack( rKP.keyval, aOrigCode ) )
+ {
+ pThis->m_pFrame->doKeyCallback( rKP.state, rKP.keyval, rKP.hardware_keycode, rKP.group, rKP.time, aOrigCode, true, true );
+ bSingleCommit = true;
+ }
+ }
+ if( ! bSingleCommit )
+ {
+ pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
+ if( ! aDel.isDeleted() )
+ pThis->doCallEndExtTextInput();
+ }
+ if( ! aDel.isDeleted() )
+ {
+ // reset input event
+ pThis->m_aInputEvent.maText.clear();
+ pThis->m_aInputEvent.mnCursorPos = 0;
+ pThis->updateIMSpotLocation();
+ }
+ }
+#ifdef SOLARIS
+ // #i51356# workaround a solaris IIIMP bug
+ // in case of partial commits the preedit changed signal
+ // and commit signal come in wrong order
+ if( ! aDel.isDeleted() )
+ signalIMPreeditChanged( pContext, im_handler );
+#else
+ (void) pContext;
+#endif
+}
+
+void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext*, gpointer im_handler )
+{
+ GtkSalFrame::IMHandler* pThis = static_cast<GtkSalFrame::IMHandler*>(im_handler);
+
+ char* pText = NULL;
+ PangoAttrList* pAttrs = NULL;
+ gint nCursorPos = 0;
+
+ gtk_im_context_get_preedit_string( pThis->m_pIMContext,
+ &pText,
+ &pAttrs,
+ &nCursorPos );
+ if( pText && ! *pText ) // empty string
+ {
+ // change from nothing to nothing -> do not start preedit
+ // e.g. this will activate input into a calc cell without
+ // user input
+ if( pThis->m_aInputEvent.maText.getLength() == 0 )
+ {
+ g_free( pText );
+ pango_attr_list_unref( pAttrs );
+ return;
+ }
+ }
+
+ pThis->m_bPreeditJustChanged = true;
+
+ bool bEndPreedit = (!pText || !*pText) && pThis->m_aInputEvent.mpTextAttr != NULL;
+ pThis->m_aInputEvent.mnTime = 0;
+ pThis->m_aInputEvent.maText = pText ? OUString( pText, strlen(pText), RTL_TEXTENCODING_UTF8 ) : OUString();
+ pThis->m_aInputEvent.mnCursorPos = nCursorPos;
+ pThis->m_aInputEvent.mnCursorFlags = 0;
+ pThis->m_aInputEvent.mbOnlyCursor = False;
+
+ pThis->m_aInputFlags = std::vector<sal_uInt16>( std::max( 1, (int)pThis->m_aInputEvent.maText.getLength() ), 0 );
+
+ PangoAttrIterator *iter = pango_attr_list_get_iterator(pAttrs);
+ do
+ {
+ GSList *attr_list = NULL;
+ GSList *tmp_list = NULL;
+ gint start, end;
+ guint sal_attr = 0;
+
+ pango_attr_iterator_range (iter, &start, &end);
+ if (end == G_MAXINT)
+ end = pText ? strlen (pText) : 0;
+ if (end == start)
+ continue;
+
+ start = g_utf8_pointer_to_offset (pText, pText + start);
+ end = g_utf8_pointer_to_offset (pText, pText + end);
+
+ tmp_list = attr_list = pango_attr_iterator_get_attrs (iter);
+ while (tmp_list)
+ {
+ PangoAttribute *pango_attr = static_cast<PangoAttribute *>(tmp_list->data);
+
+ switch (pango_attr->klass->type)
+ {
+ case PANGO_ATTR_BACKGROUND:
+ sal_attr |= (EXTTEXTINPUT_ATTR_HIGHLIGHT | EXTTEXTINPUT_CURSOR_INVISIBLE);
+ break;
+ case PANGO_ATTR_UNDERLINE:
+ sal_attr |= EXTTEXTINPUT_ATTR_UNDERLINE;
+ break;
+ case PANGO_ATTR_STRIKETHROUGH:
+ sal_attr |= EXTTEXTINPUT_ATTR_REDTEXT;
+ break;
+ default:
+ break;
+ }
+ pango_attribute_destroy (pango_attr);
+ tmp_list = tmp_list->next;
+ }
+ if (sal_attr == 0)
+ sal_attr |= EXTTEXTINPUT_ATTR_UNDERLINE;
+ g_slist_free (attr_list);
+
+ // Set the sal attributes on our text
+ for (int i = start; i < end; ++i)
+ {
+ SAL_WARN_IF(i >= static_cast<int>(pThis->m_aInputFlags.size()),
+ "vcl.gtk", "pango attrib out of range. Broken range: "
+ << start << "," << end << " Legal range: 0,"
+ << pThis->m_aInputFlags.size());
+ if (i >= static_cast<int>(pThis->m_aInputFlags.size()))
+ continue;
+ pThis->m_aInputFlags[i] |= sal_attr;
+ }
+ } while (pango_attr_iterator_next (iter));
+ pango_attr_iterator_destroy(iter);
+
+ pThis->m_aInputEvent.mpTextAttr = &pThis->m_aInputFlags[0];
+
+ g_free( pText );
+ pango_attr_list_unref( pAttrs );
+
+ SolarMutexGuard aGuard;
+ vcl::DeletionListener aDel( pThis->m_pFrame );
+
+ pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
+ if( bEndPreedit && ! aDel.isDeleted() )
+ pThis->doCallEndExtTextInput();
+ if( ! aDel.isDeleted() )
+ pThis->updateIMSpotLocation();
+}
+
+void GtkSalFrame::IMHandler::signalIMPreeditStart( GtkIMContext*, gpointer /*im_handler*/ )
+{
+}
+
+void GtkSalFrame::IMHandler::signalIMPreeditEnd( GtkIMContext*, gpointer im_handler )
+{
+ GtkSalFrame::IMHandler* pThis = static_cast<GtkSalFrame::IMHandler*>(im_handler);
+
+ pThis->m_bPreeditJustChanged = true;
+
+ SolarMutexGuard aGuard;
+ vcl::DeletionListener aDel( pThis->m_pFrame );
+ pThis->doCallEndExtTextInput();
+ if( ! aDel.isDeleted() )
+ pThis->updateIMSpotLocation();
+}
+
+uno::Reference<accessibility::XAccessibleEditableText>
+ FindFocus(uno::Reference< accessibility::XAccessibleContext > xContext)
+{
+ if (!xContext.is())
+ uno::Reference< accessibility::XAccessibleEditableText >();
+
+ uno::Reference<accessibility::XAccessibleStateSet> xState = xContext->getAccessibleStateSet();
+ if (xState.is())
+ {
+ if (xState->contains(accessibility::AccessibleStateType::FOCUSED))
+ return uno::Reference<accessibility::XAccessibleEditableText>(xContext, uno::UNO_QUERY);
+ }
+
+ for (sal_Int32 i = 0; i < xContext->getAccessibleChildCount(); ++i)
+ {
+ uno::Reference< accessibility::XAccessible > xChild = xContext->getAccessibleChild(i);
+ if (!xChild.is())
+ continue;
+ uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext();
+ if (!xChildContext.is())
+ continue;
+ uno::Reference< accessibility::XAccessibleEditableText > xText = FindFocus(xChildContext);
+ if (xText.is())
+ return xText;
+ }
+ return uno::Reference< accessibility::XAccessibleEditableText >();
+}
+
+static uno::Reference<accessibility::XAccessibleEditableText> lcl_GetxText(vcl::Window *pFocusWin)
+{
+ uno::Reference<accessibility::XAccessibleEditableText> xText;
+ try
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible( pFocusWin->GetAccessible( true ) );
+ if (xAccessible.is())
+ xText = FindFocus(xAccessible->getAccessibleContext());
+ }
+ catch(const uno::Exception& e)
+ {
+ SAL_WARN( "vcl.gtk", "Exception in getting input method surrounding text: " << e.Message);
+ }
+ return xText;
+}
+
+gboolean GtkSalFrame::IMHandler::signalIMRetrieveSurrounding( GtkIMContext* pContext, gpointer /*im_handler*/ )
+{
+ vcl::Window *pFocusWin = Application::GetFocusWindow();
+ if (!pFocusWin)
+ return true;
+
+ uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText(pFocusWin);
+ if (xText.is())
+ {
+ sal_Int32 nPosition = xText->getCaretPosition();
+ OUString sAllText = xText->getText();
+ OString sUTF = OUStringToOString(sAllText, RTL_TEXTENCODING_UTF8);
+ OUString sCursorText(sAllText.copy(0, nPosition));
+ gtk_im_context_set_surrounding(pContext, sUTF.getStr(), sUTF.getLength(),
+ OUStringToOString(sCursorText, RTL_TEXTENCODING_UTF8).getLength());
+ return true;
+ }
+
+ return false;
+}
+
+gboolean GtkSalFrame::IMHandler::signalIMDeleteSurrounding( GtkIMContext*, gint offset, gint nchars,
+ gpointer /*im_handler*/ )
+{
+ vcl::Window *pFocusWin = Application::GetFocusWindow();
+ if (!pFocusWin)
+ return true;
+
+ uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText(pFocusWin);
+ if (xText.is())
+ {
+ sal_Int32 nPosition = xText->getCaretPosition();
+ // #i111768# range checking
+ sal_Int32 nDeletePos = nPosition + offset;
+ sal_Int32 nDeleteEnd = nDeletePos + nchars;
+ if (nDeletePos < 0)
+ nDeletePos = 0;
+ if (nDeleteEnd < 0)
+ nDeleteEnd = 0;
+ if (nDeleteEnd > xText->getCharacterCount())
+ nDeleteEnd = xText->getCharacterCount();
+
+ xText->deleteText(nDeletePos, nDeleteEnd);
+ //tdf91641 adjust cursor if deleted chars shift it forward (normal case)
+ if (nDeletePos < nPosition)
+ {
+ if (nDeleteEnd <= nPosition)
+ nPosition = nPosition - (nDeleteEnd - nDeletePos);
+ else
+ nPosition = nDeletePos;
+
+ if (xText->getCharacterCount() >= nPosition)
+ xText->setCaretPosition( nPosition );
+ }
+ return true;
+ }
+
+ return false;
+}
+
+Size GtkSalDisplay::GetScreenSize( int nDisplayScreen )
+{
+ Rectangle aRect = m_pSys->GetDisplayScreenPosSizePixel( nDisplayScreen );
+ return Size( aRect.GetWidth(), aRect.GetHeight() );
+}
+
+Window GtkSalFrame::GetX11Window()
+{
+ return widget_get_xid(m_pWindow);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
new file mode 100644
index 0000000..5716058
--- /dev/null
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -0,0 +1,641 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ */
+
+#include "../../gtk/app/gtkinst.cxx"
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include "com/sun/star/lang/XServiceInfo.hpp"
+#include "com/sun/star/lang/XSingleServiceFactory.hpp"
+#include "com/sun/star/lang/XInitialization.hpp"
+#include "com/sun/star/lang/DisposedException.hpp"
+#include "com/sun/star/datatransfer/XTransferable.hpp"
+#include "com/sun/star/datatransfer/clipboard/XClipboard.hpp"
+#include "com/sun/star/datatransfer/clipboard/XClipboardEx.hpp"
+#include "com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp"
+#include "com/sun/star/datatransfer/clipboard/XClipboardListener.hpp"
+#include "com/sun/star/datatransfer/clipboard/XSystemClipboard.hpp"
+#include "com/sun/star/datatransfer/dnd/XDragSource.hpp"
+#include "com/sun/star/datatransfer/dnd/XDropTarget.hpp"
+#include "com/sun/star/datatransfer/dnd/DNDConstants.hpp"
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include "cppuhelper/compbase.hxx"
+#include "cppuhelper/implbase1.hxx"
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+
+namespace
+{
+ struct TypeEntry
+ {
+ const char* pNativeType; // string corresponding to nAtom for the case of nAtom being uninitialized
+ const char* pType; // Mime encoding on our side
+ };
+
+ static TypeEntry aConversionTab[] =
+ {
+ { "ISO10646-1", "text/plain;charset=utf-16" },
+ { "UTF8_STRING", "text/plain;charset=utf-8" },
+ { "UTF-8", "text/plain;charset=utf-8" },
+ { "text/plain;charset=UTF-8", "text/plain;charset=utf-8" },
+ // ISO encodings
+ { "ISO8859-2", "text/plain;charset=iso8859-2" },
+ { "ISO8859-3", "text/plain;charset=iso8859-3" },
+ { "ISO8859-4", "text/plain;charset=iso8859-4" },
+ { "ISO8859-5", "text/plain;charset=iso8859-5" },
+ { "ISO8859-6", "text/plain;charset=iso8859-6" },
+ { "ISO8859-7", "text/plain;charset=iso8859-7" },
+ { "ISO8859-8", "text/plain;charset=iso8859-8" },
+ { "ISO8859-9", "text/plain;charset=iso8859-9" },
+ { "ISO8859-10", "text/plain;charset=iso8859-10" },
+ { "ISO8859-13", "text/plain;charset=iso8859-13" },
+ { "ISO8859-14", "text/plain;charset=iso8859-14" },
+ { "ISO8859-15", "text/plain;charset=iso8859-15" },
+ // asian encodings
+ { "JISX0201.1976-0", "text/plain;charset=jisx0201.1976-0" },
+ { "JISX0208.1983-0", "text/plain;charset=jisx0208.1983-0" },
+ { "JISX0208.1990-0", "text/plain;charset=jisx0208.1990-0" },
+ { "JISX0212.1990-0", "text/plain;charset=jisx0212.1990-0" },
+ { "GB2312.1980-0", "text/plain;charset=gb2312.1980-0" },
+ { "KSC5601.1992-0", "text/plain;charset=ksc5601.1992-0" },
+ // eastern european encodings
+ { "KOI8-R", "text/plain;charset=koi8-r" },
+ { "KOI8-U", "text/plain;charset=koi8-u" },
+ // String (== iso8859-1)
+ { "STRING", "text/plain;charset=iso8859-1" },
+ // special for compound text
+ { "COMPOUND_TEXT", "text/plain;charset=compound_text" },
+
+ // PIXMAP
+ { "PIXMAP", "image/bmp" }
+ };
+
+ class DataFlavorEq : public std::unary_function<const css::datatransfer::DataFlavor&, bool>
+ {
+ private:
+ const css::datatransfer::DataFlavor& m_rData;
+ public:
+ explicit DataFlavorEq(const css::datatransfer::DataFlavor& rData) : m_rData(rData) {}
+ bool operator() (const css::datatransfer::DataFlavor& rData) const
+ {
+ return rData.MimeType == m_rData.MimeType &&
+ rData.DataType == m_rData.DataType;
+ }
+ };
+}
+
+class GtkTransferable : public ::cppu::WeakImplHelper1 <
+ css::datatransfer::XTransferable >
+{
+private:
+ GdkAtom m_nSelection;
+ std::map<OUString, GdkAtom> m_aMimeTypeToAtom;
+public:
+
+ GtkTransferable(GdkAtom nSelection)
+ : m_nSelection(nSelection)
+ {
+ }
+
+ /*
+ * XTransferable
+ */
+
+ virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor)
+ throw(css::datatransfer::UnsupportedFlavorException,
+ css::io::IOException,
+ css::uno::RuntimeException, std::exception
+ ) SAL_OVERRIDE
+ {
+ GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
+ if (rFlavor.MimeType == "text/plain;charset=utf-16")
+ {
+ OUString aStr;
+ gchar *pText = gtk_clipboard_wait_for_text(clipboard);
+ if (pText)
+ aStr = OUString(pText, rtl_str_getLength(pText), RTL_TEXTENCODING_UTF8);
+ g_free(pText);
+ css::uno::Any aRet;
+ aRet <<= aStr.replaceAll("\r\n", "\n");
+ return aRet;
+ }
+
+ auto it = m_aMimeTypeToAtom.find(rFlavor.MimeType);
+ if (it == m_aMimeTypeToAtom.end())
+ return css::uno::Any();
+
+ css::uno::Any aRet;
+ GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard,
+ it->second);
+ gint length;
+ const guchar *rawdata = gtk_selection_data_get_data_with_length(data,
+ &length);
+ Sequence<sal_Int8> aSeq(reinterpret_cast<const sal_Int8*>(rawdata), length);
+ gtk_selection_data_free(data);
+ aRet <<= aSeq;
+ return aRet;
+ }
+
+ std::vector<css::datatransfer::DataFlavor> getTransferDataFlavorsAsVector()
+ {
+ std::vector<css::datatransfer::DataFlavor> aVector;
+
+ GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
+
+ GdkAtom *targets;
+ gint n_targets;
+ if (gtk_clipboard_wait_for_targets(clipboard, &targets, &n_targets))
+ {
+ bool bHaveText = false, bHaveUTF16 = false;
+
+ for (gint i = 0; i < n_targets; ++i)
+ {
+ gchar* pName = gdk_atom_name(targets[i]);
+ const char* pFinalName = pName;
+ css::datatransfer::DataFlavor aFlavor;
+
+ for (size_t j = 0; j < SAL_N_ELEMENTS(aConversionTab); ++j)
+ {
+ if (rtl_str_compare(pName, aConversionTab[j].pNativeType) == 0)
+ {
+ pFinalName = aConversionTab[j].pType;
+ break;
+ }
+ }
+
+ aFlavor.MimeType = OUString(pFinalName,
+ rtl_str_getLength(pFinalName),
+ RTL_TEXTENCODING_UTF8);
+
+ m_aMimeTypeToAtom[aFlavor.MimeType] = targets[i];
+
+ aFlavor.DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
+
+ sal_Int32 nIndex(0);
+ if (aFlavor.MimeType.getToken(0, ';', nIndex) == "text/plain")
+ {
+ bHaveText = true;
+ OUString aToken(aFlavor.MimeType.getToken(0, ';', nIndex));
+ if (aToken == "charset=utf-16")
+ {
+ bHaveUTF16 = true;
+ aFlavor.DataType = cppu::UnoType<OUString>::get();
+ }
+ }
+ aVector.push_back(aFlavor);
+ g_free(pName);
+ }
+
+ g_free(targets);
+
+ //If we have text, but no UTF-16 format which is basically the only
+ //text-format LibreOffice supports for cnp then claim we do and we
+ //will convert on demand
+ if (bHaveText && !bHaveUTF16)
+ {
+ css::datatransfer::DataFlavor aFlavor;
+ aFlavor.MimeType = "text/plain;charset=utf-16";
+ aFlavor.DataType = cppu::UnoType<OUString>::get();
+ aVector.push_back(aFlavor);
+ }
+ }
+
+ return aVector;
+ }
+
+ virtual css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors()
+ throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE
+ {
+ return comphelper::containerToSequence(getTransferDataFlavorsAsVector());
+ }
+
+ virtual sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor)
+ throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE
+ {
+ const std::vector<css::datatransfer::DataFlavor> aAll =
+ getTransferDataFlavorsAsVector();
+
+ return std::find_if(aAll.begin(), aAll.end(), DataFlavorEq(rFlavor)) != aAll.end();
+ }
+};
+
+//We want to use gtk_clipboard_get_owner own owner-change to distinguish between
+//us gaining the clipboard ownership vs losing it. To do that we need to use
+//gtk_clipboard_set_with_owner and to do that we need a GObject, so define
+//one here for that purpose and just give it a VclGtkClipboard* member
+class VclGtkClipboard;
+
+typedef struct _ClipboardOwner ClipboardOwner;
+typedef struct _ClipboardOwnerClass ClipboardOwnerClass;
+
+struct _ClipboardOwner
+{
+ GObject parent_instance;
+
+ /* instance members */
+ VclGtkClipboard* m_pThis;
+};
+
+struct _ClipboardOwnerClass
+{
+ GObjectClass parent_class;
+
+ /* class members */
+};
+
+#define CLIPBOARD_OWNER_OBJECT (clipboard_owner_get_type ())
+#define CLIPBOARD_OWNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLIPBOARD_OWNER_OBJECT, ClipboardOwner))
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+G_DEFINE_TYPE(ClipboardOwner, clipboard_owner, G_TYPE_OBJECT);
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+static void clipboard_owner_class_init (ClipboardOwnerClass *)
+{
+}
+
+static void clipboard_owner_init(ClipboardOwner *)
+{
+}
+
+class VclGtkClipboard :
+ public cppu::WeakComponentImplHelper<
+ datatransfer::clipboard::XSystemClipboard,
+ XServiceInfo>
+{
+ GdkAtom m_nSelection;
+ osl::Mutex m_aMutex;
+ ClipboardOwner* m_pOwner;
+ gulong m_nOwnerChangedSignalId;
+ Reference<css::datatransfer::XTransferable> m_aContents;
+ Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner;
+ std::list< Reference<css::datatransfer::clipboard::XClipboardListener> > m_aListeners;
+ std::vector<GtkTargetEntry> m_aGtkTargets;
+ std::vector<css::datatransfer::DataFlavor> m_aInfoToFlavor;
+
+public:
+
+ VclGtkClipboard(GdkAtom nSelection);
+ virtual ~VclGtkClipboard();
+
+ /*
+ * XServiceInfo
+ */
+
+ virtual OUString SAL_CALL getImplementationName() throw( RuntimeException, std::exception ) SAL_OVERRIDE;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw( RuntimeException, std::exception ) SAL_OVERRIDE;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw( RuntimeException, std::exception ) SAL_OVERRIDE;
+
+ static OUString getImplementationName_static();
+ static Sequence< OUString > getSupportedServiceNames_static();
+
+ /*
+ * XClipboard
+ */
+
+ virtual Reference< css::datatransfer::XTransferable > SAL_CALL getContents()
+ throw(RuntimeException, std::exception) SAL_OVERRIDE;
+
+ virtual void SAL_CALL setContents(
+ const Reference< css::datatransfer::XTransferable >& xTrans,
+ const Reference< css::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner )
+ throw(RuntimeException, std::exception) SAL_OVERRIDE;
+
+ virtual OUString SAL_CALL getName()
+ throw(RuntimeException, std::exception) SAL_OVERRIDE;
+
+ /*
+ * XClipboardEx
+ */
+
+ virtual sal_Int8 SAL_CALL getRenderingCapabilities()
+ throw(RuntimeException, std::exception) SAL_OVERRIDE;
+
+ /*
+ * XClipboardNotifier
+ */
+ virtual void SAL_CALL addClipboardListener(
+ const Reference< css::datatransfer::clipboard::XClipboardListener >& listener )
+ throw(RuntimeException, std::exception) SAL_OVERRIDE;
+
+ virtual void SAL_CALL removeClipboardListener(
+ const Reference< css::datatransfer::clipboard::XClipboardListener >& listener )
+ throw(RuntimeException, std::exception) SAL_OVERRIDE;
+
+ void ClipboardGet(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info);
+ void ClipboardClear(GtkClipboard *clipboard);
+ void OwnerChanged(GtkClipboard *clipboard, GdkEvent *event);
+private:
+ GtkTargetEntry makeGtkTargetEntry(const css::datatransfer::DataFlavor& rFlavor);
+};
+
+OUString VclGtkClipboard::getImplementationName_static()
+{
+ return OUString( "com.sun.star.datatransfer.VclGtkClipboard" );
+}
+
+Sequence< OUString > VclGtkClipboard::getSupportedServiceNames_static()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = "com.sun.star.datatransfer.clipboard.SystemClipboard";
+ return aRet;
+}
+
+OUString VclGtkClipboard::getImplementationName() throw( RuntimeException, std::exception )
+{
+ return getImplementationName_static();
+}
+
+Sequence< OUString > VclGtkClipboard::getSupportedServiceNames() throw( RuntimeException, std::exception )
+{
+ return getSupportedServiceNames_static();
+}
+
+sal_Bool VclGtkClipboard::supportsService( const OUString& ServiceName ) throw( RuntimeException, std::exception )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Reference< css::datatransfer::XTransferable > VclGtkClipboard::getContents() throw( RuntimeException, std::exception )
+{
+ if (G_OBJECT(m_pOwner) != gtk_clipboard_get_owner(gtk_clipboard_get(m_nSelection)) &&
+ !m_aContents.is())
+ {
+ //tdf#93887 This is the system clipboard/selection. We fetch it when we are not
+ //the owner of the clipboard and have not already fetched it.
+ m_aContents = new GtkTransferable(m_nSelection);
+ }
+ return m_aContents;
+}
+
+void VclGtkClipboard::ClipboardGet(GtkClipboard* /*clipboard*/, GtkSelectionData *selection_data,
+ guint info)
+{
+ if (!m_aContents.is())
+ return;
+
+ GdkAtom type(gdk_atom_intern(OUStringToOString(m_aInfoToFlavor[info].MimeType,
+ RTL_TEXTENCODING_UTF8).getStr(),
+ false));
+
+ css::datatransfer::DataFlavor aFlavor(m_aInfoToFlavor[info]);
+ if (aFlavor.MimeType == "UTF8_STRING" || aFlavor.MimeType == "STRING")
+ aFlavor.MimeType = "text/plain;charset=utf-8";
+
+ Sequence<sal_Int8> aData;
+ Any aValue;
+
+ try
+ {
+ aValue = m_aContents->getTransferData(aFlavor);
+ }
+ catch(...)
+ {
+ }
+
+ if (aValue.getValueTypeClass() == TypeClass_STRING)
+ {
+ OUString aString;
+ aValue >>= aString;
+ aData = Sequence< sal_Int8 >( reinterpret_cast<sal_Int8 const *>(aString.getStr()), aString.getLength() * sizeof( sal_Unicode ) );
+ }
+ else if (aValue.getValueType() == cppu::UnoType<Sequence< sal_Int8 >>::get())
+ {
+ aValue >>= aData;
+ }
+ else if (aFlavor.MimeType == "text/plain;charset=utf-8")
+ {
+ //didn't have utf-8, try utf-16 and convert
+ aFlavor.MimeType = "text/plain;charset=utf-16";
+ aFlavor.DataType = cppu::UnoType<OUString>::get();
+ try
+ {
+ aValue = m_aContents->getTransferData(aFlavor);
+ }
+ catch(...)
+ {
+ }
+ OUString aString;
+ aValue >>= aString;
+ OString aUTF8String(OUStringToOString(aString, RTL_TEXTENCODING_UTF8));
+ gtk_selection_data_set(selection_data, type, 8,
+ reinterpret_cast<const guchar *>(aUTF8String.getStr()),
+ aUTF8String.getLength());
+ return;
+ }
+
+ gtk_selection_data_set(selection_data, type, 8,
+ reinterpret_cast<const guchar *>(aData.getArray()),
+ aData.getLength());
+}
+
+void VclGtkClipboard::OwnerChanged(GtkClipboard* clipboard, GdkEvent* /*event*/)
+{
+ if (G_OBJECT(m_pOwner) != gtk_clipboard_get_owner(clipboard))
+ {
+ //null out m_aContents to return control to the system-one which
+ //will be retrieved if getContents is called again
+ setContents(Reference<css::datatransfer::XTransferable>(),
+ Reference<css::datatransfer::clipboard::XClipboardOwner>());
+ }
+}
+
+void VclGtkClipboard::ClipboardClear(GtkClipboard * /*clipboard*/)
+{
+ for (auto &a : m_aGtkTargets)
+ free(a.target);
+ m_aGtkTargets.clear();
+}
+
+GtkTargetEntry VclGtkClipboard::makeGtkTargetEntry(const css::datatransfer::DataFlavor& rFlavor)
+{
+ GtkTargetEntry aEntry;
+ aEntry.target =
+ g_strdup(OUStringToOString(rFlavor.MimeType, RTL_TEXTENCODING_UTF8).getStr());
+ aEntry.flags = 0;
+ auto it = std::find_if(m_aInfoToFlavor.begin(), m_aInfoToFlavor.end(),
+ DataFlavorEq(rFlavor));
+ if (it != m_aInfoToFlavor.end())
+ aEntry.info = std::distance(m_aInfoToFlavor.begin(), it);
+ else
+ {
+ aEntry.info = m_aInfoToFlavor.size();
+ m_aInfoToFlavor.push_back(rFlavor);
+ }
+ return aEntry;
+}
+
+namespace
+{
+ void ClipboardGetFunc(GtkClipboard *clipboard, GtkSelectionData *selection_data,
+ guint info,
+ gpointer user_data_or_owner)
+ {
+ VclGtkClipboard* pThis = CLIPBOARD_OWNER(user_data_or_owner)->m_pThis;
+ pThis->ClipboardGet(clipboard, selection_data, info);
+ }
+
+ void ClipboardClearFunc(GtkClipboard *clipboard, gpointer user_data_or_owner)
+ {
+ VclGtkClipboard* pThis = CLIPBOARD_OWNER(user_data_or_owner)->m_pThis;
+ pThis->ClipboardClear(clipboard);
+ }
+
+ void handle_owner_change(GtkClipboard *clipboard, GdkEvent *event, gpointer user_data)
+ {
+ VclGtkClipboard* pThis = static_cast<VclGtkClipboard*>(user_data);
+ pThis->OwnerChanged(clipboard, event);
+ }
+}
+
+VclGtkClipboard::VclGtkClipboard(GdkAtom nSelection)
+ : cppu::WeakComponentImplHelper<datatransfer::clipboard::XSystemClipboard, XServiceInfo>
+ (m_aMutex)
+ , m_nSelection(nSelection)
+{
+ GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
+ m_nOwnerChangedSignalId = g_signal_connect(clipboard, "owner-change",
+ G_CALLBACK(handle_owner_change), this);
+ m_pOwner = CLIPBOARD_OWNER(g_object_new(CLIPBOARD_OWNER_OBJECT, NULL));
+ m_pOwner->m_pThis = this;
+}
+
+VclGtkClipboard::~VclGtkClipboard()
+{
+ GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
+ g_signal_handler_disconnect(clipboard, m_nOwnerChangedSignalId);
+ g_object_unref(m_pOwner);
+}
+
+void VclGtkClipboard::setContents(
+ const Reference< css::datatransfer::XTransferable >& xTrans,
+ const Reference< css::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner )
+ throw( RuntimeException, std::exception )
+{
+ osl::ClearableMutexGuard aGuard( m_aMutex );
+ Reference< datatransfer::clipboard::XClipboardOwner > xOldOwner( m_aOwner );
+ Reference< datatransfer::XTransferable > xOldContents( m_aContents );
+ m_aContents = xTrans;
+ m_aOwner = xClipboardOwner;
+
+ std::list< Reference< datatransfer::clipboard::XClipboardListener > > xListeners( m_aListeners );
+ datatransfer::clipboard::ClipboardEvent aEv;
+
+ if (m_aContents.is())
+ {
+ css::uno::Sequence<css::datatransfer::DataFlavor> aFormats = xTrans->getTransferDataFlavors();
+ std::vector<GtkTargetEntry> aGtkTargets;
+ bool bHaveText(false), bHaveUTF8(false);
+ for (int i = 0; i < aFormats.getLength(); ++i)
+ {
+ const css::datatransfer::DataFlavor& rFlavor = aFormats[i];
+
+ sal_Int32 nIndex(0);
+ if (rFlavor.MimeType.getToken(0, ';', nIndex) == "text/plain")
+ {
+ bHaveText = true;
+ OUString aToken(rFlavor.MimeType.getToken(0, ';', nIndex));
+ if (aToken == "charset=utf-8")
+ {
+ bHaveUTF8 = true;
+ }
+ }
+ GtkTargetEntry aEntry(makeGtkTargetEntry(rFlavor));
+ aGtkTargets.push_back(aEntry);
+ }
+
+ if (bHaveText)
+ {
+ css::datatransfer::DataFlavor aFlavor;
+ aFlavor.DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
+ if (!bHaveUTF8)
+ {
+ aFlavor.MimeType = "text/plain;charset=utf-8";
+ aGtkTargets.push_back(makeGtkTargetEntry(aFlavor));
+ }
+ aFlavor.MimeType = "UTF8_STRING";
+ aGtkTargets.push_back(makeGtkTargetEntry(aFlavor));
+ aFlavor.MimeType = "STRING";
+ aGtkTargets.push_back(makeGtkTargetEntry(aFlavor));
+ }
+
+ //if there was a previous gtk_clipboard_set_with_data call then
+ //ClipboardClearFunc will be called now
+ GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
+ //use with_owner with m_pOwner so we can distinguish in handle_owner_change
+ //if we have gained or lost ownership of the clipboard
+ gtk_clipboard_set_with_owner(clipboard, aGtkTargets.data(), aGtkTargets.size(),
+ ClipboardGetFunc, ClipboardClearFunc, G_OBJECT(m_pOwner));
+ m_aGtkTargets = aGtkTargets;
+ }
+
+ aEv.Contents = getContents();
+
+ aGuard.clear();
+
+ if( xOldOwner.is() && xOldOwner != xClipboardOwner )
+ xOldOwner->lostOwnership( this, xOldContents );
+ for( std::list< Reference< datatransfer::clipboard::XClipboardListener > >::iterator it =
+ xListeners.begin(); it != xListeners.end() ; ++it )
+ {
+ (*it)->changedContents( aEv );
+ }
+}
+
+OUString VclGtkClipboard::getName() throw( RuntimeException, std::exception )
+{
+ return OUString( "CLIPBOARD" );
+}
+
+sal_Int8 VclGtkClipboard::getRenderingCapabilities() throw( RuntimeException, std::exception )
+{
+ return 0;
+}
+
+void VclGtkClipboard::addClipboardListener( const Reference< datatransfer::clipboard::XClipboardListener >& listener )
+ throw( RuntimeException, std::exception )
+{
+ osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ m_aListeners.push_back( listener );
+}
+
+void VclGtkClipboard::removeClipboardListener( const Reference< datatransfer::clipboard::XClipboardListener >& listener )
+ throw( RuntimeException, std::exception )
+{
+ osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ m_aListeners.remove( listener );
+}
+
+Reference< XInterface > GtkInstance::CreateClipboard(const Sequence< Any >& arguments)
+{
+ OUString sel;
+ if (arguments.getLength() == 0) {
+ sel = "CLIPBOARD";
+ } else if (arguments.getLength() != 1 || !(arguments[0] >>= sel)) {
+ throw css::lang::IllegalArgumentException(
+ "bad GtkInstance::CreateClipboard arguments",
+ css::uno::Reference<css::uno::XInterface>(), -1);
+ }
+
+ GdkAtom nSelection = (sel == "CLIPBOARD") ? GDK_SELECTION_CLIPBOARD : GDK_SELECTION_PRIMARY;
+
+ return Reference< XInterface >( static_cast<cppu::OWeakObject *>(new VclGtkClipboard(nSelection)) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk3/window/gtk3gtkframe.cxx b/vcl/unx/gtk3/window/gtk3gtkframe.cxx
deleted file mode 100644
index 5710d50..0000000
--- a/vcl/unx/gtk3/window/gtk3gtkframe.cxx
+++ /dev/null
@@ -1,12 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * 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/.
- */
-
-#include "../../gtk/window/gtksalframe.cxx"
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
--
2.5.0