Merge lp:~ev/activity-log-manager/whoopsie into lp:~activity-log-manager/activity-log-manager/vala

Proposed by Evan
Status: Merged
Merged at revision: 85
Proposed branch: lp:~ev/activity-log-manager/whoopsie
Merge into: lp:~activity-log-manager/activity-log-manager/vala
Diff against target: 984 lines (+808/-7)
14 files modified
.bzrignore (+1/-0)
configure.ac (+16/-1)
po/POTFILES.in (+1/-0)
src/Makefile.am (+23/-6)
src/activity-log-manager.vala (+4/-0)
src/alm-cc.c (+8/-0)
src/diagnostics-widget.c (+193/-0)
src/diagnostics/Makefile.am (+44/-0)
src/diagnostics/com.ubuntu.WhoopsiePreferences.conf (+26/-0)
src/diagnostics/com.ubuntu.WhoopsiePreferences.service (+4/-0)
src/diagnostics/com.ubuntu.whoopsiepreferences.policy (+18/-0)
src/diagnostics/whoopsie-preferences.c (+297/-0)
src/diagnostics/whoopsie-preferences.xml (+8/-0)
src/diagnostics/whoopsie.ui (+165/-0)
To merge this branch: bzr merge lp:~ev/activity-log-manager/whoopsie
Reviewer Review Type Date Requested Status
Manish Sinha (मनीष सिन्हा) Approve
Review via email: mp+93899@code.launchpad.net

Description of the change

As discussed with Seif and the Canonical design team, we should merge the two existing privacy pages in GNOME Control Center into a single entity, under activity-log-manager. Here is a branch to do just that.

Christian has provided the following mockup as guidance:

http://dl.dropbox.com/u/2935618/canonical/ss/privacy-7.png

The privacy page for the Ubuntu crash report settings, hereafter referred to as "diagnostics," provides a small DBus daemon for writing the root-owned /etc/default/whoopsie preferences file.

This also adds a dependency on PolicyKit.

I've only made one change to activity-log-manager itself, which exposes a new append_page method to allow adding the diagnostics page.

As stated previously in #ubuntu-release and #ubuntu-devel, this code already exists in another form in the archive (whoopsie-daisy), and it is the release team's belief that it therefore falls under UI Freeze and not Feature Freeze. However, care will have to be taken to coordinate a release of whoopsie-daisy that does not have the aforementioned files.

To post a comment you must log in.
Revision history for this message
Seif Lotfy (seif) wrote :

Can you please make sure that the makefile is complete... I can't compile it due to

make[3]: *** No rule to make target `diagnostics/whoopsie-generated.c', needed by `libactivity_log_manager_la_vala.stamp'. Stop.
make[3]: Leaving directory `/home/seif/Projects/whoopsie/src'

Revision history for this message
Evan (ev) wrote :

On Mon, Feb 20, 2012 at 8:51 PM, Seif Lotfy <email address hidden> wrote:
> Can you please make sure that the makefile is complete... I can't compile it due to
>
> make[3]: *** No rule to make target `diagnostics/whoopsie-generated.c', needed by `libactivity_log_manager_la_vala.stamp'.  Stop.
> make[3]: Leaving directory `/home/seif/Projects/whoopsie/src'

Fixed in r85. This was due to the autogenerated vala targets pulling
in libactivity-log-manager even when --with-ccpanel was not set. I've
worked around that by explicitly building against the C source
targets:

activity_log_manager_la_SOURCES = \
    $(SOURCES:.vala=.c) alm-cc.c \
    diagnostics-widget.c \
    diagnostics/whoopsie-generated.c

Revision history for this message
Seif Lotfy (seif) wrote :

Since this is upstream work that will be deployed elsewhere I would like to
have this part optional...
Which means if possible can you make it so if i pass --enable-whoopsie or
--mode=ubuntu upon configuring that the whoopsie widget appears. It should
be disabled by default

cheers
Seif

On Mon, Feb 20, 2012 at 10:48 PM, Evan Dandrea
<email address hidden>wrote:

> On Mon, Feb 20, 2012 at 8:51 PM, Seif Lotfy <email address hidden> wrote:
> > Can you please make sure that the makefile is complete... I can't
> compile it due to
> >
> > make[3]: *** No rule to make target `diagnostics/whoopsie-generated.c',
> needed by `libactivity_log_manager_la_vala.stamp'. Stop.
> > make[3]: Leaving directory `/home/seif/Projects/whoopsie/src'
>
> Fixed in r85. This was due to the autogenerated vala targets pulling
> in libactivity-log-manager even when --with-ccpanel was not set. I've
> worked around that by explicitly building against the C source
> targets:
>
> activity_log_manager_la_SOURCES = \
> $(SOURCES:.vala=.c) alm-cc.c \
> diagnostics-widget.c \
> diagnostics/whoopsie-generated.c
>
> --
> https://code.launchpad.net/~ev/activity-log-manager/whoopsie/+merge/93899
> Your team Activity Log Manager is requested to review the proposed merge
> of lp:~ev/activity-log-manager/whoopsie into lp:activity-log-manager.
>

Revision history for this message
Seif Lotfy (seif) wrote :

Also I cant seem to see the panel anywhere...
Since this is being merged into an upstream project can you please make it so it is disabled by default..
It should be enabled upon configuring by passing a -enable-whoopsie parameter

Revision history for this message
Manish Sinha (मनीष सिन्हा) (manishsinha) wrote :

Please make this as optional (--enable-whoopsie) otherwise it cannot be packaged in other distributions without whoopsie being packaged

review: Needs Fixing (build system)
Revision history for this message
Evan (ev) wrote :

On Mon, Feb 20, 2012 at 10:05 PM, Seif Lotfy <email address hidden> wrote:
> Also I cant seem to see the panel anywhere...
> Since this is being merged into an upstream project can you please make it so it is disabled by default..
> It should be enabled upon configuring by passing a -enable-whoopsie parameter

Okay, I've made the diagnostics tab optional. Enable it by passing
--with-whoopsie to configure. You should then see a "Diagnostics" tab
on the GNOME Control Center Privacy page's GtkNotebook.

Revision history for this message
Evan (ev) wrote :

