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