Skip to content
Browse files

first commit of the berkelium kivy extension

  • Loading branch information...
1 parent dfd0fc3 commit 08ea4344308cc70efd29061dc1bafd56a89871f5 @tito tito committed
Showing with 1,634 additions and 0 deletions.
  1. +30 −0 COPYING
  2. +22 −0 Makefile
  3. +50 −0 README
  4. +526 −0 berkelium/__init__.py
  5. +598 −0 berkelium/_berkelium.pyx
  6. +303 −0 berkelium/berkelium_wrapper.h
  7. +9 −0 berkelium/demo.py
  8. +33 −0 demo/main.py
  9. +63 −0 setup.py
View
30 COPYING
@@ -0,0 +1,30 @@
+Copyright (c) 2011, Mathieu Virbel <mat@kivy.org>
+
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+- Neither the name of the 'incremental' nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
View
22 Makefile
@@ -0,0 +1,22 @@
+version=1.0
+data=berkelium/data
+
+.PHONY: all clean
+
+all: clean
+ # Copy needed data
+ cp ../berkelium ../liblibberkelium.so ../resources.pak ../chrome.pak $(data)
+ cp -r ../locales $(data)
+ cp ../build/chromium/src/out/Release/libffmpegsumo.so $(data)
+
+ # Patches data
+ chrpath -r '$$ORIGIN' $(data)/berkelium $(data)/liblibberkelium.so
+
+ # Now create package
+ python setup.py create_package
+
+clean:
+ # Create data dir
+ rm -rf $(data)
+ mkdir $(data)
+
View
50 README
@@ -0,0 +1,50 @@
+Berkelium extension for Kivy
+============================
+
+Berkelium is a BSD licensed library for offscreen rendering via Chromium
+project. Check http://berkelium.org/ for more information about it. We are using
+a patched version of Berkelium, available at https://github.com/tito/berkelium
+(branch chromium8-alternate-bin)
+
+
+Notes
+-----
+
+ - This extension require Kivy 1.0.7 !
+ - This extension is under development. It's actually working and tested
+ only for Linux 64 bits.
+ - MacOSX can't be supported at the moment, since Kivy require Python
+ 64bits, and Chromium can't be built under 64bits on MacOSX.
+
+
+How to install
+--------------
+
+ 1. Download .kex https://github.com/tito/kivy-berkelium/archives/master
+ 2. Copy the .kex to ~/.kivy/extensions
+
+
+How to test
+-----------
+
+ 1. Download https://github.com/tito/kivy-berkelium/raw/master/demo/main.py
+ 2. Run with "python main.py"
+
+
+How to recompile
+----------------
+
+Note: this method have been tested only on Linux 64bits.
+
+ #. sudo apt-get install chrpath
+ #. git clone git://github.com/tito/berkelium
+ #. git checkout chromium8-alternate-bin
+ #. util/build-chromium.sh
+ #. cmake . -DCMAKE_BUILD_TYPE=Release
+ #. make
+ #. git clone git://github.com/tito/kivy-berkelium
+ #. cd kivy-berkelium
+ #. make
+ #. mv dist/berkelium-1.0.linux-x86_64.zip dist/berkelium-1.0.linux-x86_64.kex
+
+And you can copy the berkelium-1.0.linux-x86_64.kex into your ~/.kivy/extensions
View
526 berkelium/__init__.py
@@ -0,0 +1,526 @@
+'''
+Berkelium Webbrowser Extension
+==============================
+
+This extension provide a wrapper in Python / Kivy around Berkelium project.
+Berkelium project is a offscreen webbrower based on Chromium. You can check
+more about it at http://berkelium.org/
+
+About berkelium
+---------------
+
+Berkelium is actually patched to be able to load his binary from another
+directory than the current executable in memory (aka Python.)
+The patch is available at
+https://github.com/tito/berkelium/commit/c407a023f386e05fc873113e65935e2497e0980e
+
+Usage of Webbrowser
+-------------------
+
+We not providing a direct access to Berkelium (cpp wrapping in Python is
+complex), but we are providing a Widget that use Berkelium.
+
+For example, if you want to create a Webbrowser widget that load Google::
+
+ wb = Webbrowser(url='http://google.fr')
+
+'''
+
+__all__ = ('Webbrowser', )
+
+import kivy
+kivy.require('1.0.7')
+
+from os import chmod
+from os.path import dirname, realpath, join
+from weakref import ref
+from kivy.logger import Logger
+from kivy.clock import Clock
+from kivy.uix.widget import Widget
+from kivy.graphics import Color, Rectangle
+from kivy.factory import Factory
+from kivy.base import EventLoop
+from kivy.properties import StringProperty, ObjectProperty, AliasProperty, \
+ BooleanProperty, OptionProperty, ListProperty
+
+try:
+ import _berkelium as berkelium
+except ImportError:
+ Logger.critical('Unable to load berkelium extension.')
+ Logger.critical('Ensure that you have the good version for your platform')
+ raise
+
+# ensure the berkelium binary will be executable
+curdir = dirname(__file__)
+chmod(join(curdir, 'data', 'berkelium'), 0755)
+
+_berkelium_init = False
+_berkelium_listeners = []
+_berkelium_counter = 0
+
+def _update_berkelium(*largs):
+ berkelium.update()
+ global _berkelium_counter, _berkelium_listeners
+ _berkelium_counter += 1
+ if _berkelium_counter % 30 == 0:
+ _berkelium_listeners = [x for x in _berkelium_listeners if x()]
+ if not _berkelium_listeners:
+ Clock.unschedule(_update_berkelium)
+
+def _install_berkelium_update(listener):
+ # force the reschedule of the berkelium update.
+ Clock.unschedule(_update_berkelium)
+ Clock.schedule_interval(_update_berkelium, 1 / 30.)
+ # add the listener into the list
+ _berkelium_listeners.append(ref(listener))
+
+def _init_berkelium():
+ global _berkelium_init
+ if _berkelium_init:
+ return
+ _berkelium_init = True
+ berkelium.init(realpath(join(dirname(__file__), 'data')))
+
+class _WindowDelegate(berkelium.WindowDelegate):
+ def __init__(self, impl, width, height, usetrans):
+ self.impl = impl
+ self.debug = False
+ super(_WindowDelegate, self).__init__(width, height, usetrans)
+
+ def onTitleChanged(self, title):
+ if self.debug:
+ print 'Wb(%x).onTitleChanged()' % id(self), title
+ self.impl.title = title
+
+ def onAddressBarChanged(self, newURL):
+ if self.debug:
+ print 'Wb(%x).onAddressBarChanged()' % id(self), newURL
+ self.impl.url = newURL
+
+ def onStartLoading(self, newURL):
+ if self.debug:
+ print 'Wb(%x).onStartLoading()' % id(self), newURL
+ self.impl.dispatch('on_start_loading', newURL)
+
+ def onLoad(self):
+ if self.debug:
+ print 'Wb(%x).onLoad()' % id(self)
+ self.impl.dispatch('on_load')
+
+ def onCrashedWorker(self):
+ if self.debug:
+ print 'Wb(%x).onCrashedWorker()' % id(self)
+ self.impl.dispatch('on_crashed_worker')
+
+ def onCrashedPlugin(self, pluginName):
+ if self.debug:
+ print 'Wb(%x).onCrashedPlugin()' % id(self)
+ self.impl.dispatch('on_crashed_plugin', pluginName)
+
+ def onProvisionalLoadError(self, url, errorCode, isMain):
+ if self.debug:
+ print 'Wb(%x).onProvisionalLoadError()' % id(self), \
+ url, errorCode, isMain
+ self.impl.dispatch('on_provisional_load_error', url, errorCode, isMain)
+
+ def onConsoleMessage(self, message, sourceId, line_no):
+ if self.debug:
+ print 'Wb(%x).onConsoleMessage()' % id(self), \
+ message, sourceId, line_no
+ self.impl.dispatch('on_console_message', message, sourceId, line_no)
+
+ def onScriptAlert(self, message, defaultValue, url, flags, success):
+ if self.debug:
+ print 'Wb(%x).onScriptAlert()' % id(self), \
+ message, defaultValue, url, flags, success
+ self.impl.dispatch('on_script_alert', message, defaultValue, url, flags, success)
+
+ def onNavigationRequested(self, newURL, referrer, isNewWindow):
+ if self.debug:
+ print 'Wb(%x).onNavigationRequested()' % id(self), \
+ newURL, referrer, isNewWindow
+ return self.impl.dispatch('on_navigation_requested', newURL, referrer, isNewWindow)
+
+ def onLoadingStateChanged(self, isLoading):
+ if self.debug:
+ print 'Wb(%x).onLoadingStateChanged()' % id(self), isLoading
+ self.impl.is_loading = isLoading
+
+ def onTooltipChanged(self, text):
+ if self.debug:
+ print 'Wb(%x).onTooltipChanged()' % id(self), text
+ self.impl.tooltip = text
+
+ def onCrashed(self):
+ if self.debug:
+ print 'Wb(%x).onCrashed()' % id(self)
+ self.impl.status = 'crashed'
+
+ def onUnresponsive(self):
+ if self.debug:
+ print 'Wb(%x).onUnResponsive()' % id(self)
+ self.impl.status = 'unresponsive'
+
+ def onResponsive(self):
+ if self.debug:
+ print 'Wb(%x).onResponsive()' % id(self)
+ self.impl.status = 'ok'
+
+ def onCreatedWindow(self):
+ if self.debug:
+ print 'Wb(%x).onCreatedWindow()' % id(self)
+ self.impl.dispatch('on_created_window')
+
+ def onWidgetCreated(self):
+ if self.debug:
+ print 'Wb(%x).onWidgetCreated()' % id(self)
+ self.impl.dispatch('on_widget_created')
+
+ def onWidgetResize(self):
+ if self.debug:
+ print 'Wb(%x).onWidgetResize()' % id(self)
+ self.impl.dispatch('on_widget_resize')
+
+ def onWidgetMove(self):
+ if self.debug:
+ print 'Wb(%x).onWidgetMove()' % id(self)
+ self.impl.dispatch('on_widget_move')
+
+ def onPaint(self):
+ if self.debug:
+ print 'Wb(%x).onPaint()' % id(self)
+ self.impl.dispatch('on_paint')
+
+
+class Webbrowser(Widget):
+ '''Webbrowser class. See module documentation for more information.
+
+ :Events:
+ `on_start_loading`: url
+ Fired when a new page start to load
+ `on_load`:
+ Fired when loading is in progress
+ `on_crashed_worker`:
+ Fired when a worker crash
+ `on_crashed_plugin`:
+ Fired when a plugin crash
+ `on_provisional_load_error`: url, error_code, is_main
+ Fired when we cannot reach the url
+ `on_console_message`: message, source_id, line_no
+ Fired when a new message for console is available
+ `on_script_alert`: message, default_value, url, flags, success
+ Fired when a javascript do a alert() box
+ `on_navigation_requested`: url, referrer, is_new_window
+ Fired when a navigation is requested from a page (popup for example)
+ `on_created_window`:
+ Fired when a new window is created
+ `on_widget_created`:
+ Fired when a new widget is created
+ `on_widget_resize`:
+ Fired when a new widget is resized
+ `on_widget_move`:
+ Fired when a new widget is moving
+ `on_paint`:
+ Fired when the texture is updated
+ '''
+
+ #
+ # Privates
+ #
+ _bk = ObjectProperty(None)
+
+ def get_bk(self):
+ return self._bk
+
+ bk = AliasProperty(get_bk, None, bind=('_bk', ))
+
+ #
+ # Properties
+ #
+ url = StringProperty(None)
+ '''Url of the page, default to None. As soon as you change it, it will be
+ reloaded.
+
+ wb = Webbrowser()
+ wb.url = 'http://kivy.org'
+
+ :data:`url` is a :class:`~kivy.properties.StringProperty`, default to None.
+ '''
+
+ is_loading = BooleanProperty(False)
+ '''Indicate if the page is currently loading.
+
+ :data:`is_loading` is a :class:`~kivy.properties.BooleanProperty`, default
+ to False, read-only.
+ '''
+
+ title = StringProperty('')
+ '''Title of the current webpage.
+
+ :data:`title` is a :class:`~kivy.properties.StringProperty`, default
+ to '', read-only.
+ '''
+
+ tooltip = StringProperty('')
+ '''Current tooltip to show under the cursor.
+
+ :data:`tooltip` is a :class:`~kivy.properties.StringProperty`, default to
+ '', read-only
+ '''
+
+ status = OptionProperty('ok', options=('ok', 'crashed', 'unresponsive'))
+ '''Status of the internal browser. The availables options are :
+
+ - ok: everything is ok
+ - crashed: the internal module have crashed, you must reload it.
+ - unresponsive: the internal module is unresponsive, you may reload it.
+
+ :data:`status` is a `~kivy.properties.StringProperty`, default to 'ok',
+ read-only.
+ '''
+
+ transparency = BooleanProperty(False)
+ '''Indicate if the webpage should have a transparent background or not. Be
+ careful, this will work only if your webpage don't set a big div with a
+ background color. You can use it for rendering custom html like::
+
+ with open('bleh.html', 'w') as fd:
+ fd.write('<h1 style="color: #ff0000">Hello world</h1>')
+ wb = Webbrowser(transparency=True, size=(150, 50))
+ wb.open_filename('bleh.html')
+
+ This will result to show a big Hello world in red.
+ '''
+
+ texture = ObjectProperty(None)
+ '''Represent the texture that contain the webpage rendered
+ Depending of the texture creation, the value will be a
+ :class:`~kivy.graphics.texture.Texture` or
+ :class:`~kivy.graphics.texture.TextureRegion` object.
+
+ :data:`texture` is a :class:`~kivy.properties.ObjectProperty`, default to
+ None.
+ '''
+
+ texture_size = ListProperty([0, 0])
+ '''Texture size of the image.
+
+ .. warning::
+
+ The texture size is set after the texture property. So if you listen on
+ the change to :data:`texture`, the property texture_size will be not yet
+ updated. Use self.texture.size instead.
+ '''
+
+ def __init__(self, **kwargs):
+ _init_berkelium()
+
+ # Before doing anything, ensure the windows exist.
+ EventLoop.ensure_window()
+
+ self._bk = _WindowDelegate(self, self.width, self.height,
+ self.transparency)
+ self.register_event_type('on_start_loading')
+ self.register_event_type('on_load')
+ self.register_event_type('on_crashed_worker')
+ self.register_event_type('on_crashed_plugin')
+ self.register_event_type('on_provisional_load_error')
+ self.register_event_type('on_console_message')
+ self.register_event_type('on_script_alert')
+ self.register_event_type('on_navigation_requested')
+ self.register_event_type('on_created_window')
+ self.register_event_type('on_widget_created')
+ self.register_event_type('on_widget_resize')
+ self.register_event_type('on_widget_move')
+ self.register_event_type('on_paint')
+ super(Webbrowser, self).__init__(**kwargs)
+ if self.url is not None:
+ self.open_url(self.url)
+ with self.canvas:
+ self._g_color = Color(1, 1, 1)
+ self._g_rect = Rectangle(texture=self._bk.texture, size=self.size)
+ self._g_rect.tex_coords = (0, 1, 1, 1, 1, 0, 0, 0)
+ _install_berkelium_update(self)
+
+ def on_size(self, instance, value):
+ w, h = map(int, value)
+ self._bk.resize(w, h)
+ if not hasattr(self, '_g_rect'):
+ return
+ self._g_rect.texture = self._bk.texture
+ self._g_rect.tex_coords = (0, 1, 1, 1, 1, 0, 0, 0)
+ self._g_rect.size = w, h
+
+ def on_transparency(self, instance, value):
+ self._bk.setTransparent(value)
+
+ def on_touch_down(self, touch):
+ self._mouse_move(touch)
+ self._bk.mouseButton(0, 1)
+
+ def on_touch_move(self, touch):
+ self._mouse_move(touch)
+
+ def on_touch_up(self, touch):
+ self._mouse_move(touch)
+ self._bk.mouseButton(0, 0)
+
+ def _mouse_move(self, touch):
+ x = touch.x - self.x
+ y = self.height - (touch.y - self.y)
+ self._bk.mouseMoved(x, y)
+
+ #
+ # Public methods
+ #
+
+ def open_filename(self, filename):
+ '''Open a HTML from the disk (filename can be relative or absolute.)
+ '''
+ filename = realpath(filename)
+ self.open_url('file://' + filename)
+
+ def open_url(self, url):
+ '''Open an URL (starting with http://)
+ '''
+ self.url = url
+ try:
+ self.bk.stop()
+ self.bk.navigateTo(str(url))
+ except Exception, e:
+ print e
+
+ def focus(self):
+ '''Focus the window
+ '''
+ self._bk.focus()
+
+ def unfocus(self):
+ '''Unfocus the window
+ '''
+ self._bk.unfocus()
+
+ def adjust_zoom(self, mode):
+ '''Adjust zoom from mode
+ '''
+ self._bk.adjustZoom(mode)
+
+ def refresh(self):
+ '''Refresh the current page
+ '''
+ self._bk.refresh()
+
+ def stop(self):
+ '''Stop the loading of the page
+ '''
+ self._bk.stop()
+
+ def cut(self):
+ '''Cut the current selection
+ '''
+ self._bk.cut()
+
+ def copy(self):
+ '''Copy the current selection
+ '''
+ self._bk.copy()
+
+ def paste(self):
+ '''Paste the current selection
+ '''
+ self._bk.paste()
+
+ def undo(self):
+ '''Undo last action (in text input)
+ '''
+ self._bk.undo()
+
+ def redo(self):
+ '''Redo last action (in text input)
+ '''
+ self._bk.redo()
+
+ def select_all(self):
+ '''Select all the text
+ '''
+ self._bk.selectAll()
+
+ def go_back(self):
+ '''Go to the previous webpage in the history
+ '''
+ self._bk.goBack()
+
+ def go_forward(self):
+ '''Go to the next webpage in the history
+ '''
+ self._bk.goForward()
+
+ def can_go_back(self):
+ '''Return True if we can go back (if you can display the back button)
+ '''
+ return self._bk.canGoBack()
+
+ def can_go_forward(self):
+ '''Return True if we can go forward (if you can display the forward button)
+ '''
+ return self._bk.canGoForward()
+
+ # default handlers
+ def on_start_loading(self, url):
+ pass
+
+ def on_load(self):
+ pass
+
+ def on_crashed_worker(self):
+ pass
+
+ def on_crashed_plugin(self, plugin_name):
+ pass
+
+ def on_provisional_load_error(self, url, error_code, is_main):
+ pass
+
+ def on_console_message(self, message, source_id, line_no):
+ pass
+
+ def on_script_alert(self, message, default_value, url, flags, success):
+ pass
+
+ def on_navigation_requested(self, url, referrer, is_new_window):
+ if is_new_window:
+ return False
+ return True
+
+ def on_created_window(self):
+ pass
+
+ def on_widget_created(self):
+ pass
+
+ def on_widget_resize(self):
+ pass
+
+ def on_widget_move(self):
+ pass
+
+ def on_paint(self):
+ self.canvas.ask_update()
+
+Factory.register('Webbrowser', cls=Webbrowser)
+
+
+if __name__ == '__main__':
+
+ from kivy.app import App
+ class WebbrowserApp(App):
+ def build(self):
+ wb = Webbrowser(size_hint=(None, None), size=(300, 64),
+ transparency=True)
+ with open('bleh.html', 'w') as fd:
+ fd.write('<h1><span style="color: #ff0000">Hello</span>'
+ '<span style="color: #00ff00">World</span></h1>')
+ wb.open_filename('bleh.html')
+ return wb
+
+ WebbrowserApp().run()
View
598 berkelium/_berkelium.pyx
@@ -0,0 +1,598 @@
+#
+# Wrapper to berkelium. All the internal work is done inside berkelium, except
+# the rendering. He's changed to match our Kivy graphics class, and OpenGL ES
+# 2.0 requirement.
+#
+
+from libcpp cimport bool
+from array import array
+from kivy.graphics.opengl import *
+from kivy.graphics.fbo import Fbo
+
+cdef extern from "stdlib.h":
+ ctypedef unsigned long size_t
+ void free(void *ptr)
+ void *realloc(void *ptr, size_t size)
+ void *malloc(size_t size)
+
+cdef extern from "string.h":
+ void *memcpy(void *dest, void *src, size_t n)
+
+cdef extern from "Python.h":
+ object PyString_FromStringAndSize(char *s, Py_ssize_t len)
+
+cdef extern from "berkelium/Platform.hpp" namespace "Berkelium":
+ ctypedef unsigned int size_t
+
+cdef extern from "berkelium/WeakString.hpp":
+ cdef void *berkelium_filestring_empty "Berkelium::FileString::empty"()
+ cdef void *berkelium_filestring_point_to "Berkelium::FileString::point_to"(char *, int)
+
+cdef extern from "berkelium/Berkelium.hpp":
+ cdef void berkelium_init "Berkelium::initEx"(void *, char *)
+ cdef void berkelium_destroy "Berkelium::destroy"()
+ cdef void berkelium_update "Berkelium::update"()
+
+cdef extern from "berkelium/Context.hpp":
+ cdef cppclass Context "Berkelium::Context":
+ pass
+ cdef Context *Context_create "Berkelium::Context::create"()
+
+cdef extern from "berkelium/Window.hpp":
+ ctypedef char* const_wchar_ptr "const wchar_t*"
+ cdef cppclass Window "Berkelium::Window":
+ #int is_crashed()
+ void ShowRepostFormWarningDialog()
+ int getId()
+ void focus()
+ void unfocus()
+ void mouseMoved(int xPos, int yPos)
+ void mouseButton(unsigned int buttonID, int down)
+ void mouseWheel(int xScroll, int yScroll)
+ void textEvent(const_wchar_ptr evt, size_t evtLength)
+ void keyEvent(int pressed, int mods, int vk_code, int scancode)
+ void adjustZoom(int mode)
+ void refresh()
+ void stop()
+ void cut()
+ void copy()
+ void paste()
+ void undo()
+ void redo()
+ void selectAll()
+ void goBack()
+ void goForward()
+ void resize(int width, int height)
+ void navigateTo(char *url, size_t length)
+ bool canGoBack()
+ bool canGoForward()
+ void setTransparent(bool istrans)
+
+ cdef Window *Window_create "Berkelium::Window::create"(Context *)
+
+cdef extern from "berkelium_wrapper.h":
+ cdef cppclass Widget:
+ pass
+ cdef cppclass Rect:
+ int mLeft
+ int mTop
+ int mWidth
+ int mHeight
+ int y()
+ int x()
+ int top()
+ int left()
+ int width()
+ int height()
+ int right()
+ int bottom()
+ Rect translate(int dx, int dy)
+ Rect intersect(Rect &rect)
+ ctypedef void (*tp_onAddressBarChanged)(object obj, Window *win, char *newURL, int newURL_length)
+ ctypedef void (*tp_onStartLoading)(object obj, Window *win, char *newURL, int newURL_length)
+ ctypedef void (*tp_onLoad)(object obj, Window *win)
+ ctypedef void (*tp_onCrashedWorker)(object obj, Window *win)
+ ctypedef void (*tp_onCrashedPlugin)(object obj, Window *win, char *pluginName, int pluginName_length)
+ ctypedef void (*tp_onProvisionalLoadError)(object obj, Window *win, char *url, int url_length, int errorCode, int isMainFrame)
+ ctypedef void (*tp_onConsoleMessage)(object obj, Window *win, char *message, int message_length, char *sourceId, int sourceId_length, int line_no)
+ ctypedef void (*tp_onScriptAlert)(object obj, Window *win, char *message, int message_length, char *defaultValue, int defaultValue_length, char *url, int url_length, int flags, int &success, char *value, int value_length)
+ ctypedef void (*tp_onNavigationRequested)(object obj, Window *win, char *newURL, int newURL_length, char *referrer, int referrer_length, int isNewWindow, int &cancelDefaultAction)
+ ctypedef void (*tp_onLoadingStateChanged)(object obj, Window *win, int isLoading)
+ ctypedef void (*tp_onTitleChanged)(object obj, Window *win, char *title, int title_length)
+ ctypedef void (*tp_onTooltipChanged)(object obj, Window *win, char *text, int text_length)
+ ctypedef void (*tp_onCrashed)(object obj, Window *win)
+ ctypedef void (*tp_onUnresponsive)(object obj, Window *win)
+ ctypedef void (*tp_onResponsive)(object obj, Window *win)
+ ctypedef void (*tp_onCreatedWindow)(object obj, Window *win, Window *newWindow, Rect initialRect)
+ ctypedef void (*tp_onWidgetCreated)(object obj, Window *win, Widget *newWidget, int zIndex)
+ ctypedef void (*tp_onWidgetResize)(object obj, Window *win, Widget *wid, int newWidth, int newHeight)
+ ctypedef void (*tp_onWidgetMove)(object obj, Window *win, Widget *wid, int newX, int newY)
+ ctypedef void (*tp_onPaint)(object obj, Window *wini, unsigned char *bitmap_in, Rect &bitmap_rect, size_t num_copy_rects, Rect *copy_rects, int dx, int dy, Rect &scroll_rect)
+
+ cdef cppclass CyWindowDelegate:
+ CyWindowDelegate(object obj)
+ void init(unsigned int w, unsigned int h, int usetrans)
+ Window *getWindow()
+ tp_onAddressBarChanged impl_onAddressBarChanged
+ tp_onStartLoading impl_onStartLoading
+ tp_onLoad impl_onLoad
+ tp_onCrashedWorker impl_onCrashedWorker
+ tp_onCrashedPlugin impl_onCrashedPlugin
+ tp_onProvisionalLoadError impl_onProvisionalLoadError
+ tp_onConsoleMessage impl_onConsoleMessage
+ tp_onScriptAlert impl_onScriptAlert
+ tp_onNavigationRequested impl_onNavigationRequested
+ tp_onLoadingStateChanged impl_onLoadingStateChanged
+ tp_onTitleChanged impl_onTitleChanged
+ tp_onTooltipChanged impl_onTooltipChanged
+ tp_onCrashed impl_onCrashed
+ tp_onUnresponsive impl_onUnresponsive
+ tp_onResponsive impl_onResponsive
+ tp_onCreatedWindow impl_onCreatedWindow
+ tp_onWidgetCreated impl_onWidgetCreated
+ tp_onWidgetResize impl_onWidgetResize
+ tp_onWidgetMove impl_onWidgetMove
+ tp_onPaint impl_onPaint
+
+
+def init(bytes berkelium_path):
+ berkelium_init(berkelium_filestring_point_to(
+ berkelium_path, len(berkelium_path)), <char *>berkelium_path)
+
+def destroy():
+ berkelium_destroy()
+
+def update():
+ berkelium_update()
+
+
+cdef int _debug = 0
+def set_debug(activate):
+ global _debug
+ _debug = int(activate)
+
+cdef GL_BGRA = 0x80E1
+cdef int mapOnPaintToTexture(
+ Window *wini,
+ unsigned char* bitmap_in, Rect& bitmap_rect,
+ size_t num_copy_rects, Rect *copy_rects,
+ int dx, int dy,
+ Rect& scroll_rect,
+ object fbo,
+ unsigned int dest_texture_width,
+ unsigned int dest_texture_height,
+ int ignore_partial,
+ char* scroll_buffer):
+
+ cdef object tex = fbo.texture
+ cdef object tmp
+
+ tex.bind()
+
+ cdef int kBytesPerPixel = 4
+ cdef object py_bytes
+
+ # If we've reloaded the page and need a full update, ignore updates
+ # until a full one comes in. This handles out of date updates due to
+ # delays in event processing.
+ if ignore_partial:
+ if bitmap_rect.left() != 0 or \
+ bitmap_rect.top() != 0 or \
+ bitmap_rect.right() != dest_texture_width or \
+ bitmap_rect.bottom() != dest_texture_height:
+ return 0
+
+ py_bytes = PyString_FromStringAndSize(
+ <char *>bitmap_in, dest_texture_width * dest_texture_height * kBytesPerPixel)
+ glTexImage2D(GL_TEXTURE_2D, 0, kBytesPerPixel, dest_texture_width, dest_texture_height, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, py_bytes)
+ return 1
+
+
+ # Now, we first handle scrolling. We need to do this first since it
+ # requires shifting existing data, some of which will be overwritten by
+ # the regular dirty rect update.
+ cdef Rect scrolled_shared_rect, shader_rect
+ cdef int wid, hig, inc, jj
+ cdef char *outputBuffer, *inputBuffer
+ if dx != 0 or dy != 0:
+ # scroll_rect contains the Rect we need to move
+ # First we figure out where the the data is moved to by translating it
+ scrolled_rect = scroll_rect.translate(-dx, -dy)
+ # Next we figure out where they intersect, giving the scrolled
+ # region
+ scrolled_shared_rect = scroll_rect.intersect(scrolled_rect)
+ # Only do scrolling if they have non-zero intersection
+ if scrolled_shared_rect.width() > 0 and scrolled_shared_rect.height() > 0:
+ # And the scroll is performed by moving shared_rect by (dx,dy)
+ shared_rect = scrolled_shared_rect.translate(dx, dy)
+ wid = scrolled_shared_rect.width()
+ hig = scrolled_shared_rect.height()
+ inc = 1
+ outputBuffer = scroll_buffer
+ # source data is offset by 1 line to prevent memcpy aliasing
+ # In this case, it can happen if dy==0 and dx!=0.
+ inputBuffer = scroll_buffer+(dest_texture_width*1*kBytesPerPixel)
+ jj = 0
+ if dy > 0:
+ # Here, we need to shift the buffer around so that we start in the
+ # extra row at the end, and then copy in reverse so that we
+ # don't clobber source data before copying it.
+ outputBuffer = scroll_buffer+(
+ (scrolled_shared_rect.top()+hig+1)*dest_texture_width
+ - hig*wid)*kBytesPerPixel
+ inputBuffer = scroll_buffer
+ inc = -1
+ jj = hig-1
+
+ # Copy the data out of the texture, using the fbo
+ fbo.bind()
+ tmp = glReadPixels(0, 0, fbo.size[0], fbo.size[1], GL_RGBA, GL_UNSIGNED_BYTE)
+ fbo.release()
+ tex.bind()
+
+ # We swap RGBA -> BGRA, since glReadPixels dosn't support BGRA
+ a = array('b', tmp)
+ a[0::4], a[2::4] = a[2::4], a[0::4]
+ tmp = a.tostring()
+ inputBuffer = <char *>tmp
+
+ # Annoyingly, OpenGL doesn't provide convenient primitives, so
+ # we manually copy out the region to the beginning of the
+ # buffer
+ while jj < hig and jj >= 0:
+ memcpy(
+ outputBuffer + (jj*wid) * kBytesPerPixel,
+ inputBuffer + (
+ (scrolled_shared_rect.top()+jj)*dest_texture_width
+ + scrolled_shared_rect.left()) * kBytesPerPixel,
+ wid*kBytesPerPixel)
+ jj += inc
+
+ # And finally, we push it back into the texture in the right
+ # location
+ py_bytes = PyString_FromStringAndSize(outputBuffer,
+ shared_rect.width() * shared_rect.height() * kBytesPerPixel)
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ shared_rect.left(), shared_rect.top(),
+ shared_rect.width(), shared_rect.height(),
+ GL_BGRA, GL_UNSIGNED_BYTE, py_bytes)
+
+ cdef int i, top, left
+ cdef object py_scroll_buffer
+ for i in xrange(num_copy_rects):
+ wid = copy_rects[i].width()
+ hig = copy_rects[i].height()
+ top = copy_rects[i].top() - bitmap_rect.top()
+ left = copy_rects[i].left() - bitmap_rect.left()
+ for jj in xrange(hig):
+ memcpy(
+ scroll_buffer + jj*wid*kBytesPerPixel,
+ bitmap_in + (left + (jj+top)*bitmap_rect.width())*kBytesPerPixel,
+ wid*kBytesPerPixel)
+
+ # Finally, we perform the main update, just copying the rect that is
+ # marked as dirty but not from scrolled data.
+ py_bytes = PyString_FromStringAndSize(scroll_buffer, wid * hig * kBytesPerPixel)
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ copy_rects[i].left(), copy_rects[i].top(),
+ wid, hig, GL_BGRA, GL_UNSIGNED_BYTE, py_bytes)
+
+ glBindTexture(GL_TEXTURE_2D, 0)
+
+ return 1
+
+cdef class WindowDelegate:
+
+ cdef CyWindowDelegate *impl
+ cdef int width
+ cdef int height
+ cdef int needs_full_refresh
+ cdef char *scroll_buffer
+ cdef object fbo
+
+ def __cinit__(self, *largs):
+ self.needs_full_refresh = 1
+ self.impl = new CyWindowDelegate(self)
+ self.impl.impl_onLoad = <tp_onLoad>self.impl_onLoad
+ self.impl.impl_onAddressBarChanged = <tp_onAddressBarChanged>self.impl_onAddressBarChanged
+ self.impl.impl_onStartLoading = <tp_onStartLoading>self.impl_onStartLoading
+ self.impl.impl_onLoad = <tp_onLoad>self.impl_onLoad
+ self.impl.impl_onCrashedWorker = <tp_onCrashedWorker>self.impl_onCrashedWorker
+ self.impl.impl_onCrashedPlugin = <tp_onCrashedPlugin>self.impl_onCrashedPlugin
+ self.impl.impl_onProvisionalLoadError = <tp_onProvisionalLoadError>self.impl_onProvisionalLoadError
+ self.impl.impl_onConsoleMessage = <tp_onConsoleMessage>self.impl_onConsoleMessage
+ self.impl.impl_onScriptAlert = <tp_onScriptAlert>self.impl_onScriptAlert
+ self.impl.impl_onNavigationRequested = <tp_onNavigationRequested>self.impl_onNavigationRequested
+ self.impl.impl_onLoadingStateChanged = <tp_onLoadingStateChanged>self.impl_onLoadingStateChanged
+ self.impl.impl_onTitleChanged = <tp_onTitleChanged>self.impl_onTitleChanged
+ self.impl.impl_onTooltipChanged = <tp_onTooltipChanged>self.impl_onTooltipChanged
+ self.impl.impl_onCrashed = <tp_onCrashed>self.impl_onCrashed
+ self.impl.impl_onUnresponsive = <tp_onUnresponsive>self.impl_onUnresponsive
+ self.impl.impl_onResponsive = <tp_onResponsive>self.impl_onResponsive
+ self.impl.impl_onCreatedWindow = <tp_onCreatedWindow>self.impl_onCreatedWindow
+ self.impl.impl_onWidgetCreated = <tp_onWidgetCreated>self.impl_onWidgetCreated
+ self.impl.impl_onWidgetResize = <tp_onWidgetResize>self.impl_onWidgetResize
+ self.impl.impl_onWidgetMove = <tp_onWidgetMove>self.impl_onWidgetMove
+ self.impl.impl_onPaint = <tp_onPaint>self.impl_onPaint
+
+ def __init__(self, int width, int height, int usetrans):
+ self.scroll_buffer = <char *>malloc(width*(height+1)*4)
+ self.width = width
+ self.height = height
+ self.fbo = Fbo(size=(self.width, self.height), colorfmt='rgba')
+ self.fbo.texture.flip_vertical()
+ self.impl.init(width, height, usetrans)
+
+ #
+ # Default implementation handlers to translate c++ -> Python
+ #
+
+ cdef void impl_onAddressBarChanged(self, Window *win, char *newURL,
+ int newURL_length):
+ cdef str py_newURL = PyString_FromStringAndSize(newURL, newURL_length)
+ self.onAddressBarChanged(py_newURL)
+
+ cdef void impl_onStartLoading(self, Window *win, char *newURL,
+ int newURL_length):
+ cdef str py_newURL = PyString_FromStringAndSize(newURL, newURL_length)
+ self.onStartLoading(py_newURL)
+
+ cdef void impl_onLoad(self, Window *win):
+ self.onLoad()
+
+ cdef void impl_onCrashedWorker(self, Window *win):
+ self.onCrashedWorker()
+
+ cdef void impl_onCrashedPlugin(self, Window *win, char *pluginName,
+ int pluginName_length):
+ cdef str py_pluginName = PyString_FromStringAndSize(
+ pluginName, pluginName_length)
+ self.onCrashedPlugin(py_pluginName)
+
+ cdef void impl_onProvisionalLoadError(self, Window *win, char *url,
+ int url_length, int errorCode,
+ int isMainFrame):
+ cdef str py_url = PyString_FromStringAndSize(url, url_length)
+ self.onProvisionalLoadError(py_url, errorCode, isMainFrame)
+
+ cdef void impl_onConsoleMessage(self, Window *win, char *message, int
+ message_length, char *sourceId, int
+ sourceId_length, int line_no):
+ cdef str py_message = PyString_FromStringAndSize(
+ message, message_length)
+ cdef str py_sourceId = PyString_FromStringAndSize(
+ sourceId, sourceId_length)
+ self.onConsoleMessage(py_message, py_sourceId, line_no)
+
+ cdef void impl_onScriptAlert(self, Window *win, char *message, int
+ message_length, char *defaultValue, int
+ defaultValue_length, char *url, int url_length,
+ int flags, int &success, char **value, int
+ *value_length):
+ cdef str py_message = PyString_FromStringAndSize(
+ message, message_length)
+ cdef str py_defaultValue = PyString_FromStringAndSize(
+ defaultValue, defaultValue_length)
+ cdef str py_url = PyString_FromStringAndSize(
+ url, url_length)
+ self.onScriptAlert(py_message, py_defaultValue, py_url, flags, success)
+
+ cdef void impl_onNavigationRequested(self, Window *win, char *newURL, int
+ newURL_length, char *referrer, int
+ referrer_length, int isNewWindow, int
+ &cancelDefaultAction):
+ cdef py_url = PyString_FromStringAndSize(newURL, newURL_length)
+ cdef py_referrer = PyString_FromStringAndSize(referrer, referrer_length)
+ cdef int default_action = int(not ret)
+ ret = self.onNavigationRequested(py_url, py_referrer, isNewWindow)
+ try:
+ print 'cancel default action', ret
+ cancelDefaultAction = default_action
+ print 'cancel default action OK', ret
+ except:
+ pass
+
+ cdef void impl_onLoadingStateChanged(self, Window *win, int isLoading):
+ self.onLoadingStateChanged(isLoading)
+
+ cdef void impl_onTitleChanged(self, Window *win, char *title,
+ int title_length):
+ cdef str py_title = PyString_FromStringAndSize(title, title_length)
+ self.onTitleChanged(py_title)
+
+ cdef void impl_onTooltipChanged(self, Window *win, char *text,
+ int text_length):
+ cdef str py_text = PyString_FromStringAndSize(text, text_length)
+ self.onTooltipChanged(py_text)
+
+ cdef void impl_onCrashed(self, Window *win):
+ self.onCrashed()
+
+ cdef void impl_onUnresponsive(self, Window *win):
+ self.onUnresponsive()
+
+ cdef void impl_onResponsive(self, Window *win):
+ self.onResponsive()
+
+ cdef void impl_onCreatedWindow(self, Window *win, Window *newWindow,
+ Rect initialRect):
+ self.onCreatedWindow()
+
+ cdef void impl_onWidgetCreated(self, Window *win, Widget *newWidget,
+ int zIndex):
+ self.onWidgetCreated()
+
+ cdef void impl_onWidgetResize(self, Window *win, Widget *wid, int newWidth,
+ int newHeight):
+ self.onWidgetResize()
+
+ cdef void impl_onWidgetMove(self, Window *win, Widget *wid, int newX,
+ int newY):
+ self.onWidgetMove()
+
+ cdef void impl_onPaint(self, Window *wini, unsigned char *bitmap_in, Rect
+ &bitmap_rect, size_t num_copy_rects, Rect
+ *copy_rects, int dx, int dy, Rect &scroll_rect):
+ cdef Rect _bitmap_rect = bitmap_rect
+ cdef Rect _scroll_rect = scroll_rect
+ cdef int updated = mapOnPaintToTexture(
+ wini, bitmap_in, _bitmap_rect, num_copy_rects, copy_rects,
+ dx, dy, _scroll_rect,
+ self.fbo, self.width, self.height, self.needs_full_refresh, self.scroll_buffer)
+ if updated:
+ self.needs_full_refresh = 0
+ self.onPaint()
+
+ #
+ # Default Python handlers
+ # XXX This could be removed, since they are all already defined in the
+ # Python part
+ #
+
+ def onAddressBarChanged(self, newURL):
+ pass
+
+ def onStartLoading(self, newURL):
+ pass
+
+ def onLoad(self):
+ pass
+
+ def onCrashedWorker(self):
+ pass
+
+ def onCrashedPlugin(self, pluginName):
+ pass
+
+ def onProvisionalLoadError(self, url, errorCode, isMain):
+ pass
+
+ def onConsoleMessage(self, message, sourceId, line_no):
+ pass
+
+ def onScriptAlert(self, message, defaultValue, url, flags, success):
+ pass
+
+ def onNavigationRequested(self, newURL, referrer, isNewWindow):
+ pass
+
+ def onLoadingStateChanged(self, isLoading):
+ pass
+
+ def onTitleChanged(self, title):
+ pass
+
+ def onTooltipChanged(self, text):
+ pass
+
+ def onCrashed(self):
+ pass
+
+ def onUnresponsive(self):
+ pass
+
+ def onResponsive(self):
+ pass
+
+ def onCreatedWindow(self):
+ pass
+
+ def onWidgetCreated(self):
+ pass
+
+ def onWidgetResize(self):
+ pass
+
+ def onWidgetMove(self):
+ pass
+
+ def onPaint(self):
+ pass
+
+ #
+ # Public methods
+ #
+
+ def navigateTo(self, bytes url):
+ self.impl.getWindow().navigateTo(url, len(url))
+
+ def resize(self, int width, int height):
+ cdef char *tmp = <char *>realloc(self.scroll_buffer, width*(height+1)*4)
+ if tmp == NULL:
+ raise MemoryError('Unable to resize scroll_buffer')
+ self.impl.getWindow().resize(width, height)
+ self.scroll_buffer = tmp
+ self.width = width
+ self.height = height
+ self.needs_full_refresh = 1
+ self.fbo.size = width, height
+ self.fbo.texture.flip_vertical()
+
+ def focus(self):
+ self.impl.getWindow().focus()
+
+ def unfocus(self):
+ self.impl.getWindow().unfocus()
+
+ def mouseMoved(self, int xPos, int yPos):
+ self.impl.getWindow().mouseMoved(xPos, yPos)
+
+ def mouseButton(self, unsigned int buttonID, int down):
+ self.impl.getWindow().mouseButton(buttonID, down)
+
+ def mouseWheel(self, int xScroll, int yScroll):
+ self.impl.getWindow().mouseWheel(xScroll, yScroll)
+
+ def textEvent(self, bytes evt):
+ self.impl.getWindow().textEvent(<const_wchar_ptr><char *>evt, <size_t>len(evt))
+
+ def keyEvent(self, int pressed, int mods, int vk_code, int scancode):
+ self.impl.getWindow().keyEvent(pressed, mods, vk_code, scancode)
+
+ def adjustZoom(self, int mode):
+ self.impl.getWindow().adjustZoom(mode)
+
+ def refresh(self):
+ self.impl.getWindow().refresh()
+
+ def stop(self):
+ self.impl.getWindow().stop()
+
+ def cut(self):
+ self.impl.getWindow().cut()
+
+ def copy(self):
+ self.impl.getWindow().copy()
+
+ def paste(self):
+ self.impl.getWindow().paste()
+
+ def undo(self):
+ self.impl.getWindow().undo()
+
+ def redo(self):
+ self.impl.getWindow().redo()
+
+ def selectAll(self):
+ self.impl.getWindow().selectAll()
+
+ def goBack(self):
+ self.impl.getWindow().goBack()
+
+ def goForward(self):
+ self.impl.getWindow().goForward()
+
+ def canGoBack(self):
+ return self.impl.getWindow().canGoBack()
+
+ def canGoForward(self):
+ return self.impl.getWindow().canGoForward()
+
+ def setTransparent(self, bool is_trans):
+ self.impl.getWindow().setTransparent(is_trans)
+
+ property texture:
+ def __get__(self):
+ return self.fbo.texture
+
View
303 berkelium/berkelium_wrapper.h
@@ -0,0 +1,303 @@
+#ifndef __BERKELIUM_WRAPPER__
+#define __BERKELIUM_WRAPPER__
+
+#include <iostream>
+#include "berkelium/Berkelium.hpp"
+#include "berkelium/WindowDelegate.hpp"
+#include "berkelium/ScriptUtil.hpp"
+#include "berkelium/StringUtil.hpp"
+
+using namespace Berkelium;
+
+typedef void (*tp_onAddressBarChanged)(PyObject *obj, Window *win, char *newURL, int newURL_length);
+typedef void (*tp_onStartLoading)(PyObject *obj, Window *win, char *newURL, int newURL_length);
+typedef void (*tp_onLoad)(PyObject *obj, Window *win);
+typedef void (*tp_onCrashedWorker)(PyObject *obj, Window *win);
+typedef void (*tp_onCrashedPlugin)(PyObject *obj, Window *win, char *pluginName, int pluginName_length);
+typedef void (*tp_onProvisionalLoadError)(PyObject *obj, Window *win, char *url, int url_length, int errorCode, bool isMainFrame);
+typedef void (*tp_onConsoleMessage)(PyObject *obj, Window *win, char *message, int message_length, char *sourceId, int sourceId_length, int line_no);
+typedef void (*tp_onScriptAlert)(PyObject *obj, Window *win, char *message, int message_length, char *defaultValue, int defaultValue_length, char *url, int url_length, int flags, bool &success, char **value, int *value_length);
+typedef void (*tp_onNavigationRequested)(PyObject *obj, Window *win, char *newURL, int newURL_length, char *referrer, int referrer_length, bool isNewWindow, bool &cancelDefaultAction);
+typedef void (*tp_onLoadingStateChanged)(PyObject *obj, Window *win, bool isLoading);
+typedef void (*tp_onTitleChanged)(PyObject *obj, Window *win, char *title, int title_length);
+typedef void (*tp_onTooltipChanged)(PyObject *obj, Window *win, char *text, int text_length);
+typedef void (*tp_onCrashed)(PyObject *obj, Window *win);
+typedef void (*tp_onUnresponsive)(PyObject *obj, Window *win);
+typedef void (*tp_onResponsive)(PyObject *obj, Window *win);
+typedef void (*tp_onCreatedWindow)(PyObject *obj, Window *win, Window *newWindow, const Rect &initialRect);
+typedef void (*tp_onWidgetCreated)(PyObject *obj, Window *win, Widget *newWidget, int zIndex);
+typedef void (*tp_onWidgetResize)(PyObject *obj, Window *win, Widget *wid, int newWidth, int newHeight);
+typedef void (*tp_onWidgetMove)(PyObject *obj, Window *win, Widget *wid, int newX, int newY);
+typedef void (*tp_onPaint)(PyObject *obj, Window *wini, const unsigned char *bitmap_in, const Rect &bitmap_rect, size_t num_copy_rects, const Rect *copy_rects, int dx, int dy, const Rect &scroll_rect);
+
+#if 0
+typedef void (*tp_onExternalHost)(PyObject *obj, Berkelium::Window *win, char *message, int message_length, char *origin, int origin_length, char *target, int target_length);
+typedef void (*tp_onShowContextMenu)(PyObject *obj, Window *win, const ContextMenuEventArgs& args);
+typedef void (*tp_onJavascriptCallback)(PyObject *obj, Window *win, void* replyMsg, char *url, int url_length, char *funcName, int funcName_length, Script::Variant *args, size_t numArgs);
+typedef void (*tp_onRunFileChooser)(PyObject *obj, Window *win, int mode, char *title, int title_length, FileString defaultFile);
+#endif
+
+class CyWindowDelegate : public Berkelium::WindowDelegate {
+public:
+ CyWindowDelegate(PyObject *obj) {
+ this->impl_onAddressBarChanged = NULL;
+ this->impl_onStartLoading = NULL;
+ this->impl_onLoad = NULL;
+ this->impl_onCrashedWorker = NULL;
+ this->impl_onCrashedPlugin = NULL;
+ this->impl_onProvisionalLoadError = NULL;
+ this->impl_onConsoleMessage = NULL;
+ this->impl_onScriptAlert = NULL;
+ this->impl_onNavigationRequested = NULL;
+ this->impl_onLoadingStateChanged = NULL;
+ this->impl_onTitleChanged = NULL;
+ this->impl_onTooltipChanged = NULL;
+ this->impl_onCrashed = NULL;
+ this->impl_onUnresponsive = NULL;
+ this->impl_onResponsive = NULL;
+ this->impl_onCreatedWindow = NULL;
+ this->impl_onWidgetCreated = NULL;
+ this->impl_onWidgetResize = NULL;
+ this->impl_onWidgetMove = NULL;
+ this->impl_onPaint = NULL;
+#if 0
+ this->impl_onShowContextMenu = NULL;
+ this->impl_onJavascriptCallback = NULL;
+ this->impl_onRunFileChooser = NULL;
+ this->impl_onExternalHost = NULL;
+#endif
+
+ this->obj = obj;
+ Py_XINCREF(this->obj);
+ }
+
+ ~CyWindowDelegate() {
+ Py_XDECREF(this->obj);
+ }
+
+ void init(unsigned int _w, unsigned int _h, int _usetrans) {
+ Berkelium::Context *context = Berkelium::Context::create();
+ this->bk_window = Berkelium::Window::create(context);
+ delete context;
+
+ this->bk_window->setDelegate(this);
+ this->bk_window->resize(_w, _h);
+ this->bk_window->setTransparent(_usetrans);
+ }
+
+ Berkelium::Window* getWindow() {
+ return bk_window;
+ }
+
+ // implementations
+ tp_onAddressBarChanged impl_onAddressBarChanged;
+ tp_onStartLoading impl_onStartLoading;
+ tp_onLoad impl_onLoad;
+ tp_onCrashedWorker impl_onCrashedWorker;
+ tp_onCrashedPlugin impl_onCrashedPlugin;
+ tp_onProvisionalLoadError impl_onProvisionalLoadError;
+ tp_onConsoleMessage impl_onConsoleMessage;
+ tp_onScriptAlert impl_onScriptAlert;
+ tp_onNavigationRequested impl_onNavigationRequested;
+ tp_onLoadingStateChanged impl_onLoadingStateChanged;
+ tp_onTitleChanged impl_onTitleChanged;
+ tp_onTooltipChanged impl_onTooltipChanged;
+ tp_onCrashed impl_onCrashed;
+ tp_onUnresponsive impl_onUnresponsive;
+ tp_onResponsive impl_onResponsive;
+ tp_onCreatedWindow impl_onCreatedWindow;
+ tp_onWidgetCreated impl_onWidgetCreated;
+ tp_onWidgetResize impl_onWidgetResize;
+ tp_onWidgetMove impl_onWidgetMove;
+ tp_onPaint impl_onPaint;
+#if 0
+ tp_onShowContextMenu impl_onShowContextMenu;
+ tp_onJavascriptCallback impl_onJavascriptCallback;
+ tp_onRunFileChooser impl_onRunFileChooser;
+ tp_onExternalHost impl_onExternalHost;
+#endif
+
+ void onAddressBarChanged(Window *win, URLString newURL) {
+ if ( this->impl_onAddressBarChanged == NULL )
+ return;
+ this->impl_onAddressBarChanged(this->obj, win,
+ (char*)newURL.get<std::string>().c_str(), newURL.length());
+ }
+
+ void onStartLoading(Window *win, URLString newURL) {
+ if ( this->impl_onStartLoading == NULL )
+ return;
+ this->impl_onStartLoading(this->obj, win,
+ (char *)newURL.get<std::string>().c_str(), newURL.length());
+ }
+
+ void onLoad(Window *win) {
+ if ( this->impl_onLoad == NULL )
+ return;
+ this->impl_onLoad(this->obj, win);
+ }
+
+ void onCrashedWorker(Window *win) {
+ if ( this->impl_onCrashedWorker == NULL )
+ return;
+ this->impl_onCrashedWorker(this->obj, win);
+ }
+
+ void onCrashedPlugin(Window *win, WideString pluginName) {
+ if ( this->impl_onCrashedPlugin == NULL )
+ return;
+ UTF8String utf8 = WideToUTF8(pluginName);
+ this->impl_onCrashedPlugin(this->obj, win, (char *)utf8.get<std::string>().c_str(), pluginName.length());
+ }
+
+ void onProvisionalLoadError(Window *win, URLString url, int errorCode, bool isMainFrame) {
+ if ( this->impl_onProvisionalLoadError == NULL )
+ return;
+ this->impl_onProvisionalLoadError(this->obj, win,
+ (char *)url.get<std::string>().c_str(),
+ url.length(), errorCode, isMainFrame);
+ }
+
+ void onConsoleMessage(Window *win, WideString message, WideString sourceId, int line_no) {
+ if ( this->impl_onConsoleMessage == NULL )
+ return;
+ UTF8String u1 = WideToUTF8(message);
+ UTF8String u2 = WideToUTF8(sourceId);
+ this->impl_onConsoleMessage(this->obj, win,
+ (char *)u1.get<std::string>().c_str(), message.length(),
+ (char *)u2.get<std::string>().c_str(), sourceId.length(), line_no);
+ }
+
+ void onScriptAlert(Window *win, WideString message, WideString defaultValue, URLString url, int flags, bool &success, WideString &value) {
+ if ( this->impl_onScriptAlert == NULL )
+ return;
+ UTF8String u1 = WideToUTF8(message);
+ UTF8String u2 = WideToUTF8(defaultValue);
+ char *retvalue = NULL;
+ int retvalue_length = 0;
+ this->impl_onScriptAlert(this->obj, win,
+ (char *)u1.get<std::string>().c_str(), message.length(),
+ (char *)u2.get<std::string>().c_str(), defaultValue.length(),
+ (char *)url.get<std::string>().c_str(), url.length(),
+ flags, success, &retvalue, &retvalue_length);
+ if ( retvalue != NULL && retvalue_length > 0 ) {
+ UTF8String u3 = UTF8String().point_to(retvalue, retvalue_length);
+ value = UTF8ToWide(u3);
+ }
+ }
+
+ void onNavigationRequested(Window *win, URLString newURL, URLString referrer, bool isNewWindow, bool &cancelDefaultAction) {
+ if ( this->impl_onNavigationRequested == NULL )
+ return;
+ this->impl_onNavigationRequested(this->obj, win,
+ (char *)newURL.get<std::string>().c_str(), newURL.length(),
+ (char *)referrer.get<std::string>().c_str(), referrer.length(),
+ isNewWindow, cancelDefaultAction);
+ }
+
+ void onLoadingStateChanged(Window *win, bool isLoading) {
+ if ( this->impl_onLoadingStateChanged == NULL )
+ return;
+ this->impl_onLoadingStateChanged(this->obj, win, isLoading);
+ }
+
+ void onTitleChanged(Window *win, WideString title) {
+ if ( this->impl_onTitleChanged == NULL )
+ return;
+ UTF8String u1 = WideToUTF8(title);
+ this->impl_onTitleChanged(this->obj, win,
+ (char *)u1.get<std::string>().c_str(), title.length());
+ }
+
+ void onTooltipChanged(Window *win, WideString text) {
+ if ( this->impl_onTooltipChanged == NULL )
+ return;
+ UTF8String u1 = WideToUTF8(text);
+ this->impl_onTooltipChanged(this->obj, win,
+ (char *)u1.get<std::string>().c_str(), u1.length());
+ }
+
+ void onCrashed(Window *win) {
+ if ( this->impl_onCrashed == NULL )
+ return;
+ this->impl_onCrashed(this->obj, win);
+ }
+
+ void onUnresponsive(Window *win) {
+ if ( this->impl_onUnresponsive == NULL )
+ return;
+ this->impl_onUnresponsive(this->obj, win);
+ }
+
+ void onResponsive(Window *win) {
+ if ( this->impl_onResponsive == NULL )
+ return;
+ this->impl_onResponsive(this->obj, win);
+ }
+
+ void onCreatedWindow(Window *win, Window *newWindow, const Rect &initialRect) {
+ if ( this->impl_onCreatedWindow == NULL )
+ return;
+ this->impl_onCreatedWindow(this->obj, win, newWindow, initialRect);
+ }
+
+ void onWidgetCreated(Window *win, Widget *newWidget, int zIndex) {
+ if ( this->impl_onWidgetCreated == NULL )
+ return;
+ this->impl_onWidgetCreated(this->obj, win, newWidget, zIndex);
+ }
+
+ void onWidgetResize(Window *win, Widget *wid, int newWidth, int newHeight) {
+ if ( this->impl_onWidgetResize == NULL )
+ return;
+ this->impl_onWidgetResize(this->obj, win, wid, newWidth, newHeight);
+ }
+
+ void onWidgetMove(Window *win, Widget *wid, int newX, int newY) {
+ if ( this->impl_onWidgetMove == NULL )
+ return;
+ this->impl_onWidgetMove(this->obj, win, wid, newX, newY);
+ }
+
+ void onPaint(Window *wini, const unsigned char *bitmap_in, const Rect &bitmap_rect, size_t num_copy_rects, const Rect *copy_rects, int dx, int dy, const Rect &scroll_rect) {
+ if ( this->impl_onPaint == NULL )
+ return;
+ this->impl_onPaint(this->obj, wini, bitmap_in, bitmap_rect, num_copy_rects, copy_rects, dx, dy, scroll_rect);
+ }
+
+#if 0
+ void onExternalHost( Berkelium::Window *win, char *message, int message_length, char *origin, int origin_length, char *target, int target_length) {
+ if ( this->impl_onExternalHost == NULL )
+ return;
+ this->impl_onExternalHost(this->obj, win, message, message_length,
+ origin, origin_length, target, target_length);
+ }
+
+ void onShowContextMenu(Window *win, const ContextMenuEventArgs& args) {
+ if ( this->impl_onShowContextMenu == NULL )
+ return;
+ this->impl_onShowContextMenu(this->obj, win, args);
+ }
+
+ void onJavascriptCallback(Window *win, void* replyMsg, char *url, int url_length, char *funcName, int funcName_length, Script::Variant *args, size_t numArgs) {
+ if ( this->impl_onJavascriptCallback == NULL )
+ return;
+ this->impl_onJavascriptCallback(this->obj, win);
+ }
+
+ void onRunFileChooser(Window *win, int mode, char *title, int title_length, FileString defaultFile) {
+ if ( this->impl_onRunFileChooser == NULL )
+ return;
+ this->impl_onRunFileChooser(this->obj, win);
+ }
+#endif
+
+
+private:
+ // Python representation
+ PyObject *obj;
+ // The Berkelium window, i.e. our web page
+ Berkelium::Window* bk_window;
+};
+
+#endif
View
9 berkelium/demo.py
@@ -0,0 +1,9 @@
+from kivy.app import App
+from . import Webbrowser
+
+class BerkeliumBrowserApp(App):
+ def build(self):
+ return Webbrowser(url='http://kivy.org/', transparency=False)
+
+if __name__ == '__main__':
+ BerkeliumBrowserApp().run()
View
33 demo/main.py
@@ -0,0 +1,33 @@
+'''
+Berkelium extension demo
+========================
+
+Check http://github.com/tito/kivy-berkelium for more information.
+You must have berkelium-1.0 extension installed before running the demo
+
+'''
+from kivy.uix.scatter import Scatter
+from kivy.uix.floatlayout import FloatLayout
+from kivy.app import App
+
+from kivy.ext import load
+berkelium = load('berkelium', (1, 0))
+
+urls = (
+ 'http://kivy.org',
+ 'http://www.youtube.com/watch?v=QKh1Rv0PlOQ',
+)
+
+class BerkeliumBrowserApp(App):
+ def build(self):
+ root = FloatLayout()
+ size = (1024, 768)
+ for url in urls:
+ scatter = Scatter(size=size)
+ bk = berkelium.Webbrowser(url=url, size=size)
+ scatter.add_widget(bk)
+ root.add_widget(scatter)
+ return root
+
+if __name__ == '__main__':
+ BerkeliumBrowserApp().run()
View
63 setup.py
@@ -0,0 +1,63 @@
+from os import walk
+from os.path import join, sep
+from distutils.core import setup
+from distutils.cmd import Command
+from distutils.extension import Extension
+from subprocess import call
+from Cython.Distutils import build_ext
+
+
+class PackageBuild(Command):
+ description = 'Create Extension Package'
+ user_options = []
+
+ def run(self):
+ # Call this file and make a distributable .zip file that has our desired
+ # folder structure
+ call(['python', 'setup.py', 'install', '--root', 'build/zip', '--install-lib',
+ '/', '--install-platlib', '/', '--install-data', '/berkelium/data',
+ 'bdist', '--formats=zip'])
+
+ def initialize_options(self):
+ pass
+
+ def finalize_options(self):
+ pass
+
+cmdclass = {
+ 'create_package': PackageBuild,
+ 'build_ext': build_ext
+}
+
+ext = Extension(
+ 'berkelium._berkelium',
+ ['berkelium/_berkelium.pyx'],
+ include_dirs=['../include'],
+ library_dirs=['berkelium/data'],
+ libraries=['libberkelium'],
+ extra_link_args=['-Wl,-rpath=$ORIGIN/data'],
+ language='c++',
+)
+
+# list all files to compile
+data_files = []
+for root, dirnames, filenames in walk(join('berkelium', 'data')):
+ for filename in filenames:
+ fn = join(root, filename)
+ fn = sep.join(fn.split(sep)[1:])
+ data_files.append(fn)
+
+setup(
+ name='berkelium',
+ version='1.0',
+ author='Mathieu Virbel',
+ author_email='mat@kivy.org',
+ url='http://txzone.net/',
+ license='LGPL',
+ description='A webbrowser based on Berkelium project',
+ ext_modules=[ext],
+ cmdclass=cmdclass,
+ packages=['berkelium'],
+ package_dir={'berkelium': 'berkelium'},
+ package_data={'berkelium': data_files}
+)

0 comments on commit 08ea434

Please sign in to comment.
Something went wrong with that request. Please try again.