Skip to content

Commit 638507a

Browse files
committed
Update Kivy: improve performance, add mouse scrolling and fix mouse move.
Improve performance (Issue cztomczak#240): * Use Chromium flags same as in upstream cefclient for better performance * Call message loop work in faster 6ms intervals by using a small trick. By default when scheduling after the next frame intervals are 13ms. Added popup that informs about DevTools window not working when the 'enable-begin-frame-scheduling' switch is added (for OSR performance). This will be fixed in the future when native popup widgets are implemented, see Issue cztomczak#69. Add support for mouse scrolling in on_touch_up(). Fix mouse move (Issue cztomczak#243) - not all Kivy window providers have the "mouse_pos" attribute. You can now start Kivy example with a custom url by using providing url in args, eg.: python kivy_.py http://myurl.com/ . Update build instructions - change required packages.
1 parent 779e2d5 commit 638507a

File tree

4 files changed

+130
-60
lines changed

4 files changed

+130
-60
lines changed

docs/Build-instructions.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ binaries from GH releases.
3737
2) Download [ninja](http://martine.github.io/ninja/) 1.7.1 or later
3838
and copy it to /usr/bin and chmod 755.
3939

40-
3) Install packages: `sudo apt-get install python-dev cmake g++`
40+
3) Install packages: `sudo apt-get install python-dev cmake g++ libgtk2.0-dev`
4141

4242
4) Install python dependencies by executing:
4343
`cd cefpython/tools/ && pip install -r requirements.txt`
@@ -92,7 +92,7 @@ __Windows__
9292

9393
__Linux__
9494

