Stop hildonizing widgets that don't exist, now and in the future
[gc-dialer] / src / dc_glade.py
index 3b5f004..33ad67a 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/python2.5
 
 """
 #!/usr/bin/python2.5
 
 """
-DialCentral - Front end for Google's Grand Central service.
+DialCentral - Front end for Google's GoogleVoice service.
 Copyright (C) 2008  Mark Bergman bergman AT merctech DOT com
 
 This library is free software; you can redistribute it and/or
 Copyright (C) 2008  Mark Bergman bergman AT merctech DOT com
 
 This library is free software; you can redistribute it and/or
@@ -17,14 +17,6 @@ Lesser General Public License for more details.
 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-@bug Need to add unit tests
-@todo Look into an actor system
-@bug Session timeouts are bad, possible solutions:
-       @li For every X minutes, if logged in, attempt login
-       @li Restructure so code handling login/dial/sms is beneath everything else and login attempts are made if those fail
-@todo Can't text from dialpad (so can't do any arbitrary number texts)
-@todo Add logging support to make debugging issues for people a lot easier
 """
 
 
 """
 
 
@@ -37,24 +29,23 @@ import threading
 import base64
 import ConfigParser
 import itertools
 import base64
 import ConfigParser
 import itertools
-import warnings
+import logging
 
 import gtk
 import gtk.glade
 
 
 import gtk
 import gtk.glade
 
-try:
-       import hildon
-except ImportError:
-       hildon = None
-
 import constants
 import constants
+import hildonize
 import gtk_toolbox
 
 
 import gtk_toolbox
 
 
+_moduleLogger = logging.getLogger("dc_glade")
+
+
 def getmtime_nothrow(path):
        try:
                return os.path.getmtime(path)
 def getmtime_nothrow(path):
        try:
                return os.path.getmtime(path)
-       except StandardError:
+       except Exception:
                return 0
 
 
                return 0
 
 
@@ -70,9 +61,9 @@ def display_error_message(msg):
 class Dialcentral(object):
 
        _glade_files = [
 class Dialcentral(object):
 
        _glade_files = [
-               '/usr/lib/dialcentral/dialcentral.glade',
                os.path.join(os.path.dirname(__file__), "dialcentral.glade"),
                os.path.join(os.path.dirname(__file__), "../lib/dialcentral.glade"),
                os.path.join(os.path.dirname(__file__), "dialcentral.glade"),
                os.path.join(os.path.dirname(__file__), "../lib/dialcentral.glade"),
+               '/usr/lib/dialcentral/dialcentral.glade',
        ]
 
        KEYPAD_TAB = 0
        ]
 
        KEYPAD_TAB = 0
@@ -82,12 +73,8 @@ class Dialcentral(object):
        ACCOUNT_TAB = 4
 
        NULL_BACKEND = 0
        ACCOUNT_TAB = 4
 
        NULL_BACKEND = 0
-       GC_BACKEND = 1
        GV_BACKEND = 2
        GV_BACKEND = 2
-       BACKENDS = (NULL_BACKEND, GC_BACKEND, GV_BACKEND)
-
-       _data_path = os.path.join(os.path.expanduser("~"), ".dialcentral")
-       _user_settings = "%s/settings.ini" % _data_path
+       BACKENDS = (NULL_BACKEND, GV_BACKEND)
 
        def __init__(self):
                self._initDone = False
 
        def __init__(self):
                self._initDone = False
@@ -95,16 +82,18 @@ class Dialcentral(object):
                self._osso = None
                self._clipboard = gtk.clipboard_get()
 
                self._osso = None
                self._clipboard = gtk.clipboard_get()
 
-               self._deviceIsOnline = True
                self._credentials = ("", "")
                self._selectedBackendId = self.NULL_BACKEND
                self._credentials = ("", "")
                self._selectedBackendId = self.NULL_BACKEND
-               self._defaultBackendId = self.GC_BACKEND
+               self._defaultBackendId = self.GV_BACKEND
                self._phoneBackends = None
                self._dialpads = None
                self._accountViews = None
                self._messagesViews = None
                self._recentViews = None
                self._contactsViews = None
                self._phoneBackends = None
                self._dialpads = None
                self._accountViews = None
                self._messagesViews = None
                self._recentViews = None
                self._contactsViews = None
+               self._alarmHandler = None
+               self._ledHandler = None
+               self._originalCurrentLabels = []
 
                for path in self._glade_files:
                        if os.path.isfile(path):
 
                for path in self._glade_files:
                        if os.path.isfile(path):
@@ -120,47 +109,69 @@ class Dialcentral(object):
                self._errorDisplay = gtk_toolbox.ErrorDisplay(self._widgetTree)
                self._credentialsDialog = gtk_toolbox.LoginWindow(self._widgetTree)
 
                self._errorDisplay = gtk_toolbox.ErrorDisplay(self._widgetTree)
                self._credentialsDialog = gtk_toolbox.LoginWindow(self._widgetTree)
 
-               self._app = None
                self._isFullScreen = False
                self._isFullScreen = False
