Conversation
New "Web Browser" panel type built on Qt WebEngine, off by default. With BUILD_WEBENGINE=OFF nothing links WebEngine, the panel is not registered and its preferences are not installed. With it ON the launcher enables shared OpenGL contexts and initialises WebEngine before the QApplication, and the panel appears in the panel-type list. The panel has back, forward, reload/stop, a URL field and Home. The URL field trims its text, since a pasted URL with a leading or trailing space failed to load. The home page is a preference, defaulting to about:blank. The page the panel is on is stored with the layout, so a panel comes back to it on the next run rather than to the home page. The page's JavaScript console is forwarded to the xSTUDIO log with a [web] prefix. QML gates the registration on a webEngineAvailable context property, since it cannot see the compile-time option. Rendering. On the machine this was developed on (Linux, NVIDIA, Qt 6.10.2, GNOME on Wayland) the panel is black with default settings, and Qt's qt.webenginecontext.debug logging reports "GBM is not supported ... Fallback to Vulkan rendering". These controls exist for that: - "Render Pages on CPU" preference and the --web-disable-gpu flag: both append --disable-gpu to QTWEBENGINE_CHROMIUM_FLAGS before WebEngine initialises, keeping any flags already set. Meant for machines where the GPU path gives a black panel; pages render on the CPU. - QTWEBENGINE_FORCE_USE_GBM=1: Qt's own environment variable to use GBM buffer sharing anyway. Meant to get GPU rendering on NVIDIA. It is documented in the user guide, not set by xSTUDIO. - QTWEBENGINE_CHROMIUM_FLAGS: passes any other Chromium switch. These have only been tried on that one machine: CPU rendering showed pages; FORCE_USE_GBM showed pages on the Wayland platform and crashed with QT_QPA_PLATFORM=xcb under Xwayland. Other GPUs, drivers, Qt versions and a native X11 session have not been tested. Signed-off-by: Ben de Luca <bdeluca@gmail.com>
Pages loaded in the web browser panel can now reach a native object, xstudioWebBridge, via QWebChannel. It is a stub with a single ping() that returns "pong", enough to prove the channel end to end; the real API (load media, build timelines) comes later. The panel's home page default changes from about:blank to a bundled test page that does the QWebChannel handshake, calls ping() and shows the reply. WebBridgeUI is always compiled into the studio qml component because that component globs its sources; it has no WebEngine dependency and is only registered as a context property when BUILD_WEBENGINE is on. It is registered on the channel explicitly by name because a context property cannot carry the WebChannel.id attached property. The panel injects Qt's qwebchannel.js into every page as a user script, since a page served over http cannot load qrc: resources; a web tool needs no library of its own. Signed-off-by: Ben de Luca <bdeluca@gmail.com>
A page loaded in the panel is drawn by Chromium, so it gets a browser's colours and controls unless told otherwise and reads as a web page pasted into the application. Linking xstudio.css first gives it xSTUDIO's palette, scrollbars and form controls; the page then writes only its own layout. The values are read off XsStyleSheet.qml at the shipped preference defaults, and each custom property is named after the XsStyleSheet property it carries, so refreshing the file is a re-read of that one. It is self-contained so a web server can serve it next to its own pages. The bundled channel test page now links it instead of carrying its own colours, so the panel's default page shows the file working. Signed-off-by: Ben de Luca <bdeluca@gmail.com>
WebBridgeUI grows from a ping() stub into the JavaScript API a page in the web browser panel uses to drive xSTUDIO. This sets how the API works and adds enough calls to take a file to a timeline on screen. How a call works: QWebChannel calls cannot block, so every method returns a request id and delivers its outcome on a result(id, res) signal emitted from the object's own thread. res always has ok and, on failure, error; calls that create something add uuid. Calls run on one worker thread, in call order. ping() and version() answer directly. Handles: objects are named by UUID strings. The bridge keeps a map per kind (playlist, timeline, track, media) of what it has handed out and rejects any other UUID. The maps are behind a mutex, since addMedia records its media from another thread. addMedia is the one call that does not wait on the worker thread, since a file can take a while to open: it goes on a queue, the mailbox of a small actor, and is answered on result() when the playlist replies, so a slow file does not hold up later calls. It is sent as add_media(name, uri), the way files given on the command line are added, so the playlist lists the item straight away, in call order, and replies once the file has been read. The calls: it does no more than the Python API does, one bridge call per Python call: findPlaylist, createPlaylist, createTimeline, insertVideoTrack, insertAudioTrack, addMedia, insertClip (which also reports the clip's length) and showTimeline. Two calls hand the screen back to the viewer afterwards: selectLayout switches the main window layout and selectPanel brings the first tab of a panel type to the front; both are relayed to QML through signals, since layouts and tabs live there. version() reports the release and a bridge API number so a web tool can ask for a newer xSTUDIO. Workflow logic stays out of C++ on purpose: how a payload becomes tracks and clips is the web page's job, since one web server is easier to update than every installed xSTUDIO, and this API is public while any given page is not. The bundled test page only proves the channel, ping() and version(); no sample payload, media or recipe, those belong to the tools built on the API. Signed-off-by: Ben de Luca <bdeluca@gmail.com>
Bridge API version 2. Pages could take a file to a timeline but not finish building one, see what was in the session, drive playback, change what they had built, or tell the user anything. Every call here works the way the first set does: a request id back, the outcome on result(id, res), one Python API call each. Reading back: listPlaylists, listContainers, listMedia, findTimeline, playheadState and selectedMedia. These hand the page handles to things it did not create, so a page that can call them can reach the whole session; the bridge still rejects any UUID it did not hand out itself. findPlaylist already gave out such handles. listMedia and selectedMedia describe each item the same way, including the image source's URI as xSTUDIO holds it, so a page can tell whether a file is already in a playlist before adding it again; the URI is empty for an item still being probed. Building: setMediaRate, to be set before adding media, and insertGap; a builder sizes gaps from the clip length insertClip reports. Playback on a timeline's playhead: play, setFrame, setLoopRange, setLoopMode and setCompareMode. Editing: removeClips, moveClips, splitClip, clearTimeline, and setItemEnabled / setItemName / setItemFlag on any track, clip or gap the bridge created. Media and playlists: setMediaFlag, removeMedia, clearPlaylist, removePlaylist, setSelection. Contact sheets, asked for by a review page that mirrors a desktop script building one next to the timeline: createContactSheet and addMediaToContactSheet, sharing the media the playlist already holds. Session: setViewedContainer for any playlist, timeline or contact sheet handle, save and saveAs. Telling the user: notify (info, warn, processing) and addNote, which creates a bookmark on a media item with all its fields in one call. Results ride on the existing result(id, map) signal; list results are arrays of maps, which QWebChannel serialises as JSON. Three lookups were added once for all of these: timeline to playhead, playlist to selection actor, and a map of every track, clip and gap the bridge made so one call can address any of them. Tested on Linux from a review page against a production media server. Signed-off-by: Ben de Luca <bdeluca@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the Web Browser panel and the bridge API that lets a page loaded in it drive xSTUDIO. Experimental and not fully tested; the API may change. Off unless built with
BUILD_WEBENGINE=ON; with it off the panel and bridge are never created. Built and used on Ubuntu 26.04 and Windows, not yet built on macOS or Rocky 9.1. Web browser panel (
BUILD_WEBENGINE, default OFF)XsWebBrowserPanel.qml: back, forward, reload/stop, URL field (trims pasted text), Home. Remembers the page it was on across runs, stored with the layout. Page console goes to the xSTUDIO log as[web].--web-disable-gpuflag, same effect as the preference. Needed on Linux/NVIDIA where WebEngine's Vulkan fallback leaves the panel black.2. Bridge stub
WebBridgeUIregistered asxstudioWebBridgeover QWebChannel, withping().webchannel_test.htmlas the default home page.3.
xstudio.cssXsStyleSheet, for pages that should look like part of the app.4. Bridge API v1: how a call works, and taking a file to a timeline
result(id, res). Calls run in call order.findPlaylist,createPlaylist,createTimeline,insertVideoTrack,insertAudioTrack,addMedia,insertClip,showTimeline,selectLayout,selectPanel,version.5. Bridge API v2
setMediaRate,insertGap.listPlaylists,listContainers,listMedia,findTimeline,playheadState,selectedMedia.play,setFrame,setLoopRange,setLoopMode,setCompareMode.removeClips,moveClips,splitClip,clearTimeline,setItemEnabled,setItemName,setItemFlag.setMediaFlag,removeMedia,clearPlaylist,removePlaylist,setSelection.createContactSheet,addMediaToContactSheet.setViewedContainer,save,saveAs,notify,addNote.Tested