Hi,

attached are two patches that add tabs to Browse. One of the is for
hulahop and the other is for Browse.

Thanks,

Tomeu
From e18c2291f1c68b375a2d1731ccbbec7ff76ad073 Mon Sep 17 00:00:00 2001
From: Tomeu Vizoso <to...@sugarlabs.org>
Date: Wed, 17 Jun 2009 19:19:21 +0200
Subject: [PATCH] Implement tabs

---
 browser.py          |  201 +++++++++++++++++++++++++++++++++++++++++----------
 downloadmanager.py  |    4 +-
 progresslistener.py |   68 ++++++++++--------
 viewtoolbar.py      |   12 ++--
 webactivity.py      |   86 +++++++++++------------
 webtoolbar.py       |  131 +++++++++++++++++++++++-----------
 6 files changed, 342 insertions(+), 160 deletions(-)

diff --git a/browser.py b/browser.py
index b0a7ae7..0fc683e 100644
--- a/browser.py
+++ b/browser.py
@@ -85,7 +85,10 @@ class CommandListener(object):
         cert_exception = cls.createInstance(interfaces.hulahopAddCertException)
         cert_exception.showDialog(self._window)
 
-class Browser(WebView):
+class TabbedView(gtk.Notebook):
+    __gtype_name__ = 'TabbedView'
+
+    _com_interfaces_ = interfaces.nsIWindowCreator
 
     AGENT_SHEET = os.path.join(activity.get_bundle_path(), 
                                'agent-stylesheet.css')
@@ -93,15 +96,10 @@ class Browser(WebView):
                               'user-stylesheet.css')
 
     def __init__(self):
-        WebView.__init__(self)
-
-        self.history = HistoryListener()
-        self.progress = ProgressListener()
+        gobject.GObject.__init__(self)
 
-        cls = components.classes["@mozilla.org/typeaheadfind;1"]
-        self.typeahead = cls.createInstance(interfaces.nsITypeAheadFind)
-
-        self._jobject = None
+        self.props.show_border = False
+        self.props.scrollable = True
 
         io_service_class = components.classes[ \
                 "@mozilla.org/network/io-service;1"]
@@ -115,19 +113,165 @@ class Browser(WebView):
         cls = components.classes['@mozilla.org/content/style-sheet-service;1']
         style_sheet_service = cls.getService(interfaces.nsIStyleSheetService)
 
-        if os.path.exists(Browser.AGENT_SHEET):
+        if os.path.exists(TabbedView.AGENT_SHEET):
             agent_sheet_uri = io_service.newURI('file:///' + 
-                                                Browser.AGENT_SHEET,
+                                                TabbedView.AGENT_SHEET,
                                                 None, None)
             style_sheet_service.loadAndRegisterSheet(agent_sheet_uri,
                     interfaces.nsIStyleSheetService.AGENT_SHEET)
 