On Tue, Feb 21, 2012 at 10:31 AM, Evan Dandrea
<email address hidden> wrote:
> Okay, I've made the diagnostics tab optional.  Enable it by passing
> --with-whoopsie to configure.  You should then see a "Diagnostics" tab
> on the GNOME Control Center Privacy page's GtkNotebook.

That's r86.

Revision history for this message
Seif Lotfy (seif) wrote :

Evan I dont mind also having it in the standalone version :D

Revision history for this message
Manish Sinha (मनीष सिन्हा) (manishsinha) wrote :

I get symbol lookup error. This is what I did

./autogen.sh --prefix=/usr --with-ccpanel --with-whoopsie
sudo make install

Running as
$ gnome-control-center activity-log-manager

gnome-control-center: symbol lookup error: /usr/lib/control-center-1/panels/libactivity-log-manager.so: undefined symbol: whoopsie_daisy_preferences_new

----------------

Running strace
$ strace gnome-control-center activity-log-manager

futex(0x20f578b4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x20f578b0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
futex(0x20f57fe0, FUTEX_WAKE_PRIVATE, 1) = 1
writev(2, [{"gnome-control-center", 20}, {": ", 2}, {"symbol lookup error", 19}, {": ", 2}, {"/usr/lib/control-center-1/panels"..., 59}, {": ", 2}, {"undefined symbol: whoopsie_daisy"..., 48}, {"", 0}, {"", 0}, {"\n", 1}], 10gnome-control-center: symbol lookup error: /usr/lib/control-center-1/panels/libactivity-log-manager.so: undefined symbol: whoopsie_daisy_preferences_new
) = 153
exit_group(127)

review: Needs Fixing (symbols)
Revision history for this message
Evan (ev) wrote :

On Tue, Feb 21, 2012 at 3:00 PM, Manish Sinha (मनीष सिन्हा
<email address hidden> wrote:
> Review: Needs Fixing symbols
>
> I get symbol lookup error. This is what I did
>
> ./autogen.sh --prefix=/usr --with-ccpanel --with-whoopsie
> sudo make install

This should be fixed in r87. You don't have to specify both
--with-ccpanel and --with-whoopsie. Setting --with-whoopsie will
imply --with-ccpanel.

Revision history for this message
Evan (ev) wrote :

On Tue, Feb 21, 2012 at 2:55 PM, Seif Lotfy <email address hidden> wrote:
> Evan I dont mind also having it in the standalone version :D

Sure, but presumably that requires building the whoopsie code as a
library and generating a vapi, as you cannot directly call C code from
vala source.

So could we get that in a second pass, given that UI freeze is tomorrow?

Revision history for this message
Seif Lotfy (seif) wrote :

Yep merging tomorrow first thing

On Wed, Feb 22, 2012 at 12:41 AM, Evan Dandrea
<email address hidden>wrote:

> On Tue, Feb 21, 2012 at 2:55 PM, Seif Lotfy <email address hidden> wrote:
> > Evan I dont mind also having it in the standalone version :D
>
> Sure, but presumably that requires building the whoopsie code as a
> library and generating a vapi, as you cannot directly call C code from
> vala source.
>
> So could we get that in a second pass, given that UI freeze is tomorrow?
>
> --
> https://code.launchpad.net/~ev/activity-log-manager/whoopsie/+merge/93899
> Your team Activity Log Manager is subscribed to branch
> lp:activity-log-manager.
>

lp:~ev/activity-log-manager/whoopsie updated
85. By Seif Lotfy

merge

Revision history for this message
Manish Sinha (मनीष सिन्हा) (manishsinha) wrote :

Will try it out in a few hours (when back from work) and getting it merged. alm needs to be released today so that it can be uploaded before UIF hits

Revision history for this message
Manish Sinha (मनीष सिन्हा) (manishsinha) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2012-02-15 19:55:47 +0000
3+++ .bzrignore 2012-02-21 23:40:22 +0000
4@@ -31,6 +31,7 @@
5 src/applications-widget.c
6 src/files-widget.c
7 src/history-widget.c
8+src/diagnostics/Makefile
9 po/*.gmo
10 src/*.lo
11 po/stamp-it
12
13=== modified file 'configure.ac'
14--- configure.ac 2012-02-14 20:20:46 +0000
15+++ configure.ac 2012-02-21 23:40:22 +0000
16@@ -35,6 +35,7 @@
17 PKG_CHECK_MODULES(GTK, gtk+-3.0, [HAVE_GTK=yes], [HAVE_GTK=no])
18 PKG_CHECK_MODULES(GEE, gee-1.0, [HAVE_GEE=yes], [HAVE_GEE=no])
19 PKG_CHECK_MODULES(GIO_UNIX, gio-unix-2.0, [HAVE_GIO_UNIX=yes], [HAVE_GIO_UNIX=no])
20+PKG_CHECK_MODULES(POLKIT, polkit-gobject-1, [HAVE_POLKIT=yes], [HAVE_POLKIT=no])
21
22 AC_ARG_WITH([extensiondir],
23 [AS_HELP_STRING([--with-extensiondir],
24@@ -42,6 +43,11 @@
25 [],
26 [with_extensiondir=yes])
27
28+AC_ARG_WITH([whoopsie],
29+ [AS_HELP_STRING([--with-whoopsie],
30+ [build control-center plugin Ubuntu crash reporting page @<:@default=check@:>@])],
31+ [with_ccpanel=yes],
32+ [with_whoopsie=check])
33 AC_ARG_WITH([ccpanel],
34 [AS_HELP_STRING([--with-ccpanel],
35 [build control-center plugin @<:@default=check@:>@])],
36@@ -56,7 +62,11 @@
37 [CCPANEL_DIR=`$PKG_CONFIG --variable=extensiondir libgnome-control-center`],
38 [CCPANEL_DIR="${PREFIX}/lib/control-center-1/panels"])
39 AC_SUBST(CCPANEL_DIR),
40- [if test "x$with_ccpanel" != xcheck; then
41+ [if test "x$with_whoopsie" != xcheck; then
42+ AC_MSG_FAILURE(
43+ [--with-whoopsie was given, but test for libgnome-control-center failed])
44+ fi
45+ if test "x$with_ccpanel" != xcheck; then
46 AC_MSG_FAILURE(
47 [--with-ccpanel was given, but test for libgnome-control-center failed])
48 fi
49@@ -64,6 +74,10 @@
50 )]
51 )
52 AM_CONDITIONAL([HAVE_CCPANEL], [test -n "$CCPANEL_LIBS"])
53+AM_CONDITIONAL([HAVE_WHOOPSIE], [test "x$with_whoopsie" != xcheck])
54+AS_IF([test "x$with_whoopsie" != xcheck],
55+ AC_DEFINE([HAVE_WHOOPSIE], [1],
56+ [Build control-center plugin Ubuntu crash reporting page]), [])
57
58
59
60@@ -71,5 +85,6 @@
61 Makefile
62 data/Makefile
63 src/Makefile
64+src/diagnostics/Makefile
65 po/Makefile.in
66 ])
67
68=== modified file 'po/POTFILES.in'
69--- po/POTFILES.in 2012-02-14 20:20:46 +0000
70+++ po/POTFILES.in 2012-02-21 23:40:22 +0000
71@@ -6,3 +6,4 @@
72 src/applications-widget.vala
73 src/files-widget.vala
74 src/history-widget.vala
75+src/diagnostics/whoopsie.ui
76
77=== modified file 'src/Makefile.am'
78--- src/Makefile.am 2012-02-08 14:19:18 +0000
79+++ src/Makefile.am 2012-02-21 23:40:22 +0000
80@@ -2,6 +2,11 @@
81 ccpaneldir = $(CCPANEL_DIR)
82 ccpanel_LTLIBRARIES = libactivity-log-manager.la
83 endif
84+if HAVE_WHOOPSIE
85+gnomeccuidir = $(datadir)/gnome-control-center/ui/
86+endif
87+
88+SUBDIRS = diagnostics
89
90 VALAFLAGS = \
91 --pkg zeitgeist-1.0 \
92@@ -9,7 +14,7 @@
93 --pkg gee-1.0 \
94 --target-glib=2.26 \
95 --pkg gio-unix-2.0 \
96- config.vapi
97+ config.vapi
98
99 bin_PROGRAMS = activity-log-manager
100
101@@ -28,6 +33,11 @@
102 $(SHARED_CFLAGS) \
103 $(CCPANEL_CFLAGS)
104
105+if HAVE_WHOOPSIE
106+libactivity_log_manager_la_CFLAGS += \
107+ $(POLKIT_CFLAGS) \
108+ -DGNOMECC_UI_DIR=\""$(gnomeccuidir)"\"
109+endif
110
111 SOURCES = \
112 activity-log-manager.vala \
113@@ -38,7 +48,13 @@
114 activity_log_manager_SOURCES = \
115 $(SOURCES) alm.vala
116 libactivity_log_manager_la_SOURCES = \
117- $(SOURCES) alm-cc.c
118+ $(SOURCES:.vala=.c) alm-cc.c
119+
120+if HAVE_WHOOPSIE
121+libactivity_log_manager_la_SOURCES += \
122+ diagnostics-widget.c \
123+ diagnostics/whoopsie-generated.c
124+endif
125
126 activity_log_manager_LDFLAGS = \
127 -Wl,--export-dynamic
128@@ -55,6 +71,11 @@
129 $(SHARED_LIBS) \
130 $(CCPANEL_LIBS)
131
132+if HAVE_WHOOPSIE
133+libactivity_log_manager_la_LIBADD += \
134+ $(POLKIT_LIBS)
135+endif
136+
137 GENERATED_C_FILES = $(alm_SOURCES:.vala=.c)
138
139 GENERATED_O_FILES = $(alm_SOURCES:.vala=.o)
140@@ -62,7 +83,3 @@
141 CLEANFILES = \
142 $(GENERATED_C_FILES) \
143 $(GENERATED_O_FILES)
144-
145-
146-
147-
148
149=== modified file 'src/activity-log-manager.vala'
150--- src/activity-log-manager.vala 2012-02-18 21:38:27 +0000
151+++ src/activity-log-manager.vala 2012-02-21 23:40:22 +0000
152@@ -71,6 +71,10 @@
153 this.show_all();
154 }
155
156+ public void append_page (Gtk.Widget widget, string label) {
157+ var app_label = new Gtk.Label(_(label));
158+ notebook.append_page(widget, app_label);
159+ }
160 public void on_incognito_toggled(bool status) {
161 this.logging_switch.set_active(!status);
162 }
163
164=== modified file 'src/alm-cc.c'
165--- src/alm-cc.c 2012-02-11 16:53:55 +0000
166+++ src/alm-cc.c 2012-02-21 23:40:22 +0000
167@@ -21,6 +21,10 @@
168 #include "config.h"
169
170 extern void* alm_activity_log_manager_new (void);
171+#ifdef HAVE_WHOOPSIE
172+extern void alm_activity_log_manager_append_page (void* alm, GtkWidget* widget, const gchar* label);
173+extern void* whoopsie_daisy_preferences_new (void);
174+#endif
175
176 #define ALM_TYPE_MAIN_WINDOW_PANEL alm_main_window_panel_get_type()
177
178@@ -53,6 +57,10 @@
179 alm_main_window_panel_init (AlmMainWindowPanel *self)
180 {
181 GtkWidget *widget = GTK_WIDGET (alm_activity_log_manager_new ());
182+#ifdef HAVE_WHOOPSIE
183+ GtkWidget *whoopsie = GTK_WIDGET (whoopsie_daisy_preferences_new ());
184+ alm_activity_log_manager_append_page (widget, whoopsie, "Diagnostics");
185+#endif
186 gtk_widget_show_all (widget);
187 gtk_container_add (GTK_CONTAINER (self), widget);
188 }
189
190=== added directory 'src/diagnostics'
191=== added file 'src/diagnostics-widget.c'
192--- src/diagnostics-widget.c 1970-01-01 00:00:00 +0000
193+++ src/diagnostics-widget.c 2012-02-21 23:40:22 +0000
194@@ -0,0 +1,193 @@
195+#include <gtk/gtk.h>
196+#include <gio/gio.h>
197+#include <polkit/polkit.h>
198+
199+#include "diagnostics/whoopsie-generated.h"
200+
201+static WhoopsiePreferences* proxy = NULL;
202+
203+#define POL_PATH "com.ubuntu.whoopsiepreferences.change"
204+#define PRIVACY_URL "http://www.ubuntu.com/aboutus/privacypolicy"
205+
206+#define WHOOPSIE_DAISY_TYPE_PREFERENCES whoopsie_daisy_preferences_get_type()
207+#define WHOOPSIE_DAISY_PREFERENCES(obj) \
208+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
209+ WHOOPSIE_DAISY_TYPE_PREFERENCES, WhoopsieDaisyPreferences))
210+#define WHOOPSIE_DAISY_PREFERENCES_PRIVATE(o) \
211+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), WHOOPSIE_DAISY_TYPE_PREFERENCES, WhoopsieDaisyPreferencesPrivate))
212+
213+GType whoopsie_daisy_preferences_get_type (void) G_GNUC_CONST;
214+
215+typedef struct _WhoopsieDaisyPreferences WhoopsieDaisyPreferences;
216+typedef struct _WhoopsieDaisyPreferencesClass WhoopsieDaisyPreferencesClass;
217+typedef struct _WhoopsieDaisyPreferencesPrivate WhoopsieDaisyPreferencesPrivate;
218+
219+struct _WhoopsieDaisyPreferencesPrivate
220+{
221+ GtkBuilder* builder;
222+ GPermission* permission;
223+};
224+
225+struct _WhoopsieDaisyPreferences
226+{
227+ GtkBox parent;
228+ WhoopsieDaisyPreferencesPrivate* priv;
229+};
230+
231+struct _WhoopsieDaisyPreferencesClass
232+{
233+ GtkBoxClass parent_class;
234+};
235+
236+G_DEFINE_TYPE (WhoopsieDaisyPreferences, whoopsie_daisy_preferences, GTK_TYPE_BOX)
237+
238+static void
239+whoopsie_daisy_preferences_dispose (GObject* object)
240+{
241+ WhoopsieDaisyPreferencesPrivate* priv = WHOOPSIE_DAISY_PREFERENCES (object)->priv;
242+
243+ if (priv->builder) {
244+ g_object_unref (priv->builder);
245+ priv->builder = NULL;
246+ }
247+ if (priv->permission) {
248+ g_object_unref (priv->permission);
249+ priv->permission = NULL;
250+ }
251+}
252+
253+static void
254+whoopsie_daisy_preferences_class_init (WhoopsieDaisyPreferencesClass *klass)
255+{
256+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
257+ g_type_class_add_private (klass, sizeof (WhoopsieDaisyPreferencesPrivate));
258+ object_class->dispose = whoopsie_daisy_preferences_dispose;
259+}
260+
261+static void
262+on_privacy_policy_clicked (GtkWidget* button, gpointer user_data)
263+{
264+ system ("xdg-open " PRIVACY_URL);
265+}
266+
267+static void
268+on_permission_changed (GPermission* permission, GParamSpec* pspec, gpointer data)
269+{
270+ gboolean allowed;
271+ GtkWidget* error_reports_box = NULL;
272+ WhoopsieDaisyPreferencesPrivate* priv = WHOOPSIE_DAISY_PREFERENCES (data)->priv;
273+
274+ error_reports_box = GTK_WIDGET (gtk_builder_get_object (
275+ priv->builder, "error_reports_box"));
276+
277+ allowed = g_permission_get_allowed (permission);
278+ gtk_widget_set_sensitive (error_reports_box, allowed);
279+}
280+
281+static void
282+on_submit_error_reports_checked (GtkToggleButton* button, gpointer user_data)
283+{
284+ GError* error = NULL;
285+
286+ whoopsie_preferences_call_set_report_crashes_sync (proxy,
287+ gtk_toggle_button_get_active (button), NULL, &error);
288+ if (error != NULL) {
289+ g_printerr ("Error setting crash reporting: %s\n", error->message);
290+ g_error_free (error);
291+ }
292+}
293+
294+static void
295+on_properties_changed (WhoopsiePreferences* interface,
296+ GVariant* changed_properties,
297+ const gchar* const* invalidated_properties,
298+ gpointer user_data)
299+{
300+ WhoopsieDaisyPreferencesPrivate* priv = WHOOPSIE_DAISY_PREFERENCES (user_data)->priv;
301+ gboolean report_errors;
302+ GtkWidget* submit_error_reports = NULL;
303+
304+ submit_error_reports = GTK_WIDGET (
305+ gtk_builder_get_object (priv->builder, "submit_error_reports"));
306+ report_errors = whoopsie_preferences_get_report_crashes (interface);
307+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (submit_error_reports), report_errors);
308+}
309+
310+static void
311+whoopsie_daisy_preferences_setup_dbus (WhoopsieDaisyPreferences *self, GError *error)
312+{
313+ WhoopsieDaisyPreferencesPrivate* priv = WHOOPSIE_DAISY_PREFERENCES (self)->priv;
314+ proxy = whoopsie_preferences_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
315+ G_DBUS_PROXY_FLAGS_NONE,
316+ "com.ubuntu.WhoopsiePreferences",
317+ "/com/ubuntu/WhoopsiePreferences",
318+ NULL, &error);
319+ if (!proxy)
320+ return
321+
322+ g_signal_connect (proxy, "g-properties-changed",
323+ G_CALLBACK (on_properties_changed), self);
324+ on_properties_changed (proxy, NULL, NULL, self);
325+}
326+static void
327+whoopsie_daisy_preferences_init (WhoopsieDaisyPreferences *self)
328+{
329+ GError *error = NULL;
330+ GtkWidget* privacy_page = NULL;
331+ GtkWidget* unlock_align = NULL;
332+ GtkWidget* unlock_button = NULL;
333+ GtkWidget* submit_error_reports = NULL;
334+ GtkWidget* privacy_policy = NULL;
335+ WhoopsieDaisyPreferencesPrivate* priv;
336+ priv = self->priv = WHOOPSIE_DAISY_PREFERENCES_PRIVATE (self);
337+
338+ priv->builder = gtk_builder_new ();
339+ gtk_builder_add_from_file(priv->builder, GNOMECC_UI_DIR "/whoopsie.ui", &error);
340+ if (error != NULL) {
341+ g_warning ("Could not load interface file: %s", error->message);
342+ g_error_free (error);
343+ return;
344+ }
345+ submit_error_reports = GTK_WIDGET (
346+ gtk_builder_get_object (priv->builder, "submit_error_reports"));
347+ privacy_page = GTK_WIDGET (
348+ gtk_builder_get_object (priv->builder, "privacy_page_box"));
349+ unlock_align = GTK_WIDGET (
350+ gtk_builder_get_object (priv->builder, "unlock_alignment"));
351+ privacy_policy = GTK_WIDGET (
352+ gtk_builder_get_object (priv->builder, "privacy_policy"));
353+
354+ gtk_widget_reparent (privacy_page, (GtkWidget *) self);
355+ g_object_set (self, "valign", GTK_ALIGN_START, NULL);
356+
357+ priv->permission = polkit_permission_new_sync (POL_PATH, NULL, NULL, &error);
358+ if (!priv->permission) {
359+ g_warning ("Could not acquire permission: %s", error->message);
360+ g_error_free (error);
361+ }
362+
363+ unlock_button = gtk_lock_button_new (priv->permission);
364+ gtk_container_add (GTK_CONTAINER (unlock_align), GTK_WIDGET (unlock_button));
365+ gtk_widget_show (unlock_button);
366+
367+ g_signal_connect (priv->permission, "notify", G_CALLBACK (on_permission_changed), self);
368+ on_permission_changed (priv->permission, NULL, self);
369+
370+ whoopsie_daisy_preferences_setup_dbus (self, error);
371+ if (error) {
372+ g_warning ("Could not set up DBus connection: %s", error->message);
373+ g_error_free (error);
374+ }
375+
376+ g_signal_connect (submit_error_reports, "toggled",
377+ G_CALLBACK (on_submit_error_reports_checked), NULL);
378+ g_signal_connect (privacy_policy, "clicked",
379+ G_CALLBACK (on_privacy_policy_clicked), NULL);
380+}
381+
382+GtkWidget*
383+whoopsie_daisy_preferences_new (void)
384+{
385+ return g_object_new (WHOOPSIE_DAISY_TYPE_PREFERENCES, NULL);
386+}
387+
388
389=== added file 'src/diagnostics/Makefile.am'
390--- src/diagnostics/Makefile.am 1970-01-01 00:00:00 +0000
391+++ src/diagnostics/Makefile.am 2012-02-21 23:40:22 +0000
392@@ -0,0 +1,44 @@
393+if HAVE_CCPANEL
394+ccpaneldir = $(CCPANEL_DIR)
395+bin_PROGRAMS = whoopsie-preferences
396+endif
397+
398+policykitdir = $(datadir)/polkit-1/actions/
399+dbussystemdir = $(sysconfdir)/dbus-1/system.d/
400+dbusservicedir = $(datadir)/dbus-1/system-services/
401+gnomeccuidir = $(datadir)/gnome-control-center/ui/
402+
403+whoopsie_preferences_CFLAGS = \
404+ -Wall \
405+ -g \
406+ $(POLKIT_CFLAGS) $(GIO_UNIX_CFLAGS)
407+
408+whoopsie_preferences_SOURCES = \
409+ whoopsie-generated.c whoopsie-generated.h whoopsie-preferences.c
410+
411+whoopsie_preferences_LDADD = \
412+ $(POLKIT_LIBS) \
413+ $(GIO_UNIX_LIBS)
414+
415+EXTRA_DIST = \
416+ whoopsie-preferences.xml \
417+ com.ubuntu.WhoopsiePreferences.service \
418+ com.ubuntu.WhoopsiePreferences.conf \
419+ com.ubuntu.whoopsiepreferences.policy \
420+ whoopsie.ui
421+
422+gnomeccui_DATA = \
423+ whoopsie.ui
424+policykit_DATA = \
425+ com.ubuntu.whoopsiepreferences.policy
426+dbussystem_DATA = \
427+ com.ubuntu.WhoopsiePreferences.conf
428+dbusservice_DATA = \
429+ com.ubuntu.WhoopsiePreferences.service
430+
431+whoopsie-generated.c: whoopsie-preferences.xml
432+ gdbus-codegen --interface-prefix com.ubuntu. \
433+ --generate-c-code whoopsie-generated \
434+ $<
435+
436+CLEANFILES = whoopsie-generated.[ch]
437
438=== added file 'src/diagnostics/com.ubuntu.WhoopsiePreferences.conf'
439--- src/diagnostics/com.ubuntu.WhoopsiePreferences.conf 1970-01-01 00:00:00 +0000
440+++ src/diagnostics/com.ubuntu.WhoopsiePreferences.conf 2012-02-21 23:40:22 +0000
441@@ -0,0 +1,26 @@
442+<!DOCTYPE busconfig PUBLIC
443+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
444+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
445+<busconfig>
446+
447+ <!-- This configuration file specifies the required security policies
448+ for configuring the crash daemon. -->
449+
450+ <!-- Only root can own the service -->
451+ <policy user="root">
452+ <allow own="com.ubuntu.WhoopsiePreferences"/>
453+ </policy>
454+
455+ <!-- Allow anyone to invoke methods (further constrained by
456+ PolicyKit privileges -->
457+ <policy context="default">
458+ <allow send_destination="com.ubuntu.WhoopsiePreferences"
459+ send_interface="com.ubuntu.WhoopsiePreferences"/>
460+ <allow send_destination="com.ubuntu.WhoopsiePreferences"
461+ send_interface="org.freedesktop.DBus.Introspectable"/>
462+ <allow send_destination="com.ubuntu.WhoopsiePreferences"
463+ send_interface="org.freedesktop.DBus.Properties"/>
464+ </policy>
465+
466+</busconfig>
467+
468
469=== added file 'src/diagnostics/com.ubuntu.WhoopsiePreferences.service'
470--- src/diagnostics/com.ubuntu.WhoopsiePreferences.service 1970-01-01 00:00:00 +0000
471+++ src/diagnostics/com.ubuntu.WhoopsiePreferences.service 2012-02-21 23:40:22 +0000
472@@ -0,0 +1,4 @@
473+[D-BUS Service]
474+Name=com.ubuntu.WhoopsiePreferences
475+Exec=/usr/lib/whoopsie/whoopsie-preferences
476+User=root
477
478=== added file 'src/diagnostics/com.ubuntu.whoopsiepreferences.policy'
479--- src/diagnostics/com.ubuntu.whoopsiepreferences.policy 1970-01-01 00:00:00 +0000
480+++ src/diagnostics/com.ubuntu.whoopsiepreferences.policy 2012-02-21 23:40:22 +0000
481@@ -0,0 +1,18 @@
482+<?xml version="1.0" encoding="UTF-8"?>
483+<!DOCTYPE policyconfig PUBLIC
484+ "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
485+ "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
486+<policyconfig>
487+ <vendor>Ubuntu crash reporting</vendor>
488+ <vendor_url>https://launchpad.net/whoopsie-daisy</vendor_url>
489+ <icon_name>stock_lock</icon_name>
490+ <action id="com.ubuntu.whoopsiepreferences.change">
491+ <description gettext-domain="whoopsie">Privacy settings</description>
492+ <message gettext-domain="whoopsie">To change your privacy settings you need to authenticate.</message>
493+ <defaults>
494+ <allow_any>auth_admin</allow_any>
495+ <allow_inactive>auth_admin</allow_inactive>
496+ <allow_active>auth_admin_keep</allow_active>
497+ </defaults>
498+ </action>
499+</policyconfig>
500
501=== added file 'src/diagnostics/whoopsie-preferences.c'
502--- src/diagnostics/whoopsie-preferences.c 1970-01-01 00:00:00 +0000
503+++ src/diagnostics/whoopsie-preferences.c 2012-02-21 23:40:22 +0000
504@@ -0,0 +1,297 @@
505+/* whoopsie
506+ *
507+ * Copyright © 2011 Canonical Ltd.
508+ * Author: Evan Dandrea <evan.dandrea@canonical.com>
509+ *
510+ * This program is free software: you can redistribute it and/or modify
511+ * it under the terms of the GNU General Public License as published by
512+ * the Free Software Foundation, either version 3 of the License, or
513+ * (at your option) any later version.
514+ *
515+ * This program is distributed in the hope that it will be useful,
516+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
517+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
518+ * GNU General Public License for more details.
519+ *
520+ * You should have received a copy of the GNU General Public License
521+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
522+ */
523+
524+#include <gio/gio.h>
525+#include <stdlib.h>
526+#include <polkit/polkit.h>
527+
528+#include "whoopsie-generated.h"
529+
530+#define CONFIG_PATH "/etc/default/whoopsie"
531+
532+static GMainLoop* loop = NULL;
533+static guint loop_shutdown = 0;
534+static GKeyFile* key_file = NULL;
535+static PolkitAuthority* authority = NULL;
536+
537+/* Eventually, it might make sense to move to gsettings with the dconf
538+ * backend, once it gains PolicyKit support, rather than have a program just
539+ * to expose an interface to a small configuration file over DBus/PolicyKit.
540+ * */
541+
542+/* Once upstart has an interface for disabiling jobs via initctl, we wont need
543+ * a configuration file anymore */
544+
545+gboolean
546+whoopsie_preferences_load_configuration (void)
547+{
548+ char* data;
549+ gsize data_size;
550+ gboolean ret = TRUE;
551+ GError* error = NULL;
552+
553+ if (g_key_file_load_from_file (key_file, CONFIG_PATH,
554+ G_KEY_FILE_KEEP_COMMENTS, NULL)) {
555+ return TRUE;
556+ }
557+
558+ g_key_file_set_boolean (key_file, "General", "report_crashes", TRUE);
559+ data = g_key_file_to_data (key_file, &data_size, &error);
560+ if (error) {
561+ g_print ("Could not process configuration: %s\n", error->message);
562+ ret = FALSE;
563+ goto out;
564+ }
565+ if (!g_file_set_contents (CONFIG_PATH, data, data_size, &error)) {
566+ g_print ("Could not write configuration: %s\n", error->message);
567+ ret = FALSE;
568+ goto out;
569+ }
570+
571+ out:
572+ if (data)
573+ g_free (data);
574+ if (error)
575+ g_error_free (error);
576+ return ret;
577+}
578+
579+static void
580+whoopsie_preferences_dbus_notify (WhoopsiePreferences* interface)
581+{
582+ GError* error = NULL;
583+ gboolean report_crashes = FALSE;
584+
585+ report_crashes = g_key_file_get_boolean (key_file, "General",
586+ "report_crashes", &error);
587+ if (error) {
588+ g_warning ("Could not get crashes: %s", error->message);
589+ g_error_free (error);
590+ }
591+ whoopsie_preferences_set_report_crashes (interface, report_crashes);
592+}
593+
594+static void
595+whoopsie_preferences_file_changed (GFileMonitor *monitor, GFile *file,
596+ GFile *other_file,
597+ GFileMonitorEvent event_type,
598+ gpointer user_data)
599+{
600+ if (event_type == G_FILE_MONITOR_EVENT_CHANGED) {
601+ whoopsie_preferences_load_configuration ();
602+ whoopsie_preferences_dbus_notify (user_data);
603+ }
604+}
605+
606+gboolean
607+whoopsie_preferences_load (WhoopsiePreferences* interface)
608+{
609+ GError* error = NULL;
610+ GFile* fp = NULL;
611+ GFileMonitor* file_monitor = NULL;
612+
613+ fp = g_file_new_for_path (CONFIG_PATH);
614+ file_monitor = g_file_monitor_file (fp, G_FILE_MONITOR_NONE,
615+ NULL, &error);
616+ g_signal_connect (file_monitor, "changed",
617+ G_CALLBACK (whoopsie_preferences_file_changed),
618+ interface);
619+ if (error) {
620+ g_print ("Could not set up file monitor: %s\n", error->message);
621+ g_error_free (error);
622+ }
623+ g_object_unref (fp);
624+
625+ key_file = g_key_file_new ();
626+ whoopsie_preferences_load_configuration ();
627+}
628+
629+gboolean
630+whoopsie_preferences_changed (WhoopsiePreferences* object, GParamSpec* pspec,
631+ gpointer user_data)
632+{
633+ WhoopsiePreferencesIface* iface;
634+ gboolean saved_value, new_value;
635+ GError* error = NULL;
636+ char* data;
637+ gsize data_size;
638+
639+ if (loop_shutdown) {
640+ g_source_remove (loop_shutdown);
641+ loop_shutdown = 0;
642+ }
643+ loop_shutdown = g_timeout_add_seconds (60, (GSourceFunc) g_main_loop_quit,
644+ loop);
645+
646+ iface = WHOOPSIE_PREFERENCES_GET_IFACE (object);
647+ saved_value = g_key_file_get_boolean (key_file, "General", user_data,
648+ &error);
649+ if (error) {
650+ g_print ("Could not process configuration: %s\n", error->message);
651+ return FALSE;
652+ }
653+ new_value = iface->get_report_crashes (object);
654+
655+ if (saved_value != new_value) {
656+ g_key_file_set_boolean (key_file, "General", user_data, new_value);
657+ data = g_key_file_to_data (key_file, &data_size, &error);
658+ if (error) {
659+ g_print ("Could not process configuration: %s\n", error->message);
660+ return FALSE;
661+ }
662+ if (!g_file_set_contents (CONFIG_PATH, data, data_size, &error)) {
663+ g_print ("Could not write configuration: %s\n", error->message);
664+ return FALSE;
665+ }
666+ }
667+}
668+
669+static gboolean
670+whoopsie_preferences_on_set_report_crashes (WhoopsiePreferences* object,
671+ GDBusMethodInvocation* invocation,
672+ gboolean report,
673+ gpointer user_data)
674+{
675+ whoopsie_preferences_set_report_crashes (object, report);
676+ whoopsie_preferences_complete_set_report_crashes (object, invocation);
677+ return TRUE;
678+}
679+
680+static gboolean
681+whoopsie_preferences_authorize_method (GDBusInterfaceSkeleton* interface,
682+ GDBusMethodInvocation* invocation,
683+ gpointer user_data)
684+{
685+ PolkitSubject* subject = NULL;
686+ PolkitAuthorizationResult* result = NULL;
687+ GError* error = NULL;
688+ const char* sender = NULL;
689+ gboolean ret = FALSE;
690+
691+ sender = g_dbus_method_invocation_get_sender (invocation);
692+ subject = polkit_system_bus_name_new (sender);
693+ result = polkit_authority_check_authorization_sync (authority, subject,
694+ "com.ubuntu.whoopsiepreferences.change",
695+ NULL,
696+ POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE,
697+ NULL, &error);
698+ if (result == NULL) {
699+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
700+ G_DBUS_ERROR_AUTH_FAILED, "Could not authorize: %s",
701+ error->message);
702+ g_error_free (error);
703+ goto out;
704+ }
705+ if (!polkit_authorization_result_get_is_authorized (result)) {
706+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
707+ G_DBUS_ERROR_AUTH_FAILED, "Not authorized.");
708+ goto out;
709+ }
710+ ret = TRUE;
711+ out:
712+ if (result != NULL)
713+ g_object_unref (result);
714+ g_object_unref (subject);
715+ return ret;
716+}
717+
718+static void
719+on_bus_acquired (GDBusConnection* connection, const gchar* name,
720+ gpointer user_data)
721+{
722+ WhoopsiePreferences* interface;
723+ GError* error = NULL;
724+
725+ interface = whoopsie_preferences_skeleton_new ();
726+ if (!g_dbus_interface_skeleton_export (
727+ G_DBUS_INTERFACE_SKELETON (interface),
728+ connection,
729+ "/com/ubuntu/WhoopsiePreferences", &error)) {
730+
731+ g_print ("Could not export path: %s\n", error->message);
732+ g_error_free (error);
733+ g_main_loop_quit (loop);
734+ return;
735+ }
736+
737+ authority = polkit_authority_get_sync (NULL, &error);
738+ if (authority == NULL) {
739+ g_print ("Could not get authority: %s\n", error->message);
740+ g_error_free (error);
741+ g_main_loop_quit (loop);
742+ return;
743+ }
744+ loop_shutdown = g_timeout_add_seconds (60, (GSourceFunc) g_main_loop_quit,
745+ loop);
746+
747+ g_signal_connect (interface, "notify::report-crashes",
748+ G_CALLBACK (whoopsie_preferences_changed),
749+ "report_crashes");
750+ g_signal_connect (interface, "handle-set-report-crashes",
751+ G_CALLBACK (whoopsie_preferences_on_set_report_crashes),
752+ NULL);
753+ g_signal_connect (interface, "g-authorize-method", G_CALLBACK
754+ (whoopsie_preferences_authorize_method), authority);
755+
756+ whoopsie_preferences_load (interface);
757+ whoopsie_preferences_dbus_notify (interface);
758+}
759+
760+static void
761+on_name_acquired (GDBusConnection* connection, const gchar* name,
762+ gpointer user_data)
763+{
764+ g_print ("Acquired the name: %s\n", name);
765+}
766+
767+static void
768+on_name_lost (GDBusConnection* connection, const gchar* name,
769+ gpointer user_data)
770+{
771+ g_print ("Lost the name: %s\n", name);
772+}
773+
774+int
775+main (int argc, char** argv)
776+{
777+ guint owner_id;
778+
779+ if (getuid () != 0) {
780+ g_print ("This program must be run as root.\n");
781+ return 1;
782+ }
783+
784+ g_type_init();
785+
786+ owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
787+ "com.ubuntu.WhoopsiePreferences",
788+ G_BUS_NAME_OWNER_FLAGS_NONE,
789+ on_bus_acquired,
790+ on_name_acquired,
791+ on_name_lost,
792+ NULL, NULL);
793+
794+ loop = g_main_loop_new (NULL, FALSE);
795+ g_main_loop_run (loop);
796+ g_bus_unown_name (owner_id);
797+ g_main_loop_unref (loop);
798+ if (key_file)
799+ g_key_file_free (key_file);
800+ return 0;
801+}
802
803=== added file 'src/diagnostics/whoopsie-preferences.xml'
804--- src/diagnostics/whoopsie-preferences.xml 1970-01-01 00:00:00 +0000
805+++ src/diagnostics/whoopsie-preferences.xml 2012-02-21 23:40:22 +0000
806@@ -0,0 +1,8 @@
807+<node>
808+ <interface name="com.ubuntu.WhoopsiePreferences">
809+ <property name="ReportCrashes" type="b" access="read" />
810+ <method name="SetReportCrashes">
811+ <arg direction="in" type="b" name="report" />
812+ </method>
813+ </interface>
814+</node>
815
816=== added file 'src/diagnostics/whoopsie.ui'
817--- src/diagnostics/whoopsie.ui 1970-01-01 00:00:00 +0000
818+++ src/diagnostics/whoopsie.ui 2012-02-21 23:40:22 +0000
819@@ -0,0 +1,165 @@
820+<?xml version="1.0" encoding="UTF-8"?>
821+<interface>
822+ <!-- interface-requires gtk+ 3.0 -->
823+ <object class="GtkWindow" id="window1">
824+ <property name="can_focus">False</property>
825+ <property name="has_resize_grip">False</property>
826+ <child>
827+ <object class="GtkBox" id="privacy_page_box">
828+ <property name="visible">True</property>
829+ <property name="can_focus">False</property>
830+ <property name="border_width">12</property>
831+ <property name="orientation">vertical</property>
832+ <property name="spacing">12</property>
833+ <child>
834+ <object class="GtkBox" id="privacy_box">
835+ <property name="visible">True</property>
836+ <property name="can_focus">False</property>
837+ <property name="orientation">vertical</property>
838+ <property name="spacing">12</property>
839+ <child>
840+ <object class="GtkLabel" id="privacy_heading">
841+ <property name="visible">True</property>
842+ <property name="can_focus">False</property>
843+ <property name="xalign">0</property>
844+ <property name="label" translatable="yes">Ubuntu can collect anonymous information that helps developers improve it. All information collected is covered by our privacy policy.</property>
845+ <property name="wrap">True</property>
846+ </object>
847+ <packing>
848+ <property name="expand">False</property>
849+ <property name="fill">True</property>
850+ <property name="position">0</property>
851+ </packing>
852+ </child>
853+ <child>
854+ <object class="GtkAlignment" id="privacy_policy_alignment">
855+ <property name="visible">True</property>
856+ <property name="can_focus">False</property>
857+ <property name="xalign">0</property>
858+ <property name="xscale">0</property>
859+ <child>
860+ <object class="GtkButton" id="privacy_policy">
861+ <property name="label" translatable="yes">Privacy Policy</property>
862+ <property name="use_action_appearance">False</property>
863+ <property name="visible">True</property>
864+ <property name="can_focus">True</property>
865+ <property name="receives_default">True</property>
866+ <property name="use_action_appearance">False</property>
867+ </object>
868+ </child>
869+ </object>
870+ <packing>
871+ <property name="expand">False</property>
872+ <property name="fill">True</property>
873+ <property name="position">1</property>
874+ </packing>
875+ </child>
876+ </object>
877+ <packing>
878+ <property name="expand">False</property>
879+ <property name="fill">True</property>
880+ <property name="position">0</property>
881+ </packing>
882+ </child>
883+ <child>
884+ <object class="GtkBox" id="reports_box">
885+ <property name="visible">True</property>
886+ <property name="can_focus">False</property>
887+ <property name="orientation">vertical</property>
888+ <property name="spacing">12</property>
889+ <child>
890+ <object class="GtkBox" id="reports_heading_box">
891+ <property name="visible">True</property>
892+ <property name="can_focus">False</property>
893+ <child>
894+ <object class="GtkLabel" id="reports_heading">
895+ <property name="visible">True</property>
896+ <property name="can_focus">False</property>
897+ <property name="label" translatable="yes">People using this computer can:</property>
898+ </object>
899+ <packing>
900+ <property name="expand">False</property>
901+ <property name="fill">True</property>
902+ <property name="position">0</property>
903+ </packing>
904+ </child>
905+ <child>
906+ <object class="GtkAlignment" id="unlock_alignment">
907+ <property name="visible">True</property>
908+ <property name="can_focus">False</property>
909+ <property name="xalign">1</property>
910+ <property name="xscale">0</property>
911+ <child>
912+ <placeholder/>
913+ </child>
914+ </object>
915+ <packing>
916+ <property name="expand">True</property>
917+ <property name="fill">True</property>
918+ <property name="position">1</property>
919+ </packing>
920+ </child>
921+ </object>
922+ <packing>
923+ <property name="expand">False</property>
924+ <property name="fill">True</property>
925+ <property name="position">0</property>
926+ </packing>
927+ </child>
928+ <child>
929+ <object class="GtkBox" id="error_reports_box">
930+ <property name="visible">True</property>
931+ <property name="can_focus">False</property>
932+ <property name="orientation">vertical</property>
933+ <property name="spacing">3</property>
934+ <child>
935+ <object class="GtkCheckButton" id="submit_error_reports">
936+ <property name="label" translatable="yes">Send error reports to Canonical</property>
937+ <property name="use_action_appearance">False</property>
938+ <property name="visible">True</property>
939+ <property name="can_focus">True</property>
940+ <property name="receives_default">False</property>
941+ <property name="use_action_appearance">False</property>
942+ <property name="xalign">0</property>
943+ <property name="draw_indicator">True</property>
944+ </object>
945+ <packing>
946+ <property name="expand">False</property>
947+ <property name="fill">True</property>
948+ <property name="position">0</property>
949+ </packing>
950+ </child>
951+ <child>
952+ <object class="GtkLabel" id="error_reports_description">
953+ <property name="visible">True</property>
954+ <property name="can_focus">False</property>
955+ <property name="xalign">0</property>
956+ <property name="xpad">24</property>
957+ <property name="label" translatable="yes">&lt;small&gt;Error reports include information about what a program was doing when it failed. You always have the choice to send or cancel an error report.&lt;/small&gt;</property>
958+ <property name="use_markup">True</property>
959+ <property name="wrap">True</property>
960+ </object>
961+ <packing>
962+ <property name="expand">False</property>
963+ <property name="fill">True</property>
964+ <property name="position">1</property>
965+ </packing>
966+ </child>
967+ </object>
968+ <packing>
969+ <property name="expand">False</property>
970+ <property name="fill">True</property>
971+ <property name="position">1</property>
972+ </packing>
973+ </child>
974+ </object>
975+ <packing>
976+ <property name="expand">False</property>
977+ <property name="fill">True</property>
978+ <property name="position">1</property>
979+ </packing>
980+ </child>
981+ </object>
982+ </child>
983+ </object>
984+</interface>

Subscribers

People subscribed via source and target branches

to all changes: