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