1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <unx/gtk/gtkframe.hxx>
21 #include <unx/gtk/gtkdata.hxx>
22 #include <unx/gtk/gtkinst.hxx>
23 #include <unx/gtk/gtkgdi.hxx>
24 #include <vcl/help.hxx>
25 #include <vcl/keycodes.hxx>
26 #include <vcl/layout.hxx>
27 #include <unx/wmadaptor.hxx>
29 #include <unx/salbmp.h>
30 #include <generic/genprn.h>
31 #include <generic/geninst.h>
32 #include <headless/svpgdi.hxx>
33 #include <osl/file.hxx>
34 #include <rtl/bootstrap.hxx>
35 #include <rtl/process.h>
36 #include <vcl/floatwin.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/window.hxx>
39 #include <vcl/settings.hxx>
41 #if !GTK_CHECK_VERSION(3,0,0)
42 # include <unx/x11/xlimits.hxx>
44 #if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
45 # include <unx/gtk/gtksalmenu.hxx>
47 #if defined ENABLE_GMENU_INTEGRATION // defined in gtksalmenu.hxx above
48 # include <unx/gtk/hudawareness.h>
53 #include <X11/Xatom.h>
58 #include <vcl/salbtype.hxx>
59 #include <vcl/bitmapex.hxx>
62 #include <sal/macros.h>
64 #include <basegfx/range/b2ibox.hxx>
65 #include <basegfx/vector/b2ivector.hxx>
68 #include <glib/gprintf.h>
70 #if OSL_DEBUG_LEVEL > 1
74 #include <comphelper/processfactory.hxx>
75 #include <comphelper/sequenceashashmap.hxx>
76 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
77 #include <com/sun/star/accessibility/AccessibleRole.hpp>
78 #include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
79 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
80 #include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
81 #include <com/sun/star/frame/Desktop.hpp>
82 #include <com/sun/star/frame/ModuleManager.hpp>
83 #include <com/sun/star/frame/XFrame.hpp>
84 #include <com/sun/star/util/URLTransformer.hpp>
86 #if GTK_CHECK_VERSION(3,0,0)
87 # include <gdk/gdkkeysyms-compat.h>
91 #include <dbus/dbus-glib.h>
93 #define GSM_DBUS_SERVICE "org.gnome.SessionManager"
94 #define GSM_DBUS_PATH "/org/gnome/SessionManager"
95 #define GSM_DBUS_INTERFACE "org.gnome.SessionManager"
98 #include <config_folders.h>
100 #if GTK_CHECK_VERSION(3,0,0)
101 #define IS_WIDGET_REALIZED gtk_widget_get_realized
102 #define IS_WIDGET_MAPPED gtk_widget_get_mapped
104 #define IS_WIDGET_REALIZED GTK_WIDGET_REALIZED
105 #define IS_WIDGET_MAPPED GTK_WIDGET_MAPPED
108 #if !GTK_CHECK_VERSION(3,0,0)
109 #define GDK_IS_X11_DISPLAY(foo) (true)
112 using namespace com::sun::star
;
114 int GtkSalFrame::m_nFloats
= 0;
116 #if defined ENABLE_GMENU_INTEGRATION
117 static GDBusConnection
* pSessionBus
= NULL
;
120 static sal_uInt16
GetKeyModCode( guint state
)
122 sal_uInt16 nCode
= 0;
123 if( (state
& GDK_SHIFT_MASK
) )
125 if( (state
& GDK_CONTROL_MASK
) )
127 if( (state
& GDK_MOD1_MASK
) )
130 // Map Meta/Super keys to MOD3 modifier on all Unix systems
132 if ( (state
& GDK_META_MASK
) || ( state
& GDK_SUPER_MASK
) )
137 static sal_uInt16
GetMouseModCode( guint state
)
139 sal_uInt16 nCode
= GetKeyModCode( state
);
140 if( (state
& GDK_BUTTON1_MASK
) )
142 if( (state
& GDK_BUTTON2_MASK
) )
143 nCode
|= MOUSE_MIDDLE
;
144 if( (state
& GDK_BUTTON3_MASK
) )
145 nCode
|= MOUSE_RIGHT
;
150 static sal_uInt16
GetKeyCode( guint keyval
)
152 sal_uInt16 nCode
= 0;
153 if( keyval
>= GDK_0
&& keyval
<= GDK_9
)
154 nCode
= KEY_0
+ (keyval
-GDK_0
);
155 else if( keyval
>= GDK_KP_0
&& keyval
<= GDK_KP_9
)
156 nCode
= KEY_0
+ (keyval
-GDK_KP_0
);
157 else if( keyval
>= GDK_A
&& keyval
<= GDK_Z
)
158 nCode
= KEY_A
+ (keyval
-GDK_A
);
159 else if( keyval
>= GDK_a
&& keyval
<= GDK_z
)
160 nCode
= KEY_A
+ (keyval
-GDK_a
);
161 else if( keyval
>= GDK_F1
&& keyval
<= GDK_F26
)
163 #if !GTK_CHECK_VERSION(3,0,0)
164 if( GetGtkSalData()->GetGtkDisplay()->IsNumLockFromXS() )
166 nCode
= KEY_F1
+ (keyval
-GDK_F1
);
173 // - - - - - Sun keyboard, see vcl/unx/source/app/saldisp.cxx
175 #if !GTK_CHECK_VERSION(3,0,0)
176 if( GetGtkSalData()->GetGtkDisplay()->GetServerVendor() == vendor_sun
)
182 case GDK_L3
: nCode
= KEY_PROPERTIES
; break;
183 case GDK_L4
: nCode
= KEY_UNDO
; break;
184 case GDK_L6
: nCode
= KEY_COPY
; break; // KEY_F16
185 case GDK_L8
: nCode
= KEY_PASTE
; break; // KEY_F18
186 case GDK_L10
: nCode
= KEY_CUT
; break; // KEY_F20
188 nCode
= KEY_F1
+ (keyval
-GDK_F1
); break;
197 case GDK_Down
: nCode
= KEY_DOWN
; break;
199 case GDK_Up
: nCode
= KEY_UP
; break;
201 case GDK_Left
: nCode
= KEY_LEFT
; break;
203 case GDK_Right
: nCode
= KEY_RIGHT
; break;
207 case GDK_Home
: nCode
= KEY_HOME
; break;
209 case GDK_End
: nCode
= KEY_END
; break;
211 case GDK_Page_Up
: nCode
= KEY_PAGEUP
; break;
212 case GDK_KP_Page_Down
:
213 case GDK_Page_Down
: nCode
= KEY_PAGEDOWN
; break;
215 case GDK_Return
: nCode
= KEY_RETURN
; break;
216 case GDK_Escape
: nCode
= KEY_ESCAPE
; break;
217 case GDK_ISO_Left_Tab
:
219 case GDK_Tab
: nCode
= KEY_TAB
; break;
220 case GDK_BackSpace
: nCode
= KEY_BACKSPACE
; break;
222 case GDK_space
: nCode
= KEY_SPACE
; break;
224 case GDK_Insert
: nCode
= KEY_INSERT
; break;
226 case GDK_Delete
: nCode
= KEY_DELETE
; break;
228 case GDK_KP_Add
: nCode
= KEY_ADD
; break;
230 case GDK_KP_Subtract
: nCode
= KEY_SUBTRACT
; break;
232 case GDK_KP_Multiply
: nCode
= KEY_MULTIPLY
; break;
234 case GDK_KP_Divide
: nCode
= KEY_DIVIDE
; break;
235 case GDK_period
: nCode
= KEY_POINT
; break;
236 case GDK_decimalpoint
: nCode
= KEY_POINT
; break;
237 case GDK_comma
: nCode
= KEY_COMMA
; break;
238 case GDK_less
: nCode
= KEY_LESS
; break;
239 case GDK_greater
: nCode
= KEY_GREATER
; break;
241 case GDK_equal
: nCode
= KEY_EQUAL
; break;
242 case GDK_Find
: nCode
= KEY_FIND
; break;
243 case GDK_Menu
: nCode
= KEY_CONTEXTMENU
;break;
244 case GDK_Help
: nCode
= KEY_HELP
; break;
245 case GDK_Undo
: nCode
= KEY_UNDO
; break;
246 case GDK_Redo
: nCode
= KEY_REPEAT
; break;
248 case GDK_KP_Separator
: nCode
= KEY_DECIMAL
; break;
249 case GDK_asciitilde
: nCode
= KEY_TILDE
; break;
250 case GDK_leftsinglequotemark
:
251 case GDK_quoteleft
: nCode
= KEY_QUOTELEFT
; break;
252 case GDK_bracketleft
: nCode
= KEY_BRACKETLEFT
; break;
253 case GDK_bracketright
: nCode
= KEY_BRACKETRIGHT
; break;
254 case GDK_semicolon
: nCode
= KEY_SEMICOLON
; break;
255 case GDK_quoteright
: nCode
= KEY_QUOTERIGHT
; break;
256 // some special cases, also see saldisp.cxx
257 // - - - - - - - - - - - - - Apollo - - - - - - - - - - - - - 0x1000
258 case 0x1000FF02: // apXK_Copy
261 case 0x1000FF03: // apXK_Cut
264 case 0x1000FF04: // apXK_Paste
267 case 0x1000FF14: // apXK_Repeat
271 // - - - - - - - - - - - - - - D E C - - - - - - - - - - - - - 0x1000
275 // - - - - - - - - - - - - - - H P - - - - - - - - - - - - - 0x1000
276 case 0x1000FF73: // hpXK_DeleteChar
279 case 0x1000FF74: // hpXK_BackTab
280 case 0x1000FF75: // hpXK_KP_BackTab
283 // - - - - - - - - - - - - - - I B M - - - - - - - - - - - - -
284 // - - - - - - - - - - - - - - O S F - - - - - - - - - - - - - 0x1004
285 case 0x1004FF02: // osfXK_Copy
288 case 0x1004FF03: // osfXK_Cut
291 case 0x1004FF04: // osfXK_Paste
294 case 0x1004FF07: // osfXK_BackTab
297 case 0x1004FF08: // osfXK_BackSpace
298 nCode
= KEY_BACKSPACE
;
300 case 0x1004FF1B: // osfXK_Escape
303 // Up, Down, Left, Right, PageUp, PageDown
304 // - - - - - - - - - - - - - - S C O - - - - - - - - - - - - -
305 // - - - - - - - - - - - - - - S G I - - - - - - - - - - - - - 0x1007
306 // - - - - - - - - - - - - - - S N I - - - - - - - - - - - - -
307 // - - - - - - - - - - - - - - S U N - - - - - - - - - - - - - 0x1005
308 case 0x1005FF10: // SunXK_F36
311 case 0x1005FF11: // SunXK_F37
314 case 0x1005FF70: // SunXK_Props
315 nCode
= KEY_PROPERTIES
;
317 case 0x1005FF71: // SunXK_Front
320 case 0x1005FF72: // SunXK_Copy
323 case 0x1005FF73: // SunXK_Open
326 case 0x1005FF74: // SunXK_Paste
329 case 0x1005FF75: // SunXK_Cut
338 static guint
GetKeyValFor(GdkKeymap
* pKeyMap
, guint16 hardware_keycode
, guint8 group
)
340 guint updated_keyval
= 0;
341 gdk_keymap_translate_keyboard_state(pKeyMap
, hardware_keycode
,
342 (GdkModifierType
)0, group
, &updated_keyval
, NULL
, NULL
, NULL
);
343 return updated_keyval
;
346 // F10 means either KEY_F10 or KEY_MENU, which has to be decided
347 // in the independent part.
351 sal_Unicode nCharCode
;
352 KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
353 KeyAlternate( sal_uInt16 nKey
, sal_Unicode nChar
= 0 ) : nKeyCode( nKey
), nCharCode( nChar
) {}
357 GetAlternateKeyCode( const sal_uInt16 nKeyCode
)
359 KeyAlternate aAlternate
;
363 case KEY_F10
: aAlternate
= KeyAlternate( KEY_MENU
);break;
364 case KEY_F24
: aAlternate
= KeyAlternate( KEY_SUBTRACT
, '-' );break;
370 #if GTK_CHECK_VERSION(3,0,0)
373 /// Decouple SalFrame lifetime from damagetracker lifetime
374 struct DamageTracker
: public basebmp::IBitmapDeviceDamageTracker
376 DamageTracker(GtkSalFrame
& rFrame
) : m_rFrame(rFrame
)
379 virtual ~DamageTracker() {}
381 virtual void damaged(const basegfx::B2IBox
& rDamageRect
) const SAL_OVERRIDE
383 m_rFrame
.damaged(rDamageRect
);
386 GtkSalFrame
& m_rFrame
;
390 static bool dumpframes
= false;
393 void GtkSalFrame::doKeyCallback( guint state
,
395 guint16 hardware_keycode
,
398 sal_Unicode aOrigCode
,
405 aEvent
.mnTime
= time
;
406 aEvent
.mnCharCode
= aOrigCode
;
409 vcl::DeletionListener
aDel( this );
411 #if GTK_CHECK_VERSION(3,0,0)
413 // shift-zero forces a re-draw and event is swallowed
416 fprintf( stderr
, "force widget_queue_draw\n");
417 gtk_widget_queue_draw (m_pWindow
);
420 else if (keyval
== GDK_1
)
422 fprintf( stderr
, "force repaint all\n");
426 else if (keyval
== GDK_2
)
428 dumpframes
= !dumpframes
;
429 fprintf(stderr
, "toggle dump frames to %d\n", dumpframes
);
436 * #i42122# translate all keys with Ctrl and/or Alt to group 0 else
437 * shortcuts (e.g. Ctrl-o) will not work but be inserted by the
440 * #i52338# do this for all keys that the independent part has no key code
443 * fdo#41169 rather than use group 0, detect if there is a group which can
444 * be used to input Latin text and use that if possible
446 aEvent
.mnCode
= GetKeyCode( keyval
);
447 if( aEvent
.mnCode
== 0 )
449 gint best_group
= SAL_MAX_INT32
;
451 // Try and find Latin layout
452 GdkKeymap
* keymap
= gdk_keymap_get_default();
455 if (gdk_keymap_get_entries_for_keyval(keymap
, GDK_A
, &keys
, &n_keys
))
457 // Find the lowest group that supports Latin layout
458 for (gint i
= 0; i
< n_keys
; ++i
)
460 if (keys
[i
].level
!= 0 && keys
[i
].level
!= 1)
462 best_group
= std::min(best_group
, keys
[i
].group
);
469 //Unavailable, go with original group then I suppose
470 if (best_group
== SAL_MAX_INT32
)
473 guint updated_keyval
= GetKeyValFor(keymap
, hardware_keycode
, best_group
);
474 aEvent
.mnCode
= GetKeyCode(updated_keyval
);
477 aEvent
.mnCode
|= GetKeyModCode( state
);
481 bool bHandled
= CallCallback( SALEVENT_KEYINPUT
, &aEvent
);
482 // #i46889# copy AlternatKeyCode handling from generic plugin
485 KeyAlternate aAlternate
= GetAlternateKeyCode( aEvent
.mnCode
);
486 if( aAlternate
.nKeyCode
)
488 aEvent
.mnCode
= aAlternate
.nKeyCode
;
489 if( aAlternate
.nCharCode
)
490 aEvent
.mnCharCode
= aAlternate
.nCharCode
;
491 bHandled
= CallCallback( SALEVENT_KEYINPUT
, &aEvent
);
494 if( bSendRelease
&& ! aDel
.isDeleted() )
496 CallCallback( SALEVENT_KEYUP
, &aEvent
);
500 CallCallback( SALEVENT_KEYUP
, &aEvent
);
503 GtkSalFrame::GraphicsHolder::~GraphicsHolder()
508 GtkSalFrame::GtkSalFrame( SalFrame
* pParent
, sal_uLong nStyle
)
509 : m_nXScreen( getDisplay()->GetDefaultXScreen() )
511 getDisplay()->registerFrame( this );
512 m_bDefaultPos
= true;
513 m_bDefaultSize
= ( (nStyle
& SAL_FRAME_STYLE_SIZEABLE
) && ! pParent
);
514 m_bWindowIsGtkPlug
= false;
515 #if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
516 m_pLastSyncedDbusMenu
= NULL
;
518 Init( pParent
, nStyle
);
521 GtkSalFrame::GtkSalFrame( SystemParentData
* pSysData
)
522 : m_nXScreen( getDisplay()->GetDefaultXScreen() )
524 getDisplay()->registerFrame( this );
525 // permanently ignore errors from our unruly children ...
526 GetGenericData()->ErrorTrapPush();
527 m_bDefaultPos
= true;
528 m_bDefaultSize
= true;
529 #if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
530 m_pLastSyncedDbusMenu
= NULL
;
535 #ifdef ENABLE_GMENU_INTEGRATION
538 gdk_x11_window_set_utf8_property (GdkWindow
*window
,
542 #if !GTK_CHECK_VERSION(3,0,0)
543 GdkDisplay
* display
= gdk_window_get_display (window
);
547 XChangeProperty (GDK_DISPLAY_XDISPLAY (display
),
548 GDK_WINDOW_XID (window
),
549 gdk_x11_get_xatom_by_name_for_display (display
, name
),
550 gdk_x11_get_xatom_by_name_for_display (display
, "UTF8_STRING"), 8,
551 PropModeReplace
, reinterpret_cast<guchar
const *>(value
), strlen (value
));
555 XDeleteProperty (GDK_DISPLAY_XDISPLAY (display
),
556 GDK_WINDOW_XID (window
),
557 gdk_x11_get_xatom_by_name_for_display (display
, name
));
562 // AppMenu watch functions.
564 static void ObjectDestroyedNotify( gpointer data
)
567 g_object_unref( data
);
571 #if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
572 void GtkSalFrame::EnsureDbusMenuSynced()
574 GtkSalMenu
* pSalMenu
= static_cast<GtkSalMenu
*>(GetMenu());
575 if(m_pLastSyncedDbusMenu
!= pSalMenu
) {
576 m_pLastSyncedDbusMenu
= pSalMenu
;
577 static_cast<GtkSalMenu
*>(pSalMenu
)->Activate();
582 static void hud_activated( gboolean hud_active
, gpointer user_data
)
586 SolarMutexGuard aGuard
;
587 GtkSalFrame
* pSalFrame
= static_cast< GtkSalFrame
* >( user_data
);
588 GtkSalMenu
* pSalMenu
= reinterpret_cast< GtkSalMenu
* >( pSalFrame
->GetMenu() );
591 pSalMenu
->UpdateFull();
595 static void activate_uno(GSimpleAction
*action
, GVariant
*, gpointer
)
597 uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
599 uno::Reference
< css::frame::XDesktop2
> xDesktop
= css::frame::Desktop::create( xContext
);
601 uno::Reference
< css::frame::XFrame
> xFrame(xDesktop
->getActiveFrame());
603 xFrame
= uno::Reference
< css::frame::XFrame
>(xDesktop
, uno::UNO_QUERY
);
608 uno::Reference
< css::frame::XDispatchProvider
> xDispatchProvider(xFrame
, uno::UNO_QUERY
);
609 if (!xDispatchProvider
.is())
612 gchar
*strval
= NULL
;
613 g_object_get(action
, "name", &strval
, NULL
);
617 if (strcmp(strval
, "New") == 0)
619 uno::Reference
<frame::XModuleManager2
> xModuleManager(frame::ModuleManager::create(xContext
));
620 OUString
aModuleId(xModuleManager
->identify(xFrame
));
621 if (aModuleId
.isEmpty())
624 comphelper::SequenceAsHashMap
lModuleDescription(xModuleManager
->getByName(aModuleId
));
625 OUString sFactoryService
;
626 lModuleDescription
[OUString("ooSetupFactoryEmptyDocumentURL")] >>= sFactoryService
;
627 if (sFactoryService
.isEmpty())
630 uno::Sequence
< css::beans::PropertyValue
> args(0);
631 xDesktop
->loadComponentFromURL(sFactoryService
, OUString("_blank"), 0, args
);
635 OUString
sCommand(".uno:");
636 sCommand
+= OUString(strval
, strlen(strval
), RTL_TEXTENCODING_UTF8
);
639 css::util::URL aCommand
;
640 aCommand
.Complete
= sCommand
;
641 uno::Reference
< css::util::XURLTransformer
> xParser
= css::util::URLTransformer::create(xContext
);
642 xParser
->parseStrict(aCommand
);
644 uno::Reference
< css::frame::XDispatch
> xDisp
= xDispatchProvider
->queryDispatch(aCommand
, OUString(), 0);
649 xDisp
->dispatch(aCommand
, css::uno::Sequence
< css::beans::PropertyValue
>());
652 static const GActionEntry app_entries
[] = {
653 { "OptionsTreeDialog", activate_uno
, NULL
, NULL
, NULL
, {0} },
654 { "About", activate_uno
, NULL
, NULL
, NULL
, {0} },
655 { "HelpIndex", activate_uno
, NULL
, NULL
, NULL
, {0} },
656 { "Quit", activate_uno
, NULL
, NULL
, NULL
, {0} },
657 { "New", activate_uno
, NULL
, NULL
, NULL
, {0} }
660 gboolean
ensure_dbus_setup( gpointer data
)
662 GtkSalFrame
* pSalFrame
= static_cast< GtkSalFrame
* >( data
);
663 GdkWindow
* gdkWindow
= widget_get_window( pSalFrame
->getWindow() );
665 if ( gdkWindow
!= NULL
&& g_object_get_data( G_OBJECT( gdkWindow
), "g-lo-menubar" ) == NULL
)
667 // Get a DBus session connection.
669 pSessionBus
= g_bus_get_sync (G_BUS_TYPE_SESSION
, NULL
, NULL
);
673 // Create menu model and action group attached to this frame.
674 GMenuModel
* pMenuModel
= G_MENU_MODEL( g_lo_menu_new() );
675 GActionGroup
* pActionGroup
= reinterpret_cast<GActionGroup
*>(g_lo_action_group_new( static_cast< gpointer
>( pSalFrame
) ));
677 // Generate menu paths.
678 ::Window windowId
= GDK_WINDOW_XID( gdkWindow
);
679 gchar
* aDBusWindowPath
= g_strdup_printf( "/org/libreoffice/window/%lu", windowId
);
680 gchar
* aDBusMenubarPath
= g_strdup_printf( "/org/libreoffice/window/%lu/menus/menubar", windowId
);
682 // Set window properties.
683 g_object_set_data_full( G_OBJECT( gdkWindow
), "g-lo-menubar", pMenuModel
, ObjectDestroyedNotify
);
684 g_object_set_data_full( G_OBJECT( gdkWindow
), "g-lo-action-group", pActionGroup
, ObjectDestroyedNotify
);
686 gdk_x11_window_set_utf8_property( gdkWindow
, "_GTK_APPLICATION_ID", "org.libreoffice" );
687 gdk_x11_window_set_utf8_property( gdkWindow
, "_GTK_UNIQUE_BUS_NAME", g_dbus_connection_get_unique_name( pSessionBus
) );
688 gdk_x11_window_set_utf8_property( gdkWindow
, "_GTK_APPLICATION_OBJECT_PATH", "/org/libreoffice" );
689 gdk_x11_window_set_utf8_property( gdkWindow
, "_GTK_WINDOW_OBJECT_PATH", aDBusWindowPath
);
690 gdk_x11_window_set_utf8_property( gdkWindow
, "_GTK_MENUBAR_OBJECT_PATH", aDBusMenubarPath
);
692 // Publish the menu model and the action group.
693 SAL_INFO("vcl.unity", "exporting menu model at " << pMenuModel
<< " for window " << windowId
);
694 pSalFrame
->m_nMenuExportId
= g_dbus_connection_export_menu_model (pSessionBus
, aDBusMenubarPath
, pMenuModel
, NULL
);
695 SAL_INFO("vcl.unity", "exporting action group at " << pActionGroup
<< " for window " << windowId
);
696 pSalFrame
->m_nActionGroupExportId
= g_dbus_connection_export_action_group( pSessionBus
, aDBusWindowPath
, pActionGroup
, NULL
);
697 pSalFrame
->m_nHudAwarenessId
= hud_awareness_register( pSessionBus
, aDBusMenubarPath
, hud_activated
, pSalFrame
, NULL
, NULL
);
699 // fdo#70885 we don't want app menu under Unity
700 bool bDesktopIsUnity
= (SalGetDesktopEnvironment() == "UNITY");
702 if (!bDesktopIsUnity
)
703 gdk_x11_window_set_utf8_property( gdkWindow
, "_GTK_APP_MENU_OBJECT_PATH", "/org/libreoffice/menus/appmenu" );
705 //app menu, to-do translations, block normal menus when active, honor use appmenu settings
706 ResMgr
* pMgr
= ImplGetResMgr();
707 if( pMgr
&& !bDesktopIsUnity
)
709 GMenu
*menu
= g_menu_new ();
712 GMenu
*firstsubmenu
= g_menu_new ();
714 OString
sNew(OUStringToOString(ResId(SV_BUTTONTEXT_NEW
, *pMgr
).toString(),
715 RTL_TEXTENCODING_UTF8
).replaceFirst("~", "_"));
717 item
= g_menu_item_new(sNew
.getStr(), "app.New");
718 g_menu_append_item( firstsubmenu
, item
);
719 g_object_unref(item
);
721 g_menu_append_section( menu
, NULL
, G_MENU_MODEL(firstsubmenu
));
722 g_object_unref(firstsubmenu
);
724 GMenu
*secondsubmenu
= g_menu_new ();
726 OString
sPreferences(OUStringToOString(ResId(SV_STDTEXT_PREFERENCES
, *pMgr
).toString(),
727 RTL_TEXTENCODING_UTF8
).replaceFirst("~", "_"));
729 item
= g_menu_item_new(sPreferences
.getStr(), "app.OptionsTreeDialog");
730 g_menu_append_item( secondsubmenu
, item
);
731 g_object_unref(item
);
733 g_menu_append_section( menu
, NULL
, G_MENU_MODEL(secondsubmenu
));
734 g_object_unref(secondsubmenu
);
736 GMenu
*thirdsubmenu
= g_menu_new ();
738 OString
sHelp(OUStringToOString(ResId(SV_BUTTONTEXT_HELP
, *pMgr
).toString(),
739 RTL_TEXTENCODING_UTF8
).replaceFirst("~", "_"));
741 item
= g_menu_item_new(sHelp
.getStr(), "app.HelpIndex");
742 g_menu_append_item( thirdsubmenu
, item
);
743 g_object_unref(item
);
745 OString
sAbout(OUStringToOString(ResId(SV_STDTEXT_ABOUT
, *pMgr
).toString(),
746 RTL_TEXTENCODING_UTF8
).replaceFirst("~", "_"));
748 item
= g_menu_item_new(sAbout
.getStr(), "app.About");
749 g_menu_append_item( thirdsubmenu
, item
);
750 g_object_unref(item
);
752 OString
sQuit(OUStringToOString(ResId(SV_MENU_MAC_QUITAPP
, *pMgr
).toString(),
753 RTL_TEXTENCODING_UTF8
).replaceFirst("~", "_"));
755 item
= g_menu_item_new(sQuit
.getStr(), "app.Quit");
756 g_menu_append_item( thirdsubmenu
, item
);
757 g_object_unref(item
);
758 g_menu_append_section( menu
, NULL
, G_MENU_MODEL(thirdsubmenu
));
759 g_object_unref(thirdsubmenu
);
761 GSimpleActionGroup
*group
= g_simple_action_group_new ();
762 #if GLIB_CHECK_VERSION(2,38,0) // g_simple_action_group_add_entries is deprecated since 2.38
763 g_action_map_add_action_entries (G_ACTION_MAP (group
), app_entries
, G_N_ELEMENTS (app_entries
), NULL
);
765 g_simple_action_group_add_entries (group
, app_entries
, G_N_ELEMENTS (app_entries
), NULL
);
767 GActionGroup
* pAppActionGroup
= G_ACTION_GROUP(group
);
769 pSalFrame
->m_nAppActionGroupExportId
= g_dbus_connection_export_action_group( pSessionBus
, "/org/libreoffice", pAppActionGroup
, NULL
);
770 g_object_unref(pAppActionGroup
);
771 pSalFrame
->m_nAppMenuExportId
= g_dbus_connection_export_menu_model (pSessionBus
, "/org/libreoffice/menus/appmenu", G_MENU_MODEL (menu
), NULL
);
772 g_object_unref(menu
);
775 g_free( aDBusMenubarPath
);
776 g_free( aDBusWindowPath
);
782 void on_registrar_available( GDBusConnection
* /*connection*/,
783 const gchar
* /*name*/,
784 const gchar
* /*name_owner*/,
787 SolarMutexGuard aGuard
;
789 GtkSalFrame
* pSalFrame
= static_cast< GtkSalFrame
* >( user_data
);
791 SalMenu
* pSalMenu
= pSalFrame
->GetMenu();
793 if ( pSalMenu
!= NULL
)
795 GtkSalMenu
* pGtkSalMenu
= static_cast<GtkSalMenu
*>(pSalMenu
);
796 pGtkSalMenu
->Display( true );
797 pGtkSalMenu
->UpdateFull();
801 // This is called when the registrar becomes unavailable. It shows the menubar.
802 void on_registrar_unavailable( GDBusConnection
* /*connection*/,
803 const gchar
* /*name*/,
806 SolarMutexGuard aGuard
;
808 SAL_INFO("vcl.unity", "on_registrar_unavailable");
810 //pSessionBus = NULL;
811 GtkSalFrame
* pSalFrame
= static_cast< GtkSalFrame
* >( user_data
);
813 SalMenu
* pSalMenu
= pSalFrame
->GetMenu();
816 GtkSalMenu
* pGtkSalMenu
= static_cast< GtkSalMenu
* >( pSalMenu
);
817 pGtkSalMenu
->Display( false );
822 void GtkSalFrame::EnsureAppMenuWatch()
824 #ifdef ENABLE_GMENU_INTEGRATION
827 // Get a DBus session connection.
828 if ( pSessionBus
== NULL
)
830 pSessionBus
= g_bus_get_sync( G_BUS_TYPE_SESSION
, NULL
, NULL
);
832 if ( pSessionBus
== NULL
)
836 // Publish the menu only if AppMenu registrar is available.
837 m_nWatcherId
= g_bus_watch_name_on_connection( pSessionBus
,
838 "com.canonical.AppMenu.Registrar",
839 G_BUS_NAME_WATCHER_FLAGS_NONE
,
840 on_registrar_available
,
841 on_registrar_unavailable
,
842 static_cast<GtkSalFrame
*>(this),
846 //ensure_dbus_setup( this );
848 (void) this; // loplugin:staticmethods
852 void GtkSalFrame::InvalidateGraphics()
854 for (unsigned int i
= 0; i
< SAL_N_ELEMENTS(m_aGraphics
); ++i
)
856 if( !m_aGraphics
[i
].pGraphics
)
858 #if !GTK_CHECK_VERSION(3,0,0)
859 m_aGraphics
[i
].pGraphics
->SetDrawable( None
, m_nXScreen
);
860 m_aGraphics
[i
].pGraphics
->SetWindow(NULL
);
862 m_aGraphics
[i
].bInUse
= false;
866 GtkSalFrame::~GtkSalFrame()
868 InvalidateGraphics();
871 m_pParent
->m_aChildren
.remove( this );
873 getDisplay()->deregisterFrame( this );
877 #if GTK_CHECK_VERSION(3,0,0)
878 cairo_region_destroy( m_pRegion
);
880 gdk_region_destroy( m_pRegion
);
884 #if !GTK_CHECK_VERSION(3,0,0)
885 if( m_hBackgroundPixmap
)
887 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
888 widget_get_xid(m_pWindow
),
890 XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap
);
897 if( m_pFixedContainer
)
898 gtk_widget_destroy( GTK_WIDGET( m_pFixedContainer
) );
900 SolarMutexGuard aGuard
;
901 #if defined ENABLE_GMENU_INTEGRATION
903 g_bus_unwatch_name(m_nWatcherId
);
907 g_object_set_data( G_OBJECT( m_pWindow
), "SalFrame", NULL
);
909 #if defined ENABLE_GMENU_INTEGRATION
912 if ( m_nHudAwarenessId
)
913 hud_awareness_unregister( pSessionBus
, m_nHudAwarenessId
);
914 if ( m_nMenuExportId
)
915 g_dbus_connection_unexport_menu_model( pSessionBus
, m_nMenuExportId
);
916 if ( m_nAppMenuExportId
)
917 g_dbus_connection_unexport_menu_model( pSessionBus
, m_nAppMenuExportId
);
918 if ( m_nActionGroupExportId
)
919 g_dbus_connection_unexport_action_group( pSessionBus
, m_nActionGroupExportId
);
920 if ( m_nAppActionGroupExportId
)
921 g_dbus_connection_unexport_action_group( pSessionBus
, m_nAppActionGroupExportId
);
924 gtk_widget_destroy( m_pWindow
);
927 if( m_pForeignParent
)
928 g_object_unref( G_OBJECT( m_pForeignParent
) );
929 if( m_pForeignTopLevel
)
930 g_object_unref( G_OBJECT( m_pForeignTopLevel
) );
933 void GtkSalFrame::moveWindow( long nX
, long nY
)
935 if( isChild( false, true ) )
938 gtk_fixed_move( m_pParent
->getFixedContainer(),
940 nX
- m_pParent
->maGeometry
.nX
, nY
- m_pParent
->maGeometry
.nY
);
943 gtk_window_move( GTK_WINDOW(m_pWindow
), nX
, nY
);
946 void GtkSalFrame::widget_set_size_request(long nWidth
, long nHeight
)
948 gint nOrigwidth
, nOrigheight
;
949 gtk_window_get_size(GTK_WINDOW(m_pWindow
), &nOrigwidth
, &nOrigheight
);
950 #if !GTK_CHECK_VERSION(3,0,0)
951 if (nWidth
> nOrigwidth
|| nHeight
> nOrigheight
)
953 m_bPaintsBlocked
= true;
956 gtk_widget_set_size_request(m_pWindow
, nWidth
, nHeight
);
959 void GtkSalFrame::window_resize(long nWidth
, long nHeight
)
961 gint nOrigwidth
, nOrigheight
;
962 gtk_window_get_size(GTK_WINDOW(m_pWindow
), &nOrigwidth
, &nOrigheight
);
963 #if !GTK_CHECK_VERSION(3,0,0)
964 if (nWidth
> nOrigwidth
|| nHeight
> nOrigheight
)
966 m_bPaintsBlocked
= true;
969 gtk_window_resize(GTK_WINDOW(m_pWindow
), nWidth
, nHeight
);
972 void GtkSalFrame::resizeWindow( long nWidth
, long nHeight
)
974 if( isChild( false, true ) )
976 widget_set_size_request(nWidth
, nHeight
);
978 else if( ! isChild( true, false ) )
979 window_resize(nWidth
, nHeight
);
982 #if GTK_CHECK_VERSION(3,2,0)
985 ooo_fixed_class_init(GtkFixedClass
*klass
)
987 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
988 widget_class
->get_accessible
= ooo_fixed_get_accessible
;
994 * Always use a sub-class of GtkFixed we can tag for a11y. This allows us to
995 * utilize GAIL for the toplevel window and toolkit implementation incl.
996 * key event listener support ..
1000 ooo_fixed_get_type()
1002 static GType type
= 0;
1005 static const GTypeInfo tinfo
=
1007 sizeof (GtkFixedClass
),
1008 nullptr, /* base init */
1009 nullptr, /* base finalize */
1010 #if GTK_CHECK_VERSION(3,2,0)
1011 reinterpret_cast<GClassInitFunc
>(ooo_fixed_class_init
), /* class init */
1013 nullptr, /* class init */
1015 nullptr, /* class finalize */
1016 NULL
, /* class data */
1017 sizeof (GtkFixed
), /* instance size */
1018 0, /* nb preallocs */
1019 (GInstanceInitFunc
) NULL
, /* instance init */
1020 NULL
/* value table */
1023 type
= g_type_register_static( GTK_TYPE_FIXED
, "OOoFixed",
1024 &tinfo
, (GTypeFlags
) 0);
1030 void GtkSalFrame::updateScreenNumber()
1033 GdkScreen
*pScreen
= gtk_widget_get_screen( m_pWindow
);
1035 nScreen
= getDisplay()->getSystem()->getScreenMonitorIdx( pScreen
, maGeometry
.nX
, maGeometry
.nY
);
1036 maGeometry
.nDisplayScreenNumber
= nScreen
;
1039 void GtkSalFrame::InitCommon()
1042 g_signal_connect( G_OBJECT(m_pWindow
), "style-set", G_CALLBACK(signalStyleSet
), this );
1043 g_signal_connect( G_OBJECT(m_pWindow
), "button-press-event", G_CALLBACK(signalButton
), this );
1044 g_signal_connect( G_OBJECT(m_pWindow
), "button-release-event", G_CALLBACK(signalButton
), this );
1045 #if GTK_CHECK_VERSION(3,0,0)
1046 g_signal_connect( G_OBJECT(m_pWindow
), "draw", G_CALLBACK(signalDraw
), this );
1047 g_signal_connect( G_OBJECT(m_pWindow
), "size-allocate", G_CALLBACK(sizeAllocated
), this );
1048 // g_signal_connect( G_OBJECT(m_pWindow), "state-flags-changed", G_CALLBACK(signalFlagsChanged), this );
1049 #if GTK_CHECK_VERSION(3,14,0)
1050 GtkGesture
*pSwipe
= gtk_gesture_swipe_new(m_pWindow
);
1051 g_signal_connect(pSwipe
, "swipe", G_CALLBACK(gestureSwipe
), this);
1052 gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER (pSwipe
), GTK_PHASE_TARGET
);
1053 g_object_weak_ref(G_OBJECT(m_pWindow
), reinterpret_cast<GWeakNotify
>(g_object_unref
), pSwipe
);
1055 GtkGesture
*pLongPress
= gtk_gesture_long_press_new(m_pWindow
);
1056 g_signal_connect(pLongPress
, "pressed", G_CALLBACK(gestureLongPress
), this);
1057 gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER (pLongPress
), GTK_PHASE_TARGET
);
1058 g_object_weak_ref(G_OBJECT(m_pWindow
), reinterpret_cast<GWeakNotify
>(g_object_unref
), pLongPress
);
1063 g_signal_connect( G_OBJECT(m_pWindow
), "expose-event", G_CALLBACK(signalExpose
), this );
1065 g_signal_connect( G_OBJECT(m_pWindow
), "focus-in-event", G_CALLBACK(signalFocus
), this );
1066 g_signal_connect( G_OBJECT(m_pWindow
), "focus-out-event", G_CALLBACK(signalFocus
), this );
1067 g_signal_connect( G_OBJECT(m_pWindow
), "map-event", G_CALLBACK(signalMap
), this );
1068 g_signal_connect( G_OBJECT(m_pWindow
), "unmap-event", G_CALLBACK(signalUnmap
), this );
1069 g_signal_connect( G_OBJECT(m_pWindow
), "configure-event", G_CALLBACK(signalConfigure
), this );
1070 g_signal_connect( G_OBJECT(m_pWindow
), "motion-notify-event", G_CALLBACK(signalMotion
), this );
1071 g_signal_connect( G_OBJECT(m_pWindow
), "key-press-event", G_CALLBACK(signalKey
), this );
1072 g_signal_connect( G_OBJECT(m_pWindow
), "key-release-event", G_CALLBACK(signalKey
), this );
1073 g_signal_connect( G_OBJECT(m_pWindow
), "delete-event", G_CALLBACK(signalDelete
), this );
1074 g_signal_connect( G_OBJECT(m_pWindow
), "window-state-event", G_CALLBACK(signalWindowState
), this );
1075 g_signal_connect( G_OBJECT(m_pWindow
), "scroll-event", G_CALLBACK(signalScroll
), this );
1076 g_signal_connect( G_OBJECT(m_pWindow
), "leave-notify-event", G_CALLBACK(signalCrossing
), this );
1077 g_signal_connect( G_OBJECT(m_pWindow
), "enter-notify-event", G_CALLBACK(signalCrossing
), this );
1078 g_signal_connect( G_OBJECT(m_pWindow
), "visibility-notify-event", G_CALLBACK(signalVisibility
), this );
1079 g_signal_connect( G_OBJECT(m_pWindow
), "destroy", G_CALLBACK(signalDestroy
), this );
1082 m_pCurrentCursor
= NULL
;
1083 m_nKeyModifiers
= 0;
1084 m_bFullscreen
= false;
1085 m_bSpanMonitorsWhenFullscreen
= false;
1086 m_nState
= GDK_WINDOW_STATE_WITHDRAWN
;
1087 m_nVisibility
= GDK_VISIBILITY_FULLY_OBSCURED
;
1088 m_bSendModChangeOnRelease
= false;
1089 m_pIMHandler
= NULL
;
1090 m_hBackgroundPixmap
= None
;
1091 m_nSavedScreenSaverTimeout
= 0;
1095 m_ePointerStyle
= static_cast<PointerStyle
>(0xffff);
1096 m_bSetFocusOnMap
= false;
1099 m_nMenuExportId
= 0;
1100 m_nAppMenuExportId
= 0;
1101 m_nActionGroupExportId
= 0;
1102 m_nAppActionGroupExportId
= 0;
1103 m_nHudAwarenessId
= 0;
1105 gtk_widget_set_app_paintable( m_pWindow
, TRUE
);
1106 /*non-X11 displays won't show anything at all without double-buffering
1108 if (GDK_IS_X11_DISPLAY(getGdkDisplay()))
1109 gtk_widget_set_double_buffered( m_pWindow
, FALSE
);
1110 gtk_widget_set_redraw_on_allocate( m_pWindow
, FALSE
);
1112 gtk_widget_add_events( m_pWindow
,
1113 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
|
1114 GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK
|
1115 GDK_VISIBILITY_NOTIFY_MASK
| GDK_SCROLL_MASK
1118 // add the fixed container child,
1119 // fixed is needed since we have to position plugin windows
1120 m_pFixedContainer
= GTK_FIXED(g_object_new( ooo_fixed_get_type(), NULL
));
1121 gtk_container_add( GTK_CONTAINER(m_pWindow
), GTK_WIDGET(m_pFixedContainer
) );
1124 gtk_widget_show( GTK_WIDGET(m_pFixedContainer
) );
1126 // realize the window, we need an XWindow id
1127 gtk_widget_realize( m_pWindow
);
1130 m_aSystemData
.nSize
= sizeof( SystemEnvData
);
1131 #if !GTK_CHECK_VERSION(3,0,0)
1132 GtkSalDisplay
* pDisp
= GetGtkSalData()->GetGtkDisplay();
1133 m_aSystemData
.pDisplay
= pDisp
->GetDisplay();
1134 m_aSystemData
.pVisual
= pDisp
->GetVisual( m_nXScreen
).GetVisual();
1135 m_aSystemData
.nDepth
= pDisp
->GetVisual( m_nXScreen
).GetDepth();
1136 m_aSystemData
.aColormap
= pDisp
->GetColormap( m_nXScreen
).GetXColormap();
1137 m_aSystemData
.aWindow
= widget_get_xid(m_pWindow
);
1138 m_aSystemData
.aShellWindow
= m_aSystemData
.aWindow
;
1140 static int nWindow
= 0;
1141 m_aSystemData
.aWindow
= nWindow
;
1142 m_aSystemData
.aShellWindow
= nWindow
;
1145 m_aSystemData
.pSalFrame
= this;
1146 m_aSystemData
.pWidget
= m_pWindow
;
1147 m_aSystemData
.nScreen
= m_nXScreen
.getXScreen();
1148 m_aSystemData
.pAppContext
= NULL
;
1149 m_aSystemData
.pShellWidget
= m_aSystemData
.pWidget
;
1151 // fake an initial geometry, gets updated via configure event or SetPosSize
1152 if( m_bDefaultPos
|| m_bDefaultSize
)
1154 Size aDefSize
= calcDefaultSize();
1157 maGeometry
.nWidth
= aDefSize
.Width();
1158 maGeometry
.nHeight
= aDefSize
.Height();
1162 maGeometry
.nTopDecoration
= m_pParent
->maGeometry
.nTopDecoration
;
1163 maGeometry
.nBottomDecoration
= m_pParent
->maGeometry
.nBottomDecoration
;
1164 maGeometry
.nLeftDecoration
= m_pParent
->maGeometry
.nLeftDecoration
;
1165 maGeometry
.nRightDecoration
= m_pParent
->maGeometry
.nRightDecoration
;
1169 maGeometry
.nTopDecoration
= 0;
1170 maGeometry
.nBottomDecoration
= 0;
1171 maGeometry
.nLeftDecoration
= 0;
1172 maGeometry
.nRightDecoration
= 0;
1177 resizeWindow( maGeometry
.nWidth
, maGeometry
.nHeight
);
1178 moveWindow( maGeometry
.nX
, maGeometry
.nY
);
1180 updateScreenNumber();
1184 #if !GTK_CHECK_VERSION(3,0,0)
1185 m_nWorkArea
= pDisp
->getWMAdaptor()->getCurrentWorkArea();
1186 /* #i64117# gtk sets a nice background pixmap
1187 * but we actually don't really want that, so save
1188 * some time on the Xserver as well as prevent
1191 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
1192 widget_get_xid(m_pWindow
),
1193 m_hBackgroundPixmap
);
1197 /* Sadly gtk_window_set_accept_focus exists only since gtk 2.4
1198 * for achieving the same effect we will remove the WM_TAKE_FOCUS
1199 * protocol from the window and set the input hint to false.
1200 * But gtk_window_set_accept_focus needs to be called before
1201 * window realization whereas the removal obviously can only happen
1202 * after realization.
1205 #if !GTK_CHECK_VERSION(3,0,0)
1207 typedef void(*setAcceptFn
)( GtkWindow
*, gboolean
);
1208 static setAcceptFn p_gtk_window_set_accept_focus
= NULL
;
1209 static bool bGetAcceptFocusFn
= true;
1211 typedef void(*setUserTimeFn
)( GdkWindow
*, guint32
);
1212 static setUserTimeFn p_gdk_x11_window_set_user_time
= NULL
;
1213 static bool bGetSetUserTimeFn
= true;
1217 static void lcl_set_accept_focus( GtkWindow
* pWindow
, gboolean bAccept
, bool bBeforeRealize
)
1219 #if !GTK_CHECK_VERSION(3,0,0)
1220 if( bGetAcceptFocusFn
)
1222 bGetAcceptFocusFn
= false;
1223 p_gtk_window_set_accept_focus
= reinterpret_cast<setAcceptFn
>(osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin
, "gtk_window_set_accept_focus" ));
1225 if( p_gtk_window_set_accept_focus
&& bBeforeRealize
)
1226 p_gtk_window_set_accept_focus( pWindow
, bAccept
);
1227 else if( ! bBeforeRealize
)
1229 Display
* pDisplay
= GetGtkSalData()->GetGtkDisplay()->GetDisplay();
1230 ::Window aWindow
= widget_get_xid(GTK_WIDGET(pWindow
));
1231 XWMHints
* pHints
= XGetWMHints( pDisplay
, aWindow
);
1234 pHints
= XAllocWMHints();
1237 pHints
->flags
|= InputHint
;
1238 pHints
->input
= bAccept
? True
: False
;
1239 XSetWMHints( pDisplay
, aWindow
, pHints
);
1242 if (GetGtkSalData()->GetGtkDisplay()->getWMAdaptor()->getWindowManagerName() == "compiz")
1245 /* remove WM_TAKE_FOCUS protocol; this would usually be the
1246 * right thing, but gtk handles it internally whereas we
1247 * want to handle it ourselves (as to sometimes not get
1250 Atom
* pProtocols
= NULL
;
1252 XGetWMProtocols( pDisplay
,
1254 &pProtocols
, &nProtocols
);
1258 Atom nTakeFocus
= XInternAtom( pDisplay
, "WM_TAKE_FOCUS", True
);
1261 for( int i
= 0; i
< nProtocols
; i
++ )
1263 if( pProtocols
[i
] == nTakeFocus
)
1265 for( int n
= i
; n
< nProtocols
-1; n
++ )
1266 pProtocols
[n
] = pProtocols
[n
+1];
1274 XSetWMProtocols( pDisplay
, aWindow
, pProtocols
, nProtocols
);
1275 XFree( pProtocols
);
1279 gtk_window_set_accept_focus(pWindow
, bAccept
);
1280 (void)bBeforeRealize
;
1284 #if !GTK_CHECK_VERSION(3,0,0)
1285 static void lcl_set_user_time( GtkWindow
* i_pWindow
, guint32 i_nTime
)
1287 if( bGetSetUserTimeFn
)
1289 bGetSetUserTimeFn
= false;
1290 p_gdk_x11_window_set_user_time
= reinterpret_cast<setUserTimeFn
>(osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin
, "gdk_x11_window_set_user_time" ));
1293 if( p_gdk_x11_window_set_user_time
)
1295 GdkWindow
* pWin
= widget_get_window(GTK_WIDGET(i_pWindow
));
1296 if( pWin
) // only if the window is realized.
1298 p_gdk_x11_window_set_user_time( pWin
, i_nTime
);
1304 Display
* pDisplay
= GetGtkSalData()->GetGtkDisplay()->GetDisplay();
1305 Atom nUserTime
= XInternAtom( pDisplay
, "_NET_WM_USER_TIME", True
);
1308 XChangeProperty( pDisplay
, widget_get_xid(GTK_WIDGET(i_pWindow
)),
1309 nUserTime
, XA_CARDINAL
, 32,
1310 PropModeReplace
, reinterpret_cast<unsigned char*>(&i_nTime
), 1 );
1316 GtkSalFrame
*GtkSalFrame::getFromWindow( GtkWindow
*pWindow
)
1318 return static_cast<GtkSalFrame
*>(g_object_get_data( G_OBJECT( pWindow
), "SalFrame" ));
1321 void GtkSalFrame::Init( SalFrame
* pParent
, sal_uLong nStyle
)
1323 if( nStyle
& SAL_FRAME_STYLE_DEFAULT
) // ensure default style
1325 nStyle
|= SAL_FRAME_STYLE_MOVEABLE
| SAL_FRAME_STYLE_SIZEABLE
| SAL_FRAME_STYLE_CLOSEABLE
;
1326 nStyle
&= ~SAL_FRAME_STYLE_FLOAT
;
1329 m_pParent
= static_cast<GtkSalFrame
*>(pParent
);
1330 m_pForeignParent
= NULL
;
1331 m_aForeignParentWindow
= None
;
1332 m_pForeignTopLevel
= NULL
;
1333 m_aForeignTopLevelWindow
= None
;
1336 GtkWindowType eWinType
= ( (nStyle
& SAL_FRAME_STYLE_FLOAT
) &&
1337 ! (nStyle
& (SAL_FRAME_STYLE_OWNERDRAWDECORATION
|
1338 SAL_FRAME_STYLE_FLOAT_FOCUSABLE
))
1340 ? GTK_WINDOW_POPUP
: GTK_WINDOW_TOPLEVEL
;
1342 if( nStyle
& SAL_FRAME_STYLE_SYSTEMCHILD
)
1344 m_pWindow
= gtk_event_box_new();
1347 // insert into container
1348 gtk_fixed_put( m_pParent
->getFixedContainer(),
1355 m_pWindow
= gtk_widget_new( GTK_TYPE_WINDOW
, "type", eWinType
,
1356 "visible", FALSE
, NULL
);
1358 g_object_set_data( G_OBJECT( m_pWindow
), "SalFrame", this );
1359 g_object_set_data( G_OBJECT( m_pWindow
), "libo-version", (gpointer
)LIBO_VERSION_DOTTED
);
1361 // force wm class hint
1364 m_sWMClass
= m_pParent
->m_sWMClass
;
1365 SetExtendedFrameStyle( 0 );
1367 if( m_pParent
&& m_pParent
->m_pWindow
&& ! isChild() )
1368 gtk_window_set_screen( GTK_WINDOW(m_pWindow
), gtk_window_get_screen( GTK_WINDOW(m_pParent
->m_pWindow
) ) );
1371 bool bDecoHandling
=
1373 ( ! (nStyle
& SAL_FRAME_STYLE_FLOAT
) ||
1374 (nStyle
& (SAL_FRAME_STYLE_OWNERDRAWDECORATION
|SAL_FRAME_STYLE_FLOAT_FOCUSABLE
) ) );
1378 GdkWindowTypeHint eType
= GDK_WINDOW_TYPE_HINT_NORMAL
;
1379 if( (nStyle
& SAL_FRAME_STYLE_DIALOG
) && m_pParent
!= 0 )
1380 eType
= GDK_WINDOW_TYPE_HINT_DIALOG
;
1381 if( (nStyle
& SAL_FRAME_STYLE_INTRO
) )
1383 gtk_window_set_role( GTK_WINDOW(m_pWindow
), "splashscreen" );
1384 eType
= GDK_WINDOW_TYPE_HINT_SPLASHSCREEN
;
1386 else if( (nStyle
& SAL_FRAME_STYLE_TOOLWINDOW
) )
1388 eType
= GDK_WINDOW_TYPE_HINT_UTILITY
;
1389 gtk_window_set_skip_taskbar_hint( GTK_WINDOW(m_pWindow
), true );
1391 else if( (nStyle
& SAL_FRAME_STYLE_OWNERDRAWDECORATION
) )
1393 eType
= GDK_WINDOW_TYPE_HINT_TOOLBAR
;
1394 lcl_set_accept_focus( GTK_WINDOW(m_pWindow
), false, true );
1396 else if( (nStyle
& SAL_FRAME_STYLE_FLOAT_FOCUSABLE
) )
1398 eType
= GDK_WINDOW_TYPE_HINT_UTILITY
;
1400 #if !GTK_CHECK_VERSION(3,0,0)
1401 if( (nStyle
& SAL_FRAME_STYLE_PARTIAL_FULLSCREEN
)
1402 && getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
1404 eType
= GDK_WINDOW_TYPE_HINT_TOOLBAR
;
1405 gtk_window_set_keep_above( GTK_WINDOW(m_pWindow
), true );
1408 gtk_window_set_type_hint( GTK_WINDOW(m_pWindow
), eType
);
1409 gtk_window_set_gravity( GTK_WINDOW(m_pWindow
), GDK_GRAVITY_STATIC
);
1410 if( m_pParent
&& ! (m_pParent
->m_nStyle
& SAL_FRAME_STYLE_PLUG
) )
1411 gtk_window_set_transient_for( GTK_WINDOW(m_pWindow
), GTK_WINDOW(m_pParent
->m_pWindow
) );
1413 else if( (nStyle
& SAL_FRAME_STYLE_FLOAT
) )
1415 gtk_window_set_type_hint( GTK_WINDOW(m_pWindow
), GDK_WINDOW_TYPE_HINT_UTILITY
);
1418 m_pParent
->m_aChildren
.push_back( this );
1422 #if !GTK_CHECK_VERSION(3,0,0)
1423 if( eWinType
== GTK_WINDOW_TOPLEVEL
)
1425 #ifdef ENABLE_GMENU_INTEGRATION
1426 // Enable DBus native menu if available.
1427 ensure_dbus_setup( this );
1430 guint32 nUserTime
= 0;
1431 if( (nStyle
& (SAL_FRAME_STYLE_OWNERDRAWDECORATION
|SAL_FRAME_STYLE_TOOLWINDOW
)) == 0 )
1433 nUserTime
= gdk_x11_get_server_time(GTK_WIDGET (m_pWindow
)->window
);
1435 lcl_set_user_time(GTK_WINDOW(m_pWindow
), nUserTime
);
1441 gtk_window_set_resizable( GTK_WINDOW(m_pWindow
), (nStyle
& SAL_FRAME_STYLE_SIZEABLE
) != 0 );
1442 if( ( (nStyle
& (SAL_FRAME_STYLE_OWNERDRAWDECORATION
)) ) )
1443 lcl_set_accept_focus( GTK_WINDOW(m_pWindow
), false, false );
1447 GdkNativeWindow
GtkSalFrame::findTopLevelSystemWindow( GdkNativeWindow aWindow
)
1449 #if !GTK_CHECK_VERSION(3,0,0)
1450 ::Window aRoot
, aParent
;
1451 ::Window
* pChildren
;
1452 unsigned int nChildren
;
1453 bool bBreak
= false;
1458 aParent
= aRoot
= None
;
1459 XQueryTree( getDisplay()->GetDisplay(), aWindow
,
1460 &aRoot
, &aParent
, &pChildren
, &nChildren
);
1462 if( aParent
!= aRoot
)
1465 Atom
* pProps
= XListProperties( getDisplay()->GetDisplay(),
1468 for( int i
= 0; i
< nCount
&& ! bBreak
; ++i
)
1469 bBreak
= (pProps
[i
] == XA_WM_HINTS
);
1472 } while( aParent
!= aRoot
&& ! bBreak
);
1477 //FIXME: no findToplevelSystemWindow
1482 void GtkSalFrame::Init( SystemParentData
* pSysData
)
1485 m_aForeignParentWindow
= (GdkNativeWindow
)pSysData
->aWindow
;
1486 m_pForeignParent
= NULL
;
1487 m_aForeignTopLevelWindow
= findTopLevelSystemWindow( (GdkNativeWindow
)pSysData
->aWindow
);
1488 m_pForeignTopLevel
= gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignTopLevelWindow
);
1489 gdk_window_set_events( m_pForeignTopLevel
, GDK_STRUCTURE_MASK
);
1491 if( pSysData
->nSize
> sizeof(pSysData
->nSize
)+sizeof(pSysData
->aWindow
) && pSysData
->bXEmbedSupport
)
1493 #if GTK_CHECK_VERSION(3,0,0)
1494 m_pWindow
= gtk_plug_new_for_display( getGdkDisplay(), pSysData
->aWindow
);
1496 m_pWindow
= gtk_plug_new( pSysData
->aWindow
);
1498 m_bWindowIsGtkPlug
= true;
1499 widget_set_can_default( m_pWindow
, true );
1500 widget_set_can_focus( m_pWindow
, true );
1501 gtk_widget_set_sensitive( m_pWindow
, true );
1505 m_pWindow
= gtk_window_new( GTK_WINDOW_POPUP
);
1506 m_bWindowIsGtkPlug
= false;
1508 m_nStyle
= SAL_FRAME_STYLE_PLUG
;
1511 m_pForeignParent
= gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignParentWindow
);
1512 gdk_window_set_events( m_pForeignParent
, GDK_STRUCTURE_MASK
);
1514 #if !GTK_CHECK_VERSION(3,0,0)
1516 unsigned int w
, h
, bw
, d
;
1518 XGetGeometry( getDisplay()->GetDisplay(), pSysData
->aWindow
,
1519 &aRoot
, &x_ret
, &y_ret
, &w
, &h
, &bw
, &d
);
1520 maGeometry
.nWidth
= w
;
1521 maGeometry
.nHeight
= h
;
1522 window_resize(w
, h
);
1523 gtk_window_move( GTK_WINDOW(m_pWindow
), 0, 0 );
1524 if( ! m_bWindowIsGtkPlug
)
1526 XReparentWindow( getDisplay()->GetDisplay(),
1527 widget_get_xid(m_pWindow
),
1528 (::Window
)pSysData
->aWindow
,
1532 //FIXME: Handling embedded windows, is going to be fun ...
1536 void GtkSalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode
)
1538 #if !GTK_CHECK_VERSION(3,0,0)
1541 memset( &aEvent
, 0, sizeof(aEvent
) );
1542 aEvent
.xclient
.window
= m_aForeignParentWindow
;
1543 aEvent
.xclient
.type
= ClientMessage
;
1544 aEvent
.xclient
.message_type
= getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED
);
1545 aEvent
.xclient
.format
= 32;
1546 aEvent
.xclient
.data
.l
[0] = i_nTimeCode
? i_nTimeCode
: CurrentTime
;
1547 aEvent
.xclient
.data
.l
[1] = 3; // XEMBED_REQUEST_FOCUS
1548 aEvent
.xclient
.data
.l
[2] = 0;
1549 aEvent
.xclient
.data
.l
[3] = 0;
1550 aEvent
.xclient
.data
.l
[4] = 0;
1552 GetGenericData()->ErrorTrapPush();
1553 XSendEvent( getDisplay()->GetDisplay(),
1554 m_aForeignParentWindow
,
1555 False
, NoEventMask
, &aEvent
);
1556 GetGenericData()->ErrorTrapPop();
1558 (void) this; // loplugin:staticmethods
1560 //FIXME: no askForXEmbedFocus for gtk3 yet
1564 void GtkSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle
)
1566 if( nStyle
!= m_nExtStyle
&& ! isChild() )
1568 m_nExtStyle
= nStyle
;
1573 SalGraphics
* GtkSalFrame::AcquireGraphics()
1577 for( int i
= 0; i
< nMaxGraphics
; i
++ )
1579 if( ! m_aGraphics
[i
].bInUse
)
1581 m_aGraphics
[i
].bInUse
= true;
1582 if( ! m_aGraphics
[i
].pGraphics
)
1584 #if GTK_CHECK_VERSION(3,0,0)
1585 m_aGraphics
[i
].pGraphics
= new GtkSalGraphics( this, m_pWindow
);
1586 if( !m_aFrame
.get() )
1589 TriggerPaintEvent();
1591 m_aGraphics
[i
].pGraphics
->setDevice( m_aFrame
);
1592 #else // common case:
1593 m_aGraphics
[i
].pGraphics
= new GtkSalGraphics( this, m_pWindow
, m_nXScreen
);
1596 return m_aGraphics
[i
].pGraphics
;
1604 void GtkSalFrame::ReleaseGraphics( SalGraphics
* pGraphics
)
1606 for( int i
= 0; i
< nMaxGraphics
; i
++ )
1608 if( m_aGraphics
[i
].pGraphics
== pGraphics
)
1610 m_aGraphics
[i
].bInUse
= false;
1616 bool GtkSalFrame::PostEvent( void* pData
)
1618 getDisplay()->SendInternalEvent( this, pData
);
1622 void GtkSalFrame::SetTitle( const OUString
& rTitle
)
1625 if( m_pWindow
&& ! isChild() )
1626 gtk_window_set_title( GTK_WINDOW(m_pWindow
), OUStringToOString( rTitle
, RTL_TEXTENCODING_UTF8
).getStr() );
1629 static inline sal_uInt8
*
1630 getRow( BitmapBuffer
*pBuffer
, sal_uLong nRow
)
1632 if( BMP_SCANLINE_ADJUSTMENT( pBuffer
->mnFormat
) == BMP_FORMAT_TOP_DOWN
)
1633 return pBuffer
->mpBits
+ nRow
* pBuffer
->mnScanlineSize
;
1635 return pBuffer
->mpBits
+ ( pBuffer
->mnHeight
- nRow
- 1 ) * pBuffer
->mnScanlineSize
;
1639 bitmapToPixbuf( SalBitmap
*pSalBitmap
, SalBitmap
*pSalAlpha
)
1641 g_return_val_if_fail( pSalBitmap
!= NULL
, NULL
);
1642 g_return_val_if_fail( pSalAlpha
!= NULL
, NULL
);
1644 BitmapBuffer
*pBitmap
= pSalBitmap
->AcquireBuffer( BITMAP_READ_ACCESS
);
1645 g_return_val_if_fail( pBitmap
!= NULL
, NULL
);
1646 g_return_val_if_fail( pBitmap
->mnBitCount
== 24 || pBitmap
->mnBitCount
== 32, NULL
);
1648 BitmapBuffer
*pAlpha
= pSalAlpha
->AcquireBuffer( BITMAP_READ_ACCESS
);
1649 g_return_val_if_fail( pAlpha
!= NULL
, NULL
);
1650 g_return_val_if_fail( pAlpha
->mnBitCount
== 8, NULL
);
1652 Size aSize
= pSalBitmap
->GetSize();
1653 g_return_val_if_fail( pSalAlpha
->GetSize() == aSize
, NULL
);
1656 guchar
*pPixbufData
= static_cast<guchar
*>(g_malloc (4 * aSize
.Width() * aSize
.Height() ));
1657 guchar
*pDestData
= pPixbufData
;
1659 for( nY
= 0; nY
< pBitmap
->mnHeight
; nY
++ )
1661 sal_uInt8
*pData
= getRow( pBitmap
, nY
);
1662 sal_uInt8
*pAlphaData
= getRow( pAlpha
, nY
);
1664 for( nX
= 0; nX
< pBitmap
->mnWidth
; nX
++ )
1667 if (pBitmap
->mnFormat
== BMP_FORMAT_24BIT_TC_BGR
)
1669 aColor
= BitmapColor(pData
[2], pData
[1], pData
[0]);
1672 else if (pBitmap
->mnFormat
== BMP_FORMAT_24BIT_TC_RGB
)
1674 aColor
= BitmapColor(pData
[0], pData
[1], pData
[2]);
1679 pBitmap
->maColorMask
.GetColorFor32Bit(aColor
, pData
);
1682 *pDestData
++ = aColor
.GetRed();
1683 *pDestData
++ = aColor
.GetGreen();
1684 *pDestData
++ = aColor
.GetBlue();
1685 *pDestData
++ = 255 - *pAlphaData
++;
1689 pSalBitmap
->ReleaseBuffer( pBitmap
, BITMAP_READ_ACCESS
);
1690 pSalAlpha
->ReleaseBuffer( pAlpha
, BITMAP_READ_ACCESS
);
1692 return gdk_pixbuf_new_from_data( pPixbufData
,
1693 GDK_COLORSPACE_RGB
, true, 8,
1694 aSize
.Width(), aSize
.Height(),
1696 reinterpret_cast<GdkPixbufDestroyNotify
>(g_free
),
1700 void GtkSalFrame::SetIcon( sal_uInt16 nIcon
)
1702 if( (m_nStyle
& (SAL_FRAME_STYLE_PLUG
|SAL_FRAME_STYLE_SYSTEMCHILD
|SAL_FRAME_STYLE_FLOAT
|SAL_FRAME_STYLE_INTRO
|SAL_FRAME_STYLE_OWNERDRAWDECORATION
))
1706 if( !ImplGetResMgr() )
1710 GList
*pIcons
= NULL
;
1712 sal_uInt16 nOffsets
[2] = { SV_ICON_SMALL_START
, SV_ICON_LARGE_START
};
1715 for( nIndex
= 0; nIndex
< sizeof(nOffsets
)/ sizeof(sal_uInt16
); nIndex
++ )
1717 // #i44723# workaround gcc temporary problem
1718 ResId
aResId( nOffsets
[nIndex
] + nIcon
, *ImplGetResMgr() );
1719 BitmapEx
aIcon( aResId
);
1721 // #i81083# convert to 24bit/8bit alpha bitmap
1722 Bitmap aBmp
= aIcon
.GetBitmap();
1723 if( aBmp
.GetBitCount() != 24 || ! aIcon
.IsAlpha() )
1725 if( aBmp
.GetBitCount() != 24 )
1726 aBmp
.Convert( BMP_CONVERSION_24BIT
);
1728 if( ! aIcon
.IsAlpha() )
1730 switch( aIcon
.GetTransparentType() )
1732 case TRANSPARENT_NONE
:
1734 sal_uInt8 nTrans
= 0;
1735 aMask
= AlphaMask( aBmp
.GetSizePixel(), &nTrans
);
1738 case TRANSPARENT_COLOR
:
1739 aMask
= AlphaMask( aBmp
.CreateMask( aIcon
.GetTransparentColor() ) );
1741 case TRANSPARENT_BITMAP
:
1742 aMask
= AlphaMask( aIcon
.GetMask() );
1745 OSL_FAIL( "unhandled transparent type" );
1750 aMask
= aIcon
.GetAlpha();
1751 aIcon
= BitmapEx( aBmp
, aMask
);
1754 ImpBitmap
*pIconImpBitmap
= aIcon
.ImplGetBitmapImpBitmap();
1755 ImpBitmap
*pIconImpMask
= aIcon
.ImplGetMaskImpBitmap();
1757 if( pIconImpBitmap
&& pIconImpMask
)
1759 SalBitmap
*pIconBitmap
=
1760 pIconImpBitmap
->ImplGetSalBitmap();
1761 SalBitmap
*pIconMask
=
1762 pIconImpMask
->ImplGetSalBitmap();
1764 if( ( pBuf
= bitmapToPixbuf( pIconBitmap
, pIconMask
) ) )
1765 pIcons
= g_list_prepend( pIcons
, pBuf
);
1769 gtk_window_set_icon_list( GTK_WINDOW(m_pWindow
), pIcons
);
1771 g_list_foreach( pIcons
, reinterpret_cast<GFunc
>(g_object_unref
), NULL
);
1772 g_list_free( pIcons
);
1775 void GtkSalFrame::SetMenu( SalMenu
* pSalMenu
)
1779 // static_cast<GtkSalMenu*>(m_pSalMenu)->DisconnectFrame();
1781 m_pSalMenu
= pSalMenu
;
1784 SalMenu
* GtkSalFrame::GetMenu()
1789 void GtkSalFrame::DrawMenuBar()
1793 void GtkSalFrame::Center()
1799 nX
= ((long)m_pParent
->maGeometry
.nWidth
- (long)maGeometry
.nWidth
)/2;
1800 nY
= ((long)m_pParent
->maGeometry
.nHeight
- (long)maGeometry
.nHeight
)/2;
1804 GdkScreen
*pScreen
= NULL
;
1806 GdkModifierType nMask
;
1807 gdk_display_get_pointer( getGdkDisplay(), &pScreen
, &px
, &py
, &nMask
);
1809 pScreen
= gtk_widget_get_screen( m_pWindow
);
1812 nMonitor
= gdk_screen_get_monitor_at_point( pScreen
, px
, py
);
1814 GdkRectangle aMonitor
;
1815 gdk_screen_get_monitor_geometry( pScreen
, nMonitor
, &aMonitor
);
1817 nX
= aMonitor
.x
+ (aMonitor
.width
- (long)maGeometry
.nWidth
)/2;
1818 nY
= aMonitor
.y
+ (aMonitor
.height
- (long)maGeometry
.nHeight
)/2;
1820 SetPosSize( nX
, nY
, 0, 0, SAL_FRAME_POSSIZE_X
| SAL_FRAME_POSSIZE_Y
);
1823 Size
GtkSalFrame::calcDefaultSize()
1825 return bestmaxFrameSizeForScreenSize(getDisplay()->GetScreenSize(GetDisplayScreen()));
1828 void GtkSalFrame::SetDefaultSize()
1830 Size aDefSize
= calcDefaultSize();
1832 SetPosSize( 0, 0, aDefSize
.Width(), aDefSize
.Height(),
1833 SAL_FRAME_POSSIZE_WIDTH
| SAL_FRAME_POSSIZE_HEIGHT
);
1835 if( (m_nStyle
& SAL_FRAME_STYLE_DEFAULT
) && m_pWindow
)
1836 gtk_window_maximize( GTK_WINDOW(m_pWindow
) );
1839 static void initClientId()
1841 #if !GTK_CHECK_VERSION(3,0,0)
1842 static bool bOnce
= false;
1846 const OString
& rID
= SessionManagerClient::getSessionID();
1848 gdk_set_sm_client_id(rID
.getStr());
1851 // No session management support for gtk3+ - this is now legacy.
1855 void GtkSalFrame::Show( bool bVisible
, bool bNoActivate
)
1859 #if !GTK_CHECK_VERSION(3,0,0)
1860 if( m_pParent
&& (m_pParent
->m_nStyle
& SAL_FRAME_STYLE_PARTIAL_FULLSCREEN
)
1861 && getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
1862 gtk_window_set_keep_above( GTK_WINDOW(m_pWindow
), bVisible
);
1867 getDisplay()->startupNotificationCompleted();
1871 if( m_bDefaultSize
)
1875 #if !GTK_CHECK_VERSION(3,0,0)
1876 // #i45160# switch to desktop where a dialog with parent will appear
1877 if( m_pParent
&& m_pParent
->m_nWorkArea
!= m_nWorkArea
&& IS_WIDGET_MAPPED(m_pParent
->m_pWindow
) )
1878 getDisplay()->getWMAdaptor()->switchToWorkArea( m_pParent
->m_nWorkArea
);
1881 if( isFloatGrabWindow() &&
1884 ! getDisplay()->GetCaptureFrame() )
1887 * outsmart Metacity's "focus:mouse" mode
1888 * which insists on taking the focus from the document
1889 * to the new float. Grab focus to parent frame BEFORE
1890 * showing the float (cannot grab it to the float
1893 m_pParent
->grabPointer( true, true );
1896 #if !GTK_CHECK_VERSION(3,0,0)
1897 guint32 nUserTime
= 0;
1898 if( ! bNoActivate
&& (m_nStyle
& (SAL_FRAME_STYLE_OWNERDRAWDECORATION
|SAL_FRAME_STYLE_TOOLWINDOW
)) == 0 )
1899 nUserTime
= gdk_x11_get_server_time(GTK_WIDGET (m_pWindow
)->window
);
1901 //For these floating windows we don't want the main window to lose focus, and metacity has...
1902 // metacity-2.24.0/src/core/window.c
1904 // if ((focus_window != NULL) && XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time))
1905 // "compare" window focus prevented by other activity
1907 // where "compare" is this window
1909 // which leads to...
1911 // /* This happens for error dialogs or alerts; these need to remain on
1912 // * top, but it would be confusing to have its ancestor remain
1915 // if (meta_window_is_ancestor_of_transient (focus_window, window))
1916 // "The focus window %s is an ancestor of the newly mapped "
1917 // "window %s which isn't being focused. Unfocusing the "
1920 // i.e. having a time < that of the toplevel frame means that the toplevel frame gets unfocused.
1922 if( nUserTime
== 0 )
1924 nUserTime
= gdk_x11_get_server_time(GTK_WIDGET (m_pWindow
)->window
);
1926 lcl_set_user_time(GTK_WINDOW(m_pWindow
), nUserTime
);
1929 if( ! bNoActivate
&& (m_nStyle
& SAL_FRAME_STYLE_TOOLWINDOW
) )
1930 m_bSetFocusOnMap
= true;
1932 gtk_widget_show( m_pWindow
);
1934 if( isFloatGrabWindow() )
1937 if( ! getDisplay()->GetCaptureFrame() && m_nFloats
== 1 )
1939 grabPointer(true, true);
1940 GtkSalFrame
*pKeyboardFrame
= m_pParent
? m_pParent
: this;
1941 pKeyboardFrame
->grabKeyboard(true);
1943 // #i44068# reset parent's IM context
1945 m_pParent
->EndExtTextInput(0);
1947 if( m_bWindowIsGtkPlug
)
1948 askForXEmbedFocus( 0 );
1952 if( isFloatGrabWindow() )
1955 if( ! getDisplay()->GetCaptureFrame() && m_nFloats
== 0)
1957 GtkSalFrame
*pKeyboardFrame
= m_pParent
? m_pParent
: this;
1958 pKeyboardFrame
->grabKeyboard(false);
1962 gtk_widget_hide( m_pWindow
);
1964 m_pIMHandler
->focusChanged( false );
1965 // flush here; there may be a very seldom race between
1966 // the display connection used for clipboard and our connection
1969 CallCallback( SALEVENT_RESIZE
, NULL
);
1970 TriggerPaintEvent();
1974 void GtkSalFrame::setMinMaxSize()
1976 /* #i34504# metacity (and possibly others) do not treat
1977 * _NET_WM_STATE_FULLSCREEN and max_width/height independently;
1978 * whether they should is undefined. So don't set the max size hint
1979 * for a full screen window.
1981 if( m_pWindow
&& ! isChild() )
1985 if( m_nStyle
& SAL_FRAME_STYLE_SIZEABLE
)
1987 if( m_aMinSize
.Width() && m_aMinSize
.Height() && ! m_bFullscreen
)
1989 aGeo
.min_width
= m_aMinSize
.Width();
1990 aGeo
.min_height
= m_aMinSize
.Height();
1991 aHints
|= GDK_HINT_MIN_SIZE
;
1993 if( m_aMaxSize
.Width() && m_aMaxSize
.Height() && ! m_bFullscreen
)
1995 aGeo
.max_width
= m_aMaxSize
.Width();
1996 aGeo
.max_height
= m_aMaxSize
.Height();
1997 aHints
|= GDK_HINT_MAX_SIZE
;
2002 if( ! m_bFullscreen
)
2004 aGeo
.min_width
= maGeometry
.nWidth
;
2005 aGeo
.min_height
= maGeometry
.nHeight
;
2006 aHints
|= GDK_HINT_MIN_SIZE
;
2008 aGeo
.max_width
= maGeometry
.nWidth
;
2009 aGeo
.max_height
= maGeometry
.nHeight
;
2010 aHints
|= GDK_HINT_MAX_SIZE
;
2013 if( m_bFullscreen
&& m_aMaxSize
.Width() && m_aMaxSize
.Height() )
2015 aGeo
.max_width
= m_aMaxSize
.Width();
2016 aGeo
.max_height
= m_aMaxSize
.Height();
2017 aHints
|= GDK_HINT_MAX_SIZE
;
2021 gtk_window_set_geometry_hints( GTK_WINDOW(m_pWindow
),
2024 GdkWindowHints( aHints
) );
2029 void GtkSalFrame::SetMaxClientSize( long nWidth
, long nHeight
)
2033 m_aMaxSize
= Size( nWidth
, nHeight
);
2034 // Show does a setMinMaxSize
2035 if( IS_WIDGET_MAPPED( m_pWindow
) )
2039 void GtkSalFrame::SetMinClientSize( long nWidth
, long nHeight
)
2043 m_aMinSize
= Size( nWidth
, nHeight
);
2046 widget_set_size_request(nWidth
, nHeight
);
2047 // Show does a setMinMaxSize
2048 if( IS_WIDGET_MAPPED( m_pWindow
) )
2054 // FIXME: we should really be an SvpSalFrame sub-class, and
2055 // share their AllocateFrame !
2056 void GtkSalFrame::AllocateFrame()
2058 #if GTK_CHECK_VERSION(3,0,0)
2059 basegfx::B2IVector
aFrameSize( maGeometry
.nWidth
, maGeometry
.nHeight
);
2060 if( ! m_aFrame
.get() || m_aFrame
->getSize() != aFrameSize
)
2062 if( aFrameSize
.getX() == 0 )
2063 aFrameSize
.setX( 1 );
2064 if( aFrameSize
.getY() == 0 )
2065 aFrameSize
.setY( 1 );
2066 int cairo_stride
= cairo_format_stride_for_width(CAIRO_FORMAT_RGB24
, aFrameSize
.getX());
2067 m_aFrame
= basebmp::createBitmapDevice(aFrameSize
, true,
2068 basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRX
, cairo_stride
);
2069 m_aFrame
->setDamageTracker(
2070 basebmp::IBitmapDeviceDamageTrackerSharedPtr(new DamageTracker(*this)) );
2071 SAL_INFO("vcl.gtk3", "allocated m_aFrame size of " << maGeometry
.nWidth
<< " x " << maGeometry
.nHeight
);
2073 #if OSL_DEBUG_LEVEL > 0 // set background to orange
2074 m_aFrame
->clear( basebmp::Color( 255, 127, 0 ) );
2077 // update device in existing graphics
2078 for( unsigned int i
= 0; i
< SAL_N_ELEMENTS( m_aGraphics
); ++i
)
2080 if( !m_aGraphics
[i
].pGraphics
)
2082 m_aGraphics
[i
].pGraphics
->setDevice( m_aFrame
);
2088 void GtkSalFrame::SetPosSize( long nX
, long nY
, long nWidth
, long nHeight
, sal_uInt16 nFlags
)
2090 if( !m_pWindow
|| isChild( true, false ) )
2093 bool bSized
= false, bMoved
= false;
2095 if( (nFlags
& ( SAL_FRAME_POSSIZE_WIDTH
| SAL_FRAME_POSSIZE_HEIGHT
)) &&
2096 (nWidth
> 0 && nHeight
> 0 ) // sometimes stupid things happen
2099 m_bDefaultSize
= false;
2101 if( (unsigned long)nWidth
!= maGeometry
.nWidth
|| (unsigned long)nHeight
!= maGeometry
.nHeight
)
2103 maGeometry
.nWidth
= nWidth
;
2104 maGeometry
.nHeight
= nHeight
;
2106 if( isChild( false, true ) )
2107 widget_set_size_request(nWidth
, nHeight
);
2108 else if( ! ( m_nState
& GDK_WINDOW_STATE_MAXIMIZED
) )
2109 window_resize(nWidth
, nHeight
);
2112 else if( m_bDefaultSize
)
2115 m_bDefaultSize
= false;
2117 if( nFlags
& ( SAL_FRAME_POSSIZE_X
| SAL_FRAME_POSSIZE_Y
) )
2121 if( AllSettings::GetLayoutRTL() )
2122 nX
= m_pParent
->maGeometry
.nWidth
-maGeometry
.nWidth
-1-nX
;
2123 nX
+= m_pParent
->maGeometry
.nX
;
2124 nY
+= m_pParent
->maGeometry
.nY
;
2127 if( nX
!= maGeometry
.nX
|| nY
!= maGeometry
.nY
)
2132 m_bDefaultPos
= false;
2134 moveWindow( maGeometry
.nX
, maGeometry
.nY
);
2136 updateScreenNumber();
2138 else if( m_bDefaultPos
)
2141 m_bDefaultPos
= false;
2146 if( bSized
&& ! bMoved
)
2147 CallCallback( SALEVENT_RESIZE
, NULL
);
2148 else if( bMoved
&& ! bSized
)
2149 CallCallback( SALEVENT_MOVE
, NULL
);
2150 else if( bMoved
&& bSized
)
2151 CallCallback( SALEVENT_MOVERESIZE
, NULL
);
2154 TriggerPaintEvent();
2157 void GtkSalFrame::GetClientSize( long& rWidth
, long& rHeight
)
2159 if( m_pWindow
&& !(m_nState
& GDK_WINDOW_STATE_ICONIFIED
) )
2161 rWidth
= maGeometry
.nWidth
;
2162 rHeight
= maGeometry
.nHeight
;
2165 rWidth
= rHeight
= 0;
2168 void GtkSalFrame::GetWorkArea( Rectangle
& rRect
)
2170 #if !GTK_CHECK_VERSION(3,0,0)
2171 rRect
= GetGtkSalData()->GetGtkDisplay()->getWMAdaptor()->getWorkArea( 0 );
2173 GdkScreen
*pScreen
= gtk_window_get_screen(GTK_WINDOW(m_pWindow
));
2175 int max
= gdk_screen_get_n_monitors (pScreen
);
2176 for (int i
= 0; i
< max
; ++i
)
2179 gdk_screen_get_monitor_workarea(pScreen
, i
, &aRect
);
2180 Rectangle
aMonitorRect(aRect
.x
, aRect
.y
, aRect
.x
+aRect
.width
, aRect
.y
+aRect
.height
);
2181 aRetRect
.Union(aMonitorRect
);
2187 SalFrame
* GtkSalFrame::GetParent() const
2192 void GtkSalFrame::SetWindowState( const SalFrameState
* pState
)
2194 if( ! m_pWindow
|| ! pState
|| isChild( true, false ) )
2197 const sal_uLong nMaxGeometryMask
=
2198 WINDOWSTATE_MASK_X
| WINDOWSTATE_MASK_Y
|
2199 WINDOWSTATE_MASK_WIDTH
| WINDOWSTATE_MASK_HEIGHT
|
2200 WINDOWSTATE_MASK_MAXIMIZED_X
| WINDOWSTATE_MASK_MAXIMIZED_Y
|
2201 WINDOWSTATE_MASK_MAXIMIZED_WIDTH
| WINDOWSTATE_MASK_MAXIMIZED_HEIGHT
;
2203 if( (pState
->mnMask
& WINDOWSTATE_MASK_STATE
) &&
2204 ! ( m_nState
& GDK_WINDOW_STATE_MAXIMIZED
) &&
2205 (pState
->mnState
& WINDOWSTATE_STATE_MAXIMIZED
) &&
2206 (pState
->mnMask
& nMaxGeometryMask
) == nMaxGeometryMask
)
2208 resizeWindow( pState
->mnWidth
, pState
->mnHeight
);
2209 moveWindow( pState
->mnX
, pState
->mnY
);
2210 m_bDefaultPos
= m_bDefaultSize
= false;
2212 maGeometry
.nX
= pState
->mnMaximizedX
;
2213 maGeometry
.nY
= pState
->mnMaximizedY
;
2214 maGeometry
.nWidth
= pState
->mnMaximizedWidth
;
2215 maGeometry
.nHeight
= pState
->mnMaximizedHeight
;
2216 updateScreenNumber();
2218 m_nState
= GdkWindowState( m_nState
| GDK_WINDOW_STATE_MAXIMIZED
);
2219 m_aRestorePosSize
= Rectangle( Point( pState
->mnX
, pState
->mnY
),
2220 Size( pState
->mnWidth
, pState
->mnHeight
) );
2221 CallCallback( SALEVENT_RESIZE
, NULL
);
2223 else if( pState
->mnMask
& (WINDOWSTATE_MASK_X
| WINDOWSTATE_MASK_Y
|
2224 WINDOWSTATE_MASK_WIDTH
| WINDOWSTATE_MASK_HEIGHT
) )
2226 sal_uInt16 nPosSizeFlags
= 0;
2227 long nX
= pState
->mnX
- (m_pParent
? m_pParent
->maGeometry
.nX
: 0);
2228 long nY
= pState
->mnY
- (m_pParent
? m_pParent
->maGeometry
.nY
: 0);
2229 if( pState
->mnMask
& WINDOWSTATE_MASK_X
)
2230 nPosSizeFlags
|= SAL_FRAME_POSSIZE_X
;
2232 nX
= maGeometry
.nX
- (m_pParent
? m_pParent
->maGeometry
.nX
: 0);
2233 if( pState
->mnMask
& WINDOWSTATE_MASK_Y
)
2234 nPosSizeFlags
|= SAL_FRAME_POSSIZE_Y
;
2236 nY
= maGeometry
.nY
- (m_pParent
? m_pParent
->maGeometry
.nY
: 0);
2237 if( pState
->mnMask
& WINDOWSTATE_MASK_WIDTH
)
2238 nPosSizeFlags
|= SAL_FRAME_POSSIZE_WIDTH
;
2239 if( pState
->mnMask
& WINDOWSTATE_MASK_HEIGHT
)
2240 nPosSizeFlags
|= SAL_FRAME_POSSIZE_HEIGHT
;
2241 SetPosSize( nX
, nY
, pState
->mnWidth
, pState
->mnHeight
, nPosSizeFlags
);
2243 if( pState
->mnMask
& WINDOWSTATE_MASK_STATE
&& ! isChild() )
2245 if( pState
->mnState
& WINDOWSTATE_STATE_MAXIMIZED
)
2246 gtk_window_maximize( GTK_WINDOW(m_pWindow
) );
2248 gtk_window_unmaximize( GTK_WINDOW(m_pWindow
) );
2249 /* #i42379# there is no rollup state in GDK; and rolled up windows are
2250 * (probably depending on the WM) reported as iconified. If we iconify a
2251 * window here that was e.g. a dialog, then it will be unmapped but still
2252 * not be displayed in the task list, so it's an iconified window that
2253 * the user cannot get out of this state. So do not set the iconified state
2254 * on windows with a parent (that is transient frames) since these tend
2255 * to not be represented in an icon task list.
2257 if( (pState
->mnState
& WINDOWSTATE_STATE_MINIMIZED
)
2259 gtk_window_iconify( GTK_WINDOW(m_pWindow
) );
2261 gtk_window_deiconify( GTK_WINDOW(m_pWindow
) );
2263 TriggerPaintEvent();
2266 bool GtkSalFrame::GetWindowState( SalFrameState
* pState
)
2268 pState
->mnState
= WINDOWSTATE_STATE_NORMAL
;
2269 pState
->mnMask
= WINDOWSTATE_MASK_STATE
;
2270 // rollup ? gtk 2.2 does not seem to support the shaded state
2271 if( (m_nState
& GDK_WINDOW_STATE_ICONIFIED
) )
2272 pState
->mnState
|= WINDOWSTATE_STATE_MINIMIZED
;
2273 if( m_nState
& GDK_WINDOW_STATE_MAXIMIZED
)
2275 pState
->mnState
|= WINDOWSTATE_STATE_MAXIMIZED
;
2276 pState
->mnX
= m_aRestorePosSize
.Left();
2277 pState
->mnY
= m_aRestorePosSize
.Top();
2278 pState
->mnWidth
= m_aRestorePosSize
.GetWidth();
2279 pState
->mnHeight
= m_aRestorePosSize
.GetHeight();
2280 pState
->mnMaximizedX
= maGeometry
.nX
;
2281 pState
->mnMaximizedY
= maGeometry
.nY
;
2282 pState
->mnMaximizedWidth
= maGeometry
.nWidth
;
2283 pState
->mnMaximizedHeight
= maGeometry
.nHeight
;
2284 pState
->mnMask
|= WINDOWSTATE_MASK_MAXIMIZED_X
|
2285 WINDOWSTATE_MASK_MAXIMIZED_Y
|
2286 WINDOWSTATE_MASK_MAXIMIZED_WIDTH
|
2287 WINDOWSTATE_MASK_MAXIMIZED_HEIGHT
;
2291 pState
->mnX
= maGeometry
.nX
;
2292 pState
->mnY
= maGeometry
.nY
;
2293 pState
->mnWidth
= maGeometry
.nWidth
;
2294 pState
->mnHeight
= maGeometry
.nHeight
;
2296 pState
->mnMask
|= WINDOWSTATE_MASK_X
|
2297 WINDOWSTATE_MASK_Y
|
2298 WINDOWSTATE_MASK_WIDTH
|
2299 WINDOWSTATE_MASK_HEIGHT
;
2310 void GtkSalFrame::SetScreen( unsigned int nNewScreen
, int eType
, Rectangle
*pSize
)
2315 if (maGeometry
.nDisplayScreenNumber
== nNewScreen
&& eType
== SET_RETAIN_SIZE
)
2318 GdkScreen
*pScreen
= NULL
;
2319 GdkRectangle aNewMonitor
;
2321 bool bSpanAllScreens
= nNewScreen
== (unsigned int)-1;
2322 m_bSpanMonitorsWhenFullscreen
= bSpanAllScreens
&& getDisplay()->getSystem()->GetDisplayScreenCount() > 1;
2324 if (m_bSpanMonitorsWhenFullscreen
) //span all screens
2326 pScreen
= gtk_widget_get_screen( m_pWindow
);
2329 aNewMonitor
.width
= gdk_screen_get_width(pScreen
);
2330 aNewMonitor
.height
= gdk_screen_get_height(pScreen
);
2335 bool bSameMonitor
= false;
2337 if (!bSpanAllScreens
)
2339 pScreen
= getDisplay()->getSystem()->getScreenMonitorFromIdx( nNewScreen
, nMonitor
);
2342 g_warning ("Attempt to move GtkSalFrame to invalid screen %d => "
2343 "fallback to current\n", nNewScreen
);
2349 pScreen
= gtk_widget_get_screen( m_pWindow
);
2350 bSameMonitor
= true;
2353 // Heavy lifting, need to move screen ...
2354 if( pScreen
!= gtk_widget_get_screen( m_pWindow
))
2355 gtk_window_set_screen( GTK_WINDOW( m_pWindow
), pScreen
);
2357 gint nOldMonitor
= gdk_screen_get_monitor_at_window(
2358 pScreen
, widget_get_window( m_pWindow
) );
2360 nMonitor
= nOldMonitor
;
2362 #if OSL_DEBUG_LEVEL > 1
2363 if( nMonitor
== nOldMonitor
)
2364 g_warning( "An apparently pointless SetScreen - should we elide it ?" );
2367 GdkRectangle aOldMonitor
;
2368 gdk_screen_get_monitor_geometry( pScreen
, nOldMonitor
, &aOldMonitor
);
2369 gdk_screen_get_monitor_geometry( pScreen
, nMonitor
, &aNewMonitor
);
2371 maGeometry
.nX
= aNewMonitor
.x
+ maGeometry
.nX
- aOldMonitor
.x
;
2372 maGeometry
.nY
= aNewMonitor
.y
+ maGeometry
.nY
- aOldMonitor
.y
;
2375 bool bResize
= false;
2376 bool bVisible
= IS_WIDGET_MAPPED( m_pWindow
);
2380 if( eType
== SET_FULLSCREEN
)
2382 maGeometry
.nX
= aNewMonitor
.x
;
2383 maGeometry
.nY
= aNewMonitor
.y
;
2384 maGeometry
.nWidth
= aNewMonitor
.width
;
2385 maGeometry
.nHeight
= aNewMonitor
.height
;
2386 m_nStyle
|= SAL_FRAME_STYLE_PARTIAL_FULLSCREEN
;
2389 // #i110881# for the benefit of compiz set a max size here
2390 // else setting to fullscreen fails for unknown reasons
2391 m_aMaxSize
.Width() = aNewMonitor
.width
;
2392 m_aMaxSize
.Height() = aNewMonitor
.height
;
2395 if( pSize
&& eType
== SET_UN_FULLSCREEN
)
2397 maGeometry
.nX
= pSize
->Left();
2398 maGeometry
.nY
= pSize
->Top();
2399 maGeometry
.nWidth
= pSize
->GetWidth();
2400 maGeometry
.nHeight
= pSize
->GetHeight();
2401 m_nStyle
&= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN
;
2407 // temporarily re-sizeable
2408 if( !(m_nStyle
& SAL_FRAME_STYLE_SIZEABLE
) )
2409 gtk_window_set_resizable( GTK_WINDOW(m_pWindow
), TRUE
);
2410 window_resize(maGeometry
.nWidth
, maGeometry
.nHeight
);
2411 //I wonder if we should instead leave maGeometry alone and rely on
2412 //configure-event to trigger signalConfigure and set it there
2414 TriggerPaintEvent();
2417 gtk_window_move( GTK_WINDOW( m_pWindow
), maGeometry
.nX
, maGeometry
.nY
);
2419 #if !GTK_CHECK_VERSION(3,0,0)
2420 // _NET_WM_STATE_FULLSCREEN (Metacity <-> KWin)
2421 if( ! getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
2424 #if GTK_CHECK_VERSION(3,8,0)
2425 gdk_window_set_fullscreen_mode( widget_get_window(m_pWindow
), m_bSpanMonitorsWhenFullscreen
2426 ? GDK_FULLSCREEN_ON_ALL_MONITORS
: GDK_FULLSCREEN_ON_CURRENT_MONITOR
);
2428 if( eType
== SET_FULLSCREEN
)
2429 gtk_window_fullscreen( GTK_WINDOW( m_pWindow
) );
2430 else if( eType
== SET_UN_FULLSCREEN
)
2431 gtk_window_unfullscreen( GTK_WINDOW( m_pWindow
) );
2434 if( eType
== SET_UN_FULLSCREEN
&&
2435 !(m_nStyle
& SAL_FRAME_STYLE_SIZEABLE
) )
2436 gtk_window_set_resizable( GTK_WINDOW( m_pWindow
), FALSE
);
2438 // FIXME: we should really let gtk+ handle our widget hierarchy ...
2439 if( m_pParent
&& gtk_widget_get_screen( m_pParent
->m_pWindow
) != pScreen
)
2441 std::list
< GtkSalFrame
* > aChildren
= m_aChildren
;
2442 for( std::list
< GtkSalFrame
* >::iterator it
= aChildren
.begin(); it
!= aChildren
.end(); ++it
)
2443 (*it
)->SetScreen( nNewScreen
, SET_RETAIN_SIZE
);
2445 m_bDefaultPos
= m_bDefaultSize
= false;
2446 updateScreenNumber();
2447 CallCallback( SALEVENT_MOVERESIZE
, NULL
);
2453 void GtkSalFrame::SetScreenNumber( unsigned int nNewScreen
)
2455 SetScreen( nNewScreen
, SET_RETAIN_SIZE
);
2458 void GtkSalFrame::updateWMClass()
2460 OString aResClass
= OUStringToOString(m_sWMClass
, RTL_TEXTENCODING_ASCII_US
);
2461 const char *pResClass
= !aResClass
.isEmpty() ? aResClass
.getStr() :
2462 SalGenericSystem::getFrameClassName();
2465 if (!getDisplay()->IsX11Display())
2468 #if GTK_CHECK_VERSION(3,0,0)
2469 display
= GDK_DISPLAY_XDISPLAY(getGdkDisplay());
2471 display
= getDisplay()->GetDisplay();
2474 if( IS_WIDGET_REALIZED( m_pWindow
) )
2476 XClassHint
* pClass
= XAllocClassHint();
2477 OString aResName
= SalGenericSystem::getFrameResName();
2478 pClass
->res_name
= const_cast<char*>(aResName
.getStr());
2479 pClass
->res_class
= const_cast<char*>(pResClass
);
2480 XSetClassHint( display
,
2481 widget_get_xid(m_pWindow
),
2487 void GtkSalFrame::SetApplicationID( const OUString
&rWMClass
)
2489 if( rWMClass
!= m_sWMClass
&& ! isChild() )
2491 m_sWMClass
= rWMClass
;
2494 for( std::list
< GtkSalFrame
* >::iterator it
= m_aChildren
.begin(); it
!= m_aChildren
.end(); ++it
)
2495 (*it
)->SetApplicationID(rWMClass
);
2499 void GtkSalFrame::ShowFullScreen( bool bFullScreen
, sal_Int32 nScreen
)
2501 m_bFullscreen
= bFullScreen
;
2503 if( !m_pWindow
|| isChild() )
2508 m_aRestorePosSize
= Rectangle( Point( maGeometry
.nX
, maGeometry
.nY
),
2509 Size( maGeometry
.nWidth
, maGeometry
.nHeight
) );
2510 SetScreen( nScreen
, SET_FULLSCREEN
);
2514 SetScreen( nScreen
, SET_UN_FULLSCREEN
,
2515 !m_aRestorePosSize
.IsEmpty() ? &m_aRestorePosSize
: NULL
);
2516 m_aRestorePosSize
= Rectangle();
2520 /* definitions from xautolock.c (pl15) */
2521 #define XAUTOLOCK_DISABLE 1
2522 #define XAUTOLOCK_ENABLE 2
2524 void GtkSalFrame::setAutoLock( bool bLock
)
2526 if( isChild() || !getDisplay()->IsX11Display() )
2529 GdkScreen
*pScreen
= gtk_window_get_screen( GTK_WINDOW(m_pWindow
) );
2530 GdkDisplay
*pDisplay
= gdk_screen_get_display( pScreen
);
2531 GdkWindow
*pRootWin
= gdk_screen_get_root_window( pScreen
);
2533 Atom nAtom
= XInternAtom( GDK_DISPLAY_XDISPLAY( pDisplay
),
2534 "XAUTOLOCK_MESSAGE", False
);
2536 int nMessage
= bLock
? XAUTOLOCK_ENABLE
: XAUTOLOCK_DISABLE
;
2538 XChangeProperty( GDK_DISPLAY_XDISPLAY( pDisplay
),
2539 GDK_WINDOW_XID( pRootWin
),
2542 reinterpret_cast<unsigned char*>(&nMessage
),
2543 sizeof( nMessage
) );
2547 /** cookie is returned as an unsigned integer */
2549 dbus_inhibit_gsm (const gchar
*appname
,
2550 const gchar
*reason
,
2555 GError
*error
= NULL
;
2556 DBusGProxy
*proxy
= NULL
;
2558 /* get the DBUS session connection */
2559 DBusGConnection
*session_connection
= dbus_g_bus_get (DBUS_BUS_SESSION
, &error
);
2560 if (error
!= NULL
) {
2561 g_debug ("DBUS cannot connect : %s", error
->message
);
2562 g_error_free (error
);
2566 /* get the proxy with gnome-session-manager */
2567 proxy
= dbus_g_proxy_new_for_name (session_connection
,
2570 GSM_DBUS_INTERFACE
);
2571 if (proxy
== NULL
) {
2572 g_debug ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE
);
2576 res
= dbus_g_proxy_call (proxy
,
2578 G_TYPE_STRING
, appname
,
2580 G_TYPE_STRING
, reason
,
2581 G_TYPE_UINT
, 8, //Inhibit the session being marked as idle
2583 G_TYPE_UINT
, &cookie
,
2586 /* check the return value */
2589 g_debug ("Inhibit method failed");
2592 /* check the error value */
2593 if (error
!= NULL
) {
2594 g_debug ("Inhibit problem : %s", error
->message
);
2595 g_error_free (error
);
2599 g_object_unref (G_OBJECT (proxy
));
2604 dbus_uninhibit_gsm (guint cookie
)
2607 GError
*error
= NULL
;
2608 DBusGProxy
*proxy
= NULL
;
2609 DBusGConnection
*session_connection
= NULL
;
2611 if (cookie
== guint(-1)) {
2612 g_debug ("Invalid cookie");
2616 /* get the DBUS session connection */
2617 session_connection
= dbus_g_bus_get (DBUS_BUS_SESSION
, &error
);
2619 g_debug ("DBUS cannot connect : %s", error
->message
);
2620 g_error_free (error
);
2624 /* get the proxy with gnome-session-manager */
2625 proxy
= dbus_g_proxy_new_for_name (session_connection
,
2628 GSM_DBUS_INTERFACE
);
2629 if (proxy
== NULL
) {
2630 g_debug ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE
);
2634 res
= dbus_g_proxy_call (proxy
,
2637 G_TYPE_UINT
, cookie
,
2641 /* check the return value */
2643 g_debug ("Uninhibit method failed");
2646 /* check the error value */
2647 if (error
!= NULL
) {
2648 g_debug ("Uninhibit problem : %s", error
->message
);
2649 g_error_free (error
);
2652 g_object_unref (G_OBJECT (proxy
));
2656 void GtkSalFrame::StartPresentation( bool bStart
)
2658 setAutoLock( !bStart
);
2660 if( !getDisplay()->IsX11Display() )
2663 #if !GTK_CHECK_VERSION(3,0,0)
2664 Display
*pDisplay
= GDK_DISPLAY_XDISPLAY( getGdkDisplay() );
2666 int nTimeout
, nInterval
, bPreferBlanking
, bAllowExposures
;
2667 XGetScreenSaver( pDisplay
, &nTimeout
, &nInterval
,
2668 &bPreferBlanking
, &bAllowExposures
);
2672 #if !GTK_CHECK_VERSION(3,0,0)
2675 m_nSavedScreenSaverTimeout
= nTimeout
;
2676 XResetScreenSaver( pDisplay
);
2677 XSetScreenSaver( pDisplay
, 0, nInterval
,
2678 bPreferBlanking
, bAllowExposures
);
2682 m_nGSMCookie
= dbus_inhibit_gsm(g_get_application_name(), "presentation",
2683 widget_get_xid(m_pWindow
));
2688 #if !GTK_CHECK_VERSION(3,0,0)
2689 if( m_nSavedScreenSaverTimeout
)
2690 XSetScreenSaver( pDisplay
, m_nSavedScreenSaverTimeout
,
2691 nInterval
, bPreferBlanking
,
2694 m_nSavedScreenSaverTimeout
= 0;
2696 dbus_uninhibit_gsm(m_nGSMCookie
);
2701 void GtkSalFrame::SetAlwaysOnTop( bool bOnTop
)
2704 gtk_window_set_keep_above( GTK_WINDOW( m_pWindow
), bOnTop
);
2707 void GtkSalFrame::ToTop( sal_uInt16 nFlags
)
2711 if( isChild( false, true ) )
2712 gtk_widget_grab_focus( m_pWindow
);
2713 else if( IS_WIDGET_MAPPED( m_pWindow
) )
2715 if( ! (nFlags
& SAL_FRAME_TOTOP_GRABFOCUS_ONLY
) )
2716 gtk_window_present( GTK_WINDOW(m_pWindow
) );
2719 #if !GTK_CHECK_VERSION(3,0,0)
2720 guint32 nUserTime
= gdk_x11_get_server_time(GTK_WIDGET (m_pWindow
)->window
);
2722 guint32 nUserTime
= GDK_CURRENT_TIME
;
2724 gdk_window_focus( widget_get_window(m_pWindow
), nUserTime
);
2726 #if !GTK_CHECK_VERSION(3,0,0)
2727 /* need to do an XSetInputFocus here because
2728 * gdk_window_focus will ask a EWMH compliant WM to put the focus
2729 * to our window - which it of course won't since our input hint
2732 if( (m_nStyle
& (SAL_FRAME_STYLE_OWNERDRAWDECORATION
|SAL_FRAME_STYLE_FLOAT_FOCUSABLE
)) )
2734 // sad but true: this can cause an XError, we need to catch that
2735 // to do this we need to synchronize with the XServer
2736 GetGenericData()->ErrorTrapPush();
2737 XSetInputFocus( getDisplay()->GetDisplay(), widget_get_xid(m_pWindow
), RevertToParent
, CurrentTime
);
2738 // fdo#46687 - an XSync should not be necessary - but for some reason it is.
2739 XSync( getDisplay()->GetDisplay(), False
);
2740 GetGenericData()->ErrorTrapPop();
2746 if( nFlags
& SAL_FRAME_TOTOP_RESTOREWHENMIN
)
2747 gtk_window_present( GTK_WINDOW(m_pWindow
) );
2752 void GtkSalFrame::SetPointer( PointerStyle ePointerStyle
)
2754 if( m_pWindow
&& ePointerStyle
!= m_ePointerStyle
)
2756 m_ePointerStyle
= ePointerStyle
;
2757 GdkCursor
*pCursor
= getDisplay()->getCursor( ePointerStyle
);
2758 gdk_window_set_cursor( widget_get_window(m_pWindow
), pCursor
);
2759 m_pCurrentCursor
= pCursor
;
2761 // #i80791# use grabPointer the same way as CaptureMouse, respective float grab
2762 if( getDisplay()->MouseCaptured( this ) )
2763 grabPointer( true, false );
2764 else if( m_nFloats
> 0 )
2765 grabPointer( true, true );
2769 void GtkSalFrame::grabPointer( bool bGrab
, bool bOwnerEvents
)
2771 static const char* pEnv
= getenv( "SAL_NO_MOUSEGRABS" );
2778 const int nMask
= (GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
| GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK
);
2780 #if GTK_CHECK_VERSION(3,0,0)
2781 GdkDeviceManager
* pDeviceManager
= gdk_display_get_device_manager(getGdkDisplay());
2782 GdkDevice
* pPointer
= gdk_device_manager_get_client_pointer(pDeviceManager
);
2784 gdk_device_grab(pPointer
, widget_get_window(m_pWindow
), GDK_OWNERSHIP_NONE
, bOwnerEvents
, (GdkEventMask
) nMask
, m_pCurrentCursor
, GDK_CURRENT_TIME
);
2786 gdk_device_ungrab(pPointer
, GDK_CURRENT_TIME
);
2790 bool bUseGdkGrab
= true;
2791 const std::list
< SalFrame
* >& rFrames
= getDisplay()->getFrames();
2792 for( std::list
< SalFrame
* >::const_iterator it
= rFrames
.begin(); it
!= rFrames
.end(); ++it
)
2794 const GtkSalFrame
* pFrame
= static_cast< const GtkSalFrame
* >(*it
);
2795 if( pFrame
->m_bWindowIsGtkPlug
)
2797 bUseGdkGrab
= false;
2803 gdk_pointer_grab( widget_get_window( m_pWindow
), bOwnerEvents
,
2804 (GdkEventMask
) nMask
, NULL
, m_pCurrentCursor
,
2809 // FIXME: for some unknown reason gdk_pointer_grab does not
2810 // really produce owner events for GtkPlug windows
2811 // the cause is yet unknown
2813 // this is of course a bad hack, especially as we cannot
2814 // set the right cursor this way
2815 XGrabPointer( getDisplay()->GetDisplay(),
2816 widget_get_xid( m_pWindow
),
2818 PointerMotionMask
| ButtonPressMask
| ButtonReleaseMask
,
2829 // Two GdkDisplays may be open
2830 gdk_display_pointer_ungrab( getGdkDisplay(), GDK_CURRENT_TIME
);
2835 void GtkSalFrame::grabKeyboard( bool bGrab
)
2840 #if GTK_CHECK_VERSION(3,0,0)
2841 GdkDeviceManager
* pDeviceManager
= gdk_display_get_device_manager(getGdkDisplay());
2842 GdkDevice
* pPointer
= gdk_device_manager_get_client_pointer(pDeviceManager
);
2843 GdkDevice
* pKeyboard
= gdk_device_get_associated_device(pPointer
);
2846 gdk_device_grab(pKeyboard
, widget_get_window(m_pWindow
), GDK_OWNERSHIP_NONE
,
2847 true, (GdkEventMask
)(GDK_KEY_PRESS
| GDK_KEY_RELEASE
), NULL
, GDK_CURRENT_TIME
);
2851 gdk_device_ungrab(pKeyboard
, GDK_CURRENT_TIME
);
2856 gdk_keyboard_grab(widget_get_window(m_pWindow
), true,
2861 gdk_keyboard_ungrab(GDK_CURRENT_TIME
);
2866 void GtkSalFrame::CaptureMouse( bool bCapture
)
2868 getDisplay()->CaptureMouse( bCapture
? this : NULL
);
2871 void GtkSalFrame::SetPointerPos( long nX
, long nY
)
2873 GtkSalFrame
* pFrame
= this;
2874 while( pFrame
&& pFrame
->isChild( false, true ) )
2875 pFrame
= pFrame
->m_pParent
;
2879 GdkScreen
*pScreen
= gtk_window_get_screen( GTK_WINDOW(pFrame
->m_pWindow
) );
2880 GdkDisplay
*pDisplay
= gdk_screen_get_display( pScreen
);
2882 /* when the application tries to center the mouse in the dialog the
2883 * window isn't mapped already. So use coordinates relative to the root window.
2885 unsigned int nWindowLeft
= maGeometry
.nX
+ nX
;
2886 unsigned int nWindowTop
= maGeometry
.nY
+ nY
;
2888 XWarpPointer( GDK_DISPLAY_XDISPLAY (pDisplay
), None
,
2889 GDK_WINDOW_XID (gdk_screen_get_root_window( pScreen
) ),
2890 0, 0, 0, 0, nWindowLeft
, nWindowTop
);
2891 // #i38648# ask for the next motion hint
2893 GdkModifierType mask
;
2894 gdk_window_get_pointer( widget_get_window(pFrame
->m_pWindow
) , &x
, &y
, &mask
);
2897 void GtkSalFrame::Flush()
2899 #if GTK_CHECK_VERSION(3,0,0)
2900 gdk_display_flush( getGdkDisplay() );
2902 XFlush (GDK_DISPLAY_XDISPLAY (getGdkDisplay()));
2906 void GtkSalFrame::Sync()
2908 gdk_display_sync( getGdkDisplay() );
2912 #define GDK_Open 0x1008ff6b
2915 #define GDK_Paste 0x1008ff6d
2918 #define GDK_Copy 0x1008ff57
2921 #define GDK_Cut 0x1008ff58
2924 void GtkSalFrame::KeyCodeToGdkKey(const vcl::KeyCode
& rKeyCode
,
2925 guint
* pGdkKeyCode
, GdkModifierType
*pGdkModifiers
)
2927 if ( pGdkKeyCode
== NULL
|| pGdkModifiers
== NULL
)
2930 // Get GDK key modifiers
2931 GdkModifierType nModifiers
= (GdkModifierType
) 0;
2933 if ( rKeyCode
.IsShift() )
2934 nModifiers
= (GdkModifierType
) ( nModifiers
| GDK_SHIFT_MASK
);
2936 if ( rKeyCode
.IsMod1() )
2937 nModifiers
= (GdkModifierType
) ( nModifiers
| GDK_CONTROL_MASK
);
2939 if ( rKeyCode
.IsMod2() )
2940 nModifiers
= (GdkModifierType
) ( nModifiers
| GDK_MOD1_MASK
);
2942 *pGdkModifiers
= nModifiers
;
2947 guint nCode
= rKeyCode
.GetCode();
2949 if ( nCode
>= KEY_0
&& nCode
<= KEY_9
)
2950 nKeyCode
= ( nCode
- KEY_0
) + GDK_0
;
2951 else if ( nCode
>= KEY_A
&& nCode
<= KEY_Z
)
2952 nKeyCode
= ( nCode
- KEY_A
) + GDK_A
;
2953 else if ( nCode
>= KEY_F1
&& nCode
<= KEY_F26
)
2954 nKeyCode
= ( nCode
- KEY_F1
) + GDK_F1
;
2959 case KEY_DOWN
: nKeyCode
= GDK_Down
; break;
2960 case KEY_UP
: nKeyCode
= GDK_Up
; break;
2961 case KEY_LEFT
: nKeyCode
= GDK_Left
; break;
2962 case KEY_RIGHT
: nKeyCode
= GDK_Right
; break;
2963 case KEY_HOME
: nKeyCode
= GDK_Home
; break;
2964 case KEY_END
: nKeyCode
= GDK_End
; break;
2965 case KEY_PAGEUP
: nKeyCode
= GDK_Page_Up
; break;
2966 case KEY_PAGEDOWN
: nKeyCode
= GDK_Page_Down
; break;
2967 case KEY_RETURN
: nKeyCode
= GDK_Return
; break;
2968 case KEY_ESCAPE
: nKeyCode
= GDK_Escape
; break;
2969 case KEY_TAB
: nKeyCode
= GDK_Tab
; break;
2970 case KEY_BACKSPACE
: nKeyCode
= GDK_BackSpace
; break;
2971 case KEY_SPACE
: nKeyCode
= GDK_space
; break;
2972 case KEY_INSERT
: nKeyCode
= GDK_Insert
; break;
2973 case KEY_DELETE
: nKeyCode
= GDK_Delete
; break;
2974 case KEY_ADD
: nKeyCode
= GDK_plus
; break;
2975 case KEY_SUBTRACT
: nKeyCode
= GDK_minus
; break;
2976 case KEY_MULTIPLY
: nKeyCode
= GDK_asterisk
; break;
2977 case KEY_DIVIDE
: nKeyCode
= GDK_slash
; break;
2978 case KEY_POINT
: nKeyCode
= GDK_period
; break;
2979 case KEY_COMMA
: nKeyCode
= GDK_comma
; break;
2980 case KEY_LESS
: nKeyCode
= GDK_less
; break;
2981 case KEY_GREATER
: nKeyCode
= GDK_greater
; break;
2982 case KEY_EQUAL
: nKeyCode
= GDK_equal
; break;
2983 case KEY_FIND
: nKeyCode
= GDK_Find
; break;
2984 case KEY_CONTEXTMENU
: nKeyCode
= GDK_Menu
; break;
2985 case KEY_HELP
: nKeyCode
= GDK_Help
; break;
2986 case KEY_UNDO
: nKeyCode
= GDK_Undo
; break;
2987 case KEY_REPEAT
: nKeyCode
= GDK_Redo
; break;
2988 case KEY_DECIMAL
: nKeyCode
= GDK_KP_Decimal
; break;
2989 case KEY_TILDE
: nKeyCode
= GDK_asciitilde
; break;
2990 case KEY_QUOTELEFT
: nKeyCode
= GDK_quoteleft
; break;
2991 case KEY_BRACKETLEFT
: nKeyCode
= GDK_bracketleft
; break;
2992 case KEY_BRACKETRIGHT
: nKeyCode
= GDK_bracketright
; break;
2993 case KEY_SEMICOLON
: nKeyCode
= GDK_semicolon
; break;
2994 case KEY_QUOTERIGHT
: nKeyCode
= GDK_quoteright
; break;
2997 case KEY_COPY
: nKeyCode
= GDK_Copy
; break;
2998 case KEY_CUT
: nKeyCode
= GDK_Cut
; break;
2999 case KEY_PASTE
: nKeyCode
= GDK_Paste
; break;
3000 case KEY_OPEN
: nKeyCode
= GDK_Open
; break;
3004 *pGdkKeyCode
= nKeyCode
;
3007 OUString
GtkSalFrame::GetKeyName( sal_uInt16 nKeyCode
)
3009 #if !GTK_CHECK_VERSION(3,0,0)
3010 return getDisplay()->GetKeyName( nKeyCode
);
3013 GdkModifierType nGtkModifiers
;
3014 KeyCodeToGdkKey(nKeyCode
, &nGtkKeyCode
, &nGtkModifiers
);
3016 gchar
* pName
= gtk_accelerator_get_label(nGtkKeyCode
, nGtkModifiers
);
3017 OUString
aRet(pName
, rtl_str_getLength(pName
), RTL_TEXTENCODING_UTF8
);
3023 GdkDisplay
*GtkSalFrame::getGdkDisplay()
3025 return GetGtkSalData()->GetGdkDisplay();
3028 GtkSalDisplay
*GtkSalFrame::getDisplay()
3030 return GetGtkSalData()->GetGtkDisplay();
3033 SalFrame::SalPointerState
GtkSalFrame::GetPointerState()
3035 SalPointerState aState
;
3038 GdkModifierType aMask
;
3039 gdk_display_get_pointer( getGdkDisplay(), &pScreen
, &x
, &y
, &aMask
);
3040 aState
.maPos
= Point( x
- maGeometry
.nX
, y
- maGeometry
.nY
);
3041 aState
.mnState
= GetMouseModCode( aMask
);
3045 KeyIndicatorState
GtkSalFrame::GetIndicatorState()
3047 #if !GTK_CHECK_VERSION(3,0,0)
3048 return GetGtkSalData()->GetGtkDisplay()->GetIndicatorState();
3050 g_warning ("missing get indicator state");
3051 return KeyIndicatorState::NONE
;
3055 void GtkSalFrame::SimulateKeyPress( sal_uInt16 nKeyCode
)
3057 #if !GTK_CHECK_VERSION(3,0,0)
3058 GetGtkSalData()->GetGtkDisplay()->SimulateKeyPress(nKeyCode
);
3060 g_warning ("missing simulate keypress %d", nKeyCode
);
3064 void GtkSalFrame::SetInputContext( SalInputContext
* pContext
)
3069 if( ! (pContext
->mnOptions
& InputContextFlags::Text
) )
3072 // create a new im context
3073 if( ! m_pIMHandler
)
3074 m_pIMHandler
= new IMHandler( this );
3077 void GtkSalFrame::EndExtTextInput( sal_uInt16 nFlags
)
3080 m_pIMHandler
->endExtTextInput( nFlags
);
3083 bool GtkSalFrame::MapUnicodeToKeyCode( sal_Unicode
, LanguageType
, vcl::KeyCode
& )
3085 // not supported yet
3089 LanguageType
GtkSalFrame::GetInputLanguage()
3091 return LANGUAGE_DONTKNOW
;
3094 void GtkSalFrame::UpdateSettings( AllSettings
& rSettings
)
3099 GtkSalGraphics
* pGraphics
= static_cast<GtkSalGraphics
*>(m_aGraphics
[0].pGraphics
);
3100 bool bFreeGraphics
= false;
3103 pGraphics
= static_cast<GtkSalGraphics
*>(AcquireGraphics());
3106 SAL_WARN("vcl", "Could not get graphics - unable to update settings");
3109 bFreeGraphics
= true;
3112 pGraphics
->updateSettings( rSettings
);
3115 ReleaseGraphics( pGraphics
);
3118 void GtkSalFrame::Beep()
3120 gdk_display_beep( getGdkDisplay() );
3123 const SystemEnvData
* GtkSalFrame::GetSystemData() const
3125 return &m_aSystemData
;
3128 void GtkSalFrame::SetParent( SalFrame
* pNewParent
)
3131 m_pParent
->m_aChildren
.remove( this );
3132 m_pParent
= static_cast<GtkSalFrame
*>(pNewParent
);
3134 m_pParent
->m_aChildren
.push_back( this );
3136 gtk_window_set_transient_for( GTK_WINDOW(m_pWindow
),
3137 (m_pParent
&& ! m_pParent
->isChild(true,false)) ? GTK_WINDOW(m_pParent
->m_pWindow
) : NULL
3141 #if !GTK_CHECK_VERSION(3,0,0)
3143 void GtkSalFrame::createNewWindow( ::Window aNewParent
, bool bXEmbed
, SalX11Screen nXScreen
)
3145 bool bWasVisible
= m_pWindow
&& IS_WIDGET_MAPPED(m_pWindow
);
3149 if( (int)nXScreen
.getXScreen() >= getDisplay()->GetXScreenCount() )
3150 nXScreen
= m_nXScreen
;
3152 SystemParentData aParentData
;
3153 aParentData
.aWindow
= aNewParent
;
3154 aParentData
.bXEmbedSupport
= bXEmbed
;
3155 if( aNewParent
== None
)
3157 aNewParent
= getDisplay()->GetRootWindow(nXScreen
);
3158 aParentData
.aWindow
= None
;
3159 aParentData
.bXEmbedSupport
= false;
3163 // is new parent a root window ?
3164 Display
* pDisp
= getDisplay()->GetDisplay();
3165 int nScreens
= getDisplay()->GetXScreenCount();
3166 for( int i
= 0; i
< nScreens
; i
++ )
3168 if( aNewParent
== RootWindow( pDisp
, i
) )
3170 nXScreen
= SalX11Screen( i
);
3171 aParentData
.aWindow
= None
;
3172 aParentData
.bXEmbedSupport
= false;
3178 // free xrender resources
3179 for( unsigned int i
= 0; i
< SAL_N_ELEMENTS(m_aGraphics
); i
++ )
3180 if( m_aGraphics
[i
].bInUse
)
3181 m_aGraphics
[i
].pGraphics
->SetDrawable( None
, m_nXScreen
);
3183 // first deinit frame
3186 delete m_pIMHandler
;
3187 m_pIMHandler
= NULL
;
3191 gdk_region_destroy( m_pRegion
);
3193 if( m_pFixedContainer
)
3194 gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer
) );
3196 gtk_widget_destroy( m_pWindow
);
3197 if( m_pForeignParent
)
3198 g_object_unref( G_OBJECT( m_pForeignParent
) );
3199 if( m_pForeignTopLevel
)
3200 g_object_unref( G_OBJECT( m_pForeignTopLevel
) );
3203 m_bDefaultPos
= m_bDefaultSize
= false;
3204 if( aParentData
.aWindow
!= None
)
3206 m_nStyle
|= SAL_FRAME_STYLE_PLUG
;
3207 Init( &aParentData
);
3211 m_nStyle
&= ~SAL_FRAME_STYLE_PLUG
;
3212 Init( (m_pParent
&& m_pParent
->m_nXScreen
== m_nXScreen
) ? m_pParent
: NULL
, m_nStyle
);
3216 for( unsigned int i
= 0; i
< SAL_N_ELEMENTS(m_aGraphics
); i
++ )
3218 if( m_aGraphics
[i
].bInUse
)
3220 m_aGraphics
[i
].pGraphics
->SetDrawable( widget_get_xid(m_pWindow
), m_nXScreen
);
3221 m_aGraphics
[i
].pGraphics
->SetWindow( m_pWindow
);
3225 if( ! m_aTitle
.isEmpty() )
3226 SetTitle( m_aTitle
);
3231 std::list
< GtkSalFrame
* > aChildren
= m_aChildren
;
3232 m_aChildren
.clear();
3233 for( std::list
< GtkSalFrame
* >::iterator it
= aChildren
.begin(); it
!= aChildren
.end(); ++it
)
3234 (*it
)->createNewWindow( None
, false, m_nXScreen
);
3236 // FIXME: SalObjects
3240 bool GtkSalFrame::SetPluginParent( SystemParentData
* pSysParent
)
3242 #if !GTK_CHECK_VERSION(3,0,0)
3243 GetGenericData()->ErrorTrapPush(); // permanantly ignore unruly children's errors
3244 createNewWindow( pSysParent
->aWindow
, (pSysParent
->nSize
> sizeof(long)) && pSysParent
->bXEmbedSupport
, m_nXScreen
);
3248 //FIXME: no SetPluginParent impl. for gtk3
3253 void GtkSalFrame::ResetClipRegion()
3256 gdk_window_shape_combine_region( widget_get_window( m_pWindow
), NULL
, 0, 0 );
3259 void GtkSalFrame::BeginSetClipRegion( sal_uLong
)
3261 #if GTK_CHECK_VERSION(3,0,0)
3263 cairo_region_destroy( m_pRegion
);
3264 m_pRegion
= cairo_region_create();
3267 gdk_region_destroy( m_pRegion
);
3268 m_pRegion
= gdk_region_new();
3272 void GtkSalFrame::UnionClipRegion( long nX
, long nY
, long nWidth
, long nHeight
)
3279 aRect
.width
= nWidth
;
3280 aRect
.height
= nHeight
;
3281 #if GTK_CHECK_VERSION(3,0,0)
3282 cairo_region_union_rectangle( m_pRegion
, &aRect
);
3284 gdk_region_union_with_rect( m_pRegion
, &aRect
);
3289 void GtkSalFrame::EndSetClipRegion()
3291 if( m_pWindow
&& m_pRegion
)
3292 gdk_window_shape_combine_region( widget_get_window(m_pWindow
), m_pRegion
, 0, 0 );
3295 #if !GTK_CHECK_VERSION(3,0,0)
3296 bool GtkSalFrame::Dispatch( const XEvent
* pEvent
)
3298 bool bContinueDispatch
= true;
3300 if( pEvent
->type
== PropertyNotify
)
3302 vcl_sal::WMAdaptor
* pAdaptor
= getDisplay()->getWMAdaptor();
3303 Atom nDesktopAtom
= pAdaptor
->getAtom( vcl_sal::WMAdaptor::NET_WM_DESKTOP
);
3304 if( pEvent
->xproperty
.atom
== nDesktopAtom
&&
3305 pEvent
->xproperty
.state
== PropertyNewValue
)
3307 m_nWorkArea
= pAdaptor
->getWindowWorkArea( widget_get_xid(m_pWindow
) );
3310 else if( pEvent
->type
== ConfigureNotify
)
3312 if( m_pForeignParent
&& pEvent
->xconfigure
.window
== m_aForeignParentWindow
)
3314 bContinueDispatch
= false;
3315 gtk_window_resize( GTK_WINDOW(m_pWindow
), pEvent
->xconfigure
.width
, pEvent
->xconfigure
.height
);
3316 if( ( sal::static_int_cast
< int >(maGeometry
.nWidth
) !=
3317 pEvent
->xconfigure
.width
) ||
3318 ( sal::static_int_cast
< int >(maGeometry
.nHeight
) !=
3319 pEvent
->xconfigure
.height
) )
3321 maGeometry
.nWidth
= pEvent
->xconfigure
.width
;
3322 maGeometry
.nHeight
= pEvent
->xconfigure
.height
;
3324 getDisplay()->SendInternalEvent( this, NULL
, SALEVENT_RESIZE
);
3327 else if( m_pForeignTopLevel
&& pEvent
->xconfigure
.window
== m_aForeignTopLevelWindow
)
3329 bContinueDispatch
= false;
3333 XTranslateCoordinates( getDisplay()->GetDisplay(),
3334 widget_get_xid(m_pWindow
),
3335 getDisplay()->GetRootWindow( getDisplay()->GetDefaultXScreen() ),
3339 if( x
!= maGeometry
.nX
|| y
!= maGeometry
.nY
)
3343 getDisplay()->SendInternalEvent( this, NULL
, SALEVENT_MOVE
);
3347 else if( pEvent
->type
== ClientMessage
&&
3348 pEvent
->xclient
.message_type
== getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED
) &&
3349 pEvent
->xclient
.window
== widget_get_xid(m_pWindow
) &&
3353 // FIXME: this should not be necessary, GtkPlug should do this
3354 // transparently for us
3355 if( pEvent
->xclient
.data
.l
[1] == 1 || // XEMBED_WINDOW_ACTIVATE
3356 pEvent
->xclient
.data
.l
[1] == 2 // XEMBED_WINDOW_DEACTIVATE
3359 GdkEventFocus aEvent
;
3360 aEvent
.type
= GDK_FOCUS_CHANGE
;
3361 aEvent
.window
= widget_get_window( m_pWindow
);
3362 aEvent
.send_event
= gint8(TRUE
);
3363 aEvent
.in
= gint16(pEvent
->xclient
.data
.l
[1] == 1);
3364 signalFocus( m_pWindow
, &aEvent
, this );
3368 return bContinueDispatch
;
3372 gboolean
GtkSalFrame::signalButton( GtkWidget
*, GdkEventButton
* pEvent
, gpointer frame
)
3374 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3376 SalMouseEvent aEvent
;
3377 sal_uInt16 nEventType
= 0;
3378 switch( pEvent
->type
)
3380 case GDK_BUTTON_PRESS
:
3381 nEventType
= SALEVENT_MOUSEBUTTONDOWN
;
3383 case GDK_BUTTON_RELEASE
:
3384 nEventType
= SALEVENT_MOUSEBUTTONUP
;
3389 switch( pEvent
->button
)
3391 case 1: aEvent
.mnButton
= MOUSE_LEFT
; break;
3392 case 2: aEvent
.mnButton
= MOUSE_MIDDLE
; break;
3393 case 3: aEvent
.mnButton
= MOUSE_RIGHT
; break;
3394 default: return false;
3396 aEvent
.mnTime
= pEvent
->time
;
3397 aEvent
.mnX
= (long)pEvent
->x_root
- pThis
->maGeometry
.nX
;
3398 aEvent
.mnY
= (long)pEvent
->y_root
- pThis
->maGeometry
.nY
;
3399 aEvent
.mnCode
= GetMouseModCode( pEvent
->state
);
3401 bool bClosePopups
= false;
3402 if( pEvent
->type
== GDK_BUTTON_PRESS
&&
3403 (pThis
->m_nStyle
& SAL_FRAME_STYLE_OWNERDRAWDECORATION
) == 0
3408 // close popups if user clicks outside our application
3410 bClosePopups
= (gdk_display_get_window_at_pointer( GtkSalFrame::getGdkDisplay(), &x
, &y
) == NULL
);
3412 /* #i30306# release implicit pointer grab if no popups are open; else
3413 * Drag cannot grab the pointer and will fail.
3415 if( m_nFloats
< 1 || bClosePopups
)
3416 gdk_display_pointer_ungrab( GtkSalFrame::getGdkDisplay(), GDK_CURRENT_TIME
);
3419 if( pThis
->m_bWindowIsGtkPlug
&&
3420 pEvent
->type
== GDK_BUTTON_PRESS
&&
3421 pEvent
->button
== 1 )
3423 pThis
->askForXEmbedFocus( pEvent
->time
);
3426 // --- RTL --- (mirror mouse pos)
3427 if( AllSettings::GetLayoutRTL() )
3428 aEvent
.mnX
= pThis
->maGeometry
.nWidth
-1-aEvent
.mnX
;
3430 vcl::DeletionListener
aDel( pThis
);
3432 pThis
->CallCallback( nEventType
, &aEvent
);
3434 if( ! aDel
.isDeleted() )
3438 ImplSVData
* pSVData
= ImplGetSVData();
3439 if ( pSVData
->maWinData
.mpFirstFloat
)
3441 static const char* pEnv
= getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
3442 if ( !(pSVData
->maWinData
.mpFirstFloat
->GetPopupModeFlags() & FloatWinPopupFlags::NoAppFocusClose
) && !(pEnv
&& *pEnv
) )
3443 pSVData
->maWinData
.mpFirstFloat
->EndPopupMode( FloatWinPopupEndFlags::Cancel
| FloatWinPopupEndFlags::CloseAll
);
3447 if( ! aDel
.isDeleted() )
3449 int frame_x
= (int)(pEvent
->x_root
- pEvent
->x
);
3450 int frame_y
= (int)(pEvent
->y_root
- pEvent
->y
);
3451 if( frame_x
!= pThis
->maGeometry
.nX
|| frame_y
!= pThis
->maGeometry
.nY
)
3453 pThis
->maGeometry
.nX
= frame_x
;
3454 pThis
->maGeometry
.nY
= frame_y
;
3455 pThis
->CallCallback( SALEVENT_MOVE
, NULL
);
3463 #if GTK_CHECK_VERSION(3,0,0)
3464 void GtkSalFrame::signalFlagsChanged( GtkWidget
* , GtkStateFlags state
, gpointer frame
)
3466 //TO-DO: This isn't as helpful as I'd like it to be. The color selector puts the main
3467 //windows into the backdrop, disabling everything, and the floating navigator window
3468 //is also problematic.
3469 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3471 bool bOldBackDrop
= state
& GTK_STATE_FLAG_BACKDROP
;
3472 bool bNewBackDrop
= (gtk_widget_get_state_flags(GTK_WIDGET(pThis
->m_pWindow
)) & GTK_STATE_FLAG_BACKDROP
);
3473 if (bNewBackDrop
&& !bOldBackDrop
)
3475 pThis
->GetWindow()->Disable();
3477 else if (bOldBackDrop
&& !bNewBackDrop
)
3479 pThis
->GetWindow()->Enable();
3484 gboolean
GtkSalFrame::signalScroll( GtkWidget
*, GdkEvent
* pEvent
, gpointer frame
)
3486 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3487 GdkEventScroll
* pSEvent
= reinterpret_cast<GdkEventScroll
*>(pEvent
);
3489 #if GTK_CHECK_VERSION(3,0,0)
3490 //TODO: do something less feeble here
3491 if (pSEvent
->direction
== GDK_SCROLL_SMOOTH
)
3495 static sal_uLong nLines
= 0;
3498 char* pEnv
= getenv( "SAL_WHEELLINES" );
3499 nLines
= pEnv
? atoi( pEnv
) : 3;
3501 nLines
= SAL_WHEELMOUSE_EVENT_PAGESCROLL
;
3504 bool bNeg
= (pSEvent
->direction
== GDK_SCROLL_DOWN
|| pSEvent
->direction
== GDK_SCROLL_RIGHT
);
3505 SalWheelMouseEvent aEvent
;
3506 aEvent
.mnTime
= pSEvent
->time
;
3507 aEvent
.mnX
= (sal_uLong
)pSEvent
->x
;
3508 aEvent
.mnY
= (sal_uLong
)pSEvent
->y
;
3509 aEvent
.mnDelta
= bNeg
? -120 : 120;
3510 aEvent
.mnNotchDelta
= bNeg
? -1 : 1;
3511 aEvent
.mnScrollLines
= nLines
;
3512 aEvent
.mnCode
= GetMouseModCode( pSEvent
->state
);
3513 aEvent
.mbHorz
= (pSEvent
->direction
== GDK_SCROLL_LEFT
|| pSEvent
->direction
== GDK_SCROLL_RIGHT
);
3515 // --- RTL --- (mirror mouse pos)
3516 if( AllSettings::GetLayoutRTL() )
3517 aEvent
.mnX
= pThis
->maGeometry
.nWidth
-1-aEvent
.mnX
;
3519 pThis
->CallCallback( SALEVENT_WHEELMOUSE
, &aEvent
);
3524 #if GTK_CHECK_VERSION(3,14,0)
3525 void GtkSalFrame::gestureSwipe(GtkGestureSwipe
* gesture
, gdouble velocity_x
, gdouble velocity_y
, gpointer frame
)
3527 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3529 SalSwipeEvent aEvent
;
3530 aEvent
.mnVelocityX
= velocity_x
;
3531 aEvent
.mnVelocityY
= velocity_y
;
3534 GdkEventSequence
*sequence
= gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture
));
3535 //I feel I want the first point of the sequence, not the last point which
3536 //the docs say this gives, but for the moment assume we start and end
3537 //within the same vcl window
3538 gtk_gesture_get_point(GTK_GESTURE(gesture
), sequence
, &x
, &y
);
3542 pThis
->CallCallback(SALEVENT_SWIPE
, &aEvent
);
3545 void GtkSalFrame::gestureLongPress(GtkGestureLongPress
* gesture
, gpointer frame
)
3547 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3551 SalLongPressEvent aEvent
;
3554 GdkEventSequence
*sequence
= gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture
));
3555 gtk_gesture_get_point(GTK_GESTURE(gesture
), sequence
, &x
, &y
);
3559 pThis
->CallCallback(SALEVENT_LONGPRESS
, &aEvent
);
3565 gboolean
GtkSalFrame::signalMotion( GtkWidget
*, GdkEventMotion
* pEvent
, gpointer frame
)
3567 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3569 SalMouseEvent aEvent
;
3570 aEvent
.mnTime
= pEvent
->time
;
3571 aEvent
.mnX
= (long)pEvent
->x_root
- pThis
->maGeometry
.nX
;
3572 aEvent
.mnY
= (long)pEvent
->y_root
- pThis
->maGeometry
.nY
;
3573 aEvent
.mnCode
= GetMouseModCode( pEvent
->state
);
3574 aEvent
.mnButton
= 0;
3576 // --- RTL --- (mirror mouse pos)
3577 if( AllSettings::GetLayoutRTL() )
3578 aEvent
.mnX
= pThis
->maGeometry
.nWidth
-1-aEvent
.mnX
;
3580 vcl::DeletionListener
aDel( pThis
);
3582 pThis
->CallCallback( SALEVENT_MOUSEMOVE
, &aEvent
);
3584 if( ! aDel
.isDeleted() )
3586 int frame_x
= (int)(pEvent
->x_root
- pEvent
->x
);
3587 int frame_y
= (int)(pEvent
->y_root
- pEvent
->y
);
3588 if( frame_x
!= pThis
->maGeometry
.nX
|| frame_y
!= pThis
->maGeometry
.nY
)
3590 pThis
->maGeometry
.nX
= frame_x
;
3591 pThis
->maGeometry
.nY
= frame_y
;
3592 pThis
->CallCallback( SALEVENT_MOVE
, NULL
);
3595 if( ! aDel
.isDeleted() )
3597 // ask for the next hint
3599 GdkModifierType mask
;
3600 gdk_window_get_pointer( widget_get_window(GTK_WIDGET(pThis
->m_pWindow
)), &x
, &y
, &mask
);
3607 gboolean
GtkSalFrame::signalCrossing( GtkWidget
*, GdkEventCrossing
* pEvent
, gpointer frame
)
3609 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3610 SalMouseEvent aEvent
;
3611 aEvent
.mnTime
= pEvent
->time
;
3612 aEvent
.mnX
= (long)pEvent
->x_root
- pThis
->maGeometry
.nX
;
3613 aEvent
.mnY
= (long)pEvent
->y_root
- pThis
->maGeometry
.nY
;
3614 aEvent
.mnCode
= GetMouseModCode( pEvent
->state
);
3615 aEvent
.mnButton
= 0;
3617 pThis
->CallCallback( (pEvent
->type
== GDK_ENTER_NOTIFY
) ? SALEVENT_MOUSEMOVE
: SALEVENT_MOUSELEAVE
, &aEvent
);
3622 #if GTK_CHECK_VERSION(3,0,0)
3624 cairo_t
* GtkSalFrame::getCairoContext() const
3626 cairo_t
* cr
= SvpSalGraphics::createCairoContext(m_aFrame
);
3631 void GtkSalFrame::damaged (const basegfx::B2IBox
& rDamageRect
)
3633 #if OSL_DEBUG_LEVEL > 1
3634 long long area
= rDamageRect
.getWidth() * rDamageRect
.getHeight();
3635 if( area
> 32 * 1024 )
3637 fprintf( stderr
, "bitmap damaged %d %d (%dx%d) area %lld widget\n",
3638 (int) rDamageRect
.getMinX(),
3639 (int) rDamageRect
.getMinY(),
3640 (int) rDamageRect
.getWidth(),
3641 (int) rDamageRect
.getHeight(),
3649 OString
tmp("/tmp/frame" + OString::number(frame
++) + ".png");
3650 cairo_t
* cr
= getCairoContext();
3651 cairo_surface_write_to_png(cairo_get_target(cr
), tmp
.getStr());
3655 gtk_widget_queue_draw_area(m_pWindow
,
3656 rDamageRect
.getMinX(),
3657 rDamageRect
.getMinY(),
3658 rDamageRect
.getWidth(),
3659 rDamageRect
.getHeight());
3662 // blit our backing basebmp buffer to the target cairo context cr
3663 gboolean
GtkSalFrame::signalDraw( GtkWidget
*, cairo_t
*cr
, gpointer frame
)
3665 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3669 cairo_t
* source
= pThis
->getCairoContext();
3670 cairo_surface_t
*pSurface
= cairo_get_target(source
);
3672 cairo_set_operator( cr
, CAIRO_OPERATOR_OVER
);
3673 cairo_set_source_surface(cr
, pSurface
, 0, 0);
3676 cairo_destroy(source
);
3680 cairo_surface_flush(cairo_get_target(cr
));
3685 void GtkSalFrame::sizeAllocated(GtkWidget
*, GdkRectangle
*pAllocation
, gpointer frame
)
3687 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3689 bool bSized
= false;
3691 if( pThis
->m_bFullscreen
|| (pThis
->m_nStyle
& (SAL_FRAME_STYLE_SIZEABLE
| SAL_FRAME_STYLE_PLUG
)) == SAL_FRAME_STYLE_SIZEABLE
)
3693 if( pAllocation
->width
!= (int)pThis
->maGeometry
.nWidth
|| pAllocation
->height
!= (int)pThis
->maGeometry
.nHeight
)
3696 pThis
->maGeometry
.nWidth
= pAllocation
->width
;
3697 pThis
->maGeometry
.nHeight
= pAllocation
->height
;
3703 pThis
->AllocateFrame();
3704 pThis
->CallCallback( SALEVENT_RESIZE
, nullptr );
3705 pThis
->TriggerPaintEvent();
3709 gboolean
GtkSalFrame::signalConfigure(GtkWidget
*, GdkEventConfigure
* pEvent
, gpointer frame
)
3711 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3712 pThis
->m_bPaintsBlocked
= false;
3714 bool bMoved
= false;
3715 int x
= pEvent
->x
, y
= pEvent
->y
;
3717 /* HACK: during sizing/moving a toolbar pThis->maGeometry is actually
3718 * already exact; even worse: due to the asynchronicity of configure
3719 * events the borderwindow which would evaluate this event
3720 * would size/move based on wrong data if we would actually evaluate
3721 * this event. So let's swallow it.
3723 if( (pThis
->m_nStyle
& SAL_FRAME_STYLE_OWNERDRAWDECORATION
) &&
3724 GtkSalFrame::getDisplay()->GetCaptureFrame() == pThis
)
3727 /* #i31785# claims we cannot trust the x,y members of the event;
3728 * they are e.g. not set correctly on maximize/demaximize;
3729 * yet the gdkdisplay-x11.c code handling configure_events has
3730 * done this XTranslateCoordinates work since the day ~zero.
3732 if( x
!= pThis
->maGeometry
.nX
|| y
!= pThis
->maGeometry
.nY
)
3735 pThis
->maGeometry
.nX
= x
;
3736 pThis
->maGeometry
.nY
= y
;
3739 // update decoration hints
3740 if( ! (pThis
->m_nStyle
& SAL_FRAME_STYLE_PLUG
) )
3743 gdk_window_get_frame_extents( widget_get_window(GTK_WIDGET(pThis
->m_pWindow
)), &aRect
);
3744 pThis
->maGeometry
.nTopDecoration
= y
- aRect
.y
;
3745 pThis
->maGeometry
.nBottomDecoration
= aRect
.y
+ aRect
.height
- y
- pEvent
->height
;
3746 pThis
->maGeometry
.nLeftDecoration
= x
- aRect
.x
;
3747 pThis
->maGeometry
.nRightDecoration
= aRect
.x
+ aRect
.width
- x
- pEvent
->width
;
3751 pThis
->maGeometry
.nTopDecoration
=
3752 pThis
->maGeometry
.nBottomDecoration
=
3753 pThis
->maGeometry
.nLeftDecoration
=
3754 pThis
->maGeometry
.nRightDecoration
= 0;
3757 pThis
->updateScreenNumber();
3760 pThis
->CallCallback(SALEVENT_MOVE
, nullptr);
3765 gboolean
GtkSalFrame::signalExpose( GtkWidget
*, GdkEventExpose
* pEvent
, gpointer frame
)
3767 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3768 pThis
->m_bPaintsBlocked
= false;
3770 struct SalPaintEvent
aEvent( pEvent
->area
.x
, pEvent
->area
.y
, pEvent
->area
.width
, pEvent
->area
.height
);
3772 pThis
->CallCallback( SALEVENT_PAINT
, &aEvent
);
3777 gboolean
GtkSalFrame::signalConfigure( GtkWidget
*, GdkEventConfigure
* pEvent
, gpointer frame
)
3779 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3780 pThis
->m_bPaintsBlocked
= false;
3782 bool bMoved
= false, bSized
= false;
3783 int x
= pEvent
->x
, y
= pEvent
->y
;
3785 /* HACK: during sizing/moving a toolbar pThis->maGeometry is actually
3786 * already exact; even worse: due to the asynchronicity of configure
3787 * events the borderwindow which would evaluate this event
3788 * would size/move based on wrong data if we would actually evaluate
3789 * this event. So let's swallow it.
3791 if( (pThis
->m_nStyle
& SAL_FRAME_STYLE_OWNERDRAWDECORATION
) &&
3792 GtkSalFrame::getDisplay()->GetCaptureFrame() == pThis
)
3795 /* #i31785# claims we cannot trust the x,y members of the event;
3796 * they are e.g. not set correctly on maximize/demaximize;
3797 * yet the gdkdisplay-x11.c code handling configure_events has
3798 * done this XTranslateCoordinates work since the day ~zero.
3800 if( x
!= pThis
->maGeometry
.nX
|| y
!= pThis
->maGeometry
.nY
)
3803 pThis
->maGeometry
.nX
= x
;
3804 pThis
->maGeometry
.nY
= y
;
3807 * for non sizeable windows we set the min and max hint for the window manager to
3808 * achieve correct sizing. However this is asynchronous and e.g. on Compiz
3809 * it sometimes happens that the window gets resized to another size (some default)
3810 * if we update the size here, subsequent setMinMaxSize will use this wrong size
3811 * - which is not good since the window manager will now size the window back to this
3812 * wrong size at some point.
3814 if( pThis
->m_bFullscreen
|| (pThis
->m_nStyle
& (SAL_FRAME_STYLE_SIZEABLE
| SAL_FRAME_STYLE_PLUG
)) == SAL_FRAME_STYLE_SIZEABLE
)
3816 if( pEvent
->width
!= (int)pThis
->maGeometry
.nWidth
|| pEvent
->height
!= (int)pThis
->maGeometry
.nHeight
)
3819 pThis
->maGeometry
.nWidth
= pEvent
->width
;
3820 pThis
->maGeometry
.nHeight
= pEvent
->height
;
3824 // update decoration hints
3825 if( ! (pThis
->m_nStyle
& SAL_FRAME_STYLE_PLUG
) )
3828 gdk_window_get_frame_extents( widget_get_window(GTK_WIDGET(pThis
->m_pWindow
)), &aRect
);
3829 pThis
->maGeometry
.nTopDecoration
= y
- aRect
.y
;
3830 pThis
->maGeometry
.nBottomDecoration
= aRect
.y
+ aRect
.height
- y
- pEvent
->height
;
3831 pThis
->maGeometry
.nLeftDecoration
= x
- aRect
.x
;
3832 pThis
->maGeometry
.nRightDecoration
= aRect
.x
+ aRect
.width
- x
- pEvent
->width
;
3836 pThis
->maGeometry
.nTopDecoration
=
3837 pThis
->maGeometry
.nBottomDecoration
=
3838 pThis
->maGeometry
.nLeftDecoration
=
3839 pThis
->maGeometry
.nRightDecoration
= 0;
3842 pThis
->updateScreenNumber();
3844 pThis
->AllocateFrame();
3846 if( bMoved
&& bSized
)
3847 pThis
->CallCallback( SALEVENT_MOVERESIZE
, nullptr );
3849 pThis
->CallCallback( SALEVENT_MOVE
, nullptr );
3851 pThis
->CallCallback( SALEVENT_RESIZE
, nullptr );
3854 pThis
->TriggerPaintEvent();
3858 #endif // GTK_CHECK_VERSION(3,0,0)
3860 void GtkSalFrame::TriggerPaintEvent()
3862 //Under gtk2 we can basically paint directly into the XWindow and on
3863 //additional "expose-event" events we can re-render the missing pieces
3865 //Under gtk3 we have to keep our own buffer up to date and flush it into
3866 //the given cairo context on "draw". So we emit a paint event on
3867 //opportune resize trigger events to initially fill our backbuffer and then
3868 //keep it up to date with our direct paints and tell gtk those regions
3869 //have changed and then blit them into the provided cairo context when
3872 //The other alternative was to always paint everything on "draw", but
3873 //that duplicates the amount of drawing and is hideously slow
3874 #if GTK_CHECK_VERSION(3,0,0)
3875 SAL_INFO("vcl.gtk3", "force painting" << 0 << "," << 0 << " " << maGeometry
.nWidth
<< "x" << maGeometry
.nHeight
);
3876 SalPaintEvent
aPaintEvt(0, 0, maGeometry
.nWidth
, maGeometry
.nHeight
, true);
3877 CallCallback(SALEVENT_PAINT
, &aPaintEvt
);
3878 gtk_widget_queue_draw(m_pWindow
);
3882 gboolean
GtkSalFrame::signalFocus( GtkWidget
*, GdkEventFocus
* pEvent
, gpointer frame
)
3884 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3886 SalGenericInstance
*pSalInstance
=
3887 static_cast< SalGenericInstance
* >(GetSalData()->m_pInstance
);
3889 // check if printers have changed (analogous to salframe focus handler)
3890 pSalInstance
->updatePrinterUpdate();
3894 pThis
->m_nKeyModifiers
= 0;
3895 pThis
->m_bSendModChangeOnRelease
= false;
3898 if( pThis
->m_pIMHandler
)
3899 pThis
->m_pIMHandler
->focusChanged( pEvent
->in
);
3901 // ask for changed printers like generic implementation
3902 if( pEvent
->in
&& pSalInstance
->isPrinterInit() )
3903 pSalInstance
->updatePrinterUpdate();
3905 // FIXME: find out who the hell steals the focus from our frame
3906 // while we have the pointer grabbed, this should not come from
3907 // the window manager. Is this an event that was still queued ?
3908 // The focus does not seem to get set inside our process
3910 // in the meantime do not propagate focus get/lose if floats are open
3911 if( m_nFloats
== 0 )
3912 pThis
->CallCallback( pEvent
->in
? SALEVENT_GETFOCUS
: SALEVENT_LOSEFOCUS
, NULL
);
3917 #if !GTK_CHECK_VERSION(3,8,0)
3918 static OString
getDisplayString()
3920 int nParams
= rtl_getAppCommandArgCount();
3922 for( int i
= 0; i
< nParams
; i
++ )
3924 rtl_getAppCommandArg( i
, &aParam
.pData
);
3925 if( i
< nParams
-1 && (aParam
== "-display" || aParam
== "--display" ) )
3927 rtl_getAppCommandArg( i
+1, &aParam
.pData
);
3928 return OUStringToOString( aParam
, osl_getThreadTextEncoding() );
3935 gboolean
GtkSalFrame::signalMap( GtkWidget
*pWidget
, GdkEvent
*, gpointer frame
)
3937 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3939 #if !GTK_CHECK_VERSION(3,8,0)
3940 //Spawn off a helper program that will attempt to set this fullscreen
3941 //window to span all displays.
3942 if (pThis
->m_bFullscreen
&& pThis
->m_bSpanMonitorsWhenFullscreen
)
3944 GdkWindow
* gdkwin
= widget_get_window(pThis
->m_pWindow
);
3947 OUString
sProgramURL( "$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER
"/xid-fullscreen-on-all-monitors");
3948 rtl::Bootstrap::expandMacros(sProgramURL
);
3950 if (osl::FileBase::getSystemPathFromFileURL(sProgramURL
, sProgram
) == osl::File::E_None
)
3952 OString
sFinalProgram(OUStringToOString(sProgram
, osl_getThreadTextEncoding())
3953 + " " + OString::number((int)GDK_WINDOW_XID(gdkwin
)));
3954 OString
sDisplay(getDisplayString());
3955 if (!sDisplay
.isEmpty())
3957 sFinalProgram
+= "--display " + sDisplay
;
3959 int returnValue
= system(sFinalProgram
.getStr());
3966 bool bSetFocus
= pThis
->m_bSetFocusOnMap
;
3967 pThis
->m_bSetFocusOnMap
= false;
3969 #if !GTK_CHECK_VERSION(3,0,0)
3972 GetGenericData()->ErrorTrapPush();
3973 XSetInputFocus( GtkSalFrame::getDisplay()->GetDisplay(),
3974 widget_get_xid(pWidget
),
3975 RevertToParent
, CurrentTime
);
3976 XSync( GtkSalFrame::getDisplay()->GetDisplay(), False
);
3977 GetGenericData()->ErrorTrapPop();
3980 (void)pWidget
; (void)bSetFocus
;
3981 //FIXME: no set input focus ...
3984 pThis
->CallCallback( SALEVENT_RESIZE
, NULL
);
3985 pThis
->TriggerPaintEvent();
3990 gboolean
GtkSalFrame::signalUnmap( GtkWidget
*, GdkEvent
*, gpointer frame
)
3992 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
3994 pThis
->CallCallback( SALEVENT_RESIZE
, NULL
);
3999 gboolean
GtkSalFrame::signalKey( GtkWidget
*, GdkEventKey
* pEvent
, gpointer frame
)
4001 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
4003 vcl::DeletionListener
aDel( pThis
);
4005 if( pThis
->m_pIMHandler
)
4007 if( pThis
->m_pIMHandler
->handleKeyEvent( pEvent
) )
4012 if( pEvent
->keyval
== GDK_Shift_L
|| pEvent
->keyval
== GDK_Shift_R
||
4013 pEvent
->keyval
== GDK_Control_L
|| pEvent
->keyval
== GDK_Control_R
||
4014 pEvent
->keyval
== GDK_Alt_L
|| pEvent
->keyval
== GDK_Alt_R
||
4015 pEvent
->keyval
== GDK_Meta_L
|| pEvent
->keyval
== GDK_Meta_R
||
4016 pEvent
->keyval
== GDK_Super_L
|| pEvent
->keyval
== GDK_Super_R
)
4018 SalKeyModEvent aModEvt
;
4020 sal_uInt16 nModCode
= GetKeyModCode( pEvent
->state
);
4022 aModEvt
.mnModKeyCode
= 0; // emit no MODKEYCHANGE events
4023 if( pEvent
->type
== GDK_KEY_PRESS
&& !pThis
->m_nKeyModifiers
)
4024 pThis
->m_bSendModChangeOnRelease
= true;
4026 else if( pEvent
->type
== GDK_KEY_RELEASE
&&
4027 pThis
->m_bSendModChangeOnRelease
)
4029 aModEvt
.mnModKeyCode
= pThis
->m_nKeyModifiers
;
4030 pThis
->m_nKeyModifiers
= 0;
4033 sal_uInt16 nExtModMask
= 0;
4034 sal_uInt16 nModMask
= 0;
4035 // pressing just the ctrl key leads to a keysym of XK_Control but
4036 // the event state does not contain ControlMask. In the release
4037 // event its the other way round: it does contain the Control mask.
4038 // The modifier mode therefore has to be adapted manually.
4039 switch( pEvent
->keyval
)
4042 nExtModMask
= MODKEY_LMOD1
;
4043 nModMask
= KEY_MOD1
;
4046 nExtModMask
= MODKEY_RMOD1
;
4047 nModMask
= KEY_MOD1
;
4050 nExtModMask
= MODKEY_LMOD2
;
4051 nModMask
= KEY_MOD2
;
4054 nExtModMask
= MODKEY_RMOD2
;
4055 nModMask
= KEY_MOD2
;
4058 nExtModMask
= MODKEY_LSHIFT
;
4059 nModMask
= KEY_SHIFT
;
4062 nExtModMask
= MODKEY_RSHIFT
;
4063 nModMask
= KEY_SHIFT
;
4065 // Map Meta/Super to MOD3 modifier on all Unix systems
4069 nExtModMask
= MODKEY_LMOD3
;
4070 nModMask
= KEY_MOD3
;
4074 nExtModMask
= MODKEY_RMOD3
;
4075 nModMask
= KEY_MOD3
;
4078 if( pEvent
->type
== GDK_KEY_RELEASE
)
4080 nModCode
&= ~nModMask
;
4081 pThis
->m_nKeyModifiers
&= ~nExtModMask
;
4085 nModCode
|= nModMask
;
4086 pThis
->m_nKeyModifiers
|= nExtModMask
;
4089 aModEvt
.mnCode
= nModCode
;
4090 aModEvt
.mnTime
= pEvent
->time
;
4092 pThis
->CallCallback( SALEVENT_KEYMODCHANGE
, &aModEvt
);
4097 pThis
->doKeyCallback( pEvent
->state
,
4099 pEvent
->hardware_keycode
,
4102 sal_Unicode(gdk_keyval_to_unicode( pEvent
->keyval
)),
4103 (pEvent
->type
== GDK_KEY_PRESS
),
4105 if( ! aDel
.isDeleted() )
4106 pThis
->m_bSendModChangeOnRelease
= false;
4109 if( !aDel
.isDeleted() && pThis
->m_pIMHandler
)
4110 pThis
->m_pIMHandler
->updateIMSpotLocation();
4115 gboolean
GtkSalFrame::signalDelete( GtkWidget
*, GdkEvent
*, gpointer frame
)
4117 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
4119 #if GTK_CHECK_VERSION(3,0,0)
4120 //If we went into the backdrop we disabled the toplevel window, if we
4121 //receive a delete here, re-enable so we can process it
4122 bool bBackDrop
= (gtk_widget_get_state_flags(GTK_WIDGET(pThis
->m_pWindow
)) & GTK_STATE_FLAG_BACKDROP
);
4124 pThis
->GetWindow()->Enable();
4127 pThis
->CallCallback( SALEVENT_CLOSE
, NULL
);
4132 void GtkSalFrame::signalStyleSet( GtkWidget
*, GtkStyle
* pPrevious
, gpointer frame
)
4134 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
4136 // every frame gets an initial style set on creation
4137 // do not post these as the whole application tends to
4138 // redraw itself to adjust to the new style
4139 // where there IS no new style resulting in tremendous unnecessary flickering
4140 if( pPrevious
!= NULL
)
4142 // signalStyleSet does NOT usually have the gdk lock
4143 // so post user event to safely dispatch the SALEVENT_SETTINGSCHANGED
4144 // note: settings changed for multiple frames is avoided in winproc.cxx ImplHandleSettings
4145 GtkSalFrame::getDisplay()->SendInternalEvent( pThis
, NULL
, SALEVENT_SETTINGSCHANGED
);
4146 GtkSalFrame::getDisplay()->SendInternalEvent( pThis
, NULL
, SALEVENT_FONTCHANGED
);
4149 #if !GTK_CHECK_VERSION(3,0,0)
4150 /* #i64117# gtk sets a nice background pixmap
4151 * but we actually don't really want that, so save
4152 * some time on the Xserver as well as prevent
4155 GdkWindow
* pWin
= widget_get_window(GTK_WIDGET(pThis
->getWindow()));
4158 ::Window aWin
= GDK_WINDOW_XWINDOW(pWin
);
4160 XSetWindowBackgroundPixmap( GtkSalFrame::getDisplay()->GetDisplay(),
4162 pThis
->m_hBackgroundPixmap
);
4164 if( ! pThis
->m_pParent
)
4166 // signalize theme changed for NWF caches
4167 // FIXME: should be called only once for a style change
4168 GtkSalGraphics::bThemeChanged
= true;
4173 gboolean
GtkSalFrame::signalWindowState( GtkWidget
*, GdkEvent
* pEvent
, gpointer frame
)
4175 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
4176 if( (pThis
->m_nState
& GDK_WINDOW_STATE_ICONIFIED
) != (pEvent
->window_state
.new_window_state
& GDK_WINDOW_STATE_ICONIFIED
) )
4178 GtkSalFrame::getDisplay()->SendInternalEvent( pThis
, NULL
, SALEVENT_RESIZE
);
4179 pThis
->TriggerPaintEvent();
4182 if( (pEvent
->window_state
.new_window_state
& GDK_WINDOW_STATE_MAXIMIZED
) &&
4183 ! (pThis
->m_nState
& GDK_WINDOW_STATE_MAXIMIZED
) )
4185 pThis
->m_aRestorePosSize
=
4186 Rectangle( Point( pThis
->maGeometry
.nX
, pThis
->maGeometry
.nY
),
4187 Size( pThis
->maGeometry
.nWidth
, pThis
->maGeometry
.nHeight
) );
4189 pThis
->m_nState
= pEvent
->window_state
.new_window_state
;
4191 #if OSL_DEBUG_LEVEL > 1
4192 if( (pEvent
->window_state
.changed_mask
& GDK_WINDOW_STATE_FULLSCREEN
) )
4194 fprintf( stderr
, "window %p %s full screen state\n",
4196 (pEvent
->window_state
.new_window_state
& GDK_WINDOW_STATE_FULLSCREEN
) ? "enters" : "leaves");
4203 gboolean
GtkSalFrame::signalVisibility( GtkWidget
*, GdkEventVisibility
* pEvent
, gpointer frame
)
4205 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
4206 pThis
->m_nVisibility
= pEvent
->state
;
4210 void GtkSalFrame::signalDestroy( GtkWidget
* pObj
, gpointer frame
)
4212 GtkSalFrame
* pThis
= static_cast<GtkSalFrame
*>(frame
);
4213 if( pObj
== pThis
->m_pWindow
)
4215 pThis
->m_pFixedContainer
= NULL
;
4216 pThis
->m_pWindow
= NULL
;
4217 pThis
->InvalidateGraphics();
4221 // GtkSalFrame::IMHandler
4223 GtkSalFrame::IMHandler::IMHandler( GtkSalFrame
* pFrame
)
4225 m_nPrevKeyPresses( 0 ),
4226 m_pIMContext( NULL
),
4228 m_bPreeditJustChanged( false )
4230 m_aInputEvent
.mpTextAttr
= NULL
;
4234 GtkSalFrame::IMHandler::~IMHandler()
4236 // cancel an eventual event posted to begin preedit again
4237 GtkSalFrame::getDisplay()->CancelInternalEvent( m_pFrame
, &m_aInputEvent
, SALEVENT_EXTTEXTINPUT
);
4241 void GtkSalFrame::IMHandler::createIMContext()
4243 if( ! m_pIMContext
)
4245 m_pIMContext
= gtk_im_multicontext_new ();
4246 g_signal_connect( m_pIMContext
, "commit",
4247 G_CALLBACK (signalIMCommit
), this );
4248 g_signal_connect( m_pIMContext
, "preedit_changed",
4249 G_CALLBACK (signalIMPreeditChanged
), this );
4250 g_signal_connect( m_pIMContext
, "retrieve_surrounding",
4251 G_CALLBACK (signalIMRetrieveSurrounding
), this );
4252 g_signal_connect( m_pIMContext
, "delete_surrounding",
4253 G_CALLBACK (signalIMDeleteSurrounding
), this );
4254 g_signal_connect( m_pIMContext
, "preedit_start",
4255 G_CALLBACK (signalIMPreeditStart
), this );
4256 g_signal_connect( m_pIMContext
, "preedit_end",
4257 G_CALLBACK (signalIMPreeditEnd
), this );
4259 GetGenericData()->ErrorTrapPush();
4260 gtk_im_context_set_client_window( m_pIMContext
, widget_get_window(GTK_WIDGET(m_pFrame
->m_pWindow
)) );
4261 gtk_im_context_focus_in( m_pIMContext
);
4262 GetGenericData()->ErrorTrapPop();
4267 void GtkSalFrame::IMHandler::deleteIMContext()
4271 // first give IC a chance to deinitialize
4272 GetGenericData()->ErrorTrapPush();
4273 gtk_im_context_set_client_window( m_pIMContext
, NULL
);
4274 GetGenericData()->ErrorTrapPop();
4276 g_object_unref( m_pIMContext
);
4277 m_pIMContext
= NULL
;
4281 void GtkSalFrame::IMHandler::doCallEndExtTextInput()
4283 m_aInputEvent
.mpTextAttr
= NULL
;
4284 m_pFrame
->CallCallback( SALEVENT_ENDEXTTEXTINPUT
, NULL
);
4287 void GtkSalFrame::IMHandler::updateIMSpotLocation()
4289 SalExtTextInputPosEvent aPosEvent
;
4290 m_pFrame
->CallCallback( SALEVENT_EXTTEXTINPUTPOS
, (void*)&aPosEvent
);
4292 aArea
.x
= aPosEvent
.mnX
;
4293 aArea
.y
= aPosEvent
.mnY
;
4294 aArea
.width
= aPosEvent
.mnWidth
;
4295 aArea
.height
= aPosEvent
.mnHeight
;
4296 GetGenericData()->ErrorTrapPush();
4297 gtk_im_context_set_cursor_location( m_pIMContext
, &aArea
);
4298 GetGenericData()->ErrorTrapPop();
4301 void GtkSalFrame::IMHandler::sendEmptyCommit()
4303 vcl::DeletionListener
aDel( m_pFrame
);
4305 SalExtTextInputEvent aEmptyEv
;
4306 aEmptyEv
.mnTime
= 0;
4307 aEmptyEv
.mpTextAttr
= 0;
4308 aEmptyEv
.maText
.clear();
4309 aEmptyEv
.mnCursorPos
= 0;
4310 aEmptyEv
.mnCursorFlags
= 0;
4311 aEmptyEv
.mbOnlyCursor
= False
;
4312 m_pFrame
->CallCallback( SALEVENT_EXTTEXTINPUT
, (void*)&aEmptyEv
);
4313 if( ! aDel
.isDeleted() )
4314 m_pFrame
->CallCallback( SALEVENT_ENDEXTTEXTINPUT
, NULL
);
4317 void GtkSalFrame::IMHandler::endExtTextInput( sal_uInt16
/*nFlags*/ )
4319 gtk_im_context_reset ( m_pIMContext
);
4321 if( m_aInputEvent
.mpTextAttr
)
4323 vcl::DeletionListener
aDel( m_pFrame
);
4324 // delete preedit in sal (commit an empty string)
4326 if( ! aDel
.isDeleted() )
4328 // mark previous preedit state again (will e.g. be sent at focus gain)
4329 m_aInputEvent
.mpTextAttr
= &m_aInputFlags
[0];
4332 // begin preedit again
4333 GtkSalFrame::getDisplay()->SendInternalEvent( m_pFrame
, &m_aInputEvent
, SALEVENT_EXTTEXTINPUT
);
4339 void GtkSalFrame::IMHandler::focusChanged( bool bFocusIn
)
4341 m_bFocused
= bFocusIn
;
4344 GetGenericData()->ErrorTrapPush();
4345 gtk_im_context_focus_in( m_pIMContext
);
4346 GetGenericData()->ErrorTrapPop();
4347 if( m_aInputEvent
.mpTextAttr
)
4350 // begin preedit again
4351 GtkSalFrame::getDisplay()->SendInternalEvent( m_pFrame
, &m_aInputEvent
, SALEVENT_EXTTEXTINPUT
);
4356 GetGenericData()->ErrorTrapPush();
4357 gtk_im_context_focus_out( m_pIMContext
);
4358 GetGenericData()->ErrorTrapPop();
4359 // cancel an eventual event posted to begin preedit again
4360 GtkSalFrame::getDisplay()->CancelInternalEvent( m_pFrame
, &m_aInputEvent
, SALEVENT_EXTTEXTINPUT
);
4364 bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey
* pEvent
)
4366 vcl::DeletionListener
aDel( m_pFrame
);
4368 if( pEvent
->type
== GDK_KEY_PRESS
)
4370 // Add this key press event to the list of previous key presses
4371 // to which we compare key release events. If a later key release
4372 // event has a matching key press event in this list, we swallow
4373 // the key release because some GTK Input Methods don't swallow it
4375 m_aPrevKeyPresses
.push_back( PreviousKeyPress(pEvent
) );
4376 m_nPrevKeyPresses
++;
4378 // Also pop off the earliest key press event if there are more than 10
4380 while (m_nPrevKeyPresses
> 10)
4382 m_aPrevKeyPresses
.pop_front();
4383 m_nPrevKeyPresses
--;
4386 GObject
* pRef
= G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext
) ) );
4388 // #i51353# update spot location on every key input since we cannot
4389 // know which key may activate a preedit choice window
4390 updateIMSpotLocation();
4391 if( aDel
.isDeleted() )
4394 gboolean bResult
= gtk_im_context_filter_keypress( m_pIMContext
, pEvent
);
4395 g_object_unref( pRef
);
4397 if( aDel
.isDeleted() )
4400 m_bPreeditJustChanged
= false;
4406 DBG_ASSERT( m_nPrevKeyPresses
> 0, "key press has vanished !" );
4407 if( ! m_aPrevKeyPresses
.empty() ) // sanity check
4409 // event was not swallowed, do not filter a following
4410 // key release event
4411 // note: this relies on gtk_im_context_filter_keypress
4412 // returning without calling a handler (in the "not swallowed"
4413 // case ) which might change the previous key press list so
4414 // we would pop the wrong event here
4415 m_aPrevKeyPresses
.pop_back();
4416 m_nPrevKeyPresses
--;
4421 // Determine if we got an earlier key press event corresponding to this key release
4422 if (pEvent
->type
== GDK_KEY_RELEASE
)
4424 GObject
* pRef
= G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext
) ) );
4425 gboolean bResult
= gtk_im_context_filter_keypress( m_pIMContext
, pEvent
);
4426 g_object_unref( pRef
);
4428 if( aDel
.isDeleted() )
4431 m_bPreeditJustChanged
= false;
4433 std::list
<PreviousKeyPress
>::iterator iter
= m_aPrevKeyPresses
.begin();
4434 std::list
<PreviousKeyPress
>::iterator iter_end
= m_aPrevKeyPresses
.end();
4435 while (iter
!= iter_end
)
4437 // If we found a corresponding previous key press event, swallow the release
4438 // and remove the earlier key press from our list
4439 if (*iter
== pEvent
)
4441 m_aPrevKeyPresses
.erase(iter
);
4442 m_nPrevKeyPresses
--;
4456 * #122282# still more hacking: some IMEs never start a preedit but simply commit
4457 * in this case we cannot commit a single character. Workaround: do not do the
4458 * single key hack for enter or space if the unicode committed does not match
4461 static bool checkSingleKeyCommitHack( guint keyval
, sal_Unicode cCode
)
4468 if( cCode
!= '\n' && cCode
!= '\r' )
4482 void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext
* pContext
, gchar
* pText
, gpointer im_handler
)
4484 GtkSalFrame::IMHandler
* pThis
= static_cast<GtkSalFrame::IMHandler
*>(im_handler
);
4486 SolarMutexGuard aGuard
;
4487 vcl::DeletionListener
aDel( pThis
->m_pFrame
);
4489 const bool bWasPreedit
=
4490 (pThis
->m_aInputEvent
.mpTextAttr
!= 0) ||
4491 pThis
->m_bPreeditJustChanged
;
4493 pThis
->m_aInputEvent
.mnTime
= 0;
4494 pThis
->m_aInputEvent
.mpTextAttr
= 0;
4495 pThis
->m_aInputEvent
.maText
= OUString( pText
, strlen(pText
), RTL_TEXTENCODING_UTF8
);
4496 pThis
->m_aInputEvent
.mnCursorPos
= pThis
->m_aInputEvent
.maText
.getLength();
4497 pThis
->m_aInputEvent
.mnCursorFlags
= 0;
4498 pThis
->m_aInputEvent
.mbOnlyCursor
= False
;
4500 pThis
->m_aInputFlags
.clear();
4502 /* necessary HACK: all keyboard input comes in here as soon as a IMContext is set
4503 * which is logical and consequent. But since even simple input like
4504 * <space> comes through the commit signal instead of signalKey
4505 * and all kinds of windows only implement KeyInput (e.g. PushButtons,
4506 * RadioButtons and a lot of other Controls), will send a single
4507 * KeyInput/KeyUp sequence instead of an ExtText event if there
4508 * never was a preedit and the text is only one character.
4510 * In this case there the last ExtText event must have been
4511 * SALEVENT_ENDEXTTEXTINPUT, either because of a regular commit
4512 * or because there never was a preedit.
4514 bool bSingleCommit
= false;
4516 && pThis
->m_aInputEvent
.maText
.getLength() == 1
4517 && ! pThis
->m_aPrevKeyPresses
.empty()
4520 const PreviousKeyPress
& rKP
= pThis
->m_aPrevKeyPresses
.back();
4521 sal_Unicode aOrigCode
= pThis
->m_aInputEvent
.maText
[0];
4523 if( checkSingleKeyCommitHack( rKP
.keyval
, aOrigCode
) )
4525 pThis
->m_pFrame
->doKeyCallback( rKP
.state
, rKP
.keyval
, rKP
.hardware_keycode
, rKP
.group
, rKP
.time
, aOrigCode
, true, true );
4526 bSingleCommit
= true;
4529 if( ! bSingleCommit
)
4531 pThis
->m_pFrame
->CallCallback( SALEVENT_EXTTEXTINPUT
, (void*)&pThis
->m_aInputEvent
);
4532 if( ! aDel
.isDeleted() )
4533 pThis
->doCallEndExtTextInput();
4535 if( ! aDel
.isDeleted() )
4537 // reset input event
4538 pThis
->m_aInputEvent
.maText
.clear();
4539 pThis
->m_aInputEvent
.mnCursorPos
= 0;
4540 pThis
->updateIMSpotLocation();
4544 // #i51356# workaround a solaris IIIMP bug
4545 // in case of partial commits the preedit changed signal
4546 // and commit signal come in wrong order
4547 if( ! aDel
.isDeleted() )
4548 signalIMPreeditChanged( pContext
, im_handler
);
4554 void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext
*, gpointer im_handler
)
4556 GtkSalFrame::IMHandler
* pThis
= static_cast<GtkSalFrame::IMHandler
*>(im_handler
);
4559 PangoAttrList
* pAttrs
= NULL
;
4560 gint nCursorPos
= 0;
4562 gtk_im_context_get_preedit_string( pThis
->m_pIMContext
,
4566 if( pText
&& ! *pText
) // empty string
4568 // change from nothing to nothing -> do not start preedit
4569 // e.g. this will activate input into a calc cell without
4571 if( pThis
->m_aInputEvent
.maText
.getLength() == 0 )
4574 pango_attr_list_unref( pAttrs
);
4579 pThis
->m_bPreeditJustChanged
= true;
4581 bool bEndPreedit
= (!pText
|| !*pText
) && pThis
->m_aInputEvent
.mpTextAttr
!= NULL
;
4582 pThis
->m_aInputEvent
.mnTime
= 0;
4583 pThis
->m_aInputEvent
.maText
= pText
? OUString( pText
, strlen(pText
), RTL_TEXTENCODING_UTF8
) : OUString();
4584 pThis
->m_aInputEvent
.mnCursorPos
= nCursorPos
;
4585 pThis
->m_aInputEvent
.mnCursorFlags
= 0;
4586 pThis
->m_aInputEvent
.mbOnlyCursor
= False
;
4588 pThis
->m_aInputFlags
= std::vector
<sal_uInt16
>( std::max( 1, (int)pThis
->m_aInputEvent
.maText
.getLength() ), 0 );
4590 PangoAttrIterator
*iter
= pango_attr_list_get_iterator(pAttrs
);
4593 GSList
*attr_list
= NULL
;
4594 GSList
*tmp_list
= NULL
;
4598 pango_attr_iterator_range (iter
, &start
, &end
);
4599 if (end
== G_MAXINT
)
4600 end
= pText
? strlen (pText
) : 0;
4604 start
= g_utf8_pointer_to_offset (pText
, pText
+ start
);
4605 end
= g_utf8_pointer_to_offset (pText
, pText
+ end
);
4607 tmp_list
= attr_list
= pango_attr_iterator_get_attrs (iter
);
4610 PangoAttribute
*pango_attr
= static_cast<PangoAttribute
*>(tmp_list
->data
);
4612 switch (pango_attr
->klass
->type
)
4614 case PANGO_ATTR_BACKGROUND
:
4615 sal_attr
|= (EXTTEXTINPUT_ATTR_HIGHLIGHT
| EXTTEXTINPUT_CURSOR_INVISIBLE
);
4617 case PANGO_ATTR_UNDERLINE
:
4618 sal_attr
|= EXTTEXTINPUT_ATTR_UNDERLINE
;
4620 case PANGO_ATTR_STRIKETHROUGH
:
4621 sal_attr
|= EXTTEXTINPUT_ATTR_REDTEXT
;
4626 pango_attribute_destroy (pango_attr
);
4627 tmp_list
= tmp_list
->next
;
4630 sal_attr
|= EXTTEXTINPUT_ATTR_UNDERLINE
;
4631 g_slist_free (attr_list
);
4633 // Set the sal attributes on our text
4634 for (int i
= start
; i
< end
; ++i
)
4636 SAL_WARN_IF(i
>= static_cast<int>(pThis
->m_aInputFlags
.size()),
4637 "vcl.gtk", "pango attrib out of range. Broken range: "
4638 << start
<< "," << end
<< " Legal range: 0,"
4639 << pThis
->m_aInputFlags
.size());
4640 if (i
>= static_cast<int>(pThis
->m_aInputFlags
.size()))
4642 pThis
->m_aInputFlags
[i
] |= sal_attr
;
4644 } while (pango_attr_iterator_next (iter
));
4645 pango_attr_iterator_destroy(iter
);
4647 pThis
->m_aInputEvent
.mpTextAttr
= &pThis
->m_aInputFlags
[0];
4650 pango_attr_list_unref( pAttrs
);
4652 SolarMutexGuard aGuard
;
4653 vcl::DeletionListener
aDel( pThis
->m_pFrame
);
4655 pThis
->m_pFrame
->CallCallback( SALEVENT_EXTTEXTINPUT
, (void*)&pThis
->m_aInputEvent
);
4656 if( bEndPreedit
&& ! aDel
.isDeleted() )
4657 pThis
->doCallEndExtTextInput();
4658 if( ! aDel
.isDeleted() )
4659 pThis
->updateIMSpotLocation();
4662 void GtkSalFrame::IMHandler::signalIMPreeditStart( GtkIMContext
*, gpointer
/*im_handler*/ )
4666 void GtkSalFrame::IMHandler::signalIMPreeditEnd( GtkIMContext
*, gpointer im_handler
)
4668 GtkSalFrame::IMHandler
* pThis
= static_cast<GtkSalFrame::IMHandler
*>(im_handler
);
4670 pThis
->m_bPreeditJustChanged
= true;
4672 SolarMutexGuard aGuard
;
4673 vcl::DeletionListener
aDel( pThis
->m_pFrame
);
4674 pThis
->doCallEndExtTextInput();
4675 if( ! aDel
.isDeleted() )
4676 pThis
->updateIMSpotLocation();
4679 uno::Reference
<accessibility::XAccessibleEditableText
>
4680 FindFocus(uno::Reference
< accessibility::XAccessibleContext
> xContext
)
4683 uno::Reference
< accessibility::XAccessibleEditableText
>();
4685 uno::Reference
<accessibility::XAccessibleStateSet
> xState
= xContext
->getAccessibleStateSet();
4688 if (xState
->contains(accessibility::AccessibleStateType::FOCUSED
))
4689 return uno::Reference
<accessibility::XAccessibleEditableText
>(xContext
, uno::UNO_QUERY
);
4692 for (sal_Int32 i
= 0; i
< xContext
->getAccessibleChildCount(); ++i
)
4694 uno::Reference
< accessibility::XAccessible
> xChild
= xContext
->getAccessibleChild(i
);
4697 uno::Reference
< accessibility::XAccessibleContext
> xChildContext
= xChild
->getAccessibleContext();
4698 if (!xChildContext
.is())
4700 uno::Reference
< accessibility::XAccessibleEditableText
> xText
= FindFocus(xChildContext
);
4704 return uno::Reference
< accessibility::XAccessibleEditableText
>();
4707 static uno::Reference
<accessibility::XAccessibleEditableText
> lcl_GetxText(vcl::Window
*pFocusWin
)
4709 uno::Reference
<accessibility::XAccessibleEditableText
> xText
;
4712 uno::Reference
< accessibility::XAccessible
> xAccessible( pFocusWin
->GetAccessible( true ) );
4713 if (xAccessible
.is())
4714 xText
= FindFocus(xAccessible
->getAccessibleContext());
4716 catch(const uno::Exception
& e
)
4718 SAL_WARN( "vcl.gtk", "Exception in getting input method surrounding text: " << e
.Message
);
4723 gboolean
GtkSalFrame::IMHandler::signalIMRetrieveSurrounding( GtkIMContext
* pContext
, gpointer
/*im_handler*/ )
4725 vcl::Window
*pFocusWin
= Application::GetFocusWindow();
4729 uno::Reference
<accessibility::XAccessibleEditableText
> xText
= lcl_GetxText(pFocusWin
);
4732 sal_Int32 nPosition
= xText
->getCaretPosition();
4733 OUString sAllText
= xText
->getText();
4734 OString sUTF
= OUStringToOString(sAllText
, RTL_TEXTENCODING_UTF8
);
4735 OUString
sCursorText(sAllText
.copy(0, nPosition
));
4736 gtk_im_context_set_surrounding(pContext
, sUTF
.getStr(), sUTF
.getLength(),
4737 OUStringToOString(sCursorText
, RTL_TEXTENCODING_UTF8
).getLength());
4744 gboolean
GtkSalFrame::IMHandler::signalIMDeleteSurrounding( GtkIMContext
*, gint offset
, gint nchars
,
4745 gpointer
/*im_handler*/ )
4747 vcl::Window
*pFocusWin
= Application::GetFocusWindow();
4751 uno::Reference
<accessibility::XAccessibleEditableText
> xText
= lcl_GetxText(pFocusWin
);
4754 sal_Int32 nPosition
= xText
->getCaretPosition();
4755 // #i111768# range checking
4756 sal_Int32 nDeletePos
= nPosition
+ offset
;
4757 sal_Int32 nDeleteEnd
= nDeletePos
+ nchars
;
4762 if (nDeleteEnd
> xText
->getCharacterCount())
4763 nDeleteEnd
= xText
->getCharacterCount();
4765 xText
->deleteText(nDeletePos
, nDeleteEnd
);
4766 //tdf91641 adjust cursor if deleted chars shift it forward (normal case)
4767 if (nDeletePos
< nPosition
)
4769 if (nDeleteEnd
<= nPosition
)
4770 nPosition
= nPosition
- (nDeleteEnd
- nDeletePos
);
4772 nPosition
= nDeletePos
;
4774 if (xText
->getCharacterCount() >= nPosition
)
4775 xText
->setCaretPosition( nPosition
);
4783 Size
GtkSalDisplay::GetScreenSize( int nDisplayScreen
)
4785 Rectangle aRect
= m_pSys
->GetDisplayScreenPosSizePixel( nDisplayScreen
);
4786 return Size( aRect
.GetWidth(), aRect
.GetHeight() );
4789 Window
GtkSalFrame::GetX11Window()
4791 return widget_get_xid(m_pWindow
);
4794 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */