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