diff --git a/Authors b/Authors index b4c55d204..b44b24e68 100644 --- a/Authors +++ b/Authors @@ -19,3 +19,4 @@ Contributors: Dónal McMullan nobodyguy Elliot Woods + Bryan Koroleski diff --git a/README.md b/README.md index 747381bfe..b85f34c6b 100644 --- a/README.md +++ b/README.md @@ -2,28 +2,18 @@ Table of contents: * [Introduction](#introduction) -* [Latest releases sponsored by](#latest-releases-sponsored-by) - * [Thanks to all sponsors](#thanks-to-all-sponsors) * [Install](#install) -* [Tutorial](#tutorial) * [Examples](#examples) * [Support](#support) -* [Releases](#releases) - * [Next release](#next-release) - * [Latest release](#latest-release) - * [v49 release (WinXP/Vista)](#v49-release-winxpvista) - * [v31 release (old systems)](#v31-release-old-systems) * [Support development](#support-development) - * [Thanks to all](#thanks-to-all) -* [Seeking new sponsors](#seeking-new-sponsors) -* [Other READMEs](#other-readmes) -* [Quick links](#quick-links) +* [Seeking sponsors](#seeking-sponsors) +* [API](#api) ## Introduction CEF Python is an open source project founded by -[Czarek Tomczak](https://drive.google.com/file/d/17xmoT5Z_zTHkVclqPzrs2aAV64Uiu7fh/view) +[Czarek Tomczak](https://www.linkedin.com/in/czarektomczak/) in 2012 to provide Python bindings for the [Chromium Embedded Framework](https://bitbucket.org/chromiumembedded/cef) (CEF). The Chromium project focuses mainly on Google Chrome application @@ -49,40 +39,76 @@ frameworks such as PyQt, wxPython, PyGTK, PyGObject, Tkinter, Kivy, Panda3D, PyGame, PyOpenGL, PyWin32, PySide and PySDL2. -## Latest releases sponsored by +## Install + +Command to install with pip: - -
+``` +pip install cefpython3==66.1 +``` -

- - - -

+Hosted at [pypi/cefpython3](https://pypi.python.org/pypi/cefpython3). On Linux pip 8.1+ is required. -Many Thanks to Lampix for sponsoring the -[v66 release](../../releases/tag/v66.0). Lampix is the first hardware -and software solution that turns any surface into a smart, augmented reality -or interactive surface. Please visit their website: -Lampix.com +You can also download packages for offline installation available on the [GitHub Releases](../../releases) pages. + +Below is a table with supported platforms, python versions and architectures. + +OS | Py2 | Py3 | 32bit | 64bit | Requirements +--- | --- | --- | --- | --- | --- +Windows | 2.7 | 3.4 / 3.5 / 3.6 / 3.7 / 3.8 / 3.9 | Yes | Yes | Windows 7+ (Note that Python 3.9 supports Windows 8.1+) +Linux | 2.7 | 3.4 / 3.5 / 3.6 / 3.7 | Yes | Yes | Debian 8+, Ubuntu 14.04+,
Fedora 24+, openSUSE 13.3+ +Mac | 2.7 | 3.4 / 3.5 / 3.6 / 3.7 | No | Yes | MacOS 10.9+ -
-

- - - -

+## Examples -Many thanks to Fivestars for sponsoring the -[v49 legacy release](../../releases/tag/v49.0). Fivestars helps local -communities thrive by empowering small -businesses with cutting edge marketing technology. Please visit their website: -Fivestars.com +- [Tutorial](docs/Tutorial.md) +- [All examples](examples/README-examples.md) +- [Snippets](examples/snippets/README-snippets.md) +- [PyInstaller packager](examples/pyinstaller/README-pyinstaller.md) -
-### Thanks to all sponsors +## Support + +- Ask questions and report problems on the + [Forum](https://groups.google.com/group/cefpython) +- Supported examples are listed in the + [README-examples.md](examples/README-examples.md) file +- Documentation is in the [docs/](docs) directory: + - [Build instructions](docs/Build-instructions.md) + - [Contributing code](docs/Contributing-code.md) + - [Knowledge Base](docs/Knowledge-Base.md) + - [Migration guide](docs/Migration-guide.md) + - [Tutorial](docs/Tutorial.md) +- API reference is in the [api/](api) directory: + - [API categories](api/API-categories.md#api-categories) + - [API index](api/API-index.md#api-index) +- Additional documentation is available in + [Issues labelled Knowledge Base](../../issues?q=is%3Aissue+is%3Aopen+label%3A%22Knowledge+Base%22) +- To search documentation use GitHub "This repository" search + at the top. To narrow results to documentation only select + "Markdown" in the side pane + +## Support development + +To support general CEF Python development efforts you can make a donation using PayPal button below: + + + +
+ + +## Seeking sponsors + +CEF Python is seeking companies to sponsor development of this project. Most important +thing would be to have continuous monthly releases with updates to latest Chromium. There is +also lots of cool features and new settings that would be nice to implement. We have not yet +exposed all of upstream CEF APIs. If your company would like to sponsor CEF Python development efforts +then please contact [Czarek](https://www.linkedin.com/in/czarektomczak/). There are no active sponsors +at this moment. + + +### Previous sponsors @@ -140,207 +166,7 @@ businesses with cutting edge marketing technology. Please visit their website:
-## Install - -You can install [pypi/cefpython3](https://pypi.python.org/pypi/cefpython3) -package using pip tool. On Linux pip 8.1+ is required. You can -also download packages for offline installation available on the -[GitHub Releases](../../releases) pages. Command to install with pip: - -``` -pip install cefpython3==66.0 -``` - - -## Tutorial - -See the [Tutorial.md](docs/Tutorial.md) document. - - -## Examples - -See the [README-examples.md](examples/README-examples.md) and -[README-snippets.md](examples/snippets/README-snippets.md) documents. - - -## Support - -- Ask questions and report problems on the - [Forum](https://groups.google.com/group/cefpython) -- Supported examples are listed in the - [README-examples.md](examples/README-examples.md) file -- Documentation is in the [docs/](docs) directory: - - [Build instructions](docs/Build-instructions.md) - - [Contributing code](docs/Contributing-code.md) - - [Knowledge Base](docs/Knowledge-Base.md) - - [Migration guide](docs/Migration-guide.md) - - [Tutorial](docs/Tutorial.md) -- API reference is in the [api/](api) directory: - - [API categories](api/API-categories.md#api-categories) - - [API index](api/API-index.md#api-index) -- Additional documentation is available in - [Issues labelled Knowledge Base](../../issues?q=is%3Aissue+is%3Aopen+label%3A%22Knowledge+Base%22) -- To search documentation use GitHub "This repository" search - at the top. To narrow results to documentation only select - "Markdown" in the right pane. -- You can vote on issues in the tracker to let us know which issues are - important to you. To do that add a +1 thumb up reaction to the first post - in the issue. See - [Most popular issues](../../issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc) - sorted by reactions. - - -## Releases - -Information on planned new and current releases, supported platforms, -python versions, architectures and requirements. If you want to -support old operating systems then choose the v31 release. - -### Next release - -- To see planned new features or bugs to be fixed in the near future in one of - next releases, see the - [next release](../../issues?q=is%3Aissue+is%3Aopen+label%3A%22next+release%22) - label in the tracker -- To see planned new features or bugs to be fixed in further future, see the - [next release 2](../../issues?q=is%3Aissue+is%3Aopen+label%3A%22next+release+2%22) - label in the tracker - -### Latest release - -OS | Py2 | Py3 | 32bit | 64bit | Requirements ---- | --- | --- | --- | --- | --- -Windows | 2.7 | 3.4 / 3.5 / 3.6 / 3.7 | Yes | Yes | Windows 7+ -Linux | 2.7 | 3.4 / 3.5 / 3.6 / 3.7 | Yes | Yes | Debian 8+, Ubuntu 14.04+,
Fedora 24+, openSUSE 13.3+ -Mac | 2.7 | 3.4 / 3.5 / 3.6 / 3.7 | No | Yes | MacOS 10.9+ - -These platforms are not supported yet: -- ARM - see [Issue #267](../../issues/267) -- Android - see [Issue #307](../../issues/307) - - -### v49 release (WinXP/Vista) - -OS | Py2 | Py3 | 32bit | 64bit | Requirements ---- | --- | --- | --- | --- | --- -Windows | 2.7 | 3.4 | Yes | Yes | Windows XP+ - -- Install with command: `pip --no-cache-dir install cefpython3==49.0`. - - Please note that if you were previously installing cefpython3 - package it is required to use the `--no-cache-dir` flag, - otherwise pip will end up with error message - `No matching distribution found for cefpython3==49.0`. - This happens because 49.0 release occured after 57.0 and 66.0 - releases. -- Downloads are available on GitHub Releases tagged - [v49.0](../../releases/tag/v49.0). -- See [Migration guide](docs/Migration-guide.md) document for changes - in this release -- Documentation is available in the [docs/](../../tree/cefpython49-winxp/docs) - directory in the `cefpython49-winxp` branch -- API reference is available in the [api/](../../tree/cefpython49-winxp/api) - directory in the `cefpython49-winxp` branch - - -### v31 release (old systems) - -OS | Py2 | Py3 | 32bit | 64bit | Requirements ---- | --- | --- | --- | --- | --- -Windows | 2.7 | No | Yes | Yes | Windows XP+ -Linux | 2.7 | No | Yes | Yes | Debian 7+ / Ubuntu 12.04+ -Mac | 2.7 | No | Yes | Yes | MacOS 10.7+ - -Additional information for v31.2 release: -- On Windows/Mac you can install with command: `pip install cefpython3==31.2` -- Downloads are available on the GitHub Releases page tagged - [v31.2](../../releases/tag/v31.2). -- API reference is available in revision [169a1b2](../../tree/169a1b20d3cd09879070d41aab28cfa195d2a7d5/docs/api) -- Other documentation can be downloaded by cloning the - cefpython.wiki repository: `git clone git@github.com:cztomczak/cefpython.wiki.git` - - -## Support development - -If you would like to support general CEF Python development efforts -by making a donation then please click the Paypal Donate button below. -If you would like to see a specific feature implemented then you can make -a comment about that when making a donation and that will give it a higher -priority. - - - -

- - -### Thanks to all - -* [2018] Thanks to [Fivestars](https://www.fivestars.com/) for sponsoring - the v49 release for legacy systems (WinXP/Vista) -* [2018] Many thanks to [Lampix](https://lampix.com/) for sponsoring the v66 - release for all platforms -* [2017] Many thanks to [HighSide Inc.](https://highside.io/) for sponsoring - the v55/v56 releases for all platforms -* [2016-2018] Thanks to JetBrains for providing an Open Source license for - [PyCharm](https://www.jetbrains.com/pycharm/) -* [2014] Thanks to Adam Duston for donating a Macbook to aid the development - of Mac port -* [2013-2015] Lots of thanks goes to [Cyan Inc.](http://www.blueplanet.com/) - for sponsoring this project for a long time, making CEF Python 3 mature -* [2013] Thanks to [Rentouch GmbH](http://www.rentouch.ch/) for sponsoring the - development of the off-screen rendering support -* [2013] Thanks to Thomas Wusatiuk for sponsoring the development of the web - response reading features -* [2012-2018] Thanks to those who have made a Paypal donation: - [Rentouch GmbH](http://www.rentouch.ch/), Walter Purvis, Rokas Stupuras, - Alex Rattray, Greg Kacy, Paul Korzhyk, Tomasz Tomanek. -* [2012-2017] Thanks to those who have donated their time through code - contributions, they are listed in the [Authors](Authors) file - - -## Seeking new sponsors - -CEF Python is seeking companies to sponsor further development of the project. -There are many proposals for new features submitted in the issue tracker. Most -notable are: - -* Monthly releases with latest Chromium -* An automated build system similar to upstream CEF Spotify Automated Builds -* ARM and Android support -* Multi-threaded support for increased performance -* Proprietary codecs support in build tools: H264, H265,AC3, EAC3, MPEG-4 -* More CEF API exposed, only about 50% is exposed so far -* Hundreds of new settings and Chromium preferences not yet exposed -* Easier integration with popular GUI toolkits in just a few lines of code - and support for more third party GUI frameworks -* More examples of implementing various advanced features and more snippets - as well - -If your company would like to sponsor CEF Python development efforts then -please contact -[Czarek](https://drive.google.com/file/d/17xmoT5Z_zTHkVclqPzrs2aAV64Uiu7fh/view). -Long term sponsorships are welcome and Czarek is open to ideas about -the project. He would love to spend more time on developing this project, -but he can't afford doing so in his free time. Currently there is no company -supporting this project actively on a daily basis. - - -## Other READMEs - -- [PyInstaller packager](examples/pyinstaller/README-pyinstaller.md) - - - -## Quick links - -### Docs - -- [Build instructions](docs/Build-instructions.md) -- [Knowledge Base](docs/Knowledge-Base.md) -- [Migration guide](docs/Migration-guide.md) -- [Tutorial](docs/Tutorial.md) - - -### API categories +## API #### Modules diff --git a/api/WebRequestClient.md b/api/WebRequestClient.md index d8431cecc..0c75a668d 100644 --- a/api/WebRequestClient.md +++ b/api/WebRequestClient.md @@ -65,7 +65,7 @@ response (or -1 if not determined). | Parameter | Type | | --- | --- | | web_request | [WebRequest](WebRequest.md) | -| data | string | +| data | bytes | | __Return__ | void | Called when some part of the response is read. |data| contains the current diff --git a/docs/Build-instructions.md b/docs/Build-instructions.md index 5df63bec2..9ca4d6e99 100644 --- a/docs/Build-instructions.md +++ b/docs/Build-instructions.md @@ -66,8 +66,9 @@ are named "cefpythonXX" where XX is Chromium version number. from [here](https://www.microsoft.com/en-us/download/details.aspx?id=44266) 5) For Python 2.7 and when using using "Visual C++ compiler for Python 2.7" - you have to install "Visual C++ 2008 Redistributable Package (x64)" - from [here](https://www.microsoft.com/en-us/download/details.aspx?id=15336) + you have to install "Visual C++ 2008 Redistributable Package" + from [here](https://www.microsoft.com/en-us/download/details.aspx?id=29) + and [here](https://www.microsoft.com/en-us/download/details.aspx?id=15336) 6) Clone cefpython, checkout for example "cefpython57" branch that includes Chromium v57, then create a build/ directory and enter it: @@ -164,7 +165,8 @@ requirements common for all platforms. * For Python 2.7 install "Microsoft Visual C++ Compiler for Python 2.7" from [here](https://www.microsoft.com/en-us/download/details.aspx?id=44266) * When using "Visual C++ compiler for Python 2.7" you have to install - "Microsoft Visual C++ 2008 Redistributable Package (x64)" from + "Microsoft Visual C++ 2008 Redistributable Package" from + [here](https://www.microsoft.com/en-us/download/details.aspx?id=29) and [here](https://www.microsoft.com/en-us/download/details.aspx?id=15336) * For Python 2.7 copy "cefpython/src/windows/py27/stdint.h" to "%LocalAppData%\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\include\" diff --git a/examples/README-examples.md b/examples/README-examples.md index ea5871c89..ec2f9bcd3 100644 --- a/examples/README-examples.md +++ b/examples/README-examples.md @@ -107,7 +107,7 @@ yet ported to latest CEF. Some of them are externally maintained. for reading/modifying web requests: see the [wxpython-response.py](https://github.com/cztomczak/cefpython/blob/cefpython31/cefpython/cef3/linux/binaries_64bit/wxpython-response.py) example in the cefpython31 branch. - Example of using Python network library (urllib3/openssl) instead of Chromium's - network library - see [gist by Massimiliano Dal Cero](https://gist.github.com/yattamax/0252a3c5dc54a2f81650d5c0eafabf99) + network library - see [gist by Massimiliano Dal Cero](https://gist.github.com/cztomczak/83b77cbdda03ccef81e22e8bd36a51f6) - Example of passing exceptions from Python to Javascript and using await syntax to receive values from python return values - see [Managed python calls example by Elliot Woods](https://github.com/elliotwoods/cefpython-tests/tree/0180b22eac10a1bde08820ca192fdc30eb93f00d/6.%20Managed%20python%20calls) ## More examples to come diff --git a/examples/hello_world.py b/examples/hello_world.py index 478c70604..789f4666e 100644 --- a/examples/hello_world.py +++ b/examples/hello_world.py @@ -1,5 +1,12 @@ # Hello world example. Doesn't depend on any third party GUI framework. # Tested with CEF Python v57.0+. +# +# ==== High DPI support on Windows ==== +# To enable DPI awareness on Windows you have to either embed DPI aware manifest +# in your executable created with pyinstaller or change python.exe properties manually: +# Compatibility > High DPI scaling override > Application. +# Setting DPI awareness programmatically via a call to cef.DpiAware.EnableHighDpiSupport +# is problematic in Python, may not work and can cause display glitches. from cefpython3 import cefpython as cef import platform diff --git a/examples/pyinstaller/hook-cefpython3.py b/examples/pyinstaller/hook-cefpython3.py index 7522b7be1..9160f67f9 100644 --- a/examples/pyinstaller/hook-cefpython3.py +++ b/examples/pyinstaller/hook-cefpython3.py @@ -14,8 +14,13 @@ import sys import PyInstaller from PyInstaller.utils.hooks import is_module_satisfies, get_package_paths -from PyInstaller.compat import is_win, is_darwin, is_linux, is_py2 +from PyInstaller.compat import is_win, is_darwin, is_linux from PyInstaller import log as logging +try: + # PyInstaller >= 4.0 doesn't support Python 2.7 + from PyInstaller.compat import is_py2 +except ImportError: + is_py2 = None # Constants CEFPYTHON_MIN_VERSION = "57.0" diff --git a/examples/screenshot.py b/examples/screenshot.py index d6dc661c8..5ca8d4913 100644 --- a/examples/screenshot.py +++ b/examples/screenshot.py @@ -42,7 +42,7 @@ import sys try: - from PIL import Image, PILLOW_VERSION + from PIL import Image, __version__ as PILLOW_VERSION except ImportError: print("[screenshot.py] Error: PIL module not available. To install" " type: pip install Pillow") @@ -158,6 +158,8 @@ def save_screenshot(browser): "raw", "RGBA", 0, 1) image.save(SCREENSHOT_PATH, "PNG") print("[screenshot.py] Saved image: {path}".format(path=SCREENSHOT_PATH)) + # See comments in exit_app() why PostTask must be used + cef.PostTask(cef.TID_UI, exit_app, browser) def open_with_default_application(path): @@ -188,9 +190,10 @@ def OnLoadingStateChange(self, browser, is_loading, **_): # Loading is complete sys.stdout.write(os.linesep) print("[screenshot.py] Web page loading is complete") - save_screenshot(browser) - # See comments in exit_app() why PostTask must be used - cef.PostTask(cef.TID_UI, exit_app, browser) + print("[screenshot.py] Will save screenshot in 2 seconds") + # Give up to 2 seconds for the OnPaint call. Most of the time + # it is already called, but sometimes it may be called later. + cef.PostDelayedTask(cef.TID_UI, 2000, save_screenshot, browser) def OnLoadError(self, browser, frame, error_code, failed_url, **_): """Called when the resource load for a navigation fails diff --git a/examples/snippets/keyboard_handler.py b/examples/snippets/keyboard_handler.py new file mode 100644 index 000000000..9b8e40c8a --- /dev/null +++ b/examples/snippets/keyboard_handler.py @@ -0,0 +1,19 @@ +from cefpython3 import cefpython as cef + + +def main(): + cef.Initialize() + browser = cef.CreateBrowserSync(url="https://www.google.com/", + window_title="Keyboard Handler") + browser.SetClientHandler(KeyboardHandler()) + cef.MessageLoop() + del browser + cef.Shutdown() + + +class KeyboardHandler(object): + def OnKeyEvent(self, browser, event, event_handle, **_): + print("OnKeyEvent: "+str(event)) + +if __name__ == '__main__': + main() diff --git a/examples/tkinter_.py b/examples/tkinter_.py index c823f3dc9..327f171fb 100644 --- a/examples/tkinter_.py +++ b/examples/tkinter_.py @@ -44,7 +44,7 @@ def main(): - logger.setLevel(_logging.INFO) + logger.setLevel(_logging.DEBUG) stream_handler = _logging.StreamHandler() formatter = _logging.Formatter("[%(filename)s] %(message)s") stream_handler.setFormatter(formatter) @@ -55,19 +55,23 @@ def main(): logger.info("Tk {ver}".format(ver=tk.Tcl().eval('info patchlevel'))) assert cef.__version__ >= "55.3", "CEF Python v55.3+ required to run this" sys.excepthook = cef.ExceptHook # To shutdown all CEF processes on error + # Tk must be initialized before CEF otherwise fatal error (Issue #306) root = tk.Tk() app = MainFrame(root) - # Tk must be initialized before CEF otherwise fatal error (Issue #306) - cef.Initialize() + settings = {} + if MAC: + settings["external_message_pump"] = True + cef.Initialize(settings=settings) app.mainloop() + logger.debug("Main loop exited") cef.Shutdown() - class MainFrame(tk.Frame): def __init__(self, root): self.browser_frame = None self.navigation_bar = None + self.root = root # Root root.geometry("900x640") @@ -124,7 +128,9 @@ def on_focus_out(self, _): def on_close(self): if self.browser_frame: self.browser_frame.on_root_close() - self.master.destroy() + self.browser_frame = None + else: + self.master.destroy() def get_browser(self): if self.browser_frame: @@ -147,11 +153,12 @@ def setup_icon(self): class BrowserFrame(tk.Frame): - def __init__(self, master, navigation_bar=None): + def __init__(self, mainframe, navigation_bar=None): self.navigation_bar = navigation_bar self.closing = False self.browser = None - tk.Frame.__init__(self, master) + tk.Frame.__init__(self, mainframe) + self.mainframe = mainframe self.bind("", self.on_focus_in) self.bind("", self.on_focus_out) self.bind("", self.on_configure) @@ -165,27 +172,42 @@ def embed_browser(self): self.browser = cef.CreateBrowserSync(window_info, url="https://www.google.com/") assert self.browser + self.browser.SetClientHandler(LifespanHandler(self)) self.browser.SetClientHandler(LoadHandler(self)) self.browser.SetClientHandler(FocusHandler(self)) self.message_loop_work() def get_window_handle(self): - if self.winfo_id() > 0: - return self.winfo_id() - elif MAC: - # On Mac window id is an invalid negative value (Issue #308). - # This is kind of a dirty hack to get window handle using - # PyObjC package. If you change structure of windows then you + if MAC: + # Do not use self.winfo_id() on Mac, because of these issues: + # 1. Window id sometimes has an invalid negative value (Issue #308). + # 2. Even with valid window id it crashes during the call to NSView.setAutoresizingMask: + # https://github.com/cztomczak/cefpython/issues/309#issuecomment-661094466 + # + # To fix it using PyObjC package to obtain window handle. If you change structure of windows then you # need to do modifications here as well. + # + # There is still one issue with this solution. Sometimes there is more than one window, for example when application + # didn't close cleanly last time Python displays an NSAlert window asking whether to Reopen that window. In such + # case app will crash and you will see in console: + # > Fatal Python error: PyEval_RestoreThread: NULL tstate + # > zsh: abort python tkinter_.py + # Error messages related to this: https://github.com/cztomczak/cefpython/issues/441 + # + # There is yet another issue that might be related as well: + # https://github.com/cztomczak/cefpython/issues/583 + # noinspection PyUnresolvedReferences from AppKit import NSApp # noinspection PyUnresolvedReferences import objc - # Sometimes there is more than one window, when application - # didn't close cleanly last time Python displays an NSAlert - # window asking whether to Reopen that window. + logger.info("winfo_id={}".format(self.winfo_id())) # noinspection PyUnresolvedReferences - return objc.pyobjc_id(NSApp.windows()[-1].contentView()) + content_view = objc.pyobjc_id(NSApp.windows()[-1].contentView()) + logger.info("content_view={}".format(content_view)) + return content_view + elif self.winfo_id() > 0: + return self.winfo_id() else: raise Exception("Couldn't obtain window handle") @@ -224,10 +246,15 @@ def on_focus_out(self, _): self.browser.SetFocus(False) def on_root_close(self): + logger.info("BrowserFrame.on_root_close") if self.browser: + logger.debug("CloseBrowser") self.browser.CloseBrowser(True) self.clear_browser_references() - self.destroy() + else: + logger.debug("tk.Frame.destroy") + self.destroy() + def clear_browser_references(self): # Clear browser references that you keep anywhere in your @@ -235,6 +262,16 @@ def clear_browser_references(self): self.browser = None +class LifespanHandler(object): + + def __init__(self, tkFrame): + self.tkFrame = tkFrame + + def OnBeforeClose(self, browser, **_): + logger.debug("LifespanHandler.OnBeforeClose") + self.tkFrame.quit() + + class LoadHandler(object): def __init__(self, browser_frame): diff --git a/src/client_handler/Makefile b/src/client_handler/Makefile index d217660ef..25e645ff7 100644 --- a/src/client_handler/Makefile +++ b/src/client_handler/Makefile @@ -37,6 +37,7 @@ INC = -I./../ -I./../common/ -I$(PYTHON_INCLUDE) \ -I/usr/include/glib-2.0 \ -I/usr/include/cairo \ -I/usr/include/pango-1.0 \ + -I/usr/include/harfbuzz \ -I/usr/include/gdk-pixbuf-2.0 \ -I/usr/include/atk-1.0 \ -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include \ diff --git a/src/common/cefpython_public_api.h b/src/common/cefpython_public_api.h index 53ad62c63..c796388e6 100644 --- a/src/common/cefpython_public_api.h +++ b/src/common/cefpython_public_api.h @@ -46,6 +46,10 @@ #include "../../build/build_cefpython/cefpython_py36_fixed.h" #elif PY_MINOR_VERSION == 7 #include "../../build/build_cefpython/cefpython_py37_fixed.h" +#elif PY_MINOR_VERSION == 8 +#include "../../build/build_cefpython/cefpython_py38_fixed.h" +#elif PY_MINOR_VERSION == 9 +#include "../../build/build_cefpython/cefpython_py39_fixed.h" #endif // PY_MINOR_VERSION #endif // PY_MAJOR_VERSION diff --git a/src/compile_time_constants.pxi b/src/compile_time_constants.pxi index 609470c1d..bf130d6ed 100644 --- a/src/compile_time_constants.pxi +++ b/src/compile_time_constants.pxi @@ -5,3 +5,6 @@ DEF UNAME_SYSNAME = "Windows" DEF PY_MAJOR_VERSION = 3 +cdef extern from "limits.h": + cdef int INT_MIN + cdef int INT_MAX diff --git a/src/cpp_utils/Makefile b/src/cpp_utils/Makefile index 338fd960b..e6a6a2fe5 100644 --- a/src/cpp_utils/Makefile +++ b/src/cpp_utils/Makefile @@ -7,7 +7,7 @@ OUT = libcpp_utils.a INC = -I./../ -I/usr/include/gtk-2.0 \ -I/usr/include/glib-2.0 -I/usr/lib/i386-linux-gnu/gtk-2.0/include \ -I/usr/lib/i386-linux-gnu/glib-2.0/include -I/usr/include/cairo \ - -I/usr/include/pango-1.0 -I/usr/include/gdk-pixbuf-2.0 \ + -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/gdk-pixbuf-2.0 \ -I/usr/include/atk-1.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include \ -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include \ -I/usr/lib64/glib-2.0/include -I/usr/lib64/gtk-2.0/include \ diff --git a/src/javascript_bindings.pyx b/src/javascript_bindings.pyx index 9043639e3..31620a6dc 100644 --- a/src/javascript_bindings.pyx +++ b/src/javascript_bindings.pyx @@ -140,6 +140,8 @@ cdef class JavascriptBindings: return True elif valueType == int: return True + elif valueType == long: + return True elif valueType == type(None): return True elif IsFunctionOrMethod(valueType): diff --git a/src/linux/binaries_64bit/kivy_.py b/src/linux/binaries_64bit/kivy_.py index bdfb6d2c4..a9a1590b0 100644 --- a/src/linux/binaries_64bit/kivy_.py +++ b/src/linux/binaries_64bit/kivy_.py @@ -1,18 +1,25 @@ -# An example of embedding CEF browser in the Kivy framework. -# The browser is embedded using off-screen rendering mode. - -# Tested using Kivy 1.7.2 stable, only on Linux. +# An example of embedding CEF browser with the Kivy framework +# by using off-screen rendering mode. # In this example kivy-lang is used to declare the layout which # contains two buttons (back, forward) and the browser view. from cefpython3 import cefpython as cef -import pygtk -import gtk import sys import os import time +if sys.platform == 'linux': + import pygtk + import gtk + pygtk.require('2.0') +elif sys.platform == 'darwin': + import gi + gi.require_version("Gtk", "3.0") + from gi.repository import Gtk +elif sys.platform == 'win32': + # no gtk needed on Windows + pass from kivy.app import App from kivy.uix.button import Button @@ -28,9 +35,6 @@ # Global variables g_switches = None -# PyGTK required -pygtk.require('2.0') - class BrowserLayout(BoxLayout): @@ -38,7 +42,7 @@ def __init__(self, **kwargs): super(BrowserLayout, self).__init__(**kwargs) self.orientation = "vertical" - self.browser_widget = CefBrowser(id="browser") + self.browser_widget = CefBrowser() layout = BoxLayout() layout.size_hint_y = None @@ -150,9 +154,6 @@ def start_cef(self): # Configure CEF settings = { - # This directories must be set on Linux - "locales_dir_path": cef.GetModuleDirectory()+"/locales", - "resources_dir_path": cef.GetModuleDirectory(), "browser_subprocess_path": "%s/%s" % ( cef.GetModuleDirectory(), "subprocess"), "windowless_rendering_enabled": True, @@ -161,7 +162,15 @@ def start_cef(self): "enabled": False, }, "external_message_pump": False, # See Issue #246 + "multi_threaded_message_loop": False, } + if sys.platform == 'linux': + # This directories must be set on Linux + settings["locales_dir_path"] = cef.GetModuleDirectory() + "/locales" + settings["resources_dir_path"] = cef.GetModuleDirectory() + if sys.platform == 'darwin': + settings["external_message_pump"] = True # Temporary fix for Issue #246 + switches = { # Tweaking OSR performance by setting the same Chromium flags # as in upstream cefclient (# Issue #240). @@ -190,18 +199,21 @@ def start_cef(self): # Start idle - CEF message loop work. Clock.schedule_once(self._message_loop_work, 0) + windowInfo = cef.WindowInfo() + # TODO: For printing to work in off-screen-rendering mode # it is enough to call gtk_init(). It is not required # to provide window handle when calling SetAsOffscreen(). # However it still needs to be tested whether providing # window handle is required for mouse context menu and # popup widgets to work. - gtkwin = gtk.Window() - gtkwin.realize() - # WindowInfo offscreen flag - windowInfo = cef.WindowInfo() - windowInfo.SetAsOffscreen(gtkwin.window.xid) + if sys.platform == 'linux': + gtkwin = gtk.Window() + gtkwin.realize() + windowInfo.SetAsOffscreen(gtkwin.window.xid) + elif sys.platform == 'darwin' or sys.platform == 'win32': + windowInfo.SetAsOffscreen(0) # Create Broswer and naviagte to empty page <= OnPaint won't get # called yet @@ -519,12 +531,12 @@ def get_windows_key_code(self, kivycode): def go_forward(self, *_): """Going to forward in browser history.""" - print "go forward" + print("go forward") self.browser.GoForward() def go_back(self, *_): """Going back in browser history.""" - print "go back" + print("go back") self.browser.GoBack() def reload(self, *_): @@ -864,7 +876,7 @@ def OnLoadingStateChange(self, is_loading, **_): def OnPaint(self, element_type, paint_buffer, **_): # print "OnPaint()" if element_type != cef.PET_VIEW: - print "Popups aren't implemented yet" + print("Popups aren't implemented yet") return # FPS meter ("fps" arg) diff --git a/src/process_message_utils.pyx b/src/process_message_utils.pyx index 8ced3f6ce..e2d55dabd 100644 --- a/src/process_message_utils.pyx +++ b/src/process_message_utils.pyx @@ -238,14 +238,9 @@ cdef CefRefPtr[CefListValue] PyListToCefListValue( ret.get().SetNull(index) elif valueType == bool: ret.get().SetBool(index, bool(value)) - elif valueType == int: - ret.get().SetInt(index, int(value)) - elif valueType == long: - # Int32 range is -2147483648..2147483647, we've increased the - # minimum size by one as Cython was throwing a warning: - # "unary minus operator applied to unsigned type, result still - # unsigned". - if -2147483647 <= value <= 2147483647: + elif valueType == int or valueType == long: # In Py3 int and long types are the same type. + # Int32 range is -2147483648..2147483647 + if INT_MIN <= value <= INT_MAX: ret.get().SetInt(index, int(value)) else: # Long values become strings. @@ -297,14 +292,9 @@ cdef void PyListToExistingCefListValue( cefListValue.get().SetNull(index) elif valueType == bool: cefListValue.get().SetBool(index, bool(value)) - elif valueType == int: - cefListValue.get().SetInt(index, int(value)) - elif valueType == long: - # Int32 range is -2147483648..2147483647, we've increased the - # minimum size by one as Cython was throwing a warning: - # "unary minus operator applied to unsigned type, result still - # unsigned". - if -2147483647 <= value <= 2147483647: + elif valueType == int or valueType == long: # In Py3 int and long types are the same type. + # Int32 range is -2147483648..2147483647 + if INT_MIN <= value <= INT_MAX: cefListValue.get().SetInt(index, int(value)) else: # Long values become strings. @@ -357,14 +347,9 @@ cdef CefRefPtr[CefDictionaryValue] PyDictToCefDictionaryValue( ret.get().SetNull(cefKey) elif valueType == bool: ret.get().SetBool(cefKey, bool(value)) - elif valueType == int: - ret.get().SetInt(cefKey, int(value)) - elif valueType == long: - # Int32 range is -2147483648..2147483647, we've increased the - # minimum size by one as Cython was throwing a warning: - # "unary minus operator applied to unsigned type, result still - # unsigned". - if -2147483647 <= value <= 2147483647: + elif valueType == int or valueType == long: # In Py3 int and long types are the same type. + # Int32 range is -2147483648..2147483647 + if INT_MIN <= value <= INT_MAX: ret.get().SetInt(cefKey, int(value)) else: # Long values become strings. diff --git a/src/subprocess/Makefile b/src/subprocess/Makefile index f52b72df7..adc34fca4 100644 --- a/src/subprocess/Makefile +++ b/src/subprocess/Makefile @@ -11,6 +11,7 @@ INC = -I./../ -I./../common/ -I$(PYTHON_INCLUDE) \ -I/usr/include/glib-2.0 \ -I/usr/include/cairo \ -I/usr/include/pango-1.0 \ + -I/usr/include/harfbuzz \ -I/usr/include/gdk-pixbuf-2.0 \ -I/usr/include/atk-1.0 \ -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include \ diff --git a/src/subprocess/Makefile-libcefpythonapp b/src/subprocess/Makefile-libcefpythonapp index 23fbde392..e8a6b852b 100644 --- a/src/subprocess/Makefile-libcefpythonapp +++ b/src/subprocess/Makefile-libcefpythonapp @@ -36,6 +36,7 @@ INC = -I./../ -I./../common/ -I$(PYTHON_INCLUDE) \ -I/usr/include/glib-2.0 \ -I/usr/include/cairo \ -I/usr/include/pango-1.0 \ + -I/usr/include/harfbuzz \ -I/usr/include/gdk-pixbuf-2.0 \ -I/usr/include/atk-1.0 \ -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include \ diff --git a/src/subprocess/main_message_loop/util_win.cpp b/src/subprocess/main_message_loop/util_win.cpp index bc1f0965c..834850e32 100644 --- a/src/subprocess/main_message_loop/util_win.cpp +++ b/src/subprocess/main_message_loop/util_win.cpp @@ -136,8 +136,8 @@ int GetCefKeyboardModifiers(WPARAM wparam, LPARAM lparam) { return modifiers; } -bool IsKeyDown(WPARAM wparam) { - return (GetKeyState(wparam) & 0x8000) != 0; +bool IsKeyDown(int keycode) { + return (GetKeyState(keycode) & 0x8000) != 0; } float GetDeviceScaleFactor() { diff --git a/src/subprocess/main_message_loop/util_win.h b/src/subprocess/main_message_loop/util_win.h index 39870204b..a716d9380 100644 --- a/src/subprocess/main_message_loop/util_win.h +++ b/src/subprocess/main_message_loop/util_win.h @@ -31,7 +31,7 @@ WNDPROC SetWndProcPtr(HWND hWnd, WNDPROC wndProc); int GetCefMouseModifiers(WPARAM wparam); int GetCefKeyboardModifiers(WPARAM wparam, LPARAM lparam); -bool IsKeyDown(WPARAM wparam); +bool IsKeyDown(int keycode); // Returns the device scale factor. For example, 200% display scaling will // return 2.0. diff --git a/src/web_request.pyx b/src/web_request.pyx index 9891dade8..8e51fca12 100644 --- a/src/web_request.pyx +++ b/src/web_request.pyx @@ -176,7 +176,7 @@ cdef public void WebRequestClient_OnDownloadData( if userCallback: userCallback( web_request=webRequest, - data=VoidPtrToString(data, dataLength)) + data=VoidPtrToBytes(data, dataLength)) except: (exc_type, exc_value, exc_trace) = sys.exc_info() sys.excepthook(exc_type, exc_value, exc_trace) diff --git a/tools/build.py b/tools/build.py index 522a9b086..f3960283e 100644 --- a/tools/build.py +++ b/tools/build.py @@ -293,7 +293,7 @@ def setup_environ(): print("[build.py] PYTHON_INCLUDE: {python_include}" .format(python_include=os.environ["PYTHON_INCLUDE"])) - os.environ["CEF_CCFLAGS"] = "-std=gnu++11 -DNDEBUG -Wall -Werror" + os.environ["CEF_CCFLAGS"] = "-std=gnu++11 -DNDEBUG -Wall -Werror -Wno-deprecated-declarations" if FAST_FLAG: os.environ["CEF_CCFLAGS"] += " -O0" else: @@ -809,7 +809,7 @@ def build_cefpython_module(): args = list() args.append("\"{python}\"".format(python=sys.executable)) args.append(os.path.join(TOOLS_DIR, os.path.basename(__file__))) - assert __file__ in sys.argv[0] + assert os.path.basename(__file__) in sys.argv[0] args.extend(SYS_ARGV_ORIGINAL[1:]) command = " ".join(args) print("[build.py] Running command: %s" % command) diff --git a/tools/build_distrib.py b/tools/build_distrib.py index e0a5bde1d..051914f57 100644 --- a/tools/build_distrib.py +++ b/tools/build_distrib.py @@ -80,13 +80,14 @@ ALLOW_PARTIAL = False # Python versions -SUPPORTED_PYTHON_VERSIONS = [(2, 7), (3, 4), (3, 5), (3, 6), (3, 7)] +SUPPORTED_PYTHON_VERSIONS = [(2, 7), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9)] # Python search paths. It will use first Python found for specific version. # Supports replacement of one environment variable in path eg.: %ENV_KEY%. PYTHON_SEARCH_PATHS = dict( WINDOWS=[ - "C:\\Python*\\", + "C:\\Python??*\\", + "C:\\Pythons\\Python*\\", "%LOCALAPPDATA%\\Programs\\Python\\Python*\\", "C:\\Program Files\\Python*\\", "C:\\Program Files (x86)\\Python*\\", @@ -276,6 +277,8 @@ def search_for_pythons(search_arch): version_str = subprocess.check_output([python, "-c", version_code]) version_str = version_str.strip() + if sys.version_info >= (3, 0): + version_str = version_str.decode("utf-8") match = re.search("^\((\d+), (\d+), (\d+)\)$", version_str) assert match, version_str major = match.group(1) @@ -287,6 +290,8 @@ def search_for_pythons(search_arch): "print(str(platform.architecture()[0]));") arch = subprocess.check_output([python, "-c", arch_code]) arch = arch.strip() + if sys.version_info >= (3, 0): + arch = arch.decode("utf-8") if version_tuple2 in SUPPORTED_PYTHON_VERSIONS \ and arch == search_arch: name = ("Python {major}.{minor}.{micro} {arch}" @@ -348,8 +353,14 @@ def install_upgrade_requirements(pythons): " for: {name}".format(name=python["name"])) # Upgrade pip - command = ("\"{python}\" -m pip install --upgrade pip" - .format(python=python["executable"])) + pip_version = "pip" + # Old Python versions require specific versions of pip, latest versions are broken with these. + if python["version2"] == (2, 7): + pip_version = "pip==20.3.4" + elif python["version2"] == (3, 4): + pip_version = "pip==19.1.1" + command = ("\"{python}\" -m pip install --upgrade {pip_version}" + .format(python=python["executable"], pip_version=pip_version)) command = sudo_command(command, python=python["executable"]) pcode = subprocess.call(command, shell=True) if pcode != 0: @@ -378,7 +389,7 @@ def uninstall_cefpython3_packages(pythons): .format(python=python["executable"])) try: output = subprocess.check_output(command, shell=True) - except subprocess.CalledProcessError, exc: + except subprocess.CalledProcessError as exc: # pip show returns error code when package is not installed output = exc.output if not len(output.strip()): @@ -517,39 +528,37 @@ def build_cefpython_modules(pythons, arch): def backup_subprocess_executable_issue342(python): - """Use subprocess executable build by Python 2.7 to avoid - false-positives by AVs when building subprocess with Python 3. - Windows-only issue.""" + """Use subprocess executable built by Python 3.4 to have the least amount of + false-positives by AVs. Windows-only issue.""" if not WINDOWS: return if python["version2"] == (2, 7): print("[build_distrib.py] Backup subprocess executable built" - " with Python 2.7 (Issue #342)") + " with Python 3.4 (Issue #342)") cefpython_binary_basename = get_cefpython_binary_basename( get_os_postfix2_for_arch(python["arch"])) cefpython_binary = os.path.join(BUILD_DIR, cefpython_binary_basename) assert os.path.isdir(cefpython_binary) src = os.path.join(cefpython_binary, "subprocess.exe") dst = os.path.join(BUILD_CEFPYTHON, - "subprocess_py27_{arch}_issue342.exe" + "subprocess_py34_{arch}_issue342.exe" .format(arch=python["arch"])) shutil.copy(src, dst) def restore_subprocess_executable_issue342(arch): - """Use subprocess executable build by Python 2.7 to avoid - false-positives by AVs when building subprocess with Python 3. - Windows-only issue.""" + """Use subprocess executable built by Python 3.4 to have the least amount of + false-positives by AVs. Windows-only issue.""" if not WINDOWS: return print("[build_distrib.py] Restore subprocess executable built" - " with Python 2.7 (Issue #342)") + " with Python 3.4 (Issue #342)") cefpython_binary_basename = get_cefpython_binary_basename( get_os_postfix2_for_arch(arch)) cefpython_binary = os.path.join(BUILD_DIR, cefpython_binary_basename) assert os.path.isdir(cefpython_binary) src = os.path.join(BUILD_CEFPYTHON, - "subprocess_py27_{arch}_issue342.exe" + "subprocess_py34_{arch}_issue342.exe" .format(arch=arch)) assert os.path.isfile(src) dst = os.path.join(cefpython_binary, "subprocess.exe") @@ -614,7 +623,7 @@ def check_cpp_extension_dependencies_issue359(setup_dir, all_pythons): return checked_any = False for python in all_pythons: - if python["version2"] in ((3, 5), (3, 6), (3, 7)): + if python["version2"] in ((3, 5), (3, 6), (3, 7), (3, 8), (3, 9)): checked_any = True if not os.path.exists(os.path.join(setup_dir, "cefpython3", "msvcp140.dll")): diff --git a/tools/common.py b/tools/common.py index 113bcd9eb..303ccb856 100644 --- a/tools/common.py +++ b/tools/common.py @@ -219,15 +219,19 @@ VS_PLATFORM_ARG = "x86" if ARCH32 else "amd64" +# Python 3.5 / 3.6 / 3.7 / 3.8 / 3.9 VS2015_VCVARS = ("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0" "\\VC\\vcvarsall.bat") +# Required for building old CEF branches < 2704 VS2013_VCVARS = ("C:\\Program Files (x86)\\Microsoft Visual Studio 12.0" "\\VC\\vcvarsall.bat") +# Python 3.4 VS2010_VCVARS = ("C:\\Program Files (x86)\\Microsoft Visual Studio 10.0" "\\VC\\vcvarsall.bat") +# Python 2.7 VS2008_VCVARS = ("C:\\Program Files (x86)\\Microsoft Visual Studio 9.0" "\\VC\\vcvarsall.bat") @@ -473,6 +477,10 @@ def get_msvs_for_python(vs_prefix=False): return "VS2015" if vs_prefix else "2015" elif sys.version_info[:2] == (3, 7): return "VS2015" if vs_prefix else "2015" + elif sys.version_info[:2] == (3, 8): + return "VS2015" if vs_prefix else "2015" + elif sys.version_info[:2] == (3, 9): + return "VS2015" if vs_prefix else "2015" else: print("ERROR: This version of Python is not supported") sys.exit(1) diff --git a/tools/cython_setup.py b/tools/cython_setup.py index 4f0cafc6e..436bcb2ce 100644 --- a/tools/cython_setup.py +++ b/tools/cython_setup.py @@ -147,17 +147,15 @@ def get_winsdk_lib(): if WINDOWS: if ARCH32: winsdk_libs = [ + # Windows 7 SDKs. r"C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\Lib", r"C:\\Program Files\\Microsoft SDKs\\Windows\\v7.0\\Lib", - # Visual Studio 2008 installation - r"C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0A\\Lib", ] elif ARCH64: winsdk_libs = [ + # Windows 7 SDKs. r"C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\Lib\\x64", r"C:\\Program Files\\Microsoft SDKs\\Windows\\v7.0\\Lib\\x64", - # Visual Studio 2008 installation - r"C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0A\\Lib\\x64", ] else: raise Exception("Unknown architecture") @@ -318,6 +316,7 @@ def get_include_dirs(): '/usr/include/gtk-unix-print-2.0', '/usr/include/cairo', '/usr/include/pango-1.0', + '/usr/include/harfbuzz', '/usr/include/gdk-pixbuf-2.0', '/usr/include/atk-1.0', # Fedora @@ -337,6 +336,7 @@ def get_include_dirs(): '/usr/include/gtk-unix-print-2.0', '/usr/include/cairo', '/usr/include/pango-1.0', + '/usr/include/harfbuzz', '/usr/include/gdk-pixbuf-2.0', '/usr/include/atk-1.0', # Ubuntu @@ -431,6 +431,7 @@ def get_ext_modules(options): # > Unknown Extension options: 'cython_directives' warnings.warn(msg) cython_directives={ # Any conversion to unicode must be explicit using .decode(). + "language_level": 2, # Yes, Py2 for all python versions. "c_string_type": "bytes", "c_string_encoding": "utf-8", "profile": ENABLE_PROFILING, @@ -468,6 +469,9 @@ def compile_time_constants(): # A way around Python 3.2 bug: UNAME_SYSNAME is not set contents += 'DEF UNAME_SYSNAME = "%s"\n' % platform.uname()[0] contents += 'DEF PY_MAJOR_VERSION = %s\n' % sys.version_info.major + contents += 'cdef extern from "limits.h":\n' + contents += ' cdef int INT_MIN\n' + contents += ' cdef int INT_MAX\n' fo.write(contents.encode("utf-8")) diff --git a/tools/installer/cefpython3.__init__.py b/tools/installer/cefpython3.__init__.py index fc00000dc..624a26e7b 100644 --- a/tools/installer/cefpython3.__init__.py +++ b/tools/installer/cefpython3.__init__.py @@ -26,9 +26,13 @@ package_dir = os.path.dirname(os.path.abspath(__file__)) -# This loads the libcef.so library for the subprocess executable. -# On Mac it works without setting library paths. -os.environ["LD_LIBRARY_PATH"] = package_dir +# This loads the libcef.so library for the subprocess executable on Linux. +# TODO: Use -Wl,-rpath=\$$ORIGIN in Makefile. +ld_library_path = os.environ.get("LD_LIBRARY_PATH") +if ld_library_path and ld_library_path.strip(): + os.environ["LD_LIBRARY_PATH"] = package_dir + os.pathsep + ld_library_path +else: + os.environ["LD_LIBRARY_PATH"] = package_dir # This env variable will be returned by cefpython.GetModuleDirectory(). os.environ["CEFPYTHON3_PATH"] = package_dir @@ -60,5 +64,11 @@ elif sys.version_info[:2] == (3, 7): # noinspection PyUnresolvedReferences from . import cefpython_py37 as cefpython +elif sys.version_info[:2] == (3, 8): + # noinspection PyUnresolvedReferences + from . import cefpython_py38 as cefpython +elif sys.version_info[:2] == (3, 9): + # noinspection PyUnresolvedReferences + from . import cefpython_py39 as cefpython else: raise Exception("Python version not supported: " + sys.version) diff --git a/tools/installer/cefpython3.setup.py b/tools/installer/cefpython3.setup.py index 6814cbb77..d14ee2ce5 100644 --- a/tools/installer/cefpython3.setup.py +++ b/tools/installer/cefpython3.setup.py @@ -148,6 +148,8 @@ def main(): "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Topic :: Desktop Environment", "Topic :: Internet", "Topic :: Internet :: WWW/HTTP", diff --git a/tools/make_installer.py b/tools/make_installer.py index bc3b5cef4..012e66575 100644 --- a/tools/make_installer.py +++ b/tools/make_installer.py @@ -338,7 +338,7 @@ def create_empty_log_file(log_file): def copy_cpp_extension_dependencies_issue359(pkg_dir): """CEF Python module is written in Cython and is a Python C++ - extension and depends on msvcpXX.dll. For Python 3.5 / 3.6 / 3.7 + extension and depends on msvcpXX.dll. For Python 3.5 / 3.6 / 3.7 / 3.8 / 3.9 msvcp140.dll is required. See Issue #359. For Python 2.7 msvcp90.dll is required. Etc. These dependencies are not included with Python binaries from Python.org.""" @@ -365,10 +365,12 @@ def copy_cpp_extension_dependencies_issue359(pkg_dir): # in the package. Thus if included, msvcpxx.dll dependency is # required as well. - # Python 3.5 / 3.6 / 3.7 + # Python 3.5 / 3.6 / 3.7 / 3.8 / 3.9 if os.path.exists(os.path.join(pkg_dir, "cefpython_py35.pyd")) \ or os.path.exists(os.path.join(pkg_dir, "cefpython_py36.pyd")) \ - or os.path.exists(os.path.join(pkg_dir, "cefpython_py37.pyd")): + or os.path.exists(os.path.join(pkg_dir, "cefpython_py37.pyd")) \ + or os.path.exists(os.path.join(pkg_dir, "cefpython_py38.pyd")) \ + or os.path.exists(os.path.join(pkg_dir, "cefpython_py39.pyd")): search_paths = [ # This is where Microsoft Visual C++ 2015 Update 3 installs # (14.00.24212). diff --git a/tools/requirements.txt b/tools/requirements.txt index 81ebc0c5c..4b0835794 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,4 +1,4 @@ -Cython == 0.28.4 +Cython == 0.29.21 docopt >= 0.6.2 setuptools wheel diff --git a/unittests/main_test.py b/unittests/main_test.py index 99397da88..ce71af20f 100644 --- a/unittests/main_test.py +++ b/unittests/main_test.py @@ -58,17 +58,18 @@ print("test_function() ok"); // Test binding property: test_property1 - if (test_property1 == "Test binding property to the 'window' object") { + if (test_property1 === "Test binding property to the 'window' object") { print("test_property_1 ok"); } else { throw new Error("test_property1 contains invalid string"); } // Test binding property: test_property2 - if (JSON.stringify(test_property2) == '{"key1":"Test binding property'+ - ' to the \\'window\\' object","key2":["Inside list",1,2]}') { + if (JSON.stringify(test_property2) === '{"key1":"Test binding property'+ + ' to the \\'window\\' object","key2":["Inside list",2147483647,"2147483648"]}') { print("test_property2 ok"); } else { + print("test_property2 invalid value: " + JSON.stringify(test_property2)); throw new Error("test_property2 contains invalid value"); } @@ -81,7 +82,7 @@ print("[TIMER] Call Python function and then js callback that was"+ " passed (Issue #277 test)"); external.test_callbacks(function(msg_from_python, py_callback){ - if (msg_from_python == "String sent from Python") { + if (msg_from_python === "String sent from Python") { print("test_callbacks() ok"); var execution_time = new Date().getTime() - start_time; print("[TIMER]: Elapsed = "+String(execution_time)+" ms"); @@ -163,15 +164,23 @@ def test_main(self): cef.LoadCrlSetsFile(crlset) subtest_message("cef.LoadCrlSetsFile ok") - # High DPI on Windows + # High DPI on Windows. + # Setting DPI awareness from Python is usually too late and should be done + # via manifest file. Alternatively change python.exe properties > Compatibility + # > High DPI scaling override > Application. + # Using cef.DpiAware.EnableHighDpiSupport is problematic, it can cause + # display glitches. if WINDOWS: self.assertIsInstance(cef.DpiAware.GetSystemDpi(), tuple) window_size = cef.DpiAware.CalculateWindowSize(800, 600) self.assertIsInstance(window_size, tuple) self.assertGreater(window_size[0], 0) self.assertGreater(cef.DpiAware.Scale((800, 600))[0], 0) - cef.DpiAware.EnableHighDpiSupport() - self.assertTrue(cef.DpiAware.IsProcessDpiAware()) + + # OFF - see comments above. + # cef.DpiAware.EnableHighDpiSupport() + # self.assertTrue(cef.DpiAware.IsProcessDpiAware()) + # Make some calls again after DPI Aware was set self.assertIsInstance(cef.DpiAware.GetSystemDpi(), tuple) self.assertGreater(cef.DpiAware.Scale([800, 600])[0], 0) @@ -374,9 +383,10 @@ def __init__(self, test_case): self.test_case = test_case # Test binding properties to the 'window' object. + # 2147483648 is out of INT_MAX limit and will be sent to JS as string value. self.test_property1 = "Test binding property to the 'window' object" self.test_property2 = {"key1": self.test_property1, - "key2": ["Inside list", 1, 2]} + "key2": ["Inside list", 2147483647, 2147483648]} # Asserts for True/False will be checked just before shutdown self.test_for_True = True # Test whether asserts are working correctly