-        if os.path.exists(Browser.USER_SHEET):
-            user_sheet_uri = io_service.newURI('file:///' + Browser.USER_SHEET,
+        if os.path.exists(TabbedView.USER_SHEET):
+            user_sheet_uri = io_service.newURI('file:///' + TabbedView.USER_SHEET,
                                                None, None)
             style_sheet_service.loadAndRegisterSheet(user_sheet_uri,
                     interfaces.nsIStyleSheetService.USER_SHEET)
 
+        cls = components.classes['@mozilla.org/embedcomp/window-watcher;1']
+        window_watcher = cls.getService(interfaces.nsIWindowWatcher)
+        window_creator = xpcom.server.WrapObject(self,
+                                                 interfaces.nsIWindowCreator)
+        window_watcher.setWindowCreator(window_creator)
+
+        browser = Browser()
+        self._append_tab(browser)
+
+    def createChromeWindow(self, parent, flags):
+        if flags & interfaces.nsIWebBrowserChrome.CHROME_OPENAS_CHROME:
+            dialog = PopupDialog()
+            dialog.view.is_chrome = True
+
+            parent_dom_window = parent.webBrowser.contentDOMWindow
+            parent_view = hulahop.get_view_for_window(parent_dom_window)
+            if parent_view:
+                dialog.set_transient_for(parent_view.get_toplevel())
+
+            browser = dialog.view.browser
+            
+            item = browser.queryInterface(interfaces.nsIDocShellTreeItem)
+            item.itemType = interfaces.nsIDocShellTreeItem.typeChromeWrapper
+
+            return browser.containerWindow
+        else:
+            browser = Browser()
+            self._append_tab(browser)
+
+            return browser.browser.containerWindow
+
+    def _append_tab(self, browser):
+        label = TabLabel(browser)
+        label.connect('tab-close', self.__tab_close_cb)
+
+        self.append_page(browser, label)
+        browser.show()
+
+        self.set_current_page(-1)
+        self.props.show_tabs = self.get_n_pages() > 1
+
+    def __tab_close_cb(self, label, browser):
+        self.remove_page(self.page_num(browser))
+        browser.destroy()
+        self.props.show_tabs = self.get_n_pages() > 1
+
+    def _get_current_browser(self):
+        return self.get_nth_page(self.get_current_page())
+
+    current_browser = gobject.property(type=object, getter=_get_current_browser)
+
+    def get_session(self):
+        tab_sessions = []
+        for index in xrange(-1, self.get_n_pages() - 1):
+            browser = self.get_nth_page(index)
+            tab_sessions.append(sessionstore.get_session(browser))
+        return tab_sessions
+
+    def set_session(self, tab_sessions):
+        if tab_sessions and isinstance(tab_sessions[0], dict):
+            # Old format, no tabs
+            tab_sessions = [tab_sessions]
+            
+        while self.get_n_pages():
+            self.remove_page(self.get_n_pages() - 1)
+
+        for tab_session in tab_sessions:
+            browser = Browser()
+            self._append_tab(browser)
+            sessionstore.set_session(browser, tab_session)
+
+gtk.rc_parse_string('''
+    style "browse-tab-close" {
+        xthickness = 0
+        ythickness = 0
+    }
+    widget "*browse-tab-close" style "browse-tab-close"''')
+
+class TabLabel(gtk.HBox):
+    __gtype_name__ = 'TabLabel'
+
+    __gsignals__ = {
+        'tab-close': (gobject.SIGNAL_RUN_FIRST,
+                      gobject.TYPE_NONE,
+                      ([object]))
+    }
+
+    def __init__(self, browser):
+        gobject.GObject.__init__(self)
+        
+        self._browser = browser
+        self._browser.connect('is-setup', self.__browser_is_setup_cb)
+
+        self._label = gtk.Label('')
+        self.pack_start(self._label)
+        self._label.show()
+
+        button = gtk.Button()
+        button.connect('clicked', self.__button_clicked_cb)
+        button.set_name('browse-tab-close')
+        button.props.relief = gtk.RELIEF_NONE
+        button.props.focus_on_click = False
+        self.pack_start(button)
+        button.show()
+
+        close_image = gtk.image_new_from_stock(gtk.STOCK_CLOSE,
+                                               gtk.ICON_SIZE_MENU)
+        button.add(close_image)
+        close_image.show()
+
+    def __button_clicked_cb(self, button):
+        self.emit('tab-close', self._browser)
+
+    def __browser_is_setup_cb(self, browser):
+        browser.progress.connect('notify::location', self.__location_changed_cb)
+        browser.connect('notify::title', self.__title_changed_cb)
+
+    def __location_changed_cb(self, progress_listener, pspec):
+        uri = progress_listener.location
+        cls = components.classes['@mozilla.org/intl/texttosuburi;1']
+        texttosuburi = cls.getService(interfaces.nsITextToSubURI)
+        ui_uri = texttosuburi.unEscapeURIForUI(uri.originCharset, uri.spec)
+
+        self._label.set_text(ui_uri)
+
+    def __title_changed_cb(self, browser, pspec):
+        self._label.set_text(browser.props.title)
+
+class Browser(WebView):
+    __gtype_name__ = 'Browser'
+
+    __gsignals__ = {
+        'is-setup': (gobject.SIGNAL_RUN_FIRST,
+                  gobject.TYPE_NONE,
+                  ([]))
+    }
+
+    def __init__(self):
+        WebView.__init__(self)
+
+        self.history = HistoryListener()
+        self.progress = ProgressListener()
+
+        cls = components.classes["@mozilla.org/typeaheadfind;1"]
+        self.typeahead = cls.createInstance(interfaces.nsITypeAheadFind)
+
     def do_setup(self):
         WebView.do_setup(self)
 
@@ -145,6 +289,8 @@ class Browser(WebView):
 
         self.typeahead.init(self.doc_shell)
 
+        self.emit('is-setup')
+
     def get_session(self):
         return sessionstore.get_session(self)
 
@@ -199,31 +345,12 @@ class PopupDialog(gtk.Window):
                               gtk.gdk.screen_height() - border * 2)
 
         self.view = WebView()
+        self.view.connect('notify::visibility', self.__notify_visibility_cb)
         self.add(self.view)
         self.view.realize()
 
