Skip to content

Commit f8286e0

Browse files
committed
Implement external message pump, still experimental (cztomczak#246).
Add new option ApplicationSettings.external_message_pump. This is experimental, actually it makes app slower, reported issue in upstream. Add cefpython.GetAppSetting() func. Show CEF Python version in unit test runner.
1 parent b51332e commit f8286e0

25 files changed

+1404
-88
lines changed

api/ApplicationSettings.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Table of contents:
1515
* [command_line_args_disabled](#command_line_args_disabled)
1616
* [context_menu](#context_menu)
1717
* [downloads_enabled](#downloads_enabled)
18+
* [external_message_pump](#external_message_pump)
1819
* [ignore_certificate_errors](#ignore_certificate_errors)
1920
* [javascript_flags](#javascript_flags)
2021
* [locale](#locale)
@@ -148,6 +149,30 @@ Default: True
148149
Downloads are handled automatically. A default `SaveAs` file dialog provided by OS is displayed. See also the [DownloadHandler](DownloadHandler.md) wiki page.
149150

150151

152+
### external_message_pump
153+
154+
(bool)
155+
Default: False
156+
157+
EXPERIMENTAL: currently this option makes browser slower, so don't use it.
158+
Reported issue in upstream, see Issue #246 for details.
159+
160+
It is recommended to use this option as a replacement for calls to
161+
cefpython.MessageLoopWork(). CEF Python will do these calls automatically
162+
using CEF's OnScheduleMessagePumpWork. This results in improved performance
163+
and resolves some bugs. See Issue #246 for more details.
164+
165+
Description from upstream CEF:
166+
> Set to true (1) to control browser process main (UI) thread message pump
167+
> scheduling via the CefBrowserProcessHandler::OnScheduleMessagePumpWork()
168+
> callback. This option is recommended for use in combination with the
169+
> CefDoMessageLoopWork() function in cases where the CEF message loop must be
170+
> integrated into an existing application message loop (see additional
171+
> comments and warnings on CefDoMessageLoopWork). Enabling this option is not
172+
> recommended for most users; leave this option disabled and use either the
173+
> CefRunMessageLoop() function or multi_threaded_message_loop if possible.
174+
175+
151176
### ignore_certificate_errors
152177

153178
(bool)

api/cefpython.md

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ source code of ExceptHook in the cefpython/src/helpers.pyx file.
9292
| key | string |
9393
| __Return__ | object |
9494

95-
Returns [ApplicationSettings](ApplicationSettings.md) option that was passed to Initialize(). Returns None if key is not found.
95+
Returns [ApplicationSettings](ApplicationSettings.md) option that was passed
96+
to Initialize(). Returns None if key is not found.
9697

9798

9899
### GetAppPath
@@ -147,8 +148,8 @@ Get the cefpython module directory. This method is useful to get full path to CE
147148

148149
| Parameter | Type |
149150
| --- | --- |
150-
| [ApplicationSettings](ApplicationSettings.md)=None | dict |
151-
| [CommandLineSwitches](CommandLineSwitches.md)=None | dict |
151+
| settings (optional) | [ApplicationSettings](ApplicationSettings.md) |
152+
| switches (optional) | [CommandLineSwitches](CommandLineSwitches.md) |
152153
| __Return__ | bool |
153154

154155
This function should be called on the main application thread (UI thread) to initialize CEF when the application is started. A call to Initialize() must have a corresponding call to Shutdown() so that CEF exits cleanly. Otherwise when application closes data (eg. storage, cookies) might not be saved to disk or the process might freeze (experienced on Windows XP).
@@ -186,8 +187,14 @@ List of threads in the Renderer process:
186187
| __Return__ | void |
187188

188189
Run the CEF message loop. Use this function instead of an application-
189-
provided message loop to get the best balance between performance and CPU usage. This function should only be called on the main application thread (UI thread) and only if cefpython.Initialize() is called with a
190-
[ApplicationSettings](ApplicationSettings.md).multi_threaded_message_loop value of false. This function will block until a quit message is received by the system.
190+
provided message loop to get the best balance between performance and
191+
CPU usage. This function should only be called on the main application
192+
thread (UI thread) and only if cefpython.Initialize() is called with a
193+
[ApplicationSettings](ApplicationSettings.md).multi_threaded_message_loop
194+
value of false. This function will block until a quit message is received
195+
by the system.
196+
197+
See also MessageLoopWork().
191198

192199

193200
### MessageLoopWork
@@ -196,8 +203,9 @@ provided message loop to get the best balance between performance and CPU usage.
196203
| --- | --- |
197204
| __Return__ | void |
198205

199-
Description from upstream CEF:
206+
Call this function in a periodic timer (eg. 10ms).
200207

208+
Description from upstream CEF:
201209
> Perform a single iteration of CEF message loop processing. This function is
202210
> provided for cases where the CEF message loop must be integrated into an
203211
> existing application message loop. Use of this function is not recommended
@@ -211,13 +219,6 @@ Description from upstream CEF:
211219
> with a CefSettings.multi_threaded_message_loop value of false. This function
212220
> will not block.
213221
214-
Alternatively you could create a periodic timer (with 10 ms interval) that calls
215-
cefpython.MessageLoopWork().
216-
217-
MessageLoopWork() is not tested on OS X and there are known issues - according to
218-
[this post](http://www.magpcss.org/ceforum/viewtopic.php?p=27124#p27124) by
219-
Marshall.
220-
221222

222223
### PostTask
223224

src/cefpython.pyx

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ from libc.string cimport memcpy
343343
# preincrement and dereference must be "as" otherwise not seen.
344344
# noinspection PyUnresolvedReferences
345345
from cython.operator cimport preincrement as preinc, dereference as deref
346+
# noinspection PyUnresolvedReferences
346347

347348
# from cython.operator cimport address as addr # Address of an c++ object?
348349

@@ -427,6 +428,8 @@ from cef_jsdialog_handler cimport *
427428
from cef_path_util cimport *
428429
from cef_drag_data cimport *
429430
from cef_image cimport *
431+
from main_message_loop cimport *
432+
from cef_scoped_ptr cimport scoped_ptr
430433

431434

432435
# -----------------------------------------------------------------------------
@@ -442,6 +445,8 @@ g_debugFile = "debug.log"
442445
g_applicationSettings = {"string_encoding": "utf-8"}
443446
g_commandLineSwitches = {}
444447

448+
cdef scoped_ptr[MainMessageLoopExternalPump] g_external_message_pump
449+
445450
# noinspection PyUnresolvedReferences
446451
cdef cpp_bool _MessageLoopWork_wasused = False
447452

@@ -567,7 +572,13 @@ cdef public int CommandLineSwitches_GetInt(const char* key) except * with gil:
567572
# Linux, then do not to run any of the CEF code until Initialize()
568573
# is called. See Issue #73 in the CEF Python Issue Tracker.
569574

570-
def Initialize(applicationSettings=None, commandLineSwitches=None):
575+
def Initialize(applicationSettings=None, commandLineSwitches=None, **kwargs):
576+
577+
# Alternative names for existing parameters
578+
if "settings" in kwargs:
579+
applicationSettings = kwargs["settings"]
580+
if "switches" in kwargs:
581+
commandLineSwitches = kwargs["switches"]
571582

572583
# Fix Issue #231 - Discovery of the "icudtl.dat" file fails on Linux.
573584
# Apply patch for all platforms just in case.
@@ -698,6 +709,11 @@ def Initialize(applicationSettings=None, commandLineSwitches=None):
698709
g_commandLineSwitches[key] = copy.deepcopy(
699710
commandLineSwitches[key])
700711

712+
# External message pump
713+
if GetAppSetting("external_message_pump")\
714+
and not g_external_message_pump.get():
715+
g_external_message_pump.Assign(MainMessageLoopExternalPump.Create())
716+
701717
Debug("CefInitialize()")
702718
cdef cpp_bool ret
703719
with nogil:
@@ -720,20 +736,24 @@ def CreateBrowserSync(windowInfo=None,
720736
browserSettings=None,
721737
navigateUrl="",
722738
**kwargs):
739+
# Alternative names for existing parameters
740+
if "window_info" in kwargs:
741+
windowInfo = kwargs["window_info"]
742+
if "settings" in kwargs:
743+
browserSettings = kwargs["settings"]
744+
if "url" in kwargs:
745+
navigateUrl = kwargs["url"]
746+
723747
Debug("CreateBrowserSync() called")
724748
assert IsThread(TID_UI), (
725749
"cefpython.CreateBrowserSync() may only be called on the UI thread")
726750

727-
if "window_info" in kwargs:
728-
windowInfo = kwargs["window_info"]
729751
if not windowInfo:
730752
windowInfo = WindowInfo()
731753
windowInfo.SetAsChild(0)
732754
elif not isinstance(windowInfo, WindowInfo):
733755
raise Exception("CreateBrowserSync() failed: windowInfo: invalid object")
734756

735-
if "settings" in kwargs:
736-
browserSettings = kwargs["settings"]
737757
if not browserSettings:
738758
browserSettings = {}
739759

@@ -743,8 +763,7 @@ def CreateBrowserSync(windowInfo=None,
743763
cdef CefWindowInfo cefWindowInfo
744764
SetCefWindowInfo(cefWindowInfo, windowInfo)
745765

746-
if "url" in kwargs:
747-
navigateUrl = kwargs["url"]
766+
748767
navigateUrl = GetNavigateUrl(navigateUrl)
749768
Debug("navigateUrl: %s" % navigateUrl)
750769
cdef CefString cefNavigateUrl
@@ -882,6 +901,11 @@ def Shutdown():
882901
for i in range(10):
883902
CefDoMessageLoopWork()
884903

904+
# Release external message pump, as in cefclient after Shutdown
905+
if g_external_message_pump.get():
906+
# Reset will set it to NULL
907+
g_external_message_pump.reset()
908+
885909

886910
def SetOsModalLoop(py_bool modalLoop):
887911
cdef cpp_bool cefModalLoop = bool(modalLoop)
@@ -903,3 +927,8 @@ cpdef object GetGlobalClientCallback(py_string name):
903927
else:
904928
return None
905929

930+
cpdef object GetAppSetting(py_string key):
931+
global g_applicationSettings
932+
if key in g_applicationSettings:
933+
return g_applicationSettings[key]
934+
return None

src/client_handler/client_handler.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,16 @@
2525

2626

2727
class ClientHandler : public CefClient,
28-
ContextMenuHandler,
29-
DisplayHandler,
30-
DownloadHandler,
31-
FocusHandler,
32-
JSDialogHandler,
33-
KeyboardHandler,
34-
LifespanHandler,
35-
LoadHandler,
36-
RenderHandler,
37-
RequestHandler
28+
public ContextMenuHandler,
29+
public DisplayHandler,
30+
public DownloadHandler,
31+
public FocusHandler,
32+
public JSDialogHandler,
33+
public KeyboardHandler,
34+
public LifespanHandler,
35+
public LoadHandler,
36+
public RenderHandler,
37+
public RequestHandler
3838
{
3939
public:
4040
ClientHandler(){}

src/extern/cef/cef_ptr.pxd

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,3 @@ cdef extern from "include/internal/cef_ptr.h":
1515
T* get()
1616
# noinspection PyUnresolvedReferences
1717
void swap(CefRefPtr[T]& r)
18-

src/extern/cef/cef_scoped_ptr.pxd

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright (c) 2016 CEF Python. See the Authors and License files.
2+
3+
cdef extern from "include/base/cef_scoped_ptr.h":
4+
cdef cppclass scoped_ptr[T]:
5+
scoped_ptr()
6+
# noinspection PyUnresolvedReferences
7+
scoped_ptr(T* p)
8+
# noinspection PyUnresolvedReferences
9+
void reset()
10+
# noinspection PyUnresolvedReferences
11+
T* get()
12+
# noinspection PyUnresolvedReferences
13+
scoped_ptr[T]& Assign "operator="(scoped_ptr[T]& p)

src/extern/cef/cef_types.pxd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ from libcpp cimport bool as cpp_bool
88
# noinspection PyUnresolvedReferences
99
from libc.stddef cimport wchar_t
1010
from cef_string cimport cef_string_t
11+
# noinspection PyUnresolvedReferences
1112
from libc.limits cimport UINT_MAX
1213

1314
cdef extern from "include/internal/cef_types.h":
@@ -50,6 +51,7 @@ cdef extern from "include/internal/cef_types.h":
5051
cef_string_t user_data_path
5152
int windowless_rendering_enabled
5253
int no_sandbox
54+
int external_message_pump
5355

5456
ctypedef struct CefBrowserSettings:
5557
cef_string_t accept_language_list

src/extern/main_message_loop.pxd

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2016 CEF Python. See the Authors and License files.
2+
3+
from cef_scoped_ptr cimport scoped_ptr
4+
5+
cdef extern from \
6+
"subprocess/main_message_loop/main_message_loop_external_pump.h":
7+
8+
cdef cppclass MainMessageLoopExternalPump:
9+
@staticmethod
10+
scoped_ptr[MainMessageLoopExternalPump] Create()

src/settings.pyx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ cdef void SetApplicationSettings(
113113
elif key == "windowless_rendering_enabled":
114114
cefAppSettings.windowless_rendering_enabled = \
115115
int(appSettings[key])
116+
elif key == "external_message_pump":
117+
cefAppSettings.external_message_pump = \
118+
int(appSettings[key])
116119
else:
117120
raise Exception("Invalid appSettings key: %s" % key)
118121

src/subprocess/Makefile-libcefpythonapp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,22 @@ CCFLAGS = -fPIC -std=gnu++11 -Wall -Werror -DBROWSER_PROCESS \
1414
$(CEF_CCFLAGS)
1515

1616
ifeq ($(UNAME_S), Linux)
17-
CPP_FILES = print_handler_gtk.cpp
17+
CPP_FILES = print_handler_gtk.cpp \
18+
main_message_loop/main_message_loop_external_pump_linux.cpp
19+
else ifeq ($(UNAME_S), Darwin)
20+
CPP_FILES = \
21+
main_message_loop/main_message_loop_external_pump_mac.mm
1822
else
1923
CPP_FILES =
2024
endif
2125

2226

2327
SRC = cefpython_app.cpp v8function_handler.cpp v8utils.cpp \
24-
javascript_callback.cpp $(CPP_FILES)
28+
javascript_callback.cpp \
29+
main_message_loop/main_message_loop.cpp \
30+
main_message_loop/main_message_loop_std.cpp \
31+
main_message_loop/main_message_loop_external_pump.cpp \
32+
$(CPP_FILES)
2533
OBJ = $(SRC:.cpp=.o)
2634
OUT = libcefpythonapp.a
2735

0 commit comments

Comments
 (0)