~didrocks/ubuntuone-client/dont-suffer-zg-crash

« back to all changes in this revision

Viewing changes to bin/ubuntuone-client-applet

  • Committer: Bazaar Package Importer
  • Author(s): Rodney Dawes
  • Date: 2009-06-30 12:00:00 UTC
  • Revision ID: james.westby@ubuntu.com-20090630120000-by806ovmw3193qe8
Tags: upstream-0.90.3
ImportĀ upstreamĀ versionĀ 0.90.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
 
 
3
# ubuntuone-client-applet - Tray icon applet for managing Ubuntu One
 
4
#
 
5
# Author: Rodney Dawes <rodney.dawes@canonical.com>
 
6
#
 
7
# Copyright 2009 Canonical Ltd.
 
8
#
 
9
# This program is free software: you can redistribute it and/or modify it
 
10
# under the terms of the GNU General Public License version 3, as published
 
11
# by the Free Software Foundation.
 
12
#
 
13
# This program is distributed in the hope that it will be useful, but
 
14
# WITHOUT ANY WARRANTY; without even the implied warranties of
 
15
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
16
# PURPOSE.  See the GNU General Public License for more details.
 
17
#
 
18
# You should have received a copy of the GNU General Public License along
 
19
# with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
 
 
21
from __future__ import with_statement
 
22
 
 
23
import pygtk
 
24
pygtk.require('2.0')
 
25
import gobject
 
26
import gtk
 
27
import os
 
28
import subprocess
 
29
import sys
 
30
from gettext import gettext as _
 
31
 
 
32
import dbus.service
 
33
 
 
34
# pylint: disable-msg=F0401
 
35
import pynotify
 
36
 
 
37
from dbus.exceptions import DBusException
 
38
from dbus.mainloop.glib import DBusGMainLoop
 
39
from ubuntuone.oauthdesktop.main import Login
 
40
from gobject.option import OptionGroup, OptionParser, make_option
 
41
from xdg.BaseDirectory import xdg_data_home, xdg_config_home
 
42
from urllib import quote
 
43
 
 
44
from ubuntuone.oauthdesktop.logger import setupLogging
 
45
setupLogging()
 
46
import logging
 
47
logger = logging.getLogger("UbuntuOne.Client.Applet")
 
48
 
 
49
DBusGMainLoop(set_as_default=True)
 
50
 
 
51
# Wait for 30 seconds to get a proper login request
 
52
LOGIN_TIMEOUT = 30
 
53
 
 
54
# Prepend tooltip labels with this label
 
55
TOOLTIP_TITLE = "Ubuntu One: "
 
56
 
 
57
DBUS_IFACE_NAME = "com.ubuntuone.SyncDaemon"
 
58
DBUS_IFACE_SYNC_NAME = "com.ubuntuone.SyncDaemon.SyncDaemon"
 
59
DBUS_IFACE_STATUS_NAME = "com.ubuntuone.SyncDaemon.Status"
 
60
 
 
61
def dbus_error(error):
 
62
      """Got an error from DBus."""
 
63
      logger.debug("DBusError: %s" % error.get_dbus_message())
 
64
 
 
65
def dbus_async(*args):
 
66
      """Simple handler to make dbus do stuff async."""
 
67
      pass
 
68
 
 
69
class AppletMain(object):
 
70
      """Main applet process class."""
 
71
 
 
72
      def __init__(self, signup=False, *args, **kw):
 
73
            """Initializes the child threads and dbus monitor."""
 
74
            from twisted.internet import gtk2reactor
 
75
            gtk2reactor.install()
 
76
            login = Login(dbus.service.BusName("com.ubuntuone.Authentication",
 
77
                                               bus=dbus.SessionBus()))
 
78
 
 
79
            self.__signup = signup
 
80
            self.__icon = None
 
81
            self.__check_id = 0
 
82
 
 
83
            self.__bus = dbus.SessionBus()
 
84
            self.__bus.add_signal_receiver(
 
85
                  handler_function=self.__new_credentials,
 
86
                  signal_name="NewCredentials",
 
87
                  dbus_interface="com.ubuntuone.Authentication")
 
88
            self.__bus.add_signal_receiver(
 
89
                  handler_function=self.__auth_denied,
 
90
                  signal_name="AuthorizationDenied",
 
91
                  dbus_interface="com.ubuntuone.Authentication")
 
