xref: /trunk/main/vcl/unx/gtk/window/gtkframe.cxx (revision b2b6b138)
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 
GetKeyModCode(guint state)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 
GetMouseModCode(guint state)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 
GetKeyCode(guint keyval)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;
KeyAlternateKeyAlternate297 	KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
KeyAlternateKeyAlternate298 	KeyAlternate( sal_uInt16 nKey, sal_Unicode nChar = 0 ) : nKeyCode( nKey ), nCharCode( nChar ) {}
299 };
300 
301 inline KeyAlternate
GetAlternateKeyCode(const sal_uInt16 nKeyCode)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 
doKeyCallback(guint state,guint keyval,guint16 hardware_keycode,guint8,guint32 time,sal_Unicode aOrigCode,bool bDown,bool bSendRelease)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         // work around a crash 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 
~GraphicsHolder()385 GtkSalFrame::GraphicsHolder::~GraphicsHolder()
386 {
387     delete pGraphics;
388 }
389 
GtkSalFrame(SalFrame * pParent,sal_uLong nStyle)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 
GtkSalFrame(SystemParentData * pSysData)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 
~GtkSalFrame()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 
moveWindow(long nX,long nY)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 
resizeWindow(long nWidth,long nHeight)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
ooo_fixed_get_type()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 
updateScreenNumber()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 
InitCommon()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 
lcl_set_accept_focus(GtkWindow * pWindow,gboolean bAccept,bool bBeforeRealize)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 }
lcl_set_user_time(GdkWindow * i_pWindow,guint32 i_nTime)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 
getFromWindow(GtkWindow * pWindow)748 GtkSalFrame *GtkSalFrame::getFromWindow( GtkWindow *pWindow )
749 {
750 	return (GtkSalFrame *) g_object_get_data( G_OBJECT( pWindow ), "SalFrame" );
751 }
752 
Init(SalFrame * pParent,sal_uLong nStyle)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 
findTopLevelSystemWindow(GdkNativeWindow aWindow)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 
Init(SystemParentData * pSysData)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 
askForXEmbedFocus(sal_Int32 i_nTimeCode)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 
SetExtendedFrameStyle(SalExtStyle nStyle)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).getStr(),
988                                     X11SalData::getFrameClassName() );
989     }
990 }
991 
992 
GetGraphics()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 
ReleaseGraphics(SalGraphics * pGraphics)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 
PostEvent(void * pData)1027 sal_Bool GtkSalFrame::PostEvent( void* pData )
1028 {
1029 	getDisplay()->SendInternalEvent( this, pData );
1030 	return sal_True;
1031 }
1032 
SetTitle(const String & rTitle)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 *
getRow(BitmapBuffer * pBuffer,sal_uLong nRow)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 *
bitmapToPixbuf(SalBitmap * pSalBitmap,SalBitmap * pSalAlpha)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 
SetIcon(sal_uInt16 nIcon)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 
SetMenu(SalMenu *)1188 void GtkSalFrame::SetMenu( SalMenu* )
1189 {
1190 }
1191 
DrawMenuBar()1192 void GtkSalFrame::DrawMenuBar()
1193 {
1194 }
1195 
Center()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 
calcDefaultSize()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 
1248     if (aScreenSize.Width() <= 1024 || aScreenSize.Height() <= 768)
1249     {
1250         // For small screen use the old default values. Original comment:
1251         // fill in holy default values brought to us by product management
1252         if( aScreenSize.Width() >= 800 )
1253             w = 785;
1254         if( aScreenSize.Width() >= 1024 )
1255             w = 920;
1256 
1257         if( aScreenSize.Height() >= 600 )
1258             h = 550;
1259         if( aScreenSize.Height() >= 768 )
1260             h = 630;
1261         if( aScreenSize.Height() >= 1024 )
1262             h = 875;
1263     }
1264     else
1265     {
1266         // Use the same size calculation as on Mac OSX: 80% of width
1267         // and height.
1268         w = static_cast<long>(aScreenSize.Width() * 0.8);
1269         h = static_cast<long>(aScreenSize.Height() * 0.8);
1270     }
1271 
1272     return Size( w, h );
1273 }
1274 
SetDefaultSize()1275 void GtkSalFrame::SetDefaultSize()
1276 {
1277     Size aDefSize = calcDefaultSize();
1278 
1279     SetPosSize( 0, 0, aDefSize.Width(), aDefSize.Height(),
1280                 SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
1281 
1282     if( (m_nStyle & SAL_FRAME_STYLE_DEFAULT) && m_pWindow )
1283         gtk_window_maximize( GTK_WINDOW(m_pWindow) );
1284 }
1285 
initClientId()1286 static void initClientId()
1287 {
1288     static bool bOnce = false;
1289     if( ! bOnce )
1290     {
1291         bOnce = true;
1292         const ByteString& rID = SessionManagerClient::getSessionID();
1293         if( rID.Len() > 0 )
1294             gdk_set_sm_client_id(rID.GetBuffer());
1295     }
1296 }
1297 
Show(sal_Bool bVisible,sal_Bool bNoActivate)1298 void GtkSalFrame::Show( sal_Bool bVisible, sal_Bool bNoActivate )
1299 {
1300     if( m_pWindow )
1301     {
1302         if( m_pParent && (m_pParent->m_nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN)
1303             && getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
1304             gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), bVisible );
1305         if( bVisible )
1306         {
1307             SessionManagerClient::open(); // will simply return after the first time
1308             initClientId();
1309             getDisplay()->startupNotificationCompleted();
1310 
1311             if( m_bDefaultPos )
1312                 Center();
1313             if( m_bDefaultSize )
1314                 SetDefaultSize();
1315             setMinMaxSize();
1316 
1317             // #i45160# switch to desktop where a dialog with parent will appear
1318             if( m_pParent && m_pParent->m_nWorkArea != m_nWorkArea && GTK_WIDGET_MAPPED(m_pParent->m_pWindow) )
1319                 getDisplay()->getWMAdaptor()->switchToWorkArea( m_pParent->m_nWorkArea );
1320 
1321             if( isFloatGrabWindow() &&
1322                 m_pParent &&
1323                 m_nFloats == 0 &&
1324                 ! getDisplay()->GetCaptureFrame() )
1325             {
1326                 /* #i63086#
1327                  * outsmart Metacity's "focus:mouse" mode
1328                  * which insists on taking the focus from the document
1329                  * to the new float. Grab focus to parent frame BEFORE
1330                  * showing the float (cannot grab it to the float
1331                  * before show).
1332                  */
1333                  m_pParent->grabPointer( sal_True, sal_True );
1334             }
1335 
1336             guint32 nUserTime = 0;
1337             if( ! bNoActivate && (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
1338                 /* #i99360# ugly workaround an X11 library bug */
1339                 nUserTime= getDisplay()->GetLastUserEventTime( true );
1340                 //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
1341 
1342             //For these floating windows we don't want the main window to lose focus, and metacity has...
1343             // metacity-2.24.0/src/core/window.c
1344             //
1345             //  if ((focus_window != NULL) && XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time))
1346             //  	"compare" window focus prevented by other activity
1347             //
1348             //  where "compare" is this window
1349 
1350             //  which leads to...
1351 
1352             // /* This happens for error dialogs or alerts; these need to remain on
1353             // * top, but it would be confusing to have its ancestor remain
1354             // * focused.
1355             // */
1356             // if (meta_window_is_ancestor_of_transient (focus_window, window))
1357             //          "The focus window %s is an ancestor of the newly mapped "
1358             //          "window %s which isn't being focused. Unfocusing the "
1359             //          "ancestor.\n",
1360             //
1361             // i.e. having a time < that of the toplevel frame means that the toplevel frame gets unfocused.
1362             // awesome.
1363             if( nUserTime == 0 )
1364             {
1365                 /* #i99360# ugly workaround an X11 library bug */
1366                 nUserTime= getDisplay()->GetLastUserEventTime( true );
1367                 //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
1368             }
1369             lcl_set_user_time( GTK_WIDGET(m_pWindow)->window, nUserTime );
1370 
1371             if( ! bNoActivate && (m_nStyle & SAL_FRAME_STYLE_TOOLWINDOW) )
1372                 m_bSetFocusOnMap = true;
1373 
1374             gtk_widget_show( m_pWindow );
1375 
1376             if( isFloatGrabWindow() )
1377             {
1378                 m_nFloats++;
1379                 if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 1 )
1380                     grabPointer( sal_True, sal_True );
1381                 // #i44068# reset parent's IM context
1382                 if( m_pParent )
1383                     m_pParent->EndExtTextInput(0);
1384             }
1385             if( m_bWindowIsGtkPlug )
1386                 askForXEmbedFocus( 0 );
1387         }
1388         else
1389         {
1390             if( isFloatGrabWindow() )
1391             {
1392                 m_nFloats--;
1393                 if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 0)
1394                     grabPointer( sal_False );
1395             }
1396             gtk_widget_hide( m_pWindow );
1397             if( m_pIMHandler )
1398                 m_pIMHandler->focusChanged( false );
1399             // flush here; there may be a very seldom race between
1400             // the display connection used for clipboard and our connection
1401             Flush();
1402         }
1403         CallCallback( SALEVENT_RESIZE, NULL );
1404     }
1405 }
1406 
Enable(sal_Bool)1407 void GtkSalFrame::Enable( sal_Bool /*bEnable*/ )
1408 {
1409 	// Not implemented by X11SalFrame either
1410 }
1411 
setMinMaxSize()1412 void GtkSalFrame::setMinMaxSize()
1413 {
1414 /*  FIXME: for yet unknown reasons the reported size is a little smaller
1415  *  than the max size hint; one would guess that this was due to the border
1416  *  sizes of the widgets involved (GtkWindow and GtkFixed), but setting
1417  *  their border to 0 (which is the default anyway) does not change the
1418  *  behaviour. Until the reason is known we'll add some pixels here.
1419  */
1420 #define CONTAINER_ADJUSTMENT 6
1421 
1422     /*  #i34504# metacity (and possibly others) do not treat
1423      *  _NET_WM_STATE_FULLSCREEN and max_width/height independently;
1424      *  whether they should is undefined. So don't set the max size hint
1425      *  for a full screen window.
1426     */
1427     if( m_pWindow && ! isChild() )
1428     {
1429         GdkGeometry aGeo;
1430         int aHints = 0;
1431         if( m_nStyle & SAL_FRAME_STYLE_SIZEABLE )
1432         {
1433             if( m_aMinSize.Width() && m_aMinSize.Height() )
1434             {
1435                 aGeo.min_width	= m_aMinSize.Width()+CONTAINER_ADJUSTMENT;
1436                 aGeo.min_height	= m_aMinSize.Height()+CONTAINER_ADJUSTMENT;
1437                 aHints |= GDK_HINT_MIN_SIZE;
1438             }
1439             if( m_aMaxSize.Width() && m_aMaxSize.Height() && ! m_bFullscreen )
1440             {
1441                 aGeo.max_width	= m_aMaxSize.Width()+CONTAINER_ADJUSTMENT;
1442                 aGeo.max_height	= m_aMaxSize.Height()+CONTAINER_ADJUSTMENT;
1443                 aHints |= GDK_HINT_MAX_SIZE;
1444             }
1445         }
1446         else
1447         {
1448             aGeo.min_width = maGeometry.nWidth;
1449             aGeo.min_height = maGeometry.nHeight;
1450             aHints |= GDK_HINT_MIN_SIZE;
1451             if( ! m_bFullscreen )
1452             {
1453                 aGeo.max_width = maGeometry.nWidth;
1454                 aGeo.max_height = maGeometry.nHeight;
1455                 aHints |= GDK_HINT_MAX_SIZE;
1456             }
1457         }
1458         if( m_bFullscreen && m_aMaxSize.Width() && m_aMaxSize.Height() )
1459         {
1460             aGeo.max_width = m_aMaxSize.Width();
1461             aGeo.max_height = m_aMaxSize.Height();
1462             aHints |= GDK_HINT_MAX_SIZE;
1463         }
1464         if( aHints )
1465             gtk_window_set_geometry_hints( GTK_WINDOW(m_pWindow),
1466                                            NULL,
1467                                            &aGeo,
1468                                            GdkWindowHints( aHints ) );
1469     }
1470 }
1471 
SetMaxClientSize(long nWidth,long nHeight)1472 void GtkSalFrame::SetMaxClientSize( long nWidth, long nHeight )
1473 {
1474     if( ! isChild() )
1475     {
1476         m_aMaxSize = Size( nWidth, nHeight );
1477         // Show does a setMinMaxSize
1478         if( GTK_WIDGET_MAPPED( m_pWindow ) )
1479             setMinMaxSize();
1480     }
1481 }
SetMinClientSize(long nWidth,long nHeight)1482 void GtkSalFrame::SetMinClientSize( long nWidth, long nHeight )
1483 {
1484     if( ! isChild() )
1485     {
1486         m_aMinSize = Size( nWidth, nHeight );
1487         if( m_pWindow )
1488         {
1489             gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
1490             // Show does a setMinMaxSize
1491             if( GTK_WIDGET_MAPPED( m_pWindow ) )
1492                 setMinMaxSize();
1493         }
1494     }
1495 }
1496 
SetPosSize(long nX,long nY,long nWidth,long nHeight,sal_uInt16 nFlags)1497 void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
1498 {
1499     if( !m_pWindow || isChild( true, false ) )
1500 		return;
1501 
1502     bool bSized = false, bMoved = false;
1503 
1504 	if( (nFlags & ( SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT )) &&
1505 		(nWidth > 0 && nHeight > 0 ) // sometimes stupid things happen
1506             )
1507 	{
1508         m_bDefaultSize = false;
1509 
1510         if( (unsigned long)nWidth != maGeometry.nWidth || (unsigned long)nHeight != maGeometry.nHeight )
1511             bSized = true;
1512 		maGeometry.nWidth	= nWidth;
1513 		maGeometry.nHeight	= nHeight;
1514 
1515         if( isChild( false, true ) )
1516             gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
1517         else if( ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) )
1518             gtk_window_resize( GTK_WINDOW(m_pWindow), nWidth, nHeight );
1519         setMinMaxSize();
1520 	}
1521     else if( m_bDefaultSize )
1522         SetDefaultSize();
1523 
1524     m_bDefaultSize = false;
1525 
1526 	if( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) )
1527 	{
1528         if( m_pParent )
1529         {
1530             if( Application::GetSettings().GetLayoutRTL() )
1531                 nX = m_pParent->maGeometry.nWidth-maGeometry.nWidth-1-nX;
1532             nX += m_pParent->maGeometry.nX;
1533             nY += m_pParent->maGeometry.nY;
1534         }
1535 
1536         // adjust position to avoid off screen windows
1537         // but allow toolbars to be positioned partly off screen by the user
1538         Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
1539         if( ! (m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
1540         {
1541             if( nX < (long)maGeometry.nLeftDecoration )
1542                 nX = maGeometry.nLeftDecoration;
1543             if( nY < (long)maGeometry.nTopDecoration )
1544                 nY = maGeometry.nTopDecoration;
1545             if( (nX + (long)maGeometry.nWidth + (long)maGeometry.nRightDecoration) > (long)aScreenSize.Width() )
1546                 nX = aScreenSize.Width() - maGeometry.nWidth - maGeometry.nRightDecoration;
1547             if( (nY + (long)maGeometry.nHeight + (long)maGeometry.nBottomDecoration) > (long)aScreenSize.Height() )
1548                 nY = aScreenSize.Height() - maGeometry.nHeight - maGeometry.nBottomDecoration;
1549         }
1550         else
1551         {
1552             if( nX + (long)maGeometry.nWidth < 10 )
1553                 nX = 10 - (long)maGeometry.nWidth;
1554             if( nY + (long)maGeometry.nHeight < 10 )
1555                 nY = 10 - (long)maGeometry.nHeight;
1556             if( nX > (long)aScreenSize.Width() - 10 )
1557                 nX = (long)aScreenSize.Width() - 10;
1558             if( nY > (long)aScreenSize.Height() - 10 )
1559                 nY = (long)aScreenSize.Height() - 10;
1560         }
1561 
1562         if( nX != maGeometry.nX || nY != maGeometry.nY )
1563             bMoved = true;
1564         maGeometry.nX = nX;
1565         maGeometry.nY = nY;
1566 
1567         m_bDefaultPos = false;
1568 
1569         moveWindow( maGeometry.nX, maGeometry.nY );
1570 
1571         updateScreenNumber();
1572 	}
1573 	else if( m_bDefaultPos )
1574 		Center();
1575 
1576 	m_bDefaultPos = false;
1577 
1578     if( bSized && ! bMoved )
1579         CallCallback( SALEVENT_RESIZE, NULL );
1580     else if( bMoved && ! bSized )
1581         CallCallback( SALEVENT_MOVE, NULL );
1582     else if( bMoved && bSized )
1583         CallCallback( SALEVENT_MOVERESIZE, NULL );
1584 }
1585 
GetClientSize(long & rWidth,long & rHeight)1586 void GtkSalFrame::GetClientSize( long& rWidth, long& rHeight )
1587 {
1588     if( m_pWindow && !(m_nState & GDK_WINDOW_STATE_ICONIFIED) )
1589     {
1590         rWidth = maGeometry.nWidth;
1591         rHeight = maGeometry.nHeight;
1592     }
1593     else
1594         rWidth = rHeight = 0;
1595 }
1596 
GetWorkArea(Rectangle & rRect)1597 void GtkSalFrame::GetWorkArea( Rectangle& rRect )
1598 {
1599     rRect = GetX11SalData()->GetDisplay()->getWMAdaptor()->getWorkArea( 0 );
1600 }
1601 
GetParent() const1602 SalFrame* GtkSalFrame::GetParent() const
1603 {
1604     return m_pParent;
1605 }
1606 
SetWindowState(const SalFrameState * pState)1607 void GtkSalFrame::SetWindowState( const SalFrameState* pState )
1608 {
1609     if( ! m_pWindow || ! pState || isChild( true, false ) )
1610         return;
1611 
1612     const sal_uLong nMaxGeometryMask =
1613         SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y |
1614         SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT |
1615         SAL_FRAMESTATE_MASK_MAXIMIZED_X | SAL_FRAMESTATE_MASK_MAXIMIZED_Y |
1616         SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT;
1617 
1618     if( (pState->mnMask & SAL_FRAMESTATE_MASK_STATE) &&
1619         ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) &&
1620         (pState->mnState & SAL_FRAMESTATE_MAXIMIZED) &&
1621         (pState->mnMask & nMaxGeometryMask) == nMaxGeometryMask )
1622     {
1623         resizeWindow( pState->mnWidth, pState->mnHeight );
1624         moveWindow( pState->mnX, pState->mnY );
1625         m_bDefaultPos = m_bDefaultSize = false;
1626 
1627         maGeometry.nX       = pState->mnMaximizedX;
1628         maGeometry.nY       = pState->mnMaximizedY;
1629         maGeometry.nWidth   = pState->mnMaximizedWidth;
1630         maGeometry.nHeight  = pState->mnMaximizedHeight;
1631         updateScreenNumber();
1632 
1633         m_nState = GdkWindowState( m_nState | GDK_WINDOW_STATE_MAXIMIZED );
1634         m_aRestorePosSize = Rectangle( Point( pState->mnX, pState->mnY ),
1635                                        Size( pState->mnWidth, pState->mnHeight ) );
1636     }
1637     else if( pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y |
1638                                SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT ) )
1639     {
1640         sal_uInt16 nPosSizeFlags = 0;
1641         long nX			= pState->mnX - (m_pParent ? m_pParent->maGeometry.nX : 0);
1642         long nY			= pState->mnY - (m_pParent ? m_pParent->maGeometry.nY : 0);
1643         long nWidth		= pState->mnWidth;
1644         long nHeight	= pState->mnHeight;
1645         if( pState->mnMask & SAL_FRAMESTATE_MASK_X )
1646             nPosSizeFlags |= SAL_FRAME_POSSIZE_X;
1647         else
1648             nX = maGeometry.nX - (m_pParent ? m_pParent->maGeometry.nX : 0);
1649         if( pState->mnMask & SAL_FRAMESTATE_MASK_Y )
1650             nPosSizeFlags |= SAL_FRAME_POSSIZE_Y;
1651         else
1652             nY = maGeometry.nY - (m_pParent ? m_pParent->maGeometry.nY : 0);
1653         if( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH )
1654             nPosSizeFlags |= SAL_FRAME_POSSIZE_WIDTH;
1655         else
1656             nWidth = maGeometry.nWidth;
1657         if( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT )
1658             nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT;
1659         else
1660             nHeight = maGeometry.nHeight;
1661         SetPosSize( nX, nY, pState->mnWidth, pState->mnHeight, nPosSizeFlags );
1662     }
1663     if( pState->mnMask & SAL_FRAMESTATE_MASK_STATE && ! isChild() )
1664     {
1665         if( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
1666             gtk_window_maximize( GTK_WINDOW(m_pWindow) );
1667         else
1668             gtk_window_unmaximize( GTK_WINDOW(m_pWindow) );
1669         /* #i42379# there is no rollup state in GDK; and rolled up windows are
1670         *  (probably depending on the WM) reported as iconified. If we iconify a
1671         *  window here that was e.g. a dialog, then it will be unmapped but still
1672         *  not be displayed in the task list, so it's an iconified window that
1673         *  the user cannot get out of this state. So do not set the iconified state
1674         *  on windows with a parent (that is transient frames) since these tend
1675         *  to not be represented in an icon task list.
1676         */
1677         if( (pState->mnState & SAL_FRAMESTATE_MINIMIZED)
1678             && ! m_pParent )
1679             gtk_window_iconify( GTK_WINDOW(m_pWindow) );
1680         else
1681             gtk_window_deiconify( GTK_WINDOW(m_pWindow) );
1682     }
1683 }
1684 
GetWindowState(SalFrameState * pState)1685 sal_Bool GtkSalFrame::GetWindowState( SalFrameState* pState )
1686 {
1687     pState->mnState = SAL_FRAMESTATE_NORMAL;
1688     pState->mnMask  = SAL_FRAMESTATE_MASK_STATE;
1689     // rollup ? gtk 2.2 does not seem to support the shaded state
1690     if( (m_nState & GDK_WINDOW_STATE_ICONIFIED) )
1691         pState->mnState |= SAL_FRAMESTATE_MINIMIZED;
1692     if( m_nState & GDK_WINDOW_STATE_MAXIMIZED )
1693     {
1694         pState->mnState |= SAL_FRAMESTATE_MAXIMIZED;
1695         pState->mnX                 = m_aRestorePosSize.Left();
1696         pState->mnY                 = m_aRestorePosSize.Top();
1697         pState->mnWidth             = m_aRestorePosSize.GetWidth();
1698         pState->mnHeight            = m_aRestorePosSize.GetHeight();
1699         pState->mnMaximizedX        = maGeometry.nX;
1700         pState->mnMaximizedY        = maGeometry.nY;
1701         pState->mnMaximizedWidth    = maGeometry.nWidth;
1702         pState->mnMaximizedHeight   = maGeometry.nHeight;
1703         pState->mnMask	|= SAL_FRAMESTATE_MASK_MAXIMIZED_X			|
1704                            SAL_FRAMESTATE_MASK_MAXIMIZED_Y			|
1705                            SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH		|
1706                            SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT;
1707     }
1708     else
1709     {
1710 
1711         pState->mnX			= maGeometry.nX;
1712         pState->mnY			= maGeometry.nY;
1713         pState->mnWidth		= maGeometry.nWidth;
1714         pState->mnHeight	= maGeometry.nHeight;
1715     }
1716     pState->mnMask	|= SAL_FRAMESTATE_MASK_X			|
1717                        SAL_FRAMESTATE_MASK_Y			|
1718                        SAL_FRAMESTATE_MASK_WIDTH		|
1719                        SAL_FRAMESTATE_MASK_HEIGHT;
1720 
1721     return sal_True;
1722 }
1723 
moveToScreen(int nScreen)1724 void GtkSalFrame::moveToScreen( int nScreen )
1725 {
1726     if( isChild() )
1727         return;
1728 
1729     if( nScreen < 0 || nScreen >= gdk_display_get_n_screens( getGdkDisplay() ) )
1730         nScreen = m_nScreen;
1731     if( nScreen == m_nScreen )
1732         return;
1733 
1734     GdkScreen* pScreen = gdk_display_get_screen( getGdkDisplay(), nScreen );
1735     if( pScreen )
1736     {
1737         m_nScreen = nScreen;
1738         gtk_window_set_screen( GTK_WINDOW(m_pWindow), pScreen );
1739         // realize the window, we need an XWindow id
1740         gtk_widget_realize( m_pWindow );
1741         // update system data
1742         GtkSalDisplay* pDisp = getDisplay();
1743         m_aSystemData.aWindow		= GDK_WINDOW_XWINDOW(m_pWindow->window);
1744         m_aSystemData.pVisual		= pDisp->GetVisual( m_nScreen ).GetVisual();
1745         m_aSystemData.nScreen		= nScreen;
1746         m_aSystemData.nDepth		= pDisp->GetVisual( m_nScreen ).GetDepth();
1747         m_aSystemData.aColormap		= pDisp->GetColormap( m_nScreen ).GetXColormap();
1748         m_aSystemData.pAppContext	= NULL;
1749         m_aSystemData.aShellWindow	= m_aSystemData.aWindow;
1750         // update graphics if necessary
1751         for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
1752         {
1753             if( m_aGraphics[i].bInUse )
1754                 m_aGraphics[i].pGraphics->SetDrawable( GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
1755         }
1756         updateScreenNumber();
1757     }
1758 
1759     if( m_pParent && m_pParent->m_nScreen != m_nScreen )
1760         SetParent( NULL );
1761     std::list< GtkSalFrame* > aChildren = m_aChildren;
1762     for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
1763         (*it)->moveToScreen( m_nScreen );
1764 
1765     // FIXME: SalObjects
1766 }
1767 
SetScreenNumber(unsigned int nNewScreen)1768 void GtkSalFrame::SetScreenNumber( unsigned int nNewScreen )
1769 {
1770     if( nNewScreen == maGeometry.nScreenNumber )
1771         return;
1772 
1773     if( m_pWindow && ! isChild() )
1774     {
1775         GtkSalDisplay* pDisp = getDisplay();
1776         if( pDisp->IsXinerama() && pDisp->GetXineramaScreens().size() > 1 )
1777         {
1778             if( nNewScreen >= pDisp->GetXineramaScreens().size() )
1779                 return;
1780 
1781             Rectangle aOldScreenRect( pDisp->GetXineramaScreens()[maGeometry.nScreenNumber] );
1782             Rectangle aNewScreenRect( pDisp->GetXineramaScreens()[nNewScreen] );
1783             bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
1784             if( bVisible )
1785                 Show( sal_False );
1786             maGeometry.nX = aNewScreenRect.Left() + (maGeometry.nX - aOldScreenRect.Left());
1787             maGeometry.nY = aNewScreenRect.Top() + (maGeometry.nY - aOldScreenRect.Top());
1788             createNewWindow( None, false, m_nScreen );
1789             gtk_window_move( GTK_WINDOW(m_pWindow), maGeometry.nX, maGeometry.nY );
1790             if( bVisible )
1791                 Show( sal_True );
1792             maGeometry.nScreenNumber = nNewScreen;
1793         }
1794         else if( sal_Int32(nNewScreen) < pDisp->GetScreenCount() )
1795         {
1796             moveToScreen( (int)nNewScreen );
1797             maGeometry.nScreenNumber = nNewScreen;
1798             gtk_window_move( GTK_WINDOW(m_pWindow), maGeometry.nX, maGeometry.nY );
1799         }
1800     }
1801 }
1802 
ShowFullScreen(sal_Bool bFullScreen,sal_Int32 nScreen)1803 void GtkSalFrame::ShowFullScreen( sal_Bool bFullScreen, sal_Int32 nScreen )
1804 {
1805     if( m_pWindow && ! isChild() )
1806     {
1807         GtkSalDisplay* pDisp = getDisplay();
1808         // xinerama ?
1809         if( pDisp->IsXinerama() && pDisp->GetXineramaScreens().size() > 1 )
1810         {
1811             if( bFullScreen )
1812             {
1813                 m_aRestorePosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
1814                                                Size( maGeometry.nWidth, maGeometry.nHeight ) );
1815                 bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
1816                 if( bVisible )
1817                     Show( sal_False );
1818                 m_nStyle |= SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
1819                 createNewWindow( None, false, m_nScreen );
1820                 Rectangle aNewPosSize;
1821                 if( nScreen < 0 || nScreen >= static_cast<int>(pDisp->GetXineramaScreens().size()) )
1822                     aNewPosSize = Rectangle( Point( 0, 0 ), pDisp->GetScreenSize(m_nScreen) );
1823                 else
1824                     aNewPosSize = pDisp->GetXineramaScreens()[ nScreen ];
1825 
1826                 gtk_window_resize( GTK_WINDOW(m_pWindow),
1827                                    maGeometry.nWidth = aNewPosSize.GetWidth(),
1828                                    maGeometry.nHeight = aNewPosSize.GetHeight() );
1829                 gtk_window_move( GTK_WINDOW(m_pWindow),
1830                                  maGeometry.nX = aNewPosSize.Left(),
1831                                  maGeometry.nY = aNewPosSize.Top() );
1832                 // #i110881# for the benefit of compiz set a max size here
1833                 // else setting to fullscreen fails for unknown reasons
1834                 m_aMaxSize.Width() = aNewPosSize.GetWidth()+100;
1835                 m_aMaxSize.Height() = aNewPosSize.GetHeight()+100;
1836                 // workaround different legacy version window managers have different opinions about
1837                 // _NET_WM_STATE_FULLSCREEN (Metacity <-> KWin)
1838                 if( ! getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
1839                 {
1840                     pDisp->getWMAdaptor()->setFullScreenMonitors( GDK_WINDOW_XWINDOW( GTK_WIDGET(m_pWindow)->window ), nScreen );
1841                     if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
1842                         gtk_window_set_resizable( GTK_WINDOW(m_pWindow), sal_True );
1843                     gtk_window_fullscreen( GTK_WINDOW( m_pWindow ) );
1844                 }
1845                 if( bVisible )
1846                     Show( sal_True );
1847             }
1848             else
1849             {
1850                 bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
1851                 if( ! getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
1852                     gtk_window_unfullscreen( GTK_WINDOW(m_pWindow) );
1853                 if( bVisible )
1854                     Show( sal_False );
1855                 m_nStyle &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
1856                 createNewWindow( None, false, m_nScreen );
1857                 if( ! m_aRestorePosSize.IsEmpty() )
1858                 {
1859                     gtk_window_resize( GTK_WINDOW(m_pWindow),
1860                                        maGeometry.nWidth = m_aRestorePosSize.GetWidth(),
1861                                        maGeometry.nHeight = m_aRestorePosSize.GetHeight() );
1862                     gtk_window_move( GTK_WINDOW(m_pWindow),
1863                                      maGeometry.nX = m_aRestorePosSize.Left(),
1864                                      maGeometry.nY = m_aRestorePosSize.Top() );
1865                     m_aRestorePosSize = Rectangle();
1866                 }
1867                 if( bVisible )
1868                     Show( sal_True );
1869             }
1870         }
1871         else
1872         {
1873             if( bFullScreen )
1874             {
1875                 if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
1876                     gtk_window_set_resizable( GTK_WINDOW(m_pWindow), TRUE );
1877                 gtk_window_fullscreen( GTK_WINDOW(m_pWindow) );
1878                 moveToScreen( nScreen );
1879                 Size aScreenSize = pDisp->GetScreenSize( m_nScreen );
1880                 maGeometry.nX       = 0;
1881                 maGeometry.nY       = 0;
1882                 maGeometry.nWidth   = aScreenSize.Width();
1883                 maGeometry.nHeight  = aScreenSize.Height();
1884             }
1885             else
1886             {
1887                 gtk_window_unfullscreen( GTK_WINDOW(m_pWindow) );
1888                 if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
1889                     gtk_window_set_resizable( GTK_WINDOW(m_pWindow), FALSE );
1890                 moveToScreen( nScreen );
1891             }
1892         }
1893         m_bDefaultPos = m_bDefaultSize = false;
1894         updateScreenNumber();
1895         CallCallback( SALEVENT_MOVERESIZE, NULL );
1896     }
1897     m_bFullscreen = bFullScreen;
1898 }
1899 
1900 /* definitions from xautolock.c (pl15) */
1901 #define XAUTOLOCK_DISABLE 1
1902 #define XAUTOLOCK_ENABLE  2
1903 
setAutoLock(bool bLock)1904 void GtkSalFrame::setAutoLock( bool bLock )
1905 {
1906     if( isChild() )
1907         return;
1908 
1909 	GdkScreen  *pScreen = gtk_window_get_screen( GTK_WINDOW(m_pWindow) );
1910 	GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
1911 	GdkWindow  *pRootWin = gdk_screen_get_root_window( pScreen );
1912 
1913 	Atom nAtom = XInternAtom( GDK_DISPLAY_XDISPLAY( pDisplay ),
1914 							  "XAUTOLOCK_MESSAGE", False );
1915 
1916 	int nMessage = bLock ? XAUTOLOCK_ENABLE : XAUTOLOCK_DISABLE;
1917 
1918 	XChangeProperty( GDK_DISPLAY_XDISPLAY( pDisplay ),
1919 					 GDK_WINDOW_XID( pRootWin ),
1920 					 nAtom, XA_INTEGER,
1921 					 8, PropModeReplace,
1922 					 (unsigned char*)&nMessage,
1923 					 sizeof( nMessage ) );
1924 }
1925 
1926 #ifdef ENABLE_DBUS
1927 /** cookie is returned as an unsigned integer */
1928 static guint
dbus_inhibit_gsm(const gchar * appname,const gchar * reason,guint xid)1929 dbus_inhibit_gsm (const gchar *appname,
1930                   const gchar *reason,
1931                   guint xid)
1932 {
1933         gboolean         res;
1934         guint            cookie;
1935         GError          *error = NULL;
1936         DBusGProxy      *proxy = NULL;
1937         DBusGConnection *session_connection = NULL;
1938 
1939         /* get the DBUS session connection */
1940         session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
1941         if (error != NULL) {
1942                 g_warning ("DBUS cannot connect : %s", error->message);
1943                 g_error_free (error);
1944                 return -1;
1945         }
1946 
1947         /* get the proxy with gnome-session-manager */
1948         proxy = dbus_g_proxy_new_for_name (session_connection,
1949                                            GSM_DBUS_SERVICE,
1950                                            GSM_DBUS_PATH,
1951                                            GSM_DBUS_INTERFACE);
1952         if (proxy == NULL) {
1953                 g_warning ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
1954                 return -1;
1955         }
1956 
1957         res = dbus_g_proxy_call (proxy,
1958                                  "Inhibit", &error,
1959                                  G_TYPE_STRING, appname,
1960                                  G_TYPE_UINT, xid,
1961                                  G_TYPE_STRING, reason,
1962                                  G_TYPE_UINT, 8, // Inhibit the session being marked as idle
1963                                  G_TYPE_INVALID,
1964                                  G_TYPE_UINT, &cookie,
1965                                  G_TYPE_INVALID);
1966 
1967         /* check the return value */
1968         if (! res) {
1969                 cookie = -1;
1970                 g_warning ("Inhibit method failed");
1971         }
1972 
1973         /* check the error value */
1974         if (error != NULL) {
1975                 g_warning ("Inhibit problem : %s", error->message);
1976                 g_error_free (error);
1977                 cookie = -1;
1978         }
1979 
1980         g_object_unref (G_OBJECT (proxy));
1981         return cookie;
1982 }
1983 
1984 static void
dbus_uninhibit_gsm(guint cookie)1985 dbus_uninhibit_gsm (guint cookie)
1986 {
1987         gboolean         res;
1988         GError          *error = NULL;
1989         DBusGProxy      *proxy = NULL;
1990         DBusGConnection *session_connection = NULL;
1991 
1992         if (cookie == guint(-1)) {
1993                 g_warning ("Invalid cookie");
1994                 return;
1995         }
1996 
1997         /* get the DBUS session connection */
1998         session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
1999         if (error) {
2000                 g_warning ("DBUS cannot connect : %s", error->message);
2001                 g_error_free (error);
2002                 return;
2003         }
2004 
2005         /* get the proxy with gnome-session-manager */
2006         proxy = dbus_g_proxy_new_for_name (session_connection,
2007                                            GSM_DBUS_SERVICE,
2008                                            GSM_DBUS_PATH,
2009                                            GSM_DBUS_INTERFACE);
2010         if (proxy == NULL) {
2011                 g_warning ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
2012                 return;
2013         }
2014 
2015         res = dbus_g_proxy_call (proxy,
2016                                  "Uninhibit",
2017                                  &error,
2018                                  G_TYPE_UINT, cookie,
2019                                  G_TYPE_INVALID,
2020                                  G_TYPE_INVALID);
2021 
2022         /* check the return value */
2023         if (! res) {
2024                 g_warning ("Uninhibit method failed");
2025         }
2026 
2027         /* check the error value */
2028         if (error != NULL) {
2029                 g_warning ("Uninhibit problem : %s", error->message);
2030                 g_error_free (error);
2031                 cookie = -1;
2032         }
2033         g_object_unref (G_OBJECT (proxy));
2034 }
2035 #endif
2036 
StartPresentation(sal_Bool bStart)2037 void GtkSalFrame::StartPresentation( sal_Bool bStart )
2038 {
2039 	Display *pDisplay = GDK_DISPLAY_XDISPLAY( getGdkDisplay() );
2040 
2041 	setAutoLock( !bStart );
2042 
2043 	int nTimeout, nInterval, bPreferBlanking, bAllowExposures;
2044 
2045 	XGetScreenSaver( pDisplay, &nTimeout, &nInterval,
2046 					 &bPreferBlanking, &bAllowExposures );
2047 	if( bStart )
2048 	{
2049 		if ( nTimeout )
2050 		{
2051 			m_nSavedScreenSaverTimeout = nTimeout;
2052 			XResetScreenSaver( pDisplay );
2053 			XSetScreenSaver( pDisplay, 0, nInterval,
2054 							 bPreferBlanking, bAllowExposures );
2055 		}
2056 #ifdef ENABLE_DBUS
2057 		m_nGSMCookie = dbus_inhibit_gsm(g_get_application_name(), "presentation",
2058                     GDK_WINDOW_XID(m_pWindow->window));
2059 #endif
2060 	}
2061 	else
2062 	{
2063 		if( m_nSavedScreenSaverTimeout )
2064 			XSetScreenSaver( pDisplay, m_nSavedScreenSaverTimeout,
2065 							 nInterval, bPreferBlanking,
2066 							 bAllowExposures );
2067 		m_nSavedScreenSaverTimeout = 0;
2068 #ifdef ENABLE_DBUS
2069 		dbus_uninhibit_gsm(m_nGSMCookie);
2070 #endif
2071 	}
2072 }
2073 
SetAlwaysOnTop(sal_Bool)2074 void GtkSalFrame::SetAlwaysOnTop( sal_Bool /*bOnTop*/ )
2075 {
2076 }
2077 
ToTop(sal_uInt16 nFlags)2078 void GtkSalFrame::ToTop( sal_uInt16 nFlags )
2079 {
2080     if( m_pWindow )
2081     {
2082         if( isChild( false, true ) )
2083             gtk_widget_grab_focus( m_pWindow );
2084         else if( GTK_WIDGET_MAPPED( m_pWindow ) )
2085         {
2086             if( ! (nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY) )
2087                 gtk_window_present( GTK_WINDOW(m_pWindow) );
2088             else
2089             {
2090                 // gdk_window_focus( m_pWindow->window, gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window) );
2091                 /* #i99360# ugly workaround an X11 library bug */
2092                 guint32 nUserTime= getDisplay()->GetLastUserEventTime( true );
2093                 gdk_window_focus( m_pWindow->window, nUserTime );
2094             }
2095             /*  need to do an XSetInputFocus here because
2096              *  gdk_window_focus will ask a EWMH compliant WM to put the focus
2097              *  to our window - which it of course won't since our input hint
2098              *  is set to false.
2099              */
2100             if( (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE)) )
2101             {
2102                 // sad but true: this can cause an XError, we need to catch that
2103                 // to do this we need to synchronize with the XServer
2104                 getDisplay()->GetXLib()->PushXErrorLevel( true );
2105                 XSetInputFocus( getDisplay()->GetDisplay(), GDK_WINDOW_XWINDOW( m_pWindow->window ), RevertToParent, CurrentTime );
2106                 XSync( getDisplay()->GetDisplay(), False );
2107                 getDisplay()->GetXLib()->PopXErrorLevel();
2108             }
2109         }
2110         else
2111         {
2112             if( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
2113                 gtk_window_present( GTK_WINDOW(m_pWindow) );
2114         }
2115     }
2116 }
2117 
SetPointer(PointerStyle ePointerStyle)2118 void GtkSalFrame::SetPointer( PointerStyle ePointerStyle )
2119 {
2120     if( m_pWindow && ePointerStyle != m_ePointerStyle )
2121     {
2122         m_ePointerStyle = ePointerStyle;
2123         GdkCursor *pCursor = getDisplay()->getCursor( ePointerStyle );
2124         gdk_window_set_cursor( m_pWindow->window, pCursor );
2125         m_pCurrentCursor = pCursor;
2126 
2127         // #i80791# use grabPointer the same way as CaptureMouse, respective float grab
2128         if( getDisplay()->MouseCaptured( this ) )
2129             grabPointer( sal_True, sal_False );
2130         else if( m_nFloats > 0 )
2131             grabPointer( sal_True, sal_True );
2132     }
2133 }
2134 
grabPointer(sal_Bool bGrab,sal_Bool bOwnerEvents)2135 void GtkSalFrame::grabPointer( sal_Bool bGrab, sal_Bool bOwnerEvents )
2136 {
2137     if( m_pWindow )
2138     {
2139         if( bGrab )
2140         {
2141             bool bUseGdkGrab = true;
2142             if( getDisplay()->getHaveSystemChildFrame() )
2143             {
2144                 const std::list< SalFrame* >& rFrames = getDisplay()->getFrames();
2145                 for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
2146                 {
2147                     const GtkSalFrame* pFrame = static_cast< const GtkSalFrame* >(*it);
2148                     if( pFrame->m_bWindowIsGtkPlug )
2149                     {
2150                         bUseGdkGrab = false;
2151                         break;
2152                     }
2153                 }
2154             }
2155             if( bUseGdkGrab )
2156             {
2157                 const int nMask = ( GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK );
2158 
2159                 gdk_pointer_grab( m_pWindow->window, bOwnerEvents,
2160                                   (GdkEventMask) nMask, NULL, m_pCurrentCursor,
2161                                   GDK_CURRENT_TIME );
2162             }
2163             else
2164             {
2165                 // FIXME: for some unknown reason gdk_pointer_grab does not
2166                 // really produce owner events for GtkPlug windows
2167                 // the cause is yet unknown
2168                 //
2169                 // this is of course a bad hack, especially as we cannot
2170                 // set the right cursor this way
2171                 XGrabPointer( getDisplay()->GetDisplay(),
2172                               GDK_WINDOW_XWINDOW( m_pWindow->window),
2173                               bOwnerEvents,
2174                               PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
2175                               GrabModeAsync,
2176                               GrabModeAsync,
2177                               None,
2178                               None,
2179                               CurrentTime
2180                               );
2181 
2182             }
2183         }
2184         else
2185         {
2186             // Two GdkDisplays may be open
2187             gdk_display_pointer_ungrab( getGdkDisplay(), GDK_CURRENT_TIME);
2188         }
2189     }
2190 }
2191 
CaptureMouse(sal_Bool bCapture)2192 void GtkSalFrame::CaptureMouse( sal_Bool bCapture )
2193 {
2194 	getDisplay()->CaptureMouse( bCapture ? this : NULL );
2195 }
2196 
SetPointerPos(long nX,long nY)2197 void GtkSalFrame::SetPointerPos( long nX, long nY )
2198 {
2199     GtkSalFrame* pFrame = this;
2200     while( pFrame && pFrame->isChild( false, true ) )
2201         pFrame = pFrame->m_pParent;
2202     if( ! pFrame )
2203         return;
2204 
2205 	GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(pFrame->m_pWindow) );
2206 	GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
2207 
2208     /* #87921# when the application tries to center the mouse in the dialog the
2209      * window isn't mapped already. So use coordinates relative to the root window.
2210      */
2211     unsigned int nWindowLeft = maGeometry.nX + nX;
2212     unsigned int nWindowTop  = maGeometry.nY + nY;
2213 
2214     XWarpPointer( GDK_DISPLAY_XDISPLAY (pDisplay), None,
2215 				  GDK_WINDOW_XID (gdk_screen_get_root_window( pScreen ) ),
2216                   0, 0, 0, 0, nWindowLeft, nWindowTop);
2217     // #i38648# ask for the next motion hint
2218     gint x, y;
2219     GdkModifierType mask;
2220     gdk_window_get_pointer( pFrame->m_pWindow->window, &x, &y, &mask );
2221 }
2222 
Flush()2223 void GtkSalFrame::Flush()
2224 {
2225 #ifdef HAVE_A_RECENT_GTK
2226 	gdk_display_flush( getGdkDisplay() );
2227 #else
2228     XFlush (GDK_DISPLAY_XDISPLAY (getGdkDisplay()));
2229 #endif
2230 }
2231 
Sync()2232 void GtkSalFrame::Sync()
2233 {
2234 	gdk_display_sync( getGdkDisplay() );
2235 }
2236 
GetSymbolKeyName(const String &,sal_uInt16 nKeyCode)2237 String GtkSalFrame::GetSymbolKeyName( const String&, sal_uInt16 nKeyCode )
2238 {
2239   return getDisplay()->GetKeyName( nKeyCode );
2240 }
2241 
GetKeyName(sal_uInt16 nKeyCode)2242 String GtkSalFrame::GetKeyName( sal_uInt16 nKeyCode )
2243 {
2244 	return getDisplay()->GetKeyName( nKeyCode );
2245 }
2246 
getGdkDisplay()2247 GdkDisplay *GtkSalFrame::getGdkDisplay()
2248 {
2249     return static_cast<GtkSalDisplay*>(GetX11SalData()->GetDisplay())->GetGdkDisplay();
2250 }
2251 
getDisplay()2252 GtkSalDisplay *GtkSalFrame::getDisplay()
2253 {
2254 	return static_cast<GtkSalDisplay*>(GetX11SalData()->GetDisplay());
2255 }
2256 
GetPointerState()2257 SalFrame::SalPointerState GtkSalFrame::GetPointerState()
2258 {
2259     SalPointerState aState;
2260     GdkScreen* pScreen;
2261     gint x, y;
2262     GdkModifierType aMask;
2263     gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
2264     aState.maPos = Point( x - maGeometry.nX, y - maGeometry.nY );
2265     aState.mnState = GetMouseModCode( aMask );
2266     return aState;
2267 }
2268 
SetInputContext(SalInputContext * pContext)2269 void GtkSalFrame::SetInputContext( SalInputContext* pContext )
2270 {
2271     if( ! pContext )
2272         return;
2273 
2274     if( ! (pContext->mnOptions & SAL_INPUTCONTEXT_TEXT) )
2275         return;
2276 
2277     // create a new im context
2278     if( ! m_pIMHandler )
2279         m_pIMHandler = new IMHandler( this );
2280     m_pIMHandler->setInputContext( pContext );
2281 }
2282 
EndExtTextInput(sal_uInt16 nFlags)2283 void GtkSalFrame::EndExtTextInput( sal_uInt16 nFlags )
2284 {
2285     if( m_pIMHandler )
2286         m_pIMHandler->endExtTextInput( nFlags );
2287 }
2288 
MapUnicodeToKeyCode(sal_Unicode,LanguageType,KeyCode &)2289 sal_Bool GtkSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& )
2290 {
2291     // not supported yet
2292     return sal_False;
2293 }
2294 
GetInputLanguage()2295 LanguageType GtkSalFrame::GetInputLanguage()
2296 {
2297     return LANGUAGE_DONTKNOW;
2298 }
2299 
SnapShot()2300 SalBitmap* GtkSalFrame::SnapShot()
2301 {
2302 	if( !m_pWindow )
2303 		return NULL;
2304 
2305 	X11SalBitmap *pBmp = new X11SalBitmap;
2306 	GdkWindow *pWin = m_pWindow->window;
2307 	if( pBmp->SnapShot( GDK_DISPLAY_XDISPLAY( getGdkDisplay() ),
2308 						GDK_WINDOW_XID( pWin ) ) )
2309 		return pBmp;
2310 	else
2311 		delete pBmp;
2312 
2313 	return NULL;
2314 }
2315 
UpdateSettings(AllSettings & rSettings)2316 void GtkSalFrame::UpdateSettings( AllSettings& rSettings )
2317 {
2318     if( ! m_pWindow )
2319         return;
2320 
2321     GtkSalGraphics* pGraphics = static_cast<GtkSalGraphics*>(m_aGraphics[0].pGraphics);
2322     bool bFreeGraphics = false;
2323     if( ! pGraphics )
2324     {
2325         pGraphics = static_cast<GtkSalGraphics*>(GetGraphics());
2326         bFreeGraphics = true;
2327     }
2328 
2329     pGraphics->updateSettings( rSettings );
2330 
2331     if( bFreeGraphics )
2332         ReleaseGraphics( pGraphics );
2333 }
2334 
Beep(SoundType eType)2335 void GtkSalFrame::Beep( SoundType eType )
2336 {
2337     switch( eType )
2338     {
2339         case SOUND_DEFAULT:
2340         case SOUND_ERROR:
2341             gdk_display_beep( getGdkDisplay() );
2342             break;
2343         default:
2344             break;
2345     }
2346 }
2347 
GetSystemData() const2348 const SystemEnvData* GtkSalFrame::GetSystemData() const
2349 {
2350     return &m_aSystemData;
2351 }
2352 
SetParent(SalFrame * pNewParent)2353 void GtkSalFrame::SetParent( SalFrame* pNewParent )
2354 {
2355     if( m_pParent )
2356         m_pParent->m_aChildren.remove( this );
2357     m_pParent = static_cast<GtkSalFrame*>(pNewParent);
2358     if( m_pParent )
2359         m_pParent->m_aChildren.push_back( this );
2360     if( ! isChild() )
2361         gtk_window_set_transient_for( GTK_WINDOW(m_pWindow),
2362                                       (m_pParent && ! m_pParent->isChild(true,false)) ? GTK_WINDOW(m_pParent->m_pWindow) : NULL
2363                                      );
2364 }
2365 
createNewWindow(XLIB_Window aNewParent,bool bXEmbed,int nScreen)2366 void GtkSalFrame::createNewWindow( XLIB_Window aNewParent, bool bXEmbed, int nScreen )
2367 {
2368     bool bWasVisible = GTK_WIDGET_MAPPED(m_pWindow);
2369     if( bWasVisible )
2370         Show( sal_False );
2371 
2372     if( nScreen < 0 || nScreen >= getDisplay()->GetScreenCount() )
2373         nScreen = m_nScreen;
2374 
2375     SystemParentData aParentData;
2376     aParentData.aWindow = aNewParent;
2377     aParentData.bXEmbedSupport = bXEmbed;
2378     if( aNewParent == None )
2379     {
2380         aNewParent = getDisplay()->GetRootWindow(nScreen);
2381         aParentData.aWindow = None;
2382         aParentData.bXEmbedSupport = false;
2383     }
2384     else
2385     {
2386         // is new parent a root window ?
2387         Display* pDisp = getDisplay()->GetDisplay();
2388         int nScreens = getDisplay()->GetScreenCount();
2389         for( int i = 0; i < nScreens; i++ )
2390         {
2391             if( aNewParent == RootWindow( pDisp, i ) )
2392             {
2393                 nScreen = i;
2394                 aParentData.aWindow = None;
2395                 aParentData.bXEmbedSupport = false;
2396                 break;
2397             }
2398         }
2399     }
2400 
2401     // free xrender resources
2402     for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
2403         if( m_aGraphics[i].bInUse )
2404             m_aGraphics[i].pGraphics->SetDrawable( None, m_nScreen );
2405 
2406     // first deinit frame
2407     if( m_pIMHandler )
2408     {
2409         delete m_pIMHandler;
2410         m_pIMHandler = NULL;
2411     }
2412     if( m_pRegion )
2413         gdk_region_destroy( m_pRegion );
2414     if( m_pFixedContainer )
2415         gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer) );
2416     if( m_pWindow )
2417         gtk_widget_destroy( m_pWindow );
2418     if( m_pForeignParent )
2419         g_object_unref( G_OBJECT(m_pForeignParent) );
2420     if( m_pForeignTopLevel )
2421         g_object_unref( G_OBJECT(m_pForeignTopLevel) );
2422 
2423     // init new window
2424     m_bDefaultPos = m_bDefaultSize = false;
2425     if( aParentData.aWindow != None )
2426     {
2427         m_nStyle |= SAL_FRAME_STYLE_PLUG;
2428         Init( &aParentData );
2429     }
2430     else
2431     {
2432         m_nStyle &= ~SAL_FRAME_STYLE_PLUG;
2433         Init( (m_pParent && m_pParent->m_nScreen == m_nScreen) ? m_pParent : NULL, m_nStyle );
2434     }
2435 
2436 	// update graphics
2437     for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
2438     {
2439         if( m_aGraphics[i].bInUse )
2440         {
2441             m_aGraphics[i].pGraphics->SetDrawable( GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
2442             m_aGraphics[i].pGraphics->SetWindow( m_pWindow );
2443         }
2444     }
2445 
2446     if( m_aTitle.Len() )
2447         SetTitle( m_aTitle );
2448 
2449     if( bWasVisible )
2450         Show( sal_True );
2451 
2452     std::list< GtkSalFrame* > aChildren = m_aChildren;
2453     m_aChildren.clear();
2454     for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
2455         (*it)->createNewWindow( None, false, m_nScreen );
2456 
2457     // FIXME: SalObjects
2458 }
2459 
SetPluginParent(SystemParentData * pSysParent)2460 bool GtkSalFrame::SetPluginParent( SystemParentData* pSysParent )
2461 {
2462     if( pSysParent ) // this may be the first system child frame now
2463         getDisplay()->setHaveSystemChildFrame();
2464     createNewWindow( pSysParent->aWindow, (pSysParent->nSize > sizeof(long)) ? pSysParent->bXEmbedSupport : false, m_nScreen );
2465     return true;
2466 }
2467 
ResetClipRegion()2468 void GtkSalFrame::ResetClipRegion()
2469 {
2470     if( m_pWindow )
2471         gdk_window_shape_combine_region( m_pWindow->window, NULL, 0, 0 );
2472 }
2473 
BeginSetClipRegion(sal_uLong)2474 void GtkSalFrame::BeginSetClipRegion( sal_uLong )
2475 {
2476     if( m_pRegion )
2477         gdk_region_destroy( m_pRegion );
2478     m_pRegion = gdk_region_new();
2479 }
2480 
UnionClipRegion(long nX,long nY,long nWidth,long nHeight)2481 void GtkSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
2482 {
2483     if( m_pRegion )
2484     {
2485         GdkRectangle aRect;
2486         aRect.x			= nX;
2487         aRect.y			= nY;
2488         aRect.width		= nWidth;
2489         aRect.height	= nHeight;
2490 
2491         gdk_region_union_with_rect( m_pRegion, &aRect );
2492     }
2493 }
2494 
EndSetClipRegion()2495 void GtkSalFrame::EndSetClipRegion()
2496 {
2497     if( m_pWindow && m_pRegion )
2498         gdk_window_shape_combine_region( m_pWindow->window, m_pRegion, 0, 0 );
2499 }
2500 
Dispatch(const XEvent * pEvent)2501 bool GtkSalFrame::Dispatch( const XEvent* pEvent )
2502 {
2503     bool bContinueDispatch = true;
2504 
2505     if( pEvent->type == PropertyNotify )
2506     {
2507         vcl_sal::WMAdaptor* pAdaptor = getDisplay()->getWMAdaptor();
2508         Atom nDesktopAtom = pAdaptor->getAtom( vcl_sal::WMAdaptor::NET_WM_DESKTOP );
2509         if( pEvent->xproperty.atom == nDesktopAtom &&
2510             pEvent->xproperty.state == PropertyNewValue )
2511         {
2512             m_nWorkArea = pAdaptor->getWindowWorkArea( GDK_WINDOW_XWINDOW( m_pWindow->window) );
2513         }
2514     }
2515     else if( pEvent->type == ConfigureNotify )
2516     {
2517         if( m_pForeignParent && pEvent->xconfigure.window == m_aForeignParentWindow )
2518         {
2519             bContinueDispatch = false;
2520             gtk_window_resize( GTK_WINDOW(m_pWindow), pEvent->xconfigure.width, pEvent->xconfigure.height );
2521             if( ( sal::static_int_cast< int >(maGeometry.nWidth) !=
2522                   pEvent->xconfigure.width ) ||
2523                 ( sal::static_int_cast< int >(maGeometry.nHeight) !=
2524                   pEvent->xconfigure.height ) )
2525             {
2526                 maGeometry.nWidth  = pEvent->xconfigure.width;
2527                 maGeometry.nHeight = pEvent->xconfigure.height;
2528                 setMinMaxSize();
2529                 getDisplay()->SendInternalEvent( this, NULL, SALEVENT_RESIZE );
2530             }
2531         }
2532         else if( m_pForeignTopLevel && pEvent->xconfigure.window == m_aForeignTopLevelWindow )
2533         {
2534             bContinueDispatch = false;
2535             // update position
2536             int x = 0, y = 0;
2537             XLIB_Window aChild;
2538             XTranslateCoordinates( getDisplay()->GetDisplay(),
2539                                    GDK_WINDOW_XWINDOW( m_pWindow->window),
2540                                    getDisplay()->GetRootWindow( getDisplay()->GetDefaultScreenNumber() ),
2541                                    0, 0,
2542                                    &x, &y,
2543                                    &aChild );
2544             if( x != maGeometry.nX || y != maGeometry.nY )
2545             {
2546                 maGeometry.nX = x;
2547                 maGeometry.nY = y;
2548                 getDisplay()->SendInternalEvent( this, NULL, SALEVENT_MOVE );
2549             }
2550         }
2551     }
2552     else if( pEvent->type == ClientMessage &&
2553              pEvent->xclient.message_type == getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED ) &&
2554              pEvent->xclient.window == GDK_WINDOW_XWINDOW(m_pWindow->window) &&
2555              m_bWindowIsGtkPlug
2556              )
2557     {
2558         // FIXME: this should not be necessary, GtkPlug should do this
2559         // transparently for us
2560         if( pEvent->xclient.data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
2561             pEvent->xclient.data.l[1] == 2    // XEMBED_WINDOW_DEACTIVATE
2562         )
2563         {
2564             GdkEventFocus aEvent;
2565             aEvent.type = GDK_FOCUS_CHANGE;
2566             aEvent.window = m_pWindow->window;
2567             aEvent.send_event = sal_True;
2568             aEvent.in = (pEvent->xclient.data.l[1] == 1);
2569             signalFocus( m_pWindow, &aEvent, this );
2570         }
2571     }
2572 
2573     return bContinueDispatch;
2574 }
2575 
SetBackgroundBitmap(SalBitmap * pBitmap)2576 void GtkSalFrame::SetBackgroundBitmap( SalBitmap* pBitmap )
2577 {
2578     if( m_hBackgroundPixmap )
2579     {
2580         XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
2581                                     GDK_WINDOW_XWINDOW(m_pWindow->window),
2582                                     None );
2583         XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap );
2584         m_hBackgroundPixmap = None;
2585     }
2586     if( pBitmap )
2587     {
2588         X11SalBitmap* pBM = static_cast<X11SalBitmap*>(pBitmap);
2589         Size aSize = pBM->GetSize();
2590         if( aSize.Width() && aSize.Height() )
2591         {
2592             m_hBackgroundPixmap =
2593                 XCreatePixmap( getDisplay()->GetDisplay(),
2594                                GDK_WINDOW_XWINDOW(m_pWindow->window),
2595                                aSize.Width(),
2596                                aSize.Height(),
2597                                getDisplay()->GetVisual(m_nScreen).GetDepth() );
2598             if( m_hBackgroundPixmap )
2599             {
2600                 SalTwoRect aTwoRect;
2601                 aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
2602                 aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width();
2603                 aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height();
2604                 pBM->ImplDraw( m_hBackgroundPixmap,
2605                                m_nScreen,
2606                                getDisplay()->GetVisual(m_nScreen).GetDepth(),
2607                                aTwoRect,
2608                                getDisplay()->GetCopyGC(m_nScreen) );
2609                 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
2610                                             GDK_WINDOW_XWINDOW(m_pWindow->window),
2611                                             m_hBackgroundPixmap );
2612             }
2613         }
2614     }
2615 }
2616 
signalButton(GtkWidget *,GdkEventButton * pEvent,gpointer frame)2617 gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame )
2618 {
2619     GtkSalFrame* pThis = (GtkSalFrame*)frame;
2620     SalMouseEvent aEvent;
2621     sal_uInt16 nEventType = 0;
2622     switch( pEvent->type )
2623     {
2624         case GDK_BUTTON_PRESS:
2625             nEventType = SALEVENT_MOUSEBUTTONDOWN;
2626             break;
2627         case GDK_BUTTON_RELEASE:
2628             nEventType = SALEVENT_MOUSEBUTTONUP;
2629             break;
2630         default:
2631             return sal_False;
2632     }
2633     switch( pEvent->button )
2634     {
2635         case 1: aEvent.mnButton = MOUSE_LEFT;	break;
2636         case 2: aEvent.mnButton = MOUSE_MIDDLE;	break;
2637         case 3: aEvent.mnButton = MOUSE_RIGHT;	break;
2638         default: return sal_False;
2639     }
2640     aEvent.mnTime	= pEvent->time;
2641     aEvent.mnX		= (long)pEvent->x_root - pThis->maGeometry.nX;
2642     aEvent.mnY		= (long)pEvent->y_root - pThis->maGeometry.nY;
2643     aEvent.mnCode	= GetMouseModCode( pEvent->state );
2644 
2645     bool bClosePopups = false;
2646     if( pEvent->type == GDK_BUTTON_PRESS &&
2647         (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) == 0
2648         )
2649     {
2650         if( m_nFloats > 0 )
2651         {
2652             // close popups if user clicks outside our application
2653             gint x, y;
2654             bClosePopups = (gdk_display_get_window_at_pointer( pThis->getGdkDisplay(), &x, &y ) == NULL);
2655         }
2656         /*  #i30306# release implicit pointer grab if no popups are open; else
2657          *  Drag cannot grab the pointer and will fail.
2658          */
2659         if( m_nFloats < 1 || bClosePopups )
2660             gdk_display_pointer_ungrab( pThis->getGdkDisplay(), GDK_CURRENT_TIME );
2661     }
2662 
2663     GTK_YIELD_GRAB();
2664 
2665     if( pThis->m_bWindowIsGtkPlug &&
2666         pEvent->type == GDK_BUTTON_PRESS &&
2667         pEvent->button == 1 )
2668     {
2669         pThis->askForXEmbedFocus( pEvent->time );
2670     }
2671 
2672     // --- RTL --- (mirror mouse pos)
2673     if( Application::GetSettings().GetLayoutRTL() )
2674         aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
2675 
2676 	vcl::DeletionListener aDel( pThis );
2677 
2678     pThis->CallCallback( nEventType, &aEvent );
2679 
2680 	if( ! aDel.isDeleted() )
2681 	{
2682 		if( bClosePopups )
2683 		{
2684 			ImplSVData* pSVData = ImplGetSVData();
2685 			if ( pSVData->maWinData.mpFirstFloat )
2686 			{
2687 				static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
2688 				if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) && !(pEnv && *pEnv) )
2689 					pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
2690 			}
2691 		}
2692 
2693 		if( ! aDel.isDeleted() )
2694 		{
2695 			int frame_x = (int)(pEvent->x_root - pEvent->x);
2696 			int frame_y = (int)(pEvent->y_root - pEvent->y);
2697 			if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
2698 			{
2699 				pThis->maGeometry.nX = frame_x;
2700 				pThis->maGeometry.nY = frame_y;
2701 				pThis->CallCallback( SALEVENT_MOVE, NULL );
2702 			}
2703 		}
2704 	}
2705 
2706     return sal_False;
2707 }
2708 
signalScroll(GtkWidget *,GdkEvent * pEvent,gpointer frame)2709 gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEvent* pEvent, gpointer frame )
2710 {
2711     GtkSalFrame* pThis = (GtkSalFrame*)frame;
2712     GdkEventScroll* pSEvent = (GdkEventScroll*)pEvent;
2713 
2714     static sal_uLong		nLines = 0;
2715     if( ! nLines )
2716     {
2717         char* pEnv = getenv( "SAL_WHEELLINES" );
2718         nLines = pEnv ? atoi( pEnv ) : 3;
2719         if( nLines > 10 )
2720             nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
2721     }
2722 
2723     bool bNeg = (pSEvent->direction == GDK_SCROLL_DOWN || pSEvent->direction == GDK_SCROLL_RIGHT );
2724     SalWheelMouseEvent aEvent;
2725     aEvent.mnTime			= pSEvent->time;
2726     aEvent.mnX				= (sal_uLong)pSEvent->x;
2727     aEvent.mnY				= (sal_uLong)pSEvent->y;
2728     aEvent.mnDelta			= bNeg ? -120 : 120;
2729     aEvent.mnNotchDelta		= bNeg ? -1 : 1;
2730     aEvent.mnScrollLines	= nLines;
2731     aEvent.mnCode			= GetMouseModCode( pSEvent->state );
2732     aEvent.mbHorz			= (pSEvent->direction == GDK_SCROLL_LEFT || pSEvent->direction == GDK_SCROLL_RIGHT);
2733 
2734     GTK_YIELD_GRAB();
2735 
2736     // --- RTL --- (mirror mouse pos)
2737     if( Application::GetSettings().GetLayoutRTL() )
2738         aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
2739 
2740     pThis->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
2741 
2742     return sal_False;
2743 }
2744 
signalMotion(GtkWidget *,GdkEventMotion * pEvent,gpointer frame)2745 gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer frame )
2746 {
2747     GtkSalFrame* pThis = (GtkSalFrame*)frame;
2748 
2749     SalMouseEvent aEvent;
2750     aEvent.mnTime	= pEvent->time;
2751     aEvent.mnX		= (long)pEvent->x_root - pThis->maGeometry.nX;
2752     aEvent.mnY		= (long)pEvent->y_root - pThis->maGeometry.nY;
2753     aEvent.mnCode	= GetMouseModCode( pEvent->state );
2754     aEvent.mnButton	= 0;
2755 
2756 
2757     GTK_YIELD_GRAB();
2758 
2759     // --- RTL --- (mirror mouse pos)
2760     if( Application::GetSettings().GetLayoutRTL() )
2761         aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
2762 
2763 	vcl::DeletionListener aDel( pThis );
2764 
2765     pThis->CallCallback( SALEVENT_MOUSEMOVE, &aEvent );
2766 
2767 	if( ! aDel.isDeleted() )
2768 	{
2769 		int frame_x = (int)(pEvent->x_root - pEvent->x);
2770 		int frame_y = (int)(pEvent->y_root - pEvent->y);
2771 		if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
2772 		{
2773 			pThis->maGeometry.nX = frame_x;
2774 			pThis->maGeometry.nY = frame_y;
2775 			pThis->CallCallback( SALEVENT_MOVE, NULL );
2776 		}
2777 
2778 		if( ! aDel.isDeleted() )
2779 		{
2780 			// ask for the next hint
2781 			gint x, y;
2782 			GdkModifierType mask;
2783 			gdk_window_get_pointer( GTK_WIDGET(pThis->m_pWindow)->window, &x, &y, &mask );
2784 		}
2785 	}
2786 
2787     return sal_True;
2788 }
2789 
signalCrossing(GtkWidget *,GdkEventCrossing * pEvent,gpointer frame)2790 gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpointer frame )
2791 {
2792     GtkSalFrame* pThis = (GtkSalFrame*)frame;
2793     SalMouseEvent aEvent;
2794     aEvent.mnTime	= pEvent->time;
2795     aEvent.mnX		= (long)pEvent->x_root - pThis->maGeometry.nX;
2796     aEvent.mnY		= (long)pEvent->y_root - pThis->maGeometry.nY;
2797     aEvent.mnCode	= GetMouseModCode( pEvent->state );
2798     aEvent.mnButton	= 0;
2799 
2800     GTK_YIELD_GRAB();
2801     pThis->CallCallback( (pEvent->type == GDK_ENTER_NOTIFY) ? SALEVENT_MOUSEMOVE : SALEVENT_MOUSELEAVE, &aEvent );
2802 
2803     return sal_True;
2804 }
2805 
2806 
signalExpose(GtkWidget *,GdkEventExpose * pEvent,gpointer frame)2807 gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer frame )
2808 {
2809     GtkSalFrame* pThis = (GtkSalFrame*)frame;
2810 
2811     struct SalPaintEvent aEvent( pEvent->area.x, pEvent->area.y, pEvent->area.width, pEvent->area.height );
2812 
2813     GTK_YIELD_GRAB();
2814     pThis->CallCallback( SALEVENT_PAINT, &aEvent );
2815 
2816     return sal_False;
2817 }
2818 
signalFocus(GtkWidget *,GdkEventFocus * pEvent,gpointer frame)2819 gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame )
2820 {
2821     GtkSalFrame* pThis = (GtkSalFrame*)frame;
2822 
2823     GTK_YIELD_GRAB();
2824 
2825     // check if printers have changed (analogous to salframe focus handler)
2826     vcl_sal::PrinterUpdate::update();
2827 
2828 	if( !pEvent->in )
2829 	{
2830 		pThis->m_nKeyModifiers = 0;
2831 		pThis->m_bSingleAltPress = false;
2832 		pThis->m_bSendModChangeOnRelease = false;
2833 	}
2834 
2835     if( pThis->m_pIMHandler )
2836         pThis->m_pIMHandler->focusChanged( pEvent->in );
2837 
2838     // ask for changed printers like generic implementation
2839     if( pEvent->in )
2840         if( static_cast< X11SalInstance* >(GetSalData()->m_pInstance)->isPrinterInit() )
2841             vcl_sal::PrinterUpdate::update();
2842 
2843     // FIXME: find out who the hell steals the focus from our frame
2844     // while we have the pointer grabbed, this should not come from
2845     // the window manager. Is this an event that was still queued ?
2846     // The focus does not seem to get set inside our process
2847     //
2848     // in the meantime do not propagate focus get/lose if floats are open
2849     if( m_nFloats == 0 )
2850         pThis->CallCallback( pEvent->in ? SALEVENT_GETFOCUS : SALEVENT_LOSEFOCUS, NULL );
2851 
2852     return sal_False;
2853 }
2854 
IMPL_LINK(GtkSalFrame,ImplDelayedFullScreenHdl,void *,EMPTYARG)2855 IMPL_LINK( GtkSalFrame, ImplDelayedFullScreenHdl, void*, EMPTYARG )
2856 {
2857     Atom nStateAtom = getDisplay()->getWMAdaptor()->getAtom(vcl_sal::WMAdaptor::NET_WM_STATE);
2858     Atom nFSAtom = getDisplay()->getWMAdaptor()->getAtom(vcl_sal::WMAdaptor::NET_WM_STATE_FULLSCREEN );
2859     if( nStateAtom && nFSAtom )
2860     {
2861         /* #i110881# workaround a gtk issue (see https://bugzilla.redhat.com/show_bug.cgi?id=623191#c8)
2862            gtk_window_fullscreen can fail due to a race condition, request an additional status change
2863            to fullscreen to be safe
2864         */
2865         XEvent aEvent;
2866         aEvent.type					= ClientMessage;
2867         aEvent.xclient.display		= getDisplay()->GetDisplay();
2868         aEvent.xclient.window		= GDK_WINDOW_XWINDOW(m_pWindow->window);
2869         aEvent.xclient.message_type	= nStateAtom;
2870         aEvent.xclient.format		= 32;
2871         aEvent.xclient.data.l[0]	= 1;
2872         aEvent.xclient.data.l[1]	= nFSAtom;
2873         aEvent.xclient.data.l[2]	= 0;
2874         aEvent.xclient.data.l[3]	= 0;
2875         aEvent.xclient.data.l[4]	= 0;
2876         XSendEvent( getDisplay()->GetDisplay(),
2877                     getDisplay()->GetRootWindow( m_nScreen ),
2878                     False,
2879                     SubstructureNotifyMask | SubstructureRedirectMask,
2880                     &aEvent
2881                     );
2882     }
2883 
2884     return 0;
2885 }
2886 
signalMap(GtkWidget *,GdkEvent *,gpointer frame)2887 gboolean GtkSalFrame::signalMap( GtkWidget*, GdkEvent*, gpointer frame )
2888 {
2889     GtkSalFrame* pThis = (GtkSalFrame*)frame;
2890 
2891     GTK_YIELD_GRAB();
2892 
2893     if( pThis->m_bFullscreen )
2894     {
2895         /* #i110881# workaorund a gtk issue (see https://bugzilla.redhat.com/show_bug.cgi?id=623191#c8)
2896            gtk_window_fullscreen can run into a race condition with the window's showstate
2897         */
2898         Application::PostUserEvent( LINK( pThis, GtkSalFrame, ImplDelayedFullScreenHdl ) );
2899     }
2900 
2901     bool bSetFocus = pThis->m_bSetFocusOnMap;
2902     pThis->m_bSetFocusOnMap = false;
2903     if( ImplGetSVData()->mbIsTestTool )
2904     {
2905         /* #i76541# testtool needs the focus to be in a new document
2906         *  however e.g. metacity does not necessarily put the focus into
2907         *  a newly shown window. An extra little hint seems to help here.
2908         *  however we don't want to interfere with the normal user experience
2909         *  so this is done when running in testtool only
2910         */
2911         if( ! pThis->m_pParent && (pThis->m_nStyle & SAL_FRAME_STYLE_MOVEABLE) != 0 )
2912             bSetFocus = true;
2913     }
2914 
2915     if( bSetFocus )
2916     {
2917         XSetInputFocus( pThis->getDisplay()->GetDisplay(),
2918                         GDK_WINDOW_XWINDOW( GTK_WIDGET(pThis->m_pWindow)->window),
2919                         RevertToParent, CurrentTime );
2920     }
2921 
2922     pThis->CallCallback( SALEVENT_RESIZE, NULL );
2923 
2924     return sal_False;
2925 }
2926 
signalUnmap(GtkWidget *,GdkEvent *,gpointer frame)2927 gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame )
2928 {
2929     GtkSalFrame* pThis = (GtkSalFrame*)frame;
2930 
2931     GTK_YIELD_GRAB();
2932     pThis->CallCallback( SALEVENT_RESIZE, NULL );
2933 
2934     return sal_False;
2935 }
2936 
signalConfigure(GtkWidget *,GdkEventConfigure * pEvent,gpointer frame)2937 gboolean GtkSalFrame::signalConfigure( GtkWidget*, GdkEventConfigure* pEvent, gpointer frame )
2938 {
2939     GtkSalFrame* pThis = (GtkSalFrame*)frame;
2940 
2941     bool bMoved = false, bSized = false;
2942     int x = pEvent->x, y = pEvent->y;
2943 
2944     /*  HACK: during sizing/moving a toolbar pThis->maGeometry is actually
2945      *  already exact; even worse: due to the asynchronicity of configure
2946      *  events the borderwindow which would evaluate this event
2947      *  would size/move based on wrong data if we would actually evaluate
2948      *  this event. So let's swallow it; this is also a performance
2949      *  improvement as one can omit the synchronous XTranslateCoordinates
2950      *  call below.
2951      */
2952     if( (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
2953         pThis->getDisplay()->GetCaptureFrame() == pThis )
2954         return sal_False;
2955 
2956 
2957     // in child case the coordinates are not root coordinates,
2958     // need to transform
2959 
2960     /* #i31785# sadly one cannot really trust the x,y members of the event;
2961      * they are e.g. not set correctly on maximize/demaximize; this rather
2962      * sounds like a bug in gtk we have to workaround.
2963      */
2964     XLIB_Window aChild;
2965     XTranslateCoordinates( pThis->getDisplay()->GetDisplay(),
2966                            GDK_WINDOW_XWINDOW(GTK_WIDGET(pThis->m_pWindow)->window),
2967                            pThis->getDisplay()->GetRootWindow( pThis->getDisplay()->GetDefaultScreenNumber() ),
2968                            0, 0,
2969                            &x, &y,
2970                            &aChild );
2971 
2972     if( x != pThis->maGeometry.nX || y != pThis->maGeometry.nY )
2973     {
2974         bMoved = true;
2975         pThis->maGeometry.nX		= x;
2976         pThis->maGeometry.nY		= y;
2977     }
2978     /* #i86302#
2979      * for non sizeable windows we set the min and max hint for the window manager to
2980      * achieve correct sizing. However this is asynchronous and e.g. on Compiz
2981      * it sometimes happens that the window gets resized to another size (some default)
2982      * if we update the size here, subsequent setMinMaxSize will use this wrong size
2983      * - which is not good since the window manager will now size the window back to this
2984      * wrong size at some point.
2985      */
2986     if( (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)) == SAL_FRAME_STYLE_SIZEABLE )
2987     {
2988         if( pEvent->width != (int)pThis->maGeometry.nWidth || pEvent->height != (int)pThis->maGeometry.nHeight )
2989         {
2990             bSized = true;
2991             pThis->maGeometry.nWidth	= pEvent->width;
2992             pThis->maGeometry.nHeight	= pEvent->height;
2993         }
2994     }
2995 
2996     // update decoration hints
2997     if( ! (pThis->m_nStyle & SAL_FRAME_STYLE_PLUG) )
2998     {
2999         GdkRectangle aRect;
3000         gdk_window_get_frame_extents( GTK_WIDGET(pThis->m_pWindow)->window, &aRect );
3001         pThis->maGeometry.nTopDecoration	= y - aRect.y;
3002         pThis->maGeometry.nBottomDecoration	= aRect.y + aRect.height - y - pEvent->height;
3003         pThis->maGeometry.nLeftDecoration	= x - aRect.x;
3004         pThis->maGeometry.nRightDecoration	= aRect.x + aRect.width - x - pEvent->width;
3005     }
3006     else
3007     {
3008         pThis->maGeometry.nTopDecoration =
3009             pThis->maGeometry.nBottomDecoration =
3010             pThis->maGeometry.nLeftDecoration =
3011             pThis->maGeometry.nRightDecoration = 0;
3012     }
3013 
3014 	GTK_YIELD_GRAB();
3015     pThis->updateScreenNumber();
3016     if( bMoved && bSized )
3017         pThis->CallCallback( SALEVENT_MOVERESIZE, NULL );
3018     else if( bMoved )
3019         pThis->CallCallback( SALEVENT_MOVE, NULL );
3020     else if( bSized )
3021         pThis->CallCallback( SALEVENT_RESIZE, NULL );
3022 
3023 	return sal_False;
3024 }
3025 
signalKey(GtkWidget *,GdkEventKey * pEvent,gpointer frame)3026 gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame )
3027 {
3028     GtkSalFrame* pThis = (GtkSalFrame*)frame;
3029 
3030 	vcl::DeletionListener aDel( pThis );
3031 
3032     if( pThis->m_pIMHandler )
3033     {
3034         if( pThis->m_pIMHandler->handleKeyEvent( pEvent ) )
3035         {
3036             pThis->m_bSingleAltPress = false;
3037             return sal_True;
3038         }
3039     }
3040     GTK_YIELD_GRAB();
3041 
3042 	// handle modifiers
3043     if( pEvent->keyval == GDK_Shift_L || pEvent->keyval == GDK_Shift_R ||
3044         pEvent->keyval == GDK_Control_L || pEvent->keyval == GDK_Control_R ||
3045         pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ||
3046         pEvent->keyval == GDK_Meta_L || pEvent->keyval == GDK_Meta_R ||
3047         pEvent->keyval == GDK_Super_L || pEvent->keyval == GDK_Super_R )
3048     {
3049 		SalKeyModEvent aModEvt;
3050 
3051 		sal_uInt16 nModCode = GetKeyModCode( pEvent->state );
3052 
3053         aModEvt.mnModKeyCode = 0; // emit no MODKEYCHANGE events
3054         if( pEvent->type == GDK_KEY_PRESS && !pThis->m_nKeyModifiers )
3055 			pThis->m_bSendModChangeOnRelease = true;
3056 
3057         else if( pEvent->type == GDK_KEY_RELEASE &&
3058 				 pThis->m_bSendModChangeOnRelease )
3059         {
3060 			aModEvt.mnModKeyCode = pThis->m_nKeyModifiers;
3061 			pThis->m_nKeyModifiers = 0;
3062         }
3063 
3064         sal_uInt16 nExtModMask = 0;
3065         sal_uInt16 nModMask = 0;
3066 		// pressing just the ctrl key leads to a keysym of XK_Control but
3067 		// the event state does not contain ControlMask. In the release
3068 		// event it's the other way round: it does contain the Control mask.
3069 		// The modifier mode therefore has to be adapted manually.
3070         switch( pEvent->keyval )
3071         {
3072             case GDK_Control_L:
3073                 nExtModMask = MODKEY_LMOD1;
3074                 nModMask = KEY_MOD1;
3075                 break;
3076             case GDK_Control_R:
3077                 nExtModMask = MODKEY_RMOD1;
3078                 nModMask = KEY_MOD1;
3079                 break;
3080             case GDK_Alt_L:
3081                 nExtModMask = MODKEY_LMOD2;
3082                 nModMask = KEY_MOD2;
3083                 break;
3084             case GDK_Alt_R:
3085                 nExtModMask = MODKEY_RMOD2;
3086                 nModMask = KEY_MOD2;
3087                 break;
3088             case GDK_Shift_L:
3089                 nExtModMask = MODKEY_LSHIFT;
3090                 nModMask = KEY_SHIFT;
3091                 break;
3092             case GDK_Shift_R:
3093                 nExtModMask = MODKEY_RSHIFT;
3094                 nModMask = KEY_SHIFT;
3095                 break;
3096             // Map Meta/Super to MOD3 modifier on all Unix systems
3097             // except Mac OS X
3098             case GDK_Meta_L:
3099             case GDK_Super_L:
3100                 nExtModMask = MODKEY_LMOD3;
3101                 nModMask = KEY_MOD3;
3102                 break;
3103             case GDK_Meta_R:
3104             case GDK_Super_R:
3105                 nExtModMask = MODKEY_RMOD3;
3106                 nModMask = KEY_MOD3;
3107                 break;
3108         }
3109         if( pEvent->type == GDK_KEY_RELEASE )
3110         {
3111             nModCode &= ~nModMask;
3112             pThis->m_nKeyModifiers &= ~nExtModMask;
3113         }
3114         else
3115         {
3116             nModCode |= nModMask;
3117             pThis->m_nKeyModifiers |= nExtModMask;
3118         }
3119 
3120 		aModEvt.mnCode = nModCode;
3121 		aModEvt.mnTime = pEvent->time;
3122 
3123 		pThis->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
3124 
3125 		if( ! aDel.isDeleted() )
3126 		{
3127 			// emulate KEY_MENU
3128 			if( ( pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ) &&
3129 				( nModCode & ~(KEY_MOD3|KEY_MOD2)) == 0 )
3130 			{
3131 				if( pEvent->type == GDK_KEY_PRESS )
3132 					pThis->m_bSingleAltPress = true;
3133 
3134 				else if( pThis->m_bSingleAltPress )
3135 				{
3136 					SalKeyEvent aKeyEvt;
3137 
3138 					aKeyEvt.mnCode	   = KEY_MENU | nModCode;
3139 					aKeyEvt.mnRepeat   = 0;
3140 					aKeyEvt.mnTime	   = pEvent->time;
3141 					aKeyEvt.mnCharCode = 0;
3142 
3143 					// simulate KEY_MENU
3144 					pThis->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
3145 					if( ! aDel.isDeleted() )
3146 					{
3147 						pThis->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
3148 						pThis->m_bSingleAltPress = false;
3149 					}
3150 				}
3151 			}
3152 			else
3153 				pThis->m_bSingleAltPress = false;
3154 		}
3155     }
3156     else
3157     {
3158         pThis->doKeyCallback( pEvent->state,
3159                               pEvent->keyval,
3160                               pEvent->hardware_keycode,
3161                               pEvent->group,
3162                               pEvent->time,
3163                               sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )),
3164                               (pEvent->type == GDK_KEY_PRESS),
3165                               false );
3166 		if( ! aDel.isDeleted() )
3167 		{
3168 			pThis->m_bSendModChangeOnRelease = false;
3169 			pThis->m_bSingleAltPress = false;
3170 		}
3171     }
3172 
3173 	if( !aDel.isDeleted() && pThis->m_pIMHandler )
3174 		pThis->m_pIMHandler->updateIMSpotLocation();
3175 
3176     return sal_True;
3177 }
3178 
signalDelete(GtkWidget *,GdkEvent *,gpointer frame)3179 gboolean GtkSalFrame::signalDelete( GtkWidget*, GdkEvent*, gpointer frame )
3180 {
3181     GtkSalFrame* pThis = (GtkSalFrame*)frame;
3182 
3183     GTK_YIELD_GRAB();
3184     pThis->CallCallback( SALEVENT_CLOSE, NULL );
3185 
3186     return sal_True;
3187 }
3188 
signalStyleSet(GtkWidget *,GtkStyle * pPrevious,gpointer frame)3189 void GtkSalFrame::signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer frame )
3190 {
3191     GtkSalFrame* pThis = (GtkSalFrame*)frame;
3192 
3193     // every frame gets an initial style set on creation
3194     // do not post these as the whole application tends to
3195     // redraw itself to adjust to the new style
3196     // where there IS no new style resulting in tremendous unnecessary flickering
3197     if( pPrevious != NULL )
3198     {
3199         // signalStyleSet does NOT usually have the gdk lock
3200         // so post user event to safely dispatch the SALEVENT_SETTINGSCHANGED
3201         // note: settings changed for multiple frames is avoided in winproc.cxx ImplHandleSettings
3202         pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_SETTINGSCHANGED );
3203         pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_FONTCHANGED );
3204     }
3205 
3206     /* #i64117# gtk sets a nice background pixmap
3207     *  but we actually don't really want that, so save
3208     *  some time on the Xserver as well as prevent
3209     *  some paint issues
3210     */
3211     GdkWindow* pWin = GTK_WIDGET(pThis->getWindow())->window;
3212     if( pWin )
3213     {
3214         XLIB_Window aWin = GDK_WINDOW_XWINDOW(pWin);
3215         if( aWin != None )
3216             XSetWindowBackgroundPixmap( pThis->getDisplay()->GetDisplay(),
3217                                         aWin,
3218                                         pThis->m_hBackgroundPixmap );
3219     }
3220 
3221     if( ! pThis->m_pParent )
3222     {
3223         // signalize theme changed for NWF caches
3224         // FIXME: should be called only once for a style change
3225         GtkSalGraphics::bThemeChanged = sal_True;
3226     }
3227 }
3228 
signalState(GtkWidget *,GdkEvent * pEvent,gpointer frame)3229 gboolean GtkSalFrame::signalState( GtkWidget*, GdkEvent* pEvent, gpointer frame )
3230 {
3231     GtkSalFrame* pThis = (GtkSalFrame*)frame;
3232     if( (pThis->m_nState & GDK_WINDOW_STATE_ICONIFIED) != (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED ) )
3233         pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_RESIZE );
3234 
3235     if(   (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) &&
3236         ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) )
3237     {
3238         pThis->m_aRestorePosSize =
3239             Rectangle( Point( pThis->maGeometry.nX, pThis->maGeometry.nY ),
3240                        Size( pThis->maGeometry.nWidth, pThis->maGeometry.nHeight ) );
3241     }
3242     pThis->m_nState = pEvent->window_state.new_window_state;
3243 
3244     #if OSL_DEBUG_LEVEL > 1
3245     if( (pEvent->window_state.changed_mask & GDK_WINDOW_STATE_FULLSCREEN) )
3246     {
3247         fprintf( stderr, "window %p %s full screen state\n",
3248             pThis,
3249             (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_FULLSCREEN) ? "enters" : "leaves");
3250     }
3251     #endif
3252 
3253     return sal_False;
3254 }
3255 
signalVisibility(GtkWidget *,GdkEventVisibility * pEvent,gpointer frame)3256 gboolean GtkSalFrame::signalVisibility( GtkWidget*, GdkEventVisibility* pEvent, gpointer frame )
3257 {
3258     GtkSalFrame* pThis = (GtkSalFrame*)frame;
3259     pThis->m_nVisibility = pEvent->state;
3260 
3261     return sal_False;
3262 }
3263 
signalDestroy(GtkObject * pObj,gpointer frame)3264 void GtkSalFrame::signalDestroy( GtkObject* pObj, gpointer frame )
3265 {
3266     GtkSalFrame* pThis = (GtkSalFrame*)frame;
3267     if( GTK_WIDGET( pObj ) == pThis->m_pWindow )
3268     {
3269         pThis->m_pFixedContainer = NULL;
3270         pThis->m_pWindow = NULL;
3271     }
3272 }
3273 
3274 // ----------------------------------------------------------------------
3275 // GtkSalFrame::IMHandler
3276 // ----------------------------------------------------------------------
3277 
IMHandler(GtkSalFrame * pFrame)3278 GtkSalFrame::IMHandler::IMHandler( GtkSalFrame* pFrame )
3279 : m_pFrame(pFrame),
3280   m_nPrevKeyPresses( 0 ),
3281   m_pIMContext( NULL ),
3282   m_bFocused( true ),
3283   m_bPreeditJustChanged( false )
3284 {
3285     m_aInputEvent.mpTextAttr = NULL;
3286     createIMContext();
3287 }
3288 
~IMHandler()3289 GtkSalFrame::IMHandler::~IMHandler()
3290 {
3291     // cancel an eventual event posted to begin preedit again
3292     m_pFrame->getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3293     deleteIMContext();
3294 }
3295 
createIMContext()3296 void GtkSalFrame::IMHandler::createIMContext()
3297 {
3298     if( ! m_pIMContext )
3299     {
3300         m_pIMContext = gtk_im_multicontext_new ();
3301         g_signal_connect( m_pIMContext, "commit",
3302                           G_CALLBACK (signalIMCommit), this );
3303         g_signal_connect( m_pIMContext, "preedit_changed",
3304                           G_CALLBACK (signalIMPreeditChanged), this );
3305         g_signal_connect( m_pIMContext, "retrieve_surrounding",
3306                           G_CALLBACK (signalIMRetrieveSurrounding), this );
3307         g_signal_connect( m_pIMContext, "delete_surrounding",
3308                           G_CALLBACK (signalIMDeleteSurrounding), this );
3309         g_signal_connect( m_pIMContext, "preedit_start",
3310                           G_CALLBACK (signalIMPreeditStart), this );
3311         g_signal_connect( m_pIMContext, "preedit_end",
3312                           G_CALLBACK (signalIMPreeditEnd), this );
3313 
3314         m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3315         gtk_im_context_set_client_window( m_pIMContext, GTK_WIDGET(m_pFrame->m_pWindow)->window );
3316 		gtk_im_context_focus_in( m_pIMContext );
3317         m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3318         m_bFocused = true;
3319    }
3320 }
3321 
deleteIMContext()3322 void GtkSalFrame::IMHandler::deleteIMContext()
3323 {
3324     if( m_pIMContext )
3325     {
3326         // first give IC a chance to deinitialize
3327         m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3328         gtk_im_context_set_client_window( m_pIMContext, NULL );
3329         m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3330         // destroy old IC
3331         g_object_unref( m_pIMContext );
3332         m_pIMContext = NULL;
3333     }
3334 }
3335 
doCallEndExtTextInput()3336 void GtkSalFrame::IMHandler::doCallEndExtTextInput()
3337 {
3338     m_aInputEvent.mpTextAttr = NULL;
3339     m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
3340 }
3341 
updateIMSpotLocation()3342 void GtkSalFrame::IMHandler::updateIMSpotLocation()
3343 {
3344     SalExtTextInputPosEvent aPosEvent;
3345     m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent );
3346     GdkRectangle aArea;
3347     // Positive aPosEvent.mnExtWidth means ahead of the carret,
3348     // negative value means behind of the carret.
3349     aArea.x = aPosEvent.mnX + (aPosEvent.mnExtWidth < 0 ? aPosEvent.mnExtWidth : 0);
3350     aArea.y = aPosEvent.mnY;
3351     aArea.width = aPosEvent.mnWidth;
3352     aArea.height = aPosEvent.mnHeight;
3353     m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3354     gtk_im_context_set_cursor_location( m_pIMContext, &aArea );
3355     m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3356 }
3357 
setInputContext(SalInputContext *)3358 void GtkSalFrame::IMHandler::setInputContext( SalInputContext* )
3359 {
3360 }
3361 
sendEmptyCommit()3362 void GtkSalFrame::IMHandler::sendEmptyCommit()
3363 {
3364     vcl::DeletionListener aDel( m_pFrame );
3365 
3366     SalExtTextInputEvent aEmptyEv;
3367     aEmptyEv.mnTime 			= 0;
3368     aEmptyEv.mpTextAttr 		= 0;
3369     aEmptyEv.maText 		    = String();
3370     aEmptyEv.mnCursorPos 		= 0;
3371     aEmptyEv.mnCursorFlags 	    = 0;
3372     aEmptyEv.mnDeltaStart 	    = 0;
3373     aEmptyEv.mbOnlyCursor 	    = False;
3374     m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv );
3375     if( ! aDel.isDeleted() )
3376         m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
3377 }
3378 
endExtTextInput(sal_uInt16)3379 void GtkSalFrame::IMHandler::endExtTextInput( sal_uInt16 /*nFlags*/ )
3380 {
3381     gtk_im_context_reset ( m_pIMContext );
3382 
3383     if( m_aInputEvent.mpTextAttr )
3384     {
3385         vcl::DeletionListener aDel( m_pFrame );
3386         // delete preedit in sal (commit an empty string)
3387         sendEmptyCommit();
3388         if( ! aDel.isDeleted() )
3389         {
3390             // mark previous preedit state again (will e.g. be sent at focus gain)
3391             m_aInputEvent.mpTextAttr = &m_aInputFlags[0];
3392             if( m_bFocused )
3393             {
3394                 // begin preedit again
3395                 m_pFrame->getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3396             }
3397         }
3398     }
3399 }
3400 
focusChanged(bool bFocusIn)3401 void GtkSalFrame::IMHandler::focusChanged( bool bFocusIn )
3402 {
3403     m_bFocused = bFocusIn;
3404     if( bFocusIn )
3405     {
3406         m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3407         gtk_im_context_focus_in( m_pIMContext );
3408         m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3409         if( m_aInputEvent.mpTextAttr )
3410         {
3411             sendEmptyCommit();
3412             // begin preedit again
3413             m_pFrame->getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3414         }
3415     }
3416     else
3417     {
3418         m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3419         gtk_im_context_focus_out( m_pIMContext );
3420         m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3421         // cancel an eventual event posted to begin preedit again
3422         m_pFrame->getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3423     }
3424 }
3425 
handleKeyEvent(GdkEventKey * pEvent)3426 bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent )
3427 {
3428 	vcl::DeletionListener aDel( m_pFrame );
3429 
3430     if( pEvent->type == GDK_KEY_PRESS )
3431     {
3432         // Add this key press event to the list of previous key presses
3433         // to which we compare key release events. If a later key release
3434         // event has a matching key press event in this list, we swallow
3435         // the key release because some GTK Input Methods don't swallow it
3436         // for us.
3437         m_aPrevKeyPresses.push_back( PreviousKeyPress(pEvent) );
3438         m_nPrevKeyPresses++;
3439 
3440         // Also pop off the earliest key press event if there are more than 10
3441         // already.
3442         while (m_nPrevKeyPresses > 10)
3443         {
3444             m_aPrevKeyPresses.pop_front();
3445             m_nPrevKeyPresses--;
3446         }
3447 
3448         GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
3449 
3450         // #i51353# update spot location on every key input since we cannot
3451         // know which key may activate a preedit choice window
3452         updateIMSpotLocation();
3453         if( aDel.isDeleted() )
3454             return true;
3455 
3456         gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
3457         g_object_unref( pRef );
3458 
3459         if( aDel.isDeleted() )
3460             return true;
3461 
3462         m_bPreeditJustChanged = false;
3463 
3464         if( bResult )
3465             return true;
3466         else
3467         {
3468             DBG_ASSERT( m_nPrevKeyPresses > 0, "key press has vanished !" );
3469             if( ! m_aPrevKeyPresses.empty() ) // sanity check
3470             {
3471                 // event was not swallowed, do not filter a following
3472                 // key release event
3473                 // note: this relies on gtk_im_context_filter_keypress
3474                 // returning without calling a handler (in the "not swallowed"
3475                 // case ) which might change the previous key press list so
3476                 // we would pop the wrong event here
3477                 m_aPrevKeyPresses.pop_back();
3478                 m_nPrevKeyPresses--;
3479             }
3480         }
3481     }
3482 
3483     // Determine if we got an earlier key press event corresponding to this key release
3484     if (pEvent->type == GDK_KEY_RELEASE)
3485     {
3486         GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
3487         gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
3488         g_object_unref( pRef );
3489 
3490         if( aDel.isDeleted() )
3491             return true;
3492 
3493         m_bPreeditJustChanged = false;
3494 
3495         std::list<PreviousKeyPress>::iterator    iter     = m_aPrevKeyPresses.begin();
3496         std::list<PreviousKeyPress>::iterator    iter_end = m_aPrevKeyPresses.end();
3497         while (iter != iter_end)
3498         {
3499             // If we found a corresponding previous key press event, swallow the release
3500             // and remove the earlier key press from our list
3501             if (*iter == pEvent)
3502             {
3503                 m_aPrevKeyPresses.erase(iter);
3504                 m_nPrevKeyPresses--;
3505                 return true;
3506             }
3507             ++iter;
3508         }
3509 
3510         if( bResult )
3511             return true;
3512     }
3513 
3514     return false;
3515 }
3516 
3517 /* FIXME:
3518 * #122282# still more hacking: some IMEs never start a preedit but simply commit
3519 * in this case we cannot commit a single character. Workaround: do not do the
3520 * single key hack for enter or space if the unicode committed does not match
3521 */
3522 
checkSingleKeyCommitHack(guint keyval,sal_Unicode cCode)3523 static bool checkSingleKeyCommitHack( guint keyval, sal_Unicode cCode )
3524 {
3525     bool bRet = true;
3526     switch( keyval )
3527     {
3528         case GDK_KP_Enter:
3529         case GDK_Return:
3530             if( cCode != '\n' && cCode != '\r' )
3531                 bRet = false;
3532             break;
3533         case GDK_space:
3534         case GDK_KP_Space:
3535             if( cCode != ' ' )
3536                 bRet = false;
3537             break;
3538         default:
3539             break;
3540     }
3541     return bRet;
3542 }
3543 
3544 #ifdef SOLARIS
3545 #define CONTEXT_ARG pContext
3546 #else
3547 #define CONTEXT_ARG EMPTYARG
3548 #endif
signalIMCommit(GtkIMContext * CONTEXT_ARG,gchar * pText,gpointer im_handler)3549 void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* CONTEXT_ARG, gchar* pText, gpointer im_handler )
3550 {
3551     GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
3552 
3553     vcl::DeletionListener aDel( pThis->m_pFrame );
3554     // open a block that will end the GTK_YIELD_GRAB before calling preedit changed again
3555     {
3556         GTK_YIELD_GRAB();
3557 
3558         bool bWasPreedit =
3559             (pThis->m_aInputEvent.mpTextAttr != 0) ||
3560             pThis->m_bPreeditJustChanged;
3561         pThis->m_bPreeditJustChanged = false;
3562 
3563         pThis->m_aInputEvent.mnTime 			= 0;
3564         pThis->m_aInputEvent.mpTextAttr 		= 0;
3565         pThis->m_aInputEvent.maText 		    = String( pText, RTL_TEXTENCODING_UTF8 );
3566         pThis->m_aInputEvent.mnCursorPos 		= pThis->m_aInputEvent.maText.Len();
3567         pThis->m_aInputEvent.mnCursorFlags 	    = 0;
3568         pThis->m_aInputEvent.mnDeltaStart 	    = 0;
3569         pThis->m_aInputEvent.mbOnlyCursor 	    = False;
3570 
3571         pThis->m_aInputFlags.clear();
3572 
3573         /* necessary HACK: all keyboard input comes in here as soon as a IMContext is set
3574          *  which is logical and consequent. But since even simple input like
3575          *  <space> comes through the commit signal instead of signalKey
3576          *  and all kinds of windows only implement KeyInput (e.g. PushButtons,
3577          *  RadioButtons and a lot of other Controls), will send a single
3578          *  KeyInput/KeyUp sequence instead of an ExtText event if there
3579          *  never was a preedit and the text is only one character.
3580          *
3581          *  In this case there the last ExtText event must have been
3582          *  SALEVENT_ENDEXTTEXTINPUT, either because of a regular commit
3583          *  or because there never was a preedit.
3584          */
3585         bool bSingleCommit = false;
3586 
3587         if( ! bWasPreedit
3588             && pThis->m_aInputEvent.maText.Len() == 1
3589             && ! pThis->m_aPrevKeyPresses.empty()
3590             )
3591         {
3592             const PreviousKeyPress& rKP = pThis->m_aPrevKeyPresses.back();
3593             sal_Unicode aOrigCode = pThis->m_aInputEvent.maText.GetChar(0);
3594 
3595             if( checkSingleKeyCommitHack( rKP.keyval, aOrigCode ) )
3596             {
3597                 pThis->m_pFrame->doKeyCallback( rKP.state, rKP.keyval, rKP.hardware_keycode, rKP.group, rKP.time, aOrigCode, true, true );
3598                 bSingleCommit = true;
3599             }
3600         }
3601         if( ! bSingleCommit )
3602         {
3603             pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
3604             if( ! aDel.isDeleted() )
3605                 pThis->doCallEndExtTextInput();
3606         }
3607         if( ! aDel.isDeleted() )
3608         {
3609             // reset input event
3610             pThis->m_aInputEvent.maText = String();
3611             pThis->m_aInputEvent.mnCursorPos = 0;
3612             pThis->updateIMSpotLocation();
3613         }
3614     }
3615     #ifdef SOLARIS
3616     // #i51356# workaround a solaris IIIMP bug
3617     // in case of partial commits the preedit changed signal
3618     // and commit signal come in wrong order
3619     if( ! aDel.isDeleted() )
3620         signalIMPreeditChanged( pContext, im_handler );
3621     #endif
3622 }
3623 
signalIMPreeditChanged(GtkIMContext *,gpointer im_handler)3624 void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext*, gpointer im_handler )
3625 {
3626     GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
3627 
3628     char*			pText			= NULL;
3629     PangoAttrList*	pAttrs		    = NULL;
3630     gint			nCursorPos		= 0;
3631 
3632     gtk_im_context_get_preedit_string( pThis->m_pIMContext,
3633                                        &pText,
3634                                        &pAttrs,
3635                                        &nCursorPos );
3636     if( pText && ! *pText ) // empty string
3637     {
3638         // change from nothing to nothing -> do not start preedit
3639         // e.g. this will activate input into a calc cell without
3640         // user input
3641         if( pThis->m_aInputEvent.maText.Len() == 0 )
3642         {
3643             g_free( pText );
3644             return;
3645         }
3646     }
3647 
3648     pThis->m_bPreeditJustChanged = true;
3649 
3650 	bool bEndPreedit = (!pText || !*pText) && pThis->m_aInputEvent.mpTextAttr != NULL;
3651     pThis->m_aInputEvent.mnTime 			= 0;
3652     pThis->m_aInputEvent.maText 			= String( pText, RTL_TEXTENCODING_UTF8 );
3653     pThis->m_aInputEvent.mnCursorPos 		= nCursorPos;
3654     pThis->m_aInputEvent.mnCursorFlags      = 0;
3655     pThis->m_aInputEvent.mnDeltaStart       = 0;
3656     pThis->m_aInputEvent.mbOnlyCursor       = False;
3657 
3658     pThis->m_aInputFlags = std::vector<sal_uInt16>( std::max( 1, (int)pThis->m_aInputEvent.maText.Len() ), 0 );
3659 
3660     PangoAttrIterator   *iter       = pango_attr_list_get_iterator (pAttrs);
3661     do
3662     {
3663         GSList *attr_list = NULL;
3664         GSList *tmp_list = NULL;
3665         gint start, end;
3666         guint sal_attr = 0;
3667 
3668         pango_attr_iterator_range (iter, &start, &end);
3669         if (end == G_MAXINT)
3670             end = pText ? strlen (pText) : 0;
3671         if (end == start)
3672             continue;
3673 
3674         start = g_utf8_pointer_to_offset (pText, pText + start);
3675         end = g_utf8_pointer_to_offset (pText, pText + end);
3676 
3677         tmp_list = attr_list = pango_attr_iterator_get_attrs (iter);
3678         while (tmp_list)
3679         {
3680             PangoAttribute *pango_attr = (PangoAttribute *)(tmp_list->data);
3681 
3682             switch (pango_attr->klass->type)
3683             {
3684                 case PANGO_ATTR_BACKGROUND:
3685                     sal_attr |= (SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT | SAL_EXTTEXTINPUT_CURSOR_INVISIBLE);
3686                     break;
3687                 case PANGO_ATTR_UNDERLINE:
3688                     sal_attr |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
3689                     break;
3690                 case PANGO_ATTR_STRIKETHROUGH:
3691                     sal_attr |= SAL_EXTTEXTINPUT_ATTR_REDTEXT;
3692                     break;
3693                 default:
3694                     break;
3695             }
3696             pango_attribute_destroy (pango_attr);
3697             tmp_list = tmp_list->next;
3698         }
3699         if (sal_attr == 0)
3700             sal_attr |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
3701         g_slist_free (attr_list);
3702 
3703         // Set the sal attributes on our text
3704         for (int i = start; i < end; i++)
3705             pThis->m_aInputFlags[i] |= sal_attr;
3706     } while (pango_attr_iterator_next (iter));
3707 
3708     pThis->m_aInputEvent.mpTextAttr 		= &pThis->m_aInputFlags[0];
3709 
3710     g_free( pText );
3711     pango_attr_list_unref( pAttrs );
3712 
3713     GTK_YIELD_GRAB();
3714 
3715     vcl::DeletionListener aDel( pThis->m_pFrame );
3716 
3717     pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
3718 	if( bEndPreedit && ! aDel.isDeleted() )
3719         pThis->doCallEndExtTextInput();
3720     if( ! aDel.isDeleted() )
3721         pThis->updateIMSpotLocation();
3722 }
3723 
signalIMPreeditStart(GtkIMContext *,gpointer)3724 void GtkSalFrame::IMHandler::signalIMPreeditStart( GtkIMContext*, gpointer /*im_handler*/ )
3725 {
3726 }
3727 
signalIMPreeditEnd(GtkIMContext *,gpointer im_handler)3728 void GtkSalFrame::IMHandler::signalIMPreeditEnd( GtkIMContext*, gpointer im_handler )
3729 {
3730     GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
3731     GTK_YIELD_GRAB();
3732 
3733     pThis->m_bPreeditJustChanged = true;
3734 
3735     vcl::DeletionListener aDel( pThis->m_pFrame );
3736     pThis->doCallEndExtTextInput();
3737     if( ! aDel.isDeleted() )
3738         pThis->updateIMSpotLocation();
3739 }
3740 
3741 uno::Reference<accessibility::XAccessibleEditableText>
FindFocus(uno::Reference<accessibility::XAccessibleContext> xContext)3742 	FindFocus(uno::Reference< accessibility::XAccessibleContext > xContext)
3743 {
3744     if (!xContext.is())
3745         uno::Reference< accessibility::XAccessibleEditableText >();
3746 
3747 	uno::Reference<accessibility::XAccessibleStateSet> xState = xContext->getAccessibleStateSet();
3748 	if (xState.is())
3749 	{
3750 		if (xState->contains(accessibility::AccessibleStateType::FOCUSED))
3751 			return uno::Reference<accessibility::XAccessibleEditableText>(xContext, uno::UNO_QUERY);
3752 	}
3753 
3754     try
3755     {
3756         for (sal_Int32 i = 0, n = xContext->getAccessibleChildCount(); i < n; ++i)
3757         {
3758             uno::Reference< accessibility::XAccessible > xChild = xContext->getAccessibleChild(i);
3759             if (!xChild.is())
3760                 continue;
3761                 uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext();
3762             if (!xChildContext.is())
3763                 continue;
3764             uno::Reference< accessibility::XAccessibleEditableText > xText = FindFocus(xChildContext);
3765             if (xText.is())
3766                 return xText;
3767         }
3768     }
3769     catch( lang::IndexOutOfBoundsException & e )
3770     {
3771         OSL_TRACE( "GtkFrame FindFocus, %s", ::rtl::OUStringToOString(
3772                 e.Message, RTL_TEXTENCODING_UTF8 ).pData->buffer );
3773     }
3774 	return uno::Reference< accessibility::XAccessibleEditableText >();
3775 }
3776 
lcl_GetxText()3777 uno::Reference<accessibility::XAccessibleEditableText> lcl_GetxText()
3778 {
3779     uno::Reference<accessibility::XAccessibleEditableText> xText;
3780     Window* pFocusWin = ImplGetSVData()->maWinData.mpFocusWin;
3781     if (!pFocusWin)
3782 	return xText;
3783 
3784     uno::Reference< accessibility::XAccessible > xAccessible( pFocusWin->GetAccessible( true ) );
3785     if (xAccessible.is())
3786         xText = FindFocus(xAccessible->getAccessibleContext());
3787     return xText;
3788 }
3789 
signalIMRetrieveSurrounding(GtkIMContext * pContext,gpointer)3790 gboolean GtkSalFrame::IMHandler::signalIMRetrieveSurrounding( GtkIMContext* pContext, gpointer /*im_handler*/ )
3791 {
3792     uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText();
3793 
3794     if (xText.is())
3795     {
3796         sal_uInt32 nPosition = xText->getCaretPosition();
3797         rtl::OUString sAllText = xText->getText();
3798 		if (!sAllText.getLength())
3799             return sal_False;
3800 	rtl::OString sUTF = rtl::OUStringToOString(sAllText, RTL_TEXTENCODING_UTF8);
3801 	rtl::OUString sCursorText( sAllText.getStr(), nPosition);
3802 	gtk_im_context_set_surrounding(pContext, sUTF.getStr(), sUTF.getLength(),
3803 		rtl::OUStringToOString(sCursorText, RTL_TEXTENCODING_UTF8).getLength());
3804 	return sal_True;
3805     }
3806 
3807     return sal_False;
3808 }
3809 
signalIMDeleteSurrounding(GtkIMContext *,gint offset,gint nchars,gpointer)3810 gboolean GtkSalFrame::IMHandler::signalIMDeleteSurrounding( GtkIMContext*, gint offset, gint nchars,
3811     gpointer /*im_handler*/ )
3812 {
3813     uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText();
3814 
3815     if (xText.is())
3816     {
3817         sal_uInt32 nPosition = xText->getCaretPosition();
3818         // --> OD 2010-06-04 #i111768# - apply patch from kstribley:
3819         // range checking
3820 //        xText->deleteText(nPosition + offset, nPosition + offset + nchars);
3821         sal_Int32 nDeletePos = nPosition + offset;
3822         sal_Int32 nDeleteEnd = nDeletePos + nchars;
3823         if (nDeletePos < 0)
3824             nDeletePos = 0;
3825         if (nDeleteEnd < 0)
3826             nDeleteEnd = 0;
3827         if (nDeleteEnd > xText->getCharacterCount())
3828             nDeleteEnd = xText->getCharacterCount();
3829 
3830         xText->deleteText(nDeletePos, nDeleteEnd);
3831         // <--
3832         return sal_True;
3833     }
3834 
3835     return sal_False;
3836 }
3837