General Rules#

Different projects might use different styles. General guidelines are:

  • Check the project’s CONTRIBUTING.md or HACKING.md for details
  • Format code like the surrounding code in the same file

GObject C Based Projects#

For C projects using GObject we mostly use kernel style, but

  • Use spaces, never tabs
  • Use 2 spaces for indentation

Here are more details:

GTK-style Function Argument Indentation#

If function arguments don’t fit into a single line, use GTK style alignment:

static gboolean
on_key_press_event (GtkWidget *widget,
                    GdkEvent  *event,
                    gpointer   data)

Braces#

Everything except functions and structs should have the opening curly brace on the same line.

Good:

if (i < 0) {
  ...
}

Bad:

if (i < 0)
{
  ...
}

Single-line if or else statements don’t need braces, but if either branch uses braces, both must:

Good:

if (i < 0)
  i++;
else
  i--;
if (i < 0) {
  i++;
  j++;
} else {
  i--;
}
if (i < 0) {
  i++;
} else {
  i--;
  j--;
}

Bad:

if (i < 0) {
  i++;
} else {
  i--;
}
if (i < 0) {
  i++;
  j++;
} else
  i--;
if (i < 0)
  i++;
else {
  i--;
  j--;
}

Function calls have a space between function name and invocation:

Good:

visible_child_name = gtk_stack_get_visible_child_name (GTK_STACK (self->stack));

Bad:

visible_child_name = gtk_stack_get_visible_child_name(GTK_STACK(self->stack));

Header Inclusion Guards#

Guard header inclusion with #pragma once rather than the traditional #ifndef-#define-#endif trio.

Comment style#

In comments use full sentences with proper capitalization and punctuation. Use C-style comments /* … */, avoid C++ style comments //.

Good:

/* Make sure we don't overflow. */

Bad:

/* overflow check */

Static functions#

Static functions use the class prefix but it can be dropped to shorten the method name. E.g. with a type PhoshDialer both work:

Good:

static void
grab_focus_cb (PhoshDialer *dialer, gpointer unused)
static void
phosh_dialer_grab_focus_cb (PhoshDialer *dialer, gpointer unused)

Note however, that virtual methods like <class_name>_{init,constructed,finalize,dispose} always use the class prefix. These functions are usually never called directly but only assigned once in <class_name>_constructed so the longer name is acceptable. This also helps to distinguish virtual methods from regular private methods.

Self argument#

The first argument is usually the object itself so call it self. E.g. for a static function:

Good:

static gboolean
on_expire (FooButton *self)
{
  g_return_val_if_fail (BAR_IS_FOO_BUTTON (self), FALSE);
  ...
  return FALSE;
}

And for a public function:

Good:

int
foo_button_get_state (FooButton *self)
{
  FooButtonPrivate *priv = foo_button_get_instance_private(self);

  g_return_if_fail (FOO_IS_BUTTON (self));

  g_return_val_if_fail (FOO_IS_BUTTON (self), -1);
  return priv->state;
}

Source file layout#

