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 #define _SV_SALDATA_CXX 28 29 // -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 30 31 #include <unistd.h> 32 #include <fcntl.h> 33 34 #include <stdio.h> 35 #include <string.h> 36 #include <stdlib.h> 37 #include <limits.h> 38 #include <errno.h> 39 #include <poll.h> 40 #ifdef FREEBSD 41 #include <sys/types.h> 42 #include <sys/time.h> 43 #include <unistd.h> 44 #endif 45 #include <unx/gtk/gtkdata.hxx> 46 #include <unx/gtk/gtkinst.hxx> 47 #include <unx/gtk/gtkframe.hxx> 48 #include <unx/salobj.h> 49 #include <osl/thread.h> 50 #include <osl/process.h> 51 52 #include <tools/debug.hxx> 53 #include "unx/i18n_im.hxx" 54 #include "unx/i18n_xkb.hxx" 55 #include <unx/wmadaptor.hxx> 56 57 #include "unx/x11_cursors/salcursors.h" 58 59 #include <vcl/svapp.hxx> 60 61 using namespace rtl; 62 using namespace vcl_sal; 63 64 /*************************************************************************** 65 * class GtkDisplay * 66 ***************************************************************************/ 67 68 GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay ) 69 : SalDisplay( gdk_x11_display_get_xdisplay( pDisplay ) ), 70 m_pGdkDisplay( pDisplay ), 71 m_bStartupCompleted( false ) 72 { 73 m_bUseRandRWrapper = false; // use gdk signal instead 74 for(int i = 0; i < POINTER_COUNT; i++) 75 m_aCursors[ i ] = NULL; 76 Init (); 77 } 78 79 GtkSalDisplay::~GtkSalDisplay() 80 { 81 if( !m_bStartupCompleted ) 82 gdk_notify_startup_complete(); 83 doDestruct(); 84 85 for(int i = 0; i < POINTER_COUNT; i++) 86 if( m_aCursors[ i ] ) 87 gdk_cursor_unref( m_aCursors[ i ] ); 88 89 pDisp_ = NULL; 90 } 91 92 void GtkSalDisplay::deregisterFrame( SalFrame* pFrame ) 93 { 94 if( m_pCapture == pFrame ) 95 { 96 static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE ); 97 m_pCapture = NULL; 98 } 99 SalDisplay::deregisterFrame( pFrame ); 100 } 101 102 extern "C" { 103 GdkFilterReturn call_filterGdkEvent( GdkXEvent* sys_event, 104 GdkEvent* event, 105 gpointer data ) 106 { 107 return GtkSalDisplay::filterGdkEvent( sys_event, event, data ); 108 } 109 110 void signalKeysChanged( GdkKeymap*, gpointer data ) 111 { 112 GtkSalDisplay* pDisp = (GtkSalDisplay*)data; 113 pDisp->GetKeyboardName(TRUE); 114 } 115 116 void signalScreenSizeChanged( GdkScreen* pScreen, gpointer data ) 117 { 118 GtkSalDisplay* pDisp = (GtkSalDisplay*)data; 119 pDisp->screenSizeChanged( pScreen ); 120 } 121 122 void signalMonitorsChanged( GdkScreen* pScreen, gpointer data ) 123 { 124 GtkSalDisplay* pDisp = (GtkSalDisplay*)data; 125 pDisp->monitorsChanged( pScreen ); 126 } 127 128 } 129 130 GdkFilterReturn GtkSalDisplay::filterGdkEvent( GdkXEvent* sys_event, 131 GdkEvent*, 132 gpointer data ) 133 { 134 GdkFilterReturn aFilterReturn = GDK_FILTER_CONTINUE; 135 136 XEvent *pEvent = (XEvent *)sys_event; 137 GtkSalDisplay *pDisplay = (GtkSalDisplay *)data; 138 139 // dispatch all XEvents to event callback 140 if( GetSalData()->m_pInstance-> 141 CallEventCallback( pEvent, sizeof( XEvent ) ) ) 142 aFilterReturn = GDK_FILTER_REMOVE; 143 144 GTK_YIELD_GRAB(); 145 146 if (pDisplay->GetDisplay() == pEvent->xany.display ) 147 { 148 // #i53471# gtk has no callback mechanism that lets us be notified 149 // when settings (as in XSETTING and opposed to styles) are changed. 150 // so we need to listen for corresponding property notifications here 151 // these should be rare enough so that we can assume that the settings 152 // actually change when a corresponding PropertyNotify occurs 153 if( pEvent->type == PropertyNotify && 154 pEvent->xproperty.atom == pDisplay->getWMAdaptor()->getAtom( WMAdaptor::XSETTINGS ) && 155 ! pDisplay->m_aFrames.empty() 156 ) 157 { 158 pDisplay->SendInternalEvent( pDisplay->m_aFrames.front(), NULL, SALEVENT_SETTINGSCHANGED ); 159 } 160 // let's see if one of our frames wants to swallow these events 161 // get the frame 162 for( std::list< SalFrame* >::const_iterator it = pDisplay->m_aFrames.begin(); 163 it != pDisplay->m_aFrames.end(); ++it ) 164 { 165 GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(*it); 166 if( (GdkNativeWindow)pFrame->GetSystemData()->aWindow == pEvent->xany.window || 167 ( pFrame->getForeignParent() && pFrame->getForeignParentWindow() == pEvent->xany.window ) || 168 ( pFrame->getForeignTopLevel() && pFrame->getForeignTopLevelWindow() == pEvent->xany.window ) 169 ) 170 { 171 if( ! pFrame->Dispatch( pEvent ) ) 172 aFilterReturn = GDK_FILTER_REMOVE; 173 break; 174 } 175 } 176 X11SalObject::Dispatch( pEvent ); 177 } 178 179 return aFilterReturn; 180 } 181 182 void GtkSalDisplay::screenSizeChanged( GdkScreen* pScreen ) 183 { 184 if( pScreen ) 185 { 186 int nScreen = gdk_screen_get_number( pScreen ); 187 if( nScreen < static_cast<int>(m_aScreens.size()) ) 188 { 189 ScreenData& rSD = const_cast<ScreenData&>(m_aScreens[nScreen]); 190 if( rSD.m_bInit ) 191 { 192 rSD.m_aSize = Size( gdk_screen_get_width( pScreen ), 193 gdk_screen_get_height( pScreen ) ); 194 if( ! m_aFrames.empty() ) 195 m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 ); 196 } 197 } 198 else 199 { 200 DBG_ERROR( "unknown screen changed size" ); 201 } 202 } 203 } 204 205 void GtkSalDisplay::monitorsChanged( GdkScreen* pScreen ) 206 { 207 /* Caution: since we support the _NET_WM_FULLSCREEN_MONITORS property now and 208 the EWMH spec says, the index used for that needs to be that of the 209 Xinerama extension, we need to ensure that the order of m_aXineramaScreens is actually intact. 210 211 gdk_screen_get_monitor_geometry however has a different sort order that has a default monitor number 212 Xinerama returns the default monitor as 0. 213 That means if we fill in the multiple montors vector from gdk, we'll get the wrong order unless 214 the default monitor is incidentally the same (number 0). 215 216 Given that XRandR (which is what gdk_screen_get_monitor_geometry is based on) is 217 supposed to replace Xinerama, this is bound to get a problem at some time again, 218 unfortunately there does not currently seem to be a way to map the returns of xinerama to 219 that of randr. Currently getting Xinerama values again works with updated values, given 220 a new enough Xserver. 221 */ 222 InitXinerama(); 223 (void)pScreen; 224 225 #if 0 226 if( pScreen ) 227 { 228 if( gdk_display_get_n_screens(m_pGdkDisplay) == 1 ) 229 { 230 int nScreen = gdk_screen_get_number( pScreen ); 231 if( nScreen == m_nDefaultScreen ) //To-Do, make m_aXineramaScreens a per-screen thing ? 232 { 233 gint nMonitors = gdk_screen_get_n_monitors(pScreen); 234 m_aXineramaScreens = std::vector<Rectangle>(); 235 m_aXineramaScreenIndexMap = std::vector<int>(nMonitors); 236 for (gint i = 0; i < nMonitors; ++i) 237 { 238 GdkRectangle dest; 239 gdk_screen_get_monitor_geometry(pScreen, i, &dest); 240 m_aXineramaScreenIndexMap[i] = addXineramaScreenUnique( dest.x, dest.y, dest.width, dest.height ); 241 } 242 m_bXinerama = m_aXineramaScreens.size() > 1; 243 if( ! m_aFrames.empty() ) 244 m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 ); 245 } 246 else 247 { 248 DBG_ERROR( "monitors for non-default screen changed, extend-me" ); 249 } 250 } 251 } 252 #endif 253 } 254 255 extern "C" 256 { 257 typedef gint(* screen_get_primary_monitor)(GdkScreen *screen); 258 } 259 260 int GtkSalDisplay::GetDefaultMonitorNumber() const 261 { 262 int n = 0; 263 264 // currently disabled, see remarks in monitorsChanged 265 #if 0 266 GdkScreen* pScreen = gdk_display_get_screen( m_pGdkDisplay, m_nDefaultScreen ); 267 #if GTK_CHECK_VERSION(2,20,0) 268 n = gdk_screen_get_primary_monitor(pScreen); 269 #else 270 static screen_get_primary_monitor sym_gdk_screen_get_primary_monitor = 271 (screen_get_primary_monitor)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_screen_get_primary_monitor" ); 272 if (sym_gdk_screen_get_primary_monitor) 273 n = sym_gdk_screen_get_primary_monitor( pScreen ); 274 #endif 275 if( n >= 0 && size_t(n) < m_aXineramaScreenIndexMap.size() ) 276 n = m_aXineramaScreenIndexMap[n]; 277 #endif 278 return n; 279 } 280 281 void GtkSalDisplay::initScreen( int nScreen ) const 282 { 283 if( nScreen < 0 || nScreen >= static_cast<int>(m_aScreens.size()) ) 284 nScreen = m_nDefaultScreen; 285 ScreenData& rSD = const_cast<ScreenData&>(m_aScreens[nScreen]); 286 if( rSD.m_bInit ) 287 return; 288 289 // choose visual for screen 290 SalDisplay::initScreen( nScreen ); 291 // now set a gdk default colormap matching the chosen visual to the screen 292 GdkVisual* pVis = gdkx_visual_get( rSD.m_aVisual.visualid ); 293 GdkScreen* pScreen = gdk_display_get_screen( m_pGdkDisplay, nScreen ); 294 if( pVis ) 295 { 296 GdkColormap* pDefCol = gdk_screen_get_default_colormap( pScreen ); 297 GdkVisual* pDefVis = gdk_colormap_get_visual( pDefCol ); 298 if( pDefVis != pVis ) 299 { 300 pDefCol = gdk_x11_colormap_foreign_new( pVis, rSD.m_aColormap.GetXColormap() ); 301 gdk_screen_set_default_colormap( pScreen, pDefCol ); 302 #if OSL_DEBUG_LEVEL > 1 303 fprintf( stderr, "set new gdk color map for screen %d\n", nScreen ); 304 #endif 305 } 306 } 307 #if OSL_DEBUG_LEVEL > 1 308 else 309 fprintf( stderr, "not GdkVisual for visual id %d\n", (int)rSD.m_aVisual.visualid ); 310 #endif 311 } 312 313 long GtkSalDisplay::Dispatch( XEvent* pEvent ) 314 { 315 if( GetDisplay() == pEvent->xany.display ) 316 { 317 // let's see if one of our frames wants to swallow these events 318 // get the child frame 319 for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin(); 320 it != m_aFrames.end(); ++it ) 321 { 322 if( (GdkNativeWindow)(*it)->GetSystemData()->aWindow == pEvent->xany.window ) 323 return static_cast<GtkSalFrame*>(*it)->Dispatch( pEvent ); 324 } 325 } 326 327 return GDK_FILTER_CONTINUE; 328 } 329 330 GdkCursor* GtkSalDisplay::getFromXPM( const char *pBitmap, 331 const char *pMask, 332 int nWidth, int nHeight, 333 int nXHot, int nYHot ) 334 { 335 GdkScreen *pScreen = gdk_display_get_default_screen( m_pGdkDisplay ); 336 GdkDrawable *pDrawable = GDK_DRAWABLE( gdk_screen_get_root_window (pScreen) ); 337 GdkBitmap *pBitmapPix = gdk_bitmap_create_from_data 338 ( pDrawable, pBitmap, nWidth, nHeight ); 339 GdkBitmap *pMaskPix = gdk_bitmap_create_from_data 340 ( pDrawable, pMask, nWidth, nHeight ); 341 GdkColormap *pColormap = gdk_drawable_get_colormap( pDrawable ); 342 343 GdkColor aWhite = { 0, 0xffff, 0xffff, 0xffff }; 344 GdkColor aBlack = { 0, 0, 0, 0 }; 345 346 gdk_colormap_alloc_color( pColormap, &aBlack, FALSE, TRUE); 347 gdk_colormap_alloc_color( pColormap, &aWhite, FALSE, TRUE); 348 349 return gdk_cursor_new_from_pixmap 350 ( pBitmapPix, pMaskPix, 351 &aBlack, &aWhite, nXHot, nYHot); 352 } 353 354 #define MAKE_CURSOR( vcl_name, name ) \ 355 case vcl_name: \ 356 pCursor = getFromXPM( name##curs##_bits, name##mask##_bits, \ 357 name##curs_width, name##curs_height, \ 358 name##curs_x_hot, name##curs_y_hot ); \ 359 break 360 #define MAP_BUILTIN( vcl_name, gdk_name ) \ 361 case vcl_name: \ 362 pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, gdk_name ); \ 363 break 364 365 GdkCursor *GtkSalDisplay::getCursor( PointerStyle ePointerStyle ) 366 { 367 if( ePointerStyle > POINTER_COUNT ) 368 return NULL; 369 370 if ( !m_aCursors[ ePointerStyle ] ) 371 { 372 GdkCursor *pCursor = NULL; 373 374 switch( ePointerStyle ) 375 { 376 MAP_BUILTIN( POINTER_ARROW, GDK_LEFT_PTR ); 377 MAP_BUILTIN( POINTER_TEXT, GDK_XTERM ); 378 MAP_BUILTIN( POINTER_HELP, GDK_QUESTION_ARROW ); 379 MAP_BUILTIN( POINTER_CROSS, GDK_CROSSHAIR ); 380 MAP_BUILTIN( POINTER_WAIT, GDK_WATCH ); 381 382 MAP_BUILTIN( POINTER_NSIZE, GDK_SB_V_DOUBLE_ARROW ); 383 MAP_BUILTIN( POINTER_SSIZE, GDK_SB_V_DOUBLE_ARROW ); 384 MAP_BUILTIN( POINTER_WSIZE, GDK_SB_H_DOUBLE_ARROW ); 385 MAP_BUILTIN( POINTER_ESIZE, GDK_SB_H_DOUBLE_ARROW ); 386 387 MAP_BUILTIN( POINTER_NWSIZE, GDK_TOP_LEFT_CORNER ); 388 MAP_BUILTIN( POINTER_NESIZE, GDK_TOP_RIGHT_CORNER ); 389 MAP_BUILTIN( POINTER_SWSIZE, GDK_BOTTOM_LEFT_CORNER ); 390 MAP_BUILTIN( POINTER_SESIZE, GDK_BOTTOM_RIGHT_CORNER ); 391 392 MAP_BUILTIN( POINTER_WINDOW_NSIZE, GDK_TOP_SIDE ); 393 MAP_BUILTIN( POINTER_WINDOW_SSIZE, GDK_BOTTOM_SIDE ); 394 MAP_BUILTIN( POINTER_WINDOW_WSIZE, GDK_LEFT_SIDE ); 395 MAP_BUILTIN( POINTER_WINDOW_ESIZE, GDK_RIGHT_SIDE ); 396 397 MAP_BUILTIN( POINTER_WINDOW_NWSIZE, GDK_TOP_LEFT_CORNER ); 398 MAP_BUILTIN( POINTER_WINDOW_NESIZE, GDK_TOP_RIGHT_CORNER ); 399 MAP_BUILTIN( POINTER_WINDOW_SWSIZE, GDK_BOTTOM_LEFT_CORNER ); 400 MAP_BUILTIN( POINTER_WINDOW_SESIZE, GDK_BOTTOM_RIGHT_CORNER ); 401 402 MAP_BUILTIN( POINTER_HSIZEBAR, GDK_SB_H_DOUBLE_ARROW ); 403 MAP_BUILTIN( POINTER_VSIZEBAR, GDK_SB_V_DOUBLE_ARROW ); 404 405 MAP_BUILTIN( POINTER_REFHAND, GDK_HAND1 ); 406 MAP_BUILTIN( POINTER_HAND, GDK_HAND2 ); 407 MAP_BUILTIN( POINTER_PEN, GDK_PENCIL ); 408 409 MAP_BUILTIN( POINTER_HSPLIT, GDK_SB_H_DOUBLE_ARROW ); 410 MAP_BUILTIN( POINTER_VSPLIT, GDK_SB_V_DOUBLE_ARROW ); 411 412 MAP_BUILTIN( POINTER_MOVE, GDK_FLEUR ); 413 414 MAKE_CURSOR( POINTER_NULL, null ); 415 MAKE_CURSOR( POINTER_MAGNIFY, magnify_ ); 416 MAKE_CURSOR( POINTER_FILL, fill_ ); 417 MAKE_CURSOR( POINTER_MOVEDATA, movedata_ ); 418 MAKE_CURSOR( POINTER_COPYDATA, copydata_ ); 419 MAKE_CURSOR( POINTER_MOVEFILE, movefile_ ); 420 MAKE_CURSOR( POINTER_COPYFILE, copyfile_ ); 421 MAKE_CURSOR( POINTER_MOVEFILES, movefiles_ ); 422 MAKE_CURSOR( POINTER_COPYFILES, copyfiles_ ); 423 MAKE_CURSOR( POINTER_NOTALLOWED, nodrop_ ); 424 MAKE_CURSOR( POINTER_ROTATE, rotate_ ); 425 MAKE_CURSOR( POINTER_HSHEAR, hshear_ ); 426 MAKE_CURSOR( POINTER_VSHEAR, vshear_ ); 427 MAKE_CURSOR( POINTER_DRAW_LINE, drawline_ ); 428 MAKE_CURSOR( POINTER_DRAW_RECT, drawrect_ ); 429 MAKE_CURSOR( POINTER_DRAW_POLYGON, drawpolygon_ ); 430 MAKE_CURSOR( POINTER_DRAW_BEZIER, drawbezier_ ); 431 MAKE_CURSOR( POINTER_DRAW_ARC, drawarc_ ); 432 MAKE_CURSOR( POINTER_DRAW_PIE, drawpie_ ); 433 MAKE_CURSOR( POINTER_DRAW_CIRCLECUT, drawcirclecut_ ); 434 MAKE_CURSOR( POINTER_DRAW_ELLIPSE, drawellipse_ ); 435 MAKE_CURSOR( POINTER_DRAW_CONNECT, drawconnect_ ); 436 MAKE_CURSOR( POINTER_DRAW_TEXT, drawtext_ ); 437 MAKE_CURSOR( POINTER_MIRROR, mirror_ ); 438 MAKE_CURSOR( POINTER_CROOK, crook_ ); 439 MAKE_CURSOR( POINTER_CROP, crop_ ); 440 MAKE_CURSOR( POINTER_MOVEPOINT, movepoint_ ); 441 MAKE_CURSOR( POINTER_MOVEBEZIERWEIGHT, movebezierweight_ ); 442 MAKE_CURSOR( POINTER_DRAW_FREEHAND, drawfreehand_ ); 443 MAKE_CURSOR( POINTER_DRAW_CAPTION, drawcaption_ ); 444 MAKE_CURSOR( POINTER_LINKDATA, linkdata_ ); 445 MAKE_CURSOR( POINTER_MOVEDATALINK, movedlnk_ ); 446 MAKE_CURSOR( POINTER_COPYDATALINK, copydlnk_ ); 447 MAKE_CURSOR( POINTER_LINKFILE, linkfile_ ); 448 MAKE_CURSOR( POINTER_MOVEFILELINK, moveflnk_ ); 449 MAKE_CURSOR( POINTER_COPYFILELINK, copyflnk_ ); 450 MAKE_CURSOR( POINTER_CHART, chart_ ); 451 MAKE_CURSOR( POINTER_DETECTIVE, detective_ ); 452 MAKE_CURSOR( POINTER_PIVOT_COL, pivotcol_ ); 453 MAKE_CURSOR( POINTER_PIVOT_ROW, pivotrow_ ); 454 MAKE_CURSOR( POINTER_PIVOT_FIELD, pivotfld_ ); 455 MAKE_CURSOR( POINTER_PIVOT_DELETE, pivotdel_ ); 456 MAKE_CURSOR( POINTER_CHAIN, chain_ ); 457 MAKE_CURSOR( POINTER_CHAIN_NOTALLOWED, chainnot_ ); 458 MAKE_CURSOR( POINTER_TIMEEVENT_MOVE, timemove_ ); 459 MAKE_CURSOR( POINTER_TIMEEVENT_SIZE, timesize_ ); 460 MAKE_CURSOR( POINTER_AUTOSCROLL_N, asn_ ); 461 MAKE_CURSOR( POINTER_AUTOSCROLL_S, ass_ ); 462 MAKE_CURSOR( POINTER_AUTOSCROLL_W, asw_ ); 463 MAKE_CURSOR( POINTER_AUTOSCROLL_E, ase_ ); 464 MAKE_CURSOR( POINTER_AUTOSCROLL_NW, asnw_ ); 465 MAKE_CURSOR( POINTER_AUTOSCROLL_NE, asne_ ); 466 MAKE_CURSOR( POINTER_AUTOSCROLL_SW, assw_ ); 467 MAKE_CURSOR( POINTER_AUTOSCROLL_SE, asse_ ); 468 MAKE_CURSOR( POINTER_AUTOSCROLL_NS, asns_ ); 469 MAKE_CURSOR( POINTER_AUTOSCROLL_WE, aswe_ ); 470 MAKE_CURSOR( POINTER_AUTOSCROLL_NSWE, asnswe_ ); 471 MAKE_CURSOR( POINTER_AIRBRUSH, airbrush_ ); 472 MAKE_CURSOR( POINTER_TEXT_VERTICAL, vertcurs_ ); 473 474 // --> FME 2004-07-30 #i32329# Enhanced table selection 475 MAKE_CURSOR( POINTER_TAB_SELECT_S, tblsels_ ); 476 MAKE_CURSOR( POINTER_TAB_SELECT_E, tblsele_ ); 477 MAKE_CURSOR( POINTER_TAB_SELECT_SE, tblselse_ ); 478 MAKE_CURSOR( POINTER_TAB_SELECT_W, tblselw_ ); 479 MAKE_CURSOR( POINTER_TAB_SELECT_SW, tblselsw_ ); 480 // <-- 481 482 // --> FME 2004-08-16 #i20119# Paintbrush tool 483 MAKE_CURSOR( POINTER_PAINTBRUSH, paintbrush_ ); 484 // <-- 485 486 default: 487 fprintf( stderr, "pointer %d not implemented", ePointerStyle ); 488 break; 489 } 490 if( !pCursor ) 491 pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, GDK_LEFT_PTR ); 492 493 m_aCursors[ ePointerStyle ] = pCursor; 494 } 495 496 return m_aCursors[ ePointerStyle ]; 497 } 498 499 int GtkSalDisplay::CaptureMouse( SalFrame* pSFrame ) 500 { 501 GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(pSFrame); 502 503 if( !pFrame ) 504 { 505 if( m_pCapture ) 506 static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE ); 507 m_pCapture = NULL; 508 return 0; 509 } 510 511 if( m_pCapture ) 512 { 513 if( pFrame == m_pCapture ) 514 return 1; 515 static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE ); 516 } 517 518 m_pCapture = pFrame; 519 static_cast<GtkSalFrame*>(pFrame)->grabPointer( TRUE ); 520 return 1; 521 } 522 523 /*************************************************************************** 524 * class GtkXLib * 525 ***************************************************************************/ 526 527 class GtkXLib : public SalXLib 528 { 529 GtkSalDisplay *m_pGtkSalDisplay; 530 std::list<GSource *> m_aSources; 531 GSource *m_pTimeout; 532 GSource *m_pUserEvent; 533 oslMutex m_aDispatchMutex; 534 oslCondition m_aDispatchCondition; 535 XIOErrorHandler m_aOrigGTKXIOErrorHandler; 536 537 public: 538 static gboolean timeoutFn(gpointer data); 539 static gboolean userEventFn(gpointer data); 540 541 GtkXLib(); 542 virtual ~GtkXLib(); 543 544 virtual void Init(); 545 virtual void Yield( bool bWait, bool bHandleAllCurrentEvents ); 546 virtual void Insert( int fd, void* data, 547 YieldFunc pending, 548 YieldFunc queued, 549 YieldFunc handle ); 550 virtual void Remove( int fd ); 551 552 virtual void StartTimer( sal_uLong nMS ); 553 virtual void StopTimer(); 554 virtual void Wakeup(); 555 virtual void PostUserEvent(); 556 }; 557 558 GtkXLib::GtkXLib() 559 { 560 #if OSL_DEBUG_LEVEL > 1 561 fprintf( stderr, "GtkXLib::GtkXLib()\n" ); 562 #endif 563 m_pGtkSalDisplay = NULL; 564 m_pTimeout = NULL; 565 m_nTimeoutMS = 0; 566 m_pUserEvent = NULL; 567 m_aDispatchCondition = osl_createCondition(); 568 m_aDispatchMutex = osl_createMutex(); 569 m_aOrigGTKXIOErrorHandler = NULL; 570 } 571 572 GtkXLib::~GtkXLib() 573 { 574 #if OSL_DEBUG_LEVEL > 1 575 fprintf( stderr, "GtkXLib::~GtkXLib()\n" ); 576 #endif 577 StopTimer(); 578 // sanity check: at this point nobody should be yielding, but wake them 579 // up anyway before the condition they're waiting on gets destroyed. 580 osl_setCondition( m_aDispatchCondition ); 581 osl_destroyCondition( m_aDispatchCondition ); 582 osl_destroyMutex( m_aDispatchMutex ); 583 584 PopXErrorLevel(); 585 XSetIOErrorHandler (m_aOrigGTKXIOErrorHandler); 586 } 587 588 void GtkXLib::Init() 589 { 590 int i; 591 #if OSL_DEBUG_LEVEL > 1 592 fprintf( stderr, "GtkXLib::Init()\n" ); 593 #endif 594 XrmInitialize(); 595 596 gtk_set_locale(); 597 598 /* 599 * open connection to X11 Display 600 * try in this order: 601 * o -display command line parameter, 602 * o $DISPLAY environment variable 603 * o default display 604 */ 605 606 GdkDisplay *pGdkDisp = NULL; 607 608 // is there a -display command line parameter? 609 rtl_TextEncoding aEnc = osl_getThreadTextEncoding(); 610 int nParams = osl_getCommandArgCount(); 611 rtl::OString aDisplay; 612 rtl::OUString aParam, aBin; 613 char** pCmdLineAry = new char*[ nParams+1 ]; 614 osl_getExecutableFile( &aParam.pData ); 615 osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData ); 616 pCmdLineAry[0] = g_strdup( OUStringToOString( aBin, aEnc ).getStr() ); 617 for (i=0; i<nParams; i++) 618 { 619 osl_getCommandArg(i, &aParam.pData ); 620 OString aBParam( OUStringToOString( aParam, aEnc ) ); 621 622 if( aParam.equalsAscii( "-display" ) || aParam.equalsAscii( "--display" ) ) 623 { 624 pCmdLineAry[i+1] = g_strdup( "--display" ); 625 osl_getCommandArg(i+1, &aParam.pData ); 626 aDisplay = rtl::OUStringToOString( aParam, aEnc ); 627 } 628 else 629 pCmdLineAry[i+1] = g_strdup( aBParam.getStr() ); 630 } 631 // add executable 632 nParams++; 633 634 g_set_application_name(X11SalData::getFrameClassName()); 635 636 // Set consistant name of the root accessible 637 rtl::OUString aAppName = Application::GetAppName(); 638 if( aAppName.getLength() > 0 ) 639 { 640 rtl::OString aPrgName = rtl::OUStringToOString(aAppName, aEnc); 641 g_set_prgname(aPrgName); 642 } 643 644 // init gtk/gdk 645 gtk_init_check( &nParams, &pCmdLineAry ); 646 647 //gtk_init_check sets XError/XIOError handlers, we want our own one 648 m_aOrigGTKXIOErrorHandler = XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl ); 649 PushXErrorLevel( !!getenv( "SAL_IGNOREXERRORS" ) ); 650 651 for (i = 0; i < nParams; i++ ) 652 g_free( pCmdLineAry[i] ); 653 delete [] pCmdLineAry; 654 655 #if OSL_DEBUG_LEVEL > 1 656 if (g_getenv ("SAL_DEBUG_UPDATES")) 657 gdk_window_set_debug_updates (TRUE); 658 #endif 659 660 pGdkDisp = gdk_display_get_default(); 661 if ( !pGdkDisp ) 662 { 663 rtl::OUString aProgramFileURL; 664 osl_getExecutableFile( &aProgramFileURL.pData ); 665 rtl::OUString aProgramSystemPath; 666 osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData); 667 rtl::OString aProgramName = rtl::OUStringToOString( 668 aProgramSystemPath, 669 osl_getThreadTextEncoding() ); 670 fprintf( stderr, "%s X11 error: Can't open display: %s\n", 671 aProgramName.getStr(), aDisplay.getStr()); 672 fprintf( stderr, " Set DISPLAY environment variable, use -display option\n"); 673 fprintf( stderr, " or check permissions of your X-Server\n"); 674 fprintf( stderr, " (See \"man X\" resp. \"man xhost\" for details)\n"); 675 fflush( stderr ); 676 exit(0); 677 } 678 679 /* 680 * if a -display switch was used, we need 681 * to set the environment accoringly since 682 * the clipboard build another connection 683 * to the xserver using $DISPLAY 684 */ 685 rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("DISPLAY")); 686 const gchar *name = gdk_display_get_name( pGdkDisp ); 687 rtl::OUString envValue(name, strlen(name), aEnc); 688 osl_setEnvironment(envVar.pData, envValue.pData); 689 690 Display *pDisp = gdk_x11_display_get_xdisplay( pGdkDisp ); 691 692 m_pGtkSalDisplay = new GtkSalDisplay( pGdkDisp ); 693 694 gdk_window_add_filter( NULL, call_filterGdkEvent, m_pGtkSalDisplay ); 695 696 PushXErrorLevel( true ); 697 SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp ); 698 XSync( pDisp, False ); 699 700 pKbdExtension->UseExtension( ! HasXErrorOccured() ); 701 PopXErrorLevel(); 702 703 m_pGtkSalDisplay->SetKbdExtension( pKbdExtension ); 704 705 g_signal_connect( G_OBJECT(gdk_keymap_get_default()), "keys_changed", G_CALLBACK(signalKeysChanged), m_pGtkSalDisplay ); 706 707 // add signal handler to notify screen size changes 708 int nScreens = gdk_display_get_n_screens( pGdkDisp ); 709 for( int n = 0; n < nScreens; n++ ) 710 { 711 GdkScreen *pScreen = gdk_display_get_screen( pGdkDisp, n ); 712 if( pScreen ) 713 { 714 g_signal_connect( G_OBJECT(pScreen), "size-changed", G_CALLBACK(signalScreenSizeChanged), m_pGtkSalDisplay ); 715 if( ! gtk_check_version( 2, 14, 0 ) ) // monitors-changed came in with 2.14, avoid an assertion 716 g_signal_connect( G_OBJECT(pScreen), "monitors-changed", G_CALLBACK(signalMonitorsChanged), m_pGtkSalDisplay ); 717 } 718 } 719 } 720 721 extern "C" 722 { 723 gboolean call_timeoutFn(gpointer data) 724 { 725 return GtkXLib::timeoutFn(data); 726 } 727 } 728 729 gboolean GtkXLib::timeoutFn(gpointer data) 730 { 731 SalData *pSalData = GetSalData(); 732 GtkXLib *pThis = (GtkXLib *) data; 733 734 pSalData->m_pInstance->GetYieldMutex()->acquire(); 735 736 if( pThis->m_pTimeout ) 737 { 738 g_source_unref (pThis->m_pTimeout); 739 pThis->m_pTimeout = NULL; 740 } 741 742 // Auto-restart immediately 743 pThis->StartTimer( pThis->m_nTimeoutMS ); 744 745 GetX11SalData()->Timeout(); 746 747 pSalData->m_pInstance->GetYieldMutex()->release(); 748 749 return FALSE; 750 } 751 752 void GtkXLib::StartTimer( sal_uLong nMS ) 753 { 754 m_nTimeoutMS = nMS; // for restarting 755 756 if (m_pTimeout) 757 { 758 g_source_destroy (m_pTimeout); 759 g_source_unref (m_pTimeout); 760 } 761 762 m_pTimeout = g_timeout_source_new (m_nTimeoutMS); 763 // #i36226# timers should be executed with lower priority 764 // than XEvents like in generic plugin 765 g_source_set_priority( m_pTimeout, G_PRIORITY_LOW ); 766 g_source_set_can_recurse (m_pTimeout, TRUE); 767 g_source_set_callback (m_pTimeout, call_timeoutFn, 768 (gpointer) this, NULL); 769 g_source_attach (m_pTimeout, g_main_context_default ()); 770 771 SalXLib::StartTimer( nMS ); 772 } 773 774 void GtkXLib::StopTimer() 775 { 776 SalXLib::StopTimer(); 777 778 if (m_pTimeout) 779 { 780 g_source_destroy (m_pTimeout); 781 g_source_unref (m_pTimeout); 782 m_pTimeout = NULL; 783 } 784 } 785 786 extern "C" 787 { 788 gboolean call_userEventFn( gpointer data ) 789 { 790 return GtkXLib::userEventFn( data ); 791 } 792 } 793 794 gboolean GtkXLib::userEventFn(gpointer data) 795 { 796 gboolean bContinue; 797 GtkXLib *pThis = (GtkXLib *) data; 798 SalData *pSalData = GetSalData(); 799 800 pSalData->m_pInstance->GetYieldMutex()->acquire(); 801 pThis->m_pGtkSalDisplay->EventGuardAcquire(); 802 803 if( !pThis->m_pGtkSalDisplay->HasMoreEvents() ) 804 { 805 if( pThis->m_pUserEvent ) 806 { 807 g_source_unref (pThis->m_pUserEvent); 808 pThis->m_pUserEvent = NULL; 809 } 810 bContinue = FALSE; 811 } 812 else 813 bContinue = TRUE; 814 815 pThis->m_pGtkSalDisplay->EventGuardRelease(); 816 817 pThis->m_pGtkSalDisplay->DispatchInternalEvent(); 818 819 pSalData->m_pInstance->GetYieldMutex()->release(); 820 821 return bContinue; 822 } 823 824 // hEventGuard_ held during this invocation 825 void GtkXLib::PostUserEvent() 826 { 827 if( !m_pUserEvent ) // not pending anyway 828 { 829 m_pUserEvent = g_idle_source_new(); 830 g_source_set_priority( m_pUserEvent, G_PRIORITY_HIGH ); 831 g_source_set_can_recurse (m_pUserEvent, TRUE); 832 g_source_set_callback (m_pUserEvent, call_userEventFn, 833 (gpointer) this, NULL); 834 g_source_attach (m_pUserEvent, g_main_context_default ()); 835 } 836 Wakeup(); 837 } 838 839 void GtkXLib::Wakeup() 840 { 841 g_main_context_wakeup( g_main_context_default () ); 842 } 843 844 void GtkXLib::Yield( bool bWait, bool bHandleAllCurrentEvents ) 845 { 846 /* #i33212# only enter g_main_context_iteration in one thread at any one 847 * time, else one of them potentially will never end as long as there is 848 * another thread in in there. Having only one yieldin thread actually dispatch 849 * fits the vcl event model (see e.g. the generic plugin). 850 */ 851 852 bool bDispatchThread = false; 853 gboolean wasEvent = FALSE; 854 { 855 // release YieldMutex (and re-acquire at block end) 856 YieldMutexReleaser aReleaser; 857 if( osl_tryToAcquireMutex( m_aDispatchMutex ) ) 858 bDispatchThread = true; 859 else if( ! bWait ) 860 return; // someone else is waiting already, return 861 862 863 if( bDispatchThread ) 864 { 865 int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1; 866 gboolean wasOneEvent = TRUE; 867 while( nMaxEvents-- && wasOneEvent ) 868 { 869 wasOneEvent = g_main_context_iteration( NULL, FALSE ); 870 if( wasOneEvent ) 871 wasEvent = TRUE; 872 } 873 if( bWait && ! wasEvent ) 874 wasEvent = g_main_context_iteration( NULL, TRUE ); 875 } 876 else if( bWait ) 877 { 878 /* #i41693# in case the dispatch thread hangs in join 879 * for this thread the condition will never be set 880 * workaround: timeout of 1 second a emergency exit 881 */ 882 // we are the dispatch thread 883 osl_resetCondition( m_aDispatchCondition ); 884 TimeValue aValue = { 1, 0 }; 885 osl_waitCondition( m_aDispatchCondition, &aValue ); 886 } 887 } 888 889 if( bDispatchThread ) 890 { 891 osl_releaseMutex( m_aDispatchMutex ); 892 if( wasEvent ) 893 osl_setCondition( m_aDispatchCondition ); // trigger non dispatch thread yields 894 } 895 } 896 897 extern "C" { 898 899 typedef struct { 900 GSource source; 901 902 GPollFD pollfd; 903 GIOCondition condition; 904 905 YieldFunc pending; 906 YieldFunc handle; 907 gpointer user_data; 908 } SalWatch; 909 910 static gboolean 911 sal_source_prepare (GSource *source, 912 gint *timeout) 913 { 914 SalWatch *watch = (SalWatch *)source; 915 916 *timeout = -1; 917 918 if (watch->pending && 919 watch->pending (watch->pollfd.fd, watch->user_data)) { 920 watch->pollfd.revents |= watch->condition; 921 return TRUE; 922 } 923 924 return FALSE; 925 } 926 927 static gboolean 928 sal_source_check (GSource *source) 929 { 930 SalWatch *watch = (SalWatch *)source; 931 932 return watch->pollfd.revents & watch->condition; 933 } 934 935 static gboolean 936 sal_source_dispatch (GSource *source, 937 GSourceFunc, 938 gpointer) 939 { 940 SalData *pSalData = GetSalData(); 941 SalWatch *watch = (SalWatch *) source; 942 943 pSalData->m_pInstance->GetYieldMutex()->acquire(); 944 945 watch->handle (watch->pollfd.fd, watch->user_data); 946 947 pSalData->m_pInstance->GetYieldMutex()->release(); 948 949 return TRUE; 950 } 951 952 static void 953 sal_source_finalize (GSource*) 954 { 955 } 956 957 static GSourceFuncs sal_source_watch_funcs = { 958 sal_source_prepare, 959 sal_source_check, 960 sal_source_dispatch, 961 sal_source_finalize, 962 NULL, 963 NULL 964 }; 965 966 static GSource * 967 sal_source_create_watch (int fd, 968 GIOCondition condition, 969 YieldFunc pending, 970 YieldFunc handle, 971 gpointer user_data) 972 { 973 GSource *source; 974 SalWatch *watch; 975 GMainContext *context = g_main_context_default (); 976 977 source = g_source_new (&sal_source_watch_funcs, 978 sizeof (SalWatch)); 979 watch = (SalWatch *) source; 980 981 watch->pollfd.fd = fd; 982 watch->pollfd.events = condition; 983 watch->condition = condition; 984 watch->pending = pending; 985 watch->handle = handle; 986 watch->user_data = user_data; 987 988 g_source_set_can_recurse (source, TRUE); 989 g_source_add_poll (source, &watch->pollfd); 990 g_source_attach (source, context); 991 992 return source; 993 } 994 995 } // extern "C" 996 997 void GtkXLib::Insert( int nFD, 998 void *data, 999 YieldFunc pending, 1000 YieldFunc, 1001 YieldFunc handle ) 1002 { 1003 GSource *source = sal_source_create_watch 1004 ( nFD, (GIOCondition) ((G_IO_IN|G_IO_PRI) | 1005 (G_IO_ERR|G_IO_HUP|G_IO_NVAL)), 1006 pending, handle, data ); 1007 m_aSources.push_back( source ); 1008 } 1009 1010 void GtkXLib::Remove( int nFD ) 1011 { 1012 ::std::list< GSource * >::iterator it; 1013 1014 for (it = m_aSources.begin(); it != m_aSources.end(); ++it) 1015 { 1016 SalWatch *watch = (SalWatch *) *it; 1017 1018 if (watch->pollfd.fd == nFD) 1019 { 1020 m_aSources.erase( it ); 1021 1022 g_source_destroy ((GSource *)watch); 1023 g_source_unref ((GSource *)watch); 1024 return; 1025 } 1026 } 1027 } 1028 1029 /********************************************************************** 1030 * class GtkData * 1031 **********************************************************************/ 1032 1033 GtkData::~GtkData() 1034 { 1035 } 1036 1037 void GtkData::Init() 1038 { 1039 pXLib_ = new GtkXLib(); 1040 pXLib_->Init(); 1041 } 1042