mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-06 00:30:08 +00:00
636 lines
16 KiB
Plaintext
636 lines
16 KiB
Plaintext
|
GTK+ Coding Style
|
||
|
-------------------------------------------------------------------------------
|
||
|
|
||
|
This document is intended to be a short description of the preferred
|
||
|
coding style to be used for the GTK+ source code. It was strongly
|
||
|
inspired by Clutter's CODING_STYLE.
|
||
|
|
||
|
Coding style is a matter of consistency, readability and maintainance;
|
||
|
coding style is also completely arbitrary and a matter of taste. This
|
||
|
document will use examples at the very least to provide authoritative
|
||
|
and consistent answers to common questions regarding the coding style,
|
||
|
and will also try to identify the allowed exceptions.
|
||
|
|
||
|
The examples will show the preferred coding style; the negative examples
|
||
|
will be clearly identified. Please, don't submit code to GTK+ that
|
||
|
looks like any of these.
|
||
|
|
||
|
Part of the rationales for these coding style rules are available either
|
||
|
in the kernel CodingStyle document or in Cairo's CODING_STYLE one.
|
||
|
|
||
|
When in doubt, check the surrounding code and try to imitate it.
|
||
|
|
||
|
+ Line width
|
||
|
|
||
|
The maximum line width for source files is 80 characters, whenever possible.
|
||
|
Longer lines are usually an indication that you either need a function
|
||
|
or a pre-processor macro.
|
||
|
|
||
|
+ Indentation
|
||
|
|
||
|
Each new level is indented 2 or more spaces than the previous level:
|
||
|
|
||
|
if (condition)
|
||
|
single_statement ();
|
||
|
|
||
|
This can only be achieved using space characters. It may not be achieved
|
||
|
using tab characters alone, or using a combination of spaces and tabs.
|
||
|
|
||
|
Do not change the editor's configuration to change the meaning of a
|
||
|
tab character (see below); code using tabs to indent will not be accepted
|
||
|
into GTK+.
|
||
|
|
||
|
Even if two spaces for each indentation level allows deeper nesting than
|
||
|
8 spaces, GTK+ favours self-documenting function names that can take
|
||
|
quite some space. For this reason you should avoid deeply nested code.
|
||
|
|
||
|
+ Tab characters
|
||
|
|
||
|
The tab character must always be expanded to spaces. If a literal
|
||
|
tab must be used inside the source, the tab must always be interpreted
|
||
|
according to its traditional meaning:
|
||
|
|
||
|
Advance to the next column which is a multiple of 8.
|
||
|
[ these two lines should be aligned ]
|
||
|
|
||
|
+ Braces
|
||
|
|
||
|
Curly braces should not be used for single statement blocks:
|
||
|
|
||
|
if (condition)
|
||
|
single_statement ();
|
||
|
else
|
||
|
another_single_statement (arg1);
|
||
|
|
||
|
In case of multiple statements, curly braces should be put on another
|
||
|
indentation level:
|
||
|
|
||
|
if (condition)
|
||
|
{
|
||
|
statement_1 ();
|
||
|
statement_2 ();
|
||
|
statement_3 ();
|
||
|
}
|
||
|
|
||
|
The "no block for single statements" rule has only four exceptions:
|
||
|
|
||
|
① if the single statement covers multiple lines, e.g. for functions with
|
||
|
many arguments, and it is followed by else or else if:
|
||
|
|
||
|
/* valid */
|
||
|
if (condition)
|
||
|
{
|
||
|
a_single_statement_with_many_arguments (some_lengthy_argument,
|
||
|
another_lengthy_argument,
|
||
|
and_another_one,
|
||
|
plus_one);
|
||
|
}
|
||
|
else
|
||
|
another_single_statement (arg1, arg2);
|
||
|
|
||
|
② if the condition is composed of many lines:
|
||
|
|
||
|
/* valid */
|
||
|
if (condition1 ||
|
||
|
(condition2 && condition3) ||
|
||
|
condition4 ||
|
||
|
(condition5 && (condition6 || condition7)))
|
||
|
{
|
||
|
a_single_statement ();
|
||
|
}
|
||
|
|
||
|
③ Nested if's, in which case the block should be placed on the
|
||
|
outermost if:
|
||
|
|
||
|
/* valid */
|
||
|
if (condition)
|
||
|
{
|
||
|
if (another_condition)
|
||
|
single_statement ();
|
||
|
else
|
||
|
another_single_statement ();
|
||
|
}
|
||
|
|
||
|
/* invalid */
|
||
|
if (condition)
|
||
|
if (another_condition)
|
||
|
single_statement ();
|
||
|
else if (yet_another_condition)
|
||
|
another_single_statement ();
|
||
|
|
||
|
④ If either side of an if-else statement has braces, both sides
|
||
|
should, to match up indentation:
|
||
|
|
||
|
/* valid */
|
||
|
if (condition)
|
||
|
{
|
||
|
foo ();
|
||
|
bar ();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
baz ();
|
||
|
}
|
||
|
|
||
|
/* invalid */
|
||
|
if (condition)
|
||
|
{
|
||
|
foo ();
|
||
|
bar ();
|
||
|
}
|
||
|
else
|
||
|
baz ();
|
||
|
|
||
|
In general, new blocks should be placed on a new indentation level,
|
||
|
like:
|
||
|
|
||
|
int retval = 0;
|
||
|
|
||
|
statement_1 ();
|
||
|
statement_2 ();
|
||
|
|
||
|
{
|
||
|
int var1 = 42;
|
||
|
gboolean res = FALSE;
|
||
|
|
||
|
res = statement_3 (var1);
|
||
|
|
||
|
retval = res ? -1 : 1;
|
||
|
}
|
||
|
|
||
|
While curly braces for function definitions should rest on a new line
|
||
|
they should not add an indentation level:
|
||
|
|
||
|
/* valid */
|
||
|
static void
|
||
|
my_function (int argument)
|
||
|
{
|
||
|
do_my_things ();
|
||
|
}
|
||
|
|
||
|
/* invalid */
|
||
|
static void
|
||
|
my_function (int argument) {
|
||
|
do_my_things ();
|
||
|
}
|
||
|
|
||
|
/* invalid */
|
||
|
static void
|
||
|
my_function (int argument)
|
||
|
{
|
||
|
do_my_things ();
|
||
|
}
|
||
|
|
||
|
Curly braces must not be placed on the same line as a condition:
|
||
|
|
||
|
/* invalid */
|
||
|
if (condition) {
|
||
|
statement_1 ();
|
||
|
statement_2 ();
|
||
|
}
|
||
|
+ Conditions
|
||
|
|
||
|
Do not check boolean values for equality:
|
||
|
|
||
|
/* invalid */
|
||
|
if (condition == TRUE)
|
||
|
do_foo ();
|
||
|
|
||
|
/* valid */
|
||
|
if (another_condition)
|
||
|
do_bar ();
|
||
|
|
||
|
Even if C handles NULL equality like a boolean, be explicit:
|
||
|
|
||
|
/* valid */
|
||
|
if (some_pointer == NULL)
|
||
|
do_blah ();
|
||
|
|
||
|
/* invalid */
|
||
|
if (some_other_pointer)
|
||
|
do_blurp ();
|
||
|
|
||
|
In case of conditions split over multiple lines, the logical operators should
|
||
|
always go at the end of the line:
|
||
|
|
||
|
/* invalid */
|
||
|
if (condition1
|
||
|
|| condition2
|
||
|
|| condition3)
|
||
|
{
|
||
|
do_foo ();
|
||
|
}
|
||
|
|
||
|
/* valid */
|
||
|
if (condition1 &&
|
||
|
condition2 &&
|
||
|
(condition3 || (condition4 && condition5)))
|
||
|
{
|
||
|
do_blah ();
|
||
|
}
|
||
|
|
||
|
+ Functions
|
||
|
|
||
|
Functions should be declared by placing the returned value on a separate
|
||
|
line from the function name:
|
||
|
|
||
|
void
|
||
|
my_function (void)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
The arguments list must be broken into a new line for each argument,
|
||
|
with the argument names right aligned, taking into account pointers:
|
||
|
|
||
|
void
|
||
|
my_function (some_type_t type,
|
||
|
another_type_t *a_pointer,
|
||
|
final_type_t another_type)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
The alignment also holds when invoking a function without breaking the
|
||
|
80 characters limit:
|
||
|
|
||
|
align_function_arguments (first_argument,
|
||
|
second_argument,
|
||
|
third_argument);
|
||
|
|
||
|
To respect the 80 characters limit do not break the function name from
|
||
|
the arguments:
|
||
|
|
||
|
/* invalid */
|
||
|
a_very_long_function_name_with_long_parameters
|
||
|
(argument_the_first, argument_the_second);
|
||
|
|
||
|
/* valid */
|
||
|
first_a = argument_the_first;
|
||
|
second_a = argument_the_second;
|
||
|
a_very_long_function_name_with_long_parameters (first_a, second_a);
|
||
|
|
||
|
+ Whitespace
|
||
|
|
||
|
Always put a space before a parenthesis but never after:
|
||
|
|
||
|
/* valid */
|
||
|
if (condition)
|
||
|
do_my_things ();
|
||
|
|
||
|
/* valid */
|
||
|
switch (condition)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/* invalid */
|
||
|
if(condition)
|
||
|
do_my_things();
|
||
|
|
||
|
/* invalid */
|
||
|
if ( condition )
|
||
|
do_my_things ( );
|
||
|
|
||
|
A switch() should open a block on a new indentation level, and each case
|
||
|
should start on the same indentation level as the curly braces, with the
|
||
|
case block on a new indentation level:
|
||
|
|
||
|
/* valid */
|
||
|
switch (condition)
|
||
|
{
|
||
|
case FOO:
|
||
|
do_foo ();
|
||
|
break;
|
||
|
|
||
|
case BAR:
|
||
|
do_bar ();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* invalid */
|
||
|
switch (condition) {
|
||
|
case FOO: do_foo (); break;
|
||
|
case BAR: do_bar (); break;
|
||
|
}
|
||
|
|
||
|
/* invalid */
|
||
|
switch (condition)
|
||
|
{
|
||
|
case FOO: do_foo ();
|
||
|
break;
|
||
|
case BAR: do_bar ();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* invalid */
|
||
|
switch (condition)
|
||
|
{
|
||
|
case FOO:
|
||
|
do_foo ();
|
||
|
break;
|
||
|
case BAR:
|
||
|
do_bar ();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
It is preferable, though not mandatory, to separate the various cases with
|
||
|
a newline:
|
||
|
|
||
|
switch (condition)
|
||
|
{
|
||
|
case FOO:
|
||
|
do_foo ();
|
||
|
break;
|
||
|
|
||
|
case BAR:
|
||
|
do_bar ();
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
do_default ();
|
||
|
}
|
||
|
|
||
|
The 'break' statement for the default: case is not mandatory.
|
||
|
|
||
|
If a case block needs to declare new variables, the same rules as the
|
||
|
inner blocks (see above) apply; the break statement should be placed
|
||
|
outside of the inner block:
|
||
|
|
||
|
switch (condition)
|
||
|
{
|
||
|
case FOO:
|
||
|
{
|
||
|
int foo;
|
||
|
|
||
|
foo = do_foo ();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
...
|
||
|
}
|
||
|
|
||
|
When declaring a structure type use newlines to separate logical sections
|
||
|
of the structure:
|
||
|
|
||
|
struct _GtkWrapBoxPrivate
|
||
|
{
|
||
|
GtkOrientation orientation;
|
||
|
GtkWrapAllocationMode mode;
|
||
|
|
||
|
GtkWrapBoxSpreading horizontal_spreading;
|
||
|
GtkWrapBoxSpreading vertical_spreading;
|
||
|
|
||
|
guint16 vertical_spacing;
|
||
|
guint16 horizontal_spacing;
|
||
|
|
||
|
guint16 minimum_line_children;
|
||
|
guint16 natural_line_children;
|
||
|
|
||
|
GList *children;
|
||
|
};
|
||
|
|
||
|
|
||
|
Do not eliminate whitespace and newlines just because something would
|
||
|
fit on 80 characters:
|
||
|
|
||
|
/* invalid */
|
||
|
if (condition) foo (); else bar ();
|
||
|
|
||
|
Do eliminate trailing whitespace on any line, preferably as a separate
|
||
|
patch or commit. Never use empty lines at the beginning or at the end of
|
||
|
a file.
|
||
|
|
||
|
Do enable the default git pre-commit hook that detect trailing
|
||
|
whitespace for you and help you to avoid corrupting GTK+'s tree with
|
||
|
it. Do that as follows:
|
||
|
|
||
|
chmod a+x .git/hooks/pre-commit
|
||
|
|
||
|
You might also find the git-stripspace utility helpful which acts as a
|
||
|
filter to remove trailing whitespace as well as initial, final, and
|
||
|
duplicate blank lines.
|
||
|
|
||
|
+ Headers
|
||
|
|
||
|
Headers are special, for GTK+, in that they don't have to obey the
|
||
|
80 characters limit. The only major rule for headers is that the function
|
||
|
definitions should be vertically aligned in three columns:
|
||
|
|
||
|
return value function_name (type argument,
|
||
|
type argument,
|
||
|
type argument);
|
||
|
|
||
|
The maximum width of each column is given by the longest element in the
|
||
|
column:
|
||
|
|
||
|
void gtk_type_set_property (GtkType *type,
|
||
|
const gchar *value,
|
||
|
GError **error);
|
||
|
G_CONST_RETURN gchar *gtk_type_get_property (GtkType *type);
|
||
|
|
||
|
It is also possible to align the columns to the next tab:
|
||
|
|
||
|
void gtk_type_set_prop (GtkType *type,
|
||
|
gfloat value);
|
||
|
gfloat gtk_type_get_prop (GtkType *type);
|
||
|
gint gtk_type_update_foobar (GtkType *type);
|
||
|
|
||
|
Public headers should never be included directly:
|
||
|
|
||
|
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||
|
#error "Only <gtk/gtk.h> can be included directly."
|
||
|
#endif
|
||
|
|
||
|
All headers should have inclusion guards (for internal usage)
|
||
|
and C++ guards:
|
||
|
|
||
|
#ifndef __GTK_FOO_H__
|
||
|
#define __GTK_FOO_H__
|
||
|
|
||
|
#include <gtk/gtk-bar.h>
|
||
|
|
||
|
G_BEGIN_DECLS
|
||
|
|
||
|
...
|
||
|
|
||
|
G_END_DECLS
|
||
|
|
||
|
#endif /* __GTK_FOO_H__ */
|
||
|
|
||
|
+ Includes
|
||
|
|
||
|
GTK+ source files should never include the global gtk.h header, but
|
||
|
instead include the individual headers that are needed. Every file must
|
||
|
include config.h first, then its own header, then other GTK+ headers
|
||
|
that it needs, then system and third-party headers that it needs.
|
||
|
|
||
|
/* valid */
|
||
|
#include "config.h"
|
||
|
|
||
|
#include "gtkfoo.h"
|
||
|
|
||
|
#include "gtkwidget.h"
|
||
|
#include "gtkbutton.h"
|
||
|
|
||
|
...
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
|
||
|
+ GObject
|
||
|
|
||
|
GObject classes definition and implementation require some additional
|
||
|
coding style notices.
|
||
|
|
||
|
Typedef declarations should be placed at the beginning of the file:
|
||
|
|
||
|
typedef struct _GtkFoo GtkFoo;
|
||
|
typedef struct _GtkFooClass GtkFooClass;
|
||
|
typedef struct _GtkFooPrivate GtkFooPrivate;
|
||
|
|
||
|
This includes enumeration types:
|
||
|
|
||
|
typedef enum
|
||
|
{
|
||
|
GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT,
|
||
|
GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH
|
||
|
} GtkSizeRequestMode;
|
||
|
|
||
|
And callback types:
|
||
|
|
||
|
typedef void (* GtkCallback) (GtkWidget *widget,
|
||
|
gpointer user_data);
|
||
|
|
||
|
Instance structures should only contain the parent type and a pointer to a
|
||
|
private data structure, and they should be annotated as "private":
|
||
|
|
||
|
struct _GtkFoo
|
||
|
{
|
||
|
/*< private >*/
|
||
|
GtkWidget parent_instance;
|
||
|
|
||
|
GtkFooPrivate *priv;
|
||
|
};
|
||
|
|
||
|
All the properties should be stored inside the private data structure, which
|
||
|
is defined inside the source file - or, if needed, inside a private header
|
||
|
file; the private header filename must end with "private.h" and must not be
|
||
|
installed.
|
||
|
|
||
|
The private data structure should only be accessed internally using the
|
||
|
pointer inside the instance structure, and never using the
|
||
|
G_TYPE_INSTANCE_GET_PRIVATE() macro or the g_type_instance_get_private()
|
||
|
function.
|
||
|
|
||
|
Always use the G_DEFINE_TYPE(), G_DEFINE_TYPE_WITH_CODE() macros, or
|
||
|
their abstract variants G_DEFINE_ABSTRACT_TYPE() and
|
||
|
G_DEFINE_ABSTRACT_TYPE_WITH_CODE(), and the similar macros for defining
|
||
|
interfaces.
|
||
|
|
||
|
Interface types should always have the dummy typedef for cast purposes:
|
||
|
|
||
|
typedef struct _GtkFoo GtkFoo;
|
||
|
|
||
|
The interface structure should have "Interface" postfixed to the dummy typedef:
|
||
|
|
||
|
typedef struct _GtkFooInterface GtkFooInterface;
|
||
|
|
||
|
Interfaces must have the following macros:
|
||
|
|
||
|
- Macro: - Expands to:
|
||
|
• GTK_TYPE_<iface_name> <iface_name>_get_type
|
||
|
• GTK_<iface_name> G_TYPE_CHECK_INSTANCE_CAST
|
||
|
• GTK_IS_<iface_name> G_TYPE_CHECK_INSTANCE_TYPE
|
||
|
• GTK_<iface_name>_GET_IFACE G_TYPE_INSTANCE_GET_INTERFACE
|
||
|
|
||
|
+ Memory allocation
|
||
|
|
||
|
When dynamically allocating data on the heap either use g_new() or,
|
||
|
if allocating multiple small data structures, g_slice_new().
|
||
|
|
||
|
Public structure types should always be returned after being zero-ed,
|
||
|
either explicitly for each member, or by using g_new0() or g_slice_new0().
|
||
|
|
||
|
+ Macros
|
||
|
|
||
|
Try to avoid private macros unless strictly necessary. Remember to #undef
|
||
|
them at the end of a block or a series of functions needing them.
|
||
|
|
||
|
Inline functions are usually preferable to private macros.
|
||
|
|
||
|
Public macros should not be used unless they evaluate to a constant.
|
||
|
|
||
|
+ Public API
|
||
|
|
||
|
Avoid exporting variables as public API, since this is cumbersome on some
|
||
|
platforms. It is always preferable to add getters and setters instead.
|
||
|
|
||
|
All public functions must be listed in the gtk.symbols file.
|
||
|
|
||
|
+ Private API
|
||
|
|
||
|
Non-exported functions that are needed in more than one source file
|
||
|
should be named "_gtk_...", and declared in a private header file.
|
||
|
|
||
|
Underscore-prefixed functions are never exported.
|
||
|
|
||
|
Non-exported functions that are only needed in one source file
|
||
|
should be declared static.
|
||
|
|
||
|
+ Documentation
|
||
|
|
||
|
All public APIs must have gtk-doc comments. For functions, these should
|
||
|
be placed in the source file, directly above the function.
|
||
|
|
||
|
/* valid */
|
||
|
/**
|
||
|
* gtk_get_flow:
|
||
|
* @widget: a #GtkWidget
|
||
|
*
|
||
|
* Gets the flow of a widget.
|
||
|
*
|
||
|
* Note that flows may be laminar or turbulent...
|
||
|
*
|
||
|
* Returns: (transfer none): the flow of @widget
|
||
|
*/
|
||
|
GtkFlow *
|
||
|
gtk_get_flow (GtkWidget *widget)
|
||
|
{
|
||
|
|
||
|
...
|
||
|
|
||
|
}
|
||
|
|
||
|
Doc comments for macros, function types, class structs, etc should be
|
||
|
placed next to the definitions, typically in headers.
|
||
|
|
||
|
Section introductions should be placed in the source file they describe,
|
||
|
after the license header:
|
||
|
|
||
|
/* valid */
|
||
|
/**
|
||
|
* SECTION:gtksizerequest
|
||
|
* @Short_Description: Height-for-width geometry management
|
||
|
* @Title: GtkSizeRequest
|
||
|
*
|
||
|
* The GtkSizeRequest interface is GTK+'s height-for-width (and
|
||
|
* width-for-height) geometry management system.
|
||
|
* ...
|
||
|
*/
|
||
|
|
||
|
To properly document a new function, macro, function type or struct,
|
||
|
it needs to be listed in the gtk3-sections.txt file.
|
||
|
|
||
|
To properly document a new class, it needs to be given its own section
|
||
|
in gtk3-sections.txt, needs to be included in gtk-docs.sgml, and the
|
||
|
get_type function needs to listed in gtk3.types.
|
||
|
|
||
|
+ Old code
|
||
|
|
||
|
New code that is being added to GTK+ should adhere to the style
|
||
|
explained above. Existing GTK+ code does largely follow these
|
||
|
conventions, but there are some differences, e.g. occurrences
|
||
|
of tabs, etc.
|
||
|
|
||
|
It is ok to update the style of a code block or function when you
|
||
|
are touching it anyway, but sweeping whitespace changes obscure the
|
||
|
git history and should be avoided.
|