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