blob: 0f10e1aa4d4519e8e2c6778bc8393702c4e20ccc [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "tools/debug.hxx"
#include "sal/alloca.h"
#include "vcl/floatwin.hxx"
#include "vcl/svapp.hxx"
#include "vcl/keycodes.hxx"
#include "vcl/printerinfomanager.hxx"
#include "vcl/settings.hxx"
#include <tools/prex.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include "FWS.hxx"
#include <X11/extensions/shape.h>
#ifndef SOLARIS
#include <X11/extensions/dpms.h>
#endif
#include <tools/postx.h>
#include "unx/salunx.h"
#include "unx/saldata.hxx"
#include "unx/saldisp.hxx"
#include "unx/salgdi.h"
#include "unx/salframe.h"
#include "unx/soicon.hxx"
#include "unx/dtint.hxx"
#include "unx/sm.hxx"
#include "unx/wmadaptor.hxx"
#include "unx/salprn.h"
#include "unx/salbmp.h"
#include "unx/i18n_ic.hxx"
#include "unx/i18n_keysym.hxx"
#include "unx/i18n_status.hxx"
#include "salinst.hxx"
#include "sallayout.hxx"
#include <com/sun/star/uno/Exception.hpp>
#include <algorithm>
#ifndef Button6
# define Button6 6
#endif
#ifndef Button7
# define Button7 7
#endif
using namespace vcl_sal;
using namespace vcl;
// -=-= #defines -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#define CLIENT_EVENTS StructureNotifyMask \
| SubstructureNotifyMask \
| KeyPressMask \
| KeyReleaseMask \
| ButtonPressMask \
| ButtonReleaseMask \
| PointerMotionMask \
| EnterWindowMask \
| LeaveWindowMask \
| FocusChangeMask \
| ExposureMask \
| VisibilityChangeMask \
| PropertyChangeMask \
| ColormapChangeMask
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static XLIB_Window hPresentationWindow = None, hPresFocusWindow = None;
static ::std::list< XLIB_Window > aPresentationReparentList;
static int nVisibleFloats = 0;
X11SalFrame* X11SalFrame::s_pSaveYourselfFrame = NULL;
// -=-= C++ statics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static void doReparentPresentationDialogues( SalDisplay* pDisplay )
{
pDisplay->GetXLib()->PushXErrorLevel( true );
while( aPresentationReparentList.begin() != aPresentationReparentList.end() )
{
int x, y;
XLIB_Window aRoot, aChild;
unsigned int w, h, bw, d;
XGetGeometry( pDisplay->GetDisplay(),
aPresentationReparentList.front(),
&aRoot,
&x, &y, &w, &h, &bw, &d );
XTranslateCoordinates( pDisplay->GetDisplay(),
hPresentationWindow,
aRoot,
x, y,
&x, &y,
&aChild );
XReparentWindow( pDisplay->GetDisplay(),
aPresentationReparentList.front(),
aRoot,
x, y );
aPresentationReparentList.pop_front();
}
if( hPresFocusWindow )
XSetInputFocus( pDisplay->GetDisplay(), hPresFocusWindow, PointerRoot, CurrentTime );
XSync( pDisplay->GetDisplay(), False );
pDisplay->GetXLib()->PopXErrorLevel();
}
// -=-= SalFrame / X11SalFrame =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool X11SalFrame::IsOverrideRedirect() const
{
return
((nStyle_ & SAL_FRAME_STYLE_INTRO) && !pDisplay_->getWMAdaptor()->supportsSplash())
||
(!( nStyle_ & ~SAL_FRAME_STYLE_DEFAULT ) && !pDisplay_->getWMAdaptor()->supportsFullScreen())
;
}
bool X11SalFrame::IsFloatGrabWindow() const
{
static const char* pDisableGrab = getenv( "SAL_DISABLE_FLOATGRAB" );
return
( ( !pDisableGrab || !*pDisableGrab ) &&
(
(nStyle_ & SAL_FRAME_STYLE_FLOAT) &&
! (nStyle_ & SAL_FRAME_STYLE_TOOLTIP) &&
! (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION)
)
);
}
void X11SalFrame::setXEmbedInfo()
{
if( m_bXEmbed )
{
long aInfo[2];
aInfo[0] = 1; // XEMBED protocol version
aInfo[1] = (bMapped_ ? 1 : 0); // XEMBED_MAPPED
XChangeProperty( pDisplay_->GetDisplay(),
mhWindow,
pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO ),
pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO ),
32,
PropModeReplace,
reinterpret_cast<unsigned char*>(aInfo),
sizeof(aInfo)/sizeof(aInfo[0]) );
}
}
void X11SalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
{
XEvent aEvent;
rtl_zeroMemory( &aEvent, sizeof(aEvent) );
aEvent.xclient.window = mhForeignParent;
aEvent.xclient.type = ClientMessage;
aEvent.xclient.message_type = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED );
aEvent.xclient.format = 32;
aEvent.xclient.data.l[0] = i_nTimeCode ? i_nTimeCode : CurrentTime;
aEvent.xclient.data.l[1] = 3; // XEMBED_REQUEST_FOCUS
aEvent.xclient.data.l[2] = 0;
aEvent.xclient.data.l[3] = 0;
aEvent.xclient.data.l[4] = 0;
GetDisplay()->GetXLib()->PushXErrorLevel( true );
XSendEvent( pDisplay_->GetDisplay(),
mhForeignParent,
False, NoEventMask, &aEvent );
XSync( pDisplay_->GetDisplay(), False );
GetDisplay()->GetXLib()->PopXErrorLevel();
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::Init( sal_uLong nSalFrameStyle, int nScreen, SystemParentData* pParentData, bool bUseGeometry )
{
if( nScreen < 0 || nScreen >= GetDisplay()->GetScreenCount() )
nScreen = GetDisplay()->GetDefaultScreenNumber();
if( mpParent )
nScreen = mpParent->m_nScreen;
m_nScreen = nScreen;
nStyle_ = nSalFrameStyle;
XWMHints Hints;
Hints.flags = InputHint;
Hints.input = (nSalFrameStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) ? False : True;
int x = 0, y = 0;
unsigned int w = 500, h = 500;
XSetWindowAttributes Attributes;
int nAttrMask = CWBorderPixel
| CWBackPixmap
| CWColormap
| CWOverrideRedirect
| CWEventMask
;
Attributes.border_pixel = 0;
Attributes.background_pixmap = None;
Attributes.colormap = GetDisplay()->GetColormap( m_nScreen ).GetXColormap();
Attributes.override_redirect = False;
Attributes.event_mask = CLIENT_EVENTS;
const SalVisual& rVis = GetDisplay()->GetVisual( m_nScreen );
XLIB_Window aFrameParent = pParentData ? pParentData->aWindow : GetDisplay()->GetRootWindow( m_nScreen );
XLIB_Window aClientLeader = None;
if( bUseGeometry )
{
x = maGeometry.nX;
y = maGeometry.nY;
w = maGeometry.nWidth;
h = maGeometry.nHeight;
}
if( (nSalFrameStyle & SAL_FRAME_STYLE_FLOAT) &&
! (nSalFrameStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION)
)
{
if( nShowState_ == SHOWSTATE_UNKNOWN )
{
w = 10;
h = 10;
}
Attributes.override_redirect = True;
}
else if( (nSalFrameStyle & SAL_FRAME_STYLE_SYSTEMCHILD ) )
{
DBG_ASSERT( mpParent, "SAL_FRAME_STYLE_SYSTEMCHILD window without parent" );
if( mpParent )
{
aFrameParent = mpParent->mhWindow;
// FIXME: since with SAL_FRAME_STYLE_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();
}
}
else if( pParentData )
{
// plugin parent may be killed unexpectedly by
// plugging process; ignore XErrors in that case
GetDisplay()->setHaveSystemChildFrame();
nStyle_ |= SAL_FRAME_STYLE_PLUG;
Attributes.override_redirect = True;
if( pParentData->nSize >= sizeof(SystemParentData) )
m_bXEmbed = pParentData->bXEmbedSupport;
int x_ret, y_ret;
unsigned int bw, d;
XLIB_Window aRoot, aParent;
XGetGeometry( GetXDisplay(), pParentData->aWindow,
&aRoot, &x_ret, &y_ret, &w, &h, &bw, &d );
mhForeignParent = pParentData->aWindow;
mhShellWindow = aParent = mhForeignParent;
XLIB_Window* pChildren;
unsigned int nChildren;
bool bBreak = false;
do
{
XQueryTree( GetDisplay()->GetDisplay(), mhShellWindow,
&aRoot, &aParent, &pChildren, &nChildren );
XFree( pChildren );
if( aParent != aRoot )
mhShellWindow = aParent;
int nCount = 0;
Atom* pProps = XListProperties( GetDisplay()->GetDisplay(),
mhShellWindow,
&nCount );
for( int i = 0; i < nCount && ! bBreak; ++i )
bBreak = (pProps[i] == XA_WM_HINTS);
if( pProps )
XFree( pProps );
} while( aParent != aRoot && ! bBreak );
// check if this is really one of our own frames
// do not change the input mask in that case
const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
std::list< SalFrame* >::const_iterator it = rFrames.begin();
while( it != rFrames.end() && mhForeignParent != static_cast<const X11SalFrame*>(*it)->GetWindow() )
++it;
if( it == rFrames.end() )
{
XSelectInput( GetDisplay()->GetDisplay(), mhForeignParent, StructureNotifyMask | FocusChangeMask );
XSelectInput( GetDisplay()->GetDisplay(), mhShellWindow, StructureNotifyMask | FocusChangeMask );
}
}
else
{
if( ! bUseGeometry )
{
Size aScreenSize( GetDisplay()->getDataForScreen( m_nScreen ).m_aSize );
w = aScreenSize.Width();
h = aScreenSize.Height();
if( nSalFrameStyle & SAL_FRAME_STYLE_SIZEABLE &&
nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE )
{
// fill in holy default values brought to us by product management
if( aScreenSize.Width() >= 800 )
w = 785;
if( aScreenSize.Width() >= 1024 )
w = 920;
if( aScreenSize.Height() >= 600 )
h = 550;
if( aScreenSize.Height() >= 768 )
h = 630;
if( aScreenSize.Height() >= 1024 )
h = 875;
}
if( ! mpParent )
{
// find the last document window (if any)
const X11SalFrame* pFrame = NULL;
const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
std::list< SalFrame* >::const_iterator it = rFrames.begin();
while( it != rFrames.end() )
{
pFrame = static_cast< const X11SalFrame* >(*it);
if( ! ( pFrame->mpParent
|| pFrame->mbFullScreen
|| ! ( pFrame->nStyle_ & SAL_FRAME_STYLE_SIZEABLE )
|| ! pFrame->GetUnmirroredGeometry().nWidth
|| ! pFrame->GetUnmirroredGeometry().nHeight
)
)
break;
++it;
}
if( it != rFrames.end() )
{
// set a document position and size
// the first frame gets positioned by the window manager
const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
x = rGeom.nX;
y = rGeom.nY;
if( x+(int)w+40 <= (int)aScreenSize.Width() &&
y+(int)h+40 <= (int)aScreenSize.Height()
)
{
y += 40;
x += 40;
}
else
{
x = 10; // leave some space for decoration
y = 20;
}
}
else if( GetDisplay()->IsXinerama() )
{
// place frame on same screen as mouse pointer
XLIB_Window aRoot, aChild;
int root_x = 0, root_y = 0, lx, ly;
unsigned int mask;
XQueryPointer( GetXDisplay(),
GetDisplay()->GetRootWindow( m_nScreen ),
&aRoot, &aChild,
&root_x, &root_y, &lx, &ly, &mask );
const std::vector< Rectangle >& rScreens = GetDisplay()->GetXineramaScreens();
for( unsigned int i = 0; i < rScreens.size(); i++ )
if( rScreens[i].IsInside( Point( root_x, root_y ) ) )
{
x = rScreens[i].Left();
y = rScreens[i].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_ & SAL_FRAME_STYLE_INTRO) == 0 )
{
bool bOk=false;
try
{
bOk=SelectAppIconPixmap( pDisplay_, m_nScreen,
mnIconID != 1 ? mnIconID :
(mpParent ? mpParent->mnIconID : 1), 32,
Hints.icon_pixmap, Hints.icon_mask );
}
catch( com::sun::star::uno::Exception& )
{
// can happen - no ucb during early startup
}
if( bOk )
{
Hints.flags |= IconPixmapHint;
if( Hints.icon_mask )
Hints.flags |= IconMaskHint;
}
}
// find the top level frame of the transience hierarchy
X11SalFrame* pFrame = this;
while( pFrame->mpParent )
pFrame = pFrame->mpParent;
if( (pFrame->nStyle_ & SAL_FRAME_STYLE_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_nScreen );
}
}
nShowState_ = SHOWSTATE_UNKNOWN;
bViewable_ = sal_True;
bMapped_ = sal_False;
nVisibility_ = VisibilityFullyObscured;
mhWindow = XCreateWindow( GetXDisplay(),
aFrameParent,
x, y,
w, h,
0,
rVis.GetDepth(),
InputOutput,
rVis.GetVisual(),
nAttrMask,
&Attributes );
// FIXME: see above: fake shell window for now to own window
if( /*! IsSysChildWindow() &&*/ pParentData == NULL )
{
mhShellWindow = mhWindow;
}
// correct window group if necessary
if( (Hints.flags & WindowGroupHint) == WindowGroupHint )
{
if( Hints.window_group == None )
Hints.window_group = GetShellWindow();
}
maGeometry.nX = x;
maGeometry.nY = y;
maGeometry.nWidth = w;
maGeometry.nHeight = h;
updateScreenNumber();
XSync( GetXDisplay(), False );
setXEmbedInfo();
XLIB_Time nUserTime = (nStyle_ & (SAL_FRAME_STYLE_OWNERDRAWDECORATION | SAL_FRAME_STYLE_TOOLWINDOW) ) == 0 ?
pDisplay_->GetLastUserEventTime() : 0;
pDisplay_->getWMAdaptor()->setUserTime( this, nUserTime );
if( ! pParentData && ! IsChildWindow() && ! Attributes.override_redirect )
{
XSetWMHints( GetXDisplay(), mhWindow, &Hints );
// WM Protocols && internals
Atom a[4];
int n = 0;
a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_DELETE_WINDOW );
if( pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING ) )
a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING );
if( ! s_pSaveYourselfFrame && ! mpParent)
{
// at all times have only one frame with SaveYourself
a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_SAVE_YOURSELF );
s_pSaveYourselfFrame = this;
}
if( (nSalFrameStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_TAKE_FOCUS );
XSetWMProtocols( GetXDisplay(), GetShellWindow(), a, n );
XClassHint* pClass = XAllocClassHint();
pClass->res_name = const_cast<char*>(X11SalData::getFrameResName());
pClass->res_class = const_cast<char*>(X11SalData::getFrameClassName());
XSetClassHint( GetXDisplay(), GetShellWindow(), pClass );
XFree( pClass );
XSizeHints* pHints = XAllocSizeHints();
pHints->flags = PWinGravity | PPosition;
pHints->win_gravity = GetDisplay()->getWMAdaptor()->getPositionWinGravity();
pHints->x = 0;
pHints->y = 0;
if( mbFullScreen )
{
pHints->flags |= PMaxSize | PMinSize;
pHints->max_width = w+100;
pHints->max_height = h+100;
pHints->min_width = w;
pHints->min_height = h;
}
XSetWMNormalHints( GetXDisplay(),
GetShellWindow(),
pHints );
XFree (pHints);
// set PID and WM_CLIENT_MACHINE
pDisplay_->getWMAdaptor()->setClientMachine( this );
pDisplay_->getWMAdaptor()->setPID( this );
// set client leader
if( aClientLeader )
{
XChangeProperty( GetXDisplay(),
mhWindow,
pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_CLIENT_LEADER),
XA_WINDOW,
32,
PropModeReplace,
(unsigned char*)&aClientLeader,
1
);
}
#define DECOFLAGS (SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE)
int nDecoFlags = WMAdaptor::decoration_All;
if( (nStyle_ & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN) ||
(nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION)
)
nDecoFlags = 0;
else if( (nStyle_ & DECOFLAGS ) != DECOFLAGS || (nStyle_ & SAL_FRAME_STYLE_TOOLWINDOW) )
{
if( nStyle_ & DECOFLAGS )
// if any decoration, then show a border
nDecoFlags = WMAdaptor::decoration_Border;
else
nDecoFlags = 0;
if( ! mpParent && (nStyle_ & DECOFLAGS) )
// don't add a min button if window should be decorationless
nDecoFlags |= WMAdaptor::decoration_MinimizeBtn;
if( nStyle_ & SAL_FRAME_STYLE_CLOSEABLE )
nDecoFlags |= WMAdaptor::decoration_CloseBtn;
if( nStyle_ & SAL_FRAME_STYLE_SIZEABLE )
{
nDecoFlags |= WMAdaptor::decoration_Resize;
if( ! (nStyle_ & SAL_FRAME_STYLE_TOOLWINDOW) )
nDecoFlags |= WMAdaptor::decoration_MaximizeBtn;
}
if( nStyle_ & SAL_FRAME_STYLE_MOVEABLE )
nDecoFlags |= WMAdaptor::decoration_Title;
}
WMAdaptor::WMWindowType eType = WMAdaptor::windowType_Normal;
if( nStyle_ & SAL_FRAME_STYLE_INTRO )
eType = WMAdaptor::windowType_Splash;
if( (nStyle_ & SAL_FRAME_STYLE_DIALOG) && hPresentationWindow == None )
eType = WMAdaptor::windowType_ModelessDialogue;
if( nStyle_ & SAL_FRAME_STYLE_TOOLWINDOW )
eType = WMAdaptor::windowType_Utility;
if( nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION )
eType = WMAdaptor::windowType_Toolbar;
if( (nStyle_ & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN)
&& GetDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
eType = WMAdaptor::windowType_Dock;
GetDisplay()->getWMAdaptor()->
setFrameTypeAndDecoration( this,
eType,
nDecoFlags,
hPresentationWindow ? NULL : mpParent );
if( (nStyle_ & (SAL_FRAME_STYLE_DEFAULT |
SAL_FRAME_STYLE_OWNERDRAWDECORATION|
SAL_FRAME_STYLE_FLOAT |
SAL_FRAME_STYLE_INTRO |
SAL_FRAME_STYLE_PARTIAL_FULLSCREEN) )
== SAL_FRAME_STYLE_DEFAULT )
pDisplay_->getWMAdaptor()->maximizeFrame( this, true, true );
}
m_nWorkArea = GetDisplay()->getWMAdaptor()->getCurrentWorkArea();
// Pointer
SetPointer( POINTER_ARROW );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
X11SalFrame::X11SalFrame( SalFrame *pParent, sal_uLong nSalFrameStyle, SystemParentData* pSystemParent )
{
X11SalData* pSalData = GetX11SalData();
// initialize frame geometry
memset( &maGeometry, 0, sizeof(maGeometry) );
mpParent = static_cast< X11SalFrame* >( pParent );
mbTransientForRoot = false;
pDisplay_ = pSalData->GetDisplay();
// insert frame in framelist
pDisplay_->registerFrame( this );
mhWindow = None;
mhShellWindow = None;
mhStackingWindow = None;
mhForeignParent = None;
mhBackgroundPixmap = None;
m_bSetFocusOnMap = false;
pGraphics_ = NULL;
pFreeGraphics_ = NULL;
hCursor_ = None;
nCaptured_ = 0;
nReleaseTime_ = 0;
nKeyCode_ = 0;
nKeyState_ = 0;
nCompose_ = -1;
mbKeyMenu = false;
mbSendExtKeyModChange = false;
mnExtKeyMod = 0;
nShowState_ = SHOWSTATE_UNKNOWN;
nWidth_ = 0;
nHeight_ = 0;
nStyle_ = 0;
mnExtStyle = 0;
bAlwaysOnTop_ = sal_False;
// set bViewable_ to sal_True: hack GetClientSize to report something
// different to 0/0 before first map
bViewable_ = sal_True;
bMapped_ = sal_False;
bDefaultPosition_ = sal_True;
nVisibility_ = VisibilityFullyObscured;
m_nWorkArea = 0;
mbInShow = sal_False;
m_bXEmbed = false;
nScreenSaversTimeout_ = 0;
mpInputContext = NULL;
mbInputFocus = False;
maAlwaysOnTopRaiseTimer.SetTimeoutHdl( LINK( this, X11SalFrame, HandleAlwaysOnTopRaise ) );
maAlwaysOnTopRaiseTimer.SetTimeout( 100 );
meWindowType = WMAdaptor::windowType_Normal;
mnDecorationFlags = WMAdaptor::decoration_All;
mbMaximizedVert = false;
mbMaximizedHorz = false;
mbShaded = false;
mbFullScreen = false;
mnIconID = 1; // ICON_DEFAULT
m_pClipRectangles = NULL;
m_nCurClipRect = 0;
m_nMaxClipRect = 0;
if( mpParent )
mpParent->maChildren.push_back( this );
Init( nSalFrameStyle, GetDisplay()->GetDefaultScreenNumber(), pSystemParent );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::passOnSaveYourSelf()
{
if( this == s_pSaveYourselfFrame )
{
// pass on SaveYourself
const X11SalFrame* pFrame = NULL;
const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
std::list< SalFrame* >::const_iterator it = rFrames.begin();
while( it != rFrames.end() )
{
pFrame = static_cast< const X11SalFrame* >(*it);
if( ! ( IsChildWindow() || pFrame->mpParent )
&& pFrame != s_pSaveYourselfFrame )
break;
++it;
}
s_pSaveYourselfFrame = (it != rFrames.end() ) ? const_cast<X11SalFrame*>(pFrame) : NULL;
if( s_pSaveYourselfFrame )
{
Atom a[4];
int n = 0;
a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_DELETE_WINDOW );
a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_SAVE_YOURSELF );
if( pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING ) )
a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING );
XSetWMProtocols( GetXDisplay(), s_pSaveYourselfFrame->GetShellWindow(), a, n );
}
}
}
X11SalFrame::~X11SalFrame()
{
notifyDelete();
if( m_pClipRectangles )
{
delete [] m_pClipRectangles;
m_pClipRectangles = NULL;
m_nCurClipRect = m_nMaxClipRect = 0;
}
if( mhBackgroundPixmap )
{
XSetWindowBackgroundPixmap( GetXDisplay(), GetWindow(), None );
XFreePixmap( GetXDisplay(), mhBackgroundPixmap );
}
if( mhStackingWindow )
aPresentationReparentList.remove( mhStackingWindow );
// 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 );
ShowFullScreen( sal_False, 0 );
if( bMapped_ )
Show( sal_False );
if( mpInputContext )
{
mpInputContext->UnsetICFocus( this );
mpInputContext->Unmap( this );
delete mpInputContext;
}
if( GetWindow() == hPresentationWindow )
{
hPresentationWindow = None;
doReparentPresentationDialogues( GetDisplay() );
}
if( pGraphics_ )
{
pGraphics_->DeInit();
delete pGraphics_;
}
if( pFreeGraphics_ )
{
pFreeGraphics_->DeInit();
delete pFreeGraphics_;
}
XDestroyWindow( GetXDisplay(), mhWindow );
/*
* check if there is only the status frame left
* if so, free it
*/
if( ! GetDisplay()->getFrames().empty() && I18NStatus::exists() )
{
SalFrame* pStatusFrame = I18NStatus::get().getStatusFrame();
std::list< SalFrame* >::const_iterator sit = GetDisplay()->getFrames().begin();
if( pStatusFrame
&& *sit == pStatusFrame
&& ++sit == GetDisplay()->getFrames().end() )
vcl::I18NStatus::free();
}
passOnSaveYourSelf();
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
{
if( nStyle != mnExtStyle && ! IsChildWindow() )
{
mnExtStyle = nStyle;
XClassHint* pClass = XAllocClassHint();
rtl::OString aResHint = X11SalData::getFrameResName( mnExtStyle );
pClass->res_name = const_cast<char*>(aResHint.getStr());
pClass->res_class = const_cast<char*>(X11SalData::getFrameClassName());
XSetClassHint( GetXDisplay(), GetShellWindow(), pClass );
XFree( pClass );
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetBackgroundBitmap( SalBitmap* pBitmap )
{
if( mhBackgroundPixmap )
{
XSetWindowBackgroundPixmap( GetXDisplay(), GetWindow(), None );
XFreePixmap( GetXDisplay(), mhBackgroundPixmap );
mhBackgroundPixmap = None;
}
if( pBitmap )
{
X11SalBitmap* pBM = static_cast<X11SalBitmap*>(pBitmap);
Size aSize = pBM->GetSize();
if( aSize.Width() && aSize.Height() )
{
mhBackgroundPixmap =
XCreatePixmap( GetXDisplay(),
GetWindow(),
aSize.Width(),
aSize.Height(),
GetDisplay()->GetVisual( m_nScreen ).GetDepth() );
if( mhBackgroundPixmap )
{
SalTwoRect aTwoRect;
aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width();
aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height();
pBM->ImplDraw( mhBackgroundPixmap,
m_nScreen,
GetDisplay()->GetVisual( m_nScreen ).GetDepth(),
aTwoRect, GetDisplay()->GetCopyGC( m_nScreen ) );
XSetWindowBackgroundPixmap( GetXDisplay(), GetWindow(), mhBackgroundPixmap );
}
}
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
const SystemChildData* X11SalFrame::GetSystemData() const
{
X11SalFrame *pFrame = const_cast<X11SalFrame*>(this);
pFrame->maSystemChildData.nSize = sizeof( SystemChildData );
pFrame->maSystemChildData.pDisplay = GetXDisplay();
pFrame->maSystemChildData.aWindow = pFrame->GetWindow();
pFrame->maSystemChildData.pSalFrame = pFrame;
pFrame->maSystemChildData.pWidget = NULL;
pFrame->maSystemChildData.pVisual = GetDisplay()->GetVisual( m_nScreen ).GetVisual();
pFrame->maSystemChildData.nScreen = m_nScreen;
pFrame->maSystemChildData.nDepth = GetDisplay()->GetVisual( m_nScreen ).GetDepth();
pFrame->maSystemChildData.aColormap = GetDisplay()->GetColormap( m_nScreen ).GetXColormap();
pFrame->maSystemChildData.pAppContext = NULL;
pFrame->maSystemChildData.aShellWindow = pFrame->GetShellWindow();
pFrame->maSystemChildData.pShellWidget = NULL;
return &maSystemChildData;
}
SalGraphics *X11SalFrame::GetGraphics()
{
if( pGraphics_ )
return NULL;
if( pFreeGraphics_ )
{
pGraphics_ = pFreeGraphics_;
pFreeGraphics_ = NULL;
}
else
{
pGraphics_ = new X11SalGraphics();
pGraphics_->Init( this, GetWindow(), m_nScreen );
}
return pGraphics_;
}
void X11SalFrame::ReleaseGraphics( SalGraphics *pGraphics )
{
DBG_ASSERT( pGraphics == pGraphics_, "SalFrame::ReleaseGraphics pGraphics!=pGraphics_" );
if( pGraphics != pGraphics_ )
return;
pFreeGraphics_ = pGraphics_;
pGraphics_ = NULL;
}
void X11SalFrame::updateGraphics( bool bClear )
{
Drawable aDrawable = bClear ? None : GetWindow();
if( pGraphics_ )
pGraphics_->SetDrawable( aDrawable, m_nScreen );
if( pFreeGraphics_ )
pFreeGraphics_->SetDrawable( aDrawable, m_nScreen );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::Enable( sal_Bool /*bEnable*/ )
{
// NYI: enable/disable frame
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetIcon( sal_uInt16 nIcon )
{
if ( ! IsChildWindow() )
{
// 0 == default icon -> #1
if ( nIcon == 0 )
nIcon = 1;
mnIconID = nIcon;
XIconSize *pIconSize = NULL;
int nSizes = 0;
int iconSize = 32;
if ( XGetIconSizes( GetXDisplay(), GetDisplay()->GetRootWindow( m_nScreen ), &pIconSize, &nSizes ) )
{
#if OSL_DEBUG_LEVEL > 1
fprintf(stderr, "X11SalFrame::SetIcon(): found %d IconSizes:\n", nSizes);
#endif
const int ourLargestIconSize = 48;
bool bFoundIconSize = false;
int i;
for( i=0; i<nSizes; i++)
{
// select largest supported icon
// Note: olwm/olvwm reports a huge max icon size of
// 160x160 pixels; always choosing the max as the
// preferred icon size is apparently wrong under olvwm
// - so we keep the safe default |iconSize| when we see
// unreasonable large max icon sizes (> twice of our
// largest available icon) reported by XGetIconSizes.
if( pIconSize[i].max_width > iconSize
&& pIconSize[i].max_width <= 2*ourLargestIconSize )
{
iconSize = pIconSize[i].max_width;
bFoundIconSize = true;
}
iconSize = pIconSize[i].max_width;
#if OSL_DEBUG_LEVEL > 1
fprintf(stderr, "min: %d, %d\nmax: %d, %d\ninc: %d, %d\n\n",
pIconSize[i].min_width, pIconSize[i].min_height,
pIconSize[i].max_width, pIconSize[i].max_height,
pIconSize[i].width_inc, pIconSize[i].height_inc);
#endif
}
if ( !bFoundIconSize )
{
// Unless someone has fixed olwm/olvwm, we have rejected
// the max icon size from |XGetIconSizes()|. Provide a
// better icon size default value, in case our window manager
// is olwm/olvwm.
const String& rWM( pDisplay_->getWMAdaptor()->getWindowManagerName() );
if ( rWM.EqualsAscii( "Olwm" ) )
iconSize = 48;
}
XFree( pIconSize );
}
else
{
const String& rWM( pDisplay_->getWMAdaptor()->getWindowManagerName() );
if( rWM.EqualsAscii( "KWin" ) ) // assume KDE is running
iconSize = 48;
static bool bGnomeIconSize = false;
static bool bGnomeChecked = false;
if( ! bGnomeChecked )
{
bGnomeChecked=true;
int nCount = 0;
Atom* pProps = XListProperties( GetXDisplay(),
GetDisplay()->GetRootWindow( m_nScreen ),
&nCount );
for( int i = 0; i < nCount && !bGnomeIconSize; i++ )
{
char* pName = XGetAtomName( GetXDisplay(), pProps[i] );
if( !strcmp( pName, "GNOME_PANEL_DESKTOP_AREA" ) )
bGnomeIconSize = true;
if( pName )
XFree( pName );
}
if( pProps )
XFree( pProps );
}
if( bGnomeIconSize )
iconSize = 48;
}
XWMHints Hints;
Hints.flags = 0;
XWMHints *pHints = XGetWMHints( GetXDisplay(), GetShellWindow() );
if( pHints )
{
memcpy(&Hints, pHints, sizeof( XWMHints ));
XFree( pHints );
}
pHints = &Hints;
sal_Bool bOk = SelectAppIconPixmap( GetDisplay(), m_nScreen,
nIcon, iconSize,
pHints->icon_pixmap, pHints->icon_mask );
if ( !bOk )
{
// load default icon (0)
bOk = SelectAppIconPixmap( GetDisplay(), m_nScreen,
0, iconSize,
pHints->icon_pixmap, pHints->icon_mask );
}
if( bOk )
{
pHints->flags |= IconPixmapHint;
if( pHints->icon_mask )
pHints->flags |= IconMaskHint;
XSetWMHints( GetXDisplay(), GetShellWindow(), pHints );
}
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetMaxClientSize( long nWidth, long nHeight )
{
if( ! IsChildWindow() )
{
if( GetShellWindow() && (nStyle_ & (SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) != SAL_FRAME_STYLE_FLOAT )
{
XSizeHints* pHints = XAllocSizeHints();
long nSupplied = 0;
XGetWMNormalHints( GetXDisplay(),
GetShellWindow(),
pHints,
&nSupplied
);
pHints->max_width = nWidth;
pHints->max_height = nHeight;
pHints->flags |= PMaxSize;
XSetWMNormalHints( GetXDisplay(),
GetShellWindow(),
pHints );
XFree( pHints );
}
}
}
void X11SalFrame::SetMinClientSize( long nWidth, long nHeight )
{
if( ! IsChildWindow() )
{
if( GetShellWindow() && (nStyle_ & (SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) != SAL_FRAME_STYLE_FLOAT )
{
XSizeHints* pHints = XAllocSizeHints();
long nSupplied = 0;
XGetWMNormalHints( GetXDisplay(),
GetShellWindow(),
pHints,
&nSupplied
);
pHints->min_width = nWidth;
pHints->min_height = nHeight;
pHints->flags |= PMinSize;
XSetWMNormalHints( GetXDisplay(),
GetShellWindow(),
pHints );
XFree( pHints );
}
}
}
// Show + Pos (x,y,z) + Size (width,height)
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::Show( sal_Bool bVisible, sal_Bool bNoActivate )
{
if( ( bVisible && bMapped_ )
|| ( !bVisible && !bMapped_ ) )
return;
// 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->nStyle_ & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN ) && pDisplay_->getWMAdaptor()->isLegacyPartialFullscreen())
pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bVisible );
bMapped_ = bVisible;
bViewable_ = bVisible;
setXEmbedInfo();
if( bVisible )
{
SessionManagerClient::open(); // will simply return after the first time
mbInShow = sal_True;
if( ! (nStyle_ & SAL_FRAME_STYLE_INTRO) )
{
// hide all INTRO frames
const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
{
const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it);
// look for intro bit map; if present, hide it
if( pFrame->nStyle_ & SAL_FRAME_STYLE_INTRO )
{
if( pFrame->bMapped_ )
const_cast<X11SalFrame*>(pFrame)->Show( sal_False );
}
}
}
// update NET_WM_STATE which may have been deleted due to earlier Show(sal_False)
if( nShowState_ == SHOWSTATE_HIDDEN )
GetDisplay()->getWMAdaptor()->frameIsMapping( this );
/*
* #95097#
* 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( sal_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
);
}
XLIB_Time nUserTime = 0;
if( ! bNoActivate && (nStyle_ & (SAL_FRAME_STYLE_OWNERDRAWDECORATION)) == 0 )
nUserTime = pDisplay_->GetLastUserEventTime( true );
GetDisplay()->getWMAdaptor()->setUserTime( this, nUserTime );
if( ! bNoActivate && (nStyle_ & SAL_FRAME_STYLE_TOOLWINDOW) )
m_bSetFocusOnMap = true;
// actually map the window
if( m_bXEmbed )
askForXEmbedFocus( 0 );
else
{
if( GetWindow() != GetShellWindow() && ! IsSysChildWindow() )
{
if( IsChildWindow() )
XMapWindow( GetXDisplay(), GetShellWindow() );
XSelectInput( GetXDisplay(), GetShellWindow(), CLIENT_EVENTS );
}
if( nStyle_ & SAL_FRAME_STYLE_FLOAT )
XMapRaised( GetXDisplay(), GetWindow() );
else
XMapWindow( GetXDisplay(), GetWindow() );
}
XSelectInput( GetXDisplay(), GetWindow(), CLIENT_EVENTS );
if( maGeometry.nWidth > 0
&& maGeometry.nHeight > 0
&& ( nWidth_ != (int)maGeometry.nWidth
|| nHeight_ != (int)maGeometry.nHeight ) )
{
nWidth_ = maGeometry.nWidth;
nHeight_ = maGeometry.nHeight;
}
XSync( GetXDisplay(), False );
if( IsFloatGrabWindow() )
{
/*
* #95453#
* 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, NULL );
/*
* 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( std::list< X11SalFrame* >::const_iterator it = maChildren.begin();
it != maChildren.end(); ++it )
{
if( (*it)->mbTransientForRoot )
GetDisplay()->getWMAdaptor()->changeReferenceFrame( *it, this );
}
}
/*
* leave SHOWSTATE_UNKNOWN as this indicates first mapping
* and is only reset int HandleSizeEvent
*/
if( nShowState_ != SHOWSTATE_UNKNOWN )
nShowState_ = SHOWSTATE_NORMAL;
/*
* #98107# 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(sal_True)
*/
if( (nStyle_ & SAL_FRAME_STYLE_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( this );
if( ! IsChildWindow() )
{
/* FIXME: Is deleting the property really necessary ? It hurts
* owner drawn windows at least.
*/
if( mpParent && ! (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
XDeleteProperty( GetXDisplay(), GetShellWindow(), GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::WM_TRANSIENT_FOR ) );
XWithdrawWindow( GetXDisplay(), GetShellWindow(), m_nScreen );
}
else if( ! m_bXEmbed )
XUnmapWindow( GetXDisplay(), GetWindow() );
nShowState_ = SHOWSTATE_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::ToTop( sal_uInt16 nFlags )
{
if( ( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
&& ! ( nStyle_ & SAL_FRAME_STYLE_FLOAT )
&& nShowState_ != SHOWSTATE_HIDDEN
&& nShowState_ != SHOWSTATE_UNKNOWN
)
{
GetDisplay()->getWMAdaptor()->frameIsMapping( this );
if( GetWindow() != GetShellWindow() && ! IsSysChildWindow() )
XMapWindow( GetXDisplay(), GetShellWindow() );
XMapWindow( GetXDisplay(), GetWindow() );
}
XLIB_Window aToTopWindow = IsSysChildWindow() ? GetWindow() : GetShellWindow();
if( ! (nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY) )
{
XRaiseWindow( GetXDisplay(), aToTopWindow );
if( ! GetDisplay()->getWMAdaptor()->isTransientBehaviourAsExpected() )
for( std::list< X11SalFrame* >::const_iterator it = maChildren.begin();
it != maChildren.end(); ++it )
(*it)->ToTop( nFlags & ~SAL_FRAME_TOTOP_GRABFOCUS );
}
if( ( ( nFlags & SAL_FRAME_TOTOP_GRABFOCUS ) || ( nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY ) )
&& bMapped_ )
{
if( m_bXEmbed )
askForXEmbedFocus( 0 );
else
XSetInputFocus( GetXDisplay(), aToTopWindow, RevertToParent, CurrentTime );
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::GetWorkArea( Rectangle& rWorkArea )
{
rWorkArea = pDisplay_->getWMAdaptor()->getWorkArea( 0 );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::GetClientSize( long &rWidth, long &rHeight )
{
if( ! bViewable_ )
{
rWidth = rHeight = 0;
return;
}
rWidth = maGeometry.nWidth;
rHeight = maGeometry.nHeight;
if( !rWidth || !rHeight )
{
XWindowAttributes aAttrib;
XGetWindowAttributes( GetXDisplay(), GetWindow(), &aAttrib );
maGeometry.nWidth = rWidth = aAttrib.width;
maGeometry.nHeight = rHeight = aAttrib.height;
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetWindowGravity (int nGravity) const
{
if( ! IsChildWindow() )
{
XSizeHints* pHint = XAllocSizeHints();
long nFlag;
XGetWMNormalHints (GetXDisplay(), GetShellWindow(), pHint, &nFlag);
pHint->flags |= PWinGravity;
pHint->win_gravity = nGravity;
XSetWMNormalHints (GetXDisplay(), GetShellWindow(), pHint);
XSync (GetXDisplay(), False);
XFree (pHint);
}
}
void X11SalFrame::Center( )
{
int nX, nY, nScreenWidth, nScreenHeight;
int nRealScreenWidth, nRealScreenHeight;
int nScreenX = 0, nScreenY = 0;
const Size& aScreenSize = GetDisplay()->getDataForScreen( m_nScreen ).m_aSize;
nScreenWidth = aScreenSize.Width();
nScreenHeight = aScreenSize.Height();
nRealScreenWidth = nScreenWidth;
nRealScreenHeight = nScreenHeight;
if( GetDisplay()->IsXinerama() )
{
// get xinerama screen we are on
// if there is a parent, use its center for screen determination
// else use the pointer
XLIB_Window aRoot, aChild;
int root_x, root_y, x, y;
unsigned int mask;
if( mpParent )
{
root_x = mpParent->maGeometry.nX + mpParent->maGeometry.nWidth/2;
root_y = mpParent->maGeometry.nY + mpParent->maGeometry.nHeight/2;
}
else
XQueryPointer( GetXDisplay(),
GetShellWindow(),
&aRoot, &aChild,
&root_x, &root_y,
&x, &y,
&mask );
const std::vector< Rectangle >& rScreens = GetDisplay()->GetXineramaScreens();
for( unsigned int i = 0; i < rScreens.size(); i++ )
if( rScreens[i].IsInside( Point( root_x, root_y ) ) )
{
nScreenX = rScreens[i].Left();
nScreenY = rScreens[i].Top();
nRealScreenWidth = rScreens[i].GetWidth();
nRealScreenHeight = rScreens[i].GetHeight();
break;
}
}
if( mpParent )
{
X11SalFrame* pFrame = mpParent;
while( pFrame->mpParent )
pFrame = pFrame->mpParent;
if( pFrame->maGeometry.nWidth < 1 || pFrame->maGeometry.nHeight < 1 )
{
Rectangle aRect;
pFrame->GetPosSize( aRect );
pFrame->maGeometry.nX = aRect.Left();
pFrame->maGeometry.nY = aRect.Top();
pFrame->maGeometry.nWidth = aRect.GetWidth();
pFrame->maGeometry.nHeight = aRect.GetHeight();
}
if( pFrame->nStyle_ & SAL_FRAME_STYLE_PLUG )
{
XLIB_Window aRoot;
unsigned int bw, depth;
XGetGeometry( GetXDisplay(),
pFrame->GetShellWindow(),
&aRoot,
&nScreenX, &nScreenY,
(unsigned int*)&nScreenWidth,
(unsigned int*)&nScreenHeight,
&bw, &depth );
}
else
{
nScreenX = pFrame->maGeometry.nX;
nScreenY = pFrame->maGeometry.nY;
nScreenWidth = pFrame->maGeometry.nWidth;
nScreenHeight = pFrame->maGeometry.nHeight;
}
}
if( mpParent && mpParent->nShowState_ == SHOWSTATE_NORMAL )
{
if( maGeometry.nWidth >= mpParent->maGeometry.nWidth &&
maGeometry.nHeight >= mpParent->maGeometry.nHeight )
{
nX = nScreenX + 40;
nY = nScreenY + 40;
}
else
{
// center the window relative to the top level frame
nX = (nScreenWidth - (int)maGeometry.nWidth ) / 2 + nScreenX;
nY = (nScreenHeight - (int)maGeometry.nHeight) / 2 + nScreenY;
}
}
else
{
// center the window relative to screen
nX = (nRealScreenWidth - (int)maGeometry.nWidth ) / 2 + nScreenX;
nY = (nRealScreenHeight - (int)maGeometry.nHeight) / 2 + nScreenY;
}
nX = nX < 0 ? 0 : nX;
nY = nY < 0 ? 0 : nY;
bDefaultPosition_ = False;
if( mpParent )
{
nX -= mpParent->maGeometry.nX;
nY -= mpParent->maGeometry.nY;
}
Point aPoint(nX, nY);
SetPosSize( Rectangle( aPoint, Size( maGeometry.nWidth, maGeometry.nHeight ) ) );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::updateScreenNumber()
{
if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
{
Point aPoint( maGeometry.nX, maGeometry.nY );
const std::vector<Rectangle>& rScreenRects( GetDisplay()->GetXineramaScreens() );
size_t nScreens = rScreenRects.size();
for( size_t i = 0; i < nScreens; i++ )
{
if( rScreenRects[i].IsInside( aPoint ) )
{
maGeometry.nScreenNumber = static_cast<unsigned int>(i);
break;
}
}
}
else
maGeometry.nScreenNumber = static_cast<unsigned int>(m_nScreen);
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
{
if( nStyle_ & SAL_FRAME_STYLE_PLUG )
return;
// relative positioning in X11SalFrame::SetPosSize
Rectangle aPosSize( Point( maGeometry.nX, maGeometry.nY ), Size( maGeometry.nWidth, maGeometry.nHeight ) );
aPosSize.Justify();
if( ! ( nFlags & SAL_FRAME_POSSIZE_X ) )
{
nX = aPosSize.Left();
if( mpParent )
nX -= mpParent->maGeometry.nX;
}
if( ! ( nFlags & SAL_FRAME_POSSIZE_Y ) )
{
nY = aPosSize.Top();
if( mpParent )
nY -= mpParent->maGeometry.nY;
}
if( ! ( nFlags & SAL_FRAME_POSSIZE_WIDTH ) )
nWidth = aPosSize.GetWidth();
if( ! ( nFlags & SAL_FRAME_POSSIZE_HEIGHT ) )
nHeight = aPosSize.GetHeight();
aPosSize = Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
if( ! ( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) ) )
{
if( bDefaultPosition_ )
{
maGeometry.nWidth = aPosSize.GetWidth();
maGeometry.nHeight = aPosSize.GetHeight();
Center();
}
else
SetSize( Size( nWidth, nHeight ) );
}
else
SetPosSize( aPosSize );
bDefaultPosition_ = False;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetAlwaysOnTop( sal_Bool bOnTop )
{
if( ! IsOverrideRedirect() )
{
bAlwaysOnTop_ = bOnTop;
pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bOnTop );
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#define _FRAMESTATE_MASK_GEOMETRY \
(SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y | \
SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT)
#define _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY \
(SAL_FRAMESTATE_MASK_MAXIMIZED_X | SAL_FRAMESTATE_MASK_MAXIMIZED_Y | \
SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT)
void X11SalFrame::SetWindowState( const SalFrameState *pState )
{
if (pState == NULL)
return;
// Request for position or size change
if (pState->mnMask & _FRAMESTATE_MASK_GEOMETRY)
{
Rectangle aPosSize;
bool bDoAdjust = false;
/* #i44325#
* if maximized, set restore size and guess maximized size from last time
* in state change below maximize window
*/
if( ! IsChildWindow() &&
(pState->mnMask & SAL_FRAMESTATE_MASK_STATE) &&
(pState->mnState & SAL_FRAMESTATE_MAXIMIZED) &&
(pState->mnMask & _FRAMESTATE_MASK_GEOMETRY) == _FRAMESTATE_MASK_GEOMETRY &&
(pState->mnMask & _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY) == _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY
)
{
XSizeHints* pHints = XAllocSizeHints();
long nSupplied = 0;
XGetWMNormalHints( GetXDisplay(),
GetShellWindow(),
pHints,
&nSupplied );
pHints->flags |= PPosition | PWinGravity;
pHints->x = pState->mnX;
pHints->y = pState->mnY;
pHints->win_gravity = pDisplay_->getWMAdaptor()->getPositionWinGravity();
XSetWMNormalHints( GetXDisplay(),
GetShellWindow(),
pHints );
XFree( pHints );
XMoveResizeWindow( GetXDisplay(), GetShellWindow(),
pState->mnX, pState->mnY,
pState->mnWidth, pState->mnHeight );
// guess maximized geometry from last time
maGeometry.nX = pState->mnMaximizedX;
maGeometry.nY = pState->mnMaximizedY;
maGeometry.nWidth = pState->mnMaximizedWidth;
maGeometry.nHeight = pState->mnMaximizedHeight;
updateScreenNumber();
}
else
{
// initialize with current geometry
if ((pState->mnMask & _FRAMESTATE_MASK_GEOMETRY) != _FRAMESTATE_MASK_GEOMETRY)
GetPosSize (aPosSize);
// change requested properties
if (pState->mnMask & SAL_FRAMESTATE_MASK_X)
{
aPosSize.setX (pState->mnX);
}
if (pState->mnMask & SAL_FRAMESTATE_MASK_Y)
{
aPosSize.setY (pState->mnY);
}
if (pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH)
{
long nWidth = pState->mnWidth > 0 ? pState->mnWidth - 1 : 0;
aPosSize.setWidth (nWidth);
bDoAdjust = true;
}
if (pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT)
{
int nHeight = pState->mnHeight > 0 ? pState->mnHeight - 1 : 0;
aPosSize.setHeight (nHeight);
bDoAdjust = true;
}
const Size& aScreenSize = pDisplay_->getDataForScreen( m_nScreen ).m_aSize;
const WMAdaptor *pWM = GetDisplay()->getWMAdaptor();
if( bDoAdjust && aPosSize.GetWidth() <= aScreenSize.Width()
&& aPosSize.GetHeight() <= aScreenSize.Height() )
{
SalFrameGeometry aGeom = maGeometry;
if( ! (nStyle_ & ( SAL_FRAME_STYLE_FLOAT | SAL_FRAME_STYLE_PLUG ) ) &&
mpParent &&
aGeom.nLeftDecoration == 0 &&
aGeom.nTopDecoration == 0 )
{
aGeom = mpParent->maGeometry;
if( aGeom.nLeftDecoration == 0 &&
aGeom.nTopDecoration == 0 )
{
aGeom.nLeftDecoration = 5;
aGeom.nTopDecoration = 20;
aGeom.nRightDecoration = 5;
aGeom.nBottomDecoration = 5;
}
}
// adjust position so that frame fits onto screen
if( aPosSize.Right()+(long)aGeom.nRightDecoration > aScreenSize.Width()-1 )
aPosSize.Move( (long)aScreenSize.Width() - (long)aPosSize.Right() - (long)aGeom.nRightDecoration, 0 );
if( aPosSize.Bottom()+(long)aGeom.nBottomDecoration > aScreenSize.Height()-1 )
aPosSize.Move( 0, (long)aScreenSize.Height() - (long)aPosSize.Bottom() - (long)aGeom.nBottomDecoration );
if( aPosSize.Left() < (long)aGeom.nLeftDecoration )
aPosSize.Move( (long)aGeom.nLeftDecoration - (long)aPosSize.Left(), 0 );
if( aPosSize.Top() < (long)aGeom.nTopDecoration )
aPosSize.Move( 0, (long)aGeom.nTopDecoration - (long)aPosSize.Top() );
}
// resize with new args
if (pWM->supportsICCCMPos())
{
if( mpParent )
aPosSize.Move( -mpParent->maGeometry.nX,
-mpParent->maGeometry.nY );
SetPosSize( aPosSize );
bDefaultPosition_ = False;
}
else
SetPosSize( 0, 0, aPosSize.GetWidth(), aPosSize.GetHeight(), SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
}
}
// request for status change
if (pState->mnMask & SAL_FRAMESTATE_MASK_STATE)
{
if (pState->mnState & SAL_FRAMESTATE_MAXIMIZED)
{
nShowState_ = SHOWSTATE_NORMAL;
if( ! (pState->mnState & (SAL_FRAMESTATE_MAXIMIZED_HORZ|SAL_FRAMESTATE_MAXIMIZED_VERT) ) )
Maximize();
else
{
bool bHorz = (pState->mnState & SAL_FRAMESTATE_MAXIMIZED_HORZ) ? true : false;
bool bVert = (pState->mnState & SAL_FRAMESTATE_MAXIMIZED_VERT) ? true : false;
GetDisplay()->getWMAdaptor()->maximizeFrame( this, bHorz, bVert );
}
maRestorePosSize.Left() = pState->mnX;
maRestorePosSize.Top() = pState->mnY;
maRestorePosSize.Right() = maRestorePosSize.Left() + pState->mnWidth;
maRestorePosSize.Right() = maRestorePosSize.Left() + pState->mnHeight;
}
else if( mbMaximizedHorz || mbMaximizedVert )
GetDisplay()->getWMAdaptor()->maximizeFrame( this, false, false );
if (pState->mnState & SAL_FRAMESTATE_MINIMIZED)
{
if (nShowState_ == SHOWSTATE_UNKNOWN)
nShowState_ = SHOWSTATE_NORMAL;
Minimize();
}
if (pState->mnState & SAL_FRAMESTATE_NORMAL)
{
if (nShowState_ != SHOWSTATE_NORMAL)
Restore();
}
if (pState->mnState & SAL_FRAMESTATE_ROLLUP)
GetDisplay()->getWMAdaptor()->shade( this, true );
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
sal_Bool X11SalFrame::GetWindowState( SalFrameState* pState )
{
if( SHOWSTATE_MINIMIZED == nShowState_ )
pState->mnState = SAL_FRAMESTATE_MINIMIZED;
else
pState->mnState = SAL_FRAMESTATE_NORMAL;
Rectangle aPosSize;
if( maRestorePosSize.IsEmpty() )
GetPosSize( aPosSize );
else
aPosSize = maRestorePosSize;
if( mbMaximizedHorz )
pState->mnState |= SAL_FRAMESTATE_MAXIMIZED_HORZ;
if( mbMaximizedVert )
pState->mnState |= SAL_FRAMESTATE_MAXIMIZED_VERT;
if( mbShaded )
pState->mnState |= SAL_FRAMESTATE_ROLLUP;
pState->mnX = aPosSize.Left();
pState->mnY = aPosSize.Top();
pState->mnWidth = aPosSize.GetWidth();
pState->mnHeight = aPosSize.GetHeight();
pState->mnMask = _FRAMESTATE_MASK_GEOMETRY | SAL_FRAMESTATE_MASK_STATE;
if (! maRestorePosSize.IsEmpty() )
{
GetPosSize( aPosSize );
pState->mnState |= SAL_FRAMESTATE_MAXIMIZED;
pState->mnMaximizedX = aPosSize.Left();
pState->mnMaximizedY = aPosSize.Top();
pState->mnMaximizedWidth = aPosSize.GetWidth();
pState->mnMaximizedHeight = aPosSize.GetHeight();
pState->mnMask |= _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY;
}
return sal_True;
}
// ----------------------------------------------------------------------------
// get a screenshot of the current frame including window manager decoration
SalBitmap* X11SalFrame::SnapShot()
{
Display* pDisplay = GetXDisplay();
// make sure the frame has been reparented and all paint timer have been
// expired
do
{
XSync(pDisplay, False);
Application::Reschedule ();
}
while (XPending(pDisplay));
TimeValue aVal;
aVal.Seconds = 0;
aVal.Nanosec = 50000000;
osl_waitThread( &aVal );
do
{
XSync(pDisplay, False);
Application::Reschedule ();
}
while (XPending(pDisplay));
// get the most outer window, usually the window manager decoration
Drawable hWindow = None;
if (IsOverrideRedirect())
hWindow = GetDrawable();
else
if (hPresentationWindow != None)
hWindow = hPresentationWindow;
else
hWindow = GetStackingWindow();
// query the contents of the window
if (hWindow != None)
{
X11SalBitmap *pBmp = new X11SalBitmap;
if (pBmp->SnapShot (pDisplay, hWindow))
return pBmp;
else
delete pBmp;
}
return NULL;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// native menu implementation - currently empty
void X11SalFrame::DrawMenuBar()
{
}
void X11SalFrame::SetMenu( SalMenu* )
{
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::GetPosSize( Rectangle &rPosSize )
{
if( maGeometry.nWidth < 1 || maGeometry.nHeight < 1 )
{
const Size& aScreenSize = pDisplay_->getDataForScreen( m_nScreen ).m_aSize;
long w = aScreenSize.Width() - maGeometry.nLeftDecoration - maGeometry.nRightDecoration;
long h = aScreenSize.Height() - maGeometry.nTopDecoration - maGeometry.nBottomDecoration;
rPosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ), Size( w, h ) );
}
else
rPosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
Size( maGeometry.nWidth, maGeometry.nHeight ) );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetSize( const Size &rSize )
{
if( rSize.Width() > 0 && rSize.Height() > 0 )
{
if( ! ( nStyle_ & SAL_FRAME_STYLE_SIZEABLE )
&& ! IsChildWindow()
&& ( nStyle_ & (SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) != SAL_FRAME_STYLE_FLOAT )
{
XSizeHints* pHints = XAllocSizeHints();
long nSupplied = 0;
XGetWMNormalHints( GetXDisplay(),
GetShellWindow(),
pHints,
&nSupplied
);
pHints->min_width = rSize.Width();
pHints->min_height = rSize.Height();
pHints->max_width = rSize.Width();
pHints->max_height = rSize.Height();
pHints->flags |= PMinSize | PMaxSize;
XSetWMNormalHints( GetXDisplay(),
GetShellWindow(),
pHints );
XFree( pHints );
}
XResizeWindow( GetXDisplay(), IsSysChildWindow() ? GetWindow() : GetShellWindow(), rSize.Width(), rSize.Height() );
if( GetWindow() != GetShellWindow() )
{
if( (nStyle_ & SAL_FRAME_STYLE_PLUG ) )
XMoveResizeWindow( GetXDisplay(), GetWindow(), 0, 0, rSize.Width(), rSize.Height() );
else
XResizeWindow( GetXDisplay(), GetWindow(), rSize.Width(), rSize.Height() );
}
maGeometry.nWidth = rSize.Width();
maGeometry.nHeight = rSize.Height();
// allow the external status window to reposition
if (mbInputFocus && mpInputContext != NULL)
mpInputContext->SetICFocus ( this );
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetPosSize( const Rectangle &rPosSize )
{
XWindowChanges values;
values.x = rPosSize.Left();
values.y = rPosSize.Top();
values.width = rPosSize.GetWidth();
values.height = rPosSize.GetHeight();
if( !values.width || !values.height )
return;
if( mpParent && ! IsSysChildWindow() )
{
// --- RTL --- (mirror window pos)
if( Application::GetSettings().GetLayoutRTL() )
values.x = mpParent->maGeometry.nWidth-values.width-1-values.x;
XLIB_Window aChild;
// coordinates are relative to parent, so translate to root coordinates
XTranslateCoordinates( GetDisplay()->GetDisplay(),
mpParent->GetWindow(),
GetDisplay()->GetRootWindow( m_nScreen ),
values.x, values.y,
&values.x, &values.y,
& aChild );
}
bool bMoved = false;
bool bSized = false;
if( values.x != maGeometry.nX || values.y != maGeometry.nY )
bMoved = true;
if( values.width != (int)maGeometry.nWidth || values.height != (int)maGeometry.nHeight )
bSized = true;
if( ! ( nStyle_ & ( SAL_FRAME_STYLE_PLUG | SAL_FRAME_STYLE_FLOAT ) )
&& !(pDisplay_->GetProperties() & PROPERTY_SUPPORT_WM_ClientPos) )
{
values.x -= maGeometry.nLeftDecoration;
values.y -= maGeometry.nTopDecoration;
}
// do net set WMNormalHints for ..
if(
// child windows
! IsChildWindow()
// popups (menu, help window, etc.)
&& (nStyle_ & (SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) != SAL_FRAME_STYLE_FLOAT
// shown, sizeable windows
&& ( nShowState_ == SHOWSTATE_UNKNOWN ||
nShowState_ == SHOWSTATE_HIDDEN ||
! ( nStyle_ & SAL_FRAME_STYLE_SIZEABLE )
)
)
{
XSizeHints* pHints = XAllocSizeHints();
long nSupplied = 0;
XGetWMNormalHints( GetXDisplay(),
GetShellWindow(),
pHints,
&nSupplied
);
if( ! ( nStyle_ & SAL_FRAME_STYLE_SIZEABLE ) )
{
pHints->min_width = rPosSize.GetWidth();
pHints->min_height = rPosSize.GetHeight();
pHints->max_width = rPosSize.GetWidth();
pHints->max_height = rPosSize.GetHeight();
pHints->flags |= PMinSize | PMaxSize;
}
if( nShowState_ == SHOWSTATE_UNKNOWN || nShowState_ == SHOWSTATE_HIDDEN )
{
pHints->flags |= PPosition | PWinGravity;
pHints->x = values.x;
pHints->y = values.y;
pHints->win_gravity = pDisplay_->getWMAdaptor()->getPositionWinGravity();
}
if( mbFullScreen )
{
pHints->max_width = 10000;
pHints->max_height = 10000;
pHints->flags |= PMaxSize;
}
XSetWMNormalHints( GetXDisplay(),
GetShellWindow(),
pHints );
XFree( pHints );
}
XMoveResizeWindow( GetXDisplay(), IsSysChildWindow() ? GetWindow() : GetShellWindow(), values.x, values.y, values.width, values.height );
if( GetShellWindow() != GetWindow() )
{
if( (nStyle_ & SAL_FRAME_STYLE_PLUG ) )
XMoveResizeWindow( GetXDisplay(), GetWindow(), 0, 0, values.width, values.height );
else
XMoveResizeWindow( GetXDisplay(), GetWindow(), values.x, values.y, values.width, values.height );
}
maGeometry.nX = values.x;
maGeometry.nY = values.y;
maGeometry.nWidth = values.width;
maGeometry.nHeight = values.height;
if( IsSysChildWindow() && mpParent )
{
// translate back to root coordinates
maGeometry.nX += mpParent->maGeometry.nX;
maGeometry.nY += mpParent->maGeometry.nY;
}
updateScreenNumber();
if( bSized && ! bMoved )
CallCallback( SALEVENT_RESIZE, NULL );
else if( bMoved && ! bSized )
CallCallback( SALEVENT_MOVE, NULL );
else
CallCallback( SALEVENT_MOVERESIZE, NULL );
// allow the external status window to reposition
if (mbInputFocus && mpInputContext != NULL)
mpInputContext->SetICFocus ( this );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::Minimize()
{
if( IsSysChildWindow() )
return;
if( SHOWSTATE_UNKNOWN == nShowState_ || SHOWSTATE_HIDDEN == nShowState_ )
{
stderr0( "X11SalFrame::Minimize on withdrawn window\n" );
return;
}
if( XIconifyWindow( GetXDisplay(),
GetShellWindow(),
pDisplay_->GetDefaultScreenNumber() ) )
nShowState_ = SHOWSTATE_MINIMIZED;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::Maximize()
{
if( IsSysChildWindow() )
return;
if( SHOWSTATE_MINIMIZED == nShowState_ )
{
GetDisplay()->getWMAdaptor()->frameIsMapping( this );
XMapWindow( GetXDisplay(), GetShellWindow() );
nShowState_ = SHOWSTATE_NORMAL;
}
pDisplay_->getWMAdaptor()->maximizeFrame( this, true, true );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::Restore()
{
if( IsSysChildWindow() )
return;
if( SHOWSTATE_UNKNOWN == nShowState_ || SHOWSTATE_HIDDEN == nShowState_ )
{
stderr0( "X11SalFrame::Restore on withdrawn window\n" );
return;
}
if( SHOWSTATE_MINIMIZED == nShowState_ )
{
GetDisplay()->getWMAdaptor()->frameIsMapping( this );
XMapWindow( GetXDisplay(), GetShellWindow() );
nShowState_ = SHOWSTATE_NORMAL;
}
pDisplay_->getWMAdaptor()->maximizeFrame( this, false, false );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetScreenNumber( unsigned int nNewScreen )
{
if( nNewScreen == maGeometry.nScreenNumber )
return;
if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
{
if( nNewScreen >= GetDisplay()->GetXineramaScreens().size() )
return;
Rectangle aOldScreenRect( GetDisplay()->GetXineramaScreens()[maGeometry.nScreenNumber] );
Rectangle aNewScreenRect( GetDisplay()->GetXineramaScreens()[nNewScreen] );
bool bVisible = bMapped_;
if( bVisible )
Show( sal_False );
maGeometry.nX = aNewScreenRect.Left() + (maGeometry.nX - aOldScreenRect.Left());
maGeometry.nY = aNewScreenRect.Top() + (maGeometry.nY - aOldScreenRect.Top());
createNewWindow( None, m_nScreen );
if( bVisible )
Show( sal_True );
maGeometry.nScreenNumber = nNewScreen;
}
else if( sal_Int32(nNewScreen) < GetDisplay()->GetScreenCount() )
{
bool bVisible = bMapped_;
if( bVisible )
Show( sal_False );
createNewWindow( None, nNewScreen );
if( bVisible )
Show( sal_True );
maGeometry.nScreenNumber = nNewScreen;
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::ShowFullScreen( sal_Bool bFullScreen, sal_Int32 nScreen )
{
if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
{
if( mbFullScreen == (bool)bFullScreen )
return;
if( bFullScreen )
{
maRestorePosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
Size( maGeometry.nWidth, maGeometry.nHeight ) );
Rectangle aRect;
if( nScreen < 0 || nScreen >= static_cast<int>(GetDisplay()->GetXineramaScreens().size()) )
aRect = Rectangle( Point(0,0), GetDisplay()->GetScreenSize( m_nScreen ) );
else
aRect = GetDisplay()->GetXineramaScreens()[nScreen];
nStyle_ |= SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
bool bVisible = bMapped_;
if( bVisible )
Show( sal_False );
maGeometry.nX = aRect.Left();
maGeometry.nY = aRect.Top();
maGeometry.nWidth = aRect.GetWidth();
maGeometry.nHeight = aRect.GetHeight();
mbMaximizedHorz = mbMaximizedVert = false;
mbFullScreen = true;
createNewWindow( None, m_nScreen );
if( GetDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
GetDisplay()->getWMAdaptor()->enableAlwaysOnTop( this, true );
else
{
GetDisplay()->getWMAdaptor()->setFullScreenMonitors( GetShellWindow(), nScreen );
GetDisplay()->getWMAdaptor()->showFullScreen( this, true );
}
if( bVisible )
Show(sal_True);
}
else
{
mbFullScreen = false;
nStyle_ &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
bool bVisible = bMapped_;
Rectangle aRect = maRestorePosSize;
maRestorePosSize = Rectangle();
if( bVisible )
Show( sal_False );
createNewWindow( None, m_nScreen );
if( !aRect.IsEmpty() )
SetPosSize( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(),
SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y |
SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
if( bVisible )
Show( sal_True );
}
}
else
{
if( nScreen < 0 || nScreen >= GetDisplay()->GetScreenCount() )
nScreen = m_nScreen;
if( nScreen != m_nScreen )
{
bool bVisible = bMapped_;
if( mbFullScreen )
pDisplay_->getWMAdaptor()->showFullScreen( this, false );
if( bVisible )
Show( sal_False );
createNewWindow( None, nScreen );
if( mbFullScreen )
pDisplay_->getWMAdaptor()->showFullScreen( this, true );
if( bVisible )
Show( sal_True );
}
if( mbFullScreen == (bool)bFullScreen )
return;
pDisplay_->getWMAdaptor()->showFullScreen( this, bFullScreen );
if( IsOverrideRedirect()
&& WMSupportsFWS( GetXDisplay(), GetDisplay()->GetRootWindow( m_nScreen ) ) )
{
AddFwsProtocols( GetXDisplay(), GetShellWindow() );
RegisterFwsWindow( GetXDisplay(), GetShellWindow() );
}
}
}
/* ---------------------------------------------------------------------
the xautolock pseudo screen saver needs special treatment since it
doesn't cooperate with XxxxScreenSaver settings
------------------------------------------------------------------- */
static Bool
IsRunningXAutoLock( Display *p_display, XLIB_Window a_window )
{
const char *p_atomname = "XAUTOLOCK_SEMAPHORE_PID";
Atom a_pidatom;
// xautolock interns this atom
a_pidatom = XInternAtom( p_display, p_atomname, True );
if ( a_pidatom == None )
return False;
Atom a_type;
int n_format;
unsigned long n_items;
unsigned long n_bytes_after;
pid_t *p_pid;
pid_t n_pid;
// get pid of running xautolock
XGetWindowProperty (p_display, a_window, a_pidatom, 0L, 2L, False,
AnyPropertyType, &a_type, &n_format, &n_items, &n_bytes_after,
(unsigned char**) &p_pid );
n_pid = *p_pid;
XFree( p_pid );
if ( a_type == XA_INTEGER )
{
// check if xautolock pid points to a running process
if ( kill(n_pid, 0) == -1 )
return False;
else
return True;
}
return False;
}
/* definitions from xautolock.c (pl15) */
#define XAUTOLOCK_DISABLE 1
#define XAUTOLOCK_ENABLE 2
static Bool
MessageToXAutoLock( Display *p_display, int n_message )
{
const char *p_atomname = "XAUTOLOCK_MESSAGE" ;
Atom a_messageatom;
XLIB_Window a_rootwindow;
a_rootwindow = RootWindowOfScreen( ScreenOfDisplay(p_display, 0) );
if ( ! IsRunningXAutoLock(p_display, a_rootwindow) )
{
// remove any pending messages
a_messageatom = XInternAtom( p_display, p_atomname, True );
if ( a_messageatom != None )
XDeleteProperty( p_display, a_rootwindow, a_messageatom );
return False;
}
a_messageatom = XInternAtom( p_display, p_atomname, False );
XChangeProperty (p_display, a_rootwindow, a_messageatom, XA_INTEGER,
8, PropModeReplace, (unsigned char*)&n_message, sizeof(n_message) );
return True;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::StartPresentation( sal_Bool bStart )
{
I18NStatus::get().show( !bStart, I18NStatus::presentation );
if ( bStart )
MessageToXAutoLock( GetXDisplay(), XAUTOLOCK_DISABLE );
else
MessageToXAutoLock( GetXDisplay(), XAUTOLOCK_ENABLE );
if( ! bStart && hPresentationWindow != None )
doReparentPresentationDialogues( GetDisplay() );
hPresentationWindow = (bStart && IsOverrideRedirect() ) ? GetWindow() : None;
// needs static here to save DPMS settings
int dummy;
static bool DPMSExtensionAvailable =
#ifndef SOLARIS
(DPMSQueryExtension(GetXDisplay(), &dummy, &dummy) != 0);
static sal_Bool DPMSEnabled = false;
#else
false;
bool DPMSEnabled = false;
(void)dummy;
#define CARD16 unsigned short
#endif
static CARD16 dpms_standby_timeout=0;
static CARD16 dpms_suspend_timeout=0;
static CARD16 dpms_off_timeout=0;
if( bStart || nScreenSaversTimeout_ || DPMSEnabled)
{
if( hPresentationWindow )
{
/* #i10559# workaround for WindowMaker: try to restore
* current focus after presentation window is gone
*/
int revert_to = 0;
XGetInputFocus( GetXDisplay(), &hPresFocusWindow, &revert_to );
}
int timeout, interval, prefer_blanking, allow_exposures;
XGetScreenSaver( GetXDisplay(),
&timeout,
&interval,
&prefer_blanking,
&allow_exposures );
// get the DPMS state right before the start
if (DPMSExtensionAvailable)
{
#ifndef SOLARIS
CARD16 state; // card16 is defined in Xdm.h
DPMSInfo( GetXDisplay(),
&state,
&DPMSEnabled);
#endif
}
if( bStart ) // start show
{
if ( timeout )
{
nScreenSaversTimeout_ = timeout;
XResetScreenSaver( GetXDisplay() );
XSetScreenSaver( GetXDisplay(),
0,
interval,
prefer_blanking,
allow_exposures );
}
#ifndef SOLARIS
if( DPMSEnabled )
{
if ( DPMSExtensionAvailable )
{
DPMSGetTimeouts( GetXDisplay(),
&dpms_standby_timeout,
&dpms_suspend_timeout,
&dpms_off_timeout);
DPMSSetTimeouts(GetXDisplay(), 0,0,0);
}
}
#endif
}
else // if( !bStart ) // end of show
{
if( nScreenSaversTimeout_ )
{
XSetScreenSaver( GetXDisplay(),
nScreenSaversTimeout_,
interval,
prefer_blanking,
allow_exposures );
nScreenSaversTimeout_ = 0;
}
#ifndef SOLARIS
if ( DPMSEnabled )
{
if ( DPMSExtensionAvailable )
{
// restore timeouts
DPMSSetTimeouts(GetXDisplay(), dpms_standby_timeout,
dpms_suspend_timeout, dpms_off_timeout);
}
}
#endif
}
}
}
// Pointer
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetPointer( PointerStyle ePointerStyle )
{
hCursor_ = pDisplay_->GetPointer( ePointerStyle );
XDefineCursor( GetXDisplay(), GetWindow(), hCursor_ );
if( IsCaptured() || nVisibleFloats > 0 )
XChangeActivePointerGrab( GetXDisplay(),
PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
hCursor_,
CurrentTime );
}
void X11SalFrame::SetPointerPos(long nX, long nY)
{
/* #87921# 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.
*/
unsigned int nWindowLeft = maGeometry.nX + nX;
unsigned int nWindowTop = maGeometry.nY + nY;
XWarpPointer( GetXDisplay(), None, pDisplay_->GetRootWindow( pDisplay_->GetDefaultScreenNumber() ),
0, 0, 0, 0, nWindowLeft, nWindowTop);
}
// delay handling of extended text input
#if !defined(__synchronous_extinput__)
void
X11SalFrame::PostExtTextEvent (sal_uInt16 nExtTextEventType, void *pExtTextEvent)
{
XLIB_Window nFocusWindow = GetWindow();
Atom nEventAtom = GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::SAL_EXTTEXTEVENT );
XEvent aEvent;
aEvent.xclient.type = ClientMessage;
aEvent.xclient.serial = 0;
aEvent.xclient.send_event = True;
aEvent.xclient.display = GetXDisplay();
aEvent.xclient.window = nFocusWindow;
aEvent.xclient.message_type = nEventAtom;
aEvent.xclient.format = 32;
#if SAL_TYPES_SIZEOFLONG > 4
aEvent.xclient.data.l[0] = (sal_uInt32)((long)pExtTextEvent & 0xffffffff);
aEvent.xclient.data.l[1] = (sal_uInt32)((long)pExtTextEvent >> 32);
#else
aEvent.xclient.data.l[0] = (sal_uInt32)((long)pExtTextEvent);
aEvent.xclient.data.l[1] = 0;
#endif
aEvent.xclient.data.l[2] = (sal_uInt32)nExtTextEventType;
aEvent.xclient.data.l[3] = 0;
aEvent.xclient.data.l[4] = 0;
XPutBackEvent( GetXDisplay(), &aEvent );
}
void
X11SalFrame::HandleExtTextEvent (XClientMessageEvent *pEvent)
{
#if SAL_TYPES_SIZEOFLONG > 4
void* pExtTextEvent = (void*)( (pEvent->data.l[0] & 0xffffffff)
| (pEvent->data.l[1] << 32) );
#else
void* pExtTextEvent = (void*)(pEvent->data.l[0]);
#endif
sal_uInt16 nExtTextEventType = sal_uInt16(pEvent->data.l[2]);
CallCallback(nExtTextEventType, pExtTextEvent);
switch (nExtTextEventType)
{
case SALEVENT_ENDEXTTEXTINPUT:
break;
case SALEVENT_EXTTEXTINPUT:
break;
default:
fprintf(stderr, "X11SalFrame::HandleExtTextEvent: invalid extended input\n");
}
}
#endif /* defined(__synchronous_extinput__) */
// PostEvent
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
sal_Bool X11SalFrame::PostEvent( void *pData )
{
GetDisplay()->SendInternalEvent( this, pData );
return sal_True;
}
// Title
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetTitle( const XubString& rTitle )
{
if( ! ( IsChildWindow() || (nStyle_ & SAL_FRAME_STYLE_FLOAT ) ) )
{
m_aTitle = rTitle;
GetDisplay()->getWMAdaptor()->setWMName( this, rTitle );
}
}
// -----------------------------------------------------------------------
void X11SalFrame::Flush()
{
XFlush( GetDisplay()->GetDisplay() );
}
// -----------------------------------------------------------------------
void X11SalFrame::Sync()
{
XSync( GetDisplay()->GetDisplay(), False );
}
// Keyboard
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// -----------------------------------------------------------------------
void X11SalFrame::SetInputContext( SalInputContext* pContext )
{
if (pContext == NULL)
return;
// 1. We should create an input context for this frame
// only when SAL_INPUTCONTEXT_TEXT is set.
if (!(pContext->mnOptions & SAL_INPUTCONTEXT_TEXT))
{
if( mpInputContext )
mpInputContext->Unmap( this );
return;
}
// 2. We should use on-the-spot inputstyle
// only when SAL_INPUTCONTEXT_EXTTEXTINPUT is set.
if (mpInputContext == NULL)
{
I18NStatus& rStatus( I18NStatus::get() );
rStatus.setParent( this );
mpInputContext = new SalI18N_InputContext( this );
if (mpInputContext->UseContext())
{
mpInputContext->ExtendEventMask( GetShellWindow() );
if (pContext->mnOptions & SAL_INPUTCONTEXT_CHANGELANGUAGE)
mpInputContext->SetLanguage(pContext->meLanguage);
if (mbInputFocus)
mpInputContext->SetICFocus( this );
}
}
else
mpInputContext->Map( this );
return;
}
// -----------------------------------------------------------------------
void X11SalFrame::EndExtTextInput( sal_uInt16 nFlags )
{
if (mpInputContext != NULL)
mpInputContext->EndExtTextInput( nFlags );
}
// -----------------------------------------------------------------------
XubString X11SalFrame::GetKeyName( sal_uInt16 nKeyCode )
{
return GetDisplay()->GetKeyName( nKeyCode );
}
XubString X11SalFrame::GetSymbolKeyName( const XubString&, sal_uInt16 nKeyCode )
{
return GetKeyName( nKeyCode );
}
sal_Bool X11SalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& )
{
// not supported yet
return sal_False;
}
LanguageType X11SalFrame::GetInputLanguage()
{
// could be improved by checking unicode ranges of the last input
return LANGUAGE_DONTKNOW;
}
// Settings
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
inline Color getColorFromLong( long nColor )
{
return Color( (nColor & 0xff), (nColor & 0xff00)>>8, (nColor & 0xff0000)>>16);
}
void X11SalFrame::UpdateSettings( AllSettings& rSettings )
{
DtIntegrator* pIntegrator = GetDisplay()->getDtIntegrator();
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "DtIntegrator: %d\n", pIntegrator ? pIntegrator->GetDtType() : -1 );
#endif
if( pIntegrator )
pIntegrator->GetSystemLook( rSettings );
}
void X11SalFrame::CaptureMouse( sal_Bool bCapture )
{
nCaptured_ = pDisplay_->CaptureMouse( bCapture ? this : NULL );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::SetParent( SalFrame* pNewParent )
{
if( mpParent != pNewParent )
{
if( mpParent )
mpParent->maChildren.remove( this );
mpParent = static_cast<X11SalFrame*>(pNewParent);
mpParent->maChildren.push_back( this );
if( mpParent->m_nScreen != m_nScreen )
createNewWindow( None, mpParent->m_nScreen );
GetDisplay()->getWMAdaptor()->changeReferenceFrame( this, mpParent );
}
}
SalFrame* X11SalFrame::GetParent() const
{
return mpParent;
}
void X11SalFrame::createNewWindow( XLIB_Window aNewParent, int nScreen )
{
bool bWasVisible = bMapped_;
if( bWasVisible )
Show( sal_False );
if( nScreen < 0 || nScreen >= GetDisplay()->GetScreenCount() )
nScreen = m_nScreen;
SystemParentData aParentData;
aParentData.aWindow = aNewParent;
aParentData.bXEmbedSupport = (aNewParent != None && m_bXEmbed); // caution: this is guesswork
if( aNewParent == None )
{
aNewParent = GetDisplay()->GetRootWindow(nScreen);
aParentData.aWindow = None;
m_bXEmbed = false;
}
else
{
// is new parent a root window ?
Display* pDisp = GetDisplay()->GetDisplay();
int nScreens = GetDisplay()->GetScreenCount();
for( int i = 0; i < nScreens; i++ )
{
if( aNewParent == RootWindow( pDisp, i ) )
{
nScreen = i;
aParentData.aWindow = None;
m_bXEmbed = false;
break;
}
}
}
// first deinit frame
updateGraphics(true);
if( mpInputContext )
{
mpInputContext->UnsetICFocus( this );
mpInputContext->Unmap( this );
}
if( GetWindow() == hPresentationWindow )
{
hPresentationWindow = None;
doReparentPresentationDialogues( GetDisplay() );
}
XDestroyWindow( GetXDisplay(), mhWindow );
mhWindow = None;
passOnSaveYourSelf();
// now init with new parent again
if ( aParentData.aWindow != None )
Init( nStyle_ | SAL_FRAME_STYLE_PLUG, nScreen, &aParentData );
else
Init( nStyle_ & ~SAL_FRAME_STYLE_PLUG, nScreen, NULL, true );
// update graphics if necessary
updateGraphics(false);
if( m_aTitle.Len() )
SetTitle( m_aTitle );
if( mpParent )
{
if( mpParent->m_nScreen != m_nScreen )
SetParent( NULL );
else
pDisplay_->getWMAdaptor()->changeReferenceFrame( this, mpParent );
}
if( bWasVisible )
Show( sal_True );
std::list< X11SalFrame* > aChildren = maChildren;
for( std::list< X11SalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
(*it)->createNewWindow( None, m_nScreen );
// FIXME: SalObjects
}
bool X11SalFrame::SetPluginParent( SystemParentData* pNewParent )
{
if( pNewParent->nSize >= sizeof(SystemParentData) )
m_bXEmbed = pNewParent->aWindow != None && pNewParent->bXEmbedSupport;
createNewWindow( pNewParent ? pNewParent->aWindow : None );
return true;
}
// Sound
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalFrame::Beep( SoundType eSoundType ) // not fully suported
{
switch( eSoundType )
{
case SOUND_DEFAULT:
case SOUND_ERROR:
GetDisplay()->Beep();
break;
default:
// Excessive beeping averted
break;
}
}
// Event Handling
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static sal_uInt16 sal_GetCode( int state )
{
sal_uInt16 nCode = 0;
if( state & Button1Mask )
nCode |= MOUSE_LEFT;
if( state & Button2Mask )
nCode |= MOUSE_MIDDLE;
if( state & Button3Mask )
nCode |= MOUSE_RIGHT;
if( state & ShiftMask )
nCode |= KEY_SHIFT;
if( state & ControlMask )
nCode |= KEY_MOD1;
if( state & Mod1Mask )
nCode |= KEY_MOD2;
// Map Meta/Super modifier to MOD3 on all Unix systems
// except Mac OS X
if( (state & Mod3Mask) )
nCode |= KEY_MOD3;
return nCode;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
SalFrame::SalPointerState X11SalFrame::GetPointerState()
{
SalPointerState aState;
XLIB_Window aRoot, aChild;
int rx, ry, wx, wy;
unsigned int nMask = 0;
XQueryPointer( GetXDisplay(),
GetShellWindow(),
&aRoot,
&aChild,
&rx, &ry,
&wx, &wy,
&nMask
);
aState.maPos = Point(wx, wy);
aState.mnState = sal_GetCode( nMask );
return aState;
}
long X11SalFrame::HandleMouseEvent( XEvent *pEvent )
{
SalMouseEvent aMouseEvt;
sal_uInt16 nEvent = 0;
bool bClosePopups = false;
if( nVisibleFloats && pEvent->type == EnterNotify )
return 0;
// Solaris X86: clicking the right button on a two-button mouse
// generates a button2 event not a button3 event
if (pDisplay_->GetProperties() & PROPERTY_SUPPORT_3ButtonMouse )
{
switch (pEvent->type)
{
case EnterNotify:
case LeaveNotify:
if ( pEvent->xcrossing.state & Button2Mask )
{
pEvent->xcrossing.state &= ~Button2Mask;
pEvent->xcrossing.state |= Button3Mask;
}
break;
case MotionNotify:
if ( pEvent->xmotion.state & Button2Mask )
{
pEvent->xmotion.state &= ~Button2Mask;
pEvent->xmotion.state |= Button3Mask;
}
break;
default:
if ( Button2 == pEvent->xbutton.button )
{
pEvent->xbutton.state &= ~Button2Mask;
pEvent->xbutton.state |= Button3Mask;
pEvent->xbutton.button = Button3;
}
break;
}
}
if( LeaveNotify == pEvent->type || EnterNotify == pEvent->type )
{
/*
* #89075# #89335#
*
* 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.
*
* #95901#
* 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 )
return 0;
aMouseEvt.mnX = pEvent->xcrossing.x;
aMouseEvt.mnY = pEvent->xcrossing.y;
aMouseEvt.mnTime = pEvent->xcrossing.time;
aMouseEvt.mnCode = sal_GetCode( pEvent->xcrossing.state );
aMouseEvt.mnButton = 0;
nEvent = LeaveNotify == pEvent->type
? SALEVENT_MOUSELEAVE
: SALEVENT_MOUSEMOVE;
}
else if( pEvent->type == MotionNotify )
{
aMouseEvt.mnX = pEvent->xmotion.x;
aMouseEvt.mnY = pEvent->xmotion.y;
aMouseEvt.mnTime = pEvent->xmotion.time;
aMouseEvt.mnCode = sal_GetCode( pEvent->xmotion.state );
aMouseEvt.mnButton = 0;
nEvent = SALEVENT_MOUSEMOVE;
if( nVisibleFloats > 0 && mpParent )
{
XLIB_Cursor aCursor = mpParent->GetCursor();
if( pEvent->xmotion.x >= 0 && pEvent->xmotion.x < (int)maGeometry.nWidth &&
pEvent->xmotion.y >= 0 && pEvent->xmotion.y < (int)maGeometry.nHeight )
aCursor = None;
XChangeActivePointerGrab( GetXDisplay(),
PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
aCursor,
CurrentTime );
}
}
else
{
// let mouse events reach the correct window
if( nVisibleFloats < 1 )
{
if( ! (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
XUngrabPointer( GetXDisplay(), CurrentTime );
}
else if( pEvent->type == ButtonPress )
{
// see if the user clicks outside all of the floats
// if yes release the grab
bool bInside = false;
const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
{
const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it);
if( pFrame->IsFloatGrabWindow() &&
pFrame->bMapped_ &&
pEvent->xbutton.x_root >= pFrame->maGeometry.nX &&
pEvent->xbutton.x_root < pFrame->maGeometry.nX + (int)pFrame->maGeometry.nWidth &&
pEvent->xbutton.y_root >= pFrame->maGeometry.nY &&
pEvent->xbutton.y_root < pFrame->maGeometry.nY + (int)pFrame->maGeometry.nHeight )
{
bInside = true;
break;
}
}
if( ! bInside )
{
// need not take care of the XUngrabPointer in Show( sal_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)
*/
XLIB_Window aRoot, aChild;
int root_x, root_y, win_x, win_y;
unsigned int mask_return;
if( XQueryPointer( GetXDisplay(),
GetDisplay()->GetRootWindow( m_nScreen ),
&aRoot, &aChild,
&root_x, &root_y,
&win_x, &win_y,
&mask_return )
&& aChild // pointer may not be in any child
)
{
for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
{
const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it);
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.nX && root_x < sal::static_int_cast< int >(pFrame->maGeometry.nX+pFrame->maGeometry.nWidth) &&
root_y >= pFrame->maGeometry.nY && root_y < sal::static_int_cast< int >(pFrame->maGeometry.nX+pFrame->maGeometry.nHeight) )
{
bClosePopups = false;
}
break;
}
}
}
}
}
if( m_bXEmbed && pEvent->xbutton.button == Button1 )
askForXEmbedFocus( pEvent->xbutton.time );
if( pEvent->xbutton.button == Button1 ||
pEvent->xbutton.button == Button2 ||
pEvent->xbutton.button == Button3 )
{
aMouseEvt.mnX = pEvent->xbutton.x;
aMouseEvt.mnY = pEvent->xbutton.y;
aMouseEvt.mnTime = pEvent->xbutton.time;
aMouseEvt.mnCode = sal_GetCode( pEvent->xbutton.state );
if( Button1 == pEvent->xbutton.button )
aMouseEvt.mnButton = MOUSE_LEFT;
else if( Button2 == pEvent->xbutton.button )
aMouseEvt.mnButton = MOUSE_MIDDLE;
else if( Button3 == pEvent->xbutton.button )
aMouseEvt.mnButton = MOUSE_RIGHT;
nEvent = ButtonPress == pEvent->type
? SALEVENT_MOUSEBUTTONDOWN
: SALEVENT_MOUSEBUTTONUP;
}
else if( pEvent->xbutton.button == Button4 ||
pEvent->xbutton.button == Button5 ||
pEvent->xbutton.button == Button6 ||
pEvent->xbutton.button == Button7 )
{
const bool bIncrement(
pEvent->xbutton.button == Button4 ||
pEvent->xbutton.button == Button6 );
const bool bHoriz(
pEvent->xbutton.button == Button6 ||
pEvent->xbutton.button == Button7 );
if( pEvent->type == ButtonRelease )
return 0;
static sal_uLong nLines = 0;
if( ! nLines )
{
char* pEnv = getenv( "SAL_WHEELLINES" );
nLines = pEnv ? atoi( pEnv ) : 3;
if( nLines > 10 )
nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
}
SalWheelMouseEvent aWheelEvt;
aWheelEvt.mnTime = pEvent->xbutton.time;
aWheelEvt.mnX = pEvent->xbutton.x;
aWheelEvt.mnY = pEvent->xbutton.y;
aWheelEvt.mnDelta = bIncrement ? 120 : -120;
aWheelEvt.mnNotchDelta = bIncrement ? 1 : -1;
aWheelEvt.mnScrollLines = nLines;
aWheelEvt.mnCode = sal_GetCode( pEvent->xbutton.state );
aWheelEvt.mbHorz = bHoriz;
nEvent = SALEVENT_WHEELMOUSE;
// --- RTL --- (mirror mouse pos)
if( Application::GetSettings().GetLayoutRTL() )
aWheelEvt.mnX = nWidth_-1-aWheelEvt.mnX;
return CallCallback( nEvent, &aWheelEvt );
}
}
int nRet = 0;
if( nEvent == SALEVENT_MOUSELEAVE
|| ( aMouseEvt.mnX < nWidth_ && aMouseEvt.mnX > -1 &&
aMouseEvt.mnY < nHeight_ && aMouseEvt.mnY > -1 )
|| pDisplay_->MouseCaptured( this )
)
{
// --- RTL --- (mirror mouse pos)
if( Application::GetSettings().GetLayoutRTL() )
aMouseEvt.mnX = nWidth_-1-aMouseEvt.mnX;
nRet = CallCallback( nEvent, &aMouseEvt );
}
if( bClosePopups )
{
/* #108213# close popups after dispatching the event outside the popup;
* applications do weird things.
*/
ImplSVData* pSVData = ImplGetSVData();
if ( pSVData->maWinData.mpFirstFloat )
{
static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) && !(pEnv && *pEnv) )
pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
}
}
return nRet;
}
// F10 means either KEY_F10 or KEY_MENU, which has to be decided
// in the independent part.
struct KeyAlternate
{
sal_uInt16 nKeyCode;
sal_Unicode nCharCode;
KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
KeyAlternate( sal_uInt16 nKey, sal_Unicode nChar = 0 ) : nKeyCode( nKey ), nCharCode( nChar ) {}
};
inline KeyAlternate
GetAlternateKeyCode( const sal_uInt16 nKeyCode )
{
KeyAlternate aAlternate;
switch( nKeyCode )
{
case KEY_F10: aAlternate = KeyAlternate( KEY_MENU );break;
case KEY_F24: aAlternate = KeyAlternate( KEY_SUBTRACT, '-' );break;
}
return aAlternate;
}
void X11SalFrame::beginUnicodeSequence()
{
rtl::OUString& rSeq( GetX11SalData()->GetUnicodeAccumulator() );
DeletionListener aDeleteWatch( this );
if( rSeq.getLength() )
endUnicodeSequence();
rSeq = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "u" ) );
if( ! aDeleteWatch.isDeleted() )
{
sal_uInt16 nTextAttr = SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
SalExtTextInputEvent aEv;
aEv.mnTime = 0;
aEv.maText = rSeq;
aEv.mpTextAttr = &nTextAttr;
aEv.mnCursorPos = 0;
aEv.mnDeltaStart = 0;
aEv.mnCursorFlags = 0;
aEv.mbOnlyCursor = sal_False;
CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&aEv);
}
}
bool X11SalFrame::appendUnicodeSequence( sal_Unicode c )
{
bool bRet = false;
rtl::OUString& rSeq( GetX11SalData()->GetUnicodeAccumulator() );
if( rSeq.getLength() > 0 )
{
// range check
if( (c >= sal_Unicode('0') && c <= sal_Unicode('9')) ||
(c >= sal_Unicode('a') && c <= sal_Unicode('f')) ||
(c >= sal_Unicode('A') && c <= sal_Unicode('F')) )
{
rtl::OUStringBuffer aBuf( rSeq.getLength() + 1 );
aBuf.append( rSeq );
aBuf.append( c );
rSeq = aBuf.makeStringAndClear();
std::vector<sal_uInt16> attribs( rSeq.getLength(), SAL_EXTTEXTINPUT_ATTR_UNDERLINE );
SalExtTextInputEvent aEv;
aEv.mnTime = 0;
aEv.maText = rSeq;
aEv.mpTextAttr = &attribs[0];
aEv.mnCursorPos = 0;
aEv.mnDeltaStart = 0;
aEv.mnCursorFlags = 0;
aEv.mbOnlyCursor = sal_False;
CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&aEv);
bRet = true;
}
else
bRet = endUnicodeSequence();
}
else
endUnicodeSequence();
return bRet;
}
bool X11SalFrame::endUnicodeSequence()
{
rtl::OUString& rSeq( GetX11SalData()->GetUnicodeAccumulator() );
DeletionListener aDeleteWatch( this );
if( rSeq.getLength() > 1 && rSeq.getLength() < 6 )
{
// cut the "u"
rtl::OUString aNumbers( rSeq.copy( 1 ) );
sal_Int32 nValue = aNumbers.toInt32( 16 );
if( nValue >= 32 )
{
sal_uInt16 nTextAttr = SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
SalExtTextInputEvent aEv;
aEv.mnTime = 0;
aEv.maText = rtl::OUString( sal_Unicode(nValue) );
aEv.mpTextAttr = &nTextAttr;
aEv.mnCursorPos = 0;
aEv.mnDeltaStart = 0;
aEv.mnCursorFlags = 0;
aEv.mbOnlyCursor = sal_False;
CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&aEv);
}
}
bool bWasInput = rSeq.getLength() > 0;
rSeq = rtl::OUString();
if( bWasInput && ! aDeleteWatch.isDeleted() )
CallCallback(SALEVENT_ENDEXTTEXTINPUT, NULL);
return bWasInput;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long X11SalFrame::HandleKeyEvent( XKeyEvent *pEvent )
{
KeySym nKeySym;
KeySym nUnmodifiedKeySym;
int nLen = 2048;
unsigned char *pPrintable = (unsigned char*)alloca( nLen );
// singlebyte code composed by input method, the new default
if (mpInputContext != NULL && 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 )
{
nLen *= 2;
pPrintable = (unsigned 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 );
}
SalKeyEvent aKeyEvt;
sal_uInt16 nKeyCode;
sal_uInt16 nModCode = 0;
char aDummy;
if( pEvent->state & ShiftMask )
nModCode |= KEY_SHIFT;
if( pEvent->state & ControlMask )
nModCode |= KEY_MOD1;
if( pEvent->state & Mod1Mask )
nModCode |= KEY_MOD2;
if( nModCode != (KEY_SHIFT|KEY_MOD1) )
endUnicodeSequence();
if( nKeySym == XK_Shift_L || nKeySym == XK_Shift_R
|| nKeySym == XK_Control_L || nKeySym == XK_Control_R
|| nKeySym == XK_Alt_L || nKeySym == XK_Alt_R
|| nKeySym == XK_Meta_L || nKeySym == XK_Meta_R
|| nKeySym == XK_Super_L || nKeySym == XK_Super_R )
{
SalKeyModEvent aModEvt;
aModEvt.mnModKeyCode = 0;
if( pEvent->type == XLIB_KeyPress && mnExtKeyMod == 0 )
mbSendExtKeyModChange = true;
else if( pEvent->type == KeyRelease && mbSendExtKeyModChange )
{
aModEvt.mnModKeyCode = mnExtKeyMod;
mnExtKeyMod = 0;
}
// pressing just the ctrl key leads to a keysym of XK_Control but
// the event state does not contain ControlMask. In the release
// event its the other way round: it does contain the Control mask.
// The modifier mode therefore has to be adapted manually.
sal_uInt16 nExtModMask = 0;
sal_uInt16 nModMask = 0;
switch( nKeySym )
{
case XK_Control_L:
nExtModMask = MODKEY_LMOD1;
nModMask = KEY_MOD1;
break;
case XK_Control_R:
nExtModMask = MODKEY_RMOD1;
nModMask = KEY_MOD1;
break;
case XK_Alt_L:
nExtModMask = MODKEY_LMOD2;
nModMask = KEY_MOD2;
break;
case XK_Alt_R:
nExtModMask = MODKEY_RMOD2;
nModMask = KEY_MOD2;
break;
case XK_Shift_L:
nExtModMask = MODKEY_LSHIFT;
nModMask = KEY_SHIFT;
break;
case XK_Shift_R:
nExtModMask = MODKEY_RSHIFT;
nModMask = KEY_SHIFT;
break;
// Map Meta/Super keys to MOD3 modifier on all Unix systems
// except Mac OS X
case XK_Meta_L:
case XK_Super_L:
nExtModMask = MODKEY_LMOD3;
nModMask = KEY_MOD3;
break;
case XK_Meta_R:
case XK_Super_R:
nExtModMask = MODKEY_RMOD3;
nModMask = KEY_MOD3;
break;
}
if( pEvent->type == KeyRelease )
{
nModCode &= ~nModMask;
mnExtKeyMod &= ~nExtModMask;
}
else
{
nModCode |= nModMask;
mnExtKeyMod |= nExtModMask;
}
aModEvt.mnCode = nModCode;
aModEvt.mnTime = pEvent->time;
int nRet = CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
// emulate KEY_MENU
if ( ( (nKeySym == XK_Alt_L) || (nKeySym == XK_Alt_R) ) &&
( (nModCode & ~(KEY_MOD3|KEY_MOD2)) == 0 ) )
{
if( pEvent->type == XLIB_KeyPress )
mbKeyMenu = true;
else if( mbKeyMenu )
{
// simulate KEY_MENU
aKeyEvt.mnCode = KEY_MENU | nModCode;
aKeyEvt.mnRepeat = 0;
aKeyEvt.mnTime = pEvent->time;
aKeyEvt.mnCharCode = 0;
nRet = CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
nRet = CallCallback( SALEVENT_KEYUP, &aKeyEvt );
}
}
else
mbKeyMenu = false;
return nRet;
}
mbSendExtKeyModChange = mbKeyMenu = false;
// 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)
return 0;
DeletionListener aDeleteWatch( this );
if( nModCode == (KEY_SHIFT | KEY_MOD1) && pEvent->type == XLIB_KeyPress )
{
sal_uInt16 nSeqKeyCode = pDisplay_->GetKeyCode( nUnmodifiedKeySym, &aDummy );
if( nSeqKeyCode == KEY_U )
{
beginUnicodeSequence();
return 1;
}
else if( nSeqKeyCode >= KEY_0 && nSeqKeyCode <= KEY_9 )
{
if( appendUnicodeSequence( sal_Unicode( '0' ) + sal_Unicode(nSeqKeyCode - KEY_0) ) )
return 1;
}
else if( nSeqKeyCode >= KEY_A && nSeqKeyCode <= KEY_F )
{
if( appendUnicodeSequence( sal_Unicode( 'a' ) + sal_Unicode(nSeqKeyCode - KEY_A) ) )
return 1;
}
else
endUnicodeSequence();
}
if( aDeleteWatch.isDeleted() )
return 0;
rtl_TextEncoding nEncoding;
if (mpInputContext != NULL && mpInputContext->IsMultiLingual() )
nEncoding = RTL_TEXTENCODING_UTF8;
else
nEncoding = osl_getThreadTextEncoding();
sal_Unicode *pBuffer;
sal_Unicode *pString;
sal_Size nBufferSize = nLen * 2;
sal_Size nSize;
pBuffer = (sal_Unicode*) malloc( nBufferSize + 2 );
pBuffer[ 0 ] = 0;
if (nKeyString != 0)
{
pString = &nKeyString;
nSize = 1;
}
else
if (nLen > 0 && nEncoding != RTL_TEXTENCODING_UNICODE)
{
// create text converter
rtl_TextToUnicodeConverter aConverter =
rtl_createTextToUnicodeConverter( nEncoding );
rtl_TextToUnicodeContext aContext =
rtl_createTextToUnicodeContext( aConverter );
sal_uInt32 nConversionInfo;
sal_Size nConvertedChars;
// convert to single byte text stream
nSize = rtl_convertTextToUnicode(
aConverter, aContext,
(char*)pPrintable, nLen,
pBuffer, nBufferSize,
RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE |
RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE,
&nConversionInfo, &nConvertedChars );
// destroy converter
rtl_destroyTextToUnicodeContext( aConverter, aContext );
rtl_destroyTextToUnicodeConverter( aConverter );
pString = pBuffer;
}
else
if (nLen > 0 /* nEncoding == RTL_TEXTENCODING_UNICODE */)
{
pString = (sal_Unicode*)pPrintable;
nSize = nLen;
}
else
{
pString = pBuffer;
nSize = 0;
}
if ( mpInputContext != NULL
&& mpInputContext->UseContext()
&& KeyRelease != pEvent->type
&& ( (nSize > 1)
|| (nSize > 0 && mpInputContext->IsPreeditMode())) )
{
mpInputContext->CommitKeyEvent(pString, nSize);
}
else
// normal single character keyinput
{
aKeyEvt.mnCode = nKeyCode | nModCode;
aKeyEvt.mnRepeat = 0;
aKeyEvt.mnTime = pEvent->time;
aKeyEvt.mnCharCode = pString[ 0 ];
if( KeyRelease == pEvent->type )
{
CallCallback( SALEVENT_KEYUP, &aKeyEvt );
}
else
{
if ( ! CallCallback(SALEVENT_KEYINPUT, &aKeyEvt) )
{
// independent layer doesnt 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 != NULL && mpInputContext->UseContext())
mpInputContext->UpdateSpotLocation();
}
free (pBuffer);
return True;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long X11SalFrame::HandleFocusEvent( XFocusChangeEvent *pEvent )
{
// #107739# ReflectionX in Windows mode changes focus while mouse is grabbed
if( nVisibleFloats > 0 && GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii( "ReflectionX Windows" ) )
return 1;
/* #55691# 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
* #73179# handle focus events with mode NotifyWhileGrabbed
* because with CDE alt-tab focus changing we do not get
* normal focus events
* #71791# cast focus event to the input context, otherwise the
* status window does not follow the application frame
*/
if ( mpInputContext != NULL )
{
if( FocusIn == pEvent->type )
mpInputContext->SetICFocus( this );
else
{
/*
* do not unset the IC focuse here because would kill
* a lookup choice windows that might have the focus now
* mpInputContext->UnsetICFocus( this );
*/
I18NStatus::get().show( false, I18NStatus::focus );
}
}
if ( pEvent->mode == NotifyNormal || pEvent->mode == NotifyWhileGrabbed ||
( ( nStyle_ & SAL_FRAME_STYLE_PLUG ) && pEvent->window == GetShellWindow() )
)
{
if( hPresentationWindow != None && hPresentationWindow != GetShellWindow() )
return 0;
if( FocusIn == pEvent->type )
{
vcl_sal::PrinterUpdate::update();
mbInputFocus = True;
ImplSVData* pSVData = ImplGetSVData();
long nRet = CallCallback( SALEVENT_GETFOCUS, 0 );
if ((mpParent != NULL && nStyle_ == 0)
&& pSVData->maWinData.mpFirstFloat )
{
sal_uLong nMode = pSVData->maWinData.mpFirstFloat->GetPopupModeFlags();
pSVData->maWinData.mpFirstFloat->SetPopupModeFlags(
nMode & ~(FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE));
}
return nRet;
}
else
{
mbInputFocus = False;
mbSendExtKeyModChange = mbKeyMenu = false;
mnExtKeyMod = 0;
return CallCallback( SALEVENT_LOSEFOCUS, 0 );
}
}
return 0;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long X11SalFrame::HandleExposeEvent( XEvent *pEvent )
{
XRectangle aRect = { 0, 0, 0, 0 };
sal_uInt16 nCount = 0;
if( pEvent->type == Expose )
{
aRect.x = pEvent->xexpose.x;
aRect.y = pEvent->xexpose.y;
aRect.width = pEvent->xexpose.width;
aRect.height = pEvent->xexpose.height;
nCount = pEvent->xexpose.count;
}
else if( pEvent->type == GraphicsExpose )
{
aRect.x = pEvent->xgraphicsexpose.x;
aRect.y = pEvent->xgraphicsexpose.y;
aRect.width = pEvent->xgraphicsexpose.width;
aRect.height = pEvent->xgraphicsexpose.height;
nCount = pEvent->xgraphicsexpose.count;
}
if( IsOverrideRedirect() && mbFullScreen &&
aPresentationReparentList.begin() == aPresentationReparentList.end() )
// 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( 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
return 1;
SalPaintEvent aPEvt( maPaintRegion.Left(), maPaintRegion.Top(), maPaintRegion.GetWidth(), maPaintRegion.GetHeight() );
CallCallback( SALEVENT_PAINT, &aPEvt );
maPaintRegion = Rectangle();
return 1;
}
void X11SalFrame::RestackChildren( XLIB_Window* pTopLevelWindows, int nTopLevelWindows )
{
if( maChildren.begin() != maChildren.end() )
{
int nWindow = nTopLevelWindows;
while( nWindow-- )
if( pTopLevelWindows[nWindow] == GetStackingWindow() )
break;
if( nWindow < 0 )
return;
std::list< X11SalFrame* >::const_iterator it;
for( it = maChildren.begin(); it != maChildren.end(); ++it )
{
X11SalFrame* pData = *it;
if( pData->bMapped_ )
{
int nChild = nWindow;
while( nChild-- )
{
if( pTopLevelWindows[nChild] == pData->GetStackingWindow() )
{
// if a child is behind its parent, place it above the
// parent (for insane WMs like Dtwm and olwm)
XWindowChanges aCfg;
aCfg.sibling = GetStackingWindow();
aCfg.stack_mode = Above;
XConfigureWindow( GetXDisplay(), pData->GetStackingWindow(), CWSibling|CWStackMode, &aCfg );
break;
}
}
}
}
for( it = maChildren.begin(); it != maChildren.end(); ++it )
{
X11SalFrame* pData = *it;
pData->RestackChildren( pTopLevelWindows, nTopLevelWindows );
}
}
}
void X11SalFrame::RestackChildren()
{
if( ! GetDisplay()->getWMAdaptor()->isTransientBehaviourAsExpected()
&& maChildren.begin() != maChildren.end() )
{
XLIB_Window aRoot, aParent, *pChildren = NULL;
unsigned int nChildren;
if( XQueryTree( GetXDisplay(),
GetDisplay()->GetRootWindow( m_nScreen ),
&aRoot,
&aParent,
&pChildren,
&nChildren ) )
{
RestackChildren( pChildren, nChildren );
XFree( pChildren );
}
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long X11SalFrame::HandleSizeEvent( XConfigureEvent *pEvent )
{
if ( pEvent->window != GetShellWindow()
&& pEvent->window != GetWindow()
&& pEvent->window != GetForeignParent()
&& pEvent->window != GetStackingWindow()
)
{
// could be as well a sys-child window (aka SalObject)
return 1;
}
if( ( nStyle_ & SAL_FRAME_STYLE_PLUG ) && pEvent->window == GetShellWindow() )
{
// just update the children's positions
RestackChildren();
return 1;
}
if( pEvent->window == GetForeignParent() )
XResizeWindow( GetXDisplay(),
GetWindow(),
pEvent->width,
pEvent->height );
XLIB_Window hDummy;
XTranslateCoordinates( GetXDisplay(),
GetWindow(),
pDisplay_->GetRootWindow( pDisplay_->GetDefaultScreenNumber() ),
0, 0,
&pEvent->x, &pEvent->y,
&hDummy );
if( pEvent->window == GetStackingWindow() )
{
if( maGeometry.nX != pEvent->x || maGeometry.nY != pEvent->y )
{
maGeometry.nX = pEvent->x;
maGeometry.nY = pEvent->y;
CallCallback( SALEVENT_MOVE, NULL );
}
return 1;
}
// check size hints in first time SalFrame::Show
if( SHOWSTATE_UNKNOWN == nShowState_ && bMapped_ )
nShowState_ = SHOWSTATE_NORMAL;
nWidth_ = pEvent->width;
nHeight_ = pEvent->height;
bool bMoved = ( pEvent->x != maGeometry.nX || pEvent->y != maGeometry.nY );
bool bSized = ( pEvent->width != (int)maGeometry.nWidth || pEvent->height != (int)maGeometry.nHeight );
maGeometry.nX = pEvent->x;
maGeometry.nY = pEvent->y;
maGeometry.nWidth = pEvent->width;
maGeometry.nHeight = pEvent->height;
updateScreenNumber();
// update children's position
RestackChildren();
if( bSized && ! bMoved )
CallCallback( SALEVENT_RESIZE, NULL );
else if( bMoved && ! bSized )
CallCallback( SALEVENT_MOVE, NULL );
else if( bMoved && bSized )
CallCallback( SALEVENT_MOVERESIZE, NULL );
return 1;
}
IMPL_LINK( X11SalFrame, HandleAlwaysOnTopRaise, void*, EMPTYARG )
{
if( bMapped_ )
ToTop( 0 );
return 0;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long X11SalFrame::HandleReparentEvent( XReparentEvent *pEvent )
{
Display *pDisplay = pEvent->display;
XLIB_Window hWM_Parent;
XLIB_Window hRoot, *Children, hDummy;
unsigned int nChildren;
sal_Bool bNone = pDisplay_->GetProperties()
& PROPERTY_SUPPORT_WM_Parent_Pixmap_None;
sal_Bool bAccessParentWindow = ! (pDisplay_->GetProperties()
& PROPERTY_FEATURE_TrustedSolaris);
static const char* pDisableStackingCheck = getenv( "SAL_DISABLE_STACKING_CHECK" );
GetDisplay()->GetXLib()->PushXErrorLevel( true );
/*
* #89186# 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 that would
* be very sensible)
*/
hWM_Parent = GetShellWindow();
do
{
Children = NULL;
XQueryTree( pDisplay,
hWM_Parent,
&hRoot,
&hDummy,
&Children,
&nChildren );
if( GetDisplay()->GetXLib()->HasXErrorOccured() )
{
hWM_Parent = GetShellWindow();
break;
}
/* #107048# this sometimes happens if a Show(sal_True) is
* immediately followed by Show(sal_False) (which is braindead anyway)
*/
if( hDummy == hWM_Parent )
hDummy = hRoot;
if( hDummy != hRoot )
{
hWM_Parent = hDummy;
if( bAccessParentWindow && bNone )
XSetWindowBackgroundPixmap( pDisplay, hWM_Parent, None );
}
if( Children )
XFree( Children );
} while( hDummy != hRoot );
if( GetStackingWindow() == None
&& hWM_Parent != hPresentationWindow
&& hWM_Parent != GetShellWindow()
&& ( ! pDisableStackingCheck || ! *pDisableStackingCheck )
)
{
mhStackingWindow = hWM_Parent;
if (bAccessParentWindow)
XSelectInput( pDisplay, GetStackingWindow(), StructureNotifyMask );
}
if( hWM_Parent == pDisplay_->GetRootWindow( pDisplay_->GetDefaultScreenNumber() )
|| hWM_Parent == GetForeignParent()
|| pEvent->parent == pDisplay_->GetRootWindow( pDisplay_->GetDefaultScreenNumber() )
|| ( nStyle_ & SAL_FRAME_STYLE_FLOAT ) )
{
// Reparenting before Destroy
aPresentationReparentList.remove( GetStackingWindow() );
mhStackingWindow = None;
GetDisplay()->GetXLib()->PopXErrorLevel();
return 0;
}
/*
* 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_nScreen )
)
{
int x = 0, y = 0;
XLIB_Window aChild;
XTranslateCoordinates( GetXDisplay(),
GetStackingWindow(),
GetDisplay()->GetRootWindow( m_nScreen ),
0, 0,
&x, &y,
&aChild
);
XReparentWindow( GetXDisplay(),
GetStackingWindow(),
hPresentationWindow,
x, y
);
aPresentationReparentList.push_back( GetStackingWindow() );
}
int nLeft = 0, nTop = 0;
XTranslateCoordinates( GetXDisplay(),
GetShellWindow(),
hWM_Parent,
0, 0,
&nLeft,
&nTop,
&hDummy );
maGeometry.nLeftDecoration = nLeft > 0 ? nLeft-1 : 0;
maGeometry.nTopDecoration = nTop > 0 ? nTop-1 : 0;
/*
* decorations are not symmetric,
* so need real geometries here
* (this will fail with virtual roots ?)
*/
GetDisplay()->GetXLib()->ResetXErrorOccured();
int xp, yp, x, y;
unsigned int wp, w, hp, h, bw, d;
XGetGeometry( GetXDisplay(),
GetShellWindow(),
&hRoot,
&x, &y, &w, &h, &bw, &d );
XGetGeometry( GetXDisplay(),
hWM_Parent,
&hRoot,
&xp, &yp, &wp, &hp, &bw, &d );
bool bResized = false;
if( ! GetDisplay()->GetXLib()->HasXErrorOccured() )
{
maGeometry.nRightDecoration = wp - w - maGeometry.nLeftDecoration;
maGeometry.nBottomDecoration = hp - h - maGeometry.nTopDecoration;
/*
* note: this works because hWM_Parent is direct child of root,
* not necessarily parent of GetShellWindow()
*/
maGeometry.nX = xp + nLeft;
maGeometry.nY = yp + nTop;
bResized = w != maGeometry.nWidth || h != maGeometry.nHeight;
maGeometry.nWidth = w;
maGeometry.nHeight = h;
}
// limit width and height if we are too large: #47757
// olwm and fvwm need this, it doesnt harm the rest
// #i81311# do this only for sizable frames
if( (nStyle_ & SAL_FRAME_STYLE_SIZEABLE) != 0 )
{
Size aScreenSize = GetDisplay()->GetScreenSize( m_nScreen );
int nScreenWidth = aScreenSize.Width();
int nScreenHeight = aScreenSize.Height();
int nFrameWidth = maGeometry.nWidth + maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
int nFrameHeight = maGeometry.nHeight + maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
if ((nFrameWidth > nScreenWidth) || (nFrameHeight > nScreenHeight))
{
Size aSize(maGeometry.nWidth, maGeometry.nHeight);
if (nFrameWidth > nScreenWidth)
aSize.Width() = nScreenWidth - maGeometry.nRightDecoration - maGeometry.nLeftDecoration;
if (nFrameHeight > nScreenHeight)
aSize.Height() = nScreenHeight - maGeometry.nBottomDecoration - maGeometry.nTopDecoration;
SetSize( aSize );
bResized = false;
}
}
if( bResized )
CallCallback( SALEVENT_RESIZE, NULL );
GetDisplay()->GetXLib()->PopXErrorLevel();
return 1;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long X11SalFrame::HandleColormapEvent( XColormapEvent* )
{
return 0;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long X11SalFrame::HandleStateEvent( XPropertyEvent *pEvent )
{
Atom actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *prop = NULL;
if( 0 != XGetWindowProperty( GetXDisplay(),
GetShellWindow(),
pEvent->atom, // property
0, // long_offset (32bit)
2, // long_length (32bit)
False, // delete
pEvent->atom, // req_type
&actual_type,
&actual_format,
&nitems,
&bytes_after,
&prop )
|| ! prop
)
return 0;
DBG_ASSERT( actual_type = pEvent->atom
&& 32 == actual_format
&& 2 == nitems
&& 0 == bytes_after, "HandleStateEvent" );
if( *(unsigned long*)prop == NormalState )
nShowState_ = SHOWSTATE_NORMAL;
else if( *(unsigned long*)prop == IconicState )
nShowState_ = SHOWSTATE_MINIMIZED;
XFree( prop );
return 1;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long X11SalFrame::HandleClientMessage( XClientMessageEvent *pEvent )
{
const WMAdaptor& rWMAdaptor( *pDisplay_->getWMAdaptor() );
#if !defined(__synchronous_extinput__)
if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::SAL_EXTTEXTEVENT ) )
{
HandleExtTextEvent (pEvent);
return 1;
}
#endif
else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::SAL_QUITEVENT ) )
{
stderr0( "X11SalFrame::Dispatch Quit\n" );
Close(); // ???
return 1;
}
else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::WM_PROTOCOLS ) )
{
if( (Atom)pEvent->data.l[0] == rWMAdaptor.getAtom( WMAdaptor::NET_WM_PING ) )
rWMAdaptor.answerPing( this, pEvent );
else if( ! ( nStyle_ & SAL_FRAME_STYLE_PLUG )
&& ! (( nStyle_ & SAL_FRAME_STYLE_FLOAT ) && (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION))
)
{
if( (Atom)pEvent->data.l[0] == rWMAdaptor.getAtom( WMAdaptor::WM_DELETE_WINDOW ) )
{
Close();
return 1;
}
else if( (Atom)pEvent->data.l[0] == rWMAdaptor.getAtom( WMAdaptor::WM_TAKE_FOCUS ) )
{
// do nothing, we set the input focus in ToTop() if necessary
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "got WM_TAKE_FOCUS on %s window\n",
(nStyle_&SAL_FRAME_STYLE_OWNERDRAWDECORATION) ?
"ownerdraw" : "NON OWNERDRAW" );
#endif
}
else if( (Atom)pEvent->data.l[0] == rWMAdaptor.getAtom( WMAdaptor::WM_SAVE_YOURSELF ) )
{
bool bSession = rWMAdaptor.getWindowManagerName().EqualsAscii( "Dtwm" );
if( ! bSession )
{
if( this == s_pSaveYourselfFrame )
{
ByteString aExec( SessionManagerClient::getExecName(), osl_getThreadTextEncoding() );
const char* argv[2];
argv[0] = "/bin/sh";
argv[1] = const_cast<char*>(aExec.GetBuffer());
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "SaveYourself request, setting command: %s %s\n", argv[0], argv[1] );
#endif
XSetCommand( GetXDisplay(), GetShellWindow(), (char**)argv, 2 );
}
else
// can only happen in race between WM and window closing
XChangeProperty( GetXDisplay(), GetShellWindow(), rWMAdaptor.getAtom( WMAdaptor::WM_COMMAND ), XA_STRING, 8, PropModeReplace, (unsigned char*)"", 0 );
}
else
{
// save open documents; would be good for non Dtwm, too,
// but there is no real Shutdown message in the ancient
// SM protocol; on Dtwm SaveYourself really means Shutdown, too.
IceSalSession::handleOldX11SaveYourself( this );
}
}
}
}
else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::XEMBED ) &&
pEvent->window == GetWindow() )
{
if( pEvent->data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
pEvent->data.l[1] == 2 ) // XEMBED_WINDOW_DEACTIVATE
{
XFocusChangeEvent aEvent;
aEvent.type = (pEvent->data.l[1] == 1 ? FocusIn : FocusOut);
aEvent.serial = pEvent->serial;
aEvent.send_event = True;
aEvent.display = pEvent->display;
aEvent.window = pEvent->window;
aEvent.mode = NotifyNormal;
aEvent.detail = NotifyDetailNone;
HandleFocusEvent( &aEvent );
}
}
return 0;
}
void X11SalFrame::SaveYourselfDone( SalFrame* pSaveFrame )
{
// session save was done, inform dtwm
if( s_pSaveYourselfFrame && pSaveFrame )
{
ByteString aExec( SessionManagerClient::getExecName(), osl_getThreadTextEncoding() );
const char* argv[2];
argv[0] = "/bin/sh";
argv[1] = const_cast<char*>(aExec.GetBuffer());
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "SaveYourself request, setting command: %s %s\n", argv[0], argv[1] );
#endif
XSetCommand( s_pSaveYourselfFrame->GetXDisplay(),
s_pSaveYourselfFrame->GetShellWindow(),
(char**)argv, 2 );
if( pSaveFrame != s_pSaveYourselfFrame )
{
// check if it still exists
const X11SalFrame* pFrame = NULL;
const std::list< SalFrame* >& rFrames = static_cast<X11SalFrame*>(pSaveFrame)->GetDisplay()->getFrames();
std::list< SalFrame* >::const_iterator it = rFrames.begin();
while( it != rFrames.end() )
{
pFrame = static_cast< const X11SalFrame* >(*it);
if( pFrame == pSaveFrame )
break;
++it;
}
if( pFrame == pSaveFrame )
{
const WMAdaptor& rWMAdaptor( *pFrame->pDisplay_->getWMAdaptor() );
XChangeProperty( pFrame->GetXDisplay(),
pFrame->GetShellWindow(),
rWMAdaptor.getAtom( WMAdaptor::WM_COMMAND ), XA_STRING, 8, PropModeReplace, (unsigned char*)"", 0 );
}
}
s_pSaveYourselfFrame->ShutDown();
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
extern "C"
{
Bool call_checkKeyReleaseForRepeat( Display* pDisplay, XEvent* pCheck, XPointer pX11SalFrame )
{
return X11SalFrame::checkKeyReleaseForRepeat( pDisplay, pCheck, pX11SalFrame );
}
}
Bool X11SalFrame::checkKeyReleaseForRepeat( Display*, XEvent* pCheck, XPointer pX11SalFrame )
{
X11SalFrame* pThis = (X11SalFrame*)pX11SalFrame;
return
pCheck->type == XLIB_KeyPress &&
pCheck->xkey.state == pThis->nKeyState_ &&
pCheck->xkey.keycode == pThis->nKeyCode_ &&
pCheck->xkey.time == pThis->nReleaseTime_ ? True : False;
}
long X11SalFrame::Dispatch( XEvent *pEvent )
{
long nRet = 0;
if( -1 == nCaptured_ )
{
CaptureMouse( sal_True );
#ifdef DBG_UTIL
if( -1 != nCaptured_ )
pDisplay_->PrintEvent( "Captured", pEvent );
#endif
}
if( pEvent->xany.window == GetShellWindow() || pEvent->xany.window == GetWindow() )
{
switch( pEvent->type )
{
case XLIB_KeyPress:
nKeyCode_ = pEvent->xkey.keycode;
nKeyState_ = pEvent->xkey.state;
nRet = HandleKeyEvent( &pEvent->xkey );
break;
case KeyRelease:
if( -1 == nCompose_ )
{
nReleaseTime_ = pEvent->xkey.time;
XEvent aEvent;
if( XCheckIfEvent( pEvent->xkey.display, &aEvent, call_checkKeyReleaseForRepeat, (XPointer)this ) )
XPutBackEvent( pEvent->xkey.display, &aEvent );
else
nRet = HandleKeyEvent( &pEvent->xkey );
}
break;
case ButtonPress:
// #74406# if we loose 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 );
}
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_ == SHOWSTATE_HIDDEN )
{
/*
* #95097# 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_ & SAL_FRAME_STYLE_PLUG) )
XUnmapWindow( GetXDisplay(), GetShellWindow() );
break;
}
bMapped_ = sal_True;
bViewable_ = sal_True;
nRet = sal_True;
if ( mpInputContext != NULL )
mpInputContext->Map( this );
CallCallback( SALEVENT_RESIZE, NULL );
if( pDisplay_->GetServerVendor() == vendor_hummingbird )
{
/*
* With Exceed sometimes there does not seem to be
* an Expose after the MapNotify.
* so start a delayed paint here
*/
maPaintRegion.Union( Rectangle( Point( 0, 0 ), Size( maGeometry.nWidth, maGeometry.nHeight ) ) );
XEvent aEvent;
aEvent.xexpose.type = Expose;
aEvent.xexpose.display = pDisplay_->GetDisplay();
aEvent.xexpose.x = 0;
aEvent.xexpose.y = 0;
aEvent.xexpose.width = maGeometry.nWidth;
aEvent.xexpose.height = maGeometry.nHeight;
aEvent.xexpose.count = 0;
XSendEvent( pDisplay_->GetDisplay(),
GetWindow(),
True,
ExposureMask,
&aEvent );
}
bool bSetFocus = m_bSetFocusOnMap;
/* #99570# another workaround for sawfish: if a transient window for the same parent is shown
* sawfish does not set the focus to it. Applies only for click to focus mode.
*/
if( ! (nStyle_ & SAL_FRAME_STYLE_FLOAT ) && mbInShow && GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii( "Sawfish" ) )
{
// #101775# don't set the focus into the IME status window
// since this will lead to a parent loose-focus, close status,
// reget focus, open status, .... flicker loop
if ( (I18NStatus::get().getStatusFrame() != this) )
bSetFocus = true;
}
/*
* 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( std::list< X11SalFrame* >::const_iterator it = maChildren.begin();
it != maChildren.end(); ++it )
{
if( (*it)->mbTransientForRoot )
pDisplay_->getWMAdaptor()->changeReferenceFrame( *it, this );
}
}
if( hPresentationWindow != None && GetShellWindow() == hPresentationWindow )
XSetInputFocus( GetXDisplay(), GetShellWindow(), RevertToParent, CurrentTime );
/* For unknown reasons Dtwm does respect the input_hint
* set to False, but not when mapping the window. So
* emulate the correct behaviour and set the focus back
* to where it most probably should have been.
*/
if( (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
mpParent &&
GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii( "Dtwm" )
)
{
XSetInputFocus( GetXDisplay(),
mpParent->GetShellWindow(),
RevertToParent,
CurrentTime );
bSetFocus = false;
}
if( bSetFocus )
{
XSetInputFocus( GetXDisplay(),
GetShellWindow(),
RevertToParent,
CurrentTime );
}
RestackChildren();
mbInShow = sal_False;
m_bSetFocusOnMap = false;
}
break;
case UnmapNotify:
if( pEvent->xunmap.window == GetShellWindow() )
{
bMapped_ = sal_False;
bViewable_ = sal_False;
nRet = sal_True;
if ( mpInputContext != NULL )
mpInputContext->Unmap( this );
CallCallback( SALEVENT_RESIZE, NULL );
}
break;
case ConfigureNotify:
if( pEvent->xconfigure.window == GetShellWindow()
|| pEvent->xconfigure.window == GetWindow() )
nRet = HandleSizeEvent( &pEvent->xconfigure );
break;
case VisibilityNotify:
nVisibility_ = pEvent->xvisibility.state;
nRet = sal_True;
if( bAlwaysOnTop_
&& bMapped_
&& ! GetDisplay()->getWMAdaptor()->isAlwaysOnTopOK()
&& nVisibility_ != VisibilityUnobscured )
maAlwaysOnTopRaiseTimer.Start();
break;
case ReparentNotify:
nRet = HandleReparentEvent( &pEvent->xreparent );
break;
case MappingNotify:
if( MappingPointer != pEvent->xmapping.request )
nRet = CallCallback( SALEVENT_KEYBOARDCHANGED, 0 );
break;
case ColormapNotify:
nRet = HandleColormapEvent( &pEvent->xcolormap );
break;
case PropertyNotify:
{
if( pEvent->xproperty.atom == pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_STATE ) )
nRet = HandleStateEvent( &pEvent->xproperty );
else
nRet = pDisplay_->getWMAdaptor()->handlePropertyNotify( this, &pEvent->xproperty );
break;
}
case ClientMessage:
nRet = HandleClientMessage( &pEvent->xclient );
break;
}
}
else
{
switch( pEvent->type )
{
case FocusIn:
case FocusOut:
if( ( nStyle_ & SAL_FRAME_STYLE_PLUG )
&& ( pEvent->xfocus.window == GetShellWindow()
|| pEvent->xfocus.window == GetForeignParent() )
)
{
nRet = HandleFocusEvent( &pEvent->xfocus );
}
break;
case ConfigureNotify:
if( pEvent->xconfigure.window == GetForeignParent() ||
pEvent->xconfigure.window == GetShellWindow() )
nRet = HandleSizeEvent( &pEvent->xconfigure );
if( pEvent->xconfigure.window == GetStackingWindow() )
nRet = HandleSizeEvent( &pEvent->xconfigure );
RestackChildren();
break;
}
}
return nRet;
}
void X11SalFrame::ResetClipRegion()
{
delete [] m_pClipRectangles;
m_pClipRectangles = NULL;
m_nCurClipRect = m_nMaxClipRect = 0;
const int dest_kind = ShapeBounding;
const int op = ShapeSet;
const int ordering = YSorted;
XWindowAttributes win_attrib;
XRectangle win_size;
XLIB_Window aShapeWindow = mhShellWindow;
XGetWindowAttributes ( GetDisplay()->GetDisplay(),
aShapeWindow,
&win_attrib );
win_size.x = 0;
win_size.y = 0;
win_size.width = win_attrib.width;
win_size.height = win_attrib.height;
XShapeCombineRectangles ( GetDisplay()->GetDisplay(),
aShapeWindow,
dest_kind,
0, 0, // x_off, y_off
&win_size, // list of rectangles
1, // number of rectangles
op, ordering );
}
void X11SalFrame::BeginSetClipRegion( sal_uLong nRects )
{
if( m_pClipRectangles )
delete [] m_pClipRectangles;
if( nRects )
m_pClipRectangles = new XRectangle[nRects];
else
m_pClipRectangles = NULL;
m_nMaxClipRect = static_cast<int>(nRects);
m_nCurClipRect = 0;
}
void X11SalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
{
if( m_pClipRectangles && m_nCurClipRect < m_nMaxClipRect )
{
m_pClipRectangles[m_nCurClipRect].x = nX;
m_pClipRectangles[m_nCurClipRect].y = nY;
m_pClipRectangles[m_nCurClipRect].width = nWidth;
m_pClipRectangles[m_nCurClipRect].height = nHeight;
m_nCurClipRect++;
}
}
void X11SalFrame::EndSetClipRegion()
{
const int dest_kind = ShapeBounding;
const int ordering = YSorted;
const int op = ShapeSet;
XLIB_Window aShapeWindow = mhShellWindow;
XShapeCombineRectangles ( GetDisplay()->GetDisplay(),
aShapeWindow,
dest_kind,
0, 0, // x_off, y_off
m_pClipRectangles,
m_nCurClipRect,
op, ordering );
}