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