merge the formfield patch from ooo-build
[ooovba.git] / vcl / unx / gtk / window / gtkframe.cxx
blob7f0417ee2c43daba75d621c2ec47c38927a9cb30
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 <tools/prex.h>
49 #include <X11/Xatom.h>
50 #include <tools/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 // make compile on gtk older than 2.10
79 #if GTK_MINOR_VERSION < 10
80 #define GDK_SUPER_MASK (1 << 26)
81 #define GDK_HYPER_MASK (1 << 27)
82 #define GDK_META_MASK (1 << 28)
83 #endif
85 using namespace com::sun::star;
87 int GtkSalFrame::m_nFloats = 0;
89 static USHORT GetKeyModCode( guint state )
91 USHORT nCode = 0;
92 if( (state & GDK_SHIFT_MASK) )
93 nCode |= KEY_SHIFT;
94 if( (state & GDK_CONTROL_MASK) )
95 nCode |= KEY_MOD1;
96 if( (state & GDK_MOD1_MASK) )
97 nCode |= KEY_MOD2;
99 // Map Meta/Super keys to MOD3 modifier on all Unix systems
100 // except Mac OS X
101 if ( (state & GDK_META_MASK ) || ( state & GDK_SUPER_MASK ) )
102 nCode |= KEY_MOD3;
103 return nCode;
106 static USHORT GetMouseModCode( guint state )
108 USHORT nCode = GetKeyModCode( state );
109 if( (state & GDK_BUTTON1_MASK) )
110 nCode |= MOUSE_LEFT;
111 if( (state & GDK_BUTTON2_MASK) )
112 nCode |= MOUSE_MIDDLE;
113 if( (state & GDK_BUTTON3_MASK) )
114 nCode |= MOUSE_RIGHT;
116 return nCode;
119 static USHORT GetKeyCode( guint keyval )
121 USHORT nCode = 0;
122 if( keyval >= GDK_0 && keyval <= GDK_9 )
123 nCode = KEY_0 + (keyval-GDK_0);
124 else if( keyval >= GDK_KP_0 && keyval <= GDK_KP_9 )
125 nCode = KEY_0 + (keyval-GDK_KP_0);
126 else if( keyval >= GDK_A && keyval <= GDK_Z )
127 nCode = KEY_A + (keyval-GDK_A );
128 else if( keyval >= GDK_a && keyval <= GDK_z )
129 nCode = KEY_A + (keyval-GDK_a );
130 else if( keyval >= GDK_F1 && keyval <= GDK_F26 )
132 if( GetX11SalData()->GetDisplay()->IsNumLockFromXS() )
134 nCode = KEY_F1 + (keyval-GDK_F1);
136 else
138 switch( keyval )
140 // - - - - - Sun keyboard, see vcl/unx/source/app/saldisp.cxx
141 case GDK_L2:
142 if( GetX11SalData()->GetDisplay()->GetServerVendor() == vendor_sun )
143 nCode = KEY_REPEAT;
144 else
145 nCode = KEY_F12;
146 break;
147 case GDK_L3: nCode = KEY_PROPERTIES; break;
148 case GDK_L4: nCode = KEY_UNDO; break;
149 case GDK_L6: nCode = KEY_COPY; break; // KEY_F16
150 case GDK_L8: nCode = KEY_PASTE; break; // KEY_F18
151 case GDK_L10: nCode = KEY_CUT; break; // KEY_F20
152 default:
153 nCode = KEY_F1 + (keyval-GDK_F1); break;
157 else
159 switch( keyval )
161 case GDK_KP_Down:
162 case GDK_Down: nCode = KEY_DOWN; break;
163 case GDK_KP_Up:
164 case GDK_Up: nCode = KEY_UP; break;
165 case GDK_KP_Left:
166 case GDK_Left: nCode = KEY_LEFT; break;
167 case GDK_KP_Right:
168 case GDK_Right: nCode = KEY_RIGHT; break;
169 case GDK_KP_Begin:
170 case GDK_KP_Home:
171 case GDK_Begin:
172 case GDK_Home: nCode = KEY_HOME; break;
173 case GDK_KP_End:
174 case GDK_End: nCode = KEY_END; break;
175 case GDK_KP_Page_Up:
176 case GDK_Page_Up: nCode = KEY_PAGEUP; break;
177 case GDK_KP_Page_Down:
178 case GDK_Page_Down: nCode = KEY_PAGEDOWN; break;
179 case GDK_KP_Enter:
180 case GDK_Return: nCode = KEY_RETURN; break;
181 case GDK_Escape: nCode = KEY_ESCAPE; break;
182 case GDK_ISO_Left_Tab:
183 case GDK_KP_Tab:
184 case GDK_Tab: nCode = KEY_TAB; break;
185 case GDK_BackSpace: nCode = KEY_BACKSPACE; break;
186 case GDK_KP_Space:
187 case GDK_space: nCode = KEY_SPACE; break;
188 case GDK_KP_Insert:
189 case GDK_Insert: nCode = KEY_INSERT; break;
190 case GDK_KP_Delete:
191 case GDK_Delete: nCode = KEY_DELETE; break;
192 case GDK_plus:
193 case GDK_KP_Add: nCode = KEY_ADD; break;
194 case GDK_minus:
195 case GDK_KP_Subtract: nCode = KEY_SUBTRACT; break;
196 case GDK_asterisk:
197 case GDK_KP_Multiply: nCode = KEY_MULTIPLY; break;
198 case GDK_slash:
199 case GDK_KP_Divide: nCode = KEY_DIVIDE; break;
200 case GDK_period:
201 case GDK_decimalpoint: nCode = KEY_POINT; break;
202 case GDK_comma: nCode = KEY_COMMA; break;
203 case GDK_less: nCode = KEY_LESS; break;
204 case GDK_greater: nCode = KEY_GREATER; break;
205 case GDK_KP_Equal:
206 case GDK_equal: nCode = KEY_EQUAL; break;
207 case GDK_Find: nCode = KEY_FIND; break;
208 case GDK_Menu: nCode = KEY_CONTEXTMENU;break;
209 case GDK_Help: nCode = KEY_HELP; break;
210 case GDK_Undo: nCode = KEY_UNDO; break;
211 case GDK_Redo: nCode = KEY_REPEAT; break;
212 case GDK_KP_Decimal:
213 case GDK_KP_Separator: nCode = KEY_DECIMAL; break;
214 case GDK_asciitilde: nCode = KEY_TILDE; break;
215 case GDK_leftsinglequotemark:
216 case GDK_quoteleft: nCode = KEY_QUOTELEFT; break;
217 case GDK_bracketleft: nCode = KEY_BRACKETLEFT; break;
218 case GDK_bracketright: nCode = KEY_BRACKETRIGHT; break;
219 // some special cases, also see saldisp.cxx
220 // - - - - - - - - - - - - - Apollo - - - - - - - - - - - - - 0x1000
221 case 0x1000FF02: // apXK_Copy
222 nCode = KEY_COPY;
223 break;
224 case 0x1000FF03: // apXK_Cut
225 nCode = KEY_CUT;
226 break;
227 case 0x1000FF04: // apXK_Paste
228 nCode = KEY_PASTE;
229 break;
230 case 0x1000FF14: // apXK_Repeat
231 nCode = KEY_REPEAT;
232 break;
233 // Exit, Save
234 // - - - - - - - - - - - - - - D E C - - - - - - - - - - - - - 0x1000
235 case 0x1000FF00:
236 nCode = KEY_DELETE;
237 break;
238 // - - - - - - - - - - - - - - H P - - - - - - - - - - - - - 0x1000
239 case 0x1000FF73: // hpXK_DeleteChar
240 nCode = KEY_DELETE;
241 break;
242 case 0x1000FF74: // hpXK_BackTab
243 case 0x1000FF75: // hpXK_KP_BackTab
244 nCode = KEY_TAB;
245 break;
246 // - - - - - - - - - - - - - - I B M - - - - - - - - - - - - -
247 // - - - - - - - - - - - - - - O S F - - - - - - - - - - - - - 0x1004
248 case 0x1004FF02: // osfXK_Copy
249 nCode = KEY_COPY;
250 break;
251 case 0x1004FF03: // osfXK_Cut
252 nCode = KEY_CUT;
253 break;
254 case 0x1004FF04: // osfXK_Paste
255 nCode = KEY_PASTE;
256 break;
257 case 0x1004FF07: // osfXK_BackTab
258 nCode = KEY_TAB;
259 break;
260 case 0x1004FF08: // osfXK_BackSpace
261 nCode = KEY_BACKSPACE;
262 break;
263 case 0x1004FF1B: // osfXK_Escape
264 nCode = KEY_ESCAPE;
265 break;
266 // Up, Down, Left, Right, PageUp, PageDown
267 // - - - - - - - - - - - - - - S C O - - - - - - - - - - - - -
268 // - - - - - - - - - - - - - - S G I - - - - - - - - - - - - - 0x1007
269 // - - - - - - - - - - - - - - S N I - - - - - - - - - - - - -
270 // - - - - - - - - - - - - - - S U N - - - - - - - - - - - - - 0x1005
271 case 0x1005FF10: // SunXK_F36
272 nCode = KEY_F11;
273 break;
274 case 0x1005FF11: // SunXK_F37
275 nCode = KEY_F12;
276 break;
277 case 0x1005FF70: // SunXK_Props
278 nCode = KEY_PROPERTIES;
279 break;
280 case 0x1005FF71: // SunXK_Front
281 nCode = KEY_FRONT;
282 break;
283 case 0x1005FF72: // SunXK_Copy
284 nCode = KEY_COPY;
285 break;
286 case 0x1005FF73: // SunXK_Open
287 nCode = KEY_OPEN;
288 break;
289 case 0x1005FF74: // SunXK_Paste
290 nCode = KEY_PASTE;
291 break;
292 case 0x1005FF75: // SunXK_Cut
293 nCode = KEY_CUT;
294 break;
298 return nCode;
301 // F10 means either KEY_F10 or KEY_MENU, which has to be decided
302 // in the independent part.
303 struct KeyAlternate
305 USHORT nKeyCode;
306 sal_Unicode nCharCode;
307 KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
308 KeyAlternate( USHORT nKey, sal_Unicode nChar = 0 ) : nKeyCode( nKey ), nCharCode( nChar ) {}
311 inline KeyAlternate
312 GetAlternateKeyCode( const USHORT nKeyCode )
314 KeyAlternate aAlternate;
316 switch( nKeyCode )
318 case KEY_F10: aAlternate = KeyAlternate( KEY_MENU );break;
319 case KEY_F24: aAlternate = KeyAlternate( KEY_SUBTRACT, '-' );break;
322 return aAlternate;
325 void GtkSalFrame::doKeyCallback( guint state,
326 guint keyval,
327 guint16 hardware_keycode,
328 guint8 /*group*/,
329 guint32 time,
330 sal_Unicode aOrigCode,
331 bool bDown,
332 bool bSendRelease
335 SalKeyEvent aEvent;
337 aEvent.mnTime = time;
338 aEvent.mnCharCode = aOrigCode;
339 aEvent.mnRepeat = 0;
341 vcl::DeletionListener aDel( this );
342 /* #i42122# translate all keys with Ctrl and/or Alt to group 0
343 * else shortcuts (e.g. Ctrl-o) will not work but be inserted by
344 * the application
346 /* #i52338# do this for all keys that the independent part has no key code for
348 aEvent.mnCode = GetKeyCode( keyval );
349 if( aEvent.mnCode == 0 )
351 // check other mapping
352 gint eff_group, level;
353 GdkModifierType consumed;
354 guint updated_keyval = 0;
355 // use gdk_keymap_get_default instead of NULL;
356 // workaround a crahs fixed in gtk 2.4
357 if( gdk_keymap_translate_keyboard_state( gdk_keymap_get_default(),
358 hardware_keycode,
359 (GdkModifierType)0,
361 &updated_keyval,
362 &eff_group,
363 &level,
364 &consumed ) )
366 aEvent.mnCode = GetKeyCode( updated_keyval );
369 aEvent.mnCode |= GetKeyModCode( state );
371 if( bDown )
373 bool bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
374 // #i46889# copy AlternatKeyCode handling from generic plugin
375 if( ! bHandled )
377 KeyAlternate aAlternate = GetAlternateKeyCode( aEvent.mnCode );
378 if( aAlternate.nKeyCode )
380 aEvent.mnCode = aAlternate.nKeyCode;
381 if( aAlternate.nCharCode )
382 aEvent.mnCharCode = aAlternate.nCharCode;
383 bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
386 if( bSendRelease && ! aDel.isDeleted() )
388 CallCallback( SALEVENT_KEYUP, &aEvent );
391 else
392 CallCallback( SALEVENT_KEYUP, &aEvent );
395 GtkSalFrame::GraphicsHolder::~GraphicsHolder()
397 delete pGraphics;
400 GtkSalFrame::GtkSalFrame( SalFrame* pParent, ULONG nStyle )
402 m_nScreen = getDisplay()->GetDefaultScreenNumber();
403 getDisplay()->registerFrame( this );
404 m_bDefaultPos = true;
405 m_bDefaultSize = ( (nStyle & SAL_FRAME_STYLE_SIZEABLE) && ! pParent );
406 m_bWindowIsGtkPlug = false;
407 Init( pParent, nStyle );
410 GtkSalFrame::GtkSalFrame( SystemParentData* pSysData )
412 m_nScreen = getDisplay()->GetDefaultScreenNumber();
413 getDisplay()->registerFrame( this );
414 getDisplay()->setHaveSystemChildFrame();
415 m_bDefaultPos = true;
416 m_bDefaultSize = true;
417 Init( pSysData );
420 GtkSalFrame::~GtkSalFrame()
422 for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); ++i )
424 if( !m_aGraphics[i].pGraphics )
425 continue;
426 m_aGraphics[i].pGraphics->SetDrawable( None, m_nScreen );
427 m_aGraphics[i].bInUse = false;
430 if( m_pParent )
431 m_pParent->m_aChildren.remove( this );
433 getDisplay()->deregisterFrame( this );
435 if( m_pRegion )
436 gdk_region_destroy( m_pRegion );
438 if( m_hBackgroundPixmap )
440 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
441 GDK_WINDOW_XWINDOW(m_pWindow->window),
442 None );
443 XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap );
446 if( m_pIMHandler )
447 delete m_pIMHandler;
449 if( m_pFixedContainer )
450 gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer) );
451 if( m_pWindow )
453 g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", NULL );
454 gtk_widget_destroy( m_pWindow );
456 if( m_pForeignParent )
457 g_object_unref( G_OBJECT(m_pForeignParent) );
458 if( m_pForeignTopLevel )
459 g_object_unref(G_OBJECT( m_pForeignTopLevel) );
462 void GtkSalFrame::moveWindow( long nX, long nY )
464 if( isChild( false, true ) )
466 if( m_pParent )
467 gtk_fixed_move( m_pParent->getFixedContainer(),
468 m_pWindow,
469 nX - m_pParent->maGeometry.nX, nY - m_pParent->maGeometry.nY );
471 else
472 gtk_window_move( GTK_WINDOW(m_pWindow), nX, nY );
475 void GtkSalFrame::resizeWindow( long nWidth, long nHeight )
477 if( isChild( false, true ) )
478 gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
479 else if( ! isChild( true, false ) )
480 gtk_window_resize( GTK_WINDOW(m_pWindow), nWidth, nHeight );
484 * Always use a sub-class of GtkFixed we can tag for a11y. This allows us to
485 * utilize GAIL for the toplevel window and toolkit implementation incl.
486 * key event listener support ..
489 GType
490 ooo_fixed_get_type()
492 static GType type = 0;
494 if (!type) {
495 static const GTypeInfo tinfo =
497 sizeof (GtkFixedClass),
498 (GBaseInitFunc) NULL, /* base init */
499 (GBaseFinalizeFunc) NULL, /* base finalize */
500 (GClassInitFunc) NULL, /* class init */
501 (GClassFinalizeFunc) NULL, /* class finalize */
502 NULL, /* class data */
503 sizeof (GtkFixed), /* instance size */
504 0, /* nb preallocs */
505 (GInstanceInitFunc) NULL, /* instance init */
506 NULL /* value table */
509 type = g_type_register_static( GTK_TYPE_FIXED, "OOoFixed",
510 &tinfo, (GTypeFlags) 0);
513 return type;
516 void GtkSalFrame::updateScreenNumber()
518 if( getDisplay()->IsXinerama() && getDisplay()->GetXineramaScreens().size() > 1 )
520 Point aPoint( maGeometry.nX, maGeometry.nY );
521 const std::vector<Rectangle>& rScreenRects( getDisplay()->GetXineramaScreens() );
522 size_t nScreens = rScreenRects.size();
523 for( size_t i = 0; i < nScreens; i++ )
525 if( rScreenRects[i].IsInside( aPoint ) )
527 maGeometry.nScreenNumber = static_cast<unsigned int>(i);
528 break;
532 else
533 maGeometry.nScreenNumber = static_cast<unsigned int>(m_nScreen);
536 void GtkSalFrame::InitCommon()
538 // connect signals
539 g_signal_connect( G_OBJECT(m_pWindow), "style-set", G_CALLBACK(signalStyleSet), this );
540 g_signal_connect( G_OBJECT(m_pWindow), "button-press-event", G_CALLBACK(signalButton), this );
541 g_signal_connect( G_OBJECT(m_pWindow), "button-release-event", G_CALLBACK(signalButton), this );
542 g_signal_connect( G_OBJECT(m_pWindow), "expose-event", G_CALLBACK(signalExpose), this );
543 g_signal_connect( G_OBJECT(m_pWindow), "focus-in-event", G_CALLBACK(signalFocus), this );
544 g_signal_connect( G_OBJECT(m_pWindow), "focus-out-event", G_CALLBACK(signalFocus), this );
545 g_signal_connect( G_OBJECT(m_pWindow), "map-event", G_CALLBACK(signalMap), this );
546 g_signal_connect( G_OBJECT(m_pWindow), "unmap-event", G_CALLBACK(signalUnmap), this );
547 g_signal_connect( G_OBJECT(m_pWindow), "configure-event", G_CALLBACK(signalConfigure), this );
548 g_signal_connect( G_OBJECT(m_pWindow), "motion-notify-event", G_CALLBACK(signalMotion), this );
549 g_signal_connect( G_OBJECT(m_pWindow), "key-press-event", G_CALLBACK(signalKey), this );
550 g_signal_connect( G_OBJECT(m_pWindow), "key-release-event", G_CALLBACK(signalKey), this );
551 g_signal_connect( G_OBJECT(m_pWindow), "delete-event", G_CALLBACK(signalDelete), this );
552 g_signal_connect( G_OBJECT(m_pWindow), "window-state-event", G_CALLBACK(signalState), this );
553 g_signal_connect( G_OBJECT(m_pWindow), "scroll-event", G_CALLBACK(signalScroll), this );
554 g_signal_connect( G_OBJECT(m_pWindow), "leave-notify-event", G_CALLBACK(signalCrossing), this );
555 g_signal_connect( G_OBJECT(m_pWindow), "enter-notify-event", G_CALLBACK(signalCrossing), this );
556 g_signal_connect( G_OBJECT(m_pWindow), "visibility-notify-event", G_CALLBACK(signalVisibility), this );
557 g_signal_connect( G_OBJECT(m_pWindow), "destroy", G_CALLBACK(signalDestroy), this );
559 // init members
560 m_pCurrentCursor = NULL;
561 m_nKeyModifiers = 0;
562 m_bSingleAltPress = false;
563 m_bFullscreen = false;
564 m_nState = GDK_WINDOW_STATE_WITHDRAWN;
565 m_nVisibility = GDK_VISIBILITY_FULLY_OBSCURED;
566 m_bSendModChangeOnRelease = false;
567 m_pIMHandler = NULL;
568 m_hBackgroundPixmap = None;
569 m_nSavedScreenSaverTimeout = 0;
570 m_nGSSCookie = 0;
571 m_nExtStyle = 0;
572 m_pRegion = NULL;
573 m_ePointerStyle = 0xffff;
575 gtk_widget_set_app_paintable( m_pWindow, TRUE );
576 gtk_widget_set_double_buffered( m_pWindow, FALSE );
577 gtk_widget_set_redraw_on_allocate( m_pWindow, FALSE );
578 gtk_widget_add_events( m_pWindow,
579 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
580 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
581 GDK_VISIBILITY_NOTIFY_MASK
584 // add the fixed container child,
585 // fixed is needed since we have to position plugin windows
586 m_pFixedContainer = GTK_FIXED(g_object_new( ooo_fixed_get_type(), NULL ));
587 gtk_container_add( GTK_CONTAINER(m_pWindow), GTK_WIDGET(m_pFixedContainer) );
589 // show the widgets
590 gtk_widget_show( GTK_WIDGET(m_pFixedContainer) );
592 // realize the window, we need an XWindow id
593 gtk_widget_realize( m_pWindow );
595 //system data
596 SalDisplay* pDisp = GetX11SalData()->GetDisplay();
597 m_aSystemData.nSize = sizeof( SystemChildData );
598 m_aSystemData.pDisplay = pDisp->GetDisplay();
599 m_aSystemData.aWindow = GDK_WINDOW_XWINDOW(m_pWindow->window);
600 m_aSystemData.pSalFrame = this;
601 m_aSystemData.pWidget = m_pWindow;
602 m_aSystemData.pVisual = pDisp->GetVisual( m_nScreen ).GetVisual();
603 m_aSystemData.nScreen = m_nScreen;
604 m_aSystemData.nDepth = pDisp->GetVisual( m_nScreen ).GetDepth();
605 m_aSystemData.aColormap = pDisp->GetColormap( m_nScreen ).GetXColormap();
606 m_aSystemData.pAppContext = NULL;
607 m_aSystemData.aShellWindow = m_aSystemData.aWindow;
608 m_aSystemData.pShellWidget = m_aSystemData.pWidget;
611 // fake an initial geometry, gets updated via configure event or SetPosSize
612 if( m_bDefaultPos || m_bDefaultSize )
614 Size aDefSize = calcDefaultSize();
615 maGeometry.nX = -1;
616 maGeometry.nY = -1;
617 maGeometry.nWidth = aDefSize.Width();
618 maGeometry.nHeight = aDefSize.Height();
619 if( m_pParent )
621 // approximation
622 maGeometry.nTopDecoration = m_pParent->maGeometry.nTopDecoration;
623 maGeometry.nBottomDecoration = m_pParent->maGeometry.nBottomDecoration;
624 maGeometry.nLeftDecoration = m_pParent->maGeometry.nLeftDecoration;
625 maGeometry.nRightDecoration = m_pParent->maGeometry.nRightDecoration;
627 else
629 maGeometry.nTopDecoration = 0;
630 maGeometry.nBottomDecoration = 0;
631 maGeometry.nLeftDecoration = 0;
632 maGeometry.nRightDecoration = 0;
635 else
637 resizeWindow( maGeometry.nWidth, maGeometry.nHeight );
638 moveWindow( maGeometry.nX, maGeometry.nY );
640 updateScreenNumber();
642 SetIcon(1);
643 m_nWorkArea = pDisp->getWMAdaptor()->getCurrentWorkArea();
645 /* #i64117# gtk sets a nice background pixmap
646 * but we actually don't really want that, so save
647 * some time on the Xserver as well as prevent
648 * some paint issues
650 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
651 GDK_WINDOW_XWINDOW(m_pWindow->window),
652 m_hBackgroundPixmap );
655 /* Sadly gtk_window_set_accept_focus exists only since gtk 2.4
656 * for achieving the same effect we will remove the WM_TAKE_FOCUS
657 * protocol from the window and set the input hint to false.
658 * But gtk_window_set_accept_focus needs to be called before
659 * window realization whereas the removal obviously can only happen
660 * after realization.
663 extern "C" {
664 typedef void(*setAcceptFn)( GtkWindow*, gboolean );
665 static setAcceptFn p_gtk_window_set_accept_focus = NULL;
666 static bool bGetAcceptFocusFn = true;
668 typedef void(*setUserTimeFn)( GdkWindow*, guint32 );
669 static setUserTimeFn p_gdk_x11_window_set_user_time = NULL;
670 static bool bGetSetUserTimeFn = true;
673 static void lcl_set_accept_focus( GtkWindow* pWindow, gboolean bAccept, bool bBeforeRealize )
675 if( bGetAcceptFocusFn )
677 bGetAcceptFocusFn = false;
678 p_gtk_window_set_accept_focus = (setAcceptFn)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_window_set_accept_focus" );
680 if( p_gtk_window_set_accept_focus && bBeforeRealize )
681 p_gtk_window_set_accept_focus( pWindow, bAccept );
682 else if( ! bBeforeRealize )
684 Display* pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
685 XLIB_Window aWindow = GDK_WINDOW_XWINDOW( GTK_WIDGET(pWindow)->window );
686 XWMHints* pHints = XGetWMHints( pDisplay, aWindow );
687 if( ! pHints )
689 pHints = XAllocWMHints();
690 pHints->flags = 0;
692 pHints->flags |= InputHint;
693 pHints->input = bAccept ? True : False;
694 XSetWMHints( pDisplay, aWindow, pHints );
695 XFree( pHints );
697 if (GetX11SalData()->GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("compiz"))
698 return;
700 /* remove WM_TAKE_FOCUS protocol; this would usually be the
701 * right thing, but gtk handles it internally whereas we
702 * want to handle it ourselves (as to sometimes not get
703 * the focus)
705 Atom* pProtocols = NULL;
706 int nProtocols = 0;
707 XGetWMProtocols( pDisplay,
708 aWindow,
709 &pProtocols, &nProtocols );
710 if( pProtocols )
712 bool bSet = false;
713 Atom nTakeFocus = XInternAtom( pDisplay, "WM_TAKE_FOCUS", True );
714 if( nTakeFocus )
716 for( int i = 0; i < nProtocols; i++ )
718 if( pProtocols[i] == nTakeFocus )
720 for( int n = i; n < nProtocols-1; n++ )
721 pProtocols[n] = pProtocols[n+1];
722 nProtocols--;
723 i--;
724 bSet = true;
728 if( bSet )
729 XSetWMProtocols( pDisplay, aWindow, pProtocols, nProtocols );
730 XFree( pProtocols );
734 static void lcl_set_user_time( GdkWindow* i_pWindow, guint32 i_nTime )
736 if( bGetSetUserTimeFn )
738 bGetSetUserTimeFn = false;
739 p_gdk_x11_window_set_user_time = (setUserTimeFn)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_x11_window_set_user_time" );
741 if( p_gdk_x11_window_set_user_time )
742 p_gdk_x11_window_set_user_time( i_pWindow, i_nTime );
743 else
745 Display* pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
746 XLIB_Window aWindow = GDK_WINDOW_XWINDOW( i_pWindow );
747 Atom nUserTime = XInternAtom( pDisplay, "_NET_WM_USER_TIME", True );
748 if( nUserTime )
750 XChangeProperty( pDisplay, aWindow,
751 nUserTime, XA_CARDINAL, 32,
752 PropModeReplace, (unsigned char*)&i_nTime, 1 );
757 GtkSalFrame *GtkSalFrame::getFromWindow( GtkWindow *pWindow )
759 return (GtkSalFrame *) g_object_get_data( G_OBJECT( pWindow ), "SalFrame" );
762 void GtkSalFrame::Init( SalFrame* pParent, ULONG nStyle )
764 if( nStyle & SAL_FRAME_STYLE_DEFAULT ) // ensure default style
766 nStyle |= SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE;
767 nStyle &= ~SAL_FRAME_STYLE_FLOAT;
770 m_pParent = static_cast<GtkSalFrame*>(pParent);
771 m_pForeignParent = NULL;
772 m_aForeignParentWindow = None;
773 m_pForeignTopLevel = NULL;
774 m_aForeignTopLevelWindow = None;
775 m_nStyle = nStyle;
777 GtkWindowType eWinType = ((nStyle & SAL_FRAME_STYLE_FLOAT) && ! (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION))
778 ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL;
780 if( nStyle & SAL_FRAME_STYLE_SYSTEMCHILD )
782 m_pWindow = gtk_event_box_new();
783 if( m_pParent )
785 // insert into container
786 gtk_fixed_put( m_pParent->getFixedContainer(),
787 m_pWindow, 0, 0 );
791 else
792 m_pWindow = gtk_widget_new( GTK_TYPE_WINDOW, "type", eWinType, "visible", FALSE, NULL );
793 g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", this );
795 // force wm class hint
796 m_nExtStyle = ~0;
797 SetExtendedFrameStyle( 0 );
799 if( m_pParent && m_pParent->m_pWindow && ! isChild() )
800 gtk_window_set_screen( GTK_WINDOW(m_pWindow), gtk_window_get_screen( GTK_WINDOW(m_pParent->m_pWindow) ) );
802 // set window type
803 bool bDecoHandling =
804 ! isChild() &&
805 ( ! (nStyle & SAL_FRAME_STYLE_FLOAT) ||
806 (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) );
808 /* #i100116# metacity has a peculiar behavior regarding WM_HINT accept focus and _NET_WM_USER_TIME
809 at some point that may be fixed in metacity and we will have to revisit this
811 bool bMetaCityToolWindowHack = getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("Metacity") &&
812 (nStyle & SAL_FRAME_STYLE_TOOLWINDOW );
813 if( bDecoHandling )
815 bool bNoDecor = ! (nStyle & (SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE ) );
816 GdkWindowTypeHint eType = GDK_WINDOW_TYPE_HINT_NORMAL;
817 if( (nStyle & SAL_FRAME_STYLE_DIALOG) && m_pParent != 0 )
818 eType = GDK_WINDOW_TYPE_HINT_DIALOG;
819 if( (nStyle & SAL_FRAME_STYLE_INTRO) )
821 gtk_window_set_role( GTK_WINDOW(m_pWindow), "splashscreen" );
822 eType = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN;
824 else if( (nStyle & SAL_FRAME_STYLE_TOOLWINDOW ) )
826 eType = GDK_WINDOW_TYPE_HINT_UTILITY;
827 gtk_window_set_skip_taskbar_hint( GTK_WINDOW(m_pWindow), true );
828 if( bMetaCityToolWindowHack )
829 lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, true );
831 else if( (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
833 eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
834 lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, true );
835 bNoDecor = true;
837 if( (nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN ) )
839 eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
840 gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), true );
843 gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), eType );
844 if( bNoDecor )
845 gtk_window_set_decorated( GTK_WINDOW(m_pWindow), FALSE );
846 gtk_window_set_gravity( GTK_WINDOW(m_pWindow), GDK_GRAVITY_STATIC );
847 if( m_pParent && ! (m_pParent->m_nStyle & SAL_FRAME_STYLE_PLUG) )
848 gtk_window_set_transient_for( GTK_WINDOW(m_pWindow), GTK_WINDOW(m_pParent->m_pWindow) );
850 else if( (nStyle & SAL_FRAME_STYLE_FLOAT) )
852 gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), GDK_WINDOW_TYPE_HINT_UTILITY );
854 if( m_pParent )
855 m_pParent->m_aChildren.push_back( this );
857 InitCommon();
859 if( eWinType == GTK_WINDOW_TOPLEVEL )
861 guint32 nUserTime = 0;
862 if( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
864 /* #i99360# ugly workaround an X11 library bug */
865 nUserTime= getDisplay()->GetLastUserEventTime( true );
866 // nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
868 lcl_set_user_time(GTK_WIDGET(m_pWindow)->window, nUserTime);
871 if( bDecoHandling )
873 gtk_window_set_resizable( GTK_WINDOW(m_pWindow), (nStyle & SAL_FRAME_STYLE_SIZEABLE) ? TRUE : FALSE );
874 if( ( (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) || bMetaCityToolWindowHack )
875 lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, false );
880 GdkNativeWindow GtkSalFrame::findTopLevelSystemWindow( GdkNativeWindow aWindow )
882 XLIB_Window aRoot, aParent;
883 XLIB_Window* pChildren;
884 unsigned int nChildren;
885 bool bBreak = false;
888 pChildren = NULL;
889 nChildren = 0;
890 aParent = aRoot = None;
891 XQueryTree( getDisplay()->GetDisplay(), aWindow,
892 &aRoot, &aParent, &pChildren, &nChildren );
893 XFree( pChildren );
894 if( aParent != aRoot )
895 aWindow = aParent;
896 int nCount = 0;
897 Atom* pProps = XListProperties( getDisplay()->GetDisplay(),
898 aWindow,
899 &nCount );
900 for( int i = 0; i < nCount && ! bBreak; ++i )
901 bBreak = (pProps[i] == XA_WM_HINTS);
902 if( pProps )
903 XFree( pProps );
904 } while( aParent != aRoot && ! bBreak );
906 return aWindow;
909 void GtkSalFrame::Init( SystemParentData* pSysData )
911 m_pParent = NULL;
912 m_aForeignParentWindow = (GdkNativeWindow)pSysData->aWindow;
913 m_pForeignParent = NULL;
914 m_aForeignTopLevelWindow = findTopLevelSystemWindow( (GdkNativeWindow)pSysData->aWindow );
915 m_pForeignTopLevel = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignTopLevelWindow );
916 gdk_window_set_events( m_pForeignTopLevel, GDK_STRUCTURE_MASK );
918 if( pSysData->nSize > sizeof(pSysData->nSize)+sizeof(pSysData->aWindow) && pSysData->bXEmbedSupport )
920 m_pWindow = gtk_plug_new( pSysData->aWindow );
921 m_bWindowIsGtkPlug = true;
922 GTK_WIDGET_SET_FLAGS( m_pWindow, GTK_CAN_FOCUS | GTK_SENSITIVE | GTK_CAN_DEFAULT );
923 gtk_widget_set_sensitive( m_pWindow, true );
925 else
927 m_pWindow = gtk_window_new( GTK_WINDOW_POPUP );
928 m_bWindowIsGtkPlug = false;
930 m_nStyle = SAL_FRAME_STYLE_PLUG;
931 InitCommon();
933 m_pForeignParent = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignParentWindow );
934 gdk_window_set_events( m_pForeignParent, GDK_STRUCTURE_MASK );
935 int x_ret, y_ret;
936 unsigned int w, h, bw, d;
937 XLIB_Window aRoot;
938 XGetGeometry( getDisplay()->GetDisplay(), pSysData->aWindow,
939 &aRoot, &x_ret, &y_ret, &w, &h, &bw, &d );
940 maGeometry.nWidth = w;
941 maGeometry.nHeight = h;
942 gtk_window_resize( GTK_WINDOW(m_pWindow), w, h );
943 gtk_window_move( GTK_WINDOW(m_pWindow), 0, 0 );
944 if( ! m_bWindowIsGtkPlug )
946 XReparentWindow( getDisplay()->GetDisplay(),
947 GDK_WINDOW_XWINDOW(m_pWindow->window),
948 (XLIB_Window)pSysData->aWindow,
949 0, 0 );
953 void GtkSalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
955 XEvent aEvent;
957 rtl_zeroMemory( &aEvent, sizeof(aEvent) );
958 aEvent.xclient.window = m_aForeignParentWindow;
959 aEvent.xclient.type = ClientMessage;
960 aEvent.xclient.message_type = getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED );
961 aEvent.xclient.format = 32;
962 aEvent.xclient.data.l[0] = i_nTimeCode ? i_nTimeCode : CurrentTime;
963 aEvent.xclient.data.l[1] = 3; // XEMBED_REQUEST_FOCUS
964 aEvent.xclient.data.l[2] = 0;
965 aEvent.xclient.data.l[3] = 0;
966 aEvent.xclient.data.l[4] = 0;
968 getDisplay()->GetXLib()->PushXErrorLevel( true );
969 XSendEvent( getDisplay()->GetDisplay(),
970 m_aForeignParentWindow,
971 False, NoEventMask, &aEvent );
972 XSync( getDisplay()->GetDisplay(), False );
973 getDisplay()->GetXLib()->PopXErrorLevel();
976 void GtkSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
978 if( nStyle != m_nExtStyle && ! isChild() )
980 m_nExtStyle = nStyle;
981 if( GTK_WIDGET_REALIZED( m_pWindow ) )
983 XClassHint* pClass = XAllocClassHint();
984 rtl::OString aResHint = X11SalData::getFrameResName( m_nExtStyle );
985 pClass->res_name = const_cast<char*>(aResHint.getStr());
986 pClass->res_class = const_cast<char*>(X11SalData::getFrameClassName());
987 XSetClassHint( getDisplay()->GetDisplay(),
988 GDK_WINDOW_XWINDOW(m_pWindow->window),
989 pClass );
990 XFree( pClass );
992 else
993 gtk_window_set_wmclass( GTK_WINDOW(m_pWindow),
994 X11SalData::getFrameResName( m_nExtStyle ),
995 X11SalData::getFrameClassName() );
1000 SalGraphics* GtkSalFrame::GetGraphics()
1002 if( m_pWindow )
1004 for( int i = 0; i < nMaxGraphics; i++ )
1006 if( ! m_aGraphics[i].bInUse )
1008 m_aGraphics[i].bInUse = true;
1009 if( ! m_aGraphics[i].pGraphics )
1011 m_aGraphics[i].pGraphics = new GtkSalGraphics( m_pWindow );
1012 m_aGraphics[i].pGraphics->Init( this, GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
1014 return m_aGraphics[i].pGraphics;
1019 return NULL;
1022 void GtkSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
1024 for( int i = 0; i < nMaxGraphics; i++ )
1026 if( m_aGraphics[i].pGraphics == pGraphics )
1028 m_aGraphics[i].bInUse = false;
1029 break;
1034 BOOL GtkSalFrame::PostEvent( void* pData )
1036 getDisplay()->SendInternalEvent( this, pData );
1037 return TRUE;
1040 void GtkSalFrame::SetTitle( const String& rTitle )
1042 m_aTitle = rTitle;
1043 if( m_pWindow && ! isChild() )
1044 gtk_window_set_title( GTK_WINDOW(m_pWindow), rtl::OUStringToOString( rTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
1047 static inline BYTE *
1048 getRow( BitmapBuffer *pBuffer, ULONG nRow )
1050 if( BMP_SCANLINE_ADJUSTMENT( pBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
1051 return pBuffer->mpBits + nRow * pBuffer->mnScanlineSize;
1052 else
1053 return pBuffer->mpBits + ( pBuffer->mnHeight - nRow - 1 ) * pBuffer->mnScanlineSize;
1056 static GdkPixbuf *
1057 bitmapToPixbuf( SalBitmap *pSalBitmap, SalBitmap *pSalAlpha )
1059 g_return_val_if_fail( pSalBitmap != NULL, NULL );
1060 g_return_val_if_fail( pSalAlpha != NULL, NULL );
1062 BitmapBuffer *pBitmap = pSalBitmap->AcquireBuffer( TRUE );
1063 g_return_val_if_fail( pBitmap != NULL, NULL );
1064 g_return_val_if_fail( pBitmap->mnBitCount == 24, NULL );
1066 BitmapBuffer *pAlpha = pSalAlpha->AcquireBuffer( TRUE );
1067 g_return_val_if_fail( pAlpha != NULL, NULL );
1068 g_return_val_if_fail( pAlpha->mnBitCount == 8, NULL );
1070 Size aSize = pSalBitmap->GetSize();
1071 g_return_val_if_fail( pSalAlpha->GetSize() == aSize, NULL );
1073 int nX, nY;
1074 guchar *pPixbufData = (guchar *)g_malloc (4 * aSize.Width() * aSize.Height() );
1075 guchar *pDestData = pPixbufData;
1077 for( nY = 0; nY < pBitmap->mnHeight; nY++ )
1079 BYTE *pData = getRow( pBitmap, nY );
1080 BYTE *pAlphaData = getRow( pAlpha, nY );
1082 for( nX = 0; nX < pBitmap->mnWidth; nX++ )
1084 if( pBitmap->mnFormat == BMP_FORMAT_24BIT_TC_BGR )
1086 pDestData[2] = *pData++;
1087 pDestData[1] = *pData++;
1088 pDestData[0] = *pData++;
1090 else // BMP_FORMAT_24BIT_TC_RGB
1092 pDestData[0] = *pData++;
1093 pDestData[1] = *pData++;
1094 pDestData[2] = *pData++;
1096 pDestData += 3;
1097 *pDestData++ = 255 - *pAlphaData++;
1101 pSalBitmap->ReleaseBuffer( pBitmap, TRUE );
1102 pSalAlpha->ReleaseBuffer( pAlpha, TRUE );
1104 return gdk_pixbuf_new_from_data( pPixbufData,
1105 GDK_COLORSPACE_RGB, TRUE, 8,
1106 aSize.Width(), aSize.Height(),
1107 aSize.Width() * 4,
1108 (GdkPixbufDestroyNotify) g_free,
1109 NULL );
1112 void GtkSalFrame::SetIcon( USHORT nIcon )
1114 if( (m_nStyle & (SAL_FRAME_STYLE_PLUG|SAL_FRAME_STYLE_SYSTEMCHILD|SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_INTRO|SAL_FRAME_STYLE_OWNERDRAWDECORATION))
1115 || ! m_pWindow )
1116 return;
1118 if( !ImplGetResMgr() )
1119 return;
1121 GdkPixbuf *pBuf;
1122 GList *pIcons = NULL;
1124 USHORT nOffsets[2] = { SV_ICON_SMALL_START, SV_ICON_LARGE_START };
1125 USHORT nIndex;
1127 // Use high contrast icons where appropriate
1128 if( Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
1130 nOffsets[0] = SV_ICON_LARGE_HC_START;
1131 nOffsets[1] = SV_ICON_SMALL_HC_START;
1134 for( nIndex = 0; nIndex < sizeof(nOffsets)/ sizeof(USHORT); nIndex++ )
1136 // #i44723# workaround gcc temporary problem
1137 ResId aResId( nOffsets[nIndex] + nIcon, *ImplGetResMgr() );
1138 BitmapEx aIcon;
1139 try {
1140 aIcon = BitmapEx( aResId );
1141 } catch (com::sun::star::uno::RuntimeException &) {
1142 // UCB not initialized for splash screen creation; very exceptional.
1143 continue;
1146 // #i81083# convert to 24bit/8bit alpha bitmap
1147 Bitmap aBmp = aIcon.GetBitmap();
1148 if( aBmp.GetBitCount() != 24 || ! aIcon.IsAlpha() )
1150 if( aBmp.GetBitCount() != 24 )
1151 aBmp.Convert( BMP_CONVERSION_24BIT );
1152 AlphaMask aMask;
1153 if( ! aIcon.IsAlpha() )
1155 switch( aIcon.GetTransparentType() )
1157 case TRANSPARENT_NONE:
1159 BYTE nTrans = 0;
1160 aMask = AlphaMask( aBmp.GetSizePixel(), &nTrans );
1162 break;
1163 case TRANSPARENT_COLOR:
1164 aMask = AlphaMask( aBmp.CreateMask( aIcon.GetTransparentColor() ) );
1165 break;
1166 case TRANSPARENT_BITMAP:
1167 aMask = AlphaMask( aIcon.GetMask() );
1168 break;
1169 default:
1170 DBG_ERROR( "unhandled transparent type" );
1171 break;
1174 else
1175 aMask = aIcon.GetAlpha();
1176 aIcon = BitmapEx( aBmp, aMask );
1179 ImpBitmap *pIconImpBitmap = aIcon.ImplGetBitmapImpBitmap();
1180 ImpBitmap *pIconImpMask = aIcon.ImplGetMaskImpBitmap();
1183 if( pIconImpBitmap && pIconImpMask )
1185 SalBitmap *pIconBitmap =
1186 pIconImpBitmap->ImplGetSalBitmap();
1187 SalBitmap *pIconMask =
1188 pIconImpMask->ImplGetSalBitmap();
1190 if( ( pBuf = bitmapToPixbuf( pIconBitmap, pIconMask ) ) )
1191 pIcons = g_list_prepend( pIcons, pBuf );
1195 gtk_window_set_icon_list( GTK_WINDOW(m_pWindow), pIcons );
1197 g_list_foreach( pIcons, (GFunc) g_object_unref, NULL );
1198 g_list_free( pIcons );
1201 void GtkSalFrame::SetMenu( SalMenu* )
1205 void GtkSalFrame::DrawMenuBar()
1209 void GtkSalFrame::Center()
1211 long nX, nY;
1213 if( m_pParent )
1215 nX = ((long)m_pParent->maGeometry.nWidth - (long)maGeometry.nWidth)/2;
1216 nY = ((long)m_pParent->maGeometry.nHeight - (long)maGeometry.nHeight)/2;
1219 else
1221 long nScreenWidth, nScreenHeight;
1222 long nScreenX = 0, nScreenY = 0;
1224 Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
1225 nScreenWidth = aScreenSize.Width();
1226 nScreenHeight = aScreenSize.Height();
1227 if( GetX11SalData()->GetDisplay()->IsXinerama() )
1229 // get xinerama screen we are on
1230 // if there is a parent, use its center for screen determination
1231 // else use the pointer
1232 GdkScreen* pScreen;
1233 gint x, y;
1234 GdkModifierType aMask;
1235 gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
1237 const std::vector< Rectangle >& rScreens = GetX11SalData()->GetDisplay()->GetXineramaScreens();
1238 for( unsigned int i = 0; i < rScreens.size(); i++ )
1239 if( rScreens[i].IsInside( Point( x, y ) ) )
1241 nScreenX = rScreens[i].Left();
1242 nScreenY = rScreens[i].Top();
1243 nScreenWidth = rScreens[i].GetWidth();
1244 nScreenHeight = rScreens[i].GetHeight();
1245 break;
1248 nX = nScreenX + (nScreenWidth - (long)maGeometry.nWidth)/2;
1249 nY = nScreenY + (nScreenHeight - (long)maGeometry.nHeight)/2;
1251 SetPosSize( nX, nY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
1254 Size GtkSalFrame::calcDefaultSize()
1256 Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
1257 long w = aScreenSize.Width();
1258 long h = aScreenSize.Height();
1260 // fill in holy default values brought to us by product management
1261 if( aScreenSize.Width() >= 800 )
1262 w = 785;
1263 if( aScreenSize.Width() >= 1024 )
1264 w = 920;
1266 if( aScreenSize.Height() >= 600 )
1267 h = 550;
1268 if( aScreenSize.Height() >= 768 )
1269 h = 630;
1270 if( aScreenSize.Height() >= 1024 )
1271 h = 875;
1273 return Size( w, h );
1276 void GtkSalFrame::SetDefaultSize()
1278 Size aDefSize = calcDefaultSize();
1280 SetPosSize( 0, 0, aDefSize.Width(), aDefSize.Height(),
1281 SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
1283 if( (m_nStyle & SAL_FRAME_STYLE_DEFAULT) && m_pWindow )
1284 gtk_window_maximize( GTK_WINDOW(m_pWindow) );
1287 static void initClientId()
1289 static bool bOnce = false;
1290 if( ! bOnce )
1292 bOnce = true;
1293 const ByteString& rID = SessionManagerClient::getSessionID();
1294 if( rID.Len() > 0 )
1295 gdk_set_sm_client_id(rID.GetBuffer());
1299 void GtkSalFrame::Show( BOOL bVisible, BOOL bNoActivate )
1301 if( m_pWindow )
1303 if( m_pParent && (m_pParent->m_nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN) )
1304 gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), bVisible );
1305 if( bVisible )
1307 SessionManagerClient::open(); // will simply return after the first time
1308 initClientId();
1309 getDisplay()->startupNotificationCompleted();
1311 if( m_bDefaultPos )
1312 Center();
1313 if( m_bDefaultSize )
1314 SetDefaultSize();
1315 setMinMaxSize();
1317 // #i45160# switch to desktop where a dialog with parent will appear
1318 if( m_pParent && m_pParent->m_nWorkArea != m_nWorkArea )
1319 getDisplay()->getWMAdaptor()->switchToWorkArea( m_pParent->m_nWorkArea );
1321 if( isFloatGrabWindow() &&
1322 m_pParent &&
1323 m_nFloats == 0 &&
1324 ! getDisplay()->GetCaptureFrame() )
1326 /* #i63086#
1327 * outsmart Metacity's "focus:mouse" mode
1328 * which insists on taking the focus from the document
1329 * to the new float. Grab focus to parent frame BEFORE
1330 * showing the float (cannot grab it to the float
1331 * before show).
1333 m_pParent->grabPointer( TRUE, TRUE );
1336 guint32 nUserTime = 0;
1337 if( ! bNoActivate && (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
1338 /* #i99360# ugly workaround an X11 library bug */
1339 nUserTime= getDisplay()->GetLastUserEventTime( true );
1340 //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
1342 //For these floating windows we don't want the main window to lose focus, and metacity has...
1343 // metacity-2.24.0/src/core/window.c
1345 // if ((focus_window != NULL) && XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time))
1346 // "compare" window focus prevented by other activity
1348 // where "compare" is this window
1350 // which leads to...
1352 // /* This happens for error dialogs or alerts; these need to remain on
1353 // * top, but it would be confusing to have its ancestor remain
1354 // * focused.
1355 // */
1356 // if (meta_window_is_ancestor_of_transient (focus_window, window))
1357 // "The focus window %s is an ancestor of the newly mapped "
1358 // "window %s which isn't being focused. Unfocusing the "
1359 // "ancestor.\n",
1361 // i.e. having a time < that of the toplevel frame means that the toplevel frame gets unfocused.
1362 // awesome.
1363 if( nUserTime == 0 &&
1365 getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("Metacity") ||
1367 getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("compiz") &&
1368 (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION))
1373 /* #i99360# ugly workaround an X11 library bug */
1374 nUserTime= getDisplay()->GetLastUserEventTime( true );
1375 //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
1378 lcl_set_user_time( GTK_WIDGET(m_pWindow)->window, nUserTime );
1380 gtk_widget_show( m_pWindow );
1382 if( isFloatGrabWindow() )
1384 m_nFloats++;
1385 if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 1 )
1386 grabPointer( TRUE, TRUE );
1387 // #i44068# reset parent's IM context
1388 if( m_pParent )
1389 m_pParent->EndExtTextInput(0);
1391 if( m_bWindowIsGtkPlug )
1392 askForXEmbedFocus( 0 );
1394 else
1396 if( isFloatGrabWindow() )
1398 m_nFloats--;
1399 if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 0)
1400 grabPointer( FALSE );
1402 gtk_widget_hide( m_pWindow );
1403 if( m_pIMHandler )
1404 m_pIMHandler->focusChanged( false );
1405 // flush here; there may be a very seldom race between
1406 // the display connection used for clipboard and our connection
1407 Flush();
1409 CallCallback( SALEVENT_RESIZE, NULL );
1413 void GtkSalFrame::Enable( BOOL /*bEnable*/ )
1415 // Not implemented by X11SalFrame either
1418 void GtkSalFrame::setMinMaxSize()
1420 /* FIXME: for yet unknown reasons the reported size is a little smaller
1421 * than the max size hint; one would guess that this was due to the border
1422 * sizes of the widgets involved (GtkWindow and GtkFixed), but setting the
1423 * their border to 0 (which is the default anyway) does not change the
1424 * behaviour. Until the reason is known we'll add some pixels here.
1426 #define CONTAINER_ADJUSTMENT 6
1428 /* #i34504# metacity (and possibly others) do not treat
1429 * _NET_WM_STATE_FULLSCREEN and max_width/heigth independently;
1430 * whether they should is undefined. So don't set the max size hint
1431 * for a full screen window.
1433 if( m_pWindow && ! isChild() )
1435 GdkGeometry aGeo;
1436 int aHints = 0;
1437 if( m_nStyle & SAL_FRAME_STYLE_SIZEABLE )
1439 if( m_aMinSize.Width() && m_aMinSize.Height() )
1441 aGeo.min_width = m_aMinSize.Width()+CONTAINER_ADJUSTMENT;
1442 aGeo.min_height = m_aMinSize.Height()+CONTAINER_ADJUSTMENT;
1443 aHints |= GDK_HINT_MIN_SIZE;
1445 if( m_aMaxSize.Width() && m_aMaxSize.Height() && ! m_bFullscreen )
1447 aGeo.max_width = m_aMaxSize.Width()+CONTAINER_ADJUSTMENT;
1448 aGeo.max_height = m_aMaxSize.Height()+CONTAINER_ADJUSTMENT;
1449 aHints |= GDK_HINT_MAX_SIZE;
1452 else
1454 aGeo.min_width = maGeometry.nWidth;
1455 aGeo.min_height = maGeometry.nHeight;
1456 aHints |= GDK_HINT_MIN_SIZE;
1457 if( ! m_bFullscreen )
1459 aGeo.max_width = maGeometry.nWidth;
1460 aGeo.max_height = maGeometry.nHeight;
1461 aHints |= GDK_HINT_MAX_SIZE;
1464 if( aHints )
1465 gtk_window_set_geometry_hints( GTK_WINDOW(m_pWindow),
1466 NULL,
1467 &aGeo,
1468 GdkWindowHints( aHints ) );
1472 void GtkSalFrame::SetMaxClientSize( long nWidth, long nHeight )
1474 if( ! isChild() )
1476 m_aMaxSize = Size( nWidth, nHeight );
1477 // Show does a setMinMaxSize
1478 if( GTK_WIDGET_MAPPED( m_pWindow ) )
1479 setMinMaxSize();
1482 void GtkSalFrame::SetMinClientSize( long nWidth, long nHeight )
1484 if( ! isChild() )
1486 m_aMinSize = Size( nWidth, nHeight );
1487 if( m_pWindow )
1489 gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
1490 // Show does a setMinMaxSize
1491 if( GTK_WIDGET_MAPPED( m_pWindow ) )
1492 setMinMaxSize();
1497 void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags )
1499 if( !m_pWindow || isChild( true, false ) )
1500 return;
1502 bool bSized = false, bMoved = false;
1504 if( (nFlags & ( SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT )) &&
1505 (nWidth > 0 && nHeight > 0 ) // sometimes stupid things happen
1508 m_bDefaultSize = false;
1510 if( (unsigned long)nWidth != maGeometry.nWidth || (unsigned long)nHeight != maGeometry.nHeight )
1511 bSized = true;
1512 maGeometry.nWidth = nWidth;
1513 maGeometry.nHeight = nHeight;
1515 if( isChild( false, true ) )
1516 gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
1517 else if( ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) )
1518 gtk_window_resize( GTK_WINDOW(m_pWindow), nWidth, nHeight );
1519 setMinMaxSize();
1521 else if( m_bDefaultSize )
1522 SetDefaultSize();
1524 m_bDefaultSize = false;
1526 if( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) )
1528 if( m_pParent )
1530 if( Application::GetSettings().GetLayoutRTL() )
1531 nX = m_pParent->maGeometry.nWidth-maGeometry.nWidth-1-nX;
1532 nX += m_pParent->maGeometry.nX;
1533 nY += m_pParent->maGeometry.nY;
1536 // adjust position to avoid off screen windows
1537 // but allow toolbars to be positioned partly off screen by the user
1538 Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
1539 if( ! (m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
1541 if( nX < (long)maGeometry.nLeftDecoration )
1542 nX = maGeometry.nLeftDecoration;
1543 if( nY < (long)maGeometry.nTopDecoration )
1544 nY = maGeometry.nTopDecoration;
1545 if( (nX + (long)maGeometry.nWidth + (long)maGeometry.nRightDecoration) > (long)aScreenSize.Width() )
1546 nX = aScreenSize.Width() - maGeometry.nWidth - maGeometry.nRightDecoration;
1547 if( (nY + (long)maGeometry.nHeight + (long)maGeometry.nBottomDecoration) > (long)aScreenSize.Height() )
1548 nY = aScreenSize.Height() - maGeometry.nHeight - maGeometry.nBottomDecoration;
1550 else
1552 if( nX + (long)maGeometry.nWidth < 10 )
1553 nX = 10 - (long)maGeometry.nWidth;
1554 if( nY + (long)maGeometry.nHeight < 10 )
1555 nY = 10 - (long)maGeometry.nHeight;
1556 if( nX > (long)aScreenSize.Width() - 10 )
1557 nX = (long)aScreenSize.Width() - 10;
1558 if( nY > (long)aScreenSize.Height() - 10 )
1559 nY = (long)aScreenSize.Height() - 10;
1562 if( nX != maGeometry.nX || nY != maGeometry.nY )
1563 bMoved = true;
1564 maGeometry.nX = nX;
1565 maGeometry.nY = nY;
1567 m_bDefaultPos = false;
1569 moveWindow( maGeometry.nX, maGeometry.nY );
1571 updateScreenNumber();
1573 else if( m_bDefaultPos )
1574 Center();
1576 m_bDefaultPos = false;
1578 if( bSized && ! bMoved )
1579 CallCallback( SALEVENT_RESIZE, NULL );
1580 else if( bMoved && ! bSized )
1581 CallCallback( SALEVENT_MOVE, NULL );
1582 else if( bMoved && bSized )
1583 CallCallback( SALEVENT_MOVERESIZE, NULL );
1586 void GtkSalFrame::GetClientSize( long& rWidth, long& rHeight )
1588 if( m_pWindow && !(m_nState & GDK_WINDOW_STATE_ICONIFIED) )
1590 rWidth = maGeometry.nWidth;
1591 rHeight = maGeometry.nHeight;
1593 else
1594 rWidth = rHeight = 0;
1597 void GtkSalFrame::GetWorkArea( Rectangle& rRect )
1599 rRect = GetX11SalData()->GetDisplay()->getWMAdaptor()->getWorkArea( 0 );
1602 SalFrame* GtkSalFrame::GetParent() const
1604 return m_pParent;
1607 void GtkSalFrame::SetWindowState( const SalFrameState* pState )
1609 if( ! m_pWindow || ! pState || isChild( true, false ) )
1610 return;
1612 const ULONG nMaxGeometryMask =
1613 SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y |
1614 SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT |
1615 SAL_FRAMESTATE_MASK_MAXIMIZED_X | SAL_FRAMESTATE_MASK_MAXIMIZED_Y |
1616 SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT;
1618 if( (pState->mnMask & SAL_FRAMESTATE_MASK_STATE) &&
1619 ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) &&
1620 (pState->mnState & SAL_FRAMESTATE_MAXIMIZED) &&
1621 (pState->mnMask & nMaxGeometryMask) == nMaxGeometryMask )
1623 resizeWindow( pState->mnWidth, pState->mnHeight );
1624 moveWindow( pState->mnX, pState->mnY );
1625 m_bDefaultPos = m_bDefaultSize = false;
1627 maGeometry.nX = pState->mnMaximizedX;
1628 maGeometry.nY = pState->mnMaximizedY;
1629 maGeometry.nWidth = pState->mnMaximizedWidth;
1630 maGeometry.nHeight = pState->mnMaximizedHeight;
1631 updateScreenNumber();
1633 m_nState = GdkWindowState( m_nState | GDK_WINDOW_STATE_MAXIMIZED );
1634 m_aRestorePosSize = Rectangle( Point( pState->mnX, pState->mnY ),
1635 Size( pState->mnWidth, pState->mnHeight ) );
1637 else if( pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y |
1638 SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT ) )
1640 USHORT nPosSizeFlags = 0;
1641 long nX = pState->mnX - (m_pParent ? m_pParent->maGeometry.nX : 0);
1642 long nY = pState->mnY - (m_pParent ? m_pParent->maGeometry.nY : 0);
1643 long nWidth = pState->mnWidth;
1644 long nHeight = pState->mnHeight;
1645 if( pState->mnMask & SAL_FRAMESTATE_MASK_X )
1646 nPosSizeFlags |= SAL_FRAME_POSSIZE_X;
1647 else
1648 nX = maGeometry.nX - (m_pParent ? m_pParent->maGeometry.nX : 0);
1649 if( pState->mnMask & SAL_FRAMESTATE_MASK_Y )
1650 nPosSizeFlags |= SAL_FRAME_POSSIZE_Y;
1651 else
1652 nY = maGeometry.nY - (m_pParent ? m_pParent->maGeometry.nY : 0);
1653 if( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH )
1654 nPosSizeFlags |= SAL_FRAME_POSSIZE_WIDTH;
1655 else
1656 nWidth = maGeometry.nWidth;
1657 if( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT )
1658 nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT;
1659 else
1660 nHeight = maGeometry.nHeight;
1661 SetPosSize( nX, nY, pState->mnWidth, pState->mnHeight, nPosSizeFlags );
1663 if( pState->mnMask & SAL_FRAMESTATE_MASK_STATE && ! isChild() )
1665 if( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
1666 gtk_window_maximize( GTK_WINDOW(m_pWindow) );
1667 else
1668 gtk_window_unmaximize( GTK_WINDOW(m_pWindow) );
1669 /* #i42379# there is no rollup state in GDK; and rolled up windows are
1670 * (probably depending on the WM) reported as iconified. If we iconify a
1671 * window here that was e.g. a dialog, then it will be unmapped but still
1672 * not be displayed in the task list, so it's an iconified window that
1673 * the user cannot get out of this state. So do not set the iconified state
1674 * on windows with a parent (that is transient frames) since these tend
1675 * to not be represented in an icon task list.
1677 if( (pState->mnState & SAL_FRAMESTATE_MINIMIZED)
1678 && ! m_pParent )
1679 gtk_window_iconify( GTK_WINDOW(m_pWindow) );
1680 else
1681 gtk_window_deiconify( GTK_WINDOW(m_pWindow) );
1685 BOOL GtkSalFrame::GetWindowState( SalFrameState* pState )
1687 pState->mnState = SAL_FRAMESTATE_NORMAL;
1688 pState->mnMask = SAL_FRAMESTATE_MASK_STATE;
1689 // rollup ? gtk 2.2 does not seem to support the shaded state
1690 if( (m_nState & GDK_WINDOW_STATE_ICONIFIED) )
1691 pState->mnState |= SAL_FRAMESTATE_MINIMIZED;
1692 if( m_nState & GDK_WINDOW_STATE_MAXIMIZED )
1694 pState->mnState |= SAL_FRAMESTATE_MAXIMIZED;
1695 pState->mnX = m_aRestorePosSize.Left();
1696 pState->mnY = m_aRestorePosSize.Top();
1697 pState->mnWidth = m_aRestorePosSize.GetWidth();
1698 pState->mnHeight = m_aRestorePosSize.GetHeight();
1699 pState->mnMaximizedX = maGeometry.nX;
1700 pState->mnMaximizedY = maGeometry.nY;
1701 pState->mnMaximizedWidth = maGeometry.nWidth;
1702 pState->mnMaximizedHeight = maGeometry.nHeight;
1703 pState->mnMask |= SAL_FRAMESTATE_MASK_MAXIMIZED_X |
1704 SAL_FRAMESTATE_MASK_MAXIMIZED_Y |
1705 SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH |
1706 SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT;
1708 else
1711 pState->mnX = maGeometry.nX;
1712 pState->mnY = maGeometry.nY;
1713 pState->mnWidth = maGeometry.nWidth;
1714 pState->mnHeight = maGeometry.nHeight;
1716 pState->mnMask |= SAL_FRAMESTATE_MASK_X |
1717 SAL_FRAMESTATE_MASK_Y |
1718 SAL_FRAMESTATE_MASK_WIDTH |
1719 SAL_FRAMESTATE_MASK_HEIGHT;
1721 return TRUE;
1724 void GtkSalFrame::moveToScreen( int nScreen )
1726 if( isChild() )
1727 return;
1729 if( nScreen < 0 || nScreen >= gdk_display_get_n_screens( getGdkDisplay() ) )
1730 nScreen = m_nScreen;
1731 if( nScreen == m_nScreen )
1732 return;
1734 GdkScreen* pScreen = gdk_display_get_screen( getGdkDisplay(), nScreen );
1735 if( pScreen )
1737 m_nScreen = nScreen;
1738 gtk_window_set_screen( GTK_WINDOW(m_pWindow), pScreen );
1739 // realize the window, we need an XWindow id
1740 gtk_widget_realize( m_pWindow );
1741 // update system data
1742 GtkSalDisplay* pDisp = getDisplay();
1743 m_aSystemData.aWindow = GDK_WINDOW_XWINDOW(m_pWindow->window);
1744 m_aSystemData.pVisual = pDisp->GetVisual( m_nScreen ).GetVisual();
1745 m_aSystemData.nScreen = nScreen;
1746 m_aSystemData.nDepth = pDisp->GetVisual( m_nScreen ).GetDepth();
1747 m_aSystemData.aColormap = pDisp->GetColormap( m_nScreen ).GetXColormap();
1748 m_aSystemData.pAppContext = NULL;
1749 m_aSystemData.aShellWindow = m_aSystemData.aWindow;
1750 // update graphics if necessary
1751 for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
1753 if( m_aGraphics[i].bInUse )
1754 m_aGraphics[i].pGraphics->SetDrawable( GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
1756 updateScreenNumber();
1759 if( m_pParent && m_pParent->m_nScreen != m_nScreen )
1760 SetParent( NULL );
1761 std::list< GtkSalFrame* > aChildren = m_aChildren;
1762 for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
1763 (*it)->moveToScreen( m_nScreen );
1765 // FIXME: SalObjects
1768 void GtkSalFrame::SetScreenNumber( unsigned int nNewScreen )
1770 if( nNewScreen == maGeometry.nScreenNumber )
1771 return;
1773 if( m_pWindow && ! isChild() )
1775 GtkSalDisplay* pDisp = getDisplay();
1776 if( pDisp->IsXinerama() && pDisp->GetXineramaScreens().size() > 1 )
1778 if( nNewScreen >= pDisp->GetXineramaScreens().size() )
1779 return;
1781 Rectangle aOldScreenRect( pDisp->GetXineramaScreens()[maGeometry.nScreenNumber] );
1782 Rectangle aNewScreenRect( pDisp->GetXineramaScreens()[nNewScreen] );
1783 bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
1784 if( bVisible )
1785 Show( FALSE );
1786 maGeometry.nX = aNewScreenRect.Left() + (maGeometry.nX - aOldScreenRect.Left());
1787 maGeometry.nY = aNewScreenRect.Top() + (maGeometry.nY - aOldScreenRect.Top());
1788 createNewWindow( None, false, m_nScreen );
1789 gtk_window_move( GTK_WINDOW(m_pWindow), maGeometry.nX, maGeometry.nY );
1790 if( bVisible )
1791 Show( TRUE );
1792 maGeometry.nScreenNumber = nNewScreen;
1794 else if( sal_Int32(nNewScreen) < pDisp->GetScreenCount() )
1796 moveToScreen( (int)nNewScreen );
1797 maGeometry.nScreenNumber = nNewScreen;
1798 gtk_window_move( GTK_WINDOW(m_pWindow), maGeometry.nX, maGeometry.nY );
1803 void GtkSalFrame::ShowFullScreen( BOOL bFullScreen, sal_Int32 nScreen )
1805 if( m_pWindow && ! isChild() )
1807 GtkSalDisplay* pDisp = getDisplay();
1808 // xinerama ?
1809 if( pDisp->IsXinerama() && pDisp->GetXineramaScreens().size() > 1 )
1811 if( bFullScreen )
1813 m_aRestorePosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
1814 Size( maGeometry.nWidth, maGeometry.nHeight ) );
1815 // workaround different window managers have different opinions about
1816 // _NET_WM_STATE_FULLSCREEN (Metacity <-> KWin)
1817 bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
1818 if( bVisible )
1819 Show( FALSE );
1820 m_nStyle |= SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
1821 createNewWindow( None, false, m_nScreen );
1822 Rectangle aNewPosSize;
1823 if( nScreen < 0 || nScreen >= static_cast<int>(pDisp->GetXineramaScreens().size()) )
1824 aNewPosSize = Rectangle( Point( 0, 0 ), pDisp->GetScreenSize(m_nScreen) );
1825 else
1826 aNewPosSize = pDisp->GetXineramaScreens()[ nScreen ];
1827 gtk_window_resize( GTK_WINDOW(m_pWindow),
1828 maGeometry.nWidth = aNewPosSize.GetWidth(),
1829 maGeometry.nHeight = aNewPosSize.GetHeight() );
1830 gtk_window_move( GTK_WINDOW(m_pWindow),
1831 maGeometry.nX = aNewPosSize.Left(),
1832 maGeometry.nY = aNewPosSize.Top() );
1833 if( bVisible )
1834 Show( TRUE );
1836 else
1838 bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
1839 if( bVisible )
1840 Show( FALSE );
1841 m_nStyle &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
1842 createNewWindow( None, false, m_nScreen );
1843 if( ! m_aRestorePosSize.IsEmpty() )
1845 gtk_window_resize( GTK_WINDOW(m_pWindow),
1846 maGeometry.nWidth = m_aRestorePosSize.GetWidth(),
1847 maGeometry.nHeight = m_aRestorePosSize.GetHeight() );
1848 gtk_window_move( GTK_WINDOW(m_pWindow),
1849 maGeometry.nX = m_aRestorePosSize.Left(),
1850 maGeometry.nY = m_aRestorePosSize.Top() );
1851 m_aRestorePosSize = Rectangle();
1853 if( bVisible )
1854 Show( TRUE );
1857 else
1859 if( bFullScreen )
1861 if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
1862 gtk_window_set_resizable( GTK_WINDOW(m_pWindow), TRUE );
1863 gtk_window_fullscreen( GTK_WINDOW(m_pWindow) );
1864 moveToScreen( nScreen );
1865 Size aScreenSize = pDisp->GetScreenSize( m_nScreen );
1866 maGeometry.nX = 0;
1867 maGeometry.nY = 0;
1868 maGeometry.nWidth = aScreenSize.Width();
1869 maGeometry.nHeight = aScreenSize.Height();
1871 else
1873 gtk_window_unfullscreen( GTK_WINDOW(m_pWindow) );
1874 if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
1875 gtk_window_set_resizable( GTK_WINDOW(m_pWindow), FALSE );
1876 moveToScreen( nScreen );
1879 m_bDefaultPos = m_bDefaultSize = false;
1880 updateScreenNumber();
1881 CallCallback( SALEVENT_MOVERESIZE, NULL );
1883 m_bFullscreen = bFullScreen;
1886 /* definitions from xautolock.c (pl15) */
1887 #define XAUTOLOCK_DISABLE 1
1888 #define XAUTOLOCK_ENABLE 2
1890 void GtkSalFrame::setAutoLock( bool bLock )
1892 if( isChild() )
1893 return;
1895 GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(m_pWindow) );
1896 GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
1897 GdkWindow *pRootWin = gdk_screen_get_root_window( pScreen );
1899 Atom nAtom = XInternAtom( GDK_DISPLAY_XDISPLAY( pDisplay ),
1900 "XAUTOLOCK_MESSAGE", False );
1902 int nMessage = bLock ? XAUTOLOCK_ENABLE : XAUTOLOCK_DISABLE;
1904 XChangeProperty( GDK_DISPLAY_XDISPLAY( pDisplay ),
1905 GDK_WINDOW_XID( pRootWin ),
1906 nAtom, XA_INTEGER,
1907 8, PropModeReplace,
1908 (unsigned char*)&nMessage,
1909 sizeof( nMessage ) );
1912 #ifdef ENABLE_DBUS
1913 /** cookie is returned as an unsigned integer */
1914 static guint
1915 dbus_inhibit_gss (const gchar *appname,
1916 const gchar *reason)
1918 gboolean res;
1919 guint cookie;
1920 GError *error = NULL;
1921 DBusGProxy *proxy = NULL;
1922 DBusGConnection *session_connection = NULL;
1924 /* get the DBUS session connection */
1925 session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
1926 if (error != NULL) {
1927 g_warning ("DBUS cannot connect : %s", error->message);
1928 g_error_free (error);
1929 return -1;
1932 /* get the proxy with gnome-screensaver */
1933 proxy = dbus_g_proxy_new_for_name (session_connection,
1934 GSS_DBUS_SERVICE,
1935 GSS_DBUS_PATH,
1936 GSS_DBUS_INTERFACE);
1937 if (proxy == NULL) {
1938 g_warning ("Could not get DBUS proxy: %s", GSS_DBUS_SERVICE);
1939 return -1;
1942 res = dbus_g_proxy_call (proxy,
1943 "Inhibit", &error,
1944 G_TYPE_STRING, appname,
1945 G_TYPE_STRING, reason,
1946 G_TYPE_INVALID,
1947 G_TYPE_UINT, &cookie,
1948 G_TYPE_INVALID);
1950 /* check the return value */
1951 if (! res) {
1952 cookie = -1;
1953 g_warning ("Inhibit method failed");
1956 /* check the error value */
1957 if (error != NULL) {
1958 g_warning ("Inhibit problem : %s", error->message);
1959 g_error_free (error);
1960 cookie = -1;
1963 g_object_unref (G_OBJECT (proxy));
1964 return cookie;
1967 static void
1968 dbus_uninhibit_gss (guint cookie)
1970 gboolean res;
1971 GError *error = NULL;
1972 DBusGProxy *proxy = NULL;
1973 DBusGConnection *session_connection = NULL;
1975 /* cookies have to be positive as unsigned */
1976 if (cookie < 0) {
1977 g_warning ("Invalid cookie");
1978 return;
1981 /* get the DBUS session connection */
1982 session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
1983 if (error) {
1984 g_warning ("DBUS cannot connect : %s", error->message);
1985 g_error_free (error);
1986 return;
1989 /* get the proxy with gnome-screensaver */
1990 proxy = dbus_g_proxy_new_for_name (session_connection,
1991 GSS_DBUS_SERVICE,
1992 GSS_DBUS_PATH,
1993 GSS_DBUS_INTERFACE);
1994 if (proxy == NULL) {
1995 g_warning ("Could not get DBUS proxy: %s", GSS_DBUS_SERVICE);
1996 return;
1999 res = dbus_g_proxy_call (proxy,
2000 "UnInhibit",
2001 &error,
2002 G_TYPE_UINT, cookie,
2003 G_TYPE_INVALID,
2004 G_TYPE_INVALID);
2006 /* check the return value */
2007 if (! res) {
2008 g_warning ("UnInhibit method failed");
2011 /* check the error value */
2012 if (error != NULL) {
2013 g_warning ("Inhibit problem : %s", error->message);
2014 g_error_free (error);
2015 cookie = -1;
2017 g_object_unref (G_OBJECT (proxy));
2019 #endif
2021 void GtkSalFrame::StartPresentation( BOOL bStart )
2023 Display *pDisplay = GDK_DISPLAY_XDISPLAY( getGdkDisplay() );
2025 setAutoLock( !bStart );
2027 int nTimeout, nInterval, bPreferBlanking, bAllowExposures;
2029 XGetScreenSaver( pDisplay, &nTimeout, &nInterval,
2030 &bPreferBlanking, &bAllowExposures );
2031 if( bStart )
2033 if ( nTimeout )
2035 m_nSavedScreenSaverTimeout = nTimeout;
2036 XResetScreenSaver( pDisplay );
2037 XSetScreenSaver( pDisplay, 0, nInterval,
2038 bPreferBlanking, bAllowExposures );
2040 #ifdef ENABLE_DBUS
2041 m_nGSSCookie = dbus_inhibit_gss(g_get_application_name(), "presentation");
2042 #endif
2044 else
2046 if( m_nSavedScreenSaverTimeout )
2047 XSetScreenSaver( pDisplay, m_nSavedScreenSaverTimeout,
2048 nInterval, bPreferBlanking,
2049 bAllowExposures );
2050 m_nSavedScreenSaverTimeout = 0;
2051 #ifdef ENABLE_DBUS
2052 dbus_uninhibit_gss(m_nGSSCookie);
2053 #endif
2057 void GtkSalFrame::SetAlwaysOnTop( BOOL /*bOnTop*/ )
2061 void GtkSalFrame::ToTop( USHORT nFlags )
2063 if( m_pWindow )
2065 if( isChild( false, true ) )
2066 gtk_widget_grab_focus( m_pWindow );
2067 else if( GTK_WIDGET_MAPPED( m_pWindow ) )
2069 if( ! (nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY) )
2070 gtk_window_present( GTK_WINDOW(m_pWindow) );
2071 else
2073 // gdk_window_focus( m_pWindow->window, gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window) );
2074 /* #i99360# ugly workaround an X11 library bug */
2075 guint32 nUserTime= getDisplay()->GetLastUserEventTime( true );
2076 gdk_window_focus( m_pWindow->window, nUserTime );
2078 /* need to do an XSetInputFocus here because
2079 * gdk_window_focus will ask a EWMH compliant WM to put the focus
2080 * to our window - which it of course won't since our input hint
2081 * is set to false.
2083 if( (m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
2084 XSetInputFocus( getDisplay()->GetDisplay(), GDK_WINDOW_XWINDOW( m_pWindow->window ), RevertToParent, CurrentTime );
2086 else
2088 if( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
2089 gtk_window_present( GTK_WINDOW(m_pWindow) );
2094 void GtkSalFrame::SetPointer( PointerStyle ePointerStyle )
2096 if( m_pWindow && ePointerStyle != m_ePointerStyle )
2098 m_ePointerStyle = ePointerStyle;
2099 GdkCursor *pCursor = getDisplay()->getCursor( ePointerStyle );
2100 gdk_window_set_cursor( m_pWindow->window, pCursor );
2101 m_pCurrentCursor = pCursor;
2103 // #i80791# use grabPointer the same way as CaptureMouse, respective float grab
2104 if( getDisplay()->MouseCaptured( this ) )
2105 grabPointer( TRUE, FALSE );
2106 else if( m_nFloats > 0 )
2107 grabPointer( TRUE, TRUE );
2111 void GtkSalFrame::grabPointer( BOOL bGrab, BOOL bOwnerEvents )
2113 if( m_pWindow )
2115 if( bGrab )
2117 bool bUseGdkGrab = true;
2118 if( getDisplay()->getHaveSystemChildFrame() )
2120 const std::list< SalFrame* >& rFrames = getDisplay()->getFrames();
2121 for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
2123 const GtkSalFrame* pFrame = static_cast< const GtkSalFrame* >(*it);
2124 if( pFrame->m_bWindowIsGtkPlug )
2126 bUseGdkGrab = false;
2127 break;
2131 if( bUseGdkGrab )
2133 const int nMask = ( GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK );
2135 gdk_pointer_grab( m_pWindow->window, bOwnerEvents,
2136 (GdkEventMask) nMask, NULL, m_pCurrentCursor,
2137 GDK_CURRENT_TIME );
2139 else
2141 // FIXME: for some unknown reason gdk_pointer_grab does not
2142 // really produce owner events for GtkPlug windows
2143 // the cause is yet unknown
2145 // this is of course a bad hack, especially as we cannot
2146 // set the right cursor this way
2147 XGrabPointer( getDisplay()->GetDisplay(),
2148 GDK_WINDOW_XWINDOW( m_pWindow->window),
2149 bOwnerEvents,
2150 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
2151 GrabModeAsync,
2152 GrabModeAsync,
2153 None,
2154 None,
2155 CurrentTime
2160 else
2162 // Two GdkDisplays may be open
2163 gdk_display_pointer_ungrab( getGdkDisplay(), GDK_CURRENT_TIME);
2168 void GtkSalFrame::CaptureMouse( BOOL bCapture )
2170 getDisplay()->CaptureMouse( bCapture ? this : NULL );
2173 void GtkSalFrame::SetPointerPos( long nX, long nY )
2175 GtkSalFrame* pFrame = this;
2176 while( pFrame && pFrame->isChild( false, true ) )
2177 pFrame = pFrame->m_pParent;
2178 if( ! pFrame )
2179 return;
2181 GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(pFrame->m_pWindow) );
2182 GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
2184 /* #87921# when the application tries to center the mouse in the dialog the
2185 * window isn't mapped already. So use coordinates relative to the root window.
2187 unsigned int nWindowLeft = maGeometry.nX + nX;
2188 unsigned int nWindowTop = maGeometry.nY + nY;
2190 XWarpPointer( GDK_DISPLAY_XDISPLAY (pDisplay), None,
2191 GDK_WINDOW_XID (gdk_screen_get_root_window( pScreen ) ),
2192 0, 0, 0, 0, nWindowLeft, nWindowTop);
2193 // #i38648# ask for the next motion hint
2194 gint x, y;
2195 GdkModifierType mask;
2196 gdk_window_get_pointer( pFrame->m_pWindow->window, &x, &y, &mask );
2199 void GtkSalFrame::Flush()
2201 #ifdef HAVE_A_RECENT_GTK
2202 gdk_display_flush( getGdkDisplay() );
2203 #else
2204 XFlush (GDK_DISPLAY_XDISPLAY (getGdkDisplay()));
2205 #endif
2208 void GtkSalFrame::Sync()
2210 gdk_display_sync( getGdkDisplay() );
2213 String GtkSalFrame::GetSymbolKeyName( const String&, USHORT nKeyCode )
2215 return getDisplay()->GetKeyName( nKeyCode );
2218 String GtkSalFrame::GetKeyName( USHORT nKeyCode )
2220 return getDisplay()->GetKeyName( nKeyCode );
2223 GdkDisplay *GtkSalFrame::getGdkDisplay()
2225 return static_cast<GtkSalDisplay*>(GetX11SalData()->GetDisplay())->GetGdkDisplay();
2228 GtkSalDisplay *GtkSalFrame::getDisplay()
2230 return static_cast<GtkSalDisplay*>(GetX11SalData()->GetDisplay());
2233 SalFrame::SalPointerState GtkSalFrame::GetPointerState()
2235 SalPointerState aState;
2236 GdkScreen* pScreen;
2237 gint x, y;
2238 GdkModifierType aMask;
2239 gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
2240 aState.maPos = Point( x - maGeometry.nX, y - maGeometry.nY );
2241 aState.mnState = GetMouseModCode( aMask );
2242 return aState;
2245 SalFrame::SalIndicatorState GtkSalFrame::GetIndicatorState()
2247 SalIndicatorState aState;
2248 aState.mnState = GetX11SalData()->GetDisplay()->GetIndicatorState();
2249 return aState;
2252 void GtkSalFrame::SimulateKeyPress( USHORT nKeyCode )
2254 GetX11SalData()->GetDisplay()->SimulateKeyPress(nKeyCode);
2257 void GtkSalFrame::SetInputContext( SalInputContext* pContext )
2259 if( ! pContext )
2260 return;
2262 if( ! (pContext->mnOptions & SAL_INPUTCONTEXT_TEXT) )
2263 return;
2265 // create a new im context
2266 if( ! m_pIMHandler )
2267 m_pIMHandler = new IMHandler( this );
2268 m_pIMHandler->setInputContext( pContext );
2271 void GtkSalFrame::EndExtTextInput( USHORT nFlags )
2273 if( m_pIMHandler )
2274 m_pIMHandler->endExtTextInput( nFlags );
2277 BOOL GtkSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& )
2279 // not supported yet
2280 return FALSE;
2283 LanguageType GtkSalFrame::GetInputLanguage()
2285 return LANGUAGE_DONTKNOW;
2288 SalBitmap* GtkSalFrame::SnapShot()
2290 if( !m_pWindow )
2291 return NULL;
2293 X11SalBitmap *pBmp = new X11SalBitmap;
2294 GdkWindow *pWin = m_pWindow->window;
2295 if( pBmp->SnapShot( GDK_DISPLAY_XDISPLAY( getGdkDisplay() ),
2296 GDK_WINDOW_XID( pWin ) ) )
2297 return pBmp;
2298 else
2299 delete pBmp;
2301 return NULL;
2304 void GtkSalFrame::UpdateSettings( AllSettings& rSettings )
2306 if( ! m_pWindow )
2307 return;
2309 GtkSalGraphics* pGraphics = static_cast<GtkSalGraphics*>(m_aGraphics[0].pGraphics);
2310 bool bFreeGraphics = false;
2311 if( ! pGraphics )
2313 pGraphics = static_cast<GtkSalGraphics*>(GetGraphics());
2314 bFreeGraphics = true;
2317 pGraphics->updateSettings( rSettings );
2319 if( bFreeGraphics )
2320 ReleaseGraphics( pGraphics );
2323 void GtkSalFrame::Beep( SoundType eType )
2325 switch( eType )
2327 case SOUND_DEFAULT:
2328 case SOUND_ERROR:
2329 gdk_display_beep( getGdkDisplay() );
2330 break;
2331 default:
2332 break;
2336 const SystemEnvData* GtkSalFrame::GetSystemData() const
2338 return &m_aSystemData;
2341 void GtkSalFrame::SetParent( SalFrame* pNewParent )
2343 if( m_pParent )
2344 m_pParent->m_aChildren.remove( this );
2345 m_pParent = static_cast<GtkSalFrame*>(pNewParent);
2346 if( m_pParent )
2347 m_pParent->m_aChildren.push_back( this );
2348 if( ! isChild() )
2349 gtk_window_set_transient_for( GTK_WINDOW(m_pWindow),
2350 (m_pParent && ! m_pParent->isChild(true,false)) ? GTK_WINDOW(m_pParent->m_pWindow) : NULL
2354 void GtkSalFrame::createNewWindow( XLIB_Window aNewParent, bool bXEmbed, int nScreen )
2356 bool bWasVisible = GTK_WIDGET_MAPPED(m_pWindow);
2357 if( bWasVisible )
2358 Show( FALSE );
2360 if( nScreen < 0 || nScreen >= getDisplay()->GetScreenCount() )
2361 nScreen = m_nScreen;
2363 SystemParentData aParentData;
2364 aParentData.aWindow = aNewParent;
2365 aParentData.bXEmbedSupport = bXEmbed;
2366 if( aNewParent == None )
2368 aNewParent = getDisplay()->GetRootWindow(nScreen);
2369 aParentData.aWindow = None;
2370 aParentData.bXEmbedSupport = false;
2372 else
2374 // is new parent a root window ?
2375 Display* pDisp = getDisplay()->GetDisplay();
2376 int nScreens = getDisplay()->GetScreenCount();
2377 for( int i = 0; i < nScreens; i++ )
2379 if( aNewParent == RootWindow( pDisp, i ) )
2381 nScreen = i;
2382 aParentData.aWindow = None;
2383 aParentData.bXEmbedSupport = false;
2384 break;
2389 // first deinit frame
2390 if( m_pIMHandler )
2392 delete m_pIMHandler;
2393 m_pIMHandler = NULL;
2395 if( m_pRegion )
2396 gdk_region_destroy( m_pRegion );
2397 if( m_pFixedContainer )
2398 gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer) );
2399 if( m_pWindow )
2400 gtk_widget_destroy( m_pWindow );
2401 if( m_pForeignParent )
2402 g_object_unref( G_OBJECT(m_pForeignParent) );
2403 if( m_pForeignTopLevel )
2404 g_object_unref( G_OBJECT(m_pForeignTopLevel) );
2406 // init new window
2407 m_bDefaultPos = m_bDefaultSize = false;
2408 if( aParentData.aWindow != None )
2410 m_nStyle |= SAL_FRAME_STYLE_PLUG;
2411 Init( &aParentData );
2413 else
2415 m_nStyle &= ~SAL_FRAME_STYLE_PLUG;
2416 Init( (m_pParent && m_pParent->m_nScreen == m_nScreen) ? m_pParent : NULL, m_nStyle );
2419 // update graphics
2420 for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
2422 if( m_aGraphics[i].bInUse )
2424 m_aGraphics[i].pGraphics->SetDrawable( GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
2425 m_aGraphics[i].pGraphics->SetWindow( m_pWindow );
2429 if( m_aTitle.Len() )
2430 SetTitle( m_aTitle );
2432 if( bWasVisible )
2433 Show( TRUE );
2435 std::list< GtkSalFrame* > aChildren = m_aChildren;
2436 m_aChildren.clear();
2437 for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
2438 (*it)->createNewWindow( None, false, m_nScreen );
2440 // FIXME: SalObjects
2443 bool GtkSalFrame::SetPluginParent( SystemParentData* pSysParent )
2445 if( pSysParent ) // this may be the first system child frame now
2446 getDisplay()->setHaveSystemChildFrame();
2447 createNewWindow( pSysParent->aWindow, (pSysParent->nSize > sizeof(long)) ? pSysParent->bXEmbedSupport : false, m_nScreen );
2448 return true;
2451 void GtkSalFrame::ResetClipRegion()
2453 if( m_pWindow )
2454 gdk_window_shape_combine_region( m_pWindow->window, NULL, 0, 0 );
2457 void GtkSalFrame::BeginSetClipRegion( ULONG )
2459 if( m_pRegion )
2460 gdk_region_destroy( m_pRegion );
2461 m_pRegion = gdk_region_new();
2464 void GtkSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
2466 if( m_pRegion )
2468 GdkRectangle aRect;
2469 aRect.x = nX;
2470 aRect.y = nY;
2471 aRect.width = nWidth;
2472 aRect.height = nHeight;
2474 gdk_region_union_with_rect( m_pRegion, &aRect );
2478 void GtkSalFrame::EndSetClipRegion()
2480 if( m_pWindow && m_pRegion )
2481 gdk_window_shape_combine_region( m_pWindow->window, m_pRegion, 0, 0 );
2484 bool GtkSalFrame::Dispatch( const XEvent* pEvent )
2486 bool bContinueDispatch = true;
2488 if( pEvent->type == PropertyNotify )
2490 vcl_sal::WMAdaptor* pAdaptor = getDisplay()->getWMAdaptor();
2491 Atom nDesktopAtom = pAdaptor->getAtom( vcl_sal::WMAdaptor::NET_WM_DESKTOP );
2492 if( pEvent->xproperty.atom == nDesktopAtom &&
2493 pEvent->xproperty.state == PropertyNewValue )
2495 m_nWorkArea = pAdaptor->getWindowWorkArea( GDK_WINDOW_XWINDOW( m_pWindow->window) );
2498 else if( pEvent->type == ConfigureNotify )
2500 if( m_pForeignParent && pEvent->xconfigure.window == m_aForeignParentWindow )
2502 bContinueDispatch = false;
2503 gtk_window_resize( GTK_WINDOW(m_pWindow), pEvent->xconfigure.width, pEvent->xconfigure.height );
2504 if( ( sal::static_int_cast< int >(maGeometry.nWidth) !=
2505 pEvent->xconfigure.width ) ||
2506 ( sal::static_int_cast< int >(maGeometry.nHeight) !=
2507 pEvent->xconfigure.height ) )
2509 maGeometry.nWidth = pEvent->xconfigure.width;
2510 maGeometry.nHeight = pEvent->xconfigure.height;
2511 setMinMaxSize();
2512 getDisplay()->SendInternalEvent( this, NULL, SALEVENT_RESIZE );
2515 else if( m_pForeignTopLevel && pEvent->xconfigure.window == m_aForeignTopLevelWindow )
2517 bContinueDispatch = false;
2518 // update position
2519 int x = 0, y = 0;
2520 XLIB_Window aChild;
2521 XTranslateCoordinates( getDisplay()->GetDisplay(),
2522 GDK_WINDOW_XWINDOW( m_pWindow->window),
2523 getDisplay()->GetRootWindow( getDisplay()->GetDefaultScreenNumber() ),
2524 0, 0,
2525 &x, &y,
2526 &aChild );
2527 if( x != maGeometry.nX || y != maGeometry.nY )
2529 maGeometry.nX = x;
2530 maGeometry.nY = y;
2531 getDisplay()->SendInternalEvent( this, NULL, SALEVENT_MOVE );
2535 else if( pEvent->type == ClientMessage &&
2536 pEvent->xclient.message_type == getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED ) &&
2537 pEvent->xclient.window == GDK_WINDOW_XWINDOW(m_pWindow->window) &&
2538 m_bWindowIsGtkPlug
2541 // FIXME: this should not be necessary, GtkPlug should do this
2542 // transparently for us
2543 if( pEvent->xclient.data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
2544 pEvent->xclient.data.l[1] == 2 // XEMBED_WINDOW_DEACTIVATE
2547 GdkEventFocus aEvent;
2548 aEvent.type = GDK_FOCUS_CHANGE;
2549 aEvent.window = m_pWindow->window;
2550 aEvent.send_event = TRUE;
2551 aEvent.in = (pEvent->xclient.data.l[1] == 1);
2552 signalFocus( m_pWindow, &aEvent, this );
2556 return bContinueDispatch;
2559 void GtkSalFrame::SetBackgroundBitmap( SalBitmap* pBitmap )
2561 if( m_hBackgroundPixmap )
2563 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
2564 GDK_WINDOW_XWINDOW(m_pWindow->window),
2565 None );
2566 XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap );
2567 m_hBackgroundPixmap = None;
2569 if( pBitmap )
2571 X11SalBitmap* pBM = static_cast<X11SalBitmap*>(pBitmap);
2572 Size aSize = pBM->GetSize();
2573 if( aSize.Width() && aSize.Height() )
2575 m_hBackgroundPixmap =
2576 XCreatePixmap( getDisplay()->GetDisplay(),
2577 GDK_WINDOW_XWINDOW(m_pWindow->window),
2578 aSize.Width(),
2579 aSize.Height(),
2580 getDisplay()->GetVisual(m_nScreen).GetDepth() );
2581 if( m_hBackgroundPixmap )
2583 SalTwoRect aTwoRect;
2584 aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
2585 aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width();
2586 aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height();
2587 pBM->ImplDraw( m_hBackgroundPixmap,
2588 m_nScreen,
2589 getDisplay()->GetVisual(m_nScreen).GetDepth(),
2590 aTwoRect,
2591 getDisplay()->GetCopyGC(m_nScreen) );
2592 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
2593 GDK_WINDOW_XWINDOW(m_pWindow->window),
2594 m_hBackgroundPixmap );
2600 gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame )
2602 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2603 SalMouseEvent aEvent;
2604 USHORT nEventType = 0;
2605 switch( pEvent->type )
2607 case GDK_BUTTON_PRESS:
2608 nEventType = SALEVENT_MOUSEBUTTONDOWN;
2609 break;
2610 case GDK_BUTTON_RELEASE:
2611 nEventType = SALEVENT_MOUSEBUTTONUP;
2612 break;
2613 default:
2614 return FALSE;
2616 switch( pEvent->button )
2618 case 1: aEvent.mnButton = MOUSE_LEFT; break;
2619 case 2: aEvent.mnButton = MOUSE_MIDDLE; break;
2620 case 3: aEvent.mnButton = MOUSE_RIGHT; break;
2621 default: return FALSE;
2623 aEvent.mnTime = pEvent->time;
2624 aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
2625 aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
2626 aEvent.mnCode = GetMouseModCode( pEvent->state );
2628 bool bClosePopups = false;
2629 if( pEvent->type == GDK_BUTTON_PRESS &&
2630 (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) == 0
2633 if( m_nFloats > 0 )
2635 // close popups if user clicks outside our application
2636 gint x, y;
2637 bClosePopups = (gdk_display_get_window_at_pointer( pThis->getGdkDisplay(), &x, &y ) == NULL);
2639 /* #i30306# release implicit pointer grab if no popups are open; else
2640 * Drag cannot grab the pointer and will fail.
2642 if( m_nFloats < 1 || bClosePopups )
2643 gdk_display_pointer_ungrab( pThis->getGdkDisplay(), GDK_CURRENT_TIME );
2646 GTK_YIELD_GRAB();
2648 if( pThis->m_bWindowIsGtkPlug &&
2649 pEvent->type == GDK_BUTTON_PRESS &&
2650 pEvent->button == 1 )
2652 pThis->askForXEmbedFocus( pEvent->time );
2655 // --- RTL --- (mirror mouse pos)
2656 if( Application::GetSettings().GetLayoutRTL() )
2657 aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
2659 vcl::DeletionListener aDel( pThis );
2661 pThis->CallCallback( nEventType, &aEvent );
2663 if( ! aDel.isDeleted() )
2665 if( bClosePopups )
2667 ImplSVData* pSVData = ImplGetSVData();
2668 if ( pSVData->maWinData.mpFirstFloat )
2670 static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
2671 if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) && !(pEnv && *pEnv) )
2672 pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
2676 if( ! aDel.isDeleted() )
2678 int frame_x = (int)(pEvent->x_root - pEvent->x);
2679 int frame_y = (int)(pEvent->y_root - pEvent->y);
2680 if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
2682 pThis->maGeometry.nX = frame_x;
2683 pThis->maGeometry.nY = frame_y;
2684 pThis->CallCallback( SALEVENT_MOVE, NULL );
2689 return FALSE;
2692 gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEvent* pEvent, gpointer frame )
2694 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2695 GdkEventScroll* pSEvent = (GdkEventScroll*)pEvent;
2697 static ULONG nLines = 0;
2698 if( ! nLines )
2700 char* pEnv = getenv( "SAL_WHEELLINES" );
2701 nLines = pEnv ? atoi( pEnv ) : 3;
2702 if( nLines > 10 )
2703 nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
2706 bool bNeg = (pSEvent->direction == GDK_SCROLL_DOWN || pSEvent->direction == GDK_SCROLL_RIGHT );
2707 SalWheelMouseEvent aEvent;
2708 aEvent.mnTime = pSEvent->time;
2709 aEvent.mnX = (ULONG)pSEvent->x;
2710 aEvent.mnY = (ULONG)pSEvent->y;
2711 aEvent.mnDelta = bNeg ? -120 : 120;
2712 aEvent.mnNotchDelta = bNeg ? -1 : 1;
2713 aEvent.mnScrollLines = nLines;
2714 aEvent.mnCode = GetMouseModCode( pSEvent->state );
2715 aEvent.mbHorz = (pSEvent->direction == GDK_SCROLL_LEFT || pSEvent->direction == GDK_SCROLL_RIGHT);
2717 GTK_YIELD_GRAB();
2719 // --- RTL --- (mirror mouse pos)
2720 if( Application::GetSettings().GetLayoutRTL() )
2721 aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
2723 pThis->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
2725 return FALSE;
2728 gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer frame )
2730 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2732 SalMouseEvent aEvent;
2733 aEvent.mnTime = pEvent->time;
2734 aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
2735 aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
2736 aEvent.mnCode = GetMouseModCode( pEvent->state );
2737 aEvent.mnButton = 0;
2740 GTK_YIELD_GRAB();
2742 // --- RTL --- (mirror mouse pos)
2743 if( Application::GetSettings().GetLayoutRTL() )
2744 aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
2746 vcl::DeletionListener aDel( pThis );
2748 pThis->CallCallback( SALEVENT_MOUSEMOVE, &aEvent );
2750 if( ! aDel.isDeleted() )
2752 int frame_x = (int)(pEvent->x_root - pEvent->x);
2753 int frame_y = (int)(pEvent->y_root - pEvent->y);
2754 if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
2756 pThis->maGeometry.nX = frame_x;
2757 pThis->maGeometry.nY = frame_y;
2758 pThis->CallCallback( SALEVENT_MOVE, NULL );
2761 if( ! aDel.isDeleted() )
2763 // ask for the next hint
2764 gint x, y;
2765 GdkModifierType mask;
2766 gdk_window_get_pointer( GTK_WIDGET(pThis->m_pWindow)->window, &x, &y, &mask );
2770 return TRUE;
2773 gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpointer frame )
2775 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2776 SalMouseEvent aEvent;
2777 aEvent.mnTime = pEvent->time;
2778 aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
2779 aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
2780 aEvent.mnCode = GetMouseModCode( pEvent->state );
2781 aEvent.mnButton = 0;
2783 GTK_YIELD_GRAB();
2784 pThis->CallCallback( (pEvent->type == GDK_ENTER_NOTIFY) ? SALEVENT_MOUSEMOVE : SALEVENT_MOUSELEAVE, &aEvent );
2786 return TRUE;
2790 gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer frame )
2792 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2794 struct SalPaintEvent aEvent( pEvent->area.x, pEvent->area.y, pEvent->area.width, pEvent->area.height );
2796 GTK_YIELD_GRAB();
2797 pThis->CallCallback( SALEVENT_PAINT, &aEvent );
2799 return FALSE;
2802 gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame )
2804 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2806 GTK_YIELD_GRAB();
2808 // check if printers have changed (analogous to salframe focus handler)
2809 vcl_sal::PrinterUpdate::update();
2811 if( !pEvent->in )
2813 pThis->m_nKeyModifiers = 0;
2814 pThis->m_bSingleAltPress = false;
2815 pThis->m_bSendModChangeOnRelease = false;
2818 if( pThis->m_pIMHandler )
2819 pThis->m_pIMHandler->focusChanged( pEvent->in );
2821 // ask for changed printers like generic implementation
2822 if( pEvent->in )
2823 if( static_cast< X11SalInstance* >(GetSalData()->m_pInstance)->isPrinterInit() )
2824 vcl_sal::PrinterUpdate::update();
2826 // FIXME: find out who the hell steals the focus from our frame
2827 // while we have the pointer grabbed, this should not come from
2828 // the window manager. Is this an event that was still queued ?
2829 // The focus does not seem to get set inside our process
2831 // in the meantime do not propagate focus get/lose if floats are open
2832 if( m_nFloats == 0 )
2833 pThis->CallCallback( pEvent->in ? SALEVENT_GETFOCUS : SALEVENT_LOSEFOCUS, NULL );
2835 return FALSE;
2838 gboolean GtkSalFrame::signalMap( GtkWidget*, GdkEvent*, gpointer frame )
2840 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2842 GTK_YIELD_GRAB();
2844 if( ImplGetSVData()->mbIsTestTool )
2846 /* #i76541# testtool needs the focus to be in a new document
2847 * however e.g. metacity does not necessarily put the focus into
2848 * a newly shown window. An extra little hint seems to help here.
2849 * however we don't want to interfere with the normal user experience
2850 * so this is done when running in testtool only
2852 if( ! pThis->m_pParent && (pThis->m_nStyle & SAL_FRAME_STYLE_MOVEABLE) != 0 )
2853 XSetInputFocus( pThis->getDisplay()->GetDisplay(),
2854 GDK_WINDOW_XWINDOW( GTK_WIDGET(pThis->m_pWindow)->window),
2855 RevertToParent, CurrentTime );
2858 pThis->CallCallback( SALEVENT_RESIZE, NULL );
2860 return FALSE;
2863 gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame )
2865 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2867 GTK_YIELD_GRAB();
2868 pThis->CallCallback( SALEVENT_RESIZE, NULL );
2870 return FALSE;
2873 gboolean GtkSalFrame::signalConfigure( GtkWidget*, GdkEventConfigure* pEvent, gpointer frame )
2875 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2877 bool bMoved = false, bSized = false;
2878 int x = pEvent->x, y = pEvent->y;
2880 /* HACK: during sizing/moving a toolbar pThis->maGeometry is actually
2881 * already exact; even worse: due to the asynchronicity of configure
2882 * events the borderwindow which would evaluate this event
2883 * would size/move based on wrong data if we would actually evaluate
2884 * this event. So let's swallow it; this is also a performance
2885 * improvement as one can omit the synchronous XTranslateCoordinates
2886 * call below.
2888 if( (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
2889 pThis->getDisplay()->GetCaptureFrame() == pThis )
2890 return FALSE;
2893 // in child case the coordinates are not root coordinates,
2894 // need to transform
2896 /* #i31785# sadly one cannot really trust the x,y members of the event;
2897 * they are e.g. not set correctly on maximize/demaximize; this rather
2898 * sounds like a bug in gtk we have to workaround.
2900 XLIB_Window aChild;
2901 XTranslateCoordinates( pThis->getDisplay()->GetDisplay(),
2902 GDK_WINDOW_XWINDOW(GTK_WIDGET(pThis->m_pWindow)->window),
2903 pThis->getDisplay()->GetRootWindow( pThis->getDisplay()->GetDefaultScreenNumber() ),
2904 0, 0,
2905 &x, &y,
2906 &aChild );
2908 if( x != pThis->maGeometry.nX || y != pThis->maGeometry.nY )
2910 bMoved = true;
2911 pThis->maGeometry.nX = x;
2912 pThis->maGeometry.nY = y;
2914 /* #i86302#
2915 * for non sizeable windows we set the min and max hint for the window manager to
2916 * achieve correct sizing. However this is asynchronous and e.g. on Compiz
2917 * it sometimes happens that the window gets resized to another size (some default)
2918 * if we update the size here, subsequent setMinMaxSize will use this wrong size
2919 * - which is not good since the window manager will now size the window back to this
2920 * wrong size at some point.
2922 if( (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)) == SAL_FRAME_STYLE_SIZEABLE )
2924 if( pEvent->width != (int)pThis->maGeometry.nWidth || pEvent->height != (int)pThis->maGeometry.nHeight )
2926 bSized = true;
2927 pThis->maGeometry.nWidth = pEvent->width;
2928 pThis->maGeometry.nHeight = pEvent->height;
2932 // update decoration hints
2933 if( ! (pThis->m_nStyle & SAL_FRAME_STYLE_PLUG) )
2935 GdkRectangle aRect;
2936 gdk_window_get_frame_extents( GTK_WIDGET(pThis->m_pWindow)->window, &aRect );
2937 pThis->maGeometry.nTopDecoration = y - aRect.y;
2938 pThis->maGeometry.nBottomDecoration = aRect.y + aRect.height - y - pEvent->height;
2939 pThis->maGeometry.nLeftDecoration = x - aRect.x;
2940 pThis->maGeometry.nRightDecoration = aRect.x + aRect.width - x - pEvent->width;
2942 else
2944 pThis->maGeometry.nTopDecoration =
2945 pThis->maGeometry.nBottomDecoration =
2946 pThis->maGeometry.nLeftDecoration =
2947 pThis->maGeometry.nRightDecoration = 0;
2950 GTK_YIELD_GRAB();
2951 pThis->updateScreenNumber();
2952 if( bMoved && bSized )
2953 pThis->CallCallback( SALEVENT_MOVERESIZE, NULL );
2954 else if( bMoved )
2955 pThis->CallCallback( SALEVENT_MOVE, NULL );
2956 else if( bSized )
2957 pThis->CallCallback( SALEVENT_RESIZE, NULL );
2959 return FALSE;
2962 gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame )
2964 GtkSalFrame* pThis = (GtkSalFrame*)frame;
2966 vcl::DeletionListener aDel( pThis );
2968 if( pThis->m_pIMHandler )
2970 if( pThis->m_pIMHandler->handleKeyEvent( pEvent ) )
2972 pThis->m_bSingleAltPress = false;
2973 return TRUE;
2976 GTK_YIELD_GRAB();
2978 // handle modifiers
2979 if( pEvent->keyval == GDK_Shift_L || pEvent->keyval == GDK_Shift_R ||
2980 pEvent->keyval == GDK_Control_L || pEvent->keyval == GDK_Control_R ||
2981 pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ||
2982 pEvent->keyval == GDK_Meta_L || pEvent->keyval == GDK_Meta_R ||
2983 pEvent->keyval == GDK_Super_L || pEvent->keyval == GDK_Super_R )
2985 SalKeyModEvent aModEvt;
2987 USHORT nModCode = GetKeyModCode( pEvent->state );
2989 aModEvt.mnModKeyCode = 0; // emit no MODKEYCHANGE events
2990 if( pEvent->type == GDK_KEY_PRESS && !pThis->m_nKeyModifiers )
2991 pThis->m_bSendModChangeOnRelease = true;
2993 else if( pEvent->type == GDK_KEY_RELEASE &&
2994 pThis->m_bSendModChangeOnRelease )
2996 aModEvt.mnModKeyCode = pThis->m_nKeyModifiers;
2997 pThis->m_nKeyModifiers = 0;
3000 USHORT nExtModMask = 0;
3001 USHORT nModMask = 0;
3002 // pressing just the ctrl key leads to a keysym of XK_Control but
3003 // the event state does not contain ControlMask. In the release
3004 // event its the other way round: it does contain the Control mask.
3005 // The modifier mode therefore has to be adapted manually.
3006 switch( pEvent->keyval )
3008 case GDK_Control_L:
3009 nExtModMask = MODKEY_LMOD1;
3010 nModMask = KEY_MOD1;
3011 break;
3012 case GDK_Control_R:
3013 nExtModMask = MODKEY_RMOD1;
3014 nModMask = KEY_MOD1;
3015 break;
3016 case GDK_Alt_L:
3017 nExtModMask = MODKEY_LMOD2;
3018 nModMask = KEY_MOD2;
3019 break;
3020 case GDK_Alt_R:
3021 nExtModMask = MODKEY_RMOD2;
3022 nModMask = KEY_MOD2;
3023 break;
3024 case GDK_Shift_L:
3025 nExtModMask = MODKEY_LSHIFT;
3026 nModMask = KEY_SHIFT;
3027 break;
3028 case GDK_Shift_R:
3029 nExtModMask = MODKEY_RSHIFT;
3030 nModMask = KEY_SHIFT;
3031 break;
3032 // Map Meta/Super to MOD3 modifier on all Unix systems
3033 // except Mac OS X
3034 case GDK_Meta_L:
3035 case GDK_Super_L:
3036 nExtModMask = MODKEY_LMOD3;
3037 nModMask = KEY_MOD3;
3038 break;
3039 case GDK_Meta_R:
3040 case GDK_Super_R:
3041 nExtModMask = MODKEY_RMOD3;
3042 nModMask = KEY_MOD3;
3043 break;
3045 if( pEvent->type == GDK_KEY_RELEASE )
3047 nModCode &= ~nModMask;
3048 pThis->m_nKeyModifiers &= ~nExtModMask;
3050 else
3052 nModCode |= nModMask;
3053 pThis->m_nKeyModifiers |= nExtModMask;
3056 aModEvt.mnCode = nModCode;
3057 aModEvt.mnTime = pEvent->time;
3059 pThis->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
3061 if( ! aDel.isDeleted() )
3063 // emulate KEY_MENU
3064 if( ( pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ) &&
3065 ( nModCode & ~(KEY_MOD3|KEY_MOD2)) == 0 )
3067 if( pEvent->type == GDK_KEY_PRESS )
3068 pThis->m_bSingleAltPress = true;
3070 else if( pThis->m_bSingleAltPress )
3072 SalKeyEvent aKeyEvt;
3074 aKeyEvt.mnCode = KEY_MENU | nModCode;
3075 aKeyEvt.mnRepeat = 0;
3076 aKeyEvt.mnTime = pEvent->time;
3077 aKeyEvt.mnCharCode = 0;
3079 // simulate KEY_MENU
3080 pThis->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
3081 if( ! aDel.isDeleted() )
3083 pThis->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
3084 pThis->m_bSingleAltPress = false;
3088 else
3089 pThis->m_bSingleAltPress = false;
3092 else
3094 pThis->doKeyCallback( pEvent->state,
3095 pEvent->keyval,
3096 pEvent->hardware_keycode,
3097 pEvent->group,
3098 pEvent->time,
3099 sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )),
3100 (pEvent->type == GDK_KEY_PRESS),
3101 false );
3102 if( ! aDel.isDeleted() )
3104 pThis->m_bSendModChangeOnRelease = false;
3105 pThis->m_bSingleAltPress = false;
3109 if( !aDel.isDeleted() && pThis->m_pIMHandler )
3110 pThis->m_pIMHandler->updateIMSpotLocation();
3112 return TRUE;
3115 gboolean GtkSalFrame::signalDelete( GtkWidget*, GdkEvent*, gpointer frame )
3117 GtkSalFrame* pThis = (GtkSalFrame*)frame;
3119 GTK_YIELD_GRAB();
3120 pThis->CallCallback( SALEVENT_CLOSE, NULL );
3122 return TRUE;
3125 void GtkSalFrame::signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer frame )
3127 GtkSalFrame* pThis = (GtkSalFrame*)frame;
3129 // every frame gets an initial style set on creation
3130 // do not post these as the whole application tends to
3131 // redraw itself to adjust to the new style
3132 // where there IS no new style resulting in tremendous unnecessary flickering
3133 if( pPrevious != NULL )
3134 // signalStyleSet does NOT usually have the gdk lock
3135 // so post user event to safely dispatch the SALEVENT_SETTINGSCHANGED
3136 // note: settings changed for multiple frames is avoided in winproc.cxx ImplHandleSettings
3137 pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_SETTINGSCHANGED );
3139 /* #i64117# gtk sets a nice background pixmap
3140 * but we actually don't really want that, so save
3141 * some time on the Xserver as well as prevent
3142 * some paint issues
3144 GdkWindow* pWin = GTK_WIDGET(pThis->getWindow())->window;
3145 if( pWin )
3147 XLIB_Window aWin = GDK_WINDOW_XWINDOW(pWin);
3148 if( aWin != None )
3149 XSetWindowBackgroundPixmap( pThis->getDisplay()->GetDisplay(),
3150 aWin,
3151 pThis->m_hBackgroundPixmap );
3154 if( ! pThis->m_pParent )
3156 // signalize theme changed for NWF caches
3157 // FIXME: should be called only once for a style change
3158 GtkSalGraphics::bThemeChanged = TRUE;
3162 gboolean GtkSalFrame::signalState( GtkWidget*, GdkEvent* pEvent, gpointer frame )
3164 GtkSalFrame* pThis = (GtkSalFrame*)frame;
3165 if( (pThis->m_nState & GDK_WINDOW_STATE_ICONIFIED) != (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED ) )
3166 pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_RESIZE );
3168 if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) &&
3169 ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) )
3171 pThis->m_aRestorePosSize =
3172 Rectangle( Point( pThis->maGeometry.nX, pThis->maGeometry.nY ),
3173 Size( pThis->maGeometry.nWidth, pThis->maGeometry.nHeight ) );
3175 pThis->m_nState = pEvent->window_state.new_window_state;
3177 return FALSE;
3180 gboolean GtkSalFrame::signalVisibility( GtkWidget*, GdkEventVisibility* pEvent, gpointer frame )
3182 GtkSalFrame* pThis = (GtkSalFrame*)frame;
3183 pThis->m_nVisibility = pEvent->state;
3185 return FALSE;
3188 void GtkSalFrame::signalDestroy( GtkObject* pObj, gpointer frame )
3190 GtkSalFrame* pThis = (GtkSalFrame*)frame;
3191 if( GTK_WIDGET( pObj ) == pThis->m_pWindow )
3193 pThis->m_pFixedContainer = NULL;
3194 pThis->m_pWindow = NULL;
3198 // ----------------------------------------------------------------------
3199 // GtkSalFrame::IMHandler
3200 // ----------------------------------------------------------------------
3202 GtkSalFrame::IMHandler::IMHandler( GtkSalFrame* pFrame )
3203 : m_pFrame(pFrame),
3204 m_nPrevKeyPresses( 0 ),
3205 m_pIMContext( NULL ),
3206 m_bFocused( true )
3208 m_aInputEvent.mpTextAttr = NULL;
3209 createIMContext();
3212 GtkSalFrame::IMHandler::~IMHandler()
3214 // cancel an eventual event posted to begin preedit again
3215 m_pFrame->getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3216 deleteIMContext();
3219 void GtkSalFrame::IMHandler::createIMContext()
3221 if( ! m_pIMContext )
3223 m_pIMContext = gtk_im_multicontext_new ();
3224 g_signal_connect( m_pIMContext, "commit",
3225 G_CALLBACK (signalIMCommit), this );
3226 g_signal_connect( m_pIMContext, "preedit_changed",
3227 G_CALLBACK (signalIMPreeditChanged), this );
3228 g_signal_connect( m_pIMContext, "retrieve_surrounding",
3229 G_CALLBACK (signalIMRetrieveSurrounding), this );
3230 g_signal_connect( m_pIMContext, "delete_surrounding",
3231 G_CALLBACK (signalIMDeleteSurrounding), this );
3232 g_signal_connect( m_pIMContext, "preedit_start",
3233 G_CALLBACK (signalIMPreeditStart), this );
3234 g_signal_connect( m_pIMContext, "preedit_end",
3235 G_CALLBACK (signalIMPreeditEnd), this );
3237 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3238 gtk_im_context_set_client_window( m_pIMContext, GTK_WIDGET(m_pFrame->m_pWindow)->window );
3239 gtk_im_context_focus_in( m_pIMContext );
3240 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3241 m_bFocused = true;
3245 void GtkSalFrame::IMHandler::deleteIMContext()
3247 if( m_pIMContext )
3249 // first give IC a chance to deinitialize
3250 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3251 gtk_im_context_set_client_window( m_pIMContext, NULL );
3252 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3253 // destroy old IC
3254 g_object_unref( m_pIMContext );
3255 m_pIMContext = NULL;
3259 void GtkSalFrame::IMHandler::doCallEndExtTextInput()
3261 m_aInputEvent.mpTextAttr = NULL;
3262 m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
3265 void GtkSalFrame::IMHandler::updateIMSpotLocation()
3267 SalExtTextInputPosEvent aPosEvent;
3268 m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent );
3269 GdkRectangle aArea;
3270 aArea.x = aPosEvent.mnX;
3271 aArea.y = aPosEvent.mnY;
3272 aArea.width = aPosEvent.mnWidth;
3273 aArea.height = aPosEvent.mnHeight;
3274 gtk_im_context_set_cursor_location( m_pIMContext, &aArea );
3277 void GtkSalFrame::IMHandler::setInputContext( SalInputContext* )
3281 void GtkSalFrame::IMHandler::sendEmptyCommit()
3283 vcl::DeletionListener aDel( m_pFrame );
3285 SalExtTextInputEvent aEmptyEv;
3286 aEmptyEv.mnTime = 0;
3287 aEmptyEv.mpTextAttr = 0;
3288 aEmptyEv.maText = String();
3289 aEmptyEv.mnCursorPos = 0;
3290 aEmptyEv.mnCursorFlags = 0;
3291 aEmptyEv.mnDeltaStart = 0;
3292 aEmptyEv.mbOnlyCursor = False;
3293 m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv );
3294 if( ! aDel.isDeleted() )
3295 m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
3298 void GtkSalFrame::IMHandler::endExtTextInput( USHORT /*nFlags*/ )
3300 gtk_im_context_reset ( m_pIMContext );
3302 if( m_aInputEvent.mpTextAttr )
3304 vcl::DeletionListener aDel( m_pFrame );
3305 // delete preedit in sal (commit an empty string)
3306 sendEmptyCommit();
3307 if( ! aDel.isDeleted() )
3309 // mark previous preedit state again (will e.g. be sent at focus gain)
3310 m_aInputEvent.mpTextAttr = &m_aInputFlags[0];
3311 if( m_bFocused )
3313 // begin preedit again
3314 m_pFrame->getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3320 void GtkSalFrame::IMHandler::focusChanged( bool bFocusIn )
3322 m_bFocused = bFocusIn;
3323 if( bFocusIn )
3325 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3326 gtk_im_context_focus_in( m_pIMContext );
3327 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3328 if( m_aInputEvent.mpTextAttr )
3330 sendEmptyCommit();
3331 // begin preedit again
3332 m_pFrame->getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3335 else
3337 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
3338 gtk_im_context_focus_out( m_pIMContext );
3339 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
3340 // cancel an eventual event posted to begin preedit again
3341 m_pFrame->getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
3345 bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent )
3347 vcl::DeletionListener aDel( m_pFrame );
3349 if( pEvent->type == GDK_KEY_PRESS )
3351 // Add this key press event to the list of previous key presses
3352 // to which we compare key release events. If a later key release
3353 // event has a matching key press event in this list, we swallow
3354 // the key release because some GTK Input Methods don't swallow it
3355 // for us.
3356 m_aPrevKeyPresses.push_back( PreviousKeyPress(pEvent) );
3357 m_nPrevKeyPresses++;
3359 // Also pop off the earliest key press event if there are more than 10
3360 // already.
3361 while (m_nPrevKeyPresses > 10)
3363 m_aPrevKeyPresses.pop_front();
3364 m_nPrevKeyPresses--;
3367 GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
3369 // #i51353# update spot location on every key input since we cannot
3370 // know which key may activate a preedit choice window
3371 updateIMSpotLocation();
3372 if( aDel.isDeleted() )
3373 return true;
3375 gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
3376 g_object_unref( pRef );
3378 if( aDel.isDeleted() )
3379 return true;
3381 if( bResult )
3382 return true;
3383 else
3385 DBG_ASSERT( m_nPrevKeyPresses > 0, "key press has vanished !" );
3386 if( ! m_aPrevKeyPresses.empty() ) // sanity check
3388 // event was not swallowed, do not filter a following
3389 // key release event
3390 // note: this relies on gtk_im_context_filter_keypress
3391 // returning without calling a handler (in the "not swallowed"
3392 // case ) which might change the previous key press list so
3393 // we would pop the wrong event here
3394 m_aPrevKeyPresses.pop_back();
3395 m_nPrevKeyPresses--;
3400 // Determine if we got an earlier key press event corresponding to this key release
3401 if (pEvent->type == GDK_KEY_RELEASE)
3403 GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
3404 gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
3405 g_object_unref( pRef );
3407 if( aDel.isDeleted() )
3408 return true;
3410 std::list<PreviousKeyPress>::iterator iter = m_aPrevKeyPresses.begin();
3411 std::list<PreviousKeyPress>::iterator iter_end = m_aPrevKeyPresses.end();
3412 while (iter != iter_end)
3414 // If we found a corresponding previous key press event, swallow the release
3415 // and remove the earlier key press from our list
3416 if (*iter == pEvent)
3418 m_aPrevKeyPresses.erase(iter);
3419 m_nPrevKeyPresses--;
3420 return true;
3422 ++iter;
3425 if( bResult )
3426 return true;
3429 return false;
3432 /* FIXME:
3433 * #122282# still more hacking: some IMEs never start a preedit but simply commit
3434 * in this case we cannot commit a single character. Workaround: do not do the
3435 * single key hack for enter or space if the unicode commited does not match
3438 static bool checkSingleKeyCommitHack( guint keyval, sal_Unicode cCode )
3440 bool bRet = true;
3441 switch( keyval )
3443 case GDK_KP_Enter:
3444 case GDK_Return:
3445 if( cCode != '\n' && cCode != '\r' )
3446 bRet = false;
3447 break;
3448 case GDK_space:
3449 case GDK_KP_Space:
3450 if( cCode != ' ' )
3451 bRet = false;
3452 break;
3453 default:
3454 break;
3456 return bRet;
3459 #ifdef SOLARIS
3460 #define CONTEXT_ARG pContext
3461 #else
3462 #define CONTEXT_ARG EMPTYARG
3463 #endif
3464 void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* CONTEXT_ARG, gchar* pText, gpointer im_handler )
3466 GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
3468 vcl::DeletionListener aDel( pThis->m_pFrame );
3469 // open a block that will end the GTK_YIELD_GRAB before calling preedit changed again
3471 GTK_YIELD_GRAB();
3473 bool bWasPreedit = (pThis->m_aInputEvent.mpTextAttr != 0);
3475 pThis->m_aInputEvent.mnTime = 0;
3476 pThis->m_aInputEvent.mpTextAttr = 0;
3477 pThis->m_aInputEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 );
3478 pThis->m_aInputEvent.mnCursorPos = pThis->m_aInputEvent.maText.Len();
3479 pThis->m_aInputEvent.mnCursorFlags = 0;
3480 pThis->m_aInputEvent.mnDeltaStart = 0;
3481 pThis->m_aInputEvent.mbOnlyCursor = False;
3483 pThis->m_aInputFlags.clear();
3485 /* necessary HACK: all keyboard input comes in here as soon as a IMContext is set
3486 * which is logical and consequent. But since even simple input like
3487 * <space> comes through the commit signal instead of signalKey
3488 * and all kinds of windows only implement KeyInput (e.g. PushButtons,
3489 * RadioButtons and a lot of other Controls), will send a single
3490 * KeyInput/KeyUp sequence instead of an ExtText event if there
3491 * never was a preedit and the text is only one character.
3493 * In this case there the last ExtText event must have been
3494 * SALEVENT_ENDEXTTEXTINPUT, either because of a regular commit
3495 * or because there never was a preedit.
3497 bool bSingleCommit = false;
3498 if( ! bWasPreedit
3499 && pThis->m_aInputEvent.maText.Len() == 1
3500 && ! pThis->m_aPrevKeyPresses.empty()
3503 const PreviousKeyPress& rKP = pThis->m_aPrevKeyPresses.back();
3504 sal_Unicode aOrigCode = pThis->m_aInputEvent.maText.GetChar(0);
3506 if( checkSingleKeyCommitHack( rKP.keyval, aOrigCode ) )
3508 pThis->m_pFrame->doKeyCallback( rKP.state, rKP.keyval, rKP.hardware_keycode, rKP.group, rKP.time, aOrigCode, true, true );
3509 bSingleCommit = true;
3513 if( ! bSingleCommit )
3515 pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
3516 if( ! aDel.isDeleted() )
3517 pThis->doCallEndExtTextInput();
3519 if( ! aDel.isDeleted() )
3521 // reset input event
3522 pThis->m_aInputEvent.maText = String();
3523 pThis->m_aInputEvent.mnCursorPos = 0;
3524 pThis->updateIMSpotLocation();
3527 #ifdef SOLARIS
3528 // #i51356# workaround a solaris IIIMP bug
3529 // in case of partial commits the preedit changed signal
3530 // and commit signal come in wrong order
3531 if( ! aDel.isDeleted() )
3532 signalIMPreeditChanged( pContext, im_handler );
3533 #endif
3536 void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext*, gpointer im_handler )
3538 GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
3540 char* pText = NULL;
3541 PangoAttrList* pAttrs = NULL;
3542 gint nCursorPos = 0;
3544 gtk_im_context_get_preedit_string( pThis->m_pIMContext,
3545 &pText,
3546 &pAttrs,
3547 &nCursorPos );
3548 if( pText && ! *pText ) // empty string
3550 // change from nothing to nothing -> do not start preedit
3551 // e.g. this will activate input into a calc cell without
3552 // user input
3553 if( pThis->m_aInputEvent.maText.Len() == 0 )
3555 g_free( pText );
3556 return;
3560 bool bEndPreedit = (!pText || !*pText) && pThis->m_aInputEvent.mpTextAttr != NULL;
3561 pThis->m_aInputEvent.mnTime = 0;
3562 pThis->m_aInputEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 );
3563 pThis->m_aInputEvent.mnCursorPos = nCursorPos;
3564 pThis->m_aInputEvent.mnCursorFlags = 0;
3565 pThis->m_aInputEvent.mnDeltaStart = 0;
3566 pThis->m_aInputEvent.mbOnlyCursor = False;
3568 pThis->m_aInputFlags = std::vector<USHORT>( std::max( 1, (int)pThis->m_aInputEvent.maText.Len() ), 0 );
3570 PangoAttrIterator *iter = pango_attr_list_get_iterator (pAttrs);
3573 GSList *attr_list = NULL;
3574 GSList *tmp_list = NULL;
3575 gint start, end;
3576 guint sal_attr = 0;
3578 pango_attr_iterator_range (iter, &start, &end);
3579 if (end == G_MAXINT)
3580 end = pText ? strlen (pText) : 0;
3581 if (end == start)
3582 continue;
3584 start = g_utf8_pointer_to_offset (pText, pText + start);
3585 end = g_utf8_pointer_to_offset (pText, pText + end);
3587 tmp_list = attr_list = pango_attr_iterator_get_attrs (iter);
3588 while (tmp_list)
3590 PangoAttribute *pango_attr = (PangoAttribute *)(tmp_list->data);
3592 switch (pango_attr->klass->type)
3594 case PANGO_ATTR_BACKGROUND:
3595 sal_attr |= (SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT | SAL_EXTTEXTINPUT_CURSOR_INVISIBLE);
3596 break;
3597 case PANGO_ATTR_UNDERLINE:
3598 sal_attr |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
3599 break;
3600 case PANGO_ATTR_STRIKETHROUGH:
3601 sal_attr |= SAL_EXTTEXTINPUT_ATTR_REDTEXT;
3602 break;
3603 default:
3604 break;
3606 pango_attribute_destroy (pango_attr);
3607 tmp_list = tmp_list->next;
3609 if (sal_attr == 0)
3610 sal_attr |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
3611 g_slist_free (attr_list);
3613 // Set the sal attributes on our text
3614 for (int i = start; i < end; i++)
3615 pThis->m_aInputFlags[i] |= sal_attr;
3616 } while (pango_attr_iterator_next (iter));
3618 pThis->m_aInputEvent.mpTextAttr = &pThis->m_aInputFlags[0];
3620 g_free( pText );
3621 pango_attr_list_unref( pAttrs );
3623 GTK_YIELD_GRAB();
3625 vcl::DeletionListener aDel( pThis->m_pFrame );
3627 pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
3628 if( bEndPreedit && ! aDel.isDeleted() )
3629 pThis->doCallEndExtTextInput();
3630 if( ! aDel.isDeleted() )
3631 pThis->updateIMSpotLocation();
3634 void GtkSalFrame::IMHandler::signalIMPreeditStart( GtkIMContext*, gpointer /*im_handler*/ )
3638 void GtkSalFrame::IMHandler::signalIMPreeditEnd( GtkIMContext*, gpointer im_handler )
3640 GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
3641 GTK_YIELD_GRAB();
3643 vcl::DeletionListener aDel( pThis->m_pFrame );
3644 pThis->doCallEndExtTextInput();
3645 if( ! aDel.isDeleted() )
3646 pThis->updateIMSpotLocation();
3649 uno::Reference<accessibility::XAccessibleEditableText>
3650 FindFocus(uno::Reference< accessibility::XAccessibleContext > xContext)
3652 if (!xContext.is())
3653 uno::Reference< accessibility::XAccessibleEditableText >();
3655 uno::Reference<accessibility::XAccessibleStateSet> xState = xContext->getAccessibleStateSet();
3656 if (xState.is())
3658 if (xState->contains(accessibility::AccessibleStateType::FOCUSED))
3659 return uno::Reference<accessibility::XAccessibleEditableText>(xContext, uno::UNO_QUERY);
3662 for (sal_Int32 i = 0; i < xContext->getAccessibleChildCount(); ++i)
3664 uno::Reference< accessibility::XAccessible > xChild = xContext->getAccessibleChild(i);
3665 if (!xChild.is())
3666 continue;
3667 uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext();
3668 if (!xChildContext.is())
3669 continue;
3670 uno::Reference< accessibility::XAccessibleEditableText > xText = FindFocus(xChildContext);
3671 if (xText.is())
3672 return xText;
3674 return uno::Reference< accessibility::XAccessibleEditableText >();
3677 uno::Reference<accessibility::XAccessibleEditableText> lcl_GetxText()
3679 uno::Reference<accessibility::XAccessibleEditableText> xText;
3680 Window* pFocusWin = ImplGetSVData()->maWinData.mpFocusWin;
3681 if (!pFocusWin)
3682 return xText;
3684 uno::Reference< accessibility::XAccessible > xAccessible( pFocusWin->GetAccessible( true ) );
3685 if (xAccessible.is())
3686 xText = FindFocus(xAccessible->getAccessibleContext());
3687 return xText;
3690 gboolean GtkSalFrame::IMHandler::signalIMRetrieveSurrounding( GtkIMContext* pContext, gpointer /*im_handler*/ )
3692 uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText();
3694 if (xText.is())
3696 sal_uInt32 nPosition = xText->getCaretPosition();
3697 rtl::OUString sAllText = xText->getText();
3698 if (!sAllText.getLength())
3699 return FALSE;
3700 rtl::OString sUTF = rtl::OUStringToOString(sAllText, RTL_TEXTENCODING_UTF8);
3701 rtl::OUString sCursorText(sAllText, nPosition);
3702 gtk_im_context_set_surrounding(pContext, sUTF.getStr(), sUTF.getLength(),
3703 rtl::OUStringToOString(sCursorText, RTL_TEXTENCODING_UTF8).getLength());
3704 return TRUE;
3707 return FALSE;
3710 gboolean GtkSalFrame::IMHandler::signalIMDeleteSurrounding( GtkIMContext*, gint offset, gint nchars,
3711 gpointer /*im_handler*/ )
3713 uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText();
3715 if (xText.is())
3717 sal_uInt32 nPosition = xText->getCaretPosition();
3718 xText->deleteText(nPosition + offset, nPosition + offset + nchars);
3719 return TRUE;
3722 return FALSE;