CodingStyle

Differences between revisions 3 and 4
Revision 3 as of 2010-12-09 13:32:22
Size: 13881
Editor: c-76-112-212-248
Comment:
Revision 4 as of 2010-12-11 11:19:21
Size: 14940
Editor: 124-148-255-218
Comment:
Deletions are marked like this. Additions are marked like this.
Line 375: Line 375:
== Compiz Plugins coding style ==

All compiz plugins except the unityshell plugin should follow the [[http://wiki.compiz.org/Development/CodingStyle|X11/Compiz style]]. Basically:

 * Identation: 8 size tabs, 4 spaces (alternating), eg one level of indentation is 4spaces, 2 levels is tab, 3 levels is tab, 4 spaces etc.
 * camelCaps for variables and function names, the first part starting in lower case.
 * CamelCaps for class and struct names, the first part uppercase
 * One space in between round brackets and variable / function names, eg foo () or bar (foo ());
 * Do not use exceptions, gotos or other bits of C++ which are disabled using -fno-exceptions
 * Braces always fall on the next line, at the same indentation level
 * Omit braces for single statement flow control, for example if (foo) bar ();
 * Use C style comments and documentation (/* Foo */ not // Foo)
 * Prefix member variables with m, eg mFoo, global variables with g, eg gFoo. Use [[http://en.wikipedia.org/wiki/Opaque_pointer#C.2B.2B|PIMPL]] where it makes sense

Introduction

This document describes the coding style recommended for the Unity project. It first gives general guidelines, applicable in particular to portions developed in C. Then it describes similar recommendations for modules developed in Vala.

Code

General

C style comments as much as possible please, no '//'! Please make sure the copyright is correctly assigned to Canonical and your name is added to the list of authors of that file. Also, please be careful of merge-requesting code that has warnings in it, we want clean code and clean compiles! Also, most of the time we'll be compiling with -Werror and -Wall, so that should help!

Please wrap at 80 chars for us old-skoolers who use vim/emacs :)

emacs tab settings Smile :) - add this to the top of your files and hopefully your editor will be smart enough to stick to the tab settings it defines, even if you are not using emacs

/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */

C Code

Try and stick to the gnu coding style as much as possible (although we deviate from it in certain cases like structs enums). This is basically 2 space indents, no tabs, brackets also indented and on their own line. We should try and keep the variables at the top of the function.

An example that should include most standard parts is below for C.

static MyGObject *
my_g_object_new (const gchar *name,
                 const gchar *type)
{
  MyGObject *me;
  gint       i;

  for (i = 0; i < 5; i++)
    {
      g_print ("I love you ");
      
      switch (i)
      {
        case 0:
          g_print ("%d times\n", i);
          break;
        case 1:
          g_print ("%d times\n", i);
          break;
        case 2:
          g_print ("%d times\n", i);
          break;
        case 3:
          g_print ("%d times\n", i);
          break;
        case 4:
          g_print ("%d times\n", i);
          break;
        default:
          g_print ("%d times\n", i);
          break;
      }
    }

  me = g_object_new (MY_TYPE_G_OBJECT,
                     "name", name,
                     "type", type,
                     NULL);

  return me;
}

Look at liblauncher/clutk/netbook-launcher for inspiration.

Vala Code

- Tabs for indentation, spaces for positioning OR just two spaces, not sure. - Quite similar to GNU C style

namespace Dash
{
  public class Window : Gtk.Window
  {
     public string  name { get; construct; }
     public string  title;
     
     private WinType _type;
     public  WinType type
      {
        set
          {
            if (value != _type)
              {
                _type = value;
                do_something ();
              }
          }
        get { return _type; };
      }

     private is_active;
     private loves_cheese;

     public Window (string name)
     {
       Object (name:name);

       /* Try not to use 'this.' unless it's absolutely necessary, 
        * as it's implicit in Vala anyway (and there is not much
        * chance of you calling another similar named variable or
        * function thanks to namespaces. It helps keep the code
        * clean
        */
       title = "My Window";
       is_active = true;

       type = new WinType (WinType.NORMAL);

       load_buttons ();

       button_press_event.connect (() =>
         {
           do_something_useful ();
         });
     }

     /* Although private is by default, it's nice to have it explicitly stated */
     private void load_buttons ()
     {
       GLib.List<string> files = UI.get_interface_files ();
       foreach (string file in files)
         {
           try
             {
               Gtk.Widget root = UI.load_root_from_file (file);
               /* "this." not needed */
               pack_start (root, false, false, 0);
             }
           catch (Error e)
             {
               warning ("Unable to load UI '%s': %s", file, e.message);
             }
         }
     }

     private override bool expose_event (Gdk.ExposeEvent event)
     {
       var cr = Gdk.cario_create (this.window);
       cr.set_source_rgba (0.0, 0.0, 0.0, 0.0);
       cr.set_operator (Cairo.Operator.CLEAR);
       cr.paint ();
     
       /* The following is not even close to the actual pattern API */
       var pat = new Cairo.PatternLinear ();
       var i;
       for (i = 0; i < 4; i++)
         {
           pat.add_stop (1.0, 1.0, 1.0, 0.2 * i);
         }
       cr.set_source (pat);

       /* Again, no 'this.' */
       switch (state)
         {
         case (Gtk.StateType.ACTIVE):
           cr.rectangle (0, 0, 100, 100);
           break;

         case (Gtk.StateType.PRELIGHT):
           cr.rectangle (0, 0, 100, 50);
           break;

         default:
           cr.rectangle (0, 0, 100, 25);
           break;
         }
       cr.fill ();
    }
  }
}

Vala Code Style 2

This matches more with C# and Vala upstream (though not everything)

  • Tabs for indentation, spaces for positioning.
  • loops/switches/etc have opening bracket on same line, functions have separate line.
  • Don't use 'this.' unless variable name clash or really long function.
  • Wrap at 120chars instead of 80 chars.

namespace Dash
{
  public class Window : Gtk.Window
  {
     public string  name { get; construct; }
     public string  title;
     
     private WinType _type;
     public  WinType type {
       set {
         if (value != _type) {
           _type = value;
           do_something ();
         }
       }  
       
       get { return _type; };
    }

     private is_active;
     private loves_cheese;

     public Window (string name)
     {
       Object (name:name);

       /* Try not to use 'this.' unless it's absolutely necessary, 
        * as it's implicit in Vala anyway (and there is not much
        * chance of you calling another similar named variable or
        * function thanks to namespaces. It helps keep the code
        * clean
        */
       title = "My Window";
       is_active = true;

       type = new WinType (WinType.NORMAL);

       load_buttons ();

       button_press_event.connect (() => {
           do_something_useful ();
       });
     }

     /* Although private is by default, it's nice to have it explicitly stated */
     private void load_buttons ()
     {
       GLib.List<string> files = UI.get_interface_files ();
       foreach (string file in files) {
         try {
           Gtk.Widget root = UI.load_root_from_file (file);
           /* "this." not needed */
           pack_start (root, false, false, 0);
         }
         catch (Error e) {
           warning ("Unable to load UI '%s': %s", file, e.message);
         }
       }
     }

     private override bool expose_event (Gdk.ExposeEvent event)
     {
       var cr = Gdk.cario_create (this.window);
       cr.set_source_rgba (0.0, 0.0, 0.0, 0.0);
       cr.set_operator (Cairo.Operator.CLEAR);
       cr.paint ();
     
       /* The following is not even close to the actual pattern API */
       var pat = new Cairo.PatternLinear ();
       var i;
       for (i = 0; i < 4; i++) {
           pat.add_stop (1.0, 1.0, 1.0, 0.2 * i);
       }
       cr.set_source (pat);

       /* Again, no 'this.' */
       switch (state) {
         case (Gtk.StateType.ACTIVE):
           cr.rectangle (0, 0, 100, 100);
           break;

         case (Gtk.StateType.PRELIGHT):
           cr.rectangle (0, 0, 100, 50);
           break;

         default:
           cr.rectangle (0, 0, 100, 25);
           break;
       }
       cr.fill ();
    }
  }
}

C++ Style

The obvious first:

  • Use Spaces, no Tabs.
  • Tab = 2 spaces
  • Indentation = 2 spaces
  • Brackets on new line
  • Function names like SetActive()

  • Class names like PanelMenuBar

  • Variables like is_active (never capitalised or camel case)
  • Filenames like MenuBar.h/MenuBar.cpp

  • Ints look like 5, floats look like 5.0f, doubles look like 5.0
  • Typedef enums and structs. enum members should be captials, always use the typed name of an enum rather than a “int” in function arguments.
  • Nux: For types, use standard C/C++ types and DO use the defines in stdint.h (int32_t for instance). Don’t use “int”, use int32_t. Don’t leak GLib types.
  • Unity: You can use glib types where it makes sense (i.e. don’t use gboolean just use bool).
  • Private member variables of classes should be “m_foo”, NOT “foo” or “_foo”
  • Signal names should be “like_this” “NotLikeThis

This translates to astyle -R -s2 -b -S -N -w -Y -M80 -p -H -d -k3 -n -z2 with astyle.

An example:

namespace unity
{

  // typedef enums and make sure their members are capitalised
  typedef enum
  {
    WAS_DONE = 0,
    WASNT_DONE
  } WasItDoneResult;

  class Panel : public BaseObject
  {
    // This is sweet as it helps us do easier debugging
    NUX_DECLARE_OBJECT_TYPE(Panel, BaseObject);
 
  public:
    Panel (Shell* shell);
    ~Panel ();
  
    virtual void LoadIndicators ();

    bool DoSomethingUseful (bool really_do_it, float factor)
    {
    // Declare variables at the top of a scope
    bool ret = false;
    int i = 0;

    for (i =0; i < 10; i++)
    {
      if (really_do_it)
      {
        WasItDoneResult was_it_done = Util::WasItDone ();
        switch (it_was_done)
        {
          case WAS_DONE:
            printf (“It was done\n”);
            ret = true;
            break;
          case WASNT_DONE:
            printf (“It wasn’t done\n”);
            ret = false;
            break;
          default:
            printf (“Fudge\n”);
            break;
        }
      }
      else
      {
        printf (“You didn’t want me to do anything, so I didn’t!\n”);
      }
    }
    return ret;
  }

  protected:
    std::list<Indicator*> m_indicator_list;

  private:
    bool m_has_loaded;

  } // class::Panel

} // namespace::unity

Compiz Plugins coding style

All compiz plugins except the unityshell plugin should follow the X11/Compiz style. Basically:

  • Identation: 8 size tabs, 4 spaces (alternating), eg one level of indentation is 4spaces, 2 levels is tab, 3 levels is tab, 4 spaces etc.
  • camelCaps for variables and function names, the first part starting in lower case.
  • CamelCaps for class and struct names, the first part uppercase

  • One space in between round brackets and variable / function names, eg foo () or bar (foo ());
  • Do not use exceptions, gotos or other bits of C++ which are disabled using -fno-exceptions
  • Braces always fall on the next line, at the same indentation level
  • Omit braces for single statement flow control, for example if (foo) bar ();
  • Use C style comments and documentation (/* Foo */ not // Foo)

  • Prefix member variables with m, eg mFoo, global variables with g, eg gFoo. Use PIMPL where it makes sense

Commit messages

To make using tools like bzr visualise easier, please structure your commit messages like:

[section] One line describing what you did

added:
  files added
    - What you changed the file

modified:
  files modified
    -What you changed

removed:
  files removed
    - Why you removed the file

If you do bzr commit from the commandline, it will open your favorite editor (set with EDITOR envvar) with added/modified/removed already filled out. You just need to delete the line that starts with '---' and then add the "[section] description" line at the top and annotate the files you changed.

You'll also get a list of 'unknown:' files below removed sometimes. These would be ideally added to bzr ignore, but in the minimum please delete them from your commit message.

An example message:

[tests] Bootstrap tests and add basic Dash.Launcher object

added:
  src/launcher.vala
    - Dash.Launcher (window)

  tests/
  tests/Makefile.am
  tests/test-dash-launcher.vala
    - Basic testing and make check, make check-report commands

modified:
  .bzrignore
    - Update ignores

  Makefile.am
    - Added support for check-report

  configure.ac
    - Add support for tests dir

  src/Makefile.am
    - Create static libdash-launcher-static.la lib for tests

  src/main.vala
    - Use Dash.Launcher

Random

Makefiles

Please add files in alphabetical order in Makefile.am, adding a file-per-line if you can't fit everything on one line without wrapping

Gtk-Doc

All public functions and classes should be documented using gtk-doc comments. Properties and signals are self-documenting. Details on gtk-doc syntax can be found here: http://library.gnome.org/devel/gtk-doc-manual/stable/documenting.html.en

Example method documentation

/**
 * launcher_foobar_get_value_at_index
 * @foobar: a #LauncherFoobar objecct
 * @index: an Integer representing the index to use
 *
 * Provides a method to get the data in @foobar at position @index
 *
 * Returns: a #LauncherBazItem
 */
LauncherBazItem *
launcher_foobar_get_value_at_index (LauncherFoobar *foobar, gint index) 
{
  ...
}

Gobject Introspection

GObject introspection is something we want for our libraries (but not so much for applications), It allows for bindings to be built for vala, python, javascript, perl, scheme and even QT!, mostly at runtime as well. Whilst gobject-introspection is handled with a scanner that's fairly robust, it can't detect certain logic behind some parameter declarations, out variables and ownership transfers being the main problem areas. However using gobject introspection annotations in your gtk-doc you can make sure the scanner knows what you want a method to do.

the syntax is described here: http://live.gnome.org/GObjectIntrospection/Annotations

Situations where you may want to use annotations

  • In/Out Parameters
  • Allowing NULL in parameters
  • Ownership transferring
  • Defining the element types in containers
  • Array parameters and the array properties (null terminated, size defined in another parameter and such)

Example:

/**
 * launcher_foobar_get_width_height
 * @foobar: a #LauncherFoobar object
 * @width: (out): an out integer
 * @height: (out): an out integer
 * 
 * provides the @width and @height of @foobar
 *
 */
void
launcher_foobar_get_width_height (LauncherFoobar *foobar, gint *width, gint *height) 
{
  ...
}

Unity/CodingStyle (last edited 2012-03-14 20:47:49 by c-67-170-185-42)