-class WindowCreator:
-    _com_interfaces_ = interfaces.nsIWindowCreator
-
-    def createChromeWindow(self, parent, flags):
-        dialog = PopupDialog()
-
-        parent_dom_window = parent.webBrowser.contentDOMWindow
-        parent_view = hulahop.get_view_for_window(parent_dom_window)
-        if parent_view:
-            dialog.set_transient_for(parent_view.get_toplevel())
-
-        browser = dialog.view.browser
-
-        if flags & interfaces.nsIWebBrowserChrome.CHROME_OPENAS_CHROME:
-            dialog.view.is_chrome = True
-
-            item = browser.queryInterface(interfaces.nsIDocShellTreeItem)
-            item.itemType = interfaces.nsIDocShellTreeItem.typeChromeWrapper
-
-        return browser.containerWindow
+    def __notify_visibility_cb(self, web_view, pspec):
+        if self.view.props.visibility:
+            self.view.show()
+            self.show()
 
-window_creator = WindowCreator()
-cls = components.classes['@mozilla.org/embedcomp/window-watcher;1']
-window_watcher = cls.getService(interfaces.nsIWindowWatcher)
-window_watcher.setWindowCreator(window_creator)
diff --git a/downloadmanager.py b/downloadmanager.py
index 69d1c8a..772ebaa 100644
--- a/downloadmanager.py
+++ b/downloadmanager.py
@@ -113,7 +113,7 @@ components.registrar.registerFactory('{64355793-988d-40a5-ba8e-fcde78cac631}',
 
 class Download:
     _com_interfaces_ = interfaces.nsITransfer
-    
+
     def init(self, source, target, display_name, mime_info, start_time,
              temp_file, cancelable):
         self._source = source
@@ -134,7 +134,7 @@ class Download:
         del _dest_to_window[self._target_file.path]
 
         view = hulahop.get_view_for_window(dom_window)
-        print dom_window
+        logging.debug('Download.init dom_window: %r' % dom_window)
         self._activity = view.get_toplevel()
         
         return NS_OK
diff --git a/progresslistener.py b/progresslistener.py
index 23d4966..fabf95f 100644
--- a/progresslistener.py
+++ b/progresslistener.py
@@ -22,29 +22,19 @@ from xpcom.components import interfaces
 class ProgressListener(gobject.GObject):
     _com_interfaces_ = interfaces.nsIWebProgressListener
 
-    __gsignals__ = {
-        'location-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
-                             ([object])),
-        'loading-start':    (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
-                             ([])),
-        'loading-stop':     (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
-                             ([])),
-        'loading-progress': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
-                             ([float]))
-    }
-
     def __init__(self):
         gobject.GObject.__init__(self)
 
-        self.total_requests = 0
-        self.completed_requests = 0
+        self._location = None
+        self._loading = False
+        self._progress = 0.0
+        self._total_requests = 0
+        self._completed_requests = 0
 
         self._wrapped_self = xpcom.server.WrapObject( \
                 self, interfaces.nsIWebProgressListener)
         weak_ref = xpcom.client.WeakReference(self._wrapped_self)
 
-        self._reset_requests_count()
-
     def setup(self, browser):
         mask = interfaces.nsIWebProgress.NOTIFY_STATE_NETWORK | \
                interfaces.nsIWebProgress.NOTIFY_STATE_REQUEST | \
@@ -53,12 +43,13 @@ class ProgressListener(gobject.GObject):
         browser.web_progress.addProgressListener(self._wrapped_self, mask)
     
     def _reset_requests_count(self):
-        self.total_requests = 0
-        self.completed_requests = 0
+        self._total_requests = 0
+        self._completed_requests = 0
     
     def onLocationChange(self, webProgress, request, location):
-        self.emit('location-changed', location)
-        
+        self._location = location
+        self.notify('location')
+
     def onProgressChange(self, webProgress, request, curSelfProgress,
                          maxSelfProgress, curTotalProgress, maxTotalProgress):
         pass
@@ -69,24 +60,43 @@ class ProgressListener(gobject.GObject):
     def onStateChange(self, webProgress, request, stateFlags, status):
         if stateFlags & interfaces.nsIWebProgressListener.STATE_IS_REQUEST:
             if stateFlags & interfaces.nsIWebProgressListener.STATE_START:
-                self.total_requests += 1
+                self._total_requests += 1
             elif stateFlags & interfaces.nsIWebProgressListener.STATE_STOP:
-                self.completed_requests += 1
+                self._completed_requests += 1
 
         if stateFlags & interfaces.nsIWebProgressListener.STATE_IS_NETWORK:
             if stateFlags & interfaces.nsIWebProgressListener.STATE_START:
-                self.emit('loading-start')
+                self._loading = True
                 self._reset_requests_count()                
+                self.notify('loading')
             elif stateFlags & interfaces.nsIWebProgressListener.STATE_STOP:
-                self.emit('loading-stop')
+                self._loading = False
+                self.notify('loading')
 
-        if self.total_requests < self.completed_requests:
-            self.emit('loading-progress', 1.0)
-        elif self.total_requests > 0:
-            self.emit('loading-progress', float(self.completed_requests) /
-                                          float(self.total_requests))
+        if self._total_requests < self._completed_requests:
+            self._progress = 1.0
+        elif self._total_requests > 0:
+            self._progress = \
+                    self._completed_requests / float(self._total_requests)
         else:
