├── .gitignore ├── BUILDING_CEF.md ├── CEF_UPGRADE.md ├── LICENSE ├── Makefile ├── README.md ├── cefium.png ├── cefium ├── Application.vala ├── BrowserWindow.vala ├── Cefium.vala ├── CefiumRendererExtension.vala └── URLBar.vala ├── cefsubprocess └── Subprocess.vala ├── genvalacef.py ├── launch.sh.in ├── overrides ├── cef_base.h ├── cef_error_codes.h ├── cef_primitives.h └── cef_string.h ├── utils └── sysinfo.vala ├── valacef ├── Checks.vala ├── SimpleAccessor.vala ├── SimpleInterceptor.vala ├── V8.vala ├── constants.vala ├── valacef.pc.in └── version.vala ├── valacefgen ├── __init__.py ├── cparser.py ├── types.py ├── utils.py └── vala.py ├── valacefgtk ├── AboutBlankPopupClient.vala ├── AboutBlankPopupRequestHandler.vala ├── BrowserProcess.vala ├── BrowserProcessHandler.vala ├── Client.vala ├── ContextMenuHandler.vala ├── DisplayHandler.vala ├── DownloadHandler.vala ├── DownloadManager.vala ├── FlashPlugin.vala ├── FocusHandler.vala ├── Function.vala ├── InitFlags.vala ├── JsdialogHandler.vala ├── KeyboardHandler.vala ├── LifeSpanHandler.vala ├── LoadHandler.vala ├── MsgId.vala ├── NavigationRequest.vala ├── Proxy.vala ├── RenderHandler.vala ├── RenderProcess.vala ├── RenderProcessHandler.vala ├── RenderSideEventLoop.vala ├── RendererContext.vala ├── RequestHandler.vala ├── Task.vala ├── UIEvents.vala ├── Utils.vala ├── WeakRef.vala ├── WebContext.vala ├── WebView.vala ├── WebViewOffscreen.vala ├── WebViewWidget.vala ├── WebViewWindowed.vala ├── WidevinePlugin.vala ├── init.vala ├── valacefgtk.pc.in └── x11.vala ├── vapi └── x11.vapi ├── waf ├── widevine └── manifest.json └── wscript /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .idea 3 | cef 4 | _cef 5 | build 6 | .lock* 7 | .waf* 8 | cefium_data 9 | tmp 10 | utils/sysinfo 11 | -------------------------------------------------------------------------------- /BUILDING_CEF.md: -------------------------------------------------------------------------------- 1 | Building Chromium Embedded Framework for ValaCEF 2 | =========================================== 3 | 4 | You need [patched CEF 76.3809.x](https://github.com/tiliado/cef/tree/3809-valacef). 5 | 6 | Paths 7 | ----- 8 | 9 | * /media/fenryxo/exthdd7/cef/build/ -- the build directory 10 | * /media/fenryxo/exthdd7/cef/build/ -- the download directory 11 | * /home/fenryxo/dev/projects/cef/cef -- the source directory 12 | of [patched CEF 76.3809.x](https://github.com/tiliado/cef/tree/3809-valacef) 13 | 14 | Install dependencies 15 | ------------------ 16 | 17 | On Ubuntu 18.04 LTS: 18 | 19 | apt install \ 20 | curl build-essential flex g++ git-svn libcairo2-dev libglib2.0-dev \ 21 | libcups2-dev libgtkglext1-dev git-core libglu1-mesa-dev libnspr4-dev \ 22 | libnss3-dev libgnome-keyring-dev libasound2-dev gperf bison libpci-dev \ 23 | libkrb5-dev libgtk-3-dev libxss-dev python libpulse-dev ca-certificates \ 24 | default-jre 25 | 26 | Use LXC container (here in Fedora 29): 27 | 28 | sudo lxc-create -n cef-bionic -t /usr/share/lxc/templates/lxc-download -- -d ubuntu -r bionic -a amd64 29 | sudo lxc-start -n cef-bionic 30 | sudo lxc-attach -n cef-bionic 31 | apt update && apt full-upgrade 32 | apt install ... 33 | mkdir -p /media/fenryxo/exthdd7/cef 34 | poweroff 35 | sudo nano /var/lib/lxc/cef-bionic/config 36 | lxc.mount.entry = /media/fenryxo/exthdd7/cef media/fenryxo/exthdd7/cef none bind 0 0 37 | 38 | 39 | Download automate-git.py script 40 | ---------------------------- 41 | 42 | mkdir -p /media/fenryxo/exthdd7/cef/build 43 | cd /media/fenryxo/exthdd7/cef/build 44 | wget https://bitbucket.org/chromiumembedded/cef/raw/master/tools/automate/automate-git.py 45 | 46 | Set up environment 47 | ---------------- 48 | 49 | sudo lxc-start -n cef-bionic 50 | sudo lxc-attach -n cef-bionic 51 | apt update; apt full-upgrade 52 | su ubuntu 53 | cd /media/fenryxo/exthdd7/cef/build 54 | export GN_DEFINES='is_official_build=true use_allocator=none symbol_level=1 ffmpeg_branding=Chrome proprietary_codecs=true' 55 | export CFLAGS="-Wno-error" 56 | export CXXFLAGS="-Wno-error" 57 | export CEF_ARCHIVE_FORMAT=tar.bz2 58 | 59 | Download & build CEF 60 | ------------------ 61 | 62 | ### Full download 63 | 64 | cd /media/fenryxo/exthdd7/cef/build/ 65 | time python automate-git.py --download-dir=download \ 66 | --url=/home/fenryxo/dev/projects/cef/cef \ 67 | --branch=3809 --checkout=3809-valacef \ 68 | --force-clean --force-clean-deps --force-config \ 69 | --x64-build --build-target=cefsimple --no-build --no-distrib 70 | 71 | ### Update 72 | 73 | cd /media/fenryxo/exthdd7/cef/build/ 74 | time python automate-git.py --download-dir=download \ 75 | --url=/home/fenryxo/dev/projects/cef/cef \ 76 | --branch=3809 --checkout=origin/3809-valacef \ 77 | --force-clean --force-config \ 78 | --x64-build --build-target=cefsimple --no-build --no-distrib 79 | 80 | ### Build 81 | 82 | time python automate-git.py --download-dir=download \ 83 | --url=/home/fenryxo/dev/projects/cef/cef \ 84 | --branch=3809 --checkout=origin/3809-valacef \ 85 | --x64-build --build-target=cefsimple --no-update --force-build \ 86 | --no-debug-build 87 | 88 | Install CEF to be found by ValaCEF 89 | ------------------------------ 90 | 91 | In the directory of an extracted minimal CEF distribution: 92 | 93 | mkdir -p build 94 | cd build 95 | cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .. 96 | make 97 | su # or sudo su 98 | mkdir -p /usr/local/include/cef 99 | cp -r include /usr/local/include/cef 100 | mkdir -p /usr/local/lib/cef 101 | cp -r Release/* /usr/local/lib/cef 102 | cp build/libcef_dll_wrapper/libcef_dll_wrapper.a /usr/local/lib/cef/libcef_dll_wrapper.a 103 | cp -r Resources/* /usr/local/lib/cef 104 | 105 | If you use a non-standard prefix (i.e. different than `/usr`, `/usr/local`, `/app`), use `CEF_PREFIX=/myprefix` 106 | to build ValaCEF. 107 | 108 | Issues 109 | ------ 110 | 111 | ### curl: (35) error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol 112 | 113 | This happens behind a HTTP proxy. 114 | 115 | * Use a VPN connection tunnelled through the proxy 116 | * unset http_proxy; unset https_proxy 117 | * nano /etc/resolv.conf 118 | 119 | Build cefclient 120 | --------------- 121 | 122 | * apt install libgtk2.0-dev libgtkglext1-dev cmake 123 | * mkdir build && cd build 124 | * cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug .. 125 | * make -j4 cefclient cefsimple 126 | -------------------------------------------------------------------------------- /CEF_UPGRADE.md: -------------------------------------------------------------------------------- 1 | CEF UPGRADE 2 | =========== 3 | 4 | * Update upstream branches 5 | 6 | ``` 7 | $ cd ~/dev/projects/cef/cef 8 | $ git remote -v show 9 | origin git@github.com:tiliado/cef.git (fetch) 10 | origin git@github.com:tiliado/cef.git (push) 11 | upstream git@bitbucket.org:chromiumembedded/cef.git (fetch) 12 | upstream git@bitbucket.org:chromiumembedded/cef.git (push) 13 | $ git fetch upstream 14 | ``` 15 | 16 | * Look at [supported upstream branches](https://bitbucket.org/chromiumembedded/cef/wiki/BranchesAndBuilding) 17 | and branch it. 18 | 19 | ``` 20 | git checkout upstream/3809 21 | git checkout -b 3809 22 | git checkout -b 3809-valacef 23 | ``` 24 | 25 | * Or update it: 26 | 27 | ``` 28 | git checkout 3809 29 | git rebase upstream/3809 30 | git checkout 3809-valacef 31 | git rebase 3809 32 | ``` 33 | 34 | * Rebase patches 35 | 36 | ``` 37 | cd ~/dev/projects/cef/cef 38 | git checkout 3809-valacef 39 | git cherry-pick ... 40 | cd /media/fenryxo/exthdd7/cef/build/ 41 | # Download latest https://bitbucket.org/chromiumembedded/cef/src/master/tools/automate/automate-git.py 42 | time python automate-git.py --download-dir=download \ 43 | --url=/home/fenryxo/dev/projects/cef/cef --branch=3809 --checkout=origin/3809-valacef \ 44 | --force-clean --force-config --x64-build --build-target=cefsimple --no-build --no-distrib 45 | cd /media/fenryxo/exthdd7/cef/build/download/chromium/src/cef/tools 46 | # Attempt to update patch files. Any merge conflicts will be highlighted in the output. 47 | python patch_updater.py 48 | cp -v /media/fenryxo/exthdd7/cef/build/download/chromium/src/cef/patch/patches/* /home/fenryxo/dev/projects/cef/cef/patch/patches 49 | ... 50 | ``` 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that the following conditions are met: 3 | 4 | 1. Redistributions of source code must retain the above copyright notice, this 5 | list of conditions and the following disclaimer. 6 | 2. Redistributions in binary form must reproduce the above copyright notice, 7 | this list of conditions and the following disclaimer in the documentation 8 | and/or other materials provided with the distribution. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 11 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 12 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 13 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 14 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 15 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 16 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 17 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 18 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 19 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | ./waf build -v 3 | sh build/launch.sh build/Cefium 4 | 5 | gdb: 6 | ./waf build -v 7 | sh build/launch.sh gdb --args build/Cefium 8 | 9 | config: 10 | ./waf configure 11 | 12 | rebuild: 13 | ./waf distclean configure 14 | ./waf build -v 15 | 16 | clean: 17 | rm -rf build 18 | 19 | push: 20 | git checkout master 21 | git push && git push --tags 22 | git checkout 76.3809.x 23 | git push && git push --tags 24 | git checkout master 25 | 26 | merge: 27 | git checkout 76.3809.x 28 | git merge --ff-only master 29 | git checkout master 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Vala-CEF 76.3809 2 | ================ 3 | 4 | ⛔ Deprecated ⛔ 5 | ---------------- 6 | 7 | 💀 Valacef is deprecated as [I haven't managed to make Nuvola work with Chromium 76 or newer](https://github.com/tiliado/valacef/issues/17). 8 | 9 | 👉 [The last working branch is 75.3770.x](https://github.com/tiliado/valacef/tree/75.3770.x). 10 | 11 | 👍 [Nuvola will be ported to QtWebEngine](https://github.com/tiliado/nuvolaruntime/issues/583). 12 | 13 | About 14 | ----- 15 | 16 | **WIP [Vala](https://wiki.gnome.org/Projects/Vala) bindings for 17 | [Chromium Embedded Framework](https://bitbucket.org/chromiumembedded/cef/)** 18 | 19 | ![Screenshot](cefium.png) 20 | 21 | Components 22 | --------- 23 | 24 | * [valacefgen](./valacefgen): Generates Vala bindings for CEF C API from CEF C header files. 25 | * [valacef](./valacef): Combines generates Vala bindings and extra goodies into a shared library. 26 | * [valacefgtk](./valacefgtk): High-level GTK+ 3 based API inspired by WebKitGTK+. 27 | * [cefium](./cefium): A demo web browser based on valacef(gtk). 28 | 29 | Dependencies 30 | ----------- 31 | 32 | * Python >= 3.6 33 | * Vala => 0.34.7 34 | * glib-2.0 >= 2.52.0 35 | * gtk+-3.0 >= 3.22.0 36 | * x11 37 | * [Patched CEF 76.3809.x](https://github.com/tiliado/cef/tree/3809-valacef) (see [BUILDING_CEF.md](./BUILDING_CEF.md)) 38 | 39 | Build Instructions 40 | ---------------- 41 | 42 | * `./waf --help` 43 | * `./waf configure` 44 | * `make run` 45 | 46 | Environment variables 47 | --------------------- 48 | 49 | ValaCEF supports following environment variables for debugging purposes: 50 | 51 | * `VALACEF_FORCE_GPU=yes` - Force GPU rasterization (disables builtin GPU blacklist). 52 | * `VALACEF_DEFAULT_RENDERING_MODE=offscreen` - Set offscreen rendering as the default rendering mode. 53 | 54 | Copyright 55 | -------- 56 | 57 | * Copyright 2017-2019 Jiří Janoušek 58 | * License: [BSD-2-Clause](./LICENSE) 59 | 60 | -------------------------------------------------------------------------------- /cefium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiliado/valacef/580706ec081299ff3eda8eecac88d8d336ec95ea/cefium.png -------------------------------------------------------------------------------- /cefium/Application.vala: -------------------------------------------------------------------------------- 1 | namespace Cefium { 2 | 3 | public class Application : Gtk.Application { 4 | private BrowserWindow main_window; 5 | private string versions; 6 | 7 | public Application(string versions) { 8 | GLib.Object(application_id: "eu.tiliado.Cefium", flags: ApplicationFlags.FLAGS_NONE); 9 | this.versions = versions; 10 | } 11 | 12 | protected override void startup() { 13 | base.startup(); 14 | var source = new IdleSource(); 15 | source.set_callback(() => { 16 | CefGtk.run_main_loop(); 17 | return false; 18 | }); 19 | source.set_priority(GLib.Priority.HIGH); 20 | source.set_can_recurse(false); 21 | source.attach(MainContext.ref_thread_default()); 22 | } 23 | 24 | protected override void activate () { 25 | create_main_window(); 26 | main_window.present(); 27 | } 28 | 29 | private void create_main_window() { 30 | if (main_window == null) { 31 | var ctx = new CefGtk.WebContext(GLib.Environment.get_user_config_dir() + "/cefium"); 32 | var web_view = new CefGtk.WebView(ctx); 33 | web_view.add_autoloaded_renderer_extension( 34 | Environment.get_variable("CEFIUM_RENDERER_EXTENSION") ?? LIBDIR + "/libcefiumrendererextension.so", 35 | new Variant[]{"hello", 123}); 36 | var win = new BrowserWindow(this, web_view, opt_url ?? "https://github.com/tiliado/valacef/wiki", versions); 37 | win.quit.connect(() => {CefGtk.quit_main_loop(); quit();}); 38 | win.set_default_size(1100, 800); 39 | main_window = win; 40 | add_window(win); 41 | } 42 | } 43 | } 44 | 45 | } // namespace Cefium 46 | -------------------------------------------------------------------------------- /cefium/BrowserWindow.vala: -------------------------------------------------------------------------------- 1 | namespace Cefium { 2 | 3 | public class BrowserWindow : Gtk.ApplicationWindow { 4 | public Gtk.Grid grid; 5 | private Gtk.HeaderBar header_bar; 6 | private Gtk.HeaderBar tool_bar; 7 | private Gtk.Label status_bar; 8 | private string? default_status; 9 | private CefGtk.WebView web_view; 10 | private URLBar url_bar; 11 | private string home_uri; 12 | private unowned Gtk.Application app; 13 | private Gtk.Overlay overlay; 14 | Gtk.EventBox box; 15 | 16 | public BrowserWindow(Gtk.Application app, CefGtk.WebView web_view, string home_uri, string? default_status) { 17 | this.app = app; 18 | this.default_status = default_status; 19 | this.web_view = web_view; 20 | this.home_uri = home_uri; 21 | override_background_color(Gtk.StateFlags.NORMAL, {0.4, 0.9, 0.4, 1.0}); 22 | overlay = new Gtk.Overlay(); 23 | header_bar = new Gtk.HeaderBar(); 24 | header_bar.show_close_button = true; 25 | header_bar.show(); 26 | set_titlebar(header_bar); 27 | grid = new Gtk.Grid(); 28 | grid.hexpand = grid.vexpand = true; 29 | add(grid); 30 | tool_bar = new Gtk.HeaderBar(); 31 | 32 | add_simple_action("go-back", "Left").activate.connect(() => web_view.go_back()); 33 | add_simple_action("go-forward", "Right").activate.connect(() => web_view.go_forward()); 34 | add_simple_action("go-home", "Home").activate.connect(() => go_home()); 35 | add_simple_action("reload", "r").activate.connect(() => web_view.reload()); 36 | add_simple_action("abort", "Escape").activate.connect(() => web_view.stop_load()); 37 | add_simple_action("zoom-out", "minus").activate.connect(() => web_view.zoom_out()); 38 | add_simple_action("zoom-reset", "0").activate.connect(() => web_view.zoom_reset()); 39 | add_simple_action("zoom-in", "plus").activate.connect(() => web_view.zoom_in()); 40 | add_simple_action("edit-select-all", "A").activate.connect(() => web_view.edit_select_all()); 41 | add_simple_action("edit-paste").activate.connect(() => web_view.edit_paste()); 42 | add_simple_action("edit-copy").activate.connect(() => web_view.edit_copy()); 43 | add_simple_action("edit-cut").activate.connect(() => web_view.edit_cut()); 44 | add_simple_action("edit-redo").activate.connect(() => web_view.edit_redo()); 45 | add_simple_action("edit-undo").activate.connect(() => web_view.edit_undo()); 46 | add_simple_action("snapshot").activate.connect(() => take_snapshot()); 47 | add_simple_action("open-developer-tools", "c").activate.connect(() => web_view.open_developer_tools()); 48 | add_simple_action("quit", "q").activate.connect(() => quit()); 49 | 50 | add_buttons({ 51 | "(", "go-previous-symbolic|go-back", "go-next-symbolic|go-forward", ")", 52 | "(", "go-home-symbolic|go-home", "view-refresh-symbolic|reload", "process-stop-symbolic|abort", ")", 53 | "|", 54 | "(", "camera-photo-symbolic|snapshot", "preferences-other-symbolic|open-developer-tools", ")", 55 | "(", "zoom-in-symbolic|zoom-in", "zoom-original-symbolic|zoom-reset", "zoom-out-symbolic|zoom-out", ")", 56 | "(", "edit-undo-symbolic|edit-undo", "edit-redo-symbolic|edit-redo", ")", 57 | "(", "edit-cut-symbolic|edit-cut", "edit-copy-symbolic|edit-copy", 58 | "edit-paste-symbolic|edit-paste", "edit-select-all-symbolic|edit-select-all", ")", 59 | }); 60 | 61 | url_bar = new URLBar(null); 62 | url_bar.hexpand = true; 63 | url_bar.response.connect(on_url_bar_response); 64 | tool_bar.custom_title = url_bar; 65 | status_bar = new Gtk.Label(default_status); 66 | status_bar.hexpand = true; 67 | status_bar.halign = Gtk.Align.START; 68 | status_bar.margin = 5; 69 | status_bar.ellipsize = Pango.EllipsizeMode.MIDDLE; 70 | web_view.hexpand = web_view.vexpand = true; 71 | overlay.add(web_view); 72 | 73 | box = new Gtk.EventBox(); 74 | box.margin = 200; 75 | box.set_app_paintable(false); 76 | box.set_visual(box.get_screen().get_rgba_visual()); 77 | box.override_background_color(Gtk.StateFlags.NORMAL, {0.5, 0.5, 1.0, 0.5}); 78 | var button = new Gtk.Button.with_label("Close overlay"); 79 | button.vexpand = button.hexpand = false; 80 | button.valign = button.halign = Gtk.Align.CENTER; 81 | button.clicked.connect((b) => {button.get_parent().get_parent().remove(button.get_parent());}); 82 | button.show(); 83 | box.add(button); 84 | box.show(); 85 | overlay.add_overlay(box); 86 | overlay.hexpand = overlay.vexpand = true; 87 | grid.attach(tool_bar, 0, 0, 1, 1); 88 | grid.attach(overlay, 0, 1, 1, 1); 89 | grid.attach(status_bar, 0, 5, 1, 1); 90 | grid.show_all(); 91 | web_view.notify.connect_after(on_web_view_notify); 92 | update("title"); 93 | update("uri"); 94 | update("status-message"); 95 | update("is-loading"); 96 | update("can-go-back"); 97 | update("can-go-forward"); 98 | go_home(); 99 | delete_event.connect(() => {hide(); quit(); return true;}); 100 | } 101 | 102 | public signal void quit(); 103 | 104 | public void go_home() { 105 | web_view.load_uri(home_uri); 106 | } 107 | 108 | private GLib.SimpleAction add_simple_action(string action_name, string? accelerator=null) { 109 | var action = new GLib.SimpleAction(action_name, null); 110 | action.set_enabled(true); 111 | add_action(action); 112 | if (accelerator != null) { 113 | app.add_accelerator(accelerator, "win." + action_name, null); 114 | } 115 | return action; 116 | } 117 | 118 | private void add_buttons(string[] buttons) { 119 | Gtk.Grid? grid = null; 120 | bool start = true; 121 | foreach (var entry in buttons) { 122 | if (entry == "(") { 123 | grid = new Gtk.Grid(); 124 | grid.orientation = Gtk.Orientation.HORIZONTAL; 125 | grid.get_style_context().add_class("linked"); 126 | grid.hexpand = grid.vexpand = false; 127 | grid.halign = grid.valign = Gtk.Align.CENTER; 128 | if (start) { 129 | tool_bar.pack_start(grid); 130 | } else { 131 | tool_bar.pack_end(grid); 132 | } 133 | } else if (entry == ")") { 134 | grid = null; 135 | } else if (entry == "|") { 136 | start = false; 137 | } else { 138 | var data = entry.split("|"); 139 | var button = new Gtk.Button.from_icon_name(data[0]); 140 | button.vexpand = false; 141 | button.valign = Gtk.Align.CENTER; 142 | button.action_name = "win." + data[1]; 143 | if (grid != null) { 144 | grid.add(button); 145 | } else if (start) { 146 | tool_bar.pack_start(button); 147 | } else { 148 | tool_bar.pack_end(button); 149 | } 150 | } 151 | } 152 | } 153 | 154 | private void on_web_view_notify(GLib.Object? o, ParamSpec param) { 155 | update(param.name); 156 | } 157 | 158 | private void update(string property) { 159 | switch (property) { 160 | case "title": 161 | var title = web_view.title; 162 | title = title != null && title != "" ? title + " ~~ " : ""; 163 | this.title = title + "Cefium browser " + Cef.get_valacef_version(); 164 | break; 165 | case "uri": 166 | url_bar.url = web_view.uri ?? ""; 167 | web_view.send_message("uri", {new Variant.string(url_bar.url)}); 168 | break; 169 | case "status-message": 170 | status_bar.label = web_view.status_message ?? default_status ?? ""; 171 | break; 172 | case "is-loading": 173 | set_action_enabled("abort", web_view.is_loading); 174 | break; 175 | case "can-go-back": 176 | set_action_enabled("go-back", web_view.can_go_back); 177 | break; 178 | case "can-go-forward": 179 | set_action_enabled("go-forward", web_view.can_go_forward); 180 | break; 181 | case "fullscreen": 182 | if (web_view.fullscreen) { 183 | this.tool_bar.hide(); 184 | this.status_bar.hide(); 185 | fullscreen(); 186 | } else { 187 | unfullscreen(); 188 | this.tool_bar.show(); 189 | this.status_bar.show(); 190 | } 191 | break; 192 | } 193 | } 194 | 195 | public void set_action_enabled(string name, bool enabled) { 196 | var action = lookup_action(name) as GLib.SimpleAction; 197 | return_if_fail(action != null); 198 | action.set_enabled(enabled); 199 | } 200 | 201 | private void on_url_bar_response(bool accepted) { 202 | if (accepted) { 203 | web_view.load_uri(url_bar.url); 204 | } 205 | } 206 | 207 | private void take_snapshot() { 208 | Gdk.Pixbuf snapshot = web_view.get_snapshot(); 209 | if (snapshot != null) { 210 | var win = new Gtk.Window(); 211 | var image = new Gtk.Image.from_pixbuf(snapshot); 212 | win.override_background_color(Gtk.StateFlags.NORMAL, {0.4, 0.9, 0.4, 1.0}); 213 | win.add(image); 214 | win.show_all(); 215 | } 216 | } 217 | } 218 | 219 | } // namespace Cefium 220 | -------------------------------------------------------------------------------- /cefium/Cefium.vala: -------------------------------------------------------------------------------- 1 | namespace Cefium { 2 | 3 | private extern const string LIBDIR; 4 | 5 | static bool opt_disable_widevine = false; 6 | static string? opt_flash_dir = null; 7 | static string? opt_url = null; 8 | public const OptionEntry[] opt_main_options = { 9 | {"url", 'U', 0, OptionArg.STRING, ref opt_url, "Load URL", "URL" }, 10 | {"disable-widevine", 0, 0, OptionArg.NONE, ref opt_disable_widevine, 11 | "Disable widevine DRM plugin.", null}, 12 | {"flash-dir", 0, 0, OptionArg.STRING, ref opt_flash_dir, 13 | "Adobe Flash plugin directory.", null}, 14 | {null} 15 | }; 16 | 17 | int main(string[] argv) { 18 | Environment.set_variable("GDK_BACKEND", "x11", true); 19 | 20 | try { 21 | var opt_context = new OptionContext("- Cefium %s".printf(Cef.get_valacef_version())); 22 | opt_context.set_help_enabled(true); 23 | opt_context.add_main_entries(opt_main_options, null); 24 | opt_context.set_ignore_unknown_options(false); 25 | opt_context.parse(ref argv); 26 | } catch (OptionError e) { 27 | stderr.printf("Error: Option parsing failed: %s\n", e.message); 28 | return 1; 29 | } 30 | var versions = "Cefium browser powered by ValaCEF %s, CEF %s, Chromium %s, GTK+ %u.%u.%u".printf( 31 | Cef.get_valacef_version(), Cef.get_cef_version(), Cef.get_chromium_version(), 32 | Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version()); 33 | message("Versions: %s", versions); 34 | unowned string[]? gtk_argv = null; 35 | Gtk.init(ref gtk_argv); 36 | var window = new Gtk.Window(); 37 | window.show(); 38 | var flags = new CefGtk.InitFlags(); 39 | flags.auto_play_policy = CefGtk.AutoPlayPolicy.NO_USER_GESTURE_REQUIRED; 40 | CefGtk.init(flags, window.scale_factor * 1.0, opt_disable_widevine? null : Cef.get_cef_lib_dir(), opt_flash_dir); 41 | window.destroy(); 42 | window = null; 43 | var app = new Application(versions); 44 | var result = app.run(gtk_argv); 45 | CefGtk.shutdown(); 46 | return result; 47 | } 48 | 49 | } // namespace Cefium 50 | -------------------------------------------------------------------------------- /cefium/CefiumRendererExtension.vala: -------------------------------------------------------------------------------- 1 | namespace Cefium { 2 | 3 | 4 | } // namespace Cefium 5 | 6 | public void init_renderer_extension(CefGtk.RendererContext ctx, int browser, Variant?[] parameters) { 7 | message("Extension for browser(%d)'s renderer.", browser); 8 | for (var i = 0; i < parameters.length; i++) { 9 | message("init_renderer_extension[%d]: %s", i, parameters[i] == null ? "null" : parameters[i].print(false)); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /cefium/URLBar.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Jiří Janoušek 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | namespace Cefium { 26 | 27 | public class URLBar: Gtk.Grid { 28 | public Gtk.Entry entry; 29 | public string? url { 30 | get {return entry.text;} 31 | set {entry.text = value;} 32 | } 33 | private Gtk.Button go_button; 34 | 35 | public URLBar(string? url) { 36 | orientation = Gtk.Orientation.HORIZONTAL; 37 | hexpand = true; 38 | halign = Gtk.Align.FILL; 39 | margin_start = margin_end = 20; 40 | get_style_context().add_class("linked"); 41 | entry = new Gtk.Entry(); 42 | if (url != null) { 43 | entry.text = url; 44 | } 45 | entry.hexpand = true; 46 | entry.halign = Gtk.Align.FILL; 47 | entry.activate.connect(on_go_button_clicked); 48 | entry.show(); 49 | add(entry); 50 | go_button = new Gtk.Button.from_icon_name("media-playback-start-symbolic"); 51 | go_button.clicked.connect(on_go_button_clicked); 52 | go_button.show(); 53 | add(go_button); 54 | } 55 | 56 | ~URLBar() { 57 | go_button.clicked.disconnect(on_go_button_clicked); 58 | entry.activate.disconnect(on_go_button_clicked); 59 | } 60 | 61 | public signal void response(bool accepted); 62 | 63 | private void on_go_button_clicked() { 64 | response(true); 65 | } 66 | } 67 | 68 | } // namespace Cefium 69 | -------------------------------------------------------------------------------- /cefsubprocess/Subprocess.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | int main(string[] argv) { 4 | Cef.String cef_path = {}; 5 | Cef.set_string(&cef_path, Cef.get_cef_lib_dir()); 6 | Cef.enable_highdpi_support(); 7 | var app = new CefGtk.RenderProcess(); 8 | Cef.MainArgs main_args = {argv.length, argv}; 9 | var code = Cef.execute_process(main_args, app, null); 10 | if (code >= 0) { 11 | return code; 12 | } else { 13 | assert_not_reached(); 14 | } 15 | } 16 | 17 | } // namespace CefSubprocess 18 | -------------------------------------------------------------------------------- /genvalacef.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from valacefgen.cparser import Parser, Naming 4 | from valacefgen.types import Repository, Function 5 | from valacefgen.utils import TypeInfo 6 | 7 | try: 8 | CEF_INCLUDE_DIR = sys.argv[1] 9 | except IndexError: 10 | CEF_INCLUDE_DIR = "/app/include/cef/include" 11 | try: 12 | TOP = sys.argv[2] or '.' 13 | except IndexError: 14 | TOP = '.' 15 | try: 16 | OUT = sys.argv[3] or '.' 17 | except IndexError: 18 | OUT = 'build' 19 | 20 | header_files = [ 21 | ('%s/overrides/cef_primitives.h' % TOP, 'capi/cef_base_capi.h'), 22 | ('%s/overrides/cef_base.h' % TOP, 'capi/cef_base_capi.h'), 23 | ('%s/overrides/cef_string.h' % TOP, 'capi/cef_base_capi.h'), 24 | ('%s/overrides/cef_error_codes.h' % TOP, 'internal/cef_types.h'), 25 | 'internal/cef_types_linux.h', 26 | 'internal/cef_types.h', 27 | 'internal/cef_string_list.h', 28 | 'capi/cef_app_capi.h', 29 | 'capi/cef_base_capi.h', 30 | 'internal/cef_time.h', 31 | 'capi/cef_audio_handler_capi.h', 32 | 'capi/cef_command_line_capi.h', 33 | 'capi/cef_browser_process_handler_capi.h', 34 | 'capi/cef_render_process_handler_capi.h', 35 | 'capi/cef_resource_bundle_handler_capi.h', 36 | 'capi/cef_resource_handler_capi.h', 37 | 'capi/cef_resource_request_handler_capi.h', 38 | 'capi/cef_request_callback_capi.h', 39 | 'capi/cef_urlrequest_capi.h', 40 | 'capi/cef_scheme_capi.h', 41 | 'capi/cef_request_capi.h', 42 | 'capi/cef_browser_capi.h', 43 | 'capi/cef_path_util_capi.h', 44 | 'capi/cef_client_capi.h', 45 | 'capi/cef_dialog_handler_capi.h', 46 | 'capi/cef_keyboard_handler_capi.h', 47 | 'capi/cef_process_message_capi.h', 48 | 'capi/cef_life_span_handler_capi.h', 49 | 'capi/cef_load_handler_capi.h', 50 | 'capi/cef_drag_handler_capi.h', 51 | 'capi/cef_focus_handler_capi.h', 52 | 'capi/cef_context_menu_handler_capi.h', 53 | 'capi/cef_render_handler_capi.h', 54 | 'capi/cef_jsdialog_handler_capi.h', 55 | 'capi/cef_request_handler_capi.h', 56 | 'capi/cef_download_handler_capi.h', 57 | 'capi/cef_find_handler_capi.h', 58 | 'capi/cef_display_handler_capi.h', 59 | 'capi/cef_frame_capi.h', 60 | 'capi/cef_menu_model_capi.h', 61 | 'capi/cef_menu_model_delegate_capi.h', 62 | 'capi/cef_download_item_capi.h', 63 | 'capi/cef_drag_data_capi.h', 64 | 'capi/cef_image_capi.h', 65 | 'capi/cef_string_visitor_capi.h', 66 | 'capi/cef_dom_capi.h', 67 | 'capi/cef_v8_capi.h', 68 | 'capi/cef_stream_capi.h', 69 | 'capi/cef_values_capi.h', 70 | 'capi/cef_accessibility_handler_capi.h', 71 | 'capi/cef_response_capi.h', 72 | 'capi/cef_task_capi.h', 73 | 'capi/cef_response_filter_capi.h', 74 | 'capi/cef_ssl_info_capi.h', 75 | 'capi/cef_auth_callback_capi.h', 76 | 'capi/cef_x509_certificate_capi.h', 77 | 'capi/cef_request_context_capi.h', 78 | 'capi/cef_request_context_handler_capi.h', 79 | 'capi/cef_cookie_capi.h', 80 | 'capi/cef_web_plugin_capi.h', 81 | 'capi/cef_callback_capi.h', 82 | 'capi/cef_print_handler_capi.h', 83 | 'capi/cef_print_settings_capi.h', 84 | 'capi/cef_navigation_entry_capi.h', 85 | 'capi/cef_ssl_status_capi.h', 86 | 'capi/cef_extension_capi.h', 87 | 'capi/cef_extension_handler_capi.h', 88 | ] 89 | 90 | ignore = { 91 | 'XEvent', 92 | 'XDisplay', 93 | 'cef_get_xdisplay', 94 | 'TID_FILE', 95 | } 96 | 97 | base_structs = { 98 | "cef_base_scoped_t", 99 | } 100 | 101 | base_classes = { 102 | "cef_base_ref_counted_t", 103 | } 104 | 105 | 106 | class Overrides: 107 | def param__cef_string_utf8_to_utf16__src(self, info: TypeInfo): 108 | info.c_type = 'string' 109 | 110 | def param__cef_string_utf8_to_utf16__output(self, info: TypeInfo): 111 | info.ref = True 112 | 113 | def param__cef_string_utf16_to_utf8_output(self, info: TypeInfo): 114 | info.ref = True 115 | 116 | parser = Parser(Naming('Cef'), Repository('Cef', Overrides()), ignore, base_structs, base_classes) 117 | 118 | for entry in header_files: 119 | if isinstance(entry, str): 120 | c_include_path = entry 121 | path = os.path.join(CEF_INCLUDE_DIR, entry) 122 | else: 123 | path, c_include_path = entry 124 | 125 | parser.parse_header(path, c_include_path) 126 | 127 | repo = parser.repo 128 | ref_func = Function('cef_base_ref_counted_ref', 'ref', "valacef_api.h") 129 | unref_func = Function('cef_base_ref_counted_unref', 'unref', "valacef_api.h") 130 | 131 | base_refcounted = repo.structs['cef_base_ref_counted_t'] 132 | base_refcounted.add_method(ref_func) 133 | base_refcounted.add_method(unref_func) 134 | base_refcounted.set_ref_counting(ref_func.c_name, unref_func.c_name) 135 | 136 | ref_func = Function('cef_base_ref_counted_ref', 'ref', "capi/cef_base_capi.h", 137 | params=[("cef_base_ref_counted_t*", "self")], 138 | body=['self->add_ref(self);', 'return self;'], 139 | ret_type="cef_base_ref_counted_t*") 140 | unref_func = Function('cef_base_ref_counted_unref', 'unref', "capi/cef_base_capi.h", 141 | params=[("cef_base_ref_counted_t*", "self")], 142 | body=['self->release(self);']) 143 | parser.add_c_glue(ref_func, unref_func) 144 | 145 | add_ref_func = Function( 146 | 'cef_base_ref_counted_add_ref', 'base_ref_counted_add_ref', 'capi/cef_base_capi.h;stdio.h', 147 | params=[('void*', 'self_ptr')], 148 | body=[ 149 | 'cef_base_ref_counted_t* self = (cef_base_ref_counted_t*) self_ptr;', 150 | 'char* pointer = (char*) self + (self->size - (sizeof(int) > sizeof(void*) ? sizeof(int) : sizeof(void*)));', 151 | 'volatile int* ref_count = (volatile int*) pointer;', 152 | '// printf("%p++ (%d) size: %d\\n", self, *ref_count + 1, (int) self->size);', 153 | 'g_atomic_int_inc(ref_count);', 154 | ]) 155 | release_ref_func = Function( 156 | 'cef_base_ref_counted_release_ref', 'base_ref_counted_release_ref', 'stdlib.h;capi/cef_base_capi.h;stdio.h', 'int', 157 | params=[('void*', 'self_ptr')], 158 | body=[ 159 | 'gboolean is_dead = FALSE;' 160 | 'cef_base_ref_counted_t* self = (cef_base_ref_counted_t*) self_ptr;', 161 | 'char* pointer = (char*) self + (self->size - (sizeof(int) > sizeof(void*) ? sizeof(int) : sizeof(void*)));', 162 | 'volatile int* ref_count = (volatile int*) pointer;', 163 | '// printf("%p-- (%d) size: %d\\n", self, *ref_count - 1, (int) self->size);', 164 | 'is_dead = g_atomic_int_dec_and_test(ref_count);', 165 | 'if (is_dead) {', 166 | ' // printf("%p dealloc!\\n", self);', 167 | ' GData** priv_data = (GData**)(pointer - sizeof(void*));', 168 | ' g_datalist_clear(priv_data);', 169 | ' free(self_ptr);', 170 | '}', 171 | 'return is_dead;' 172 | ]) 173 | has_one_ref_func = Function( 174 | 'cef_base_ref_counted_has_one_ref', 'base_ref_counted_has_one_ref', 'capi/cef_base_capi.h;stdio.h', 'int', 175 | params=[('void*', 'self_ptr')], 176 | body=[ 177 | 'cef_base_ref_counted_t* self = (cef_base_ref_counted_t*) self_ptr;', 178 | 'char* pointer = (char*) self + (self->size - (sizeof(int) > sizeof(void*) ? sizeof(int) : sizeof(void*)));', 179 | 'volatile int* ref_count = (volatile int*) pointer;', 180 | '// printf("%p?? %d size: %d\\n", self, *ref_count, (int) self->size);', 181 | 'return g_atomic_int_get(ref_count) == 1;', 182 | ]) 183 | init_refcounting_func = Function( 184 | 'cef_base_ref_counted_init_ref_counting', 'init_refcounting', 'capi/cef_base_capi.h;stdio.h', 185 | params=[('void*', 'self_ptr'), ('size_t', 'base_size'), ('size_t', 'derived_size')], 186 | body=[ 187 | 'cef_base_ref_counted_t* self = (cef_base_ref_counted_t*) self_ptr;', 188 | 'self->size = derived_size;', 189 | 'self->add_ref = %s;' % add_ref_func.c_name, 190 | 'self->release = %s;' % release_ref_func.c_name, 191 | 'self->has_one_ref = %s;' % has_one_ref_func.c_name, 192 | 'g_assert(base_size + (sizeof(int) > sizeof(void*) ? sizeof(int) : sizeof(void*)) + sizeof(void*) == ' 193 | 'derived_size);', 194 | 'char* pointer = (char*) self + (self->size - (sizeof(int) > sizeof(void*) ? sizeof(int) : sizeof(void*)));', 195 | 'volatile int* ref_count = (volatile int*) pointer;', 196 | 'g_atomic_int_set(ref_count, 1);', 197 | '// printf("%p=%d size: %d\\n", self, *ref_count, (int) self->size);', 198 | ]) 199 | parser.add_c_glue(add_ref_func, release_ref_func, has_one_ref_func, init_refcounting_func) 200 | 201 | utf16_to_utf8_func = Function( 202 | 'cef_utf16_string_to_vala_string', 'get_string', 'capi/cef_base_capi.h;stdio.h', 'char*', 203 | params=[('cef_string_t*', 'utf16_str')], 204 | body=[ 205 | 'if (utf16_str == NULL) return NULL;', 206 | 'cef_string_utf8_t utf8_str = {};', 207 | 'cef_string_utf16_to_utf8(utf16_str->str, utf16_str->length, &utf8_str);', 208 | 'return utf8_str.str;', 209 | ]) 210 | parser.add_c_glue(utf16_to_utf8_func) 211 | 212 | utf16_to_utf8_func = Function( 213 | 'cef_utf16_string_to_vala_string', 'get_string', 'valacef_api.h', 'char*', 214 | params=[('cef_string_t*', 'utf16_str')]) 215 | repo.add_function(utf16_to_utf8_func) 216 | 217 | utf8_to_utf16_func = Function( 218 | 'cef_utf16_string_from_vala_string', 'set_string', 'string.h;capi/cef_base_capi.h;stdio.h', 219 | params=[('cef_string_t*', 'utf16_str'), ('char*', 'str')], 220 | body=[ 221 | 'cef_string_utf8_to_utf16(str, strlen(str), utf16_str);', 222 | ]) 223 | parser.add_c_glue(utf8_to_utf16_func) 224 | 225 | utf8_to_utf16_func = Function( 226 | 'cef_utf16_string_from_vala_string', 'set_string', 'valacef_api.h', 227 | params=[('cef_string_t*', 'utf16_str'), ('char*', 'str')]) 228 | repo.add_function(utf8_to_utf16_func) 229 | 230 | vapi, vala, c_header, c_glue = parser.finish() 231 | 232 | os.makedirs(OUT, exist_ok=True) 233 | with open(OUT + "/valacef_api.vapi", "wt") as f: 234 | f.write(vapi) 235 | 236 | with open(OUT + "/cef.vala", "wt") as f: 237 | f.write(vala) 238 | 239 | with open(OUT + "/valacef_api.c", "wt") as f: 240 | f.write(c_glue) 241 | 242 | with open(OUT + "/valacef_api.h", "wt") as f: 243 | f.write(c_header) 244 | -------------------------------------------------------------------------------- /launch.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export LD_LIBRARY_PATH=@CEF_LIB_DIR@:@OUT@ 3 | export CEF_SUBPROCESS_PATH="@OUT@/ValacefSubprocess" 4 | export CEFIUM_RENDERER_EXTENSION="@OUT@/libcefiumrendererextension.so" 5 | exec "$@" 6 | -------------------------------------------------------------------------------- /overrides/cef_base.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | template 4 | class CefRefPtr { 5 | public: 6 | // Constructor. Defaults to initializing with NULL. 7 | CefRefPtr() : CefRefPtr(NULL); 8 | // Constructor. Takes ownership of p. 9 | explicit CefRefPtr(T* t); 10 | 11 | T& operator*() const; 12 | T* operator->() const; 13 | }; 14 | 15 | template 16 | class CefRawPtr { 17 | public: 18 | CefRawPtr() : CefRawPtr(NULL); 19 | CefRawPtr(T* p); 20 | // CefRawPtr(const CefRawPtr& r) : ptr_(r.ptr_) {} 21 | T* get() const; 22 | T* operator->() const; 23 | CefRawPtr& operator=(T* p); 24 | CefRawPtr& operator=(const CefRawPtr& r); 25 | }; 26 | 27 | 28 | */ 29 | 30 | //typedef CefStringBase CefStringUTF8; 31 | //typedef CefStringUTF8 CefString; 32 | 33 | 34 | 35 | 36 | typedef cef_string_utf16_t cef_string_t; 37 | typedef unsigned long cef_window_handle_t; 38 | typedef cef_string_utf16_t* cef_string_userfree_utf16_t; 39 | typedef cef_string_userfree_utf16_t cef_string_userfree_t; 40 | typedef void* cef_string_map_t; 41 | typedef void* cef_string_multimap_t; 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /overrides/cef_primitives.h: -------------------------------------------------------------------------------- 1 | 2 | typedef short unsigned int char16; 3 | typedef char cef_char_t; 4 | typedef void* cef_event_handle_t; 5 | typedef unsigned long cef_cursor_handle_t; 6 | -------------------------------------------------------------------------------- /overrides/cef_string.h: -------------------------------------------------------------------------------- 1 | typedef struct _cef_string_utf8_t { 2 | char* str; 3 | size_t length; 4 | void (*dtor)(char* str); 5 | } cef_string_utf8_t; 6 | 7 | typedef struct _cef_string_utf16_t { 8 | char16* str; 9 | size_t length; 10 | void (*dtor)(char16* str); 11 | } cef_string_utf16_t; 12 | 13 | 14 | /// 15 | // These functions convert between UTF-8, -16, and -32 strings. They are 16 | // potentially slow so unnecessary conversions should be avoided. The best 17 | // possible result will always be written to |output| with the boolean return 18 | // value indicating whether the conversion is 100% valid. 19 | /// 20 | int cef_string_utf8_to_utf16(const char* src, size_t src_len, cef_string_t* output); 21 | 22 | /// 23 | // These functions convert between UTF-8, -16, and -32 strings. They are 24 | // potentially slow so unnecessary conversions should be avoided. The best 25 | // possible result will always be written to |output| with the boolean return 26 | // value indicating whether the conversion is 100% valid. 27 | /// 28 | int cef_string_utf16_to_utf8(const char16* src, size_t src_len, cef_string_utf8_t* output); 29 | 30 | /// 31 | // These functions set string values. If |copy| is true (1) the value will be 32 | // copied instead of referenced. It is up to the user to properly manage 33 | // the lifespan of references. 34 | /// 35 | int cef_string_utf16_set(const char16* src, size_t src_len, cef_string_utf16_t* output, int copy); 36 | 37 | /// 38 | // Convenience macros for copying values. 39 | /// 40 | int cef_string_utf16_copy(const char16* src, size_t src_len, cef_string_utf16_t* output); 41 | 42 | /// 43 | // These functions clear string values. The structure itself is not freed. 44 | /// 45 | void cef_string_utf16_clear(cef_string_utf16_t* str); 46 | 47 | /// 48 | // These functions free the string structure allocated by the associated 49 | // alloc function. Any string contents will first be cleared. 50 | /// 51 | void cef_string_userfree_utf16_free(cef_string_userfree_utf16_t str); 52 | -------------------------------------------------------------------------------- /utils/sysinfo.vala: -------------------------------------------------------------------------------- 1 | namespace SysInfo { 2 | 3 | Gtk.Window window; 4 | 5 | int main(string[] argv) { 6 | unowned string[] gtk_argv = null; 7 | Gtk.init(ref gtk_argv); 8 | window = new Gtk.Window(); 9 | window.set_default_size(100, 100); 10 | window.title = "Hello."; 11 | window.add(new Gtk.Label("Hello.")); 12 | window.show_all(); 13 | Idle.add(() => {collect_info(); Gtk.main_quit(); return false;}); 14 | Gtk.main(); 15 | return 0; 16 | } 17 | 18 | void collect_info() { 19 | print_dpi(); 20 | ln(); 21 | print_properties(Gtk.Settings.get_default()); 22 | } 23 | 24 | void ln () { 25 | stdout.puts("\n"); 26 | } 27 | 28 | void print_properties(GLib.Object object) { 29 | unowned string name = object.get_type().name(); 30 | stdout.printf("==== %s properties ====\n", name); 31 | unowned ObjectClass klass = object.get_class(); 32 | (unowned ParamSpec)[] properties = klass.list_properties(); 33 | foreach (unowned ParamSpec prop in properties) { 34 | unowned Type type = prop.value_type; 35 | if (type == typeof(string)) { 36 | string? str_val = null; 37 | object.get(prop.name, out str_val); 38 | if (str_val == null) { 39 | stdout.printf("%s = null string\n", prop.name); 40 | } else { 41 | stdout.printf("%s = \"%s\"\n", prop.name, str_val); 42 | } 43 | } else if (type == typeof(int)) { 44 | int int_val = 0; 45 | object.get(prop.name, out int_val); 46 | stdout.printf("%s = %d\n", prop.name, int_val); 47 | } else if (type == typeof(uint)) { 48 | uint uint_val = 0; 49 | object.get(prop.name, out uint_val); 50 | stdout.printf("%s = %u\n", prop.name, uint_val); 51 | } else if (type == typeof(bool)) { 52 | bool bool_val = false; 53 | object.get(prop.name, out bool_val); 54 | stdout.printf("%s = %s\n", prop.name, bool_val ? "true" : "false"); 55 | } else { 56 | stdout.printf("%s = unknown type %s\n", prop.name, type.name()); 57 | } 58 | } 59 | } 60 | 61 | void print_dpi() { 62 | stdout.printf("==== DPI ====\n"); 63 | double xft_dpi = 1.0 * Gtk.Settings.get_default().gtk_xft_dpi / 1024; 64 | stdout.printf("Gtk.Settings.gtk_xft_dpi = %f\n", xft_dpi); 65 | stdout.printf(" calcd scaling factor = %f\n", xft_dpi / 96); 66 | stdout.printf("Gtk.Widget.scale_factor = %d\n", window.scale_factor); 67 | stdout.printf("Gdk.Window.scale_factor = %d\n", window.get_window().get_scale_factor()); 68 | unowned Gdk.Display display = Gdk.Display.get_default(); 69 | int n_monitors = display.get_n_monitors(); 70 | for (var i = 0; i < n_monitors; i++) { 71 | stdout.printf( 72 | "Gdk.Monitor[%d].scale_factor = %d\n", 73 | i, display.get_monitor(i).get_scale_factor()); 74 | } 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /valacef/Checks.vala: -------------------------------------------------------------------------------- 1 | namespace Cef { 2 | 3 | public void assert_renderer_thread(string context=GLib.Log.METHOD) { 4 | if (Cef.currently_on(Cef.ThreadId.RENDERER) == 0) { 5 | error("%s: Not on Renderer thread.", context); 6 | } 7 | } 8 | 9 | public void assert_browser_ui_thread(string context=GLib.Log.METHOD) { 10 | if (Cef.currently_on(Cef.ThreadId.UI) == 0) { 11 | error("%s: Not on Browser UI thread.", context); 12 | } 13 | } 14 | 15 | public void assert_browser_io_thread(string context=GLib.Log.METHOD) { 16 | if (Cef.currently_on(Cef.ThreadId.IO) == 0) { 17 | error("%s: Not on Browser IO thread.", context); 18 | } 19 | } 20 | 21 | public bool on_renderer_thread(string context=GLib.Log.METHOD) { 22 | return Cef.currently_on(Cef.ThreadId.RENDERER) == 1; 23 | } 24 | 25 | public bool on_browser_ui_thread(string context=GLib.Log.METHOD) { 26 | return Cef.currently_on(Cef.ThreadId.UI) == 1; 27 | } 28 | 29 | public bool on_browser_io_thread(string context=GLib.Log.METHOD) { 30 | return Cef.currently_on(Cef.ThreadId.IO) == 1; 31 | } 32 | 33 | public int get_current_thread_id() { 34 | Cef.ThreadId[] ids = { 35 | Cef.ThreadId.UI, 36 | Cef.ThreadId.FILE_BACKGROUND, 37 | Cef.ThreadId.FILE_USER_BLOCKING, 38 | Cef.ThreadId.FILE_USER_VISIBLE, 39 | Cef.ThreadId.PROCESS_LAUNCHER, 40 | Cef.ThreadId.IO, 41 | Cef.ThreadId.RENDERER 42 | }; 43 | foreach (var id in ids) { 44 | if (Cef.currently_on(id) == 1) { 45 | return id; 46 | } 47 | } 48 | return -1; 49 | } 50 | 51 | public string? get_current_thread_name() { 52 | var id = get_current_thread_id(); 53 | return id == -1 ? null : ((Cef.ThreadId) id).to_string(); 54 | } 55 | 56 | } // namespace Cef 57 | -------------------------------------------------------------------------------- /valacef/SimpleAccessor.vala: -------------------------------------------------------------------------------- 1 | namespace Cef.V8 { 2 | 3 | [Compact] 4 | public class SimpleAccessor : V8accessorRef { 5 | public SimpleAccessor() { 6 | base(); 7 | /** 8 | * Handle retrieval the accessor value identified by |name|. |object| is the 9 | * receiver ('this' object) of the accessor. If retrieval succeeds set 10 | * |retval| to the return value. If retrieval fails set |exception| to the 11 | * exception that will be thrown. Return true (1) if accessor retrieval was 12 | * handled. 13 | */ 14 | /*int*/ vfunc_get = (self, /*String*/ name, /*V8value*/ object, /*V8value*/ out retval, 15 | /*String*/ exception) => { 16 | message("SimpleV8accessor.set"); 17 | return 0; 18 | }; 19 | 20 | /** 21 | * Handle assignment of the accessor value identified by |name|. |object| is 22 | * the receiver ('this' object) of the accessor. |value| is the new value 23 | * being assigned to the accessor. If assignment fails set |exception| to the 24 | * exception that will be thrown. Return true (1) if accessor assignment was 25 | * handled. 26 | */ 27 | /*int*/ vfunc_set = (self, /*String*/ name, /*V8value*/ object, /*V8value*/ value, 28 | /*String*/ exception) => { 29 | message("SimpleV8accessor.set"); 30 | return 0; 31 | }; 32 | } 33 | } 34 | 35 | } // namespace Cef.V8 36 | -------------------------------------------------------------------------------- /valacef/SimpleInterceptor.vala: -------------------------------------------------------------------------------- 1 | namespace Cef.V8 { 2 | 3 | [Compact] 4 | public class SimpleInterceptor : V8interceptorRef { 5 | public SimpleInterceptor(){ 6 | base(); 7 | /** 8 | * Handle retrieval of the interceptor value identified by |name|. |object| is 9 | * the receiver ('this' object) of the interceptor. If retrieval succeeds, set 10 | * |retval| to the return value. If the requested value does not exist, don't 11 | * set either |retval| or |exception|. If retrieval fails, set |exception| to 12 | * the exception that will be thrown. If the property has an associated 13 | * accessor, it will be called only if you don't set |retval|. Return true (1) 14 | * if interceptor retrieval was handled, false (0) otherwise. 15 | */ 16 | /*int*/ vfunc_get_byname = (self, /*String*/ name, /*V8value*/ object, /*V8value*/ out retval, 17 | /*String*/ exception) => { 18 | message("SimpleV8interceptor.get_byname"); 19 | return 0; 20 | }; 21 | 22 | /** 23 | * Handle retrieval of the interceptor value identified by |index|. |object| 24 | * is the receiver ('this' object) of the interceptor. If retrieval succeeds, 25 | * set |retval| to the return value. If the requested value does not exist, 26 | * don't set either |retval| or |exception|. If retrieval fails, set 27 | * |exception| to the exception that will be thrown. Return true (1) if 28 | * interceptor retrieval was handled, false (0) otherwise. 29 | */ 30 | /*int*/ vfunc_get_byindex = (self, /*int*/ index, /*V8value*/ object, /*V8value*/ out retval, 31 | /*String*/ exception) => { 32 | message("SimpleV8interceptor.get_byindex"); 33 | return 0; 34 | }; 35 | 36 | /** 37 | * Handle assignment of the interceptor value identified by |name|. |object| 38 | * is the receiver ('this' object) of the interceptor. |value| is the new 39 | * value being assigned to the interceptor. If assignment fails, set 40 | * |exception| to the exception that will be thrown. This setter will always 41 | * be called, even when the property has an associated accessor. Return true 42 | * (1) if interceptor assignment was handled, false (0) otherwise. 43 | */ 44 | /*int*/ vfunc_set_byname = (self, /*String*/ name, /*V8value*/ object, /*V8value*/ value, 45 | /*String*/ exception) => { 46 | message("SimpleV8interceptor.set_byname"); 47 | ((V8interceptorRef) self).priv_set(Cef.get_string(name), value); 48 | return 1; 49 | }; 50 | 51 | /** 52 | * Handle assignment of the interceptor value identified by |index|. |object| 53 | * is the receiver ('this' object) of the interceptor. |value| is the new 54 | * value being assigned to the interceptor. If assignment fails, set 55 | * |exception| to the exception that will be thrown. Return true (1) if 56 | * interceptor assignment was handled, false (0) otherwise. 57 | */ 58 | /*int*/ vfunc_set_byindex = (self, /*int*/ index, /*V8value*/ object, /*V8value*/ value, 59 | /*String*/ exception) => { 60 | message("SimpleV8interceptor.set_byindex"); 61 | return 0; 62 | }; 63 | } 64 | } 65 | 66 | } // namespace Cef.V8 67 | -------------------------------------------------------------------------------- /valacef/V8.vala: -------------------------------------------------------------------------------- 1 | namespace Cef.V8 { 2 | 3 | public V8value create_string(string? value) { 4 | String _value = {}; 5 | if (value != null) { 6 | Cef.set_string(&_value, value); 7 | } 8 | return v8value_create_string(&_value); 9 | } 10 | 11 | public bool set_value(V8value object, string key, V8value? value) { 12 | Cef.String _key = {}; 13 | Cef.set_string(&_key, key); 14 | V8value _value = value != null ? value : v8value_create_null(); 15 | _value.ref(); 16 | return (bool) object.set_value_bykey(&_key, _value, V8Propertyattribute.NONE); 17 | } 18 | 19 | public bool set_string(V8value object, string key, string? value) { 20 | if (value == null) { 21 | return set_value(object, key, null); 22 | } else { 23 | String _value = {}; 24 | Cef.set_string(&_value, value); 25 | return set_value(object, key, v8value_create_string(&_value)); 26 | } 27 | } 28 | 29 | public bool set_null(V8value object, string key) { 30 | return set_value(object, key, null); 31 | } 32 | 33 | public bool set_undefined(V8value object, string key) { 34 | return set_value(object, key, v8value_create_undefined()); 35 | } 36 | 37 | public bool set_bool(V8value object, string key, bool value) { 38 | return set_value(object, key, v8value_create_bool((int) value)); 39 | } 40 | 41 | public bool set_int(V8value object, string key, int value) { 42 | return set_value(object, key, v8value_create_int(value)); 43 | } 44 | 45 | public bool set_uint(V8value object, string key, uint value) { 46 | return set_value(object, key, v8value_create_uint(value)); 47 | } 48 | 49 | public bool set_double(V8value object, string key, double value) { 50 | return set_value(object, key, v8value_create_double( value)); 51 | } 52 | 53 | public V8value? get_function(V8value object, string key) { 54 | var value = get_value(object, key); 55 | return (value != null && value.is_function() != 0) ? value : null; 56 | } 57 | 58 | public V8value? get_object(V8value object, string key) { 59 | var value = get_value(object, key); 60 | return (value != null && value.is_object() != 0) ? value : null; 61 | } 62 | 63 | public V8value? get_value(V8value object, string key) { 64 | Cef.String _key = {}; 65 | Cef.set_string(&_key, key); 66 | return object.get_value_bykey(&_key); 67 | } 68 | 69 | public string? string_or_null(V8value? value) { 70 | if (value == null) { 71 | return null; 72 | } else if (value.is_string() > 0) { 73 | return value.get_string_value(); 74 | } 75 | return null; 76 | // TODO: why this fails to return a valid string. 77 | // return value == null ? null : (value.is_string() != 0 ? value.get_string_value() : null); 78 | } 79 | 80 | public int any_int(V8value? value) { 81 | if (value == null) { 82 | return 0; 83 | } 84 | if (value.is_int() != 0) { 85 | return value.get_int_value(); 86 | } 87 | if (value.is_uint() != 0) { 88 | return (int) value.get_uint_value(); 89 | } 90 | if (value.is_double() != 0) { 91 | return (int) value.get_double_value(); 92 | } 93 | return 0; 94 | } 95 | 96 | public Variant? variant_from_value(V8value? val, out string? exception) { 97 | exception = null; 98 | if (val.is_null() != 0) { 99 | return new Variant("mv", null); 100 | } 101 | if (val.is_string() != 0) { 102 | var str = val.get_string_value(); 103 | return new Variant.string(str ?? ""); 104 | } 105 | if (val.is_double() != 0) { 106 | return new Variant.double(val.get_double_value()); 107 | } 108 | if (val.is_int() != 0) { 109 | return new Variant.int32((int32) val.get_int_value()); 110 | } 111 | if (val.is_uint() != 0) { 112 | return new Variant.uint32((uint32) val.get_uint_value()); 113 | } 114 | if (val.is_bool() != 0) { 115 | return new Variant.boolean((bool) val.get_bool_value()); 116 | } 117 | if (val.is_array() != 0) { 118 | VariantBuilder builder = new VariantBuilder(new VariantType ("av")); 119 | int size = val.get_array_length(); 120 | for (int i = 0; i < size; i++) { 121 | var member = variant_from_value(val.get_value_byindex(i), out exception); 122 | if (member == null) { 123 | return null; 124 | } 125 | builder.add("v", member); 126 | } 127 | return builder.end(); 128 | } 129 | if (val.is_object() != 0) { 130 | var properties = new Cef.StringList(); 131 | val.get_keys(properties); 132 | var size = properties.size(); 133 | var builder = new VariantBuilder(new VariantType("a{smv}")); 134 | for (size_t i = 0; i < size; i++) { 135 | Cef.String key = {}; 136 | properties.value(i, &key); 137 | var member = variant_from_value(val.get_value_bykey(&key), out exception); 138 | if (member == null) { 139 | return null; 140 | } 141 | builder.add("{smv}", Cef.get_string(&key), member); 142 | } 143 | return builder.end(); 144 | } 145 | exception = val.is_undefined() != 0 ? "Refusing to convert undefined value." : "Unsupported type."; 146 | return null; 147 | } 148 | 149 | public V8value? value_from_variant(Variant? variant, out string? exception) { 150 | exception = null; 151 | if (variant == null) { 152 | return v8value_create_null(); 153 | } 154 | var type = variant.get_type(); 155 | if (variant.is_of_type(VariantType.VARIANT)) { 156 | return value_from_variant(variant.get_variant(), out exception); 157 | } 158 | if (type.is_subtype_of(VariantType.MAYBE)) { 159 | Variant? maybe = null; 160 | variant.get("m*", &maybe); 161 | return (maybe == null) ? v8value_create_null(): value_from_variant(maybe, out exception); 162 | } 163 | var object_type = new VariantType("a{s*}"); 164 | if (type.is_subtype_of(object_type)) { 165 | var object = v8value_create_object(null, null); 166 | VariantIter iter = null; 167 | variant.get("a{s*}", &iter); 168 | string key = null; 169 | Variant value = null; 170 | while (iter.next("{s*}", &key, &value)) { 171 | var member = value_from_variant(value, out exception); 172 | if (member == null) { 173 | return null; 174 | } 175 | set_value(object, key, member); 176 | } 177 | return object; 178 | } 179 | if (variant.is_of_type(VariantType.STRING)) { 180 | return create_string(variant.get_string()); 181 | } 182 | if (variant.is_of_type(VariantType.BOOLEAN)) { 183 | return v8value_create_bool((int) variant.get_boolean()); 184 | } 185 | if (variant.is_of_type(VariantType.DOUBLE)) { 186 | return v8value_create_double(variant.get_double()); 187 | } 188 | if (variant.is_of_type(VariantType.INT32)) { 189 | return v8value_create_int((int) variant.get_int32()); 190 | } 191 | if (variant.is_of_type(VariantType.UINT32)) { 192 | return v8value_create_uint((uint) variant.get_uint32()); 193 | } 194 | if (variant.is_of_type(VariantType.INT64)) { 195 | return v8value_create_int((int) variant.get_int64()); 196 | } 197 | if (variant.is_of_type(VariantType.UINT64)) { 198 | return v8value_create_uint((uint) variant.get_uint64()); 199 | } 200 | if (variant.is_container()) { 201 | var size = variant.n_children(); 202 | var array = v8value_create_array((int) size); 203 | for (var i = 0; i < size; i++) { 204 | var member = value_from_variant(variant.get_child_value(i), out exception); 205 | if (member == null) { 206 | return null; 207 | } 208 | array.set_value_byindex(i, member); 209 | } 210 | return array; 211 | } 212 | exception = "Unsupported type '%s'. Content: %s".printf(variant.get_type_string(), variant.print(true)); 213 | return null; 214 | } 215 | 216 | public string format_exception(Cef.V8exception exception) { 217 | var buf = new StringBuilder(""); 218 | buf.append_printf("%s:%d: %s\n%s\n", 219 | exception.get_script_resource_name(), exception.get_line_number(), exception.get_message(), 220 | exception.get_source_line()); 221 | var start = exception.get_start_column(); 222 | var end = exception.get_end_column(); 223 | for (var i = 0; i <= end; i++) { 224 | buf.append_c(i < start ? ' ' : '^'); 225 | } 226 | return buf.str; 227 | } 228 | 229 | public V8value? parse_json(V8context context, string json, out string? error) { 230 | error = null; 231 | var object = Cef.V8.get_object(context.get_global(), "JSON"); 232 | if (object == null) { 233 | error = "Cannot find window.JSON object in the given V8 context."; 234 | return null; 235 | } 236 | object.ref(); 237 | var func = Cef.V8.get_function(object, "parse"); 238 | if (func == null) { 239 | error = "Cannot find window.JSON.parse function in the given V8 context."; 240 | return null; 241 | } 242 | var _json = create_string(json == "" ? "{}" : json); 243 | _json.ref(); 244 | var result = func.execute_function(object, {_json}); 245 | if (result == null) { 246 | error = format_exception(func.get_exception()); 247 | return null; 248 | } else { 249 | return result; 250 | } 251 | } 252 | 253 | } // namespace Cef.V8 254 | -------------------------------------------------------------------------------- /valacef/constants.vala: -------------------------------------------------------------------------------- 1 | namespace Cef { 2 | 3 | [CCode (cname="CEF_LIB_DIR")] 4 | private extern const string CEF_LIB_DIR; 5 | [CCode (cname="VALACEF_WIDEVINE_MANIFEST_PATH")] 6 | private extern const string WIDEVINE_MANIFEST_PATH; 7 | private static unowned string? cached_cef_lib_dir; 8 | private static unowned string? cached_widevine_manifest_path; 9 | private static string? cached_widevine_adapter_path; 10 | private static string? minimal_chromium_version_for_widevine = null; 11 | 12 | public unowned string get_cef_lib_dir() { 13 | if (cached_cef_lib_dir == null) { 14 | cached_cef_lib_dir = Environment.get_variable("CEF_LIB_DIR") ?? CEF_LIB_DIR; 15 | } 16 | return cached_cef_lib_dir; 17 | } 18 | 19 | 20 | public unowned string get_widevine_manifest_path() { 21 | if (cached_widevine_manifest_path == null) { 22 | cached_widevine_manifest_path = Environment.get_variable( 23 | "VALACEF_WIDEVINE_MANIFEST_PATH") ?? WIDEVINE_MANIFEST_PATH; 24 | } 25 | return cached_widevine_manifest_path; 26 | } 27 | 28 | 29 | public unowned string get_widevine_adapter_path() { 30 | if (cached_widevine_adapter_path == null) { 31 | cached_widevine_adapter_path = get_cef_lib_dir() + "/libwidevinecdmadapter.so"; 32 | } 33 | return cached_widevine_adapter_path; 34 | } 35 | 36 | 37 | public unowned string get_minimal_chromium_version_for_widevine() { 38 | if (minimal_chromium_version_for_widevine == null) { 39 | minimal_chromium_version_for_widevine = Cef.get_chromium_major().to_string(); 40 | } 41 | return minimal_chromium_version_for_widevine; 42 | } 43 | 44 | } // namespace Cef 45 | -------------------------------------------------------------------------------- /valacef/valacef.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@PREFIX@ 2 | libdir=@LIBDIR@ 3 | ceflibdir=@CEFLIBDIR@ 4 | includedir=@INCLUDEDIR@ 5 | 6 | Name: ValaCEF 7 | Description: Vala bindings for CEF 8 | Version: @VERSION@ 9 | Requires.private: glib-2.0 10 | Libs: -Wl,-rpath=${ceflibdir} -L${libdir} -L${ceflibdir} -lcef -l@LIBNAME@ 11 | Cflags: @INCLUDE_CEF_DIRS@ -I${includedir}/@APPNAME@-1.0 @PC_CFLAGS@ 12 | -------------------------------------------------------------------------------- /valacef/version.vala: -------------------------------------------------------------------------------- 1 | namespace Cef { 2 | 3 | [CCode (cheader_filename = "cef_version.h")] 4 | private extern int version_info(int entry); 5 | 6 | [CCode (cname="VALACEF_VERSION_MAJOR")] 7 | private extern const int VALACEF_VERSION_MAJOR; 8 | 9 | [CCode (cname="VALACEF_VERSION_MINOR")] 10 | private extern const int VALACEF_VERSION_MINOR; 11 | 12 | [CCode (cname="VALACEF_VERSION_MICRO")] 13 | private extern const int VALACEF_VERSION_MICRO; 14 | 15 | public int get_cef_major() { 16 | return version_info(0); 17 | } 18 | 19 | 20 | public int get_cef_commit() { 21 | return version_info(3); 22 | } 23 | 24 | 25 | public int get_chromium_major() { 26 | return version_info(4); 27 | } 28 | 29 | 30 | public int get_chromium_minor() { 31 | return version_info(5); 32 | } 33 | 34 | 35 | public int get_chromium_build() { 36 | return version_info(6); 37 | } 38 | 39 | 40 | public int get_chromium_patch() { 41 | return version_info(7); 42 | } 43 | 44 | public int get_chromium_branch() { 45 | return version_info(6); 46 | } 47 | 48 | public int get_valacef_major() { 49 | return VALACEF_VERSION_MAJOR; 50 | } 51 | 52 | 53 | public int get_valacef_minor() { 54 | return VALACEF_VERSION_MINOR; 55 | } 56 | 57 | public int get_valacef_micro() { 58 | return VALACEF_VERSION_MICRO; 59 | } 60 | 61 | public int get_valacef_branch() { 62 | return VALACEF_VERSION_MINOR; 63 | } 64 | 65 | public string get_valacef_version() { 66 | return "%d.%d.%d".printf(get_valacef_major(), get_valacef_minor(), get_valacef_micro()); 67 | } 68 | 69 | 70 | public string get_cef_version() { 71 | return "%d.%d.%d".printf(get_cef_major(), get_chromium_build(), get_cef_commit()); 72 | } 73 | 74 | 75 | public string get_chromium_version() { 76 | return "%d.%d.%d.%d".printf(get_chromium_major(), get_chromium_minor(), get_chromium_build(), get_chromium_patch()); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /valacefgen/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiliado/valacef/580706ec081299ff3eda8eecac88d8d336ec95ea/valacefgen/__init__.py -------------------------------------------------------------------------------- /valacefgen/utils.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | from typing import List, Tuple, Iterable, Optional 3 | 4 | from . import vala 5 | 6 | def find_prefix(items: List[str]) -> str: 7 | pos = len(items[0]) 8 | while pos > 0: 9 | prefix = items[0][0:pos] 10 | for item in items: 11 | if not item.startswith(prefix): 12 | break 13 | else: 14 | return prefix 15 | pos -= 1 16 | return "" 17 | 18 | 19 | def lstrip(value, start="") -> str: 20 | return value if not value.startswith(start) else value[len(start):] 21 | 22 | 23 | def rstrip(value, end="") -> str: 24 | return value if not value.endswith(end) else value[:-len(end)] 25 | 26 | 27 | def camel_case(name: str) -> str: 28 | return ''.join(s[0].upper() + s[1:] for s in name.split('_')) 29 | 30 | 31 | def normalize_pointer(c_type: str) -> str: 32 | """Remove extra space and const* qualifier.""" 33 | return c_type.replace('const*', '*').replace('const *', '*').replace(' *', '*') 34 | 35 | 36 | def bare_c_type(c_type: str) -> str: 37 | """Remove stars from pointer types except for `void*` and `void**`.""" 38 | c_type = normalize_pointer(c_type) 39 | return c_type if c_type in ('void*', 'void**') else c_type.rstrip('*') 40 | 41 | 42 | def is_func_pointer(c_type: str) -> bool: 43 | """Return true if the C type is a pointer to a function.""" 44 | return ' ( * ) (' in c_type 45 | 46 | 47 | def parse_c_func_pointer(c_type: str) -> Tuple[str, List[Tuple[str, str]]]: 48 | func = c_type.replace(' ( * ) ', '') 49 | ret_type, params = func.split('(', 1) 50 | params = [tuple(p.strip().rsplit(None, 1)) for p in params.rsplit(')', 1)[0].split(',')] 51 | return ret_type, params 52 | 53 | 54 | class TypeInfo: 55 | def __init__(self, c_type: str, pointer: bool = False, const: bool = False, volatile: bool = False, 56 | ref: bool = False, out: bool = False, array: bool = False): 57 | self.array = array 58 | self.c_type = c_type 59 | self.pointer = pointer 60 | self.const = const 61 | self.volatile = volatile 62 | self.ref = ref 63 | self.out = out 64 | 65 | 66 | def parse_c_type(c_type: str) -> TypeInfo: 67 | const = c_type.startswith('const ') 68 | c_type = lstrip(c_type, 'const ') 69 | volatile = c_type.startswith('volatile ') 70 | c_type = lstrip(c_type, 'volatile ') 71 | c_type = normalize_pointer(c_type) 72 | if c_type in ('void*', 'void**'): 73 | return TypeInfo(c_type, False, const, volatile, False, False) 74 | pointer = c_type.endswith('*') 75 | out = c_type.endswith('**') 76 | c_type = c_type.rstrip('*') 77 | is_ref = False 78 | if pointer and c_type in vala.VALUE_TYPES: 79 | pointer = False 80 | is_ref = True 81 | 82 | c_type = lstrip(c_type, 'struct _') 83 | return TypeInfo(c_type, pointer, const, volatile, is_ref, out) 84 | 85 | 86 | def vala_comment(lines: Iterable[str], valadoc: bool = False) -> Iterable[str]: 87 | yield '/*' if not valadoc else '/**' 88 | for line in lines: 89 | yield ' * ' + line 90 | yield ' */' 91 | 92 | 93 | def reformat_comment(comment: Optional[str], strip_chars=3) -> Optional[str]: 94 | return [line[strip_chars:] for line in comment.splitlines(False)[1:-1]] if comment else None 95 | -------------------------------------------------------------------------------- /valacefgen/vala.py: -------------------------------------------------------------------------------- 1 | VALUE_TYPES = { 2 | 'short', 'int', 'long', 3 | 'uchar', 'ushort', 'uint', 'ulong', 4 | 'bool', 'float', 'double', 'size_t', 5 | 'uint8', 'int8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64', 6 | } 7 | 8 | 9 | VALA_TYPES = VALUE_TYPES | { 10 | 'char', 'string', 'void*', 'void**', 'time_t', 11 | } 12 | 13 | 14 | VALA_ALIASES = { 15 | 'unsigned int': 'uint', 16 | 'short unsigned int': 'ushort', 17 | 'unsigned long': 'ulong', 18 | 'int64_t': 'int64', 19 | 'uint64_t': 'uint64', 20 | 'long long': 'int64', 21 | } 22 | 23 | GLIB_TYPES = { 24 | "GData": "GLib.Datalist", 25 | } 26 | -------------------------------------------------------------------------------- /valacefgtk/AboutBlankPopupClient.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class AboutBlankPopupClient : Cef.ClientRef { 4 | public AboutBlankPopupClient(WebView web_view) { 5 | base(); 6 | priv_set("web_view", web_view); 7 | priv_set("request_handler", new AboutBlankPopupRequestHandler(web_view, this)); 8 | 9 | /** 10 | * Return the handler for context menus. If no handler is provided the default 11 | * implementation will be used. 12 | */ 13 | vfunc_get_context_menu_handler = (self) => { 14 | Cef.assert_browser_ui_thread(); 15 | return null; 16 | }; 17 | 18 | /** 19 | * Return the handler for dialogs. If no handler is provided the default 20 | * implementation will be used. 21 | */ 22 | vfunc_get_dialog_handler = (self) => { 23 | Cef.assert_browser_ui_thread(); 24 | return null; 25 | }; 26 | 27 | /** 28 | * Return the handler for browser display state events. 29 | */ 30 | vfunc_get_display_handler = (self) => { 31 | Cef.assert_browser_ui_thread(); 32 | return null; 33 | }; 34 | 35 | /** 36 | * Return the handler for download events. If no handler is returned downloads 37 | * will not be allowed. 38 | */ 39 | vfunc_get_download_handler = (self) => { 40 | Cef.assert_browser_ui_thread(); 41 | return null; 42 | }; 43 | 44 | /** 45 | * Return the handler for drag events. 46 | */ 47 | vfunc_get_drag_handler = (self) => { 48 | Cef.assert_browser_ui_thread(); 49 | return null; 50 | }; 51 | 52 | /** 53 | * Return the handler for find result events. 54 | */ 55 | vfunc_get_find_handler = (self) => { 56 | Cef.assert_browser_ui_thread(); 57 | return null; 58 | }; 59 | 60 | /** 61 | * Return the handler for focus events. 62 | */ 63 | vfunc_get_focus_handler = (self) => { 64 | Cef.assert_browser_ui_thread(); 65 | return null; 66 | }; 67 | 68 | /** 69 | * Return the handler for JavaScript dialogs. If no handler is provided the 70 | * default implementation will be used. 71 | */ 72 | vfunc_get_jsdialog_handler = (self) => { 73 | Cef.assert_browser_ui_thread(); 74 | return null; 75 | }; 76 | 77 | /** 78 | * Return the handler for keyboard events. 79 | */ 80 | vfunc_get_keyboard_handler = (self) => { 81 | Cef.assert_browser_ui_thread(); 82 | return null; 83 | }; 84 | 85 | /** 86 | * Return the handler for browser life span events. 87 | */ 88 | vfunc_get_life_span_handler = (self) => { 89 | Cef.assert_browser_ui_thread(); 90 | return null; 91 | }; 92 | 93 | /** 94 | * Return the handler for browser load status events. 95 | */ 96 | vfunc_get_load_handler = (self) => { 97 | Cef.assert_browser_ui_thread(); 98 | return null; 99 | }; 100 | 101 | /** 102 | * Return the handler for off-screen rendering events. 103 | */ 104 | vfunc_get_render_handler = (self) => { 105 | Cef.assert_browser_ui_thread(); 106 | return null; 107 | }; 108 | 109 | /** 110 | * Return the handler for browser request events. 111 | */ 112 | vfunc_get_request_handler = (self) => { 113 | assert(Cef.currently_on(Cef.ThreadId.UI) + Cef.currently_on(Cef.ThreadId.IO) == 1); 114 | return ((Cef.ClientRef?)self).priv_get("request_handler"); 115 | }; 116 | /** 117 | * Called when a new message is received from a different process. Return true 118 | * (1) if the message was handled or false (0) otherwise. Do not keep a 119 | * reference to or attempt to access the message outside of this callback. 120 | */ 121 | vfunc_on_process_message_received = (self, browser, source_process, msg) => { 122 | return 0; 123 | }; 124 | } 125 | 126 | public void navigation_request(NavigationRequest request) { 127 | // Track only the first navigation from about:blank 128 | priv_del("request_handler"); 129 | if (!request.allowed) { 130 | // Close empty pop-up window 131 | Timeout.add(50, () => { 132 | request.browser.get_host().close_browser(1); 133 | return false; 134 | }); 135 | } 136 | } 137 | } 138 | 139 | } // namespace CefGtk 140 | -------------------------------------------------------------------------------- /valacefgtk/AboutBlankPopupRequestHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class AboutBlankPopupRequestHandler: Cef.RequestHandlerRef { 4 | 5 | public AboutBlankPopupRequestHandler(WebView web_view, AboutBlankPopupClient client) { 6 | base(); 7 | priv_set("web_view", web_view); 8 | priv_set("client", client); 9 | 10 | /** 11 | * Called on the UI thread before browser navigation. Return true (1) to 12 | * cancel the navigation or false (0) to allow the navigation to proceed. The 13 | * |request| object cannot be modified in this callback. 14 | * cef_load_handler_t::OnLoadingStateChange will be called twice in all cases. 15 | * If the navigation is allowed cef_load_handler_t::OnLoadStart and 16 | * cef_load_handler_t::OnLoadEnd will be called. If the navigation is canceled 17 | * cef_load_handler_t::OnLoadError will be called with an |errorCode| value of 18 | * ERR_ABORTED. 19 | */ 20 | /*int*/ vfunc_on_before_browse = ( 21 | self, /*Browser*/ browser, /*Frame*/ frame, /*Request*/ request, /*int*/ is_redirect 22 | ) => { 23 | bool user_gesture; 24 | switch (request.get_transition_type()) { 25 | case Cef.TransitionType.LINK: 26 | case Cef.TransitionType.EXPLICIT: 27 | case Cef.TransitionType.MANUAL_SUBFRAME: 28 | case Cef.TransitionType.FORM_SUBMIT: 29 | user_gesture = true; 30 | break; 31 | default: 32 | user_gesture = false; 33 | break; 34 | } 35 | var navigation_request = new NavigationRequest( 36 | browser, frame, request.get_url(), frame != null ? frame.get_name() : null, 37 | Cef.WindowOpenDisposition.UNKNOWN, request.get_transition_type(), 38 | request.get_resource_type(), user_gesture, true, (bool) is_redirect); 39 | unowned WebView _web_view = ((Cef.RequestHandlerRef) self).priv_get("web_view"); 40 | _web_view.navigation_request(navigation_request); 41 | ((Cef.RequestHandlerRef) self).priv_get("client").navigation_request( 42 | navigation_request); 43 | return navigation_request.allowed ? 0 : 1; 44 | }; 45 | 46 | /** 47 | * Called on the UI thread before OnBeforeBrowse in certain limited cases 48 | * where navigating a new or different browser might be desirable. This 49 | * includes user-initiated navigation that might open in a special way (e.g. 50 | * links clicked via middle-click or ctrl + left-click) and certain types of 51 | * cross-origin navigation initiated from the renderer process (e.g. 52 | * navigating the top-level frame to/from a file URL). The |browser| and 53 | * |frame| values represent the source of the navigation. The 54 | * |target_disposition| value indicates where the user intended to navigate 55 | * the browser based on standard Chromium behaviors (e.g. current tab, new 56 | * tab, etc). The |user_gesture| value will be true (1) if the browser 57 | * navigated via explicit user gesture (e.g. clicking a link) or false (0) if 58 | * it navigated automatically (e.g. via the DomContentLoaded event). Return 59 | * true (1) to cancel the navigation or false (0) to allow the navigation to 60 | * proceed in the source browser's top-level frame. 61 | */ 62 | /*int*/ vfunc_on_open_urlfrom_tab = ( 63 | self, /*Browser*/ browser, /*Frame*/ frame, /*String*/ target_url, 64 | /*WindowOpenDisposition*/ target_disposition, /*int*/ user_gesture 65 | ) => { 66 | if (frame.is_main() == 1) { 67 | warning("vfunc_on_open_urlfrom_tab: '%s' %s %s", 68 | Cef.get_string(target_url), 69 | target_disposition.to_string(), 70 | user_gesture.to_string()); 71 | } 72 | return 0; 73 | }; 74 | } 75 | } 76 | 77 | } // namespace CefGtk 78 | -------------------------------------------------------------------------------- /valacefgtk/BrowserProcess.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class BrowserProcess : Cef.AppRef { 4 | public BrowserProcess(InitFlags? flags, FlashPlugin? flash_plugin, double scale_factor, owned ProxySettings proxy) { 5 | base(); 6 | priv_set("bph", new BrowserProcessHandler()); 7 | priv_set("flags", flags ?? new InitFlags()); 8 | priv_set("flash_plugin", flash_plugin); 9 | priv_set("proxy", (owned) proxy); 10 | priv_set("scale_factor", scale_factor); 11 | 12 | /** 13 | * Provides an opportunity to register custom schemes. Do not keep a reference 14 | * to the |registrar| object. This function is called on the main thread for 15 | * each process and the registered schemes should be the same across all 16 | * processes. 17 | */ 18 | vfunc_on_register_custom_schemes = (self, scheme_registrar) => {}; 19 | 20 | /** 21 | * Return the handler for resource bundle events. If 22 | * CefSettings.pack_loading_disabled is true (1) a handler must be returned. 23 | * If no handler is returned resources will be loaded from pack files. This 24 | * function is called by the browser and render processes on multiple threads. 25 | */ 26 | vfunc_get_resource_bundle_handler = (self) => null; 27 | 28 | /** 29 | * Return the handler for functionality specific to the browser process. This 30 | * function is called on multiple threads in the browser process. 31 | */ 32 | vfunc_get_browser_process_handler = (self) => { 33 | return ((BrowserProcess) self).priv_get("bph"); 34 | }; 35 | 36 | /** 37 | * Provides an opportunity to view and/or modify command-line arguments before 38 | * processing by CEF and Chromium. The |process_type| value will be NULL for 39 | * the browser process. Do not keep a reference to the cef_command_line_t 40 | * object passed to this function. The CefSettings.command_line_args_disabled 41 | * value can be used to start with an NULL command-line object. Any values 42 | * specified in CefSettings that equate to command-line arguments will be set 43 | * before this function is called. Be cautious when using this function to 44 | * modify command-line arguments for non-browser processes as this may result 45 | * in undefined behavior including crashes. 46 | */ 47 | /*void*/ vfunc_on_before_command_line_processing = (self, /*String*/ process_type, /*CommandLine*/ command_line 48 | ) => { 49 | assert(!CefGtk.is_initialized()); 50 | var _this = ((BrowserProcess) self); 51 | Cef.String name = {}; 52 | Cef.String value = {}; 53 | var flash = _this.priv_get("flash_plugin"); 54 | if (flash != null && flash.available) { 55 | Cef.set_string(&name, "ppapi-flash-path"); 56 | Cef.set_string(&value, flash.plugin_path); 57 | command_line.append_switch_with_value(&name, &value); 58 | Cef.set_string(&name, "ppapi-flash-version"); 59 | Cef.set_string(&value, flash.version); 60 | command_line.append_switch_with_value(&name, &value); 61 | Cef.set_string(&name, "plugin-policy"); 62 | Cef.set_string(&value, "allow"); 63 | command_line.append_switch_with_value(&name, &value); 64 | } 65 | 66 | double _scale_factor = _this.get_scale_factor(); 67 | if (_scale_factor > 0.0 && (Environment.get_variable("VALACEF_DEFAULT_RENDERING_MODE") != "offscreen")) { 68 | Cef.set_string(&name, "force-device-scale-factor"); 69 | Cef.set_string(&value, _scale_factor.to_string()); 70 | command_line.append_switch_with_value(&name, &value); 71 | } 72 | 73 | unowned ProxySettings? _proxy = _this.priv_get("proxy"); 74 | if (_proxy != null && _proxy.type != ProxyType.SYSTEM) { 75 | if (_proxy.type == ProxyType.NONE) { 76 | Cef.set_string(&name, "no-proxy-server"); 77 | command_line.append_switch(&name); 78 | } else { 79 | Cef.set_string(&name, "proxy-server"); 80 | Cef.set_string(&value, "%s://%s:%u".printf( 81 | _proxy.type == ProxyType.SOCKS ? "socks" : "http", _proxy.server, _proxy.port)); 82 | command_line.append_switch_with_value(&name, &value); 83 | } 84 | } 85 | if (Environment.get_variable("VALACEF_FORCE_GPU") == "yes") { 86 | Cef.set_string(&name, "force-gpu-rasterization"); 87 | command_line.append_switch(&name); 88 | } 89 | 90 | var _flags = _this.priv_get("flags"); 91 | if (_flags.auto_play_policy != AutoPlayPolicy.DEFAULT) { 92 | Cef.set_string(&name, "autoplay-policy"); 93 | Cef.set_string(&value, _flags.auto_play_policy.to_string()); 94 | command_line.append_switch_with_value(&name, &value); 95 | } 96 | }; 97 | } 98 | 99 | /** 100 | * Get current scaling factor. 101 | * 102 | * @return The current scaling factor. 103 | */ 104 | public double get_scale_factor() { 105 | return priv_get("scale_factor").get_double(); 106 | } 107 | } 108 | 109 | } // namespace CefGtk 110 | -------------------------------------------------------------------------------- /valacefgtk/BrowserProcessHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class BrowserProcessHandler : Cef.BrowserProcessHandlerRef { 4 | private static IdleSource? cef_idle_work = null; 5 | 6 | public BrowserProcessHandler() { 7 | base(); 8 | 9 | if (cef_idle_work == null) { 10 | cef_idle_work = new IdleSource(); 11 | cef_idle_work.set_callback(do_cef_work_now); 12 | } 13 | 14 | /** 15 | * Called on the browser process UI thread immediately after the CEF context 16 | * has been initialized. 17 | */ 18 | /*void*/ vfunc_on_context_initialized = (self) => {}; 19 | 20 | /** 21 | * Called before a child process is launched. Will be called on the browser 22 | * process UI thread when launching a render process and on the browser 23 | * process IO thread when launching a GPU or plugin process. Provides an 24 | * opportunity to modify the child process command line. Do not keep a 25 | * reference to |command_line| outside of this function. 26 | */ 27 | /*void*/ vfunc_on_before_child_process_launch = (self, /*CommandLine*/ command_line) => {}; 28 | 29 | /** 30 | * Called on the browser process IO thread after the main thread has been 31 | * created for a new render process. Provides an opportunity to specify extra 32 | * information that will be passed to 33 | * cef_render_process_handler_t::on_render_thread_created() in the render 34 | * process. Do not keep a reference to |extra_info| outside of this function. 35 | */ 36 | /*void*/ vfunc_on_render_process_thread_created = (self, /*ListValue*/ extra_info) => { 37 | WebContext.notify_render_process_created(extra_info); 38 | }; 39 | 40 | /** 41 | * Return the handler for printing on Linux. If a print handler is not 42 | * provided then printing will not be supported on the Linux platform. 43 | */ 44 | /*PrintHandler*/ vfunc_get_print_handler = (self) => null; 45 | 46 | /** 47 | * Called from any thread when work has been scheduled for the browser process 48 | * main (UI) thread. This callback is used in combination with CefSettings. 49 | * external_message_pump and cef_do_message_loop_work() in cases where the CEF 50 | * message loop must be integrated into an existing application message loop 51 | * (see additional comments and warnings on CefDoMessageLoopWork). This 52 | * callback should schedule a cef_do_message_loop_work() call to happen on the 53 | * main (UI) thread. |delay_ms| is the requested delay in milliseconds. If 54 | * |delay_ms| is <= 0 then the call should happen reasonably soon. If 55 | * |delay_ms| is > 0 then the call should be scheduled to happen after the 56 | * specified delay and any currently pending scheduled call should be 57 | * cancelled. 58 | */ 59 | /*void*/ vfunc_on_schedule_message_pump_work = (self, /*int64*/ delay_ms) => { 60 | if (delay_ms <= 0) { 61 | if (cef_idle_work.get_context() == null) { 62 | cef_idle_work.attach(null); 63 | } 64 | } 65 | /* We use a 50 ms timer for CEF work at init.vala */ 66 | }; 67 | } 68 | 69 | private static bool do_cef_work_now() { 70 | Cef.assert_browser_ui_thread(); 71 | Cef.do_message_loop_work(); 72 | return false; 73 | } 74 | } 75 | 76 | } // namespace CefGtk 77 | -------------------------------------------------------------------------------- /valacefgtk/Client.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class Client : Cef.ClientRef { 4 | public Client(WebView web_view, FocusHandler focus_handler, DisplayHandler display_handler, 5 | LoadHandler load_handler, JsdialogHandler js_dialog_handler, DownloadHandler download_handler, 6 | KeyboardHandler keyboard_handler, RequestHandler request_handler, LifeSpanHandler life_span_handler, 7 | Cef.RenderHandler? render_handler 8 | ) { 9 | base(); 10 | priv_set("web_view", web_view); 11 | priv_set("focus_handler", focus_handler); 12 | priv_set("display_handler", display_handler); 13 | priv_set("load_handler", load_handler); 14 | priv_set("js_dialog_handler", js_dialog_handler); 15 | priv_set("download_handler", download_handler); 16 | priv_set("keyboard_handler", keyboard_handler); 17 | priv_set("request_handler", request_handler); 18 | priv_set("life_span_handler", life_span_handler); 19 | priv_set("render_handler", render_handler); 20 | priv_set("menu_handler", new ContextMenuHandler(web_view)); 21 | 22 | /** 23 | * Return the handler for context menus. If no handler is provided the default 24 | * implementation will be used. 25 | */ 26 | vfunc_get_context_menu_handler = (self) => { 27 | Cef.assert_browser_ui_thread(); 28 | return ((Cef.ClientRef?)self).priv_get("menu_handler"); 29 | }; 30 | 31 | /** 32 | * Return the handler for dialogs. If no handler is provided the default 33 | * implementation will be used. 34 | */ 35 | vfunc_get_dialog_handler = (self) => { 36 | Cef.assert_browser_ui_thread(); 37 | message("get_dialog_handler"); 38 | return null; 39 | }; 40 | 41 | /** 42 | * Return the handler for browser display state events. 43 | */ 44 | vfunc_get_display_handler = (self) => { 45 | Cef.assert_browser_ui_thread(); 46 | return ((Cef.ClientRef?)self).priv_get("display_handler"); 47 | }; 48 | 49 | /** 50 | * Return the handler for download events. If no handler is returned downloads 51 | * will not be allowed. 52 | */ 53 | vfunc_get_download_handler = (self) => { 54 | Cef.assert_browser_ui_thread(); 55 | return ((Cef.ClientRef?)self).priv_get("download_handler"); 56 | }; 57 | 58 | /** 59 | * Return the handler for drag events. 60 | */ 61 | vfunc_get_drag_handler = (self) => { 62 | Cef.assert_browser_ui_thread(); 63 | message("get_drag_handler"); 64 | return null; 65 | }; 66 | 67 | /** 68 | * Return the handler for find result events. 69 | */ 70 | vfunc_get_find_handler = (self) => { 71 | Cef.assert_browser_ui_thread(); 72 | message("get_find_handler"); 73 | return null; 74 | }; 75 | 76 | /** 77 | * Return the handler for focus events. 78 | */ 79 | vfunc_get_focus_handler = (self) => { 80 | Cef.assert_browser_ui_thread(); 81 | return ((Cef.ClientRef?)self).priv_get("focus_handler"); 82 | }; 83 | 84 | /** 85 | * Return the handler for JavaScript dialogs. If no handler is provided the 86 | * default implementation will be used. 87 | */ 88 | vfunc_get_jsdialog_handler = (self) => { 89 | Cef.assert_browser_ui_thread(); 90 | return ((Cef.ClientRef?)self).priv_get("js_dialog_handler"); 91 | }; 92 | 93 | /** 94 | * Return the handler for keyboard events. 95 | */ 96 | vfunc_get_keyboard_handler = (self) => { 97 | Cef.assert_browser_ui_thread(); 98 | return ((Cef.ClientRef?)self).priv_get("keyboard_handler"); 99 | }; 100 | 101 | /** 102 | * Return the handler for browser life span events. 103 | */ 104 | vfunc_get_life_span_handler = (self) => { 105 | Cef.assert_browser_ui_thread(); 106 | message("get_life_span_handler"); 107 | return ((Cef.ClientRef?)self).priv_get("life_span_handler"); 108 | }; 109 | 110 | /** 111 | * Return the handler for browser load status events. 112 | */ 113 | vfunc_get_load_handler = (self) => { 114 | Cef.assert_browser_ui_thread(); 115 | return ((Cef.ClientRef?)self).priv_get("load_handler"); 116 | }; 117 | 118 | /** 119 | * Return the handler for off-screen rendering events. 120 | */ 121 | vfunc_get_render_handler = (self) => { 122 | Cef.assert_browser_ui_thread(); 123 | Cef.RenderHandler? handler = ((Cef.ClientRef?)self).priv_get("render_handler"); 124 | return handler; 125 | }; 126 | 127 | /** 128 | * Return the handler for browser request events. 129 | */ 130 | vfunc_get_request_handler = (self) => { 131 | assert(Cef.currently_on(Cef.ThreadId.UI) + Cef.currently_on(Cef.ThreadId.IO) == 1); 132 | return ((Cef.ClientRef?)self).priv_get("request_handler"); 133 | }; 134 | /** 135 | * Called when a new message is received from a different process. Return true 136 | * (1) if the message was handled or false (0) otherwise. Do not keep a 137 | * reference to or attempt to access the message outside of this callback. 138 | */ 139 | vfunc_on_process_message_received = (self, browser, frame, source_process, msg) => { 140 | Cef.assert_browser_ui_thread(); 141 | return (int) ((Cef.ClientRef?) self).priv_get("web_view").on_message_received( 142 | browser, frame, msg); 143 | }; 144 | } 145 | } 146 | 147 | } // namespace CefGtk 148 | -------------------------------------------------------------------------------- /valacefgtk/ContextMenuHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class ContextMenuHandler : Cef.ContextMenuHandlerRef { 4 | public ContextMenuHandler(WebView web_view) { 5 | base(); 6 | priv_set("web_view", web_view); 7 | 8 | /** 9 | * Called before a context menu is displayed. |params| provides information 10 | * about the context menu state. |model| initially contains the default 11 | * context menu. The |model| can be cleared to show no context menu or 12 | * modified to show a custom menu. Do not keep references to |params| or 13 | * |model| outside of this callback. 14 | */ 15 | /*void*/ vfunc_on_before_context_menu = ( 16 | self, /*Browser*/ browser, /*Frame*/ frame, /*ContextMenuParams*/ parameters, /*MenuModel*/ model 17 | ) => {}; 18 | 19 | /** 20 | * Called to allow custom display of the context menu. |params| provides 21 | * information about the context menu state. |model| contains the context menu 22 | * model resulting from OnBeforeContextMenu. For custom display return true 23 | * (1) and execute |callback| either synchronously or asynchronously with the 24 | * selected command ID. For default display return false (0). Do not keep 25 | * references to |params| or |model| outside of this callback. 26 | */ 27 | /*int*/ vfunc_run_context_menu = ( 28 | self, /*Browser*/ browser, /*Frame*/ frame, /*ContextMenuParams*/ parameters, /*MenuModel*/ model, 29 | /*RunContextMenuCallback*/ callback 30 | ) => { 31 | ((Cef.ContextMenuHandlerRef) self).priv_get("web_view").context_menu_visible = true; 32 | return 0; 33 | }; 34 | 35 | /** 36 | * Called to execute a command selected from the context menu. Return true (1) 37 | * if the command was handled or false (0) for the default implementation. See 38 | * cef_menu_id_t for the command ids that have default implementations. All 39 | * user-defined command ids should be between MENU_ID_USER_FIRST and 40 | * MENU_ID_USER_LAST. |params| will have the same values as what was passed to 41 | * on_before_context_menu(). Do not keep a reference to |params| outside of 42 | * this callback. 43 | */ 44 | /*int*/ vfunc_on_context_menu_command = ( 45 | self, /*Browser*/ browser, /*Frame*/ frame, /*ContextMenuParams*/ parameters, /*int*/ command_id, 46 | /*EventFlags*/ event_flags 47 | ) => { 48 | return 0; 49 | }; 50 | 51 | /** 52 | * Called when the context menu is dismissed irregardless of whether the menu 53 | * was NULL or a command was selected. 54 | */ 55 | /*void*/ vfunc_on_context_menu_dismissed = (self, /*Browser*/ browser, /*Frame*/ frame) => { 56 | ((Cef.ContextMenuHandlerRef) self).priv_get("web_view").context_menu_visible = false; 57 | }; 58 | } 59 | } 60 | 61 | } // namespace CefGtk 62 | -------------------------------------------------------------------------------- /valacefgtk/DisplayHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class DisplayHandler : Cef.DisplayHandlerRef { 4 | public DisplayHandler(WebView web_view) { 5 | base(); 6 | priv_set("web_view", web_view); 7 | 8 | /** 9 | * Called when a frame's address has changed. 10 | */ 11 | /*void*/ vfunc_on_address_change = (self, /*Browser*/ browser, /*Frame*/ frame, /*String*/ url) => { 12 | Cef.assert_browser_ui_thread(); 13 | if (frame.is_main() == 1) { 14 | var uri = Cef.get_string(url); 15 | get_web_view(self).uri = uri != "" && uri != "about:blank" ? uri : null; 16 | } 17 | }; 18 | 19 | /** 20 | * Called when the page title changes. 21 | */ 22 | /*void*/ vfunc_on_title_change = (self, /*Browser*/ browser, /*String*/ title) => { 23 | Cef.assert_browser_ui_thread(); 24 | get_web_view(self).title = Cef.get_string(title); 25 | }; 26 | 27 | /** 28 | * Called when the page icon changes. 29 | */ 30 | /*void*/ vfunc_on_favicon_urlchange = (self, /*Browser*/ browser, /*StringList*/ icon_urls) => {}; 31 | 32 | /** 33 | * Called when web content in the page has toggled fullscreen mode. If 34 | * |fullscreen| is true (1) the content will automatically be sized to fill 35 | * the browser content area. If |fullscreen| is false (0) the content will 36 | * automatically return to its original size and position. The client is 37 | * responsible for resizing the browser if desired. 38 | */ 39 | /*void*/ vfunc_on_fullscreen_mode_change = (self, /*Browser*/ browser, /*int*/ fullscreen) => { 40 | get_web_view(self).toggle_fullscreen((bool) fullscreen); 41 | }; 42 | 43 | /** 44 | * Called when the browser is about to display a tooltip. |text| contains the 45 | * text that will be displayed in the tooltip. To handle the display of the 46 | * tooltip yourself return true (1). Otherwise, you can optionally modify 47 | * |text| and then return false (0) to allow the browser to display the 48 | * tooltip. When window rendering is disabled the application is responsible 49 | * for drawing tooltips and the return value is ignored. 50 | */ 51 | /*int*/ vfunc_on_tooltip = (self, /*Browser*/ browser, /*String*/ text) => { 52 | Cef.assert_browser_ui_thread(); 53 | message("Tooltip: %s", Cef.get_string(text)); 54 | return 0; 55 | }; 56 | 57 | /** 58 | * Called when the browser receives a status message. |value| contains the 59 | * text that will be displayed in the status message. 60 | */ 61 | /*void*/ vfunc_on_status_message = (self, /*Browser*/ browser, /*String*/ status_message) => { 62 | Cef.assert_browser_ui_thread(); 63 | get_web_view(self).status_message = Cef.get_string(status_message); 64 | }; 65 | 66 | /** 67 | * Called to display a console message. Return true (1) to stop the message 68 | * from being output to the console. 69 | */ 70 | /*int*/ vfunc_on_console_message = (self, /*Browser*/ browser, /*LogSeverity*/ severity, /*String*/ text, 71 | /*String*/ source, /*int*/ line) => { 72 | Cef.assert_browser_ui_thread(); 73 | get_web_view(self).console_message(Cef.get_string(source), line, Cef.get_string(text)); 74 | return 0; 75 | }; 76 | 77 | } 78 | 79 | private static unowned WebView get_web_view(Cef.DisplayHandler self) { 80 | return ((Cef.DisplayHandlerRef)self).priv_get("web_view"); 81 | } 82 | } 83 | 84 | } // namespace CefGtk 85 | -------------------------------------------------------------------------------- /valacefgtk/DownloadHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class DownloadHandler : Cef.DownloadHandlerRef { 4 | public DownloadHandler(DownloadManager manager) { 5 | base(); 6 | priv_set("manager", manager); 7 | /** 8 | * Called before a download begins. |suggested_name| is the suggested name for 9 | * the download file. By default the download will be canceled. Execute 10 | * |callback| either asynchronously or in this function to continue the 11 | * download if desired. Do not keep a reference to |download_item| outside of 12 | * this function. 13 | */ 14 | /*void*/ vfunc_on_before_download = (self, /*Browser*/ browser, /*DownloadItem*/ download_item, 15 | /*String*/ suggested_name, /*BeforeDownloadCallback*/ callback) => { 16 | Cef.assert_browser_ui_thread(); 17 | ((Cef.DownloadHandlerRef) self).priv_get("manager").on_before_download( 18 | download_item, Cef.get_string(suggested_name), callback); 19 | }; 20 | 21 | /** 22 | * Called when a download's status or progress information has been updated. 23 | * This may be called multiple times before and after on_before_download(). 24 | * Execute |callback| either asynchronously or in this function to cancel the 25 | * download if desired. Do not keep a reference to |download_item| outside of 26 | * this function. 27 | */ 28 | /*void*/ vfunc_on_download_updated = (self, /*Browser*/ browser, /*DownloadItem*/ download_item, 29 | /*DownloadItemCallback*/ callback) => { 30 | Cef.assert_browser_ui_thread(); 31 | ((Cef.DownloadHandlerRef) self).priv_get("manager").on_download_updated( 32 | download_item, callback); 33 | }; 34 | } 35 | } 36 | 37 | } // namespace CefGtk 38 | -------------------------------------------------------------------------------- /valacefgtk/DownloadManager.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class DownloadManager : GLib.Object { 4 | private unowned WebView web_view; 5 | private HashTable tasks; 6 | private uint next_task_id = 0; 7 | 8 | public DownloadManager(WebView web_view) { 9 | this.web_view = web_view; 10 | tasks = new HashTable(str_hash, str_equal); 11 | } 12 | 13 | public bool start_download(string uri) { 14 | Cef.assert_browser_ui_thread(); 15 | return web_view.start_download(uri); 16 | } 17 | 18 | public async bool download_file(string uri, string destination, Cancellable? cancellable=null) { 19 | Cef.assert_browser_ui_thread(); 20 | string id_uri = null; 21 | uint id = 0; 22 | do { 23 | id = next_task_id++; // uint wraps to zero 24 | id_uri = task_id_str(id); 25 | } while (id_uri in tasks); 26 | if (!start_download(uri)) { 27 | return false; 28 | } 29 | var task = new Task(id, uri, destination, download_file.callback, cancellable); 30 | tasks[id_uri] = task; 31 | yield; 32 | return task.result; 33 | } 34 | 35 | internal void on_before_download(Cef.DownloadItem item, string? suggested_name, 36 | Cef.BeforeDownloadCallback handler) { 37 | Cef.assert_browser_ui_thread(); 38 | var download_id = item.get_id(); 39 | var uri = item.get_original_url(); 40 | assert(!(download_id_str(download_id) in tasks)); 41 | var iter = HashTableIter(tasks); 42 | unowned Task task; 43 | while (iter.next(null, out task)) { 44 | if (!task.claimed && task.uri == uri) { 45 | task.claim(download_id); 46 | tasks[download_id_str(download_id)] = task; 47 | Cef.String _destination = {}; 48 | Cef.set_string(&_destination, task.destination); 49 | handler.cont(&_destination, 0); 50 | return; 51 | } 52 | } 53 | } 54 | 55 | internal void on_download_updated(Cef.DownloadItem item, Cef.DownloadItemCallback handler) { 56 | Cef.assert_browser_ui_thread(); 57 | var download_id = download_id_str(item.get_id()); 58 | var task = tasks[download_id]; 59 | if (task != null) { 60 | if (item.is_complete() + item.is_canceled() != 0) { 61 | task.finished(!((bool) item.is_canceled())); 62 | tasks.remove(task_id_str(task.task_id)); 63 | tasks.remove(download_id); 64 | } else if (task.is_cancelled()) { 65 | tasks.remove(task_id_str(task.task_id)); 66 | tasks.remove(download_id); 67 | handler.cancel(); 68 | task.finished(false); 69 | } 70 | } 71 | } 72 | 73 | private inline static string task_id_str(uint task_id) { 74 | return "task:%u".printf(task_id); 75 | } 76 | 77 | private inline static string download_id_str(uint download_id) { 78 | return "download:%u".printf(download_id); 79 | } 80 | 81 | private class Task { 82 | public uint task_id; 83 | public uint download_id = 0; 84 | public string uri; 85 | public bool claimed = false; 86 | public string destination; 87 | public Cancellable? cancellable; 88 | public bool result = false; 89 | public SourceFunc callback; 90 | 91 | public Task(uint task_id, string uri, string destination, owned SourceFunc callback, 92 | Cancellable? cancellable) { 93 | this.task_id = task_id; 94 | this.uri = uri; 95 | this.destination = destination; 96 | this.cancellable = cancellable; 97 | this.callback = (owned) callback; 98 | } 99 | 100 | public void claim(uint download_id) { 101 | assert(!claimed); 102 | this.download_id = download_id; 103 | this.claimed = true; 104 | } 105 | 106 | public void finished(bool result) { 107 | Cef.assert_browser_ui_thread(); 108 | this.result = result; 109 | Idle.add((owned) callback); 110 | callback = null; 111 | } 112 | 113 | public bool is_cancelled() { 114 | return cancellable != null && cancellable.is_cancelled(); 115 | } 116 | } 117 | } 118 | 119 | } // namespace CefGtk 120 | -------------------------------------------------------------------------------- /valacefgtk/FlashPlugin.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class FlashPlugin: GLib.Object { 4 | public const string PLUGIN_FILENAME = "libpepflashplayer.so"; 5 | public const string VERSION_FILENAME = "libpepflashplayer.so.version"; 6 | public const string MANIFEST_FILENAME = "manifest.json"; 7 | public string? plugin_directory {get; private set; default = null;} 8 | public string? plugin_path {get; private set; default = null;} 9 | public string? registration_error {get; private set; default = null;} 10 | public bool available {get; private set; default = false;} 11 | public string version {get; private set; default = "";} 12 | 13 | public FlashPlugin() { 14 | } 15 | 16 | public bool register(string plugin_directory) { 17 | assert(!CefGtk.is_initialized()); 18 | var path = "%s/%s".printf(plugin_directory, PLUGIN_FILENAME); 19 | if (FileUtils.test(path, FileTest.IS_REGULAR)) { 20 | this.plugin_path = path; 21 | path = "%s/%s".printf(plugin_directory, VERSION_FILENAME); 22 | if (FileUtils.test(path, FileTest.IS_REGULAR)) { 23 | string? version; 24 | try { 25 | FileUtils.get_contents(path, out version); 26 | } catch (GLib.FileError e) { 27 | this.plugin_directory = null; 28 | this.plugin_path = null; 29 | this.registration_error = "Failed to read '%s': %s".printf(path, e.message); 30 | this.available = false; 31 | return false; 32 | } 33 | this.version = (version ?? "").strip(); 34 | this.plugin_directory = plugin_directory; 35 | this.registration_error = null; 36 | this.available = true; 37 | return true; 38 | } 39 | } 40 | this.plugin_directory = null; 41 | this.plugin_path = null; 42 | this.registration_error = "File '%s' does not exist.".printf(path); 43 | this.available = false; 44 | return false; 45 | } 46 | } 47 | 48 | } // namespace CefGtk 49 | -------------------------------------------------------------------------------- /valacefgtk/FocusHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class FocusHandler : Cef.FocusHandlerRef { 4 | public FocusHandler(WebView web_view) { 5 | base(); 6 | priv_set("web_view", web_view); 7 | /** 8 | * Called when the browser component is about to loose focus. For instance, if 9 | * focus was on the last HTML element and the user pressed the TAB key. |next| 10 | * will be true (1) if the browser is giving focus to the next component and 11 | * false (0) if the browser is giving focus to the previous component. 12 | */ 13 | vfunc_on_take_focus = (self, /*Browser*/ browser, /*int*/ next) => { 14 | Cef.assert_browser_ui_thread(); 15 | message("on_take_focus %d", next); 16 | }; 17 | 18 | /** 19 | * Called when the browser component is requesting focus. |source| indicates 20 | * where the focus request is originating from. Return false (0) to allow the 21 | * focus to be set or true (1) to cancel setting the focus. 22 | */ 23 | vfunc_on_set_focus = (self, /*Browser*/ browser, /*FocusSource*/ source) => { 24 | Cef.assert_browser_ui_thread(); 25 | return source == Cef.FocusSource.NAVIGATION ? 1 : 0; 26 | }; 27 | 28 | /** 29 | * Called when the browser component has received focus. 30 | */ 31 | vfunc_on_got_focus = (self, /*Browser*/ browser) => { 32 | Cef.assert_browser_ui_thread(); 33 | ((FocusHandler) self).priv_get("web_view").grab_focus(); 34 | }; 35 | } 36 | } 37 | 38 | } // namespace CefGtk 39 | -------------------------------------------------------------------------------- /valacefgtk/Function.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class Function { 4 | public delegate void HandlerFunc(string? name, Cef.V8value? object, Cef.V8value?[] arguments, 5 | out Cef.V8value? retval, out string? exception); 6 | 7 | public static Cef.V8value create(string name, owned HandlerFunc handler) { 8 | Cef.assert_renderer_thread(); 9 | Cef.String _name = {}; 10 | Cef.set_string(&_name, name); 11 | var _handler = new Handler(new Function((owned) handler)); 12 | return Cef.v8value_create_function(&_name, _handler); 13 | } 14 | 15 | private HandlerFunc handler; 16 | 17 | private Function(owned HandlerFunc handler) { 18 | Cef.assert_renderer_thread(); 19 | this.handler = (owned) handler; 20 | } 21 | 22 | public void run(string? name, Cef.V8value? object, Cef.V8value?[] arguments, out Cef.V8value? retval, 23 | out string? exception) { 24 | handler(name, object, arguments, out retval, out exception); 25 | } 26 | 27 | private class Handler : Cef.V8handlerRef { 28 | public Handler(Function function) { 29 | base(); 30 | priv_set("function", function); 31 | /** 32 | * Handle execution of the function identified by |name|. |object| is the 33 | * receiver ('this' object) of the function. |arguments| is the list of 34 | * arguments passed to the function. If execution succeeds set |retval| to the 35 | * function return value. If execution fails set |exception| to the exception 36 | * that will be thrown. Return true (1) if execution was handled. 37 | */ 38 | /*int*/ vfunc_execute = (self, /*String*/ name, /*V8value*/ object, /*V8value?[]*/ arguments, 39 | out /*V8value*/ retval, /*String*/ exception) => { 40 | Cef.assert_renderer_thread(); 41 | string? _exception = null; 42 | assert ((int)((void*) object) != 0x2); 43 | ((Cef.V8handlerRef) self).priv_get("function").run( 44 | Cef.get_string(name), object, arguments, out retval, out _exception); 45 | if (_exception != null) { 46 | Cef.set_string(exception, _exception); 47 | } 48 | return 1; 49 | }; 50 | } 51 | } 52 | } 53 | 54 | } // namespace Cef 55 | -------------------------------------------------------------------------------- /valacefgtk/InitFlags.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class InitFlags { 4 | public AutoPlayPolicy auto_play_policy {get; set; default = AutoPlayPolicy.DEFAULT;} 5 | 6 | public InitFlags() {} 7 | } 8 | 9 | public enum AutoPlayPolicy { 10 | /** 11 | * Use default policy. 12 | */ 13 | DEFAULT, 14 | /** 15 | * Autoplay policy that requires a document user activation. 16 | */ 17 | DOCUMENT_USER_ACTIVATION_REQUIRED, 18 | /** 19 | * Autoplay policy that does not require any user gesture. 20 | */ 21 | NO_USER_GESTURE_REQUIRED, 22 | /** 23 | * Autoplay policy to require a user gesture in order to play. 24 | */ 25 | USER_GESTURE_REQUIRED, 26 | /** 27 | * Autoplay policy to require a user gesture in order to play for cross origin iframes. 28 | */ 29 | USER_GESTURE_REQUIRED_FOR_CROSS_ORIGIN; 30 | 31 | public string to_string() { 32 | switch (this) { 33 | case DOCUMENT_USER_ACTIVATION_REQUIRED: 34 | return "document-user-activation-required"; 35 | case NO_USER_GESTURE_REQUIRED: 36 | return "no-user-gesture-required"; 37 | case USER_GESTURE_REQUIRED: 38 | return "user-gesture-required"; 39 | case USER_GESTURE_REQUIRED_FOR_CROSS_ORIGIN: 40 | return "user-gesture-required-for-cross-origin"; 41 | default: 42 | return ""; 43 | } 44 | } 45 | } 46 | 47 | } // namespace CefGtk 48 | -------------------------------------------------------------------------------- /valacefgtk/JsdialogHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class JsdialogHandler: Cef.JsdialogHandlerRef { 4 | public JsdialogHandler(WebView web_view) { 5 | base(); 6 | priv_set("web_view", web_view); 7 | 8 | /** 9 | * Called to run a JavaScript dialog. If |origin_url| is non-NULL it can be 10 | * passed to the CefFormatUrlForSecurityDisplay function to retrieve a secure 11 | * and user-friendly display string. The |default_prompt_text| value will be 12 | * specified for prompt dialogs only. Set |suppress_message| to true (1) and 13 | * return false (0) to suppress the message (suppressing messages is 14 | * preferable to immediately executing the callback as this is used to detect 15 | * presumably malicious behavior like spamming alert messages in 16 | * onbeforeunload). Set |suppress_message| to false (0) and return false (0) 17 | * to use the default implementation (the default implementation will show one 18 | * modal dialog at a time and suppress any additional dialog requests until 19 | * the displayed dialog is dismissed). Return true (1) if the application will 20 | * use a custom dialog or if the callback has been executed immediately. 21 | * Custom dialogs may be either modal or modeless. If a custom dialog is used 22 | * the application must execute |callback| once the custom dialog is 23 | * dismissed. 24 | */ 25 | /*int*/ vfunc_on_jsdialog = (self, /*Browser*/ browser, /*String*/ url, /*JsdialogType*/ dialog_type, 26 | /*String*/ message_text, /*String*/ default_prompt_text, /*JsdialogCallback*/ callback, 27 | /*int*/ ref suppress_message) => { 28 | Cef.assert_browser_ui_thread(); 29 | message("Show JS dialog for %s", dialog_type.to_string()); 30 | var _web_view = get_web_view(self); 31 | var _handled = false; 32 | var _url = Cef.get_string(url); 33 | var _message_text = Cef.get_string(message_text); 34 | var _default_prompt_text = Cef.get_string(default_prompt_text); 35 | switch (dialog_type) { 36 | case Cef.JsdialogType.ALERT: 37 | _web_view.alert_dialog(ref _handled, _url, _message_text, callback); 38 | return (int) _handled; 39 | case Cef.JsdialogType.CONFIRM: 40 | _web_view.confirm_dialog(ref _handled, _url, _message_text, callback); 41 | return (int) _handled; 42 | case Cef.JsdialogType.PROMPT: 43 | _web_view.prompt_dialog(ref _handled, _url, _message_text, _default_prompt_text, callback); 44 | return (int) _handled; 45 | default: 46 | return 0; 47 | } 48 | }; 49 | 50 | /** 51 | * Called to run a dialog asking the user if they want to leave a page. Return 52 | * false (0) to use the default dialog implementation. Return true (1) if the 53 | * application will use a custom dialog or if the callback has been executed 54 | * immediately. Custom dialogs may be either modal or modeless. If a custom 55 | * dialog is used the application must execute |callback| once the custom 56 | * dialog is dismissed. 57 | */ 58 | /*int*/ vfunc_on_before_unload_dialog = (self, /*Browser*/ browser, /*String*/ message_text, /*int*/ is_reload, 59 | /*JsdialogCallback*/ callback) => { 60 | Cef.assert_browser_ui_thread(); 61 | callback.cont(1, null); 62 | return 1; 63 | }; 64 | 65 | /** 66 | * Called to cancel any pending dialogs and reset any saved dialog state. Will 67 | * be called due to events like page navigation irregardless of whether any 68 | * dialogs are currently pending. 69 | */ 70 | /*void*/ vfunc_on_reset_dialog_state = (self, /*Browser*/ browser) => { 71 | Cef.assert_browser_ui_thread(); 72 | get_web_view(self).discard_js_dialogs(); 73 | }; 74 | 75 | /** 76 | * Called when the default implementation dialog is closed. 77 | */ 78 | // /*void*/ on_dialog_closed = (self, owned Browser? browser); 79 | } 80 | 81 | private static WebView get_web_view(Cef.JsdialogHandler self) { 82 | return ((Cef.JsdialogHandlerRef) self).priv_get("web_view"); 83 | } 84 | } 85 | 86 | } // namespace CefGtk 87 | -------------------------------------------------------------------------------- /valacefgtk/KeyboardHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class KeyboardHandler : Cef.KeyboardHandlerRef { 4 | public KeyboardHandler(WebView web_view) { 5 | base(); 6 | priv_set("web_view", web_view); 7 | 8 | /** 9 | * Called before a keyboard event is sent to the renderer. |event| contains 10 | * information about the keyboard event. |os_event| is the operating system 11 | * event message, if any. Return true (1) if the event was handled or false 12 | * (0) otherwise. If the event will be handled in on_key_event() as a keyboard 13 | * shortcut set |is_keyboard_shortcut| to true (1) and return false (0). 14 | */ 15 | /*int*/ vfunc_on_pre_key_event = (Cef.KeyboardHandlerOnPreKeyEventFunc) handle; 16 | } 17 | 18 | private static int handle(Cef.KeyboardHandler self, Cef.Browser? browser, Cef.KeyEvent key, 19 | Cef.EventHandle? os_event, int? is_keyboard_shortcut) { 20 | Cef.assert_browser_ui_thread(); 21 | return (int) ((Cef.KeyboardHandlerRef) self).priv_get("web_view").handle_key_event(key); 22 | } 23 | } 24 | 25 | } // namespace CefGtk 26 | -------------------------------------------------------------------------------- /valacefgtk/LifeSpanHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class LifeSpanHandler : Cef.LifeSpanHandlerRef { 4 | public LifeSpanHandler(WebView web_view) { 5 | base(); 6 | priv_set("web_view", web_view); 7 | 8 | /** 9 | * Called on the UI thread before a new popup browser is created. The 10 | * |browser| and |frame| values represent the source of the popup request. The 11 | * |target_url| and |target_frame_name| values indicate where the popup 12 | * browser should navigate and may be NULL if not specified with the request. 13 | * The |target_disposition| value indicates where the user intended to open 14 | * the popup (e.g. current tab, new tab, etc). The |user_gesture| value will 15 | * be true (1) if the popup was opened via explicit user gesture (e.g. 16 | * clicking a link) or false (0) if the popup opened automatically (e.g. via 17 | * the DomContentLoaded event). The |popupFeatures| structure contains 18 | * additional information about the requested popup window. To allow creation 19 | * of the popup browser optionally modify |windowInfo|, |client|, |settings| 20 | * and |no_javascript_access| and return false (0). To cancel creation of the 21 | * popup browser return true (1). The |client| and |settings| values will 22 | * default to the source browser's values. If the |no_javascript_access| value 23 | * is set to false (0) the new browser will not be scriptable and may not be 24 | * hosted in the same renderer process as the source browser. Any 25 | * modifications to |windowInfo| will be ignored if the parent browser is 26 | * wrapped in a cef_browser_view_t. Popup browser creation will be canceled if 27 | * the parent browser is destroyed before the popup browser creation completes 28 | * (indicated by a call to OnAfterCreated for the popup browser). 29 | */ 30 | /*int*/ vfunc_on_before_popup = ( 31 | self, /*Browser*/ browser, /*Frame*/ frame, /*String*/ target_url, /*String*/ target_frame_name, 32 | /*WindowOpenDisposition*/ target_disposition, /*int*/ user_gesture, /*PopupFeatures*/ popupFeatures, 33 | /*WindowInfo*/ windowInfo, out /*Client*/ client, /*BrowserSettings*/ settings, 34 | out /*DictionaryValue?*/ extra_info, /*int*/ ref no_javascript_access 35 | ) => { 36 | client = null; 37 | extra_info = null; 38 | string? url = Cef.get_string(target_url); 39 | var request = new NavigationRequest( 40 | browser, frame, url, Cef.get_string(target_frame_name), 41 | target_disposition, Cef.TransitionType.EXPLICIT, 42 | frame.is_main() == 1 ? Cef.ResourceType.MAIN_FRAME : Cef.ResourceType.SUB_FRAME, 43 | (bool) user_gesture, true, false); 44 | unowned WebView _web_view = ((Cef.LifeSpanHandlerRef) self).priv_get("web_view"); 45 | _web_view.navigation_request(request); 46 | if (url == "about:blank" && request.allowed) { 47 | client = new AboutBlankPopupClient(_web_view); 48 | } 49 | return request.allowed ? 0 : 1; 50 | }; 51 | /** 52 | * Called after a new browser is created. This callback will be the first 53 | * notification that references |browser|. 54 | */ 55 | /*void*/ vfunc_on_after_created = (self, /*Browser*/ browser) => {}; 56 | /** 57 | * Called when a browser has recieved a request to close. This may result 58 | * directly from a call to cef_browser_host_t::*close_browser() or indirectly 59 | * if the browser is parented to a top-level window created by CEF and the 60 | * user attempts to close that window (by clicking the 'X', for example). The 61 | * do_close() function will be called after the JavaScript 'onunload' event 62 | * has been fired. 63 | * 64 | * An application should handle top-level owner window close notifications by 65 | * calling cef_browser_host_t::try_close_browser() or 66 | * cef_browser_host_t::CloseBrowser(false (0)) instead of allowing the window 67 | * to close immediately (see the examples below). This gives CEF an 68 | * opportunity to process the 'onbeforeunload' event and optionally cancel the 69 | * close before do_close() is called. 70 | * 71 | * When windowed rendering is enabled CEF will internally create a window or 72 | * view to host the browser. In that case returning false (0) from do_close() 73 | * will send the standard close notification to the browser's top-level owner 74 | * window (e.g. WM_CLOSE on Windows, performClose: on OS X, "delete_event" on 75 | * Linux or cef_window_delegate_t::can_close() callback from Views). If the 76 | * browser's host window/view has already been destroyed (via view hierarchy 77 | * tear-down, for example) then do_close() will not be called for that browser 78 | * since is no longer possible to cancel the close. 79 | * 80 | * When windowed rendering is disabled returning false (0) from do_close() 81 | * will cause the browser object to be destroyed immediately. 82 | * 83 | * If the browser's top-level owner window requires a non-standard close 84 | * notification then send that notification from do_close() and return true 85 | * (1). 86 | * 87 | * The cef_life_span_handler_t::on_before_close() function will be called 88 | * after do_close() (if do_close() is called) and immediately before the 89 | * browser object is destroyed. The application should only exit after 90 | * on_before_close() has been called for all existing browsers. 91 | * 92 | * The below examples describe what should happen during window close when the 93 | * browser is parented to an application-provided top-level window. 94 | * 95 | * Example 1: Using cef_browser_host_t::try_close_browser(). This is 96 | * recommended for clients using standard close handling and windows created 97 | * on the browser process UI thread. 1. User clicks the window close button 98 | * which sends a close notification to 99 | * the application's top-level window. 100 | * 2. Application's top-level window receives the close notification and 101 | * calls TryCloseBrowser() (which internally calls CloseBrowser(false)). 102 | * TryCloseBrowser() returns false so the client cancels the window close. 103 | * 3. JavaScript 'onbeforeunload' handler executes and shows the close 104 | * confirmation dialog (which can be overridden via 105 | * CefJSDialogHandler::OnBeforeUnloadDialog()). 106 | * 4. User approves the close. 5. JavaScript 'onunload' handler executes. 6. 107 | * CEF sends a close notification to the application's top-level window 108 | * (because DoClose() returned false by default). 109 | * 7. Application's top-level window receives the close notification and 110 | * calls TryCloseBrowser(). TryCloseBrowser() returns true so the client 111 | * allows the window close. 112 | * 8. Application's top-level window is destroyed. 9. Application's 113 | * on_before_close() handler is called and the browser object 114 | * is destroyed. 115 | * 10. Application exits by calling cef_quit_message_loop() if no other 116 | * browsers 117 | * exist. 118 | * 119 | * Example 2: Using cef_browser_host_t::CloseBrowser(false (0)) and 120 | * implementing the do_close() callback. This is recommended for clients using 121 | * non-standard close handling or windows that were not created on the browser 122 | * process UI thread. 1. User clicks the window close button which sends a 123 | * close notification to 124 | * the application's top-level window. 125 | * 2. Application's top-level window receives the close notification and: 126 | * A. Calls CefBrowserHost::CloseBrowser(false). 127 | * B. Cancels the window close. 128 | * 3. JavaScript 'onbeforeunload' handler executes and shows the close 129 | * confirmation dialog (which can be overridden via 130 | * CefJSDialogHandler::OnBeforeUnloadDialog()). 131 | * 4. User approves the close. 5. JavaScript 'onunload' handler executes. 6. 132 | * Application's do_close() handler is called. Application will: 133 | * A. Set a flag to indicate that the next close attempt will be allowed. 134 | * B. Return false. 135 | * 7. CEF sends an close notification to the application's top-level window. 136 | * 8. Application's top-level window receives the close notification and 137 | * allows the window to close based on the flag from #6B. 138 | * 9. Application's top-level window is destroyed. 10. Application's 139 | * on_before_close() handler is called and the browser object 140 | * is destroyed. 141 | * 11. Application exits by calling cef_quit_message_loop() if no other 142 | * browsers 143 | * exist. 144 | */ 145 | /*int*/ vfunc_do_close = (self, /*Browser*/ browser) => {return 0;}; 146 | /** 147 | * Called just before a browser is destroyed. Release all references to the 148 | * browser object and do not attempt to execute any functions on the browser 149 | * object after this callback returns. This callback will be the last 150 | * notification that references |browser|. See do_close() documentation for 151 | * additional usage information. 152 | */ 153 | /*void*/ vfunc_on_before_close = (self, /*Browser*/ browser) => {}; 154 | } 155 | } 156 | 157 | } // namespace CefGtk 158 | -------------------------------------------------------------------------------- /valacefgtk/LoadHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class LoadHandler : Cef.LoadHandlerRef { 4 | public LoadHandler(WebView web_view) { 5 | base(); 6 | priv_set("web_view", web_view); 7 | 8 | /** 9 | * Called when the loading state has changed. This callback will be executed 10 | * twice -- once when loading is initiated either programmatically or by user 11 | * action, and once when loading is terminated due to completion, cancellation 12 | * of failure. It will be called before any calls to OnLoadStart and after all 13 | * calls to OnLoadError and/or OnLoadEnd. 14 | */ 15 | /*void*/ vfunc_on_loading_state_change = (self, /*Browser*/ browser, /*int*/ is_loading, /*int*/ can_go_back, 16 | /*int*/ can_go_forward) => { 17 | Cef.assert_browser_ui_thread(); 18 | var web = get_web_view(self); 19 | web.can_go_back = (bool) can_go_back; 20 | web.can_go_forward = (bool) can_go_forward; 21 | web.is_loading = (bool) is_loading; 22 | }; 23 | 24 | /** 25 | * Called after a navigation has been committed and before the browser begins 26 | * loading contents in the frame. The |frame| value will never be NULL -- call 27 | * the is_main() function to check if this frame is the main frame. 28 | * |transition_type| provides information about the source of the navigation 29 | * and an accurate value is only available in the browser process. Multiple 30 | * frames may be loading at the same time. Sub-frames may start or continue 31 | * loading after the main frame load has ended. This function will not be 32 | * called for same page navigations (fragments, history state, etc.) or for 33 | * navigations that fail or are canceled before commit. For notification of 34 | * overall browser load status use OnLoadingStateChange instead. 35 | */ 36 | /*void*/ vfunc_on_load_start = (self, /*Browser*/ browser, /*Frame*/ frame, /*TransitionType*/ transition_type 37 | ) => { 38 | Cef.assert_browser_ui_thread(); 39 | if (frame.is_main() == 1) { 40 | get_web_view(self).load_started(transition_type); 41 | } 42 | }; 43 | 44 | /** 45 | * Called when the browser is done loading a frame. The |frame| value will 46 | * never be NULL -- call the is_main() function to check if this frame is the 47 | * main frame. Multiple frames may be loading at the same time. Sub-frames may 48 | * start or continue loading after the main frame load has ended. This 49 | * function will not be called for same page navigations (fragments, history 50 | * state, etc.) or for navigations that fail or are canceled before commit. 51 | * For notification of overall browser load status use OnLoadingStateChange 52 | * instead. 53 | */ 54 | /*void*/ vfunc_on_load_end = (self, /*Browser*/ browser, /*Frame*/ frame, /*int*/ http_status_code) => { 55 | Cef.assert_browser_ui_thread(); 56 | if (frame.is_main() == 1) { 57 | get_web_view(self).load_ended(http_status_code); 58 | } 59 | }; 60 | 61 | /** 62 | * Called when a navigation fails or is canceled. This function may be called 63 | * by itself if before commit or in combination with OnLoadStart/OnLoadEnd if 64 | * after commit. |errorCode| is the error code number, |errorText| is the 65 | * error text and |failedUrl| is the URL that failed to load. See 66 | * net\base\net_error_list.h for complete descriptions of the error codes. 67 | */ 68 | /*void*/ vfunc_on_load_error = (self, /*Browser*/ browser, /*Frame*/ frame, /*Errorcode*/ error_code, 69 | /*String*/ error_text, /*String*/ failed_url) => { 70 | Cef.assert_browser_ui_thread(); 71 | if (frame.is_main() == 1) { 72 | get_web_view(self).load_error(error_code, Cef.get_string(error_text), Cef.get_string(failed_url)); 73 | } 74 | }; 75 | } 76 | 77 | private static unowned WebView get_web_view(Cef.LoadHandler self) { 78 | return ((Cef.LoadHandlerRef)self).priv_get("web_view"); 79 | } 80 | } 81 | 82 | } // namespace CefGtk 83 | -------------------------------------------------------------------------------- /valacefgtk/MsgId.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk.MsgId { 2 | 3 | public const string LOAD_RENDERER_EXTENSION = "LOAD_RENDERER_EXTENSION"; 4 | public const string BROWSER_CREATED = "BROWSER_CREATED"; 5 | public const string BROWSER_DESTROYED = "BROWSER_DESTROYED"; 6 | public const string AUTOLOAD_EXTENSION = "AUTOLOAD_EXTENSION"; 7 | 8 | } // namespace CefGtk.MsgId 9 | -------------------------------------------------------------------------------- /valacefgtk/NavigationRequest.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class NavigationRequest { 4 | public Cef.Browser browser {get; private set;} 5 | public Cef.Frame frame {get; private set;} 6 | public string? target_url {get; private set;} 7 | public string? target_frame_name {get; private set;} 8 | public Cef.WindowOpenDisposition target_disposition {get; private set;} 9 | public Cef.TransitionType transition_type {get; private set;} 10 | public Cef.ResourceType resource_type {get; private set;} 11 | public bool user_gesture {get; private set;} 12 | public bool new_window {get; private set;} 13 | public bool is_redirect {get; private set;} 14 | public bool allowed {get; private set;} 15 | 16 | public NavigationRequest( 17 | Cef.Browser browser, Cef.Frame frame, string? target_url, string? target_frame_name, 18 | Cef.WindowOpenDisposition target_disposition, Cef.TransitionType transition_type, 19 | Cef.ResourceType resource_type, bool user_gesture, bool new_window, bool is_redirect 20 | ) { 21 | this.browser = browser; 22 | this.frame = frame; 23 | this.target_url = target_url; 24 | this.target_frame_name = target_frame_name; 25 | this.target_disposition = target_disposition; 26 | this.transition_type = transition_type; 27 | this.resource_type = resource_type; 28 | this.user_gesture = user_gesture; 29 | this.new_window = new_window; 30 | this.is_redirect = is_redirect; 31 | this.allowed = true; 32 | } 33 | 34 | public void allow() { 35 | allowed = true; 36 | } 37 | 38 | public void cancel() { 39 | allowed = false; 40 | } 41 | } 42 | 43 | } // namespace CefGtk 44 | -------------------------------------------------------------------------------- /valacefgtk/Proxy.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public enum ProxyType { 4 | SYSTEM, 5 | NONE, 6 | HTTP, 7 | SOCKS; 8 | } 9 | 10 | [Compact] 11 | public class ProxySettings { 12 | public ProxyType type; 13 | public string? server; 14 | public uint port; 15 | 16 | public ProxySettings(ProxyType proxy_type, string? proxy_server, uint proxy_port) { 17 | this.type = proxy_type; 18 | this.server = proxy_server; 19 | this.port = proxy_port; 20 | } 21 | } 22 | 23 | } // namespace CefGtk 24 | -------------------------------------------------------------------------------- /valacefgtk/RenderHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | private class RenderHandler : Cef.RenderHandlerRef { 4 | public RenderHandler(WebViewOffscreen web_view) { 5 | base(); 6 | priv_set("web_view", web_view); 7 | 8 | /** 9 | * Return the handler for accessibility notifications. If no handler is 10 | * provided the default implementation will be used. 11 | */ 12 | /*AccessibilityHandler*/ vfunc_get_accessibility_handler = (self) => {return null;}; 13 | 14 | /** 15 | * Called to retrieve the root window rectangle in screen coordinates. Return 16 | * true (1) if the rectangle was provided. 17 | */ 18 | /*int*/ vfunc_get_root_screen_rect = (self, /*Browser*/ browser, /*Rect?*/ rect) => { 19 | return 0; 20 | }; 21 | 22 | /** 23 | * Called to retrieve the view rectangle which is relative to screen 24 | * coordinates. This function must always provide a non-NULL rectangle. 25 | */ 26 | /*void*/ vfunc_get_view_rect = (self, /*Browser*/ browser, /*Rect?*/ rect) => { 27 | ((RenderHandler) self).set_rect_from_allocation(rect); 28 | }; 29 | 30 | /** 31 | * Called to retrieve the translation from view coordinates to actual screen 32 | * coordinates. Return true (1) if the screen coordinates were provided. 33 | */ 34 | 35 | /*int*/ vfunc_get_screen_point = ( 36 | self, /*Browser*/ browser, /*int*/ viewX, /*int*/ viewY, /*int*/ ref screenX, /*int*/ ref screenY 37 | ) => { 38 | ((RenderHandler) self).get_screen_coords(viewX, viewY, ref screenX, ref screenY); 39 | return 1; 40 | }; 41 | /** 42 | * Called to allow the client to fill in the CefScreenInfo object with 43 | * appropriate values. Return true (1) if the |screen_info| structure has been 44 | * modified. 45 | * 46 | * If the screen info rectangle is left NULL the rectangle from GetViewRect 47 | * will be used. If the rectangle is still NULL or invalid popups may not be 48 | * drawn correctly. 49 | */ 50 | /*int*/ vfunc_get_screen_info = (self, /*Browser*/ browser, /*ScreenInfo*/ screen_info) => { 51 | unowned WebViewOffscreen view = ((RenderHandler) self).priv_get("web_view"); 52 | screen_info.device_scale_factor = 1.0f * view.scale_factor; 53 | ((RenderHandler) self).set_rect_from_allocation(screen_info.rect); 54 | ((RenderHandler) self).set_rect_from_allocation(screen_info.available_rect); 55 | return 1; 56 | }; 57 | 58 | /** 59 | * Called when the browser wants to show or hide the popup widget. The popup 60 | * should be shown if |show| is true (1) and hidden if |show| is false (0). 61 | */ 62 | /*void*/ vfunc_on_popup_show = (self, /*Browser*/ browser, /*int*/ show) => { 63 | message("vfunc_on_popup_show %d", show); 64 | }; 65 | 66 | /** 67 | * Called when the browser wants to move or resize the popup widget. |rect| 68 | * contains the new location and size in view coordinates. 69 | */ 70 | /*void*/ vfunc_on_popup_size = (self, /*Browser*/ browser, /*Rect*/ rect) => { 71 | message("vfunc_on_popup_size"); 72 | }; 73 | 74 | /** 75 | * Called when an element should be painted. Pixel values passed to this 76 | * function are scaled relative to view coordinates based on the value of 77 | * CefScreenInfo.device_scale_factor returned from GetScreenInfo. |type| 78 | * indicates whether the element is the view or the popup widget. |buffer| 79 | * contains the pixel data for the whole image. |dirtyRects| contains the set 80 | * of rectangles in pixel coordinates that need to be repainted. |buffer| will 81 | * be |width|*|height|*4 bytes in size and represents a BGRA image with an 82 | * upper-left origin. 83 | */ 84 | /*void*/ vfunc_on_paint = ( 85 | self, /*Browser*/ browser, /*PaintElementType*/ type, /*Rect[]*/ dirtyRects, /*void*/ buffer, 86 | /*int*/ width, /*int*/ height 87 | ) => { 88 | ((RenderHandler) self).priv_get("web_view").paint( 89 | dirtyRects, buffer, width, height); 90 | }; 91 | 92 | /** 93 | * Called when the browser's cursor has changed. If |type| is CT_CUSTOM then 94 | * |custom_cursor_info| will be populated with the custom cursor information. 95 | */ 96 | /*void*/ vfunc_on_cursor_change = ( 97 | self, /*Browser*/ browser, /*CursorHandle*/ cursor, /*CursorType*/ type, /*CursorInfo*/ custom_cursor 98 | ) => { 99 | ((RenderHandler) self).priv_get("web_view").change_cursor( 100 | cursor, type, custom_cursor); 101 | }; 102 | 103 | /** 104 | * Called when the user starts dragging content in the web view. Contextual 105 | * information about the dragged content is supplied by |drag_data|. (|x|, 106 | * |y|) is the drag start location in screen coordinates. OS APIs that run a 107 | * system message loop may be used within the StartDragging call. 108 | * 109 | * Return false (0) to abort the drag operation. Don't call any of 110 | * cef_browser_host_t::DragSource*Ended* functions after returning false (0). 111 | * 112 | * Return true (1) to handle the drag operation. Call 113 | * cef_browser_host_t::DragSourceEndedAt and DragSourceSystemDragEnded either 114 | * synchronously or asynchronously to inform the web view that the drag 115 | * operation has ended. 116 | */ 117 | /*int*/ vfunc_start_dragging = ( 118 | self, /*Browser*/ browser, /*DragData*/ drag_data, /*DragOperationsMask*/ allowed_ops, /*int*/ x, /*int*/ y 119 | ) => { 120 | message("vfunc_start_dragging"); 121 | return 0; 122 | }; 123 | 124 | /** 125 | * Called when the web view wants to update the mouse cursor during a drag & 126 | * drop operation. |operation| describes the allowed operation (none, move, 127 | * copy, link). 128 | */ 129 | /*void*/ vfunc_update_drag_cursor = (self, /*Browser*/ browser, /*DragOperationsMask*/ operation) => { 130 | message("vfunc_update_drag_cursor"); 131 | }; 132 | 133 | /** 134 | * Called when the scroll offset has changed. 135 | */ 136 | /*void*/ vfunc_on_scroll_offset_changed = (self, /*Browser*/ browser, /*double*/ x, /*double*/ y) => { 137 | unowned WebViewOffscreen view = ((RenderHandler) self).priv_get("web_view"); 138 | view.scroll_offset_x = x; 139 | view.scroll_offset_y = y; 140 | }; 141 | 142 | /** 143 | * Called when the IME composition range has changed. |selected_range| is the 144 | * range of characters that have been selected. |character_bounds| is the 145 | * bounds of each character in view coordinates. 146 | */ 147 | /*void*/ vfunc_on_ime_composition_range_changed = ( 148 | self, /*Browser*/ browser, /*Range*/ selected_range, /*Rect[]*/ character_bounds 149 | ) => { 150 | message("vfunc_on_ime_composition_range_changed"); 151 | }; 152 | 153 | /** 154 | * Called when text selection has changed for the specified |browser|. 155 | * |selected_text| is the currently selected text and |selected_range| is the 156 | * character range. 157 | */ 158 | /*void*/ vfunc_on_text_selection_changed = ( 159 | self, /*Browser*/ browser, /*String*/ selected_text, /*Range*/ selected_range 160 | ) => { 161 | message("vfunc_on_text_selection_changed"); 162 | }; 163 | } 164 | 165 | public void set_rect_from_allocation(Cef.Rect? rect) { 166 | Gtk.Allocation alloc; 167 | unowned WebViewOffscreen view = priv_get("web_view"); 168 | view.get_allocation(out alloc); 169 | rect.x = rect.y = 0; 170 | rect.width = alloc.width; 171 | rect.height = alloc.height; 172 | } 173 | 174 | public void get_screen_coords(int x, int y, ref int screen_x, ref int screen_y) { 175 | unowned WebViewOffscreen view = priv_get("web_view"); 176 | Gdk.Window? window = view.get_window(); 177 | assert (window != null); 178 | window.get_root_coords(x, y, out screen_x, out screen_y); 179 | screen_x *= view.scale_factor; 180 | screen_y *= view.scale_factor; 181 | } 182 | } 183 | 184 | } // namespace CefGtk 185 | -------------------------------------------------------------------------------- /valacefgtk/RenderProcess.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class RenderProcess : Cef.AppRef { 4 | public RenderProcess() { 5 | base(); 6 | priv_set("handler", new RenderProcessHandler()); 7 | /** 8 | * Return the handler for functionality specific to the render process. This 9 | * function is called on the render process main thread. 10 | */ 11 | /*RenderProcessHandler*/ vfunc_get_render_process_handler = (self) => { 12 | Cef.assert_renderer_thread(); 13 | return ((Cef.AppRef) self).priv_get("handler"); 14 | }; 15 | } 16 | } 17 | 18 | } // namespace CefGtk 19 | -------------------------------------------------------------------------------- /valacefgtk/RenderProcessHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class RenderProcessHandler: Cef.RenderProcessHandlerRef { 4 | public RenderProcessHandler() { 5 | base(); 6 | /** 7 | * Called after the render process main thread has been created. |extra_info| 8 | * is a read-only value originating from 9 | * cef_browser_process_handler_t::on_render_process_thread_created(). Do not 10 | * keep a reference to |extra_info| outside of this function. 11 | */ 12 | /*void*/ vfunc_on_render_thread_created = (self, /*ListValue*/ extra_info) => { 13 | Cef.assert_renderer_thread(); 14 | var _this = ((RenderProcessHandler) self); 15 | var ctx = new RendererContext(_this); 16 | ctx.init(extra_info); 17 | _this.priv_set("context", ctx); 18 | }; 19 | 20 | /** 21 | * Called when a new message is received from a different process. Return true 22 | * (1) if the message was handled or false (0) otherwise. Do not keep a 23 | * reference to or attempt to access the message outside of this callback. 24 | */ 25 | /*int*/ vfunc_on_process_message_received = (self, /*Browser*/ browser, /*Frame*/ frame, 26 | /*ProcessId*/ source_process, /*ProcessMessage*/ message) => { 27 | Cef.assert_renderer_thread(); 28 | return (int) get_ctx(self).message_received(browser, frame, message); 29 | }; 30 | 31 | /** 32 | * Called after a browser has been created. When browsing cross-origin a new 33 | * browser will be created before the old browser with the same identifier is 34 | * destroyed. 35 | */ 36 | /*void*/ vfunc_on_browser_created = (self, /*Browser*/ browser) => { 37 | Cef.assert_renderer_thread(); 38 | get_ctx(self).browser_created(browser); 39 | }; 40 | 41 | /** 42 | * Called before a browser is destroyed. 43 | */ 44 | /*void*/ vfunc_on_browser_destroyed = (self, /*Browser*/ browser) => { 45 | Cef.assert_renderer_thread(); 46 | get_ctx(self).browser_destroyed(browser); 47 | }; 48 | 49 | /** 50 | * Called immediately after the V8 context for a frame has been created. To 51 | * retrieve the JavaScript 'window' object use the 52 | * cef_v8context_t::get_global() function. V8 handles can only be accessed 53 | * from the thread on which they are created. A task runner for posting tasks 54 | * on the associated thread can be retrieved via the 55 | * cef_v8context_t::get_task_runner() function. 56 | */ 57 | /*void*/ vfunc_on_context_created = (self, /*Browser*/ browser, /*Frame*/ frame, /*V8context*/ context) => { 58 | Cef.assert_renderer_thread(); 59 | get_ctx(self).js_context_created(browser, frame, context); 60 | }; 61 | 62 | /** 63 | * Called immediately before the V8 context for a frame is released. No 64 | * references to the context should be kept after this function is called. 65 | */ 66 | /*void*/ vfunc_on_context_released = (self, /*Browser*/ browser, /*Frame*/ frame, /*V8context*/ context) => { 67 | Cef.assert_renderer_thread(); 68 | get_ctx(self).js_context_released(browser, frame, context); 69 | }; 70 | } 71 | 72 | private static RendererContext get_ctx(Cef.RenderProcessHandler self) { 73 | return ((RenderProcessHandler) self).priv_get("context"); 74 | } 75 | } 76 | 77 | } // namespace CefGtk 78 | -------------------------------------------------------------------------------- /valacefgtk/RenderSideEventLoop.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class RenderSideEventLoop : GLib.Object { 4 | public MainLoop loop; 5 | public MainContext context; 6 | public Thread thread; 7 | 8 | public RenderSideEventLoop(MainContext? main_context=null) { 9 | context = main_context ?? new MainContext(); 10 | } 11 | 12 | public RenderSideEventLoop start() { 13 | assert(thread == null); 14 | thread = new Thread("RenderSideEventLoop", run); 15 | return this; 16 | } 17 | 18 | /** 19 | * Attach an idle callback to this event loop. 20 | * 21 | * Similar to {@link GLib.Idle.add} but uses this event loop instead of the global 22 | * {@link GLib.MainContext}. 23 | * 24 | * @param function The idle callback function. 25 | * @param priority The priority of the callback. 26 | * @return Id of the corresponding event source. 27 | */ 28 | public uint add_idle(owned SourceFunc function, int priority=GLib.Priority.DEFAULT_IDLE) { 29 | var source = new IdleSource(); 30 | source.set_priority(priority); 31 | source.set_callback((owned) function); 32 | return source.attach(context); 33 | } 34 | 35 | /** 36 | * Attach a timeout callback to this event loop. 37 | * 38 | * Similar to {@link GLib.Timeout.add} but uses this event loop instead of the global 39 | * {@link GLib.MainContext}. 40 | * 41 | * @param interval_ms The number of miliseconds to wait before the callback is called. 42 | * @param function The callback function. 43 | * @param priority The priority of the callback. 44 | * @return Id of the corresponding event source. 45 | */ 46 | public uint add_timeout(uint interval_ms, owned SourceFunc function, int priority=GLib.Priority.DEFAULT) { 47 | var source = new TimeoutSource(interval_ms); 48 | source.set_priority(priority); 49 | source.set_callback((owned) function); 50 | return source.attach(context ?? MainContext.ref_thread_default()); 51 | } 52 | 53 | private void* run() { 54 | context.push_thread_default(); 55 | loop = new MainLoop(context); 56 | loop.run(); 57 | loop = null; 58 | context.pop_thread_default(); 59 | return null; 60 | } 61 | 62 | public void stop() { 63 | loop.quit(); 64 | thread.join(); 65 | thread = null; 66 | } 67 | } 68 | 69 | } // namespace CefGtk 70 | -------------------------------------------------------------------------------- /valacefgtk/RendererContext.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public delegate void InitRendererExtensionFunc(RendererContext ctx, int browser, Variant?[] parameters); 4 | 5 | public class RendererContext : GLib.Object { 6 | public RenderProcessHandler handler {get; construct;} 7 | public RenderSideEventLoop event_loop {get; construct;} 8 | private SList renderer_extensions = null; 9 | private SList autoloaded_renderer_extensions = null; 10 | 11 | public RendererContext(RenderProcessHandler handler) { 12 | GLib.Object(handler: handler, event_loop: new RenderSideEventLoop(GLib.MainContext.@default())); 13 | } 14 | 15 | public void init(Cef.ListValue? extra_info) { 16 | Cef.assert_renderer_thread(); 17 | event_loop.start(); 18 | if (extra_info != null) { 19 | var size = extra_info.get_size(); 20 | for (var i = 0; i < size; i++) { 21 | var type = extra_info.get_type(i); 22 | switch (type) { 23 | case Cef.ValueType.LIST: 24 | var list = extra_info.get_list(i); 25 | if (list.get_size() == 3 && list.get_type(0) == Cef.ValueType.STRING 26 | && list.get_type(1) == Cef.ValueType.INT && list.get_type(2) == Cef.ValueType.LIST) { 27 | var name = list.get_string(0); 28 | assert(name == MsgId.AUTOLOAD_EXTENSION); 29 | var browser_id = list.get_int(1); 30 | var parameters = Utils.convert_list_to_variant(list.get_list(2)); 31 | var path = parameters[0].get_string(); 32 | autoloaded_renderer_extensions.append( 33 | new RendererExtensionInfo(browser_id, path, parameters)); 34 | } 35 | break; 36 | default: 37 | break; 38 | } 39 | } 40 | } 41 | } 42 | 43 | public virtual signal void browser_created(Cef.Browser browser) { 44 | Cef.assert_renderer_thread(); 45 | send_message(browser, MsgId.BROWSER_CREATED, {browser.get_identifier()}); 46 | autoload_renderer_extensions(browser); 47 | } 48 | 49 | public virtual signal void browser_destroyed(Cef.Browser browser) { 50 | Cef.assert_renderer_thread(); 51 | send_message(browser, MsgId.BROWSER_DESTROYED, {browser.get_identifier()}); 52 | } 53 | 54 | public virtual signal void js_context_created(Cef.Browser browser, Cef.Frame frame, Cef.V8context context) { 55 | Cef.assert_renderer_thread(); 56 | if (frame.is_main() > 0) { 57 | message("JS Context created %d", browser.get_identifier()); 58 | } 59 | } 60 | 61 | public virtual signal void js_context_released(Cef.Browser browser, Cef.Frame frame, Cef.V8context context) { 62 | Cef.assert_renderer_thread(); 63 | if (frame.is_main() > 0) { 64 | message("JS Context released: %d", browser.get_identifier()); 65 | } 66 | } 67 | 68 | public void load_renderer_extension(Cef.Browser browser, string path, owned Variant?[] parameters) { 69 | Cef.assert_renderer_thread(); 70 | assert(GLib.Module.supported()); 71 | var module = GLib.Module.open(path, 0); 72 | if (module == null) { 73 | warning("Failed to load Renderer Extension '%s': %s", path, GLib.Module.error()); 74 | } else { 75 | void* function; 76 | module.symbol("init_renderer_extension", out function); 77 | if (function == null) { 78 | warning("renderer Extension '%s' does not contain init_renderer_extension() function.", path); 79 | } else { 80 | var extension = new RendererExtension( 81 | this, browser.get_identifier(), (owned) module, function, (owned) parameters); 82 | renderer_extensions.prepend(extension); 83 | extension.init(); 84 | } 85 | } 86 | } 87 | 88 | public void send_message(Cef.Browser browser, string name, Variant?[] parameters) { 89 | Cef.assert_renderer_thread(); 90 | var msg = Utils.create_process_message(name, parameters); 91 | send_cef_message(browser, name, msg); 92 | } 93 | 94 | private bool send_cef_message(Cef.Browser browser, string name, Cef.ProcessMessage msg) { 95 | var frame = browser.get_main_frame(); 96 | if (frame != null) { 97 | frame.send_process_message(Cef.ProcessId.BROWSER, msg); 98 | return true; 99 | } 100 | Task.schedule(Cef.ThreadId.RENDERER, 50, () => { 101 | send_cef_message(browser, name, msg); 102 | }); 103 | return false; 104 | } 105 | 106 | public bool message_received(Cef.Browser? browser, Cef.Frame? frame, Cef.ProcessMessage? msg) { 107 | Cef.assert_renderer_thread(); 108 | var args = Utils.convert_list_to_variant(msg.get_argument_list()); 109 | var name = msg.get_name(); 110 | if (name == MsgId.LOAD_RENDERER_EXTENSION) { 111 | var extension = args[0].get_string(); 112 | load_renderer_extension(browser, extension, args); 113 | } else { 114 | message("Message received: '%s'", name); 115 | } 116 | return true; 117 | } 118 | 119 | private void autoload_renderer_extensions(Cef.Browser browser) { 120 | foreach (var extension in autoloaded_renderer_extensions) { 121 | if (browser.get_identifier() == extension.browser_id) { 122 | load_renderer_extension(browser, extension.path, extension.parameters); 123 | } 124 | } 125 | } 126 | 127 | private class RendererExtension { 128 | unowned RendererContext ctx; 129 | int browser; 130 | GLib.Module? module; 131 | void* init_function; 132 | Variant?[] parameters; 133 | 134 | public RendererExtension(RendererContext ctx, int browser, owned GLib.Module? module, 135 | void* init_function, owned Variant?[] parameters) { 136 | this.ctx = ctx; 137 | this.browser = browser; 138 | this.module = (owned) module; 139 | this.init_function = init_function; 140 | this.parameters = (owned) parameters; 141 | } 142 | 143 | public void init() { 144 | InitRendererExtensionFunc init_renderer_extension = (InitRendererExtensionFunc) init_function; 145 | init_renderer_extension(ctx, browser, parameters); 146 | parameters = null; 147 | } 148 | } 149 | } 150 | 151 | } // namespace CefGtk 152 | -------------------------------------------------------------------------------- /valacefgtk/RequestHandler.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class RequestHandler: Cef.RequestHandlerRef { 4 | 5 | public RequestHandler(WebView web_view) { 6 | base(); 7 | priv_set("web_view", web_view); 8 | 9 | /** 10 | * Called on the UI thread before browser navigation. Return true (1) to 11 | * cancel the navigation or false (0) to allow the navigation to proceed. The 12 | * |request| object cannot be modified in this callback. 13 | * cef_load_handler_t::OnLoadingStateChange will be called twice in all cases. 14 | * If the navigation is allowed cef_load_handler_t::OnLoadStart and 15 | * cef_load_handler_t::OnLoadEnd will be called. If the navigation is canceled 16 | * cef_load_handler_t::OnLoadError will be called with an |errorCode| value of 17 | * ERR_ABORTED. 18 | */ 19 | /*int*/ vfunc_on_before_browse = ( 20 | self, /*Browser*/ browser, /*Frame*/ frame, /*Request*/ request, /*int*/ is_redirect 21 | ) => { 22 | bool user_gesture; 23 | switch (request.get_transition_type()) { 24 | case Cef.TransitionType.LINK: 25 | case Cef.TransitionType.EXPLICIT: 26 | case Cef.TransitionType.MANUAL_SUBFRAME: 27 | case Cef.TransitionType.FORM_SUBMIT: 28 | user_gesture = true; 29 | break; 30 | default: 31 | user_gesture = false; 32 | break; 33 | } 34 | var navigation_request = new NavigationRequest( 35 | browser, frame, request.get_url(), frame != null ? frame.get_name() : null, 36 | Cef.WindowOpenDisposition.UNKNOWN, request.get_transition_type(), 37 | request.get_resource_type(), user_gesture, false, (bool) is_redirect); 38 | unowned WebView _web_view = ((Cef.RequestHandlerRef) self).priv_get("web_view"); 39 | _web_view.navigation_request(navigation_request); 40 | return navigation_request.allowed ? 0 : 1; 41 | }; 42 | 43 | /** 44 | * Called on the UI thread before OnBeforeBrowse in certain limited cases 45 | * where navigating a new or different browser might be desirable. This 46 | * includes user-initiated navigation that might open in a special way (e.g. 47 | * links clicked via middle-click or ctrl + left-click) and certain types of 48 | * cross-origin navigation initiated from the renderer process (e.g. 49 | * navigating the top-level frame to/from a file URL). The |browser| and 50 | * |frame| values represent the source of the navigation. The 51 | * |target_disposition| value indicates where the user intended to navigate 52 | * the browser based on standard Chromium behaviors (e.g. current tab, new 53 | * tab, etc). The |user_gesture| value will be true (1) if the browser 54 | * navigated via explicit user gesture (e.g. clicking a link) or false (0) if 55 | * it navigated automatically (e.g. via the DomContentLoaded event). Return 56 | * true (1) to cancel the navigation or false (0) to allow the navigation to 57 | * proceed in the source browser's top-level frame. 58 | */ 59 | /*int*/ vfunc_on_open_urlfrom_tab = ( 60 | self, /*Browser*/ browser, /*Frame*/ frame, /*String*/ target_url, 61 | /*WindowOpenDisposition*/ target_disposition, /*int*/ user_gesture 62 | ) => { 63 | if (frame.is_main() == 1) { 64 | warning("vfunc_on_open_urlfrom_tab: '%s' %s %s", 65 | Cef.get_string(target_url), 66 | target_disposition.to_string(), 67 | user_gesture.to_string()); 68 | } 69 | return 0; 70 | }; 71 | } 72 | } 73 | 74 | } // namespace CefGtk 75 | -------------------------------------------------------------------------------- /valacefgtk/Task.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public delegate void TaskFunc(); 4 | 5 | public class Task { 6 | public static bool post(Cef.ThreadId thread_id, owned TaskFunc func) { 7 | return (bool) Cef.post_task(thread_id, new CefTask(new Task(thread_id, (owned) func))); 8 | } 9 | 10 | public static bool schedule(Cef.ThreadId thread_id, int64 delay_ms, owned TaskFunc func) { 11 | return (bool) Cef.post_delayed_task(thread_id, new CefTask(new Task(thread_id, (owned) func)), delay_ms); 12 | } 13 | 14 | private TaskFunc func; 15 | private Cef.ThreadId thread_id; 16 | 17 | private Task(Cef.ThreadId thread_id, owned TaskFunc func) { 18 | this.thread_id = thread_id; 19 | this.func = (owned) func; 20 | } 21 | 22 | private void execute() { 23 | assert(Cef.currently_on(thread_id) > 0); 24 | func(); 25 | } 26 | 27 | private class CefTask : Cef.TaskRef { 28 | public CefTask(Task task) { 29 | base(); 30 | priv_set("task", task); 31 | 32 | /** 33 | * Method that will be executed on the target thread. 34 | */ 35 | /*void*/ vfunc_execute = (self) => { 36 | ((Cef.TaskRef) self).priv_get("task").execute(); 37 | ((Cef.TaskRef) self).priv_del("task"); 38 | }; 39 | } 40 | } 41 | } 42 | 43 | } // namespace CefGtk 44 | -------------------------------------------------------------------------------- /valacefgtk/Utils.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk.Utils { 2 | 3 | /** 4 | * Create new CEF process message. 5 | * 6 | * @param name Message name. 7 | * @param parameters Message parameters. 8 | * @return New CEF process message. 9 | */ 10 | public Cef.ProcessMessage? create_process_message(string name, Variant?[] parameters) { 11 | Cef.String msg_name = {}; 12 | Cef.set_string(&msg_name, name); 13 | var msg = Cef.process_message_create(&msg_name); 14 | var args = msg.get_argument_list(); 15 | set_list_from_variant(args, parameters); 16 | return msg; 17 | } 18 | 19 | 20 | /** 21 | * Unpack variant. 22 | * 23 | * @param variant Value to unpack. 24 | * @return Unpacked variant, Variant and maybe type are replaced by child variants. 25 | */ 26 | public Variant? unpack_variant(Variant? variant) { 27 | if (variant == null) { 28 | return null; 29 | } else if (variant.is_of_type(VariantType.VARIANT)) { 30 | return unpack_variant(variant.get_variant()); 31 | } else if (variant.get_type().is_subtype_of(VariantType.MAYBE)) { 32 | Variant? maybe_variant = null; 33 | variant.get("m*", &maybe_variant); 34 | return unpack_variant(maybe_variant); 35 | } 36 | return variant; 37 | } 38 | 39 | 40 | /** 41 | * Populate CEF list with Variant values. 42 | * 43 | * @param list CEF list to populate. 44 | * @param values Variant values. 45 | */ 46 | public void set_list_from_variant(Cef.ListValue list, Variant?[] values, int offset=0) { 47 | list.set_size(values.length + offset); 48 | for (var i = 0; i < values.length; i++) { 49 | var index = offset + i; 50 | var variant = unpack_variant(values[i]); 51 | if (variant == null) { 52 | list.set_null(index); 53 | } else { 54 | var type = variant.get_type(); 55 | var object_type = new VariantType("a{s*}"); 56 | if (type.is_subtype_of(object_type)) { 57 | critical("Object type is not supported (%d).", index); 58 | list.set_null(index); 59 | } else if (variant.is_of_type(VariantType.STRING)) { 60 | Cef.String cef_string = {}; 61 | Cef.set_string(&cef_string, variant.get_string()); 62 | list.set_string(index, &cef_string); 63 | } else if (variant.is_of_type(VariantType.BOOLEAN)) { 64 | list.set_bool(index, variant.get_boolean() ? 1 : 0); 65 | } else if (variant.is_of_type(VariantType.DOUBLE)) { 66 | list.set_double(index, variant.get_double()); 67 | } else if (variant.is_of_type(VariantType.INT32)) { 68 | list.set_int(index, (int) variant.get_int32()); 69 | } else if (variant.is_of_type(VariantType.UINT32)) { 70 | list.set_int(index, (int) variant.get_uint32()); 71 | } else if (variant.is_of_type(VariantType.INT64)) { 72 | list.set_int(index, (int) variant.get_int64()); 73 | } else if (variant.is_of_type(VariantType.UINT64)) { 74 | list.set_int(index, (int) variant.get_uint64()); 75 | } else { 76 | critical("Type %s not supported at index %d", type.dup_string(), index); 77 | list.set_null(index); 78 | } 79 | } 80 | } 81 | } 82 | 83 | /** 84 | * Convert CEF list to Variant values. 85 | * 86 | * @param list CEF list to convert. 87 | * @return Variant values. 88 | */ 89 | public Variant?[] convert_list_to_variant(Cef.ListValue list) { 90 | var size = list.get_size(); 91 | if (size == 0) { 92 | return {}; 93 | } 94 | var result = new Variant?[size]; 95 | for (var index = 0; index < size; index++) { 96 | var type = list.get_type(index); 97 | switch (type) { 98 | case Cef.ValueType.NULL: 99 | result[index] = null; 100 | break; 101 | case Cef.ValueType.BOOL: 102 | result[index] = new Variant.boolean(list.get_bool(index) > 0); 103 | break; 104 | case Cef.ValueType.INT: 105 | result[index] = new Variant.int64(list.get_int(index)); 106 | break; 107 | case Cef.ValueType.DOUBLE: 108 | result[index] = new Variant.double(list.get_double(index)); 109 | break; 110 | case Cef.ValueType.STRING: 111 | result[index] = new Variant.string(list.get_string(index)); 112 | break; 113 | case Cef.ValueType.INVALID: 114 | case Cef.ValueType.BINARY: 115 | case Cef.ValueType.DICTIONARY: 116 | case Cef.ValueType.LIST: 117 | default: 118 | critical("Unsupported type %s at index %d.", type.to_string(), index); 119 | result[index] = null; 120 | break; 121 | } 122 | } 123 | return result; 124 | } 125 | 126 | } // CefGtk.Utils 127 | -------------------------------------------------------------------------------- /valacefgtk/WeakRef.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class WeakRef { 4 | private GLib.Object object = null; 5 | 6 | public WeakRef(GLib.Object object) { 7 | set(object); 8 | } 9 | 10 | public T? get() { 11 | lock (this.object) { 12 | return (T) this.object; 13 | } 14 | } 15 | 16 | public void set(GLib.Object? object) { 17 | assert(object == null || object is T); 18 | lock (this.object) { 19 | if (this.object != null) { 20 | this.object.weak_unref(on_finalized); 21 | } 22 | this.object = object; 23 | this.object.weak_ref(on_finalized); 24 | } 25 | } 26 | 27 | private void on_finalized(GLib.Object object) { 28 | lock (this.object) { 29 | assert(this.object == object); 30 | this.object.weak_unref(on_finalized); 31 | this.object = null; 32 | } 33 | } 34 | } 35 | 36 | } // namespace CefGtk 37 | -------------------------------------------------------------------------------- /valacefgtk/WebContext.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class WebContext : GLib.Object { 4 | private static SList> all_contexts = null; 5 | public string? user_data_path {get; construct;} 6 | internal Cef.RequestContext request_context; 7 | internal Cef.RequestContextHandlerRef context_handler; 8 | internal Cef.CookieManager cookie_manager; 9 | 10 | public static void notify_render_process_created(Cef.ListValue extra_info) { 11 | foreach (unowned WeakRef weakref in all_contexts) { 12 | var ctx = weakref.get(); 13 | if (ctx != null) { 14 | ctx.render_process_created(extra_info); 15 | } 16 | } 17 | } 18 | 19 | public WebContext(string? user_data_path) { 20 | GLib.Object(user_data_path: user_data_path); 21 | all_contexts.append(new WeakRef(this)); 22 | } 23 | 24 | public signal void render_process_created(Cef.ListValue extra_info); 25 | 26 | construct { 27 | assert(CefGtk.is_initialized()); 28 | Cef.assert_browser_ui_thread(); 29 | Cef.RequestContextSettings request_settings = {sizeof(Cef.RequestContextSettings)}; 30 | if (user_data_path != null) { 31 | Cef.set_string(&request_settings.cache_path, user_data_path); 32 | } 33 | request_settings.persist_user_preferences = 1; 34 | request_settings.enable_net_security_expiration = 1; 35 | 36 | 37 | context_handler = new Handler(); 38 | request_context = Cef.request_context_create_context(request_settings, context_handler); 39 | cookie_manager = request_context.get_cookie_manager(null); 40 | assert(cookie_manager != null); 41 | Timeout.add(200, () => { 42 | cookie_manager.flush_store(null); 43 | return true; 44 | }); 45 | } 46 | 47 | private class Handler : Cef.RequestContextHandlerRef { 48 | public Handler() { 49 | base(); 50 | 51 | /** 52 | * Called on the browser process UI thread immediately after the request 53 | * context has been initialized. 54 | */ 55 | /*void vfunc_on_request_context_initialized(owned RequestContext? request_context);*/ 56 | 57 | /** 58 | * Called on multiple browser process threads before a plugin instance is 59 | * loaded. |mime_type| is the mime type of the plugin that will be loaded. 60 | * |plugin_url| is the content URL that the plugin will load and may be NULL. 61 | * |is_main_frame| will be true (1) if the plugin is being loaded in the main 62 | * (top-level) frame, |top_origin_url| is the URL for the top-level frame that 63 | * contains the plugin when loading a specific plugin instance or NULL when 64 | * building the initial list of enabled plugins for 'navigator.plugins' 65 | * JavaScript state. |plugin_info| includes additional information about the 66 | * plugin that will be loaded. |plugin_policy| is the recommended policy. 67 | * Modify |plugin_policy| and return true (1) to change the policy. Return 68 | * false (0) to use the recommended policy. The default plugin policy can be 69 | * set at runtime using the `--plugin-policy=[allow|detect|block]` command- 70 | * line flag. Decisions to mark a plugin as disabled by setting 71 | * |plugin_policy| to PLUGIN_POLICY_DISABLED may be cached when 72 | * |top_origin_url| is NULL. To purge the plugin list cache and potentially 73 | * trigger new calls to this function call 74 | * cef_request_tContext::PurgePluginListCache. 75 | */ 76 | /*int on_before_plugin_load(String* mime_type, String* plugin_url, int is_main_frame, String* top_origin_url, owned WebPluginInfo? plugin_info, PluginPolicy? plugin_policy);*/ 77 | 78 | } 79 | } 80 | } 81 | 82 | } // namespace CefGtk 83 | -------------------------------------------------------------------------------- /valacefgtk/WebViewOffscreen.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | private class WebViewOffscreen : Gtk.DrawingArea, WebViewWidget { 4 | public double scroll_offset_x {get; internal set; default = 0.0;} 5 | public double scroll_offset_y {get; internal set; default = 0.0;} 6 | private unowned WebView web_view; 7 | private unowned Cef.Browser browser = null; 8 | Cairo.ImageSurface? surface = null; 9 | private uint update_source_id = 0; 10 | 11 | public WebViewOffscreen(WebView web_view) { 12 | this.web_view = web_view; 13 | set_can_focus(true); 14 | set_has_window(true); 15 | set_focus_on_click(true); 16 | add_events( 17 | Gdk.EventMask.POINTER_MOTION_MASK 18 | |Gdk.EventMask.BUTTON_PRESS_MASK 19 | |Gdk.EventMask.BUTTON_RELEASE_MASK 20 | |Gdk.EventMask.BUTTON_PRESS_MASK 21 | |Gdk.EventMask.KEY_PRESS_MASK 22 | |Gdk.EventMask.KEY_RELEASE_MASK 23 | |Gdk.EventMask.ENTER_NOTIFY_MASK 24 | |Gdk.EventMask.LEAVE_NOTIFY_MASK 25 | |Gdk.EventMask.FOCUS_CHANGE_MASK 26 | |Gdk.EventMask.SCROLL_MASK 27 | ); 28 | notify["scale-factor"].connect_after(on_scale_factor_changed); 29 | } 30 | 31 | ~WebViewOffscreen() { 32 | notify["scale-factor"].disconnect(on_scale_factor_changed); 33 | } 34 | 35 | public override void realize() { 36 | Gtk.Allocation allocation; 37 | get_allocation(out allocation); 38 | set_realized(true); 39 | set_redraw_on_allocate(false); 40 | base.realize(); 41 | embed_cef(); 42 | update_source_id = Timeout.add(200, () => { 43 | // FIXME: This is only a workaround. 44 | if (visible && !web_view.context_menu_visible) { 45 | browser.get_host().was_hidden((int) true); 46 | browser.get_host().was_hidden((int) false); 47 | } 48 | return true; 49 | }); 50 | } 51 | 52 | public override void unrealize() { 53 | Source.remove(update_source_id); 54 | update_source_id = 0; 55 | web_view.close_browser(true); 56 | surface = null; 57 | base.unrealize(); 58 | } 59 | 60 | public override void show() { 61 | base.show(); 62 | if (get_realized()) { 63 | browser.get_host().was_hidden((int) false); 64 | } 65 | } 66 | 67 | public override void hide() { 68 | base.hide(); 69 | if (get_realized()) { 70 | browser.get_host().was_hidden((int) true); 71 | } 72 | } 73 | 74 | public override void size_allocate (Gtk.Allocation allocation) { 75 | set_allocation(allocation); 76 | if (browser != null) { 77 | browser.get_host().was_resized(); 78 | } 79 | base.size_allocate(allocation); 80 | } 81 | 82 | private void embed_cef() { 83 | assert(CefGtk.is_initialized()); 84 | Cef.assert_browser_ui_thread(); 85 | Gtk.Allocation allocation; 86 | get_allocation(out allocation); 87 | Cef.WindowInfo window_info = {}; 88 | window_info.parent_window = 0; 89 | window_info.windowless_rendering_enabled = 1; 90 | window_info.x = 0; 91 | window_info.y = 0; 92 | window_info.width = 0; 93 | window_info.height = 0; 94 | Cef.BrowserSettings browser_settings = {sizeof(Cef.BrowserSettings)}; 95 | browser_settings.javascript_access_clipboard = Cef.State.ENABLED; 96 | browser_settings.javascript_dom_paste = Cef.State.ENABLED; 97 | browser_settings.universal_access_from_file_urls = Cef.State.ENABLED; 98 | browser_settings.file_access_from_file_urls = Cef.State.ENABLED; 99 | browser_settings.windowless_frame_rate = 60 ; 100 | var client = new Client( 101 | web_view, 102 | new FocusHandler(web_view), 103 | new DisplayHandler(web_view), 104 | new LoadHandler(web_view), 105 | new JsdialogHandler(web_view), 106 | new DownloadHandler(web_view.download_manager), 107 | new KeyboardHandler(web_view), 108 | new RequestHandler(web_view), 109 | new LifeSpanHandler(web_view), 110 | new RenderHandler(this)); 111 | Cef.String url = {}; 112 | Cef.set_string(&url, "about:blank"); 113 | Cef.Browser browser = Cef.browser_host_create_browser_sync( 114 | window_info, client, &url, browser_settings, null, web_view.web_context.request_context); 115 | this.browser = browser; 116 | browser_created(client, browser); 117 | } 118 | 119 | public override bool draw(Cairo.Context cr) { 120 | if (surface != null) { 121 | Gdk.Rectangle clip; 122 | if (!Gdk.cairo_get_clip_rectangle(cr, out clip)) { 123 | return false; 124 | } 125 | cr.save(); 126 | /* The surface is in device pixels, but cairo scale is in logical pixels. */ 127 | int factor = scale_factor; 128 | cr.scale(1.0 / factor, 1.0 / factor); 129 | cr.rectangle(factor * clip.x, factor * clip.y, factor * clip.width, factor * clip.height); 130 | surface.mark_dirty(); 131 | cr.set_source_surface(surface, 0, 0); 132 | cr.set_operator(Cairo.Operator.OVER); 133 | cr.fill(); 134 | cr.restore(); 135 | } 136 | return true; 137 | } 138 | 139 | internal void paint(Cef.Rect[] dirty_rects, void* buffer, int width, int height) { 140 | /* Width & height are in device pixels, not logical pixels. */ 141 | if (width <= 2 || height <= 2) { 142 | surface = null; 143 | return; 144 | } 145 | if (surface == null || surface.get_width() != width || surface.get_height() != height) { 146 | surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, width, height); 147 | } 148 | unowned uint8[] pixels = (uint8[])surface.get_data(); 149 | unowned uint8[] dirty = (uint8[]) buffer; 150 | int stride = surface.get_stride(); 151 | foreach (unowned Cef.Rect rect in dirty_rects) { 152 | for (var x = rect.x; x < rect.x + rect.width; x++) { 153 | for (var y = rect.y; y < rect.y + rect.height; y++) { 154 | int cr_pos = y * stride + x * 4; 155 | int cef_pos = y * width * 4 + x * 4; 156 | pixels[cr_pos + 0] = dirty[cef_pos + 0]; 157 | pixels[cr_pos + 1] = dirty[cef_pos + 1]; 158 | pixels[cr_pos + 2] = dirty[cef_pos + 2]; 159 | pixels[cr_pos + 3] = dirty[cef_pos + 3]; 160 | } 161 | } 162 | } 163 | foreach (unowned Cef.Rect rect in dirty_rects) { 164 | queue_draw_area(rect.x, rect.y, rect.width, rect.height); 165 | } 166 | } 167 | 168 | public override bool button_press_event(Gdk.EventButton event) { 169 | grab_focus(); 170 | web_view.send_click_event(event); 171 | return Gdk.EVENT_STOP; 172 | } 173 | 174 | public override bool button_release_event(Gdk.EventButton event) { 175 | grab_focus(); 176 | web_view.send_click_event(event); 177 | return Gdk.EVENT_STOP; 178 | } 179 | 180 | public override bool motion_notify_event(Gdk.EventMotion event) { 181 | web_view.send_motion_event(event); 182 | return Gdk.EVENT_STOP; 183 | } 184 | 185 | public override bool scroll_event(Gdk.EventScroll event) { 186 | web_view.send_scroll_event(event); 187 | return Gdk.EVENT_STOP; 188 | } 189 | 190 | public override void grab_focus() { 191 | base.grab_focus(); 192 | web_view.send_focus_toggled(true); 193 | } 194 | 195 | public override bool focus(Gtk.DirectionType direction) { 196 | grab_focus(); 197 | return Gdk.EVENT_STOP; 198 | } 199 | 200 | public override bool focus_in_event(Gdk.EventFocus event) { 201 | web_view.send_focus_event(event); 202 | return Gdk.EVENT_STOP; 203 | } 204 | 205 | public override bool focus_out_event(Gdk.EventFocus event) { 206 | web_view.send_focus_event(event); 207 | return Gdk.EVENT_STOP; 208 | } 209 | 210 | public override bool key_press_event(Gdk.EventKey event) { 211 | web_view.send_key_event(event); 212 | return Gdk.EVENT_STOP; 213 | } 214 | 215 | public override bool key_release_event(Gdk.EventKey event) { 216 | web_view.send_key_event(event); 217 | return Gdk.EVENT_STOP; 218 | } 219 | 220 | public void change_cursor(Cef.CursorHandle cursor, Cef.CursorType type, Cef.CursorInfo? custom_cursor) { 221 | var window = (Gdk.X11.Window) get_window(); 222 | var display = (Gdk.X11.Display) window.get_display(); 223 | unowned string? name = null; 224 | switch (type) { 225 | case Cef.CursorType.POINTER: 226 | name = "default"; 227 | break; 228 | case Cef.CursorType.CROSS: 229 | name = "crosshair"; 230 | break; 231 | case Cef.CursorType.HAND: 232 | name = "pointer"; 233 | break; 234 | case Cef.CursorType.IBEAM: 235 | name = "text"; 236 | break; 237 | case Cef.CursorType.WAIT: 238 | name = "wait"; 239 | break; 240 | case Cef.CursorType.HELP: 241 | name = "help"; 242 | break; 243 | case Cef.CursorType.EASTRESIZE: 244 | case Cef.CursorType.EASTPANNING: 245 | name = "e-resize"; 246 | break; 247 | case Cef.CursorType.NORTHRESIZE: 248 | case Cef.CursorType.NORTHPANNING: 249 | name = "n-resize"; 250 | break; 251 | case Cef.CursorType.NORTHEASTRESIZE: 252 | case Cef.CursorType.NORTHEASTPANNING: 253 | name = "ne-resize"; 254 | break; 255 | case Cef.CursorType.NORTHWESTRESIZE: 256 | case Cef.CursorType.NORTHWESTPANNING: 257 | name = "nw-resize"; 258 | break; 259 | case Cef.CursorType.SOUTHRESIZE: 260 | case Cef.CursorType.SOUTHPANNING: 261 | name = "s-resize"; 262 | break; 263 | case Cef.CursorType.SOUTHEASTRESIZE: 264 | case Cef.CursorType.SOUTHEASTPANNING: 265 | name = "se-resize"; 266 | break; 267 | case Cef.CursorType.SOUTHWESTRESIZE: 268 | case Cef.CursorType.SOUTHWESTPANNING: 269 | name = "sw-resize"; 270 | break; 271 | case Cef.CursorType.WESTRESIZE: 272 | case Cef.CursorType.WESTPANNING: 273 | name = "w-resize"; 274 | break; 275 | case Cef.CursorType.NORTHSOUTHRESIZE: 276 | name = "ns-resize"; 277 | break; 278 | case Cef.CursorType.EASTWESTRESIZE: 279 | name = "ew-resize"; 280 | break; 281 | case Cef.CursorType.NORTHEASTSOUTHWESTRESIZE: 282 | name = "nesw-resize"; 283 | break; 284 | case Cef.CursorType.NORTHWESTSOUTHEASTRESIZE: 285 | name = "nwse-resize"; 286 | break; 287 | case Cef.CursorType.COLUMNRESIZE: 288 | name = "col-resize"; 289 | break; 290 | case Cef.CursorType.ROWRESIZE: 291 | name = "row-resize"; 292 | break; 293 | case Cef.CursorType.MOVE: 294 | case Cef.CursorType.MIDDLEPANNING: 295 | name = "move"; 296 | break; 297 | case Cef.CursorType.VERTICALTEXT: 298 | name = "vertical-text"; 299 | break; 300 | case Cef.CursorType.CELL: 301 | name = "cell"; 302 | break; 303 | case Cef.CursorType.CONTEXTMENU: 304 | name = "context-menu"; 305 | break; 306 | case Cef.CursorType.ALIAS: 307 | name = "alias"; 308 | break; 309 | case Cef.CursorType.PROGRESS: 310 | name = "progress"; 311 | break; 312 | case Cef.CursorType.NODROP: 313 | name = "no-drop"; 314 | break; 315 | case Cef.CursorType.COPY: 316 | name = "copy"; 317 | break; 318 | case Cef.CursorType.NONE: 319 | name = "none"; 320 | break; 321 | case Cef.CursorType.NOTALLOWED: 322 | name = "not-allowed"; 323 | break; 324 | case Cef.CursorType.ZOOMIN: 325 | name = "zoom-in"; 326 | break; 327 | case Cef.CursorType.ZOOMOUT: 328 | name = "zoom-out"; 329 | break; 330 | case Cef.CursorType.GRAB: 331 | name = "grab"; 332 | break; 333 | case Cef.CursorType.GRABBING: 334 | name = "grabbing"; 335 | break; 336 | case Cef.CursorType.CUSTOM: 337 | int width = custom_cursor.size.width; 338 | int height = custom_cursor.size.height; 339 | int x = custom_cursor.hotspot.x; 340 | int y = custom_cursor.hotspot.y; 341 | unowned uint8[] buffer = (uint8[]) custom_cursor.buffer; 342 | buffer.length = 4 * width * height; 343 | var pixbuf = new Gdk.Pixbuf.from_data(buffer, Gdk.Colorspace.RGB, true, 8, width, height, 4 * width); 344 | window.set_cursor(new Gdk.Cursor.from_pixbuf(display, pixbuf, x, y)); 345 | return; 346 | default: 347 | name = "default"; 348 | break; 349 | } 350 | if (name != null) { 351 | window.set_cursor(new Gdk.Cursor.from_name(display, name)); 352 | } 353 | } 354 | 355 | private void on_scale_factor_changed(GLib.Object o, ParamSpec p) { 356 | web_view.update_screen_info(); 357 | } 358 | } 359 | 360 | } // namespace CefGtk 361 | -------------------------------------------------------------------------------- /valacefgtk/WebViewWidget.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public interface WebViewWidget : Gtk.Widget { 4 | public signal void browser_created(Client client, Cef.Browser browser); 5 | 6 | public virtual Gdk.Pixbuf? get_snapshot() { 7 | Gtk.Allocation allocation; 8 | get_allocation(out allocation); 9 | return Gdk.pixbuf_get_from_window(get_window(), 0, 0, allocation.width, allocation.height); 10 | } 11 | } 12 | 13 | } // namespace CefGtk 14 | -------------------------------------------------------------------------------- /valacefgtk/WebViewWindowed.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | private class WebViewWindowed : Gtk.Widget, WebViewWidget { 4 | private Gdk.X11.Window? chromium_window = null; 5 | private Gdk.X11.Window? cef_window = null; 6 | private unowned WebView web_view; 7 | 8 | public WebViewWindowed(WebView web_view) { 9 | this.web_view = web_view; 10 | set_has_window(true); 11 | set_can_focus(false); 12 | } 13 | 14 | public override void get_preferred_width(out int minimum_width, out int natural_width) { 15 | minimum_width = natural_width = 100; 16 | } 17 | 18 | public override void get_preferred_height(out int minimum_height, out int natural_height) { 19 | minimum_height = natural_height = 100; 20 | } 21 | 22 | public override void realize() { 23 | Gtk.Allocation allocation; 24 | get_allocation(out allocation); 25 | set_realized(true); 26 | 27 | Gdk.WindowAttr attributes = {}; 28 | attributes.x = allocation.x; 29 | attributes.y = allocation.y; 30 | attributes.width = allocation.width; 31 | attributes.height = allocation.height; 32 | attributes.window_type = Gdk.WindowType.CHILD; 33 | attributes.visual = get_visual(); 34 | attributes.wclass = Gdk.WindowWindowClass.INPUT_OUTPUT; 35 | attributes.event_mask = (get_events() 36 | | Gdk.EventMask.BUTTON_MOTION_MASK 37 | | Gdk.EventMask.BUTTON_PRESS_MASK 38 | | Gdk.EventMask.BUTTON_RELEASE_MASK 39 | | Gdk.EventMask.EXPOSURE_MASK 40 | | Gdk.EventMask.ENTER_NOTIFY_MASK 41 | | Gdk.EventMask.LEAVE_NOTIFY_MASK); 42 | Gdk.WindowAttributesType attributes_mask = ( 43 | Gdk.WindowAttributesType.X | Gdk.WindowAttributesType.Y | Gdk.WindowAttributesType.VISUAL); 44 | 45 | var window = new Gdk.Window (get_parent_window (), attributes, attributes_mask); 46 | set_window(window); 47 | register_window(window); 48 | embed_cef(); 49 | } 50 | 51 | public override void size_allocate (Gtk.Allocation allocation) { 52 | Gtk.Allocation child_allocation = {}; 53 | set_allocation(allocation); 54 | if (!get_has_window()) { 55 | child_allocation.x = allocation.x; 56 | child_allocation.y = allocation.y; 57 | } 58 | else { 59 | child_allocation.x = 0; 60 | child_allocation.y = 0; 61 | } 62 | child_allocation.width = allocation.width; 63 | child_allocation.height = allocation.height; 64 | if (get_realized() && get_has_window()) { 65 | debug("allocation %d,%d+%d,%d child_allocation %d,%d+%d,%d", 66 | allocation.x, allocation.y, allocation.width, allocation.height, 67 | child_allocation.x, child_allocation.y, child_allocation.width, child_allocation.height); 68 | get_window().move_resize(allocation.x, allocation.y, child_allocation.width, child_allocation.height); 69 | cef_window.move_resize(child_allocation.x, child_allocation.y, child_allocation.width, child_allocation.height); 70 | } 71 | } 72 | 73 | private void embed_cef() { 74 | assert(CefGtk.is_initialized()); 75 | Cef.assert_browser_ui_thread(); 76 | var toplevel = get_toplevel(); 77 | assert(toplevel.is_toplevel()); 78 | CefGtk.override_system_visual(toplevel.get_visual()); 79 | var parent_window = get_window() as Gdk.X11.Window; 80 | assert(parent_window != null); 81 | Gtk.Allocation allocation; 82 | get_allocation(out allocation); 83 | Cef.WindowInfo window_info = {}; 84 | window_info.parent_window = (Cef.WindowHandle) parent_window.get_xid(); 85 | window_info.x = 0; 86 | window_info.y = 0; 87 | window_info.width = allocation.width; 88 | window_info.height = allocation.height; 89 | Cef.BrowserSettings browser_settings = {sizeof(Cef.BrowserSettings)}; 90 | browser_settings.javascript_access_clipboard = Cef.State.ENABLED; 91 | browser_settings.javascript_dom_paste = Cef.State.ENABLED; 92 | browser_settings.universal_access_from_file_urls = Cef.State.ENABLED; 93 | browser_settings.file_access_from_file_urls = Cef.State.ENABLED; 94 | var client = new Client( 95 | web_view, 96 | new FocusHandler(web_view), 97 | new DisplayHandler(web_view), 98 | new LoadHandler(web_view), 99 | new JsdialogHandler(web_view), 100 | new DownloadHandler(web_view.download_manager), 101 | new KeyboardHandler(web_view), 102 | new RequestHandler(web_view), 103 | new LifeSpanHandler(web_view), 104 | null); 105 | Cef.String url = {}; 106 | Cef.set_string(&url, "about:blank"); 107 | Cef.Browser browser = Cef.browser_host_create_browser_sync( 108 | window_info, client, &url, browser_settings, null, web_view.web_context.request_context); 109 | 110 | var host = browser.get_host(); 111 | cef_window = wrap_xwindow( 112 | parent_window.get_display() as Gdk.X11.Display, (X.Window) host.get_window_handle()); 113 | cef_window.ensure_native(); 114 | register_window(cef_window); 115 | chromium_window = find_child_window(cef_window); 116 | assert(chromium_window != null); 117 | chromium_window.ensure_native(); 118 | register_window(chromium_window); 119 | browser_created(client, browser); 120 | } 121 | } 122 | 123 | } // namespace CefGtk 124 | -------------------------------------------------------------------------------- /valacefgtk/WidevinePlugin.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public class WidevinePlugin: GLib.Object { 4 | public bool registration_complete {get; private set; default = false;} 5 | public bool available {get; private set; default = false;} 6 | public Cef.CdmRegistrationError registration_status { 7 | get; private set; default = Cef.CdmRegistrationError.NOT_SUPPORTED;} 8 | public string? registration_error {get; private set; default = null;} 9 | 10 | public WidevinePlugin() { 11 | } 12 | 13 | public void register(string path) { 14 | assert(!CefGtk.is_initialized()); 15 | debug("Widevine path: %s", path); 16 | Cef.String cef_path = {}; 17 | Cef.set_string(&cef_path, path); 18 | Cef.register_widevine_cdm(&cef_path, new RegisterCallback(this)); 19 | } 20 | 21 | public virtual signal void registration_finished(Cef.CdmRegistrationError status, string? error) { 22 | this.registration_status = status; 23 | this.registration_error = error; 24 | this.registration_complete = true; 25 | this.available = status == Cef.CdmRegistrationError.NONE; 26 | if (available) { 27 | message("WidevinePlugin is available: %d %s", (int) status, error); 28 | } else { 29 | warning("WidevinePlugin not available: %d %s", (int) status, error); 30 | } 31 | } 32 | 33 | public class RegisterCallback: Cef.RegisterCdmCallbackRef { 34 | public RegisterCallback(WidevinePlugin plugin) { 35 | base(); 36 | priv_set("plugin", plugin); 37 | vfunc_on_cdm_registration_complete = (self, /*CdmRegistrationError*/ result, /*String*/ error_message) => { 38 | Cef.assert_browser_ui_thread(); 39 | ((Cef.RegisterCdmCallbackRef) self).priv_get("plugin").registration_finished( 40 | result, Cef.get_string(error_message)); 41 | }; 42 | } 43 | } 44 | } 45 | 46 | } // namespace CefGtk 47 | -------------------------------------------------------------------------------- /valacefgtk/init.vala: -------------------------------------------------------------------------------- 1 | extern const string VALACEF_LIBDIR; 2 | 3 | namespace CefGtk { 4 | 5 | private static InitializationResult? initialization_result = null; 6 | private static uint message_loop_source_id = 0; 7 | 8 | public class InitializationResult { 9 | public string cef_lib_dir {get; private set;} 10 | public WidevinePlugin? widevine_plugin {get; private set;} 11 | public FlashPlugin? flash_plugin {get; private set;} 12 | public BrowserProcess app {get; private set;} 13 | 14 | public InitializationResult(BrowserProcess app, string cef_lib_dir, WidevinePlugin? widevine_plugin, 15 | FlashPlugin? flash_plugin) { 16 | this.cef_lib_dir = cef_lib_dir; 17 | this.widevine_plugin = widevine_plugin; 18 | this.flash_plugin = flash_plugin; 19 | this.app = app; 20 | } 21 | } 22 | 23 | public InitializationResult init( 24 | InitFlags? flags, double scale_factor, 25 | string? widevine_plugin_dir=null, string? flash_plugin_dir=null, 26 | string? user_agent=null, string? product_version=null, 27 | ProxyType proxy_type=ProxyType.SYSTEM, string? proxy_server=null, uint proxy_port=0) { 28 | assert (initialization_result == null); 29 | 30 | if (Cef.get_chromium_major() != Cef.get_valacef_major() 31 | || Cef.get_chromium_branch() != Cef.get_valacef_branch()) { 32 | error( 33 | "Incompatible versions: ValaCEF %s, Chromium %s", 34 | Cef.get_valacef_version(), Cef.get_chromium_version()); 35 | } 36 | 37 | Cef.enable_highdpi_support(); 38 | set_x11_error_handlers(); 39 | 40 | Cef.MainArgs main_args = {0, null}; 41 | FlashPlugin? flash_plugin = null; 42 | if (flash_plugin_dir != null) { 43 | flash_plugin = new FlashPlugin(); 44 | if (!flash_plugin.register(flash_plugin_dir)) { 45 | warning("Failed to register Flash plugin: %s", flash_plugin.registration_error); 46 | } 47 | } 48 | var app = new BrowserProcess(flags, flash_plugin, scale_factor, new ProxySettings(proxy_type, proxy_server, proxy_port)); 49 | var code = Cef.execute_process(main_args, app, null); 50 | assert(code < 0); 51 | 52 | Cef.Settings settings = {sizeof(Cef.Settings)}; 53 | settings.no_sandbox = 1; 54 | /* Even if we use a fixed 50 ms timer (see bellow), 55 | * turning the external_message_pump on decreases CPU usage rapidly. */ 56 | // But clipboard paste does not work: tiliado/valacef#2 57 | settings.external_message_pump = (int) ((Environment.get_variable("CEF_EXTERNAL_MESSAGE_PUMP") ?? "no") == "yes"); 58 | settings.log_severity = Cef.LogSeverity.WARNING; 59 | Cef.set_string(&settings.resources_dir_path, Cef.get_cef_lib_dir()); 60 | Cef.set_string(&settings.locales_dir_path, Cef.get_cef_lib_dir() + "/locales"); 61 | var subprocess_path = Environment.get_variable("CEF_SUBPROCESS_PATH") ?? (VALACEF_LIBDIR + "/ValacefSubprocess"); 62 | assert(FileUtils.test(subprocess_path, FileTest.IS_EXECUTABLE)); 63 | Cef.set_string(&settings.browser_subprocess_path, subprocess_path); 64 | WidevinePlugin? widevine_plugin = null; 65 | if (widevine_plugin_dir != null) { 66 | File base_dir = File.new_for_path(widevine_plugin_dir); 67 | File libwidevine = base_dir.get_child("libwidevinecdm.so"); 68 | File adapter = base_dir.get_child("libwidevinecdmadapter.so"); 69 | File manifest = base_dir.get_child("manifest.json"); 70 | if (libwidevine.query_exists()) { 71 | try { 72 | if (adapter.query_file_type(GLib.FileQueryInfoFlags.NONE, null) != GLib.FileType.REGULAR) { 73 | try { 74 | adapter.@delete(null); 75 | } catch (GLib.Error e) { 76 | debug("Failed to remove '%s'. %s", adapter.get_path(), e.message); 77 | } 78 | adapter.make_symbolic_link(Cef.get_widevine_adapter_path(), null); 79 | } 80 | if (manifest.query_file_type(GLib.FileQueryInfoFlags.NONE, null) != GLib.FileType.REGULAR) { 81 | try { 82 | manifest.@delete(null); 83 | } catch (GLib.Error e) { 84 | debug("Failed to remove '%s'. %s", manifest.get_path(), e.message); 85 | } 86 | manifest.make_symbolic_link(Cef.get_widevine_manifest_path(), null); 87 | } 88 | } catch (GLib.Error e) { 89 | warning("Failed to set up Widevine adapter/manifest symlinks. %s", e.message); 90 | } 91 | widevine_plugin = new WidevinePlugin(); 92 | widevine_plugin.register(widevine_plugin_dir); 93 | } else { 94 | warning("%s does not exist.", libwidevine.get_path()); 95 | } 96 | } else { 97 | debug("No widevine plugin dir."); 98 | } 99 | if (user_agent != null) { 100 | Cef.set_string(&settings.user_agent, user_agent); 101 | } else if (product_version != null) { 102 | Cef.set_string(&settings.product_version, product_version); 103 | } 104 | 105 | Cef.initialize(main_args, settings, app, null); 106 | var source = new TimeoutSource(20); 107 | source.set_priority(GLib.Priority.DEFAULT_IDLE); 108 | source.set_callback(() => { 109 | Cef.do_message_loop_work(); 110 | return true; 111 | }); 112 | source.set_can_recurse(false); 113 | message_loop_source_id = source.attach(MainContext.ref_thread_default()); 114 | 115 | initialization_result = new InitializationResult(app, Cef.get_cef_lib_dir(), widevine_plugin, flash_plugin); 116 | return initialization_result; 117 | } 118 | 119 | public bool is_initialized() { 120 | return initialization_result != null; 121 | } 122 | 123 | public InitializationResult? get_init_result() { 124 | return initialization_result; 125 | } 126 | 127 | public void run_main_loop() { 128 | if (is_initialized()) { 129 | if (message_loop_source_id > 0) { 130 | Source.remove(message_loop_source_id); 131 | message_loop_source_id = 0; 132 | } 133 | Cef.run_message_loop(); 134 | } 135 | } 136 | 137 | public void quit_main_loop() { 138 | if (is_initialized()) { 139 | Cef.quit_message_loop(); 140 | } 141 | } 142 | 143 | public void shutdown() { 144 | if (is_initialized()) { 145 | if (message_loop_source_id > 0) { 146 | Source.remove(message_loop_source_id); 147 | message_loop_source_id = 0; 148 | } 149 | Cef.shutdown(); 150 | } 151 | } 152 | 153 | } // namespace CefGtk 154 | -------------------------------------------------------------------------------- /valacefgtk/valacefgtk.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@PREFIX@ 2 | libdir=@LIBDIR@ 3 | ceflibdir=@CEFLIBDIR@ 4 | includedir=@INCLUDEDIR@ 5 | 6 | Name: ValaCEF GTK+ 7 | Description: Vala & GTK+ 3 bindings for CEF 8 | Version: @VERSION@ 9 | Requires.private: glib-2.0 gtk+-3.0 valacef 10 | Libs: -Wl,-rpath=${ceflibdir} -L${libdir} -L${ceflibdir} -lcef -l@LIBNAME@ 11 | Cflags: @INCLUDE_CEF_DIRS@ -I${includedir}/@APPNAME@-1.0 @PC_CFLAGS@ 12 | -------------------------------------------------------------------------------- /valacefgtk/x11.vala: -------------------------------------------------------------------------------- 1 | namespace CefGtk { 2 | 3 | public void set_x11_error_handlers() { 4 | X.set_io_error_handler((d) => 0); 5 | X.set_error_handler((display, event) => { 6 | critical( 7 | "X11 error: type=%d, serial=%lu, code=%d", 8 | event.type, event.serial, (int) event.error_code); 9 | return 0; 10 | }); 11 | 12 | } 13 | 14 | public Gdk.Visual get_default_visual() { 15 | // GTK+ > 3.15.1 uses an X11 visual optimized for GTK+'s OpenGL stuff 16 | // since revid dae447728d: https://github.com/GNOME/gtk/commit/dae447728d 17 | // However, it breaks CEF: https://github.com/cztomczak/cefcapi/issues/9 18 | // Let's use the default X11 visual instead of the GTK's blessed one. 19 | var screen = Gdk.Screen.get_default(); 20 | var visuals = screen.list_visuals(); 21 | var x11_screen = screen as Gdk.X11.Screen; 22 | assert(x11_screen != null); 23 | var default_xvisual = x11_screen.get_xscreen().default_visual_of_screen(); 24 | foreach (Gdk.Visual visual in visuals) { 25 | if (default_xvisual.visualid == ((Gdk.X11.Visual) visual).get_xvisual().visualid) { 26 | return visual; 27 | } 28 | } 29 | assert_not_reached(); 30 | } 31 | 32 | public void override_system_visual(Gdk.Visual visual) { 33 | cef_override_system_visual(((Gdk.X11.Visual) visual).get_xvisual().visualid); 34 | } 35 | 36 | public void override_rgba_visual(Gdk.Visual visual) { 37 | cef_override_rgba_visual(((Gdk.X11.Visual) visual).get_xvisual().visualid); 38 | } 39 | 40 | public Gdk.Visual? get_visual_by_id(X.VisualID visual_id) { 41 | var screen = Gdk.Screen.get_default(); 42 | var visuals = screen.list_visuals(); 43 | var x11_screen = screen as Gdk.X11.Screen; 44 | assert(x11_screen != null); 45 | foreach (Gdk.Visual visual in visuals) { 46 | if (((Gdk.X11.Visual) visual).get_xvisual().visualid == visual_id) { 47 | return visual; 48 | } 49 | } 50 | return null; 51 | } 52 | 53 | public Gdk.X11.Window? find_child_window(Gdk.X11.Window window) { 54 | X.Window root = X.None; 55 | X.Window parent = X.None; 56 | X.Window[] children = null; 57 | var display = window.get_display() as Gdk.X11.Display; 58 | display.get_xdisplay().query_tree(window.get_xid(), out root, out parent, out children); 59 | return (children != null && children.length > 0) ? wrap_xwindow(display, children[0]) : null; 60 | } 61 | 62 | public Gdk.X11.Window wrap_xwindow(Gdk.X11.Display display, X.Window xwindow) { 63 | var window = Gdk.X11.Window.lookup_for_display(display, xwindow); 64 | return window != null ? window : new Gdk.X11.Window.foreign_for_display(display, xwindow); 65 | } 66 | 67 | } // namespace CefX11 68 | 69 | 70 | private extern void cef_override_system_visual(X.VisualID id); 71 | private extern void cef_override_rgba_visual(X.VisualID id); 72 | -------------------------------------------------------------------------------- /waf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiliado/valacef/580706ec081299ff3eda8eecac88d8d336ec95ea/waf -------------------------------------------------------------------------------- /widevine/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "os": "linux", 3 | "arch": "x64", 4 | "x-cdm-module-versions": "4", 5 | "x-cdm-interface-versions": "8,9", 6 | "x-cdm-host-versions": "8,9", 7 | "x-cdm-codecs": "vp8,vp9.0,avc1", 8 | "version": "1.4.8.903" 9 | } 10 | -------------------------------------------------------------------------------- /wscript: -------------------------------------------------------------------------------- 1 | APPNAME = 'valacef' 2 | VERSION = '76.3809.0' 3 | MIN_VALA = "0.34.7" 4 | MIN_GLIB = "2.52.0" 5 | MIN_GTK = "3.22.0" 6 | 7 | top = '.' 8 | out = 'build' 9 | 10 | import os 11 | import waflib 12 | 13 | REVISION_SNAPSHOT = "snapshot" 14 | 15 | 16 | def get_git_version(): 17 | import os 18 | import subprocess 19 | if os.path.isdir(".git"): 20 | output = subprocess.check_output(["git", "describe", "--tags", "--long"]) 21 | return output.decode("utf-8").strip().split("-") 22 | return VERSION, "0", REVISION_SNAPSHOT 23 | 24 | def add_version_info(ctx): 25 | bare_version, n_commits, revision_id = get_git_version() 26 | if revision_id != REVISION_SNAPSHOT: 27 | revision_id = "{}-{}".format(n_commits, revision_id) 28 | versions = list(int(i) for i in bare_version.split(".")) 29 | versions[2] += int(n_commits) 30 | version = "{}.{}.{}".format(*versions) 31 | ctx.env.VERSION = version 32 | ctx.env.VERSIONS = versions 33 | ctx.env.REVISION_ID = revision_id 34 | 35 | def find_cef(ctx, lib_dirs=None, incude_dirs=None): 36 | ctx.start_msg("Checking for 'libcef.so' dir") 37 | lib_dirs = lib_dirs or ('./cef/lib', '/app/lib/cef', '/usr/local/lib/cef', '/usr/lib/cef') 38 | for cef_lib_dir in lib_dirs: 39 | if os.path.isfile(os.path.join(cef_lib_dir, 'libcef.so')): 40 | ctx.env.CEF_LIB_DIR = os.path.abspath(cef_lib_dir) 41 | ctx.end_msg(ctx.env.CEF_LIB_DIR) 42 | break 43 | else: 44 | ctx.end_msg(False, color='RED') 45 | ctx.fatal("Could not find 'libcef.so' in %s." % (lib_dirs,)) 46 | 47 | ctx.start_msg("Checking for 'libcef_dll_wrapper'") 48 | libcef_dll_wrappers = 'libcef_dll_wrapper.a', 'libcef_dll_wrapper' 49 | for wrapper_name in libcef_dll_wrappers: 50 | wrapper_path = os.path.join(ctx.env.CEF_LIB_DIR, wrapper_name) 51 | if os.path.isfile(wrapper_path): 52 | ctx.env.CEF_LIB_WRAPPER = wrapper_path 53 | ctx.end_msg(ctx.env.CEF_LIB_WRAPPER) 54 | break 55 | else: 56 | ctx.end_msg(False, color='RED') 57 | ctx.fatal("Could not find %s in '%s'." % (libcef_dll_wrappers, ctx.env.CEF_LIB_DIR)) 58 | 59 | ctx.start_msg("Checking for 'cef_version.h' dir") 60 | incude_dirs = incude_dirs or ('./cef/include', '/app/include/cef/include', '/usr/local/include/cef/include', '/usr/include/cef/include') 61 | for cef_include_dir in incude_dirs: 62 | if os.path.isfile(os.path.join(cef_include_dir, 'cef_version.h')): 63 | ctx.env.CEF_INCLUDE_DIR = os.path.abspath(cef_include_dir) 64 | ctx.end_msg(ctx.env.CEF_INCLUDE_DIR) 65 | break 66 | else: 67 | ctx.end_msg(False, color='RED') 68 | ctx.fatal("Could not find 'cef_version.h' in %s." % (incude_dirs,)) 69 | 70 | def vala_def(ctx, vala_definition): 71 | """Appends a Vala definition""" 72 | ctx.env.append_unique("VALA_DEFINES", vala_definition) 73 | 74 | def pkgconfig(ctx, pkg, uselib, version, mandatory=True, store=None, valadef=None, define=None): 75 | """Wrapper for ctx.check_cfg.""" 76 | result = True 77 | try: 78 | res = ctx.check_cfg(package=pkg, uselib_store=uselib, atleast_version=version, mandatory=True, args = '--cflags --libs') 79 | if valadef: 80 | vala_def(ctx, valadef) 81 | if define: 82 | for key, value in define.iteritems(): 83 | ctx.define(key, value) 84 | except waflib.Errors.ConfigurationError as e: 85 | result = False 86 | if mandatory: 87 | raise e 88 | finally: 89 | if store is not None: 90 | ctx.env[store] = result 91 | return res 92 | 93 | def find_python3(ctx, version=None): 94 | ctx.find_program('python3', var='PYTHON3') 95 | if version: 96 | versions = [int(s) for s in version.split('.')] 97 | ctx.start_msg("Checking for Python >= %s" % version) 98 | py_version = ctx.cmd_and_log( 99 | [ctx.env.PYTHON3[0], '--version'], output=waflib.Context.STDOUT, quiet=waflib.Context.BOTH) 100 | py_version = py_version.strip().split(' ')[1] 101 | py_versions = [int(s) for s in py_version.split('.')] 102 | if py_versions >= versions: 103 | ctx.end_msg(py_version, color='GREEN') 104 | else: 105 | ctx.end_msg(py_version, color='RED') 106 | if len(versions) == 1: 107 | ctx.fatal("Could not find Python >= %s" % version) 108 | else: 109 | del ctx.env.PYTHON3 110 | for i in reversed(range(versions[1], 8)): 111 | try: 112 | ctx.find_program('python3.%d' % i, var='PYTHON3') 113 | break 114 | except waflib.Errors.ConfigurationError: 115 | pass 116 | else: 117 | ctx.fatal("Could not find PythonXX >= %s" % version) 118 | ctx.start_msg("Checking for Python >= %s" % version) 119 | py_version = ctx.cmd_and_log( 120 | [ctx.env.PYTHON3[0], '--version'], output=waflib.Context.STDOUT, quiet=waflib.Context.BOTH) 121 | py_version = py_version.strip().split(' ')[1] 122 | py_versions = [int(s) for s in py_version.split('.')] 123 | if py_versions >= versions: 124 | ctx.end_msg(py_version, color='GREEN') 125 | else: 126 | ctx.end_msg(py_version, color='RED') 127 | ctx.fatal("Could not find Python >= %s" % version) 128 | 129 | 130 | def options(ctx): 131 | ctx.load('compiler_c vala') 132 | 133 | 134 | def configure(ctx): 135 | ctx.load('compiler_c vala') 136 | ctx.check_vala(min_version=tuple(int(i) for i in MIN_VALA.split("."))) 137 | pkgconfig(ctx, 'glib-2.0', 'GLIB', MIN_GLIB) 138 | pkgconfig(ctx, 'gio-2.0', 'GIO', MIN_GLIB) 139 | pkgconfig(ctx, 'gmodule-2.0', 'GMODULE', MIN_GLIB) 140 | pkgconfig(ctx, 'gio-unix-2.0', 'UNIXGIO', MIN_GLIB) 141 | pkgconfig(ctx, 'gtk+-3.0', 'GTK', MIN_GTK) 142 | pkgconfig(ctx, 'gdk-x11-3.0', 'GDKX11', MIN_GTK) 143 | pkgconfig(ctx, 'x11', 'X11', "0") 144 | find_python3(ctx, "3.6") 145 | 146 | CEF_PREFIX = os.environ.get("CEF_PREFIX") 147 | if CEF_PREFIX: 148 | find_cef(ctx, [CEF_PREFIX + '/lib/cef'], [CEF_PREFIX + '/include/cef/include']) 149 | else: 150 | find_cef(ctx) 151 | 152 | ctx.env.append_unique("VALAFLAGS", "-v") 153 | ctx.env.append_unique('CFLAGS', ['-w', '-Wno-incompatible-pointer-types']) 154 | ctx.env.append_unique("LINKFLAGS", ["-Wl,--no-undefined", "-Wl,--as-needed"]) 155 | ctx.env.append_unique('CFLAGS', '-O2') 156 | ctx.env.append_unique('CFLAGS', '-g3') 157 | 158 | ctx.env.VALACEF_LIBDIR = "%s/%s" % (ctx.env.LIBDIR, APPNAME) 159 | ctx.define("VALACEF_LIBDIR", ctx.env.VALACEF_LIBDIR) 160 | ctx.define("CEFIUM_LIBDIR", ctx.env.VALACEF_LIBDIR) 161 | ctx.define("VALACEF_WIDEVINE_MANIFEST_PATH", os.path.join(ctx.env.PREFIX, 'share/valacef/widevine/manifest.json')) 162 | 163 | add_version_info(ctx) 164 | 165 | 166 | def build(ctx): 167 | vapi_dirs = ["vapi", out] 168 | env_vapi_dir = os.environ.get("VAPIDIR") 169 | if env_vapi_dir: 170 | vapi_dirs.extend(os.path.relpath(path) for path in env_vapi_dir.split(":")) 171 | include_dirs = [".", ctx.env.CEF_INCLUDE_DIR, os.path.dirname(ctx.env.CEF_INCLUDE_DIR), out] 172 | cef_vala, valacef_api_vapi, valacef_api_h, valacef_api_c = [ctx.path.find_or_declare(i) for i in ( 173 | 'cef.vala', 'valacef_api.vapi', 'valacef_api.h', 'valacef_api.c')] 174 | ctx.define('VALACEF_VERSION_MAJOR', ctx.env.VERSIONS[0]) 175 | ctx.define('VALACEF_VERSION_MINOR', ctx.env.VERSIONS[1]) 176 | ctx.define('VALACEF_VERSION_MICRO', ctx.env.VERSIONS[2]) 177 | ctx( 178 | rule='${PYTHON3} ../genvalacef.py ${CEF_INCLUDE_DIR} .. .', 179 | source=[ctx.path.find_node('genvalacef.py')] + ctx.path.ant_glob('valacefgen/*.py'), 180 | target=[cef_vala, valacef_api_vapi, valacef_api_h, valacef_api_c] 181 | ) 182 | 183 | ctx.shlib( 184 | source = [ 185 | cef_vala, valacef_api_c, 186 | 'valacef/version.vala', 187 | 'valacef/constants.vala', 188 | 'valacef/Checks.vala', 189 | 'valacef/V8.vala', 190 | 'valacef/SimpleInterceptor.vala', 191 | 'valacef/SimpleAccessor.vala', 192 | ], 193 | target = 'valacef', 194 | packages = "valacef_api", 195 | defines = ['G_LOG_DOMAIN="Cef"', 'CEF_LIB_DIR="%s"' % ctx.env.CEF_LIB_DIR, '__VALACEF_H__'], 196 | vapi_dirs = vapi_dirs, 197 | includes = include_dirs, 198 | lib = ['cef'], 199 | libpath = [ctx.env.CEF_LIB_DIR], 200 | rpath = [ctx.env.CEF_LIB_DIR], 201 | cflags = ['-O2', ctx.env.CEF_LIB_WRAPPER], 202 | #vala_target_glib = TARGET_GLIB, 203 | #install_path = ctx.env.NUVOLA_LIBDIR, 204 | ) 205 | 206 | ctx.shlib( 207 | source = [ 208 | 'valacefgtk/init.vala', 209 | 'valacefgtk/InitFlags.vala', 210 | 'valacefgtk/x11.vala', 211 | 'valacefgtk/WeakRef.vala', 212 | 'valacefgtk/WebView.vala', 213 | 'valacefgtk/WebViewWidget.vala', 214 | 'valacefgtk/WebViewOffscreen.vala', 215 | 'valacefgtk/WebViewWindowed.vala', 216 | 'valacefgtk/WebContext.vala', 217 | 'valacefgtk/DownloadManager.vala', 218 | 'valacefgtk/BrowserProcess.vala', 219 | 'valacefgtk/AboutBlankPopupClient.vala', 220 | 'valacefgtk/Client.vala', 221 | 'valacefgtk/BrowserProcessHandler.vala', 222 | 'valacefgtk/ContextMenuHandler.vala', 223 | 'valacefgtk/FocusHandler.vala', 224 | 'valacefgtk/DisplayHandler.vala', 225 | 'valacefgtk/LoadHandler.vala', 226 | 'valacefgtk/LifeSpanHandler.vala', 227 | 'valacefgtk/DownloadHandler.vala', 228 | 'valacefgtk/KeyboardHandler.vala', 229 | 'valacefgtk/JsdialogHandler.vala', 230 | 'valacefgtk/UIEvents.vala', 231 | 'valacefgtk/WidevinePlugin.vala', 232 | 'valacefgtk/FlashPlugin.vala', 233 | 'valacefgtk/RenderHandler.vala', 234 | 'valacefgtk/RendererContext.vala', 235 | 'valacefgtk/RenderProcess.vala', 236 | 'valacefgtk/RenderProcessHandler.vala', 237 | 'valacefgtk/RequestHandler.vala', 238 | 'valacefgtk/AboutBlankPopupRequestHandler.vala', 239 | 'valacefgtk/RenderSideEventLoop.vala', 240 | 'valacefgtk/Utils.vala', 241 | 'valacefgtk/MsgId.vala', 242 | 'valacefgtk/Task.vala', 243 | 'valacefgtk/Function.vala', 244 | 'valacefgtk/Proxy.vala', 245 | 'valacefgtk/NavigationRequest.vala', 246 | ], 247 | target = 'valacefgtk', 248 | packages = "valacef valacef_api gtk+-3.0 gdk-x11-3.0 x11 gmodule-2.0", 249 | uselib = "GTK GDKX11 X11 GMODULE", 250 | defines = ['G_LOG_DOMAIN="CefGtk"'], 251 | vapi_dirs = vapi_dirs, 252 | includes = include_dirs, 253 | use = ['valacef'], 254 | lib = ['cef', 'm'], 255 | libpath = [ctx.env.CEF_LIB_DIR], 256 | rpath = [ctx.env.CEF_LIB_DIR], 257 | cflags = ['-O2'], 258 | #vala_target_glib = TARGET_GLIB, 259 | #install_path = ctx.env.NUVOLA_LIBDIR, 260 | ) 261 | 262 | ctx.program( 263 | source = ['cefsubprocess/Subprocess.vala'], 264 | target = 'ValacefSubprocess', 265 | packages = "gtk+-3.0 gdk-x11-3.0 x11", 266 | uselib = "GTK GDKX11 X11", 267 | use = ['valacef', 'valacefgtk'], 268 | defines = ['G_LOG_DOMAIN="CefSub"'], 269 | vapi_dirs = vapi_dirs, 270 | includes = include_dirs, 271 | lib = ['cef'], 272 | libpath = [ctx.env.CEF_LIB_DIR], 273 | rpath = [ctx.env.CEF_LIB_DIR], 274 | cflags = ['-O2'], 275 | #vala_target_glib = TARGET_GLIB, 276 | install_path = ctx.env.VALACEF_LIBDIR, 277 | ) 278 | 279 | ctx.program( 280 | source = [ 281 | 'cefium/Cefium.vala', 282 | 'cefium/Application.vala', 283 | 'cefium/BrowserWindow.vala', 284 | 'cefium/URLBar.vala', 285 | ], 286 | target = 'Cefium', 287 | use = ['valacef', 'valacefgtk'], 288 | packages = "gtk+-3.0 gdk-x11-3.0 x11", 289 | uselib = "GTK GDKX11 X11", 290 | defines = ['G_LOG_DOMAIN="Cefium"'], 291 | vapi_dirs = vapi_dirs, 292 | includes = include_dirs, 293 | lib = ['cef'], 294 | libpath = [ctx.env.CEF_LIB_DIR], 295 | rpath = [ctx.env.CEF_LIB_DIR], 296 | cflags = ['-O2'], 297 | #vala_target_glib = TARGET_GLIB, 298 | #install_path = ctx.env.NUVOLA_LIBDIR, 299 | ) 300 | 301 | ctx.shlib( 302 | source = [ 303 | 'cefium/CefiumRendererExtension.vala', 304 | ], 305 | target = 'cefiumrendererextension', 306 | use = ['valacef', 'valacefgtk'], 307 | packages = "gtk+-3.0 gdk-x11-3.0 x11 gmodule-2.0", 308 | uselib = "GTK GDKX11 X11 GMODULE", 309 | defines = ['G_LOG_DOMAIN="Cefium"'], 310 | vapi_dirs = vapi_dirs, 311 | includes = include_dirs, 312 | lib = ['cef'], 313 | libpath = [ctx.env.CEF_LIB_DIR], 314 | rpath = [ctx.env.CEF_LIB_DIR], 315 | cflags = ['-O2'], 316 | #vala_target_glib = TARGET_GLIB, 317 | install_path = ctx.env.VALACEF_LIBDIR, 318 | ) 319 | 320 | ctx(features = 'subst', 321 | source='launch.sh.in', 322 | target='launch.sh', 323 | CEF_LIB_DIR=ctx.env.CEF_LIB_DIR, 324 | OUT=out 325 | ) 326 | 327 | ctx(features = 'subst', 328 | source='valacef/valacef.pc.in', 329 | target='valacef.pc', 330 | install_path='${LIBDIR}/pkgconfig', 331 | VERSION=ctx.env.VERSION, 332 | PREFIX=ctx.env.PREFIX, 333 | INCLUDEDIR = ctx.env.INCLUDEDIR, 334 | LIBDIR = ctx.env.LIBDIR, 335 | APPNAME=APPNAME, 336 | LIBNAME='valacef', 337 | CEFLIBDIR=ctx.env.CEF_LIB_DIR, 338 | INCLUDE_CEF_DIRS="-I%s -I%s" % (ctx.env.CEF_INCLUDE_DIR, os.path.dirname(ctx.env.CEF_INCLUDE_DIR)), 339 | ) 340 | 341 | ctx(features = 'subst', 342 | source='valacefgtk/valacefgtk.pc.in', 343 | target='valacefgtk.pc', 344 | install_path='${LIBDIR}/pkgconfig', 345 | VERSION=ctx.env.VERSION, 346 | PREFIX=ctx.env.PREFIX, 347 | INCLUDEDIR = ctx.env.INCLUDEDIR, 348 | LIBDIR = ctx.env.LIBDIR, 349 | APPNAME=APPNAME, 350 | LIBNAME='valacefgtk', 351 | CEFLIBDIR=ctx.env.CEF_LIB_DIR, 352 | INCLUDE_CEF_DIRS="-I%s -I%s" % (ctx.env.CEF_INCLUDE_DIR, os.path.dirname(ctx.env.CEF_INCLUDE_DIR)), 353 | ) 354 | 355 | ctx.install_files('${PREFIX}/share/vala/vapi', ['valacef_api.vapi']) 356 | ctx.install_files('${PREFIX}/include/valacef-1.0', ['valacef_api.h']) 357 | ctx.install_files('${PREFIX}/share/valacef/widevine', ['widevine/manifest.json']) 358 | 359 | --------------------------------------------------------------------------------