diff options
Diffstat (limited to 'kwin/tools')
-rw-r--r-- | kwin/tools/Makefile.am | 11 | ||||
-rw-r--r-- | kwin/tools/decobenchmark/Makefile.am | 9 | ||||
-rw-r--r-- | kwin/tools/decobenchmark/main.cpp | 138 | ||||
-rw-r--r-- | kwin/tools/decobenchmark/main.h | 51 | ||||
-rw-r--r-- | kwin/tools/decobenchmark/preview.cpp | 412 | ||||
-rw-r--r-- | kwin/tools/decobenchmark/preview.h | 137 | ||||
-rw-r--r-- | kwin/tools/test_gravity.cpp | 99 | ||||
-rw-r--r-- | kwin/tools/xreply/Makefile | 2 | ||||
-rw-r--r-- | kwin/tools/xreply/xreply.c | 197 |
9 files changed, 1056 insertions, 0 deletions
diff --git a/kwin/tools/Makefile.am b/kwin/tools/Makefile.am new file mode 100644 index 000000000..da92d969d --- /dev/null +++ b/kwin/tools/Makefile.am @@ -0,0 +1,11 @@ +noinst_PROGRAMS = test_gravity + +SUBDIRS = decobenchmark + +INCLUDES = $(all_includes) + +test_gravity_SOURCES = test_gravity.cpp +test_gravity_LDFLAGS = $(all_libraries) $(KDE_RPATH) +test_gravity_LDADD = $(LIB_X11) + +METASOURCES = AUTO diff --git a/kwin/tools/decobenchmark/Makefile.am b/kwin/tools/decobenchmark/Makefile.am new file mode 100644 index 000000000..306c89971 --- /dev/null +++ b/kwin/tools/decobenchmark/Makefile.am @@ -0,0 +1,9 @@ +noinst_PROGRAMS = decobenchmark + +INCLUDES = $(all_includes) + +decobenchmark_SOURCES = main.cpp preview.cpp +decobenchmark_LDFLAGS = $(all_libraries) +decobenchmark_LDADD = ../../lib/libkdecorations.la + +METASOURCES = AUTO diff --git a/kwin/tools/decobenchmark/main.cpp b/kwin/tools/decobenchmark/main.cpp new file mode 100644 index 000000000..847fef69c --- /dev/null +++ b/kwin/tools/decobenchmark/main.cpp @@ -0,0 +1,138 @@ +/* + * + * Copyright (c) 2005 Sandro Giessl <[email protected]> + * Copyright (c) 2005 Luciano Montanaro <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <qtimer.h> + +#include <kdebug.h> +#include <kconfig.h> +#include <kdecoration_plugins_p.h> +#include <kdecorationfactory.h> + +#include <time.h> +#include <sys/timeb.h> +#include <iostream> + + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kcmdlineargs.h> + +#include "preview.h" +#include "main.h" + +static KCmdLineOptions options[] = +{ + { "+decoration", "Decoration library to use, such as kwin3_plastik.", 0 }, + { "+tests", "Which test should be executed ('all', 'repaint', 'caption', 'resize', 'recreation')", 0 }, + { "+repetitions", "Number of test repetitions.", 0 }, + { 0, 0, 0 } +}; + +DecoBenchApplication::DecoBenchApplication(const QString &library, Tests tests, int count) : + m_tests(tests), + m_count(count) +{ + KConfig kwinConfig("kwinrc"); + kwinConfig.setGroup("Style"); + + plugins = new KDecorationPreviewPlugins( &kwinConfig ); + preview = new KDecorationPreview( plugins, 0 ); + + if (plugins->loadPlugin(library) ) + kdDebug() << "Decoration library " << library << " loaded..." << endl; + else + kdError() << "Error loading decoration library " << library << "!" << endl; + + if (preview->recreateDecoration() ) + kdDebug() << "Decoration created..." << endl; + else + kdError() << "Error creating decoration!" << endl; + + preview->show(); +} + +DecoBenchApplication::~DecoBenchApplication() +{ + delete preview; + delete plugins; +} + +void DecoBenchApplication::executeTest() +{ + clock_t stime = clock(); + timeb astart, aend; + ftime(&astart); + + if (m_tests == AllTests || m_tests == RepaintTest) + preview->performRepaintTest(m_count); + if (m_tests == AllTests || m_tests == CaptionTest) + preview->performCaptionTest(m_count); + if (m_tests == AllTests || m_tests == ResizeTest) + preview->performResizeTest(m_count); + if (m_tests == AllTests || m_tests == RecreationTest) + preview->performRecreationTest(m_count); + + clock_t etime = clock(); + ftime(&aend); + + long long time_diff = (aend.time - astart.time)*1000+aend.millitm - astart.millitm; + kdDebug() << "Total:" << (float(time_diff)/1000) << endl; + quit(); +} + +int main(int argc, char** argv) +{ + QString style = "keramik"; + // KApplication app(argc, argv); + KAboutData about("decobenchmark", "DecoBenchmark", "0.1", "kwin decoration performance tester...", KAboutData::License_LGPL, "(C) 2005 Sandro Giessl"); + KCmdLineArgs::init(argc, argv, &about); + KCmdLineArgs::addCmdLineOptions( options ); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if (args->count() != 3) + KCmdLineArgs::usage("Wrong number of arguments!"); + + QString library = QString(args->arg(0) ); + QString t = QString(args->arg(1) ); + int count = QString(args->arg(2) ).toInt(); + + Tests test; + if (t == "all") + test = AllTests; + else if (t == "repaint") + test = RepaintTest; + else if (t == "caption") + test = CaptionTest; + else if (t == "resize") + test = ResizeTest; + else if (t == "recreation") + test = RecreationTest; + else + KCmdLineArgs::usage("Specify a valid test!"); + + DecoBenchApplication app(library, test, count); + + QTimer::singleShot(0, &app, SLOT(executeTest())); + app.exec(); +} +#include "main.moc" + +// kate: space-indent off; tab-width 4; diff --git a/kwin/tools/decobenchmark/main.h b/kwin/tools/decobenchmark/main.h new file mode 100644 index 000000000..4073238a1 --- /dev/null +++ b/kwin/tools/decobenchmark/main.h @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2005 Sandro Giessl <[email protected]> + * Copyright (c) 2005 Luciano Montanaro <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef BENCH_MAIN_H +#define BENCH_MAIN_H + +enum Tests { + AllTests, + RepaintTest, + CaptionTest, + ResizeTest, + RecreationTest +}; + +class DecoBenchApplication : public KApplication +{ + Q_OBJECT +public: + DecoBenchApplication(const QString &library, Tests tests, int count); + ~DecoBenchApplication(); + +public slots: + void executeTest(); + +private: + KDecorationPreview *preview; + KDecorationPlugins *plugins; + Tests m_tests; + int m_count; +}; + +#endif // BENCH_MAIN_H + +// kate: space-indent off; tab-width 4; diff --git a/kwin/tools/decobenchmark/preview.cpp b/kwin/tools/decobenchmark/preview.cpp new file mode 100644 index 000000000..35301c513 --- /dev/null +++ b/kwin/tools/decobenchmark/preview.cpp @@ -0,0 +1,412 @@ +/* + * + * Copyright (c) 2003 Lubos Lunak <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "preview.h" + +#include <kdebug.h> + +#include <kapplication.h> +#include <klocale.h> +#include <kconfig.h> +#include <kglobal.h> +#include <qlabel.h> +#include <qstyle.h> +#include <kiconloader.h> + +#include <X11/Xlib.h> +#include <X11/extensions/shape.h> + +#include <kdecorationfactory.h> +#include <kdecoration_plugins_p.h> + +// FRAME the preview doesn't update to reflect the changes done in the kcm + +KDecorationPreview::KDecorationPreview( KDecorationPlugins* plugin, QWidget* parent, const char* name ) + : QWidget( parent, name ), + m_plugin(plugin) +{ + options = new KDecorationPreviewOptions; + + bridge = new KDecorationPreviewBridge( this, true, "Deco Benchmark" ); + + deco = 0; + + setFixedSize( 600, 500 ); + + positionPreviews(); +} + +KDecorationPreview::~KDecorationPreview() +{ + delete deco; + delete bridge; + delete options; +} + +void KDecorationPreview::performRepaintTest(int n) +{ + kdDebug() << "start " << n << " repaints..." << endl; + bridge->setCaption("Deco Benchmark"); + deco->captionChange(); + positionPreviews(0); + for (int i = 0; i < n; ++i) { + deco->widget()->repaint(); + kapp->processEvents(); + } +} + +void KDecorationPreview::performCaptionTest(int n) +{ + kdDebug() << "start " << n << " caption changes..." << endl; + QString caption = "Deco Benchmark %1"; + positionPreviews(0); + for (int i = 0; i < n; ++i) { + bridge->setCaption(caption.arg(i) ); + deco->captionChange(); + deco->widget()->repaint(); + kapp->processEvents(); + } +} + +void KDecorationPreview::performResizeTest(int n) +{ + kdDebug() << "start " << n << " resizes..." << endl; + bridge->setCaption("Deco Benchmark"); + deco->captionChange(); + for (int i = 0; i < n; ++i) { + positionPreviews(i % 200); + kapp->processEvents(); + } +} + +void KDecorationPreview::performRecreationTest(int n) +{ + kdDebug() << "start " << n << " resizes..." << endl; + bridge->setCaption("Deco Benchmark"); + deco->captionChange(); + positionPreviews(0); + for (int i = 0; i < n; ++i) { + recreateDecoration(); + kapp->processEvents(); + } +} + +bool KDecorationPreview::recreateDecoration() +{ + delete deco; + deco = m_plugin->createDecoration(bridge); + deco->init(); + + if (!deco) + return false; + + positionPreviews(); + deco->widget()->show(); + + return true; +} + +void KDecorationPreview::positionPreviews(int shrink) +{ + if ( !deco ) + return; + + QSize size = QSize(width()-2*10-shrink, height()-2*10-shrink)/*.expandedTo(deco->minimumSize()*/; + + QRect geometry(QPoint(10, 10), size); + deco->widget()->setGeometry(geometry); +} + +void KDecorationPreview::setPreviewMask( const QRegion& reg, int mode ) +{ + QWidget *widget = deco->widget(); + + // FRAME duped from client.cpp + if( mode == Unsorted ) + { + XShapeCombineRegion( qt_xdisplay(), widget->winId(), ShapeBounding, 0, 0, + reg.handle(), ShapeSet ); + } + else + { + QMemArray< QRect > rects = reg.rects(); + XRectangle* xrects = new XRectangle[ rects.count() ]; + for( unsigned int i = 0; + i < rects.count(); + ++i ) + { + xrects[ i ].x = rects[ i ].x(); + xrects[ i ].y = rects[ i ].y(); + xrects[ i ].width = rects[ i ].width(); + xrects[ i ].height = rects[ i ].height(); + } + XShapeCombineRectangles( qt_xdisplay(), widget->winId(), ShapeBounding, 0, 0, + xrects, rects.count(), ShapeSet, mode ); + delete[] xrects; + } +} + +QRect KDecorationPreview::windowGeometry( bool active ) const +{ + QWidget *widget = deco->widget(); + return widget->geometry(); +} + +QRegion KDecorationPreview::unobscuredRegion( bool active, const QRegion& r ) const +{ + return r; +} + +KDecorationPreviewBridge::KDecorationPreviewBridge( KDecorationPreview* p, bool a, const QString &c ) + : preview( p ), active( a ), m_caption( c ) +{ +} + +void KDecorationPreviewBridge::setCaption(const QString &c) +{ + m_caption = c; +} + +QWidget* KDecorationPreviewBridge::initialParentWidget() const + { + return preview; + } + +Qt::WFlags KDecorationPreviewBridge::initialWFlags() const + { + return 0; + } + +bool KDecorationPreviewBridge::isActive() const + { + return active; + } + +bool KDecorationPreviewBridge::isCloseable() const + { + return true; + } + +bool KDecorationPreviewBridge::isMaximizable() const + { + return true; + } + +KDecoration::MaximizeMode KDecorationPreviewBridge::maximizeMode() const + { + return KDecoration::MaximizeRestore; + } + +bool KDecorationPreviewBridge::isMinimizable() const + { + return true; + } + +bool KDecorationPreviewBridge::providesContextHelp() const + { + return true; + } + +int KDecorationPreviewBridge::desktop() const + { + return 1; + } + +bool KDecorationPreviewBridge::isModal() const + { + return false; + } + +bool KDecorationPreviewBridge::isShadeable() const + { + return true; + } + +bool KDecorationPreviewBridge::isShade() const + { + return false; + } + +bool KDecorationPreviewBridge::isSetShade() const + { + return false; + } + +bool KDecorationPreviewBridge::keepAbove() const + { + return false; + } + +bool KDecorationPreviewBridge::keepBelow() const + { + return false; + } + +bool KDecorationPreviewBridge::isMovable() const + { + return true; + } + +bool KDecorationPreviewBridge::isResizable() const + { + return true; + } + +NET::WindowType KDecorationPreviewBridge::windowType( unsigned long ) const + { + return NET::Normal; + } + +QIconSet KDecorationPreviewBridge::icon() const + { + return SmallIconSet( "xapp" ); + } + +QString KDecorationPreviewBridge::caption() const +{ + return m_caption; +} + +void KDecorationPreviewBridge::processMousePressEvent( QMouseEvent* ) + { + } + +void KDecorationPreviewBridge::showWindowMenu( const QRect &) + { + } + +void KDecorationPreviewBridge::showWindowMenu( QPoint ) + { + } + +void KDecorationPreviewBridge::performWindowOperation( WindowOperation ) + { + } + +void KDecorationPreviewBridge::setMask( const QRegion& reg, int mode ) + { + preview->setPreviewMask( reg, mode ); + } + +bool KDecorationPreviewBridge::isPreview() const + { + return false; + } + +QRect KDecorationPreviewBridge::geometry() const + { + return preview->windowGeometry( active ); + } + +QRect KDecorationPreviewBridge::iconGeometry() const + { + return QRect(); + } + +QRegion KDecorationPreviewBridge::unobscuredRegion( const QRegion& r ) const + { + return preview->unobscuredRegion( active, r ); + } + +QWidget* KDecorationPreviewBridge::workspaceWidget() const + { + return preview; + } + +WId KDecorationPreviewBridge::windowId() const + { + return 0; // no decorated window + } + +void KDecorationPreviewBridge::closeWindow() + { + } + +void KDecorationPreviewBridge::maximize( MaximizeMode ) + { + } + +void KDecorationPreviewBridge::minimize() + { + } + +void KDecorationPreviewBridge::showContextHelp() + { + } + +void KDecorationPreviewBridge::setDesktop( int ) + { + } + +void KDecorationPreviewBridge::titlebarDblClickOperation() + { + } + +void KDecorationPreviewBridge::setShade( bool ) + { + } + +void KDecorationPreviewBridge::setKeepAbove( bool ) + { + } + +void KDecorationPreviewBridge::setKeepBelow( bool ) + { + } + +int KDecorationPreviewBridge::currentDesktop() const + { + return 1; + } + +void KDecorationPreviewBridge::helperShowHide( bool ) + { + } + +void KDecorationPreviewBridge::grabXServer( bool ) + { + } + +KDecorationPreviewOptions::KDecorationPreviewOptions() + { + d = new KDecorationOptionsPrivate; + d->defaultKWinSettings(); + updateSettings(); + } + +KDecorationPreviewOptions::~KDecorationPreviewOptions() + { + delete d; + } + +unsigned long KDecorationPreviewOptions::updateSettings() +{ + KConfig cfg( "kwinrc", true ); + unsigned long changed = 0; + changed |= d->updateKWinSettings( &cfg ); + + return changed; +} + +bool KDecorationPreviewPlugins::provides( Requirement ) + { + return false; + } + +// #include "preview.moc" diff --git a/kwin/tools/decobenchmark/preview.h b/kwin/tools/decobenchmark/preview.h new file mode 100644 index 000000000..4c82ac0a1 --- /dev/null +++ b/kwin/tools/decobenchmark/preview.h @@ -0,0 +1,137 @@ +/* + * + * Copyright (c) 2003 Lubos Lunak <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KWINDECORATION_PREVIEW_H +#define KWINDECORATION_PREVIEW_H + +#include <qwidget.h> +#include <kdecoration_p.h> +#include <kdecoration_plugins_p.h> + +class QLabel; + +class KDecorationPreviewBridge; +class KDecorationPreviewOptions; + +class KDecorationPreview + : public QWidget + { + public: + KDecorationPreview( KDecorationPlugins* plugin, QWidget* parent = NULL, const char* name = NULL ); + virtual ~KDecorationPreview(); + + void performRepaintTest(int n); + void performCaptionTest(int n); + void performResizeTest(int n); + void performRecreationTest(int n); + + bool recreateDecoration(); + void setPreviewMask( const QRegion&, int ); + QRegion unobscuredRegion( bool, const QRegion& ) const; + QRect windowGeometry( bool ) const; + private: + void positionPreviews(int shrink = 0); + KDecorationPreviewOptions* options; + KDecorationPreviewBridge* bridge; + KDecoration* deco; + KDecorationPlugins* m_plugin; + }; + +class KDecorationPreviewBridge + : public KDecorationBridge + { + public: + KDecorationPreviewBridge( KDecorationPreview* preview, bool active, const QString &caption ); + + void setCaption(const QString &caption); + + virtual bool isActive() const; + virtual bool isCloseable() const; + virtual bool isMaximizable() const; + virtual MaximizeMode maximizeMode() const; + virtual bool isMinimizable() const; + virtual bool providesContextHelp() const; + virtual int desktop() const; + virtual bool isModal() const; + virtual bool isShadeable() const; + virtual bool isShade() const; + virtual bool isSetShade() const; + virtual bool keepAbove() const; + virtual bool keepBelow() const; + virtual bool isMovable() const; + virtual bool isResizable() const; + virtual NET::WindowType windowType( unsigned long supported_types ) const; + virtual QIconSet icon() const; + virtual QString caption() const; + virtual void processMousePressEvent( QMouseEvent* ); + virtual void showWindowMenu( const QRect &); + virtual void showWindowMenu( QPoint ); + virtual void performWindowOperation( WindowOperation ); + virtual void setMask( const QRegion&, int ); + virtual bool isPreview() const; + virtual QRect geometry() const; + virtual QRect iconGeometry() const; + virtual QRegion unobscuredRegion( const QRegion& r ) const; + virtual QWidget* workspaceWidget() const; + virtual WId windowId() const; + virtual void closeWindow(); + virtual void maximize( MaximizeMode mode ); + virtual void minimize(); + virtual void showContextHelp(); + virtual void setDesktop( int desktop ); + virtual void titlebarDblClickOperation(); + virtual void setShade( bool set ); + virtual void setKeepAbove( bool ); + virtual void setKeepBelow( bool ); + virtual int currentDesktop() const; + virtual QWidget* initialParentWidget() const; + virtual Qt::WFlags initialWFlags() const; + virtual void helperShowHide( bool show ); + virtual void grabXServer( bool grab ); + private: + KDecorationPreview* preview; + bool active; + QString m_caption; + }; + +class KDecorationPreviewOptions + : public KDecorationOptions + { + public: + KDecorationPreviewOptions(); + virtual ~KDecorationPreviewOptions(); + virtual unsigned long updateSettings(); + + private: + }; + +class KDecorationPreviewPlugins + : public KDecorationPlugins + { + public: + KDecorationPreviewPlugins( KConfig* cfg ); + virtual bool provides( Requirement ); + }; + +inline KDecorationPreviewPlugins::KDecorationPreviewPlugins( KConfig* cfg ) + : KDecorationPlugins( cfg ) + { + } + +#endif diff --git a/kwin/tools/test_gravity.cpp b/kwin/tools/test_gravity.cpp new file mode 100644 index 000000000..618023b5f --- /dev/null +++ b/kwin/tools/test_gravity.cpp @@ -0,0 +1,99 @@ +// tests for window gravity + +#include <iostream> +#include <stdlib.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +using namespace std; + +const int gravities[ 10 ] = + { + NorthWestGravity, + NorthGravity, + NorthEastGravity, + WestGravity, + CenterGravity, + EastGravity, + SouthWestGravity, + SouthGravity, + SouthEastGravity, + StaticGravity + }; + +const char* const gravity_names[ 10 ] = + { + "NW", "N", "NE", "W", "C", "E", "SW", "S", "SE", "ST" + }; + +Display* dpy = NULL; + +int get_gravity( const char* name ) + { + for( int i = 0; + i < 10; + ++i ) + if( strcmp( name, gravity_names[ i ] ) == 0 ) + return gravities[ i ]; + cerr << "Wrong gravity name" << endl; + exit( 1 ); + } + +void test( const char* gravity ) + { + XSetWindowAttributes attrs; + XSizeHints hints; + hints.flags = USPosition | PWinGravity; + hints.win_gravity = get_gravity( gravity ); + Window w = XCreateWindow( dpy, DefaultRootWindow( dpy ), 100, 100, 200, 100, 0, CopyFromParent, CopyFromParent, + CopyFromParent, 0, &attrs ); + XSetWMNormalHints( dpy, w, &hints ); + XSelectInput( dpy, w, StructureNotifyMask | ButtonPressMask ); + XMapWindow( dpy, w ); + for(;;) + { + XEvent ev; + XNextEvent( dpy, &ev ); + if( ev.type == ConfigureNotify ) + { + cout << "CONFIGURENOTIFY:" << ev.xany.send_event << ":" << ev.xconfigure.x << ":" << ev.xconfigure.y + << ":" << ev.xconfigure.width << ":" << ev.xconfigure.height << endl; + Window root, child; + int x, x_local, y, y_local; + unsigned int width, height, border, depth; + XGetGeometry( dpy, w, &root, &x_local, &y_local, &width, &height, &border, &depth ); + XTranslateCoordinates( dpy, w, root, 0, 0, &x, &y, &child ); + cout << "GEOMETRY:" << x << ":" << y << ":" << width << ":" << height << ":(" << x_local << ":" << y_local << ")" << endl; + } + else if( ev.type == ButtonPress ) + { + if( ev.xbutton.button == Button1 ) // move + { + cout << "MOVE" << endl; + XMoveWindow( dpy, w, 100, 100 ); + } + else if( ev.xbutton.button == Button2 ) // resize + { + cout << "RESIZE" << endl; + XResizeWindow( dpy, w, 200, 100 ); + } + else if( ev.xbutton.button == Button3 ) // move and resize + { + cout << "MOVERESIZE" << endl; + XMoveResizeWindow( dpy, w, 100, 100, 200, 100 ); + } + } + } + } + +int main( int argc, char* argv[] ) + { + dpy = XOpenDisplay( NULL ); + if( argc != 2 ) + { + cerr << "specify gravity" << endl; + exit( 1 ); + } + test( argv[ 1 ] ); + XCloseDisplay( dpy ); + } diff --git a/kwin/tools/xreply/Makefile b/kwin/tools/xreply/Makefile new file mode 100644 index 000000000..af06929d5 --- /dev/null +++ b/kwin/tools/xreply/Makefile @@ -0,0 +1,2 @@ +all: + gcc -O2 -Wall -shared -fPIC -o libxreply.so xreply.c diff --git a/kwin/tools/xreply/xreply.c b/kwin/tools/xreply/xreply.c new file mode 100644 index 000000000..ecdf6ebc3 --- /dev/null +++ b/kwin/tools/xreply/xreply.c @@ -0,0 +1,197 @@ +/* + + LD_PRELOAD library that gives statistic on number of roundtrips in an application. + + $XREPLY_BACKTRACE defines whether and how backtraces will be printed for every + roundtrip. If not set, only total number of roundtrips is printed after the process + exits. If set to a number, backtrace for every roundtrip will be printed, and the + backtraces will be as deep as the given number. If set to C<number> (e.g. C10), + the backtraces will be "compressed" - every backtrace will be printed only once + after the process exits, together with number of times it occured. + +*/ + +#define _GNU_SOURCE +#include <dlfcn.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <execinfo.h> +#include <assert.h> +#include <X11/Xlibint.h> + +/* Since these symbols are weak, the apps can provide their own, and therefore + e.g. temporarily suspend counting of roundtrips. At least theoretically, + I haven't really tried it. +*/ +__attribute((weak)) long ___xreply_reply_count = 0; +__attribute((weak)) int ___xreply_reply_enabled = 1; + +#define MAX_BACKTRACES 1024 + +extern long ___xreply_reply_count; +extern int ___xreply_reply_enabled; + +typedef Status (*xreply_ptr_t)(Display*,xReply*,int,Bool); + +static xreply_ptr_t xreply_ptr = NULL; +static int xreply_backtrace_set = 0; +static int xreply_backtrace_type = 0; + +struct xreply_struct + { + char* key; + char* text; + int count; + }; +static struct xreply_struct backtraces[ MAX_BACKTRACES ]; +static int backtraces_size = 0; + +static int xreply_compare( const void* left, const void* right ) + { + int left_count = ((struct xreply_struct*)left)->count; + int right_count = ((struct xreply_struct*)right)->count; + return right_count - left_count; + } + +static void xreply_print(void) + { + char tmp[ 1024 ]; + int fd; + fd = open( "/proc/self/cmdline", O_RDONLY ); + if( fd >= 0 ) + { + read( fd, tmp, 1024 ); + tmp[ 1023 ] = '\0'; + close( fd ); + } + fprintf( stderr, "XREPLY (%d : %s): %ld\n", getpid(), tmp, ___xreply_reply_count ); + if( xreply_backtrace_type < 0 ) + { + int i; + qsort( backtraces, backtraces_size, sizeof( struct xreply_struct ), xreply_compare ); + for( i = 0; + i < backtraces_size; + ++i ) + fprintf( stderr, "%d:%s\n\n", backtraces[ i ].count, backtraces[ i ].text ); + } + } + +static void xreply_backtrace() + { + void* trace[256]; + int n = backtrace(trace, 256); + char** strings = backtrace_symbols (trace, n); + + if( xreply_backtrace_type > 0 ) + { + fprintf( stderr, "%ld [\n", ___xreply_reply_count ); + if( n > xreply_backtrace_type ) + n = xreply_backtrace_type; + int i; + for( i = 0; + i < n; + ++i ) + fprintf( stderr, "%d: %s\n", i, strings[ i ] ); + fprintf( stderr, "]\n" ); + } + else + { + char stack[ 256 * 20 ]; + int pos = 0; + int i; + stack[ 0 ] = '\0'; + if( n > -xreply_backtrace_type ) + n = -xreply_backtrace_type; + for( i = 0; + i < n; + ++i ) + { + const char* start = strrchr( strings[ i ], '[' ); + if( start == NULL ) + assert( !"No [ in address." ); + long addr; + if( sscanf( start + 1, "0x%lx", &addr ) != 1 ) + assert( !"Failed to parse address." ); + if( sizeof( void* ) == 4 ) + { + sprintf( stack + pos, "0x%8lx", addr ); + pos += 10; + } + else if( sizeof( void* ) == 8 ) + { + sprintf( stack + pos, "0x%16lx", addr ); + pos += 18; + } + else + assert( !"Unknown sizeof( void* )." ); + } + for( i = 0; + i < backtraces_size; + ++i ) + if( strcmp( backtraces[ i ].key, stack ) == 0 ) + { + ++backtraces[ i ].count; + break; + } + if( i == backtraces_size ) + { + int stack_text_size = 10; + char* stack_text; + char* stack_text_pos; + for( i = 0; + i < n; + ++i ) + stack_text_size += strlen( strings[ i ] ) + 5; + stack_text = stack_text_pos = malloc( stack_text_size ); + for( i = 0; + i < n; + ++i ) + { + stack_text_pos = stpcpy( stack_text_pos, "\n" ); + stack_text_pos = stpcpy( stack_text_pos, strings[ i ] ); + } + backtraces[ backtraces_size ].key = strdup( stack ); + backtraces[ backtraces_size ].text = stack_text; + backtraces[ backtraces_size ].count = 1; + ++backtraces_size; + if( backtraces_size >= MAX_BACKTRACES ) + assert( !"MAX_BACKTRACES reached." ); + } + } + free (strings); + } + +Status +_XReply (dpy, rep, extra, discard) + register Display *dpy; + register xReply *rep; + int extra; /* number of 32-bit words expected after the reply */ + Bool discard; /* should I discard data following "extra" words? */ + { + if( ___xreply_reply_enabled ) + ++___xreply_reply_count; + if( xreply_backtrace_set == 0 ) + { + if( getenv( "XREPLY_BACKTRACE" ) != NULL ) + { // C<number> - compress backtraces, saved as negative value in xreply_backtrace_type + if( getenv( "XREPLY_BACKTRACE" )[ 0 ] == 'C' ) + xreply_backtrace_type = -atoi( getenv( "XREPLY_BACKTRACE" ) + 1 ); + else // <number> - print the backtrace every time + xreply_backtrace_type = atoi( getenv( "XREPLY_BACKTRACE" )); + } + else + xreply_backtrace_type = 0; + } + if( xreply_backtrace_type != 0 ) + xreply_backtrace(); + if( xreply_ptr == NULL ) + { + xreply_ptr = (xreply_ptr_t)dlsym( RTLD_NEXT, "_XReply" ); + if( xreply_ptr == NULL ) + assert( !"dlsym() failed." ); + atexit( xreply_print ); + } + return xreply_ptr( dpy, rep, extra, discard ); + } |