-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add RFC: Switch to Advanced Docking System
- Loading branch information
Showing
4 changed files
with
385 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,385 @@ | ||
# Summary | ||
|
||
- Switch main dock system to [ADS][1] | ||
- Make ADS dock state per profile | ||
- Allow the user to switch between pre-made layouts | ||
- Plugins could register their own | ||
- Users could save their own | ||
- Dock added by plugins with the old method are added as "*Legacy dock*" | ||
- Frontend API methods and events about ADS docks | ||
|
||
Note: The "central widget" design is kept. | ||
|
||
# Motivation | ||
|
||
Provide a better dock system to end-users. | ||
|
||
# Design | ||
**DISCLAIMER**: The "central widget" design is kept, switching to a non-"central widget" one is not part of this RFC. | ||
|
||
## Main window dock separation | ||
To make OBS Studio compatible with ADS, Controls, Transitions, Mixer, Sources, Scenes docks need to be separated from the main window. | ||
|
||
And the central widget of main window should also be separated as well to become the central dock. | ||
|
||
So the docks will be separated as widget class with their own UI class. | ||
|
||
Then those widget are inserted in OBSDock (QDockWidget) and the central widget and put as main window central widget. | ||
|
||
And then we switch to ADS, all those widget will become docks and added the ADS dock manager. | ||
|
||
The Main window heavily rely on some UI element from those docks, to resolve that when really required OBSBasic will be set as a friend class of the widget. | ||
|
||
Each widget class will be put as a friend class in OBSBasic to allow access to private slot and avoid moving them as public. | ||
|
||
### Controls widget | ||
*Future ADS Controls dock widget* | ||
|
||
Some hotkeys and pause functions rely on UI buttons, so OBS Basic will be added as friend class to allow access to those to OBSBasic. | ||
|
||
This class will require to have OBSBasic as a friend class because: | ||
- The streaming hotkey pair rely on the stream button enabled/disabled state. | ||
- The recording hotkey pair rely on the record button checked state. | ||
- The pause hotkey pair rely on the pause button pointer and checked state. | ||
- Pause and unpause recording function rely on the pause button pointer. | ||
|
||
|
||
*Note: In my [WIP implementation][2], many signals are added to OBSBasic to interract with controls dock UI through slots. Some of them happen to be used by other docks.* | ||
|
||
### Transistions widget | ||
*Future ADS Transitions dock widget* | ||
|
||
The transition duration will become an attribute of OBSBasic, and signal and slots will be setup to synchromise it with the dock spinbox. | ||
|
||
This class will require to have OBSBasic as a friend class because the transition combobox store the transitions themselves. | ||
|
||
### Mixer widget | ||
*Future ADS Mixer dock widget* | ||
|
||
Easily separable, no need to set OBSBasic as a friend class of this widget. | ||
|
||
### Sources widget | ||
*Future ADS Sources dock widget* | ||
|
||
OBSBasic heavily rely on the SourceTree from the widget, so for now OBSBasic will access it by being a friend class of the widget. | ||
|
||
### Scenes widget | ||
*Future ADS Scenes dock widget* | ||
|
||
OBSBasic heavily rely on the SceneTree from the widget, so for now OBSBasic will access it by being a friend class of the widget. | ||
|
||
### Central widget | ||
*Future ADS Central dock widget* | ||
|
||
Some context bar, preview/program and nudge related code is moved to the central widget class. | ||
|
||
This class will have OBSBasicPreview as a friend class. | ||
|
||
This class will be a friend class of OBSBasic also to have access to some gs_vertbuffer_t type attributes. | ||
|
||
## ADS | ||
The Advanced Docking System, require to add a Dock Manager in the main window and then add the central widget and then add other docks. | ||
|
||
Some work on themes CSS will be required. | ||
|
||
### About obs-deps | ||
|
||
obs-deps already build Qt for macOS, so adding a ADS script for the Qt tarball is not a problem. | ||
|
||
But in the case of Windows, there is some issues: | ||
- ADS does not use debug Qt DLLs when building OBS with `Debug` config. So it may require to copy non-debug one just for ADS. | ||
- It needs to build Qt or repackage it to include ADS. | ||
|
||
### About ADS translations | ||
OBS does not use the Qt translations but a customised one which use source text without spaces only. | ||
|
||
So in the `OBSTranslator::translate()` function, removing spaces from source text will to translate ADS texts. | ||
|
||
In `OBSTranslator::translate()` function: | ||
```c++ | ||
if (QT_UTF8(sourceText).contains(" ")) { | ||
QString text(QT_UTF8(sourceText).remove(" ")); | ||
sourceText = strdup(QT_TO_UTF8(text)); | ||
} | ||
``` | ||
In `en-US.ini` file: | ||
```ini | ||
# ADS | ||
CloseOthers="Close Others" | ||
CloseTab="Close Tab" | ||
CloseActiveTab="Close Active Tab" | ||
ShowView="Show View" | ||
DetachGroup="Detach Group" | ||
CloseGroup="Close Group" | ||
CloseOtherGroups="Close Other Groups" | ||
ListAllTabs="List All Tabs" | ||
``` | ||
|
||
### Floating docks titlebar on X11 | ||
On X11, ADS provide two type of titlebar for floating docks: | ||
|
||
- Native | ||
|
||
[![Native titlebar under GNOME](./0047-switch-to-advanced-docking-system/linux_native_floating_dock_titlebar.png)]() | ||
|
||
- QWidget based (WIP CSS) | ||
|
||
[![QWidget titlebar](./0047-switch-to-advanced-docking-system/linux_qwidget_floating_dock_titlebar.png)]() | ||
|
||
The QWidget one is used by default when using KWin based Desktop Environement like Plasma. And this titlebar requires some CSS in the themes to match it. | ||
|
||
So the QWidget based titlebar usage will be enforced thanks to a flag for the Dock Manager to "force" theme makers to theme this bar, and not just ignore it because it's only "under Plasma X11". | ||
|
||
### Dock state | ||
*The per profile dock state feature is not taken into account to describe those changes.* | ||
|
||
In the global config (`global.ini`). | ||
- `"dockState"` is kept for for backward compatiblity and no longer overwitten. It will be used if the following state is not present. | ||
- `"windowState"` is the state of the main window, since it does not store only the state of legacy docks. | ||
- `"advDockState"` is the state of the dock manager which contain only the states of any ADS dock. | ||
|
||
Service integrations only save `"advDockProfile"` | ||
|
||
ADS dock state is compressed by default but behind the scene it's XML. | ||
|
||
### OBSAdvDock | ||
OBSAdvDock is a class which inherit `ads::CDockWidget` class. | ||
|
||
This class has a constructor which require a QWidget and setup some things arround the widget and set some connections. | ||
|
||
It adds a warning message when closing a dock from a close dock button. | ||
|
||
It allows to reset a dock position after a UI reset or a layout change with a possibility to reset the size if set beforehand. | ||
|
||
### Custom Browser docks and BrowserAdvDock | ||
The custom browser docks feature is modified to use BrowserAdvDock which inherit OBSAdvDock. | ||
|
||
Those docks are stored in the dock manager and their names is stored in a QStringList for browser docks to be able to get the dock from the manager to modify it like changing the URL. | ||
|
||
Each of those browser dock is named `extraBrowser_$UUID` where `$UUID` is replaced by the dock UUID to have a really unique name. | ||
|
||
### Service integration docks | ||
|
||
Like custom browser docks, those integration are modified to use BrowserAdvDock. But their names is stored in the QStringList for plugins extra docks. | ||
|
||
Those docks are named `obs-$SERVICE_$DOCK_NAME` where `$SERVICE` is the service name in lowercase and `$DOCK_NAME` the name of the dock. | ||
|
||
`"dockState"` will be imported from the integration config if `"windowState"` is not present. | ||
|
||
### Reset UI action | ||
1. Legacy dock are hidden | ||
2. The default state written in XML is applied | ||
3. Each not shown OBSAdvDock/BrowserAdvDock dock have its position and size reseted. | ||
|
||
## Legacy dock | ||
The frontend API method `obs_frontend_add_dock()` is put in deprecation. | ||
|
||
And dock added through this method are added to a sub-menu named `Legacy dock` of the Dock menu. | ||
|
||
[![Legacy dock menu](./0047-switch-to-advanced-docking-system/legacy_dock.png)]() | ||
|
||
When openning a legacy dock, a message will appear explaining that those docks will not meld wery well with "new" docks. | ||
|
||
The state of those are saved through `"windowState"` global config. | ||
|
||
## Per profile dock state | ||
Move the `"advDockState"` from global config to the profile and integration no longer store their own state. `"windowState"` is kept global. | ||
|
||
If a release happen between the switch to ADS and this feature, import the one from the integration service if the profile has one set up. | ||
|
||
## Layouts management | ||
Add the feature, to switch between registered/saved dock layouts: | ||
- Though a sub-menu in the dock menu | ||
- Through a hotkey | ||
- Through the frontend API | ||
|
||
OBS Studio could provide layouts, the default count as one. | ||
|
||
Plugins could also register their own XML layouts through the frontend API. | ||
|
||
Users could be able to save their own layouts. Those layouts will have their name prefixed with`user_` to avoid name conflicts. | ||
|
||
Note: ADS perspective feature is not directly used because it relies heavily on QSettings. | ||
|
||
## Frontend API | ||
Like said earlier, the method `obs_frontend_add_dock()` is put in deprecation. | ||
|
||
All add/remove methods related to ADS requiring a name will require the plugin module to be able to prefix the given name with the module name to avoid conflicts. | ||
|
||
### Add a dock | ||
```c++ | ||
/* takes QWidget */ | ||
#define obs_frontend_add_adv_dock(title, unique_name, dock) \ | ||
obs_frontend_add_module_adv_dock(obs_current_module(), title, \ | ||
unique_name, widget) | ||
EXPORT void obs_frontend_add_module_adv_dock(obs_module_t *module, | ||
const char *title, | ||
const char *unique_name, | ||
void *widget); | ||
``` | ||
This allow to add a OBSAdvDock with the given QWidget. Those docks are stored in the Dock Manager and their names is stored in the QStringList for plugins extra docks. | ||
Default height and width could be set through `"defaultHeight"` `"defaultHeight"` with the [`setProperty()`][7] method. | ||
Minimum sizes used by the dock are based on the widget ones. | ||
### Remove a dock | ||
```c++ | ||
#define obs_frontend_remove_adv_dock(unique_name) \ | ||
obs_frontend_remove_module_adv_dock(obs_current_module(), unique_name) | ||
EXPORT void obs_frontend_remove_module_adv_dock(obs_module_t *module, | ||
const char *unique_name); | ||
``` | ||
|
||
This allow the plugin to remove a dock added earlier. | ||
|
||
### Add a browser dock | ||
```c++ | ||
#define obs_frontend_add_adv_browser_dock(dock_params, browser_params) \ | ||
obs_frontend_add_module_adv_browser_dock(obs_current_module(), \ | ||
dock_params, browser_params) | ||
EXPORT bool obs_frontend_add_module_adv_browser_dock(obs_module_t *module, | ||
struct obs_frontend_browser_dock_params *dock_params, | ||
struct obs_frontend_browser_params *browser_params) | ||
``` | ||
This allow the plugin to add a dock with a QCefWidget as widget. Return false if the browser dock could not be created. | ||
The QCefWidget will get parameters from this structure: | ||
```c++ | ||
struct obs_frontend_browser_params { | ||
const char *url; | ||
bool enable_cookie; | ||
struct dstr startup_script; | ||
DARRAY(char *) force_popup_urls; | ||
}; | ||
``` | ||
|
||
- `bool enable_cookie`: if true `panel_cookie` will be used. The plugin maker will have to remove the dock the between profile change because the cookie manager is per profile. | ||
- `struct dstr startup_script` allow to set a startup script for the QCefWidget. | ||
- `DARRAY(char *) force_popup_urls` allow to set a list of url forced to popup. | ||
|
||
And the dock itself will get parameters from this structure: | ||
|
||
```c++ | ||
struct obs_frontend_browser_dock_params { | ||
const char *unique_name; | ||
const char *title; | ||
int default_width; | ||
int default_height; | ||
int min_width; | ||
int min_height; | ||
}; | ||
``` | ||
`obs_frontend_remove_adv_dock()` can be used to remove the browser dock. | ||
### Add a dock layouts | ||
```c++ | ||
#define obs_frontend_add_adv_dock_layout(title, unique_name, xml_layout) \ | ||
obs_frontend_add_module_adv_dock_layout(obs_current_module(), \ | ||
title, unique_name, xml_layout) | ||
EXPORT void obs_frontend_add_module_adv_dock_layout(obs_module_t *module, | ||
const char *title, | ||
const char *unique_name, | ||
const char *xml_layout); | ||
``` | ||
|
||
This allow the plugin to add a dock layouts in XML to the UI. ADS allow to test a layout (state/perspective) without applying it, so the layout will be tested before registering it. | ||
|
||
### Get a list of docks layouts | ||
```c++ | ||
EXPORT char **obs_frontend_get_adv_dock_layouts(void); | ||
``` | ||
This allow the plugin to get a list of registered dock layouts from the UI. | ||
### Set a registered dock layout | ||
```c++ | ||
EXPORT void obs_frontend_set_adv_dock_layouts(const char *layout_name); | ||
``` | ||
|
||
This allow the plugin to set a registered dock layouts to the UI, the asked name should come directly from the get list method. | ||
|
||
### Remove a dock layouts | ||
```c++ | ||
#define obs_frontend_remove_adv_dock_layout(unique_name) \ | ||
obs_frontend_remove_module_adv_dock_layout(obs_current_module(), \ | ||
unique_name) | ||
EXPORT void obs_frontend_remove_module_adv_dock_layout(obs_module_t *module, | ||
const char *unique_name); | ||
``` | ||
This allow the plugin to remove a dock layouts from the UI. | ||
### Add a entirely custom dock | ||
```c++ | ||
/* takes ads::CDockWidget */ | ||
#define obs_frontend_add_custom_adv_dock(unique_name, dock) \ | ||
obs_frontend_add_module_custom_adv_dock(obs_current_module(), \ | ||
unique_name, dock) | ||
EXPORT void obs_frontend_add_module_custom_adv_dock(obs_module_t *module, | ||
const char *unique_name, | ||
void *dock); | ||
``` | ||
|
||
Some plugin like [Sources Dock][6], do not add their docks to the Dock menu. | ||
|
||
So this method allow to do this but requires the plugin to be link against ADS library. | ||
|
||
And the dock will not have OBSAdvDock features. | ||
|
||
`obs_frontend_remove_adv_dock()` can be used to remove the reference stored in the Dock Manager. Because their names is stored in the QStringList for plugins custom extra docks. | ||
|
||
### Get the XML behind a registered dock layout | ||
*Method meant to allow a Dock Layout editor tool to exist* | ||
|
||
```c++ | ||
EXPORT char *obs_frontend_get_current_profile(const char *layout_name); | ||
``` | ||
This allow the plugin to get a registered dock layouts XML, the asked name should come directly from the get list method. | ||
### Get the XML of the actual dock state | ||
*Method meant to allow a Dock Layout editor tool to exist* | ||
```c++ | ||
EXPORT char *obs_frontend_get_current_profile(const char *layout_name); | ||
``` | ||
|
||
This allow the plugin to get the dock states XML of the UI. | ||
|
||
### Events addition | ||
- An event before the startup restore dock state and `OBS_FRONTEND_EVENT_FINISHED_LOADING` to allow plugins to load their docks before the restore or redo a restore if the number of extra docks has changed. This event could possibly be emitted when profile is changed before restoring profile dock state and `OBS_FRONTEND_EVENT_PROFILE_CHANGED`. | ||
|
||
- An event when the a dock layout is applied (reset or not) to allow plugins to reset the positions of their customs docks, if they want to. | ||
|
||
## About making dock states future proof | ||
By default generated state are version 0. If one day we make a breaking change like remove the notion of central widget and so change the version. | ||
|
||
We could take the saved `"advDockState"` and uncompress to edit the XML, to make it compatible with the change. | ||
|
||
# Drawbacks | ||
We can't convert old `"dockState"` to the new dock system. | ||
|
||
# Additional Information | ||
We may require to make some changes to allow ADS to be built on FreeBSD and submit the required changes to upstream. **I'm just waiting for a build guide for OBS Studio on FreeBSD to make it.** | ||
|
||
About Wayland support, Qt and ADS docking system have very bad support because of Qt Wayland. The Wayland backend is apparently third-class on Qt's priorities. | ||
|
||
My WIP branches: | ||
- [Main window dock separation][2] | ||
- [Switch to ADS][3] | ||
- [Frontend API to add ADS dock][4] | ||
- [Frontend API to add custom ADS dock][5] | ||
|
||
[1]: https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System | ||
[2]: https://github.com/tytan652/obs-studio/tree/main_win_separation | ||
[3]: https://github.com/tytan652/obs-studio/tree/advanced_docking | ||
[4]: https://github.com/tytan652/obs-studio/tree/ads_frontend_api | ||
[5]: https://github.com/tytan652/obs-studio/tree/add_custom_dock | ||
[6]: https://obsproject.com/forum/resources/source-dock.1317/ | ||
[7]: https://doc.qt.io/qt-5/qobject.html#setProperty |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+9.24 KB
.../0047-switch-to-advanced-docking-system/linux_native_floating_dock_titlebar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+9.02 KB
...0047-switch-to-advanced-docking-system/linux_qwidget_floating_dock_titlebar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.