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