Merge lp:~alecu/ubuntuone-client/restrain-out-of-space-dialog into lp:ubuntuone-client

Proposed by Alejandro J. Cura
Status: Rejected
Rejected by: dobey
Proposed branch: lp:~alecu/ubuntuone-client/restrain-out-of-space-dialog
Merge into: lp:ubuntuone-client
Diff against target: 364 lines (+181/-20)
4 files modified
gsd-plugin/gsd-ubuntuone.c (+82/-19)
gsd-plugin/gsd-ubuntuone.h (+3/-0)
gsd-plugin/test-flood.py (+95/-0)
nautilus/test-contacts-picker.c (+1/-1)
To merge this branch: bzr merge lp:~alecu/ubuntuone-client/restrain-out-of-space-dialog
Reviewer Review Type Date Requested Status
dobey (community) Disapprove
Natalia Bidart (community) fieldtest Approve
Roberto Alsina (community) Approve
Review via email: mp+45317@code.launchpad.net

Commit message

show out-of-space dialog with an interval stored in gconf, 0 to disable (fixes LP:#650671)

Description of the change

show out-of-space dialog with an interval stored in gconf, 0 to disable

To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) wrote :

I agree with the idea, and the code looks ok to me. I think this is the best solution we can provide currently. I didn't fieldtest it though.

review: Approve
Revision history for this message
Alejandro J. Cura (alecu) wrote :

How to test this code:

First let's build the branch:
    cd $HOME/canonical/ubuntuone-client
    bzr branch lp:ubuntuone-client review_restrain-out-of-space-dialog
    cd review_restrain-out-of-space-dialog
    bzr merge lp:~alecu/ubuntuone-client/restrain-out-of-space-dialog
    gnome-autogen.sh && make

now let's make sure that syncdaemon is stopped, because the testing script will take its d-bus spot:
    u1sdtool -q

let's start up the testing script:
    cd gsd-plugin
    ./test-flood.py

The dialog will very quickly go thru three different messages. But since it keeps popping up, changing the messages but keeping popping up, that means that the bug was reproduced. Now let's replace the plugin with the one we just compiled. In a different terminal do:

    cd /usr/lib/gnome-settings-daemon-2.0
    sudo mv libubuntuone.so old.libubuntuone.so
    sudo ln -s $HOME/canonical/ubuntuone-client review_restrain-out-of-space-dialog/gsd-plugin/.libs/libubuntuone.so
    killall gnome-settings-daemon # your gnome settings will melt. Don't worry!
    gnome-settings-daemon --debug --no-daemon

Now go back to the first terminal and run the testing script again. It should now only show each message once every hour! The events should still be logged on the gnome-settings-daemon debug output.

Since we don't want you to waste a whole hour, let's open gconf-editor and change this (newly created) gconf key:
* /apps/gnome_settings_daemon/plugins/ubuntuone/out_of_space_warnings_interval

it should say 3600; let's change it to 10 and test the script again. (no need to restart g-s-d) Now the messages should take turns, but each message won't repeat more than every 10 seconds.

Finally, we can change that value to 0, and if you run the script no new messages should pop up at all.

You may now kill that g-s-d and start it again in the background:
 * killall gnome-settings-daemon ; sleep 3; gnome-settings-daemon

Revision history for this message
Alejandro J. Cura (alecu) wrote :

I made a mistake on a line above. Here's how it should look like:

sudo ln -s $HOME/canonical/ubuntuone-client/review_restrain-out-of-space-dialog/gsd-plugin/.libs/libubuntuone.so .

Revision history for this message
dobey (dobey) wrote :

This seems like an overly complex stopgap 'solution' to the issue. I think the proper fix would be simpler code, and it certainly wouldn't require more incorrect usage of gconf.

I would only show the dialog once per session, unless the quota limit has changed since the message was shown. This way, if there are pending uploads, and the user never upgrades, then at most, they should only get shown the dialog once at log-in time; unless their quota was increased and they hit the new limit, or gnome-settings-daemon crashes (which is a larger bug and possibly not ours).

review: Disapprove
Revision history for this message
dobey (dobey) wrote :

