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:
- Change kwin_ to kwin3_ (in LDFLAGS, LIBADD, kde_module_LTLIBRARIES, SOURCES).
- Make sure LDFLAGS contains $(KDE_PLUGIN) and -module .
- Add -lkdecorations to LIBADD.
- Do NOT rename the directory where the .desktop file is installed ( $(kde_datadir)/kwin/ ).

.desktop file:
- Change kwin_ to kwin3_ in X-KDE-Library.

Sources:
- There are no kwin/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::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( "<center><b>MyDecoration</b></center>" ), 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 KStandardDirs, as the decoration will be used
  also in other applications than kwin.
- Implement all missing pure virtual functions. For mousePosition(), you may call
  KDecoration::mousePosition() if it's sufficient.
