It's suggested you check sources of some KDE CVS decoration if in doubts or in need of an example. Also, the API is documented in the .h header files. Makefile.am: - Make sure LDFLAGS contains $(KDE_PLUGIN) and -module . - Add -ltdecorations to LIBADD. - Do NOT rename the directory where the .desktop file is installed ( $(kde_datadir)/twin/ ). Sources: - There are no twin/something.h includes, and don't use the KWinInternal namespace. - Use QToolTip instead of KWinToolTip. - Use QButton instead of KWinButton, QToolButton instead of KWinToolButton and QWidget instead of KWinWidgetButton. - For tooltips, use simply QToolTip::add(). - Change Client* to MyClient* (or whatever is your main client class) in your MyButton. - Pass parent->widget() to QButton constructor in your MyButton constructor. - Make your MyClient class inherit from KDecoration instead of Client. - Make MyClient constructor take KDecorationBridge* and KDecorationFactory* as arguments, and pass these arguments to KDecoration constructor. - Except for data members initialization, make the constructor empty, move everything to void MyClient::init(). - As the first thing in init(), call createMainWidget(); if your client class took some flags such as WResizeNoErase, pass them to this function. - Then, do 'widget()->installEventFilter( this );'. - Implement MyClient::eventFilter() - as MyClient is now no longer QWidget, you need the event filter to call all the functions that used to be called directly. Usually, it's something like: ===== bool MyClient::eventFilter( QObject* o, QEvent* e ) { if ( o != widget() ) return false; switch ( e->type() ) { case QEvent::Resize: resizeEvent( static_cast< QResizeEvent* >( e ) ); return true; case QEvent::Paint: paintEvent( static_cast< QPaintEvent* >( e ) ); return true; case QEvent::MouseButtonDblClick: mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ) ); return true; case QEvent::Wheel: wheelEvent( static_cast< QWheelEvent* >( e )); return true; case QEvent::MouseButtonPress: processMousePressEvent( static_cast< QMouseEvent* >( e ) ); return true; case QEvent::Show: showEvent( static_cast< QShowEvent* >( e ) ); return true; default: return false; } } ===== - In MyClient, 'this' will have to be often replaced with 'widget()', pay special attention to cases where this won't cause compile error (e.g. in connect() calls, which take QObject* ). - Also, many calls may need 'widget()->' prepended. - Layout is created in init(), so call createLayout() directly there (if it's implemented). - Remove calls to Client methods (Client::resizeEvent() and so on). - Replace Options:: with KDecorationOptions:: . - Replace 'options' with 'options()' in MyClient (which is KDecoration::options()), if often used outside of MyClient, you may want to create (this assumes your code is in its namespace): ===== inline const KDecorationOptions* options() { return KDecoration::options(); } ===== - Options for colors need 'Color' prepended (e.g. 'ColorButtonBg'). - Replace miniIcon() with getting the right pixmap from icon() (usually 'icon().pixmap( QIconSet::Small, QIconSet::Normal )' ). - Replace stickyChange() with desktopChange(), and test isOnAllDesktops(). - Replace Sticky with OnAllDestops. - Replace iconify with minimize. - Change activeChange(bool) to activeChange(), and use isActive() to check the state. Similar for desktopChange, captionChange(), iconChange(), maximizeChange(). - Replace 'contextHelp()' with 'showContextHelp()'. - WindowWrapperShowEvent() is gone, simply use showEvent() filtered by the event filter if needed. - Change 'animateIconifyOrDeiconify()' to 'animateMinize()', if it's empty, simply remove it. Make sure it doesn't reenter the event loop (no kapp->processEvents()). - Buttons should use explicit setCursor() if they don't want cursor set by mousePosition(). I.e. usually call setCursor( ArrowCursor ) in your MyButton. - In the part where you insert windowWrapper() into the layout, i.e. something like ===== layout->addWidget( windowWrapper()); ===== replace it with something like ===== if( isPreview()) layout->addWidget( new QLabel( i18n( "
MyDecoration
" ), widget())); else layout->addItem( new QSpacerItem( 0, 0 )); ===== - Implement MyClient::minimumSize(). - Handling maximization - to change vertical or horizontal maximalization, use e.g. 'maximize( maximizeMode() ^ MaximizeVertical', to change normal maximalization, i.e. after left-clicking on the button, use 'maximize( maximizeMode() == MaximizeFull ? MaximizeRestore : MaximizeFull );' (which also means that there's also no maximize() slot). Also, if your decoration button has only two visual states representing the maximalization state, it's recommended that it shows the maximized state only for MaximizeFull state. - Make sure the decoration matches the window state after init() is finished, that is, that the buttons represent correctly the maximalization, on-all-desktops etc. states. As the simplest solution, you can call maximizeChange(), desktopChange(), etc. at the end of init(). - Use 'titlebarDblClickOperation()' for performing the application after doubleclicking the titlebar. - Implement borders() returning the width of the top,left,right and bottom border. You may check values like 'maximizeMode() == MaximizeFull && !options()->moveResizeMaximizedWindows()' to check whether you can disable some borders completely. Note that your painting code must of course match these sizes. - If your code uses XGrabServer() or XUnGrabServer(), replace them with (un)grabXServer(). - In cases where you call some function from the KDecoration API that can possibly destroy the decoration (e.g. showWindowMenu() or closeWindow()), make sure to use exists() if some more code will follow this call. Refer to showWindowMenu() documentation for an example. - Create class MyFactory inheriting from KDecorationFactory, and move the code that was in 'extern "C"' to it: From init() to constructor, from deinit() to destructor, from allocate() or create() to createDecoration(). Pass the KDecorationBridge* argument and 'this' to created MyClient objects. If createDecoration() needs to know the window type (e.g. it used the tool argument), use windowType() similarly like in KDecoration, and pass it the KDecorationBridge* argument. - Add something like this: ===== extern "C" { KDecorationFactory *create_factory() { return new MyNamespace::MyFactory(); } } ===== - The reset handling has changed: There's no signal resetClients(), and no slotResetAllClientsDelayed(). If your MyClient has some slotReset(), make it reset( unsigned long ), where the argument is mask of things that have changed ( SettingXYZ ). If you have some global function that handles resetting, make it MyFactory::reset( unsigned long ). Try to minimize the effects of the changed things, e.g. if only the color setting has changed, doing a repaint is often enough, and there's no need to recreate the decorations. If you need to recreate the decorations, return true from MyFactory::reset(), otherwise, you may call resetDecorations() to call reset() in all MyClient instances. - Implement resize() to resize the decoration to the given size (usually 'widget()->resize( s );' is enough). - Review mousePosition() if it's implemented. Position constants need 'Position' prepended, e.g. Top -> PositionTop. - Note that you cannot use "appdata" with TDEStandardDirs, as the decoration will be used also in other applications than twin. - Implement all missing pure virtual functions. For mousePosition(), you may call KDecoration::mousePosition() if it's sufficient.