We use one file per GObject named like the GObject lowercase and ‘_’ replaced by ‘-’. So a hypothetical PhoshThing would go to src/thing.c. If there are likely name clashes, add the phosh- prefix (e.g. phosh-wayland.c). The individual C files should be structured as (top to bottom of file):

  • License boilerplate

    /*
     * Copyright (C) year copyright holder
     *
     * SPDX-License-Identifier: GPL-3-or-later
     * Author: you <youremail@example.com>
     */
  • A log domain, usually the filename with phosh- prefix

    #define G_LOG_DOMAIN "phosh-thing"
  • #includes: Phosh ones go first, then glib/gtk, then generic C headers. These blocks are separated by newline and each sorted alphabetically:

    #define G_LOG_DOMAIN "phosh-settings"
    
    #include "phosh-config.h"
    
    #include "settings.h"
    #include "shell-priv.h"
    
    #include <gio/gdesktopappinfo.h>
    #include <glib/glib.h>
    
    #include <math.h>

    This helps to detect missing headers in includes.

  • docstring: If you have trouble describing the class concisely, then it might be an indication that it should be split into multiple classes.

    /**
     * PhoshYourThing:
     *
     * Short, single line, summary
     *
     * A longer description with details that can be
     * multiline.
     *
     * Since: 0.44.0
     */
  • property enum

    enum {
      PROP_0,
      PROP_FOO,
      PROP_BAR,
      LAST_PROP
    };
    static GParamSpec *props[LAST_PROP];
  • signal enum

    enum {
      FOO_HAPPENED,
      BAR_TRIGGERED,
      N_SIGNALS
    };
    static guint signals[N_SIGNALS];
  • type definitions

    typedef struct _PhoshThing {
      GObject parent;
    
      ...
    } PhoshThing;
    
    G_DEFINE_TYPE (PhoshThing, phosh_thing, G_TYPE_OBJECT)
  • private methods and callbacks (these can also be placed at convenient locations above phosh_thing_constructed ())

  • phosh_thing_set_property (). Set properties. If setting a property requires more than a single line prefer adding a setter method, e.g. for the foo property, the setter method would be phosh_thing_set_foo (). This is almost always the case as we prefer G_PARAM_EXPLICIT_NOTIFY (see below).

    static void
    phosh_thing_set_property (GObject      *object,
                              guint         property_id,
                              const GValue *value,
                              GParamSpec   *pspec)
    {
       PhoshThing *self = PHOSH_THING (object);
    
       switch (property_id) {
       case PROP_FOO:
         phosh_thing_set_foo (self, g_value_get_string (value));
         break;
       
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
         break;
       }
    }
  • phosh_thing_get_property ()

  • phosh_thing_constructed (): Finish object construction. Usually only needed if you need the values of multiple properties passed at object construction time.

  • phosh_thing_dispose (): Usually only needed when you need to break reference cycles. Otherwise, prefer finalize. As dispose can be run multiple times, use g_clear_* to avoid freeing resources multiple times:

    static void
    phosh_thing_dispose (GObject *object)
    {
      PhoshThing *self = PHOSH_THING (object);
    
      g_cancellable_cancel (self->cancel);
      g_clear_object (&self->cancel);
      g_clear_object (&self->bar);
      g_clear_pointer (&self->foo, g_free);
    
      G_OBJECT_CLASS (phosh_thing_parent_class)->dispose (object);
    }
  • phosh_thing_finalize (): Free allocated resources.

  • phosh_thing_class_init (): Define properties and signals. For widget templates bind child widgets and signal handlers.

  • phosh_thing_init (): Initialize defaults for member variables here.

  • phosh_thing_new (): A convenience wrapper around g_object_new (). Don’t do further object initialization here but rather do that in phosh_thing_init (), phosh_thing_constructed () or individual property setters. This ensures that objects can be constructed either via this constructor or g_object_new ().

  • Public methods, all starting with the object name (i.e. phosh_thing_).

The reason public methods go at the bottom is that they are declared in the header file and can thus be referenced from anywhere else in the source file.

Derivable Parent Widgets#

If the widget is derivable and accepts a child, then prefer to expose the child as a property than as its UI child (<child> in UI file). This way we align with how GTK 4 structures the API and avoid the need to hijack the parent container’s add/remove method in the derivatives.

For example, a derivable parent widget called PhoshFoo would have the code for adding and removing child like this:

...

enum {
  PROP_0,
  PROP_CHILD,
  LAST_PROP
};
static GParamSpec *props[LAST_PROP];

typedef struct {
  GtkWidget       *child;
} PhoshFooPrivate;

G_DEFINE_TYPE_WITH_PRIVATE (PhoshFoo, phosh_foo, GTK_TYPE_BOX);

...