92
 
 
93
      def __new_credentials(self, realm=None, consumer_key=None, sender=None):
 
94
            """Signal callback for when we get new credentials."""
 
95
            self.__start_storage_daemon()
 
96
 
 
97
            if not self.__icon:
 
98
                  self.__icon = AppletIcon()
 
99
            if self.__check_id > 0:
 
100
                  gobject.source_remove(self.__check_id)
 
101
            if self.__signup:
 
102
                  self.add_to_autostart()
 
103
 
 
104
      def __auth_denied(self):
 
105
            """Signal callback for when auth was denied by user."""
 
106
            def timeout_exit():
 
107
                  """Do the quit on a timeout"""
 
108
                  from twisted.internet import reactor
 
109
                  reactor.stop()
 
110
                  return False
 
111
 
 
112
            self.remove_from_autostart()
 
113
            if not self.__signup:
 
114
                  self.__check_id = gobject.timeout_add_seconds(LOGIN_TIMEOUT,
 
115
                                                                timeout_exit)
 
116
 
 
117
      def __check_for_token(self):
 
118
            """Method to check for an existing token."""
 
119
            try:
 
120
                  client = self.__bus.get_object("com.ubuntuone.Authentication",
 
121
                                                 "/")
 
122
            except DBusException:
 
123
                  return False
 
124
 
 
125
            iface = dbus.Interface(client, "com.ubuntuone.Authentication")
 
126
            iface.maybe_login("https://ubuntuone.com", "ubuntuone",
 
127
                              self.__signup,
 
128
                              reply_handler=dbus_async,
 
129
                              error_handler=dbus_error)
 
130
            return False
 
131
 
 
132
      def __start_storage_daemon_maybe(self):
 
133
            """Start the storage daemon."""
 
134
            try:
 
135
                  client = self.__bus.get_object(DBUS_IFACE_NAME, "/")
 
136
            except DBusException:
 
137
                  return False
 
138
 
 
139
            iface = dbus.Interface(client, DBUS_IFACE_SYNC_NAME)
 
140
            iface.get_rootdir(reply_handler=dbus_async,
 
141
                              error_handler=dbus_error)
 
142
            return False
 
143
 
 
144
      def __start_storage_daemon(self):
 
145
            """Need to call dbus from a idle callback"""
 
146
            gobject.idle_add(self.__start_storage_daemon_maybe)
 
147
 
 
148
      def add_to_autostart(self):
 
149
            """Add ourself to the autostart config."""
 
150
            autostart_entry = """[Desktop Entry]
 
151
Name=Ubuntu One
 
152
Comment=Control applet for Ubuntu One
 
153
Exec=ubuntuone-client-applet
 
154
Icon=ubuntuone-client
 
155
Terminal=false
 
156
Type=Application
 
157
X-Ubuntu-Gettext-Domain=ubuntuone-client
 
158
X-KDE-autostart-after=panel
 
159
X-GNOME-Autostart-enabled=true
 
160
"""
 
161
            if not os.path.exists(os.path.join(xdg_config_home, "autostart")):
 
162
                  os.makedirs(os.path.join(xdg_config_home, "autostart"))
 
163
 
 
164
            with open(os.path.join(xdg_config_home, "autostart",
 
165
                                   "ubuntuone-client-applet.desktop"),
 
166
                      "w+") as f:
 
167
                  f.write(autostart_entry)
 
168
 
 
169
      def remove_from_autostart(self):
 
170
            """Remove ourself from the autostart config."""
 
171
            path = os.path.join(xdg_config_home, "autostart",
 
172
                                "ubuntuone-client-applet.desktop")
 
173
            try:
 
174
                  os.unlink(path)
 
175
            except OSError:
 
176
                  pass
 
177
 
 
178
      def main(self):
 
179
            """Starts the gtk main loop."""
 
180
            from twisted.internet import reactor
 
181
            gobject.idle_add(self.__check_for_token)
 
182
 
 
183
            reactor.run()
 
184
 
 
185
 
 
186
def do_xdg_open(path_or_url):
 
187
      """Utility method to run xdg-open with path_or_url."""
 
188
      ret = subprocess.call(["xdg-open", path_or_url])
 
189
      if ret != 0:
 
190
            logger.debug("Failed to run 'xdg-open %s'" % path_or_url)
 
191
 
 
192
class AppletIcon(gtk.StatusIcon):
 