-            self.emit('loading-progress', 0.0)
+            self._progress = 0.0
+        self.notify('progress')
 
     def onStatusChange(self, webProgress, request, status, message):
         pass
+
+    def _get_location(self):
+        return self._location
+
+    location = gobject.property(type=object, getter=_get_location)
+
+    def _get_loading(self):
+        return self._loading
+
+    loading = gobject.property(type=bool, default=False, getter=_get_loading)
+
+    def _get_progress(self):
+        return self._progress
+
+    progress = gobject.property(type=float, getter=_get_progress)
+
diff --git a/viewtoolbar.py b/viewtoolbar.py
index 2b08360..6490eb2 100644
--- a/viewtoolbar.py
+++ b/viewtoolbar.py
@@ -27,8 +27,6 @@ class ViewToolbar(gtk.Toolbar):
         self._activity = activity        
         self._activity.tray.connect('unmap', self.__unmap_cb)
         self._activity.tray.connect('map', self.__map_cb)
-
-        self._browser = self._activity._browser
                 
         self.zoomout = ToolButton('zoom-out')
         self.zoomout.set_tooltip(_('Zoom out'))
@@ -60,11 +58,13 @@ class ViewToolbar(gtk.Toolbar):
         self.traybutton.show()
                 
     def __zoomin_clicked_cb(self, button):
-        self._browser.zoom_in()
-        
+        tabbed_view = self._activity.get_canvas()
+        tabbed_view.props.current_browser.zoom_in()
+
     def __zoomout_clicked_cb(self, button):
-        self._browser.zoom_out()
-                
+        tabbed_view = self._activity.get_canvas()
+        tabbed_view.props.current_browser.zoom_out()
+
     def __fullscreen_clicked_cb(self, button):
         self._activity.fullscreen()
 
diff --git a/webactivity.py b/webactivity.py
index a7c55bb..20150b6 100644
--- a/webactivity.py
+++ b/webactivity.py
@@ -152,7 +152,7 @@ def _set_accept_languages():
     branch.setCharPref('intl.accept_languages', pref)
     logging.debug('LANG set')
 
-from browser import Browser
+from browser import TabbedView
 from edittoolbar import EditToolbar
 from webtoolbar import WebToolbar
 from viewtoolbar import ViewToolbar
@@ -182,7 +182,7 @@ class WebActivity(activity.Activity):
 
         _logger.debug('Starting the web activity')
 
-        self._browser = Browser()
+        self._tabbed_view = TabbedView()
 
         _set_accept_languages()
         _seed_xs_cookie()
@@ -195,11 +195,12 @@ class WebActivity(activity.Activity):
 
         toolbox = activity.ActivityToolbox(self)
 
-        self._edit_toolbar = EditToolbar(self._browser)
+        self._edit_toolbar = EditToolbar(self._tabbed_view)
         toolbox.add_toolbar(_('Edit'), self._edit_toolbar)
         self._edit_toolbar.show()
 
-        self._web_toolbar = WebToolbar(self._browser)
+        self._web_toolbar = WebToolbar(self._tabbed_view)
+        self._web_toolbar.connect('add-link', self._link_add_button_cb)
         toolbox.add_toolbar(_('Browse'), self._web_toolbar)
         self._web_toolbar.show()
        
@@ -214,26 +215,18 @@ class WebActivity(activity.Activity):
         self.set_toolbox(toolbox)
         toolbox.show()
 
-        self.set_canvas(self._browser)
-        self._browser.show()
-                 
-        self._browser.history.connect('session-link-changed', 
-                                      self._session_history_changed_cb)
-        self._web_toolbar.connect('add-link', self._link_add_button_cb)
-
-        self._browser.connect("notify::title", self._title_changed_cb)
+        self.set_canvas(self._tabbed_view)
+        self._tabbed_view.show()
 
         self.model = Model()
         self.model.connect('add_link', self._add_link_model_cb)
 
-        self.current = _('blank')
-        self.webtitle = _('blank')
         self.connect('key-press-event', self._key_press_cb)
                      
         self.toolbox.set_current_toolbar(_TOOLBAR_BROWSE)
         
         if handle.uri:
-            self._browser.load_uri(handle.uri)        
+            self._tabbed_view.current_browser.load_uri(handle.uri)        
         elif not self._jobject.file_path:
             # TODO: we need this hack until we extend the activity API for
             # opening URIs and default docs.
@@ -362,23 +355,14 @@ class WebActivity(activity.Activity):
             self.messenger = Messenger(self.tube_conn, self.initiating, 
                                        self.model)         
 
