Support for input shape from XShape1.1 (#122425).

svn path=/trunk/KDE/kdebase/workspace/; revision=571712
This commit is contained in:
Luboš Luňák 2006-08-10 13:15:16 +00:00
parent 72d4e4205c
commit 293f093ea1
5 changed files with 621 additions and 389 deletions

View file

@ -28,7 +28,6 @@ License. See the file "COPYING" for the exact licensing terms.
#include "atoms.h"
#include "notifications.h"
#include "rules.h"
#include "scene.h"
#include <X11/extensions/shape.h>
#include <QX11Info>
@ -64,10 +63,12 @@ namespace KWinInternal
is done in manage().
*/
Client::Client( Workspace *ws )
: Toplevel( ws ),
: QObject( NULL ),
client( None ),
wrapper( None ),
frame( None ),
decoration( NULL ),
wspace( ws ),
bridge( new Bridge( this )),
move_faked_activity( false ),
move_resize_grab_window( None ),
@ -142,8 +143,11 @@ Client::Client( Workspace *ws )
cmap = None;
geom = QRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
frame_geometry = QRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
client_size = QSize( 100, 100 );
custom_opacity = false;
rule_opacity_active = 0;; //translucency rules
rule_opacity_inactive = 0; //dito.
// SELI initialize xsizehints??
}
@ -155,8 +159,7 @@ Client::~Client()
{
assert(!moveResizeMode);
assert( client == None );
assert( wrapper == None );
// assert( frameId() == None );
assert( frame == None && wrapper == None );
assert( decoration == NULL );
assert( postpone_geometry_updates == 0 );
assert( !check_active_modal );
@ -177,9 +180,9 @@ void Client::releaseWindow( bool on_shutdown )
{
assert( !deleting );
deleting = true;
finishCompositing();
workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
StackingUpdatesBlocker blocker( workspace());
if (!custom_opacity) setOpacity(false);
if (moveResizeMode)
leaveMoveResize();
finishWindowRules();
@ -189,7 +192,7 @@ void Client::releaseWindow( bool on_shutdown )
hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags)
if( !on_shutdown )
workspace()->clientHidden( this );
XUnmapWindow( display(), frameId()); // destroying decoration would cause ugly visual effect
XUnmapWindow( QX11Info::display(), frameId()); // destroying decoration would cause ugly visual effect
destroyDecoration();
cleanGrouping();
if( !on_shutdown )
@ -201,28 +204,28 @@ void Client::releaseWindow( bool on_shutdown )
desk = 0;
info->setState( 0, info->state()); // reset all state flags
}
XDeleteProperty( display(), client, atoms->kde_net_wm_user_creation_time);
XDeleteProperty( display(), client, atoms->net_frame_extents );
XDeleteProperty( display(), client, atoms->kde_net_wm_frame_strut );
XReparentWindow( display(), client, workspace()->rootWin(), x(), y());
XRemoveFromSaveSet( display(), client );
XSelectInput( display(), client, NoEventMask );
XDeleteProperty( QX11Info::display(), client, atoms->kde_net_wm_user_creation_time);
XDeleteProperty( QX11Info::display(), client, atoms->net_frame_extents );
XDeleteProperty( QX11Info::display(), client, atoms->kde_net_wm_frame_strut );
XReparentWindow( QX11Info::display(), client, workspace()->rootWin(), x(), y());
XRemoveFromSaveSet( QX11Info::display(), client );
XSelectInput( QX11Info::display(), client, NoEventMask );
if( on_shutdown )
{ // map the window, so it can be found after another WM is started
XMapWindow( display(), client );
XMapWindow( QX11Info::display(), client );
// TODO preserve minimized, shaded etc. state?
}
else
{
// Make sure it's not mapped if the app unmapped it (#65279). The app
// may do map+unmap before we initially map the window by calling rawShow() from manage().
XUnmapWindow( display(), client );
XUnmapWindow( QX11Info::display(), client );
}
client = None;
XDestroyWindow( display(), wrapper );
XDestroyWindow( QX11Info::display(), wrapper );
wrapper = None;
XDestroyWindow( display(), frameId());
// frame = None;
XDestroyWindow( QX11Info::display(), frame );
frame = None;
--postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
deleteClient( this, Allowed );
}
@ -233,7 +236,6 @@ void Client::destroyClient()
{
assert( !deleting );
deleting = true;
finishCompositing();
workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
StackingUpdatesBlocker blocker( workspace());
if (moveResizeMode)
@ -247,10 +249,10 @@ void Client::destroyClient()
cleanGrouping();
workspace()->removeClient( this, Allowed );
client = None; // invalidate
XDestroyWindow( display(), wrapper );
XDestroyWindow( QX11Info::display(), wrapper );
wrapper = None;
XDestroyWindow( display(), frameId());
// frame = None;
XDestroyWindow( QX11Info::display(), frame );
frame = None;
--postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
deleteClient( this, Allowed );
}
@ -270,9 +272,12 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
// TODO check decoration's minimum size?
decoration->init();
decoration->widget()->installEventFilter( this );
XReparentWindow( display(), decoration->widget()->winId(), frameId(), 0, 0 );
XReparentWindow( QX11Info::display(), decoration->widget()->winId(), frameId(), 0, 0 );
decoration->widget()->lower();
decoration->borders( border_left, border_right, border_top, border_bottom );
options->onlyDecoTranslucent ?
setDecoHashProperty(border_top, border_right, border_bottom, border_left):
unsetDecoHashProperty();
int save_workarea_diff_x = workarea_diff_x;
int save_workarea_diff_y = workarea_diff_y;
move( calculateGravitation( false ));
@ -280,8 +285,6 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
workarea_diff_x = save_workarea_diff_x;
workarea_diff_y = save_workarea_diff_y;
do_show = true;
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
}
else
destroyDecoration();
@ -308,8 +311,6 @@ void Client::destroyDecoration()
move( grav );
workarea_diff_x = save_workarea_diff_x;
workarea_diff_y = save_workarea_diff_y;
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
}
}
@ -332,6 +333,9 @@ void Client::checkBorderSizes()
border_right != new_right ||
border_top != new_top ||
border_bottom != new_bottom)
options->onlyDecoTranslucent ?
setDecoHashProperty(new_top, new_right, new_bottom, new_left):
unsetDecoHashProperty();
move( calculateGravitation( false ));
plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
checkWorkspacePosition();
@ -339,7 +343,7 @@ void Client::checkBorderSizes()
void Client::detectNoBorder()
{
if( hasShape( window()))
if( Shape::hasShape( window()))
{
noborder = true;
return;
@ -370,6 +374,30 @@ void Client::detectNoBorder()
noborder = true;
}
void Client::detectShapable()
{
if( Shape::hasShape( window()))
return;
switch( windowType())
{
case NET::Desktop :
case NET::Dock :
case NET::TopMenu :
case NET::Splash :
break;
case NET::Unknown :
case NET::Normal :
case NET::Toolbar :
case NET::Menu :
case NET::Dialog :
case NET::Utility :
setShapable(false);
break;
default:
assert( false );
}
}
void Client::updateFrameExtents()
{
NETStrut strut;
@ -427,31 +455,46 @@ void Client::setUserNoBorder( bool set )
void Client::updateShape()
{
if ( shape() )
XShapeCombineShape(display(), frameId(), ShapeBounding,
clientPos().x(), clientPos().y(),
window(), ShapeBounding, ShapeSet);
else
XShapeCombineMask( display(), frameId(), ShapeBounding, 0, 0,
None, ShapeSet);
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
// workaround for #19644 - shaped windows shouldn't have decoration
if( shape() && !noBorder())
{
noborder = true;
updateDecoration( true );
}
if( shape())
{
XShapeCombineShape(QX11Info::display(), frameId(), ShapeBounding,
clientPos().x(), clientPos().y(),
window(), ShapeBounding, ShapeSet);
}
else
{
XShapeCombineMask( QX11Info::display(), frameId(), ShapeBounding, 0, 0,
None, ShapeSet);
}
if( Shape::major() > 1 || Shape::minor() >= 1 ) // has input shape support
{ // there appears to be no way to find out if a window has input
// shape set or not, so always set propagate the input shape
// (it's the same like the bounding shape by default)
XShapeCombineMask( QX11Info::display(), frameId(), ShapeInput, 0, 0,
None, ShapeSet );
XShapeCombineShape( QX11Info::display(), frameId(), ShapeInput,
clientPos().x(), clientPos().y(),
window(), ShapeBounding, ShapeSubtract );
XShapeCombineShape( QX11Info::display(), frameId(), ShapeInput,
clientPos().x(), clientPos().y(),
window(), ShapeInput, ShapeUnion );
}
}
void Client::setMask( const QRegion& reg, int mode )
{
_mask = reg;
if( reg.isEmpty())
XShapeCombineMask( display(), frameId(), ShapeBounding, 0, 0,
XShapeCombineMask( QX11Info::display(), frameId(), ShapeBounding, 0, 0,
None, ShapeSet );
else if( mode == X::Unsorted )
XShapeCombineRegion( display(), frameId(), ShapeBounding, 0, 0,
XShapeCombineRegion( QX11Info::display(), frameId(), ShapeBounding, 0, 0,
reg.handle(), ShapeSet );
else
{
@ -466,12 +509,10 @@ void Client::setMask( const QRegion& reg, int mode )
xrects[ i ].width = rects[ i ].width();
xrects[ i ].height = rects[ i ].height();
}
XShapeCombineRectangles( display(), frameId(), ShapeBounding, 0, 0,
XShapeCombineRectangles( QX11Info::display(), frameId(), ShapeBounding, 0, 0,
xrects, rects.count(), ShapeSet, mode );
delete[] xrects;
}
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
}
QRegion Client::mask() const
@ -481,6 +522,12 @@ QRegion Client::mask() const
return _mask;
}
void Client::setShapable(bool b)
{
long tmp = b?1:0;
XChangeProperty(QX11Info::display(), frameId(), atoms->net_wm_window_shapable, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &tmp, 1L);
}
void Client::hideClient( bool hide )
{
if( hidden == hide )
@ -632,7 +679,7 @@ void Client::animateMinimizeOrUnminimize( bool minimize )
if (area2 != area)
{
pm = animationPixmap( area.width() );
pm2 = QPixmap::grabWindow( rootWindow(), area.x(), area.y(), area.width(), area.height() );
pm2 = QPixmap::grabWindow( QX11Info::appRootWindow(), area.x(), area.y(), area.width(), area.height() );
p.drawPixmap( area.x(), area.y(), pm );
if ( need_to_clear )
{
@ -641,8 +688,8 @@ void Client::animateMinimizeOrUnminimize( bool minimize )
}
area2 = area;
}
XFlush(display());
XSync( display(), false );
XFlush(QX11Info::display());
XSync( QX11Info::display(), false );
diff = t.elapsed();
if (diff > step)
diff = step;
@ -730,16 +777,16 @@ void Client::setShade( ShadeMode mode )
{ // shade_mode == ShadeNormal
// we're about to shade, texx xcompmgr to prepare
long _shade = 1;
XChangeProperty(display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
XChangeProperty(QX11Info::display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
// shade
int h = height();
shade_geometry_change = true;
QSize s( sizeForClientSize( QSize( clientSize())));
s.setHeight( border_top + border_bottom );
XSelectInput( display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
XUnmapWindow( display(), wrapper );
XUnmapWindow( display(), client );
XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask );
XSelectInput( QX11Info::display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
XUnmapWindow( QX11Info::display(), wrapper );
XUnmapWindow( QX11Info::display(), client );
XSelectInput( QX11Info::display(), wrapper, ClientWinMask | SubstructureNotifyMask );
//as we hid the unmap event, xcompmgr didn't recognize the client wid has vanished, so we'll extra inform it
//done xcompmgr workaround
// FRAME repaint( false );
@ -749,7 +796,7 @@ void Client::setShade( ShadeMode mode )
do
{
h -= step;
XResizeWindow( display(), frameId(), s.width(), h );
XResizeWindow( QX11Info::display(), frameId(), s.width(), h );
resizeDecoration( QSize( s.width(), h ));
QApplication::syncX();
} while ( h > s.height() + step );
@ -766,7 +813,7 @@ void Client::setShade( ShadeMode mode )
}
// tell xcompmgr shade's done
_shade = 2;
XChangeProperty(display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
XChangeProperty(QX11Info::display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
}
else
{
@ -779,7 +826,7 @@ void Client::setShade( ShadeMode mode )
do
{
h += step;
XResizeWindow( display(), frameId(), s.width(), h );
XResizeWindow( QX11Info::display(), frameId(), s.width(), h );
resizeDecoration( QSize( s.width(), h ));
// assume a border
// we do not have time to wait for X to send us paint events
@ -792,9 +839,9 @@ void Client::setShade( ShadeMode mode )
plainResize( s );
if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
setActive( true );
XMapWindow( display(), wrapperId());
XMapWindow( display(), window());
XDeleteProperty (display(), client, atoms->net_wm_window_shade);
XMapWindow( QX11Info::display(), wrapperId());
XMapWindow( QX11Info::display(), window());
XDeleteProperty (QX11Info::display(), client, atoms->net_wm_window_shade);
if ( isActive() )
workspace()->requestFocus( this );
}
@ -893,7 +940,7 @@ void Client::setMappingState(int s)
mapping_state = s;
if( mapping_state == WithdrawnState )
{
XDeleteProperty( display(), window(), atoms->wm_state );
XDeleteProperty( QX11Info::display(), window(), atoms->wm_state );
return;
}
assert( s == NormalState || s == IconicState );
@ -901,7 +948,7 @@ void Client::setMappingState(int s)
unsigned long data[2];
data[0] = (unsigned long) s;
data[1] = (unsigned long) None;
XChangeProperty(display(), window(), atoms->wm_state, atoms->wm_state, 32,
XChangeProperty(QX11Info::display(), window(), atoms->wm_state, atoms->wm_state, 32,
PropModeReplace, (unsigned char *)data, 2);
if( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry
@ -916,11 +963,11 @@ void Client::rawShow()
{
if( decoration != NULL )
decoration->widget()->show(); // not really necessary, but let it know the state
XMapWindow( display(), frameId());
XMapWindow( QX11Info::display(), frame );
if( !isShade())
{
XMapWindow( display(), wrapper );
XMapWindow( display(), client );
XMapWindow( QX11Info::display(), wrapper );
XMapWindow( QX11Info::display(), client );
}
}
@ -937,11 +984,11 @@ void Client::rawHide()
// which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify
// will be missed is also very minimal, so I don't think it's needed to grab the server
// here.
XSelectInput( display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
XUnmapWindow( display(), frameId());
XUnmapWindow( display(), wrapper );
XUnmapWindow( display(), client );
XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask );
XSelectInput( QX11Info::display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
XUnmapWindow( QX11Info::display(), frame );
XUnmapWindow( QX11Info::display(), wrapper );
XUnmapWindow( QX11Info::display(), client );
XSelectInput( QX11Info::display(), wrapper, ClientWinMask | SubstructureNotifyMask );
if( decoration != NULL )
decoration->widget()->hide(); // not really necessary, but let it know the state
workspace()->clientHidden( this );
@ -958,14 +1005,14 @@ void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long
ev.xclient.message_type = a;
ev.xclient.format = 32;
ev.xclient.data.l[0] = protocol;
ev.xclient.data.l[1] = xTime();
ev.xclient.data.l[1] = QX11Info::appTime();
ev.xclient.data.l[2] = data1;
ev.xclient.data.l[3] = data2;
ev.xclient.data.l[4] = data3;
mask = 0L;
if (w == rootWindow())
if (w == QX11Info::appRootWindow())
mask = SubstructureRedirectMask; /* magic! */
XSendEvent(display(), w, False, mask, &ev);
XSendEvent(QX11Info::display(), w, False, mask, &ev);
}
/*
@ -1017,7 +1064,7 @@ void Client::killWindow()
Notify::raise( Notify::Delete );
killProcess( false );
// always kill this client at the server
XKillClient(display(), window() );
XKillClient(QX11Info::display(), window() );
destroyClient();
}
@ -1036,7 +1083,7 @@ void Client::pingWindow()
connect( ping_timer, SIGNAL( timeout()), SLOT( pingTimeout()));
ping_timer->setSingleShot( true );
ping_timer->start( options->killPingTimeout );
ping_timestamp = xTime();
ping_timestamp = QX11Info::appTime();
workspace()->sendPingToWindow( window(), ping_timestamp );
}
@ -1203,15 +1250,15 @@ void Client::takeActivity( int flags, bool handled, allowed_t )
#ifndef NDEBUG
static Time previous_activity_timestamp;
static Client* previous_client;
if( previous_activity_timestamp == xTime() && previous_client != this )
if( previous_activity_timestamp == QX11Info::appTime() && previous_client != this )
{
kDebug( 1212 ) << "Repeated use of the same X timestamp for activity" << endl;
kDebug( 1212 ) << kBacktrace() << endl;
}
previous_activity_timestamp = xTime();
previous_activity_timestamp = QX11Info::appTime();
previous_client = this;
#endif
workspace()->sendTakeActivity( this, xTime(), flags );
workspace()->sendTakeActivity( this, QX11Info::appTime(), flags );
}
// performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS
@ -1220,17 +1267,17 @@ void Client::takeFocus( allowed_t )
#ifndef NDEBUG
static Time previous_focus_timestamp;
static Client* previous_client;
if( previous_focus_timestamp == xTime() && previous_client != this )
if( previous_focus_timestamp == QX11Info::appTime() && previous_client != this )
{
kDebug( 1212 ) << "Repeated use of the same X timestamp for focus" << endl;
kDebug( 1212 ) << kBacktrace() << endl;
}
previous_focus_timestamp = xTime();
previous_focus_timestamp = QX11Info::appTime();
previous_client = this;
#endif
if ( rules()->checkAcceptFocus( input ))
{
XSetInputFocus( display(), window(), RevertToPointerRoot, xTime() );
XSetInputFocus( QX11Info::display(), window(), RevertToPointerRoot, QX11Info::appTime() );
}
if ( Ptakefocus )
sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
@ -1283,7 +1330,7 @@ QString Client::readName() const
return KWin::readNameProperty( window(), XA_WM_NAME );
}
KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, Client, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
void Client::setCaption( const QString& _s, bool force )
{
@ -1363,7 +1410,7 @@ QString Client::caption( bool full ) const
void Client::getWMHints()
{
XWMHints *hints = XGetWMHints(display(), window() );
XWMHints *hints = XGetWMHints(QX11Info::display(), window() );
input = true;
window_group = None;
urgency = false;
@ -1452,7 +1499,7 @@ void Client::getWindowProtocols()
Pcontexthelp = 0;
Pping = 0;
if (XGetWMProtocols(display(), window(), &p, &n))
if (XGetWMProtocols(QX11Info::display(), window(), &p, &n))
{
for (i = 0; i < n; i++)
if (p[i] == atoms->wm_delete_window)
@ -1511,7 +1558,7 @@ Window Client::staticWmClientLeader(WId w)
unsigned char *data = 0;
Window result = w;
XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
status = XGetWindowProperty( display(), w, atoms->wm_client_leader, 0, 10000,
status = XGetWindowProperty( QX11Info::display(), w, atoms->wm_client_leader, 0, 10000,
false, XA_WINDOW, &type, &format,
&nitems, &extra, &data );
XSetErrorHandler(oldHandler);
@ -1600,6 +1647,58 @@ bool Client::wantsInput() const
return rules()->checkAcceptFocus( input || Ptakefocus );
}
bool Client::isDesktop() const
{
return windowType() == NET::Desktop;
}
bool Client::isDock() const
{
return windowType() == NET::Dock;
}
bool Client::isTopMenu() const
{
return windowType() == NET::TopMenu;
}
bool Client::isMenu() const
{
return windowType() == NET::Menu && !isTopMenu(); // because of backwards comp.
}
bool Client::isToolbar() const
{
return windowType() == NET::Toolbar;
}
bool Client::isSplash() const
{
return windowType() == NET::Splash;
}
bool Client::isUtility() const
{
return windowType() == NET::Utility;
}
bool Client::isDialog() const
{
return windowType() == NET::Dialog;
}
bool Client::isNormalWindow() const
{
return windowType() == NET::Normal;
}
bool Client::isSpecialWindow() const
{
return isDesktop() || isDock() || isSplash() || isTopMenu()
|| isToolbar(); // TODO
}
NET::WindowType Client::windowType( bool direct, int supported_types ) const
{
NET::WindowType wt = info->windowType( supported_types );
@ -1631,12 +1730,6 @@ NET::WindowType Client::windowType( bool direct, int supported_types ) const
return wt;
}
bool Client::isSpecialWindow() const
{
return isDesktop() || isDock() || isSplash() || isTopMenu()
|| isToolbar(); // TODO
}
/*!
Sets an appropriate cursor shape for the logical mouse position \a m
@ -1682,7 +1775,7 @@ void Client::setCursor( const QCursor& c )
cursor = c;
if( decoration != NULL )
decoration->widget()->setCursor( cursor );
XDefineCursor( display(), frameId(), cursor.handle());
XDefineCursor( QX11Info::display(), frameId(), cursor.handle());
}
Client::Position Client::mousePosition( const QPoint& p ) const
@ -1733,38 +1826,312 @@ void Client::cancelAutoRaise()
autoRaiseTimer = 0;
}
// does the window w need a shape combine mask around it?
bool Client::hasShape( Window w )
void Client::setOpacity(bool translucent, uint opacity)
{
int xws, yws, xbs, ybs;
unsigned int wws, hws, wbs, hbs;
int boundingShaped = 0, clipShaped = 0;
if( !Extensions::shapeAvailable())
return false;
XShapeQueryExtents(display(), w,
&boundingShaped, &xws, &yws, &wws, &hws,
&clipShaped, &xbs, &ybs, &wbs, &hbs);
return boundingShaped != 0;
if (isDesktop())
return; // xcompmgr does not like non solid desktops and the user could set it accidently by mouse scrolling
// qWarning("setting opacity for %d",QX11Info::display());
//rule out activated translulcency with 100% opacity
if (!translucent || opacity == 0xFFFFFFFF)
{
opacity_ = 0xFFFFFFFF;
XDeleteProperty (QX11Info::display(), frameId(), atoms->net_wm_window_opacity);
XDeleteProperty (QX11Info::display(), window(), atoms->net_wm_window_opacity); // ??? frameId() is necessary for visible changes, window() is the winId() that would be set by apps - we set both to be sure the app knows what's currently displayd
}
else{
if(opacity == opacity_)
return;
opacity_ = opacity;
long data = opacity; // 32bit XChangeProperty needs long
XChangeProperty(QX11Info::display(), frameId(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
XChangeProperty(QX11Info::display(), window(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
}
}
void Client::setShadowSize(uint shadowSize)
{
// ignoring all individual settings - if we control a window, we control it's shadow
// TODO somehow handle individual settings for docks (besides custom sizes)
long data = shadowSize;
XChangeProperty(QX11Info::display(), frameId(), atoms->net_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
}
void Client::updateOpacity()
// extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
{
if (!(isNormalWindow() || isDialog() || isUtility() )|| custom_opacity)
return;
if (isActive())
{
if( ruleOpacityActive() )
setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
else
setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
if (isBMP())
// beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
{
ClientList tmpGroupMembers = group()->members();
ClientList activeGroupMembers;
activeGroupMembers.append(this);
tmpGroupMembers.removeAll(this);
ClientList::Iterator it = tmpGroupMembers.begin();
while (it != tmpGroupMembers.end())
// search for next attached and not activated client and repeat if found
{
if ((*it) != this && (*it)->isBMP())
// potential "to activate" client found
{
// qWarning("client found");
if ((*it)->touches(this)) // first test, if the new client touches the just activated one
{
// qWarning("found client touches me");
if( ruleOpacityActive() )
(*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
else
(*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
// qWarning("activated, search restarted (1)");
(*it)->setShadowSize(options->activeWindowShadowSize);
activeGroupMembers.append(*it);
tmpGroupMembers.erase(it);
it = tmpGroupMembers.begin(); // restart, search next client
continue;
}
else
{ // pot. client does not touch c, so we have to search if it touches some other activated client
bool found = false;
for( ClientList::ConstIterator it2 = activeGroupMembers.begin(); it2 != activeGroupMembers.end(); it2++ )
{
if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
{
// qWarning("found client touches other active client");
if( ruleOpacityActive() )
(*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
else
(*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
(*it)->setShadowSize(options->activeWindowShadowSize);
activeGroupMembers.append(*it);
tmpGroupMembers.erase(it);
it = tmpGroupMembers.begin(); // reset potential client search
found = true;
// qWarning("activated, search restarted (2)");
break; // skip this loop
}
}
if (found) continue;
}
}
it++;
}
}
else if (isNormalWindow())
// activate dependent minor windows as well
{
for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
if ((*it)->isDialog() || (*it)->isUtility())
if( (*it)->ruleOpacityActive() )
(*it)->setOpacity((*it)->ruleOpacityActive() < 0xFFFFFFFF, (*it)->ruleOpacityActive());
else
(*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
}
}
else
{
if( ruleOpacityInactive() )
setOpacity(rule_opacity_inactive < 0xFFFFFFFF, rule_opacity_inactive);
else
setOpacity(options->translucentInactiveWindows && !(keepAbove() && options->keepAboveAsActive),
options->inactiveWindowOpacity);
// deactivate dependent minor windows as well
if (isBMP())
// beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
{
ClientList tmpGroupMembers = group()->members();
ClientList inactiveGroupMembers;
inactiveGroupMembers.append(this);
tmpGroupMembers.removeAll(this);
ClientList::Iterator it = tmpGroupMembers.begin();
while ( it != tmpGroupMembers.end() )
// search for next attached and not activated client and repeat if found
{
if ((*it) != this && (*it)->isBMP())
// potential "to activate" client found
{
// qWarning("client found");
if ((*it)->touches(this)) // first test, if the new client touches the just activated one
{
// qWarning("found client touches me");
if( (*it)->ruleOpacityInactive() )
(*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
else
(*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
(*it)->setShadowSize(options->inactiveWindowShadowSize);
// qWarning("deactivated, search restarted (1)");
inactiveGroupMembers.append(*it);
tmpGroupMembers.erase(it);
it = tmpGroupMembers.begin(); // restart, search next client
continue;
}
else // pot. client does not touch c, so we have to search if it touches some other activated client
{
bool found = false;
for( ClientList::ConstIterator it2 = inactiveGroupMembers.begin(); it2 != inactiveGroupMembers.end(); it2++ )
{
if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
{
// qWarning("found client touches other inactive client");
if( (*it)->ruleOpacityInactive() )
(*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
else
(*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
(*it)->setShadowSize(options->inactiveWindowShadowSize);
// qWarning("deactivated, search restarted (2)");
inactiveGroupMembers.append(*it);
tmpGroupMembers.erase(it);
it = tmpGroupMembers.begin(); // reset potential client search
found = true;
break; // skip this loop
}
}
if (found) continue;
}
}
it++;
}
}
else if (isNormalWindow())
{
for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
if ((*it)->isUtility()) //don't deactivate dialogs...
if( (*it)->ruleOpacityInactive() )
(*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
else
(*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
}
}
}
void Client::updateShadowSize()
// extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
{
if (!(isNormalWindow() || isDialog() || isUtility() ))
return;
if (isActive())
setShadowSize(options->activeWindowShadowSize);
else
setShadowSize(options->inactiveWindowShadowSize);
}
double Client::opacity() const
uint Client::ruleOpacityInactive()
{
if( info->opacity() == 0xffffffff )
return 1.0;
return info->opacity() * 1.0 / 0xffffffff;
return rule_opacity_inactive;// != 0 ;
}
void Client::setOpacity( double opacity )
uint Client::ruleOpacityActive()
{
opacity = qBound( 0.0, opacity, 1.0 );
info->setOpacity( static_cast< unsigned long >( opacity * 0xffffffff ));
// we'll react on PropertyNotify
return rule_opacity_active;// != 0;
}
bool Client::getWindowOpacity() //query translucency settings from X, returns true if window opacity is set
{
unsigned char *data = 0;
Atom actual;
int format, result;
unsigned long n, left;
result = XGetWindowProperty(QX11Info::display(), window(), atoms->net_wm_window_opacity, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
if (result == Success && data != None && format == 32 )
{
opacity_ = *reinterpret_cast< long* >( data );
custom_opacity = true;
// setOpacity(opacity_ < 0xFFFFFFFF, opacity_);
XFree ((char*)data);
return true;
}
return false;
}
void Client::setCustomOpacityFlag(bool custom)
{
custom_opacity = custom;
}
uint Client::opacity()
{
return opacity_;
}
void Client::debug( kdbgstream& stream ) const
int Client::opacityPercentage()
{
stream << "\'ID:" << window() << ";WMCLASS:" << resourceClass() << ":" << resourceName() << ";Caption:" << caption() << "\'";
return int(100*((double)opacity_/0xffffffff));
}
bool Client::touches(const Client* c)
// checks if this client borders c, needed to test beep media player window state
{
if (y() == c->y() + c->height()) // this bottom to c
return true;
if (y() + height() == c->y()) // this top to c
return true;
if (x() == c->x() + c->width()) // this right to c
return true;
if (x() + width() == c->x()) // this left to c
return true;
return false;
}
void Client::setDecoHashProperty(uint topHeight, uint rightWidth, uint bottomHeight, uint leftWidth)
{
long data = (topHeight < 255 ? topHeight : 255) << 24 |
(rightWidth < 255 ? rightWidth : 255) << 16 |
(bottomHeight < 255 ? bottomHeight : 255) << 8 |
(leftWidth < 255 ? leftWidth : 255);
XChangeProperty(QX11Info::display(), frameId(), atoms->net_wm_window_decohash, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
}
void Client::unsetDecoHashProperty()
{
XDeleteProperty( QX11Info::display(), frameId(), atoms->net_wm_window_decohash);
}
#ifndef NDEBUG
kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
{
if( cl == NULL )
return stream << "\'NULL_CLIENT\'";
return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
}
kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
{
stream << "LIST:(";
bool first = true;
for( ClientList::ConstIterator it = list.begin();
it != list.end();
++it )
{
if( !first )
stream << ":";
first = false;
stream << *it;
}
stream << ")";
return stream;
}
kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
{
stream << "LIST:(";
bool first = true;
for( ConstClientList::ConstIterator it = list.begin();
it != list.end();
++it )
{
if( !first )
stream << ":";
first = false;
stream << *it;
}
stream << ")";
return stream;
}
#endif
QPixmap * kwin_get_menu_pix_hack()
{

View file

@ -28,7 +28,6 @@ License. See the file "COPYING" for the exact licensing terms.
#include "notifications.h"
#include "geometrytip.h"
#include "rules.h"
#include "effects.h"
#include <QX11Info>
#include <QDesktopWidget>
@ -634,18 +633,18 @@ void Workspace::updateTopMenuGeometry( Client* c )
if( c != NULL )
{
XEvent ev;
ev.xclient.display = display();
ev.xclient.display = QX11Info::display();
ev.xclient.type = ClientMessage;
ev.xclient.window = c->window();
static Atom msg_type_atom = XInternAtom( display(), "_KDE_TOPMENU_MINSIZE", False );
static Atom msg_type_atom = XInternAtom( QX11Info::display(), "_KDE_TOPMENU_MINSIZE", False );
ev.xclient.message_type = msg_type_atom;
ev.xclient.format = 32;
ev.xclient.data.l[0] = xTime();
ev.xclient.data.l[0] = QX11Info::appTime();
ev.xclient.data.l[1] = topmenu_space->width();
ev.xclient.data.l[2] = topmenu_space->height();
ev.xclient.data.l[3] = 0;
ev.xclient.data.l[4] = 0;
XSendEvent( display(), c->window(), False, NoEventMask, &ev );
XSendEvent( QX11Info::display(), c->window(), False, NoEventMask, &ev );
KWin::setStrut( c->window(), 0, 0, topmenu_height, 0 ); // so that kicker etc. know
c->checkWorkspacePosition();
return;
@ -781,25 +780,25 @@ NETExtendedStrut Client::strut() const
{
ext.left_width = str.left;
ext.left_start = 0;
ext.left_end = displayHeight();
ext.left_end = XDisplayHeight( QX11Info::display(), DefaultScreen( QX11Info::display()));
}
if( str.right != 0 )
{
ext.right_width = str.right;
ext.right_start = 0;
ext.right_end = displayHeight();
ext.right_end = XDisplayHeight( QX11Info::display(), DefaultScreen( QX11Info::display()));
}
if( str.top != 0 )
{
ext.top_width = str.top;
ext.top_start = 0;
ext.top_end = displayWidth();
ext.top_end = XDisplayWidth( QX11Info::display(), DefaultScreen( QX11Info::display()));
}
if( str.bottom != 0 )
{
ext.bottom_width = str.bottom;
ext.bottom_start = 0;
ext.bottom_end = displayWidth();
ext.bottom_end = XDisplayWidth( QX11Info::display(), DefaultScreen( QX11Info::display()));
}
}
return ext;
@ -1197,7 +1196,7 @@ QSize Client::sizeForClientSize( const QSize& wsize, Sizemode mode, bool noframe
void Client::getWmNormalHints()
{
long msize;
if (XGetWMNormalHints(display(), window(), &xSizeHint, &msize) == 0 )
if (XGetWMNormalHints(QX11Info::display(), window(), &xSizeHint, &msize) == 0 )
xSizeHint.flags = 0;
// set defined values for the fields, even if they're not in flags
@ -1299,7 +1298,7 @@ void Client::sendSyntheticConfigureNotify()
c.border_width = 0;
c.above = None;
c.override_redirect = 0;
XSendEvent( display(), c.event, true, StructureNotifyMask, (XEvent*)&c );
XSendEvent( QX11Info::display(), c.event, true, StructureNotifyMask, (XEvent*)&c );
}
const QPoint Client::calculateGravitation( bool invert, int gravity ) const
@ -1658,11 +1657,9 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
{
client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
}
if( force == NormalGeometrySet && geom == QRect( x, y, w, h ))
if( force == NormalGeometrySet && frame_geometry == QRect( x, y, w, h ))
return;
// TODO add damage only if not obscured
workspace()->addDamage( this, geometry()); // TODO cache the previous real geometry
geom = QRect( x, y, w, h );
frame_geometry = QRect( x, y, w, h );
updateWorkareaDiffs();
if( postpone_geometry_updates != 0 )
{
@ -1670,24 +1667,21 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
return;
}
resizeDecoration( QSize( w, h ));
XMoveResizeWindow( display(), frameId(), x, y, w, h );
XMoveResizeWindow( QX11Info::display(), frameId(), x, y, w, h );
// resizeDecoration( QSize( w, h ));
if( !isShade())
{
QSize cs = clientSize();
XMoveResizeWindow( display(), wrapperId(), clientPos().x(), clientPos().y(),
XMoveResizeWindow( QX11Info::display(), wrapperId(), clientPos().x(), clientPos().y(),
cs.width(), cs.height());
XMoveResizeWindow( display(), window(), 0, 0, cs.width(), cs.height());
XMoveResizeWindow( QX11Info::display(), window(), 0, 0, cs.width(), cs.height());
}
if( shape())
updateShape();
updateShape();
// SELI TODO won't this be too expensive?
updateWorkareaDiffs();
sendSyntheticConfigureNotify();
updateWindowRules();
checkMaximizeGeometry();
resetWindowPixmap();
workspace()->addDamage( this, geometry());
}
void Client::plainResize( int w, int h, ForceGeometry_t force )
@ -1717,10 +1711,9 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
kDebug() << "forced size fail:" << QSize( w,h ) << ":" << rules()->checkSize( QSize( w, h )) << endl;
kDebug() << kBacktrace() << endl;
}
if( force == NormalGeometrySet && geom.size() == QSize( w, h ))
if( force == NormalGeometrySet && frame_geometry.size() == QSize( w, h ))
return;
workspace()->addDamage( this, geometry()); // TODO cache the previous real geometry
geom.setSize( QSize( w, h ));
frame_geometry.setSize( QSize( w, h ));
updateWorkareaDiffs();
if( postpone_geometry_updates != 0 )
{
@ -1728,23 +1721,20 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
return;
}
resizeDecoration( QSize( w, h ));
XResizeWindow( display(), frameId(), w, h );
XResizeWindow( QX11Info::display(), frameId(), w, h );
// resizeDecoration( QSize( w, h ));
if( !isShade())
{
QSize cs = clientSize();
XMoveResizeWindow( display(), wrapperId(), clientPos().x(), clientPos().y(),
XMoveResizeWindow( QX11Info::display(), wrapperId(), clientPos().x(), clientPos().y(),
cs.width(), cs.height());
XMoveResizeWindow( display(), window(), 0, 0, cs.width(), cs.height());
XMoveResizeWindow( QX11Info::display(), window(), 0, 0, cs.width(), cs.height());
}
if( shape())
updateShape();
updateShape();
updateWorkareaDiffs();
sendSyntheticConfigureNotify();
updateWindowRules();
checkMaximizeGeometry();
resetWindowPixmap();
workspace()->addDamage( this, geometry());
}
/*!
@ -1752,23 +1742,22 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
*/
void Client::move( int x, int y, ForceGeometry_t force )
{
if( force == NormalGeometrySet && geom.topLeft() == QPoint( x, y ))
if( force == NormalGeometrySet && frame_geometry.topLeft() == QPoint( x, y ))
return;
workspace()->addDamage( this, geometry()); // TODO cache the previous real geometry
geom.moveTopLeft( QPoint( x, y ));
frame_geometry.moveTopLeft( QPoint( x, y ));
updateWorkareaDiffs();
if( postpone_geometry_updates != 0 )
{
pending_geometry_update = true;
return;
}
XMoveWindow( display(), frameId(), x, y );
XMoveWindow( QX11Info::display(), frameId(), x, y );
sendSyntheticConfigureNotify();
updateWindowRules();
checkMaximizeGeometry();
workspace()->addDamage( this, geometry());
}
void Client::postponeGeometryUpdates( bool postpone )
{
if( postpone )
@ -2231,18 +2220,18 @@ bool Client::startMoveResize()
// (http://lists.kde.org/?t=107302193400001&r=1&w=2)
XSetWindowAttributes attrs;
QRect r = workspace()->clientArea( FullArea, this );
move_resize_grab_window = XCreateWindow( display(), workspace()->rootWin(), r.x(), r.y(),
move_resize_grab_window = XCreateWindow( QX11Info::display(), workspace()->rootWin(), r.x(), r.y(),
r.width(), r.height(), 0, CopyFromParent, InputOnly, CopyFromParent, 0, &attrs );
XMapRaised( display(), move_resize_grab_window );
if( XGrabPointer( display(), move_resize_grab_window, False,
XMapRaised( QX11Info::display(), move_resize_grab_window );
if( XGrabPointer( QX11Info::display(), move_resize_grab_window, False,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask,
GrabModeAsync, GrabModeAsync, None, cursor.handle(), xTime() ) == Success )
GrabModeAsync, GrabModeAsync, None, cursor.handle(), QX11Info::appTime() ) == Success )
has_grab = true;
if( XGrabKeyboard( display(), frameId(), False, GrabModeAsync, GrabModeAsync, xTime() ) == Success )
if( XGrabKeyboard( QX11Info::display(), frameId(), False, GrabModeAsync, GrabModeAsync, QX11Info::appTime() ) == Success )
has_grab = true;
if( !has_grab ) // at least one grab is necessary in order to be able to finish move/resize
{
XDestroyWindow( display(), move_resize_grab_window );
XDestroyWindow( QX11Info::display(), move_resize_grab_window );
move_resize_grab_window = None;
return false;
}
@ -2252,6 +2241,13 @@ bool Client::startMoveResize()
workspace()->setClientIsMoving(this);
initialMoveResizeGeom = moveResizeGeom = geometry();
checkUnrestrictedMoveResize();
// rule out non opaque windows from useless translucency settings, maybe resizes?
if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
setShadowSize(0);
if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque){
savedOpacity_ = opacity_;
setOpacity(options->translucentMovingWindows, options->movingWindowOpacity);
}
if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
|| ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
{
@ -2266,8 +2262,6 @@ bool Client::startMoveResize()
// not needed anymore? kapp->installEventFilter( eater );
}
Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart );
if( effects )
effects->windowUserMovedResized( this, true, false );
return true;
}
@ -2281,12 +2275,15 @@ void Client::finishMoveResize( bool cancel )
checkMaximizeGeometry();
// FRAME update();
Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd );
if( effects )
effects->windowUserMovedResized( this, false, true );
}
void Client::leaveMoveResize()
{
// rule out non opaque windows from useless translucency settings, maybe resizes?
if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque)
setOpacity(true, savedOpacity_);
if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
updateShadowSize();
clearbound();
if (geometryTip)
{
@ -2297,9 +2294,9 @@ void Client::leaveMoveResize()
if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
|| ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
ungrabXServer();
XUngrabKeyboard( display(), xTime() );
XUngrabPointer( display(), xTime() );
XDestroyWindow( display(), move_resize_grab_window );
XUngrabKeyboard( QX11Info::display(), QX11Info::appTime() );
XUngrabPointer( QX11Info::display(), QX11Info::appTime() );
XDestroyWindow( QX11Info::display(), move_resize_grab_window );
move_resize_grab_window = None;
workspace()->setClientIsMoving(0);
if( move_faked_activity )
@ -2545,9 +2542,8 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
} // so the geometry tip will be painted above the outline
}
if ( isMove() )
workspace()->clientMoved(globalPos, xTime());
if( effects )
effects->windowUserMovedResized( this, false, false );
workspace()->clientMoved(globalPos, QX11Info::appTime());
}
} // namespace

View file

@ -38,29 +38,22 @@ bool Client::manage( Window w, bool isMapped )
{
StackingUpdatesBlocker stacking_blocker( workspace());
grabXServer();
XWindowAttributes attr;
if( !XGetWindowAttributes(display(), w, &attr))
{
ungrabXServer();
if( !XGetWindowAttributes(QX11Info::display(), w, &attr))
return false;
}
grabXServer();
// from this place on, manage() mustn't return false
postpone_geometry_updates = 1;
pending_geometry_update = true; // force update when finishing with geometry changes
embedClient( w, attr );
vis = attr.visual;
setupCompositing();
// SELI order all these things in some sane manner
bool init_minimize = false;
XWMHints * hints = XGetWMHints(display(), w );
XWMHints * hints = XGetWMHints(QX11Info::display(), w );
if (hints && (hints->flags & StateHint) && hints->initial_state == IconicState)
init_minimize = true;
if (hints)
@ -84,15 +77,14 @@ bool Client::manage( Window w, bool isMapped )
NET::WM2UserTime |
NET::WM2StartupId |
NET::WM2ExtendedStrut |
NET::WM2Opacity |
0;
info = new WinInfo( this, display(), client, rootWindow(), properties, 2 );
info = new WinInfo( this, QX11Info::display(), client, QX11Info::appRootWindow(), properties, 2 );
cmap = attr.colormap;
XClassHint classHint;
if ( XGetClassHint( display(), client, &classHint ) )
if ( XGetClassHint( QX11Info::display(), client, &classHint ) )
{
// Qt3.2 and older had this all lowercase, Qt3.3 capitalized resource class
// force lowercase, so that workarounds listing resource classes still work
@ -114,6 +106,7 @@ bool Client::manage( Window w, bool isMapped )
setCaption( cap_normal, true );
detectNoBorder();
detectShapable();
fetchIconicName();
getWMHints(); // needs to be done before readTransient() because of reading the group
modal = ( info->state() & NET::Modal ) != 0; // needs to be valid before handling groups
@ -150,6 +143,8 @@ bool Client::manage( Window w, bool isMapped )
if( rules()->checkNoBorder( false, !isMapped ))
setUserNoBorder( true );
checkAndSetInitialRuledOpacity();
// initial desktop placement
if ( session )
{
@ -321,10 +316,9 @@ bool Client::manage( Window w, bool isMapped )
if(( !isSpecialWindow() || isToolbar()) && isMovable())
keepInArea( area, partial_keep_in_area );
if( Extensions::shapeAvailable())
XShapeSelectInput( display(), window(), ShapeNotifyMask );
if ( (is_shape = hasShape( window())) )
updateShape();
XShapeSelectInput( QX11Info::display(), window(), ShapeNotifyMask );
is_shape = Shape::hasShape( window());
updateShape();
//CT extra check for stupid jdk 1.3.1. But should make sense in general
// if client has initial state set to Iconic and is transient with a parent
@ -437,7 +431,7 @@ bool Client::manage( Window w, bool isMapped )
// this should avoid flicker, because real restacking is done
// only after manage() finishes because of blocking, but the window is shown sooner
XLowerWindow( display(), frameId());
XLowerWindow( QX11Info::display(), frameId());
if( session && session->stackingOrder != -1 )
{
sm_stacking_order = session->stackingOrder;
@ -509,9 +503,9 @@ bool Client::manage( Window w, bool isMapped )
if( user_time == CurrentTime || user_time == -1U ) // no known user time, set something old
{
user_time = xTime() - 1000000;
user_time = QX11Info::appTime() - 1000000;
if( user_time == CurrentTime || user_time == -1U ) // let's be paranoid
user_time = xTime() - 1000000 + 10;
user_time = QX11Info::appTime() - 1000000 + 10;
}
updateWorkareaDiffs();
@ -519,7 +513,7 @@ bool Client::manage( Window w, bool isMapped )
// sendSyntheticConfigureNotify(); done when setting mapping state
delete session;
ungrabXServer();
client_rules.discardTemporary();
@ -537,35 +531,34 @@ bool Client::manage( Window w, bool isMapped )
void Client::embedClient( Window w, const XWindowAttributes &attr )
{
assert( client == None );
assert( frameId() == None );
assert( frame == None );
assert( wrapper == None );
client = w;
// we don't want the window to be destroyed when we are destroyed
XAddToSaveSet( display(), client );
XSelectInput( display(), client, NoEventMask );
XUnmapWindow( display(), client );
XAddToSaveSet( QX11Info::display(), client );
XSelectInput( QX11Info::display(), client, NoEventMask );
XUnmapWindow( QX11Info::display(), client );
XWindowChanges wc; // set the border width to 0
wc.border_width = 0; // TODO possibly save this, and also use it for initial configuring of the window
XConfigureWindow( display(), client, CWBorderWidth, &wc );
XConfigureWindow( QX11Info::display(), client, CWBorderWidth, &wc );
XSetWindowAttributes swa;
swa.colormap = attr.colormap;
swa.background_pixmap = None;
swa.border_pixel = 0;
Window frame = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0,
frame = XCreateWindow( QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0,
attr.depth, InputOutput, attr.visual,
CWColormap | CWBackPixmap | CWBorderPixel, &swa );
setHandle( frame );
wrapper = XCreateWindow( display(), frame, 0, 0, 1, 1, 0,
wrapper = XCreateWindow( QX11Info::display(), frame, 0, 0, 1, 1, 0,
attr.depth, InputOutput, attr.visual,
CWColormap | CWBackPixmap | CWBorderPixel, &swa );
XDefineCursor( display(), frame, QCursor( Qt::ArrowCursor ).handle());
XDefineCursor( QX11Info::display(), frame, QCursor( Qt::ArrowCursor ).handle());
// some apps are stupid and don't define their own cursor - set the arrow one for them
XDefineCursor( display(), wrapper, QCursor( Qt::ArrowCursor ).handle());
XReparentWindow( display(), client, wrapper, 0, 0 );
XSelectInput( display(), frame,
XDefineCursor( QX11Info::display(), wrapper, QCursor( Qt::ArrowCursor ).handle());
XReparentWindow( QX11Info::display(), client, wrapper, 0, 0 );
XSelectInput( QX11Info::display(), frame,
KeyPressMask | KeyReleaseMask |
ButtonPressMask | ButtonReleaseMask |
KeymapStateMask |
@ -577,8 +570,8 @@ void Client::embedClient( Window w, const XWindowAttributes &attr )
PropertyChangeMask |
StructureNotifyMask | SubstructureRedirectMask |
VisibilityChangeMask );
XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask );
XSelectInput( display(), client,
XSelectInput( QX11Info::display(), wrapper, ClientWinMask | SubstructureNotifyMask );
XSelectInput( QX11Info::display(), client,
FocusChangeMask |
PropertyChangeMask |
ColormapChangeMask |

130
utils.cpp
View file

@ -30,7 +30,6 @@ License. See the file "COPYING" for the exact licensing terms.
#include <X11/extensions/shape.h>
#include <X11/Xatom.h>
#include <QX11Info>
#include <stdio.h>
#include "atoms.h"
@ -43,54 +42,41 @@ namespace KWinInternal
#ifndef KCMRULES
bool Extensions::has_shape = 0;
int Extensions::shape_event_base = 0;
bool Extensions::has_damage = 0;
int Extensions::damage_event_base = 0;
bool Extensions::has_composite = 0;
bool Extensions::has_fixes = 0;
// used to store the return values of
// XShapeQueryExtension.
// Necessary since shaped window are an extension to X
int Shape::kwin_shape_version = 0;
int Shape::kwin_shape_event = 0;
void Extensions::init()
// does the window w need a shape combine mask around it?
bool Shape::hasShape( WId w)
{
int xws, yws, xbs, ybs;
unsigned int wws, hws, wbs, hbs;
int boundingShaped = 0, clipShaped = 0;
if (!available())
return false;
XShapeQueryExtents(QX11Info::display(), w,
&boundingShaped, &xws, &yws, &wws, &hws,
&clipShaped, &xbs, &ybs, &wbs, &hbs);
return boundingShaped != 0;
}
int Shape::shapeEvent()
{
return kwin_shape_event;
}
void Shape::init()
{
kwin_shape_version = 0;
int dummy;
has_shape = XShapeQueryExtension( display(), &shape_event_base, &dummy);
#ifdef HAVE_XDAMAGE
has_damage = XDamageQueryExtension( display(), &damage_event_base, &dummy );
#else
has_damage = false;
#endif
#ifdef HAVE_XCOMPOSITE
has_composite = XCompositeQueryExtension( display(), &dummy, &dummy );
if( has_composite )
{
int major = 0;
int minor = 2;
XCompositeQueryVersion( display(), &major, &minor );
if( major == 0 && minor < 2 )
has_composite = false;
}
#else
has_composite = false;
#endif
#ifdef HAVE_XFIXES
has_fixes = XFixesQueryExtension( display(), &dummy, &dummy );
#else
has_fixes = false;
#endif
}
int Extensions::shapeNotifyEvent()
{
return shape_event_base + ShapeNotify;
}
int Extensions::damageNotifyEvent()
{
#ifdef HAVE_XDAMAGE
return damage_event_base + XDamageNotify;
#else
return 0;
#endif
if( !XShapeQueryExtension( QX11Info::display(), &kwin_shape_event, &dummy ))
return;
int major, minor;
if( !XShapeQueryVersion( QX11Info::display(), &major, &minor ))
return;
kwin_shape_version = major * 16 + minor;
}
void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move,
@ -101,7 +87,7 @@ void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move,
unsigned long length, after;
unsigned char* data;
MwmHints* hints = 0;
if ( XGetWindowProperty( display(), w, atoms->motif_wm_hints, 0, 5,
if ( XGetWindowProperty( QX11Info::display(), w, atoms->motif_wm_hints, 0, 5,
false, atoms->motif_wm_hints, &type, &format,
&length, &after, &data ) == Success )
{
@ -154,10 +140,10 @@ KWinSelectionOwner::KWinSelectionOwner( int screen_P )
Atom KWinSelectionOwner::make_selection_atom( int screen_P )
{
if( screen_P < 0 )
screen_P = DefaultScreen( display());
screen_P = DefaultScreen( QX11Info::display());
char tmp[ 30 ];
sprintf( tmp, "WM_S%d", screen_P );
return XInternAtom( display(), tmp, False );
return XInternAtom( QX11Info::display(), tmp, False );
}
void KWinSelectionOwner::getAtoms()
@ -168,7 +154,7 @@ void KWinSelectionOwner::getAtoms()
Atom atoms[ 1 ];
const char* const names[] =
{ "VERSION" };
XInternAtoms( display(), const_cast< char** >( names ), 1, False, atoms );
XInternAtoms( QX11Info::display(), const_cast< char** >( names ), 1, False, atoms );
xa_version = atoms[ 0 ];
}
}
@ -178,7 +164,7 @@ void KWinSelectionOwner::replyTargets( Atom property_P, Window requestor_P )
KSelectionOwner::replyTargets( property_P, requestor_P );
Atom atoms[ 1 ] = { xa_version };
// PropModeAppend !
XChangeProperty( display(), requestor_P, property_P, XA_ATOM, 32, PropModeAppend,
XChangeProperty( QX11Info::display(), requestor_P, property_P, XA_ATOM, 32, PropModeAppend,
reinterpret_cast< unsigned char* >( atoms ), 1 );
}
@ -187,7 +173,7 @@ bool KWinSelectionOwner::genericReply( Atom target_P, Atom property_P, Window re
if( target_P == xa_version )
{
long version[] = { 2, 0 };
XChangeProperty( display(), requestor_P, property_P, XA_INTEGER, 32,
XChangeProperty( QX11Info::display(), requestor_P, property_P, XA_INTEGER, 32,
PropModeReplace, reinterpret_cast< unsigned char* >( &version ), 2 );
}
else
@ -207,7 +193,7 @@ QByteArray getStringProperty(WId w, Atom prop, char separator)
unsigned char *data = 0;
QByteArray result = "";
KXErrorHandler handler; // ignore errors
status = XGetWindowProperty( display(), w, prop, 0, 10000,
status = XGetWindowProperty( QX11Info::display(), w, prop, 0, 10000,
false, XA_STRING, &type, &format,
&nitems, &extra, &data );
if ( status == Success)
@ -262,8 +248,8 @@ static Bool update_x_time_predicate( Display*, XEvent* event, XPointer )
}
/*
Updates xTime(). This used to simply fetch current timestamp from the server,
but that can cause xTime() to be newer than timestamp of events that are
Updates QX11Info::appTime(). This used to simply fetch current timestamp from the server,
but that can cause QX11Info::appTime() to be newer than timestamp of events that are
still in our events queue, thus e.g. making XSetInputFocus() caused by such
event to be ignored. Therefore events queue is searched for first
event with timestamp, and extra PropertyNotify is generated in order to make
@ -275,20 +261,20 @@ void updateXTime()
if ( !w )
w = new QWidget;
long data = 1;
XChangeProperty(display(), w->winId(), atoms->kwin_running, atoms->kwin_running, 32,
XChangeProperty(QX11Info::display(), w->winId(), atoms->kwin_running, atoms->kwin_running, 32,
PropModeAppend, (unsigned char*) &data, 1);
next_x_time = CurrentTime;
XEvent dummy;
XCheckIfEvent( display(), &dummy, update_x_time_predicate, NULL );
XCheckIfEvent( QX11Info::display(), &dummy, update_x_time_predicate, NULL );
if( next_x_time == CurrentTime )
{
XSync( display(), False );
XCheckIfEvent( display(), &dummy, update_x_time_predicate, NULL );
XSync( QX11Info::display(), False );
XCheckIfEvent( QX11Info::display(), &dummy, update_x_time_predicate, NULL );
}
assert( next_x_time != CurrentTime );
QX11Info::setAppTime( next_x_time );
XEvent ev; // remove the PropertyNotify event from the events queue
XWindowEvent( display(), w->winId(), PropertyChangeMask, &ev );
XWindowEvent( QX11Info::display(), w->winId(), PropertyChangeMask, &ev );
}
static int server_grab_count = 0;
@ -296,7 +282,7 @@ static int server_grab_count = 0;
void grabXServer()
{
if( ++server_grab_count == 1 )
XGrabServer( display());
XGrabServer( QX11Info::display());
}
void ungrabXServer()
@ -304,8 +290,8 @@ void ungrabXServer()
assert( server_grab_count > 0 );
if( --server_grab_count == 0 )
{
XUngrabServer( display());
XFlush( display());
XUngrabServer( QX11Info::display());
XFlush( QX11Info::display());
Notify::sendPendingEvents();
}
}
@ -315,20 +301,6 @@ bool grabbedXServer()
return server_grab_count > 0;
}
kdbgstream& operator<<( kdbgstream& stream, RegionDebug r )
{
if( r.rr == None )
return stream << "EMPTY";
int num;
XRectangle* rects = XFixesFetchRegion( display(), r.rr, &num );
if( rects == NULL || num == 0 )
return stream << "EMPTY";
for( int i = 0;
i < num;
++i )
stream << "[" << rects[ i ].x << "+" << rects[ i ].y << " " << rects[ i ].width << "x" << rects[ i ].height << "]";
return stream;
}
#endif
bool isLocalMachine( const QByteArray& host )
@ -360,7 +332,7 @@ ShortcutDialog::ShortcutDialog( const KShortcut& cut )
// make it a popup, so that it has the grab
XSetWindowAttributes attrs;
attrs.override_redirect = True;
XChangeWindowAttributes( display(), winId(), CWOverrideRedirect, &attrs );
XChangeWindowAttributes( QX11Info::display(), winId(), CWOverrideRedirect, &attrs );
setWindowFlags( Qt::Popup );
}
@ -395,6 +367,8 @@ void ShortcutDialog::accept()
KShortcutDialog::accept();
}
#endif
} // namespace
#ifndef KCMRULES

128
utils.h
View file

@ -12,43 +12,15 @@ License. See the file "COPYING" for the exact licensing terms.
#ifndef KWIN_UTILS_H
#define KWIN_UTILS_H
#include <config.h>
#include <X11/Xlib.h>
#ifdef HAVE_XCOMPOSITE
#include <X11/extensions/Xcomposite.h>
#endif
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
#include <fixx11h.h>
#include <QWidget>
#include <kmanagerselection.h>
#include <netwm_def.h>
#include <kshortcutdialog.h>
#include <limits.h>
#include <QX11Info>
namespace KWinInternal
{
#ifndef HAVE_XDAMAGE
typedef long Damage;
struct XDamageNotifyEvent
{
};
#endif
#ifndef HAVE_XFIXES
struct XserverRegion
{
};
#endif
const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
| NET::ToolbarMask | NET::MenuMask | NET::DialogMask /*| NET::OverrideMask*/ | NET::TopMenuMask
| NET::UtilityMask | NET::SplashMask;
@ -66,18 +38,12 @@ const long ClientWinMask = KeyPressMask | KeyReleaseMask |
const QPoint invalidPoint( INT_MIN, INT_MIN );
class Toplevel;
class Client;
class Unmanaged;
class Group;
class Options;
typedef QList< Toplevel* > ToplevelList;
typedef QList< const Toplevel* > ConstToplevelList;
typedef QList< Client* > ClientList;
typedef QList< const Client* > ConstClientList;
typedef QList< Unmanaged* > UnmanagedList;
typedef QList< const Unmanaged* > ConstUnmanagedList;
typedef QList< Group* > GroupList;
typedef QList< const Group* > ConstGroupList;
@ -120,20 +86,6 @@ enum allowed_t { Allowed };
// some enums to have more readable code, instead of using bools
enum ForceGeometry_t { NormalGeometrySet, ForceGeometrySet };
struct RegionDebug
{
RegionDebug( XserverRegion r ) : rr( r ) {}
XserverRegion rr;
};
#ifdef NDEBUG
inline
kndbgstream& operator<<( kndbgstream& stream, RegionDebug ) { return stream; }
#else
kdbgstream& operator<<( kdbgstream& stream, RegionDebug r );
#endif
// Areas, mostly related to Xinerama
enum clientAreaOption
{
@ -156,23 +108,18 @@ enum ShadeMode
ShadeActivated // "shaded", but visible due to alt+tab to the window
};
class Extensions
class Shape
{
public:
static bool available() { return kwin_shape_version > 0; }
static int major() { return kwin_shape_version / 16; }
static int minor() { return kwin_shape_version % 16; }
static bool hasShape( WId w);
static int shapeEvent();
static void init();
static bool shapeAvailable() { return has_shape; }
static int shapeNotifyEvent();
static bool damageAvailable() { return has_damage; }
static int damageNotifyEvent();
static bool compositeAvailable() { return has_composite; }
static bool fixesAvailable() { return has_fixes; }
private:
static bool has_shape;
static int shape_event_base;
static bool has_damage;
static int damage_event_base;
static bool has_composite;
static bool has_fixes;
static int kwin_shape_version; // as 16*major+minor
static int kwin_shape_event;
};
class Motif
@ -244,68 +191,34 @@ void grabXServer();
void ungrabXServer();
bool grabbedXServer();
inline
Display* display()
{
return QX11Info::display();
}
inline
Window rootWindow()
{
return QX11Info::appRootWindow();
}
inline
Window xTime()
{
return QX11Info::appTime();
}
inline
int displayWidth()
{
return XDisplayWidth( display(), DefaultScreen( display()));
}
inline
int displayHeight()
{
return XDisplayHeight( display(), DefaultScreen( display()));
}
class Scene;
extern Scene* scene;
inline bool compositing() { return scene != NULL; }
// the docs say it's UrgencyHint, but it's often #defined as XUrgencyHint
#ifndef UrgencyHint
#define UrgencyHint XUrgencyHint
#endif
// for STL-like algo's
#define KWIN_CHECK_PREDICATE( name, cls, check ) \
#define KWIN_CHECK_PREDICATE( name, check ) \
struct name \
{ \
inline bool operator()( const cls* cl ) { return check; }; \
inline bool operator()( const Client* cl ) { return check; }; \
}
#define KWIN_COMPARE_PREDICATE( name, cls, type, check ) \
#define KWIN_COMPARE_PREDICATE( name, type, check ) \
struct name \
{ \
typedef type type_helper; /* in order to work also with type being 'const Client*' etc. */ \
inline name( const type_helper& compare_value ) : value( compare_value ) {}; \
inline bool operator()( const cls* cl ) { return check; }; \
inline bool operator()( const Client* cl ) { return check; }; \
const type_helper& value; \
}
#define KWIN_PROCEDURE( name, cls, action ) \
#define KWIN_PROCEDURE( name, action ) \
struct name \
{ \
inline void operator()( cls* cl ) { action; }; \
inline void operator()( Client* cl ) { action; }; \
}
KWIN_CHECK_PREDICATE( TruePredicate, Client, cl == cl /*true, avoid warning about 'cl' */ );
KWIN_CHECK_PREDICATE( TruePredicate, cl == cl /*true, avoid warning about 'cl' */ );
template< typename T >
Client* findClientInList( const ClientList& list, T predicate )
@ -318,17 +231,6 @@ Client* findClientInList( const ClientList& list, T predicate )
return NULL;
}
template< typename T >
Unmanaged* findUnmanagedInList( const UnmanagedList& list, T predicate )
{
for ( UnmanagedList::ConstIterator it = list.begin(); it != list.end(); ++it)
{
if ( predicate( const_cast< const Unmanaged* >( *it)))
return *it;
}
return NULL;
}
inline
int timestampCompare( Time time1, Time time2 ) // like strcmp()
{