193
      """
 
194
      Custom StatusIcon derived from gtk.StatusIcon which supports
 
195
      animated icons and a few other nice things.
 
196
      """
 
197
 
 
198
      def __init__(self, *args, **kw):
 
199
            """Initializes our custom StatusIcon based widget."""
 
200
            super(AppletIcon, self).__init__(*args, **kw)
 
201
 
 
202
            self.__managed_dir = None
 
203
 
 
204
            self.__theme = gtk.icon_theme_get_default()
 
205
            iconpath = os.path.abspath(os.path.join(
 
206
                        os.path.split(os.path.dirname(__file__))[0],
 
207
                        "data"))
 
208
            self.__theme.append_search_path(iconpath)
 
209
 
 
210
            self.__theme.append_search_path(os.path.sep + os.path.join(
 
211
                        "usr", "share", "ubuntuone-client", "icons"))
 
212
            self.__theme.append_search_path(os.path.sep + os.path.join(
 
213
                        "usr", "local", "share", "ubuntuone-client", "icons"))
 
214
 
 
215
            self.set_from_icon_name('ubuntuone-client')
 
216
            self.connect("popup-menu", self.__popup_menu)
 
217
            self.connect("activate", self.__open_folder)
 
218
 
 
219
            self.__busy = False
 
220
            self.__busy_id = 0
 
221
 
 
222
            self.__size = 24
 
223
            self.__pixbuf = None
 
224
 
 
225
            self.__vframes = 0
 
226
            self.__hframes = 0
 
227
            self.__vpos = 0
 
228
            self.__hpos = 0
 
229
 
 
230
            self.__size_changed(self, self.__size)
 
231
 
 
232
            self.__items = {}
 
233
            self.__menu = self.__build_menus()
 
234
 
 
235
            self.__connected = False
 
236
            self.__need_update = False
 
237
 
 
238
            pynotify.init("Ubuntu One")
 
239
 
 
240
            self.__bus = dbus.SessionBus()
 
241
 
 
242
            self.__bus.add_signal_receiver(
 
243
                  handler_function=self.__status_changed,
 
244
                  signal_name="StatusChanged",
 
245
                  dbus_interface=DBUS_IFACE_STATUS_NAME)
 
246
 
 
247
            gobject.idle_add(self.__get_root)
 
248
 
 
249
      def __status_changed(self, status):
 
250
            """The sync daemon status changed."""
 
251
            if self.__managed_dir is None:
 
252
                gobject.idle_add(self.__get_root)
 
253
            if status['name'] == "OFFLINE" or \
 
254
                      status['name'].startswith("INIT") or \
 
255
                      status['name'].startswith("READY"):
 
256
                  self.set_busy(False)
 
257
                  self.set_from_icon_name("ubuntuone-client-offline")
 
258
                  self.set_tooltip(TOOLTIP_TITLE + _("Disconnected"))
 
259
                  self.__connected = False
 
260
            elif status['name'].startswith("IDLE"):
 
261
                  self.set_busy(False)
 
262
                  self.set_from_icon_name("ubuntuone-client")
 
263
                  self.set_tooltip(TOOLTIP_TITLE + _("Idle"))
 
264
                  self.__connected = True
 
265
            elif status['name'] == "BAD_VERSION":
 
266
                  self.set_busy(False)
 
267
                  self.set_from_icon_name("ubuntuone-client-offline")
 
268
                  self.set_tooltip(TOOLTIP_TITLE + _("Update Required"))
 
269
                  self.__connected = False
 
270
                  self.__need_update = True
 
271
                  self.__items["connect"].set_sensitive(False)
 
272
                  n = pynotify.Notification(
 
273
                        "Ubuntu One",
 
274
                        _("A new client version is required to continue " +
 
275
                        "using the service. Please click the Ubuntu One" +
 
276
                        "applet icon to upgrade."),
 
277
                        "ubuntuone-client-offline")
 
278
                  n.set_urgency(pynotify.URGENCY_CRITICAL)
 
279
                  n.show()
 
280
                  logger.debug("Invalid protocol version. Update needed.")
 
281
            elif status['name'] == "AUTH_FAILED":
 
282
                  self.set_busy(False)
 
283
                  self.set_from_icon_name("ubuntuone-client-offline")
 
284
                  self.set_tooltip(TOOLTIP_TITLE + "Authentication failed")
 
285
                  self.__connected = False
 