static void
phosh_foo_set_child (PhoshFoo *self, GtkWidget *child)
{
  PhoshFooPrivate *priv;

  g_return_if_fail (PHOSH_IS_FOO (self));

  priv = phosh_foo_get_instance_private (self);

  if (priv->child) {
    /* Remove the existing child */
  }

  priv->child = child;

  /* child can be NULL, which is used to remove
    existing child without replacement. */
  if (priv->child) {
   /* Add the new child */
  }

  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CHILD]);
}

For the widgets that take multiple children and adds them to internal widgets, prefer to implement GtkBuildable interface and expose methods to add and remove child like phosh_foo_add and phosh_foo_remove.

As an example, a PhoshFoo that can have multiple children, its code would be like:

...

static void phosh_foo_buildable_init (GtkBuildableIface *iface);

G_DEFINE_TYPE_WITH_CODE (PhoshFoo, phosh_foo,
                         PHOSH_TYPE_FOO,
                         G_ADD_PRIVATE (PhoshFoo)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
                                                phosh_foo_buildable_init))

...

static GtkBuildableIface *parent_buildable_iface;

static void
phosh_foo_buildable_add_child (GtkBuildable *buildable,
                               GtkBuilder   *builder,
                               GObject      *child,
                               const gchar  *type)
{
  PhoshFoo *self = PHOSH_FOO (buildable);

  /* Check if the child is meant for PhoshFoo by checking child's type etc. */
  if (condition) {
    phosh_foo_add (self, child);
    return;
  }

  /* The parent is a container itself so chain up */
  parent_buildable_iface->add_child (buildable, builder, child, type);
}


static void
phosh_foo_buildable_init (GtkBuildableIface *iface)
{
  parent_buildable_iface = g_type_interface_peek_parent (iface);
  iface->add_child = phosh_foo_buildable_add_child;
}

...

void
phosh_foo_add (PhoshFoo *self, GtkWidget *child)
{
  /* Add the child to self using usual logic. */
  ...
}

The ultimate aim is to do a little heavy-lifting in the widget implementations, so it is easy to port them to GTK 4. And, as a direct consequence, restrict the usage of GtkContainer APIs for implementation logic only and expose public methods to do the same.

CSS Theming#

For custom widgets set the css name using gtk_widget_class_set_css_name (). There’s no need to set an (additional) style class in the ui file.

Good:

static void
phosh_lockscreen_class_init (PhoshLockscreenClass *klass)
{
  
  gtk_widget_class_set_css_name (widget_class, "phosh-lockscreen");
  
}

Bad:

  <template class="PhoshLockscreen" parent="…">
     <style>
         <class name="phosh-lockscreen"/>
      </style>
  </template>

Properties#

Prefix property enum names with PROP_.

Good:

enum {
  PROP_0,
  PROP_NUMBER,
  PROP_SHOW_ACTION_BUTTONS,
  PROP_COLUMN_SPACING,
  PROP_ROW_SPACING,
  PROP_RELIEF,
  LAST_PROP
};

static GParamSpec *props[LAST_PROP];

Signal Emission on Changed Properties#

Except for G_CONSTRUCT_ONLY properties use G_PARAM_EXPLICIT_NOTIFY and notify about property changes only when the underlying variable changes value:

static void
on_present_changed (PhoshDockedInfo *self)
{
  

  if (self->enabled == enabled)
    return;

  self->enabled = enabled;
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ENABLED]);
}

static void
phosh_docked_info_class_init (PhoshDockedInfoClass *klass)
{
  

  /**
   * PhoshDockedInfo:enabled:
   *
   * Whether docked mode is enabled
   *
   * Since: 0.44.0
   */
  props[PROP_PRESENT] =
    g_param_spec_boolean ("present", "", "",
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);

  
}

This makes sure we minimize the notifications on changed property values.

Property documentation#

Prefer a docstring over filling in the properties’ nick and blurb. See example above.

Property bindings#

If the state of a property depends on the state of another one prefer g_object_bind_property () to keep these in sync:

Good:

  g_object_bind_property (self, "bar",
                          self->avatar, "loadable-icon",
                          G_BINDING_SYNC_CREATE);