-               if hildon is not None:
-                       self._app = hildon.Program()
-                       oldWindow = self._window
-                       self._window = hildon.Window()
-                       oldWindow.get_child().reparent(self._window)
-                       self._app.add_window(self._window)
-                       self._widgetTree.get_widget("usernameentry").set_property('hildon-input-mode', 7)
-                       self._widgetTree.get_widget("passwordentry").set_property('hildon-input-mode', 7|(1 << 29))
-                       self._widgetTree.get_widget("callbackcombo").get_child().set_property('hildon-input-mode', (1 << 4))
-                       hildon.hildon_helper_set_thumb_scrollbar(self._widgetTree.get_widget('recent_scrolledwindow'), True)
-                       hildon.hildon_helper_set_thumb_scrollbar(self._widgetTree.get_widget('message_scrolledwindow'), True)
-                       hildon.hildon_helper_set_thumb_scrollbar(self._widgetTree.get_widget('contacts_scrolledwindow'), True)
-
-                       gtkMenu = self._widgetTree.get_widget("dialpad_menubar")
-                       menu = gtk.Menu()
-                       for child in gtkMenu.get_children():
-                               child.reparent(menu)
-                       self._window.set_menu(menu)
-                       gtkMenu.destroy()
-
-                       self._window.connect("key-press-event", self._on_key_press)
-                       self._window.connect("window-state-event", self._on_window_state_change)
-               else:
-                       pass # warnings.warn("No Hildon", UserWarning, 2)
+               self._app = hildonize.get_app_class()()
+               self._window = hildonize.hildonize_window(self._app, self._window)
+               hildonize.hildonize_text_entry(self._widgetTree.get_widget("usernameentry"))
+               hildonize.hildonize_password_entry(self._widgetTree.get_widget("passwordentry"))
+
+               for scrollingWidgetName in (
+                       'recent_scrolledwindow',
+                       'message_scrolledwindow',
+                       'contacts_scrolledwindow',
+                       "smsMessages_scrolledwindow",
+               ):
+                       scrollingWidget = self._widgetTree.get_widget(scrollingWidgetName)
+                       assert scrollingWidget is not None, scrollingWidgetName
+                       hildonize.hildonize_scrollwindow(scrollingWidget)
+               for scrollingWidgetName in (
+                       "smsMessage_scrolledEntry",
+               ):
+                       scrollingWidget = self._widgetTree.get_widget(scrollingWidgetName)
+                       assert scrollingWidget is not None, scrollingWidgetName
+                       hildonize.hildonize_scrollwindow_with_viewport(scrollingWidget)
+
+               for buttonName in (
+                       "back",
+                       "addressbookSelectButton",
+                       "sendSmsButton",
+                       "dialButton",
+                       "selectButton",
+                       "cancelSmsButton",
+                       "callbackSelectButton",
+                       "minutesEntryButton",
+                       "clearcookies",
+                       "phoneTypeSelection",
+               ):
+                       button = self._widgetTree.get_widget(buttonName)
+                       assert button is not None, buttonName
+                       hildonize.set_button_thumb_selectable(button)
 
 
-               if hildon is not None:
-                       self._window.set_title("Keypad")
-               else:
-                       self._window.set_title("%s - Keypad" % constants.__pretty_app_name__)
+               replacementButtons = [gtk.Button("Test")]
+               menu = hildonize.hildonize_menu(
+                       self._window,
+                       self._widgetTree.get_widget("dialpad_menubar"),
+                       replacementButtons
+               )
+
+               self._window.connect("key-press-event", self._on_key_press)
+               self._window.connect("window-state-event", self._on_window_state_change)
+               if not hildonize.IS_HILDON_SUPPORTED:
+                       _moduleLogger.warning("No hildonization support")
 
 
-               callbackMapping = {
-                       "on_dialpad_quit": self._on_close,
-               }
-               self._widgetTree.signal_autoconnect(callbackMapping)
+               hildonize.set_application_title(self._window, "%s" % constants.__pretty_app_name__)
 
                self._window.connect("destroy", self._on_close)
                self._window.set_default_size(800, 300)
                self._window.show_all()
 
 
                self._window.connect("destroy", self._on_close)
                self._window.set_default_size(800, 300)
                self._window.show_all()
 
+               self._loginSink = gtk_toolbox.threaded_stage(
+                       gtk_toolbox.comap(
+                               self._attempt_login,
+                               gtk_toolbox.null_sink(),
+                       )
+               )
+
                backgroundSetup = threading.Thread(target=self._idle_setup)
                backgroundSetup.setDaemon(True)
                backgroundSetup.start()
                backgroundSetup = threading.Thread(target=self._idle_setup)
                backgroundSetup.setDaemon(True)
                backgroundSetup.start()
@@ -169,8 +180,8 @@ class Dialcentral(object):
                """
                If something can be done after the UI loads, push it here so it's not blocking the UI
                """
                """
                If something can be done after the UI loads, push it here so it's not blocking the UI
                """
+               # Barebones UI handlers
                try:
                try:
-                       # Barebones UI handlers
                        import null_backend
                        import null_views
 
                        import null_backend
                        import null_views
 
@@ -187,11 +198,15 @@ class Dialcentral(object):
                                self._recentViews[self._selectedBackendId].enable()
                                self._messagesViews[self._selectedBackendId].enable()
                                self._contactsViews[self._selectedBackendId].enable()
                                self._recentViews[self._selectedBackendId].enable()
                                self._messagesViews[self._selectedBackendId].enable()
                                self._contactsViews[self._selectedBackendId].enable()
+               except Exception, e:
+                       with gtk_toolbox.gtk_lock():
+                               self._errorDisplay.push_exception()
 
 
-                       # Setup maemo specifics
+               # Setup maemo specifics
+               try:
                        try:
                                import osso
                        try:
                                import osso
-                       except ImportError:
+                       except (ImportError, OSError):
                                osso = None
                        self._osso = None
                        if osso is not None:
                                osso = None
                        self._osso = None
                        if osso is not None:
@@ -199,12 +214,31 @@ class Dialcentral(object):
                                device = osso.DeviceState(self._osso)
                                device.set_device_state_callback(self._on_device_state_change, 0)
                        else:
                                device = osso.DeviceState(self._osso)
                                device.set_device_state_callback(self._on_device_state_change, 0)
                        else:
-                               pass # warnings.warn("No OSSO", UserWarning, 2)
+                               _moduleLogger.warning("No device state support")
+
+                       try:
+                               import alarm_handler
+                               self._alarmHandler = alarm_handler.AlarmHandler()
+                       except (ImportError, OSError):
+                               alarm_handler = None
+                       except Exception:
+                               with gtk_toolbox.gtk_lock():
+                                       self._errorDisplay.push_exception()
+                               alarm_handler = None
+                               _moduleLogger.warning("No notification support")
+                       if hildonize.IS_HILDON_SUPPORTED:
+                               try:
+                                       import led_handler
+                                       self._ledHandler = led_handler.LedHandler()
+                               except Exception, e:
+                                       _moduleLogger.exception('LED Handling failed: "%s"' % str(e))
+                                       self._ledHandler = None
+                       else:
+                               self._ledHandler = None
 
 
-                       # Setup maemo specifics
                        try:
                                import conic
                        try:
                                import conic
-                       except ImportError:
+                       except (ImportError, OSError):
                                conic = None
                        self._connection = None
                        if conic is not None:
                                conic = None
                        self._connection = None
                        if conic is not None:
@@ -212,156 +246,150 @@ class Dialcentral(object):
                                self._connection.connect("connection-event", self._on_connection_change, constants.__app_magic__)
                                self._connection.request_connection(conic.CONNECT_FLAG_NONE)
                        else:
                                self._connection.connect("connection-event", self._on_connection_change, constants.__app_magic__)
                                self._connection.request_connection(conic.CONNECT_FLAG_NONE)
                        else:
