nss: upgrade to release 3.73
[LibreOffice.git] / vcl / unx / generic / window / salframe.cxx
blob1b54b43419d77c857e13b2fd0cd96807be931c0f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <string.h>
21 #include <string_view>
22 #include <stdio.h>
23 #include <stdlib.h>
25 #include <tools/debug.hxx>
27 #include <vcl/event.hxx>
28 #include <vcl/floatwin.hxx>
29 #include <vcl/keycodes.hxx>
30 #include <vcl/settings.hxx>
31 #include <vcl/bitmapaccess.hxx>
32 #include <vcl/opengl/OpenGLContext.hxx>
33 #include <vcl/BitmapTools.hxx>
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>
41 #include <saldatabasic.hxx>
42 #include <unx/saldisp.hxx>
43 #include <unx/salgdi.h>
44 #include <unx/salframe.h>
45 #include <unx/wmadaptor.hxx>
46 #include <unx/salbmp.h>
47 #include <unx/i18n_ic.hxx>
48 #include <unx/i18n_keysym.hxx>
49 #include <opengl/zone.hxx>
51 #include <unx/gensys.h>
52 #include <window.h>
54 #include <sal/macros.h>
55 #include <sal/log.hxx>
56 #include <com/sun/star/uno/Exception.hpp>
58 #include <svdata.hxx>
59 #include <bitmaps.hlst>
61 #include <optional>
63 #include <algorithm>
65 #ifndef Button6
66 # define Button6 6
67 #endif
68 #ifndef Button7
69 # define Button7 7
70 #endif
72 using namespace vcl_sal;
74 constexpr auto CLIENT_EVENTS = StructureNotifyMask
75 | SubstructureNotifyMask
76 | KeyPressMask
77 | KeyReleaseMask
78 | ButtonPressMask
79 | ButtonReleaseMask
80 | PointerMotionMask
81 | EnterWindowMask
82 | LeaveWindowMask
83 | FocusChangeMask
84 | ExposureMask
85 | VisibilityChangeMask
86 | PropertyChangeMask
87 | ColormapChangeMask;
89 static ::Window hPresentationWindow = None, hPresFocusWindow = None;
90 static ::std::list< ::Window > aPresentationReparentList;
91 static int nVisibleFloats = 0;
93 static void doReparentPresentationDialogues( SalDisplay const * pDisplay )
95 GetGenericUnixSalData()->ErrorTrapPush();
96 for (auto const& elem : aPresentationReparentList)
98 int x, y;
99 ::Window aRoot, aChild;
100 unsigned int w, h, bw, d;
101 XGetGeometry( pDisplay->GetDisplay(),
102 elem,
103 &aRoot,
104 &x, &y, &w, &h, &bw, &d );
105 XTranslateCoordinates( pDisplay->GetDisplay(),
106 hPresentationWindow,
107 aRoot,
108 x, y,
109 &x, &y,
110 &aChild );
111 XReparentWindow( pDisplay->GetDisplay(),
112 elem,
113 aRoot,
114 x, y );
116 aPresentationReparentList.clear();
117 if( hPresFocusWindow )
118 XSetInputFocus( pDisplay->GetDisplay(), hPresFocusWindow, PointerRoot, CurrentTime );
119 XSync( pDisplay->GetDisplay(), False );
120 GetGenericUnixSalData()->ErrorTrapPop();
123 bool X11SalFrame::IsOverrideRedirect() const
125 return
126 ((nStyle_ & SalFrameStyleFlags::INTRO) && !pDisplay_->getWMAdaptor()->supportsSplash())
128 (!( nStyle_ & ~SalFrameStyleFlags::DEFAULT ) && !pDisplay_->getWMAdaptor()->supportsFullScreen())
132 bool X11SalFrame::IsFloatGrabWindow() const
134 static const char* pDisableGrab = getenv( "SAL_DISABLE_FLOATGRAB" );
136 return
137 ( ( !pDisableGrab || !*pDisableGrab ) &&
139 (nStyle_ & SalFrameStyleFlags::FLOAT) &&
140 ! (nStyle_ & SalFrameStyleFlags::TOOLTIP) &&
141 ! (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION)
146 void X11SalFrame::setXEmbedInfo()
148 if( !m_bXEmbed )
149 return;
151 tools::Long aInfo[2];
152 aInfo[0] = 1; // XEMBED protocol version
153 aInfo[1] = (bMapped_ ? 1 : 0); // XEMBED_MAPPED
154 XChangeProperty( pDisplay_->GetDisplay(),
155 mhWindow,
156 pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO ),
157 pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO ),
159 PropModeReplace,
160 reinterpret_cast<unsigned char*>(aInfo),
161 SAL_N_ELEMENTS(aInfo) );
164 void X11SalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
166 XEvent aEvent;
168 memset( &aEvent, 0, sizeof(aEvent) );
169 aEvent.xclient.window = mhForeignParent;
170 aEvent.xclient.type = ClientMessage;
171 aEvent.xclient.message_type = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED );
172 aEvent.xclient.format = 32;
173 aEvent.xclient.data.l[0] = i_nTimeCode ? i_nTimeCode : CurrentTime;
174 aEvent.xclient.data.l[1] = 3; // XEMBED_REQUEST_FOCUS
175 aEvent.xclient.data.l[2] = 0;
176 aEvent.xclient.data.l[3] = 0;
177 aEvent.xclient.data.l[4] = 0;
179 GetGenericUnixSalData()->ErrorTrapPush();
180 XSendEvent( pDisplay_->GetDisplay(),
181 mhForeignParent,
182 False, NoEventMask, &aEvent );
183 XSync( pDisplay_->GetDisplay(), False );
184 GetGenericUnixSalData()->ErrorTrapPop();
187 typedef std::vector< unsigned long > NetWmIconData;
189 namespace
191 const std::u16string_view SV_ICON_SIZE48[] =
193 u"" MAINAPP_48_8,
194 u"" MAINAPP_48_8,
195 u"" ODT_48_8,
196 u"" OTT_48_8,
197 u"" ODS_48_8,
198 u"" OTS_48_8,
199 u"" ODG_48_8,
200 u"" MAINAPP_48_8,
201 u"" ODP_48_8,
202 u"" MAINAPP_48_8,
203 u"" ODM_48_8,
204 u"" MAINAPP_48_8,
205 u"" ODB_48_8,
206 u"" ODF_48_8
209 const std::u16string_view SV_ICON_SIZE32[] =
211 u"" MAINAPP_32_8,
212 u"" MAINAPP_32_8,
213 u"" ODT_32_8,
214 u"" OTT_32_8,
215 u"" ODS_32_8,
216 u"" OTS_32_8,
217 u"" ODG_32_8,
218 u"" MAINAPP_32_8,
219 u"" ODP_32_8,
220 u"" MAINAPP_32_8,
221 u"" ODM_32_8,
222 u"" MAINAPP_32_8,
223 u"" ODB_32_8,
224 u"" ODF_32_8
227 const std::u16string_view SV_ICON_SIZE16[] =
229 u"" MAINAPP_16_8,
230 u"" MAINAPP_16_8,
231 u"" ODT_16_8,
232 u"" OTT_16_8,
233 u"" ODS_16_8,
234 u"" OTS_16_8,
235 u"" ODG_16_8,
236 u"" MAINAPP_16_8,
237 u"" ODP_16_8,
238 u"" MAINAPP_16_8,
239 u"" ODM_16_8,
240 u"" MAINAPP_16_8,
241 u"" ODB_16_8,
242 u"" ODF_16_8
246 static void CreateNetWmAppIcon( sal_uInt16 nIcon, NetWmIconData& netwm_icon )
248 const int sizes[ 3 ] = { 48, 32, 16 };
249 netwm_icon.resize( 48 * 48 + 32 * 32 + 16 * 16 + 3 * 2 );
250 int pos = 0;
251 for(int size : sizes)
253 OUString sIcon;
254 if( size >= 48 )
255 sIcon = SV_ICON_SIZE48[nIcon];
256 else if( size >= 32 )
257 sIcon = SV_ICON_SIZE32[nIcon];
258 else
259 sIcon = SV_ICON_SIZE16[nIcon];
261 BitmapEx aIcon = vcl::bitmap::loadFromName(sIcon, ImageLoadFlags::IgnoreScalingFactor);
263 if( aIcon.IsEmpty())
264 continue;
265 vcl::bitmap::convertBitmap32To24Plus8(aIcon, aIcon);
266 Bitmap icon = aIcon.GetBitmap();
267 AlphaMask mask;
268 switch( aIcon.GetTransparentType())
270 case TransparentType::NONE:
272 sal_uInt8 nTrans = 0;
273 mask = AlphaMask( icon.GetSizePixel(), &nTrans );
275 break;
276 case TransparentType::Color:
277 mask = AlphaMask( icon.CreateMask( aIcon.GetTransparentColor() ) );
278 break;
279 case TransparentType::Bitmap:
280 mask = aIcon.GetAlpha();
281 break;
283 BitmapReadAccess* iconData = icon.AcquireReadAccess();
284 BitmapReadAccess* maskData = mask.AcquireReadAccess();
285 netwm_icon[ pos++ ] = size; // width
286 netwm_icon[ pos++ ] = size; // height
287 for( int y = 0; y < size; ++y )
288 for( int x = 0; x < size; ++x )
290 BitmapColor col = iconData->GetColor( y, x );
291 BitmapColor alpha = maskData->GetColor( y, x );
292 netwm_icon[ pos++ ] = (((( 255 - alpha.GetBlue()) * 256U ) + col.GetRed()) * 256 + col.GetGreen()) * 256 + col.GetBlue();
294 Bitmap::ReleaseAccess( iconData );
295 mask.ReleaseAccess( maskData );
297 netwm_icon.resize( pos );
300 static bool lcl_SelectAppIconPixmap( SalDisplay const *pDisplay, SalX11Screen nXScreen,
301 sal_uInt16 nIcon, sal_uInt16 iconSize,
302 Pixmap& icon_pixmap, Pixmap& icon_mask, NetWmIconData& netwm_icon)
304 PreDefaultWinNoOpenGLZone aGuard;
306 CreateNetWmAppIcon( nIcon, netwm_icon );
308 OUString sIcon;
310 if( iconSize >= 48 )
311 sIcon = SV_ICON_SIZE48[nIcon];
312 else if( iconSize >= 32 )
313 sIcon = SV_ICON_SIZE32[nIcon];
314 else if( iconSize >= 16 )
315 sIcon = SV_ICON_SIZE16[nIcon];
316 else
317 return false;
319 BitmapEx aIcon = vcl::bitmap::loadFromName(sIcon, ImageLoadFlags::IgnoreScalingFactor);
321 if( aIcon.IsEmpty() )
322 return false;
324 X11SalBitmap *pBitmap = dynamic_cast < X11SalBitmap * >
325 (aIcon.ImplGetBitmapSalBitmap().get());
326 if (!pBitmap) // FIXME: opengl , TODO SKIA
327 return false;
329 icon_pixmap = XCreatePixmap( pDisplay->GetDisplay(),
330 pDisplay->GetRootWindow( nXScreen ),
331 iconSize, iconSize,
332 DefaultDepth( pDisplay->GetDisplay(),
333 nXScreen.getXScreen() )
336 SalTwoRect aRect(0, 0, iconSize, iconSize, 0, 0, iconSize, iconSize);
338 pBitmap->ImplDraw( icon_pixmap,
339 nXScreen,
340 DefaultDepth( pDisplay->GetDisplay(),
341 nXScreen.getXScreen() ),
342 aRect,
343 DefaultGC( pDisplay->GetDisplay(),
344 nXScreen.getXScreen() ) );
346 icon_mask = None;
348 if( TransparentType::Bitmap == aIcon.GetTransparentType() )
350 icon_mask = XCreatePixmap( pDisplay->GetDisplay(),
351 pDisplay->GetRootWindow( pDisplay->GetDefaultXScreen() ),
352 iconSize, iconSize, 1);
354 XGCValues aValues;
355 aValues.foreground = 0xffffffff;
356 aValues.background = 0;
357 aValues.function = GXcopy;
358 GC aMonoGC = XCreateGC( pDisplay->GetDisplay(), icon_mask,
359 GCFunction|GCForeground|GCBackground, &aValues );
361 Bitmap aMask = aIcon.GetMask();
362 aMask.Invert();
364 X11SalBitmap *pMask = static_cast < X11SalBitmap * >
365 (aMask.ImplGetSalBitmap().get());
367 pMask->ImplDraw(icon_mask, nXScreen, 1, aRect, aMonoGC);
368 XFreeGC( pDisplay->GetDisplay(), aMonoGC );
371 return true;
374 void X11SalFrame::Init( SalFrameStyleFlags nSalFrameStyle, SalX11Screen nXScreen, SystemParentData const * pParentData, bool bUseGeometry )
376 if( nXScreen.getXScreen() >= GetDisplay()->GetXScreenCount() )
377 nXScreen = GetDisplay()->GetDefaultXScreen();
378 if( mpParent )
379 nXScreen = mpParent->m_nXScreen;
381 m_nXScreen = nXScreen;
382 nStyle_ = nSalFrameStyle;
383 XWMHints Hints;
384 Hints.flags = InputHint;
385 Hints.input = (nSalFrameStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) ? False : True;
386 NetWmIconData netwm_icon;
388 int x = 0, y = 0;
389 unsigned int w = 500, h = 500;
390 XSetWindowAttributes Attributes;
392 int nAttrMask = CWBorderPixel
393 | CWBackPixmap
394 | CWColormap
395 | CWOverrideRedirect
396 | CWEventMask
398 Attributes.border_pixel = 0;
399 Attributes.background_pixmap = None;
400 Attributes.colormap = GetDisplay()->GetColormap( m_nXScreen ).GetXColormap();
401 Attributes.override_redirect = False;
402 Attributes.event_mask = CLIENT_EVENTS;
404 const SalVisual& rVis = GetDisplay()->GetVisual( m_nXScreen );
405 ::Window aFrameParent = pParentData ? pParentData->aWindow : GetDisplay()->GetRootWindow( m_nXScreen );
406 ::Window aClientLeader = None;
408 if( bUseGeometry )
410 x = maGeometry.nX;
411 y = maGeometry.nY;
412 w = maGeometry.nWidth;
413 h = maGeometry.nHeight;
416 if( (nSalFrameStyle & SalFrameStyleFlags::FLOAT) &&
417 ! (nSalFrameStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)
420 if( nShowState_ == SHOWSTATE_UNKNOWN )
422 w = 10;
423 h = 10;
425 Attributes.override_redirect = True;
427 else if( nSalFrameStyle & SalFrameStyleFlags::SYSTEMCHILD )
429 SAL_WARN_IF( !mpParent, "vcl", "SalFrameStyleFlags::SYSTEMCHILD window without parent" );
430 if( mpParent )
432 aFrameParent = mpParent->mhWindow;
433 // FIXME: since with SalFrameStyleFlags::SYSTEMCHILD
434 // multiple X11SalFrame objects can have the same shell window
435 // dispatching events in saldisp.cxx is unclear (the first frame)
436 // wins. HTH this correctly is unclear yet
437 // for the time being, treat set the shell window to own window
438 // like for a normal frame
439 // mhShellWindow = mpParent->GetShellWindow();
442 else if( pParentData )
444 // plugin parent may be killed unexpectedly by plugging
445 // process; start permanently ignoring X errors...
446 GetGenericUnixSalData()->ErrorTrapPush();
448 nStyle_ |= SalFrameStyleFlags::PLUG;
449 Attributes.override_redirect = True;
450 if( pParentData->nSize >= sizeof(SystemParentData) )
451 m_bXEmbed = pParentData->bXEmbedSupport;
453 int x_ret, y_ret;
454 unsigned int bw, d;
455 ::Window aRoot, aParent;
457 XGetGeometry( GetXDisplay(), pParentData->aWindow,
458 &aRoot, &x_ret, &y_ret, &w, &h, &bw, &d );
459 mhForeignParent = pParentData->aWindow;
461 mhShellWindow = aParent = mhForeignParent;
462 ::Window* pChildren;
463 unsigned int nChildren;
464 bool bBreak = false;
467 XQueryTree( GetDisplay()->GetDisplay(), mhShellWindow,
468 &aRoot, &aParent, &pChildren, &nChildren );
469 XFree( pChildren );
470 if( aParent != aRoot )
471 mhShellWindow = aParent;
472 int nCount = 0;
473 Atom* pProps = XListProperties( GetDisplay()->GetDisplay(),
474 mhShellWindow,
475 &nCount );
476 for( int i = 0; i < nCount && ! bBreak; ++i )
477 bBreak = (pProps[i] == XA_WM_HINTS);
478 if( pProps )
479 XFree( pProps );
480 } while( aParent != aRoot && ! bBreak );
482 // check if this is really one of our own frames
483 // do not change the input mask in that case
484 bool bIsReallyOurFrame = false;
485 for (auto pSalFrame : GetDisplay()->getFrames() )
486 if ( static_cast<const X11SalFrame*>( pSalFrame )->GetWindow() == mhForeignParent )
488 bIsReallyOurFrame = true;
489 break;
491 if (!bIsReallyOurFrame)
493 XSelectInput( GetDisplay()->GetDisplay(), mhForeignParent, StructureNotifyMask | FocusChangeMask );
494 XSelectInput( GetDisplay()->GetDisplay(), mhShellWindow, StructureNotifyMask | FocusChangeMask );
497 else
499 if( ! bUseGeometry )
501 Size aScreenSize( GetDisplay()->getDataForScreen( m_nXScreen ).m_aSize );
502 w = aScreenSize.Width();
503 h = aScreenSize.Height();
504 if( nSalFrameStyle & SalFrameStyleFlags::SIZEABLE &&
505 nSalFrameStyle & SalFrameStyleFlags::MOVEABLE )
507 Size aBestFitSize(bestmaxFrameSizeForScreenSize(aScreenSize));
508 w = aBestFitSize.Width();
509 h = aBestFitSize.Height();
511 if( ! mpParent )
513 // find the last document window (if any)
514 const X11SalFrame* pFrame = nullptr;
515 bool bIsDocumentWindow = false;
516 for (auto pSalFrame : GetDisplay()->getFrames() )
518 pFrame = static_cast< const X11SalFrame* >( pSalFrame );
519 if( !pFrame->mpParent
520 && !pFrame->mbFullScreen
521 && ( pFrame->nStyle_ & SalFrameStyleFlags::SIZEABLE )
522 && pFrame->GetUnmirroredGeometry().nWidth
523 && pFrame->GetUnmirroredGeometry().nHeight )
525 bIsDocumentWindow = true;
526 break;
530 if( bIsDocumentWindow )
532 // set a document position and size
533 // the first frame gets positioned by the window manager
534 const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
535 x = rGeom.nX;
536 y = rGeom.nY;
537 if( x+static_cast<int>(w)+40 <= static_cast<int>(aScreenSize.Width()) &&
538 y+static_cast<int>(h)+40 <= static_cast<int>(aScreenSize.Height())
541 y += 40;
542 x += 40;
544 else
546 x = 10; // leave some space for decoration
547 y = 20;
550 else if( GetDisplay()->IsXinerama() )
552 // place frame on same screen as mouse pointer
553 ::Window aRoot, aChild;
554 int root_x = 0, root_y = 0, lx, ly;
555 unsigned int mask;
556 XQueryPointer( GetXDisplay(),
557 GetDisplay()->GetRootWindow( m_nXScreen ),
558 &aRoot, &aChild,
559 &root_x, &root_y, &lx, &ly, &mask );
560 const std::vector< tools::Rectangle >& rScreens = GetDisplay()->GetXineramaScreens();
561 for(const auto & rScreen : rScreens)
562 if( rScreen.IsInside( Point( root_x, root_y ) ) )
564 x = rScreen.Left();
565 y = rScreen.Top();
566 break;
571 Attributes.win_gravity = pDisplay_->getWMAdaptor()->getInitWinGravity();
572 nAttrMask |= CWWinGravity;
573 if( mpParent )
575 Attributes.save_under = True;
576 nAttrMask |= CWSaveUnder;
578 if( IsOverrideRedirect() )
579 Attributes.override_redirect = True;
580 // default icon
581 if( !(nStyle_ & SalFrameStyleFlags::INTRO) )
583 bool bOk=false;
586 bOk = lcl_SelectAppIconPixmap( pDisplay_, m_nXScreen,
587 mnIconID != SV_ICON_ID_OFFICE ? mnIconID :
588 (mpParent ? mpParent->mnIconID : SV_ICON_ID_OFFICE), 32,
589 Hints.icon_pixmap, Hints.icon_mask, netwm_icon );
591 catch( css::uno::Exception& )
593 // can happen - no ucb during early startup
595 if( bOk )
597 Hints.flags |= IconPixmapHint;
598 if( Hints.icon_mask )
599 Hints.flags |= IconMaskHint;
603 // find the top level frame of the transience hierarchy
604 X11SalFrame* pFrame = this;
605 while( pFrame->mpParent )
606 pFrame = pFrame->mpParent;
607 if( pFrame->nStyle_ & SalFrameStyleFlags::PLUG )
609 // if the top level window is a plugin window,
610 // then we should place us in the same window group as
611 // the parent application (or none if there is no window group
612 // hint in the parent).
613 if( pFrame->GetShellWindow() )
615 XWMHints* pWMHints = XGetWMHints( pDisplay_->GetDisplay(),
616 pFrame->GetShellWindow() );
617 if( pWMHints )
619 if( pWMHints->flags & WindowGroupHint )
621 Hints.flags |= WindowGroupHint;
622 Hints.window_group = pWMHints->window_group;
624 XFree( pWMHints );
628 else
630 Hints.flags |= WindowGroupHint;
631 Hints.window_group = pFrame->GetShellWindow();
632 // note: for a normal document window this will produce None
633 // as the window is not yet created and the shell window is
634 // initialized to None. This must be corrected after window creation.
635 aClientLeader = GetDisplay()->GetDrawable( m_nXScreen );
639 nShowState_ = SHOWSTATE_UNKNOWN;
640 bViewable_ = true;
641 bMapped_ = false;
642 nVisibility_ = VisibilityFullyObscured;
643 mhWindow = XCreateWindow( GetXDisplay(),
644 aFrameParent,
645 x, y,
646 w, h,
648 rVis.GetDepth(),
649 InputOutput,
650 rVis.GetVisual(),
651 nAttrMask,
652 &Attributes );
653 // FIXME: see above: fake shell window for now to own window
654 if( pParentData == nullptr )
656 mhShellWindow = mhWindow;
659 // correct window group if necessary
660 if( (Hints.flags & WindowGroupHint) == WindowGroupHint )
662 if( Hints.window_group == None )
663 Hints.window_group = GetShellWindow();
666 maGeometry.nX = x;
667 maGeometry.nY = y;
668 maGeometry.nWidth = w;
669 maGeometry.nHeight = h;
670 updateScreenNumber();
672 XSync( GetXDisplay(), False );
673 setXEmbedInfo();
675 Time nUserTime = (nStyle_ & (SalFrameStyleFlags::OWNERDRAWDECORATION | SalFrameStyleFlags::TOOLWINDOW) ) == SalFrameStyleFlags::NONE ?
676 pDisplay_->GetLastUserEventTime() : 0;
677 pDisplay_->getWMAdaptor()->setUserTime( this, nUserTime );
679 if( ! pParentData && ! IsChildWindow() && ! Attributes.override_redirect )
681 XSetWMHints( GetXDisplay(), mhWindow, &Hints );
682 // WM Protocols && internals
683 Atom a[3];
684 int n = 0;
685 a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_DELETE_WINDOW );
687 // LibreOffice advertises NET_WM_PING atom, so mutter rightfully warns of an unresponsive application during debugging.
688 // Hack that out unconditionally for debug builds, as per https://bugzilla.redhat.com/show_bug.cgi?id=981149
689 // upstream refuses to make this configurable in any way.
690 // NOTE: You need to use the 'gen' backend for this to work (SAL_USE_VCLPLUGIN=gen)
691 #if OSL_DEBUG_LEVEL < 1
692 if( pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING ) )
693 a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING );
694 #endif
696 if( nSalFrameStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
697 a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_TAKE_FOCUS );
698 XSetWMProtocols( GetXDisplay(), GetShellWindow(), a, n );
700 // force wm class hint
701 mnExtStyle = ~0;
702 if (mpParent)
703 m_sWMClass = mpParent->m_sWMClass;
704 SetExtendedFrameStyle( 0 );
706 XSizeHints* pHints = XAllocSizeHints();
707 pHints->flags = PWinGravity | PPosition;
708 pHints->win_gravity = GetDisplay()->getWMAdaptor()->getPositionWinGravity();
709 pHints->x = 0;
710 pHints->y = 0;
711 if( mbFullScreen )
713 pHints->flags |= PMaxSize | PMinSize;
714 pHints->max_width = w+100;
715 pHints->max_height = h+100;
716 pHints->min_width = w;
717 pHints->min_height = h;
719 XSetWMNormalHints( GetXDisplay(),
720 GetShellWindow(),
721 pHints );
722 XFree (pHints);
724 // set PID and WM_CLIENT_MACHINE
725 pDisplay_->getWMAdaptor()->setClientMachine( this );
726 pDisplay_->getWMAdaptor()->setPID( this );
728 // set client leader
729 if( aClientLeader )
731 XChangeProperty( GetXDisplay(),
732 mhWindow,
733 pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_CLIENT_LEADER),
734 XA_WINDOW,
736 PropModeReplace,
737 reinterpret_cast<unsigned char*>(&aClientLeader),
741 #define DECOFLAGS (SalFrameStyleFlags::MOVEABLE | SalFrameStyleFlags::SIZEABLE | SalFrameStyleFlags::CLOSEABLE)
742 int nDecoFlags = WMAdaptor::decoration_All;
743 if( (nStyle_ & SalFrameStyleFlags::PARTIAL_FULLSCREEN) ||
744 (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION)
746 nDecoFlags = 0;
747 else if( (nStyle_ & DECOFLAGS ) != DECOFLAGS || (nStyle_ & SalFrameStyleFlags::TOOLWINDOW) )
749 if( nStyle_ & DECOFLAGS )
750 // if any decoration, then show a border
751 nDecoFlags = WMAdaptor::decoration_Border;
752 else
753 nDecoFlags = 0;
755 if( ! mpParent && (nStyle_ & DECOFLAGS) )
756 // don't add a min button if window should be decorationless
757 nDecoFlags |= WMAdaptor::decoration_MinimizeBtn;
758 if( nStyle_ & SalFrameStyleFlags::CLOSEABLE )
759 nDecoFlags |= WMAdaptor::decoration_CloseBtn;
760 if( nStyle_ & SalFrameStyleFlags::SIZEABLE )
762 nDecoFlags |= WMAdaptor::decoration_Resize;
763 if( ! (nStyle_ & SalFrameStyleFlags::TOOLWINDOW) )
764 nDecoFlags |= WMAdaptor::decoration_MaximizeBtn;
766 if( nStyle_ & SalFrameStyleFlags::MOVEABLE )
767 nDecoFlags |= WMAdaptor::decoration_Title;
770 WMWindowType eType = WMWindowType::Normal;
771 if( nStyle_ & SalFrameStyleFlags::INTRO )
772 eType = WMWindowType::Splash;
773 if( (nStyle_ & SalFrameStyleFlags::DIALOG) && hPresentationWindow == None )
774 eType = WMWindowType::ModelessDialogue;
775 if( nStyle_ & SalFrameStyleFlags::TOOLWINDOW )
776 eType = WMWindowType::Utility;
777 if( nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION )
778 eType = WMWindowType::Toolbar;
779 if( (nStyle_ & SalFrameStyleFlags::PARTIAL_FULLSCREEN)
780 && GetDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
781 eType = WMWindowType::Dock;
783 GetDisplay()->getWMAdaptor()->
784 setFrameTypeAndDecoration( this,
785 eType,
786 nDecoFlags,
787 hPresentationWindow ? nullptr : mpParent );
789 if( (nStyle_ & (SalFrameStyleFlags::DEFAULT |
790 SalFrameStyleFlags::OWNERDRAWDECORATION|
791 SalFrameStyleFlags::FLOAT |
792 SalFrameStyleFlags::INTRO |
793 SalFrameStyleFlags::PARTIAL_FULLSCREEN) )
794 == SalFrameStyleFlags::DEFAULT )
795 pDisplay_->getWMAdaptor()->maximizeFrame( this );
797 if( !netwm_icon.empty() && GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_ICON ))
798 XChangeProperty( GetXDisplay(), mhWindow,
799 GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_ICON ),
800 XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<unsigned char*>(netwm_icon.data()), netwm_icon.size());
803 m_nWorkArea = GetDisplay()->getWMAdaptor()->getCurrentWorkArea();
805 // Pointer
806 SetPointer( PointerStyle::Arrow );
809 X11SalFrame::X11SalFrame( SalFrame *pParent, SalFrameStyleFlags nSalFrameStyle,
810 SystemParentData const * pSystemParent ) :
811 m_nXScreen( 0 )
813 GenericUnixSalData *pData = GetGenericUnixSalData();
815 mpParent = static_cast< X11SalFrame* >( pParent );
817 mbTransientForRoot = false;
819 pDisplay_ = vcl_sal::getSalDisplay(pData);
820 // insert frame in framelist
821 pDisplay_->registerFrame( this );
823 mhWindow = None;
824 mhShellWindow = None;
825 mhStackingWindow = None;
826 mhForeignParent = None;
827 m_bSetFocusOnMap = false;
829 pGraphics_ = nullptr;
830 pFreeGraphics_ = nullptr;
832 hCursor_ = None;
833 nCaptured_ = 0;
835 mbSendExtKeyModChange = false;
836 mnExtKeyMod = ModKeyFlags::NONE;
838 nShowState_ = SHOWSTATE_UNKNOWN;
839 nWidth_ = 0;
840 nHeight_ = 0;
841 nStyle_ = SalFrameStyleFlags::NONE;
842 mnExtStyle = 0;
843 bAlwaysOnTop_ = false;
845 // set bViewable_ to true: hack GetClientSize to report something
846 // different to 0/0 before first map
847 bViewable_ = true;
848 bMapped_ = false;
849 bDefaultPosition_ = true;
850 nVisibility_ = VisibilityFullyObscured;
851 m_nWorkArea = 0;
852 m_bXEmbed = false;
855 mpInputContext = nullptr;
856 mbInputFocus = False;
858 maAlwaysOnTopRaiseTimer.SetInvokeHandler( LINK( this, X11SalFrame, HandleAlwaysOnTopRaise ) );
859 maAlwaysOnTopRaiseTimer.SetTimeout( 100 );
860 maAlwaysOnTopRaiseTimer.SetDebugName( "vcl::X11SalFrame maAlwaysOnTopRaiseTimer" );
862 meWindowType = WMWindowType::Normal;
863 mbMaximizedVert = false;
864 mbMaximizedHorz = false;
865 mbShaded = false;
866 mbFullScreen = false;
868 mnIconID = SV_ICON_ID_OFFICE;
870 if( mpParent )
871 mpParent->maChildren.push_back( this );
873 Init( nSalFrameStyle, GetDisplay()->GetDefaultXScreen(), pSystemParent );
876 X11SalFrame::~X11SalFrame()
878 notifyDelete();
880 m_vClipRectangles.clear();
882 if( mhStackingWindow )
883 aPresentationReparentList.remove( mhStackingWindow );
885 // remove from parent's list
886 if( mpParent )
887 mpParent->maChildren.remove( this );
889 // deregister on SalDisplay
890 pDisplay_->deregisterFrame( this );
892 // unselect all events, some may be still in the queue anyway
893 if( ! IsSysChildWindow() )
894 XSelectInput( GetXDisplay(), GetShellWindow(), 0 );
895 XSelectInput( GetXDisplay(), GetWindow(), 0 );
897 ShowFullScreen( false, 0 );
899 if( bMapped_ )
900 Show( false );
902 if( mpInputContext )
904 mpInputContext->UnsetICFocus();
905 mpInputContext->Unmap();
906 mpInputContext.reset();
909 if( GetWindow() == hPresentationWindow )
911 hPresentationWindow = None;
912 doReparentPresentationDialogues( GetDisplay() );
915 if( pGraphics_ )
917 pGraphics_->DeInit();
918 pGraphics_.reset();
921 if( pFreeGraphics_ )
923 pFreeGraphics_->DeInit();
924 pFreeGraphics_.reset();
927 // reset all OpenGL contexts using this window
928 rtl::Reference<OpenGLContext> pContext = ImplGetSVData()->maGDIData.mpLastContext;
929 while( pContext.is() )
931 if (static_cast<const GLX11Window&>(pContext->getOpenGLWindow()).win == mhWindow)
932 pContext->reset();
933 pContext = pContext->mpPrevContext;
936 XDestroyWindow( GetXDisplay(), mhWindow );
939 void X11SalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
941 if( nStyle != mnExtStyle && ! IsChildWindow() )
943 mnExtStyle = nStyle;
944 updateWMClass();
948 const SystemEnvData* X11SalFrame::GetSystemData() const
950 X11SalFrame *pFrame = const_cast<X11SalFrame*>(this);
951 pFrame->maSystemChildData.pDisplay = GetXDisplay();
952 pFrame->maSystemChildData.SetWindowHandle(pFrame->GetWindow());
953 pFrame->maSystemChildData.pSalFrame = pFrame;
954 pFrame->maSystemChildData.pWidget = nullptr;
955 pFrame->maSystemChildData.pVisual = GetDisplay()->GetVisual( m_nXScreen ).GetVisual();
956 pFrame->maSystemChildData.nScreen = m_nXScreen.getXScreen();
957 pFrame->maSystemChildData.aShellWindow = pFrame->GetShellWindow();
958 pFrame->maSystemChildData.toolkit = SystemEnvData::Toolkit::Gen;
959 pFrame->maSystemChildData.platform = SystemEnvData::Platform::Xcb;
960 return &maSystemChildData;
963 SalGraphics *X11SalFrame::AcquireGraphics()
965 if( pGraphics_ )
966 return nullptr;
968 if( pFreeGraphics_ )
970 pGraphics_ = std::move(pFreeGraphics_);
972 else
974 pGraphics_.reset(new X11SalGraphics());
975 pGraphics_->Init( this, GetWindow(), m_nXScreen );
978 return pGraphics_.get();
981 void X11SalFrame::ReleaseGraphics( SalGraphics *pGraphics )
983 SAL_WARN_IF( pGraphics != pGraphics_.get(), "vcl", "SalFrame::ReleaseGraphics pGraphics!=pGraphics_" );
985 if( pGraphics != pGraphics_.get() )
986 return;
988 pFreeGraphics_ = std::move(pGraphics_);
991 void X11SalFrame::updateGraphics( bool bClear )
993 Drawable aDrawable = bClear ? None : GetWindow();
994 if( pGraphics_ )
995 pGraphics_->SetDrawable( aDrawable, nullptr, m_nXScreen );
996 if( pFreeGraphics_ )
997 pFreeGraphics_->SetDrawable( aDrawable, nullptr, m_nXScreen );
1000 void X11SalFrame::SetIcon( sal_uInt16 nIcon )
1002 if ( IsChildWindow() )
1003 return;
1005 // 0 == default icon -> #1
1006 if ( nIcon == 0 )
1007 nIcon = 1;
1009 mnIconID = nIcon;
1011 XIconSize *pIconSize = nullptr;
1012 int nSizes = 0;
1013 int iconSize = 32;
1014 if ( XGetIconSizes( GetXDisplay(), GetDisplay()->GetRootWindow( m_nXScreen ), &pIconSize, &nSizes ) )
1016 #if OSL_DEBUG_LEVEL > 1
1017 SAL_INFO("vcl.window", "X11SalFrame::SetIcon(): found "
1018 << nSizes
1019 << " IconSizes:");
1020 #endif
1021 int i;
1022 for( i=0; i<nSizes; i++)
1024 // select largest supported icon
1025 if( pIconSize[i].max_width > iconSize )
1027 iconSize = pIconSize[i].max_width;
1030 #if OSL_DEBUG_LEVEL > 1
1031 SAL_INFO("vcl.window", "min: "
1032 << pIconSize[i].min_width
1033 << ", "
1034 << pIconSize[i].min_height);
1035 SAL_INFO("vcl.window", "max: "
1036 << pIconSize[i].max_width
1037 << ", "
1038 << pIconSize[i].max_height);
1039 SAL_INFO("vcl.window", "inc: "
1040 << pIconSize[i].width_inc
1041 << ", "
1042 << pIconSize[i].height_inc);
1043 #endif
1046 XFree( pIconSize );
1048 else
1050 const OUString& rWM( pDisplay_->getWMAdaptor()->getWindowManagerName() );
1051 if( rWM == "KWin" ) // assume KDE is running
1052 iconSize = 48;
1053 static bool bGnomeIconSize = false;
1054 static bool bGnomeChecked = false;
1055 if( ! bGnomeChecked )
1057 bGnomeChecked=true;
1058 int nCount = 0;
1059 Atom* pProps = XListProperties( GetXDisplay(),
1060 GetDisplay()->GetRootWindow( m_nXScreen ),
1061 &nCount );
1062 for( int i = 0; i < nCount && !bGnomeIconSize; i++ )
1064 char* pName = XGetAtomName( GetXDisplay(), pProps[i] );
1065 if( pName )
1067 if( !strcmp( pName, "GNOME_PANEL_DESKTOP_AREA" ) )
1068 bGnomeIconSize = true;
1069 XFree( pName );
1072 if( pProps )
1073 XFree( pProps );
1075 if( bGnomeIconSize )
1076 iconSize = 48;
1079 XWMHints Hints;
1080 Hints.flags = 0;
1081 XWMHints *pHints = XGetWMHints( GetXDisplay(), GetShellWindow() );
1082 if( pHints )
1084 memcpy(&Hints, pHints, sizeof( XWMHints ));
1085 XFree( pHints );
1087 pHints = &Hints;
1089 NetWmIconData netwm_icon;
1090 bool bOk = lcl_SelectAppIconPixmap( GetDisplay(), m_nXScreen,
1091 nIcon, iconSize,
1092 pHints->icon_pixmap, pHints->icon_mask, netwm_icon );
1093 if ( !bOk )
1095 // load default icon (0)
1096 bOk = lcl_SelectAppIconPixmap( GetDisplay(), m_nXScreen,
1097 0, iconSize,
1098 pHints->icon_pixmap, pHints->icon_mask, netwm_icon );
1100 if( bOk )
1102 pHints->flags |= IconPixmapHint;
1103 if( pHints->icon_mask )
1104 pHints->flags |= IconMaskHint;
1106 XSetWMHints( GetXDisplay(), GetShellWindow(), pHints );
1107 if( !netwm_icon.empty() && GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_ICON ))
1108 XChangeProperty( GetXDisplay(), mhWindow,
1109 GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_ICON ),
1110 XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<unsigned char*>(netwm_icon.data()), netwm_icon.size());
1115 void X11SalFrame::SetMaxClientSize( tools::Long nWidth, tools::Long nHeight )
1117 if( IsChildWindow() )
1118 return;
1120 if( !GetShellWindow() ||
1121 (nStyle_ & (SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::OWNERDRAWDECORATION) ) == SalFrameStyleFlags::FLOAT )
1122 return;
1124 XSizeHints* pHints = XAllocSizeHints();
1125 tools::Long nSupplied = 0;
1126 XGetWMNormalHints( GetXDisplay(),
1127 GetShellWindow(),
1128 pHints,
1129 &nSupplied
1131 pHints->max_width = nWidth;
1132 pHints->max_height = nHeight;
1133 pHints->flags |= PMaxSize;
1134 XSetWMNormalHints( GetXDisplay(),
1135 GetShellWindow(),
1136 pHints );
1137 XFree( pHints );
1140 void X11SalFrame::SetMinClientSize( tools::Long nWidth, tools::Long nHeight )
1142 if( IsChildWindow() )
1143 return;
1145 if( !GetShellWindow() ||
1146 (nStyle_ & (SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::OWNERDRAWDECORATION) ) == SalFrameStyleFlags::FLOAT )
1147 return;
1149 XSizeHints* pHints = XAllocSizeHints();
1150 tools::Long nSupplied = 0;
1151 XGetWMNormalHints( GetXDisplay(),
1152 GetShellWindow(),
1153 pHints,
1154 &nSupplied
1156 pHints->min_width = nWidth;
1157 pHints->min_height = nHeight;
1158 pHints->flags |= PMinSize;
1159 XSetWMNormalHints( GetXDisplay(),
1160 GetShellWindow(),
1161 pHints );
1162 XFree( pHints );
1165 // Show + Pos (x,y,z) + Size (width,height)
1167 void X11SalFrame::Show( bool bVisible, bool bNoActivate )
1169 if( ( bVisible && bMapped_ )
1170 || ( !bVisible && !bMapped_ ) )
1171 return;
1173 // HACK: this is a workaround for (at least) kwin
1174 // even though transient frames should be kept above their parent
1175 // this does not necessarily hold true for DOCK type windows
1176 // so artificially set ABOVE and remove it again on hide
1177 if( mpParent && (mpParent->nStyle_ & SalFrameStyleFlags::PARTIAL_FULLSCREEN ) && pDisplay_->getWMAdaptor()->isLegacyPartialFullscreen())
1178 pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bVisible );
1180 bMapped_ = bVisible;
1181 bViewable_ = bVisible;
1182 setXEmbedInfo();
1183 if( bVisible )
1185 if( ! (nStyle_ & SalFrameStyleFlags::INTRO) )
1187 // hide all INTRO frames
1188 for (auto pSalFrame : GetDisplay()->getFrames() )
1190 const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame );
1191 // look for intro bit map; if present, hide it
1192 if( pFrame->nStyle_ & SalFrameStyleFlags::INTRO )
1194 if( pFrame->bMapped_ )
1195 const_cast<X11SalFrame*>(pFrame)->Show( false );
1200 // update NET_WM_STATE which may have been deleted due to earlier Show(false)
1201 if( nShowState_ == SHOWSTATE_HIDDEN )
1202 GetDisplay()->getWMAdaptor()->frameIsMapping( this );
1205 * Actually this is rather exotic and currently happens only in conjunction
1206 * with the basic dialogue editor,
1207 * which shows a frame and instantly hides it again. After that the
1208 * editor window is shown and the WM takes this as an opportunity
1209 * to show our hidden transient frame also. So Show( false ) must
1210 * withdraw the frame AND delete the WM_TRANSIENT_FOR property.
1211 * In case the frame is shown again, the transient hint must be restored here.
1213 if( ! IsChildWindow()
1214 && ! IsOverrideRedirect()
1215 && ! IsFloatGrabWindow()
1216 && mpParent
1219 GetDisplay()->getWMAdaptor()->changeReferenceFrame( this, mpParent );
1222 // #i45160# switch to desktop where a dialog with parent will appear
1223 if( mpParent && mpParent->m_nWorkArea != m_nWorkArea )
1224 GetDisplay()->getWMAdaptor()->switchToWorkArea( mpParent->m_nWorkArea );
1226 if( IsFloatGrabWindow() &&
1227 mpParent &&
1228 nVisibleFloats == 0 &&
1229 ! GetDisplay()->GetCaptureFrame() )
1231 /* #i39420#
1232 * outsmart KWin's "focus strictly under mouse" mode
1233 * which insists on taking the focus from the document
1234 * to the new float. Grab focus to parent frame BEFORE
1235 * showing the float (cannot grab it to the float
1236 * before show).
1238 XGrabPointer( GetXDisplay(),
1239 mpParent->GetWindow(),
1240 True,
1241 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1242 GrabModeAsync,
1243 GrabModeAsync,
1244 None,
1245 mpParent ? mpParent->GetCursor() : None,
1246 CurrentTime
1250 Time nUserTime = 0;
1251 if( ! bNoActivate && !(nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION) )
1252 nUserTime = pDisplay_->GetX11ServerTime();
1253 GetDisplay()->getWMAdaptor()->setUserTime( this, nUserTime );
1254 if( ! bNoActivate && (nStyle_ & SalFrameStyleFlags::TOOLWINDOW) )
1255 m_bSetFocusOnMap = true;
1257 // actually map the window
1258 if( m_bXEmbed )
1259 askForXEmbedFocus( 0 );
1260 else
1262 if( GetWindow() != GetShellWindow() && ! IsSysChildWindow() )
1264 if( IsChildWindow() )
1265 XMapWindow( GetXDisplay(), GetShellWindow() );
1266 XSelectInput( GetXDisplay(), GetShellWindow(), CLIENT_EVENTS );
1268 if( nStyle_ & SalFrameStyleFlags::FLOAT )
1269 XMapRaised( GetXDisplay(), GetWindow() );
1270 else
1271 XMapWindow( GetXDisplay(), GetWindow() );
1273 XSelectInput( GetXDisplay(), GetWindow(), CLIENT_EVENTS );
1275 if( maGeometry.nWidth > 0
1276 && maGeometry.nHeight > 0
1277 && ( nWidth_ != static_cast<int>(maGeometry.nWidth)
1278 || nHeight_ != static_cast<int>(maGeometry.nHeight) ) )
1280 nWidth_ = maGeometry.nWidth;
1281 nHeight_ = maGeometry.nHeight;
1284 XSync( GetXDisplay(), False );
1286 if( IsFloatGrabWindow() )
1289 * Sawfish and twm can be switched to enter-exit focus behaviour. In this case
1290 * we must grab the pointer else the dumb WM will put the focus to the
1291 * override-redirect float window. The application window will be deactivated
1292 * which causes that the floats are destroyed, so the user can never click on
1293 * a menu because it vanishes as soon as he enters it.
1295 nVisibleFloats++;
1296 if( nVisibleFloats == 1 && ! GetDisplay()->GetCaptureFrame() )
1298 /* #i39420# now move grab to the new float window */
1299 XGrabPointer( GetXDisplay(),
1300 GetWindow(),
1301 True,
1302 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1303 GrabModeAsync,
1304 GrabModeAsync,
1305 None,
1306 mpParent ? mpParent->GetCursor() : None,
1307 CurrentTime
1311 CallCallback( SalEvent::Resize, nullptr );
1314 * sometimes a message box/dialogue is brought up when a frame is not mapped
1315 * the corresponding TRANSIENT_FOR hint is then set to the root window
1316 * so that the dialogue shows in all cases. Correct it here if the
1317 * frame is shown afterwards.
1319 if( ! IsChildWindow()
1320 && ! IsOverrideRedirect()
1321 && ! IsFloatGrabWindow()
1324 for (auto const& child : maChildren)
1326 if( child->mbTransientForRoot )
1327 GetDisplay()->getWMAdaptor()->changeReferenceFrame( child, this );
1331 * leave SHOWSTATE_UNKNOWN as this indicates first mapping
1332 * and is only reset int HandleSizeEvent
1334 if( nShowState_ != SHOWSTATE_UNKNOWN )
1335 nShowState_ = SHOWSTATE_NORMAL;
1338 * plugged windows don't necessarily get the
1339 * focus on show because the parent may already be mapped
1340 * and have the focus. So try to set the focus
1341 * to the child on Show(true)
1343 if( (nStyle_ & SalFrameStyleFlags::PLUG) && ! m_bXEmbed )
1344 XSetInputFocus( GetXDisplay(),
1345 GetWindow(),
1346 RevertToParent,
1347 CurrentTime );
1349 if( mpParent )
1351 // push this frame so it will be in front of its siblings
1352 // only necessary for insane transient behaviour of Dtwm/olwm
1353 mpParent->maChildren.remove( this );
1354 mpParent->maChildren.push_front(this);
1357 else
1359 if( getInputContext() )
1360 getInputContext()->Unmap();
1362 if( ! IsChildWindow() )
1364 /* FIXME: Is deleting the property really necessary ? It hurts
1365 * owner drawn windows at least.
1367 if( mpParent && ! (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION) )
1368 XDeleteProperty( GetXDisplay(), GetShellWindow(), GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::WM_TRANSIENT_FOR ) );
1369 XWithdrawWindow( GetXDisplay(), GetShellWindow(), m_nXScreen.getXScreen() );
1371 else if( ! m_bXEmbed )
1372 XUnmapWindow( GetXDisplay(), GetWindow() );
1374 nShowState_ = SHOWSTATE_HIDDEN;
1375 if( IsFloatGrabWindow() && nVisibleFloats )
1377 nVisibleFloats--;
1378 if( nVisibleFloats == 0 && ! GetDisplay()->GetCaptureFrame() )
1379 XUngrabPointer( GetXDisplay(),
1380 CurrentTime );
1382 // flush here; there may be a very seldom race between
1383 // the display connection used for clipboard and our connection
1384 Flush();
1388 void X11SalFrame::ToTop( SalFrameToTop nFlags )
1390 if( ( nFlags & SalFrameToTop::RestoreWhenMin )
1391 && ! ( nStyle_ & SalFrameStyleFlags::FLOAT )
1392 && nShowState_ != SHOWSTATE_HIDDEN
1393 && nShowState_ != SHOWSTATE_UNKNOWN
1396 GetDisplay()->getWMAdaptor()->frameIsMapping( this );
1397 if( GetWindow() != GetShellWindow() && ! IsSysChildWindow() )
1398 XMapWindow( GetXDisplay(), GetShellWindow() );
1399 XMapWindow( GetXDisplay(), GetWindow() );
1402 ::Window aToTopWindow = IsSysChildWindow() ? GetWindow() : GetShellWindow();
1403 if( ! (nFlags & SalFrameToTop::GrabFocusOnly) )
1405 XRaiseWindow( GetXDisplay(), aToTopWindow );
1408 if( ( ( nFlags & SalFrameToTop::GrabFocus ) || ( nFlags & SalFrameToTop::GrabFocusOnly ) )
1409 && bMapped_ )
1411 if( m_bXEmbed )
1412 askForXEmbedFocus( 0 );
1413 else
1414 XSetInputFocus( GetXDisplay(), aToTopWindow, RevertToParent, CurrentTime );
1416 else if( ( nFlags & SalFrameToTop::RestoreWhenMin ) || ( nFlags & SalFrameToTop::ForegroundTask ) )
1418 Time nTimestamp = pDisplay_->GetX11ServerTime();
1419 GetDisplay()->getWMAdaptor()->activateWindow( this, nTimestamp );
1423 void X11SalFrame::GetWorkArea( tools::Rectangle& rWorkArea )
1425 rWorkArea = pDisplay_->getWMAdaptor()->getWorkArea( 0 );
1428 void X11SalFrame::GetClientSize( tools::Long &rWidth, tools::Long &rHeight )
1430 if( ! bViewable_ )
1432 rWidth = rHeight = 0;
1433 return;
1436 rWidth = maGeometry.nWidth;
1437 rHeight = maGeometry.nHeight;
1439 if( !rWidth || !rHeight )
1441 XWindowAttributes aAttrib;
1443 XGetWindowAttributes( GetXDisplay(), GetWindow(), &aAttrib );
1445 maGeometry.nWidth = rWidth = aAttrib.width;
1446 maGeometry.nHeight = rHeight = aAttrib.height;
1450 void X11SalFrame::Center( )
1452 int nX, nY, nScreenWidth, nScreenHeight;
1453 int nRealScreenWidth, nRealScreenHeight;
1454 int nScreenX = 0, nScreenY = 0;
1456 const Size& aScreenSize = GetDisplay()->getDataForScreen( m_nXScreen ).m_aSize;
1457 nScreenWidth = aScreenSize.Width();
1458 nScreenHeight = aScreenSize.Height();
1459 nRealScreenWidth = nScreenWidth;
1460 nRealScreenHeight = nScreenHeight;
1462 if( GetDisplay()->IsXinerama() )
1464 // get xinerama screen we are on
1465 // if there is a parent, use its center for screen determination
1466 // else use the pointer
1467 ::Window aRoot, aChild;
1468 int root_x, root_y, x, y;
1469 unsigned int mask;
1470 if( mpParent )
1472 root_x = mpParent->maGeometry.nX + mpParent->maGeometry.nWidth/2;
1473 root_y = mpParent->maGeometry.nY + mpParent->maGeometry.nHeight/2;
1475 else
1476 XQueryPointer( GetXDisplay(),
1477 GetShellWindow(),
1478 &aRoot, &aChild,
1479 &root_x, &root_y,
1480 &x, &y,
1481 &mask );
1482 const std::vector< tools::Rectangle >& rScreens = GetDisplay()->GetXineramaScreens();
1483 for(const auto & rScreen : rScreens)
1484 if( rScreen.IsInside( Point( root_x, root_y ) ) )
1486 nScreenX = rScreen.Left();
1487 nScreenY = rScreen.Top();
1488 nRealScreenWidth = rScreen.GetWidth();
1489 nRealScreenHeight = rScreen.GetHeight();
1490 break;
1494 if( mpParent )
1496 X11SalFrame* pFrame = mpParent;
1497 while( pFrame->mpParent )
1498 pFrame = pFrame->mpParent;
1499 if( pFrame->maGeometry.nWidth < 1 || pFrame->maGeometry.nHeight < 1 )
1501 tools::Rectangle aRect;
1502 pFrame->GetPosSize( aRect );
1503 pFrame->maGeometry.nX = aRect.Left();
1504 pFrame->maGeometry.nY = aRect.Top();
1505 pFrame->maGeometry.nWidth = aRect.GetWidth();
1506 pFrame->maGeometry.nHeight = aRect.GetHeight();
1509 if( pFrame->nStyle_ & SalFrameStyleFlags::PLUG )
1511 ::Window aRoot;
1512 unsigned int bw, depth;
1513 XGetGeometry( GetXDisplay(),
1514 pFrame->GetShellWindow(),
1515 &aRoot,
1516 &nScreenX, &nScreenY,
1517 reinterpret_cast<unsigned int*>(&nScreenWidth),
1518 reinterpret_cast<unsigned int*>(&nScreenHeight),
1519 &bw, &depth );
1521 else
1523 nScreenX = pFrame->maGeometry.nX;
1524 nScreenY = pFrame->maGeometry.nY;
1525 nScreenWidth = pFrame->maGeometry.nWidth;
1526 nScreenHeight = pFrame->maGeometry.nHeight;
1530 if( mpParent && mpParent->nShowState_ == SHOWSTATE_NORMAL )
1532 if( maGeometry.nWidth >= mpParent->maGeometry.nWidth &&
1533 maGeometry.nHeight >= mpParent->maGeometry.nHeight )
1535 nX = nScreenX + 40;
1536 nY = nScreenY + 40;
1538 else
1540 // center the window relative to the top level frame
1541 nX = (nScreenWidth - static_cast<int>(maGeometry.nWidth) ) / 2 + nScreenX;
1542 nY = (nScreenHeight - static_cast<int>(maGeometry.nHeight)) / 2 + nScreenY;
1545 else
1547 // center the window relative to screen
1548 nX = (nRealScreenWidth - static_cast<int>(maGeometry.nWidth) ) / 2 + nScreenX;
1549 nY = (nRealScreenHeight - static_cast<int>(maGeometry.nHeight)) / 2 + nScreenY;
1551 nX = nX < 0 ? 0 : nX;
1552 nY = nY < 0 ? 0 : nY;
1554 bDefaultPosition_ = False;
1555 if( mpParent )
1557 nX -= mpParent->maGeometry.nX;
1558 nY -= mpParent->maGeometry.nY;
1561 Point aPoint(nX, nY);
1562 SetPosSize( tools::Rectangle( aPoint, Size( maGeometry.nWidth, maGeometry.nHeight ) ) );
1565 void X11SalFrame::updateScreenNumber()
1567 if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
1569 Point aPoint( maGeometry.nX, maGeometry.nY );
1570 const std::vector<tools::Rectangle>& rScreenRects( GetDisplay()->GetXineramaScreens() );
1571 size_t nScreens = rScreenRects.size();
1572 for( size_t i = 0; i < nScreens; i++ )
1574 if( rScreenRects[i].IsInside( aPoint ) )
1576 maGeometry.nDisplayScreenNumber = static_cast<unsigned int>(i);
1577 break;
1581 else
1582 maGeometry.nDisplayScreenNumber = m_nXScreen.getXScreen();
1585 void X11SalFrame::SetPosSize( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt16 nFlags )
1587 if( nStyle_ & SalFrameStyleFlags::PLUG )
1588 return;
1590 // relative positioning in X11SalFrame::SetPosSize
1591 tools::Rectangle aPosSize( Point( maGeometry.nX, maGeometry.nY ), Size( maGeometry.nWidth, maGeometry.nHeight ) );
1592 aPosSize.Justify();
1594 if( ! ( nFlags & SAL_FRAME_POSSIZE_X ) )
1596 nX = aPosSize.Left();
1597 if( mpParent )
1598 nX -= mpParent->maGeometry.nX;
1600 if( ! ( nFlags & SAL_FRAME_POSSIZE_Y ) )
1602 nY = aPosSize.Top();
1603 if( mpParent )
1604 nY -= mpParent->maGeometry.nY;
1606 if( ! ( nFlags & SAL_FRAME_POSSIZE_WIDTH ) )
1607 nWidth = aPosSize.GetWidth();
1608 if( ! ( nFlags & SAL_FRAME_POSSIZE_HEIGHT ) )
1609 nHeight = aPosSize.GetHeight();
1611 aPosSize = tools::Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
1613 if( ! ( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) ) )
1615 if( bDefaultPosition_ )
1617 maGeometry.nWidth = aPosSize.GetWidth();
1618 maGeometry.nHeight = aPosSize.GetHeight();
1619 Center();
1621 else
1622 SetSize( Size( nWidth, nHeight ) );
1624 else
1625 SetPosSize( aPosSize );
1627 bDefaultPosition_ = False;
1630 void X11SalFrame::SetAlwaysOnTop( bool bOnTop )
1632 if( ! IsOverrideRedirect() )
1634 bAlwaysOnTop_ = bOnTop;
1635 pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bOnTop );
1639 constexpr auto FRAMESTATE_MASK_GEOMETRY =
1640 WindowStateMask::X | WindowStateMask::Y |
1641 WindowStateMask::Width | WindowStateMask::Height;
1642 constexpr auto FRAMESTATE_MASK_MAXIMIZED_GEOMETRY =
1643 WindowStateMask::MaximizedX | WindowStateMask::MaximizedY |
1644 WindowStateMask::MaximizedWidth | WindowStateMask::MaximizedHeight;
1646 void X11SalFrame::SetWindowState( const SalFrameState *pState )
1648 if (pState == nullptr)
1649 return;
1651 // Request for position or size change
1652 if (pState->mnMask & FRAMESTATE_MASK_GEOMETRY)
1654 /* #i44325#
1655 * if maximized, set restore size and guess maximized size from last time
1656 * in state change below maximize window
1658 if( ! IsChildWindow() &&
1659 (pState->mnMask & WindowStateMask::State) &&
1660 (pState->mnState & WindowStateState::Maximized) &&
1661 (pState->mnMask & FRAMESTATE_MASK_GEOMETRY) == FRAMESTATE_MASK_GEOMETRY &&
1662 (pState->mnMask & FRAMESTATE_MASK_MAXIMIZED_GEOMETRY) == FRAMESTATE_MASK_MAXIMIZED_GEOMETRY
1665 XSizeHints* pHints = XAllocSizeHints();
1666 tools::Long nSupplied = 0;
1667 XGetWMNormalHints( GetXDisplay(),
1668 GetShellWindow(),
1669 pHints,
1670 &nSupplied );
1671 pHints->flags |= PPosition | PWinGravity;
1672 pHints->x = pState->mnX;
1673 pHints->y = pState->mnY;
1674 pHints->win_gravity = pDisplay_->getWMAdaptor()->getPositionWinGravity();
1675 XSetWMNormalHints( GetXDisplay(),
1676 GetShellWindow(),
1677 pHints );
1678 XFree( pHints );
1680 XMoveResizeWindow( GetXDisplay(), GetShellWindow(),
1681 pState->mnX, pState->mnY,
1682 pState->mnWidth, pState->mnHeight );
1683 // guess maximized geometry from last time
1684 maGeometry.nX = pState->mnMaximizedX;
1685 maGeometry.nY = pState->mnMaximizedY;
1686 maGeometry.nWidth = pState->mnMaximizedWidth;
1687 maGeometry.nHeight = pState->mnMaximizedHeight;
1688 updateScreenNumber();
1690 else
1692 bool bDoAdjust = false;
1693 tools::Rectangle aPosSize;
1694 // initialize with current geometry
1695 if ((pState->mnMask & FRAMESTATE_MASK_GEOMETRY) != FRAMESTATE_MASK_GEOMETRY)
1696 GetPosSize (aPosSize);
1698 // change requested properties
1699 if (pState->mnMask & WindowStateMask::X)
1701 aPosSize.setX (pState->mnX);
1703 if (pState->mnMask & WindowStateMask::Y)
1705 aPosSize.setY (pState->mnY);
1707 if (pState->mnMask & WindowStateMask::Width)
1709 tools::Long nWidth = pState->mnWidth > 0 ? pState->mnWidth - 1 : 0;
1710 aPosSize.setWidth (nWidth);
1711 bDoAdjust = true;
1713 if (pState->mnMask & WindowStateMask::Height)
1715 int nHeight = pState->mnHeight > 0 ? pState->mnHeight - 1 : 0;
1716 aPosSize.setHeight (nHeight);
1717 bDoAdjust = true;
1720 const Size& aScreenSize = pDisplay_->getDataForScreen( m_nXScreen ).m_aSize;
1722 if( bDoAdjust && aPosSize.GetWidth() <= aScreenSize.Width()
1723 && aPosSize.GetHeight() <= aScreenSize.Height() )
1725 SalFrameGeometry aGeom = maGeometry;
1727 if( ! (nStyle_ & ( SalFrameStyleFlags::FLOAT | SalFrameStyleFlags::PLUG ) ) &&
1728 mpParent &&
1729 aGeom.nLeftDecoration == 0 &&
1730 aGeom.nTopDecoration == 0 )
1732 aGeom = mpParent->maGeometry;
1733 if( aGeom.nLeftDecoration == 0 &&
1734 aGeom.nTopDecoration == 0 )
1736 aGeom.nLeftDecoration = 5;
1737 aGeom.nTopDecoration = 20;
1738 aGeom.nRightDecoration = 5;
1739 aGeom.nBottomDecoration = 5;
1743 // adjust position so that frame fits onto screen
1744 if( aPosSize.Right()+static_cast<tools::Long>(aGeom.nRightDecoration) > aScreenSize.Width()-1 )
1745 aPosSize.Move( aScreenSize.Width() - aPosSize.Right() - static_cast<tools::Long>(aGeom.nRightDecoration), 0 );
1746 if( aPosSize.Bottom()+static_cast<tools::Long>(aGeom.nBottomDecoration) > aScreenSize.Height()-1 )
1747 aPosSize.Move( 0, aScreenSize.Height() - aPosSize.Bottom() - static_cast<tools::Long>(aGeom.nBottomDecoration) );
1748 if( aPosSize.Left() < static_cast<tools::Long>(aGeom.nLeftDecoration) )
1749 aPosSize.Move( static_cast<tools::Long>(aGeom.nLeftDecoration) - aPosSize.Left(), 0 );
1750 if( aPosSize.Top() < static_cast<tools::Long>(aGeom.nTopDecoration) )
1751 aPosSize.Move( 0, static_cast<tools::Long>(aGeom.nTopDecoration) - aPosSize.Top() );
1754 SetPosSize( 0, 0, aPosSize.GetWidth(), aPosSize.GetHeight(), SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
1758 // request for status change
1759 if (!(pState->mnMask & WindowStateMask::State))
1760 return;
1762 if (pState->mnState & WindowStateState::Maximized)
1764 nShowState_ = SHOWSTATE_NORMAL;
1765 if( ! (pState->mnState & (WindowStateState::MaximizedHorz|WindowStateState::MaximizedVert) ) )
1766 Maximize();
1767 else
1769 bool bHorz(pState->mnState & WindowStateState::MaximizedHorz);
1770 bool bVert(pState->mnState & WindowStateState::MaximizedVert);
1771 GetDisplay()->getWMAdaptor()->maximizeFrame( this, bHorz, bVert );
1773 maRestorePosSize.SetLeft( pState->mnX );
1774 maRestorePosSize.SetTop( pState->mnY );
1775 maRestorePosSize.SetRight( maRestorePosSize.Left() + pState->mnWidth );
1776 maRestorePosSize.SetRight( maRestorePosSize.Left() + pState->mnHeight );
1778 else if( mbMaximizedHorz || mbMaximizedVert )
1779 GetDisplay()->getWMAdaptor()->maximizeFrame( this, false, false );
1781 if (pState->mnState & WindowStateState::Minimized)
1783 if (nShowState_ == SHOWSTATE_UNKNOWN)
1784 nShowState_ = SHOWSTATE_NORMAL;
1785 Minimize();
1787 if (pState->mnState & WindowStateState::Normal)
1789 if (nShowState_ != SHOWSTATE_NORMAL)
1790 Restore();
1792 if (pState->mnState & WindowStateState::Rollup)
1793 GetDisplay()->getWMAdaptor()->shade( this, true );
1796 bool X11SalFrame::GetWindowState( SalFrameState* pState )
1798 if( SHOWSTATE_MINIMIZED == nShowState_ )
1799 pState->mnState = WindowStateState::Minimized;
1800 else
1801 pState->mnState = WindowStateState::Normal;
1803 tools::Rectangle aPosSize;
1804 if( maRestorePosSize.IsEmpty() )
1805 GetPosSize( aPosSize );
1806 else
1807 aPosSize = maRestorePosSize;
1809 if( mbMaximizedHorz )
1810 pState->mnState |= WindowStateState::MaximizedHorz;
1811 if( mbMaximizedVert )
1812 pState->mnState |= WindowStateState::MaximizedVert;
1813 if( mbShaded )
1814 pState->mnState |= WindowStateState::Rollup;
1816 pState->mnX = aPosSize.Left();
1817 pState->mnY = aPosSize.Top();
1818 pState->mnWidth = aPosSize.GetWidth();
1819 pState->mnHeight = aPosSize.GetHeight();
1821 pState->mnMask = FRAMESTATE_MASK_GEOMETRY | WindowStateMask::State;
1823 if (! maRestorePosSize.IsEmpty() )
1825 GetPosSize( aPosSize );
1826 pState->mnState |= WindowStateState::Maximized;
1827 pState->mnMaximizedX = aPosSize.Left();
1828 pState->mnMaximizedY = aPosSize.Top();
1829 pState->mnMaximizedWidth = aPosSize.GetWidth();
1830 pState->mnMaximizedHeight = aPosSize.GetHeight();
1831 pState->mnMask |= FRAMESTATE_MASK_MAXIMIZED_GEOMETRY;
1834 return true;
1837 // native menu implementation - currently empty
1838 void X11SalFrame::DrawMenuBar()
1842 void X11SalFrame::SetMenu( SalMenu* )
1846 void X11SalFrame::GetPosSize( tools::Rectangle &rPosSize )
1848 if( maGeometry.nWidth < 1 || maGeometry.nHeight < 1 )
1850 const Size& aScreenSize = pDisplay_->getDataForScreen( m_nXScreen ).m_aSize;
1851 tools::Long w = aScreenSize.Width() - maGeometry.nLeftDecoration - maGeometry.nRightDecoration;
1852 tools::Long h = aScreenSize.Height() - maGeometry.nTopDecoration - maGeometry.nBottomDecoration;
1854 rPosSize = tools::Rectangle( Point( maGeometry.nX, maGeometry.nY ), Size( w, h ) );
1856 else
1857 rPosSize = tools::Rectangle( Point( maGeometry.nX, maGeometry.nY ),
1858 Size( maGeometry.nWidth, maGeometry.nHeight ) );
1861 void X11SalFrame::SetSize( const Size &rSize )
1863 if( rSize.IsEmpty() )
1864 return;
1866 if( ! ( nStyle_ & SalFrameStyleFlags::SIZEABLE )
1867 && ! IsChildWindow()
1868 && ( nStyle_ & (SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::OWNERDRAWDECORATION) ) != SalFrameStyleFlags::FLOAT )
1870 XSizeHints* pHints = XAllocSizeHints();
1871 tools::Long nSupplied = 0;
1872 XGetWMNormalHints( GetXDisplay(),
1873 GetShellWindow(),
1874 pHints,
1875 &nSupplied
1877 pHints->min_width = rSize.Width();
1878 pHints->min_height = rSize.Height();
1879 pHints->max_width = rSize.Width();
1880 pHints->max_height = rSize.Height();
1881 pHints->flags |= PMinSize | PMaxSize;
1882 XSetWMNormalHints( GetXDisplay(),
1883 GetShellWindow(),
1884 pHints );
1885 XFree( pHints );
1887 XResizeWindow( GetXDisplay(), IsSysChildWindow() ? GetWindow() : GetShellWindow(), rSize.Width(), rSize.Height() );
1888 if( GetWindow() != GetShellWindow() )
1890 if( nStyle_ & SalFrameStyleFlags::PLUG )
1891 XMoveResizeWindow( GetXDisplay(), GetWindow(), 0, 0, rSize.Width(), rSize.Height() );
1892 else
1893 XResizeWindow( GetXDisplay(), GetWindow(), rSize.Width(), rSize.Height() );
1896 maGeometry.nWidth = rSize.Width();
1897 maGeometry.nHeight = rSize.Height();
1899 // allow the external status window to reposition
1900 if (mbInputFocus && mpInputContext != nullptr)
1901 mpInputContext->SetICFocus ( this );
1904 void X11SalFrame::SetPosSize( const tools::Rectangle &rPosSize )
1906 XWindowChanges values;
1907 values.x = rPosSize.Left();
1908 values.y = rPosSize.Top();
1909 values.width = rPosSize.GetWidth();
1910 values.height = rPosSize.GetHeight();
1912 if( !values.width || !values.height )
1913 return;
1915 if( mpParent && ! IsSysChildWindow() )
1917 if( AllSettings::GetLayoutRTL() )
1918 values.x = mpParent->maGeometry.nWidth-values.width-1-values.x;
1920 ::Window aChild;
1921 // coordinates are relative to parent, so translate to root coordinates
1922 XTranslateCoordinates( GetDisplay()->GetDisplay(),
1923 mpParent->GetWindow(),
1924 GetDisplay()->GetRootWindow( m_nXScreen ),
1925 values.x, values.y,
1926 &values.x, &values.y,
1927 & aChild );
1930 bool bMoved = false;
1931 bool bSized = false;
1932 if( values.x != maGeometry.nX || values.y != maGeometry.nY )
1933 bMoved = true;
1934 if( values.width != static_cast<int>(maGeometry.nWidth) || values.height != static_cast<int>(maGeometry.nHeight) )
1935 bSized = true;
1937 // do not set WMNormalHints for...
1939 // child windows
1940 ! IsChildWindow()
1941 // popups (menu, help window, etc.)
1942 && (nStyle_ & (SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::OWNERDRAWDECORATION) ) != SalFrameStyleFlags::FLOAT
1943 // shown, sizeable windows
1944 && ( nShowState_ == SHOWSTATE_UNKNOWN ||
1945 nShowState_ == SHOWSTATE_HIDDEN ||
1946 ! ( nStyle_ & SalFrameStyleFlags::SIZEABLE )
1950 XSizeHints* pHints = XAllocSizeHints();
1951 tools::Long nSupplied = 0;
1952 XGetWMNormalHints( GetXDisplay(),
1953 GetShellWindow(),
1954 pHints,
1955 &nSupplied
1957 if( ! ( nStyle_ & SalFrameStyleFlags::SIZEABLE ) )
1959 pHints->min_width = rPosSize.GetWidth();
1960 pHints->min_height = rPosSize.GetHeight();
1961 pHints->max_width = rPosSize.GetWidth();
1962 pHints->max_height = rPosSize.GetHeight();
1963 pHints->flags |= PMinSize | PMaxSize;
1965 if( nShowState_ == SHOWSTATE_UNKNOWN || nShowState_ == SHOWSTATE_HIDDEN )
1967 pHints->flags |= PPosition | PWinGravity;
1968 pHints->x = values.x;
1969 pHints->y = values.y;
1970 pHints->win_gravity = pDisplay_->getWMAdaptor()->getPositionWinGravity();
1972 if( mbFullScreen )
1974 pHints->max_width = 10000;
1975 pHints->max_height = 10000;
1976 pHints->flags |= PMaxSize;
1978 XSetWMNormalHints( GetXDisplay(),
1979 GetShellWindow(),
1980 pHints );
1981 XFree( pHints );
1984 XMoveResizeWindow( GetXDisplay(), IsSysChildWindow() ? GetWindow() : GetShellWindow(), values.x, values.y, values.width, values.height );
1985 if( GetShellWindow() != GetWindow() )
1987 if( nStyle_ & SalFrameStyleFlags::PLUG )
1988 XMoveResizeWindow( GetXDisplay(), GetWindow(), 0, 0, values.width, values.height );
1989 else
1990 XMoveResizeWindow( GetXDisplay(), GetWindow(), values.x, values.y, values.width, values.height );
1993 maGeometry.nX = values.x;
1994 maGeometry.nY = values.y;
1995 maGeometry.nWidth = values.width;
1996 maGeometry.nHeight = values.height;
1997 if( IsSysChildWindow() && mpParent )
1999 // translate back to root coordinates
2000 maGeometry.nX += mpParent->maGeometry.nX;
2001 maGeometry.nY += mpParent->maGeometry.nY;
2004 updateScreenNumber();
2005 if( bSized && ! bMoved )
2006 CallCallback( SalEvent::Resize, nullptr );
2007 else if( bMoved && ! bSized )
2008 CallCallback( SalEvent::Move, nullptr );
2009 else
2010 CallCallback( SalEvent::MoveResize, nullptr );
2012 // allow the external status window to reposition
2013 if (mbInputFocus && mpInputContext != nullptr)
2014 mpInputContext->SetICFocus ( this );
2017 void X11SalFrame::Minimize()
2019 if( IsSysChildWindow() )
2020 return;
2022 if( SHOWSTATE_UNKNOWN == nShowState_ || SHOWSTATE_HIDDEN == nShowState_ )
2024 SAL_WARN( "vcl", "X11SalFrame::Minimize on withdrawn window" );
2025 return;
2028 if( XIconifyWindow( GetXDisplay(),
2029 GetShellWindow(),
2030 pDisplay_->GetDefaultXScreen().getXScreen() ) )
2031 nShowState_ = SHOWSTATE_MINIMIZED;
2034 void X11SalFrame::Maximize()
2036 if( IsSysChildWindow() )
2037 return;
2039 if( SHOWSTATE_MINIMIZED == nShowState_ )
2041 GetDisplay()->getWMAdaptor()->frameIsMapping( this );
2042 XMapWindow( GetXDisplay(), GetShellWindow() );
2043 nShowState_ = SHOWSTATE_NORMAL;
2046 pDisplay_->getWMAdaptor()->maximizeFrame( this );
2049 void X11SalFrame::Restore()
2051 if( IsSysChildWindow() )
2052 return;
2054 if( SHOWSTATE_UNKNOWN == nShowState_ || SHOWSTATE_HIDDEN == nShowState_ )
2056 SAL_WARN( "vcl", "X11SalFrame::Restore on withdrawn window" );
2057 return;
2060 if( SHOWSTATE_MINIMIZED == nShowState_ )
2062 GetDisplay()->getWMAdaptor()->frameIsMapping( this );
2063 XMapWindow( GetXDisplay(), GetShellWindow() );
2064 nShowState_ = SHOWSTATE_NORMAL;
2067 pDisplay_->getWMAdaptor()->maximizeFrame( this, false, false );
2070 void X11SalFrame::SetScreenNumber( unsigned int nNewScreen )
2072 if( nNewScreen == maGeometry.nDisplayScreenNumber )
2073 return;
2075 if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
2077 if( nNewScreen >= GetDisplay()->GetXineramaScreens().size() )
2078 return;
2080 tools::Rectangle aOldScreenRect( GetDisplay()->GetXineramaScreens()[maGeometry.nDisplayScreenNumber] );
2081 tools::Rectangle aNewScreenRect( GetDisplay()->GetXineramaScreens()[nNewScreen] );
2082 bool bVisible = bMapped_;
2083 if( bVisible )
2084 Show( false );
2085 maGeometry.nX = aNewScreenRect.Left() + (maGeometry.nX - aOldScreenRect.Left());
2086 maGeometry.nY = aNewScreenRect.Top() + (maGeometry.nY - aOldScreenRect.Top());
2087 createNewWindow( None, m_nXScreen );
2088 if( bVisible )
2089 Show( true );
2090 maGeometry.nDisplayScreenNumber = nNewScreen;
2092 else if( nNewScreen < GetDisplay()->GetXScreenCount() )
2094 bool bVisible = bMapped_;
2095 if( bVisible )
2096 Show( false );
2097 createNewWindow( None, SalX11Screen( nNewScreen ) );
2098 if( bVisible )
2099 Show( true );
2100 maGeometry.nDisplayScreenNumber = nNewScreen;
2104 void X11SalFrame::SetApplicationID( const OUString &rWMClass )
2106 if( rWMClass != m_sWMClass && ! IsChildWindow() )
2108 m_sWMClass = rWMClass;
2109 updateWMClass();
2110 for (auto const& child : maChildren)
2111 child->SetApplicationID(rWMClass);
2115 void X11SalFrame::updateWMClass()
2117 XClassHint* pClass = XAllocClassHint();
2118 OString aResName = SalGenericSystem::getFrameResName();
2119 pClass->res_name = const_cast<char*>(aResName.getStr());
2121 OString aResClass = OUStringToOString(m_sWMClass, RTL_TEXTENCODING_ASCII_US);
2122 const char *pResClass = !aResClass.isEmpty() ? aResClass.getStr() :
2123 SalGenericSystem::getFrameClassName();
2125 pClass->res_class = const_cast<char*>(pResClass);
2126 XSetClassHint( GetXDisplay(), GetShellWindow(), pClass );
2127 XFree( pClass );
2130 void X11SalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nScreen )
2132 if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
2134 if( mbFullScreen == bFullScreen )
2135 return;
2136 if( bFullScreen )
2138 maRestorePosSize = tools::Rectangle( Point( maGeometry.nX, maGeometry.nY ),
2139 Size( maGeometry.nWidth, maGeometry.nHeight ) );
2140 tools::Rectangle aRect;
2141 if( nScreen < 0 || nScreen >= static_cast<int>(GetDisplay()->GetXineramaScreens().size()) )
2142 aRect = tools::Rectangle( Point(0,0), GetDisplay()->GetScreenSize( m_nXScreen ) );
2143 else
2144 aRect = GetDisplay()->GetXineramaScreens()[nScreen];
2145 nStyle_ |= SalFrameStyleFlags::PARTIAL_FULLSCREEN;
2146 bool bVisible = bMapped_;
2147 if( bVisible )
2148 Show( false );
2149 maGeometry.nX = aRect.Left();
2150 maGeometry.nY = aRect.Top();
2151 maGeometry.nWidth = aRect.GetWidth();
2152 maGeometry.nHeight = aRect.GetHeight();
2153 mbMaximizedHorz = mbMaximizedVert = false;
2154 mbFullScreen = true;
2155 createNewWindow( None, m_nXScreen );
2156 if( GetDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
2157 GetDisplay()->getWMAdaptor()->enableAlwaysOnTop( this, true );
2158 else
2159 GetDisplay()->getWMAdaptor()->showFullScreen( this, true );
2160 if( bVisible )
2161 Show(true);
2164 else
2166 mbFullScreen = false;
2167 nStyle_ &= ~SalFrameStyleFlags::PARTIAL_FULLSCREEN;
2168 bool bVisible = bMapped_;
2169 tools::Rectangle aRect = maRestorePosSize;
2170 maRestorePosSize = tools::Rectangle();
2171 if( bVisible )
2172 Show( false );
2173 createNewWindow( None, m_nXScreen );
2174 if( !aRect.IsEmpty() )
2175 SetPosSize( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(),
2176 SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y |
2177 SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
2178 if( bVisible )
2179 Show( true );
2182 else
2184 if( nScreen < 0 || nScreen >= static_cast<int>(GetDisplay()->GetXScreenCount()) )
2185 nScreen = m_nXScreen.getXScreen();
2186 if( nScreen != static_cast<int>(m_nXScreen.getXScreen()) )
2188 bool bVisible = bMapped_;
2189 if( mbFullScreen )
2190 pDisplay_->getWMAdaptor()->showFullScreen( this, false );
2191 if( bVisible )
2192 Show( false );
2193 createNewWindow( None, SalX11Screen( nScreen ) );
2194 if( mbFullScreen )
2195 pDisplay_->getWMAdaptor()->showFullScreen( this, true );
2196 if( bVisible )
2197 Show( true );
2199 if( mbFullScreen == bFullScreen )
2200 return;
2202 pDisplay_->getWMAdaptor()->showFullScreen( this, bFullScreen );
2206 void X11SalFrame::StartPresentation( bool bStart )
2208 maScreenSaverInhibitor.inhibit( bStart,
2209 "presentation",
2210 true, // isX11
2211 mhWindow,
2212 GetXDisplay() );
2214 if( ! bStart && hPresentationWindow != None )
2215 doReparentPresentationDialogues( GetDisplay() );
2216 hPresentationWindow = (bStart && IsOverrideRedirect() ) ? GetWindow() : None;
2218 if( bStart && hPresentationWindow )
2220 /* #i10559# workaround for WindowMaker: try to restore
2221 * current focus after presentation window is gone
2223 int revert_to = 0;
2224 XGetInputFocus( GetXDisplay(), &hPresFocusWindow, &revert_to );
2228 // Pointer
2230 void X11SalFrame::SetPointer( PointerStyle ePointerStyle )
2232 hCursor_ = pDisplay_->GetPointer( ePointerStyle );
2233 XDefineCursor( GetXDisplay(), GetWindow(), hCursor_ );
2235 if( IsCaptured() || nVisibleFloats > 0 )
2236 XChangeActivePointerGrab( GetXDisplay(),
2237 PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
2238 hCursor_,
2239 CurrentTime );
2242 void X11SalFrame::SetPointerPos(tools::Long nX, tools::Long nY)
2244 /* when the application tries to center the mouse in the dialog the
2245 * window isn't mapped already. So use coordinates relative to the root window.
2247 unsigned int nWindowLeft = maGeometry.nX + nX;
2248 unsigned int nWindowTop = maGeometry.nY + nY;
2250 XWarpPointer( GetXDisplay(), None, pDisplay_->GetRootWindow( pDisplay_->GetDefaultXScreen() ),
2251 0, 0, 0, 0, nWindowLeft, nWindowTop);
2254 // delay handling of extended text input
2255 #if !defined(__synchronous_extinput__)
2256 void
2257 X11SalFrame::HandleExtTextEvent (XClientMessageEvent const *pEvent)
2259 #if SAL_TYPES_SIZEOFLONG > 4
2260 void* pExtTextEvent = reinterpret_cast<void*>( (pEvent->data.l[0] & 0xffffffff)
2261 | (pEvent->data.l[1] << 32) );
2262 #else
2263 void* pExtTextEvent = reinterpret_cast<void*>(pEvent->data.l[0]);
2264 #endif
2265 SalEvent nExtTextEventType = SalEvent(pEvent->data.l[2]);
2267 CallCallback(nExtTextEventType, pExtTextEvent);
2269 switch (nExtTextEventType)
2271 case SalEvent::EndExtTextInput:
2272 break;
2274 case SalEvent::ExtTextInput:
2275 break;
2277 default:
2278 SAL_WARN("vcl.window",
2279 "X11SalFrame::HandleExtTextEvent: invalid extended input.");
2282 #endif /* defined(__synchronous_extinput__) */
2284 // PostEvent
2286 bool X11SalFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData)
2288 GetDisplay()->SendInternalEvent( this, pData.release() );
2289 return true;
2292 // Title
2294 void X11SalFrame::SetTitle( const OUString& rTitle )
2296 if( ! ( IsChildWindow() || (nStyle_ & SalFrameStyleFlags::FLOAT ) ) )
2298 m_aTitle = rTitle;
2299 GetDisplay()->getWMAdaptor()->setWMName( this, rTitle );
2303 void X11SalFrame::Flush()
2305 if( pGraphics_ )
2306 pGraphics_->Flush();
2307 XFlush( GetDisplay()->GetDisplay() );
2310 // Keyboard
2312 void X11SalFrame::SetInputContext( SalInputContext* pContext )
2314 if (pContext == nullptr)
2315 return;
2317 // 1. We should create an input context for this frame
2318 // only when InputContextFlags::Text is set.
2320 if (!(pContext->mnOptions & InputContextFlags::Text))
2322 if( mpInputContext )
2323 mpInputContext->Unmap();
2324 return;
2327 // 2. We should use on-the-spot inputstyle
2328 // only when InputContextFlags::ExtTExt is set.
2330 if (mpInputContext == nullptr)
2332 mpInputContext.reset( new SalI18N_InputContext( this ) );
2333 if (mpInputContext->UseContext())
2335 mpInputContext->ExtendEventMask( GetShellWindow() );
2336 if (mbInputFocus)
2337 mpInputContext->SetICFocus( this );
2340 else
2341 mpInputContext->Map( this );
2344 void X11SalFrame::EndExtTextInput( EndExtTextInputFlags )
2346 if (mpInputContext != nullptr)
2347 mpInputContext->EndExtTextInput();
2350 OUString X11SalFrame::GetKeyName( sal_uInt16 nKeyCode )
2352 return GetDisplay()->GetKeyName( nKeyCode );
2355 bool X11SalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& )
2357 // not supported yet
2358 return false;
2361 LanguageType X11SalFrame::GetInputLanguage()
2363 // could be improved by checking unicode ranges of the last input
2364 return LANGUAGE_DONTKNOW;
2367 // Settings
2369 void X11SalFrame::UpdateSettings( AllSettings& rSettings )
2371 StyleSettings aStyleSettings = rSettings.GetStyleSettings();
2372 aStyleSettings.SetCursorBlinkTime( 500 );
2373 aStyleSettings.SetMenuBarTextColor( aStyleSettings.GetPersonaMenuBarTextColor().value_or( COL_BLACK ) );
2374 rSettings.SetStyleSettings( aStyleSettings );
2377 void X11SalFrame::CaptureMouse( bool bCapture )
2379 nCaptured_ = pDisplay_->CaptureMouse( bCapture ? this : nullptr );
2382 void X11SalFrame::SetParent( SalFrame* pNewParent )
2384 if( mpParent != pNewParent )
2386 if( mpParent )
2387 mpParent->maChildren.remove( this );
2389 mpParent = static_cast<X11SalFrame*>(pNewParent);
2390 mpParent->maChildren.push_back( this );
2391 if( mpParent->m_nXScreen != m_nXScreen )
2392 createNewWindow( None, mpParent->m_nXScreen );
2393 GetDisplay()->getWMAdaptor()->changeReferenceFrame( this, mpParent );
2397 SalFrame* X11SalFrame::GetParent() const
2399 return mpParent;
2402 void X11SalFrame::createNewWindow( ::Window aNewParent, SalX11Screen nXScreen )
2404 bool bWasVisible = bMapped_;
2405 if( bWasVisible )
2406 Show( false );
2408 if( nXScreen.getXScreen() >= GetDisplay()->GetXScreenCount() )
2409 nXScreen = m_nXScreen;
2411 SystemParentData aParentData;
2412 aParentData.nSize = sizeof(SystemParentData);
2413 aParentData.aWindow = aNewParent;
2414 aParentData.bXEmbedSupport = (aNewParent != None && m_bXEmbed); // caution: this is guesswork
2415 if( aNewParent == None )
2417 aParentData.aWindow = None;
2418 m_bXEmbed = false;
2420 else
2422 // is new parent a root window ?
2423 Display* pDisp = GetDisplay()->GetDisplay();
2424 int nScreens = GetDisplay()->GetXScreenCount();
2425 for( int i = 0; i < nScreens; i++ )
2427 if( aNewParent == RootWindow( pDisp, i ) )
2429 nXScreen = SalX11Screen( i );
2430 aParentData.aWindow = None;
2431 m_bXEmbed = false;
2432 break;
2437 // first deinit frame
2438 updateGraphics(true);
2439 if( mpInputContext )
2441 mpInputContext->UnsetICFocus();
2442 mpInputContext->Unmap();
2444 if( GetWindow() == hPresentationWindow )
2446 hPresentationWindow = None;
2447 doReparentPresentationDialogues( GetDisplay() );
2449 XDestroyWindow( GetXDisplay(), mhWindow );
2450 mhWindow = None;
2452 // now init with new parent again
2453 if ( aParentData.aWindow != None )
2454 Init( nStyle_ | SalFrameStyleFlags::PLUG, nXScreen, &aParentData );
2455 else
2456 Init( nStyle_ & ~SalFrameStyleFlags::PLUG, nXScreen, nullptr, true );
2458 // update graphics if necessary
2459 updateGraphics(false);
2461 if( ! m_aTitle.isEmpty() )
2462 SetTitle( m_aTitle );
2464 if( mpParent )
2466 if( mpParent->m_nXScreen != m_nXScreen )
2467 SetParent( nullptr );
2468 else
2469 pDisplay_->getWMAdaptor()->changeReferenceFrame( this, mpParent );
2472 if( bWasVisible )
2473 Show( true );
2475 std::list< X11SalFrame* > aChildren = maChildren;
2476 for (auto const& child : aChildren)
2477 child->createNewWindow( None, m_nXScreen );
2479 // FIXME: SalObjects
2482 bool X11SalFrame::SetPluginParent( SystemParentData* pNewParent )
2484 if( pNewParent->nSize >= sizeof(SystemParentData) )
2485 m_bXEmbed = pNewParent->aWindow != None && pNewParent->bXEmbedSupport;
2487 createNewWindow(pNewParent->aWindow);
2489 return true;
2492 // Sound
2493 void X11SalFrame::Beep()
2495 GetDisplay()->Beep();
2498 // Event Handling
2500 static sal_uInt16 sal_GetCode( int state )
2502 sal_uInt16 nCode = 0;
2504 if( state & Button1Mask )
2505 nCode |= MOUSE_LEFT;
2506 if( state & Button2Mask )
2507 nCode |= MOUSE_MIDDLE;
2508 if( state & Button3Mask )
2509 nCode |= MOUSE_RIGHT;
2511 if( state & ShiftMask )
2512 nCode |= KEY_SHIFT;
2513 if( state & ControlMask )
2514 nCode |= KEY_MOD1;
2515 if( state & Mod1Mask )
2516 nCode |= KEY_MOD2;
2518 // Map Meta/Super modifier to MOD3 on all Unix systems
2519 // except macOS
2520 if( state & Mod3Mask )
2521 nCode |= KEY_MOD3;
2523 return nCode;
2526 SalFrame::SalPointerState X11SalFrame::GetPointerState()
2528 SalPointerState aState;
2529 ::Window aRoot, aChild;
2530 int rx, ry, wx, wy;
2531 unsigned int nMask = 0;
2532 XQueryPointer( GetXDisplay(),
2533 GetShellWindow(),
2534 &aRoot,
2535 &aChild,
2536 &rx, &ry,
2537 &wx, &wy,
2538 &nMask
2541 aState.maPos = Point(wx, wy);
2542 aState.mnState = sal_GetCode( nMask );
2543 return aState;
2546 KeyIndicatorState X11SalFrame::GetIndicatorState()
2548 return vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetIndicatorState();
2551 void X11SalFrame::SimulateKeyPress( sal_uInt16 nKeyCode )
2553 vcl_sal::getSalDisplay(GetGenericUnixSalData())->SimulateKeyPress(nKeyCode);
2556 namespace
2558 struct CompressWheelEventsData
2560 XEvent* firstEvent;
2561 bool ignore;
2562 int count; // number of compressed events
2565 Bool compressWheelEvents( Display*, XEvent* event, XPointer p )
2567 CompressWheelEventsData* data = reinterpret_cast< CompressWheelEventsData* >( p );
2568 if( data->ignore )
2569 return False; // we're already after the events to compress
2570 if( event->type == ButtonPress || event->type == ButtonRelease )
2572 const unsigned int mask = Button1Mask << ( event->xbutton.button - Button1 );
2573 if( event->xbutton.button == data->firstEvent->xbutton.button
2574 && event->xbutton.window == data->firstEvent->xbutton.window
2575 && event->xbutton.x == data->firstEvent->xbutton.x
2576 && event->xbutton.y == data->firstEvent->xbutton.y
2577 && ( event->xbutton.state | mask ) == ( data->firstEvent->xbutton.state | mask ))
2579 // Count if it's another press (i.e. wheel start event).
2580 if( event->type == ButtonPress )
2581 ++data->count;
2582 return True; // And remove the event from the queue.
2585 // Non-matching event, skip certain events that cannot possibly affect input processing,
2586 // but otherwise ignore all further events.
2587 switch( event->type )
2589 case Expose:
2590 case NoExpose:
2591 break;
2592 default:
2593 data->ignore = true;
2594 break;
2596 return False;
2599 } // namespace
2601 bool X11SalFrame::HandleMouseEvent( XEvent *pEvent )
2603 SalMouseEvent aMouseEvt;
2604 SalEvent nEvent = SalEvent::NONE;
2605 bool bClosePopups = false;
2607 if( nVisibleFloats && pEvent->type == EnterNotify )
2608 return false;
2610 if( LeaveNotify == pEvent->type || EnterNotify == pEvent->type )
2613 * some WMs (and/or) applications have a passive grab on
2614 * mouse buttons (XGrabButton). This leads to enter/leave notifies
2615 * with mouse buttons pressed in the state mask before the actual
2616 * ButtonPress event gets dispatched. But EnterNotify
2617 * is reported in vcl as MouseMove event. Some office code
2618 * decides that a pressed button in a MouseMove belongs to
2619 * a drag operation which leads to doing things differently.
2621 * ignore Enter/LeaveNotify resulting from grabs so that
2622 * help windows do not disappear just after appearing
2624 * hopefully this workaround will not break anything.
2626 if( pEvent->xcrossing.mode == NotifyGrab || pEvent->xcrossing.mode == NotifyUngrab )
2627 return false;
2629 aMouseEvt.mnX = pEvent->xcrossing.x;
2630 aMouseEvt.mnY = pEvent->xcrossing.y;
2631 aMouseEvt.mnTime = pEvent->xcrossing.time;
2632 aMouseEvt.mnCode = sal_GetCode( pEvent->xcrossing.state );
2633 aMouseEvt.mnButton = 0;
2635 nEvent = LeaveNotify == pEvent->type
2636 ? SalEvent::MouseLeave
2637 : SalEvent::MouseMove;
2639 else if( pEvent->type == MotionNotify )
2641 aMouseEvt.mnX = pEvent->xmotion.x;
2642 aMouseEvt.mnY = pEvent->xmotion.y;
2643 aMouseEvt.mnTime = pEvent->xmotion.time;
2644 aMouseEvt.mnCode = sal_GetCode( pEvent->xmotion.state );
2646 aMouseEvt.mnButton = 0;
2648 nEvent = SalEvent::MouseMove;
2649 if( nVisibleFloats > 0 && mpParent )
2651 Cursor aCursor = mpParent->GetCursor();
2652 if( pEvent->xmotion.x >= 0 && pEvent->xmotion.x < static_cast<int>(maGeometry.nWidth) &&
2653 pEvent->xmotion.y >= 0 && pEvent->xmotion.y < static_cast<int>(maGeometry.nHeight) )
2654 aCursor = None;
2656 XChangeActivePointerGrab( GetXDisplay(),
2657 PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
2658 aCursor,
2659 CurrentTime );
2662 else
2664 // let mouse events reach the correct window
2665 if( nVisibleFloats < 1 )
2667 if( ! (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION) )
2668 XUngrabPointer( GetXDisplay(), CurrentTime );
2670 else if( pEvent->type == ButtonPress )
2672 // see if the user clicks outside all of the floats
2673 // if yes release the grab
2674 bool bInside = false;
2675 for (auto pSalFrame : GetDisplay()->getFrames() )
2677 const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame );
2678 if( pFrame->IsFloatGrabWindow() &&
2679 pFrame->bMapped_ &&
2680 pEvent->xbutton.x_root >= pFrame->maGeometry.nX &&
2681 pEvent->xbutton.x_root < pFrame->maGeometry.nX + static_cast<int>(pFrame->maGeometry.nWidth) &&
2682 pEvent->xbutton.y_root >= pFrame->maGeometry.nY &&
2683 pEvent->xbutton.y_root < pFrame->maGeometry.nY + static_cast<int>(pFrame->maGeometry.nHeight) )
2685 bInside = true;
2686 break;
2689 if( ! bInside )
2691 // need not take care of the XUngrabPointer in Show( false )
2692 // because XUngrabPointer does not produce errors if pointer
2693 // is not grabbed
2694 XUngrabPointer( GetXDisplay(), CurrentTime );
2695 bClosePopups = true;
2697 /* #i15246# only close popups if pointer is outside all our frames
2698 * cannot use our own geometry data here because stacking
2699 * is unknown (the above case implicitly assumes
2700 * that floats are on top which should be true)
2702 ::Window aRoot, aChild;
2703 int root_x, root_y, win_x, win_y;
2704 unsigned int mask_return;
2705 if( XQueryPointer( GetXDisplay(),
2706 GetDisplay()->GetRootWindow( m_nXScreen ),
2707 &aRoot, &aChild,
2708 &root_x, &root_y,
2709 &win_x, &win_y,
2710 &mask_return )
2711 && aChild // pointer may not be in any child
2714 for (auto pSalFrame : GetDisplay()->getFrames() )
2716 const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame );
2717 if( ! pFrame->IsFloatGrabWindow()
2718 && ( pFrame->GetWindow() == aChild ||
2719 pFrame->GetShellWindow() == aChild ||
2720 pFrame->GetStackingWindow() == aChild )
2723 // #i63638# check that pointer is inside window, not
2724 // only inside stacking window
2725 if( root_x >= pFrame->maGeometry.nX && root_x < sal::static_int_cast< int >(pFrame->maGeometry.nX+pFrame->maGeometry.nWidth) &&
2726 root_y >= pFrame->maGeometry.nY && root_y < sal::static_int_cast< int >(pFrame->maGeometry.nX+pFrame->maGeometry.nHeight) )
2728 bClosePopups = false;
2730 break;
2737 if( m_bXEmbed && pEvent->xbutton.button == Button1 )
2738 askForXEmbedFocus( pEvent->xbutton.time );
2740 if( pEvent->xbutton.button == Button1 ||
2741 pEvent->xbutton.button == Button2 ||
2742 pEvent->xbutton.button == Button3 )
2744 aMouseEvt.mnX = pEvent->xbutton.x;
2745 aMouseEvt.mnY = pEvent->xbutton.y;
2746 aMouseEvt.mnTime = pEvent->xbutton.time;
2747 aMouseEvt.mnCode = sal_GetCode( pEvent->xbutton.state );
2749 if( Button1 == pEvent->xbutton.button )
2750 aMouseEvt.mnButton = MOUSE_LEFT;
2751 else if( Button2 == pEvent->xbutton.button )
2752 aMouseEvt.mnButton = MOUSE_MIDDLE;
2753 else if( Button3 == pEvent->xbutton.button )
2754 aMouseEvt.mnButton = MOUSE_RIGHT;
2756 nEvent = ButtonPress == pEvent->type
2757 ? SalEvent::MouseButtonDown
2758 : SalEvent::MouseButtonUp;
2760 else if( pEvent->xbutton.button == Button4 ||
2761 pEvent->xbutton.button == Button5 ||
2762 pEvent->xbutton.button == Button6 ||
2763 pEvent->xbutton.button == Button7 )
2765 const bool bIncrement(
2766 pEvent->xbutton.button == Button4 ||
2767 pEvent->xbutton.button == Button6 );
2768 const bool bHoriz(
2769 pEvent->xbutton.button == Button6 ||
2770 pEvent->xbutton.button == Button7 );
2772 if( pEvent->type == ButtonRelease )
2773 return false;
2775 static sal_uLong nLines = 0;
2776 if( ! nLines )
2778 char* pEnv = getenv( "SAL_WHEELLINES" );
2779 nLines = pEnv ? atoi( pEnv ) : 3;
2780 if( nLines > 10 )
2781 nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
2784 // Compress consecutive wheel events (way too fine scrolling may cause lags if one scrolling steps takes long).
2785 CompressWheelEventsData data;
2786 data.firstEvent = pEvent;
2787 data.count = 1;
2788 XEvent dummy;
2791 data.ignore = false;
2792 } while( XCheckIfEvent( pEvent->xany.display, &dummy, compressWheelEvents, reinterpret_cast< XPointer >( &data )));
2794 SalWheelMouseEvent aWheelEvt;
2795 aWheelEvt.mnTime = pEvent->xbutton.time;
2796 aWheelEvt.mnX = pEvent->xbutton.x;
2797 aWheelEvt.mnY = pEvent->xbutton.y;
2798 aWheelEvt.mnDelta = ( bIncrement ? 120 : -120 ) * data.count;
2799 aWheelEvt.mnNotchDelta = bIncrement ? 1 : -1;
2800 aWheelEvt.mnScrollLines = nLines * data.count;
2801 aWheelEvt.mnCode = sal_GetCode( pEvent->xbutton.state );
2802 aWheelEvt.mbHorz = bHoriz;
2804 nEvent = SalEvent::WheelMouse;
2806 if( AllSettings::GetLayoutRTL() )
2807 aWheelEvt.mnX = nWidth_-1-aWheelEvt.mnX;
2808 return CallCallback( nEvent, &aWheelEvt );
2812 bool nRet = false;
2813 if( nEvent == SalEvent::MouseLeave
2814 || ( aMouseEvt.mnX < nWidth_ && aMouseEvt.mnX > -1 &&
2815 aMouseEvt.mnY < nHeight_ && aMouseEvt.mnY > -1 )
2816 || pDisplay_->MouseCaptured( this )
2819 if( AllSettings::GetLayoutRTL() )
2820 aMouseEvt.mnX = nWidth_-1-aMouseEvt.mnX;
2821 nRet = CallCallback( nEvent, &aMouseEvt );
2824 if( bClosePopups )
2826 /* #108213# close popups after dispatching the event outside the popup;
2827 * applications do weird things.
2829 ImplSVData* pSVData = ImplGetSVData();
2830 if (pSVData->mpWinData->mpFirstFloat)
2832 if (!(pSVData->mpWinData->mpFirstFloat->GetPopupModeFlags()
2833 & FloatWinPopupFlags::NoAppFocusClose))
2834 pSVData->mpWinData->mpFirstFloat->EndPopupMode(FloatWinPopupEndFlags::Cancel
2835 | FloatWinPopupEndFlags::CloseAll);
2839 return nRet;
2842 namespace {
2844 // F10 means either KEY_F10 or KEY_MENU, which has to be decided
2845 // in the independent part.
2846 struct KeyAlternate
2848 sal_uInt16 nKeyCode;
2849 sal_Unicode nCharCode;
2850 KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
2851 KeyAlternate( sal_uInt16 nKey, sal_Unicode nChar = 0 ) : nKeyCode( nKey ), nCharCode( nChar ) {}
2856 static KeyAlternate
2857 GetAlternateKeyCode( const sal_uInt16 nKeyCode )
2859 KeyAlternate aAlternate;
2861 switch( nKeyCode )
2863 case KEY_F10: aAlternate = KeyAlternate( KEY_MENU );break;
2864 case KEY_F24: aAlternate = KeyAlternate( KEY_SUBTRACT, '-' );break;
2867 return aAlternate;
2870 void X11SalFrame::beginUnicodeSequence()
2872 OUString& rSeq( GetGenericUnixSalData()->GetUnicodeCommand() );
2873 vcl::DeletionListener aDeleteWatch( this );
2875 if( !rSeq.isEmpty() )
2876 endUnicodeSequence();
2878 rSeq = "u";
2880 if( ! aDeleteWatch.isDeleted() )
2882 ExtTextInputAttr nTextAttr = ExtTextInputAttr::Underline;
2883 SalExtTextInputEvent aEv;
2884 aEv.maText = rSeq;
2885 aEv.mpTextAttr = &nTextAttr;
2886 aEv.mnCursorPos = 0;
2887 aEv.mnCursorFlags = 0;
2889 CallCallback(SalEvent::ExtTextInput, static_cast<void*>(&aEv));
2893 bool X11SalFrame::appendUnicodeSequence( sal_Unicode c )
2895 bool bRet = false;
2896 OUString& rSeq( GetGenericUnixSalData()->GetUnicodeCommand() );
2897 if( !rSeq.isEmpty() )
2899 // range check
2900 if( (c >= '0' && c <= '9') ||
2901 (c >= 'a' && c <= 'f') ||
2902 (c >= 'A' && c <= 'F') )
2904 rSeq += OUStringChar(c);
2905 std::vector<ExtTextInputAttr> attribs( rSeq.getLength(), ExtTextInputAttr::Underline );
2907 SalExtTextInputEvent aEv;
2908 aEv.maText = rSeq;
2909 aEv.mpTextAttr = attribs.data();
2910 aEv.mnCursorPos = 0;
2911 aEv.mnCursorFlags = 0;
2913 CallCallback(SalEvent::ExtTextInput, static_cast<void*>(&aEv));
2914 bRet = true;
2916 else
2917 bRet = endUnicodeSequence();
2919 else
2920 endUnicodeSequence();
2921 return bRet;
2924 bool X11SalFrame::endUnicodeSequence()
2926 OUString& rSeq( GetGenericUnixSalData()->GetUnicodeCommand() );
2928 vcl::DeletionListener aDeleteWatch( this );
2929 if( rSeq.getLength() > 1 && rSeq.getLength() < 6 )
2931 // cut the "u"
2932 OUString aNumbers( rSeq.copy( 1 ) );
2933 sal_uInt32 nValue = aNumbers.toUInt32( 16 );
2934 if( nValue >= 32 )
2936 ExtTextInputAttr nTextAttr = ExtTextInputAttr::Underline;
2937 SalExtTextInputEvent aEv;
2938 aEv.maText = OUString( sal_Unicode(nValue) );
2939 aEv.mpTextAttr = &nTextAttr;
2940 aEv.mnCursorPos = 0;
2941 aEv.mnCursorFlags = 0;
2942 CallCallback(SalEvent::ExtTextInput, static_cast<void*>(&aEv));
2945 bool bWasInput = !rSeq.isEmpty();
2946 rSeq.clear();
2947 if( bWasInput && ! aDeleteWatch.isDeleted() )
2948 CallCallback(SalEvent::EndExtTextInput, nullptr);
2949 return bWasInput;
2952 bool X11SalFrame::HandleKeyEvent( XKeyEvent *pEvent )
2954 if( pEvent->type == KeyRelease )
2956 // Ignore autorepeat keyrelease events. If there is a series of keypress+keyrelease+keypress events
2957 // generated by holding down a key, and if these are from autorepeat (keyrelease and the following keypress
2958 // have the same timestamp), drop the autorepeat keyrelease event. Not exactly sure why this is done
2959 // (possibly hiding differences between platforms, or just making it more sensible, because technically
2960 // the key has not been released at all).
2961 bool ignore = false;
2962 // Discard queued excessive autorepeat events.
2963 // If the user presses and holds down a key, the autorepeating keypress events
2964 // may overload LO (e.g. if the key is PageDown and the LO cannot keep up scrolling).
2965 // Reduce the load by simply discarding such excessive events (so for a KeyRelease event,
2966 // check if it's followed by matching KeyPress+KeyRelease pair(s) and discard those).
2967 // This shouldn't have any negative effects - unlike with normal (non-autorepeat
2968 // events), the user is unlikely to rely on the exact number of resulting actions
2969 // (since autorepeat generates keypress events rather quickly and it's hard to estimate
2970 // how many exactly) and the idea should be just keeping the key pressed until something
2971 // happens (in which case more events that just lag LO shouldn't make a difference).
2972 Display* dpy = pEvent->display;
2973 XKeyEvent previousRelease = *pEvent;
2974 while( XPending( dpy ))
2976 XEvent nextEvent1;
2977 bool discard1 = false;
2978 XNextEvent( dpy, &nextEvent1 );
2979 if( nextEvent1.type == KeyPress && nextEvent1.xkey.time == previousRelease.time
2980 && !nextEvent1.xkey.send_event && nextEvent1.xkey.window == previousRelease.window
2981 && nextEvent1.xkey.state == previousRelease.state && nextEvent1.xkey.keycode == previousRelease.keycode )
2982 { // This looks like another autorepeat keypress.
2983 ignore = true;
2984 if( XPending( dpy ))
2986 XEvent nextEvent2;
2987 XNextEvent( dpy, &nextEvent2 );
2988 if( nextEvent2.type == KeyRelease && nextEvent2.xkey.time <= ( previousRelease.time + 100 )
2989 && !nextEvent2.xkey.send_event && nextEvent2.xkey.window == previousRelease.window
2990 && nextEvent2.xkey.state == previousRelease.state && nextEvent2.xkey.keycode == previousRelease.keycode )
2991 { // And the matching keyrelease -> drop them both.
2992 discard1 = true;
2993 previousRelease = nextEvent2.xkey;
2994 ignore = false; // There either will be another autorepeating keypress that'll lead to discarding
2995 // the pEvent keyrelease, it this discarding makes that keyrelease the last one.
2997 else
2999 XPutBackEvent( dpy, &nextEvent2 );
3000 break;
3004 if( !discard1 )
3005 { // Unrelated event, put back and stop compressing.
3006 XPutBackEvent( dpy, &nextEvent1 );
3007 break;
3010 if( ignore ) // This autorepeating keyrelease is followed by another keypress.
3011 return false;
3014 KeySym nKeySym;
3015 KeySym nUnmodifiedKeySym;
3016 int nLen = 2048;
3017 char *pPrintable = static_cast<char*>(alloca( nLen ));
3019 // singlebyte code composed by input method, the new default
3020 if (mpInputContext != nullptr && mpInputContext->UseContext())
3022 // returns a keysym as well as the pPrintable (in system encoding)
3023 // printable may be empty.
3024 Status nStatus;
3025 nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen,
3026 &nUnmodifiedKeySym,
3027 &nStatus, mpInputContext->GetContext() );
3028 if ( nStatus == XBufferOverflow )
3030 // In case of overflow, XmbLookupString (called by GetKeySym)
3031 // returns required size
3032 // TODO : check if +1 is needed for 0 terminator
3033 nLen += 1;
3034 pPrintable = static_cast<char*>(alloca( nLen ));
3035 nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen,
3036 &nUnmodifiedKeySym,
3037 &nStatus, mpInputContext->GetContext() );
3040 else
3042 // fallback, this should never ever be called
3043 Status nStatus = 0;
3044 nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen, &nUnmodifiedKeySym, &nStatus );
3047 SalKeyEvent aKeyEvt;
3048 sal_uInt16 nKeyCode;
3049 sal_uInt16 nModCode = 0;
3050 char aDummy;
3052 if( pEvent->state & ShiftMask )
3053 nModCode |= KEY_SHIFT;
3054 if( pEvent->state & ControlMask )
3055 nModCode |= KEY_MOD1;
3056 if( pEvent->state & Mod1Mask )
3057 nModCode |= KEY_MOD2;
3059 if( nModCode != (KEY_SHIFT|KEY_MOD1) )
3060 endUnicodeSequence();
3062 if( nKeySym == XK_Shift_L || nKeySym == XK_Shift_R
3063 || nKeySym == XK_Control_L || nKeySym == XK_Control_R
3064 || nKeySym == XK_Alt_L || nKeySym == XK_Alt_R
3065 || nKeySym == XK_Meta_L || nKeySym == XK_Meta_R
3066 || nKeySym == XK_Super_L || nKeySym == XK_Super_R )
3068 SalKeyModEvent aModEvt;
3069 aModEvt.mbDown = false; // auto-accelerator feature not supported here.
3070 aModEvt.mnModKeyCode = ModKeyFlags::NONE;
3071 if( pEvent->type == KeyPress && mnExtKeyMod == ModKeyFlags::NONE )
3072 mbSendExtKeyModChange = true;
3073 else if( pEvent->type == KeyRelease && mbSendExtKeyModChange )
3075 aModEvt.mnModKeyCode = mnExtKeyMod;
3076 mnExtKeyMod = ModKeyFlags::NONE;
3079 // pressing just the ctrl key leads to a keysym of XK_Control but
3080 // the event state does not contain ControlMask. In the release
3081 // event it's the other way round: it does contain the Control mask.
3082 // The modifier mode therefore has to be adapted manually.
3083 ModKeyFlags nExtModMask = ModKeyFlags::NONE;
3084 sal_uInt16 nModMask = 0;
3085 switch( nKeySym )
3087 case XK_Control_L:
3088 nExtModMask = ModKeyFlags::LeftMod1;
3089 nModMask = KEY_MOD1;
3090 break;
3091 case XK_Control_R:
3092 nExtModMask = ModKeyFlags::RightMod1;
3093 nModMask = KEY_MOD1;
3094 break;
3095 case XK_Alt_L:
3096 nExtModMask = ModKeyFlags::LeftMod2;
3097 nModMask = KEY_MOD2;
3098 break;
3099 case XK_Alt_R:
3100 nExtModMask = ModKeyFlags::RightMod2;
3101 nModMask = KEY_MOD2;
3102 break;
3103 case XK_Shift_L:
3104 nExtModMask = ModKeyFlags::LeftShift;
3105 nModMask = KEY_SHIFT;
3106 break;
3107 case XK_Shift_R:
3108 nExtModMask = ModKeyFlags::RightShift;
3109 nModMask = KEY_SHIFT;
3110 break;
3111 // Map Meta/Super keys to MOD3 modifier on all Unix systems
3112 // except macOS
3113 case XK_Meta_L:
3114 case XK_Super_L:
3115 nExtModMask = ModKeyFlags::LeftMod3;
3116 nModMask = KEY_MOD3;
3117 break;
3118 case XK_Meta_R:
3119 case XK_Super_R:
3120 nExtModMask = ModKeyFlags::RightMod3;
3121 nModMask = KEY_MOD3;
3122 break;
3124 if( pEvent->type == KeyRelease )
3126 nModCode &= ~nModMask;
3127 mnExtKeyMod &= ~nExtModMask;
3129 else
3131 nModCode |= nModMask;
3132 mnExtKeyMod |= nExtModMask;
3135 aModEvt.mnCode = nModCode;
3137 return CallCallback( SalEvent::KeyModChange, &aModEvt );
3140 mbSendExtKeyModChange = false;
3142 // try to figure out the vcl code for the keysym
3143 // #i52338# use the unmodified KeySym if there is none for the real KeySym
3144 // because the independent part has only keycodes for unshifted keys
3145 nKeyCode = pDisplay_->GetKeyCode( nKeySym, &aDummy );
3146 if( nKeyCode == 0 )
3147 nKeyCode = pDisplay_->GetKeyCode( nUnmodifiedKeySym, &aDummy );
3149 // try to figure out a printable if XmbLookupString returns only a keysym
3150 // and NOT a printable. Do not store it in pPrintable[0] since it is expected to
3151 // be in system encoding, not unicode.
3152 // #i8988##, if KeySym and printable look equally promising then prefer KeySym
3153 // the printable is bound to the encoding so the KeySym might contain more
3154 // information (in et_EE locale: "Compose + Z + <" delivers "," in printable and
3155 // (the desired) Zcaron in KeySym
3156 sal_Unicode nKeyString = 0x0;
3157 if ( (nLen == 0)
3158 || ((nLen == 1) && (nKeySym > 0)) )
3159 nKeyString = KeysymToUnicode (nKeySym);
3160 // if we have nothing we give up
3161 if( !nKeyCode && !nLen && !nKeyString)
3162 return false;
3164 vcl::DeletionListener aDeleteWatch( this );
3166 if( nModCode == (KEY_SHIFT | KEY_MOD1) && pEvent->type == KeyPress )
3168 sal_uInt16 nSeqKeyCode = pDisplay_->GetKeyCode( nUnmodifiedKeySym, &aDummy );
3169 if( nSeqKeyCode == KEY_U )
3171 beginUnicodeSequence();
3172 return true;
3174 else if( nSeqKeyCode >= KEY_0 && nSeqKeyCode <= KEY_9 )
3176 if( appendUnicodeSequence( u'0' + sal_Unicode(nSeqKeyCode - KEY_0) ) )
3177 return true;
3179 else if( nSeqKeyCode >= KEY_A && nSeqKeyCode <= KEY_F )
3181 if( appendUnicodeSequence( u'a' + sal_Unicode(nSeqKeyCode - KEY_A) ) )
3182 return true;
3184 else
3185 endUnicodeSequence();
3188 if( aDeleteWatch.isDeleted() )
3189 return false;
3191 rtl_TextEncoding nEncoding = osl_getThreadTextEncoding();
3193 sal_Unicode *pBuffer;
3194 sal_Unicode *pString;
3195 sal_Size nBufferSize = nLen * 2;
3196 sal_Size nSize;
3197 pBuffer = static_cast<sal_Unicode*>(malloc( nBufferSize + 2 ));
3198 pBuffer[ 0 ] = 0;
3200 if (nKeyString != 0)
3202 pString = &nKeyString;
3203 nSize = 1;
3205 else if (nLen > 0 && nEncoding != RTL_TEXTENCODING_UNICODE)
3207 // create text converter
3208 rtl_TextToUnicodeConverter aConverter =
3209 rtl_createTextToUnicodeConverter( nEncoding );
3210 rtl_TextToUnicodeContext aContext =
3211 rtl_createTextToUnicodeContext( aConverter );
3213 sal_uInt32 nConversionInfo;
3214 sal_Size nConvertedChars;
3216 // convert to single byte text stream
3217 nSize = rtl_convertTextToUnicode(
3218 aConverter, aContext,
3219 reinterpret_cast<char*>(pPrintable), nLen,
3220 pBuffer, nBufferSize,
3221 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE |
3222 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE,
3223 &nConversionInfo, &nConvertedChars );
3225 // destroy converter
3226 rtl_destroyTextToUnicodeContext( aConverter, aContext );
3227 rtl_destroyTextToUnicodeConverter( aConverter );
3229 pString = pBuffer;
3231 else if (nLen > 0 /* nEncoding == RTL_TEXTENCODING_UNICODE */)
3233 pString = reinterpret_cast<sal_Unicode*>(pPrintable);
3234 nSize = nLen;
3236 else
3238 pString = pBuffer;
3239 nSize = 0;
3242 if ( mpInputContext != nullptr
3243 && mpInputContext->UseContext()
3244 && KeyRelease != pEvent->type
3245 && ( (nSize > 1)
3246 || (nSize > 0 && mpInputContext->IsPreeditMode())) )
3248 mpInputContext->CommitKeyEvent(pString, nSize);
3250 else
3251 // normal single character keyinput
3253 aKeyEvt.mnCode = nKeyCode | nModCode;
3254 aKeyEvt.mnRepeat = 0;
3255 aKeyEvt.mnCharCode = pString[ 0 ];
3257 if( KeyRelease == pEvent->type )
3259 CallCallback( SalEvent::KeyUp, &aKeyEvt );
3261 else
3263 if ( ! CallCallback(SalEvent::KeyInput, &aKeyEvt) )
3265 // independent layer doesn't want to handle key-event, so check
3266 // whether the keycode may have an alternate meaning
3267 KeyAlternate aAlternate = GetAlternateKeyCode( nKeyCode );
3268 if ( aAlternate.nKeyCode != 0 )
3270 aKeyEvt.mnCode = aAlternate.nKeyCode | nModCode;
3271 if( aAlternate.nCharCode )
3272 aKeyEvt.mnCharCode = aAlternate.nCharCode;
3273 CallCallback(SalEvent::KeyInput, &aKeyEvt);
3279 // update the spot location for PreeditPosition IME style
3281 if (! aDeleteWatch.isDeleted())
3283 if (mpInputContext != nullptr && mpInputContext->UseContext())
3284 mpInputContext->UpdateSpotLocation();
3287 free (pBuffer);
3288 return true;
3291 bool X11SalFrame::HandleFocusEvent( XFocusChangeEvent const *pEvent )
3293 // ReflectionX in Windows mode changes focus while mouse is grabbed
3294 if( nVisibleFloats > 0 && GetDisplay()->getWMAdaptor()->getWindowManagerName() == "ReflectionX Windows" )
3295 return true;
3297 /* ignore focusout resulting from keyboard grabs
3298 * we do not grab it and are not interested when
3299 * someone else does CDE e.g. does a XGrabKey on arrow keys
3300 * handle focus events with mode NotifyWhileGrabbed
3301 * because with CDE alt-tab focus changing we do not get
3302 * normal focus events
3303 * cast focus event to the input context, otherwise the
3304 * status window does not follow the application frame
3307 if ( mpInputContext != nullptr )
3309 if( FocusIn == pEvent->type )
3310 mpInputContext->SetICFocus( this );
3313 if ( pEvent->mode == NotifyNormal || pEvent->mode == NotifyWhileGrabbed ||
3314 ( ( nStyle_ & SalFrameStyleFlags::PLUG ) && pEvent->window == GetShellWindow() )
3317 if( hPresentationWindow != None && hPresentationWindow != GetShellWindow() )
3318 return false;
3320 if( FocusIn == pEvent->type )
3322 GetSalData()->m_pInstance->updatePrinterUpdate();
3323 mbInputFocus = True;
3324 ImplSVData* pSVData = ImplGetSVData();
3326 bool nRet = CallCallback( SalEvent::GetFocus, nullptr );
3327 if ((mpParent != nullptr && nStyle_ == SalFrameStyleFlags::NONE)
3328 && pSVData->mpWinData->mpFirstFloat)
3330 FloatWinPopupFlags nMode = pSVData->mpWinData->mpFirstFloat->GetPopupModeFlags();
3331 pSVData->mpWinData->mpFirstFloat->SetPopupModeFlags(
3332 nMode & ~FloatWinPopupFlags::NoAppFocusClose);
3334 return nRet;
3336 else
3338 mbInputFocus = False;
3339 mbSendExtKeyModChange = false;
3340 mnExtKeyMod = ModKeyFlags::NONE;
3341 return CallCallback( SalEvent::LoseFocus, nullptr );
3345 return false;
3348 bool X11SalFrame::HandleExposeEvent( XEvent const *pEvent )
3350 XRectangle aRect = { 0, 0, 0, 0 };
3351 sal_uInt16 nCount = 0;
3353 if( pEvent->type == Expose )
3355 aRect.x = pEvent->xexpose.x;
3356 aRect.y = pEvent->xexpose.y;
3357 aRect.width = pEvent->xexpose.width;
3358 aRect.height = pEvent->xexpose.height;
3359 nCount = pEvent->xexpose.count;
3361 else if( pEvent->type == GraphicsExpose )
3363 aRect.x = pEvent->xgraphicsexpose.x;
3364 aRect.y = pEvent->xgraphicsexpose.y;
3365 aRect.width = pEvent->xgraphicsexpose.width;
3366 aRect.height = pEvent->xgraphicsexpose.height;
3367 nCount = pEvent->xgraphicsexpose.count;
3370 if( IsOverrideRedirect() && mbFullScreen &&
3371 aPresentationReparentList.empty() )
3372 // we are in fullscreen mode -> override redirect
3373 // focus is possibly lost, so reget it
3374 XSetInputFocus( GetXDisplay(), GetShellWindow(), RevertToNone, CurrentTime );
3376 // width and height are extents, so they are of by one for rectangle
3377 maPaintRegion.Union( tools::Rectangle( Point(aRect.x, aRect.y), Size(aRect.width+1, aRect.height+1) ) );
3379 if( nCount )
3380 // wait for last expose rectangle, do not wait for resize timer
3381 // if a completed graphics expose sequence is available
3382 return true;
3384 SalPaintEvent aPEvt( maPaintRegion.Left(), maPaintRegion.Top(), maPaintRegion.GetWidth(), maPaintRegion.GetHeight() );
3386 CallCallback( SalEvent::Paint, &aPEvt );
3387 maPaintRegion = tools::Rectangle();
3389 return true;
3392 void X11SalFrame::RestackChildren( ::Window* pTopLevelWindows, int nTopLevelWindows )
3394 if( maChildren.empty() )
3395 return;
3397 int nWindow = nTopLevelWindows;
3398 while( nWindow-- )
3399 if( pTopLevelWindows[nWindow] == GetStackingWindow() )
3400 break;
3401 if( nWindow < 0 )
3402 return;
3404 for (auto const& child : maChildren)
3406 if( child->bMapped_ )
3408 int nChild = nWindow;
3409 while( nChild-- )
3411 if( pTopLevelWindows[nChild] == child->GetStackingWindow() )
3413 // if a child is behind its parent, place it above the
3414 // parent (for insane WMs like Dtwm and olwm)
3415 XWindowChanges aCfg;
3416 aCfg.sibling = GetStackingWindow();
3417 aCfg.stack_mode = Above;
3418 XConfigureWindow( GetXDisplay(), child->GetStackingWindow(), CWSibling|CWStackMode, &aCfg );
3419 break;
3424 for (auto const& child : maChildren)
3426 child->RestackChildren( pTopLevelWindows, nTopLevelWindows );
3430 void X11SalFrame::RestackChildren()
3432 if( maChildren.empty() )
3433 return;
3435 ::Window aRoot, aParent, *pChildren = nullptr;
3436 unsigned int nChildren;
3437 if( XQueryTree( GetXDisplay(),
3438 GetDisplay()->GetRootWindow( m_nXScreen ),
3439 &aRoot,
3440 &aParent,
3441 &pChildren,
3442 &nChildren ) )
3444 RestackChildren( pChildren, nChildren );
3445 XFree( pChildren );
3449 static Bool size_event_predicate( Display*, XEvent* event, XPointer arg )
3451 if( event->type != ConfigureNotify )
3452 return False;
3453 X11SalFrame* frame = reinterpret_cast< X11SalFrame* >( arg );
3454 XConfigureEvent* pEvent = &event->xconfigure;
3455 if( pEvent->window != frame->GetShellWindow()
3456 && pEvent->window != frame->GetWindow()
3457 && pEvent->window != frame->GetForeignParent()
3458 && pEvent->window != frame->GetStackingWindow())
3459 { // ignored at top of HandleSizeEvent()
3460 return False;
3462 if( pEvent->window == frame->GetStackingWindow())
3463 return False; // filtered later in HandleSizeEvent()
3464 // at this point we know that there is another similar event in the queue
3465 frame->setPendingSizeEvent();
3466 return False; // but do not process the new event out of order
3469 void X11SalFrame::setPendingSizeEvent()
3471 mPendingSizeEvent = true;
3474 bool X11SalFrame::HandleSizeEvent( XConfigureEvent *pEvent )
3476 // NOTE: if you add more tests in this function, make sure to update size_event_predicate()
3477 // so that it finds exactly the same events
3479 if ( pEvent->window != GetShellWindow()
3480 && pEvent->window != GetWindow()
3481 && pEvent->window != GetForeignParent()
3482 && pEvent->window != GetStackingWindow()
3485 // could be as well a sys-child window (aka SalObject)
3486 return true;
3489 if( ( nStyle_ & SalFrameStyleFlags::PLUG ) && pEvent->window == GetShellWindow() )
3491 // just update the children's positions
3492 RestackChildren();
3493 return true;
3496 if( pEvent->window == GetForeignParent() )
3497 XResizeWindow( GetXDisplay(),
3498 GetWindow(),
3499 pEvent->width,
3500 pEvent->height );
3502 ::Window hDummy;
3503 XTranslateCoordinates( GetXDisplay(),
3504 GetWindow(),
3505 pDisplay_->GetRootWindow( pDisplay_->GetDefaultXScreen() ),
3506 0, 0,
3507 &pEvent->x, &pEvent->y,
3508 &hDummy );
3510 if( pEvent->window == GetStackingWindow() )
3512 if( maGeometry.nX != pEvent->x || maGeometry.nY != pEvent->y )
3514 maGeometry.nX = pEvent->x;
3515 maGeometry.nY = pEvent->y;
3516 CallCallback( SalEvent::Move, nullptr );
3518 return true;
3521 // check size hints in first time SalFrame::Show
3522 if( SHOWSTATE_UNKNOWN == nShowState_ && bMapped_ )
3523 nShowState_ = SHOWSTATE_NORMAL;
3525 // Avoid a race condition where resizing this window to one size and shortly after that
3526 // to another size generates first size event with the old size and only after that
3527 // with the new size, temporarily making us think the old size is valid (bnc#674806).
3528 // So if there is another size event for this window pending, ignore this one.
3529 mPendingSizeEvent = false;
3530 XEvent dummy;
3531 XCheckIfEvent( GetXDisplay(), &dummy, size_event_predicate, reinterpret_cast< XPointer >( this ));
3532 if( mPendingSizeEvent )
3533 return true;
3535 nWidth_ = pEvent->width;
3536 nHeight_ = pEvent->height;
3538 bool bMoved = ( pEvent->x != maGeometry.nX || pEvent->y != maGeometry.nY );
3539 bool bSized = ( pEvent->width != static_cast<int>(maGeometry.nWidth) || pEvent->height != static_cast<int>(maGeometry.nHeight) );
3541 maGeometry.nX = pEvent->x;
3542 maGeometry.nY = pEvent->y;
3543 maGeometry.nWidth = pEvent->width;
3544 maGeometry.nHeight = pEvent->height;
3545 updateScreenNumber();
3547 // update children's position
3548 RestackChildren();
3550 if( bSized && ! bMoved )
3551 CallCallback( SalEvent::Resize, nullptr );
3552 else if( bMoved && ! bSized )
3553 CallCallback( SalEvent::Move, nullptr );
3554 else if( bMoved && bSized )
3555 CallCallback( SalEvent::MoveResize, nullptr );
3557 return true;
3560 IMPL_LINK_NOARG(X11SalFrame, HandleAlwaysOnTopRaise, Timer *, void)
3562 if( bMapped_ )
3563 ToTop( SalFrameToTop::NONE );
3566 bool X11SalFrame::HandleReparentEvent( XReparentEvent *pEvent )
3568 Display *pDisplay = pEvent->display;
3569 ::Window hWM_Parent;
3570 ::Window hRoot, *Children, hDummy;
3571 unsigned int nChildren;
3573 static const char* pDisableStackingCheck = getenv( "SAL_DISABLE_STACKING_CHECK" );
3575 GetGenericUnixSalData()->ErrorTrapPush();
3578 * don't rely on the new parent from the event.
3579 * the event may be "out of date", that is the window manager
3580 * window may not exist anymore. This can happen if someone
3581 * shows a frame and hides it again quickly (not that it would
3582 * be very sensible)
3584 hWM_Parent = GetShellWindow();
3587 Children = nullptr;
3588 XQueryTree( pDisplay,
3589 hWM_Parent,
3590 &hRoot,
3591 &hDummy,
3592 &Children,
3593 &nChildren );
3595 bool bError = GetGenericUnixSalData()->ErrorTrapPop( false );
3596 GetGenericUnixSalData()->ErrorTrapPush();
3598 if( bError )
3600 hWM_Parent = GetShellWindow();
3601 break;
3603 /* this sometimes happens if a Show(true) is
3604 * immediately followed by Show(false) (which is braindead anyway)
3606 if( hDummy == hWM_Parent )
3607 hDummy = hRoot;
3608 if( hDummy != hRoot )
3609 hWM_Parent = hDummy;
3610 if( Children )
3611 XFree( Children );
3612 } while( hDummy != hRoot );
3614 if( GetStackingWindow() == None
3615 && hWM_Parent != hPresentationWindow
3616 && hWM_Parent != GetShellWindow()
3617 && ( ! pDisableStackingCheck || ! *pDisableStackingCheck )
3620 mhStackingWindow = hWM_Parent;
3621 XSelectInput( pDisplay, GetStackingWindow(), StructureNotifyMask );
3624 if( hWM_Parent == pDisplay_->GetRootWindow( pDisplay_->GetDefaultXScreen() )
3625 || hWM_Parent == GetForeignParent()
3626 || pEvent->parent == pDisplay_->GetRootWindow( pDisplay_->GetDefaultXScreen() )
3627 || ( nStyle_ & SalFrameStyleFlags::FLOAT ) )
3629 // Reparenting before Destroy
3630 aPresentationReparentList.remove( GetStackingWindow() );
3631 mhStackingWindow = None;
3632 GetGenericUnixSalData()->ErrorTrapPop();
3633 return false;
3637 * evil hack to show decorated windows on top
3638 * of override redirect presentation windows:
3639 * reparent the window manager window to the presentation window
3640 * does not work with non-reparenting WMs
3641 * in future this should not be necessary anymore with
3642 * _NET_WM_STATE_FULLSCREEN available
3644 if( hPresentationWindow != None
3645 && hPresentationWindow != GetWindow()
3646 && GetStackingWindow() != None
3647 && GetStackingWindow() != GetDisplay()->GetRootWindow( m_nXScreen )
3650 int x = 0, y = 0;
3651 ::Window aChild;
3652 XTranslateCoordinates( GetXDisplay(),
3653 GetStackingWindow(),
3654 GetDisplay()->GetRootWindow( m_nXScreen ),
3655 0, 0,
3656 &x, &y,
3657 &aChild
3659 XReparentWindow( GetXDisplay(),
3660 GetStackingWindow(),
3661 hPresentationWindow,
3662 x, y
3664 aPresentationReparentList.push_back( GetStackingWindow() );
3667 int nLeft = 0, nTop = 0;
3668 XTranslateCoordinates( GetXDisplay(),
3669 GetShellWindow(),
3670 hWM_Parent,
3671 0, 0,
3672 &nLeft,
3673 &nTop,
3674 &hDummy );
3675 maGeometry.nLeftDecoration = nLeft > 0 ? nLeft-1 : 0;
3676 maGeometry.nTopDecoration = nTop > 0 ? nTop-1 : 0;
3679 * decorations are not symmetric,
3680 * so need real geometries here
3681 * (this will fail with virtual roots ?)
3684 // reset error occurred
3685 GetGenericUnixSalData()->ErrorTrapPop();
3686 GetGenericUnixSalData()->ErrorTrapPush();
3688 int xp, yp, x, y;
3689 unsigned int wp, w, hp, h, bw, d;
3690 XGetGeometry( GetXDisplay(),
3691 GetShellWindow(),
3692 &hRoot,
3693 &x, &y, &w, &h, &bw, &d );
3694 XGetGeometry( GetXDisplay(),
3695 hWM_Parent,
3696 &hRoot,
3697 &xp, &yp, &wp, &hp, &bw, &d );
3698 bool bResized = false;
3699 bool bError = GetGenericUnixSalData()->ErrorTrapPop( false );
3700 GetGenericUnixSalData()->ErrorTrapPush();
3702 if( ! bError )
3704 maGeometry.nRightDecoration = wp - w - maGeometry.nLeftDecoration;
3705 maGeometry.nBottomDecoration = hp - h - maGeometry.nTopDecoration;
3707 * note: this works because hWM_Parent is direct child of root,
3708 * not necessarily parent of GetShellWindow()
3710 maGeometry.nX = xp + nLeft;
3711 maGeometry.nY = yp + nTop;
3712 bResized = w != maGeometry.nWidth || h != maGeometry.nHeight;
3713 maGeometry.nWidth = w;
3714 maGeometry.nHeight = h;
3717 // limit width and height if we are too large: #47757
3718 // olwm and fvwm need this, it doesn't harm the rest
3720 // #i81311# do this only for sizable frames
3721 if( nStyle_ & SalFrameStyleFlags::SIZEABLE )
3723 Size aScreenSize = GetDisplay()->GetScreenSize( m_nXScreen );
3724 int nScreenWidth = aScreenSize.Width();
3725 int nScreenHeight = aScreenSize.Height();
3726 int nFrameWidth = maGeometry.nWidth + maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
3727 int nFrameHeight = maGeometry.nHeight + maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
3729 if ((nFrameWidth > nScreenWidth) || (nFrameHeight > nScreenHeight))
3731 Size aSize(maGeometry.nWidth, maGeometry.nHeight);
3733 if (nFrameWidth > nScreenWidth)
3734 aSize.setWidth( nScreenWidth - maGeometry.nRightDecoration - maGeometry.nLeftDecoration );
3735 if (nFrameHeight > nScreenHeight)
3736 aSize.setHeight( nScreenHeight - maGeometry.nBottomDecoration - maGeometry.nTopDecoration );
3738 SetSize( aSize );
3739 bResized = false;
3742 if( bResized )
3743 CallCallback( SalEvent::Resize, nullptr );
3745 GetGenericUnixSalData()->ErrorTrapPop();
3747 return true;
3750 bool X11SalFrame::HandleStateEvent( XPropertyEvent const *pEvent )
3752 Atom actual_type;
3753 int actual_format;
3754 unsigned long nitems, bytes_after;
3755 unsigned char *prop = nullptr;
3757 if( 0 != XGetWindowProperty( GetXDisplay(),
3758 GetShellWindow(),
3759 pEvent->atom, // property
3760 0, // long_offset (32bit)
3761 2, // long_length (32bit)
3762 False, // delete
3763 pEvent->atom, // req_type
3764 &actual_type,
3765 &actual_format,
3766 &nitems,
3767 &bytes_after,
3768 &prop )
3769 || ! prop
3771 return false;
3773 DBG_ASSERT( actual_type == pEvent->atom
3774 && 32 == actual_format
3775 && 2 == nitems
3776 && 0 == bytes_after, "HandleStateEvent" );
3778 if( *reinterpret_cast<unsigned long*>(prop) == NormalState )
3779 nShowState_ = SHOWSTATE_NORMAL;
3780 else if( *reinterpret_cast<unsigned long*>(prop) == IconicState )
3781 nShowState_ = SHOWSTATE_MINIMIZED;
3783 XFree( prop );
3784 return true;
3787 bool X11SalFrame::HandleClientMessage( XClientMessageEvent *pEvent )
3789 const WMAdaptor& rWMAdaptor( *pDisplay_->getWMAdaptor() );
3791 #if !defined(__synchronous_extinput__)
3792 if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::SAL_EXTTEXTEVENT ) )
3794 HandleExtTextEvent (pEvent);
3795 return true;
3797 #endif
3798 else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::SAL_QUITEVENT ) )
3800 SAL_WARN( "vcl", "X11SalFrame::Dispatch Quit" );
3801 Close(); // ???
3802 return true;
3804 else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::WM_PROTOCOLS ) )
3806 if( static_cast<Atom>(pEvent->data.l[0]) == rWMAdaptor.getAtom( WMAdaptor::NET_WM_PING ) )
3807 rWMAdaptor.answerPing( this, pEvent );
3808 else if( ! ( nStyle_ & SalFrameStyleFlags::PLUG )
3809 && ! (( nStyle_ & SalFrameStyleFlags::FLOAT ) && (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION))
3812 if( static_cast<Atom>(pEvent->data.l[0]) == rWMAdaptor.getAtom( WMAdaptor::WM_DELETE_WINDOW ) )
3814 Close();
3815 return true;
3817 else if( static_cast<Atom>(pEvent->data.l[0]) == rWMAdaptor.getAtom( WMAdaptor::WM_TAKE_FOCUS ) )
3819 // do nothing, we set the input focus in ToTop() if necessary
3820 #if OSL_DEBUG_LEVEL > 1
3821 SAL_INFO("vcl.window", "got WM_TAKE_FOCUS on "
3822 << ((nStyle_ &
3823 SalFrameStyleFlags::OWNERDRAWDECORATION) ?
3824 "ownerdraw" :
3825 "NON OWNERDRAW" )
3826 << " window.");
3827 #endif
3831 else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::XEMBED ) &&
3832 pEvent->window == GetWindow() )
3834 if( pEvent->data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
3835 pEvent->data.l[1] == 2 ) // XEMBED_WINDOW_DEACTIVATE
3837 XFocusChangeEvent aEvent;
3838 aEvent.type = (pEvent->data.l[1] == 1 ? FocusIn : FocusOut);
3839 aEvent.serial = pEvent->serial;
3840 aEvent.send_event = True;
3841 aEvent.display = pEvent->display;
3842 aEvent.window = pEvent->window;
3843 aEvent.mode = NotifyNormal;
3844 aEvent.detail = NotifyDetailNone;
3845 HandleFocusEvent( &aEvent );
3848 return false;
3851 bool X11SalFrame::Dispatch( XEvent *pEvent )
3853 bool nRet = false;
3855 if( -1 == nCaptured_ )
3857 CaptureMouse( true );
3858 #ifdef DBG_UTIL
3859 if( -1 != nCaptured_ )
3860 pDisplay_->DbgPrintDisplayEvent("Captured", pEvent);
3861 #endif
3864 if( pEvent->xany.window == GetShellWindow() || pEvent->xany.window == GetWindow() )
3866 switch( pEvent->type )
3868 case KeyPress:
3869 nRet = HandleKeyEvent( &pEvent->xkey );
3870 break;
3872 case KeyRelease:
3873 nRet = HandleKeyEvent( &pEvent->xkey );
3874 break;
3876 case ButtonPress:
3877 // if we lose the focus in presentation mode
3878 // there are good chances that we never get it back
3879 // since the WM ignores us
3880 if( IsOverrideRedirect() )
3882 XSetInputFocus( GetXDisplay(), GetShellWindow(),
3883 RevertToNone, CurrentTime );
3885 [[fallthrough]];
3886 case ButtonRelease:
3887 case MotionNotify:
3888 case EnterNotify:
3889 case LeaveNotify:
3890 nRet = HandleMouseEvent( pEvent );
3891 break;
3893 case FocusIn:
3894 case FocusOut:
3895 nRet = HandleFocusEvent( &pEvent->xfocus );
3896 break;
3898 case Expose:
3899 case GraphicsExpose:
3900 nRet = HandleExposeEvent( pEvent );
3901 break;
3903 case MapNotify:
3904 if( pEvent->xmap.window == GetShellWindow() )
3906 if( nShowState_ == SHOWSTATE_HIDDEN )
3909 * workaround for (at least) KWin 2.2.2
3910 * which will map windows that were once transient
3911 * even if they are withdrawn when the respective
3912 * document is mapped.
3914 if( ! (nStyle_ & SalFrameStyleFlags::PLUG) )
3915 XUnmapWindow( GetXDisplay(), GetShellWindow() );
3916 break;
3918 bMapped_ = true;
3919 bViewable_ = true;
3920 nRet = true;
3921 if ( mpInputContext != nullptr )
3922 mpInputContext->Map( this );
3923 CallCallback( SalEvent::Resize, nullptr );
3925 bool bSetFocus = m_bSetFocusOnMap;
3928 * sometimes a message box/dialogue is brought up when a frame is not mapped
3929 * the corresponding TRANSIENT_FOR hint is then set to the root window
3930 * so that the dialogue shows in all cases. Correct it here if the
3931 * frame is shown afterwards.
3933 if( ! IsChildWindow()
3934 && ! IsOverrideRedirect()
3935 && ! IsFloatGrabWindow()
3938 for (auto const& child : maChildren)
3940 if( child->mbTransientForRoot )
3941 pDisplay_->getWMAdaptor()->changeReferenceFrame( child, this );
3945 if( hPresentationWindow != None && GetShellWindow() == hPresentationWindow )
3946 XSetInputFocus( GetXDisplay(), GetShellWindow(), RevertToParent, CurrentTime );
3948 if( bSetFocus )
3950 XSetInputFocus( GetXDisplay(),
3951 GetShellWindow(),
3952 RevertToParent,
3953 CurrentTime );
3956 RestackChildren();
3957 m_bSetFocusOnMap = false;
3959 break;
3961 case UnmapNotify:
3962 if( pEvent->xunmap.window == GetShellWindow() )
3964 bMapped_ = false;
3965 bViewable_ = false;
3966 nRet = true;
3967 if ( mpInputContext != nullptr )
3968 mpInputContext->Unmap();
3969 CallCallback( SalEvent::Resize, nullptr );
3971 break;
3973 case ConfigureNotify:
3974 if( pEvent->xconfigure.window == GetShellWindow()
3975 || pEvent->xconfigure.window == GetWindow() )
3976 nRet = HandleSizeEvent( &pEvent->xconfigure );
3977 break;
3979 case VisibilityNotify:
3980 nVisibility_ = pEvent->xvisibility.state;
3981 nRet = true;
3982 if( bAlwaysOnTop_
3983 && bMapped_
3984 && ! GetDisplay()->getWMAdaptor()->isAlwaysOnTopOK()
3985 && nVisibility_ != VisibilityUnobscured )
3986 maAlwaysOnTopRaiseTimer.Start();
3987 break;
3989 case ReparentNotify:
3990 nRet = HandleReparentEvent( &pEvent->xreparent );
3991 break;
3993 case MappingNotify:
3994 break;
3996 case ColormapNotify:
3997 nRet = false;
3998 break;
4000 case PropertyNotify:
4002 if( pEvent->xproperty.atom == pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_STATE ) )
4003 nRet = HandleStateEvent( &pEvent->xproperty );
4004 else
4005 nRet = pDisplay_->getWMAdaptor()->handlePropertyNotify( this, &pEvent->xproperty );
4006 break;
4009 case ClientMessage:
4010 nRet = HandleClientMessage( &pEvent->xclient );
4011 break;
4014 else
4016 switch( pEvent->type )
4018 case FocusIn:
4019 case FocusOut:
4020 if( ( nStyle_ & SalFrameStyleFlags::PLUG )
4021 && ( pEvent->xfocus.window == GetShellWindow()
4022 || pEvent->xfocus.window == GetForeignParent() )
4025 nRet = HandleFocusEvent( &pEvent->xfocus );
4027 break;
4029 case ConfigureNotify:
4030 if( pEvent->xconfigure.window == GetForeignParent() ||
4031 pEvent->xconfigure.window == GetShellWindow() )
4032 nRet = HandleSizeEvent( &pEvent->xconfigure );
4034 if( pEvent->xconfigure.window == GetStackingWindow() )
4035 nRet = HandleSizeEvent( &pEvent->xconfigure );
4037 RestackChildren();
4038 break;
4042 return nRet;
4045 void X11SalFrame::ResetClipRegion()
4047 m_vClipRectangles.clear();
4049 const int dest_kind = ShapeBounding;
4050 const int op = ShapeSet;
4051 const int ordering = YSorted;
4053 XWindowAttributes win_attrib;
4054 XRectangle win_size;
4056 ::Window aShapeWindow = mhShellWindow;
4058 XGetWindowAttributes ( GetDisplay()->GetDisplay(),
4059 aShapeWindow,
4060 &win_attrib );
4062 win_size.x = 0;
4063 win_size.y = 0;
4064 win_size.width = win_attrib.width;
4065 win_size.height = win_attrib.height;
4067 XShapeCombineRectangles ( GetDisplay()->GetDisplay(),
4068 aShapeWindow,
4069 dest_kind,
4070 0, 0, // x_off, y_off
4071 &win_size, // list of rectangles
4072 1, // number of rectangles
4073 op, ordering );
4076 void X11SalFrame::BeginSetClipRegion( sal_uInt32 /*nRects*/ )
4078 m_vClipRectangles.clear();
4081 void X11SalFrame::UnionClipRegion( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
4083 m_vClipRectangles.emplace_back( XRectangle { static_cast<short>(nX), static_cast<short>(nY),
4084 static_cast<unsigned short>(nWidth), static_cast<unsigned short>(nHeight) } );
4087 void X11SalFrame::EndSetClipRegion()
4089 const int dest_kind = ShapeBounding;
4090 const int ordering = YSorted;
4091 const int op = ShapeSet;
4093 ::Window aShapeWindow = mhShellWindow;
4094 XShapeCombineRectangles ( GetDisplay()->GetDisplay(),
4095 aShapeWindow,
4096 dest_kind,
4097 0, 0, // x_off, y_off
4098 m_vClipRectangles.data(),
4099 m_vClipRectangles.size(),
4100 op, ordering );
4104 sal_uIntPtr X11SalFrame::GetNativeWindowHandle()
4106 return mhWindow;
4109 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */