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