-                               pass # warnings.warn("No Internet Connectivity API ", UserWarning)
+                               _moduleLogger.warning("No connection support")
+               except Exception, e:
+                       with gtk_toolbox.gtk_lock():
+                               self._errorDisplay.push_exception()
 
 
-                       # Setup costly backends
+               # Setup costly backends
+               try:
                        import gv_backend
                        import gv_backend
-                       import gc_backend
                        import file_backend
                        import file_backend
-                       import evo_backend
-                       import gc_views
+                       import gv_views
 
                        try:
 
                        try:
-                               os.makedirs(self._data_path)
+                               os.makedirs(constants._data_path_)
                        except OSError, e:
                                if e.errno != 17:
                                        raise
                        except OSError, e:
                                if e.errno != 17:
                                        raise
-                       gcCookiePath = os.path.join(self._data_path, "gc_cookies.txt")
-                       gvCookiePath = os.path.join(self._data_path, "gv_cookies.txt")
-                       self._defaultBackendId = self._guess_preferred_backend((
-                               (self.GC_BACKEND, gcCookiePath),
-                               (self.GV_BACKEND, gvCookiePath),
-                       ))
+                       gvCookiePath = os.path.join(constants._data_path_, "gv_cookies.txt")
 
                        self._phoneBackends.update({
 
                        self._phoneBackends.update({
-                               self.GC_BACKEND: gc_backend.GCDialer(gcCookiePath),
                                self.GV_BACKEND: gv_backend.GVDialer(gvCookiePath),
                        })
                        with gtk_toolbox.gtk_lock():
                                self.GV_BACKEND: gv_backend.GVDialer(gvCookiePath),
                        })
                        with gtk_toolbox.gtk_lock():
-                               unifiedDialpad = gc_views.Dialpad(self._widgetTree, self._errorDisplay)
-                               unifiedDialpad.set_number("")
+                               unifiedDialpad = gv_views.Dialpad(self._widgetTree, self._errorDisplay)
                                self._dialpads.update({
                                self._dialpads.update({
-                                       self.GC_BACKEND: unifiedDialpad,
                                        self.GV_BACKEND: unifiedDialpad,
                                })
                                self._accountViews.update({
                                        self.GV_BACKEND: unifiedDialpad,
                                })
                                self._accountViews.update({
-                                       self.GC_BACKEND: gc_views.AccountInfo(
-                                               self._widgetTree, self._phoneBackends[self.GC_BACKEND], self._errorDisplay
-                                       ),
-                                       self.GV_BACKEND: gc_views.AccountInfo(
-                                               self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay
+                                       self.GV_BACKEND: gv_views.AccountInfo(
+                                               self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._alarmHandler, self._errorDisplay
                                        ),
                                })
                                        ),
                                })
+                               self._accountViews[self.GV_BACKEND].save_everything = self._save_settings
                                self._recentViews.update({
                                self._recentViews.update({
-                                       self.GC_BACKEND: gc_views.RecentCallsView(
-                                               self._widgetTree, self._phoneBackends[self.GC_BACKEND], self._errorDisplay
-                                       ),
-                                       self.GV_BACKEND: gc_views.RecentCallsView(
+                                       self.GV_BACKEND: gv_views.RecentCallsView(
                                                self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay
                                        ),
                                })
                                self._messagesViews.update({
                                                self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay
                                        ),
                                })
                                self._messagesViews.update({
-                                       self.GC_BACKEND: null_views.MessagesView(self._widgetTree),
-                                       self.GV_BACKEND: gc_views.MessagesView(
+                                       self.GV_BACKEND: gv_views.MessagesView(
                                                self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay
                                        ),
                                })
                                self._contactsViews.update({
                                                self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay
                                        ),
                                })
                                self._contactsViews.update({
-                                       self.GC_BACKEND: gc_views.ContactsView(
-                                               self._widgetTree, self._phoneBackends[self.GC_BACKEND], self._errorDisplay
-                                       ),
-                                       self.GV_BACKEND: gc_views.ContactsView(
+                                       self.GV_BACKEND: gv_views.ContactsView(
                                                self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay
                                        ),
                                })
 
                                                self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay
                                        ),
                                })
 
-                       evoBackend = evo_backend.EvolutionAddressBook()
-                       fsContactsPath = os.path.join(self._data_path, "contacts")
+                       fsContactsPath = os.path.join(constants._data_path_, "contacts")
                        fileBackend = file_backend.FilesystemAddressBookFactory(fsContactsPath)
                        fileBackend = file_backend.FilesystemAddressBookFactory(fsContactsPath)
-                       for backendId in (self.GV_BACKEND, self.GC_BACKEND):
-                               self._dialpads[backendId].number_selected = self._select_action
-                               self._recentViews[backendId].number_selected = self._select_action
-                               self._messagesViews[backendId].number_selected = self._select_action
-                               self._contactsViews[backendId].number_selected = self._select_action
-
-                               addressBooks = [
-                                       self._phoneBackends[backendId],
-                                       evoBackend,
-                                       fileBackend,
-                               ]
-                               mergedBook = gc_views.MergedAddressBook(addressBooks, gc_views.MergedAddressBook.advanced_lastname_sorter)
-                               self._contactsViews[backendId].append(mergedBook)
-                               self._contactsViews[backendId].extend(addressBooks)
-                               self._contactsViews[backendId].open_addressbook(*self._contactsViews[backendId].get_addressbooks().next()[0][0:2])
+
+                       self._dialpads[self.GV_BACKEND].number_selected = self._select_action
+                       self._recentViews[self.GV_BACKEND].number_selected = self._select_action
+                       self._messagesViews[self.GV_BACKEND].number_selected = self._select_action
+                       self._contactsViews[self.GV_BACKEND].number_selected = self._select_action
+
+                       addressBooks = [
+                               self._phoneBackends[self.GV_BACKEND],
+                               fileBackend,
+                       ]
+                       mergedBook = gv_views.MergedAddressBook(addressBooks, gv_views.MergedAddressBook.advanced_lastname_sorter)
+                       self._contactsViews[self.GV_BACKEND].append(mergedBook)
+                       self._contactsViews[self.GV_BACKEND].extend(addressBooks)
+                       self._contactsViews[self.GV_BACKEND].open_addressbook(*self._contactsViews[self.GV_BACKEND].get_addressbooks().next()[0][0:2])
 
                        callbackMapping = {
                                "on_paste": self._on_paste,
 
                        callbackMapping = {
                                "on_paste": self._on_paste,
-                               "on_refresh": self._on_refresh,
+                               "on_refresh": self._on_menu_refresh,
                                "on_clearcookies_clicked": self._on_clearcookies_clicked,
                                "on_clearcookies_clicked": self._on_clearcookies_clicked,
-                               "on_notebook_switch_page": self._on_notebook_switch_page,
                                "on_about_activate": self._on_about_activate,
                        }
                                "on_about_activate": self._on_about_activate,
                        }
