Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <unistd.h>
21 : #include <fcntl.h>
22 :
23 : #include <stdio.h>
24 : #include <string.h>
25 : #include <stdlib.h>
26 : #include <limits.h>
27 : #include <errno.h>
28 : #include <poll.h>
29 : #if defined(FREEBSD) || defined(NETBSD)
30 : #include <sys/types.h>
31 : #include <sys/time.h>
32 : #include <unistd.h>
33 : #endif
34 : #define GLIB_DISABLE_DEPRECATION_WARNINGS
35 : #include <unx/gtk/gtkdata.hxx>
36 : #include <unx/gtk/gtkinst.hxx>
37 : #include <unx/gtk/gtkframe.hxx>
38 : #include <unx/salobj.h>
39 : #include <generic/geninst.h>
40 : #include <osl/thread.h>
41 : #include <osl/process.h>
42 :
43 : #include "unx/i18n_im.hxx"
44 : #include "unx/i18n_xkb.hxx"
45 : #include <unx/wmadaptor.hxx>
46 :
47 : #include "unx/x11_cursors/salcursors.h"
48 :
49 : #include <vcl/svapp.hxx>
50 :
51 : using namespace vcl_sal;
52 :
53 : using ::rtl::OUString;
54 :
55 : /***************************************************************
56 : * class GtkSalDisplay *
57 : ***************************************************************/
58 : extern "C" {
59 0 : GdkFilterReturn call_filterGdkEvent( GdkXEvent* sys_event,
60 : GdkEvent* event,
61 : gpointer data )
62 : {
63 0 : GtkSalDisplay *pDisplay = (GtkSalDisplay *)data;
64 0 : return pDisplay->filterGdkEvent( sys_event, event );
65 : }
66 : }
67 :
68 0 : GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay ) :
69 : #if !GTK_CHECK_VERSION(3,0,0)
70 : SalDisplay( gdk_x11_display_get_xdisplay( pDisplay ) ),
71 : #endif
72 0 : m_pSys( GtkSalSystem::GetSingleton() ),
73 : m_pGdkDisplay( pDisplay ),
74 0 : m_bStartupCompleted( false )
75 : {
76 0 : for(int i = 0; i < POINTER_COUNT; i++)
77 0 : m_aCursors[ i ] = NULL;
78 : #if !GTK_CHECK_VERSION(3,0,0)
79 0 : m_bUseRandRWrapper = false; // use gdk signal instead
80 0 : Init ();
81 : #endif
82 :
83 : // FIXME: unify this with SalInst's filter too ?
84 0 : gdk_window_add_filter( NULL, call_filterGdkEvent, this );
85 :
86 0 : if ( getenv( "SAL_IGNOREXERRORS" ) )
87 0 : GetGenericData()->ErrorTrapPush(); // and leak the trap
88 :
89 : #if GTK_CHECK_VERSION(3,0,0)
90 : m_bX11Display = GDK_IS_X11_DISPLAY( m_pGdkDisplay );
91 : #else
92 0 : m_bX11Display = true;
93 : #endif
94 0 : }
95 :
96 0 : GtkSalDisplay::~GtkSalDisplay()
97 : {
98 0 : gdk_window_remove_filter( NULL, call_filterGdkEvent, this );
99 :
100 0 : if( !m_bStartupCompleted )
101 0 : gdk_notify_startup_complete();
102 :
103 : #if !GTK_CHECK_VERSION(3,0,0)
104 0 : doDestruct();
105 0 : pDisp_ = NULL;
106 : #endif
107 :
108 0 : for(int i = 0; i < POINTER_COUNT; i++)
109 0 : if( m_aCursors[ i ] )
110 0 : gdk_cursor_unref( m_aCursors[ i ] );
111 0 : }
112 :
113 : extern "C" {
114 :
115 0 : void signalScreenSizeChanged( GdkScreen* pScreen, gpointer data )
116 : {
117 0 : GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
118 0 : pDisp->screenSizeChanged( pScreen );
119 0 : }
120 :
121 0 : void signalMonitorsChanged( GdkScreen* pScreen, gpointer data )
122 : {
123 0 : GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
124 0 : pDisp->monitorsChanged( pScreen );
125 0 : }
126 :
127 : }
128 :
129 0 : GdkFilterReturn GtkSalDisplay::filterGdkEvent( GdkXEvent* sys_event,
130 : GdkEvent* )
131 : {
132 : #if !GTK_CHECK_VERSION(3,0,0)
133 0 : GdkFilterReturn aFilterReturn = GDK_FILTER_CONTINUE;
134 0 : XEvent *pEvent = (XEvent *)sys_event;
135 :
136 : // dispatch all XEvents to event callback
137 0 : if( GetSalData()->m_pInstance->
138 0 : CallEventCallback( pEvent, sizeof( XEvent ) ) )
139 0 : aFilterReturn = GDK_FILTER_REMOVE;
140 :
141 0 : GTK_YIELD_GRAB();
142 :
143 0 : if (GetDisplay() == pEvent->xany.display )
144 : {
145 : // #i53471# gtk has no callback mechanism that lets us be notified
146 : // when settings (as in XSETTING and opposed to styles) are changed.
147 : // so we need to listen for corresponding property notifications here
148 : // these should be rare enough so that we can assume that the settings
149 : // actually change when a corresponding PropertyNotify occurs
150 0 : if( pEvent->type == PropertyNotify &&
151 0 : pEvent->xproperty.atom == getWMAdaptor()->getAtom( WMAdaptor::XSETTINGS ) &&
152 0 : ! m_aFrames.empty()
153 : )
154 : {
155 0 : SendInternalEvent( m_aFrames.front(), NULL, SALEVENT_SETTINGSCHANGED );
156 : }
157 : // let's see if one of our frames wants to swallow these events
158 : // get the frame
159 0 : for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin();
160 0 : it != m_aFrames.end(); ++it )
161 : {
162 0 : GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(*it);
163 0 : if( (GdkNativeWindow)pFrame->GetSystemData()->aWindow == pEvent->xany.window ||
164 0 : ( pFrame->getForeignParent() && pFrame->getForeignParentWindow() == pEvent->xany.window ) ||
165 0 : ( pFrame->getForeignTopLevel() && pFrame->getForeignTopLevelWindow() == pEvent->xany.window )
166 : )
167 : {
168 0 : if( ! pFrame->Dispatch( pEvent ) )
169 0 : aFilterReturn = GDK_FILTER_REMOVE;
170 0 : break;
171 : }
172 : }
173 0 : X11SalObject::Dispatch( pEvent );
174 : }
175 :
176 0 : return aFilterReturn;
177 : #else
178 : (void) sys_event;
179 : #warning FIXME: implement filterGdkEvent ...
180 : return GDK_FILTER_CONTINUE;
181 : #endif
182 : }
183 :
184 0 : void GtkSalDisplay::screenSizeChanged( GdkScreen* pScreen )
185 : {
186 0 : m_pSys->countScreenMonitors();
187 0 : if (pScreen)
188 0 : emitDisplayChanged();
189 0 : }
190 :
191 0 : void GtkSalDisplay::monitorsChanged( GdkScreen* pScreen )
192 : {
193 0 : m_pSys->countScreenMonitors();
194 0 : if (pScreen)
195 0 : emitDisplayChanged();
196 0 : }
197 :
198 : #if !GTK_CHECK_VERSION(3,0,0)
199 : SalDisplay::ScreenData *
200 0 : GtkSalDisplay::initScreen( SalX11Screen nXScreen ) const
201 : {
202 : // choose visual for screen
203 : ScreenData *pSD;
204 0 : if (!(pSD = SalDisplay::initScreen( nXScreen )))
205 0 : return NULL;
206 :
207 : // now set a gdk default colormap matching the chosen visual to the screen
208 0 : GdkScreen* pScreen = gdk_display_get_screen( m_pGdkDisplay, nXScreen.getXScreen() );
209 : // should really use this:
210 : // GdkVisual* pVis = gdk_x11_screen_lookup_visual_get( screen, pSD->m_aVisual.visualid );
211 : // and not this:
212 0 : GdkVisual* pVis = gdkx_visual_get( pSD->m_aVisual.visualid );
213 0 : if( pVis )
214 : {
215 0 : GdkColormap* pDefCol = gdk_screen_get_default_colormap( pScreen );
216 0 : GdkVisual* pDefVis = gdk_colormap_get_visual( pDefCol );
217 0 : if( pDefVis != pVis )
218 : {
219 0 : pDefCol = gdk_x11_colormap_foreign_new( pVis, pSD->m_aColormap.GetXColormap() );
220 0 : gdk_screen_set_default_colormap( pScreen, pDefCol );
221 : #if OSL_DEBUG_LEVEL > 1
222 : fprintf( stderr, "set new gdk color map for screen %d\n", nXScreen.getXScreen() );
223 : #endif
224 : }
225 : }
226 : #if OSL_DEBUG_LEVEL > 1
227 : else
228 : fprintf( stderr, "not GdkVisual for visual id %d\n", (int)pSD->m_aVisual.visualid );
229 : #endif
230 0 : return pSD;
231 : }
232 :
233 0 : long GtkSalDisplay::Dispatch( XEvent* pEvent )
234 : {
235 0 : if( GetDisplay() == pEvent->xany.display )
236 : {
237 : // let's see if one of our frames wants to swallow these events
238 : // get the child frame
239 0 : for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin();
240 0 : it != m_aFrames.end(); ++it )
241 : {
242 0 : if( (GdkNativeWindow)(*it)->GetSystemData()->aWindow == pEvent->xany.window )
243 0 : return static_cast<GtkSalFrame*>(*it)->Dispatch( pEvent );
244 : }
245 : }
246 :
247 0 : return GDK_FILTER_CONTINUE;
248 : }
249 : #endif
250 :
251 : #if GTK_CHECK_VERSION(3,0,0)
252 : namespace
253 : {
254 : //cairo annoyingly won't take raw xbm data unless it fits
255 : //the required cairo stride
256 : unsigned char* ensurePaddedForCairo(const unsigned char *pXBM,
257 : int nWidth, int nHeight, int nStride)
258 : {
259 : unsigned char *pPaddedXBM = const_cast<unsigned char*>(pXBM);
260 :
261 : int bytes_per_row = (nWidth + 7) / 8;
262 :
263 : if (nStride != bytes_per_row)
264 : {
265 : pPaddedXBM = new unsigned char[nStride * nHeight];
266 : for (int row = 0; row < nHeight; ++row)
267 : {
268 : memcpy(pPaddedXBM + (nStride * row),
269 : pXBM + (bytes_per_row * row), bytes_per_row);
270 : memset(pPaddedXBM + (nStride * row) + bytes_per_row,
271 : 0, nStride - bytes_per_row);
272 : }
273 : }
274 :
275 : return pPaddedXBM;
276 : }
277 : }
278 : #endif
279 :
280 0 : GdkCursor* GtkSalDisplay::getFromXBM( const unsigned char *pBitmap,
281 : const unsigned char *pMask,
282 : int nWidth, int nHeight,
283 : int nXHot, int nYHot )
284 : {
285 : #if GTK_CHECK_VERSION(3,0,0)
286 : int cairo_stride = cairo_format_stride_for_width(CAIRO_FORMAT_A1, nWidth);
287 :
288 : unsigned char *pPaddedXBM = ensurePaddedForCairo(pBitmap, nWidth, nHeight, cairo_stride);
289 : cairo_surface_t *s = cairo_image_surface_create_for_data(
290 : pPaddedXBM,
291 : CAIRO_FORMAT_A1, nWidth, nHeight,
292 : cairo_stride);
293 :
294 : cairo_t *cr = cairo_create(s);
295 : unsigned char *pPaddedMaskXBM = ensurePaddedForCairo(pMask, nWidth, nHeight, cairo_stride);
296 : cairo_surface_t *mask = cairo_image_surface_create_for_data(
297 : pPaddedMaskXBM,
298 : CAIRO_FORMAT_A1, nWidth, nHeight,
299 : cairo_stride);
300 : cairo_mask_surface(cr, mask, 0, 0);
301 : cairo_destroy(cr);
302 : cairo_surface_destroy(mask);
303 : if (pPaddedMaskXBM != pMask)
304 : delete [] pPaddedMaskXBM;
305 :
306 : GdkPixbuf *pixbuf = gdk_pixbuf_get_from_surface(s, 0, 0, nWidth, nHeight);
307 : cairo_surface_destroy(s);
308 : if (pPaddedXBM != pBitmap)
309 : delete [] pPaddedXBM;
310 :
311 : GdkCursor *cursor = gdk_cursor_new_from_pixbuf(m_pGdkDisplay, pixbuf, nXHot, nYHot);
312 : g_object_unref(pixbuf);
313 :
314 : return cursor;
315 : #else
316 0 : GdkScreen *pScreen = gdk_display_get_default_screen( m_pGdkDisplay );
317 0 : GdkDrawable *pDrawable = GDK_DRAWABLE( gdk_screen_get_root_window (pScreen) );
318 : GdkBitmap *pBitmapPix = gdk_bitmap_create_from_data
319 0 : ( pDrawable, reinterpret_cast<const char*>(pBitmap), nWidth, nHeight );
320 : GdkBitmap *pMaskPix = gdk_bitmap_create_from_data
321 0 : ( pDrawable, reinterpret_cast<const char*>(pMask), nWidth, nHeight );
322 0 : GdkColormap *pColormap = gdk_drawable_get_colormap( pDrawable );
323 :
324 0 : GdkColor aWhite = { 0, 0xffff, 0xffff, 0xffff };
325 0 : GdkColor aBlack = { 0, 0, 0, 0 };
326 :
327 0 : gdk_colormap_alloc_color( pColormap, &aBlack, FALSE, TRUE);
328 0 : gdk_colormap_alloc_color( pColormap, &aWhite, FALSE, TRUE);
329 :
330 : return gdk_cursor_new_from_pixmap
331 : ( pBitmapPix, pMaskPix,
332 0 : &aBlack, &aWhite, nXHot, nYHot);
333 : #endif
334 : }
335 :
336 : #define MAKE_CURSOR( vcl_name, name ) \
337 : case vcl_name: \
338 : pCursor = getFromXBM( name##curs##_bits, name##mask##_bits, \
339 : name##curs_width, name##curs_height, \
340 : name##curs_x_hot, name##curs_y_hot ); \
341 : break
342 : #define MAP_BUILTIN( vcl_name, gdk_name ) \
343 : case vcl_name: \
344 : pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, gdk_name ); \
345 : break
346 :
347 0 : GdkCursor *GtkSalDisplay::getCursor( PointerStyle ePointerStyle )
348 : {
349 0 : if( ePointerStyle >= POINTER_COUNT )
350 0 : return NULL;
351 :
352 0 : if ( !m_aCursors[ ePointerStyle ] )
353 : {
354 0 : GdkCursor *pCursor = NULL;
355 :
356 0 : switch( ePointerStyle )
357 : {
358 0 : MAP_BUILTIN( POINTER_ARROW, GDK_LEFT_PTR );
359 0 : MAP_BUILTIN( POINTER_TEXT, GDK_XTERM );
360 0 : MAP_BUILTIN( POINTER_HELP, GDK_QUESTION_ARROW );
361 0 : MAP_BUILTIN( POINTER_CROSS, GDK_CROSSHAIR );
362 0 : MAP_BUILTIN( POINTER_WAIT, GDK_WATCH );
363 :
364 0 : MAP_BUILTIN( POINTER_NSIZE, GDK_SB_V_DOUBLE_ARROW );
365 0 : MAP_BUILTIN( POINTER_SSIZE, GDK_SB_V_DOUBLE_ARROW );
366 0 : MAP_BUILTIN( POINTER_WSIZE, GDK_SB_H_DOUBLE_ARROW );
367 0 : MAP_BUILTIN( POINTER_ESIZE, GDK_SB_H_DOUBLE_ARROW );
368 :
369 0 : MAP_BUILTIN( POINTER_NWSIZE, GDK_TOP_LEFT_CORNER );
370 0 : MAP_BUILTIN( POINTER_NESIZE, GDK_TOP_RIGHT_CORNER );
371 0 : MAP_BUILTIN( POINTER_SWSIZE, GDK_BOTTOM_LEFT_CORNER );
372 0 : MAP_BUILTIN( POINTER_SESIZE, GDK_BOTTOM_RIGHT_CORNER );
373 :
374 0 : MAP_BUILTIN( POINTER_WINDOW_NSIZE, GDK_TOP_SIDE );
375 0 : MAP_BUILTIN( POINTER_WINDOW_SSIZE, GDK_BOTTOM_SIDE );
376 0 : MAP_BUILTIN( POINTER_WINDOW_WSIZE, GDK_LEFT_SIDE );
377 0 : MAP_BUILTIN( POINTER_WINDOW_ESIZE, GDK_RIGHT_SIDE );
378 :
379 0 : MAP_BUILTIN( POINTER_WINDOW_NWSIZE, GDK_TOP_LEFT_CORNER );
380 0 : MAP_BUILTIN( POINTER_WINDOW_NESIZE, GDK_TOP_RIGHT_CORNER );
381 0 : MAP_BUILTIN( POINTER_WINDOW_SWSIZE, GDK_BOTTOM_LEFT_CORNER );
382 0 : MAP_BUILTIN( POINTER_WINDOW_SESIZE, GDK_BOTTOM_RIGHT_CORNER );
383 :
384 0 : MAP_BUILTIN( POINTER_HSIZEBAR, GDK_SB_H_DOUBLE_ARROW );
385 0 : MAP_BUILTIN( POINTER_VSIZEBAR, GDK_SB_V_DOUBLE_ARROW );
386 :
387 0 : MAP_BUILTIN( POINTER_REFHAND, GDK_HAND2 );
388 0 : MAP_BUILTIN( POINTER_HAND, GDK_HAND2 );
389 0 : MAP_BUILTIN( POINTER_PEN, GDK_PENCIL );
390 :
391 0 : MAP_BUILTIN( POINTER_HSPLIT, GDK_SB_H_DOUBLE_ARROW );
392 0 : MAP_BUILTIN( POINTER_VSPLIT, GDK_SB_V_DOUBLE_ARROW );
393 :
394 0 : MAP_BUILTIN( POINTER_MOVE, GDK_FLEUR );
395 :
396 0 : MAKE_CURSOR( POINTER_NULL, null );
397 0 : MAKE_CURSOR( POINTER_MAGNIFY, magnify_ );
398 0 : MAKE_CURSOR( POINTER_FILL, fill_ );
399 0 : MAKE_CURSOR( POINTER_MOVEDATA, movedata_ );
400 0 : MAKE_CURSOR( POINTER_COPYDATA, copydata_ );
401 0 : MAKE_CURSOR( POINTER_MOVEFILE, movefile_ );
402 0 : MAKE_CURSOR( POINTER_COPYFILE, copyfile_ );
403 0 : MAKE_CURSOR( POINTER_MOVEFILES, movefiles_ );
404 0 : MAKE_CURSOR( POINTER_COPYFILES, copyfiles_ );
405 0 : MAKE_CURSOR( POINTER_NOTALLOWED, nodrop_ );
406 0 : MAKE_CURSOR( POINTER_ROTATE, rotate_ );
407 0 : MAKE_CURSOR( POINTER_HSHEAR, hshear_ );
408 0 : MAKE_CURSOR( POINTER_VSHEAR, vshear_ );
409 0 : MAKE_CURSOR( POINTER_DRAW_LINE, drawline_ );
410 0 : MAKE_CURSOR( POINTER_DRAW_RECT, drawrect_ );
411 0 : MAKE_CURSOR( POINTER_DRAW_POLYGON, drawpolygon_ );
412 0 : MAKE_CURSOR( POINTER_DRAW_BEZIER, drawbezier_ );
413 0 : MAKE_CURSOR( POINTER_DRAW_ARC, drawarc_ );
414 0 : MAKE_CURSOR( POINTER_DRAW_PIE, drawpie_ );
415 0 : MAKE_CURSOR( POINTER_DRAW_CIRCLECUT, drawcirclecut_ );
416 0 : MAKE_CURSOR( POINTER_DRAW_ELLIPSE, drawellipse_ );
417 0 : MAKE_CURSOR( POINTER_DRAW_CONNECT, drawconnect_ );
418 0 : MAKE_CURSOR( POINTER_DRAW_TEXT, drawtext_ );
419 0 : MAKE_CURSOR( POINTER_MIRROR, mirror_ );
420 0 : MAKE_CURSOR( POINTER_CROOK, crook_ );
421 0 : MAKE_CURSOR( POINTER_CROP, crop_ );
422 0 : MAKE_CURSOR( POINTER_MOVEPOINT, movepoint_ );
423 0 : MAKE_CURSOR( POINTER_MOVEBEZIERWEIGHT, movebezierweight_ );
424 0 : MAKE_CURSOR( POINTER_DRAW_FREEHAND, drawfreehand_ );
425 0 : MAKE_CURSOR( POINTER_DRAW_CAPTION, drawcaption_ );
426 0 : MAKE_CURSOR( POINTER_LINKDATA, linkdata_ );
427 0 : MAKE_CURSOR( POINTER_MOVEDATALINK, movedlnk_ );
428 0 : MAKE_CURSOR( POINTER_COPYDATALINK, copydlnk_ );
429 0 : MAKE_CURSOR( POINTER_LINKFILE, linkfile_ );
430 0 : MAKE_CURSOR( POINTER_MOVEFILELINK, moveflnk_ );
431 0 : MAKE_CURSOR( POINTER_COPYFILELINK, copyflnk_ );
432 0 : MAKE_CURSOR( POINTER_CHART, chart_ );
433 0 : MAKE_CURSOR( POINTER_DETECTIVE, detective_ );
434 0 : MAKE_CURSOR( POINTER_PIVOT_COL, pivotcol_ );
435 0 : MAKE_CURSOR( POINTER_PIVOT_ROW, pivotrow_ );
436 0 : MAKE_CURSOR( POINTER_PIVOT_FIELD, pivotfld_ );
437 0 : MAKE_CURSOR( POINTER_PIVOT_DELETE, pivotdel_ );
438 0 : MAKE_CURSOR( POINTER_CHAIN, chain_ );
439 0 : MAKE_CURSOR( POINTER_CHAIN_NOTALLOWED, chainnot_ );
440 0 : MAKE_CURSOR( POINTER_TIMEEVENT_MOVE, timemove_ );
441 0 : MAKE_CURSOR( POINTER_TIMEEVENT_SIZE, timesize_ );
442 0 : MAKE_CURSOR( POINTER_AUTOSCROLL_N, asn_ );
443 0 : MAKE_CURSOR( POINTER_AUTOSCROLL_S, ass_ );
444 0 : MAKE_CURSOR( POINTER_AUTOSCROLL_W, asw_ );
445 0 : MAKE_CURSOR( POINTER_AUTOSCROLL_E, ase_ );
446 0 : MAKE_CURSOR( POINTER_AUTOSCROLL_NW, asnw_ );
447 0 : MAKE_CURSOR( POINTER_AUTOSCROLL_NE, asne_ );
448 0 : MAKE_CURSOR( POINTER_AUTOSCROLL_SW, assw_ );
449 0 : MAKE_CURSOR( POINTER_AUTOSCROLL_SE, asse_ );
450 0 : MAKE_CURSOR( POINTER_AUTOSCROLL_NS, asns_ );
451 0 : MAKE_CURSOR( POINTER_AUTOSCROLL_WE, aswe_ );
452 0 : MAKE_CURSOR( POINTER_AUTOSCROLL_NSWE, asnswe_ );
453 0 : MAKE_CURSOR( POINTER_AIRBRUSH, airbrush_ );
454 0 : MAKE_CURSOR( POINTER_TEXT_VERTICAL, vertcurs_ );
455 :
456 : // #i32329#
457 0 : MAKE_CURSOR( POINTER_TAB_SELECT_S, tblsels_ );
458 0 : MAKE_CURSOR( POINTER_TAB_SELECT_E, tblsele_ );
459 0 : MAKE_CURSOR( POINTER_TAB_SELECT_SE, tblselse_ );
460 0 : MAKE_CURSOR( POINTER_TAB_SELECT_W, tblselw_ );
461 0 : MAKE_CURSOR( POINTER_TAB_SELECT_SW, tblselsw_ );
462 :
463 : // #i20119#
464 0 : MAKE_CURSOR( POINTER_PAINTBRUSH, paintbrush_ );
465 :
466 : default:
467 0 : fprintf( stderr, "pointer %d not implemented", ePointerStyle );
468 0 : break;
469 : }
470 0 : if( !pCursor )
471 0 : pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, GDK_LEFT_PTR );
472 :
473 0 : m_aCursors[ ePointerStyle ] = pCursor;
474 : }
475 :
476 0 : return m_aCursors[ ePointerStyle ];
477 : }
478 :
479 0 : int GtkSalDisplay::CaptureMouse( SalFrame* pSFrame )
480 : {
481 0 : GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(pSFrame);
482 :
483 0 : if( !pFrame )
484 : {
485 0 : if( m_pCapture )
486 0 : static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
487 0 : m_pCapture = NULL;
488 0 : return 0;
489 : }
490 :
491 0 : if( m_pCapture )
492 : {
493 0 : if( pFrame == m_pCapture )
494 0 : return 1;
495 0 : static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
496 : }
497 :
498 0 : m_pCapture = pFrame;
499 0 : static_cast<GtkSalFrame*>(pFrame)->grabPointer( TRUE );
500 0 : return 1;
501 : }
502 :
503 :
504 : /**********************************************************************
505 : * class GtkData *
506 : **********************************************************************/
507 :
508 0 : GtkData::GtkData( SalInstance *pInstance )
509 : #if GTK_CHECK_VERSION(3,0,0)
510 : : SalGenericData( SAL_DATA_GTK3, pInstance )
511 : #else
512 0 : : SalGenericData( SAL_DATA_GTK, pInstance )
513 : #endif
514 : {
515 0 : m_pUserEvent = NULL;
516 0 : m_aDispatchMutex = osl_createMutex();
517 0 : m_aDispatchCondition = osl_createCondition();
518 0 : }
519 :
520 : XIOErrorHandler aOrigXIOErrorHandler = NULL;
521 :
522 0 : int XIOErrorHdl(Display *pDisplay)
523 : {
524 0 : if (::osl::Thread::getCurrentIdentifier() != Application::GetMainThreadIdentifier())
525 : {
526 0 : pthread_exit(NULL);
527 : return 0;
528 : }
529 0 : return aOrigXIOErrorHandler ? aOrigXIOErrorHandler(pDisplay) : 0;
530 : }
531 :
532 0 : GtkData::~GtkData()
533 : {
534 0 : Yield( true, true );
535 0 : g_warning ("TESTME: We used to have a stop-timer here, but the central code should do this");
536 :
537 : // sanity check: at this point nobody should be yielding, but wake them
538 : // up anyway before the condition they're waiting on gets destroyed.
539 0 : osl_setCondition( m_aDispatchCondition );
540 :
541 0 : osl_acquireMutex( m_aDispatchMutex );
542 0 : if (m_pUserEvent)
543 : {
544 0 : g_source_destroy (m_pUserEvent);
545 0 : g_source_unref (m_pUserEvent);
546 0 : m_pUserEvent = NULL;
547 : }
548 0 : osl_destroyCondition( m_aDispatchCondition );
549 0 : osl_releaseMutex( m_aDispatchMutex );
550 0 : osl_destroyMutex( m_aDispatchMutex );
551 0 : XSetIOErrorHandler(aOrigXIOErrorHandler);
552 0 : }
553 :
554 0 : void GtkData::Dispose()
555 : {
556 0 : deInitNWF();
557 0 : }
558 :
559 0 : void GtkData::Yield( bool bWait, bool bHandleAllCurrentEvents )
560 : {
561 : /* #i33212# only enter g_main_context_iteration in one thread at any one
562 : * time, else one of them potentially will never end as long as there is
563 : * another thread in in there. Having only one yieldin thread actually dispatch
564 : * fits the vcl event model (see e.g. the generic plugin).
565 : */
566 0 : bool bDispatchThread = false;
567 0 : bool bWasEvent = false;
568 : {
569 : // release YieldMutex (and re-acquire at block end)
570 0 : SalYieldMutexReleaser aReleaser;
571 0 : if( osl_tryToAcquireMutex( m_aDispatchMutex ) )
572 0 : bDispatchThread = true;
573 0 : else if( ! bWait )
574 0 : return; // someone else is waiting already, return
575 :
576 0 : if( bDispatchThread )
577 : {
578 0 : int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
579 0 : gboolean wasOneEvent = TRUE;
580 0 : while( nMaxEvents-- && wasOneEvent )
581 : {
582 0 : wasOneEvent = g_main_context_iteration( NULL, FALSE );
583 0 : if( wasOneEvent )
584 0 : bWasEvent = true;
585 : }
586 0 : if( bWait && ! bWasEvent )
587 0 : bWasEvent = g_main_context_iteration( NULL, TRUE ) != 0;
588 : }
589 0 : else if( bWait )
590 : {
591 : /* #i41693# in case the dispatch thread hangs in join
592 : * for this thread the condition will never be set
593 : * workaround: timeout of 1 second a emergency exit
594 : */
595 : // we are the dispatch thread
596 0 : osl_resetCondition( m_aDispatchCondition );
597 0 : TimeValue aValue = { 1, 0 };
598 0 : osl_waitCondition( m_aDispatchCondition, &aValue );
599 0 : }
600 : }
601 :
602 0 : if( bDispatchThread )
603 : {
604 0 : osl_releaseMutex( m_aDispatchMutex );
605 0 : if( bWasEvent )
606 0 : osl_setCondition( m_aDispatchCondition ); // trigger non dispatch thread yields
607 : }
608 : }
609 :
610 0 : void GtkData::Init()
611 : {
612 : int i;
613 : #if OSL_DEBUG_LEVEL > 1
614 : fprintf( stderr, "GtkMainloop::Init()\n" );
615 : #endif
616 0 : XrmInitialize();
617 :
618 : #if !GTK_CHECK_VERSION(3,0,0)
619 0 : gtk_set_locale();
620 : #endif
621 :
622 : /*
623 : * open connection to X11 Display
624 : * try in this order:
625 : * o -display command line parameter,
626 : * o $DISPLAY environment variable
627 : * o default display
628 : */
629 :
630 0 : GdkDisplay *pGdkDisp = NULL;
631 :
632 : // is there a -display command line parameter?
633 0 : rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
634 0 : int nParams = osl_getCommandArgCount();
635 0 : rtl::OString aDisplay;
636 0 : rtl::OUString aParam, aBin;
637 0 : char** pCmdLineAry = new char*[ nParams+1 ];
638 0 : osl_getExecutableFile( &aParam.pData );
639 0 : osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData );
640 0 : pCmdLineAry[0] = g_strdup( OUStringToOString( aBin, aEnc ).getStr() );
641 0 : for (i=0; i<nParams; i++)
642 : {
643 0 : osl_getCommandArg(i, &aParam.pData );
644 0 : OString aBParam( OUStringToOString( aParam, aEnc ) );
645 :
646 0 : if( aParam == "-display" || aParam == "--display" )
647 : {
648 0 : pCmdLineAry[i+1] = g_strdup( "--display" );
649 0 : osl_getCommandArg(i+1, &aParam.pData );
650 0 : aDisplay = rtl::OUStringToOString( aParam, aEnc );
651 : }
652 : else
653 0 : pCmdLineAry[i+1] = g_strdup( aBParam.getStr() );
654 0 : }
655 : // add executable
656 0 : nParams++;
657 :
658 0 : g_set_application_name(SalGenericSystem::getFrameClassName());
659 :
660 : // Set consistant name of the root accessible
661 0 : rtl::OUString aAppName = Application::GetAppName();
662 0 : if( !aAppName.isEmpty() )
663 : {
664 0 : rtl::OString aPrgName = rtl::OUStringToOString(aAppName, aEnc);
665 0 : g_set_prgname(aPrgName.getStr());
666 : }
667 :
668 : // init gtk/gdk
669 0 : gtk_init_check( &nParams, &pCmdLineAry );
670 0 : gdk_error_trap_push();
671 0 : aOrigXIOErrorHandler = XSetIOErrorHandler(XIOErrorHdl);
672 :
673 0 : for (i = 0; i < nParams; i++ )
674 0 : g_free( pCmdLineAry[i] );
675 0 : delete [] pCmdLineAry;
676 :
677 : #if OSL_DEBUG_LEVEL > 1
678 : if (g_getenv ("SAL_DEBUG_UPDATES"))
679 : gdk_window_set_debug_updates (TRUE);
680 : #endif
681 :
682 0 : pGdkDisp = gdk_display_get_default();
683 0 : if ( !pGdkDisp )
684 : {
685 0 : rtl::OUString aProgramFileURL;
686 0 : osl_getExecutableFile( &aProgramFileURL.pData );
687 0 : rtl::OUString aProgramSystemPath;
688 0 : osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData);
689 : rtl::OString aProgramName = rtl::OUStringToOString(
690 : aProgramSystemPath,
691 0 : osl_getThreadTextEncoding() );
692 : fprintf( stderr, "%s X11 error: Can't open display: %s\n",
693 0 : aProgramName.getStr(), aDisplay.getStr());
694 0 : fprintf( stderr, " Set DISPLAY environment variable, use -display option\n");
695 0 : fprintf( stderr, " or check permissions of your X-Server\n");
696 0 : fprintf( stderr, " (See \"man X\" resp. \"man xhost\" for details)\n");
697 0 : fflush( stderr );
698 0 : exit(0);
699 : }
700 :
701 : /*
702 : * if a -display switch was used, we need
703 : * to set the environment accoringly since
704 : * the clipboard build another connection
705 : * to the xserver using $DISPLAY
706 : */
707 0 : rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("DISPLAY"));
708 0 : const gchar *name = gdk_display_get_name( pGdkDisp );
709 0 : rtl::OUString envValue(name, strlen(name), aEnc);
710 0 : osl_setEnvironment(envVar.pData, envValue.pData);
711 :
712 0 : GtkSalDisplay *pDisplay = new GtkSalDisplay( pGdkDisp );
713 0 : SetDisplay( pDisplay );
714 :
715 : #if !GTK_CHECK_VERSION(3,0,0)
716 0 : Display *pDisp = gdk_x11_display_get_xdisplay( pGdkDisp );
717 :
718 0 : gdk_error_trap_push();
719 0 : SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp );
720 0 : bool bErrorOccured = gdk_error_trap_pop() != 0;
721 0 : gdk_error_trap_push();
722 0 : pKbdExtension->UseExtension( bErrorOccured );
723 0 : gdk_error_trap_pop();
724 0 : GetGtkDisplay()->SetKbdExtension( pKbdExtension );
725 : #else
726 : # warning unwind keyboard extension bits
727 : #endif
728 :
729 : // add signal handler to notify screen size changes
730 0 : int nScreens = gdk_display_get_n_screens( pGdkDisp );
731 0 : for( int n = 0; n < nScreens; n++ )
732 : {
733 0 : GdkScreen *pScreen = gdk_display_get_screen( pGdkDisp, n );
734 0 : if( pScreen )
735 : {
736 0 : pDisplay->screenSizeChanged( pScreen );
737 0 : pDisplay->monitorsChanged( pScreen );
738 0 : g_signal_connect( G_OBJECT(pScreen), "size-changed",
739 0 : G_CALLBACK(signalScreenSizeChanged), pDisplay );
740 0 : if( ! gtk_check_version( 2, 14, 0 ) ) // monitors-changed came in with 2.14, avoid an assertion
741 0 : g_signal_connect( G_OBJECT(pScreen), "monitors-changed",
742 0 : G_CALLBACK(signalMonitorsChanged), GetGtkDisplay() );
743 : }
744 0 : }
745 0 : }
746 :
747 0 : void GtkData::ErrorTrapPush()
748 : {
749 0 : gdk_error_trap_push ();
750 0 : }
751 :
752 0 : bool GtkData::ErrorTrapPop( bool bIgnoreError )
753 : {
754 : #if GTK_CHECK_VERSION(3,0,0)
755 : if( bIgnoreError )
756 : {
757 : gdk_error_trap_pop_ignored (); // faster
758 : return false;
759 : }
760 : #else
761 : (void) bIgnoreError;
762 : #endif
763 0 : return gdk_error_trap_pop () != 0;
764 : }
765 :
766 : extern "C" {
767 :
768 : struct SalGtkTimeoutSource {
769 : GSource aParent;
770 : GTimeVal aFireTime;
771 : GtkSalTimer *pInstance;
772 : };
773 :
774 0 : static void sal_gtk_timeout_defer( SalGtkTimeoutSource *pTSource )
775 : {
776 0 : g_get_current_time( &pTSource->aFireTime );
777 0 : g_time_val_add( &pTSource->aFireTime, pTSource->pInstance->m_nTimeoutMS * 1000 );
778 0 : }
779 :
780 0 : static gboolean sal_gtk_timeout_expired( SalGtkTimeoutSource *pTSource,
781 : gint *nTimeoutMS, GTimeVal *pTimeNow )
782 : {
783 0 : glong nDeltaSec = pTSource->aFireTime.tv_sec - pTimeNow->tv_sec;
784 0 : glong nDeltaUSec = pTSource->aFireTime.tv_usec - pTimeNow->tv_usec;
785 0 : if( nDeltaSec < 0 || ( nDeltaSec == 0 && nDeltaUSec < 0) )
786 : {
787 0 : *nTimeoutMS = 0;
788 0 : return TRUE;
789 : }
790 0 : if( nDeltaUSec < 0 )
791 : {
792 0 : nDeltaUSec += 1000000;
793 0 : nDeltaSec -= 1;
794 : }
795 : // if the clock changes backwards we need to cope ...
796 0 : if( (unsigned long) nDeltaSec > 1 + ( pTSource->pInstance->m_nTimeoutMS / 1000 ) )
797 : {
798 0 : sal_gtk_timeout_defer( pTSource );
799 0 : return TRUE;
800 : }
801 :
802 0 : *nTimeoutMS = MIN( G_MAXINT, ( nDeltaSec * 1000 + (nDeltaUSec + 999) / 1000 ) );
803 :
804 0 : return *nTimeoutMS == 0;
805 : }
806 :
807 0 : static gboolean sal_gtk_timeout_prepare( GSource *pSource, gint *nTimeoutMS )
808 : {
809 0 : SalGtkTimeoutSource *pTSource = (SalGtkTimeoutSource *)pSource;
810 :
811 : GTimeVal aTimeNow;
812 0 : g_get_current_time( &aTimeNow );
813 :
814 0 : return sal_gtk_timeout_expired( pTSource, nTimeoutMS, &aTimeNow );
815 : }
816 :
817 0 : static gboolean sal_gtk_timeout_check( GSource *pSource )
818 : {
819 0 : SalGtkTimeoutSource *pTSource = (SalGtkTimeoutSource *)pSource;
820 :
821 : GTimeVal aTimeNow;
822 0 : g_get_current_time( &aTimeNow );
823 :
824 : return ( pTSource->aFireTime.tv_sec < aTimeNow.tv_sec ||
825 : ( pTSource->aFireTime.tv_sec == aTimeNow.tv_sec &&
826 0 : pTSource->aFireTime.tv_usec < aTimeNow.tv_usec ) );
827 : }
828 :
829 0 : static gboolean sal_gtk_timeout_dispatch( GSource *pSource, GSourceFunc, gpointer )
830 : {
831 0 : SalGtkTimeoutSource *pTSource = (SalGtkTimeoutSource *)pSource;
832 :
833 0 : if( !pTSource->pInstance )
834 0 : return FALSE;
835 :
836 0 : SalData *pSalData = GetSalData();
837 :
838 0 : osl::SolarGuard aGuard( pSalData->m_pInstance->GetYieldMutex() );
839 :
840 0 : sal_gtk_timeout_defer( pTSource );
841 :
842 0 : ImplSVData* pSVData = ImplGetSVData();
843 0 : if( pSVData->mpSalTimer )
844 0 : pSVData->mpSalTimer->CallCallback();
845 :
846 0 : return TRUE;
847 : }
848 :
849 : static GSourceFuncs sal_gtk_timeout_funcs =
850 : {
851 : sal_gtk_timeout_prepare,
852 : sal_gtk_timeout_check,
853 : sal_gtk_timeout_dispatch,
854 : NULL, NULL, NULL
855 : };
856 : }
857 :
858 : static SalGtkTimeoutSource *
859 0 : create_sal_gtk_timeout( GtkSalTimer *pTimer )
860 : {
861 0 : GSource *pSource = g_source_new( &sal_gtk_timeout_funcs, sizeof( SalGtkTimeoutSource ) );
862 0 : SalGtkTimeoutSource *pTSource = (SalGtkTimeoutSource *)pSource;
863 0 : pTSource->pInstance = pTimer;
864 :
865 : // #i36226# timers should be executed with lower priority
866 : // than XEvents like in generic plugin
867 0 : g_source_set_priority( pSource, G_PRIORITY_LOW );
868 0 : g_source_set_can_recurse( pSource, TRUE );
869 : g_source_set_callback( pSource,
870 : /* unused dummy */ g_idle_remove_by_data,
871 0 : NULL, NULL );
872 0 : g_source_attach( pSource, g_main_context_default() );
873 :
874 0 : sal_gtk_timeout_defer( pTSource );
875 :
876 0 : return pTSource;
877 : }
878 :
879 0 : GtkSalTimer::GtkSalTimer()
880 0 : : m_pTimeout( NULL )
881 : {
882 0 : }
883 :
884 0 : GtkSalTimer::~GtkSalTimer()
885 : {
886 0 : GtkInstance *pInstance = static_cast<GtkInstance *>(GetSalData()->m_pInstance);
887 0 : pInstance->RemoveTimer( this );
888 0 : Stop();
889 0 : }
890 :
891 0 : bool GtkSalTimer::Expired()
892 : {
893 0 : if( !m_pTimeout )
894 0 : return false;
895 :
896 0 : gint nDummy = 0;
897 : GTimeVal aTimeNow;
898 0 : g_get_current_time( &aTimeNow );
899 0 : return !!sal_gtk_timeout_expired( m_pTimeout, &nDummy, &aTimeNow);
900 : }
901 :
902 0 : void GtkSalTimer::Start( sal_uLong nMS )
903 : {
904 0 : m_nTimeoutMS = nMS; // for restarting
905 0 : Stop(); // FIXME: ideally re-use an existing m_pTimeout
906 0 : m_pTimeout = create_sal_gtk_timeout( this );
907 0 : }
908 :
909 0 : void GtkSalTimer::Stop()
910 : {
911 0 : if( m_pTimeout )
912 : {
913 0 : g_source_destroy( (GSource *)m_pTimeout );
914 0 : g_source_unref( (GSource *)m_pTimeout );
915 0 : m_pTimeout = NULL;
916 : }
917 0 : }
918 :
919 0 : gboolean GtkData::userEventFn( gpointer data )
920 : {
921 0 : gboolean bContinue = FALSE;
922 0 : GtkData *pThis = (GtkData *) data;
923 0 : SalGenericData *pData = GetGenericData();
924 0 : osl::SolarGuard aGuard( pData->m_pInstance->GetYieldMutex() );
925 0 : const SalGenericDisplay *pDisplay = pData->GetDisplay();
926 0 : if (pDisplay)
927 : {
928 : OSL_ASSERT(static_cast<const SalGenericDisplay *>(pThis->GetGtkDisplay()) == pDisplay);
929 0 : pThis->GetGtkDisplay()->EventGuardAcquire();
930 :
931 0 : if( !pThis->GetGtkDisplay()->HasUserEvents() )
932 : {
933 0 : if( pThis->m_pUserEvent )
934 : {
935 0 : g_source_unref (pThis->m_pUserEvent);
936 0 : pThis->m_pUserEvent = NULL;
937 : }
938 0 : bContinue = FALSE;
939 : }
940 : else
941 0 : bContinue = TRUE;
942 :
943 0 : pThis->GetGtkDisplay()->EventGuardRelease();
944 :
945 0 : pThis->GetGtkDisplay()->DispatchInternalEvent();
946 : }
947 :
948 0 : return bContinue;
949 : }
950 :
951 : extern "C" {
952 0 : static gboolean call_userEventFn( void *data )
953 : {
954 0 : SolarMutexGuard aGuard;
955 0 : return GtkData::userEventFn( data );
956 : }
957 : }
958 :
959 : // hEventGuard_ held during this invocation
960 0 : void GtkData::PostUserEvent()
961 : {
962 0 : if (m_pUserEvent)
963 0 : g_main_context_wakeup (NULL); // really needed ?
964 : else // nothing pending anyway
965 : {
966 0 : m_pUserEvent = g_idle_source_new();
967 0 : g_source_set_priority (m_pUserEvent, G_PRIORITY_HIGH);
968 0 : g_source_set_can_recurse (m_pUserEvent, TRUE);
969 : g_source_set_callback (m_pUserEvent, call_userEventFn,
970 0 : (gpointer) this, NULL);
971 0 : g_source_attach (m_pUserEvent, g_main_context_default ());
972 : }
973 0 : }
974 :
975 0 : void GtkSalDisplay::PostUserEvent()
976 : {
977 0 : GetGtkSalData()->PostUserEvent();
978 0 : }
979 :
980 0 : void GtkSalDisplay::deregisterFrame( SalFrame* pFrame )
981 : {
982 0 : if( m_pCapture == pFrame )
983 : {
984 0 : static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
985 0 : m_pCapture = NULL;
986 : }
987 0 : SalGenericDisplay::deregisterFrame( pFrame );
988 0 : }
989 :
990 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|