← Back to team overview

elementaryart team mailing list archive

[Merge] lp:~elementaryart/granite/about-dialog into lp:granite

 

Adrien Plazas has proposed merging lp:~elementaryart/granite/about-dialog into lp:granite.

Requested reviews:
  elementary desktop team (elementaryart)

For more details, see:
https://code.launchpad.net/~elementaryart/granite/about-dialog/+merge/75887

Added a new Aboutdialog to the framework
-- 
https://code.launchpad.net/~elementaryart/granite/about-dialog/+merge/75887
Your team elementary desktop team is requested to review the proposed merge of lp:~elementaryart/granite/about-dialog into lp:granite.
=== modified file 'demo/main.vala'
--- demo/main.vala	2011-09-06 16:22:53 +0000
+++ demo/main.vala	2011-09-18 08:52:23 +0000
@@ -22,9 +22,40 @@
 
 public class Granite.Demo : Granite.Application
 {
+    construct
+    {
+		application_id = "demo.granite.org";
+		program_name = "Granite Demo";
+		app_years = "2011";
+		
+		build_version = "1.0";
+		app_icon = "text-editor";
+		main_url = "https://launchpad.net/granite";;
+		bug_url = "https://bugs.launchpad.net/granite";;
+		help_url = "https://answers.launchpad.net/granite";;
+		translate_url = "https://translations.launchpad.net/granite";;
+		about_authors = {"Kekun",
+						 null
+						 };
+		about_documenters = {"Valadoc",
+							 null
+							 };
+		about_artists = {"Daniel P. Fore",
+						 null
+						 };
+		
+		about_authors = {"Maxwell Barvian <mbarvian@xxxxxxxxx>",
+						 "Daniel Foré <bunny@xxxxxxxxxxxx>",
+						 "Avi Romanoff <aviromanoff@xxxxxxxxx>",
+						 null
+						 };
+
+		about_comments = "A demo of the Granite toolkit";
+		about_translators = "Launchpad Translators";
+		about_license_type = Gtk.License.GPL_3_0;
+    }
     public Demo()
     {
-        Object(application_id:"demo.granite.org");
         var win = new Gtk.Window();
         win.delete_event.connect( () => { Gtk.main_quit(); return false; });
         
@@ -74,6 +105,9 @@
         staticbox.add (staticnotebook);
         
         notebook.append_page (staticbox, new Gtk.Label ("Static Notebook"));
+        var button_about = new Gtk.Button.with_label("show_about");
+        notebook.append_page (button_about, new Gtk.Label ("About Dialog"));
+        button_about.clicked.connect(() => { show_about(win); } );
         
         /* window properties */
         win.show_all();

=== added file 'lib/Animation.vala.OTHER'
--- lib/Animation.vala.OTHER	1970-01-01 00:00:00 +0000
+++ lib/Animation.vala.OTHER	2011-09-18 08:52:23 +0000
@@ -0,0 +1,382 @@
+//  
+//  Copyright (C) 2011 Maxwell Barvian.
+//  Ported from https://github.com/chergert/simply-chat/blob/master/ppg-animation.c, with some tweaks.
+// 
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+// 
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+using Gtk;
+
+namespace Granite {
+
+	public enum EasingMode {
+		LINEAR,
+		EASE_IN_QUAD,
+		EASE_OUT_QUAD,
+		EASE_IN_OUT_QUAD,
+		EASE_IN_CUBIC;
+		
+		/**
+		 * An alpha function to transform the offset within the animation into the given acceleration.
+		 *
+		 * @param the offset within the animation
+		 * 
+		 * @return the transformed offset within the animation
+		 */
+		public double transform (double offset) {
+			
+			switch (this) {
+			
+				case EasingMode.EASE_IN_QUAD:
+					return offset * offset;
+				case EasingMode.EASE_OUT_QUAD:
+					return -1.0 * offset * (offset - 2.0);
+				case EASE_IN_OUT_QUAD:
+					offset *= 2.0;
+					if (offset < 1.0)
+						return 0.5 * offset * offset;
+					offset -= 1.0;
+					return -0.5 * (offset * (offset - 2.0) - 1.0);
+				case EasingMode.EASE_IN_CUBIC:
+					return offset * offset * offset;
+				default:
+					return offset;
+			}
+		}
+	}
+	
+	[CCode (has_target = false)]
+	public delegate void TweenFunc (Value begin, Value end, double offset, ref Value value);
+
+	public class Animation : GLib.Object {
+	
+		protected struct Tween {
+			public bool is_child; // does pspec belong to a parent widget
+			public ParamSpec pspec; // ParamSpec of target property
+			public Value begin; // beginning value in animaton
+			public Value end; // end value in animation
+			
+			public Tween (Object target, ParamSpec pspec, Value value) {
+				
+				is_child = !target.get_type ().is_a (pspec.owner_type);
+				this.pspec = pspec.ref ();
+				begin = Value (pspec.value_type);
+				end = Value (pspec.value_type);
+				value.copy (ref end);
+			}
+		}
+		
+		/**
+		 * Maps a {@link GLib.Type} with a {@link Granite.TweenFunc}.  {@link Granite.Animation.get_value_at_offset} uses this
+		 * to calculate new values for specific offsets.  However, the types {@link int}, {@link uint}, {@link .long},
+		 * {@link ulong}, {@link float}, and {@link double} have been added by default for convenience, so it is rare
+		 * that you would have to add a {@link GLib.Type} here yourself.
+		 */
+		public static HashTable<Type, TweenFunc> tween_funcs { get; protected set; }
+		
+		static construct {
+			
+			tween_funcs = new HashTable<Type, TweenFunc> (null, null);
+			
+			// Add sensible default TweenFunc's. I really wish I had a macro for this.
+			tween_funcs.insert (typeof (int), (b, e, o, v) => { var x = b.get_int (), y = e.get_int (); v.set_int ((int) (x + (y - x) * o)); });
+			tween_funcs.insert (typeof (uint), (b, e, o, v) => { var x = b.get_uint (), y = e.get_uint (); v.set_uint ((uint) (x + (y - x) * o)); });
+			tween_funcs.insert (typeof (long), (b, e, o, v) => { var x = b.get_long (), y = e.get_long (); v.set_long ((long) (x + (y - x) * o)); });
+			tween_funcs.insert (typeof (ulong), (b, e, o, v) => { var x = b.get_ulong (), y = e.get_ulong (); v.set_ulong ((ulong) (x + (y - x) * o)); });
+			tween_funcs.insert (typeof (float), (b, e, o, v) => { var x = b.get_float (), y = e.get_float (); v.set_float ((float) (x + (y - x) * o)); });
+			tween_funcs.insert (typeof (double), (b, e, o, v) => { var x = b.get_double (), y = e.get_double (); v.set_double (x + (y - x) * o); });
+		}
+		
+		/**
+		 * This signal is emitted when the animation has completed without interruption.
+		 */
+		public signal void completed ();
+				
+		/**
+		 * The target of the animation.
+		 */
+		public Object target { get; construct set; }
+		
+		/** 
+		 * The duration of the animation in milliseconds.
+		 */
+		public uint duration { get; construct set; default = 250; }
+		
+		/**
+		 * The easing mode of the animation.
+		 */
+		public EasingMode easing_mode { get; construct set; default = EasingMode.LINEAR; }
+
+		/**
+		 * The frame rate of the animation.
+		 */
+		public uint frame_rate { get; construct set; default = 60; }
+		
+		protected uint64 begin_msec; // time which animation started
+		protected uint tween_handler = 0; // Timeout performing tweens
+		protected List<Tween?> tweens; // array of tweens to perform
+		protected uint frame_count; // counter for debugging #frames rendered
+		
+		/**
+		 * The percentage of the animation that has been completed, expressed in decimal form.
+		 */
+		protected double offset {
+			get {
+				return ((double) (timeval_to_msec (TimeVal ()) - begin_msec) / duration).clamp (0.0, 1.0);
+			}
+		}
+		
+		/**
+		 * Whether or not the animation is currently running.
+		 */
+		public bool is_running {
+			get {
+				return (tween_handler != 0);
+			}
+		}
+		
+		protected Animation () {
+			// blank. only reason we're not using this is because of a Vala bug with
+			// varargs in the constructor. :-/
+		}
+		
+		protected static Animation create (Object target, va_list args) {
+		
+			var anim = new Animation ();
+			anim.target = target;
+			anim.tweens = new List<Tween?> ();
+			
+			string name;
+			Value value;
+			ParamSpec pspec;
+			Gtk.Widget parent;
+			Type type = target.get_type ();
+			
+			while ((name = args.arg ()) != null) {
+			
+				if ((pspec = target.get_class ().find_property (name)) == null) {
+					if (!type.is_a (typeof (Gtk.Widget)))
+						critical ("Failed to find property %s in %s", name, type.name ());
+					if ((parent = (target as Gtk.Widget).get_parent ()) == null)
+						critical ("Failed to find property %s in %s", name, type.name ());
+					if ((pspec = Container.class_find_child_property (parent.get_class (), name)) == null)
+						critical ("Failed to find property %s in %s or parent %s", name, type.name (), parent.get_type ().name ());
+				}
+				
+				// Parse the value for the pspec
+				value = Value (pspec.value_type);
+				type = value.type ();
+				if (type == typeof (bool))
+					value.set_boolean (args.arg<bool> ());
+				else if (type == typeof (string))
+					value.set_string (args.arg<string> ());
+				else if (type == typeof (int))
+					value.set_int (args.arg<int> ());
+				else if (type == typeof (uint))
+					value.set_uint (args.arg<uint> ());
+				else if (type == typeof (long))
+					value.set_long (args.arg<long> ());
+				else if (type == typeof (ulong))
+					value.set_ulong (args.arg<ulong> ());
+				else if (type == typeof (int64))
+					value.set_int64 (args.arg<int64> ());
+				else if (type == typeof (double))
+					value.set_double (args.arg<double> ());
+				else
+					value.set_object (args.arg<Object> ());
+				
+				anim.tweens.append (Tween (target, pspec, value));
+			}
+			
+			return anim;
+		}
+		
+		/**
+		 * Creates a new {@link Granite.Animation} for the specified target using the default options.
+		 *
+		 * @param target the object that is to be animated
+		 * 
+		 * @return the {@link Granite.Animation}
+		 */
+		public static Animation create_simple (Object target, ...) {
+						
+			va_list args = va_list (); // have to define variable for some vala bug
+			return create (target, args);
+		}
+		
+		/**
+		 * Constructs a new {@link Granite.Animation} for the specified target using the specified options.
+		 *
+		 * @param target the object that is to be animated
+		 * @param duration the duration of the animation
+		 * @param easing_mode the easing mode of the animation
+		 *
+		 * @return the {@link Granite.Animation}
+		 */
+		public static Animation create_advanced (Object target, uint duration, EasingMode easing_mode, ...) {
+		
+			va_list args = va_list ();
+			var anim = create (target, args);
+			anim.duration = duration;
+			anim.easing_mode = easing_mode;
+			
+			return anim;
+		}
+		
+		~Animation () {
+			debug ("Rendered %u frames in %u milliseconds for target %s", frame_count, duration, target.get_class ().get_type ().name ());
+		}
+		
+		protected inline uint64 timeval_to_msec (TimeVal t) {
+			return (t.tv_sec * 1000 + t.tv_usec / 1000);
+		}
+		
+		/**
+		 * Load the begin values for all the properties that are about to be animated.
+		 */
+		protected void load_begin_values () {
+			
+			// Vala's foreach loop isn't working here for some reason. No biggie.
+			tweens.foreach ((tween) => {
+				
+				tween.begin.reset ();
+				if (tween.is_child)
+					((Container) ((Gtk.Widget) target).get_parent ()).child_get_property ((Gtk.Widget) target, tween.pspec.name, tween.begin);
+				else
+					target.get_property (tween.pspec.name, ref tween.begin);				
+			});
+		}
+		
+		protected void unload_begin_values () {
+		
+			tweens.foreach ((tween) => tween.begin.reset ());
+		}
+		
+		/**
+		 * Updates the value of a property on an object using value.
+		 *
+		 * @param target the {@link GLib.Object} with the property which will be updated
+		 * @param tween a {@link Granite.Animation.Tween} containing the property
+		 * @param value the new {@link GLib.Value} for the property
+		 */
+		protected virtual void update_property (Object target, Tween tween, Value value) {
+			target.set_property (tween.pspec.name, value);
+		}
+		
+		/**
+		 * Updates the value of the parent widget of the target using value.
+		 *
+		 * @param target the {@link GLib.Object} with the property which will be updated
+		 * @param tween a {@link Granite.Animation.Tween} containing the property
+		 * @param value the new {@link GLib.Value} for the property
+		 */
+		protected virtual void update_child_property (Object target, Tween tween, Value value) {
+			((Container) ((Gtk.Widget) target).get_parent ()).child_set_property ((Gtk.Widget) target, tween.pspec.name, value);
+		}
+		
+		/**
+		 * Retrieves a value for a particular position within the animation.
+		 *
+		 * @param offset the offset in the animation from 0.0 to 1.0
+		 * @param tween a {@link Granite.Animation.Tween} containing the property
+		 * @param value a {@link GLib.Value} in which to store the property
+		 */
+		protected void get_value_at_offset (double offset, Tween tween, ref Value value) {
+			
+			return_if_fail (offset >= 0.0 && offset <= 1.0);
+			return_if_fail (value.holds (tween.pspec.value_type));
+			
+			var tween_func = tween_funcs.lookup (value.type ());
+			if (tween_func != null) {
+				tween_func (tween.begin, tween.end, offset, ref value);
+			} else {
+				warning ("No tween function found for type '%s'", value.type ().name ());
+				
+				if (offset >= 1.0)
+					tween.end.copy (ref value);
+			}
+		}
+		
+		/**
+		 * Move the object properties to the next position in the animation.
+		 *
+		 * @return true if the animation has not completed, false otherwise
+		 */
+		public virtual signal bool tick () {
+		
+			frame_count++;
+			
+			// Update property values
+			tweens.foreach ((tween) => {
+			
+				var value = Value (tween.pspec.value_type);
+				get_value_at_offset (easing_mode.transform (offset), tween, ref value);
+				if (tween.is_child)
+					update_child_property (target, tween, value);
+				else
+					update_property (target, tween, value);
+			});
+			
+			// Flush any outstanding events to the graphics server (in the case of X)
+			if (target is Gtk.Widget) {
+				
+				var window = ((Gtk.Widget) target).get_parent_window ();
+				if (window != null)
+					window.flush ();
+			}
+				
+			return (offset < 1.0);
+		}
+		
+		/**
+		 * The actual callback for the tween_handler {@link GLib.Timeout}. This method first invokes {@link Granite.Animation.tick}
+		 * and, if necessary, will invoke {@link Granite.Animation.stop}.
+		 */
+		protected bool timeout () {
+			
+			bool ret = tick ();
+			if (!ret) {
+				stop ();
+				completed ();
+			}
+			
+			return ret;
+		}
+		
+		/**
+		 * Start the animation.
+		 */
+		public void start () {
+			
+			return_if_fail (!is_running);
+			
+			load_begin_values ();
+			begin_msec = timeval_to_msec (TimeVal ());
+			tween_handler = Timeout.add (1000 / frame_rate, timeout);
+		}
+		
+		/**
+		 * Stop the animation.
+		 */
+		public void stop () {
+			
+			Source.remove (tween_handler);
+			tween_handler = 0;
+			unload_begin_values ();
+		}
+		
+	}
+	
+}
+

=== modified file 'lib/Application.vala'
--- lib/Application.vala	2011-08-28 16:35:55 +0000
+++ lib/Application.vala	2011-09-18 08:52:23 +0000
@@ -51,6 +51,7 @@
 		public string exec_name;
 		
 		public string app_copyright;
+		public string app_years;
 		public string app_icon;
 		public string app_launcher;
 
@@ -62,8 +63,10 @@
 		public string[] about_authors;
 		public string[] about_documenters;
 		public string[] about_artists;
+		public string about_comments;
 		public string about_translators;
 		public string about_license;
+		public License about_license_type;
 		
 		public Application () {
 		
@@ -136,13 +139,13 @@
 		
 		public AppMenu create_appmenu (Menu menu) {
 		
-		    AppMenu app_menu = new AppMenu.with_urls (menu, this.help_url, this.translate_url, this.bug_url);
+		    AppMenu app_menu = new AppMenu (menu);
 		    app_menu.show_about.connect ((parent) => this.show_about (parent));
 		    
 		    return app_menu;
 		}
 		
-		protected AboutDialog about_dlg;
+		protected Granite.Widgets.AboutDialog about_dlg;
 			
 		public virtual void show_about (Gtk.Widget parent) {
 		
@@ -151,26 +154,31 @@
 				return;
 			}
 			
-			about_dlg = new AboutDialog ();
+			about_dlg = new Granite.Widgets.AboutDialog ();
 			
 			about_dlg.modal = true;
 			about_dlg.window_position = Gtk.WindowPosition.CENTER_ON_PARENT;
 			about_dlg.transient_for = (Gtk.Window) parent;
                 			
-			about_dlg.set_program_name (exec_name);
-			about_dlg.set_version (build_version + "\n" + build_version_info);
-			about_dlg.set_logo_icon_name (app_icon);
-			
-			about_dlg.set_comments (program_name + ". " + build_release_name);
-			about_dlg.set_copyright ("Copyright © %s %s Developers".printf (app_copyright, program_name));
-			about_dlg.set_website (main_url);
-			about_dlg.set_website_label ("Website");
-			
-			about_dlg.set_authors (about_authors);
-			about_dlg.set_documenters (about_documenters);
-			about_dlg.set_artists (about_artists);
-			about_dlg.set_translator_credits (about_translators);
-			about_dlg.set_license (about_license);
+			about_dlg.program_name = program_name;
+			about_dlg.version = build_version;
+			about_dlg.logo_icon_name = app_icon;
+			
+			about_dlg.comments = about_comments;
+			about_dlg.copyright = "%s %s Developers".printf (app_years, program_name);
+			about_dlg.website = main_url;
+			about_dlg.website_label = "Website";
+			
+			about_dlg.authors = about_authors;
+			about_dlg.documenters = about_documenters;
+			about_dlg.artists = about_artists;
+			about_dlg.translator_credits = about_translators;
+			about_dlg.license  = about_license;
+			about_dlg.license_type  = about_license_type;
+			
+			about_dlg.help = help_url;
+			about_dlg.translate = translate_url;
+			about_dlg.bug = bug_url;
 			
 			about_dlg.response.connect (() => {
 				about_dlg.hide ();
@@ -180,7 +188,7 @@
 				about_dlg = null;
 			});
 			
-			about_dlg.show_all ();
+			about_dlg.show ();
 		}
 		
 	}

=== modified file 'lib/CMakeLists.txt'
--- lib/CMakeLists.txt	2011-09-17 17:41:55 +0000
+++ lib/CMakeLists.txt	2011-09-18 08:52:23 +0000
@@ -48,10 +48,12 @@
 	Drawing/Color.vala
 	Drawing/BufferSurface.vala
 	Drawing/Utilities.vala
+	GtkPatch/AboutDialog.vala
 	Services/Settings.vala
 	Services/Logger.vala
 	Services/Paths.vala
 	Services/System.vala
+	Widgets/AboutDialog.vala
 	Widgets/ModeButton.vala
 	Widgets/DatePicker.vala
 	Widgets/Entries.vala

=== modified file 'lib/Granite-0.1.gir'
--- lib/Granite-0.1.gir	2011-08-25 11:19:12 +0000
+++ lib/Granite-0.1.gir	2011-09-18 08:52:23 +0000
@@ -381,12 +381,12 @@
       <field name="frame_count">
         <type name="guint" c:type="guint"/>
       </field>
-      <glib:signal name="completed">
+      <glib:signal name="completed" when="last">
         <return-value transfer-ownership="none">
           <type name="none"/>
         </return-value>
       </glib:signal>
-      <glib:signal name="tick">
+      <glib:signal name="tick" when="last">
         <return-value transfer-ownership="none">
           <type name="gboolean"/>
         </return-value>
@@ -563,6 +563,18 @@
           </parameter>
         </parameters>
       </virtual-method>
+      <method name="create_appmenu"
+              c:identifier="granite_application_create_appmenu"
+              introspectable="0">
+        <return-value>
+          <type name="WidgetsAppMenu" c:type="GraniteWidgetsAppMenu*"/>
+        </return-value>
+        <parameters>
+          <parameter name="menu" transfer-ownership="none">
+            <type name="Gtk.Menu" c:type="GtkMenu*"/>
+          </parameter>
+        </parameters>
+      </method>
       <method name="run" c:identifier="granite_application_run">
         <return-value transfer-ownership="none">
           <type name="gint" c:type="gint"/>
@@ -665,7 +677,7 @@
         <type name="utf8" c:type="gchar*"/>
       </field>
       <field name="about_dlg">
-        <type name="Gtk.AboutDialog" c:type="GtkAboutDialog*"/>
+        <type name="WidgetsAboutDialog" c:type="GraniteWidgetsAboutDialog*"/>
       </field>
     </class>
     <record name="ApplicationClass"
@@ -1349,7 +1361,452 @@
               value="4"
               c:identifier="GRANITE_EASING_MODE_EASE_IN_CUBIC"
               glib:nick="ease-in-cubic"/>
+      <function name="transform" c:identifier="granite_easing_mode_transform">
+        <return-value transfer-ownership="none">
+          <type name="gdouble" c:type="gdouble"/>
+        </return-value>
+        <parameters>
+          <parameter name="self" transfer-ownership="none">
+            <type name="EasingMode" c:type="GraniteEasingMode"/>
+          </parameter>
+          <parameter name="offset" transfer-ownership="none">
+            <type name="gdouble" c:type="gdouble"/>
+          </parameter>
+        </parameters>
+      </function>
     </enumeration>
+    <class name="GtkPatchAboutDialog"
+           c:symbol-prefix="gtk_patch_about_dialog"
+           c:type="GraniteGtkPatchAboutDialog"
+           parent="Gtk.Dialog"
+           glib:type-name="GraniteGtkPatchAboutDialog"
+           glib:get-type="granite_gtk_patch_about_dialog_get_type"
+           glib:type-struct="GtkPatchAboutDialogClass">
+      <implements name="Atk.ImplementorIface"/>
+      <implements name="Gtk.Buildable"/>
+      <constructor name="new"
+                   c:identifier="granite_gtk_patch_about_dialog_new">
+        <return-value transfer-ownership="none">
+          <type name="GtkPatchAboutDialog"
+                c:type="GraniteGtkPatchAboutDialog*"/>
+        </return-value>
+      </constructor>
+      <function name="construct"
+                c:identifier="granite_gtk_patch_about_dialog_construct"
+                introspectable="0">
+        <return-value>
+          <type name="GtkPatchAboutDialog"
+                c:type="GraniteGtkPatchAboutDialog*"/>
+        </return-value>
+        <parameters>
+          <parameter name="object_type" transfer-ownership="none">
+            <type name="GType" c:type="GType"/>
+          </parameter>
+        </parameters>
+      </function>
+      <virtual-method name="activate_link">
+        <return-value transfer-ownership="none">
+          <type name="gboolean" c:type="gboolean"/>
+        </return-value>
+        <parameters>
+          <parameter name="uri" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </virtual-method>
+      <method name="get_artists"
+              c:identifier="granite_gtk_patch_about_dialog_get_artists"
+              introspectable="0">
+        <return-value>
+          <array c:type="gchar**">
+            <type name="utf8"/>
+          </array>
+        </return-value>
+        <parameters>
+          <parameter name="result_length1" transfer-ownership="none">
+            <type name="gint" c:type="int*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="get_authors"
+              c:identifier="granite_gtk_patch_about_dialog_get_authors"
+              introspectable="0">
+        <return-value>
+          <array c:type="gchar**">
+            <type name="utf8"/>
+          </array>
+        </return-value>
+        <parameters>
+          <parameter name="result_length1" transfer-ownership="none">
+            <type name="gint" c:type="int*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="get_comments"
+              c:identifier="granite_gtk_patch_about_dialog_get_comments">
+        <return-value transfer-ownership="none">
+          <type name="utf8" c:type="gchar*"/>
+        </return-value>
+      </method>
+      <method name="get_copyright"
+              c:identifier="granite_gtk_patch_about_dialog_get_copyright">
+        <return-value transfer-ownership="none">
+          <type name="utf8" c:type="gchar*"/>
+        </return-value>
+      </method>
+      <method name="get_documenters"
+              c:identifier="granite_gtk_patch_about_dialog_get_documenters"
+              introspectable="0">
+        <return-value>
+          <array c:type="gchar**">
+            <type name="utf8"/>
+          </array>
+        </return-value>
+        <parameters>
+          <parameter name="result_length1" transfer-ownership="none">
+            <type name="gint" c:type="int*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="get_license"
+              c:identifier="granite_gtk_patch_about_dialog_get_license">
+        <return-value transfer-ownership="none">
+          <type name="utf8" c:type="gchar*"/>
+        </return-value>
+      </method>
+      <method name="get_license_type"
+              c:identifier="granite_gtk_patch_about_dialog_get_license_type">
+        <return-value transfer-ownership="none">
+          <type name="Gtk.License" c:type="GtkLicense"/>
+        </return-value>
+      </method>
+      <method name="get_logo"
+              c:identifier="granite_gtk_patch_about_dialog_get_logo"
+              introspectable="0">
+        <return-value>
+          <type name="GdkPixbuf.Pixbuf" c:type="GdkPixbuf*"/>
+        </return-value>
+      </method>
+      <method name="get_logo_icon_name"
+              c:identifier="granite_gtk_patch_about_dialog_get_logo_icon_name">
+        <return-value transfer-ownership="none">
+          <type name="utf8" c:type="gchar*"/>
+        </return-value>
+      </method>
+      <method name="get_program_name"
+              c:identifier="granite_gtk_patch_about_dialog_get_program_name">
+        <return-value transfer-ownership="none">
+          <type name="utf8" c:type="gchar*"/>
+        </return-value>
+      </method>
+      <method name="get_translator_credits"
+              c:identifier="granite_gtk_patch_about_dialog_get_translator_credits">
+        <return-value transfer-ownership="none">
+          <type name="utf8" c:type="gchar*"/>
+        </return-value>
+      </method>
+      <method name="get_version"
+              c:identifier="granite_gtk_patch_about_dialog_get_version">
+        <return-value transfer-ownership="none">
+          <type name="utf8" c:type="gchar*"/>
+        </return-value>
+      </method>
+      <method name="get_website"
+              c:identifier="granite_gtk_patch_about_dialog_get_website">
+        <return-value transfer-ownership="none">
+          <type name="utf8" c:type="gchar*"/>
+        </return-value>
+      </method>
+      <method name="get_website_label"
+              c:identifier="granite_gtk_patch_about_dialog_get_website_label">
+        <return-value transfer-ownership="none">
+          <type name="utf8" c:type="gchar*"/>
+        </return-value>
+      </method>
+      <method name="get_wrap_license"
+              c:identifier="granite_gtk_patch_about_dialog_get_wrap_license">
+        <return-value transfer-ownership="none">
+          <type name="gboolean" c:type="gboolean"/>
+        </return-value>
+      </method>
+      <method name="set_artists"
+              c:identifier="granite_gtk_patch_about_dialog_set_artists">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar**"/>
+          </parameter>
+          <parameter name="value_length1" transfer-ownership="none">
+            <type name="gint" c:type="int"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_authors"
+              c:identifier="granite_gtk_patch_about_dialog_set_authors">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar**"/>
+          </parameter>
+          <parameter name="value_length1" transfer-ownership="none">
+            <type name="gint" c:type="int"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_comments"
+              c:identifier="granite_gtk_patch_about_dialog_set_comments">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_copyright"
+              c:identifier="granite_gtk_patch_about_dialog_set_copyright">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_documenters"
+              c:identifier="granite_gtk_patch_about_dialog_set_documenters">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar**"/>
+          </parameter>
+          <parameter name="value_length1" transfer-ownership="none">
+            <type name="gint" c:type="int"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_license"
+              c:identifier="granite_gtk_patch_about_dialog_set_license">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_license_type"
+              c:identifier="granite_gtk_patch_about_dialog_set_license_type">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="Gtk.License" c:type="GtkLicense"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_logo"
+              c:identifier="granite_gtk_patch_about_dialog_set_logo">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="GdkPixbuf.Pixbuf" c:type="GdkPixbuf*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_logo_icon_name"
+              c:identifier="granite_gtk_patch_about_dialog_set_logo_icon_name">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_program_name"
+              c:identifier="granite_gtk_patch_about_dialog_set_program_name">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_translator_credits"
+              c:identifier="granite_gtk_patch_about_dialog_set_translator_credits">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_version"
+              c:identifier="granite_gtk_patch_about_dialog_set_version">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_website"
+              c:identifier="granite_gtk_patch_about_dialog_set_website">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_website_label"
+              c:identifier="granite_gtk_patch_about_dialog_set_website_label">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_wrap_license"
+              c:identifier="granite_gtk_patch_about_dialog_set_wrap_license">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="gboolean" c:type="gboolean"/>
+          </parameter>
+        </parameters>
+      </method>
+      <property name="artists" writable="1" transfer-ownership="none">
+        <array>
+          <type name="utf8"/>
+        </array>
+      </property>
+      <property name="authors" writable="1" transfer-ownership="none">
+        <array>
+          <type name="utf8"/>
+        </array>
+      </property>
+      <property name="comments" writable="1" transfer-ownership="none">
+        <type name="utf8"/>
+      </property>
+      <property name="copyright" writable="1" transfer-ownership="none">
+        <type name="utf8"/>
+      </property>
+      <property name="documenters" writable="1" transfer-ownership="none">
+        <array>
+          <type name="utf8"/>
+        </array>
+      </property>
+      <property name="license" writable="1" transfer-ownership="none">
+        <type name="utf8"/>
+      </property>
+      <property name="license-type" writable="1" transfer-ownership="none">
+        <type name="Gtk.License"/>
+      </property>
+      <property name="logo" writable="1" transfer-ownership="none">
+        <type name="GdkPixbuf.Pixbuf"/>
+      </property>
+      <property name="logo-icon-name" writable="1" transfer-ownership="none">
+        <type name="utf8"/>
+      </property>
+      <property name="program-name" writable="1" transfer-ownership="none">
+        <type name="utf8"/>
+      </property>
+      <property name="translator-credits"
+                writable="1"
+                transfer-ownership="none">
+        <type name="utf8"/>
+      </property>
+      <property name="version" writable="1" transfer-ownership="none">
+        <type name="utf8"/>
+      </property>
+      <property name="website" writable="1" transfer-ownership="none">
+        <type name="utf8"/>
+      </property>
+      <property name="website-label" writable="1" transfer-ownership="none">
+        <type name="utf8"/>
+      </property>
+      <property name="wrap-license" writable="1" transfer-ownership="none">
+        <type name="gboolean"/>
+      </property>
+      <field name="parent_instance">
+        <type name="Gtk.Dialog" c:type="GtkDialog"/>
+      </field>
+      <field name="priv">
+        <type name="GtkPatchAboutDialogPrivate"
+              c:type="GraniteGtkPatchAboutDialogPrivate*"/>
+      </field>
+      <field name="action_hbox">
+        <type name="Gtk.HBox" c:type="GtkHBox*"/>
+      </field>
+      <field name="action_homogeneous_hbox">
+        <type name="Gtk.HBox" c:type="GtkHBox*"/>
+      </field>
+      <glib:signal name="activate-link" when="last">
+        <return-value transfer-ownership="none">
+          <type name="gboolean"/>
+        </return-value>
+        <parameters>
+          <parameter name="object" transfer-ownership="none">
+            <type name="utf8"/>
+          </parameter>
+        </parameters>
+      </glib:signal>
+    </class>
+    <record name="GtkPatchAboutDialogClass"
+            c:type="GraniteGtkPatchAboutDialogClass"
+            glib:is-gtype-struct-for="GtkPatchAboutDialog">
+      <field name="parent_class">
+        <type name="Gtk.DialogClass" c:type="GtkDialogClass"/>
+      </field>
+      <field name="activate_link">
+        <callback name="activate_link">
+          <return-value transfer-ownership="none">
+            <type name="gboolean" c:type="gboolean"/>
+          </return-value>
+          <parameters>
+            <parameter name="self" transfer-ownership="none">
+              <type name="GtkPatchAboutDialog"
+                    c:type="GraniteGtkPatchAboutDialog*"/>
+            </parameter>
+            <parameter name="uri" transfer-ownership="none">
+              <type name="utf8" c:type="gchar*"/>
+            </parameter>
+          </parameters>
+        </callback>
+      </field>
+    </record>
+    <record name="GtkPatchAboutDialogPrivate"
+            c:type="GraniteGtkPatchAboutDialogPrivate"
+            disguised="1">
+    </record>
     <enumeration name="ServicesLogLevel"
                  glib:type-name="GraniteServicesLogLevel"
                  glib:get-type="granite_services_log_level_get_type"
@@ -1653,7 +2110,8 @@
         </parameters>
       </function>
       <function name="set_xdg_data_dir_folders"
-                c:identifier="granite_services_paths_set_xdg_data_dir_folders">
+                c:identifier="granite_services_paths_set_xdg_data_dir_folders"
+                introspectable="0">
         <return-value transfer-ownership="none">
           <type name="none" c:type="void"/>
         </return-value>
@@ -1815,7 +2273,12 @@
         <type name="ServicesSettingsPrivate"
               c:type="GraniteServicesSettingsPrivate*"/>
       </field>
-      <glib:signal name="changed">
+      <glib:signal name="changed"
+                   when="first"
+                   no-recurse="1"
+                   detailed="1"
+                   action="1"
+                   no-hooks="1">
         <return-value transfer-ownership="none">
           <type name="none"/>
         </return-value>
@@ -2058,6 +2521,117 @@
         </parameter>
       </parameters>
     </callback>
+    <class name="WidgetsAboutDialog"
+           c:symbol-prefix="widgets_about_dialog"
+           c:type="GraniteWidgetsAboutDialog"
+           parent="GtkPatchAboutDialog"
+           glib:type-name="GraniteWidgetsAboutDialog"
+           glib:get-type="granite_widgets_about_dialog_get_type"
+           glib:type-struct="WidgetsAboutDialogClass">
+      <implements name="Atk.ImplementorIface"/>
+      <implements name="Gtk.Buildable"/>
+      <constructor name="new" c:identifier="granite_widgets_about_dialog_new">
+        <return-value transfer-ownership="none">
+          <type name="WidgetsAboutDialog" c:type="GraniteWidgetsAboutDialog*"/>
+        </return-value>
+      </constructor>
+      <function name="construct"
+                c:identifier="granite_widgets_about_dialog_construct"
+                introspectable="0">
+        <return-value>
+          <type name="WidgetsAboutDialog" c:type="GraniteWidgetsAboutDialog*"/>
+        </return-value>
+        <parameters>
+          <parameter name="object_type" transfer-ownership="none">
+            <type name="GType" c:type="GType"/>
+          </parameter>
+        </parameters>
+      </function>
+      <method name="get_bug"
+              c:identifier="granite_widgets_about_dialog_get_bug">
+        <return-value transfer-ownership="none">
+          <type name="utf8" c:type="gchar*"/>
+        </return-value>
+      </method>
+      <method name="get_help"
+              c:identifier="granite_widgets_about_dialog_get_help">
+        <return-value transfer-ownership="none">
+          <type name="utf8" c:type="gchar*"/>
+        </return-value>
+      </method>
+      <method name="get_translate"
+              c:identifier="granite_widgets_about_dialog_get_translate">
+        <return-value transfer-ownership="none">
+          <type name="utf8" c:type="gchar*"/>
+        </return-value>
+      </method>
+      <method name="set_bug"
+              c:identifier="granite_widgets_about_dialog_set_bug">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_help"
+              c:identifier="granite_widgets_about_dialog_set_help">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_translate"
+              c:identifier="granite_widgets_about_dialog_set_translate">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="update" c:identifier="granite_widgets_about_dialog_update">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+      </method>
+      <property name="bug" writable="1" transfer-ownership="none">
+        <type name="utf8"/>
+      </property>
+      <property name="help" writable="1" transfer-ownership="none">
+        <type name="utf8"/>
+      </property>
+      <property name="translate" writable="1" transfer-ownership="none">
+        <type name="utf8"/>
+      </property>
+      <field name="parent_instance">
+        <type name="GtkPatchAboutDialog" c:type="GraniteGtkPatchAboutDialog"/>
+      </field>
+      <field name="priv">
+        <type name="WidgetsAboutDialogPrivate"
+              c:type="GraniteWidgetsAboutDialogPrivate*"/>
+      </field>
+    </class>
+    <record name="WidgetsAboutDialogClass"
+            c:type="GraniteWidgetsAboutDialogClass"
+            glib:is-gtype-struct-for="WidgetsAboutDialog">
+      <field name="parent_class">
+        <type name="GtkPatchAboutDialogClass"
+              c:type="GraniteGtkPatchAboutDialogClass"/>
+      </field>
+    </record>
+    <record name="WidgetsAboutDialogPrivate"
+            c:type="GraniteWidgetsAboutDialogPrivate"
+            disguised="1">
+    </record>
     <class name="WidgetsAppMenu"
            c:symbol-prefix="widgets_app_menu"
            c:type="GraniteWidgetsAppMenu"
@@ -2078,6 +2652,26 @@
           </parameter>
         </parameters>
       </constructor>
+      <constructor name="new_with_urls"
+                   c:identifier="granite_widgets_app_menu_new_with_urls">
+        <return-value transfer-ownership="none">
+          <type name="WidgetsAppMenu" c:type="GraniteWidgetsAppMenu*"/>
+        </return-value>
+        <parameters>
+          <parameter name="menu" transfer-ownership="none">
+            <type name="Gtk.Menu" c:type="GtkMenu*"/>
+          </parameter>
+          <parameter name="help_url" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+          <parameter name="translate_url" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+          <parameter name="bug_url" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </constructor>
       <function name="construct"
                 c:identifier="granite_widgets_app_menu_construct"
                 introspectable="0">
@@ -2093,6 +2687,51 @@
           </parameter>
         </parameters>
       </function>
+      <function name="construct_with_urls"
+                c:identifier="granite_widgets_app_menu_construct_with_urls"
+                introspectable="0">
+        <return-value>
+          <type name="WidgetsAppMenu" c:type="GraniteWidgetsAppMenu*"/>
+        </return-value>
+        <parameters>
+          <parameter name="object_type" transfer-ownership="none">
+            <type name="GType" c:type="GType"/>
+          </parameter>
+          <parameter name="menu" transfer-ownership="none">
+            <type name="Gtk.Menu" c:type="GtkMenu*"/>
+          </parameter>
+          <parameter name="help_url" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+          <parameter name="translate_url" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+          <parameter name="bug_url" transfer-ownership="none">
+            <type name="utf8" c:type="gchar*"/>
+          </parameter>
+        </parameters>
+      </function>
+      <virtual-method name="show_about">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="parent" transfer-ownership="none">
+            <type name="Gtk.Widget" c:type="GtkWidget*"/>
+          </parameter>
+        </parameters>
+      </virtual-method>
+      <method name="add_items"
+              c:identifier="granite_widgets_app_menu_add_items">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="menu" transfer-ownership="none">
+            <type name="Gtk.Menu" c:type="GtkMenu*"/>
+          </parameter>
+        </parameters>
+      </method>
       <field name="parent_instance">
         <type name="WidgetsToolButtonWithMenu"
               c:type="GraniteWidgetsToolButtonWithMenu"/>
@@ -2101,6 +2740,28 @@
         <type name="WidgetsAppMenuPrivate"
               c:type="GraniteWidgetsAppMenuPrivate*"/>
       </field>
+      <field name="help_item">
+        <type name="Gtk.MenuItem" c:type="GtkMenuItem*"/>
+      </field>
+      <field name="translate_item">
+        <type name="Gtk.MenuItem" c:type="GtkMenuItem*"/>
+      </field>
+      <field name="report_item">
+        <type name="Gtk.MenuItem" c:type="GtkMenuItem*"/>
+      </field>
+      <field name="about_item">
+        <type name="Gtk.MenuItem" c:type="GtkMenuItem*"/>
+      </field>
+      <glib:signal name="show-about" when="last">
+        <return-value transfer-ownership="none">
+          <type name="none"/>
+        </return-value>
+        <parameters>
+          <parameter name="object" transfer-ownership="none">
+            <type name="Gtk.Widget"/>
+          </parameter>
+        </parameters>
+      </glib:signal>
     </class>
     <record name="WidgetsAppMenuClass"
             c:type="GraniteWidgetsAppMenuClass"
@@ -2109,6 +2770,21 @@
         <type name="WidgetsToolButtonWithMenuClass"
               c:type="GraniteWidgetsToolButtonWithMenuClass"/>
       </field>
+      <field name="show_about">
+        <callback name="show_about">
+          <return-value transfer-ownership="none">
+            <type name="none" c:type="void"/>
+          </return-value>
+          <parameters>
+            <parameter name="self" transfer-ownership="none">
+              <type name="WidgetsAppMenu" c:type="GraniteWidgetsAppMenu*"/>
+            </parameter>
+            <parameter name="parent" transfer-ownership="none">
+              <type name="Gtk.Widget" c:type="GtkWidget*"/>
+            </parameter>
+          </parameters>
+        </callback>
+      </field>
     </record>
     <record name="WidgetsAppMenuPrivate"
             c:type="GraniteWidgetsAppMenuPrivate"
@@ -2618,7 +3294,7 @@
         <type name="WidgetsModeButtonPrivate"
               c:type="GraniteWidgetsModeButtonPrivate*"/>
       </field>
-      <glib:signal name="mode-added">
+      <glib:signal name="mode-added" when="last">
         <return-value transfer-ownership="none">
           <type name="none"/>
         </return-value>
@@ -2631,7 +3307,7 @@
           </parameter>
         </parameters>
       </glib:signal>
-      <glib:signal name="mode-changed">
+      <glib:signal name="mode-changed" when="last">
         <return-value transfer-ownership="none">
           <type name="none"/>
         </return-value>
@@ -2641,7 +3317,7 @@
           </parameter>
         </parameters>
       </glib:signal>
-      <glib:signal name="mode-removed">
+      <glib:signal name="mode-removed" when="last">
         <return-value transfer-ownership="none">
           <type name="none"/>
         </return-value>
@@ -2727,6 +3403,110 @@
             c:type="GraniteWidgetsSearchBarPrivate"
             disguised="1">
     </record>
+    <class name="WidgetsStaticNotebook"
+           c:symbol-prefix="widgets_static_notebook"
+           c:type="GraniteWidgetsStaticNotebook"
+           parent="Gtk.VBox"
+           glib:type-name="GraniteWidgetsStaticNotebook"
+           glib:get-type="granite_widgets_static_notebook_get_type"
+           glib:type-struct="WidgetsStaticNotebookClass">
+      <implements name="Atk.ImplementorIface"/>
+      <implements name="Gtk.Buildable"/>
+      <implements name="Gtk.Orientable"/>
+      <constructor name="new"
+                   c:identifier="granite_widgets_static_notebook_new">
+        <return-value transfer-ownership="none">
+          <type name="WidgetsStaticNotebook"
+                c:type="GraniteWidgetsStaticNotebook*"/>
+        </return-value>
+      </constructor>
+      <function name="construct"
+                c:identifier="granite_widgets_static_notebook_construct"
+                introspectable="0">
+        <return-value>
+          <type name="WidgetsStaticNotebook"
+                c:type="GraniteWidgetsStaticNotebook*"/>
+        </return-value>
+        <parameters>
+          <parameter name="object_type" transfer-ownership="none">
+            <type name="GType" c:type="GType"/>
+          </parameter>
+        </parameters>
+      </function>
+      <method name="append_page"
+              c:identifier="granite_widgets_static_notebook_append_page">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="widget" transfer-ownership="none">
+            <type name="Gtk.Widget" c:type="GtkWidget*"/>
+          </parameter>
+          <parameter name="label" transfer-ownership="none">
+            <type name="Gtk.Label" c:type="GtkLabel*"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="get_page"
+              c:identifier="granite_widgets_static_notebook_get_page">
+        <return-value transfer-ownership="none">
+          <type name="gint" c:type="gint"/>
+        </return-value>
+      </method>
+      <method name="remove_page"
+              c:identifier="granite_widgets_static_notebook_remove_page">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="number" transfer-ownership="none">
+            <type name="gint" c:type="gint"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="set_page"
+              c:identifier="granite_widgets_static_notebook_set_page">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="value" transfer-ownership="none">
+            <type name="gint" c:type="gint"/>
+          </parameter>
+        </parameters>
+      </method>
+      <property name="page" writable="1" transfer-ownership="none">
+        <type name="gint"/>
+      </property>
+      <field name="parent_instance">
+        <type name="Gtk.VBox" c:type="GtkVBox"/>
+      </field>
+      <field name="priv">
+        <type name="WidgetsStaticNotebookPrivate"
+              c:type="GraniteWidgetsStaticNotebookPrivate*"/>
+      </field>
+      <glib:signal name="page-changed" when="last">
+        <return-value transfer-ownership="none">
+          <type name="none"/>
+        </return-value>
+        <parameters>
+          <parameter name="object" transfer-ownership="none">
+            <type name="gint"/>
+          </parameter>
+        </parameters>
+      </glib:signal>
+    </class>
+    <record name="WidgetsStaticNotebookClass"
+            c:type="GraniteWidgetsStaticNotebookClass"
+            glib:is-gtype-struct-for="WidgetsStaticNotebook">
+      <field name="parent_class">
+        <type name="Gtk.VBoxClass" c:type="GtkVBoxClass"/>
+      </field>
+    </record>
+    <record name="WidgetsStaticNotebookPrivate"
+            c:type="GraniteWidgetsStaticNotebookPrivate"
+            disguised="1">
+    </record>
     <class name="WidgetsTimePicker"
            c:symbol-prefix="widgets_time_picker"
            c:type="GraniteWidgetsTimePicker"
@@ -3187,7 +3967,7 @@
       <field name="options">
         <type name="Gtk.VBox" c:type="GtkVBox*"/>
       </field>
-      <glib:signal name="activated">
+      <glib:signal name="activated" when="last">
         <return-value transfer-ownership="none">
           <type name="none"/>
         </return-value>
@@ -3210,7 +3990,8 @@
             disguised="1">
     </record>
     <function name="easing_mode_transform"
-              c:identifier="granite_easing_mode_transform">
+              c:identifier="granite_easing_mode_transform"
+              moved-to="EasingMode.transform">
       <return-value transfer-ownership="none">
         <type name="gdouble" c:type="gdouble"/>
       </return-value>

=== added directory 'lib/GtkPatch'
=== added file 'lib/GtkPatch/AboutDialog.vala'
--- lib/GtkPatch/AboutDialog.vala	1970-01-01 00:00:00 +0000
+++ lib/GtkPatch/AboutDialog.vala	2011-09-18 08:52:23 +0000
@@ -0,0 +1,472 @@
+//  
+//  Copyright (C) 2011 Adrien Plazas
+// 
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//  
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// 
+//  Authors:
+//      Adrien Plazas <kekun.plazas@xxxxxxxxxxx>
+//  Artists:
+//      Daniel Foré <daniel@xxxxxxxxxxxxxxxx>
+// 
+
+/* TODO
+ * GtkPatch : update_website
+ * Demo : 
+ */
+using Gtk;
+using Gdk;
+
+public class Granite.GtkPatch.AboutDialog : Gtk.Dialog
+{
+	/**
+	 * The people who contributed artwork to the program, as a null-terminated array of strings.
+	 */
+	public string[] artists {
+		set {
+			_artists = value;
+			if (_artists == null || _artists.length == 0) {
+				artists_label.hide();
+				artists_label.set_text("");
+			}
+			else {
+				artists_label.set_text(set_string_from_string_array("Designed by" + ":\n", _artists));
+				artists_label.show();
+			}
+		}
+		get { return _artists; }
+	}
+	string[] _artists = new string[0];
+	
+	/**
+	 * The authors of the program, as a null-terminated array of strings.
+	 */
+	public string[] authors {
+		set {
+			_authors = value;
+			if (_authors == null || _authors.length == 0) {
+				authors_label.hide();
+				authors_label.set_text("");
+			}
+			else {
+				authors_label.set_text(set_string_from_string_array("Written by" + ":\n", _authors));
+				authors_label.show();
+			}
+		}
+		get { return _authors; }
+	}
+	string[] _authors = new string[0];
+	
+	/**
+	 * Comments about the program.
+	 */
+	public string comments {
+		set {
+			_comments = value;
+			if (_comments == null || _comments == "") {
+				comments_label.hide();
+				comments_label.set_text("");
+			}
+			else {
+				comments_label.set_text(_comments + "\n");
+				comments_label.show();
+			}
+		}
+		get { return _comments; }
+	}
+	string _comments = "";
+	
+	/**
+	 * Copyright information for the program.
+	 */
+	public string copyright {
+		set {
+			_copyright = value;
+			if (_copyright == null || _copyright == "") {
+				copyright_label.hide();
+				copyright_label.set_text("");
+			}
+			else {
+				copyright_label.set_text("Copyright © " + _copyright + "\n");
+				copyright_label.show();
+			}
+		}
+		get { return _copyright; }
+	}
+	string _copyright = "";
+	
+	/**
+	 * The people documenting the program, as a null-terminated array of strings.
+	 */
+	public string[] documenters {
+		set {
+			_documenters = value;
+			if (documenters.length == 0 || documenters == null)
+				documenters_label.hide();
+			else {
+				documenters_label.show();
+				documenters_label.set_text(set_string_from_string_array("Documented by:\n", documenters));
+			}
+		}
+		get { return _documenters; }
+	}
+	string[] _documenters = new string[0];
+	
+	/**
+	 * The license of the program.
+	 */
+	public string license {
+		set { _license = value; update_license(); }
+		get { return _license; }
+	}
+	string _license = "";
+	
+	public License license_type {
+		set { _license_type = value; update_license(); }
+		get { return _license_type; }
+	}
+	License _license_type = License.UNKNOWN;
+	
+	/**
+	 * A logo for the about box.
+	 */
+	public Pixbuf logo {
+		set { _logo = value; update_logo_image(); }
+		get { return _logo; }
+	}
+	Pixbuf _logo = null;
+	
+	/**
+	 * A named icon to use as the logo for the about box.
+	 */
+	public string logo_icon_name {
+		set { _logo_icon_name = value; update_logo_image(); }
+		get { return _logo_icon_name; }
+	}
+	string _logo_icon_name = "";
+	
+	/**
+	 * The name of the program.
+	 */
+	public string program_name {
+		set { _program_name = value; set_name_and_version(); }
+		get { return _program_name; }
+	}
+	string _program_name = "";
+	
+	/**
+	 * Credits to the translators.
+	 */
+	public string translator_credits {
+		set {
+			_translator_credits = value;
+			if (_translator_credits == null || _translator_credits == "") {
+				translators_label.hide();
+				translators_label.set_text("");
+			}
+			else {
+				translators_label.set_text("Translated by: " + _translator_credits + "\n");
+				translators_label.show();
+			}
+		}
+		get { return _translator_credits; }
+	}
+	string _translator_credits = "";
+	
+	/**
+	 * The version of the program.
+	 */
+	public string version {
+		set { _version = value; set_name_and_version(); }
+		get { return _version; }
+	}
+	string _version = "";
+	
+	/**
+	 * The URL for the link to the website of the program.
+	 */
+	public string website {
+		set { _website = value; update_website(); }
+		get { return _website; }
+	}
+	string _website = "";
+	
+	/**
+	 * The label for the link to the website of the program.
+	 */
+	public string website_label {
+		set { _website_label = value; update_website(); }
+		get { return _website_label; }
+	}
+	string _website_label = "";
+	
+	/**
+	 * Whether to wrap the text in the license dialog.
+	 */
+	public bool wrap_license {
+		set {
+			_wrap_license = value;
+			license_label.set_line_wrap(_wrap_license);
+		}
+		get { return _wrap_license; }
+	}
+	bool _wrap_license = true;
+	
+	// Signals
+	public virtual signal bool activate_link (string uri) {
+		// Improve error management FIXME
+		bool result = false;
+		if (uri != null)
+		{
+			try {
+				result = Gtk.show_uri(get_screen(), uri, Gtk.get_current_event_time());
+			} catch (Error err) {
+				stderr.printf ("Unable to open the URI: %s", err.message);
+			}
+		}
+		return result;
+	}
+	
+	// UI elements
+	Image logo_image;
+	Label name_label;
+	Label copyright_label;
+	Label comments_label;
+	Label authors_label;
+	Label artists_label;
+	Label documenters_label;
+	Label translators_label;
+	Label license_label;
+	Label website_url_label;
+	Button close_button;
+	
+	public HBox action_hbox;
+	public HBox action_homogeneous_hbox;
+	
+	string big_text_markup_start;
+	string big_text_markup_end;
+	
+	/**
+	 * Creates a new Granite.AboutDialog
+	 */
+	public AboutDialog()
+	{
+		has_resize_grip = false;
+		resizable = false;
+		set_default_response(ResponseType.CANCEL);
+		
+		// Set the markup used for big text (program name and version)
+		big_text_markup_start = "<span weight='heavy' size='x-large'>";
+		big_text_markup_end = "</span>";
+		
+		// Set the default containers
+		Box content_area = (Box)get_content_area();
+		Box action_area = (Box)get_action_area();
+		action_area.realize();
+		var content_hbox = new HBox(false, 12);
+		var content_scrolled = new ScrolledWindow(null, new Adjustment(0, 0, 100, 1, 10, 0));
+		var content_viewport = new Viewport(null, null);
+		var content_vbox = new VBox(false, 0);
+		action_hbox = new HBox(false, action_area.spacing);
+		action_homogeneous_hbox = new HBox(true, action_area.spacing);
+		
+		content_viewport.shadow_type = ShadowType.NONE;
+		content_scrolled.hscrollbar_policy = PolicyType.NEVER;
+		content_area.pack_start(content_hbox);
+		action_area.pack_start(action_hbox);
+		
+		logo_image = new Image();
+		
+		// Adjust sizes
+		content_hbox.margin = 12;
+		action_hbox.margin = 6;
+		content_hbox.height_request = 160;
+		content_vbox.width_request = 288;
+		logo_image.set_size_request(128, 128);
+		
+		name_label = new Label("");
+		name_label.xalign = 0;
+		name_label.set_line_wrap(true);
+		name_label.use_markup = true;
+		
+		close_button = new Button.from_stock(Stock.CLOSE);
+		
+		copyright_label = new Label("");
+		copyright_label.set_sensitive(false);
+		copyright_label.xalign = 0;
+		copyright_label.set_line_wrap(true);
+		
+		comments_label = new Label("");
+		comments_label.set_sensitive(false);
+		comments_label.xalign = 0;
+		comments_label.set_line_wrap(true);
+		
+		authors_label = new Label("");
+		authors_label.set_sensitive(false);
+		authors_label.xalign = 0;
+		authors_label.set_line_wrap(true);
+		
+		artists_label = new Label("");
+		artists_label.set_sensitive(false);
+		artists_label.xalign = 0;
+		artists_label.set_line_wrap(true);
+		
+		documenters_label = new Label("");
+		documenters_label.set_sensitive(false);
+		documenters_label.xalign = 0;
+		documenters_label.set_line_wrap(true);
+		
+		translators_label = new Label("");
+		translators_label.set_sensitive(false);
+		translators_label.xalign = 0;
+		translators_label.set_line_wrap(true);
+		
+		license_label = new Label("");
+		license_label.set_sensitive(false);
+		license_label.xalign = 0;
+		license_label.set_line_wrap(wrap_license);
+		
+		website_url_label = new Label("");
+		website_url_label.set_sensitive(false);
+		website_url_label.xalign = 0;
+		website_url_label.set_line_wrap(true);
+		
+		content_hbox.pack_start(logo_image);
+		content_hbox.pack_start(content_scrolled);
+		content_scrolled.add(content_viewport);
+		content_viewport.add(content_vbox);
+		
+		content_vbox.pack_start(name_label);
+		content_vbox.pack_start(comments_label);
+		content_vbox.pack_start(website_url_label);
+		
+		content_vbox.pack_start(copyright_label);
+		content_vbox.pack_start(license_label);
+		
+		content_vbox.pack_start(authors_label);
+		content_vbox.pack_start(artists_label);
+		content_vbox.pack_start(documenters_label);
+		content_vbox.pack_start(translators_label);
+		
+		action_hbox.pack_start(action_homogeneous_hbox);
+		action_homogeneous_hbox.pack_start(close_button);
+		
+		action_area.show_all();
+		content_area.show();
+		content_hbox.show();
+		content_scrolled.show();
+		content_viewport.show();
+		content_vbox.show();
+		logo_image.show();
+		
+		close_button.pressed.connect(() => { response(ResponseType.CANCEL); });
+	}
+	
+	private string set_string_from_string_array(string title, string[] list)
+	{
+		string text = title;
+		foreach (string i in list)
+			text += i + "\n";
+		return text;
+	}
+	
+	private void update_logo_image()
+	{
+		try {
+			logo_image.set_from_pixbuf(IconTheme.get_default ().load_icon ("application-default-icon", 128, 0));
+		} catch (Error err) {
+			stderr.printf ("Unable to load terminal icon: %s", err.message);
+		}
+		if (logo_icon_name != null && logo_icon_name != "") {
+			try {
+			logo_image.set_from_pixbuf(IconTheme.get_default ().load_icon (logo_icon_name, 128, 0));
+			} catch (Error err) {
+				stderr.printf ("Unable to load terminal icon: %s", err.message);
+			}
+		}
+		else if (logo != null)
+			logo_image.set_from_pixbuf(logo);
+	}
+	
+	private void update_license()
+	{
+		switch (license_type) {
+		case License.GPL_2_0:
+			set_generic_license("http://www.gnu.org/licenses/old-licenses/gpl-2.0.html";);
+			break;
+		case License.GPL_3_0:
+			set_generic_license("http://www.gnu.org/licenses/gpl.html";);
+			break;
+		case License.LGPL_2_1:
+			set_generic_license("http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html";);
+			break;
+		case License.LGPL_3_0:
+			set_generic_license("http://www.gnu.org/licenses/lgpl.html";);
+			break;
+		case License.BSD:
+			set_generic_license("http://opensource.org/licenses/bsd-license.php";);
+			break;
+		case License.MIT_X11:
+			set_generic_license("http://opensource.org/licenses/mit-license.php";);
+			break;
+		case License.ARTISTIC:
+			set_generic_license("http://opensource.org/licenses/artistic-license-2.0.php";);
+			break;
+		default:
+			if (license != null && license != "") {
+				license_label.set_markup(license + "\n");
+				license_label.show();
+			}
+			else
+				license_label.hide();
+			break;
+		}
+	}
+	
+	private void set_generic_license(string url)
+	{
+		license_label.set_markup("This program comes with ABSOLUTELY NO WARRANTY; for details, visit <a href=\"" + url + "\">" + url + "</a>\n");
+		license_label.show();
+	}
+	
+	private void set_name_and_version()
+	{
+		if (program_name != null && program_name != "")
+		{
+			set_title("About " + program_name);
+			name_label.set_text(program_name);
+			if (version != null && version != "")
+				name_label.set_text(name_label.get_text() + " " + version);
+			name_label.set_markup(big_text_markup_start + name_label.get_text() + big_text_markup_end + "\n");
+			name_label.show();
+		}
+		else
+			name_label.hide();
+			set_title("About");
+	}
+	
+	private void update_website()
+	{
+		if (website != null && website != "") {
+			if (website != null && website != "") {
+				website_url_label.set_markup("<a href=\"" + website + "\">" + website_label + "</a>\n");
+			}
+			else
+				website_url_label.set_markup("<a href=\"" + website + "\">" + website + "</a>\n");
+			website_url_label.show();
+		}
+		else
+			website_url_label.hide();
+	}
+}

=== added file 'lib/Widgets/AboutDialog.vala'
--- lib/Widgets/AboutDialog.vala	1970-01-01 00:00:00 +0000
+++ lib/Widgets/AboutDialog.vala	2011-09-18 08:52:23 +0000
@@ -0,0 +1,96 @@
+//  
+//  Copyright (C) 2011 Adrien Plazas
+// 
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//  
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+// 
+//  Authors:
+//      Adrien Plazas <kekun.plazas@xxxxxxxxxxx>
+//  Artists:
+//      Daniel Foré <daniel@xxxxxxxxxxxxxxxx>
+// 
+
+using Gtk;
+
+public class Granite.Widgets.AboutDialog : Granite.GtkPatch.AboutDialog
+{
+	/**
+	 * The URL for the link to the website of the program.
+	 */
+	public string help {
+		set {
+			_help = value;
+			help_button.sensitive = !(_help == null || _help == "");
+		}
+		get { return _help; }
+	}
+	string _help = "";
+	
+	/**
+	 * The URL for the link to the website of the program.
+	 */
+	public string translate {
+		set {
+			_translate = value;
+			translate_button.sensitive = !(_translate == null || _translate == "");
+		}
+		get { return _translate; }
+	}
+	string _translate = "";
+	
+	/**
+	 * The URL for the link to the website of the program.
+	 */
+	public string bug {
+		set {
+			_bug = value;
+			bug_button.sensitive = !(_bug == null || _bug == "");
+		}
+		get { return _bug; }
+	}
+	string _bug = "";
+	
+	Button help_button;
+	Button translate_button;
+	Button bug_button;
+	
+	/**
+	 * Creates a new Granite.AboutDialog
+	 */
+	public AboutDialog()
+	{
+		// Creating the buttons
+		help_button = new Button.with_label(" ? ");
+		help_button.pressed.connect(() => { activate_link(help); });
+		
+		translate_button = new Button.with_label("Translate this app");
+		translate_button.pressed.connect(() => { activate_link(translate); });
+		
+		bug_button = new Button.with_label("Report a problem");
+		bug_button.pressed.connect(() => { activate_link(bug); });
+		
+		// Pack
+		action_hbox.pack_start(help_button);
+		action_hbox.reorder_child(help_button, 0);
+		action_homogeneous_hbox.pack_start(translate_button);
+		action_homogeneous_hbox.pack_start(bug_button);
+		action_homogeneous_hbox.reorder_child(bug_button, 0);
+		action_homogeneous_hbox.reorder_child(translate_button, 0);
+		
+		// Show
+		help_button.show();
+		translate_button.show();
+		bug_button.show();
+	}
+}

=== modified file 'lib/Widgets/AppMenu.vala'
--- lib/Widgets/AppMenu.vala	2011-08-25 21:43:08 +0000
+++ lib/Widgets/AppMenu.vala	2011-09-18 08:52:23 +0000
@@ -23,9 +23,6 @@
 	
 	public class AppMenu : ToolButtonWithMenu {
 	
-	    public MenuItem help_item;
-	    public MenuItem translate_item;
-	    public MenuItem report_item;
 	    public MenuItem about_item;
 	
 	    /**
@@ -33,45 +30,32 @@
 	     *
 	     * @deprecated
 	     */
+//~ 		public AppMenu (Menu menu) {
+//~ 			
+//~ 			base (new Image.from_stock (Stock.PROPERTIES, IconSize.MENU), _("Menu"), menu);
+//~ 			
+//~ 			this.add_items (menu);
+//~ 			
+//~ 			about_item.activate.connect (() => Granite.app.show_about (get_toplevel ()));
+//~ 		}
+		
+		public virtual signal void show_about (Gtk.Widget parent) { }
+		
 		public AppMenu (Menu menu) {
-			
-			base (new Image.from_stock (Stock.PROPERTIES, IconSize.MENU), _("Menu"), menu);
-			
-			this.add_items (menu);
-			
-			help_item.activate.connect(() => System.open_uri (Granite.app.help_url));
-			translate_item.activate.connect(() => System.open_uri (Granite.app.translate_url));
-			report_item.activate.connect(() => System.open_uri (Granite.app.bug_url));
-			about_item.activate.connect (() => Granite.app.show_about (get_toplevel ()));
-		}
-		
-		public virtual signal void show_about (Gtk.Widget parent) { }
-		
-		public AppMenu.with_urls (Menu menu, string help_url, string translate_url, string bug_url) {
-		
-			base (new Image.from_stock (Stock.PROPERTIES, IconSize.MENU), _("Menu"), menu);
-			
-			this.add_items (menu);
-			
-			help_item.activate.connect(() => System.open_uri (help_url));
-			translate_item.activate.connect(() => System.open_uri (translate_url));
-			report_item.activate.connect(() => System.open_uri (bug_url));
+		
+			base (new Image.from_stock (Stock.PROPERTIES, IconSize.MENU), _("Menu"), menu);
+			
+			this.add_items (menu);
+			
 			about_item.activate.connect (() => this.show_about (get_toplevel ()));
 		}
 		
 		public void add_items (Menu menu) {
 		    
-		    help_item = new MenuItem.with_label (_("Get Help Online..."));
-			translate_item = new MenuItem.with_label (_("Translate This Application..."));
-			report_item = new MenuItem.with_label (_("Report a Problem..."));
 			about_item = new MenuItem.with_label (_("About"));
 			
 			if (menu.get_children ().length () > 0)
 				menu.append (new SeparatorMenuItem ());
-			menu.append (help_item);
-			menu.append (translate_item);
-			menu.append (report_item);
-			menu.append (new SeparatorMenuItem ());
 			menu.append (about_item);
 		}
 		

=== modified file 'lib/Widgets/ModeButton.vala'
--- lib/Widgets/ModeButton.vala	2011-09-17 18:08:27 +0000
+++ lib/Widgets/ModeButton.vala	2011-09-18 08:52:23 +0000
@@ -23,17 +23,25 @@
      
     public class ModeButton : HBox {
 	  
+<<<<<<< TREE
 		public signal void mode_added (int index, Gtk.Widget widget);
 		public signal void mode_removed (int index, Gtk.Widget widget);
 		public signal void mode_changed (Gtk.Widget widget);
 		static CssProvider style_provider;
  
+=======
+		public signal void mode_added (int index, Gtk.Widget widget);
+		public signal void mode_removed (int index, Gtk.Widget widget);
+		public signal void mode_changed (Gtk.Widget widget);
+
+>>>>>>> MERGE-SOURCE
 		private int _selected = -1;
 		public int selected {
 			get {
 				return _selected;
 			}
 			set {
+<<<<<<< TREE
 				set_active(value);
 			}
 		}
@@ -120,6 +128,88 @@
 	public class ModeButton : Gtk.EventBox, Gtk.Buildable {
 
 		public new void focus (Gtk.Widget widget) {
+=======
+				if (value == _selected || value < 0 || value >= box.get_children().length())
+					return;
+
+				if (_selected >= 0)
+					box.get_children ().nth_data (_selected).set_state (StateType.NORMAL);
+
+				_selected = value;
+				box.get_children ().nth_data (_selected).set_state (StateType.SELECTED);
+				queue_draw ();
+
+				Gtk.Widget selectedItem = (value >= 0) ? box.get_children ().nth_data (value) : null;
+				mode_changed (selectedItem);
+			}
+		}
+		
+		private int _hovered = -1;
+		public int hovered {
+			get {
+				return _hovered;
+			}
+			set {
+				if (value == _hovered || value <= -1 || value >= box.get_children().length())
+					return;
+
+				_hovered = value;
+				queue_draw ();
+			}
+		}
+
+		private HBox box;
+
+		construct {
+		
+			events |= EventMask.BUTTON_PRESS_MASK
+				   |  EventMask.POINTER_MOTION_MASK
+				   |  EventMask.LEAVE_NOTIFY_MASK; 
+
+			box = new HBox (true, 1);
+			box.border_width = 0;
+			add (box);
+			box.show ();
+			set_visible_window (false);
+			
+			set_size_request(-1, 24);
+			
+			get_style_context().add_class("button");
+		}
+		
+		private void add_child (Builder builder, Object child, string? type) {
+			
+			append (child as Gtk.Widget);
+		}
+		
+		public void append (Gtk.Widget widget) {
+		
+			box.pack_start (widget, true, true, 3);
+			int index = (int) box.get_children ().length () - 2;
+			mode_added (index, widget);
+			int height;
+			widget.set_margin_right(3);
+			widget.set_margin_left(3);
+			widget.set_margin_top(3);
+			widget.set_margin_bottom(3);
+		}
+
+		public new void remove (int index) {
+		
+			Gtk.Widget child = box.get_children ().nth_data (index);
+			box.remove (child);
+			if (_selected == index)
+				_selected = -1;
+			else if (_selected >= index)
+				_selected--;
+			if (_hovered >= index)
+				_hovered--;
+			mode_removed (index, child);
+			queue_draw ();
+		}
+
+		public new void focus (Gtk.Widget widget) {
+>>>>>>> MERGE-SOURCE
 		
 			int select = box.get_children ().index (widget);
 


Follow ups