286
                  try:
 
287
                        client = self.__bus.get_object(
 
288
                              "com.ubuntuone.Authentication",
 
289
                              "/")
 
290
                        iface = dbus.Interface(client,
 
291
                                               "com.ubuntuone.Authentication")
 
292
                        iface.maybe_login("https://ubuntuone.com",
 
293
                                          "ubuntuone",
 
294
                                          True,
 
295
                                          reply_handler=dbus_async,
 
296
                                          error_handler=dbus_error)
 
297
 
 
298
                  except DBusException, e:
 
299
                        raise e
 
300
 
 
301
            else:
 
302
                  self.set_busy()
 
303
                  self.__connected = True
 
304
                  if status['name'].startswith("CONNECTING") or \
 
305
                            status['name'].startswith("AUTHENTICATING") or \
 
306
                            status['name'].startswith("CONNECTED"):
 
307
                        self.set_tooltip(TOOLTIP_TITLE + _("Connecting"))
 
308
                  elif status['name'].startswith("SCANNING") or \
 
309
                            status['name'].startswith("READING"):
 
310
                        self.set_tooltip(TOOLTIP_TITLE + _("Scanning"))
 
311
                  elif status['name'].startswith("WORKING"):
 
312
                        self.set_tooltip(TOOLTIP_TITLE + _("Synchronizing"))
 
313
                  elif status['name'].startswith("UNKNOWN_ERROR"):
 
314
                        pass
 
315
                  else:
 
316
                        self.set_tooltip(TOOLTIP_TITLE + _("Working"))
 
317
 
 
318
            if self.__connected:
 
319
                  self.__items["connect"].hide()
 
320
                  self.__items["disconnect"].show()
 
321
            else:
 
322
                  self.__items["connect"].show()
 
323
                  self.__items["disconnect"].hide()
 
324
 
 
325
      def __get_root(self):
 
326
            """Method to get the rootdir from the sync daemon."""
 
327
            # Get the managed root directory
 
328
            try:
 
329
                  client = self.__bus.get_object(DBUS_IFACE_NAME, "/")
 
330
            except DBusException:
 
331
                  return False
 
332
 
 
333
            iface = dbus.Interface(client, DBUS_IFACE_SYNC_NAME)
 
334
            def got_root(root):
 
335
                  """We got the root dir."""
 
336
                  if self.__managed_dir:
 
337
                        self.__remove_from_places(self.__managed_dir)
 
338
                  self.__managed_dir = root
 
339
                  if os.path.isdir(self.__managed_dir) and \
 
340
                            os.access(self.__managed_dir,
 
341
                                      os.F_OK | os.R_OK):
 
342
                        self.__items["open"].set_sensitive(True)
 
343
                        self.__add_to_places()
 
344
                  else:
 
345
                        self.__items["open"].set_sensitive(False)
 
346
 
 
347
            def got_err(error):
 
348
                  """Handle error from the dbus callback."""
 
349
                  if self.__managed_dir:
 
350
                        self.__remove_from_places(self.__managed_dir)
 
351
                  self.__managed_dir = None
 
352
                  self.__items["open"].set_sensitive(False)
 
353
 
 
354
            iface.get_rootdir(reply_handler=got_root, error_handler=got_err)
 
355
 
 
356
            # Now get the current status
 
357
            try:
 
358
                  client = self.__bus.get_object(DBUS_IFACE_NAME, "/status")
 
359
            except DBusException:
 
360
                  return False
 
361
 
 
362
            iface = dbus.Interface(client, DBUS_IFACE_STATUS_NAME)
 
363
            iface.current_status(reply_handler=self.__status_changed,
 
364
                                 error_handler=dbus_error)
 
365
 
 
366
            return False
 
367
 
 
368
      def __build_menus(self):
 
369
            """Create the pop-up menu items."""
 
370
            menu = gtk.Menu()
 
371
 
 
372
            self.__items["connect"] = gtk.ImageMenuItem(stock_id=gtk.STOCK_CONNECT)
 
373
            menu.append(self.__items["connect"])
 
374
            self.__items["connect"].connect("activate", self.__toggle_state)
 
375
            self.__items["connect"].show()
 
376
 
 
377
            self.__items["disconnect"] = gtk.ImageMenuItem(stock_id=gtk.STOCK_DISCONNECT)
 
378
            menu.append(self.__items["disconnect"])
 
379
            self.__items["disconnect"].connect("activate", self.__toggle_state)
 
380
 
 
381
            sep = gtk.SeparatorMenuItem()
 
382
            menu.append(sep)
 
383
            sep.show()
 
384
 
 
385
            self.__items["bug"] = gtk.MenuItem(label=_("_Report a Problem"))
 
386
            menu.append(self.__items["bug"])
 
387
            self.__items["bug"].connect("activate", self.__open_website,
 
388
                    "https://bugs.launchpad.net/ubuntuone-client/+filebug")
 
389
            self.__items["bug"].show()
 
390
 
 
391
            self.__items["open"] = gtk.MenuItem(label=_("_Open Folder"))
 
392
            menu.append(self.__items["open"])
 
393
            self.__items["open"].connect("activate", self.__open_folder)
 
394
            self.__items["open"].set_sensitive(False)
 
395
            self.__items["open"].show()
 
396
 
 
397
            self.__items["web"] = gtk.MenuItem(label=_("_Go to Web"))
 
398
            menu.append(self.__items["web"])
 
399
            self.__items["web"].connect("activate", self.__open_website)
 
400
            self.__items["web"].show()
 
401
 
 
402
            sep = gtk.SeparatorMenuItem()
 
403
            menu.append(sep)
 
404
            sep.show()
 
405
 
 
406
            self.__items["quit"] = gtk.ImageMenuItem(stock_id=gtk.STOCK_QUIT)
 
407
            menu.append(self.__items["quit"])
 
408
            self.__items["quit"].connect("activate", self.__quit_applet)
 
409
            self.__items["quit"].show()
 
410
 
 
411
            menu.show()
 
412
 
 
413
            return menu
 
414
 
 
415
      def __size_changed(self, icon, size, data=None):
 
416
            """Callback for when the size changes."""
 
417
            if size < 24:
 
418
                  self.__size = 16
 
419
            elif size >= 24 and size < 32:
 
420
                  self.__size = 24
 
421
            elif size >= 32 and size < 48:
 
422
                  self.__size = 32
 
423
            elif size >= 48 and size < 64:
 
424
                  self.__size = 48
 
425
            else:
 
426
                  self.__size = size
 
427
 
 
428
            self.__pixbuf = self.__theme.load_icon(
 
429
                  'ubuntuone-client-working',
 
430
                  self.__size,
 
431
                  gtk.ICON_LOOKUP_GENERIC_FALLBACK)
 
432
 
 
433
            self.__hframes = self.__pixbuf.get_width() / self.__size
 
434
            self.__vframes = self.__pixbuf.get_height() / self.__size
 
435
 
 
436
            return True
 
437
 
 
438
 
 
439
      def __spinner_timeout(self):
 
440
            """Timeout callback that spins the spinner."""
 
441
            # This is wrong
 
442
            if not self.__busy:
 
443
                  return False
 
444
 
 
445
            # Skip the first (resting) frame to avoid flicker
 
446
            if self.__hpos == 0 and self.__vpos == 0:
 
447
                  self.__hpos = 1
 
448
 
 
449
            x = self.__size * self.__hpos
 
450
            y = self.__size * self.__vpos
 
451
            pixbuf = self.__pixbuf.subpixbuf(x, y, self.__size, self.__size)
 
452
            self.set_from_pixbuf(pixbuf)
 
453
 
 
454
            self.__hpos += 1
 
455
            if self.__hpos == self.__hframes:
 
456
                  self.__hpos = 0
 
457
                  self.__vpos += 1
 
458
            if self.__vpos >= self.__vframes:
 
459
                  self.__vpos = 0
 
460
 
 
461
            return True
 
462
 
 
463
      def set_busy(self, busy=True):
 
464
            if self.__busy and busy:
 
465
                  return
 
466
 
 
467
            if self.__busy_id:
 
468
                  gobject.source_remove(self.__busy_id)
 
469
 
 
470
            self.__busy = busy
 
471
            self.__busy_id = gobject.timeout_add(100,
 
472
                                                 self.__spinner_timeout)
 
473
 
 
474
      def __popup_menu(self, icon, button, timestamp, data=None):
 
475
            """Pops up the context menu for the tray icon."""
 
476
            self.__menu.popup(None, None, gtk.status_icon_position_menu,
 
477
                              button, timestamp, icon)
 
478
 
 
479
      def __quit_applet(self, menuitem, data=None):
 
480
            """Quit the daemon and closes the applet."""
 
481
 
 
482
            try:
 
483
                  client = self.__bus.get_object(DBUS_IFACE_NAME, "/")
 
484
                  iface = dbus.Interface(client, DBUS_IFACE_SYNC_NAME)
 
485
                  iface.quit(reply_handler=dbus_async,
 
486
                             error_handler=dbus_error)
 
487
            except DBusException:
 
488
                  pass
 
489
 
 
490
            from twisted.internet import reactor
 
491
            reactor.stop()
 
492
 
 
493
      def __toggle_state(self, menuitem, data=None):
 
494
            """Connects or disconnects the storage sync process."""
 
495
            try:
 
496
                  client = self.__bus.get_object(DBUS_IFACE_NAME, "/")
 
497
            except DBusException:
 
498
                  return
 
499
 
 
500
            iface = dbus.Interface(client, DBUS_IFACE_SYNC_NAME)
 
501
            if self.__connected:
 
502
                  iface.disconnect(reply_handler=dbus_async,
 
503
                                   error_handler=dbus_error)
 
504
            else:
 
505
                  iface.connect(reply_handler=dbus_async,
 
506
                                error_handler=dbus_error)
 
507
 
 
508
      def __open_folder(self, data=None):
 
509
            """Opens the storage folder in the file manager."""
 
510
            if self.__need_update:
 
511
                  do_xdg_open("apt:ubuntuone-storage-protocol?refresh=yes")
 
512
                  return
 
513
 
 
514
            if not self.__managed_dir or not os.path.isdir(self.__managed_dir):
 
515
                  return
 
516
 
 
517
            folder = "file://%s" % quote(self.__managed_dir)
 
518
            do_xdg_open(folder)
 
519
 
 
520
      def __open_website(self, data=None, url=None):
 
521
            """Opens the ubuntuone.com web site."""
 
522
            if url:
 
523
                  do_xdg_open(url)
 
524
            else:
 
525
                  do_xdg_open("https://ubuntuone.com/")
 
526
 
 
527
      def __add_to_places(self):
 
528
            """Add the managed directory to the .gtk-bookmarks file."""
 
529
            path = os.path.join(os.path.expanduser("~"), ".gtk-bookmarks")
 
530
            with open(path, "a+") as f:
 
531
                  bookmarks_entry = "file://%s %s\n" % (
 
532
                        quote(self.__managed_dir),
 
533
                        os.path.basename(self.__managed_dir))
 
534
                  in_file = False
 
535
                  for line in f:
 
536
                        if line == bookmarks_entry:
 
537
                              in_file = True
 
538
                  if not in_file:
 
539
                        f.write(bookmarks_entry)
 
540
 
 
541
      def __remove_from_places(self, dir):
 
542
            """Remove the old path from the .gtk-bookmarks file."""
 
543
            path = os.path.join(os.path.expanduser("~"), ".gtk-bookmarks")
 
544
            with open(path, "a+") as f:
 
545
                  entry = "file://%s %s\n" % (quote(dir), os.path.basename(dir))
 
546
                  lines = []
 
547
                  for line in f:
 
548
                        if line != entry:
 
549
                              lines.append(line)
 
550
                  f.truncate(0)
 
551
                  f.seek(0)
 
552
                  output = "".join(lines)
 
553
                  f.write(output)
 
554
 
 
555
 
 
556
if __name__ == "__main__":
 
557
      parser = OptionParser("",
 
558
                            description="Ubuntu One status applet",
 
559
                            option_list = [
 
560
                  make_option("--signup", "-s",
 
561
                              action="store_true",
 
562
                              dest="signup",
 
563
                              help=_("Log in or Sign Up for Ubuntu One")),
 
564
                  ])
 
565
      options, args = parser.parse_args()
 
566
 
 
567
      # Register DBus service for making sure we run only one instance
 
568
      bus = dbus.SessionBus()
 
569
      if bus.request_name("com.ubuntuone.ClientApplet", dbus.bus.NAME_FLAG_DO_NOT_QUEUE) == dbus.bus.REQUEST_NAME_REPLY_EXISTS:
 
570
            print _("Ubuntu One client applet already running, quitting")
 
571
            sys.exit(-1)
 
572
 
 
573
      icon = AppletMain(signup=options.signup)
 
574
      icon.main()