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