-             
     def _load_homepage(self):
+        browser = self._tabbed_view.current_browser
         if os.path.isfile(_LIBRARY_PATH):
-            self._browser.load_uri('file://' + _LIBRARY_PATH)
+            browser.load_uri('file://' + _LIBRARY_PATH)
         else:
             default_page = os.path.join(activity.get_bundle_path(), 
                                         "data/index.html")
-            self._browser.load_uri(default_page)
-
-    def _session_history_changed_cb(self, session_history, link):
-        _logger.debug('NewPage: %s.' %link)
-        self.current = link
-        
-    def _title_changed_cb(self, embed, pspec):
-        if embed.props.title is not '':
-            _logger.debug('Title changed=%s' % embed.props.title)
-            self.webtitle = embed.props.title
+            browser.load_uri(default_page)
 
     def _get_data_from_file_path(self, file_path):
         fd = open(file_path, 'r')
@@ -401,43 +385,46 @@ class WebActivity(activity.Activity):
                                       base64.b64decode(link['thumb']),
                                       link['color'], link['title'],
                                       link['owner'], -1, link['hash'])      
-            self._browser.set_session(self.model.data['history'])
+            logging.debug('########## reading %s' % data)
+            self._tabbed_view.set_session(self.model.data['history'])
         elif self.metadata['mime_type'] == 'text/uri-list':
             data = self._get_data_from_file_path(file_path)
             uris = mime.split_uri_list(data)
             if len(uris) == 1:
-                self._browser.load_uri(uris[0])
+                self._tabbed_view.props.current_browser.load_uri(uris[0])
             else:
                 _logger.error('Open uri-list: Does not support' 
                               'list of multiple uris by now.') 
         else:
-            self._browser.load_uri(file_path)
+            self._tabbed_view.props.current_browser.load_uri(file_path)
         
     def write_file(self, file_path):
         if not self.metadata['mime_type']:
             self.metadata['mime_type'] = 'text/plain'
-        
+
         if self.metadata['mime_type'] == 'text/plain':
+
+            browser = self._tabbed_view.current_browser
+
             if not self._jobject.metadata['title_set_by_user'] == '1':
-                if self._browser.props.title:
-                    self.metadata['title'] = self._browser.props.title
+                if browser.props.title:
+                    self.metadata['title'] = browser.props.title
 
-            self.model.data['history'] = self._browser.get_session()
+            self.model.data['history'] = self._tabbed_view.get_session()
 
             f = open(file_path, 'w')
             try:
+                logging.debug('########## writing %s' % self.model.serialize())
                 f.write(self.model.serialize())
             finally:
                 f.close()
 
     def _link_add_button_cb(self, button):
-        _logger.debug('button: Add link: %s.' % self.current)                
         self._add_link()
             
     def _key_press_cb(self, widget, event):
         if event.state & gtk.gdk.CONTROL_MASK:
             if gtk.gdk.keyval_name(event.keyval) == "d":
-                _logger.debug('keyboard: Add link: %s.' % self.current)     
                 self._add_link()                
                 return True
             elif gtk.gdk.keyval_name(event.keyval) == "f":
@@ -452,30 +439,37 @@ class WebActivity(activity.Activity):
                 return True
             elif gtk.gdk.keyval_name(event.keyval) == "minus":
                 _logger.debug('keyboard: Zoom out')
-                self._browser.zoom_out()
+                self._tabbed_view.props.current_browser.zoom_out()
                 return True
             elif gtk.gdk.keyval_name(event.keyval) == "plus" \
                      or gtk.gdk.keyval_name(event.keyval) == "equal" :
                 _logger.debug('keyboard: Zoom in')
-                self._browser.zoom_in()
+                self._tabbed_view.props.current_browser.zoom_in()
                 return True
         return False
 
     def _add_link(self):
         ''' take screenshot and add link info to the model '''
+
+        browser = self._tabbed_view.props.current_browser
+        uri = browser.progress_listener.location
+        cls = components.classes['@mozilla.org/intl/texttosuburi;1']
+        texttosuburi = cls.getService(interfaces.nsITextToSubURI)
+        ui_uri = texttosuburi.unEscapeURIForUI(uri.originCharset, uri.spec)
+
         for link in self.model.data['shared_links']:
-            if link['hash'] == sha.new(self.current).hexdigest():
+            if link['hash'] == sha.new(ui_uri).hexdigest():
                 _logger.debug('_add_link: link exist already a=%s b=%s' %(
-                    link['hash'], sha.new(self.current).hexdigest()))
+                    link['hash'], sha.new(ui_uri).hexdigest()))
                 return
         buf = self._get_screenshot()
         timestamp = time.time()