This has the upside that the binding goes away automatically when either of the two objects gets disposed and also avoids bugs in manual syncing code.

For widgets you can construct the binding via the UI XML:

  <object class="PhoshQuickSetting" id="foo_quick_setting">
    <property name="sensitive" bind-source="wwaninfo" bind-property="present" bind-flags="sync-create"/>
  </object>

Signals#

Don’t prefix signal enum names with SIGNAL_.

Good:

enum {
  SUBMITTED,
  DELETED,
  SYMBOL_CLICKED,
  N_SIGNALS
};

static guint signals[N_SIGNALS];

Signals should be documented. Since class_offset, accumulator and c_marshaller are often unused we put them on a single line.

Good:

  /**
   * PhoshWwanManager::new-cbm
   * @self: The wwan manager
   * @message: The message text
   * @channel: The channel specifying the source of the CBM
   *
   * This signal is emitted when a new cell broadcast message is
   * received.
   *
   * Since: 0.44.0
   */
  signals[NEW_CBM] = g_signal_new ("new-cbm",
                                   G_TYPE_FROM_CLASS (klass),
                                   G_SIGNAL_RUN_LAST,
                                   0, NULL, NULL, NULL,
                                   G_TYPE_NONE,
                                   2,
                                   G_TYPE_STRING,
                                   G_TYPE_UINT);

In the same source file prefer g_signal_emit over g_signal_emit_by_name:

Good:

  g_signal_emit (self, signals[NEW_CBM], "data", 32);

Callbacks#

There are callbacks for signals, async functions, and actions. We usually have them all start with on_ to make it easy to spot that these aren’t just methods (and hence have restrictions regarding their function arguments and return values).

  • Signal handlers are named on_<signalname>. E.g. the handler for a GListModels items-changed signal would be named on_items_changed (). To avoid ambiguity one can add the emitter’s name (on_devices_list_box_items_changed ()).

  • For notify:: signal handler callbacks acting on property changes we use the on_<property>_changed () naming. E.g. on_nm_signal_strength_changed ().

  • For GAsyncReadyCallbacks we use on_<async-function>_ready(), e.g. the callback for nm_client_new_async that invokes nm_client_new_finish would be named on_nm_client_new_ready ().

  • For actions we use on_<action>_activated, e.g. for a go-back action we’d use on_go_back_activated ().

  • In cases where the signal handler name should express what it does rather than what signal it connects to, we use a _cb suffix. This is often the case when we want to use the same signal handler to handle multiple signals. E.g. a callback that updates a GtkStackPage when a signal happens would be named update_stack_page_cb ().

API Contracts#

Public (non static) functions must check the input arguments at the top of the function. This makes it easy to reuse them in other parts and makes API misuse easy to debug via G_DEBUG=fatal-criticals. You usually want to check argument types and if the arguments fulfill the requirements (e.g. if they need to be non-NULL). Public functions should have doc strings.

Good:

/**
 * phosh_foo_set_name:
 * @self: The foo
 * @name: The name to set
 *
 * Set Foo's `name`
 */
void
phosh_foo_set_name (PhoshFoo *self, const char *name)
{
  GtkWidget *somewidget;

  g_return_if_fail (PHOSH_IS_FOO (self));
  g_return_if_fail (name != NULL);

  
}

GObject introspection annotations#

For the Rust bindings we want to have introspection annotations on public methods. Use a space after the colon:

Good:

 * Returns: (transfer none): The generated wisdom

Bad:

 * Returns:(transfer none): The generated wisdom

Uncrustify#

Several projects ship a uncrustify to ease formatting. The config is not 100% correct so if it breaks above rules trust your style more than uncrustify.

Rust Based Projects#

For Rust projects see if rustfmt is usually used in CI to check the format. Make sure to use it too during development.

Python Scripts#

Projects that ship Python scripts often have a lint check in CI. If in doubt formatting with black usually comes close.