-                       self._widgetTree.signal_autoconnect(callbackMapping)
+                       if hildonize.GTK_MENU_USED:
+                               self._widgetTree.signal_autoconnect(callbackMapping)
+                       self._notebook.connect("switch-page", self._on_notebook_switch_page)
+                       self._widgetTree.get_widget("clearcookies").connect("clicked", self._on_clearcookies_clicked)
+
+                       with gtk_toolbox.gtk_lock():
+                               self._originalCurrentLabels = [
+                                       self._notebook.get_tab_label(self._notebook.get_nth_page(pageIndex)).get_text()
+                                       for pageIndex in xrange(self._notebook.get_n_pages())
+                               ]
+                               self._notebookTapHandler = gtk_toolbox.TapOrHold(self._notebook)
+                               self._notebookTapHandler.enable()
+                       self._notebookTapHandler.on_tap = self._reset_tab_refresh
+                       self._notebookTapHandler.on_hold = self._on_tab_refresh
+                       self._notebookTapHandler.on_holding = self._set_tab_refresh
+                       self._notebookTapHandler.on_cancel = self._reset_tab_refresh
 
                        self._initDone = True
 
                        config = ConfigParser.SafeConfigParser()
 
                        self._initDone = True
 
                        config = ConfigParser.SafeConfigParser()
-                       config.read(self._user_settings)
+                       config.read(constants._user_settings_)
                        with gtk_toolbox.gtk_lock():
                                self.load_settings(config)
                        with gtk_toolbox.gtk_lock():
                                self.load_settings(config)
+               except Exception, e:
+                       with gtk_toolbox.gtk_lock():
+                               self._errorDisplay.push_exception()
+               finally:
+                       self._spawn_attempt_login(2)
 
 
-                       gtk_toolbox.asynchronous_gtk_message(self._spawn_attempt_login)(2)
-               except StandardError, e:
-                       warnings.warn(e.message, UserWarning, 2)
-               except BaseException, e:
-                       try:
-                               warnings.warn(e.message, UserWarning, 2)
-                       finally:
-                               raise
+       def _spawn_attempt_login(self, *args):
+               self._loginSink.send(args)
 
 
-       def attempt_login(self, numOfAttempts = 10, force = False):
+       def _attempt_login(self, numOfAttempts = 10, force = False):
                """
                """
-               @todo Handle user notification better like attempting to login and failed login
-
                @note This must be run outside of the UI lock
                """
                try:
                        assert 0 <= numOfAttempts, "That was pointless having 0 or less login attempts"
                        assert self._initDone, "Attempting login before app is fully loaded"
                @note This must be run outside of the UI lock
                """
                try:
                        assert 0 <= numOfAttempts, "That was pointless having 0 or less login attempts"
                        assert self._initDone, "Attempting login before app is fully loaded"
-                       if not self._deviceIsOnline:
-                               raise RuntimeError("Unable to login, device is not online")
 
                        serviceId = self.NULL_BACKEND
                        loggedIn = False
                        if not force:
 
                        serviceId = self.NULL_BACKEND
                        loggedIn = False
                        if not force:
+                               with gtk_toolbox.gtk_lock():
+                                       banner = hildonize.show_busy_banner_start(self._window, "Logging In...")
                                try:
                                        self.refresh_session()
                                        serviceId = self._defaultBackendId
                                        loggedIn = True
                                try:
                                        self.refresh_session()
                                        serviceId = self._defaultBackendId
                                        loggedIn = True
-                               except StandardError, e:
-                                       warnings.warn('Session refresh failed with the following message "%s"' % e.message, UserWarning, 2)
+                               except Exception, e:
+                                       _moduleLogger.exception('Session refresh failed with the following message "%s"' % str(e))
+                               finally:
+                                       with gtk_toolbox.gtk_lock():
+                                               hildonize.show_busy_banner_end(banner)
 
                        if not loggedIn:
                                loggedIn, serviceId = self._login_by_user(numOfAttempts)
 
                        with gtk_toolbox.gtk_lock():
                                self._change_loggedin_status(serviceId)
 
                        if not loggedIn:
                                loggedIn, serviceId = self._login_by_user(numOfAttempts)
 
                        with gtk_toolbox.gtk_lock():
                                self._change_loggedin_status(serviceId)
-               except StandardError, e:
+                               if loggedIn:
+                                       hildonize.show_information_banner(self._window, "Logged In")
+                               else:
+                                       hildonize.show_information_banner(self._window, "Login Failed")
+               except Exception, e:
                        with gtk_toolbox.gtk_lock():
                        with gtk_toolbox.gtk_lock():
-                               self._errorDisplay.push_exception(e)
-
-       def _spawn_attempt_login(self, *args):
-               backgroundLogin = threading.Thread(target=self.attempt_login, args=args)
-               backgroundLogin.setDaemon(True)
-               backgroundLogin.start()
+                               self._errorDisplay.push_exception()
 
        def refresh_session(self):
                """
                @note Thread agnostic
                """
                assert self._initDone, "Attempting login before app is fully loaded"
 
        def refresh_session(self):
                """
                @note Thread agnostic
                """
                assert self._initDone, "Attempting login before app is fully loaded"
-               if not self._deviceIsOnline:
-                       raise RuntimeError("Unable to login, device is not online")
 
                loggedIn = False
                if not loggedIn:
 
                loggedIn = False
                if not loggedIn:
@@ -378,10 +406,7 @@ class Dialcentral(object):
                """
                loggedIn = self._phoneBackends[self._defaultBackendId].is_authed()
                if loggedIn:
                """
                loggedIn = self._phoneBackends[self._defaultBackendId].is_authed()
                if loggedIn:
-                       warnings.warn(
-                               "Logged into %r through cookies" % self._phoneBackends[self._defaultBackendId],
-                               UserWarning, 2
-                       )
+                       _moduleLogger.info("Logged into %r through cookies" % self._phoneBackends[self._defaultBackendId])
                return loggedIn
 
        def _login_by_settings(self):
                return loggedIn
 
        def _login_by_settings(self):
