When working on Glib/GTK+, there are several points one should consider, to keep the code in shape.

Good habits

  • Keep declarations at the start of the block. Some compilers require that. (Or just use -Wdeclaration-after-statement)

    • See below, for no C99.

  • Use a private structure for all instance data
    • Either use G_DEFINE_WITH_PRIVATE or G_ADD_PRIVATE with G_DEFINE_WITH_CODE when declaring types

  • Private functions that can be used from multiple compilation units need to either have their name start with an underscore, or be marked as G_GNUC_INTERNAL when declaring them.

  • Private functions that can be used from multiple compilation units should go into the private header of the class they refer to.
  • Private functions that are only used from a single compilation unit should be marked as static and not start with an underscore.

  • Update gtk.symbols if you're adding new public functions.
  • Always use inline documentation for new public types, functions, and macros.
  • Add Since: tags pointing to the next stable release when adding API.
  • Instead of multiple GTK_FOO (widget) casts, declare GtkFoo *foo = GTK_FOO (widget); once.

  • Always include config.h, and always include it first.
  • Check that your commit doesn't introduce warnings (shouldn't -Wall -Werror be enabled at least in the buildbots?)
  • Use the versioned macros for marking deprecated API in headers: GLIB_DEPRECATED_IN_X_Y, GLIB_DEPRECATED_IN_X_Y_FOR(), GDK_DEPRECATED_IN_X_Y, GDK_DEPRECATED_IN_X_Y_FOR()
  • Use the versioned macros for marking new API in headers: GLIB_AVAILABLE_IN_X_Y, GDK_AVAILABLE_IN_X_Y
  • Every new public header must have an unconditional single-include guard.
  • Keep the inclusions in the global headers (gdk.h, gtk.h, etc) sorted alphabetically.

Coding Style

  • GTK+ coding style

  • GTK+ is pretty much kept GNU style, with a few exceptions. While the maintainers are not religious over stylistic issues, it is good to maintain consistent habits.

  • No C99 comments or declarations.
    • Rationale: we expect GLib and GTK+ to be buildable on various compilers with only C89 support.

  • Avoid trailing whitespace, check your editor settings.
    • Suggestion: enable a pre-commit hook in Git to avoid committing unnecessary trailing whitespace, for instance: here.

  • Use two spaces for indentation.
    • Use real spaces. Do not change the length of the tab character in your editor to 2 spaces.

  • When breaking conditions, use trailing boolean operators:
    •    if (you_need_to_break_this ||
             the_line_was_too_long)
           {
             ...
  • Use GtkFoo *bar_foo = GTK_FOO (bar) instead of GtkFoo *foo_bar = GTK_FOO (bar)

Quality of Implementation

Widgets in GTK+ are supposed to be general-purpose and high-quality, and are expected to be well-behaved in areas such as the following:

  • Documentation
    • GTK-Doc annotation for public functions, types, enumerations and macros
    • Internal documentation for data types and functions
    • Introspection annotations
  • Themability, including
    • Colors
    • Fonts
    • Sizes
  • Binding-friendlyness, including
    • full property support
    • trivial _new() functions
    • introspection annotations
    • vector-based variant for each variadic arguments function
  • GtkBuilder support

  • Internationalization, including
    • Translations
    • Input methods
    • RTL flipping
  • Accessibility, including
    • Atk interface
    • Key navigation
  • Platform support, including
    • Respecting GTK+ settings where appropriate
    • Use GdkModifierIntent when handling events

  • Multi-monitor awareness when positioning popups
  • DND support, where appropriate
  • Examples of usage
    • gtk3-demo
    • gtk3-widget-factory
  • Tests

Widgets

This is the 'state of the art' way to write new GObjects:

  • Widgets are patched during the 3.0 ABI break so their currently public struct members are moved to GtkFooPrivate.

  • g_type_class_add_private() the GtkFooPrivate struct to prevent some fragmentation.

  • Add a GtkFooPrivate* to the object's public struct, populate it during gtk_foo_init() with a single G_TYPE_INSTANCE_GET_PRIVATE() call to speed up access and prevent duplicate GtkFooPrivate *priv = G_TYPE_INSTANCE_... lines.

  • Accessing members can be done via a local pointer to widget->priv in each method.

  • For some cases, introducing a private header can be used instead of using accessor functions, depending which is more appropriate.

You can see an example here: GtkAlignment migration

Advantages:

  • Roughly as fast as before, low memory overhead
  • Code is future-proof and much easier to maintain with proper encapsulation

Classes

  • Every signal handler, unless discussed, should have a default handler in the class vtable.
    • If the class vtable is running out of padding, and after discussing it, pass 0 to the class_offset argument of g_signal_new(). If you need to override the class handler in a sub-class, use g_signal_override_class_handler() (available since GLib >= 2.18) or g_signal_override_class_closure().

Be binding friendly

Take a look at these notes: Writing bindingable APIs

Projects/GTK+/BestPractices (last edited 2016-01-28 20:36:38 by SébastienWilmet)