Sigh. :(

review: Abstain
793. By Alejandro J. Cura

GTK_DIALOG_NO_SEPARATOR has been deprecated in GTK+ 2.22 and will be removed in GTK+ 3

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

The code makes sense though I'm not an experienced gnome dev. Works like a charm.

review: Approve (fieldtest)
Revision history for this message
dobey (dobey) wrote :

Part of the problem is also that the dialog is destroyed and shown again, even if it's already shown. Instead it needs to be in a static variable, and if already shown, simply presented again.

review: Needs Fixing
794. By Alejandro J. Cura

only nag once per day

Revision history for this message
Roberto Alsina (ralsina) wrote :

rodney: that's for another bug, isn't it?

Revision history for this message
Roberto Alsina (ralsina) wrote :

> Part of the problem is also that the dialog is destroyed and shown again, even
> if it's already shown. Instead it needs to be in a static variable, and if
> already shown, simply presented again.

Now replying the right way ;-)

That's not the issue in this bug. You can add another for that and assign it to alecu or yourself, if you want.

Revision history for this message
Alejandro J. Cura (alecu) wrote :

> Part of the problem is also that the dialog is destroyed and shown again, even
> if it's already shown. Instead it needs to be in a static variable, and if
> already shown, simply presented again.

That's a valid point, but it's not something that's being done on this branch.
Would you mind opening a different bug for it?

Revision history for this message
dobey (dobey) wrote :

I'm not sure it's necessarily another bug entirely. Rather, after a little bit more thought, I think it is part of the fundamental flaw in the code that leads to this issue.

With 3000 files say, that would cauase the dialog to appear, instead of just show()ing the same dialog 3000 times, it is instead destroyed and then created again, over and over. This means it creates a state of constant flicker until the last display of the dialog, and the action happens fast enough that the user can't click "Cancel" in the middle. Destroying and creating the dialog so many times and so fast, consumes a lot of resources. While this isn't necessarily the primary fundamental flaw, I think it exposes another flaw. That is the code does not wait for all the events to coalesce, so that only one dialog is shown, at the end of the spam of messages from DBus.

While not necessarily a total fix, I do think it would be better than this patch, and be more of a step in the right direction for the total fix. And since the real target of this fix is an SRU for Maverick, I do think we need to exercise more caution in deciding what goes in, and try to minimize the change set before rushing it in.

Revision history for this message
dobey (dobey) wrote :

Changing this back to disapprove, and marking as rejected, since I proposed a better solution which is now approved.

review: Disapprove

Unmerged revisions

794. By Alejandro J. Cura

only nag once per day

793. By Alejandro J. Cura

GTK_DIALOG_NO_SEPARATOR has been deprecated in GTK+ 2.22 and will be removed in GTK+ 3

792. By Alejandro J. Cura

include the bug number in the branch

791. By Alejandro J. Cura

show out-of-space dialog with an interval, 0 to disable

790. By Alejandro J. Cura

disable dialog by a checkbox

789. By Alejandro J. Cura

use a gconf-client for the plugin

788. By Alejandro J. Cura

show each message only once per hour

787. By Alejandro J. Cura

