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).getStr(), 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 1248 if (aScreenSize.Width() <= 1024 || aScreenSize.Height() <= 768) 1249 { 1250 // For small screen use the old default values. Original comment: 1251 // fill in holy default values brought to us by product management 1252 if( aScreenSize.Width() >= 800 ) 1253 w = 785; 1254 if( aScreenSize.Width() >= 1024 ) 1255 w = 920; 1256 1257 if( aScreenSize.Height() >= 600 ) 1258 h = 550; 1259 if( aScreenSize.Height() >= 768 ) 1260 h = 630; 1261 if( aScreenSize.Height() >= 1024 ) 1262 h = 875; 1263 } 1264 else 1265 { 1266 // Use the same size calculation as on Mac OSX: 80% of width 1267 // and height. 1268 w = static_cast<long>(aScreenSize.Width() * 0.8); 1269 h = static_cast<long>(aScreenSize.Height() * 0.8); 1270 } 1271 1272 return Size( w, h ); 1273 } 1274 1275 void GtkSalFrame::SetDefaultSize() 1276 { 1277 Size aDefSize = calcDefaultSize(); 1278 1279 SetPosSize( 0, 0, aDefSize.Width(), aDefSize.Height(), 1280 SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT ); 1281 1282 if( (m_nStyle & SAL_FRAME_STYLE_DEFAULT) && m_pWindow ) 1283 gtk_window_maximize( GTK_WINDOW(m_pWindow) ); 1284 } 1285 1286 static void initClientId() 1287 { 1288 static bool bOnce = false; 1289 if( ! bOnce ) 1290 { 1291 bOnce = true; 1292 const ByteString& rID = SessionManagerClient::getSessionID(); 1293 if( rID.Len() > 0 ) 1294 gdk_set_sm_client_id(rID.GetBuffer()); 1295 } 1296 } 1297 1298 void GtkSalFrame::Show( sal_Bool bVisible, sal_Bool bNoActivate ) 1299 { 1300 if( m_pWindow ) 1301 { 1302 if( m_pParent && (m_pParent->m_nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN) 1303 && getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() ) 1304 gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), bVisible ); 1305 if( bVisible ) 1306 { 1307 SessionManagerClient::open(); // will simply return after the first time 1308 initClientId(); 1309 getDisplay()->startupNotificationCompleted(); 1310 1311 if( m_bDefaultPos ) 1312 Center(); 1313 if( m_bDefaultSize ) 1314 SetDefaultSize(); 1315 setMinMaxSize(); 1316 1317 // #i45160# switch to desktop where a dialog with parent will appear 1318 if( m_pParent && m_pParent->m_nWorkArea != m_nWorkArea && GTK_WIDGET_MAPPED(m_pParent->m_pWindow) ) 1319 getDisplay()->getWMAdaptor()->switchToWorkArea( m_pParent->m_nWorkArea ); 1320 1321 if( isFloatGrabWindow() && 1322 m_pParent && 1323 m_nFloats == 0 && 1324 ! getDisplay()->GetCaptureFrame() ) 1325 { 1326 /* #i63086# 1327 * outsmart Metacity's "focus:mouse" mode 1328 * which insists on taking the focus from the document 1329 * to the new float. Grab focus to parent frame BEFORE 1330 * showing the float (cannot grab it to the float 1331 * before show). 1332 */ 1333 m_pParent->grabPointer( sal_True, sal_True ); 1334 } 1335 1336 guint32 nUserTime = 0; 1337 if( ! bNoActivate && (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 ) 1338 /* #i99360# ugly workaround an X11 library bug */ 1339 nUserTime= getDisplay()->GetLastUserEventTime( true ); 1340 //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window); 1341 1342 //For these floating windows we don't want the main window to lose focus, and metacity has... 1343 // metacity-2.24.0/src/core/window.c 1344 // 1345 // if ((focus_window != NULL) && XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time)) 1346 // "compare" window focus prevented by other activity 1347 // 1348 // where "compare" is this window 1349 1350 // which leads to... 1351 1352 // /* This happens for error dialogs or alerts; these need to remain on 1353 // * top, but it would be confusing to have its ancestor remain 1354 // * focused. 1355 // */ 1356 // if (meta_window_is_ancestor_of_transient (focus_window, window)) 1357 // "The focus window %s is an ancestor of the newly mapped " 1358 // "window %s which isn't being focused. Unfocusing the " 1359 // "ancestor.\n", 1360 // 1361 // i.e. having a time < that of the toplevel frame means that the toplevel frame gets unfocused. 1362 // awesome. 1363 if( nUserTime == 0 ) 1364 { 1365 /* #i99360# ugly workaround an X11 library bug */ 1366 nUserTime= getDisplay()->GetLastUserEventTime( true ); 1367 //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window); 1368 } 1369 lcl_set_user_time( GTK_WIDGET(m_pWindow)->window, nUserTime ); 1370 1371 if( ! bNoActivate && (m_nStyle & SAL_FRAME_STYLE_TOOLWINDOW) ) 1372 m_bSetFocusOnMap = true; 1373 1374 gtk_widget_show( m_pWindow ); 1375 1376 if( isFloatGrabWindow() ) 1377 { 1378 m_nFloats++; 1379 if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 1 ) 1380 grabPointer( sal_True, sal_True ); 1381 // #i44068# reset parent's IM context 1382 if( m_pParent ) 1383 m_pParent->EndExtTextInput(0); 1384 } 1385 if( m_bWindowIsGtkPlug ) 1386 askForXEmbedFocus( 0 ); 1387 } 1388 else 1389 { 1390 if( isFloatGrabWindow() ) 1391 { 1392 m_nFloats--; 1393 if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 0) 1394 grabPointer( sal_False ); 1395 } 1396 gtk_widget_hide( m_pWindow ); 1397 if( m_pIMHandler ) 1398 m_pIMHandler->focusChanged( false ); 1399 // flush here; there may be a very seldom race between 1400 // the display connection used for clipboard and our connection 1401 Flush(); 1402 } 1403 CallCallback( SALEVENT_RESIZE, NULL ); 1404 } 1405 } 1406 1407 void GtkSalFrame::Enable( sal_Bool /*bEnable*/ ) 1408 { 1409 // Not implemented by X11SalFrame either 1410 } 1411 1412 void GtkSalFrame::setMinMaxSize() 1413 { 1414 /* FIXME: for yet unknown reasons the reported size is a little smaller 1415 * than the max size hint; one would guess that this was due to the border 1416 * sizes of the widgets involved (GtkWindow and GtkFixed), but setting the 1417 * their border to 0 (which is the default anyway) does not change the 1418 * behaviour. Until the reason is known we'll add some pixels here. 1419 */ 1420 #define CONTAINER_ADJUSTMENT 6 1421 1422 /* #i34504# metacity (and possibly others) do not treat 1423 * _NET_WM_STATE_FULLSCREEN and max_width/heigth independently; 1424 * whether they should is undefined. So don't set the max size hint 1425 * for a full screen window. 1426 */ 1427 if( m_pWindow && ! isChild() ) 1428 { 1429 GdkGeometry aGeo; 1430 int aHints = 0; 1431 if( m_nStyle & SAL_FRAME_STYLE_SIZEABLE ) 1432 { 1433 if( m_aMinSize.Width() && m_aMinSize.Height() ) 1434 { 1435 aGeo.min_width = m_aMinSize.Width()+CONTAINER_ADJUSTMENT; 1436 aGeo.min_height = m_aMinSize.Height()+CONTAINER_ADJUSTMENT; 1437 aHints |= GDK_HINT_MIN_SIZE; 1438 } 1439 if( m_aMaxSize.Width() && m_aMaxSize.Height() && ! m_bFullscreen ) 1440 { 1441 aGeo.max_width = m_aMaxSize.Width()+CONTAINER_ADJUSTMENT; 1442 aGeo.max_height = m_aMaxSize.Height()+CONTAINER_ADJUSTMENT; 1443 aHints |= GDK_HINT_MAX_SIZE; 1444 } 1445 } 1446 else 1447 { 1448 aGeo.min_width = maGeometry.nWidth; 1449 aGeo.min_height = maGeometry.nHeight; 1450 aHints |= GDK_HINT_MIN_SIZE; 1451 if( ! m_bFullscreen ) 1452 { 1453 aGeo.max_width = maGeometry.nWidth; 1454 aGeo.max_height = maGeometry.nHeight; 1455 aHints |= GDK_HINT_MAX_SIZE; 1456 } 1457 } 1458 if( m_bFullscreen && m_aMaxSize.Width() && m_aMaxSize.Height() ) 1459 { 1460 aGeo.max_width = m_aMaxSize.Width(); 1461 aGeo.max_height = m_aMaxSize.Height(); 1462 aHints |= GDK_HINT_MAX_SIZE; 1463 } 1464 if( aHints ) 1465 gtk_window_set_geometry_hints( GTK_WINDOW(m_pWindow), 1466 NULL, 1467 &aGeo, 1468 GdkWindowHints( aHints ) ); 1469 } 1470 } 1471 1472 void GtkSalFrame::SetMaxClientSize( long nWidth, long nHeight ) 1473 { 1474 if( ! isChild() ) 1475 { 1476 m_aMaxSize = Size( nWidth, nHeight ); 1477 // Show does a setMinMaxSize 1478 if( GTK_WIDGET_MAPPED( m_pWindow ) ) 1479 setMinMaxSize(); 1480 } 1481 } 1482 void GtkSalFrame::SetMinClientSize( long nWidth, long nHeight ) 1483 { 1484 if( ! isChild() ) 1485 { 1486 m_aMinSize = Size( nWidth, nHeight ); 1487 if( m_pWindow ) 1488 { 1489 gtk_widget_set_size_request( m_pWindow, nWidth, nHeight ); 1490 // Show does a setMinMaxSize 1491 if( GTK_WIDGET_MAPPED( m_pWindow ) ) 1492 setMinMaxSize(); 1493 } 1494 } 1495 } 1496 1497 void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags ) 1498 { 1499 if( !m_pWindow || isChild( true, false ) ) 1500 return; 1501 1502 bool bSized = false, bMoved = false; 1503 1504 if( (nFlags & ( SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT )) && 1505 (nWidth > 0 && nHeight > 0 ) // sometimes stupid things happen 1506 ) 1507 { 1508 m_bDefaultSize = false; 1509 1510 if( (unsigned long)nWidth != maGeometry.nWidth || (unsigned long)nHeight != maGeometry.nHeight ) 1511 bSized = true; 1512 maGeometry.nWidth = nWidth; 1513 maGeometry.nHeight = nHeight; 1514 1515 if( isChild( false, true ) ) 1516 gtk_widget_set_size_request( m_pWindow, nWidth, nHeight ); 1517 else if( ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) ) 1518 gtk_window_resize( GTK_WINDOW(m_pWindow), nWidth, nHeight ); 1519 setMinMaxSize(); 1520 } 1521 else if( m_bDefaultSize ) 1522 SetDefaultSize(); 1523 1524 m_bDefaultSize = false; 1525 1526 if( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) ) 1527 { 1528 if( m_pParent ) 1529 { 1530 if( Application::GetSettings().GetLayoutRTL() ) 1531 nX = m_pParent->maGeometry.nWidth-maGeometry.nWidth-1-nX; 1532 nX += m_pParent->maGeometry.nX; 1533 nY += m_pParent->maGeometry.nY; 1534 } 1535 1536 // adjust position to avoid off screen windows 1537 // but allow toolbars to be positioned partly off screen by the user 1538 Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen ); 1539 if( ! (m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) 1540 { 1541 if( nX < (long)maGeometry.nLeftDecoration ) 1542 nX = maGeometry.nLeftDecoration; 1543 if( nY < (long)maGeometry.nTopDecoration ) 1544 nY = maGeometry.nTopDecoration; 1545 if( (nX + (long)maGeometry.nWidth + (long)maGeometry.nRightDecoration) > (long)aScreenSize.Width() ) 1546 nX = aScreenSize.Width() - maGeometry.nWidth - maGeometry.nRightDecoration; 1547 if( (nY + (long)maGeometry.nHeight + (long)maGeometry.nBottomDecoration) > (long)aScreenSize.Height() ) 1548 nY = aScreenSize.Height() - maGeometry.nHeight - maGeometry.nBottomDecoration; 1549 } 1550 else 1551 { 1552 if( nX + (long)maGeometry.nWidth < 10 ) 1553 nX = 10 - (long)maGeometry.nWidth; 1554 if( nY + (long)maGeometry.nHeight < 10 ) 1555 nY = 10 - (long)maGeometry.nHeight; 1556 if( nX > (long)aScreenSize.Width() - 10 ) 1557 nX = (long)aScreenSize.Width() - 10; 1558 if( nY > (long)aScreenSize.Height() - 10 ) 1559 nY = (long)aScreenSize.Height() - 10; 1560 } 1561 1562 if( nX != maGeometry.nX || nY != maGeometry.nY ) 1563 bMoved = true; 1564 maGeometry.nX = nX; 1565 maGeometry.nY = nY; 1566 1567 m_bDefaultPos = false; 1568 1569 moveWindow( maGeometry.nX, maGeometry.nY ); 1570 1571 updateScreenNumber(); 1572 } 1573 else if( m_bDefaultPos ) 1574 Center(); 1575 1576 m_bDefaultPos = false; 1577 1578 if( bSized && ! bMoved ) 1579 CallCallback( SALEVENT_RESIZE, NULL ); 1580 else if( bMoved && ! bSized ) 1581 CallCallback( SALEVENT_MOVE, NULL ); 1582 else if( bMoved && bSized ) 1583 CallCallback( SALEVENT_MOVERESIZE, NULL ); 1584 } 1585 1586 void GtkSalFrame::GetClientSize( long& rWidth, long& rHeight ) 1587 { 1588 if( m_pWindow && !(m_nState & GDK_WINDOW_STATE_ICONIFIED) ) 1589 { 1590 rWidth = maGeometry.nWidth; 1591 rHeight = maGeometry.nHeight; 1592 } 1593 else 1594 rWidth = rHeight = 0; 1595 } 1596 1597 void GtkSalFrame::GetWorkArea( Rectangle& rRect ) 1598 { 1599 rRect = GetX11SalData()->GetDisplay()->getWMAdaptor()->getWorkArea( 0 ); 1600 } 1601 1602 SalFrame* GtkSalFrame::GetParent() const 1603 { 1604 return m_pParent; 1605 } 1606 1607 void GtkSalFrame::SetWindowState( const SalFrameState* pState ) 1608 { 1609 if( ! m_pWindow || ! pState || isChild( true, false ) ) 1610 return; 1611 1612 const sal_uLong nMaxGeometryMask = 1613 SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y | 1614 SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT | 1615 SAL_FRAMESTATE_MASK_MAXIMIZED_X | SAL_FRAMESTATE_MASK_MAXIMIZED_Y | 1616 SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT; 1617 1618 if( (pState->mnMask & SAL_FRAMESTATE_MASK_STATE) && 1619 ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) && 1620 (pState->mnState & SAL_FRAMESTATE_MAXIMIZED) && 1621 (pState->mnMask & nMaxGeometryMask) == nMaxGeometryMask ) 1622 { 1623 resizeWindow( pState->mnWidth, pState->mnHeight ); 1624 moveWindow( pState->mnX, pState->mnY ); 1625 m_bDefaultPos = m_bDefaultSize = false; 1626 1627 maGeometry.nX = pState->mnMaximizedX; 1628 maGeometry.nY = pState->mnMaximizedY; 1629 maGeometry.nWidth = pState->mnMaximizedWidth; 1630 maGeometry.nHeight = pState->mnMaximizedHeight; 1631 updateScreenNumber(); 1632 1633 m_nState = GdkWindowState( m_nState | GDK_WINDOW_STATE_MAXIMIZED ); 1634 m_aRestorePosSize = Rectangle( Point( pState->mnX, pState->mnY ), 1635 Size( pState->mnWidth, pState->mnHeight ) ); 1636 } 1637 else if( pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y | 1638 SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT ) ) 1639 { 1640 sal_uInt16 nPosSizeFlags = 0; 1641 long nX = pState->mnX - (m_pParent ? m_pParent->maGeometry.nX : 0); 1642 long nY = pState->mnY - (m_pParent ? m_pParent->maGeometry.nY : 0); 1643 long nWidth = pState->mnWidth; 1644 long nHeight = pState->mnHeight; 1645 if( pState->mnMask & SAL_FRAMESTATE_MASK_X ) 1646 nPosSizeFlags |= SAL_FRAME_POSSIZE_X; 1647 else 1648 nX = maGeometry.nX - (m_pParent ? m_pParent->maGeometry.nX : 0); 1649 if( pState->mnMask & SAL_FRAMESTATE_MASK_Y ) 1650 nPosSizeFlags |= SAL_FRAME_POSSIZE_Y; 1651 else 1652 nY = maGeometry.nY - (m_pParent ? m_pParent->maGeometry.nY : 0); 1653 if( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH ) 1654 nPosSizeFlags |= SAL_FRAME_POSSIZE_WIDTH; 1655 else 1656 nWidth = maGeometry.nWidth; 1657 if( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT ) 1658 nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT; 1659 else 1660 nHeight = maGeometry.nHeight; 1661 SetPosSize( nX, nY, pState->mnWidth, pState->mnHeight, nPosSizeFlags ); 1662 } 1663 if( pState->mnMask & SAL_FRAMESTATE_MASK_STATE && ! isChild() ) 1664 { 1665 if( pState->mnState & SAL_FRAMESTATE_MAXIMIZED ) 1666 gtk_window_maximize( GTK_WINDOW(m_pWindow) ); 1667 else 1668 gtk_window_unmaximize( GTK_WINDOW(m_pWindow) ); 1669 /* #i42379# there is no rollup state in GDK; and rolled up windows are 1670 * (probably depending on the WM) reported as iconified. If we iconify a 1671 * window here that was e.g. a dialog, then it will be unmapped but still 1672 * not be displayed in the task list, so it's an iconified window that 1673 * the user cannot get out of this state. So do not set the iconified state 1674 * on windows with a parent (that is transient frames) since these tend 1675 * to not be represented in an icon task list. 1676 */ 1677 if( (pState->mnState & SAL_FRAMESTATE_MINIMIZED) 1678 && ! m_pParent ) 1679 gtk_window_iconify( GTK_WINDOW(m_pWindow) ); 1680 else 1681 gtk_window_deiconify( GTK_WINDOW(m_pWindow) ); 1682 } 1683 } 1684 1685 sal_Bool GtkSalFrame::GetWindowState( SalFrameState* pState ) 1686 { 1687 pState->mnState = SAL_FRAMESTATE_NORMAL; 1688 pState->mnMask = SAL_FRAMESTATE_MASK_STATE; 1689 // rollup ? gtk 2.2 does not seem to support the shaded state 1690 if( (m_nState & GDK_WINDOW_STATE_ICONIFIED) ) 1691 pState->mnState |= SAL_FRAMESTATE_MINIMIZED; 1692 if( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) 1693 { 1694 pState->mnState |= SAL_FRAMESTATE_MAXIMIZED; 1695 pState->mnX = m_aRestorePosSize.Left(); 1696 pState->mnY = m_aRestorePosSize.Top(); 1697 pState->mnWidth = m_aRestorePosSize.GetWidth(); 1698 pState->mnHeight = m_aRestorePosSize.GetHeight(); 1699 pState->mnMaximizedX = maGeometry.nX; 1700 pState->mnMaximizedY = maGeometry.nY; 1701 pState->mnMaximizedWidth = maGeometry.nWidth; 1702 pState->mnMaximizedHeight = maGeometry.nHeight; 1703 pState->mnMask |= SAL_FRAMESTATE_MASK_MAXIMIZED_X | 1704 SAL_FRAMESTATE_MASK_MAXIMIZED_Y | 1705 SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | 1706 SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT; 1707 } 1708 else 1709 { 1710 1711 pState->mnX = maGeometry.nX; 1712 pState->mnY = maGeometry.nY; 1713 pState->mnWidth = maGeometry.nWidth; 1714 pState->mnHeight = maGeometry.nHeight; 1715 } 1716 pState->mnMask |= SAL_FRAMESTATE_MASK_X | 1717 SAL_FRAMESTATE_MASK_Y | 1718 SAL_FRAMESTATE_MASK_WIDTH | 1719 SAL_FRAMESTATE_MASK_HEIGHT; 1720 1721 return sal_True; 1722 } 1723 1724 void GtkSalFrame::moveToScreen( int nScreen ) 1725 { 1726 if( isChild() ) 1727 return; 1728 1729 if( nScreen < 0 || nScreen >= gdk_display_get_n_screens( getGdkDisplay() ) ) 1730 nScreen = m_nScreen; 1731 if( nScreen == m_nScreen ) 1732 return; 1733 1734 GdkScreen* pScreen = gdk_display_get_screen( getGdkDisplay(), nScreen ); 1735 if( pScreen ) 1736 { 1737 m_nScreen = nScreen; 1738 gtk_window_set_screen( GTK_WINDOW(m_pWindow), pScreen ); 1739 // realize the window, we need an XWindow id 1740 gtk_widget_realize( m_pWindow ); 1741 // update system data 1742 GtkSalDisplay* pDisp = getDisplay(); 1743 m_aSystemData.aWindow = GDK_WINDOW_XWINDOW(m_pWindow->window); 1744 m_aSystemData.pVisual = pDisp->GetVisual( m_nScreen ).GetVisual(); 1745 m_aSystemData.nScreen = nScreen; 1746 m_aSystemData.nDepth = pDisp->GetVisual( m_nScreen ).GetDepth(); 1747 m_aSystemData.aColormap = pDisp->GetColormap( m_nScreen ).GetXColormap(); 1748 m_aSystemData.pAppContext = NULL; 1749 m_aSystemData.aShellWindow = m_aSystemData.aWindow; 1750 // update graphics if necessary 1751 for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ ) 1752 { 1753 if( m_aGraphics[i].bInUse ) 1754 m_aGraphics[i].pGraphics->SetDrawable( GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen ); 1755 } 1756 updateScreenNumber(); 1757 } 1758 1759 if( m_pParent && m_pParent->m_nScreen != m_nScreen ) 1760 SetParent( NULL ); 1761 std::list< GtkSalFrame* > aChildren = m_aChildren; 1762 for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it ) 1763 (*it)->moveToScreen( m_nScreen ); 1764 1765 // FIXME: SalObjects 1766 } 1767 1768 void GtkSalFrame::SetScreenNumber( unsigned int nNewScreen ) 1769 { 1770 if( nNewScreen == maGeometry.nScreenNumber ) 1771 return; 1772 1773 if( m_pWindow && ! isChild() ) 1774 { 1775 GtkSalDisplay* pDisp = getDisplay(); 1776 if( pDisp->IsXinerama() && pDisp->GetXineramaScreens().size() > 1 ) 1777 { 1778 if( nNewScreen >= pDisp->GetXineramaScreens().size() ) 1779 return; 1780 1781 Rectangle aOldScreenRect( pDisp->GetXineramaScreens()[maGeometry.nScreenNumber] ); 1782 Rectangle aNewScreenRect( pDisp->GetXineramaScreens()[nNewScreen] ); 1783 bool bVisible = GTK_WIDGET_MAPPED(m_pWindow); 1784 if( bVisible ) 1785 Show( sal_False ); 1786 maGeometry.nX = aNewScreenRect.Left() + (maGeometry.nX - aOldScreenRect.Left()); 1787 maGeometry.nY = aNewScreenRect.Top() + (maGeometry.nY - aOldScreenRect.Top()); 1788 createNewWindow( None, false, m_nScreen ); 1789 gtk_window_move( GTK_WINDOW(m_pWindow), maGeometry.nX, maGeometry.nY ); 1790 if( bVisible ) 1791 Show( sal_True ); 1792 maGeometry.nScreenNumber = nNewScreen; 1793 } 1794 else if( sal_Int32(nNewScreen) < pDisp->GetScreenCount() ) 1795 { 1796 moveToScreen( (int)nNewScreen ); 1797 maGeometry.nScreenNumber = nNewScreen; 1798 gtk_window_move( GTK_WINDOW(m_pWindow), maGeometry.nX, maGeometry.nY ); 1799 } 1800 } 1801 } 1802 1803 void GtkSalFrame::ShowFullScreen( sal_Bool bFullScreen, sal_Int32 nScreen ) 1804 { 1805 if( m_pWindow && ! isChild() ) 1806 { 1807 GtkSalDisplay* pDisp = getDisplay(); 1808 // xinerama ? 1809 if( pDisp->IsXinerama() && pDisp->GetXineramaScreens().size() > 1 ) 1810 { 1811 if( bFullScreen ) 1812 { 1813 m_aRestorePosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ), 1814 Size( maGeometry.nWidth, maGeometry.nHeight ) ); 1815 bool bVisible = GTK_WIDGET_MAPPED(m_pWindow); 1816 if( bVisible ) 1817 Show( sal_False ); 1818 m_nStyle |= SAL_FRAME_STYLE_PARTIAL_FULLSCREEN; 1819 createNewWindow( None, false, m_nScreen ); 1820 Rectangle aNewPosSize; 1821 if( nScreen < 0 || nScreen >= static_cast<int>(pDisp->GetXineramaScreens().size()) ) 1822 aNewPosSize = Rectangle( Point( 0, 0 ), pDisp->GetScreenSize(m_nScreen) ); 1823 else 1824 aNewPosSize = pDisp->GetXineramaScreens()[ nScreen ]; 1825 1826 gtk_window_resize( GTK_WINDOW(m_pWindow), 1827 maGeometry.nWidth = aNewPosSize.GetWidth(), 1828 maGeometry.nHeight = aNewPosSize.GetHeight() ); 1829 gtk_window_move( GTK_WINDOW(m_pWindow), 1830 maGeometry.nX = aNewPosSize.Left(), 1831 maGeometry.nY = aNewPosSize.Top() ); 1832 // #i110881# for the benefit of compiz set a max size here 1833 // else setting to fullscreen fails for unknown reasons 1834 m_aMaxSize.Width() = aNewPosSize.GetWidth()+100; 1835 m_aMaxSize.Height() = aNewPosSize.GetHeight()+100; 1836 // workaround different legacy version window managers have different opinions about 1837 // _NET_WM_STATE_FULLSCREEN (Metacity <-> KWin) 1838 if( ! getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() ) 1839 { 1840 pDisp->getWMAdaptor()->setFullScreenMonitors( GDK_WINDOW_XWINDOW( GTK_WIDGET(m_pWindow)->window ), nScreen ); 1841 if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) ) 1842 gtk_window_set_resizable( GTK_WINDOW(m_pWindow), sal_True ); 1843 gtk_window_fullscreen( GTK_WINDOW( m_pWindow ) ); 1844 } 1845 if( bVisible ) 1846 Show( sal_True ); 1847 } 1848 else 1849 { 1850 bool bVisible = GTK_WIDGET_MAPPED(m_pWindow); 1851 if( ! getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() ) 1852 gtk_window_unfullscreen( GTK_WINDOW(m_pWindow) ); 1853 if( bVisible ) 1854 Show( sal_False ); 1855 m_nStyle &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN; 1856 createNewWindow( None, false, m_nScreen ); 1857 if( ! m_aRestorePosSize.IsEmpty() ) 1858 { 1859 gtk_window_resize( GTK_WINDOW(m_pWindow), 1860 maGeometry.nWidth = m_aRestorePosSize.GetWidth(), 1861 maGeometry.nHeight = m_aRestorePosSize.GetHeight() ); 1862 gtk_window_move( GTK_WINDOW(m_pWindow), 1863 maGeometry.nX = m_aRestorePosSize.Left(), 1864 maGeometry.nY = m_aRestorePosSize.Top() ); 1865 m_aRestorePosSize = Rectangle(); 1866 } 1867 if( bVisible ) 1868 Show( sal_True ); 1869 } 1870 } 1871 else 1872 { 1873 if( bFullScreen ) 1874 { 1875 if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) ) 1876 gtk_window_set_resizable( GTK_WINDOW(m_pWindow), TRUE ); 1877 gtk_window_fullscreen( GTK_WINDOW(m_pWindow) ); 1878 moveToScreen( nScreen ); 1879 Size aScreenSize = pDisp->GetScreenSize( m_nScreen ); 1880 maGeometry.nX = 0; 1881 maGeometry.nY = 0; 1882 maGeometry.nWidth = aScreenSize.Width(); 1883 maGeometry.nHeight = aScreenSize.Height(); 1884 } 1885 else 1886 { 1887 gtk_window_unfullscreen( GTK_WINDOW(m_pWindow) ); 1888 if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) ) 1889 gtk_window_set_resizable( GTK_WINDOW(m_pWindow), FALSE ); 1890 moveToScreen( nScreen ); 1891 } 1892 } 1893 m_bDefaultPos = m_bDefaultSize = false; 1894 updateScreenNumber(); 1895 CallCallback( SALEVENT_MOVERESIZE, NULL ); 1896 } 1897 m_bFullscreen = bFullScreen; 1898 } 1899 1900 /* definitions from xautolock.c (pl15) */ 1901 #define XAUTOLOCK_DISABLE 1 1902 #define XAUTOLOCK_ENABLE 2 1903 1904 void GtkSalFrame::setAutoLock( bool bLock ) 1905 { 1906 if( isChild() ) 1907 return; 1908 1909 GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(m_pWindow) ); 1910 GdkDisplay *pDisplay = gdk_screen_get_display( pScreen ); 1911 GdkWindow *pRootWin = gdk_screen_get_root_window( pScreen ); 1912 1913 Atom nAtom = XInternAtom( GDK_DISPLAY_XDISPLAY( pDisplay ), 1914 "XAUTOLOCK_MESSAGE", False ); 1915 1916 int nMessage = bLock ? XAUTOLOCK_ENABLE : XAUTOLOCK_DISABLE; 1917 1918 XChangeProperty( GDK_DISPLAY_XDISPLAY( pDisplay ), 1919 GDK_WINDOW_XID( pRootWin ), 1920 nAtom, XA_INTEGER, 1921 8, PropModeReplace, 1922 (unsigned char*)&nMessage, 1923 sizeof( nMessage ) ); 1924 } 1925 1926 #ifdef ENABLE_DBUS 1927 /** cookie is returned as an unsigned integer */ 1928 static guint 1929 dbus_inhibit_gsm (const gchar *appname, 1930 const gchar *reason, 1931 guint xid) 1932 { 1933 gboolean res; 1934 guint cookie; 1935 GError *error = NULL; 1936 DBusGProxy *proxy = NULL; 1937 DBusGConnection *session_connection = NULL; 1938 1939 /* get the DBUS session connection */ 1940 session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); 1941 if (error != NULL) { 1942 g_warning ("DBUS cannot connect : %s", error->message); 1943 g_error_free (error); 1944 return -1; 1945 } 1946 1947 /* get the proxy with gnome-session-manager */ 1948 proxy = dbus_g_proxy_new_for_name (session_connection, 1949 GSM_DBUS_SERVICE, 1950 GSM_DBUS_PATH, 1951 GSM_DBUS_INTERFACE); 1952 if (proxy == NULL) { 1953 g_warning ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE); 1954 return -1; 1955 } 1956 1957 res = dbus_g_proxy_call (proxy, 1958 "Inhibit", &error, 1959 G_TYPE_STRING, appname, 1960 G_TYPE_UINT, xid, 1961 G_TYPE_STRING, reason, 1962 G_TYPE_UINT, 8, //Inhibit the session being marked as idle 1963 G_TYPE_INVALID, 1964 G_TYPE_UINT, &cookie, 1965 G_TYPE_INVALID); 1966 1967 /* check the return value */ 1968 if (! res) { 1969 cookie = -1; 1970 g_warning ("Inhibit method failed"); 1971 } 1972 1973 /* check the error value */ 1974 if (error != NULL) { 1975 g_warning ("Inhibit problem : %s", error->message); 1976 g_error_free (error); 1977 cookie = -1; 1978 } 1979 1980 g_object_unref (G_OBJECT (proxy)); 1981 return cookie; 1982 } 1983 1984 static void 1985 dbus_uninhibit_gsm (guint cookie) 1986 { 1987 gboolean res; 1988 GError *error = NULL; 1989 DBusGProxy *proxy = NULL; 1990 DBusGConnection *session_connection = NULL; 1991 1992 if (cookie == guint(-1)) { 1993 g_warning ("Invalid cookie"); 1994 return; 1995 } 1996 1997 /* get the DBUS session connection */ 1998 session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); 1999 if (error) { 2000 g_warning ("DBUS cannot connect : %s", error->message); 2001 g_error_free (error); 2002 return; 2003 } 2004 2005 /* get the proxy with gnome-session-manager */ 2006 proxy = dbus_g_proxy_new_for_name (session_connection, 2007 GSM_DBUS_SERVICE, 2008 GSM_DBUS_PATH, 2009 GSM_DBUS_INTERFACE); 2010 if (proxy == NULL) { 2011 g_warning ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE); 2012 return; 2013 } 2014 2015 res = dbus_g_proxy_call (proxy, 2016 "Uninhibit", 2017 &error, 2018 G_TYPE_UINT, cookie, 2019 G_TYPE_INVALID, 2020 G_TYPE_INVALID); 2021 2022 /* check the return value */ 2023 if (! res) { 2024 g_warning ("Uninhibit method failed"); 2025 } 2026 2027 /* check the error value */ 2028 if (error != NULL) { 2029 g_warning ("Uninhibit problem : %s", error->message); 2030 g_error_free (error); 2031 cookie = -1; 2032 } 2033 g_object_unref (G_OBJECT (proxy)); 2034 } 2035 #endif 2036 2037 void GtkSalFrame::StartPresentation( sal_Bool bStart ) 2038 { 2039 Display *pDisplay = GDK_DISPLAY_XDISPLAY( getGdkDisplay() ); 2040 2041 setAutoLock( !bStart ); 2042 2043 int nTimeout, nInterval, bPreferBlanking, bAllowExposures; 2044 2045 XGetScreenSaver( pDisplay, &nTimeout, &nInterval, 2046 &bPreferBlanking, &bAllowExposures ); 2047 if( bStart ) 2048 { 2049 if ( nTimeout ) 2050 { 2051 m_nSavedScreenSaverTimeout = nTimeout; 2052 XResetScreenSaver( pDisplay ); 2053 XSetScreenSaver( pDisplay, 0, nInterval, 2054 bPreferBlanking, bAllowExposures ); 2055 } 2056 #ifdef ENABLE_DBUS 2057 m_nGSMCookie = dbus_inhibit_gsm(g_get_application_name(), "presentation", 2058 GDK_WINDOW_XID(m_pWindow->window)); 2059 #endif 2060 } 2061 else 2062 { 2063 if( m_nSavedScreenSaverTimeout ) 2064 XSetScreenSaver( pDisplay, m_nSavedScreenSaverTimeout, 2065 nInterval, bPreferBlanking, 2066 bAllowExposures ); 2067 m_nSavedScreenSaverTimeout = 0; 2068 #ifdef ENABLE_DBUS 2069 dbus_uninhibit_gsm(m_nGSMCookie); 2070 #endif 2071 } 2072 } 2073 2074 void GtkSalFrame::SetAlwaysOnTop( sal_Bool /*bOnTop*/ ) 2075 { 2076 } 2077 2078 void GtkSalFrame::ToTop( sal_uInt16 nFlags ) 2079 { 2080 if( m_pWindow ) 2081 { 2082 if( isChild( false, true ) ) 2083 gtk_widget_grab_focus( m_pWindow ); 2084 else if( GTK_WIDGET_MAPPED( m_pWindow ) ) 2085 { 2086 if( ! (nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY) ) 2087 gtk_window_present( GTK_WINDOW(m_pWindow) ); 2088 else 2089 { 2090 // gdk_window_focus( m_pWindow->window, gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window) ); 2091 /* #i99360# ugly workaround an X11 library bug */ 2092 guint32 nUserTime= getDisplay()->GetLastUserEventTime( true ); 2093 gdk_window_focus( m_pWindow->window, nUserTime ); 2094 } 2095 /* need to do an XSetInputFocus here because 2096 * gdk_window_focus will ask a EWMH compliant WM to put the focus 2097 * to our window - which it of course won't since our input hint 2098 * is set to false. 2099 */ 2100 if( (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE)) ) 2101 { 2102 // sad but true: this can cause an XError, we need to catch that 2103 // to do this we need to synchronize with the XServer 2104 getDisplay()->GetXLib()->PushXErrorLevel( true ); 2105 XSetInputFocus( getDisplay()->GetDisplay(), GDK_WINDOW_XWINDOW( m_pWindow->window ), RevertToParent, CurrentTime ); 2106 XSync( getDisplay()->GetDisplay(), False ); 2107 getDisplay()->GetXLib()->PopXErrorLevel(); 2108 } 2109 } 2110 else 2111 { 2112 if( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN ) 2113 gtk_window_present( GTK_WINDOW(m_pWindow) ); 2114 } 2115 } 2116 } 2117 2118 void GtkSalFrame::SetPointer( PointerStyle ePointerStyle ) 2119 { 2120 if( m_pWindow && ePointerStyle != m_ePointerStyle ) 2121 { 2122 m_ePointerStyle = ePointerStyle; 2123 GdkCursor *pCursor = getDisplay()->getCursor( ePointerStyle ); 2124 gdk_window_set_cursor( m_pWindow->window, pCursor ); 2125 m_pCurrentCursor = pCursor; 2126 2127 // #i80791# use grabPointer the same way as CaptureMouse, respective float grab 2128 if( getDisplay()->MouseCaptured( this ) ) 2129 grabPointer( sal_True, sal_False ); 2130 else if( m_nFloats > 0 ) 2131 grabPointer( sal_True, sal_True ); 2132 } 2133 } 2134 2135 void GtkSalFrame::grabPointer( sal_Bool bGrab, sal_Bool bOwnerEvents ) 2136 { 2137 if( m_pWindow ) 2138 { 2139 if( bGrab ) 2140 { 2141 bool bUseGdkGrab = true; 2142 if( getDisplay()->getHaveSystemChildFrame() ) 2143 { 2144 const std::list< SalFrame* >& rFrames = getDisplay()->getFrames(); 2145 for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) 2146 { 2147 const GtkSalFrame* pFrame = static_cast< const GtkSalFrame* >(*it); 2148 if( pFrame->m_bWindowIsGtkPlug ) 2149 { 2150 bUseGdkGrab = false; 2151 break; 2152 } 2153 } 2154 } 2155 if( bUseGdkGrab ) 2156 { 2157 const int nMask = ( GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK ); 2158 2159 gdk_pointer_grab( m_pWindow->window, bOwnerEvents, 2160 (GdkEventMask) nMask, NULL, m_pCurrentCursor, 2161 GDK_CURRENT_TIME ); 2162 } 2163 else 2164 { 2165 // FIXME: for some unknown reason gdk_pointer_grab does not 2166 // really produce owner events for GtkPlug windows 2167 // the cause is yet unknown 2168 // 2169 // this is of course a bad hack, especially as we cannot 2170 // set the right cursor this way 2171 XGrabPointer( getDisplay()->GetDisplay(), 2172 GDK_WINDOW_XWINDOW( m_pWindow->window), 2173 bOwnerEvents, 2174 PointerMotionMask | ButtonPressMask | ButtonReleaseMask, 2175 GrabModeAsync, 2176 GrabModeAsync, 2177 None, 2178 None, 2179 CurrentTime 2180 ); 2181 2182 } 2183 } 2184 else 2185 { 2186 // Two GdkDisplays may be open 2187 gdk_display_pointer_ungrab( getGdkDisplay(), GDK_CURRENT_TIME); 2188 } 2189 } 2190 } 2191 2192 void GtkSalFrame::CaptureMouse( sal_Bool bCapture ) 2193 { 2194 getDisplay()->CaptureMouse( bCapture ? this : NULL ); 2195 } 2196 2197 void GtkSalFrame::SetPointerPos( long nX, long nY ) 2198 { 2199 GtkSalFrame* pFrame = this; 2200 while( pFrame && pFrame->isChild( false, true ) ) 2201 pFrame = pFrame->m_pParent; 2202 if( ! pFrame ) 2203 return; 2204 2205 GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(pFrame->m_pWindow) ); 2206 GdkDisplay *pDisplay = gdk_screen_get_display( pScreen ); 2207 2208 /* #87921# when the application tries to center the mouse in the dialog the 2209 * window isn't mapped already. So use coordinates relative to the root window. 2210 */ 2211 unsigned int nWindowLeft = maGeometry.nX + nX; 2212 unsigned int nWindowTop = maGeometry.nY + nY; 2213 2214 XWarpPointer( GDK_DISPLAY_XDISPLAY (pDisplay), None, 2215 GDK_WINDOW_XID (gdk_screen_get_root_window( pScreen ) ), 2216 0, 0, 0, 0, nWindowLeft, nWindowTop); 2217 // #i38648# ask for the next motion hint 2218 gint x, y; 2219 GdkModifierType mask; 2220 gdk_window_get_pointer( pFrame->m_pWindow->window, &x, &y, &mask ); 2221 } 2222 2223 void GtkSalFrame::Flush() 2224 { 2225 #ifdef HAVE_A_RECENT_GTK 2226 gdk_display_flush( getGdkDisplay() ); 2227 #else 2228 XFlush (GDK_DISPLAY_XDISPLAY (getGdkDisplay())); 2229 #endif 2230 } 2231 2232 void GtkSalFrame::Sync() 2233 { 2234 gdk_display_sync( getGdkDisplay() ); 2235 } 2236 2237 String GtkSalFrame::GetSymbolKeyName( const String&, sal_uInt16 nKeyCode ) 2238 { 2239 return getDisplay()->GetKeyName( nKeyCode ); 2240 } 2241 2242 String GtkSalFrame::GetKeyName( sal_uInt16 nKeyCode ) 2243 { 2244 return getDisplay()->GetKeyName( nKeyCode ); 2245 } 2246 2247 GdkDisplay *GtkSalFrame::getGdkDisplay() 2248 { 2249 return static_cast<GtkSalDisplay*>(GetX11SalData()->GetDisplay())->GetGdkDisplay(); 2250 } 2251 2252 GtkSalDisplay *GtkSalFrame::getDisplay() 2253 { 2254 return static_cast<GtkSalDisplay*>(GetX11SalData()->GetDisplay()); 2255 } 2256 2257 SalFrame::SalPointerState GtkSalFrame::GetPointerState() 2258 { 2259 SalPointerState aState; 2260 GdkScreen* pScreen; 2261 gint x, y; 2262 GdkModifierType aMask; 2263 gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask ); 2264 aState.maPos = Point( x - maGeometry.nX, y - maGeometry.nY ); 2265 aState.mnState = GetMouseModCode( aMask ); 2266 return aState; 2267 } 2268 2269 void GtkSalFrame::SetInputContext( SalInputContext* pContext ) 2270 { 2271 if( ! pContext ) 2272 return; 2273 2274 if( ! (pContext->mnOptions & SAL_INPUTCONTEXT_TEXT) ) 2275 return; 2276 2277 // create a new im context 2278 if( ! m_pIMHandler ) 2279 m_pIMHandler = new IMHandler( this ); 2280 m_pIMHandler->setInputContext( pContext ); 2281 } 2282 2283 void GtkSalFrame::EndExtTextInput( sal_uInt16 nFlags ) 2284 { 2285 if( m_pIMHandler ) 2286 m_pIMHandler->endExtTextInput( nFlags ); 2287 } 2288 2289 sal_Bool GtkSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& ) 2290 { 2291 // not supported yet 2292 return sal_False; 2293 } 2294 2295 LanguageType GtkSalFrame::GetInputLanguage() 2296 { 2297 return LANGUAGE_DONTKNOW; 2298 } 2299 2300 SalBitmap* GtkSalFrame::SnapShot() 2301 { 2302 if( !m_pWindow ) 2303 return NULL; 2304 2305 X11SalBitmap *pBmp = new X11SalBitmap; 2306 GdkWindow *pWin = m_pWindow->window; 2307 if( pBmp->SnapShot( GDK_DISPLAY_XDISPLAY( getGdkDisplay() ), 2308 GDK_WINDOW_XID( pWin ) ) ) 2309 return pBmp; 2310 else 2311 delete pBmp; 2312 2313 return NULL; 2314 } 2315 2316 void GtkSalFrame::UpdateSettings( AllSettings& rSettings ) 2317 { 2318 if( ! m_pWindow ) 2319 return; 2320 2321 GtkSalGraphics* pGraphics = static_cast<GtkSalGraphics*>(m_aGraphics[0].pGraphics); 2322 bool bFreeGraphics = false; 2323 if( ! pGraphics ) 2324 { 2325 pGraphics = static_cast<GtkSalGraphics*>(GetGraphics()); 2326 bFreeGraphics = true; 2327 } 2328 2329 pGraphics->updateSettings( rSettings ); 2330 2331 if( bFreeGraphics ) 2332 ReleaseGraphics( pGraphics ); 2333 } 2334 2335 void GtkSalFrame::Beep( SoundType eType ) 2336 { 2337 switch( eType ) 2338 { 2339 case SOUND_DEFAULT: 2340 case SOUND_ERROR: 2341 gdk_display_beep( getGdkDisplay() ); 2342 break; 2343 default: 2344 break; 2345 } 2346 } 2347 2348 const SystemEnvData* GtkSalFrame::GetSystemData() const 2349 { 2350 return &m_aSystemData; 2351 } 2352 2353 void GtkSalFrame::SetParent( SalFrame* pNewParent ) 2354 { 2355 if( m_pParent ) 2356 m_pParent->m_aChildren.remove( this ); 2357 m_pParent = static_cast<GtkSalFrame*>(pNewParent); 2358 if( m_pParent ) 2359 m_pParent->m_aChildren.push_back( this ); 2360 if( ! isChild() ) 2361 gtk_window_set_transient_for( GTK_WINDOW(m_pWindow), 2362 (m_pParent && ! m_pParent->isChild(true,false)) ? GTK_WINDOW(m_pParent->m_pWindow) : NULL 2363 ); 2364 } 2365 2366 void GtkSalFrame::createNewWindow( XLIB_Window aNewParent, bool bXEmbed, int nScreen ) 2367 { 2368 bool bWasVisible = GTK_WIDGET_MAPPED(m_pWindow); 2369 if( bWasVisible ) 2370 Show( sal_False ); 2371 2372 if( nScreen < 0 || nScreen >= getDisplay()->GetScreenCount() ) 2373 nScreen = m_nScreen; 2374 2375 SystemParentData aParentData; 2376 aParentData.aWindow = aNewParent; 2377 aParentData.bXEmbedSupport = bXEmbed; 2378 if( aNewParent == None ) 2379 { 2380 aNewParent = getDisplay()->GetRootWindow(nScreen); 2381 aParentData.aWindow = None; 2382 aParentData.bXEmbedSupport = false; 2383 } 2384 else 2385 { 2386 // is new parent a root window ? 2387 Display* pDisp = getDisplay()->GetDisplay(); 2388 int nScreens = getDisplay()->GetScreenCount(); 2389 for( int i = 0; i < nScreens; i++ ) 2390 { 2391 if( aNewParent == RootWindow( pDisp, i ) ) 2392 { 2393 nScreen = i; 2394 aParentData.aWindow = None; 2395 aParentData.bXEmbedSupport = false; 2396 break; 2397 } 2398 } 2399 } 2400 2401 // free xrender resources 2402 for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ ) 2403 if( m_aGraphics[i].bInUse ) 2404 m_aGraphics[i].pGraphics->SetDrawable( None, m_nScreen ); 2405 2406 // first deinit frame 2407 if( m_pIMHandler ) 2408 { 2409 delete m_pIMHandler; 2410 m_pIMHandler = NULL; 2411 } 2412 if( m_pRegion ) 2413 gdk_region_destroy( m_pRegion ); 2414 if( m_pFixedContainer ) 2415 gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer) ); 2416 if( m_pWindow ) 2417 gtk_widget_destroy( m_pWindow ); 2418 if( m_pForeignParent ) 2419 g_object_unref( G_OBJECT(m_pForeignParent) ); 2420 if( m_pForeignTopLevel ) 2421 g_object_unref( G_OBJECT(m_pForeignTopLevel) ); 2422 2423 // init new window 2424 m_bDefaultPos = m_bDefaultSize = false; 2425 if( aParentData.aWindow != None ) 2426 { 2427 m_nStyle |= SAL_FRAME_STYLE_PLUG; 2428 Init( &aParentData ); 2429 } 2430 else 2431 { 2432 m_nStyle &= ~SAL_FRAME_STYLE_PLUG; 2433 Init( (m_pParent && m_pParent->m_nScreen == m_nScreen) ? m_pParent : NULL, m_nStyle ); 2434 } 2435 2436 // update graphics 2437 for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ ) 2438 { 2439 if( m_aGraphics[i].bInUse ) 2440 { 2441 m_aGraphics[i].pGraphics->SetDrawable( GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen ); 2442 m_aGraphics[i].pGraphics->SetWindow( m_pWindow ); 2443 } 2444 } 2445 2446 if( m_aTitle.Len() ) 2447 SetTitle( m_aTitle ); 2448 2449 if( bWasVisible ) 2450 Show( sal_True ); 2451 2452 std::list< GtkSalFrame* > aChildren = m_aChildren; 2453 m_aChildren.clear(); 2454 for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it ) 2455 (*it)->createNewWindow( None, false, m_nScreen ); 2456 2457 // FIXME: SalObjects 2458 } 2459 2460 bool GtkSalFrame::SetPluginParent( SystemParentData* pSysParent ) 2461 { 2462 if( pSysParent ) // this may be the first system child frame now 2463 getDisplay()->setHaveSystemChildFrame(); 2464 createNewWindow( pSysParent->aWindow, (pSysParent->nSize > sizeof(long)) ? pSysParent->bXEmbedSupport : false, m_nScreen ); 2465 return true; 2466 } 2467 2468 void GtkSalFrame::ResetClipRegion() 2469 { 2470 if( m_pWindow ) 2471 gdk_window_shape_combine_region( m_pWindow->window, NULL, 0, 0 ); 2472 } 2473 2474 void GtkSalFrame::BeginSetClipRegion( sal_uLong ) 2475 { 2476 if( m_pRegion ) 2477 gdk_region_destroy( m_pRegion ); 2478 m_pRegion = gdk_region_new(); 2479 } 2480 2481 void GtkSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) 2482 { 2483 if( m_pRegion ) 2484 { 2485 GdkRectangle aRect; 2486 aRect.x = nX; 2487 aRect.y = nY; 2488 aRect.width = nWidth; 2489 aRect.height = nHeight; 2490 2491 gdk_region_union_with_rect( m_pRegion, &aRect ); 2492 } 2493 } 2494 2495 void GtkSalFrame::EndSetClipRegion() 2496 { 2497 if( m_pWindow && m_pRegion ) 2498 gdk_window_shape_combine_region( m_pWindow->window, m_pRegion, 0, 0 ); 2499 } 2500 2501 bool GtkSalFrame::Dispatch( const XEvent* pEvent ) 2502 { 2503 bool bContinueDispatch = true; 2504 2505 if( pEvent->type == PropertyNotify ) 2506 { 2507 vcl_sal::WMAdaptor* pAdaptor = getDisplay()->getWMAdaptor(); 2508 Atom nDesktopAtom = pAdaptor->getAtom( vcl_sal::WMAdaptor::NET_WM_DESKTOP ); 2509 if( pEvent->xproperty.atom == nDesktopAtom && 2510 pEvent->xproperty.state == PropertyNewValue ) 2511 { 2512 m_nWorkArea = pAdaptor->getWindowWorkArea( GDK_WINDOW_XWINDOW( m_pWindow->window) ); 2513 } 2514 } 2515 else if( pEvent->type == ConfigureNotify ) 2516 { 2517 if( m_pForeignParent && pEvent->xconfigure.window == m_aForeignParentWindow ) 2518 { 2519 bContinueDispatch = false; 2520 gtk_window_resize( GTK_WINDOW(m_pWindow), pEvent->xconfigure.width, pEvent->xconfigure.height ); 2521 if( ( sal::static_int_cast< int >(maGeometry.nWidth) != 2522 pEvent->xconfigure.width ) || 2523 ( sal::static_int_cast< int >(maGeometry.nHeight) != 2524 pEvent->xconfigure.height ) ) 2525 { 2526 maGeometry.nWidth = pEvent->xconfigure.width; 2527 maGeometry.nHeight = pEvent->xconfigure.height; 2528 setMinMaxSize(); 2529 getDisplay()->SendInternalEvent( this, NULL, SALEVENT_RESIZE ); 2530 } 2531 } 2532 else if( m_pForeignTopLevel && pEvent->xconfigure.window == m_aForeignTopLevelWindow ) 2533 { 2534 bContinueDispatch = false; 2535 // update position 2536 int x = 0, y = 0; 2537 XLIB_Window aChild; 2538 XTranslateCoordinates( getDisplay()->GetDisplay(), 2539 GDK_WINDOW_XWINDOW( m_pWindow->window), 2540 getDisplay()->GetRootWindow( getDisplay()->GetDefaultScreenNumber() ), 2541 0, 0, 2542 &x, &y, 2543 &aChild ); 2544 if( x != maGeometry.nX || y != maGeometry.nY ) 2545 { 2546 maGeometry.nX = x; 2547 maGeometry.nY = y; 2548 getDisplay()->SendInternalEvent( this, NULL, SALEVENT_MOVE ); 2549 } 2550 } 2551 } 2552 else if( pEvent->type == ClientMessage && 2553 pEvent->xclient.message_type == getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED ) && 2554 pEvent->xclient.window == GDK_WINDOW_XWINDOW(m_pWindow->window) && 2555 m_bWindowIsGtkPlug 2556 ) 2557 { 2558 // FIXME: this should not be necessary, GtkPlug should do this 2559 // transparently for us 2560 if( pEvent->xclient.data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE 2561 pEvent->xclient.data.l[1] == 2 // XEMBED_WINDOW_DEACTIVATE 2562 ) 2563 { 2564 GdkEventFocus aEvent; 2565 aEvent.type = GDK_FOCUS_CHANGE; 2566 aEvent.window = m_pWindow->window; 2567 aEvent.send_event = sal_True; 2568 aEvent.in = (pEvent->xclient.data.l[1] == 1); 2569 signalFocus( m_pWindow, &aEvent, this ); 2570 } 2571 } 2572 2573 return bContinueDispatch; 2574 } 2575 2576 void GtkSalFrame::SetBackgroundBitmap( SalBitmap* pBitmap ) 2577 { 2578 if( m_hBackgroundPixmap ) 2579 { 2580 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(), 2581 GDK_WINDOW_XWINDOW(m_pWindow->window), 2582 None ); 2583 XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap ); 2584 m_hBackgroundPixmap = None; 2585 } 2586 if( pBitmap ) 2587 { 2588 X11SalBitmap* pBM = static_cast<X11SalBitmap*>(pBitmap); 2589 Size aSize = pBM->GetSize(); 2590 if( aSize.Width() && aSize.Height() ) 2591 { 2592 m_hBackgroundPixmap = 2593 XCreatePixmap( getDisplay()->GetDisplay(), 2594 GDK_WINDOW_XWINDOW(m_pWindow->window), 2595 aSize.Width(), 2596 aSize.Height(), 2597 getDisplay()->GetVisual(m_nScreen).GetDepth() ); 2598 if( m_hBackgroundPixmap ) 2599 { 2600 SalTwoRect aTwoRect; 2601 aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0; 2602 aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width(); 2603 aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height(); 2604 pBM->ImplDraw( m_hBackgroundPixmap, 2605 m_nScreen, 2606 getDisplay()->GetVisual(m_nScreen).GetDepth(), 2607 aTwoRect, 2608 getDisplay()->GetCopyGC(m_nScreen) ); 2609 XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(), 2610 GDK_WINDOW_XWINDOW(m_pWindow->window), 2611 m_hBackgroundPixmap ); 2612 } 2613 } 2614 } 2615 } 2616 2617 gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame ) 2618 { 2619 GtkSalFrame* pThis = (GtkSalFrame*)frame; 2620 SalMouseEvent aEvent; 2621 sal_uInt16 nEventType = 0; 2622 switch( pEvent->type ) 2623 { 2624 case GDK_BUTTON_PRESS: 2625 nEventType = SALEVENT_MOUSEBUTTONDOWN; 2626 break; 2627 case GDK_BUTTON_RELEASE: 2628 nEventType = SALEVENT_MOUSEBUTTONUP; 2629 break; 2630 default: 2631 return sal_False; 2632 } 2633 switch( pEvent->button ) 2634 { 2635 case 1: aEvent.mnButton = MOUSE_LEFT; break; 2636 case 2: aEvent.mnButton = MOUSE_MIDDLE; break; 2637 case 3: aEvent.mnButton = MOUSE_RIGHT; break; 2638 default: return sal_False; 2639 } 2640 aEvent.mnTime = pEvent->time; 2641 aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX; 2642 aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY; 2643 aEvent.mnCode = GetMouseModCode( pEvent->state ); 2644 2645 bool bClosePopups = false; 2646 if( pEvent->type == GDK_BUTTON_PRESS && 2647 (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) == 0 2648 ) 2649 { 2650 if( m_nFloats > 0 ) 2651 { 2652 // close popups if user clicks outside our application 2653 gint x, y; 2654 bClosePopups = (gdk_display_get_window_at_pointer( pThis->getGdkDisplay(), &x, &y ) == NULL); 2655 } 2656 /* #i30306# release implicit pointer grab if no popups are open; else 2657 * Drag cannot grab the pointer and will fail. 2658 */ 2659 if( m_nFloats < 1 || bClosePopups ) 2660 gdk_display_pointer_ungrab( pThis->getGdkDisplay(), GDK_CURRENT_TIME ); 2661 } 2662 2663 GTK_YIELD_GRAB(); 2664 2665 if( pThis->m_bWindowIsGtkPlug && 2666 pEvent->type == GDK_BUTTON_PRESS && 2667 pEvent->button == 1 ) 2668 { 2669 pThis->askForXEmbedFocus( pEvent->time ); 2670 } 2671 2672 // --- RTL --- (mirror mouse pos) 2673 if( Application::GetSettings().GetLayoutRTL() ) 2674 aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX; 2675 2676 vcl::DeletionListener aDel( pThis ); 2677 2678 pThis->CallCallback( nEventType, &aEvent ); 2679 2680 if( ! aDel.isDeleted() ) 2681 { 2682 if( bClosePopups ) 2683 { 2684 ImplSVData* pSVData = ImplGetSVData(); 2685 if ( pSVData->maWinData.mpFirstFloat ) 2686 { 2687 static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" ); 2688 if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) && !(pEnv && *pEnv) ) 2689 pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); 2690 } 2691 } 2692 2693 if( ! aDel.isDeleted() ) 2694 { 2695 int frame_x = (int)(pEvent->x_root - pEvent->x); 2696 int frame_y = (int)(pEvent->y_root - pEvent->y); 2697 if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY ) 2698 { 2699 pThis->maGeometry.nX = frame_x; 2700 pThis->maGeometry.nY = frame_y; 2701 pThis->CallCallback( SALEVENT_MOVE, NULL ); 2702 } 2703 } 2704 } 2705 2706 return sal_False; 2707 } 2708 2709 gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEvent* pEvent, gpointer frame ) 2710 { 2711 GtkSalFrame* pThis = (GtkSalFrame*)frame; 2712 GdkEventScroll* pSEvent = (GdkEventScroll*)pEvent; 2713 2714 static sal_uLong nLines = 0; 2715 if( ! nLines ) 2716 { 2717 char* pEnv = getenv( "SAL_WHEELLINES" ); 2718 nLines = pEnv ? atoi( pEnv ) : 3; 2719 if( nLines > 10 ) 2720 nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL; 2721 } 2722 2723 bool bNeg = (pSEvent->direction == GDK_SCROLL_DOWN || pSEvent->direction == GDK_SCROLL_RIGHT ); 2724 SalWheelMouseEvent aEvent; 2725 aEvent.mnTime = pSEvent->time; 2726 aEvent.mnX = (sal_uLong)pSEvent->x; 2727 aEvent.mnY = (sal_uLong)pSEvent->y; 2728 aEvent.mnDelta = bNeg ? -120 : 120; 2729 aEvent.mnNotchDelta = bNeg ? -1 : 1; 2730 aEvent.mnScrollLines = nLines; 2731 aEvent.mnCode = GetMouseModCode( pSEvent->state ); 2732 aEvent.mbHorz = (pSEvent->direction == GDK_SCROLL_LEFT || pSEvent->direction == GDK_SCROLL_RIGHT); 2733 2734 GTK_YIELD_GRAB(); 2735 2736 // --- RTL --- (mirror mouse pos) 2737 if( Application::GetSettings().GetLayoutRTL() ) 2738 aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX; 2739 2740 pThis->CallCallback( SALEVENT_WHEELMOUSE, &aEvent ); 2741 2742 return sal_False; 2743 } 2744 2745 gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer frame ) 2746 { 2747 GtkSalFrame* pThis = (GtkSalFrame*)frame; 2748 2749 SalMouseEvent aEvent; 2750 aEvent.mnTime = pEvent->time; 2751 aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX; 2752 aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY; 2753 aEvent.mnCode = GetMouseModCode( pEvent->state ); 2754 aEvent.mnButton = 0; 2755 2756 2757 GTK_YIELD_GRAB(); 2758 2759 // --- RTL --- (mirror mouse pos) 2760 if( Application::GetSettings().GetLayoutRTL() ) 2761 aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX; 2762 2763 vcl::DeletionListener aDel( pThis ); 2764 2765 pThis->CallCallback( SALEVENT_MOUSEMOVE, &aEvent ); 2766 2767 if( ! aDel.isDeleted() ) 2768 { 2769 int frame_x = (int)(pEvent->x_root - pEvent->x); 2770 int frame_y = (int)(pEvent->y_root - pEvent->y); 2771 if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY ) 2772 { 2773 pThis->maGeometry.nX = frame_x; 2774 pThis->maGeometry.nY = frame_y; 2775 pThis->CallCallback( SALEVENT_MOVE, NULL ); 2776 } 2777 2778 if( ! aDel.isDeleted() ) 2779 { 2780 // ask for the next hint 2781 gint x, y; 2782 GdkModifierType mask; 2783 gdk_window_get_pointer( GTK_WIDGET(pThis->m_pWindow)->window, &x, &y, &mask ); 2784 } 2785 } 2786 2787 return sal_True; 2788 } 2789 2790 gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpointer frame ) 2791 { 2792 GtkSalFrame* pThis = (GtkSalFrame*)frame; 2793 SalMouseEvent aEvent; 2794 aEvent.mnTime = pEvent->time; 2795 aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX; 2796 aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY; 2797 aEvent.mnCode = GetMouseModCode( pEvent->state ); 2798 aEvent.mnButton = 0; 2799 2800 GTK_YIELD_GRAB(); 2801 pThis->CallCallback( (pEvent->type == GDK_ENTER_NOTIFY) ? SALEVENT_MOUSEMOVE : SALEVENT_MOUSELEAVE, &aEvent ); 2802 2803 return sal_True; 2804 } 2805 2806 2807 gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer frame ) 2808 { 2809 GtkSalFrame* pThis = (GtkSalFrame*)frame; 2810 2811 struct SalPaintEvent aEvent( pEvent->area.x, pEvent->area.y, pEvent->area.width, pEvent->area.height ); 2812 2813 GTK_YIELD_GRAB(); 2814 pThis->CallCallback( SALEVENT_PAINT, &aEvent ); 2815 2816 return sal_False; 2817 } 2818 2819 gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame ) 2820 { 2821 GtkSalFrame* pThis = (GtkSalFrame*)frame; 2822 2823 GTK_YIELD_GRAB(); 2824 2825 // check if printers have changed (analogous to salframe focus handler) 2826 vcl_sal::PrinterUpdate::update(); 2827 2828 if( !pEvent->in ) 2829 { 2830 pThis->m_nKeyModifiers = 0; 2831 pThis->m_bSingleAltPress = false; 2832 pThis->m_bSendModChangeOnRelease = false; 2833 } 2834 2835 if( pThis->m_pIMHandler ) 2836 pThis->m_pIMHandler->focusChanged( pEvent->in ); 2837 2838 // ask for changed printers like generic implementation 2839 if( pEvent->in ) 2840 if( static_cast< X11SalInstance* >(GetSalData()->m_pInstance)->isPrinterInit() ) 2841 vcl_sal::PrinterUpdate::update(); 2842 2843 // FIXME: find out who the hell steals the focus from our frame 2844 // while we have the pointer grabbed, this should not come from 2845 // the window manager. Is this an event that was still queued ? 2846 // The focus does not seem to get set inside our process 2847 // 2848 // in the meantime do not propagate focus get/lose if floats are open 2849 if( m_nFloats == 0 ) 2850 pThis->CallCallback( pEvent->in ? SALEVENT_GETFOCUS : SALEVENT_LOSEFOCUS, NULL ); 2851 2852 return sal_False; 2853 } 2854 2855 IMPL_LINK( GtkSalFrame, ImplDelayedFullScreenHdl, void*, EMPTYARG ) 2856 { 2857 Atom nStateAtom = getDisplay()->getWMAdaptor()->getAtom(vcl_sal::WMAdaptor::NET_WM_STATE); 2858 Atom nFSAtom = getDisplay()->getWMAdaptor()->getAtom(vcl_sal::WMAdaptor::NET_WM_STATE_FULLSCREEN ); 2859 if( nStateAtom && nFSAtom ) 2860 { 2861 /* #i110881# workaround a gtk issue (see https://bugzilla.redhat.com/show_bug.cgi?id=623191#c8) 2862 gtk_window_fullscreen can fail due to a race condition, request an additional status change 2863 to fullscreen to be safe 2864 */ 2865 XEvent aEvent; 2866 aEvent.type = ClientMessage; 2867 aEvent.xclient.display = getDisplay()->GetDisplay(); 2868 aEvent.xclient.window = GDK_WINDOW_XWINDOW(m_pWindow->window); 2869 aEvent.xclient.message_type = nStateAtom; 2870 aEvent.xclient.format = 32; 2871 aEvent.xclient.data.l[0] = 1; 2872 aEvent.xclient.data.l[1] = nFSAtom; 2873 aEvent.xclient.data.l[2] = 0; 2874 aEvent.xclient.data.l[3] = 0; 2875 aEvent.xclient.data.l[4] = 0; 2876 XSendEvent( getDisplay()->GetDisplay(), 2877 getDisplay()->GetRootWindow( m_nScreen ), 2878 False, 2879 SubstructureNotifyMask | SubstructureRedirectMask, 2880 &aEvent 2881 ); 2882 } 2883 2884 return 0; 2885 } 2886 2887 gboolean GtkSalFrame::signalMap( GtkWidget*, GdkEvent*, gpointer frame ) 2888 { 2889 GtkSalFrame* pThis = (GtkSalFrame*)frame; 2890 2891 GTK_YIELD_GRAB(); 2892 2893 if( pThis->m_bFullscreen ) 2894 { 2895 /* #i110881# workaorund a gtk issue (see https://bugzilla.redhat.com/show_bug.cgi?id=623191#c8) 2896 gtk_window_fullscreen can run into a race condition with the window's showstate 2897 */ 2898 Application::PostUserEvent( LINK( pThis, GtkSalFrame, ImplDelayedFullScreenHdl ) ); 2899 } 2900 2901 bool bSetFocus = pThis->m_bSetFocusOnMap; 2902 pThis->m_bSetFocusOnMap = false; 2903 if( ImplGetSVData()->mbIsTestTool ) 2904 { 2905 /* #i76541# testtool needs the focus to be in a new document 2906 * however e.g. metacity does not necessarily put the focus into 2907 * a newly shown window. An extra little hint seems to help here. 2908 * however we don't want to interfere with the normal user experience 2909 * so this is done when running in testtool only 2910 */ 2911 if( ! pThis->m_pParent && (pThis->m_nStyle & SAL_FRAME_STYLE_MOVEABLE) != 0 ) 2912 bSetFocus = true; 2913 } 2914 2915 if( bSetFocus ) 2916 { 2917 XSetInputFocus( pThis->getDisplay()->GetDisplay(), 2918 GDK_WINDOW_XWINDOW( GTK_WIDGET(pThis->m_pWindow)->window), 2919 RevertToParent, CurrentTime ); 2920 } 2921 2922 pThis->CallCallback( SALEVENT_RESIZE, NULL ); 2923 2924 return sal_False; 2925 } 2926 2927 gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame ) 2928 { 2929 GtkSalFrame* pThis = (GtkSalFrame*)frame; 2930 2931 GTK_YIELD_GRAB(); 2932 pThis->CallCallback( SALEVENT_RESIZE, NULL ); 2933 2934 return sal_False; 2935 } 2936 2937 gboolean GtkSalFrame::signalConfigure( GtkWidget*, GdkEventConfigure* pEvent, gpointer frame ) 2938 { 2939 GtkSalFrame* pThis = (GtkSalFrame*)frame; 2940 2941 bool bMoved = false, bSized = false; 2942 int x = pEvent->x, y = pEvent->y; 2943 2944 /* HACK: during sizing/moving a toolbar pThis->maGeometry is actually 2945 * already exact; even worse: due to the asynchronicity of configure 2946 * events the borderwindow which would evaluate this event 2947 * would size/move based on wrong data if we would actually evaluate 2948 * this event. So let's swallow it; this is also a performance 2949 * improvement as one can omit the synchronous XTranslateCoordinates 2950 * call below. 2951 */ 2952 if( (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) && 2953 pThis->getDisplay()->GetCaptureFrame() == pThis ) 2954 return sal_False; 2955 2956 2957 // in child case the coordinates are not root coordinates, 2958 // need to transform 2959 2960 /* #i31785# sadly one cannot really trust the x,y members of the event; 2961 * they are e.g. not set correctly on maximize/demaximize; this rather 2962 * sounds like a bug in gtk we have to workaround. 2963 */ 2964 XLIB_Window aChild; 2965 XTranslateCoordinates( pThis->getDisplay()->GetDisplay(), 2966 GDK_WINDOW_XWINDOW(GTK_WIDGET(pThis->m_pWindow)->window), 2967 pThis->getDisplay()->GetRootWindow( pThis->getDisplay()->GetDefaultScreenNumber() ), 2968 0, 0, 2969 &x, &y, 2970 &aChild ); 2971 2972 if( x != pThis->maGeometry.nX || y != pThis->maGeometry.nY ) 2973 { 2974 bMoved = true; 2975 pThis->maGeometry.nX = x; 2976 pThis->maGeometry.nY = y; 2977 } 2978 /* #i86302# 2979 * for non sizeable windows we set the min and max hint for the window manager to 2980 * achieve correct sizing. However this is asynchronous and e.g. on Compiz 2981 * it sometimes happens that the window gets resized to another size (some default) 2982 * if we update the size here, subsequent setMinMaxSize will use this wrong size 2983 * - which is not good since the window manager will now size the window back to this 2984 * wrong size at some point. 2985 */ 2986 if( (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)) == SAL_FRAME_STYLE_SIZEABLE ) 2987 { 2988 if( pEvent->width != (int)pThis->maGeometry.nWidth || pEvent->height != (int)pThis->maGeometry.nHeight ) 2989 { 2990 bSized = true; 2991 pThis->maGeometry.nWidth = pEvent->width; 2992 pThis->maGeometry.nHeight = pEvent->height; 2993 } 2994 } 2995 2996 // update decoration hints 2997 if( ! (pThis->m_nStyle & SAL_FRAME_STYLE_PLUG) ) 2998 { 2999 GdkRectangle aRect; 3000 gdk_window_get_frame_extents( GTK_WIDGET(pThis->m_pWindow)->window, &aRect ); 3001 pThis->maGeometry.nTopDecoration = y - aRect.y; 3002 pThis->maGeometry.nBottomDecoration = aRect.y + aRect.height - y - pEvent->height; 3003 pThis->maGeometry.nLeftDecoration = x - aRect.x; 3004 pThis->maGeometry.nRightDecoration = aRect.x + aRect.width - x - pEvent->width; 3005 } 3006 else 3007 { 3008 pThis->maGeometry.nTopDecoration = 3009 pThis->maGeometry.nBottomDecoration = 3010 pThis->maGeometry.nLeftDecoration = 3011 pThis->maGeometry.nRightDecoration = 0; 3012 } 3013 3014 GTK_YIELD_GRAB(); 3015 pThis->updateScreenNumber(); 3016 if( bMoved && bSized ) 3017 pThis->CallCallback( SALEVENT_MOVERESIZE, NULL ); 3018 else if( bMoved ) 3019 pThis->CallCallback( SALEVENT_MOVE, NULL ); 3020 else if( bSized ) 3021 pThis->CallCallback( SALEVENT_RESIZE, NULL ); 3022 3023 return sal_False; 3024 } 3025 3026 gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame ) 3027 { 3028 GtkSalFrame* pThis = (GtkSalFrame*)frame; 3029 3030 vcl::DeletionListener aDel( pThis ); 3031 3032 if( pThis->m_pIMHandler ) 3033 { 3034 if( pThis->m_pIMHandler->handleKeyEvent( pEvent ) ) 3035 { 3036 pThis->m_bSingleAltPress = false; 3037 return sal_True; 3038 } 3039 } 3040 GTK_YIELD_GRAB(); 3041 3042 // handle modifiers 3043 if( pEvent->keyval == GDK_Shift_L || pEvent->keyval == GDK_Shift_R || 3044 pEvent->keyval == GDK_Control_L || pEvent->keyval == GDK_Control_R || 3045 pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R || 3046 pEvent->keyval == GDK_Meta_L || pEvent->keyval == GDK_Meta_R || 3047 pEvent->keyval == GDK_Super_L || pEvent->keyval == GDK_Super_R ) 3048 { 3049 SalKeyModEvent aModEvt; 3050 3051 sal_uInt16 nModCode = GetKeyModCode( pEvent->state ); 3052 3053 aModEvt.mnModKeyCode = 0; // emit no MODKEYCHANGE events 3054 if( pEvent->type == GDK_KEY_PRESS && !pThis->m_nKeyModifiers ) 3055 pThis->m_bSendModChangeOnRelease = true; 3056 3057 else if( pEvent->type == GDK_KEY_RELEASE && 3058 pThis->m_bSendModChangeOnRelease ) 3059 { 3060 aModEvt.mnModKeyCode = pThis->m_nKeyModifiers; 3061 pThis->m_nKeyModifiers = 0; 3062 } 3063 3064 sal_uInt16 nExtModMask = 0; 3065 sal_uInt16 nModMask = 0; 3066 // pressing just the ctrl key leads to a keysym of XK_Control but 3067 // the event state does not contain ControlMask. In the release 3068 // event its the other way round: it does contain the Control mask. 3069 // The modifier mode therefore has to be adapted manually. 3070 switch( pEvent->keyval ) 3071 { 3072 case GDK_Control_L: 3073 nExtModMask = MODKEY_LMOD1; 3074 nModMask = KEY_MOD1; 3075 break; 3076 case GDK_Control_R: 3077 nExtModMask = MODKEY_RMOD1; 3078 nModMask = KEY_MOD1; 3079 break; 3080 case GDK_Alt_L: 3081 nExtModMask = MODKEY_LMOD2; 3082 nModMask = KEY_MOD2; 3083 break; 3084 case GDK_Alt_R: 3085 nExtModMask = MODKEY_RMOD2; 3086 nModMask = KEY_MOD2; 3087 break; 3088 case GDK_Shift_L: 3089 nExtModMask = MODKEY_LSHIFT; 3090 nModMask = KEY_SHIFT; 3091 break; 3092 case GDK_Shift_R: 3093 nExtModMask = MODKEY_RSHIFT; 3094 nModMask = KEY_SHIFT; 3095 break; 3096 // Map Meta/Super to MOD3 modifier on all Unix systems 3097 // except Mac OS X 3098 case GDK_Meta_L: 3099 case GDK_Super_L: 3100 nExtModMask = MODKEY_LMOD3; 3101 nModMask = KEY_MOD3; 3102 break; 3103 case GDK_Meta_R: 3104 case GDK_Super_R: 3105 nExtModMask = MODKEY_RMOD3; 3106 nModMask = KEY_MOD3; 3107 break; 3108 } 3109 if( pEvent->type == GDK_KEY_RELEASE ) 3110 { 3111 nModCode &= ~nModMask; 3112 pThis->m_nKeyModifiers &= ~nExtModMask; 3113 } 3114 else 3115 { 3116 nModCode |= nModMask; 3117 pThis->m_nKeyModifiers |= nExtModMask; 3118 } 3119 3120 aModEvt.mnCode = nModCode; 3121 aModEvt.mnTime = pEvent->time; 3122 3123 pThis->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt ); 3124 3125 if( ! aDel.isDeleted() ) 3126 { 3127 // emulate KEY_MENU 3128 if( ( pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ) && 3129 ( nModCode & ~(KEY_MOD3|KEY_MOD2)) == 0 ) 3130 { 3131 if( pEvent->type == GDK_KEY_PRESS ) 3132 pThis->m_bSingleAltPress = true; 3133 3134 else if( pThis->m_bSingleAltPress ) 3135 { 3136 SalKeyEvent aKeyEvt; 3137 3138 aKeyEvt.mnCode = KEY_MENU | nModCode; 3139 aKeyEvt.mnRepeat = 0; 3140 aKeyEvt.mnTime = pEvent->time; 3141 aKeyEvt.mnCharCode = 0; 3142 3143 // simulate KEY_MENU 3144 pThis->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt ); 3145 if( ! aDel.isDeleted() ) 3146 { 3147 pThis->CallCallback( SALEVENT_KEYUP, &aKeyEvt ); 3148 pThis->m_bSingleAltPress = false; 3149 } 3150 } 3151 } 3152 else 3153 pThis->m_bSingleAltPress = false; 3154 } 3155 } 3156 else 3157 { 3158 pThis->doKeyCallback( pEvent->state, 3159 pEvent->keyval, 3160 pEvent->hardware_keycode, 3161 pEvent->group, 3162 pEvent->time, 3163 sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )), 3164 (pEvent->type == GDK_KEY_PRESS), 3165 false ); 3166 if( ! aDel.isDeleted() ) 3167 { 3168 pThis->m_bSendModChangeOnRelease = false; 3169 pThis->m_bSingleAltPress = false; 3170 } 3171 } 3172 3173 if( !aDel.isDeleted() && pThis->m_pIMHandler ) 3174 pThis->m_pIMHandler->updateIMSpotLocation(); 3175 3176 return sal_True; 3177 } 3178 3179 gboolean GtkSalFrame::signalDelete( GtkWidget*, GdkEvent*, gpointer frame ) 3180 { 3181 GtkSalFrame* pThis = (GtkSalFrame*)frame; 3182 3183 GTK_YIELD_GRAB(); 3184 pThis->CallCallback( SALEVENT_CLOSE, NULL ); 3185 3186 return sal_True; 3187 } 3188 3189 void GtkSalFrame::signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer frame ) 3190 { 3191 GtkSalFrame* pThis = (GtkSalFrame*)frame; 3192 3193 // every frame gets an initial style set on creation 3194 // do not post these as the whole application tends to 3195 // redraw itself to adjust to the new style 3196 // where there IS no new style resulting in tremendous unnecessary flickering 3197 if( pPrevious != NULL ) 3198 { 3199 // signalStyleSet does NOT usually have the gdk lock 3200 // so post user event to safely dispatch the SALEVENT_SETTINGSCHANGED 3201 // note: settings changed for multiple frames is avoided in winproc.cxx ImplHandleSettings 3202 pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_SETTINGSCHANGED ); 3203 pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_FONTCHANGED ); 3204 } 3205 3206 /* #i64117# gtk sets a nice background pixmap 3207 * but we actually don't really want that, so save 3208 * some time on the Xserver as well as prevent 3209 * some paint issues 3210 */ 3211 GdkWindow* pWin = GTK_WIDGET(pThis->getWindow())->window; 3212 if( pWin ) 3213 { 3214 XLIB_Window aWin = GDK_WINDOW_XWINDOW(pWin); 3215 if( aWin != None ) 3216 XSetWindowBackgroundPixmap( pThis->getDisplay()->GetDisplay(), 3217 aWin, 3218 pThis->m_hBackgroundPixmap ); 3219 } 3220 3221 if( ! pThis->m_pParent ) 3222 { 3223 // signalize theme changed for NWF caches 3224 // FIXME: should be called only once for a style change 3225 GtkSalGraphics::bThemeChanged = sal_True; 3226 } 3227 } 3228 3229 gboolean GtkSalFrame::signalState( GtkWidget*, GdkEvent* pEvent, gpointer frame ) 3230 { 3231 GtkSalFrame* pThis = (GtkSalFrame*)frame; 3232 if( (pThis->m_nState & GDK_WINDOW_STATE_ICONIFIED) != (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED ) ) 3233 pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_RESIZE ); 3234 3235 if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && 3236 ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) ) 3237 { 3238 pThis->m_aRestorePosSize = 3239 Rectangle( Point( pThis->maGeometry.nX, pThis->maGeometry.nY ), 3240 Size( pThis->maGeometry.nWidth, pThis->maGeometry.nHeight ) ); 3241 } 3242 pThis->m_nState = pEvent->window_state.new_window_state; 3243 3244 #if OSL_DEBUG_LEVEL > 1 3245 if( (pEvent->window_state.changed_mask & GDK_WINDOW_STATE_FULLSCREEN) ) 3246 { 3247 fprintf( stderr, "window %p %s full screen state\n", 3248 pThis, 3249 (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_FULLSCREEN) ? "enters" : "leaves"); 3250 } 3251 #endif 3252 3253 return sal_False; 3254 } 3255 3256 gboolean GtkSalFrame::signalVisibility( GtkWidget*, GdkEventVisibility* pEvent, gpointer frame ) 3257 { 3258 GtkSalFrame* pThis = (GtkSalFrame*)frame; 3259 pThis->m_nVisibility = pEvent->state; 3260 3261 return sal_False; 3262 } 3263 3264 void GtkSalFrame::signalDestroy( GtkObject* pObj, gpointer frame ) 3265 { 3266 GtkSalFrame* pThis = (GtkSalFrame*)frame; 3267 if( GTK_WIDGET( pObj ) == pThis->m_pWindow ) 3268 { 3269 pThis->m_pFixedContainer = NULL; 3270 pThis->m_pWindow = NULL; 3271 } 3272 } 3273 3274 // ---------------------------------------------------------------------- 3275 // GtkSalFrame::IMHandler 3276 // ---------------------------------------------------------------------- 3277 3278 GtkSalFrame::IMHandler::IMHandler( GtkSalFrame* pFrame ) 3279 : m_pFrame(pFrame), 3280 m_nPrevKeyPresses( 0 ), 3281 m_pIMContext( NULL ), 3282 m_bFocused( true ), 3283 m_bPreeditJustChanged( false ) 3284 { 3285 m_aInputEvent.mpTextAttr = NULL; 3286 createIMContext(); 3287 } 3288 3289 GtkSalFrame::IMHandler::~IMHandler() 3290 { 3291 // cancel an eventual event posted to begin preedit again 3292 m_pFrame->getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT ); 3293 deleteIMContext(); 3294 } 3295 3296 void GtkSalFrame::IMHandler::createIMContext() 3297 { 3298 if( ! m_pIMContext ) 3299 { 3300 m_pIMContext = gtk_im_multicontext_new (); 3301 g_signal_connect( m_pIMContext, "commit", 3302 G_CALLBACK (signalIMCommit), this ); 3303 g_signal_connect( m_pIMContext, "preedit_changed", 3304 G_CALLBACK (signalIMPreeditChanged), this ); 3305 g_signal_connect( m_pIMContext, "retrieve_surrounding", 3306 G_CALLBACK (signalIMRetrieveSurrounding), this ); 3307 g_signal_connect( m_pIMContext, "delete_surrounding", 3308 G_CALLBACK (signalIMDeleteSurrounding), this ); 3309 g_signal_connect( m_pIMContext, "preedit_start", 3310 G_CALLBACK (signalIMPreeditStart), this ); 3311 g_signal_connect( m_pIMContext, "preedit_end", 3312 G_CALLBACK (signalIMPreeditEnd), this ); 3313 3314 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true ); 3315 gtk_im_context_set_client_window( m_pIMContext, GTK_WIDGET(m_pFrame->m_pWindow)->window ); 3316 gtk_im_context_focus_in( m_pIMContext ); 3317 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel(); 3318 m_bFocused = true; 3319 } 3320 } 3321 3322 void GtkSalFrame::IMHandler::deleteIMContext() 3323 { 3324 if( m_pIMContext ) 3325 { 3326 // first give IC a chance to deinitialize 3327 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true ); 3328 gtk_im_context_set_client_window( m_pIMContext, NULL ); 3329 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel(); 3330 // destroy old IC 3331 g_object_unref( m_pIMContext ); 3332 m_pIMContext = NULL; 3333 } 3334 } 3335 3336 void GtkSalFrame::IMHandler::doCallEndExtTextInput() 3337 { 3338 m_aInputEvent.mpTextAttr = NULL; 3339 m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL ); 3340 } 3341 3342 void GtkSalFrame::IMHandler::updateIMSpotLocation() 3343 { 3344 SalExtTextInputPosEvent aPosEvent; 3345 m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent ); 3346 GdkRectangle aArea; 3347 // Positive aPosEvent.mnExtWidth means ahead of the carret, 3348 // negative value means behind of the carret. 3349 aArea.x = aPosEvent.mnX + (aPosEvent.mnExtWidth < 0 ? aPosEvent.mnExtWidth : 0); 3350 aArea.y = aPosEvent.mnY; 3351 aArea.width = aPosEvent.mnWidth; 3352 aArea.height = aPosEvent.mnHeight; 3353 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true ); 3354 gtk_im_context_set_cursor_location( m_pIMContext, &aArea ); 3355 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel(); 3356 } 3357 3358 void GtkSalFrame::IMHandler::setInputContext( SalInputContext* ) 3359 { 3360 } 3361 3362 void GtkSalFrame::IMHandler::sendEmptyCommit() 3363 { 3364 vcl::DeletionListener aDel( m_pFrame ); 3365 3366 SalExtTextInputEvent aEmptyEv; 3367 aEmptyEv.mnTime = 0; 3368 aEmptyEv.mpTextAttr = 0; 3369 aEmptyEv.maText = String(); 3370 aEmptyEv.mnCursorPos = 0; 3371 aEmptyEv.mnCursorFlags = 0; 3372 aEmptyEv.mnDeltaStart = 0; 3373 aEmptyEv.mbOnlyCursor = False; 3374 m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv ); 3375 if( ! aDel.isDeleted() ) 3376 m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL ); 3377 } 3378 3379 void GtkSalFrame::IMHandler::endExtTextInput( sal_uInt16 /*nFlags*/ ) 3380 { 3381 gtk_im_context_reset ( m_pIMContext ); 3382 3383 if( m_aInputEvent.mpTextAttr ) 3384 { 3385 vcl::DeletionListener aDel( m_pFrame ); 3386 // delete preedit in sal (commit an empty string) 3387 sendEmptyCommit(); 3388 if( ! aDel.isDeleted() ) 3389 { 3390 // mark previous preedit state again (will e.g. be sent at focus gain) 3391 m_aInputEvent.mpTextAttr = &m_aInputFlags[0]; 3392 if( m_bFocused ) 3393 { 3394 // begin preedit again 3395 m_pFrame->getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT ); 3396 } 3397 } 3398 } 3399 } 3400 3401 void GtkSalFrame::IMHandler::focusChanged( bool bFocusIn ) 3402 { 3403 m_bFocused = bFocusIn; 3404 if( bFocusIn ) 3405 { 3406 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true ); 3407 gtk_im_context_focus_in( m_pIMContext ); 3408 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel(); 3409 if( m_aInputEvent.mpTextAttr ) 3410 { 3411 sendEmptyCommit(); 3412 // begin preedit again 3413 m_pFrame->getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT ); 3414 } 3415 } 3416 else 3417 { 3418 m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true ); 3419 gtk_im_context_focus_out( m_pIMContext ); 3420 m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel(); 3421 // cancel an eventual event posted to begin preedit again 3422 m_pFrame->getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT ); 3423 } 3424 } 3425 3426 bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent ) 3427 { 3428 vcl::DeletionListener aDel( m_pFrame ); 3429 3430 if( pEvent->type == GDK_KEY_PRESS ) 3431 { 3432 // Add this key press event to the list of previous key presses 3433 // to which we compare key release events. If a later key release 3434 // event has a matching key press event in this list, we swallow 3435 // the key release because some GTK Input Methods don't swallow it 3436 // for us. 3437 m_aPrevKeyPresses.push_back( PreviousKeyPress(pEvent) ); 3438 m_nPrevKeyPresses++; 3439 3440 // Also pop off the earliest key press event if there are more than 10 3441 // already. 3442 while (m_nPrevKeyPresses > 10) 3443 { 3444 m_aPrevKeyPresses.pop_front(); 3445 m_nPrevKeyPresses--; 3446 } 3447 3448 GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) ); 3449 3450 // #i51353# update spot location on every key input since we cannot 3451 // know which key may activate a preedit choice window 3452 updateIMSpotLocation(); 3453 if( aDel.isDeleted() ) 3454 return true; 3455 3456 gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent ); 3457 g_object_unref( pRef ); 3458 3459 if( aDel.isDeleted() ) 3460 return true; 3461 3462 m_bPreeditJustChanged = false; 3463 3464 if( bResult ) 3465 return true; 3466 else 3467 { 3468 DBG_ASSERT( m_nPrevKeyPresses > 0, "key press has vanished !" ); 3469 if( ! m_aPrevKeyPresses.empty() ) // sanity check 3470 { 3471 // event was not swallowed, do not filter a following 3472 // key release event 3473 // note: this relies on gtk_im_context_filter_keypress 3474 // returning without calling a handler (in the "not swallowed" 3475 // case ) which might change the previous key press list so 3476 // we would pop the wrong event here 3477 m_aPrevKeyPresses.pop_back(); 3478 m_nPrevKeyPresses--; 3479 } 3480 } 3481 } 3482 3483 // Determine if we got an earlier key press event corresponding to this key release 3484 if (pEvent->type == GDK_KEY_RELEASE) 3485 { 3486 GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) ); 3487 gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent ); 3488 g_object_unref( pRef ); 3489 3490 if( aDel.isDeleted() ) 3491 return true; 3492 3493 m_bPreeditJustChanged = false; 3494 3495 std::list<PreviousKeyPress>::iterator iter = m_aPrevKeyPresses.begin(); 3496 std::list<PreviousKeyPress>::iterator iter_end = m_aPrevKeyPresses.end(); 3497 while (iter != iter_end) 3498 { 3499 // If we found a corresponding previous key press event, swallow the release 3500 // and remove the earlier key press from our list 3501 if (*iter == pEvent) 3502 { 3503 m_aPrevKeyPresses.erase(iter); 3504 m_nPrevKeyPresses--; 3505 return true; 3506 } 3507 ++iter; 3508 } 3509 3510 if( bResult ) 3511 return true; 3512 } 3513 3514 return false; 3515 } 3516 3517 /* FIXME: 3518 * #122282# still more hacking: some IMEs never start a preedit but simply commit 3519 * in this case we cannot commit a single character. Workaround: do not do the 3520 * single key hack for enter or space if the unicode committed does not match 3521 */ 3522 3523 static bool checkSingleKeyCommitHack( guint keyval, sal_Unicode cCode ) 3524 { 3525 bool bRet = true; 3526 switch( keyval ) 3527 { 3528 case GDK_KP_Enter: 3529 case GDK_Return: 3530 if( cCode != '\n' && cCode != '\r' ) 3531 bRet = false; 3532 break; 3533 case GDK_space: 3534 case GDK_KP_Space: 3535 if( cCode != ' ' ) 3536 bRet = false; 3537 break; 3538 default: 3539 break; 3540 } 3541 return bRet; 3542 } 3543 3544 #ifdef SOLARIS 3545 #define CONTEXT_ARG pContext 3546 #else 3547 #define CONTEXT_ARG EMPTYARG 3548 #endif 3549 void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* CONTEXT_ARG, gchar* pText, gpointer im_handler ) 3550 { 3551 GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler; 3552 3553 vcl::DeletionListener aDel( pThis->m_pFrame ); 3554 // open a block that will end the GTK_YIELD_GRAB before calling preedit changed again 3555 { 3556 GTK_YIELD_GRAB(); 3557 3558 bool bWasPreedit = 3559 (pThis->m_aInputEvent.mpTextAttr != 0) || 3560 pThis->m_bPreeditJustChanged; 3561 pThis->m_bPreeditJustChanged = false; 3562 3563 pThis->m_aInputEvent.mnTime = 0; 3564 pThis->m_aInputEvent.mpTextAttr = 0; 3565 pThis->m_aInputEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 ); 3566 pThis->m_aInputEvent.mnCursorPos = pThis->m_aInputEvent.maText.Len(); 3567 pThis->m_aInputEvent.mnCursorFlags = 0; 3568 pThis->m_aInputEvent.mnDeltaStart = 0; 3569 pThis->m_aInputEvent.mbOnlyCursor = False; 3570 3571 pThis->m_aInputFlags.clear(); 3572 3573 /* necessary HACK: all keyboard input comes in here as soon as a IMContext is set 3574 * which is logical and consequent. But since even simple input like 3575 * <space> comes through the commit signal instead of signalKey 3576 * and all kinds of windows only implement KeyInput (e.g. PushButtons, 3577 * RadioButtons and a lot of other Controls), will send a single 3578 * KeyInput/KeyUp sequence instead of an ExtText event if there 3579 * never was a preedit and the text is only one character. 3580 * 3581 * In this case there the last ExtText event must have been 3582 * SALEVENT_ENDEXTTEXTINPUT, either because of a regular commit 3583 * or because there never was a preedit. 3584 */ 3585 bool bSingleCommit = false; 3586 3587 if( ! bWasPreedit 3588 && pThis->m_aInputEvent.maText.Len() == 1 3589 && ! pThis->m_aPrevKeyPresses.empty() 3590 ) 3591 { 3592 const PreviousKeyPress& rKP = pThis->m_aPrevKeyPresses.back(); 3593 sal_Unicode aOrigCode = pThis->m_aInputEvent.maText.GetChar(0); 3594 3595 if( checkSingleKeyCommitHack( rKP.keyval, aOrigCode ) ) 3596 { 3597 pThis->m_pFrame->doKeyCallback( rKP.state, rKP.keyval, rKP.hardware_keycode, rKP.group, rKP.time, aOrigCode, true, true ); 3598 bSingleCommit = true; 3599 } 3600 } 3601 if( ! bSingleCommit ) 3602 { 3603 pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent); 3604 if( ! aDel.isDeleted() ) 3605 pThis->doCallEndExtTextInput(); 3606 } 3607 if( ! aDel.isDeleted() ) 3608 { 3609 // reset input event 3610 pThis->m_aInputEvent.maText = String(); 3611 pThis->m_aInputEvent.mnCursorPos = 0; 3612 pThis->updateIMSpotLocation(); 3613 } 3614 } 3615 #ifdef SOLARIS 3616 // #i51356# workaround a solaris IIIMP bug 3617 // in case of partial commits the preedit changed signal 3618 // and commit signal come in wrong order 3619 if( ! aDel.isDeleted() ) 3620 signalIMPreeditChanged( pContext, im_handler ); 3621 #endif 3622 } 3623 3624 void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext*, gpointer im_handler ) 3625 { 3626 GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler; 3627 3628 char* pText = NULL; 3629 PangoAttrList* pAttrs = NULL; 3630 gint nCursorPos = 0; 3631 3632 gtk_im_context_get_preedit_string( pThis->m_pIMContext, 3633 &pText, 3634 &pAttrs, 3635 &nCursorPos ); 3636 if( pText && ! *pText ) // empty string 3637 { 3638 // change from nothing to nothing -> do not start preedit 3639 // e.g. this will activate input into a calc cell without 3640 // user input 3641 if( pThis->m_aInputEvent.maText.Len() == 0 ) 3642 { 3643 g_free( pText ); 3644 return; 3645 } 3646 } 3647 3648 pThis->m_bPreeditJustChanged = true; 3649 3650 bool bEndPreedit = (!pText || !*pText) && pThis->m_aInputEvent.mpTextAttr != NULL; 3651 pThis->m_aInputEvent.mnTime = 0; 3652 pThis->m_aInputEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 ); 3653 pThis->m_aInputEvent.mnCursorPos = nCursorPos; 3654 pThis->m_aInputEvent.mnCursorFlags = 0; 3655 pThis->m_aInputEvent.mnDeltaStart = 0; 3656 pThis->m_aInputEvent.mbOnlyCursor = False; 3657 3658 pThis->m_aInputFlags = std::vector<sal_uInt16>( std::max( 1, (int)pThis->m_aInputEvent.maText.Len() ), 0 ); 3659 3660 PangoAttrIterator *iter = pango_attr_list_get_iterator (pAttrs); 3661 do 3662 { 3663 GSList *attr_list = NULL; 3664 GSList *tmp_list = NULL; 3665 gint start, end; 3666 guint sal_attr = 0; 3667 3668 pango_attr_iterator_range (iter, &start, &end); 3669 if (end == G_MAXINT) 3670 end = pText ? strlen (pText) : 0; 3671 if (end == start) 3672 continue; 3673 3674 start = g_utf8_pointer_to_offset (pText, pText + start); 3675 end = g_utf8_pointer_to_offset (pText, pText + end); 3676 3677 tmp_list = attr_list = pango_attr_iterator_get_attrs (iter); 3678 while (tmp_list) 3679 { 3680 PangoAttribute *pango_attr = (PangoAttribute *)(tmp_list->data); 3681 3682 switch (pango_attr->klass->type) 3683 { 3684 case PANGO_ATTR_BACKGROUND: 3685 sal_attr |= (SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT | SAL_EXTTEXTINPUT_CURSOR_INVISIBLE); 3686 break; 3687 case PANGO_ATTR_UNDERLINE: 3688 sal_attr |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE; 3689 break; 3690 case PANGO_ATTR_STRIKETHROUGH: 3691 sal_attr |= SAL_EXTTEXTINPUT_ATTR_REDTEXT; 3692 break; 3693 default: 3694 break; 3695 } 3696 pango_attribute_destroy (pango_attr); 3697 tmp_list = tmp_list->next; 3698 } 3699 if (sal_attr == 0) 3700 sal_attr |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE; 3701 g_slist_free (attr_list); 3702 3703 // Set the sal attributes on our text 3704 for (int i = start; i < end; i++) 3705 pThis->m_aInputFlags[i] |= sal_attr; 3706 } while (pango_attr_iterator_next (iter)); 3707 3708 pThis->m_aInputEvent.mpTextAttr = &pThis->m_aInputFlags[0]; 3709 3710 g_free( pText ); 3711 pango_attr_list_unref( pAttrs ); 3712 3713 GTK_YIELD_GRAB(); 3714 3715 vcl::DeletionListener aDel( pThis->m_pFrame ); 3716 3717 pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent); 3718 if( bEndPreedit && ! aDel.isDeleted() ) 3719 pThis->doCallEndExtTextInput(); 3720 if( ! aDel.isDeleted() ) 3721 pThis->updateIMSpotLocation(); 3722 } 3723 3724 void GtkSalFrame::IMHandler::signalIMPreeditStart( GtkIMContext*, gpointer /*im_handler*/ ) 3725 { 3726 } 3727 3728 void GtkSalFrame::IMHandler::signalIMPreeditEnd( GtkIMContext*, gpointer im_handler ) 3729 { 3730 GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler; 3731 GTK_YIELD_GRAB(); 3732 3733 pThis->m_bPreeditJustChanged = true; 3734 3735 vcl::DeletionListener aDel( pThis->m_pFrame ); 3736 pThis->doCallEndExtTextInput(); 3737 if( ! aDel.isDeleted() ) 3738 pThis->updateIMSpotLocation(); 3739 } 3740 3741 uno::Reference<accessibility::XAccessibleEditableText> 3742 FindFocus(uno::Reference< accessibility::XAccessibleContext > xContext) 3743 { 3744 if (!xContext.is()) 3745 uno::Reference< accessibility::XAccessibleEditableText >(); 3746 3747 uno::Reference<accessibility::XAccessibleStateSet> xState = xContext->getAccessibleStateSet(); 3748 if (xState.is()) 3749 { 3750 if (xState->contains(accessibility::AccessibleStateType::FOCUSED)) 3751 return uno::Reference<accessibility::XAccessibleEditableText>(xContext, uno::UNO_QUERY); 3752 } 3753 3754 try 3755 { 3756 for (sal_Int32 i = 0, n = xContext->getAccessibleChildCount(); i < n; ++i) 3757 { 3758 uno::Reference< accessibility::XAccessible > xChild = xContext->getAccessibleChild(i); 3759 if (!xChild.is()) 3760 continue; 3761 uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext(); 3762 if (!xChildContext.is()) 3763 continue; 3764 uno::Reference< accessibility::XAccessibleEditableText > xText = FindFocus(xChildContext); 3765 if (xText.is()) 3766 return xText; 3767 } 3768 } 3769 catch( lang::IndexOutOfBoundsException & e ) 3770 { 3771 OSL_TRACE( "GtkFrame FindFocus, %s", ::rtl::OUStringToOString( 3772 e.Message, RTL_TEXTENCODING_UTF8 ).pData->buffer ); 3773 } 3774 return uno::Reference< accessibility::XAccessibleEditableText >(); 3775 } 3776 3777 uno::Reference<accessibility::XAccessibleEditableText> lcl_GetxText() 3778 { 3779 uno::Reference<accessibility::XAccessibleEditableText> xText; 3780 Window* pFocusWin = ImplGetSVData()->maWinData.mpFocusWin; 3781 if (!pFocusWin) 3782 return xText; 3783 3784 uno::Reference< accessibility::XAccessible > xAccessible( pFocusWin->GetAccessible( true ) ); 3785 if (xAccessible.is()) 3786 xText = FindFocus(xAccessible->getAccessibleContext()); 3787 return xText; 3788 } 3789 3790 gboolean GtkSalFrame::IMHandler::signalIMRetrieveSurrounding( GtkIMContext* pContext, gpointer /*im_handler*/ ) 3791 { 3792 uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText(); 3793 3794 if (xText.is()) 3795 { 3796 sal_uInt32 nPosition = xText->getCaretPosition(); 3797 rtl::OUString sAllText = xText->getText(); 3798 if (!sAllText.getLength()) 3799 return sal_False; 3800 rtl::OString sUTF = rtl::OUStringToOString(sAllText, RTL_TEXTENCODING_UTF8); 3801 rtl::OUString sCursorText( sAllText.getStr(), nPosition); 3802 gtk_im_context_set_surrounding(pContext, sUTF.getStr(), sUTF.getLength(), 3803 rtl::OUStringToOString(sCursorText, RTL_TEXTENCODING_UTF8).getLength()); 3804 return sal_True; 3805 } 3806 3807 return sal_False; 3808 } 3809 3810 gboolean GtkSalFrame::IMHandler::signalIMDeleteSurrounding( GtkIMContext*, gint offset, gint nchars, 3811 gpointer /*im_handler*/ ) 3812 { 3813 uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText(); 3814 3815 if (xText.is()) 3816 { 3817 sal_uInt32 nPosition = xText->getCaretPosition(); 3818 // --> OD 2010-06-04 #i111768# - apply patch from kstribley: 3819 // range checking 3820 // xText->deleteText(nPosition + offset, nPosition + offset + nchars); 3821 sal_Int32 nDeletePos = nPosition + offset; 3822 sal_Int32 nDeleteEnd = nDeletePos + nchars; 3823 if (nDeletePos < 0) 3824 nDeletePos = 0; 3825 if (nDeleteEnd < 0) 3826 nDeleteEnd = 0; 3827 if (nDeleteEnd > xText->getCharacterCount()) 3828 nDeleteEnd = xText->getCharacterCount(); 3829 3830 xText->deleteText(nDeletePos, nDeleteEnd); 3831 // <-- 3832 return sal_True; 3833 } 3834 3835 return sal_False; 3836 } 3837