@@ -392,10 +417,7 @@ class Dialcentral(object):
                loggedIn = self._phoneBackends[self._defaultBackendId].login(username, password)
                if loggedIn:
                        self._credentials = username, password
                loggedIn = self._phoneBackends[self._defaultBackendId].login(username, password)
                if loggedIn:
                        self._credentials = username, password
-                       warnings.warn(
-                               "Logged into %r through settings" % self._phoneBackends[self._defaultBackendId],
-                               UserWarning, 2
-                       )
+                       _moduleLogger.info("Logged into %r through settings" % self._phoneBackends[self._defaultBackendId])
                return loggedIn
 
        def _login_by_user(self, numOfAttempts):
                return loggedIn
 
        def _login_by_user(self, numOfAttempts):
@@ -403,30 +425,32 @@ class Dialcentral(object):
                @note This must be run outside of the UI lock
                """
                loggedIn, (username, password) = False, self._credentials
                @note This must be run outside of the UI lock
                """
                loggedIn, (username, password) = False, self._credentials
-               tmpServiceId = self.NULL_BACKEND
+               tmpServiceId = self.GV_BACKEND
                for attemptCount in xrange(numOfAttempts):
                        if loggedIn:
                                break
                for attemptCount in xrange(numOfAttempts):
                        if loggedIn:
                                break
-                       availableServices = {
-                               self.GV_BACKEND: "Google Voice",
-                               self.GC_BACKEND: "Grand Central",
-                       }
                        with gtk_toolbox.gtk_lock():
                        with gtk_toolbox.gtk_lock():
-                               credentials = self._credentialsDialog.request_credentials_from(
-                                       availableServices, defaultCredentials = self._credentials
+                               credentials = self._credentialsDialog.request_credentials(
+                                       defaultCredentials = self._credentials
                                )
                                )
-                       tmpServiceId, username, password = credentials
-                       loggedIn = self._phoneBackends[tmpServiceId].login(username, password)
+                               if not self._phoneBackends[tmpServiceId].get_callback_number():
+                                       # subtle reminder to the users to configure things
+                                       self._notebook.set_current_page(self.ACCOUNT_TAB)
+                               banner = hildonize.show_busy_banner_start(self._window, "Logging In...")
+                       try:
+                               username, password = credentials
+                               loggedIn = self._phoneBackends[tmpServiceId].login(username, password)
+                       finally:
+                               with gtk_toolbox.gtk_lock():
+                                       hildonize.show_busy_banner_end(banner)
 
                if loggedIn:
                        serviceId = tmpServiceId
                        self._credentials = username, password
 
                if loggedIn:
                        serviceId = tmpServiceId
                        self._credentials = username, password
-                       warnings.warn(
-                               "Logged into %r through user request" % self._phoneBackends[serviceId],
-                               UserWarning, 2
-                       )
+                       _moduleLogger.info("Logged into %r through user request" % self._phoneBackends[serviceId])
                else:
                        serviceId = self.NULL_BACKEND
                else:
                        serviceId = self.NULL_BACKEND
+                       self._notebook.set_current_page(self.ACCOUNT_TAB)
 
                return loggedIn, serviceId
 
 
                return loggedIn, serviceId
 
@@ -461,16 +485,18 @@ class Dialcentral(object):
 
                if self._phoneBackends[self._selectedBackendId].get_callback_number() is None:
                        self._phoneBackends[self._selectedBackendId].set_sane_callback()
 
                if self._phoneBackends[self._selectedBackendId].get_callback_number() is None:
                        self._phoneBackends[self._selectedBackendId].set_sane_callback()
-               self._accountViews[self._selectedBackendId].update()
 
                self._selectedBackendId = newStatus
 
 
                self._selectedBackendId = newStatus
 
+               self._accountViews[self._selectedBackendId].update()
+               self._refresh_active_tab()
+
        def load_settings(self, config):
                """
                @note UI Thread
                """
                try:
        def load_settings(self, config):
                """
                @note UI Thread
                """
                try:
-                       self._defaultBackendId = int(config.get(constants.__pretty_app_name__, "active"))
+                       self._defaultBackendId = config.getint(constants.__pretty_app_name__, "active")
                        blobs = (
                                config.get(constants.__pretty_app_name__, "bin_blob_%i" % i)
                                for i in xrange(len(self._credentials))
                        blobs = (
                                config.get(constants.__pretty_app_name__, "bin_blob_%i" % i)
                                for i in xrange(len(self._credentials))
@@ -480,13 +506,22 @@ class Dialcentral(object):
                                for blob in blobs
                        )
                        self._credentials = tuple(creds)
                                for blob in blobs
                        )
                        self._credentials = tuple(creds)
+
+                       if self._alarmHandler is not None:
+                               self._alarmHandler.load_settings(config, "alarm")
+               except ConfigParser.NoOptionError, e:
+                       _moduleLogger.exception(
+                               "Settings file %s is missing section %s" % (
+                                       constants._user_settings_,
+                                       e.section,
+                               ),
+                       )
                except ConfigParser.NoSectionError, e:
                except ConfigParser.NoSectionError, e:
