| 1 |
Hacking on Amarok |
| 2 |
----------------- |
| 3 |
|
| 4 |
Please respect these guidelines when coding for Amarok, thanks! |
| 5 |
|
| 6 |
* Where this document isn't clear, refer to Amarok code. |
| 7 |
|
| 8 |
|
| 9 |
This C++ FAQ is a life saver in many situations, so you want to keep it handy: |
| 10 |
|
| 11 |
http://www.parashift.com/c++-faq-lite/ |
| 12 |
|
| 13 |
|
| 14 |
Formatting |
| 15 |
---------- |
| 16 |
* Spaces, not tabs |
| 17 |
* Indentation is 4 spaces |
| 18 |
* Lines should be limited to 90 characters |
| 19 |
* Spaces between brackets and argument functions |
| 20 |
* For pointer and reference variable declarations put a space between the type |
| 21 |
and the * or & and no space before the variable name. |
| 22 |
* For if, else, while and similar statements put the brackets on the next line, |
| 23 |
although brackets are not needed for single statements. |
| 24 |
* Function and class definitions have their brackets on separate lines |
| 25 |
* A function implementation's return type is on its own line. |
| 26 |
* CamelCase.{cpp,h} style file names. |
| 27 |
* Qt 4 includes a foreach keyword which makes it very easy to iterate over all |
| 28 |
elements of a container. |
| 29 |
|
| 30 |
Example: |
| 31 |
|
| 32 |
| bool |
| 33 |
| MyClass::myMethod( QStringList list, const QString &name ) |
| 34 |
| { |
| 35 |
| if( list.isEmpty() ) |
| 36 |
| return false; |
| 37 |
| |
| 38 |
| /* |
| 39 |
| Define the temporary variable like this to restrict its scope |
| 40 |
| when you do not need it outside the loop. Let the compiler |
| 41 |
| optimise it. |
| 42 |
| */ |
| 43 |
| foreach( const QString &string, list ) |
| 44 |
| debug() << "Current string is " << string << endl; |
| 45 |
| } |
| 46 |
|
| 47 |
|
| 48 |
Using "astyle" for auto formatting |
| 49 |
---------------------------------- |
| 50 |
The program astyle can be used to automatically format source code, which can |
| 51 |
be useful for badly formatted 3rd party patches. |
| 52 |
|
| 53 |
Use it like this to get (approximately) Amarok formatting style: |
| 54 |
|
| 55 |
"astyle -s4 -b -p -U -D -o source.cpp" |
| 56 |
|
| 57 |
|
| 58 |
Class, Function & Variable Naming |
| 59 |
--------------------------------- |
| 60 |
*Use CamelCase for everything. |
| 61 |
*Local variables should start out with a lowercase letter. |
| 62 |
*Class names are captialized |
| 63 |
*Prefix class member variables with m_, ex. m_trackList. |
| 64 |
*Prefix static member variables with s_, ex s_instance |
| 65 |
*Functions are named in the Qt style. It's like Java's, without the "get" |
| 66 |
prefix. |
| 67 |
*A getter is variable() |
| 68 |
*If it's a getter for a boolean, prefix with 'is', so isCondition() |
| 69 |
*A setter is setVariable( arg ). |
| 70 |
|
| 71 |
|
| 72 |
Includes |
| 73 |
-------- |
| 74 |
Header includes should be listed in the following order: |
| 75 |
- Own Header |
| 76 |
- Amarok includes |
| 77 |
- KDE includes |
| 78 |
- Qt includes |
| 79 |
|
| 80 |
They should also be sorted alphabetically, for ease of locating them. A small comment |
| 81 |
if applicable is also helpful. |
| 82 |
|
| 83 |
Includes in a header file should be kept to the absolute minimum, as to keep compile times |
| 84 |
low. This can be achieved by using "forward declarations" instead of includes, like |
| 85 |
"class QListView;" Forward declarations work for pointers and const references. |
| 86 |
|
| 87 |
TIP: |
| 88 |
Kate/KDevelop users can sort the headers automatically. Select the lines you want to sort, |
| 89 |
then Tools -> Filter Selection Through Command -> "sort". |
| 90 |
|
| 91 |
In vim the same can be achieved by marking the block, and then doing ":sort". |
| 92 |
|
| 93 |
Example: |
| 94 |
|
| 95 |
| #include "MySuperWidget.h" |
| 96 |
| |
| 97 |
| #include "Amarok.h" |
| 98 |
| #include "Debug.h" |
| 99 |
| #include "Playlist.h" |
| 100 |
| |
| 101 |
| #include <KDialogBase> //baseclass |
| 102 |
| #include <KPushButton> //see function... |
| 103 |
| |
| 104 |
| #include <QGraphicsView> |
| 105 |
| #include <QWidget> |
| 106 |
|
| 107 |
|
| 108 |
Comments |
| 109 |
-------- |
| 110 |
Comment your code. Don't comment what the code does, comment on the purpose of the code. It's |
| 111 |
good for others reading your code, and ultimately it's good for you too. |
| 112 |
|
| 113 |
Comments are essential when adding a strange hack, like the following example: |
| 114 |
|
| 115 |
| /** Due to xine-lib, we have to make K3Process close all fds, otherwise we get "device is busy" messages |
| 116 |
| * Used by AmarokProcIO and AmarokProcess, exploiting commSetupDoneC(), a virtual method that |
| 117 |
| * happens to be called in the forked process |
| 118 |
| * See bug #103750 for more information. |
| 119 |
| */ |
| 120 |
| class AmarokProcIO : public K3ProcIO |
| 121 |
| { |
| 122 |
| public: |
| 123 |
| virtual int commSetupDoneC() { |
| 124 |
| const int i = K3ProcIO::commSetupDoneC(); |
| 125 |
| Amarok::closeOpenFiles(K3ProcIO::out[0],K3ProcIO::in[0],K3ProcIO::err[0]); |
| 126 |
| return i; |
| 127 |
| } |
| 128 |
| }; |
| 129 |
|
| 130 |
|
| 131 |
For headers, use the Doxygen syntax. See: http://www.stack.nl/~dimitri/doxygen/ |
| 132 |
|
| 133 |
Example: |
| 134 |
|
| 135 |
| /** |
| 136 |
| * Start playback. |
| 137 |
| * @param offset Start playing at @p msec position. |
| 138 |
| * @return True for success. |
| 139 |
| */ |
| 140 |
| virtual bool play( uint offset = 0 ) = 0; |
| 141 |
|
| 142 |
|
| 143 |
Header Formatting |
| 144 |
----------------- |
| 145 |
General rules apply here. Please keep header function definitions aligned nicely, |
| 146 |
if possible. It helps greatly when looking through the code. Sorted methods, |
| 147 |
either by name or by their function (ie, group all related methods together) is |
| 148 |
great too. Access levels should be sorted in this order: public, protected, private. |
| 149 |
|
| 150 |
|
| 151 |
| #ifndef AMAROK_QUEUEMANAGER_H |
| 152 |
| #define AMAROK_QUEUEMANAGER_H |
| 153 |
|
| 154 |
| class QueueList : public K3ListView |
| 155 |
| { |
| 156 |
| Q_OBJECT |
| 157 |
| |
| 158 |
| public: |
| 159 |
| Queuelist( QWidget *parent, const char *name = 0 ); |
| 160 |
| ~QueueList() {}; |
| 161 |
| |
| 162 |
| public slots: |
| 163 |
| void moveSelectedUp(); |
| 164 |
| void moveSelectedDown(); |
| 165 |
| }; |
| 166 |
|
| 167 |
#endif /* AMAROK_QUEUEMANAGER_H */ |
| 168 |
|
| 169 |
|
| 170 |
0 vs NULL |
| 171 |
--------- |
| 172 |
The use of 0 to express a null pointer is preferred over the use of NULL. |
| 173 |
0 is not a magic value, it's the defined value of the null pointer in C++. |
| 174 |
NULL, on the other hand, is a preprocessor directive (#define) and not only is |
| 175 |
it more typing than '0' but preprocessor directives are less elegant. |
| 176 |
|
| 177 |
| SomeClass *instance = 0; |
| 178 |
|
| 179 |
|
| 180 |
Const Correctness |
| 181 |
----------------- |
| 182 |
Try to keep your code const correct. Declare methods const if they don't mutate the object, |
| 183 |
and use const variables. It improves safety, and also makes it easier to understand the code. |
| 184 |
|
| 185 |
See: http://www.parashift.com/c++-faq-lite/const-correctness.html |
| 186 |
|
| 187 |
|
| 188 |
Example: |
| 189 |
|
| 190 |
| bool |
| 191 |
| MyClass::isValidFile( const QString& path ) const |
| 192 |
| { |
| 193 |
| const bool valid = QFile::exist( path ); |
| 194 |
| |
| 195 |
| return valid; |
| 196 |
| } |
| 197 |
|
| 198 |
|
| 199 |
Debugging |
| 200 |
--------- |
| 201 |
debug.h contains some handy functions for our debug console output. |
| 202 |
Please use them instead of kDebug(). |
| 203 |
|
| 204 |
Usage: |
| 205 |
|
| 206 |
| #include "debug.h" |
| 207 |
| |
| 208 |
| debug() << "Something is happening" << endl; |
| 209 |
| warning() << "Something bad may happen" << endl; |
| 210 |
| error() << "Something bad did happen!" << endl; |
| 211 |
|
| 212 |
Additionally, there are some macros for debugging functions: |
| 213 |
|
| 214 |
DEBUG_BLOCK |
| 215 |
DEBUG_FUNC_INFO |
| 216 |
DEBUG_LINE_INFO |
| 217 |
DEBUG_INDENT |
| 218 |
DEBUG_UNINDENT |
| 219 |
|
| 220 |
AMAROK_NOTIMPLEMENTED |
| 221 |
AMAROK_DEPRECATED |
| 222 |
|
| 223 |
threadweaver.h has two additional macros: |
| 224 |
DEBUG_THREAD_FUNC_INFO outputs the memory address of the current QThread or 'none' |
| 225 |
if its the original GUI thread. |
| 226 |
SHOULD_BE_GUI outputs a warning message if it occurs in a thread that isn't in |
| 227 |
the original "GUI Thread", otherwise it is silent. Useful for documenting |
| 228 |
functions and to prevent problems in the future. |
| 229 |
|
| 230 |
|
| 231 |
Errors & Asserts |
| 232 |
---------------- |
| 233 |
*Never use assert() or fatal(). There must be a better option than crashing a user's |
| 234 |
application (its not uncommon for end-users to have debugging enabled). |
| 235 |
|
| 236 |
*KMessageBox is fine to use to prompt the user, but do not use it to display errors |
| 237 |
or informational messages. Instead, KDE::StatusBar has a few handy methods. Refer to |
| 238 |
amarok/src/statusbar/statusBarBase.h |
| 239 |
|
| 240 |
|
| 241 |
Commenting Out Code |
| 242 |
------------------- |
| 243 |
Don't keep commented out code. It just causes confusion and makes the source |
| 244 |
harder to read. Remember, the last revision before your change is always |
| 245 |
availabe in SVN. Hence no need for leaving cruft in the source. |
| 246 |
|
| 247 |
Wrong: |
| 248 |
| myWidget->show(); |
| 249 |
| //myWidget->rise(); //what is this good for? |
| 250 |
|
| 251 |
Correct: |
| 252 |
| myWidget->show(); |
| 253 |
|
| 254 |
|
| 255 |
Tips & Tricks |
| 256 |
------------- |
| 257 |
A useful service is http://lxr.kde.org. Lxr is a cross reference of the entire |
| 258 |
KDE SVN repository. You can for instance use it to search for example code |
| 259 |
from other applications for a given KDElibs method. |
| 260 |
|
| 261 |
Markey's .vimrc |
| 262 |
--------------- |
| 263 |
|
| 264 |
let ruby_no_expensive = 1 |
| 265 |
syntax on |
| 266 |
|
| 267 |
set shiftwidth=4 |
| 268 |
set tabstop=4 |
| 269 |
set expandtab |
| 270 |
set hlsearch |
| 271 |
set ruler |
| 272 |
set smartindent |
| 273 |
set nowrap |
| 274 |
|
| 275 |
set ignorecase |
| 276 |
set smartcase |
| 277 |
|
| 278 |
set title |
| 279 |
set showtabline=2 "Makes the status bar always show, also for just one tab |
| 280 |
|
| 281 |
autocmd FileType ruby set shiftwidth=2 tabstop=2 |
| 282 |
|
| 283 |
Git and SVN aware prompt |
| 284 |
---------------- |
| 285 |
The following prompt shows the current git branch if sitting in a git repository. |
| 286 |
Random crap courtesy of shell colours. |
| 287 |
export PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\[\033[01;33m\]`git branch 2>/dev/null|cut -f2 -d\* -s`\[\033[00m\]\$ ' |
| 288 |
|
| 289 |
This is an even more colorful configuration for .bashrc that displays the |
| 290 |
current git branch if sitting in a git repository and the current SVN revision |
| 291 |
if sitting in an SVN checkout. |
| 292 |
svn_prompt() { |
| 293 |
SVNBRANCH=`svn info 2>/dev/null | grep Revision: | cut -f 2 -d " "` |
| 294 |
if [ -n "$SVNBRANCH" ]; then |
| 295 |
BRANCH=" (r$SVNBRANCH)"; |
| 296 |
else |
| 297 |
BRANCH=""; |
| 298 |
fi |
| 299 |
echo "$BRANCH" |
| 300 |
} |
| 301 |
export PS1='\[\e[0;32m\]\u@\h\[\e[m\] \[\e[1;34m\]\w\[\e[m\]\[\033[01;33m\]`__git_ps1`\[\e[m\]\[\e[01;35m\]`svn_prompt`\[\e[m\]\[\033[00m\] \[\e[1;32m\]\$ \[\e[m\]\[\e[1;37m\] ' |
| 302 |
|
| 303 |
Copyright |
| 304 |
--------- |
| 305 |
To comply with the GPL, add your name, email address & the year to the top of any file |
| 306 |
that you edit. If you bring in code or files from elsewhere, make sure its |
| 307 |
GPL-compatible and to put the authors name, email & copyright year to the top of |
| 308 |
those files. |
| 309 |
|
| 310 |
Please note that it is not sufficient to write a pointer to the license (like a URL). |
| 311 |
The complete license header needs to be written everytime. |
| 312 |
|
| 313 |
|
| 314 |
Thanks, now have fun! |
| 315 |
-- the Amarok developers |