-        self.model.add_link(self.current, self.webtitle, buf,
+        self.model.add_link(ui_uri, browser.props.title, buf,
                             profile.get_nick_name(),
                             profile.get_color().to_string(), timestamp)
 
         if self.messenger is not None:
-            self.messenger._add_link(self.current, self.webtitle,       
+            self.messenger._add_link(ui_uri, browser.props.title,       
                                      profile.get_color().to_string(),
                                      profile.get_nick_name(),
                                      base64.b64encode(buf), timestamp)
@@ -507,7 +501,7 @@ class WebActivity(activity.Activity):
 
     def _link_clicked_cb(self, button, url):
         ''' an item of the link tray has been clicked '''
-        self._browser.load_uri(url)
+        self._tabbed_view.props.current_browser.load_uri(url)
 
     def _pixbuf_save_cb(self, buf, data):
         data[0] += buf
@@ -519,7 +513,7 @@ class WebActivity(activity.Activity):
         return str(data[0])
 
     def _get_screenshot(self):
-        window = self._browser.window
+        window = self._tabbed_view.props.current_browser.window
         width, height = window.get_size()
 
         screenshot = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, has_alpha=False,
@@ -562,4 +556,6 @@ class WebActivity(activity.Activity):
             self.close(force=True)
 
     def get_document_path(self, async_cb, async_err_cb):
-        self._browser.get_source(async_cb, async_err_cb)
+        browser = self._tabbed_view.props.current_browser
+        browser.get_source(async_cb, async_err_cb)
+
diff --git a/webtoolbar.py b/webtoolbar.py
index 428fd89..e3f6f7f 100644
--- a/webtoolbar.py
+++ b/webtoolbar.py
@@ -220,10 +220,10 @@ class WebToolbar(gtk.Toolbar):
                      ([]))
     }
 
-    def __init__(self, browser):
+    def __init__(self, tabbed_view):
         gtk.Toolbar.__init__(self)
 
-        self._browser = browser
+        self._tabbed_view = tabbed_view
         
         self._loading = False
 
@@ -262,50 +262,92 @@ class WebToolbar(gtk.Toolbar):
         self._link_add.connect('clicked', self._link_add_clicked_cb)
         self.insert(self._link_add, -1)
         self._link_add.show()
-        
-        progress_listener = browser.progress
-        progress_listener.connect('location-changed', 
-                                  self._location_changed_cb)
-        progress_listener.connect('loading-start', self._loading_start_cb)
-        progress_listener.connect('loading-stop', self._loading_stop_cb)
-        progress_listener.connect('loading-progress', 
-                                  self._loading_progress_cb)
 
-        self._browser.history.connect('session-history-changed', 
-                                      self._session_history_changed_cb)
+        self._progress_listener = None
+        self._history = None
+        self._browser = None
+
+        self._location_changed_hid = None
+        self._loading_changed_hid = None
+        self._progress_changed_hid = None
+        self._session_history_changed_hid = None
+        self._title_changed_hid = None
+
+        gobject.idle_add(lambda:
+                self._connect_to_browser(tabbed_view.props.current_browser))
+
+        tabbed_view.connect_after('switch-page', self.__switch_page_cb)
+
+    def __switch_page_cb(self, tabbed_view, page, page_num):
+        self._connect_to_browser(tabbed_view.props.current_browser)
+
+    def _connect_to_browser(self, browser):
+        if self._progress_listener is not None:
+            self._progress_listener.disconnect(self._location_changed_hid)
+            self._progress_listener.disconnect(self._loading_changed_hid)
+            self._progress_listener.disconnect(self._progress_changed_hid)
+
+        self._progress_listener = browser.progress
+        self._set_progress(self._progress_listener.progress)
+        if self._progress_listener.location:
+            self._set_address(self._progress_listener.location)
+        else:
+            self._set_address(None)
+        self._set_loading(self._progress_listener.loading)
+        self._update_navigation_buttons()
+
+        self._location_changed_hid = self._progress_listener.connect(
+                'notify::location', self.__location_changed_cb)
+        self._loading_changed_hid = self._progress_listener.connect(
+                'notify::loading', self.__loading_changed_cb)
+        self._progress_changed_hid = self._progress_listener.connect(
+                'notify::progress', self.__progress_changed_cb)
 
-        self._browser.connect("notify::title", self._title_changed_cb)
+        if self._history is not None:
+            self._history.disconnect(self._session_history_changed_hid)
+
+        self._history = browser.history
+        self._session_history_changed_hid = self._history.connect(
+                'session-history-changed', self._session_history_changed_cb)
+
+        if self._browser is not None:
+            self._browser.disconnect(self._title_changed_hid)
+
+        self._browser = browser
+        self._set_title(self._browser.props.title)
+
+        self._title_changed_hid = self._browser.connect(
+                'notify::title', self._title_changed_cb)
 
     def _session_history_changed_cb(self, session_history, current_page_index):
         # We have to wait until the history info is updated.
         gobject.idle_add(self._reload_session_history, current_page_index)
 
