1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
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( "<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 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.
|