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