Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPootle daemon <pootle@pootle.sugarlabs.org>2012-01-06 05:32:49 (GMT)
committer Pootle daemon <pootle@pootle.sugarlabs.org>2012-01-06 05:32:49 (GMT)
commitd12bd7718e913a0d57e47a7bb0e78cbe62e34513 (patch)
tree459a99f3e0901b74bbfecd2b4facccd762c85a0b
parent7457e06829989a8a9a413852ab3f9e17d09dcc55 (diff)
parent766ae15770617580c0cba22a7118d13dc175d3cc (diff)
Merge branch 'master' of git.sugarlabs.org:browse/mainline
-rw-r--r--browser.py204
-rw-r--r--linkbutton.py48
-rw-r--r--webactivity.py40
-rw-r--r--webtoolbar.py4
-rw-r--r--widgets.py30
5 files changed, 117 insertions, 209 deletions
diff --git a/browser.py b/browser.py
index f6efe26..0ff0b77 100644
--- a/browser.py
+++ b/browser.py
@@ -18,6 +18,7 @@
import os
import time
+import re
from gettext import gettext as _
from gi.repository import GObject
@@ -25,51 +26,32 @@ from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import Pango
from gi.repository import WebKit
+from gi.repository import Soup
from sugar3 import env
from sugar3.activity import activity
from sugar3.graphics import style
from sugar3.graphics.icon import Icon
-# FIXME
-# from palettes import ContentInvoker
-# from sessionhistory import HistoryListener
-# from progresslistener import ProgressListener
from widgets import BrowserNotebook
_ZOOM_AMOUNT = 0.1
_LIBRARY_PATH = '/usr/share/library-common/index.html'
+_WEB_SCHEMES = ['http', 'https', 'ftp', 'file', 'javascript', 'data',
+ 'about', 'gopher', 'mailto']
-class SaveListener(object):
- def __init__(self, user_data, callback):
- self._user_data = user_data
- self._callback = callback
-
- def onStateChange(self, webProgress, request, stateFlags, status):
- listener_class = interfaces.nsIWebProgressListener
- if (stateFlags & listener_class.STATE_IS_REQUEST and
- stateFlags & listener_class.STATE_STOP):
- self._callback(self._user_data)
-
- # Contrary to the documentation, STATE_IS_REQUEST is _not_ always set
- # if STATE_IS_DOCUMENT is set.
- if (stateFlags & listener_class.STATE_IS_DOCUMENT and
- stateFlags & listener_class.STATE_STOP):
- self._callback(self._user_data)
-
- def onProgressChange(self, progress, request, curSelfProgress,
- maxSelfProgress, curTotalProgress, maxTotalProgress):
- pass
-
- def onLocationChange(self, progress, request, location):
- pass
-
- def onStatusChange(self, progress, request, status, message):
- pass
-
- def onSecurityChange(self, progress, request, state):
- pass
+_NON_SEARCH_REGEX = re.compile('''
+ (^localhost(\\.[^\s]+)?(:\\d+)?(/.*)?$|
+ ^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]$|
+ ^::[0-9a-f:]*$| # IPv6 literals
+ ^[0-9a-f:]+:[0-9a-f:]*$| # IPv6 literals
+ ^[^\\.\s]+\\.[^\\.\s]+.*$| # foo.bar...
+ ^https?://[^/\\.\s]+.*$|
+ ^about:.*$|
+ ^data:.*$|
+ ^file:.*$)
+ ''', re.VERBOSE)
class CommandListener(object):
@@ -98,49 +80,12 @@ class TabbedView(BrowserNotebook):
([])),
}
- AGENT_SHEET = os.path.join(activity.get_bundle_path(),
- 'agent-stylesheet.css')
- USER_SHEET = os.path.join(env.get_profile_path(), 'gecko',
- 'user-stylesheet.css')
-
def __init__(self):
BrowserNotebook.__init__(self)
self.props.show_border = False
self.props.scrollable = True
- # FIXME
- # io_service_class = components.classes[ \
- # "@mozilla.org/network/io-service;1"]
- # io_service = io_service_class.getService(interfaces.nsIIOService)
-
- # # Use xpcom to turn off "offline mode" detection, which disables
- # # access to localhost for no good reason. (Trac #6250.)
- # io_service2 = io_service_class.getService(interfaces.nsIIOService2)
- # io_service2.manageOfflineStatus = False
-
- # cls = components.classes['@mozilla.org/content/style-sheet-service;1']
- # style_sheet_service = cls.getService(interfaces.nsIStyleSheetService)
-
- # if os.path.exists(TabbedView.AGENT_SHEET):
- # agent_sheet_uri = io_service.newURI('file:///' +
- # TabbedView.AGENT_SHEET,
- # None, None)
- # style_sheet_service.loadAndRegisterSheet(agent_sheet_uri,
- # interfaces.nsIStyleSheetService.AGENT_SHEET)
-
- # if os.path.exists(TabbedView.USER_SHEET):
- # url = 'file:///' + TabbedView.USER_SHEET
- # user_sheet_uri = io_service.newURI(url, 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)
-
self.connect('size-allocate', self.__size_allocate_cb)
self.connect('page-added', self.__page_added_cb)
self.connect('page-removed', self.__page_removed_cb)
@@ -149,28 +94,56 @@ class TabbedView(BrowserNotebook):
self._update_closing_buttons()
self._update_tab_sizes()
- def createChromeWindow(self, parent, flags):
- if flags & interfaces.nsIWebBrowserChrome.CHROME_OPENAS_CHROME:
- dialog = PopupDialog()
- dialog.view.is_chrome = True
+ def normalize_or_autosearch_url(self, url):
+ """Normalize the url input or return a url for search.
- 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())
+ We use SoupURI as an indication of whether the value given in url
+ is not something we want to search; we only do that, though, if
+ the address has a web scheme, because SoupURI will consider any
+ string: as a valid scheme, and we will end up prepending http://
+ to it.
- browser = dialog.view.browser
+ This code is borrowed from Epiphany.
- item = browser.queryInterface(interfaces.nsIDocShellTreeItem)
- item.itemType = interfaces.nsIDocShellTreeItem.typeChromeWrapper
+ url -- input string that can be normalized to an url or serve
+ as search
- return browser.containerWindow
+ Return: a string containing a valid url
+
+ """
+ def has_web_scheme(address):
+ if address == '':
+ return False
+
+ scheme, sep, after = address.partition(':')
+ if sep == '':
+ return False
+
+ return scheme in _WEB_SCHEMES
+
+ soup_uri = None
+ effective_url = None
+
+ if has_web_scheme(url):
+ try:
+ soup_uri = Soup.URI.new(url)
+ except TypeError:
+ pass
+
+ if soup_uri is None and not _NON_SEARCH_REGEX.match(url):
+ # If the string doesn't look like an URI, let's search it:
+ url_search = \
+ _('http://www.google.com/search?q=%s&ie=UTF-8&oe=UTF-8')
+ query_param = Soup.form_encode_hash({'q': url})
+ # [2:] here is getting rid of 'q=':
+ effective_url = url_search % query_param[2:]
else:
- browser = Browser()
- browser.connect('new-tab', self.__new_tab_cb)
- self._append_tab(browser)
+ if has_web_scheme(url):
+ effective_url = url
+ else:
+ effective_url = 'http://' + url
- return browser.browser.containerWindow
+ return effective_url
def __size_allocate_cb(self, widget, allocation):
self._update_tab_sizes()
@@ -376,9 +349,6 @@ class Browser(WebKit.WebView):
__gtype_name__ = 'Browser'
__gsignals__ = {
- 'is-setup': (GObject.SignalFlags.RUN_FIRST,
- None,
- ([])),
'new-tab': (GObject.SignalFlags.RUN_FIRST,
None,
([str])),
@@ -387,38 +357,6 @@ class Browser(WebKit.WebView):
def __init__(self):
WebKit.WebView.__init__(self)
- # FIXME
- # self.history = HistoryListener()
- # self.progress = ProgressListener()
-
- def do_setup(self):
- WebKit.WebView.do_setup(self)
- listener = xpcom.server.WrapObject(ContentInvoker(self),
- interfaces.nsIDOMEventListener)
- self.window_root.addEventListener('click', listener, False)
-
- listener = xpcom.server.WrapObject(CommandListener(self.dom_window),
- interfaces.nsIDOMEventListener)
- self.window_root.addEventListener('command', listener, False)
-
- self.progress.setup(self)
-
- self.history.setup(self.web_navigation)
-
- self.typeahead.init(self.doc_shell)
-
- self.emit('is-setup')
-
- def get_url_from_nsiuri(self, uri):
- """
- get a nsIURI object and return a string with the url
- """
- if uri == None:
- return ''
- cls = components.classes['@mozilla.org/intl/texttosuburi;1']
- texttosuburi = cls.getService(interfaces.nsITextToSubURI)
- return texttosuburi.unEscapeURIForUI(uri.originCharset, uri.spec)
-
def get_history(self):
"""Return the browsing history of this browser."""
back_forward_list = self.get_back_forward_list()
@@ -476,25 +414,17 @@ class Browser(WebKit.WebView):
return all_items
def get_source(self, async_cb, async_err_cb):
- cls = components.classes[ \
- '@mozilla.org/embedding/browser/nsWebBrowserPersist;1']
- persist = cls.createInstance(interfaces.nsIWebBrowserPersist)
- # get the source from the cache
- persist.persistFlags = \
- interfaces.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE
-
+ data_source = self.get_main_frame().get_data_source()
+ data = data_source.get_data()
+ if data_source.is_loading() or data is None:
+ async_err_cb()
temp_path = os.path.join(activity.get_activity_root(), 'instance')
file_path = os.path.join(temp_path, '%i' % time.time())
- cls = components.classes["@mozilla.org/file/local;1"]
- local_file = cls.createInstance(interfaces.nsILocalFile)
- local_file.initWithPath(file_path)
-
- progresslistener = SaveListener(file_path, async_cb)
- persist.progressListener = xpcom.server.WrapObject(
- progresslistener, interfaces.nsIWebProgressListener)
- uri = self.web_navigation.currentURI
- persist.saveURI(uri, self.doc_shell, None, None, None, local_file)
+ file_handle = file(file_path, 'w')
+ file_handle.write(data.str)
+ file_handle.close()
+ async_cb(file_path)
def open_new_tab(self, url):
self.emit('new-tab', url)
diff --git a/linkbutton.py b/linkbutton.py
index 151f74c..a6248bf 100644
--- a/linkbutton.py
+++ b/linkbutton.py
@@ -20,6 +20,9 @@ from gi.repository import GdkPixbuf
import os
from gi.repository import GObject
+from gi.repository import Gdk
+import StringIO
+import cairo
from gettext import gettext as _
import rsvg
import re
@@ -47,32 +50,27 @@ class LinkButton(TrayButton, GObject.GObject):
def set_image(self, buf, fill='#0000ff', stroke='#4d4c4f'):
img = Gtk.Image()
- loader = GdkPixbuf.PixbufLoader()
- loader.write(buf)
- loader.close()
- pixbuf = loader.get_pixbuf()
- del loader
+ str_buf = StringIO.StringIO(buf)
+ thumb_surface = cairo.ImageSurface.create_from_png(str_buf)
xo_buddy = os.path.join(os.path.dirname(__file__), "icons/link.svg")
- pixbuf_bg = self._read_link_background(xo_buddy, fill, stroke)
- pixbuf_bg = pixbuf_bg.scale_simple(style.zoom(120),
- style.zoom(110),
- GdkPixbuf.InterpType.BILINEAR)
+
+ bg_surface = self._read_link_background(xo_buddy, fill, stroke)
+
+ cairo_context = cairo.Context(bg_surface)
dest_x = style.zoom(10)
dest_y = style.zoom(20)
- w = pixbuf.get_width()
- h = pixbuf.get_height()
- scale_x = 1
- scale_y = 1
-
- pixbuf.composite(pixbuf_bg, dest_x, dest_y, w, h, dest_x, dest_y,
- scale_x, scale_y, GdkPixbuf.InterpType.BILINEAR, 255)
+ cairo_context.set_source_surface(thumb_surface, dest_x, dest_y)
+ thumb_width, thumb_height = style.zoom(100), style.zoom(80)
+ cairo_context.rectangle(dest_x, dest_y, thumb_width, thumb_height)
+ cairo_context.fill()
+
+ bg_width, bg_height = style.zoom(120), style.zoom(110)
+ pixbuf_bg = Gdk.pixbuf_get_from_surface(bg_surface, 0, 0,
+ bg_width, bg_height)
img.set_from_pixbuf(pixbuf_bg)
self.set_icon_widget(img)
img.show()
- del pixbuf
- del pixbuf_bg
- gc.collect()
def _read_link_background(self, filename, fill_color, stroke_color):
icon_file = open(filename, 'r')
@@ -87,8 +85,16 @@ class LinkButton(TrayButton, GObject.GObject):
entity = '<!ENTITY stroke_color "%s">' % stroke_color
data = re.sub('<!ENTITY stroke_color .*>', entity, data)
- data_size = len(data)
- return rsvg.Handle(data=data).get_pixbuf()
+ link_width, link_height = style.zoom(120), style.zoom(110)
+ link_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
+ link_width, link_height)
+ link_context = cairo.Context(link_surface)
+ link_scale_w = link_width * 1.0 / 120
+ link_scale_h = link_height * 1.0 / 110
+ link_context.scale(link_scale_w, link_scale_h)
+ handler = rsvg.Handle(data=data)
+ handler.render_cairo(link_context)
+ return link_surface
def setup_rollover_options(self, info):
palette = Palette(info, text_maxlen=50)
diff --git a/webactivity.py b/webactivity.py
index 4730588..3d741d9 100644
--- a/webactivity.py
+++ b/webactivity.py
@@ -35,6 +35,7 @@ import cjson
from gi.repository import GConf
import locale
import cairo
+import StringIO
from hashlib import sha1
from sugar3.activity import activity
@@ -504,7 +505,7 @@ class WebActivity(activity.Activity):
''' take screenshot and add link info to the model '''
browser = self._tabbed_view.props.current_browser
- ui_uri = browser.get_url_from_nsiuri(browser.progress.location)
+ ui_uri = browser.get_uri()
for link in self.model.data['shared_links']:
if link['hash'] == sha1(ui_uri).hexdigest():
@@ -553,31 +554,26 @@ class WebActivity(activity.Activity):
''' an item of the link tray has been clicked '''
self._tabbed_view.props.current_browser.load_uri(url)
- def _pixbuf_save_cb(self, buf, data):
- data[0] += buf
- return True
-
- def get_buffer(self, pixbuf):
- data = [""]
- pixbuf.save_to_callback(self._pixbuf_save_cb, "png", {}, data)
- return str(data[0])
-
def _get_screenshot(self):
- window = self._tabbed_view.props.current_browser.window
- width, height = window.get_size()
+ browser = self._tabbed_view.props.current_browser
+ window = browser.get_window()
+ width, height = window.get_width(), window.get_height()
+
+ thumb_width, thumb_height = style.zoom(100), style.zoom(80)
- screenshot = GdkPixbuf.Pixbuf(GdkPixbuf.Colorspace.RGB, has_alpha=False,
- bits_per_sample=8, width=width,
- height=height)
- screenshot.get_from_drawable(window, window.get_colormap(), 0, 0, 0, 0,
- width, height)
+ thumb_surface = Gdk.Window.create_similar_surface(window,
+ cairo.CONTENT_COLOR, thumb_width, thumb_height)
- screenshot = screenshot.scale_simple(style.zoom(100),
- style.zoom(80),
- GdkPixbuf.InterpType.BILINEAR)
+ cairo_context = cairo.Context(thumb_surface)
+ thumb_scale_w = thumb_width * 1.0 / width
+ thumb_scale_h = thumb_height * 1.0 / height
+ cairo_context.scale(thumb_scale_w, thumb_scale_h)
+ Gdk.cairo_set_source_window(cairo_context, window, 0, 0)
+ cairo_context.paint()
- buf = self.get_buffer(screenshot)
- return buf
+ thumb_str = StringIO.StringIO()
+ thumb_surface.write_to_png(thumb_str)
+ return thumb_str.getvalue()
def can_close(self):
if self._force_close:
diff --git a/webtoolbar.py b/webtoolbar.py
index 47ece72..c0e1396 100644
--- a/webtoolbar.py
+++ b/webtoolbar.py
@@ -384,7 +384,9 @@ class PrimaryToolbar(ToolbarBase):
def _entry_activate_cb(self, entry):
browser = self._tabbed_view.props.current_browser
- browser.load_uri(entry.props.text)
+ url = entry.props.text
+ effective_url = self._tabbed_view.normalize_or_autosearch_url(url)
+ browser.load_uri(effective_url)
browser.grab_focus()
def _go_home_cb(self, button):
diff --git a/widgets.py b/widgets.py
index 3cfdf1e..d1de3ee 100644
--- a/widgets.py
+++ b/widgets.py
@@ -59,37 +59,11 @@ class BrowserNotebook(Gtk.Notebook):
def __init__(self):
GObject.GObject.__init__(self)
- self._switch_handler = self.connect('switch-page',
- self.__on_switch_page)
tab_add = TabAdd()
tab_add.connect('tab-added', self.on_add_tab)
- empty_page = Gtk.HBox()
- self.append_page(empty_page, tab_add)
- empty_page.show()
+ self.set_action_widget(tab_add, Gtk.PackType.END)
+ tab_add.show()
def on_add_tab(self, obj):
raise NotImplementedError("implement this in the subclass")
-
- def __on_switch_page(self, notebook, page, page_num):
- """Don't switch to the extra tab at the end."""
- if page_num > 0 and page_num == Gtk.Notebook.get_n_pages(self) - 1:
- self.handler_block(self._switch_handler)
- self.set_current_page(-1)
- self.handler_unblock(self._switch_handler)
- self.connect('switch-page', self.__on_switch_page)
- self.stop_emission("switch-page")
-
- def get_n_pages(self):
- """Skip the extra tab at the end on the pages count."""
- return Gtk.Notebook.get_n_pages(self) - 1
-
- def append_page(self, page, label):
- """Append keeping the extra tab at the end."""
- return self.insert_page(page, label, self.get_n_pages())
-
- def set_current_page(self, number):
- """If indexing from the end, skip the extra tab."""
- if number < 0:
- number = self.get_n_pages() - 1
- Gtk.Notebook.set_current_page(self, number)