From 6f0d9b3af1ff4569266ca9d0cb5319e922597ff4 Mon Sep 17 00:00:00 2001 From: cztomczak Date: Sat, 17 Sep 2016 21:04:37 +0200 Subject: [PATCH] Add experimental Python 3 support (#121, #183) among others. Add hello_world.py example (#207). Update to Cython 0.24.1 (#110). Test with Python 3.4.5 (#121) on Ubuntu 14.04 by running the hello_world.py example. No other examples were run, so there still may be bugs. Expose new funcs in the cefpython module: CreateBrowser, ExceptHook, GetAppPath. Add --fast flag to compile.py for faster build time of the cefpython module. Don't use it for building official binary distrib. --- .gitignore | 1 + api/WindowInfo.md | 5 +- api/cefpython.md | 48 +++++++- examples/hello_world.py | 25 +++++ src/cefpython.pyx | 58 ++++++++-- src/compile_time_constants.pxi | 2 +- src/helpers.pyx | 92 ++++++++++++++++ src/linux/compile.py | 63 +++++++++-- src/linux/installer/__init__.py.template | 6 +- src/linux/installer/make-setup.py | 2 +- src/linux/setup/cefpython.h | 134 ++++++++++++----------- src/linux/setup/setup.py | 38 +++++-- src/string_utils.pyx | 14 ++- src/utils.pyx | 18 --- src/window_info.pyx | 6 +- 15 files changed, 382 insertions(+), 130 deletions(-) create mode 100644 examples/hello_world.py create mode 100644 src/helpers.pyx diff --git a/.gitignore b/.gitignore index 41f7f34f..e1146150 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea/ build/ +*.log \ No newline at end of file diff --git a/api/WindowInfo.md b/api/WindowInfo.md index 207018e7..319e0d6f 100644 --- a/api/WindowInfo.md +++ b/api/WindowInfo.md @@ -25,13 +25,12 @@ Table of contents: | Parameter | Type | | --- | --- | | parentWindowHandle | int | -| windowRect | list | +| windowRect (optional) | list | | __Return__ | void | Create the browser as a child window/view. -`windowRect` param is optional on Windows. On Linux & Mac it is required. -Example value: [left, top, right, bottom]. +`windowRect` example value: [left, top, right, bottom]. ### SetAsPopup diff --git a/api/cefpython.md b/api/cefpython.md index 91c603d9..931586d5 100644 --- a/api/cefpython.md +++ b/api/cefpython.md @@ -8,8 +8,11 @@ Functions in the cefpython module. Table of contents: * [Functions](#functions) + * [CreateBrowser](#createbrowsersync) * [CreateBrowserSync](#createbrowsersync) + * [ExceptHook](#excepthook) * [GetAppSetting](#getappsetting) + * [GetAppPath](#getapppath) * [GetBrowserByWindowHandle](#getbrowserbywindowhandle) * [GetCommandLineSwitch](#getcommandlineswitch) * [GetGlobalClientCallback](#getglobalclientcallback) @@ -28,17 +31,26 @@ Table of contents: ## Functions +### CreateBrowser + +Create browser asynchronously (does not return Browser object). +See `CreateBrowserSync()` for params list. + +NOTE: currently this is just an alias and actually creates browser +synchronously. The async call to CefCreateBrowser is yet TODO. + + ### CreateBrowserSync | Parameter | Type | | --- | --- | -| windowInfo | [WindowInfo](WindowInfo.md) | -| [BrowserSettings](BrowserSettings.md) | dict | -| navigateUrl | string | -| requestContext | void | +| window_info | [WindowInfo](WindowInfo.md) | +| [settings](BrowserSettings.md) | [BrowserSettings](BrowserSettings.md) | +| url | string | +| request_context | void | | __Return__ | [Browser](Browser.md) | -This function should only be called on the UI thread. The 'requestContext' parameter is not yet implemented. You must first create a window and initialize 'windowInfo' by calling WindowInfo.SetAsChild(). +This function should only be called on the UI thread. The 'request_context' parameter is not yet implemented. You must first create a window and initialize 'window_info' by calling WindowInfo.SetAsChild(). After the call to CreateBrowserSync() the page is not yet loaded, if you want your next lines of code to do some stuff on the webpage you will have to implement [LoadHandler](LoadHandler.md).OnLoadEnd() callback, see example below: @@ -52,6 +64,23 @@ browser = cefpython.CreateBrowserSync(windowInfo, settings, url) browser.SetClientCallback("OnLoadEnd", OnLoadEnd) ``` + +### ExceptHook + +| Parameter | Type | +| --- | --- | +| excType | - | +| excValue | - | +| traceObject | - | +| __Return__ | string | + +Global except hook to exit app cleanly on error. + +This hook does the following: in case of exception write it to +the "error.log" file, display it to the console, shutdown CEF +and exit application immediately by ignoring "finally" (_exit()) + + ### GetAppSetting | Parameter | Type | @@ -62,6 +91,15 @@ browser.SetClientCallback("OnLoadEnd", OnLoadEnd) Returns [ApplicationSettings](ApplicationSettings.md) option that was passed to Initialize(). Returns None if key is not found. +### GetAppPath + +| | | +| --- | --- | +| __Return__ | string | + +Get path to where application resides. + + ### GetBrowserByWindowHandle | Parameter | Type | diff --git a/examples/hello_world.py b/examples/hello_world.py new file mode 100644 index 00000000..5901f851 --- /dev/null +++ b/examples/hello_world.py @@ -0,0 +1,25 @@ +# Hello world example doesn't depend on any third party GUI framework. + +from cefpython3 import cefpython as cef +import sys + + +def main(): + """Main entry point.""" + sys.excepthook = cef.ExceptHook + cef.Initialize() + browser = cef.CreateBrowserSync(url="https://www.google.com/") + browser.SetClientHandler(ClientHandler()) + cef.MessageLoop() + cef.Shutdown() + + +class ClientHandler: + """Client handler.""" + def OnBeforeClose(self, browser): + if not browser.IsPopup(): + cef.QuitMessageLoop() + + +if __name__ == '__main__': + main() diff --git a/src/cefpython.pyx b/src/cefpython.pyx index 47333a0c..2ba302be 100644 --- a/src/cefpython.pyx +++ b/src/cefpython.pyx @@ -437,7 +437,8 @@ g_debugFile = "debug.log" # When put None here and assigned a local dictionary in Initialize(), later # while running app this global variable was garbage collected, see topic: # https://groups.google.com/d/topic/cython-users/0dw3UASh7HY/discussion -g_applicationSettings = {} +# The string_encoding key must be set early here and also in Initialize. +g_applicationSettings = {"string_encoding": "utf-8"} g_commandLineSwitches = {} # noinspection PyUnresolvedReferences @@ -504,6 +505,7 @@ include "command_line.pyx" include "app.pyx" include "javascript_dialog_handler.pyx" include "drag_data.pyx" +include "helpers.pyx" # ----------------------------------------------------------------------------- # Utility functions to provide settings to the C++ browser process code. @@ -513,7 +515,7 @@ cdef public void cefpython_GetDebugOptions( cpp_string* debugFile ) except * with gil: # Called from subprocess/cefpython_app.cpp -> CefPythonApp constructor. - cdef cpp_string cppString = g_debugFile + cdef cpp_string cppString = PyStringToChar(g_debugFile) try: debug[0] = bool(g_debug) debugFile.assign(cppString) @@ -547,7 +549,7 @@ cdef public cpp_string ApplicationSettings_GetString(const char* key cdef py_string pyKey = CharToPyString(key) cdef cpp_string cppString if pyKey in g_applicationSettings: - cppString = AnyToPyString(g_applicationSettings[pyKey]) + cppString = PyStringToChar(AnyToPyString(g_applicationSettings[pyKey])) return cppString cdef public int CommandLineSwitches_GetInt(const char* key) except * with gil: @@ -567,11 +569,11 @@ def Initialize(applicationSettings=None, commandLineSwitches=None): # Fix Issue #231 - Discovery of the "icudtl.dat" file fails on Linux. # Apply patch for all platforms just in case. cdef str py_module_dir = GetModuleDirectory() - cdef CefString module_dir - PyToCefString(py_module_dir, module_dir) - CefOverridePath(PK_DIR_EXE, module_dir)\ + cdef CefString cef_module_dir + PyToCefString(py_module_dir, cef_module_dir) + CefOverridePath(PK_DIR_EXE, cef_module_dir)\ or Debug("ERROR: CefOverridePath failed") - CefOverridePath(PK_DIR_MODULE, module_dir)\ + CefOverridePath(PK_DIR_MODULE, cef_module_dir)\ or Debug("ERROR: CefOverridePath failed") if not applicationSettings: @@ -611,6 +613,20 @@ def Initialize(applicationSettings=None, commandLineSwitches=None): if DpiAware.IsProcessDpiAware(): applicationSettings["auto_zooming"] = "system_dpi" + # Paths + cdef str module_dir = GetModuleDirectory() + if "locales_dir_path" not in applicationSettings: + if platform.system() != "Darwin": + applicationSettings["locales_dir_path"] = os.path.join( + module_dir, "/locales") + if "resources_dir_path" not in applicationSettings: + applicationSettings["resources_dir_path"] = module_dir + if platform.system() == "Darwin": + applicationSettings["resources_dir_path"] = module_dir+"/Resources" + if "browser_subprocess_path" not in applicationSettings: + applicationSettings["browser_subprocess_path"] = os.path.join( + module_dir, "subprocess") + # Mouse context menu if "context_menu" not in applicationSettings: applicationSettings["context_menu"] = {} @@ -682,22 +698,46 @@ def Initialize(applicationSettings=None, commandLineSwitches=None): if not ret: Debug("CefInitialize() failed") + + IF UNAME_SYSNAME == "Linux": + # Install by default. + WindowUtils.InstallX11ErrorHandlers() + return ret -def CreateBrowserSync(windowInfo, browserSettings, navigateUrl, requestContext=None): +def CreateBrowser(**kwargs): + """Create browser asynchronously. TODO. """ + CreateBrowserSync(**kwargs) + +def CreateBrowserSync(windowInfo=None, + browserSettings=None, + navigateUrl="", + **kwargs): Debug("CreateBrowserSync() called") assert IsThread(TID_UI), ( "cefpython.CreateBrowserSync() may only be called on the UI thread") - if not isinstance(windowInfo, WindowInfo): + if "window_info" in kwargs: + windowInfo = kwargs["window_info"] + if not windowInfo: + windowInfo = WindowInfo() + windowInfo.SetAsChild(0) + elif not isinstance(windowInfo, WindowInfo): raise Exception("CreateBrowserSync() failed: windowInfo: invalid object") + if "settings" in kwargs: + browserSettings = kwargs["settings"] + if not browserSettings: + browserSettings = {} + cdef CefBrowserSettings cefBrowserSettings SetBrowserSettings(browserSettings, &cefBrowserSettings) cdef CefWindowInfo cefWindowInfo SetCefWindowInfo(cefWindowInfo, windowInfo) + if "url" in kwargs: + navigateUrl = kwargs["url"] navigateUrl = GetNavigateUrl(navigateUrl) Debug("navigateUrl: %s" % navigateUrl) cdef CefString cefNavigateUrl diff --git a/src/compile_time_constants.pxi b/src/compile_time_constants.pxi index 35f85002..47dedaec 100644 --- a/src/compile_time_constants.pxi +++ b/src/compile_time_constants.pxi @@ -1,3 +1,3 @@ # This file was generated by setup.py DEF UNAME_SYSNAME = "Linux" -DEF PY_MAJOR_VERSION = 2 +DEF PY_MAJOR_VERSION = 3 diff --git a/src/helpers.pyx b/src/helpers.pyx new file mode 100644 index 00000000..2ed292e7 --- /dev/null +++ b/src/helpers.pyx @@ -0,0 +1,92 @@ +# Copyright (c) 2016 The CEF Python authors. All rights reserved. + +include "cefpython.pyx" + +import os +import platform +import re +import traceback +import time +import codecs + + +cpdef str GetModuleDirectory(): + """Get path to the cefpython module (so/pyd).""" + if platform.system() == "Linux" and os.getenv("CEFPYTHON3_PATH"): + # cefpython3 package __init__.py sets CEFPYTHON3_PATH. + # When cefpython3 is installed as debian package, this + # env variable is the only way of getting valid path. + return os.getenv("CEFPYTHON3_PATH") + if hasattr(sys, "frozen"): + path = os.path.dirname(sys.executable) + elif "__file__" in globals(): + path = os.path.dirname(os.path.realpath(__file__)) + else: + path = os.getcwd() + if platform.system() == "Windows": + path = re.sub(r"[/\\]+", re.escape(os.sep), path) + path = re.sub(r"[/\\]+$", "", path) + return os.path.abspath(path) + +g_GetAppPath_dir = None + +cpdef GetAppPath(file=None): + """Get application path.""" + # On Windows after downloading file and calling Browser.GoForward(), + # current working directory is set to %UserProfile%. + # Calling os.path.dirname(os.path.realpath(__file__)) + # returns for eg. "C:\Users\user\Downloads". A solution + # is to cache path on first call. + if not g_GetAppPath_dir: + if hasattr(sys, "frozen"): + adir = os.path.dirname(sys.executable) + else: + adir = os.getcwd() + global g_GetAppPath_dir + g_GetAppPath_dir = adir + # If file is None return current directory without trailing slash. + if file is None: + file = "" + # Only when relative path. + if not file.startswith("/") and not file.startswith("\\") and ( + not re.search(r"^[\w-]+:", file)): + path = g_GetAppPath_dir + os.sep + file + if platform.system() == "Windows": + path = re.sub(r"[/\\]+", re.escape(os.sep), path) + path = re.sub(r"[/\\]+$", "", path) + return path + return str(file) + + +cpdef ExceptHook(excType, excValue, traceObject): + """Global except hook to exit app cleanly on error.""" + # This hook does the following: in case of exception write it to + # the "error.log" file, display it to the console, shutdown CEF + # and exit application immediately by ignoring "finally" (_exit()). + errorMsg = "\n".join(traceback.format_exception(excType, excValue, + traceObject)) + errorFile = GetAppPath("error.log") + try: + appEncoding = g_applicationSettings["string_encoding"] + except: + appEncoding = "utf-8" + if type(errorMsg) == bytes: + errorMsg = errorMsg.decode(encoding=appEncoding, errors="replace") + try: + with codecs.open(errorFile, mode="a", encoding=appEncoding) as fp: + fp.write("\n[%s] %s\n" % ( + time.strftime("%Y-%m-%d %H:%M:%S"), errorMsg)) + except: + print("[pygtk_.py]: WARNING: failed writing to error file: %s" % ( + errorFile)) + # Convert error message to ascii before printing, otherwise + # you may get error like this: + # | UnicodeEncodeError: 'charmap' codec can't encode characters + errorMsg = errorMsg.encode("ascii", errors="replace") + errorMsg = errorMsg.decode("ascii", errors="replace") + print("\n"+errorMsg+"\n") + QuitMessageLoop() + Shutdown() + # noinspection PyProtectedMember + os._exit(1) + diff --git a/src/linux/compile.py b/src/linux/compile.py index 86f642d3..7ca4c1d1 100644 --- a/src/linux/compile.py +++ b/src/linux/compile.py @@ -1,3 +1,17 @@ +""" +Build the cefpython module, install package and run example. + +Usage: + compile.py VERSION [--debug] [--fast] + +Options: + VERSION Version in format xx.xx + --debug Debug mode + --fast Fast mode, don't delete C++ .o .a files, nor the setup/build/ + directory, and disable optimization flags when building + the so/pyd module. +""" + import sys import os import glob @@ -6,6 +20,14 @@ import platform import re +# raw_input() was renamed to input() in Python 3 +try: + # noinspection PyUnresolvedReferences + # noinspection PyShadowingBuiltins + input = raw_input +except NameError: + pass + # This will not show "Segmentation fault" error message: # | subprocess.call(["python", "./wxpython.py"]) # You need to call it with shell=True for this kind of @@ -26,6 +48,14 @@ else: DEBUG = False +if len(sys.argv) > 1 and "--fast" in sys.argv: + # Fast mode doesn't delete C++ .o .a files. + # Fast mode also disables optimization flags in setup/setup.py . + FAST = True + print("FAST mode On") +else: + FAST = False + if len(sys.argv) > 1 and re.search(r"^\d+\.\d+$", sys.argv[1]): VERSION = sys.argv[1] else: @@ -52,36 +82,40 @@ # make should succeed. os.chdir("./../cpp_utils/") -subprocess.call("rm -f *.o *.a", shell=True) +if not FAST: + subprocess.call("rm -f *.o *.a", shell=True) ret = subprocess.call("make -f Makefile", shell=True) if ret != 0: - what = raw_input("make failed, press 'y' to continue, 'n' to stop: ") + # noinspection PyUnboundLocalVariable + what = input("make failed, press 'y' to continue, 'n' to stop: ") if what != "y": sys.exit(1) os.chdir("./../client_handler/") -subprocess.call("rm -f *.o *.a", shell=True) +if not FAST: + subprocess.call("rm -f *.o *.a", shell=True) ret = subprocess.call("make -f Makefile", shell=True) if ret != 0: - what = raw_input("make failed, press 'y' to continue, 'n' to stop: ") + what = input("make failed, press 'y' to continue, 'n' to stop: ") if what != "y": sys.exit(1) os.chdir("./../subprocess/") -subprocess.call("rm -f *.o *.a", shell=True) -subprocess.call("rm -f subprocess", shell=True) +if not FAST: + subprocess.call("rm -f *.o *.a", shell=True) + subprocess.call("rm -f subprocess", shell=True) ret = subprocess.call("make -f Makefile-libcefpythonapp", shell=True) if ret != 0: - what = raw_input("make failed, press 'y' to continue, 'n' to stop: ") + what = input("make failed, press 'y' to continue, 'n' to stop: ") if what != "y": sys.exit(1) ret = subprocess.call("make -f Makefile", shell=True) if ret != 0: - what = raw_input("make failed, press 'y' to continue, 'n' to stop: ") + what = input("make failed, press 'y' to continue, 'n' to stop: ") if what != "y": sys.exit(1) subprocess_exe = "./../linux/binaries_%s/subprocess" % BITS @@ -103,7 +137,8 @@ os.remove(f) try: - shutil.rmtree("./setup/build") + if not FAST: + shutil.rmtree("./setup/build") except OSError: pass @@ -123,7 +158,7 @@ ret = subprocess.call("python-dbg setup.py build_ext --inplace" " --cython-gdb", shell=True) else: - ret = subprocess.call("python setup.py build_ext --inplace", shell=True) + ret = subprocess.call("python setup.py build_ext --inplace --fast", shell=True) if DEBUG: shutil.rmtree("./../binaries_%s/cython_debug/" % BITS, ignore_errors=True) @@ -152,5 +187,9 @@ os.chdir("./binaries_%s" % BITS) subprocess.call("cygdb . --args python-dbg wxpython.py", shell=True) else: - subprocess.call("cd ./binaries_%s && python pygtk_.py && cd .." % BITS, - shell=True) + os.system("rm -rf ./installer/cefpython3-%s-*" % (VERSION,)) + subprocess.call("cd ./installer/ && python make-setup.py --version %s" + " && cd cefpython3-%s-* && python setup.py install" + " && cd ../../../../examples/" + " && python hello_world.py && cd ../src/linux/"\ + % (VERSION,VERSION), shell=True) diff --git a/src/linux/installer/__init__.py.template b/src/linux/installer/__init__.py.template index 80cb8605..d78179d9 100644 --- a/src/linux/installer/__init__.py.template +++ b/src/linux/installer/__init__.py.template @@ -28,7 +28,11 @@ libcef_so = os.path.join(package_dir, "libcef.so") ctypes.CDLL(libcef_so, ctypes.RTLD_GLOBAL) import sys -if 0x02070000 <= sys.hexversion < 0x03000000: +if 0x02070000 <= sys.hexversion < 0x02080000: from . import cefpython_py27 as cefpython +elif 0x03040000 <= sys.hexversion < 0x03050000: + from . import cefpython_py34 as cefpython +elif 0x03050000 <= sys.hexversion < 0x03060000: + from . import cefpython_py35 as cefpython else: raise Exception("Unsupported python version: " + sys.version) diff --git a/src/linux/installer/make-setup.py b/src/linux/installer/make-setup.py index bab58023..f4cafc0f 100644 --- a/src/linux/installer/make-setup.py +++ b/src/linux/installer/make-setup.py @@ -30,7 +30,7 @@ def str_format(string, dictionary): orig_string = string - for key, value in dictionary.iteritems(): + for key, value in dictionary.items(): string = string.replace("%("+key+")s", value) if string == orig_string: raise Exception("Nothing to format") diff --git a/src/linux/setup/cefpython.h b/src/linux/setup/cefpython.h index a33bde25..8405da2b 100644 --- a/src/linux/setup/cefpython.h +++ b/src/linux/setup/cefpython.h @@ -1,8 +1,10 @@ -#ifndef __PYX_HAVE__cefpython_py27 -#define __PYX_HAVE__cefpython_py27 +/* Generated by Cython 0.24.1 */ +#ifndef __PYX_HAVE__cefpython_py34 +#define __PYX_HAVE__cefpython_py34 -#ifndef __PYX_HAVE_API__cefpython_py27 + +#ifndef __PYX_HAVE_API__cefpython_py34 #ifndef __PYX_EXTERN_C #ifdef __cplusplus @@ -12,83 +14,87 @@ #endif #endif -__PYX_EXTERN_C DL_IMPORT(void) PyBrowser_ShowDevTools(CefRefPtr); +#ifndef DL_IMPORT + #define DL_IMPORT(_T) _T +#endif + +__PYX_EXTERN_C DL_IMPORT(void) PyBrowser_ShowDevTools(CefRefPtr ); __PYX_EXTERN_C DL_IMPORT(void) PyTaskRunnable(int); -__PYX_EXTERN_C DL_IMPORT(void) V8ContextHandler_OnContextCreated(CefRefPtr, CefRefPtr); +__PYX_EXTERN_C DL_IMPORT(void) V8ContextHandler_OnContextCreated(CefRefPtr , CefRefPtr ); __PYX_EXTERN_C DL_IMPORT(void) V8ContextHandler_OnContextReleased(int, int64); -__PYX_EXTERN_C DL_IMPORT(void) V8FunctionHandler_Execute(CefRefPtr, CefRefPtr, CefString &, CefRefPtr); +__PYX_EXTERN_C DL_IMPORT(void) V8FunctionHandler_Execute(CefRefPtr , CefRefPtr , CefString &, CefRefPtr ); __PYX_EXTERN_C DL_IMPORT(void) RemovePythonCallbacksForFrame(int); -__PYX_EXTERN_C DL_IMPORT(bool) ExecutePythonCallback(CefRefPtr, int, CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(bool) LifespanHandler_OnBeforePopup(CefRefPtr, CefRefPtr, CefString const &, CefString const &, cef_window_open_disposition_t, bool, int const , CefWindowInfo &, CefRefPtr &, CefBrowserSettings &, bool *); -__PYX_EXTERN_C DL_IMPORT(void) LifespanHandler_OnAfterCreated(CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(bool) LifespanHandler_DoClose(CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(void) LifespanHandler_OnBeforeClose(CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(void) DisplayHandler_OnAddressChange(CefRefPtr, CefRefPtr, CefString const &); -__PYX_EXTERN_C DL_IMPORT(void) DisplayHandler_OnTitleChange(CefRefPtr, CefString const &); -__PYX_EXTERN_C DL_IMPORT(bool) DisplayHandler_OnTooltip(CefRefPtr, CefString &); -__PYX_EXTERN_C DL_IMPORT(void) DisplayHandler_OnStatusMessage(CefRefPtr, CefString const &); -__PYX_EXTERN_C DL_IMPORT(bool) DisplayHandler_OnConsoleMessage(CefRefPtr, CefString const &, CefString const &, int); -__PYX_EXTERN_C DL_IMPORT(bool) KeyboardHandler_OnPreKeyEvent(CefRefPtr, CefKeyEvent const &, CefEventHandle, bool *); -__PYX_EXTERN_C DL_IMPORT(bool) KeyboardHandler_OnKeyEvent(CefRefPtr, CefKeyEvent const &, CefEventHandle); -__PYX_EXTERN_C DL_IMPORT(bool) RequestHandler_OnBeforeResourceLoad(CefRefPtr, CefRefPtr, CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(bool) RequestHandler_OnBeforeBrowse(CefRefPtr, CefRefPtr, CefRefPtr, bool); -__PYX_EXTERN_C DL_IMPORT(CefRefPtr) RequestHandler_GetResourceHandler(CefRefPtr, CefRefPtr, CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(void) RequestHandler_OnResourceRedirect(CefRefPtr, CefRefPtr, CefString const &, CefString &, CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(bool) RequestHandler_GetAuthCredentials(CefRefPtr, CefRefPtr, bool, CefString const &, int, CefString const &, CefString const &, CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(bool) RequestHandler_OnQuotaRequest(CefRefPtr, CefString const &, int64, CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(CefRefPtr) RequestHandler_GetCookieManager(CefRefPtr, CefString const &); -__PYX_EXTERN_C DL_IMPORT(void) RequestHandler_OnProtocolExecution(CefRefPtr, CefString const &, bool &); -__PYX_EXTERN_C DL_IMPORT(bool) RequestHandler_OnBeforePluginLoad(CefRefPtr, CefString const &, CefString const &, CefString const &, CefRefPtr, cef_plugin_policy_t *); -__PYX_EXTERN_C DL_IMPORT(bool) RequestHandler_OnCertificateError(int, CefString const &, CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(void) RequestHandler_OnRendererProcessTerminated(CefRefPtr, cef_termination_status_t); -__PYX_EXTERN_C DL_IMPORT(void) RequestHandler_OnPluginCrashed(CefRefPtr, CefString const &); +__PYX_EXTERN_C DL_IMPORT(bool) ExecutePythonCallback(CefRefPtr , int, CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(bool) LifespanHandler_OnBeforePopup(CefRefPtr , CefRefPtr , CefString const &, CefString const &, cef_window_open_disposition_t, bool, int const , CefWindowInfo &, CefRefPtr &, CefBrowserSettings &, bool *); +__PYX_EXTERN_C DL_IMPORT(void) LifespanHandler_OnAfterCreated(CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(bool) LifespanHandler_DoClose(CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(void) LifespanHandler_OnBeforeClose(CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(void) DisplayHandler_OnAddressChange(CefRefPtr , CefRefPtr , CefString const &); +__PYX_EXTERN_C DL_IMPORT(void) DisplayHandler_OnTitleChange(CefRefPtr , CefString const &); +__PYX_EXTERN_C DL_IMPORT(bool) DisplayHandler_OnTooltip(CefRefPtr , CefString &); +__PYX_EXTERN_C DL_IMPORT(void) DisplayHandler_OnStatusMessage(CefRefPtr , CefString const &); +__PYX_EXTERN_C DL_IMPORT(bool) DisplayHandler_OnConsoleMessage(CefRefPtr , CefString const &, CefString const &, int); +__PYX_EXTERN_C DL_IMPORT(bool) KeyboardHandler_OnPreKeyEvent(CefRefPtr , CefKeyEvent const &, CefEventHandle, bool *); +__PYX_EXTERN_C DL_IMPORT(bool) KeyboardHandler_OnKeyEvent(CefRefPtr , CefKeyEvent const &, CefEventHandle); +__PYX_EXTERN_C DL_IMPORT(bool) RequestHandler_OnBeforeResourceLoad(CefRefPtr , CefRefPtr , CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(bool) RequestHandler_OnBeforeBrowse(CefRefPtr , CefRefPtr , CefRefPtr , bool); +__PYX_EXTERN_C DL_IMPORT(CefRefPtr ) RequestHandler_GetResourceHandler(CefRefPtr , CefRefPtr , CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(void) RequestHandler_OnResourceRedirect(CefRefPtr , CefRefPtr , CefString const &, CefString &, CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(bool) RequestHandler_GetAuthCredentials(CefRefPtr , CefRefPtr , bool, CefString const &, int, CefString const &, CefString const &, CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(bool) RequestHandler_OnQuotaRequest(CefRefPtr , CefString const &, int64, CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(CefRefPtr ) RequestHandler_GetCookieManager(CefRefPtr , CefString const &); +__PYX_EXTERN_C DL_IMPORT(void) RequestHandler_OnProtocolExecution(CefRefPtr , CefString const &, bool &); +__PYX_EXTERN_C DL_IMPORT(bool) RequestHandler_OnBeforePluginLoad(CefRefPtr , CefString const &, CefString const &, CefString const &, CefRefPtr , cef_plugin_policy_t *); +__PYX_EXTERN_C DL_IMPORT(bool) RequestHandler_OnCertificateError(int, CefString const &, CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(void) RequestHandler_OnRendererProcessTerminated(CefRefPtr , cef_termination_status_t); +__PYX_EXTERN_C DL_IMPORT(void) RequestHandler_OnPluginCrashed(CefRefPtr , CefString const &); __PYX_EXTERN_C DL_IMPORT(bool) CookieVisitor_Visit(int, CefCookie const &, int, int, bool &); __PYX_EXTERN_C DL_IMPORT(void) StringVisitor_Visit(int, CefString const &); -__PYX_EXTERN_C DL_IMPORT(void) LoadHandler_OnLoadingStateChange(CefRefPtr, bool, bool, bool); -__PYX_EXTERN_C DL_IMPORT(void) LoadHandler_OnLoadStart(CefRefPtr, CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(void) LoadHandler_OnLoadEnd(CefRefPtr, CefRefPtr, int); -__PYX_EXTERN_C DL_IMPORT(void) LoadHandler_OnLoadError(CefRefPtr, CefRefPtr, cef_errorcode_t, CefString const &, CefString const &); -__PYX_EXTERN_C DL_IMPORT(void) BrowserProcessHandler_OnRenderProcessThreadCreated(CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(void) BrowserProcessHandler_OnBeforeChildProcessLaunch(CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(bool) RenderHandler_GetRootScreenRect(CefRefPtr, CefRect &); -__PYX_EXTERN_C DL_IMPORT(bool) RenderHandler_GetViewRect(CefRefPtr, CefRect &); -__PYX_EXTERN_C DL_IMPORT(bool) RenderHandler_GetScreenRect(CefRefPtr, CefRect &); -__PYX_EXTERN_C DL_IMPORT(bool) RenderHandler_GetScreenPoint(CefRefPtr, int, int, int &, int &); -__PYX_EXTERN_C DL_IMPORT(bool) RenderHandler_GetScreenInfo(CefRefPtr, CefScreenInfo &); -__PYX_EXTERN_C DL_IMPORT(void) RenderHandler_OnPopupShow(CefRefPtr, bool); -__PYX_EXTERN_C DL_IMPORT(void) RenderHandler_OnPopupSize(CefRefPtr, CefRect const &); -__PYX_EXTERN_C DL_IMPORT(void) RenderHandler_OnPaint(CefRefPtr, cef_paint_element_type_t, std::vector &, void const *, int, int); -__PYX_EXTERN_C DL_IMPORT(void) RenderHandler_OnCursorChange(CefRefPtr, CefCursorHandle); -__PYX_EXTERN_C DL_IMPORT(void) RenderHandler_OnScrollOffsetChanged(CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(bool) RenderHandler_StartDragging(CefRefPtr, CefRefPtr, PY_LONG_LONG, int, int); -__PYX_EXTERN_C DL_IMPORT(void) RenderHandler_UpdateDragCursor(CefRefPtr, PY_LONG_LONG); -__PYX_EXTERN_C DL_IMPORT(bool) ResourceHandler_ProcessRequest(int, CefRefPtr, CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(void) ResourceHandler_GetResponseHeaders(int, CefRefPtr, int64 &, CefString &); -__PYX_EXTERN_C DL_IMPORT(bool) ResourceHandler_ReadResponse(int, void *, int, int &, CefRefPtr); +__PYX_EXTERN_C DL_IMPORT(void) LoadHandler_OnLoadingStateChange(CefRefPtr , bool, bool, bool); +__PYX_EXTERN_C DL_IMPORT(void) LoadHandler_OnLoadStart(CefRefPtr , CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(void) LoadHandler_OnLoadEnd(CefRefPtr , CefRefPtr , int); +__PYX_EXTERN_C DL_IMPORT(void) LoadHandler_OnLoadError(CefRefPtr , CefRefPtr , cef_errorcode_t, CefString const &, CefString const &); +__PYX_EXTERN_C DL_IMPORT(void) BrowserProcessHandler_OnRenderProcessThreadCreated(CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(void) BrowserProcessHandler_OnBeforeChildProcessLaunch(CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(bool) RenderHandler_GetRootScreenRect(CefRefPtr , CefRect &); +__PYX_EXTERN_C DL_IMPORT(bool) RenderHandler_GetViewRect(CefRefPtr , CefRect &); +__PYX_EXTERN_C DL_IMPORT(bool) RenderHandler_GetScreenRect(CefRefPtr , CefRect &); +__PYX_EXTERN_C DL_IMPORT(bool) RenderHandler_GetScreenPoint(CefRefPtr , int, int, int &, int &); +__PYX_EXTERN_C DL_IMPORT(bool) RenderHandler_GetScreenInfo(CefRefPtr , CefScreenInfo &); +__PYX_EXTERN_C DL_IMPORT(void) RenderHandler_OnPopupShow(CefRefPtr , bool); +__PYX_EXTERN_C DL_IMPORT(void) RenderHandler_OnPopupSize(CefRefPtr , CefRect const &); +__PYX_EXTERN_C DL_IMPORT(void) RenderHandler_OnPaint(CefRefPtr , cef_paint_element_type_t, std::vector &, void const *, int, int); +__PYX_EXTERN_C DL_IMPORT(void) RenderHandler_OnCursorChange(CefRefPtr , CefCursorHandle); +__PYX_EXTERN_C DL_IMPORT(void) RenderHandler_OnScrollOffsetChanged(CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(bool) RenderHandler_StartDragging(CefRefPtr , CefRefPtr , PY_LONG_LONG, int, int); +__PYX_EXTERN_C DL_IMPORT(void) RenderHandler_UpdateDragCursor(CefRefPtr , PY_LONG_LONG); +__PYX_EXTERN_C DL_IMPORT(bool) ResourceHandler_ProcessRequest(int, CefRefPtr , CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(void) ResourceHandler_GetResponseHeaders(int, CefRefPtr , int64 &, CefString &); +__PYX_EXTERN_C DL_IMPORT(bool) ResourceHandler_ReadResponse(int, void *, int, int &, CefRefPtr ); __PYX_EXTERN_C DL_IMPORT(bool) ResourceHandler_CanGetCookie(int, CefCookie const &); __PYX_EXTERN_C DL_IMPORT(bool) ResourceHandler_CanSetCookie(int, CefCookie const &); __PYX_EXTERN_C DL_IMPORT(void) ResourceHandler_Cancel(int); -__PYX_EXTERN_C DL_IMPORT(void) WebRequestClient_OnUploadProgress(int, CefRefPtr, int64, int64); -__PYX_EXTERN_C DL_IMPORT(void) WebRequestClient_OnDownloadProgress(int, CefRefPtr, int64, int64); -__PYX_EXTERN_C DL_IMPORT(void) WebRequestClient_OnDownloadData(int, CefRefPtr, void const *, size_t); -__PYX_EXTERN_C DL_IMPORT(void) WebRequestClient_OnRequestComplete(int, CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(void) App_OnBeforeCommandLineProcessing_BrowserProcess(CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(bool) JavascriptDialogHandler_OnJavascriptDialog(CefRefPtr, CefString const &, cef_jsdialog_type_t, CefString const &, CefString const &, CefRefPtr, bool &); -__PYX_EXTERN_C DL_IMPORT(bool) JavascriptDialogHandler_OnBeforeUnloadJavascriptDialog(CefRefPtr, CefString const &, bool, CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(void) JavascriptDialogHandler_OnResetJavascriptDialogState(CefRefPtr); -__PYX_EXTERN_C DL_IMPORT(void) JavascriptDialogHandler_OnJavascriptDialogClosed(CefRefPtr); +__PYX_EXTERN_C DL_IMPORT(void) WebRequestClient_OnUploadProgress(int, CefRefPtr , int64, int64); +__PYX_EXTERN_C DL_IMPORT(void) WebRequestClient_OnDownloadProgress(int, CefRefPtr , int64, int64); +__PYX_EXTERN_C DL_IMPORT(void) WebRequestClient_OnDownloadData(int, CefRefPtr , void const *, size_t); +__PYX_EXTERN_C DL_IMPORT(void) WebRequestClient_OnRequestComplete(int, CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(void) App_OnBeforeCommandLineProcessing_BrowserProcess(CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(bool) JavascriptDialogHandler_OnJavascriptDialog(CefRefPtr , CefString const &, cef_jsdialog_type_t, CefString const &, CefString const &, CefRefPtr , bool &); +__PYX_EXTERN_C DL_IMPORT(bool) JavascriptDialogHandler_OnBeforeUnloadJavascriptDialog(CefRefPtr , CefString const &, bool, CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(void) JavascriptDialogHandler_OnResetJavascriptDialogState(CefRefPtr ); +__PYX_EXTERN_C DL_IMPORT(void) JavascriptDialogHandler_OnJavascriptDialogClosed(CefRefPtr ); __PYX_EXTERN_C DL_IMPORT(void) cefpython_GetDebugOptions(bool *, std::string *); __PYX_EXTERN_C DL_IMPORT(bool) ApplicationSettings_GetBool(char const *); __PYX_EXTERN_C DL_IMPORT(bool) ApplicationSettings_GetBoolFromDict(char const *, char const *); __PYX_EXTERN_C DL_IMPORT(std::string) ApplicationSettings_GetString(char const *); __PYX_EXTERN_C DL_IMPORT(int) CommandLineSwitches_GetInt(char const *); -#endif /* !__PYX_HAVE_API__cefpython_py27 */ +#endif /* !__PYX_HAVE_API__cefpython_py34 */ #if PY_MAJOR_VERSION < 3 -PyMODINIT_FUNC initcefpython_py27(void); +PyMODINIT_FUNC initcefpython_py34(void); #else -PyMODINIT_FUNC PyInit_cefpython_py27(void); +PyMODINIT_FUNC PyInit_cefpython_py34(void); #endif -#endif /* !__PYX_HAVE__cefpython_py27 */ +#endif /* !__PYX_HAVE__cefpython_py34 */ diff --git a/src/linux/setup/setup.py b/src/linux/setup/setup.py index a52cd573..06117075 100644 --- a/src/linux/setup/setup.py +++ b/src/linux/setup/setup.py @@ -9,6 +9,24 @@ print("Cython version: %s" % Cython.__version__) +if len(sys.argv) > 1 and "--fast" in sys.argv: + sys.argv.remove("--fast") + # Fast mode disables optimization flags + FAST = True + print("FAST mode On") + COMPILE_OPTIMIZE_FLAGS = ['-flto', '-std=gnu++11'] + LINK_OPTIMIZE_FLAGS = ['-flto'] +else: + FAST = False + # Fix "ImportError ... undefined symbol ..." caused by CEF's include/base/ + # headers by adding the -flto flag (Issue #230). Unfortunately -flto + # prolongs compilation time significantly. + # More on the other flags: https://stackoverflow.com/questions/6687630/ + COMPILE_OPTIMIZE_FLAGS = ['-flto', '-fdata-sections', '-ffunction-sections', + '-std=gnu++11'] + LINK_OPTIMIZE_FLAGS = ['-flto', '-Wl,--gc-sections'] + + BITS = platform.architecture()[0] assert (BITS == "32bit" or BITS == "64bit") @@ -18,6 +36,7 @@ # Python version string: "27" or "32". PYTHON_VERSION = str(sys.version_info.major) + str(sys.version_info.minor) + def CompileTimeConstants(): print("Generating: compile_time_constants.pxi") @@ -75,7 +94,7 @@ def CompileTimeConstants(): library_dirs=[ r'./lib_%s' % BITS, r'./../../client_handler/', - r'./../../subprocess/', # libcefpythonapp + r'./../../subprocess/', # libcefpythonapp r'./../../cpp_utils/' ], @@ -97,22 +116,17 @@ def CompileTimeConstants(): # running scripts from the same directory that libcef.so resides in. # runtime_library_dirs=[ # './' - #], + # ], - # Fix "ImportError ... undefined symbol ..." caused by CEF's include/base/ - # headers by adding the -flto flag (Issue #230). Unfortunately -flto - # prolongs compilation time significantly. - # More on the other flags: https://stackoverflow.com/questions/6687630/ - extra_compile_args=['-flto', '-fdata-sections', '-ffunction-sections', - '-std=gnu++11'], - extra_link_args=['-flto', '-Wl,--gc-sections'], + extra_compile_args=COMPILE_OPTIMIZE_FLAGS, + extra_link_args=LINK_OPTIMIZE_FLAGS, # Defining macros: # define_macros = [("UNICODE","1"), ("_UNICODE","1"), ] )] setup( - name = 'cefpython_py%s' % PYTHON_VERSION, - cmdclass = {'build_ext': build_ext}, - ext_modules = ext_modules + name='cefpython_py%s' % PYTHON_VERSION, + cmdclass={'build_ext': build_ext}, + ext_modules=ext_modules ) diff --git a/src/string_utils.pyx b/src/string_utils.pyx index a3784ec6..9ec6364b 100644 --- a/src/string_utils.pyx +++ b/src/string_utils.pyx @@ -44,6 +44,19 @@ cdef py_string CharToPyString( g_applicationSettings["string_encoding"], errors=BYTES_DECODE_ERRORS)) + +cdef bytes PyStringToChar(py_string pyString): + if PY_MAJOR_VERSION < 3: + return pyString + else: + # The unicode type is not defined in Python 3. + if type(pyString) == str: + pyString = (pyString.encode( + g_applicationSettings["string_encoding"], + errors=UNICODE_ENCODE_ERRORS)) + return pyString + + # Not used anywhere so commented out. # --- # cdef py_string CppToPyString( @@ -123,7 +136,6 @@ cdef void PyToCefStringPointer( pyString = (pyString.encode( g_applicationSettings["string_encoding"], errors=UNICODE_ENCODE_ERRORS)) - cdef cpp_string cppString = pyString # When used cefString.FromASCII(), a DCHECK failed # when passed a unicode string. diff --git a/src/utils.pyx b/src/utils.pyx index d30e93f2..9051a751 100644 --- a/src/utils.pyx +++ b/src/utils.pyx @@ -101,24 +101,6 @@ cpdef str GetNavigateUrl(py_string url): return str(url) -cpdef str GetModuleDirectory(): - import re, os, platform - if platform.system() == "Linux" and os.getenv("CEFPYTHON3_PATH"): - # cefpython3 package __init__.py sets CEFPYTHON3_PATH. - # When cefpython3 is installed as debian package, this - # env variable is the only way of getting valid path. - return os.getenv("CEFPYTHON3_PATH") - if hasattr(sys, "frozen"): - path = os.path.dirname(sys.executable) - elif "__file__" in globals(): - path = os.path.dirname(os.path.realpath(__file__)) - else: - path = os.getcwd() - if platform.system() == "Windows": - path = re.sub(r"[/\\]+", re.escape(os.sep), path) - path = re.sub(r"[/\\]+$", "", path) - return os.path.abspath(path) - cpdef py_bool IsFunctionOrMethod(object valueType): if (valueType == types.FunctionType or valueType == types.MethodType diff --git a/src/window_info.pyx b/src/window_info.pyx index 18a3d3ce..eb9b5fb1 100644 --- a/src/window_info.pyx +++ b/src/window_info.pyx @@ -15,7 +15,8 @@ cdef void SetCefWindowInfo( # some things like context menus and plugins may not display correctly. if windowInfo.windowType != "offscreen": if not windowInfo.parentWindowHandle: - raise Exception("WindowInfo: parentWindowHandle is not set") + # raise Exception("WindowInfo: parentWindowHandle is not set") + pass IF UNAME_SYSNAME == "Windows": cdef RECT windowRect @@ -87,8 +88,7 @@ cdef class WindowInfo: self.parentWindowHandle = parentWindowHandle IF UNAME_SYSNAME == "Darwin" or UNAME_SYSNAME == "Linux": if not windowRect: - raise Exception("WindowInfo.SetAsChild() failed: " - "windowRect is required") + windowRect = [0,0,0,0] if windowRect: if type(windowRect) == list and len(windowRect) == 4: self.windowRect = [windowRect[0], windowRect[1],