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