95-
* Install packages: `sudo apt-get install python-dev cmake g++`
95+
* Install packages: `sudo apt-get install python-dev cmake g++ libgtk2.0-dev`
9696
* If building CEF from sources:
9797
* Official binaries are built on Ubuntu 14.04 (cmake 2.8.12, g++ 4.8.4)
9898
* Download [ninja](http://martine.github.io/ninja/) 1.7.1 or later
@@ -113,7 +113,7 @@ __Linux__
113113
[cef/#1804](https://bitbucket.org/chromiumembedded/cef/issues/1804).
114114
* If using prebuilt binaries from Spotify automated builds and want to
115115
build cefclient/cefsimple you need to install these packages:
116-
`sudo apt-get install libgtk2.0-dev libgtkglext1-dev`
116+
`sudo apt-get install libgtkglext1-dev`
117117

118118

119119
__All platforms__

src/linux/binaries_64bit/kivy_.py

Lines changed: 123 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@
3737
pygtk.require('2.0')
3838
import gtk
3939

40+
import kivy
4041
from kivy.app import App
42+
from kivy.uix.button import Button
43+
from kivy.uix.popup import Popup
44+
from kivy.uix.label import Label
4145
from kivy.uix.widget import Widget
4246
from kivy.graphics import Color, Rectangle, GraphicException
4347
from kivy.clock import Clock
@@ -47,40 +51,30 @@
4751
from kivy.uix.boxlayout import BoxLayout
4852
from kivy.base import EventLoop
4953

50-
####Kivy APP ####
51-
Builder.load_string("""
52-
53-
<BrowserLayout>:
54-
orientation: 'vertical'
55-
BoxLayout:
56-
size_hint_y: None
57-
height: 40
58-
Button:
59-
text: "Back"
60-
on_press: browser.go_back()
61-
Button:
62-
text: "Forward"
63-
on_press: browser.go_forward()
64-
Button:
65-
text: "Reload"
66-
on_press: browser.reload()
67-
Button:
68-
text: "Print"
69-
on_press: browser.print_page()
70-
Button:
71-
text: "DevTools"
72-
on_press: browser.devtools()
73-
CefBrowser:
74-
id: browser
75-
76-
""")
77-
54+
# Global variables
55+
g_switches = None
7856

7957

8058
class BrowserLayout(BoxLayout):
59+
browser = None
8160

8261
def __init__(self, **kwargs):
8362
super(BrowserLayout, self).__init__(**kwargs)
63+
self.orientation = "vertical"
64+
65+
browser = CefBrowser(id="browser")
66+
67+
layout = BoxLayout()
68+
layout.size_hint_y = None
69+
layout.height = 40
70+
layout.add_widget(Button(text="Back", on_press=browser.go_back))
71+
layout.add_widget(Button(text="Forward", on_press=browser.go_forward))
72+
layout.add_widget(Button(text="Reload", on_press=browser.reload))
73+
layout.add_widget(Button(text="Print", on_press=browser.print_page))
74+
layout.add_widget(Button(text="DevTools", on_press=browser.devtools))
75+
76+
self.add_widget(layout)
77+
self.add_widget(browser)
8478

8579

8680

@@ -97,6 +91,9 @@ class CefBrowser(Widget):
9791
def __init__(self, start_url='https://www.google.com/', **kwargs):
9892
super(CefBrowser, self).__init__(**kwargs)
9993

94+
for arg in sys.argv:
95+
if arg.startswith("http://") or arg.startswith("https://"):
96+
start_url = arg
10097
self.start_url = start_url
10198

10299
#Workaround for flexible size:
@@ -128,12 +125,29 @@ def size_changed(self, *kwargs):
128125
self.browser.WasResized()
129126

130127

131-
def _cef_mes(self, *kwargs):
128+
count = 0
129+
def _message_loop_work(self, *kwargs):
132130
'''Get called every frame.
133131
'''
132+
self.count += 1
133+
# print(self.count)
134134
cefpython.MessageLoopWork()
135135
self.on_mouse_move_emulate()
136136

137+
# From Kivy docs:
138+
# Clock.schedule_once(my_callback, 0) # call after the next frame
139+
# Clock.schedule_once(my_callback, -1) # call before the next frame
140+
141+
# When scheduling "after the next frame" Kivy calls _message_loop_work
142+
# in about 13ms intervals. We use a small trick to make this 6ms
143+
# interval by scheduling it alternately before and after the next
144+
# frame. This gives better User Experience when scrolling.
145+
# See Issue #240 for more details on OSR performance.
146+
if self.count % 2 == 0:
147+
Clock.schedule_once(self._message_loop_work, 0)
148+
else:
149+
Clock.schedule_once(self._message_loop_work, -1)
150+
137151

138152
def _update_rect(self, *kwargs):
139153
'''Get called whenever the texture got updated.
@@ -153,7 +167,7 @@ def start_cef(self):
153167
Color(1, 1, 1)
154168
self.rect = Rectangle(size=self.size, texture=self.texture)
155169

156-
#configure cef
170+
# Configure CEF
157171
settings = {
158172
"debug": True, # cefpython debug messages in console and in log_file
159173
"log_severity": cefpython.LOGSEVERITY_INFO,
@@ -169,26 +183,41 @@ def start_cef(self):
169183
"enabled": False,
170184
},
171185
}
186+
switches = {
187+
# Tweaking OSR performance by setting the same Chromium flags
188+
# as in upstream cefclient (# Issue #240).
189+
"disable-surfaces": "",
190+
"disable-gpu": "",
191+
"disable-gpu-compositing": "",
192+
"enable-begin-frame-scheduling": "",
193+
}
194+
browserSettings = {
195+
# Tweaking OSR performance (Issue #240)
196+
"windowless_frame_rate": 60
197+
}
172198

173-
#start idle
174-
Clock.schedule_interval(self._cef_mes, 0)
175-
176-
#init CEF
199+
# Initialize CEF
177200
cefpython.WindowUtils.InstallX11ErrorHandlers()
178-
cefpython.Initialize(settings)
201+
202+
global g_switches
203+
g_switches = switches
204+
cefpython.Initialize(settings, switches)
205+
206+
# Start idle - CEF message loop work.
207+
Clock.schedule_once(self._message_loop_work, 0)
179208

180209
# CEF needs a valid window handle passed to SetAsOffscreen()
181210
# for Printing to work. There is no API to get Kivy's window
182211
# handle so creating a dummy hidden Window using GTK.
183212
gtkwin = gtk.Window()
184213
gtkwin.realize()
185214

186-
#WindowInfo offscreen flag
215+
# WindowInfo offscreen flag
187216
windowInfo = cefpython.WindowInfo()
188217
windowInfo.SetAsOffscreen(gtkwin.window.xid)
189218

190-
#Create Broswer and naviagte to empty page <= OnPaint won't get called yet
191-
browserSettings = {}
219+
# Create Broswer and naviagte to empty page <= OnPaint won't get
220+
# called yet
192221
# The render handler callbacks are not yet set, thus an
193222
# error report will be thrown in the console (when release
194223
# DCHECKS are enabled), however don't worry, it is harmless.
@@ -201,17 +230,19 @@ def start_cef(self):
201230
# --
202231
# Do not use "about:blank" as navigateUrl - this will cause
203232
# the GoBack() and GoForward() methods to not work.
233+
#
204234
self.browser = cefpython.CreateBrowserSync(windowInfo, browserSettings,
205235
navigateUrl=self.start_url)
206236

207-
#set focus
237+
# Set focus
208238
self.browser.SendFocusEvent(True)
209239

210240
self._client_handler = ClientHandler(self)
211241
self.browser.SetClientHandler(self._client_handler)
212242
self.set_js_bindings()
213243

214-
#Call WasResized() => force cef to call GetViewRect() and OnPaint afterwards
244+
# Call WasResized() => force cef to call GetViewRect() and OnPaint
245+
# afterwards
215246
self.browser.WasResized()
216247

217248
# The browserWidget instance is required in OnLoadingStateChange().
@@ -493,33 +524,53 @@ def get_windows_key_code(self, kivycode):
493524
return cefcode
494525

495526

496-
def go_forward(self):
527+
def go_forward(self, *kwargs):
497528
'''Going to forward in browser history
498529
'''
499530
print "go forward"
500531
self.browser.GoForward()
501532

502533

503-
def go_back(self):
534+
def go_back(self, *kwargs):
504535
'''Going back in browser history
505536
'''
506537
print "go back"
507538
self.browser.GoBack()
508539

509540

510-
def reload(self):
541+
def reload(self, *kwargs):
511542
self.browser.Reload()
512543

513544

514-
def print_page(self):
545+
def print_page(self, *kwargs):
515546
self.browser.Print()
516547

517548

518-
def devtools(self):
519-
self.browser.ShowDevTools()
549+
def devtools(self, *kwargs):
550+
# ShowDevTools doesn't work with the 'enable-begin-frame-scheduling'
551+
# switch. This might be fixed by implementing native popup widgets,
552+
# see Issue #69. The solution for now is to remove that switch,
553+
# but this will impact performance.
554+
if "enable-begin-frame-scheduling" in g_switches:
555+
text = ("To enable DevTools you need to remove the\n"
556+
"'enable-begin-frame-scheduling' switch that\n"
557+
"is passed to cefpython.Initialize(). See also\n"
558+
"comment in CefBrowser.devtools().")
559+
popup = Popup(title='DevTools INFO', content=Label(text=text),
560+
size_hint=(None, None), size=(400, 400))
561+
popup.open()
562+
563+
else:
564+
self.browser.ShowDevTools()
520565

521566

522567
def on_touch_down(self, touch, *kwargs):
568+
# Mouse scrolling
569+
if "button" in touch.profile:
570+
if touch.button in ["scrollup", "scrolldown"]:
571+
# Handled in on_touch_up()
572+
return
573+
523574
if not self.collide_point(*touch.pos):
524575
return
525576
touch.grab(self)
@@ -542,8 +593,32 @@ def on_touch_down(self, touch, *kwargs):
542593
cefpython.MOUSEBUTTON_LEFT,
543594
mouseUp=False, clickCount=1)
544595

596+
597+
def on_touch_up(self, touch, *kwargs):
598+
# Mouse scrolling
599+
if "button" in touch.profile:
600+
if touch.button in ["scrollup", "scrolldown"]:
601+
x = touch.x
602+
y = self.height-touch.pos[1]
603+
deltaY = -40 if "scrollup" == touch.button else 40
604+
self.browser.SendMouseWheelEvent(x, y, deltaX=0, deltaY=deltaY)
605+
return
606+
607+
if touch.grab_current is not self:
608+
return
609+
610+
y = self.height-touch.pos[1]
611+
self.browser.SendMouseClickEvent(touch.x, y, cefpython.MOUSEBUTTON_LEFT,
612+
mouseUp=True, clickCount=1)
613+
touch.ungrab(self)
614+
615+
545616
last_mouse_pos = None
546617
def on_mouse_move_emulate(self):
618+
if not hasattr(self.get_root_window(), "mouse_pos"):
619+
# Not all Kivy window providers have the "mouse_pos" attribute.
620+
# WindowPygame does have (kivy/kivy#325).
621+
return
547622
mouse_pos = self.get_root_window().mouse_pos
548623
if self.last_mouse_pos == mouse_pos:
549624
return
@@ -566,15 +641,6 @@ def on_touch_move(self, touch, *kwargs):
566641
modifiers=modifiers)
567642

568643

569-
def on_touch_up(self, touch, *kwargs):
570-
if touch.grab_current is not self:
571-
return
572-
573-
y = self.height-touch.pos[1]
574-
self.browser.SendMouseClickEvent(touch.x, y, cefpython.MOUSEBUTTON_LEFT,
575-
mouseUp=True, clickCount=1)
576-
touch.ungrab(self)
577-
578644

579645
class ClientHandler:
580646

@@ -736,10 +802,11 @@ def OnBeforeUnloadJavascriptDialog(self, browser, messageText, isReload,
736802
return True
737803

738804

805+
739806
if __name__ == '__main__':
807+
740808
class CefBrowserApp(App):
741809
def build(self):
742810
return BrowserLayout()
743811
CefBrowserApp().run()
744-
745812
cefpython.Shutdown()

src/linux/binaries_64bit/pygtk_.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,12 @@ def CreateMenu(self):
155155

156156
return menubar
157157

158+
# count = 0
158159
def OnTimer(self):
159160
if self.exiting:
160161
return False
162+
# self.count += 1
163+
# print(self.count)
161164
cefpython.MessageLoopWork()
162165
return True
163166

tools/automate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ def build_cef_projects():
281281
else:
282282
files = glob.glob(os.path.join(Options.binary_distrib,
283283
"cef_binary_*_"+OS_POSTFIX2))
284-
assert len(files) == 1, "More than one cef binary dir found"
284+
assert len(files) == 1, "Error finding binary distrib"
285285
cef_binary = files[0]
286286
assert os.path.exists(cef_binary)
287287
Options.cef_binary = cef_binary

0 commit comments

Comments
 (0)