-    def _location_changed_cb(self, progress_listener, uri):
-        cls = components.classes['@mozilla.org/intl/texttosuburi;1']
-        texttosuburi = cls.getService(interfaces.nsITextToSubURI)
-        ui_uri = texttosuburi.unEscapeURIForUI(uri.originCharset, uri.spec)
-
-        self._set_address(ui_uri)
+    def __location_changed_cb(self, progress_listener, pspec):
+        self._set_address(progress_listener.location)
         self._update_navigation_buttons()
         filepicker.cleanup_temp_files()
 
-    def _loading_start_cb(self, progress_listener):
-        self._set_title(None)
-        self._set_loading(True)
+    def __loading_changed_cb(self, progress_listener, pspec):
+        if progress_listener.loading:
+            self._set_title(None)
+        self._set_loading(progress_listener.loading)
         self._update_navigation_buttons()
 
-    def _loading_stop_cb(self, progress_listener):
-        self._set_loading(False)
-        self._update_navigation_buttons()
-
-    def _loading_progress_cb(self, progress_listener, progress):
-        self._set_progress(progress)
+    def __progress_changed_cb(self, progress_listener, pspec):
+        self._set_progress(progress_listener.progress)
 
     def _set_progress(self, progress):
         self.entry.props.progress = progress
 
-    def _set_address(self, address):
-        self.entry.props.address = address
+    def _set_address(self, uri):
+        if uri is not None:
+            cls = components.classes['@mozilla.org/intl/texttosuburi;1']
+            texttosuburi = cls.getService(interfaces.nsITextToSubURI)
+            ui_uri = texttosuburi.unEscapeURIForUI(uri.originCharset, uri.spec)
+        else:
+            ui_uri = None
+        self.entry.props.address = ui_uri
 
     def _set_title(self, title):
         self.entry.props.title = title
@@ -317,32 +359,37 @@ class WebToolbar(gtk.Toolbar):
         self._stop_and_reload.set_icon('view-refresh')
 
     def _update_navigation_buttons(self):
-        can_go_back = self._browser.web_navigation.canGoBack
+        browser = self._tabbed_view.props.current_browser
+
+        can_go_back = browser.web_navigation.canGoBack
         self._back.props.sensitive = can_go_back
 
-        can_go_forward = self._browser.web_navigation.canGoForward
+        can_go_forward = browser.web_navigation.canGoForward
         self._forward.props.sensitive = can_go_forward
 
     def _entry_activate_cb(self, entry):
-        self._browser.load_uri(entry.props.text)
-        self._browser.grab_focus()
+        browser = self._tabbed_view.props.current_browser
+        browser.load_uri(entry.props.text)
+        browser.grab_focus()
 
     def _go_back_cb(self, button):
-        self._browser.web_navigation.goBack()
+        browser = self._tabbed_view.props.current_browser
+        browser.web_navigation.goBack()
     
     def _go_forward_cb(self, button):
-        self._browser.web_navigation.goForward()
+        browser = self._tabbed_view.props.current_browser
+        browser.web_navigation.goForward()
 
     def _title_changed_cb(self, embed, spec):
         self._set_title(embed.props.title)
 
     def _stop_and_reload_cb(self, button):
+        browser = self._tabbed_view.props.current_browser
         if self._loading:
-            self._browser.web_navigation.stop( \
-                    interfaces.nsIWebNavigation.STOP_ALL)
+            browser.web_navigation.stop(interfaces.nsIWebNavigation.STOP_ALL)
         else:
             flags = interfaces.nsIWebNavigation.LOAD_FLAGS_NONE
-            self._browser.web_navigation.reload(flags)
+            browser.web_navigation.reload(flags)
 
     def _set_loading(self, loading):
         self._loading = loading
@@ -355,7 +402,8 @@ class WebToolbar(gtk.Toolbar):
             self._stop_and_reload.set_tooltip(_('Reload'))
 
     def _reload_session_history(self, current_page_index=None):
-        session_history = self._browser.web_navigation.sessionHistory
+        browser = self._tabbed_view.props.current_browser
+        session_history = browser.web_navigation.sessionHistory
         if current_page_index is None:
             current_page_index = session_history.index
 
@@ -391,7 +439,8 @@ class WebToolbar(gtk.Toolbar):
             menu_item.show()
 
     def _history_item_activated_cb(self, menu_item, index):
-        self._browser.web_navigation.gotoIndex(index)
+        browser = self._tabbed_view.props.current_browser
+        browser.web_navigation.gotoIndex(index)
 
     def _link_add_clicked_cb(self, button):
         self.emit('add-link')
-- 
1.5.6.3

