diff --git a/Cargo.lock b/Cargo.lock index 17bdbe93..defd9291 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "accesskit" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5351dcebb14b579ccab05f288596b2ae097005be7ee50a7c3d4ca9d0d5a66f6a" -dependencies = [ - "uuid", -] - [[package]] name = "addr2line" version = "0.25.1" @@ -196,20 +187,6 @@ name = "bytemuck" version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] [[package]] name = "byteorder" @@ -307,15 +284,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" -[[package]] -name = "color" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18ef4657441fb193b65f34dc39b3781f0dfec23d3bd94d0eeb4e88cde421edb" -dependencies = [ - "bytemuck", -] - [[package]] name = "colorchoice" version = "1.0.5" @@ -397,77 +365,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "ecolor" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "137c0ce4ce4152ff7e223a7ce22ee1057cdff61fce0a45c32459c3ccec64868d" -dependencies = [ - "emath", -] - -[[package]] -name = "egui" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34aaf627da598dfadd64b0fee6101d22e9c451d1e5348157312720b7f459f0f" -dependencies = [ - "accesskit", - "ahash", - "bitflags", - "emath", - "epaint", - "log", - "nohash-hasher", - "profiling", - "smallvec", - "unicode-segmentation", -] - -[[package]] -name = "egui_tiles" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08e570b77f6cce3292eba4aee9b9c08cf11dfc68430f4dc9613d939628498647" -dependencies = [ - "ahash", - "egui", - "itertools", - "log", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "emath" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a05cd8bdf3b598488c627ca97c7fe8909448ffa26278dd3c7e535cdb554d721" - -[[package]] -name = "epaint" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f3017dd67f147a697ee0c8484fb568fd9553e2a0c114be5020dbbc11962841" -dependencies = [ - "ahash", - "ecolor", - "emath", - "font-types", - "log", - "nohash-hasher", - "parking_lot", - "profiling", - "self_cell", - "skrifa", - "smallvec", - "vello_cpu", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -490,15 +387,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31ae425815400e5ed474178a7a22e275a9687086a12ca63ec793ff292d8fdae8" -[[package]] -name = "euclid" -version = "0.22.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" -dependencies = [ - "num-traits", -] - [[package]] name = "fastrand" version = "2.3.0" @@ -514,15 +402,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "fearless_simd" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb2907d1f08b2b316b9223ced5b0e89d87028ba8deae9764741dba8ff7f3903" -dependencies = [ - "bytemuck", -] - [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -545,21 +424,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - -[[package]] -name = "font-types" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73829a7b5c91198af28a99159b7ae4afbb252fb906159ff7f189f3a2ceaa3df2" -dependencies = [ - "bytemuck", -] - [[package]] name = "futures-core" version = "0.3.32" @@ -672,7 +536,7 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "foldhash 0.1.5", + "foldhash", ] [[package]] @@ -680,9 +544,6 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -dependencies = [ - "foldhash 0.2.0", -] [[package]] name = "heck" @@ -756,15 +617,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1697e6b71679da96d5c41bb9035116141baadbf59a60625fd66cb3c9584e7b0" -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.17" @@ -805,8 +657,6 @@ dependencies = [ "clap", "clap_complete", "dirs", - "egui", - "egui_tiles", "futures-util", "gpu-alloc", "gpu-alloc-types", @@ -925,17 +775,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "kurbo" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7564e90fe3c0d5771e1f0bc95322b21baaeaa0d9213fa6a0b61c99f8b17b3bfb" -dependencies = [ - "arrayvec", - "euclid", - "smallvec", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -997,12 +836,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "linebender_resource_handle" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" - [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -1040,12 +873,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "nohash-hasher" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" - [[package]] name = "num-conv" version = "0.2.0" @@ -1143,19 +970,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "peniko" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2b6aadb221872732e87d465213e9be5af2849b0e8cc5300a8ba98fffa2e00a" -dependencies = [ - "bytemuck", - "color", - "kurbo", - "linebender_resource_handle", - "smallvec", -] - [[package]] name = "phf" version = "0.13.1" @@ -1269,12 +1083,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "profiling" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" - [[package]] name = "quick-xml" version = "0.39.2" @@ -1352,16 +1160,6 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" -[[package]] -name = "read-fonts" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5" -dependencies = [ - "bytemuck", - "font-types", -] - [[package]] name = "redox_syscall" version = "0.5.18" @@ -1487,12 +1285,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "self_cell" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" - [[package]] name = "semver" version = "1.0.27" @@ -1585,16 +1377,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" -[[package]] -name = "skrifa" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac" -dependencies = [ - "bytemuck", - "read-fonts", -] - [[package]] name = "slab" version = "0.4.12" @@ -1792,12 +1574,6 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - [[package]] name = "unicode-width" version = "0.2.2" @@ -1822,38 +1598,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "1.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" - -[[package]] -name = "vello_common" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd1a4c633ce09e7d713df1a6e036644a125e15e0c169cfb5180ddf5836ca04b" -dependencies = [ - "bytemuck", - "fearless_simd", - "hashbrown 0.16.1", - "log", - "peniko", - "skrifa", - "smallvec", -] - -[[package]] -name = "vello_cpu" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162bfe48aabf6a9fdcd401b628c7d9f260c2cbabb343c70a65feba6f7849edc" -dependencies = [ - "bytemuck", - "hashbrown 0.16.1", - "vello_common", -] - [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index 48ad558d..9a1b38a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,8 +68,6 @@ opera = "1.0.1" with_builtin_macros = "0.1.0" blake3 = "1.8.2" run-on-drop = "1.0.0" -egui = { version = "0.34.1", default-features = false } -egui_tiles = { version = "0.15.0", default-features = false } numeric-sort = "0.1.5" [build-dependencies] @@ -89,49 +87,6 @@ opt-level = 3 [profile.dev.package."smallvec"] opt-level = 3 -[profile.dev.package."egui"] -opt-level = 3 -debug = "line-tables-only" - -[profile.dev.package."emath"] -opt-level = 3 -debug = "line-tables-only" - -[profile.dev.package."epaint"] -opt-level = 3 -debug = "line-tables-only" - -[profile.dev.package."ecolor"] -opt-level = 3 -debug = "line-tables-only" - -[profile.dev.package."font-types"] -opt-level = 3 -debug = "line-tables-only" - -[profile.dev.package."skrifa"] -opt-level = 3 -debug = "line-tables-only" - -[profile.dev.package."read-fonts"] -opt-level = 3 -debug = "line-tables-only" - -[profile.dev.package."vello_cpu"] -opt-level = 3 -debug = "line-tables-only" - -[profile.dev.package."vello_common"] -opt-level = 3 -debug = "line-tables-only" - -[profile.dev.package."peniko"] -opt-level = 3 -debug = "line-tables-only" - -[profile.dev.package."kurbo"] -opt-level = 3 -debug = "line-tables-only" [features] rc_tracking = [] diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 6441d28c..2bb5904a 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -10,7 +10,6 @@ - [Installation](installation.md) - [Running Jay](running.md) -- [Control Center](control-center.md) # Configuration diff --git a/book/src/cli.md b/book/src/cli.md index 41e3b479..c7c222a6 100644 --- a/book/src/cli.md +++ b/book/src/cli.md @@ -674,14 +674,6 @@ Show color management status: ## Other Commands -### `jay control-center` - -Open the [Control Center](control-center.md) GUI: - -```shell -~$ jay control-center -``` - ### `jay portal` Run the Jay desktop portal (provides screen sharing and other XDG desktop diff --git a/book/src/configuration/shortcuts.md b/book/src/configuration/shortcuts.md index ecc0b64d..465c2bb8 100644 --- a/book/src/configuration/shortcuts.md +++ b/book/src/configuration/shortcuts.md @@ -134,7 +134,6 @@ alt-shift-r = "reload-config-toml" - `disable-pointer-constraint` -- release a pointer lock/confinement - `focus-parent` -- move focus to the parent container - `toggle-bar`, `show-bar`, `hide-bar` -- control the status bar -- `open-control-center` -- open the Jay control center GUI - `warp-mouse-to-focus` -- warp the cursor to the center of the focused window - `kill-client` -- forcefully disconnect a client (in a window rule, kills the window's client; in a client rule, kills the matched client; has no effect diff --git a/book/src/control-center.md b/book/src/control-center.md deleted file mode 100644 index 00157689..00000000 --- a/book/src/control-center.md +++ /dev/null @@ -1,608 +0,0 @@ -# Control Center - -The control center is Jay's built-in graphical interface for inspecting and -modifying compositor settings. It provides a convenient alternative to editing -configuration files or running CLI commands -- most settings that can be changed -in `config.toml` or via the CLI can also be changed here. - -> [!NOTE] -> Changes made in the control center are not persisted across compositor -> restarts. To make settings permanent, add them to your `config.toml`. - -> [!TIP] -> The control center consumes GPU and CPU resources while open. Close it when -> not in use to avoid reducing compositor performance. - -## Opening the Control Center - -- Press `alt-c` (the default shortcut for the `open-control-center` action). -- Run the CLI command: - - ```shell - ~$ jay control-center - ``` - -## Interface Overview - -The control center window has a sidebar on the left listing all available panes -and a central panel area on the right. - -- **Click** a pane name in the sidebar to open it. -- **Multiple panes** can be open at the same time -- they appear as tabs in the - panel area. -- **Drag** pane tabs to rearrange them or to split the panel area into - side-by-side or stacked layouts. -- **Close** a pane by clicking its X button or middle-clicking its tab. - -## Panes - -### Compositor - -General information and top-level controls for the running compositor. - -Repository -: Link to the Jay GitHub repository - -Version -: The running Jay version - -PID -: The compositor process ID - -WAYLAND_DISPLAY -: The Wayland socket name (shown when available) - -Config DIR -: Path to the active configuration directory (shown when available) - -Libei Socket -: Toggle the libei input emulation socket - -LIBEI_SOCKET -: The socket name (shown when the Libei Socket toggle is enabled) - -Workspace Display Order -: Dropdown to select how workspaces are ordered in the bar - -Log Level -: Dropdown to change the active log level at runtime (shown when the logger is available) - -Log File -: Click to copy the log file path to the clipboard (shown when the logger is available) - -Buttons at the bottom: - -- **Quit** -- stop the compositor. -- **Reload Config** -- reload the configuration file. -- **Switch to VT** -- switch to another virtual terminal (with a numeric input - to select which one). - -### Outputs - -The Outputs pane is the largest and most interactive pane. It has two sub-views: -a visual **arrangement editor** and per-connector **settings**. - -#### Arrangement editor - -A 2D preview of your monitor layout. Monitors are drawn as labeled rectangles -at their configured positions and sizes. - -- **Click** a monitor to select it (highlighted with a shadow). -- **Drag** a selected monitor to reposition it. -- **Scroll** to zoom in and out. -- **Middle-click drag** or **right-click drag** to pan the viewport. -- **Arrow keys** nudge the selected monitor by 1 pixel. -- **Snap to neighbor** -- when enabled, dragged monitors snap to the edges of - neighboring monitors within a 10-pixel threshold. Hold **Shift** to - temporarily invert the snapping behavior. -- **Guide lines** -- optional horizontal and vertical lines at the edges of all - monitors, helping you align them precisely. - -A **Zoom To Fit** checkbox in the top bar auto-scales the view to fit all -monitors. It is disabled when you manually pan or zoom. - -Arrangement settings (accessible via the Settings button): - -Show guide lines -: Draw alignment guide lines - -Snap to neighbor -: Snap edges when dragging (hold Shift to invert) - -Show arrangement area -: Toggle the visual arrangement sub-pane - -Layout -: How the arrangement and settings are split: Auto, Vertical, or Horizontal - -Show disconnected heads -: Include outputs that are no longer connected - -Show disabled heads -: Include outputs that are disabled - -#### Staged changes - -Changes made in the Outputs pane are **staged** -- they are not applied -immediately. Three buttons in the top bar control the workflow: - -- **Test** -- validates the staged changes against the display backend without - applying them. Errors are shown in the pane. -- **Commit** -- applies all staged changes. The pane title shows `Outputs (*)` - when there are uncommitted changes. -- **Reset** -- discards all staged changes and reverts to the live state. - This is displayed as a checkbox; checking it resets the staged changes. - -When a staged value differs from the live value, the current (live) value is -shown alongside with a `^ current` annotation. - -#### Per-connector settings - -Each connected display appears as a collapsible section with the connector name, -manufacturer, and model. Inside: - -Serial Number -: Read-only identifier - -Enabled -: Toggle the connector on or off - -Position -: X and Y coordinates in compositor space - -Scale -: Fractional scaling factor, with +/- buttons for fine adjustment - -Mode -: Resolution and refresh rate (dropdown when multiple modes are available) - -Physical Size (mm) -: Read-only physical dimensions in millimeters - -Size -: Read-only computed pixel dimensions of the output - -Transform -: Rotation and mirroring (none, rotate-90, rotate-180, rotate-270, flip, and flipped rotations) - -Custom Brightness -: Toggle whether to use a custom SDR content brightness - -Brightness -: Brightness value in cd/m^2 (shown when Custom Brightness is enabled) - -Colorimetry -: Color space (depends on monitor capabilities) - -EOTF -: Transfer function (depends on monitor capabilities) - -Format -: Framebuffer pixel format - -Tearing -: Tearing mode. When set to a "Fullscreen" mode, a **Limit Windows** checkbox appears; inside that, a **Requests Tearing** checkbox filters by whether the window has requested tearing. - -VRR Active -: Read-only indicator of whether VRR is currently active (only shown when the monitor supports VRR) - -VRR -: Variable refresh rate mode (only shown when the monitor supports VRR). When set to a "Fullscreen" mode, a **Limit Windows** checkbox appears; inside that, a **Limit Content Types** checkbox enables filtering by content type (**Photos**, **Videos**, **Games** checkboxes). - -Non-desktop -: Read-only indicator (Yes/No) of whether the connector is inherently non-desktop - -Override -: Force the connector to be treated as desktop or non-desktop - -Blend Space -: How colors are blended during compositing (sRGB or linear) - -Use Native Gamut -: Use the display's advertised color primaries instead of assuming sRGB - -Native Gamut -: Read-only CIE xy primaries for red, green, blue, and white point - -Limit Cursor HZ -: Toggle to limit cursor-triggered refresh rate when VRR is active - -Cursor HZ -: Cursor refresh rate value (shown when Limit Cursor HZ is enabled) - -Flip Margin (ms) -: Read-only page-flip margin for this connector - -### Virtual Outputs - -Manage headless virtual outputs. These are useful for screen sharing, testing, -or running applications on a display without a physical monitor. - -- View the list of existing virtual outputs. -- **Add** a new virtual output by entering a name and clicking Add. -- **Remove** an existing virtual output by clicking its X button. - -### GPUs - -Inspect and configure graphics cards (DRM devices). Each GPU appears as a -collapsible section showing its device path and model name. - -Vendor -: Read-only GPU vendor name - -Model -: Read-only GPU model name - -Devnode -: Read-only device path - -Syspath -: Read-only sysfs path - -PCI ID -: Read-only vendor:model in hex - -Dev -: Read-only major:minor device numbers - -API -: Dropdown to select the graphics API -- Vulkan (recommended) or the legacy OpenGL renderer - -Primary Device -: Checkbox to make this GPU the render device - -Direct Scanout -: Toggle direct scanout (bypasses composition for lower latency) - -Flip Margin -: Adjust the page-flip margin in milliseconds, with +/- buttons for 0.1 ms steps - -Connectors -: List of display connectors attached to this GPU - -### Input - -The Input pane is divided into per-seat and per-device sections. - -#### Per-seat settings - -Each seat (typically just `default`) appears as a collapsible section: - -Repeat Rate -: Key repeat speed, with +/- 20 buttons - -Repeat Delay -: Initial delay before key repeat begins, with +/- 20 buttons - -Cursor Size -: Size of the seat cursor in pixels - -Simple IM -: Toggle the built-in XCompose-based input method - -Hardware Cursor -: Toggle hardware cursor rendering - -Pointer Revert Key -: Text field for the keysym name of the cancel key - -Focus Follows Mouse -: Toggle whether moving the pointer over a window gives it focus - -Fallback Output Mode -: Dropdown to choose between cursor-based and focus-based output selection - -Below the settings grid: - -- **Focus History** -- checkboxes for "Only Visible" and "Same Workspace". -- **Reload Simple IM** -- button to reload XCompose files without restarting. - -##### Keymap management - -Each seat has a full keymap management section: - -- **Copy Keymap** -- copies the current keymap text to the clipboard. -- **Load Default Keymap** -- restores the compositor's default keymap. -- **Backup / Restore Keymap** -- save and restore a keymap backup. -- **Load Keymap from Clipboard** -- paste a keymap from the clipboard. -- **Create Keymap from Names** -- build a keymap from RMLVO (Rules, Model, - Layout, Variant, Options) fields. Rules and Model have a text input and a - "Default" checkbox; Layouts, Variants, and Options have text inputs only. - Click **Load** to apply. - -#### Per-device settings - -Each input device appears as a collapsible section. The available settings -depend on the device's capabilities: - -Seat -: Dropdown to assign the device to a seat, with a Detach button. Shown for all devices. - -Syspath / Devnode -: Read-only device paths. Shown for all devices. - -Capabilities -: Read-only list (e.g. Keyboard, Pointer, Touch). Shown for all devices. - -Natural Scrolling -: Toggle scroll direction. Shown for devices that support it. - -Scroll Distance (px) -: Pixels per legacy scroll event. Shown for pointer devices. - -Accel Profile -: Dropdown: Flat or Adaptive. Shown for devices with acceleration. - -Accel Speed -: Numeric input (-1.0 to 1.0). Shown for devices with acceleration. - -Click Method -: Dropdown: none, button-areas, clickfinger. Shown for devices that support it. - -Tap Enabled -: Toggle tap-to-click. Shown for touchpads. - -Tap Drag Enabled -: Toggle tap-and-drag. Shown for touchpads. - -Tap Drag Lock Enabled -: Toggle tap-drag lock. Shown for touchpads. - -Left Handed -: Swap primary and secondary buttons. Shown for devices that support it. - -Middle Button Emulation -: Simultaneous left+right produces middle click. Shown for devices that support it. - -Output -: Dropdown to map the device to a specific output (only has effect for touch and tablet devices), with a Detach button. Shown for all devices. - -Transform Matrix -: 2x2 matrix applied to relative motion. Shown for pointer devices. - -Calibration Matrix -: 2x3 matrix for absolute input calibration. Shown for devices that support it. - -Device Keymap -: Override the seat keymap for this device, with full keymap management UI and a "Use Seat Keymap" button to revert. Shown for keyboards. - -### Idle - -Configure the screensaver and idle behavior: - -Interval -: Minutes and seconds of inactivity before the on-idle action fires - -Grace period -: Minutes and seconds of the warning phase (screen goes black but is not yet locked) - -Inhibitors -: Collapsible list showing which applications are currently preventing idle (e.g. video players), with a count in the header - -### Look and Feel - -Visual customization with live preview. Changes take effect immediately. - -Show Bar -: Toggle the status bar - -Bar Position -: Dropdown to select the bar position - -Show Titles -: Toggle window title bars - -Primary Selection -: Toggle middle-click paste (requires application restart to take effect) - -UI Drag -: Toggle whether workspaces and tiles can be dragged - -UI Drag Threshold (px) -: Minimum distance in pixels before a drag begins - -Float Pin Icon -: Show the pin icon on floating windows even when not pinned - -Float Above Fullscreen -: Show floating windows above fullscreen windows - -Font -: Text field for the main compositor font family - -Title Font -: Override font for window title bars (empty = use main font) - -Bar Font -: Override font for the status bar (empty = use main font) - -Three reset buttons at the bottom: **Reset Sizes**, **Reset Colors**, and -**Reset Fonts**. - -#### Sizes - -A collapsible section with numeric inputs for every theme size: border widths, -title heights, bar height, gaps, and other spacing values. - -#### Colors - -A collapsible section with **color pickers** for every theme color. Click a -color swatch to open a full RGBA color picker with sliders and hex input. -This includes colors for backgrounds, borders, text, the status bar, focused -and unfocused windows, attention indicators, and more. - -### Clients - -Inspect and manage connected Wayland clients. - -A **Filter** toggle at the top enables the composable filter builder (see -[Filtering](#filtering) below). When filtering is off, all clients are shown. - -Each client appears as a collapsible section showing its ID and process name. -Expand it to see: - -ID -: Client identifier - -PID -: Process ID - -UID -: User ID - -comm -: Process name - -exe -: Executable path - -Sandboxed -: Whether the client is sandboxed (only shown for sandboxed clients) - -Secure -: Whether the client uses the privileged socket (only shown for secure clients) - -Xwayland -: Shown only for X11 clients - -Sandbox Engine -: Sandbox engine name (shown when sandboxed) - -App ID -: Sandbox application ID (shown when sandboxed) - -Instance ID -: Sandbox instance ID (shown when sandboxed) - -Tag -: The connection tag, if any - -Kill -: Button to forcefully disconnect the client - -Capabilities -: Collapsible list of effective Wayland capabilities - -Windows -: Collapsible list of all windows owned by this client - -Click the **open in new pane** icon on any client to open a dedicated pane for -that client, allowing you to keep it visible while browsing other panes. - -### Window Search - -Search and filter windows across the compositor using the composable filter -builder (see [Filtering](#filtering) below). - -Each matching window appears as a collapsible section showing its title. Expand -it to see: - -ID -: Window identifier - -Title -: Window title - -Workspace -: Which workspace the window is on - -Type -: Container, xdg_toplevel, X Window, or Placeholder - -Tag -: Toplevel tag (set via window rules); only shown for xdg_toplevel windows - -X11 properties -: Class, Instance, and Role (only shown for Xwayland windows) - -App ID -: Application identifier - -Floating -: Whether the window is floating - -Visible -: Whether the window is visible - -Urgent -: Whether the window has the urgency flag - -Fullscreen -: Whether the window is fullscreen - -Content Type -: The content type hint (photo, video, game), if set - -Client -: Full client details (same as the Clients pane) - -Click the **open in new pane** icon on any window to open a dedicated pane for -that window. - -### Xwayland - -Manage the Xwayland compatibility layer for running X11 applications: - -Enabled -: Toggle Xwayland on or off - -Scaling Mode -: Dropdown: `default` or `downscaled` (renders at highest integer scale then downscales for sharper text on HiDPI) - -DISPLAY -: Read-only X11 display number (only shown when Xwayland is running) - -Running -: Whether Xwayland is currently running - -PID -: Xwayland process ID (only shown when Xwayland is running) - -Kill -: Button to forcefully terminate Xwayland (only shown when Xwayland is running) - -Client -: Collapsible section with full client details for the Xwayland process (only shown when Xwayland is running) - -### Color Management - -Configure the Wayland color management protocol: - -Enabled -: Toggle the color management protocol for clients - -Available -: Read-only indicator of whether color management is available with the current renderer and hardware - -## Filtering - -The **Clients** and **Window Search** panes share a composable filter system -for narrowing down results. The filter builder works as follows: - -At the top level, select a combinator or a leaf criterion from the dropdown: - -- **Not** -- inverts a single child criterion. -- **All** -- all child criteria must match (AND). -- **Any** -- at least one child criterion must match (OR). -- **Exactly(n)** -- exactly *n* child criteria must match (with a numeric input - for *n*). - -Compound criteria contain a list of children. Click **Add** to append a new -criterion; click the X button on any child to remove it. Criteria can be nested -to arbitrary depth. - -Leaf criteria vary by context: - -**Client criteria:** Comm, Exe, Tag, Sandbox Engine, Sandbox App ID, Sandbox -Instance ID (all regex-matched text fields with a "Regex" checkbox), Sandboxed, -Is Xwayland (boolean), UID, PID (numeric inputs). - -**Window criteria:** Title, App ID, Tag, Workspace, X Class, X Instance, X Role -(all regex-matched text fields), Floating, Visible, Urgent, Fullscreen -(boolean), Content Types (checkboxes for Photo, Video, Game), and **Client** -(a nested client criterion builder for filtering by the owning client's -properties). - -Text-matching criteria have a **Regex** checkbox. When unchecked, the input is -matched as a literal string. When checked, it is treated as a regular -expression. Invalid regex patterns show an error message. diff --git a/book/src/features.md b/book/src/features.md index ae20f6c9..1e7c69a3 100644 --- a/book/src/features.md +++ b/book/src/features.md @@ -71,7 +71,6 @@ Commands: color-management Inspect/modify the color-management settings clients Inspect/manipulate the connected clients tree Inspect the surface tree - control-center Opens the control center version Prints the Jay version and exits pid Prints the Jay PID and exits help Print this message or the help of the given subcommand(s) @@ -85,12 +84,6 @@ Options: See the full [Command-Line Interface](cli.md) reference for details. -## Control Center - -Jay includes a built-in GUI control center (opened with `alt-c`) for managing -outputs, input devices, GPUs, idle settings, color management, and more -- -without editing the config file. See [Control Center](control-center.md). - ## Multi-Monitor Support Jay can be used with multiple monitors with hot-plug and hot-unplug support. @@ -133,7 +126,7 @@ automatically by the default configuration. ## Fractional Scaling Jay supports per-monitor fractional scaling. Scale factors can be set per -output in the config file or at runtime via the control center and CLI. +output in the config file or at runtime via the CLI. See [Outputs (Monitors)](configuration/outputs.md) for details. diff --git a/book/src/introduction.md b/book/src/introduction.md index 27da4c1a..306a5a46 100644 --- a/book/src/introduction.md +++ b/book/src/introduction.md @@ -26,12 +26,8 @@ variable refresh rate (VRR), tearing presentation, HDR, and screen sharing via xdg-desktop-portal. X11 applications are supported through Xwayland. Jay is configured through a declarative TOML file, with an optional advanced -mode that uses a shared library for programmatic control. A built-in -[control center](control-center.md) (opened with `alt-c`) provides a full GUI -for inspecting and changing compositor settings at runtime -- including output -arrangement, input devices, color management, GPU selection, and more. A -comprehensive command-line interface makes scripting and automation -straightforward. +mode that uses a shared library for programmatic control. A comprehensive +command-line interface makes scripting and automation straightforward. See the [Features](features.md) chapter for a comprehensive overview of what Jay can do, or jump straight to [Installation](installation.md) to get started. diff --git a/book/src/running.md b/book/src/running.md index 08eef933..b303fa7d 100644 --- a/book/src/running.md +++ b/book/src/running.md @@ -44,24 +44,6 @@ Then log out and select **Jay** from the session list. > ~$ sudo ln -s ~/.cargo/bin/jay /usr/local/bin/jay > ``` -## The Control Center - -Once Jay is running, press `alt-c` to open the -[control center](control-center.md) -- a built-in GUI that lets you inspect and -modify most compositor settings without editing config files or running CLI -commands. From the control center you can: - -- Rearrange monitors with a visual drag-and-drop editor. -- Configure input devices -- acceleration, tap behavior, keymaps, and more. -- Switch GPUs and graphics APIs. -- Adjust theme colors, fonts, borders, and gaps with live color pickers. -- Manage idle timeouts and screen locking. -- Search and filter windows and clients. -- Toggle Xwayland and color management. - -You can also open it from the command line with `jay control-center`. See the -[Control Center](control-center.md) chapter for a full tour of every pane. - ## Default Keybindings Jay ships with a built-in default configuration. The most important default @@ -99,9 +81,6 @@ keybindings are listed below. `alt-shift-f` : Toggle floating -`alt-c` -: Open the control center - `alt-shift-c` : Close focused window diff --git a/build/vulkan/hash.rs b/build/vulkan/hash.rs index 7a0cb297..452d6646 100644 --- a/build/vulkan/hash.rs +++ b/build/vulkan/hash.rs @@ -26,12 +26,6 @@ pub const TREES: &[Tree] = &[ "legacy/tex.frag", ], }, - Tree { - root: "src/egui_adapter/shaders", - hash: "src/egui_adapter/shaders_hash.txt", - bin: "src/egui_adapter/shaders_bin", - shaders: &["shader.vert", "shader.frag"], - }, ]; fn calculate_hash(tree: &Tree) -> anyhow::Result { diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index ff850946..c4a912ac 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -1067,21 +1067,10 @@ impl ConfigClient { position } - pub fn set_egui_fonts(&self, proportional: Option>, monospace: Option>) { - self.send(&ClientMessage::SetEguiFonts { - proportional, - monospace, - }); - } - pub fn set_middle_click_paste_enabled(&self, enabled: bool) { self.send(&ClientMessage::SetMiddleClickPasteEnabled { enabled }); } - pub fn open_control_center(&self) { - self.send(&ClientMessage::OpenControlCenter); - } - pub fn set_workspace_display_order(&self, order: WorkspaceDisplayOrder) { self.send(&ClientMessage::SetWorkspaceDisplayOrder { order }); } diff --git a/jay-config/src/_private/ipc.rs b/jay-config/src/_private/ipc.rs index 9e0415b7..bcd48fcc 100644 --- a/jay-config/src/_private/ipc.rs +++ b/jay-config/src/_private/ipc.rs @@ -847,11 +847,6 @@ pub enum ClientMessage<'a> { fds: Vec<(i32, i32)>, tag: Option<&'a str>, }, - SetEguiFonts { - proportional: Option>, - monospace: Option>, - }, - OpenControlCenter, ConnectorSupportsArbitraryModes { connector: Connector, }, diff --git a/jay-config/src/lib.rs b/jay-config/src/lib.rs index 0b980479..34a58f1e 100644 --- a/jay-config/src/lib.rs +++ b/jay-config/src/lib.rs @@ -381,7 +381,3 @@ pub fn set_middle_click_paste_enabled(enabled: bool) { get!().set_middle_click_paste_enabled(enabled); } -/// Opens the control center. -pub fn open_control_center() { - get!().open_control_center(); -} diff --git a/jay-config/src/theme.rs b/jay-config/src/theme.rs index d3e3fbb0..64883b09 100644 --- a/jay-config/src/theme.rs +++ b/jay-config/src/theme.rs @@ -197,20 +197,6 @@ pub fn get_bar_position() -> BarPosition { get!(BarPosition::Top).get_bar_position() } -/// Sets the proportional fonts used by egui windows. -/// -/// The default is `["sans-serif", "Noto Sans", "Noto Color Emoji"]`. -pub fn set_egui_proportional_fonts<'a>(fonts: impl IntoIterator) { - get!().set_egui_fonts(Some(fonts.into_iter().collect()), None); -} - -/// Sets the monospace fonts used by egui windows. -/// -/// The default is `["monospace", "Noto Sans Mono", "Noto Color Emoji"]`. -pub fn set_egui_monospace_fonts<'a>(fonts: impl IntoIterator) { - get!().set_egui_fonts(None, Some(fonts.into_iter().collect())); -} - /// Elements of the compositor whose color can be changed. pub mod colors { use { diff --git a/src/backend.rs b/src/backend.rs index 5a2296be..af63d868 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -596,9 +596,6 @@ pub trait BackendDrmDevice { fn set_flip_margin(&self, margin: u64) { let _ = margin; } - fn flip_margin(&self) -> Option { - None - } } pub trait BackendDrmLease { diff --git a/src/backends/metal/video.rs b/src/backends/metal/video.rs index c95781c6..64cc7c12 100644 --- a/src/backends/metal/video.rs +++ b/src/backends/metal/video.rs @@ -318,9 +318,6 @@ impl BackendDrmDevice for MetalDrmDevice { } } - fn flip_margin(&self) -> Option { - Some(self.min_post_commit_margin.get()) - } } pub struct HandleEvents { diff --git a/src/cli.rs b/src/cli.rs index 6e94634f..e3d8d74a 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -2,7 +2,6 @@ mod clients; mod color; mod color_management; mod config; -mod control_center; mod damage_tracking; mod duration; mod generate; @@ -112,8 +111,6 @@ pub enum Cmd { Clients(ClientsArgs), /// Inspect the surface tree. Tree(TreeArgs), - /// Opens the control center. - ControlCenter, /// Prints the Jay version and exits. Version, /// Prints the Jay PID and exits. @@ -270,7 +267,6 @@ pub fn main() { #[cfg(feature = "it")] Cmd::RunTests => crate::it::run_tests(), Cmd::Reexec(a) => reexec::main(cli.global, a), - Cmd::ControlCenter => control_center::main(cli.global), Cmd::Config(a) => config::main(cli.global, a), } } diff --git a/src/cli/control_center.rs b/src/cli/control_center.rs deleted file mode 100644 index 3a3f2b93..00000000 --- a/src/cli/control_center.rs +++ /dev/null @@ -1,32 +0,0 @@ -use { - crate::{ - cli::GlobalArgs, - tools::tool_client::{Handle, ToolClient, with_tool_client}, - wire::{jay_compositor, jay_open_control_center_request}, - }, - std::rc::Rc, -}; - -pub fn main(global: GlobalArgs) { - with_tool_client(global.log_level, |tc| async move { - let cc = ControlCenter { tc: tc.clone() }; - cc.run().await; - }); -} - -struct ControlCenter { - tc: Rc, -} - -impl ControlCenter { - async fn run(self) { - let tc = &self.tc; - let comp = tc.jay_compositor().await; - let id = tc.id(); - tc.send(jay_compositor::OpenControlCenter { self_id: comp, id }); - jay_open_control_center_request::Failed::handle(&tc, id, (), |_, ev| { - fatal!("Could not open the control center: {}", ev.msg); - }); - tc.round_trip().await; - } -} diff --git a/src/compositor.rs b/src/compositor.rs index 611c8bdc..c02bcb4c 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -14,7 +14,6 @@ use { clientmem::{self, ClientMemError}, cmm::{cmm_manager::ColorManager, cmm_primaries::Primaries}, config::ConfigProxy, - control_center::redraw_control_centers, copy_device::CopyDeviceRegistry, cpu_worker::{CpuWorker, CpuWorkerError}, criteria::{ @@ -395,8 +394,6 @@ fn start_compositor2( eventfd_cache, lazy_event_sources: Default::default(), bo_drop_queue: Rc::new(ObjectDropQueue::new(&ring)), - egg_state: Default::default(), - control_centers: Default::default(), virtual_outputs: Default::default(), clean_logs_older_than: Default::default(), }); @@ -605,10 +602,6 @@ fn start_global_event_handlers(state: &Rc) -> Vec> { "lazy event sources", handle_lazy_event_sources(state.clone()), ), - eng.spawn( - "redraw control centers", - redraw_control_centers(state.clone()), - ), eng.spawn( "warp mouse to focus", handle_warp_mouse_to_focus(state.clone()), diff --git a/src/config/handler.rs b/src/config/handler.rs index 4dd15861..24f22015 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -1841,16 +1841,6 @@ impl ConfigProxyHandler { Ok(()) } - fn handle_set_egui_fonts(&self, proportional: Option>, monospace: Option>) { - self.state.set_egui_fonts(proportional, monospace); - } - - fn handle_open_control_center(&self) { - if let Err(e) = self.state.open_control_center() { - log::error!("Could not open control center: {}", ErrorFmt(e)); - } - } - fn handle_set_log_level(&self, level: ConfigLogLevel) { self.state.set_log_level(level.into()); } @@ -3410,11 +3400,6 @@ impl ConfigProxyHandler { fds, tag, } => self.handle_run(prog, args, env, fds, tag).wrn("run")?, - ClientMessage::SetEguiFonts { - proportional, - monospace, - } => self.handle_set_egui_fonts(proportional, monospace), - ClientMessage::OpenControlCenter => self.handle_open_control_center(), ClientMessage::ConnectorSupportsArbitraryModes { connector } => self .handle_connector_supports_arbitrary_modes(connector) .wrn("connector_supports_arbitrary_modes")?, diff --git a/src/control_center.rs b/src/control_center.rs deleted file mode 100644 index e3fc8be7..00000000 --- a/src/control_center.rs +++ /dev/null @@ -1,687 +0,0 @@ -use { - crate::{ - control_center::{ - cc_clients::{ClientPane, ClientsPane}, - cc_color_management::ColorManagementPane, - cc_compositor::CompositorPane, - cc_gpus::GpusPane, - cc_idle::IdlePane, - cc_input::InputPane, - cc_look_and_feel::LookAndFeelPane, - cc_outputs::OutputsPane, - cc_virtual_outputs::VirtualOutputsPane, - cc_window::{WindowPane, WindowSearchPane}, - cc_xwayland::XwaylandPane, - }, - egui_adapter::egui_platform::{ - EggError, EggWindow, EggWindowOwner, - icons::{ICON_CLOSE, ICON_DRAG_INDICATOR, ICON_INFO}, - }, - macros::Bitflag, - state::State, - utils::{ - asyncevent::AsyncEvent, copyhashmap::CopyHashMap, - event_listener::LazyEventSourceListener, numcell::NumCell, static_text::StaticText, - }, - }, - egui::{ - Align, CentralPanel, Checkbox, Color32, ComboBox, CursorIcon, DragValue, Frame, Grid, Id, - InnerResponse, Label, Layout, Panel, Response, Rgba, RichText, ScrollArea, Sense, Stroke, - TextBuffer, TextEdit, Ui, UiBuilder, Visuals, Widget, WidgetText, emath::Numeric, vec2, - }, - egui_tiles::{ResizeState, TabState, Tile, TileId, Tiles, Tree}, - linearize::{Linearize, LinearizeExt}, - std::{ - cell::RefCell, - hash::Hash, - mem, - ops::{Deref, DerefMut, RangeInclusive}, - rc::Rc, - }, - thiserror::Error, -}; - -mod cc_clients; -mod cc_color_management; -mod cc_compositor; -mod cc_criterion; -mod cc_gpus; -mod cc_idle; -mod cc_input; -mod cc_look_and_feel; -mod cc_outputs; -mod cc_sidebar; -mod cc_virtual_outputs; -mod cc_window; -mod cc_xwayland; - -#[derive(Debug, Error)] -pub enum ControlCenterError { - #[error("Could not get the egg context")] - GetEggContext(#[source] EggError), -} - -linear_ids!(ControlCenterIds, ControlCenterId, u64); - -pub async fn redraw_control_centers(state: Rc) { - let cc = &state.control_centers; - loop { - cc.redraw.triggered().await; - let interests = cc.change.take(); - for cc in cc.control_centers.lock().values() { - if cc.inner.interests.interests.get().intersects(interests) { - cc.inner.window.request_redraw(); - } - } - } -} - -#[derive(Default)] -pub struct ControlCenters { - ids: ControlCenterIds, - change: NumCell, - redraw: AsyncEvent, - control_centers: CopyHashMap>, -} - -bitflags! { - ControlCenterInterest: u32; - CCI_COMPOSITOR, - CCI_IDLE, - CCI_COLOR_MANAGEMENT, - CCI_XWAYLAND, - CCI_OUTPUTS, - CCI_GPUS, - CCI_INPUT, - CCI_LOOK_AND_FEEL, - CCI_VIRTUAL_OUTPUTS, -} - -pub struct ControlCenter { - inner: Rc, -} - -linear_ids!(PaneIds, PaneId, u64); - -struct ControlCenterInner { - id: ControlCenterId, - state: Rc, - tree: RefCell, - window: Rc, - pane_ids: PaneIds, - interests: Rc, -} - -#[derive(Default)] -struct Interests { - interests: NumCell, - interests_array: [NumCell; ::Type::BITS as usize], -} - -struct Settings { - tree: Tree, -} - -struct Pane { - id: PaneId, - ps: PaneState, - own_interests: ControlCenterInterest, - cc_interests: Rc, - ty: PaneType, -} - -struct PaneState { - errors: Vec, -} - -enum PaneType { - Compositor(CompositorPane), - Idle(IdlePane), - ColorManagement(ColorManagementPane), - Xwayland(XwaylandPane), - Outputs(Box), - GPUs(GpusPane), - Input(InputPane), - LookAndFeel(LookAndFeelPane), - Clients(ClientsPane), - Client(ClientPane), - WindowSearch(WindowSearchPane), - Window(WindowPane), - VirtualOutputs(VirtualOutputsPane), -} - -struct CcBehavior<'a> { - cc: &'a Rc, - close: Option, - open: Option, -} - -impl ControlCenters { - pub fn clear(&self) { - self.control_centers.clear(); - } -} - -impl Pane { - fn title(&self, res: &mut String) { - match &self.ty { - PaneType::Compositor(v) => v.title(res), - PaneType::Idle(v) => v.title(res), - PaneType::ColorManagement(v) => v.title(res), - PaneType::Xwayland(v) => v.title(res), - PaneType::Outputs(v) => v.title(res), - PaneType::GPUs(v) => v.title(res), - PaneType::Input(v) => v.title(res), - PaneType::LookAndFeel(v) => v.title(res), - PaneType::Clients(v) => v.title(res), - PaneType::Client(v) => v.title(res), - PaneType::WindowSearch(v) => v.title(res), - PaneType::Window(v) => v.title(res), - PaneType::VirtualOutputs(v) => v.title(res), - } - } - - fn show(&mut self, behavior: &mut CcBehavior<'_>, ui: &mut Ui) { - match &mut self.ty { - PaneType::Compositor(p) => p.show(ui), - PaneType::Idle(p) => p.show(ui), - PaneType::ColorManagement(p) => p.show(ui), - PaneType::Xwayland(p) => p.show(behavior, ui), - PaneType::Outputs(p) => p.show(&mut self.ps, ui), - PaneType::GPUs(p) => p.show(ui), - PaneType::Input(p) => p.show(&mut self.ps, ui), - PaneType::LookAndFeel(p) => p.show(ui), - PaneType::Clients(p) => p.show(behavior, ui), - PaneType::Client(p) => p.show(behavior, ui), - PaneType::WindowSearch(p) => p.show(behavior, ui), - PaneType::Window(p) => p.show(behavior, ui), - PaneType::VirtualOutputs(p) => p.show(ui), - } - } -} - -impl PaneType { - fn interest(&self) -> ControlCenterInterest { - match self { - PaneType::Compositor(_) => CCI_COMPOSITOR, - PaneType::Idle(_) => CCI_IDLE, - PaneType::ColorManagement(_) => CCI_COLOR_MANAGEMENT, - PaneType::Xwayland(_) => CCI_XWAYLAND, - PaneType::Outputs(_) => CCI_OUTPUTS, - PaneType::GPUs(_) => CCI_GPUS, - PaneType::Input(_) => CCI_INPUT, - PaneType::LookAndFeel(_) => CCI_LOOK_AND_FEEL, - PaneType::Clients(_) => ControlCenterInterest::none(), - PaneType::Client(_) => ControlCenterInterest::none(), - PaneType::WindowSearch(_) => ControlCenterInterest::none(), - PaneType::Window(_) => ControlCenterInterest::none(), - PaneType::VirtualOutputs(_) => CCI_VIRTUAL_OUTPUTS, - } - } -} - -impl egui_tiles::Behavior for CcBehavior<'_> { - fn pane_ui(&mut self, ui: &mut Ui, tile_id: TileId, pane: &mut Pane) -> egui_tiles::UiResponse { - let mut drag = false; - Frame::central_panel(ui.style()).show(ui, |ui| { - ui.horizontal(|ui| { - drag = ui - .add(icon_label(ICON_DRAG_INDICATOR).sense(Sense::drag())) - .total_drag_delta() - .map(|d| d.length() >= 5.0) - .unwrap_or(false); - let mut title = String::new(); - pane.title(&mut title); - if ui - .add(icon_label(&title).sense(Sense::click())) - .middle_clicked() - { - self.close = Some(tile_id); - } - if ui - .add(icon_label(ICON_CLOSE).sense(Sense::click())) - .clicked() - { - self.close = Some(tile_id); - } - }); - ui.separator(); - show_errors(ui, &mut pane.ps); - ui.scope_builder(UiBuilder::new().id(Id::new(("pane", pane.id))), |ui| { - ScrollArea::vertical().show(ui, |ui| { - ui.allocate_space(vec2(ui.available_width(), 0.0)); - pane.show(self, ui); - }); - }); - }); - if drag { - egui_tiles::UiResponse::DragStarted - } else { - egui_tiles::UiResponse::None - } - } - - fn tab_title_for_pane(&mut self, _pane: &Pane) -> WidgetText { - "".into() - } - - fn tab_hover_cursor_icon(&self) -> CursorIcon { - CursorIcon::Default - } - - fn tab_title_for_tile(&mut self, tiles: &Tiles, tile_id: TileId) -> WidgetText { - fn add_title(tiles: &Tiles, res: &mut String, first: &mut bool, tile_id: TileId) { - if !mem::take(first) { - res.push_str("/"); - } - let Some(tile) = tiles.get(tile_id) else { - res.push_str("MISSING TILE"); - return; - }; - match tile { - Tile::Pane(p) => p.title(res), - Tile::Container(c) => { - let mut first = true; - for &tile_id in c.children() { - add_title(tiles, res, &mut first, tile_id); - } - } - } - } - let mut res = String::new(); - let mut first = true; - add_title(tiles, &mut res, &mut first, tile_id); - res.into() - } - - fn on_tab_button( - &mut self, - _tiles: &mut Tiles, - tile_id: TileId, - button_response: Response, - ) -> Response { - if button_response.middle_clicked() { - self.close = Some(tile_id); - } - button_response - } - - fn resize_stroke(&self, style: &egui::Style, resize_state: ResizeState) -> Stroke { - match resize_state { - ResizeState::Idle => style.visuals.widgets.noninteractive.bg_stroke, - ResizeState::Hovering => style.visuals.widgets.hovered.fg_stroke, - ResizeState::Dragging => style.visuals.widgets.active.fg_stroke, - } - } - - fn tab_bar_color(&self, visuals: &Visuals) -> Color32 { - (Rgba::from(visuals.panel_fill) * Rgba::from_gray(0.8)).into() - } - - fn tab_bg_color( - &self, - visuals: &Visuals, - _tiles: &Tiles, - _tile_id: TileId, - state: &TabState, - ) -> Color32 { - match state.active { - true => visuals.panel_fill, - false => self.tab_bar_color(visuals), - } - } -} - -impl EggWindowOwner for ControlCenterInner { - fn close(&self) { - self.close(); - } - - fn render(self: Rc, ui: &mut Ui) { - let settings = &mut *self.tree.borrow_mut(); - Panel::left("sidebar").show_inside(ui, |ui| self.show_sidebar(&mut settings.tree, ui)); - CentralPanel::default() - .frame( - Frame::central_panel(&ui.global_style()) - .outer_margin(0.0) - .inner_margin(0.0), - ) - .show_inside(ui, |ui| { - let tree = &mut settings.tree; - let mut behavior = CcBehavior { - cc: &self, - close: Default::default(), - open: Default::default(), - }; - tree.ui(&mut behavior, ui); - if let Some(close) = behavior.close { - tree.set_visible(close, false); - tree.remove_recursively(close); - ui.request_repaint(); - } - if let Some(ty) = behavior.open { - self.open(tree, ty); - ui.request_repaint(); - } - }); - } -} - -impl State { - pub fn open_control_center(self: &Rc) -> Result, ControlCenterError> { - let ctx = self - .get_egg_context() - .map_err(ControlCenterError::GetEggContext)?; - let window = ctx.create_window("Control Center"); - let cc = Rc::new(ControlCenter { - inner: Rc::new(ControlCenterInner { - id: self.control_centers.ids.next(), - window, - state: self.clone(), - tree: RefCell::new(Settings { - tree: Tree::new_tabs("abcd", vec![]), - }), - pane_ids: Default::default(), - interests: Default::default(), - }), - }); - cc.inner.window.set_owner(Some(cc.inner.clone())); - self.control_centers - .control_centers - .set(cc.inner.id, cc.clone()); - Ok(cc) - } - - pub fn trigger_cci(&self, cci: ControlCenterInterest) { - self.control_centers.change.or_assign(cci); - self.control_centers.redraw.trigger(); - } -} - -impl ControlCenterInner { - fn close(&self) { - self.window.set_owner(None); - self.tree.borrow_mut().tree = Tree::empty(""); - self.state.control_centers.control_centers.remove(&self.id); - } -} - -impl Drop for ControlCenter { - fn drop(&mut self) { - self.inner.close(); - } -} - -impl ControlCenterInner { - fn create_pane(&self, ty: PaneType) -> Pane { - let pane = Pane { - id: self.pane_ids.next(), - ps: PaneState { - errors: Default::default(), - }, - own_interests: ty.interest(), - cc_interests: self.interests.clone(), - ty, - }; - let own = pane.own_interests; - for (idx, v) in pane.cc_interests.interests_array.iter().enumerate() { - let interest = ControlCenterInterest(1 << idx); - if own.intersects(interest) && v.fetch_add(1) == 0 { - pane.cc_interests.interests.or_assign(interest); - } - } - pane - } - - fn open(&self, tree: &mut Tree, ty: PaneType) { - let pane = self.create_pane(ty); - let id = tree.tiles.insert_pane(pane); - if let Some(root) = tree.root - && let Some(tile) = tree.tiles.get_mut(root) - { - match tile { - Tile::Container(c) => { - c.add_child(id); - } - Tile::Pane(_) => { - let root = tree.tiles.insert_tab_tile(vec![root, id]); - tree.root = Some(root); - } - } - } else { - tree.root = Some(id); - } - tree.make_active(|t, _| t == id); - } -} - -impl Drop for Pane { - fn drop(&mut self) { - let own = self.own_interests; - for (idx, v) in self.cc_interests.interests_array.iter().enumerate() { - let interest = ControlCenterInterest(1 << idx); - if own.intersects(interest) && v.fetch_sub(1) == 1 { - self.cc_interests.interests.and_assign(!interest); - } - } - } -} - -fn icon_label(icon: &str) -> Label { - Label::new(icon).selectable(false) -} - -fn grid_label(ui: &mut Ui, label: &str) { - ui.with_layout(Layout::right_to_left(Align::Center), |ui| { - ui.label(label); - }); -} - -fn grid_label_ui(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse { - ui.with_layout(Layout::right_to_left(Align::Center), add_contents) -} - -fn tip(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui)) { - icon_label(ICON_INFO).ui(ui).on_hover_ui(add_contents); -} - -fn text_edit(ui: &mut Ui, v: &mut dyn TextBuffer) -> Response { - TextEdit::singleline(v) - .clip_text(false) - .min_size(vec2(200.0, 0.0)) - .ui(ui) -} - -fn show_errors(ui: &mut Ui, pane: &mut PaneState) { - if pane.errors.is_empty() { - return; - } - let mut to_remove = None; - for (idx, e) in pane.errors.iter().enumerate() { - ui.horizontal(|ui| { - Frame::new().inner_margin(5.0).show(ui, |ui| { - if ui.button(ICON_CLOSE).clicked() { - to_remove = Some(idx); - } - ui.label( - RichText::new("Error:") - .strong() - .color(ui.style().visuals.error_fg_color), - ); - ui.add(Label::new(e).wrap()); - }); - }); - } - if let Some(idx) = to_remove { - pane.errors.remove(idx); - ui.request_repaint(); - } - ui.separator(); -} - -fn grid( - ui: &mut Ui, - id_salt: impl Hash, - add_contents: impl FnOnce(&mut Ui) -> R, -) -> InnerResponse { - let mut spacing = ui.spacing().item_spacing; - spacing.x *= 3.0; - Grid::new(id_salt).spacing(spacing).show(ui, add_contents) -} - -fn row(ui: &mut Ui, name: &str, add_contents: impl FnOnce(&mut Ui) -> R) -> R { - row_ui(ui, name, |_| (), add_contents) -} - -fn row_ui( - ui: &mut Ui, - name: &str, - label: impl FnOnce(&mut Ui) -> S, - add_contents: impl FnOnce(&mut Ui) -> R, -) -> R { - let ui = &mut *ui.row(); - grid_label_ui(ui, |ui| { - ui.label(name); - label(ui); - }); - add_contents(ui) -} - -fn bool(ui: &mut Ui, name: &str, old: bool, set: impl FnOnce(bool)) { - bool_ui(ui, name, |_| (), old, set); -} - -fn bool_ui( - ui: &mut Ui, - name: &str, - label: impl FnOnce(&mut Ui) -> R, - mut v: bool, - set: impl FnOnce(bool), -) { - row_ui(ui, name, label, |ui| { - if Checkbox::without_text(&mut v).ui(ui).changed() { - set(v); - } - }); -} - -fn read_only_bool(ui: &mut Ui, name: &str, old: bool) { - read_only_bool_ui(ui, name, |_| (), old); -} - -fn read_only_bool_ui(ui: &mut Ui, name: &str, label: impl FnOnce(&mut Ui) -> R, mut v: bool) { - row_ui(ui, name, label, |ui| { - ui.add_enabled_ui(false, |ui| Checkbox::without_text(&mut v).ui(ui)); - }); -} - -fn combo_box(ui: &mut Ui, name: &str, old: T, set: impl FnOnce(T)) -where - T: StaticText + Linearize + PartialEq + Copy, -{ - combo_box_ui(ui, name, |_| (), old, set); -} - -fn combo_box_ui( - ui: &mut Ui, - name: &str, - label: impl FnOnce(&mut Ui) -> R, - mut v: T, - set: impl FnOnce(T), -) where - T: StaticText + Linearize + PartialEq + Copy, -{ - row_ui(ui, name, label, |ui| { - let old = v; - ComboBox::from_id_salt(name) - .selected_text(v.text()) - .show_ui(ui, |ui| { - for s in T::variants() { - ui.selectable_value(&mut v, s, s.text()); - } - }); - if old != v { - set(v); - } - }); -} - -fn drag_value( - ui: &mut Ui, - name: &str, - old: N, - range: RangeInclusive, - speed: f64, - set: impl FnOnce(N), -) where - N: Numeric, -{ - drag_value_ui(ui, name, |_| (), old, range, speed, set); -} - -fn drag_value_ui( - ui: &mut Ui, - name: &str, - label: impl FnOnce(&mut Ui) -> R, - mut v: N, - range: RangeInclusive, - speed: f64, - set: impl FnOnce(N), -) where - N: Numeric, -{ - row_ui(ui, name, label, |ui| { - if DragValue::new(&mut v) - .range(range) - .speed(speed) - .ui(ui) - .changed() - { - set(v); - } - }); -} - -fn label(ui: &mut Ui, name: &str, text: impl Into) { - row(ui, name, |ui| ui.label(text)); -} - -trait GridExt { - fn row(&mut self) -> impl DerefMut; -} - -impl GridExt for Ui { - fn row(&mut self) -> impl DerefMut { - GridRow { ui: self } - } -} - -struct GridRow<'a> { - ui: &'a mut Ui, -} - -impl Deref for GridRow<'_> { - type Target = Ui; - - fn deref(&self) -> &Self::Target { - self.ui - } -} - -impl DerefMut for GridRow<'_> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut *self.ui - } -} - -impl Drop for GridRow<'_> { - fn drop(&mut self) { - self.end_row(); - } -} - -impl LazyEventSourceListener for ControlCenterInner { - fn triggered(self: Rc) { - self.window.request_redraw(); - } -} diff --git a/src/control_center/cc_clients.rs b/src/control_center/cc_clients.rs deleted file mode 100644 index 75e52d67..00000000 --- a/src/control_center/cc_clients.rs +++ /dev/null @@ -1,453 +0,0 @@ -use { - crate::{ - client::{Client, ClientId}, - control_center::{ - CcBehavior, ControlCenterInner, PaneType, - cc_criterion::{CcCriterion, CritImpl, CritRegex}, - cc_window::show_window_collapsible, - grid, icon_label, label, read_only_bool, - }, - criteria::{CritMgrExt, CritUpstreamNode, crit_leaf::CritLeafMatcher}, - egui_adapter::egui_platform::icons::ICON_OPEN_IN_NEW, - state::State, - tree::{ToplevelData, ToplevelIdentifier}, - utils::{copyhashmap::CopyHashMap, static_text::StaticText}, - }, - ahash::AHashMap, - egui::{ - CollapsingHeader, DragValue, Sense, TextFormat, Ui, Widget, cache::CacheTrait, - text::LayoutJob, - }, - linearize::Linearize, - std::rc::{Rc, Weak}, -}; - -pub enum ClientCrit { - SandboxEngine(CritRegex), - SandboxAppId(CritRegex), - SandboxInstanceId(CritRegex), - Sandboxed, - Uid(i32), - Pid(i32), - IsXwayland, - Comm(CritRegex), - Exe(CritRegex), - Tag(CritRegex), -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Linearize)] -pub enum ClientCritTy { - SandboxEngine, - SandboxAppId, - SandboxInstanceId, - Sandboxed, - Uid, - Pid, - IsXwayland, - Comm, - Exe, - Tag, -} - -impl Default for ClientCrit { - fn default() -> Self { - ClientCrit::Comm(Default::default()) - } -} - -impl StaticText for ClientCritTy { - fn text(&self) -> &'static str { - match self { - ClientCritTy::SandboxEngine => "Sandbox Engine", - ClientCritTy::SandboxAppId => "Sandbox App ID", - ClientCritTy::SandboxInstanceId => "Sandbox Instance ID", - ClientCritTy::Sandboxed => "Sandboxed", - ClientCritTy::Uid => "UID", - ClientCritTy::Pid => "PID", - ClientCritTy::IsXwayland => "Is Xwayland", - ClientCritTy::Comm => "Comm", - ClientCritTy::Exe => "Exe", - ClientCritTy::Tag => "Tag", - } - } -} - -impl CritImpl for ClientCrit { - type Type = ClientCritTy; - type Target = Rc; - - fn ty(&self) -> Self::Type { - macro_rules! map { - ($($n:ident,)*) => { - match self { - $( - Self::$n { .. } => ClientCritTy::$n, - )* - } - }; - } - map! { - SandboxEngine, - SandboxAppId, - SandboxInstanceId, - Sandboxed, - Uid, - Pid, - IsXwayland, - Comm, - Exe, - Tag, - } - } - - fn from_ty(ty: Self::Type) -> Self { - match ty { - ClientCritTy::SandboxEngine => Self::SandboxEngine(Default::default()), - ClientCritTy::SandboxAppId => Self::SandboxAppId(Default::default()), - ClientCritTy::SandboxInstanceId => Self::SandboxInstanceId(Default::default()), - ClientCritTy::Sandboxed => Self::Sandboxed, - ClientCritTy::Uid => Self::Uid(Default::default()), - ClientCritTy::Pid => Self::Pid(Default::default()), - ClientCritTy::IsXwayland => Self::IsXwayland, - ClientCritTy::Comm => Self::Comm(Default::default()), - ClientCritTy::Exe => Self::Exe(Default::default()), - ClientCritTy::Tag => Self::Tag(Default::default()), - } - } - - fn show(&mut self, ui: &mut Ui) -> bool { - match self { - ClientCrit::SandboxEngine(v) => v.show(ui), - ClientCrit::SandboxAppId(v) => v.show(ui), - ClientCrit::SandboxInstanceId(v) => v.show(ui), - ClientCrit::Sandboxed => false, - ClientCrit::Uid(v) => DragValue::new(v).ui(ui).changed(), - ClientCrit::Pid(v) => DragValue::new(v).ui(ui).changed(), - ClientCrit::IsXwayland => false, - ClientCrit::Comm(v) => v.show(ui), - ClientCrit::Exe(v) => v.show(ui), - ClientCrit::Tag(v) => v.show(ui), - } - } - - fn to_crit(&self, state: &Rc) -> Option>> { - let m = &state.cl_matcher_manager; - let res = match self { - ClientCrit::SandboxEngine(v) => m.sandbox_engine(v.to_crit()?), - ClientCrit::SandboxAppId(v) => m.sandbox_app_id(v.to_crit()?), - ClientCrit::SandboxInstanceId(v) => m.sandbox_instance_id(v.to_crit()?), - ClientCrit::Sandboxed => m.sandboxed(), - ClientCrit::Uid(v) => m.uid(*v), - ClientCrit::Pid(v) => m.pid(*v), - ClientCrit::IsXwayland => m.is_xwayland(), - ClientCrit::Comm(v) => m.comm(v.to_crit()?), - ClientCrit::Exe(v) => m.exe(v.to_crit()?), - ClientCrit::Tag(v) => m.tag(v.to_crit()?), - }; - Some(res) - } - - fn not( - state: &State, - upstream: &Rc>, - ) -> Rc> { - state.cl_matcher_manager.not(upstream) - } - - fn list( - state: &State, - upstream: &[Rc>], - all: bool, - ) -> Rc> { - state.cl_matcher_manager.list(upstream, all) - } - - fn exactly( - state: &State, - n: usize, - upstream: &[Rc>], - ) -> Rc> { - state.cl_matcher_manager.exactly(upstream, n) - } -} - -pub struct ClientsPane { - state: Rc, - filter: bool, - criterion: CcCriterion, - matched: Rc, - leaf: Option>>>, -} - -struct Matched { - slf: Weak, - clients: CopyHashMap, -} - -impl Matched { - fn request_frame(&self) { - if let Some(slf) = self.slf.upgrade() { - slf.window.request_redraw(); - } - } -} - -impl ControlCenterInner { - pub fn create_clients_pane(self: &Rc) -> ClientsPane { - let mut pane = ClientsPane { - state: self.state.clone(), - filter: false, - criterion: Default::default(), - matched: Rc::new(Matched { - slf: Rc::downgrade(self), - clients: Default::default(), - }), - leaf: Default::default(), - }; - pane.update_matcher(); - pane - } -} - -impl ClientsPane { - pub fn title(&self, res: &mut String) { - res.push_str("Clients"); - } - - pub fn show(&mut self, behavior: &mut CcBehavior<'_>, ui: &mut Ui) { - if ui.checkbox(&mut self.filter, "Filter").changed() && !self.filter { - self.criterion = Default::default(); - self.update_matcher(); - } - let mut clear_clients = false; - if self.filter && self.criterion.show(ui) { - clear_clients = self.update_matcher(); - } - ui.separator(); - let mut clients: Vec<_> = self.matched.clients.lock().keys().copied().collect(); - clients.sort(); - for id in clients { - let Ok(client) = self.state.clients.get(id) else { - continue; - }; - show_client_collapsible(behavior, ui, &client); - } - if clear_clients { - self.matched.clients.clear(); - } - } - - fn update_matcher(&mut self) -> bool { - let mut clear_clients = false; - let state = &self.state; - if let Some(new) = self.criterion.to_crit(state) { - clear_clients = true; - let matched = self.matched.clone(); - let leaf = state.cl_matcher_manager.leaf(&new, move |data| { - matched.clients.set(data, ()); - matched.request_frame(); - Box::new({ - let matched = matched.clone(); - move || { - matched.clients.remove(&data); - matched.request_frame(); - } - }) - }); - state.cl_matcher_manager.rematch_all(state); - self.leaf = Some(leaf); - } - clear_clients - } -} - -pub struct ClientPane { - client: Rc, -} - -impl ControlCenterInner { - pub fn create_client_pane(self: &Rc, client: &Rc) -> ClientPane { - ClientPane { - client: client.clone(), - } - } -} - -impl ClientPane { - pub fn title(&self, res: &mut String) { - res.push_str("Client "); - res.push_str(&self.client.pid_info.comm); - } - - pub fn show(&mut self, behavior: &mut CcBehavior<'_>, ui: &mut Ui) { - show_client(behavior, ui, &self.client); - } -} - -pub fn show_client_collapsible(behavior: &mut CcBehavior, ui: &mut Ui, client: &Rc) { - let mut layout_job = LayoutJob::default(); - layout_job.append( - "Client", - 0.0, - TextFormat { - color: ui.style().visuals.widgets.inactive.text_color(), - ..Default::default() - }, - ); - layout_job.append( - &client.id.to_string(), - 10.0, - TextFormat { - color: ui.style().visuals.widgets.active.text_color(), - ..Default::default() - }, - ); - layout_job.append( - &client.pid_info.comm, - 10.0, - TextFormat { - color: ui.style().visuals.widgets.inactive.text_color(), - ..Default::default() - }, - ); - CollapsingHeader::new(layout_job) - .id_salt(("client", client.id)) - .show(ui, |ui| { - if icon_label(ICON_OPEN_IN_NEW) - .sense(Sense::CLICK) - .ui(ui) - .clicked() - { - behavior.open = Some(PaneType::Client(behavior.cc.create_client_pane(client))); - } - show_client(behavior, ui, client) - }); -} - -pub fn show_client(behavior: &mut CcBehavior<'_>, ui: &mut Ui, client: &Client) { - grid(ui, ("client", client.id), |ui| { - label(ui, "ID", client.id.to_string()); - label(ui, "PID", client.pid_info.pid.to_string()); - label(ui, "UID", client.pid_info.uid.to_string()); - label(ui, "comm", &client.pid_info.comm); - label(ui, "exe", &client.pid_info.exe); - if client.acceptor.sandboxed { - read_only_bool(ui, "Sandboxed", true); - } - if client.acceptor.secure { - read_only_bool(ui, "Secure", true); - } - if client.is_xwayland { - read_only_bool(ui, "Xwayland", true); - } - if let Some(v) = &client.acceptor.sandbox_engine { - label(ui, "Sandbox Engine", v); - } - if let Some(v) = &client.acceptor.app_id { - label(ui, "App ID", v); - } - if let Some(v) = &client.acceptor.instance_id { - label(ui, "Instance ID", v); - } - if let Some(v) = &client.acceptor.tag { - label(ui, "Tag", v); - } - }); - if ui.button("Kill").clicked() { - client.state.clients.kill(client.id); - } - ui.collapsing("Capabilities", |ui| { - ui.add_enabled_ui(false, |ui| { - for (k, v) in client.effective_caps.get().to_map() { - if v { - ui.checkbox(&mut true, k.text()); - } - } - }); - }); - ui.collapsing("Windows", |ui| { - let matcher = ui.memory_mut(|m| { - m.caches - .cache::() - .get(behavior.cc, client.id) - .clone() - }); - let mut windows: Vec<_> = matcher.windows.lock().keys().copied().collect(); - windows.sort(); - for id in windows { - let Some(window) = client.state.toplevels.get(&id).and_then(|v| v.upgrade()) else { - continue; - }; - show_window_collapsible(behavior, ui, &window); - } - }); -} - -#[derive(Default)] -struct ClientWindowMatchersCache { - generation: u64, - matchers: AHashMap, -} - -struct CachedWindowMatcher { - generation: u64, - _matcher: Rc>, - matchers: Rc, -} - -struct WindowMatchers { - cc: Weak, - windows: CopyHashMap, -} - -impl ClientWindowMatchersCache { - fn get(&mut self, cc: &Rc, id: ClientId) -> &Rc { - let res = self.matchers.entry(id).or_insert_with(|| { - let state = &cc.state; - let node = state.cl_matcher_manager.id(id); - let node = state.tl_matcher_manager.client(state, &node); - let matchers = Rc::new(WindowMatchers { - cc: Rc::downgrade(&cc), - windows: Default::default(), - }); - let matchers2 = matchers.clone(); - let matcher = state.tl_matcher_manager.leaf(&node, move |id| { - matchers2.windows.set(id, ()); - if let Some(cc) = matchers2.cc.upgrade() { - cc.window.request_redraw(); - } - let matchers2 = matchers2.clone(); - Box::new(move || { - matchers2.windows.remove(&id); - if let Some(cc) = matchers2.cc.upgrade() { - cc.window.request_redraw(); - } - }) - }); - let res = CachedWindowMatcher { - generation: 0, - _matcher: matcher, - matchers, - }; - state.cl_matcher_manager.rematch_all(state); - state.tl_matcher_manager.rematch_all(state); - res - }); - res.generation = self.generation; - &res.matchers - } -} - -unsafe impl Sync for ClientWindowMatchersCache {} -unsafe impl Send for ClientWindowMatchersCache {} - -impl CacheTrait for ClientWindowMatchersCache { - fn update(&mut self) { - self.matchers.retain(|_, m| m.generation == self.generation); - self.generation += 1; - } - - fn len(&self) -> usize { - self.matchers.len() - } -} diff --git a/src/control_center/cc_color_management.rs b/src/control_center/cc_color_management.rs deleted file mode 100644 index c4926081..00000000 --- a/src/control_center/cc_color_management.rs +++ /dev/null @@ -1,36 +0,0 @@ -use { - crate::{ - control_center::{ControlCenterInner, bool, grid, read_only_bool}, - state::State, - }, - egui::Ui, - std::rc::Rc, -}; - -pub struct ColorManagementPane { - state: Rc, -} - -impl ControlCenterInner { - pub fn create_color_management_pane(self: &Rc) -> ColorManagementPane { - ColorManagementPane { - state: self.state.clone(), - } - } -} - -impl ColorManagementPane { - pub fn title(&self, res: &mut String) { - res.push_str("Color Management"); - } - - pub fn show(&mut self, ui: &mut Ui) { - let s = &self.state; - grid(ui, "settings", |ui| { - bool(ui, "Enabled", s.color_management_enabled.get(), |b| { - s.set_color_management_enabled(b); - }); - read_only_bool(ui, "Available", s.color_management_available()); - }); - } -} diff --git a/src/control_center/cc_compositor.rs b/src/control_center/cc_compositor.rs deleted file mode 100644 index 5091b379..00000000 --- a/src/control_center/cc_compositor.rs +++ /dev/null @@ -1,88 +0,0 @@ -use { - crate::{ - compositor::{LIBEI_SOCKET, WAYLAND_DISPLAY}, - control_center::{ControlCenterInner, bool, combo_box, grid, label, row}, - state::State, - version::VERSION, - }, - egui::{DragValue, OpenUrl, Ui, Widget}, - std::rc::Rc, -}; - -pub struct CompositorPane { - state: Rc, - switch_to_vt: u32, -} - -impl ControlCenterInner { - pub fn create_compositor_pane(self: &Rc) -> CompositorPane { - CompositorPane { - state: self.state.clone(), - switch_to_vt: 1, - } - } -} - -impl CompositorPane { - pub fn title(&self, res: &mut String) { - res.push_str("Compositor"); - } - - pub fn show(&mut self, ui: &mut Ui) { - let s = &self.state; - grid(ui, "compositor", |ui| { - row(ui, "Repository", |ui| { - let url = "https://github.com/mahkoh/jay"; - if ui.link(url).clicked() { - ui.open_url(OpenUrl::new_tab(url)); - } - }); - label(ui, "Version", VERSION); - label(ui, "PID", s.pid.to_string()); - if let Some(acceptor) = s.acceptor.get() { - label(ui, WAYLAND_DISPLAY, acceptor.socket_name()); - } - if let Some(dir) = &s.config_dir { - label(ui, "Config DIR", dir); - } - bool(ui, "Libei Socket", s.enable_ei_acceptor.get(), |v| { - s.set_ei_socket_enabled(v); - }); - if let Some(a) = s.ei_acceptor.get() { - label(ui, LIBEI_SOCKET, a.socket_name()); - } - combo_box( - ui, - "Workspace Display Order", - s.workspace_display_order.get(), - |o| s.set_workspace_display_order(o), - ); - if let Some(logger) = &s.logger { - combo_box(ui, "Log Level", logger.level(), |l| s.set_log_level(l)); - row(ui, "Log File", |ui| { - let path = logger.path().to_string(); - if ui - .link(&path) - .on_hover_text_at_pointer("Copy to clipboard") - .clicked() - { - ui.copy_text(path); - } - }); - } - }); - if ui.button("Quit").clicked() { - s.quit(); - } - if ui.button("Reload Config").clicked() { - s.reload_config(); - } - ui.horizontal(|ui| { - let button = ui.button("Switch to VT"); - DragValue::new(&mut self.switch_to_vt).ui(ui); - if button.clicked() { - s.backend.get().switch_to(self.switch_to_vt); - } - }); - } -} diff --git a/src/control_center/cc_criterion.rs b/src/control_center/cc_criterion.rs deleted file mode 100644 index ed37aa8a..00000000 --- a/src/control_center/cc_criterion.rs +++ /dev/null @@ -1,253 +0,0 @@ -use { - crate::{ - criteria::{CritLiteralOrRegex, CritUpstreamNode}, - egui_adapter::egui_platform::icons::ICON_CLOSE, - state::State, - utils::{numcell::NumCell, static_text::StaticText}, - }, - ahash::AHashSet, - egui::{ComboBox, DragValue, Ui, UiBuilder, Widget}, - isnt::std_1::collections::IsntHashSetExt, - linearize::{Linearize, LinearizeExt}, - regex::Regex, - std::rc::Rc, -}; - -pub enum CcCriterion { - Not(Box), - List(Vec, bool), - Exactly(usize, Vec), - T(T), -} - -impl Default for CcCriterion -where - T: Default, -{ - fn default() -> Self { - Self::T(T::default()) - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Linearize)] -enum CompoundCritTy { - Not, - All, - Any, - Exactly, -} - -#[derive(Copy, Clone, Eq, PartialEq)] -enum CritTy { - Compound(CompoundCritTy), - T(T), -} - -impl StaticText for CompoundCritTy { - fn text(&self) -> &'static str { - match self { - Self::Not => "Not", - Self::All => "All", - Self::Any => "Any", - Self::Exactly => "Exactly", - } - } -} - -impl StaticText for CritTy -where - T: StaticText, -{ - fn text(&self) -> &'static str { - match self { - Self::Compound(t) => t.text(), - Self::T(t) => t.text(), - } - } -} - -pub trait CritImpl: Default { - type Type: Copy + Eq + PartialEq + StaticText + Linearize; - type Target; - - fn ty(&self) -> Self::Type; - fn from_ty(ty: Self::Type) -> Self; - #[must_use] - fn show(&mut self, ui: &mut Ui) -> bool; - - fn to_crit(&self, state: &Rc) -> Option>>; - fn not( - state: &State, - upstream: &Rc>, - ) -> Rc>; - fn list( - state: &State, - upstream: &[Rc>], - all: bool, - ) -> Rc>; - fn exactly( - state: &State, - n: usize, - upstream: &[Rc>], - ) -> Rc>; -} - -impl CcCriterion -where - T: CritImpl, -{ - #[must_use] - pub fn show(&mut self, ui: &mut Ui) -> bool { - let mut changed = false; - ui.vertical(|ui| { - ui.horizontal(|ui| { - let mut v = self.ty(); - let old = v; - ComboBox::from_id_salt("ty") - .selected_text(v.text()) - .show_ui(ui, |ui| { - for s in CompoundCritTy::variants() { - ui.selectable_value(&mut v, CritTy::Compound(s), s.text()); - } - for s in T::Type::variants() { - ui.selectable_value(&mut v, CritTy::T(s), s.text()); - } - }); - if old != v { - *self = match v { - CritTy::Compound(CompoundCritTy::Not) => { - CcCriterion::Not(Default::default()) - } - CritTy::Compound(CompoundCritTy::All) => { - CcCriterion::List(Default::default(), true) - } - CritTy::Compound(CompoundCritTy::Any) => { - CcCriterion::List(Default::default(), false) - } - CritTy::Compound(CompoundCritTy::Exactly) => { - CcCriterion::Exactly(1, Default::default()) - } - CritTy::T(t) => CcCriterion::T(T::from_ty(t)), - }; - changed = true; - } - match self { - CcCriterion::Not(n) => changed |= n.show(ui), - CcCriterion::List(_, _) => {} - CcCriterion::Exactly(n, _) => { - changed |= DragValue::new(n).ui(ui).changed(); - } - CcCriterion::T(t) => changed |= t.show(ui), - } - }); - match self { - CcCriterion::Not(_) => {} - CcCriterion::List(v, _) | CcCriterion::Exactly(_, v) => { - ui.indent("compound", |ui| { - let mut to_remove = AHashSet::new(); - for (idx, v) in v.iter_mut().enumerate() { - ui.horizontal(|ui| { - if ui.button(ICON_CLOSE).clicked() { - changed = true; - to_remove.insert(idx); - } - ui.scope_builder(UiBuilder::new().id_salt(idx), |ui| { - changed |= v.show(ui); - }); - }); - } - let i = NumCell::new(0); - v.retain(|_| to_remove.not_contains(&i.fetch_add(1))); - if ui.button("Add").clicked() { - v.push(CcCriterion::default()); - changed = true; - } - }); - } - CcCriterion::T(_) => {} - } - }); - changed - } - - fn ty(&self) -> CritTy { - match self { - CcCriterion::Not(_) => CritTy::Compound(CompoundCritTy::Not), - CcCriterion::List(_, true) => CritTy::Compound(CompoundCritTy::All), - CcCriterion::List(_, false) => CritTy::Compound(CompoundCritTy::Any), - CcCriterion::Exactly(_, _) => CritTy::Compound(CompoundCritTy::Exactly), - CcCriterion::T(t) => CritTy::T(t.ty()), - } - } - - pub fn to_crit(&self, state: &Rc) -> Option>> { - match self { - CcCriterion::Not(t) => Some(T::not(state, &t.to_crit(state)?)), - CcCriterion::List(v, all) => { - let mut upstream = Vec::with_capacity(v.len()); - for v in v { - upstream.push(v.to_crit(state)?); - } - Some(T::list(state, &upstream, *all)) - } - CcCriterion::Exactly(n, v) => { - let mut upstream = Vec::with_capacity(v.len()); - for v in v { - upstream.push(v.to_crit(state)?); - } - Some(T::exactly(state, *n, &upstream)) - } - CcCriterion::T(t) => t.to_crit(state), - } - } - - pub fn any(&self, mut any: impl FnMut(&T) -> bool) -> bool { - self.any_(&mut any) - } - - fn any_(&self, any: &mut impl FnMut(&T) -> bool) -> bool { - match self { - CcCriterion::Not(v) => v.any_(any), - CcCriterion::List(v, _) => v.iter().any(|v| v.any_(any)), - CcCriterion::Exactly(_, v) => v.iter().any(|v| v.any_(any)), - CcCriterion::T(t) => any(t), - } - } -} - -pub struct CritRegex { - pub text: String, - pub regex: Option>, -} - -impl Default for CritRegex { - fn default() -> Self { - Self { - text: Default::default(), - regex: Some(Some(Regex::new("").unwrap())), - } - } -} - -impl CritRegex { - pub fn show(&mut self, ui: &mut Ui) -> bool { - let mut is_regex = self.regex.is_some(); - let mut changed = false; - changed |= ui.text_edit_singleline(&mut self.text).changed(); - changed |= ui.checkbox(&mut is_regex, "Regex").changed(); - if changed { - self.regex = is_regex.then(|| Regex::new(&self.text).ok()); - } - if let Some(None) = self.regex { - ui.label("Error: Invalid regex"); - } - changed - } - - pub fn to_crit(&self) -> Option { - match &self.regex { - None => Some(CritLiteralOrRegex::Literal(self.text.clone())), - Some(v) => Some(CritLiteralOrRegex::Regex(v.clone()?)), - } - } -} diff --git a/src/control_center/cc_gpus.rs b/src/control_center/cc_gpus.rs deleted file mode 100644 index 38beffe6..00000000 --- a/src/control_center/cc_gpus.rs +++ /dev/null @@ -1,146 +0,0 @@ -use { - crate::{ - control_center::{ - ControlCenterInner, GridExt, bool, combo_box, grid, grid_label, label, row, - }, - egui_adapter::egui_platform::icons::{ICON_ADD, ICON_REMOVE}, - state::{DrmDevData, State}, - }, - egui::{Checkbox, CollapsingHeader, DragValue, TextFormat, Ui, Widget, text::LayoutJob}, - std::rc::Rc, -}; - -pub struct GpusPane { - state: Rc, -} - -impl ControlCenterInner { - pub fn create_gpus_pane(self: &Rc) -> GpusPane { - GpusPane { - state: self.state.clone(), - } - } -} - -impl GpusPane { - pub fn title(&self, res: &mut String) { - res.push_str("GPUs"); - } - - pub fn show(&mut self, ui: &mut Ui) { - let devs = self.state.drm_devs.lock(); - let mut devs: Vec<_> = devs.iter().collect(); - devs.sort_by_key(|d| d.0); - for dev in devs { - self.show_dev(ui, dev.1); - } - } - - fn show_dev(&self, ui: &mut Ui, dev: &DrmDevData) { - let title_buf; - let title = match dev.devnode.as_deref() { - Some(t) => t, - _ => { - let dev_t = dev.dev.dev_t(); - title_buf = format!("{}:{}", uapi::major(dev_t), uapi::minor(dev_t)); - &title_buf - } - }; - let mut layout_job = LayoutJob::default(); - layout_job.append( - title, - 0.0, - TextFormat { - color: ui.style().visuals.widgets.active.text_color(), - ..Default::default() - }, - ); - if let Some(model) = &dev.model { - layout_job.append( - model, - 10.0, - TextFormat { - color: ui.style().visuals.widgets.inactive.text_color(), - ..Default::default() - }, - ); - } - ui.collapsing(layout_job, |ui| { - grid(ui, ("settings", dev.dev.id()), |ui| { - macro_rules! string { - ($field:ident, $name:expr) => { - if let Some(v) = &dev.$field { - label(ui, $name, v); - } - }; - } - string!(vendor, "Vendor"); - string!(model, "Model"); - string!(devnode, "Devnode"); - string!(syspath, "Syspath"); - if let Some(v) = dev.pci_id { - label(ui, "PCI ID", format!("{:x}:{:x}", v.vendor, v.model)); - } - { - let v = dev.dev.dev_t(); - label(ui, "Dev", format!("{}:{}", uapi::major(v), uapi::minor(v))); - } - combo_box(ui, "API", dev.dev.gtx_api(), |v| dev.dev.set_gfx_api(v)); - row(ui, "Primary Device", |ui| { - let mut v = dev.dev.is_render_device(); - let old = v; - ui.add_enabled(!v, Checkbox::without_text(&mut v)); - if v != old { - dev.dev.make_render_device(); - } - }); - bool( - ui, - "Direct Scanout", - dev.dev.direct_scanout_enabled(), - |v| dev.set_direct_scanout_enabled(&self.state, v), - ); - if let Some(mut v) = dev.dev.flip_margin() { - let ui = &mut *ui.row(); - grid_label(ui, "Flip Margin"); - let old = v; - let denom = 1_000_000.0; - ui.horizontal(|ui| { - let mut s = v as f64 / denom; - let res = DragValue::new(&mut s) - .range(0.0..=50.0) - .speed(0.1) - .fixed_decimals(1) - .ui(ui); - if res.changed() { - v = (s * denom) as u64; - } - if ui.button(ICON_REMOVE).clicked() { - v = v.saturating_sub(100_000); - } - if ui.button(ICON_ADD).clicked() { - v += 100_000; - } - }); - if old != v { - dev.set_flip_margin(&self.state, v); - } - } - }); - CollapsingHeader::new("Connectors") - .default_open(true) - .show(ui, |ui| { - let mut cs: Vec<_> = dev - .connectors - .lock() - .values() - .map(|v| v.name.clone()) - .collect::>(); - cs.sort(); - for c in cs { - ui.label(&**c); - } - }); - }); - } -} diff --git a/src/control_center/cc_idle.rs b/src/control_center/cc_idle.rs deleted file mode 100644 index 2520463f..00000000 --- a/src/control_center/cc_idle.rs +++ /dev/null @@ -1,72 +0,0 @@ -use { - crate::{ - control_center::{ControlCenterInner, grid, row}, - state::State, - }, - egui::{CollapsingHeader, DragValue, Ui, Widget}, - std::{rc::Rc, time::Duration}, -}; - -pub struct IdlePane { - state: Rc, -} - -impl ControlCenterInner { - pub fn create_idle_pane(self: &Rc) -> IdlePane { - IdlePane { - state: self.state.clone(), - } - } -} - -impl IdlePane { - pub fn title(&self, res: &mut String) { - res.push_str("Idle"); - } - - pub fn show(&mut self, ui: &mut Ui) { - grid(ui, "sliders", |ui| { - for interval in [true, false] { - let label = match interval { - true => "Interval", - false => "Grace period", - }; - let idle = &self.state.idle; - let field = match interval { - true => &idle.timeout, - false => &idle.grace_period, - }; - row(ui, label, |ui| { - let secs = field.get().as_secs(); - let mut minutes = secs / 60; - let mut seconds = secs % 60; - let mut changed = false; - changed |= DragValue::new(&mut minutes).ui(ui).changed(); - ui.label("minutes"); - changed |= DragValue::new(&mut seconds).range(0..=59).ui(ui).changed(); - ui.label("seconds"); - if changed { - let duration = - Duration::from_secs(minutes.saturating_mul(60).saturating_add(seconds)); - match interval { - true => idle.set_timeout(&self.state, duration), - false => idle.set_grace_period(&self.state, duration), - } - } - }); - } - }); - let inhibitors = self.state.idle.inhibitors.lock(); - let mut is: Vec<_> = inhibitors.values().collect(); - is.sort_by_key(|is| is.inhibit_id); - CollapsingHeader::new(format!("Inhibitors ({})", is.len())) - .id_salt("Inhibitors") - .show(ui, |ui| { - for i in is { - ui.horizontal(|ui| { - ui.label(&i.client.pid_info.comm); - }); - } - }); - } -} diff --git a/src/control_center/cc_input.rs b/src/control_center/cc_input.rs deleted file mode 100644 index 6359e937..00000000 --- a/src/control_center/cc_input.rs +++ /dev/null @@ -1,685 +0,0 @@ -use { - crate::{ - backend::{InputDeviceCapability, InputDeviceId}, - control_center::{ - ControlCenterInner, GridExt, PaneState, bool, bool_ui, combo_box, combo_box_ui, - drag_value, drag_value_ui, grid, grid_label, grid_label_ui, label, text_edit, tip, - }, - egui_adapter::egui_platform::icons::ICON_PENDING, - ifs::{ - wl_output::WlOutputGlobal, - wl_seat::{SeatId, WlSeatGlobal}, - }, - kbvm::KbvmMap, - state::{DeviceHandlerData, State}, - utils::{errorfmt::ErrorFmt, static_text::StaticText}, - }, - ahash::AHashMap, - egui::{ - CollapsingHeader, ComboBox, DragValue, Event, Grid, Id, TextBuffer, TextFormat, Ui, - UiBuilder, ViewportCommand, Widget, emath::Numeric, text::LayoutJob, - }, - isnt::std_1::string::IsntStringExt, - jay_config::keyboard::syms::KeySym, - kbvm::Keysym, - linearize::LinearizeExt, - rand::random, - std::{mem, rc::Rc}, -}; - -pub struct InputPane { - state: Rc, - paste_requested: Option, - keymaps: AHashMap, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -enum Key { - Seat(SeatId), - Dev(InputDeviceId), -} - -struct KeymapState { - seed: u64, - rules_default: bool, - rules: String, - model_default: bool, - model: String, - layouts: String, - variants: String, - options: String, - backup: Option>, - pointer_revert_key: Keysym, - pointer_revert_key_str: Option, - unknown_pointer_revert_key: bool, -} - -impl Default for KeymapState { - fn default() -> Self { - Self { - seed: random(), - rules_default: true, - rules: Default::default(), - model_default: true, - model: Default::default(), - layouts: Default::default(), - variants: Default::default(), - options: Default::default(), - backup: Default::default(), - pointer_revert_key: Default::default(), - pointer_revert_key_str: None, - unknown_pointer_revert_key: false, - } - } -} - -impl ControlCenterInner { - pub fn create_input_pane(self: &Rc) -> InputPane { - InputPane { - state: self.state.clone(), - paste_requested: Default::default(), - keymaps: Default::default(), - } - } -} - -impl InputPane { - pub fn title(&self, res: &mut String) { - res.push_str("Input"); - } - - pub fn show(&mut self, ps: &mut PaneState, ui: &mut Ui) { - let state = self.state.clone(); - let seats = state.globals.seats.lock(); - let mut seats: Vec<_> = seats.values().collect(); - seats.sort_by_key(|d| d.seat_name()); - for seat in &seats { - self.show_seat(ps, ui, seat); - } - let outputs = state.globals.outputs.lock(); - let mut outputs: Vec<_> = outputs.values().collect(); - outputs.sort_by_key(|o| &o.connector.name); - let dev = &*state.input_device_handlers.borrow(); - let mut dev: Vec<_> = dev.values().collect(); - dev.sort_by_key(|d| d.data.device.name()); - for dev in dev { - self.show_device(ps, ui, &dev.data, &seats, &outputs); - } - } - - fn show_seat(&mut self, ps: &mut PaneState, ui: &mut Ui, seat: &Rc) { - let mut layout_job = LayoutJob::default(); - layout_job.append( - "Seat", - 0.0, - TextFormat { - color: ui.style().visuals.widgets.inactive.text_color(), - ..Default::default() - }, - ); - layout_job.append( - seat.seat_name(), - 10.0, - TextFormat { - color: ui.style().visuals.widgets.active.text_color(), - ..Default::default() - }, - ); - let ks = self.keymaps.entry(Key::Seat(seat.id())).or_default(); - CollapsingHeader::new(layout_job) - .id_salt(("seat", seat.id())) - .show(ui, |ui| { - grid(ui, ("seat", seat.id()), |ui| { - let mut dv = |name: &str, get: &dyn Fn(&mut (i32, i32)) -> &mut i32| { - let ui = &mut *ui.row(); - grid_label(ui, name); - let mut v = seat.get_rate(); - let old = v; - ui.horizontal(|ui| { - let v = get(&mut v); - DragValue::new(v).range(0..=i32::MAX).ui(ui); - if ui.button("-20").clicked() { - *v = v.saturating_sub(20).max(0) - } - if ui.button("+20").clicked() { - *v = v.saturating_add(20); - } - }); - if v != old { - seat.set_rate(v.0, v.1); - } - }; - dv("Repeat Rate", &|v| &mut v.0); - dv("Repeat Delay", &|v| &mut v.1); - drag_value( - ui, - "Cursor Size", - seat.cursor_group().cursor_size(), - 0..=u32::MAX, - 1.0, - |v| seat.cursor_group().set_cursor_size(v), - ); - bool_ui( - ui, - "Simple IM", - |ui| { - tip(ui, |ui| { - ui.label("A simple input method based on Xcompose files."); - ui.label(concat!( - "If you're not using another input method, you should ", - "leave this enabled as it will work for sandboxed ", - "applications, which regular Xcompose will not.", - )); - ui.label(concat!( - "The `enable-unicode-input` action can be used to input ", - "characters by their unicode value.", - )); - }); - }, - seat.simple_im_enabled(), - |b| seat.set_simple_im_enabled(b), - ); - bool_ui( - ui, - "Hardware Cursor", - |ui| { - tip(ui, |ui| { - ui.label( - "Allow this seat to use the hardware cursor, if available.", - ); - ui.label("Only one seat can use the hardware cursor at a time."); - }); - }, - seat.cursor_group().hardware_cursor(), - |b| seat.cursor_group().set_hardware_cursor(b), - ); - { - let ui = &mut *ui.row(); - let v = seat.pointer_revert_key(); - let v = Keysym(v.0); - if mem::replace(&mut ks.pointer_revert_key, v) != v { - ks.pointer_revert_key_str = None; - } - let name = ks - .pointer_revert_key_str - .get_or_insert_with(|| v.name().unwrap_or_default().to_string()); - grid_label_ui(ui, |ui| { - ui.label("Pointer Revert Key"); - tip(ui, |ui| { - ui.label(concat!( - "Pressing this key reverts the pointer to the default state, ", - "breaking grabs, drags, etc.", - )); - ui.label( - "Setting this to `NoSymbol` effectively disables this feature.", - ); - }); - }); - ui.horizontal(|ui| { - if ui.text_edit_singleline(name).changed() { - let v = Keysym::from_str(name); - ks.unknown_pointer_revert_key = v.is_none(); - if let Some(v) = v { - ks.pointer_revert_key = v; - seat.set_pointer_revert_key(KeySym(v.0)); - } - } - if ks.unknown_pointer_revert_key { - ui.label("Error: Unknown key"); - } - }); - } - bool(ui, "Focus Follows Mouse", seat.focus_follows_mouse(), |v| { - seat.set_focus_follows_mouse(v); - }); - bool(ui, "Mouse Follows Focus", seat.mouse_follows_focus(), |v| { - seat.set_mouse_follows_focus(v); - }); - combo_box_ui( - ui, - "Fallback Output Mode", - |ui| { - tip(ui, |ui| { - ui.label(concat!( - "This determines the output to use in operations where no ", - "output is explicitly specified.", - )); - ui.label(concat!( - "For example, when a new window is opened, this determines ", - "where the window will be opened.", - )); - ui.label("`Cursor` refers to the output that contains the cursor."); - ui.label( - "`Focus` refers to the output that has the keyboard focus.", - ); - }); - }, - seat.fallback_output_mode(), - |v| seat.set_fallback_output_mode(v), - ); - }); - ui.label("Focus History"); - ui.indent("focus-history", |ui| { - let mut v = seat.focus_history_visible(); - if ui.checkbox(&mut v, "Only Visible").changed() { - seat.focus_history_set_visible(v); - } - let mut v = seat.focus_history_same_workspace(); - if ui.checkbox(&mut v, "Same Workspace").changed() { - seat.focus_history_set_same_workspace(v); - } - }); - if ui.button("Reload Simple IM").clicked() { - seat.reload_simple_im(); - } - show_keymap( - &self.state, - ps, - &mut self.paste_requested, - ks, - ui, - Some(&seat.keymap()), - |m| seat.set_seat_keymap(m), - ); - }); - } - - fn show_device( - &mut self, - ps: &mut PaneState, - ui: &mut Ui, - dev: &Rc, - seats: &[&Rc], - outputs: &[&Rc], - ) { - let mut layout_job = LayoutJob::default(); - layout_job.append( - "Device", - 0.0, - TextFormat { - color: ui.style().visuals.widgets.inactive.text_color(), - ..Default::default() - }, - ); - layout_job.append( - &dev.device.name(), - 10.0, - TextFormat { - color: ui.style().visuals.widgets.active.text_color(), - ..Default::default() - }, - ); - let dev_id = dev.device.id(); - CollapsingHeader::new(layout_job) - .id_salt(("device", dev_id)) - .show(ui, |ui| { - grid(ui, ("device", dev_id), |ui| { - { - let old = dev.seat.get(); - let ui = &mut *ui.row(); - grid_label(ui, "Seat"); - let mut seat = old.as_ref(); - ui.horizontal(|ui| { - let mut cb = ComboBox::from_id_salt("seat"); - if let Some(seat) = seat { - cb = cb.selected_text(seat.seat_name()); - } - cb.show_ui(ui, |ui| { - for s in seats { - ui.selectable_value(&mut seat, Some(s), s.seat_name()); - } - }); - if ui.button("Detach").clicked() { - seat = None; - } - }); - if seat != old.as_ref() { - dev.set_seat(&self.state, seat.cloned()); - } - } - macro_rules! string { - ($field:ident, $name:expr) => { - if let Some(v) = &dev.$field { - label(ui, $name, v); - } - }; - } - string!(syspath, "Syspath"); - string!(devnode, "Devnode"); - { - let ui = &mut *ui.row(); - grid_label(ui, "Capabilities"); - let mut s = String::new(); - for cap in InputDeviceCapability::variants() { - if dev.device.has_capability(cap) { - if s.is_not_empty() { - s.push_str(" | "); - } - s.push_str(cap.text()); - } - } - ui.label(s); - } - if let Some(old) = dev.device.natural_scrolling_enabled() { - bool(ui, "Natural Scrolling", old, |v| { - dev.set_natural_scrolling_enabled(&self.state, v) - }); - } - if dev.device.has_capability(InputDeviceCapability::Pointer) { - drag_value_ui( - ui, - "Scroll Distance (px)", - |ui| { - tip(ui, |ui| { - ui.label(concat!( - "This only applies to applications that use the ", - "legacy px scrolling events.", - )); - }); - }, - dev.px_per_scroll_wheel.get(), - -f64::INFINITY..=f64::INFINITY, - 0.1, - |v| dev.set_px_per_scroll_wheel(&self.state, v), - ); - } - if let Some(old) = dev.device.accel_profile() { - combo_box(ui, "Accel Profile", old, |v| { - dev.set_accel_profile(&self.state, v) - }); - } - if let Some(old) = dev.device.accel_speed() { - drag_value(ui, "Accel Speed", old, -1.0..=1.0, 0.01, |v| { - dev.set_accel_speed(&self.state, v) - }); - } - if let Some(old) = dev.device.click_method() { - combo_box(ui, "Click Method", old, |v| { - dev.set_click_method(&self.state, v) - }); - } - if let Some(old) = dev.device.tap_enabled() { - bool(ui, "Tap Enabled", old, |v| { - dev.set_tap_enabled(&self.state, v) - }); - } - if let Some(old) = dev.device.drag_enabled() { - bool(ui, "Tap Drag Enabled", old, |v| { - dev.set_drag_enabled(&self.state, v) - }); - } - if let Some(old) = dev.device.drag_lock_enabled() { - bool(ui, "Tap Drag Lock Enabled", old, |v| { - dev.set_drag_lock_enabled(&self.state, v) - }); - } - if let Some(old) = dev.device.left_handed() { - bool(ui, "Left Handed", old, |v| { - dev.set_left_handed(&self.state, v) - }); - } - if let Some(old) = dev.device.middle_button_emulation_enabled() { - bool(ui, "Middle Button Emulation", old, |v| { - dev.set_middle_button_emulation_enabled(&self.state, v) - }); - } - { - let ui = &mut *ui.row(); - grid_label_ui(ui, |ui| { - ui.label("Output"); - tip(ui, |ui| { - ui.label("This applies to touch and tablet input."); - }); - }); - ui.horizontal(|ui| { - let old = dev.output.get().and_then(|v| v.global.get()); - let old = old.as_ref(); - let mut v = old; - let mut cb = ComboBox::from_id_salt("output"); - if let Some(v) = v { - cb = cb.selected_text(&*v.connector.name); - } - cb.show_ui(ui, |ui| { - for &output in outputs { - ui.selectable_value( - &mut v, - Some(output), - &*output.connector.name, - ); - } - }); - if v != old { - dev.set_output(&self.state, v.map(|v| &**v)); - } - if ui.button("Detach").clicked() { - dev.set_output(&self.state, None); - } - }); - } - matrix_ui( - ui, - "Transform Matrix", - |ui| { - tip(ui, |ui| { - ui.label("This matrix is applied to relative pointer movements."); - }); - }, - dev.device - .has_capability(InputDeviceCapability::Pointer) - .then(|| { - dev.device - .transform_matrix() - .unwrap_or([[1.0, 0.0], [0.0, 1.0]]) - }), - |v| dev.set_transform_matrix(&self.state, v), - ); - matrix( - ui, - "Calibration Matrix", - dev.device.calibration_matrix(), - |v| dev.set_calibration_matrix(&self.state, v), - ); - }); - if dev.device.has_capability(InputDeviceCapability::Keyboard) { - ui.collapsing("Device Keymap", |ui| { - let ks = self.keymaps.entry(Key::Dev(dev_id)).or_default(); - let map = dev.keymap.get(); - ui.add_enabled_ui(map.is_some(), |ui| { - if ui.button("Use Seat Keymap").clicked() { - ks.backup(map.as_ref()); - dev.set_keymap(&self.state, None); - } - }); - show_keymap( - &self.state, - ps, - &mut self.paste_requested, - ks, - ui, - map.as_ref(), - |m| { - dev.set_keymap(&self.state, Some(m.clone())); - }, - ); - }); - } - }); - } -} - -impl KeymapState { - fn backup(&mut self, map: Option<&Rc>) { - if self.backup.is_none() - && let Some(map) = map - { - self.backup = Some(map.clone()); - } - } -} - -fn show_keymap( - state: &State, - ps: &mut PaneState, - paste_requested: &mut Option, - ks: &mut KeymapState, - ui: &mut Ui, - map: Option<&Rc>, - set_map: impl Fn(&Rc), -) { - ui.scope_builder( - UiBuilder::new().id(Id::new(("keymap-settings", ks.seed))), - |ui| { - ui.add_enabled_ui(map.is_some(), |ui| { - if ui.button("Copy Keymap").clicked() - && let Some(map) = map - { - ui.copy_text(map.map_text.clone()); - } - }); - let backup = |ks: &mut KeymapState| { - ks.backup(map); - }; - if ui.button("Load Default Keymap").clicked() { - backup(ks); - set_map(&state.default_keymap); - } - ui.horizontal(|ui| { - ui.add_enabled_ui(map.is_some(), |ui| { - if ui.button("Backup Keymap").clicked() { - ks.backup = None; - backup(ks); - } - }); - if let Some(backup) = &ks.backup - && ui.button("Restore Keymap").clicked() - { - set_map(backup); - ks.backup = None; - } - }); - let mut label = "Load Keymap from Clipboard".to_string(); - if *paste_requested == Some(ui.id()) { - label.push_str(" "); - label.push_str(ICON_PENDING); - } - let button = ui.button(label); - if button.clicked() { - *paste_requested = Some(ui.id()); - button.request_focus(); - ui.send_viewport_cmd(ViewportCommand::RequestPaste); - } else if *paste_requested == Some(ui.id()) && button.has_focus() { - ui.input(|e| { - let map = e - .events - .iter() - .filter_map(|e| match e { - Event::Paste(s) => Some(s), - _ => None, - }) - .next(); - let Some(map) = map else { - return; - }; - *paste_requested = None; - let map = match state.kb_ctx.parse_keymap(map.as_bytes()) { - Ok(m) => m, - Err(e) => { - let error = format!("Could not parse keymap: {}", ErrorFmt(e)); - ps.errors.push(error); - return; - } - }; - backup(ks); - set_map(&map); - }); - } else if *paste_requested == Some(ui.id()) { - *paste_requested = None; - } - ui.collapsing("Create Keymap from Names", |ui| { - grid(ui, ("keymap-from-names", ui.id()), |ui| { - let defaulted = - |ui: &mut Ui, name: &str, default: &mut bool, text: &mut dyn TextBuffer| { - let ui = &mut *ui.row(); - grid_label(ui, name); - ui.add_enabled_ui(!*default, |ui| { - text_edit(ui, text); - }); - ui.checkbox(default, "Default"); - }; - let required = |ui: &mut Ui, name, text| { - let ui = &mut *ui.row(); - grid_label(ui, name); - text_edit(ui, text); - }; - defaulted(ui, "Rules", &mut ks.rules_default, &mut ks.rules); - defaulted(ui, "Model", &mut ks.model_default, &mut ks.model); - required(ui, "Layouts", &mut ks.layouts); - required(ui, "Variants", &mut ks.variants); - required(ui, "Options", &mut ks.options); - }); - if ui.button("Load").clicked() { - 'set_map: { - let map = state.kb_ctx.keymap_from_rmlvo( - (!ks.rules_default).then_some(&ks.rules), - (!ks.model_default).then_some(&ks.model), - Some(&ks.layouts), - Some(&ks.variants), - Some(&ks.options), - ); - let map = match map { - Ok(map) => map, - Err(e) => { - let error = format!("Could not parse keymap: {}", ErrorFmt(e)); - ps.errors.push(error); - break 'set_map; - } - }; - backup(ks); - set_map(&map); - } - } - }); - }, - ); -} - -fn matrix( - ui: &mut Ui, - name: &str, - old: Option<[[T; W]; 2]>, - set: impl FnOnce([[T; W]; 2]), -) where - T: Numeric, -{ - matrix_ui(ui, name, |_| (), old, set); -} - -fn matrix_ui( - ui: &mut Ui, - name: &str, - label: impl FnOnce(&mut Ui) -> R, - old: Option<[[T; W]; 2]>, - set: impl FnOnce([[T; W]; 2]), -) where - T: Numeric, -{ - if let Some(mut m) = old { - let old = m; - let ui = &mut *ui.row(); - grid_label_ui(ui, |ui| { - ui.label(name); - label(ui); - }); - Grid::new(name).show(ui, |ui| { - for row in &mut m { - for cell in row { - DragValue::new(cell).speed(0.01).ui(ui); - } - ui.end_row(); - } - }); - if old != m { - set(m); - } - } -} diff --git a/src/control_center/cc_look_and_feel.rs b/src/control_center/cc_look_and_feel.rs deleted file mode 100644 index 636e80da..00000000 --- a/src/control_center/cc_look_and_feel.rs +++ /dev/null @@ -1,163 +0,0 @@ -use { - crate::{ - cmm::cmm_eotf::Eotf, - control_center::{ - ControlCenterInner, bool, bool_ui, combo_box, drag_value, grid, grid_label, row, - text_edit, tip, - }, - gfx_api::AlphaMode, - state::State, - theme::{Color, ThemeColor, ThemeSized}, - utils::static_text::StaticText, - }, - egui::Ui, - isnt::std_1::primitive::IsntStrExt, - linearize::LinearizeExt, - std::rc::Rc, -}; - -pub struct LookAndFeelPane { - state: Rc, -} - -impl ControlCenterInner { - pub fn create_look_and_feel_pane(self: &Rc) -> LookAndFeelPane { - LookAndFeelPane { - state: self.state.clone(), - } - } -} - -impl LookAndFeelPane { - pub fn title(&self, res: &mut String) { - res.push_str("Look and Feel"); - } - - pub fn show(&mut self, ui: &mut Ui) { - let t = &self.state.theme; - grid(ui, "settings", |ui| { - bool(ui, "Show Bar", self.state.show_bar.get(), |v| { - self.state.set_show_bar(v) - }); - combo_box(ui, "Bar Position", t.bar_position.get(), |p| { - self.state.set_bar_position(p); - }); - bool(ui, "Show Titles", t.show_titles.get(), |v| { - self.state.set_show_titles(v) - }); - bool_ui( - ui, - "Primary Selection", - |ui| { - tip(ui, |ui| { - ui.label("Requires applications to be restarted."); - }); - }, - self.state.enable_primary_selection.get(), - |v| self.state.set_primary_selection_enabled(v), - ); - bool_ui( - ui, - "UI Drag", - |ui| { - tip(ui, |ui| { - ui.label("Allows dragging workspaces and tiled windows with the mouse."); - }); - }, - self.state.ui_drag_enabled.get(), - |v| self.state.set_ui_drag_enabled(v), - ); - drag_value( - ui, - "UI Drag Threshold (px)", - self.state.ui_drag_threshold_squared.get().isqrt(), - 1..=i32::MAX, - 1.0, - |v| { - self.state.set_ui_drag_threshold(v); - }, - ); - bool_ui( - ui, - "Float Pin Icon", - |ui| { - tip(ui, |ui| { - ui.label("Show the pin icon even if the window is not pinned."); - ui.label("Pinned floating windows are shown on all workspaces."); - }); - }, - self.state.show_pin_icon.get(), - |v| self.state.set_show_pin_icon(v), - ); - bool_ui( - ui, - "Float Above Fullscreen", - |ui| { - tip(ui, |ui| { - ui.label("Show floating windows above fullscreen windows."); - }); - }, - self.state.float_above_fullscreen.get(), - |v| self.state.set_float_above_fullscreen(v), - ); - row(ui, "Font", |ui| { - let mut v = self.state.theme.font.get().to_string(); - if text_edit(ui, &mut v).changed() { - self.state.set_font(&v); - } - }); - row(ui, "Title Font", |ui| { - let mut v = t - .title_font - .get() - .map(|v| v.to_string()) - .unwrap_or_default(); - if text_edit(ui, &mut v).changed() { - self.state.set_title_font(v.is_not_empty().then_some(&v)); - } - }); - row(ui, "Bar Font", |ui| { - let mut v = t.bar_font.get().map(|v| v.to_string()).unwrap_or_default(); - if text_edit(ui, &mut v).changed() { - self.state.set_bar_font(v.is_not_empty().then_some(&v)); - } - }); - }); - if ui.button("Reset Sizes").clicked() { - self.state.reset_sizes(); - } - if ui.button("Reset Colors").clicked() { - self.state.reset_colors(); - } - if ui.button("Reset Fonts").clicked() { - self.state.reset_fonts(); - } - ui.collapsing("Sizes", |ui| { - grid(ui, "Sizes", |ui| { - for v in ThemeSized::variants() { - let f = v.field(&self.state.theme); - drag_value(ui, v.text(), f.get(), v.min()..=v.max(), 1.0, |i| { - self.state.set_size(v, i); - }); - } - }); - }); - ui.collapsing("Colors", |ui| { - grid(ui, "Colors", |ui| { - for tc in ThemeColor::variants() { - let f = tc.field(t); - let mut v = f.get().to_array(Eotf::Linear); - grid_label(ui, tc.text()); - let changed = ui.color_edit_button_rgba_premultiplied(&mut v).changed(); - ui.end_row(); - if changed { - let [r, g, b, a] = v; - let c = - Color::new(Eotf::Linear, AlphaMode::PremultipliedOptical, r, g, b, a); - self.state.set_color(tc, c); - } - } - }); - }); - } -} diff --git a/src/control_center/cc_outputs.rs b/src/control_center/cc_outputs.rs deleted file mode 100644 index f01b1d33..00000000 --- a/src/control_center/cc_outputs.rs +++ /dev/null @@ -1,1727 +0,0 @@ -use { - crate::{ - backend::{ - BackendColorSpace, BackendEotfs, ConnectorId, Mode, - transaction::{ - BackendConnectorTransactionError, ConnectorTransaction, - PreparedConnectorTransaction, - }, - }, - cmm::cmm_luminance::Luminance, - compositor::{MAX_EXTENTS, MAX_SCALE, MIN_SCALE}, - control_center::{ControlCenterInner, GridExt, PaneState, grid, grid_label, label, tip}, - egui_adapter::{ - egui_oklch::Color32Ext, - egui_platform::icons::{ICON_ADD, ICON_REMOVE}, - }, - ifs::{ - head_management::{HeadName, HeadState, ReadOnlyHeadState}, - wl_output::BlendSpace, - }, - scale::{SCALE_BASE, SCALE_BASEF, Scale}, - state::State, - tree::{TearingMode, Transform, VrrMode}, - utils::{errorfmt::ErrorFmt, static_text::StaticText}, - }, - ahash::AHashMap, - egui::{ - Align, Button, Checkbox, CollapsingHeader, Color32, ComboBox, DragValue, EventFilter, - FontId, Frame, Grid, Id, Key, Layout, PointerButton, Rect, ScrollArea, Sense, Shadow, - Stroke, StrokeKind, Style, TextFormat, Ui, UiBuilder, Vec2, Widget, WidgetText, emath, - pos2, text::LayoutJob, vec2, - }, - egui_tiles::{ - Behavior, Container, Linear, LinearDir, ResizeState, SimplificationOptions, Tile, TileId, - Tiles, Tree, UiResponse, - }, - linearize::{Linearize, LinearizeExt}, - rand::random, - serde::{Deserialize, Serialize}, - std::{ - cell::{Cell, Ref}, - fmt, - rc::Rc, - }, - thiserror::Error, -}; - -pub struct OutputsPane { - tree: Tree, - root_id: TileId, - arrangement_id: Option, - inner: OutputsPaneInner, -} - -struct OutputsPaneInner { - state: Rc, - in_transaction: Cell, - heads: AHashMap, - ui: UiSettings, - settings: Settings, - seed: u64, -} - -enum Pane { - Arrangement, - Settings, -} - -struct CompleteHead { - id: ConnectorId, - name: HeadName, - pretty_name: Rc, - live_state: ReadOnlyHeadState, - changed_state: Option, - z: u64, - focus: u64, - drag_pos: Option<(f32, f32)>, -} - -struct UiSettings { - scale: f32, - origin: Vec2, - origin_drag: Option, - next_z: u64, - focus: u64, - zoom_to_fit: bool, - view: View, -} - -struct Settings { - show_guide_lines: bool, - snap_to_neighbor: bool, - show_disconnected: bool, - show_disabled: bool, - show_arrangement: bool, - layout: UiLayout, -} - -impl Default for Settings { - fn default() -> Self { - Self { - show_guide_lines: false, - snap_to_neighbor: true, - show_disconnected: false, - show_disabled: true, - show_arrangement: true, - layout: UiLayout::Auto, - } - } -} - -#[derive(Copy, Clone, Serialize, Deserialize, PartialEq, Linearize)] -enum UiLayout { - Auto, - Vertical, - Horizontal, -} - -#[derive(Copy, Clone)] -pub enum View { - Connectors, - Settings, -} - -#[derive(Error, Debug)] -enum HeadTransactionError { - #[error("The connector {} has been removed", .0)] - HeadRemoved(Rc), - #[error("The display connected to connector {} has changed", .0)] - MonitorChanged(Rc), - #[error(transparent)] - Backend(#[from] BackendConnectorTransactionError), -} - -macro_rules! effective { - ($m:expr, $t:expr) => { - $t.as_ref().unwrap_or($m) - }; -} - -macro_rules! modify { - ($m:expr, $t:expr) => { - $t.get_or_insert_with(|| $m.clone()) - }; -} - -impl ControlCenterInner { - pub fn create_outputs_pane(self: &Rc) -> OutputsPane { - let seed = random(); - let mut tiles = Tiles::default(); - let settings_id = tiles.insert_pane(Pane::Settings); - let arrangement_id = tiles.insert_pane(Pane::Arrangement); - let root_id = tiles.insert_container(Linear::new( - LinearDir::Horizontal, - vec![arrangement_id, settings_id], - )); - let tree = Tree::new(Id::new(("cc_outputs", seed)), root_id, tiles); - let mut pane = OutputsPane { - root_id, - arrangement_id: Some(arrangement_id), - tree, - inner: OutputsPaneInner { - state: self.state.clone(), - ui: UiSettings { - scale: 0.1, - origin: Default::default(), - origin_drag: None, - next_z: 0, - focus: 0, - zoom_to_fit: true, - view: View::Connectors, - }, - settings: Default::default(), - in_transaction: Default::default(), - heads: Default::default(), - seed, - }, - }; - pane.inner.reset(); - pane - } -} - -struct B<'a>(&'a mut OutputsPaneInner, &'a mut PaneState); - -impl Behavior for B<'_> { - fn pane_ui(&mut self, ui: &mut Ui, _tile_id: TileId, pane: &mut Pane) -> UiResponse { - Frame::new().inner_margin(5.0).show(ui, |ui| match pane { - Pane::Arrangement => self.0.show_arrangement(ui), - Pane::Settings => self.0.show_main_area(self.1, ui), - }); - UiResponse::None - } - - fn tab_title_for_pane(&mut self, _pane: &Pane) -> WidgetText { - "".into() - } - - fn gap_width(&self, _style: &Style) -> f32 { - 5.0 - } - - fn simplification_options(&self) -> SimplificationOptions { - SimplificationOptions { - prune_empty_tabs: false, - prune_empty_containers: false, - prune_single_child_tabs: false, - prune_single_child_containers: false, - all_panes_must_have_tabs: false, - join_nested_linear_containers: false, - } - } - - fn resize_stroke(&self, style: &Style, resize_state: ResizeState) -> Stroke { - match resize_state { - ResizeState::Idle => style.visuals.widgets.noninteractive.bg_stroke, - ResizeState::Hovering => style.visuals.widgets.hovered.fg_stroke, - ResizeState::Dragging => style.visuals.widgets.active.fg_stroke, - } - } -} - -impl OutputsPane { - pub fn title(&self, res: &mut String) { - res.push_str("Outputs"); - if self.inner.in_transaction.get() { - res.push_str(" (*)"); - } - } - - pub fn show(&mut self, ps: &mut PaneState, ui: &mut Ui) { - self.inner.add_new_heads(); - if let Some(id) = self.arrangement_id { - if !self.inner.settings.show_arrangement { - self.tree.remove_recursively(id); - self.arrangement_id = None; - } - } else { - if self.inner.settings.show_arrangement { - let id = self.tree.tiles.insert_pane(Pane::Arrangement); - self.tree.move_tile_to_container(id, self.root_id, 0, false); - self.arrangement_id = Some(id); - } - } - let show_vertical = match self.inner.settings.layout { - UiLayout::Auto => ui.available_width() < 1024.0, - UiLayout::Vertical => true, - UiLayout::Horizontal => false, - }; - if let Some(root) = self.tree.tiles.get_mut(self.root_id) - && let Tile::Container(root) = root - && let Container::Linear(root) = root - { - root.dir = match show_vertical { - true => LinearDir::Vertical, - false => LinearDir::Horizontal, - }; - } - self.tree.ui(&mut B(&mut self.inner, ps), ui) - } -} - -impl OutputsPaneInner { - fn show_main_area(&mut self, ps: &mut PaneState, ui: &mut Ui) { - ui.scope_builder( - UiBuilder::new().id(Id::new(("main_area", self.seed))), - |ui| { - self.show_settings_bar(ps, ui); - ScrollArea::vertical().show(ui, |ui| { - match self.ui.view { - View::Connectors => self.show_connectors(ui), - View::Settings => self.show_settings(ui), - } - ui.allocate_space(ui.available_size()); - }); - }, - ); - } - - fn show_settings_bar(&mut self, ps: &mut PaneState, ui: &mut Ui) { - ui.horizontal_wrapped(|ui| { - if ui.button("Connectors").clicked() { - self.ui.view = View::Connectors; - ui.request_repaint(); - } - if ui.button("Settings").clicked() { - self.ui.view = View::Settings; - ui.request_repaint(); - } - if ui - .checkbox(&mut self.ui.zoom_to_fit, "Zoom To Fit") - .changed() - { - ui.request_repaint(); - } - { - let mut reset = !self.in_transaction.get(); - let reset2 = reset; - let widget = Checkbox::new(&mut reset, "Reset"); - if reset2 { - ui.add_enabled(false, widget); - } else { - if widget.ui(ui).changed() { - self.reset(); - } - } - } - ui.with_layout(Layout::right_to_left(Align::LEFT), |ui| { - let enabled = self.in_transaction.get(); - ui.add_enabled_ui(enabled, |ui| { - if ui.button("Test").clicked() { - if let Err(e) = self.test_transaction() { - ps.errors.push(ErrorFmt(e).to_string()); - } - } - }); - let enabled = self.in_transaction.get(); - ui.add_enabled_ui(enabled, |ui| { - let button = Button::new("Commit").fill(ui.style().visuals.extreme_bg_color); - if ui.add(button).clicked() { - match self.commit_transaction() { - Ok(_) => self.reset(), - Err(e) => { - ps.errors.push(ErrorFmt(e).to_string()); - } - } - } - }); - ui.add_space(ui.available_width()); - }); - }); - ui.separator(); - } - - fn show_connectors(&mut self, ui: &mut Ui) { - let mut heads: Vec<_> = self.heads.values_mut().collect(); - heads.sort_by(|a, b| { - a.live_state - .borrow() - .name - .cmp(&b.live_state.borrow().name) - .then_with(|| a.name.cmp(&b.name)) - }); - let mut is_in_transaction = false; - for head in &mut heads { - show_connector(&self.state, &self.settings, head, ui); - if head.changed_state.is_some() { - is_in_transaction = true; - } - } - self.in_transaction.set(is_in_transaction); - } - - fn show_settings(&mut self, ui: &mut Ui) { - let mut changed = false; - - { - changed |= ui - .checkbox(&mut self.settings.show_guide_lines, "Show guide lines") - .changed(); - } - - { - ui.horizontal(|ui| { - changed |= ui - .checkbox(&mut self.settings.snap_to_neighbor, "Snap to neighbor") - .changed(); - tip(ui, |ui| { - ui.label("Hold Shift to invert this"); - }); - }); - } - - { - ui.checkbox(&mut self.settings.show_arrangement, "Show arrangement area"); - } - - { - let layout_text = |l: UiLayout| match l { - UiLayout::Auto => "Auto", - UiLayout::Vertical => "Vertical", - UiLayout::Horizontal => "Horizontal", - }; - changed |= ComboBox::new("layout", "Layout") - .selected_text(layout_text(self.settings.layout)) - .show_ui(ui, |ui| { - for l in UiLayout::variants() { - ui.selectable_value(&mut self.settings.layout, l, layout_text(l)); - } - }) - .response - .changed(); - } - - { - changed |= ui - .checkbox( - &mut self.settings.show_disconnected, - "Show disconnected heads", - ) - .changed(); - } - - { - changed |= ui - .checkbox(&mut self.settings.show_disabled, "Show disabled heads") - .changed(); - } - - if changed { - ui.request_repaint(); - } - } - - fn show_arrangement(&mut self, ui: &mut Ui) { - let clip_rect = ui.available_rect_before_wrap(); - let origin = &mut self.ui.origin; - let ox = origin.x.round(); - let oy = origin.y.round(); - let mut heads = vec![]; - let scale = self.ui.scale; - struct PreparedHead<'a> { - name: HeadName, - m: Ref<'a, HeadState>, - changed_state: &'a mut Option, - z: &'a mut u64, - focus: &'a mut u64, - drag_pos: &'a mut Option<(f32, f32)>, - x1: i32, - y1: i32, - x2: i32, - y2: i32, - rect: Rect, - } - for head in self.heads.values_mut() { - let m = head.live_state.borrow(); - let e = effective!(&*m, head.changed_state); - if !e.in_compositor_space { - continue; - } - let (x, y) = e.position; - let (w, h) = e.size; - let x1 = (x as f32 * scale).round() - ox + clip_rect.min.x; - let y1 = (y as f32 * scale).round() - oy + clip_rect.min.y; - let x2 = ((x + w) as f32 * scale).round() - ox + clip_rect.min.x; - let y2 = ((y + h) as f32 * scale).round() - oy + clip_rect.min.y; - heads.push(PreparedHead { - name: head.name, - m, - changed_state: &mut head.changed_state, - z: &mut head.z, - focus: &mut head.focus, - drag_pos: &mut head.drag_pos, - x1: x, - y1: y, - x2: x + w, - y2: y + h, - rect: Rect { - min: pos2(x1, y1), - max: pos2(x2, y2), - }, - }); - } - if self.ui.zoom_to_fit { - let mut x_min = i32::MAX; - let mut x_max = i32::MIN; - let mut y_min = i32::MAX; - let mut y_max = i32::MIN; - for head in &heads { - x_min = x_min.min(head.x1); - x_max = x_max.max(head.x2); - y_min = y_min.min(head.y1); - y_max = y_max.max(head.y2); - } - if x_min > x_max { - x_min = 0; - x_max = 0; - } - if y_min > y_max { - y_min = 0; - y_max = 0; - } - x_min -= 100; - y_min -= 100; - x_max += 100; - y_max += 100; - let dx = x_max - x_min + 1; - let dy = y_max - y_min + 1; - let x_scale = clip_rect.width() / dx as f32; - let y_scale = clip_rect.height() / dy as f32; - let new_scale = x_scale.min(y_scale); - let new_ox = x_min as f32 * new_scale; - let new_oy = y_min as f32 * new_scale; - if new_scale != scale || new_ox != ox || new_oy != oy { - self.ui.scale = new_scale; - origin.x = new_ox; - origin.y = new_oy; - ui.request_repaint(); - } - } - heads.sort_by_key(|h| *h.z); - let style = &ui.style().visuals; - let mut bg_color = style.panel_fill.to_oklch(); - let mut no_capture_bg_color = bg_color; - let mut disabled_bg_color = bg_color; - if bg_color.l > 0.5 { - bg_color.l -= 0.05; - disabled_bg_color.l -= 0.1; - no_capture_bg_color.l -= 0.075; - } else { - bg_color.l += 0.05; - disabled_bg_color.l += 0.1; - no_capture_bg_color.l += 0.075; - } - let fg_color_base = style.widgets.noninteractive.text_color().to_oklab(); - let fg_color_1 = fg_color_base * 1.0 / 3.0 + bg_color.to_oklab() * 2.0 / 3.0; - let fg_color_2 = fg_color_base * 2.0 / 3.0 + bg_color.to_oklab() * 1.0 / 3.0; - let painter = ui.painter_at(clip_rect); - painter.rect( - Rect::EVERYTHING, - 0.0, - disabled_bg_color, - Stroke::NONE, - StrokeKind::Inside, - ); - { - let x_min = 0.0; - let y_min = 0.0; - let x_max = MAX_EXTENTS as f32; - let y_max = MAX_EXTENTS as f32; - let good = Rect { - min: clip_rect.min + vec2(x_min, y_min) * scale - *origin, - max: clip_rect.min + vec2(x_max, y_max) * scale - *origin, - }; - painter.rect(good, 0.0, bg_color, Stroke::NONE, StrokeKind::Inside); - } - painter.hline( - clip_rect.left()..=clip_rect.right(), - clip_rect.min.y - origin.y, - (1.0, fg_color_1), - ); - painter.vline( - clip_rect.min.x - origin.x, - clip_rect.top()..=clip_rect.bottom(), - (1.0, fg_color_1), - ); - if self.settings.show_guide_lines { - for head in &heads { - let rect = head.rect; - painter.hline( - clip_rect.left()..=clip_rect.right(), - rect.top(), - (1.0, fg_color_2), - ); - painter.hline( - clip_rect.left()..=clip_rect.right(), - rect.bottom(), - (1.0, fg_color_2), - ); - painter.vline( - rect.left(), - clip_rect.top()..=clip_rect.bottom(), - (1.0, fg_color_2), - ); - painter.vline( - rect.right(), - clip_rect.top()..=clip_rect.bottom(), - (1.0, fg_color_2), - ); - } - } - for head in &mut heads { - let rect = head.rect; - let mut color = fg_color_2; - if *head.focus == self.ui.focus { - let shape = Shadow { - offset: [0, 0], - blur: (512.0 * scale).sqrt() as u8, - spread: (255.0 * scale).sqrt() as u8, - color: Color32::from_black_alpha(200), - } - .as_shape(rect, 0.0); - painter.add(shape); - color = fg_color_base; - } - painter.hline(rect.left()..=rect.right() + 1.0, rect.top(), (1.0, color)); - painter.hline( - rect.left()..=rect.right() + 1.0, - rect.bottom(), - (1.0, color), - ); - painter.vline(rect.left(), rect.top()..=rect.bottom() + 1.0, (1.0, color)); - painter.vline(rect.right(), rect.top()..=rect.bottom() + 1.0, (1.0, color)); - let content_rect = Rect { - min: pos2(rect.min.x + 1.0, rect.min.y + 1.0), - max: pos2(rect.max.x, rect.max.y), - }; - let painter = painter.with_clip_rect(content_rect); - painter.rect( - content_rect, - 0.0, - no_capture_bg_color, - Stroke::NONE, - StrokeKind::Inside, - ); - let galley = - painter.layout_no_wrap(head.m.name.to_string(), FontId::default(), Color32::WHITE); - let rect = Rect::from_min_size(content_rect.min, galley.rect.size() + vec2(2.0, 2.0)); - painter.rect(rect, 0.0, Color32::BLUE, Stroke::NONE, StrokeKind::Inside); - painter.galley(rect.min + vec2(1.0, 1.0), galley, Color32::WHITE); - } - ui.allocate_space(ui.available_size()); - macro_rules! interacted { - () => {{ - self.ui.zoom_to_fit = false; - }}; - } - let response = ui.allocate_rect(clip_rect, Sense::all()); - if response.has_focus() { - let mut dx = 0; - let mut dy = 0; - ui.input(|i| { - if i.key_pressed(Key::ArrowUp) { - dy -= 1; - } - if i.key_pressed(Key::ArrowDown) { - dy += 1; - } - if i.key_pressed(Key::ArrowLeft) { - dx -= 1; - } - if i.key_pressed(Key::ArrowRight) { - dx += 1; - } - }); - if dx != 0 || dy != 0 { - interacted!(); - for head in &mut heads { - if *head.focus == self.ui.focus { - let x = (head.x1 + dx).clamp(0, MAX_EXTENTS); - let y = (head.y1 + dy).clamp(0, MAX_EXTENTS); - let pos = (x, y); - if effective!(&*head.m, head.changed_state).position != pos { - modify!(&*head.m, head.changed_state).position = pos; - ui.request_repaint(); - } - } - } - } - } - if let Some(pos) = response.hover_pos() { - let scroll = ui.input(|i| i.smooth_scroll_delta); - let mut new = scale; - if scroll.y != 0.0 { - interacted!(); - } - if scroll.y < 0.0 { - new /= 1.0 - scroll.y / 1000.0; - } else { - new *= 1.0 + scroll.y / 1000.0; - } - new = new.max(0.01); - if new != scale { - self.ui.scale = new; - ui.request_repaint(); - let relative_pos = pos - clip_rect.min; - let real_pos = (relative_pos + *origin) / scale; - *origin = real_pos * new - relative_pos; - } - } - if ui.input(|i| i.pointer.button_pressed(PointerButton::Primary)) { - self.ui.focus += 1; - if let Some(pos) = response.hover_pos() { - interacted!(); - response.request_focus(); - for head in heads.iter_mut().rev() { - if head.rect.contains(pos) { - *head.z = self.ui.next_z; - self.ui.next_z += 1; - *head.focus = self.ui.focus; - ui.request_repaint(); - break; - } - } - } - } - if response.clicked_elsewhere() { - self.ui.focus += 1; - } - if response.drag_started_by(PointerButton::Middle) - || response.drag_started_by(PointerButton::Secondary) - { - interacted!(); - self.ui.origin_drag = Some(self.ui.origin); - } else if response.drag_started_by(PointerButton::Primary) - && let Some(pos) = response.hover_pos() - { - interacted!(); - for head in heads.iter_mut().rev() { - if head.rect.contains(pos) { - *head.drag_pos = Some((head.x1 as f32, head.y1 as f32)); - break; - } - } - } - let drag_delta = response.drag_delta(); - if drag_delta.x != 0.0 || drag_delta.y != 0.0 { - if let Some(origin_drag) = &mut self.ui.origin_drag { - *origin_drag -= drag_delta; - self.ui.origin = *origin_drag; - ui.request_repaint(); - } - let snap = self.settings.snap_to_neighbor ^ ui.input(|i| i.modifiers.shift); - let mut head_positions = vec![]; - struct HeadPosition { - name: HeadName, - x1: i32, - y1: i32, - x2: i32, - y2: i32, - } - if snap { - for head in &heads { - let PreparedHead { - name, - x1, - y1, - x2, - y2, - .. - } = *head; - head_positions.push(HeadPosition { - name, - x1, - y1, - x2, - y2, - }); - } - } - for head in &mut heads { - if let Some((mut x, mut y)) = *head.drag_pos { - x += drag_delta.x / scale; - y += drag_delta.y / scale; - let mut x_int = if x < 0.0 { x.ceil() } else { x.floor() } as i32; - let mut y_int = if y < 0.0 { y.ceil() } else { y.floor() } as i32; - if snap { - for other in &head_positions { - if head.name == other.name { - continue; - } - macro_rules! snap { - ($int:ident, $one:ident, $two:ident) => { - if $int.abs() as f32 * scale <= 10.0 { - $int = 0; - } else if ($int - other.$one).abs() as f32 * scale <= 10.0 { - $int = other.$one; - } else if ($int - other.$two).abs() as f32 * scale <= 10.0 { - $int = other.$two; - } else if ($int + head.$two - head.$one - other.$one).abs() - as f32 - * scale - <= 10.0 - { - $int = other.$one + head.$one - head.$two; - } else if ($int + head.$two - head.$one - other.$two).abs() - as f32 - * scale - <= 10.0 - { - $int = other.$two + head.$one - head.$two; - } - }; - } - snap!(x_int, x1, x2); - snap!(y_int, y1, y2); - } - } - x_int = x_int.clamp(0, MAX_EXTENTS); - y_int = y_int.clamp(0, MAX_EXTENTS); - let pos = (x_int, y_int); - if effective!(&*head.m, head.changed_state).position != pos { - modify!(&*head.m, head.changed_state).position = pos; - ui.request_repaint(); - } - *head.drag_pos = Some((x, y)); - } - } - } - if response.drag_stopped() { - self.ui.origin_drag = None; - for head in heads.iter_mut().rev() { - *head.drag_pos = None; - } - } - ui.memory_mut(|mem| { - mem.set_focus_lock_filter( - response.id, - EventFilter { - tab: false, - horizontal_arrows: true, - vertical_arrows: true, - escape: false, - }, - ) - }); - } - - fn prepare_transaction(&self) -> Result { - let mut tran = ConnectorTransaction::new(&self.state); - for head in self.heads.values() { - let Some(desired) = &head.changed_state else { - continue; - }; - let Some(connector) = self.state.connectors.get(&head.id) else { - return Err(HeadTransactionError::HeadRemoved(head.pretty_name.clone())); - }; - if head.live_state.borrow().monitor_info != desired.monitor_info { - return Err(HeadTransactionError::MonitorChanged( - head.pretty_name.clone(), - )); - } - let old = connector.state.borrow().clone(); - let mut new = old.clone(); - new.enabled = desired.connector_enabled; - new.mode = desired.mode; - new.non_desktop_override = desired.override_non_desktop; - new.format = desired.format; - new.color_space = desired.color_space; - new.eotf = desired.eotf; - if old == new { - continue; - } - tran.add(&connector.connector, new)?; - } - Ok(tran.prepare()?) - } - - fn commit_transaction(&self) -> Result<(), HeadTransactionError> { - self.prepare_transaction()?.apply()?.commit(); - for head in self.heads.values() { - let Some(desired) = &head.changed_state else { - continue; - }; - desired.flush_persistent_state(&self.state); - if let Some(output) = self.state.outputs.get(&head.id) - && let Some(node) = &output.node - { - node.set_position(desired.position.0, desired.position.1); - node.set_preferred_scale(desired.scale); - node.update_transform(desired.transform); - node.set_vrr_mode(&desired.vrr_mode); - node.set_tearing_mode(&desired.tearing_mode); - node.set_brightness(desired.brightness); - node.set_blend_space(desired.blend_space); - node.set_use_native_gamut(desired.use_native_gamut); - node.schedule - .set_cursor_hz(&self.state, desired.vrr_cursor_hz.unwrap_or(f64::INFINITY)); - } else if let Some(mi) = &desired.monitor_info { - let pos = &self.state.persistent_output_states; - let pos = pos.lock().entry(mi.output_id.clone()).or_default().clone(); - pos.pos.set(desired.position); - pos.scale.set(desired.scale); - pos.transform.set(desired.transform); - pos.vrr_mode.set(desired.vrr_mode); - pos.tearing_mode.set(desired.tearing_mode); - pos.brightness.set(desired.brightness); - pos.blend_space.set(desired.blend_space); - pos.use_native_gamut.set(desired.use_native_gamut); - pos.vrr_cursor_hz.set(desired.vrr_cursor_hz); - } - } - Ok(()) - } - - fn test_transaction(&self) -> Result<(), HeadTransactionError> { - self.prepare_transaction()?; - Ok(()) - } - - fn reset(&mut self) { - self.in_transaction.set(false); - let mut to_remove = vec![]; - for head in self.heads.values_mut() { - if self.state.connectors.contains(&head.id) { - head.changed_state = None; - } else { - to_remove.push(head.name); - } - } - for name in to_remove { - self.heads.remove(&name); - } - } - - fn add_new_heads(&mut self) { - for connector in self.state.connectors.lock().values() { - let mgrs = &connector.head_managers; - self.heads.entry(mgrs.name).or_insert_with(|| CompleteHead { - id: connector.id, - name: mgrs.name, - pretty_name: connector.name.clone(), - live_state: mgrs.state(), - changed_state: None, - z: 0, - focus: 0, - drag_pos: None, - }); - } - } -} - -fn show_connector(state: &State, settings: &Settings, head: &mut CompleteHead, ui: &mut Ui) { - let m = &*head.live_state.borrow(); - let t = &mut head.changed_state; - if t.is_none() { - if !m.connector_enabled && !settings.show_disabled { - return; - } - if !m.connected && !settings.show_disconnected { - return; - } - } - let mut layout_job = LayoutJob::default(); - layout_job.append( - "Connector", - 0.0, - TextFormat { - color: ui.style().visuals.widgets.inactive.text_color(), - ..Default::default() - }, - ); - layout_job.append( - &m.name, - 10.0, - TextFormat { - color: ui.style().visuals.widgets.active.text_color(), - ..Default::default() - }, - ); - let mut name = String::new(); - if let Some(v) = &m.monitor_info { - name.push_str(&v.output_id.manufacturer); - name.push_str(" - "); - name.push_str(&v.output_id.model); - } - layout_job.append( - &name, - 10.0, - TextFormat { - color: ui.style().visuals.widgets.inactive.text_color(), - ..Default::default() - }, - ); - CollapsingHeader::new(layout_job) - .id_salt(("connector", head.name)) - .show(ui, |ui| { - grid(ui, ("settings", head.name), |ui| { - let mut diff = false; - show_serial_number(ui, m); - diff |= show_enablement(state, ui, m, t); - diff |= show_position(ui, m, t); - diff |= show_scale(ui, m, t); - diff |= show_mode(ui, m, t); - diff |= show_size(ui, m, t); - diff |= show_transform(ui, m, t); - diff |= show_brightness(ui, m, t); - diff |= show_color_space(ui, m, t); - diff |= show_eotf(ui, m, t); - diff |= show_format(ui, m, t); - diff |= show_tearing(ui, m, t); - diff |= show_vrr(ui, m, t); - diff |= show_non_desktop(state, ui, m, t); - diff |= show_blend_space(ui, m, t); - diff |= show_use_native_gamut(ui, m, t); - show_native_gamut(ui, m); - diff |= show_cursor_hz(ui, m, t); - show_flip_margin(state, ui, m, t, head.id); - if diff { - let ui = &mut *ui.row(); - ui.label(""); - ui.label(""); - ui.label("^ current"); - } - }); - }); -} - -fn show_serial_number(ui: &mut Ui, m: &HeadState) { - if let Some(info) = &m.monitor_info { - let ui = &mut *ui.row(); - grid_label(ui, "Serial Number"); - ui.label(&info.output_id.serial_number); - } -} - -fn show_enablement(state: &State, ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - let ui = &mut *ui.row(); - grid_label(ui, "Enabled"); - let mut v = effective!(m, t).connector_enabled; - let changed = Checkbox::without_text(&mut v).ui(ui).changed(); - if changed { - let t = modify!(m, t); - t.connector_enabled = v; - t.update_in_compositor_space(state, m.wl_output); - } - let diff = v != m.connector_enabled; - if diff { - ui.label(match m.connector_enabled { - true => "enabled", - false => "disabled", - }); - } - diff -} - -fn show_position(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - let ui = &mut *ui.row(); - grid_label(ui, "Position"); - let (mut x, mut y) = effective!(m, t).position; - ui.horizontal(|ui| { - let value = |ui: &mut Ui, v, min, max| { - let res = DragValue::new(v).range(min..=max).speed(1.0).ui(ui); - res.changed() - }; - let mut changed = false; - changed |= value(ui, &mut x, 0, MAX_EXTENTS); - ui.label("x"); - changed |= value(ui, &mut y, 0, MAX_EXTENTS); - if changed { - modify!(m, t).position = (x, y); - } - }); - let diff = m.position != (x, y); - if diff { - ui.label(format!("{} x {}", m.position.0, m.position.1)); - } - diff -} - -fn show_scale(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - let ui = &mut *ui.row(); - grid_label(ui, "Scale"); - let mut v = effective!(m, t).scale; - let old = v; - ui.horizontal(|ui| { - let mut s = v.to_f64(); - let res = DragValue::new(&mut s) - .range(MIN_SCALE.to_f64()..=MAX_SCALE.to_f64()) - .speed(1.0 / SCALE_BASEF) - .fixed_decimals(5) - .ui(ui); - if res.changed() { - v = Scale::from_f64(s); - } - if ui.button(ICON_REMOVE).clicked() { - v = Scale::from_wl(v.to_wl().saturating_sub(SCALE_BASE)).clamp(MIN_SCALE, MAX_SCALE); - } - if ui.button(ICON_ADD).clicked() { - v = Scale::from_wl(v.to_wl().saturating_add(SCALE_BASE)).clamp(MIN_SCALE, MAX_SCALE); - } - }); - if old != v { - let t = modify!(m, t); - t.scale = v; - t.update_size(); - } - let diff = m.scale != v; - if diff { - ui.label(format!("{}", m.scale.to_f64())); - } - diff -} - -fn show_mode(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - let ui = &mut *ui.row(); - let mut mode = effective!(m, t).mode; - let old = mode; - grid_label(ui, "Mode"); - let mode_text = |mode: Mode| { - format!( - "{}x{}@{}", - mode.width, - mode.height, - mode.refresh_rate_millihz as f64 / 1000.0 - ) - }; - if let Some(monitor_info) = &m.monitor_info - && let Some(modes) = &monitor_info.modes - && modes.len() > 1 - { - ComboBox::from_id_salt("modes") - .selected_text(mode_text(mode)) - .show_ui(ui, |ui| { - for v in modes { - ui.selectable_value(&mut mode, *v, mode_text(*v)); - } - }); - } else if let Some(monitor_info) = &m.monitor_info - && monitor_info.modes.is_none() - { - ui.horizontal(|ui| { - fn value(ui: &mut Ui, v: &mut T, min: T, max: T) -> bool { - let res = DragValue::new(v).range(min..=max).speed(1.0).ui(ui); - res.changed() - } - value(ui, &mut mode.width, 1, u16::MAX as i32); - ui.label("x"); - value(ui, &mut mode.height, 1, u16::MAX as i32); - ui.label("@"); - let mut hz = mode.refresh_rate_millihz as f64 / 1_000.0; - if value(ui, &mut hz, 0.0, 1_000_000.0) { - mode.refresh_rate_millihz = (hz * 1_000.0).round() as u32; - } - }); - } else { - ui.label(mode_text(mode)); - } - if old != mode { - let t = modify!(m, t); - t.mode = mode; - t.update_size(); - } - let mut diff = false; - if m.mode != mode { - diff = true; - ui.label(mode_text(m.mode)); - } - diff -} - -fn show_size(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if let Some(info) = &m.monitor_info { - let ui = &mut *ui.row(); - grid_label(ui, "Physical Size (mm)"); - ui.label(format!("{} x {}", info.width_mm, info.height_mm)); - } - if !effective!(m, t).in_compositor_space { - return false; - } - let ui = &mut *ui.row(); - grid_label(ui, "Size"); - let (w, h) = effective!(m, t).size; - ui.label(format!("{w} x {h}")); - let diff = m.size != (w, h); - if diff { - ui.label(format!("{} x {}", m.size.0, m.size.1)); - } - diff -} - -fn show_transform(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - let ui = &mut *ui.row(); - grid_label(ui, "Transform"); - let mut v = effective!(m, t).transform; - let mut changed = false; - ComboBox::from_id_salt("transform") - .selected_text(v.text()) - .show_ui(ui, |ui| { - let transforms = [ - Transform::None, - Transform::Rotate90, - Transform::Rotate180, - Transform::Rotate270, - Transform::Flip, - Transform::FlipRotate90, - Transform::FlipRotate180, - Transform::FlipRotate270, - ]; - for s in transforms { - changed |= ui.selectable_value(&mut v, s, s.text()).changed(); - } - }); - if changed { - let t = modify!(m, t); - t.transform = v; - t.update_size(); - } - let diff = m.transform != v; - if diff { - ui.label(m.transform.text()); - } - diff -} - -fn show_brightness(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - let old_custom_brightness = effective!(m, t).brightness.is_some(); - let mut custom_brightness = old_custom_brightness; - let mut changed = false; - grid_label(ui, "Custom Brightness"); - Checkbox::without_text(&mut custom_brightness).ui(ui); - changed |= old_custom_brightness != custom_brightness; - let diff1 = m.brightness.is_some() != custom_brightness; - if diff1 { - ui.label(match m.brightness.is_some() { - true => "enabled", - false => "disabled", - }); - } - ui.end_row(); - - if !custom_brightness { - if changed { - modify!(m, t).brightness = None; - } - return diff1; - } - - grid_label(ui, "Brightness"); - ui.vertical(|ui| { - let effective = effective!(m, t); - let default_brightness = match effective.eotf { - BackendEotfs::Default => effective - .monitor_info - .as_ref() - .and_then(|m| m.luminance.as_ref()) - .map(|l| l.max) - .unwrap_or(Luminance::SRGB.white.0), - BackendEotfs::Pq => Luminance::ST2084_PQ.white.0, - }; - let mut brightness = effective.brightness.unwrap_or(default_brightness); - changed |= DragValue::new(&mut brightness) - .range(0.0..=1000.0) - .ui(ui) - .changed(); - ui.label(format!("reference: {default_brightness})")); - if changed { - modify!(m, t).brightness = Some(brightness); - } - }); - let mut diff2 = false; - if let Some(t) = t - && m.brightness != t.brightness - { - diff2 = true; - ui.label(format!( - "{}", - fmt::from_fn(|f| match m.brightness { - None => f.write_str("disabled"), - Some(v) => write!(f, "{}", v), - }) - )); - } - ui.end_row(); - diff1 || diff2 -} - -fn show_color_space(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - let ui = &mut *ui.row(); - grid_label(ui, "Colorimetry"); - let mut v = effective!(m, t).color_space; - ui.horizontal(|ui| { - if let Some(monitor_info) = &effective!(m, t).monitor_info { - if monitor_info.color_spaces.is_empty() { - ui.label(v.name()); - } else { - let mut changed = false; - ComboBox::from_id_salt("colorimetry") - .selected_text(v.name()) - .show_ui(ui, |ui| { - changed |= ui - .selectable_value( - &mut v, - BackendColorSpace::Default, - BackendColorSpace::Default.name(), - ) - .changed(); - for &s in &monitor_info.color_spaces { - changed |= ui.selectable_value(&mut v, s, s.name()).changed(); - } - }); - if changed { - modify!(m, t).color_space = v; - } - } - } - }); - let diff = m.color_space != v; - if diff { - ui.label(m.color_space.name()); - } - diff -} - -fn show_eotf(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - let ui = &mut *ui.row(); - grid_label(ui, "EOTF"); - let mut v = effective!(m, t).eotf; - ui.horizontal(|ui| { - if let Some(monitor_info) = &effective!(m, t).monitor_info { - if monitor_info.eotfs.is_empty() { - ui.label(v.name()); - } else { - let mut changed = false; - ComboBox::from_id_salt("eotf") - .selected_text(v.name()) - .show_ui(ui, |ui| { - changed |= ui - .selectable_value( - &mut v, - BackendEotfs::Default, - BackendEotfs::Default.name(), - ) - .changed(); - for &s in &monitor_info.eotfs { - changed |= ui.selectable_value(&mut v, s, s.name()).changed(); - } - }); - if changed { - modify!(m, t).eotf = v; - } - } - } - }); - let diff = m.eotf != v; - if diff { - ui.label(m.eotf.name()); - } - diff -} - -fn show_format(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - let ui = &mut *ui.row(); - grid_label(ui, "Format"); - let mut v = effective!(m, t).format; - ui.horizontal(|ui| { - if m.supported_formats.len() < 2 { - ui.label(v.name); - } else { - let mut changed = false; - ComboBox::from_id_salt("format") - .selected_text(v.name) - .show_ui(ui, |ui| { - for &s in &*m.supported_formats { - changed |= ui.selectable_value(&mut v, s, s.name).changed(); - } - }); - if changed { - modify!(m, t).format = v; - } - } - }); - let diff = m.format != v; - if diff { - ui.label(m.format.name); - } - diff -} - -fn show_tearing(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - let render_settings = |ui: &mut Ui, old: TearingMode| { - #[derive(Copy, Clone, PartialEq, Linearize)] - enum Mode { - Never, - Always, - Fullscreen, - } - fn name(mode: Mode) -> &'static str { - match mode { - Mode::Never => "Never", - Mode::Always => "Always", - Mode::Fullscreen => "Fullscreen", - } - } - let mut mode = match old { - TearingMode::Never => Mode::Never, - TearingMode::Always => Mode::Always, - TearingMode::Fullscreen { .. } => Mode::Fullscreen, - }; - let old_mode = mode; - let mut surface = None; - ui.vertical(|ui| { - ComboBox::from_id_salt("tearing mode") - .selected_text(name(mode)) - .show_ui(ui, |ui| { - for s in Mode::variants() { - ui.selectable_value(&mut mode, s, name(s)); - } - }); - if mode == Mode::Fullscreen { - if old_mode != mode { - surface = Some(Default::default()); - } - if let TearingMode::Fullscreen { surface: s } = old { - surface = s; - } - let mut limit_windows = surface.is_some(); - ui.checkbox(&mut limit_windows, "Limit Windows"); - if !limit_windows { - surface = None; - } else { - ui.indent("limit windows", |ui| { - let surface = surface.get_or_insert_default(); - ui.checkbox(&mut surface.tearing_requested, "Requests Tearing"); - }); - } - } - }); - match mode { - Mode::Never => TearingMode::Never, - Mode::Always => TearingMode::Always, - Mode::Fullscreen => TearingMode::Fullscreen { surface }, - } - }; - let ui = &mut *ui.row(); - grid_label(ui, "Tearing"); - let old = effective!(m, t).tearing_mode; - let v = render_settings(ui, old); - if v != old { - modify!(m, t).tearing_mode = v; - } - let diff = v != m.tearing_mode; - if diff { - ui.add_enabled_ui(false, |ui| { - render_settings(ui, m.tearing_mode); - }); - } - diff -} - -fn show_vrr(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - if let Some(info) = &m.monitor_info - && !info.vrr_capable - { - return false; - } - { - let ui = &mut *ui.row(); - grid_label(ui, "VRR Active"); - ui.label(effective!(m, t).vrr.to_string()); - } - let render_settings = |ui: &mut Ui, old: VrrMode| { - #[derive(Copy, Clone, PartialEq, Linearize)] - enum Mode { - Never, - Always, - Fullscreen, - } - fn name(mode: Mode) -> &'static str { - match mode { - Mode::Never => "Never", - Mode::Always => "Always", - Mode::Fullscreen => "Fullscreen", - } - } - let mut mode = match old { - VrrMode::Never => Mode::Never, - VrrMode::Always => Mode::Always, - VrrMode::Fullscreen { .. } => Mode::Fullscreen, - }; - let mut surface = None; - ui.vertical(|ui| { - ComboBox::from_id_salt("vrr mode") - .selected_text(name(mode)) - .show_ui(ui, |ui| { - for s in Mode::variants() { - ui.selectable_value(&mut mode, s, name(s)); - } - }); - if mode == Mode::Fullscreen { - if let VrrMode::Fullscreen { surface: s } = old { - surface = s; - } - let mut limit_windows = surface.is_some(); - ui.checkbox(&mut limit_windows, "Limit Windows"); - if !limit_windows { - surface = None; - } else { - ui.indent("limit windows", |ui| { - let surface = surface.get_or_insert_default(); - let mut limit_content_type = surface.content_type.is_some(); - ui.checkbox(&mut limit_content_type, "Limit Content Types"); - if !limit_content_type { - surface.content_type = None; - } else { - ui.indent("limit content type", |ui| { - let limit = surface.content_type.get_or_insert_default(); - let fields = [ - ("Photos", &mut limit.photo), - ("Videos", &mut limit.video), - ("Games", &mut limit.game), - ]; - for (name, field) in fields { - ui.checkbox(field, name); - } - }); - } - }); - } - } - }); - match mode { - Mode::Never => VrrMode::Never, - Mode::Always => VrrMode::Always, - Mode::Fullscreen => VrrMode::Fullscreen { surface }, - } - }; - let ui = &mut *ui.row(); - grid_label(ui, "VRR"); - let old = effective!(m, t).vrr_mode; - let v = render_settings(ui, old); - if v != old { - modify!(m, t).vrr_mode = v; - } - let diff = v != m.vrr_mode; - if diff { - ui.add_enabled_ui(false, |ui| { - render_settings(ui, m.vrr_mode); - }); - } - diff -} - -fn show_non_desktop(state: &State, ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - { - let ui = &mut *ui.row(); - grid_label(ui, "Non-desktop"); - if m.inherent_non_desktop { - ui.label("Yes"); - } else { - ui.label("No"); - } - } - - let ui = &mut *ui.row(); - grid_label(ui, "Override"); - let mut v = effective!(m, t).override_non_desktop; - let mut changed = false; - let name = |v: Option| match v { - None => "None", - Some(false) => "Desktop", - Some(true) => "Non-Desktop", - }; - ComboBox::from_id_salt("non-desktop-override") - .selected_text(name(v)) - .show_ui(ui, |ui| { - for s in [None, Some(false), Some(true)] { - changed |= ui.selectable_value(&mut v, s, name(s)).changed(); - } - }); - if changed { - let t = modify!(m, t); - t.override_non_desktop = v; - t.update_in_compositor_space(state, m.wl_output); - } - let diff = v != m.override_non_desktop; - if diff { - ui.label(name(m.override_non_desktop)); - } - diff -} - -fn show_blend_space(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - let ui = &mut *ui.row(); - grid_label(ui, "Blend Space"); - let mut v = effective!(m, t).blend_space; - ui.horizontal(|ui| { - let mut changed = false; - ComboBox::from_id_salt("blend-space") - .selected_text(v.name()) - .show_ui(ui, |ui| { - for s in BlendSpace::variants() { - changed |= ui.selectable_value(&mut v, s, s.name()).changed(); - } - }); - if changed { - modify!(m, t).blend_space = v; - } - }); - let diff = m.blend_space != v; - if diff { - ui.label(m.blend_space.name()); - } - diff -} - -fn show_use_native_gamut(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - let ui = &mut *ui.row(); - grid_label(ui, "Use Native Gamut"); - let mut use_native_gamut = effective!(m, t).use_native_gamut; - if Checkbox::without_text(&mut use_native_gamut) - .ui(ui) - .changed() - { - modify!(m, t).use_native_gamut = use_native_gamut; - } - let diff = m.use_native_gamut != use_native_gamut; - if diff { - let mut old = m.use_native_gamut; - ui.add_enabled(false, Checkbox::without_text(&mut old)); - } - diff -} - -fn show_native_gamut(ui: &mut Ui, m: &HeadState) { - let Some(info) = &m.monitor_info else { - return; - }; - let p = info.primaries; - let ui = &mut *ui.row(); - grid_label(ui, "Native Gamut"); - Grid::new("native gamut").show(ui, |ui| { - let fields = [ - ("red:", p.r), - ("green:", p.g), - ("blue:", p.b), - ("white:", p.wp), - ]; - for (name, field) in fields { - let ui = &mut *ui.row(); - ui.label(name); - ui.label(format!("{:.6}", field.0)); - ui.label(format!("{:.6}", field.1)); - } - }); -} - -fn show_cursor_hz(ui: &mut Ui, m: &HeadState, t: &mut Option) -> bool { - if !effective!(m, t).in_compositor_space { - return false; - } - let old_cursor_hz = effective!(m, t).vrr_cursor_hz.is_some(); - let mut custom_cursor_hz = old_cursor_hz; - let mut changed = false; - grid_label(ui, "Limit Cursor HZ"); - Checkbox::without_text(&mut custom_cursor_hz).ui(ui); - changed |= old_cursor_hz != custom_cursor_hz; - let diff1 = m.vrr_cursor_hz.is_some() != custom_cursor_hz; - if diff1 { - ui.label(match m.vrr_cursor_hz.is_some() { - true => "enabled", - false => "disabled", - }); - } - ui.end_row(); - - if !custom_cursor_hz { - if changed { - modify!(m, t).vrr_cursor_hz = None; - } - return diff1; - } - - grid_label(ui, "Cursor HZ"); - let mut cursor_hz = effective!(m, t).vrr_cursor_hz.unwrap_or(60.0); - changed |= DragValue::new(&mut cursor_hz) - .range(0.0..=500.0) - .ui(ui) - .changed(); - if changed { - modify!(m, t).vrr_cursor_hz = Some(cursor_hz); - } - let mut diff2 = false; - if let Some(t) = t - && m.vrr_cursor_hz != t.vrr_cursor_hz - { - diff2 = true; - ui.label(format!( - "{}", - fmt::from_fn(|f| match m.vrr_cursor_hz { - None => f.write_str("disabled"), - Some(v) => write!(f, "{}", v), - }) - )); - } - ui.end_row(); - diff1 || diff2 -} - -fn show_flip_margin( - state: &State, - ui: &mut Ui, - m: &HeadState, - t: &mut Option, - connector_id: ConnectorId, -) { - if !effective!(m, t).in_compositor_space { - return; - } - let Some(node) = state.root.outputs.get(&connector_id) else { - return; - }; - let Some(margin) = node.flip_margin_ns.get() else { - return; - }; - label( - ui, - "Flip Margin (ms)", - format!("{}", margin as f64 / 1_000_000.0), - ); -} diff --git a/src/control_center/cc_sidebar.rs b/src/control_center/cc_sidebar.rs deleted file mode 100644 index e444f853..00000000 --- a/src/control_center/cc_sidebar.rs +++ /dev/null @@ -1,97 +0,0 @@ -use { - crate::control_center::{ControlCenterInner, Pane, PaneType}, - egui::{Align, Layout, ScrollArea, Ui, ViewportCommand}, - egui_tiles::Tree, - linearize::{Linearize, LinearizeExt}, - std::{rc::Rc, sync::LazyLock}, -}; - -#[derive(Copy, Clone, Linearize)] -enum PaneName { - Compositor, - Idle, - ColorManagement, - Xwayland, - Outputs, - GPUs, - Input, - LookAndFeel, - Clients, - WindowSearch, - VirtualOutputs, -} - -impl PaneName { - fn name(self) -> &'static str { - match self { - PaneName::Compositor => "Compositor", - PaneName::Idle => "Idle", - PaneName::ColorManagement => "Color Management", - PaneName::Xwayland => "Xwayland", - PaneName::Outputs => "Outputs", - PaneName::GPUs => "GPUs", - PaneName::Input => "Input", - PaneName::LookAndFeel => "Look and Feel", - PaneName::Clients => "Clients", - PaneName::WindowSearch => "Window Search", - PaneName::VirtualOutputs => "Virtual Outputs", - } - } -} - -static TYPES: LazyLock> = LazyLock::new(|| { - let mut res: Vec<_> = PaneName::variants().collect(); - res.sort_by_key(|t| t.name()); - res -}); - -impl ControlCenterInner { - pub fn show_sidebar(self: &Rc, tree: &mut Tree, ui: &mut Ui) { - ui.with_layout( - Layout::top_down(Align::Center).with_cross_justify(true), - |ui| { - ui.add_space(6.0); - if ui.button("Close").clicked() { - ui.send_viewport_cmd(ViewportCommand::Close); - } - ui.separator(); - ScrollArea::vertical().show(ui, |ui| { - for &ty in &*TYPES { - if ui.button(ty.name()).clicked() { - let ty = match ty { - PaneName::Compositor => { - PaneType::Compositor(self.create_compositor_pane()) - } - PaneName::Idle => PaneType::Idle(self.create_idle_pane()), - PaneName::ColorManagement => { - PaneType::ColorManagement(self.create_color_management_pane()) - } - PaneName::Xwayland => { - PaneType::Xwayland(self.create_xwayland_pane()) - } - PaneName::Outputs => { - PaneType::Outputs(Box::new(self.create_outputs_pane())) - } - PaneName::GPUs => PaneType::GPUs(self.create_gpus_pane()), - PaneName::Input => PaneType::Input(self.create_input_pane()), - PaneName::LookAndFeel => { - PaneType::LookAndFeel(self.create_look_and_feel_pane()) - } - PaneName::Clients => PaneType::Clients(self.create_clients_pane()), - PaneName::WindowSearch => { - PaneType::WindowSearch(self.create_window_search_pane()) - } - PaneName::VirtualOutputs => { - PaneType::VirtualOutputs(self.create_virtual_outputs_pane()) - } - }; - self.open(tree, ty); - ui.request_repaint(); - } - } - ui.add_space(3.0); - }) - }, - ); - } -} diff --git a/src/control_center/cc_virtual_outputs.rs b/src/control_center/cc_virtual_outputs.rs deleted file mode 100644 index b4d96673..00000000 --- a/src/control_center/cc_virtual_outputs.rs +++ /dev/null @@ -1,49 +0,0 @@ -use { - crate::{ - control_center::ControlCenterInner, egui_adapter::egui_platform::icons::ICON_CLOSE, - state::State, - }, - egui::Ui, - std::rc::Rc, -}; - -pub struct VirtualOutputsPane { - state: Rc, - new: String, -} - -impl ControlCenterInner { - pub fn create_virtual_outputs_pane(self: &Rc) -> VirtualOutputsPane { - VirtualOutputsPane { - state: self.state.clone(), - new: Default::default(), - } - } -} - -impl VirtualOutputsPane { - pub fn title(&self, res: &mut String) { - res.push_str("Virtual Outputs"); - } - - pub fn show(&mut self, ui: &mut Ui) { - let s = &self.state; - let mut outputs: Vec<_> = s.virtual_outputs.outputs.lock().keys().cloned().collect(); - outputs.sort(); - for o in &outputs { - ui.horizontal(|ui| { - if ui.button(ICON_CLOSE).clicked() { - s.virtual_outputs.remove_output(s, o); - } - ui.label(o); - }); - } - ui.horizontal(|ui| { - ui.text_edit_singleline(&mut self.new); - if ui.button("Add").clicked() { - s.virtual_outputs.get_or_create(s, &self.new); - ui.request_repaint(); - } - }); - } -} diff --git a/src/control_center/cc_window.rs b/src/control_center/cc_window.rs deleted file mode 100644 index 34974033..00000000 --- a/src/control_center/cc_window.rs +++ /dev/null @@ -1,475 +0,0 @@ -use { - crate::{ - control_center::{ - CcBehavior, ControlCenterInner, PaneType, - cc_clients::{ClientCrit, show_client_collapsible}, - cc_criterion::{CcCriterion, CritImpl, CritRegex}, - grid, icon_label, label, read_only_bool, - }, - criteria::{CritMgrExt, CritUpstreamNode, crit_leaf::CritLeafMatcher}, - egui_adapter::egui_platform::icons::ICON_OPEN_IN_NEW, - state::State, - tree::{NodeId, ToplevelData, ToplevelIdentifier, ToplevelNode, ToplevelType}, - utils::{ - copyhashmap::CopyHashMap, - event_listener::{EventListener, LazyEventSourceListener}, - static_text::StaticText, - }, - }, - ahash::AHashMap, - egui::{CollapsingHeader, Sense, TextFormat, Ui, Widget, cache::CacheTrait, text::LayoutJob}, - isnt::std_1::primitive::IsntStrExt, - jay_config::window::{ - ContentType, GAME_CONTENT, NO_CONTENT_TYPE, PHOTO_CONTENT, VIDEO_CONTENT, - }, - linearize::Linearize, - std::{ - mem, - rc::{Rc, Weak}, - }, -}; - -enum WindowClit { - Client(CcCriterion), - Title(CritRegex), - AppId(CritRegex), - Floating, - Visible, - Urgent, - Fullscreen, - Tag(CritRegex), - XClass(CritRegex), - XInstance(CritRegex), - XRole(CritRegex), - Workspace(CritRegex), - ContentTypes(ContentType), -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Linearize)] -enum WindowCritTy { - Client, - Title, - AppId, - Floating, - Visible, - Urgent, - Fullscreen, - Tag, - XClass, - XInstance, - XRole, - Workspace, - ContentTypes, -} - -impl Default for WindowClit { - fn default() -> Self { - WindowClit::Title(Default::default()) - } -} - -impl StaticText for WindowCritTy { - fn text(&self) -> &'static str { - match self { - WindowCritTy::Client => "Client", - WindowCritTy::Title => "Title", - WindowCritTy::AppId => "App ID", - WindowCritTy::Floating => "Floating", - WindowCritTy::Visible => "Visible", - WindowCritTy::Urgent => "Urgent", - WindowCritTy::Fullscreen => "Fullscreen", - WindowCritTy::Tag => "Tag", - WindowCritTy::XClass => "X Class", - WindowCritTy::XInstance => "X Instance", - WindowCritTy::XRole => "X Role", - WindowCritTy::Workspace => "Workspace", - WindowCritTy::ContentTypes => "Content Types", - } - } -} - -impl CritImpl for WindowClit { - type Type = WindowCritTy; - type Target = ToplevelData; - - fn ty(&self) -> Self::Type { - macro_rules! map { - ($($n:ident,)*) => { - match self { - $( - Self::$n { .. } => WindowCritTy::$n, - )* - } - }; - } - map! { - Client, - Title, - AppId, - Floating, - Visible, - Urgent, - Fullscreen, - Tag, - XClass, - XInstance, - XRole, - Workspace, - ContentTypes, - } - } - - fn from_ty(ty: Self::Type) -> Self { - match ty { - WindowCritTy::Client => Self::Client(Default::default()), - WindowCritTy::Title => Self::Title(Default::default()), - WindowCritTy::AppId => Self::AppId(Default::default()), - WindowCritTy::Floating => Self::Floating, - WindowCritTy::Visible => Self::Visible, - WindowCritTy::Urgent => Self::Urgent, - WindowCritTy::Fullscreen => Self::Fullscreen, - WindowCritTy::Tag => Self::Tag(Default::default()), - WindowCritTy::XClass => Self::XClass(Default::default()), - WindowCritTy::XInstance => Self::XInstance(Default::default()), - WindowCritTy::XRole => Self::XRole(Default::default()), - WindowCritTy::Workspace => Self::Workspace(Default::default()), - WindowCritTy::ContentTypes => { - Self::ContentTypes(PHOTO_CONTENT | VIDEO_CONTENT | GAME_CONTENT) - } - } - } - - fn show(&mut self, ui: &mut Ui) -> bool { - match self { - WindowClit::Client(v) => v.show(ui), - WindowClit::Title(v) => v.show(ui), - WindowClit::AppId(v) => v.show(ui), - WindowClit::Floating => false, - WindowClit::Visible => false, - WindowClit::Urgent => false, - WindowClit::Fullscreen => false, - WindowClit::Tag(v) => v.show(ui), - WindowClit::XClass(v) => v.show(ui), - WindowClit::XInstance(v) => v.show(ui), - WindowClit::XRole(v) => v.show(ui), - WindowClit::Workspace(v) => v.show(ui), - WindowClit::ContentTypes(v) => show_content_types(ui, v), - } - } - - fn to_crit(&self, state: &Rc) -> Option>> { - let m = &state.tl_matcher_manager; - let res = match self { - WindowClit::Client(v) => m.client(state, &v.to_crit(state)?), - WindowClit::Title(v) => m.title(v.to_crit()?), - WindowClit::AppId(v) => m.app_id(v.to_crit()?), - WindowClit::Floating => m.floating(), - WindowClit::Visible => m.visible(), - WindowClit::Urgent => m.urgent(), - WindowClit::Fullscreen => m.fullscreen(), - WindowClit::Tag(v) => m.tag(v.to_crit()?), - WindowClit::XClass(v) => m.class(v.to_crit()?), - WindowClit::XInstance(v) => m.instance(v.to_crit()?), - WindowClit::XRole(v) => m.role(v.to_crit()?), - WindowClit::Workspace(v) => m.workspace(v.to_crit()?), - WindowClit::ContentTypes(v) => m.content_type(*v), - }; - Some(res) - } - - fn not( - state: &State, - upstream: &Rc>, - ) -> Rc> { - state.tl_matcher_manager.not(upstream) - } - - fn list( - state: &State, - upstream: &[Rc>], - all: bool, - ) -> Rc> { - state.tl_matcher_manager.list(upstream, all) - } - - fn exactly( - state: &State, - n: usize, - upstream: &[Rc>], - ) -> Rc> { - state.tl_matcher_manager.exactly(upstream, n) - } -} - -pub struct WindowSearchPane { - state: Rc, - criterion: CcCriterion, - matched: Rc, - leaf: Option>>, -} - -struct Matched { - slf: Weak, - windows: CopyHashMap, -} - -impl Matched { - fn request_frame(&self) { - if let Some(slf) = self.slf.upgrade() { - slf.window.request_redraw(); - } - } -} - -impl ControlCenterInner { - pub fn create_window_search_pane(self: &Rc) -> WindowSearchPane { - let mut pane = WindowSearchPane { - state: self.state.clone(), - criterion: Default::default(), - matched: Rc::new(Matched { - slf: Rc::downgrade(self), - windows: Default::default(), - }), - leaf: Default::default(), - }; - pane.update_matcher(); - pane - } -} - -impl WindowSearchPane { - pub fn title(&self, res: &mut String) { - res.push_str("Window Search"); - } - - pub fn show(&mut self, behavior: &mut CcBehavior<'_>, ui: &mut Ui) { - let mut clear = false; - if self.criterion.show(ui) { - clear = self.update_matcher(); - } - ui.separator(); - let mut windows: Vec<_> = self.matched.windows.lock().keys().copied().collect(); - windows.sort(); - for id in windows { - let Some(window) = self.state.toplevels.get(&id).and_then(|v| v.upgrade()) else { - continue; - }; - show_window_collapsible(behavior, ui, &window); - } - if clear { - self.matched.windows.clear(); - } - } - - fn update_matcher(&mut self) -> bool { - let mut clear = false; - let state = &self.state; - if let Some(new) = self.criterion.to_crit(state) { - clear = true; - let matched = self.matched.clone(); - let leaf = state.tl_matcher_manager.leaf(&new, move |data| { - matched.windows.set(data, ()); - matched.request_frame(); - Box::new({ - let matched = matched.clone(); - move || { - matched.windows.remove(&data); - matched.request_frame(); - } - }) - }); - state.tl_matcher_manager.rematch_all(state); - if self.criterion.any(|c| matches!(c, WindowClit::Client(_))) { - state.cl_matcher_manager.rematch_all(state); - } - self.leaf = Some(leaf); - } - clear - } -} - -pub struct WindowPane { - window: Rc, -} - -impl ControlCenterInner { - pub fn create_window_pane(self: &Rc, window: &Rc) -> WindowPane { - WindowPane { - window: window.clone(), - } - } -} - -impl WindowPane { - pub fn title(&self, res: &mut String) { - res.push_str("Window"); - } - - pub fn show(&mut self, behavior: &mut CcBehavior<'_>, ui: &mut Ui) { - show_window(behavior, ui, &*self.window) - } -} - -pub fn show_window_collapsible( - behavior: &mut CcBehavior, - ui: &mut Ui, - window: &Rc, -) { - let data = window.tl_data(); - let mut layout_job = LayoutJob::default(); - layout_job.append( - "Window", - 0.0, - TextFormat { - color: ui.style().visuals.widgets.inactive.text_color(), - ..Default::default() - }, - ); - layout_job.append( - &data.title.borrow(), - 10.0, - TextFormat { - color: ui.style().visuals.widgets.active.text_color(), - ..Default::default() - }, - ); - let closed = CollapsingHeader::new(layout_job) - .id_salt(("window", data.identifier.get())) - .show(ui, |ui| { - if icon_label(ICON_OPEN_IN_NEW) - .sense(Sense::CLICK) - .ui(ui) - .clicked() - { - behavior.open = Some(PaneType::Window(behavior.cc.create_window_pane(window))); - } - show_window(behavior, ui, &**window) - }) - .fully_closed(); - if closed { - ensure_listener(ui, behavior, data); - } -} - -pub fn show_window(behavior: &mut CcBehavior<'_>, ui: &mut Ui, window: &dyn ToplevelNode) { - let data = window.tl_data(); - ensure_listener(ui, behavior, data); - grid(ui, ("window", data.identifier.get()), |ui| { - label(ui, "ID", &*data.identifier.get().to_string()); - label(ui, "Title", &*data.title.borrow()); - if let Some(w) = data.workspace.get() { - label(ui, "Workspace", &w.name); - } - match &data.kind { - ToplevelType::Container => { - label(ui, "Type", "Container"); - } - ToplevelType::Placeholder(_) => { - label(ui, "Type", "Placeholder"); - } - ToplevelType::XdgToplevel(t) => { - label(ui, "Type", "xdg_toplevel"); - let tag = &*t.tag.borrow(); - if tag.is_not_empty() { - label(ui, "Tag", tag); - } - } - ToplevelType::XWindow(t) => { - label(ui, "Type", "X Window"); - if let Some(class) = &*t.info.class.borrow() { - label(ui, "Class", class); - } - if let Some(instance) = &*t.info.instance.borrow() { - label(ui, "Instance", instance); - } - if let Some(role) = &*t.info.role.borrow() { - label(ui, "Role", role); - } - } - } - let app_id = &*data.app_id.borrow(); - if app_id.is_not_empty() { - label(ui, "App ID", app_id); - } - read_only_bool(ui, "Floating", data.parent_is_float.get()); - read_only_bool(ui, "Visible", data.visible.get()); - read_only_bool(ui, "Urgent", data.wants_attention.get()); - read_only_bool(ui, "Fullscreen", data.is_fullscreen.get()); - if let Some(ct) = data.content_type.get() { - label(ui, "Content Type", ct.text()); - } - }); - if let Some(client) = &data.client { - show_client_collapsible(behavior, ui, client); - } -} - -fn ensure_listener(ui: &mut Ui, behavior: &CcBehavior<'_>, data: &ToplevelData) { - ui.memory_mut(|m| { - m.caches - .cache::() - .ensure(behavior.cc, data); - }); -} - -#[derive(Default)] -struct WindowPropertyListeners { - generation: u64, - listeners: AHashMap, -} - -struct WindowPropertyListener { - _listener: EventListener, - generation: u64, -} - -impl WindowPropertyListeners { - fn ensure(&mut self, cc: &Rc, data: &ToplevelData) { - let listener = self.listeners.entry(data.node_id).or_insert_with(|| { - let listener = - EventListener::new(Rc::downgrade(cc) as Weak); - listener.attach(data.property_changed_source()); - WindowPropertyListener { - _listener: listener, - generation: 0, - } - }); - listener.generation = self.generation; - } -} - -unsafe impl Sync for WindowPropertyListeners {} -unsafe impl Send for WindowPropertyListeners {} - -impl CacheTrait for WindowPropertyListeners { - fn update(&mut self) { - self.listeners - .retain(|_, m| m.generation == self.generation); - self.generation += 1; - } - - fn len(&self) -> usize { - self.listeners.len() - } -} - -fn show_content_types(ui: &mut Ui, ct: &mut ContentType) -> bool { - let mut v = *ct; - let mut photo = (v & PHOTO_CONTENT).0 != 0; - let mut video = (v & VIDEO_CONTENT).0 != 0; - let mut game = (v & GAME_CONTENT).0 != 0; - ui.checkbox(&mut photo, "Photo"); - ui.checkbox(&mut video, "Video"); - ui.checkbox(&mut game, "Game"); - v = NO_CONTENT_TYPE; - if photo { - v |= PHOTO_CONTENT; - } - if video { - v |= VIDEO_CONTENT; - } - if game { - v |= GAME_CONTENT; - } - mem::replace(ct, v) != v -} diff --git a/src/control_center/cc_xwayland.rs b/src/control_center/cc_xwayland.rs deleted file mode 100644 index 292c9fe7..00000000 --- a/src/control_center/cc_xwayland.rs +++ /dev/null @@ -1,91 +0,0 @@ -use { - crate::{ - compositor::DISPLAY, - control_center::{ - CcBehavior, ControlCenterInner, bool, cc_clients::show_client_collapsible, - combo_box_ui, grid, label, read_only_bool, tip, - }, - state::State, - utils::{errorfmt::ErrorFmt, oserror::OsErrorExt, static_text::StaticText}, - }, - egui::Ui, - linearize::Linearize, - std::rc::Rc, - uapi::c, -}; - -pub struct XwaylandPane { - state: Rc, -} - -impl ControlCenterInner { - pub fn create_xwayland_pane(self: &Rc) -> XwaylandPane { - XwaylandPane { - state: self.state.clone(), - } - } -} - -#[derive(Copy, Clone, PartialEq, Linearize)] -enum ScalingMode { - Default, - Downscaled, -} - -impl StaticText for ScalingMode { - fn text(&self) -> &'static str { - match self { - ScalingMode::Default => "default", - ScalingMode::Downscaled => "downscaled", - } - } -} - -impl XwaylandPane { - pub fn title(&self, res: &mut String) { - res.push_str("Xwayland"); - } - - pub fn show(&mut self, behavior: &mut CcBehavior<'_>, ui: &mut Ui) { - let s = &self.state; - grid(ui, "settings", |ui| { - bool(ui, "Enabled", s.xwayland.enabled.get(), |b| { - s.set_xwayland_enabled(b) - }); - let mode = match self.state.xwayland.use_wire_scale.get() { - true => ScalingMode::Downscaled, - false => ScalingMode::Default, - }; - combo_box_ui( - ui, - "Scaling Mode", - |ui| { - tip(ui, |ui| { - ui.label(r#"`downscaled` is known as "X applications scale themselves""#); - }); - }, - mode, - |v| { - self.state - .set_xwayland_use_wire_scale(v == ScalingMode::Downscaled); - }, - ); - if let Some(display) = self.state.xwayland.display.get() { - label(ui, DISPLAY, &*display); - } - read_only_bool(ui, "Running", self.state.xwayland.running.get()); - if let Some(client) = self.state.xwayland.client.get() { - label(ui, "PID", client.pid_info.pid.to_string()); - } - }); - if let Some(client) = self.state.xwayland.client.get() - && ui.button("Kill").clicked() - && let Err(e) = uapi::kill(client.pid_info.pid, c::SIGTERM).to_os_error() - { - log::error!("Could not kill Xwayland: {}", ErrorFmt(e)); - } - if let Some(client) = self.state.xwayland.client.get() { - show_client_collapsible(behavior, ui, &client); - } - } -} diff --git a/src/criteria/clm.rs b/src/criteria/clm.rs index 7a3175cb..80a79784 100644 --- a/src/criteria/clm.rs +++ b/src/criteria/clm.rs @@ -234,9 +234,6 @@ impl ClMatcherManager { self.root(ClmMatchTag::new(string)) } - pub fn id(&self, id: ClientId) -> Rc { - self.root(ClmMatchId(id)) - } } impl CritTarget for Rc { diff --git a/src/cursor_user.rs b/src/cursor_user.rs index e79beade..2af875df 100644 --- a/src/cursor_user.rs +++ b/src/cursor_user.rs @@ -1,7 +1,6 @@ use { crate::{ backend::HardwareCursorUpdate, - control_center::CCI_INPUT, cursor::{Cursor, DEFAULT_CURSOR_SIZE, KnownCursor}, fixed::Fixed, gfx_api::{AcquireSync, ReleaseSync}, @@ -184,7 +183,6 @@ impl CursorUserGroup { self.remove_hardware_cursor(); self.state.cursor_user_group_hardware_cursor.take(); } - self.state.trigger_cci(CCI_INPUT); } pub fn hardware_cursor(&self) -> bool { @@ -197,13 +195,9 @@ impl CursorUserGroup { self.state.remove_cursor_size(old); self.state.add_cursor_size(size); self.reload_known_cursor(); - self.state.trigger_cci(CCI_INPUT); } } - pub fn cursor_size(&self) -> u32 { - self.size.get() - } fn output_center(&self, output: &Rc) -> (Fixed, Fixed) { let pos = output.global.pos.get(); diff --git a/src/egui_adapter.rs b/src/egui_adapter.rs deleted file mode 100644 index c9939c56..00000000 --- a/src/egui_adapter.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod egui_oklch; -pub mod egui_platform; -mod egui_vulkan; diff --git a/src/egui_adapter/egui_oklch.rs b/src/egui_adapter/egui_oklch.rs deleted file mode 100644 index dedbb4d3..00000000 --- a/src/egui_adapter/egui_oklch.rs +++ /dev/null @@ -1,36 +0,0 @@ -use { - crate::{ - cmm::cmm_eotf::Eotf, - theme::{Color, Oklab, Oklch}, - }, - egui::{Color32, Rgba}, -}; - -pub trait Color32Ext { - fn to_oklab(self) -> Oklab; - fn to_oklch(self) -> Oklch; -} - -impl Color32Ext for Color32 { - fn to_oklab(self) -> Oklab { - let [r, g, b, a] = self.to_array(); - Color::from_srgba_premultiplied(r, g, b, a).srgb_to_oklab() - } - - fn to_oklch(self) -> Oklch { - self.to_oklab().to_oklch() - } -} - -impl Into for Oklch { - fn into(self) -> Color32 { - self.to_oklab().into() - } -} - -impl Into for Oklab { - fn into(self) -> Color32 { - let [r, g, b, a] = self.to_srgb().to_array(Eotf::Linear); - Rgba::from_rgba_premultiplied(r, g, b, a).into() - } -} diff --git a/src/egui_adapter/egui_platform.rs b/src/egui_adapter/egui_platform.rs deleted file mode 100644 index 86d8fef2..00000000 --- a/src/egui_adapter/egui_platform.rs +++ /dev/null @@ -1,1445 +0,0 @@ -use { - crate::{ - allocator::{Allocator, AllocatorError, BO_USE_RENDERING, BufferObject}, - async_engine::SpawnedFuture, - client::{Client, ClientCaps, ClientError}, - cursor::KnownCursor, - egui_adapter::egui_vulkan::{ - EGV_FORMAT, EgvContext, EgvError, EgvFramebuffer, EgvRenderer, - }, - fixed::Fixed, - fontconfig::match_font, - gfx_api::SyncFile, - globals::{GlobalName, Singleton}, - ifs::wl_seat::{ - BTN_EXTRA, BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, BTN_SIDE, - wl_pointer::{self, HORIZONTAL_SCROLL, PendingScroll, VERTICAL_SCROLL}, - }, - object::Version, - scale::Scale, - security_context_acceptor::AcceptorMetadata, - state::State, - utils::{ - asyncevent::AsyncEvent, - buf::Buf, - clonecell::CloneCell, - copyhashmap::CopyHashMap, - double_buffered::DoubleBuffered, - errorfmt::ErrorFmt, - object_drop_queue::ObjectDropQueue, - oserror::{OsError, OsErrorExt2}, - pipe::{Pipe, pipe}, - rc_eq::rc_eq, - }, - video::{dmabuf::DMA_BUF_SYNC_WRITE, drm::DrmError}, - wire::{ - WlSurfaceId, - wl_pointer::{Button, Enter, Leave, Motion}, - wp_fractional_scale_v1::PreferredScale, - }, - wl_usr::{ - UsrCon, UsrConOwner, - usr_ifs::{ - usr_jay_compositor::UsrJayCompositor, - usr_jay_sync_file_release::UsrJaySyncFileReleaseOwner, - usr_jay_sync_file_surface::UsrJaySyncFileSurface, - usr_wl_buffer::UsrWlBuffer, - usr_wl_callback::UsrWlCallbackOwner, - usr_wl_compositor::UsrWlCompositor, - usr_wl_data_device::UsrWlDataDevice, - usr_wl_data_device_manager::UsrWlDataDeviceManager, - usr_wl_data_source::{UsrWlDataSource, UsrWlDataSourceOwner}, - usr_wl_keyboard::{UsrWlKeyboard, UsrWlKeyboardOwner}, - usr_wl_pointer::{UsrWlPointer, UsrWlPointerOwner}, - usr_wl_registry::UsrWlRegistry, - usr_wl_seat::UsrWlSeat, - usr_wl_surface::UsrWlSurface, - usr_wp_cursor_shape_device_v1::UsrWpCursorShapeDeviceV1, - usr_wp_cursor_shape_manager_v1::UsrWpCursorShapeManagerV1, - usr_wp_fractional_scale::{UsrWpFractionalScale, UsrWpFractionalScaleOwner}, - usr_wp_fractional_scale_manager::UsrWpFractionalScaleManager, - usr_wp_viewport::UsrWpViewport, - usr_wp_viewporter::UsrWpViewporter, - usr_xdg_surface::{UsrXdgSurface, UsrXdgSurfaceOwner}, - usr_xdg_toplevel::{UsrXdgToplevel, UsrXdgToplevelOwner}, - usr_xdg_wm_base::UsrXdgWmBase, - usr_zwp_linux_dmabuf_v1::UsrZwpLinuxDmabufV1, - usr_zwp_primary_selection_device_manager::UsrZwpPrimarySelectionDeviceManagerV1, - }, - }, - }, - egui::{ - CursorIcon, Event, FontData, FontDefinitions, FontFamily, FullOutput, Key, Modifiers, - MouseWheelUnit, OutputCommand, PlatformOutput, PointerButton, Pos2, RawInput, TouchPhase, - Vec2, ViewportCommand, ViewportEvent, ViewportId, ViewportInfo, pos2, vec2, - }, - futures_util::{FutureExt, select}, - isnt::std_1::primitive::{IsntCharExt, IsntSliceExt, IsntStrExt}, - kbvm::{Keysym, ModifierMask, lookup::Lookup}, - std::{ - cell::{Cell, RefCell}, - collections::btree_map::Entry, - fs, mem, - rc::{Rc, Weak}, - sync::Arc, - }, - thiserror::Error, - uapi::{OwnedFd, c}, -}; - -#[derive(Debug, Error)] -pub enum EggError { - #[error("Could not create a socket pair")] - CreateSocketPair(#[source] OsError), - #[error("Could not spawn a client")] - SpawnClient(#[source] ClientError), - #[error("Could not create a renderer")] - CreateRenderer(#[source] EgvError), - #[error("There is no render context")] - NoRenderContext, - #[error("Could not allocate a buffer")] - AllocateBuffer(#[source] AllocatorError), - #[error("Could not import a framebuffer")] - ImportFramebuffer(#[source] EgvError), - #[error("Could not render")] - Render(#[source] EgvError), - #[error("No viewport output")] - NoViewportOutput, - #[error("Could not export initial dmabuf sync file")] - ExportBoSyncFile(#[source] DrmError), -} - -pub mod icons { - pub const ICON_ADD: &str = "\u{e145}"; - pub const ICON_CLOSE: &str = "\u{e5cd}"; - pub const ICON_DRAG_INDICATOR: &str = "\u{e945}"; - pub const ICON_INFO: &str = "\u{e88e}"; - pub const ICON_OPEN_IN_NEW: &str = "\u{e89e}"; - pub const ICON_PENDING: &str = "\u{ef64}"; - pub const ICON_REMOVE: &str = "\u{e15b}"; -} - -linear_ids!(EggContextIds, EggContextId, u64); - -pub struct EggState { - fonts: RefCell, - ctx: CloneCell>>, - context_ids: EggContextIds, - cxts: CopyHashMap>, -} - -#[derive(Default)] -struct EggFonts { - definitions: Option, - proportional: Vec, - monospace: Vec, -} - -pub struct EggContext { - inner: Rc, -} - -struct EggContextInner { - id: EggContextId, - renderer: Rc, - allocator: Rc, - state: Rc, - _client: Rc, - con: Rc, - jay_compositor: Rc, - wl_compositor: Rc, - xdg_wm_base: Rc, - wl_data_device_manager: Rc, - _zwp_primary_selection_device_manager_v1: Rc, - wp_viewporter: Rc, - wp_cursor_shape_manager_v1: Rc, - wp_fractional_scale_manager: Rc, - zwp_linux_dmabuf_v1: Rc, - registry: Rc, - windows: CopyHashMap>, - seats: CopyHashMap, -} - -struct EggSeat { - inner: Rc, -} - -pub struct EggSeatInner { - ctx: Rc, - global_name: GlobalName, - wl_seat: Rc, - wl_pointer: Rc, - wl_data_device: Rc, - pointer_window: CloneCell>>, - pointer_enter_serial: Cell, - pointer_serial: Cell, - pointer_pos: Cell, - kb_modifiers: Cell, - wp_cursor_shape_device_v1: Rc, - wl_keyboard: Rc, - kb_window: CloneCell>>, - kb_serial: Cell, - serial: Cell, - wl_data_source: CloneCell>>, - copy_text: RefCell>, - copy_task: Cell>>, - paste_task: Cell>>, -} - -pub struct EggWindow { - _ctx: Rc, - inner: Rc, - _render_task: SpawnedFuture<()>, - _timer_task: SpawnedFuture<()>, -} - -pub trait EggWindowOwner { - fn close(&self); - fn render(self: Rc, ui: &mut egui::Ui); -} - -struct EggWindowInner { - ctx: Rc, - egv: Rc, - egui: egui::Context, - wl_surface: Rc, - wp_viewport: Rc, - wp_fractional_scale: Rc, - xdg_surface: Rc, - xdg_toplevel: Rc, - jay_sync_file_surface: Rc, - frame_task: AsyncEvent, - want_frame: Cell, - have_frame: Cell, - initial_commit_pending: Cell, - owner: CloneCell>>, - active_seat: CloneCell>>, - raw_input: RefCell>, - close: Cell, - repaint_timeout: Cell, - repaint_timeout_changed: AsyncEvent, - fonts_changed: Cell, - - buffers: DoubleBuffered>>>, - - surface_pending: RefCell, - logical_size: Cell<[i32; 2]>, - physical_size: Cell<[i32; 2]>, - scale: Cell, -} - -struct EggFramebuffer { - client_acquire_fence: CloneCell>>, - size: Cell<[i32; 2]>, - bo: Rc, - egv: Rc, - wl_buffer: Rc, - window: Weak, - drop_queue: Rc>>, -} - -#[derive(Default)] -struct PendingWindowState { - size: Option<(i32, i32)>, -} - -const PROPORTIONAL_FONTS: &[&str] = &["sans-serif", "Noto Sans", "Noto Color Emoji"]; - -const MONOSPACE_FONTS: &[&str] = &["monospace", "Noto Sans Mono", "Noto Color Emoji"]; - -impl Default for EggState { - fn default() -> Self { - let slf = Self { - fonts: Default::default(), - ctx: Default::default(), - context_ids: Default::default(), - cxts: Default::default(), - }; - slf.reset_fonts(); - slf - } -} - -impl EggState { - pub fn reset_fonts(&self) { - self.set_proportional_fonts(PROPORTIONAL_FONTS); - self.set_monospace_fonts(MONOSPACE_FONTS); - } - - pub fn set_proportional_fonts(&self, fonts: &[&str]) { - self.change_fonts(fonts, |f| &mut f.proportional) - } - - pub fn set_monospace_fonts(&self, fonts: &[&str]) { - self.change_fonts(fonts, |f| &mut f.monospace) - } - - fn change_fonts(&self, fonts: &[&str], field: impl Fn(&mut EggFonts) -> &mut Vec) { - let f = &mut *self.fonts.borrow_mut(); - let field = field(f); - if *field == fonts { - return; - } - *field = fonts.iter().map(|s| s.to_string()).collect(); - f.definitions.take(); - for ctx in self.cxts.lock().values() { - for window in ctx.windows.lock().values() { - window.fonts_changed.set(true); - window.want_frame(); - } - } - } - - pub fn clear(&self) { - self.ctx.take(); - } - - fn font_definitions(&self) -> FontDefinitions { - let f = &mut self.fonts.borrow_mut(); - if let Some(d) = &f.definitions { - return d.clone(); - } - let mut d = FontDefinitions::empty(); - for (ff, list) in [ - (FontFamily::Proportional, &f.proportional), - (FontFamily::Monospace, &f.monospace), - ] { - for family in list { - let font = match match_font(family) { - Ok(f) => f, - Err(e) => { - log::warn!("Could not find font family {family}: {}", ErrorFmt(e)); - continue; - } - }; - if let Entry::Vacant(e) = d.font_data.entry(font.fullname.clone()) { - let data = match fs::read(&font.file) { - Ok(f) => f, - Err(e) => { - log::error!("Could not read {}: {}", font.file.display(), ErrorFmt(e)); - continue; - } - }; - let data = Arc::new(FontData { - font: data.into(), - index: font.index.unwrap_or(0) as u32, - tweak: Default::default(), - }); - e.insert(data); - } - let list = d.families.entry(ff.clone()).or_default(); - if list.not_contains(&font.fullname) { - list.push(font.fullname); - } - } - } - { - let name = "material-icons"; - let list = d.families.entry(FontFamily::Proportional).or_default(); - if list.iter().all(|n| n != name) { - if let Entry::Vacant(e) = d.font_data.entry(name.to_string()) { - let data = Arc::new(FontData { - font: include_bytes!("icons.ttf").into(), - index: 0, - tweak: Default::default(), - }); - e.insert(data); - } - list.push(name.to_string()); - } - } - f.definitions = Some(d.clone()); - d - } -} - -impl State { - pub fn get_egg_context(self: &Rc) -> Result, EggError> { - if let Some(ctx) = self.egg_state.ctx.get() { - return Ok(ctx); - } - let Some(ctx) = self.render_ctx.get() else { - return Err(EggError::NoRenderContext); - }; - let (client1, client2) = uapi::socketpair(c::AF_UNIX, c::SOCK_STREAM | c::SOCK_CLOEXEC, 0) - .map_os_err(EggError::CreateSocketPair)?; - let allocator = ctx.allocator(); - let dev = allocator.drm().map(|d| d.dev()); - let renderer = EgvRenderer::new(&self.eng, &self.ring, &self.eventfd_cache, dev) - .map_err(EggError::CreateRenderer)?; - let con = UsrCon::from_socket( - &self.ring, - &self.wheel, - &self.eng, - &self.dma_buf_ids, - &Rc::new(client1), - 0, - ); - let client = self - .clients - .spawn2( - self.clients.id(), - self, - Rc::new(client2), - uapi::getuid(), - uapi::getpid(), - ClientCaps::all(), - true, - false, - &Rc::new(AcceptorMetadata::secure()), - ) - .map_err(EggError::SpawnClient)?; - let registry = con.get_registry(); - let jay_compositor = { - let obj = Rc::new(UsrJayCompositor { - id: con.id(), - con: con.clone(), - owner: Default::default(), - caps: Default::default(), - version: Version(27), - }); - registry.bind(self.globals.singletons[Singleton::JayCompositor], &*obj); - con.add_object(obj.clone()); - obj - }; - macro_rules! add_singletons { - ($($name:ident, $global:ident, $ty:ident, $version:expr;)*) => { - $( - let $name = Rc::new($ty { - id: con.id(), - con: con.clone(), - version: Version($version), - }); - registry.bind(self.globals.singletons[Singleton::$global], &*$name); - con.add_object($name.clone()); - )* - }; - } - add_singletons! { - wl_compositor, WlCompositor, UsrWlCompositor, 6; - xdg_wm_base, XdgWmBase, UsrXdgWmBase, 7; - wl_data_device_manager, WlDataDeviceManager, UsrWlDataDeviceManager, 3; - zwp_primary_selection_device_manager_v1, ZwpPrimarySelectionDeviceManagerV1, UsrZwpPrimarySelectionDeviceManagerV1, 1; - wp_viewporter, WpViewporter, UsrWpViewporter, 1; - wp_cursor_shape_manager_v1, WpCursorShapeManagerV1, UsrWpCursorShapeManagerV1, 2; - wp_fractional_scale_manager, WpFractionalScaleManagerV1, UsrWpFractionalScaleManager, 1; - zwp_linux_dmabuf_v1, ZwpLinuxDmabufV1, UsrZwpLinuxDmabufV1, 5; - } - let ctx = Rc::new(EggContext { - inner: Rc::new(EggContextInner { - id: self.egg_state.context_ids.next(), - renderer, - allocator, - state: self.clone(), - _client: client.clone(), - con, - jay_compositor, - wl_compositor, - xdg_wm_base, - wl_data_device_manager, - _zwp_primary_selection_device_manager_v1: zwp_primary_selection_device_manager_v1, - wp_viewporter, - wp_cursor_shape_manager_v1, - wp_fractional_scale_manager, - zwp_linux_dmabuf_v1, - registry, - windows: Default::default(), - seats: Default::default(), - }), - }); - ctx.inner.con.owner.set(Some(ctx.inner.clone())); - self.egg_state.cxts.set(ctx.inner.id, ctx.inner.clone()); - for &global_name in self.globals.seats.lock().keys() { - ctx.inner.add_seat(global_name); - } - self.egg_state.ctx.set(Some(ctx.clone())); - Ok(ctx) - } -} - -impl EggContext { - pub fn create_window(self: &Rc, title: &str) -> Rc { - let i = &self.inner; - let wl_surface = i.wl_compositor.create_surface(); - let jay_sync_file_surface = i.jay_compositor.get_sync_file_surface(&wl_surface); - let xdg_surface = i.xdg_wm_base.get_xdg_surface(&wl_surface); - let xdg_toplevel = xdg_surface.get_toplevel(); - xdg_toplevel.set_title(title); - let wp_fractional_scale = i - .wp_fractional_scale_manager - .get_fractional_scale(&wl_surface); - let wp_viewport = i.wp_viewporter.get_viewport(&wl_surface); - wl_surface.commit(); - let window = Rc::new(EggWindowInner { - ctx: self.inner.clone(), - egv: i.renderer.create_context(), - egui: egui::Context::default(), - wl_surface, - wp_viewport, - wp_fractional_scale, - xdg_surface, - xdg_toplevel, - jay_sync_file_surface, - frame_task: Default::default(), - want_frame: Default::default(), - have_frame: Cell::new(true), - initial_commit_pending: Cell::new(true), - owner: Default::default(), - active_seat: Default::default(), - raw_input: RefCell::new(None), - close: Default::default(), - repaint_timeout: Cell::new(u64::MAX), - repaint_timeout_changed: Default::default(), - fonts_changed: Cell::new(true), - buffers: Default::default(), - surface_pending: Default::default(), - logical_size: Cell::new([800, 600]), - physical_size: Cell::new([800, 600]), - scale: Default::default(), - }); - window - .egui - .all_styles_mut(|s| s.spacing.item_spacing.y = 5.0); - window.xdg_surface.owner.set(Some(window.clone())); - window.xdg_toplevel.owner.set(Some(window.clone())); - window.wp_fractional_scale.owner.set(Some(window.clone())); - i.windows.set(window.wl_surface.id, window.clone()); - let eng = &i.state.eng; - let render_task = eng.spawn("egui-render", window.clone().render_frames()); - let timer_task = eng.spawn("egui-timer", window.clone().handle_timer()); - let window = EggWindow { - _ctx: self.clone(), - inner: window, - _render_task: render_task, - _timer_task: timer_task, - }; - Rc::new(window) - } -} - -impl EggContextInner { - pub fn add_seat(self: &Rc, global_name: GlobalName) { - let wl_seat = Rc::new(UsrWlSeat { - id: self.con.id(), - con: self.con.clone(), - owner: Default::default(), - version: Version(10), - }); - self.registry.bind(global_name, &*wl_seat); - self.con.add_object(wl_seat.clone()); - let wl_pointer = wl_seat.get_pointer(); - let wl_keyboard = wl_seat.get_keyboard(); - let wp_cursor_shape_device_v1 = self.wp_cursor_shape_manager_v1.get_pointer(&wl_pointer); - let wl_data_device = self.wl_data_device_manager.get_data_device(&wl_seat); - let seat = Rc::new(EggSeatInner { - ctx: self.clone(), - global_name, - wl_seat, - wl_pointer, - wl_data_device, - pointer_window: Default::default(), - pointer_enter_serial: Default::default(), - pointer_serial: Default::default(), - pointer_pos: Default::default(), - kb_modifiers: Default::default(), - wp_cursor_shape_device_v1, - wl_keyboard, - kb_window: Default::default(), - kb_serial: Default::default(), - serial: Default::default(), - wl_data_source: Default::default(), - copy_text: Default::default(), - copy_task: Default::default(), - paste_task: Default::default(), - }); - seat.wl_pointer.owner.set(Some(seat.clone())); - seat.wl_keyboard.owner.set(Some(seat.clone())); - let seat = EggSeat { inner: seat }; - self.seats.set(global_name, seat); - } -} - -const TEXT_PLAIN: &str = "text/plain;charset=utf-8"; - -impl EggSeatInner { - pub fn request_paste(self: &Rc) { - let Some(offer) = self.wl_data_device.selection.get() else { - return; - }; - if !offer.mime_types.borrow().contains(TEXT_PLAIN) { - return; - } - let Some(window) = self.kb_window.get() else { - return; - }; - let Pipe { read, write } = match pipe() { - Ok(p) => p.map_read(Rc::new).map_write(Rc::new), - Err(e) => { - log::error!("Could not create pipe: {}", ErrorFmt(e)); - return; - } - }; - offer.receive(TEXT_PLAIN, &write); - let window = Rc::downgrade(&window); - let ring = self.ctx.state.ring.clone(); - let mut buf = Buf::new(1024); - let mut out = Vec::new(); - let task = self.ctx.state.eng.spawn("egui-paste", async move { - loop { - let n = match ring.read(&read, buf.clone()).await { - Ok(n) => n, - Err(e) => { - log::error!("Could not read from peer: {}", ErrorFmt(e)); - return; - } - }; - if n == 0 { - if let Some(window) = window.upgrade() { - let s = match String::from_utf8(out) { - Ok(s) => s, - Err(e) => { - log::error!("Peer did not send UTF-8: {}", ErrorFmt(e)); - return; - } - }; - window.event(Event::Paste(s)); - } - return; - } - out.extend_from_slice(&buf[..n]); - if out.len() >= 1024 * buf.len() { - log::error!("Paste buffer is too large"); - return; - } - } - }); - self.paste_task.set(Some(task)); - } -} - -impl EggWindow { - pub fn request_redraw(&self) { - self.inner.want_frame(); - } - - pub fn set_owner(&self, owner: Option>) { - self.inner.owner.set(owner); - } -} - -impl EggWindowInner { - fn update_physical_size(&self) { - let size = self.logical_size.get(); - let scale = self.scale.get(); - let physical_size = scale.pixel_size(size); - if self.physical_size.replace(physical_size) != physical_size { - self.want_frame(); - } - } - - fn want_frame(&self) { - self.want_frame.set(true); - self.maybe_trigger_frame(); - } - - fn maybe_trigger_frame(&self) { - if self.want_frame.get() && self.have_frame.get() { - self.frame_task.trigger(); - } - } - - async fn handle_timer(self: Rc) { - loop { - let timeout = self.ctx.state.ring.timeout(self.repaint_timeout.get()); - let triggered = || self.repaint_timeout_changed.triggered(); - let timeout = select! { - _ = timeout.fuse() => true, - _ = triggered().fuse() => false, - }; - if timeout { - self.want_frame(); - triggered().await; - } - } - } - - async fn render_frames(self: Rc) { - loop { - self.frame_task.triggered().await; - if let Err(e) = self.render_frame() { - log::error!("Could not render frame: {}", ErrorFmt(e)); - break; - } - } - } - - fn render_frame(self: &Rc) -> Result<(), EggError> { - if self.fonts_changed.take() { - self.egui - .set_fonts(self.ctx.state.egg_state.font_definitions()); - } - if self.initial_commit_pending.get() { - return Ok(()); - } - if !self.have_frame.get() { - return Ok(()); - } - if !self.want_frame.get() { - return Ok(()); - } - let Some(owner) = self.owner.get() else { - return Ok(()); - }; - let Some(render_ctx) = self.ctx.state.render_ctx.get() else { - return Ok(()); - }; - let Some(format) = render_ctx.formats().get(&EGV_FORMAT.drm) else { - return Ok(()); - }; - let logical_size = self.logical_size.get(); - let physical_size = self.physical_size.get(); - let mut fb_opt = self.buffers.back().get(); - 'check: { - if let Some(fb) = &fb_opt { - if fb.size.get() != physical_size { - fb_opt = None; - break 'check; - } - if !format.read_modifiers.contains(&fb.bo.dmabuf().modifier) { - fb_opt = None; - break 'check; - } - } - } - let fb = match fb_opt { - Some(fb) => fb, - _ => { - let modifiers: Vec<_> = self - .ctx - .renderer - .support() - .iter() - .filter(|s| { - s.max_width >= physical_size[0] as u32 - && s.max_height >= physical_size[1] as u32 - && format.read_modifiers.contains(&s.modifier) - }) - .map(|s| s.modifier) - .collect(); - let bo = self - .ctx - .allocator - .create_bo( - &self.ctx.state.dma_buf_ids, - physical_size[0], - physical_size[1], - EGV_FORMAT, - &modifiers, - BO_USE_RENDERING, - ) - .map_err(EggError::AllocateBuffer)?; - let egv = self - .egv - .import_framebuffer(&bo) - .map_err(EggError::ImportFramebuffer)?; - let dmabuf = bo.dmabuf(); - let sync_file = dmabuf - .export_sync_file(DMA_BUF_SYNC_WRITE) - .map_err(EggError::ExportBoSyncFile)?; - let wl_buffer = self.ctx.zwp_linux_dmabuf_v1.create_buffer(dmabuf); - let fb = Rc::new(EggFramebuffer { - client_acquire_fence: CloneCell::new(Some(sync_file)), - size: Cell::new(physical_size), - bo, - egv, - wl_buffer, - window: Rc::downgrade(self), - drop_queue: self.ctx.state.bo_drop_queue.clone(), - }); - self.buffers.back().set(Some(fb.clone())); - fb - } - }; - let Some(sync_file) = fb.client_acquire_fence.get() else { - return Ok(()); - }; - let raw_input = self - .raw_input - .take() - .unwrap_or_else(|| self.default_raw_input()); - let full_output = self.egui.run_ui(raw_input, |ui| { - owner.clone().render(ui); - }); - let FullOutput { - platform_output, - textures_delta, - shapes, - pixels_per_point, - viewport_output, - } = full_output; - let primitives = self.egui.tessellate(shapes, pixels_per_point); - let sync = fb - .egv - .render( - textures_delta, - pixels_per_point, - &primitives, - (0.0, 0.0), - sync_file.as_ref(), - ) - .map_err(EggError::Render)?; - let PlatformOutput { - commands, - cursor_icon, - .. - } = platform_output; - if let Some(seat) = self.active_seat.get() { - 'set_icon: { - let cursor = match cursor_icon { - CursorIcon::None => { - seat.wl_pointer - .set_cursor(seat.pointer_serial.get(), None, 0, 0); - break 'set_icon; - } - CursorIcon::Default => KnownCursor::Default, - CursorIcon::ContextMenu => KnownCursor::ContextMenu, - CursorIcon::Help => KnownCursor::Help, - CursorIcon::PointingHand => KnownCursor::Pointer, - CursorIcon::Progress => KnownCursor::Progress, - CursorIcon::Wait => KnownCursor::Wait, - CursorIcon::Cell => KnownCursor::Cell, - CursorIcon::Crosshair => KnownCursor::Crosshair, - CursorIcon::Text => KnownCursor::Text, - CursorIcon::VerticalText => KnownCursor::VerticalText, - CursorIcon::Alias => KnownCursor::Alias, - CursorIcon::Copy => KnownCursor::Copy, - CursorIcon::Move => KnownCursor::Move, - CursorIcon::NoDrop => KnownCursor::NoDrop, - CursorIcon::NotAllowed => KnownCursor::NotAllowed, - CursorIcon::Grab => KnownCursor::Grab, - CursorIcon::Grabbing => KnownCursor::Grabbing, - CursorIcon::AllScroll => KnownCursor::AllScroll, - CursorIcon::ResizeHorizontal => KnownCursor::EwResize, - CursorIcon::ResizeNeSw => KnownCursor::NeswResize, - CursorIcon::ResizeNwSe => KnownCursor::NwseResize, - CursorIcon::ResizeVertical => KnownCursor::NsResize, - CursorIcon::ResizeEast => KnownCursor::EResize, - CursorIcon::ResizeSouthEast => KnownCursor::SeResize, - CursorIcon::ResizeSouth => KnownCursor::SResize, - CursorIcon::ResizeSouthWest => KnownCursor::SwResize, - CursorIcon::ResizeWest => KnownCursor::WResize, - CursorIcon::ResizeNorthWest => KnownCursor::NwResize, - CursorIcon::ResizeNorth => KnownCursor::NResize, - CursorIcon::ResizeNorthEast => KnownCursor::NeResize, - CursorIcon::ResizeColumn => KnownCursor::ColResize, - CursorIcon::ResizeRow => KnownCursor::RowResize, - CursorIcon::ZoomIn => KnownCursor::ZoomIn, - CursorIcon::ZoomOut => KnownCursor::ZoomOut, - }; - seat.wp_cursor_shape_device_v1 - .set_shape(seat.pointer_serial.get(), cursor); - } - } - for command in commands { - match command { - OutputCommand::CopyText(t) => { - if let Some(seat) = self.active_seat.get() { - let data_src = self.ctx.wl_data_device_manager.create_data_source(); - data_src.offer(TEXT_PLAIN); - data_src.owner.set(Some(seat.clone())); - seat.wl_data_device - .set_selection(seat.serial.get(), &data_src); - if let Some(old) = seat.wl_data_source.set(Some(data_src)) { - old.con.remove_obj(&*old); - } - seat.copy_text.replace(Some(Buf::from_slice(t.as_bytes()))); - } - } - OutputCommand::CopyImage(_) => {} - OutputCommand::OpenUrl(url) => { - if let Some(forker) = self.ctx.state.forker.get() { - forker.spawn("xdg-open".to_string(), vec![url.url], vec![], vec![]); - } - } - } - } - let Some(viewport) = viewport_output.get(&ViewportId::ROOT) else { - return Err(EggError::NoViewportOutput); - }; - for command in &viewport.commands { - match command { - ViewportCommand::Close => self.close.set(true), - ViewportCommand::CancelClose => self.close.set(false), - ViewportCommand::Title(s) => self.xdg_toplevel.set_title(s), - ViewportCommand::Fullscreen(b) => self.xdg_toplevel.set_fullscreen(*b), - ViewportCommand::RequestPaste => { - if let Some(seat) = self.active_seat.get() { - seat.request_paste(); - } - } - _ => {} - } - } - let repaint_delay = u64::try_from(viewport.repaint_delay.as_nanos()).unwrap_or(u64::MAX); - let repaint_timeout = self.ctx.state.now_nsec().saturating_add(repaint_delay); - self.repaint_timeout.set(repaint_timeout); - if repaint_timeout != u64::MAX { - self.repaint_timeout_changed.trigger(); - } - self.wl_surface.attach(&fb.wl_buffer); - self.wl_surface.damage(); - self.jay_sync_file_surface.set_acquire(sync.as_ref()); - self.jay_sync_file_surface - .get_release() - .owner - .set(Some(fb.clone())); - self.wl_surface.frame().owner.set(Some(self.clone())); - self.wp_viewport - .set_destination(logical_size[0], logical_size[1]); - self.wl_surface.commit(); - fb.client_acquire_fence.take(); - self.buffers.flip(); - self.have_frame.set(false); - self.want_frame.set(false); - if self.close.get() { - owner.close(); - } - Ok(()) - } -} - -impl UsrXdgSurfaceOwner for EggWindowInner { - fn configure(&self) { - let pending = mem::take(&mut *self.surface_pending.borrow_mut()); - if let Some((mut w, mut h)) = pending.size { - let [old_w, old_h] = self.logical_size.get(); - w = if w > 0 { w } else { old_w }; - h = if h > 0 { h } else { old_h }; - let size = [w, h]; - if self.logical_size.replace(size) != size { - self.update_physical_size(); - } - } - if self.initial_commit_pending.take() { - self.want_frame(); - } - } -} - -impl UsrXdgToplevelOwner for EggWindowInner { - fn configure(&self, width: i32, height: i32) { - self.surface_pending.borrow_mut().size = Some((width, height)); - } - - fn close(&self) { - let raw_input = &mut *self.raw_input.borrow_mut(); - let raw_input = raw_input.get_or_insert_with(|| self.default_raw_input()); - raw_input - .viewports - .get_mut(&ViewportId::ROOT) - .unwrap() - .events - .push(ViewportEvent::Close); - self.close.set(true); - self.want_frame(); - } -} - -impl UsrWpFractionalScaleOwner for EggWindowInner { - fn preferred_scale(self: Rc, ev: &PreferredScale) { - let scale = Scale::from_wl(ev.scale); - if self.scale.replace(scale) != scale { - self.update_physical_size(); - } - } -} - -impl EggWindowInner { - fn event(&self, event: Event) { - let raw_input = &mut *self.raw_input.borrow_mut(); - let raw_input = raw_input.get_or_insert_with(|| self.default_raw_input()); - raw_input.events.push(event); - self.want_frame(); - } - - fn default_raw_input(&self) -> RawInput { - let viewport_info = ViewportInfo { - native_pixels_per_point: Some(self.scale.get().to_f64() as _), - ..Default::default() - }; - let size = self.logical_size.get(); - let size = - egui::Rect::from_min_size(Pos2::default(), Vec2::new(size[0] as f32, size[1] as f32)); - let mut modifiers = Modifiers::default(); - if let Some(seat) = self.active_seat.get() { - modifiers = seat.kb_modifiers.get(); - } - RawInput { - viewport_id: ViewportId::ROOT, - viewports: std::iter::once((ViewportId::ROOT, viewport_info)).collect(), - screen_rect: Some(size), - max_texture_side: Some(self.ctx.renderer.max_texture_side()), - time: Some(self.ctx.state.now_nsec() as f64 / 1_000_000_000.0), - modifiers, - ..Default::default() - } - } -} - -impl EggSeatInner { - fn activate_pointer_window(self: &Rc) -> Option> { - let window = self.pointer_window.get()?; - window.active_seat.set(Some(self.clone())); - Some(window) - } - - fn activate_kb_window(self: &Rc) -> Option> { - let window = self.kb_window.get()?; - window.active_seat.set(Some(self.clone())); - Some(window) - } - - fn leave(self: &Rc) { - if let Some(window) = self.pointer_window.take() - && let Some(active_seat) = window.active_seat.get() - && rc_eq(&active_seat, &self) - { - window.active_seat.take(); - } - } - - fn unfocus(self: &Rc) { - if let Some(window) = self.kb_window.take() - && let Some(active_seat) = window.active_seat.get() - && rc_eq(&active_seat, &self) - { - window.active_seat.take(); - } - } - - fn motion(self: &Rc, surface_x: Fixed, surface_y: Fixed) { - let Some(window) = self.activate_pointer_window() else { - return; - }; - let pos = pos2(surface_x.to_f32(), surface_y.to_f32()); - self.pointer_pos.set(pos); - window.event(Event::PointerMoved(pos)); - } -} - -impl UsrWlPointerOwner for EggSeatInner { - fn enter(self: Rc, ev: &Enter) { - let Some(window) = self.ctx.windows.get(&ev.surface) else { - return; - }; - self.pointer_window.set(Some(window.clone())); - self.pointer_enter_serial.set(ev.serial); - self.pointer_serial.set(ev.serial); - self.serial.set(ev.serial); - (&self).motion(ev.surface_x, ev.surface_y); - } - - fn leave(self: Rc, _ev: &Leave) { - (&self).leave(); - } - - fn motion(self: Rc, ev: &Motion) { - (&self).motion(ev.surface_x, ev.surface_y); - } - - fn button(self: Rc, ev: &Button) { - let Some(window) = self.activate_pointer_window() else { - return; - }; - self.pointer_serial.set(ev.serial); - self.serial.set(ev.serial); - let button = match ev.button { - BTN_LEFT => PointerButton::Primary, - BTN_RIGHT => PointerButton::Secondary, - BTN_MIDDLE => PointerButton::Middle, - BTN_SIDE => PointerButton::Extra1, - BTN_EXTRA => PointerButton::Extra2, - _ => return, - }; - window.event(Event::PointerButton { - pos: self.pointer_pos.get(), - button, - pressed: ev.state == wl_pointer::PRESSED, - modifiers: self.kb_modifiers.get(), - }); - } - - fn scroll(self: Rc, ps: &PendingScroll) { - let Some(window) = self.activate_pointer_window() else { - return; - }; - let v120_x = ps.v120[HORIZONTAL_SCROLL].get(); - let v120_y = ps.v120[VERTICAL_SCROLL].get(); - let px_x = ps.px[HORIZONTAL_SCROLL].get(); - let px_y = ps.px[VERTICAL_SCROLL].get(); - let unit; - let delta; - if v120_x.is_some() || v120_y.is_some() { - unit = MouseWheelUnit::Line; - delta = vec2( - -v120_x.unwrap_or_default() as f32 / 120.0, - -v120_y.unwrap_or_default() as f32 / 120.0, - ); - } else if px_x.is_some() || px_y.is_some() { - unit = MouseWheelUnit::Point; - delta = vec2( - -px_x.unwrap_or_default().to_f32(), - -px_y.unwrap_or_default().to_f32(), - ); - } else { - return; - } - window.event(Event::MouseWheel { - unit, - delta, - phase: TouchPhase::Move, - modifiers: self.kb_modifiers.get(), - }); - } -} - -impl EggSeatInner { - fn handle_key(self: &Rc, lookup: Lookup<'_>, serial: u32, down: bool) { - let Some(window) = self.activate_kb_window() else { - return; - }; - self.kb_serial.set(serial); - self.serial.set(serial); - if down { - let mut text = String::new(); - for key in lookup { - if let Some(c) = key.char() - && c.is_not_control() - { - text.push(c); - } - } - if text.is_not_empty() { - window.event(Event::Text(text)); - } - } - for key in lookup { - let mut modifiers = map_mods(lookup.remaining_mods()); - let Some(key) = map_key(key.keysym(), &mut modifiers) else { - continue; - }; - if down && modifiers.ctrl { - match key { - Key::V => self.request_paste(), - Key::C => window.event(Event::Copy), - Key::X => window.event(Event::Cut), - _ => {} - } - } - window.event(Event::Key { - key, - physical_key: None, - pressed: down, - repeat: false, - modifiers, - }); - } - } -} - -impl UsrWlKeyboardOwner for EggSeatInner { - fn focus(self: Rc, surface: WlSurfaceId, serial: u32) { - let Some(window) = self.ctx.windows.get(&surface) else { - return; - }; - self.kb_window.set(Some(window.clone())); - self.kb_serial.set(serial); - self.serial.set(serial); - window.active_seat.set(Some(self.clone())); - } - - fn unfocus(self: Rc) { - (&self).unfocus(); - } - - fn modifiers(self: Rc, mods: ModifierMask) { - self.kb_modifiers.set(map_mods(mods)); - } - - fn down(self: Rc, lookup: Lookup<'_>, serial: u32) { - self.handle_key(lookup, serial, true); - } - - fn repeat(self: Rc, lookup: Lookup<'_>, serial: u32) { - self.handle_key(lookup, serial, true); - } - - fn up(self: Rc, lookup: Lookup<'_>, serial: u32) { - self.handle_key(lookup, serial, false); - } -} - -fn map_mods(mods: ModifierMask) -> Modifiers { - Modifiers { - alt: mods.contains(ModifierMask::ALT), - ctrl: mods.contains(ModifierMask::CONTROL), - shift: mods.contains(ModifierMask::SHIFT), - mac_cmd: false, - command: mods.contains(ModifierMask::CONTROL), - } -} - -impl UsrJaySyncFileReleaseOwner for EggFramebuffer { - fn release(&self, sync_file: Option) { - self.client_acquire_fence.set(Some(sync_file)); - if let Some(window) = self.window.upgrade() { - window.maybe_trigger_frame(); - } - } -} - -impl UsrWlCallbackOwner for EggWindowInner { - fn done(self: Rc) { - self.have_frame.set(true); - self.maybe_trigger_frame(); - } -} - -fn map_key(kc: Keysym, mods: &mut Modifiers) -> Option { - use {Key as K, kbvm::syms as s}; - let mut with_shift = |k| { - mods.shift = true; - k - }; - let key = match kc { - s::Down | s::KP_Down => K::ArrowDown, - s::Left | s::KP_Left => K::ArrowLeft, - s::Right | s::KP_Right => K::ArrowRight, - s::Up | s::KP_Up => K::ArrowUp, - s::Escape => K::Escape, - s::Tab | s::KP_Tab => K::Tab, - s::ISO_Left_Tab => with_shift(K::Tab), - s::BackSpace => K::Backspace, - s::Return | s::KP_Enter => K::Enter, - s::space | s::KP_Space => K::Space, - s::Insert | s::KP_Insert => K::Insert, - s::Delete | s::KP_Delete => K::Delete, - s::Home | s::KP_Home | s::KP_Begin => K::Home, - s::End | s::KP_End => K::End, - s::Page_Up | s::KP_Page_Up => K::PageUp, - s::Page_Down | s::KP_Page_Down => K::PageDown, - s::XF86Copy => K::Copy, - s::XF86Cut => K::Cut, - s::XF86Paste => K::Paste, - s::colon => K::Colon, - s::comma => K::Comma, - s::backslash => K::Backslash, - s::slash | s::KP_Divide => K::Slash, - s::bar => K::Pipe, - s::question => K::Questionmark, - s::exclam => K::Exclamationmark, - s::bracketleft => K::OpenBracket, - s::bracketright => K::CloseBracket, - s::braceleft => K::OpenCurlyBracket, - s::braceright => K::CloseCurlyBracket, - s::grave => K::Backtick, - s::minus | s::KP_Subtract => K::Minus, - s::period | s::KP_Decimal => K::Period, - s::plus | s::KP_Add => K::Plus, - s::equal | s::KP_Equal => K::Equals, - s::semicolon => K::Semicolon, - s::quotedbl => K::Quote, - s::KP_0 | s::_0 => K::Num0, - s::KP_1 | s::_1 => K::Num1, - s::KP_2 | s::_2 => K::Num2, - s::KP_3 | s::_3 => K::Num3, - s::KP_4 | s::_4 => K::Num4, - s::KP_5 | s::_5 => K::Num5, - s::KP_6 | s::_6 => K::Num6, - s::KP_7 | s::_7 => K::Num7, - s::KP_8 | s::_8 => K::Num8, - s::KP_9 | s::_9 => K::Num9, - s::a => K::A, - s::b => K::B, - s::c => K::C, - s::d => K::D, - s::e => K::E, - s::f => K::F, - s::g => K::G, - s::h => K::H, - s::i => K::I, - s::j => K::J, - s::k => K::K, - s::l => K::L, - s::m => K::M, - s::n => K::N, - s::o => K::O, - s::p => K::P, - s::q => K::Q, - s::r => K::R, - s::s => K::S, - s::t => K::T, - s::u => K::U, - s::v => K::V, - s::w => K::W, - s::x => K::X, - s::y => K::Y, - s::z => K::Z, - s::A => with_shift(K::A), - s::B => with_shift(K::B), - s::C => with_shift(K::C), - s::D => with_shift(K::D), - s::E => with_shift(K::E), - s::F => with_shift(K::F), - s::G => with_shift(K::G), - s::H => with_shift(K::H), - s::I => with_shift(K::I), - s::J => with_shift(K::J), - s::K => with_shift(K::K), - s::L => with_shift(K::L), - s::M => with_shift(K::M), - s::N => with_shift(K::N), - s::O => with_shift(K::O), - s::P => with_shift(K::P), - s::Q => with_shift(K::Q), - s::R => with_shift(K::R), - s::S => with_shift(K::S), - s::T => with_shift(K::T), - s::U => with_shift(K::U), - s::V => with_shift(K::V), - s::W => with_shift(K::W), - s::X => with_shift(K::X), - s::Y => with_shift(K::Y), - s::Z => with_shift(K::Z), - s::F1 | s::KP_F1 => K::F1, - s::F2 | s::KP_F2 => K::F2, - s::F3 | s::KP_F3 => K::F3, - s::F4 | s::KP_F4 => K::F4, - s::F5 => K::F5, - s::F6 => K::F6, - s::F7 => K::F7, - s::F8 => K::F8, - s::F9 => K::F9, - s::F10 => K::F10, - s::F11 => K::F11, - s::F12 => K::F12, - s::F13 => K::F13, - s::F14 => K::F14, - s::F15 => K::F15, - s::F16 => K::F16, - s::F17 => K::F17, - s::F18 => K::F18, - s::F19 => K::F19, - s::F20 => K::F20, - s::F21 => K::F21, - s::F22 => K::F22, - s::F23 => K::F23, - s::F24 => K::F24, - s::F25 => K::F25, - s::F26 => K::F26, - s::F27 => K::F27, - s::F28 => K::F28, - s::F29 => K::F29, - s::F30 => K::F30, - s::F31 => K::F31, - s::F32 => K::F32, - s::F33 => K::F33, - s::F34 => K::F34, - s::F35 => K::F35, - s::XF86Back => K::BrowserBack, - _ => return None, - }; - Some(key) -} - -impl Drop for EggSeat { - fn drop(&mut self) { - let s = &self.inner; - s.copy_task.take(); - s.paste_task.take(); - s.leave(); - s.unfocus(); - if let Some(v) = s.wl_data_source.take() { - s.ctx.con.remove_obj(&*v); - } - s.ctx.seats.remove(&s.global_name); - s.ctx.con.remove_obj(&*s.wl_data_device); - s.ctx.con.remove_obj(&*s.wl_keyboard); - s.ctx.con.remove_obj(&*s.wp_cursor_shape_device_v1); - s.ctx.con.remove_obj(&*s.wl_pointer); - s.ctx.con.remove_obj(&*s.wl_seat); - } -} - -impl Drop for EggContext { - fn drop(&mut self) { - let i = &self.inner; - i.state.egg_state.cxts.remove(&self.inner.id); - i.seats.clear(); - i.windows.clear(); - i.con.owner.take(); - i.con.kill(); - } -} - -impl Drop for EggWindow { - fn drop(&mut self) { - let i = &self.inner; - i.ctx.windows.remove(&i.wl_surface.id); - if let Some(seat) = i.active_seat.take() { - for field in [&seat.kb_window, &seat.pointer_window] { - if let Some(w) = field.get() - && rc_eq(&w, i) - { - field.take(); - } - } - } - i.owner.take(); - i.ctx.con.remove_obj(&*i.jay_sync_file_surface); - i.ctx.con.remove_obj(&*i.xdg_toplevel); - i.ctx.con.remove_obj(&*i.xdg_surface); - i.ctx.con.remove_obj(&*i.wp_fractional_scale); - i.ctx.con.remove_obj(&*i.wp_viewport); - i.ctx.con.remove_obj(&*i.wl_surface); - } -} - -impl UsrWlDataSourceOwner for EggSeatInner { - fn send(&self, _mime_type: &str, fd: Rc) { - let Some(buf) = self.copy_text.borrow_mut().as_mut().map(|b| b.clone()) else { - return; - }; - let ring = self.ctx.state.ring.clone(); - let task = self.ctx.state.eng.spawn("egg-copy-text", async move { - if let Err(e) = ring.write(&fd, buf, None).await { - log::error!("Could not send text to client: {}", e); - } - }); - self.copy_task.set(Some(task)); - } -} - -impl UsrConOwner for EggContextInner { - fn killed(&self) { - if let Some(ctx) = self.state.egg_state.ctx.get() - && ctx.inner.id == self.id - { - self.state.egg_state.ctx.take(); - } - for window in self.windows.clear().values() { - if let Some(owner) = window.owner.take() { - owner.close(); - } - } - } -} - -impl Drop for EggFramebuffer { - fn drop(&mut self) { - if let Some(Some(fence)) = self.client_acquire_fence.take() { - self.drop_queue.push(&fence.0, self.bo.clone()); - } - self.wl_buffer.con.remove_obj(&*self.wl_buffer); - } -} diff --git a/src/egui_adapter/egui_vulkan.rs b/src/egui_adapter/egui_vulkan.rs deleted file mode 100644 index 8067665a..00000000 --- a/src/egui_adapter/egui_vulkan.rs +++ /dev/null @@ -1,2063 +0,0 @@ -use { - crate::{ - allocator::BufferObject, - async_engine::{AsyncEngine, SpawnedFuture}, - eventfd_cache::EventfdCache, - format::XRGB8888, - gfx_api::{FdSync, SyncFile}, - io_uring::IoUring, - utils::{ - errorfmt::ErrorFmt, - oserror::{OsError, OsErrorExt2}, - queue::AsyncQueue, - }, - video::{Modifier, dmabuf::PlaneVec, drm::syncobj::SyncobjCtx}, - vulkan_core::{ - VULKAN_API_VERSION, VulkanCoreError, VulkanCoreInstance, VulkanDeviceFeatures, - device::VulkanDeviceInf, - gpu_alloc_ash::AshMemoryDevice, - map_extension_properties, - sync::{VulkanDeviceSyncExt, VulkanSync}, - timeline_semaphore::{VulkanDeviceTimelineSemaphoreExt, VulkanTimelineSemaphore}, - }, - }, - ahash::AHashMap, - arrayvec::ArrayVec, - ash::{ - Device, - ext::{ - external_memory_dma_buf, image_drm_format_modifier, physical_device_drm, - queue_family_foreign, - }, - khr::{external_fence_fd, external_memory_fd, external_semaphore_fd, push_descriptor}, - util::read_spv, - vk::{ - self, AccessFlags2, AttachmentLoadOp, AttachmentStoreOp, BindImageMemoryInfo, - BindImagePlaneMemoryInfo, BlendFactor, BlendOp, BorderColor, Buffer, BufferCreateInfo, - BufferImageCopy2, BufferMemoryBarrier2, BufferUsageFlags, ColorComponentFlags, - CommandBuffer, CommandBufferAllocateInfo, CommandBufferBeginInfo, CommandBufferLevel, - CommandBufferSubmitInfo, CommandBufferUsageFlags, CommandPool, CommandPoolCreateFlags, - CommandPoolCreateInfo, ComponentMapping, ComponentSwizzle, CopyBufferToImageInfo2, - CullModeFlags, DependencyInfo, DescriptorImageInfo, DescriptorSetLayout, - DescriptorSetLayoutBinding, DescriptorSetLayoutCreateFlags, - DescriptorSetLayoutCreateInfo, DescriptorType, DeviceCreateInfo, DeviceMemory, - DeviceQueueCreateInfo, DrmFormatModifierPropertiesEXT, - DrmFormatModifierPropertiesListEXT, DynamicState, Extent2D, Extent3D, - ExternalFenceFeatureFlags, ExternalFenceHandleTypeFlags, ExternalFenceProperties, - ExternalImageFormatPropertiesKHR, ExternalMemoryFeatureFlags, - ExternalMemoryHandleTypeFlags, ExternalMemoryImageCreateInfo, - ExternalSemaphoreFeatureFlags, ExternalSemaphoreHandleTypeFlags, - ExternalSemaphoreProperties, Filter, Format, FormatFeatureFlags, FormatProperties2, - FrontFace, GraphicsPipelineCreateInfo, Image, ImageAspectFlags, ImageCreateFlags, - ImageCreateInfo, ImageDrmFormatModifierExplicitCreateInfoEXT, ImageFormatProperties2, - ImageLayout, ImageMemoryBarrier2, ImageMemoryRequirementsInfo2, - ImagePlaneMemoryRequirementsInfo, ImageSubresourceLayers, ImageSubresourceRange, - ImageTiling, ImageType, ImageUsageFlags, ImageView, ImageViewCreateInfo, ImageViewType, - ImportMemoryFdInfoKHR, ImportSemaphoreFdInfoKHR, IndexType, MappedMemoryRange, - MemoryAllocateInfo, MemoryDedicatedAllocateInfo, MemoryFdPropertiesKHR, - MemoryRequirements, MemoryRequirements2, Offset2D, Offset3D, - PhysicalDeviceDrmPropertiesEXT, PhysicalDeviceDynamicRenderingFeatures, - PhysicalDeviceExternalFenceInfo, PhysicalDeviceExternalImageFormatInfoKHR, - PhysicalDeviceExternalSemaphoreInfo, PhysicalDeviceFeatures2, - PhysicalDeviceImageDrmFormatModifierInfoEXT, PhysicalDeviceImageFormatInfo2, - PhysicalDeviceProperties2, PhysicalDeviceSynchronization2Features, - PhysicalDeviceTimelineSemaphoreFeatures, PhysicalDeviceType, - PhysicalDeviceVulkan13Properties, Pipeline, PipelineBindPoint, PipelineCache, - PipelineColorBlendAttachmentState, PipelineColorBlendStateCreateInfo, - PipelineDynamicStateCreateInfo, PipelineInputAssemblyStateCreateInfo, PipelineLayout, - PipelineLayoutCreateInfo, PipelineMultisampleStateCreateInfo, - PipelineRasterizationStateCreateInfo, PipelineRenderingCreateInfo, - PipelineShaderStageCreateInfo, PipelineStageFlags2, PipelineVertexInputStateCreateInfo, - PipelineViewportStateCreateInfo, PolygonMode, PrimitiveTopology, - QUEUE_FAMILY_FOREIGN_EXT, Queue, QueueFlags, Rect2D, RenderingAttachmentInfo, - RenderingInfoKHR, SampleCountFlags, Sampler, SamplerAddressMode, SamplerCreateInfo, - SamplerMipmapMode, Semaphore, SemaphoreCreateInfo, SemaphoreImportFlags, - SemaphoreSubmitInfo, ShaderModule, ShaderModuleCreateInfo, ShaderStageFlags, - SharingMode, SubmitInfo2, SubresourceLayout, VertexInputAttributeDescription, - VertexInputBindingDescription, VertexInputRate, Viewport, WHOLE_SIZE, - WriteDescriptorSet, - }, - }, - bstr::ByteSlice, - egui::epaint::{ - ClippedPrimitive, ImageData, ImageDelta, Primitive, TextureId, Vertex, - textures::{TextureFilter, TextureOptions, TextureWrapMode, TexturesDelta}, - }, - gpu_alloc::{ - AllocationError, Config, GpuAllocator, MapError, MemoryBlock, Request, UsageFlags, - }, - gpu_alloc_types::MemoryPropertyFlags, - isnt::std_1::{collections::IsntHashMapExt, primitive::IsntSliceExt}, - log::Level, - run_on_drop::on_drop, - std::{ - cell::{Cell, RefCell}, - collections::hash_map::Entry, - ffi::CStr, - io::{self, Cursor}, - mem::{ManuallyDrop, offset_of}, - ptr, - rc::Rc, - slice, - }, - thiserror::Error, - uapi::{AsUstr, AssertPacked, Packed, Pod, c}, -}; - -#[derive(Debug, Error)] -pub enum EgvError { - #[error(transparent)] - Core(#[from] VulkanCoreError), - #[error("could not read spv source")] - ReadSpv(#[source] io::Error), - #[error("could not create a shader module")] - CreateShaderModule(#[source] vk::Result), - #[error("could not create a sampler")] - CreateSampler(#[source] vk::Result), - #[error("could not allocate GPU memory")] - AllocateMemory(#[source] AllocationError), - #[error("could not map GPU memory")] - MapMemory(#[source] MapError), - #[error("could not create a buffer")] - CreateBuffer(#[source] vk::Result), - #[error("could not bind memory to buffer")] - BindBufferMemory(#[source] vk::Result), - #[error("could not bind memory to image")] - BindImageMemory(#[source] vk::Result), - #[error("could not flush GPU memory")] - FlushMemory(#[source] vk::Result), - #[error("could not create an image")] - CreateImage(#[source] vk::Result), - #[error("could not create an image view")] - CreateImageView(#[source] vk::Result), - #[error("tried to render an unknown texture {0:?}")] - UnknownTexture(TextureId), - #[error("could not create a descriptor set layout")] - CreateDescriptorSetLayout(#[source] vk::Result), - #[error("could not create a pipeline layout")] - CreatePipelineLayout(#[source] vk::Result), - #[error("could not create a pipeline")] - CreatePipeline(#[source] vk::Result), - #[error("cannot perform a partial update of unknown texture {0:?}")] - PartialTextureUpdateForUnknownTexture(TextureId), - #[error("cannot perform out-of-bounds texture update for {0:?}")] - TextureUpdateOutOfBounds(TextureId), - #[error("could not allocate a command buffer")] - AllocateCommandBuffer(#[source] vk::Result), - #[error("could not begin a command buffer")] - BeginCommandBuffer(#[source] vk::Result), - #[error("could not end a command buffer")] - EndCommandBuffer(#[source] vk::Result), - #[error("could not create a semaphore")] - CreateSemaphore(#[source] vk::Result), - #[error("could not submit a command buffer")] - Submit(#[source] vk::Result), - #[error("could not get device properties")] - GetDeviceProperties(#[source] vk::Result), - #[error("could not create a command pool")] - CreateCommandPool(#[source] vk::Result), - #[error("driver does not support all required format features")] - MissingFormatFeatures, - #[error("could not get image format properties")] - GetImageFormatProperties(#[source] vk::Result), - #[error("texture is empty")] - EmptyImage, - #[error("texture is too large")] - TexTooLarge, - #[error("driver does not support sufficiently-large buffers")] - BufferTooLarge, - #[error("Could not enumerate the physical devices")] - EnumeratePhysicalDevice(#[source] vk::Result), - #[error("Could not find a corresponding vulkan device")] - NoVulkanDevice, - #[error("Device does not support vulkan 1.3")] - NoVulkan13, - #[error("Device does not support the synchronization2 feature")] - NoSynchronization2, - #[error("Device does not support the dynamic rendering feature")] - NoDynamicRendering, - #[error("Device does not support the device extension {}", .0.as_ustr().as_bytes().as_bstr())] - MissingDeviceExtensions(&'static CStr), - #[error("Device does not support importing sync files")] - NoSyncFileImport, - #[error("Device does not support exporting sync files")] - NoSyncFileExport, - #[error("Device does not have a graphics queue family")] - NoGfxQueueFamily, - #[error("Could not create the device")] - CreateDevice(#[source] vk::Result), - #[error("Only XRGB8888 is supported as the framebuffer format")] - WrongFbFormat, - #[error("The size of FB must be > 0")] - NonPositiveFbSize, - #[error("The modifier is not supported")] - UnsupportedModifier, - #[error("The number of planes is incorrect")] - WrongPlaneCount, - #[error("The FB is too large")] - TooLarge, - #[error("Could not query memory fd properties")] - GetMemoryFdProperties(#[source] vk::Result), - #[error("Could not find a memory type for import")] - NoMemoryTypeForImport, - #[error("Could not dup a dma buf")] - DupDmaBuf(#[source] OsError), - #[error("Could not import memory")] - ImportMemory(#[source] vk::Result), - #[error("Could not dup a sync file")] - DupSyncFile(#[source] OsError), - #[error("Could not import a sync file")] - ImportSyncFile(#[source] vk::Result), -} - -pub struct EgvRenderer { - ri: Rc, - timeline_semaphore: Option>>, - _task: SpawnedFuture<()>, -} - -linear_ids!(EgvContextIds, EgvContextId, u64); - -pub struct EgvContext { - renderer: Rc, - id: EgvContextId, -} - -pub struct EgvFramebuffer { - renderer: Rc, - ctx: Rc, - image: Rc>, -} - -pub struct Support { - pub modifier: Modifier, - pub planes: usize, - pub max_width: u32, - pub max_height: u32, -} - -struct EgvRendererInner { - instance: VulkanCoreInstance, - sync_ctx: Option>, - eventfd_cache: Rc, - supports_timeline_opaque_export: bool, - device: Device, - queue: Queue, - queue_family: u32, - external_fence_fd: external_fence_fd::Device, - external_semaphore_fd: external_semaphore_fd::Device, - external_memory_fd: external_memory_fd::Device, - push_descriptor: push_descriptor::Device, - vert: ShaderModule, - frag: ShaderModule, - non_coherent_atom_size: u64, - descriptor_set_layout: DescriptorSetLayout, - pipeline_layout: PipelineLayout, - max_tex_width: u32, - max_tex_height: u32, - max_buffer_size: u64, - allocator: RefCell>, - pool: CommandPool, - cache: RefCell, - submissions: Rc, - pipeline: Pipeline, - dmabuf_support: Vec, - context_ids: EgvContextIds, -} - -#[derive(Default)] -struct EgvRendererCache { - device_local_buffers: Vec, - samplers: AHashMap>, - images: AHashMap<(EgvContextId, TextureId), EgvSampledImage>, - upload_todos: Vec<(Rc>, EgvBuffer, ImageDelta)>, - buffer_memory_barriers: Vec>, - initial_image_memory_barriers: Vec>, - final_image_memory_barriers: Vec>, - semaphores: Vec, -} - -struct EgvBuffer { - ri: Rc, - memory: EgvAllocatedMemory, - buffer: Buffer, - size: u64, - usage: BufferUsageFlags, - mapping: *mut [u8], - host_coherent: bool, -} - -struct EgvImportedMemory { - ri: Rc, - _bo: Rc, - memories: PlaneVec, -} - -struct EgvAllocatedMemory { - ri: Rc, - block: ManuallyDrop>, - mapping: Option<*mut [u8]>, -} - -struct EgvCommandBuffer { - ri: Rc, - buf: CommandBuffer, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct VkVertex { - pos: [f32; 2], - uv: [f32; 2], - color: [u8; 4], -} - -unsafe impl Pod for VkVertex {} -unsafe impl Packed for VkVertex {} - -struct VkSampler { - ri: Rc, - options: TextureOptions, - sampler: Sampler, -} - -#[derive(Clone)] -struct EgvSampledImage { - image: Rc>, - sampler: Rc, -} - -struct EgvImage { - ri: Rc, - width: u32, - height: u32, - image: Image, - image_view: ImageView, - _memory: M, - layout: Cell, -} - -#[derive(Default)] -struct PendingSubmissions { - task_has_pending: Cell, - pending: AsyncQueue, -} - -struct Pending { - ri: Rc, - sync: Option, - semaphore: Option, - vulkan_sync: VulkanSync, - _cmd: EgvCommandBuffer, - _uploads: Vec<(Rc>, EgvBuffer)>, - _sampled: Vec, - _fb: Rc>, - index_buffer: Option, - vertex_buffer: Option, -} - -struct EgvSemaphore { - ri: Rc, - semaphore: Semaphore, -} - -const SRGB_FORMAT: Format = Format::R8G8B8A8_SRGB; -const SRGB_FORMAT_BPP: u64 = 4; -pub const EGV_FORMAT: &crate::format::Format = XRGB8888; -const VK_FB_FORMAT: Format = Format::B8G8R8A8_SRGB; - -const DEVICE_EXTENSIONS: [&CStr; 7] = [ - external_fence_fd::NAME, - external_semaphore_fd::NAME, - external_memory_fd::NAME, - external_memory_dma_buf::NAME, - image_drm_format_modifier::NAME, - queue_family_foreign::NAME, - push_descriptor::NAME, -]; - -const VERT: &[u8] = include_bytes!("shaders_bin/shader.vert.spv"); -const FRAG: &[u8] = include_bytes!("shaders_bin/shader.frag.spv"); - -const IMAGE_SUBRESOURCE_RANGE: ImageSubresourceRange = ImageSubresourceRange { - aspect_mask: ImageAspectFlags::COLOR, - base_mip_level: 0, - level_count: 1, - base_array_layer: 0, - layer_count: 1, -}; - -const IMAGE_SUBRESOURCE_LAYERS: ImageSubresourceLayers = ImageSubresourceLayers { - aspect_mask: ImageAspectFlags::COLOR, - mip_level: 0, - base_array_layer: 0, - layer_count: 1, -}; - -impl EgvRenderer { - pub fn new( - eng: &Rc, - ring: &Rc, - eventfd_cache: &Rc, - dev: Option, - ) -> Result, EgvError> { - let core_instance = VulkanCoreInstance::new(Level::Debug)?; - let instance = &core_instance.instance; - let mut physical_device; - let mut device_extensions; - let mut device_properties; - 'find_device: { - let devices = unsafe { - instance - .enumerate_physical_devices() - .map_err(EgvError::EnumeratePhysicalDevice)? - }; - for software in [false, true] { - 'outer: for &phy in &devices { - let res = unsafe { instance.enumerate_device_extension_properties(phy) }; - let exts = match res { - Ok(res) => map_extension_properties(res), - Err(e) => { - log::error!( - "Could not enumerate extensions of physical device: {}", - ErrorFmt(e), - ); - continue; - } - }; - let mut drm_props = PhysicalDeviceDrmPropertiesEXT::default(); - let mut props = PhysicalDeviceProperties2::default().push_next(&mut drm_props); - unsafe { - instance.get_physical_device_properties2(phy, &mut props); - } - let props = props.properties; - physical_device = phy; - device_extensions = exts; - device_properties = props; - if let Some(dev) = dev - && !software - { - if device_extensions.not_contains_key(physical_device_drm::NAME) { - continue 'outer; - } - let major = uapi::major(dev) as i64; - let minor = uapi::minor(dev) as i64; - let matches = (drm_props.has_primary == vk::TRUE - && drm_props.primary_major == major - && drm_props.primary_minor == minor) - || (drm_props.has_render == vk::TRUE - && drm_props.render_major == major - && drm_props.render_minor == minor); - if matches { - break 'find_device; - } - } else { - if device_properties.device_type == PhysicalDeviceType::CPU { - break 'find_device; - } - } - } - } - return Err(EgvError::NoVulkanDevice); - } - if device_properties.device_type == PhysicalDeviceType::CPU && dev.is_some() { - log::warn!("Using software rendering"); - } - if device_properties.api_version < VULKAN_API_VERSION { - return Err(EgvError::NoVulkan13); - } - for ext in DEVICE_EXTENSIONS { - if device_extensions.not_contains_key(ext) { - return Err(EgvError::MissingDeviceExtensions(ext)); - } - } - let features = { - let mut synchronization2_features = PhysicalDeviceSynchronization2Features::default(); - let mut dynamic_rendering_features = PhysicalDeviceDynamicRenderingFeatures::default(); - let mut timeline_semaphore_features = - PhysicalDeviceTimelineSemaphoreFeatures::default(); - let mut physical_device_features = PhysicalDeviceFeatures2::default() - .push_next(&mut synchronization2_features) - .push_next(&mut dynamic_rendering_features) - .push_next(&mut timeline_semaphore_features); - unsafe { - instance - .get_physical_device_features2(physical_device, &mut physical_device_features); - } - let features = physical_device_features.features; - if synchronization2_features.synchronization2 != vk::TRUE { - return Err(EgvError::NoSynchronization2); - } - if dynamic_rendering_features.dynamic_rendering != vk::TRUE { - return Err(EgvError::NoDynamicRendering); - } - VulkanDeviceFeatures { - features, - semaphore_features: timeline_semaphore_features, - } - }; - { - let info = PhysicalDeviceExternalSemaphoreInfo::default() - .handle_type(ExternalSemaphoreHandleTypeFlags::SYNC_FD); - let mut props = ExternalSemaphoreProperties::default(); - unsafe { - instance.get_physical_device_external_semaphore_properties( - physical_device, - &info, - &mut props, - ); - } - let supported = props - .external_semaphore_features - .contains(ExternalSemaphoreFeatureFlags::IMPORTABLE); - if !supported { - return Err(EgvError::NoSyncFileImport); - } - } - { - let info = PhysicalDeviceExternalFenceInfo::default() - .handle_type(ExternalFenceHandleTypeFlags::SYNC_FD); - let mut props = ExternalFenceProperties::default(); - unsafe { - instance.get_physical_device_external_fence_properties( - physical_device, - &info, - &mut props, - ); - } - let supported = props - .external_fence_features - .contains(ExternalFenceFeatureFlags::EXPORTABLE); - if !supported { - return Err(EgvError::NoSyncFileExport); - } - } - let queue_family = 'queue_family: { - let families = - unsafe { instance.get_physical_device_queue_family_properties(physical_device) }; - for (idx, family) in families.iter().enumerate() { - if family.queue_count > 0 && family.queue_flags.contains(QueueFlags::GRAPHICS) { - break 'queue_family idx as u32; - } - } - return Err(EgvError::NoGfxQueueFamily); - }; - let dmabuf_support = { - let mut list = vec![]; - for attach in [false, true] { - let mut modifiers = DrmFormatModifierPropertiesListEXT::default(); - if attach { - modifiers = modifiers.drm_format_modifier_properties(&mut list); - } - let mut out = FormatProperties2::default().push_next(&mut modifiers); - unsafe { - instance.get_physical_device_format_properties2( - physical_device, - VK_FB_FORMAT, - &mut out, - ); - } - if !attach { - list = vec![ - DrmFormatModifierPropertiesEXT::default(); - modifiers.drm_format_modifier_count as usize - ]; - } - } - let mut support = vec![]; - for modifier in list { - let image_features = modifier.drm_format_modifier_tiling_features; - if !image_features.contains( - FormatFeatureFlags::COLOR_ATTACHMENT - | FormatFeatureFlags::COLOR_ATTACHMENT_BLEND, - ) { - continue; - } - let mut modifier_info = PhysicalDeviceImageDrmFormatModifierInfoEXT::default() - .drm_format_modifier(modifier.drm_format_modifier); - let mut external_memory_info = PhysicalDeviceExternalImageFormatInfoKHR::default() - .handle_type(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); - let info = PhysicalDeviceImageFormatInfo2::default() - .format(VK_FB_FORMAT) - .ty(ImageType::TYPE_2D) - .tiling(ImageTiling::DRM_FORMAT_MODIFIER_EXT) - .usage(ImageUsageFlags::COLOR_ATTACHMENT) - .push_next(&mut external_memory_info) - .push_next(&mut modifier_info); - let mut external_memory_prop = ExternalImageFormatPropertiesKHR::default(); - let mut prop = - ImageFormatProperties2::default().push_next(&mut external_memory_prop); - let res = unsafe { - instance.get_physical_device_image_format_properties2( - physical_device, - &info, - &mut prop, - ) - }; - if res.is_err() { - continue; - } - let prop = prop.image_format_properties; - let memory_features = external_memory_prop - .external_memory_properties - .external_memory_features; - if !memory_features.contains(ExternalMemoryFeatureFlags::IMPORTABLE) { - continue; - } - let me = prop.max_extent; - if me.width > 0 && me.height > 0 && me.depth > 0 { - support.push(Support { - modifier: modifier.drm_format_modifier, - planes: modifier.drm_format_modifier_plane_count as usize, - max_width: me.width, - max_height: me.height, - }); - } - } - support - }; - let supports_timeline_opaque_export = - core_instance.supports_timeline_opaque_export(physical_device, &features); - let format_properties = - unsafe { instance.get_physical_device_format_properties(physical_device, SRGB_FORMAT) }; - let required_features = FormatFeatureFlags::SAMPLED_IMAGE - | FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR - | FormatFeatureFlags::TRANSFER_DST; - if !format_properties - .optimal_tiling_features - .contains(required_features) - { - return Err(EgvError::MissingFormatFeatures); - } - let format_properties = unsafe { - instance - .get_physical_device_image_format_properties( - physical_device, - SRGB_FORMAT, - ImageType::TYPE_2D, - ImageTiling::OPTIMAL, - ImageUsageFlags::SAMPLED | ImageUsageFlags::TRANSFER_DST, - ImageCreateFlags::empty(), - ) - .map_err(EgvError::GetImageFormatProperties)? - }; - let max_buffer_size; - { - let mut prop13 = PhysicalDeviceVulkan13Properties::default(); - let mut prop = PhysicalDeviceProperties2::default().push_next(&mut prop13); - unsafe { - instance.get_physical_device_properties2(physical_device, &mut prop); - } - max_buffer_size = prop13.max_buffer_size; - } - let device = { - let queue_create_info = DeviceQueueCreateInfo::default() - .queue_family_index(queue_family) - .queue_priorities(&[1.0]); - let extensions = DEVICE_EXTENSIONS.map(|e| e.as_ptr()); - let mut dynamic_rendering_features = - PhysicalDeviceDynamicRenderingFeatures::default().dynamic_rendering(true); - let mut synchronization2_features = - PhysicalDeviceSynchronization2Features::default().synchronization2(true); - let mut timeline_semaphore_features = - PhysicalDeviceTimelineSemaphoreFeatures::default() - .timeline_semaphore(supports_timeline_opaque_export); - let info = DeviceCreateInfo::default() - .queue_create_infos(slice::from_ref(&queue_create_info)) - .enabled_extension_names(&extensions) - .push_next(&mut synchronization2_features) - .push_next(&mut dynamic_rendering_features) - .push_next(&mut timeline_semaphore_features); - unsafe { - instance - .create_device(physical_device, &info, None) - .map_err(EgvError::CreateDevice)? - } - }; - let destroy_device = on_drop(|| unsafe { device.destroy_device(None) }); - let external_fence_fd = external_fence_fd::Device::new(instance, &device); - let external_semaphore_fd = external_semaphore_fd::Device::new(instance, &device); - let external_memory_fd = external_memory_fd::Device::new(instance, &device); - let push_descriptor = push_descriptor::Device::new(instance, &device); - let queue = unsafe { device.get_device_queue(queue_family, 0) }; - let pool = { - let info = CommandPoolCreateInfo::default() - .queue_family_index(queue_family) - .flags(CommandPoolCreateFlags::RESET_COMMAND_BUFFER); - unsafe { - device - .create_command_pool(&info, None) - .map_err(EgvError::CreateCommandPool)? - } - }; - let destroy_pool = on_drop(|| unsafe { device.destroy_command_pool(pool, None) }); - let create_shader = |src: &[u8]| { - let mut cursor = Cursor::new(src); - let spv = read_spv(&mut cursor).map_err(EgvError::ReadSpv)?; - let create_info = ShaderModuleCreateInfo::default().code(&spv); - unsafe { - device - .create_shader_module(&create_info, None) - .map_err(EgvError::CreateShaderModule) - } - }; - let vert = create_shader(VERT)?; - let destroy_vert = on_drop(|| unsafe { device.destroy_shader_module(vert, None) }); - let frag = create_shader(FRAG)?; - let destroy_frag = on_drop(|| unsafe { device.destroy_shader_module(frag, None) }); - let descriptor_set_layout = { - let binding = DescriptorSetLayoutBinding::default() - .descriptor_type(DescriptorType::COMBINED_IMAGE_SAMPLER) - .descriptor_count(1) - .stage_flags(ShaderStageFlags::FRAGMENT); - let create_info = DescriptorSetLayoutCreateInfo::default() - .flags(DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR_KHR) - .bindings(slice::from_ref(&binding)); - unsafe { - device - .create_descriptor_set_layout(&create_info, None) - .map_err(EgvError::CreateDescriptorSetLayout)? - } - }; - let destroy_descriptor_set_layout = on_drop(|| unsafe { - device.destroy_descriptor_set_layout(descriptor_set_layout, None) - }); - let pipeline_layout = { - let create_info = PipelineLayoutCreateInfo::default() - .set_layouts(slice::from_ref(&descriptor_set_layout)); - unsafe { - device - .create_pipeline_layout(&create_info, None) - .map_err(EgvError::CreatePipelineLayout)? - } - }; - let destroy_pipeline_layout = - on_drop(|| unsafe { device.destroy_pipeline_layout(pipeline_layout, None) }); - let mut device_properties = unsafe { - crate::vulkan_core::gpu_alloc_ash::device_properties(instance, physical_device) - .map_err(EgvError::GetDeviceProperties)? - }; - device_properties.buffer_device_address = false; - let non_coherent_atom_size = device_properties.non_coherent_atom_size; - let allocator = GpuAllocator::new(Config::i_am_potato(), device_properties); - let pipeline = { - let stages = [ - PipelineShaderStageCreateInfo::default() - .stage(ShaderStageFlags::VERTEX) - .module(vert) - .name(c"main"), - PipelineShaderStageCreateInfo::default() - .stage(ShaderStageFlags::FRAGMENT) - .module(frag) - .name(c"main"), - ]; - let vertex_input_binding_description = VertexInputBindingDescription { - binding: 0, - stride: size_of::() as _, - input_rate: VertexInputRate::VERTEX, - }; - let vertex_attribute_descriptions = [ - VertexInputAttributeDescription::default() - .location(0) - .format(Format::R32G32_SFLOAT) - .offset(offset_of!(Vertex, pos) as u32), - VertexInputAttributeDescription::default() - .location(1) - .format(Format::R32G32_SFLOAT) - .offset(offset_of!(Vertex, uv) as u32), - VertexInputAttributeDescription::default() - .location(2) - .format(Format::R8G8B8A8_UNORM) - .offset(offset_of!(Vertex, color) as u32), - ]; - let vertex_input_state = PipelineVertexInputStateCreateInfo::default() - .vertex_binding_descriptions(slice::from_ref(&vertex_input_binding_description)) - .vertex_attribute_descriptions(&vertex_attribute_descriptions); - let input_assembly_info = PipelineInputAssemblyStateCreateInfo::default() - .topology(PrimitiveTopology::TRIANGLE_LIST); - let viewport_state = PipelineViewportStateCreateInfo::default() - .viewport_count(1) - .scissor_count(1); - let rasterization_state = PipelineRasterizationStateCreateInfo::default() - .polygon_mode(PolygonMode::FILL) - .cull_mode(CullModeFlags::NONE) - .front_face(FrontFace::CLOCKWISE) - .line_width(1.0); - let multisampling_state = PipelineMultisampleStateCreateInfo::default() - .rasterization_samples(SampleCountFlags::TYPE_1) - .min_sample_shading(1.0); - let color_blend_attachment_state = PipelineColorBlendAttachmentState::default() - .blend_enable(true) - .src_color_blend_factor(BlendFactor::ONE) - .dst_color_blend_factor(BlendFactor::ONE_MINUS_SRC_ALPHA) - .color_blend_op(BlendOp::ADD) - .src_alpha_blend_factor(BlendFactor::ONE) - .dst_alpha_blend_factor(BlendFactor::ONE_MINUS_SRC_ALPHA) - .alpha_blend_op(BlendOp::ADD) - .color_write_mask(ColorComponentFlags::RGBA); - let color_blend_state = PipelineColorBlendStateCreateInfo::default() - .attachments(slice::from_ref(&color_blend_attachment_state)); - let dynamic_state = PipelineDynamicStateCreateInfo::default() - .dynamic_states(&[DynamicState::VIEWPORT, DynamicState::SCISSOR]); - let mut rendering_create_info = PipelineRenderingCreateInfo::default() - .color_attachment_formats(slice::from_ref(&VK_FB_FORMAT)); - let create_info = GraphicsPipelineCreateInfo::default() - .stages(&stages) - .vertex_input_state(&vertex_input_state) - .input_assembly_state(&input_assembly_info) - .viewport_state(&viewport_state) - .rasterization_state(&rasterization_state) - .multisample_state(&multisampling_state) - .color_blend_state(&color_blend_state) - .dynamic_state(&dynamic_state) - .layout(pipeline_layout) - .push_next(&mut rendering_create_info); - let mut pipelines = unsafe { - device - .create_graphics_pipelines( - PipelineCache::null(), - slice::from_ref(&create_info), - None, - ) - .map_err(|e| EgvError::CreatePipeline(e.1))? - }; - pipelines.pop().unwrap() - }; - let destroy_pipeline = on_drop(|| unsafe { device.destroy_pipeline(pipeline, None) }); - let submissions = Rc::new(PendingSubmissions::default()); - let sync_ctx = dev - .and_then(|d| { - SyncobjCtx::from_dev_t(d) - .inspect_err(|e| log::warn!("Could not create a syncobj ctx: {}", ErrorFmt(e))) - .ok() - }) - .map(Rc::new); - destroy_pipeline.forget(); - destroy_pool.forget(); - destroy_pipeline_layout.forget(); - destroy_descriptor_set_layout.forget(); - destroy_frag.forget(); - destroy_vert.forget(); - destroy_device.forget(); - let renderer = Rc::new(EgvRendererInner { - push_descriptor, - sync_ctx, - eventfd_cache: eventfd_cache.clone(), - supports_timeline_opaque_export, - device, - queue, - queue_family, - external_fence_fd, - external_semaphore_fd, - vert, - frag, - non_coherent_atom_size, - descriptor_set_layout, - pipeline_layout, - max_tex_width: format_properties.max_extent.width, - max_tex_height: format_properties.max_extent.height, - max_buffer_size, - allocator: RefCell::new(allocator), - pool, - cache: Default::default(), - submissions: submissions.clone(), - pipeline, - instance: core_instance, - external_memory_fd, - dmabuf_support, - context_ids: Default::default(), - }); - let task = { - let future = wait_for_submissions(submissions, renderer.clone(), ring.clone()); - eng.spawn("egui-vulkan-await-pending", future) - }; - let renderer = Self { - timeline_semaphore: renderer.create_timeline_semaphore_or_log(), - ri: renderer, - _task: task, - }; - Ok(Rc::new(renderer)) - } - - fn create_semaphore(&self) -> Result { - let ri = &self.ri; - let create_info = SemaphoreCreateInfo::default(); - let semaphore = unsafe { - ri.device - .create_semaphore(&create_info, None) - .map_err(EgvError::CreateSemaphore)? - }; - Ok(EgvSemaphore { - ri: ri.clone(), - semaphore, - }) - } - - fn allocate_command_buffer(&self) -> Result { - let ri = &self.ri; - let allocate_info = CommandBufferAllocateInfo::default() - .command_pool(ri.pool) - .command_buffer_count(1) - .level(CommandBufferLevel::PRIMARY); - let mut cmd = unsafe { - ri.device - .allocate_command_buffers(&allocate_info) - .map_err(EgvError::AllocateCommandBuffer)? - }; - Ok(EgvCommandBuffer { - ri: ri.clone(), - buf: cmd.pop().unwrap(), - }) - } - - fn create_image( - self: &Rc, - data: &ImageData, - ) -> Result>, EgvError> { - let extent = Extent3D { - width: data.width() as _, - height: data.height() as _, - depth: 1, - }; - if extent.width == 0 || extent.height == 0 { - return Err(EgvError::EmptyImage); - } - let ri = &self.ri; - if extent.width > ri.max_tex_width || extent.height > ri.max_tex_height { - return Err(EgvError::TexTooLarge); - } - let dev = &ri.device; - let image = { - let create_info = ImageCreateInfo::default() - .image_type(ImageType::TYPE_2D) - .format(SRGB_FORMAT) - .extent(extent) - .mip_levels(1) - .array_layers(1) - .samples(SampleCountFlags::TYPE_1) - .tiling(ImageTiling::OPTIMAL) - .usage(ImageUsageFlags::SAMPLED | ImageUsageFlags::TRANSFER_DST) - .sharing_mode(SharingMode::EXCLUSIVE); - unsafe { - dev.create_image(&create_info, None) - .map_err(EgvError::CreateImage)? - } - }; - let destroy_image = on_drop(|| unsafe { dev.destroy_image(image, None) }); - let memory = { - let req = unsafe { dev.get_image_memory_requirements(image) }; - self.allocate_memory(req, UsageFlags::FAST_DEVICE_ACCESS, false)? - }; - unsafe { - dev.bind_image_memory(image, *memory.block.memory(), memory.block.offset()) - .map_err(EgvError::BindImageMemory)?; - } - let view = { - let create_info = ImageViewCreateInfo::default() - .image(image) - .view_type(ImageViewType::TYPE_2D) - .format(SRGB_FORMAT) - .components(ComponentMapping { - r: ComponentSwizzle::R, - g: ComponentSwizzle::G, - b: ComponentSwizzle::B, - a: ComponentSwizzle::A, - }) - .subresource_range(IMAGE_SUBRESOURCE_RANGE); - unsafe { - dev.create_image_view(&create_info, None) - .map_err(EgvError::CreateImageView)? - } - }; - let destroy_image_view = on_drop(|| unsafe { dev.destroy_image_view(view, None) }); - destroy_image_view.forget(); - destroy_image.forget(); - Ok(Rc::new(EgvImage { - ri: ri.clone(), - width: extent.width, - height: extent.height, - image, - _memory: memory, - image_view: view, - layout: Cell::new(ImageLayout::UNDEFINED), - })) - } - - fn get_device_local_buffer( - &self, - sync: &mut EgvRendererCache, - size: u64, - usage: BufferUsageFlags, - ) -> Result { - { - let mut best = None; - let mut best_size = u64::MAX; - for (i, buf) in sync.device_local_buffers.iter().enumerate() { - if buf.size < size { - continue; - } - if buf.usage != usage { - continue; - } - if buf.size < best_size { - best = Some(i); - best_size = buf.size; - } - } - if let Some(best) = best { - return Ok(sync.device_local_buffers.swap_remove(best)); - } - } - self.create_device_local_buffer(size, usage) - } - - fn create_device_local_buffer( - &self, - size: u64, - usage: BufferUsageFlags, - ) -> Result { - self.create_buffer( - size, - usage, - UsageFlags::FAST_DEVICE_ACCESS | UsageFlags::UPLOAD, - ) - } - - fn create_staging_buffer(&self, size: u64) -> Result { - self.create_buffer( - size, - BufferUsageFlags::TRANSFER_SRC, - UsageFlags::TRANSIENT | UsageFlags::UPLOAD, - ) - } - - fn create_buffer( - &self, - mut size: u64, - usage: BufferUsageFlags, - usage_flags: UsageFlags, - ) -> Result { - const MIN_SIZE: u64 = 1024; - size = size.max(MIN_SIZE); - let ri = &self.ri; - if size > ri.max_buffer_size { - return Err(EgvError::BufferTooLarge); - } - let dev = &ri.device; - let buffer = { - let create_info = BufferCreateInfo::default().size(size).usage(usage); - unsafe { - dev.create_buffer(&create_info, None) - .map_err(EgvError::CreateBuffer)? - } - }; - let destroy_buffer = on_drop(|| unsafe { dev.destroy_buffer(buffer, None) }); - let memory_requirements = unsafe { dev.get_buffer_memory_requirements(buffer) }; - let memory = self.allocate_memory(memory_requirements, usage_flags, true)?; - unsafe { - dev.bind_buffer_memory(buffer, *memory.block.memory(), memory.block.offset()) - .map_err(EgvError::BindBufferMemory)?; - } - destroy_buffer.forget(); - Ok(EgvBuffer { - ri: ri.clone(), - mapping: memory.mapping.unwrap(), - host_coherent: memory - .block - .props() - .contains(MemoryPropertyFlags::HOST_COHERENT), - memory, - buffer, - size, - usage, - }) - } - - fn allocate_memory( - &self, - req: MemoryRequirements, - usage: UsageFlags, - map: bool, - ) -> Result { - let request = Request { - size: req.size, - align_mask: req.alignment - 1, - usage, - memory_types: req.memory_type_bits, - }; - let ri = &self.ri; - let block = unsafe { - ri.allocator - .borrow_mut() - .alloc(AshMemoryDevice::wrap(&ri.device), request) - .map_err(EgvError::AllocateMemory)? - }; - let block = RefCell::new(ManuallyDrop::new(block)); - let deallocate = on_drop(|| unsafe { - ri.allocator.borrow_mut().dealloc( - AshMemoryDevice::wrap(&ri.device), - ManuallyDrop::take(&mut block.borrow_mut()), - ); - }); - let mut block_mut = block.borrow_mut(); - let mut mapping = None; - if map { - let size = block_mut.size() as usize; - let ptr = unsafe { - block_mut - .map(AshMemoryDevice::wrap(&ri.device), 0, size) - .map_err(EgvError::MapMemory)? - }; - let slice = unsafe { slice::from_raw_parts_mut(ptr.as_ptr(), size) }; - mapping = Some(slice as *mut [u8]); - } - drop(block_mut); - deallocate.forget(); - Ok(EgvAllocatedMemory { - ri: ri.clone(), - block: block.into_inner(), - mapping, - }) - } - - fn fill_index_buffer( - &self, - sync: &mut EgvRendererCache, - primitives: &[ClippedPrimitive], - ) -> Result { - let indices: Vec<_> = primitives - .iter() - .filter_map(|c| match &c.primitive { - Primitive::Mesh(m) => Some(&m.indices), - Primitive::Callback(_) => None, - }) - .flat_map(|i| i.iter().copied()) - .collect(); - let indices: &[u8] = uapi::as_bytes(&*indices); - let buffer = self.get_device_local_buffer( - sync, - indices.len() as u64, - BufferUsageFlags::INDEX_BUFFER, - )?; - buffer.upload(indices)?; - Ok(buffer) - } - - fn get_sampler( - self: &Rc, - samplers: &mut AHashMap>, - options: &TextureOptions, - ) -> Result, EgvError> { - let sampler = match samplers.entry(*options) { - Entry::Occupied(o) => o.get().clone(), - Entry::Vacant(v) => { - let s = self.create_sampler(options)?; - v.insert(s).clone() - } - }; - Ok(sampler) - } - - fn create_sampler( - self: &Rc, - options: &TextureOptions, - ) -> Result, EgvError> { - let address_mode = match options.wrap_mode { - TextureWrapMode::ClampToEdge => SamplerAddressMode::CLAMP_TO_EDGE, - TextureWrapMode::Repeat => SamplerAddressMode::REPEAT, - TextureWrapMode::MirroredRepeat => SamplerAddressMode::MIRRORED_REPEAT, - }; - let map_filter = |f: TextureFilter| match f { - TextureFilter::Nearest => Filter::NEAREST, - TextureFilter::Linear => Filter::LINEAR, - }; - let create_info = SamplerCreateInfo::default() - .mag_filter(map_filter(options.magnification)) - .min_filter(map_filter(options.minification)) - .address_mode_u(address_mode) - .address_mode_v(address_mode) - .address_mode_w(address_mode) - .mipmap_mode(SamplerMipmapMode::NEAREST) - .max_anisotropy(1.0) - .min_lod(0.0) - .max_lod(0.25) - .border_color(BorderColor::FLOAT_TRANSPARENT_BLACK); - let ri = &self.ri; - let sampler = unsafe { - ri.device - .create_sampler(&create_info, None) - .map_err(EgvError::CreateSampler)? - }; - Ok(Rc::new(VkSampler { - ri: ri.clone(), - options: *options, - sampler, - })) - } - - pub fn support(&self) -> &[Support] { - &self.ri.dmabuf_support - } - - pub fn max_texture_side(&self) -> usize { - self.ri.max_tex_width.min(self.ri.max_tex_height) as usize - } - - pub fn create_context(self: &Rc) -> Rc { - Rc::new(EgvContext { - renderer: self.clone(), - id: self.ri.context_ids.next(), - }) - } -} - -async fn wait_for_submissions( - submissions: Rc, - dev: Rc, - ring: Rc, -) { - loop { - submissions.task_has_pending.set(false); - let pending = submissions.pending.pop().await; - submissions.task_has_pending.set(true); - if let Some(sync) = &pending.sync - && let Err(e) = sync.try_signaled(&ring).await - { - log::warn!( - "Could not wait for sync file to become readable: {}", - ErrorFmt(e), - ); - dev.wait_idle(); - } - pending.vulkan_sync.handle_validation(); - } -} - -impl EgvRendererInner { - fn wait_idle(&self) { - log::warn!("Blocking"); - let res = unsafe { self.device.device_wait_idle() }; - if let Err(e) = res { - log::error!("Could not wait for device idle: {}", ErrorFmt(e)); - log::error!("This is unsound."); - } - self.submissions.pending.clear(); - } -} - -impl EgvContext { - pub fn import_framebuffer( - self: &Rc, - bo: &Rc, - ) -> Result, EgvError> { - let ri = &self.renderer.ri; - let buf = bo.dmabuf(); - if buf.format != EGV_FORMAT { - return Err(EgvError::WrongFbFormat); - } - if buf.width <= 0 || buf.height <= 0 { - return Err(EgvError::NonPositiveFbSize); - } - let Some(support) = ri - .dmabuf_support - .iter() - .find(|s| s.modifier == buf.modifier) - else { - return Err(EgvError::UnsupportedModifier); - }; - if buf.planes.len() != support.planes { - return Err(EgvError::WrongPlaneCount); - } - let width = buf.width as u32; - let height = buf.height as u32; - if width > support.max_width || height > support.max_height { - return Err(EgvError::TooLarge); - } - let dev = &ri.device; - let disjoint = buf.is_disjoint(); - let image = { - let image_create_flags = match disjoint { - true => ImageCreateFlags::DISJOINT, - false => ImageCreateFlags::empty(), - }; - let plane_layouts: PlaneVec<_> = buf - .planes - .iter() - .map(|p| SubresourceLayout { - offset: p.offset as _, - row_pitch: p.stride as _, - size: 0, - array_pitch: 0, - depth_pitch: 0, - }) - .collect(); - let mut mod_info = ImageDrmFormatModifierExplicitCreateInfoEXT::default() - .drm_format_modifier(buf.modifier) - .plane_layouts(&plane_layouts); - let mut memory_image_create_info = ExternalMemoryImageCreateInfo::default() - .handle_types(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); - let info = ImageCreateInfo::default() - .flags(image_create_flags) - .image_type(ImageType::TYPE_2D) - .format(VK_FB_FORMAT) - .extent(Extent3D { - width, - height, - depth: 1, - }) - .mip_levels(1) - .array_layers(1) - .samples(SampleCountFlags::TYPE_1) - .tiling(ImageTiling::DRM_FORMAT_MODIFIER_EXT) - .usage(ImageUsageFlags::COLOR_ATTACHMENT) - .sharing_mode(SharingMode::EXCLUSIVE) - .initial_layout(ImageLayout::UNDEFINED) - .push_next(&mut mod_info) - .push_next(&mut memory_image_create_info); - unsafe { - dev.create_image(&info, None) - .map_err(EgvError::CreateImage)? - } - }; - let destroy_image = on_drop(|| unsafe { dev.destroy_image(image, None) }); - let mut memories = PlaneVec::new(); - let mut free_memories = PlaneVec::new(); - { - let num_device_memories = match disjoint { - true => buf.planes.len(), - false => 1, - }; - let mut bind_image_plane_memory_infos = PlaneVec::new(); - for plane_idx in 0..num_device_memories { - let dma_buf_plane = &buf.planes[plane_idx]; - let mut image_memory_requirements_info = - ImageMemoryRequirementsInfo2::default().image(image); - let mut image_plane_memory_requirements_info; - if disjoint { - let plane_aspect = match plane_idx { - 0 => ImageAspectFlags::MEMORY_PLANE_0_EXT, - 1 => ImageAspectFlags::MEMORY_PLANE_1_EXT, - 2 => ImageAspectFlags::MEMORY_PLANE_2_EXT, - 3 => ImageAspectFlags::MEMORY_PLANE_3_EXT, - _ => unreachable!(), - }; - image_plane_memory_requirements_info = - ImagePlaneMemoryRequirementsInfo::default().plane_aspect(plane_aspect); - image_memory_requirements_info = image_memory_requirements_info - .push_next(&mut image_plane_memory_requirements_info); - bind_image_plane_memory_infos - .push(BindImagePlaneMemoryInfo::default().plane_aspect(plane_aspect)); - } - let mut memory_requirements = MemoryRequirements2::default(); - unsafe { - dev.get_image_memory_requirements2( - &image_memory_requirements_info, - &mut memory_requirements, - ); - } - let mut fd_props = MemoryFdPropertiesKHR::default(); - unsafe { - ri.external_memory_fd - .get_memory_fd_properties( - ExternalMemoryHandleTypeFlags::DMA_BUF_EXT, - dma_buf_plane.fd.raw(), - &mut fd_props, - ) - .map_err(EgvError::GetMemoryFdProperties)?; - } - let memory_type_bits = memory_requirements.memory_requirements.memory_type_bits - & fd_props.memory_type_bits; - if memory_type_bits == 0 { - return Err(EgvError::NoMemoryTypeForImport); - } - let fd = uapi::fcntl_dupfd_cloexec(dma_buf_plane.fd.raw(), 0) - .map_os_err(EgvError::DupDmaBuf)?; - let mut memory_dedicated_allocate_info = - MemoryDedicatedAllocateInfo::default().image(image); - let mut import_memory_fd_info = ImportMemoryFdInfoKHR::default() - .fd(fd.raw()) - .handle_type(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); - let memory_allocate_info = MemoryAllocateInfo::default() - .allocation_size(memory_requirements.memory_requirements.size) - .memory_type_index(memory_type_bits.trailing_zeros() as _) - .push_next(&mut import_memory_fd_info) - .push_next(&mut memory_dedicated_allocate_info); - let device_memory = unsafe { - dev.allocate_memory(&memory_allocate_info, None) - .map_err(EgvError::ImportMemory)? - }; - let _ = fd.unwrap(); - memories.push(device_memory); - free_memories.push(on_drop(move || unsafe { - dev.free_memory(device_memory, None) - })); - } - let mut bind_image_memory_infos = PlaneVec::new(); - let mut bind_image_plane_memory_infos = bind_image_plane_memory_infos.iter_mut(); - for mem in memories.iter().copied() { - let mut info = BindImageMemoryInfo::default().image(image).memory(mem); - if disjoint { - info = info.push_next(bind_image_plane_memory_infos.next().unwrap()); - } - bind_image_memory_infos.push(info); - } - unsafe { - dev.bind_image_memory2(&bind_image_memory_infos) - .map_err(EgvError::BindImageMemory)?; - } - } - let image_view = { - let info = ImageViewCreateInfo::default() - .image(image) - .view_type(ImageViewType::TYPE_2D) - .format(VK_FB_FORMAT) - .components(ComponentMapping { - r: ComponentSwizzle::IDENTITY, - g: ComponentSwizzle::IDENTITY, - b: ComponentSwizzle::IDENTITY, - a: ComponentSwizzle::IDENTITY, - }) - .subresource_range(IMAGE_SUBRESOURCE_RANGE); - unsafe { - dev.create_image_view(&info, None) - .map_err(EgvError::CreateImageView)? - } - }; - let destroy_image_view = on_drop(|| unsafe { dev.destroy_image_view(image_view, None) }); - destroy_image_view.forget(); - free_memories.into_iter().for_each(|f| f.forget()); - destroy_image.forget(); - let image = Rc::new(EgvImage { - ri: ri.clone(), - width, - height, - image, - image_view, - _memory: EgvImportedMemory { - ri: ri.clone(), - _bo: bo.clone(), - memories, - }, - layout: Cell::new(ImageLayout::UNDEFINED), - }); - let fb = Rc::new(EgvFramebuffer { - renderer: self.renderer.clone(), - ctx: self.clone(), - image, - }); - Ok(fb) - } -} - -impl EgvFramebuffer { - fn create_vertex_buffer( - &self, - sync: &mut EgvRendererCache, - pixels_per_point: f32, - primitives: &[ClippedPrimitive], - offset: (f32, f32), - ) -> Result { - let width = self.image.width as f32 / pixels_per_point; - let height = self.image.height as f32 / pixels_per_point; - let vertices: Vec<_> = primitives - .iter() - .filter_map(|c| match &c.primitive { - Primitive::Mesh(m) => Some(&m.vertices), - Primitive::Callback(_) => None, - }) - .flat_map(|i| i.iter().copied()) - .map(|mut v| { - v.pos.x = 2.0 * (v.pos.x + offset.0) / width - 1.0; - v.pos.y = 2.0 * (v.pos.y + offset.1) / height - 1.0; - VkVertex { - pos: [v.pos.x, v.pos.y], - uv: [v.uv.x, v.uv.y], - color: [v.color.r(), v.color.g(), v.color.b(), v.color.a()], - } - }) - .collect(); - let vertices: &[u8] = uapi::as_bytes(&*vertices); - let buffer = self.renderer.get_device_local_buffer( - sync, - vertices.len() as u64, - BufferUsageFlags::VERTEX_BUFFER, - )?; - buffer.upload(vertices)?; - Ok(buffer) - } - - pub fn render( - &self, - delta: TexturesDelta, - pixels_per_point: f32, - primitives: &[ClippedPrimitive], - offset: (f32, f32), - sync_file: Option<&SyncFile>, - ) -> Result, EgvError> { - let renderer = &self.renderer; - let ri = &renderer.ri; - let dev = &ri.device; - let cache = &mut *ri.cache.borrow_mut(); - let index_buffer = self.renderer.fill_index_buffer(cache, primitives)?; - let vertex_buffer = - self.create_vertex_buffer(cache, pixels_per_point, primitives, offset)?; - let uploads = &mut cache.upload_todos; - uploads.clear(); - for (id, delta) in delta.set { - let id = (self.ctx.id, id); - let mut options = delta.options; - options.mipmap_mode = None; - let mut create_sampled_image = || -> Result<_, EgvError> { - let sampler = renderer.get_sampler(&mut cache.samplers, &options)?; - let image = renderer.create_image(&delta.image)?; - let sampled = EgvSampledImage { - image: image.clone(), - sampler, - }; - Ok((image, sampled)) - }; - let image = match cache.images.entry(id) { - Entry::Occupied(mut o) => { - let t = o.get(); - if delta.pos.is_none() - && [t.image.width as usize, t.image.height as usize] != delta.image.size() - { - let (image, sampled) = create_sampled_image()?; - *o.get_mut() = sampled; - image - } else if t.sampler.options != options { - let sampler = self.renderer.get_sampler(&mut cache.samplers, &options)?; - let image = t.image.clone(); - *o.get_mut() = EgvSampledImage { - image: image.clone(), - sampler, - }; - image - } else { - t.image.clone() - } - } - Entry::Vacant(v) => { - if delta.pos.is_some() { - return Err(EgvError::PartialTextureUpdateForUnknownTexture(id.1)); - } - let (image, sampled) = create_sampled_image()?; - v.insert(sampled); - image - } - }; - if let Some(pos) = delta.pos { - let x2 = pos[0].saturating_add(delta.image.width()); - let y2 = pos[1].saturating_add(delta.image.height()); - if x2 > image.width as usize || y2 > image.height as usize { - return Err(EgvError::TextureUpdateOutOfBounds(id.1)); - } - } - let size = delta.image.width() as u64 * delta.image.height() as u64 * SRGB_FORMAT_BPP; - uploads.push((image.clone(), renderer.create_staging_buffer(size)?, delta)); - } - let buffer_memory_barriers = &mut cache.buffer_memory_barriers; - buffer_memory_barriers.clear(); - let initial_image_barriers = &mut cache.initial_image_memory_barriers; - initial_image_barriers.clear(); - let final_image_barriers = &mut cache.final_image_memory_barriers; - final_image_barriers.clear(); - for (image, buf, delta) in &*uploads { - match &delta.image { - ImageData::Color(c) => { - let pixels = unsafe { AssertPacked::new(&c.pixels as &[_]) }; - buf.upload(uapi::as_bytes(pixels))?; - } - } - buffer_memory_barriers.push( - BufferMemoryBarrier2::default() - .src_access_mask(AccessFlags2::HOST_WRITE) - .src_stage_mask(PipelineStageFlags2::HOST) - .dst_access_mask(AccessFlags2::TRANSFER_READ) - .dst_stage_mask(PipelineStageFlags2::TRANSFER) - .buffer(buf.buffer) - .size(WHOLE_SIZE), - ); - initial_image_barriers.push( - ImageMemoryBarrier2::default() - .src_access_mask(AccessFlags2::SHADER_READ) - .src_stage_mask(PipelineStageFlags2::FRAGMENT_SHADER) - .dst_access_mask(AccessFlags2::TRANSFER_WRITE) - .dst_stage_mask(PipelineStageFlags2::TRANSFER) - .old_layout(image.layout.get()) - .new_layout(ImageLayout::TRANSFER_DST_OPTIMAL) - .image(image.image) - .subresource_range(IMAGE_SUBRESOURCE_RANGE), - ); - final_image_barriers.push( - ImageMemoryBarrier2::default() - .src_access_mask(AccessFlags2::TRANSFER_WRITE) - .src_stage_mask(PipelineStageFlags2::TRANSFER) - .dst_access_mask(AccessFlags2::SHADER_READ) - .dst_stage_mask(PipelineStageFlags2::FRAGMENT_SHADER) - .old_layout(ImageLayout::TRANSFER_DST_OPTIMAL) - .new_layout(ImageLayout::SHADER_READ_ONLY_OPTIMAL) - .image(image.image) - .subresource_range(IMAGE_SUBRESOURCE_RANGE), - ); - } - let cmd = renderer.allocate_command_buffer()?; - let buf = cmd.buf; - { - let begin_info = - CommandBufferBeginInfo::default().flags(CommandBufferUsageFlags::ONE_TIME_SUBMIT); - unsafe { - dev.begin_command_buffer(buf, &begin_info) - .map_err(EgvError::BeginCommandBuffer)?; - } - } - unsafe { - let info = DependencyInfo::default() - .buffer_memory_barriers(&buffer_memory_barriers) - .image_memory_barriers(&initial_image_barriers); - dev.cmd_pipeline_barrier2(buf, &info); - } - for (image, staging, delta) in &*uploads { - let x = delta.pos.unwrap_or_default()[0] as i32; - let y = delta.pos.unwrap_or_default()[1] as i32; - let region = BufferImageCopy2::default() - .image_subresource(IMAGE_SUBRESOURCE_LAYERS) - .image_offset(Offset3D { x, y, z: 0 }) - .image_extent(Extent3D { - width: delta.image.width() as u32, - height: delta.image.height() as u32, - depth: 1, - }); - let info = CopyBufferToImageInfo2::default() - .src_buffer(staging.buffer) - .dst_image(image.image) - .dst_image_layout(ImageLayout::TRANSFER_DST_OPTIMAL) - .regions(slice::from_ref(®ion)); - unsafe { - dev.cmd_copy_buffer_to_image2(buf, &info); - } - } - { - final_image_barriers.push( - ImageMemoryBarrier2::default() - .dst_access_mask(AccessFlags2::COLOR_ATTACHMENT_WRITE) - .dst_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) - .old_layout(ImageLayout::GENERAL) - .new_layout(ImageLayout::GENERAL) - .src_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT) - .dst_queue_family_index(ri.queue_family) - .image(self.image.image) - .subresource_range(IMAGE_SUBRESOURCE_RANGE), - ); - final_image_barriers.push( - ImageMemoryBarrier2::default() - .src_access_mask(AccessFlags2::COLOR_ATTACHMENT_WRITE) - .src_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) - .dst_access_mask(AccessFlags2::COLOR_ATTACHMENT_WRITE) - .dst_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) - .old_layout(ImageLayout::GENERAL) - .new_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL) - .src_queue_family_index(ri.queue_family) - .dst_queue_family_index(ri.queue_family) - .image(self.image.image) - .subresource_range(IMAGE_SUBRESOURCE_RANGE), - ) - } - unsafe { - let info = DependencyInfo::default().image_memory_barriers(&final_image_barriers); - dev.cmd_pipeline_barrier2(buf, &info); - } - for primitive in primitives { - match &primitive.primitive { - Primitive::Mesh(m) => { - if cache.images.not_contains_key(&(self.ctx.id, m.texture_id)) { - return Err(EgvError::UnknownTexture(m.texture_id)); - } - } - Primitive::Callback(_) => { - unreachable!() - } - } - } - { - let rendering_attachment_info = RenderingAttachmentInfo::default() - .image_view(self.image.image_view) - .image_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL) - .load_op(AttachmentLoadOp::DONT_CARE) - .store_op(AttachmentStoreOp::STORE); - let rendering_info = RenderingInfoKHR::default() - .render_area(Rect2D { - offset: Default::default(), - extent: Extent2D { - width: self.image.width, - height: self.image.height, - }, - }) - .layer_count(1) - .color_attachments(slice::from_ref(&rendering_attachment_info)); - unsafe { - dev.cmd_begin_rendering(buf, &rendering_info); - } - } - if primitives.is_not_empty() { - unsafe { - dev.cmd_bind_pipeline(buf, PipelineBindPoint::GRAPHICS, ri.pipeline); - dev.cmd_bind_index_buffer(buf, index_buffer.buffer, 0, IndexType::UINT32); - dev.cmd_bind_vertex_buffers(buf, 0, &[vertex_buffer.buffer], &[0]); - dev.cmd_set_viewport( - buf, - 0, - &[Viewport { - x: 0.0, - y: 0.0, - width: self.image.width as f32, - height: self.image.height as f32, - min_depth: 0.0, - max_depth: 1.0, - }], - ); - } - } - let mut first_index = 0; - let mut vertex_offset = 0; - let mut sampled_images = Vec::with_capacity(primitives.len()); - for primitive in primitives { - let mesh = match &primitive.primitive { - Primitive::Mesh(m) => m, - Primitive::Callback(_) => unreachable!(), - }; - let sampled = cache.images.get(&(self.ctx.id, mesh.texture_id)).unwrap(); - sampled_images.push(sampled.clone()); - let image_info = DescriptorImageInfo::default() - .sampler(sampled.sampler.sampler) - .image_view(sampled.image.image_view) - .image_layout(ImageLayout::SHADER_READ_ONLY_OPTIMAL); - let write_descriptor_set = WriteDescriptorSet::default() - .descriptor_type(DescriptorType::COMBINED_IMAGE_SAMPLER) - .image_info(slice::from_ref(&image_info)); - unsafe { - ri.push_descriptor.cmd_push_descriptor_set( - buf, - PipelineBindPoint::GRAPHICS, - ri.pipeline_layout, - 0, - slice::from_ref(&write_descriptor_set), - ); - } - { - let c = primitive.clip_rect; - let x1 = ((c.min.x + offset.0) * pixels_per_point).floor().max(0.0) as i32; - let y1 = ((c.min.y + offset.1) * pixels_per_point).floor().max(0.0) as i32; - let x2 = ((c.max.x + offset.0) * pixels_per_point).ceil().max(0.0) as i32; - let y2 = ((c.max.y + offset.1) * pixels_per_point).ceil().max(0.0) as i32; - unsafe { - dev.cmd_set_scissor( - buf, - 0, - &[Rect2D { - offset: Offset2D { x: x1, y: y1 }, - extent: Extent2D { - width: x2.wrapping_sub(x1) as u32, - height: y2.wrapping_sub(y1) as u32, - }, - }], - ); - } - } - let index_count = mesh.indices.len() as u32; - unsafe { - dev.cmd_draw_indexed(buf, index_count, 1, first_index, vertex_offset, 0); - } - first_index += index_count; - vertex_offset += mesh.vertices.len() as i32; - } - unsafe { - dev.cmd_end_rendering(buf); - } - { - final_image_barriers.clear(); - final_image_barriers.push( - ImageMemoryBarrier2::default() - .src_access_mask(AccessFlags2::COLOR_ATTACHMENT_WRITE) - .src_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) - .dst_access_mask(AccessFlags2::COLOR_ATTACHMENT_WRITE) - .dst_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) - .old_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL) - .new_layout(ImageLayout::GENERAL) - .src_queue_family_index(ri.queue_family) - .dst_queue_family_index(ri.queue_family) - .image(self.image.image) - .subresource_range(IMAGE_SUBRESOURCE_RANGE), - ); - final_image_barriers.push( - ImageMemoryBarrier2::default() - .src_access_mask(AccessFlags2::COLOR_ATTACHMENT_WRITE) - .src_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) - .old_layout(ImageLayout::GENERAL) - .new_layout(ImageLayout::GENERAL) - .src_queue_family_index(ri.queue_family) - .dst_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT) - .image(self.image.image) - .subresource_range(IMAGE_SUBRESOURCE_RANGE), - ); - unsafe { - let info = DependencyInfo::default().image_memory_barriers(&final_image_barriers); - dev.cmd_pipeline_barrier2(buf, &info); - } - } - unsafe { - dev.end_command_buffer(buf) - .map_err(EgvError::EndCommandBuffer)?; - } - let mut semaphore = None; - let mut vk_semaphores = ArrayVec::<_, 1>::new(); - if let Some(sync_file) = sync_file { - let s = match cache.semaphores.pop() { - Some(f) => f, - None => renderer.create_semaphore()?, - }; - s.import(sync_file)?; - let info = SemaphoreSubmitInfo::default() - .semaphore(s.semaphore) - .stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT); - vk_semaphores.push(info); - semaphore = Some(s); - } - let command_buffer_info = CommandBufferSubmitInfo::default().command_buffer(buf); - let mut submit_info = SubmitInfo2::default() - .command_buffer_infos(slice::from_ref(&command_buffer_info)) - .wait_semaphore_infos(&vk_semaphores); - let mut semaphore_submit_info = SemaphoreSubmitInfo::default(); - let vulkan_sync = ri.create_sync( - renderer.timeline_semaphore.as_ref(), - &mut semaphore_submit_info, - &mut submit_info, - )?; - unsafe { - dev.queue_submit2(ri.queue, slice::from_ref(&submit_info), vulkan_sync.fence()) - .map_err(EgvError::Submit)?; - } - for id in delta.free { - cache.images.remove(&(self.ctx.id, id)); - } - let mut used_uploads = Vec::with_capacity(uploads.len()); - for (image, staging, _) in uploads.drain(..) { - image.layout.set(ImageLayout::SHADER_READ_ONLY_OPTIMAL); - used_uploads.push((image, staging)); - } - let sync = vulkan_sync.to_sync(|| ri.wait_idle()); - let pending = Pending { - ri: ri.clone(), - sync: sync.clone(), - semaphore, - vulkan_sync, - _cmd: cmd, - _uploads: used_uploads, - _sampled: sampled_images, - _fb: self.image.clone(), - index_buffer: Some(index_buffer), - vertex_buffer: Some(vertex_buffer), - }; - ri.submissions.pending.push(pending); - Ok(sync) - } -} - -impl EgvBuffer { - fn upload(&self, data: &[u8]) -> Result<(), EgvError> { - assert!(self.mapping.len() >= data.len()); - unsafe { - ptr::copy_nonoverlapping(data.as_ptr(), self.mapping.cast(), data.len()); - } - if !self.host_coherent { - let m = &self.memory; - let mask = m.ri.non_coherent_atom_size - 1; - let lo = m.block.offset() & !mask; - let hi = (m.block.offset() + data.len() as u64 + mask) & !mask; - let range = MappedMemoryRange::default() - .memory(*m.block.memory()) - .offset(lo) - .size(hi - lo); - unsafe { - m.ri.device - .flush_mapped_memory_ranges(slice::from_ref(&range)) - .map_err(EgvError::FlushMemory)?; - } - } - Ok(()) - } -} - -impl EgvSemaphore { - fn import(&self, sync_file: &SyncFile) -> Result<(), EgvError> { - let fd = uapi::fcntl_dupfd_cloexec(sync_file.raw(), 0).map_os_err(EgvError::DupSyncFile)?; - let info = ImportSemaphoreFdInfoKHR::default() - .flags(SemaphoreImportFlags::TEMPORARY) - .semaphore(self.semaphore) - .handle_type(ExternalSemaphoreHandleTypeFlags::SYNC_FD) - .fd(fd.raw()); - unsafe { - self.ri - .external_semaphore_fd - .import_semaphore_fd(&info) - .map_err(EgvError::ImportSyncFile)?; - } - let _ = fd.unwrap(); - Ok(()) - } -} - -impl Drop for EgvBuffer { - fn drop(&mut self) { - unsafe { - self.ri.device.destroy_buffer(self.buffer, None); - } - } -} - -impl Drop for EgvRendererInner { - fn drop(&mut self) { - let dev = &self.device; - unsafe { - self.allocator - .borrow_mut() - .cleanup(AshMemoryDevice::wrap(dev)); - dev.destroy_pipeline(self.pipeline, None); - dev.destroy_command_pool(self.pool, None); - dev.destroy_pipeline_layout(self.pipeline_layout, None); - dev.destroy_descriptor_set_layout(self.descriptor_set_layout, None); - dev.destroy_shader_module(self.vert, None); - dev.destroy_shader_module(self.frag, None); - dev.destroy_device(None); - } - } -} - -impl Drop for EgvImportedMemory { - fn drop(&mut self) { - unsafe { - for &memory in &self.memories { - self.ri.device.free_memory(memory, None); - } - } - } -} - -impl Drop for EgvAllocatedMemory { - fn drop(&mut self) { - if self.mapping.is_some() { - unsafe { - self.block.unmap(AshMemoryDevice::wrap(&self.ri.device)); - } - } - unsafe { - self.ri.allocator.borrow_mut().dealloc( - AshMemoryDevice::wrap(&self.ri.device), - ManuallyDrop::take(&mut self.block), - ); - } - } -} - -impl Drop for EgvCommandBuffer { - fn drop(&mut self) { - let ri = &self.ri; - unsafe { - ri.device - .free_command_buffers(ri.pool, slice::from_ref(&self.buf)); - } - } -} - -impl Drop for VkSampler { - fn drop(&mut self) { - unsafe { - self.ri.device.destroy_sampler(self.sampler, None); - } - } -} - -impl Drop for EgvImage { - fn drop(&mut self) { - let dev = &self.ri.device; - unsafe { - dev.destroy_image_view(self.image_view, None); - dev.destroy_image(self.image, None); - } - } -} - -impl Drop for Pending { - fn drop(&mut self) { - let cache = &mut *self.ri.cache.borrow_mut(); - if let Some(v) = self.semaphore.take() { - cache.semaphores.push(v); - } - if let Some(v) = self.index_buffer.take() { - cache.device_local_buffers.push(v); - } - if let Some(v) = self.vertex_buffer.take() { - cache.device_local_buffers.push(v); - } - } -} - -impl Drop for EgvSemaphore { - fn drop(&mut self) { - let dev = &self.ri.device; - unsafe { - dev.destroy_semaphore(self.semaphore, None); - } - } -} - -impl Drop for EgvRenderer { - fn drop(&mut self) { - let ri = &self.ri; - if ri.submissions.pending.is_not_empty() || ri.submissions.task_has_pending.get() { - ri.wait_idle(); - } - ri.cache.take(); - } -} - -impl Drop for EgvContext { - fn drop(&mut self) { - self.renderer - .ri - .cache - .borrow_mut() - .images - .retain(|&(id, _), _| id != self.id); - } -} - -impl VulkanDeviceInf for EgvRendererInner { - fn instance(&self) -> &VulkanCoreInstance { - &self.instance - } - - fn device(&self) -> &Device { - &self.device - } - - fn external_fence_fd(&self) -> &external_fence_fd::Device { - &self.external_fence_fd - } - - fn external_semaphore_fd(&self) -> &external_semaphore_fd::Device { - &self.external_semaphore_fd - } - - fn supports_timeline_opaque_export(&self) -> bool { - self.supports_timeline_opaque_export - } - - fn sync_ctx(&self) -> Option<&Rc> { - self.sync_ctx.as_ref() - } - - fn eventfd_cache(&self) -> &Rc { - &self.eventfd_cache - } -} diff --git a/src/egui_adapter/icons.ttf b/src/egui_adapter/icons.ttf deleted file mode 100644 index 0abd161b..00000000 Binary files a/src/egui_adapter/icons.ttf and /dev/null differ diff --git a/src/egui_adapter/shaders/shader.frag b/src/egui_adapter/shaders/shader.frag deleted file mode 100644 index 56defac2..00000000 --- a/src/egui_adapter/shaders/shader.frag +++ /dev/null @@ -1,13 +0,0 @@ -#version 450 - -layout(location = 0) in vec4 color; -layout(location = 1) in vec2 pos; - -layout(binding = 0, set = 0) uniform sampler2D tex; - -layout(location = 0) out vec4 res; - -void main() { - vec4 src = texture(tex, pos); - res = color * src; -} diff --git a/src/egui_adapter/shaders/shader.vert b/src/egui_adapter/shaders/shader.vert deleted file mode 100644 index 73584e1a..00000000 --- a/src/egui_adapter/shaders/shader.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 if_pos; -layout(location = 1) in vec2 it_pos; -layout(location = 2) in vec4 i_color; - -layout(location = 0) out vec4 o_color; -layout(location = 1) out vec2 ot_pos; - -void main() { - o_color = i_color; - o_color.rgb = mix( - o_color.rgb / vec3(12.92), - pow((o_color.rgb + vec3(0.055)) / vec3(1.055), vec3(2.4)), - greaterThan(o_color.rgb, vec3(0.04045)) - ); - ot_pos = it_pos; - gl_Position = vec4(if_pos.x, if_pos.y, 0.0, 1.0); -} diff --git a/src/egui_adapter/shaders_bin/shader.frag.spv b/src/egui_adapter/shaders_bin/shader.frag.spv deleted file mode 100644 index 28f8c6f5..00000000 Binary files a/src/egui_adapter/shaders_bin/shader.frag.spv and /dev/null differ diff --git a/src/egui_adapter/shaders_bin/shader.vert.spv b/src/egui_adapter/shaders_bin/shader.vert.spv deleted file mode 100644 index 20e61987..00000000 Binary files a/src/egui_adapter/shaders_bin/shader.vert.spv and /dev/null differ diff --git a/src/egui_adapter/shaders_hash.txt b/src/egui_adapter/shaders_hash.txt deleted file mode 100644 index fab5b02f..00000000 --- a/src/egui_adapter/shaders_hash.txt +++ /dev/null @@ -1,2 +0,0 @@ -7eb8fae39ae513bc4f6973c12227aa4aa43734bdf34c90e1b3b69294ad98db87 src/egui_adapter/shaders/shader.frag -501f4d0c5c5f10a371659b89f12d87abb03e5b57a31dbae5f3c6ca5726e4db01 src/egui_adapter/shaders/shader.vert diff --git a/src/fontconfig.rs b/src/fontconfig.rs deleted file mode 100644 index 76275bee..00000000 --- a/src/fontconfig.rs +++ /dev/null @@ -1,136 +0,0 @@ -use { - crate::fontconfig::consts::{FC_MATCH_PATTERN, FC_RESULT_MATCH}, - run_on_drop::on_drop, - std::{ - borrow::Cow, - ffi::{CStr, OsStr, c_char}, - os::{ - raw::{c_int, c_uchar}, - unix::ffi::OsStrExt, - }, - path::PathBuf, - ptr, - }, - thiserror::Error, - uapi::IntoUstr, -}; - -mod consts; - -include!(concat!(env!("OUT_DIR"), "/fontconfig_tys.rs")); - -#[derive(Debug, Error)] -pub enum FontconfigError { - #[error("FcConfigGetCurrent returned NULL")] - Init, - #[error("Could not create a pattern")] - CreatePattern, - #[error("Could not find a match")] - NoMatch, - #[error("Match has no name")] - NoName, - #[error("Match has no file")] - NoFile, -} - -#[derive(Debug)] -pub struct Font { - pub fullname: String, - pub file: PathBuf, - pub index: Option, -} - -pub fn match_font(family: &str) -> Result { - thread_local! { - static CONFIG: *mut FcConfig = FcConfigGetCurrent(); - } - let config = CONFIG.with(|c| *c); - if config.is_null() { - return Err(FontconfigError::Init); - } - let family = family.into_ustr(); - let p = FcPatternCreate(); - if p.is_null() { - return Err(FontconfigError::CreatePattern); - } - let _destroy_pattern = on_drop(|| unsafe { FcPatternDestroy(p) }); - let mut result = 0; - let p = unsafe { - FcPatternAddString(p, FC_FAMILY.as_ptr(), family.as_ptr() as _); - FcConfigSubstitute(config, p, FC_MATCH_PATTERN.0 as _); - FcDefaultSubstitute(p); - FcFontMatch(config, p, &mut result) - }; - if p.is_null() { - return Err(FontconfigError::NoMatch); - } - let _destroy_pattern = on_drop(|| unsafe { FcPatternDestroy(p) }); - if result != FC_RESULT_MATCH.0 as FcResult { - return Err(FontconfigError::NoMatch); - } - let get_cstr = |name: &CStr| { - let mut out = ptr::null_mut(); - let res = unsafe { FcPatternGetString(p, name.as_ptr(), 0, &mut out) }; - if res != FC_RESULT_MATCH.0 as FcResult || out.is_null() { - return None; - } - let cstr = unsafe { CStr::from_ptr(out.cast()) }; - Some(cstr) - }; - let get_int = |name: &CStr| { - let mut out = 0; - let res = unsafe { FcPatternGetInteger(p, name.as_ptr(), 0, &mut out) }; - if res != FC_RESULT_MATCH.0 as FcResult { - return None; - } - Some(out as i32) - }; - Ok(Font { - fullname: get_cstr(FC_FULLNAME) - .map(CStr::to_string_lossy) - .map(Cow::into_owned) - .ok_or(FontconfigError::NoName)?, - file: get_cstr(FC_FILE) - .map(CStr::to_bytes) - .map(OsStr::from_bytes) - .map(Into::into) - .ok_or(FontconfigError::NoFile)?, - index: get_int(FC_INDEX), - }) -} - -type FcBool = c_int; -type FcPattern = u8; -type FcConfig = u8; -type FcChar8 = c_uchar; -const FC_FAMILY: &CStr = c"family"; -const FC_FULLNAME: &CStr = c"fullname"; -const FC_FILE: &CStr = c"file"; -const FC_INDEX: &CStr = c"index"; - -#[link(name = "fontconfig")] -unsafe extern "C" { - safe fn FcConfigGetCurrent() -> *mut FcConfig; - safe fn FcPatternCreate() -> *mut FcPattern; - fn FcPatternDestroy(p: *mut FcPattern); - fn FcPatternAddString(p: *mut FcPattern, object: *const c_char, s: *const FcChar8) -> FcBool; - fn FcConfigSubstitute(config: *mut FcConfig, p: *mut FcPattern, kind: FcMatchKind) -> FcBool; - fn FcDefaultSubstitute(p: *mut FcPattern); - fn FcFontMatch( - config: *mut FcConfig, - p: *mut FcPattern, - result: *mut FcResult, - ) -> *mut FcPattern; - fn FcPatternGetString( - p: *mut FcPattern, - object: *const c_char, - id: c_int, - s: *mut *mut FcChar8, - ) -> FcResult; - fn FcPatternGetInteger( - p: *mut FcPattern, - object: *const c_char, - id: c_int, - i: *mut c_int, - ) -> FcResult; -} diff --git a/src/ifs.rs b/src/ifs.rs index 8c94796f..93ac167b 100644 --- a/src/ifs.rs +++ b/src/ifs.rs @@ -21,7 +21,6 @@ pub mod jay_ei_session_builder; pub mod jay_idle; pub mod jay_input; pub mod jay_log_file; -pub mod jay_open_control_center_request; pub mod jay_output; pub mod jay_pointer; pub mod jay_popup_ext_manager_v1; diff --git a/src/ifs/head_management.rs b/src/ifs/head_management.rs index f10ace52..5df25618 100644 --- a/src/ifs/head_management.rs +++ b/src/ifs/head_management.rs @@ -21,7 +21,7 @@ use { wire::JayHeadManagerSessionV1Id, }, std::{ - cell::{Cell, Ref, RefCell}, + cell::{Cell, RefCell}, collections::hash_map::Entry, rc::Rc, }, @@ -103,16 +103,6 @@ pub struct HeadState { pub persistent_state: Option>, } -pub struct ReadOnlyHeadState { - state: Rc>, -} - -impl ReadOnlyHeadState { - pub fn borrow(&self) -> Ref<'_, HeadState> { - self.state.borrow() - } -} - impl HeadState { pub fn update_in_compositor_space(&mut self, state: &State, wl_output: Option) { self.in_compositor_space = false; @@ -269,12 +259,6 @@ impl HeadManagers { } } - pub fn state(&self) -> ReadOnlyHeadState { - ReadOnlyHeadState { - state: self.state.clone(), - } - } - pub fn handle_removed(&self) { for head in self.managers.lock().drain_values() { skip_in_transaction!(head); diff --git a/src/ifs/jay_compositor.rs b/src/ifs/jay_compositor.rs index 90c4f3ae..7441206c 100644 --- a/src/ifs/jay_compositor.rs +++ b/src/ifs/jay_compositor.rs @@ -11,7 +11,6 @@ use { jay_idle::JayIdle, jay_input::JayInput, jay_log_file::JayLogFile, - jay_open_control_center_request::JayOpenControlCenterRequest, jay_output::JayOutput, jay_pointer::JayPointer, jay_randr::JayRandr, @@ -544,24 +543,6 @@ impl JayCompositorRequestHandler for JayCompositor { Ok(()) } - fn open_control_center( - &self, - req: OpenControlCenter, - _slf: &Rc, - ) -> Result<(), Self::Error> { - let obj = Rc::new(JayOpenControlCenterRequest { - id: req.id, - client: self.client.clone(), - tracker: Default::default(), - version: self.version, - }); - track!(self.client, obj); - self.client.add_client_obj(&obj)?; - if let Err(e) = self.client.state.open_control_center() { - obj.send_failed(e); - } - Ok(()) - } } object_base! { diff --git a/src/ifs/jay_open_control_center_request.rs b/src/ifs/jay_open_control_center_request.rs deleted file mode 100644 index a5c0ef5d..00000000 --- a/src/ifs/jay_open_control_center_request.rs +++ /dev/null @@ -1,53 +0,0 @@ -use { - crate::{ - client::{Client, ClientError}, - leaks::Tracker, - object::{Object, Version}, - utils::errorfmt::ErrorFmt, - wire::{JayOpenControlCenterRequestId, jay_open_control_center_request::*}, - }, - std::{error::Error, rc::Rc}, - thiserror::Error, -}; - -pub struct JayOpenControlCenterRequest { - pub id: JayOpenControlCenterRequestId, - pub client: Rc, - pub tracker: Tracker, - pub version: Version, -} - -impl JayOpenControlCenterRequest { - pub fn send_failed(&self, err: impl Error) { - let msg = &ErrorFmt(err).to_string(); - self.client.event(Failed { - self_id: self.id, - msg, - }); - } -} - -impl JayOpenControlCenterRequestRequestHandler for JayOpenControlCenterRequest { - type Error = JayOpenControlCenterRequestError; - - fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { - self.client.remove_obj(self)?; - Ok(()) - } -} - -object_base! { - self = JayOpenControlCenterRequest; - version = self.version; -} - -impl Object for JayOpenControlCenterRequest {} - -simple_add_obj!(JayOpenControlCenterRequest); - -#[derive(Debug, Error)] -pub enum JayOpenControlCenterRequestError { - #[error(transparent)] - ClientError(Box), -} -efrom!(JayOpenControlCenterRequestError, ClientError); diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 818ad37a..99ede1c5 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -28,7 +28,6 @@ use { ButtonState, InputDeviceAccelProfile, InputDeviceClickMethod, Leds, TransformMatrix, }, client::{Client, ClientError, ClientId}, - control_center::CCI_INPUT, cursor_user::{CursorUser, CursorUserGroup, CursorUserOwner}, ei::ei_ifs::ei_seat::EiSeat, fixed::Fixed, @@ -141,9 +140,6 @@ const MISSING_CAPABILITY: u32 = 0; pub const BTN_LEFT: u32 = 0x110; pub const BTN_RIGHT: u32 = 0x111; -pub const BTN_MIDDLE: u32 = 0x112; -pub const BTN_SIDE: u32 = 0x113; -pub const BTN_EXTRA: u32 = 0x114; pub const SEAT_NAME_SINCE: Version = Version(2); @@ -788,7 +784,6 @@ impl WlSeatGlobal { if let Some(grab) = self.input_method_grab.get() { grab.on_repeat_info(); } - self.state.trigger_cci(CCI_INPUT); } pub fn close(self: &Rc) { @@ -1034,20 +1029,10 @@ impl WlSeatGlobal { pub fn focus_history_set_visible(&self, visible: bool) { self.focus_history_visible_only.set(visible); - self.state.trigger_cci(CCI_INPUT); - } - - pub fn focus_history_visible(&self) -> bool { - self.focus_history_visible_only.get() } pub fn focus_history_set_same_workspace(&self, same_workspace: bool) { self.focus_history_same_workspace.set(same_workspace); - self.state.trigger_cci(CCI_INPUT); - } - - pub fn focus_history_same_workspace(&self) -> bool { - self.focus_history_same_workspace.get() } fn focus_layer_rel( @@ -1585,16 +1570,10 @@ impl WlSeatGlobal { pub fn set_focus_follows_mouse(&self, focus_follows_mouse: bool) { self.focus_follows_mouse.set(focus_follows_mouse); - self.state.trigger_cci(CCI_INPUT); - } - - pub fn focus_follows_mouse(&self) -> bool { - self.focus_follows_mouse.get() } pub fn set_mouse_follows_focus(&self, enabled: bool) { self.mouse_follows_focus.set(enabled); - self.state.trigger_cci(CCI_INPUT); } pub fn mouse_follows_focus(&self) -> bool { @@ -1603,11 +1582,6 @@ impl WlSeatGlobal { pub fn set_fallback_output_mode(&self, fallback_output_mode: FallbackOutputMode) { self.fallback_output_mode.set(fallback_output_mode); - self.state.trigger_cci(CCI_INPUT); - } - - pub fn fallback_output_mode(&self) -> FallbackOutputMode { - self.fallback_output_mode.get() } pub fn set_window_management_enabled(self: &Rc, enabled: bool) { @@ -1725,12 +1699,8 @@ impl WlSeatGlobal { pub fn set_pointer_revert_key(&self, key: KeySym) { self.revert_key.set(key); - self.state.trigger_cci(CCI_INPUT); } - pub fn pointer_revert_key(&self) -> KeySym { - self.revert_key.get() - } } impl CursorUserOwner for WlSeatGlobal { @@ -1924,7 +1894,7 @@ pub fn collect_kb_foci(node: Rc) -> SmallVec<[Rc; 3]> { } impl DeviceHandlerData { - pub fn set_seat(&self, state: &State, seat: Option>) { + pub fn set_seat(&self, _state: &State, seat: Option>) { if let Some(new) = &seat { if let Some(old) = self.seat.get() && old.id() == new.id() @@ -1963,7 +1933,6 @@ impl DeviceHandlerData { } } self.attach_event_listeners(); - state.trigger_cci(CCI_INPUT); } fn destroy_physical_keyboard_state(&self) { @@ -1985,14 +1954,13 @@ impl DeviceHandlerData { }; } - pub fn set_keymap(&self, state: &State, keymap: Option>) { + pub fn set_keymap(&self, _state: &State, keymap: Option>) { self.destroy_physical_keyboard_state(); self.keymap.set(keymap); self.attach_event_listeners(); - state.trigger_cci(CCI_INPUT); } - pub fn set_output(&self, state: &State, output: Option<&WlOutputGlobal>) { + pub fn set_output(&self, _state: &State, output: Option<&WlOutputGlobal>) { match output { None => { log::info!("Removing output mapping of {}", self.device.name()); @@ -2003,7 +1971,6 @@ impl DeviceHandlerData { self.output.set(Some(o.opt.clone())); } } - state.trigger_cci(CCI_INPUT); } pub fn get_rect(&self, state: &State) -> Rect { @@ -2015,64 +1982,52 @@ impl DeviceHandlerData { state.root.extents.get() } - pub fn set_accel_profile(&self, state: &State, v: InputDeviceAccelProfile) { + pub fn set_accel_profile(&self, _state: &State, v: InputDeviceAccelProfile) { self.device.set_accel_profile(v); - state.trigger_cci(CCI_INPUT); } - pub fn set_accel_speed(&self, state: &State, v: f64) { + pub fn set_accel_speed(&self, _state: &State, v: f64) { self.device.set_accel_speed(v); - state.trigger_cci(CCI_INPUT); } - pub fn set_tap_enabled(&self, state: &State, v: bool) { + pub fn set_tap_enabled(&self, _state: &State, v: bool) { self.device.set_tap_enabled(v); - state.trigger_cci(CCI_INPUT); } - pub fn set_drag_enabled(&self, state: &State, v: bool) { + pub fn set_drag_enabled(&self, _state: &State, v: bool) { self.device.set_drag_enabled(v); - state.trigger_cci(CCI_INPUT); } - pub fn set_drag_lock_enabled(&self, state: &State, v: bool) { + pub fn set_drag_lock_enabled(&self, _state: &State, v: bool) { self.device.set_drag_lock_enabled(v); - state.trigger_cci(CCI_INPUT); } - pub fn set_left_handed(&self, state: &State, v: bool) { + pub fn set_left_handed(&self, _state: &State, v: bool) { self.device.set_left_handed(v); - state.trigger_cci(CCI_INPUT); } - pub fn set_natural_scrolling_enabled(&self, state: &State, v: bool) { + pub fn set_natural_scrolling_enabled(&self, _state: &State, v: bool) { self.device.set_natural_scrolling_enabled(v); - state.trigger_cci(CCI_INPUT); } - pub fn set_px_per_scroll_wheel(&self, state: &State, v: f64) { + pub fn set_px_per_scroll_wheel(&self, _state: &State, v: f64) { self.px_per_scroll_wheel.set(v); - state.trigger_cci(CCI_INPUT); } - pub fn set_transform_matrix(&self, state: &State, v: TransformMatrix) { + pub fn set_transform_matrix(&self, _state: &State, v: TransformMatrix) { self.device.set_transform_matrix(v); - state.trigger_cci(CCI_INPUT); } - pub fn set_calibration_matrix(&self, state: &State, v: [[f32; 3]; 2]) { + pub fn set_calibration_matrix(&self, _state: &State, v: [[f32; 3]; 2]) { self.device.set_calibration_matrix(v); - state.trigger_cci(CCI_INPUT); } - pub fn set_click_method(&self, state: &State, v: InputDeviceClickMethod) { + pub fn set_click_method(&self, _state: &State, v: InputDeviceClickMethod) { self.device.set_click_method(v); - state.trigger_cci(CCI_INPUT); } - pub fn set_middle_button_emulation_enabled(&self, state: &State, v: bool) { + pub fn set_middle_button_emulation_enabled(&self, _state: &State, v: bool) { self.device.set_middle_button_emulation_enabled(v); - state.trigger_cci(CCI_INPUT); } } diff --git a/src/ifs/wl_seat/text_input.rs b/src/ifs/wl_seat/text_input.rs index 77d2d09e..51cea1d3 100644 --- a/src/ifs/wl_seat/text_input.rs +++ b/src/ifs/wl_seat/text_input.rs @@ -1,7 +1,6 @@ use { crate::{ backend::KeyState, - control_center::CCI_INPUT, ifs::{ wl_seat::{ WlSeatGlobal, @@ -90,7 +89,6 @@ impl WlSeatGlobal { im.cancel_simple(self); } } - self.state.trigger_cci(CCI_INPUT); } pub fn simple_im_enabled(&self) -> bool { diff --git a/src/ifs/wp_cursor_shape_device_v1.rs b/src/ifs/wp_cursor_shape_device_v1.rs index b4fdec17..7cd56264 100644 --- a/src/ifs/wp_cursor_shape_device_v1.rs +++ b/src/ifs/wp_cursor_shape_device_v1.rs @@ -140,46 +140,6 @@ impl KnownCursor { Some(cursor) } - pub fn to_shape(self) -> u32 { - match self { - KnownCursor::Default => DEFAULT, - KnownCursor::ContextMenu => CONTEXT_MENU, - KnownCursor::Help => HELP, - KnownCursor::Pointer => POINTER, - KnownCursor::Progress => PROGRESS, - KnownCursor::Wait => WAIT, - KnownCursor::Cell => CELL, - KnownCursor::Crosshair => CROSSHAIR, - KnownCursor::Text => TEXT, - KnownCursor::VerticalText => VERTICAL_TEXT, - KnownCursor::Alias => ALIAS, - KnownCursor::Copy => COPY, - KnownCursor::Move => MOVE, - KnownCursor::NoDrop => NO_DROP, - KnownCursor::NotAllowed => NOT_ALLOWED, - KnownCursor::Grab => GRAB, - KnownCursor::Grabbing => GRABBING, - KnownCursor::EResize => E_RESIZE, - KnownCursor::NResize => N_RESIZE, - KnownCursor::NeResize => NE_RESIZE, - KnownCursor::NwResize => NW_RESIZE, - KnownCursor::SResize => S_RESIZE, - KnownCursor::SeResize => SE_RESIZE, - KnownCursor::SwResize => SW_RESIZE, - KnownCursor::WResize => W_RESIZE, - KnownCursor::EwResize => EW_RESIZE, - KnownCursor::NsResize => NS_RESIZE, - KnownCursor::NeswResize => NESW_RESIZE, - KnownCursor::NwseResize => NWSE_RESIZE, - KnownCursor::ColResize => COL_RESIZE, - KnownCursor::RowResize => ROW_RESIZE, - KnownCursor::AllScroll => ALL_SCROLL, - KnownCursor::ZoomIn => ZOOM_IN, - KnownCursor::ZoomOut => ZOOM_OUT, - KnownCursor::DndAsk => DND_ASK, - KnownCursor::AllResize => ALL_RESIZE, - } - } } object_base! { diff --git a/src/kbvm.rs b/src/kbvm.rs index 37de9db4..5d8b2921 100644 --- a/src/kbvm.rs +++ b/src/kbvm.rs @@ -56,7 +56,6 @@ pub struct KbvmMap { pub id: KbvmMapId, pub state_machine: StateMachine, pub lookup_table: LookupTable, - pub map_text: String, pub map: KeymapFd, pub xwayland_map: KeymapFd, pub has_indicators: bool, @@ -161,12 +160,11 @@ impl KbvmContext { } let builder = map.to_builder(); let (_, xwayland_map) = create_keymap_memfd(&map, true).map_err(KbvmError::KeymapMemfd)?; - let (map_text, map) = create_keymap_memfd(&map, false).map_err(KbvmError::KeymapMemfd)?; + let (_, map) = create_keymap_memfd(&map, false).map_err(KbvmError::KeymapMemfd)?; Ok(Rc::new(KbvmMap { id, state_machine: builder.build_state_machine(), map, - map_text, xwayland_map, lookup_table: builder.build_lookup_table(), has_indicators, diff --git a/src/logger.rs b/src/logger.rs index 17fc9119..f5e2266d 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -96,10 +96,6 @@ impl Logger { }); } - pub fn level(&self) -> LogLevel { - self.level.load(Relaxed) - } - pub fn path(&self) -> Arc { self.path.lock().clone() } diff --git a/src/main.rs b/src/main.rs index ed4c92ff..5a566f9b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,7 +58,6 @@ mod clientmem; mod cmm; mod compositor; mod config; -mod control_center; mod copy_device; mod cpu_worker; mod criteria; @@ -68,11 +67,9 @@ mod damage; mod dbus; mod drm_feedback; mod edid; -mod egui_adapter; mod ei; mod eventfd_cache; mod fixed; -mod fontconfig; mod forker; mod format; mod gfx_api; diff --git a/src/output_schedule.rs b/src/output_schedule.rs index dec598e8..098c1e91 100644 --- a/src/output_schedule.rs +++ b/src/output_schedule.rs @@ -2,7 +2,6 @@ use { crate::{ async_engine::AsyncEngine, backend::HardwareCursor, - control_center::CCI_OUTPUTS, ifs::wl_output::PersistentOutputState, io_uring::{IoUring, IoUringError}, state::{ConnectorData, State}, @@ -118,7 +117,7 @@ impl OutputSchedule { self.trigger(); } - pub fn set_cursor_hz(&self, state: &State, hz: f64) { + pub fn set_cursor_hz(&self, _state: &State, hz: f64) { let (hz, delta) = match map_cursor_hz(hz) { None => { log::warn!("Ignoring cursor frequency {hz}"); @@ -128,7 +127,6 @@ impl OutputSchedule { }; self.persistent.vrr_cursor_hz.set(hz); self.connector.head_managers.handle_cursor_hz_change(hz); - state.trigger_cci(CCI_OUTPUTS); self.cursor_delta_nsec.set(delta); self.trigger(); } diff --git a/src/security_context_acceptor.rs b/src/security_context_acceptor.rs index bf164643..0a5f9bb0 100644 --- a/src/security_context_acceptor.rs +++ b/src/security_context_acceptor.rs @@ -42,15 +42,6 @@ pub struct AcceptorMetadata { pub tag: Option, } -impl AcceptorMetadata { - pub fn secure() -> Self { - Self { - secure: true, - ..Default::default() - } - } -} - impl SecurityContextAcceptors { pub fn clear(&self) { for acceptor in self.acceptors.lock().drain_values() { diff --git a/src/state.rs b/src/state.rs index 30f2c5ad..a328353a 100644 --- a/src/state.rs +++ b/src/state.rs @@ -19,10 +19,6 @@ use { }, compositor::{LIBEI_SOCKET, LogLevel}, config::ConfigProxy, - control_center::{ - CCI_COLOR_MANAGEMENT, CCI_COMPOSITOR, CCI_GPUS, CCI_IDLE, CCI_LOOK_AND_FEEL, - CCI_OUTPUTS, CCI_XWAYLAND, ControlCenters, - }, copy_device::CopyDeviceRegistry, cpu_worker::CpuWorker, criteria::{clm::ClMatcherManager, tlm::TlMatcherManager}, @@ -31,7 +27,6 @@ use { damage::DamageVisualizer, dbus::Dbus, drm_feedback::{DrmFeedback, DrmFeedbackIds}, - egui_adapter::egui_platform::EggState, ei::{ ei_acceptor::EiAcceptor, ei_client::{EiClient, EiClients}, @@ -304,8 +299,6 @@ pub struct State { pub eventfd_cache: Rc, pub lazy_event_sources: Rc, pub bo_drop_queue: Rc>>, - pub egg_state: EggState, - pub control_centers: ControlCenters, pub virtual_outputs: VirtualOutputs, pub clean_logs_older_than: Cell>, } @@ -366,10 +359,9 @@ impl IdleState { self.timeout_changed(state); } - fn timeout_changed(&self, state: &State) { + fn timeout_changed(&self, _state: &State) { self.timeout_changed.set(true); self.change.trigger(); - state.trigger_cci(CCI_IDLE); } pub fn add_inhibitor(&self, state: &State, inhibitor: &Rc) { @@ -385,10 +377,9 @@ impl IdleState { } } - fn inhibitors_changed(&self, state: &State) { + fn inhibitors_changed(&self, _state: &State) { self.inhibitors_changed.set(true); self.change.trigger(); - state.trigger_cci(CCI_IDLE); } fn resume_inhibited_notifications(&self) { @@ -500,39 +491,30 @@ impl ConnectorData { return; } *self.state.borrow_mut() = s.clone(); - macro_rules! b { - ($expr:expr) => {{ - let e = $expr; - if e { - state.trigger_cci(CCI_OUTPUTS); - } - e - }}; - } - if b!(old.enabled != s.enabled) { + if old.enabled != s.enabled { self.head_managers.handle_enabled_change(state, s.enabled); } - if b!(old.active != s.active) { + if old.active != s.active { self.head_managers.handle_active_change(s.active); } - if b!(old.non_desktop_override != s.non_desktop_override) { + if old.non_desktop_override != s.non_desktop_override { self.head_managers .handle_non_desktop_override_changed(s.non_desktop_override); } - if b!(old.vrr != s.vrr) { + if old.vrr != s.vrr { self.head_managers.handle_vrr_change(s.vrr); } - if b!(old.tearing != s.tearing) { + if old.tearing != s.tearing { self.head_managers.handle_tearing_enabled_change(s.tearing); } - if b!(old.format != s.format) { + if old.format != s.format { self.head_managers.handle_format_change(s.format); } - if b!((old.color_space, old.eotf) != (s.color_space, s.eotf)) { + if (old.color_space, old.eotf) != (s.color_space, s.eotf) { self.head_managers .handle_colors_change(s.color_space, s.eotf); } - if b!(old.mode != s.mode) { + if old.mode != s.mode { self.head_managers.handle_mode_change(s.mode); for head in self.wlr_output_heads.lock().values() { head.handle_mode_change(s.mode); @@ -555,14 +537,12 @@ impl DrmDevData { self.dev.clone().make_render_device(); } - pub fn set_direct_scanout_enabled(&self, state: &State, enabled: bool) { + pub fn set_direct_scanout_enabled(&self, _state: &State, enabled: bool) { self.dev.set_direct_scanout_enabled(enabled); - state.trigger_cci(CCI_GPUS); } - pub fn set_flip_margin(&self, state: &State, margin: u64) { + pub fn set_flip_margin(&self, _state: &State, margin: u64) { self.dev.set_flip_margin(margin); - state.trigger_cci(CCI_GPUS); } } @@ -671,7 +651,6 @@ impl State { } pub fn set_render_ctx(&self, ctx: Option>) { - self.egg_state.clear(); self.explicit_sync_supported.set(false); self.render_ctx.set(ctx.clone()); self.render_ctx_version.fetch_add(1); @@ -787,7 +766,6 @@ impl State { } self.expose_new_singletons(); - self.trigger_cci(CCI_COLOR_MANAGEMENT | CCI_GPUS); } fn reload_cursors(&self) { @@ -1033,7 +1011,6 @@ impl State { } else { self.stop_xwayland(); } - self.trigger_cci(CCI_XWAYLAND); } pub fn set_xwayland_use_wire_scale(&self, use_wire_scale: bool) { @@ -1041,7 +1018,6 @@ impl State { return; } self.update_xwayland_wire_scale(); - self.trigger_cci(CCI_XWAYLAND); } pub fn next_serial(&self, client: Option<&Client>) -> u64 { @@ -1191,8 +1167,6 @@ impl State { self.xdg_surface_configure_events.clear(); self.lazy_event_sources.clear(); self.bo_drop_queue.kill(); - self.egg_state.clear(); - self.control_centers.clear(); self.virtual_outputs.clear(); } @@ -1744,13 +1718,11 @@ impl State { pub fn set_color_management_enabled(&self, enabled: bool) { self.color_management_enabled.set(enabled); self.expose_new_singletons(); - self.trigger_cci(CCI_COLOR_MANAGEMENT); } pub fn set_primary_selection_enabled(&self, enabled: bool) { self.enable_primary_selection.set(enabled); self.expose_new_singletons(); - self.trigger_cci(CCI_LOOK_AND_FEEL); } pub fn set_explicit_sync_enabled(&self, enabled: bool) { @@ -1761,7 +1733,6 @@ impl State { pub fn set_log_level(&self, level: LogLevel) { if let Some(logger) = &self.logger { logger.set_level(level); - self.trigger_cci(CCI_COMPOSITOR); } } @@ -1794,7 +1765,6 @@ impl State { self.root.clone().node_visit(&mut V); self.damage(self.root.extents.get()); self.icons.clear(); - self.trigger_cci(CCI_LOOK_AND_FEEL); } pub fn reset_colors(&self) { @@ -1829,7 +1799,6 @@ impl State { pub fn set_ei_socket_enabled(self: &Rc, enabled: bool) { self.enable_ei_acceptor.set(enabled); self.update_ei_acceptor(); - self.trigger_cci(CCI_COMPOSITOR); } pub fn set_workspace_display_order(&self, order: WorkspaceDisplayOrder) { @@ -1837,7 +1806,6 @@ impl State { for output in self.root.outputs.lock().values() { output.handle_workspace_display_order_update(); } - self.trigger_cci(CCI_COMPOSITOR); } fn spaces_changed(&self) { @@ -1859,7 +1827,6 @@ impl State { self.root.clone().node_visit(&mut V); self.damage(self.root.extents.get()); self.icons.update_sizes(self); - self.trigger_cci(CCI_LOOK_AND_FEEL); } pub fn set_show_bar(&self, show: bool) { @@ -1874,18 +1841,15 @@ impl State { pub fn set_ui_drag_enabled(&self, enabled: bool) { self.ui_drag_enabled.set(enabled); - self.trigger_cci(CCI_LOOK_AND_FEEL); } pub fn set_ui_drag_threshold(&self, threshold: i32) { self.ui_drag_threshold_squared .set(threshold.saturating_mul(threshold)); - self.trigger_cci(CCI_LOOK_AND_FEEL); } pub fn set_show_pin_icon(&self, show: bool) { self.show_pin_icon.set(show); - self.trigger_cci(CCI_LOOK_AND_FEEL); for stacked in self.root.stacked.iter() { if let Some(float) = stacked.deref().clone().node_into_float() { float.schedule_render_titles(); @@ -1895,7 +1859,6 @@ impl State { pub fn set_float_above_fullscreen(&self, v: bool) { self.float_above_fullscreen.set(v); - self.trigger_cci(CCI_LOOK_AND_FEEL); for seat in self.globals.seats.lock().values() { seat.emulate_cursor_moved(); seat.trigger_tree_changed(false); @@ -1909,7 +1872,6 @@ impl State { } fn fonts_changed(&self) { - self.trigger_cci(CCI_LOOK_AND_FEEL); struct V; impl NodeVisitorBase for V { fn visit_container(&mut self, node: &Rc) { @@ -1933,7 +1895,6 @@ impl State { theme.font.set(self.theme.default_font.clone()); theme.bar_font.set(None); theme.title_font.set(None); - self.egg_state.reset_fonts(); self.fonts_changed(); } @@ -1954,16 +1915,6 @@ impl State { self.fonts_changed(); } - pub fn set_egui_fonts(&self, proportional: Option>, monospace: Option>) { - if let Some(fonts) = &proportional { - self.egg_state.set_proportional_fonts(fonts); - } - if let Some(fonts) = &monospace { - self.egg_state.set_monospace_fonts(fonts); - } - self.fonts_changed(); - } - pub fn set_bar_position(&self, p: BarPosition) { self.theme.bar_position.set(p); self.spaces_changed(); diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index b966f50e..aaab66aa 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -1,7 +1,6 @@ use { crate::{ backend::{Connector, ConnectorEvent, ConnectorId, MonitorInfo}, - control_center::CCI_OUTPUTS, globals::GlobalName, ifs::{ head_management::{HeadManagers, HeadState}, @@ -95,7 +94,6 @@ pub fn handle(state: &Rc, connector: &Rc) { for mgr in state.head_managers.lock().values() { mgr.announce(&data); } - state.trigger_cci(CCI_OUTPUTS); if state.connectors.set(id, data).is_some() { panic!("Connector id has been reused"); } @@ -135,7 +133,6 @@ impl ConnectorHandler { self.data.handler.set(None); self.state.connectors.remove(&self.id); self.data.head_managers.handle_removed(); - self.state.trigger_cci(CCI_OUTPUTS); } async fn handle_connected(&self, info: MonitorInfo) { @@ -157,7 +154,6 @@ impl ConnectorHandler { self.data .head_managers .handle_output_disconnected(&self.state); - self.state.trigger_cci(CCI_OUTPUTS); for head in self.data.wlr_output_heads.lock().drain_values() { head.handle_disconnected(); } @@ -304,7 +300,6 @@ impl ConnectorHandler { self.data .head_managers .handle_output_connected(&self.state, &output_data); - self.state.trigger_cci(CCI_OUTPUTS); self.state.wlr_output_managers.announce_head(&output_data); global.add_damage_area(&global.pos.get()); self.data.damage(); @@ -319,7 +314,6 @@ impl ConnectorHandler { } ConnectorEvent::FormatsChanged(formats) => { self.data.head_managers.handle_formats_change(&formats); - self.state.trigger_cci(CCI_OUTPUTS); on.global.formats.set(formats); } ConnectorEvent::State(state) => { @@ -433,7 +427,6 @@ impl ConnectorHandler { self.data .head_managers .handle_output_connected(&self.state, &output_data); - self.state.trigger_cci(CCI_OUTPUTS); self.state.wlr_output_managers.announce_head(&output_data); 'outer: loop { while let Some(event) = self.data.connector.event() { diff --git a/src/tree/output.rs b/src/tree/output.rs index 78b65c4f..429741d5 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -6,7 +6,6 @@ use { }, client::ClientId, cmm::cmm_description::ColorDescription, - control_center::CCI_OUTPUTS, cursor::KnownCursor, fixed::Fixed, gfx_api::{AcquireSync, BufferResv, GfxTexture, ReleaseSync}, @@ -245,7 +244,6 @@ impl OutputNode { .connector .head_managers .handle_tearing_active_change(tearing); - self.state.trigger_cci(CCI_OUTPUTS); } } @@ -504,7 +502,6 @@ impl OutputNode { .connector .head_managers .handle_scale_change(scale); - self.state.trigger_cci(CCI_OUTPUTS); for head in self.global.connector.wlr_output_heads.lock().values() { head.handle_new_scale(scale); } @@ -877,7 +874,6 @@ impl OutputNode { .connector .head_managers .handle_transform_change(transform); - self.state.trigger_cci(CCI_OUTPUTS); for head in self.global.connector.wlr_output_heads.lock().values() { head.hande_transform_change(transform); } @@ -940,7 +936,6 @@ impl OutputNode { .connector .head_managers .handle_position_size_change(self); - self.state.trigger_cci(CCI_OUTPUTS); } pub fn update_state(self: &Rc, old: BackendConnectorState, state: BackendConnectorState) { @@ -995,7 +990,6 @@ impl OutputNode { .connector .head_managers .handle_brightness_change(brightness); - self.state.trigger_cci(CCI_OUTPUTS); } } @@ -1011,7 +1005,6 @@ impl OutputNode { .connector .head_managers .handle_use_native_gamut_change(use_native_gamut); - self.state.trigger_cci(CCI_OUTPUTS); } } @@ -1023,7 +1016,6 @@ impl OutputNode { .connector .head_managers .handle_blend_space_change(blend_space); - self.state.trigger_cci(CCI_OUTPUTS); } } fn find_stacked_at( @@ -1489,7 +1481,6 @@ impl OutputNode { .connector .head_managers .handle_vrr_mode_change(mode); - self.state.trigger_cci(CCI_OUTPUTS); for head in self.global.connector.wlr_output_heads.lock().values() { head.handle_vrr_mode_change(mode); } @@ -1504,7 +1495,6 @@ impl OutputNode { .connector .head_managers .handle_tearing_mode_change(mode); - self.state.trigger_cci(CCI_OUTPUTS); } } @@ -1554,7 +1544,6 @@ impl OutputNode { pub fn set_flip_margin(&self, margin_ns: u64) { self.flip_margin_ns.set(Some(margin_ns)); - self.state.trigger_cci(CCI_OUTPUTS); } } diff --git a/src/tree/toplevel.rs b/src/tree/toplevel.rs index 5b2167c9..bf9c7060 100644 --- a/src/tree/toplevel.rs +++ b/src/tree/toplevel.rs @@ -948,10 +948,6 @@ impl ToplevelData { parent.node_is_workspace() } - pub fn property_changed_source(&self) -> &Rc { - self.property_changed_source - .get_or_init(|| self.state.lazy_event_sources.create_source()) - } } impl Drop for ToplevelData { diff --git a/src/utils/atomic_enum.rs b/src/utils/atomic_enum.rs index 45e50416..de2b81d2 100644 --- a/src/utils/atomic_enum.rs +++ b/src/utils/atomic_enum.rs @@ -31,6 +31,7 @@ where } } + #[allow(dead_code)] pub fn load(&self, ordering: Ordering) -> T { unsafe { T::from_linear_unchecked(self.v.load(ordering)) } } diff --git a/src/utils/event_listener.rs b/src/utils/event_listener.rs index 63c66012..55385ae5 100644 --- a/src/utils/event_listener.rs +++ b/src/utils/event_listener.rs @@ -141,6 +141,7 @@ impl LazyEventSource { } impl LazyEventSources { + #[allow(dead_code)] pub fn create_source(self: &Rc) -> Rc { Rc::new(LazyEventSource { sources: self.clone(), diff --git a/src/utils/object_drop_queue.rs b/src/utils/object_drop_queue.rs index f14eabbb..56010e85 100644 --- a/src/utils/object_drop_queue.rs +++ b/src/utils/object_drop_queue.rs @@ -11,6 +11,7 @@ use { }; pub struct ObjectDropQueue { + #[allow(dead_code)] ring: Rc, killed: Cell, pending: RefCell>>, @@ -32,6 +33,7 @@ impl ObjectDropQueue { } } + #[allow(dead_code)] pub fn push(self: &Rc, fd: &Rc, t: T) where T: 'static, diff --git a/src/utils/pipe.rs b/src/utils/pipe.rs index 371ef91a..9d07d2ef 100644 --- a/src/utils/pipe.rs +++ b/src/utils/pipe.rs @@ -14,6 +14,7 @@ pub fn pipe() -> Result, OsError> { } impl Pipe { + #[allow(dead_code)] pub fn map_read(self, map: impl FnOnce(L) -> Lprime) -> Pipe { Pipe { read: map(self.read), @@ -21,6 +22,7 @@ impl Pipe { } } + #[allow(dead_code)] pub fn map_write(self, map: impl FnOnce(R) -> Rprime) -> Pipe { Pipe { read: self.read, diff --git a/src/video/dmabuf.rs b/src/video/dmabuf.rs index 9ff8b1b8..bbcb9ace 100644 --- a/src/video/dmabuf.rs +++ b/src/video/dmabuf.rs @@ -1,12 +1,8 @@ use { crate::{ format::Format, - gfx_api::SyncFile, utils::{compat::IoctlNumber, oserror::OsError}, - video::{ - LINEAR_MODIFIER, Modifier, - drm::{DrmError, syncobj::merge_sync_files}, - }, + video::{LINEAR_MODIFIER, Modifier}, }, arrayvec::ArrayVec, std::{cell::OnceCell, rc::Rc, sync::OnceLock}, @@ -118,21 +114,6 @@ impl DmaBuf { Ok(()) } - pub fn export_sync_file(&self, flags: u32) -> Result, DrmError> { - let mut sf = PlaneVec::new(); - for plane in &self.planes { - sf.push( - dma_buf_export_sync_file(&plane.fd, flags) - .map(Rc::new) - .map(SyncFile) - .map_err(DrmError::ExportSyncFile)?, - ); - if self.is_one_file() { - break; - } - } - merge_sync_files(sf.iter()) - } } const DMA_BUF_BASE: u64 = b'b' as _; diff --git a/src/virtual_output.rs b/src/virtual_output.rs index ce153d7e..281c1d65 100644 --- a/src/virtual_output.rs +++ b/src/virtual_output.rs @@ -12,7 +12,6 @@ use { }, }, cmm::{cmm_description::ColorDescription, cmm_primaries::Primaries}, - control_center::CCI_VIRTUAL_OUTPUTS, format::{Format, XRGB8888}, gfx_api::{ AcquireSync, BufferResv, DirectScanoutPosition, FdSync, GfxBlendBuffer, GfxContext, @@ -285,18 +284,16 @@ impl VirtualOutputs { self.outputs.set(name.to_string(), vo.clone()); vo.flip_task .set(Some(state.eng.spawn("vo-flip", vo.clone().flip_task()))); - state.trigger_cci(CCI_VIRTUAL_OUTPUTS); vo } - pub fn remove_output(&self, state: &Rc, name: &str) { + pub fn remove_output(&self, _state: &Rc, name: &str) { let Some(o) = self.outputs.remove(name) else { return; }; o.clear(); o.events.send_event(ConnectorEvent::Disconnected); o.events.send_event(ConnectorEvent::Removed); - state.trigger_cci(CCI_VIRTUAL_OUTPUTS); } pub fn clear(&self) { diff --git a/src/wl_usr/usr_ifs/usr_jay_compositor.rs b/src/wl_usr/usr_ifs/usr_jay_compositor.rs index 63102b64..77c8b516 100644 --- a/src/wl_usr/usr_ifs/usr_jay_compositor.rs +++ b/src/wl_usr/usr_ifs/usr_jay_compositor.rs @@ -12,9 +12,8 @@ use { usr_jay_screencast::UsrJayScreencast, usr_jay_select_toplevel::UsrJaySelectToplevel, usr_jay_select_workspace::UsrJaySelectWorkspace, - usr_jay_sync_file_surface::UsrJaySyncFileSurface, usr_jay_workspace_watcher::UsrJayWorkspaceWatcher, usr_wl_output::UsrWlOutput, - usr_wl_seat::UsrWlSeat, usr_wl_surface::UsrWlSurface, + usr_wl_seat::UsrWlSeat, }, usr_object::UsrObject, }, @@ -189,20 +188,6 @@ impl UsrJayCompositor { obj } - pub fn get_sync_file_surface(&self, surface: &UsrWlSurface) -> Rc { - let obj = Rc::new(UsrJaySyncFileSurface { - id: self.con.id(), - con: self.con.clone(), - version: self.version, - }); - self.con.request(GetSyncFileSurface { - self_id: self.id, - id: obj.id, - surface: surface.id, - }); - self.con.add_object(obj.clone()); - obj - } } impl JayCompositorEventHandler for UsrJayCompositor { diff --git a/src/wl_usr/usr_ifs/usr_jay_sync_file_surface.rs b/src/wl_usr/usr_ifs/usr_jay_sync_file_surface.rs index bd07ef76..f4d38e06 100644 --- a/src/wl_usr/usr_ifs/usr_jay_sync_file_surface.rs +++ b/src/wl_usr/usr_ifs/usr_jay_sync_file_surface.rs @@ -1,12 +1,8 @@ use { crate::{ - gfx_api::FdSync, object::Version, wire::{JaySyncFileSurfaceId, jay_sync_file_surface::*}, - wl_usr::{ - UsrCon, usr_ifs::usr_jay_sync_file_release::UsrJaySyncFileRelease, - usr_object::UsrObject, - }, + wl_usr::{UsrCon, usr_object::UsrObject}, }, std::{convert::Infallible, rc::Rc}, }; @@ -17,37 +13,6 @@ pub struct UsrJaySyncFileSurface { pub version: Version, } -impl UsrJaySyncFileSurface { - pub fn set_acquire(&self, sf: Option<&FdSync>) { - match sf.and_then(|s| s.get_sync_file()) { - None => { - self.con.request(SetAcquireImmediate { self_id: self.id }); - } - Some(sf) => { - self.con.request(SetAcquireAsync { - self_id: self.id, - sync_file: sf.0.clone(), - }); - } - } - } - - pub fn get_release(&self) -> Rc { - let obj = Rc::new(UsrJaySyncFileRelease { - id: self.con.id(), - con: self.con.clone(), - owner: Default::default(), - version: self.version, - }); - self.con.request(GetRelease { - self_id: self.id, - release: obj.id, - }); - self.con.add_object(obj.clone()); - obj - } -} - impl JaySyncFileSurfaceEventHandler for UsrJaySyncFileSurface { type Error = Infallible; } diff --git a/src/wl_usr/usr_ifs/usr_wl_data_device.rs b/src/wl_usr/usr_ifs/usr_wl_data_device.rs index 6309e86f..a64a173e 100644 --- a/src/wl_usr/usr_ifs/usr_wl_data_device.rs +++ b/src/wl_usr/usr_ifs/usr_wl_data_device.rs @@ -5,7 +5,7 @@ use { wire::{WlDataDeviceId, wl_data_device::*}, wl_usr::{ UsrCon, - usr_ifs::{usr_wl_data_offer::UsrWlDataOffer, usr_wl_data_source::UsrWlDataSource}, + usr_ifs::usr_wl_data_offer::UsrWlDataOffer, usr_object::UsrObject, }, }, @@ -20,16 +20,6 @@ pub struct UsrWlDataDevice { pub selection: CloneCell>>, } -impl UsrWlDataDevice { - pub fn set_selection(&self, serial: u32, source: &UsrWlDataSource) { - self.con.request(SetSelection { - self_id: self.id, - source: source.id, - serial, - }); - } -} - impl WlDataDeviceEventHandler for UsrWlDataDevice { type Error = Infallible; diff --git a/src/wl_usr/usr_ifs/usr_wl_data_device_manager.rs b/src/wl_usr/usr_ifs/usr_wl_data_device_manager.rs index 58847c9f..9f9a1ad4 100644 --- a/src/wl_usr/usr_ifs/usr_wl_data_device_manager.rs +++ b/src/wl_usr/usr_ifs/usr_wl_data_device_manager.rs @@ -2,14 +2,7 @@ use { crate::{ object::Version, wire::{WlDataDeviceManagerId, wl_data_device_manager::*}, - wl_usr::{ - UsrCon, - usr_ifs::{ - usr_wl_data_device::UsrWlDataDevice, usr_wl_data_source::UsrWlDataSource, - usr_wl_seat::UsrWlSeat, - }, - usr_object::UsrObject, - }, + wl_usr::{UsrCon, usr_object::UsrObject}, }, std::{convert::Infallible, rc::Rc}, }; @@ -20,40 +13,6 @@ pub struct UsrWlDataDeviceManager { pub version: Version, } -impl UsrWlDataDeviceManager { - pub fn create_data_source(&self) -> Rc { - let obj = Rc::new(UsrWlDataSource { - id: self.con.id(), - con: self.con.clone(), - owner: Default::default(), - version: self.version, - }); - self.con.request(CreateDataSource { - self_id: self.id, - id: obj.id, - }); - self.con.add_object(obj.clone()); - obj - } - - pub fn get_data_device(&self, seat: &UsrWlSeat) -> Rc { - let obj = Rc::new(UsrWlDataDevice { - id: self.con.id(), - con: self.con.clone(), - version: self.version, - offer: Default::default(), - selection: Default::default(), - }); - self.con.request(GetDataDevice { - self_id: self.id, - id: obj.id, - seat: seat.id, - }); - self.con.add_object(obj.clone()); - obj - } -} - impl WlDataDeviceManagerEventHandler for UsrWlDataDeviceManager { type Error = Infallible; } diff --git a/src/wl_usr/usr_ifs/usr_wl_data_offer.rs b/src/wl_usr/usr_ifs/usr_wl_data_offer.rs index e757180a..fe413f61 100644 --- a/src/wl_usr/usr_ifs/usr_wl_data_offer.rs +++ b/src/wl_usr/usr_ifs/usr_wl_data_offer.rs @@ -6,7 +6,6 @@ use { }, ahash::AHashSet, std::{cell::RefCell, convert::Infallible, rc::Rc}, - uapi::OwnedFd, }; pub struct UsrWlDataOffer { @@ -16,16 +15,6 @@ pub struct UsrWlDataOffer { pub mime_types: RefCell>, } -impl UsrWlDataOffer { - pub fn receive(&self, mime_type: &str, fd: &Rc) { - self.con.request(Receive { - self_id: self.id, - mime_type, - fd: fd.clone(), - }); - } -} - impl WlDataOfferEventHandler for UsrWlDataOffer { type Error = Infallible; diff --git a/src/wl_usr/usr_ifs/usr_wl_data_source.rs b/src/wl_usr/usr_ifs/usr_wl_data_source.rs index 99c07f67..e14a8e85 100644 --- a/src/wl_usr/usr_ifs/usr_wl_data_source.rs +++ b/src/wl_usr/usr_ifs/usr_wl_data_source.rs @@ -20,15 +20,6 @@ pub trait UsrWlDataSourceOwner { fn send(&self, mime_type: &str, fd: Rc); } -impl UsrWlDataSource { - pub fn offer(&self, mime_type: &str) { - self.con.request(Offer { - self_id: self.id, - mime_type, - }); - } -} - impl WlDataSourceEventHandler for UsrWlDataSource { type Error = Infallible; diff --git a/src/wl_usr/usr_ifs/usr_wl_pointer.rs b/src/wl_usr/usr_ifs/usr_wl_pointer.rs index 661d9db9..298c652d 100644 --- a/src/wl_usr/usr_ifs/usr_wl_pointer.rs +++ b/src/wl_usr/usr_ifs/usr_wl_pointer.rs @@ -3,8 +3,8 @@ use { ifs::wl_seat::wl_pointer::PendingScroll, object::Version, utils::clonecell::CloneCell, - wire::{WlPointerId, WlSurfaceId, wl_pointer::*}, - wl_usr::{UsrCon, usr_ifs::usr_wl_surface::UsrWlSurface, usr_object::UsrObject}, + wire::{WlPointerId, wl_pointer::*}, + wl_usr::{UsrCon, usr_object::UsrObject}, }, std::{cell::Cell, convert::Infallible, rc::Rc}, }; @@ -40,18 +40,6 @@ pub trait UsrWlPointerOwner { } } -impl UsrWlPointer { - pub fn set_cursor(&self, serial: u32, cursor: Option<&UsrWlSurface>, hot_x: i32, hot_y: i32) { - self.con.request(SetCursor { - self_id: self.id, - serial, - surface: cursor.map(|c| c.id).unwrap_or(WlSurfaceId::NONE), - hotspot_x: hot_x, - hotspot_y: hot_y, - }); - } -} - impl WlPointerEventHandler for UsrWlPointer { type Error = Infallible; diff --git a/src/wl_usr/usr_ifs/usr_wl_seat.rs b/src/wl_usr/usr_ifs/usr_wl_seat.rs index 76cfcab6..08b48f1f 100644 --- a/src/wl_usr/usr_ifs/usr_wl_seat.rs +++ b/src/wl_usr/usr_ifs/usr_wl_seat.rs @@ -5,7 +5,7 @@ use { wire::{WlSeatId, wl_seat::*}, wl_usr::{ UsrCon, - usr_ifs::{usr_wl_keyboard::UsrWlKeyboard, usr_wl_pointer::UsrWlPointer}, + usr_ifs::usr_wl_pointer::UsrWlPointer, usr_object::UsrObject, }, }, @@ -47,21 +47,6 @@ impl UsrWlSeat { ptr } - pub fn get_keyboard(&self) -> Rc { - let kb = Rc::new(UsrWlKeyboard { - id: self.con.id(), - con: self.con.clone(), - keyboard: Default::default(), - owner: Default::default(), - version: self.version, - }); - self.con.add_object(kb.clone()); - self.con.request(GetKeyboard { - self_id: self.id, - id: kb.id, - }); - kb - } } impl WlSeatEventHandler for UsrWlSeat { diff --git a/src/wl_usr/usr_ifs/usr_wp_cursor_shape_device_v1.rs b/src/wl_usr/usr_ifs/usr_wp_cursor_shape_device_v1.rs index 623f085f..904891e3 100644 --- a/src/wl_usr/usr_ifs/usr_wp_cursor_shape_device_v1.rs +++ b/src/wl_usr/usr_ifs/usr_wp_cursor_shape_device_v1.rs @@ -1,6 +1,5 @@ use { crate::{ - cursor::KnownCursor, object::Version, wire::{WpCursorShapeDeviceV1Id, wp_cursor_shape_device_v1::*}, wl_usr::{UsrCon, usr_object::UsrObject}, @@ -14,16 +13,6 @@ pub struct UsrWpCursorShapeDeviceV1 { pub version: Version, } -impl UsrWpCursorShapeDeviceV1 { - pub fn set_shape(&self, serial: u32, cursor: KnownCursor) { - self.con.request(SetShape { - self_id: self.id, - serial, - shape: cursor.to_shape(), - }); - } -} - impl WpCursorShapeDeviceV1EventHandler for UsrWpCursorShapeDeviceV1 { type Error = Infallible; } diff --git a/src/wl_usr/usr_ifs/usr_wp_cursor_shape_manager_v1.rs b/src/wl_usr/usr_ifs/usr_wp_cursor_shape_manager_v1.rs index 49549cb9..69f7cd09 100644 --- a/src/wl_usr/usr_ifs/usr_wp_cursor_shape_manager_v1.rs +++ b/src/wl_usr/usr_ifs/usr_wp_cursor_shape_manager_v1.rs @@ -2,14 +2,7 @@ use { crate::{ object::Version, wire::{WpCursorShapeManagerV1Id, wp_cursor_shape_manager_v1::*}, - wl_usr::{ - UsrCon, - usr_ifs::{ - usr_wl_pointer::UsrWlPointer, - usr_wp_cursor_shape_device_v1::UsrWpCursorShapeDeviceV1, - }, - usr_object::UsrObject, - }, + wl_usr::{UsrCon, usr_object::UsrObject}, }, std::{convert::Infallible, rc::Rc}, }; @@ -20,23 +13,6 @@ pub struct UsrWpCursorShapeManagerV1 { pub version: Version, } -impl UsrWpCursorShapeManagerV1 { - pub fn get_pointer(&self, pointer: &UsrWlPointer) -> Rc { - let obj = Rc::new(UsrWpCursorShapeDeviceV1 { - id: self.con.id(), - con: self.con.clone(), - version: self.version, - }); - self.con.request(GetPointer { - self_id: self.id, - cursor_shape_device: obj.id, - pointer: pointer.id, - }); - self.con.add_object(obj.clone()); - obj - } -} - impl WpCursorShapeManagerV1EventHandler for UsrWpCursorShapeManagerV1 { type Error = Infallible; } diff --git a/src/wl_usr/usr_ifs/usr_xdg_surface.rs b/src/wl_usr/usr_ifs/usr_xdg_surface.rs index 04eebaf3..bcd2ca91 100644 --- a/src/wl_usr/usr_ifs/usr_xdg_surface.rs +++ b/src/wl_usr/usr_ifs/usr_xdg_surface.rs @@ -3,7 +3,7 @@ use { object::Version, utils::clonecell::CloneCell, wire::{XdgSurfaceId, xdg_surface::*}, - wl_usr::{UsrCon, usr_ifs::usr_xdg_toplevel::UsrXdgToplevel, usr_object::UsrObject}, + wl_usr::{UsrCon, usr_object::UsrObject}, }, std::{convert::Infallible, rc::Rc}, }; @@ -21,23 +21,6 @@ pub trait UsrXdgSurfaceOwner { } } -impl UsrXdgSurface { - pub fn get_toplevel(&self) -> Rc { - let obj = Rc::new(UsrXdgToplevel { - id: self.con.id(), - con: self.con.clone(), - owner: Default::default(), - version: self.version, - }); - self.con.request(GetToplevel { - self_id: self.id, - id: obj.id, - }); - self.con.add_object(obj.clone()); - obj - } -} - impl XdgSurfaceEventHandler for UsrXdgSurface { type Error = Infallible; diff --git a/src/wl_usr/usr_ifs/usr_xdg_toplevel.rs b/src/wl_usr/usr_ifs/usr_xdg_toplevel.rs index 3705abc6..66fbd6f3 100644 --- a/src/wl_usr/usr_ifs/usr_xdg_toplevel.rs +++ b/src/wl_usr/usr_ifs/usr_xdg_toplevel.rs @@ -2,7 +2,7 @@ use { crate::{ object::Version, utils::clonecell::CloneCell, - wire::{WlOutputId, XdgToplevelId, xdg_toplevel::*}, + wire::{XdgToplevelId, xdg_toplevel::*}, wl_usr::{UsrCon, usr_object::UsrObject}, }, std::{convert::Infallible, rc::Rc}, @@ -15,29 +15,6 @@ pub struct UsrXdgToplevel { pub version: Version, } -impl UsrXdgToplevel { - pub fn set_title(&self, title: &str) { - self.con.request(SetTitle { - self_id: self.id, - title, - }); - } - - pub fn set_fullscreen(&self, fullscreen: bool) { - match fullscreen { - true => { - self.con.request(SetFullscreen { - self_id: self.id, - output: WlOutputId::NONE, - }); - } - false => { - self.con.request(UnsetFullscreen { self_id: self.id }); - } - } - } -} - pub trait UsrXdgToplevelOwner { fn configure(&self, width: i32, height: i32) { let _ = width; @@ -49,8 +26,6 @@ pub trait UsrXdgToplevelOwner { } } -impl UsrXdgToplevel {} - impl XdgToplevelEventHandler for UsrXdgToplevel { type Error = Infallible; diff --git a/src/wl_usr/usr_ifs/usr_xdg_wm_base.rs b/src/wl_usr/usr_ifs/usr_xdg_wm_base.rs index 95b5f16a..7cc16a8f 100644 --- a/src/wl_usr/usr_ifs/usr_xdg_wm_base.rs +++ b/src/wl_usr/usr_ifs/usr_xdg_wm_base.rs @@ -2,11 +2,7 @@ use { crate::{ object::Version, wire::{XdgWmBaseId, xdg_wm_base::*}, - wl_usr::{ - UsrCon, - usr_ifs::{usr_wl_surface::UsrWlSurface, usr_xdg_surface::UsrXdgSurface}, - usr_object::UsrObject, - }, + wl_usr::{UsrCon, usr_object::UsrObject}, }, std::{convert::Infallible, rc::Rc}, }; @@ -17,24 +13,6 @@ pub struct UsrXdgWmBase { pub version: Version, } -impl UsrXdgWmBase { - pub fn get_xdg_surface(&self, surface: &UsrWlSurface) -> Rc { - let obj = Rc::new(UsrXdgSurface { - id: self.con.id(), - con: self.con.clone(), - owner: Default::default(), - version: self.version, - }); - self.con.request(GetXdgSurface { - self_id: self.id, - id: obj.id, - surface: surface.id, - }); - self.con.add_object(obj.clone()); - obj - } -} - impl XdgWmBaseEventHandler for UsrXdgWmBase { type Error = Infallible; diff --git a/src/wl_usr/usr_ifs/usr_zwp_linux_buffer_params_v1.rs b/src/wl_usr/usr_ifs/usr_zwp_linux_buffer_params_v1.rs index f06a383b..8e908dcb 100644 --- a/src/wl_usr/usr_ifs/usr_zwp_linux_buffer_params_v1.rs +++ b/src/wl_usr/usr_ifs/usr_zwp_linux_buffer_params_v1.rs @@ -1,13 +1,10 @@ use { crate::{ - format::Format, object::Version, - video::Modifier, wire::{ZwpLinuxBufferParamsV1Id, zwp_linux_buffer_params_v1::*}, - wl_usr::{UsrCon, usr_ifs::usr_wl_buffer::UsrWlBuffer, usr_object::UsrObject}, + wl_usr::{UsrCon, usr_object::UsrObject}, }, std::{convert::Infallible, rc::Rc}, - uapi::OwnedFd, }; pub struct UsrZwpLinuxBufferParamsV1 { @@ -16,45 +13,6 @@ pub struct UsrZwpLinuxBufferParamsV1 { pub version: Version, } -impl UsrZwpLinuxBufferParamsV1 { - pub fn add( - &self, - fd: &Rc, - plane_idx: usize, - offset: u32, - stride: u32, - modifier: Modifier, - ) { - self.con.request(Add { - self_id: self.id, - fd: fd.clone(), - plane_idx: plane_idx as u32, - offset, - stride, - modifier, - }); - } - - pub fn create_immed(&self, width: i32, height: i32, format: &Format) -> Rc { - let obj = Rc::new(UsrWlBuffer { - id: self.con.id(), - con: self.con.clone(), - owner: Default::default(), - version: self.version, - }); - self.con.request(CreateImmed { - self_id: self.id, - buffer_id: obj.id, - width, - height, - format: format.drm, - flags: 0, - }); - self.con.add_object(obj.clone()); - obj - } -} - impl ZwpLinuxBufferParamsV1EventHandler for UsrZwpLinuxBufferParamsV1 { type Error = Infallible; diff --git a/src/wl_usr/usr_ifs/usr_zwp_linux_dmabuf_v1.rs b/src/wl_usr/usr_ifs/usr_zwp_linux_dmabuf_v1.rs index f39e85b4..0cbb1d96 100644 --- a/src/wl_usr/usr_ifs/usr_zwp_linux_dmabuf_v1.rs +++ b/src/wl_usr/usr_ifs/usr_zwp_linux_dmabuf_v1.rs @@ -1,16 +1,8 @@ use { crate::{ object::Version, - video::dmabuf::DmaBuf, wire::{ZwpLinuxDmabufV1Id, zwp_linux_dmabuf_v1::*}, - wl_usr::{ - UsrCon, - usr_ifs::{ - usr_wl_buffer::UsrWlBuffer, - usr_zwp_linux_buffer_params_v1::UsrZwpLinuxBufferParamsV1, - }, - usr_object::UsrObject, - }, + wl_usr::{UsrCon, usr_object::UsrObject}, }, std::{convert::Infallible, rc::Rc}, }; @@ -21,27 +13,6 @@ pub struct UsrZwpLinuxDmabufV1 { pub version: Version, } -impl UsrZwpLinuxDmabufV1 { - pub fn create_buffer(&self, buffer: &DmaBuf) -> Rc { - let params = Rc::new(UsrZwpLinuxBufferParamsV1 { - id: self.con.id(), - con: self.con.clone(), - version: self.version, - }); - self.con.request(CreateParams { - self_id: self.id, - params_id: params.id, - }); - self.con.add_object(params.clone()); - for (idx, plane) in buffer.planes.iter().enumerate() { - params.add(&plane.fd, idx, plane.offset, plane.stride, buffer.modifier); - } - let obj = params.create_immed(buffer.width, buffer.height, &buffer.format); - self.con.remove_obj(&*params); - obj - } -} - impl ZwpLinuxDmabufV1EventHandler for UsrZwpLinuxDmabufV1 { type Error = Infallible; diff --git a/src/xwayland.rs b/src/xwayland.rs index 04234dd7..a60e34a4 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -5,7 +5,6 @@ use { crate::{ client::{ClientCaps, ClientError}, compositor::DISPLAY, - control_center::CCI_XWAYLAND, forker::{ForkerError, ForkerProxy}, ifs::{ ipc::{DataOfferId, DataSourceId, IpcLocation, x_data_offer::XDataOffer}, @@ -118,11 +117,9 @@ pub async fn manage(state: Rc) { let display = Rc::new(format!(":{}", xsocket.id)); forker.setenv(DISPLAY.as_bytes(), display.as_bytes()); state.xwayland.display.set(Some(display.clone())); - state.trigger_cci(CCI_XWAYLAND); let _unsetenv = on_drop(|| { forker.unsetenv(DISPLAY.as_bytes()); state.xwayland.display.take(); - state.trigger_cci(CCI_XWAYLAND); }); log::info!("Allocated display :{} for Xwayland", xsocket.id); log::info!("Waiting for connection attempt"); @@ -209,11 +206,9 @@ async fn run( state.xwayland.queue.clear(); state.xwayland.pidfd.set(Some(pidfd.clone())); state.xwayland.client.set(Some(client.clone())); - state.trigger_cci(CCI_XWAYLAND); let _remove_pidfd = on_drop(|| { state.xwayland.pidfd.take(); state.xwayland.client.take(); - state.trigger_cci(CCI_XWAYLAND); }); { let shared = Rc::new(XwmShared::default()); diff --git a/toml-config/src/config.rs b/toml-config/src/config.rs index e25ccaa0..4359f8aa 100644 --- a/toml-config/src/config.rs +++ b/toml-config/src/config.rs @@ -91,7 +91,6 @@ pub enum SimpleCommand { ToggleSimpleImEnabled, ReloadSimpleIm, EnableUnicodeInput, - OpenControlCenter, WarpMouseToFocus, } @@ -226,12 +225,6 @@ pub struct Theme { pub bar_separator_width: Option, } -#[derive(Debug, Clone, Default)] -pub struct Egui { - pub proportional_fonts: Option>, - pub monospace_fonts: Option>, -} - #[derive(Debug, Clone)] pub struct Status { pub format: MessageFormat, @@ -532,7 +525,6 @@ pub struct Config { pub log_level: Option, pub clean_logs_older_than: Option, pub theme: Theme, - pub egui: Egui, pub gfx_api: Option, pub direct_scanout_enabled: Option, pub drm_devices: Vec, diff --git a/toml-config/src/config/parsers.rs b/toml-config/src/config/parsers.rs index 448c26b4..4c5e337b 100644 --- a/toml-config/src/config/parsers.rs +++ b/toml-config/src/config/parsers.rs @@ -20,7 +20,6 @@ mod connector_match; mod content_type; mod drm_device; mod drm_device_match; -mod egui; mod env; pub mod exec; mod fallback_output_mode; diff --git a/toml-config/src/config/parsers/action.rs b/toml-config/src/config/parsers/action.rs index abbb5ce3..9cfa631f 100644 --- a/toml-config/src/config/parsers/action.rs +++ b/toml-config/src/config/parsers/action.rs @@ -168,7 +168,6 @@ impl ActionParser<'_> { "toggle-simple-im-enabled" => ToggleSimpleImEnabled, "reload-simple-im" => ReloadSimpleIm, "enable-unicode-input" => EnableUnicodeInput, - "open-control-center" => OpenControlCenter, "warp-mouse-to-focus" => WarpMouseToFocus, _ => { return Err( diff --git a/toml-config/src/config/parsers/config.rs b/toml-config/src/config/parsers/config.rs index 9a150ecb..b9d34e74 100644 --- a/toml-config/src/config/parsers/config.rs +++ b/toml-config/src/config/parsers/config.rs @@ -1,7 +1,7 @@ use { crate::{ config::{ - Action, Config, Egui, Libei, Theme, UiDrag, + Action, Config, Libei, Theme, UiDrag, context::Context, extractor::{Extractor, ExtractorError, arr, bol, int, opt, recover, str, val}, parser::{DataType, ParseResult, Parser, UnexpectedDataType}, @@ -14,7 +14,6 @@ use { connector::ConnectorsParser, drm_device::DrmDevicesParser, drm_device_match::DrmDeviceMatchParser, - egui::EguiParser, env::EnvParser, fallback_output_mode::FallbackOutputModeParser, float::FloatParser, @@ -152,7 +151,6 @@ impl Parser for ConfigParser<'_> { simple_im_val, show_titles, fallback_output_mode_val, - egui_val, clean_logs_older_than_val, mouse_follows_focus, ), @@ -213,7 +211,6 @@ impl Parser for ConfigParser<'_> { opt(val("simple-im")), recover(opt(bol("show-titles"))), opt(val("fallback-output-mode")), - opt(val("egui")), opt(val("clean-logs-older-than")), recover(opt(bol("unstable-mouse-follows-focus"))), ), @@ -332,15 +329,6 @@ impl Parser for ConfigParser<'_> { } } } - let mut egui = Egui::default(); - if let Some(value) = egui_val { - match value.parse(&mut EguiParser(self.0)) { - Ok(v) => egui = v, - Err(e) => { - log::warn!("Could not parse the egui settings: {}", self.0.error(e)); - } - } - } let mut gfx_api = None; if let Some(value) = gfx_api_val { match value.parse(&mut GfxApiParser) { @@ -585,7 +573,6 @@ impl Parser for ConfigParser<'_> { log_level, clean_logs_older_than, theme, - egui, gfx_api, drm_devices, direct_scanout_enabled: direct_scanout.despan(), diff --git a/toml-config/src/config/parsers/egui.rs b/toml-config/src/config/parsers/egui.rs deleted file mode 100644 index 6c77606e..00000000 --- a/toml-config/src/config/parsers/egui.rs +++ /dev/null @@ -1,63 +0,0 @@ -use { - crate::{ - config::{ - Egui, - context::Context, - extractor::{Extractor, ExtractorError, arr, opt}, - parser::{DataType, ParseResult, Parser, UnexpectedDataType}, - }, - toml::{ - toml_span::{Span, Spanned}, - toml_value::Value, - }, - }, - indexmap::IndexMap, - thiserror::Error, -}; - -pub struct EguiParser<'a>(pub &'a Context<'a>); - -#[derive(Debug, Error)] -pub enum EguiParserError { - #[error(transparent)] - Expected(#[from] UnexpectedDataType), - #[error(transparent)] - Extractor(#[from] ExtractorError), -} - -impl Parser for EguiParser<'_> { - type Value = Egui; - type Error = EguiParserError; - const EXPECTED: &'static [DataType] = &[DataType::Table]; - - fn parse_table( - &mut self, - span: Span, - table: &IndexMap, Spanned>, - ) -> ParseResult { - let mut ext = Extractor::new(self.0, span, table); - let (proportional_fonts_arr, monospace_fonts_arr) = - ext.extract((opt(arr("proportional-fonts")), opt(arr("monospace-fonts"))))?; - let mut proportional_fonts = None; - let mut monospace_fonts = None; - for (out, f) in [ - (&mut proportional_fonts, proportional_fonts_arr), - (&mut monospace_fonts, monospace_fonts_arr), - ] { - if let Some(f) = f { - let fonts = out.insert(vec![]); - for f in f.value { - let Value::String(s) = &f.value else { - log::error!("Expected a string: {}", self.0.error3(f.span)); - continue; - }; - fonts.push(s.clone()); - } - } - } - Ok(Egui { - proportional_fonts, - monospace_fonts, - }) - } -} diff --git a/toml-config/src/default-config.toml b/toml-config/src/default-config.toml index f8c3026f..fd572891 100644 --- a/toml-config/src/default-config.toml +++ b/toml-config/src/default-config.toml @@ -31,7 +31,6 @@ alt-m = "toggle-mono" alt-u = "toggle-fullscreen" alt-f = "focus-parent" -alt-c = "open-control-center" alt-shift-c = "close" alt-shift-f = "toggle-floating" Super_L = { type = "exec", exec = "alacritty" } diff --git a/toml-config/src/lib.rs b/toml-config/src/lib.rs index b46320a7..3a948cc5 100644 --- a/toml-config/src/lib.rs +++ b/toml-config/src/lib.rs @@ -36,7 +36,7 @@ use { is_reload, keyboard::Keymap, logging::{clean_logs_older_than, set_log_level}, - on_devices_enumerated, on_idle, on_unload, open_control_center, quit, reload, + on_devices_enumerated, on_idle, on_unload, quit, reload, set_color_management_enabled, set_default_workspace_capture, set_explicit_sync_enabled, set_float_above_fullscreen, set_idle, set_idle_grace_period, set_middle_click_paste_enabled, set_show_bar, set_show_float_pin_icon, set_show_titles, @@ -45,8 +45,8 @@ use { switch_to_vt, tasks::{self, JoinHandle}, theme::{ - reset_colors, reset_font, reset_sizes, set_bar_font, set_bar_position, - set_egui_monospace_fonts, set_egui_proportional_fonts, set_font, set_title_font, + reset_colors, reset_font, reset_sizes, set_bar_font, set_bar_position, set_font, + set_title_font, }, toggle_float_above_fullscreen, toggle_show_bar, toggle_show_titles, video::{ @@ -250,7 +250,6 @@ impl Action { let persistent = state.persistent.clone(); b.new(move || persistent.seat.enable_unicode_input()) } - SimpleCommand::OpenControlCenter => b.new(open_control_center), SimpleCommand::WarpMouseToFocus => { let persistent = state.persistent.clone(); b.new(move || persistent.seat.warp_mouse_to_focus()) @@ -1662,12 +1661,6 @@ fn load_config(initial_load: bool, auto_reload: bool, persistent: &Rc