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