-                       warnings.warn(
+                       _moduleLogger.exception(
                                "Settings file %s is missing section %s" % (
                                "Settings file %s is missing section %s" % (
-                                       self._user_settings,
+                                       constants._user_settings_,
                                        e.section,
                                ),
                                        e.section,
                                ),
-                               stacklevel=2
                        )
 
                for backendId, view in itertools.chain(
                        )
 
                for backendId, view in itertools.chain(
@@ -499,24 +534,56 @@ class Dialcentral(object):
                        sectionName = "%s - %s" % (backendId, view.name())
                        try:
                                view.load_settings(config, sectionName)
                        sectionName = "%s - %s" % (backendId, view.name())
                        try:
                                view.load_settings(config, sectionName)
+                       except ConfigParser.NoOptionError, e:
+                               _moduleLogger.exception(
+                                       "Settings file %s is missing section %s" % (
+                                               constants._user_settings_,
+                                               e.section,
+                                       ),
+                               )
                        except ConfigParser.NoSectionError, e:
                        except ConfigParser.NoSectionError, e:
-                               warnings.warn(
+                               _moduleLogger.exception(
                                        "Settings file %s is missing section %s" % (
                                        "Settings file %s is missing section %s" % (
-                                               self._user_settings,
+                                               constants._user_settings_,
                                                e.section,
                                        ),
                                                e.section,
                                        ),
-                                       stacklevel=2
                                )
 
                                )
 
+               try:
+                       previousOrientation = config.getint(constants.__pretty_app_name__, "orientation")
+                       if previousOrientation == gtk.ORIENTATION_HORIZONTAL:
+                               hildonize.window_to_landscape(self._window)
+                       elif previousOrientation == gtk.ORIENTATION_VERTICAL:
+                               hildonize.window_to_portrait(self._window)
+               except ConfigParser.NoOptionError, e:
+                       _moduleLogger.exception(
+                               "Settings file %s is missing section %s" % (
+                                       constants._user_settings_,
+                                       e.section,
+                               ),
+                       )
+               except ConfigParser.NoSectionError, e:
+                       _moduleLogger.exception(
+                               "Settings file %s is missing section %s" % (
+                                       constants._user_settings_,
+                                       e.section,
+                               ),
+                       )
+
        def save_settings(self, config):
                """
                @note Thread Agnostic
                """
                config.add_section(constants.__pretty_app_name__)
                config.set(constants.__pretty_app_name__, "active", str(self._selectedBackendId))
        def save_settings(self, config):
                """
                @note Thread Agnostic
                """
                config.add_section(constants.__pretty_app_name__)
                config.set(constants.__pretty_app_name__, "active", str(self._selectedBackendId))
+               config.set(constants.__pretty_app_name__, "orientation", str(int(gtk_toolbox.get_screen_orientation())))
                for i, value in enumerate(self._credentials):
                        blob = base64.b64encode(value)
                        config.set(constants.__pretty_app_name__, "bin_blob_%i" % i, blob)
                for i, value in enumerate(self._credentials):
                        blob = base64.b64encode(value)
                        config.set(constants.__pretty_app_name__, "bin_blob_%i" % i, blob)
+               config.add_section("alarm")
+               if self._alarmHandler is not None:
+                       self._alarmHandler.save_settings(config, "alarm")
+
                for backendId, view in itertools.chain(
                        self._dialpads.iteritems(),
                        self._accountViews.iteritems(),
                for backendId, view in itertools.chain(
                        self._dialpads.iteritems(),
                        self._accountViews.iteritems(),
@@ -528,23 +595,28 @@ class Dialcentral(object):
                        config.add_section(sectionName)
                        view.save_settings(config, sectionName)
 
                        config.add_section(sectionName)
                        view.save_settings(config, sectionName)
 
-       def _guess_preferred_backend(self, backendAndCookiePaths):
-               modTimeAndPath = [
-                       (getmtime_nothrow(path), backendId, path)
-                       for backendId, path in backendAndCookiePaths
-               ]
-               modTimeAndPath.sort()
-               return modTimeAndPath[-1][1]
-
        def _save_settings(self):
                """
                @note Thread Agnostic
                """
                config = ConfigParser.SafeConfigParser()
                self.save_settings(config)
        def _save_settings(self):
                """
                @note Thread Agnostic
                """
                config = ConfigParser.SafeConfigParser()
                self.save_settings(config)
-               with open(self._user_settings, "wb") as configFile:
+               with open(constants._user_settings_, "wb") as configFile:
                        config.write(configFile)
 
                        config.write(configFile)
 
+       def _refresh_active_tab(self):
+               pageIndex = self._notebook.get_current_page()
+               if pageIndex == self.CONTACTS_TAB:
+                       self._contactsViews[self._selectedBackendId].update(force=True)
+               elif pageIndex == self.RECENT_TAB:
+                       self._recentViews[self._selectedBackendId].update(force=True)
+               elif pageIndex == self.MESSAGES_TAB:
+                       self._messagesViews[self._selectedBackendId].update(force=True)
+
+               if pageIndex in (self.RECENT_TAB, self.MESSAGES_TAB):
+                       if self._ledHandler is not None:
+                               self._ledHandler.off()
+
        def _on_close(self, *args, **kwds):
                try:
                        if self._osso is not None:
        def _on_close(self, *args, **kwds):
                try:
                        if self._osso is not None:
@@ -562,157 +634,217 @@ class Dialcentral(object):
 
                @note Hildon specific
                """
 
                @note Hildon specific
                """
-               if memory_low:
-                       for backendId in self.BACKENDS:
-                               self._phoneBackends[backendId].clear_caches()
-                       self._contactsViews[self._selectedBackendId].clear_caches()
-                       gc.collect()
+               try:
+                       if memory_low:
+                               for backendId in self.BACKENDS:
+                                       self._phoneBackends[backendId].clear_caches()
+                               self._contactsViews[self._selectedBackendId].clear_caches()
+                               gc.collect()
 
 
-               if save_unsaved_data or shutdown:
-                       self._save_settings()
+                       if save_unsaved_data or shutdown:
+                               self._save_settings()
+               except Exception, e:
+                       self._errorDisplay.push_exception()
 
        def _on_connection_change(self, connection, event, magicIdentifier):
                """
                @note Hildon specific
                """
 
        def _on_connection_change(self, connection, event, magicIdentifier):
                """
                @note Hildon specific
                """
-               import conic
-
-               status = event.get_status()
-               error = event.get_error()
-               iap_id = event.get_iap_id()
-               bearer = event.get_bearer_type()
-
-               if status == conic.STATUS_CONNECTED:
-                       self._deviceIsOnline = True
-                       if self._initDone:
-                               self._spawn_attempt_login(2)
-               elif status == conic.STATUS_DISCONNECTED:
-                       self._deviceIsOnline = False
-                       if self._initDone:
-                               self._defaultBackendId = self._selectedBackendId
-                               self._change_loggedin_status(self.NULL_BACKEND)
+               try:
+                       import conic
+
+                       status = event.get_status()
+                       error = event.get_error()
+                       iap_id = event.get_iap_id()
+                       bearer = event.get_bearer_type()
+
+                       if status == conic.STATUS_CONNECTED:
+                               if self._initDone:
+                                       self._spawn_attempt_login(2)
+                       elif status == conic.STATUS_DISCONNECTED:
+                               if self._initDone:
+                                       self._defaultBackendId = self._selectedBackendId
+                                       self._change_loggedin_status(self.NULL_BACKEND)
+               except Exception, e:
+                       self._errorDisplay.push_exception()
 
        def _on_window_state_change(self, widget, event, *args):
                """
                @note Hildon specific
                """
 
        def _on_window_state_change(self, widget, event, *args):
                """
                @note Hildon specific
                """
-               if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
-                       self._isFullScreen = True
-               else:
-                       self._isFullScreen = False
+               try:
+                       if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
+                               self._isFullScreen = True
+                       else:
+                               self._isFullScreen = False
+               except Exception, e:
+                       self._errorDisplay.push_exception()
 
        def _on_key_press(self, widget, event, *args):
                """
                @note Hildon specific
                """
 
        def _on_key_press(self, widget, event, *args):
                """
                @note Hildon specific
                """
-               if event.keyval == gtk.keysyms.F6:
-                       if self._isFullScreen:
-                               self._window.unfullscreen()
-                       else:
-                               self._window.fullscreen()
+               RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
+               try:
+                       if (
+                               event.keyval == gtk.keysyms.F6 or
+                               event.keyval in RETURN_TYPES and event.get_state() & gtk.gdk.CONTROL_MASK
+                       ):
+                               if self._isFullScreen:
+                                       self._window.unfullscreen()
+                               else:
+                                       self._window.fullscreen()
+               except Exception, e:
+                       self._errorDisplay.push_exception()
 
        def _on_clearcookies_clicked(self, *args):
 
        def _on_clearcookies_clicked(self, *args):
-               self._phoneBackends[self._selectedBackendId].logout()
-               self._accountViews[self._selectedBackendId].clear()
-               self._recentViews[self._selectedBackendId].clear()
-               self._messagesViews[self._selectedBackendId].clear()
-               self._contactsViews[self._selectedBackendId].clear()
-               self._change_loggedin_status(self.NULL_BACKEND)
-
-               self._spawn_attempt_login(2, True)
-
-       def _on_notebook_switch_page(self, notebook, page, page_num):
-               if page_num == self.RECENT_TAB:
-                       self._recentViews[self._selectedBackendId].update()
-               elif page_num == self.MESSAGES_TAB:
-                       self._messagesViews[self._selectedBackendId].update()
-               elif page_num == self.CONTACTS_TAB:
-                       self._contactsViews[self._selectedBackendId].update()
-               elif page_num == self.ACCOUNT_TAB:
-                       self._accountViews[self._selectedBackendId].update()
-
-               tabTitle = self._notebook.get_tab_label(self._notebook.get_nth_page(page_num)).get_text()
-               if hildon is not None:
-                       self._window.set_title(tabTitle)
-               else:
-                       self._window.set_title("%s - %s" % (constants.__pretty_app_name__, tabTitle))
+               try:
+                       self._phoneBackends[self._selectedBackendId].logout()
+                       self._accountViews[self._selectedBackendId].clear()
+                       self._recentViews[self._selectedBackendId].clear()
+                       self._messagesViews[self._selectedBackendId].clear()
+                       self._contactsViews[self._selectedBackendId].clear()
+                       self._change_loggedin_status(self.NULL_BACKEND)
+
+                       self._spawn_attempt_login(2, True)
+               except Exception, e:
+                       self._errorDisplay.push_exception()
+
+       def _on_notebook_switch_page(self, notebook, page, pageIndex):
+               try:
+                       self._reset_tab_refresh()
+
+                       didRecentUpdate = False
+                       didMessagesUpdate = False
+
+                       if pageIndex == self.RECENT_TAB:
+                               didRecentUpdate = self._recentViews[self._selectedBackendId].update()
+                       elif pageIndex == self.MESSAGES_TAB:
+                               didMessagesUpdate = self._messagesViews[self._selectedBackendId].update()
+                       elif pageIndex == self.CONTACTS_TAB:
+                               self._contactsViews[self._selectedBackendId].update()
+                       elif pageIndex == self.ACCOUNT_TAB:
+                               self._accountViews[self._selectedBackendId].update()
+
+                       if didRecentUpdate or didMessagesUpdate:
+                               if self._ledHandler is not None:
+                                       self._ledHandler.off()
+               except Exception, e:
+                       self._errorDisplay.push_exception()
+
+       def _set_tab_refresh(self, *args):
+               try:
+                       pageIndex = self._notebook.get_current_page()
+                       child = self._notebook.get_nth_page(pageIndex)
+                       self._notebook.get_tab_label(child).set_text("Refresh?")
+               except Exception, e:
+                       self._errorDisplay.push_exception()
+               return False
+
+       def _reset_tab_refresh(self, *args):
+               try:
+                       pageIndex = self._notebook.get_current_page()
+                       child = self._notebook.get_nth_page(pageIndex)
+                       self._notebook.get_tab_label(child).set_text(self._originalCurrentLabels[pageIndex])
+               except Exception, e:
+                       self._errorDisplay.push_exception()
+               return False
+
+       def _on_tab_refresh(self, *args):
+               try:
+                       self._refresh_active_tab()
+                       self._reset_tab_refresh()
+               except Exception, e:
+                       self._errorDisplay.push_exception()
+               return False
 
        def _on_sms_clicked(self, number, message):
 
        def _on_sms_clicked(self, number, message):
-               assert number
-               assert message
                try:
                try:
-                       loggedIn = self._phoneBackends[self._selectedBackendId].is_authed()
-               except RuntimeError, e:
-                       loggedIn = False
-                       self._errorDisplay.push_exception(e)
-                       return
+                       assert number, "No number specified"
+                       assert message, "Empty message"
+                       try:
+                               loggedIn = self._phoneBackends[self._selectedBackendId].is_authed()
+                       except Exception, e:
+                               loggedIn = False
+                               self._errorDisplay.push_exception()
+                               return
 
 
-               if not loggedIn:
-                       self._errorDisplay.push_message(
-                               "Backend link with grandcentral is not working, please try again"
-                       )
-                       return
+                       if not loggedIn:
+                               self._errorDisplay.push_message(
+                                       "Backend link with GoogleVoice is not working, please try again"
+                               )
+                               return
 
 
-               dialed = False
-               try:
-                       self._phoneBackends[self._selectedBackendId].send_sms(number, message)
-                       dialed = True
-               except RuntimeError, e:
-                       self._errorDisplay.push_exception(e)
-               except ValueError, e:
-                       self._errorDisplay.push_exception(e)
+                       dialed = False
+                       try:
+                               self._phoneBackends[self._selectedBackendId].send_sms(number, message)
+                               hildonize.show_information_banner(self._window, "Sending to %s" % number)
+                               dialed = True
+                       except Exception, e:
+                               self._errorDisplay.push_exception()
+
+                       if dialed:
+                               self._dialpads[self._selectedBackendId].clear()
+               except Exception, e:
+                       self._errorDisplay.push_exception()
 
        def _on_dial_clicked(self, number):
 
        def _on_dial_clicked(self, number):
-               assert number
                try:
                try:
-                       loggedIn = self._phoneBackends[self._selectedBackendId].is_authed()
-               except RuntimeError, e:
-                       loggedIn = False
-                       self._errorDisplay.push_exception(e)
-                       return
+                       assert number, "No number to call"
+                       try:
+                               loggedIn = self._phoneBackends[self._selectedBackendId].is_authed()
+                       except Exception, e:
+                               loggedIn = False
+                               self._errorDisplay.push_exception()
+                               return
 
 
-               if not loggedIn:
-                       self._errorDisplay.push_message(
-                               "Backend link with grandcentral is not working, please try again"
-                       )
-                       return
+                       if not loggedIn:
+                               self._errorDisplay.push_message(
+                                       "Backend link with GoogleVoice is not working, please try again"
+                               )
+                               return
 
 
-               dialed = False
+                       dialed = False
+                       try:
+                               assert self._phoneBackends[self._selectedBackendId].get_callback_number() != "", "No callback number specified"
+                               self._phoneBackends[self._selectedBackendId].dial(number)
+                               hildonize.show_information_banner(self._window, "Calling %s" % number)
+                               dialed = True
+                       except Exception, e:
+                               self._errorDisplay.push_exception()
+
+                       if dialed:
+                               self._dialpads[self._selectedBackendId].clear()
+               except Exception, e:
+                       self._errorDisplay.push_exception()
+
+       def _on_menu_refresh(self, *args):
                try:
                try:
-                       assert self._phoneBackends[self._selectedBackendId].get_callback_number() != ""
-                       self._phoneBackends[self._selectedBackendId].dial(number)
-                       dialed = True
-               except RuntimeError, e:
-                       self._errorDisplay.push_exception(e)
-               except ValueError, e:
-                       self._errorDisplay.push_exception(e)
-
-               if dialed:
-                       self._dialpads[self._selectedBackendId].clear()
-
-       def _on_refresh(self, *args):
-               page_num = self._notebook.get_current_page()
-               if page_num == self.CONTACTS_TAB:
-                       self._contactsViews[self._selectedBackendId].update(force=True)
-               elif page_num == self.RECENT_TAB:
-                       self._recentViews[self._selectedBackendId].update(force=True)
-               elif page_num == self.MESSAGES_TAB:
-                       self._messagesViews[self._selectedBackendId].update(force=True)
+                       self._refresh_active_tab()
+               except Exception, e:
+                       self._errorDisplay.push_exception()
 
        def _on_paste(self, *args):
 
        def _on_paste(self, *args):
-               contents = self._clipboard.wait_for_text()
-               self._dialpads[self._selectedBackendId].set_number(contents)
+               try:
+                       contents = self._clipboard.wait_for_text()
+                       if contents is not None:
+                               self._dialpads[self._selectedBackendId].set_number(contents)
+               except Exception, e:
+                       self._errorDisplay.push_exception()
 
        def _on_about_activate(self, *args):
 
        def _on_about_activate(self, *args):
-               dlg = gtk.AboutDialog()
-               dlg.set_name(constants.__pretty_app_name__)
-               dlg.set_version(constants.__version__)
-               dlg.set_copyright("Copyright 2008 - LGPL")
-               dlg.set_comments("Dialer is designed to interface with your Google Grandcentral account.  This application is not affiliated with Google or Grandcentral in any way")
-               dlg.set_website("http://gc-dialer.garage.maemo.org/")
-               dlg.set_authors(["<z2n@merctech.com>", "Eric Warnke <ericew@gmail.com>", "Ed Page <edpage@byu.net>"])
-               dlg.run()
-               dlg.destroy()
+               try:
+                       dlg = gtk.AboutDialog()
+                       dlg.set_name(constants.__pretty_app_name__)
+                       dlg.set_version("%s-%d" % (constants.__version__, constants.__build__))
+                       dlg.set_copyright("Copyright 2008 - LGPL")
+                       dlg.set_comments("Dialcentral is a touch screen enhanced interface to your GoogleVoice account.  This application is not affiliated with Google in any way")
+                       dlg.set_website("http://gc-dialer.garage.maemo.org/")
+                       dlg.set_authors(["<z2n@merctech.com>", "Eric Warnke <ericew@gmail.com>", "Ed Page <edpage@byu.net>"])
+                       dlg.run()
+                       dlg.destroy()
+               except Exception, e:
+                       self._errorDisplay.push_exception()
 
 
 def run_doctest():
 
 
 def run_doctest():
@@ -727,8 +859,11 @@ def run_doctest():
 
 
 def run_dialpad():
 
 
 def run_dialpad():
+       _lock_file = os.path.join(constants._data_path_, ".lock")
+       #with gtk_toolbox.flock(_lock_file, 0):
        gtk.gdk.threads_init()
        gtk.gdk.threads_init()
-       if hildon is not None:
+
+       if hildonize.IS_HILDON_SUPPORTED:
                gtk.set_application_name(constants.__pretty_app_name__)
        handle = Dialcentral()
        gtk.main()
                gtk.set_application_name(constants.__pretty_app_name__)
        handle = Dialcentral()
        gtk.main()
@@ -741,21 +876,25 @@ class DummyOptions(object):
 
 
 if __name__ == "__main__":
 
 
 if __name__ == "__main__":
-       if len(sys.argv) > 1:
-               try:
-                       import optparse
-               except ImportError:
-                       optparse = None
-
-               if optparse is not None:
-                       parser = optparse.OptionParser()
-                       parser.add_option("-t", "--test", action="store_true", dest="test", help="Run tests")
-                       (commandOptions, commandArgs) = parser.parse_args()
-       else:
-               commandOptions = DummyOptions()
-               commandArgs = []
+       logging.basicConfig(level=logging.DEBUG)
+       try:
+               if len(sys.argv) > 1:
+                       try:
+                               import optparse
+                       except ImportError:
+                               optparse = None
 
 
-       if commandOptions.test:
-               run_doctest()
-       else:
-               run_dialpad()
+                       if optparse is not None:
+                               parser = optparse.OptionParser()
+                               parser.add_option("-t", "--test", action="store_true", dest="test", help="Run tests")
+                               (commandOptions, commandArgs) = parser.parse_args()
+               else:
+                       commandOptions = DummyOptions()
+                       commandArgs = []
+
+               if commandOptions.test:
+                       run_doctest()
+               else:
+                       run_dialpad()
+       finally:
+               logging.shutdown()