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