update ooo310-m15
[ooovba.git] / vcl / unx / gtk / window / gtkframe.cxx
blobdbb3debc32010481e5a6394fc0d1681e60bbb040
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: gtkframe.cxx,v $
10 * $Revision: 1.84.36.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include <plugins/gtk/gtkframe.hxx>
35 #include <plugins/gtk/gtkdata.hxx>
36 #include <plugins/gtk/gtkinst.hxx>
37 #include <plugins/gtk/gtkgdi.hxx>
38 #include <vcl/keycodes.hxx>
39 #include <wmadaptor.hxx>
40 #include <sm.hxx>
41 #include <salbmp.h>
42 #include <salprn.h>
43 #include <vcl/floatwin.hxx>
44 #include <salprn.h>
45 #include <vcl/svapp.hxx>
46 #include <vcl/window.hxx>
48 #include <prex.h>
49 #include <X11/Xatom.h>
50 #include <postx.h>
52 #include <dlfcn.h>
53 #include <vcl/salbtype.hxx>
54 #include <vcl/bitmapex.hxx>
55 #include <vcl/impbmp.hxx>
56 #include <vcl/svids.hrc>
58 #include <algorithm>
60 #if OSL_DEBUG_LEVEL > 1
61 #include <cstdio>
62 #endif
64 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
65 #include <com/sun/star/accessibility/AccessibleRole.hpp>
66 #include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
67 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
68 #include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
70 #ifdef ENABLE_DBUS
71 #include <dbus/dbus-glib.h>
73 #define GSS_DBUS_SERVICE "org.gnome.ScreenSaver"
74 #define GSS_DBUS_PATH "/org/gnome/ScreenSaver"
75 #define GSS_DBUS_INTERFACE "org.gnome.ScreenSaver"
76 #endif
78 using namespace com::sun::star;
80 int GtkSalFrame::m_nFloats = 0;
82 static USHORT GetKeyModCode( guint state )
84 USHORT nCode = 0;
85 if( (state & GDK_SHIFT_MASK) )
86 nCode |= KEY_SHIFT;
87 if( (state & GDK_CONTROL_MASK)
88 #ifdef MACOSX
89 || (state & GDK_MOD2_MASK) // map Meta (aka Command key) to Ctrl
90 #endif
92 nCode |= KEY_MOD1;
93 if( (state & GDK_MOD1_MASK) )
95 nCode |= KEY_MOD2;
96 #ifdef MACOSX
97 if( ! (nCode & KEY_MOD1) )
98 nCode |= KEY_MOD3;
99 #endif
101 return nCode;
104 static USHORT GetMouseModCode( guint state )
106 USHORT nCode = GetKeyModCode( state );
107 if( (state & GDK_BUTTON1_MASK) )
108 nCode |= MOUSE_LEFT;
109 if( (state & GDK_BUTTON2_MASK) )
110 nCode |= MOUSE_MIDDLE;
111 if( (state & GDK_BUTTON3_MASK) )
112 nCode |= MOUSE_RIGHT;
114 return nCode;
117 static USHORT GetKeyCode( guint keyval )
119 USHORT nCode = 0;
120 if( keyval >= GDK_0 && keyval <= GDK_9 )
121 nCode = KEY_0 + (keyval-GDK_0);
122 else if( keyval >= GDK_KP_0 && keyval <= GDK_KP_9 )
123 nCode = KEY_0 + (keyval-GDK_KP_0);
124 else if( keyval >= GDK_A && keyval <= GDK_Z )
125 nCode = KEY_A + (keyval-GDK_A );
126 else if( keyval >= GDK_a && keyval <= GDK_z )
127 nCode = KEY_A + (keyval-GDK_a );
128 else if( keyval >= GDK_F1 && keyval <= GDK_F26 )
130 if( GetX11SalData()->GetDisplay()->IsNumLockFromXS() )
132 nCode = KEY_F1 + (keyval-GDK_F1);
134 else
136 switch( keyval )
138 // - - - - - Sun keyboard, see vcl/unx/source/app/saldisp.cxx
139 case GDK_L2:
140 if( GetX11SalData()->GetDisplay()->GetServerVendor() == vendor_sun )
141 nCode = KEY_REPEAT;
142 else
143 nCode = KEY_F12;
144 break;
145 case GDK_L3: nCode = KEY_PROPERTIES; break;
146 case GDK_L4: nCode = KEY_UNDO; break;
147 case GDK_L6: nCode = KEY_COPY; break; // KEY_F16
148 case GDK_L8: nCode = KEY_PASTE; break; // KEY_F18
149 case GDK_L10: nCode = KEY_CUT; break; // KEY_F20
150 default:
151 nCode = KEY_F1 + (keyval-GDK_F1); break;
155 else
157 switch( keyval )
159 case GDK_KP_Down:
160 case GDK_Down: nCode = KEY_DOWN; break;
161 case GDK_KP_Up:
162 case GDK_Up: nCode = KEY_UP; break;
163 case GDK_KP_Left:
164 case GDK_Left: nCode = KEY_LEFT; break;
165 case GDK_KP_Right:
166 case GDK_Right: nCode = KEY_RIGHT; break;
167 case GDK_KP_Begin:
168 case GDK_KP_Home:
169 case GDK_Begin:
170 case GDK_Home: nCode = KEY_HOME; break;
171 case GDK_KP_End:
172 case GDK_End: nCode = KEY_END; break;
173 case GDK_KP_Page_Up:
174 case GDK_Page_Up: nCode = KEY_PAGEUP; break;
175 case GDK_KP_Page_Down:
176 case GDK_Page_Down: nCode = KEY_PAGEDOWN; break;
177 case GDK_KP_Enter:
178 case GDK_Return: nCode = KEY_RETURN; break;
179 case GDK_Escape: nCode = KEY_ESCAPE; break;
180 case GDK_ISO_Left_Tab:
181 case GDK_KP_Tab:
182 case GDK_Tab: nCode = KEY_TAB; break;
183 case GDK_BackSpace: nCode = KEY_BACKSPACE; break;
184 case GDK_KP_Space:
185 case GDK_space: nCode = KEY_SPACE; break;
186 case GDK_KP_Insert:
187 case GDK_Insert: nCode = KEY_INSERT; break;
188 case GDK_KP_Delete:
189 case GDK_Delete: nCode = KEY_DELETE; break;
190 case GDK_plus:
191 case GDK_KP_Add: nCode = KEY_ADD; break;
192 case GDK_minus:
193 case GDK_KP_Subtract: nCode = KEY_SUBTRACT; break;
194 case GDK_asterisk:
195 case GDK_KP_Multiply: nCode = KEY_MULTIPLY; break;
196 case GDK_slash:
197 case GDK_KP_Divide: nCode = KEY_DIVIDE; break;
198 case GDK_period:
199 case GDK_decimalpoint: nCode = KEY_POINT; break;
200 case GDK_comma: nCode = KEY_COMMA; break;
201 case GDK_less: nCode = KEY_LESS; break;
202 case GDK_greater: nCode = KEY_GREATER; break;
203 case GDK_KP_Equal:
204 case GDK_equal: nCode = KEY_EQUAL; break;
205 case GDK_Find: nCode = KEY_FIND; break;
206 case GDK_Menu: nCode = KEY_CONTEXTMENU;break;
207 case GDK_Help: nCode = KEY_HELP; break;
208 case GDK_Undo: nCode = KEY_UNDO; break;
209 case GDK_Redo: nCode = KEY_REPEAT; break;
210 case GDK_KP_Decimal:
211 case GDK_KP_Separator: nCode = KEY_DECIMAL; break;
212 case GDK_asciitilde: nCode = KEY_TILDE; break;
213 case GDK_leftsinglequotemark:
214 case GDK_quoteleft: nCode = KEY_QUOTELEFT; break;
215 case GDK_bracketleft: nCode = KEY_BRACKETLEFT; break;
216 case GDK_bracketright: nCode = KEY_BRACKETRIGHT; break;
217 // some special cases, also see saldisp.cxx
218 // - - - - - - - - - - - - - Apollo - - - - - - - - - - - - - 0x1000
219 case 0x1000FF02: // apXK_Copy
220 nCode = KEY_COPY;
221 break;
222 case 0x1000FF03: // apXK_Cut
223 nCode = KEY_CUT;
224 break;
225 case 0x1000FF04: // apXK_Paste
226 nCode = KEY_PASTE;
227 break;
228 case 0x1000FF14: // apXK_Repeat
229 nCode = KEY_REPEAT;
230 break;
231 // Exit, Save
232 // - - - - - - - - - - - - - - D E C - - - - - - - - - - - - - 0x1000
233 case 0x1000FF00:
234 nCode = KEY_DELETE;
235 break;
236 // - - - - - - - - - - - - - - H P - - - - - - - - - - - - - 0x1000
237 case 0x1000FF73: // hpXK_DeleteChar
238 nCode = KEY_DELETE;
239 break;
240 case 0x1000FF74: // hpXK_BackTab
241 case 0x1000FF75: // hpXK_KP_BackTab
242 nCode = KEY_TAB;
243 break;
244 // - - - - - - - - - - - - - - I B M - - - - - - - - - - - - -
245 // - - - - - - - - - - - - - - O S F - - - - - - - - - - - - - 0x1004
246 case 0x1004FF02: // osfXK_Copy
247 nCode = KEY_COPY;
248 break;
249 case 0x1004FF03: // osfXK_Cut
250 nCode = KEY_CUT;
251 break;
252 case 0x1004FF04: // osfXK_Paste
253 nCode = KEY_PASTE;
254 break;
255 case 0x1004FF07: // osfXK_BackTab
256 nCode = KEY_TAB;
257 break;
258 case 0x1004FF08: // osfXK_BackSpace
259 nCode = KEY_BACKSPACE;
260 break;
261 case 0x1004FF1B: // osfXK_Escape
262 nCode = KEY_ESCAPE;
263 break;
264 // Up, Down, Left, Right, PageUp, PageDown
265 // - - - - - - - - - - - - - - S C O - - - - - - - - - - - - -
266 // - - - - - - - - - - - - - - S G I - - - - - - - - - - - - - 0x1007
267 // - - - - - - - - - - - - - - S N I - - - - - - - - - - - - -
268 // - - - - - - - - - - - - - - S U N - - - - - - - - - - - - - 0x1005
269 case 0x1005FF10: // SunXK_F36
270 nCode = KEY_F11;
271 break;
272 case 0x1005FF11: // SunXK_F37
273 nCode = KEY_F12;
274 break;
275 case 0x1005FF70: // SunXK_Props
276 nCode = KEY_PROPERTIES;
277 break;
278 case 0x1005FF71: // SunXK_Front
279 nCode = KEY_FRONT;
280 break;
281 case 0x1005FF72: // SunXK_Copy
282 nCode = KEY_COPY;
283 break;
284 case 0x1005FF73: // SunXK_Open
285 nCode = KEY_OPEN;
286 break;
287 case 0x1005FF74: // SunXK_Paste
288 nCode = KEY_PASTE;
289 break;
290 case 0x1005FF75: // SunXK_Cut
291 nCode = KEY_CUT;
292 break;
296 return nCode;
299 // F10 means either KEY_F10 or KEY_MENU, which has to be decided
300 // in the independent part.
301 struct KeyAlternate
303 USHORT nKeyCode;
304 sal_Unicode nCharCode;
305 KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
306 KeyAlternate( USHORT nKey, sal_Unicode nChar = 0 ) : nKeyCode( nKey ), nCharCode( nChar ) {}
309 inline KeyAlternate
310 GetAlternateKeyCode( const USHORT nKeyCode )
312 KeyAlternate aAlternate;
314 switch( nKeyCode )
316 case KEY_F10: aAlternate = KeyAlternate( KEY_MENU );break;
317 case KEY_F24: aAlternate = KeyAlternate( KEY_SUBTRACT, '-' );break;
320 return aAlternate;
323 void GtkSalFrame::doKeyCallback( guint state,
324 guint keyval,
325 guint16 hardware_keycode,
326 guint8 /*group*/,
327 guint32 time,
328 sal_Unicode aOrigCode,
329 bool bDown,
330 bool bSendRelease
333 SalKeyEvent aEvent;
335 aEvent.mnTime = time;
336 aEvent.mnCharCode = aOrigCode;
337 aEvent.mnRepeat = 0;
339 vcl::DeletionListener aDel( this );
340 /* #i42122# translate all keys with Ctrl and/or Alt to group 0
341 * else shortcuts (e.g. Ctrl-o) will not work but be inserted by
342 * the application
344 /* #i52338# do this for all keys that the independent part has no key code for
346 aEvent.mnCode = GetKeyCode( keyval );
347 if( aEvent.mnCode == 0 )
349 // check other mapping
350 gint eff_group, level;
351 GdkModifierType consumed;
352 guint updated_keyval = 0;
353 // use gdk_keymap_get_default instead of NULL;
354 // workaround a crahs fixed in gtk 2.4
355 if( gdk_keymap_translate_keyboard_state( gdk_keymap_get_default(),
356 hardware_keycode,
357 (GdkModifierType)0,
359 &updated_keyval,
360 &eff_group,
361 &level,
362 &consumed ) )
364 aEvent.mnCode = GetKeyCode( updated_keyval );
367 aEvent.mnCode |= GetKeyModCode( state );
369 if( bDown )
371 bool bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
372 // #i46889# copy AlternatKeyCode handling from generic plugin
373 if( ! bHandled )
375 KeyAlternate aAlternate = GetAlternateKeyCode( aEvent.mnCode );
376 if( aAlternate.nKeyCode )
378 aEvent.mnCode = aAlternate.nKeyCode;
379 if( aAlternate.nCharCode )
380 aEvent.mnCharCode = aAlternate.nCharCode;
381 bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
384 if( bSendRelease && ! aDel.isDeleted() )
386 CallCallback( SALEVENT_KEYUP, &aEvent );
389 else
390 CallCallback( SALEVENT_KEYUP, &aEvent );
393 GtkSalFrame::GraphicsHolder::~GraphicsHolder()
395 delete pGraphics;
398 GtkSalFrame::GtkSalFrame( SalFrame* pParent, ULONG nStyle )
400 m_nScreen = getDisplay()->GetDefaultScreenNumber();
401 getDisplay()->registerFrame( this );
402 m_bDefaultPos = true;
403 m_bDefaultSize = ( (nStyle & SAL_FRAME_STYLE_SIZEABLE) && ! pParent );
404 m_bWindowIsGtkPlug = false;
405 Init( pParent, nStyle );
408 GtkSalFrame::GtkSalFrame( SystemParentData* pSysData )
410 m_nScreen = getDisplay()->GetDefaultScreenNumber();
411 getDisplay()->registerFrame( this );
412 getDisplay()->setHaveSystemChildFrame();
413 m_bDefaultPos = true;
414 m_bDefaultSize = true;
415 Init( pSysData );
418 GtkSalFrame::~GtkSalFrame()
420 if( m_pParent )
421 m_pParent->m_aChildren.remove( this );
423 getDisplay()->deregisterFrame( this );
425 if( m_pRegion )
426 gdk_region_destroy( m_pRegion );
428 if( m_hBackgroundPixmap )
430 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
431 GDK_WINDOW_XWINDOW(m_pWindow->window),
432 None );
433 XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap );
436 if( m_pIMHandler )
437 delete m_pIMHandler;
439 if( m_pFixedContainer )
440 gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer) );
441 if( m_pWindow )
443 g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", NULL );
444 gtk_widget_destroy( m_pWindow );
446 if( m_pForeignParent )
447 g_object_unref( G_OBJECT(m_pForeignParent) );
448 if( m_pForeignTopLevel )
449 g_object_unref(G_OBJECT( m_pForeignTopLevel) );
452 void GtkSalFrame::moveWindow( long nX, long nY )
454 if( isChild( false, true ) )
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 );
461 else
462 gtk_window_move( GTK_WINDOW(m_pWindow), nX, nY );
465 void GtkSalFrame::resizeWindow( long nWidth, long nHeight )
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 );
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 ..
479 GType
480 ooo_fixed_get_type()
482 static GType type = 0;
484 if (!type) {
485 static const GTypeInfo tinfo =
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 */
499 type = g_type_register_static( GTK_TYPE_FIXED, "OOoFixed",
500 &tinfo, (GTypeFlags) 0);
503 return type;
506 void GtkSalFrame::updateScreenNumber()
508 if( getDisplay()->IsXinerama() && getDisplay()->GetXineramaScreens().size() > 1 )
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++ )
515 if( rScreenRects[i].IsInside( aPoint ) )
517 maGeometry.nScreenNumber = static_cast<unsigned int>(i);
518 break;
522 else
523 maGeometry.nScreenNumber = static_cast<unsigned int>(m_nScreen);
526 void GtkSalFrame::InitCommon()
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 );
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_nGSSCookie = 0;
561 m_nExtStyle = 0;
562 m_pRegion = NULL;
563 m_ePointerStyle = 0xffff;
565 gtk_widget_set_app_paintable( m_pWindow, TRUE );
566 gtk_widget_set_double_buffered( m_pWindow, FALSE );
567 gtk_widget_set_redraw_on_allocate( m_pWindow, FALSE );
568 gtk_widget_add_events( m_pWindow,
569 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
570 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
571 GDK_VISIBILITY_NOTIFY_MASK
574 // add the fixed container child,
575 // fixed is needed since we have to position plugin windows
576 m_pFixedContainer = GTK_FIXED(g_object_new( ooo_fixed_get_type(), NULL ));
577 gtk_container_add( GTK_CONTAINER(m_pWindow), GTK_WIDGET(m_pFixedContainer) );
579 // show the widgets
580 gtk_widget_show( GTK_WIDGET(m_pFixedContainer) );
582 // realize the window, we need an XWindow id
583 gtk_widget_realize( m_pWindow );
585 //system data
586 SalDisplay* pDisp = GetX11SalData()->GetDisplay();
587 m_aSystemData.nSize = sizeof( SystemChildData );
588 m_aSystemData.pDisplay = pDisp->GetDisplay();
589 m_aSystemData.aWindow = GDK_WINDOW_XWINDOW(m_pWindow->window);
590 m_aSystemData.pSalFrame = this;
591 m_aSystemData.pWidget = m_pWindow;
592 m_aSystemData.pVisual = pDisp->GetVisual( m_nScreen ).GetVisual();
593 m_aSystemData.nScreen = m_nScreen;
594 m_aSystemData.nDepth = pDisp->GetVisual( m_nScreen ).GetDepth();
595 m_aSystemData.aColormap = pDisp->GetColormap( m_nScreen ).GetXColormap();
596 m_aSystemData.pAppContext = NULL;
597 m_aSystemData.aShellWindow = m_aSystemData.aWindow;
598 m_aSystemData.pShellWidget = m_aSystemData.pWidget;
601 // fake an initial geometry, gets updated via configure event or SetPosSize
602 if( m_bDefaultPos || m_bDefaultSize )
604 Size aDefSize = calcDefaultSize();
605 maGeometry.nX = -1;
606 maGeometry.nY = -1;
607 maGeometry.nWidth = aDefSize.Width();
608 maGeometry.nHeight = aDefSize.Height();
609 if( m_pParent )
611 // approximation
612 maGeometry.nTopDecoration = m_pParent->maGeometry.nTopDecoration;
613 maGeometry.nBottomDecoration = m_pParent->maGeometry.nBottomDecoration;
614 maGeometry.nLeftDecoration = m_pParent->maGeometry.nLeftDecoration;
615 maGeometry.nRightDecoration = m_pParent->maGeometry.nRightDecoration;
617 else
619 maGeometry.nTopDecoration = 0;
620 maGeometry.nBottomDecoration = 0;
621 maGeometry.nLeftDecoration = 0;
622 maGeometry.nRightDecoration = 0;
625 else
627 resizeWindow( maGeometry.nWidth, maGeometry.nHeight );
628 moveWindow( maGeometry.nX, maGeometry.nY );
630 updateScreenNumber();
632 SetIcon(1);
633 m_nWorkArea = pDisp->getWMAdaptor()->getCurrentWorkArea();
635 /* #i64117# gtk sets a nice background pixmap
636 * but we actually don't really want that, so save
637 * some time on the Xserver as well as prevent
638 * some paint issues
640 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
641 GDK_WINDOW_XWINDOW(m_pWindow->window),
642 m_hBackgroundPixmap );
645 /* Sadly gtk_window_set_accept_focus exists only since gtk 2.4
646 * for achieving the same effect we will remove the WM_TAKE_FOCUS
647 * protocol from the window and set the input hint to false.
648 * But gtk_window_set_accept_focus needs to be called before
649 * window realization whereas the removal obviously can only happen
650 * after realization.
653 extern "C" {
654 typedef void(*setAcceptFn)( GtkWindow*, gboolean );
655 static setAcceptFn p_gtk_window_set_accept_focus = NULL;
656 static bool bGetAcceptFocusFn = true;
658 typedef void(*setUserTimeFn)( GdkWindow*, guint32 );
659 static setUserTimeFn p_gdk_x11_window_set_user_time = NULL;
660 static bool bGetSetUserTimeFn = true;
663 static void lcl_set_accept_focus( GtkWindow* pWindow, gboolean bAccept, bool bBeforeRealize )
665 if( bGetAcceptFocusFn )
667 bGetAcceptFocusFn = false;
668 p_gtk_window_set_accept_focus = (setAcceptFn)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_window_set_accept_focus" );
670 if( p_gtk_window_set_accept_focus && bBeforeRealize )
671 p_gtk_window_set_accept_focus( pWindow, bAccept );
672 else if( ! bBeforeRealize )
674 Display* pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
675 XLIB_Window aWindow = GDK_WINDOW_XWINDOW( GTK_WIDGET(pWindow)->window );
676 XWMHints* pHints = XGetWMHints( pDisplay, aWindow );
677 if( ! pHints )
679 pHints = XAllocWMHints();
680 pHints->flags = 0;
682 pHints->flags |= InputHint;
683 pHints->input = bAccept ? True : False;
684 XSetWMHints( pDisplay, aWindow, pHints );
685 XFree( pHints );
687 if (GetX11SalData()->GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("compiz"))
688 return;
690 /* remove WM_TAKE_FOCUS protocol; this would usually be the
691 * right thing, but gtk handles it internally whereas we
692 * want to handle it ourselves (as to sometimes not get
693 * the focus)
695 Atom* pProtocols = NULL;
696 int nProtocols = 0;
697 XGetWMProtocols( pDisplay,
698 aWindow,
699 &pProtocols, &nProtocols );
700 if( pProtocols )
702 bool bSet = false;
703 Atom nTakeFocus = XInternAtom( pDisplay, "WM_TAKE_FOCUS", True );
704 if( nTakeFocus )
706 for( int i = 0; i < nProtocols; i++ )
708 if( pProtocols[i] == nTakeFocus )
710 for( int n = i; n < nProtocols-1; n++ )
711 pProtocols[n] = pProtocols[n+1];
712 nProtocols--;
713 i--;
714 bSet = true;
718 if( bSet )
719 XSetWMProtocols( pDisplay, aWindow, pProtocols, nProtocols );
720 XFree( pProtocols );
724 static void lcl_set_user_time( GdkWindow* i_pWindow, guint32 i_nTime )
726 if( bGetSetUserTimeFn )
728 bGetSetUserTimeFn = false;
729 p_gdk_x11_window_set_user_time = (setUserTimeFn)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_x11_window_set_user_time" );
731 if( p_gdk_x11_window_set_user_time )
732 p_gdk_x11_window_set_user_time( i_pWindow, i_nTime );
733 else
735 Display* pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
736 XLIB_Window aWindow = GDK_WINDOW_XWINDOW( i_pWindow );
737 Atom nUserTime = XInternAtom( pDisplay, "_NET_WM_USER_TIME", True );
738 if( nUserTime )
740 XChangeProperty( pDisplay, aWindow,
741 nUserTime, XA_CARDINAL, 32,
742 PropModeReplace, (unsigned char*)&i_nTime, 1 );
747 GtkSalFrame *GtkSalFrame::getFromWindow( GtkWindow *pWindow )
749 return (GtkSalFrame *) g_object_get_data( G_OBJECT( pWindow ), "SalFrame" );
752 void GtkSalFrame::Init( SalFrame* pParent, ULONG nStyle )
754 if( nStyle & SAL_FRAME_STYLE_DEFAULT ) // ensure default style
756 nStyle |= SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE;
757 nStyle &= ~SAL_FRAME_STYLE_FLOAT;
760 m_pParent = static_cast<GtkSalFrame*>(pParent);
761 m_pForeignParent = NULL;
762 m_aForeignParentWindow = None;
763 m_pForeignTopLevel = NULL;
764 m_aForeignTopLevelWindow = None;
765 m_nStyle = nStyle;
767 GtkWindowType eWinType = ((nStyle & SAL_FRAME_STYLE_FLOAT) && ! (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION))
768 ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL;
770 if( nStyle & SAL_FRAME_STYLE_SYSTEMCHILD )
772 m_pWindow = gtk_event_box_new();
773 if( m_pParent )
775 // insert into container
776 gtk_fixed_put( m_pParent->getFixedContainer(),
777 m_pWindow, 0, 0 );
781 else
782 m_pWindow = gtk_widget_new( GTK_TYPE_WINDOW, "type", eWinType, "visible", FALSE, NULL );
783 g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", this );
785 // force wm class hint
786 m_nExtStyle = ~0;
787 SetExtendedFrameStyle( 0 );
789 if( m_pParent && m_pParent->m_pWindow && ! isChild() )
790 gtk_window_set_screen( GTK_WINDOW(m_pWindow), gtk_window_get_screen( GTK_WINDOW(m_pParent->m_pWindow) ) );
792 // set window type
793 bool bDecoHandling =
794 ! isChild() &&
795 ( ! (nStyle & SAL_FRAME_STYLE_FLOAT) ||
796 (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) );
798 /* #i100116# metacity has a peculiar behavior regarding WM_HINT accept focus and _NET_WM_USER_TIME
799 at some point that may be fixed in metacity and we will have to revisit this
801 bool bMetaCityToolWindowHack = getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("Metacity") &&
802 (nStyle & SAL_FRAME_STYLE_TOOLWINDOW );
803 if( bDecoHandling )
805 bool bNoDecor = ! (nStyle & (SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE ) );
806 GdkWindowTypeHint eType = GDK_WINDOW_TYPE_HINT_NORMAL;
807 if( (nStyle & SAL_FRAME_STYLE_DIALOG) && m_pParent != 0 )
808 eType = GDK_WINDOW_TYPE_HINT_DIALOG;
809 if( (nStyle & SAL_FRAME_STYLE_INTRO) )
811 gtk_window_set_role( GTK_WINDOW(m_pWindow), "splashscreen" );
812 eType = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN;
814 else if( (nStyle & SAL_FRAME_STYLE_TOOLWINDOW ) )
816 eType = GDK_WINDOW_TYPE_HINT_UTILITY;
817 gtk_window_set_skip_taskbar_hint( GTK_WINDOW(m_pWindow), true );
818 if( bMetaCityToolWindowHack )
819 lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, true );
821 else if( (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
823 eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
824 lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, true );
825 bNoDecor = true;
827 if( (nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN ) )
829 eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
830 gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), true );
833 gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), eType );
834 if( bNoDecor )
835 gtk_window_set_decorated( GTK_WINDOW(m_pWindow), FALSE );
836 gtk_window_set_gravity( GTK_WINDOW(m_pWindow), GDK_GRAVITY_STATIC );
837 if( m_pParent && ! (m_pParent->m_nStyle & SAL_FRAME_STYLE_PLUG) )
838 gtk_window_set_transient_for( GTK_WINDOW(m_pWindow), GTK_WINDOW(m_pParent->m_pWindow) );
840 else if( (nStyle & SAL_FRAME_STYLE_FLOAT) )
842 gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), GDK_WINDOW_TYPE_HINT_UTILITY );
844 if( m_pParent )
845 m_pParent->m_aChildren.push_back( this );
847 InitCommon();
849 if( eWinType == GTK_WINDOW_TOPLEVEL )
851 guint32 nUserTime = 0;
852 if( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
854 /* #i99360# ugly workaround an X11 library bug */
855 nUserTime= getDisplay()->GetLastUserEventTime( true );
856 // nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
858 lcl_set_user_time(GTK_WIDGET(m_pWindow)->window, nUserTime);
861 if( bDecoHandling )
863 gtk_window_set_resizable( GTK_WINDOW(m_pWindow), (nStyle & SAL_FRAME_STYLE_SIZEABLE) ? TRUE : FALSE );
864 if( ( (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) || bMetaCityToolWindowHack )
865 lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, false );
870 GdkNativeWindow GtkSalFrame::findTopLevelSystemWindow( GdkNativeWindow aWindow )
872 XLIB_Window aRoot, aParent;
873 XLIB_Window* pChildren;
874 unsigned int nChildren;
875 bool bBreak = false;
878 pChildren = NULL;
879 nChildren = 0;
880 aParent = aRoot = None;
881 XQueryTree( getDisplay()->GetDisplay(), aWindow,
882 &aRoot, &aParent, &pChildren, &nChildren );
883 XFree( pChildren );
884 if( aParent != aRoot )
885 aWindow = aParent;
886 int nCount = 0;
887 Atom* pProps = XListProperties( getDisplay()->GetDisplay(),
888 aWindow,
889 &nCount );
890 for( int i = 0; i < nCount && ! bBreak; ++i )
891 bBreak = (pProps[i] == XA_WM_HINTS);
892 if( pProps )
893 XFree( pProps );
894 } while( aParent != aRoot && ! bBreak );
896 return aWindow;
899 void GtkSalFrame::Init( SystemParentData* pSysData )
901 m_pParent = NULL;
902 m_aForeignParentWindow = (GdkNativeWindow)pSysData->aWindow;
903 m_pForeignParent = NULL;
904 m_aForeignTopLevelWindow = findTopLevelSystemWindow( (GdkNativeWindow)pSysData->aWindow );
905 m_pForeignTopLevel = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignTopLevelWindow );
906 gdk_window_set_events( m_pForeignTopLevel, GDK_STRUCTURE_MASK );
908 if( pSysData->nSize > sizeof(pSysData->nSize)+sizeof(pSysData->aWindow) && pSysData->bXEmbedSupport )
910 m_pWindow = gtk_plug_new( pSysData->aWindow );
911 m_bWindowIsGtkPlug = true;
912 GTK_WIDGET_SET_FLAGS( m_pWindow, GTK_CAN_FOCUS | GTK_SENSITIVE | GTK_CAN_DEFAULT );
913 gtk_widget_set_sensitive( m_pWindow, true );
915 else
917 m_pWindow = gtk_window_new( GTK_WINDOW_POPUP );
918 m_bWindowIsGtkPlug = false;
920 m_nStyle = SAL_FRAME_STYLE_PLUG;
921 InitCommon();
923 m_pForeignParent = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignParentWindow );
924 gdk_window_set_events( m_pForeignParent, GDK_STRUCTURE_MASK );
925 int x_ret, y_ret;
926 unsigned int w, h, bw, d;
927 XLIB_Window aRoot;
928 XGetGeometry( getDisplay()->GetDisplay(), pSysData->aWindow,
929 &aRoot, &x_ret, &y_ret, &w, &h, &bw, &d );
930 maGeometry.nWidth = w;
931 maGeometry.nHeight = h;
932 gtk_window_resize( GTK_WINDOW(m_pWindow), w, h );
933 gtk_window_move( GTK_WINDOW(m_pWindow), 0, 0 );
934 if( ! m_bWindowIsGtkPlug )
936 XReparentWindow( getDisplay()->GetDisplay(),
937 GDK_WINDOW_XWINDOW(m_pWindow->window),
938 (XLIB_Window)pSysData->aWindow,
939 0, 0 );
943 void GtkSalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
945 XEvent aEvent;
947 rtl_zeroMemory( &aEvent, sizeof(aEvent) );
948 aEvent.xclient.window = m_aForeignParentWindow;
949 aEvent.xclient.type = ClientMessage;
950 aEvent.xclient.message_type = getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED );
951 aEvent.xclient.format = 32;
952 aEvent.xclient.data.l[0] = i_nTimeCode ? i_nTimeCode : CurrentTime;
953 aEvent.xclient.data.l[1] = 3; // XEMBED_REQUEST_FOCUS
954 aEvent.xclient.data.l[2] = 0;
955 aEvent.xclient.data.l[3] = 0;
956 aEvent.xclient.data.l[4] = 0;
958 getDisplay()->GetXLib()->PushXErrorLevel( true );
959 XSendEvent( getDisplay()->GetDisplay(),
960 m_aForeignParentWindow,
961 False, NoEventMask, &aEvent );
962 XSync( getDisplay()->GetDisplay(), False );
963 getDisplay()->GetXLib()->PopXErrorLevel();
966 void GtkSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
968 if( nStyle != m_nExtStyle && ! isChild() )
970 m_nExtStyle = nStyle;
971 if( GTK_WIDGET_REALIZED( m_pWindow ) )
973 XClassHint* pClass = XAllocClassHint();
974 rtl::OString aResHint = X11SalData::getFrameResName( m_nExtStyle );
975 pClass->res_name = const_cast<char*>(aResHint.getStr());
976 pClass->res_class = const_cast<char*>(X11SalData::getFrameClassName());
977 XSetClassHint( getDisplay()->GetDisplay(),
978 GDK_WINDOW_XWINDOW(m_pWindow->window),
979 pClass );
980 XFree( pClass );
982 else
983 gtk_window_set_wmclass( GTK_WINDOW(m_pWindow),
984 X11SalData::getFrameResName( m_nExtStyle ),
985 X11SalData::getFrameClassName() );
990 SalGraphics* GtkSalFrame::GetGraphics()
992 if( m_pWindow )
994 for( int i = 0; i < nMaxGraphics; i++ )
996 if( ! m_aGraphics[i].bInUse )
998 m_aGraphics[i].bInUse = true;
999 if( ! m_aGraphics[i].pGraphics )
1001 m_aGraphics[i].pGraphics = new GtkSalGraphics( m_pWindow );
1002 m_aGraphics[i].pGraphics->Init( this, GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
1004 return m_aGraphics[i].pGraphics;
1009 return NULL;
1012 void GtkSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
1014 for( int i = 0; i < nMaxGraphics; i++ )
1016 if( m_aGraphics[i].pGraphics == pGraphics )
1018 m_aGraphics[i].bInUse = false;
1019 break;
1024 BOOL GtkSalFrame::PostEvent( void* pData )
1026 getDisplay()->SendInternalEvent( this, pData );
1027 return TRUE;
1030 void GtkSalFrame::SetTitle( const String& rTitle )
1032 m_aTitle = rTitle;
1033 if( m_pWindow && ! isChild() )
1034 gtk_window_set_title( GTK_WINDOW(m_pWindow), rtl::OUStringToOString( rTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
1037 static inline BYTE *
1038 getRow( BitmapBuffer *pBuffer, ULONG nRow )
1040 if( BMP_SCANLINE_ADJUSTMENT( pBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
1041 return pBuffer->mpBits + nRow * pBuffer->mnScanlineSize;
1042 else
1043 return pBuffer->mpBits + ( pBuffer->mnHeight - nRow - 1 ) * pBuffer->mnScanlineSize;
1046 static GdkPixbuf *
1047 bitmapToPixbuf( SalBitmap *pSalBitmap, SalBitmap *pSalAlpha )
1049 g_return_val_if_fail( pSalBitmap != NULL, NULL );
1050 g_return_val_if_fail( pSalAlpha != NULL, NULL );
1052 BitmapBuffer *pBitmap = pSalBitmap->AcquireBuffer( TRUE );
1053 g_return_val_if_fail( pBitmap != NULL, NULL );
1054 g_return_val_if_fail( pBitmap->mnBitCount == 24, NULL );
1056 BitmapBuffer *pAlpha = pSalAlpha->AcquireBuffer( TRUE );
1057 g_return_val_if_fail( pAlpha != NULL, NULL );
1058 g_return_val_if_fail( pAlpha->mnBitCount == 8, NULL );
1060 Size aSize = pSalBitmap->GetSize();
1061 g_return_val_if_fail( pSalAlpha->GetSize() == aSize, NULL );
1063 int nX, nY;
1064 guchar *pPixbufData = (guchar *)g_malloc (4 * aSize.Width() * aSize.Height() );
1065 guchar *pDestData = pPixbufData;
1067 for( nY = 0; nY < pBitmap->mnHeight; nY++ )
1069 BYTE *pData = getRow( pBitmap, nY );
1070 BYTE *pAlphaData = getRow( pAlpha, nY );
1072 for( nX = 0; nX < pBitmap->mnWidth; nX++ )
1074 if( pBitmap->mnFormat == BMP_FORMAT_24BIT_TC_BGR )
1076 pDestData[2] = *pData++;
1077 pDestData[1] = *pData++;
1078 pDestData[0] = *pData++;
1080 else // BMP_FORMAT_24BIT_TC_RGB
1082 pDestData[0] = *pData++;
1083 pDestData[1] = *pData++;
1084 pDestData[2] = *pData++;
1086 pDestData += 3;
1087 *pDestData++ = 255 - *pAlphaData++;
1091 pSalBitmap->ReleaseBuffer( pBitmap, TRUE );
1092 pSalAlpha->ReleaseBuffer( pAlpha, TRUE );
1094 return gdk_pixbuf_new_from_data( pPixbufData,
1095 GDK_COLORSPACE_RGB, TRUE, 8,
1096 aSize.Width(), aSize.Height(),
1097 aSize.Width() * 4,
1098 (GdkPixbufDestroyNotify) g_free,
1099 NULL );
1102 void GtkSalFrame::SetIcon( USHORT nIcon )
1104 if( (m_nStyle & (SAL_FRAME_STYLE_PLUG|SAL_FRAME_STYLE_SYSTEMCHILD|SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_INTRO|SAL_FRAME_STYLE_OWNERDRAWDECORATION))
1105 || ! m_pWindow )
1106 return;
1108 if( !ImplGetResMgr() )
1109 return;
1111 GdkPixbuf *pBuf;
1112 GList *pIcons = NULL;
1114 USHORT nOffsets[2] = { SV_ICON_SMALL_START, SV_ICON_LARGE_START };
1115 USHORT nIndex;
1117 // Use high contrast icons where appropriate
1118 if( Application::GetSettings().GetStyleSettings().GetFaceColor().IsDark() )
1120 nOffsets[0] = SV_ICON_LARGE_HC_START;
1121 nOffsets[1] = SV_ICON_SMALL_HC_START;
1124 for( nIndex = 0; nIndex < sizeof(nOffsets)/ sizeof(USHORT); nIndex++ )
1126 // #i44723# workaround gcc temporary problem
1127 ResId aResId( nOffsets[nIndex] + nIcon, *ImplGetResMgr() );
1128 BitmapEx aIcon;
1129 try {
1130 aIcon = BitmapEx( aResId );
1131 } catch (com::sun::star::uno::RuntimeException &) {
1132 // UCB not initialized for splash screen creation; very exceptional.
1133 continue;
1136 // #i81083# convert to 24bit/8bit alpha bitmap
1137 Bitmap aBmp = aIcon.GetBitmap();
1138 if( aBmp.GetBitCount() != 24 || ! aIcon.IsAlpha() )
1140 if( aBmp.GetBitCount() != 24 )
1141 aBmp.Convert( BMP_CONVERSION_24BIT );
1142 AlphaMask aMask;
1143 if( ! aIcon.IsAlpha() )
1145 switch( aIcon.GetTransparentType() )
1147 case TRANSPARENT_NONE:
1149 BYTE nTrans = 0;
1150 aMask = AlphaMask( aBmp.GetSizePixel(), &nTrans );
1152 break;
1153 case TRANSPARENT_COLOR:
1154 aMask = AlphaMask( aBmp.CreateMask( aIcon.GetTransparentColor() ) );
1155 break;
1156 case TRANSPARENT_BITMAP:
1157 aMask = AlphaMask( aIcon.GetMask() );
1158 break;
1159 default:
1160 DBG_ERROR( "unhandled transparent type" );
1161 break;
1164 else
1165 aMask = aIcon.GetAlpha();
1166 aIcon = BitmapEx( aBmp, aMask );
1169 ImpBitmap *pIconImpBitmap = aIcon.ImplGetBitmapImpBitmap();
1170 ImpBitmap *pIconImpMask = aIcon.ImplGetMaskImpBitmap();
1173 if( pIconImpBitmap && pIconImpMask )
1175 SalBitmap *pIconBitmap =
1176 pIconImpBitmap->ImplGetSalBitmap();
1177 SalBitmap *pIconMask =
1178 pIconImpMask->ImplGetSalBitmap();
1180 if( ( pBuf = bitmapToPixbuf( pIconBitmap, pIconMask ) ) )
1181 pIcons = g_list_prepend( pIcons, pBuf );
1185 gtk_window_set_icon_list( GTK_WINDOW(m_pWindow), pIcons );
1187 g_list_foreach( pIcons, (GFunc) g_object_unref, NULL );
1188 g_list_free( pIcons );
1191 void GtkSalFrame::SetMenu( SalMenu* )
1195 void GtkSalFrame::DrawMenuBar()
1199 void GtkSalFrame::Center()
1201 long nX, nY;
1203 if( m_pParent )
1205 nX = ((long)m_pParent->maGeometry.nWidth - (long)maGeometry.nWidth)/2;
1206 nY = ((long)m_pParent->maGeometry.nHeight - (long)maGeometry.nHeight)/2;
1209 else
1211 long nScreenWidth, nScreenHeight;
1212 long nScreenX = 0, nScreenY = 0;
1214 Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
1215 nScreenWidth = aScreenSize.Width();
1216 nScreenHeight = aScreenSize.Height();
1217 if( GetX11SalData()->GetDisplay()->IsXinerama() )
1219 // get xinerama screen we are on
1220 // if there is a parent, use its center for screen determination
1221 // else use the pointer
1222 GdkScreen* pScreen;
1223 gint x, y;
1224 GdkModifierType aMask;
1225 gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
1227 const std::vector< Rectangle >& rScreens = GetX11SalData()->GetDisplay()->GetXineramaScreens();
1228 for( unsigned int i = 0; i < rScreens.size(); i++ )
1229 if( rScreens[i].IsInside( Point( x, y ) ) )
1231 nScreenX = rScreens[i].Left();
1232 nScreenY = rScreens[i].Top();
1233 nScreenWidth = rScreens[i].GetWidth();
1234 nScreenHeight = rScreens[i].GetHeight();
1235 break;
1238 nX = nScreenX + (nScreenWidth - (long)maGeometry.nWidth)/2;
1239 nY = nScreenY + (nScreenHeight - (long)maGeometry.nHeight)/2;
1241 SetPosSize( nX, nY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
1244 Size GtkSalFrame::calcDefaultSize()
1246 Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
1247 long w = aScreenSize.Width();
1248 long h = aScreenSize.Height();
1250 // fill in holy default values brought to us by product management
1251 if( aScreenSize.Width() >= 800 )
1252 w = 785;
1253 if( aScreenSize.Width() >= 1024 )
1254 w = 920;
1256 if( aScreenSize.Height() >= 600 )
1257 h = 550;
1258 if( aScreenSize.Height() >= 768 )
1259 h = 630;
1260 if( aScreenSize.Height() >= 1024 )
1261 h = 875;
1263 return Size( w, h );
1266 void GtkSalFrame::SetDefaultSize()
1268 Size aDefSize = calcDefaultSize();
1270 SetPosSize( 0, 0, aDefSize.Width(), aDefSize.Height(),
1271 SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
1273 if( (m_nStyle & SAL_FRAME_STYLE_DEFAULT) && m_pWindow )
1274 gtk_window_maximize( GTK_WINDOW(m_pWindow) );
1277 static void initClientId()
1279 static bool bOnce = false;
1280 if( ! bOnce )
1282 bOnce = true;
1283 const ByteString& rID = SessionManagerClient::getSessionID();
1284 if( rID.Len() > 0 )
1285 gdk_set_sm_client_id(rID.GetBuffer());
1289 void GtkSalFrame::Show( BOOL bVisible, BOOL bNoActivate )
1291 if( m_pWindow )
1293 if( m_pParent && (m_pParent->m_nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN) )
1294 gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), bVisible );
1295 if( bVisible )
1297 SessionManagerClient::open(); // will simply return after the first time
1298 initClientId();
1299 getDisplay()->startupNotificationCompleted();
1301 if( m_bDefaultPos )
1302 Center();
1303 if( m_bDefaultSize )
1304 SetDefaultSize();
1305 setMinMaxSize();
1307 // #i45160# switch to desktop where a dialog with parent will appear
1308 if( m_pParent && m_pParent->m_nWorkArea != m_nWorkArea )
1309 getDisplay()->getWMAdaptor()->switchToWorkArea( m_pParent->m_nWorkArea );
1311 if( isFloatGrabWindow() &&
1312 m_pParent &&
1313 m_nFloats == 0 &&
1314 ! getDisplay()->GetCaptureFrame() )
1316 /* #i63086#
1317 * outsmart Metacity's "focus:mouse" mode
1318 * which insists on taking the focus from the document
1319 * to the new float. Grab focus to parent frame BEFORE
1320 * showing the float (cannot grab it to the float
1321 * before show).
1323 m_pParent->grabPointer( TRUE, TRUE );
1326 guint32 nUserTime = 0;
1327 if( ! bNoActivate && (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
1328 /* #i99360# ugly workaround an X11 library bug */
1329 nUserTime= getDisplay()->GetLastUserEventTime( true );
1330 //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
1332 //For these floating windows we don't want the main window to lose focus, and metacity has...
1333 // metacity-2.24.0/src/core/window.c
1335 // if ((focus_window != NULL) && XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time))
1336 // "compare" window focus prevented by other activity
1338 // where "compare" is this window
1340 // which leads to...
1342 // /* This happens for error dialogs or alerts; these need to remain on
1343 // * top, but it would be confusing to have its ancestor remain
1344 // * focused.
1345 // */
1346 // if (meta_window_is_ancestor_of_transient (focus_window, window))
1347 // "The focus window %s is an ancestor of the newly mapped "
1348 // "window %s which isn't being focused. Unfocusing the "
1349 // "ancestor.\n",
1351 // i.e. having a time < that of the toplevel frame means that the toplevel frame gets unfocused.
1352 // awesome.
1353 if( nUserTime == 0 &&
1355 getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("Metacity") ||
1357 getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("compiz") &&
1358 (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION))
1363 /* #i99360# ugly workaround an X11 library bug */
1364 nUserTime= getDisplay()->GetLastUserEventTime( true );
1365 //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
1368 lcl_set_user_time( GTK_WIDGET(m_pWindow)->window, nUserTime );
1370 gtk_widget_show( m_pWindow );
1372 if( isFloatGrabWindow() )
1374 m_nFloats++;
1375 if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 1 )
1376 grabPointer( TRUE, TRUE );
1377 // #i44068# reset parent's IM context
1378 if( m_pParent )
1379 m_pParent->EndExtTextInput(0);
1381 if( m_bWindowIsGtkPlug )
1382 askForXEmbedFocus( 0 );
1384 else
1386 if( isFloatGrabWindow() )
1388 m_nFloats--;
1389 if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 0)
1390 grabPointer( FALSE );
1392 gtk_widget_hide( m_pWindow );
1393 if( m_pIMHandler )
1394 m_pIMHandler->focusChanged( false );
1396 CallCallback( SALEVENT_RESIZE, NULL );
1400 void GtkSalFrame::Enable( BOOL /*bEnable*/ )
1402 // Not implemented by X11SalFrame either
1405 void GtkSalFrame::setMinMaxSize()
1407 /* FIXME: for yet unknown reasons the reported size is a little smaller
1408 * than the max size hint; one would guess that this was due to the border
1409 * sizes of the widgets involved (GtkWindow and GtkFixed), but setting the
1410 * their border to 0 (which is the default anyway) does not change the
1411 * behaviour. Until the reason is known we'll add some pixels here.
1413 #define CONTAINER_ADJUSTMENT 6
1415 /* #i34504# metacity (and possibly others) do not treat
1416 * _NET_WM_STATE_FULLSCREEN and max_width/heigth independently;
1417 * whether they should is undefined. So don't set the max size hint
1418 * for a full screen window.
1420 if( m_pWindow && ! isChild() )
1422 GdkGeometry aGeo;
1423 int aHints = 0;
1424 if( m_nStyle & SAL_FRAME_STYLE_SIZEABLE )
1426 if( m_aMinSize.Width() && m_aMinSize.Height() )
1428 aGeo.min_width = m_aMinSize.Width()+CONTAINER_ADJUSTMENT;
1429 aGeo.min_height = m_aMinSize.Height()+CONTAINER_ADJUSTMENT;
1430 aHints |= GDK_HINT_MIN_SIZE;
1432 if( m_aMaxSize.Width() && m_aMaxSize.Height() && ! m_bFullscreen )
1434 aGeo.max_width = m_aMaxSize.Width()+CONTAINER_ADJUSTMENT;
1435 aGeo.max_height = m_aMaxSize.Height()+CONTAINER_ADJUSTMENT;
1436 aHints |= GDK_HINT_MAX_SIZE;
1439 else
1441 aGeo.min_width = maGeometry.nWidth;
1442 aGeo.min_height = maGeometry.nHeight;
1443 aHints |= GDK_HINT_MIN_SIZE;
1444 if( ! m_bFullscreen )
1446 aGeo.max_width = maGeometry.nWidth;
1447 aGeo.max_height = maGeometry.nHeight;
1448 aHints |= GDK_HINT_MAX_SIZE;
1451 if( aHints )
1452 gtk_window_set_geometry_hints( GTK_WINDOW(m_pWindow),
1453 NULL,
1454 &aGeo,
1455 GdkWindowHints( aHints ) );
1459 void GtkSalFrame::SetMaxClientSize( long nWidth, long nHeight )
1461 if( ! isChild() )
1463 m_aMaxSize = Size( nWidth, nHeight );
1464 // Show does a setMinMaxSize
1465 if( GTK_WIDGET_MAPPED( m_pWindow ) )
1466 setMinMaxSize();
1469 void GtkSalFrame::SetMinClientSize( long nWidth, long nHeight )
1471 if( ! isChild() )
1473 m_aMinSize = Size( nWidth, nHeight );
1474 if( m_pWindow )
1476 gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
1477 // Show does a setMinMaxSize
1478 if( GTK_WIDGET_MAPPED( m_pWindow ) )
1479 setMinMaxSize();
1484 void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags )
1486 if( !m_pWindow || isChild( true, false ) )
1487 return;
1489 bool bSized = false, bMoved = false;
1491 if( (nFlags & ( SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT )) &&
1492 (nWidth > 0 && nHeight > 0 ) // sometimes stupid things happen
1495 m_bDefaultSize = false;
1497 if( (unsigned long)nWidth != maGeometry.nWidth || (unsigned long)nHeight != maGeometry.nHeight )
1498 bSized = true;
1499 maGeometry.nWidth = nWidth;
1500 maGeometry.nHeight = nHeight;
1502 if( isChild( false, true ) )
1503 gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
1504 else
1505 gtk_window_resize( GTK_WINDOW(m_pWindow), nWidth, nHeight );
1506 setMinMaxSize();
1508 else if( m_bDefaultSize )
1509 SetDefaultSize();
1511 m_bDefaultSize = false;
1513 if( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) )
1515 if( m_pParent )
1517 if( Application::GetSettings().GetLayoutRTL() )
1518 nX = m_pParent->maGeometry.nWidth-maGeometry.nWidth-1-nX;
1519 nX += m_pParent->maGeometry.nX;
1520 nY += m_pParent->maGeometry.nY;
1523 // adjust position to avoid off screen windows
1524 // but allow toolbars to be positioned partly off screen by the user
1525 Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
1526 if( ! (m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
1528 if( nX < (long)maGeometry.nLeftDecoration )
1529 nX = maGeometry.nLeftDecoration;
1530 if( nY < (long)maGeometry.nTopDecoration )
1531 nY = maGeometry.nTopDecoration;
1532 if( (nX + (long)maGeometry.nWidth + (long)maGeometry.nRightDecoration) > (long)aScreenSize.Width() )
1533 nX = aScreenSize.Width() - maGeometry.nWidth - maGeometry.nRightDecoration;
1534 if( (nY + (long)maGeometry.nHeight + (long)maGeometry.nBottomDecoration) > (long)aScreenSize.Height() )
1535 nY = aScreenSize.Height() - maGeometry.nHeight - maGeometry.nBottomDecoration;
1537 else
1539 if( nX + (long)maGeometry.nWidth < 10 )
1540 nX = 10 - (long)maGeometry.nWidth;
1541 if( nY + (long)maGeometry.nHeight < 10 )
1542 nY = 10 - (long)maGeometry.nHeight;
1543 if( nX > (long)aScreenSize.Width() - 10 )
1544 nX = (long)aScreenSize.Width() - 10;
1545 if( nY > (long)aScreenSize.Height() - 10 )
1546 nY = (long)aScreenSize.Height() - 10;
1549 if( nX != maGeometry.nX || nY != maGeometry.nY )
1550 bMoved = true;
1551 maGeometry.nX = nX;
1552 maGeometry.nY = nY;
1554 m_bDefaultPos = false;
1556 moveWindow( maGeometry.nX, maGeometry.nY );
1558 updateScreenNumber();
1560 else if( m_bDefaultPos )
1561 Center();
1563 m_bDefaultPos = false;
1565 if( bSized && ! bMoved )
1566 CallCallback( SALEVENT_RESIZE, NULL );
1567 else if( bMoved && ! bSized )
1568 CallCallback( SALEVENT_MOVE, NULL );
1569 else if( bMoved && bSized )
1570 CallCallback( SALEVENT_MOVERESIZE, NULL );
1573 void GtkSalFrame::GetClientSize( long& rWidth, long& rHeight )
1575 if( m_pWindow && !(m_nState & GDK_WINDOW_STATE_ICONIFIED) )
1577 rWidth = maGeometry.nWidth;
1578 rHeight = maGeometry.nHeight;
1580 else
1581 rWidth = rHeight = 0;
1584 void GtkSalFrame::GetWorkArea( Rectangle& rRect )
1586 rRect = GetX11SalData()->GetDisplay()->getWMAdaptor()->getWorkArea( 0 );
1589 SalFrame* GtkSalFrame::GetParent() const
1591 return m_pParent;
1594 void GtkSalFrame::SetWindowState( const SalFrameState* pState )
1596 if( ! m_pWindow || ! pState || isChild( true, false ) )
1597 return;
1599 const ULONG nMaxGeometryMask =
1600 SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y |
1601 SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT |
1602 SAL_FRAMESTATE_MASK_MAXIMIZED_X | SAL_FRAMESTATE_MASK_MAXIMIZED_Y |
1603 SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT;
1605 if( (pState->mnMask & SAL_FRAMESTATE_MASK_STATE) &&
1606 (pState->mnState & SAL_FRAMESTATE_MAXIMIZED) &&
1607 (pState->mnMask & nMaxGeometryMask) == nMaxGeometryMask )
1609 resizeWindow( pState->mnWidth, pState->mnHeight );
1610 moveWindow( pState->mnX, pState->mnY );
1611 m_bDefaultPos = m_bDefaultSize = false;
1613 maGeometry.nX = pState->mnMaximizedX;
1614 maGeometry.nY = pState->mnMaximizedY;
1615 maGeometry.nWidth = pState->mnMaximizedWidth;
1616 maGeometry.nHeight = pState->mnMaximizedHeight;
1617 updateScreenNumber();
1619 m_nState = GdkWindowState( m_nState | GDK_WINDOW_STATE_MAXIMIZED );
1620 m_aRestorePosSize = Rectangle( Point( pState->mnX, pState->mnY ),
1621 Size( pState->mnWidth, pState->mnHeight ) );
1623 else if( pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y |
1624 SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT ) )
1626 USHORT nPosSizeFlags = 0;
1627 long nX = pState->mnX - (m_pParent ? m_pParent->maGeometry.nX : 0);
1628 long nY = pState->mnY - (m_pParent ? m_pParent->maGeometry.nY : 0);
1629 long nWidth = pState->mnWidth;
1630 long nHeight = pState->mnHeight;
1631 if( pState->mnMask & SAL_FRAMESTATE_MASK_X )
1632 nPosSizeFlags |= SAL_FRAME_POSSIZE_X;
1633 else
1634 nX = maGeometry.nX - (m_pParent ? m_pParent->maGeometry.nX : 0);
1635 if( pState->mnMask & SAL_FRAMESTATE_MASK_Y )
1636 nPosSizeFlags |= SAL_FRAME_POSSIZE_Y;
1637 else
1638 nY = maGeometry.nY - (m_pParent ? m_pParent->maGeometry.nY : 0);
1639 if( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH )
1640 nPosSizeFlags |= SAL_FRAME_POSSIZE_WIDTH;
1641 else
1642 nWidth = maGeometry.nWidth;
1643 if( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT )
1644 nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT;
1645 else
1646 nHeight = maGeometry.nHeight;
1647 SetPosSize( nX, nY, pState->mnWidth, pState->mnHeight, nPosSizeFlags );
1649 if( pState->mnMask & SAL_FRAMESTATE_MASK_STATE && ! isChild() )
1651 if( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
1652 gtk_window_maximize( GTK_WINDOW(m_pWindow) );
1653 else
1654 gtk_window_unmaximize( GTK_WINDOW(m_pWindow) );
1655 /* #i42379# there is no rollup state in GDK; and rolled up windows are
1656 * (probably depending on the WM) reported as iconified. If we iconify a
1657 * window here that was e.g. a dialog, then it will be unmapped but still
1658 * not be displayed in the task list, so it's an iconified window that
1659 * the user cannot get out of this state. So do not set the iconified state
1660 * on windows with a parent (that is transient frames) since these tend
1661 * to not be represented in an icon task list.
1663 if( (pState->mnState & SAL_FRAMESTATE_MINIMIZED)
1664 && ! m_pParent )
1665 gtk_window_iconify( GTK_WINDOW(m_pWindow) );
1666 else
1667 gtk_window_deiconify( GTK_WINDOW(m_pWindow) );
1671 BOOL GtkSalFrame::GetWindowState( SalFrameState* pState )
1673 pState->mnState = SAL_FRAMESTATE_NORMAL;
1674 pState->mnMask = SAL_FRAMESTATE_MASK_STATE;
1675 // rollup ? gtk 2.2 does not seem to support the shaded state
1676 if( (m_nState & GDK_WINDOW_STATE_ICONIFIED) )
1677 pState->mnState |= SAL_FRAMESTATE_MINIMIZED;
1678 if( m_nState & GDK_WINDOW_STATE_MAXIMIZED )
1680 pState->mnState |= SAL_FRAMESTATE_MAXIMIZED;
1681 pState->mnX = m_aRestorePosSize.Left();
1682 pState->mnY = m_aRestorePosSize.Top();
1683 pState->mnWidth = m_aRestorePosSize.GetWidth();
1684 pState->mnHeight = m_aRestorePosSize.GetHeight();
1685 pState->mnMaximizedX = maGeometry.nX;
1686 pState->mnMaximizedY = maGeometry.nY;
1687 pState->mnMaximizedWidth = maGeometry.nWidth;
1688 pState->mnMaximizedHeight = maGeometry.nHeight;
1689 pState->mnMask |= SAL_FRAMESTATE_MASK_MAXIMIZED_X |
1690 SAL_FRAMESTATE_MASK_MAXIMIZED_Y |
1691 SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH |
1692 SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT;
1694 else
1697 pState->mnX = maGeometry.nX;
1698 pState->mnY = maGeometry.nY;
1699 pState->mnWidth = maGeometry.nWidth;
1700 pState->mnHeight = maGeometry.nHeight;
1702 pState->mnMask |= SAL_FRAMESTATE_MASK_X |
1703 SAL_FRAMESTATE_MASK_Y |
1704 SAL_FRAMESTATE_MASK_WIDTH |
1705 SAL_FRAMESTATE_MASK_HEIGHT;
1707 return TRUE;
1710 void GtkSalFrame::moveToScreen( int nScreen )
1712 if( isChild() )
1713 return;
1715 if( nScreen < 0 || nScreen >= gdk_display_get_n_screens( getGdkDisplay() ) )
1716 nScreen = m_nScreen;
1717 if( nScreen == m_nScreen )
1718 return;
1720 GdkScreen* pScreen = gdk_display_get_screen( getGdkDisplay(), nScreen );
1721 if( pScreen )
1723 m_nScreen = nScreen;
1724 gtk_window_set_screen( GTK_WINDOW(m_pWindow), pScreen );
1725 // realize the window, we need an XWindow id
1726 gtk_widget_realize( m_pWindow );
1727 // update system data
1728 GtkSalDisplay* pDisp = getDisplay();
1729 m_aSystemData.aWindow = GDK_WINDOW_XWINDOW(m_pWindow->window);
1730 m_aSystemData.pVisual = pDisp->GetVisual( m_nScreen ).GetVisual();
1731 m_aSystemData.nScreen = nScreen;
1732 m_aSystemData.nDepth = pDisp->GetVisual( m_nScreen ).GetDepth();
1733 m_aSystemData.aColormap = pDisp->GetColormap( m_nScreen ).GetXColormap();
1734 m_aSystemData.pAppContext = NULL;
1735 m_aSystemData.aShellWindow = m_aSystemData.aWindow;
1736 // update graphics if necessary
1737 for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
1739 if( m_aGraphics[i].bInUse )
1740 m_aGraphics[i].pGraphics->SetDrawable( GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
1742 updateScreenNumber();
1745 if( m_pParent && m_pParent->m_nScreen != m_nScreen )
1746 SetParent( NULL );
1747 std::list< GtkSalFrame* > aChildren = m_aChildren;
1748 for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
1749 (*it)->moveToScreen( m_nScreen );
1751 // FIXME: SalObjects
1754 void GtkSalFrame::SetScreenNumber( unsigned int nNewScreen )
1756 if( nNewScreen == maGeometry.nScreenNumber )
1757 return;
1759 if( m_pWindow && ! isChild() )
1761 GtkSalDisplay* pDisp = getDisplay();
1762 if( pDisp->IsXinerama() && pDisp->GetXineramaScreens().size() > 1 )
1764 if( nNewScreen >= pDisp->GetXineramaScreens().size() )
1765 return;
1767 Rectangle aOldScreenRect( pDisp->GetXineramaScreens()[maGeometry.nScreenNumber] );
1768 Rectangle aNewScreenRect( pDisp->GetXineramaScreens()[nNewScreen] );
1769 bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
1770 if( bVisible )
1771 Show( FALSE );
1772 maGeometry.nX = aNewScreenRect.Left() + (maGeometry.nX - aOldScreenRect.Left());
1773 maGeometry.nY = aNewScreenRect.Top() + (maGeometry.nY - aOldScreenRect.Top());
1774 createNewWindow( None, false, m_nScreen );
1775 gtk_window_move( GTK_WINDOW(m_pWindow), maGeometry.nX, maGeometry.nY );
1776 if( bVisible )
1777 Show( TRUE );
1778 maGeometry.nScreenNumber = nNewScreen;
1780 else if( sal_Int32(nNewScreen) < pDisp->GetScreenCount() )
1782 moveToScreen( (int)nNewScreen );
1783 maGeometry.nScreenNumber = nNewScreen;
1784 gtk_window_move( GTK_WINDOW(m_pWindow), maGeometry.nX, maGeometry.nY );
1789 void GtkSalFrame::ShowFullScreen( BOOL bFullScreen, sal_Int32 nScreen )
1791 if( m_pWindow && ! isChild() )
1793 GtkSalDisplay* pDisp = getDisplay();
1794 // xinerama ?
1795 if( pDisp->IsXinerama() && pDisp->GetXineramaScreens().size() > 1 )
1797 if( bFullScreen )
1799 m_aRestorePosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
1800 Size( maGeometry.nWidth, maGeometry.nHeight ) );
1801 // workaround different window managers have different opinions about
1802 // _NET_WM_STATE_FULLSCREEN (Metacity <-> KWin)
1803 bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
1804 if( bVisible )
1805 Show( FALSE );
1806 m_nStyle |= SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
1807 createNewWindow( None, false, m_nScreen );
1808 Rectangle aNewPosSize;
1809 if( nScreen < 0 || nScreen >= static_cast<int>(pDisp->GetXineramaScreens().size()) )
1810 aNewPosSize = Rectangle( Point( 0, 0 ), pDisp->GetScreenSize(m_nScreen) );
1811 else
1812 aNewPosSize = pDisp->GetXineramaScreens()[ nScreen ];
1813 gtk_window_resize( GTK_WINDOW(m_pWindow),
1814 maGeometry.nWidth = aNewPosSize.GetWidth(),
1815 maGeometry.nHeight = aNewPosSize.GetHeight() );
1816 gtk_window_move( GTK_WINDOW(m_pWindow),
1817 maGeometry.nX = aNewPosSize.Left(),
1818 maGeometry.nY = aNewPosSize.Top() );
1819 if( bVisible )
1820 Show( TRUE );
1822 else
1824 bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
1825 if( bVisible )
1826 Show( FALSE );
1827 m_nStyle &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
1828 createNewWindow( None, false, m_nScreen );
1829 if( ! m_aRestorePosSize.IsEmpty() )
1831 gtk_window_resize( GTK_WINDOW(m_pWindow),
1832 maGeometry.nWidth = m_aRestorePosSize.GetWidth(),
1833 maGeometry.nHeight = m_aRestorePosSize.GetHeight() );
1834 gtk_window_move( GTK_WINDOW(m_pWindow),
1835 maGeometry.nX = m_aRestorePosSize.Left(),
1836 maGeometry.nY = m_aRestorePosSize.Top() );
1837 m_aRestorePosSize = Rectangle();
1839 if( bVisible )
1840 Show( TRUE );
1843 else
1845 if( bFullScreen )
1847 if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
1848 gtk_window_set_resizable( GTK_WINDOW(m_pWindow), TRUE );
1849 gtk_window_fullscreen( GTK_WINDOW(m_pWindow) );
1850 moveToScreen( nScreen );
1851 Size aScreenSize = pDisp->GetScreenSize( m_nScreen );
1852 maGeometry.nX = 0;
1853 maGeometry.nY = 0;
1854 maGeometry.nWidth = aScreenSize.Width();
1855 maGeometry.nHeight = aScreenSize.Height();
1857 else
1859 gtk_window_unfullscreen( GTK_WINDOW(m_pWindow) );
1860 if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
1861 gtk_window_set_resizable( GTK_WINDOW(m_pWindow), FALSE );
1862 moveToScreen( nScreen );
1865 m_bDefaultPos = m_bDefaultSize = false;
1866 updateScreenNumber();
1867 CallCallback( SALEVENT_MOVERESIZE, NULL );
1869 m_bFullscreen = bFullScreen;
1872 /* definitions from xautolock.c (pl15) */
1873 #define XAUTOLOCK_DISABLE 1
1874 #define XAUTOLOCK_ENABLE 2
1876 void GtkSalFrame::setAutoLock( bool bLock )
1878 if( isChild() )
1879 return;
1881 GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(m_pWindow) );
1882 GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
1883 GdkWindow *pRootWin = gdk_screen_get_root_window( pScreen );
1885 Atom nAtom = XInternAtom( GDK_DISPLAY_XDISPLAY( pDisplay ),
1886 "XAUTOLOCK_MESSAGE", False );
1888 int nMessage = bLock ? XAUTOLOCK_ENABLE : XAUTOLOCK_DISABLE;
1890 XChangeProperty( GDK_DISPLAY_XDISPLAY( pDisplay ),
1891 GDK_WINDOW_XID( pRootWin ),
1892 nAtom, XA_INTEGER,
1893 8, PropModeReplace,
1894 (unsigned char*)&nMessage,
1895 sizeof( nMessage ) );
1898 #ifdef ENABLE_DBUS
1899 /** cookie is returned as an unsigned integer */
1900 static guint
1901 dbus_inhibit_gss (const gchar *appname,
1902 const gchar *reason)
1904 gboolean res;
1905 guint cookie;
1906 GError *error = NULL;
1907 DBusGProxy *proxy = NULL;
1908 DBusGConnection *session_connection = NULL;
1910 /* get the DBUS session connection */
1911 session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
1912 if (error != NULL) {
1913 g_warning ("DBUS cannot connect : %s", error->message);
1914 g_error_free (error);
1915 return -1;
1918 /* get the proxy with gnome-screensaver */
1919 proxy = dbus_g_proxy_new_for_name (session_connection,
1920 GSS_DBUS_SERVICE,
1921 GSS_DBUS_PATH,
1922 GSS_DBUS_INTERFACE);
1923 if (proxy == NULL) {
1924 g_warning ("Could not get DBUS proxy: %s", GSS_DBUS_SERVICE);
1925 return -1;
1928 res = dbus_g_proxy_call (proxy,
1929 "Inhibit", &error,
1930 G_TYPE_STRING, appname,
1931 G_TYPE_STRING, reason,
1932 G_TYPE_INVALID,
1933 G_TYPE_UINT, &cookie,
1934 G_TYPE_INVALID);
1936 /* check the return value */
1937 if (! res) {
1938 cookie = -1;
1939 g_warning ("Inhibit method failed");
1942 /* check the error value */
1943 if (error != NULL) {
1944 g_warning ("Inhibit problem : %s", error->message);
1945 g_error_free (error);
1946 cookie = -1;
1949 g_object_unref (G_OBJECT (proxy));
1950 return cookie;
1953 static void
1954 dbus_uninhibit_gss (guint cookie)
1956 gboolean res;
1957 GError *error = NULL;
1958 DBusGProxy *proxy = NULL;
1959 DBusGConnection *session_connection = NULL;
1961 /* cookies have to be positive as unsigned */
1962 if (cookie < 0) {
1963 g_warning ("Invalid cookie");
1964 return;
1967 /* get the DBUS session connection */
1968 session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
1969 if (error) {
1970 g_warning ("DBUS cannot connect : %s", error->message);
1971 g_error_free (error);
1972 return;
1975 /* get the proxy with gnome-screensaver */
1976 proxy = dbus_g_proxy_new_for_name (session_connection,
1977 GSS_DBUS_SERVICE,
1978 GSS_DBUS_PATH,
1979 GSS_DBUS_INTERFACE);
1980 if (proxy == NULL) {
1981 g_warning ("Could not get DBUS proxy: %s", GSS_DBUS_SERVICE);
1982 return;
1985 res = dbus_g_proxy_call (proxy,
1986 "UnInhibit",
1987 &error,
1988 G_TYPE_UINT, cookie,
1989 G_TYPE_INVALID,
1990 G_TYPE_INVALID);
1992 /* check the return value */
1993 if (! res) {
1994 g_warning ("UnInhibit method failed");
1997 /* check the error value */
1998 if (error != NULL) {
1999 g_warning ("Inhibit problem : %s", error->message);
2000 g_error_free (error);
2001 cookie = -1;
2003 g_object_unref (G_OBJECT (proxy));
2005 #endif
2007 void GtkSalFrame::StartPresentation( BOOL bStart )
2009 Display *pDisplay = GDK_DISPLAY_XDISPLAY( getGdkDisplay() );
2011 setAutoLock( !bStart );
2013 int nTimeout, nInterval, bPreferBlanking, bAllowExposures;
2015 XGetScreenSaver( pDisplay, &nTimeout, &nInterval,
2016 &bPreferBlanking, &bAllowExposures );
2017 if( bStart )
2019 if ( nTimeout )
2021 m_nSavedScreenSaverTimeout = nTimeout;
2022 XResetScreenSaver( pDisplay );
2023 XSetScreenSaver( pDisplay, 0, nInterval,
2024 bPreferBlanking, bAllowExposures );
2026 #ifdef ENABLE_DBUS
2027 m_nGSSCookie = dbus_inhibit_gss(g_get_application_name(), "presentation");
2028 #endif
2030 else
2032 if( m_nSavedScreenSaverTimeout )
2033 XSetScreenSaver( pDisplay, m_nSavedScreenSaverTimeout,
2034 nInterval, bPreferBlanking,
2035 bAllowExposures );
2036 m_nSavedScreenSaverTimeout = 0;
2037 #ifdef ENABLE_DBUS
2038 dbus_uninhibit_gss(m_nGSSCookie);
2039 #endif
2043 void GtkSalFrame::SetAlwaysOnTop( BOOL /*bOnTop*/ )
2047 void GtkSalFrame::ToTop( USHORT nFlags )
2049 if( m_pWindow )
2051 if( isChild( false, true ) )
2052 gtk_widget_grab_focus( m_pWindow );
2053 else if( GTK_WIDGET_MAPPED( m_pWindow ) )
2055 if( ! (nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY) )
2056 gtk_window_present( GTK_WINDOW(m_pWindow) );
2057 else
2059 // gdk_window_focus( m_pWindow->window, gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window) );
2060 /* #i99360# ugly workaround an X11 library bug */
2061 guint32 nUserTime= getDisplay()->GetLastUserEventTime( true );
2062 gdk_window_focus( m_pWindow->window, nUserTime );
2064 /* need to do an XSetInputFocus here because
2065 * gdk_window_focus will ask a EWMH compliant WM to put the focus
2066 * to our window - which it of course won't since our input hint
2067 * is set to false.
2069 if( (m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
2070 XSetInputFocus( getDisplay()->GetDisplay(), GDK_WINDOW_XWINDOW( m_pWindow->window ), RevertToParent, CurrentTime );
2072 else
2074 if( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
2075 gtk_window_present( GTK_WINDOW(m_pWindow) );
2080 void GtkSalFrame::SetPointer( PointerStyle ePointerStyle )
2082 if( m_pWindow && ePointerStyle != m_ePointerStyle )
2084 m_ePointerStyle = ePointerStyle;
2085 GdkCursor *pCursor = getDisplay()->getCursor( ePointerStyle );
2086 gdk_window_set_cursor( m_pWindow->window, pCursor );
2087 m_pCurrentCursor = pCursor;
2089 // #i80791# use grabPointer the same way as CaptureMouse, respective float grab
2090 if( getDisplay()->MouseCaptured( this ) )
2091 grabPointer( TRUE, FALSE );
2092 else if( m_nFloats > 0 )
2093 grabPointer( TRUE, TRUE );
2097 void GtkSalFrame::grabPointer( BOOL bGrab, BOOL bOwnerEvents )
2099 if( m_pWindow )
2101 if( bGrab )
2103 bool bUseGdkGrab = true;
2104 if( getDisplay()->getHaveSystemChildFrame() )
2106 const std::list< SalFrame* >& rFrames = getDisplay()->getFrames();
2107 for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
2109 const GtkSalFrame* pFrame = static_cast< const GtkSalFrame* >(*it);
2110 if( pFrame->m_bWindowIsGtkPlug )
2112 bUseGdkGrab = false;
2113 break;
2117 if( bUseGdkGrab )
2119 const int nMask = ( GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK );
2121 gdk_pointer_grab( m_pWindow->window, bOwnerEvents,
2122 (GdkEventMask) nMask, NULL, m_pCurrentCursor,
2123 GDK_CURRENT_TIME );
2125 else
2127 // FIXME: for some unknown reason gdk_pointer_grab does not
2128 // really produce owner events for GtkPlug windows
2129 // the cause is yet unknown
2131 // this is of course a bad hack, especially as we cannot
2132 // set the right cursor this way
2133 XGrabPointer( getDisplay()->GetDisplay(),
2134 GDK_WINDOW_XWINDOW( m_pWindow->window),
2135 bOwnerEvents,
2136 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
2137 GrabModeAsync,
2138 GrabModeAsync,
2139 None,
2140 None,
2141 CurrentTime
2146 else
2148 // Two GdkDisplays may be open
2149 gdk_display_pointer_ungrab( getGdkDisplay(), GDK_CURRENT_TIME);
2154 void GtkSalFrame::CaptureMouse( BOOL bCapture )
2156 getDisplay()->CaptureMouse( bCapture ? this : NULL );
2159 void GtkSalFrame::SetPointerPos( long nX, long nY )
2161 GtkSalFrame* pFrame = this;
2162 while( pFrame && pFrame->isChild( false, true ) )
2163 pFrame = pFrame->m_pParent;
2164 if( ! pFrame )
2165 return;
2167 GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(pFrame->m_pWindow) );
2168 GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
2170 /* #87921# when the application tries to center the mouse in the dialog the
2171 * window isn't mapped already. So use coordinates relative to the root window.
2173 unsigned int nWindowLeft = maGeometry.nX + nX;
2174 unsigned int nWindowTop = maGeometry.nY + nY;
2176 XWarpPointer( GDK_DISPLAY_XDISPLAY (pDisplay), None,
2177 GDK_WINDOW_XID (gdk_screen_get_root_window( pScreen ) ),
2178 0, 0, 0, 0, nWindowLeft, nWindowTop);
2179 // #i38648# ask for the next motion hint
2180 gint x, y;
2181 GdkModifierType mask;
2182 gdk_window_get_pointer( pFrame->m_pWindow->window, &x, &y, &mask );
2185 void GtkSalFrame::Flush()
2187 #ifdef HAVE_A_RECENT_GTK
2188 gdk_display_flush( getGdkDisplay() );
2189 #else
2190 XFlush (GDK_DISPLAY_XDISPLAY (getGdkDisplay()));
2191 #endif
2194 void GtkSalFrame::Sync()
2196 gdk_display_sync( getGdkDisplay() );
2199 String GtkSalFrame::GetSymbolKeyName( const String&, USHORT nKeyCode )
2201 return getDisplay()->GetKeyName( nKeyCode );
2204 String GtkSalFrame::GetKeyName( USHORT nKeyCode )
2206 return getDisplay()->GetKeyName( nKeyCode );
2209 GdkDisplay *GtkSalFrame::getGdkDisplay()
2211 return static_cast<GtkSalDisplay*>(GetX11SalData()->GetDisplay())->GetGdkDisplay();
2214 GtkSalDisplay *GtkSalFrame::getDisplay()
2216 return static_cast<GtkSalDisplay*>(GetX11SalData()->GetDisplay());
2219 SalFrame::SalPointerState GtkSalFrame::GetPointerState()
2221 SalPointerState aState;
2222 GdkScreen* pScreen;
2223 gint x, y;
2224 GdkModifierType aMask;
2225 gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
2226 aState.maPos = Point( x - maGeometry.nX, y - maGeometry.nY );
2227 aState.mnState = GetMouseModCode( aMask );
2228 return aState;
2231 SalFrame::SalIndicatorState GtkSalFrame::GetIndicatorState()
2233 SalIndicatorState aState;
2234 aState.mnState = GetX11SalData()->GetDisplay()->GetIndicatorState();
2235 return aState;
2238 void GtkSalFrame::SimulateKeyPress( USHORT nKeyCode )
2240 GetX11SalData()->GetDisplay()->SimulateKeyPress(nKeyCode);
2243 void GtkSalFrame::SetInputContext( SalInputContext* pContext )
2245 if( ! pContext )
2246 return;
2248 if( ! (pContext->mnOptions & SAL_INPUTCONTEXT_TEXT) )
2249 return;
2251 // create a new im context
2252 if( ! m_pIMHandler )
2253 m_pIMHandler = new IMHandler( this );
2254 m_pIMHandler->setInputContext( pContext );
2257 void GtkSalFrame::EndExtTextInput( USHORT nFlags )
2259 if( m_pIMHandler )
2260 m_pIMHandler->endExtTextInput( nFlags );
2263 BOOL GtkSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& )
2265 // not supported yet
2266 return FALSE;
2269 LanguageType GtkSalFrame::GetInputLanguage()
2271 return LANGUAGE_DONTKNOW;
2274 SalBitmap* GtkSalFrame::SnapShot()
2276 if( !m_pWindow )
2277 return NULL;
2279 X11SalBitmap *pBmp = new X11SalBitmap;
2280 GdkWindow *pWin = m_pWindow->window;
2281 if( pBmp->SnapShot( GDK_DISPLAY_XDISPLAY( getGdkDisplay() ),
2282 GDK_WINDOW_XID( pWin ) ) )
2283 return pBmp;
2284 else
2285 delete pBmp;
2287 return NULL;
2290 void GtkSalFrame::UpdateSettings( AllSettings& rSettings )
2292 if( ! m_pWindow )
2293 return;
2295 GtkSalGraphics* pGraphics = static_cast<GtkSalGraphics*>(m_aGraphics[0].pGraphics);
2296 bool bFreeGraphics = false;
2297 if( ! pGraphics )
2299 pGraphics = static_cast<GtkSalGraphics*>(GetGraphics());
2300 bFreeGraphics = true;
2303 pGraphics->updateSettings( rSettings );
2305 if( bFreeGraphics )
2306 ReleaseGraphics( pGraphics );
2309 void GtkSalFrame::Beep( SoundType eType )
2311 switch( eType )
2313 case SOUND_DEFAULT:
2314 case SOUND_ERROR:
2315 gdk_display_beep( getGdkDisplay() );
2316 break;
2317 default:
2318 break;
2322 const SystemEnvData* GtkSalFrame::GetSystemData() const
2324 return &m_aSystemData;
2327 void GtkSalFrame::SetParent( SalFrame* pNewParent )
2329 if( m_pParent )
2330 m_pParent->m_aChildren.remove( this );
2331 m_pParent = static_cast<GtkSalFrame*>(pNewParent);
2332 if( m_pParent )
2333 m_pParent->m_aChildren.push_back( this );
2334 if( ! isChild() )
2335 gtk_window_set_transient_for( GTK_WINDOW(m_pWindow),
2336 (m_pParent && ! m_pParent->isChild(true,false)) ? GTK_WINDOW(m_pParent->m_pWindow) : NULL
2340 void GtkSalFrame::createNewWindow( XLIB_Window aNewParent, bool bXEmbed, int nScreen )
2342 bool bWasVisible = GTK_WIDGET_MAPPED(m_pWindow);
2343 if( bWasVisible )
2344 Show( FALSE );
2346 if( nScreen < 0 || nScreen >= getDisplay()->GetScreenCount() )
2347 nScreen = m_nScreen;
2349 SystemParentData aParentData;
2350 aParentData.aWindow = aNewParent;
2351 aParentData.bXEmbedSupport = bXEmbed;
2352 if( aNewParent == None )
2354 aNewParent = getDisplay()->GetRootWindow(nScreen);
2355 aParentData.aWindow = None;
2356 aParentData.bXEmbedSupport = false;
2358 else
2360 // is new parent a root window ?
2361 Display* pDisp = getDisplay()->GetDisplay();
2362 int nScreens = getDisplay()->GetScreenCount();
2363 for( int i = 0; i < nScreens; i++ )
2365 if( aNewParent == RootWindow( pDisp, i ) )
2367 nScreen = i;
2368 aParentData.aWindow = None;
2369 aParentData.bXEmbedSupport = false;
2370 break;
2375 // first deinit frame
2376 if( m_pIMHandler )
2378 delete m_pIMHandler;
2379 m_pIMHandler = NULL;
2381 if( m_pRegion )
2382 gdk_region_destroy( m_pRegion );
2383 if( m_pFixedContainer )
2384 gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer) );
2385 if( m_pWindow )
2386 gtk_widget_destroy( m_pWindow );
2387 if( m_pForeignParent )
2388 g_object_unref( G_OBJECT(m_pForeignParent) );
2389 if( m_pForeignTopLevel )
2390 g_object_unref( G_OBJECT(m_pForeignTopLevel) );
2392 // init new window
2393 m_bDefaultPos = m_bDefaultSize = false;
2394 if( aParentData.aWindow != None )
2396 m_nStyle |= SAL_FRAME_STYLE_PLUG;
2397 Init( &aParentData );
2399 else
2401 m_nStyle &= ~SAL_FRAME_STYLE_PLUG;
2402 Init( (m_pParent && m_pParent->m_nScreen == m_nScreen) ? m_pParent : NULL, m_nStyle );
2405 // update graphics
2406 for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
2408 if( m_aGraphics[i].bInUse )
2410 m_aGraphics[i].pGraphics->SetDrawable( GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
2411 m_aGraphics[i].pGraphics->SetWindow( m_pWindow );
2415 if( m_aTitle.Len() )
2416 SetTitle( m_aTitle );
2418 if( bWasVisible )
2419 Show( TRUE );
2421 std::list< GtkSalFrame* > aChildren = m_aChildren;
2422 m_aChildren.clear();
2423 for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
2424 (*it)->createNewWindow( None, false, m_nScreen );
2426 // FIXME: SalObjects
2429 bool GtkSalFrame::SetPluginParent( SystemParentData* pSysParent )
2431 if( pSysParent ) // this may be the first system child frame now
2432 getDisplay()->setHaveSystemChildFrame();
2433 createNewWindow( pSysParent->aWindow, (pSysParent->nSize > sizeof(long)) ? pSysParent->bXEmbedSupport : false, m_nScreen );
2434 return true;
2437 void GtkSalFrame::ResetClipRegion()
2439 if( m_pWindow )
2440 gdk_window_shape_combine_region( m_pWindow->window, NULL, 0, 0 );
2443 void GtkSalFrame::BeginSetClipRegion( ULONG )
2445 if( m_pRegion )
2446 gdk_region_destroy( m_pRegion );
2447 m_pRegion = gdk_region_new();
2450 void GtkSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
2452 if( m_pRegion )
2454 GdkRectangle aRect;
2455 aRect.x = nX;
2456 aRect.y = nY;
2457 aRect.width = nWidth;
2458 aRect.height = nHeight;
2460 gdk_region_union_with_rect( m_pRegion, &aRect );
2464 void GtkSalFrame::EndSetClipRegion()
2466 if( m_pWindow && m_pRegion )
2467 gdk_window_shape_combine_region( m_pWindow->window, m_pRegion, 0, 0 );
2470 bool GtkSalFrame::Dispatch( const XEvent* pEvent )
2472 bool bContinueDispatch = true;
2474 if( pEvent->type == PropertyNotify )
2476 vcl_sal::WMAdaptor* pAdaptor = getDisplay()->getWMAdaptor();
2477 Atom nDesktopAtom = pAdaptor->getAtom( vcl_sal::WMAdaptor::NET_WM_DESKTOP );
2478 if( pEvent->xproperty.atom == nDesktopAtom &&
2479 pEvent->xproperty.state == PropertyNewValue )
2481 m_nWorkArea = pAdaptor->getWindowWorkArea( GDK_WINDOW_XWINDOW( m_pWindow->window) );
2484 else if( pEvent->type == ConfigureNotify )
2486 if( m_pForeignParent && pEvent->xconfigure.window == m_aForeignParentWindow )
2488 bContinueDispatch = false;
2489 gtk_window_resize( GTK_WINDOW(m_pWindow), pEvent->xconfigure.width, pEvent->xconfigure.height );
2490 if( ( sal::static_int_cast< int >(maGeometry.nWidth) !=
2491 pEvent->xconfigure.width ) ||
2492 ( sal::static_int_cast< int >(maGeometry.nHeight) !=
2493 pEvent->xconfigure.height ) )
2495 maGeometry.nWidth = pEvent->xconfigure.width;
2496 maGeometry.nHeight = pEvent->xconfigure.height;
2497 setMinMaxSize();
2498 getDisplay()->SendInternalEvent( this, NULL, SALEVENT_RESIZE );
2501 else if( m_pForeignTopLevel && pEvent->xconfigure.window == m_aForeignTopLevelWindow )
2503 bContinueDispatch = false;
2504 // update position
2505 int x = 0, y = 0;
2506 XLIB_Window aChild;
2507 XTranslateCoordinates( getDisplay()->GetDisplay(),
2508 GDK_WINDOW_XWINDOW( m_pWindow->window),
2509 getDisplay()->GetRootWindow( getDisplay()->GetDefaultScreenNumber() ),
2510 0, 0,
2511 &x, &y,
2512 &aChild );
2513 if( x != maGeometry.nX || y != maGeometry.nY )
2515 maGeometry.nX = x;
2516 maGeometry.nY = y;
2517 getDisplay()->SendInternalEvent( this, NULL, SALEVENT_MOVE );
2521 else if( pEvent->type == ClientMessage &&
2522 pEvent->xclient.message_type == getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED ) &&
2523 pEvent->xclient.window == GDK_WINDOW_XWINDOW(m_pWindow->window) &&
2524 m_bWindowIsGtkPlug
2527 // FIXME: this should not be necessary, GtkPlug should do this
2528 // transparently for us
2529 if( pEvent->xclient.data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
2530 pEvent->xclient.data.l[1] == 2 // XEMBED_WINDOW_DEACTIVATE
2533 GdkEventFocus aEvent;
2534 aEvent.type = GDK_FOCUS_CHANGE;
2535 aEvent.window = m_pWindow->window;
2536 aEvent.send_event = TRUE;
2537 aEvent.in = (pEvent->xclient.data.l[1] == 1);
2538 signalFocus( m_pWindow, &aEvent, this );
2542 return bContinueDispatch;
2545 void GtkSalFrame::SetBackgroundBitmap( SalBitmap* pBitmap )
2547 if( m_hBackgroundPixmap )
2549 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
2550 GDK_WINDOW_XWINDOW(m_pWindow->window),
2551 None );
2552 XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap );
2553 m_hBackgroundPixmap = None;
2555 if( pBitmap )
2557 X11SalBitmap* pBM = static_cast<X11SalBitmap*>(pBitmap);
2558 Size aSize = pBM->GetSize();
2559 if( aSize.Width() && aSize.Height() )
2561 m_hBackgroundPixmap =
2562 XCreatePixmap( getDisplay()->GetDisplay(),
2563 GDK_WINDOW_XWINDOW(m_pWindow->window),
2564 aSize.Width(),
2565 aSize.Height(),
2566 getDisplay()->GetVisual(m_nScreen).GetDepth() );
2567 if( m_hBackgroundPixmap )
2569 SalTwoRect aTwoRect;
2570 aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
2571 aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width();
2572 aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height();
2573 pBM->ImplDraw( m_hBackgroundPixmap,
2574 m_nScreen,
2575 getDisplay()->GetVisual(m_nScreen).GetDepth(),
2576 aTwoRect,
2577 getDisplay()->GetCopyGC(m_nScreen) );
2578 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
2579 GDK_WINDOW_XWINDOW(m_pWindow->window),
2580 m_hBackgroundPixmap );
2586 gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame )
2588 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2589 SalMouseEvent aEvent;
2590 USHORT nEventType = 0;
2591 switch( pEvent->type )
2593 case GDK_BUTTON_PRESS:
2594 nEventType = SALEVENT_MOUSEBUTTONDOWN;
2595 break;
2596 case GDK_BUTTON_RELEASE:
2597 nEventType = SALEVENT_MOUSEBUTTONUP;
2598 break;
2599 default:
2600 return FALSE;
2602 switch( pEvent->button )
2604 case 1: aEvent.mnButton = MOUSE_LEFT; break;
2605 case 2: aEvent.mnButton = MOUSE_MIDDLE; break;
2606 case 3: aEvent.mnButton = MOUSE_RIGHT; break;
2607 default: return FALSE;
2609 aEvent.mnTime = pEvent->time;
2610 aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
2611 aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
2612 aEvent.mnCode = GetMouseModCode( pEvent->state );
2614 bool bClosePopups = false;
2615 if( pEvent->type == GDK_BUTTON_PRESS &&
2616 (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) == 0
2619 if( m_nFloats > 0 )
2621 // close popups if user clicks outside our application
2622 gint x, y;
2623 bClosePopups = (gdk_display_get_window_at_pointer( pThis->getGdkDisplay(), &x, &y ) == NULL);
2625 /* #i30306# release implicit pointer grab if no popups are open; else
2626 * Drag cannot grab the pointer and will fail.
2628 if( m_nFloats < 1 || bClosePopups )
2629 gdk_display_pointer_ungrab( pThis->getGdkDisplay(), GDK_CURRENT_TIME );
2632 GTK_YIELD_GRAB();
2634 if( pThis->m_bWindowIsGtkPlug &&
2635 pEvent->type == GDK_BUTTON_PRESS &&
2636 pEvent->button == 1 )
2638 pThis->askForXEmbedFocus( pEvent->time );
2641 // --- RTL --- (mirror mouse pos)
2642 if( Application::GetSettings().GetLayoutRTL() )
2643 aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
2645 vcl::DeletionListener aDel( pThis );
2647 pThis->CallCallback( nEventType, &aEvent );
2649 if( ! aDel.isDeleted() )
2651 if( bClosePopups )
2653 ImplSVData* pSVData = ImplGetSVData();
2654 if ( pSVData->maWinData.mpFirstFloat )
2656 static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
2657 if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) && !(pEnv && *pEnv) )
2658 pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
2662 if( ! aDel.isDeleted() )
2664 int frame_x = (int)(pEvent->x_root - pEvent->x);
2665 int frame_y = (int)(pEvent->y_root - pEvent->y);
2666 if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
2668 pThis->maGeometry.nX = frame_x;
2669 pThis->maGeometry.nY = frame_y;
2670 pThis->CallCallback( SALEVENT_MOVE, NULL );
2675 return FALSE;
2678 gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEvent* pEvent, gpointer frame )
2680 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2681 GdkEventScroll* pSEvent = (GdkEventScroll*)pEvent;
2683 static ULONG nLines = 0;
2684 if( ! nLines )
2686 char* pEnv = getenv( "SAL_WHEELLINES" );
2687 nLines = pEnv ? atoi( pEnv ) : 3;
2688 if( nLines > 10 )
2689 nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
2692 bool bNeg = (pSEvent->direction == GDK_SCROLL_DOWN || pSEvent->direction == GDK_SCROLL_RIGHT );
2693 SalWheelMouseEvent aEvent;
2694 aEvent.mnTime = pSEvent->time;
2695 aEvent.mnX = (ULONG)pSEvent->x;
2696 aEvent.mnY = (ULONG)pSEvent->y;
2697 aEvent.mnDelta = bNeg ? -120 : 120;
2698 aEvent.mnNotchDelta = bNeg ? -1 : 1;
2699 aEvent.mnScrollLines = nLines;
2700 aEvent.mnCode = GetMouseModCode( pSEvent->state );
2701 aEvent.mbHorz = (pSEvent->direction == GDK_SCROLL_LEFT || pSEvent->direction == GDK_SCROLL_RIGHT);
2703 GTK_YIELD_GRAB();
2705 // --- RTL --- (mirror mouse pos)
2706 if( Application::GetSettings().GetLayoutRTL() )
2707 aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
2709 pThis->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
2711 return FALSE;
2714 gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer frame )
2716 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2718 SalMouseEvent aEvent;
2719 aEvent.mnTime = pEvent->time;
2720 aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
2721 aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
2722 aEvent.mnCode = GetMouseModCode( pEvent->state );
2723 aEvent.mnButton = 0;
2726 GTK_YIELD_GRAB();
2728 // --- RTL --- (mirror mouse pos)
2729 if( Application::GetSettings().GetLayoutRTL() )
2730 aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
2732 vcl::DeletionListener aDel( pThis );
2734 pThis->CallCallback( SALEVENT_MOUSEMOVE, &aEvent );
2736 if( ! aDel.isDeleted() )
2738 int frame_x = (int)(pEvent->x_root - pEvent->x);
2739 int frame_y = (int)(pEvent->y_root - pEvent->y);
2740 if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
2742 pThis->maGeometry.nX = frame_x;
2743 pThis->maGeometry.nY = frame_y;
2744 pThis->CallCallback( SALEVENT_MOVE, NULL );
2747 if( ! aDel.isDeleted() )
2749 // ask for the next hint
2750 gint x, y;
2751 GdkModifierType mask;
2752 gdk_window_get_pointer( GTK_WIDGET(pThis->m_pWindow)->window, &x, &y, &mask );
2756 return TRUE;
2759 gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpointer frame )
2761 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2762 SalMouseEvent aEvent;
2763 aEvent.mnTime = pEvent->time;
2764 aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
2765 aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
2766 aEvent.mnCode = GetMouseModCode( pEvent->state );
2767 aEvent.mnButton = 0;
2769 GTK_YIELD_GRAB();
2770 pThis->CallCallback( (pEvent->type == GDK_ENTER_NOTIFY) ? SALEVENT_MOUSEMOVE : SALEVENT_MOUSELEAVE, &aEvent );
2772 return TRUE;
2776 gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer frame )
2778 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2780 struct SalPaintEvent aEvent( pEvent->area.x, pEvent->area.y, pEvent->area.width, pEvent->area.height );
2782 GTK_YIELD_GRAB();
2783 pThis->CallCallback( SALEVENT_PAINT, &aEvent );
2785 return FALSE;
2788 gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame )
2790 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2792 GTK_YIELD_GRAB();
2794 // check if printers have changed (analogous to salframe focus handler)
2795 vcl_sal::PrinterUpdate::update();
2797 if( !pEvent->in )
2799 pThis->m_nKeyModifiers = 0;
2800 pThis->m_bSingleAltPress = false;
2801 pThis->m_bSendModChangeOnRelease = false;
2804 if( pThis->m_pIMHandler )
2805 pThis->m_pIMHandler->focusChanged( pEvent->in );
2807 // ask for changed printers like generic implementation
2808 if( pEvent->in )
2809 if( static_cast< X11SalInstance* >(GetSalData()->m_pInstance)->isPrinterInit() )
2810 vcl_sal::PrinterUpdate::update();
2812 // FIXME: find out who the hell steals the focus from our frame
2813 // while we have the pointer grabbed, this should not come from
2814 // the window manager. Is this an event that was still queued ?
2815 // The focus does not seem to get set inside our process
2817 // in the meantime do not propagate focus get/lose if floats are open
2818 if( m_nFloats == 0 )
2819 pThis->CallCallback( pEvent->in ? SALEVENT_GETFOCUS : SALEVENT_LOSEFOCUS, NULL );
2821 return FALSE;
2824 gboolean GtkSalFrame::signalMap( GtkWidget*, GdkEvent*, gpointer frame )
2826 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2828 GTK_YIELD_GRAB();
2830 if( ImplGetSVData()->mbIsTestTool )
2832 /* #i76541# testtool needs the focus to be in a new document
2833 * however e.g. metacity does not necessarily put the focus into
2834 * a newly shown window. An extra little hint seems to help here.
2835 * however we don't want to interfere with the normal user experience
2836 * so this is done when running in testtool only
2838 if( ! pThis->m_pParent && (pThis->m_nStyle & SAL_FRAME_STYLE_MOVEABLE) != 0 )
2839 XSetInputFocus( pThis->getDisplay()->GetDisplay(),
2840 GDK_WINDOW_XWINDOW( GTK_WIDGET(pThis->m_pWindow)->window),
2841 RevertToParent, CurrentTime );
2844 pThis->CallCallback( SALEVENT_RESIZE, NULL );
2846 return FALSE;
2849 gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame )
2851 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2853 GTK_YIELD_GRAB();
2854 pThis->CallCallback( SALEVENT_RESIZE, NULL );
2856 return FALSE;
2859 gboolean GtkSalFrame::signalConfigure( GtkWidget*, GdkEventConfigure* pEvent, gpointer frame )
2861 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2863 bool bMoved = false, bSized = false;
2864 int x = pEvent->x, y = pEvent->y;
2866 /* HACK: during sizing/moving a toolbar pThis->maGeometry is actually
2867 * already exact; even worse: due to the asynchronicity of configure
2868 * events the borderwindow which would evaluate this event
2869 * would size/move based on wrong data if we would actually evaluate
2870 * this event. So let's swallow it; this is also a performance
2871 * improvement as one can omit the synchronous XTranslateCoordinates
2872 * call below.
2874 if( (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
2875 pThis->getDisplay()->GetCaptureFrame() == pThis )
2876 return FALSE;
2879 // in child case the coordinates are not root coordinates,
2880 // need to transform
2882 /* #i31785# sadly one cannot really trust the x,y members of the event;
2883 * they are e.g. not set correctly on maximize/demaximize; this rather
2884 * sounds like a bug in gtk we have to workaround.
2886 XLIB_Window aChild;
2887 XTranslateCoordinates( pThis->getDisplay()->GetDisplay(),
2888 GDK_WINDOW_XWINDOW(GTK_WIDGET(pThis->m_pWindow)->window),
2889 pThis->getDisplay()->GetRootWindow( pThis->getDisplay()->GetDefaultScreenNumber() ),
2890 0, 0,
2891 &x, &y,
2892 &aChild );
2894 if( x != pThis->maGeometry.nX || y != pThis->maGeometry.nY )
2896 bMoved = true;
2897 pThis->maGeometry.nX = x;
2898 pThis->maGeometry.nY = y;
2900 /* #i86302#
2901 * for non sizeable windows we set the min and max hint for the window manager to
2902 * achieve correct sizing. However this is asynchronous and e.g. on Compiz
2903 * it sometimes happens that the window gets resized to another size (some default)
2904 * if we update the size here, subsequent setMinMaxSize will use this wrong size
2905 * - which is not good since the window manager will now size the window back to this
2906 * wrong size at some point.
2908 if( (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)) == SAL_FRAME_STYLE_SIZEABLE )
2910 if( pEvent->width != (int)pThis->maGeometry.nWidth || pEvent->height != (int)pThis->maGeometry.nHeight )
2912 bSized = true;
2913 pThis->maGeometry.nWidth = pEvent->width;
2914 pThis->maGeometry.nHeight = pEvent->height;
2918 // update decoration hints
2919 if( ! (pThis->m_nStyle & SAL_FRAME_STYLE_PLUG) )
2921 GdkRectangle aRect;
2922 gdk_window_get_frame_extents( GTK_WIDGET(pThis->m_pWindow)->window, &aRect );
2923 pThis->maGeometry.nTopDecoration = y - aRect.y;
2924 pThis->maGeometry.nBottomDecoration = aRect.y + aRect.height - y - pEvent->height;
2925 pThis->maGeometry.nLeftDecoration = x - aRect.x;
2926 pThis->maGeometry.nRightDecoration = aRect.x + aRect.width - x - pEvent->width;
2928 else
2930 pThis->maGeometry.nTopDecoration =
2931 pThis->maGeometry.nBottomDecoration =
2932 pThis->maGeometry.nLeftDecoration =
2933 pThis->maGeometry.nRightDecoration = 0;
2936 GTK_YIELD_GRAB();
2937 pThis->updateScreenNumber();
2938 if( bMoved && bSized )
2939 pThis->CallCallback( SALEVENT_MOVERESIZE, NULL );
2940 else if( bMoved )
2941 pThis->CallCallback( SALEVENT_MOVE, NULL );
2942 else if( bSized )
2943 pThis->CallCallback( SALEVENT_RESIZE, NULL );
2945 return FALSE;
2948 gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame )
2950 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2952 vcl::DeletionListener aDel( pThis );
2954 if( pThis->m_pIMHandler )
2956 if( pThis->m_pIMHandler->handleKeyEvent( pEvent ) )
2958 pThis->m_bSingleAltPress = false;
2959 return TRUE;
2962 GTK_YIELD_GRAB();
2964 // handle modifiers
2965 if( pEvent->keyval == GDK_Shift_L || pEvent->keyval == GDK_Shift_R ||
2966 pEvent->keyval == GDK_Control_L || pEvent->keyval == GDK_Control_R ||
2967 pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ||
2968 pEvent->keyval == GDK_Meta_L || pEvent->keyval == GDK_Meta_R )
2970 SalKeyModEvent aModEvt;
2972 USHORT nModCode = GetKeyModCode( pEvent->state );
2974 aModEvt.mnModKeyCode = 0; // emit no MODKEYCHANGE events
2975 if( pEvent->type == GDK_KEY_PRESS && !pThis->m_nKeyModifiers )
2976 pThis->m_bSendModChangeOnRelease = true;
2978 else if( pEvent->type == GDK_KEY_RELEASE &&
2979 pThis->m_bSendModChangeOnRelease )
2981 aModEvt.mnModKeyCode = pThis->m_nKeyModifiers;
2982 pThis->m_nKeyModifiers = 0;
2985 USHORT nExtModMask = 0;
2986 USHORT nModMask = 0;
2987 // pressing just the ctrl key leads to a keysym of XK_Control but
2988 // the event state does not contain ControlMask. In the release
2989 // event its the other way round: it does contain the Control mask.
2990 // The modifier mode therefore has to be adapted manually.
2991 switch( pEvent->keyval )
2993 #ifdef MACOSX
2994 case GDK_Meta_L: // map Meta (aka Command key) to Ctrl
2995 #endif
2996 case GDK_Control_L:
2997 nExtModMask = MODKEY_LMOD1;
2998 nModMask = KEY_MOD1;
2999 break;
3000 #ifdef MACOSX
3001 case GDK_Meta_R: // map Meta (aka Command key) to Ctrl
3002 #endif
3003 case GDK_Control_R:
3004 nExtModMask = MODKEY_RMOD1;
3005 nModMask = KEY_MOD1;
3006 break;
3007 case GDK_Alt_L:
3008 nExtModMask = MODKEY_LMOD2;
3009 #ifdef MACOSX
3010 nModMask = KEY_MOD3;
3011 #else
3012 nModMask = KEY_MOD2;
3013 #endif
3014 break;
3015 case GDK_Alt_R:
3016 nExtModMask = MODKEY_RMOD2;
3017 #ifdef MACOSX
3018 nModMask = KEY_MOD2 | (pEvent->type == GDK_KEY_RELEASE ? KEY_MOD3 : 0);
3019 #else
3020 nModMask = KEY_MOD2;
3021 #endif
3022 break;
3023 case GDK_Shift_L:
3024 nExtModMask = MODKEY_LSHIFT;
3025 nModMask = KEY_SHIFT;
3026 break;
3027 case GDK_Shift_R:
3028 nExtModMask = MODKEY_RSHIFT;
3029 nModMask = KEY_SHIFT;
3030 break;
3032 if( pEvent->type == GDK_KEY_RELEASE )
3034 nModCode &= ~nModMask;
3035 pThis->m_nKeyModifiers &= ~nExtModMask;
3037 else
3039 nModCode |= nModMask;
3040 pThis->m_nKeyModifiers |= nExtModMask;
3043 aModEvt.mnCode = nModCode;
3044 aModEvt.mnTime = pEvent->time;
3046 pThis->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
3048 if( ! aDel.isDeleted() )
3050 // emulate KEY_MENU
3051 if( ( pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ) &&
3052 ( nModCode & ~(KEY_MOD3|KEY_MOD2)) == 0 )
3054 if( pEvent->type == GDK_KEY_PRESS )
3055 pThis->m_bSingleAltPress = true;
3057 else if( pThis->m_bSingleAltPress )
3059 SalKeyEvent aKeyEvt;
3061 aKeyEvt.mnCode = KEY_MENU | nModCode;
3062 aKeyEvt.mnRepeat = 0;
3063 aKeyEvt.mnTime = pEvent->time;
3064 aKeyEvt.mnCharCode = 0;
3066 // simulate KEY_MENU
3067 pThis->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
3068 if( ! aDel.isDeleted() )
3070 pThis->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
3071 pThis->m_bSingleAltPress = false;
3075 else
3076 pThis->m_bSingleAltPress = false;
3079 else
3081 pThis->doKeyCallback( pEvent->state,
3082 pEvent->keyval,
3083 pEvent->hardware_keycode,
3084 pEvent->group,
3085 pEvent->time,
3086 sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )),
3087 (pEvent->type == GDK_KEY_PRESS),
3088 false );
3089 if( ! aDel.isDeleted() )
3091 pThis->m_bSendModChangeOnRelease = false;
3092 pThis->m_bSingleAltPress = false;
3096 if( !aDel.isDeleted() && pThis->m_pIMHandler )
3097 pThis->m_pIMHandler->updateIMSpotLocation();
3099 return TRUE;
3102 gboolean GtkSalFrame::signalDelete( GtkWidget*, GdkEvent*, gpointer frame )
3104 GtkSalFrame* pThis = (GtkSalFrame*)frame;
3106 GTK_YIELD_GRAB();
3107 pThis->CallCallback( SALEVENT_CLOSE, NULL );
3109 return TRUE;
3112 void GtkSalFrame::signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer frame )
3114 GtkSalFrame* pThis = (GtkSalFrame*)frame;
3116 // every frame gets an initial style set on creation
3117 // do not post these as the whole application tends to
3118 // redraw itself to adjust to the new style
3119 // where there IS no new style resulting in tremendous unnecessary flickering
3120 if( pPrevious != NULL )
3121 // signalStyleSet does NOT usually have the gdk lock
3122 // so post user event to safely dispatch the SALEVENT_SETTINGSCHANGED
3123 // note: settings changed for multiple frames is avoided in winproc.cxx ImplHandleSettings
3124 pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_SETTINGSCHANGED );
3126 /* #i64117# gtk sets a nice background pixmap
3127 * but we actually don't really want that, so save
3128 * some time on the Xserver as well as prevent
3129 * some paint issues
3131 GdkWindow* pWin = GTK_WIDGET(pThis->getWindow())->window;
3132 if( pWin )
3134 XLIB_Window aWin = GDK_WINDOW_XWINDOW(pWin);
3135 if( aWin != None )
3136 XSetWindowBackgroundPixmap( pThis->getDisplay()->GetDisplay(),
3137 aWin,
3138 pThis->m_hBackgroundPixmap );
3141 if( ! pThis->m_pParent )
3143 // signalize theme changed for NWF caches
3144 // FIXME: should be called only once for a style change
3145 GtkSalGraphics::bThemeChanged = TRUE;
3149 gboolean GtkSalFrame::signalState( GtkWidget*, GdkEvent* pEvent, gpointer frame )
3151 GtkSalFrame* pThis = (GtkSalFrame*)frame;
3152 if( (pThis->m_nState & GDK_WINDOW_STATE_ICONIFIED) != (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED ) )
3153 pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_RESIZE );
3155 if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) &&
3156 ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) )
3158 pThis->m_aRestorePosSize =
3159 Rectangle( Point( pThis->maGeometry.nX, pThis->maGeometry.nY ),
3160 Size( pThis->maGeometry.nWidth, pThis->maGeometry.nHeight ) );
3162 pThis->m_nState = pEvent->window_state.new_window_state;
3164 return FALSE;
3167 gboolean GtkSalFrame::signalVisibility( GtkWidget*, GdkEventVisibility* pEvent, gpointer frame )
3169 GtkSalFrame* pThis = (GtkSalFrame*)frame;
3170 pThis->m_nVisibility = pEvent->state;
3172 return FALSE;
3175 void GtkSalFrame::signalDestroy( GtkObject* pObj, gpointer frame )
3177 GtkSalFrame* pThis = (GtkSalFrame*)frame;
3178 if( GTK_WIDGET( pObj ) == pThis->m_pWindow )
3180 pThis->m_pFixedContainer = NULL;
3181 pThis->m_pWindow = NULL;
3185 // ----------------------------------------------------------------------
3186 // GtkSalFrame::IMHandler
3187 // ----------------------------------------------------------------------
3189 GtkSalFrame::IMHandler::IMHandler( GtkSalFrame* pFrame )
3190 : m_pFrame(pFrame),
3191 m_nPrevKeyPresses( 0 ),
3192 m_pIMContext( NULL ),
3193 m_bFocused( true )
3195 m_aInputEvent.mpTextAttr = NULL;
3196 createIMContext();
3199 GtkSalFrame::IMHandler::~IMHandler()
3201 // cancel an eventual event posted to begin preedit again
3202 m_pFrame->getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3203 deleteIMContext();
3206 void GtkSalFrame::IMHandler::createIMContext()
3208 if( ! m_pIMContext )
3210 m_pIMContext = gtk_im_multicontext_new ();
3211 g_signal_connect( m_pIMContext, "commit",
3212 G_CALLBACK (signalIMCommit), this );
3213 g_signal_connect( m_pIMContext, "preedit_changed",
3214 G_CALLBACK (signalIMPreeditChanged), this );
3215 g_signal_connect( m_pIMContext, "retrieve_surrounding",
3216 G_CALLBACK (signalIMRetrieveSurrounding), this );
3217 g_signal_connect( m_pIMContext, "delete_surrounding",
3218 G_CALLBACK (signalIMDeleteSurrounding), this );
3219 g_signal_connect( m_pIMContext, "preedit_start",
3220 G_CALLBACK (signalIMPreeditStart), this );
3221 g_signal_connect( m_pIMContext, "preedit_end",
3222 G_CALLBACK (signalIMPreeditEnd), this );
3224 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3225 gtk_im_context_set_client_window( m_pIMContext, GTK_WIDGET(m_pFrame->m_pWindow)->window );
3226 gtk_im_context_focus_in( m_pIMContext );
3227 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3228 m_bFocused = true;
3232 void GtkSalFrame::IMHandler::deleteIMContext()
3234 if( m_pIMContext )
3236 // first give IC a chance to deinitialize
3237 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3238 gtk_im_context_set_client_window( m_pIMContext, NULL );
3239 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3240 // destroy old IC
3241 g_object_unref( m_pIMContext );
3242 m_pIMContext = NULL;
3246 void GtkSalFrame::IMHandler::doCallEndExtTextInput()
3248 m_aInputEvent.mpTextAttr = NULL;
3249 m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
3252 void GtkSalFrame::IMHandler::updateIMSpotLocation()
3254 SalExtTextInputPosEvent aPosEvent;
3255 m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent );
3256 GdkRectangle aArea;
3257 aArea.x = aPosEvent.mnX;
3258 aArea.y = aPosEvent.mnY;
3259 aArea.width = aPosEvent.mnWidth;
3260 aArea.height = aPosEvent.mnHeight;
3261 gtk_im_context_set_cursor_location( m_pIMContext, &aArea );
3264 void GtkSalFrame::IMHandler::setInputContext( SalInputContext* )
3268 void GtkSalFrame::IMHandler::sendEmptyCommit()
3270 vcl::DeletionListener aDel( m_pFrame );
3272 SalExtTextInputEvent aEmptyEv;
3273 aEmptyEv.mnTime = 0;
3274 aEmptyEv.mpTextAttr = 0;
3275 aEmptyEv.maText = String();
3276 aEmptyEv.mnCursorPos = 0;
3277 aEmptyEv.mnCursorFlags = 0;
3278 aEmptyEv.mnDeltaStart = 0;
3279 aEmptyEv.mbOnlyCursor = False;
3280 m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv );
3281 if( ! aDel.isDeleted() )
3282 m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
3285 void GtkSalFrame::IMHandler::endExtTextInput( USHORT /*nFlags*/ )
3287 gtk_im_context_reset ( m_pIMContext );
3289 if( m_aInputEvent.mpTextAttr )
3291 vcl::DeletionListener aDel( m_pFrame );
3292 // delete preedit in sal (commit an empty string)
3293 sendEmptyCommit();
3294 if( ! aDel.isDeleted() )
3296 // mark previous preedit state again (will e.g. be sent at focus gain)
3297 m_aInputEvent.mpTextAttr = &m_aInputFlags[0];
3298 if( m_bFocused )
3300 // begin preedit again
3301 m_pFrame->getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3307 void GtkSalFrame::IMHandler::focusChanged( bool bFocusIn )
3309 m_bFocused = bFocusIn;
3310 if( bFocusIn )
3312 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3313 gtk_im_context_focus_in( m_pIMContext );
3314 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3315 if( m_aInputEvent.mpTextAttr )
3317 sendEmptyCommit();
3318 // begin preedit again
3319 m_pFrame->getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3322 else
3324 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3325 gtk_im_context_focus_out( m_pIMContext );
3326 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3327 // cancel an eventual event posted to begin preedit again
3328 m_pFrame->getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3332 bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent )
3334 vcl::DeletionListener aDel( m_pFrame );
3336 if( pEvent->type == GDK_KEY_PRESS )
3338 // Add this key press event to the list of previous key presses
3339 // to which we compare key release events. If a later key release
3340 // event has a matching key press event in this list, we swallow
3341 // the key release because some GTK Input Methods don't swallow it
3342 // for us.
3343 m_aPrevKeyPresses.push_back( PreviousKeyPress(pEvent) );
3344 m_nPrevKeyPresses++;
3346 // Also pop off the earliest key press event if there are more than 10
3347 // already.
3348 while (m_nPrevKeyPresses > 10)
3350 m_aPrevKeyPresses.pop_front();
3351 m_nPrevKeyPresses--;
3354 GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
3356 // #i51353# update spot location on every key input since we cannot
3357 // know which key may activate a preedit choice window
3358 updateIMSpotLocation();
3359 if( aDel.isDeleted() )
3360 return true;
3362 gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
3363 g_object_unref( pRef );
3365 if( aDel.isDeleted() )
3366 return true;
3368 if( bResult )
3369 return true;
3370 else
3372 DBG_ASSERT( m_nPrevKeyPresses > 0, "key press has vanished !" );
3373 if( ! m_aPrevKeyPresses.empty() ) // sanity check
3375 // event was not swallowed, do not filter a following
3376 // key release event
3377 // note: this relies on gtk_im_context_filter_keypress
3378 // returning without calling a handler (in the "not swallowed"
3379 // case ) which might change the previous key press list so
3380 // we would pop the wrong event here
3381 m_aPrevKeyPresses.pop_back();
3382 m_nPrevKeyPresses--;
3387 // Determine if we got an earlier key press event corresponding to this key release
3388 if (pEvent->type == GDK_KEY_RELEASE)
3390 GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
3391 gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
3392 g_object_unref( pRef );
3394 if( aDel.isDeleted() )
3395 return true;
3397 std::list<PreviousKeyPress>::iterator iter = m_aPrevKeyPresses.begin();
3398 std::list<PreviousKeyPress>::iterator iter_end = m_aPrevKeyPresses.end();
3399 while (iter != iter_end)
3401 // If we found a corresponding previous key press event, swallow the release
3402 // and remove the earlier key press from our list
3403 if (*iter == pEvent)
3405 m_aPrevKeyPresses.erase(iter);
3406 m_nPrevKeyPresses--;
3407 return true;
3409 ++iter;
3412 if( bResult )
3413 return true;
3416 return false;
3419 /* FIXME:
3420 * #122282# still more hacking: some IMEs never start a preedit but simply commit
3421 * in this case we cannot commit a single character. Workaround: do not do the
3422 * single key hack for enter or space if the unicode commited does not match
3425 static bool checkSingleKeyCommitHack( guint keyval, sal_Unicode cCode )
3427 bool bRet = true;
3428 switch( keyval )
3430 case GDK_KP_Enter:
3431 case GDK_Return:
3432 if( cCode != '\n' && cCode != '\r' )
3433 bRet = false;
3434 break;
3435 case GDK_space:
3436 case GDK_KP_Space:
3437 if( cCode != ' ' )
3438 bRet = false;
3439 break;
3440 default:
3441 break;
3443 return bRet;
3446 #ifdef SOLARIS
3447 #define CONTEXT_ARG pContext
3448 #else
3449 #define CONTEXT_ARG EMPTYARG
3450 #endif
3451 void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* CONTEXT_ARG, gchar* pText, gpointer im_handler )
3453 GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
3455 vcl::DeletionListener aDel( pThis->m_pFrame );
3456 // open a block that will end the GTK_YIELD_GRAB before calling preedit changed again
3458 GTK_YIELD_GRAB();
3460 bool bWasPreedit = (pThis->m_aInputEvent.mpTextAttr != 0);
3462 pThis->m_aInputEvent.mnTime = 0;
3463 pThis->m_aInputEvent.mpTextAttr = 0;
3464 pThis->m_aInputEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 );
3465 pThis->m_aInputEvent.mnCursorPos = pThis->m_aInputEvent.maText.Len();
3466 pThis->m_aInputEvent.mnCursorFlags = 0;
3467 pThis->m_aInputEvent.mnDeltaStart = 0;
3468 pThis->m_aInputEvent.mbOnlyCursor = False;
3470 pThis->m_aInputFlags.clear();
3472 /* necessary HACK: all keyboard input comes in here as soon as a IMContext is set
3473 * which is logical and consequent. But since even simple input like
3474 * <space> comes through the commit signal instead of signalKey
3475 * and all kinds of windows only implement KeyInput (e.g. PushButtons,
3476 * RadioButtons and a lot of other Controls), will send a single
3477 * KeyInput/KeyUp sequence instead of an ExtText event if there
3478 * never was a preedit and the text is only one character.
3480 * In this case there the last ExtText event must have been
3481 * SALEVENT_ENDEXTTEXTINPUT, either because of a regular commit
3482 * or because there never was a preedit.
3484 bool bSingleCommit = false;
3485 if( ! bWasPreedit
3486 && pThis->m_aInputEvent.maText.Len() == 1
3487 && ! pThis->m_aPrevKeyPresses.empty()
3490 const PreviousKeyPress& rKP = pThis->m_aPrevKeyPresses.back();
3491 sal_Unicode aOrigCode = pThis->m_aInputEvent.maText.GetChar(0);
3493 if( checkSingleKeyCommitHack( rKP.keyval, aOrigCode ) )
3495 pThis->m_pFrame->doKeyCallback( rKP.state, rKP.keyval, rKP.hardware_keycode, rKP.group, rKP.time, aOrigCode, true, true );
3496 bSingleCommit = true;
3500 if( ! bSingleCommit )
3502 pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
3503 if( ! aDel.isDeleted() )
3504 pThis->doCallEndExtTextInput();
3506 if( ! aDel.isDeleted() )
3508 // reset input event
3509 pThis->m_aInputEvent.maText = String();
3510 pThis->m_aInputEvent.mnCursorPos = 0;
3511 pThis->updateIMSpotLocation();
3514 #ifdef SOLARIS
3515 // #i51356# workaround a solaris IIIMP bug
3516 // in case of partial commits the preedit changed signal
3517 // and commit signal come in wrong order
3518 if( ! aDel.isDeleted() )
3519 signalIMPreeditChanged( pContext, im_handler );
3520 #endif
3523 void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext*, gpointer im_handler )
3525 GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
3527 char* pText = NULL;
3528 PangoAttrList* pAttrs = NULL;
3529 gint nCursorPos = 0;
3531 gtk_im_context_get_preedit_string( pThis->m_pIMContext,
3532 &pText,
3533 &pAttrs,
3534 &nCursorPos );
3535 if( pText && ! *pText ) // empty string
3537 // change from nothing to nothing -> do not start preedit
3538 // e.g. this will activate input into a calc cell without
3539 // user input
3540 if( pThis->m_aInputEvent.maText.Len() == 0 )
3542 g_free( pText );
3543 return;
3547 bool bEndPreedit = (!pText || !*pText) && pThis->m_aInputEvent.mpTextAttr != NULL;
3548 pThis->m_aInputEvent.mnTime = 0;
3549 pThis->m_aInputEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 );
3550 pThis->m_aInputEvent.mnCursorPos = nCursorPos;
3551 pThis->m_aInputEvent.mnCursorFlags = 0;
3552 pThis->m_aInputEvent.mnDeltaStart = 0;
3553 pThis->m_aInputEvent.mbOnlyCursor = False;
3555 pThis->m_aInputFlags = std::vector<USHORT>( std::max( 1, (int)pThis->m_aInputEvent.maText.Len() ), 0 );
3557 PangoAttrIterator *iter = pango_attr_list_get_iterator (pAttrs);
3560 GSList *attr_list = NULL;
3561 GSList *tmp_list = NULL;
3562 gint start, end;
3563 guint sal_attr = 0;
3565 pango_attr_iterator_range (iter, &start, &end);
3566 if (end == G_MAXINT)
3567 end = pText ? strlen (pText) : 0;
3568 if (end == start)
3569 continue;
3571 start = g_utf8_pointer_to_offset (pText, pText + start);
3572 end = g_utf8_pointer_to_offset (pText, pText + end);
3574 tmp_list = attr_list = pango_attr_iterator_get_attrs (iter);
3575 while (tmp_list)
3577 PangoAttribute *pango_attr = (PangoAttribute *)(tmp_list->data);
3579 switch (pango_attr->klass->type)
3581 case PANGO_ATTR_BACKGROUND:
3582 sal_attr |= (SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT | SAL_EXTTEXTINPUT_CURSOR_INVISIBLE);
3583 break;
3584 case PANGO_ATTR_UNDERLINE:
3585 sal_attr |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
3586 break;
3587 case PANGO_ATTR_STRIKETHROUGH:
3588 sal_attr |= SAL_EXTTEXTINPUT_ATTR_REDTEXT;
3589 break;
3590 default:
3591 break;
3593 pango_attribute_destroy (pango_attr);
3594 tmp_list = tmp_list->next;
3596 if (sal_attr == 0)
3597 sal_attr |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
3598 g_slist_free (attr_list);
3600 // Set the sal attributes on our text
3601 for (int i = start; i < end; i++)
3602 pThis->m_aInputFlags[i] |= sal_attr;
3603 } while (pango_attr_iterator_next (iter));
3605 pThis->m_aInputEvent.mpTextAttr = &pThis->m_aInputFlags[0];
3607 g_free( pText );
3608 pango_attr_list_unref( pAttrs );
3610 GTK_YIELD_GRAB();
3612 vcl::DeletionListener aDel( pThis->m_pFrame );
3614 pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
3615 if( bEndPreedit && ! aDel.isDeleted() )
3616 pThis->doCallEndExtTextInput();
3617 if( ! aDel.isDeleted() )
3618 pThis->updateIMSpotLocation();
3621 void GtkSalFrame::IMHandler::signalIMPreeditStart( GtkIMContext*, gpointer /*im_handler*/ )
3625 void GtkSalFrame::IMHandler::signalIMPreeditEnd( GtkIMContext*, gpointer im_handler )
3627 GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
3628 GTK_YIELD_GRAB();
3630 vcl::DeletionListener aDel( pThis->m_pFrame );
3631 pThis->doCallEndExtTextInput();
3632 if( ! aDel.isDeleted() )
3633 pThis->updateIMSpotLocation();
3636 uno::Reference<accessibility::XAccessibleEditableText>
3637 FindFocus(uno::Reference< accessibility::XAccessibleContext > xContext)
3639 if (!xContext.is())
3640 uno::Reference< accessibility::XAccessibleEditableText >();
3642 uno::Reference<accessibility::XAccessibleStateSet> xState = xContext->getAccessibleStateSet();
3643 if (xState.is())
3645 if (xState->contains(accessibility::AccessibleStateType::FOCUSED))
3646 return uno::Reference<accessibility::XAccessibleEditableText>(xContext, uno::UNO_QUERY);
3649 for (sal_Int32 i = 0; i < xContext->getAccessibleChildCount(); ++i)
3651 uno::Reference< accessibility::XAccessible > xChild = xContext->getAccessibleChild(i);
3652 if (!xChild.is())
3653 continue;
3654 uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext();
3655 if (!xChildContext.is())
3656 continue;
3657 uno::Reference< accessibility::XAccessibleEditableText > xText = FindFocus(xChildContext);
3658 if (xText.is())
3659 return xText;
3661 return uno::Reference< accessibility::XAccessibleEditableText >();
3664 uno::Reference<accessibility::XAccessibleEditableText> lcl_GetxText()
3666 uno::Reference<accessibility::XAccessibleEditableText> xText;
3667 Window* pFocusWin = ImplGetSVData()->maWinData.mpFocusWin;
3668 if (!pFocusWin)
3669 return xText;
3671 uno::Reference< accessibility::XAccessible > xAccessible( pFocusWin->GetAccessible( true ) );
3672 if (xAccessible.is())
3673 xText = FindFocus(xAccessible->getAccessibleContext());
3674 return xText;
3677 gboolean GtkSalFrame::IMHandler::signalIMRetrieveSurrounding( GtkIMContext* pContext, gpointer /*im_handler*/ )
3679 uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText();
3681 if (xText.is())
3683 sal_uInt32 nPosition = xText->getCaretPosition();
3684 rtl::OUString sAllText = xText->getText();
3685 if (!sAllText.getLength())
3686 return FALSE;
3687 rtl::OString sUTF = rtl::OUStringToOString(sAllText, RTL_TEXTENCODING_UTF8);
3688 rtl::OUString sCursorText(sAllText, nPosition);
3689 gtk_im_context_set_surrounding(pContext, sUTF.getStr(), sUTF.getLength(),
3690 rtl::OUStringToOString(sCursorText, RTL_TEXTENCODING_UTF8).getLength());
3691 return TRUE;
3694 return FALSE;
3697 gboolean GtkSalFrame::IMHandler::signalIMDeleteSurrounding( GtkIMContext*, gint offset, gint nchars,
3698 gpointer /*im_handler*/ )
3700 uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText();
3702 if (xText.is())
3704 sal_uInt32 nPosition = xText->getCaretPosition();
3705 xText->deleteText(nPosition + offset, nPosition + offset + nchars);
3706 return TRUE;
3709 return FALSE;