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