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