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