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 <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <math.h>
24 #include <unistd.h>
25
26 #if defined(__sun) || defined(AIX)
27 #include <osl/module.h>
28 #endif
29
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include <X11/XKBlib.h>
33
34 #include <X11/cursorfont.h>
35 #include <unx/x11_cursors/salcursors.h>
36 #include <unx/x11_cursors/invert50.h>
37 #ifdef __sun
38 #define XK_KOREAN
39 #endif
40 #include <X11/keysym.h>
41 #include <X11/Xatom.h>
42
43 #ifdef USE_XINERAMA_XORG
44 #include <X11/extensions/Xinerama.h>
45 #endif
46
47 #include <opengl/zone.hxx>
48
49 #include <i18nlangtag/languagetag.hxx>
50 #include <tools/debug.hxx>
51 #include <vcl/svapp.hxx>
52 #include <vcl/settings.hxx>
53
54 #include <sal/log.hxx>
55 #include <sal/types.h>
56 #include <unx/i18n_im.hxx>
57 #include <unx/i18n_xkb.hxx>
58 #include <unx/saldisp.hxx>
59 #include <unx/saldata.hxx>
60 #include <salinst.hxx>
61 #include <unx/salframe.h>
62 #include <vcl/keycodes.hxx>
63 #include <unx/salbmp.h>
64 #include <osl/diagnose.h>
65 #include <unx/salobj.h>
66 #include <unx/sm.hxx>
67 #include <unx/wmadaptor.hxx>
68 #include <unx/x11/xrender_peer.hxx>
69 #include <unx/glyphcache.hxx>
70
71 #include <vcl/opengl/OpenGLHelper.hxx>
72
73 #include <poll.h>
74 #include <memory>
75 #include <vector>
76
77 /* From <X11/Intrinsic.h> */
78 typedef unsigned long Pixel;
79
80 using namespace vcl_sal;
81
82 #ifdef DBG_UTIL
Null(const char * p)83 static const char *Null( const char *p ) { return p ? p : ""; }
GetEnv(const char * p)84 static const char *GetEnv( const char *p ) { return Null( getenv( p ) ); }
KeyStr(KeySym n)85 static const char *KeyStr( KeySym n ) { return Null( XKeysymToString( n ) ); }
86
GetAtomName(Display * d,Atom a)87 static const char *GetAtomName( Display *d, Atom a )
88 { return Null( XGetAtomName( d, a ) ); }
89
Hypothenuse(long w,long h)90 static double Hypothenuse( long w, long h )
91 { return sqrt( static_cast<double>((w*w)+(h*h)) ); }
92 #endif
93
ColorDiff(int r,int g,int b)94 static int ColorDiff( int r, int g, int b )
95 { return (r*r)+(g*g)+(b*b); }
96
ColorDiff(Color c1,int r,int g,int b)97 static int ColorDiff( Color c1, int r, int g, int b )
98 { return ColorDiff( static_cast<int>(c1.GetRed())-r,
99 static_cast<int>(c1.GetGreen())-g,
100 static_cast<int>(c1.GetBlue())-b ); }
101
sal_Shift(Pixel nMask)102 static int sal_Shift( Pixel nMask )
103 {
104 int i = 24;
105 if( nMask < 0x00010000 ) { nMask <<= 16; i -= 16; }
106 if( nMask < 0x01000000 ) { nMask <<= 8; i -= 8; }
107 if( nMask < 0x10000000 ) { nMask <<= 4; i -= 4; }
108 if( nMask < 0x40000000 ) { nMask <<= 2; i -= 2; }
109 if( nMask < 0x80000000 ) { i -= 1; }
110 return i;
111 }
112
sal_significantBits(Pixel nMask)113 static int sal_significantBits( Pixel nMask )
114 {
115 int nRotate = sizeof(Pixel)*4;
116 int nBits = 0;
117 while( nRotate-- )
118 {
119 if( nMask & 1 )
120 nBits++;
121 nMask >>= 1;
122 }
123 return nBits;
124 }
125
126 // check if the resolution is sane
sal_ValidDPI(long nDPI)127 static bool sal_ValidDPI(long nDPI)
128 {
129 return (nDPI >= 50) && (nDPI <= 500);
130 }
131
sal_GetVisualInfo(Display * pDisplay,XID nVID,XVisualInfo & rVI)132 static bool sal_GetVisualInfo( Display *pDisplay, XID nVID, XVisualInfo &rVI )
133 {
134 int nInfos;
135 XVisualInfo aTemplate;
136 XVisualInfo*pInfo;
137
138 aTemplate.visualid = nVID;
139
140 pInfo = XGetVisualInfo( pDisplay, VisualIDMask, &aTemplate, &nInfos );
141 if( !pInfo )
142 return false;
143
144 rVI = *pInfo;
145 XFree( pInfo );
146
147 SAL_WARN_IF( rVI.visualid != nVID, "vcl",
148 "sal_GetVisualInfo: could not get correct visual by visualId" );
149 return true;
150 }
151
152 extern "C" srv_vendor_t
sal_GetServerVendor(Display * p_display)153 sal_GetServerVendor( Display *p_display )
154 {
155 struct vendor_t {
156 srv_vendor_t e_vendor; // vendor as enum
157 const char* p_name; // vendor name as returned by VendorString()
158 unsigned int n_len; // number of chars to compare
159 };
160
161 static const vendor_t vendorlist[] = {
162 { vendor_sun, "Sun Microsystems, Inc.", 10 },
163 };
164
165 // handle regular server vendors
166 char *p_name = ServerVendor( p_display );
167 for (auto const & vendor : vendorlist)
168 {
169 if ( strncmp (p_name, vendor.p_name, vendor.n_len) == 0 )
170 return vendor.e_vendor;
171 }
172
173 // vendor not found in list
174 return vendor_unknown;
175 }
176
BestOpenGLVisual(Display * pDisplay,int nScreen,XVisualInfo & rVI)177 bool SalDisplay::BestOpenGLVisual(Display* pDisplay, int nScreen, XVisualInfo& rVI)
178 {
179 OpenGLZone aZone;
180
181 XVisualInfo* pVI;
182 int aAttrib[] = { GLX_RGBA,
183 GLX_RED_SIZE, 8,
184 GLX_GREEN_SIZE, 8,
185 GLX_BLUE_SIZE, 8,
186 GLX_DEPTH_SIZE, 24,
187 GLX_STENCIL_SIZE, 8,
188 None };
189
190 pVI = glXChooseVisual( pDisplay, nScreen, aAttrib );
191 if( !pVI )
192 return false;
193
194 rVI = *pVI;
195 XFree( pVI );
196
197 CHECK_GL_ERROR();
198 return true;
199 }
200
BestVisual(Display * pDisplay,int nScreen,XVisualInfo & rVI)201 bool SalDisplay::BestVisual( Display *pDisplay,
202 int nScreen,
203 XVisualInfo &rVI )
204 {
205 VisualID nDefVID = XVisualIDFromVisual( DefaultVisual( pDisplay, nScreen ) );
206 VisualID nVID = 0;
207 char *pVID = getenv( "SAL_VISUAL" );
208 if( pVID )
209 sscanf( pVID, "%li", &nVID );
210
211 if( nVID && sal_GetVisualInfo( pDisplay, nVID, rVI ) )
212 return rVI.visualid == nDefVID;
213
214 bool bUseOpenGL = OpenGLHelper::isVCLOpenGLEnabled();
215 if (bUseOpenGL && BestOpenGLVisual(pDisplay, nScreen, rVI))
216 return rVI.visualid == nDefVID;
217
218 XVisualInfo aVI;
219 aVI.screen = nScreen;
220 // get all visuals
221 int nVisuals;
222 XVisualInfo* pVInfos = XGetVisualInfo( pDisplay, VisualScreenMask,
223 &aVI, &nVisuals );
224 // pVInfos should contain at least one visual, otherwise
225 // we're in trouble
226 std::vector<int> aWeights(nVisuals);
227 int i;
228 for( i = 0; i < nVisuals; i++ )
229 {
230 bool bUsable = false;
231 int nTrueColor = 1;
232
233 if ( pVInfos[i].screen != nScreen )
234 {
235 bUsable = false;
236 }
237 else if( pVInfos[i].c_class == TrueColor )
238 {
239 nTrueColor = 2048;
240 if( pVInfos[i].depth == 24 )
241 bUsable = true;
242 }
243 else if( pVInfos[i].c_class == PseudoColor )
244 {
245 bUsable = true;
246 }
247 aWeights[i] = bUsable ? nTrueColor*pVInfos[i].depth : -1024;
248 aWeights[i] -= pVInfos[ i ].visualid;
249 }
250
251 int nBestVisual = 0;
252 int nBestWeight = -1024;
253 for( i = 0; i < nVisuals; i++ )
254 {
255 if (aWeights[i] > nBestWeight)
256 {
257 nBestWeight = aWeights[i];
258 nBestVisual = i;
259 }
260 }
261
262 rVI = pVInfos[ nBestVisual ];
263
264 XFree( pVInfos );
265 return rVI.visualid == nDefVID;
266 }
267
SalDisplay(Display * display)268 SalDisplay::SalDisplay( Display *display ) :
269 pXLib_( nullptr ),
270 mpKbdExtension( nullptr ),
271 pDisp_( display ),
272 m_nXDefaultScreen( 0 ),
273 nMaxRequestSize_( 0 ),
274 meServerVendor( vendor_unknown ),
275 bNumLockFromXS_( false ),
276 nNumLockIndex_( 0 ),
277 nShiftKeySym_( 0 ),
278 nCtrlKeySym_( 0 ),
279 nMod1KeySym_( 0 ),
280 m_bXinerama( false ),
281 m_nLastUserEventTime( CurrentTime )
282 {
283 #if OSL_DEBUG_LEVEL > 1
284 fprintf( stderr, "SalDisplay::SalDisplay()\n" );
285 #endif
286 GenericUnixSalData *pData = GetGenericUnixSalData();
287
288 SAL_WARN_IF( pData->GetDisplay(), "vcl", "Second SalDisplay created !!!" );
289 pData->SetDisplay( this );
290
291 m_nXDefaultScreen = SalX11Screen( DefaultScreen( pDisp_ ) );
292 }
293
~SalDisplay()294 SalDisplay::~SalDisplay()
295 {
296 #if OSL_DEBUG_LEVEL > 1
297 fprintf( stderr, "SalDisplay::~SalDisplay()\n" );
298 #endif
299 if( pDisp_ )
300 {
301 doDestruct();
302 #if OSL_DEBUG_LEVEL > 1
303 fprintf( stderr, "display %p closed\n", pDisp_ );
304 #endif
305 pDisp_ = nullptr;
306 }
307 // don't do this in doDestruct since RandR extension adds hooks into Display
308 // that is XCloseDisplay still needs the RandR library if it was used
309 DeInitRandR();
310 }
311
doDestruct()312 void SalDisplay::doDestruct()
313 {
314 GenericUnixSalData *pData = GetGenericUnixSalData();
315
316 m_pWMAdaptor.reset();
317 X11SalBitmap::ImplDestroyCache();
318
319 if (ImplGetSVData())
320 {
321 SalDisplay* pSalDisp = vcl_sal::getSalDisplay(pData);
322 Display* const pX11Disp = pSalDisp->GetDisplay();
323 int nMaxScreens = pSalDisp->GetXScreenCount();
324 XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
325
326 for (int i = 0; i < nMaxScreens; i++)
327 {
328 SalDisplay::RenderEntryMap& rMap = pSalDisp->GetRenderEntries(SalX11Screen(i));
329 for (auto const& elem : rMap)
330 {
331 if (elem.second.m_aPixmap)
332 ::XFreePixmap(pX11Disp, elem.second.m_aPixmap);
333 if (elem.second.m_aPicture)
334 rRenderPeer.FreePicture(elem.second.m_aPicture);
335 }
336 rMap.clear();
337 }
338 }
339 GlyphCache::GetInstance().ClearFontCache();
340
341 if( IsDisplay() )
342 {
343 delete mpKbdExtension;
344 mpKbdExtension = nullptr;
345
346 for( size_t i = 0; i < m_aScreens.size(); i++ )
347 {
348 ScreenData& rData = m_aScreens[i];
349 if( rData.m_bInit )
350 {
351 if( rData.m_aMonoGC != rData.m_aCopyGC )
352 XFreeGC( pDisp_, rData.m_aMonoGC );
353 XFreeGC( pDisp_, rData.m_aCopyGC );
354 XFreeGC( pDisp_, rData.m_aAndInvertedGC );
355 XFreeGC( pDisp_, rData.m_aAndGC );
356 XFreeGC( pDisp_, rData.m_aOrGC );
357 XFreeGC( pDisp_, rData.m_aStippleGC );
358 XFreePixmap( pDisp_, rData.m_hInvert50 );
359 XDestroyWindow( pDisp_, rData.m_aRefWindow );
360 Colormap aColMap = rData.m_aColormap.GetXColormap();
361 if( aColMap != None && aColMap != DefaultColormap( pDisp_, i ) )
362 XFreeColormap( pDisp_, aColMap );
363 }
364 }
365
366 for( const Cursor & aCsr : aPointerCache_ )
367 {
368 if( aCsr )
369 XFreeCursor( pDisp_, aCsr );
370 }
371
372 if( pXLib_ )
373 pXLib_->Remove( ConnectionNumber( pDisp_ ) );
374 }
375
376 if( pData->GetDisplay() == static_cast<const SalGenericDisplay *>( this ) )
377 pData->SetDisplay( nullptr );
378 }
379
DisplayHasEvent(int fd,void * data)380 static int DisplayHasEvent( int fd, void * data )
381 {
382 auto pDisplay = static_cast<SalX11Display *>(data);
383 SAL_WARN_IF( ConnectionNumber( pDisplay->GetDisplay() ) != fd, "vcl",
384 "wrong fd in DisplayHasEvent" );
385 if( ! pDisplay->IsDisplay() )
386 return 0;
387
388 bool result;
389
390 SolarMutexGuard aGuard;
391 result = pDisplay->IsEvent();
392 return int(result);
393 }
DisplayQueue(int fd,void * data)394 static int DisplayQueue( int fd, void * data )
395 {
396 auto pDisplay = static_cast<SalX11Display *>(data);
397 SAL_WARN_IF( ConnectionNumber( pDisplay->GetDisplay() ) != fd, "vcl",
398 "wrong fd in DisplayHasEvent" );
399 int result;
400
401 SolarMutexGuard aGuard;
402 result = XEventsQueued( pDisplay->GetDisplay(),
403 QueuedAfterReading );
404 return result;
405 }
DisplayYield(int fd,void * data)406 static int DisplayYield( int fd, void * data )
407 {
408 auto pDisplay = static_cast<SalX11Display *>(data);
409 SAL_WARN_IF( ConnectionNumber( pDisplay->GetDisplay() ) != fd, "vcl",
410 "wrong fd in DisplayHasEvent" );
411
412 SolarMutexGuard aGuard;
413 pDisplay->Yield();
414 return 1;
415 }
416
SalX11Display(Display * display)417 SalX11Display::SalX11Display( Display *display )
418 : SalDisplay( display )
419 {
420 Init();
421
422 pXLib_ = GetX11SalData()->GetLib();
423 pXLib_->Insert( ConnectionNumber( pDisp_ ),
424 this,
425 reinterpret_cast<YieldFunc>(DisplayHasEvent),
426 reinterpret_cast<YieldFunc>(DisplayQueue),
427 reinterpret_cast<YieldFunc>(DisplayYield) );
428 }
429
~SalX11Display()430 SalX11Display::~SalX11Display()
431 {
432 #if OSL_DEBUG_LEVEL > 1
433 fprintf( stderr, "SalX11Display::~SalX11Display()\n" );
434 #endif
435 if( pDisp_ )
436 {
437 doDestruct();
438 XCloseDisplay( pDisp_ );
439 pDisp_ = nullptr;
440 }
441 }
442
TriggerUserEventProcessing()443 void SalX11Display::TriggerUserEventProcessing()
444 {
445 if( pXLib_ )
446 pXLib_->TriggerUserEventProcessing();
447 }
448
449 SalDisplay::ScreenData *
initScreen(SalX11Screen nXScreen) const450 SalDisplay::initScreen( SalX11Screen nXScreen ) const
451 {
452 if( nXScreen.getXScreen() >= m_aScreens.size() )
453 nXScreen = m_nXDefaultScreen;
454 ScreenData* pSD = const_cast<ScreenData *>(&m_aScreens[nXScreen.getXScreen()]);
455 if( pSD->m_bInit )
456 return nullptr;
457 pSD->m_bInit = true;
458
459 XVisualInfo aVI;
460 Colormap aColMap;
461
462 if( SalDisplay::BestVisual( pDisp_, nXScreen.getXScreen(), aVI ) ) // DefaultVisual
463 aColMap = DefaultColormap( pDisp_, nXScreen.getXScreen() );
464 else
465 aColMap = XCreateColormap( pDisp_,
466 RootWindow( pDisp_, nXScreen.getXScreen() ),
467 aVI.visual,
468 AllocNone );
469
470 Screen* pScreen = ScreenOfDisplay( pDisp_, nXScreen.getXScreen() );
471
472 pSD->m_aSize = Size( WidthOfScreen( pScreen ), HeightOfScreen( pScreen ) );
473 pSD->m_aRoot = RootWindow( pDisp_, nXScreen.getXScreen() );
474 pSD->m_aVisual = SalVisual( &aVI );
475 pSD->m_aColormap = SalColormap( this, aColMap, nXScreen );
476
477 // we're interested in configure notification of root windows
478 InitRandR( pSD->m_aRoot );
479
480 // - - - - - - - - - - Reference Window/Default Drawable - -
481 XSetWindowAttributes aXWAttributes;
482 aXWAttributes.border_pixel = 0;
483 aXWAttributes.background_pixel = 0;
484 aXWAttributes.colormap = aColMap;
485 pSD->m_aRefWindow = XCreateWindow( pDisp_,
486 pSD->m_aRoot,
487 0,0, 16,16, 0,
488 pSD->m_aVisual.GetDepth(),
489 InputOutput,
490 pSD->m_aVisual.GetVisual(),
491 CWBorderPixel|CWBackPixel|CWColormap,
492 &aXWAttributes );
493
494 // set client leader (session id gets set when session is started)
495 if( pSD->m_aRefWindow )
496 {
497 // client leader must have WM_CLIENT_LEADER pointing to itself
498 XChangeProperty( pDisp_,
499 pSD->m_aRefWindow,
500 XInternAtom( pDisp_, "WM_CLIENT_LEADER", False ),
501 XA_WINDOW,
502 32,
503 PropModeReplace,
504 reinterpret_cast<unsigned char*>(&pSD->m_aRefWindow),
505 1
506 );
507
508 OString aExec(OUStringToOString(SessionManagerClient::getExecName(), osl_getThreadTextEncoding()));
509 const char* argv[1];
510 argv[0] = aExec.getStr();
511 XSetCommand( pDisp_, pSD->m_aRefWindow, const_cast<char**>(argv), 1 );
512 XSelectInput( pDisp_, pSD->m_aRefWindow, PropertyChangeMask );
513
514 // - - - - - - - - - - GCs - - - - - - - - - - - - - - - - -
515 XGCValues values;
516 values.graphics_exposures = False;
517 values.fill_style = FillOpaqueStippled;
518 values.background = (1<<pSD->m_aVisual.GetDepth())-1;
519 values.foreground = 0;
520
521 pSD->m_aCopyGC = XCreateGC( pDisp_,
522 pSD->m_aRefWindow,
523 GCGraphicsExposures
524 | GCForeground
525 | GCBackground,
526 &values );
527 pSD->m_aAndInvertedGC= XCreateGC( pDisp_,
528 pSD->m_aRefWindow,
529 GCGraphicsExposures
530 | GCForeground
531 | GCBackground,
532 &values );
533 pSD->m_aAndGC = XCreateGC( pDisp_,
534 pSD->m_aRefWindow,
535 GCGraphicsExposures
536 | GCForeground
537 | GCBackground,
538 &values );
539 pSD->m_aOrGC = XCreateGC( pDisp_,
540 pSD->m_aRefWindow,
541 GCGraphicsExposures
542 | GCForeground
543 | GCBackground,
544 &values );
545 pSD->m_aStippleGC = XCreateGC( pDisp_,
546 pSD->m_aRefWindow,
547 GCGraphicsExposures
548 | GCFillStyle
549 | GCForeground
550 | GCBackground,
551 &values );
552
553 XSetFunction( pDisp_, pSD->m_aAndInvertedGC, GXandInverted );
554 XSetFunction( pDisp_, pSD->m_aAndGC, GXand );
555 // PowerPC Solaris 2.5 (XSun 3500) Bug: GXor = GXnop
556 XSetFunction( pDisp_, pSD->m_aOrGC, GXxor );
557
558 if( 1 == pSD->m_aVisual.GetDepth() )
559 {
560 XSetFunction( pDisp_, pSD->m_aCopyGC, GXcopyInverted );
561 pSD->m_aMonoGC = pSD->m_aCopyGC;
562 }
563 else
564 {
565 Pixmap hPixmap = XCreatePixmap( pDisp_, pSD->m_aRefWindow, 1, 1, 1 );
566 pSD->m_aMonoGC = XCreateGC( pDisp_,
567 hPixmap,
568 GCGraphicsExposures,
569 &values );
570 XFreePixmap( pDisp_, hPixmap );
571 }
572 pSD->m_hInvert50 = XCreateBitmapFromData( pDisp_,
573 pSD->m_aRefWindow,
574 reinterpret_cast<const char*>(invert50_bits),
575 invert50_width,
576 invert50_height );
577 }
578 return pSD;
579 }
580
Init()581 void SalDisplay::Init()
582 {
583 for( Cursor & aCsr : aPointerCache_ )
584 aCsr = None;
585
586 m_bXinerama = false;
587
588 int nDisplayScreens = ScreenCount( pDisp_ );
589 m_aScreens = std::vector<ScreenData>(nDisplayScreens);
590
591 bool bExactResolution = false;
592 /* #i15507#
593 * Xft resolution should take precedence since
594 * it is what modern desktops use.
595 */
596 const char* pValStr = XGetDefault( pDisp_, "Xft", "dpi" );
597 if( pValStr != nullptr )
598 {
599 const OString aValStr( pValStr );
600 const long nDPI = static_cast<long>(aValStr.toDouble());
601 // guard against insane resolution
602 if( sal_ValidDPI(nDPI) )
603 {
604 aResolution_ = Pair( nDPI, nDPI );
605 bExactResolution = true;
606 }
607 }
608 if( !bExactResolution )
609 {
610 /* if Xft.dpi is not set, try and find the DPI from the
611 * reported screen sizes and resolution. If there are multiple
612 * screens, just fall back to the default 96x96
613 */
614 long xDPI = 96;
615 long yDPI = 96;
616 if (m_aScreens.size() == 1) {
617 xDPI = static_cast<long>(round(DisplayWidth(pDisp_, 0)*25.4/DisplayWidthMM(pDisp_, 0)));
618 yDPI = static_cast<long>(round(DisplayHeight(pDisp_, 0)*25.4/DisplayHeightMM(pDisp_, 0)));
619 // if either is invalid set it equal to the other
620 if (!sal_ValidDPI(xDPI) && sal_ValidDPI(yDPI))
621 xDPI = yDPI;
622 if (!sal_ValidDPI(yDPI) && sal_ValidDPI(xDPI))
623 yDPI = xDPI;
624 // if both are invalid, reset them to the default
625 if (!sal_ValidDPI(xDPI) && !sal_ValidDPI(yDPI))
626 xDPI = yDPI = 96;
627 }
628 aResolution_ = Pair( xDPI, yDPI );
629 }
630
631 nMaxRequestSize_ = XExtendedMaxRequestSize( pDisp_ ) * 4;
632 if( !nMaxRequestSize_ )
633 nMaxRequestSize_ = XMaxRequestSize( pDisp_ ) * 4;
634
635 meServerVendor = sal_GetServerVendor(pDisp_);
636 X11SalBitmap::ImplCreateCache();
637
638 // - - - - - - - - - - Synchronize - - - - - - - - - - - - -
639 if( getenv( "SAL_SYNCHRONIZE" ) )
640 XSynchronize( pDisp_, True );
641
642 // - - - - - - - - - - Keyboardmapping - - - - - - - - - - -
643 ModifierMapping();
644
645 // - - - - - - - - - - Window Manager - - - - - - - - - - -
646 m_pWMAdaptor = ::vcl_sal::WMAdaptor::createWMAdaptor( this );
647
648 InitXinerama();
649
650 #ifdef DBG_UTIL
651 PrintInfo();
652 #endif
653 }
654
SetupInput()655 void SalX11Display::SetupInput()
656 {
657 GetGenericUnixSalData()->ErrorTrapPush();
658 SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp_ );
659 XSync( pDisp_, False );
660
661 bool bError = GetGenericUnixSalData()->ErrorTrapPop( false );
662 GetGenericUnixSalData()->ErrorTrapPush();
663 pKbdExtension->UseExtension( ! bError );
664 GetGenericUnixSalData()->ErrorTrapPop();
665
666 SetKbdExtension( pKbdExtension );
667 }
668
669 // Sound
Beep() const670 void SalDisplay::Beep() const
671 {
672 XBell( pDisp_, 100 );
673 }
674
675 // Keyboard
676
677 namespace {
678
InitXkb(Display * dpy)679 bool InitXkb(Display* dpy)
680 {
681 int nOpcode, nEvent, nError;
682 int nXkbMajor = XkbMajorVersion;
683 int nXkbMinor = XkbMinorVersion;
684
685 if (!XkbLibraryVersion(&nXkbMajor, &nXkbMinor))
686 return false;
687
688 return XkbQueryExtension(
689 dpy, &nOpcode, &nEvent, &nError, &nXkbMajor, &nXkbMinor);
690 }
691
GetKeySymMask(Display * dpy,KeySym nKeySym)692 unsigned int GetKeySymMask(Display* dpy, KeySym nKeySym)
693 {
694 int nMask = 0;
695 XModifierKeymap* pXmkMap = XGetModifierMapping(dpy);
696 KeyCode nKeyCode = XKeysymToKeycode(dpy, nKeySym);
697 if (nKeyCode == NoSymbol)
698 return 0;
699
700 for (int i = 0; i < 8; ++i)
701 {
702 KeyCode nThisKeyCode = pXmkMap->modifiermap[pXmkMap->max_keypermod*i];
703 if (nThisKeyCode == nKeyCode)
704 nMask = 1 << i;
705 }
706 XFreeModifiermap(pXmkMap);
707 return nMask;
708 }
709
710 }
711
SimulateKeyPress(sal_uInt16 nKeyCode)712 void SalDisplay::SimulateKeyPress( sal_uInt16 nKeyCode )
713 {
714 if (nKeyCode == KEY_CAPSLOCK)
715 {
716 Display* dpy = GetDisplay();
717 if (!InitXkb(dpy))
718 return;
719
720 unsigned int nMask = GetKeySymMask(dpy, XK_Caps_Lock);
721 XkbStateRec xkbState;
722 XkbGetState(dpy, XkbUseCoreKbd, &xkbState);
723 unsigned int nCapsLockState = xkbState.locked_mods & nMask;
724 if (nCapsLockState)
725 XkbLockModifiers (dpy, XkbUseCoreKbd, nMask, 0);
726 else
727 XkbLockModifiers (dpy, XkbUseCoreKbd, nMask, nMask);
728 }
729 }
730
GetIndicatorState() const731 KeyIndicatorState SalDisplay::GetIndicatorState() const
732 {
733 unsigned int _state = 0;
734 KeyIndicatorState nState = KeyIndicatorState::NONE;
735 XkbGetIndicatorState(pDisp_, XkbUseCoreKbd, &_state);
736
737 if (_state & 0x00000001)
738 nState |= KeyIndicatorState::CAPSLOCK;
739 if (_state & 0x00000002)
740 nState |= KeyIndicatorState::NUMLOCK;
741 if (_state & 0x00000004)
742 nState |= KeyIndicatorState::SCROLLLOCK;
743
744 return nState;
745 }
746
GetKeyNameFromKeySym(KeySym nKeySym) const747 OUString SalDisplay::GetKeyNameFromKeySym( KeySym nKeySym ) const
748 {
749 OUString aLang = Application::GetSettings().GetUILanguageTag().getLanguage();
750 OUString aRet;
751
752 // return an empty string for keysyms that are not bound to
753 // any key code
754 KeyCode aKeyCode = XKeysymToKeycode( GetDisplay(), nKeySym );
755 static_assert(NoSymbol == 0, "X11 inconsistency");
756 if( aKeyCode != NoSymbol )
757 {
758 if( !nKeySym )
759 aRet = "???";
760 else
761 {
762 aRet = ::vcl_sal::getKeysymReplacementName( aLang, nKeySym );
763 if( aRet.isEmpty() )
764 {
765 const char *pString = XKeysymToString( nKeySym );
766 if (pString)
767 {
768 int n = strlen( pString );
769 if( n > 2 && pString[n-2] == '_' )
770 aRet = OUString( pString, n-2, RTL_TEXTENCODING_ISO_8859_1 );
771 else
772 aRet = OUString( pString, n, RTL_TEXTENCODING_ISO_8859_1 );
773 }
774 else
775 aRet = "???";
776 }
777 }
778 }
779 return aRet;
780 }
781
sal_XModifier2Keysym(Display * pDisplay,XModifierKeymap const * pXModMap,int n)782 static KeySym sal_XModifier2Keysym( Display *pDisplay,
783 XModifierKeymap const *pXModMap,
784 int n )
785 {
786 return XkbKeycodeToKeysym( pDisplay,
787 pXModMap->modifiermap[n*pXModMap->max_keypermod],
788 0,0 );
789 }
790
ModifierMapping()791 void SalDisplay::ModifierMapping()
792 {
793 XModifierKeymap *pXModMap = XGetModifierMapping( pDisp_ );
794
795 bNumLockFromXS_ = True;
796 nShiftKeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, ShiftMapIndex );
797 nCtrlKeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, ControlMapIndex );
798 nMod1KeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, Mod1MapIndex );
799 // on Sun and SCO servers XLookupString does not account for NumLock
800 if( GetServerVendor() == vendor_sun )
801 {
802 KeyCode aNumLock = XKeysymToKeycode( pDisp_, XK_Num_Lock );
803
804 if( aNumLock ) for( int i = ShiftMapIndex; i <= Mod5MapIndex; i++ )
805 {
806 if( pXModMap->modifiermap[i*pXModMap->max_keypermod] == aNumLock )
807 {
808 bNumLockFromXS_ = False;
809 nNumLockIndex_ = i;
810 break;
811 }
812 }
813 }
814
815 XFreeModifiermap( pXModMap );
816 }
817
GetKeyName(sal_uInt16 nKeyCode) const818 OUString SalDisplay::GetKeyName( sal_uInt16 nKeyCode ) const
819 {
820 OUString aStrMap;
821 OUString aCustomKeyName;
822
823 if( nKeyCode & KEY_MOD1 )
824 aStrMap += GetKeyNameFromKeySym( nCtrlKeySym_ );
825
826 if( nKeyCode & KEY_MOD2 )
827 {
828 if( !aStrMap.isEmpty() )
829 aStrMap += "+";
830 aStrMap += GetKeyNameFromKeySym( nMod1KeySym_ );
831 }
832
833 if( nKeyCode & KEY_SHIFT )
834 {
835 if( !aStrMap.isEmpty() )
836 aStrMap += "+";
837 aStrMap += GetKeyNameFromKeySym( nShiftKeySym_ );
838 }
839 nKeyCode &= 0x0FFF;
840
841 KeySym nKeySym = 0;
842
843 if( KEY_0 <= nKeyCode && nKeyCode <= KEY_9 )
844 nKeySym = XK_0 + (nKeyCode - KEY_0);
845 else if( KEY_A <= nKeyCode && nKeyCode <= KEY_Z )
846 nKeySym = XK_A + (nKeyCode - KEY_A);
847 else if( KEY_F1 <= nKeyCode && nKeyCode <= KEY_F26 ) // does this key exist?
848 nKeySym = XK_F1 + (nKeyCode - KEY_F1);
849 else switch( nKeyCode )
850 {
851 case KEY_DOWN:
852 nKeySym = XK_Down;
853 break;
854 case KEY_UP:
855 nKeySym = XK_Up;
856 break;
857 case KEY_LEFT:
858 nKeySym = XK_Left;
859 break;
860 case KEY_RIGHT:
861 nKeySym = XK_Right;
862 break;
863 case KEY_HOME:
864 nKeySym = XK_Home;
865 break;
866 case KEY_END:
867 nKeySym = XK_End;
868 break;
869 case KEY_PAGEUP:
870 nKeySym = XK_Page_Up;
871 break;
872 case KEY_PAGEDOWN:
873 nKeySym = XK_Page_Down;
874 break;
875 case KEY_RETURN:
876 nKeySym = XK_Return;
877 break;
878 case KEY_ESCAPE:
879 nKeySym = XK_Escape;
880 break;
881 case KEY_TAB:
882 nKeySym = XK_Tab;
883 break;
884 case KEY_BACKSPACE:
885 nKeySym = XK_BackSpace;
886 break;
887 case KEY_SPACE:
888 nKeySym = XK_space;
889 break;
890 case KEY_INSERT:
891 nKeySym = XK_Insert;
892 break;
893 case KEY_DELETE:
894 nKeySym = XK_Delete;
895 break;
896
897 #if !defined (SunXK_Undo)
898 // we don't intend to use SunXK_Undo, but if it has not been
899 // defined already, then we _do_ need the following:
900 #define SunXK_Props 0x1005FF70
901 #define SunXK_Front 0x1005FF71
902 #define SunXK_Copy 0x1005FF72
903 #define SunXK_Open 0x1005FF73
904 #define SunXK_Paste 0x1005FF74
905 #define SunXK_Cut 0x1005FF75
906 #endif
907 // the following are for XF86 systems
908 #define XF86XK_Copy 0x1008FF57
909 #define XF86XK_Cut 0x1008FF58
910 #define XF86XK_Open 0x1008FF6B
911 #define XF86XK_Paste 0x1008FF6D
912 // which leaves Apollo and OSF systems in the lurch
913
914 case KEY_REPEAT:
915 nKeySym = XK_Redo;
916 break;
917 case KEY_PROPERTIES:
918 nKeySym = SunXK_Props;
919 break;
920 case KEY_UNDO:
921 nKeySym = XK_Undo;
922 break;
923 case KEY_FRONT:
924 nKeySym = SunXK_Front;
925 break;
926 case KEY_COPY:
927 nKeySym = GetServerVendor() == vendor_sun ? SunXK_Copy : XF86XK_Copy;
928 break;
929 case KEY_OPEN:
930 nKeySym = GetServerVendor() == vendor_sun ? SunXK_Open : XF86XK_Open;
931 break;
932 case KEY_PASTE:
933 nKeySym = GetServerVendor() == vendor_sun ? SunXK_Paste : XF86XK_Paste;
934 break;
935 case KEY_FIND:
936 nKeySym = XK_Find;
937 break;
938 case KEY_CUT:
939 nKeySym = GetServerVendor() == vendor_sun ? SunXK_Cut : XF86XK_Cut;
940 /* The original code here had:
941 nKeySym = GetServerVendor() == vendor_sun ? SunXK_Cut : XK_L10;
942 if anyone can remember which non-vendor_sun system used this
943 XK_L10 keysym, and why this hack only applied to KEY_CUT,
944 then please re-hack this code to put it back
945 */
946 break;
947 case KEY_ADD:
948 aCustomKeyName = "+";
949 break;
950 case KEY_SUBTRACT:
951 aCustomKeyName = "-";
952 break;
953 case KEY_MULTIPLY:
954 nKeySym = XK_asterisk;
955 break;
956 case KEY_DIVIDE:
957 nKeySym = XK_slash;
958 break;
959 case KEY_POINT:
960 aCustomKeyName = ".";
961 break;
962 case KEY_COMMA:
963 nKeySym = XK_comma;
964 break;
965 case KEY_LESS:
966 nKeySym = XK_less;
967 break;
968 case KEY_GREATER:
969 nKeySym = XK_greater;
970 break;
971 case KEY_EQUAL:
972 nKeySym = XK_equal;
973 break;
974 case KEY_HELP:
975 nKeySym = XK_Help;
976 break;
977 case KEY_HANGUL_HANJA:
978 nKeySym = XK_Hangul_Hanja;
979 break;
980 case KEY_TILDE:
981 nKeySym = XK_asciitilde;
982 break;
983 case KEY_QUOTELEFT:
984 nKeySym = XK_grave;
985 break;
986 case KEY_BRACKETLEFT:
987 aCustomKeyName = "[";
988 break;
989 case KEY_BRACKETRIGHT:
990 aCustomKeyName = "]";
991 break;
992 case KEY_SEMICOLON:
993 aCustomKeyName = ";";
994 break;
995 case KEY_QUOTERIGHT:
996 aCustomKeyName = "'";
997 break;
998 default:
999 nKeySym = 0;
1000 break;
1001 }
1002
1003 if( nKeySym )
1004 {
1005 OUString aKeyName = GetKeyNameFromKeySym( nKeySym );
1006 if( !aKeyName.isEmpty() )
1007 {
1008 if( !aStrMap.isEmpty() )
1009 aStrMap += "+";
1010 aStrMap += aKeyName;
1011 }
1012 else
1013 aStrMap.clear();
1014 }
1015 else if (!aCustomKeyName.isEmpty())
1016 {
1017 // For semicolon, bracket left and bracket right, it's better to use
1018 // their keys than their names. (fdo#32891)
1019 if (!aStrMap.isEmpty())
1020 aStrMap += "+";
1021 aStrMap += aCustomKeyName;
1022 }
1023 else
1024 aStrMap.clear();
1025
1026 return aStrMap;
1027 }
1028
1029 #ifndef IsISOKey
1030 #define IsISOKey( n ) (0x0000FE00==((n)&0xFFFFFF00))
1031 #endif
1032
GetKeyCode(KeySym keysym,char * pcPrintable) const1033 sal_uInt16 SalDisplay::GetKeyCode( KeySym keysym, char*pcPrintable ) const
1034 {
1035 sal_uInt16 nKey = 0;
1036
1037 if( XK_a <= keysym && XK_z >= keysym )
1038 nKey = static_cast<sal_uInt16>(KEY_A + (keysym - XK_a));
1039 else if( XK_A <= keysym && XK_Z >= keysym )
1040 nKey = static_cast<sal_uInt16>(KEY_A + (keysym - XK_A));
1041 else if( XK_0 <= keysym && XK_9 >= keysym )
1042 nKey = static_cast<sal_uInt16>(KEY_0 + (keysym - XK_0));
1043 else if( IsModifierKey( keysym ) )
1044 ;
1045 else if( IsKeypadKey( keysym ) )
1046 {
1047 if( (keysym >= XK_KP_0) && (keysym <= XK_KP_9) )
1048 {
1049 nKey = static_cast<sal_uInt16>(KEY_0 + (keysym - XK_KP_0));
1050 *pcPrintable = '0' + nKey - KEY_0;
1051 }
1052 else if( IsPFKey( keysym ) )
1053 nKey = static_cast<sal_uInt16>(KEY_F1 + (keysym - XK_KP_F1));
1054 else switch( keysym )
1055 {
1056 case XK_KP_Space:
1057 nKey = KEY_SPACE;
1058 *pcPrintable = ' ';
1059 break;
1060 case XK_KP_Tab:
1061 nKey = KEY_TAB;
1062 break;
1063 case XK_KP_Enter:
1064 nKey = KEY_RETURN;
1065 break;
1066 case XK_KP_Begin:
1067 case XK_KP_Home:
1068 nKey = KEY_HOME;
1069 break;
1070 case XK_KP_Left:
1071 nKey = KEY_LEFT;
1072 break;
1073 case XK_KP_Up:
1074 nKey = KEY_UP;
1075 break;
1076 case XK_KP_Right:
1077 nKey = KEY_RIGHT;
1078 break;
1079 case XK_KP_Down:
1080 nKey = KEY_DOWN;
1081 break;
1082 case XK_KP_Page_Up: // XK_KP_Page_Up
1083 nKey = KEY_PAGEUP;
1084 break;
1085 case XK_KP_Page_Down: // XK_KP_Page_Down
1086 nKey = KEY_PAGEDOWN;
1087 break;
1088 case XK_KP_End:
1089 nKey = KEY_END;
1090 break;
1091 case XK_KP_Insert:
1092 nKey = KEY_INSERT;
1093 break;
1094 case XK_KP_Delete:
1095 nKey = KEY_DELETE;
1096 break;
1097 case XK_KP_Equal:
1098 nKey = KEY_EQUAL;
1099 *pcPrintable = '=';
1100 break;
1101 case XK_KP_Multiply:
1102 nKey = KEY_MULTIPLY;
1103 *pcPrintable = '*';
1104 break;
1105 case XK_KP_Add:
1106 nKey = KEY_ADD;
1107 *pcPrintable = '+';
1108 break;
1109 case XK_KP_Separator:
1110 nKey = KEY_DECIMAL;
1111 *pcPrintable = ',';
1112 break;
1113 case XK_KP_Subtract:
1114 nKey = KEY_SUBTRACT;
1115 *pcPrintable = '-';
1116 break;
1117 case XK_KP_Decimal:
1118 nKey = KEY_DECIMAL;
1119 *pcPrintable = '.';
1120 break;
1121 case XK_KP_Divide:
1122 nKey = KEY_DIVIDE;
1123 *pcPrintable = '/';
1124 break;
1125 }
1126 }
1127 else if( IsFunctionKey( keysym ) )
1128 {
1129 if( bNumLockFromXS_ )
1130 {
1131 if( keysym >= XK_F1 && keysym <= XK_F26 )
1132 nKey = static_cast<sal_uInt16>(KEY_F1 + keysym - XK_F1);
1133 }
1134 else switch( keysym )
1135 {
1136 // - - - - - Sun X-Server keyboard without Cursorblock ??? - - -
1137 case XK_R7: // XK_F27:
1138 nKey = KEY_HOME;
1139 break;
1140 case XK_R8: // XK_F28:
1141 nKey = KEY_UP;
1142 break;
1143 case XK_R9: // XK_F29:
1144 nKey = KEY_PAGEUP;
1145 break;
1146 case XK_R10: // XK_F30:
1147 nKey = KEY_LEFT;
1148 break;
1149 case XK_R11: // XK_F31:
1150 nKey = 0; // KEY_F31
1151 break;
1152 case XK_R12: // XK_F32:
1153 nKey = KEY_RIGHT;
1154 break;
1155 case XK_R13: // XK_F33:
1156 nKey = KEY_END;
1157 break;
1158 case XK_R14: // XK_F34:
1159 nKey = KEY_DOWN;
1160 break;
1161 case XK_R15: // XK_F35:
1162 nKey = KEY_PAGEDOWN;
1163 break;
1164 // - - - - - Sun X-Server keyboard ??? - - - - - - - - - - - -
1165 case XK_L1: // XK_F11:
1166 nKey = KEY_F11; // on a sun keyboard this actually is usually SunXK_Stop = 0x0000FF69 (XK_Cancel),
1167 // but VCL doesn't have a key definition for that
1168 break;
1169 case XK_L2: // XK_F12:
1170 if ( GetServerVendor() == vendor_sun )
1171 nKey = KEY_REPEAT;
1172 else
1173 nKey = KEY_F12;
1174 break;
1175 case XK_L3: // XK_F13:
1176 nKey = KEY_PROPERTIES; // KEY_F13
1177 break;
1178 case XK_L4: // XK_F14:
1179 nKey = KEY_UNDO; // KEY_F14
1180 break;
1181 case XK_L5: // XK_F15:
1182 nKey = KEY_F15; // KEY_FRONT
1183 break;
1184 case XK_L6: // XK_F16:
1185 nKey = KEY_COPY; // KEY_F16
1186 break;
1187 case XK_L7: // XK_F17:
1188 nKey = KEY_F17; // KEY_OPEN
1189 break;
1190 case XK_L8: // XK_F18:
1191 nKey = KEY_PASTE; // KEY_F18
1192 break;
1193 case XK_L9: // XK_F19:
1194 nKey = KEY_F19; // KEY_FIND
1195 break;
1196 case XK_L10: // XK_F20:
1197 nKey = KEY_CUT; // KEY_F20
1198 break;
1199 default:
1200 if( keysym >= XK_F1 && keysym <= XK_F26 )
1201 nKey = static_cast<sal_uInt16>(KEY_F1 + keysym - XK_F1);
1202 break;
1203 }
1204 }
1205 else if( IsCursorKey( keysym ) )
1206 {
1207 switch( keysym )
1208 {
1209 case XK_Begin:
1210 case XK_Home:
1211 nKey = KEY_HOME;
1212 break;
1213 case XK_Left:
1214 nKey = KEY_LEFT;
1215 break;
1216 case XK_Up:
1217 nKey = KEY_UP;
1218 break;
1219 case XK_Right:
1220 nKey = KEY_RIGHT;
1221 break;
1222 case XK_Down:
1223 nKey = KEY_DOWN;
1224 break;
1225 case XK_Page_Up: // XK_Page_Up
1226 nKey = KEY_PAGEUP;
1227 break;
1228 case XK_Page_Down: // XK_Page_Down
1229 nKey = KEY_PAGEDOWN;
1230 break;
1231 case XK_End:
1232 nKey = KEY_END;
1233 break;
1234 }
1235 }
1236 else if( IsMiscFunctionKey( keysym ) )
1237 {
1238 switch( keysym )
1239 {
1240 case XK_Insert:
1241 nKey = KEY_INSERT;
1242 break;
1243 case XK_Redo:
1244 nKey = KEY_REPEAT;
1245 break;
1246 case XK_Undo:
1247 nKey = KEY_UNDO;
1248 break;
1249 case XK_Find:
1250 nKey = KEY_FIND;
1251 break;
1252 case XK_Help:
1253 nKey = KEY_HELP;
1254 break;
1255 case XK_Menu:
1256 nKey = KEY_CONTEXTMENU;
1257 break;
1258 }
1259 }
1260 else if( IsISOKey( keysym ) ) // XK_ISO_
1261 {
1262 switch( keysym )
1263 {
1264 case 0xFE20: // XK_ISO_Left_Tab:
1265 nKey = KEY_TAB;
1266 break;
1267 }
1268 }
1269 else switch( keysym )
1270 {
1271 case XK_Return:
1272 nKey = KEY_RETURN;
1273 break;
1274 case XK_BackSpace:
1275 nKey = KEY_BACKSPACE;
1276 break;
1277 case XK_Delete:
1278 nKey = KEY_DELETE;
1279 break;
1280 case XK_space:
1281 nKey = KEY_SPACE;
1282 break;
1283 case XK_Tab:
1284 nKey = KEY_TAB;
1285 break;
1286 case XK_Escape:
1287 nKey = KEY_ESCAPE;
1288 break;
1289 case XK_plus:
1290 nKey = KEY_ADD;
1291 break;
1292 case XK_minus:
1293 nKey = KEY_SUBTRACT;
1294 break;
1295 case XK_asterisk:
1296 nKey = KEY_MULTIPLY;
1297 break;
1298 case XK_slash:
1299 nKey = KEY_DIVIDE;
1300 break;
1301 case XK_period:
1302 nKey = KEY_POINT;
1303 *pcPrintable = '.';
1304 break;
1305 case XK_comma:
1306 nKey = KEY_COMMA;
1307 break;
1308 case XK_less:
1309 nKey = KEY_LESS;
1310 break;
1311 case XK_greater:
1312 nKey = KEY_GREATER;
1313 break;
1314 case XK_equal:
1315 nKey = KEY_EQUAL;
1316 break;
1317 case XK_Hangul_Hanja:
1318 nKey = KEY_HANGUL_HANJA;
1319 break;
1320 case XK_asciitilde:
1321 nKey = KEY_TILDE;
1322 *pcPrintable = '~';
1323 break;
1324 case XK_grave:
1325 nKey = KEY_QUOTELEFT;
1326 *pcPrintable = '`';
1327 break;
1328 case XK_bracketleft:
1329 nKey = KEY_BRACKETLEFT;
1330 *pcPrintable = '[';
1331 break;
1332 case XK_bracketright:
1333 nKey = KEY_BRACKETRIGHT;
1334 *pcPrintable = ']';
1335 break;
1336 case XK_semicolon:
1337 nKey = KEY_SEMICOLON;
1338 *pcPrintable = ';';
1339 break;
1340 case XK_quoteright:
1341 nKey = KEY_QUOTERIGHT;
1342 *pcPrintable = '\'';
1343 break;
1344 // - - - - - - - - - - - - - Apollo - - - - - - - - - - - - - 0x1000
1345 case 0x1000FF02: // apXK_Copy
1346 nKey = KEY_COPY;
1347 break;
1348 case 0x1000FF03: // apXK_Cut
1349 nKey = KEY_CUT;
1350 break;
1351 case 0x1000FF04: // apXK_Paste
1352 nKey = KEY_PASTE;
1353 break;
1354 case 0x1000FF14: // apXK_Repeat
1355 nKey = KEY_REPEAT;
1356 break;
1357 // Exit, Save
1358 // - - - - - - - - - - - - - - D E C - - - - - - - - - - - - - 0x1000
1359 case 0x1000FF00:
1360 nKey = KEY_DELETE;
1361 break;
1362 // - - - - - - - - - - - - - - H P - - - - - - - - - - - - - 0x1000
1363 case 0x1000FF73: // hpXK_DeleteChar
1364 nKey = KEY_DELETE;
1365 break;
1366 case 0x1000FF74: // hpXK_BackTab
1367 case 0x1000FF75: // hpXK_KP_BackTab
1368 nKey = KEY_TAB;
1369 break;
1370 // - - - - - - - - - - - - - - I B M - - - - - - - - - - - - -
1371 // - - - - - - - - - - - - - - O S F - - - - - - - - - - - - - 0x1004
1372 case 0x1004FF02: // osfXK_Copy
1373 nKey = KEY_COPY;
1374 break;
1375 case 0x1004FF03: // osfXK_Cut
1376 nKey = KEY_CUT;
1377 break;
1378 case 0x1004FF04: // osfXK_Paste
1379 nKey = KEY_PASTE;
1380 break;
1381 case 0x1004FF07: // osfXK_BackTab
1382 nKey = KEY_TAB;
1383 break;
1384 case 0x1004FF08: // osfXK_BackSpace
1385 nKey = KEY_BACKSPACE;
1386 break;
1387 case 0x1004FF1B: // osfXK_Escape
1388 nKey = KEY_ESCAPE;
1389 break;
1390 // Up, Down, Left, Right, PageUp, PageDown
1391 // - - - - - - - - - - - - - - S C O - - - - - - - - - - - - -
1392 // - - - - - - - - - - - - - - S G I - - - - - - - - - - - - - 0x1007
1393 // - - - - - - - - - - - - - - S N I - - - - - - - - - - - - -
1394 // - - - - - - - - - - - - - - S U N - - - - - - - - - - - - - 0x1005
1395 case 0x1005FF10: // SunXK_F36
1396 nKey = KEY_F11;
1397 break;
1398 case 0x1005FF11: // SunXK_F37
1399 nKey = KEY_F12;
1400 break;
1401 case 0x1005FF70: // SunXK_Props
1402 nKey = KEY_PROPERTIES;
1403 break;
1404 case 0x1005FF71: // SunXK_Front
1405 nKey = KEY_FRONT;
1406 break;
1407 case 0x1005FF72: // SunXK_Copy
1408 nKey = KEY_COPY;
1409 break;
1410 case 0x1005FF73: // SunXK_Open
1411 nKey = KEY_OPEN;
1412 break;
1413 case 0x1005FF74: // SunXK_Paste
1414 nKey = KEY_PASTE;
1415 break;
1416 case 0x1005FF75: // SunXK_Cut
1417 nKey = KEY_CUT;
1418 break;
1419 }
1420 return nKey;
1421 }
1422
GetKeySym(XKeyEvent * pEvent,char * pPrintable,int * pLen,KeySym * pUnmodifiedKeySym,Status * pStatusReturn,XIC aInputContext) const1423 KeySym SalDisplay::GetKeySym( XKeyEvent *pEvent,
1424 char *pPrintable,
1425 int *pLen,
1426 KeySym *pUnmodifiedKeySym,
1427 Status *pStatusReturn,
1428 XIC aInputContext ) const
1429 {
1430 KeySym nKeySym = 0;
1431 memset( pPrintable, 0, *pLen );
1432 *pStatusReturn = 0;
1433
1434 SalI18N_InputMethod* const pInputMethod =
1435 pXLib_ ? pXLib_->GetInputMethod() : nullptr;
1436
1437 // first get the printable of the possibly modified KeySym
1438 if ( (aInputContext == nullptr)
1439 || (pEvent->type == KeyRelease)
1440 || (pInputMethod != nullptr && pInputMethod->PosixLocale()) )
1441 {
1442 // XmbLookupString must not be called for KeyRelease events
1443 // Cannot enter space in c locale problem #89616# #88978# btraq #4478197
1444 *pLen = XLookupString( pEvent, pPrintable, 1, &nKeySym, nullptr );
1445 }
1446 else
1447 {
1448 *pLen = XmbLookupString( aInputContext,
1449 pEvent, pPrintable, *pLen - 1, &nKeySym, pStatusReturn );
1450
1451 // Lookup the string again, now with appropriate size
1452 if ( *pStatusReturn == XBufferOverflow )
1453 {
1454 pPrintable[ 0 ] = '\0';
1455 return 0;
1456 }
1457
1458 switch ( *pStatusReturn )
1459 {
1460 case XBufferOverflow:
1461 /* unhandled error */
1462 break;
1463 case XLookupNone:
1464 /* unhandled error */
1465 break;
1466 case XLookupKeySym:
1467 /* this is a strange one: on exceed sometimes
1468 * no printable is returned for the first char entered,
1469 * just to retry lookup solves the problem. The problem
1470 * is not yet fully understood, so restrict 2nd lookup
1471 * to 7bit ascii chars */
1472 if ( (XK_space <= nKeySym) && (XK_asciitilde >= nKeySym) )
1473 {
1474 *pLen = 1;
1475 pPrintable[ 0 ] = static_cast<char>(nKeySym);
1476 }
1477 break;
1478 case XLookupBoth:
1479 case XLookupChars:
1480
1481 /* nothing to, char already in pPrintable */
1482 break;
1483 }
1484 }
1485
1486 if( !bNumLockFromXS_
1487 && (IsCursorKey(nKeySym)
1488 || IsFunctionKey(nKeySym)
1489 || IsKeypadKey(nKeySym)
1490 || XK_Delete == nKeySym ) )
1491 {
1492 // For some X-servers special care is needed for Keypad keys.
1493 // For example Solaris XServer:
1494 // 2, 4, 6, 8 are classified as Cursorkeys (Up, Down, Left, Right)
1495 // 1, 3, 5, 9 are classified as Functionkeys (F27,F29,F33,F35)
1496 // 0 as Keypadkey, and the decimal point key not at all (KP_Insert)
1497 KeySym nNewKeySym = XLookupKeysym( pEvent, nNumLockIndex_ );
1498 if( nNewKeySym != NoSymbol )
1499 nKeySym = nNewKeySym;
1500 }
1501
1502 // Now get the unmodified KeySym for KeyCode retrieval
1503 // try to strip off modifiers, e.g. Ctrl-$ becomes Ctrl-Shift-4
1504 *pUnmodifiedKeySym = XkbKeycodeToKeysym( GetDisplay(), pEvent->keycode, 0, 0);
1505
1506 return nKeySym;
1507 }
1508
1509 // Pointer
1510 static unsigned char nullmask_bits[] = { 0x00, 0x00, 0x00, 0x00 };
1511 static unsigned char nullcurs_bits[] = { 0x00, 0x00, 0x00, 0x00 };
1512
1513 #define MAKE_BITMAP( name ) \
1514 XCreateBitmapFromData( pDisp_, \
1515 DefaultRootWindow( pDisp_ ), \
1516 reinterpret_cast<const char*>(name##_bits), \
1517 name##_width, \
1518 name##_height )
1519
1520 #define MAKE_CURSOR( name ) \
1521 aCursBitmap = MAKE_BITMAP( name##curs ); \
1522 aMaskBitmap = MAKE_BITMAP( name##mask ); \
1523 nXHot = name##curs_x_hot; \
1524 nYHot = name##curs_y_hot
1525
GetPointer(PointerStyle ePointerStyle)1526 Cursor SalDisplay::GetPointer( PointerStyle ePointerStyle )
1527 {
1528 Cursor &aCur = aPointerCache_[ePointerStyle];
1529
1530 if( aCur != None )
1531 return aCur;
1532
1533 Pixmap aCursBitmap = None, aMaskBitmap = None;
1534 unsigned int nXHot = 0, nYHot = 0;
1535
1536 switch( ePointerStyle )
1537 {
1538 case PointerStyle::Null:
1539 MAKE_CURSOR( null );
1540 break;
1541 case PointerStyle::Arrow:
1542 aCur = XCreateFontCursor( pDisp_, XC_left_ptr );
1543 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1544 break;
1545 case PointerStyle::Wait:
1546 aCur = XCreateFontCursor( pDisp_, XC_watch );
1547 break;
1548 case PointerStyle::Text: // Mouse Pointer is a "I" Beam
1549 aCur = XCreateFontCursor( pDisp_, XC_xterm );
1550 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1551 break;
1552 case PointerStyle::Help:
1553 aCur = XCreateFontCursor( pDisp_, XC_question_arrow );
1554 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1555 break;
1556 case PointerStyle::Cross: // Mouse Pointer is a cross
1557 aCur = XCreateFontCursor( pDisp_, XC_crosshair );
1558 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1559 break;
1560 case PointerStyle::NSize:
1561 aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow );
1562 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1563 break;
1564 case PointerStyle::SSize:
1565 aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow );
1566 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1567 break;
1568 case PointerStyle::WSize:
1569 aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow );
1570 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1571 break;
1572 case PointerStyle::ESize:
1573 aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow );
1574 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1575 break;
1576 case PointerStyle::WindowNSize:
1577 aCur = XCreateFontCursor( pDisp_, XC_top_side );
1578 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1579 break;
1580 case PointerStyle::WindowSSize:
1581 aCur = XCreateFontCursor( pDisp_, XC_bottom_side );
1582 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1583 break;
1584 case PointerStyle::WindowWSize:
1585 aCur = XCreateFontCursor( pDisp_, XC_left_side );
1586 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1587 break;
1588 case PointerStyle::WindowESize:
1589 aCur = XCreateFontCursor( pDisp_, XC_right_side );
1590 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1591 break;
1592 case PointerStyle::NWSize:
1593 aCur = XCreateFontCursor( pDisp_, XC_top_left_corner );
1594 break;
1595 case PointerStyle::NESize:
1596 aCur = XCreateFontCursor( pDisp_, XC_top_right_corner );
1597 break;
1598 case PointerStyle::SWSize:
1599 aCur = XCreateFontCursor( pDisp_, XC_bottom_left_corner );
1600 break;
1601 case PointerStyle::SESize:
1602 aCur = XCreateFontCursor( pDisp_, XC_bottom_right_corner );
1603 break;
1604 case PointerStyle::WindowNWSize:
1605 aCur = XCreateFontCursor( pDisp_, XC_top_left_corner );
1606 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1607 break;
1608 case PointerStyle::WindowNESize:
1609 aCur = XCreateFontCursor( pDisp_, XC_top_right_corner );
1610 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1611 break;
1612 case PointerStyle::WindowSWSize:
1613 aCur = XCreateFontCursor( pDisp_, XC_bottom_left_corner );
1614 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1615 break;
1616 case PointerStyle::WindowSESize:
1617 aCur = XCreateFontCursor( pDisp_, XC_bottom_right_corner );
1618 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1619 break;
1620 case PointerStyle::HSplit:
1621 aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow );
1622 break;
1623 case PointerStyle::VSplit:
1624 aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow );
1625 break;
1626 case PointerStyle::HSizeBar:
1627 aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow ); // ???
1628 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1629 break;
1630 case PointerStyle::VSizeBar:
1631 aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow ); // ???
1632 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1633 break;
1634 case PointerStyle::RefHand:
1635 aCur = XCreateFontCursor( pDisp_, XC_hand1 );
1636 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1637 break;
1638 case PointerStyle::Hand:
1639 aCur = XCreateFontCursor( pDisp_, XC_hand2 );
1640 break;
1641 case PointerStyle::Magnify:
1642 MAKE_CURSOR( magnify_ );
1643 break;
1644 case PointerStyle::Fill:
1645 MAKE_CURSOR( fill_ );
1646 break;
1647 case PointerStyle::Move:
1648 aCur = XCreateFontCursor( pDisp_, XC_fleur );
1649 break;
1650 case PointerStyle::MoveData:
1651 MAKE_CURSOR( movedata_ );
1652 break;
1653 case PointerStyle::CopyData:
1654 MAKE_CURSOR( copydata_ );
1655 break;
1656 case PointerStyle::MoveFile:
1657 MAKE_CURSOR( movefile_ );
1658 break;
1659 case PointerStyle::CopyFile:
1660 MAKE_CURSOR( copyfile_ );
1661 break;
1662 case PointerStyle::MoveFiles:
1663 MAKE_CURSOR( movefiles_ );
1664 break;
1665 case PointerStyle::CopyFiles:
1666 MAKE_CURSOR( copyfiles_ );
1667 break;
1668 case PointerStyle::NotAllowed:
1669 MAKE_CURSOR( nodrop_ );
1670 break;
1671 case PointerStyle::Rotate:
1672 MAKE_CURSOR( rotate_ );
1673 break;
1674 case PointerStyle::HShear:
1675 MAKE_CURSOR( hshear_ );
1676 break;
1677 case PointerStyle::VShear:
1678 MAKE_CURSOR( vshear_ );
1679 break;
1680 case PointerStyle::DrawLine:
1681 MAKE_CURSOR( drawline_ );
1682 break;
1683 case PointerStyle::DrawRect:
1684 MAKE_CURSOR( drawrect_ );
1685 break;
1686 case PointerStyle::DrawPolygon:
1687 MAKE_CURSOR( drawpolygon_ );
1688 break;
1689 case PointerStyle::DrawBezier:
1690 MAKE_CURSOR( drawbezier_ );
1691 break;
1692 case PointerStyle::DrawArc:
1693 MAKE_CURSOR( drawarc_ );
1694 break;
1695 case PointerStyle::DrawPie:
1696 MAKE_CURSOR( drawpie_ );
1697 break;
1698 case PointerStyle::DrawCircleCut:
1699 MAKE_CURSOR( drawcirclecut_ );
1700 break;
1701 case PointerStyle::DrawEllipse:
1702 MAKE_CURSOR( drawellipse_ );
1703 break;
1704 case PointerStyle::DrawConnect:
1705 MAKE_CURSOR( drawconnect_ );
1706 break;
1707 case PointerStyle::DrawText:
1708 MAKE_CURSOR( drawtext_ );
1709 break;
1710 case PointerStyle::Mirror:
1711 MAKE_CURSOR( mirror_ );
1712 break;
1713 case PointerStyle::Crook:
1714 MAKE_CURSOR( crook_ );
1715 break;
1716 case PointerStyle::Crop:
1717 MAKE_CURSOR( crop_ );
1718 break;
1719 case PointerStyle::MovePoint:
1720 MAKE_CURSOR( movepoint_ );
1721 break;
1722 case PointerStyle::MoveBezierWeight:
1723 MAKE_CURSOR( movebezierweight_ );
1724 break;
1725 case PointerStyle::DrawFreehand:
1726 MAKE_CURSOR( drawfreehand_ );
1727 break;
1728 case PointerStyle::DrawCaption:
1729 MAKE_CURSOR( drawcaption_ );
1730 break;
1731 case PointerStyle::Pen: // Mouse Pointer is a pencil
1732 aCur = XCreateFontCursor( pDisp_, XC_pencil );
1733 SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
1734 break;
1735 case PointerStyle::LinkData:
1736 MAKE_CURSOR( linkdata_ );
1737 break;
1738 case PointerStyle::MoveDataLink:
1739 MAKE_CURSOR( movedlnk_ );
1740 break;
1741 case PointerStyle::CopyDataLink:
1742 MAKE_CURSOR( copydlnk_ );
1743 break;
1744 case PointerStyle::LinkFile:
1745 MAKE_CURSOR( linkfile_ );
1746 break;
1747 case PointerStyle::MoveFileLink:
1748 MAKE_CURSOR( moveflnk_ );
1749 break;
1750 case PointerStyle::CopyFileLink:
1751 MAKE_CURSOR( copyflnk_ );
1752 break;
1753 case PointerStyle::Chart:
1754 MAKE_CURSOR( chart_ );
1755 break;
1756 case PointerStyle::Detective:
1757 MAKE_CURSOR( detective_ );
1758 break;
1759 case PointerStyle::PivotCol:
1760 MAKE_CURSOR( pivotcol_ );
1761 break;
1762 case PointerStyle::PivotRow:
1763 MAKE_CURSOR( pivotrow_ );
1764 break;
1765 case PointerStyle::PivotField:
1766 MAKE_CURSOR( pivotfld_ );
1767 break;
1768 case PointerStyle::PivotDelete:
1769 MAKE_CURSOR( pivotdel_ );
1770 break;
1771 case PointerStyle::Chain:
1772 MAKE_CURSOR( chain_ );
1773 break;
1774 case PointerStyle::ChainNotAllowed:
1775 MAKE_CURSOR( chainnot_ );
1776 break;
1777 case PointerStyle::AutoScrollN:
1778 MAKE_CURSOR(asn_ );
1779 break;
1780 case PointerStyle::AutoScrollS:
1781 MAKE_CURSOR( ass_ );
1782 break;
1783 case PointerStyle::AutoScrollW:
1784 MAKE_CURSOR( asw_ );
1785 break;
1786 case PointerStyle::AutoScrollE:
1787 MAKE_CURSOR( ase_ );
1788 break;
1789 case PointerStyle::AutoScrollNW:
1790 MAKE_CURSOR( asnw_ );
1791 break;
1792 case PointerStyle::AutoScrollNE:
1793 MAKE_CURSOR( asne_ );
1794 break;
1795 case PointerStyle::AutoScrollSW:
1796 MAKE_CURSOR( assw_ );
1797 break;
1798 case PointerStyle::AutoScrollSE:
1799 MAKE_CURSOR( asse_ );
1800 break;
1801 case PointerStyle::AutoScrollNS:
1802 MAKE_CURSOR( asns_ );
1803 break;
1804 case PointerStyle::AutoScrollWE:
1805 MAKE_CURSOR( aswe_ );
1806 break;
1807 case PointerStyle::AutoScrollNSWE:
1808 MAKE_CURSOR( asnswe_ );
1809 break;
1810 case PointerStyle::TextVertical:
1811 MAKE_CURSOR( vertcurs_ );
1812 break;
1813
1814 // #i32329# Enhanced table selection
1815 case PointerStyle::TabSelectS:
1816 MAKE_CURSOR( tblsels_ );
1817 break;
1818 case PointerStyle::TabSelectE:
1819 MAKE_CURSOR( tblsele_ );
1820 break;
1821 case PointerStyle::TabSelectSE:
1822 MAKE_CURSOR( tblselse_ );
1823 break;
1824 case PointerStyle::TabSelectW:
1825 MAKE_CURSOR( tblselw_ );
1826 break;
1827 case PointerStyle::TabSelectSW:
1828 MAKE_CURSOR( tblselsw_ );
1829 break;
1830
1831 case PointerStyle::HideWhitespace:
1832 MAKE_CURSOR( hidewhitespace_ );
1833 break;
1834 case PointerStyle::ShowWhitespace:
1835 MAKE_CURSOR( showwhitespace_ );
1836 break;
1837
1838 default:
1839 OSL_FAIL("pointer not implemented");
1840 aCur = XCreateFontCursor( pDisp_, XC_arrow );
1841 break;
1842 }
1843
1844 if( None == aCur )
1845 {
1846 XColor aBlack, aWhite, aDummy;
1847 Colormap hColormap = GetColormap(m_nXDefaultScreen).GetXColormap();
1848
1849 XAllocNamedColor( pDisp_, hColormap, "black", &aBlack, &aDummy );
1850 XAllocNamedColor( pDisp_, hColormap, "white", &aWhite, &aDummy );
1851
1852 aCur = XCreatePixmapCursor( pDisp_,
1853 aCursBitmap, aMaskBitmap,
1854 &aBlack, &aWhite,
1855 nXHot, nYHot );
1856
1857 XFreePixmap( pDisp_, aCursBitmap );
1858 XFreePixmap( pDisp_, aMaskBitmap );
1859 }
1860
1861 return aCur;
1862 }
1863
CaptureMouse(SalFrame * pCapture)1864 int SalDisplay::CaptureMouse( SalFrame *pCapture )
1865 {
1866 static const char* pEnv = getenv( "SAL_NO_MOUSEGRABS" );
1867
1868 if( !pCapture )
1869 {
1870 m_pCapture = nullptr;
1871 if( !pEnv || !*pEnv )
1872 XUngrabPointer( GetDisplay(), CurrentTime );
1873 XFlush( GetDisplay() );
1874 return 0;
1875 }
1876
1877 m_pCapture = nullptr;
1878
1879 // FIXME: get rid of X11SalFrame
1880 const SystemEnvData* pEnvData = pCapture->GetSystemData();
1881 if( !pEnv || !*pEnv )
1882 {
1883 int ret = XGrabPointer( GetDisplay(),
1884 static_cast<::Window>(pEnvData->aWindow),
1885 False,
1886 PointerMotionMask| ButtonPressMask|ButtonReleaseMask,
1887 GrabModeAsync,
1888 GrabModeAsync,
1889 None,
1890 static_cast<X11SalFrame*>(pCapture)->GetCursor(),
1891 CurrentTime );
1892
1893 if( ret != GrabSuccess )
1894 {
1895 SAL_WARN("vcl", "SalDisplay::CaptureMouse could not grab pointer: " << ret);
1896 return -1;
1897 }
1898 }
1899
1900 m_pCapture = pCapture;
1901 return 1;
1902 }
1903
1904 // Events
1905
IsEvent()1906 bool SalX11Display::IsEvent()
1907 {
1908 if( HasUserEvents() || XEventsQueued( pDisp_, QueuedAlready ) )
1909 return true;
1910
1911 XFlush( pDisp_ );
1912 return false;
1913 }
1914
Yield()1915 void SalX11Display::Yield()
1916 {
1917 if( DispatchInternalEvent() )
1918 return;
1919
1920 XEvent aEvent;
1921 DBG_ASSERT( GetSalData()->m_pInstance->GetYieldMutex()->IsCurrentThread(),
1922 "will crash soon since solar mutex not locked in SalDisplay::Yield" );
1923
1924 XNextEvent( pDisp_, &aEvent );
1925
1926 // FIXME: under-convinced by Dispatch boolean return value vs. salframe.
1927 Dispatch( &aEvent );
1928
1929 #ifdef DBG_UTIL
1930 if( GetX11SalData()->HasXErrorOccurred() )
1931 {
1932 XFlush( pDisp_ );
1933 DbgPrintDisplayEvent("SalDisplay::Yield (WasXError)", &aEvent);
1934 }
1935 #endif
1936 GetX11SalData()->ResetXErrorOccurred();
1937 }
1938
Dispatch(XEvent * pEvent)1939 bool SalX11Display::Dispatch( XEvent *pEvent )
1940 {
1941 SalI18N_InputMethod* const pInputMethod =
1942 pXLib_ ? pXLib_->GetInputMethod() : nullptr;
1943
1944 if( pInputMethod )
1945 {
1946 ::Window aFrameWindow = None;
1947 if( pEvent->type == KeyPress || pEvent->type == KeyRelease )
1948 {
1949 const ::Window aWindow = pEvent->xkey.window;
1950 for( auto pSalFrame : m_aFrames )
1951 {
1952 const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame );
1953 const ::Window aCurFrameWindow = pFrame->GetWindow();
1954 if( aCurFrameWindow == aWindow || pFrame->GetShellWindow() == aWindow )
1955 {
1956 aFrameWindow = aCurFrameWindow;
1957 break;
1958 }
1959 }
1960 }
1961 if( pInputMethod->FilterEvent( pEvent, aFrameWindow ) )
1962 return false;
1963 }
1964
1965 SalInstance* pInstance = GetSalData()->m_pInstance;
1966 pInstance->CallEventCallback( pEvent, sizeof( XEvent ) );
1967
1968 switch( pEvent->type )
1969 {
1970 case MotionNotify:
1971 while( XCheckWindowEvent( pEvent->xany.display,
1972 pEvent->xany.window,
1973 ButtonMotionMask,
1974 pEvent ) )
1975 ;
1976 m_nLastUserEventTime = pEvent->xmotion.time;
1977 break;
1978 case PropertyNotify:
1979 if( pEvent->xproperty.atom == getWMAdaptor()->getAtom( WMAdaptor::VCL_SYSTEM_SETTINGS ) )
1980 {
1981 for(const ScreenData & rScreen : m_aScreens)
1982 {
1983 if( pEvent->xproperty.window == rScreen.m_aRefWindow )
1984 {
1985 for (auto pSalFrame : m_aFrames )
1986 pSalFrame->CallCallback( SalEvent::SettingsChanged, nullptr );
1987 return false;
1988 }
1989 }
1990 }
1991 break;
1992 case MappingNotify:
1993 if( MappingModifier == pEvent->xmapping.request )
1994 {
1995 XRefreshKeyboardMapping( &pEvent->xmapping );
1996 ModifierMapping();
1997 }
1998 break;
1999 case ButtonPress:
2000 case ButtonRelease:
2001 m_nLastUserEventTime = pEvent->xbutton.time;
2002 break;
2003 case KeyPress:
2004 case KeyRelease:
2005 m_nLastUserEventTime = pEvent->xkey.time;
2006 break;
2007 default:
2008
2009 if ( GetKbdExtension()->UseExtension()
2010 && GetKbdExtension()->GetEventBase() == pEvent->type )
2011 {
2012 GetKbdExtension()->Dispatch( pEvent );
2013 return true;
2014 }
2015 break;
2016 }
2017
2018 for (auto pSalFrame : m_aFrames )
2019 {
2020 X11SalFrame* pFrame = static_cast<X11SalFrame*>( pSalFrame );
2021
2022 ::Window aDispatchWindow = pEvent->xany.window;
2023 if( pFrame->GetWindow() == aDispatchWindow
2024 || pFrame->GetShellWindow() == aDispatchWindow
2025 || pFrame->GetForeignParent() == aDispatchWindow
2026 )
2027 {
2028 return pFrame->Dispatch( pEvent );
2029 }
2030 if( pEvent->type == ConfigureNotify && pEvent->xconfigure.window == pFrame->GetStackingWindow() )
2031 {
2032 return pFrame->Dispatch( pEvent );
2033 }
2034 }
2035
2036 // dispatch to salobjects
2037 X11SalObject::Dispatch( pEvent );
2038
2039 // is this perhaps a root window that changed size ?
2040 processRandREvent( pEvent );
2041
2042 return false;
2043 }
2044
2045 #ifdef DBG_UTIL
DbgPrintDisplayEvent(const char * pComment,XEvent * pEvent) const2046 void SalDisplay::DbgPrintDisplayEvent(const char *pComment, XEvent *pEvent) const
2047 {
2048 static const char* const EventNames[] =
2049 {
2050 nullptr,
2051 nullptr,
2052 "KeyPress",
2053 "KeyRelease",
2054 "ButtonPress",
2055 "ButtonRelease",
2056 "MotionNotify",
2057 "EnterNotify",
2058 "LeaveNotify",
2059 "FocusIn",
2060 "FocusOut",
2061 "KeymapNotify",
2062 "Expose",
2063 "GraphicsExpose",
2064 "NoExpose",
2065 "VisibilityNotify",
2066 "CreateNotify",
2067 "DestroyNotify",
2068 "UnmapNotify",
2069 "MapNotify",
2070 "MapRequest",
2071 "ReparentNotify",
2072 "ConfigureNotify",
2073 "ConfigureRequest",
2074 "GravityNotify",
2075 "ResizeRequest",
2076 "CirculateNotify",
2077 "CirculateRequest",
2078 "PropertyNotify",
2079 "SelectionClear",
2080 "SelectionRequest",
2081 "SelectionNotify",
2082 "ColormapNotify",
2083 "ClientMessage",
2084 "MappingNotify"
2085 };
2086
2087 if( pEvent->type <= MappingNotify )
2088 {
2089 fprintf( stderr, "[%s] %s s=%d w=%ld\n",
2090 pComment,
2091 EventNames[pEvent->type],
2092 pEvent->xany.send_event,
2093 pEvent->xany.window );
2094
2095 switch( pEvent->type )
2096 {
2097 case KeyPress:
2098 case KeyRelease:
2099 fprintf( stderr, "\t\ts=%d c=%d\n",
2100 pEvent->xkey.state,
2101 pEvent->xkey.keycode );
2102 break;
2103
2104 case ButtonPress:
2105 case ButtonRelease:
2106 fprintf( stderr, "\t\ts=%d b=%d x=%d y=%d rx=%d ry=%d\n",
2107 pEvent->xbutton.state,
2108 pEvent->xbutton.button,
2109 pEvent->xbutton.x,
2110 pEvent->xbutton.y,
2111 pEvent->xbutton.x_root,
2112 pEvent->xbutton.y_root );
2113 break;
2114
2115 case MotionNotify:
2116 fprintf( stderr, "\t\ts=%d x=%d y=%d\n",
2117 pEvent->xmotion.state,
2118 pEvent->xmotion.x,
2119 pEvent->xmotion.y );
2120 break;
2121
2122 case EnterNotify:
2123 case LeaveNotify:
2124 fprintf( stderr, "\t\tm=%d f=%d x=%d y=%d\n",
2125 pEvent->xcrossing.mode,
2126 pEvent->xcrossing.focus,
2127 pEvent->xcrossing.x,
2128 pEvent->xcrossing.y );
2129 break;
2130
2131 case FocusIn:
2132 case FocusOut:
2133 fprintf( stderr, "\t\tm=%d d=%d\n",
2134 pEvent->xfocus.mode,
2135 pEvent->xfocus.detail );
2136 break;
2137
2138 case Expose:
2139 case GraphicsExpose:
2140 fprintf( stderr, "\t\tc=%d %d*%d %d+%d\n",
2141 pEvent->xexpose.count,
2142 pEvent->xexpose.width,
2143 pEvent->xexpose.height,
2144 pEvent->xexpose.x,
2145 pEvent->xexpose.y );
2146 break;
2147
2148 case VisibilityNotify:
2149 fprintf( stderr, "\t\ts=%d\n",
2150 pEvent->xvisibility.state );
2151 break;
2152
2153 case CreateNotify:
2154 case DestroyNotify:
2155 break;
2156
2157 case MapNotify:
2158 case UnmapNotify:
2159 break;
2160
2161 case ReparentNotify:
2162 fprintf( stderr, "\t\tp=%d x=%d y=%d\n",
2163 sal::static_int_cast< int >(pEvent->xreparent.parent),
2164 pEvent->xreparent.x,
2165 pEvent->xreparent.y );
2166 break;
2167
2168 case ConfigureNotify:
2169 fprintf( stderr, "\t\tb=%d %d*%d %d+%d\n",
2170 pEvent->xconfigure.border_width,
2171 pEvent->xconfigure.width,
2172 pEvent->xconfigure.height,
2173 pEvent->xconfigure.x,
2174 pEvent->xconfigure.y );
2175 break;
2176
2177 case PropertyNotify:
2178 fprintf( stderr, "\t\ta=%s (0x%X)\n",
2179 GetAtomName( pDisp_, pEvent->xproperty.atom ),
2180 sal::static_int_cast< unsigned int >(
2181 pEvent->xproperty.atom) );
2182 break;
2183
2184 case ColormapNotify:
2185 fprintf( stderr, "\t\tc=%ld n=%d s=%d\n",
2186 pEvent->xcolormap.colormap,
2187 pEvent->xcolormap.c_new,
2188 pEvent->xcolormap.state );
2189 break;
2190
2191 case ClientMessage:
2192 fprintf( stderr, "\t\ta=%s (0x%X) f=%i [0x%lX,0x%lX,0x%lX,0x%lX,0x%lX])\n",
2193 GetAtomName( pDisp_, pEvent->xclient.message_type ),
2194 sal::static_int_cast< unsigned int >(
2195 pEvent->xclient.message_type),
2196 pEvent->xclient.format,
2197 pEvent->xclient.data.l[0],
2198 pEvent->xclient.data.l[1],
2199 pEvent->xclient.data.l[2],
2200 pEvent->xclient.data.l[3],
2201 pEvent->xclient.data.l[4] );
2202 break;
2203
2204 case MappingNotify:
2205 fprintf( stderr, "\t\tr=%sd\n",
2206 MappingModifier == pEvent->xmapping.request
2207 ? "MappingModifier"
2208 : MappingKeyboard == pEvent->xmapping.request
2209 ? "MappingKeyboard"
2210 : "MappingPointer" );
2211
2212 break;
2213 }
2214 }
2215 else
2216 fprintf( stderr, "[%s] %d s=%d w=%ld\n",
2217 pComment,
2218 pEvent->type,
2219 pEvent->xany.send_event,
2220 pEvent->xany.window );
2221 }
2222
PrintInfo() const2223 void SalDisplay::PrintInfo() const
2224 {
2225 if( IsDisplay() )
2226 {
2227 SAL_INFO( "vcl", "Environment" );
2228 SAL_INFO( "vcl", "\t$DISPLAY \t\"" << GetEnv( "DISPLAY" ) << "\"");
2229 SAL_INFO( "vcl", "\t$SAL_VISUAL \t\"" << GetEnv( "SAL_VISUAL" ) << "\"");
2230 SAL_INFO( "vcl", "\t$SAL_IGNOREXERRORS\t\"" << GetEnv( "SAL_IGNOREXERRORS" ) << "\"");
2231 SAL_INFO( "vcl", "\t$SAL_PROPERTIES \t\"" << GetEnv( "SAL_PROPERTIES" ) << "\"");
2232 SAL_INFO( "vcl", "\t$SAL_SYNCHRONIZE \t\"" << GetEnv( "SAL_SYNCHRONIZE" ) << "\"");
2233
2234 char sHostname[ 120 ];
2235 gethostname (sHostname, 120 );
2236 SAL_INFO( "vcl", "Client" );
2237 SAL_INFO( "vcl", "\tHost \t\"" << sHostname << "\"");
2238
2239 SAL_INFO( "vcl", "Display" );
2240 SAL_INFO( "vcl", "\tHost \t\"" << DisplayString(pDisp_) << "\"");
2241 SAL_INFO( "vcl", "\tVendor (Release) \t\"" << ServerVendor(pDisp_) << " (" << VendorRelease(pDisp_) << ")\"");
2242 SAL_INFO( "vcl", "\tProtocol \t" << ProtocolVersion(pDisp_) << "." << ProtocolRevision(pDisp_) );
2243 SAL_INFO( "vcl", "\tScreen (count,def)\t" << m_nXDefaultScreen.getXScreen() << " (" << ScreenCount(pDisp_) << "," << DefaultScreen(pDisp_) << ")");
2244 SAL_INFO( "vcl", "\tshift ctrl alt \t" << KeyStr( nShiftKeySym_ ) << " (0x" << std::hex << sal::static_int_cast< unsigned int >(nShiftKeySym_) << ") "
2245 << KeyStr( nCtrlKeySym_ ) << " (0x" << sal::static_int_cast< unsigned int >(nCtrlKeySym_) << ") "
2246 << KeyStr( nMod1KeySym_ ) << " (0x" << sal::static_int_cast< unsigned int >(nMod1KeySym_) << ")");
2247 if( XExtendedMaxRequestSize(pDisp_) != 0 )
2248 SAL_INFO( "vcl", "\tXMaxRequestSize \t" << XMaxRequestSize(pDisp_) * 4 << " " << XExtendedMaxRequestSize(pDisp_) * 4 << " [bytes]");
2249 SAL_INFO( "vcl", "\tWMName \t" << getWMAdaptor()->getWindowManagerName() );
2250 }
2251 SAL_INFO( "vcl", "Screen" );
2252 SAL_INFO( "vcl", "\tResolution/Size \t" << aResolution_.A() << "*" << aResolution_.B()
2253 << " " << m_aScreens[m_nXDefaultScreen.getXScreen()].m_aSize.Width() << "*" << m_aScreens[m_nXDefaultScreen.getXScreen()].m_aSize.Height()
2254 << " " << (Hypothenuse( DisplayWidthMM ( pDisp_, m_nXDefaultScreen.getXScreen() ),
2255 DisplayHeightMM( pDisp_, m_nXDefaultScreen.getXScreen() ) ) / 25.4 ) << "\"" );
2256 SAL_INFO( "vcl", "\tBlack&White \t" << GetColormap(m_nXDefaultScreen).GetBlackPixel() << " "
2257 << GetColormap(m_nXDefaultScreen).GetWhitePixel() );
2258 SAL_INFO( "vcl", "\tRGB \t0x" << std::hex << GetVisual(m_nXDefaultScreen).red_mask
2259 << " 0x" << GetVisual(m_nXDefaultScreen).green_mask
2260 << " 0x" << GetVisual(m_nXDefaultScreen).blue_mask);
2261 }
2262 #endif
2263
addXineramaScreenUnique(int i,long i_nX,long i_nY,long i_nWidth,long i_nHeight)2264 void SalDisplay::addXineramaScreenUnique( int i, long i_nX, long i_nY, long i_nWidth, long i_nHeight )
2265 {
2266 // see if any frame buffers are at the same coordinates
2267 // this can happen with weird configuration e.g. on
2268 // XFree86 and Clone displays
2269 const size_t nScreens = m_aXineramaScreens.size();
2270 for( size_t n = 0; n < nScreens; n++ )
2271 {
2272 if( m_aXineramaScreens[n].Left() == i_nX &&
2273 m_aXineramaScreens[n].Top() == i_nY )
2274 {
2275 if( m_aXineramaScreens[n].GetWidth() < i_nWidth ||
2276 m_aXineramaScreens[n].GetHeight() < i_nHeight )
2277 {
2278 m_aXineramaScreenIndexMap[i] = n;
2279 m_aXineramaScreens[n].SetSize( Size( i_nWidth, i_nHeight ) );
2280 }
2281 return;
2282 }
2283 }
2284 m_aXineramaScreenIndexMap[i] = m_aXineramaScreens.size();
2285 m_aXineramaScreens.emplace_back( Point( i_nX, i_nY ), Size( i_nWidth, i_nHeight ) );
2286 }
2287
InitXinerama()2288 void SalDisplay::InitXinerama()
2289 {
2290 if( m_aScreens.size() > 1 )
2291 {
2292 m_bXinerama = false;
2293 return; // multiple screens mean no xinerama
2294 }
2295 #if defined(USE_XINERAMA_XORG)
2296 if( XineramaIsActive( pDisp_ ) )
2297 {
2298 int nFramebuffers = 1;
2299 XineramaScreenInfo* pScreens = XineramaQueryScreens( pDisp_, &nFramebuffers );
2300 if( pScreens )
2301 {
2302 if( nFramebuffers > 1 )
2303 {
2304 m_aXineramaScreens = std::vector<tools::Rectangle>();
2305 m_aXineramaScreenIndexMap = std::vector<int>(nFramebuffers);
2306 for( int i = 0; i < nFramebuffers; i++ )
2307 {
2308 addXineramaScreenUnique( i, pScreens[i].x_org,
2309 pScreens[i].y_org,
2310 pScreens[i].width,
2311 pScreens[i].height );
2312 }
2313 m_bXinerama = m_aXineramaScreens.size() > 1;
2314 }
2315 XFree( pScreens );
2316 }
2317 }
2318 #endif
2319 #if OSL_DEBUG_LEVEL > 1
2320 if( m_bXinerama )
2321 {
2322 for (auto const& screen : m_aXineramaScreens)
2323 fprintf( stderr, "Xinerama screen: %ldx%ld+%ld+%ld\n", screen.GetWidth(), screen.GetHeight(), screen.Left(), screen.Top() );
2324 }
2325 #endif
2326 }
2327
2328 extern "C"
2329 {
timestamp_predicate(Display *,XEvent * i_pEvent,XPointer i_pArg)2330 static Bool timestamp_predicate( Display*, XEvent* i_pEvent, XPointer i_pArg )
2331 {
2332 SalDisplay* pSalDisplay = reinterpret_cast<SalDisplay*>(i_pArg);
2333 if( i_pEvent->type == PropertyNotify &&
2334 i_pEvent->xproperty.window == pSalDisplay->GetDrawable( pSalDisplay->GetDefaultXScreen() ) &&
2335 i_pEvent->xproperty.atom == pSalDisplay->getWMAdaptor()->getAtom( WMAdaptor::SAL_GETTIMEEVENT )
2336 )
2337 return True;
2338
2339 return False;
2340 }
2341 }
2342
GetEventTimeImpl(bool i_bAlwaysReget) const2343 Time SalDisplay::GetEventTimeImpl( bool i_bAlwaysReget ) const
2344 {
2345 if( m_nLastUserEventTime == CurrentTime || i_bAlwaysReget )
2346 {
2347 // get current server time
2348 unsigned char c = 0;
2349 XEvent aEvent;
2350 Atom nAtom = getWMAdaptor()->getAtom( WMAdaptor::SAL_GETTIMEEVENT );
2351 XChangeProperty( GetDisplay(), GetDrawable( GetDefaultXScreen() ),
2352 nAtom, nAtom, 8, PropModeReplace, &c, 1 );
2353 XIfEvent( GetDisplay(), &aEvent, timestamp_predicate, reinterpret_cast<XPointer>(const_cast<SalDisplay *>(this)));
2354 m_nLastUserEventTime = aEvent.xproperty.time;
2355 }
2356 return m_nLastUserEventTime;
2357 }
2358
XIfEventWithTimeout(XEvent * o_pEvent,XPointer i_pPredicateData,X_if_predicate i_pPredicate) const2359 bool SalDisplay::XIfEventWithTimeout( XEvent* o_pEvent, XPointer i_pPredicateData,
2360 X_if_predicate i_pPredicate ) const
2361 {
2362 /* #i99360# ugly workaround an X11 library bug
2363 this replaces the following call:
2364 XIfEvent( GetDisplay(), o_pEvent, i_pPredicate, i_pPredicateData );
2365 */
2366 bool bRet = true;
2367
2368 if( ! XCheckIfEvent( GetDisplay(), o_pEvent, i_pPredicate, i_pPredicateData ) )
2369 {
2370 // wait for some event to arrive
2371 struct pollfd aFD;
2372 aFD.fd = ConnectionNumber(GetDisplay());
2373 aFD.events = POLLIN;
2374 aFD.revents = 0;
2375 long nTimeout = 1000;
2376 (void)poll(&aFD, 1, nTimeout);
2377 if( ! XCheckIfEvent( GetDisplay(), o_pEvent, i_pPredicate, i_pPredicateData ) )
2378 {
2379 (void)poll(&aFD, 1, nTimeout); // try once more for a packet of events from the Xserver
2380 if( ! XCheckIfEvent( GetDisplay(), o_pEvent, i_pPredicate, i_pPredicateData ) )
2381 {
2382 bRet = false;
2383 }
2384 }
2385 }
2386 return bRet;
2387 }
2388
SalVisual()2389 SalVisual::SalVisual():
2390 eRGBMode_(SalRGB::RGB), nRedShift_(0), nGreenShift_(0), nBlueShift_(0), nRedBits_(0), nGreenBits_(0),
2391 nBlueBits_(0)
2392 {}
2393
SalVisual(const XVisualInfo * pXVI)2394 SalVisual::SalVisual( const XVisualInfo* pXVI )
2395 {
2396 *static_cast<XVisualInfo*>(this) = *pXVI;
2397 if( GetClass() == TrueColor )
2398 {
2399 nRedShift_ = sal_Shift( red_mask );
2400 nGreenShift_ = sal_Shift( green_mask );
2401 nBlueShift_ = sal_Shift( blue_mask );
2402
2403 nRedBits_ = sal_significantBits( red_mask );
2404 nGreenBits_ = sal_significantBits( green_mask );
2405 nBlueBits_ = sal_significantBits( blue_mask );
2406
2407 if( GetDepth() == 24 )
2408 if( red_mask == 0xFF0000 )
2409 if( green_mask == 0xFF00 )
2410 if( blue_mask == 0xFF )
2411 eRGBMode_ = SalRGB::RGB;
2412 else
2413 eRGBMode_ = SalRGB::otherSalRGB;
2414 else if( blue_mask == 0xFF00 )
2415 if( green_mask == 0xFF )
2416 eRGBMode_ = SalRGB::RBG;
2417 else
2418 eRGBMode_ = SalRGB::otherSalRGB;
2419 else
2420 eRGBMode_ = SalRGB::otherSalRGB;
2421 else if( green_mask == 0xFF0000 )
2422 if( red_mask == 0xFF00 )
2423 if( blue_mask == 0xFF )
2424 eRGBMode_ = SalRGB::GRB;
2425 else
2426 eRGBMode_ = SalRGB::otherSalRGB;
2427 else if( blue_mask == 0xFF00 )
2428 if( red_mask == 0xFF )
2429 eRGBMode_ = SalRGB::GBR;
2430 else
2431 eRGBMode_ = SalRGB::otherSalRGB;
2432 else
2433 eRGBMode_ = SalRGB::otherSalRGB;
2434 else if( blue_mask == 0xFF0000 )
2435 if( red_mask == 0xFF00 )
2436 if( green_mask == 0xFF )
2437 eRGBMode_ = SalRGB::BRG;
2438 else
2439 eRGBMode_ = SalRGB::otherSalRGB;
2440 else if( green_mask == 0xFF00 )
2441 if( red_mask == 0xFF )
2442 eRGBMode_ = SalRGB::BGR;
2443 else
2444 eRGBMode_ = SalRGB::otherSalRGB;
2445 else
2446 eRGBMode_ = SalRGB::otherSalRGB;
2447 else
2448 eRGBMode_ = SalRGB::otherSalRGB;
2449 else
2450 eRGBMode_ = SalRGB::otherSalRGB;
2451 }
2452 }
2453
2454 // Converts the order of bytes of a Pixel into bytes of a Color
2455 // This is not reversible for the 6 XXXA
2456
2457 // Color is RGB (ABGR) a=0xFF000000, r=0xFF0000, g=0xFF00, b=0xFF
2458
2459 #define SALCOLOR SalRGB::RGB
2460 #define SALCOLORREVERSE SalRGB::BGR
2461
GetTCColor(Pixel nPixel) const2462 Color SalVisual::GetTCColor( Pixel nPixel ) const
2463 {
2464 if( SALCOLOR == eRGBMode_ )
2465 return static_cast<Color>(nPixel);
2466
2467 if( SALCOLORREVERSE == eRGBMode_ )
2468 return Color( (nPixel & 0x0000FF),
2469 (nPixel & 0x00FF00) >> 8,
2470 (nPixel & 0xFF0000) >> 16);
2471
2472 Pixel r = nPixel & red_mask;
2473 Pixel g = nPixel & green_mask;
2474 Pixel b = nPixel & blue_mask;
2475
2476 if( SalRGB::otherSalRGB != eRGBMode_ ) // 8+8+8=24
2477 return Color( r >> nRedShift_,
2478 g >> nGreenShift_,
2479 b >> nBlueShift_ );
2480
2481 if( nRedShift_ > 0 ) r >>= nRedShift_; else r <<= -nRedShift_;
2482 if( nGreenShift_ > 0 ) g >>= nGreenShift_; else g <<= -nGreenShift_;
2483 if( nBlueShift_ > 0 ) b >>= nBlueShift_; else b <<= -nBlueShift_;
2484
2485 if( nRedBits_ != 8 )
2486 r |= (r & 0xff) >> (8-nRedBits_);
2487 if( nGreenBits_ != 8 )
2488 g |= (g & 0xff) >> (8-nGreenBits_);
2489 if( nBlueBits_ != 8 )
2490 b |= (b & 0xff) >> (8-nBlueBits_);
2491
2492 return Color( r, g, b );
2493 }
2494
GetTCPixel(Color nColor) const2495 Pixel SalVisual::GetTCPixel( Color nColor ) const
2496 {
2497 if( SALCOLOR == eRGBMode_ )
2498 return static_cast<Pixel>(sal_uInt32(nColor));
2499
2500 Pixel r = static_cast<Pixel>( nColor.GetRed() );
2501 Pixel g = static_cast<Pixel>( nColor.GetGreen() );
2502 Pixel b = static_cast<Pixel>( nColor.GetBlue() );
2503
2504 if( SALCOLORREVERSE == eRGBMode_ )
2505 return (b << 16) | (g << 8) | r;
2506
2507 if( SalRGB::otherSalRGB != eRGBMode_ ) // 8+8+8=24
2508 return (r << nRedShift_) | (g << nGreenShift_) | (b << nBlueShift_);
2509
2510 if( nRedShift_ > 0 ) r <<= nRedShift_; else r >>= -nRedShift_;
2511 if( nGreenShift_ > 0 ) g <<= nGreenShift_; else g >>= -nGreenShift_;
2512 if( nBlueShift_ > 0 ) b <<= nBlueShift_; else b >>= -nBlueShift_;
2513
2514 return (r&red_mask) | (g&green_mask) | (b&blue_mask);
2515 }
2516
SalColormap(const SalDisplay * pDisplay,Colormap hColormap,SalX11Screen nXScreen)2517 SalColormap::SalColormap( const SalDisplay *pDisplay, Colormap hColormap,
2518 SalX11Screen nXScreen )
2519 : m_pDisplay( pDisplay ),
2520 m_hColormap( hColormap ),
2521 m_nXScreen( nXScreen )
2522 {
2523 m_aVisual = m_pDisplay->GetVisual( m_nXScreen );
2524
2525 XColor aColor;
2526
2527 GetXPixel( aColor, 0x00, 0x00, 0x00 );
2528 m_nBlackPixel = aColor.pixel;
2529
2530 GetXPixel( aColor, 0xFF, 0xFF, 0xFF );
2531 m_nWhitePixel = aColor.pixel;
2532
2533 m_nUsed = 1 << m_aVisual.GetDepth();
2534
2535 if( m_aVisual.GetClass() != PseudoColor )
2536 return;
2537
2538 int r, g, b;
2539
2540 // black, white, gray, ~gray = 4
2541 GetXPixels( aColor, 0xC0, 0xC0, 0xC0 );
2542
2543 // light colors: 3 * 2 = 6
2544
2545 GetXPixels( aColor, 0x00, 0x00, 0xFF );
2546 GetXPixels( aColor, 0x00, 0xFF, 0x00 );
2547 GetXPixels( aColor, 0x00, 0xFF, 0xFF );
2548
2549 // standard colors: 7 * 2 = 14
2550 GetXPixels( aColor, 0x00, 0x00, 0x80 );
2551 GetXPixels( aColor, 0x00, 0x80, 0x00 );
2552 GetXPixels( aColor, 0x00, 0x80, 0x80 );
2553 GetXPixels( aColor, 0x80, 0x00, 0x00 );
2554 GetXPixels( aColor, 0x80, 0x00, 0x80 );
2555 GetXPixels( aColor, 0x80, 0x80, 0x00 );
2556 GetXPixels( aColor, 0x80, 0x80, 0x80 );
2557 GetXPixels( aColor, 0x00, 0xB8, 0xFF ); // Blue 7
2558
2559 // cube: 6*6*6 - 8 = 208
2560 for( r = 0; r < 0x100; r += 0x33 ) // 0x33, 0x66, 0x99, 0xCC, 0xFF
2561 for( g = 0; g < 0x100; g += 0x33 )
2562 for( b = 0; b < 0x100; b += 0x33 )
2563 GetXPixels( aColor, r, g, b );
2564
2565 // gray: 16 - 6 = 10
2566 for( g = 0x11; g < 0xFF; g += 0x11 )
2567 GetXPixels( aColor, g, g, g );
2568
2569 // green: 16 - 6 = 10
2570 for( g = 0x11; g < 0xFF; g += 0x11 )
2571 GetXPixels( aColor, 0, g, 0 );
2572
2573 // red: 16 - 6 = 10
2574 for( r = 0x11; r < 0xFF; r += 0x11 )
2575 GetXPixels( aColor, r, 0, 0 );
2576
2577 // blue: 16 - 6 = 10
2578 for( b = 0x11; b < 0xFF; b += 0x11 )
2579 GetXPixels( aColor, 0, 0, b );
2580
2581 }
2582
2583 // MonoChrome
SalColormap()2584 SalColormap::SalColormap()
2585 : m_pDisplay( vcl_sal::getSalDisplay(GetGenericUnixSalData()) ),
2586 m_hColormap( None ),
2587 m_nWhitePixel( 1 ),
2588 m_nBlackPixel( 0 ),
2589 m_nUsed( 2 ),
2590 m_nXScreen( m_pDisplay != nullptr ? m_pDisplay->GetDefaultXScreen() : SalX11Screen( 0 ) )
2591 {
2592 m_aPalette = std::vector<Color>(m_nUsed);
2593
2594 m_aPalette[m_nBlackPixel] = COL_BLACK;
2595 m_aPalette[m_nWhitePixel] = COL_WHITE;
2596 }
2597
2598 // TrueColor
SalColormap(sal_uInt16 nDepth)2599 SalColormap::SalColormap( sal_uInt16 nDepth )
2600 : m_pDisplay( vcl_sal::getSalDisplay(GetGenericUnixSalData()) ),
2601 m_hColormap( None ),
2602 m_nWhitePixel( (1 << nDepth) - 1 ),
2603 m_nBlackPixel( 0x00000000 ),
2604 m_nUsed( 1 << nDepth ),
2605 m_nXScreen( vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetDefaultXScreen() )
2606 {
2607 const SalVisual *pVisual = &m_pDisplay->GetVisual( m_nXScreen );
2608
2609 if( pVisual->GetClass() == TrueColor && pVisual->GetDepth() == nDepth )
2610 m_aVisual = *pVisual;
2611 else
2612 {
2613 XVisualInfo aVI;
2614
2615 if( !XMatchVisualInfo( m_pDisplay->GetDisplay(),
2616 m_pDisplay->GetDefaultXScreen().getXScreen(),
2617 nDepth,
2618 TrueColor,
2619 &aVI ) )
2620 {
2621 aVI.visual = new Visual;
2622 aVI.visualid = VisualID(-1);
2623 aVI.screen = -1;
2624 aVI.depth = nDepth;
2625 aVI.c_class = TrueColor;
2626 if( 24 == nDepth ) // 888
2627 {
2628 aVI.red_mask = 0xFF0000;
2629 aVI.green_mask = 0x00FF00;
2630 aVI.blue_mask = 0x0000FF;
2631 }
2632 else if( 8 == nDepth ) // 332
2633 {
2634 aVI.red_mask = 0x0000E0;
2635 aVI.green_mask = 0x00001C;
2636 aVI.blue_mask = 0x000003;
2637 }
2638 else
2639 {
2640 aVI.red_mask = 0x000000;
2641 aVI.green_mask = 0x000000;
2642 aVI.blue_mask = 0x000000;
2643 }
2644 aVI.colormap_size = 0;
2645 aVI.bits_per_rgb = 8;
2646
2647 aVI.visual->ext_data = nullptr;
2648 aVI.visual->visualid = aVI.visualid;
2649 aVI.visual->c_class = aVI.c_class;
2650 aVI.visual->red_mask = aVI.red_mask;
2651 aVI.visual->green_mask = aVI.green_mask;
2652 aVI.visual->blue_mask = aVI.blue_mask;
2653 aVI.visual->bits_per_rgb = aVI.bits_per_rgb;
2654 aVI.visual->map_entries = aVI.colormap_size;
2655
2656 m_aVisual = SalVisual( &aVI );
2657 m_aVisualOwnership.owner = true;
2658 }
2659 else
2660 m_aVisual = SalVisual( &aVI );
2661 }
2662 }
2663
~SalColormap()2664 SalColormap::~SalColormap()
2665 {
2666 if (m_aVisualOwnership.owner)
2667 {
2668 delete m_aVisual.visual;
2669 }
2670 }
2671
GetPalette()2672 void SalColormap::GetPalette()
2673 {
2674 Pixel i;
2675 m_aPalette = std::vector<Color>(m_nUsed);
2676
2677 std::unique_ptr<XColor[]> aColor(new XColor[m_nUsed]);
2678
2679 for( i = 0; i < m_nUsed; i++ )
2680 {
2681 aColor[i].red = aColor[i].green = aColor[i].blue = 0;
2682 aColor[i].pixel = i;
2683 }
2684
2685 XQueryColors( m_pDisplay->GetDisplay(), m_hColormap, aColor.get(), m_nUsed );
2686
2687 for( i = 0; i < m_nUsed; i++ )
2688 {
2689 m_aPalette[i] = Color( aColor[i].red >> 8,
2690 aColor[i].green >> 8,
2691 aColor[i].blue >> 8 );
2692 }
2693 }
2694
sal_Lookup(const std::vector<Color> & rPalette,int r,int g,int b,Pixel nUsed)2695 static sal_uInt16 sal_Lookup( const std::vector<Color>& rPalette,
2696 int r, int g, int b,
2697 Pixel nUsed )
2698 {
2699 sal_uInt16 nPixel = 0;
2700 int nBest = ColorDiff( rPalette[0], r, g, b );
2701
2702 for( Pixel i = 1; i < nUsed; i++ )
2703 {
2704 int n = ColorDiff( rPalette[i], r, g, b );
2705
2706 if( n < nBest )
2707 {
2708 if( !n )
2709 return i;
2710
2711 nPixel = i;
2712 nBest = n;
2713 }
2714 }
2715 return nPixel;
2716 }
2717
GetLookupTable()2718 void SalColormap::GetLookupTable()
2719 {
2720 m_aLookupTable = std::vector<sal_uInt16>(16*16*16);
2721
2722 int i = 0;
2723 for( int r = 0; r < 256; r += 17 )
2724 for( int g = 0; g < 256; g += 17 )
2725 for( int b = 0; b < 256; b += 17 )
2726 m_aLookupTable[i++] = sal_Lookup( m_aPalette, r, g, b, m_nUsed );
2727 }
2728
GetColor(Pixel nPixel) const2729 Color SalColormap::GetColor( Pixel nPixel ) const
2730 {
2731 if( m_nBlackPixel == nPixel ) return COL_BLACK;
2732 if( m_nWhitePixel == nPixel ) return COL_WHITE;
2733
2734 if( m_aVisual.GetVisual() )
2735 {
2736 if( m_aVisual.GetClass() == TrueColor )
2737 return m_aVisual.GetTCColor( nPixel );
2738
2739 if( m_aPalette.empty()
2740 && m_hColormap
2741 && m_aVisual.GetDepth() <= 12
2742 && m_aVisual.GetClass() == PseudoColor )
2743 const_cast<SalColormap*>(this)->GetPalette();
2744 }
2745
2746 if( !m_aPalette.empty() && nPixel < m_nUsed )
2747 return m_aPalette[nPixel];
2748
2749 if( !m_hColormap )
2750 {
2751 SAL_WARN("vcl", "SalColormap::GetColor() !m_hColormap");
2752 return nPixel;
2753 }
2754
2755 // DirectColor, StaticColor, StaticGray, GrayScale
2756 XColor aColor;
2757
2758 aColor.pixel = nPixel;
2759
2760 XQueryColor( m_pDisplay->GetDisplay(), m_hColormap, &aColor );
2761
2762 return Color( aColor.red>>8, aColor.green>>8, aColor.blue>>8 );
2763 }
2764
GetXPixel(XColor & rColor,int r,int g,int b) const2765 inline bool SalColormap::GetXPixel( XColor &rColor,
2766 int r,
2767 int g,
2768 int b ) const
2769 {
2770 rColor.red = r * 257;
2771 rColor.green = g * 257;
2772 rColor.blue = b * 257;
2773 return XAllocColor( GetXDisplay(), m_hColormap, &rColor );
2774 }
2775
GetXPixels(XColor & rColor,int r,int g,int b) const2776 bool SalColormap::GetXPixels( XColor &rColor,
2777 int r,
2778 int g,
2779 int b ) const
2780 {
2781 if( !GetXPixel( rColor, r, g, b ) )
2782 return false;
2783 if( rColor.pixel & 1 )
2784 return true;
2785 return GetXPixel( rColor, r^0xFF, g^0xFF, b^0xFF );
2786 }
2787
GetPixel(Color nColor) const2788 Pixel SalColormap::GetPixel( Color nColor ) const
2789 {
2790 if( SALCOLOR_NONE == nColor ) return 0;
2791 if( COL_BLACK == nColor ) return m_nBlackPixel;
2792 if( COL_WHITE == nColor ) return m_nWhitePixel;
2793
2794 if( m_aVisual.GetClass() == TrueColor )
2795 return m_aVisual.GetTCPixel( nColor );
2796
2797 if( m_aLookupTable.empty() )
2798 {
2799 if( m_aPalette.empty()
2800 && m_hColormap
2801 && m_aVisual.GetDepth() <= 12
2802 && m_aVisual.GetClass() == PseudoColor ) // what else ???
2803 const_cast<SalColormap*>(this)->GetPalette();
2804
2805 if( !m_aPalette.empty() )
2806 for( Pixel i = 0; i < m_nUsed; i++ )
2807 if( m_aPalette[i] == nColor )
2808 return i;
2809
2810 if( m_hColormap )
2811 {
2812 // DirectColor, StaticColor, StaticGray, GrayScale (PseudoColor)
2813 XColor aColor;
2814
2815 if( GetXPixel( aColor,
2816 nColor.GetRed(),
2817 nColor.GetGreen(),
2818 nColor.GetBlue() ) )
2819 {
2820 if( !m_aPalette.empty() && m_aPalette[aColor.pixel] == Color(0) )
2821 {
2822 const_cast<SalColormap*>(this)->m_aPalette[aColor.pixel] = nColor;
2823
2824 if( !(aColor.pixel & 1) && m_aPalette[aColor.pixel+1] == Color(0) )
2825 {
2826 XColor aInversColor;
2827
2828 Color nInversColor = sal_uInt32(nColor) ^ 0xFFFFFF;
2829
2830 GetXPixel( aInversColor,
2831 nInversColor.GetRed(),
2832 nInversColor.GetGreen(),
2833 nInversColor.GetBlue() );
2834
2835 if( m_aPalette[aInversColor.pixel] == Color(0) )
2836 const_cast<SalColormap*>(this)->m_aPalette[aInversColor.pixel] = nInversColor;
2837 #ifdef DBG_UTIL
2838 else
2839 fprintf( stderr, "SalColormap::GetPixel() 0x%06lx=%lu 0x%06lx=%lu\n",
2840 static_cast< unsigned long >(sal_uInt32(nColor)), aColor.pixel,
2841 static_cast< unsigned long >(sal_uInt32(nInversColor)), aInversColor.pixel);
2842 #endif
2843 }
2844 }
2845
2846 return aColor.pixel;
2847 }
2848
2849 #ifdef DBG_UTIL
2850 fprintf( stderr, "SalColormap::GetPixel() !XAllocColor %lx\n",
2851 static_cast< unsigned long >(sal_uInt32(nColor)) );
2852 #endif
2853 }
2854
2855 if( m_aPalette.empty() )
2856 {
2857 #ifdef DBG_UTIL
2858 fprintf( stderr, "SalColormap::GetPixel() Palette empty %lx\n",
2859 static_cast< unsigned long >(sal_uInt32(nColor)));
2860 #endif
2861 return sal_uInt32(nColor);
2862 }
2863
2864 const_cast<SalColormap*>(this)->GetLookupTable();
2865 }
2866
2867 // color matching via palette
2868 sal_uInt16 r = nColor.GetRed();
2869 sal_uInt16 g = nColor.GetGreen();
2870 sal_uInt16 b = nColor.GetBlue();
2871 return m_aLookupTable[ (((r+8)/17) << 8)
2872 + (((g+8)/17) << 4)
2873 + ((b+8)/17) ];
2874 }
2875
2876 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2877