From 2ac21c39adea52bbcd6edc50ff1fff5d8c523b81 Mon Sep 17 00:00:00 2001
From: Tomeu Vizoso <to...@sugarlabs.org>
Date: Wed, 17 Jun 2009 19:18:59 +0200
Subject: [PATCH] Fix visibility (inspired on gtkmozembed)

---
 configure.ac      |    2 ++
 python/webview.py |   38 ++++++++++++++++++++++++++++----------
 2 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/configure.ac b/configure.ac
index 39506be..7994e9c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,6 +17,8 @@ AC_SUBST([HULAHOP_HOST_OS],[$host_os])
 
 AM_INIT_AUTOMAKE([1.9 foreign dist-bzip2 no-dist-gzip])
 
+AM_MAINTAINER_MODE
+
 AC_PROG_LIBTOOL
 
 AC_PROG_CXX
diff --git a/python/webview.py b/python/webview.py
index 3cccde6..08f55ff 100644
--- a/python/webview.py
+++ b/python/webview.py
@@ -17,6 +17,7 @@
 import logging
 
 import gobject
+import gtk
 
 from hulahop import _hulahop
 
@@ -38,6 +39,7 @@ class _Chrome:
         self.title = ''
         self._modal = False
         self._chrome_flags = interfaces.nsIWebBrowserChrome.CHROME_ALL
+        self._visible = False
 
     def provideWindow(self, parent, flags, position_specified,
                       size_specified, uri, name, features):
@@ -140,10 +142,6 @@ class _Chrome:
         logging.debug("nsIEmbeddingSiteWindow.set_title: %r" % title)
         self.title = title
         self.web_view._notify_title_changed()
-        
-    def get_visibility(self):
-        #logging.debug("nsIEmbeddingSiteWindow.get_visibility: %r" % self.web_view.get_toplevel().props.visible)
-        return self.web_view.get_toplevel().props.visible
 
     def get_webBrowser(self):
         return self.web_view.browser
@@ -154,13 +152,20 @@ class _Chrome:
     def set_chromeFlags(self, flags):
         self._chrome_flags = flags
 
+    def get_visibility(self):
+        logging.debug("nsIEmbeddingSiteWindow.get_visibility: %r" % self._visible)
+        # See bug https://bugzilla.mozilla.org/show_bug.cgi?id=312998
+        # Work around the problem that sometimes the window is already visible
+        # even though mVisibility isn't true yet.
+        visibility = self.web_view.props.visibility
+        mapped = self.web_view.flags() & gtk.MAPPED
+        return visibility or (not self.web_view.is_chrome and mapped)
+
     def set_visibility(self, visibility):
         logging.debug("nsIEmbeddingSiteWindow.set_visibility: %r" % visibility)
-        if visibility:
-            self.web_view.show()
-            self.web_view.get_toplevel().show()
-        else:
-            self.web_view.get_toplevel().hide()
+        if visibility == self.web_view.props.visibility:
+            return
+        self.web_view.props.visibility = visibility
 
     # nsIWebProgressListener
     def onStateChange(self, web_progress, request, state_flags, status):
@@ -176,10 +181,14 @@ class _Chrome:
 
     # nsIInterfaceRequestor
     def queryInterface(self, uuid):
+        if uuid == interfaces.nsIDOMWindow:
+            return self.web_view.dom_window
+
         if not uuid in self._com_interfaces_:
             # Components.returnCode = Cr.NS_ERROR_NO_INTERFACE;
             logging.warning('Interface %s not implemented by this instance: %r' % (uuid, self))
             return None
+
         return xpcom.server.WrapObject(self, uuid)
 
     def getInterface(self, uuid):
@@ -205,7 +214,9 @@ class WebView(_hulahop.WebView):
         'title' : (str, None, None, None,
                    gobject.PARAM_READABLE),
         'status' : (str, None, None, None,
-                   gobject.PARAM_READABLE)
+                   gobject.PARAM_READABLE),
+        'visibility' : (bool, None, None, False,
+                        gobject.PARAM_READWRITE)
     }
 
     def __init__(self):
@@ -228,6 +239,7 @@ class WebView(_hulahop.WebView):
 
         self._status = ''
         self._first_uri = None
+        self._visibility = False
 
     def do_setup(self):
         _hulahop.WebView.do_setup(self)
@@ -247,6 +259,12 @@ class WebView(_hulahop.WebView):
             return self._chrome.title
         elif pspec.name == 'status':
             return self._status
+        elif pspec.name == 'visibility':
+            return self._visibility
+
+    def do_set_property(self, pspec, value):
+        if pspec.name == 'visibility':
+            self._visibility = value
 
     def get_window_root(self):
         return _hulahop.WebView.get_window_root(self)
-- 
1.5.6.3

_______________________________________________
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel

Reply via email to