xref: /core/vcl/unx/generic/window/salframe.cxx (revision 10831c8b)
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 <string_view>
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 #include <tools/debug.hxx>
26 
27 #include <vcl/event.hxx>
28 #include <vcl/toolkit/floatwin.hxx>
29 #include <vcl/keycodes.hxx>
30 #include <vcl/settings.hxx>
31 #include <vcl/BitmapReadAccess.hxx>
32 #include <vcl/opengl/OpenGLContext.hxx>
33 #include <vcl/BitmapTools.hxx>
34 
35 #include <X11/Xlib.h>
36 #include <X11/Xutil.h>
37 #include <X11/Xatom.h>
38 #include <X11/keysym.h>
39 #include <X11/extensions/shape.h>
40 
41 #include <headless/BitmapHelper.hxx>
42 #include <headless/svpbmp.hxx>
43 #include <unx/saldisp.hxx>
44 #include <unx/salgdi.h>
45 #include <unx/salframe.h>
46 #include <unx/wmadaptor.hxx>
47 #include <unx/i18n_ic.hxx>
48 #include <unx/i18n_keysym.hxx>
49 #include <opengl/zone.hxx>
50 
51 #include <unx/gensys.h>
52 #include <window.h>
53 
54 #include <sal/macros.h>
55 #include <sal/log.hxx>
56 #include <o3tl/safeint.hxx>
57 #include <o3tl/string_view.hxx>
58 #include <com/sun/star/uno/Exception.hpp>
59 
60 #include <salinst.hxx>
61 #include <svdata.hxx>
62 #include <bitmaps.hlst>
63 
64 #include <cairo-xlib.h>
65 
66 #include <optional>
67 
68 #include <algorithm>
69 
70 #ifndef Button6
71 # define Button6 6
72 #endif
73 #ifndef Button7
74 # define Button7 7
75 #endif
76 
77 using namespace vcl_sal;
78 
79 constexpr auto CLIENT_EVENTS = StructureNotifyMask
80                                 | SubstructureNotifyMask
81                                 | KeyPressMask
82                                 | KeyReleaseMask
83                                 | ButtonPressMask
84                                 | ButtonReleaseMask
85                                 | PointerMotionMask
86                                 | EnterWindowMask
87                                 | LeaveWindowMask
88                                 | FocusChangeMask
89                                 | ExposureMask
90                                 | VisibilityChangeMask
91                                 | PropertyChangeMask
92                                 | ColormapChangeMask;
93 
94 static ::Window  hPresentationWindow = None, hPresFocusWindow = None;
95 static ::std::list< ::Window > aPresentationReparentList;
96 static int          nVisibleFloats      = 0;
97 
doReparentPresentationDialogues(SalDisplay const * pDisplay)98 static void doReparentPresentationDialogues( SalDisplay const * pDisplay )
99 {
100     GetGenericUnixSalData()->ErrorTrapPush();
101     for (auto const& elem : aPresentationReparentList)
102     {
103         int x, y;
104         ::Window aRoot, aChild;
105         unsigned int w, h, bw, d;
106         XGetGeometry( pDisplay->GetDisplay(),
107                       elem,
108                       &aRoot,
109                       &x, &y, &w, &h, &bw, &d );
110         XTranslateCoordinates( pDisplay->GetDisplay(),
111                                hPresentationWindow,
112                                aRoot,
113                                x, y,
114                                &x, &y,
115                                &aChild );
116         XReparentWindow( pDisplay->GetDisplay(),
117                          elem,
118                          aRoot,
119                          x, y );
120     }
121     aPresentationReparentList.clear();
122     if( hPresFocusWindow )
123         XSetInputFocus( pDisplay->GetDisplay(), hPresFocusWindow, PointerRoot, CurrentTime );
124     XSync( pDisplay->GetDisplay(), False );
125     GetGenericUnixSalData()->ErrorTrapPop();
126 }
127 
IsOverrideRedirect() const128 bool X11SalFrame::IsOverrideRedirect() const
129 {
130     return
131         ((nStyle_ & SalFrameStyleFlags::INTRO) && !pDisplay_->getWMAdaptor()->supportsSplash())
132         ||
133         (!( nStyle_ & ~SalFrameStyleFlags::DEFAULT ) && !pDisplay_->getWMAdaptor()->supportsFullScreen())
134         ;
135 }
136 
IsFloatGrabWindow() const137 bool X11SalFrame::IsFloatGrabWindow() const
138 {
139     static const char* pDisableGrab = getenv( "SAL_DISABLE_FLOATGRAB" );
140 
141     return
142         ( ( !pDisableGrab || !*pDisableGrab ) &&
143           (
144            (nStyle_ & SalFrameStyleFlags::FLOAT)    &&
145            ! (nStyle_ & SalFrameStyleFlags::TOOLTIP)    &&
146            ! (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION)
147            )
148           );
149 }
150 
setXEmbedInfo()151 void X11SalFrame::setXEmbedInfo()
152 {
153     if( !m_bXEmbed )
154         return;
155 
156     tools::Long aInfo[2];
157     aInfo[0] = 1; // XEMBED protocol version
158     aInfo[1] = (bMapped_ ? 1 : 0); // XEMBED_MAPPED
159     XChangeProperty( pDisplay_->GetDisplay(),
160                      mhWindow,
161                      pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO ),
162                      pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO ),
163                      32,
164                      PropModeReplace,
165                      reinterpret_cast<unsigned char*>(aInfo),
166                      SAL_N_ELEMENTS(aInfo) );
167 }
168 
askForXEmbedFocus(sal_Int32 i_nTimeCode)169 void X11SalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
170 {
171     XEvent aEvent;
172 
173     memset( &aEvent, 0, sizeof(aEvent) );
174     aEvent.xclient.window = mhForeignParent;
175     aEvent.xclient.type = ClientMessage;
176     aEvent.xclient.message_type = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED );
177     aEvent.xclient.format = 32;
178     aEvent.xclient.data.l[0] = i_nTimeCode ? i_nTimeCode : CurrentTime;
179     aEvent.xclient.data.l[1] = 3; // XEMBED_REQUEST_FOCUS
180     aEvent.xclient.data.l[2] = 0;
181     aEvent.xclient.data.l[3] = 0;
182     aEvent.xclient.data.l[4] = 0;
183 
184     GetGenericUnixSalData()->ErrorTrapPush();
185     XSendEvent( pDisplay_->GetDisplay(),
186                 mhForeignParent,
187                 False, NoEventMask, &aEvent );
188     XSync( pDisplay_->GetDisplay(), False );
189     GetGenericUnixSalData()->ErrorTrapPop();
190 }
191 
192 typedef std::vector< unsigned long > NetWmIconData;
193 
194 namespace
195 {
196     constexpr OUString SV_ICON_SIZE48[] =
197     {
198         MAINAPP_48_8,
199         MAINAPP_48_8,
200         ODT_48_8,
201         OTT_48_8,
202         ODS_48_8,
203         OTS_48_8,
204         ODG_48_8,
205         MAINAPP_48_8,
206         ODP_48_8,
207         MAINAPP_48_8,
208         ODM_48_8,
209         MAINAPP_48_8,
210         ODB_48_8,
211         ODF_48_8
212     };
213 
214     constexpr OUString SV_ICON_SIZE32[] =
215     {
216         MAINAPP_32_8,
217         MAINAPP_32_8,
218         ODT_32_8,
219         OTT_32_8,
220         ODS_32_8,
221         OTS_32_8,
222         ODG_32_8,
223         MAINAPP_32_8,
224         ODP_32_8,
225         MAINAPP_32_8,
226         ODM_32_8,
227         MAINAPP_32_8,
228         ODB_32_8,
229         ODF_32_8
230     };
231 
232     constexpr OUString SV_ICON_SIZE16[] =
233     {
234         MAINAPP_16_8,
235         MAINAPP_16_8,
236         ODT_16_8,
237         OTT_16_8,
238         ODS_16_8,
239         OTS_16_8,
240         ODG_16_8,
241         MAINAPP_16_8,
242         ODP_16_8,
243         MAINAPP_16_8,
244         ODM_16_8,
245         MAINAPP_16_8,
246         ODB_16_8,
247         ODF_16_8
248     };
249 }
250 
CreateNetWmAppIcon(sal_uInt16 nIcon,NetWmIconData & netwm_icon)251 static void CreateNetWmAppIcon( sal_uInt16 nIcon, NetWmIconData& netwm_icon )
252 {
253     const int sizes[ 3 ] = { 48, 32, 16 };
254     netwm_icon.resize( 48 * 48 + 32 * 32 + 16 * 16 + 3 * 2 );
255     int pos = 0;
256     for(int size : sizes)
257     {
258         OUString sIcon;
259         if( size >= 48 )
260             sIcon = SV_ICON_SIZE48[nIcon];
261         else if( size >= 32 )
262             sIcon = SV_ICON_SIZE32[nIcon];
263         else
264             sIcon = SV_ICON_SIZE16[nIcon];
265 
266         BitmapEx aIcon = vcl::bitmap::loadFromName(sIcon, ImageLoadFlags::IgnoreScalingFactor);
267 
268         if( aIcon.IsEmpty())
269             continue;
270         vcl::bitmap::convertBitmap32To24Plus8(aIcon, aIcon);
271         Bitmap icon = aIcon.GetBitmap();
272         AlphaMask mask = aIcon.GetAlphaMask();
273         BitmapScopedReadAccess iconData(icon);
274         BitmapScopedReadAccess maskData(mask);
275         netwm_icon[ pos++ ] = size; // width
276         netwm_icon[ pos++ ] = size; // height
277         for( int y = 0; y < size; ++y )
278             for( int x = 0; x < size; ++x )
279             {
280                 BitmapColor col = iconData->GetColor( y, x );
281                 BitmapColor alpha = maskData->GetColor( y, x );
282                 netwm_icon[ pos++ ] = (((( 255 - alpha.GetBlue()) * 256U ) + col.GetRed()) * 256 + col.GetGreen()) * 256 + col.GetBlue();
283             }
284     }
285     netwm_icon.resize( pos );
286 }
287 
Init(SalFrameStyleFlags nSalFrameStyle,SalX11Screen nXScreen,SystemParentData const * pParentData,bool bUseGeometry)288 void X11SalFrame::Init( SalFrameStyleFlags nSalFrameStyle, SalX11Screen nXScreen, SystemParentData const * pParentData, bool bUseGeometry )
289 {
290     if( nXScreen.getXScreen() >= GetDisplay()->GetXScreenCount() )
291         nXScreen = GetDisplay()->GetDefaultXScreen();
292     if( mpParent )
293         nXScreen = mpParent->m_nXScreen;
294 
295     m_nXScreen  = nXScreen;
296     nStyle_     = nSalFrameStyle;
297     XWMHints Hints;
298     Hints.flags = InputHint;
299     Hints.input = (nSalFrameStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) ? False : True;
300     NetWmIconData netwm_icon;
301 
302     int x = 0, y = 0;
303     unsigned int w = 500, h = 500;
304     XSetWindowAttributes Attributes;
305 
306     int nAttrMask =   CWBorderPixel
307                     | CWBackPixmap
308                     | CWColormap
309                     | CWOverrideRedirect
310                     | CWEventMask
311                     ;
312     Attributes.border_pixel             = 0;
313     Attributes.background_pixmap        = None;
314     Attributes.colormap                 = GetDisplay()->GetColormap( m_nXScreen ).GetXColormap();
315     Attributes.override_redirect        = False;
316     Attributes.event_mask               = CLIENT_EVENTS;
317 
318     const SalVisual& rVis = GetDisplay()->GetVisual( m_nXScreen );
319     ::Window aFrameParent = pParentData ? pParentData->aWindow : GetDisplay()->GetRootWindow( m_nXScreen );
320     ::Window aClientLeader = None;
321 
322     if( bUseGeometry )
323     {
324         x = maGeometry.x();
325         y = maGeometry.y();
326         w = maGeometry.width();
327         h = maGeometry.height();
328     }
329 
330     if( (nSalFrameStyle & SalFrameStyleFlags::FLOAT) &&
331         ! (nSalFrameStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)
332         )
333     {
334         if( nShowState_ == X11ShowState::Unknown )
335         {
336             w = 10;
337             h = 10;
338         }
339         Attributes.override_redirect = True;
340     }
341     else if( nSalFrameStyle & SalFrameStyleFlags::SYSTEMCHILD )
342     {
343         SAL_WARN_IF( !mpParent, "vcl", "SalFrameStyleFlags::SYSTEMCHILD window without parent" );
344         if( mpParent )
345         {
346             aFrameParent = mpParent->mhWindow;
347             // FIXME: since with SalFrameStyleFlags::SYSTEMCHILD
348             // multiple X11SalFrame objects can have the same shell window
349             // dispatching events in saldisp.cxx is unclear (the first frame)
350             // wins. HTH this correctly is unclear yet
351             // for the time being, treat set the shell window to own window
352             // like for a normal frame
353             // mhShellWindow = mpParent->GetShellWindow();
354         }
355     }
356     else if( pParentData )
357     {
358         // plugin parent may be killed unexpectedly by plugging
359         // process; start permanently ignoring X errors...
360         GetGenericUnixSalData()->ErrorTrapPush();
361 
362         nStyle_ |= SalFrameStyleFlags::PLUG;
363         Attributes.override_redirect = True;
364         if( pParentData->nSize >= sizeof(SystemParentData) )
365             m_bXEmbed = pParentData->bXEmbedSupport;
366 
367         int x_ret, y_ret;
368         unsigned int bw, d;
369         ::Window aRoot, aParent;
370 
371         XGetGeometry( GetXDisplay(), pParentData->aWindow,
372                       &aRoot, &x_ret, &y_ret, &w, &h, &bw, &d );
373         mhForeignParent = pParentData->aWindow;
374 
375         mhShellWindow = aParent = mhForeignParent;
376         ::Window* pChildren;
377         unsigned int nChildren;
378         bool bBreak = false;
379         do
380         {
381             XQueryTree( GetDisplay()->GetDisplay(), mhShellWindow,
382                         &aRoot, &aParent, &pChildren, &nChildren );
383             XFree( pChildren );
384             if( aParent != aRoot )
385                 mhShellWindow = aParent;
386             int nCount = 0;
387             Atom* pProps = XListProperties( GetDisplay()->GetDisplay(),
388                                             mhShellWindow,
389                                             &nCount );
390             for( int i = 0; i < nCount && ! bBreak; ++i )
391                 bBreak = (pProps[i] == XA_WM_HINTS);
392             if( pProps )
393                 XFree( pProps );
394         } while( aParent != aRoot && ! bBreak );
395 
396         // check if this is really one of our own frames
397         // do not change the input mask in that case
398         bool bIsReallyOurFrame = false;
399         for (auto pSalFrame : GetDisplay()->getFrames() )
400             if ( static_cast<const X11SalFrame*>( pSalFrame )->GetWindow() == mhForeignParent )
401             {
402                 bIsReallyOurFrame = true;
403                 break;
404             }
405         if (!bIsReallyOurFrame)
406         {
407             XSelectInput( GetDisplay()->GetDisplay(), mhForeignParent, StructureNotifyMask | FocusChangeMask );
408             XSelectInput( GetDisplay()->GetDisplay(), mhShellWindow, StructureNotifyMask | FocusChangeMask );
409         }
410     }
411     else
412     {
413         if( ! bUseGeometry )
414         {
415             Size aScreenSize( GetDisplay()->getDataForScreen( m_nXScreen ).m_aSize );
416             w = aScreenSize.Width();
417             h = aScreenSize.Height();
418             if( nSalFrameStyle & SalFrameStyleFlags::SIZEABLE &&
419                 nSalFrameStyle & SalFrameStyleFlags::MOVEABLE )
420             {
421                 Size aBestFitSize(bestmaxFrameSizeForScreenSize(aScreenSize));
422                 w = aBestFitSize.Width();
423                 h = aBestFitSize.Height();
424             }
425             if( ! mpParent )
426             {
427                 // find the last document window (if any)
428                 const X11SalFrame* pFrame = nullptr;
429                 bool bIsDocumentWindow = false;
430                 for (auto pSalFrame : GetDisplay()->getFrames() )
431                 {
432                     pFrame = static_cast< const X11SalFrame* >( pSalFrame );
433                     if( !pFrame->mpParent
434                         && !pFrame->mbFullScreen
435                         && ( pFrame->nStyle_ & SalFrameStyleFlags::SIZEABLE )
436                         && pFrame->GetUnmirroredGeometry().width()
437                         && pFrame->GetUnmirroredGeometry().height() )
438                     {
439                         bIsDocumentWindow = true;
440                         break;
441                     }
442                 }
443 
444                 if( bIsDocumentWindow )
445                 {
446                     // set a document position and size
447                     // the first frame gets positioned by the window manager
448                     const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
449                     x = rGeom.x();
450                     y = rGeom.y();
451                     if( x+static_cast<int>(w)+40 <= static_cast<int>(aScreenSize.Width()) &&
452                         y+static_cast<int>(h)+40 <= static_cast<int>(aScreenSize.Height())
453                         )
454                     {
455                         y += 40;
456                         x += 40;
457                     }
458                     else
459                     {
460                         x = 10; // leave some space for decoration
461                         y = 20;
462                     }
463                 }
464                 else if( GetDisplay()->IsXinerama() )
465                 {
466                     // place frame on same screen as mouse pointer
467                     ::Window aRoot, aChild;
468                     int root_x = 0, root_y = 0, lx, ly;
469                     unsigned int mask;
470                     XQueryPointer( GetXDisplay(),
471                                    GetDisplay()->GetRootWindow( m_nXScreen ),
472                                    &aRoot, &aChild,
473                                    &root_x, &root_y, &lx, &ly, &mask );
474                     const std::vector< AbsoluteScreenPixelRectangle >& rScreens = GetDisplay()->GetXineramaScreens();
475                     for(const auto & rScreen : rScreens)
476                         if( rScreen.Contains( AbsoluteScreenPixelPoint( root_x, root_y ) ) )
477                         {
478                             x = rScreen.Left();
479                             y = rScreen.Top();
480                             break;
481                         }
482                 }
483             }
484         }
485         Attributes.win_gravity = pDisplay_->getWMAdaptor()->getInitWinGravity();
486         nAttrMask |= CWWinGravity;
487         if( mpParent )
488         {
489             Attributes.save_under = True;
490             nAttrMask |= CWSaveUnder;
491         }
492         if( IsOverrideRedirect() )
493             Attributes.override_redirect = True;
494         // default icon
495         if( !(nStyle_ & SalFrameStyleFlags::INTRO) && !(nStyle_ & SalFrameStyleFlags::NOICON))
496         {
497             try
498             {
499                 CreateNetWmAppIcon( mnIconID != SV_ICON_ID_OFFICE ? mnIconID :
500                                     (mpParent ? mpParent->mnIconID : SV_ICON_ID_OFFICE), netwm_icon );
501             }
502             catch( css::uno::Exception& )
503             {
504                 // can happen - no ucb during early startup
505             }
506         }
507 
508         // find the top level frame of the transience hierarchy
509         X11SalFrame* pFrame = this;
510         while( pFrame->mpParent )
511             pFrame = pFrame->mpParent;
512         if( pFrame->nStyle_ & SalFrameStyleFlags::PLUG )
513         {
514             // if the top level window is a plugin window,
515             // then we should place us in the same window group as
516             // the parent application (or none if there is no window group
517             // hint in the parent).
518             if( pFrame->GetShellWindow() )
519             {
520                 XWMHints* pWMHints = XGetWMHints( pDisplay_->GetDisplay(),
521                     pFrame->GetShellWindow() );
522                 if( pWMHints )
523                 {
524                     if( pWMHints->flags & WindowGroupHint )
525                     {
526                         Hints.flags |= WindowGroupHint;
527                         Hints.window_group = pWMHints->window_group;
528                     }
529                     XFree( pWMHints );
530                 }
531             }
532         }
533         else
534         {
535             Hints.flags         |= WindowGroupHint;
536             Hints.window_group  = pFrame->GetShellWindow();
537             // note: for a normal document window this will produce None
538             // as the window is not yet created and the shell window is
539             // initialized to None. This must be corrected after window creation.
540             aClientLeader = GetDisplay()->GetDrawable( m_nXScreen );
541         }
542     }
543 
544     nShowState_                 = X11ShowState::Unknown;
545     bViewable_                  = true;
546     bMapped_                    = false;
547     nVisibility_                = VisibilityFullyObscured;
548     mhWindow = XCreateWindow( GetXDisplay(),
549                               aFrameParent,
550                               x, y,
551                               w, h,
552                               0,
553                               rVis.GetDepth(),
554                               InputOutput,
555                               rVis.GetVisual(),
556                               nAttrMask,
557                               &Attributes );
558     mpSurface = cairo_xlib_surface_create(GetXDisplay(), mhWindow,
559                                           rVis.GetVisual(),
560                                           w, h);
561 
562     // FIXME: see above: fake shell window for now to own window
563     if( pParentData == nullptr )
564     {
565         mhShellWindow = mhWindow;
566     }
567 
568     // correct window group if necessary
569     if( (Hints.flags & WindowGroupHint) == WindowGroupHint )
570     {
571         if( Hints.window_group == None )
572             Hints.window_group = GetShellWindow();
573     }
574 
575     maGeometry.setPosSize({ x, y }, { static_cast<tools::Long>(w), static_cast<tools::Long>(h) });
576     updateScreenNumber();
577 
578     XSync( GetXDisplay(), False );
579     setXEmbedInfo();
580 
581     Time nUserTime = (nStyle_ & (SalFrameStyleFlags::OWNERDRAWDECORATION | SalFrameStyleFlags::TOOLWINDOW) ) == SalFrameStyleFlags::NONE ?
582         pDisplay_->GetLastUserEventTime() : 0;
583     pDisplay_->getWMAdaptor()->setUserTime( this, nUserTime );
584 
585     if( ! pParentData && ! IsChildWindow() && ! Attributes.override_redirect )
586     {
587         XSetWMHints( GetXDisplay(), mhWindow, &Hints );
588         // WM Protocols && internals
589         Atom a[3];
590         int  n = 0;
591         a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_DELETE_WINDOW );
592 
593 // LibreOffice advertises NET_WM_PING atom, so mutter rightfully warns of an unresponsive application during debugging.
594 // Hack that out unconditionally for debug builds, as per https://bugzilla.redhat.com/show_bug.cgi?id=981149
595 // upstream refuses to make this configurable in any way.
596 // NOTE: You need to use the 'gen' backend for this to work (SAL_USE_VCLPLUGIN=gen)
597 #if OSL_DEBUG_LEVEL < 1
598         if( pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING ) )
599             a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING );
600 #endif
601 
602         if( nSalFrameStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
603             a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_TAKE_FOCUS );
604         XSetWMProtocols( GetXDisplay(), GetShellWindow(), a, n );
605 
606         // force wm class hint
607         mnExtStyle = ~0;
608         if (mpParent)
609             m_sWMClass = mpParent->m_sWMClass;
610         SetExtendedFrameStyle( 0 );
611 
612         XSizeHints* pHints = XAllocSizeHints();
613         pHints->flags       = PWinGravity | PPosition;
614         pHints->win_gravity = GetDisplay()->getWMAdaptor()->getPositionWinGravity();
615         pHints->x           = 0;
616         pHints->y           = 0;
617         if( mbFullScreen )
618         {
619             pHints->flags |= PMaxSize | PMinSize;
620             pHints->max_width = w+100;
621             pHints->max_height = h+100;
622             pHints->min_width  = w;
623             pHints->min_height = h;
624         }
625         XSetWMNormalHints( GetXDisplay(),
626                            GetShellWindow(),
627                            pHints );
628         XFree (pHints);
629 
630         // set PID and WM_CLIENT_MACHINE
631         pDisplay_->getWMAdaptor()->setClientMachine( this );
632         pDisplay_->getWMAdaptor()->setPID( this );
633 
634         // set client leader
635         if( aClientLeader )
636         {
637             XChangeProperty( GetXDisplay(),
638                              mhWindow,
639                              pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_CLIENT_LEADER),
640                              XA_WINDOW,
641                              32,
642                              PropModeReplace,
643                              reinterpret_cast<unsigned char*>(&aClientLeader),
644                              1
645                              );
646         }
647 #define DECOFLAGS (SalFrameStyleFlags::MOVEABLE | SalFrameStyleFlags::SIZEABLE | SalFrameStyleFlags::CLOSEABLE)
648         int nDecoFlags = WMAdaptor::decoration_All;
649         if (m_bIsPartialFullScreen || (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION))
650             nDecoFlags = 0;
651         else if( (nStyle_ & DECOFLAGS ) != DECOFLAGS || (nStyle_ & SalFrameStyleFlags::TOOLWINDOW) )
652         {
653             if( nStyle_ & DECOFLAGS )
654                 // if any decoration, then show a border
655                 nDecoFlags = WMAdaptor::decoration_Border;
656             else
657                 nDecoFlags = 0;
658 
659             if( ! mpParent && (nStyle_ & DECOFLAGS) )
660                 // don't add a min button if window should be decorationless
661                 nDecoFlags |= WMAdaptor::decoration_MinimizeBtn;
662             if( nStyle_ & SalFrameStyleFlags::CLOSEABLE )
663                 nDecoFlags |= WMAdaptor::decoration_CloseBtn;
664             if( nStyle_ & SalFrameStyleFlags::SIZEABLE )
665             {
666                 nDecoFlags |= WMAdaptor::decoration_Resize;
667                 if( ! (nStyle_ & SalFrameStyleFlags::TOOLWINDOW) )
668                     nDecoFlags |= WMAdaptor::decoration_MaximizeBtn;
669             }
670             if( nStyle_ & SalFrameStyleFlags::MOVEABLE )
671                 nDecoFlags |= WMAdaptor::decoration_Title;
672         }
673 
674         WMWindowType eType = WMWindowType::Normal;
675         if( nStyle_ & SalFrameStyleFlags::INTRO )
676             eType = WMWindowType::Splash;
677         if( (nStyle_ & SalFrameStyleFlags::DIALOG) && hPresentationWindow == None )
678             eType = WMWindowType::ModelessDialogue;
679         if( nStyle_ & SalFrameStyleFlags::TOOLWINDOW )
680             eType = WMWindowType::Utility;
681         if( nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION )
682             eType = WMWindowType::Toolbar;
683         if (m_bIsPartialFullScreen && GetDisplay()->getWMAdaptor()->isLegacyPartialFullscreen())
684             eType = WMWindowType::Dock;
685 
686         GetDisplay()->getWMAdaptor()->
687             setFrameTypeAndDecoration( this,
688                                        eType,
689                                        nDecoFlags,
690                                        hPresentationWindow ? nullptr : mpParent );
691 
692         if (!m_bIsPartialFullScreen && (nStyle_ & (SalFrameStyleFlags::DEFAULT |
693                         SalFrameStyleFlags::OWNERDRAWDECORATION|
694                         SalFrameStyleFlags::FLOAT |
695                         SalFrameStyleFlags::INTRO))
696              == SalFrameStyleFlags::DEFAULT )
697             pDisplay_->getWMAdaptor()->maximizeFrame( this );
698 
699         if( !netwm_icon.empty() && GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_ICON ))
700             XChangeProperty( GetXDisplay(), mhWindow,
701                 GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_ICON ),
702                 XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<unsigned char*>(netwm_icon.data()), netwm_icon.size());
703     }
704 
705     m_nWorkArea = GetDisplay()->getWMAdaptor()->getCurrentWorkArea();
706 
707     // Pointer
708     SetPointer( PointerStyle::Arrow );
709 }
710 
X11SalFrame(SalFrame * pParent,SalFrameStyleFlags nSalFrameStyle,SystemParentData const * pSystemParent)711 X11SalFrame::X11SalFrame( SalFrame *pParent, SalFrameStyleFlags nSalFrameStyle,
712                           SystemParentData const * pSystemParent ) :
713     m_nXScreen( 0 ),
714     maAlwaysOnTopRaiseTimer( "vcl::X11SalFrame maAlwaysOnTopRaiseTimer" )
715 {
716     GenericUnixSalData *pData = GetGenericUnixSalData();
717 
718     mpParent                    = static_cast< X11SalFrame* >( pParent );
719 
720     mbTransientForRoot          = false;
721 
722     pDisplay_                   = vcl_sal::getSalDisplay(pData);
723     // insert frame in framelist
724     pDisplay_->registerFrame( this );
725 
726     mhWindow                    = None;
727     mpSurface                   = nullptr;
728     mhShellWindow               = None;
729     mhStackingWindow            = None;
730     mhForeignParent             = None;
731     m_bSetFocusOnMap            = false;
732 
733     pGraphics_                  = nullptr;
734     pFreeGraphics_              = nullptr;
735 
736     hCursor_                    = None;
737     nCaptured_                  = 0;
738 
739     mbSendExtKeyModChange       = false;
740     mnExtKeyMod                 = ModKeyFlags::NONE;
741 
742     nShowState_                 = X11ShowState::Unknown;
743     nWidth_                     = 0;
744     nHeight_                    = 0;
745     nStyle_                     = SalFrameStyleFlags::NONE;
746     mnExtStyle                  = 0;
747     bAlwaysOnTop_               = false;
748 
749     // set bViewable_ to true: hack GetClientSize to report something
750     // different to 0/0 before first map
751     bViewable_                  = true;
752     bMapped_                    = false;
753     bDefaultPosition_           = true;
754     nVisibility_                = VisibilityFullyObscured;
755     m_nWorkArea                 = 0;
756     m_bXEmbed                   = false;
757 
758 
759     mpInputContext              = nullptr;
760     mbInputFocus                = False;
761 
762     maAlwaysOnTopRaiseTimer.SetInvokeHandler( LINK( this, X11SalFrame, HandleAlwaysOnTopRaise ) );
763     maAlwaysOnTopRaiseTimer.SetTimeout( 100 );
764 
765     meWindowType                = WMWindowType::Normal;
766     mbMaximizedVert             = false;
767     mbMaximizedHorz             = false;
768     mbFullScreen                = false;
769     m_bIsPartialFullScreen = false;
770 
771     mnIconID                    = SV_ICON_ID_OFFICE;
772 
773     if( mpParent )
774         mpParent->maChildren.push_back( this );
775 
776     Init( nSalFrameStyle, GetDisplay()->GetDefaultXScreen(), pSystemParent );
777 }
778 
~X11SalFrame()779 X11SalFrame::~X11SalFrame()
780 {
781     notifyDelete();
782 
783     m_vClipRectangles.clear();
784 
785     if( mhStackingWindow )
786         aPresentationReparentList.remove( mhStackingWindow );
787 
788     // remove from parent's list
789     if( mpParent )
790         mpParent->maChildren.remove( this );
791 
792     // deregister on SalDisplay
793     pDisplay_->deregisterFrame( this );
794 
795     // unselect all events, some may be still in the queue anyway
796     if( ! IsSysChildWindow() )
797         XSelectInput( GetXDisplay(), GetShellWindow(), 0 );
798     XSelectInput( GetXDisplay(), GetWindow(), 0 );
799 
800     ShowFullScreen( false, 0 );
801 
802     if( bMapped_ )
803         Show( false );
804 
805     if( mpInputContext )
806     {
807         mpInputContext->UnsetICFocus();
808         mpInputContext->Unmap();
809         mpInputContext.reset();
810     }
811 
812     if( GetWindow() == hPresentationWindow )
813     {
814         hPresentationWindow = None;
815         doReparentPresentationDialogues( GetDisplay() );
816     }
817 
818     if( pGraphics_ )
819     {
820         pGraphics_->DeInit();
821         pGraphics_.reset();
822     }
823 
824     if( pFreeGraphics_ )
825     {
826         pFreeGraphics_->DeInit();
827         pFreeGraphics_.reset();
828     }
829 
830     // reset all OpenGL contexts using this window
831     rtl::Reference<OpenGLContext> pContext = ImplGetSVData()->maGDIData.mpLastContext;
832     while( pContext.is() )
833     {
834         if (static_cast<const GLX11Window&>(pContext->getOpenGLWindow()).win == mhWindow)
835             pContext->reset();
836         pContext = pContext->mpPrevContext;
837     }
838 
839     if (mpSurface)
840         cairo_surface_destroy(mpSurface);
841 
842     XDestroyWindow( GetXDisplay(), mhWindow );
843 }
844 
SetExtendedFrameStyle(SalExtStyle nStyle)845 void X11SalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
846 {
847     if( nStyle != mnExtStyle && ! IsChildWindow() )
848     {
849         mnExtStyle = nStyle;
850         updateWMClass();
851     }
852 }
853 
GetSystemData() const854 const SystemEnvData* X11SalFrame::GetSystemData() const
855 {
856     X11SalFrame *pFrame = const_cast<X11SalFrame*>(this);
857     pFrame->maSystemChildData.pDisplay      = GetXDisplay();
858     pFrame->maSystemChildData.SetWindowHandle(pFrame->GetWindow());
859     pFrame->maSystemChildData.pSalFrame     = pFrame;
860     pFrame->maSystemChildData.pWidget       = nullptr;
861     pFrame->maSystemChildData.pVisual       = GetDisplay()->GetVisual( m_nXScreen ).GetVisual();
862     pFrame->maSystemChildData.nScreen       = m_nXScreen.getXScreen();
863     pFrame->maSystemChildData.aShellWindow  = pFrame->GetShellWindow();
864     pFrame->maSystemChildData.toolkit       = SystemEnvData::Toolkit::Gen;
865     pFrame->maSystemChildData.platform      = SystemEnvData::Platform::Xcb;
866     return &maSystemChildData;
867 }
868 
AcquireGraphics()869 SalGraphics *X11SalFrame::AcquireGraphics()
870 {
871     if( pGraphics_ )
872         return nullptr;
873 
874     if( pFreeGraphics_ )
875     {
876         pGraphics_      = std::move(pFreeGraphics_);
877     }
878     else
879     {
880         pGraphics_.reset(new X11SalGraphics());
881         pGraphics_->Init(*this, GetWindow(), m_nXScreen);
882     }
883 
884     return pGraphics_.get();
885 }
886 
ReleaseGraphics(SalGraphics * pGraphics)887 void X11SalFrame::ReleaseGraphics( SalGraphics *pGraphics )
888 {
889     SAL_WARN_IF( pGraphics != pGraphics_.get(), "vcl", "SalFrame::ReleaseGraphics pGraphics!=pGraphics_" );
890 
891     if( pGraphics != pGraphics_.get() )
892         return;
893 
894     pFreeGraphics_  = std::move(pGraphics_);
895 }
896 
updateGraphics(bool bClear)897 void X11SalFrame::updateGraphics( bool bClear )
898 {
899     Drawable aDrawable = bClear ? None : GetWindow();
900     if( pGraphics_ )
901         pGraphics_->SetDrawable( aDrawable, mpSurface, m_nXScreen );
902     if( pFreeGraphics_ )
903         pFreeGraphics_->SetDrawable( aDrawable, mpSurface, m_nXScreen );
904 }
905 
SetIcon(sal_uInt16 nIcon)906 void X11SalFrame::SetIcon( sal_uInt16 nIcon )
907 {
908     if (  IsChildWindow() )
909         return;
910 
911     // 0 == default icon -> #1
912     if ( nIcon == 0 )
913         nIcon = 1;
914 
915     mnIconID = nIcon;
916 
917     NetWmIconData netwm_icon;
918     CreateNetWmAppIcon( nIcon, netwm_icon );
919 
920     if( !netwm_icon.empty() && GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_ICON ))
921         XChangeProperty( GetXDisplay(), mhWindow,
922             GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_ICON ),
923             XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<unsigned char*>(netwm_icon.data()), netwm_icon.size());
924 }
925 
SetMaxClientSize(tools::Long nWidth,tools::Long nHeight)926 void X11SalFrame::SetMaxClientSize( tools::Long nWidth, tools::Long nHeight )
927 {
928     if(  IsChildWindow() )
929         return;
930 
931     if( !GetShellWindow() ||
932         (nStyle_ & (SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::OWNERDRAWDECORATION) ) == SalFrameStyleFlags::FLOAT )
933         return;
934 
935     XSizeHints* pHints = XAllocSizeHints();
936     tools::Long nSupplied = 0;
937     XGetWMNormalHints( GetXDisplay(),
938                        GetShellWindow(),
939                        pHints,
940                        &nSupplied
941                        );
942     pHints->max_width   = nWidth;
943     pHints->max_height  = nHeight;
944     pHints->flags |= PMaxSize;
945     XSetWMNormalHints( GetXDisplay(),
946                        GetShellWindow(),
947                        pHints );
948     XFree( pHints );
949 }
950 
SetMinClientSize(tools::Long nWidth,tools::Long nHeight)951 void X11SalFrame::SetMinClientSize( tools::Long nWidth, tools::Long nHeight )
952 {
953     if(  IsChildWindow() )
954         return;
955 
956     if( !GetShellWindow() ||
957         (nStyle_ & (SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::OWNERDRAWDECORATION) ) == SalFrameStyleFlags::FLOAT )
958         return;
959 
960     XSizeHints* pHints = XAllocSizeHints();
961     tools::Long nSupplied = 0;
962     XGetWMNormalHints( GetXDisplay(),
963                        GetShellWindow(),
964                        pHints,
965                        &nSupplied
966                        );
967     pHints->min_width   = nWidth;
968     pHints->min_height  = nHeight;
969     pHints->flags |= PMinSize;
970     XSetWMNormalHints( GetXDisplay(),
971                        GetShellWindow(),
972                        pHints );
973     XFree( pHints );
974 }
975 
976 // Show + Pos (x,y,z) + Size (width,height)
977 
Show(bool bVisible,bool bNoActivate)978 void X11SalFrame::Show( bool bVisible, bool bNoActivate )
979 {
980     if( ( bVisible && bMapped_ )
981         || ( !bVisible && !bMapped_ ) )
982         return;
983 
984     // HACK: this is a workaround for (at least) kwin
985     // even though transient frames should be kept above their parent
986     // this does not necessarily hold true for DOCK type windows
987     // so artificially set ABOVE and remove it again on hide
988     if( mpParent && mpParent->m_bIsPartialFullScreen && pDisplay_->getWMAdaptor()->isLegacyPartialFullscreen())
989         pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bVisible );
990 
991     bMapped_   = bVisible;
992     bViewable_ = bVisible;
993     setXEmbedInfo();
994     if( bVisible )
995     {
996         if( ! (nStyle_ & SalFrameStyleFlags::INTRO) )
997         {
998             // hide all INTRO frames
999             for (auto pSalFrame : GetDisplay()->getFrames() )
1000             {
1001                 const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame );
1002                 // look for intro bit map; if present, hide it
1003                 if( pFrame->nStyle_ & SalFrameStyleFlags::INTRO )
1004                 {
1005                     if( pFrame->bMapped_ )
1006                         const_cast<X11SalFrame*>(pFrame)->Show( false );
1007                 }
1008             }
1009         }
1010 
1011         // update NET_WM_STATE which may have been deleted due to earlier Show(false)
1012         if( nShowState_ == X11ShowState::Hidden )
1013             GetDisplay()->getWMAdaptor()->frameIsMapping( this );
1014 
1015         /*
1016          *  Actually this is rather exotic and currently happens only in conjunction
1017          *  with the basic dialogue editor,
1018          *  which shows a frame and instantly hides it again. After that the
1019          *  editor window is shown and the WM takes this as an opportunity
1020          *  to show our hidden transient frame also. So Show( false ) must
1021          *  withdraw the frame AND delete the WM_TRANSIENT_FOR property.
1022          *  In case the frame is shown again, the transient hint must be restored here.
1023          */
1024         if(    ! IsChildWindow()
1025             && ! IsOverrideRedirect()
1026             && ! IsFloatGrabWindow()
1027             && mpParent
1028             )
1029         {
1030             GetDisplay()->getWMAdaptor()->changeReferenceFrame( this, mpParent );
1031         }
1032 
1033         // #i45160# switch to desktop where a dialog with parent will appear
1034         if( mpParent && mpParent->m_nWorkArea != m_nWorkArea )
1035             GetDisplay()->getWMAdaptor()->switchToWorkArea( mpParent->m_nWorkArea );
1036 
1037         if( IsFloatGrabWindow() &&
1038             mpParent &&
1039             nVisibleFloats == 0 &&
1040             ! GetDisplay()->GetCaptureFrame() )
1041         {
1042             /* #i39420#
1043              * outsmart KWin's "focus strictly under mouse" mode
1044              * which insists on taking the focus from the document
1045              * to the new float. Grab focus to parent frame BEFORE
1046              * showing the float (cannot grab it to the float
1047              * before show).
1048              */
1049             XGrabPointer( GetXDisplay(),
1050                           mpParent->GetWindow(),
1051                           True,
1052                           PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1053                           GrabModeAsync,
1054                           GrabModeAsync,
1055                           None,
1056                           mpParent ? mpParent->GetCursor() : None,
1057                           CurrentTime
1058                           );
1059         }
1060 
1061         Time nUserTime = 0;
1062         if( ! bNoActivate && !(nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION) )
1063             nUserTime = pDisplay_->GetX11ServerTime();
1064         GetDisplay()->getWMAdaptor()->setUserTime( this, nUserTime );
1065         if( ! bNoActivate && (nStyle_ & SalFrameStyleFlags::TOOLWINDOW) )
1066             m_bSetFocusOnMap = true;
1067 
1068         // actually map the window
1069         if( m_bXEmbed )
1070             askForXEmbedFocus( 0 );
1071         else
1072         {
1073             if( GetWindow() != GetShellWindow() && ! IsSysChildWindow() )
1074             {
1075                 if( IsChildWindow() )
1076                     XMapWindow( GetXDisplay(), GetShellWindow() );
1077                 XSelectInput( GetXDisplay(), GetShellWindow(), CLIENT_EVENTS );
1078             }
1079             if( nStyle_ & SalFrameStyleFlags::FLOAT )
1080                 XMapRaised( GetXDisplay(), GetWindow() );
1081             else
1082                 XMapWindow( GetXDisplay(), GetWindow() );
1083         }
1084         XSelectInput( GetXDisplay(), GetWindow(), CLIENT_EVENTS );
1085 
1086         if( maGeometry.width() > 0
1087             && maGeometry.height() > 0
1088             && (   nWidth_  != static_cast<int>(maGeometry.width())
1089                 || nHeight_ != static_cast<int>(maGeometry.height()) ) )
1090         {
1091             nWidth_  = maGeometry.width();
1092             nHeight_ = maGeometry.height();
1093         }
1094 
1095         XSync( GetXDisplay(), False );
1096 
1097         if( IsFloatGrabWindow() )
1098         {
1099             /*
1100              *  Sawfish and twm can be switched to enter-exit focus behaviour. In this case
1101              *  we must grab the pointer else the dumb WM will put the focus to the
1102              *  override-redirect float window. The application window will be deactivated
1103              *  which causes that the floats are destroyed, so the user can never click on
1104              *  a menu because it vanishes as soon as he enters it.
1105              */
1106             nVisibleFloats++;
1107             if( nVisibleFloats == 1 && ! GetDisplay()->GetCaptureFrame() )
1108             {
1109                 /* #i39420# now move grab to the new float window */
1110                 XGrabPointer( GetXDisplay(),
1111                               GetWindow(),
1112                               True,
1113                               PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1114                               GrabModeAsync,
1115                               GrabModeAsync,
1116                               None,
1117                               mpParent ? mpParent->GetCursor() : None,
1118                               CurrentTime
1119                               );
1120             }
1121         }
1122         CallCallback( SalEvent::Resize, nullptr );
1123 
1124         /*
1125          *  sometimes a message box/dialogue is brought up when a frame is not mapped
1126          *  the corresponding TRANSIENT_FOR hint is then set to the root window
1127          *  so that the dialogue shows in all cases. Correct it here if the
1128          *  frame is shown afterwards.
1129          */
1130         if( ! IsChildWindow()
1131             && ! IsOverrideRedirect()
1132             && ! IsFloatGrabWindow()
1133             )
1134         {
1135             for (auto const& child : maChildren)
1136             {
1137                 if( child->mbTransientForRoot )
1138                     GetDisplay()->getWMAdaptor()->changeReferenceFrame( child, this );
1139             }
1140         }
1141         /*
1142          *  leave X11ShowState::Unknown as this indicates first mapping
1143          *  and is only reset int HandleSizeEvent
1144          */
1145         if( nShowState_ != X11ShowState::Unknown )
1146             nShowState_ = X11ShowState::Normal;
1147 
1148         /*
1149          *  plugged windows don't necessarily get the
1150          *  focus on show because the parent may already be mapped
1151          *  and have the focus. So try to set the focus
1152          *  to the child on Show(true)
1153          */
1154         if( (nStyle_ & SalFrameStyleFlags::PLUG) && ! m_bXEmbed )
1155             XSetInputFocus( GetXDisplay(),
1156                             GetWindow(),
1157                             RevertToParent,
1158                             CurrentTime );
1159 
1160         if( mpParent )
1161         {
1162             // push this frame so it will be in front of its siblings
1163             // only necessary for insane transient behaviour of Dtwm/olwm
1164             mpParent->maChildren.remove( this );
1165             mpParent->maChildren.push_front(this);
1166         }
1167     }
1168     else
1169     {
1170         if( getInputContext() )
1171             getInputContext()->Unmap();
1172 
1173         if( ! IsChildWindow() )
1174         {
1175             /*  FIXME: Is deleting the property really necessary ? It hurts
1176              *  owner drawn windows at least.
1177              */
1178             if( mpParent && ! (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION) )
1179                 XDeleteProperty( GetXDisplay(), GetShellWindow(), GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::WM_TRANSIENT_FOR ) );
1180             XWithdrawWindow( GetXDisplay(), GetShellWindow(), m_nXScreen.getXScreen() );
1181         }
1182         else if( ! m_bXEmbed )
1183             XUnmapWindow( GetXDisplay(), GetWindow() );
1184 
1185         nShowState_ = X11ShowState::Hidden;
1186         if( IsFloatGrabWindow() && nVisibleFloats )
1187         {
1188             nVisibleFloats--;
1189             if( nVisibleFloats == 0  && ! GetDisplay()->GetCaptureFrame() )
1190                 XUngrabPointer( GetXDisplay(),
1191                                 CurrentTime );
1192         }
1193         // flush here; there may be a very seldom race between
1194         // the display connection used for clipboard and our connection
1195         Flush();
1196     }
1197 }
1198 
ToTop(SalFrameToTop nFlags)1199 void X11SalFrame::ToTop( SalFrameToTop nFlags )
1200 {
1201     if( ( nFlags & SalFrameToTop::RestoreWhenMin )
1202         && ! ( nStyle_ & SalFrameStyleFlags::FLOAT )
1203         && nShowState_ != X11ShowState::Hidden
1204         && nShowState_ != X11ShowState::Unknown
1205         )
1206     {
1207         GetDisplay()->getWMAdaptor()->frameIsMapping( this );
1208         if( GetWindow() != GetShellWindow() && ! IsSysChildWindow() )
1209             XMapWindow( GetXDisplay(), GetShellWindow() );
1210         XMapWindow( GetXDisplay(), GetWindow() );
1211     }
1212 
1213     ::Window aToTopWindow = IsSysChildWindow() ? GetWindow() : GetShellWindow();
1214     if( ! (nFlags & SalFrameToTop::GrabFocusOnly) )
1215     {
1216         XRaiseWindow( GetXDisplay(), aToTopWindow );
1217     }
1218 
1219     if( ( ( nFlags & SalFrameToTop::GrabFocus ) || ( nFlags & SalFrameToTop::GrabFocusOnly ) )
1220         && bMapped_ )
1221     {
1222         if( m_bXEmbed )
1223             askForXEmbedFocus( 0 );
1224         else
1225             XSetInputFocus( GetXDisplay(), aToTopWindow, RevertToParent, CurrentTime );
1226     }
1227     else if( ( nFlags & SalFrameToTop::RestoreWhenMin ) || ( nFlags & SalFrameToTop::ForegroundTask ) )
1228     {
1229             Time nTimestamp = pDisplay_->GetX11ServerTime();
1230             GetDisplay()->getWMAdaptor()->activateWindow( this, nTimestamp );
1231     }
1232 }
1233 
GetWorkArea(AbsoluteScreenPixelRectangle & rWorkArea)1234 void X11SalFrame::GetWorkArea( AbsoluteScreenPixelRectangle& rWorkArea )
1235 {
1236     rWorkArea = pDisplay_->getWMAdaptor()->getWorkArea( 0 );
1237 }
1238 
GetClientSize(tools::Long & rWidth,tools::Long & rHeight)1239 void X11SalFrame::GetClientSize( tools::Long &rWidth, tools::Long &rHeight )
1240 {
1241     if( ! bViewable_  )
1242     {
1243         rWidth = rHeight = 0;
1244         return;
1245     }
1246 
1247     rWidth  = maGeometry.width();
1248     rHeight = maGeometry.height();
1249 
1250     if( !rWidth || !rHeight )
1251     {
1252         XWindowAttributes aAttrib;
1253 
1254         XGetWindowAttributes( GetXDisplay(), GetWindow(), &aAttrib );
1255 
1256         rWidth = aAttrib.width;
1257         rHeight = aAttrib.height;
1258         maGeometry.setSize({ aAttrib.width, aAttrib.height });
1259     }
1260 }
1261 
Center()1262 void X11SalFrame::Center( )
1263 {
1264     int             nX, nY;
1265     AbsoluteScreenPixelSize aRealScreenSize(GetDisplay()->getDataForScreen(m_nXScreen).m_aSize);
1266     AbsoluteScreenPixelRectangle aScreen({ 0, 0 }, aRealScreenSize);
1267 
1268     if( GetDisplay()->IsXinerama() )
1269     {
1270         // get xinerama screen we are on
1271         // if there is a parent, use its center for screen determination
1272         // else use the pointer
1273         ::Window aRoot, aChild;
1274         int root_x, root_y, x, y;
1275         unsigned int mask;
1276         if( mpParent )
1277         {
1278             root_x = mpParent->maGeometry.x() + mpParent->maGeometry.width() / 2;
1279             root_y = mpParent->maGeometry.y() + mpParent->maGeometry.height() / 2;
1280         }
1281         else
1282             XQueryPointer( GetXDisplay(),
1283                            GetShellWindow(),
1284                            &aRoot, &aChild,
1285                            &root_x, &root_y,
1286                            &x, &y,
1287                            &mask );
1288         const std::vector< AbsoluteScreenPixelRectangle >& rScreens = GetDisplay()->GetXineramaScreens();
1289         for(const auto & rScreen : rScreens)
1290             if( rScreen.Contains( AbsoluteScreenPixelPoint( root_x, root_y ) ) )
1291             {
1292                 aScreen.SetPos(rScreen.GetPos());
1293                 aRealScreenSize = rScreen.GetSize();
1294                 break;
1295             }
1296     }
1297 
1298     if( mpParent )
1299     {
1300         X11SalFrame* pFrame = mpParent;
1301         while( pFrame->mpParent )
1302             pFrame = pFrame->mpParent;
1303         if( pFrame->maGeometry.width() < 1  || pFrame->maGeometry.height() < 1 )
1304         {
1305             AbsoluteScreenPixelRectangle aRect;
1306             pFrame->GetPosSize( aRect );
1307             pFrame->maGeometry.setPosSize(tools::Rectangle(aRect));
1308         }
1309 
1310         if( pFrame->nStyle_ & SalFrameStyleFlags::PLUG )
1311         {
1312             ::Window aRoot;
1313             unsigned int nScreenWidth, nScreenHeight, bw, depth;
1314             int nScreenX, nScreenY;
1315             XGetGeometry( GetXDisplay(),
1316                           pFrame->GetShellWindow(),
1317                           &aRoot,
1318                           &nScreenX, &nScreenY,
1319                           &nScreenWidth, &nScreenHeight,
1320                           &bw, &depth );
1321             aScreen = {{ nScreenX, nScreenY }, Size(nScreenWidth, nScreenHeight)};
1322         }
1323         else
1324             aScreen = AbsoluteScreenPixelRectangle(pFrame->maGeometry.posSize());
1325     }
1326 
1327     if( mpParent && mpParent->nShowState_ == X11ShowState::Normal )
1328     {
1329         if( maGeometry.width() >= mpParent->maGeometry.width() &&
1330             maGeometry.height() >= mpParent->maGeometry.height() )
1331         {
1332             nX = aScreen.getX() + 40;
1333             nY = aScreen.getY() + 40;
1334         }
1335         else
1336         {
1337             // center the window relative to the top level frame
1338             nX = (aScreen.GetWidth()  - static_cast<int>(maGeometry.width()) ) / 2 + aScreen.getX();
1339             nY = (aScreen.GetHeight() - static_cast<int>(maGeometry.height())) / 2 + aScreen.getY();
1340         }
1341     }
1342     else
1343     {
1344         // center the window relative to screen
1345         nX = (aRealScreenSize.getWidth()  - static_cast<int>(maGeometry.width()) ) / 2 + aScreen.getX();
1346         nY = (aRealScreenSize.getHeight() - static_cast<int>(maGeometry.height())) / 2 + aScreen.getY();
1347     }
1348     nX = nX < 0 ? 0 : nX;
1349     nY = nY < 0 ? 0 : nY;
1350 
1351     bDefaultPosition_ = False;
1352     if( mpParent )
1353     {
1354         nX -= mpParent->maGeometry.x();
1355         nY -= mpParent->maGeometry.y();
1356     }
1357 
1358     SetPosSize({ { nX, nY }, maGeometry.size() });
1359 }
1360 
updateScreenNumber()1361 void X11SalFrame::updateScreenNumber()
1362 {
1363     if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
1364     {
1365         AbsoluteScreenPixelPoint aPoint( maGeometry.x(), maGeometry.y() );
1366         const std::vector<AbsoluteScreenPixelRectangle>& rScreenRects( GetDisplay()->GetXineramaScreens() );
1367         size_t nScreens = rScreenRects.size();
1368         for( size_t i = 0; i < nScreens; i++ )
1369         {
1370             if( rScreenRects[i].Contains( aPoint ) )
1371             {
1372                 maGeometry.setScreen(static_cast<unsigned int>(i));
1373                 break;
1374             }
1375         }
1376     }
1377     else
1378         maGeometry.setScreen(m_nXScreen.getXScreen());
1379 }
1380 
SetPosSize(tools::Long nX,tools::Long nY,tools::Long nWidth,tools::Long nHeight,sal_uInt16 nFlags)1381 void X11SalFrame::SetPosSize( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt16 nFlags )
1382 {
1383     if( nStyle_ & SalFrameStyleFlags::PLUG )
1384         return;
1385 
1386     // relative positioning in X11SalFrame::SetPosSize
1387     AbsoluteScreenPixelRectangle aPosSize( AbsoluteScreenPixelPoint( maGeometry.x(), maGeometry.y() ), AbsoluteScreenPixelSize( maGeometry.width(), maGeometry.height() ) );
1388     aPosSize.Normalize();
1389 
1390     if( ! ( nFlags & SAL_FRAME_POSSIZE_X ) )
1391     {
1392         nX = aPosSize.Left();
1393         if( mpParent )
1394             nX -= mpParent->maGeometry.x();
1395     }
1396     if( ! ( nFlags & SAL_FRAME_POSSIZE_Y ) )
1397     {
1398         nY = aPosSize.Top();
1399         if( mpParent )
1400             nY -= mpParent->maGeometry.y();
1401     }
1402     if( ! ( nFlags & SAL_FRAME_POSSIZE_WIDTH ) )
1403         nWidth = aPosSize.GetWidth();
1404     if( ! ( nFlags & SAL_FRAME_POSSIZE_HEIGHT ) )
1405         nHeight = aPosSize.GetHeight();
1406 
1407     aPosSize = AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint( nX, nY ), AbsoluteScreenPixelSize( nWidth, nHeight ) );
1408 
1409     if( ! ( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) ) )
1410     {
1411         if( bDefaultPosition_ )
1412         {
1413             maGeometry.setSize(Size(aPosSize.GetSize()));
1414             Center();
1415         }
1416         else
1417             SetSize( Size( nWidth, nHeight ) );
1418     }
1419     else
1420         SetPosSize( aPosSize );
1421 
1422     bDefaultPosition_ = False;
1423 }
1424 
SetAlwaysOnTop(bool bOnTop)1425 void X11SalFrame::SetAlwaysOnTop( bool bOnTop )
1426 {
1427     if( ! IsOverrideRedirect() )
1428     {
1429         bAlwaysOnTop_ = bOnTop;
1430         pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bOnTop );
1431     }
1432 }
1433 
1434 constexpr auto FRAMESTATE_MASK_MAXIMIZED_GEOMETRY =
1435      vcl::WindowDataMask::MaximizedX     | vcl::WindowDataMask::MaximizedY |
1436      vcl::WindowDataMask::MaximizedWidth | vcl::WindowDataMask::MaximizedHeight;
1437 
SetWindowState(const vcl::WindowData * pState)1438 void X11SalFrame::SetWindowState( const vcl::WindowData *pState )
1439 {
1440     if (pState == nullptr)
1441         return;
1442 
1443     // Request for position or size change
1444     if (pState->mask() & vcl::WindowDataMask::PosSize)
1445     {
1446         /* #i44325#
1447          * if maximized, set restore size and guess maximized size from last time
1448          * in state change below maximize window
1449          */
1450         if( ! IsChildWindow() &&
1451             (pState->mask() & vcl::WindowDataMask::PosSizeState) == vcl::WindowDataMask::PosSizeState &&
1452             (pState->state() & vcl::WindowState::Maximized) &&
1453             (pState->mask() & FRAMESTATE_MASK_MAXIMIZED_GEOMETRY) == FRAMESTATE_MASK_MAXIMIZED_GEOMETRY
1454             )
1455         {
1456             XSizeHints* pHints = XAllocSizeHints();
1457             tools::Long nSupplied = 0;
1458             XGetWMNormalHints( GetXDisplay(),
1459                                GetShellWindow(),
1460                                pHints,
1461                                &nSupplied );
1462             pHints->flags |= PPosition | PWinGravity;
1463             pHints->x = pState->x();
1464             pHints->y = pState->y();
1465             pHints->win_gravity = pDisplay_->getWMAdaptor()->getPositionWinGravity();
1466             XSetWMNormalHints(GetXDisplay(), GetShellWindow(), pHints);
1467             XFree( pHints );
1468 
1469             XMoveResizeWindow(GetXDisplay(), GetShellWindow(), pState->x(), pState->y(),
1470                               pState->width(), pState->height());
1471             // guess maximized geometry from last time
1472             maGeometry.setPos({ pState->GetMaximizedX(), pState->GetMaximizedY() });
1473             maGeometry.setSize({ static_cast<tools::Long>(pState->GetMaximizedWidth()), static_cast<tools::Long>(pState->GetMaximizedHeight()) });
1474             cairo_xlib_surface_set_size(mpSurface,  pState->GetMaximizedWidth(), pState->GetMaximizedHeight());
1475             updateScreenNumber();
1476         }
1477         else
1478         {
1479             bool bDoAdjust = false;
1480             AbsoluteScreenPixelRectangle aPosSize;
1481             // initialize with current geometry
1482             if ((pState->mask() & vcl::WindowDataMask::PosSize) != vcl::WindowDataMask::PosSize)
1483                 GetPosSize(aPosSize);
1484 
1485             sal_uInt16 nPosFlags = 0;
1486 
1487             // change requested properties
1488             if (pState->mask() & vcl::WindowDataMask::X)
1489             {
1490                 aPosSize.SetPosX(pState->x() - (mpParent ? mpParent->maGeometry.x() : 0));
1491                 nPosFlags |= SAL_FRAME_POSSIZE_X;
1492             }
1493             if (pState->mask() & vcl::WindowDataMask::Y)
1494             {
1495                 aPosSize.SetPosY(pState->y() - (mpParent ? mpParent->maGeometry.y() : 0));
1496                 nPosFlags |= SAL_FRAME_POSSIZE_Y;
1497             }
1498             if (pState->mask() & vcl::WindowDataMask::Width)
1499             {
1500                 tools::Long nWidth = pState->width() > 0 ? pState->width()  - 1 : 0;
1501                 aPosSize.setWidth (nWidth);
1502                 bDoAdjust = true;
1503             }
1504             if (pState->mask() & vcl::WindowDataMask::Height)
1505             {
1506                 int nHeight = pState->height() > 0 ? pState->height() - 1 : 0;
1507                 aPosSize.setHeight (nHeight);
1508                 bDoAdjust = true;
1509             }
1510 
1511             const AbsoluteScreenPixelSize& aScreenSize = pDisplay_->getDataForScreen( m_nXScreen ).m_aSize;
1512 
1513             if( bDoAdjust && aPosSize.GetWidth() <= aScreenSize.Width()
1514                 && aPosSize.GetHeight() <= aScreenSize.Height() )
1515             {
1516                 SalFrameGeometry aGeom = maGeometry;
1517 
1518                 if( ! (nStyle_ & ( SalFrameStyleFlags::FLOAT | SalFrameStyleFlags::PLUG ) ) &&
1519                     mpParent && aGeom.leftDecoration() == 0 && aGeom.topDecoration() == 0)
1520                 {
1521                     aGeom = mpParent->maGeometry;
1522                     if (aGeom.leftDecoration() == 0 && aGeom.topDecoration() == 0)
1523                         aGeom.setDecorations(5, 20, 5, 5);
1524                 }
1525 
1526                 auto nRight = aPosSize.Right() + (mpParent ? mpParent->maGeometry.x() : 0);
1527                 auto nBottom = aPosSize.Bottom() + (mpParent ? mpParent->maGeometry.y() : 0);
1528                 auto nLeft = aPosSize.Left() + (mpParent ? mpParent->maGeometry.x() : 0);
1529                 auto nTop = aPosSize.Top() + (mpParent ? mpParent->maGeometry.y() : 0);
1530 
1531                 // adjust position so that frame fits onto screen
1532                 if( nRight+static_cast<tools::Long>(aGeom.rightDecoration()) > aScreenSize.Width()-1 )
1533                     aPosSize.Move( aScreenSize.Width() - nRight - static_cast<tools::Long>(aGeom.rightDecoration()), 0 );
1534                 if( nBottom+static_cast<tools::Long>(aGeom.bottomDecoration()) > aScreenSize.Height()-1 )
1535                     aPosSize.Move( 0, aScreenSize.Height() - nBottom - static_cast<tools::Long>(aGeom.bottomDecoration()) );
1536                 if( nLeft < static_cast<tools::Long>(aGeom.leftDecoration()) )
1537                     aPosSize.Move( static_cast<tools::Long>(aGeom.leftDecoration()) - nLeft, 0 );
1538                 if( nTop < static_cast<tools::Long>(aGeom.topDecoration()) )
1539                     aPosSize.Move( 0, static_cast<tools::Long>(aGeom.topDecoration()) - nTop );
1540             }
1541 
1542             SetPosSize(aPosSize.getX(), aPosSize.getY(),
1543                        aPosSize.GetWidth(), aPosSize.GetHeight(),
1544                        SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT |
1545                        nPosFlags);
1546         }
1547     }
1548 
1549     // request for status change
1550     if (!(pState->mask() & vcl::WindowDataMask::State))
1551         return;
1552 
1553     if (pState->state() & vcl::WindowState::Maximized)
1554     {
1555         nShowState_ = X11ShowState::Normal;
1556         if( ! (pState->state() & (vcl::WindowState::MaximizedHorz|vcl::WindowState::MaximizedVert) ) )
1557             Maximize();
1558         else
1559         {
1560             bool bHorz(pState->state() & vcl::WindowState::MaximizedHorz);
1561             bool bVert(pState->state() & vcl::WindowState::MaximizedVert);
1562             GetDisplay()->getWMAdaptor()->maximizeFrame( this, bHorz, bVert );
1563         }
1564         maRestorePosSize = AbsoluteScreenPixelRectangle(pState->posSize());
1565     }
1566     else if( mbMaximizedHorz || mbMaximizedVert )
1567         GetDisplay()->getWMAdaptor()->maximizeFrame( this, false, false );
1568 
1569     if (pState->state() & vcl::WindowState::Minimized)
1570     {
1571         if (nShowState_ == X11ShowState::Unknown)
1572             nShowState_ = X11ShowState::Normal;
1573         Minimize();
1574     }
1575     if (pState->state() & vcl::WindowState::Normal)
1576     {
1577         if (nShowState_ != X11ShowState::Normal)
1578             Restore();
1579     }
1580 }
1581 
GetWindowState(vcl::WindowData * pState)1582 bool X11SalFrame::GetWindowState( vcl::WindowData* pState )
1583 {
1584     if( X11ShowState::Minimized == nShowState_ )
1585         pState->setState(vcl::WindowState::Minimized);
1586     else
1587         pState->setState(vcl::WindowState::Normal);
1588 
1589     AbsoluteScreenPixelRectangle aPosSize;
1590     if( maRestorePosSize.IsEmpty() )
1591         GetPosSize( aPosSize );
1592     else
1593         aPosSize = maRestorePosSize;
1594 
1595     if( mbMaximizedHorz )
1596         pState->rState() |= vcl::WindowState::MaximizedHorz;
1597     if( mbMaximizedVert )
1598         pState->rState() |= vcl::WindowState::MaximizedVert;
1599 
1600     pState->setPosSize(tools::Rectangle(aPosSize));
1601     pState->setMask(vcl::WindowDataMask::PosSizeState);
1602 
1603     if (! maRestorePosSize.IsEmpty() )
1604     {
1605         GetPosSize( aPosSize );
1606         pState->rState() |= vcl::WindowState::Maximized;
1607         pState->SetMaximizedX(aPosSize.Left());
1608         pState->SetMaximizedY(aPosSize.Top());
1609         pState->SetMaximizedWidth(aPosSize.GetWidth());
1610         pState->SetMaximizedHeight(aPosSize.GetHeight());
1611         pState->rMask() |= FRAMESTATE_MASK_MAXIMIZED_GEOMETRY;
1612     }
1613 
1614     return true;
1615 }
1616 
SetMenu(SalMenu *)1617 void X11SalFrame::SetMenu( SalMenu* )
1618 {
1619 }
1620 
GetPosSize(AbsoluteScreenPixelRectangle & rPosSize)1621 void X11SalFrame::GetPosSize( AbsoluteScreenPixelRectangle &rPosSize )
1622 {
1623     if( maGeometry.width() < 1 || maGeometry.height() < 1 )
1624     {
1625         const AbsoluteScreenPixelSize& aScreenSize = pDisplay_->getDataForScreen( m_nXScreen ).m_aSize;
1626         tools::Long w = aScreenSize.Width()  - maGeometry.leftDecoration() - maGeometry.rightDecoration();
1627         tools::Long h = aScreenSize.Height() - maGeometry.topDecoration() - maGeometry.bottomDecoration();
1628 
1629         rPosSize = AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint( maGeometry.x(), maGeometry.y() ), AbsoluteScreenPixelSize( w, h ) );
1630     }
1631     else
1632         rPosSize = AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint( maGeometry.x(), maGeometry.y() ),
1633                               AbsoluteScreenPixelSize( maGeometry.width(), maGeometry.height() ) );
1634 }
1635 
SetSize(const Size & rSize)1636 void X11SalFrame::SetSize( const Size &rSize )
1637 {
1638     if( rSize.IsEmpty() )
1639         return;
1640 
1641     if( ! ( nStyle_ & SalFrameStyleFlags::SIZEABLE )
1642         && ! IsChildWindow()
1643         && ( nStyle_ & (SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::OWNERDRAWDECORATION) ) != SalFrameStyleFlags::FLOAT )
1644     {
1645         XSizeHints* pHints = XAllocSizeHints();
1646         tools::Long nSupplied = 0;
1647         XGetWMNormalHints( GetXDisplay(),
1648                            GetShellWindow(),
1649                            pHints,
1650                            &nSupplied
1651                            );
1652         pHints->min_width   = rSize.Width();
1653         pHints->min_height  = rSize.Height();
1654         pHints->max_width   = rSize.Width();
1655         pHints->max_height  = rSize.Height();
1656         pHints->flags |= PMinSize | PMaxSize;
1657         XSetWMNormalHints( GetXDisplay(),
1658                            GetShellWindow(),
1659                            pHints );
1660         XFree( pHints );
1661     }
1662     XResizeWindow( GetXDisplay(), IsSysChildWindow() ? GetWindow() : GetShellWindow(), rSize.Width(), rSize.Height() );
1663     if( GetWindow() != GetShellWindow() )
1664     {
1665         if( nStyle_ & SalFrameStyleFlags::PLUG )
1666             XMoveResizeWindow( GetXDisplay(), GetWindow(), 0, 0, rSize.Width(), rSize.Height() );
1667         else
1668             XResizeWindow( GetXDisplay(), GetWindow(), rSize.Width(), rSize.Height() );
1669     }
1670 
1671     cairo_xlib_surface_set_size(mpSurface, rSize.Width(), rSize.Height());
1672     maGeometry.setSize(rSize);
1673 
1674     // allow the external status window to reposition
1675     if (mbInputFocus && mpInputContext != nullptr)
1676         mpInputContext->SetICFocus ( this );
1677 }
1678 
SetPosSize(const AbsoluteScreenPixelRectangle & rPosSize)1679 void X11SalFrame::SetPosSize( const AbsoluteScreenPixelRectangle &rPosSize )
1680 {
1681     XWindowChanges values;
1682     values.x        = rPosSize.Left();
1683     values.y        = rPosSize.Top();
1684     values.width    = rPosSize.GetWidth();
1685     values.height   = rPosSize.GetHeight();
1686 
1687     if( !values.width || !values.height )
1688         return;
1689 
1690     if( mpParent && ! IsSysChildWindow() )
1691     {
1692         if( AllSettings::GetLayoutRTL() )
1693             values.x = mpParent->maGeometry.width()-values.width-1-values.x;
1694 
1695         ::Window aChild;
1696         // coordinates are relative to parent, so translate to root coordinates
1697         XTranslateCoordinates( GetDisplay()->GetDisplay(),
1698                                 mpParent->GetWindow(),
1699                                 GetDisplay()->GetRootWindow( m_nXScreen ),
1700                                 values.x, values.y,
1701                                 &values.x, &values.y,
1702                                 & aChild );
1703     }
1704 
1705     bool bMoved = false;
1706     bool bSized = false;
1707     if( values.x != maGeometry.x() || values.y != maGeometry.y() )
1708         bMoved = true;
1709     if( values.width != static_cast<int>(maGeometry.width()) || values.height != static_cast<int>(maGeometry.height()) )
1710         bSized = true;
1711 
1712     // do not set WMNormalHints for...
1713     if(
1714         // child windows
1715         ! IsChildWindow()
1716         // popups (menu, help window, etc.)
1717         &&  (nStyle_ & (SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::OWNERDRAWDECORATION) ) != SalFrameStyleFlags::FLOAT
1718         // shown, sizeable windows
1719         && ( nShowState_ == X11ShowState::Unknown ||
1720              nShowState_ == X11ShowState::Hidden ||
1721              ! ( nStyle_ & SalFrameStyleFlags::SIZEABLE )
1722              )
1723         )
1724     {
1725         XSizeHints* pHints = XAllocSizeHints();
1726         tools::Long nSupplied = 0;
1727         XGetWMNormalHints( GetXDisplay(),
1728                            GetShellWindow(),
1729                            pHints,
1730                            &nSupplied
1731                            );
1732         if( ! ( nStyle_ & SalFrameStyleFlags::SIZEABLE ) )
1733         {
1734             pHints->min_width   = rPosSize.GetWidth();
1735             pHints->min_height  = rPosSize.GetHeight();
1736             pHints->max_width   = rPosSize.GetWidth();
1737             pHints->max_height  = rPosSize.GetHeight();
1738             pHints->flags |= PMinSize | PMaxSize;
1739         }
1740         if( nShowState_ == X11ShowState::Unknown || nShowState_ == X11ShowState::Hidden )
1741         {
1742             pHints->flags |= PPosition | PWinGravity;
1743             pHints->x           = values.x;
1744             pHints->y           = values.y;
1745             pHints->win_gravity = pDisplay_->getWMAdaptor()->getPositionWinGravity();
1746         }
1747         if( mbFullScreen )
1748         {
1749             pHints->max_width   = 10000;
1750             pHints->max_height  = 10000;
1751             pHints->flags |= PMaxSize;
1752         }
1753         XSetWMNormalHints( GetXDisplay(),
1754                            GetShellWindow(),
1755                            pHints );
1756         XFree( pHints );
1757     }
1758 
1759     XMoveResizeWindow( GetXDisplay(), IsSysChildWindow() ? GetWindow() : GetShellWindow(), values.x, values.y, values.width, values.height );
1760     if( GetShellWindow() != GetWindow() )
1761     {
1762         if( nStyle_ & SalFrameStyleFlags::PLUG )
1763             XMoveResizeWindow( GetXDisplay(), GetWindow(), 0, 0, values.width, values.height );
1764         else
1765             XMoveResizeWindow( GetXDisplay(), GetWindow(), values.x, values.y, values.width, values.height );
1766     }
1767 
1768     cairo_xlib_surface_set_size(mpSurface, values.width, values.height);
1769     maGeometry.setPosSize({ values.x, values.y }, { values.width, values.height });
1770     if( IsSysChildWindow() && mpParent )
1771         // translate back to root coordinates
1772         maGeometry.move(mpParent->maGeometry.x(), mpParent->maGeometry.y());
1773 
1774     updateScreenNumber();
1775     if( bSized && ! bMoved )
1776         CallCallback( SalEvent::Resize, nullptr );
1777     else if( bMoved && ! bSized )
1778         CallCallback( SalEvent::Move, nullptr );
1779     else
1780         CallCallback( SalEvent::MoveResize, nullptr );
1781 
1782     // allow the external status window to reposition
1783     if (mbInputFocus && mpInputContext != nullptr)
1784         mpInputContext->SetICFocus ( this );
1785 }
1786 
Minimize()1787 void X11SalFrame::Minimize()
1788 {
1789     if( IsSysChildWindow() )
1790         return;
1791 
1792     if( X11ShowState::Unknown == nShowState_ || X11ShowState::Hidden == nShowState_ )
1793     {
1794         SAL_WARN( "vcl", "X11SalFrame::Minimize on withdrawn window" );
1795         return;
1796     }
1797 
1798     if( XIconifyWindow( GetXDisplay(),
1799                         GetShellWindow(),
1800                         pDisplay_->GetDefaultXScreen().getXScreen() ) )
1801         nShowState_ = X11ShowState::Minimized;
1802 }
1803 
Maximize()1804 void X11SalFrame::Maximize()
1805 {
1806     if( IsSysChildWindow() )
1807         return;
1808 
1809     if( X11ShowState::Minimized == nShowState_ )
1810     {
1811         GetDisplay()->getWMAdaptor()->frameIsMapping( this );
1812         XMapWindow( GetXDisplay(), GetShellWindow() );
1813         nShowState_ = X11ShowState::Normal;
1814     }
1815 
1816     pDisplay_->getWMAdaptor()->maximizeFrame( this );
1817 }
1818 
Restore()1819 void X11SalFrame::Restore()
1820 {
1821     if( IsSysChildWindow() )
1822         return;
1823 
1824     if( X11ShowState::Unknown == nShowState_ || X11ShowState::Hidden == nShowState_ )
1825     {
1826         SAL_INFO( "vcl", "X11SalFrame::Restore on withdrawn window" );
1827         return;
1828     }
1829 
1830     if( X11ShowState::Minimized == nShowState_ )
1831     {
1832         GetDisplay()->getWMAdaptor()->frameIsMapping( this );
1833         XMapWindow( GetXDisplay(), GetShellWindow() );
1834         nShowState_ = X11ShowState::Normal;
1835     }
1836 
1837     pDisplay_->getWMAdaptor()->maximizeFrame( this, false, false );
1838 }
1839 
SetScreenNumber(unsigned int nNewScreen)1840 void X11SalFrame::SetScreenNumber( unsigned int nNewScreen )
1841 {
1842     if( nNewScreen == maGeometry.screen() )
1843         return;
1844 
1845     if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
1846     {
1847         if( nNewScreen >= GetDisplay()->GetXineramaScreens().size() )
1848             return;
1849 
1850         tools::Rectangle aOldScreenRect( GetDisplay()->GetXineramaScreens()[maGeometry.screen()] );
1851         tools::Rectangle aNewScreenRect( GetDisplay()->GetXineramaScreens()[nNewScreen] );
1852         bool bVisible = bMapped_;
1853         if( bVisible )
1854             Show( false );
1855         maGeometry.setX(aNewScreenRect.Left() + (maGeometry.x() - aOldScreenRect.Left()));
1856         maGeometry.setY(aNewScreenRect.Top() + (maGeometry.y() - aOldScreenRect.Top()));
1857         createNewWindow( None, m_nXScreen );
1858         if( bVisible )
1859             Show( true );
1860         maGeometry.setScreen(nNewScreen);
1861     }
1862     else if( nNewScreen < GetDisplay()->GetXScreenCount() )
1863     {
1864         bool bVisible = bMapped_;
1865         if( bVisible )
1866             Show( false );
1867         createNewWindow( None, SalX11Screen( nNewScreen ) );
1868         if( bVisible )
1869             Show( true );
1870         maGeometry.setScreen(nNewScreen);
1871     }
1872 }
1873 
SetApplicationID(const OUString & rWMClass)1874 void X11SalFrame::SetApplicationID( const OUString &rWMClass )
1875 {
1876     if( rWMClass != m_sWMClass && ! IsChildWindow() )
1877     {
1878         m_sWMClass = rWMClass;
1879         updateWMClass();
1880         for (auto const& child : maChildren)
1881             child->SetApplicationID(rWMClass);
1882     }
1883 }
1884 
updateWMClass()1885 void X11SalFrame::updateWMClass()
1886 {
1887     XClassHint* pClass = XAllocClassHint();
1888     OString aResName = SalGenericSystem::getFrameResName();
1889     pClass->res_name  = const_cast<char*>(aResName.getStr());
1890 
1891     OString aResClass = OUStringToOString(m_sWMClass, RTL_TEXTENCODING_ASCII_US);
1892     const char *pResClass = !aResClass.isEmpty() ? aResClass.getStr() :
1893                             SalGenericSystem::getFrameClassName();
1894 
1895     pClass->res_class = const_cast<char*>(pResClass);
1896     XSetClassHint( GetXDisplay(), GetShellWindow(), pClass );
1897     XFree( pClass );
1898 }
1899 
ShowFullScreen(bool bFullScreen,sal_Int32 nScreen)1900 void X11SalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nScreen )
1901 {
1902     if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
1903     {
1904         if( mbFullScreen == bFullScreen )
1905             return;
1906         if( bFullScreen )
1907         {
1908             maRestorePosSize = AbsoluteScreenPixelRectangle(maGeometry.posSize());
1909             AbsoluteScreenPixelRectangle aRect;
1910             if( nScreen < 0 || o3tl::make_unsigned(nScreen) >= GetDisplay()->GetXineramaScreens().size() )
1911                 aRect = AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint(0,0), GetDisplay()->GetScreenSize( m_nXScreen ) );
1912             else
1913                 aRect = GetDisplay()->GetXineramaScreens()[nScreen];
1914             m_bIsPartialFullScreen = true;
1915             bool bVisible = bMapped_;
1916             if( bVisible )
1917                 Show( false );
1918             maGeometry.setPosSize(tools::Rectangle(aRect));
1919             mbMaximizedHorz = mbMaximizedVert = false;
1920             mbFullScreen = true;
1921             createNewWindow( None, m_nXScreen );
1922             if( GetDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
1923                 GetDisplay()->getWMAdaptor()->enableAlwaysOnTop( this, true );
1924             else
1925                 GetDisplay()->getWMAdaptor()->showFullScreen( this, true );
1926             if( bVisible )
1927                 Show(true);
1928 
1929         }
1930         else
1931         {
1932             mbFullScreen = false;
1933             m_bIsPartialFullScreen = false;
1934             bool bVisible = bMapped_;
1935             AbsoluteScreenPixelRectangle aRect = maRestorePosSize;
1936             maRestorePosSize = AbsoluteScreenPixelRectangle();
1937             if( bVisible )
1938                 Show( false );
1939             createNewWindow( None, m_nXScreen );
1940             if( !aRect.IsEmpty() )
1941                 SetPosSize( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(),
1942                             SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y |
1943                             SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
1944             if( bVisible )
1945                 Show( true );
1946         }
1947     }
1948     else
1949     {
1950         if( nScreen < 0 || o3tl::make_unsigned(nScreen) >= GetDisplay()->GetXScreenCount() )
1951             nScreen = m_nXScreen.getXScreen();
1952         if( nScreen != static_cast<int>(m_nXScreen.getXScreen()) )
1953         {
1954             bool bVisible = bMapped_;
1955             if( mbFullScreen )
1956                 pDisplay_->getWMAdaptor()->showFullScreen( this, false );
1957             if( bVisible )
1958                 Show( false );
1959             createNewWindow( None, SalX11Screen( nScreen ) );
1960             if( mbFullScreen )
1961                 pDisplay_->getWMAdaptor()->showFullScreen( this, true );
1962             if( bVisible )
1963                 Show( true );
1964         }
1965         if( mbFullScreen == bFullScreen )
1966             return;
1967 
1968         pDisplay_->getWMAdaptor()->showFullScreen( this, bFullScreen );
1969     }
1970 }
1971 
StartPresentation(bool bStart)1972 void X11SalFrame::StartPresentation( bool bStart )
1973 {
1974     maSessionManagerInhibitor.inhibit( bStart,
1975                                     u"presentation",
1976                                     APPLICATION_INHIBIT_IDLE,
1977                                     mhWindow,
1978                                     GetXDisplay() );
1979 
1980     if( ! bStart && hPresentationWindow != None )
1981         doReparentPresentationDialogues( GetDisplay() );
1982     hPresentationWindow = (bStart && IsOverrideRedirect() ) ? GetWindow() : None;
1983 
1984     if( bStart && hPresentationWindow )
1985     {
1986         /*  #i10559# workaround for WindowMaker: try to restore
1987          *  current focus after presentation window is gone
1988          */
1989         int revert_to = 0;
1990         XGetInputFocus( GetXDisplay(), &hPresFocusWindow, &revert_to );
1991     }
1992 }
1993 
1994 // Pointer
1995 
SetPointer(PointerStyle ePointerStyle)1996 void X11SalFrame::SetPointer( PointerStyle ePointerStyle )
1997 {
1998     hCursor_ = pDisplay_->GetPointer( ePointerStyle );
1999     XDefineCursor( GetXDisplay(), GetWindow(), hCursor_ );
2000 
2001     if( IsCaptured() || nVisibleFloats > 0 )
2002         XChangeActivePointerGrab( GetXDisplay(),
2003                         PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
2004                         hCursor_,
2005                         CurrentTime );
2006 }
2007 
SetPointerPos(tools::Long nX,tools::Long nY)2008 void X11SalFrame::SetPointerPos(tools::Long nX, tools::Long nY)
2009 {
2010     /* when the application tries to center the mouse in the dialog the
2011      * window isn't mapped already. So use coordinates relative to the root window.
2012      */
2013     unsigned int nWindowLeft = maGeometry.x() + nX;
2014     unsigned int nWindowTop  = maGeometry.y() + nY;
2015 
2016     XWarpPointer( GetXDisplay(), None, pDisplay_->GetRootWindow( pDisplay_->GetDefaultXScreen() ),
2017                   0, 0, 0, 0, nWindowLeft, nWindowTop);
2018 }
2019 
2020 // delay handling of extended text input
2021 #if !defined(__synchronous_extinput__)
2022 void
HandleExtTextEvent(XClientMessageEvent const * pEvent)2023 X11SalFrame::HandleExtTextEvent (XClientMessageEvent const *pEvent)
2024 {
2025     #if SAL_TYPES_SIZEOFLONG > 4
2026     void* pExtTextEvent = reinterpret_cast<void*>(  (pEvent->data.l[0] & 0xffffffff)
2027                                                   | (pEvent->data.l[1] << 32) );
2028     #else
2029     void* pExtTextEvent = reinterpret_cast<void*>(pEvent->data.l[0]);
2030     #endif
2031     SalEvent nExtTextEventType = SalEvent(pEvent->data.l[2]);
2032 
2033     CallCallback(nExtTextEventType, pExtTextEvent);
2034 
2035     switch (nExtTextEventType)
2036     {
2037         case SalEvent::EndExtTextInput:
2038             break;
2039 
2040         case SalEvent::ExtTextInput:
2041             break;
2042 
2043         default:
2044             SAL_WARN("vcl.window",
2045                     "X11SalFrame::HandleExtTextEvent: invalid extended input.");
2046     }
2047 }
2048 #endif /* defined(__synchronous_extinput__) */
2049 
2050 // PostEvent
2051 
PostEvent(std::unique_ptr<ImplSVEvent> pData)2052 bool X11SalFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData)
2053 {
2054     GetDisplay()->SendInternalEvent( this, pData.release() );
2055     return true;
2056 }
2057 
2058 // Title
2059 
SetTitle(const OUString & rTitle)2060 void X11SalFrame::SetTitle( const OUString& rTitle )
2061 {
2062     if( ! ( IsChildWindow() || (nStyle_ & SalFrameStyleFlags::FLOAT ) ) )
2063     {
2064         m_aTitle = rTitle;
2065         GetDisplay()->getWMAdaptor()->setWMName( this, rTitle );
2066     }
2067 }
2068 
Flush()2069 void X11SalFrame::Flush()
2070 {
2071     if( pGraphics_ )
2072         pGraphics_->Flush();
2073     XFlush( GetDisplay()->GetDisplay() );
2074 }
2075 
2076 // Keyboard
2077 
SetInputContext(SalInputContext * pContext)2078 void X11SalFrame::SetInputContext( SalInputContext* pContext )
2079 {
2080     if (pContext == nullptr)
2081         return;
2082 
2083     // 1. We should create an input context for this frame
2084     //    only when InputContextFlags::Text is set.
2085 
2086     if (!(pContext->mnOptions & InputContextFlags::Text))
2087     {
2088         if( mpInputContext )
2089             mpInputContext->Unmap();
2090         return;
2091     }
2092 
2093     // 2. We should use on-the-spot inputstyle
2094     //    only when InputContextFlags::ExtTExt is set.
2095 
2096     if (mpInputContext == nullptr)
2097     {
2098         mpInputContext.reset( new SalI18N_InputContext( this ) );
2099         if (mpInputContext->UseContext())
2100         {
2101             mpInputContext->ExtendEventMask( GetShellWindow() );
2102             if (mbInputFocus)
2103                 mpInputContext->SetICFocus( this );
2104         }
2105     }
2106     else
2107         mpInputContext->Map( this );
2108 }
2109 
EndExtTextInput(EndExtTextInputFlags)2110 void X11SalFrame::EndExtTextInput( EndExtTextInputFlags )
2111 {
2112     if (mpInputContext != nullptr)
2113           mpInputContext->EndExtTextInput();
2114 }
2115 
GetKeyName(sal_uInt16 nKeyCode)2116 OUString X11SalFrame::GetKeyName( sal_uInt16 nKeyCode )
2117 {
2118     return GetDisplay()->GetKeyName( nKeyCode );
2119 }
2120 
MapUnicodeToKeyCode(sal_Unicode,LanguageType,vcl::KeyCode &)2121 bool X11SalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& )
2122 {
2123     // not supported yet
2124     return false;
2125 }
2126 
GetInputLanguage()2127 LanguageType X11SalFrame::GetInputLanguage()
2128 {
2129     // could be improved by checking unicode ranges of the last input
2130     return LANGUAGE_DONTKNOW;
2131 }
2132 
2133 // Settings
2134 
UpdateSettings(AllSettings & rSettings)2135 void X11SalFrame::UpdateSettings( AllSettings& rSettings )
2136 {
2137     StyleSettings aStyleSettings = rSettings.GetStyleSettings();
2138     aStyleSettings.SetCursorBlinkTime( 500 );
2139     aStyleSettings.SetMenuBarTextColor( aStyleSettings.GetPersonaMenuBarTextColor().value_or( COL_BLACK ) );
2140     rSettings.SetStyleSettings( aStyleSettings );
2141 }
2142 
CaptureMouse(bool bCapture)2143 void X11SalFrame::CaptureMouse( bool bCapture )
2144 {
2145     nCaptured_ = pDisplay_->CaptureMouse( bCapture ? this : nullptr );
2146 }
2147 
SetParent(SalFrame * pNewParent)2148 void X11SalFrame::SetParent( SalFrame* pNewParent )
2149 {
2150     if( mpParent != pNewParent )
2151     {
2152         if( mpParent )
2153             mpParent->maChildren.remove( this );
2154 
2155         mpParent = static_cast<X11SalFrame*>(pNewParent);
2156         mpParent->maChildren.push_back( this );
2157         if( mpParent->m_nXScreen != m_nXScreen )
2158             createNewWindow( None, mpParent->m_nXScreen );
2159         GetDisplay()->getWMAdaptor()->changeReferenceFrame( this, mpParent );
2160     }
2161 }
2162 
GetParent() const2163 SalFrame* X11SalFrame::GetParent() const
2164 {
2165     return mpParent;
2166 }
2167 
createNewWindow(::Window aNewParent,SalX11Screen nXScreen)2168 void X11SalFrame::createNewWindow( ::Window aNewParent, SalX11Screen nXScreen )
2169 {
2170     bool bWasVisible = bMapped_;
2171     if( bWasVisible )
2172         Show( false );
2173 
2174     if( nXScreen.getXScreen() >= GetDisplay()->GetXScreenCount() )
2175         nXScreen = m_nXScreen;
2176 
2177     SystemParentData aParentData;
2178     aParentData.nSize = sizeof(SystemParentData);
2179     aParentData.aWindow = aNewParent;
2180     aParentData.bXEmbedSupport = (aNewParent != None && m_bXEmbed); // caution: this is guesswork
2181     if( aNewParent == None )
2182     {
2183         aParentData.aWindow = None;
2184         m_bXEmbed = false;
2185     }
2186     else
2187     {
2188         // is new parent a root window ?
2189         Display* pDisp = GetDisplay()->GetDisplay();
2190         int nScreens = GetDisplay()->GetXScreenCount();
2191         for( int i = 0; i < nScreens; i++ )
2192         {
2193             if( aNewParent == RootWindow( pDisp, i ) )
2194             {
2195                 nXScreen = SalX11Screen( i );
2196                 aParentData.aWindow = None;
2197                 m_bXEmbed = false;
2198                 break;
2199             }
2200         }
2201     }
2202 
2203     // first deinit frame
2204     updateGraphics(true);
2205     if( mpInputContext )
2206     {
2207         mpInputContext->UnsetICFocus();
2208         mpInputContext->Unmap();
2209     }
2210     if( GetWindow() == hPresentationWindow )
2211     {
2212         hPresentationWindow = None;
2213         doReparentPresentationDialogues( GetDisplay() );
2214     }
2215     if (mpSurface)
2216     {
2217         cairo_surface_destroy(mpSurface);
2218         mpSurface = nullptr;
2219     }
2220     XDestroyWindow( GetXDisplay(), mhWindow );
2221     mhWindow = None;
2222 
2223     // now init with new parent again
2224     if ( aParentData.aWindow != None )
2225         Init( nStyle_ | SalFrameStyleFlags::PLUG, nXScreen, &aParentData );
2226     else
2227         Init( nStyle_ & ~SalFrameStyleFlags::PLUG, nXScreen, nullptr, true );
2228 
2229     // update graphics if necessary
2230     updateGraphics(false);
2231 
2232     if( ! m_aTitle.isEmpty() )
2233         SetTitle( m_aTitle );
2234 
2235     if( mpParent )
2236     {
2237         if( mpParent->m_nXScreen != m_nXScreen )
2238             SetParent( nullptr );
2239         else
2240             pDisplay_->getWMAdaptor()->changeReferenceFrame( this, mpParent );
2241     }
2242 
2243     if( bWasVisible )
2244         Show( true );
2245 
2246     std::list< X11SalFrame* > aChildren = maChildren;
2247     for (auto const& child : aChildren)
2248         child->createNewWindow( None, m_nXScreen );
2249 
2250     // FIXME: SalObjects
2251 }
2252 
SetPluginParent(SystemParentData * pNewParent)2253 void X11SalFrame::SetPluginParent( SystemParentData* pNewParent )
2254 {
2255     if( pNewParent->nSize >= sizeof(SystemParentData) )
2256         m_bXEmbed = pNewParent->aWindow != None && pNewParent->bXEmbedSupport;
2257 
2258     createNewWindow(pNewParent->aWindow);
2259 }
2260 
2261 // Sound
Beep()2262 void X11SalFrame::Beep()
2263 {
2264     GetDisplay()->Beep();
2265 }
2266 
2267 // Event Handling
2268 
sal_GetCode(int state)2269 static sal_uInt16 sal_GetCode( int state )
2270 {
2271     sal_uInt16 nCode = 0;
2272 
2273     if( state & Button1Mask )
2274         nCode |= MOUSE_LEFT;
2275     if( state & Button2Mask )
2276         nCode |= MOUSE_MIDDLE;
2277     if( state & Button3Mask )
2278         nCode |= MOUSE_RIGHT;
2279 
2280     if( state & ShiftMask )
2281         nCode |= KEY_SHIFT;
2282     if( state & ControlMask )
2283         nCode |= KEY_MOD1;
2284     if( state & Mod1Mask )
2285         nCode |= KEY_MOD2;
2286 
2287     // Map Meta/Super modifier to MOD3 on all Unix systems
2288     // except macOS
2289     if( state & Mod3Mask )
2290         nCode |= KEY_MOD3;
2291 
2292     return nCode;
2293 }
2294 
GetPointerState()2295 SalFrame::SalPointerState X11SalFrame::GetPointerState()
2296 {
2297     SalPointerState aState;
2298     ::Window aRoot, aChild;
2299     int rx, ry, wx, wy;
2300     unsigned int nMask = 0;
2301     XQueryPointer( GetXDisplay(),
2302                    GetShellWindow(),
2303                    &aRoot,
2304                    &aChild,
2305                    &rx, &ry,
2306                    &wx, &wy,
2307                    &nMask
2308                    );
2309 
2310     aState.maPos = Point(wx, wy);
2311     aState.mnState = sal_GetCode( nMask );
2312     return aState;
2313 }
2314 
GetIndicatorState()2315 KeyIndicatorState X11SalFrame::GetIndicatorState()
2316 {
2317     return vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetIndicatorState();
2318 }
2319 
SimulateKeyPress(sal_uInt16 nKeyCode)2320 void X11SalFrame::SimulateKeyPress( sal_uInt16 nKeyCode )
2321 {
2322     vcl_sal::getSalDisplay(GetGenericUnixSalData())->SimulateKeyPress(nKeyCode);
2323 }
2324 
2325 namespace
2326 {
2327 struct CompressWheelEventsData
2328 {
2329     XEvent* firstEvent;
2330     bool ignore;
2331     int count; // number of compressed events
2332 };
2333 
compressWheelEvents(Display *,XEvent * event,XPointer p)2334 Bool compressWheelEvents( Display*, XEvent* event, XPointer p )
2335 {
2336     CompressWheelEventsData* data = reinterpret_cast< CompressWheelEventsData* >( p );
2337     if( data->ignore )
2338         return False; // we're already after the events to compress
2339     if( event->type == ButtonPress || event->type == ButtonRelease )
2340     {
2341         const unsigned int mask = Button1Mask << ( event->xbutton.button - Button1 );
2342         if( event->xbutton.button == data->firstEvent->xbutton.button
2343             && event->xbutton.window == data->firstEvent->xbutton.window
2344             && event->xbutton.x == data->firstEvent->xbutton.x
2345             && event->xbutton.y == data->firstEvent->xbutton.y
2346             && ( event->xbutton.state | mask ) == ( data->firstEvent->xbutton.state | mask ))
2347         {
2348             // Count if it's another press (i.e. wheel start event).
2349             if( event->type == ButtonPress )
2350                 ++data->count;
2351             return True; // And remove the event from the queue.
2352         }
2353     }
2354     // Non-matching event, skip certain events that cannot possibly affect input processing,
2355     // but otherwise ignore all further events.
2356     switch( event->type )
2357     {
2358         case Expose:
2359         case NoExpose:
2360             break;
2361         default:
2362             data->ignore = true;
2363             break;
2364     }
2365     return False;
2366 }
2367 
2368 } // namespace
2369 
HandleMouseEvent(XEvent * pEvent)2370 bool X11SalFrame::HandleMouseEvent( XEvent *pEvent )
2371 {
2372     SalMouseEvent aMouseEvt;
2373     SalEvent            nEvent = SalEvent::NONE;
2374     bool                bClosePopups = false;
2375 
2376     if( nVisibleFloats && pEvent->type == EnterNotify )
2377         return false;
2378 
2379     if( LeaveNotify == pEvent->type || EnterNotify == pEvent->type )
2380     {
2381         /*
2382          *  some WMs (and/or) applications  have a passive grab on
2383          *  mouse buttons (XGrabButton). This leads to enter/leave notifies
2384          *  with mouse buttons pressed in the state mask before the actual
2385          *  ButtonPress event gets dispatched. But EnterNotify
2386          *  is reported in vcl as MouseMove event. Some office code
2387          *  decides that a pressed button in a MouseMove belongs to
2388          *  a drag operation which leads to doing things differently.
2389          *
2390          *  ignore Enter/LeaveNotify resulting from grabs so that
2391          *  help windows do not disappear just after appearing
2392          *
2393          *  hopefully this workaround will not break anything.
2394          */
2395         if( pEvent->xcrossing.mode == NotifyGrab || pEvent->xcrossing.mode == NotifyUngrab  )
2396             return false;
2397 
2398         aMouseEvt.mnX       = pEvent->xcrossing.x;
2399         aMouseEvt.mnY       = pEvent->xcrossing.y;
2400         aMouseEvt.mnTime    = pEvent->xcrossing.time;
2401         aMouseEvt.mnCode    = sal_GetCode( pEvent->xcrossing.state );
2402         aMouseEvt.mnButton  = 0;
2403 
2404         nEvent              = LeaveNotify == pEvent->type
2405                               ? SalEvent::MouseLeave
2406                               : SalEvent::MouseMove;
2407     }
2408     else if( pEvent->type == MotionNotify )
2409     {
2410         aMouseEvt.mnX       = pEvent->xmotion.x;
2411         aMouseEvt.mnY       = pEvent->xmotion.y;
2412         aMouseEvt.mnTime    = pEvent->xmotion.time;
2413         aMouseEvt.mnCode    = sal_GetCode( pEvent->xmotion.state );
2414 
2415         aMouseEvt.mnButton  = 0;
2416 
2417         nEvent              = SalEvent::MouseMove;
2418         if( nVisibleFloats > 0 && mpParent )
2419         {
2420             Cursor aCursor = mpParent->GetCursor();
2421             if( pEvent->xmotion.x >= 0 && pEvent->xmotion.x < static_cast<int>(maGeometry.width()) &&
2422                 pEvent->xmotion.y >= 0 && pEvent->xmotion.y < static_cast<int>(maGeometry.height()) )
2423                 aCursor = None;
2424 
2425             XChangeActivePointerGrab( GetXDisplay(),
2426                                       PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
2427                                       aCursor,
2428                                       CurrentTime );
2429         }
2430     }
2431     else
2432     {
2433         // let mouse events reach the correct window
2434         if( nVisibleFloats < 1 )
2435         {
2436             if( ! (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION) )
2437                 XUngrabPointer( GetXDisplay(), CurrentTime );
2438         }
2439         else if( pEvent->type == ButtonPress )
2440         {
2441             // see if the user clicks outside all of the floats
2442             // if yes release the grab
2443             bool bInside = false;
2444             for (auto pSalFrame : GetDisplay()->getFrames() )
2445             {
2446                 const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame );
2447                 if( pFrame->IsFloatGrabWindow()                                     &&
2448                     pFrame->bMapped_                                                &&
2449                     pEvent->xbutton.x_root >= pFrame->maGeometry.x()                             &&
2450                     pEvent->xbutton.x_root < pFrame->maGeometry.x() + static_cast<int>(pFrame->maGeometry.width()) &&
2451                     pEvent->xbutton.y_root >= pFrame->maGeometry.y()                             &&
2452                     pEvent->xbutton.y_root < pFrame->maGeometry.y() + static_cast<int>(pFrame->maGeometry.height()) )
2453                 {
2454                     bInside = true;
2455                     break;
2456                 }
2457             }
2458             if( ! bInside )
2459             {
2460                 // need not take care of the XUngrabPointer in Show( false )
2461                 // because XUngrabPointer does not produce errors if pointer
2462                 // is not grabbed
2463                 XUngrabPointer( GetXDisplay(), CurrentTime );
2464                 bClosePopups = true;
2465 
2466                 /*  #i15246# only close popups if pointer is outside all our frames
2467                  *  cannot use our own geometry data here because stacking
2468                  *  is unknown (the above case implicitly assumes
2469                  *  that floats are on top which should be true)
2470                  */
2471                 ::Window aRoot, aChild;
2472                 int root_x, root_y, win_x, win_y;
2473                 unsigned int mask_return;
2474                 if( XQueryPointer( GetXDisplay(),
2475                                    GetDisplay()->GetRootWindow( m_nXScreen ),
2476                                    &aRoot, &aChild,
2477                                    &root_x, &root_y,
2478                                    &win_x, &win_y,
2479                                    &mask_return )
2480                     && aChild // pointer may not be in any child
2481                     )
2482                 {
2483                     for (auto pSalFrame : GetDisplay()->getFrames() )
2484                     {
2485                         const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame );
2486                         if( ! pFrame->IsFloatGrabWindow()
2487                             && ( pFrame->GetWindow() == aChild ||
2488                                  pFrame->GetShellWindow() == aChild ||
2489                                  pFrame->GetStackingWindow() == aChild )
2490                             )
2491                         {
2492                             // #i63638# check that pointer is inside window, not
2493                             // only inside stacking window
2494                             if( root_x >= pFrame->maGeometry.x() && root_x < sal::static_int_cast< int >(pFrame->maGeometry.x()+pFrame->maGeometry.width()) &&
2495                                 root_y >= pFrame->maGeometry.y() && root_y < sal::static_int_cast< int >(pFrame->maGeometry.x()+pFrame->maGeometry.height()) )
2496                             {
2497                                 bClosePopups = false;
2498                             }
2499                             break;
2500                         }
2501                     }
2502                 }
2503             }
2504         }
2505 
2506         if( m_bXEmbed && pEvent->xbutton.button == Button1 )
2507             askForXEmbedFocus( pEvent->xbutton.time );
2508 
2509         if( pEvent->xbutton.button == Button1 ||
2510             pEvent->xbutton.button == Button2 ||
2511             pEvent->xbutton.button == Button3 )
2512         {
2513             aMouseEvt.mnX       = pEvent->xbutton.x;
2514             aMouseEvt.mnY       = pEvent->xbutton.y;
2515             aMouseEvt.mnTime    = pEvent->xbutton.time;
2516             aMouseEvt.mnCode    = sal_GetCode( pEvent->xbutton.state );
2517 
2518             if( Button1 == pEvent->xbutton.button )
2519                 aMouseEvt.mnButton  = MOUSE_LEFT;
2520             else if( Button2 == pEvent->xbutton.button )
2521                 aMouseEvt.mnButton  = MOUSE_MIDDLE;
2522             else if( Button3 == pEvent->xbutton.button )
2523                 aMouseEvt.mnButton  = MOUSE_RIGHT;
2524 
2525             nEvent              = ButtonPress == pEvent->type
2526                 ? SalEvent::MouseButtonDown
2527                 : SalEvent::MouseButtonUp;
2528         }
2529         else if( pEvent->xbutton.button == Button4 ||
2530                  pEvent->xbutton.button == Button5 ||
2531                  pEvent->xbutton.button == Button6 ||
2532                  pEvent->xbutton.button == Button7 )
2533         {
2534             const bool bIncrement(
2535                 pEvent->xbutton.button == Button4 ||
2536                 pEvent->xbutton.button == Button6 );
2537             const bool bHoriz(
2538                 pEvent->xbutton.button == Button6 ||
2539                 pEvent->xbutton.button == Button7 );
2540 
2541             if( pEvent->type == ButtonRelease )
2542                 return false;
2543 
2544             static sal_uLong        nLines = 0;
2545             if( ! nLines )
2546             {
2547                 char* pEnv = getenv( "SAL_WHEELLINES" );
2548                 nLines = pEnv ? atoi( pEnv ) : 3;
2549                 if( nLines > 10 )
2550                     nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
2551             }
2552 
2553             // Compress consecutive wheel events (way too fine scrolling may cause lags if one scrolling steps takes long).
2554             CompressWheelEventsData data;
2555             data.firstEvent = pEvent;
2556             data.count = 1;
2557             XEvent dummy;
2558             do
2559             {
2560                 data.ignore = false;
2561             } while( XCheckIfEvent( pEvent->xany.display, &dummy, compressWheelEvents, reinterpret_cast< XPointer >( &data )));
2562 
2563             SalWheelMouseEvent  aWheelEvt;
2564             aWheelEvt.mnTime        = pEvent->xbutton.time;
2565             aWheelEvt.mnX           = pEvent->xbutton.x;
2566             aWheelEvt.mnY           = pEvent->xbutton.y;
2567             aWheelEvt.mnDelta       = ( bIncrement ? 120 : -120 ) * data.count;
2568             aWheelEvt.mnNotchDelta  = bIncrement ? 1 : -1;
2569             aWheelEvt.mnScrollLines = nLines * data.count;
2570             aWheelEvt.mnCode        = sal_GetCode( pEvent->xbutton.state );
2571             aWheelEvt.mbHorz        = bHoriz;
2572 
2573             nEvent = SalEvent::WheelMouse;
2574 
2575             if( AllSettings::GetLayoutRTL() )
2576                 aWheelEvt.mnX = nWidth_-1-aWheelEvt.mnX;
2577             return CallCallback( nEvent, &aWheelEvt );
2578         }
2579     }
2580 
2581     bool nRet = false;
2582     if( nEvent == SalEvent::MouseLeave
2583         || ( aMouseEvt.mnX <  nWidth_  && aMouseEvt.mnX >  -1 &&
2584              aMouseEvt.mnY <  nHeight_ && aMouseEvt.mnY >  -1 )
2585         || pDisplay_->MouseCaptured( this )
2586         )
2587     {
2588         if( AllSettings::GetLayoutRTL() )
2589             aMouseEvt.mnX = nWidth_-1-aMouseEvt.mnX;
2590         nRet = CallCallback( nEvent, &aMouseEvt );
2591     }
2592 
2593     if( bClosePopups )
2594     {
2595         /*  #108213# close popups after dispatching the event outside the popup;
2596          *  applications do weird things.
2597          */
2598         ImplSVData* pSVData = ImplGetSVData();
2599         if (pSVData->mpWinData->mpFirstFloat)
2600         {
2601             if (!(pSVData->mpWinData->mpFirstFloat->GetPopupModeFlags()
2602                   & FloatWinPopupFlags::NoAppFocusClose))
2603                 pSVData->mpWinData->mpFirstFloat->EndPopupMode(FloatWinPopupEndFlags::Cancel
2604                                                                | FloatWinPopupEndFlags::CloseAll);
2605         }
2606     }
2607 
2608     return nRet;
2609 }
2610 
2611 namespace {
2612 
2613 // F10 means either KEY_F10 or KEY_MENU, which has to be decided
2614 // in the independent part.
2615 struct KeyAlternate
2616 {
2617     sal_uInt16          nKeyCode;
2618     sal_Unicode     nCharCode;
KeyAlternate__anon82de0bf20311::KeyAlternate2619     KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
KeyAlternate__anon82de0bf20311::KeyAlternate2620     KeyAlternate( sal_uInt16 nKey, sal_Unicode nChar = 0 ) : nKeyCode( nKey ), nCharCode( nChar ) {}
2621 };
2622 
2623 }
2624 
2625 static KeyAlternate
GetAlternateKeyCode(const sal_uInt16 nKeyCode)2626 GetAlternateKeyCode( const sal_uInt16 nKeyCode )
2627 {
2628     KeyAlternate aAlternate;
2629 
2630     switch( nKeyCode )
2631     {
2632         case KEY_F10: aAlternate = KeyAlternate( KEY_MENU );break;
2633         case KEY_F24: aAlternate = KeyAlternate( KEY_SUBTRACT, '-' );break;
2634     }
2635 
2636     return aAlternate;
2637 }
2638 
beginUnicodeSequence()2639 void X11SalFrame::beginUnicodeSequence()
2640 {
2641     OUString& rSeq( GetGenericUnixSalData()->GetUnicodeCommand() );
2642     vcl::DeletionListener aDeleteWatch( this );
2643 
2644     if( !rSeq.isEmpty() )
2645         endUnicodeSequence();
2646 
2647     rSeq = "u";
2648 
2649     if( ! aDeleteWatch.isDeleted() )
2650     {
2651         ExtTextInputAttr nTextAttr = ExtTextInputAttr::Underline;
2652         SalExtTextInputEvent aEv;
2653         aEv.maText          = rSeq;
2654         aEv.mpTextAttr      = &nTextAttr;
2655         aEv.mnCursorPos     = 0;
2656         aEv.mnCursorFlags   = 0;
2657 
2658         CallCallback(SalEvent::ExtTextInput, static_cast<void*>(&aEv));
2659     }
2660 }
2661 
appendUnicodeSequence(sal_Unicode c)2662 bool X11SalFrame::appendUnicodeSequence( sal_Unicode c )
2663 {
2664     bool bRet = false;
2665     OUString& rSeq( GetGenericUnixSalData()->GetUnicodeCommand() );
2666     if( !rSeq.isEmpty() )
2667     {
2668         // range check
2669         if( (c >= '0' && c <= '9') ||
2670             (c >= 'a' && c <= 'f') ||
2671             (c >= 'A' && c <= 'F') )
2672         {
2673             rSeq += OUStringChar(c);
2674             std::vector<ExtTextInputAttr> attribs( rSeq.getLength(), ExtTextInputAttr::Underline );
2675 
2676             SalExtTextInputEvent aEv;
2677             aEv.maText          = rSeq;
2678             aEv.mpTextAttr      = attribs.data();
2679             aEv.mnCursorPos     = 0;
2680             aEv.mnCursorFlags   = 0;
2681 
2682             CallCallback(SalEvent::ExtTextInput, static_cast<void*>(&aEv));
2683             bRet = true;
2684         }
2685         else
2686             bRet = endUnicodeSequence();
2687     }
2688     else
2689         endUnicodeSequence();
2690     return bRet;
2691 }
2692 
endUnicodeSequence()2693 bool X11SalFrame::endUnicodeSequence()
2694 {
2695     OUString& rSeq( GetGenericUnixSalData()->GetUnicodeCommand() );
2696 
2697     vcl::DeletionListener aDeleteWatch( this );
2698     if( rSeq.getLength() > 1 && rSeq.getLength() < 6 )
2699     {
2700         // cut the "u"
2701         std::u16string_view aNumbers( rSeq.subView( 1 ) );
2702         sal_uInt32 nValue = o3tl::toUInt32(aNumbers, 16);
2703         if( nValue >= 32 )
2704         {
2705             ExtTextInputAttr nTextAttr = ExtTextInputAttr::Underline;
2706             SalExtTextInputEvent aEv;
2707             aEv.maText          = OUString( sal_Unicode(nValue) );
2708             aEv.mpTextAttr      = &nTextAttr;
2709             aEv.mnCursorPos     = 0;
2710             aEv.mnCursorFlags   = 0;
2711             CallCallback(SalEvent::ExtTextInput, static_cast<void*>(&aEv));
2712         }
2713     }
2714     bool bWasInput = !rSeq.isEmpty();
2715     rSeq.clear();
2716     if( bWasInput && ! aDeleteWatch.isDeleted() )
2717         CallCallback(SalEvent::EndExtTextInput, nullptr);
2718     return bWasInput;
2719 }
2720 
HandleKeyEvent(XKeyEvent * pEvent)2721 bool X11SalFrame::HandleKeyEvent( XKeyEvent *pEvent )
2722 {
2723     if( pEvent->type == KeyRelease )
2724     {
2725         // Ignore autorepeat keyrelease events. If there is a series of keypress+keyrelease+keypress events
2726         // generated by holding down a key, and if these are from autorepeat (keyrelease and the following keypress
2727         // have the same timestamp), drop the autorepeat keyrelease event. Not exactly sure why this is done
2728         // (possibly hiding differences between platforms, or just making it more sensible, because technically
2729         // the key has not been released at all).
2730         bool ignore = false;
2731         // Discard queued excessive autorepeat events.
2732         // If the user presses and holds down a key, the autorepeating keypress events
2733         // may overload LO (e.g. if the key is PageDown and the LO cannot keep up scrolling).
2734         // Reduce the load by simply discarding such excessive events (so for a KeyRelease event,
2735         // check if it's followed by matching KeyPress+KeyRelease pair(s) and discard those).
2736         // This shouldn't have any negative effects - unlike with normal (non-autorepeat
2737         // events), the user is unlikely to rely on the exact number of resulting actions
2738         // (since autorepeat generates keypress events rather quickly and it's hard to estimate
2739         // how many exactly) and the idea should be just keeping the key pressed until something
2740         // happens (in which case more events that just lag LO shouldn't make a difference).
2741         Display* dpy = pEvent->display;
2742         XKeyEvent previousRelease = *pEvent;
2743         while( XPending( dpy ))
2744         {
2745             XEvent nextEvent1;
2746             bool discard1 = false;
2747             XNextEvent( dpy, &nextEvent1 );
2748             if( nextEvent1.type == KeyPress && nextEvent1.xkey.time == previousRelease.time
2749                 && !nextEvent1.xkey.send_event && nextEvent1.xkey.window == previousRelease.window
2750                 && nextEvent1.xkey.state == previousRelease.state && nextEvent1.xkey.keycode == previousRelease.keycode )
2751             {   // This looks like another autorepeat keypress.
2752                 ignore = true;
2753                 if( XPending( dpy ))
2754                 {
2755                     XEvent nextEvent2;
2756                     XNextEvent( dpy, &nextEvent2 );
2757                     if( nextEvent2.type == KeyRelease && nextEvent2.xkey.time <= ( previousRelease.time + 100 )
2758                         && !nextEvent2.xkey.send_event && nextEvent2.xkey.window == previousRelease.window
2759                         && nextEvent2.xkey.state == previousRelease.state && nextEvent2.xkey.keycode == previousRelease.keycode )
2760                     {   // And the matching keyrelease -> drop them both.
2761                         discard1 = true;
2762                         previousRelease = nextEvent2.xkey;
2763                         ignore = false; // There either will be another autorepeating keypress that'll lead to discarding
2764                                         // the pEvent keyrelease, it this discarding makes that keyrelease the last one.
2765                     }
2766                     else
2767                     {
2768                         XPutBackEvent( dpy, &nextEvent2 );
2769                         break;
2770                     }
2771                 }
2772             }
2773             if( !discard1 )
2774             {   // Unrelated event, put back and stop compressing.
2775                 XPutBackEvent( dpy, &nextEvent1 );
2776                 break;
2777             }
2778         }
2779         if( ignore ) // This autorepeating keyrelease is followed by another keypress.
2780             return false;
2781     }
2782 
2783     KeySym          nKeySym;
2784     KeySym          nUnmodifiedKeySym;
2785     int             nLen = 2048;
2786     char            *pPrintable = static_cast<char*>(alloca( nLen ));
2787 
2788     // singlebyte code composed by input method, the new default
2789     if (mpInputContext != nullptr && mpInputContext->UseContext())
2790     {
2791         // returns a keysym as well as the pPrintable (in system encoding)
2792         // printable may be empty.
2793         Status nStatus;
2794         nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen,
2795                                         &nUnmodifiedKeySym,
2796                                         &nStatus, mpInputContext->GetContext() );
2797         if ( nStatus == XBufferOverflow )
2798         {
2799             // In case of overflow, XmbLookupString (called by GetKeySym)
2800             // returns required size
2801             // TODO : check if +1 is needed for 0 terminator
2802             nLen += 1;
2803             pPrintable = static_cast<char*>(alloca( nLen ));
2804             nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen,
2805                                             &nUnmodifiedKeySym,
2806                                             &nStatus, mpInputContext->GetContext() );
2807         }
2808     }
2809     else
2810     {
2811         // fallback, this should never ever be called
2812         Status nStatus = 0;
2813         nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen, &nUnmodifiedKeySym, &nStatus );
2814     }
2815 
2816     SalKeyEvent aKeyEvt;
2817     sal_uInt16  nKeyCode;
2818     sal_uInt16  nModCode = 0;
2819     char        aDummy;
2820 
2821     if( pEvent->state & ShiftMask )
2822         nModCode |= KEY_SHIFT;
2823     if( pEvent->state & ControlMask )
2824         nModCode |= KEY_MOD1;
2825     if( pEvent->state & Mod1Mask )
2826         nModCode |= KEY_MOD2;
2827 
2828     if( nModCode != (KEY_SHIFT|KEY_MOD1) )
2829         endUnicodeSequence();
2830 
2831     if(     nKeySym == XK_Shift_L   || nKeySym == XK_Shift_R
2832         ||  nKeySym == XK_Control_L || nKeySym == XK_Control_R
2833         ||  nKeySym == XK_Alt_L     || nKeySym == XK_Alt_R
2834         ||  nKeySym == XK_Meta_L    || nKeySym == XK_Meta_R
2835         ||  nKeySym == XK_Super_L   || nKeySym == XK_Super_R )
2836     {
2837         SalKeyModEvent aModEvt;
2838         aModEvt.mbDown = false; // auto-accelerator feature not supported here.
2839         aModEvt.mnModKeyCode = ModKeyFlags::NONE;
2840         if( pEvent->type == KeyPress && mnExtKeyMod == ModKeyFlags::NONE )
2841             mbSendExtKeyModChange = true;
2842         else if( pEvent->type == KeyRelease && mbSendExtKeyModChange )
2843         {
2844             aModEvt.mnModKeyCode = mnExtKeyMod;
2845             mnExtKeyMod = ModKeyFlags::NONE;
2846         }
2847 
2848         // pressing just the ctrl key leads to a keysym of XK_Control but
2849         // the event state does not contain ControlMask. In the release
2850         // event it's the other way round: it does contain the Control mask.
2851         // The modifier mode therefore has to be adapted manually.
2852         ModKeyFlags nExtModMask = ModKeyFlags::NONE;
2853         sal_uInt16 nModMask = 0;
2854         switch( nKeySym )
2855         {
2856             case XK_Control_L:
2857                 nExtModMask = ModKeyFlags::LeftMod1;
2858                 nModMask = KEY_MOD1;
2859                 break;
2860             case XK_Control_R:
2861                 nExtModMask = ModKeyFlags::RightMod1;
2862                 nModMask = KEY_MOD1;
2863                 break;
2864             case XK_Alt_L:
2865                 nExtModMask = ModKeyFlags::LeftMod2;
2866                 nModMask = KEY_MOD2;
2867                 break;
2868             case XK_Alt_R:
2869                 nExtModMask = ModKeyFlags::RightMod2;
2870                 nModMask = KEY_MOD2;
2871                 break;
2872             case XK_Shift_L:
2873                 nExtModMask = ModKeyFlags::LeftShift;
2874                 nModMask = KEY_SHIFT;
2875                 break;
2876             case XK_Shift_R:
2877                 nExtModMask = ModKeyFlags::RightShift;
2878                 nModMask = KEY_SHIFT;
2879                 break;
2880             // Map Meta/Super keys to MOD3 modifier on all Unix systems
2881             // except macOS
2882             case XK_Meta_L:
2883             case XK_Super_L:
2884                 nExtModMask = ModKeyFlags::LeftMod3;
2885                 nModMask = KEY_MOD3;
2886                 break;
2887             case XK_Meta_R:
2888             case XK_Super_R:
2889                 nExtModMask = ModKeyFlags::RightMod3;
2890                 nModMask = KEY_MOD3;
2891                 break;
2892         }
2893         if( pEvent->type == KeyRelease )
2894         {
2895             nModCode &= ~nModMask;
2896             mnExtKeyMod &= ~nExtModMask;
2897         }
2898         else
2899         {
2900             nModCode |= nModMask;
2901             mnExtKeyMod |= nExtModMask;
2902         }
2903 
2904         aModEvt.mnCode = nModCode;
2905 
2906         return CallCallback( SalEvent::KeyModChange, &aModEvt );
2907     }
2908 
2909     mbSendExtKeyModChange = false;
2910 
2911     // try to figure out the vcl code for the keysym
2912     // #i52338# use the unmodified KeySym if there is none for the real KeySym
2913     // because the independent part has only keycodes for unshifted keys
2914     nKeyCode = pDisplay_->GetKeyCode( nKeySym, &aDummy );
2915     if( nKeyCode == 0 )
2916         nKeyCode = pDisplay_->GetKeyCode( nUnmodifiedKeySym, &aDummy );
2917 
2918     // try to figure out a printable if XmbLookupString returns only a keysym
2919     // and NOT a printable. Do not store it in pPrintable[0] since it is expected to
2920     // be in system encoding, not unicode.
2921     // #i8988##, if KeySym and printable look equally promising then prefer KeySym
2922     // the printable is bound to the encoding so the KeySym might contain more
2923     // information (in et_EE locale: "Compose + Z + <" delivers "," in printable and
2924     // (the desired) Zcaron in KeySym
2925     sal_Unicode nKeyString = 0x0;
2926     if (   (nLen == 0)
2927         || ((nLen == 1) && (nKeySym > 0)) )
2928         nKeyString = KeysymToUnicode (nKeySym);
2929     // if we have nothing we give up
2930     if( !nKeyCode && !nLen && !nKeyString)
2931         return false;
2932 
2933     vcl::DeletionListener aDeleteWatch( this );
2934 
2935     if( nModCode == (KEY_SHIFT | KEY_MOD1) && pEvent->type == KeyPress )
2936     {
2937         sal_uInt16 nSeqKeyCode = pDisplay_->GetKeyCode( nUnmodifiedKeySym, &aDummy );
2938         if( nSeqKeyCode == KEY_U )
2939         {
2940             beginUnicodeSequence();
2941             return true;
2942         }
2943         else if( nSeqKeyCode >= KEY_0 && nSeqKeyCode <= KEY_9 )
2944         {
2945             if( appendUnicodeSequence( u'0' + sal_Unicode(nSeqKeyCode - KEY_0) ) )
2946                 return true;
2947         }
2948         else if( nSeqKeyCode >= KEY_A && nSeqKeyCode <= KEY_F )
2949         {
2950             if( appendUnicodeSequence( u'a' + sal_Unicode(nSeqKeyCode - KEY_A) ) )
2951                 return true;
2952         }
2953         else
2954             endUnicodeSequence();
2955     }
2956 
2957     if( aDeleteWatch.isDeleted() )
2958         return false;
2959 
2960     rtl_TextEncoding nEncoding = osl_getThreadTextEncoding();
2961 
2962     sal_Unicode *pBuffer;
2963     sal_Unicode *pString;
2964     sal_Size     nBufferSize = nLen * 2;
2965     sal_Size     nSize;
2966     pBuffer = static_cast<sal_Unicode*>(malloc( nBufferSize + 2 ));
2967     pBuffer[ 0 ] = 0;
2968 
2969     if (nKeyString != 0)
2970     {
2971         pString = &nKeyString;
2972         nSize = 1;
2973     }
2974     else if (nLen > 0 && nEncoding != RTL_TEXTENCODING_UNICODE)
2975     {
2976         // create text converter
2977         rtl_TextToUnicodeConverter aConverter =
2978                 rtl_createTextToUnicodeConverter( nEncoding );
2979         rtl_TextToUnicodeContext aContext =
2980                  rtl_createTextToUnicodeContext( aConverter );
2981 
2982         sal_uInt32  nConversionInfo;
2983         sal_Size    nConvertedChars;
2984 
2985         // convert to single byte text stream
2986         nSize = rtl_convertTextToUnicode(
2987                                 aConverter, aContext,
2988                                 pPrintable, nLen,
2989                                 pBuffer, nBufferSize,
2990                                 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE |
2991                                 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE,
2992                                 &nConversionInfo, &nConvertedChars );
2993 
2994         // destroy converter
2995         rtl_destroyTextToUnicodeContext( aConverter, aContext );
2996         rtl_destroyTextToUnicodeConverter( aConverter );
2997 
2998         pString = pBuffer;
2999     }
3000     else if (nLen > 0 /* nEncoding == RTL_TEXTENCODING_UNICODE */)
3001     {
3002         pString = reinterpret_cast<sal_Unicode*>(pPrintable);
3003         nSize = nLen;
3004     }
3005     else
3006     {
3007         pString = pBuffer;
3008         nSize   = 0;
3009     }
3010 
3011     if (   mpInputContext != nullptr
3012         && mpInputContext->UseContext()
3013         && KeyRelease != pEvent->type
3014         && (   (nSize >  1)
3015             || (nSize >  0 && mpInputContext->IsPreeditMode())) )
3016     {
3017         mpInputContext->CommitKeyEvent(pString, nSize);
3018     }
3019     else
3020     // normal single character keyinput
3021     {
3022         aKeyEvt.mnCode     = nKeyCode | nModCode;
3023         aKeyEvt.mnRepeat   = 0;
3024         aKeyEvt.mnCharCode = pString[ 0 ];
3025 
3026         if( KeyRelease == pEvent->type )
3027         {
3028             CallCallback( SalEvent::KeyUp, &aKeyEvt );
3029         }
3030         else
3031         {
3032             if ( ! CallCallback(SalEvent::KeyInput, &aKeyEvt) )
3033             {
3034                 // independent layer doesn't want to handle key-event, so check
3035                 // whether the keycode may have an alternate meaning
3036                 KeyAlternate aAlternate = GetAlternateKeyCode( nKeyCode );
3037                 if ( aAlternate.nKeyCode != 0 )
3038                 {
3039                     aKeyEvt.mnCode = aAlternate.nKeyCode | nModCode;
3040                     if( aAlternate.nCharCode )
3041                         aKeyEvt.mnCharCode = aAlternate.nCharCode;
3042                     CallCallback(SalEvent::KeyInput, &aKeyEvt);
3043                 }
3044             }
3045         }
3046     }
3047 
3048       // update the spot location for PreeditPosition IME style
3049 
3050     if (! aDeleteWatch.isDeleted())
3051     {
3052         if (mpInputContext != nullptr && mpInputContext->UseContext())
3053             mpInputContext->UpdateSpotLocation();
3054     }
3055 
3056     free (pBuffer);
3057     return true;
3058 }
3059 
HandleFocusEvent(XFocusChangeEvent const * pEvent)3060 bool X11SalFrame::HandleFocusEvent( XFocusChangeEvent const *pEvent )
3061 {
3062     // ReflectionX in Windows mode changes focus while mouse is grabbed
3063     if( nVisibleFloats > 0 && GetDisplay()->getWMAdaptor()->getWindowManagerName() == "ReflectionX Windows" )
3064         return true;
3065 
3066     /*  ignore focusout resulting from keyboard grabs
3067      *  we do not grab it and are not interested when
3068      *  someone else does CDE e.g. does a XGrabKey on arrow keys
3069      *  handle focus events with mode NotifyWhileGrabbed
3070      *  because with CDE alt-tab focus changing we do not get
3071      *  normal focus events
3072      *  cast focus event to the input context, otherwise the
3073      *  status window does not follow the application frame
3074      */
3075 
3076     if ( mpInputContext != nullptr  )
3077     {
3078         if( FocusIn == pEvent->type )
3079             mpInputContext->SetICFocus( this );
3080     }
3081 
3082     if ( pEvent->mode == NotifyNormal || pEvent->mode == NotifyWhileGrabbed ||
3083          ( ( nStyle_ & SalFrameStyleFlags::PLUG ) && pEvent->window == GetShellWindow() )
3084          )
3085     {
3086         if( hPresentationWindow != None && hPresentationWindow != GetShellWindow() )
3087             return false;
3088 
3089         if( FocusIn == pEvent->type )
3090         {
3091             GetSalInstance()->updatePrinterUpdate();
3092             mbInputFocus = True;
3093             ImplSVData* pSVData = ImplGetSVData();
3094 
3095             bool nRet = CallCallback( SalEvent::GetFocus,  nullptr );
3096             if ((mpParent != nullptr && nStyle_ == SalFrameStyleFlags::NONE)
3097                 && pSVData->mpWinData->mpFirstFloat)
3098             {
3099                 FloatWinPopupFlags nMode = pSVData->mpWinData->mpFirstFloat->GetPopupModeFlags();
3100                 pSVData->mpWinData->mpFirstFloat->SetPopupModeFlags(
3101                     nMode & ~FloatWinPopupFlags::NoAppFocusClose);
3102             }
3103             return nRet;
3104         }
3105         else
3106         {
3107             mbInputFocus = False;
3108             mbSendExtKeyModChange = false;
3109             mnExtKeyMod = ModKeyFlags::NONE;
3110             return CallCallback( SalEvent::LoseFocus, nullptr );
3111         }
3112     }
3113 
3114     return false;
3115 }
3116 
HandleExposeEvent(XEvent const * pEvent)3117 bool X11SalFrame::HandleExposeEvent( XEvent const *pEvent )
3118 {
3119     XRectangle  aRect = { 0, 0, 0, 0 };
3120     sal_uInt16  nCount = 0;
3121 
3122     if( pEvent->type == Expose )
3123     {
3124         aRect.x         = pEvent->xexpose.x;
3125         aRect.y         = pEvent->xexpose.y;
3126         aRect.width     = pEvent->xexpose.width;
3127         aRect.height    = pEvent->xexpose.height;
3128         nCount          = pEvent->xexpose.count;
3129     }
3130     else if( pEvent->type == GraphicsExpose )
3131     {
3132         aRect.x         = pEvent->xgraphicsexpose.x;
3133         aRect.y         = pEvent->xgraphicsexpose.y;
3134         aRect.width     = pEvent->xgraphicsexpose.width;
3135         aRect.height    = pEvent->xgraphicsexpose.height;
3136         nCount          = pEvent->xgraphicsexpose.count;
3137     }
3138 
3139     if( IsOverrideRedirect() && mbFullScreen &&
3140         aPresentationReparentList.empty() )
3141         // we are in fullscreen mode -> override redirect
3142          // focus is possibly lost, so reget it
3143          XSetInputFocus( GetXDisplay(), GetShellWindow(), RevertToNone, CurrentTime );
3144 
3145     // width and height are extents, so they are of by one for rectangle
3146     maPaintRegion.Union( tools::Rectangle( Point(aRect.x, aRect.y), Size(aRect.width+1, aRect.height+1) ) );
3147 
3148     if( nCount )
3149         // wait for last expose rectangle, do not wait for resize timer
3150         // if a completed graphics expose sequence is available
3151         return true;
3152 
3153     SalPaintEvent aPEvt( maPaintRegion.Left(), maPaintRegion.Top(), maPaintRegion.GetWidth(), maPaintRegion.GetHeight() );
3154 
3155     CallCallback( SalEvent::Paint, &aPEvt );
3156     maPaintRegion = tools::Rectangle();
3157 
3158     return true;
3159 }
3160 
RestackChildren(::Window * pTopLevelWindows,int nTopLevelWindows)3161 void X11SalFrame::RestackChildren( ::Window* pTopLevelWindows, int nTopLevelWindows )
3162 {
3163     if( maChildren.empty() )
3164         return;
3165 
3166     int nWindow = nTopLevelWindows;
3167     while( nWindow-- )
3168         if( pTopLevelWindows[nWindow] == GetStackingWindow() )
3169             break;
3170     if( nWindow < 0 )
3171         return;
3172 
3173     for (auto const& child : maChildren)
3174     {
3175         if( child->bMapped_ )
3176         {
3177             int nChild = nWindow;
3178             while( nChild-- )
3179             {
3180                 if( pTopLevelWindows[nChild] == child->GetStackingWindow() )
3181                 {
3182                     // if a child is behind its parent, place it above the
3183                     // parent (for insane WMs like Dtwm and olwm)
3184                     XWindowChanges aCfg;
3185                     aCfg.sibling    = GetStackingWindow();
3186                     aCfg.stack_mode = Above;
3187                     XConfigureWindow( GetXDisplay(), child->GetStackingWindow(), CWSibling|CWStackMode, &aCfg );
3188                     break;
3189                 }
3190             }
3191         }
3192     }
3193     for (auto const& child : maChildren)
3194     {
3195         child->RestackChildren( pTopLevelWindows, nTopLevelWindows );
3196     }
3197 }
3198 
RestackChildren()3199 void X11SalFrame::RestackChildren()
3200 {
3201     if( maChildren.empty() )
3202         return;
3203 
3204     ::Window aRoot, aParent, *pChildren = nullptr;
3205     unsigned int nChildren;
3206     if( XQueryTree( GetXDisplay(),
3207                     GetDisplay()->GetRootWindow( m_nXScreen ),
3208                     &aRoot,
3209                     &aParent,
3210                     &pChildren,
3211                     &nChildren ) )
3212     {
3213         RestackChildren( pChildren, nChildren );
3214         XFree( pChildren );
3215     }
3216 }
3217 
size_event_predicate(Display *,XEvent * event,XPointer arg)3218 static Bool size_event_predicate( Display*, XEvent* event, XPointer arg )
3219 {
3220     if( event->type != ConfigureNotify )
3221         return False;
3222     X11SalFrame* frame = reinterpret_cast< X11SalFrame* >( arg );
3223     XConfigureEvent* pEvent = &event->xconfigure;
3224     if( pEvent->window != frame->GetShellWindow()
3225         && pEvent->window != frame->GetWindow()
3226         && pEvent->window != frame->GetForeignParent()
3227         && pEvent->window != frame->GetStackingWindow())
3228     { // ignored at top of HandleSizeEvent()
3229         return False;
3230     }
3231     if( pEvent->window == frame->GetStackingWindow())
3232         return False; // filtered later in HandleSizeEvent()
3233     // at this point we know that there is another similar event in the queue
3234     frame->setPendingSizeEvent();
3235     return False; // but do not process the new event out of order
3236 }
3237 
setPendingSizeEvent()3238 void X11SalFrame::setPendingSizeEvent()
3239 {
3240     mPendingSizeEvent = true;
3241 }
3242 
HandleSizeEvent(XConfigureEvent * pEvent)3243 bool X11SalFrame::HandleSizeEvent( XConfigureEvent *pEvent )
3244 {
3245     // NOTE: if you add more tests in this function, make sure to update size_event_predicate()
3246     // so that it finds exactly the same events
3247 
3248     if (   pEvent->window != GetShellWindow()
3249            && pEvent->window != GetWindow()
3250            && pEvent->window != GetForeignParent()
3251            && pEvent->window != GetStackingWindow()
3252            )
3253     {
3254         // could be as well a sys-child window (aka SalObject)
3255         return true;
3256     }
3257 
3258     if( ( nStyle_ & SalFrameStyleFlags::PLUG ) && pEvent->window == GetShellWindow() )
3259     {
3260         // just update the children's positions
3261         RestackChildren();
3262         return true;
3263     }
3264 
3265     if( pEvent->window == GetForeignParent() )
3266     {
3267         XResizeWindow( GetXDisplay(),
3268                        GetWindow(),
3269                        pEvent->width,
3270                        pEvent->height );
3271         cairo_xlib_surface_set_size(mpSurface, pEvent->width, pEvent->height);
3272     }
3273 
3274     ::Window hDummy;
3275     XTranslateCoordinates( GetXDisplay(),
3276                            GetWindow(),
3277                            pDisplay_->GetRootWindow( pDisplay_->GetDefaultXScreen() ),
3278                            0, 0,
3279                            &pEvent->x, &pEvent->y,
3280                            &hDummy );
3281 
3282     if( pEvent->window == GetStackingWindow() )
3283     {
3284         if( maGeometry.x() != pEvent->x || maGeometry.y() != pEvent->y )
3285         {
3286             maGeometry.setPos({ pEvent->x, pEvent->y });
3287             CallCallback( SalEvent::Move, nullptr );
3288         }
3289         return true;
3290     }
3291 
3292     // check size hints in first time SalFrame::Show
3293     if( X11ShowState::Unknown == nShowState_ && bMapped_ )
3294         nShowState_ = X11ShowState::Normal;
3295 
3296     // Avoid a race condition where resizing this window to one size and shortly after that
3297     // to another size generates first size event with the old size and only after that
3298     // with the new size, temporarily making us think the old size is valid (bnc#674806).
3299     // So if there is another size event for this window pending, ignore this one.
3300     mPendingSizeEvent = false;
3301     XEvent dummy;
3302     XCheckIfEvent( GetXDisplay(), &dummy, size_event_predicate, reinterpret_cast< XPointer >( this ));
3303     if( mPendingSizeEvent )
3304         return true;
3305 
3306     nWidth_     = pEvent->width;
3307     nHeight_    = pEvent->height;
3308 
3309     bool bMoved = ( pEvent->x != maGeometry.x() || pEvent->y != maGeometry.y() );
3310     bool bSized = ( pEvent->width != static_cast<int>(maGeometry.width()) || pEvent->height != static_cast<int>(maGeometry.height()) );
3311 
3312     cairo_xlib_surface_set_size(mpSurface, pEvent->width, pEvent->height);
3313     maGeometry.setPosSize({ pEvent->x, pEvent->y }, { pEvent->width, pEvent->height });
3314     updateScreenNumber();
3315 
3316     // update children's position
3317     RestackChildren();
3318 
3319     if( bSized && ! bMoved )
3320         CallCallback( SalEvent::Resize, nullptr );
3321     else if( bMoved && ! bSized )
3322         CallCallback( SalEvent::Move, nullptr );
3323     else if( bMoved && bSized )
3324         CallCallback( SalEvent::MoveResize, nullptr );
3325 
3326     return true;
3327 }
3328 
IMPL_LINK_NOARG(X11SalFrame,HandleAlwaysOnTopRaise,Timer *,void)3329 IMPL_LINK_NOARG(X11SalFrame, HandleAlwaysOnTopRaise, Timer *, void)
3330 {
3331     if( bMapped_ )
3332         ToTop( SalFrameToTop::NONE );
3333 }
3334 
HandleReparentEvent(XReparentEvent * pEvent)3335 bool X11SalFrame::HandleReparentEvent( XReparentEvent *pEvent )
3336 {
3337     Display        *pDisplay   = pEvent->display;
3338     ::Window        hWM_Parent;
3339     ::Window        hRoot, *Children, hDummy;
3340     unsigned int    nChildren;
3341 
3342     static const char* pDisableStackingCheck = getenv( "SAL_DISABLE_STACKING_CHECK" );
3343 
3344     GetGenericUnixSalData()->ErrorTrapPush();
3345 
3346     /*
3347      *  don't rely on the new parent from the event.
3348      *  the event may be "out of date", that is the window manager
3349      *  window may not exist anymore. This can happen if someone
3350      *  shows a frame and hides it again quickly (not that it would
3351      *  be very sensible)
3352      */
3353     hWM_Parent = GetShellWindow();
3354     do
3355     {
3356         Children = nullptr;
3357         XQueryTree( pDisplay,
3358                     hWM_Parent,
3359                     &hRoot,
3360                     &hDummy,
3361                     &Children,
3362                     &nChildren );
3363 
3364         bool bError = GetGenericUnixSalData()->ErrorTrapPop( false );
3365         GetGenericUnixSalData()->ErrorTrapPush();
3366 
3367         if( bError )
3368         {
3369             hWM_Parent = GetShellWindow();
3370             break;
3371         }
3372          /* this sometimes happens if a Show(true) is
3373          *  immediately followed by Show(false) (which is braindead anyway)
3374          */
3375         if( hDummy == hWM_Parent )
3376             hDummy = hRoot;
3377         if( hDummy != hRoot )
3378             hWM_Parent = hDummy;
3379         if( Children )
3380             XFree( Children );
3381     } while( hDummy != hRoot );
3382 
3383     if( GetStackingWindow() == None
3384         && hWM_Parent != hPresentationWindow
3385         && hWM_Parent != GetShellWindow()
3386         && ( ! pDisableStackingCheck || ! *pDisableStackingCheck )
3387         )
3388     {
3389         mhStackingWindow = hWM_Parent;
3390         XSelectInput( pDisplay, GetStackingWindow(), StructureNotifyMask );
3391     }
3392 
3393     if(     hWM_Parent == pDisplay_->GetRootWindow( pDisplay_->GetDefaultXScreen() )
3394             ||  hWM_Parent == GetForeignParent()
3395             ||  pEvent->parent == pDisplay_->GetRootWindow( pDisplay_->GetDefaultXScreen() )
3396             || ( nStyle_ & SalFrameStyleFlags::FLOAT ) )
3397     {
3398         // Reparenting before Destroy
3399         aPresentationReparentList.remove( GetStackingWindow() );
3400         mhStackingWindow = None;
3401         GetGenericUnixSalData()->ErrorTrapPop();
3402         return false;
3403     }
3404 
3405     /*
3406      *  evil hack to show decorated windows on top
3407      *  of override redirect presentation windows:
3408      *  reparent the window manager window to the presentation window
3409      *  does not work with non-reparenting WMs
3410      *  in future this should not be necessary anymore with
3411      *  _NET_WM_STATE_FULLSCREEN available
3412      */
3413     if( hPresentationWindow != None
3414         && hPresentationWindow != GetWindow()
3415         && GetStackingWindow() != None
3416         && GetStackingWindow() != GetDisplay()->GetRootWindow( m_nXScreen )
3417         )
3418     {
3419         int x = 0, y = 0;
3420         ::Window aChild;
3421         XTranslateCoordinates( GetXDisplay(),
3422                                GetStackingWindow(),
3423                                GetDisplay()->GetRootWindow( m_nXScreen ),
3424                                0, 0,
3425                                &x, &y,
3426                                &aChild
3427                                );
3428         XReparentWindow( GetXDisplay(),
3429                          GetStackingWindow(),
3430                          hPresentationWindow,
3431                          x, y
3432                          );
3433         aPresentationReparentList.push_back( GetStackingWindow() );
3434     }
3435 
3436     int nLeft = 0, nTop = 0;
3437     XTranslateCoordinates( GetXDisplay(),
3438                            GetShellWindow(),
3439                            hWM_Parent,
3440                            0, 0,
3441                            &nLeft,
3442                            &nTop,
3443                            &hDummy );
3444     maGeometry.setLeftDecoration(nLeft > 0 ? nLeft-1 : 0);
3445     maGeometry.setTopDecoration(nTop  > 0 ? nTop-1  : 0);
3446 
3447     /*
3448      *  decorations are not symmetric,
3449      *  so need real geometries here
3450      *  (this will fail with virtual roots ?)
3451      */
3452 
3453     // reset error occurred
3454     GetGenericUnixSalData()->ErrorTrapPop();
3455     GetGenericUnixSalData()->ErrorTrapPush();
3456 
3457     int xp, yp, x, y;
3458     unsigned int wp, w, hp, h, bw, d;
3459     XGetGeometry( GetXDisplay(),
3460                   GetShellWindow(),
3461                   &hRoot,
3462                   &x, &y, &w, &h, &bw, &d );
3463     XGetGeometry( GetXDisplay(),
3464                   hWM_Parent,
3465                   &hRoot,
3466                   &xp, &yp, &wp, &hp, &bw, &d );
3467     bool bResized = false;
3468     bool bError = GetGenericUnixSalData()->ErrorTrapPop( false );
3469     GetGenericUnixSalData()->ErrorTrapPush();
3470 
3471     if( ! bError )
3472     {
3473         maGeometry.setRightDecoration(wp - w - maGeometry.leftDecoration());
3474         maGeometry.setBottomDecoration(hp - h - maGeometry.topDecoration());
3475         bResized = w != o3tl::make_unsigned(maGeometry.width()) ||
3476                    h != o3tl::make_unsigned(maGeometry.height());
3477         /*
3478          *  note: this works because hWM_Parent is direct child of root,
3479          *  not necessarily parent of GetShellWindow()
3480          */
3481         maGeometry.setPosSize({ xp + nLeft, yp + nTop }, { static_cast<tools::Long>(w), static_cast<tools::Long>(h) });
3482     }
3483 
3484     // limit width and height if we are too large: #47757
3485     // olwm and fvwm need this, it doesn't harm the rest
3486 
3487     // #i81311# do this only for sizable frames
3488     if( nStyle_ & SalFrameStyleFlags::SIZEABLE )
3489     {
3490         AbsoluteScreenPixelSize aScreenSize = GetDisplay()->GetScreenSize( m_nXScreen );
3491         int nScreenWidth  = aScreenSize.Width();
3492         int nScreenHeight = aScreenSize.Height();
3493         int nFrameWidth   = maGeometry.width() + maGeometry.leftDecoration() + maGeometry.rightDecoration();
3494         int nFrameHeight  = maGeometry.height() + maGeometry.topDecoration()  + maGeometry.bottomDecoration();
3495 
3496         if ((nFrameWidth > nScreenWidth) || (nFrameHeight > nScreenHeight))
3497         {
3498             Size aSize(maGeometry.width(), maGeometry.height());
3499 
3500             if (nFrameWidth  > nScreenWidth)
3501                 aSize.setWidth( nScreenWidth  - maGeometry.rightDecoration() - maGeometry.leftDecoration() );
3502             if (nFrameHeight > nScreenHeight)
3503                 aSize.setHeight( nScreenHeight - maGeometry.bottomDecoration() - maGeometry.topDecoration() );
3504 
3505             SetSize( aSize );
3506             bResized = false;
3507         }
3508     }
3509     if( bResized )
3510         CallCallback( SalEvent::Resize, nullptr );
3511 
3512     GetGenericUnixSalData()->ErrorTrapPop();
3513 
3514     return true;
3515 }
3516 
HandleStateEvent(XPropertyEvent const * pEvent)3517 bool X11SalFrame::HandleStateEvent( XPropertyEvent const *pEvent )
3518 {
3519     Atom          actual_type;
3520     int           actual_format;
3521     unsigned long nitems, bytes_after;
3522     unsigned char *prop = nullptr;
3523 
3524     if( 0 != XGetWindowProperty( GetXDisplay(),
3525                                  GetShellWindow(),
3526                                  pEvent->atom,          // property
3527                                  0,                     // long_offset (32bit)
3528                                  2,                     // long_length (32bit)
3529                                  False,                 // delete
3530                                  pEvent->atom,          // req_type
3531                                  &actual_type,
3532                                  &actual_format,
3533                                  &nitems,
3534                                  &bytes_after,
3535                                  &prop )
3536         || ! prop
3537         )
3538         return false;
3539 
3540     DBG_ASSERT( actual_type == pEvent->atom
3541                 && 32 == actual_format
3542                 &&  2 == nitems
3543                 &&  0 == bytes_after, "HandleStateEvent" );
3544 
3545     if( *reinterpret_cast<unsigned long*>(prop) == NormalState )
3546         nShowState_ = X11ShowState::Normal;
3547     else if( *reinterpret_cast<unsigned long*>(prop) == IconicState )
3548         nShowState_ = X11ShowState::Minimized;
3549 
3550     XFree( prop );
3551     return true;
3552 }
3553 
HandleClientMessage(XClientMessageEvent * pEvent)3554 bool X11SalFrame::HandleClientMessage( XClientMessageEvent *pEvent )
3555 {
3556     const WMAdaptor& rWMAdaptor( *pDisplay_->getWMAdaptor() );
3557 
3558 #if !defined(__synchronous_extinput__)
3559     if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::SAL_EXTTEXTEVENT ) )
3560     {
3561         HandleExtTextEvent (pEvent);
3562         return true;
3563     }
3564 #endif
3565     else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::SAL_QUITEVENT ) )
3566     {
3567         SAL_WARN( "vcl", "X11SalFrame::Dispatch Quit" );
3568         Close(); // ???
3569         return true;
3570     }
3571     else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::WM_PROTOCOLS ) )
3572     {
3573         if( static_cast<Atom>(pEvent->data.l[0]) == rWMAdaptor.getAtom( WMAdaptor::NET_WM_PING ) )
3574             rWMAdaptor.answerPing( this, pEvent );
3575         else if( ! ( nStyle_ & SalFrameStyleFlags::PLUG )
3576               && ! (( nStyle_ & SalFrameStyleFlags::FLOAT ) && (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION))
3577              )
3578         {
3579             if( static_cast<Atom>(pEvent->data.l[0]) == rWMAdaptor.getAtom( WMAdaptor::WM_DELETE_WINDOW ) )
3580             {
3581                 Close();
3582                 return true;
3583             }
3584             else if( static_cast<Atom>(pEvent->data.l[0]) == rWMAdaptor.getAtom( WMAdaptor::WM_TAKE_FOCUS ) )
3585             {
3586                 // do nothing, we set the input focus in ToTop() if necessary
3587 #if OSL_DEBUG_LEVEL > 1
3588                 SAL_INFO("vcl.window", "got WM_TAKE_FOCUS on "
3589                         << ((nStyle_ &
3590                                 SalFrameStyleFlags::OWNERDRAWDECORATION) ?
3591                             "ownerdraw" :
3592                             "NON OWNERDRAW" )
3593                         << " window.");
3594 #endif
3595             }
3596         }
3597     }
3598     else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::XEMBED ) &&
3599              pEvent->window == GetWindow() )
3600     {
3601         if( pEvent->data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
3602             pEvent->data.l[1] == 2 )  // XEMBED_WINDOW_DEACTIVATE
3603         {
3604             XFocusChangeEvent aEvent;
3605             aEvent.type         = (pEvent->data.l[1] == 1 ? FocusIn : FocusOut);
3606             aEvent.serial       = pEvent->serial;
3607             aEvent.send_event   = True;
3608             aEvent.display      = pEvent->display;
3609             aEvent.window       = pEvent->window;
3610             aEvent.mode         = NotifyNormal;
3611             aEvent.detail       = NotifyDetailNone;
3612             HandleFocusEvent( &aEvent );
3613         }
3614     }
3615     return false;
3616 }
3617 
Dispatch(XEvent * pEvent)3618 bool X11SalFrame::Dispatch( XEvent *pEvent )
3619 {
3620     bool nRet = false;
3621 
3622     if( -1 == nCaptured_ )
3623     {
3624         CaptureMouse( true );
3625 #ifdef DBG_UTIL
3626         if( -1 != nCaptured_ )
3627             pDisplay_->DbgPrintDisplayEvent("Captured", pEvent);
3628 #endif
3629     }
3630 
3631     if( pEvent->xany.window == GetShellWindow() || pEvent->xany.window == GetWindow() )
3632     {
3633         switch( pEvent->type )
3634         {
3635             case KeyPress:
3636                 nRet        = HandleKeyEvent( &pEvent->xkey );
3637                 break;
3638 
3639             case KeyRelease:
3640                 nRet = HandleKeyEvent( &pEvent->xkey );
3641             break;
3642 
3643             case ButtonPress:
3644                 // if we lose the focus in presentation mode
3645                 // there are good chances that we never get it back
3646                 // since the WM ignores us
3647                  if( IsOverrideRedirect() )
3648                  {
3649                      XSetInputFocus( GetXDisplay(), GetShellWindow(),
3650                              RevertToNone, CurrentTime );
3651                  }
3652                 [[fallthrough]];
3653             case ButtonRelease:
3654             case MotionNotify:
3655             case EnterNotify:
3656             case LeaveNotify:
3657                 nRet = HandleMouseEvent( pEvent );
3658                 break;
3659 
3660             case FocusIn:
3661             case FocusOut:
3662                 nRet = HandleFocusEvent( &pEvent->xfocus );
3663                 break;
3664 
3665             case Expose:
3666             case GraphicsExpose:
3667                 nRet = HandleExposeEvent( pEvent );
3668                 break;
3669 
3670             case MapNotify:
3671                 if( pEvent->xmap.window == GetShellWindow() )
3672                 {
3673                     if( nShowState_ == X11ShowState::Hidden )
3674                     {
3675                         /*
3676                          *  workaround for (at least) KWin 2.2.2
3677                          *  which will map windows that were once transient
3678                          *  even if they are withdrawn when the respective
3679                          *  document is mapped.
3680                          */
3681                         if( ! (nStyle_ & SalFrameStyleFlags::PLUG) )
3682                             XUnmapWindow( GetXDisplay(), GetShellWindow() );
3683                         break;
3684                     }
3685                     bMapped_   = true;
3686                     bViewable_ = true;
3687                     nRet = true;
3688                     if ( mpInputContext != nullptr )
3689                         mpInputContext->Map( this );
3690                     CallCallback( SalEvent::Resize, nullptr );
3691 
3692                     bool bSetFocus = m_bSetFocusOnMap;
3693 
3694                     /*
3695                      *  sometimes a message box/dialogue is brought up when a frame is not mapped
3696                      *  the corresponding TRANSIENT_FOR hint is then set to the root window
3697                      *  so that the dialogue shows in all cases. Correct it here if the
3698                      *  frame is shown afterwards.
3699                      */
3700                     if( ! IsChildWindow()
3701                         && ! IsOverrideRedirect()
3702                         && ! IsFloatGrabWindow()
3703                         )
3704                     {
3705                         for (auto const& child : maChildren)
3706                         {
3707                             if( child->mbTransientForRoot )
3708                                 pDisplay_->getWMAdaptor()->changeReferenceFrame( child, this );
3709                         }
3710                     }
3711 
3712                     if( hPresentationWindow != None && GetShellWindow() == hPresentationWindow )
3713                         XSetInputFocus( GetXDisplay(), GetShellWindow(), RevertToParent, CurrentTime );
3714 
3715                     if( bSetFocus )
3716                     {
3717                         XSetInputFocus( GetXDisplay(),
3718                                         GetShellWindow(),
3719                                         RevertToParent,
3720                                         CurrentTime );
3721                     }
3722 
3723                     RestackChildren();
3724                     m_bSetFocusOnMap = false;
3725                 }
3726                 break;
3727 
3728             case UnmapNotify:
3729                 if( pEvent->xunmap.window == GetShellWindow() )
3730                 {
3731                     bMapped_   = false;
3732                     bViewable_ = false;
3733                     nRet = true;
3734                     if ( mpInputContext != nullptr )
3735                         mpInputContext->Unmap();
3736                     CallCallback( SalEvent::Resize, nullptr );
3737                 }
3738                 break;
3739 
3740             case ConfigureNotify:
3741                 if( pEvent->xconfigure.window == GetShellWindow()
3742                     || pEvent->xconfigure.window == GetWindow() )
3743                     nRet = HandleSizeEvent( &pEvent->xconfigure );
3744                 break;
3745 
3746             case VisibilityNotify:
3747                 nVisibility_ = pEvent->xvisibility.state;
3748                 nRet = true;
3749                 if( bAlwaysOnTop_
3750                     && bMapped_
3751                     && ! GetDisplay()->getWMAdaptor()->isAlwaysOnTopOK()
3752                     && nVisibility_ != VisibilityUnobscured )
3753                     maAlwaysOnTopRaiseTimer.Start();
3754             break;
3755 
3756             case ReparentNotify:
3757                 nRet = HandleReparentEvent( &pEvent->xreparent );
3758                 break;
3759 
3760             case MappingNotify:
3761                 break;
3762 
3763             case ColormapNotify:
3764                 nRet = false;
3765                 break;
3766 
3767             case PropertyNotify:
3768             {
3769                 if( pEvent->xproperty.atom == pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_STATE ) )
3770                     nRet = HandleStateEvent( &pEvent->xproperty );
3771                 else
3772                     nRet = pDisplay_->getWMAdaptor()->handlePropertyNotify( this, &pEvent->xproperty );
3773                 break;
3774             }
3775 
3776             case ClientMessage:
3777                 nRet = HandleClientMessage( &pEvent->xclient );
3778                 break;
3779         }
3780     }
3781     else
3782     {
3783         switch( pEvent->type )
3784         {
3785              case FocusIn:
3786              case FocusOut:
3787                 if( ( nStyle_ & SalFrameStyleFlags::PLUG )
3788                     && ( pEvent->xfocus.window == GetShellWindow()
3789                          || pEvent->xfocus.window == GetForeignParent() )
3790                     )
3791                 {
3792                     nRet = HandleFocusEvent( &pEvent->xfocus );
3793                 }
3794                  break;
3795 
3796             case ConfigureNotify:
3797                 if( pEvent->xconfigure.window == GetForeignParent() ||
3798                     pEvent->xconfigure.window == GetShellWindow() )
3799                     nRet = HandleSizeEvent( &pEvent->xconfigure );
3800 
3801                 if( pEvent->xconfigure.window == GetStackingWindow() )
3802                     nRet = HandleSizeEvent( &pEvent->xconfigure );
3803 
3804                 RestackChildren();
3805                 break;
3806         }
3807     }
3808 
3809     return nRet;
3810 }
3811 
ResetClipRegion()3812 void X11SalFrame::ResetClipRegion()
3813 {
3814     m_vClipRectangles.clear();
3815 
3816     const int   dest_kind   = ShapeBounding;
3817     const int   op          = ShapeSet;
3818     const int   ordering    = YSorted;
3819 
3820     XWindowAttributes win_attrib;
3821     XRectangle        win_size;
3822 
3823     ::Window aShapeWindow = mhShellWindow;
3824 
3825     XGetWindowAttributes ( GetDisplay()->GetDisplay(),
3826                            aShapeWindow,
3827                            &win_attrib );
3828 
3829     win_size.x      = 0;
3830     win_size.y      = 0;
3831     win_size.width  = win_attrib.width;
3832     win_size.height = win_attrib.height;
3833 
3834     XShapeCombineRectangles ( GetDisplay()->GetDisplay(),
3835                               aShapeWindow,
3836                               dest_kind,
3837                               0, 0,             // x_off, y_off
3838                               &win_size,        // list of rectangles
3839                               1,                // number of rectangles
3840                               op, ordering );
3841 }
3842 
BeginSetClipRegion(sal_uInt32)3843 void X11SalFrame::BeginSetClipRegion( sal_uInt32 /*nRects*/ )
3844 {
3845     m_vClipRectangles.clear();
3846 }
3847 
UnionClipRegion(tools::Long nX,tools::Long nY,tools::Long nWidth,tools::Long nHeight)3848 void X11SalFrame::UnionClipRegion( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
3849 {
3850     m_vClipRectangles.emplace_back( XRectangle { static_cast<short>(nX), static_cast<short>(nY),
3851                                                  static_cast<unsigned short>(nWidth), static_cast<unsigned short>(nHeight) } );
3852 }
3853 
EndSetClipRegion()3854 void X11SalFrame::EndSetClipRegion()
3855 {
3856     const int   dest_kind   = ShapeBounding;
3857     const int   ordering    = YSorted;
3858     const int   op = ShapeSet;
3859 
3860     ::Window aShapeWindow = mhShellWindow;
3861     XShapeCombineRectangles ( GetDisplay()->GetDisplay(),
3862                               aShapeWindow,
3863                               dest_kind,
3864                               0, 0, // x_off, y_off
3865                               m_vClipRectangles.data(),
3866                               m_vClipRectangles.size(),
3867                               op, ordering );
3868 
3869 }
3870 
3871 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3872