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