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_AUTOSCROLL_N, asn_ ); 457 MAKE_CURSOR( POINTER_AUTOSCROLL_S, ass_ ); 458 MAKE_CURSOR( POINTER_AUTOSCROLL_W, asw_ ); 459 MAKE_CURSOR( POINTER_AUTOSCROLL_E, ase_ ); 460 MAKE_CURSOR( POINTER_AUTOSCROLL_NW, asnw_ ); 461 MAKE_CURSOR( POINTER_AUTOSCROLL_NE, asne_ ); 462 MAKE_CURSOR( POINTER_AUTOSCROLL_SW, assw_ ); 463 MAKE_CURSOR( POINTER_AUTOSCROLL_SE, asse_ ); 464 MAKE_CURSOR( POINTER_AUTOSCROLL_NS, asns_ ); 465 MAKE_CURSOR( POINTER_AUTOSCROLL_WE, aswe_ ); 466 MAKE_CURSOR( POINTER_AUTOSCROLL_NSWE, asnswe_ ); 467 MAKE_CURSOR( POINTER_AIRBRUSH, airbrush_ ); 468 MAKE_CURSOR( POINTER_TEXT_VERTICAL, vertcurs_ ); 469 470 // --> FME 2004-07-30 #i32329# Enhanced table selection 471 MAKE_CURSOR( POINTER_TAB_SELECT_S, tblsels_ ); 472 MAKE_CURSOR( POINTER_TAB_SELECT_E, tblsele_ ); 473 MAKE_CURSOR( POINTER_TAB_SELECT_SE, tblselse_ ); 474 MAKE_CURSOR( POINTER_TAB_SELECT_W, tblselw_ ); 475 MAKE_CURSOR( POINTER_TAB_SELECT_SW, tblselsw_ ); 476 // <-- 477 478 // --> FME 2004-08-16 #i20119# Paintbrush tool 479 MAKE_CURSOR( POINTER_PAINTBRUSH, paintbrush_ ); 480 // <-- 481 482 default: 483 fprintf( stderr, "pointer %d not implemented", ePointerStyle ); 484 break; 485 } 486 if( !pCursor ) 487 pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, GDK_LEFT_PTR ); 488 489 m_aCursors[ ePointerStyle ] = pCursor; 490 } 491 492 return m_aCursors[ ePointerStyle ]; 493 } 494 495 int GtkSalDisplay::CaptureMouse( SalFrame* pSFrame ) 496 { 497 GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(pSFrame); 498 499 if( !pFrame ) 500 { 501 if( m_pCapture ) 502 static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE ); 503 m_pCapture = NULL; 504 return 0; 505 } 506 507 if( m_pCapture ) 508 { 509 if( pFrame == m_pCapture ) 510 return 1; 511 static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE ); 512 } 513 514 m_pCapture = pFrame; 515 static_cast<GtkSalFrame*>(pFrame)->grabPointer( TRUE ); 516 return 1; 517 } 518 519 /*************************************************************************** 520 * class GtkXLib 521 ***************************************************************************/ 522 523 class GtkXLib : public SalXLib 524 { 525 GtkSalDisplay *m_pGtkSalDisplay; 526 std::list<GSource *> m_aSources; 527 GSource *m_pTimeout; 528 GSource *m_pUserEvent; 529 oslMutex m_aDispatchMutex; 530 oslCondition m_aDispatchCondition; 531 XIOErrorHandler m_aOrigGTKXIOErrorHandler; 532 533 public: 534 static gboolean timeoutFn(gpointer data); 535 static gboolean userEventFn(gpointer data); 536 537 GtkXLib(); 538 virtual ~GtkXLib(); 539 540 virtual void Init(); 541 virtual void Yield( bool bWait, bool bHandleAllCurrentEvents ); 542 virtual void Insert( int fd, void* data, 543 YieldFunc pending, 544 YieldFunc queued, 545 YieldFunc handle ); 546 virtual void Remove( int fd ); 547 548 virtual void StartTimer( sal_uLong nMS ); 549 virtual void StopTimer(); 550 virtual void Wakeup(); 551 virtual void PostUserEvent(); 552 }; 553 554 GtkXLib::GtkXLib() 555 { 556 #if OSL_DEBUG_LEVEL > 1 557 fprintf( stderr, "GtkXLib::GtkXLib()\n" ); 558 #endif 559 m_pGtkSalDisplay = NULL; 560 m_pTimeout = NULL; 561 m_nTimeoutMS = 0; 562 m_pUserEvent = NULL; 563 m_aDispatchCondition = osl_createCondition(); 564 m_aDispatchMutex = osl_createMutex(); 565 m_aOrigGTKXIOErrorHandler = NULL; 566 } 567 568 GtkXLib::~GtkXLib() 569 { 570 #if OSL_DEBUG_LEVEL > 1 571 fprintf( stderr, "GtkXLib::~GtkXLib()\n" ); 572 #endif 573 StopTimer(); 574 // sanity check: at this point nobody should be yielding, but wake them 575 // up anyway before the condition they're waiting on gets destroyed. 576 osl_setCondition( m_aDispatchCondition ); 577 osl_destroyCondition( m_aDispatchCondition ); 578 osl_destroyMutex( m_aDispatchMutex ); 579 580 PopXErrorLevel(); 581 XSetIOErrorHandler (m_aOrigGTKXIOErrorHandler); 582 } 583 584 void GtkXLib::Init() 585 { 586 int i; 587 #if OSL_DEBUG_LEVEL > 1 588 fprintf( stderr, "GtkXLib::Init()\n" ); 589 #endif 590 XrmInitialize(); 591 592 gtk_set_locale(); 593 594 /* 595 * open connection to X11 Display 596 * try in this order: 597 * o -display command line parameter, 598 * o $DISPLAY environment variable 599 * o default display 600 */ 601 602 GdkDisplay *pGdkDisp = NULL; 603 604 // is there a -display command line parameter? 605 rtl_TextEncoding aEnc = osl_getThreadTextEncoding(); 606 int nParams = osl_getCommandArgCount(); 607 rtl::OString aDisplay; 608 rtl::OUString aParam, aBin; 609 char** pCmdLineAry = new char*[ nParams+1 ]; 610 osl_getExecutableFile( &aParam.pData ); 611 osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData ); 612 pCmdLineAry[0] = g_strdup( OUStringToOString( aBin, aEnc ).getStr() ); 613 for (i=0; i<nParams; i++) 614 { 615 osl_getCommandArg(i, &aParam.pData ); 616 OString aBParam( OUStringToOString( aParam, aEnc ) ); 617 618 if( aParam.equalsAscii( "-display" ) || aParam.equalsAscii( "--display" ) ) 619 { 620 pCmdLineAry[i+1] = g_strdup( "--display" ); 621 osl_getCommandArg(i+1, &aParam.pData ); 622 aDisplay = rtl::OUStringToOString( aParam, aEnc ); 623 } 624 else 625 pCmdLineAry[i+1] = g_strdup( aBParam.getStr() ); 626 } 627 // add executable 628 nParams++; 629 630 g_set_application_name(X11SalData::getFrameClassName()); 631 632 // Set consistent name of the root accessible 633 rtl::OUString aAppName = Application::GetAppName(); 634 if( aAppName.getLength() > 0 ) 635 { 636 rtl::OString aPrgName = rtl::OUStringToOString(aAppName, aEnc); 637 g_set_prgname( aPrgName.getStr()); 638 } 639 640 // init gtk/gdk 641 gtk_init_check( &nParams, &pCmdLineAry ); 642 643 // gtk_init_check sets XError/XIOError handlers, we want our own one 644 m_aOrigGTKXIOErrorHandler = XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl ); 645 PushXErrorLevel( !!getenv( "SAL_IGNOREXERRORS" ) ); 646 647 for (i = 0; i < nParams; i++ ) 648 g_free( pCmdLineAry[i] ); 649 delete [] pCmdLineAry; 650 651 #if OSL_DEBUG_LEVEL > 1 652 if (g_getenv ("SAL_DEBUG_UPDATES")) 653 gdk_window_set_debug_updates (TRUE); 654 #endif 655 656 pGdkDisp = gdk_display_get_default(); 657 if ( !pGdkDisp ) 658 { 659 rtl::OUString aProgramFileURL; 660 osl_getExecutableFile( &aProgramFileURL.pData ); 661 rtl::OUString aProgramSystemPath; 662 osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData); 663 rtl::OString aProgramName = rtl::OUStringToOString( 664 aProgramSystemPath, 665 osl_getThreadTextEncoding() ); 666 fprintf( stderr, "%s X11 error: Can't open display: %s\n", 667 aProgramName.getStr(), aDisplay.getStr()); 668 fprintf( stderr, " Set DISPLAY environment variable, use -display option\n"); 669 fprintf( stderr, " or check permissions of your X-Server\n"); 670 fprintf( stderr, " (See \"man X\" resp. \"man xhost\" for details)\n"); 671 fflush( stderr ); 672 exit(0); 673 } 674 675 /* 676 * if a -display switch was used, we need 677 * to set the environment accordingly since 678 * the clipboard build another connection 679 * to the xserver using $DISPLAY 680 */ 681 rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("DISPLAY")); 682 const gchar *name = gdk_display_get_name( pGdkDisp ); 683 rtl::OUString envValue(name, strlen(name), aEnc); 684 osl_setEnvironment(envVar.pData, envValue.pData); 685 686 Display *pDisp = gdk_x11_display_get_xdisplay( pGdkDisp ); 687 688 m_pGtkSalDisplay = new GtkSalDisplay( pGdkDisp ); 689 690 gdk_window_add_filter( NULL, call_filterGdkEvent, m_pGtkSalDisplay ); 691 692 PushXErrorLevel( true ); 693 SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp ); 694 XSync( pDisp, False ); 695 696 pKbdExtension->UseExtension( ! HasXErrorOccured() ); 697 PopXErrorLevel(); 698 699 m_pGtkSalDisplay->SetKbdExtension( pKbdExtension ); 700 701 g_signal_connect( G_OBJECT(gdk_keymap_get_default()), "keys_changed", G_CALLBACK(signalKeysChanged), m_pGtkSalDisplay ); 702 703 // add signal handler to notify screen size changes 704 int nScreens = gdk_display_get_n_screens( pGdkDisp ); 705 for( int n = 0; n < nScreens; n++ ) 706 { 707 GdkScreen *pScreen = gdk_display_get_screen( pGdkDisp, n ); 708 if( pScreen ) 709 { 710 g_signal_connect( G_OBJECT(pScreen), "size-changed", G_CALLBACK(signalScreenSizeChanged), m_pGtkSalDisplay ); 711 if( ! gtk_check_version( 2, 14, 0 ) ) // monitors-changed came in with 2.14, avoid an assertion 712 g_signal_connect( G_OBJECT(pScreen), "monitors-changed", G_CALLBACK(signalMonitorsChanged), m_pGtkSalDisplay ); 713 } 714 } 715 } 716 717 extern "C" 718 { 719 gboolean call_timeoutFn(gpointer data) 720 { 721 return GtkXLib::timeoutFn(data); 722 } 723 } 724 725 gboolean GtkXLib::timeoutFn(gpointer data) 726 { 727 SalData *pSalData = GetSalData(); 728 GtkXLib *pThis = (GtkXLib *) data; 729 730 pSalData->m_pInstance->GetYieldMutex()->acquire(); 731 732 if( pThis->m_pTimeout ) 733 { 734 g_source_unref (pThis->m_pTimeout); 735 pThis->m_pTimeout = NULL; 736 } 737 738 // Auto-restart immediately 739 pThis->StartTimer( pThis->m_nTimeoutMS ); 740 741 GetX11SalData()->Timeout(); 742 743 pSalData->m_pInstance->GetYieldMutex()->release(); 744 745 return FALSE; 746 } 747 748 void GtkXLib::StartTimer( sal_uLong nMS ) 749 { 750 m_nTimeoutMS = nMS; // for restarting 751 752 if (m_pTimeout) 753 { 754 g_source_destroy (m_pTimeout); 755 g_source_unref (m_pTimeout); 756 } 757 758 m_pTimeout = g_timeout_source_new (m_nTimeoutMS); 759 // #i36226# timers should be executed with lower priority 760 // than XEvents like in generic plugin 761 g_source_set_priority( m_pTimeout, G_PRIORITY_LOW ); 762 g_source_set_can_recurse (m_pTimeout, TRUE); 763 g_source_set_callback (m_pTimeout, call_timeoutFn, 764 (gpointer) this, NULL); 765 g_source_attach (m_pTimeout, g_main_context_default ()); 766 767 SalXLib::StartTimer( nMS ); 768 } 769 770 void GtkXLib::StopTimer() 771 { 772 SalXLib::StopTimer(); 773 774 if (m_pTimeout) 775 { 776 g_source_destroy (m_pTimeout); 777 g_source_unref (m_pTimeout); 778 m_pTimeout = NULL; 779 } 780 } 781 782 extern "C" 783 { 784 gboolean call_userEventFn( gpointer data ) 785 { 786 return GtkXLib::userEventFn( data ); 787 } 788 } 789 790 gboolean GtkXLib::userEventFn(gpointer data) 791 { 792 gboolean bContinue; 793 GtkXLib *pThis = (GtkXLib *) data; 794 SalData *pSalData = GetSalData(); 795 796 pSalData->m_pInstance->GetYieldMutex()->acquire(); 797 pThis->m_pGtkSalDisplay->EventGuardAcquire(); 798 799 if( !pThis->m_pGtkSalDisplay->HasMoreEvents() ) 800 { 801 if( pThis->m_pUserEvent ) 802 { 803 g_source_unref (pThis->m_pUserEvent); 804 pThis->m_pUserEvent = NULL; 805 } 806 bContinue = FALSE; 807 } 808 else 809 bContinue = TRUE; 810 811 pThis->m_pGtkSalDisplay->EventGuardRelease(); 812 813 pThis->m_pGtkSalDisplay->DispatchInternalEvent(); 814 815 pSalData->m_pInstance->GetYieldMutex()->release(); 816 817 return bContinue; 818 } 819 820 // hEventGuard_ held during this invocation 821 void GtkXLib::PostUserEvent() 822 { 823 if( !m_pUserEvent ) // not pending anyway 824 { 825 m_pUserEvent = g_idle_source_new(); 826 g_source_set_priority( m_pUserEvent, G_PRIORITY_HIGH ); 827 g_source_set_can_recurse (m_pUserEvent, TRUE); 828 g_source_set_callback (m_pUserEvent, call_userEventFn, 829 (gpointer) this, NULL); 830 g_source_attach (m_pUserEvent, g_main_context_default ()); 831 } 832 Wakeup(); 833 } 834 835 void GtkXLib::Wakeup() 836 { 837 g_main_context_wakeup( g_main_context_default () ); 838 } 839 840 void GtkXLib::Yield( bool bWait, bool bHandleAllCurrentEvents ) 841 { 842 /* #i33212# only enter g_main_context_iteration in one thread at any one 843 * time, else one of them potentially will never end as long as there is 844 * another thread in in there. Having only one yielding thread actually dispatch 845 * fits the vcl event model (see e.g. the generic plugin). 846 */ 847 848 bool bDispatchThread = false; 849 gboolean wasEvent = FALSE; 850 { 851 // release YieldMutex (and re-acquire at block end) 852 YieldMutexReleaser aReleaser; 853 if( osl_tryToAcquireMutex( m_aDispatchMutex ) ) 854 bDispatchThread = true; 855 else if( ! bWait ) 856 return; // someone else is waiting already, return 857 858 859 if( bDispatchThread ) 860 { 861 int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1; 862 gboolean wasOneEvent = TRUE; 863 while( nMaxEvents-- && wasOneEvent ) 864 { 865 wasOneEvent = g_main_context_iteration( NULL, FALSE ); 866 if( wasOneEvent ) 867 wasEvent = TRUE; 868 } 869 if( bWait && ! wasEvent ) 870 wasEvent = g_main_context_iteration( NULL, TRUE ); 871 } 872 else if( bWait ) 873 { 874 /* #i41693# in case the dispatch thread hangs in join 875 * for this thread the condition will never be set 876 * workaround: timeout of 1 second a emergency exit 877 */ 878 // we are the dispatch thread 879 osl_resetCondition( m_aDispatchCondition ); 880 TimeValue aValue = { 1, 0 }; 881 osl_waitCondition( m_aDispatchCondition, &aValue ); 882 } 883 } 884 885 if( bDispatchThread ) 886 { 887 osl_releaseMutex( m_aDispatchMutex ); 888 if( wasEvent ) 889 osl_setCondition( m_aDispatchCondition ); // trigger non dispatch thread yields 890 } 891 } 892 893 extern "C" { 894 895 typedef struct { 896 GSource source; 897 898 GPollFD pollfd; 899 GIOCondition condition; 900 901 YieldFunc pending; 902 YieldFunc handle; 903 gpointer user_data; 904 } SalWatch; 905 906 static gboolean 907 sal_source_prepare (GSource *source, 908 gint *timeout) 909 { 910 SalWatch *watch = (SalWatch *)source; 911 912 *timeout = -1; 913 914 if (watch->pending && 915 watch->pending (watch->pollfd.fd, watch->user_data)) { 916 watch->pollfd.revents |= watch->condition; 917 return TRUE; 918 } 919 920 return FALSE; 921 } 922 923 static gboolean 924 sal_source_check (GSource *source) 925 { 926 SalWatch *watch = (SalWatch *)source; 927 928 return watch->pollfd.revents & watch->condition; 929 } 930 931 static gboolean 932 sal_source_dispatch (GSource *source, 933 GSourceFunc, 934 gpointer) 935 { 936 SalData *pSalData = GetSalData(); 937 SalWatch *watch = (SalWatch *) source; 938 939 pSalData->m_pInstance->GetYieldMutex()->acquire(); 940 941 watch->handle (watch->pollfd.fd, watch->user_data); 942 943 pSalData->m_pInstance->GetYieldMutex()->release(); 944 945 return TRUE; 946 } 947 948 static void 949 sal_source_finalize (GSource*) 950 { 951 } 952 953 static GSourceFuncs sal_source_watch_funcs = { 954 sal_source_prepare, 955 sal_source_check, 956 sal_source_dispatch, 957 sal_source_finalize, 958 NULL, 959 NULL 960 }; 961 962 static GSource * 963 sal_source_create_watch (int fd, 964 GIOCondition condition, 965 YieldFunc pending, 966 YieldFunc handle, 967 gpointer user_data) 968 { 969 GSource *source; 970 SalWatch *watch; 971 GMainContext *context = g_main_context_default (); 972 973 source = g_source_new (&sal_source_watch_funcs, 974 sizeof (SalWatch)); 975 watch = (SalWatch *) source; 976 977 watch->pollfd.fd = fd; 978 watch->pollfd.events = condition; 979 watch->condition = condition; 980 watch->pending = pending; 981 watch->handle = handle; 982 watch->user_data = user_data; 983 984 g_source_set_can_recurse (source, TRUE); 985 g_source_add_poll (source, &watch->pollfd); 986 g_source_attach (source, context); 987 988 return source; 989 } 990 991 } // extern "C" 992 993 void GtkXLib::Insert( int nFD, 994 void *data, 995 YieldFunc pending, 996 YieldFunc, 997 YieldFunc handle ) 998 { 999 GSource *source = sal_source_create_watch 1000 ( nFD, (GIOCondition) ((G_IO_IN|G_IO_PRI) | 1001 (G_IO_ERR|G_IO_HUP|G_IO_NVAL)), 1002 pending, handle, data ); 1003 m_aSources.push_back( source ); 1004 } 1005 1006 void GtkXLib::Remove( int nFD ) 1007 { 1008 ::std::list< GSource * >::iterator it; 1009 1010 for (it = m_aSources.begin(); it != m_aSources.end(); ++it) 1011 { 1012 SalWatch *watch = (SalWatch *) *it; 1013 1014 if (watch->pollfd.fd == nFD) 1015 { 1016 m_aSources.erase( it ); 1017 1018 g_source_destroy ((GSource *)watch); 1019 g_source_unref ((GSource *)watch); 1020 return; 1021 } 1022 } 1023 } 1024 1025 /********************************************************************** 1026 * class GtkData 1027 **********************************************************************/ 1028 1029 GtkData::~GtkData() 1030 { 1031 } 1032 1033 void GtkData::Init() 1034 { 1035 pXLib_ = new GtkXLib(); 1036 pXLib_->Init(); 1037 } 1038 1039 /* vim: set noet sw=4 ts=4: */ 1040