Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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>
28 : #include <unx/sm.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>
40 :
41 : #if !GTK_CHECK_VERSION(3,0,0)
42 : # include <unx/x11/xlimits.hxx>
43 : #endif
44 : #if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
45 : # include <unx/gtk/gtksalmenu.hxx>
46 : #endif
47 : #if defined ENABLE_GMENU_INTEGRATION // defined in gtksalmenu.hxx above
48 : # include <unx/gtk/hudawareness.h>
49 : #endif
50 :
51 : #include <gtk/gtk.h>
52 : #include <prex.h>
53 : #include <X11/Xatom.h>
54 : #include <gdk/gdkx.h>
55 : #include <postx.h>
56 :
57 : #include <dlfcn.h>
58 : #include <vcl/salbtype.hxx>
59 : #include <vcl/bitmapex.hxx>
60 : #include <impbmp.hxx>
61 : #include <svids.hrc>
62 : #include <sal/macros.h>
63 :
64 : #include <basegfx/range/b2ibox.hxx>
65 : #include <basegfx/vector/b2ivector.hxx>
66 :
67 : #include <algorithm>
68 : #include <glib/gprintf.h>
69 :
70 : #if OSL_DEBUG_LEVEL > 1
71 : # include <cstdio>
72 : #endif
73 :
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>
85 :
86 : #if GTK_CHECK_VERSION(3,0,0)
87 : # include <gdk/gdkkeysyms-compat.h>
88 : #endif
89 :
90 : #ifdef ENABLE_DBUS
91 : #include <dbus/dbus-glib.h>
92 :
93 : #define GSM_DBUS_SERVICE "org.gnome.SessionManager"
94 : #define GSM_DBUS_PATH "/org/gnome/SessionManager"
95 : #define GSM_DBUS_INTERFACE "org.gnome.SessionManager"
96 : #endif
97 :
98 : #include <config_folders.h>
99 :
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
103 : #else
104 : #define IS_WIDGET_REALIZED GTK_WIDGET_REALIZED
105 : #define IS_WIDGET_MAPPED GTK_WIDGET_MAPPED
106 : #endif
107 :
108 : using namespace com::sun::star;
109 :
110 : int GtkSalFrame::m_nFloats = 0;
111 :
112 : #if defined ENABLE_GMENU_INTEGRATION
113 : static GDBusConnection* pSessionBus = NULL;
114 : #endif
115 :
116 0 : static sal_uInt16 GetKeyModCode( guint state )
117 : {
118 0 : sal_uInt16 nCode = 0;
119 0 : if( (state & GDK_SHIFT_MASK) )
120 0 : nCode |= KEY_SHIFT;
121 0 : if( (state & GDK_CONTROL_MASK) )
122 0 : nCode |= KEY_MOD1;
123 0 : if( (state & GDK_MOD1_MASK) )
124 0 : nCode |= KEY_MOD2;
125 :
126 : // Map Meta/Super keys to MOD3 modifier on all Unix systems
127 : // except Mac OS X
128 0 : if ( (state & GDK_META_MASK ) || ( state & GDK_SUPER_MASK ) )
129 0 : nCode |= KEY_MOD3;
130 0 : return nCode;
131 : }
132 :
133 0 : static sal_uInt16 GetMouseModCode( guint state )
134 : {
135 0 : sal_uInt16 nCode = GetKeyModCode( state );
136 0 : if( (state & GDK_BUTTON1_MASK) )
137 0 : nCode |= MOUSE_LEFT;
138 0 : if( (state & GDK_BUTTON2_MASK) )
139 0 : nCode |= MOUSE_MIDDLE;
140 0 : if( (state & GDK_BUTTON3_MASK) )
141 0 : nCode |= MOUSE_RIGHT;
142 :
143 0 : return nCode;
144 : }
145 :
146 0 : static sal_uInt16 GetKeyCode( guint keyval )
147 : {
148 0 : sal_uInt16 nCode = 0;
149 0 : if( keyval >= GDK_0 && keyval <= GDK_9 )
150 0 : nCode = KEY_0 + (keyval-GDK_0);
151 0 : else if( keyval >= GDK_KP_0 && keyval <= GDK_KP_9 )
152 0 : nCode = KEY_0 + (keyval-GDK_KP_0);
153 0 : else if( keyval >= GDK_A && keyval <= GDK_Z )
154 0 : nCode = KEY_A + (keyval-GDK_A );
155 0 : else if( keyval >= GDK_a && keyval <= GDK_z )
156 0 : nCode = KEY_A + (keyval-GDK_a );
157 0 : else if( keyval >= GDK_F1 && keyval <= GDK_F26 )
158 : {
159 : #if !GTK_CHECK_VERSION(3,0,0)
160 0 : if( GetGtkSalData()->GetGtkDisplay()->IsNumLockFromXS() )
161 : {
162 0 : nCode = KEY_F1 + (keyval-GDK_F1);
163 : }
164 : else
165 : #endif
166 : {
167 0 : switch( keyval )
168 : {
169 : // - - - - - Sun keyboard, see vcl/unx/source/app/saldisp.cxx
170 : case GDK_L2:
171 : #if !GTK_CHECK_VERSION(3,0,0)
172 0 : if( GetGtkSalData()->GetGtkDisplay()->GetServerVendor() == vendor_sun )
173 0 : nCode = KEY_REPEAT;
174 : else
175 : #endif
176 0 : nCode = KEY_F12;
177 0 : break;
178 0 : case GDK_L3: nCode = KEY_PROPERTIES; break;
179 0 : case GDK_L4: nCode = KEY_UNDO; break;
180 0 : case GDK_L6: nCode = KEY_COPY; break; // KEY_F16
181 0 : case GDK_L8: nCode = KEY_PASTE; break; // KEY_F18
182 0 : case GDK_L10: nCode = KEY_CUT; break; // KEY_F20
183 : default:
184 0 : nCode = KEY_F1 + (keyval-GDK_F1); break;
185 : }
186 : }
187 : }
188 : else
189 : {
190 0 : switch( keyval )
191 : {
192 : case GDK_KP_Down:
193 0 : case GDK_Down: nCode = KEY_DOWN; break;
194 : case GDK_KP_Up:
195 0 : case GDK_Up: nCode = KEY_UP; break;
196 : case GDK_KP_Left:
197 0 : case GDK_Left: nCode = KEY_LEFT; break;
198 : case GDK_KP_Right:
199 0 : case GDK_Right: nCode = KEY_RIGHT; break;
200 : case GDK_KP_Begin:
201 : case GDK_KP_Home:
202 : case GDK_Begin:
203 0 : case GDK_Home: nCode = KEY_HOME; break;
204 : case GDK_KP_End:
205 0 : case GDK_End: nCode = KEY_END; break;
206 : case GDK_KP_Page_Up:
207 0 : case GDK_Page_Up: nCode = KEY_PAGEUP; break;
208 : case GDK_KP_Page_Down:
209 0 : case GDK_Page_Down: nCode = KEY_PAGEDOWN; break;
210 : case GDK_KP_Enter:
211 0 : case GDK_Return: nCode = KEY_RETURN; break;
212 0 : case GDK_Escape: nCode = KEY_ESCAPE; break;
213 : case GDK_ISO_Left_Tab:
214 : case GDK_KP_Tab:
215 0 : case GDK_Tab: nCode = KEY_TAB; break;
216 0 : case GDK_BackSpace: nCode = KEY_BACKSPACE; break;
217 : case GDK_KP_Space:
218 0 : case GDK_space: nCode = KEY_SPACE; break;
219 : case GDK_KP_Insert:
220 0 : case GDK_Insert: nCode = KEY_INSERT; break;
221 : case GDK_KP_Delete:
222 0 : case GDK_Delete: nCode = KEY_DELETE; break;
223 : case GDK_plus:
224 0 : case GDK_KP_Add: nCode = KEY_ADD; break;
225 : case GDK_minus:
226 0 : case GDK_KP_Subtract: nCode = KEY_SUBTRACT; break;
227 : case GDK_asterisk:
228 0 : case GDK_KP_Multiply: nCode = KEY_MULTIPLY; break;
229 : case GDK_slash:
230 0 : case GDK_KP_Divide: nCode = KEY_DIVIDE; break;
231 0 : case GDK_period: nCode = KEY_POINT; break;
232 0 : case GDK_decimalpoint: nCode = KEY_POINT; break;
233 0 : case GDK_comma: nCode = KEY_COMMA; break;
234 0 : case GDK_less: nCode = KEY_LESS; break;
235 0 : case GDK_greater: nCode = KEY_GREATER; break;
236 : case GDK_KP_Equal:
237 0 : case GDK_equal: nCode = KEY_EQUAL; break;
238 0 : case GDK_Find: nCode = KEY_FIND; break;
239 0 : case GDK_Menu: nCode = KEY_CONTEXTMENU;break;
240 0 : case GDK_Help: nCode = KEY_HELP; break;
241 0 : case GDK_Undo: nCode = KEY_UNDO; break;
242 0 : case GDK_Redo: nCode = KEY_REPEAT; break;
243 : case GDK_KP_Decimal:
244 0 : case GDK_KP_Separator: nCode = KEY_DECIMAL; break;
245 0 : case GDK_asciitilde: nCode = KEY_TILDE; break;
246 : case GDK_leftsinglequotemark:
247 0 : case GDK_quoteleft: nCode = KEY_QUOTELEFT; break;
248 0 : case GDK_bracketleft: nCode = KEY_BRACKETLEFT; break;
249 0 : case GDK_bracketright: nCode = KEY_BRACKETRIGHT; break;
250 0 : case GDK_semicolon: nCode = KEY_SEMICOLON; break;
251 0 : case GDK_quoteright: nCode = KEY_QUOTERIGHT; break;
252 : // some special cases, also see saldisp.cxx
253 : // - - - - - - - - - - - - - Apollo - - - - - - - - - - - - - 0x1000
254 : case 0x1000FF02: // apXK_Copy
255 0 : nCode = KEY_COPY;
256 0 : break;
257 : case 0x1000FF03: // apXK_Cut
258 0 : nCode = KEY_CUT;
259 0 : break;
260 : case 0x1000FF04: // apXK_Paste
261 0 : nCode = KEY_PASTE;
262 0 : break;
263 : case 0x1000FF14: // apXK_Repeat
264 0 : nCode = KEY_REPEAT;
265 0 : break;
266 : // Exit, Save
267 : // - - - - - - - - - - - - - - D E C - - - - - - - - - - - - - 0x1000
268 : case 0x1000FF00:
269 0 : nCode = KEY_DELETE;
270 0 : break;
271 : // - - - - - - - - - - - - - - H P - - - - - - - - - - - - - 0x1000
272 : case 0x1000FF73: // hpXK_DeleteChar
273 0 : nCode = KEY_DELETE;
274 0 : break;
275 : case 0x1000FF74: // hpXK_BackTab
276 : case 0x1000FF75: // hpXK_KP_BackTab
277 0 : nCode = KEY_TAB;
278 0 : break;
279 : // - - - - - - - - - - - - - - I B M - - - - - - - - - - - - -
280 : // - - - - - - - - - - - - - - O S F - - - - - - - - - - - - - 0x1004
281 : case 0x1004FF02: // osfXK_Copy
282 0 : nCode = KEY_COPY;
283 0 : break;
284 : case 0x1004FF03: // osfXK_Cut
285 0 : nCode = KEY_CUT;
286 0 : break;
287 : case 0x1004FF04: // osfXK_Paste
288 0 : nCode = KEY_PASTE;
289 0 : break;
290 : case 0x1004FF07: // osfXK_BackTab
291 0 : nCode = KEY_TAB;
292 0 : break;
293 : case 0x1004FF08: // osfXK_BackSpace
294 0 : nCode = KEY_BACKSPACE;
295 0 : break;
296 : case 0x1004FF1B: // osfXK_Escape
297 0 : nCode = KEY_ESCAPE;
298 0 : break;
299 : // Up, Down, Left, Right, PageUp, PageDown
300 : // - - - - - - - - - - - - - - S C O - - - - - - - - - - - - -
301 : // - - - - - - - - - - - - - - S G I - - - - - - - - - - - - - 0x1007
302 : // - - - - - - - - - - - - - - S N I - - - - - - - - - - - - -
303 : // - - - - - - - - - - - - - - S U N - - - - - - - - - - - - - 0x1005
304 : case 0x1005FF10: // SunXK_F36
305 0 : nCode = KEY_F11;
306 0 : break;
307 : case 0x1005FF11: // SunXK_F37
308 0 : nCode = KEY_F12;
309 0 : break;
310 : case 0x1005FF70: // SunXK_Props
311 0 : nCode = KEY_PROPERTIES;
312 0 : break;
313 : case 0x1005FF71: // SunXK_Front
314 0 : nCode = KEY_FRONT;
315 0 : break;
316 : case 0x1005FF72: // SunXK_Copy
317 0 : nCode = KEY_COPY;
318 0 : break;
319 : case 0x1005FF73: // SunXK_Open
320 0 : nCode = KEY_OPEN;
321 0 : break;
322 : case 0x1005FF74: // SunXK_Paste
323 0 : nCode = KEY_PASTE;
324 0 : break;
325 : case 0x1005FF75: // SunXK_Cut
326 0 : nCode = KEY_CUT;
327 0 : break;
328 : }
329 : }
330 :
331 0 : return nCode;
332 : }
333 :
334 0 : static guint GetKeyValFor(GdkKeymap* pKeyMap, guint16 hardware_keycode, guint8 group)
335 : {
336 0 : guint updated_keyval = 0;
337 : gdk_keymap_translate_keyboard_state(pKeyMap, hardware_keycode,
338 0 : (GdkModifierType)0, group, &updated_keyval, NULL, NULL, NULL);
339 0 : return updated_keyval;
340 : }
341 :
342 : // F10 means either KEY_F10 or KEY_MENU, which has to be decided
343 : // in the independent part.
344 : struct KeyAlternate
345 : {
346 : sal_uInt16 nKeyCode;
347 : sal_Unicode nCharCode;
348 0 : KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
349 0 : KeyAlternate( sal_uInt16 nKey, sal_Unicode nChar = 0 ) : nKeyCode( nKey ), nCharCode( nChar ) {}
350 : };
351 :
352 : inline KeyAlternate
353 0 : GetAlternateKeyCode( const sal_uInt16 nKeyCode )
354 : {
355 0 : KeyAlternate aAlternate;
356 :
357 0 : switch( nKeyCode )
358 : {
359 0 : case KEY_F10: aAlternate = KeyAlternate( KEY_MENU );break;
360 0 : case KEY_F24: aAlternate = KeyAlternate( KEY_SUBTRACT, '-' );break;
361 : }
362 :
363 0 : return aAlternate;
364 : }
365 :
366 : #if GTK_CHECK_VERSION(3,0,0)
367 :
368 : namespace {
369 : /// Decouple SalFrame lifetime from damagetracker lifetime
370 : struct DamageTracker : public basebmp::IBitmapDeviceDamageTracker
371 : {
372 : DamageTracker(GtkSalFrame& rFrame) : m_rFrame(rFrame)
373 : {}
374 :
375 : virtual ~DamageTracker() {}
376 :
377 : virtual void damaged(const basegfx::B2IBox& rDamageRect) const SAL_OVERRIDE
378 : {
379 : m_rFrame.damaged(rDamageRect);
380 : }
381 :
382 : GtkSalFrame& m_rFrame;
383 : };
384 : }
385 :
386 : static bool dumpframes = false;
387 : #endif
388 :
389 0 : void GtkSalFrame::doKeyCallback( guint state,
390 : guint keyval,
391 : guint16 hardware_keycode,
392 : guint8 group,
393 : guint32 time,
394 : sal_Unicode aOrigCode,
395 : bool bDown,
396 : bool bSendRelease
397 : )
398 : {
399 : SalKeyEvent aEvent;
400 :
401 0 : aEvent.mnTime = time;
402 0 : aEvent.mnCharCode = aOrigCode;
403 0 : aEvent.mnRepeat = 0;
404 :
405 0 : vcl::DeletionListener aDel( this );
406 :
407 : #if GTK_CHECK_VERSION(3,0,0)
408 : #if 0
409 : // shift-zero forces a re-draw and event is swallowed
410 : if (keyval == GDK_0)
411 : {
412 : fprintf( stderr, "force widget_queue_draw\n");
413 : gtk_widget_queue_draw (m_pWindow);
414 : return;
415 : }
416 : else if (keyval == GDK_1)
417 : {
418 : fprintf( stderr, "force repaint all\n");
419 : TriggerPaintEvent();
420 : return;
421 : }
422 : else if (keyval == GDK_2)
423 : {
424 : dumpframes = !dumpframes;
425 : fprintf(stderr, "toggle dump frames to %d\n", dumpframes);
426 : return;
427 : }
428 : #endif
429 : #endif
430 :
431 : /*
432 : * #i42122# translate all keys with Ctrl and/or Alt to group 0 else
433 : * shortcuts (e.g. Ctrl-o) will not work but be inserted by the
434 : * application
435 : *
436 : * #i52338# do this for all keys that the independent part has no key code
437 : * for
438 : *
439 : * fdo#41169 rather than use group 0, detect if there is a group which can
440 : * be used to input Latin text and use that if possible
441 : */
442 0 : aEvent.mnCode = GetKeyCode( keyval );
443 0 : if( aEvent.mnCode == 0 )
444 : {
445 0 : gint best_group = SAL_MAX_INT32;
446 :
447 : // Try and find Latin layout
448 0 : GdkKeymap* keymap = gdk_keymap_get_default();
449 : GdkKeymapKey *keys;
450 : gint n_keys;
451 0 : if (gdk_keymap_get_entries_for_keyval(keymap, GDK_A, &keys, &n_keys))
452 : {
453 : // Find the lowest group that supports Latin layout
454 0 : for (gint i = 0; i < n_keys; ++i)
455 : {
456 0 : if (keys[i].level != 0 && keys[i].level != 1)
457 0 : continue;
458 0 : best_group = std::min(best_group, keys[i].group);
459 0 : if (best_group == 0)
460 0 : break;
461 : }
462 0 : g_free(keys);
463 : }
464 :
465 : //Unavailable, go with original group then I suppose
466 0 : if (best_group == SAL_MAX_INT32)
467 0 : best_group = group;
468 :
469 0 : guint updated_keyval = GetKeyValFor(keymap, hardware_keycode, best_group);
470 0 : aEvent.mnCode = GetKeyCode(updated_keyval);
471 : }
472 :
473 0 : aEvent.mnCode |= GetKeyModCode( state );
474 :
475 0 : if( bDown )
476 : {
477 0 : bool bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
478 : // #i46889# copy AlternatKeyCode handling from generic plugin
479 0 : if( ! bHandled )
480 : {
481 0 : KeyAlternate aAlternate = GetAlternateKeyCode( aEvent.mnCode );
482 0 : if( aAlternate.nKeyCode )
483 : {
484 0 : aEvent.mnCode = aAlternate.nKeyCode;
485 0 : if( aAlternate.nCharCode )
486 0 : aEvent.mnCharCode = aAlternate.nCharCode;
487 0 : bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
488 : }
489 : }
490 0 : if( bSendRelease && ! aDel.isDeleted() )
491 : {
492 0 : CallCallback( SALEVENT_KEYUP, &aEvent );
493 : }
494 : }
495 : else
496 0 : CallCallback( SALEVENT_KEYUP, &aEvent );
497 0 : }
498 :
499 26 : GtkSalFrame::GraphicsHolder::~GraphicsHolder()
500 : {
501 26 : delete pGraphics;
502 26 : }
503 :
504 16 : GtkSalFrame::GtkSalFrame( SalFrame* pParent, sal_uLong nStyle )
505 16 : : m_nXScreen( getDisplay()->GetDefaultXScreen() )
506 : {
507 16 : getDisplay()->registerFrame( this );
508 16 : m_bDefaultPos = true;
509 16 : m_bDefaultSize = ( (nStyle & SAL_FRAME_STYLE_SIZEABLE) && ! pParent );
510 16 : m_bWindowIsGtkPlug = false;
511 : #if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
512 16 : m_pLastSyncedDbusMenu = NULL;
513 : #endif
514 16 : Init( pParent, nStyle );
515 16 : }
516 :
517 0 : GtkSalFrame::GtkSalFrame( SystemParentData* pSysData )
518 0 : : m_nXScreen( getDisplay()->GetDefaultXScreen() )
519 : {
520 0 : getDisplay()->registerFrame( this );
521 : // permanently ignore errors from our unruly children ...
522 0 : GetGenericData()->ErrorTrapPush();
523 0 : m_bDefaultPos = true;
524 0 : m_bDefaultSize = true;
525 : #if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
526 0 : m_pLastSyncedDbusMenu = NULL;
527 : #endif
528 0 : Init( pSysData );
529 0 : }
530 :
531 : #ifdef ENABLE_GMENU_INTEGRATION
532 :
533 : static void
534 96 : gdk_x11_window_set_utf8_property (GdkWindow *window,
535 : const gchar *name,
536 : const gchar *value)
537 : {
538 : #if !GTK_CHECK_VERSION(3,0,0)
539 96 : GdkDisplay* display = gdk_window_get_display (window);
540 :
541 96 : if (value != NULL)
542 : {
543 : XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
544 : GDK_WINDOW_XID (window),
545 : gdk_x11_get_xatom_by_name_for_display (display, name),
546 : gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
547 96 : PropModeReplace, reinterpret_cast<guchar const *>(value), strlen (value));
548 : }
549 : else
550 : {
551 : XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
552 : GDK_WINDOW_XID (window),
553 0 : gdk_x11_get_xatom_by_name_for_display (display, name));
554 : }
555 : #endif
556 96 : }
557 :
558 : // AppMenu watch functions.
559 :
560 0 : static void ObjectDestroyedNotify( gpointer data )
561 : {
562 0 : if ( data ) {
563 0 : g_object_unref( data );
564 : }
565 0 : }
566 :
567 : #if defined(ENABLE_DBUS) && defined(ENABLE_GIO)
568 0 : void GtkSalFrame::EnsureDbusMenuSynced()
569 : {
570 0 : GtkSalMenu* pSalMenu = static_cast<GtkSalMenu*>(GetMenu());
571 0 : if(m_pLastSyncedDbusMenu != pSalMenu) {
572 0 : m_pLastSyncedDbusMenu = pSalMenu;
573 0 : static_cast<GtkSalMenu*>(pSalMenu)->Activate();
574 : }
575 0 : }
576 : #endif
577 :
578 0 : static void hud_activated( gboolean hud_active, gpointer user_data )
579 : {
580 0 : if ( hud_active )
581 : {
582 0 : SolarMutexGuard aGuard;
583 0 : GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( user_data );
584 0 : GtkSalMenu* pSalMenu = reinterpret_cast< GtkSalMenu* >( pSalFrame->GetMenu() );
585 :
586 0 : if ( pSalMenu )
587 0 : pSalMenu->UpdateFull();
588 : }
589 0 : }
590 :
591 0 : static void activate_uno(GSimpleAction *action, GVariant*, gpointer)
592 : {
593 0 : uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
594 :
595 0 : uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext );
596 :
597 0 : uno::Reference < css::frame::XFrame > xFrame(xDesktop->getActiveFrame());
598 0 : if (!xFrame.is())
599 0 : xFrame = uno::Reference < css::frame::XFrame >(xDesktop, uno::UNO_QUERY);
600 :
601 0 : if (!xFrame.is())
602 0 : return;
603 :
604 0 : uno::Reference< css::frame::XDispatchProvider > xDispatchProvider(xFrame, uno::UNO_QUERY);
605 0 : if (!xDispatchProvider.is())
606 0 : return;
607 :
608 0 : gchar *strval = NULL;
609 0 : g_object_get(action, "name", &strval, NULL);
610 0 : if (!strval)
611 0 : return;
612 :
613 0 : if (strcmp(strval, "New") == 0)
614 : {
615 0 : uno::Reference<frame::XModuleManager2> xModuleManager(frame::ModuleManager::create(xContext));
616 0 : OUString aModuleId(xModuleManager->identify(xFrame));
617 0 : if (aModuleId.isEmpty())
618 0 : return;
619 :
620 0 : comphelper::SequenceAsHashMap lModuleDescription(xModuleManager->getByName(aModuleId));
621 0 : OUString sFactoryService;
622 0 : lModuleDescription[OUString("ooSetupFactoryEmptyDocumentURL")] >>= sFactoryService;
623 0 : if (sFactoryService.isEmpty())
624 0 : return;
625 :
626 0 : uno::Sequence < css::beans::PropertyValue > args(0);
627 0 : xDesktop->loadComponentFromURL(sFactoryService, OUString("_blank"), 0, args);
628 0 : return;
629 : }
630 :
631 0 : OUString sCommand(".uno:");
632 0 : sCommand += OUString(strval, strlen(strval), RTL_TEXTENCODING_UTF8);
633 0 : g_free(strval);
634 :
635 0 : css::util::URL aCommand;
636 0 : aCommand.Complete = sCommand;
637 0 : uno::Reference< css::util::XURLTransformer > xParser = css::util::URLTransformer::create(xContext);
638 0 : xParser->parseStrict(aCommand);
639 :
640 0 : uno::Reference< css::frame::XDispatch > xDisp = xDispatchProvider->queryDispatch(aCommand, OUString(), 0);
641 :
642 0 : if (!xDisp.is())
643 0 : return;
644 :
645 0 : xDisp->dispatch(aCommand, css::uno::Sequence< css::beans::PropertyValue >());
646 : }
647 :
648 : static const GActionEntry app_entries[] = {
649 : { "OptionsTreeDialog", activate_uno, NULL, NULL, NULL, {0} },
650 : { "About", activate_uno, NULL, NULL, NULL, {0} },
651 : { "HelpIndex", activate_uno, NULL, NULL, NULL, {0} },
652 : { "Quit", activate_uno, NULL, NULL, NULL, {0} },
653 : { "New", activate_uno, NULL, NULL, NULL, {0} }
654 : };
655 :
656 16 : gboolean ensure_dbus_setup( gpointer data )
657 : {
658 16 : GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( data );
659 16 : GdkWindow* gdkWindow = widget_get_window( pSalFrame->getWindow() );
660 :
661 16 : if ( gdkWindow != NULL && g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" ) == NULL )
662 : {
663 : // Get a DBus session connection.
664 16 : if(!pSessionBus)
665 3 : pSessionBus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
666 16 : if( !pSessionBus )
667 0 : return FALSE;
668 :
669 : // Create menu model and action group attached to this frame.
670 16 : GMenuModel* pMenuModel = G_MENU_MODEL( g_lo_menu_new() );
671 16 : GActionGroup* pActionGroup = reinterpret_cast<GActionGroup*>(g_lo_action_group_new( static_cast< gpointer >( pSalFrame ) ));
672 :
673 : // Generate menu paths.
674 16 : ::Window windowId = GDK_WINDOW_XID( gdkWindow );
675 16 : gchar* aDBusWindowPath = g_strdup_printf( "/org/libreoffice/window/%lu", windowId );
676 16 : gchar* aDBusMenubarPath = g_strdup_printf( "/org/libreoffice/window/%lu/menus/menubar", windowId );
677 :
678 : // Set window properties.
679 16 : g_object_set_data_full( G_OBJECT( gdkWindow ), "g-lo-menubar", pMenuModel, ObjectDestroyedNotify );
680 16 : g_object_set_data_full( G_OBJECT( gdkWindow ), "g-lo-action-group", pActionGroup, ObjectDestroyedNotify );
681 :
682 16 : gdk_x11_window_set_utf8_property( gdkWindow, "_GTK_APPLICATION_ID", "org.libreoffice" );
683 16 : gdk_x11_window_set_utf8_property( gdkWindow, "_GTK_UNIQUE_BUS_NAME", g_dbus_connection_get_unique_name( pSessionBus ) );
684 16 : gdk_x11_window_set_utf8_property( gdkWindow, "_GTK_APPLICATION_OBJECT_PATH", "/org/libreoffice" );
685 16 : gdk_x11_window_set_utf8_property( gdkWindow, "_GTK_WINDOW_OBJECT_PATH", aDBusWindowPath );
686 16 : gdk_x11_window_set_utf8_property( gdkWindow, "_GTK_MENUBAR_OBJECT_PATH", aDBusMenubarPath );
687 :
688 : // Publish the menu model and the action group.
689 : SAL_INFO("vcl.unity", "exporting menu model at " << pMenuModel << " for window " << windowId);
690 16 : pSalFrame->m_nMenuExportId = g_dbus_connection_export_menu_model (pSessionBus, aDBusMenubarPath, pMenuModel, NULL);
691 : SAL_INFO("vcl.unity", "exporting action group at " << pActionGroup << " for window " << windowId);
692 16 : pSalFrame->m_nActionGroupExportId = g_dbus_connection_export_action_group( pSessionBus, aDBusWindowPath, pActionGroup, NULL);
693 16 : pSalFrame->m_nHudAwarenessId = hud_awareness_register( pSessionBus, aDBusMenubarPath, hud_activated, pSalFrame, NULL, NULL );
694 :
695 : // fdo#70885 we don't want app menu under Unity
696 16 : bool bDesktopIsUnity = (SalGetDesktopEnvironment() == "UNITY");
697 :
698 16 : if (!bDesktopIsUnity)
699 16 : gdk_x11_window_set_utf8_property( gdkWindow, "_GTK_APP_MENU_OBJECT_PATH", "/org/libreoffice/menus/appmenu" );
700 :
701 : //app menu, to-do translations, block normal menus when active, honor use appmenu settings
702 16 : ResMgr* pMgr = ImplGetResMgr();
703 16 : if( pMgr && !bDesktopIsUnity )
704 : {
705 16 : GMenu *menu = g_menu_new ();
706 : GMenuItem* item;
707 :
708 16 : GMenu *firstsubmenu = g_menu_new ();
709 :
710 : OString sNew(OUStringToOString(ResId(SV_BUTTONTEXT_NEW, *pMgr).toString(),
711 16 : RTL_TEXTENCODING_UTF8).replaceFirst("~", "_"));
712 :
713 16 : item = g_menu_item_new(sNew.getStr(), "app.New");
714 16 : g_menu_append_item( firstsubmenu, item );
715 16 : g_object_unref(item);
716 :
717 16 : g_menu_append_section( menu, NULL, G_MENU_MODEL(firstsubmenu));
718 16 : g_object_unref(firstsubmenu);
719 :
720 16 : GMenu *secondsubmenu = g_menu_new ();
721 :
722 : OString sPreferences(OUStringToOString(ResId(SV_STDTEXT_PREFERENCES, *pMgr).toString(),
723 32 : RTL_TEXTENCODING_UTF8).replaceFirst("~", "_"));
724 :
725 16 : item = g_menu_item_new(sPreferences.getStr(), "app.OptionsTreeDialog");
726 16 : g_menu_append_item( secondsubmenu, item );
727 16 : g_object_unref(item);
728 :
729 16 : g_menu_append_section( menu, NULL, G_MENU_MODEL(secondsubmenu));
730 16 : g_object_unref(secondsubmenu);
731 :
732 16 : GMenu *thirdsubmenu = g_menu_new ();
733 :
734 : OString sHelp(OUStringToOString(ResId(SV_BUTTONTEXT_HELP, *pMgr).toString(),
735 32 : RTL_TEXTENCODING_UTF8).replaceFirst("~", "_"));
736 :
737 16 : item = g_menu_item_new(sHelp.getStr(), "app.HelpIndex");
738 16 : g_menu_append_item( thirdsubmenu, item );
739 16 : g_object_unref(item);
740 :
741 : OString sAbout(OUStringToOString(ResId(SV_STDTEXT_ABOUT, *pMgr).toString(),
742 32 : RTL_TEXTENCODING_UTF8).replaceFirst("~", "_"));
743 :
744 16 : item = g_menu_item_new(sAbout.getStr(), "app.About");
745 16 : g_menu_append_item( thirdsubmenu, item );
746 16 : g_object_unref(item);
747 :
748 : OString sQuit(OUStringToOString(ResId(SV_MENU_MAC_QUITAPP, *pMgr).toString(),
749 32 : RTL_TEXTENCODING_UTF8).replaceFirst("~", "_"));
750 :
751 16 : item = g_menu_item_new(sQuit.getStr(), "app.Quit");
752 16 : g_menu_append_item( thirdsubmenu, item );
753 16 : g_object_unref(item);
754 16 : g_menu_append_section( menu, NULL, G_MENU_MODEL(thirdsubmenu));
755 16 : g_object_unref(thirdsubmenu);
756 :
757 16 : GSimpleActionGroup *group = g_simple_action_group_new ();
758 : #if GLIB_CHECK_VERSION(2,38,0) // g_simple_action_group_add_entries is deprecated since 2.38
759 16 : g_action_map_add_action_entries (G_ACTION_MAP (group), app_entries, G_N_ELEMENTS (app_entries), NULL);
760 : #else
761 : g_simple_action_group_add_entries (group, app_entries, G_N_ELEMENTS (app_entries), NULL);
762 : #endif
763 16 : GActionGroup* pAppActionGroup = G_ACTION_GROUP(group);
764 :
765 16 : pSalFrame->m_nAppActionGroupExportId = g_dbus_connection_export_action_group( pSessionBus, "/org/libreoffice", pAppActionGroup, NULL);
766 16 : g_object_unref(pAppActionGroup);
767 16 : pSalFrame->m_nAppMenuExportId = g_dbus_connection_export_menu_model (pSessionBus, "/org/libreoffice/menus/appmenu", G_MENU_MODEL (menu), NULL);
768 32 : g_object_unref(menu);
769 : }
770 :
771 16 : g_free( aDBusMenubarPath );
772 16 : g_free( aDBusWindowPath );
773 : }
774 :
775 16 : return FALSE;
776 : }
777 :
778 0 : void on_registrar_available( GDBusConnection * /*connection*/,
779 : const gchar * /*name*/,
780 : const gchar * /*name_owner*/,
781 : gpointer user_data )
782 : {
783 0 : SolarMutexGuard aGuard;
784 :
785 0 : GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( user_data );
786 :
787 0 : SalMenu* pSalMenu = pSalFrame->GetMenu();
788 :
789 0 : if ( pSalMenu != NULL )
790 : {
791 0 : GtkSalMenu* pGtkSalMenu = static_cast<GtkSalMenu*>(pSalMenu);
792 0 : pGtkSalMenu->Display( true );
793 0 : pGtkSalMenu->UpdateFull();
794 0 : }
795 0 : }
796 :
797 : // This is called when the registrar becomes unavailable. It shows the menubar.
798 0 : void on_registrar_unavailable( GDBusConnection * /*connection*/,
799 : const gchar * /*name*/,
800 : gpointer user_data )
801 : {
802 0 : SolarMutexGuard aGuard;
803 :
804 : SAL_INFO("vcl.unity", "on_registrar_unavailable");
805 :
806 : //pSessionBus = NULL;
807 0 : GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( user_data );
808 :
809 0 : SalMenu* pSalMenu = pSalFrame->GetMenu();
810 :
811 0 : if ( pSalMenu ) {
812 0 : GtkSalMenu* pGtkSalMenu = static_cast< GtkSalMenu* >( pSalMenu );
813 0 : pGtkSalMenu->Display( false );
814 0 : }
815 0 : }
816 : #endif
817 :
818 2 : void GtkSalFrame::EnsureAppMenuWatch()
819 : {
820 : #ifdef ENABLE_GMENU_INTEGRATION
821 2 : if ( !m_nWatcherId )
822 : {
823 : // Get a DBus session connection.
824 2 : if ( pSessionBus == NULL )
825 : {
826 0 : pSessionBus = g_bus_get_sync( G_BUS_TYPE_SESSION, NULL, NULL );
827 :
828 0 : if ( pSessionBus == NULL )
829 2 : return;
830 : }
831 :
832 : // Publish the menu only if AppMenu registrar is available.
833 : m_nWatcherId = g_bus_watch_name_on_connection( pSessionBus,
834 : "com.canonical.AppMenu.Registrar",
835 : G_BUS_NAME_WATCHER_FLAGS_NONE,
836 : on_registrar_available,
837 : on_registrar_unavailable,
838 : static_cast<GtkSalFrame*>(this),
839 2 : NULL );
840 : }
841 :
842 : //ensure_dbus_setup( this );
843 : #else
844 : (void) this; // loplugin:staticmethods
845 : #endif
846 : }
847 :
848 39 : GtkSalFrame::~GtkSalFrame()
849 : {
850 39 : for( unsigned int i = 0; i < SAL_N_ELEMENTS(m_aGraphics); ++i )
851 : {
852 26 : if( !m_aGraphics[i].pGraphics )
853 1 : continue;
854 : #if !GTK_CHECK_VERSION(3,0,0)
855 25 : m_aGraphics[i].pGraphics->SetDrawable( None, m_nXScreen );
856 : #endif
857 25 : m_aGraphics[i].bInUse = false;
858 : }
859 :
860 13 : if( m_pParent )
861 0 : m_pParent->m_aChildren.remove( this );
862 :
863 13 : getDisplay()->deregisterFrame( this );
864 :
865 13 : if( m_pRegion )
866 : {
867 : #if GTK_CHECK_VERSION(3,0,0)
868 : cairo_region_destroy( m_pRegion );
869 : #else
870 0 : gdk_region_destroy( m_pRegion );
871 : #endif
872 : }
873 :
874 : #if !GTK_CHECK_VERSION(3,0,0)
875 13 : if( m_hBackgroundPixmap )
876 : {
877 0 : XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
878 : widget_get_xid(m_pWindow),
879 0 : None );
880 0 : XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap );
881 : }
882 : #endif
883 :
884 13 : if( m_pIMHandler )
885 0 : delete m_pIMHandler;
886 :
887 13 : if( m_pFixedContainer )
888 13 : gtk_widget_destroy( GTK_WIDGET( m_pFixedContainer ) );
889 : {
890 13 : SolarMutexGuard aGuard;
891 : #if defined ENABLE_GMENU_INTEGRATION
892 13 : if(m_nWatcherId)
893 2 : g_bus_unwatch_name(m_nWatcherId);
894 : #endif
895 13 : if( m_pWindow )
896 : {
897 13 : g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", NULL );
898 :
899 : #if defined ENABLE_GMENU_INTEGRATION
900 13 : if ( pSessionBus )
901 : {
902 13 : if ( m_nHudAwarenessId )
903 13 : hud_awareness_unregister( pSessionBus, m_nHudAwarenessId );
904 13 : if ( m_nMenuExportId )
905 13 : g_dbus_connection_unexport_menu_model( pSessionBus, m_nMenuExportId );
906 13 : if ( m_nAppMenuExportId )
907 3 : g_dbus_connection_unexport_menu_model( pSessionBus, m_nAppMenuExportId );
908 13 : if ( m_nActionGroupExportId )
909 13 : g_dbus_connection_unexport_action_group( pSessionBus, m_nActionGroupExportId );
910 13 : if ( m_nAppActionGroupExportId )
911 3 : g_dbus_connection_unexport_action_group( pSessionBus, m_nAppActionGroupExportId );
912 : }
913 : #endif
914 13 : gtk_widget_destroy( m_pWindow );
915 13 : }
916 : }
917 13 : if( m_pForeignParent )
918 0 : g_object_unref( G_OBJECT( m_pForeignParent ) );
919 13 : if( m_pForeignTopLevel )
920 0 : g_object_unref( G_OBJECT( m_pForeignTopLevel) );
921 26 : }
922 :
923 9 : void GtkSalFrame::moveWindow( long nX, long nY )
924 : {
925 9 : if( isChild( false, true ) )
926 : {
927 0 : if( m_pParent )
928 : gtk_fixed_move( m_pParent->getFixedContainer(),
929 : m_pWindow,
930 0 : nX - m_pParent->maGeometry.nX, nY - m_pParent->maGeometry.nY );
931 : }
932 : else
933 9 : gtk_window_move( GTK_WINDOW(m_pWindow), nX, nY );
934 9 : }
935 :
936 0 : void GtkSalFrame::resizeWindow( long nWidth, long nHeight )
937 : {
938 0 : if( isChild( false, true ) )
939 0 : gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
940 0 : else if( ! isChild( true, false ) )
941 0 : gtk_window_resize( GTK_WINDOW(m_pWindow), nWidth, nHeight );
942 0 : }
943 :
944 : /*
945 : * Always use a sub-class of GtkFixed we can tag for a11y. This allows us to
946 : * utilize GAIL for the toplevel window and toolkit implementation incl.
947 : * key event listener support ..
948 : */
949 :
950 : GType
951 16 : ooo_fixed_get_type()
952 : {
953 : static GType type = 0;
954 :
955 16 : if (!type) {
956 : static const GTypeInfo tinfo =
957 : {
958 : sizeof (GtkFixedClass),
959 : nullptr, /* base init */
960 : nullptr, /* base finalize */
961 : nullptr, /* class init */
962 : nullptr, /* class finalize */
963 : NULL, /* class data */
964 : sizeof (GtkFixed), /* instance size */
965 : 0, /* nb preallocs */
966 : nullptr, /* instance init */
967 : NULL /* value table */
968 : };
969 :
970 : type = g_type_register_static( GTK_TYPE_FIXED, "OOoFixed",
971 3 : &tinfo, (GTypeFlags) 0);
972 : }
973 :
974 16 : return type;
975 : }
976 :
977 25 : void GtkSalFrame::updateScreenNumber()
978 : {
979 25 : int nScreen = 0;
980 25 : GdkScreen *pScreen = gtk_widget_get_screen( m_pWindow );
981 25 : if( pScreen )
982 25 : nScreen = getDisplay()->getSystem()->getScreenMonitorIdx( pScreen, maGeometry.nX, maGeometry.nY );
983 25 : maGeometry.nDisplayScreenNumber = nScreen;
984 25 : }
985 :
986 16 : void GtkSalFrame::InitCommon()
987 : {
988 : // connect signals
989 16 : g_signal_connect( G_OBJECT(m_pWindow), "style-set", G_CALLBACK(signalStyleSet), this );
990 16 : g_signal_connect( G_OBJECT(m_pWindow), "button-press-event", G_CALLBACK(signalButton), this );
991 16 : g_signal_connect( G_OBJECT(m_pWindow), "button-release-event", G_CALLBACK(signalButton), this );
992 : #if GTK_CHECK_VERSION(3,0,0)
993 : g_signal_connect( G_OBJECT(m_pWindow), "draw", G_CALLBACK(signalDraw), this );
994 : #if GTK_CHECK_VERSION(3,14,0)
995 : GtkGesture *pSwipe = gtk_gesture_swipe_new(m_pWindow);
996 : g_signal_connect(pSwipe, "swipe", G_CALLBACK(gestureSwipe), this);
997 : gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER (pSwipe), GTK_PHASE_TARGET);
998 : g_object_weak_ref(G_OBJECT(m_pWindow), reinterpret_cast<GWeakNotify>(g_object_unref), pSwipe);
999 :
1000 : GtkGesture *pLongPress = gtk_gesture_long_press_new(m_pWindow);
1001 : g_signal_connect(pLongPress, "pressed", G_CALLBACK(gestureLongPress), this);
1002 : gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER (pLongPress), GTK_PHASE_TARGET);
1003 : g_object_weak_ref(G_OBJECT(m_pWindow), reinterpret_cast<GWeakNotify>(g_object_unref), pLongPress);
1004 :
1005 : #endif
1006 :
1007 : #else
1008 16 : g_signal_connect( G_OBJECT(m_pWindow), "expose-event", G_CALLBACK(signalExpose), this );
1009 : #endif
1010 16 : g_signal_connect( G_OBJECT(m_pWindow), "focus-in-event", G_CALLBACK(signalFocus), this );
1011 16 : g_signal_connect( G_OBJECT(m_pWindow), "focus-out-event", G_CALLBACK(signalFocus), this );
1012 16 : g_signal_connect( G_OBJECT(m_pWindow), "map-event", G_CALLBACK(signalMap), this );
1013 16 : g_signal_connect( G_OBJECT(m_pWindow), "unmap-event", G_CALLBACK(signalUnmap), this );
1014 16 : g_signal_connect( G_OBJECT(m_pWindow), "configure-event", G_CALLBACK(signalConfigure), this );
1015 16 : g_signal_connect( G_OBJECT(m_pWindow), "motion-notify-event", G_CALLBACK(signalMotion), this );
1016 16 : g_signal_connect( G_OBJECT(m_pWindow), "key-press-event", G_CALLBACK(signalKey), this );
1017 16 : g_signal_connect( G_OBJECT(m_pWindow), "key-release-event", G_CALLBACK(signalKey), this );
1018 16 : g_signal_connect( G_OBJECT(m_pWindow), "delete-event", G_CALLBACK(signalDelete), this );
1019 16 : g_signal_connect( G_OBJECT(m_pWindow), "window-state-event", G_CALLBACK(signalState), this );
1020 16 : g_signal_connect( G_OBJECT(m_pWindow), "scroll-event", G_CALLBACK(signalScroll), this );
1021 16 : g_signal_connect( G_OBJECT(m_pWindow), "leave-notify-event", G_CALLBACK(signalCrossing), this );
1022 16 : g_signal_connect( G_OBJECT(m_pWindow), "enter-notify-event", G_CALLBACK(signalCrossing), this );
1023 16 : g_signal_connect( G_OBJECT(m_pWindow), "visibility-notify-event", G_CALLBACK(signalVisibility), this );
1024 16 : g_signal_connect( G_OBJECT(m_pWindow), "destroy", G_CALLBACK(signalDestroy), this );
1025 :
1026 : // init members
1027 16 : m_pCurrentCursor = NULL;
1028 16 : m_nKeyModifiers = 0;
1029 16 : m_bFullscreen = false;
1030 16 : m_bSpanMonitorsWhenFullscreen = false;
1031 16 : m_nState = GDK_WINDOW_STATE_WITHDRAWN;
1032 16 : m_nVisibility = GDK_VISIBILITY_FULLY_OBSCURED;
1033 16 : m_bSendModChangeOnRelease = false;
1034 16 : m_pIMHandler = NULL;
1035 16 : m_hBackgroundPixmap = None;
1036 16 : m_nSavedScreenSaverTimeout = 0;
1037 16 : m_nGSMCookie = 0;
1038 16 : m_nExtStyle = 0;
1039 16 : m_pRegion = NULL;
1040 16 : m_ePointerStyle = static_cast<PointerStyle>(0xffff);
1041 16 : m_bSetFocusOnMap = false;
1042 16 : m_pSalMenu = NULL;
1043 16 : m_nWatcherId = 0;
1044 16 : m_nMenuExportId = 0;
1045 16 : m_nAppMenuExportId = 0;
1046 16 : m_nActionGroupExportId = 0;
1047 16 : m_nAppActionGroupExportId = 0;
1048 16 : m_nHudAwarenessId = 0;
1049 :
1050 16 : gtk_widget_set_app_paintable( m_pWindow, TRUE );
1051 16 : gtk_widget_set_double_buffered( m_pWindow, FALSE );
1052 16 : gtk_widget_set_redraw_on_allocate( m_pWindow, FALSE );
1053 :
1054 : gtk_widget_add_events( m_pWindow,
1055 : GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1056 : GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1057 : GDK_VISIBILITY_NOTIFY_MASK | GDK_SCROLL_MASK
1058 16 : );
1059 :
1060 : // add the fixed container child,
1061 : // fixed is needed since we have to position plugin windows
1062 16 : m_pFixedContainer = GTK_FIXED(g_object_new( ooo_fixed_get_type(), NULL ));
1063 16 : gtk_container_add( GTK_CONTAINER(m_pWindow), GTK_WIDGET(m_pFixedContainer) );
1064 :
1065 : // show the widgets
1066 16 : gtk_widget_show( GTK_WIDGET(m_pFixedContainer) );
1067 :
1068 : // realize the window, we need an XWindow id
1069 16 : gtk_widget_realize( m_pWindow );
1070 :
1071 : //system data
1072 16 : m_aSystemData.nSize = sizeof( SystemEnvData );
1073 : #if !GTK_CHECK_VERSION(3,0,0)
1074 16 : GtkSalDisplay* pDisp = GetGtkSalData()->GetGtkDisplay();
1075 16 : m_aSystemData.pDisplay = pDisp->GetDisplay();
1076 16 : m_aSystemData.pVisual = pDisp->GetVisual( m_nXScreen ).GetVisual();
1077 16 : m_aSystemData.nDepth = pDisp->GetVisual( m_nXScreen ).GetDepth();
1078 16 : m_aSystemData.aColormap = pDisp->GetColormap( m_nXScreen ).GetXColormap();
1079 16 : m_aSystemData.aWindow = widget_get_xid(m_pWindow);
1080 16 : m_aSystemData.aShellWindow = m_aSystemData.aWindow;
1081 : #else
1082 : static int nWindow = 0;
1083 : m_aSystemData.aWindow = nWindow;
1084 : m_aSystemData.aShellWindow = nWindow;
1085 : ++nWindow;
1086 : #endif
1087 16 : m_aSystemData.pSalFrame = this;
1088 16 : m_aSystemData.pWidget = m_pWindow;
1089 16 : m_aSystemData.nScreen = m_nXScreen.getXScreen();
1090 16 : m_aSystemData.pAppContext = NULL;
1091 16 : m_aSystemData.pShellWidget = m_aSystemData.pWidget;
1092 :
1093 : // fake an initial geometry, gets updated via configure event or SetPosSize
1094 16 : if( m_bDefaultPos || m_bDefaultSize )
1095 : {
1096 16 : Size aDefSize = calcDefaultSize();
1097 16 : maGeometry.nX = -1;
1098 16 : maGeometry.nY = -1;
1099 16 : maGeometry.nWidth = aDefSize.Width();
1100 16 : maGeometry.nHeight = aDefSize.Height();
1101 16 : if( m_pParent )
1102 : {
1103 : // approximation
1104 0 : maGeometry.nTopDecoration = m_pParent->maGeometry.nTopDecoration;
1105 0 : maGeometry.nBottomDecoration = m_pParent->maGeometry.nBottomDecoration;
1106 0 : maGeometry.nLeftDecoration = m_pParent->maGeometry.nLeftDecoration;
1107 0 : maGeometry.nRightDecoration = m_pParent->maGeometry.nRightDecoration;
1108 : }
1109 : else
1110 : {
1111 16 : maGeometry.nTopDecoration = 0;
1112 16 : maGeometry.nBottomDecoration = 0;
1113 16 : maGeometry.nLeftDecoration = 0;
1114 16 : maGeometry.nRightDecoration = 0;
1115 16 : }
1116 : }
1117 : else
1118 : {
1119 0 : resizeWindow( maGeometry.nWidth, maGeometry.nHeight );
1120 0 : moveWindow( maGeometry.nX, maGeometry.nY );
1121 : }
1122 16 : updateScreenNumber();
1123 :
1124 16 : SetIcon(1);
1125 :
1126 : #if !GTK_CHECK_VERSION(3,0,0)
1127 16 : m_nWorkArea = pDisp->getWMAdaptor()->getCurrentWorkArea();
1128 : /* #i64117# gtk sets a nice background pixmap
1129 : * but we actually don't really want that, so save
1130 : * some time on the Xserver as well as prevent
1131 : * some paint issues
1132 : */
1133 16 : XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
1134 : widget_get_xid(m_pWindow),
1135 32 : m_hBackgroundPixmap );
1136 : #endif
1137 16 : }
1138 :
1139 : /* Sadly gtk_window_set_accept_focus exists only since gtk 2.4
1140 : * for achieving the same effect we will remove the WM_TAKE_FOCUS
1141 : * protocol from the window and set the input hint to false.
1142 : * But gtk_window_set_accept_focus needs to be called before
1143 : * window realization whereas the removal obviously can only happen
1144 : * after realization.
1145 : */
1146 :
1147 : #if !GTK_CHECK_VERSION(3,0,0)
1148 : extern "C" {
1149 : typedef void(*setAcceptFn)( GtkWindow*, gboolean );
1150 : static setAcceptFn p_gtk_window_set_accept_focus = NULL;
1151 : static bool bGetAcceptFocusFn = true;
1152 :
1153 : typedef void(*setUserTimeFn)( GdkWindow*, guint32 );
1154 : static setUserTimeFn p_gdk_x11_window_set_user_time = NULL;
1155 : static bool bGetSetUserTimeFn = true;
1156 : }
1157 : #endif
1158 :
1159 0 : static void lcl_set_accept_focus( GtkWindow* pWindow, gboolean bAccept, bool bBeforeRealize )
1160 : {
1161 : #if !GTK_CHECK_VERSION(3,0,0)
1162 0 : if( bGetAcceptFocusFn )
1163 : {
1164 0 : bGetAcceptFocusFn = false;
1165 0 : p_gtk_window_set_accept_focus = reinterpret_cast<setAcceptFn>(osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_window_set_accept_focus" ));
1166 : }
1167 0 : if( p_gtk_window_set_accept_focus && bBeforeRealize )
1168 0 : p_gtk_window_set_accept_focus( pWindow, bAccept );
1169 0 : else if( ! bBeforeRealize )
1170 : {
1171 0 : Display* pDisplay = GetGtkSalData()->GetGtkDisplay()->GetDisplay();
1172 0 : ::Window aWindow = widget_get_xid(GTK_WIDGET(pWindow));
1173 0 : XWMHints* pHints = XGetWMHints( pDisplay, aWindow );
1174 0 : if( ! pHints )
1175 : {
1176 0 : pHints = XAllocWMHints();
1177 0 : pHints->flags = 0;
1178 : }
1179 0 : pHints->flags |= InputHint;
1180 0 : pHints->input = bAccept ? True : False;
1181 0 : XSetWMHints( pDisplay, aWindow, pHints );
1182 0 : XFree( pHints );
1183 :
1184 0 : if (GetGtkSalData()->GetGtkDisplay()->getWMAdaptor()->getWindowManagerName() == "compiz")
1185 0 : return;
1186 :
1187 : /* remove WM_TAKE_FOCUS protocol; this would usually be the
1188 : * right thing, but gtk handles it internally whereas we
1189 : * want to handle it ourselves (as to sometimes not get
1190 : * the focus)
1191 : */
1192 0 : Atom* pProtocols = NULL;
1193 0 : int nProtocols = 0;
1194 : XGetWMProtocols( pDisplay,
1195 : aWindow,
1196 0 : &pProtocols, &nProtocols );
1197 0 : if( pProtocols )
1198 : {
1199 0 : bool bSet = false;
1200 0 : Atom nTakeFocus = XInternAtom( pDisplay, "WM_TAKE_FOCUS", True );
1201 0 : if( nTakeFocus )
1202 : {
1203 0 : for( int i = 0; i < nProtocols; i++ )
1204 : {
1205 0 : if( pProtocols[i] == nTakeFocus )
1206 : {
1207 0 : for( int n = i; n < nProtocols-1; n++ )
1208 0 : pProtocols[n] = pProtocols[n+1];
1209 0 : nProtocols--;
1210 0 : i--;
1211 0 : bSet = true;
1212 : }
1213 : }
1214 : }
1215 0 : if( bSet )
1216 0 : XSetWMProtocols( pDisplay, aWindow, pProtocols, nProtocols );
1217 0 : XFree( pProtocols );
1218 : }
1219 : }
1220 : #else
1221 : gtk_window_set_accept_focus(pWindow, bAccept);
1222 : (void)bBeforeRealize;
1223 : #endif
1224 : }
1225 :
1226 : #if !GTK_CHECK_VERSION(3,0,0)
1227 16 : static void lcl_set_user_time( GtkWindow* i_pWindow, guint32 i_nTime )
1228 : {
1229 16 : if( bGetSetUserTimeFn )
1230 : {
1231 3 : bGetSetUserTimeFn = false;
1232 3 : p_gdk_x11_window_set_user_time = reinterpret_cast<setUserTimeFn>(osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_x11_window_set_user_time" ));
1233 : }
1234 16 : bool bSet = false;
1235 16 : if( p_gdk_x11_window_set_user_time )
1236 : {
1237 16 : GdkWindow* pWin = widget_get_window(GTK_WIDGET(i_pWindow));
1238 16 : if( pWin ) // only if the window is realized.
1239 : {
1240 16 : p_gdk_x11_window_set_user_time( pWin, i_nTime );
1241 16 : bSet = true;
1242 : }
1243 : }
1244 16 : if( !bSet )
1245 : {
1246 0 : Display* pDisplay = GetGtkSalData()->GetGtkDisplay()->GetDisplay();
1247 0 : Atom nUserTime = XInternAtom( pDisplay, "_NET_WM_USER_TIME", True );
1248 0 : if( nUserTime )
1249 : {
1250 0 : XChangeProperty( pDisplay, widget_get_xid(GTK_WIDGET(i_pWindow)),
1251 : nUserTime, XA_CARDINAL, 32,
1252 0 : PropModeReplace, reinterpret_cast<unsigned char*>(&i_nTime), 1 );
1253 : }
1254 : }
1255 16 : };
1256 : #endif
1257 :
1258 0 : GtkSalFrame *GtkSalFrame::getFromWindow( GtkWindow *pWindow )
1259 : {
1260 0 : return static_cast<GtkSalFrame *>(g_object_get_data( G_OBJECT( pWindow ), "SalFrame" ));
1261 : }
1262 :
1263 16 : void GtkSalFrame::Init( SalFrame* pParent, sal_uLong nStyle )
1264 : {
1265 16 : if( nStyle & SAL_FRAME_STYLE_DEFAULT ) // ensure default style
1266 : {
1267 0 : nStyle |= SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE;
1268 0 : nStyle &= ~SAL_FRAME_STYLE_FLOAT;
1269 : }
1270 :
1271 16 : m_pParent = static_cast<GtkSalFrame*>(pParent);
1272 16 : m_pForeignParent = NULL;
1273 16 : m_aForeignParentWindow = None;
1274 16 : m_pForeignTopLevel = NULL;
1275 16 : m_aForeignTopLevelWindow = None;
1276 16 : m_nStyle = nStyle;
1277 :
1278 16 : GtkWindowType eWinType = ( (nStyle & SAL_FRAME_STYLE_FLOAT) &&
1279 0 : ! (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|
1280 : SAL_FRAME_STYLE_FLOAT_FOCUSABLE))
1281 : )
1282 16 : ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL;
1283 :
1284 16 : if( nStyle & SAL_FRAME_STYLE_SYSTEMCHILD )
1285 : {
1286 0 : m_pWindow = gtk_event_box_new();
1287 0 : if( m_pParent )
1288 : {
1289 : // insert into container
1290 : gtk_fixed_put( m_pParent->getFixedContainer(),
1291 0 : m_pWindow, 0, 0 );
1292 :
1293 : }
1294 : }
1295 : else
1296 : m_pWindow = gtk_widget_new( GTK_TYPE_WINDOW, "type", eWinType,
1297 16 : "visible", FALSE, NULL );
1298 16 : g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", this );
1299 16 : g_object_set_data( G_OBJECT( m_pWindow ), "libo-version", const_cast<char *>(LIBO_VERSION_DOTTED));
1300 :
1301 : // force wm class hint
1302 16 : m_nExtStyle = ~0;
1303 16 : if (m_pParent)
1304 0 : m_sWMClass = m_pParent->m_sWMClass;
1305 16 : SetExtendedFrameStyle( 0 );
1306 :
1307 16 : if( m_pParent && m_pParent->m_pWindow && ! isChild() )
1308 0 : gtk_window_set_screen( GTK_WINDOW(m_pWindow), gtk_window_get_screen( GTK_WINDOW(m_pParent->m_pWindow) ) );
1309 :
1310 : // set window type
1311 : bool bDecoHandling =
1312 48 : ! isChild() &&
1313 16 : ( ! (nStyle & SAL_FRAME_STYLE_FLOAT) ||
1314 16 : (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE) ) );
1315 :
1316 16 : if( bDecoHandling )
1317 : {
1318 16 : GdkWindowTypeHint eType = GDK_WINDOW_TYPE_HINT_NORMAL;
1319 16 : if( (nStyle & SAL_FRAME_STYLE_DIALOG) && m_pParent != 0 )
1320 0 : eType = GDK_WINDOW_TYPE_HINT_DIALOG;
1321 16 : if( (nStyle & SAL_FRAME_STYLE_INTRO) )
1322 : {
1323 0 : gtk_window_set_role( GTK_WINDOW(m_pWindow), "splashscreen" );
1324 0 : eType = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN;
1325 : }
1326 16 : else if( (nStyle & SAL_FRAME_STYLE_TOOLWINDOW ) )
1327 : {
1328 0 : eType = GDK_WINDOW_TYPE_HINT_UTILITY;
1329 0 : gtk_window_set_skip_taskbar_hint( GTK_WINDOW(m_pWindow), true );
1330 : }
1331 16 : else if( (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
1332 : {
1333 0 : eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
1334 0 : lcl_set_accept_focus( GTK_WINDOW(m_pWindow), false, true );
1335 : }
1336 16 : else if( (nStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
1337 : {
1338 0 : eType = GDK_WINDOW_TYPE_HINT_UTILITY;
1339 : }
1340 : #if !GTK_CHECK_VERSION(3,0,0)
1341 32 : if( (nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN )
1342 16 : && getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
1343 : {
1344 0 : eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
1345 0 : gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), true );
1346 : }
1347 : #endif
1348 16 : gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), eType );
1349 16 : gtk_window_set_gravity( GTK_WINDOW(m_pWindow), GDK_GRAVITY_STATIC );
1350 16 : if( m_pParent && ! (m_pParent->m_nStyle & SAL_FRAME_STYLE_PLUG) )
1351 0 : gtk_window_set_transient_for( GTK_WINDOW(m_pWindow), GTK_WINDOW(m_pParent->m_pWindow) );
1352 : }
1353 0 : else if( (nStyle & SAL_FRAME_STYLE_FLOAT) )
1354 : {
1355 0 : gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), GDK_WINDOW_TYPE_HINT_UTILITY );
1356 : }
1357 16 : if( m_pParent )
1358 0 : m_pParent->m_aChildren.push_back( this );
1359 :
1360 16 : InitCommon();
1361 :
1362 : #if !GTK_CHECK_VERSION(3,0,0)
1363 16 : if( eWinType == GTK_WINDOW_TOPLEVEL )
1364 : {
1365 : #ifdef ENABLE_GMENU_INTEGRATION
1366 : // Enable DBus native menu if available.
1367 16 : ensure_dbus_setup( this );
1368 : #endif
1369 :
1370 16 : guint32 nUserTime = 0;
1371 16 : if( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
1372 : {
1373 16 : nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
1374 : }
1375 16 : lcl_set_user_time(GTK_WINDOW(m_pWindow), nUserTime);
1376 : }
1377 : #endif
1378 :
1379 16 : if( bDecoHandling )
1380 : {
1381 16 : gtk_window_set_resizable( GTK_WINDOW(m_pWindow), (nStyle & SAL_FRAME_STYLE_SIZEABLE) != 0 );
1382 16 : if( ( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION)) ) )
1383 0 : lcl_set_accept_focus( GTK_WINDOW(m_pWindow), false, false );
1384 : }
1385 16 : }
1386 :
1387 0 : GdkNativeWindow GtkSalFrame::findTopLevelSystemWindow( GdkNativeWindow aWindow )
1388 : {
1389 : #if !GTK_CHECK_VERSION(3,0,0)
1390 : ::Window aRoot, aParent;
1391 : ::Window* pChildren;
1392 : unsigned int nChildren;
1393 0 : bool bBreak = false;
1394 0 : do
1395 : {
1396 0 : pChildren = NULL;
1397 0 : nChildren = 0;
1398 0 : aParent = aRoot = None;
1399 0 : XQueryTree( getDisplay()->GetDisplay(), aWindow,
1400 0 : &aRoot, &aParent, &pChildren, &nChildren );
1401 0 : XFree( pChildren );
1402 0 : if( aParent != aRoot )
1403 0 : aWindow = aParent;
1404 0 : int nCount = 0;
1405 0 : Atom* pProps = XListProperties( getDisplay()->GetDisplay(),
1406 : aWindow,
1407 0 : &nCount );
1408 0 : for( int i = 0; i < nCount && ! bBreak; ++i )
1409 0 : bBreak = (pProps[i] == XA_WM_HINTS);
1410 0 : if( pProps )
1411 0 : XFree( pProps );
1412 0 : } while( aParent != aRoot && ! bBreak );
1413 :
1414 0 : return aWindow;
1415 : #else
1416 : (void)aWindow;
1417 : //FIXME: no findToplevelSystemWindow
1418 : return 0;
1419 : #endif
1420 : }
1421 :
1422 0 : void GtkSalFrame::Init( SystemParentData* pSysData )
1423 : {
1424 0 : m_pParent = NULL;
1425 0 : m_aForeignParentWindow = (GdkNativeWindow)pSysData->aWindow;
1426 0 : m_pForeignParent = NULL;
1427 0 : m_aForeignTopLevelWindow = findTopLevelSystemWindow( (GdkNativeWindow)pSysData->aWindow );
1428 0 : m_pForeignTopLevel = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignTopLevelWindow );
1429 0 : gdk_window_set_events( m_pForeignTopLevel, GDK_STRUCTURE_MASK );
1430 :
1431 0 : if( pSysData->nSize > sizeof(pSysData->nSize)+sizeof(pSysData->aWindow) && pSysData->bXEmbedSupport )
1432 : {
1433 : #if GTK_CHECK_VERSION(3,0,0)
1434 : m_pWindow = gtk_plug_new_for_display( getGdkDisplay(), pSysData->aWindow );
1435 : #else
1436 0 : m_pWindow = gtk_plug_new( pSysData->aWindow );
1437 : #endif
1438 0 : m_bWindowIsGtkPlug = true;
1439 0 : widget_set_can_default( m_pWindow, true );
1440 0 : widget_set_can_focus( m_pWindow, true );
1441 0 : gtk_widget_set_sensitive( m_pWindow, true );
1442 : }
1443 : else
1444 : {
1445 0 : m_pWindow = gtk_window_new( GTK_WINDOW_POPUP );
1446 0 : m_bWindowIsGtkPlug = false;
1447 : }
1448 0 : m_nStyle = SAL_FRAME_STYLE_PLUG;
1449 0 : InitCommon();
1450 :
1451 0 : m_pForeignParent = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignParentWindow );
1452 0 : gdk_window_set_events( m_pForeignParent, GDK_STRUCTURE_MASK );
1453 :
1454 : #if !GTK_CHECK_VERSION(3,0,0)
1455 : int x_ret, y_ret;
1456 : unsigned int w, h, bw, d;
1457 : ::Window aRoot;
1458 0 : XGetGeometry( getDisplay()->GetDisplay(), pSysData->aWindow,
1459 0 : &aRoot, &x_ret, &y_ret, &w, &h, &bw, &d );
1460 0 : maGeometry.nWidth = w;
1461 0 : maGeometry.nHeight = h;
1462 0 : gtk_window_resize( GTK_WINDOW(m_pWindow), w, h );
1463 0 : gtk_window_move( GTK_WINDOW(m_pWindow), 0, 0 );
1464 0 : if( ! m_bWindowIsGtkPlug )
1465 : {
1466 0 : XReparentWindow( getDisplay()->GetDisplay(),
1467 : widget_get_xid(m_pWindow),
1468 : (::Window)pSysData->aWindow,
1469 0 : 0, 0 );
1470 : }
1471 : #else
1472 : //FIXME: Handling embedded windows, is going to be fun ...
1473 : #endif
1474 0 : }
1475 :
1476 0 : void GtkSalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
1477 : {
1478 : #if !GTK_CHECK_VERSION(3,0,0)
1479 : XEvent aEvent;
1480 :
1481 0 : memset( &aEvent, 0, sizeof(aEvent) );
1482 0 : aEvent.xclient.window = m_aForeignParentWindow;
1483 0 : aEvent.xclient.type = ClientMessage;
1484 0 : aEvent.xclient.message_type = getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED );
1485 0 : aEvent.xclient.format = 32;
1486 0 : aEvent.xclient.data.l[0] = i_nTimeCode ? i_nTimeCode : CurrentTime;
1487 0 : aEvent.xclient.data.l[1] = 3; // XEMBED_REQUEST_FOCUS
1488 0 : aEvent.xclient.data.l[2] = 0;
1489 0 : aEvent.xclient.data.l[3] = 0;
1490 0 : aEvent.xclient.data.l[4] = 0;
1491 :
1492 0 : GetGenericData()->ErrorTrapPush();
1493 0 : XSendEvent( getDisplay()->GetDisplay(),
1494 : m_aForeignParentWindow,
1495 0 : False, NoEventMask, &aEvent );
1496 0 : GetGenericData()->ErrorTrapPop();
1497 : #else
1498 : (void) this; // loplugin:staticmethods
1499 : (void)i_nTimeCode;
1500 : //FIXME: no askForXEmbedFocus for gtk3 yet
1501 : #endif
1502 0 : }
1503 :
1504 35 : void GtkSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
1505 : {
1506 35 : if( nStyle != m_nExtStyle && ! isChild() )
1507 : {
1508 35 : m_nExtStyle = nStyle;
1509 35 : updateWMClass();
1510 : }
1511 35 : }
1512 :
1513 825 : SalGraphics* GtkSalFrame::AcquireGraphics()
1514 : {
1515 825 : if( m_pWindow )
1516 : {
1517 2416 : for( int i = 0; i < nMaxGraphics; i++ )
1518 : {
1519 1629 : if( ! m_aGraphics[i].bInUse )
1520 : {
1521 38 : m_aGraphics[i].bInUse = true;
1522 38 : if( ! m_aGraphics[i].pGraphics )
1523 : {
1524 : #if GTK_CHECK_VERSION(3,0,0)
1525 : m_aGraphics[i].pGraphics = new GtkSalGraphics( this, m_pWindow );
1526 : if( !m_aFrame.get() )
1527 : {
1528 : AllocateFrame();
1529 : TriggerPaintEvent();
1530 : }
1531 : m_aGraphics[i].pGraphics->setDevice( m_aFrame );
1532 : #else // common case:
1533 31 : m_aGraphics[i].pGraphics = new GtkSalGraphics( this, m_pWindow, m_nXScreen );
1534 : #endif
1535 : }
1536 38 : return m_aGraphics[i].pGraphics;
1537 : }
1538 : }
1539 : }
1540 :
1541 787 : return NULL;
1542 : }
1543 :
1544 32 : void GtkSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
1545 : {
1546 46 : for( int i = 0; i < nMaxGraphics; i++ )
1547 : {
1548 46 : if( m_aGraphics[i].pGraphics == pGraphics )
1549 : {
1550 32 : m_aGraphics[i].bInUse = false;
1551 32 : break;
1552 : }
1553 : }
1554 32 : }
1555 :
1556 58 : bool GtkSalFrame::PostEvent( void* pData )
1557 : {
1558 58 : getDisplay()->SendInternalEvent( this, pData );
1559 58 : return true;
1560 : }
1561 :
1562 26 : void GtkSalFrame::SetTitle( const OUString& rTitle )
1563 : {
1564 26 : m_aTitle = rTitle;
1565 26 : if( m_pWindow && ! isChild() )
1566 26 : gtk_window_set_title( GTK_WINDOW(m_pWindow), OUStringToOString( rTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
1567 26 : }
1568 :
1569 : static inline sal_uInt8 *
1570 2496 : getRow( BitmapBuffer *pBuffer, sal_uLong nRow )
1571 : {
1572 2496 : if( BMP_SCANLINE_ADJUSTMENT( pBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
1573 0 : return pBuffer->mpBits + nRow * pBuffer->mnScanlineSize;
1574 : else
1575 2496 : return pBuffer->mpBits + ( pBuffer->mnHeight - nRow - 1 ) * pBuffer->mnScanlineSize;
1576 : }
1577 :
1578 : static GdkPixbuf *
1579 56 : bitmapToPixbuf( SalBitmap *pSalBitmap, SalBitmap *pSalAlpha )
1580 : {
1581 56 : g_return_val_if_fail( pSalBitmap != NULL, NULL );
1582 56 : g_return_val_if_fail( pSalAlpha != NULL, NULL );
1583 :
1584 56 : BitmapBuffer *pBitmap = pSalBitmap->AcquireBuffer( BITMAP_READ_ACCESS );
1585 56 : g_return_val_if_fail( pBitmap != NULL, NULL );
1586 56 : g_return_val_if_fail( pBitmap->mnBitCount == 24, NULL );
1587 :
1588 56 : BitmapBuffer *pAlpha = pSalAlpha->AcquireBuffer( BITMAP_READ_ACCESS );
1589 56 : g_return_val_if_fail( pAlpha != NULL, NULL );
1590 56 : g_return_val_if_fail( pAlpha->mnBitCount == 8, NULL );
1591 :
1592 56 : Size aSize = pSalBitmap->GetSize();
1593 56 : g_return_val_if_fail( pSalAlpha->GetSize() == aSize, NULL );
1594 :
1595 : int nX, nY;
1596 56 : guchar *pPixbufData = static_cast<guchar *>(g_malloc (4 * aSize.Width() * aSize.Height() ));
1597 56 : guchar *pDestData = pPixbufData;
1598 :
1599 1304 : for( nY = 0; nY < pBitmap->mnHeight; nY++ )
1600 : {
1601 1248 : sal_uInt8 *pData = getRow( pBitmap, nY );
1602 1248 : sal_uInt8 *pAlphaData = getRow( pAlpha, nY );
1603 :
1604 31712 : for( nX = 0; nX < pBitmap->mnWidth; nX++ )
1605 : {
1606 30464 : if( pBitmap->mnFormat == BMP_FORMAT_24BIT_TC_BGR )
1607 : {
1608 30464 : pDestData[2] = *pData++;
1609 30464 : pDestData[1] = *pData++;
1610 30464 : pDestData[0] = *pData++;
1611 : }
1612 : else // BMP_FORMAT_24BIT_TC_RGB
1613 : {
1614 0 : pDestData[0] = *pData++;
1615 0 : pDestData[1] = *pData++;
1616 0 : pDestData[2] = *pData++;
1617 : }
1618 30464 : pDestData += 3;
1619 30464 : *pDestData++ = 255 - *pAlphaData++;
1620 : }
1621 : }
1622 :
1623 56 : pSalBitmap->ReleaseBuffer( pBitmap, BITMAP_READ_ACCESS );
1624 56 : pSalAlpha->ReleaseBuffer( pAlpha, BITMAP_READ_ACCESS );
1625 :
1626 : return gdk_pixbuf_new_from_data( pPixbufData,
1627 : GDK_COLORSPACE_RGB, true, 8,
1628 112 : aSize.Width(), aSize.Height(),
1629 56 : aSize.Width() * 4,
1630 : reinterpret_cast<GdkPixbufDestroyNotify>(g_free),
1631 168 : NULL );
1632 : }
1633 :
1634 28 : void GtkSalFrame::SetIcon( sal_uInt16 nIcon )
1635 : {
1636 28 : if( (m_nStyle & (SAL_FRAME_STYLE_PLUG|SAL_FRAME_STYLE_SYSTEMCHILD|SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_INTRO|SAL_FRAME_STYLE_OWNERDRAWDECORATION))
1637 28 : || ! m_pWindow )
1638 0 : return;
1639 :
1640 28 : if( !ImplGetResMgr() )
1641 0 : return;
1642 :
1643 : GdkPixbuf *pBuf;
1644 28 : GList *pIcons = NULL;
1645 :
1646 28 : sal_uInt16 nOffsets[2] = { SV_ICON_SMALL_START, SV_ICON_LARGE_START };
1647 : sal_uInt16 nIndex;
1648 :
1649 84 : for( nIndex = 0; nIndex < sizeof(nOffsets)/ sizeof(sal_uInt16); nIndex++ )
1650 : {
1651 : // #i44723# workaround gcc temporary problem
1652 56 : ResId aResId( nOffsets[nIndex] + nIcon, *ImplGetResMgr() );
1653 56 : BitmapEx aIcon( aResId );
1654 :
1655 : // #i81083# convert to 24bit/8bit alpha bitmap
1656 112 : Bitmap aBmp = aIcon.GetBitmap();
1657 56 : if( aBmp.GetBitCount() != 24 || ! aIcon.IsAlpha() )
1658 : {
1659 32 : if( aBmp.GetBitCount() != 24 )
1660 32 : aBmp.Convert( BMP_CONVERSION_24BIT );
1661 32 : AlphaMask aMask;
1662 32 : if( ! aIcon.IsAlpha() )
1663 : {
1664 16 : switch( aIcon.GetTransparentType() )
1665 : {
1666 : case TRANSPARENT_NONE:
1667 : {
1668 0 : sal_uInt8 nTrans = 0;
1669 0 : aMask = AlphaMask( aBmp.GetSizePixel(), &nTrans );
1670 : }
1671 0 : break;
1672 : case TRANSPARENT_COLOR:
1673 0 : aMask = AlphaMask( aBmp.CreateMask( aIcon.GetTransparentColor() ) );
1674 0 : break;
1675 : case TRANSPARENT_BITMAP:
1676 16 : aMask = AlphaMask( aIcon.GetMask() );
1677 16 : break;
1678 : default:
1679 : OSL_FAIL( "unhandled transparent type" );
1680 0 : break;
1681 : }
1682 : }
1683 : else
1684 16 : aMask = aIcon.GetAlpha();
1685 32 : aIcon = BitmapEx( aBmp, aMask );
1686 : }
1687 :
1688 56 : ImpBitmap *pIconImpBitmap = aIcon.ImplGetBitmapImpBitmap();
1689 56 : ImpBitmap *pIconImpMask = aIcon.ImplGetMaskImpBitmap();
1690 :
1691 56 : if( pIconImpBitmap && pIconImpMask )
1692 : {
1693 : SalBitmap *pIconBitmap =
1694 56 : pIconImpBitmap->ImplGetSalBitmap();
1695 : SalBitmap *pIconMask =
1696 56 : pIconImpMask->ImplGetSalBitmap();
1697 :
1698 56 : if( ( pBuf = bitmapToPixbuf( pIconBitmap, pIconMask ) ) )
1699 56 : pIcons = g_list_prepend( pIcons, pBuf );
1700 : }
1701 56 : }
1702 :
1703 28 : gtk_window_set_icon_list( GTK_WINDOW(m_pWindow), pIcons );
1704 :
1705 28 : g_list_foreach( pIcons, reinterpret_cast<GFunc>(g_object_unref), NULL );
1706 28 : g_list_free( pIcons );
1707 : }
1708 :
1709 2 : void GtkSalFrame::SetMenu( SalMenu* pSalMenu )
1710 : {
1711 : // if(m_pSalMenu)
1712 : // {
1713 : // static_cast<GtkSalMenu*>(m_pSalMenu)->DisconnectFrame();
1714 : // }
1715 2 : m_pSalMenu = pSalMenu;
1716 2 : }
1717 :
1718 0 : SalMenu* GtkSalFrame::GetMenu()
1719 : {
1720 0 : return m_pSalMenu;
1721 : }
1722 :
1723 0 : void GtkSalFrame::DrawMenuBar()
1724 : {
1725 0 : }
1726 :
1727 0 : void GtkSalFrame::Center()
1728 : {
1729 : long nX, nY;
1730 :
1731 0 : if( m_pParent )
1732 : {
1733 0 : nX = ((long)m_pParent->maGeometry.nWidth - (long)maGeometry.nWidth)/2;
1734 0 : nY = ((long)m_pParent->maGeometry.nHeight - (long)maGeometry.nHeight)/2;
1735 : }
1736 : else
1737 : {
1738 0 : GdkScreen *pScreen = NULL;
1739 : gint px, py;
1740 : GdkModifierType nMask;
1741 0 : gdk_display_get_pointer( getGdkDisplay(), &pScreen, &px, &py, &nMask );
1742 0 : if( !pScreen )
1743 0 : pScreen = gtk_widget_get_screen( m_pWindow );
1744 :
1745 : gint nMonitor;
1746 0 : nMonitor = gdk_screen_get_monitor_at_point( pScreen, px, py );
1747 :
1748 : GdkRectangle aMonitor;
1749 0 : gdk_screen_get_monitor_geometry( pScreen, nMonitor, &aMonitor );
1750 :
1751 0 : nX = aMonitor.x + (aMonitor.width - (long)maGeometry.nWidth)/2;
1752 0 : nY = aMonitor.y + (aMonitor.height - (long)maGeometry.nHeight)/2;
1753 : }
1754 0 : SetPosSize( nX, nY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
1755 0 : }
1756 :
1757 16 : Size GtkSalFrame::calcDefaultSize()
1758 : {
1759 16 : return bestmaxFrameSizeForScreenSize(getDisplay()->GetScreenSize(GetDisplayScreen()));
1760 : }
1761 :
1762 0 : void GtkSalFrame::SetDefaultSize()
1763 : {
1764 0 : Size aDefSize = calcDefaultSize();
1765 :
1766 0 : SetPosSize( 0, 0, aDefSize.Width(), aDefSize.Height(),
1767 0 : SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
1768 :
1769 0 : if( (m_nStyle & SAL_FRAME_STYLE_DEFAULT) && m_pWindow )
1770 0 : gtk_window_maximize( GTK_WINDOW(m_pWindow) );
1771 0 : }
1772 :
1773 0 : static void initClientId()
1774 : {
1775 : #if !GTK_CHECK_VERSION(3,0,0)
1776 : static bool bOnce = false;
1777 0 : if (!bOnce)
1778 : {
1779 0 : bOnce = true;
1780 0 : const OString& rID = SessionManagerClient::getSessionID();
1781 0 : if (!rID.isEmpty())
1782 0 : gdk_set_sm_client_id(rID.getStr());
1783 : }
1784 : #else
1785 : // No session management support for gtk3+ - this is now legacy.
1786 : #endif
1787 0 : }
1788 :
1789 1 : void GtkSalFrame::Show( bool bVisible, bool bNoActivate )
1790 : {
1791 1 : if( m_pWindow )
1792 : {
1793 : #if !GTK_CHECK_VERSION(3,0,0)
1794 1 : if( m_pParent && (m_pParent->m_nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN)
1795 1 : && getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
1796 0 : gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), bVisible );
1797 : #endif
1798 1 : if( bVisible )
1799 : {
1800 0 : initClientId();
1801 0 : getDisplay()->startupNotificationCompleted();
1802 :
1803 0 : if( m_bDefaultPos )
1804 0 : Center();
1805 0 : if( m_bDefaultSize )
1806 0 : SetDefaultSize();
1807 0 : setMinMaxSize();
1808 :
1809 : #if !GTK_CHECK_VERSION(3,0,0)
1810 : // #i45160# switch to desktop where a dialog with parent will appear
1811 0 : if( m_pParent && m_pParent->m_nWorkArea != m_nWorkArea && IS_WIDGET_MAPPED(m_pParent->m_pWindow) )
1812 0 : getDisplay()->getWMAdaptor()->switchToWorkArea( m_pParent->m_nWorkArea );
1813 : #endif
1814 :
1815 0 : if( isFloatGrabWindow() &&
1816 0 : m_pParent &&
1817 0 : m_nFloats == 0 &&
1818 0 : ! getDisplay()->GetCaptureFrame() )
1819 : {
1820 : /* #i63086#
1821 : * outsmart Metacity's "focus:mouse" mode
1822 : * which insists on taking the focus from the document
1823 : * to the new float. Grab focus to parent frame BEFORE
1824 : * showing the float (cannot grab it to the float
1825 : * before show).
1826 : */
1827 0 : m_pParent->grabPointer( true, true );
1828 : }
1829 :
1830 : #if !GTK_CHECK_VERSION(3,0,0)
1831 0 : guint32 nUserTime = 0;
1832 0 : if( ! bNoActivate && (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
1833 0 : nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
1834 :
1835 : //For these floating windows we don't want the main window to lose focus, and metacity has...
1836 : // metacity-2.24.0/src/core/window.c
1837 :
1838 : // if ((focus_window != NULL) && XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time))
1839 : // "compare" window focus prevented by other activity
1840 :
1841 : // where "compare" is this window
1842 :
1843 : // which leads to...
1844 :
1845 : // /* This happens for error dialogs or alerts; these need to remain on
1846 : // * top, but it would be confusing to have its ancestor remain
1847 : // * focused.
1848 : // */
1849 : // if (meta_window_is_ancestor_of_transient (focus_window, window))
1850 : // "The focus window %s is an ancestor of the newly mapped "
1851 : // "window %s which isn't being focused. Unfocusing the "
1852 : // "ancestor.\n",
1853 :
1854 : // i.e. having a time < that of the toplevel frame means that the toplevel frame gets unfocused.
1855 : // awesome.
1856 0 : if( nUserTime == 0 )
1857 : {
1858 0 : nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
1859 : }
1860 0 : lcl_set_user_time(GTK_WINDOW(m_pWindow), nUserTime );
1861 : #endif
1862 :
1863 0 : if( ! bNoActivate && (m_nStyle & SAL_FRAME_STYLE_TOOLWINDOW) )
1864 0 : m_bSetFocusOnMap = true;
1865 :
1866 0 : gtk_widget_show( m_pWindow );
1867 :
1868 0 : if( isFloatGrabWindow() )
1869 : {
1870 0 : m_nFloats++;
1871 0 : if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 1 )
1872 : {
1873 0 : grabPointer(true, true);
1874 0 : GtkSalFrame *pKeyboardFrame = this;
1875 0 : while (pKeyboardFrame->m_pParent)
1876 0 : pKeyboardFrame = pKeyboardFrame->m_pParent;
1877 0 : pKeyboardFrame->grabKeyboard(true);
1878 : }
1879 : // #i44068# reset parent's IM context
1880 0 : if( m_pParent )
1881 0 : m_pParent->EndExtTextInput(EndExtTextInputFlags::NONE);
1882 : }
1883 0 : if( m_bWindowIsGtkPlug )
1884 0 : askForXEmbedFocus( 0 );
1885 : }
1886 : else
1887 : {
1888 1 : if( isFloatGrabWindow() )
1889 : {
1890 0 : m_nFloats--;
1891 0 : if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 0)
1892 : {
1893 0 : GtkSalFrame *pKeyboardFrame = this;
1894 0 : while (pKeyboardFrame->m_pParent)
1895 0 : pKeyboardFrame = pKeyboardFrame->m_pParent;
1896 0 : pKeyboardFrame->grabKeyboard(false);
1897 0 : grabPointer(false);
1898 : }
1899 : }
1900 1 : gtk_widget_hide( m_pWindow );
1901 1 : if( m_pIMHandler )
1902 0 : m_pIMHandler->focusChanged( false );
1903 : // flush here; there may be a very seldom race between
1904 : // the display connection used for clipboard and our connection
1905 1 : Flush();
1906 : }
1907 1 : CallCallback( SALEVENT_RESIZE, NULL );
1908 1 : TriggerPaintEvent();
1909 : }
1910 1 : }
1911 :
1912 9 : void GtkSalFrame::setMinMaxSize()
1913 : {
1914 : /* #i34504# metacity (and possibly others) do not treat
1915 : * _NET_WM_STATE_FULLSCREEN and max_width/height independently;
1916 : * whether they should is undefined. So don't set the max size hint
1917 : * for a full screen window.
1918 : */
1919 9 : if( m_pWindow && ! isChild() )
1920 : {
1921 : GdkGeometry aGeo;
1922 9 : int aHints = 0;
1923 9 : if( m_nStyle & SAL_FRAME_STYLE_SIZEABLE )
1924 : {
1925 9 : if( m_aMinSize.Width() && m_aMinSize.Height() && ! m_bFullscreen )
1926 : {
1927 0 : aGeo.min_width = m_aMinSize.Width();
1928 0 : aGeo.min_height = m_aMinSize.Height();
1929 0 : aHints |= GDK_HINT_MIN_SIZE;
1930 : }
1931 9 : if( m_aMaxSize.Width() && m_aMaxSize.Height() && ! m_bFullscreen )
1932 : {
1933 0 : aGeo.max_width = m_aMaxSize.Width();
1934 0 : aGeo.max_height = m_aMaxSize.Height();
1935 0 : aHints |= GDK_HINT_MAX_SIZE;
1936 : }
1937 : }
1938 : else
1939 : {
1940 0 : if( ! m_bFullscreen )
1941 : {
1942 0 : aGeo.min_width = maGeometry.nWidth;
1943 0 : aGeo.min_height = maGeometry.nHeight;
1944 0 : aHints |= GDK_HINT_MIN_SIZE;
1945 :
1946 0 : aGeo.max_width = maGeometry.nWidth;
1947 0 : aGeo.max_height = maGeometry.nHeight;
1948 0 : aHints |= GDK_HINT_MAX_SIZE;
1949 : }
1950 : }
1951 9 : if( m_bFullscreen && m_aMaxSize.Width() && m_aMaxSize.Height() )
1952 : {
1953 0 : aGeo.max_width = m_aMaxSize.Width();
1954 0 : aGeo.max_height = m_aMaxSize.Height();
1955 0 : aHints |= GDK_HINT_MAX_SIZE;
1956 : }
1957 9 : if( aHints )
1958 0 : gtk_window_set_geometry_hints( GTK_WINDOW(m_pWindow),
1959 : NULL,
1960 : &aGeo,
1961 0 : GdkWindowHints( aHints ) );
1962 : }
1963 9 : }
1964 :
1965 0 : void GtkSalFrame::SetMaxClientSize( long nWidth, long nHeight )
1966 : {
1967 0 : if( ! isChild() )
1968 : {
1969 0 : m_aMaxSize = Size( nWidth, nHeight );
1970 : // Show does a setMinMaxSize
1971 0 : if( IS_WIDGET_MAPPED( m_pWindow ) )
1972 0 : setMinMaxSize();
1973 : }
1974 0 : }
1975 0 : void GtkSalFrame::SetMinClientSize( long nWidth, long nHeight )
1976 : {
1977 0 : if( ! isChild() )
1978 : {
1979 0 : m_aMinSize = Size( nWidth, nHeight );
1980 0 : if( m_pWindow )
1981 : {
1982 0 : gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
1983 : // Show does a setMinMaxSize
1984 0 : if( IS_WIDGET_MAPPED( m_pWindow ) )
1985 0 : setMinMaxSize();
1986 : }
1987 : }
1988 0 : }
1989 :
1990 : // FIXME: we should really be an SvpSalFrame sub-class, and
1991 : // share their AllocateFrame !
1992 0 : void GtkSalFrame::AllocateFrame()
1993 : {
1994 : #if GTK_CHECK_VERSION(3,0,0)
1995 : basegfx::B2IVector aFrameSize( maGeometry.nWidth, maGeometry.nHeight );
1996 : if( ! m_aFrame.get() || m_aFrame->getSize() != aFrameSize )
1997 : {
1998 : if( aFrameSize.getX() == 0 )
1999 : aFrameSize.setX( 1 );
2000 : if( aFrameSize.getY() == 0 )
2001 : aFrameSize.setY( 1 );
2002 : int cairo_stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, aFrameSize.getX());
2003 : m_aFrame = basebmp::createBitmapDevice(aFrameSize, true,
2004 : basebmp::Format::ThirtyTwoBitTcMaskBGRX, cairo_stride);
2005 : m_aFrame->setDamageTracker(
2006 : basebmp::IBitmapDeviceDamageTrackerSharedPtr(new DamageTracker(*this)) );
2007 : SAL_INFO("vcl.gtk3", "allocated m_aFrame size of " << maGeometry.nWidth << " x " << maGeometry.nHeight);
2008 :
2009 : #if OSL_DEBUG_LEVEL > 0 // set background to orange
2010 : m_aFrame->clear( basebmp::Color( 255, 127, 0 ) );
2011 : #endif
2012 :
2013 : // update device in existing graphics
2014 : for( unsigned int i = 0; i < SAL_N_ELEMENTS( m_aGraphics ); ++i )
2015 : {
2016 : if( !m_aGraphics[i].pGraphics )
2017 : continue;
2018 : m_aGraphics[i].pGraphics->setDevice( m_aFrame );
2019 : }
2020 : }
2021 : #endif
2022 0 : }
2023 :
2024 9 : void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
2025 : {
2026 9 : if( !m_pWindow || isChild( true, false ) )
2027 9 : return;
2028 :
2029 9 : bool bSized = false, bMoved = false;
2030 :
2031 9 : if( (nFlags & ( SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT )) &&
2032 9 : (nWidth > 0 && nHeight > 0 ) // sometimes stupid things happen
2033 : )
2034 : {
2035 9 : m_bDefaultSize = false;
2036 :
2037 9 : if( (unsigned long)nWidth != maGeometry.nWidth || (unsigned long)nHeight != maGeometry.nHeight )
2038 0 : bSized = true;
2039 9 : maGeometry.nWidth = nWidth;
2040 9 : maGeometry.nHeight = nHeight;
2041 :
2042 9 : if( isChild( false, true ) )
2043 0 : gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
2044 9 : else if( ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) )
2045 9 : gtk_window_resize( GTK_WINDOW(m_pWindow), nWidth, nHeight );
2046 9 : setMinMaxSize();
2047 : }
2048 0 : else if( m_bDefaultSize )
2049 0 : SetDefaultSize();
2050 :
2051 9 : m_bDefaultSize = false;
2052 :
2053 9 : if( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) )
2054 : {
2055 9 : if( m_pParent )
2056 : {
2057 0 : if( AllSettings::GetLayoutRTL() )
2058 0 : nX = m_pParent->maGeometry.nWidth-maGeometry.nWidth-1-nX;
2059 0 : nX += m_pParent->maGeometry.nX;
2060 0 : nY += m_pParent->maGeometry.nY;
2061 : }
2062 :
2063 : #if GTK_CHECK_VERSION(3,0,0)
2064 : // adjust position to avoid off screen windows
2065 : // but allow toolbars to be positioned partly off screen by the user
2066 : Size aScreenSize = getDisplay()->GetScreenSize( GetDisplayScreen() );
2067 : if( ! (m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
2068 : {
2069 : if( nX < (long)maGeometry.nLeftDecoration )
2070 : nX = maGeometry.nLeftDecoration;
2071 : if( nY < (long)maGeometry.nTopDecoration )
2072 : nY = maGeometry.nTopDecoration;
2073 : if( (nX + (long)maGeometry.nWidth + (long)maGeometry.nRightDecoration) > (long)aScreenSize.Width() )
2074 : nX = aScreenSize.Width() - maGeometry.nWidth - maGeometry.nRightDecoration;
2075 : if( (nY + (long)maGeometry.nHeight + (long)maGeometry.nBottomDecoration) > (long)aScreenSize.Height() )
2076 : nY = aScreenSize.Height() - maGeometry.nHeight - maGeometry.nBottomDecoration;
2077 : }
2078 : else
2079 : {
2080 : if( nX + (long)maGeometry.nWidth < 10 )
2081 : nX = 10 - (long)maGeometry.nWidth;
2082 : if( nY + (long)maGeometry.nHeight < 10 )
2083 : nY = 10 - (long)maGeometry.nHeight;
2084 : if( nX > (long)aScreenSize.Width() - 10 )
2085 : nX = (long)aScreenSize.Width() - 10;
2086 : if( nY > (long)aScreenSize.Height() - 10 )
2087 : nY = (long)aScreenSize.Height() - 10;
2088 : }
2089 : #endif
2090 :
2091 9 : if( nX != maGeometry.nX || nY != maGeometry.nY )
2092 0 : bMoved = true;
2093 9 : maGeometry.nX = nX;
2094 9 : maGeometry.nY = nY;
2095 :
2096 9 : m_bDefaultPos = false;
2097 :
2098 9 : moveWindow( maGeometry.nX, maGeometry.nY );
2099 :
2100 9 : updateScreenNumber();
2101 : }
2102 0 : else if( m_bDefaultPos )
2103 0 : Center();
2104 :
2105 9 : m_bDefaultPos = false;
2106 :
2107 9 : if( bSized )
2108 0 : AllocateFrame();
2109 :
2110 9 : if( bSized && ! bMoved )
2111 0 : CallCallback( SALEVENT_RESIZE, NULL );
2112 9 : else if( bMoved && ! bSized )
2113 0 : CallCallback( SALEVENT_MOVE, NULL );
2114 9 : else if( bMoved && bSized )
2115 0 : CallCallback( SALEVENT_MOVERESIZE, NULL );
2116 :
2117 9 : if (bSized)
2118 0 : TriggerPaintEvent();
2119 : }
2120 :
2121 15 : void GtkSalFrame::GetClientSize( long& rWidth, long& rHeight )
2122 : {
2123 15 : if( m_pWindow && !(m_nState & GDK_WINDOW_STATE_ICONIFIED) )
2124 : {
2125 15 : rWidth = maGeometry.nWidth;
2126 15 : rHeight = maGeometry.nHeight;
2127 : }
2128 : else
2129 0 : rWidth = rHeight = 0;
2130 15 : }
2131 :
2132 27 : void GtkSalFrame::GetWorkArea( Rectangle& rRect )
2133 : {
2134 : #if !GTK_CHECK_VERSION(3,0,0)
2135 27 : rRect = GetGtkSalData()->GetGtkDisplay()->getWMAdaptor()->getWorkArea( 0 );
2136 : #else
2137 : GdkScreen *pScreen = gtk_window_get_screen(GTK_WINDOW(m_pWindow));
2138 : gint nMonitor = gdk_screen_get_monitor_at_window(pScreen, widget_get_window(m_pWindow));
2139 : GdkRectangle aRect;
2140 : gdk_screen_get_monitor_workarea(pScreen, nMonitor, &aRect);
2141 : rRect = Rectangle(aRect.x, aRect.y, aRect.width, aRect.height);
2142 : #endif
2143 27 : }
2144 :
2145 3 : SalFrame* GtkSalFrame::GetParent() const
2146 : {
2147 3 : return m_pParent;
2148 : }
2149 :
2150 11 : void GtkSalFrame::SetWindowState( const SalFrameState* pState )
2151 : {
2152 11 : if( ! m_pWindow || ! pState || isChild( true, false ) )
2153 11 : return;
2154 :
2155 : const sal_uLong nMaxGeometryMask =
2156 : WINDOWSTATE_MASK_X | WINDOWSTATE_MASK_Y |
2157 : WINDOWSTATE_MASK_WIDTH | WINDOWSTATE_MASK_HEIGHT |
2158 : WINDOWSTATE_MASK_MAXIMIZED_X | WINDOWSTATE_MASK_MAXIMIZED_Y |
2159 11 : WINDOWSTATE_MASK_MAXIMIZED_WIDTH | WINDOWSTATE_MASK_MAXIMIZED_HEIGHT;
2160 :
2161 22 : if( (pState->mnMask & WINDOWSTATE_MASK_STATE) &&
2162 22 : ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) &&
2163 13 : (pState->mnState & WINDOWSTATE_STATE_MAXIMIZED) &&
2164 2 : (pState->mnMask & nMaxGeometryMask) == nMaxGeometryMask )
2165 : {
2166 0 : resizeWindow( pState->mnWidth, pState->mnHeight );
2167 0 : moveWindow( pState->mnX, pState->mnY );
2168 0 : m_bDefaultPos = m_bDefaultSize = false;
2169 :
2170 0 : maGeometry.nX = pState->mnMaximizedX;
2171 0 : maGeometry.nY = pState->mnMaximizedY;
2172 0 : maGeometry.nWidth = pState->mnMaximizedWidth;
2173 0 : maGeometry.nHeight = pState->mnMaximizedHeight;
2174 0 : updateScreenNumber();
2175 :
2176 0 : m_nState = GdkWindowState( m_nState | GDK_WINDOW_STATE_MAXIMIZED );
2177 : m_aRestorePosSize = Rectangle( Point( pState->mnX, pState->mnY ),
2178 0 : Size( pState->mnWidth, pState->mnHeight ) );
2179 0 : CallCallback( SALEVENT_RESIZE, NULL );
2180 : }
2181 11 : else if( pState->mnMask & (WINDOWSTATE_MASK_X | WINDOWSTATE_MASK_Y |
2182 : WINDOWSTATE_MASK_WIDTH | WINDOWSTATE_MASK_HEIGHT ) )
2183 : {
2184 9 : sal_uInt16 nPosSizeFlags = 0;
2185 9 : long nX = pState->mnX - (m_pParent ? m_pParent->maGeometry.nX : 0);
2186 9 : long nY = pState->mnY - (m_pParent ? m_pParent->maGeometry.nY : 0);
2187 9 : if( pState->mnMask & WINDOWSTATE_MASK_X )
2188 9 : nPosSizeFlags |= SAL_FRAME_POSSIZE_X;
2189 : else
2190 0 : nX = maGeometry.nX - (m_pParent ? m_pParent->maGeometry.nX : 0);
2191 9 : if( pState->mnMask & WINDOWSTATE_MASK_Y )
2192 9 : nPosSizeFlags |= SAL_FRAME_POSSIZE_Y;
2193 : else
2194 0 : nY = maGeometry.nY - (m_pParent ? m_pParent->maGeometry.nY : 0);
2195 9 : if( pState->mnMask & WINDOWSTATE_MASK_WIDTH )
2196 9 : nPosSizeFlags |= SAL_FRAME_POSSIZE_WIDTH;
2197 9 : if( pState->mnMask & WINDOWSTATE_MASK_HEIGHT )
2198 9 : nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT;
2199 9 : SetPosSize( nX, nY, pState->mnWidth, pState->mnHeight, nPosSizeFlags );
2200 : }
2201 11 : if( pState->mnMask & WINDOWSTATE_MASK_STATE && ! isChild() )
2202 : {
2203 11 : if( pState->mnState & WINDOWSTATE_STATE_MAXIMIZED )
2204 2 : gtk_window_maximize( GTK_WINDOW(m_pWindow) );
2205 : else
2206 9 : gtk_window_unmaximize( GTK_WINDOW(m_pWindow) );
2207 : /* #i42379# there is no rollup state in GDK; and rolled up windows are
2208 : * (probably depending on the WM) reported as iconified. If we iconify a
2209 : * window here that was e.g. a dialog, then it will be unmapped but still
2210 : * not be displayed in the task list, so it's an iconified window that
2211 : * the user cannot get out of this state. So do not set the iconified state
2212 : * on windows with a parent (that is transient frames) since these tend
2213 : * to not be represented in an icon task list.
2214 : */
2215 11 : if( (pState->mnState & WINDOWSTATE_STATE_MINIMIZED)
2216 0 : && ! m_pParent )
2217 0 : gtk_window_iconify( GTK_WINDOW(m_pWindow) );
2218 : else
2219 11 : gtk_window_deiconify( GTK_WINDOW(m_pWindow) );
2220 : }
2221 11 : TriggerPaintEvent();
2222 : }
2223 :
2224 43 : bool GtkSalFrame::GetWindowState( SalFrameState* pState )
2225 : {
2226 43 : pState->mnState = WINDOWSTATE_STATE_NORMAL;
2227 43 : pState->mnMask = WINDOWSTATE_MASK_STATE;
2228 : // rollup ? gtk 2.2 does not seem to support the shaded state
2229 43 : if( (m_nState & GDK_WINDOW_STATE_ICONIFIED) )
2230 0 : pState->mnState |= WINDOWSTATE_STATE_MINIMIZED;
2231 43 : if( m_nState & GDK_WINDOW_STATE_MAXIMIZED )
2232 : {
2233 0 : pState->mnState |= WINDOWSTATE_STATE_MAXIMIZED;
2234 0 : pState->mnX = m_aRestorePosSize.Left();
2235 0 : pState->mnY = m_aRestorePosSize.Top();
2236 0 : pState->mnWidth = m_aRestorePosSize.GetWidth();
2237 0 : pState->mnHeight = m_aRestorePosSize.GetHeight();
2238 0 : pState->mnMaximizedX = maGeometry.nX;
2239 0 : pState->mnMaximizedY = maGeometry.nY;
2240 0 : pState->mnMaximizedWidth = maGeometry.nWidth;
2241 0 : pState->mnMaximizedHeight = maGeometry.nHeight;
2242 : pState->mnMask |= WINDOWSTATE_MASK_MAXIMIZED_X |
2243 : WINDOWSTATE_MASK_MAXIMIZED_Y |
2244 : WINDOWSTATE_MASK_MAXIMIZED_WIDTH |
2245 0 : WINDOWSTATE_MASK_MAXIMIZED_HEIGHT;
2246 : }
2247 : else
2248 : {
2249 43 : pState->mnX = maGeometry.nX;
2250 43 : pState->mnY = maGeometry.nY;
2251 43 : pState->mnWidth = maGeometry.nWidth;
2252 43 : pState->mnHeight = maGeometry.nHeight;
2253 : }
2254 : pState->mnMask |= WINDOWSTATE_MASK_X |
2255 : WINDOWSTATE_MASK_Y |
2256 : WINDOWSTATE_MASK_WIDTH |
2257 43 : WINDOWSTATE_MASK_HEIGHT;
2258 :
2259 43 : return true;
2260 : }
2261 :
2262 : typedef enum {
2263 : SET_RETAIN_SIZE,
2264 : SET_FULLSCREEN,
2265 : SET_UN_FULLSCREEN
2266 : } SetType;
2267 :
2268 0 : void GtkSalFrame::SetScreen( unsigned int nNewScreen, int eType, Rectangle *pSize )
2269 : {
2270 0 : if( !m_pWindow )
2271 0 : return;
2272 :
2273 0 : if (maGeometry.nDisplayScreenNumber == nNewScreen && eType == SET_RETAIN_SIZE)
2274 0 : return;
2275 :
2276 0 : GdkScreen *pScreen = NULL;
2277 : GdkRectangle aNewMonitor;
2278 :
2279 0 : bool bSpanAllScreens = nNewScreen == (unsigned int)-1;
2280 0 : m_bSpanMonitorsWhenFullscreen = bSpanAllScreens && getDisplay()->getSystem()->GetDisplayScreenCount() > 1;
2281 :
2282 0 : if (m_bSpanMonitorsWhenFullscreen) //span all screens
2283 : {
2284 0 : pScreen = gtk_widget_get_screen( m_pWindow );
2285 0 : aNewMonitor.x = 0;
2286 0 : aNewMonitor.y = 0;
2287 0 : aNewMonitor.width = gdk_screen_get_width(pScreen);
2288 0 : aNewMonitor.height = gdk_screen_get_height(pScreen);
2289 : }
2290 : else
2291 : {
2292 : gint nMonitor;
2293 0 : bool bSameMonitor = false;
2294 :
2295 0 : if (!bSpanAllScreens)
2296 : {
2297 0 : pScreen = getDisplay()->getSystem()->getScreenMonitorFromIdx( nNewScreen, nMonitor );
2298 0 : if (!pScreen)
2299 : {
2300 : g_warning ("Attempt to move GtkSalFrame to invalid screen %d => "
2301 0 : "fallback to current\n", nNewScreen);
2302 : }
2303 : }
2304 :
2305 0 : if (!pScreen)
2306 : {
2307 0 : pScreen = gtk_widget_get_screen( m_pWindow );
2308 0 : bSameMonitor = true;
2309 : }
2310 :
2311 : // Heavy lifting, need to move screen ...
2312 0 : if( pScreen != gtk_widget_get_screen( m_pWindow ))
2313 0 : gtk_window_set_screen( GTK_WINDOW( m_pWindow ), pScreen );
2314 :
2315 : gint nOldMonitor = gdk_screen_get_monitor_at_window(
2316 0 : pScreen, widget_get_window( m_pWindow ) );
2317 0 : if (bSameMonitor)
2318 0 : nMonitor = nOldMonitor;
2319 :
2320 : #if OSL_DEBUG_LEVEL > 1
2321 : if( nMonitor == nOldMonitor )
2322 : g_warning( "An apparently pointless SetScreen - should we elide it ?" );
2323 : #endif
2324 :
2325 : GdkRectangle aOldMonitor;
2326 0 : gdk_screen_get_monitor_geometry( pScreen, nOldMonitor, &aOldMonitor );
2327 0 : gdk_screen_get_monitor_geometry( pScreen, nMonitor, &aNewMonitor );
2328 :
2329 0 : maGeometry.nX = aNewMonitor.x + maGeometry.nX - aOldMonitor.x;
2330 0 : maGeometry.nY = aNewMonitor.y + maGeometry.nY - aOldMonitor.y;
2331 : }
2332 :
2333 0 : bool bResize = false;
2334 0 : bool bVisible = IS_WIDGET_MAPPED( m_pWindow );
2335 0 : if( bVisible )
2336 0 : Show( false );
2337 :
2338 0 : if( eType == SET_FULLSCREEN )
2339 : {
2340 0 : maGeometry.nX = aNewMonitor.x;
2341 0 : maGeometry.nY = aNewMonitor.y;
2342 0 : maGeometry.nWidth = aNewMonitor.width;
2343 0 : maGeometry.nHeight = aNewMonitor.height;
2344 0 : m_nStyle |= SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
2345 0 : bResize = true;
2346 :
2347 : // #i110881# for the benefit of compiz set a max size here
2348 : // else setting to fullscreen fails for unknown reasons
2349 0 : m_aMaxSize.Width() = aNewMonitor.width;
2350 0 : m_aMaxSize.Height() = aNewMonitor.height;
2351 : }
2352 :
2353 0 : if( pSize && eType == SET_UN_FULLSCREEN )
2354 : {
2355 0 : maGeometry.nX = pSize->Left();
2356 0 : maGeometry.nY = pSize->Top();
2357 0 : maGeometry.nWidth = pSize->GetWidth();
2358 0 : maGeometry.nHeight = pSize->GetHeight();
2359 0 : m_nStyle &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
2360 0 : bResize = true;
2361 : }
2362 :
2363 0 : if (bResize)
2364 : {
2365 : // temporarily re-sizeable
2366 0 : if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
2367 0 : gtk_window_set_resizable( GTK_WINDOW(m_pWindow), TRUE );
2368 0 : gtk_window_resize( GTK_WINDOW( m_pWindow ), maGeometry.nWidth, maGeometry.nHeight );
2369 : //I wonder if we should instead leave maGeometry alone and rely on
2370 : //configure-event to trigger signalConfigure and set it there
2371 0 : AllocateFrame();
2372 0 : TriggerPaintEvent();
2373 : }
2374 :
2375 0 : gtk_window_move( GTK_WINDOW( m_pWindow ), maGeometry.nX, maGeometry.nY );
2376 :
2377 : #if !GTK_CHECK_VERSION(3,0,0)
2378 : // _NET_WM_STATE_FULLSCREEN (Metacity <-> KWin)
2379 0 : if( ! getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
2380 : #endif
2381 : {
2382 : #if GTK_CHECK_VERSION(3,8,0)
2383 : gdk_window_set_fullscreen_mode( widget_get_window(m_pWindow), m_bSpanMonitorsWhenFullscreen
2384 : ? GDK_FULLSCREEN_ON_ALL_MONITORS : GDK_FULLSCREEN_ON_CURRENT_MONITOR );
2385 : #endif
2386 0 : if( eType == SET_FULLSCREEN )
2387 0 : gtk_window_fullscreen( GTK_WINDOW( m_pWindow ) );
2388 0 : else if( eType == SET_UN_FULLSCREEN )
2389 0 : gtk_window_unfullscreen( GTK_WINDOW( m_pWindow ) );
2390 : }
2391 :
2392 0 : if( eType == SET_UN_FULLSCREEN &&
2393 0 : !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
2394 0 : gtk_window_set_resizable( GTK_WINDOW( m_pWindow ), FALSE );
2395 :
2396 : // FIXME: we should really let gtk+ handle our widget hierarchy ...
2397 0 : if( m_pParent && gtk_widget_get_screen( m_pParent->m_pWindow ) != pScreen )
2398 0 : SetParent( NULL );
2399 0 : std::list< GtkSalFrame* > aChildren = m_aChildren;
2400 0 : for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
2401 0 : (*it)->SetScreen( nNewScreen, SET_RETAIN_SIZE );
2402 :
2403 0 : m_bDefaultPos = m_bDefaultSize = false;
2404 0 : updateScreenNumber();
2405 0 : CallCallback( SALEVENT_MOVERESIZE, NULL );
2406 :
2407 0 : if( bVisible )
2408 0 : Show( true );
2409 : }
2410 :
2411 0 : void GtkSalFrame::SetScreenNumber( unsigned int nNewScreen )
2412 : {
2413 0 : SetScreen( nNewScreen, SET_RETAIN_SIZE );
2414 0 : }
2415 :
2416 58 : void GtkSalFrame::updateWMClass()
2417 : {
2418 58 : OString aResClass = OUStringToOString(m_sWMClass, RTL_TEXTENCODING_ASCII_US);
2419 58 : const char *pResClass = !aResClass.isEmpty() ? aResClass.getStr() :
2420 58 : SalGenericSystem::getFrameClassName();
2421 : Display *display;
2422 :
2423 58 : if (!getDisplay()->IsX11Display())
2424 58 : return;
2425 :
2426 : #if GTK_CHECK_VERSION(3,0,0)
2427 : display = GDK_DISPLAY_XDISPLAY(getGdkDisplay());
2428 : #else
2429 58 : display = getDisplay()->GetDisplay();
2430 : #endif
2431 :
2432 58 : if( IS_WIDGET_REALIZED( m_pWindow ) )
2433 : {
2434 42 : XClassHint* pClass = XAllocClassHint();
2435 42 : OString aResName = SalGenericSystem::getFrameResName();
2436 42 : pClass->res_name = const_cast<char*>(aResName.getStr());
2437 42 : pClass->res_class = const_cast<char*>(pResClass);
2438 : XSetClassHint( display,
2439 : widget_get_xid(m_pWindow),
2440 42 : pClass );
2441 42 : XFree( pClass );
2442 58 : }
2443 : }
2444 :
2445 34 : void GtkSalFrame::SetApplicationID( const OUString &rWMClass )
2446 : {
2447 34 : if( rWMClass != m_sWMClass && ! isChild() )
2448 : {
2449 23 : m_sWMClass = rWMClass;
2450 23 : updateWMClass();
2451 :
2452 23 : for( std::list< GtkSalFrame* >::iterator it = m_aChildren.begin(); it != m_aChildren.end(); ++it )
2453 0 : (*it)->SetApplicationID(rWMClass);
2454 : }
2455 34 : }
2456 :
2457 0 : void GtkSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nScreen )
2458 : {
2459 0 : m_bFullscreen = bFullScreen;
2460 :
2461 0 : if( !m_pWindow || isChild() )
2462 0 : return;
2463 :
2464 0 : if( bFullScreen )
2465 : {
2466 : m_aRestorePosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
2467 0 : Size( maGeometry.nWidth, maGeometry.nHeight ) );
2468 0 : SetScreen( nScreen, SET_FULLSCREEN );
2469 : }
2470 : else
2471 : {
2472 : SetScreen( nScreen, SET_UN_FULLSCREEN,
2473 0 : !m_aRestorePosSize.IsEmpty() ? &m_aRestorePosSize : NULL );
2474 0 : m_aRestorePosSize = Rectangle();
2475 : }
2476 : }
2477 :
2478 : /* definitions from xautolock.c (pl15) */
2479 : #define XAUTOLOCK_DISABLE 1
2480 : #define XAUTOLOCK_ENABLE 2
2481 :
2482 0 : void GtkSalFrame::setAutoLock( bool bLock )
2483 : {
2484 0 : if( isChild() || !getDisplay()->IsX11Display() )
2485 0 : return;
2486 :
2487 0 : GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(m_pWindow) );
2488 0 : GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
2489 0 : GdkWindow *pRootWin = gdk_screen_get_root_window( pScreen );
2490 :
2491 : Atom nAtom = XInternAtom( GDK_DISPLAY_XDISPLAY( pDisplay ),
2492 0 : "XAUTOLOCK_MESSAGE", False );
2493 :
2494 0 : int nMessage = bLock ? XAUTOLOCK_ENABLE : XAUTOLOCK_DISABLE;
2495 :
2496 : XChangeProperty( GDK_DISPLAY_XDISPLAY( pDisplay ),
2497 : GDK_WINDOW_XID( pRootWin ),
2498 : nAtom, XA_INTEGER,
2499 : 8, PropModeReplace,
2500 : reinterpret_cast<unsigned char*>(&nMessage),
2501 0 : sizeof( nMessage ) );
2502 : }
2503 :
2504 : #ifdef ENABLE_DBUS
2505 : /** cookie is returned as an unsigned integer */
2506 : static guint
2507 0 : dbus_inhibit_gsm (const gchar *appname,
2508 : const gchar *reason,
2509 : guint xid)
2510 : {
2511 : gboolean res;
2512 : guint cookie;
2513 0 : GError *error = NULL;
2514 0 : DBusGProxy *proxy = NULL;
2515 :
2516 : /* get the DBUS session connection */
2517 0 : DBusGConnection *session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
2518 0 : if (error != NULL) {
2519 0 : g_debug ("DBUS cannot connect : %s", error->message);
2520 0 : g_error_free (error);
2521 0 : return -1;
2522 : }
2523 :
2524 : /* get the proxy with gnome-session-manager */
2525 : proxy = dbus_g_proxy_new_for_name (session_connection,
2526 : GSM_DBUS_SERVICE,
2527 : GSM_DBUS_PATH,
2528 0 : GSM_DBUS_INTERFACE);
2529 0 : if (proxy == NULL) {
2530 0 : g_debug ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
2531 0 : return -1;
2532 : }
2533 :
2534 : res = dbus_g_proxy_call (proxy,
2535 : "Inhibit", &error,
2536 : G_TYPE_STRING, appname,
2537 : G_TYPE_UINT, xid,
2538 : G_TYPE_STRING, reason,
2539 : G_TYPE_UINT, 8, //Inhibit the session being marked as idle
2540 : G_TYPE_INVALID,
2541 : G_TYPE_UINT, &cookie,
2542 0 : G_TYPE_INVALID);
2543 :
2544 : /* check the return value */
2545 0 : if (! res) {
2546 0 : cookie = -1;
2547 0 : g_debug ("Inhibit method failed");
2548 : }
2549 :
2550 : /* check the error value */
2551 0 : if (error != NULL) {
2552 0 : g_debug ("Inhibit problem : %s", error->message);
2553 0 : g_error_free (error);
2554 0 : cookie = -1;
2555 : }
2556 :
2557 0 : g_object_unref (G_OBJECT (proxy));
2558 0 : return cookie;
2559 : }
2560 :
2561 : static void
2562 0 : dbus_uninhibit_gsm (guint cookie)
2563 : {
2564 : gboolean res;
2565 0 : GError *error = NULL;
2566 0 : DBusGProxy *proxy = NULL;
2567 0 : DBusGConnection *session_connection = NULL;
2568 :
2569 0 : if (cookie == guint(-1)) {
2570 0 : g_debug ("Invalid cookie");
2571 0 : return;
2572 : }
2573 :
2574 : /* get the DBUS session connection */
2575 0 : session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
2576 0 : if (error) {
2577 0 : g_debug ("DBUS cannot connect : %s", error->message);
2578 0 : g_error_free (error);
2579 0 : return;
2580 : }
2581 :
2582 : /* get the proxy with gnome-session-manager */
2583 : proxy = dbus_g_proxy_new_for_name (session_connection,
2584 : GSM_DBUS_SERVICE,
2585 : GSM_DBUS_PATH,
2586 0 : GSM_DBUS_INTERFACE);
2587 0 : if (proxy == NULL) {
2588 0 : g_debug ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
2589 0 : return;
2590 : }
2591 :
2592 : res = dbus_g_proxy_call (proxy,
2593 : "Uninhibit",
2594 : &error,
2595 : G_TYPE_UINT, cookie,
2596 : G_TYPE_INVALID,
2597 0 : G_TYPE_INVALID);
2598 :
2599 : /* check the return value */
2600 0 : if (! res) {
2601 0 : g_debug ("Uninhibit method failed");
2602 : }
2603 :
2604 : /* check the error value */
2605 0 : if (error != NULL) {
2606 0 : g_debug ("Uninhibit problem : %s", error->message);
2607 0 : g_error_free (error);
2608 0 : cookie = -1;
2609 : }
2610 0 : g_object_unref (G_OBJECT (proxy));
2611 : }
2612 : #endif
2613 :
2614 0 : void GtkSalFrame::StartPresentation( bool bStart )
2615 : {
2616 0 : setAutoLock( !bStart );
2617 :
2618 0 : if( !getDisplay()->IsX11Display() )
2619 0 : return;
2620 :
2621 : #if !GTK_CHECK_VERSION(3,0,0)
2622 0 : Display *pDisplay = GDK_DISPLAY_XDISPLAY( getGdkDisplay() );
2623 :
2624 : int nTimeout, nInterval, bPreferBlanking, bAllowExposures;
2625 : XGetScreenSaver( pDisplay, &nTimeout, &nInterval,
2626 0 : &bPreferBlanking, &bAllowExposures );
2627 : #endif
2628 0 : if( bStart )
2629 : {
2630 : #if !GTK_CHECK_VERSION(3,0,0)
2631 0 : if ( nTimeout )
2632 : {
2633 0 : m_nSavedScreenSaverTimeout = nTimeout;
2634 0 : XResetScreenSaver( pDisplay );
2635 : XSetScreenSaver( pDisplay, 0, nInterval,
2636 0 : bPreferBlanking, bAllowExposures );
2637 : }
2638 : #endif
2639 : #ifdef ENABLE_DBUS
2640 : m_nGSMCookie = dbus_inhibit_gsm(g_get_application_name(), "presentation",
2641 0 : widget_get_xid(m_pWindow));
2642 : #endif
2643 : }
2644 : else
2645 : {
2646 : #if !GTK_CHECK_VERSION(3,0,0)
2647 0 : if( m_nSavedScreenSaverTimeout )
2648 : XSetScreenSaver( pDisplay, m_nSavedScreenSaverTimeout,
2649 : nInterval, bPreferBlanking,
2650 0 : bAllowExposures );
2651 : #endif
2652 0 : m_nSavedScreenSaverTimeout = 0;
2653 : #ifdef ENABLE_DBUS
2654 0 : dbus_uninhibit_gsm(m_nGSMCookie);
2655 : #endif
2656 : }
2657 : }
2658 :
2659 0 : void GtkSalFrame::SetAlwaysOnTop( bool bOnTop )
2660 : {
2661 0 : if( m_pWindow )
2662 0 : gtk_window_set_keep_above( GTK_WINDOW( m_pWindow ), bOnTop );
2663 0 : }
2664 :
2665 3 : void GtkSalFrame::ToTop( sal_uInt16 nFlags )
2666 : {
2667 3 : if( m_pWindow )
2668 : {
2669 3 : if( isChild( false, true ) )
2670 0 : gtk_widget_grab_focus( m_pWindow );
2671 3 : else if( IS_WIDGET_MAPPED( m_pWindow ) )
2672 : {
2673 0 : if( ! (nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY) )
2674 0 : gtk_window_present( GTK_WINDOW(m_pWindow) );
2675 : else
2676 : {
2677 : #if !GTK_CHECK_VERSION(3,0,0)
2678 0 : guint32 nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
2679 : #else
2680 : guint32 nUserTime = GDK_CURRENT_TIME;
2681 : #endif
2682 0 : gdk_window_focus( widget_get_window(m_pWindow), nUserTime );
2683 : }
2684 : #if !GTK_CHECK_VERSION(3,0,0)
2685 : /* need to do an XSetInputFocus here because
2686 : * gdk_window_focus will ask a EWMH compliant WM to put the focus
2687 : * to our window - which it of course won't since our input hint
2688 : * is set to false.
2689 : */
2690 0 : if( (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE)) )
2691 : {
2692 : // sad but true: this can cause an XError, we need to catch that
2693 : // to do this we need to synchronize with the XServer
2694 0 : GetGenericData()->ErrorTrapPush();
2695 0 : XSetInputFocus( getDisplay()->GetDisplay(), widget_get_xid(m_pWindow), RevertToParent, CurrentTime );
2696 : // fdo#46687 - an XSync should not be necessary - but for some reason it is.
2697 0 : XSync( getDisplay()->GetDisplay(), False );
2698 0 : GetGenericData()->ErrorTrapPop();
2699 : }
2700 : #endif
2701 : }
2702 : else
2703 : {
2704 3 : if( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
2705 0 : gtk_window_present( GTK_WINDOW(m_pWindow) );
2706 : }
2707 : }
2708 3 : }
2709 :
2710 0 : void GtkSalFrame::SetPointer( PointerStyle ePointerStyle )
2711 : {
2712 0 : if( m_pWindow && ePointerStyle != m_ePointerStyle )
2713 : {
2714 0 : m_ePointerStyle = ePointerStyle;
2715 0 : GdkCursor *pCursor = getDisplay()->getCursor( ePointerStyle );
2716 0 : gdk_window_set_cursor( widget_get_window(m_pWindow), pCursor );
2717 0 : m_pCurrentCursor = pCursor;
2718 :
2719 : // #i80791# use grabPointer the same way as CaptureMouse, respective float grab
2720 0 : if( getDisplay()->MouseCaptured( this ) )
2721 0 : grabPointer( true, false );
2722 0 : else if( m_nFloats > 0 )
2723 0 : grabPointer( true, true );
2724 : }
2725 0 : }
2726 :
2727 0 : void GtkSalFrame::grabPointer( bool bGrab, bool bOwnerEvents )
2728 : {
2729 0 : static const char* pEnv = getenv( "SAL_NO_MOUSEGRABS" );
2730 0 : if (pEnv && *pEnv)
2731 0 : return;
2732 :
2733 0 : if (!m_pWindow)
2734 0 : return;
2735 :
2736 0 : const int nMask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
2737 :
2738 : #if GTK_CHECK_VERSION(3,0,0)
2739 : GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(getGdkDisplay());
2740 : GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager);
2741 : if (bGrab)
2742 : gdk_device_grab(pPointer, widget_get_window(m_pWindow), GDK_OWNERSHIP_NONE, bOwnerEvents, (GdkEventMask) nMask, m_pCurrentCursor, GDK_CURRENT_TIME);
2743 : else
2744 : gdk_device_ungrab(pPointer, GDK_CURRENT_TIME);
2745 : #else
2746 0 : if( bGrab )
2747 : {
2748 0 : bool bUseGdkGrab = true;
2749 0 : const std::list< SalFrame* >& rFrames = getDisplay()->getFrames();
2750 0 : for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
2751 : {
2752 0 : const GtkSalFrame* pFrame = static_cast< const GtkSalFrame* >(*it);
2753 0 : if( pFrame->m_bWindowIsGtkPlug )
2754 : {
2755 0 : bUseGdkGrab = false;
2756 0 : break;
2757 : }
2758 : }
2759 0 : if( bUseGdkGrab )
2760 : {
2761 : gdk_pointer_grab( widget_get_window( m_pWindow ), bOwnerEvents,
2762 : (GdkEventMask) nMask, NULL, m_pCurrentCursor,
2763 0 : GDK_CURRENT_TIME );
2764 : }
2765 : else
2766 : {
2767 : // FIXME: for some unknown reason gdk_pointer_grab does not
2768 : // really produce owner events for GtkPlug windows
2769 : // the cause is yet unknown
2770 :
2771 : // this is of course a bad hack, especially as we cannot
2772 : // set the right cursor this way
2773 0 : XGrabPointer( getDisplay()->GetDisplay(),
2774 : widget_get_xid( m_pWindow ),
2775 : bOwnerEvents,
2776 : PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
2777 : GrabModeAsync,
2778 : GrabModeAsync,
2779 : None,
2780 : None,
2781 : CurrentTime
2782 0 : );
2783 : }
2784 : }
2785 : else
2786 : {
2787 : // Two GdkDisplays may be open
2788 0 : gdk_display_pointer_ungrab( getGdkDisplay(), GDK_CURRENT_TIME);
2789 : }
2790 : #endif
2791 : }
2792 :
2793 0 : void GtkSalFrame::grabKeyboard( bool bGrab )
2794 : {
2795 0 : if (!m_pWindow)
2796 0 : return;
2797 :
2798 : #if GTK_CHECK_VERSION(3,0,0)
2799 : GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(getGdkDisplay());
2800 : GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager);
2801 : GdkDevice* pKeyboard = gdk_device_get_associated_device(pPointer);
2802 : if (bGrab)
2803 : {
2804 : gdk_device_grab(pKeyboard, widget_get_window(m_pWindow), GDK_OWNERSHIP_NONE,
2805 : true, (GdkEventMask)(GDK_KEY_PRESS | GDK_KEY_RELEASE), NULL, GDK_CURRENT_TIME);
2806 : }
2807 : else
2808 : {
2809 : gdk_device_ungrab(pKeyboard, GDK_CURRENT_TIME);
2810 : }
2811 : #else
2812 0 : if( bGrab )
2813 : {
2814 : gdk_keyboard_grab(widget_get_window(m_pWindow), true,
2815 0 : GDK_CURRENT_TIME);
2816 : }
2817 : else
2818 : {
2819 0 : gdk_keyboard_ungrab(GDK_CURRENT_TIME);
2820 : }
2821 : #endif
2822 : }
2823 :
2824 0 : void GtkSalFrame::CaptureMouse( bool bCapture )
2825 : {
2826 0 : getDisplay()->CaptureMouse( bCapture ? this : NULL );
2827 0 : }
2828 :
2829 0 : void GtkSalFrame::SetPointerPos( long nX, long nY )
2830 : {
2831 0 : GtkSalFrame* pFrame = this;
2832 0 : while( pFrame && pFrame->isChild( false, true ) )
2833 0 : pFrame = pFrame->m_pParent;
2834 0 : if( ! pFrame )
2835 0 : return;
2836 :
2837 0 : GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(pFrame->m_pWindow) );
2838 0 : GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
2839 :
2840 : /* when the application tries to center the mouse in the dialog the
2841 : * window isn't mapped already. So use coordinates relative to the root window.
2842 : */
2843 0 : unsigned int nWindowLeft = maGeometry.nX + nX;
2844 0 : unsigned int nWindowTop = maGeometry.nY + nY;
2845 :
2846 : XWarpPointer( GDK_DISPLAY_XDISPLAY (pDisplay), None,
2847 : GDK_WINDOW_XID (gdk_screen_get_root_window( pScreen ) ),
2848 0 : 0, 0, 0, 0, nWindowLeft, nWindowTop);
2849 : // #i38648# ask for the next motion hint
2850 : gint x, y;
2851 : GdkModifierType mask;
2852 0 : gdk_window_get_pointer( widget_get_window(pFrame->m_pWindow) , &x, &y, &mask );
2853 : }
2854 :
2855 1 : void GtkSalFrame::Flush()
2856 : {
2857 : #if GTK_CHECK_VERSION(3,0,0)
2858 : gdk_display_flush( getGdkDisplay() );
2859 : #else
2860 1 : XFlush (GDK_DISPLAY_XDISPLAY (getGdkDisplay()));
2861 : #endif
2862 1 : }
2863 :
2864 0 : void GtkSalFrame::Sync()
2865 : {
2866 0 : gdk_display_sync( getGdkDisplay() );
2867 0 : }
2868 :
2869 12 : OUString GtkSalFrame::GetKeyName( sal_uInt16 nKeyCode )
2870 : {
2871 : #if !GTK_CHECK_VERSION(3,0,0)
2872 12 : return getDisplay()->GetKeyName( nKeyCode );
2873 : #else
2874 : (void)nKeyCode;
2875 : //FIXME: key names
2876 : return OUString();
2877 : #endif
2878 : }
2879 :
2880 1 : GdkDisplay *GtkSalFrame::getGdkDisplay()
2881 : {
2882 1 : return GetGtkSalData()->GetGdkDisplay();
2883 : }
2884 :
2885 288 : GtkSalDisplay *GtkSalFrame::getDisplay()
2886 : {
2887 288 : return GetGtkSalData()->GetGtkDisplay();
2888 : }
2889 :
2890 0 : SalFrame::SalPointerState GtkSalFrame::GetPointerState()
2891 : {
2892 0 : SalPointerState aState;
2893 : GdkScreen* pScreen;
2894 : gint x, y;
2895 : GdkModifierType aMask;
2896 0 : gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
2897 0 : aState.maPos = Point( x - maGeometry.nX, y - maGeometry.nY );
2898 0 : aState.mnState = GetMouseModCode( aMask );
2899 0 : return aState;
2900 : }
2901 :
2902 0 : KeyIndicatorState GtkSalFrame::GetIndicatorState()
2903 : {
2904 : #if !GTK_CHECK_VERSION(3,0,0)
2905 0 : return GetGtkSalData()->GetGtkDisplay()->GetIndicatorState();
2906 : #else
2907 : g_warning ("missing get indicator state");
2908 : return KeyIndicatorState::NONE;
2909 : #endif
2910 : }
2911 :
2912 0 : void GtkSalFrame::SimulateKeyPress( sal_uInt16 nKeyCode )
2913 : {
2914 : #if !GTK_CHECK_VERSION(3,0,0)
2915 0 : GetGtkSalData()->GetGtkDisplay()->SimulateKeyPress(nKeyCode);
2916 : #else
2917 : g_warning ("missing simulate keypress %d", nKeyCode);
2918 : #endif
2919 0 : }
2920 :
2921 0 : void GtkSalFrame::SetInputContext( SalInputContext* pContext )
2922 : {
2923 0 : if( ! pContext )
2924 0 : return;
2925 :
2926 0 : if( ! (pContext->mnOptions & InputContextFlags::Text) )
2927 0 : return;
2928 :
2929 : // create a new im context
2930 0 : if( ! m_pIMHandler )
2931 0 : m_pIMHandler = new IMHandler( this );
2932 : }
2933 :
2934 0 : void GtkSalFrame::EndExtTextInput( EndExtTextInputFlags nFlags )
2935 : {
2936 0 : if( m_pIMHandler )
2937 0 : m_pIMHandler->endExtTextInput( nFlags );
2938 0 : }
2939 :
2940 0 : bool GtkSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& )
2941 : {
2942 : // not supported yet
2943 0 : return false;
2944 : }
2945 :
2946 0 : LanguageType GtkSalFrame::GetInputLanguage()
2947 : {
2948 0 : return LANGUAGE_DONTKNOW;
2949 : }
2950 :
2951 11 : void GtkSalFrame::UpdateSettings( AllSettings& rSettings )
2952 : {
2953 11 : if( ! m_pWindow )
2954 0 : return;
2955 :
2956 11 : GtkSalGraphics* pGraphics = static_cast<GtkSalGraphics*>(m_aGraphics[0].pGraphics);
2957 11 : bool bFreeGraphics = false;
2958 11 : if( ! pGraphics )
2959 : {
2960 0 : pGraphics = static_cast<GtkSalGraphics*>(AcquireGraphics());
2961 0 : if ( !pGraphics )
2962 : {
2963 : SAL_WARN("vcl", "Could not get graphics - unable to update settings");
2964 0 : return;
2965 : }
2966 0 : bFreeGraphics = true;
2967 : }
2968 :
2969 11 : pGraphics->updateSettings( rSettings );
2970 :
2971 11 : if( bFreeGraphics )
2972 0 : ReleaseGraphics( pGraphics );
2973 : }
2974 :
2975 0 : void GtkSalFrame::Beep()
2976 : {
2977 0 : gdk_display_beep( getGdkDisplay() );
2978 0 : }
2979 :
2980 19 : const SystemEnvData* GtkSalFrame::GetSystemData() const
2981 : {
2982 19 : return &m_aSystemData;
2983 : }
2984 :
2985 0 : void GtkSalFrame::SetParent( SalFrame* pNewParent )
2986 : {
2987 0 : if( m_pParent )
2988 0 : m_pParent->m_aChildren.remove( this );
2989 0 : m_pParent = static_cast<GtkSalFrame*>(pNewParent);
2990 0 : if( m_pParent )
2991 0 : m_pParent->m_aChildren.push_back( this );
2992 0 : if( ! isChild() )
2993 0 : gtk_window_set_transient_for( GTK_WINDOW(m_pWindow),
2994 0 : (m_pParent && ! m_pParent->isChild(true,false)) ? GTK_WINDOW(m_pParent->m_pWindow) : NULL
2995 0 : );
2996 0 : }
2997 :
2998 : #if !GTK_CHECK_VERSION(3,0,0)
2999 :
3000 0 : void GtkSalFrame::createNewWindow( ::Window aNewParent, bool bXEmbed, SalX11Screen nXScreen )
3001 : {
3002 0 : bool bWasVisible = m_pWindow && IS_WIDGET_MAPPED(m_pWindow);
3003 0 : if( bWasVisible )
3004 0 : Show( false );
3005 :
3006 0 : if( (int)nXScreen.getXScreen() >= getDisplay()->GetXScreenCount() )
3007 0 : nXScreen = m_nXScreen;
3008 :
3009 : SystemParentData aParentData;
3010 0 : aParentData.aWindow = aNewParent;
3011 0 : aParentData.bXEmbedSupport = bXEmbed;
3012 0 : if( aNewParent == None )
3013 : {
3014 0 : aNewParent = getDisplay()->GetRootWindow(nXScreen);
3015 0 : aParentData.aWindow = None;
3016 0 : aParentData.bXEmbedSupport = false;
3017 : }
3018 : else
3019 : {
3020 : // is new parent a root window ?
3021 0 : Display* pDisp = getDisplay()->GetDisplay();
3022 0 : int nScreens = getDisplay()->GetXScreenCount();
3023 0 : for( int i = 0; i < nScreens; i++ )
3024 : {
3025 0 : if( aNewParent == RootWindow( pDisp, i ) )
3026 : {
3027 0 : nXScreen = SalX11Screen( i );
3028 0 : aParentData.aWindow = None;
3029 0 : aParentData.bXEmbedSupport = false;
3030 0 : break;
3031 : }
3032 : }
3033 : }
3034 :
3035 : // free xrender resources
3036 0 : for( unsigned int i = 0; i < SAL_N_ELEMENTS(m_aGraphics); i++ )
3037 0 : if( m_aGraphics[i].bInUse )
3038 0 : m_aGraphics[i].pGraphics->SetDrawable( None, m_nXScreen );
3039 :
3040 : // first deinit frame
3041 0 : if( m_pIMHandler )
3042 : {
3043 0 : delete m_pIMHandler;
3044 0 : m_pIMHandler = NULL;
3045 : }
3046 0 : if( m_pRegion )
3047 : {
3048 : #if GTK_CHECK_VERSION(3,0,0)
3049 : cairo_region_destroy( m_pRegion );
3050 : #else
3051 0 : gdk_region_destroy( m_pRegion );
3052 : #endif
3053 : }
3054 0 : if( m_pFixedContainer )
3055 0 : gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer) );
3056 0 : if( m_pWindow )
3057 0 : gtk_widget_destroy( m_pWindow );
3058 0 : if( m_pForeignParent )
3059 0 : g_object_unref( G_OBJECT( m_pForeignParent ) );
3060 0 : if( m_pForeignTopLevel )
3061 0 : g_object_unref( G_OBJECT( m_pForeignTopLevel ) );
3062 :
3063 : // init new window
3064 0 : m_bDefaultPos = m_bDefaultSize = false;
3065 0 : if( aParentData.aWindow != None )
3066 : {
3067 0 : m_nStyle |= SAL_FRAME_STYLE_PLUG;
3068 0 : Init( &aParentData );
3069 : }
3070 : else
3071 : {
3072 0 : m_nStyle &= ~SAL_FRAME_STYLE_PLUG;
3073 0 : Init( (m_pParent && m_pParent->m_nXScreen == m_nXScreen) ? m_pParent : NULL, m_nStyle );
3074 : }
3075 :
3076 : // update graphics
3077 0 : for( unsigned int i = 0; i < SAL_N_ELEMENTS(m_aGraphics); i++ )
3078 : {
3079 0 : if( m_aGraphics[i].bInUse )
3080 : {
3081 0 : m_aGraphics[i].pGraphics->SetDrawable( widget_get_xid(m_pWindow), m_nXScreen );
3082 0 : m_aGraphics[i].pGraphics->SetWindow( m_pWindow );
3083 : }
3084 : }
3085 :
3086 0 : if( ! m_aTitle.isEmpty() )
3087 0 : SetTitle( m_aTitle );
3088 :
3089 0 : if( bWasVisible )
3090 0 : Show( true );
3091 :
3092 0 : std::list< GtkSalFrame* > aChildren = m_aChildren;
3093 0 : m_aChildren.clear();
3094 0 : for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
3095 0 : (*it)->createNewWindow( None, false, m_nXScreen );
3096 :
3097 : // FIXME: SalObjects
3098 0 : }
3099 : #endif
3100 :
3101 0 : bool GtkSalFrame::SetPluginParent( SystemParentData* pSysParent )
3102 : {
3103 : #if !GTK_CHECK_VERSION(3,0,0)
3104 0 : GetGenericData()->ErrorTrapPush(); // permanantly ignore unruly children's errors
3105 0 : createNewWindow( pSysParent->aWindow, (pSysParent->nSize > sizeof(long)) && pSysParent->bXEmbedSupport, m_nXScreen );
3106 0 : return true;
3107 : #else
3108 : (void)pSysParent;
3109 : //FIXME: no SetPluginParent impl. for gtk3
3110 : return false;
3111 : #endif
3112 : }
3113 :
3114 0 : void GtkSalFrame::ResetClipRegion()
3115 : {
3116 0 : if( m_pWindow )
3117 0 : gdk_window_shape_combine_region( widget_get_window( m_pWindow ), NULL, 0, 0 );
3118 0 : }
3119 :
3120 0 : void GtkSalFrame::BeginSetClipRegion( sal_uLong )
3121 : {
3122 : #if GTK_CHECK_VERSION(3,0,0)
3123 : if( m_pRegion )
3124 : cairo_region_destroy( m_pRegion );
3125 : m_pRegion = cairo_region_create();
3126 : #else
3127 0 : if( m_pRegion )
3128 0 : gdk_region_destroy( m_pRegion );
3129 0 : m_pRegion = gdk_region_new();
3130 : #endif
3131 0 : }
3132 :
3133 0 : void GtkSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
3134 : {
3135 0 : if( m_pRegion )
3136 : {
3137 : GdkRectangle aRect;
3138 0 : aRect.x = nX;
3139 0 : aRect.y = nY;
3140 0 : aRect.width = nWidth;
3141 0 : aRect.height = nHeight;
3142 : #if GTK_CHECK_VERSION(3,0,0)
3143 : cairo_region_union_rectangle( m_pRegion, &aRect );
3144 : #else
3145 0 : gdk_region_union_with_rect( m_pRegion, &aRect );
3146 : #endif
3147 : }
3148 0 : }
3149 :
3150 0 : void GtkSalFrame::EndSetClipRegion()
3151 : {
3152 0 : if( m_pWindow && m_pRegion )
3153 0 : gdk_window_shape_combine_region( widget_get_window(m_pWindow), m_pRegion, 0, 0 );
3154 0 : }
3155 :
3156 : #if !GTK_CHECK_VERSION(3,0,0)
3157 0 : bool GtkSalFrame::Dispatch( const XEvent* pEvent )
3158 : {
3159 0 : bool bContinueDispatch = true;
3160 :
3161 0 : if( pEvent->type == PropertyNotify )
3162 : {
3163 0 : vcl_sal::WMAdaptor* pAdaptor = getDisplay()->getWMAdaptor();
3164 0 : Atom nDesktopAtom = pAdaptor->getAtom( vcl_sal::WMAdaptor::NET_WM_DESKTOP );
3165 0 : if( pEvent->xproperty.atom == nDesktopAtom &&
3166 0 : pEvent->xproperty.state == PropertyNewValue )
3167 : {
3168 0 : m_nWorkArea = pAdaptor->getWindowWorkArea( widget_get_xid(m_pWindow) );
3169 : }
3170 : }
3171 0 : else if( pEvent->type == ConfigureNotify )
3172 : {
3173 0 : if( m_pForeignParent && pEvent->xconfigure.window == m_aForeignParentWindow )
3174 : {
3175 0 : bContinueDispatch = false;
3176 0 : gtk_window_resize( GTK_WINDOW(m_pWindow), pEvent->xconfigure.width, pEvent->xconfigure.height );
3177 0 : if( ( sal::static_int_cast< int >(maGeometry.nWidth) !=
3178 0 : pEvent->xconfigure.width ) ||
3179 0 : ( sal::static_int_cast< int >(maGeometry.nHeight) !=
3180 : pEvent->xconfigure.height ) )
3181 : {
3182 0 : maGeometry.nWidth = pEvent->xconfigure.width;
3183 0 : maGeometry.nHeight = pEvent->xconfigure.height;
3184 0 : setMinMaxSize();
3185 0 : getDisplay()->SendInternalEvent( this, NULL, SALEVENT_RESIZE );
3186 : }
3187 : }
3188 0 : else if( m_pForeignTopLevel && pEvent->xconfigure.window == m_aForeignTopLevelWindow )
3189 : {
3190 0 : bContinueDispatch = false;
3191 : // update position
3192 0 : int x = 0, y = 0;
3193 : ::Window aChild;
3194 0 : XTranslateCoordinates( getDisplay()->GetDisplay(),
3195 : widget_get_xid(m_pWindow),
3196 0 : getDisplay()->GetRootWindow( getDisplay()->GetDefaultXScreen() ),
3197 : 0, 0,
3198 : &x, &y,
3199 0 : &aChild );
3200 0 : if( x != maGeometry.nX || y != maGeometry.nY )
3201 : {
3202 0 : maGeometry.nX = x;
3203 0 : maGeometry.nY = y;
3204 0 : getDisplay()->SendInternalEvent( this, NULL, SALEVENT_MOVE );
3205 : }
3206 : }
3207 : }
3208 0 : else if( pEvent->type == ClientMessage &&
3209 0 : pEvent->xclient.message_type == getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED ) &&
3210 0 : pEvent->xclient.window == widget_get_xid(m_pWindow) &&
3211 : m_bWindowIsGtkPlug
3212 : )
3213 : {
3214 : // FIXME: this should not be necessary, GtkPlug should do this
3215 : // transparently for us
3216 0 : if( pEvent->xclient.data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
3217 0 : pEvent->xclient.data.l[1] == 2 // XEMBED_WINDOW_DEACTIVATE
3218 : )
3219 : {
3220 : GdkEventFocus aEvent;
3221 0 : aEvent.type = GDK_FOCUS_CHANGE;
3222 0 : aEvent.window = widget_get_window( m_pWindow );
3223 0 : aEvent.send_event = gint8(TRUE);
3224 0 : aEvent.in = gint16(pEvent->xclient.data.l[1] == 1);
3225 0 : signalFocus( m_pWindow, &aEvent, this );
3226 : }
3227 : }
3228 :
3229 0 : return bContinueDispatch;
3230 : }
3231 : #endif
3232 :
3233 0 : gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame )
3234 : {
3235 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3236 :
3237 : SalMouseEvent aEvent;
3238 0 : sal_uInt16 nEventType = 0;
3239 0 : switch( pEvent->type )
3240 : {
3241 : case GDK_BUTTON_PRESS:
3242 0 : nEventType = SALEVENT_MOUSEBUTTONDOWN;
3243 0 : break;
3244 : case GDK_BUTTON_RELEASE:
3245 0 : nEventType = SALEVENT_MOUSEBUTTONUP;
3246 0 : break;
3247 : default:
3248 0 : return false;
3249 : }
3250 0 : switch( pEvent->button )
3251 : {
3252 0 : case 1: aEvent.mnButton = MOUSE_LEFT; break;
3253 0 : case 2: aEvent.mnButton = MOUSE_MIDDLE; break;
3254 0 : case 3: aEvent.mnButton = MOUSE_RIGHT; break;
3255 0 : default: return false;
3256 : }
3257 0 : aEvent.mnTime = pEvent->time;
3258 0 : aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
3259 0 : aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
3260 0 : aEvent.mnCode = GetMouseModCode( pEvent->state );
3261 :
3262 0 : bool bClosePopups = false;
3263 0 : if( pEvent->type == GDK_BUTTON_PRESS &&
3264 0 : (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) == 0
3265 : )
3266 : {
3267 0 : if( m_nFloats > 0 )
3268 : {
3269 : // close popups if user clicks outside our application
3270 : gint x, y;
3271 0 : bClosePopups = (gdk_display_get_window_at_pointer( GtkSalFrame::getGdkDisplay(), &x, &y ) == NULL);
3272 : }
3273 : /* #i30306# release implicit pointer grab if no popups are open; else
3274 : * Drag cannot grab the pointer and will fail.
3275 : */
3276 0 : if( m_nFloats < 1 || bClosePopups )
3277 0 : gdk_display_pointer_ungrab( GtkSalFrame::getGdkDisplay(), GDK_CURRENT_TIME );
3278 : }
3279 :
3280 0 : if( pThis->m_bWindowIsGtkPlug &&
3281 0 : pEvent->type == GDK_BUTTON_PRESS &&
3282 0 : pEvent->button == 1 )
3283 : {
3284 0 : pThis->askForXEmbedFocus( pEvent->time );
3285 : }
3286 :
3287 : // --- RTL --- (mirror mouse pos)
3288 0 : if( AllSettings::GetLayoutRTL() )
3289 0 : aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
3290 :
3291 0 : vcl::DeletionListener aDel( pThis );
3292 :
3293 0 : pThis->CallCallback( nEventType, &aEvent );
3294 :
3295 0 : if( ! aDel.isDeleted() )
3296 : {
3297 0 : if( bClosePopups )
3298 : {
3299 0 : ImplSVData* pSVData = ImplGetSVData();
3300 0 : if ( pSVData->maWinData.mpFirstFloat )
3301 : {
3302 0 : static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
3303 0 : if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FloatWinPopupFlags::NoAppFocusClose) && !(pEnv && *pEnv) )
3304 0 : pSVData->maWinData.mpFirstFloat->EndPopupMode( FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll );
3305 : }
3306 : }
3307 :
3308 0 : if( ! aDel.isDeleted() )
3309 : {
3310 0 : int frame_x = (int)(pEvent->x_root - pEvent->x);
3311 0 : int frame_y = (int)(pEvent->y_root - pEvent->y);
3312 0 : if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
3313 : {
3314 0 : pThis->maGeometry.nX = frame_x;
3315 0 : pThis->maGeometry.nY = frame_y;
3316 0 : pThis->CallCallback( SALEVENT_MOVE, NULL );
3317 : }
3318 : }
3319 : }
3320 :
3321 0 : return true;
3322 : }
3323 :
3324 0 : gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEvent* pEvent, gpointer frame )
3325 : {
3326 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3327 0 : GdkEventScroll* pSEvent = reinterpret_cast<GdkEventScroll*>(pEvent);
3328 :
3329 : #if GTK_CHECK_VERSION(3,0,0)
3330 : //TODO: do something less feeble here
3331 : if (pSEvent->direction == GDK_SCROLL_SMOOTH)
3332 : return true;
3333 : #endif
3334 :
3335 : static sal_uLong nLines = 0;
3336 0 : if( ! nLines )
3337 : {
3338 0 : char* pEnv = getenv( "SAL_WHEELLINES" );
3339 0 : nLines = pEnv ? atoi( pEnv ) : 3;
3340 0 : if( nLines > 10 )
3341 0 : nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
3342 : }
3343 :
3344 0 : bool bNeg = (pSEvent->direction == GDK_SCROLL_DOWN || pSEvent->direction == GDK_SCROLL_RIGHT );
3345 0 : SalWheelMouseEvent aEvent;
3346 0 : aEvent.mnTime = pSEvent->time;
3347 0 : aEvent.mnX = (sal_uLong)pSEvent->x;
3348 0 : aEvent.mnY = (sal_uLong)pSEvent->y;
3349 0 : aEvent.mnDelta = bNeg ? -120 : 120;
3350 0 : aEvent.mnNotchDelta = bNeg ? -1 : 1;
3351 0 : aEvent.mnScrollLines = nLines;
3352 0 : aEvent.mnCode = GetMouseModCode( pSEvent->state );
3353 0 : aEvent.mbHorz = (pSEvent->direction == GDK_SCROLL_LEFT || pSEvent->direction == GDK_SCROLL_RIGHT);
3354 :
3355 : // --- RTL --- (mirror mouse pos)
3356 0 : if( AllSettings::GetLayoutRTL() )
3357 0 : aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
3358 :
3359 0 : pThis->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
3360 :
3361 0 : return true;
3362 : }
3363 :
3364 : #if GTK_CHECK_VERSION(3,14,0)
3365 : void GtkSalFrame::gestureSwipe(GtkGestureSwipe* gesture, gdouble velocity_x, gdouble velocity_y, gpointer frame)
3366 : {
3367 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3368 :
3369 : SalSwipeEvent aEvent;
3370 : aEvent.mnVelocityX = velocity_x;
3371 : aEvent.mnVelocityY = velocity_y;
3372 :
3373 : gdouble x, y;
3374 : GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
3375 : //I feel I want the first point of the sequence, not the last point which
3376 : //the docs say this gives, but for the moment assume we start and end
3377 : //within the same vcl window
3378 : gtk_gesture_get_point(GTK_GESTURE(gesture), sequence, &x, &y);
3379 : aEvent.mnX = x;
3380 : aEvent.mnY = y;
3381 :
3382 : pThis->CallCallback(SALEVENT_SWIPE, &aEvent);
3383 : }
3384 :
3385 : void GtkSalFrame::gestureLongPress(GtkGestureLongPress* gesture, gpointer frame)
3386 : {
3387 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3388 :
3389 : SalLongPressEvent aEvent;
3390 :
3391 : gdouble x, y;
3392 : GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
3393 : gtk_gesture_get_point(GTK_GESTURE(gesture), sequence, &x, &y);
3394 : aEvent.mnX = x;
3395 : aEvent.mnY = y;
3396 :
3397 : pThis->CallCallback(SALEVENT_LONGPRESS, &aEvent);
3398 : }
3399 :
3400 : #endif
3401 :
3402 0 : gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer frame )
3403 : {
3404 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3405 :
3406 : SalMouseEvent aEvent;
3407 0 : aEvent.mnTime = pEvent->time;
3408 0 : aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
3409 0 : aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
3410 0 : aEvent.mnCode = GetMouseModCode( pEvent->state );
3411 0 : aEvent.mnButton = 0;
3412 :
3413 : // --- RTL --- (mirror mouse pos)
3414 0 : if( AllSettings::GetLayoutRTL() )
3415 0 : aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
3416 :
3417 0 : vcl::DeletionListener aDel( pThis );
3418 :
3419 0 : pThis->CallCallback( SALEVENT_MOUSEMOVE, &aEvent );
3420 :
3421 0 : if( ! aDel.isDeleted() )
3422 : {
3423 0 : int frame_x = (int)(pEvent->x_root - pEvent->x);
3424 0 : int frame_y = (int)(pEvent->y_root - pEvent->y);
3425 0 : if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
3426 : {
3427 0 : pThis->maGeometry.nX = frame_x;
3428 0 : pThis->maGeometry.nY = frame_y;
3429 0 : pThis->CallCallback( SALEVENT_MOVE, NULL );
3430 : }
3431 :
3432 0 : if( ! aDel.isDeleted() )
3433 : {
3434 : // ask for the next hint
3435 : gint x, y;
3436 : GdkModifierType mask;
3437 0 : gdk_window_get_pointer( widget_get_window(GTK_WIDGET(pThis->m_pWindow)), &x, &y, &mask );
3438 : }
3439 : }
3440 :
3441 0 : return true;
3442 : }
3443 :
3444 0 : gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpointer frame )
3445 : {
3446 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3447 : SalMouseEvent aEvent;
3448 0 : aEvent.mnTime = pEvent->time;
3449 0 : aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
3450 0 : aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
3451 0 : aEvent.mnCode = GetMouseModCode( pEvent->state );
3452 0 : aEvent.mnButton = 0;
3453 :
3454 0 : pThis->CallCallback( (pEvent->type == GDK_ENTER_NOTIFY) ? SALEVENT_MOUSEMOVE : SALEVENT_MOUSELEAVE, &aEvent );
3455 :
3456 0 : return true;
3457 : }
3458 :
3459 : #if GTK_CHECK_VERSION(3,0,0)
3460 :
3461 : cairo_t* GtkSalFrame::getCairoContext() const
3462 : {
3463 : basebmp::RawMemorySharedArray data = m_aFrame->getBuffer();
3464 : basegfx::B2IVector size = m_aFrame->getSize();
3465 : sal_Int32 nStride = m_aFrame->getScanlineStride();
3466 : assert(cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, size.getX()) == nStride);
3467 : cairo_surface_t *target =
3468 : cairo_image_surface_create_for_data(data.get(),
3469 : CAIRO_FORMAT_RGB24,
3470 : size.getX(), size.getY(),
3471 : nStride);
3472 : cairo_t* cr = cairo_create(target);
3473 : cairo_surface_destroy(target);
3474 : return cr;
3475 : }
3476 :
3477 : void GtkSalFrame::damaged (const basegfx::B2IBox& rDamageRect)
3478 : {
3479 : #if OSL_DEBUG_LEVEL > 1
3480 : long long area = rDamageRect.getWidth() * rDamageRect.getHeight();
3481 : if( area > 32 * 1024 )
3482 : {
3483 : fprintf( stderr, "bitmap damaged %d %d (%dx%d) area %lld widget\n",
3484 : (int) rDamageRect.getMinX(),
3485 : (int) rDamageRect.getMinY(),
3486 : (int) rDamageRect.getWidth(),
3487 : (int) rDamageRect.getHeight(),
3488 : area );
3489 : }
3490 : #endif
3491 :
3492 : if (dumpframes)
3493 : {
3494 : static int frame;
3495 : OString tmp("/tmp/frame" + OString::number(frame++) + ".png");
3496 : cairo_t* cr = getCairoContext();
3497 : cairo_surface_write_to_png(cairo_get_target(cr), tmp.getStr());
3498 : cairo_destroy(cr);
3499 : }
3500 :
3501 : gtk_widget_queue_draw_area(m_pWindow,
3502 : rDamageRect.getMinX(),
3503 : rDamageRect.getMinY(),
3504 : rDamageRect.getWidth(),
3505 : rDamageRect.getHeight());
3506 : }
3507 :
3508 : // blit our backing basebmp buffer to the target cairo context cr
3509 : gboolean GtkSalFrame::signalDraw( GtkWidget*, cairo_t *cr, gpointer frame )
3510 : {
3511 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3512 :
3513 : cairo_save(cr);
3514 :
3515 : cairo_t* source = pThis->getCairoContext();
3516 : cairo_surface_t *pSurface = cairo_get_target(source);
3517 :
3518 : cairo_set_operator( cr, CAIRO_OPERATOR_OVER );
3519 : cairo_set_source_surface(cr, pSurface, 0, 0);
3520 : cairo_paint(cr);
3521 :
3522 : cairo_destroy(source);
3523 :
3524 : cairo_restore(cr);
3525 :
3526 : cairo_surface_flush(cairo_get_target(cr));
3527 :
3528 : return FALSE;
3529 : }
3530 : #else
3531 0 : gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer frame )
3532 : {
3533 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3534 :
3535 0 : struct SalPaintEvent aEvent( pEvent->area.x, pEvent->area.y, pEvent->area.width, pEvent->area.height );
3536 :
3537 0 : pThis->CallCallback( SALEVENT_PAINT, &aEvent );
3538 :
3539 0 : return false;
3540 : }
3541 :
3542 : #endif // GTK_CHECK_VERSION(3,0,0)
3543 :
3544 12 : void GtkSalFrame::TriggerPaintEvent()
3545 : {
3546 : //Under gtk2 we can basically paint directly into the XWindow and on
3547 : //additional "expose-event" events we can re-render the missing pieces
3548 : //
3549 : //Under gtk3 we have to keep our own buffer up to date and flush it into
3550 : //the given cairo context on "draw". So we emit a paint event on
3551 : //opportune resize trigger events to initially fill our backbuffer and then
3552 : //keep it up to date with our direct paints and tell gtk those regions
3553 : //have changed and then blit them into the provided cairo context when
3554 : //we get the "draw"
3555 : //
3556 : //The other alternative was to always paint everything on "draw", but
3557 : //that duplicates the amount of drawing and is hideously slow
3558 : #if GTK_CHECK_VERSION(3,0,0)
3559 : SAL_INFO("vcl.gtk3", "force painting" << 0 << "," << 0 << " " << maGeometry.nWidth << "x" << maGeometry.nHeight);
3560 : SalPaintEvent aPaintEvt(0, 0, maGeometry.nWidth, maGeometry.nHeight, true);
3561 : CallCallback(SALEVENT_PAINT, &aPaintEvt);
3562 : gtk_widget_queue_draw(m_pWindow);
3563 : #endif
3564 12 : }
3565 :
3566 0 : gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame )
3567 : {
3568 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3569 :
3570 : X11SalInstance *pSalInstance =
3571 0 : static_cast< X11SalInstance* >(GetSalData()->m_pInstance);
3572 :
3573 : // check if printers have changed (analogous to salframe focus handler)
3574 0 : pSalInstance->updatePrinterUpdate();
3575 :
3576 0 : if( !pEvent->in )
3577 : {
3578 0 : pThis->m_nKeyModifiers = 0;
3579 0 : pThis->m_bSendModChangeOnRelease = false;
3580 : }
3581 :
3582 0 : if( pThis->m_pIMHandler )
3583 0 : pThis->m_pIMHandler->focusChanged( pEvent->in );
3584 :
3585 : // ask for changed printers like generic implementation
3586 0 : if( pEvent->in && pSalInstance->isPrinterInit() )
3587 0 : pSalInstance->updatePrinterUpdate();
3588 :
3589 : // FIXME: find out who the hell steals the focus from our frame
3590 : // while we have the pointer grabbed, this should not come from
3591 : // the window manager. Is this an event that was still queued ?
3592 : // The focus does not seem to get set inside our process
3593 :
3594 : // in the meantime do not propagate focus get/lose if floats are open
3595 0 : if( m_nFloats == 0 )
3596 0 : pThis->CallCallback( pEvent->in ? SALEVENT_GETFOCUS : SALEVENT_LOSEFOCUS, NULL );
3597 :
3598 0 : return false;
3599 : }
3600 :
3601 : #if !GTK_CHECK_VERSION(3,8,0)
3602 0 : static OString getDisplayString()
3603 : {
3604 0 : int nParams = rtl_getAppCommandArgCount();
3605 0 : OUString aParam;
3606 0 : for( int i = 0; i < nParams; i++ )
3607 : {
3608 0 : rtl_getAppCommandArg( i, &aParam.pData );
3609 0 : if( i < nParams-1 && (aParam == "-display" || aParam == "--display" ) )
3610 : {
3611 0 : rtl_getAppCommandArg( i+1, &aParam.pData );
3612 0 : return OUStringToOString( aParam, osl_getThreadTextEncoding() );
3613 : }
3614 : }
3615 0 : return OString();
3616 : }
3617 : #endif
3618 :
3619 0 : gboolean GtkSalFrame::signalMap( GtkWidget *pWidget, GdkEvent*, gpointer frame )
3620 : {
3621 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3622 :
3623 : #if !GTK_CHECK_VERSION(3,8,0)
3624 : //Spawn off a helper program that will attempt to set this fullscreen
3625 : //window to span all displays.
3626 0 : if (pThis->m_bFullscreen && pThis->m_bSpanMonitorsWhenFullscreen)
3627 : {
3628 0 : GdkWindow* gdkwin = widget_get_window(pThis->m_pWindow);
3629 0 : if (gdkwin)
3630 : {
3631 0 : OUString sProgramURL( "$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER "/xid-fullscreen-on-all-monitors");
3632 0 : rtl::Bootstrap::expandMacros(sProgramURL);
3633 0 : OUString sProgram;
3634 0 : if (osl::FileBase::getSystemPathFromFileURL(sProgramURL, sProgram) == osl::File::E_None)
3635 : {
3636 0 : OString sFinalProgram(OUStringToOString(sProgram, osl_getThreadTextEncoding())
3637 0 : + " " + OString::number((int)GDK_WINDOW_XID(gdkwin)));
3638 0 : OString sDisplay(getDisplayString());
3639 0 : if (!sDisplay.isEmpty())
3640 : {
3641 0 : sFinalProgram += "--display " + sDisplay;
3642 : }
3643 0 : int returnValue = system(sFinalProgram.getStr());
3644 0 : (void)returnValue;
3645 0 : }
3646 : }
3647 : }
3648 : #endif
3649 :
3650 0 : bool bSetFocus = pThis->m_bSetFocusOnMap;
3651 0 : pThis->m_bSetFocusOnMap = false;
3652 :
3653 : #if !GTK_CHECK_VERSION(3,0,0)
3654 0 : if( bSetFocus )
3655 : {
3656 0 : GetGenericData()->ErrorTrapPush();
3657 0 : XSetInputFocus( GtkSalFrame::getDisplay()->GetDisplay(),
3658 : widget_get_xid(pWidget),
3659 0 : RevertToParent, CurrentTime );
3660 0 : XSync( GtkSalFrame::getDisplay()->GetDisplay(), False );
3661 0 : GetGenericData()->ErrorTrapPop();
3662 : }
3663 : #else
3664 : (void)pWidget; (void)bSetFocus;
3665 : //FIXME: no set input focus ...
3666 : #endif
3667 :
3668 0 : pThis->CallCallback( SALEVENT_RESIZE, NULL );
3669 0 : pThis->TriggerPaintEvent();
3670 :
3671 0 : return false;
3672 : }
3673 :
3674 0 : gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame )
3675 : {
3676 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3677 :
3678 0 : pThis->CallCallback( SALEVENT_RESIZE, NULL );
3679 :
3680 0 : return false;
3681 : }
3682 :
3683 0 : gboolean GtkSalFrame::signalConfigure( GtkWidget*, GdkEventConfigure* pEvent, gpointer frame )
3684 : {
3685 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3686 :
3687 0 : bool bMoved = false, bSized = false;
3688 0 : int x = pEvent->x, y = pEvent->y;
3689 :
3690 : /* HACK: during sizing/moving a toolbar pThis->maGeometry is actually
3691 : * already exact; even worse: due to the asynchronicity of configure
3692 : * events the borderwindow which would evaluate this event
3693 : * would size/move based on wrong data if we would actually evaluate
3694 : * this event. So let's swallow it.
3695 : */
3696 0 : if( (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
3697 0 : GtkSalFrame::getDisplay()->GetCaptureFrame() == pThis )
3698 0 : return false;
3699 :
3700 : /* #i31785# claims we cannot trust the x,y members of the event;
3701 : * they are e.g. not set correctly on maximize/demaximize;
3702 : * yet the gdkdisplay-x11.c code handling configure_events has
3703 : * done this XTranslateCoordinates work since the day ~zero.
3704 : */
3705 0 : if( x != pThis->maGeometry.nX || y != pThis->maGeometry.nY )
3706 : {
3707 0 : bMoved = true;
3708 0 : pThis->maGeometry.nX = x;
3709 0 : pThis->maGeometry.nY = y;
3710 : }
3711 : /* #i86302#
3712 : * for non sizeable windows we set the min and max hint for the window manager to
3713 : * achieve correct sizing. However this is asynchronous and e.g. on Compiz
3714 : * it sometimes happens that the window gets resized to another size (some default)
3715 : * if we update the size here, subsequent setMinMaxSize will use this wrong size
3716 : * - which is not good since the window manager will now size the window back to this
3717 : * wrong size at some point.
3718 : */
3719 : /* fprintf (stderr, "configure %d %d %d (%d) %d, %d diff? %d\n",
3720 : (int)pThis->m_bFullscreen, (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)), SAL_FRAME_STYLE_SIZEABLE,
3721 : !!( pThis->m_bFullscreen || (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)) == SAL_FRAME_STYLE_SIZEABLE ),
3722 : pEvent->width, pEvent->height,
3723 : !!(pEvent->width != (int)pThis->maGeometry.nWidth || pEvent->height != (int)pThis->maGeometry.nHeight)
3724 : ); */
3725 0 : if( pThis->m_bFullscreen || (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)) == SAL_FRAME_STYLE_SIZEABLE )
3726 : {
3727 0 : if( pEvent->width != (int)pThis->maGeometry.nWidth || pEvent->height != (int)pThis->maGeometry.nHeight )
3728 : {
3729 0 : bSized = true;
3730 0 : pThis->maGeometry.nWidth = pEvent->width;
3731 0 : pThis->maGeometry.nHeight = pEvent->height;
3732 : }
3733 : }
3734 :
3735 : // update decoration hints
3736 0 : if( ! (pThis->m_nStyle & SAL_FRAME_STYLE_PLUG) )
3737 : {
3738 : GdkRectangle aRect;
3739 0 : gdk_window_get_frame_extents( widget_get_window(GTK_WIDGET(pThis->m_pWindow)), &aRect );
3740 0 : pThis->maGeometry.nTopDecoration = y - aRect.y;
3741 0 : pThis->maGeometry.nBottomDecoration = aRect.y + aRect.height - y - pEvent->height;
3742 0 : pThis->maGeometry.nLeftDecoration = x - aRect.x;
3743 0 : pThis->maGeometry.nRightDecoration = aRect.x + aRect.width - x - pEvent->width;
3744 : }
3745 : else
3746 : {
3747 : pThis->maGeometry.nTopDecoration =
3748 : pThis->maGeometry.nBottomDecoration =
3749 : pThis->maGeometry.nLeftDecoration =
3750 0 : pThis->maGeometry.nRightDecoration = 0;
3751 : }
3752 :
3753 0 : pThis->updateScreenNumber();
3754 0 : if( bSized )
3755 0 : pThis->AllocateFrame();
3756 :
3757 0 : if( bMoved && bSized )
3758 0 : pThis->CallCallback( SALEVENT_MOVERESIZE, NULL );
3759 0 : else if( bMoved )
3760 0 : pThis->CallCallback( SALEVENT_MOVE, NULL );
3761 0 : else if( bSized )
3762 0 : pThis->CallCallback( SALEVENT_RESIZE, NULL );
3763 :
3764 0 : if (bSized)
3765 0 : pThis->TriggerPaintEvent();
3766 0 : return false;
3767 : }
3768 :
3769 0 : gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame )
3770 : {
3771 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3772 :
3773 0 : vcl::DeletionListener aDel( pThis );
3774 :
3775 0 : if( pThis->m_pIMHandler )
3776 : {
3777 0 : if( pThis->m_pIMHandler->handleKeyEvent( pEvent ) )
3778 0 : return true;
3779 : }
3780 :
3781 : // handle modifiers
3782 0 : if( pEvent->keyval == GDK_Shift_L || pEvent->keyval == GDK_Shift_R ||
3783 0 : pEvent->keyval == GDK_Control_L || pEvent->keyval == GDK_Control_R ||
3784 0 : pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ||
3785 0 : pEvent->keyval == GDK_Meta_L || pEvent->keyval == GDK_Meta_R ||
3786 0 : pEvent->keyval == GDK_Super_L || pEvent->keyval == GDK_Super_R )
3787 : {
3788 : SalKeyModEvent aModEvt;
3789 :
3790 0 : sal_uInt16 nModCode = GetKeyModCode( pEvent->state );
3791 :
3792 0 : aModEvt.mnModKeyCode = 0; // emit no MODKEYCHANGE events
3793 0 : if( pEvent->type == GDK_KEY_PRESS && !pThis->m_nKeyModifiers )
3794 0 : pThis->m_bSendModChangeOnRelease = true;
3795 :
3796 0 : else if( pEvent->type == GDK_KEY_RELEASE &&
3797 : pThis->m_bSendModChangeOnRelease )
3798 : {
3799 0 : aModEvt.mnModKeyCode = pThis->m_nKeyModifiers;
3800 0 : pThis->m_nKeyModifiers = 0;
3801 : }
3802 :
3803 0 : sal_uInt16 nExtModMask = 0;
3804 0 : sal_uInt16 nModMask = 0;
3805 : // pressing just the ctrl key leads to a keysym of XK_Control but
3806 : // the event state does not contain ControlMask. In the release
3807 : // event its the other way round: it does contain the Control mask.
3808 : // The modifier mode therefore has to be adapted manually.
3809 0 : switch( pEvent->keyval )
3810 : {
3811 : case GDK_Control_L:
3812 0 : nExtModMask = MODKEY_LMOD1;
3813 0 : nModMask = KEY_MOD1;
3814 0 : break;
3815 : case GDK_Control_R:
3816 0 : nExtModMask = MODKEY_RMOD1;
3817 0 : nModMask = KEY_MOD1;
3818 0 : break;
3819 : case GDK_Alt_L:
3820 0 : nExtModMask = MODKEY_LMOD2;
3821 0 : nModMask = KEY_MOD2;
3822 0 : break;
3823 : case GDK_Alt_R:
3824 0 : nExtModMask = MODKEY_RMOD2;
3825 0 : nModMask = KEY_MOD2;
3826 0 : break;
3827 : case GDK_Shift_L:
3828 0 : nExtModMask = MODKEY_LSHIFT;
3829 0 : nModMask = KEY_SHIFT;
3830 0 : break;
3831 : case GDK_Shift_R:
3832 0 : nExtModMask = MODKEY_RSHIFT;
3833 0 : nModMask = KEY_SHIFT;
3834 0 : break;
3835 : // Map Meta/Super to MOD3 modifier on all Unix systems
3836 : // except Mac OS X
3837 : case GDK_Meta_L:
3838 : case GDK_Super_L:
3839 0 : nExtModMask = MODKEY_LMOD3;
3840 0 : nModMask = KEY_MOD3;
3841 0 : break;
3842 : case GDK_Meta_R:
3843 : case GDK_Super_R:
3844 0 : nExtModMask = MODKEY_RMOD3;
3845 0 : nModMask = KEY_MOD3;
3846 0 : break;
3847 : }
3848 0 : if( pEvent->type == GDK_KEY_RELEASE )
3849 : {
3850 0 : nModCode &= ~nModMask;
3851 0 : pThis->m_nKeyModifiers &= ~nExtModMask;
3852 : }
3853 : else
3854 : {
3855 0 : nModCode |= nModMask;
3856 0 : pThis->m_nKeyModifiers |= nExtModMask;
3857 : }
3858 :
3859 0 : aModEvt.mnCode = nModCode;
3860 0 : aModEvt.mnTime = pEvent->time;
3861 :
3862 0 : pThis->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
3863 :
3864 : }
3865 : else
3866 : {
3867 : pThis->doKeyCallback( pEvent->state,
3868 : pEvent->keyval,
3869 : pEvent->hardware_keycode,
3870 : pEvent->group,
3871 : pEvent->time,
3872 0 : sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )),
3873 : (pEvent->type == GDK_KEY_PRESS),
3874 0 : false );
3875 0 : if( ! aDel.isDeleted() )
3876 0 : pThis->m_bSendModChangeOnRelease = false;
3877 : }
3878 :
3879 0 : if( !aDel.isDeleted() && pThis->m_pIMHandler )
3880 0 : pThis->m_pIMHandler->updateIMSpotLocation();
3881 :
3882 0 : return true;
3883 : }
3884 :
3885 0 : gboolean GtkSalFrame::signalDelete( GtkWidget*, GdkEvent*, gpointer frame )
3886 : {
3887 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3888 :
3889 0 : pThis->CallCallback( SALEVENT_CLOSE, NULL );
3890 :
3891 0 : return true;
3892 : }
3893 :
3894 16 : void GtkSalFrame::signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer frame )
3895 : {
3896 16 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3897 :
3898 : // every frame gets an initial style set on creation
3899 : // do not post these as the whole application tends to
3900 : // redraw itself to adjust to the new style
3901 : // where there IS no new style resulting in tremendous unnecessary flickering
3902 16 : if( pPrevious != NULL )
3903 : {
3904 : // signalStyleSet does NOT usually have the gdk lock
3905 : // so post user event to safely dispatch the SALEVENT_SETTINGSCHANGED
3906 : // note: settings changed for multiple frames is avoided in winproc.cxx ImplHandleSettings
3907 0 : GtkSalFrame::getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_SETTINGSCHANGED );
3908 0 : GtkSalFrame::getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_FONTCHANGED );
3909 : }
3910 :
3911 : #if !GTK_CHECK_VERSION(3,0,0)
3912 : /* #i64117# gtk sets a nice background pixmap
3913 : * but we actually don't really want that, so save
3914 : * some time on the Xserver as well as prevent
3915 : * some paint issues
3916 : */
3917 16 : GdkWindow* pWin = widget_get_window(GTK_WIDGET(pThis->getWindow()));
3918 16 : if( pWin )
3919 : {
3920 0 : ::Window aWin = GDK_WINDOW_XWINDOW(pWin);
3921 0 : if( aWin != None )
3922 0 : XSetWindowBackgroundPixmap( GtkSalFrame::getDisplay()->GetDisplay(),
3923 : aWin,
3924 0 : pThis->m_hBackgroundPixmap );
3925 : }
3926 16 : if( ! pThis->m_pParent )
3927 : {
3928 : // signalize theme changed for NWF caches
3929 : // FIXME: should be called only once for a style change
3930 16 : GtkSalGraphics::bThemeChanged = true;
3931 : }
3932 : #endif
3933 16 : }
3934 :
3935 0 : gboolean GtkSalFrame::signalState( GtkWidget*, GdkEvent* pEvent, gpointer frame )
3936 : {
3937 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3938 0 : if( (pThis->m_nState & GDK_WINDOW_STATE_ICONIFIED) != (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED ) )
3939 : {
3940 0 : GtkSalFrame::getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_RESIZE );
3941 0 : pThis->TriggerPaintEvent();
3942 : }
3943 :
3944 0 : if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) &&
3945 0 : ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) )
3946 : {
3947 : pThis->m_aRestorePosSize =
3948 : Rectangle( Point( pThis->maGeometry.nX, pThis->maGeometry.nY ),
3949 0 : Size( pThis->maGeometry.nWidth, pThis->maGeometry.nHeight ) );
3950 : }
3951 0 : pThis->m_nState = pEvent->window_state.new_window_state;
3952 :
3953 : #if OSL_DEBUG_LEVEL > 1
3954 : if( (pEvent->window_state.changed_mask & GDK_WINDOW_STATE_FULLSCREEN) )
3955 : {
3956 : fprintf( stderr, "window %p %s full screen state\n",
3957 : pThis,
3958 : (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_FULLSCREEN) ? "enters" : "leaves");
3959 : }
3960 : #endif
3961 :
3962 0 : return false;
3963 : }
3964 :
3965 0 : gboolean GtkSalFrame::signalVisibility( GtkWidget*, GdkEventVisibility* pEvent, gpointer frame )
3966 : {
3967 0 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3968 0 : pThis->m_nVisibility = pEvent->state;
3969 0 : return true;
3970 : }
3971 :
3972 13 : void GtkSalFrame::signalDestroy( GtkWidget* pObj, gpointer frame )
3973 : {
3974 13 : GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
3975 13 : if( pObj == pThis->m_pWindow )
3976 : {
3977 13 : pThis->m_pFixedContainer = NULL;
3978 13 : pThis->m_pWindow = NULL;
3979 : }
3980 13 : }
3981 :
3982 : // GtkSalFrame::IMHandler
3983 :
3984 0 : GtkSalFrame::IMHandler::IMHandler( GtkSalFrame* pFrame )
3985 : : m_pFrame(pFrame),
3986 : m_nPrevKeyPresses( 0 ),
3987 : m_pIMContext( NULL ),
3988 : m_bFocused( true ),
3989 0 : m_bPreeditJustChanged( false )
3990 : {
3991 0 : m_aInputEvent.mpTextAttr = NULL;
3992 0 : createIMContext();
3993 0 : }
3994 :
3995 0 : GtkSalFrame::IMHandler::~IMHandler()
3996 : {
3997 : // cancel an eventual event posted to begin preedit again
3998 0 : GtkSalFrame::getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3999 0 : deleteIMContext();
4000 0 : }
4001 :
4002 0 : void GtkSalFrame::IMHandler::createIMContext()
4003 : {
4004 0 : if( ! m_pIMContext )
4005 : {
4006 0 : m_pIMContext = gtk_im_multicontext_new ();
4007 0 : g_signal_connect( m_pIMContext, "commit",
4008 0 : G_CALLBACK (signalIMCommit), this );
4009 0 : g_signal_connect( m_pIMContext, "preedit_changed",
4010 0 : G_CALLBACK (signalIMPreeditChanged), this );
4011 0 : g_signal_connect( m_pIMContext, "retrieve_surrounding",
4012 0 : G_CALLBACK (signalIMRetrieveSurrounding), this );
4013 0 : g_signal_connect( m_pIMContext, "delete_surrounding",
4014 0 : G_CALLBACK (signalIMDeleteSurrounding), this );
4015 0 : g_signal_connect( m_pIMContext, "preedit_start",
4016 0 : G_CALLBACK (signalIMPreeditStart), this );
4017 0 : g_signal_connect( m_pIMContext, "preedit_end",
4018 0 : G_CALLBACK (signalIMPreeditEnd), this );
4019 :
4020 0 : GetGenericData()->ErrorTrapPush();
4021 0 : gtk_im_context_set_client_window( m_pIMContext, widget_get_window(GTK_WIDGET(m_pFrame->m_pWindow)) );
4022 0 : gtk_im_context_focus_in( m_pIMContext );
4023 0 : GetGenericData()->ErrorTrapPop();
4024 0 : m_bFocused = true;
4025 : }
4026 0 : }
4027 :
4028 0 : void GtkSalFrame::IMHandler::deleteIMContext()
4029 : {
4030 0 : if( m_pIMContext )
4031 : {
4032 : // first give IC a chance to deinitialize
4033 0 : GetGenericData()->ErrorTrapPush();
4034 0 : gtk_im_context_set_client_window( m_pIMContext, NULL );
4035 0 : GetGenericData()->ErrorTrapPop();
4036 : // destroy old IC
4037 0 : g_object_unref( m_pIMContext );
4038 0 : m_pIMContext = NULL;
4039 : }
4040 0 : }
4041 :
4042 0 : void GtkSalFrame::IMHandler::doCallEndExtTextInput()
4043 : {
4044 0 : m_aInputEvent.mpTextAttr = NULL;
4045 0 : m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
4046 0 : }
4047 :
4048 0 : void GtkSalFrame::IMHandler::updateIMSpotLocation()
4049 : {
4050 0 : SalExtTextInputPosEvent aPosEvent;
4051 0 : m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, static_cast<void*>(&aPosEvent) );
4052 : GdkRectangle aArea;
4053 0 : aArea.x = aPosEvent.mnX;
4054 0 : aArea.y = aPosEvent.mnY;
4055 0 : aArea.width = aPosEvent.mnWidth;
4056 0 : aArea.height = aPosEvent.mnHeight;
4057 0 : GetGenericData()->ErrorTrapPush();
4058 0 : gtk_im_context_set_cursor_location( m_pIMContext, &aArea );
4059 0 : GetGenericData()->ErrorTrapPop();
4060 0 : }
4061 :
4062 0 : void GtkSalFrame::IMHandler::sendEmptyCommit()
4063 : {
4064 0 : vcl::DeletionListener aDel( m_pFrame );
4065 :
4066 0 : SalExtTextInputEvent aEmptyEv;
4067 0 : aEmptyEv.mnTime = 0;
4068 0 : aEmptyEv.mpTextAttr = 0;
4069 0 : aEmptyEv.maText.clear();
4070 0 : aEmptyEv.mnCursorPos = 0;
4071 0 : aEmptyEv.mnCursorFlags = 0;
4072 0 : aEmptyEv.mbOnlyCursor = False;
4073 0 : m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, static_cast<void*>(&aEmptyEv) );
4074 0 : if( ! aDel.isDeleted() )
4075 0 : m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
4076 0 : }
4077 :
4078 0 : void GtkSalFrame::IMHandler::endExtTextInput( EndExtTextInputFlags /*nFlags*/ )
4079 : {
4080 0 : gtk_im_context_reset ( m_pIMContext );
4081 :
4082 0 : if( m_aInputEvent.mpTextAttr )
4083 : {
4084 0 : vcl::DeletionListener aDel( m_pFrame );
4085 : // delete preedit in sal (commit an empty string)
4086 0 : sendEmptyCommit();
4087 0 : if( ! aDel.isDeleted() )
4088 : {
4089 : // mark previous preedit state again (will e.g. be sent at focus gain)
4090 0 : m_aInputEvent.mpTextAttr = &m_aInputFlags[0];
4091 0 : if( m_bFocused )
4092 : {
4093 : // begin preedit again
4094 0 : GtkSalFrame::getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
4095 : }
4096 0 : }
4097 : }
4098 0 : }
4099 :
4100 0 : void GtkSalFrame::IMHandler::focusChanged( bool bFocusIn )
4101 : {
4102 0 : m_bFocused = bFocusIn;
4103 0 : if( bFocusIn )
4104 : {
4105 0 : GetGenericData()->ErrorTrapPush();
4106 0 : gtk_im_context_focus_in( m_pIMContext );
4107 0 : GetGenericData()->ErrorTrapPop();
4108 0 : if( m_aInputEvent.mpTextAttr )
4109 : {
4110 0 : sendEmptyCommit();
4111 : // begin preedit again
4112 0 : GtkSalFrame::getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
4113 : }
4114 : }
4115 : else
4116 : {
4117 0 : GetGenericData()->ErrorTrapPush();
4118 0 : gtk_im_context_focus_out( m_pIMContext );
4119 0 : GetGenericData()->ErrorTrapPop();
4120 : // cancel an eventual event posted to begin preedit again
4121 0 : GtkSalFrame::getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
4122 : }
4123 0 : }
4124 :
4125 0 : bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent )
4126 : {
4127 0 : vcl::DeletionListener aDel( m_pFrame );
4128 :
4129 0 : if( pEvent->type == GDK_KEY_PRESS )
4130 : {
4131 : // Add this key press event to the list of previous key presses
4132 : // to which we compare key release events. If a later key release
4133 : // event has a matching key press event in this list, we swallow
4134 : // the key release because some GTK Input Methods don't swallow it
4135 : // for us.
4136 0 : m_aPrevKeyPresses.push_back( PreviousKeyPress(pEvent) );
4137 0 : m_nPrevKeyPresses++;
4138 :
4139 : // Also pop off the earliest key press event if there are more than 10
4140 : // already.
4141 0 : while (m_nPrevKeyPresses > 10)
4142 : {
4143 0 : m_aPrevKeyPresses.pop_front();
4144 0 : m_nPrevKeyPresses--;
4145 : }
4146 :
4147 0 : GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
4148 :
4149 : // #i51353# update spot location on every key input since we cannot
4150 : // know which key may activate a preedit choice window
4151 0 : updateIMSpotLocation();
4152 0 : if( aDel.isDeleted() )
4153 0 : return true;
4154 :
4155 0 : gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
4156 0 : g_object_unref( pRef );
4157 :
4158 0 : if( aDel.isDeleted() )
4159 0 : return true;
4160 :
4161 0 : m_bPreeditJustChanged = false;
4162 :
4163 0 : if( bResult )
4164 0 : return true;
4165 : else
4166 : {
4167 : DBG_ASSERT( m_nPrevKeyPresses > 0, "key press has vanished !" );
4168 0 : if( ! m_aPrevKeyPresses.empty() ) // sanity check
4169 : {
4170 : // event was not swallowed, do not filter a following
4171 : // key release event
4172 : // note: this relies on gtk_im_context_filter_keypress
4173 : // returning without calling a handler (in the "not swallowed"
4174 : // case ) which might change the previous key press list so
4175 : // we would pop the wrong event here
4176 0 : m_aPrevKeyPresses.pop_back();
4177 0 : m_nPrevKeyPresses--;
4178 : }
4179 : }
4180 : }
4181 :
4182 : // Determine if we got an earlier key press event corresponding to this key release
4183 0 : if (pEvent->type == GDK_KEY_RELEASE)
4184 : {
4185 0 : GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
4186 0 : gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
4187 0 : g_object_unref( pRef );
4188 :
4189 0 : if( aDel.isDeleted() )
4190 0 : return true;
4191 :
4192 0 : m_bPreeditJustChanged = false;
4193 :
4194 0 : std::list<PreviousKeyPress>::iterator iter = m_aPrevKeyPresses.begin();
4195 0 : std::list<PreviousKeyPress>::iterator iter_end = m_aPrevKeyPresses.end();
4196 0 : while (iter != iter_end)
4197 : {
4198 : // If we found a corresponding previous key press event, swallow the release
4199 : // and remove the earlier key press from our list
4200 0 : if (*iter == pEvent)
4201 : {
4202 0 : m_aPrevKeyPresses.erase(iter);
4203 0 : m_nPrevKeyPresses--;
4204 0 : return true;
4205 : }
4206 0 : ++iter;
4207 : }
4208 :
4209 0 : if( bResult )
4210 0 : return true;
4211 : }
4212 :
4213 0 : return false;
4214 : }
4215 :
4216 : /* FIXME:
4217 : * #122282# still more hacking: some IMEs never start a preedit but simply commit
4218 : * in this case we cannot commit a single character. Workaround: do not do the
4219 : * single key hack for enter or space if the unicode committed does not match
4220 : */
4221 :
4222 0 : static bool checkSingleKeyCommitHack( guint keyval, sal_Unicode cCode )
4223 : {
4224 0 : bool bRet = true;
4225 0 : switch( keyval )
4226 : {
4227 : case GDK_KP_Enter:
4228 : case GDK_Return:
4229 0 : if( cCode != '\n' && cCode != '\r' )
4230 0 : bRet = false;
4231 0 : break;
4232 : case GDK_space:
4233 : case GDK_KP_Space:
4234 0 : if( cCode != ' ' )
4235 0 : bRet = false;
4236 0 : break;
4237 : default:
4238 0 : break;
4239 : }
4240 0 : return bRet;
4241 : }
4242 :
4243 0 : void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* pContext, gchar* pText, gpointer im_handler )
4244 : {
4245 0 : GtkSalFrame::IMHandler* pThis = static_cast<GtkSalFrame::IMHandler*>(im_handler);
4246 :
4247 0 : SolarMutexGuard aGuard;
4248 0 : vcl::DeletionListener aDel( pThis->m_pFrame );
4249 : {
4250 : const bool bWasPreedit =
4251 0 : (pThis->m_aInputEvent.mpTextAttr != 0) ||
4252 0 : pThis->m_bPreeditJustChanged;
4253 :
4254 0 : pThis->m_aInputEvent.mnTime = 0;
4255 0 : pThis->m_aInputEvent.mpTextAttr = 0;
4256 0 : pThis->m_aInputEvent.maText = OUString( pText, strlen(pText), RTL_TEXTENCODING_UTF8 );
4257 0 : pThis->m_aInputEvent.mnCursorPos = pThis->m_aInputEvent.maText.getLength();
4258 0 : pThis->m_aInputEvent.mnCursorFlags = 0;
4259 0 : pThis->m_aInputEvent.mbOnlyCursor = False;
4260 :
4261 0 : pThis->m_aInputFlags.clear();
4262 :
4263 : /* necessary HACK: all keyboard input comes in here as soon as a IMContext is set
4264 : * which is logical and consequent. But since even simple input like
4265 : * <space> comes through the commit signal instead of signalKey
4266 : * and all kinds of windows only implement KeyInput (e.g. PushButtons,
4267 : * RadioButtons and a lot of other Controls), will send a single
4268 : * KeyInput/KeyUp sequence instead of an ExtText event if there
4269 : * never was a preedit and the text is only one character.
4270 : *
4271 : * In this case there the last ExtText event must have been
4272 : * SALEVENT_ENDEXTTEXTINPUT, either because of a regular commit
4273 : * or because there never was a preedit.
4274 : */
4275 0 : bool bSingleCommit = false;
4276 0 : if( ! bWasPreedit
4277 0 : && pThis->m_aInputEvent.maText.getLength() == 1
4278 0 : && ! pThis->m_aPrevKeyPresses.empty()
4279 : )
4280 : {
4281 0 : const PreviousKeyPress& rKP = pThis->m_aPrevKeyPresses.back();
4282 0 : sal_Unicode aOrigCode = pThis->m_aInputEvent.maText[0];
4283 :
4284 0 : if( checkSingleKeyCommitHack( rKP.keyval, aOrigCode ) )
4285 : {
4286 0 : pThis->m_pFrame->doKeyCallback( rKP.state, rKP.keyval, rKP.hardware_keycode, rKP.group, rKP.time, aOrigCode, true, true );
4287 0 : bSingleCommit = true;
4288 : }
4289 : }
4290 0 : if( ! bSingleCommit )
4291 : {
4292 0 : pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, static_cast<void*>(&pThis->m_aInputEvent));
4293 0 : if( ! aDel.isDeleted() )
4294 0 : pThis->doCallEndExtTextInput();
4295 : }
4296 0 : if( ! aDel.isDeleted() )
4297 : {
4298 : // reset input event
4299 0 : pThis->m_aInputEvent.maText.clear();
4300 0 : pThis->m_aInputEvent.mnCursorPos = 0;
4301 0 : pThis->updateIMSpotLocation();
4302 : }
4303 : }
4304 : #ifdef SOLARIS
4305 : // #i51356# workaround a solaris IIIMP bug
4306 : // in case of partial commits the preedit changed signal
4307 : // and commit signal come in wrong order
4308 : if( ! aDel.isDeleted() )
4309 : signalIMPreeditChanged( pContext, im_handler );
4310 : #else
4311 0 : (void) pContext;
4312 : #endif
4313 0 : }
4314 :
4315 0 : void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext*, gpointer im_handler )
4316 : {
4317 0 : GtkSalFrame::IMHandler* pThis = static_cast<GtkSalFrame::IMHandler*>(im_handler);
4318 :
4319 0 : char* pText = NULL;
4320 0 : PangoAttrList* pAttrs = NULL;
4321 0 : gint nCursorPos = 0;
4322 :
4323 : gtk_im_context_get_preedit_string( pThis->m_pIMContext,
4324 : &pText,
4325 : &pAttrs,
4326 0 : &nCursorPos );
4327 0 : if( pText && ! *pText ) // empty string
4328 : {
4329 : // change from nothing to nothing -> do not start preedit
4330 : // e.g. this will activate input into a calc cell without
4331 : // user input
4332 0 : if( pThis->m_aInputEvent.maText.getLength() == 0 )
4333 : {
4334 0 : g_free( pText );
4335 0 : pango_attr_list_unref( pAttrs );
4336 0 : return;
4337 : }
4338 : }
4339 :
4340 0 : pThis->m_bPreeditJustChanged = true;
4341 :
4342 0 : bool bEndPreedit = (!pText || !*pText) && pThis->m_aInputEvent.mpTextAttr != NULL;
4343 0 : pThis->m_aInputEvent.mnTime = 0;
4344 0 : pThis->m_aInputEvent.maText = pText ? OUString( pText, strlen(pText), RTL_TEXTENCODING_UTF8 ) : OUString();
4345 0 : pThis->m_aInputEvent.mnCursorPos = nCursorPos;
4346 0 : pThis->m_aInputEvent.mnCursorFlags = 0;
4347 0 : pThis->m_aInputEvent.mbOnlyCursor = False;
4348 :
4349 0 : pThis->m_aInputFlags = std::vector<sal_uInt16>( std::max( 1, (int)pThis->m_aInputEvent.maText.getLength() ), 0 );
4350 :
4351 0 : PangoAttrIterator *iter = pango_attr_list_get_iterator(pAttrs);
4352 0 : do
4353 : {
4354 0 : GSList *attr_list = NULL;
4355 0 : GSList *tmp_list = NULL;
4356 : gint start, end;
4357 0 : guint sal_attr = 0;
4358 :
4359 0 : pango_attr_iterator_range (iter, &start, &end);
4360 0 : if (end == G_MAXINT)
4361 0 : end = pText ? strlen (pText) : 0;
4362 0 : if (end == start)
4363 0 : continue;
4364 :
4365 0 : start = g_utf8_pointer_to_offset (pText, pText + start);
4366 0 : end = g_utf8_pointer_to_offset (pText, pText + end);
4367 :
4368 0 : tmp_list = attr_list = pango_attr_iterator_get_attrs (iter);
4369 0 : while (tmp_list)
4370 : {
4371 0 : PangoAttribute *pango_attr = static_cast<PangoAttribute *>(tmp_list->data);
4372 :
4373 0 : switch (pango_attr->klass->type)
4374 : {
4375 : case PANGO_ATTR_BACKGROUND:
4376 0 : sal_attr |= (EXTTEXTINPUT_ATTR_HIGHLIGHT | EXTTEXTINPUT_CURSOR_INVISIBLE);
4377 0 : break;
4378 : case PANGO_ATTR_UNDERLINE:
4379 0 : sal_attr |= EXTTEXTINPUT_ATTR_UNDERLINE;
4380 0 : break;
4381 : case PANGO_ATTR_STRIKETHROUGH:
4382 0 : sal_attr |= EXTTEXTINPUT_ATTR_REDTEXT;
4383 0 : break;
4384 : default:
4385 0 : break;
4386 : }
4387 0 : pango_attribute_destroy (pango_attr);
4388 0 : tmp_list = tmp_list->next;
4389 : }
4390 0 : if (sal_attr == 0)
4391 0 : sal_attr |= EXTTEXTINPUT_ATTR_UNDERLINE;
4392 0 : g_slist_free (attr_list);
4393 :
4394 : // Set the sal attributes on our text
4395 0 : for (int i = start; i < end; ++i)
4396 : {
4397 : SAL_WARN_IF(i >= static_cast<int>(pThis->m_aInputFlags.size()),
4398 : "vcl.gtk", "pango attrib out of range. Broken range: "
4399 : << start << "," << end << " Legal range: 0,"
4400 : << pThis->m_aInputFlags.size());
4401 0 : if (i >= static_cast<int>(pThis->m_aInputFlags.size()))
4402 0 : continue;
4403 0 : pThis->m_aInputFlags[i] |= sal_attr;
4404 : }
4405 0 : } while (pango_attr_iterator_next (iter));
4406 0 : pango_attr_iterator_destroy(iter);
4407 :
4408 0 : pThis->m_aInputEvent.mpTextAttr = &pThis->m_aInputFlags[0];
4409 :
4410 0 : g_free( pText );
4411 0 : pango_attr_list_unref( pAttrs );
4412 :
4413 0 : SolarMutexGuard aGuard;
4414 0 : vcl::DeletionListener aDel( pThis->m_pFrame );
4415 :
4416 0 : pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, static_cast<void*>(&pThis->m_aInputEvent));
4417 0 : if( bEndPreedit && ! aDel.isDeleted() )
4418 0 : pThis->doCallEndExtTextInput();
4419 0 : if( ! aDel.isDeleted() )
4420 0 : pThis->updateIMSpotLocation();
4421 : }
4422 :
4423 0 : void GtkSalFrame::IMHandler::signalIMPreeditStart( GtkIMContext*, gpointer /*im_handler*/ )
4424 : {
4425 0 : }
4426 :
4427 0 : void GtkSalFrame::IMHandler::signalIMPreeditEnd( GtkIMContext*, gpointer im_handler )
4428 : {
4429 0 : GtkSalFrame::IMHandler* pThis = static_cast<GtkSalFrame::IMHandler*>(im_handler);
4430 :
4431 0 : pThis->m_bPreeditJustChanged = true;
4432 :
4433 0 : SolarMutexGuard aGuard;
4434 0 : vcl::DeletionListener aDel( pThis->m_pFrame );
4435 0 : pThis->doCallEndExtTextInput();
4436 0 : if( ! aDel.isDeleted() )
4437 0 : pThis->updateIMSpotLocation();
4438 0 : }
4439 :
4440 : uno::Reference<accessibility::XAccessibleEditableText>
4441 0 : FindFocus(uno::Reference< accessibility::XAccessibleContext > xContext)
4442 : {
4443 0 : if (!xContext.is())
4444 0 : uno::Reference< accessibility::XAccessibleEditableText >();
4445 :
4446 0 : uno::Reference<accessibility::XAccessibleStateSet> xState = xContext->getAccessibleStateSet();
4447 0 : if (xState.is())
4448 : {
4449 0 : if (xState->contains(accessibility::AccessibleStateType::FOCUSED))
4450 0 : return uno::Reference<accessibility::XAccessibleEditableText>(xContext, uno::UNO_QUERY);
4451 : }
4452 :
4453 0 : for (sal_Int32 i = 0; i < xContext->getAccessibleChildCount(); ++i)
4454 : {
4455 0 : uno::Reference< accessibility::XAccessible > xChild = xContext->getAccessibleChild(i);
4456 0 : if (!xChild.is())
4457 0 : continue;
4458 0 : uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext();
4459 0 : if (!xChildContext.is())
4460 0 : continue;
4461 0 : uno::Reference< accessibility::XAccessibleEditableText > xText = FindFocus(xChildContext);
4462 0 : if (xText.is())
4463 0 : return xText;
4464 0 : }
4465 0 : return uno::Reference< accessibility::XAccessibleEditableText >();
4466 : }
4467 :
4468 0 : static uno::Reference<accessibility::XAccessibleEditableText> lcl_GetxText(vcl::Window *pFocusWin)
4469 : {
4470 0 : uno::Reference<accessibility::XAccessibleEditableText> xText;
4471 : try
4472 : {
4473 0 : uno::Reference< accessibility::XAccessible > xAccessible( pFocusWin->GetAccessible( true ) );
4474 0 : if (xAccessible.is())
4475 0 : xText = FindFocus(xAccessible->getAccessibleContext());
4476 : }
4477 0 : catch(const uno::Exception& e)
4478 : {
4479 : SAL_WARN( "vcl.gtk", "Exception in getting input method surrounding text: " << e.Message);
4480 : }
4481 0 : return xText;
4482 : }
4483 :
4484 0 : gboolean GtkSalFrame::IMHandler::signalIMRetrieveSurrounding( GtkIMContext* pContext, gpointer /*im_handler*/ )
4485 : {
4486 0 : vcl::Window *pFocusWin = Application::GetFocusWindow();
4487 0 : if (!pFocusWin)
4488 0 : return true;
4489 :
4490 0 : uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText(pFocusWin);
4491 0 : if (xText.is())
4492 : {
4493 0 : sal_Int32 nPosition = xText->getCaretPosition();
4494 0 : OUString sAllText = xText->getText();
4495 0 : OString sUTF = OUStringToOString(sAllText, RTL_TEXTENCODING_UTF8);
4496 0 : OUString sCursorText(sAllText.copy(0, nPosition));
4497 : gtk_im_context_set_surrounding(pContext, sUTF.getStr(), sUTF.getLength(),
4498 0 : OUStringToOString(sCursorText, RTL_TEXTENCODING_UTF8).getLength());
4499 0 : return true;
4500 : }
4501 :
4502 0 : return false;
4503 : }
4504 :
4505 0 : gboolean GtkSalFrame::IMHandler::signalIMDeleteSurrounding( GtkIMContext*, gint offset, gint nchars,
4506 : gpointer /*im_handler*/ )
4507 : {
4508 0 : vcl::Window *pFocusWin = Application::GetFocusWindow();
4509 0 : if (!pFocusWin)
4510 0 : return true;
4511 :
4512 0 : uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText(pFocusWin);
4513 0 : if (xText.is())
4514 : {
4515 0 : sal_uInt32 nPosition = xText->getCaretPosition();
4516 : // #i111768# range checking
4517 0 : sal_Int32 nDeletePos = nPosition + offset;
4518 0 : sal_Int32 nDeleteEnd = nDeletePos + nchars;
4519 0 : if (nDeletePos < 0)
4520 0 : nDeletePos = 0;
4521 0 : if (nDeleteEnd < 0)
4522 0 : nDeleteEnd = 0;
4523 0 : if (nDeleteEnd > xText->getCharacterCount())
4524 0 : nDeleteEnd = xText->getCharacterCount();
4525 :
4526 0 : xText->deleteText(nDeletePos, nDeleteEnd);
4527 0 : return true;
4528 : }
4529 :
4530 0 : return false;
4531 : }
4532 :
4533 16 : Size GtkSalDisplay::GetScreenSize( int nDisplayScreen )
4534 : {
4535 16 : Rectangle aRect = m_pSys->GetDisplayScreenPosSizePixel( nDisplayScreen );
4536 16 : return Size( aRect.GetWidth(), aRect.GetHeight() );
4537 : }
4538 :
4539 0 : Window GtkSalFrame::GetX11Window()
4540 : {
4541 0 : return widget_get_xid(m_pWindow);
4542 9 : }
4543 :
4544 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|