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