was never shown recently

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'gsd-plugin/gsd-ubuntuone.c'
2--- gsd-plugin/gsd-ubuntuone.c 2010-10-04 18:47:52 +0000
3+++ gsd-plugin/gsd-ubuntuone.c 2011-01-06 22:07:46 +0000
4@@ -21,6 +21,7 @@
5
6 #include "config.h"
7
8+#include <glib.h>
9 #include <glib/gi18n-lib.h>
10 #include <gmodule.h>
11 #include <gconf/gconf-client.h>
12@@ -41,6 +42,9 @@
13 #define UPGRADE_SUBSCRIPTION_TEXT _("Upgrade Subscription")
14 #define UPGRADE_SUBSCRIPTION_URI "http://one.ubuntu.com/plans/"
15 #define CHECKED_BOOKMARK_FILE_KEY "/apps/gnome_settings_daemon/plugins/ubuntuone/checked_bookmark_file"
16+#define OUT_OF_SPACE_INTERVAL_KEY "/apps/gnome_settings_daemon/plugins/ubuntuone/out_of_space_warnings_interval"
17+/* default is to show at most once per day */
18+#define DEFAULT_OUT_OF_SPACE_INTERVAL 86400
19
20 static void
21 dialog_closed_callback (GtkDialog *dialog,
22@@ -54,12 +58,45 @@
23 plugin->out_of_space_dialog = NULL;
24 }
25
26+static gboolean
27+was_shown_recently (GsdUbuntuOne *plugin, const gchar *dialog_body, gint interval_between_warnings)
28+{
29+ gboolean result = FALSE;
30+ GTimeVal current_time, *last_time_shown;
31+ last_time_shown = g_hash_table_lookup (plugin->map_last_times_shown,
32+ dialog_body);
33+ if (last_time_shown != NULL) {
34+ g_get_current_time (&current_time);
35+ if (last_time_shown->tv_sec + interval_between_warnings > current_time.tv_sec) {
36+ result = TRUE;
37+ }
38+ }
39+ return result;
40+}
41+
42+static void
43+set_just_shown (GsdUbuntuOne *plugin, const gchar *dialog_body)
44+{
45+ GTimeVal *current_time = g_new0 (GTimeVal, 1);
46+ g_get_current_time (current_time);
47+ g_hash_table_insert (plugin->map_last_times_shown,
48+ g_strdup(dialog_body),
49+ current_time);
50+}
51+
52 static void
53 show_out_of_space_dialog (GsdUbuntuOne *plugin,
54 const gchar *title,
55 const gchar *body,
56- gboolean show_upgrade_link)
57+ gboolean show_upgrade_link,
58+ gint interval_between_warnings)
59 {
60+ if (was_shown_recently (plugin, body, interval_between_warnings)) {
61+ g_debug ("not showing notification: %s "
62+ "(as it was shown recently)", body);
63+ return;
64+ }
65+
66 if (plugin->out_of_space_dialog != NULL) {
67 gtk_widget_destroy (GTK_WIDGET (plugin->out_of_space_dialog));
68 plugin->out_of_space_dialog = NULL;
69@@ -68,7 +105,7 @@
70 g_debug ("notification: %s - %s", title, body);
71
72 plugin->out_of_space_dialog = gtk_message_dialog_new (NULL,
73- GTK_DIALOG_NO_SEPARATOR,
74+ 0,
75 GTK_MESSAGE_WARNING,
76 GTK_BUTTONS_CLOSE,
77 "%s",
78@@ -92,17 +129,35 @@
79 g_signal_connect (G_OBJECT (plugin->out_of_space_dialog), "response",
80 G_CALLBACK (dialog_closed_callback), plugin);
81 gtk_widget_show (plugin->out_of_space_dialog);
82-}
83-
84+ set_just_shown (plugin, body);
85+}
86+
87+static gint
88+get_interval_between_warnings (GsdUbuntuOne *plugin)
89+{
90+ if (gconf_client_get (plugin->conf_client, OUT_OF_SPACE_INTERVAL_KEY, NULL) == NULL) {
91+ gconf_client_set_int (plugin->conf_client, OUT_OF_SPACE_INTERVAL_KEY,
92+ DEFAULT_OUT_OF_SPACE_INTERVAL, NULL);
93+ }
94+
95+ return gconf_client_get_int (plugin->conf_client, OUT_OF_SPACE_INTERVAL_KEY, NULL);
96+}
97
98 static void
99 quota_exceeded_callback (SyncdaemonDaemon *daemon,
100 GHashTable *file_info,
101 gpointer user_data)
102 {
103+ gint interval_between_warnings;
104 gchar * volume_type;
105 GsdUbuntuOne *plugin = GSD_UBUNTUONE (user_data);
106
107+ interval_between_warnings = get_interval_between_warnings (plugin);
108+ if (interval_between_warnings == 0) {
109+ g_debug ("Not showing out of space dialog due to gconf setting.\n");
110+ return;
111+ }
112+
113 volume_type = g_hash_table_lookup (file_info, "type");
114 if (g_strcmp0 (volume_type, "Share") == 0) {
115 gchar * other_visible_name, * path, * message;
116@@ -110,10 +165,12 @@
117 other_visible_name = g_hash_table_lookup (file_info, "other_visible_name");
118 path = g_hash_table_lookup (file_info, "path");
119 message = g_strdup_printf (NO_SPACE_SHARE, path, other_visible_name);
120- show_out_of_space_dialog (plugin, NO_SPACE_TITLE, message, FALSE);
121+ show_out_of_space_dialog (plugin, NO_SPACE_TITLE, message, FALSE,
122+ interval_between_warnings);
123 g_free (message);
124 } else {
125- show_out_of_space_dialog (plugin, NO_SPACE_TITLE, NO_SPACE, TRUE);
126+ show_out_of_space_dialog (plugin, NO_SPACE_TITLE, NO_SPACE, TRUE,
127+ interval_between_warnings);
128 }
129 }
130
131@@ -122,6 +179,7 @@
132 {
133 gchar *contents = NULL;
134 GError *error = NULL;
135+ GsdUbuntuOne *plugin = GSD_UBUNTUONE(user_data);
136
137 g_file_load_contents_finish (G_FILE (source), res, &contents, NULL, NULL, &error);
138 if (error == NULL) {
139@@ -151,10 +209,8 @@
140 NULL,
141 FALSE,
142 0, NULL, NULL, &error)) {
143- GConfClient *conf_client;
144
145- conf_client = gconf_client_get_default ();
146- gconf_client_set_bool (conf_client, CHECKED_BOOKMARK_FILE_KEY, TRUE, NULL);
147+ gconf_client_set_bool (plugin->conf_client, CHECKED_BOOKMARK_FILE_KEY, TRUE, NULL);
148 } else {
149 g_warning ("Could not save bookmarks file: %s\n", error->message);
150 g_error_free (error);
151@@ -171,15 +227,13 @@
152 }
153
154 static void
155-check_bookmark_file (void)
156+check_bookmark_file (GsdUbuntuOne *plugin)
157 {
158 gchar *filename;
159- GConfClient *conf_client;
160 GError *error = NULL;
161
162 /* We only check the bookmark file if we haven't already done so */
163- conf_client = gconf_client_get_default ();
164- if (!gconf_client_get_bool (conf_client, CHECKED_BOOKMARK_FILE_KEY, &error)) {
165+ if (!gconf_client_get_bool (plugin->conf_client, CHECKED_BOOKMARK_FILE_KEY, &error)) {
166 if (error == NULL) {
167 gchar *u1_folder;
168
169@@ -191,7 +245,7 @@
170 GFile *file;
171
172 file = g_file_new_for_path (filename);
173- g_file_load_contents_async (file, NULL, bookmark_file_loaded, NULL);
174+ g_file_load_contents_async (file, NULL, bookmark_file_loaded, plugin);
175
176 g_object_unref (G_OBJECT (file));
177 g_free (filename);
178@@ -204,14 +258,13 @@
179 g_error_free (error);
180 }
181 }
182-
183- g_object_unref (conf_client);
184 }
185
186 static void
187 credentials_found_cb (SyncdaemonAuthentication *auth, SyncdaemonCredentials *credentials, gpointer user_data)
188 {
189- check_bookmark_file ();
190+ GsdUbuntuOne *plugin = GSD_UBUNTUONE (user_data);
191+ check_bookmark_file (plugin);
192 }
193
194 static gboolean
195@@ -225,16 +278,20 @@
196
197 plugin->syncdaemon = syncdaemon_daemon_new ();
198 plugin->out_of_space_dialog = NULL;
199+ plugin->map_last_times_shown = g_hash_table_new_full (g_str_hash,
200+ g_str_equal,
201+ g_free, g_free);
202+ plugin->conf_client = gconf_client_get_default ();
203 g_signal_connect (G_OBJECT (plugin->syncdaemon), "quota_exceeded",
204 G_CALLBACK (quota_exceeded_callback), plugin);
205
206 /* Check for authentication */
207 auth = syncdaemon_daemon_get_authentication (plugin->syncdaemon);
208 if (syncdaemon_authentication_has_credentials (auth))
209- check_bookmark_file ();
210+ check_bookmark_file (plugin);
211 else
212 g_signal_connect (auth, "credentials_found",
213- G_CALLBACK (credentials_found_cb), NULL);
214+ G_CALLBACK (credentials_found_cb), plugin);
215
216 return FALSE;
217 }
218@@ -259,6 +316,12 @@
219 GsdUbuntuOneClass *klass = GSD_UBUNTUONE_GET_CLASS (object);
220 GObjectClass *parent_class = G_OBJECT_CLASS (klass);
221
222+ if (plugin->conf_client != NULL)
223+ g_object_unref (plugin->conf_client);
224+
225+ if (plugin->map_last_times_shown != NULL)
226+ g_hash_table_destroy (plugin->map_last_times_shown);
227+
228 if (plugin->syncdaemon != NULL)
229 g_object_unref (plugin->syncdaemon);
230
231
232=== modified file 'gsd-plugin/gsd-ubuntuone.h'
233--- gsd-plugin/gsd-ubuntuone.h 2010-09-30 13:38:15 +0000
234+++ gsd-plugin/gsd-ubuntuone.h 2011-01-06 22:07:46 +0000
235@@ -25,6 +25,7 @@
236 #include <glib.h>
237 #include <glib-object.h>
238 #include <gmodule.h>
239+#include <gconf/gconf-client.h>
240
241 #include "gnome-settings-daemon/gnome-settings-plugin.h"
242 #include <libsyncdaemon/libsyncdaemon.h>
243@@ -48,6 +49,8 @@
244 /*< private >*/
245 SyncdaemonDaemon *syncdaemon;
246 GtkWidget *out_of_space_dialog;
247+ GHashTable *map_last_times_shown;
248+ GConfClient *conf_client;
249 };
250
251 struct _GsdUbuntuOneClass
252
253=== added file 'gsd-plugin/test-flood.py'
254--- gsd-plugin/test-flood.py 1970-01-01 00:00:00 +0000
255+++ gsd-plugin/test-flood.py 2011-01-06 22:07:46 +0000
256@@ -0,0 +1,95 @@
257+#!/usr/bin/env python
258+# -*- encoding: utf-8 -*-
259+#
260+# Authors: Alejandro J. Cura <alecu@canonical.com>
261+#
262+# Copyright (C) 2010 Canonical Ltd.
263+#
264+# This program is free software; you can redistribute it and/or modify
265+# it under the terms of the GNU General Public License version 3,
266+# as published by the Free Software Foundation.
267+#
268+# This program is distributed in the hope that it will be useful,
269+# but WITHOUT ANY WARRANTY; without even the implied warranty of
270+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
271+# GNU General Public License for more details.
272+#
273+# You should have received a copy of the GNU General Public License
274+# along with this program; if not, write to the Free Software
275+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
276+#
277+
278+
279+import gobject
280+
281+import dbus
282+import dbus.service
283+import dbus.mainloop.glib
284+
285+import sys
286+
287+OBJECT_PATH = "/"
288+OBJECT_NAME = "com.ubuntuone.SyncDaemon"
289+OBJECT_INTERFACE = "com.ubuntuone.SyncDaemon.SyncDaemon"
290+SAMPLE_VOLUME_INFO = {
291+ "volume_id": "sample_volume_id",
292+ "owner_id": "sample_owner_id",
293+ "volume_name": "sample_volume_name",
294+ "type": "UDF",
295+}
296+SAMPLE_SHARE_INFO = {
297+ "volume_id": "sample_volume_id",
298+ "owner_id": "sample_owner_id",
299+ "volume_name": "sample_volume_name",
300+ "type": "Share",
301+ "other_visible_name": "Some Body",
302+ "path": "~/A shared folder",
303+}
304+SAMPLE_SHARE_INFO2 = {
305+ "volume_id": "sample_volume_id",
306+ "owner_id": "sample_owner_id",
307+ "volume_name": "sample_volume_name",
308+ "type": "Share",
309+ "other_visible_name": "Some Other Body",
310+ "path": "~/A shared folder",
311+}
312+
313+class SyncDaemonMocker(dbus.service.Object):
314+ def __init__(self, conn, object_path=OBJECT_PATH):
315+ dbus.service.Object.__init__(self, conn, object_path)
316+
317+ @dbus.service.signal(OBJECT_INTERFACE)
318+ def QuotaExceeded(self, volume_info):
319+ pass
320+
321+ @dbus.service.method(OBJECT_INTERFACE)
322+ def emitQuotaExceeded(self):
323+ self.QuotaExceeded(SAMPLE_VOLUME_INFO)
324+ return 'Signal emitted'
325+
326+ @dbus.service.method(OBJECT_INTERFACE, in_signature='', out_signature='')
327+ def Quit(self):
328+ main_loop.quit()
329+
330+if __name__ == '__main__':
331+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
332+
333+ bus = dbus.SessionBus()
334+ name = dbus.service.BusName(OBJECT_NAME, bus)
335+ object = SyncDaemonMocker(bus)
336+
337+ main_loop = gobject.MainLoop()
338+
339+ if "-d" not in sys.argv:
340+ for n in range(30):
341+ gobject.timeout_add(1000 * n, object.QuotaExceeded,
342+ SAMPLE_VOLUME_INFO)
343+ if n - 3 >= 0:
344+ gobject.timeout_add(1000 * n, object.QuotaExceeded,
345+ SAMPLE_SHARE_INFO)
346+ if n - 6 >= 0:
347+ gobject.timeout_add(1000 * n, object.QuotaExceeded,
348+ SAMPLE_SHARE_INFO2)
349+ gobject.timeout_add(38000, main_loop.quit)
350+
351+ main_loop.run()
352
353=== modified file 'nautilus/test-contacts-picker.c'
354--- nautilus/test-contacts-picker.c 2010-10-07 14:19:53 +0000
355+++ nautilus/test-contacts-picker.c 2011-01-06 22:07:46 +0000
356@@ -77,7 +77,7 @@
357 /* Create the main window */
358 window = gtk_dialog_new_with_buttons ("Test contacts picker",
359 NULL,
360- GTK_DIALOG_NO_SEPARATOR,
361+ 0,
362 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
363 GTK_STOCK_OK, GTK_RESPONSE_OK,
364 NULL);

Subscribers

People subscribed via source and target branches