1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <string_view>
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>
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>
54 #include <sal/macros.h>
55 #include <sal/log.hxx>
56 #include <com/sun/star/uno/Exception.hpp>
59 #include <bitmaps.hlst>
72 using namespace vcl_sal
;
74 constexpr auto CLIENT_EVENTS
= StructureNotifyMask
75 | SubstructureNotifyMask
85 | VisibilityChangeMask
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
)
99 ::Window aRoot
, aChild
;
100 unsigned int w
, h
, bw
, d
;
101 XGetGeometry( pDisplay
->GetDisplay(),
104 &x
, &y
, &w
, &h
, &bw
, &d
);
105 XTranslateCoordinates( pDisplay
->GetDisplay(),
111 XReparentWindow( pDisplay
->GetDisplay(),
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
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" );
137 ( ( !pDisableGrab
|| !*pDisableGrab
) &&
139 (nStyle_
& SalFrameStyleFlags::FLOAT
) &&
140 ! (nStyle_
& SalFrameStyleFlags::TOOLTIP
) &&
141 ! (nStyle_
& SalFrameStyleFlags::OWNERDRAWDECORATION
)
146 void X11SalFrame::setXEmbedInfo()
151 tools::Long aInfo
[2];
152 aInfo
[0] = 1; // XEMBED protocol version
153 aInfo
[1] = (bMapped_
? 1 : 0); // XEMBED_MAPPED
154 XChangeProperty( pDisplay_
->GetDisplay(),
156 pDisplay_
->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO
),
157 pDisplay_
->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO
),
160 reinterpret_cast<unsigned char*>(aInfo
),
161 SAL_N_ELEMENTS(aInfo
) );
164 void X11SalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode
)
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(),
182 False
, NoEventMask
, &aEvent
);
183 XSync( pDisplay_
->GetDisplay(), False
);
184 GetGenericUnixSalData()->ErrorTrapPop();
187 typedef std::vector
< unsigned long > NetWmIconData
;
191 const std::u16string_view SV_ICON_SIZE48
[] =
209 const std::u16string_view SV_ICON_SIZE32
[] =
227 const std::u16string_view SV_ICON_SIZE16
[] =
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 );
251 for(int size
: sizes
)
255 sIcon
= SV_ICON_SIZE48
[nIcon
];
256 else if( size
>= 32 )
257 sIcon
= SV_ICON_SIZE32
[nIcon
];
259 sIcon
= SV_ICON_SIZE16
[nIcon
];
261 BitmapEx aIcon
= vcl::bitmap::loadFromName(sIcon
, ImageLoadFlags::IgnoreScalingFactor
);
265 vcl::bitmap::convertBitmap32To24Plus8(aIcon
, aIcon
);
266 Bitmap icon
= aIcon
.GetBitmap();
268 switch( aIcon
.GetTransparentType())
270 case TransparentType::NONE
:
272 sal_uInt8 nTrans
= 0;
273 mask
= AlphaMask( icon
.GetSizePixel(), &nTrans
);
276 case TransparentType::Color
:
277 mask
= AlphaMask( icon
.CreateMask( aIcon
.GetTransparentColor() ) );
279 case TransparentType::Bitmap
:
280 mask
= aIcon
.GetAlpha();
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
);
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
];
319 BitmapEx aIcon
= vcl::bitmap::loadFromName(sIcon
, ImageLoadFlags::IgnoreScalingFactor
);
321 if( aIcon
.IsEmpty() )
324 X11SalBitmap
*pBitmap
= dynamic_cast < X11SalBitmap
* >
325 (aIcon
.ImplGetBitmapSalBitmap().get());
326 if (!pBitmap
) // FIXME: opengl , TODO SKIA
329 icon_pixmap
= XCreatePixmap( pDisplay
->GetDisplay(),
330 pDisplay
->GetRootWindow( nXScreen
),
332 DefaultDepth( pDisplay
->GetDisplay(),
333 nXScreen
.getXScreen() )
336 SalTwoRect
aRect(0, 0, iconSize
, iconSize
, 0, 0, iconSize
, iconSize
);
338 pBitmap
->ImplDraw( icon_pixmap
,
340 DefaultDepth( pDisplay
->GetDisplay(),
341 nXScreen
.getXScreen() ),
343 DefaultGC( pDisplay
->GetDisplay(),
344 nXScreen
.getXScreen() ) );
348 if( TransparentType::Bitmap
== aIcon
.GetTransparentType() )
350 icon_mask
= XCreatePixmap( pDisplay
->GetDisplay(),
351 pDisplay
->GetRootWindow( pDisplay
->GetDefaultXScreen() ),
352 iconSize
, iconSize
, 1);
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();
364 X11SalBitmap
*pMask
= static_cast < X11SalBitmap
* >
365 (aMask
.ImplGetSalBitmap().get());
367 pMask
->ImplDraw(icon_mask
, nXScreen
, 1, aRect
, aMonoGC
);
368 XFreeGC( pDisplay
->GetDisplay(), aMonoGC
);
374 void X11SalFrame::Init( SalFrameStyleFlags nSalFrameStyle
, SalX11Screen nXScreen
, SystemParentData
const * pParentData
, bool bUseGeometry
)
376 if( nXScreen
.getXScreen() >= GetDisplay()->GetXScreenCount() )
377 nXScreen
= GetDisplay()->GetDefaultXScreen();
379 nXScreen
= mpParent
->m_nXScreen
;
381 m_nXScreen
= nXScreen
;
382 nStyle_
= nSalFrameStyle
;
384 Hints
.flags
= InputHint
;
385 Hints
.input
= (nSalFrameStyle
& SalFrameStyleFlags::OWNERDRAWDECORATION
) ? False
: True
;
386 NetWmIconData netwm_icon
;
389 unsigned int w
= 500, h
= 500;
390 XSetWindowAttributes Attributes
;
392 int nAttrMask
= CWBorderPixel
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
;
412 w
= maGeometry
.nWidth
;
413 h
= maGeometry
.nHeight
;
416 if( (nSalFrameStyle
& SalFrameStyleFlags::FLOAT
) &&
417 ! (nSalFrameStyle
& SalFrameStyleFlags::OWNERDRAWDECORATION
)
420 if( nShowState_
== SHOWSTATE_UNKNOWN
)
425 Attributes
.override_redirect
= True
;
427 else if( nSalFrameStyle
& SalFrameStyleFlags::SYSTEMCHILD
)
429 SAL_WARN_IF( !mpParent
, "vcl", "SalFrameStyleFlags::SYSTEMCHILD window without parent" );
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
;
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
;
463 unsigned int nChildren
;
467 XQueryTree( GetDisplay()->GetDisplay(), mhShellWindow
,
468 &aRoot
, &aParent
, &pChildren
, &nChildren
);
470 if( aParent
!= aRoot
)
471 mhShellWindow
= aParent
;
473 Atom
* pProps
= XListProperties( GetDisplay()->GetDisplay(),
476 for( int i
= 0; i
< nCount
&& ! bBreak
; ++i
)
477 bBreak
= (pProps
[i
] == XA_WM_HINTS
);
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;
491 if (!bIsReallyOurFrame
)
493 XSelectInput( GetDisplay()->GetDisplay(), mhForeignParent
, StructureNotifyMask
| FocusChangeMask
);
494 XSelectInput( GetDisplay()->GetDisplay(), mhShellWindow
, StructureNotifyMask
| FocusChangeMask
);
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();
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;
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() );
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())
546 x
= 10; // leave some space for decoration
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
;
556 XQueryPointer( GetXDisplay(),
557 GetDisplay()->GetRootWindow( m_nXScreen
),
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
) ) )
571 Attributes
.win_gravity
= pDisplay_
->getWMAdaptor()->getInitWinGravity();
572 nAttrMask
|= CWWinGravity
;
575 Attributes
.save_under
= True
;
576 nAttrMask
|= CWSaveUnder
;
578 if( IsOverrideRedirect() )
579 Attributes
.override_redirect
= True
;
581 if( !(nStyle_
& SalFrameStyleFlags::INTRO
) )
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
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() );
619 if( pWMHints
->flags
& WindowGroupHint
)
621 Hints
.flags
|= WindowGroupHint
;
622 Hints
.window_group
= pWMHints
->window_group
;
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
;
642 nVisibility_
= VisibilityFullyObscured
;
643 mhWindow
= XCreateWindow( GetXDisplay(),
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();
668 maGeometry
.nWidth
= w
;
669 maGeometry
.nHeight
= h
;
670 updateScreenNumber();
672 XSync( GetXDisplay(), False
);
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
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
);
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
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();
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(),
724 // set PID and WM_CLIENT_MACHINE
725 pDisplay_
->getWMAdaptor()->setClientMachine( this );
726 pDisplay_
->getWMAdaptor()->setPID( this );
731 XChangeProperty( GetXDisplay(),
733 pDisplay_
->getWMAdaptor()->getAtom( WMAdaptor::WM_CLIENT_LEADER
),
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
)
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
;
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,
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();
806 SetPointer( PointerStyle::Arrow
);
809 X11SalFrame::X11SalFrame( SalFrame
*pParent
, SalFrameStyleFlags nSalFrameStyle
,
810 SystemParentData
const * pSystemParent
) :
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 );
824 mhShellWindow
= None
;
825 mhStackingWindow
= None
;
826 mhForeignParent
= None
;
827 m_bSetFocusOnMap
= false;
829 pGraphics_
= nullptr;
830 pFreeGraphics_
= nullptr;
835 mbSendExtKeyModChange
= false;
836 mnExtKeyMod
= ModKeyFlags::NONE
;
838 nShowState_
= SHOWSTATE_UNKNOWN
;
841 nStyle_
= SalFrameStyleFlags::NONE
;
843 bAlwaysOnTop_
= false;
845 // set bViewable_ to true: hack GetClientSize to report something
846 // different to 0/0 before first map
849 bDefaultPosition_
= true;
850 nVisibility_
= VisibilityFullyObscured
;
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;
866 mbFullScreen
= false;
868 mnIconID
= SV_ICON_ID_OFFICE
;
871 mpParent
->maChildren
.push_back( this );
873 Init( nSalFrameStyle
, GetDisplay()->GetDefaultXScreen(), pSystemParent
);
876 X11SalFrame::~X11SalFrame()
880 m_vClipRectangles
.clear();
882 if( mhStackingWindow
)
883 aPresentationReparentList
.remove( mhStackingWindow
);
885 // remove from parent's list
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 );
904 mpInputContext
->UnsetICFocus();
905 mpInputContext
->Unmap();
906 mpInputContext
.reset();
909 if( GetWindow() == hPresentationWindow
)
911 hPresentationWindow
= None
;
912 doReparentPresentationDialogues( GetDisplay() );
917 pGraphics_
->DeInit();
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
)
933 pContext
= pContext
->mpPrevContext
;
936 XDestroyWindow( GetXDisplay(), mhWindow
);
939 void X11SalFrame::SetExtendedFrameStyle( SalExtStyle nStyle
)
941 if( nStyle
!= mnExtStyle
&& ! IsChildWindow() )
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()
970 pGraphics_
= std::move(pFreeGraphics_
);
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() )
988 pFreeGraphics_
= std::move(pGraphics_
);
991 void X11SalFrame::updateGraphics( bool bClear
)
993 Drawable aDrawable
= bClear
? None
: GetWindow();
995 pGraphics_
->SetDrawable( aDrawable
, nullptr, m_nXScreen
);
997 pFreeGraphics_
->SetDrawable( aDrawable
, nullptr, m_nXScreen
);
1000 void X11SalFrame::SetIcon( sal_uInt16 nIcon
)
1002 if ( IsChildWindow() )
1005 // 0 == default icon -> #1
1011 XIconSize
*pIconSize
= nullptr;
1014 if ( XGetIconSizes( GetXDisplay(), GetDisplay()->GetRootWindow( m_nXScreen
), &pIconSize
, &nSizes
) )
1016 #if OSL_DEBUG_LEVEL > 1
1017 SAL_INFO("vcl.window", "X11SalFrame::SetIcon(): found "
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
1034 << pIconSize
[i
].min_height
);
1035 SAL_INFO("vcl.window", "max: "
1036 << pIconSize
[i
].max_width
1038 << pIconSize
[i
].max_height
);
1039 SAL_INFO("vcl.window", "inc: "
1040 << pIconSize
[i
].width_inc
1042 << pIconSize
[i
].height_inc
);
1050 const OUString
& rWM( pDisplay_
->getWMAdaptor()->getWindowManagerName() );
1051 if( rWM
== "KWin" ) // assume KDE is running
1053 static bool bGnomeIconSize
= false;
1054 static bool bGnomeChecked
= false;
1055 if( ! bGnomeChecked
)
1059 Atom
* pProps
= XListProperties( GetXDisplay(),
1060 GetDisplay()->GetRootWindow( m_nXScreen
),
1062 for( int i
= 0; i
< nCount
&& !bGnomeIconSize
; i
++ )
1064 char* pName
= XGetAtomName( GetXDisplay(), pProps
[i
] );
1067 if( !strcmp( pName
, "GNOME_PANEL_DESKTOP_AREA" ) )
1068 bGnomeIconSize
= true;
1075 if( bGnomeIconSize
)
1081 XWMHints
*pHints
= XGetWMHints( GetXDisplay(), GetShellWindow() );
1084 memcpy(&Hints
, pHints
, sizeof( XWMHints
));
1089 NetWmIconData netwm_icon
;
1090 bool bOk
= lcl_SelectAppIconPixmap( GetDisplay(), m_nXScreen
,
1092 pHints
->icon_pixmap
, pHints
->icon_mask
, netwm_icon
);
1095 // load default icon (0)
1096 bOk
= lcl_SelectAppIconPixmap( GetDisplay(), m_nXScreen
,
1098 pHints
->icon_pixmap
, pHints
->icon_mask
, netwm_icon
);
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() )
1120 if( !GetShellWindow() ||
1121 (nStyle_
& (SalFrameStyleFlags::FLOAT
|SalFrameStyleFlags::OWNERDRAWDECORATION
) ) == SalFrameStyleFlags::FLOAT
)
1124 XSizeHints
* pHints
= XAllocSizeHints();
1125 tools::Long nSupplied
= 0;
1126 XGetWMNormalHints( GetXDisplay(),
1131 pHints
->max_width
= nWidth
;
1132 pHints
->max_height
= nHeight
;
1133 pHints
->flags
|= PMaxSize
;
1134 XSetWMNormalHints( GetXDisplay(),
1140 void X11SalFrame::SetMinClientSize( tools::Long nWidth
, tools::Long nHeight
)
1142 if( IsChildWindow() )
1145 if( !GetShellWindow() ||
1146 (nStyle_
& (SalFrameStyleFlags::FLOAT
|SalFrameStyleFlags::OWNERDRAWDECORATION
) ) == SalFrameStyleFlags::FLOAT
)
1149 XSizeHints
* pHints
= XAllocSizeHints();
1150 tools::Long nSupplied
= 0;
1151 XGetWMNormalHints( GetXDisplay(),
1156 pHints
->min_width
= nWidth
;
1157 pHints
->min_height
= nHeight
;
1158 pHints
->flags
|= PMinSize
;
1159 XSetWMNormalHints( GetXDisplay(),
1165 // Show + Pos (x,y,z) + Size (width,height)
1167 void X11SalFrame::Show( bool bVisible
, bool bNoActivate
)
1169 if( ( bVisible
&& bMapped_
)
1170 || ( !bVisible
&& !bMapped_
) )
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
;
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()
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() &&
1228 nVisibleFloats
== 0 &&
1229 ! GetDisplay()->GetCaptureFrame() )
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
1238 XGrabPointer( GetXDisplay(),
1239 mpParent
->GetWindow(),
1241 PointerMotionMask
| ButtonPressMask
| ButtonReleaseMask
,
1245 mpParent
? mpParent
->GetCursor() : None
,
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
1259 askForXEmbedFocus( 0 );
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() );
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.
1296 if( nVisibleFloats
== 1 && ! GetDisplay()->GetCaptureFrame() )
1298 /* #i39420# now move grab to the new float window */
1299 XGrabPointer( GetXDisplay(),
1302 PointerMotionMask
| ButtonPressMask
| ButtonReleaseMask
,
1306 mpParent
? mpParent
->GetCursor() : None
,
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(),
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);
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
)
1378 if( nVisibleFloats
== 0 && ! GetDisplay()->GetCaptureFrame() )
1379 XUngrabPointer( GetXDisplay(),
1382 // flush here; there may be a very seldom race between
1383 // the display connection used for clipboard and our connection
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
) )
1412 askForXEmbedFocus( 0 );
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
)
1432 rWidth
= rHeight
= 0;
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
;
1472 root_x
= mpParent
->maGeometry
.nX
+ mpParent
->maGeometry
.nWidth
/2;
1473 root_y
= mpParent
->maGeometry
.nY
+ mpParent
->maGeometry
.nHeight
/2;
1476 XQueryPointer( GetXDisplay(),
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();
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
)
1512 unsigned int bw
, depth
;
1513 XGetGeometry( GetXDisplay(),
1514 pFrame
->GetShellWindow(),
1516 &nScreenX
, &nScreenY
,
1517 reinterpret_cast<unsigned int*>(&nScreenWidth
),
1518 reinterpret_cast<unsigned int*>(&nScreenHeight
),
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
)
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
;
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
;
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
);
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
)
1590 // relative positioning in X11SalFrame::SetPosSize
1591 tools::Rectangle
aPosSize( Point( maGeometry
.nX
, maGeometry
.nY
), Size( maGeometry
.nWidth
, maGeometry
.nHeight
) );
1594 if( ! ( nFlags
& SAL_FRAME_POSSIZE_X
) )
1596 nX
= aPosSize
.Left();
1598 nX
-= mpParent
->maGeometry
.nX
;
1600 if( ! ( nFlags
& SAL_FRAME_POSSIZE_Y
) )
1602 nY
= aPosSize
.Top();
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();
1622 SetSize( Size( nWidth
, nHeight
) );
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)
1651 // Request for position or size change
1652 if (pState
->mnMask
& FRAMESTATE_MASK_GEOMETRY
)
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(),
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(),
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();
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
);
1713 if (pState
->mnMask
& WindowStateMask::Height
)
1715 int nHeight
= pState
->mnHeight
> 0 ? pState
->mnHeight
- 1 : 0;
1716 aPosSize
.setHeight (nHeight
);
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
) ) &&
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
))
1762 if (pState
->mnState
& WindowStateState::Maximized
)
1764 nShowState_
= SHOWSTATE_NORMAL
;
1765 if( ! (pState
->mnState
& (WindowStateState::MaximizedHorz
|WindowStateState::MaximizedVert
) ) )
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
;
1787 if (pState
->mnState
& WindowStateState::Normal
)
1789 if (nShowState_
!= SHOWSTATE_NORMAL
)
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
;
1801 pState
->mnState
= WindowStateState::Normal
;
1803 tools::Rectangle aPosSize
;
1804 if( maRestorePosSize
.IsEmpty() )
1805 GetPosSize( aPosSize
);
1807 aPosSize
= maRestorePosSize
;
1809 if( mbMaximizedHorz
)
1810 pState
->mnState
|= WindowStateState::MaximizedHorz
;
1811 if( mbMaximizedVert
)
1812 pState
->mnState
|= WindowStateState::MaximizedVert
;
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
;
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
) );
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() )
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(),
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(),
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() );
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
)
1915 if( mpParent
&& ! IsSysChildWindow() )
1917 if( AllSettings::GetLayoutRTL() )
1918 values
.x
= mpParent
->maGeometry
.nWidth
-values
.width
-1-values
.x
;
1921 // coordinates are relative to parent, so translate to root coordinates
1922 XTranslateCoordinates( GetDisplay()->GetDisplay(),
1923 mpParent
->GetWindow(),
1924 GetDisplay()->GetRootWindow( m_nXScreen
),
1926 &values
.x
, &values
.y
,
1930 bool bMoved
= false;
1931 bool bSized
= false;
1932 if( values
.x
!= maGeometry
.nX
|| values
.y
!= maGeometry
.nY
)
1934 if( values
.width
!= static_cast<int>(maGeometry
.nWidth
) || values
.height
!= static_cast<int>(maGeometry
.nHeight
) )
1937 // do not set WMNormalHints for...
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(),
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();
1974 pHints
->max_width
= 10000;
1975 pHints
->max_height
= 10000;
1976 pHints
->flags
|= PMaxSize
;
1978 XSetWMNormalHints( GetXDisplay(),
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
);
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 );
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() )
2022 if( SHOWSTATE_UNKNOWN
== nShowState_
|| SHOWSTATE_HIDDEN
== nShowState_
)
2024 SAL_WARN( "vcl", "X11SalFrame::Minimize on withdrawn window" );
2028 if( XIconifyWindow( GetXDisplay(),
2030 pDisplay_
->GetDefaultXScreen().getXScreen() ) )
2031 nShowState_
= SHOWSTATE_MINIMIZED
;
2034 void X11SalFrame::Maximize()
2036 if( IsSysChildWindow() )
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() )
2054 if( SHOWSTATE_UNKNOWN
== nShowState_
|| SHOWSTATE_HIDDEN
== nShowState_
)
2056 SAL_WARN( "vcl", "X11SalFrame::Restore on withdrawn window" );
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
)
2075 if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
2077 if( nNewScreen
>= GetDisplay()->GetXineramaScreens().size() )
2080 tools::Rectangle
aOldScreenRect( GetDisplay()->GetXineramaScreens()[maGeometry
.nDisplayScreenNumber
] );
2081 tools::Rectangle
aNewScreenRect( GetDisplay()->GetXineramaScreens()[nNewScreen
] );
2082 bool bVisible
= bMapped_
;
2085 maGeometry
.nX
= aNewScreenRect
.Left() + (maGeometry
.nX
- aOldScreenRect
.Left());
2086 maGeometry
.nY
= aNewScreenRect
.Top() + (maGeometry
.nY
- aOldScreenRect
.Top());
2087 createNewWindow( None
, m_nXScreen
);
2090 maGeometry
.nDisplayScreenNumber
= nNewScreen
;
2092 else if( nNewScreen
< GetDisplay()->GetXScreenCount() )
2094 bool bVisible
= bMapped_
;
2097 createNewWindow( None
, SalX11Screen( nNewScreen
) );
2100 maGeometry
.nDisplayScreenNumber
= nNewScreen
;
2104 void X11SalFrame::SetApplicationID( const OUString
&rWMClass
)
2106 if( rWMClass
!= m_sWMClass
&& ! IsChildWindow() )
2108 m_sWMClass
= rWMClass
;
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
);
2130 void X11SalFrame::ShowFullScreen( bool bFullScreen
, sal_Int32 nScreen
)
2132 if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
2134 if( mbFullScreen
== 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
) );
2144 aRect
= GetDisplay()->GetXineramaScreens()[nScreen
];
2145 nStyle_
|= SalFrameStyleFlags::PARTIAL_FULLSCREEN
;
2146 bool bVisible
= bMapped_
;
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 );
2159 GetDisplay()->getWMAdaptor()->showFullScreen( this, true );
2166 mbFullScreen
= false;
2167 nStyle_
&= ~SalFrameStyleFlags::PARTIAL_FULLSCREEN
;
2168 bool bVisible
= bMapped_
;
2169 tools::Rectangle aRect
= maRestorePosSize
;
2170 maRestorePosSize
= tools::Rectangle();
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
);
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_
;
2190 pDisplay_
->getWMAdaptor()->showFullScreen( this, false );
2193 createNewWindow( None
, SalX11Screen( nScreen
) );
2195 pDisplay_
->getWMAdaptor()->showFullScreen( this, true );
2199 if( mbFullScreen
== bFullScreen
)
2202 pDisplay_
->getWMAdaptor()->showFullScreen( this, bFullScreen
);
2206 void X11SalFrame::StartPresentation( bool bStart
)
2208 maScreenSaverInhibitor
.inhibit( bStart
,
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
2224 XGetInputFocus( GetXDisplay(), &hPresFocusWindow
, &revert_to
);
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
,
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__)
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) );
2263 void* pExtTextEvent
= reinterpret_cast<void*>(pEvent
->data
.l
[0]);
2265 SalEvent nExtTextEventType
= SalEvent(pEvent
->data
.l
[2]);
2267 CallCallback(nExtTextEventType
, pExtTextEvent
);
2269 switch (nExtTextEventType
)
2271 case SalEvent::EndExtTextInput
:
2274 case SalEvent::ExtTextInput
:
2278 SAL_WARN("vcl.window",
2279 "X11SalFrame::HandleExtTextEvent: invalid extended input.");
2282 #endif /* defined(__synchronous_extinput__) */
2286 bool X11SalFrame::PostEvent(std::unique_ptr
<ImplSVEvent
> pData
)
2288 GetDisplay()->SendInternalEvent( this, pData
.release() );
2294 void X11SalFrame::SetTitle( const OUString
& rTitle
)
2296 if( ! ( IsChildWindow() || (nStyle_
& SalFrameStyleFlags::FLOAT
) ) )
2299 GetDisplay()->getWMAdaptor()->setWMName( this, rTitle
);
2303 void X11SalFrame::Flush()
2306 pGraphics_
->Flush();
2307 XFlush( GetDisplay()->GetDisplay() );
2312 void X11SalFrame::SetInputContext( SalInputContext
* pContext
)
2314 if (pContext
== nullptr)
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();
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() );
2337 mpInputContext
->SetICFocus( this );
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
2361 LanguageType
X11SalFrame::GetInputLanguage()
2363 // could be improved by checking unicode ranges of the last input
2364 return LANGUAGE_DONTKNOW
;
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
)
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
2402 void X11SalFrame::createNewWindow( ::Window aNewParent
, SalX11Screen nXScreen
)
2404 bool bWasVisible
= bMapped_
;
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
;
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
;
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
);
2452 // now init with new parent again
2453 if ( aParentData
.aWindow
!= None
)
2454 Init( nStyle_
| SalFrameStyleFlags::PLUG
, nXScreen
, &aParentData
);
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
);
2466 if( mpParent
->m_nXScreen
!= m_nXScreen
)
2467 SetParent( nullptr );
2469 pDisplay_
->getWMAdaptor()->changeReferenceFrame( this, mpParent
);
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
);
2493 void X11SalFrame::Beep()
2495 GetDisplay()->Beep();
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
)
2513 if( state
& ControlMask
)
2515 if( state
& Mod1Mask
)
2518 // Map Meta/Super modifier to MOD3 on all Unix systems
2520 if( state
& Mod3Mask
)
2526 SalFrame::SalPointerState
X11SalFrame::GetPointerState()
2528 SalPointerState aState
;
2529 ::Window aRoot
, aChild
;
2531 unsigned int nMask
= 0;
2532 XQueryPointer( GetXDisplay(),
2541 aState
.maPos
= Point(wx
, wy
);
2542 aState
.mnState
= sal_GetCode( nMask
);
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
);
2558 struct CompressWheelEventsData
2562 int count
; // number of compressed events
2565 Bool
compressWheelEvents( Display
*, XEvent
* event
, XPointer p
)
2567 CompressWheelEventsData
* data
= reinterpret_cast< CompressWheelEventsData
* >( p
);
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
)
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
)
2593 data
->ignore
= true;
2601 bool X11SalFrame::HandleMouseEvent( XEvent
*pEvent
)
2603 SalMouseEvent aMouseEvt
;
2604 SalEvent nEvent
= SalEvent::NONE
;
2605 bool bClosePopups
= false;
2607 if( nVisibleFloats
&& pEvent
->type
== EnterNotify
)
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
)
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
) )
2656 XChangeActivePointerGrab( GetXDisplay(),
2657 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
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() &&
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
) )
2691 // need not take care of the XUngrabPointer in Show( false )
2692 // because XUngrabPointer does not produce errors if pointer
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
),
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;
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
);
2769 pEvent
->xbutton
.button
== Button6
||
2770 pEvent
->xbutton
.button
== Button7
);
2772 if( pEvent
->type
== ButtonRelease
)
2775 static sal_uLong nLines
= 0;
2778 char* pEnv
= getenv( "SAL_WHEELLINES" );
2779 nLines
= pEnv
? atoi( pEnv
) : 3;
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
;
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
);
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
);
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
);
2844 // F10 means either KEY_F10 or KEY_MENU, which has to be decided
2845 // in the independent part.
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
) {}
2857 GetAlternateKeyCode( const sal_uInt16 nKeyCode
)
2859 KeyAlternate aAlternate
;
2863 case KEY_F10
: aAlternate
= KeyAlternate( KEY_MENU
);break;
2864 case KEY_F24
: aAlternate
= KeyAlternate( KEY_SUBTRACT
, '-' );break;
2870 void X11SalFrame::beginUnicodeSequence()
2872 OUString
& rSeq( GetGenericUnixSalData()->GetUnicodeCommand() );
2873 vcl::DeletionListener
aDeleteWatch( this );
2875 if( !rSeq
.isEmpty() )
2876 endUnicodeSequence();
2880 if( ! aDeleteWatch
.isDeleted() )
2882 ExtTextInputAttr nTextAttr
= ExtTextInputAttr::Underline
;
2883 SalExtTextInputEvent aEv
;
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
)
2896 OUString
& rSeq( GetGenericUnixSalData()->GetUnicodeCommand() );
2897 if( !rSeq
.isEmpty() )
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
;
2909 aEv
.mpTextAttr
= attribs
.data();
2910 aEv
.mnCursorPos
= 0;
2911 aEv
.mnCursorFlags
= 0;
2913 CallCallback(SalEvent::ExtTextInput
, static_cast<void*>(&aEv
));
2917 bRet
= endUnicodeSequence();
2920 endUnicodeSequence();
2924 bool X11SalFrame::endUnicodeSequence()
2926 OUString
& rSeq( GetGenericUnixSalData()->GetUnicodeCommand() );
2928 vcl::DeletionListener
aDeleteWatch( this );
2929 if( rSeq
.getLength() > 1 && rSeq
.getLength() < 6 )
2932 OUString
aNumbers( rSeq
.copy( 1 ) );
2933 sal_uInt32 nValue
= aNumbers
.toUInt32( 16 );
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();
2947 if( bWasInput
&& ! aDeleteWatch
.isDeleted() )
2948 CallCallback(SalEvent::EndExtTextInput
, nullptr);
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
))
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.
2984 if( XPending( dpy
))
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.
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.
2999 XPutBackEvent( dpy
, &nextEvent2
);
3005 { // Unrelated event, put back and stop compressing.
3006 XPutBackEvent( dpy
, &nextEvent1
);
3010 if( ignore
) // This autorepeating keyrelease is followed by another keypress.
3015 KeySym nUnmodifiedKeySym
;
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.
3025 nKeySym
= pDisplay_
->GetKeySym( pEvent
, pPrintable
, &nLen
,
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
3034 pPrintable
= static_cast<char*>(alloca( nLen
));
3035 nKeySym
= pDisplay_
->GetKeySym( pEvent
, pPrintable
, &nLen
,
3037 &nStatus
, mpInputContext
->GetContext() );
3042 // fallback, this should never ever be called
3044 nKeySym
= pDisplay_
->GetKeySym( pEvent
, pPrintable
, &nLen
, &nUnmodifiedKeySym
, &nStatus
);
3047 SalKeyEvent aKeyEvt
;
3048 sal_uInt16 nKeyCode
;
3049 sal_uInt16 nModCode
= 0;
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;
3088 nExtModMask
= ModKeyFlags::LeftMod1
;
3089 nModMask
= KEY_MOD1
;
3092 nExtModMask
= ModKeyFlags::RightMod1
;
3093 nModMask
= KEY_MOD1
;
3096 nExtModMask
= ModKeyFlags::LeftMod2
;
3097 nModMask
= KEY_MOD2
;
3100 nExtModMask
= ModKeyFlags::RightMod2
;
3101 nModMask
= KEY_MOD2
;
3104 nExtModMask
= ModKeyFlags::LeftShift
;
3105 nModMask
= KEY_SHIFT
;
3108 nExtModMask
= ModKeyFlags::RightShift
;
3109 nModMask
= KEY_SHIFT
;
3111 // Map Meta/Super keys to MOD3 modifier on all Unix systems
3115 nExtModMask
= ModKeyFlags::LeftMod3
;
3116 nModMask
= KEY_MOD3
;
3120 nExtModMask
= ModKeyFlags::RightMod3
;
3121 nModMask
= KEY_MOD3
;
3124 if( pEvent
->type
== KeyRelease
)
3126 nModCode
&= ~nModMask
;
3127 mnExtKeyMod
&= ~nExtModMask
;
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
);
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;
3158 || ((nLen
== 1) && (nKeySym
> 0)) )
3159 nKeyString
= KeysymToUnicode (nKeySym
);
3160 // if we have nothing we give up
3161 if( !nKeyCode
&& !nLen
&& !nKeyString
)
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();
3174 else if( nSeqKeyCode
>= KEY_0
&& nSeqKeyCode
<= KEY_9
)
3176 if( appendUnicodeSequence( u
'0' + sal_Unicode(nSeqKeyCode
- KEY_0
) ) )
3179 else if( nSeqKeyCode
>= KEY_A
&& nSeqKeyCode
<= KEY_F
)
3181 if( appendUnicodeSequence( u
'a' + sal_Unicode(nSeqKeyCode
- KEY_A
) ) )
3185 endUnicodeSequence();
3188 if( aDeleteWatch
.isDeleted() )
3191 rtl_TextEncoding nEncoding
= osl_getThreadTextEncoding();
3193 sal_Unicode
*pBuffer
;
3194 sal_Unicode
*pString
;
3195 sal_Size nBufferSize
= nLen
* 2;
3197 pBuffer
= static_cast<sal_Unicode
*>(malloc( nBufferSize
+ 2 ));
3200 if (nKeyString
!= 0)
3202 pString
= &nKeyString
;
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
);
3231 else if (nLen
> 0 /* nEncoding == RTL_TEXTENCODING_UNICODE */)
3233 pString
= reinterpret_cast<sal_Unicode
*>(pPrintable
);
3242 if ( mpInputContext
!= nullptr
3243 && mpInputContext
->UseContext()
3244 && KeyRelease
!= pEvent
->type
3246 || (nSize
> 0 && mpInputContext
->IsPreeditMode())) )
3248 mpInputContext
->CommitKeyEvent(pString
, nSize
);
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
);
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();
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" )
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() )
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
);
3338 mbInputFocus
= False
;
3339 mbSendExtKeyModChange
= false;
3340 mnExtKeyMod
= ModKeyFlags::NONE
;
3341 return CallCallback( SalEvent::LoseFocus
, nullptr );
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) ) );
3380 // wait for last expose rectangle, do not wait for resize timer
3381 // if a completed graphics expose sequence is available
3384 SalPaintEvent
aPEvt( maPaintRegion
.Left(), maPaintRegion
.Top(), maPaintRegion
.GetWidth(), maPaintRegion
.GetHeight() );
3386 CallCallback( SalEvent::Paint
, &aPEvt
);
3387 maPaintRegion
= tools::Rectangle();
3392 void X11SalFrame::RestackChildren( ::Window
* pTopLevelWindows
, int nTopLevelWindows
)
3394 if( maChildren
.empty() )
3397 int nWindow
= nTopLevelWindows
;
3399 if( pTopLevelWindows
[nWindow
] == GetStackingWindow() )
3404 for (auto const& child
: maChildren
)
3406 if( child
->bMapped_
)
3408 int nChild
= nWindow
;
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
);
3424 for (auto const& child
: maChildren
)
3426 child
->RestackChildren( pTopLevelWindows
, nTopLevelWindows
);
3430 void X11SalFrame::RestackChildren()
3432 if( maChildren
.empty() )
3435 ::Window aRoot
, aParent
, *pChildren
= nullptr;
3436 unsigned int nChildren
;
3437 if( XQueryTree( GetXDisplay(),
3438 GetDisplay()->GetRootWindow( m_nXScreen
),
3444 RestackChildren( pChildren
, nChildren
);
3449 static Bool
size_event_predicate( Display
*, XEvent
* event
, XPointer arg
)
3451 if( event
->type
!= ConfigureNotify
)
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()
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)
3489 if( ( nStyle_
& SalFrameStyleFlags::PLUG
) && pEvent
->window
== GetShellWindow() )
3491 // just update the children's positions
3496 if( pEvent
->window
== GetForeignParent() )
3497 XResizeWindow( GetXDisplay(),
3503 XTranslateCoordinates( GetXDisplay(),
3505 pDisplay_
->GetRootWindow( pDisplay_
->GetDefaultXScreen() ),
3507 &pEvent
->x
, &pEvent
->y
,
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 );
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;
3531 XCheckIfEvent( GetXDisplay(), &dummy
, size_event_predicate
, reinterpret_cast< XPointer
>( this ));
3532 if( mPendingSizeEvent
)
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
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 );
3560 IMPL_LINK_NOARG(X11SalFrame
, HandleAlwaysOnTopRaise
, Timer
*, void)
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
3584 hWM_Parent
= GetShellWindow();
3588 XQueryTree( pDisplay
,
3595 bool bError
= GetGenericUnixSalData()->ErrorTrapPop( false );
3596 GetGenericUnixSalData()->ErrorTrapPush();
3600 hWM_Parent
= GetShellWindow();
3603 /* this sometimes happens if a Show(true) is
3604 * immediately followed by Show(false) (which is braindead anyway)
3606 if( hDummy
== hWM_Parent
)
3608 if( hDummy
!= hRoot
)
3609 hWM_Parent
= hDummy
;
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();
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
)
3652 XTranslateCoordinates( GetXDisplay(),
3653 GetStackingWindow(),
3654 GetDisplay()->GetRootWindow( m_nXScreen
),
3659 XReparentWindow( GetXDisplay(),
3660 GetStackingWindow(),
3661 hPresentationWindow
,
3664 aPresentationReparentList
.push_back( GetStackingWindow() );
3667 int nLeft
= 0, nTop
= 0;
3668 XTranslateCoordinates( GetXDisplay(),
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();
3689 unsigned int wp
, w
, hp
, h
, bw
, d
;
3690 XGetGeometry( GetXDisplay(),
3693 &x
, &y
, &w
, &h
, &bw
, &d
);
3694 XGetGeometry( GetXDisplay(),
3697 &xp
, &yp
, &wp
, &hp
, &bw
, &d
);
3698 bool bResized
= false;
3699 bool bError
= GetGenericUnixSalData()->ErrorTrapPop( false );
3700 GetGenericUnixSalData()->ErrorTrapPush();
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
);
3743 CallCallback( SalEvent::Resize
, nullptr );
3745 GetGenericUnixSalData()->ErrorTrapPop();
3750 bool X11SalFrame::HandleStateEvent( XPropertyEvent
const *pEvent
)
3754 unsigned long nitems
, bytes_after
;
3755 unsigned char *prop
= nullptr;
3757 if( 0 != XGetWindowProperty( GetXDisplay(),
3759 pEvent
->atom
, // property
3760 0, // long_offset (32bit)
3761 2, // long_length (32bit)
3763 pEvent
->atom
, // req_type
3773 DBG_ASSERT( actual_type
== pEvent
->atom
3774 && 32 == actual_format
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
;
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
);
3798 else if( pEvent
->message_type
== rWMAdaptor
.getAtom( WMAdaptor::SAL_QUITEVENT
) )
3800 SAL_WARN( "vcl", "X11SalFrame::Dispatch Quit" );
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
) )
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 "
3823 SalFrameStyleFlags::OWNERDRAWDECORATION
) ?
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
);
3851 bool X11SalFrame::Dispatch( XEvent
*pEvent
)
3855 if( -1 == nCaptured_
)
3857 CaptureMouse( true );
3859 if( -1 != nCaptured_
)
3860 pDisplay_
->DbgPrintDisplayEvent("Captured", pEvent
);
3864 if( pEvent
->xany
.window
== GetShellWindow() || pEvent
->xany
.window
== GetWindow() )
3866 switch( pEvent
->type
)
3869 nRet
= HandleKeyEvent( &pEvent
->xkey
);
3873 nRet
= HandleKeyEvent( &pEvent
->xkey
);
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
);
3890 nRet
= HandleMouseEvent( pEvent
);
3895 nRet
= HandleFocusEvent( &pEvent
->xfocus
);
3899 case GraphicsExpose
:
3900 nRet
= HandleExposeEvent( pEvent
);
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() );
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
);
3950 XSetInputFocus( GetXDisplay(),
3957 m_bSetFocusOnMap
= false;
3962 if( pEvent
->xunmap
.window
== GetShellWindow() )
3967 if ( mpInputContext
!= nullptr )
3968 mpInputContext
->Unmap();
3969 CallCallback( SalEvent::Resize
, nullptr );
3973 case ConfigureNotify
:
3974 if( pEvent
->xconfigure
.window
== GetShellWindow()
3975 || pEvent
->xconfigure
.window
== GetWindow() )
3976 nRet
= HandleSizeEvent( &pEvent
->xconfigure
);
3979 case VisibilityNotify
:
3980 nVisibility_
= pEvent
->xvisibility
.state
;
3984 && ! GetDisplay()->getWMAdaptor()->isAlwaysOnTopOK()
3985 && nVisibility_
!= VisibilityUnobscured
)
3986 maAlwaysOnTopRaiseTimer
.Start();
3989 case ReparentNotify
:
3990 nRet
= HandleReparentEvent( &pEvent
->xreparent
);
3996 case ColormapNotify
:
4000 case PropertyNotify
:
4002 if( pEvent
->xproperty
.atom
== pDisplay_
->getWMAdaptor()->getAtom( WMAdaptor::WM_STATE
) )
4003 nRet
= HandleStateEvent( &pEvent
->xproperty
);
4005 nRet
= pDisplay_
->getWMAdaptor()->handlePropertyNotify( this, &pEvent
->xproperty
);
4010 nRet
= HandleClientMessage( &pEvent
->xclient
);
4016 switch( pEvent
->type
)
4020 if( ( nStyle_
& SalFrameStyleFlags::PLUG
)
4021 && ( pEvent
->xfocus
.window
== GetShellWindow()
4022 || pEvent
->xfocus
.window
== GetForeignParent() )
4025 nRet
= HandleFocusEvent( &pEvent
->xfocus
);
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
);
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(),
4064 win_size
.width
= win_attrib
.width
;
4065 win_size
.height
= win_attrib
.height
;
4067 XShapeCombineRectangles ( GetDisplay()->GetDisplay(),
4070 0, 0, // x_off, y_off
4071 &win_size
, // list of rectangles
4072 1, // number of rectangles
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(),
4097 0, 0, // x_off, y_off
4098 m_vClipRectangles
.data(),
4099 m_vClipRectangles
.size(),
4104 sal_uIntPtr
X11SalFrame::GetNativeWindowHandle()
4109 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */