Support for _NET_WM_SYNC_REQUEST, based on a patch
by Rayiner Hashem <gtg990h@mail.gatech.edu>. svn path=/trunk/KDE/kdebase/workspace/; revision=679986
This commit is contained in:
parent
8eac2caca5
commit
162d6ac7c9
12 changed files with 248 additions and 14 deletions
|
@ -92,6 +92,12 @@ Atoms::Atoms()
|
|||
atoms[n] = &kde_net_wm_frame_strut;
|
||||
names[n++] = (char*) "_KDE_NET_WM_FRAME_STRUT";
|
||||
|
||||
atoms[n] = &net_wm_sync_request_counter;
|
||||
names[n++] = (char*) "_NET_WM_SYNC_REQUEST_COUNTER";
|
||||
|
||||
atoms[n] = &net_wm_sync_request;
|
||||
names[n++] = (char*) "_NET_WM_SYNC_REQUEST";
|
||||
|
||||
assert( n <= max );
|
||||
|
||||
XInternAtoms( display(), names, n, false, atoms_return );
|
||||
|
|
2
atoms.h
2
atoms.h
|
@ -47,6 +47,8 @@ class Atoms
|
|||
Atom xdnd_position;
|
||||
Atom net_frame_extents;
|
||||
Atom kde_net_wm_frame_strut;
|
||||
Atom net_wm_sync_request_counter;
|
||||
Atom net_wm_sync_request;
|
||||
};
|
||||
|
||||
|
||||
|
|
87
client.cpp
87
client.cpp
|
@ -36,6 +36,10 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#include <X11/extensions/shape.h>
|
||||
#include <QX11Info>
|
||||
|
||||
#ifdef HAVE_XSYNC
|
||||
#include <X11/extensions/sync.h>
|
||||
#endif
|
||||
|
||||
// put all externs before the namespace statement to allow the linker
|
||||
// to resolve them properly
|
||||
|
||||
|
@ -91,6 +95,12 @@ Client::Client( Workspace *ws )
|
|||
block_geometry_updates( 0 ),
|
||||
pending_geometry_update( PendingGeometryNone ),
|
||||
shade_geometry_change( false ),
|
||||
#ifdef HAVE_XSYNC
|
||||
sync_counter( None ),
|
||||
sync_alarm( None ),
|
||||
#endif
|
||||
sync_timeout( NULL ),
|
||||
sync_resize_pending( false ),
|
||||
border_left( 0 ),
|
||||
border_right( 0 ),
|
||||
border_top( 0 ),
|
||||
|
@ -147,6 +157,9 @@ Client::Client( Workspace *ws )
|
|||
|
||||
geom = QRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
|
||||
client_size = QSize( 100, 100 );
|
||||
#if defined(HAVE_XSYNC) || defined(HAVE_XDAMAGE)
|
||||
ready_for_painting = false; // wait for first damage or sync reply
|
||||
#endif
|
||||
|
||||
// SELI initialize xsizehints??
|
||||
}
|
||||
|
@ -156,6 +169,10 @@ Client::Client( Workspace *ws )
|
|||
*/
|
||||
Client::~Client()
|
||||
{
|
||||
#ifdef HAVE_XSYNC
|
||||
if( sync_alarm != None )
|
||||
XSyncDestroyAlarm( display(), sync_alarm );
|
||||
#endif
|
||||
assert(!moveResizeMode);
|
||||
assert( client == None );
|
||||
assert( wrapper == None );
|
||||
|
@ -1431,6 +1448,76 @@ void Client::getWindowProtocols()
|
|||
}
|
||||
}
|
||||
|
||||
void Client::getSyncCounter()
|
||||
{
|
||||
#ifdef HAVE_XSYNC
|
||||
if( !Extensions::syncAvailable())
|
||||
return;
|
||||
|
||||
Atom retType;
|
||||
unsigned long nItemRet;
|
||||
unsigned long byteRet;
|
||||
int formatRet;
|
||||
unsigned char* propRet;
|
||||
int ret = XGetWindowProperty( display(), window(), atoms->net_wm_sync_request_counter,
|
||||
0, 1, false, XA_CARDINAL, &retType, &formatRet, &nItemRet, &byteRet, &propRet );
|
||||
|
||||
if( ret == Success && formatRet == 32 )
|
||||
{
|
||||
sync_counter = *(long*)propRet;
|
||||
XSyncIntToValue( &sync_counter_value, 0 );
|
||||
XSyncValue zero;
|
||||
XSyncIntToValue( &zero, 0 );
|
||||
XSyncSetCounter( display(), sync_counter, zero );
|
||||
if( sync_alarm == None )
|
||||
{
|
||||
XSyncAlarmAttributes attrs;
|
||||
attrs.trigger.counter = sync_counter;
|
||||
attrs.trigger.value_type = XSyncRelative;
|
||||
attrs.trigger.test_type = XSyncPositiveTransition;
|
||||
XSyncIntToValue( &attrs.trigger.wait_value, 1 );
|
||||
XSyncIntToValue( &attrs.delta, 1 );
|
||||
sync_alarm = XSyncCreateAlarm( display(),
|
||||
XSyncCACounter | XSyncCAValueType | XSyncCATestType | XSyncCADelta | XSyncCAValue,
|
||||
&attrs );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// send the client a _NET_SYNC_REQUEST
|
||||
void Client::sendSyncRequest()
|
||||
{
|
||||
#ifdef HAVE_XSYNC
|
||||
if( sync_counter == None )
|
||||
return;
|
||||
|
||||
// we increment before the notify so that after the notify
|
||||
// syncCounterSerial will equal the value we are expecting
|
||||
// in the acknowledgement
|
||||
int overflow;
|
||||
XSyncValue one;
|
||||
XSyncIntToValue( &one, 1 );
|
||||
#undef XSyncValueAdd // it causes a warning :-/
|
||||
XSyncValueAdd( &sync_counter_value, sync_counter_value, one, &overflow );
|
||||
|
||||
// send the message to client
|
||||
XEvent ev;
|
||||
ev.xclient.type = ClientMessage;
|
||||
ev.xclient.window = window();
|
||||
ev.xclient.format = 32;
|
||||
ev.xclient.message_type = atoms->wm_protocols;
|
||||
ev.xclient.data.l[ 0 ] = atoms->net_wm_sync_request;
|
||||
ev.xclient.data.l[ 1 ] = xTime();
|
||||
ev.xclient.data.l[ 2 ] = XSyncValueLow32( sync_counter_value );
|
||||
ev.xclient.data.l[ 3 ] = XSyncValueHigh32( sync_counter_value );
|
||||
ev.xclient.data.l[ 4 ] = 0;
|
||||
XSendEvent( display(), window(), False, NoEventMask, &ev );
|
||||
XSync(display(),false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool Client::wantsTabFocus() const
|
||||
{
|
||||
return ( isNormalWindow() || isDialog()) && wantsInput();
|
||||
|
|
23
client.h
23
client.h
|
@ -12,6 +12,8 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#ifndef KWIN_CLIENT_H
|
||||
#define KWIN_CLIENT_H
|
||||
|
||||
#include <config-X11.h>
|
||||
|
||||
#include <qframe.h>
|
||||
#include <QPixmap>
|
||||
#include <netwm.h>
|
||||
|
@ -30,6 +32,10 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#include "rules.h"
|
||||
#include "toplevel.h"
|
||||
|
||||
#ifdef HAVE_XSYNC
|
||||
#include <X11/extensions/sync.h>
|
||||
#endif
|
||||
|
||||
class QTimer;
|
||||
class K3Process;
|
||||
class KStartupInfoData;
|
||||
|
@ -84,6 +90,9 @@ class Client
|
|||
|
||||
bool windowEvent( XEvent* e );
|
||||
virtual bool eventFilter( QObject* o, QEvent* e );
|
||||
#ifdef HAVE_XSYNC
|
||||
void syncEvent( XSyncAlarmNotifyEvent* e );
|
||||
#endif
|
||||
|
||||
bool manage( Window w, bool isMapped );
|
||||
void releaseWindow( bool on_shutdown = false );
|
||||
|
@ -293,6 +302,9 @@ class Client
|
|||
void leaveNotifyEvent( XCrossingEvent* e );
|
||||
void focusInEvent( XFocusInEvent* e );
|
||||
void focusOutEvent( XFocusOutEvent* e );
|
||||
#ifdef HAVE_XDAMAGE
|
||||
virtual void damageNotifyEvent( XDamageNotifyEvent* e );
|
||||
#endif
|
||||
|
||||
bool buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root );
|
||||
bool buttonReleaseEvent( Window w, int button, int state, int x, int y, int x_root, int y_root );
|
||||
|
@ -307,6 +319,7 @@ class Client
|
|||
void pingTimeout();
|
||||
void processKillerExited();
|
||||
void demandAttentionKNotify();
|
||||
void syncTimeout();
|
||||
|
||||
private:
|
||||
// ICCCM 4.1.3.1, 4.1.4 , NETWM 2.5.1
|
||||
|
@ -339,6 +352,8 @@ class Client
|
|||
NETExtendedStrut strut() const;
|
||||
int checkShadeGeometry( int w, int h );
|
||||
void blockGeometryUpdates( bool block );
|
||||
void getSyncCounter();
|
||||
void sendSyncRequest();
|
||||
|
||||
bool startMoveResize();
|
||||
void finishMoveResize( bool cancel );
|
||||
|
@ -352,6 +367,7 @@ class Client
|
|||
void ungrabButton( int mod );
|
||||
void resetMaximize();
|
||||
void resizeDecoration( const QSize& s );
|
||||
void performMoveResize();
|
||||
|
||||
void pingWindow();
|
||||
void killProcess( bool ask, Time timestamp = CurrentTime );
|
||||
|
@ -465,6 +481,13 @@ class Client
|
|||
PendingGeometry_t pending_geometry_update;
|
||||
QRect geom_before_block;
|
||||
bool shade_geometry_change;
|
||||
#ifdef HAVE_XSYNC
|
||||
XSyncCounter sync_counter;
|
||||
XSyncValue sync_counter_value;
|
||||
XSyncAlarm sync_alarm;
|
||||
#endif
|
||||
QTimer* sync_timeout;
|
||||
bool sync_resize_pending;
|
||||
int border_left, border_right, border_top, border_bottom;
|
||||
QRegion _mask;
|
||||
static bool check_active_modal; // see Client::checkActiveModal()
|
||||
|
|
|
@ -284,6 +284,11 @@ void Workspace::performCompositing()
|
|||
repaints_region |= c->repaints().translated( c->pos());
|
||||
c->resetRepaints( c->rect());
|
||||
}
|
||||
ToplevelList tmp = windows;
|
||||
windows.clear();
|
||||
foreach( Toplevel* c, tmp )
|
||||
if( c->readyForPainting())
|
||||
windows.append( c );
|
||||
QRegion repaints = repaints_region;
|
||||
// clear all repaints, so that post-pass can add repaints for the next repaint
|
||||
repaints_region = QRegion();
|
||||
|
@ -445,6 +450,17 @@ void Toplevel::damageNotifyEvent( XDamageNotifyEvent* e )
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::damageNotifyEvent( XDamageNotifyEvent* e )
|
||||
{
|
||||
Toplevel::damageNotifyEvent( e );
|
||||
#ifdef HAVE_XSYNC
|
||||
if( sync_counter == None ) // cannot detect complete redraw, consider done now
|
||||
ready_for_painting = true;
|
||||
#else
|
||||
ready_for_painting = true; // no sync at all, consider done now
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void Toplevel::addDamage( const QRect& r )
|
||||
|
|
28
events.cpp
28
events.cpp
|
@ -478,6 +478,15 @@ bool Workspace::workspaceEvent( XEvent * e )
|
|||
QTimer::singleShot( 0, this, SLOT( setupCompositing() ) );
|
||||
}
|
||||
}
|
||||
else if( e->type == Extensions::syncAlarmNotifyEvent() && Extensions::syncAvailable())
|
||||
{
|
||||
#ifdef HAVE_XSYNC
|
||||
foreach( Client* c, clients )
|
||||
c->syncEvent( reinterpret_cast< XSyncAlarmNotifyEvent* >( e ));
|
||||
foreach( Client* c, desktops )
|
||||
c->syncEvent( reinterpret_cast< XSyncAlarmNotifyEvent* >( e ));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
|
@ -909,6 +918,8 @@ void Client::propertyNotifyEvent( XPropertyEvent* e )
|
|||
getWindowProtocols();
|
||||
else if( e->atom == atoms->motif_wm_hints )
|
||||
getMotifHints();
|
||||
else if( e->atom == atoms->net_wm_sync_request_counter )
|
||||
getSyncCounter();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1560,6 +1571,23 @@ void Client::keyPressEvent( uint key_code )
|
|||
QCursor::setPos( pos );
|
||||
}
|
||||
|
||||
#ifdef HAVE_XSYNC
|
||||
void Client::syncEvent( XSyncAlarmNotifyEvent* e )
|
||||
{
|
||||
if( e->alarm == sync_alarm && XSyncValueEqual( e->counter_value, sync_counter_value ))
|
||||
{
|
||||
ready_for_painting = true;
|
||||
if( isResize())
|
||||
{
|
||||
delete sync_timeout;
|
||||
sync_timeout = NULL;
|
||||
if( sync_resize_pending )
|
||||
performMoveResize();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// ****************************************
|
||||
// Unmanaged
|
||||
// ****************************************
|
||||
|
|
41
geometry.cpp
41
geometry.cpp
|
@ -2368,6 +2368,8 @@ void Client::leaveMoveResize()
|
|||
moveResizeMode = false;
|
||||
delete eater;
|
||||
eater = 0;
|
||||
delete sync_timeout;
|
||||
sync_timeout = NULL;
|
||||
if( options->electricBorders() == Options::ElectricMoveOnly )
|
||||
workspace()->reserveElectricBorderSwitching( false );
|
||||
}
|
||||
|
@ -2618,8 +2620,34 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
|
|||
else
|
||||
assert( false );
|
||||
|
||||
if( update )
|
||||
if( isResize())
|
||||
{
|
||||
if( sync_timeout != NULL )
|
||||
{
|
||||
sync_resize_pending = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if( update )
|
||||
performMoveResize();
|
||||
if ( isMove() )
|
||||
workspace()->checkElectricBorder(globalPos, xTime());
|
||||
}
|
||||
|
||||
void Client::performMoveResize()
|
||||
{
|
||||
#ifdef HAVE_XSYNC
|
||||
if( isResize() && sync_counter != None )
|
||||
{
|
||||
sync_timeout = new QTimer( this );
|
||||
connect( sync_timeout, SIGNAL( timeout()), SLOT( syncTimeout()));
|
||||
sync_timeout->setSingleShot( true );
|
||||
sync_timeout->start( 500 );
|
||||
sendSyncRequest();
|
||||
}
|
||||
#endif
|
||||
sync_resize_pending = false;
|
||||
if( rules()->checkMoveResizeMode
|
||||
( isResize() ? options->resizeMode : options->moveMode ) == Options::Opaque )
|
||||
{
|
||||
|
@ -2633,11 +2661,16 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
|
|||
positionGeometryTip(); // shown, otherwise it would cause repaint problems in case
|
||||
drawbound( moveResizeGeom ); // they overlap; the paint event will come after this,
|
||||
} // so the geometry tip will be painted above the outline
|
||||
}
|
||||
if ( isMove() )
|
||||
workspace()->checkElectricBorder(globalPos, xTime());
|
||||
if( effects )
|
||||
static_cast<EffectsHandlerImpl*>(effects)->windowUserMovedResized( effectWindow(), false, false );
|
||||
}
|
||||
|
||||
void Client::syncTimeout()
|
||||
{
|
||||
sync_timeout->deleteLater();
|
||||
sync_timeout = NULL;
|
||||
if( sync_resize_pending )
|
||||
performMoveResize();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -96,6 +96,7 @@ bool Client::manage( Window w, bool isMapped )
|
|||
getWindowRole();
|
||||
getWmClientLeader();
|
||||
getWmClientMachine();
|
||||
getSyncCounter();
|
||||
// first only read the caption text, so that setupWindowRules() can use it for matching,
|
||||
// and only then really set the caption using setCaption(), which checks for duplicates etc.
|
||||
// and also relies on rules already existing
|
||||
|
@ -441,6 +442,9 @@ bool Client::manage( Window w, bool isMapped )
|
|||
workspace()->restoreSessionStackingOrder( this );
|
||||
}
|
||||
|
||||
if( compositing()) // sending ConfigureNotify is done when setting mapping state below,
|
||||
sendSyncRequest(); // getting the first sync response means window is ready for compositing
|
||||
|
||||
if( isShown( true ) && !doNotShow )
|
||||
{
|
||||
if( isDialog())
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace KWin
|
|||
Toplevel::Toplevel( Workspace* ws )
|
||||
: vis( NULL )
|
||||
, info( NULL )
|
||||
, ready_for_painting( true )
|
||||
, client( None )
|
||||
, frame( None )
|
||||
, wspace( ws )
|
||||
|
@ -104,6 +105,7 @@ void Toplevel::copyToDeleted( Toplevel* c )
|
|||
frame = c->frame;
|
||||
wspace = c->wspace;
|
||||
window_pix = c->window_pix;
|
||||
ready_for_painting = c->ready_for_painting;
|
||||
#ifdef HAVE_XDAMAGE
|
||||
damage_handle = None;
|
||||
#endif
|
||||
|
|
|
@ -85,6 +85,7 @@ class Toplevel
|
|||
static bool resourceMatch( const Toplevel* c1, const Toplevel* c2 );
|
||||
|
||||
Pixmap windowPixmap( bool allow_create = true ); // may return None (e.g. at a bad moment while resizing)
|
||||
bool readyForPainting() const; // true if the window has been already painted its contents
|
||||
Visual* visual() const;
|
||||
bool shape() const;
|
||||
void setOpacity( double opacity );
|
||||
|
@ -111,7 +112,7 @@ class Toplevel
|
|||
void detectShape( Window id );
|
||||
virtual void propertyNotifyEvent( XPropertyEvent* e );
|
||||
#ifdef HAVE_XDAMAGE
|
||||
void damageNotifyEvent( XDamageNotifyEvent* e );
|
||||
virtual void damageNotifyEvent( XDamageNotifyEvent* e );
|
||||
#endif
|
||||
Pixmap createWindowPixmap();
|
||||
void discardWindowPixmap();
|
||||
|
@ -130,6 +131,7 @@ class Toplevel
|
|||
Visual* vis;
|
||||
int bit_depth;
|
||||
NETWinInfo* info;
|
||||
bool ready_for_painting;
|
||||
private:
|
||||
static QByteArray staticWindowRole(WId);
|
||||
static QByteArray staticSessionId(WId);
|
||||
|
@ -219,6 +221,11 @@ inline QRect Toplevel::rect() const
|
|||
return QRect( 0, 0, width(), height());
|
||||
}
|
||||
|
||||
inline bool Toplevel::readyForPainting() const
|
||||
{
|
||||
return ready_for_painting;
|
||||
}
|
||||
|
||||
inline Visual* Toplevel::visual() const
|
||||
{
|
||||
return vis;
|
||||
|
|
22
utils.cpp
22
utils.cpp
|
@ -50,6 +50,9 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#ifdef HAVE_OPENGL
|
||||
#include <GL/glx.h>
|
||||
#endif
|
||||
#ifdef HAVE_XSYNC
|
||||
#include <X11/extensions/sync.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -74,6 +77,8 @@ int Extensions::composite_version = 0;
|
|||
int Extensions::fixes_version = 0;
|
||||
int Extensions::render_version = 0;
|
||||
bool Extensions::has_glx = false;
|
||||
bool Extensions::has_sync = false;
|
||||
int Extensions::sync_event_base = 0;
|
||||
|
||||
void Extensions::init()
|
||||
{
|
||||
|
@ -131,6 +136,14 @@ void Extensions::init()
|
|||
has_glx = false;
|
||||
#ifdef HAVE_OPENGL
|
||||
has_glx = glXQueryExtension( display(), &dummy, &dummy );
|
||||
#endif
|
||||
#ifdef HAVE_XSYNC
|
||||
if( XSyncQueryExtension( display(), &sync_event_base, &dummy ))
|
||||
{
|
||||
int major = 0, minor = 0;
|
||||
if( XSyncInitialize( display(), &major, &minor ))
|
||||
has_sync = true;
|
||||
}
|
||||
#endif
|
||||
kDebug( 1212 ) << "Extensions: shape: 0x" << QString::number( shape_version, 16 )
|
||||
<< " composite: 0x" << QString::number( composite_version, 16 )
|
||||
|
@ -190,6 +203,15 @@ bool Extensions::fixesRegionAvailable()
|
|||
return fixes_version >= 0x30; // 3
|
||||
}
|
||||
|
||||
int Extensions::syncAlarmNotifyEvent()
|
||||
{
|
||||
#ifdef HAVE_XSYNC
|
||||
return sync_event_base + XSyncAlarmNotify;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move,
|
||||
bool& minimize, bool& maximize, bool& close )
|
||||
{
|
||||
|
|
4
utils.h
4
utils.h
|
@ -143,6 +143,8 @@ class Extensions
|
|||
static bool fixesAvailable() { return fixes_version > 0; }
|
||||
static bool fixesRegionAvailable();
|
||||
static bool glxAvailable() { return has_glx; }
|
||||
static bool syncAvailable() { return has_sync; }
|
||||
static int syncAlarmNotifyEvent();
|
||||
private:
|
||||
static int shape_version;
|
||||
static int shape_event_base;
|
||||
|
@ -154,6 +156,8 @@ class Extensions
|
|||
static int render_version;
|
||||
static int fixes_version;
|
||||
static bool has_glx;
|
||||
static bool has_sync;
|
||||
static int sync_event_base;
|
||||
};
|
||||
|
||||
// compile with XShape older than 1.0
|
||||
|
|
Loading…
Reference in a new issue