/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
if( bUseGeometry )
{
x = maGeometry.x();
y = maGeometry.y();
w = maGeometry.width();
h = maGeometry.height();
}
if( (nSalFrameStyle & SalFrameStyleFlags::FLOAT) &&
! (nSalFrameStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)
)
{ if( nShowState_ == X11ShowState::Unknown )
{
w = 10;
h = 10;
}
Attributes.override_redirect = True;
} elseif( nSalFrameStyle & SalFrameStyleFlags::SYSTEMCHILD )
{
SAL_WARN_IF( !mpParent, "vcl", "SalFrameStyleFlags::SYSTEMCHILD window without parent"); if( mpParent )
{
aFrameParent = mpParent->mhWindow; // FIXME: since with SalFrameStyleFlags::SYSTEMCHILD // multiple X11SalFrame objects can have the same shell window // dispatching events in saldisp.cxx is unclear (the first frame) // wins. HTH this correctly is unclear yet // for the time being, treat set the shell window to own window // like for a normal frame // mhShellWindow = mpParent->GetShellWindow();
}
} elseif( pParentData )
{ // plugin parent may be killed unexpectedly by plugging // process; start permanently ignoring X errors...
GetGenericUnixSalData()->ErrorTrapPush();
// check if this is really one of our own frames // do not change the input mask in that case bool bIsReallyOurFrame = false; for (auto pSalFrame : GetDisplay()->getFrames() ) if ( static_cast<const X11SalFrame*>( pSalFrame )->GetWindow() == mhForeignParent )
{
bIsReallyOurFrame = true; break;
} if (!bIsReallyOurFrame)
{
XSelectInput( GetDisplay()->GetDisplay(), mhForeignParent, StructureNotifyMask | FocusChangeMask );
XSelectInput( GetDisplay()->GetDisplay(), mhShellWindow, StructureNotifyMask | FocusChangeMask );
}
} else
{ if( ! bUseGeometry )
{
Size aScreenSize( GetDisplay()->getDataForScreen( m_nXScreen ).m_aSize );
w = aScreenSize.Width();
h = aScreenSize.Height(); if( nSalFrameStyle & SalFrameStyleFlags::SIZEABLE &&
nSalFrameStyle & SalFrameStyleFlags::MOVEABLE )
{
Size aBestFitSize(bestmaxFrameSizeForScreenSize(aScreenSize));
w = aBestFitSize.Width();
h = aBestFitSize.Height();
} if( ! mpParent )
{ // find the last document window (if any) const X11SalFrame* pFrame = nullptr; bool bIsDocumentWindow = false; for (auto pSalFrame : GetDisplay()->getFrames() )
{
pFrame = static_cast< const X11SalFrame* >( pSalFrame ); if( !pFrame->mpParent
&& !pFrame->mbFullScreen
&& ( pFrame->nStyle_ & SalFrameStyleFlags::SIZEABLE )
&& pFrame->GetUnmirroredGeometry().width()
&& pFrame->GetUnmirroredGeometry().height() )
{
bIsDocumentWindow = true; break;
}
}
if( bIsDocumentWindow )
{ // set a document position and size // the first frame gets positioned by the window manager const SalFrameGeometry aGeom( pFrame->GetUnmirroredGeometry() );
x = aGeom.x();
y = aGeom.y(); if( x+static_cast<int>(w)+40 <= static_cast<int>(aScreenSize.Width()) &&
y+static_cast<int>(h)+40 <= static_cast<int>(aScreenSize.Height())
)
{
y += 40;
x += 40;
} else
{
x = 10; // leave some space for decoration
y = 20;
}
} elseif( GetDisplay()->IsXinerama() )
{ // place frame on same screen as mouse pointer
::Window aRoot, aChild; int root_x = 0, root_y = 0, lx, ly; unsignedint mask;
XQueryPointer( GetXDisplay(),
GetDisplay()->GetRootWindow( m_nXScreen ),
&aRoot, &aChild,
&root_x, &root_y, &lx, &ly, &mask ); const std::vector< AbsoluteScreenPixelRectangle >& rScreens = GetDisplay()->GetXineramaScreens(); for(constauto & rScreen : rScreens) if( rScreen.Contains( AbsoluteScreenPixelPoint( root_x, root_y ) ) )
{
x = rScreen.Left();
y = rScreen.Top(); break;
}
}
}
}
Attributes.win_gravity = pDisplay_->getWMAdaptor()->getInitWinGravity();
nAttrMask |= CWWinGravity; if( mpParent )
{
Attributes.save_under = True;
nAttrMask |= CWSaveUnder;
} if( IsOverrideRedirect() )
Attributes.override_redirect = True; // default icon if( !(nStyle_ & SalFrameStyleFlags::INTRO) && !(nStyle_ & SalFrameStyleFlags::NOICON))
{ try
{
CreateNetWmAppIcon( mnIconID != SV_ICON_ID_OFFICE ? mnIconID :
(mpParent ? mpParent->mnIconID : SV_ICON_ID_OFFICE), netwm_icon );
} catch( css::uno::Exception& )
{ // can happen - no ucb during early startup
}
}
// find the top level frame of the transience hierarchy
X11SalFrame* pFrame = this; while( pFrame->mpParent )
pFrame = pFrame->mpParent; if( pFrame->nStyle_ & SalFrameStyleFlags::PLUG )
{ // if the top level window is a plugin window, // then we should place us in the same window group as // the parent application (or none if there is no window group // hint in the parent). if( pFrame->GetShellWindow() )
{
XWMHints* pWMHints = XGetWMHints( pDisplay_->GetDisplay(),
pFrame->GetShellWindow() ); if( pWMHints )
{ if( pWMHints->flags & WindowGroupHint )
{
Hints.flags |= WindowGroupHint;
Hints.window_group = pWMHints->window_group;
}
XFree( pWMHints );
}
}
} else
{
Hints.flags |= WindowGroupHint;
Hints.window_group = pFrame->GetShellWindow(); // note: for a normal document window this will produce None // as the window is not yet created and the shell window is // initialized to None. This must be corrected after window creation.
aClientLeader = GetDisplay()->GetDrawable( m_nXScreen );
}
}
// LibreOffice advertises NET_WM_PING atom, so mutter rightfully warns of an unresponsive application during debugging. // Hack that out unconditionally for debug builds, as per https://bugzilla.redhat.com/show_bug.cgi?id=981149 // upstream refuses to make this configurable in any way. // NOTE: You need to use the 'gen' backend for this to work (SAL_USE_VCLPLUGIN=gen) #if OSL_DEBUG_LEVEL < 1 if( pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING ) )
a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING ); #endif
if( nSalFrameStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_TAKE_FOCUS );
XSetWMProtocols( GetXDisplay(), GetShellWindow(), a, n );
// force wm class hint
mnExtStyle = ~0; if (mpParent)
m_sWMClass = mpParent->m_sWMClass;
SetExtendedFrameStyle( 0 );
// set bViewable_ to true: hack GetClientSize to report something // different to 0/0 before first map
bViewable_ = true;
bMapped_ = false;
bDefaultPosition_ = true;
nVisibility_ = VisibilityFullyObscured;
m_nWorkArea = 0;
m_bXEmbed = false;
// remove from parent's list if( mpParent )
mpParent->maChildren.remove( this );
// deregister on SalDisplay
pDisplay_->deregisterFrame( this );
// unselect all events, some may be still in the queue anyway if( ! IsSysChildWindow() )
XSelectInput( GetXDisplay(), GetShellWindow(), 0 );
XSelectInput( GetXDisplay(), GetWindow(), 0 );
// HACK: this is a workaround for (at least) kwin // even though transient frames should be kept above their parent // this does not necessarily hold true for DOCK type windows // so artificially set ABOVE and remove it again on hide if( mpParent && mpParent->m_bIsPartialFullScreen && pDisplay_->getWMAdaptor()->isLegacyPartialFullscreen())
pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bVisible );
// update NET_WM_STATE which may have been deleted due to earlier Show(false) if( nShowState_ == X11ShowState::Hidden )
GetDisplay()->getWMAdaptor()->frameIsMapping( this );
/* * Actually this is rather exotic and currently happens only in conjunction * with the basic dialogue editor, * which shows a frame and instantly hides it again. After that the * editor window is shown and the WM takes this as an opportunity * to show our hidden transient frame also. So Show( false ) must * withdraw the frame AND delete the WM_TRANSIENT_FOR property. * In case the frame is shown again, the transient hint must be restored here.
*/ if( ! IsChildWindow()
&& ! IsOverrideRedirect()
&& ! IsFloatGrabWindow()
&& mpParent
)
{
GetDisplay()->getWMAdaptor()->changeReferenceFrame( this, mpParent );
}
// #i45160# switch to desktop where a dialog with parent will appear if( mpParent && mpParent->m_nWorkArea != m_nWorkArea )
GetDisplay()->getWMAdaptor()->switchToWorkArea( mpParent->m_nWorkArea );
if( IsFloatGrabWindow() &&
mpParent &&
nVisibleFloats == 0 &&
! GetDisplay()->GetCaptureFrame() )
{ /* #i39420# * outsmart KWin's "focus strictly under mouse" mode * which insists on taking the focus from the document * to the new float. Grab focus to parent frame BEFORE * showing the float (cannot grab it to the float * before show).
*/
XGrabPointer( GetXDisplay(),
mpParent->GetWindow(), True,
PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
GrabModeAsync,
GrabModeAsync,
None,
mpParent ? mpParent->GetCursor() : None,
CurrentTime
);
}
if( IsFloatGrabWindow() )
{ /* * Sawfish and twm can be switched to enter-exit focus behaviour. In this case * we must grab the pointer else the dumb WM will put the focus to the * override-redirect float window. The application window will be deactivated * which causes that the floats are destroyed, so the user can never click on * a menu because it vanishes as soon as he enters it.
*/
nVisibleFloats++; if( nVisibleFloats == 1 && ! GetDisplay()->GetCaptureFrame() )
{ /* #i39420# now move grab to the new float window */
XGrabPointer( GetXDisplay(),
GetWindow(), True,
PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
GrabModeAsync,
GrabModeAsync,
None,
mpParent ? mpParent->GetCursor() : None,
CurrentTime
);
}
}
CallCallback( SalEvent::Resize, nullptr );
/* * sometimes a message box/dialogue is brought up when a frame is not mapped * the corresponding TRANSIENT_FOR hint is then set to the root window * so that the dialogue shows in all cases. Correct it here if the * frame is shown afterwards.
*/ if( ! IsChildWindow()
&& ! IsOverrideRedirect()
&& ! IsFloatGrabWindow()
)
{ for (autoconst& child : maChildren)
{ if( child->mbTransientForRoot )
GetDisplay()->getWMAdaptor()->changeReferenceFrame( child, this );
}
} /* * leave X11ShowState::Unknown as this indicates first mapping * and is only reset int HandleSizeEvent
*/ if( nShowState_ != X11ShowState::Unknown )
nShowState_ = X11ShowState::Normal;
/* * plugged windows don't necessarily get the * focus on show because the parent may already be mapped * and have the focus. So try to set the focus * to the child on Show(true)
*/ if( (nStyle_ & SalFrameStyleFlags::PLUG) && ! m_bXEmbed )
XSetInputFocus( GetXDisplay(),
GetWindow(),
RevertToParent,
CurrentTime );
if( mpParent )
{ // push this frame so it will be in front of its siblings // only necessary for insane transient behaviour of Dtwm/olwm
mpParent->maChildren.remove( this );
mpParent->maChildren.push_front(this);
}
} else
{ if( getInputContext() )
getInputContext()->Unmap();
nShowState_ = X11ShowState::Hidden; if( IsFloatGrabWindow() && nVisibleFloats )
{
nVisibleFloats--; if( nVisibleFloats == 0 && ! GetDisplay()->GetCaptureFrame() )
XUngrabPointer( GetXDisplay(),
CurrentTime );
} // flush here; there may be a very seldom race between // the display connection used for clipboard and our connection
Flush();
}
}
void X11SalFrame::SetPointerPos(tools::Long nX, tools::Long nY)
{ /* when the application tries to center the mouse in the dialog the * window isn't mapped already. So use coordinates relative to the root window.
*/ unsignedint nWindowLeft = maGeometry.x() + nX; unsignedint nWindowTop = maGeometry.y() + nY;
// 2. We should use on-the-spot inputstyle // only when InputContextFlags::ExtTExt is set.
if (mpInputContext == nullptr)
{
mpInputContext.reset( new SalI18N_InputContext( this ) ); if (mpInputContext->UseContext())
{
mpInputContext->ExtendEventMask( GetShellWindow() ); if (mbInputFocus)
mpInputContext->SetICFocus( this );
}
} else
mpInputContext->Map( this );
}
if( LeaveNotify == pEvent->type || EnterNotify == pEvent->type )
{ /* * some WMs (and/or) applications have a passive grab on * mouse buttons (XGrabButton). This leads to enter/leave notifies * with mouse buttons pressed in the state mask before the actual * ButtonPress event gets dispatched. But EnterNotify * is reported in vcl as MouseMove event. Some office code * decides that a pressed button in a MouseMove belongs to * a drag operation which leads to doing things differently. * * ignore Enter/LeaveNotify resulting from grabs so that * help windows do not disappear just after appearing * * hopefully this workaround will not break anything.
*/ if( pEvent->xcrossing.mode == NotifyGrab || pEvent->xcrossing.mode == NotifyUngrab ) returnfalse;
XChangeActivePointerGrab( GetXDisplay(),
PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
aCursor,
CurrentTime );
}
} else
{ // let mouse events reach the correct window if( nVisibleFloats < 1 )
{ if( ! (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION) )
XUngrabPointer( GetXDisplay(), CurrentTime );
} elseif( pEvent->type == ButtonPress )
{ // see if the user clicks outside all of the floats // if yes release the grab bool bInside = false; for (auto pSalFrame : GetDisplay()->getFrames() )
{ const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame ); if( pFrame->IsFloatGrabWindow() &&
pFrame->bMapped_ &&
pEvent->xbutton.x_root >= pFrame->maGeometry.x() &&
pEvent->xbutton.x_root < pFrame->maGeometry.x() + static_cast<int>(pFrame->maGeometry.width()) &&
pEvent->xbutton.y_root >= pFrame->maGeometry.y() &&
pEvent->xbutton.y_root < pFrame->maGeometry.y() + static_cast<int>(pFrame->maGeometry.height()) )
{
bInside = true; break;
}
} if( ! bInside )
{ // need not take care of the XUngrabPointer in Show( false ) // because XUngrabPointer does not produce errors if pointer // is not grabbed
XUngrabPointer( GetXDisplay(), CurrentTime );
bClosePopups = true;
/* #i15246# only close popups if pointer is outside all our frames * cannot use our own geometry data here because stacking * is unknown (the above case implicitly assumes * that floats are on top which should be true)
*/
::Window aRoot, aChild; int root_x, root_y, win_x, win_y; unsignedint mask_return; if( XQueryPointer( GetXDisplay(),
GetDisplay()->GetRootWindow( m_nXScreen ),
&aRoot, &aChild,
&root_x, &root_y,
&win_x, &win_y,
&mask_return )
&& aChild // pointer may not be in any child
)
{ for (auto pSalFrame : GetDisplay()->getFrames() )
{ const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame ); if( ! pFrame->IsFloatGrabWindow()
&& ( pFrame->GetWindow() == aChild ||
pFrame->GetShellWindow() == aChild ||
pFrame->GetStackingWindow() == aChild )
)
{ // #i63638# check that pointer is inside window, not // only inside stacking window if( root_x >= pFrame->maGeometry.x() && root_x < sal::static_int_cast< int >(pFrame->maGeometry.x()+pFrame->maGeometry.width()) &&
root_y >= pFrame->maGeometry.y() && root_y < sal::static_int_cast< int >(pFrame->maGeometry.x()+pFrame->maGeometry.height()) )
{
bClosePopups = false;
} break;
}
}
}
}
}
bool X11SalFrame::HandleKeyEvent( XKeyEvent *pEvent )
{ if( pEvent->type == KeyRelease )
{ // Ignore autorepeat keyrelease events. If there is a series of keypress+keyrelease+keypress events // generated by holding down a key, and if these are from autorepeat (keyrelease and the following keypress // have the same timestamp), drop the autorepeat keyrelease event. Not exactly sure why this is done // (possibly hiding differences between platforms, or just making it more sensible, because technically // the key has not been released at all). bool ignore = false; // Discard queued excessive autorepeat events. // If the user presses and holds down a key, the autorepeating keypress events // may overload LO (e.g. if the key is PageDown and the LO cannot keep up scrolling). // Reduce the load by simply discarding such excessive events (so for a KeyRelease event, // check if it's followed by matching KeyPress+KeyRelease pair(s) and discard those). // This shouldn't have any negative effects - unlike with normal (non-autorepeat // events), the user is unlikely to rely on the exact number of resulting actions // (since autorepeat generates keypress events rather quickly and it's hard to estimate // how many exactly) and the idea should be just keeping the key pressed until something // happens (in which case more events that just lag LO shouldn't make a difference).
Display* dpy = pEvent->display;
XKeyEvent previousRelease = *pEvent; while( XPending( dpy ))
{
XEvent nextEvent1; bool discard1 = false;
XNextEvent( dpy, &nextEvent1 ); if( nextEvent1.type == KeyPress && nextEvent1.xkey.time == previousRelease.time
&& !nextEvent1.xkey.send_event && nextEvent1.xkey.window == previousRelease.window
&& nextEvent1.xkey.state == previousRelease.state && nextEvent1.xkey.keycode == previousRelease.keycode )
{ // This looks like another autorepeat keypress.
ignore = true; if( XPending( dpy ))
{
XEvent nextEvent2;
XNextEvent( dpy, &nextEvent2 ); if( nextEvent2.type == KeyRelease && nextEvent2.xkey.time <= ( previousRelease.time + 100 )
&& !nextEvent2.xkey.send_event && nextEvent2.xkey.window == previousRelease.window
&& nextEvent2.xkey.state == previousRelease.state && nextEvent2.xkey.keycode == previousRelease.keycode )
{ // And the matching keyrelease -> drop them both.
discard1 = true;
previousRelease = nextEvent2.xkey;
ignore = false; // There either will be another autorepeating keypress that'll lead to discarding // the pEvent keyrelease, it this discarding makes that keyrelease the last one.
} else
{
XPutBackEvent( dpy, &nextEvent2 ); break;
}
}
} if( !discard1 )
{ // Unrelated event, put back and stop compressing.
XPutBackEvent( dpy, &nextEvent1 ); break;
}
} if( ignore ) // This autorepeating keyrelease is followed by another keypress. returnfalse;
}
// singlebyte code composed by input method, the new default if (mpInputContext != nullptr && mpInputContext->UseContext())
{ // returns a keysym as well as the pPrintable (in system encoding) // printable may be empty.
Status nStatus;
nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen,
&nUnmodifiedKeySym,
&nStatus, mpInputContext->GetContext() ); if ( nStatus == XBufferOverflow )
{ // In case of overflow, XmbLookupString (called by GetKeySym) // returns required size // TODO : check if +1 is needed for 0 terminator
nLen += 1;
pPrintable = static_cast<char*>(alloca( nLen ));
nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen,
&nUnmodifiedKeySym,
&nStatus, mpInputContext->GetContext() );
}
} else
{ // fallback, this should never ever be called
Status nStatus = 0;
nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen, &nUnmodifiedKeySym, &nStatus );
}
// pressing just the ctrl key leads to a keysym of XK_Control but // the event state does not contain ControlMask. In the release // event it's the other way round: it does contain the Control mask. // The modifier mode therefore has to be adapted manually.
ModKeyFlags nExtModMask = ModKeyFlags::NONE;
sal_uInt16 nModMask = 0; switch( nKeySym )
{ case XK_Control_L:
nExtModMask = ModKeyFlags::LeftMod1;
nModMask = KEY_MOD1; break; case XK_Control_R:
nExtModMask = ModKeyFlags::RightMod1;
nModMask = KEY_MOD1; break; case XK_Alt_L:
nExtModMask = ModKeyFlags::LeftMod2;
nModMask = KEY_MOD2; break; case XK_Alt_R:
nExtModMask = ModKeyFlags::RightMod2;
nModMask = KEY_MOD2; break; case XK_Shift_L:
nExtModMask = ModKeyFlags::LeftShift;
nModMask = KEY_SHIFT; break; case XK_Shift_R:
nExtModMask = ModKeyFlags::RightShift;
nModMask = KEY_SHIFT; break; // Map Meta/Super keys to MOD3 modifier on all Unix systems // except macOS case XK_Meta_L: case XK_Super_L:
nExtModMask = ModKeyFlags::LeftMod3;
nModMask = KEY_MOD3; break; case XK_Meta_R: case XK_Super_R:
nExtModMask = ModKeyFlags::RightMod3;
nModMask = KEY_MOD3; break;
} if( pEvent->type == KeyRelease )
{
nModCode &= ~nModMask;
mnExtKeyMod &= ~nExtModMask;
} else
{
nModCode |= nModMask;
mnExtKeyMod |= nExtModMask;
}
// try to figure out the vcl code for the keysym // #i52338# use the unmodified KeySym if there is none for the real KeySym // because the independent part has only keycodes for unshifted keys
nKeyCode = pDisplay_->GetKeyCode( nKeySym, &aDummy ); if( nKeyCode == 0 )
nKeyCode = pDisplay_->GetKeyCode( nUnmodifiedKeySym, &aDummy );
// try to figure out a printable if XmbLookupString returns only a keysym // and NOT a printable. Do not store it in pPrintable[0] since it is expected to // be in system encoding, not unicode. // #i8988##, if KeySym and printable look equally promising then prefer KeySym // the printable is bound to the encoding so the KeySym might contain more // information (in et_EE locale: "Compose + Z + <" delivers "," in printable and // (the desired) Zcaron in KeySym
sal_Unicode nKeyString = 0x0; if ( (nLen == 0)
|| ((nLen == 1) && (nKeySym > 0)) )
nKeyString = KeysymToUnicode (nKeySym); // if we have nothing we give up if( !nKeyCode && !nLen && !nKeyString) returnfalse;
if( KeyRelease == pEvent->type )
{
CallCallback( SalEvent::KeyUp, &aKeyEvt );
} else
{ if ( ! CallCallback(SalEvent::KeyInput, &aKeyEvt) )
{ // independent layer doesn't want to handle key-event, so check // whether the keycode may have an alternate meaning
KeyAlternate aAlternate = GetAlternateKeyCode( nKeyCode ); if ( aAlternate.nKeyCode != 0 )
{
aKeyEvt.mnCode = aAlternate.nKeyCode | nModCode; if( aAlternate.nCharCode )
aKeyEvt.mnCharCode = aAlternate.nCharCode;
CallCallback(SalEvent::KeyInput, &aKeyEvt);
}
}
}
}
// update the spot location for PreeditPosition IME style
if (! aDeleteWatch.isDeleted())
{ if (mpInputContext != nullptr && mpInputContext->UseContext())
mpInputContext->UpdateSpotLocation();
}
free (pBuffer); returntrue;
}
bool X11SalFrame::HandleFocusEvent( XFocusChangeEvent const *pEvent )
{ // ReflectionX in Windows mode changes focus while mouse is grabbed if( nVisibleFloats > 0 && GetDisplay()->getWMAdaptor()->getWindowManagerName() == "ReflectionX Windows" ) returntrue;
/* ignore focusout resulting from keyboard grabs * we do not grab it and are not interested when * someone else does CDE e.g. does a XGrabKey on arrow keys * handle focus events with mode NotifyWhileGrabbed * because with CDE alt-tab focus changing we do not get * normal focus events * cast focus event to the input context, otherwise the * status window does not follow the application frame
*/
if ( mpInputContext != nullptr )
{ if( FocusIn == pEvent->type )
mpInputContext->SetICFocus( this );
}
if( IsOverrideRedirect() && mbFullScreen &&
aPresentationReparentList.empty() ) // we are in fullscreen mode -> override redirect // focus is possibly lost, so reget it
XSetInputFocus( GetXDisplay(), GetShellWindow(), RevertToNone, CurrentTime );
// width and height are extents, so they are of by one for rectangle
maPaintRegion.Union( tools::Rectangle( Point(aRect.x, aRect.y), Size(aRect.width+1, aRect.height+1) ) );
if( nCount ) // wait for last expose rectangle, do not wait for resize timer // if a completed graphics expose sequence is available returntrue;
staticBool size_event_predicate( Display*, XEvent* event, XPointer arg )
{ if( event->type != ConfigureNotify ) returnFalse;
X11SalFrame* frame = reinterpret_cast< X11SalFrame* >( arg );
XConfigureEvent* pEvent = &event->xconfigure; if( pEvent->window != frame->GetShellWindow()
&& pEvent->window != frame->GetWindow()
&& pEvent->window != frame->GetForeignParent()
&& pEvent->window != frame->GetStackingWindow())
{ // ignored at top of HandleSizeEvent() returnFalse;
} if( pEvent->window == frame->GetStackingWindow()) returnFalse; // filtered later in HandleSizeEvent() // at this point we know that there is another similar event in the queue
frame->setPendingSizeEvent(); returnFalse; // but do not process the new event out of order
}
bool X11SalFrame::HandleSizeEvent( XConfigureEvent *pEvent )
{ // NOTE: if you add more tests in this function, make sure to update size_event_predicate() // so that it finds exactly the same events
if ( pEvent->window != GetShellWindow()
&& pEvent->window != GetWindow()
&& pEvent->window != GetForeignParent()
&& pEvent->window != GetStackingWindow()
)
{ // could be as well a sys-child window (aka SalObject) returntrue;
}
// check size hints in first time SalFrame::Show if( X11ShowState::Unknown == nShowState_ && bMapped_ )
nShowState_ = X11ShowState::Normal;
// Avoid a race condition where resizing this window to one size and shortly after that // to another size generates first size event with the old size and only after that // with the new size, temporarily making us think the old size is valid (bnc#674806). // So if there is another size event for this window pending, ignore this one.
mPendingSizeEvent = false;
XEvent dummy;
XCheckIfEvent( GetXDisplay(), &dummy, size_event_predicate, reinterpret_cast< XPointer >( this )); if( mPendingSizeEvent ) returntrue;
/* * don't rely on the new parent from the event. * the event may be "out of date", that is the window manager * window may not exist anymore. This can happen if someone * shows a frame and hides it again quickly (not that it would * be very sensible)
*/
hWM_Parent = GetShellWindow(); do
{
Children = nullptr;
XQueryTree( pDisplay,
hWM_Parent,
&hRoot,
&hDummy,
&Children,
&nChildren );
/* * evil hack to show decorated windows on top * of override redirect presentation windows: * reparent the window manager window to the presentation window * does not work with non-reparenting WMs * in future this should not be necessary anymore with * _NET_WM_STATE_FULLSCREEN available
*/ if( hPresentationWindow != None
&& hPresentationWindow != GetWindow()
&& GetStackingWindow() != None
&& GetStackingWindow() != GetDisplay()->GetRootWindow( m_nXScreen )
)
{ int x = 0, y = 0;
::Window aChild;
XTranslateCoordinates( GetXDisplay(),
GetStackingWindow(),
GetDisplay()->GetRootWindow( m_nXScreen ),
0, 0,
&x, &y,
&aChild
);
XReparentWindow( GetXDisplay(),
GetStackingWindow(),
hPresentationWindow,
x, y
);
aPresentationReparentList.push_back( GetStackingWindow() );
}
if( ! bError )
{
maGeometry.setRightDecoration(wp - w - maGeometry.leftDecoration());
maGeometry.setBottomDecoration(hp - h - maGeometry.topDecoration());
bResized = w != o3tl::make_unsigned(maGeometry.width()) ||
h != o3tl::make_unsigned(maGeometry.height()); /* * note: this works because hWM_Parent is direct child of root, * not necessarily parent of GetShellWindow()
*/
maGeometry.setPosSize({ xp + nLeft, yp + nTop }, { static_cast<tools::Long>(w), static_cast<tools::Long>(h) });
}
// limit width and height if we are too large: #47757 // olwm and fvwm need this, it doesn't harm the rest
// #i81311# do this only for sizable frames if( nStyle_ & SalFrameStyleFlags::SIZEABLE )
{
AbsoluteScreenPixelSize aScreenSize = GetDisplay()->GetScreenSize( m_nXScreen ); int nScreenWidth = aScreenSize.Width(); int nScreenHeight = aScreenSize.Height(); int nFrameWidth = maGeometry.width() + maGeometry.leftDecoration() + maGeometry.rightDecoration(); int nFrameHeight = maGeometry.height() + maGeometry.topDecoration() + maGeometry.bottomDecoration();
case KeyRelease:
nRet = HandleKeyEvent( &pEvent->xkey ); break;
case ButtonPress: // if we lose the focus in presentation mode // there are good chances that we never get it back // since the WM ignores us if( IsOverrideRedirect() )
{
XSetInputFocus( GetXDisplay(), GetShellWindow(),
RevertToNone, CurrentTime );
}
[[fallthrough]]; case ButtonRelease: case MotionNotify: case EnterNotify: case LeaveNotify:
nRet = HandleMouseEvent( pEvent ); break;
case FocusIn: case FocusOut:
nRet = HandleFocusEvent( &pEvent->xfocus ); break;
case Expose: case GraphicsExpose:
nRet = HandleExposeEvent( pEvent ); break;
case MapNotify: if( pEvent->xmap.window == GetShellWindow() )
{ if( nShowState_ == X11ShowState::Hidden )
{ /* * workaround for (at least) KWin 2.2.2 * which will map windows that were once transient * even if they are withdrawn when the respective * document is mapped.
*/ if( ! (nStyle_ & SalFrameStyleFlags::PLUG) )
XUnmapWindow( GetXDisplay(), GetShellWindow() ); break;
}
bMapped_ = true;
bViewable_ = true;
nRet = true; if ( mpInputContext != nullptr )
mpInputContext->Map( this );
CallCallback( SalEvent::Resize, nullptr );
bool bSetFocus = m_bSetFocusOnMap;
/* * sometimes a message box/dialogue is brought up when a frame is not mapped * the corresponding TRANSIENT_FOR hint is then set to the root window * so that the dialogue shows in all cases. Correct it here if the * frame is shown afterwards.
*/ if( ! IsChildWindow()
&& ! IsOverrideRedirect()
&& ! IsFloatGrabWindow()
)
{ for (autoconst& child : maChildren)
{ if( child->mbTransientForRoot )
pDisplay_->getWMAdaptor()->changeReferenceFrame( child, this );
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.