From bc31ad4a8c61f1eb2f3daf28a892fcd147b08185 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 19 Feb 2026 18:57:49 +0100 Subject: [PATCH] gpui: Extract gpui_platform out of gpui (#49277) #2874 on steroids Before you mark this PR as ready for review, make sure that you have: - [ ] Added a solid test coverage and/or screenshots from doing manual testing - [ ] Done a self-review taking into account security and performance aspects - [ ] Aligned any UI changes with the [UI checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) Release Notes: - N/A --------- Co-authored-by: Eric Holk --- Cargo.lock | 166 +++++- Cargo.toml | 12 + crates/component_preview/Cargo.toml | 5 +- .../examples/component_preview.rs | 151 ++++- .../src/component_preview.rs | 8 +- .../src/component_preview_example.rs | 148 ----- crates/edit_prediction_cli/Cargo.toml | 1 + crates/edit_prediction_cli/src/main.rs | 4 +- crates/eval/Cargo.toml | 1 + crates/eval/src/eval.rs | 4 +- crates/eval_utils/Cargo.toml | 2 +- crates/eval_utils/src/eval_utils.rs | 2 +- crates/extension_cli/Cargo.toml | 2 +- crates/extension_cli/src/main.rs | 2 +- crates/fs_benchmarks/Cargo.toml | 3 +- crates/fs_benchmarks/src/main.rs | 6 +- crates/gpui/Cargo.toml | 106 +--- crates/gpui/build.rs | 465 +-------------- crates/gpui/examples/animation.rs | 39 +- crates/gpui/examples/data_table.rs | 9 +- crates/gpui/examples/drag_drop.rs | 7 +- crates/gpui/examples/focus_visible.rs | 7 +- crates/gpui/examples/gif_viewer.rs | 5 +- crates/gpui/examples/gradient.rs | 7 +- crates/gpui/examples/grid_layout.rs | 6 +- crates/gpui/examples/hello_world.rs | 7 +- crates/gpui/examples/image/image.rs | 9 +- crates/gpui/examples/image_gallery.rs | 7 +- crates/gpui/examples/image_loading.rs | 37 +- crates/gpui/examples/input.rs | 9 +- crates/gpui/examples/layer_shell.rs | 8 +- crates/gpui/examples/mouse_pressure.rs | 7 +- crates/gpui/examples/on_window_close_quit.rs | 7 +- crates/gpui/examples/opacity.rs | 7 +- crates/gpui/examples/ownership_post.rs | 5 +- crates/gpui/examples/painting.rs | 9 +- crates/gpui/examples/paths_bench.rs | 9 +- crates/gpui/examples/pattern.rs | 7 +- crates/gpui/examples/popover.rs | 7 +- crates/gpui/examples/scrollable.rs | 8 +- crates/gpui/examples/set_menus.rs | 7 +- crates/gpui/examples/shadow.rs | 7 +- crates/gpui/examples/svg/svg.rs | 7 +- crates/gpui/examples/tab_stop.rs | 7 +- crates/gpui/examples/testing.rs | 5 +- crates/gpui/examples/text.rs | 9 +- crates/gpui/examples/text_layout.rs | 7 +- crates/gpui/examples/text_wrapper.rs | 7 +- crates/gpui/examples/tree.rs | 8 +- crates/gpui/examples/uniform_list.rs | 7 +- crates/gpui/examples/window.rs | 7 +- crates/gpui/examples/window_positioning.rs | 5 +- crates/gpui/examples/window_shadow.rs | 11 +- crates/gpui/src/_ownership_and_data_flow.rs | 10 +- crates/gpui/src/app.rs | 23 +- crates/gpui/src/app/visual_test_context.rs | 126 +--- crates/gpui/src/assets.rs | 7 +- crates/gpui/src/color.rs | 2 +- crates/gpui/src/geometry.rs | 16 +- crates/gpui/src/gpui.rs | 11 +- crates/gpui/src/interactive.rs | 2 +- crates/gpui/src/keymap/context.rs | 2 +- crates/gpui/src/platform.rs | 239 ++++---- crates/gpui/src/platform/keystroke.rs | 3 +- .../{linux/wayland => }/layer_shell.rs | 28 - crates/gpui/src/platform/linux.rs | 32 - crates/gpui/src/platform/linux/wayland.rs | 49 -- crates/gpui/src/platform/mac/status_item.rs | 387 ------------ .../src/platform/mac/window_appearance.rs | 37 -- .../gpui/src/platform/scap_screen_capture.rs | 2 +- crates/gpui/src/platform/test/platform.rs | 31 - crates/gpui/src/platform/test/window.rs | 4 +- crates/gpui/src/platform/visual_test.rs | 48 +- crates/gpui/src/platform/wgpu.rs | 7 - crates/gpui/src/profiler.rs | 26 +- crates/gpui/src/queue.rs | 32 +- crates/gpui/src/scene.rs | 85 +-- crates/gpui/src/svg_renderer.rs | 7 +- crates/gpui/src/text_system.rs | 60 +- crates/gpui/src/text_system/line_layout.rs | 5 +- crates/gpui/src/window.rs | 6 +- crates/gpui_linux/Cargo.toml | 134 +++++ crates/gpui_linux/LICENSE-APACHE | 1 + crates/gpui_linux/src/gpui_linux.rs | 4 + crates/gpui_linux/src/linux.rs | 57 ++ .../src}/linux/dispatcher.rs | 21 +- .../src}/linux/headless.rs | 0 .../src}/linux/headless/client.rs | 27 +- .../src}/linux/keyboard.rs | 2 +- .../src}/linux/platform.rs | 560 +++++++++--------- .../src}/linux/text_system.rs | 120 +--- crates/gpui_linux/src/linux/wayland.rs | 47 ++ .../src}/linux/wayland/client.rs | 154 ++--- .../src}/linux/wayland/clipboard.rs | 8 +- .../src}/linux/wayland/cursor.rs | 10 +- .../src}/linux/wayland/display.rs | 4 +- .../src/linux/wayland/layer_shell.rs | 26 + .../src}/linux/wayland/serial.rs | 0 .../src}/linux/wayland/window.rs | 99 ++-- .../platform => gpui_linux/src}/linux/x11.rs | 0 .../src}/linux/x11/client.rs | 116 ++-- .../src}/linux/x11/clipboard.rs | 2 +- .../src}/linux/x11/display.rs | 4 +- .../src}/linux/x11/event.rs | 2 +- .../src}/linux/x11/window.rs | 68 +-- .../src}/linux/x11/xim_handler.rs | 0 .../src}/linux/xdg_desktop_portal.rs | 31 +- crates/gpui_macos/Cargo.toml | 62 ++ crates/gpui_macos/LICENSE-APACHE | 1 + crates/gpui_macos/build.rs | 209 +++++++ .../mac => gpui_macos/src}/dispatch.h | 0 .../mac => gpui_macos/src}/dispatcher.rs | 2 +- .../mac => gpui_macos/src}/display.rs | 6 +- .../mac => gpui_macos/src}/display_link.rs | 2 +- .../platform/mac => gpui_macos/src}/events.rs | 382 ++++++------ .../mac.rs => gpui_macos/src/gpui_macos.rs} | 36 +- .../mac => gpui_macos/src}/keyboard.rs | 4 +- .../mac => gpui_macos/src}/metal_atlas.rs | 54 +- .../mac => gpui_macos/src}/metal_renderer.rs | 24 +- .../mac => gpui_macos/src}/open_type.rs | 2 +- .../mac => gpui_macos/src}/pasteboard.rs | 10 +- .../mac => gpui_macos/src}/platform.rs | 50 +- .../mac => gpui_macos/src}/screen_capture.rs | 19 +- .../mac => gpui_macos/src}/shaders.metal | 0 .../mac => gpui_macos/src}/text_system.rs | 171 +++--- .../platform/mac => gpui_macos/src}/window.rs | 97 +-- crates/gpui_macos/src/window_appearance.rs | 35 ++ crates/gpui_platform/Cargo.toml | 32 + crates/gpui_platform/LICENSE-APACHE | 1 + crates/gpui_platform/src/gpui_platform.rs | 150 +++++ crates/gpui_wgpu/Cargo.toml | 26 + crates/gpui_wgpu/LICENSE-APACHE | 1 + crates/gpui_wgpu/src/gpui_wgpu.rs | 8 + .../wgpu => gpui_wgpu/src}/shaders.wgsl | 0 .../wgpu => gpui_wgpu/src}/wgpu_atlas.rs | 12 +- .../wgpu => gpui_wgpu/src}/wgpu_context.rs | 0 .../wgpu => gpui_wgpu/src}/wgpu_renderer.rs | 6 +- crates/gpui_windows/Cargo.toml | 46 ++ crates/gpui_windows/LICENSE-APACHE | 1 + crates/gpui_windows/build.rs | 242 ++++++++ .../src}/alpha_correction.hlsl | 0 .../windows => gpui_windows/src}/clipboard.rs | 27 +- .../src}/color_text_raster.hlsl | 0 .../src}/destination_list.rs | 2 +- .../src}/direct_write.rs | 72 ++- .../src}/directx_atlas.rs | 34 +- .../src}/directx_devices.rs | 0 .../src}/directx_renderer.rs | 11 +- .../src}/dispatcher.rs | 24 +- .../windows => gpui_windows/src}/display.rs | 21 +- .../windows => gpui_windows/src}/events.rs | 27 +- .../src/gpui_windows.rs} | 9 +- .../windows => gpui_windows/src}/keyboard.rs | 5 +- .../windows => gpui_windows/src}/platform.rs | 22 +- .../windows => gpui_windows/src}/shaders.hlsl | 0 .../src}/system_settings.rs | 0 .../windows => gpui_windows/src}/util.rs | 14 +- .../windows => gpui_windows/src}/vsync.rs | 0 .../windows => gpui_windows/src}/window.rs | 24 +- .../windows => gpui_windows/src}/wrapper.rs | 0 crates/livekit_client/Cargo.toml | 3 +- crates/livekit_client/examples/test_app.rs | 2 +- crates/markdown/Cargo.toml | 1 + crates/markdown/examples/markdown.rs | 4 +- crates/markdown/examples/markdown_as_child.rs | 4 +- crates/project_benchmarks/Cargo.toml | 3 +- crates/project_benchmarks/src/main.rs | 4 +- crates/remote_server/Cargo.toml | 3 +- crates/remote_server/src/server.rs | 2 +- crates/storybook/Cargo.toml | 1 + crates/storybook/src/storybook.rs | 80 +-- crates/worktree_benchmarks/Cargo.toml | 2 +- crates/worktree_benchmarks/src/main.rs | 3 +- crates/zed/Cargo.toml | 9 +- crates/zed/src/main.rs | 6 +- crates/zed/src/visual_test_runner.rs | 5 +- crates/zed/src/zed/visual_tests.rs | 6 +- typos.toml | 10 +- 178 files changed, 3115 insertions(+), 3205 deletions(-) delete mode 100644 crates/component_preview/src/component_preview_example.rs rename crates/gpui/src/platform/{linux/wayland => }/layer_shell.rs (76%) delete mode 100644 crates/gpui/src/platform/linux.rs delete mode 100644 crates/gpui/src/platform/linux/wayland.rs delete mode 100644 crates/gpui/src/platform/mac/status_item.rs delete mode 100644 crates/gpui/src/platform/mac/window_appearance.rs delete mode 100644 crates/gpui/src/platform/wgpu.rs create mode 100644 crates/gpui_linux/Cargo.toml create mode 120000 crates/gpui_linux/LICENSE-APACHE create mode 100644 crates/gpui_linux/src/gpui_linux.rs create mode 100644 crates/gpui_linux/src/linux.rs rename crates/{gpui/src/platform => gpui_linux/src}/linux/dispatcher.rs (95%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/headless.rs (100%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/headless/client.rs (79%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/keyboard.rs (87%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/platform.rs (66%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/text_system.rs (85%) create mode 100644 crates/gpui_linux/src/linux/wayland.rs rename crates/{gpui/src/platform => gpui_linux/src}/linux/wayland/client.rs (95%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/wayland/clipboard.rs (97%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/wayland/cursor.rs (94%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/wayland/display.rs (89%) create mode 100644 crates/gpui_linux/src/linux/wayland/layer_shell.rs rename crates/{gpui/src/platform => gpui_linux/src}/linux/wayland/serial.rs (100%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/wayland/window.rs (94%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/x11.rs (100%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/x11/client.rs (96%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/x11/clipboard.rs (99%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/x11/display.rs (91%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/x11/event.rs (98%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/x11/window.rs (97%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/x11/xim_handler.rs (100%) rename crates/{gpui/src/platform => gpui_linux/src}/linux/xdg_desktop_portal.rs (84%) create mode 100644 crates/gpui_macos/Cargo.toml create mode 120000 crates/gpui_macos/LICENSE-APACHE create mode 100644 crates/gpui_macos/build.rs rename crates/{gpui/src/platform/mac => gpui_macos/src}/dispatch.h (100%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/dispatcher.rs (99%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/display.rs (97%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/display_link.rs (99%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/events.rs (63%) rename crates/{gpui/src/platform/mac.rs => gpui_macos/src/gpui_macos.rs} (73%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/keyboard.rs (99%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/metal_atlas.rs (85%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/metal_renderer.rs (99%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/open_type.rs (99%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/pasteboard.rs (97%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/platform.rs (97%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/screen_capture.rs (97%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/shaders.metal (100%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/text_system.rs (89%) rename crates/{gpui/src/platform/mac => gpui_macos/src}/window.rs (97%) create mode 100644 crates/gpui_macos/src/window_appearance.rs create mode 100644 crates/gpui_platform/Cargo.toml create mode 120000 crates/gpui_platform/LICENSE-APACHE create mode 100644 crates/gpui_platform/src/gpui_platform.rs create mode 100644 crates/gpui_wgpu/Cargo.toml create mode 120000 crates/gpui_wgpu/LICENSE-APACHE create mode 100644 crates/gpui_wgpu/src/gpui_wgpu.rs rename crates/{gpui/src/platform/wgpu => gpui_wgpu/src}/shaders.wgsl (100%) rename crates/{gpui/src/platform/wgpu => gpui_wgpu/src}/wgpu_atlas.rs (97%) rename crates/{gpui/src/platform/wgpu => gpui_wgpu/src}/wgpu_context.rs (100%) rename crates/{gpui/src/platform/wgpu => gpui_wgpu/src}/wgpu_renderer.rs (99%) create mode 100644 crates/gpui_windows/Cargo.toml create mode 120000 crates/gpui_windows/LICENSE-APACHE create mode 100644 crates/gpui_windows/build.rs rename crates/{gpui/src/platform/windows => gpui_windows/src}/alpha_correction.hlsl (100%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/clipboard.rs (96%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/color_text_raster.hlsl (100%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/destination_list.rs (99%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/direct_write.rs (97%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/directx_atlas.rs (91%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/directx_devices.rs (100%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/directx_renderer.rs (99%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/dispatcher.rs (92%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/display.rs (94%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/events.rs (98%) rename crates/{gpui/src/platform/windows.rs => gpui_windows/src/gpui_windows.rs} (80%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/keyboard.rs (99%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/platform.rs (98%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/shaders.hlsl (100%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/system_settings.rs (100%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/util.rs (95%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/vsync.rs (100%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/window.rs (98%) rename crates/{gpui/src/platform/windows => gpui_windows/src}/wrapper.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index dfcb8cc63b1e51995e3c3eca2a3d8c41fb4e1e98..800e9e2d2b0feda6b759c8e76f7218c7897dbd8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3438,6 +3438,7 @@ dependencies = [ "db", "fs", "gpui", + "gpui_platform", "language", "log", "node_runtime", @@ -5242,6 +5243,7 @@ dependencies = [ "fs", "futures 0.3.31", "gpui", + "gpui_platform", "gpui_tokio", "http_client", "indoc", @@ -5779,6 +5781,7 @@ dependencies = [ "fs", "futures 0.3.31", "gpui", + "gpui_platform", "gpui_tokio", "handlebars 4.5.0", "language", @@ -5814,7 +5817,7 @@ dependencies = [ name = "eval_utils" version = "0.1.0" dependencies = [ - "gpui", + "gpui_platform", "serde", "smol", ] @@ -5931,7 +5934,7 @@ dependencies = [ "env_logger 0.11.8", "extension", "fs", - "gpui", + "gpui_platform", "language", "log", "reqwest_client", @@ -6498,6 +6501,7 @@ version = "0.1.0" dependencies = [ "fs", "gpui", + "gpui_platform", ] [[package]] @@ -7348,16 +7352,11 @@ name = "gpui" version = "0.2.2" dependencies = [ "anyhow", - "as-raw-xcb-connection", - "ashpd", "async-task", "backtrace", "bindgen 0.71.1", "bitflags 2.10.0", "block", - "bytemuck", - "calloop", - "calloop-wayland-source", "cbindgen", "chrono", "circular-buffer", @@ -7369,21 +7368,19 @@ dependencies = [ "core-graphics 0.24.0", "core-text", "core-video", - "cosmic-text", "ctor", "derive_more 0.99.20", "embed-resource", "env_logger 0.11.8", "etagere", - "filedescriptor", "foreign-types 0.5.0", "futures 0.3.31", "gpui_macros", + "gpui_platform", "http_client", "image", "inventory", "itertools 0.14.0", - "libc", "log", "lyon", "mach2 0.5.0", @@ -7394,8 +7391,6 @@ dependencies = [ "objc", "objc2", "objc2-metal", - "oo7", - "open", "parking", "parking_lot", "pathfinder_geometry", @@ -7411,7 +7406,6 @@ dependencies = [ "scheduler", "schemars", "seahash", - "semver", "serde", "serde_json", "slotmap", @@ -7421,7 +7415,6 @@ dependencies = [ "stacksafe", "strum 0.27.2", "sum_tree", - "swash", "taffy", "thiserror 2.0.17", "unicode-segmentation", @@ -7430,17 +7423,50 @@ dependencies = [ "util_macros", "uuid", "waker-fn", + "windows 0.61.3", + "zed-font-kit", + "zed-scap", +] + +[[package]] +name = "gpui_linux" +version = "0.1.0" +dependencies = [ + "anyhow", + "as-raw-xcb-connection", + "ashpd", + "bitflags 2.10.0", + "bytemuck", + "calloop", + "calloop-wayland-source", + "collections", + "cosmic-text", + "filedescriptor", + "futures 0.3.31", + "gpui", + "gpui_wgpu", + "http_client", + "itertools 0.14.0", + "libc", + "log", + "oo7", + "open", + "parking_lot", + "pathfinder_geometry", + "profiling", + "raw-window-handle", + "smallvec", + "smol", + "strum 0.27.2", + "swash", + "util", + "uuid", "wayland-backend", "wayland-client", "wayland-cursor", "wayland-protocols", "wayland-protocols-plasma", "wayland-protocols-wlr", - "wgpu", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-numerics 0.2.0", - "windows-registry 0.5.3", "x11-clipboard", "x11rb", "xkbcommon", @@ -7449,6 +7475,47 @@ dependencies = [ "zed-xim", ] +[[package]] +name = "gpui_macos" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-task", + "bindgen 0.71.1", + "block", + "cbindgen", + "cocoa 0.26.0", + "collections", + "core-foundation 0.10.0", + "core-foundation-sys", + "core-graphics 0.24.0", + "core-text", + "core-video", + "ctor", + "derive_more 0.99.20", + "etagere", + "foreign-types 0.5.0", + "futures 0.3.31", + "gpui", + "image", + "itertools 0.14.0", + "libc", + "log", + "mach2 0.5.0", + "media", + "metal 0.29.0", + "objc", + "parking_lot", + "pathfinder_geometry", + "raw-window-handle", + "semver", + "smallvec", + "strum 0.27.2", + "util", + "uuid", + "zed-font-kit", +] + [[package]] name = "gpui_macros" version = "0.1.0" @@ -7460,6 +7527,16 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "gpui_platform" +version = "0.1.0" +dependencies = [ + "gpui", + "gpui_linux", + "gpui_macos", + "gpui_windows", +] + [[package]] name = "gpui_tokio" version = "0.1.0" @@ -7470,6 +7547,49 @@ dependencies = [ "util", ] +[[package]] +name = "gpui_wgpu" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytemuck", + "collections", + "etagere", + "gpui", + "log", + "parking_lot", + "profiling", + "raw-window-handle", + "smol", + "util", + "wgpu", +] + +[[package]] +name = "gpui_windows" +version = "0.1.0" +dependencies = [ + "anyhow", + "collections", + "etagere", + "futures 0.3.31", + "gpui", + "image", + "itertools 0.14.0", + "log", + "parking_lot", + "rand 0.9.2", + "raw-window-handle", + "smallvec", + "util", + "uuid", + "windows 0.61.3", + "windows-core 0.61.2", + "windows-numerics 0.2.0", + "windows-registry 0.5.3", + "zed-scap", +] + [[package]] name = "grid" version = "0.18.0" @@ -9534,6 +9654,7 @@ dependencies = [ "cpal", "futures 0.3.31", "gpui", + "gpui_platform", "gpui_tokio", "http_client_tls", "image", @@ -9786,6 +9907,7 @@ dependencies = [ "fs", "futures 0.3.31", "gpui", + "gpui_platform", "language", "languages", "linkify", @@ -12736,6 +12858,7 @@ dependencies = [ "client", "futures 0.3.31", "gpui", + "gpui_platform", "http_client", "language", "node_runtime", @@ -13702,6 +13825,7 @@ dependencies = [ "git2", "git_hosting_providers", "gpui", + "gpui_platform", "gpui_tokio", "http_client", "image", @@ -15911,6 +16035,7 @@ dependencies = [ "editor", "fuzzy", "gpui", + "gpui_platform", "indoc", "language", "log", @@ -20724,7 +20849,7 @@ name = "worktree_benchmarks" version = "0.1.0" dependencies = [ "fs", - "gpui", + "gpui_platform", "settings", "worktree", ] @@ -21140,6 +21265,7 @@ dependencies = [ "git_ui", "go_to_line", "gpui", + "gpui_platform", "gpui_tokio", "http_client", "image", diff --git a/Cargo.toml b/Cargo.toml index fd4962e74928d7d13fbeeab5ce17b0a7b1ba4e59..2eae224ffb4377c13d38674437ce011ac5d03d20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,7 +83,12 @@ members = [ "crates/go_to_line", "crates/google_ai", "crates/gpui", + "crates/gpui_linux", + "crates/gpui_macos", "crates/gpui_macros", + "crates/gpui_platform", + "crates/gpui_wgpu", + "crates/gpui_windows", "crates/gpui_tokio", "crates/html_to_markdown", "crates/http_client", @@ -321,7 +326,12 @@ git_ui = { path = "crates/git_ui" } go_to_line = { path = "crates/go_to_line" } google_ai = { path = "crates/google_ai" } gpui = { path = "crates/gpui", default-features = false } +gpui_linux = { path = "crates/gpui_linux", default-features = false } +gpui_macos = { path = "crates/gpui_macos", default-features = false } gpui_macros = { path = "crates/gpui_macros" } +gpui_platform = { path = "crates/gpui_platform", default-features = false } +gpui_wgpu = { path = "crates/gpui_wgpu" } +gpui_windows = { path = "crates/gpui_windows", default-features = false } gpui_tokio = { path = "crates/gpui_tokio" } html_to_markdown = { path = "crates/html_to_markdown" } http_client = { path = "crates/http_client" } @@ -819,6 +829,8 @@ codegen-units = 16 # (without this cargo will compile ~400 crates twice) [profile.dev.build-override] codegen-units = 16 +split-debuginfo = "unpacked" +debug = true [profile.dev.package] # proc-macros start diff --git a/crates/component_preview/Cargo.toml b/crates/component_preview/Cargo.toml index d7ca3bad47d74d86c701007da879ddf092a08b73..3bfbdcf2979ebca34a80c9d8703813c40a20387b 100644 --- a/crates/component_preview/Cargo.toml +++ b/crates/component_preview/Cargo.toml @@ -13,7 +13,6 @@ path = "src/component_preview.rs" [features] default = [] -preview = [] test-support = ["db/test-support"] [dependencies] @@ -39,7 +38,9 @@ ui_input.workspace = true uuid.workspace = true workspace.workspace = true +[dev-dependencies] +gpui_platform = { workspace = true, features = ["screen-capture"] } + [[example]] name = "component_preview" path = "examples/component_preview.rs" -required-features = ["preview"] diff --git a/crates/component_preview/examples/component_preview.rs b/crates/component_preview/examples/component_preview.rs index a49110e91ee76fef8b6f69048153f47493e52097..3859ff6803c79a176bc733af156e1304bbc5f61e 100644 --- a/crates/component_preview/examples/component_preview.rs +++ b/crates/component_preview/examples/component_preview.rs @@ -1,18 +1,143 @@ //! Component Preview Example //! -//! Run with: `cargo run -p component_preview --example component_preview --features="preview"` -//! -//! To use this in other projects, add the following to your `Cargo.toml`: -//! -//! ```toml -//! [dependencies] -//! component_preview = { path = "../component_preview", features = ["preview"] } -//! -//! [[example]] -//! name = "component_preview" -//! path = "examples/component_preview.rs" -//! ``` +//! Run with: `cargo run -p component_preview --example component_preview"` +use fs::RealFs; +use gpui::{AppContext as _, Bounds, KeyBinding, WindowBounds, WindowOptions, actions, size}; + +use client::{Client, UserStore}; +use language::LanguageRegistry; +use node_runtime::NodeRuntime; +use project::Project; +use reqwest_client::ReqwestClient; +use session::{AppSession, Session}; +use std::sync::Arc; +use ui::{App, px}; +use workspace::{AppState, Workspace, WorkspaceStore}; + +use component_preview::{ComponentPreview, init}; + +actions!(zed, [Quit]); + +fn quit(_: &Quit, cx: &mut App) { + cx.quit(); +} fn main() { - component_preview::run_component_preview(); + gpui_platform::application().run(|cx| { + component::init(); + + cx.on_action(quit); + cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]); + let version = release_channel::AppVersion::load(env!("CARGO_PKG_VERSION"), None, None); + release_channel::init(version, cx); + + let http_client = + ReqwestClient::user_agent("component_preview").expect("Failed to create HTTP client"); + cx.set_http_client(Arc::new(http_client)); + + let fs = Arc::new(RealFs::new(None, cx.background_executor().clone())); + ::set_global(fs.clone(), cx); + + settings::init(cx); + theme::init(theme::LoadThemes::JustBase, cx); + + let languages = Arc::new(LanguageRegistry::new(cx.background_executor().clone())); + let client = Client::production(cx); + client::init(&client, cx); + + let user_store = cx.new(|cx| UserStore::new(client.clone(), cx)); + let workspace_store = cx.new(|cx| WorkspaceStore::new(client.clone(), cx)); + let session_id = uuid::Uuid::new_v4().to_string(); + let session = cx.foreground_executor().block_on(Session::new(session_id)); + let session = cx.new(|cx| AppSession::new(session, cx)); + let node_runtime = NodeRuntime::unavailable(); + + let app_state = Arc::new(AppState { + languages, + client, + user_store, + workspace_store, + fs, + build_window_options: |_, _| Default::default(), + node_runtime, + session, + }); + AppState::set_global(Arc::downgrade(&app_state), cx); + + workspace::init(app_state.clone(), cx); + init(app_state.clone(), cx); + + let size = size(px(1200.), px(800.)); + let bounds = Bounds::centered(None, size, cx); + + cx.open_window( + WindowOptions { + window_bounds: Some(WindowBounds::Windowed(bounds)), + ..Default::default() + }, + { + move |window, cx| { + let app_state = app_state; + theme::setup_ui_font(window, cx); + + let project = Project::local( + app_state.client.clone(), + app_state.node_runtime.clone(), + app_state.user_store.clone(), + app_state.languages.clone(), + app_state.fs.clone(), + None, + project::LocalProjectFlags { + init_worktree_trust: false, + ..Default::default() + }, + cx, + ); + + let workspace = cx.new(|cx| { + Workspace::new( + Default::default(), + project.clone(), + app_state.clone(), + window, + cx, + ) + }); + + workspace.update(cx, |workspace, cx| { + let weak_workspace = cx.entity().downgrade(); + let language_registry = app_state.languages.clone(); + let user_store = app_state.user_store.clone(); + + let component_preview = cx.new(|cx| { + ComponentPreview::new( + weak_workspace, + project, + language_registry, + user_store, + None, + None, + window, + cx, + ) + .expect("Failed to create component preview") + }); + + workspace.add_item_to_active_pane( + Box::new(component_preview), + None, + true, + window, + cx, + ); + }); + + workspace + } + }, + ) + .expect("Failed to open component preview window"); + + cx.activate(true); + }); } diff --git a/crates/component_preview/src/component_preview.rs b/crates/component_preview/src/component_preview.rs index ba00db3f9b11ddb2e4f516551fa3112042aaf4ca..640b243b73e4cf6042bb7c81a8869b0ffb64230b 100644 --- a/crates/component_preview/src/component_preview.rs +++ b/crates/component_preview/src/component_preview.rs @@ -1,4 +1,3 @@ -mod component_preview_example; mod persistence; use client::UserStore; @@ -20,9 +19,6 @@ use workspace::{ Item, ItemId, SerializableItem, Workspace, WorkspaceId, delete_unloaded_items, item::ItemEvent, }; -#[allow(unused_imports)] -pub use component_preview_example::*; - pub fn init(app_state: Arc, cx: &mut App) { workspace::register_serializable_item::(cx); @@ -85,13 +81,13 @@ impl From for PreviewEntry { } #[derive(Default, Debug, Clone, PartialEq, Eq)] -enum PreviewPage { +pub enum PreviewPage { #[default] AllComponents, Component(ComponentId), } -struct ComponentPreview { +pub struct ComponentPreview { active_page: PreviewPage, reset_key: usize, component_list: ListState, diff --git a/crates/component_preview/src/component_preview_example.rs b/crates/component_preview/src/component_preview_example.rs deleted file mode 100644 index 6f2235e88a62be37f0aaadceea042c45dd2133be..0000000000000000000000000000000000000000 --- a/crates/component_preview/src/component_preview_example.rs +++ /dev/null @@ -1,148 +0,0 @@ -/// Run the component preview application. -/// -/// This initializes the application with minimal required infrastructure -/// and opens a workspace with the ComponentPreview item. -#[cfg(feature = "preview")] -pub fn run_component_preview() { - use fs::RealFs; - use gpui::{ - AppContext as _, Application, Bounds, KeyBinding, WindowBounds, WindowOptions, actions, - size, - }; - - use client::{Client, UserStore}; - use language::LanguageRegistry; - use node_runtime::NodeRuntime; - use project::Project; - use reqwest_client::ReqwestClient; - use session::{AppSession, Session}; - use std::sync::Arc; - use ui::{App, px}; - use workspace::{AppState, Workspace, WorkspaceStore}; - - use crate::{ComponentPreview, init}; - - actions!(zed, [Quit]); - - fn quit(_: &Quit, cx: &mut App) { - cx.quit(); - } - - Application::new().run(|cx| { - component::init(); - - cx.on_action(quit); - cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]); - let version = release_channel::AppVersion::load(env!("CARGO_PKG_VERSION"), None, None); - release_channel::init(version, cx); - - let http_client = - ReqwestClient::user_agent("component_preview").expect("Failed to create HTTP client"); - cx.set_http_client(Arc::new(http_client)); - - let fs = Arc::new(RealFs::new(None, cx.background_executor().clone())); - ::set_global(fs.clone(), cx); - - settings::init(cx); - theme::init(theme::LoadThemes::JustBase, cx); - - let languages = Arc::new(LanguageRegistry::new(cx.background_executor().clone())); - let client = Client::production(cx); - client::init(&client, cx); - - let user_store = cx.new(|cx| UserStore::new(client.clone(), cx)); - let workspace_store = cx.new(|cx| WorkspaceStore::new(client.clone(), cx)); - let session_id = uuid::Uuid::new_v4().to_string(); - let session = cx.foreground_executor().block_on(Session::new(session_id)); - let session = cx.new(|cx| AppSession::new(session, cx)); - let node_runtime = NodeRuntime::unavailable(); - - let app_state = Arc::new(AppState { - languages, - client, - user_store, - workspace_store, - fs, - build_window_options: |_, _| Default::default(), - node_runtime, - session, - }); - AppState::set_global(Arc::downgrade(&app_state), cx); - - workspace::init(app_state.clone(), cx); - init(app_state.clone(), cx); - - let size = size(px(1200.), px(800.)); - let bounds = Bounds::centered(None, size, cx); - - cx.open_window( - WindowOptions { - window_bounds: Some(WindowBounds::Windowed(bounds)), - ..Default::default() - }, - { - move |window, cx| { - let app_state = app_state; - theme::setup_ui_font(window, cx); - - let project = Project::local( - app_state.client.clone(), - app_state.node_runtime.clone(), - app_state.user_store.clone(), - app_state.languages.clone(), - app_state.fs.clone(), - None, - project::LocalProjectFlags { - init_worktree_trust: false, - ..Default::default() - }, - cx, - ); - - let workspace = cx.new(|cx| { - Workspace::new( - Default::default(), - project.clone(), - app_state.clone(), - window, - cx, - ) - }); - - workspace.update(cx, |workspace, cx| { - let weak_workspace = cx.entity().downgrade(); - let language_registry = app_state.languages.clone(); - let user_store = app_state.user_store.clone(); - - let component_preview = cx.new(|cx| { - ComponentPreview::new( - weak_workspace, - project, - language_registry, - user_store, - None, - None, - window, - cx, - ) - .expect("Failed to create component preview") - }); - - workspace.add_item_to_active_pane( - Box::new(component_preview), - None, - true, - window, - cx, - ); - }); - - workspace - } - }, - ) - .expect("Failed to open component preview window"); - - cx.activate(true); - }); -} diff --git a/crates/edit_prediction_cli/Cargo.toml b/crates/edit_prediction_cli/Cargo.toml index df5d742a3bb90d7e20a9cf6b4bd84314b14e206e..82ddfe504aa7519597696c2b13531b0e14cfcda3 100644 --- a/crates/edit_prediction_cli/Cargo.toml +++ b/crates/edit_prediction_cli/Cargo.toml @@ -27,6 +27,7 @@ extension.workspace = true fs.workspace = true futures.workspace = true gpui.workspace = true +gpui_platform.workspace = true gpui_tokio.workspace = true indoc.workspace = true language.workspace = true diff --git a/crates/edit_prediction_cli/src/main.rs b/crates/edit_prediction_cli/src/main.rs index e08fb62090ed4d09fc408ced6a684ed0ffad2233..e62350b6da7ff55833664c17fce32cb32cf4dd36 100644 --- a/crates/edit_prediction_cli/src/main.rs +++ b/crates/edit_prediction_cli/src/main.rs @@ -31,7 +31,7 @@ use collections::HashSet; use edit_prediction::EditPredictionStore; use futures::channel::mpsc; use futures::{SinkExt as _, StreamExt as _}; -use gpui::{AppContext as _, Application, BackgroundExecutor, Task}; +use gpui::{AppContext as _, BackgroundExecutor, Task}; use zeta_prompt::ZetaFormat; use reqwest_client::ReqwestClient; @@ -851,7 +851,7 @@ fn main() { } let http_client = Arc::new(ReqwestClient::new()); - let app = Application::headless().with_http_client(http_client); + let app = gpui_platform::headless().with_http_client(http_client); app.run(move |cx| { let app_state = Arc::new(headless::init(cx)); diff --git a/crates/eval/Cargo.toml b/crates/eval/Cargo.toml index 30908be1e2fde15c0c32894b266d971b7f0ca54f..a8917181a1253dea614a02bfaa799ace0ee6ba64 100644 --- a/crates/eval/Cargo.toml +++ b/crates/eval/Cargo.toml @@ -38,6 +38,7 @@ extension.workspace = true fs.workspace = true futures.workspace = true gpui.workspace = true +gpui_platform.workspace = true gpui_tokio.workspace = true handlebars.workspace = true language.workspace = true diff --git a/crates/eval/src/eval.rs b/crates/eval/src/eval.rs index ac773bab786223fb073a5a87118ec0304e1781bf..4e9a0cb7915d8369c7989ca332a01ff12f86cefe 100644 --- a/crates/eval/src/eval.rs +++ b/crates/eval/src/eval.rs @@ -18,7 +18,7 @@ use collections::{HashMap, HashSet}; use extension::ExtensionHostProxy; use futures::future; use gpui::http_client::read_proxy_from_env; -use gpui::{App, AppContext, Application, AsyncApp, Entity, UpdateGlobal}; +use gpui::{App, AppContext, AsyncApp, Entity, UpdateGlobal}; use gpui_tokio::Tokio; use language::LanguageRegistry; use language_model::{ConfiguredModel, LanguageModel, LanguageModelRegistry, SelectedModel}; @@ -114,7 +114,7 @@ fn main() { let languages: HashSet = args.languages.into_iter().collect(); let http_client = Arc::new(ReqwestClient::new()); - let app = Application::headless().with_http_client(http_client); + let app = gpui_platform::headless().with_http_client(http_client); let all_threads = examples::all(&examples_dir); app.run(move |cx| { diff --git a/crates/eval_utils/Cargo.toml b/crates/eval_utils/Cargo.toml index a512035f5d1754f0f6f942faa27d063e169a22ef..479e146b998f0e457bc95a0557a922e99d037e5d 100644 --- a/crates/eval_utils/Cargo.toml +++ b/crates/eval_utils/Cargo.toml @@ -13,6 +13,6 @@ path = "src/eval_utils.rs" doctest = false [dependencies] -gpui.workspace = true +gpui_platform.workspace = true serde.workspace = true smol.workspace = true diff --git a/crates/eval_utils/src/eval_utils.rs b/crates/eval_utils/src/eval_utils.rs index be3294ed1490d6a602c3a5282d25dbba7d065443..7705e0f2cf50857a522d1ca6d0fd0e8d7a8c2ea6 100644 --- a/crates/eval_utils/src/eval_utils.rs +++ b/crates/eval_utils/src/eval_utils.rs @@ -82,7 +82,7 @@ pub fn eval

( let (tx, rx) = mpsc::channel(); - let executor = gpui::background_executor(); + let executor = gpui_platform::background_executor(); let semaphore = Arc::new(smol::lock::Semaphore::new(32)); let evalf = Arc::new(evalf); // Warm the cache once diff --git a/crates/extension_cli/Cargo.toml b/crates/extension_cli/Cargo.toml index 2c780c41a63212d2a87dd74a28a17164ed0bff3f..9795c13e75864184299fba026f499bbcbefee117 100644 --- a/crates/extension_cli/Cargo.toml +++ b/crates/extension_cli/Cargo.toml @@ -19,7 +19,7 @@ cloud_api_types.workspace = true env_logger.workspace = true extension.workspace = true fs.workspace = true -gpui.workspace = true +gpui_platform.workspace = true language.workspace = true log.workspace = true reqwest_client.workspace = true diff --git a/crates/extension_cli/src/main.rs b/crates/extension_cli/src/main.rs index 5ead773ba2ca229dabac0248c01ee3518d73f47f..baefb72fe4bd986edbfaa866e50663b159eff3c9 100644 --- a/crates/extension_cli/src/main.rs +++ b/crates/extension_cli/src/main.rs @@ -35,7 +35,7 @@ async fn main() -> Result<()> { env_logger::init(); let args = Args::parse(); - let fs = Arc::new(RealFs::new(None, gpui::background_executor())); + let fs = Arc::new(RealFs::new(None, gpui_platform::background_executor())); let engine = wasmtime::Engine::default(); let mut wasm_store = WasmStore::new(&engine)?; diff --git a/crates/fs_benchmarks/Cargo.toml b/crates/fs_benchmarks/Cargo.toml index f207a2db3b7354ca96347aaffb5c1915a514ef7c..c597ec6469e88f7e4394a1d6071c8b3c0f97248e 100644 --- a/crates/fs_benchmarks/Cargo.toml +++ b/crates/fs_benchmarks/Cargo.toml @@ -6,7 +6,8 @@ edition.workspace = true [dependencies] fs.workspace = true -gpui = {workspace = true, features = ["windows-manifest"]} +gpui.workspace = true +gpui_platform.workspace = true [lints] workspace = true diff --git a/crates/fs_benchmarks/src/main.rs b/crates/fs_benchmarks/src/main.rs index 12df32f0763e02a95c3f261d2c14fa6e295c304e..471492ad6878052d82cbc90fe0dcba4a7dcea856 100644 --- a/crates/fs_benchmarks/src/main.rs +++ b/crates/fs_benchmarks/src/main.rs @@ -1,12 +1,14 @@ use fs::Fs; -use gpui::{AppContext, Application}; +use gpui::AppContext; +use gpui_platform::headless; + fn main() { let Some(path_to_read) = std::env::args().nth(1) else { println!("Expected path to read as 1st argument."); return; }; - let _ = Application::headless().run(|cx| { + let _ = headless().run(|cx| { let fs = fs::RealFs::new(None, cx.background_executor().clone()); cx.background_spawn(async move { let timer = std::time::Instant::now(); diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 120cd00d3552cab59103c66bcbf3cff9e6b3e599..5a163c11ecccb76a0fe1cc4f3d08ed20f7dcafe0 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -31,37 +31,8 @@ leak-detection = ["backtrace"] runtime_shaders = [] wayland = [ "bitflags", - "wgpu", - "bytemuck", - "ashpd/wayland", - "cosmic-text", - "font-kit", - "calloop-wayland-source", - "wayland-backend", - "wayland-client", - "wayland-cursor", - "wayland-protocols", - "wayland-protocols-plasma", - "wayland-protocols-wlr", - "filedescriptor", - "xkbcommon", - "open", -] -x11 = [ - "wgpu", - "bytemuck", - "ashpd", - "cosmic-text", - "font-kit", - "as-raw-xcb-connection", - "x11rb", - "xkbcommon", - "xim", - "x11-clipboard", - "filedescriptor", - "open", - "scap?/x11", ] +x11 = [] screen-capture = [ "scap", ] @@ -76,7 +47,7 @@ anyhow.workspace = true async-task = "4.7" backtrace = { workspace = true, optional = true } bitflags = { workspace = true, optional = true } -bytemuck = { version = "1", optional = true } + collections.workspace = true ctor.workspace = true derive_more.workspace = true @@ -107,7 +78,6 @@ usvg = { version = "0.45.0", default-features = false } util_macros.workspace = true schemars.workspace = true seahash = "4.1" -semver.workspace = true serde.workspace = true serde_json.workspace = true slotmap.workspace = true @@ -122,7 +92,6 @@ util.workspace = true uuid.workspace = true waker-fn = "1.2.0" lyon = "1.0" -libc.workspace = true pin-project = "1.1.10" circular-buffer.workspace = true spin = "0.10.0" @@ -154,76 +123,17 @@ pathfinder_geometry = "0.5" [target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os = "windows"))'.dependencies] scap = { workspace = true, optional = true } -[target.'cfg(any(target_os = "linux", target_os = "freebsd"))'.dependencies] -# Always used -oo7 = { version = "0.5.0", default-features = false, features = [ - "async-std", - "native_crypto", -] } -# Used in both windowing options -ashpd = { workspace = true, optional = true } -wgpu = { workspace = true, optional = true } -cosmic-text = { version = "0.17.0", optional = true } -swash = { version = "0.2.6" } -# WARNING: If you change this, you must also publish a new version of zed-font-kit to crates.io -font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "110523127440aefb11ce0cf280ae7c5071337ec5", package = "zed-font-kit", version = "0.14.1-zed", features = [ - "source-fontconfig-dlopen", -], optional = true } -calloop = "0.14.3" -filedescriptor = { version = "0.8.2", optional = true } -open = { version = "5.2.0", optional = true } -xkbcommon = { version = "0.8.0", features = ["wayland", "x11"], optional = true } - -# Wayland -calloop-wayland-source = { version = "0.4.1", optional = true } -wayland-backend = { version = "0.3.3", features = [ - "client_system", - "dlopen", -], optional = true } -wayland-client = { version = "0.31.11", optional = true } -wayland-cursor = { version = "0.31.11", optional = true } -wayland-protocols = { version = "0.32.9", features = [ - "client", - "staging", - "unstable", -], optional = true } -wayland-protocols-plasma = { version = "0.3.9", features = [ - "client", -], optional = true } -wayland-protocols-wlr = { version = "0.3.9", features = [ - "client", -], optional = true } - -# X11 -as-raw-xcb-connection = { version = "1", optional = true } -x11rb = { version = "0.13.1", features = [ - "allow-unsafe-code", - "xkb", - "randr", - "xinput", - "cursor", - "resource_manager", - "sync", -], optional = true } -# WARNING: If you change this, you must also publish a new version of zed-xim to crates.io -xim = { git = "https://github.com/zed-industries/xim-rs.git", rev = "16f35a2c881b815a2b6cdfd6687988e84f8447d8" , features = [ - "x11rb-xcb", - "x11rb-client", -], package = "zed-xim", version = "0.4.0-zed", optional = true } -x11-clipboard = { version = "0.9.3", optional = true } [target.'cfg(target_os = "windows")'.dependencies] -rand.workspace = true -windows.workspace = true -windows-core.workspace = true -windows-numerics = "0.2" -windows-registry = "0.5" +windows = { version = "0.61", features = ["Win32_Foundation"] } + [dev-dependencies] backtrace.workspace = true collections = { workspace = true, features = ["test-support"] } env_logger.workspace = true +gpui_platform.workspace = true http_client = { workspace = true, features = ["test-support"] } lyon = { version = "1.0", features = ["extra"] } pretty_assertions.workspace = true @@ -233,17 +143,17 @@ scheduler = { workspace = true, features = ["test-support"] } unicode-segmentation.workspace = true util = { workspace = true, features = ["test-support"] } + + [target.'cfg(target_os = "windows")'.build-dependencies] embed-resource = "3.0" -windows-registry = "0.5" [target.'cfg(target_os = "macos")'.build-dependencies] bindgen = "0.71" cbindgen = { version = "0.28.0", default-features = false } naga.workspace = true -[target.'cfg(any(target_os = "linux", target_os = "freebsd"))'.build-dependencies] -naga.workspace = true + [[example]] diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index 9363128fc26d7a87f2242e38d0e8a30ed72b3b0e..53f78e3c416d27d73d8593ef1315c4f943712715 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -1,463 +1,20 @@ #![allow(clippy::disallowed_methods, reason = "build scripts are exempt")] #![cfg_attr(not(target_os = "macos"), allow(unused))] -use std::env; - fn main() { - let target = env::var("CARGO_CFG_TARGET_OS"); println!("cargo::rustc-check-cfg=cfg(gles)"); - match target.as_deref() { - Ok("macos") => { - #[cfg(target_os = "macos")] - macos::build(); - } - Ok("windows") => { - #[cfg(target_os = "windows")] - windows::build(); - } - _ => (), - }; + #[cfg(all(target_os = "windows", feature = "windows-manifest"))] + embed_resource(); } -#[cfg(target_os = "macos")] -mod macos { - use std::{ - env, - path::{Path, PathBuf}, - }; - - use cbindgen::Config; - - pub(super) fn build() { - generate_dispatch_bindings(); - - let header_path = generate_shader_bindings(); - - #[cfg(feature = "runtime_shaders")] - emit_stitched_shaders(&header_path); - #[cfg(not(feature = "runtime_shaders"))] - compile_metal_shaders(&header_path); - } - - fn generate_dispatch_bindings() { - println!("cargo:rustc-link-lib=framework=System"); - - let bindings = bindgen::Builder::default() - .header("src/platform/mac/dispatch.h") - .allowlist_var("_dispatch_main_q") - .allowlist_var("_dispatch_source_type_data_add") - .allowlist_var("DISPATCH_QUEUE_PRIORITY_HIGH") - .allowlist_var("DISPATCH_QUEUE_PRIORITY_DEFAULT") - .allowlist_var("DISPATCH_QUEUE_PRIORITY_LOW") - .allowlist_var("DISPATCH_TIME_NOW") - .allowlist_function("dispatch_get_global_queue") - .allowlist_function("dispatch_async_f") - .allowlist_function("dispatch_after_f") - .allowlist_function("dispatch_time") - .allowlist_function("dispatch_source_merge_data") - .allowlist_function("dispatch_source_create") - .allowlist_function("dispatch_source_set_event_handler_f") - .allowlist_function("dispatch_resume") - .allowlist_function("dispatch_suspend") - .allowlist_function("dispatch_source_cancel") - .allowlist_function("dispatch_set_context") - .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) - .layout_tests(false) - .generate() - .expect("unable to generate bindings"); - - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - bindings - .write_to_file(out_path.join("dispatch_sys.rs")) - .expect("couldn't write dispatch bindings"); - } - - fn generate_shader_bindings() -> PathBuf { - let output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("scene.h"); - let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - let mut config = Config { - include_guard: Some("SCENE_H".into()), - language: cbindgen::Language::C, - no_includes: true, - ..Default::default() - }; - config.export.include.extend([ - "Bounds".into(), - "Corners".into(), - "Edges".into(), - "Size".into(), - "Pixels".into(), - "PointF".into(), - "Hsla".into(), - "ContentMask".into(), - "Uniforms".into(), - "AtlasTile".into(), - "PathRasterizationInputIndex".into(), - "PathVertex_ScaledPixels".into(), - "PathRasterizationVertex".into(), - "ShadowInputIndex".into(), - "Shadow".into(), - "QuadInputIndex".into(), - "Underline".into(), - "UnderlineInputIndex".into(), - "Quad".into(), - "BorderStyle".into(), - "SpriteInputIndex".into(), - "MonochromeSprite".into(), - "PolychromeSprite".into(), - "PathSprite".into(), - "SurfaceInputIndex".into(), - "SurfaceBounds".into(), - "TransformationMatrix".into(), - ]); - config.no_includes = true; - config.enumeration.prefix_with_name = true; - - let mut builder = cbindgen::Builder::new(); - - let src_paths = [ - crate_dir.join("src/scene.rs"), - crate_dir.join("src/geometry.rs"), - crate_dir.join("src/color.rs"), - crate_dir.join("src/window.rs"), - crate_dir.join("src/platform.rs"), - crate_dir.join("src/platform/mac/metal_renderer.rs"), - ]; - for src_path in src_paths { - println!("cargo:rerun-if-changed={}", src_path.display()); - builder = builder.with_src(src_path); - } - - builder - .with_config(config) - .generate() - .expect("Unable to generate bindings") - .write_to_file(&output_path); - - output_path - } - - /// To enable runtime compilation, we need to "stitch" the shaders file with the generated header - /// so that it is self-contained. - #[cfg(feature = "runtime_shaders")] - fn emit_stitched_shaders(header_path: &Path) { - use std::str::FromStr; - fn stitch_header(header: &Path, shader_path: &Path) -> std::io::Result { - let header_contents = std::fs::read_to_string(header)?; - let shader_contents = std::fs::read_to_string(shader_path)?; - let stitched_contents = format!("{header_contents}\n{shader_contents}"); - let out_path = - PathBuf::from(env::var("OUT_DIR").unwrap()).join("stitched_shaders.metal"); - std::fs::write(&out_path, stitched_contents)?; - Ok(out_path) - } - let shader_source_path = "./src/platform/mac/shaders.metal"; - let shader_path = PathBuf::from_str(shader_source_path).unwrap(); - stitch_header(header_path, &shader_path).unwrap(); - println!("cargo:rerun-if-changed={}", &shader_source_path); - } - - #[cfg(not(feature = "runtime_shaders"))] - fn compile_metal_shaders(header_path: &Path) { - use std::process::{self, Command}; - let shader_path = "./src/platform/mac/shaders.metal"; - let air_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.air"); - let metallib_output_path = - PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.metallib"); - println!("cargo:rerun-if-changed={}", shader_path); - - let output = Command::new("xcrun") - .args([ - "-sdk", - "macosx", - "metal", - "-gline-tables-only", - "-mmacosx-version-min=10.15.7", - "-MO", - "-c", - shader_path, - "-include", - (header_path.to_str().unwrap()), - "-o", - ]) - .arg(&air_output_path) - .output() - .unwrap(); - - if !output.status.success() { - println!( - "cargo::error=metal shader compilation failed:\n{}", - String::from_utf8_lossy(&output.stderr) - ); - process::exit(1); - } - - let output = Command::new("xcrun") - .args(["-sdk", "macosx", "metallib"]) - .arg(air_output_path) - .arg("-o") - .arg(metallib_output_path) - .output() - .unwrap(); - - if !output.status.success() { - println!( - "cargo::error=metallib compilation failed:\n{}", - String::from_utf8_lossy(&output.stderr) - ); - process::exit(1); - } - } -} - -#[cfg(target_os = "windows")] -mod windows { - use std::{ - ffi::OsString, - fs, - io::Write, - path::{Path, PathBuf}, - process::{self, Command}, - }; - - pub(super) fn build() { - // Compile HLSL shaders - #[cfg(not(debug_assertions))] - compile_shaders(); - - // Embed the Windows manifest and resource file - #[cfg(feature = "windows-manifest")] - embed_resource(); - } - - #[cfg(feature = "windows-manifest")] - fn embed_resource() { - let manifest = std::path::Path::new("resources/windows/gpui.manifest.xml"); - let rc_file = std::path::Path::new("resources/windows/gpui.rc"); - println!("cargo:rerun-if-changed={}", manifest.display()); - println!("cargo:rerun-if-changed={}", rc_file.display()); - embed_resource::compile(rc_file, embed_resource::NONE) - .manifest_required() - .unwrap(); - } - - /// You can set the `GPUI_FXC_PATH` environment variable to specify the path to the fxc.exe compiler. - fn compile_shaders() { - let shader_path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()) - .join("src/platform/windows/shaders.hlsl"); - let out_dir = std::env::var("OUT_DIR").unwrap(); - - println!("cargo:rerun-if-changed={}", shader_path.display()); - - // Check if fxc.exe is available - let fxc_path = find_fxc_compiler(); - - // Define all modules - let modules = [ - "quad", - "shadow", - "path_rasterization", - "path_sprite", - "underline", - "monochrome_sprite", - "subpixel_sprite", - "polychrome_sprite", - ]; - - let rust_binding_path = format!("{}/shaders_bytes.rs", out_dir); - if Path::new(&rust_binding_path).exists() { - fs::remove_file(&rust_binding_path) - .expect("Failed to remove existing Rust binding file"); - } - for module in modules { - compile_shader_for_module( - module, - &out_dir, - &fxc_path, - shader_path.to_str().unwrap(), - &rust_binding_path, - ); - } - - { - let shader_path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()) - .join("src/platform/windows/color_text_raster.hlsl"); - compile_shader_for_module( - "emoji_rasterization", - &out_dir, - &fxc_path, - shader_path.to_str().unwrap(), - &rust_binding_path, - ); - } - } - - /// Locate `binary` in the newest installed Windows SDK. - pub fn find_latest_windows_sdk_binary( - binary: &str, - ) -> Result, Box> { - let key = windows_registry::LOCAL_MACHINE - .open("SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0")?; - - let install_folder: String = key.get_string("InstallationFolder")?; // "C:\Program Files (x86)\Windows Kits\10\" - let install_folder_bin = Path::new(&install_folder).join("bin"); - - let mut versions: Vec<_> = std::fs::read_dir(&install_folder_bin)? - .flatten() - .filter(|entry| entry.path().is_dir()) - .filter_map(|entry| entry.file_name().into_string().ok()) - .collect(); - - versions.sort_by_key(|s| { - s.split('.') - .filter_map(|p| p.parse().ok()) - .collect::>() - }); - - let arch = match std::env::consts::ARCH { - "x86_64" => "x64", - "aarch64" => "arm64", - _ => Err(format!( - "Unsupported architecture: {}", - std::env::consts::ARCH - ))?, - }; - - if let Some(highest_version) = versions.last() { - return Ok(Some( - install_folder_bin - .join(highest_version) - .join(arch) - .join(binary), - )); - } - - Ok(None) - } - - /// You can set the `GPUI_FXC_PATH` environment variable to specify the path to the fxc.exe compiler. - fn find_fxc_compiler() -> String { - // Check environment variable - if let Ok(path) = std::env::var("GPUI_FXC_PATH") - && Path::new(&path).exists() - { - return path; - } - - // Try to find in PATH - // NOTE: This has to be `where.exe` on Windows, not `where`, it must be ended with `.exe` - if let Ok(output) = std::process::Command::new("where.exe") - .arg("fxc.exe") - .output() - && output.status.success() - { - let path = String::from_utf8_lossy(&output.stdout); - return path.trim().to_string(); - } - - if let Ok(Some(path)) = find_latest_windows_sdk_binary("fxc.exe") { - return path.to_string_lossy().into_owned(); - } - - panic!("Failed to find fxc.exe"); - } - - fn compile_shader_for_module( - module: &str, - out_dir: &str, - fxc_path: &str, - shader_path: &str, - rust_binding_path: &str, - ) { - // Compile vertex shader - let output_file = format!("{}/{}_vs.h", out_dir, module); - let const_name = format!("{}_VERTEX_BYTES", module.to_uppercase()); - compile_shader_impl( - fxc_path, - &format!("{module}_vertex"), - &output_file, - &const_name, - shader_path, - "vs_4_1", - ); - generate_rust_binding(&const_name, &output_file, rust_binding_path); - - // Compile fragment shader - let output_file = format!("{}/{}_ps.h", out_dir, module); - let const_name = format!("{}_FRAGMENT_BYTES", module.to_uppercase()); - compile_shader_impl( - fxc_path, - &format!("{module}_fragment"), - &output_file, - &const_name, - shader_path, - "ps_4_1", - ); - generate_rust_binding(&const_name, &output_file, rust_binding_path); - } - - fn compile_shader_impl( - fxc_path: &str, - entry_point: &str, - output_path: &str, - var_name: &str, - shader_path: &str, - target: &str, - ) { - let output = Command::new(fxc_path) - .args([ - "/T", - target, - "/E", - entry_point, - "/Fh", - output_path, - "/Vn", - var_name, - "/O3", - shader_path, - ]) - .output(); - - match output { - Ok(result) => { - if result.status.success() { - return; - } - println!( - "cargo::error=Shader compilation failed for {}:\n{}", - entry_point, - String::from_utf8_lossy(&result.stderr) - ); - process::exit(1); - } - Err(e) => { - println!("cargo::error=Failed to run fxc for {}: {}", entry_point, e); - process::exit(1); - } - } - } - fn generate_rust_binding(const_name: &str, head_file: &str, output_path: &str) { - let header_content = fs::read_to_string(head_file).expect("Failed to read header file"); - let const_definition = { - let global_var_start = header_content.find("const BYTE").unwrap(); - let global_var = &header_content[global_var_start..]; - let equal = global_var.find('=').unwrap(); - global_var[equal + 1..].trim() - }; - let rust_binding = format!( - "const {}: &[u8] = &{}\n", - const_name, - const_definition.replace('{', "[").replace('}', "]") - ); - let mut options = fs::OpenOptions::new() - .create(true) - .append(true) - .open(output_path) - .expect("Failed to open Rust binding file"); - options - .write_all(rust_binding.as_bytes()) - .expect("Failed to write Rust binding file"); - } +#[cfg(all(target_os = "windows", feature = "windows-manifest"))] +fn embed_resource() { + let manifest = std::path::Path::new("resources/windows/gpui.manifest.xml"); + let rc_file = std::path::Path::new("resources/windows/gpui.rc"); + println!("cargo:rerun-if-changed={}", manifest.display()); + println!("cargo:rerun-if-changed={}", rc_file.display()); + embed_resource::compile(rc_file, embed_resource::NONE) + .manifest_required() + .unwrap(); } diff --git a/crates/gpui/examples/animation.rs b/crates/gpui/examples/animation.rs index 16d6e1b269975f61316fa35880d5d3924790fed1..27a9a0fa35152dfdcd02df207af4fd1f78ec2b7c 100644 --- a/crates/gpui/examples/animation.rs +++ b/crates/gpui/examples/animation.rs @@ -2,10 +2,11 @@ use std::time::Duration; use anyhow::Result; use gpui::{ - Animation, AnimationExt as _, App, Application, AssetSource, Bounds, Context, SharedString, - Transformation, Window, WindowBounds, WindowOptions, bounce, div, ease_in_out, percentage, - prelude::*, px, size, svg, + Animation, AnimationExt as _, App, AssetSource, Bounds, Context, SharedString, Transformation, + Window, WindowBounds, WindowOptions, bounce, div, ease_in_out, percentage, prelude::*, px, + size, svg, }; +use gpui_platform::application; struct Assets {} @@ -101,21 +102,19 @@ impl Render for AnimationExample { } fn main() { - Application::new() - .with_assets(Assets {}) - .run(|cx: &mut App| { - let options = WindowOptions { - window_bounds: Some(WindowBounds::Windowed(Bounds::centered( - None, - size(px(300.), px(300.)), - cx, - ))), - ..Default::default() - }; - cx.open_window(options, |_, cx| { - cx.activate(false); - cx.new(|_| AnimationExample {}) - }) - .unwrap(); - }); + application().with_assets(Assets {}).run(|cx: &mut App| { + let options = WindowOptions { + window_bounds: Some(WindowBounds::Windowed(Bounds::centered( + None, + size(px(300.), px(300.)), + cx, + ))), + ..Default::default() + }; + cx.open_window(options, |_, cx| { + cx.activate(false); + cx.new(|_| AnimationExample {}) + }) + .unwrap(); + }); } diff --git a/crates/gpui/examples/data_table.rs b/crates/gpui/examples/data_table.rs index dd1a443a9dfaa28a5079a034b8214ce1bbf01da8..d32ceea0136e943f30f5150da915ed2957f90628 100644 --- a/crates/gpui/examples/data_table.rs +++ b/crates/gpui/examples/data_table.rs @@ -1,10 +1,11 @@ use std::{ops::Range, rc::Rc, time::Duration}; use gpui::{ - App, Application, Bounds, Context, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, - Render, SharedString, UniformListScrollHandle, Window, WindowBounds, WindowOptions, canvas, - div, point, prelude::*, px, rgb, size, uniform_list, + App, Bounds, Context, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, Render, + SharedString, UniformListScrollHandle, Window, WindowBounds, WindowOptions, canvas, div, point, + prelude::*, px, rgb, size, uniform_list, }; +use gpui_platform::application; const TOTAL_ITEMS: usize = 10000; const SCROLLBAR_THUMB_WIDTH: Pixels = px(8.); @@ -447,7 +448,7 @@ impl Render for DataTable { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { cx.open_window( WindowOptions { focus: true, diff --git a/crates/gpui/examples/drag_drop.rs b/crates/gpui/examples/drag_drop.rs index cf5048f6d3132a87365f4141bc375bb76955be7d..734a614bd6c978b45c5dbc397e068e6e87875312 100644 --- a/crates/gpui/examples/drag_drop.rs +++ b/crates/gpui/examples/drag_drop.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Bounds, Context, Half, Hsla, Pixels, Point, Window, WindowBounds, - WindowOptions, div, prelude::*, px, rgb, size, + App, Bounds, Context, Half, Hsla, Pixels, Point, Window, WindowBounds, WindowOptions, div, + prelude::*, px, rgb, size, }; +use gpui_platform::application; #[derive(Clone, Copy)] struct DragInfo { @@ -121,7 +122,7 @@ impl Render for DragDrop { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(800.), px(600.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/focus_visible.rs b/crates/gpui/examples/focus_visible.rs index d7c15396f0381ef29b3d6600347fd90a602256f5..c32ffc62a2fa3696a72f7319cbd5ee843d9308bc 100644 --- a/crates/gpui/examples/focus_visible.rs +++ b/crates/gpui/examples/focus_visible.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Bounds, Context, Div, ElementId, FocusHandle, KeyBinding, SharedString, - Stateful, Window, WindowBounds, WindowOptions, actions, div, prelude::*, px, size, + App, Bounds, Context, Div, ElementId, FocusHandle, KeyBinding, SharedString, Stateful, Window, + WindowBounds, WindowOptions, actions, div, prelude::*, px, size, }; +use gpui_platform::application; actions!(example, [Tab, TabPrev, Quit]); @@ -192,7 +193,7 @@ impl Render for Example { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { cx.bind_keys([ KeyBinding::new("tab", Tab, None), KeyBinding::new("shift-tab", TabPrev, None), diff --git a/crates/gpui/examples/gif_viewer.rs b/crates/gpui/examples/gif_viewer.rs index 3206a2fb7a3faa1f01378aedcf3e1ac9d9febf96..6dea19d7820876ca6334045fa5a98c63c00cf800 100644 --- a/crates/gpui/examples/gif_viewer.rs +++ b/crates/gpui/examples/gif_viewer.rs @@ -1,4 +1,5 @@ -use gpui::{App, Application, Context, Render, Window, WindowOptions, div, img, prelude::*}; +use gpui::{App, Context, Render, Window, WindowOptions, div, img, prelude::*}; +use gpui_platform::application; use std::path::PathBuf; struct GifViewer { @@ -24,7 +25,7 @@ impl Render for GifViewer { fn main() { env_logger::init(); - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let gif_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples/image/black-cat-typing.gif"); diff --git a/crates/gpui/examples/gradient.rs b/crates/gpui/examples/gradient.rs index 30fb3090a30d4f6c70e968d637dbf98b73559529..f931e6a3067b6b922a9ee29ea561d6f1eda7eb78 100644 --- a/crates/gpui/examples/gradient.rs +++ b/crates/gpui/examples/gradient.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Bounds, ColorSpace, Context, Half, Render, Window, WindowOptions, canvas, - div, linear_color_stop, linear_gradient, point, prelude::*, px, size, + App, Bounds, ColorSpace, Context, Half, Render, Window, WindowOptions, canvas, div, + linear_color_stop, linear_gradient, point, prelude::*, px, size, }; +use gpui_platform::application; struct GradientViewer { color_space: ColorSpace, @@ -243,7 +244,7 @@ impl Render for GradientViewer { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { cx.open_window( WindowOptions { focus: true, diff --git a/crates/gpui/examples/grid_layout.rs b/crates/gpui/examples/grid_layout.rs index f28549757838c8afa65ffebb9ad94dcdfa9bd837..49119a89616758201edb3ca35eff3db364afd908 100644 --- a/crates/gpui/examples/grid_layout.rs +++ b/crates/gpui/examples/grid_layout.rs @@ -1,7 +1,7 @@ use gpui::{ - App, Application, Bounds, Context, Hsla, Window, WindowBounds, WindowOptions, div, prelude::*, - px, rgb, size, + App, Bounds, Context, Hsla, Window, WindowBounds, WindowOptions, div, prelude::*, px, rgb, size, }; +use gpui_platform::application; // https://en.wikipedia.org/wiki/Holy_grail_(web_design) struct HolyGrailExample {} @@ -65,7 +65,7 @@ impl Render for HolyGrailExample { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/hello_world.rs b/crates/gpui/examples/hello_world.rs index 70110934741e583a6a56f338d8a010c5758f6f01..634eca511269a8ad29a03cfdd104af4f081bee1c 100644 --- a/crates/gpui/examples/hello_world.rs +++ b/crates/gpui/examples/hello_world.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Bounds, Context, SharedString, Window, WindowBounds, WindowOptions, div, - prelude::*, px, rgb, size, + App, Bounds, Context, SharedString, Window, WindowBounds, WindowOptions, div, prelude::*, px, + rgb, size, }; +use gpui_platform::application; struct HelloWorld { text: SharedString, @@ -87,7 +88,7 @@ impl Render for HelloWorld { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/image/image.rs b/crates/gpui/examples/image/image.rs index 34a510f76db396a91a225dffe21fcec986a62e20..10e40e65320c677a36f3a3027528db044b09e63e 100644 --- a/crates/gpui/examples/image/image.rs +++ b/crates/gpui/examples/image/image.rs @@ -4,10 +4,11 @@ use std::sync::Arc; use anyhow::Result; use gpui::{ - App, AppContext, Application, AssetSource, Bounds, Context, ImageSource, KeyBinding, Menu, - MenuItem, Point, SharedString, SharedUri, TitlebarOptions, Window, WindowBounds, WindowOptions, - actions, div, img, prelude::*, px, rgb, size, + App, AppContext, AssetSource, Bounds, Context, ImageSource, KeyBinding, Menu, MenuItem, Point, + SharedString, SharedUri, TitlebarOptions, Window, WindowBounds, WindowOptions, actions, div, + img, prelude::*, px, rgb, size, }; +use gpui_platform::application; use reqwest_client::ReqwestClient; struct Assets { @@ -150,7 +151,7 @@ fn main() { let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - Application::new() + application() .with_assets(Assets { base: manifest_dir.join("examples"), }) diff --git a/crates/gpui/examples/image_gallery.rs b/crates/gpui/examples/image_gallery.rs index 1fa7a8678f4794b50d245a02e210ea0c2d423ca3..881ef5307ffebeba60daab30fe098b2f5a6cabb6 100644 --- a/crates/gpui/examples/image_gallery.rs +++ b/crates/gpui/examples/image_gallery.rs @@ -1,10 +1,11 @@ use futures::FutureExt; use gpui::{ - App, AppContext, Application, Asset as _, AssetLogger, Bounds, ClickEvent, Context, ElementId, - Entity, ImageAssetLoader, ImageCache, ImageCacheProvider, KeyBinding, Menu, MenuItem, + App, AppContext, Asset as _, AssetLogger, Bounds, ClickEvent, Context, ElementId, Entity, + ImageAssetLoader, ImageCache, ImageCacheProvider, KeyBinding, Menu, MenuItem, RetainAllImageCache, SharedString, TitlebarOptions, Window, WindowBounds, WindowOptions, actions, div, hash, image_cache, img, prelude::*, px, rgb, size, }; +use gpui_platform::application; use reqwest_client::ReqwestClient; use std::{collections::HashMap, sync::Arc}; @@ -247,7 +248,7 @@ actions!(image, [Quit]); fn main() { env_logger::init(); - Application::new().run(move |cx: &mut App| { + application().run(move |cx: &mut App| { let http_client = ReqwestClient::user_agent("gpui example").unwrap(); cx.set_http_client(Arc::new(http_client)); diff --git a/crates/gpui/examples/image_loading.rs b/crates/gpui/examples/image_loading.rs index 399bd2634f9bfb363d3ff9614150f2082e824eca..2de18fd7576ee91b3d54479ada909e04aa49475e 100644 --- a/crates/gpui/examples/image_loading.rs +++ b/crates/gpui/examples/image_loading.rs @@ -1,11 +1,12 @@ use std::{path::Path, sync::Arc, time::Duration}; use gpui::{ - Animation, AnimationExt, App, Application, Asset, AssetLogger, AssetSource, Bounds, Context, - Hsla, ImageAssetLoader, ImageCacheError, ImgResourceLoader, LOADING_DELAY, Length, RenderImage, + Animation, AnimationExt, App, Asset, AssetLogger, AssetSource, Bounds, Context, Hsla, + ImageAssetLoader, ImageCacheError, ImgResourceLoader, LOADING_DELAY, Length, RenderImage, Resource, SharedString, Window, WindowBounds, WindowOptions, black, div, img, prelude::*, pulsating_between, px, red, size, }; +use gpui_platform::application; struct Assets {} @@ -193,21 +194,19 @@ impl Render for ImageLoadingExample { fn main() { env_logger::init(); - Application::new() - .with_assets(Assets {}) - .run(|cx: &mut App| { - let options = WindowOptions { - window_bounds: Some(WindowBounds::Windowed(Bounds::centered( - None, - size(px(300.), px(300.)), - cx, - ))), - ..Default::default() - }; - cx.open_window(options, |_, cx| { - cx.activate(false); - cx.new(|_| ImageLoadingExample {}) - }) - .unwrap(); - }); + application().with_assets(Assets {}).run(|cx: &mut App| { + let options = WindowOptions { + window_bounds: Some(WindowBounds::Windowed(Bounds::centered( + None, + size(px(300.), px(300.)), + cx, + ))), + ..Default::default() + }; + cx.open_window(options, |_, cx| { + cx.activate(false); + cx.new(|_| ImageLoadingExample {}) + }) + .unwrap(); + }); } diff --git a/crates/gpui/examples/input.rs b/crates/gpui/examples/input.rs index aac56bdf1d0b739f28f395e537b171264c78a1e8..1f8a9806ebee1f69973e4a54a5746aabda6f3f0c 100644 --- a/crates/gpui/examples/input.rs +++ b/crates/gpui/examples/input.rs @@ -1,13 +1,14 @@ use std::ops::Range; use gpui::{ - App, Application, Bounds, ClipboardItem, Context, CursorStyle, ElementId, ElementInputHandler, - Entity, EntityInputHandler, FocusHandle, Focusable, GlobalElementId, KeyBinding, Keystroke, - LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, Pixels, Point, + App, Bounds, ClipboardItem, Context, CursorStyle, ElementId, ElementInputHandler, Entity, + EntityInputHandler, FocusHandle, Focusable, GlobalElementId, KeyBinding, Keystroke, LayoutId, + MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, Pixels, Point, ShapedLine, SharedString, Style, TextRun, UTF16Selection, UnderlineStyle, Window, WindowBounds, WindowOptions, actions, black, div, fill, hsla, opaque_grey, point, prelude::*, px, relative, rgb, rgba, size, white, yellow, }; +use gpui_platform::application; use unicode_segmentation::*; actions!( @@ -682,7 +683,7 @@ impl Render for InputExample { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(300.0), px(300.0)), cx); cx.bind_keys([ KeyBinding::new("backspace", Backspace, None), diff --git a/crates/gpui/examples/layer_shell.rs b/crates/gpui/examples/layer_shell.rs index 51577b1b26491b8416a7df17ee310fd50dade8a3..49958711318ef70dc4e0e89dbc096f5f8761dc41 100644 --- a/crates/gpui/examples/layer_shell.rs +++ b/crates/gpui/examples/layer_shell.rs @@ -11,10 +11,10 @@ mod example { use std::time::{Duration, SystemTime, UNIX_EPOCH}; use gpui::{ - App, Application, Bounds, Context, FontWeight, Size, Window, WindowBackgroundAppearance, - WindowBounds, WindowKind, WindowOptions, div, layer_shell::*, point, prelude::*, px, rems, - rgba, white, + App, Bounds, Context, FontWeight, Size, Window, WindowBackgroundAppearance, WindowBounds, + WindowKind, WindowOptions, div, layer_shell::*, point, prelude::*, px, rems, rgba, white, }; + use gpui_platform::application; struct LayerShellExample; @@ -60,7 +60,7 @@ mod example { } pub fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { cx.open_window( WindowOptions { titlebar: None, diff --git a/crates/gpui/examples/mouse_pressure.rs b/crates/gpui/examples/mouse_pressure.rs index 12790f988eedac3009ae619cadbc6f40c4af2e4b..1d0fe01b820caaed115d8b1d8baa46fa48266f64 100644 --- a/crates/gpui/examples/mouse_pressure.rs +++ b/crates/gpui/examples/mouse_pressure.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Bounds, Context, MousePressureEvent, PressureStage, Window, WindowBounds, - WindowOptions, div, prelude::*, px, rgb, size, + App, Bounds, Context, MousePressureEvent, PressureStage, Window, WindowBounds, WindowOptions, + div, prelude::*, px, rgb, size, }; +use gpui_platform::application; struct MousePressureExample { pressure_stage: PressureStage, @@ -44,7 +45,7 @@ impl MousePressureExample { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx); cx.open_window( diff --git a/crates/gpui/examples/on_window_close_quit.rs b/crates/gpui/examples/on_window_close_quit.rs index 9a2b2f2fee43f753aece55d076be647ad8060965..6aa0887db5efea6cf093dc2fa1c4e8f6bd4fb908 100644 --- a/crates/gpui/examples/on_window_close_quit.rs +++ b/crates/gpui/examples/on_window_close_quit.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Bounds, Context, FocusHandle, KeyBinding, Window, WindowBounds, - WindowOptions, actions, div, prelude::*, px, rgb, size, + App, Bounds, Context, FocusHandle, KeyBinding, Window, WindowBounds, WindowOptions, actions, + div, prelude::*, px, rgb, size, }; +use gpui_platform::application; actions!(example, [CloseWindow]); @@ -35,7 +36,7 @@ impl Render for ExampleWindow { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let mut bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx); cx.bind_keys([KeyBinding::new("cmd-w", CloseWindow, None)]); diff --git a/crates/gpui/examples/opacity.rs b/crates/gpui/examples/opacity.rs index b6c01fc3cf3866d29e184ccf975e6796e7d07df7..31094f49343074e6494250ba08b3062daea6b7f7 100644 --- a/crates/gpui/examples/opacity.rs +++ b/crates/gpui/examples/opacity.rs @@ -2,9 +2,10 @@ use std::{fs, path::PathBuf}; use anyhow::Result; use gpui::{ - App, Application, AssetSource, Bounds, BoxShadow, ClickEvent, Context, SharedString, Task, - Window, WindowBounds, WindowOptions, div, hsla, img, point, prelude::*, px, rgb, size, svg, + App, AssetSource, Bounds, BoxShadow, ClickEvent, Context, SharedString, Task, Window, + WindowBounds, WindowOptions, div, hsla, img, point, prelude::*, px, rgb, size, svg, }; +use gpui_platform::application; struct Assets { base: PathBuf, @@ -156,7 +157,7 @@ impl Render for HelloWorld { } fn main() { - Application::new() + application() .with_assets(Assets { base: PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples"), }) diff --git a/crates/gpui/examples/ownership_post.rs b/crates/gpui/examples/ownership_post.rs index e690de54a88609c6a725b359962f165f6c0b5574..ef9143f0c0685424738be54f56c7bd64af8a8f56 100644 --- a/crates/gpui/examples/ownership_post.rs +++ b/crates/gpui/examples/ownership_post.rs @@ -1,4 +1,5 @@ -use gpui::{App, Application, Context, Entity, EventEmitter, prelude::*}; +use gpui::{App, Context, Entity, EventEmitter, prelude::*}; +use gpui_platform::application; struct Counter { count: usize, @@ -11,7 +12,7 @@ struct Change { impl EventEmitter for Counter {} fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let counter: Entity = cx.new(|_cx| Counter { count: 0 }); let subscriber = cx.new(|cx: &mut Context| { cx.subscribe(&counter, |subscriber, _emitter, event, _cx| { diff --git a/crates/gpui/examples/painting.rs b/crates/gpui/examples/painting.rs index 9f15d12f469fa6ec5c7be52d30a63b30163ff254..fa73a38136d287f357eb8b44bea732ad84185a25 100644 --- a/crates/gpui/examples/painting.rs +++ b/crates/gpui/examples/painting.rs @@ -1,8 +1,9 @@ use gpui::{ - Application, Background, Bounds, ColorSpace, Context, MouseDownEvent, Path, PathBuilder, - PathStyle, Pixels, Point, Render, StrokeOptions, Window, WindowOptions, canvas, div, - linear_color_stop, linear_gradient, point, prelude::*, px, quad, rgb, size, + Background, Bounds, ColorSpace, Context, MouseDownEvent, Path, PathBuilder, PathStyle, Pixels, + Point, Render, StrokeOptions, Window, WindowOptions, canvas, div, linear_color_stop, + linear_gradient, point, prelude::*, px, quad, rgb, size, }; +use gpui_platform::application; struct PaintingViewer { default_lines: Vec<(Path, Background)>, @@ -445,7 +446,7 @@ impl Render for PaintingViewer { } fn main() { - Application::new().run(|cx| { + application().run(|cx| { cx.open_window( WindowOptions { focus: true, diff --git a/crates/gpui/examples/paths_bench.rs b/crates/gpui/examples/paths_bench.rs index a801889ae869ea7c08dce1362036b1d29c4daf36..17f80b0ff470901af4da1213e9ed12ad1585673d 100644 --- a/crates/gpui/examples/paths_bench.rs +++ b/crates/gpui/examples/paths_bench.rs @@ -1,8 +1,9 @@ use gpui::{ - Application, Background, Bounds, ColorSpace, Context, Path, PathBuilder, Pixels, Render, - TitlebarOptions, Window, WindowBounds, WindowOptions, canvas, div, linear_color_stop, - linear_gradient, point, prelude::*, px, rgb, size, + Background, Bounds, ColorSpace, Context, Path, PathBuilder, Pixels, Render, TitlebarOptions, + Window, WindowBounds, WindowOptions, canvas, div, linear_color_stop, linear_gradient, point, + prelude::*, px, rgb, size, }; +use gpui_platform::application; const DEFAULT_WINDOW_WIDTH: Pixels = px(1024.0); const DEFAULT_WINDOW_HEIGHT: Pixels = px(768.0); @@ -69,7 +70,7 @@ impl Render for PaintingViewer { } fn main() { - Application::new().run(|cx| { + application().run(|cx| { cx.open_window( WindowOptions { titlebar: Some(TitlebarOptions { diff --git a/crates/gpui/examples/pattern.rs b/crates/gpui/examples/pattern.rs index 8be6642fdaf032aef9105f8925986544d8606b7c..bc9237268d70157a415a8819984db7d96e477e5b 100644 --- a/crates/gpui/examples/pattern.rs +++ b/crates/gpui/examples/pattern.rs @@ -1,7 +1,8 @@ use gpui::{ - App, AppContext, Application, Bounds, Context, Window, WindowBounds, WindowOptions, div, - linear_color_stop, linear_gradient, pattern_slash, prelude::*, px, rgb, size, + App, AppContext, Bounds, Context, Window, WindowBounds, WindowOptions, div, linear_color_stop, + linear_gradient, pattern_slash, prelude::*, px, rgb, size, }; +use gpui_platform::application; struct PatternExample; @@ -99,7 +100,7 @@ impl Render for PatternExample { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(600.0), px(600.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/popover.rs b/crates/gpui/examples/popover.rs index 9a3d47d06dd0f92d176dd4e81d739403a4870062..429eb17c0629938dcbd9fb21698ab887503fd51a 100644 --- a/crates/gpui/examples/popover.rs +++ b/crates/gpui/examples/popover.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Context, Corner, Div, Hsla, Stateful, Window, WindowOptions, anchored, - deferred, div, prelude::*, px, + App, Context, Corner, Div, Hsla, Stateful, Window, WindowOptions, anchored, deferred, div, + prelude::*, px, }; +use gpui_platform::application; /// An example show use deferred to create a floating layers. struct HelloWorld { @@ -161,7 +162,7 @@ impl Render for HelloWorld { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { cx.open_window(WindowOptions::default(), |_, cx| { cx.new(|_| HelloWorld { open: false, diff --git a/crates/gpui/examples/scrollable.rs b/crates/gpui/examples/scrollable.rs index b668c19c40abc3cde13c953a24fcbec375019247..6e4865ee496366da69494334152b703a509780d3 100644 --- a/crates/gpui/examples/scrollable.rs +++ b/crates/gpui/examples/scrollable.rs @@ -1,7 +1,5 @@ -use gpui::{ - App, Application, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, - size, -}; +use gpui::{App, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, size}; +use gpui_platform::application; struct Scrollable {} @@ -45,7 +43,7 @@ impl Render for Scrollable { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/set_menus.rs b/crates/gpui/examples/set_menus.rs index f4e5e5e11234d3140d088195174f617637802811..30f8ef0f32a0d8c56bafeb71faa1c2435ef9fff3 100644 --- a/crates/gpui/examples/set_menus.rs +++ b/crates/gpui/examples/set_menus.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Context, Global, Menu, MenuItem, SharedString, SystemMenuType, Window, - WindowOptions, actions, div, prelude::*, rgb, + App, Context, Global, Menu, MenuItem, SharedString, SystemMenuType, Window, WindowOptions, + actions, div, prelude::*, rgb, }; +use gpui_platform::application; struct SetMenus; @@ -20,7 +21,7 @@ impl Render for SetMenus { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { cx.set_global(AppState::new()); // Bring the menu bar to the foreground (so you can see the menu bar) diff --git a/crates/gpui/examples/shadow.rs b/crates/gpui/examples/shadow.rs index 352e29c042af688abf554a611f6218a468280b9e..519053ae9293d51df86ba14b66e1182d718035a0 100644 --- a/crates/gpui/examples/shadow.rs +++ b/crates/gpui/examples/shadow.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Bounds, BoxShadow, Context, Div, SharedString, Window, WindowBounds, - WindowOptions, div, hsla, point, prelude::*, px, relative, rgb, size, + App, Bounds, BoxShadow, Context, Div, SharedString, Window, WindowBounds, WindowOptions, div, + hsla, point, prelude::*, px, relative, rgb, size, }; +use gpui_platform::application; struct Shadow {} @@ -569,7 +570,7 @@ impl Render for Shadow { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(1000.0), px(800.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/svg/svg.rs b/crates/gpui/examples/svg/svg.rs index 5d938998e8799f873ff8490ba8dfd8118fbf6ae3..54e99320bd59a9d8fffeea65c7825105781d9226 100644 --- a/crates/gpui/examples/svg/svg.rs +++ b/crates/gpui/examples/svg/svg.rs @@ -3,9 +3,10 @@ use std::path::PathBuf; use anyhow::Result; use gpui::{ - App, Application, AssetSource, Bounds, Context, SharedString, Window, WindowBounds, - WindowOptions, div, prelude::*, px, rgb, size, svg, + App, AssetSource, Bounds, Context, SharedString, Window, WindowBounds, WindowOptions, div, + prelude::*, px, rgb, size, svg, }; +use gpui_platform::application; struct Assets { base: PathBuf, @@ -68,7 +69,7 @@ impl Render for SvgExample { } fn main() { - Application::new() + application() .with_assets(Assets { base: PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples"), }) diff --git a/crates/gpui/examples/tab_stop.rs b/crates/gpui/examples/tab_stop.rs index efad97236cfc778870db1ee723c92691578860dd..6fa0ee4929db62b2122748729686d955f96932bb 100644 --- a/crates/gpui/examples/tab_stop.rs +++ b/crates/gpui/examples/tab_stop.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Bounds, Context, Div, ElementId, FocusHandle, KeyBinding, SharedString, - Stateful, Window, WindowBounds, WindowOptions, actions, div, prelude::*, px, size, + App, Bounds, Context, Div, ElementId, FocusHandle, KeyBinding, SharedString, Stateful, Window, + WindowBounds, WindowOptions, actions, div, prelude::*, px, size, }; +use gpui_platform::application; actions!(example, [Tab, TabPrev]); @@ -178,7 +179,7 @@ impl Render for Example { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { cx.bind_keys([ KeyBinding::new("tab", Tab, None), KeyBinding::new("shift-tab", TabPrev, None), diff --git a/crates/gpui/examples/testing.rs b/crates/gpui/examples/testing.rs index 41f7dad7632a6da9397ba9003b885ae067475915..a3d09d1395a165635cb785a910009c8e96401f2f 100644 --- a/crates/gpui/examples/testing.rs +++ b/crates/gpui/examples/testing.rs @@ -7,9 +7,10 @@ //! Run tests: cargo test -p gpui --example testing --features test-support use gpui::{ - App, Application, Bounds, Context, FocusHandle, Focusable, Render, Task, Window, WindowBounds, + App, Bounds, Context, FocusHandle, Focusable, Render, Task, Window, WindowBounds, WindowOptions, actions, div, prelude::*, px, rgb, size, }; +use gpui_platform::application; actions!(counter, [Increment, Decrement]); @@ -176,7 +177,7 @@ impl Render for Counter { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { cx.bind_keys([ gpui::KeyBinding::new("up", Increment, Some("Counter")), gpui::KeyBinding::new("down", Decrement, Some("Counter")), diff --git a/crates/gpui/examples/text.rs b/crates/gpui/examples/text.rs index 3cb95897b668eeb142d6b84f13af83b1ad3ff5f4..d4effbbce91cc6e8261a5ec44d196a1868a772a6 100644 --- a/crates/gpui/examples/text.rs +++ b/crates/gpui/examples/text.rs @@ -4,10 +4,11 @@ use std::{ }; use gpui::{ - AbsoluteLength, App, Application, Context, DefiniteLength, ElementId, Global, Hsla, Menu, - SharedString, TextStyle, TitlebarOptions, Window, WindowBounds, WindowOptions, bounds, - colors::DefaultColors, div, point, prelude::*, px, relative, rgb, size, + AbsoluteLength, App, Context, DefiniteLength, ElementId, Global, Hsla, Menu, SharedString, + TextStyle, TitlebarOptions, Window, WindowBounds, WindowOptions, bounds, colors::DefaultColors, + div, point, prelude::*, px, relative, rgb, size, }; +use gpui_platform::application; use std::iter; #[derive(Clone, Debug)] @@ -298,7 +299,7 @@ impl Render for TextExample { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { cx.set_menus(vec![Menu { name: "GPUI Typography".into(), items: vec![], diff --git a/crates/gpui/examples/text_layout.rs b/crates/gpui/examples/text_layout.rs index 8929955ba824c36c90951ece2cf9ba710259ddac..5c9ef368b8406e0882ab159f82c3eecba52a19da 100644 --- a/crates/gpui/examples/text_layout.rs +++ b/crates/gpui/examples/text_layout.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Bounds, Context, FontStyle, FontWeight, StyledText, Window, WindowBounds, - WindowOptions, div, prelude::*, px, size, + App, Bounds, Context, FontStyle, FontWeight, StyledText, Window, WindowBounds, WindowOptions, + div, prelude::*, px, size, }; +use gpui_platform::application; struct HelloWorld {} @@ -81,7 +82,7 @@ impl Render for HelloWorld { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(800.0), px(600.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/text_wrapper.rs b/crates/gpui/examples/text_wrapper.rs index 18372ea9e137cc3cfb11f3df59ce698660ad06be..cfc981e9e2b0bff6a63ecc78125292d6ff43ce48 100644 --- a/crates/gpui/examples/text_wrapper.rs +++ b/crates/gpui/examples/text_wrapper.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Bounds, Context, TextOverflow, Window, WindowBounds, WindowOptions, div, - prelude::*, px, size, + App, Bounds, Context, TextOverflow, Window, WindowBounds, WindowOptions, div, prelude::*, px, + size, }; +use gpui_platform::application; struct HelloWorld {} @@ -108,7 +109,7 @@ impl Render for HelloWorld { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(800.0), px(600.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/tree.rs b/crates/gpui/examples/tree.rs index 1bd45920037839c27ea5773f23daa9dcbbceae0e..43607b6648f3a7894f90a3c42ab0af8d8663790c 100644 --- a/crates/gpui/examples/tree.rs +++ b/crates/gpui/examples/tree.rs @@ -2,10 +2,8 @@ //! handle deep hierarchies (even though it cannot just yet!). use std::sync::LazyLock; -use gpui::{ - App, Application, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, - size, -}; +use gpui::{App, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, size}; +use gpui_platform::application; struct Tree {} @@ -32,7 +30,7 @@ impl Render for Tree { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(300.0), px(300.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/uniform_list.rs b/crates/gpui/examples/uniform_list.rs index fc5d92bdd4e90878ca77f8528834b0b7e5fbdaec..c287cdfb45568d32d939881df5b7e289c4a41727 100644 --- a/crates/gpui/examples/uniform_list.rs +++ b/crates/gpui/examples/uniform_list.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, - rgb, size, uniform_list, + App, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, rgb, size, + uniform_list, }; +use gpui_platform::application; struct UniformListExample {} @@ -36,7 +37,7 @@ impl Render for UniformListExample { } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(300.0), px(300.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/window.rs b/crates/gpui/examples/window.rs index c9672c448a629a2edcf1c57b5fa9f854dc12df6a..80d4f46ac09d8adb483f909f00bd88fd97f1f990 100644 --- a/crates/gpui/examples/window.rs +++ b/crates/gpui/examples/window.rs @@ -1,7 +1,8 @@ use gpui::{ - App, Application, Bounds, Context, KeyBinding, PromptButton, PromptLevel, Window, WindowBounds, - WindowKind, WindowOptions, actions, div, prelude::*, px, rgb, size, + App, Bounds, Context, KeyBinding, PromptButton, PromptLevel, Window, WindowBounds, WindowKind, + WindowOptions, actions, div, prelude::*, px, rgb, size, }; +use gpui_platform::application; struct SubWindow { custom_titlebar: bool, @@ -306,7 +307,7 @@ impl Render for WindowDemo { actions!(window, [Quit]); fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(800.0), px(600.0)), cx); cx.open_window( diff --git a/crates/gpui/examples/window_positioning.rs b/crates/gpui/examples/window_positioning.rs index ca6cd535d67aa8b2e700b2d0bc632056e928e0e7..45ac3fcd78fc811dcb450609c293d81900d3c67b 100644 --- a/crates/gpui/examples/window_positioning.rs +++ b/crates/gpui/examples/window_positioning.rs @@ -1,8 +1,9 @@ use gpui::{ - App, Application, Bounds, Context, DisplayId, Hsla, Pixels, SharedString, Size, Window, + App, Bounds, Context, DisplayId, Hsla, Pixels, SharedString, Size, Window, WindowBackgroundAppearance, WindowBounds, WindowKind, WindowOptions, div, point, prelude::*, px, rgb, }; +use gpui_platform::application; struct WindowContent { text: SharedString, @@ -68,7 +69,7 @@ fn build_window_options(display_id: DisplayId, bounds: Bounds) -> Window } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { // Create several new windows, positioned in the top right corner of each screen let size = Size { width: px(350.), diff --git a/crates/gpui/examples/window_shadow.rs b/crates/gpui/examples/window_shadow.rs index 469017da795d54a36353449f0043483526f63708..c8e37b67e98c38d45608836e5752dee8a575091a 100644 --- a/crates/gpui/examples/window_shadow.rs +++ b/crates/gpui/examples/window_shadow.rs @@ -1,9 +1,10 @@ use gpui::{ - App, Application, Bounds, Context, CursorStyle, Decorations, HitboxBehavior, Hsla, MouseButton, - Pixels, Point, ResizeEdge, Size, Window, WindowBackgroundAppearance, WindowBounds, - WindowDecorations, WindowOptions, black, canvas, div, green, point, prelude::*, px, rgb, size, - transparent_black, white, + App, Bounds, Context, CursorStyle, Decorations, HitboxBehavior, Hsla, MouseButton, Pixels, + Point, ResizeEdge, Size, Window, WindowBackgroundAppearance, WindowBounds, WindowDecorations, + WindowOptions, black, canvas, div, green, point, prelude::*, px, rgb, size, transparent_black, + white, }; +use gpui_platform::application; struct WindowShadow {} @@ -203,7 +204,7 @@ fn resize_edge(pos: Point, shadow_size: Pixels, size: Size) -> O } fn main() { - Application::new().run(|cx: &mut App| { + application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(600.0), px(600.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/src/_ownership_and_data_flow.rs b/crates/gpui/src/_ownership_and_data_flow.rs index 9bb8bf66956a101cc8d9db170e34512628a6b0be..68699cce7f595eca8172569ad51f10b3cabc27d2 100644 --- a/crates/gpui/src/_ownership_and_data_flow.rs +++ b/crates/gpui/src/_ownership_and_data_flow.rs @@ -7,7 +7,7 @@ //! # struct Counter { //! # count: usize, //! # } -//! Application::new().run(|cx: &mut App| { +//! gpui_platform::application().run(|cx: &mut App| { //! let _counter: Entity = cx.new(|_cx| Counter { count: 0 }); //! // ... //! }); @@ -22,7 +22,7 @@ //! # struct Counter { //! # count: usize, //! # } -//! Application::new().run(|cx: &mut App| { +//! gpui_platform::application().run(|cx: &mut App| { //! let counter: Entity = cx.new(|_cx| Counter { count: 0 }); //! // Call `update` to access the model's state. //! counter.update(cx, |counter: &mut Counter, _cx: &mut Context| { @@ -42,7 +42,7 @@ //! # struct Counter { //! # count: usize, //! # } -//! Application::new().run(|cx: &mut App| { +//! gpui_platform::application().run(|cx: &mut App| { //! let counter: Entity = cx.new(|_cx| Counter { count: 0 }); //! counter.update(cx, |counter, cx| { //! counter.count += 1; @@ -60,7 +60,7 @@ //! # struct Counter { //! # count: usize, //! # } -//! Application::new().run(|cx: &mut App| { +//! gpui_platform::application().run(|cx: &mut App| { //! let first_counter: Entity = cx.new(|_cx| Counter { count: 0 }); //! //! let second_counter = cx.new(|cx: &mut Context| { @@ -114,7 +114,7 @@ //! # increment: usize, //! # } //! # impl EventEmitter for Counter {} -//! Application::new().run(|cx: &mut App| { +//! gpui_platform::application().run(|cx: &mut App| { //! let first_counter: Entity = cx.new(|_cx| Counter { count: 0 }); //! //! let second_counter = cx.new(|cx: &mut Context| { diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 8f5c082a05de90be9575798daef4c8ea6f17b0b3..2a83045aa0f9b776eb247f40ba39312f2cd15d4a 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -46,7 +46,7 @@ use crate::{ SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextRenderingMode, TextSystem, ThermalState, Window, WindowAppearance, WindowHandle, WindowId, WindowInvalidator, colors::{Colors, GlobalColors}, - current_platform, hash, init_app_menus, + hash, init_app_menus, }; mod async_context; @@ -132,25 +132,10 @@ pub struct Application(Rc); /// Represents an application before it is fully launched. Once your app is /// configured, you'll start the app with `App::run`. impl Application { - /// Builds an app with the given asset source. - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - #[cfg(any(test, feature = "test-support"))] - log::info!("GPUI was compiled in test mode"); - - Self(App::new_app( - current_platform(false), - Arc::new(()), - Arc::new(NullHttpClient), - )) - } - - /// Build an app in headless mode. This prevents opening windows, - /// but makes it possible to run an application in an context like - /// SSH, where GUI applications are not allowed. - pub fn headless() -> Self { + /// Builds an app with a caller-provided platform implementation. + pub fn with_platform(platform: Rc) -> Self { Self(App::new_app( - current_platform(true), + platform, Arc::new(()), Arc::new(NullHttpClient), )) diff --git a/crates/gpui/src/app/visual_test_context.rs b/crates/gpui/src/app/visual_test_context.rs index f0598ef9a7d5a81df1a4fe530e207b8d67d2846d..22389b5b27566db05be7c462e87596f17def880a 100644 --- a/crates/gpui/src/app/visual_test_context.rs +++ b/crates/gpui/src/app/visual_test_context.rs @@ -42,15 +42,18 @@ impl VisualTestAppContext { /// /// Note: This uses a no-op asset source, so SVG icons won't render. /// Use `with_asset_source` to provide real assets for icon rendering. - pub fn new() -> Self { - Self::with_asset_source(Arc::new(())) + pub fn new(platform: Rc) -> Self { + Self::with_asset_source(platform, Arc::new(())) } /// Creates a new `VisualTestAppContext` with a custom asset source. /// /// Use this when you need SVG icons to render properly in visual tests. /// Pass the real `Assets` struct to enable icon rendering. - pub fn with_asset_source(asset_source: Arc) -> Self { + pub fn with_asset_source( + platform: Rc, + asset_source: Arc, + ) -> Self { // Use a seeded RNG for deterministic behavior let seed = std::env::var("SEED") .ok() @@ -59,7 +62,7 @@ impl VisualTestAppContext { // Create a visual test platform that combines real Mac rendering // with controllable TestDispatcher for deterministic task scheduling - let platform = Rc::new(VisualTestPlatform::new(seed)); + let platform = Rc::new(VisualTestPlatform::new(platform, seed)); // Get the dispatcher and executors from the platform let dispatcher = platform.dispatcher().clone(); @@ -391,12 +394,6 @@ impl VisualTestAppContext { } } -impl Default for VisualTestAppContext { - fn default() -> Self { - Self::new() - } -} - impl AppContext for VisualTestAppContext { fn new(&mut self, build_entity: impl FnOnce(&mut Context) -> T) -> Entity { let mut app = self.app.borrow_mut(); @@ -476,112 +473,3 @@ impl AppContext for VisualTestAppContext { callback(app.global::(), &app) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::Empty; - use std::cell::RefCell; - - // Note: All VisualTestAppContext tests are ignored by default because they require - // the macOS main thread. Standard Rust tests run on worker threads, which causes - // SIGABRT when interacting with macOS AppKit/Cocoa APIs. - // - // To run these tests, use: - // cargo test -p gpui visual_test_context -- --ignored --test-threads=1 - - #[test] - #[ignore] // Requires macOS main thread - fn test_foreground_tasks_run_with_run_until_parked() { - let mut cx = VisualTestAppContext::new(); - - let task_ran = Rc::new(RefCell::new(false)); - - // Spawn a foreground task via the App's spawn method - // This should use our TestDispatcher, not the MacDispatcher - { - let task_ran = task_ran.clone(); - cx.update(|cx| { - cx.spawn(async move |_| { - *task_ran.borrow_mut() = true; - }) - .detach(); - }); - } - - // The task should not have run yet - assert!(!*task_ran.borrow()); - - // Run until parked should execute the foreground task - cx.run_until_parked(); - - // Now the task should have run - assert!(*task_ran.borrow()); - } - - #[test] - #[ignore] // Requires macOS main thread - fn test_advance_clock_triggers_delayed_tasks() { - let mut cx = VisualTestAppContext::new(); - - let task_ran = Rc::new(RefCell::new(false)); - - // Spawn a task that waits for a timer - { - let task_ran = task_ran.clone(); - let executor = cx.background_executor.clone(); - cx.update(|cx| { - cx.spawn(async move |_| { - executor.timer(Duration::from_millis(500)).await; - *task_ran.borrow_mut() = true; - }) - .detach(); - }); - } - - // Run until parked - the task should be waiting on the timer - cx.run_until_parked(); - assert!(!*task_ran.borrow()); - - // Advance clock past the timer duration - cx.advance_clock(Duration::from_millis(600)); - - // Now the task should have completed - assert!(*task_ran.borrow()); - } - - #[test] - #[ignore] // Requires macOS main thread - window creation fails on test threads - fn test_window_spawn_uses_test_dispatcher() { - let mut cx = VisualTestAppContext::new(); - - let task_ran = Rc::new(RefCell::new(false)); - - let window = cx - .open_offscreen_window_default(|_, cx| cx.new(|_| Empty)) - .expect("Failed to open window"); - - // Spawn a task via window.spawn - this is the critical test case - // for tooltip behavior, as tooltips use window.spawn for delayed show - { - let task_ran = task_ran.clone(); - cx.update_window(window.into(), |_, window, cx| { - window - .spawn(cx, async move |_| { - *task_ran.borrow_mut() = true; - }) - .detach(); - }) - .ok(); - } - - // The task should not have run yet - assert!(!*task_ran.borrow()); - - // Run until parked should execute the foreground task spawned via window - cx.run_until_parked(); - - // Now the task should have run - assert!(*task_ran.borrow()); - } -} diff --git a/crates/gpui/src/assets.rs b/crates/gpui/src/assets.rs index 8930b58f8d4fc0423b7d6f41755189a03d8b8b84..231a571ecde5d6cd8c4d6da89d375c0db0de0b17 100644 --- a/crates/gpui/src/assets.rs +++ b/crates/gpui/src/assets.rs @@ -33,9 +33,10 @@ impl AssetSource for () { pub struct ImageId(pub usize); #[derive(PartialEq, Eq, Hash, Clone)] -pub(crate) struct RenderImageParams { - pub(crate) image_id: ImageId, - pub(crate) frame_index: usize, +#[expect(missing_docs)] +pub struct RenderImageParams { + pub image_id: ImageId, + pub frame_index: usize, } /// A cached and processed image, in BGRA format diff --git a/crates/gpui/src/color.rs b/crates/gpui/src/color.rs index 86af97c8279406f2f1830a02462c00d53050802c..bb41a2f996e250b8c73377922f81170bb432321f 100644 --- a/crates/gpui/src/color.rs +++ b/crates/gpui/src/color.rs @@ -23,7 +23,7 @@ pub fn rgba(hex: u32) -> Rgba { } /// Swap from RGBA with premultiplied alpha to BGRA -pub(crate) fn swap_rgba_pa_to_bgra(color: &mut [u8]) { +pub fn swap_rgba_pa_to_bgra(color: &mut [u8]) { color.swap(0, 2); if color[3] > 0 { let a = color[3] as f32 / 255.; diff --git a/crates/gpui/src/geometry.rs b/crates/gpui/src/geometry.rs index 6d9a4fe281576a02aef9caaf7b91d5e28445e2c0..73fa9906267412c9f1c840d8403beeef4718119e 100644 --- a/crates/gpui/src/geometry.rs +++ b/crates/gpui/src/geometry.rs @@ -1592,7 +1592,7 @@ impl> Disp impl Size { /// Converts the size from physical to logical pixels. - pub(crate) fn to_pixels(self, scale_factor: f32) -> Size { + pub fn to_pixels(self, scale_factor: f32) -> Size { size( px(self.width.0 as f32 / scale_factor), px(self.height.0 as f32 / scale_factor), @@ -1602,7 +1602,7 @@ impl Size { impl Size { /// Converts the size from logical to physical pixels. - pub(crate) fn to_device_pixels(self, scale_factor: f32) -> Size { + pub fn to_device_pixels(self, scale_factor: f32) -> Size { size( DevicePixels((self.width.0 * scale_factor).round() as i32), DevicePixels((self.height.0 * scale_factor).round() as i32), @@ -2683,6 +2683,11 @@ impl Pixels { /// The minimum value that can be represented by `Pixels`. pub const MIN: Pixels = Pixels(f32::MIN); + /// Returns the raw `f32` value of this `Pixels`. + pub fn as_f32(self) -> f32 { + self.0 + } + /// Floors the `Pixels` value to the nearest whole number. /// /// # Returns @@ -2964,9 +2969,14 @@ impl From for DevicePixels { /// display resolutions. #[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, DivAssign, PartialEq)] #[repr(transparent)] -pub struct ScaledPixels(pub(crate) f32); +pub struct ScaledPixels(pub f32); impl ScaledPixels { + /// Returns the raw `f32` value of this `ScaledPixels`. + pub fn as_f32(self) -> f32 { + self.0 + } + /// Floors the `ScaledPixels` value to the nearest whole number. /// /// # Returns diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index 8398874ea257a41cbd0138c2ce113dda9c4422e5..7e2f0a981493cc12bca9f02e47a90ed6d6f21595 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -5,7 +5,8 @@ #![allow(unused_mut)] // False positives in platform specific code extern crate self as gpui; - +#[doc(hidden)] +pub static GPUI_MANIFEST_DIR: &'static str = env!("CARGO_MANIFEST_DIR"); #[macro_use] mod action; mod app; @@ -32,9 +33,11 @@ mod keymap; mod path_builder; mod platform; pub mod prelude; -mod profiler; +/// Profiling utilities for task timing and thread performance tracking. +pub mod profiler; #[cfg(any(target_os = "windows", target_os = "linux"))] -mod queue; +#[expect(missing_docs)] +pub mod queue; mod scene; mod shared_string; mod shared_uri; @@ -94,7 +97,7 @@ pub use path_builder::*; pub use platform::*; pub use profiler::*; #[cfg(any(target_os = "windows", target_os = "linux"))] -pub(crate) use queue::{PriorityQueueReceiver, PriorityQueueSender}; +pub use queue::{PriorityQueueReceiver, PriorityQueueSender}; pub use refineable::*; pub use scene::*; pub use shared_string::*; diff --git a/crates/gpui/src/interactive.rs b/crates/gpui/src/interactive.rs index bfa3196adb41f1703e911ee546b37e3ae9b168fe..5316a5992bb41d11ef5b6518555a9a20795f894c 100644 --- a/crates/gpui/src/interactive.rs +++ b/crates/gpui/src/interactive.rs @@ -557,7 +557,7 @@ impl Deref for MouseExitEvent { /// A collection of paths from the platform, such as from a file drop. #[derive(Debug, Clone, Default, Eq, PartialEq)] -pub struct ExternalPaths(pub(crate) SmallVec<[PathBuf; 2]>); +pub struct ExternalPaths(pub SmallVec<[PathBuf; 2]>); impl ExternalPaths { /// Convert this collection of paths into a slice. diff --git a/crates/gpui/src/keymap/context.rs b/crates/gpui/src/keymap/context.rs index 960bd1752fe8c1527b9c593658e429af4cd61029..f47ab307b6ba133bdfd40094322776f4c98a905c 100644 --- a/crates/gpui/src/keymap/context.rs +++ b/crates/gpui/src/keymap/context.rs @@ -262,7 +262,7 @@ impl KeyBindingContextPredicate { /// Eval a predicate against a set of contexts, arranged from lowest to highest. #[allow(unused)] - pub(crate) fn eval(&self, contexts: &[KeyContext]) -> bool { + pub fn eval(&self, contexts: &[KeyContext]) -> bool { self.eval_inner(contexts, contexts) } diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index ac277ff423b4403f4dfc4066c9f742bc8dc82499..401c70ea488a8896151de047c04898f4f6b7e15a 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -2,17 +2,9 @@ mod app_menu; mod keyboard; mod keystroke; -#[cfg(any(target_os = "linux", target_os = "freebsd"))] -mod linux; - -#[cfg(target_os = "macos")] -mod mac; - -#[cfg(all( - any(target_os = "linux", target_os = "freebsd"), - any(feature = "wayland", feature = "x11") -))] -mod wgpu; +#[cfg(all(target_os = "linux", feature = "wayland"))] +#[expect(missing_docs)] +pub mod layer_shell; #[cfg(any(test, feature = "test-support"))] mod test; @@ -20,14 +12,21 @@ mod test; #[cfg(all(target_os = "macos", any(test, feature = "test-support")))] mod visual_test; -#[cfg(target_os = "windows")] -mod windows; - #[cfg(all( feature = "screen-capture", any(target_os = "windows", target_os = "linux", target_os = "freebsd",) ))] -pub(crate) mod scap_screen_capture; +pub mod scap_screen_capture; + +#[cfg(all( + any(target_os = "windows", target_os = "linux"), + feature = "screen-capture" +))] +pub(crate) type PlatformScreenCaptureFrame = scap::frame::Frame; +#[cfg(not(feature = "screen-capture"))] +pub(crate) type PlatformScreenCaptureFrame = (); +#[cfg(all(target_os = "macos", feature = "screen-capture"))] +pub(crate) type PlatformScreenCaptureFrame = core_video::image_buffer::CVImageBuffer; use crate::{ Action, AnyWindowHandle, App, AsyncWindowContext, BackgroundExecutor, Bounds, @@ -69,17 +68,8 @@ pub use app_menu::*; pub use keyboard::*; pub use keystroke::*; -#[cfg(any(target_os = "linux", target_os = "freebsd"))] -pub(crate) use linux::*; -#[cfg(target_os = "macos")] -pub(crate) use mac::*; #[cfg(any(test, feature = "test-support"))] pub(crate) use test::*; -#[cfg(target_os = "windows")] -pub(crate) use windows::*; - -#[cfg(all(target_os = "linux", feature = "wayland"))] -pub use linux::layer_shell; #[cfg(any(test, feature = "test-support"))] pub use test::{TestDispatcher, TestScreenCaptureSource, TestScreenCaptureStream}; @@ -87,52 +77,8 @@ pub use test::{TestDispatcher, TestScreenCaptureSource, TestScreenCaptureStream} #[cfg(all(target_os = "macos", any(test, feature = "test-support")))] pub use visual_test::VisualTestPlatform; -/// Returns a background executor for the current platform. -pub fn background_executor() -> BackgroundExecutor { - current_platform(true).background_executor() -} - -#[cfg(target_os = "macos")] -pub(crate) fn current_platform(headless: bool) -> Rc { - Rc::new(MacPlatform::new(headless)) -} - -#[cfg(any(target_os = "linux", target_os = "freebsd"))] -pub(crate) fn current_platform(headless: bool) -> Rc { - #[cfg(feature = "x11")] - use anyhow::Context as _; - - if headless { - return Rc::new(HeadlessClient::new()); - } - - match guess_compositor() { - #[cfg(feature = "wayland")] - "Wayland" => Rc::new(WaylandClient::new()), - - #[cfg(feature = "x11")] - "X11" => Rc::new( - X11Client::new() - .context("Failed to initialize X11 client.") - .unwrap(), - ), - - "Headless" => Rc::new(HeadlessClient::new()), - _ => unreachable!(), - } -} - -#[cfg(target_os = "windows")] -pub(crate) fn current_platform(headless: bool) -> Rc { - Rc::new( - WindowsPlatform::new(headless) - .inspect_err(|err| show_error("Failed to launch", err.to_string())) - .unwrap(), - ) -} - /// Return which compositor we're guessing we'll use. -/// Does not attempt to connect to the given compositor +/// Does not attempt to connect to the given compositor. #[cfg(any(target_os = "linux", target_os = "freebsd"))] #[inline] pub fn guess_compositor() -> &'static str { @@ -162,7 +108,8 @@ pub fn guess_compositor() -> &'static str { } } -pub(crate) trait Platform: 'static { +#[expect(missing_docs)] +pub trait Platform: 'static { fn background_executor(&self) -> BackgroundExecutor; fn foreground_executor(&self) -> ForegroundExecutor; fn text_system(&self) -> Arc; @@ -182,16 +129,10 @@ pub(crate) trait Platform: 'static { None } - #[cfg(feature = "screen-capture")] - fn is_screen_capture_supported(&self) -> bool; - #[cfg(not(feature = "screen-capture"))] fn is_screen_capture_supported(&self) -> bool { false } - #[cfg(feature = "screen-capture")] - fn screen_capture_sources(&self) - -> oneshot::Receiver>>>; - #[cfg(not(feature = "screen-capture"))] + fn screen_capture_sources( &self, ) -> oneshot::Receiver>>> { @@ -370,6 +311,19 @@ pub struct ScreenCaptureFrame(pub PlatformScreenCaptureFrame); #[derive(PartialEq, Eq, Hash, Copy, Clone)] pub struct DisplayId(pub(crate) u32); +impl DisplayId { + /// Create a new `DisplayId` from a raw platform display identifier. + pub fn new(id: u32) -> Self { + Self(id) + } +} + +impl From for DisplayId { + fn from(id: u32) -> Self { + Self(id) + } +} + impl From for u32 { fn from(id: DisplayId) -> Self { id.0 @@ -482,13 +436,16 @@ impl Tiling { } #[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] -pub(crate) struct RequestFrameOptions { - pub(crate) require_presentation: bool, - /// Force refresh of all rendering states when true - pub(crate) force_render: bool, +#[expect(missing_docs)] +pub struct RequestFrameOptions { + /// Whether a presentation is required. + pub require_presentation: bool, + /// Force refresh of all rendering states when true. + pub force_render: bool, } -pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle { +#[expect(missing_docs)] +pub trait PlatformWindow: HasWindowHandle + HasDisplayHandle { fn bounds(&self) -> Bounds; fn is_maximized(&self) -> bool; fn window_bounds(&self) -> WindowBounds; @@ -558,7 +515,7 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle { fn set_tabbing_identifier(&self, _identifier: Option) {} #[cfg(target_os = "windows")] - fn get_raw_handle(&self) -> windows::HWND; + fn get_raw_handle(&self) -> windows::Win32::Foundation::HWND; // Linux specific methods fn inner_window_bounds(&self) -> WindowBounds { @@ -603,17 +560,7 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle { pub type RunnableVariant = Runnable; #[doc(hidden)] -pub struct TimerResolutionGuard { - cleanup: Option>, -} - -impl Drop for TimerResolutionGuard { - fn drop(&mut self) { - if let Some(cleanup) = self.cleanup.take() { - cleanup(); - } - } -} +pub type TimerResolutionGuard = util::Deferred>; /// This type is public so that our test macro can generate and use it, but it should not /// be considered part of our public API. @@ -632,7 +579,7 @@ pub trait PlatformDispatcher: Send + Sync { } fn increase_timer_resolution(&self) -> TimerResolutionGuard { - TimerResolutionGuard { cleanup: None } + util::defer(Box::new(|| {})) } #[cfg(any(test, feature = "test-support"))] @@ -641,7 +588,8 @@ pub trait PlatformDispatcher: Send + Sync { } } -pub(crate) trait PlatformTextSystem: Send + Sync { +#[expect(missing_docs)] +pub trait PlatformTextSystem: Send + Sync { fn add_fonts(&self, fonts: Vec>) -> Result<()>; fn all_font_names(&self) -> Vec; fn font_id(&self, descriptor: &Font) -> Result; @@ -660,8 +608,10 @@ pub(crate) trait PlatformTextSystem: Send + Sync { -> TextRenderingMode; } -pub(crate) struct NoopTextSystem; +#[expect(missing_docs)] +pub struct NoopTextSystem; +#[expect(missing_docs)] impl NoopTextSystem { #[allow(dead_code)] pub fn new() -> Self { @@ -791,8 +741,9 @@ impl PlatformTextSystem for NoopTextSystem { // Adapted from https://github.com/microsoft/terminal/blob/1283c0f5b99a2961673249fa77c6b986efb5086c/src/renderer/atlas/dwrite.cpp // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +/// Compute gamma correction ratios for subpixel text rendering. #[allow(dead_code)] -pub(crate) fn get_gamma_correction_ratios(gamma: f32) -> [f32; 4] { +pub fn get_gamma_correction_ratios(gamma: f32) -> [f32; 4] { const GAMMA_INCORRECT_TARGET_RATIOS: [[f32; 4]; 13] = [ [0.0000 / 4.0, 0.0000 / 4.0, 0.0000 / 4.0, 0.0000 / 4.0], // gamma = 1.0 [0.0166 / 4.0, -0.0807 / 4.0, 0.2227 / 4.0, -0.0751 / 4.0], // gamma = 1.1 @@ -824,7 +775,8 @@ pub(crate) fn get_gamma_correction_ratios(gamma: f32) -> [f32; 4] { } #[derive(PartialEq, Eq, Hash, Clone)] -pub(crate) enum AtlasKey { +#[expect(missing_docs)] +pub enum AtlasKey { Glyph(RenderGlyphParams), Svg(RenderSvgParams), Image(RenderImageParams), @@ -838,7 +790,8 @@ impl AtlasKey { ), allow(dead_code) )] - pub(crate) fn texture_kind(&self) -> AtlasTextureKind { + /// Returns the texture kind for this atlas key. + pub fn texture_kind(&self) -> AtlasTextureKind { match self { AtlasKey::Glyph(params) => { if params.is_emoji { @@ -873,7 +826,8 @@ impl From for AtlasKey { } } -pub(crate) trait PlatformAtlas: Send + Sync { +#[expect(missing_docs)] +pub trait PlatformAtlas: Send + Sync { fn get_or_insert_with<'a>( &self, key: &AtlasKey, @@ -882,9 +836,10 @@ pub(crate) trait PlatformAtlas: Send + Sync { fn remove(&self, key: &AtlasKey); } -struct AtlasTextureList { - textures: Vec>, - free_list: Vec, +#[doc(hidden)] +pub struct AtlasTextureList { + pub textures: Vec>, + pub free_list: Vec, } impl Default for AtlasTextureList { @@ -906,32 +861,40 @@ impl ops::Index for AtlasTextureList { impl AtlasTextureList { #[allow(unused)] - fn drain(&mut self) -> std::vec::Drain<'_, Option> { + pub fn drain(&mut self) -> std::vec::Drain<'_, Option> { self.free_list.clear(); self.textures.drain(..) } #[allow(dead_code)] - fn iter_mut(&mut self) -> impl DoubleEndedIterator { + pub fn iter_mut(&mut self) -> impl DoubleEndedIterator { self.textures.iter_mut().flatten() } } #[derive(Clone, Debug, PartialEq, Eq)] #[repr(C)] -pub(crate) struct AtlasTile { - pub(crate) texture_id: AtlasTextureId, - pub(crate) tile_id: TileId, - pub(crate) padding: u32, - pub(crate) bounds: Bounds, +#[expect(missing_docs)] +pub struct AtlasTile { + /// The texture this tile belongs to. + pub texture_id: AtlasTextureId, + /// The unique ID of this tile within its texture. + pub tile_id: TileId, + /// Padding around the tile content in pixels. + pub padding: u32, + /// The bounds of this tile within the texture. + pub bounds: Bounds, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[repr(C)] -pub(crate) struct AtlasTextureId { +#[expect(missing_docs)] +pub struct AtlasTextureId { // We use u32 instead of usize for Metal Shader Language compatibility - pub(crate) index: u32, - pub(crate) kind: AtlasTextureKind, + /// The index of this texture in the atlas. + pub index: u32, + /// The kind of content stored in this texture. + pub kind: AtlasTextureKind, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -943,7 +906,8 @@ pub(crate) struct AtlasTextureId { ), allow(dead_code) )] -pub(crate) enum AtlasTextureKind { +#[expect(missing_docs)] +pub enum AtlasTextureKind { Monochrome = 0, Polychrome = 1, Subpixel = 2, @@ -951,7 +915,8 @@ pub(crate) enum AtlasTextureKind { #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[repr(C)] -pub(crate) struct TileId(pub(crate) u32); +#[expect(missing_docs)] +pub struct TileId(pub u32); impl From for TileId { fn from(id: etagere::AllocId) -> Self { @@ -965,11 +930,13 @@ impl From for etagere::AllocId { } } -pub(crate) struct PlatformInputHandler { +#[expect(missing_docs)] +pub struct PlatformInputHandler { cx: AsyncWindowContext, handler: Box, } +#[expect(missing_docs)] #[cfg_attr( all( any(target_os = "linux", target_os = "freebsd"), @@ -982,7 +949,7 @@ impl PlatformInputHandler { Self { cx, handler } } - fn selected_text_range(&mut self, ignore_disabled_input: bool) -> Option { + pub fn selected_text_range(&mut self, ignore_disabled_input: bool) -> Option { self.cx .update(|window, cx| { self.handler @@ -993,7 +960,7 @@ impl PlatformInputHandler { } #[cfg_attr(target_os = "windows", allow(dead_code))] - fn marked_text_range(&mut self) -> Option> { + pub fn marked_text_range(&mut self) -> Option> { self.cx .update(|window, cx| self.handler.marked_text_range(window, cx)) .ok() @@ -1004,7 +971,7 @@ impl PlatformInputHandler { any(target_os = "linux", target_os = "freebsd", target_os = "windows"), allow(dead_code) )] - fn text_for_range( + pub fn text_for_range( &mut self, range_utf16: Range, adjusted: &mut Option>, @@ -1018,7 +985,7 @@ impl PlatformInputHandler { .flatten() } - fn replace_text_in_range(&mut self, replacement_range: Option>, text: &str) { + pub fn replace_text_in_range(&mut self, replacement_range: Option>, text: &str) { self.cx .update(|window, cx| { self.handler @@ -1047,13 +1014,13 @@ impl PlatformInputHandler { } #[cfg_attr(target_os = "windows", allow(dead_code))] - fn unmark_text(&mut self) { + pub fn unmark_text(&mut self) { self.cx .update(|window, cx| self.handler.unmark_text(window, cx)) .ok(); } - fn bounds_for_range(&mut self, range_utf16: Range) -> Option> { + pub fn bounds_for_range(&mut self, range_utf16: Range) -> Option> { self.cx .update(|window, cx| self.handler.bounds_for_range(range_utf16, window, cx)) .ok() @@ -1061,11 +1028,11 @@ impl PlatformInputHandler { } #[allow(dead_code)] - fn apple_press_and_hold_enabled(&mut self) -> bool { + pub fn apple_press_and_hold_enabled(&mut self) -> bool { self.handler.apple_press_and_hold_enabled() } - pub(crate) fn dispatch_input(&mut self, input: &str, window: &mut Window, cx: &mut App) { + pub fn dispatch_input(&mut self, input: &str, window: &mut Window, cx: &mut App) { self.handler.replace_text_in_range(None, input, window, cx); } @@ -1091,7 +1058,7 @@ impl PlatformInputHandler { } #[allow(dead_code)] - pub(crate) fn accepts_text_input(&mut self, window: &mut Window, cx: &mut App) -> bool { + pub fn accepts_text_input(&mut self, window: &mut Window, cx: &mut App) -> bool { self.handler.accepts_text_input(window, cx) } } @@ -1268,7 +1235,8 @@ pub struct WindowOptions { ), allow(dead_code) )] -pub(crate) struct WindowParams { +#[expect(missing_docs)] +pub struct WindowParams { pub bounds: Bounds, /// The titlebar configuration of the window @@ -1523,8 +1491,9 @@ impl PromptButton { PromptButton::Cancel(label.into()) } + /// Returns true if this button is a cancel button. #[allow(dead_code)] - pub(crate) fn is_cancel(&self) -> bool { + pub fn is_cancel(&self) -> bool { matches!(self, PromptButton::Cancel(_)) } @@ -1642,7 +1611,8 @@ pub enum CursorStyle { /// A clipboard item that should be copied to the clipboard #[derive(Clone, Debug, Eq, PartialEq)] pub struct ClipboardItem { - entries: Vec, + /// The entries in this clipboard item. + pub entries: Vec, } /// Either a ClipboardString or a ClipboardImage @@ -1842,7 +1812,7 @@ pub struct Image { /// The raw image bytes pub bytes: Vec, /// The unique ID for the image - id: u64, + pub id: u64, } impl Hash for Image { @@ -1960,8 +1930,10 @@ impl Image { /// A clipboard item that should be copied to the clipboard #[derive(Clone, Debug, Eq, PartialEq)] pub struct ClipboardString { - pub(crate) text: String, - pub(crate) metadata: Option, + /// The text content. + pub text: String, + /// Optional metadata associated with this clipboard string. + pub metadata: Option, } impl ClipboardString { @@ -2001,7 +1973,8 @@ impl ClipboardString { } #[cfg_attr(any(target_os = "linux", target_os = "freebsd"), allow(dead_code))] - pub(crate) fn text_hash(text: &str) -> u64 { + /// Compute a hash of the given text for clipboard change detection. + pub fn text_hash(text: &str) -> u64 { let mut hasher = SeaHasher::new(); text.hash(&mut hasher); hasher.finish() diff --git a/crates/gpui/src/platform/keystroke.rs b/crates/gpui/src/platform/keystroke.rs index e1f1b0c9fbba5367eaabc5ca2de920a3eebdd4ca..c45c7c1b335addf2c91df2a45a04d5c958910ec7 100644 --- a/crates/gpui/src/platform/keystroke.rs +++ b/crates/gpui/src/platform/keystroke.rs @@ -265,7 +265,8 @@ impl Keystroke { impl KeybindingKeystroke { #[cfg(target_os = "windows")] - pub(crate) fn new(inner: Keystroke, display_modifiers: Modifiers, display_key: String) -> Self { + #[expect(missing_docs)] + pub fn new(inner: Keystroke, display_modifiers: Modifiers, display_key: String) -> Self { KeybindingKeystroke { inner, display_modifiers, diff --git a/crates/gpui/src/platform/linux/wayland/layer_shell.rs b/crates/gpui/src/platform/layer_shell.rs similarity index 76% rename from crates/gpui/src/platform/linux/wayland/layer_shell.rs rename to crates/gpui/src/platform/layer_shell.rs index 0f165ed8e0ca2c1ec8d5b7c4cbdfea6cb5eec71b..8be1b5fcdb46c98acb80e6970edbc5a856f180bb 100644 --- a/crates/gpui/src/platform/linux/wayland/layer_shell.rs +++ b/crates/gpui/src/platform/layer_shell.rs @@ -1,6 +1,5 @@ use bitflags::bitflags; use thiserror::Error; -use wayland_protocols_wlr::layer_shell::v1::client::{zwlr_layer_shell_v1, zwlr_layer_surface_v1}; use crate::Pixels; @@ -22,17 +21,6 @@ pub enum Layer { Overlay, } -impl From for zwlr_layer_shell_v1::Layer { - fn from(layer: Layer) -> Self { - match layer { - Layer::Background => Self::Background, - Layer::Bottom => Self::Bottom, - Layer::Top => Self::Top, - Layer::Overlay => Self::Overlay, - } - } -} - bitflags! { /// Screen anchor point for layer_shell surfaces. These can be used in any combination, e.g. /// specifying `Anchor::LEFT | Anchor::RIGHT` will stretch the surface across the width of the @@ -50,12 +38,6 @@ bitflags! { } } -impl From for zwlr_layer_surface_v1::Anchor { - fn from(anchor: Anchor) -> Self { - Self::from_bits_truncate(anchor.bits()) - } -} - /// Keyboard interactivity mode for the layer_shell surfaces. #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub enum KeyboardInteractivity { @@ -72,16 +54,6 @@ pub enum KeyboardInteractivity { OnDemand, } -impl From for zwlr_layer_surface_v1::KeyboardInteractivity { - fn from(value: KeyboardInteractivity) -> Self { - match value { - KeyboardInteractivity::None => Self::None, - KeyboardInteractivity::Exclusive => Self::Exclusive, - KeyboardInteractivity::OnDemand => Self::OnDemand, - } - } -} - /// Options for creating a layer_shell window. #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct LayerShellOptions { diff --git a/crates/gpui/src/platform/linux.rs b/crates/gpui/src/platform/linux.rs deleted file mode 100644 index f7d7ed0ebaa4165065f9963ee1be6d05601cf4ce..0000000000000000000000000000000000000000 --- a/crates/gpui/src/platform/linux.rs +++ /dev/null @@ -1,32 +0,0 @@ -mod dispatcher; -mod headless; -mod keyboard; -mod platform; -#[cfg(any(feature = "wayland", feature = "x11"))] -mod text_system; -#[cfg(feature = "wayland")] -mod wayland; -#[cfg(feature = "x11")] -mod x11; - -#[cfg(any(feature = "wayland", feature = "x11"))] -mod xdg_desktop_portal; - -pub(crate) use dispatcher::*; -pub(crate) use headless::*; -pub(crate) use keyboard::*; -pub(crate) use platform::*; -#[cfg(any(feature = "wayland", feature = "x11"))] -pub(crate) use text_system::*; -#[cfg(feature = "wayland")] -pub(crate) use wayland::*; -#[cfg(feature = "x11")] -pub(crate) use x11::*; - -#[cfg(all(feature = "screen-capture", any(feature = "wayland", feature = "x11")))] -pub(crate) type PlatformScreenCaptureFrame = scap::frame::Frame; -#[cfg(not(all(feature = "screen-capture", any(feature = "wayland", feature = "x11"))))] -pub(crate) type PlatformScreenCaptureFrame = (); - -#[cfg(feature = "wayland")] -pub use wayland::layer_shell; diff --git a/crates/gpui/src/platform/linux/wayland.rs b/crates/gpui/src/platform/linux/wayland.rs deleted file mode 100644 index 366b5703e448522a59d397e00cbd268951cb1873..0000000000000000000000000000000000000000 --- a/crates/gpui/src/platform/linux/wayland.rs +++ /dev/null @@ -1,49 +0,0 @@ -mod client; -mod clipboard; -mod cursor; -mod display; -mod serial; -mod window; - -/// Contains Types for configuring layer_shell surfaces. -pub mod layer_shell; - -pub(crate) use client::*; - -use wayland_protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::Shape; - -use crate::CursorStyle; - -impl CursorStyle { - pub(super) fn to_shape(self) -> Shape { - match self { - CursorStyle::Arrow => Shape::Default, - CursorStyle::IBeam => Shape::Text, - CursorStyle::Crosshair => Shape::Crosshair, - CursorStyle::ClosedHand => Shape::Grabbing, - CursorStyle::OpenHand => Shape::Grab, - CursorStyle::PointingHand => Shape::Pointer, - CursorStyle::ResizeLeft => Shape::WResize, - CursorStyle::ResizeRight => Shape::EResize, - CursorStyle::ResizeLeftRight => Shape::EwResize, - CursorStyle::ResizeUp => Shape::NResize, - CursorStyle::ResizeDown => Shape::SResize, - CursorStyle::ResizeUpDown => Shape::NsResize, - CursorStyle::ResizeUpLeftDownRight => Shape::NwseResize, - CursorStyle::ResizeUpRightDownLeft => Shape::NeswResize, - CursorStyle::ResizeColumn => Shape::ColResize, - CursorStyle::ResizeRow => Shape::RowResize, - CursorStyle::IBeamCursorForVerticalLayout => Shape::VerticalText, - CursorStyle::OperationNotAllowed => Shape::NotAllowed, - CursorStyle::DragLink => Shape::Alias, - CursorStyle::DragCopy => Shape::Copy, - CursorStyle::ContextualMenu => Shape::ContextMenu, - CursorStyle::None => { - #[cfg(debug_assertions)] - panic!("CursorStyle::None should be handled separately in the client"); - #[cfg(not(debug_assertions))] - Shape::Default - } - } - } -} diff --git a/crates/gpui/src/platform/mac/status_item.rs b/crates/gpui/src/platform/mac/status_item.rs deleted file mode 100644 index a52e6b4ce44981da8e39b36770fd1162000af9de..0000000000000000000000000000000000000000 --- a/crates/gpui/src/platform/mac/status_item.rs +++ /dev/null @@ -1,387 +0,0 @@ -use crate::{ - Scene, - geometry::{ - rect::RectF, - vector::{Vector2F, vec2f}, - }, - platform::{ - self, Event, FontSystem, WindowBounds, - mac::{platform::NSViewLayerContentsRedrawDuringViewResize, renderer::Renderer}, - }, -}; -use cocoa::{ - appkit::{NSScreen, NSSquareStatusItemLength, NSStatusBar, NSStatusItem, NSView, NSWindow}, - base::{YES, id, nil}, - foundation::{NSPoint, NSRect, NSSize}, -}; -use ctor::ctor; -use foreign_types::ForeignTypeRef; -use objc::{ - class, - declare::ClassDecl, - msg_send, - rc::StrongPtr, - runtime::{Class, Object, Protocol, Sel}, - sel, sel_impl, -}; -use std::{ - cell::RefCell, - ffi::c_void, - ptr, - rc::{Rc, Weak}, - sync::Arc, -}; - -use super::screen::Screen; - -static mut VIEW_CLASS: *const Class = ptr::null(); -const STATE_IVAR: &str = "state"; - -#[ctor] -unsafe fn build_classes() { - VIEW_CLASS = { - let mut decl = ClassDecl::new("GPUIStatusItemView", class!(NSView)).unwrap(); - decl.add_ivar::<*mut c_void>(STATE_IVAR); - - decl.add_method(sel!(dealloc), dealloc_view as extern "C" fn(&Object, Sel)); - - decl.add_method( - sel!(mouseDown:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(mouseUp:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(rightMouseDown:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(rightMouseUp:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(otherMouseDown:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(otherMouseUp:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(mouseMoved:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(mouseDragged:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(scrollWheel:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(flagsChanged:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(makeBackingLayer), - make_backing_layer as extern "C" fn(&Object, Sel) -> id, - ); - decl.add_method( - sel!(viewDidChangeEffectiveAppearance), - view_did_change_effective_appearance as extern "C" fn(&Object, Sel), - ); - - decl.add_protocol(Protocol::get("CALayerDelegate").unwrap()); - decl.add_method( - sel!(displayLayer:), - display_layer as extern "C" fn(&Object, Sel, id), - ); - - decl.register() - }; -} - -pub struct StatusItem(Rc>); - -struct StatusItemState { - native_item: StrongPtr, - native_view: StrongPtr, - renderer: Renderer, - scene: Option, - event_callback: Option bool>>, - appearance_changed_callback: Option>, -} - -impl StatusItem { - pub fn add(fonts: Arc) -> Self { - unsafe { - let renderer = Renderer::new(false, fonts); - let status_bar = NSStatusBar::systemStatusBar(nil); - let native_item = - StrongPtr::retain(status_bar.statusItemWithLength_(NSSquareStatusItemLength)); - - let button = native_item.button(); - let _: () = msg_send![button, setHidden: YES]; - - let native_view = msg_send![VIEW_CLASS, alloc]; - let state = Rc::new(RefCell::new(StatusItemState { - native_item, - native_view: StrongPtr::new(native_view), - renderer, - scene: None, - event_callback: None, - appearance_changed_callback: None, - })); - - let parent_view = button.superview().superview(); - NSView::initWithFrame_( - native_view, - NSRect::new(NSPoint::new(0., 0.), NSView::frame(parent_view).size), - ); - (*native_view).set_ivar( - STATE_IVAR, - Weak::into_raw(Rc::downgrade(&state)) as *const c_void, - ); - native_view.setWantsBestResolutionOpenGLSurface_(YES); - native_view.setWantsLayer(YES); - let _: () = msg_send![ - native_view, - setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize - ]; - - parent_view.addSubview_(native_view); - - { - let state = state.borrow(); - let layer = state.renderer.layer(); - let scale_factor = state.scale_factor(); - let size = state.content_size() * scale_factor; - layer.set_contents_scale(scale_factor.into()); - layer.set_drawable_size(metal::CGSize::new(size.x().into(), size.y().into())); - } - - Self(state) - } - } -} - -impl platform::Window for StatusItem { - fn bounds(&self) -> WindowBounds { - self.0.borrow().bounds() - } - - fn content_size(&self) -> Vector2F { - self.0.borrow().content_size() - } - - fn scale_factor(&self) -> f32 { - self.0.borrow().scale_factor() - } - - fn appearance(&self) -> platform::Appearance { - unsafe { - let appearance: id = - msg_send![self.0.borrow().native_item.button(), effectiveAppearance]; - platform::Appearance::from_native(appearance) - } - } - - fn screen(&self) -> Rc { - unsafe { - Rc::new(Screen { - native_screen: self.0.borrow().native_window().screen(), - }) - } - } - - fn mouse_position(&self) -> Vector2F { - unimplemented!() - } - - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { - self - } - - fn set_input_handler(&mut self, _: Box) {} - - fn prompt( - &self, - _: crate::platform::PromptLevel, - _: &str, - _: &[&str], - ) -> postage::oneshot::Receiver { - unimplemented!() - } - - fn activate(&self) { - unimplemented!() - } - - fn set_title(&mut self, _: &str) { - unimplemented!() - } - - fn set_edited(&mut self, _: bool) { - unimplemented!() - } - - fn show_character_palette(&self) { - unimplemented!() - } - - fn minimize(&self) { - unimplemented!() - } - - fn zoom(&self) { - unimplemented!() - } - - fn present_scene(&mut self, scene: Scene) { - self.0.borrow_mut().scene = Some(scene); - unsafe { - let _: () = msg_send![*self.0.borrow().native_view, setNeedsDisplay: YES]; - } - } - - fn toggle_fullscreen(&self) { - unimplemented!() - } - - fn on_event(&mut self, callback: Box bool>) { - self.0.borrow_mut().event_callback = Some(callback); - } - - fn on_active_status_change(&mut self, _: Box) {} - - fn on_resize(&mut self, _: Box) {} - - fn on_fullscreen(&mut self, _: Box) {} - - fn on_moved(&mut self, _: Box) {} - - fn on_should_close(&mut self, _: Box bool>) {} - - fn on_close(&mut self, _: Box) {} - - fn on_appearance_changed(&mut self, callback: Box) { - self.0.borrow_mut().appearance_changed_callback = Some(callback); - } - - fn is_topmost_for_position(&self, _: Vector2F) -> bool { - true - } -} - -impl StatusItemState { - fn bounds(&self) -> WindowBounds { - unsafe { - let window: id = self.native_window(); - let screen_frame = window.screen().visibleFrame(); - let window_frame = NSWindow::frame(window); - let origin = vec2f( - window_frame.origin.x as f32, - (window_frame.origin.y - screen_frame.size.height - window_frame.size.height) - as f32, - ); - let size = vec2f( - window_frame.size.width as f32, - window_frame.size.height as f32, - ); - WindowBounds::Fixed(RectF::new(origin, size)) - } - } - - fn content_size(&self) -> Vector2F { - unsafe { - let NSSize { width, height, .. } = - NSView::frame(self.native_item.button().superview().superview()).size; - vec2f(width as f32, height as f32) - } - } - - fn scale_factor(&self) -> f32 { - unsafe { - let window: id = msg_send![self.native_item.button(), window]; - NSScreen::backingScaleFactor(window.screen()) as f32 - } - } - - pub fn native_window(&self) -> id { - unsafe { msg_send![self.native_item.button(), window] } - } -} - -extern "C" fn dealloc_view(this: &Object, _: Sel) { - unsafe { - drop_state(this); - - let _: () = msg_send![super(this, class!(NSView)), dealloc]; - } -} - -extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { - unsafe { - if let Some(state) = get_state(this).upgrade() { - let mut state_borrow = state.as_ref().borrow_mut(); - if let Some(event) = - Event::from_native(native_event, Some(state_borrow.content_size().y())) - { - if let Some(mut callback) = state_borrow.event_callback.take() { - drop(state_borrow); - callback(event); - state.borrow_mut().event_callback = Some(callback); - } - } - } - } -} - -extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { - if let Some(state) = unsafe { get_state(this).upgrade() } { - let state = state.borrow(); - state.renderer.layer().as_ptr() as id - } else { - nil - } -} - -extern "C" fn display_layer(this: &Object, _: Sel, _: id) { - unsafe { - if let Some(state) = get_state(this).upgrade() { - let mut state = state.borrow_mut(); - if let Some(scene) = state.scene.take() { - state.renderer.render(&scene); - } - } - } -} - -extern "C" fn view_did_change_effective_appearance(this: &Object, _: Sel) { - unsafe { - if let Some(state) = get_state(this).upgrade() { - let mut state_borrow = state.as_ref().borrow_mut(); - if let Some(mut callback) = state_borrow.appearance_changed_callback.take() { - drop(state_borrow); - callback(); - state.borrow_mut().appearance_changed_callback = Some(callback); - } - } - } -} - -unsafe fn get_state(object: &Object) -> Weak> { - let raw: *mut c_void = *object.get_ivar(STATE_IVAR); - let weak1 = Weak::from_raw(raw as *mut RefCell); - let weak2 = weak1.clone(); - let _ = Weak::into_raw(weak1); - weak2 -} - -unsafe fn drop_state(object: &Object) { - let raw: *const c_void = *object.get_ivar(STATE_IVAR); - Weak::from_raw(raw as *const RefCell); -} diff --git a/crates/gpui/src/platform/mac/window_appearance.rs b/crates/gpui/src/platform/mac/window_appearance.rs deleted file mode 100644 index 65c409d30ce4f162001dd1c0256b9c55839d208a..0000000000000000000000000000000000000000 --- a/crates/gpui/src/platform/mac/window_appearance.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::WindowAppearance; -use cocoa::{ - appkit::{NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight}, - base::id, - foundation::NSString, -}; -use objc::{msg_send, sel, sel_impl}; -use std::ffi::CStr; - -impl WindowAppearance { - pub(crate) unsafe fn from_native(appearance: id) -> Self { - let name: id = msg_send![appearance, name]; - unsafe { - if name == NSAppearanceNameVibrantLight { - Self::VibrantLight - } else if name == NSAppearanceNameVibrantDark { - Self::VibrantDark - } else if name == NSAppearanceNameAqua { - Self::Light - } else if name == NSAppearanceNameDarkAqua { - Self::Dark - } else { - println!( - "unknown appearance: {:?}", - CStr::from_ptr(name.UTF8String()) - ); - Self::Light - } - } - } -} - -#[link(name = "AppKit", kind = "framework")] -unsafe extern "C" { - pub static NSAppearanceNameAqua: id; - pub static NSAppearanceNameDarkAqua: id; -} diff --git a/crates/gpui/src/platform/scap_screen_capture.rs b/crates/gpui/src/platform/scap_screen_capture.rs index d6d19cd8102d58ceaa9bc87bff348eaeda9adfef..2c827bb0d80b330440f050b01c024faa700329ad 100644 --- a/crates/gpui/src/platform/scap_screen_capture.rs +++ b/crates/gpui/src/platform/scap_screen_capture.rs @@ -15,7 +15,7 @@ use std::sync::atomic::{self, AtomicBool}; /// `scap_default_target_source` should be used instead on Wayland, since `scap_screen_sources` /// won't return any results. #[allow(dead_code)] -pub(crate) fn scap_screen_sources( +pub fn scap_screen_sources( foreground_executor: &ForegroundExecutor, ) -> oneshot::Receiver>>> { let (sources_tx, sources_rx) = oneshot::channel(); diff --git a/crates/gpui/src/platform/test/platform.rs b/crates/gpui/src/platform/test/platform.rs index 06963ba23cb291f601297aa5b682e7ed1c85fee8..1da42f5742215f9001dcbd09cc42977ea28623ea 100644 --- a/crates/gpui/src/platform/test/platform.rs +++ b/crates/gpui/src/platform/test/platform.rs @@ -15,11 +15,6 @@ use std::{ rc::{Rc, Weak}, sync::Arc, }; -#[cfg(target_os = "windows")] -use windows::Win32::{ - Graphics::Imaging::{CLSID_WICImagingFactory, IWICImagingFactory}, - System::Com::{CLSCTX_INPROC_SERVER, CoCreateInstance}, -}; /// TestPlatform implements the Platform trait for use in tests. pub(crate) struct TestPlatform { @@ -39,8 +34,6 @@ pub(crate) struct TestPlatform { pub opened_url: RefCell>, pub text_system: Arc, pub expect_restart: RefCell>>>, - #[cfg(target_os = "windows")] - bitmap_factory: std::mem::ManuallyDrop, weak: Weak, } @@ -95,16 +88,6 @@ pub(crate) struct TestPrompts { impl TestPlatform { pub fn new(executor: BackgroundExecutor, foreground_executor: ForegroundExecutor) -> Rc { - #[cfg(target_os = "windows")] - let bitmap_factory = unsafe { - windows::Win32::System::Ole::OleInitialize(None) - .expect("unable to initialize Windows OLE"); - std::mem::ManuallyDrop::new( - CoCreateInstance(&CLSID_WICImagingFactory, None, CLSCTX_INPROC_SERVER) - .expect("Error creating bitmap factory."), - ) - }; - let text_system = Arc::new(NoopTextSystem); Rc::new_cyclic(|weak| TestPlatform { @@ -123,8 +106,6 @@ impl TestPlatform { current_find_pasteboard_item: Mutex::new(None), weak: weak.clone(), opened_url: Default::default(), - #[cfg(target_os = "windows")] - bitmap_factory, text_system, }) } @@ -288,12 +269,10 @@ impl Platform for TestPlatform { Some(self.active_display.clone()) } - #[cfg(feature = "screen-capture")] fn is_screen_capture_supported(&self) -> bool { true } - #[cfg(feature = "screen-capture")] fn screen_capture_sources( &self, ) -> oneshot::Receiver>>> { @@ -458,16 +437,6 @@ impl TestScreenCaptureSource { } } -#[cfg(target_os = "windows")] -impl Drop for TestPlatform { - fn drop(&mut self) { - unsafe { - std::mem::ManuallyDrop::drop(&mut self.bitmap_factory); - windows::Win32::System::Ole::OleUninitialize(); - } - } -} - struct TestKeyboardLayout; impl PlatformKeyboardLayout for TestKeyboardLayout { diff --git a/crates/gpui/src/platform/test/window.rs b/crates/gpui/src/platform/test/window.rs index bec52ccb0b3924d6e5233f4834f68f5c108d6735..2c97b5fe087411768f3c039322be00a391e05dfe 100644 --- a/crates/gpui/src/platform/test/window.rs +++ b/crates/gpui/src/platform/test/window.rs @@ -32,7 +32,7 @@ pub(crate) struct TestWindowState { } #[derive(Clone)] -pub(crate) struct TestWindow(pub(crate) Rc>); +pub struct TestWindow(pub(crate) Rc>); impl HasWindowHandle for TestWindow { fn window_handle( @@ -51,7 +51,7 @@ impl HasDisplayHandle for TestWindow { } impl TestWindow { - pub fn new( + pub(crate) fn new( handle: AnyWindowHandle, params: WindowParams, platform: Weak, diff --git a/crates/gpui/src/platform/visual_test.rs b/crates/gpui/src/platform/visual_test.rs index 0329e8b45bf3945be903381bf5ba89f4f350d8b8..0c5e3e6553df47eb9b62128a67a97e765fb1ccf1 100644 --- a/crates/gpui/src/platform/visual_test.rs +++ b/crates/gpui/src/platform/visual_test.rs @@ -9,7 +9,7 @@ use crate::ScreenCaptureSource; use crate::{ AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, ForegroundExecutor, Keymap, - MacPlatform, Menu, MenuItem, OwnedMenu, PathPromptOptions, Platform, PlatformDisplay, + Menu, MenuItem, OwnedMenu, PathPromptOptions, Platform, PlatformDisplay, PlatformKeyboardLayout, PlatformKeyboardMapper, PlatformTextSystem, PlatformWindow, Task, TestDispatcher, WindowAppearance, WindowParams, }; @@ -33,7 +33,7 @@ pub struct VisualTestPlatform { dispatcher: TestDispatcher, background_executor: BackgroundExecutor, foreground_executor: ForegroundExecutor, - mac_platform: MacPlatform, + platform: Rc, clipboard: Mutex>, find_pasteboard: Mutex>, } @@ -42,20 +42,18 @@ impl VisualTestPlatform { /// Creates a new VisualTestPlatform with the given random seed. /// /// The seed is used for deterministic random number generation in the TestDispatcher. - pub fn new(seed: u64) -> Self { + pub fn new(platform: Rc, seed: u64) -> Self { let dispatcher = TestDispatcher::new(seed); let arc_dispatcher = Arc::new(dispatcher.clone()); let background_executor = BackgroundExecutor::new(arc_dispatcher.clone()); let foreground_executor = ForegroundExecutor::new(arc_dispatcher); - let mac_platform = MacPlatform::new(false); - Self { dispatcher, background_executor, foreground_executor, - mac_platform, + platform, clipboard: Mutex::new(None), find_pasteboard: Mutex::new(None), } @@ -77,7 +75,7 @@ impl Platform for VisualTestPlatform { } fn text_system(&self) -> Arc { - self.mac_platform.text_system() + self.platform.text_system() } fn run(&self, _on_finish_launching: Box) { @@ -97,31 +95,29 @@ impl Platform for VisualTestPlatform { fn unhide_other_apps(&self) {} fn displays(&self) -> Vec> { - self.mac_platform.displays() + self.platform.displays() } fn primary_display(&self) -> Option> { - self.mac_platform.primary_display() + self.platform.primary_display() } fn active_window(&self) -> Option { - self.mac_platform.active_window() + self.platform.active_window() } fn window_stack(&self) -> Option> { - self.mac_platform.window_stack() + self.platform.window_stack() } - #[cfg(feature = "screen-capture")] fn is_screen_capture_supported(&self) -> bool { - self.mac_platform.is_screen_capture_supported() + self.platform.is_screen_capture_supported() } - #[cfg(feature = "screen-capture")] fn screen_capture_sources( &self, ) -> oneshot::Receiver>>> { - self.mac_platform.screen_capture_sources() + self.platform.screen_capture_sources() } fn open_window( @@ -129,15 +125,15 @@ impl Platform for VisualTestPlatform { handle: AnyWindowHandle, options: WindowParams, ) -> Result> { - self.mac_platform.open_window(handle, options) + self.platform.open_window(handle, options) } fn window_appearance(&self) -> WindowAppearance { - self.mac_platform.window_appearance() + self.platform.window_appearance() } fn open_url(&self, url: &str) { - self.mac_platform.open_url(url) + self.platform.open_url(url) } fn on_open_urls(&self, _callback: Box)>) {} @@ -170,11 +166,11 @@ impl Platform for VisualTestPlatform { } fn reveal_path(&self, path: &Path) { - self.mac_platform.reveal_path(path) + self.platform.reveal_path(path) } fn open_with_system(&self, path: &Path) { - self.mac_platform.open_with_system(path) + self.platform.open_with_system(path) } fn on_quit(&self, _callback: Box) {} @@ -196,19 +192,19 @@ impl Platform for VisualTestPlatform { fn on_validate_app_menu_command(&self, _callback: Box bool>) {} fn app_path(&self) -> Result { - self.mac_platform.app_path() + self.platform.app_path() } fn path_for_auxiliary_executable(&self, name: &str) -> Result { - self.mac_platform.path_for_auxiliary_executable(name) + self.platform.path_for_auxiliary_executable(name) } fn set_cursor_style(&self, style: CursorStyle) { - self.mac_platform.set_cursor_style(style) + self.platform.set_cursor_style(style) } fn should_auto_hide_scrollbars(&self) -> bool { - self.mac_platform.should_auto_hide_scrollbars() + self.platform.should_auto_hide_scrollbars() } fn read_from_clipboard(&self) -> Option { @@ -242,11 +238,11 @@ impl Platform for VisualTestPlatform { } fn keyboard_layout(&self) -> Box { - self.mac_platform.keyboard_layout() + self.platform.keyboard_layout() } fn keyboard_mapper(&self) -> Rc { - self.mac_platform.keyboard_mapper() + self.platform.keyboard_mapper() } fn on_keyboard_layout_change(&self, _callback: Box) {} diff --git a/crates/gpui/src/platform/wgpu.rs b/crates/gpui/src/platform/wgpu.rs deleted file mode 100644 index cb1bafe04bae1783a6898debb76a2aa8ccd37072..0000000000000000000000000000000000000000 --- a/crates/gpui/src/platform/wgpu.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod wgpu_atlas; -mod wgpu_context; -mod wgpu_renderer; - -pub(crate) use wgpu_atlas::*; -pub(crate) use wgpu_context::*; -pub(crate) use wgpu_renderer::*; diff --git a/crates/gpui/src/profiler.rs b/crates/gpui/src/profiler.rs index 4b7cbfd0e1e63246e094615013da19e6d750283b..0863aa8cdaaa6bb7cbf593adea1fd4d12726acce 100644 --- a/crates/gpui/src/profiler.rs +++ b/crates/gpui/src/profiler.rs @@ -30,7 +30,8 @@ pub struct ThreadTaskTimings { } impl ThreadTaskTimings { - pub(crate) fn convert(timings: &[GlobalThreadTimings]) -> Vec { + /// Convert global thread timings into their structured format. + pub fn convert(timings: &[GlobalThreadTimings]) -> Vec { timings .iter() .filter_map(|t| match t.timings.upgrade() { @@ -245,19 +246,24 @@ impl ProfilingCollector { // Allow 20mb of task timing entries const MAX_TASK_TIMINGS: usize = (20 * 1024 * 1024) / core::mem::size_of::(); -pub(crate) type TaskTimings = circular_buffer::CircularBuffer; -pub(crate) type GuardedTaskTimings = spin::Mutex; +#[doc(hidden)] +pub type TaskTimings = circular_buffer::CircularBuffer; +#[doc(hidden)] +pub type GuardedTaskTimings = spin::Mutex; -pub(crate) struct GlobalThreadTimings { +#[doc(hidden)] +pub struct GlobalThreadTimings { pub thread_id: ThreadId, pub timings: std::sync::Weak, } -pub(crate) static GLOBAL_THREAD_TIMINGS: spin::Mutex> = +#[doc(hidden)] +pub static GLOBAL_THREAD_TIMINGS: spin::Mutex> = spin::Mutex::new(Vec::new()); thread_local! { - pub(crate) static THREAD_TIMINGS: LazyCell> = LazyCell::new(|| { + #[doc(hidden)] + pub static THREAD_TIMINGS: LazyCell> = LazyCell::new(|| { let current_thread = std::thread::current(); let thread_name = current_thread.name(); let thread_id = current_thread.id(); @@ -277,7 +283,8 @@ thread_local! { }); } -pub(crate) struct ThreadTimings { +#[doc(hidden)] +pub struct ThreadTimings { pub thread_name: Option, pub thread_id: ThreadId, pub timings: Box, @@ -285,7 +292,7 @@ pub(crate) struct ThreadTimings { } impl ThreadTimings { - pub(crate) fn new(thread_name: Option, thread_id: ThreadId) -> Self { + pub fn new(thread_name: Option, thread_id: ThreadId) -> Self { ThreadTimings { thread_name, thread_id, @@ -310,8 +317,9 @@ impl Drop for ThreadTimings { } } +#[doc(hidden)] #[allow(dead_code)] // Used by Linux and Windows dispatchers, not macOS -pub(crate) fn add_task_timing(timing: TaskTiming) { +pub fn add_task_timing(timing: TaskTiming) { THREAD_TIMINGS.with(|timings| { let mut timings = timings.lock(); diff --git a/crates/gpui/src/queue.rs b/crates/gpui/src/queue.rs index 99ad07b434cb5424a93239b8e4d295727e027fe0..45712ba27e1c022a0be18056a9df7960ecac380f 100644 --- a/crates/gpui/src/queue.rs +++ b/crates/gpui/src/queue.rs @@ -86,7 +86,8 @@ impl PriorityQueueState { } } -pub(crate) struct PriorityQueueSender { +#[doc(hidden)] +pub struct PriorityQueueSender { state: Arc>, } @@ -95,7 +96,7 @@ impl PriorityQueueSender { Self { state } } - pub(crate) fn send(&self, priority: Priority, item: T) -> Result<(), SendError> { + pub fn send(&self, priority: Priority, item: T) -> Result<(), SendError> { self.state.send(priority, item)?; Ok(()) } @@ -109,7 +110,8 @@ impl Drop for PriorityQueueSender { } } -pub(crate) struct PriorityQueueReceiver { +#[doc(hidden)] +pub struct PriorityQueueReceiver { state: Arc>, rand: SmallRng, disconnected: bool, @@ -128,7 +130,8 @@ impl Clone for PriorityQueueReceiver { } } -pub(crate) struct SendError(T); +#[doc(hidden)] +pub struct SendError(pub T); impl fmt::Debug for SendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -137,11 +140,12 @@ impl fmt::Debug for SendError { } #[derive(Debug)] -pub(crate) struct RecvError; +#[doc(hidden)] +pub struct RecvError; #[allow(dead_code)] impl PriorityQueueReceiver { - pub(crate) fn new() -> (PriorityQueueSender, Self) { + pub fn new() -> (PriorityQueueSender, Self) { let state = PriorityQueueState { queues: parking_lot::Mutex::new(PriorityQueues { high_priority: VecDeque::new(), @@ -175,7 +179,7 @@ impl PriorityQueueReceiver { /// # Errors /// /// If the sender was dropped - pub(crate) fn try_pop(&mut self) -> Result, RecvError> { + pub fn try_pop(&mut self) -> Result, RecvError> { self.pop_inner(false) } @@ -187,13 +191,13 @@ impl PriorityQueueReceiver { /// # Errors /// /// If the sender was dropped - pub(crate) fn pop(&mut self) -> Result { + pub fn pop(&mut self) -> Result { self.pop_inner(true).map(|e| e.unwrap()) } /// Returns an iterator over the elements of the queue /// this iterator will end when all elements have been consumed and will not wait for new ones. - pub(crate) fn try_iter(self) -> TryIter { + pub fn try_iter(self) -> TryIter { TryIter { receiver: self, ended: false, @@ -202,7 +206,7 @@ impl PriorityQueueReceiver { /// Returns an iterator over the elements of the queue /// this iterator will wait for new elements if the queue is empty. - pub(crate) fn iter(self) -> Iter { + pub fn iter(self) -> Iter { Iter(self) } @@ -261,8 +265,8 @@ impl Drop for PriorityQueueReceiver { } } -/// If None is returned the sender disconnected -pub(crate) struct Iter(PriorityQueueReceiver); +#[doc(hidden)] +pub struct Iter(PriorityQueueReceiver); impl Iterator for Iter { type Item = T; @@ -272,8 +276,8 @@ impl Iterator for Iter { } impl FusedIterator for Iter {} -/// If None is returned there are no more elements in the queue -pub(crate) struct TryIter { +#[doc(hidden)] +pub struct TryIter { receiver: PriorityQueueReceiver, ended: bool, } diff --git a/crates/gpui/src/scene.rs b/crates/gpui/src/scene.rs index b5ec2662d29b9af95f36fdfd989733c0e9ddb1e1..7b841da1f231f85073dd20d51769ed406d539ce8 100644 --- a/crates/gpui/src/scene.rs +++ b/crates/gpui/src/scene.rs @@ -16,25 +16,29 @@ use std::{ }; #[allow(non_camel_case_types, unused)] -pub(crate) type PathVertex_ScaledPixels = PathVertex; +#[expect(missing_docs)] +pub type PathVertex_ScaledPixels = PathVertex; -pub(crate) type DrawOrder = u32; +#[expect(missing_docs)] +pub type DrawOrder = u32; #[derive(Default)] -pub(crate) struct Scene { +#[expect(missing_docs)] +pub struct Scene { pub(crate) paint_operations: Vec, primitive_bounds: BoundsTree, layer_stack: Vec, - pub(crate) shadows: Vec, - pub(crate) quads: Vec, - pub(crate) paths: Vec>, - pub(crate) underlines: Vec, - pub(crate) monochrome_sprites: Vec, - pub(crate) subpixel_sprites: Vec, - pub(crate) polychrome_sprites: Vec, - pub(crate) surfaces: Vec, + pub shadows: Vec, + pub quads: Vec, + pub paths: Vec>, + pub underlines: Vec, + pub monochrome_sprites: Vec, + pub subpixel_sprites: Vec, + pub polychrome_sprites: Vec, + pub surfaces: Vec, } +#[expect(missing_docs)] impl Scene { pub fn clear(&mut self) { self.paint_operations.clear(); @@ -151,7 +155,7 @@ impl Scene { ), allow(dead_code) )] - pub(crate) fn batches(&self) -> impl Iterator + '_ { + pub fn batches(&self) -> impl Iterator + '_ { BatchIterator { shadows_start: 0, shadows_iter: self.shadows.iter().peekable(), @@ -200,7 +204,8 @@ pub(crate) enum PaintOperation { } #[derive(Clone)] -pub(crate) enum Primitive { +#[expect(missing_docs)] +pub enum Primitive { Shadow(Shadow), Quad(Quad), Path(Path), @@ -211,6 +216,7 @@ pub(crate) enum Primitive { Surface(PaintSurface), } +#[expect(missing_docs)] impl Primitive { pub fn bounds(&self) -> &Bounds { match self { @@ -453,7 +459,8 @@ impl<'a> Iterator for BatchIterator<'a> { ), allow(dead_code) )] -pub(crate) enum PrimitiveBatch { +#[expect(missing_docs)] +pub enum PrimitiveBatch { Shadows(Range), Quads(Range), Paths(Range), @@ -476,7 +483,8 @@ pub(crate) enum PrimitiveBatch { #[derive(Default, Debug, Clone)] #[repr(C)] -pub(crate) struct Quad { +#[expect(missing_docs)] +pub struct Quad { pub order: DrawOrder, pub border_style: BorderStyle, pub bounds: Bounds, @@ -495,7 +503,8 @@ impl From for Primitive { #[derive(Debug, Clone)] #[repr(C)] -pub(crate) struct Underline { +#[expect(missing_docs)] +pub struct Underline { pub order: DrawOrder, pub pad: u32, // align to 8 bytes pub bounds: Bounds, @@ -513,7 +522,8 @@ impl From for Primitive { #[derive(Debug, Clone)] #[repr(C)] -pub(crate) struct Shadow { +#[expect(missing_docs)] +pub struct Shadow { pub order: DrawOrder, pub blur_radius: ScaledPixels, pub bounds: Bounds, @@ -644,7 +654,8 @@ impl Default for TransformationMatrix { #[derive(Clone, Debug)] #[repr(C)] -pub(crate) struct MonochromeSprite { +#[expect(missing_docs)] +pub struct MonochromeSprite { pub order: DrawOrder, pub pad: u32, // align to 8 bytes pub bounds: Bounds, @@ -662,7 +673,8 @@ impl From for Primitive { #[derive(Clone, Debug)] #[repr(C)] -pub(crate) struct SubpixelSprite { +#[expect(missing_docs)] +pub struct SubpixelSprite { pub order: DrawOrder, pub pad: u32, // align to 8 bytes pub bounds: Bounds, @@ -680,7 +692,8 @@ impl From for Primitive { #[derive(Clone, Debug)] #[repr(C)] -pub(crate) struct PolychromeSprite { +#[expect(missing_docs)] +pub struct PolychromeSprite { pub order: DrawOrder, pub pad: u32, // align to 8 bytes pub grayscale: bool, @@ -698,7 +711,8 @@ impl From for Primitive { } #[derive(Clone, Debug)] -pub(crate) struct PaintSurface { +#[expect(missing_docs)] +pub struct PaintSurface { pub order: DrawOrder, pub bounds: Bounds, pub content_mask: ContentMask, @@ -713,17 +727,19 @@ impl From for Primitive { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub(crate) struct PathId(pub(crate) usize); +#[expect(missing_docs)] +pub struct PathId(pub usize); /// A line made up of a series of vertices and control points. #[derive(Clone, Debug)] +#[expect(missing_docs)] pub struct Path { - pub(crate) id: PathId, - pub(crate) order: DrawOrder, - pub(crate) bounds: Bounds

, - pub(crate) content_mask: ContentMask

, - pub(crate) vertices: Vec>, - pub(crate) color: Background, + pub id: PathId, + pub order: DrawOrder, + pub bounds: Bounds

, + pub content_mask: ContentMask

, + pub vertices: Vec>, + pub color: Background, start: Point

, current: Point

, contour_count: usize, @@ -847,7 +863,8 @@ where T: Clone + Debug + Default + PartialEq + PartialOrd + Add + Sub, { #[allow(unused)] - pub(crate) fn clipped_bounds(&self) -> Bounds { + #[expect(missing_docs)] + pub fn clipped_bounds(&self) -> Bounds { self.bounds.intersect(&self.content_mask.bounds) } } @@ -860,12 +877,14 @@ impl From> for Primitive { #[derive(Clone, Debug)] #[repr(C)] -pub(crate) struct PathVertex { - pub(crate) xy_position: Point

, - pub(crate) st_position: Point, - pub(crate) content_mask: ContentMask

, +#[expect(missing_docs)] +pub struct PathVertex { + pub xy_position: Point

, + pub st_position: Point, + pub content_mask: ContentMask

, } +#[expect(missing_docs)] impl PathVertex { pub fn scale(&self, factor: f32) -> PathVertex { PathVertex { diff --git a/crates/gpui/src/svg_renderer.rs b/crates/gpui/src/svg_renderer.rs index cae1b5d423b9a01e30f19c049dc37bb377e4e887..f82530f8d10fab074dd5e116114cf028a8a19cfe 100644 --- a/crates/gpui/src/svg_renderer.rs +++ b/crates/gpui/src/svg_renderer.rs @@ -14,9 +14,10 @@ use std::{ pub const SMOOTH_SVG_SCALE_FACTOR: f32 = 2.; #[derive(Clone, PartialEq, Hash, Eq)] -pub(crate) struct RenderSvgParams { - pub(crate) path: SharedString, - pub(crate) size: Size, +#[expect(missing_docs)] +pub struct RenderSvgParams { + pub path: SharedString, + pub size: Size, } #[derive(Clone)] diff --git a/crates/gpui/src/text_system.rs b/crates/gpui/src/text_system.rs index cb0918045e6d22eab967060ed0df569f5f6c7cc1..43982b2666bde8210f770419623cc0b9afd6e2af 100644 --- a/crates/gpui/src/text_system.rs +++ b/crates/gpui/src/text_system.rs @@ -41,14 +41,15 @@ pub struct FontId(pub usize); #[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)] pub struct FontFamilyId(pub usize); -pub(crate) const SUBPIXEL_VARIANTS_X: u8 = 4; - -pub(crate) const SUBPIXEL_VARIANTS_Y: u8 = - if cfg!(target_os = "windows") || cfg!(target_os = "linux") { - 1 - } else { - SUBPIXEL_VARIANTS_X - }; +/// Number of subpixel glyph variants along the X axis. +pub const SUBPIXEL_VARIANTS_X: u8 = 4; + +/// Number of subpixel glyph variants along the Y axis. +pub const SUBPIXEL_VARIANTS_Y: u8 = if cfg!(target_os = "windows") || cfg!(target_os = "linux") { + 1 +} else { + SUBPIXEL_VARIANTS_X +}; /// The GPUI text rendering sub system. pub struct TextSystem { @@ -799,17 +800,18 @@ impl TextRun { /// An identifier for a specific glyph, as returned by [`WindowTextSystem::layout_line`]. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[repr(C)] -pub struct GlyphId(pub(crate) u32); +pub struct GlyphId(pub u32); #[derive(Clone, Debug, PartialEq)] -pub(crate) struct RenderGlyphParams { - pub(crate) font_id: FontId, - pub(crate) glyph_id: GlyphId, - pub(crate) font_size: Pixels, - pub(crate) subpixel_variant: Point, - pub(crate) scale_factor: f32, - pub(crate) is_emoji: bool, - pub(crate) subpixel_rendering: bool, +#[expect(missing_docs)] +pub struct RenderGlyphParams { + pub font_id: FontId, + pub glyph_id: GlyphId, + pub font_size: Pixels, + pub subpixel_variant: Point, + pub scale_factor: f32, + pub is_emoji: bool, + pub subpixel_rendering: bool, } impl Eq for RenderGlyphParams {} @@ -884,32 +886,32 @@ impl Font { pub struct FontMetrics { /// The number of font units that make up the "em square", /// a scalable grid for determining the size of a typeface. - pub(crate) units_per_em: u32, + pub units_per_em: u32, /// The vertical distance from the baseline of the font to the top of the glyph covers. - pub(crate) ascent: f32, + pub ascent: f32, /// The vertical distance from the baseline of the font to the bottom of the glyph covers. - pub(crate) descent: f32, + pub descent: f32, /// The recommended additional space to add between lines of type. - pub(crate) line_gap: f32, + pub line_gap: f32, /// The suggested position of the underline. - pub(crate) underline_position: f32, + pub underline_position: f32, /// The suggested thickness of the underline. - pub(crate) underline_thickness: f32, + pub underline_thickness: f32, /// The height of a capital letter measured from the baseline of the font. - pub(crate) cap_height: f32, + pub cap_height: f32, /// The height of a lowercase x. - pub(crate) x_height: f32, + pub x_height: f32, /// The outer limits of the area that the font covers. /// Corresponds to the xMin / xMax / yMin / yMax values in the OpenType `head` table - pub(crate) bounding_box: Bounds, + pub bounding_box: Bounds, } impl FontMetrics { @@ -954,8 +956,9 @@ impl FontMetrics { } } +/// Maps well-known virtual font names to their concrete equivalents. #[allow(unused)] -pub(crate) fn font_name_with_fallbacks<'a>(name: &'a str, system: &'a str) -> &'a str { +pub fn font_name_with_fallbacks<'a>(name: &'a str, system: &'a str) -> &'a str { // Note: the "Zed Plex" fonts were deprecated as we are not allowed to use "Plex" // in a derived font name. They are essentially indistinguishable from IBM Plex/Lilex, // and so retained here for backward compatibility. @@ -967,8 +970,9 @@ pub(crate) fn font_name_with_fallbacks<'a>(name: &'a str, system: &'a str) -> &' } } +/// Like [`font_name_with_fallbacks`] but accepts and returns [`SharedString`] references. #[allow(unused)] -pub(crate) fn font_name_with_fallbacks_shared<'a>( +pub fn font_name_with_fallbacks_shared<'a>( name: &'a SharedString, system: &'a SharedString, ) -> &'a SharedString { diff --git a/crates/gpui/src/text_system/line_layout.rs b/crates/gpui/src/text_system/line_layout.rs index 375a9bdc7bccdddb9d34409c5ced138b2d5aebd2..78ab21b3d324674b0f34d9ab418893430df70f2a 100644 --- a/crates/gpui/src/text_system/line_layout.rs +++ b/crates/gpui/src/text_system/line_layout.rs @@ -594,9 +594,10 @@ impl LineLayoutCache { /// A run of text with a single font. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[expect(missing_docs)] pub struct FontRun { - pub(crate) len: usize, - pub(crate) font_id: FontId, + pub len: usize, + pub font_id: FontId, } trait AsCacheKeyRef { diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 206ab7b6cb7532bbf74ba4fa56c140786d815ee9..92101fdfcacd36b6d71e0d422f3fd2cc6d773e3a 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -59,7 +59,8 @@ mod prompts; use crate::util::atomic_incr_if_not_zero; pub use prompts::*; -pub(crate) const DEFAULT_WINDOW_SIZE: Size = size(px(1536.), px(864.)); +/// Default window size used when no explicit size is provided. +pub const DEFAULT_WINDOW_SIZE: Size = size(px(1536.), px(864.)); /// A 6:5 aspect ratio minimum window size to be used for functional, /// additional-to-main-Zed windows, like the settings and rules library windows. @@ -1447,7 +1448,8 @@ impl Window { } #[derive(Clone, Debug, Default, PartialEq, Eq)] -pub(crate) struct DispatchEventResult { +#[expect(missing_docs)] +pub struct DispatchEventResult { pub propagate: bool, pub default_prevented: bool, } diff --git a/crates/gpui_linux/Cargo.toml b/crates/gpui_linux/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..a6d3755bd30140c1549e385227f3908cf1625831 --- /dev/null +++ b/crates/gpui_linux/Cargo.toml @@ -0,0 +1,134 @@ +[package] +name = "gpui_linux" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "Apache-2.0" + +[lints] +workspace = true + +[lib] +path = "src/gpui_linux.rs" + +[features] +default = ["wayland", "x11"] +test-support = ["gpui/test-support"] +wayland = [ + "bitflags", + "gpui_wgpu", + "ashpd/wayland", + "cosmic-text", + "font-kit", + "calloop-wayland-source", + "wayland-backend", + "wayland-client", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-plasma", + "wayland-protocols-wlr", + "filedescriptor", + "xkbcommon", + "open", +] +x11 = [ + "gpui_wgpu", + "ashpd", + "cosmic-text", + "font-kit", + "as-raw-xcb-connection", + "x11rb", + "xkbcommon", + "xim", + "x11-clipboard", + "filedescriptor", + "open", + "scap?/x11", +] +screen-capture = [ + "gpui/screen-capture", + "scap", +] + + +[target.'cfg(any(target_os = "linux", target_os = "freebsd"))'.dependencies] +anyhow.workspace = true +bytemuck = "1" +collections.workspace = true +futures.workspace = true +gpui.workspace = true +gpui_wgpu = { workspace = true, optional = true } +http_client.workspace = true +itertools.workspace = true +libc.workspace = true +log.workspace = true +parking_lot.workspace = true +pathfinder_geometry = "0.5" +profiling.workspace = true +smallvec.workspace = true +smol.workspace = true +strum.workspace = true +util.workspace = true +uuid.workspace = true + +# Always used +oo7 = { version = "0.5.0", default-features = false, features = [ + "async-std", + "native_crypto", +] } +calloop = "0.14.3" +raw-window-handle = "0.6" + +# Used in both windowing options +ashpd = { workspace = true, optional = true } +cosmic-text = { version = "0.17.0", optional = true } +swash = { version = "0.2.6" } +# WARNING: If you change this, you must also publish a new version of zed-font-kit to crates.io +font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "110523127440aefb11ce0cf280ae7c5071337ec5", package = "zed-font-kit", version = "0.14.1-zed", features = [ + "source-fontconfig-dlopen", +], optional = true } +bitflags = { workspace = true, optional = true } +filedescriptor = { version = "0.8.2", optional = true } +open = { version = "5.2.0", optional = true } +xkbcommon = { version = "0.8.0", features = ["wayland", "x11"], optional = true } + +# Screen capture +scap = { workspace = true, optional = true } + +# Wayland +calloop-wayland-source = { version = "0.4.1", optional = true } +wayland-backend = { version = "0.3.3", features = [ + "client_system", + "dlopen", +], optional = true } +wayland-client = { version = "0.31.11", optional = true } +wayland-cursor = { version = "0.31.11", optional = true } +wayland-protocols = { version = "0.32.9", features = [ + "client", + "staging", + "unstable", +], optional = true } +wayland-protocols-plasma = { version = "0.3.9", features = [ + "client", +], optional = true } +wayland-protocols-wlr = { version = "0.3.9", features = [ + "client", +], optional = true } + +# X11 +as-raw-xcb-connection = { version = "1", optional = true } +x11rb = { version = "0.13.1", features = [ + "allow-unsafe-code", + "xkb", + "randr", + "xinput", + "cursor", + "resource_manager", + "sync", +], optional = true } +# WARNING: If you change this, you must also publish a new version of zed-xim to crates.io +xim = { git = "https://github.com/zed-industries/xim-rs.git", rev = "16f35a2c881b815a2b6cdfd6687988e84f8447d8", features = [ + "x11rb-xcb", + "x11rb-client", +], package = "zed-xim", version = "0.4.0-zed", optional = true } +x11-clipboard = { version = "0.9.3", optional = true } diff --git a/crates/gpui_linux/LICENSE-APACHE b/crates/gpui_linux/LICENSE-APACHE new file mode 120000 index 0000000000000000000000000000000000000000..1cd601d0a3affae83854be02a0afdec3b7a9ec4d --- /dev/null +++ b/crates/gpui_linux/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/gpui_linux/src/gpui_linux.rs b/crates/gpui_linux/src/gpui_linux.rs new file mode 100644 index 0000000000000000000000000000000000000000..62d972dc4e07d1d960c342dfa677186e1e4d0805 --- /dev/null +++ b/crates/gpui_linux/src/gpui_linux.rs @@ -0,0 +1,4 @@ +#![cfg(any(target_os = "linux", target_os = "freebsd"))] +mod linux; + +pub use linux::current_platform; diff --git a/crates/gpui_linux/src/linux.rs b/crates/gpui_linux/src/linux.rs new file mode 100644 index 0000000000000000000000000000000000000000..27fda08056fec9d38c4aadf6a8ec955b0e1066df --- /dev/null +++ b/crates/gpui_linux/src/linux.rs @@ -0,0 +1,57 @@ +mod dispatcher; +mod headless; +mod keyboard; +mod platform; +#[cfg(any(feature = "wayland", feature = "x11"))] +mod text_system; +#[cfg(feature = "wayland")] +mod wayland; +#[cfg(feature = "x11")] +mod x11; + +#[cfg(any(feature = "wayland", feature = "x11"))] +mod xdg_desktop_portal; + +pub use dispatcher::*; +pub(crate) use headless::*; +pub(crate) use keyboard::*; +pub use platform::*; +#[cfg(any(feature = "wayland", feature = "x11"))] +pub(crate) use text_system::*; +#[cfg(feature = "wayland")] +pub(crate) use wayland::*; +#[cfg(feature = "x11")] +pub(crate) use x11::*; + +use std::rc::Rc; + +/// Returns the default platform implementation for the current OS. +pub fn current_platform(headless: bool) -> Rc { + #[cfg(feature = "x11")] + use anyhow::Context as _; + + if headless { + return Rc::new(LinuxPlatform { + inner: HeadlessClient::new(), + }); + } + + match gpui::guess_compositor() { + #[cfg(feature = "wayland")] + "Wayland" => Rc::new(LinuxPlatform { + inner: WaylandClient::new(), + }), + + #[cfg(feature = "x11")] + "X11" => Rc::new(LinuxPlatform { + inner: X11Client::new() + .context("Failed to initialize X11 client.") + .unwrap(), + }), + + "Headless" => Rc::new(LinuxPlatform { + inner: HeadlessClient::new(), + }), + _ => unreachable!(), + } +} diff --git a/crates/gpui/src/platform/linux/dispatcher.rs b/crates/gpui_linux/src/linux/dispatcher.rs similarity index 95% rename from crates/gpui/src/platform/linux/dispatcher.rs rename to crates/gpui_linux/src/linux/dispatcher.rs index 10f6b9440a21c50a56071141cf8b3384996e6e0d..ff17fd238ae2a4b40ebdf8e36133c05f3e41f9b3 100644 --- a/crates/gpui/src/platform/linux/dispatcher.rs +++ b/crates/gpui_linux/src/linux/dispatcher.rs @@ -11,7 +11,7 @@ use std::{ time::{Duration, Instant}, }; -use crate::{ +use gpui::{ GLOBAL_THREAD_TIMINGS, PlatformDispatcher, Priority, PriorityQueueReceiver, PriorityQueueSender, RunnableVariant, THREAD_TIMINGS, TaskTiming, ThreadTaskTimings, profiler, }; @@ -39,8 +39,7 @@ impl LinuxDispatcher { let mut background_threads = (0..thread_count) .map(|i| { - let mut receiver: PriorityQueueReceiver = - background_receiver.clone(); + let receiver: PriorityQueueReceiver = background_receiver.clone(); std::thread::Builder::new() .name(format!("Worker-{i}")) .spawn(move || { @@ -140,12 +139,12 @@ impl LinuxDispatcher { } impl PlatformDispatcher for LinuxDispatcher { - fn get_all_timings(&self) -> Vec { + fn get_all_timings(&self) -> Vec { let global_timings = GLOBAL_THREAD_TIMINGS.lock(); ThreadTaskTimings::convert(&global_timings) } - fn get_current_thread_timings(&self) -> crate::ThreadTaskTimings { + fn get_current_thread_timings(&self) -> gpui::ThreadTaskTimings { THREAD_TIMINGS.with(|timings| { let timings = timings.lock(); let thread_name = timings.thread_name.clone(); @@ -158,7 +157,7 @@ impl PlatformDispatcher for LinuxDispatcher { vec.extend_from_slice(s1); vec.extend_from_slice(s2); - crate::ThreadTaskTimings { + gpui::ThreadTaskTimings { thread_name, thread_id: std::thread::current().id(), timings: vec, @@ -232,7 +231,7 @@ impl PriorityQueueCalloopSender { Self { sender: tx, ping } } - fn send(&self, priority: Priority, item: T) -> Result<(), crate::queue::SendError> { + fn send(&self, priority: Priority, item: T) -> Result<(), gpui::queue::SendError> { let res = self.sender.send(priority, item); if res.is_ok() { self.ping.ping(); @@ -312,7 +311,7 @@ impl calloop::EventSource for PriorityQueueCalloopReceiver { .process_events(readiness, token, |(), &mut ()| { let mut is_empty = true; - let mut receiver = self.receiver.clone(); + let receiver = self.receiver.clone(); for runnable in receiver.try_iter() { match runnable { Ok(r) => { @@ -429,11 +428,11 @@ mod tests { } // running 1 test -// test platform::linux::dispatcher::tests::tomato ... FAILED +// test linux::dispatcher::tests::tomato ... FAILED // failures: -// ---- platform::linux::dispatcher::tests::tomato stdout ---- +// ---- linux::dispatcher::tests::tomato stdout ---- // [crates/gpui/src/platform/linux/dispatcher.rs:262:9] // returning 1 tasks to process // [crates/gpui/src/platform/linux/dispatcher.rs:480:75] evt = Msg( @@ -441,6 +440,6 @@ mod tests { // ) // returning 0 tasks to process -// thread 'platform::linux::dispatcher::tests::tomato' (478301) panicked at crates/gpui/src/platform/linux/dispatcher.rs:515:9: +// thread 'linux::dispatcher::tests::tomato' (478301) panicked at crates/gpui/src/platform/linux/dispatcher.rs:515:9: // assertion failed: data.got_closed // note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/crates/gpui/src/platform/linux/headless.rs b/crates/gpui_linux/src/linux/headless.rs similarity index 100% rename from crates/gpui/src/platform/linux/headless.rs rename to crates/gpui_linux/src/linux/headless.rs diff --git a/crates/gpui/src/platform/linux/headless/client.rs b/crates/gpui_linux/src/linux/headless/client.rs similarity index 79% rename from crates/gpui/src/platform/linux/headless/client.rs rename to crates/gpui_linux/src/linux/headless/client.rs index da54db371033bac53e2ac3324306fa86eb57fb57..6dbdc556751b27d144feb4a40c916910bc6ff5f7 100644 --- a/crates/gpui/src/platform/linux/headless/client.rs +++ b/crates/gpui_linux/src/linux/headless/client.rs @@ -4,11 +4,10 @@ use std::rc::Rc; use calloop::{EventLoop, LoopHandle}; use util::ResultExt; -use crate::platform::linux::LinuxClient; -use crate::platform::{LinuxCommon, PlatformWindow}; -use crate::{ - AnyWindowHandle, CursorStyle, DisplayId, LinuxKeyboardLayout, PlatformDisplay, - PlatformKeyboardLayout, WindowParams, +use crate::linux::{LinuxClient, LinuxCommon, LinuxKeyboardLayout}; +use gpui::{ + AnyWindowHandle, CursorStyle, DisplayId, PlatformDisplay, PlatformKeyboardLayout, + PlatformWindow, WindowParams, }; pub struct HeadlessClientState { @@ -65,17 +64,11 @@ impl LinuxClient for HeadlessClient { None } - #[cfg(feature = "screen-capture")] - fn is_screen_capture_supported(&self) -> bool { - false - } - - #[cfg(feature = "screen-capture")] fn screen_capture_sources( &self, - ) -> futures::channel::oneshot::Receiver>>> + ) -> futures::channel::oneshot::Receiver>>> { - let (mut tx, rx) = futures::channel::oneshot::channel(); + let (tx, rx) = futures::channel::oneshot::channel(); tx.send(Err(anyhow::anyhow!( "Headless mode does not support screen capture." ))) @@ -109,15 +102,15 @@ impl LinuxClient for HeadlessClient { fn reveal_path(&self, _path: std::path::PathBuf) {} - fn write_to_primary(&self, _item: crate::ClipboardItem) {} + fn write_to_primary(&self, _item: gpui::ClipboardItem) {} - fn write_to_clipboard(&self, _item: crate::ClipboardItem) {} + fn write_to_clipboard(&self, _item: gpui::ClipboardItem) {} - fn read_from_primary(&self) -> Option { + fn read_from_primary(&self) -> Option { None } - fn read_from_clipboard(&self) -> Option { + fn read_from_clipboard(&self) -> Option { None } diff --git a/crates/gpui/src/platform/linux/keyboard.rs b/crates/gpui_linux/src/linux/keyboard.rs similarity index 87% rename from crates/gpui/src/platform/linux/keyboard.rs rename to crates/gpui_linux/src/linux/keyboard.rs index 4e83cc4744d3c706a4f2b201315bbbac8f9359d8..d810a2f4f7d2659a768b767222c8cb2623319201 100644 --- a/crates/gpui/src/platform/linux/keyboard.rs +++ b/crates/gpui_linux/src/linux/keyboard.rs @@ -1,4 +1,4 @@ -use crate::{PlatformKeyboardLayout, SharedString}; +use gpui::{PlatformKeyboardLayout, SharedString}; #[derive(Clone)] pub(crate) struct LinuxKeyboardLayout { diff --git a/crates/gpui/src/platform/linux/platform.rs b/crates/gpui_linux/src/linux/platform.rs similarity index 66% rename from crates/gpui/src/platform/linux/platform.rs rename to crates/gpui_linux/src/linux/platform.rs index f891aa35adbc62d4d384970fb9d997e60cbfc848..c3ee684ea290596685b43e6af7e7b14155766047 100644 --- a/crates/gpui/src/platform/linux/platform.rs +++ b/crates/gpui_linux/src/linux/platform.rs @@ -21,15 +21,15 @@ use util::command::{new_command, new_std_command}; #[cfg(any(feature = "wayland", feature = "x11"))] use xkbcommon::xkb::{self, Keycode, Keysym, State}; -use crate::{ +use crate::linux::{LinuxDispatcher, PriorityQueueCalloopReceiver}; +use gpui::{ Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId, - ForegroundExecutor, Keymap, LinuxDispatcher, Menu, MenuItem, OwnedMenu, PathPromptOptions, - Platform, PlatformDisplay, PlatformKeyboardLayout, PlatformKeyboardMapper, PlatformTextSystem, - PlatformWindow, PriorityQueueCalloopReceiver, Result, RunnableVariant, Task, ThermalState, - WindowAppearance, WindowParams, + ForegroundExecutor, Keymap, Menu, MenuItem, OwnedMenu, PathPromptOptions, Platform, + PlatformDisplay, PlatformKeyboardLayout, PlatformKeyboardMapper, PlatformTextSystem, + PlatformWindow, Result, RunnableVariant, Task, ThermalState, WindowAppearance, WindowParams, }; #[cfg(any(feature = "wayland", feature = "x11"))] -use crate::{Pixels, Point, px}; +use gpui::{Pixels, Point, px}; #[cfg(any(feature = "wayland", feature = "x11"))] pub(crate) const SCROLL_LINES: f32 = 3.0; @@ -90,7 +90,7 @@ impl ResultExt for anyhow::Result { } } -pub trait LinuxClient { +pub(crate) trait LinuxClient { fn compositor_name(&self) -> &'static str; fn with_common(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R; fn keyboard_layout(&self) -> Box; @@ -99,11 +99,21 @@ pub trait LinuxClient { fn display(&self, id: DisplayId) -> Option>; fn primary_display(&self) -> Option>; #[cfg(feature = "screen-capture")] - fn is_screen_capture_supported(&self) -> bool; + fn is_screen_capture_supported(&self) -> bool { + false + } #[cfg(feature = "screen-capture")] fn screen_capture_sources( &self, - ) -> oneshot::Receiver>>>; + ) -> oneshot::Receiver>>> { + let (sources_tx, sources_rx) = oneshot::channel(); + sources_tx + .send(Err(anyhow::anyhow!( + "gpui_linux was compiled without the screen-capture feature" + ))) + .ok(); + sources_rx + } fn open_window( &self, @@ -156,7 +166,7 @@ impl LinuxCommon { let (main_sender, main_receiver) = PriorityQueueCalloopReceiver::new(); #[cfg(any(feature = "wayland", feature = "x11"))] - let text_system = Arc::new(crate::CosmicTextSystem::new()); + let text_system = Arc::new(crate::linux::CosmicTextSystem::new()); #[cfg(not(any(feature = "wayland", feature = "x11")))] let text_system = Arc::new(crate::NoopTextSystem::new()); @@ -181,29 +191,36 @@ impl LinuxCommon { } } -impl Platform for P { +pub(crate) struct LinuxPlatform

{ + pub(crate) inner: P, +} + +impl Platform for LinuxPlatform

{ fn background_executor(&self) -> BackgroundExecutor { - self.with_common(|common| common.background_executor.clone()) + self.inner + .with_common(|common| common.background_executor.clone()) } fn foreground_executor(&self) -> ForegroundExecutor { - self.with_common(|common| common.foreground_executor.clone()) + self.inner + .with_common(|common| common.foreground_executor.clone()) } fn text_system(&self) -> Arc { - self.with_common(|common| common.text_system.clone()) + self.inner.with_common(|common| common.text_system.clone()) } fn keyboard_layout(&self) -> Box { - self.keyboard_layout() + self.inner.keyboard_layout() } fn keyboard_mapper(&self) -> Rc { - Rc::new(crate::DummyKeyboardMapper) + Rc::new(gpui::DummyKeyboardMapper) } fn on_keyboard_layout_change(&self, callback: Box) { - self.with_common(|common| common.callbacks.keyboard_layout_change = Some(callback)); + self.inner + .with_common(|common| common.callbacks.keyboard_layout_change = Some(callback)); } fn on_thermal_state_change(&self, _callback: Box) {} @@ -215,20 +232,22 @@ impl Platform for P { fn run(&self, on_finish_launching: Box) { on_finish_launching(); - LinuxClient::run(self); + LinuxClient::run(&self.inner); - let quit = self.with_common(|common| common.callbacks.quit.take()); + let quit = self + .inner + .with_common(|common| common.callbacks.quit.take()); if let Some(mut fun) = quit { fun(); } } fn quit(&self) { - self.with_common(|common| common.signal.stop()); + self.inner.with_common(|common| common.signal.stop()); } fn compositor_name(&self) -> &'static str { - self.compositor_name() + self.inner.compositor_name() } fn restart(&self, binary_path: Option) { @@ -298,31 +317,31 @@ impl Platform for P { } fn primary_display(&self) -> Option> { - self.primary_display() + self.inner.primary_display() } fn displays(&self) -> Vec> { - self.displays() + self.inner.displays() } #[cfg(feature = "screen-capture")] fn is_screen_capture_supported(&self) -> bool { - self.is_screen_capture_supported() + self.inner.is_screen_capture_supported() } #[cfg(feature = "screen-capture")] fn screen_capture_sources( &self, - ) -> oneshot::Receiver>>> { - self.screen_capture_sources() + ) -> oneshot::Receiver>>> { + self.inner.screen_capture_sources() } fn active_window(&self) -> Option { - self.active_window() + self.inner.active_window() } fn window_stack(&self) -> Option> { - self.window_stack() + self.inner.window_stack() } fn open_window( @@ -330,15 +349,16 @@ impl Platform for P { handle: AnyWindowHandle, options: WindowParams, ) -> anyhow::Result> { - self.open_window(handle, options) + self.inner.open_window(handle, options) } fn open_url(&self, url: &str) { - self.open_uri(url); + self.inner.open_uri(url); } fn on_open_urls(&self, callback: Box)>) { - self.with_common(|common| common.callbacks.open_urls = Some(callback)); + self.inner + .with_common(|common| common.callbacks.open_urls = Some(callback)); } fn prompt_for_paths( @@ -351,7 +371,7 @@ impl Platform for P { let _ = (done_tx.send(Ok(None)), options); #[cfg(any(feature = "wayland", feature = "x11"))] - let identifier = self.window_identifier(); + let identifier = self.inner.window_identifier(); #[cfg(any(feature = "wayland", feature = "x11"))] self.foreground_executor() @@ -366,7 +386,7 @@ impl Platform for P { .identifier(identifier.await) .modal(true) .title(title) - .accept_label(options.prompt.as_ref().map(crate::SharedString::as_str)) + .accept_label(options.prompt.as_ref().map(gpui::SharedString::as_str)) .multiple(options.multiple) .directory(options.directories) .send() @@ -411,7 +431,7 @@ impl Platform for P { let _ = (done_tx.send(Ok(None)), directory, suggested_name); #[cfg(any(feature = "wayland", feature = "x11"))] - let identifier = self.window_identifier(); + let identifier = self.inner.window_identifier(); #[cfg(any(feature = "wayland", feature = "x11"))] self.foreground_executor() @@ -468,7 +488,7 @@ impl Platform for P { } fn reveal_path(&self, path: &Path) { - self.reveal_path(path.to_owned()); + self.inner.reveal_path(path.to_owned()); } fn open_with_system(&self, path: &Path) { @@ -489,31 +509,31 @@ impl Platform for P { } fn on_quit(&self, callback: Box) { - self.with_common(|common| { + self.inner.with_common(|common| { common.callbacks.quit = Some(callback); }); } fn on_reopen(&self, callback: Box) { - self.with_common(|common| { + self.inner.with_common(|common| { common.callbacks.reopen = Some(callback); }); } fn on_app_menu_action(&self, callback: Box) { - self.with_common(|common| { + self.inner.with_common(|common| { common.callbacks.app_menu_action = Some(callback); }); } fn on_will_open_app_menu(&self, callback: Box) { - self.with_common(|common| { + self.inner.with_common(|common| { common.callbacks.will_open_app_menu = Some(callback); }); } fn on_validate_app_menu_command(&self, callback: Box bool>) { - self.with_common(|common| { + self.inner.with_common(|common| { common.callbacks.validate_app_menu_command = Some(callback); }); } @@ -525,13 +545,13 @@ impl Platform for P { } fn set_menus(&self, menus: Vec

, _keymap: &Keymap) { - self.with_common(|common| { + self.inner.with_common(|common| { common.menus = menus.into_iter().map(|menu| menu.owned()).collect(); }) } fn get_menus(&self) -> Option> { - self.with_common(|common| Some(common.menus.clone())) + self.inner.with_common(|common| Some(common.menus.clone())) } fn set_dock_menu(&self, _menu: Vec, _keymap: &Keymap) { @@ -545,11 +565,11 @@ impl Platform for P { } fn set_cursor_style(&self, style: CursorStyle) { - self.set_cursor_style(style) + self.inner.set_cursor_style(style) } fn should_auto_hide_scrollbars(&self) -> bool { - self.with_common(|common| common.auto_hide_scrollbars) + self.inner.with_common(|common| common.auto_hide_scrollbars) } fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Task> { @@ -619,7 +639,7 @@ impl Platform for P { } fn window_appearance(&self) -> WindowAppearance { - self.with_common(|common| common.appearance) + self.inner.with_common(|common| common.appearance) } fn register_url_scheme(&self, _: &str) -> Task> { @@ -627,19 +647,19 @@ impl Platform for P { } fn write_to_primary(&self, item: ClipboardItem) { - self.write_to_primary(item) + self.inner.write_to_primary(item) } fn write_to_clipboard(&self, item: ClipboardItem) { - self.write_to_clipboard(item) + self.inner.write_to_clipboard(item) } fn read_from_primary(&self) -> Option { - self.read_from_primary() + self.inner.read_from_primary() } fn read_from_clipboard(&self) -> Option { - self.read_from_clipboard() + self.inner.read_from_clipboard() } fn add_recent_document(&self, _path: &Path) {} @@ -750,39 +770,37 @@ pub(super) unsafe fn read_fd(fd: filedescriptor::FileDescriptor) -> Result &'static [&'static str] { - // Based on cursor names from chromium: - // https://github.com/chromium/chromium/blob/d3069cf9c973dc3627fa75f64085c6a86c8f41bf/ui/base/cursor/cursor_factory.cc#L113 - match self { - CursorStyle::Arrow => &[DEFAULT_CURSOR_ICON_NAME], - CursorStyle::IBeam => &["text", "xterm"], - CursorStyle::Crosshair => &["crosshair", "cross"], - CursorStyle::ClosedHand => &["closedhand", "grabbing", "hand2"], - CursorStyle::OpenHand => &["openhand", "grab", "hand1"], - CursorStyle::PointingHand => &["pointer", "hand", "hand2"], - CursorStyle::ResizeLeft => &["w-resize", "left_side"], - CursorStyle::ResizeRight => &["e-resize", "right_side"], - CursorStyle::ResizeLeftRight => &["ew-resize", "sb_h_double_arrow"], - CursorStyle::ResizeUp => &["n-resize", "top_side"], - CursorStyle::ResizeDown => &["s-resize", "bottom_side"], - CursorStyle::ResizeUpDown => &["sb_v_double_arrow", "ns-resize"], - CursorStyle::ResizeUpLeftDownRight => &["size_fdiag", "bd_double_arrow", "nwse-resize"], - CursorStyle::ResizeUpRightDownLeft => &["size_bdiag", "nesw-resize", "fd_double_arrow"], - CursorStyle::ResizeColumn => &["col-resize", "sb_h_double_arrow"], - CursorStyle::ResizeRow => &["row-resize", "sb_v_double_arrow"], - CursorStyle::IBeamCursorForVerticalLayout => &["vertical-text"], - CursorStyle::OperationNotAllowed => &["not-allowed", "crossed_circle"], - CursorStyle::DragLink => &["alias"], - CursorStyle::DragCopy => &["copy"], - CursorStyle::ContextualMenu => &["context-menu"], - CursorStyle::None => { - #[cfg(debug_assertions)] - panic!("CursorStyle::None should be handled separately in the client"); - #[cfg(not(debug_assertions))] - &[DEFAULT_CURSOR_ICON_NAME] - } +#[cfg(any(feature = "wayland", feature = "x11"))] +pub(super) fn cursor_style_to_icon_names(style: CursorStyle) -> &'static [&'static str] { + // Based on cursor names from chromium: + // https://github.com/chromium/chromium/blob/d3069cf9c973dc3627fa75f64085c6a86c8f41bf/ui/base/cursor/cursor_factory.cc#L113 + match style { + CursorStyle::Arrow => &[DEFAULT_CURSOR_ICON_NAME], + CursorStyle::IBeam => &["text", "xterm"], + CursorStyle::Crosshair => &["crosshair", "cross"], + CursorStyle::ClosedHand => &["closedhand", "grabbing", "hand2"], + CursorStyle::OpenHand => &["openhand", "grab", "hand1"], + CursorStyle::PointingHand => &["pointer", "hand", "hand2"], + CursorStyle::ResizeLeft => &["w-resize", "left_side"], + CursorStyle::ResizeRight => &["e-resize", "right_side"], + CursorStyle::ResizeLeftRight => &["ew-resize", "sb_h_double_arrow"], + CursorStyle::ResizeUp => &["n-resize", "top_side"], + CursorStyle::ResizeDown => &["s-resize", "bottom_side"], + CursorStyle::ResizeUpDown => &["sb_v_double_arrow", "ns-resize"], + CursorStyle::ResizeUpLeftDownRight => &["size_fdiag", "bd_double_arrow", "nwse-resize"], + CursorStyle::ResizeUpRightDownLeft => &["size_bdiag", "nesw-resize", "fd_double_arrow"], + CursorStyle::ResizeColumn => &["col-resize", "sb_h_double_arrow"], + CursorStyle::ResizeRow => &["row-resize", "sb_v_double_arrow"], + CursorStyle::IBeamCursorForVerticalLayout => &["vertical-text"], + CursorStyle::OperationNotAllowed => &["not-allowed", "crossed_circle"], + CursorStyle::DragLink => &["alias"], + CursorStyle::DragCopy => &["copy"], + CursorStyle::ContextualMenu => &["context-menu"], + CursorStyle::None => { + #[cfg(debug_assertions)] + panic!("CursorStyle::None should be handled separately in the client"); + #[cfg(not(debug_assertions))] + &[DEFAULT_CURSOR_ICON_NAME] } } } @@ -856,222 +874,214 @@ fn guess_ascii(keycode: Keycode, shift: bool) -> Option { } #[cfg(any(feature = "wayland", feature = "x11"))] -impl crate::Keystroke { - pub(super) fn from_xkb( - state: &State, - mut modifiers: crate::Modifiers, - keycode: Keycode, - ) -> Self { - let key_utf32 = state.key_get_utf32(keycode); - let key_utf8 = state.key_get_utf8(keycode); - let key_sym = state.key_get_one_sym(keycode); - - let key = match key_sym { - Keysym::Return => "enter".to_owned(), - Keysym::Prior => "pageup".to_owned(), - Keysym::Next => "pagedown".to_owned(), - Keysym::ISO_Left_Tab => "tab".to_owned(), - Keysym::KP_Prior => "pageup".to_owned(), - Keysym::KP_Next => "pagedown".to_owned(), - Keysym::XF86_Back => "back".to_owned(), - Keysym::XF86_Forward => "forward".to_owned(), - Keysym::XF86_Cut => "cut".to_owned(), - Keysym::XF86_Copy => "copy".to_owned(), - Keysym::XF86_Paste => "paste".to_owned(), - Keysym::XF86_New => "new".to_owned(), - Keysym::XF86_Open => "open".to_owned(), - Keysym::XF86_Save => "save".to_owned(), - - Keysym::comma => ",".to_owned(), - Keysym::period => ".".to_owned(), - Keysym::less => "<".to_owned(), - Keysym::greater => ">".to_owned(), - Keysym::slash => "/".to_owned(), - Keysym::question => "?".to_owned(), - - Keysym::semicolon => ";".to_owned(), - Keysym::colon => ":".to_owned(), - Keysym::apostrophe => "'".to_owned(), - Keysym::quotedbl => "\"".to_owned(), - - Keysym::bracketleft => "[".to_owned(), - Keysym::braceleft => "{".to_owned(), - Keysym::bracketright => "]".to_owned(), - Keysym::braceright => "}".to_owned(), - Keysym::backslash => "\\".to_owned(), - Keysym::bar => "|".to_owned(), - - Keysym::grave => "`".to_owned(), - Keysym::asciitilde => "~".to_owned(), - Keysym::exclam => "!".to_owned(), - Keysym::at => "@".to_owned(), - Keysym::numbersign => "#".to_owned(), - Keysym::dollar => "$".to_owned(), - Keysym::percent => "%".to_owned(), - Keysym::asciicircum => "^".to_owned(), - Keysym::ampersand => "&".to_owned(), - Keysym::asterisk => "*".to_owned(), - Keysym::parenleft => "(".to_owned(), - Keysym::parenright => ")".to_owned(), - Keysym::minus => "-".to_owned(), - Keysym::underscore => "_".to_owned(), - Keysym::equal => "=".to_owned(), - Keysym::plus => "+".to_owned(), - Keysym::space => "space".to_owned(), - Keysym::BackSpace => "backspace".to_owned(), - Keysym::Tab => "tab".to_owned(), - Keysym::Delete => "delete".to_owned(), - Keysym::Escape => "escape".to_owned(), - - Keysym::Left => "left".to_owned(), - Keysym::Right => "right".to_owned(), - Keysym::Up => "up".to_owned(), - Keysym::Down => "down".to_owned(), - Keysym::Home => "home".to_owned(), - Keysym::End => "end".to_owned(), - Keysym::Insert => "insert".to_owned(), - - _ => { - let name = xkb::keysym_get_name(key_sym).to_lowercase(); - if key_sym.is_keypad_key() { - name.replace("kp_", "") - } else if let Some(key) = key_utf8.chars().next() - && key_utf8.len() == 1 - && key.is_ascii() +pub(super) fn keystroke_from_xkb( + state: &State, + mut modifiers: gpui::Modifiers, + keycode: Keycode, +) -> gpui::Keystroke { + let key_utf32 = state.key_get_utf32(keycode); + let key_utf8 = state.key_get_utf8(keycode); + let key_sym = state.key_get_one_sym(keycode); + + let key = match key_sym { + Keysym::Return => "enter".to_owned(), + Keysym::Prior => "pageup".to_owned(), + Keysym::Next => "pagedown".to_owned(), + Keysym::ISO_Left_Tab => "tab".to_owned(), + Keysym::KP_Prior => "pageup".to_owned(), + Keysym::KP_Next => "pagedown".to_owned(), + Keysym::XF86_Back => "back".to_owned(), + Keysym::XF86_Forward => "forward".to_owned(), + Keysym::XF86_Cut => "cut".to_owned(), + Keysym::XF86_Copy => "copy".to_owned(), + Keysym::XF86_Paste => "paste".to_owned(), + Keysym::XF86_New => "new".to_owned(), + Keysym::XF86_Open => "open".to_owned(), + Keysym::XF86_Save => "save".to_owned(), + + Keysym::comma => ",".to_owned(), + Keysym::period => ".".to_owned(), + Keysym::less => "<".to_owned(), + Keysym::greater => ">".to_owned(), + Keysym::slash => "/".to_owned(), + Keysym::question => "?".to_owned(), + + Keysym::semicolon => ";".to_owned(), + Keysym::colon => ":".to_owned(), + Keysym::apostrophe => "'".to_owned(), + Keysym::quotedbl => "\"".to_owned(), + + Keysym::bracketleft => "[".to_owned(), + Keysym::braceleft => "{".to_owned(), + Keysym::bracketright => "]".to_owned(), + Keysym::braceright => "}".to_owned(), + Keysym::backslash => "\\".to_owned(), + Keysym::bar => "|".to_owned(), + + Keysym::grave => "`".to_owned(), + Keysym::asciitilde => "~".to_owned(), + Keysym::exclam => "!".to_owned(), + Keysym::at => "@".to_owned(), + Keysym::numbersign => "#".to_owned(), + Keysym::dollar => "$".to_owned(), + Keysym::percent => "%".to_owned(), + Keysym::asciicircum => "^".to_owned(), + Keysym::ampersand => "&".to_owned(), + Keysym::asterisk => "*".to_owned(), + Keysym::parenleft => "(".to_owned(), + Keysym::parenright => ")".to_owned(), + Keysym::minus => "-".to_owned(), + Keysym::underscore => "_".to_owned(), + Keysym::equal => "=".to_owned(), + Keysym::plus => "+".to_owned(), + Keysym::space => "space".to_owned(), + Keysym::BackSpace => "backspace".to_owned(), + Keysym::Tab => "tab".to_owned(), + Keysym::Delete => "delete".to_owned(), + Keysym::Escape => "escape".to_owned(), + + Keysym::Left => "left".to_owned(), + Keysym::Right => "right".to_owned(), + Keysym::Up => "up".to_owned(), + Keysym::Down => "down".to_owned(), + Keysym::Home => "home".to_owned(), + Keysym::End => "end".to_owned(), + Keysym::Insert => "insert".to_owned(), + + _ => { + let name = xkb::keysym_get_name(key_sym).to_lowercase(); + if key_sym.is_keypad_key() { + name.replace("kp_", "") + } else if let Some(key) = key_utf8.chars().next() + && key_utf8.len() == 1 + && key.is_ascii() + { + if key.is_ascii_graphic() { + key_utf8.to_lowercase() + // map ctrl-a to `a` + // ctrl-0..9 may emit control codes like ctrl-[, but + // we don't want to map them to `[` + } else if key_utf32 <= 0x1f + && !name.chars().next().is_some_and(|c| c.is_ascii_digit()) { - if key.is_ascii_graphic() { - key_utf8.to_lowercase() - // map ctrl-a to `a` - // ctrl-0..9 may emit control codes like ctrl-[, but - // we don't want to map them to `[` - } else if key_utf32 <= 0x1f - && !name.chars().next().is_some_and(|c| c.is_ascii_digit()) - { - ((key_utf32 as u8 + 0x40) as char) - .to_ascii_lowercase() - .to_string() - } else { - name - } - } else if let Some(key_en) = guess_ascii(keycode, modifiers.shift) { - String::from(key_en) + ((key_utf32 as u8 + 0x40) as char) + .to_ascii_lowercase() + .to_string() } else { name } - } - }; - - if modifiers.shift { - // we only include the shift for upper-case letters by convention, - // so don't include for numbers and symbols, but do include for - // tab/enter, etc. - if key.chars().count() == 1 && key.to_lowercase() == key.to_uppercase() { - modifiers.shift = false; + } else if let Some(key_en) = guess_ascii(keycode, modifiers.shift) { + String::from(key_en) + } else { + name } } + }; - // Ignore control characters (and DEL) for the purposes of key_char - let key_char = - (key_utf32 >= 32 && key_utf32 != 127 && !key_utf8.is_empty()).then_some(key_utf8); - - Self { - modifiers, - key, - key_char, + if modifiers.shift { + // we only include the shift for upper-case letters by convention, + // so don't include for numbers and symbols, but do include for + // tab/enter, etc. + if key.chars().count() == 1 && key.to_lowercase() == key.to_uppercase() { + modifiers.shift = false; } } - /** - * Returns which symbol the dead key represents - * - */ - pub fn underlying_dead_key(keysym: Keysym) -> Option { - match keysym { - Keysym::dead_grave => Some("`".to_owned()), - Keysym::dead_acute => Some("´".to_owned()), - Keysym::dead_circumflex => Some("^".to_owned()), - Keysym::dead_tilde => Some("~".to_owned()), - Keysym::dead_macron => Some("¯".to_owned()), - Keysym::dead_breve => Some("˘".to_owned()), - Keysym::dead_abovedot => Some("˙".to_owned()), - Keysym::dead_diaeresis => Some("¨".to_owned()), - Keysym::dead_abovering => Some("˚".to_owned()), - Keysym::dead_doubleacute => Some("˝".to_owned()), - Keysym::dead_caron => Some("ˇ".to_owned()), - Keysym::dead_cedilla => Some("¸".to_owned()), - Keysym::dead_ogonek => Some("˛".to_owned()), - Keysym::dead_iota => Some("ͅ".to_owned()), - Keysym::dead_voiced_sound => Some("゙".to_owned()), - Keysym::dead_semivoiced_sound => Some("゚".to_owned()), - Keysym::dead_belowdot => Some("̣̣".to_owned()), - Keysym::dead_hook => Some("̡".to_owned()), - Keysym::dead_horn => Some("̛".to_owned()), - Keysym::dead_stroke => Some("̶̶".to_owned()), - Keysym::dead_abovecomma => Some("̓̓".to_owned()), - Keysym::dead_abovereversedcomma => Some("ʽ".to_owned()), - Keysym::dead_doublegrave => Some("̏".to_owned()), - Keysym::dead_belowring => Some("˳".to_owned()), - Keysym::dead_belowmacron => Some("̱".to_owned()), - Keysym::dead_belowcircumflex => Some("ꞈ".to_owned()), - Keysym::dead_belowtilde => Some("̰".to_owned()), - Keysym::dead_belowbreve => Some("̮".to_owned()), - Keysym::dead_belowdiaeresis => Some("̤".to_owned()), - Keysym::dead_invertedbreve => Some("̯".to_owned()), - Keysym::dead_belowcomma => Some("̦".to_owned()), - Keysym::dead_currency => None, - Keysym::dead_lowline => None, - Keysym::dead_aboveverticalline => None, - Keysym::dead_belowverticalline => None, - Keysym::dead_longsolidusoverlay => None, - Keysym::dead_a => None, - Keysym::dead_A => None, - Keysym::dead_e => None, - Keysym::dead_E => None, - Keysym::dead_i => None, - Keysym::dead_I => None, - Keysym::dead_o => None, - Keysym::dead_O => None, - Keysym::dead_u => None, - Keysym::dead_U => None, - Keysym::dead_small_schwa => Some("ə".to_owned()), - Keysym::dead_capital_schwa => Some("Ə".to_owned()), - Keysym::dead_greek => None, - _ => None, - } + // Ignore control characters (and DEL) for the purposes of key_char + let key_char = + (key_utf32 >= 32 && key_utf32 != 127 && !key_utf8.is_empty()).then_some(key_utf8); + + gpui::Keystroke { + modifiers, + key, + key_char, } } +/** + * Returns which symbol the dead key represents + * + */ #[cfg(any(feature = "wayland", feature = "x11"))] -impl crate::Modifiers { - pub(super) fn from_xkb(keymap_state: &State) -> Self { - let shift = keymap_state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE); - let alt = keymap_state.mod_name_is_active(xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE); - let control = - keymap_state.mod_name_is_active(xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE); - let platform = - keymap_state.mod_name_is_active(xkb::MOD_NAME_LOGO, xkb::STATE_MODS_EFFECTIVE); - Self { - shift, - alt, - control, - platform, - function: false, - } +pub fn keystroke_underlying_dead_key(keysym: Keysym) -> Option { + match keysym { + Keysym::dead_grave => Some("`".to_owned()), + Keysym::dead_acute => Some("´".to_owned()), + Keysym::dead_circumflex => Some("^".to_owned()), + Keysym::dead_tilde => Some("~".to_owned()), + Keysym::dead_macron => Some("¯".to_owned()), + Keysym::dead_breve => Some("˘".to_owned()), + Keysym::dead_abovedot => Some("˙".to_owned()), + Keysym::dead_diaeresis => Some("¨".to_owned()), + Keysym::dead_abovering => Some("˚".to_owned()), + Keysym::dead_doubleacute => Some("˝".to_owned()), + Keysym::dead_caron => Some("ˇ".to_owned()), + Keysym::dead_cedilla => Some("¸".to_owned()), + Keysym::dead_ogonek => Some("˛".to_owned()), + Keysym::dead_iota => Some("ͅ".to_owned()), + Keysym::dead_voiced_sound => Some("゙".to_owned()), + Keysym::dead_semivoiced_sound => Some("゚".to_owned()), + Keysym::dead_belowdot => Some("̣̣".to_owned()), + Keysym::dead_hook => Some("̡".to_owned()), + Keysym::dead_horn => Some("̛".to_owned()), + Keysym::dead_stroke => Some("̶̶".to_owned()), + Keysym::dead_abovecomma => Some("̓̓".to_owned()), + Keysym::dead_abovereversedcomma => Some("ʽ".to_owned()), + Keysym::dead_doublegrave => Some("̏".to_owned()), + Keysym::dead_belowring => Some("˳".to_owned()), + Keysym::dead_belowmacron => Some("̱".to_owned()), + Keysym::dead_belowcircumflex => Some("ꞈ".to_owned()), + Keysym::dead_belowtilde => Some("̰".to_owned()), + Keysym::dead_belowbreve => Some("̮".to_owned()), + Keysym::dead_belowdiaeresis => Some("̤".to_owned()), + Keysym::dead_invertedbreve => Some("̯".to_owned()), + Keysym::dead_belowcomma => Some("̦".to_owned()), + Keysym::dead_currency => None, + Keysym::dead_lowline => None, + Keysym::dead_aboveverticalline => None, + Keysym::dead_belowverticalline => None, + Keysym::dead_longsolidusoverlay => None, + Keysym::dead_a => None, + Keysym::dead_A => None, + Keysym::dead_e => None, + Keysym::dead_E => None, + Keysym::dead_i => None, + Keysym::dead_I => None, + Keysym::dead_o => None, + Keysym::dead_O => None, + Keysym::dead_u => None, + Keysym::dead_U => None, + Keysym::dead_small_schwa => Some("ə".to_owned()), + Keysym::dead_capital_schwa => Some("Ə".to_owned()), + Keysym::dead_greek => None, + _ => None, } } - #[cfg(any(feature = "wayland", feature = "x11"))] -impl crate::Capslock { - pub(super) fn from_xkb(keymap_state: &State) -> Self { - let on = keymap_state.mod_name_is_active(xkb::MOD_NAME_CAPS, xkb::STATE_MODS_EFFECTIVE); - Self { on } +pub(super) fn modifiers_from_xkb(keymap_state: &State) -> gpui::Modifiers { + let shift = keymap_state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE); + let alt = keymap_state.mod_name_is_active(xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE); + let control = keymap_state.mod_name_is_active(xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE); + let platform = keymap_state.mod_name_is_active(xkb::MOD_NAME_LOGO, xkb::STATE_MODS_EFFECTIVE); + gpui::Modifiers { + shift, + alt, + control, + platform, + function: false, } } +#[cfg(any(feature = "wayland", feature = "x11"))] +pub(super) fn capslock_from_xkb(keymap_state: &State) -> gpui::Capslock { + let on = keymap_state.mod_name_is_active(xkb::MOD_NAME_CAPS, xkb::STATE_MODS_EFFECTIVE); + gpui::Capslock { on } +} + #[cfg(test)] mod tests { use super::*; - use crate::{Point, px}; + use gpui::{Point, px}; #[test] fn test_is_within_click_distance() { diff --git a/crates/gpui/src/platform/linux/text_system.rs b/crates/gpui_linux/src/linux/text_system.rs similarity index 85% rename from crates/gpui/src/platform/linux/text_system.rs rename to crates/gpui_linux/src/linux/text_system.rs index 63532ee85a0669663abbfc5053329b4adcdcac62..af0298e5961e500fe9e01495905ba53a85f74f37 100644 --- a/crates/gpui/src/platform/linux/text_system.rs +++ b/crates/gpui_linux/src/linux/text_system.rs @@ -1,22 +1,17 @@ -use crate::{ - Bounds, DevicePixels, Font, FontFeatures, FontId, FontMetrics, FontRun, FontStyle, FontWeight, - GlyphId, LineLayout, Pixels, PlatformTextSystem, Point, RenderGlyphParams, SUBPIXEL_VARIANTS_X, - SUBPIXEL_VARIANTS_Y, ShapedGlyph, ShapedRun, SharedString, Size, TextRenderingMode, point, - size, -}; use anyhow::{Context as _, Ok, Result}; use collections::HashMap; use cosmic_text::{ Attrs, AttrsList, Family, Font as CosmicTextFont, FontFeatures as CosmicFontFeatures, FontSystem, ShapeBuffer, ShapeLine, }; +use gpui::{ + Bounds, DevicePixels, Font, FontFeatures, FontId, FontMetrics, FontRun, GlyphId, LineLayout, + Pixels, PlatformTextSystem, RenderGlyphParams, SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y, + ShapedGlyph, ShapedRun, SharedString, Size, TextRenderingMode, point, size, +}; use itertools::Itertools; use parking_lot::RwLock; -use pathfinder_geometry::{ - rect::{RectF, RectI}, - vector::{Vector2F, Vector2I}, -}; use smallvec::SmallVec; use std::{borrow::Cow, sync::Arc}; use swash::{ @@ -58,7 +53,7 @@ struct LoadedFont { impl CosmicTextSystem { pub(crate) fn new() -> Self { // todo(linux) make font loading non-blocking - let mut font_system = FontSystem::new(); + let font_system = FontSystem::new(); Self(RwLock::new(CosmicTextSystemState { font_system, @@ -227,7 +222,7 @@ impl CosmicTextSystemState { features: &FontFeatures, ) -> Result> { // TODO: Determine the proper system UI font. - let name = crate::text_system::font_name_with_fallbacks(name, "IBM Plex Sans"); + let name = gpui::font_name_with_fallbacks(name, "IBM Plex Sans"); let families = self .font_system @@ -261,7 +256,7 @@ impl CosmicTextSystemState { loaded_font_ids.push(font_id); self.loaded_fonts.push(LoadedFont { font, - features: features.try_into()?, + features: cosmic_font_features(features)?, is_known_emoji_font: check_is_known_emoji_font(&postscript_name), }); } @@ -324,7 +319,7 @@ impl CosmicTextSystemState { ) -> Result { let loaded_font = &self.loaded_fonts[params.font_id.0]; let font_ref = loaded_font.font.as_swash(); - let pixel_size = params.font_size.0; + let pixel_size = f32::from(params.font_size); let subpixel_offset = Vector::new( params.subpixel_variant.x as f32 / SUBPIXEL_VARIANTS_X as f32 / params.scale_factor, @@ -428,7 +423,7 @@ impl CosmicTextSystemState { let mut layout_lines = Vec::with_capacity(1); line.layout_to_buffer( &mut self.scratch, - font_size.0, + f32::from(font_size), None, // We do our own wrapping cosmic_text::Wrap::None, None, @@ -484,93 +479,28 @@ impl CosmicTextSystemState { } } -impl TryFrom<&FontFeatures> for CosmicFontFeatures { - type Error = anyhow::Error; - - fn try_from(features: &FontFeatures) -> Result { - let mut result = CosmicFontFeatures::new(); - for feature in features.0.iter() { - let name_bytes: [u8; 4] = feature - .0 - .as_bytes() - .try_into() - .context("Incorrect feature flag format")?; - - let tag = cosmic_text::FeatureTag::new(&name_bytes); - - result.set(tag, feature.1); - } - Ok(result) - } -} - -impl From for Bounds { - fn from(rect: RectF) -> Self { - Bounds { - origin: point(rect.origin_x(), rect.origin_y()), - size: size(rect.width(), rect.height()), - } - } -} - -impl From for Bounds { - fn from(rect: RectI) -> Self { - Bounds { - origin: point(DevicePixels(rect.origin_x()), DevicePixels(rect.origin_y())), - size: size(DevicePixels(rect.width()), DevicePixels(rect.height())), - } - } -} - -impl From for Size { - fn from(value: Vector2I) -> Self { - size(value.x().into(), value.y().into()) - } -} - -impl From for Bounds { - fn from(rect: RectI) -> Self { - Bounds { - origin: point(rect.origin_x(), rect.origin_y()), - size: size(rect.width(), rect.height()), - } - } -} - -impl From> for Vector2I { - fn from(size: Point) -> Self { - Vector2I::new(size.x as i32, size.y as i32) - } -} - -impl From for Size { - fn from(vec: Vector2F) -> Self { - size(vec.x(), vec.y()) - } -} +fn cosmic_font_features(features: &FontFeatures) -> Result { + let mut result = CosmicFontFeatures::new(); + for feature in features.0.iter() { + let name_bytes: [u8; 4] = feature + .0 + .as_bytes() + .try_into() + .context("Incorrect feature flag format")?; -impl From for cosmic_text::Weight { - fn from(value: FontWeight) -> Self { - cosmic_text::Weight(value.0 as u16) - } -} + let tag = cosmic_text::FeatureTag::new(&name_bytes); -impl From for cosmic_text::Style { - fn from(style: FontStyle) -> Self { - match style { - FontStyle::Normal => cosmic_text::Style::Normal, - FontStyle::Italic => cosmic_text::Style::Italic, - FontStyle::Oblique => cosmic_text::Style::Oblique, - } + result.set(tag, feature.1); } + Ok(result) } -fn font_into_properties(font: &crate::Font) -> font_kit::properties::Properties { +fn font_into_properties(font: &gpui::Font) -> font_kit::properties::Properties { font_kit::properties::Properties { style: match font.style { - crate::FontStyle::Normal => font_kit::properties::Style::Normal, - crate::FontStyle::Italic => font_kit::properties::Style::Italic, - crate::FontStyle::Oblique => font_kit::properties::Style::Oblique, + gpui::FontStyle::Normal => font_kit::properties::Style::Normal, + gpui::FontStyle::Italic => font_kit::properties::Style::Italic, + gpui::FontStyle::Oblique => font_kit::properties::Style::Oblique, }, weight: font_kit::properties::Weight(font.weight.0), stretch: Default::default(), diff --git a/crates/gpui_linux/src/linux/wayland.rs b/crates/gpui_linux/src/linux/wayland.rs new file mode 100644 index 0000000000000000000000000000000000000000..aa1e797404341900443002b35aaf73acefcb7c44 --- /dev/null +++ b/crates/gpui_linux/src/linux/wayland.rs @@ -0,0 +1,47 @@ +mod client; +mod clipboard; +mod cursor; +mod display; +mod serial; +mod window; + +/// Contains Types for configuring layer_shell surfaces. +pub mod layer_shell; + +pub(crate) use client::*; + +use wayland_protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::Shape; + +use gpui::CursorStyle; + +pub(super) fn to_shape(style: CursorStyle) -> Shape { + match style { + CursorStyle::Arrow => Shape::Default, + CursorStyle::IBeam => Shape::Text, + CursorStyle::Crosshair => Shape::Crosshair, + CursorStyle::ClosedHand => Shape::Grabbing, + CursorStyle::OpenHand => Shape::Grab, + CursorStyle::PointingHand => Shape::Pointer, + CursorStyle::ResizeLeft => Shape::WResize, + CursorStyle::ResizeRight => Shape::EResize, + CursorStyle::ResizeLeftRight => Shape::EwResize, + CursorStyle::ResizeUp => Shape::NResize, + CursorStyle::ResizeDown => Shape::SResize, + CursorStyle::ResizeUpDown => Shape::NsResize, + CursorStyle::ResizeUpLeftDownRight => Shape::NwseResize, + CursorStyle::ResizeUpRightDownLeft => Shape::NeswResize, + CursorStyle::ResizeColumn => Shape::ColResize, + CursorStyle::ResizeRow => Shape::RowResize, + CursorStyle::IBeamCursorForVerticalLayout => Shape::VerticalText, + CursorStyle::OperationNotAllowed => Shape::NotAllowed, + CursorStyle::DragLink => Shape::Alias, + CursorStyle::DragCopy => Shape::Copy, + CursorStyle::ContextualMenu => Shape::ContextMenu, + CursorStyle::None => { + #[cfg(debug_assertions)] + panic!("CursorStyle::None should be handled separately in the client"); + #[cfg(not(debug_assertions))] + Shape::Default + } + } +} diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui_linux/src/linux/wayland/client.rs similarity index 95% rename from crates/gpui/src/platform/linux/wayland/client.rs rename to crates/gpui_linux/src/linux/wayland/client.rs index 41f12916b971d173181225dce185872f4dba6c72..2378b822c53dce527d622b24da7cb602b4fc7060 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui_linux/src/linux/wayland/client.rs @@ -73,32 +73,29 @@ use super::{ window::{ImeInput, WaylandWindowStatePtr}, }; -use crate::{ - AnyWindowHandle, Bounds, Capslock, CursorStyle, DOUBLE_CLICK_INTERVAL, DevicePixels, DisplayId, - FileDropEvent, ForegroundExecutor, KeyDownEvent, KeyUpEvent, Keystroke, LinuxCommon, - LinuxKeyboardLayout, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, - MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, Pixels, PlatformDisplay, - PlatformInput, PlatformKeyboardLayout, Point, ResultExt as _, SCROLL_LINES, ScrollDelta, - ScrollWheelEvent, Size, TouchPhase, WindowParams, point, profiler, px, size, -}; -use crate::{ - SharedString, - platform::linux::{ - LinuxClient, get_xkb_compose_state, is_within_click_distance, open_uri_internal, read_fd, - reveal_path_internal, - wayland::{ - clipboard::{Clipboard, DataOffer, FILE_LIST_MIME_TYPE, TEXT_MIME_TYPES}, - cursor::Cursor, - serial::{SerialKind, SerialTracker}, - window::WaylandWindow, - }, - xdg_desktop_portal::{Event as XDPEvent, XDPEventSource}, +use crate::linux::{ + DOUBLE_CLICK_INTERVAL, LinuxClient, LinuxCommon, LinuxKeyboardLayout, ResultExt as _, + SCROLL_LINES, capslock_from_xkb, cursor_style_to_icon_names, get_xkb_compose_state, + is_within_click_distance, keystroke_from_xkb, keystroke_underlying_dead_key, + modifiers_from_xkb, open_uri_internal, read_fd, reveal_path_internal, + wayland::{ + clipboard::{Clipboard, DataOffer, FILE_LIST_MIME_TYPE, TEXT_MIME_TYPES}, + cursor::Cursor, + serial::{SerialKind, SerialTracker}, + to_shape, + window::WaylandWindow, }, + xdg_desktop_portal::{Event as XDPEvent, XDPEventSource}, }; -use crate::{ - TaskTiming, - platform::{PlatformWindow, wgpu::WgpuContext}, +use gpui::{ + AnyWindowHandle, Bounds, Capslock, CursorStyle, DevicePixels, DisplayId, FileDropEvent, + ForegroundExecutor, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, ModifiersChangedEvent, + MouseButton, MouseDownEvent, MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, + Pixels, PlatformDisplay, PlatformInput, PlatformKeyboardLayout, PlatformWindow, Point, + ScrollDelta, ScrollWheelEvent, SharedString, Size, TaskTiming, TouchPhase, WindowParams, point, + profiler, px, size, }; +use gpui_wgpu::WgpuContext; /// Used to convert evdev scancode to xkb scancode const MIN_KEYCODE: u32 = 8; @@ -303,7 +300,7 @@ impl WaylandClientStatePtr { pub fn enable_ime(&self) { let client = self.get_client(); let mut state = client.borrow_mut(); - let Some(mut text_input) = state.text_input.take() else { + let Some(text_input) = state.text_input.take() else { return; }; @@ -313,10 +310,10 @@ impl WaylandClientStatePtr { drop(state); if let Some(area) = window.get_ime_area() { text_input.set_cursor_rectangle( - area.origin.x.0 as i32, - area.origin.y.0 as i32, - area.size.width.0 as i32, - area.size.height.0 as i32, + f32::from(area.origin.x) as i32, + f32::from(area.origin.y) as i32, + f32::from(area.size.width) as i32, + f32::from(area.size.height) as i32, ); } state = client.borrow_mut(); @@ -337,17 +334,17 @@ impl WaylandClientStatePtr { pub fn update_ime_position(&self, bounds: Bounds) { let client = self.get_client(); - let mut state = client.borrow_mut(); + let state = client.borrow_mut(); if state.composing || state.text_input.is_none() || state.pre_edit_text.is_some() { return; } let text_input = state.text_input.as_ref().unwrap(); text_input.set_cursor_rectangle( - bounds.origin.x.0 as i32, - bounds.origin.y.0 as i32, - bounds.size.width.0 as i32, - bounds.size.height.0 as i32, + bounds.origin.x.as_f32() as i32, + bounds.origin.y.as_f32() as i32, + bounds.size.width.as_f32() as i32, + bounds.size.height.as_f32() as i32, ); text_input.commit(); } @@ -382,7 +379,7 @@ impl WaylandClientStatePtr { } pub fn drop_window(&self, surface_id: &ObjectId) { - let mut client = self.get_client(); + let client = self.get_client(); let mut state = client.borrow_mut(); let closed_window = state.windows.remove(surface_id).unwrap(); if let Some(window) = state.mouse_focused_window.take() @@ -456,8 +453,7 @@ impl WaylandClient { pub(crate) fn new() -> Self { let conn = Connection::connect_to_env().unwrap(); - let (globals, mut event_queue) = - registry_queue_init::(&conn).unwrap(); + let (globals, event_queue) = registry_queue_init::(&conn).unwrap(); let qh = event_queue.handle(); let mut seat: Option = None; @@ -540,7 +536,7 @@ impl WaylandClient { .as_ref() .map(|primary_selection_manager| primary_selection_manager.get_device(&seat, &qh, ())); - let mut cursor = Cursor::new(&conn, &globals, 24); + let cursor = Cursor::new(&conn, &globals, 24); handle .insert_source(XDPEventSource::new(&common.background_executor), { @@ -572,7 +568,7 @@ impl WaylandClient { }) .unwrap(); - let mut state = Rc::new(RefCell::new(WaylandClientState { + let state = Rc::new(RefCell::new(WaylandClientState { serial_tracker: SerialTracker::new(), globals, gpu_context, @@ -673,7 +669,7 @@ impl LinuxClient for WaylandClient { .outputs .iter() .find_map(|(object_id, output)| { - (object_id.protocol_id() == id.0).then(|| { + (object_id.protocol_id() == u32::from(id)).then(|| { Rc::new(WaylandDisplay { id: object_id.clone(), name: output.name.clone(), @@ -695,7 +691,7 @@ impl LinuxClient for WaylandClient { #[cfg(feature = "screen-capture")] fn screen_capture_sources( &self, - ) -> futures::channel::oneshot::Receiver>>> + ) -> futures::channel::oneshot::Receiver>>> { // TODO: Get screen capture working on wayland. Be sure to try window resizing as that may // be tricky. @@ -754,7 +750,7 @@ impl LinuxClient for WaylandClient { .expect("window is focused by pointer"); wl_pointer.set_cursor(serial, None, 0, 0); } else if let Some(cursor_shape_device) = &state.cursor_shape_device { - cursor_shape_device.set_shape(serial, style.to_shape()); + cursor_shape_device.set_shape(serial, to_shape(style)); } else if let Some(focused_window) = &state.mouse_focused_window { // cursor-shape-v1 isn't supported, set the cursor using a surface. let wl_pointer = state @@ -762,9 +758,12 @@ impl LinuxClient for WaylandClient { .clone() .expect("window is focused by pointer"); let scale = focused_window.primary_output_scale(); - state - .cursor - .set_icon(&wl_pointer, serial, style.to_icon_names(), scale); + state.cursor.set_icon( + &wl_pointer, + serial, + cursor_style_to_icon_names(style), + scale, + ); } } } @@ -826,7 +825,7 @@ impl LinuxClient for WaylandClient { .log_err(); } - fn write_to_primary(&self, item: crate::ClipboardItem) { + fn write_to_primary(&self, item: gpui::ClipboardItem) { let mut state = self.0.borrow_mut(); let (Some(primary_selection_manager), Some(primary_selection)) = ( state.globals.primary_selection_manager.clone(), @@ -846,7 +845,7 @@ impl LinuxClient for WaylandClient { } } - fn write_to_clipboard(&self, item: crate::ClipboardItem) { + fn write_to_clipboard(&self, item: gpui::ClipboardItem) { let mut state = self.0.borrow_mut(); let (Some(data_device_manager), Some(data_device)) = ( state.globals.data_device_manager.clone(), @@ -866,11 +865,11 @@ impl LinuxClient for WaylandClient { } } - fn read_from_primary(&self) -> Option { + fn read_from_primary(&self) -> Option { self.0.borrow_mut().clipboard.read_primary() } - fn read_from_clipboard(&self) -> Option { + fn read_from_clipboard(&self) -> Option { self.0.borrow_mut().clipboard.read() } @@ -914,7 +913,7 @@ impl Dispatch for WaylandClientStat _: &Connection, qh: &QueueHandle, ) { - let mut client = this.get_client(); + let client = this.get_client(); let mut state = client.borrow_mut(); match event { @@ -1002,7 +1001,7 @@ impl Dispatch for WaylandClientStatePtr { } pub(crate) fn get_window( - mut state: &mut RefMut, + state: &mut RefMut, surface_id: &ObjectId, ) -> Option { state.windows.get(surface_id).cloned() @@ -1017,7 +1016,7 @@ impl Dispatch for WaylandClientStatePtr { _: &Connection, _: &QueueHandle, ) { - let mut client = this.get_client(); + let client = this.get_client(); let mut state = client.borrow_mut(); let Some(window) = get_window(&mut state, &surface.id()) else { @@ -1040,10 +1039,10 @@ impl Dispatch for WaylandClientStatePtr { _: &Connection, _: &QueueHandle, ) { - let mut client = this.get_client(); + let client = this.get_client(); let mut state = client.borrow_mut(); - let Some(mut in_progress_output) = state.in_progress_outputs.get_mut(&output.id()) else { + let Some(in_progress_output) = state.in_progress_outputs.get_mut(&output.id()) else { return; }; @@ -1257,7 +1256,7 @@ impl Dispatch for WaylandClientStatePtr { _: &Connection, _: &QueueHandle, ) { - let mut client = this.get_client(); + let client = this.get_client(); let mut state = client.borrow_mut(); match event { wl_keyboard::Event::RepeatInfo { rate, delay } => { @@ -1332,9 +1331,9 @@ impl Dispatch for WaylandClientStatePtr { let old_layout = keymap_state.serialize_layout(xkbcommon::xkb::STATE_LAYOUT_EFFECTIVE); keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group); - state.modifiers = Modifiers::from_xkb(keymap_state); + state.modifiers = modifiers_from_xkb(keymap_state); let keymap_state = state.keymap_state.as_mut().unwrap(); - state.capslock = Capslock::from_xkb(keymap_state); + state.capslock = capslock_from_xkb(keymap_state); let input = PlatformInput::ModifiersChanged(ModifiersChangedEvent { modifiers: state.modifiers, @@ -1370,14 +1369,14 @@ impl Dispatch for WaylandClientStatePtr { match key_state { wl_keyboard::KeyState::Pressed if !keysym.is_modifier_key() => { let mut keystroke = - Keystroke::from_xkb(keymap_state, state.modifiers, keycode); + keystroke_from_xkb(keymap_state, state.modifiers, keycode); if let Some(mut compose) = state.compose_state.take() { compose.feed(keysym); match compose.status() { xkb::Status::Composing => { keystroke.key_char = None; state.pre_edit_text = - compose.utf8().or(Keystroke::underlying_dead_key(keysym)); + compose.utf8().or(keystroke_underlying_dead_key(keysym)); let pre_edit = state.pre_edit_text.clone().unwrap_or(String::default()); drop(state); @@ -1394,7 +1393,7 @@ impl Dispatch for WaylandClientStatePtr { } xkb::Status::Cancelled => { let pre_edit = state.pre_edit_text.take(); - let new_pre_edit = Keystroke::underlying_dead_key(keysym); + let new_pre_edit = keystroke_underlying_dead_key(keysym); state.pre_edit_text = new_pre_edit.clone(); drop(state); if let Some(pre_edit) = pre_edit { @@ -1432,8 +1431,8 @@ impl Dispatch for WaylandClientStatePtr { prefer_character_input: false, }); move |event_timestamp, _metadata, this| { - let mut client = this.get_client(); - let mut state = client.borrow_mut(); + let client = this.get_client(); + let state = client.borrow(); let is_repeating = id == state.repeat.current_id && state.repeat.current_keycode.is_some() && state.keyboard_focused_window.is_some(); @@ -1459,7 +1458,7 @@ impl Dispatch for WaylandClientStatePtr { } wl_keyboard::KeyState::Released if !keysym.is_modifier_key() => { let input = PlatformInput::KeyUp(KeyUpEvent { - keystroke: Keystroke::from_xkb(keymap_state, state.modifiers, keycode), + keystroke: keystroke_from_xkb(keymap_state, state.modifiers, keycode), }); if state.repeat.current_keycode == Some(keycode) { @@ -1538,10 +1537,10 @@ impl Dispatch for WaylandClientStatePtr { window.handle_ime(ImeInput::SetMarkedText(text)); if let Some(area) = window.get_ime_area() { text_input.set_cursor_rectangle( - area.origin.x.0 as i32, - area.origin.y.0 as i32, - area.size.width.0 as i32, - area.size.height.0 as i32, + f32::from(area.origin.x) as i32, + f32::from(area.origin.y) as i32, + f32::from(area.size.width) as i32, + f32::from(area.size.height) as i32, ); if last_serial == serial { text_input.commit(); @@ -1587,7 +1586,7 @@ impl Dispatch for WaylandClientStatePtr { _: &Connection, _: &QueueHandle, ) { - let mut client = this.get_client(); + let client = this.get_client(); let mut state = client.borrow_mut(); match event { @@ -1616,12 +1615,15 @@ impl Dispatch for WaylandClientStatePtr { .expect("window is focused by pointer"); wl_pointer.set_cursor(serial, None, 0, 0); } else if let Some(cursor_shape_device) = &state.cursor_shape_device { - cursor_shape_device.set_shape(serial, style.to_shape()); + cursor_shape_device.set_shape(serial, to_shape(style)); } else { let scale = window.primary_output_scale(); - state - .cursor - .set_icon(wl_pointer, serial, style.to_icon_names(), scale); + state.cursor.set_icon( + wl_pointer, + serial, + cursor_style_to_icon_names(style), + scale, + ); } } drop(state); @@ -1662,7 +1664,7 @@ impl Dispatch for WaylandClientStatePtr { state.cursor_style = Some(default_style); if let Some(cursor_shape_device) = &state.cursor_shape_device { - cursor_shape_device.set_shape(serial, default_style.to_shape()); + cursor_shape_device.set_shape(serial, to_shape(default_style)); } else { // cursor-shape-v1 isn't supported, set the cursor using a surface. let wl_pointer = state @@ -1673,7 +1675,7 @@ impl Dispatch for WaylandClientStatePtr { state.cursor.set_icon( &wl_pointer, serial, - default_style.to_icon_names(), + cursor_style_to_icon_names(default_style), scale, ); } @@ -2043,7 +2045,7 @@ impl Dispatch for WaylandClientStatePtr { let input = PlatformInput::FileDrop(FileDropEvent::Entered { position, - paths: crate::ExternalPaths(paths), + paths: gpui::ExternalPaths(paths), }); let client = this.get_client(); @@ -2151,7 +2153,7 @@ impl Dispatch for WaylandClientStatePtr { _: &QueueHandle, ) { let client = this.get_client(); - let mut state = client.borrow_mut(); + let state = client.borrow_mut(); match event { wl_data_source::Event::Send { mime_type, fd } => { @@ -2237,7 +2239,7 @@ impl Dispatch _: &QueueHandle, ) { let client = this.get_client(); - let mut state = client.borrow_mut(); + let state = client.borrow_mut(); match event { zwp_primary_selection_source_v1::Event::Send { mime_type, fd } => { diff --git a/crates/gpui/src/platform/linux/wayland/clipboard.rs b/crates/gpui_linux/src/linux/wayland/clipboard.rs similarity index 97% rename from crates/gpui/src/platform/linux/wayland/clipboard.rs rename to crates/gpui_linux/src/linux/wayland/clipboard.rs index 9d58ad7391a5d699688d6690a0dc660d01b3abbf..49c58724dadc3b4002f44f4eabd8e38e1d46def7 100644 --- a/crates/gpui/src/platform/linux/wayland/clipboard.rs +++ b/crates/gpui_linux/src/linux/wayland/clipboard.rs @@ -10,10 +10,8 @@ use strum::IntoEnumIterator; use wayland_client::{Connection, protocol::wl_data_offer::WlDataOffer}; use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_offer_v1::ZwpPrimarySelectionOfferV1; -use crate::{ - ClipboardEntry, ClipboardItem, Image, ImageFormat, WaylandClientStatePtr, hash, - platform::linux::platform::read_fd, -}; +use crate::linux::{WaylandClientStatePtr, platform::read_fd}; +use gpui::{ClipboardEntry, ClipboardItem, Image, ImageFormat, hash}; /// Text mime types that we'll offer to other programs. pub(crate) const TEXT_MIME_TYPES: [&str; 3] = @@ -241,7 +239,7 @@ impl Clipboard { calloop::Mode::Level, ), move |_, file, _| { - let mut file = unsafe { file.get_mut() }; + let file = unsafe { file.get_mut() }; loop { match file.write(&bytes[written..]) { Ok(n) if written + n == bytes.len() => { diff --git a/crates/gpui/src/platform/linux/wayland/cursor.rs b/crates/gpui_linux/src/linux/wayland/cursor.rs similarity index 94% rename from crates/gpui/src/platform/linux/wayland/cursor.rs rename to crates/gpui_linux/src/linux/wayland/cursor.rs index c7c9139dea795701e459387a309b1817e2f60971..957fcf39be832ecc3388dd029d8c9523c998dee3 100644 --- a/crates/gpui/src/platform/linux/wayland/cursor.rs +++ b/crates/gpui_linux/src/linux/wayland/cursor.rs @@ -1,5 +1,5 @@ -use crate::Globals; -use crate::platform::linux::{DEFAULT_CURSOR_ICON_NAME, log_cursor_icon_warning}; +use crate::linux::Globals; +use crate::linux::{DEFAULT_CURSOR_ICON_NAME, log_cursor_icon_warning}; use anyhow::{Context as _, anyhow}; use util::ResultExt; @@ -95,7 +95,7 @@ impl Cursor { &mut self, wl_pointer: &WlPointer, serial_id: u32, - mut cursor_icon_names: &[&str], + cursor_icon_names: &[&str], scale: i32, ) { self.set_scaled_size(self.size * scale as u32); @@ -104,9 +104,9 @@ impl Cursor { log::warn!("Wayland: Unable to load cursor themes"); return; }; - let mut theme = &mut loaded_theme.theme; + let theme = &mut loaded_theme.theme; - let mut buffer: &CursorImageBuffer; + let buffer: &CursorImageBuffer; 'outer: { for cursor_icon_name in cursor_icon_names { if let Some(cursor) = theme.get_cursor(cursor_icon_name) { diff --git a/crates/gpui/src/platform/linux/wayland/display.rs b/crates/gpui_linux/src/linux/wayland/display.rs similarity index 89% rename from crates/gpui/src/platform/linux/wayland/display.rs rename to crates/gpui_linux/src/linux/wayland/display.rs index c3d2fc9815d1d22cf43510248fb833867074b7da..874cae878381cfeabc502c780f3d15c168368522 100644 --- a/crates/gpui/src/platform/linux/wayland/display.rs +++ b/crates/gpui_linux/src/linux/wayland/display.rs @@ -7,7 +7,7 @@ use anyhow::Context as _; use uuid::Uuid; use wayland_backend::client::ObjectId; -use crate::{Bounds, DisplayId, Pixels, PlatformDisplay}; +use gpui::{Bounds, DisplayId, Pixels, PlatformDisplay}; #[derive(Debug, Clone)] pub(crate) struct WaylandDisplay { @@ -25,7 +25,7 @@ impl Hash for WaylandDisplay { impl PlatformDisplay for WaylandDisplay { fn id(&self) -> DisplayId { - DisplayId(self.id.protocol_id()) + DisplayId::new(self.id.protocol_id()) } fn uuid(&self) -> anyhow::Result { diff --git a/crates/gpui_linux/src/linux/wayland/layer_shell.rs b/crates/gpui_linux/src/linux/wayland/layer_shell.rs new file mode 100644 index 0000000000000000000000000000000000000000..a400552065df07fc38e98117e90be2a5795473d7 --- /dev/null +++ b/crates/gpui_linux/src/linux/wayland/layer_shell.rs @@ -0,0 +1,26 @@ +pub use gpui::layer_shell::*; + +use wayland_protocols_wlr::layer_shell::v1::client::{zwlr_layer_shell_v1, zwlr_layer_surface_v1}; + +pub(crate) fn wayland_layer(layer: Layer) -> zwlr_layer_shell_v1::Layer { + match layer { + Layer::Background => zwlr_layer_shell_v1::Layer::Background, + Layer::Bottom => zwlr_layer_shell_v1::Layer::Bottom, + Layer::Top => zwlr_layer_shell_v1::Layer::Top, + Layer::Overlay => zwlr_layer_shell_v1::Layer::Overlay, + } +} + +pub(crate) fn wayland_anchor(anchor: Anchor) -> zwlr_layer_surface_v1::Anchor { + zwlr_layer_surface_v1::Anchor::from_bits_truncate(anchor.bits()) +} + +pub(crate) fn wayland_keyboard_interactivity( + value: KeyboardInteractivity, +) -> zwlr_layer_surface_v1::KeyboardInteractivity { + match value { + KeyboardInteractivity::None => zwlr_layer_surface_v1::KeyboardInteractivity::None, + KeyboardInteractivity::Exclusive => zwlr_layer_surface_v1::KeyboardInteractivity::Exclusive, + KeyboardInteractivity::OnDemand => zwlr_layer_surface_v1::KeyboardInteractivity::OnDemand, + } +} diff --git a/crates/gpui/src/platform/linux/wayland/serial.rs b/crates/gpui_linux/src/linux/wayland/serial.rs similarity index 100% rename from crates/gpui/src/platform/linux/wayland/serial.rs rename to crates/gpui_linux/src/linux/wayland/serial.rs diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui_linux/src/linux/wayland/window.rs similarity index 94% rename from crates/gpui/src/platform/linux/wayland/window.rs rename to crates/gpui_linux/src/linux/wayland/window.rs index 7642b93ffe1b8fc7ee9d227fe3711704a370ce87..54e868683696b6b6bee08b6ab09fdae15b9cbaf4 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui_linux/src/linux/wayland/window.rs @@ -24,27 +24,22 @@ use wayland_protocols::{ use wayland_protocols_plasma::blur::client::org_kde_kwin_blur; use wayland_protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1; -use crate::{ - AnyWindowHandle, Bounds, Decorations, DevicePixels, Globals, GpuSpecs, Modifiers, Output, - Pixels, PlatformDisplay, PlatformInput, Point, PromptButton, PromptLevel, RequestFrameOptions, - ResizeEdge, Size, Tiling, WaylandClientStatePtr, WindowAppearance, WindowBackgroundAppearance, - WindowBounds, WindowControlArea, WindowControls, WindowDecorations, WindowParams, get_window, - layer_shell::LayerShellNotSupportedError, px, size, +use crate::linux::wayland::{display::WaylandDisplay, serial::SerialKind}; +use crate::linux::{Globals, Output, WaylandClientStatePtr, get_window}; +use gpui::{ + AnyWindowHandle, Bounds, Capslock, Decorations, DevicePixels, GpuSpecs, Modifiers, Pixels, + PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, + PromptButton, PromptLevel, RequestFrameOptions, ResizeEdge, Scene, Size, Tiling, + WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowControls, + WindowDecorations, WindowKind, WindowParams, layer_shell::LayerShellNotSupportedError, px, + size, }; -use crate::{ - Capslock, - platform::{ - PlatformAtlas, PlatformInputHandler, PlatformWindow, - linux::wayland::{display::WaylandDisplay, serial::SerialKind}, - wgpu::{WgpuContext, WgpuRenderer, WgpuSurfaceConfig}, - }, -}; -use crate::{WindowKind, scene::Scene}; +use gpui_wgpu::{WgpuContext, WgpuRenderer, WgpuSurfaceConfig}; #[derive(Default)] pub(crate) struct Callbacks { request_frame: Option>, - input: Option crate::DispatchEventResult>>, + input: Option gpui::DispatchEventResult>>, active_status_change: Option>, hover_status_change: Option>, resize: Option, f32)>>, @@ -144,34 +139,37 @@ impl WaylandSurfaceState { let layer_surface = layer_shell.get_layer_surface( &surface, None, - options.layer.into(), + super::layer_shell::wayland_layer(options.layer), options.namespace.clone(), &globals.qh, surface.id(), ); - let width = params.bounds.size.width.0; - let height = params.bounds.size.height.0; + let width = f32::from(params.bounds.size.width); + let height = f32::from(params.bounds.size.height); layer_surface.set_size(width as u32, height as u32); - layer_surface.set_anchor(options.anchor.into()); - layer_surface.set_keyboard_interactivity(options.keyboard_interactivity.into()); + layer_surface.set_anchor(super::layer_shell::wayland_anchor(options.anchor)); + layer_surface.set_keyboard_interactivity( + super::layer_shell::wayland_keyboard_interactivity(options.keyboard_interactivity), + ); if let Some(margin) = options.margin { layer_surface.set_margin( - margin.0.0 as i32, - margin.1.0 as i32, - margin.2.0 as i32, - margin.3.0 as i32, + f32::from(margin.0) as i32, + f32::from(margin.1) as i32, + f32::from(margin.2) as i32, + f32::from(margin.3) as i32, ) } if let Some(exclusive_zone) = options.exclusive_zone { - layer_surface.set_exclusive_zone(exclusive_zone.0 as i32); + layer_surface.set_exclusive_zone(f32::from(exclusive_zone) as i32); } if let Some(exclusive_edge) = options.exclusive_edge { - layer_surface.set_exclusive_edge(exclusive_edge.into()); + layer_surface + .set_exclusive_edge(super::layer_shell::wayland_anchor(exclusive_edge)); } return Ok(WaylandSurfaceState::LayerShell(WaylandLayerSurfaceState { @@ -208,7 +206,7 @@ impl WaylandSurfaceState { }; if let Some(size) = params.window_min_size { - toplevel.set_min_size(size.width.0 as i32, size.height.0 as i32); + toplevel.set_min_size(f32::from(size.width) as i32, f32::from(size.height) as i32); } // Attempt to set up window decorations based on the requested configuration @@ -335,8 +333,8 @@ impl WaylandWindowState { }; let config = WgpuSurfaceConfig { size: Size { - width: DevicePixels(options.bounds.size.width.0 as i32), - height: DevicePixels(options.bounds.size.height.0 as i32), + width: DevicePixels(f32::from(options.bounds.size.width) as i32), + height: DevicePixels(f32::from(options.bounds.size.height) as i32), }, transparent: true, }; @@ -618,7 +616,7 @@ impl WaylandWindowStatePtr { state.inset(), state.tiling, ) - .map(|v| v.0 as i32) + .map(|v| f32::from(v) as i32) .map_size(|v| if v <= 0 { 1 } else { v }); state.surface_state.set_geometry( @@ -642,7 +640,7 @@ impl WaylandWindowStatePtr { match mode { WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ServerSide) => { self.state.borrow_mut().decorations = WindowDecorations::Server; - if let Some(mut appearance_changed) = + if let Some(appearance_changed) = self.callbacks.borrow_mut().appearance_changed.as_mut() { appearance_changed(); @@ -651,7 +649,7 @@ impl WaylandWindowStatePtr { WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ClientSide) => { self.state.borrow_mut().decorations = WindowDecorations::Client; // Update background to be transparent - if let Some(mut appearance_changed) = + if let Some(appearance_changed) = self.callbacks.borrow_mut().appearance_changed.as_mut() { appearance_changed(); @@ -680,7 +678,7 @@ impl WaylandWindowStatePtr { height, states, } => { - let mut size = if width == 0 || height == 0 { + let size = if width == 0 || height == 0 { None } else { Some(size(px(width as f32), px(height as f32))) @@ -787,7 +785,7 @@ impl WaylandWindowStatePtr { height, serial, } => { - let mut size = if width == 0 || height == 0 { + let size = if width == 0 || height == 0 { None } else { Some(size(px(width as f32), px(height as f32))) @@ -933,7 +931,8 @@ impl WaylandWindowStatePtr { { let state = self.state.borrow(); if let Some(viewport) = &state.viewport { - viewport.set_destination(size.width.0 as i32, size.height.0 as i32); + viewport + .set_destination(f32::from(size.width) as i32, f32::from(size.height) as i32); } } } @@ -1108,7 +1107,7 @@ impl PlatformWindow for WaylandWindow { state.inset(), state.tiling, ) - .map(|v| v.0 as i32) + .map(|v| f32::from(v) as i32) .map_size(|v| if v <= 0 { 1 } else { v }); state.surface_state.set_geometry( @@ -1252,7 +1251,7 @@ impl PlatformWindow for WaylandWindow { } fn toggle_fullscreen(&self) { - let mut state = self.borrow(); + let state = self.borrow(); if let Some(toplevel) = state.surface_state.toplevel() { if !state.fullscreen { toplevel.set_fullscreen(None); @@ -1270,7 +1269,7 @@ impl PlatformWindow for WaylandWindow { self.0.callbacks.borrow_mut().request_frame = Some(callback); } - fn on_input(&self, callback: Box crate::DispatchEventResult>) { + fn on_input(&self, callback: Box gpui::DispatchEventResult>) { self.0.callbacks.borrow_mut().input = Some(callback); } @@ -1327,8 +1326,8 @@ impl PlatformWindow for WaylandWindow { toplevel.show_window_menu( &state.globals.seat, serial, - position.x.0 as i32, - position.y.0 as i32, + f32::from(position.x) as i32, + f32::from(position.y) as i32, ); } } @@ -1341,7 +1340,7 @@ impl PlatformWindow for WaylandWindow { } } - fn start_window_resize(&self, edge: crate::ResizeEdge) { + fn start_window_resize(&self, edge: gpui::ResizeEdge) { let state = self.borrow(); if let Some(toplevel) = state.surface_state.toplevel() { toplevel.resize( @@ -1408,8 +1407,8 @@ fn update_window(mut state: RefMut) { let opaque = !state.is_transparent(); state.renderer.update_transparency(!opaque); - let mut opaque_area = state.window_bounds.map(|v| v.0 as i32); - opaque_area.inset(state.inset().0 as i32); + let opaque_area = state.window_bounds.map(|v| f32::from(v) as i32); + opaque_area.inset(f32::from(state.inset()) as i32); let region = state .globals @@ -1454,7 +1453,11 @@ fn update_window(mut state: RefMut) { region.destroy(); } -impl WindowDecorations { +pub(crate) trait WindowDecorationsExt { + fn to_xdg(self) -> zxdg_toplevel_decoration_v1::Mode; +} + +impl WindowDecorationsExt for WindowDecorations { fn to_xdg(self) -> zxdg_toplevel_decoration_v1::Mode { match self { WindowDecorations::Client => zxdg_toplevel_decoration_v1::Mode::ClientSide, @@ -1463,7 +1466,11 @@ impl WindowDecorations { } } -impl ResizeEdge { +pub(crate) trait ResizeEdgeWaylandExt { + fn to_xdg(self) -> xdg_toplevel::ResizeEdge; +} + +impl ResizeEdgeWaylandExt for ResizeEdge { fn to_xdg(self) -> xdg_toplevel::ResizeEdge { match self { ResizeEdge::Top => xdg_toplevel::ResizeEdge::Top, diff --git a/crates/gpui/src/platform/linux/x11.rs b/crates/gpui_linux/src/linux/x11.rs similarity index 100% rename from crates/gpui/src/platform/linux/x11.rs rename to crates/gpui_linux/src/linux/x11.rs diff --git a/crates/gpui/src/platform/linux/x11/client.rs b/crates/gpui_linux/src/linux/x11/client.rs similarity index 96% rename from crates/gpui/src/platform/linux/x11/client.rs rename to crates/gpui_linux/src/linux/x11/client.rs index 08d756d3620e0ec63ba562646f78c2d0f059e78d..7766f23095fccf1a1c8c002314afdf012d3494ea 100644 --- a/crates/gpui/src/platform/linux/x11/client.rs +++ b/crates/gpui_linux/src/linux/x11/client.rs @@ -1,4 +1,3 @@ -use crate::{Capslock, ResultExt as _, TaskTiming, profiler, xcb_flush}; use anyhow::{Context as _, anyhow}; use ashpd::WindowIdentifier; use calloop::{ @@ -7,6 +6,7 @@ use calloop::{ }; use collections::HashMap; use core::str; +use gpui::{Capslock, TaskTiming, profiler}; use http_client::Url; use log::Level; use smallvec::SmallVec; @@ -45,26 +45,27 @@ use super::{ XimHandler, button_or_scroll_from_event_detail, check_reply, clipboard::{self, Clipboard}, get_reply, get_valuator_axis_index, handle_connection_error, modifiers_from_state, - pressed_button_from_mask, + pressed_button_from_mask, xcb_flush, }; -use crate::platform::{ - LinuxCommon, PlatformWindow, - linux::{ - DEFAULT_CURSOR_ICON_NAME, LinuxClient, get_xkb_compose_state, is_within_click_distance, - log_cursor_icon_warning, open_uri_internal, - platform::{DOUBLE_CLICK_INTERVAL, SCROLL_LINES}, - reveal_path_internal, - xdg_desktop_portal::{Event as XDPEvent, XDPEventSource}, - }, - wgpu::WgpuContext, +use crate::linux::{ + DEFAULT_CURSOR_ICON_NAME, LinuxClient, ResultExt as _, capslock_from_xkb, + cursor_style_to_icon_names, get_xkb_compose_state, is_within_click_distance, + keystroke_from_xkb, keystroke_underlying_dead_key, log_cursor_icon_warning, modifiers_from_xkb, + open_uri_internal, + platform::{DOUBLE_CLICK_INTERVAL, SCROLL_LINES}, + reveal_path_internal, + xdg_desktop_portal::{Event as XDPEvent, XDPEventSource}, }; -use crate::{ +use crate::linux::{LinuxCommon, LinuxKeyboardLayout, X11Window, modifiers_from_xinput_info}; + +use gpui::{ AnyWindowHandle, Bounds, ClipboardItem, CursorStyle, DisplayId, FileDropEvent, Keystroke, - LinuxKeyboardLayout, Modifiers, ModifiersChangedEvent, MouseButton, Pixels, Platform, - PlatformDisplay, PlatformInput, PlatformKeyboardLayout, Point, RequestFrameOptions, - ScrollDelta, Size, TouchPhase, WindowParams, X11Window, modifiers_from_xinput_info, point, px, + Modifiers, ModifiersChangedEvent, MouseButton, Pixels, PlatformDisplay, PlatformInput, + PlatformKeyboardLayout, PlatformWindow, Point, RequestFrameOptions, ScrollDelta, Size, + TouchPhase, WindowParams, point, px, }; +use gpui_wgpu::WgpuContext; /// Value for DeviceId parameters which selects all devices. pub(crate) const XINPUT_ALL_DEVICES: xinput::DeviceId = 0; @@ -684,7 +685,7 @@ impl X11Client { return; } - let Some((mut ximc, mut xim_handler)) = state.take_xim() else { + let Some((mut ximc, xim_handler)) = state.take_xim() else { return; }; let mut ic_attributes = ximc @@ -815,7 +816,7 @@ impl X11Client { state.xcb_connection.query_pointer(event.window), ) { state.xdnd_state.position = - Point::new(Pixels(pos.win_x as f32), Pixels(pos.win_y as f32)); + Point::new(px(pos.win_x as f32), px(pos.win_y as f32)); } if !state.xdnd_state.retrieved { check_reply( @@ -857,7 +858,7 @@ impl X11Client { } Event::SelectionNotify(event) => { let window = self.get_window(event.requestor)?; - let mut state = self.0.borrow_mut(); + let state = self.0.borrow_mut(); let reply = get_reply( || "Failed to get XDND_DATA", state.xcb_connection.get_property( @@ -881,7 +882,7 @@ impl X11Client { .collect(); let input = PlatformInput::FileDrop(FileDropEvent::Entered { position: state.xdnd_state.position, - paths: crate::ExternalPaths(paths), + paths: gpui::ExternalPaths(paths), }); drop(state); window.handle_input(input); @@ -969,8 +970,8 @@ impl X11Client { event.latched_group as u32, event.locked_group.into(), ); - let modifiers = Modifiers::from_xkb(&state.xkb); - let capslock = Capslock::from_xkb(&state.xkb); + let modifiers = modifiers_from_xkb(&state.xkb); + let capslock = capslock_from_xkb(&state.xkb); if state.last_modifiers_changed_event == modifiers && state.last_capslock_changed_event == capslock { @@ -1011,7 +1012,7 @@ impl X11Client { let keystroke = { let code = event.detail.into(); - let mut keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code); + let mut keystroke = keystroke_from_xkb(&state.xkb, modifiers, code); let keysym = state.xkb.key_get_one_sym(code); if keysym.is_modifier_key() { @@ -1035,7 +1036,7 @@ impl X11Client { keystroke.key_char = None; state.pre_edit_text = compose_state .utf8() - .or(crate::Keystroke::underlying_dead_key(keysym)); + .or(keystroke_underlying_dead_key(keysym)); let pre_edit = state.pre_edit_text.clone().unwrap_or(String::default()); drop(state); @@ -1048,7 +1049,7 @@ impl X11Client { if let Some(pre_edit) = pre_edit { window.handle_ime_commit(pre_edit); } - if let Some(current_key) = Keystroke::underlying_dead_key(keysym) { + if let Some(current_key) = keystroke_underlying_dead_key(keysym) { window.handle_ime_preedit(current_key); } state = self.0.borrow_mut(); @@ -1061,7 +1062,7 @@ impl X11Client { keystroke }; drop(state); - window.handle_input(PlatformInput::KeyDown(crate::KeyDownEvent { + window.handle_input(PlatformInput::KeyDown(gpui::KeyDownEvent { keystroke, is_held: false, prefer_character_input: false, @@ -1081,7 +1082,7 @@ impl X11Client { let keystroke = { let code = event.detail.into(); - let keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code); + let keystroke = keystroke_from_xkb(&state.xkb, modifiers, code); let keysym = state.xkb.key_get_one_sym(code); if keysym.is_modifier_key() { @@ -1094,7 +1095,7 @@ impl X11Client { keystroke }; drop(state); - window.handle_input(PlatformInput::KeyUp(crate::KeyUpEvent { keystroke })); + window.handle_input(PlatformInput::KeyUp(gpui::KeyUpEvent { keystroke })); } Event::XinputButtonPress(event) => { let window = self.get_window(event.event)?; @@ -1141,7 +1142,7 @@ impl X11Client { let current_count = state.current_count; drop(state); - window.handle_input(PlatformInput::MouseDown(crate::MouseDownEvent { + window.handle_input(PlatformInput::MouseDown(gpui::MouseDownEvent { button, position, modifiers, @@ -1187,7 +1188,7 @@ impl X11Client { Some(ButtonOrScroll::Button(button)) => { let click_count = state.current_count; drop(state); - window.handle_input(PlatformInput::MouseUp(crate::MouseUpEvent { + window.handle_input(PlatformInput::MouseUp(gpui::MouseUpEvent { button, position, modifiers, @@ -1238,7 +1239,7 @@ impl X11Client { drop(state); if event.valuator_mask[0] & 3 != 0 { - window.handle_input(PlatformInput::MouseMove(crate::MouseMoveEvent { + window.handle_input(PlatformInput::MouseMove(gpui::MouseMoveEvent { position, pressed_button, modifiers, @@ -1246,7 +1247,7 @@ impl X11Client { } state = self.0.borrow_mut(); - if let Some(mut pointer) = state.pointer_device_states.get_mut(&event.sourceid) { + if let Some(pointer) = state.pointer_device_states.get_mut(&event.sourceid) { let scroll_delta = get_scroll_delta_and_update_state(pointer, &event); drop(state); if let Some(scroll_delta) = scroll_delta { @@ -1280,7 +1281,7 @@ impl X11Client { drop(state); let window = self.get_window(event.event)?; - window.handle_input(PlatformInput::MouseExited(crate::MouseExitEvent { + window.handle_input(PlatformInput::MouseExited(gpui::MouseExitEvent { pressed_button, position, modifiers, @@ -1305,7 +1306,7 @@ impl X11Client { } Event::XinputDeviceChanged(event) => { let mut state = self.0.borrow_mut(); - if let Some(mut pointer) = state.pointer_device_states.get_mut(&event.sourceid) { + if let Some(pointer) = state.pointer_device_states.get_mut(&event.sourceid) { reset_pointer_device_scroll_positions(pointer); } } @@ -1333,7 +1334,7 @@ impl X11Client { match event { Event::KeyPress(event) | Event::KeyRelease(event) => { let mut state = self.0.borrow_mut(); - state.pre_key_char_down = Some(Keystroke::from_xkb( + state.pre_key_char_down = Some(keystroke_from_xkb( &state.xkb, state.modifiers, event.detail.into(), @@ -1379,7 +1380,7 @@ impl X11Client { }; let mut state = self.0.borrow_mut(); - let (mut ximc, mut xim_handler) = state.take_xim()?; + let (mut ximc, xim_handler) = state.take_xim()?; state.composing = !text.is_empty(); drop(state); window.handle_ime_preedit(text); @@ -1473,7 +1474,12 @@ impl LinuxClient for X11Client { let state = self.0.borrow(); Some(Rc::new( - X11Display::new(&state.xcb_connection, state.scale_factor, id.0 as usize).ok()?, + X11Display::new( + &state.xcb_connection, + state.scale_factor, + u32::from(id) as usize, + ) + .ok()?, )) } @@ -1485,11 +1491,9 @@ impl LinuxClient for X11Client { #[cfg(feature = "screen-capture")] fn screen_capture_sources( &self, - ) -> futures::channel::oneshot::Receiver>>> + ) -> futures::channel::oneshot::Receiver>>> { - crate::platform::scap_screen_capture::scap_screen_sources( - &self.0.borrow().common.foreground_executor, - ) + gpui::scap_screen_capture::scap_screen_sources(&self.0.borrow().common.foreground_executor) } fn open_window( @@ -1589,15 +1593,23 @@ impl LinuxClient for X11Client { fn open_uri(&self, uri: &str) { #[cfg(any(feature = "wayland", feature = "x11"))] - open_uri_internal(self.background_executor(), uri, None); + open_uri_internal( + self.with_common(|c| c.background_executor.clone()), + uri, + None, + ); } fn reveal_path(&self, path: PathBuf) { #[cfg(any(feature = "x11", feature = "wayland"))] - reveal_path_internal(self.background_executor(), path, None); + reveal_path_internal( + self.with_common(|c| c.background_executor.clone()), + path, + None, + ); } - fn write_to_primary(&self, item: crate::ClipboardItem) { + fn write_to_primary(&self, item: gpui::ClipboardItem) { let state = self.0.borrow_mut(); state .clipboard @@ -1610,7 +1622,7 @@ impl LinuxClient for X11Client { .log_with_level(log::Level::Debug); } - fn write_to_clipboard(&self, item: crate::ClipboardItem) { + fn write_to_clipboard(&self, item: gpui::ClipboardItem) { let mut state = self.0.borrow_mut(); state .clipboard @@ -1624,7 +1636,7 @@ impl LinuxClient for X11Client { state.clipboard_item.replace(item); } - fn read_from_primary(&self) -> Option { + fn read_from_primary(&self) -> Option { let state = self.0.borrow_mut(); state .clipboard @@ -1633,7 +1645,7 @@ impl LinuxClient for X11Client { .log_with_level(log::Level::Debug) } - fn read_from_clipboard(&self) -> Option { + fn read_from_clipboard(&self) -> Option { let state = self.0.borrow_mut(); // if the last copy was from this app, return our cached item // which has metadata attached. @@ -1876,7 +1888,7 @@ impl X11ClientState { return *cursor; } - let mut result; + let result; match style { CursorStyle::None => match create_invisible_cursor(&self.xcb_connection) { Ok(loaded_cursor) => result = Ok(loaded_cursor), @@ -1884,7 +1896,7 @@ impl X11ClientState { }, _ => 'outer: { let mut errors = String::new(); - let cursor_icon_names = style.to_icon_names(); + let cursor_icon_names = cursor_style_to_icon_names(style); for cursor_icon_name in cursor_icon_names { match self .cursor_handle @@ -2262,7 +2274,7 @@ fn make_scroll_wheel_event( position: Point, scroll_delta: Point, modifiers: Modifiers, -) -> crate::ScrollWheelEvent { +) -> gpui::ScrollWheelEvent { // When shift is held down, vertical scrolling turns into horizontal scrolling. let delta = if modifiers.shift { Point { @@ -2272,7 +2284,7 @@ fn make_scroll_wheel_event( } else { scroll_delta }; - crate::ScrollWheelEvent { + gpui::ScrollWheelEvent { position, delta: ScrollDelta::Lines(delta), modifiers, @@ -2282,7 +2294,7 @@ fn make_scroll_wheel_event( fn create_invisible_cursor( connection: &XCBConnection, -) -> anyhow::Result { +) -> anyhow::Result { let empty_pixmap = connection.generate_id()?; let root = connection.setup().roots[0].root; connection.create_pixmap(1, empty_pixmap, root, 1, 1)?; diff --git a/crates/gpui/src/platform/linux/x11/clipboard.rs b/crates/gpui_linux/src/linux/x11/clipboard.rs similarity index 99% rename from crates/gpui/src/platform/linux/x11/clipboard.rs rename to crates/gpui_linux/src/linux/x11/clipboard.rs index 3be5008505446e8ca6c6fd93b559fec4779ae85c..d2ea58b3f8c2acd0b6fbeba44eaf8b5a2e57531f 100644 --- a/crates/gpui/src/platform/linux/x11/clipboard.rs +++ b/crates/gpui_linux/src/linux/x11/clipboard.rs @@ -47,7 +47,7 @@ use x11rb::{ wrapper::ConnectionExt as _, }; -use crate::{ClipboardItem, Image, ImageFormat, hash}; +use gpui::{ClipboardItem, Image, ImageFormat, hash}; type Result = std::result::Result; diff --git a/crates/gpui/src/platform/linux/x11/display.rs b/crates/gpui_linux/src/linux/x11/display.rs similarity index 91% rename from crates/gpui/src/platform/linux/x11/display.rs rename to crates/gpui_linux/src/linux/x11/display.rs index ea2f8bb189d98749e9f1c2b304dafb3ae5095e78..900c55e759ac86474059f33d80b485fb3323ed43 100644 --- a/crates/gpui/src/platform/linux/x11/display.rs +++ b/crates/gpui_linux/src/linux/x11/display.rs @@ -2,7 +2,7 @@ use anyhow::Context as _; use uuid::Uuid; use x11rb::{connection::Connection as _, xcb_ffi::XCBConnection}; -use crate::{Bounds, DisplayId, Pixels, PlatformDisplay, Size, px}; +use gpui::{Bounds, DisplayId, Pixels, PlatformDisplay, Size, px}; #[derive(Debug)] pub(crate) struct X11Display { @@ -38,7 +38,7 @@ impl X11Display { impl PlatformDisplay for X11Display { fn id(&self) -> DisplayId { - DisplayId(self.x_screen_index as u32) + DisplayId::new(self.x_screen_index as u32) } fn uuid(&self) -> anyhow::Result { diff --git a/crates/gpui/src/platform/linux/x11/event.rs b/crates/gpui_linux/src/linux/x11/event.rs similarity index 98% rename from crates/gpui/src/platform/linux/x11/event.rs rename to crates/gpui_linux/src/linux/x11/event.rs index 17bcc908d3a6bdd48f16a8f5db69f08290b9444f..3fb916425b78fc995ce84d42342917d87a51b7af 100644 --- a/crates/gpui/src/platform/linux/x11/event.rs +++ b/crates/gpui_linux/src/linux/x11/event.rs @@ -3,7 +3,7 @@ use x11rb::protocol::{ xproto::{self, ModMask}, }; -use crate::{Modifiers, MouseButton, NavigationDirection}; +use gpui::{Modifiers, MouseButton, NavigationDirection}; pub(crate) enum ButtonOrScroll { Button(MouseButton), diff --git a/crates/gpui/src/platform/linux/x11/window.rs b/crates/gpui_linux/src/linux/x11/window.rs similarity index 97% rename from crates/gpui/src/platform/linux/x11/window.rs rename to crates/gpui_linux/src/linux/x11/window.rs index acfdcb068d42e6b342a8cde69e54421b972e3a4a..cc48a86b0c33890d58880360848fa6336cd95a75 100644 --- a/crates/gpui/src/platform/linux/x11/window.rs +++ b/crates/gpui_linux/src/linux/x11/window.rs @@ -1,14 +1,15 @@ use anyhow::{Context as _, anyhow}; use x11rb::connection::RequestConnection; -use crate::platform::wgpu::{WgpuContext, WgpuRenderer, WgpuSurfaceConfig}; -use crate::{ +use crate::linux::X11ClientStatePtr; +use gpui::{ AnyWindowHandle, Bounds, Decorations, DevicePixels, ForegroundExecutor, GpuSpecs, Modifiers, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, PromptButton, PromptLevel, RequestFrameOptions, ResizeEdge, ScaledPixels, Scene, Size, Tiling, WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControlArea, - WindowDecorations, WindowKind, WindowParams, X11ClientStatePtr, px, + WindowDecorations, WindowKind, WindowParams, px, }; +use gpui_wgpu::{WgpuContext, WgpuRenderer, WgpuSurfaceConfig}; use collections::FxHashSet; use raw_window_handle as rwh; @@ -95,18 +96,16 @@ fn query_render_extent( }) } -impl ResizeEdge { - fn to_moveresize(self) -> u32 { - match self { - ResizeEdge::TopLeft => 0, - ResizeEdge::Top => 1, - ResizeEdge::TopRight => 2, - ResizeEdge::Right => 3, - ResizeEdge::BottomRight => 4, - ResizeEdge::Bottom => 5, - ResizeEdge::BottomLeft => 6, - ResizeEdge::Left => 7, - } +fn resize_edge_to_moveresize(edge: ResizeEdge) -> u32 { + match edge { + ResizeEdge::TopLeft => 0, + ResizeEdge::Top => 1, + ResizeEdge::TopRight => 2, + ResizeEdge::Right => 3, + ResizeEdge::BottomRight => 4, + ResizeEdge::Bottom => 5, + ResizeEdge::BottomLeft => 6, + ResizeEdge::Left => 7, } } @@ -242,7 +241,7 @@ unsafe impl Sync for RawWindow {} #[derive(Default)] pub struct Callbacks { request_frame: Option>, - input: Option crate::DispatchEventResult>>, + input: Option gpui::DispatchEventResult>>, active_status_change: Option>, hovered_status_change: Option>, resize: Option, f32)>>, @@ -405,7 +404,7 @@ impl X11WindowState { ) -> anyhow::Result { let x_screen_index = params .display_id - .map_or(x_main_screen_index, |did| did.0 as usize); + .map_or(x_main_screen_index, |did| u32::from(did) as usize); let visual_set = find_visuals(xcb, x_screen_index); @@ -500,7 +499,7 @@ impl X11WindowState { if let Some(size) = params.window_min_size { let mut size_hints = WmSizeHints::new(); - let min_size = (size.width.0 as i32, size.height.0 as i32); + let min_size = (f32::from(size.width) as i32, f32::from(size.height) as i32); size_hints.min_size = Some(min_size); check_reply( || { @@ -874,8 +873,8 @@ impl X11Window { self.0.xcb.translate_coordinates( self.0.x_window, state.x_root_window, - (position.x.0 * state.scale_factor) as i16, - (position.y.0 * state.scale_factor) as i16, + (f32::from(position.x) * state.scale_factor) as i16, + (f32::from(position.y) * state.scale_factor) as i16, ), ) } @@ -932,7 +931,7 @@ impl X11WindowStatePtr { } pub fn property_notify(&self, event: xproto::PropertyNotifyEvent) -> anyhow::Result<()> { - let mut state = self.state.borrow_mut(); + let state = self.state.borrow_mut(); if event.atom == state.atoms._NET_WM_STATE { self.set_wm_properties(state)?; } else if event.atom == state.atoms._GTK_EDGE_CONSTRAINTS { @@ -1247,10 +1246,10 @@ impl PlatformWindow for X11Window { let [left, right, top, bottom] = state.last_insets; let [left, right, top, bottom] = [ - Pixels((left as f32) / state.scale_factor), - Pixels((right as f32) / state.scale_factor), - Pixels((top as f32) / state.scale_factor), - Pixels((bottom as f32) / state.scale_factor), + px((left as f32) / state.scale_factor), + px((right as f32) / state.scale_factor), + px((top as f32) / state.scale_factor), + px((bottom as f32) / state.scale_factor), ]; bounds.origin.x += left; @@ -1327,7 +1326,7 @@ impl PlatformWindow for X11Window { .unwrap_or_default() } - fn capslock(&self) -> crate::Capslock { + fn capslock(&self) -> gpui::Capslock { self.0 .state .borrow() @@ -1522,7 +1521,7 @@ impl PlatformWindow for X11Window { self.0.callbacks.borrow_mut().request_frame = Some(callback); } - fn on_input(&self, callback: Box crate::DispatchEventResult>) { + fn on_input(&self, callback: Box gpui::DispatchEventResult>) { self.0.callbacks.borrow_mut().input = Some(callback); } @@ -1609,10 +1608,11 @@ impl PlatformWindow for X11Window { } fn start_window_resize(&self, edge: ResizeEdge) { - self.send_moveresize(edge.to_moveresize()).log_err(); + self.send_moveresize(resize_edge_to_moveresize(edge)) + .log_err(); } - fn window_decorations(&self) -> crate::Decorations { + fn window_decorations(&self) -> gpui::Decorations { let state = self.0.state.borrow(); // Client window decorations require compositor support @@ -1644,7 +1644,7 @@ impl PlatformWindow for X11Window { fn set_client_inset(&self, inset: Pixels) { let mut state = self.0.state.borrow_mut(); - let dp = (inset.0 * state.scale_factor) as u32; + let dp = (f32::from(inset) * state.scale_factor) as u32; let insets = if state.fullscreen { [0, 0, 0, 0] @@ -1688,16 +1688,16 @@ impl PlatformWindow for X11Window { } } - fn request_decorations(&self, mut decorations: crate::WindowDecorations) { + fn request_decorations(&self, mut decorations: gpui::WindowDecorations) { let mut state = self.0.state.borrow_mut(); - if matches!(decorations, crate::WindowDecorations::Client) + if matches!(decorations, gpui::WindowDecorations::Client) && !state.client_side_decorations_supported { log::info!( "x11: no compositor present, falling back to server-side window decorations" ); - decorations = crate::WindowDecorations::Server; + decorations = gpui::WindowDecorations::Server; } // https://github.com/rust-windowing/winit/blob/master/src/platform_impl/linux/x11/util/hint.rs#L53-L87 @@ -1745,7 +1745,7 @@ impl PlatformWindow for X11Window { } fn update_ime_position(&self, bounds: Bounds) { - let mut state = self.0.state.borrow_mut(); + let state = self.0.state.borrow(); let client = state.client.clone(); drop(state); client.update_ime_position(bounds); diff --git a/crates/gpui/src/platform/linux/x11/xim_handler.rs b/crates/gpui_linux/src/linux/x11/xim_handler.rs similarity index 100% rename from crates/gpui/src/platform/linux/x11/xim_handler.rs rename to crates/gpui_linux/src/linux/x11/xim_handler.rs diff --git a/crates/gpui/src/platform/linux/xdg_desktop_portal.rs b/crates/gpui_linux/src/linux/xdg_desktop_portal.rs similarity index 84% rename from crates/gpui/src/platform/linux/xdg_desktop_portal.rs rename to crates/gpui_linux/src/linux/xdg_desktop_portal.rs index 722947a299e7b25605bb198341732d33f8208ab4..911ac319db2b2a803a5e5e715f7a04f8cb128d7a 100644 --- a/crates/gpui/src/platform/linux/xdg_desktop_portal.rs +++ b/crates/gpui_linux/src/linux/xdg_desktop_portal.rs @@ -7,7 +7,7 @@ use calloop::channel::Channel; use calloop::{EventSource, Poll, PostAction, Readiness, Token, TokenFactory}; use smol::stream::StreamExt; -use crate::{BackgroundExecutor, WindowAppearance}; +use gpui::{BackgroundExecutor, WindowAppearance}; pub enum Event { WindowAppearance(WindowAppearance), @@ -32,9 +32,9 @@ impl XDPEventSource { let settings = Settings::new().await?; if let Ok(initial_appearance) = settings.color_scheme().await { - sender.send(Event::WindowAppearance(WindowAppearance::from_native( - initial_appearance, - )))?; + sender.send(Event::WindowAppearance( + window_appearance_from_color_scheme(initial_appearance), + ))?; } if let Ok(initial_theme) = settings .read::("org.gnome.desktop.interface", "cursor-theme") @@ -91,9 +91,9 @@ impl XDPEventSource { let mut appearance_changed = settings.receive_color_scheme_changed().await?; while let Some(scheme) = appearance_changed.next().await { - sender.send(Event::WindowAppearance(WindowAppearance::from_native( - scheme, - )))?; + sender.send(Event::WindowAppearance( + window_appearance_from_color_scheme(scheme), + ))?; } anyhow::Ok(()) @@ -155,17 +155,10 @@ impl EventSource for XDPEventSource { } } -impl WindowAppearance { - fn from_native(cs: ColorScheme) -> WindowAppearance { - match cs { - ColorScheme::PreferDark => WindowAppearance::Dark, - ColorScheme::PreferLight => WindowAppearance::Light, - ColorScheme::NoPreference => WindowAppearance::Light, - } - } - - #[cfg_attr(any(target_os = "linux", target_os = "freebsd"), allow(dead_code))] - fn set_native(&mut self, cs: ColorScheme) { - *self = Self::from_native(cs); +fn window_appearance_from_color_scheme(cs: ColorScheme) -> WindowAppearance { + match cs { + ColorScheme::PreferDark => WindowAppearance::Dark, + ColorScheme::PreferLight => WindowAppearance::Light, + ColorScheme::NoPreference => WindowAppearance::Light, } } diff --git a/crates/gpui_macos/Cargo.toml b/crates/gpui_macos/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..4aedb1f4f1bed02e22f0dc6a881d60cc39ddd3a1 --- /dev/null +++ b/crates/gpui_macos/Cargo.toml @@ -0,0 +1,62 @@ +[package] +name = "gpui_macos" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "Apache-2.0" + +[lints] +workspace = true + +[lib] +path = "src/gpui_macos.rs" + +[features] +default = ["gpui/default"] +test-support = ["gpui/test-support"] +runtime_shaders = [] +font-kit = ["dep:font-kit"] +screen-capture = ["gpui/screen-capture"] + +[dependencies] +gpui.workspace = true + +[target.'cfg(target_os = "macos")'.dependencies] +anyhow.workspace = true +async-task = "4.7" +block = "0.1" +cocoa.workspace = true +collections.workspace = true +core-foundation.workspace = true +core-foundation-sys.workspace = true +core-graphics = "0.24" +core-text = "21" +core-video.workspace = true +ctor.workspace = true +derive_more.workspace = true +etagere = "0.2" +# WARNING: If you change this, you must also publish a new version of zed-font-kit to crates.io +font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "110523127440aefb11ce0cf280ae7c5071337ec5", package = "zed-font-kit", version = "0.14.1-zed", optional = true } +foreign-types = "0.5" +futures.workspace = true +image.workspace = true +itertools.workspace = true +libc.workspace = true +log.workspace = true +mach2.workspace = true +media.workspace = true +metal.workspace = true +objc.workspace = true +parking_lot.workspace = true +pathfinder_geometry = "0.5" +raw-window-handle = "0.6" +semver.workspace = true +smallvec.workspace = true +strum.workspace = true +util.workspace = true +uuid.workspace = true + +[target.'cfg(target_os = "macos")'.build-dependencies] +bindgen = "0.71" +cbindgen = { version = "0.28.0", default-features = false } +gpui.workspace = true \ No newline at end of file diff --git a/crates/gpui_macos/LICENSE-APACHE b/crates/gpui_macos/LICENSE-APACHE new file mode 120000 index 0000000000000000000000000000000000000000..1cd601d0a3affae83854be02a0afdec3b7a9ec4d --- /dev/null +++ b/crates/gpui_macos/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/gpui_macos/build.rs b/crates/gpui_macos/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..32dfc571d257495c9c0a8cae54bc9fb567b51489 --- /dev/null +++ b/crates/gpui_macos/build.rs @@ -0,0 +1,209 @@ +#![allow(clippy::disallowed_methods, reason = "build scripts are exempt")] + +fn main() { + #[cfg(target_os = "macos")] + macos_build::run(); +} + +#[cfg(target_os = "macos")] +mod macos_build { + use std::{ + env, + path::{Path, PathBuf}, + }; + + use cbindgen::Config; + + pub fn run() { + generate_dispatch_bindings(); + + let header_path = generate_shader_bindings(); + + #[cfg(feature = "runtime_shaders")] + emit_stitched_shaders(&header_path); + #[cfg(not(feature = "runtime_shaders"))] + compile_metal_shaders(&header_path); + } + + fn generate_dispatch_bindings() { + println!("cargo:rustc-link-lib=framework=System"); + + let bindings = bindgen::Builder::default() + .header("src/dispatch.h") + .allowlist_var("_dispatch_main_q") + .allowlist_var("_dispatch_source_type_data_add") + .allowlist_var("DISPATCH_QUEUE_PRIORITY_HIGH") + .allowlist_var("DISPATCH_QUEUE_PRIORITY_DEFAULT") + .allowlist_var("DISPATCH_QUEUE_PRIORITY_LOW") + .allowlist_var("DISPATCH_TIME_NOW") + .allowlist_function("dispatch_get_global_queue") + .allowlist_function("dispatch_async_f") + .allowlist_function("dispatch_after_f") + .allowlist_function("dispatch_time") + .allowlist_function("dispatch_source_merge_data") + .allowlist_function("dispatch_source_create") + .allowlist_function("dispatch_source_set_event_handler_f") + .allowlist_function("dispatch_resume") + .allowlist_function("dispatch_suspend") + .allowlist_function("dispatch_source_cancel") + .allowlist_function("dispatch_set_context") + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .layout_tests(false) + .generate() + .expect("unable to generate bindings"); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("dispatch_sys.rs")) + .expect("couldn't write dispatch bindings"); + } + + fn generate_shader_bindings() -> PathBuf { + let output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("scene.h"); + + let gpui_dir = find_gpui_crate_dir(); + + let mut config = Config { + include_guard: Some("SCENE_H".into()), + language: cbindgen::Language::C, + no_includes: true, + ..Default::default() + }; + config.export.include.extend([ + "Bounds".into(), + "Corners".into(), + "Edges".into(), + "Size".into(), + "Pixels".into(), + "PointF".into(), + "Hsla".into(), + "ContentMask".into(), + "Uniforms".into(), + "AtlasTile".into(), + "PathRasterizationInputIndex".into(), + "PathVertex_ScaledPixels".into(), + "PathRasterizationVertex".into(), + "ShadowInputIndex".into(), + "Shadow".into(), + "QuadInputIndex".into(), + "Underline".into(), + "UnderlineInputIndex".into(), + "Quad".into(), + "BorderStyle".into(), + "SpriteInputIndex".into(), + "MonochromeSprite".into(), + "PolychromeSprite".into(), + "PathSprite".into(), + "SurfaceInputIndex".into(), + "SurfaceBounds".into(), + "TransformationMatrix".into(), + ]); + config.no_includes = true; + config.enumeration.prefix_with_name = true; + + let mut builder = cbindgen::Builder::new(); + + let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + + // Source files from gpui that define types used in shaders + let gpui_src_paths = [ + gpui_dir.join("src/scene.rs"), + gpui_dir.join("src/geometry.rs"), + gpui_dir.join("src/color.rs"), + gpui_dir.join("src/window.rs"), + gpui_dir.join("src/platform.rs"), + ]; + + // Source files from this crate + let local_src_paths = [crate_dir.join("src/metal_renderer.rs")]; + + for src_path in gpui_src_paths.iter().chain(local_src_paths.iter()) { + println!("cargo:rerun-if-changed={}", src_path.display()); + builder = builder.with_src(src_path); + } + + builder + .with_config(config) + .generate() + .expect("Unable to generate bindings") + .write_to_file(&output_path); + + output_path + } + + /// Locate the gpui crate directory relative to this crate. + fn find_gpui_crate_dir() -> PathBuf { + gpui::GPUI_MANIFEST_DIR.into() + } + + /// To enable runtime compilation, we need to "stitch" the shaders file with the generated header + /// so that it is self-contained. + #[cfg(feature = "runtime_shaders")] + fn emit_stitched_shaders(header_path: &Path) { + fn stitch_header(header: &Path, shader_path: &Path) -> std::io::Result { + let header_contents = std::fs::read_to_string(header)?; + let shader_contents = std::fs::read_to_string(shader_path)?; + let stitched_contents = format!("{header_contents}\n{shader_contents}"); + let out_path = + PathBuf::from(env::var("OUT_DIR").unwrap()).join("stitched_shaders.metal"); + std::fs::write(&out_path, stitched_contents)?; + Ok(out_path) + } + let shader_source_path = "./src/shaders.metal"; + let shader_path = PathBuf::from(shader_source_path); + stitch_header(header_path, &shader_path).unwrap(); + println!("cargo:rerun-if-changed={}", &shader_source_path); + } + + #[cfg(not(feature = "runtime_shaders"))] + fn compile_metal_shaders(header_path: &Path) { + use std::process::{self, Command}; + let shader_path = "./src/shaders.metal"; + let air_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.air"); + let metallib_output_path = + PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.metallib"); + println!("cargo:rerun-if-changed={}", shader_path); + + let output = Command::new("xcrun") + .args([ + "-sdk", + "macosx", + "metal", + "-gline-tables-only", + "-mmacosx-version-min=10.15.7", + "-MO", + "-c", + shader_path, + "-include", + (header_path.to_str().unwrap()), + "-o", + ]) + .arg(&air_output_path) + .output() + .unwrap(); + + if !output.status.success() { + println!( + "cargo::error=metal shader compilation failed:\n{}", + String::from_utf8_lossy(&output.stderr) + ); + process::exit(1); + } + + let output = Command::new("xcrun") + .args(["-sdk", "macosx", "metallib"]) + .arg(air_output_path) + .arg("-o") + .arg(metallib_output_path) + .output() + .unwrap(); + + if !output.status.success() { + println!( + "cargo::error=metallib compilation failed:\n{}", + String::from_utf8_lossy(&output.stderr) + ); + process::exit(1); + } + } +} diff --git a/crates/gpui/src/platform/mac/dispatch.h b/crates/gpui_macos/src/dispatch.h similarity index 100% rename from crates/gpui/src/platform/mac/dispatch.h rename to crates/gpui_macos/src/dispatch.h diff --git a/crates/gpui/src/platform/mac/dispatcher.rs b/crates/gpui_macos/src/dispatcher.rs similarity index 99% rename from crates/gpui/src/platform/mac/dispatcher.rs rename to crates/gpui_macos/src/dispatcher.rs index 4d3aa6effaf1626d6fa50eff79a0a72b57cd5f7d..755016e44be84f585631fbf311ef499adfc69367 100644 --- a/crates/gpui/src/platform/mac/dispatcher.rs +++ b/crates/gpui_macos/src/dispatcher.rs @@ -2,7 +2,7 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] -use crate::{ +use gpui::{ GLOBAL_THREAD_TIMINGS, PlatformDispatcher, Priority, RunnableMeta, RunnableVariant, THREAD_TIMINGS, TaskTiming, ThreadTaskTimings, }; diff --git a/crates/gpui/src/platform/mac/display.rs b/crates/gpui_macos/src/display.rs similarity index 97% rename from crates/gpui/src/platform/mac/display.rs rename to crates/gpui_macos/src/display.rs index 94791620e8a394f67a38c257c95c575398cee0b7..20ffa6fa2fc3ff09ce2b38a22b03a973f0e6c635 100644 --- a/crates/gpui/src/platform/mac/display.rs +++ b/crates/gpui_macos/src/display.rs @@ -1,5 +1,4 @@ -use super::ns_string; -use crate::{Bounds, DisplayId, Pixels, PlatformDisplay, point, px, size}; +use crate::ns_string; use anyhow::Result; use cocoa::{ appkit::NSScreen, @@ -8,6 +7,7 @@ use cocoa::{ }; use core_foundation::uuid::{CFUUIDGetUUIDBytes, CFUUIDRef}; use core_graphics::display::{CGDirectDisplayID, CGDisplayBounds, CGGetActiveDisplayList}; +use gpui::{Bounds, DisplayId, Pixels, PlatformDisplay, point, px, size}; use objc::{msg_send, sel, sel_impl}; use uuid::Uuid; @@ -72,7 +72,7 @@ unsafe extern "C" { impl PlatformDisplay for MacDisplay { fn id(&self) -> DisplayId { - DisplayId(self.0) + DisplayId::new(self.0) } fn uuid(&self) -> Result { diff --git a/crates/gpui/src/platform/mac/display_link.rs b/crates/gpui_macos/src/display_link.rs similarity index 99% rename from crates/gpui/src/platform/mac/display_link.rs rename to crates/gpui_macos/src/display_link.rs index ce39b4141f70198d5f3862aa244384461d1cca33..b086cc1b12182db661e5fa1cb82b671c7fd5b8bc 100644 --- a/crates/gpui/src/platform/mac/display_link.rs +++ b/crates/gpui_macos/src/display_link.rs @@ -1,6 +1,6 @@ use crate::{ dispatch_get_main_queue, - dispatch_sys::{ + dispatcher::dispatch_sys::{ _dispatch_source_type_data_add, dispatch_resume, dispatch_set_context, dispatch_source_cancel, dispatch_source_create, dispatch_source_merge_data, dispatch_source_set_event_handler_f, dispatch_source_t, dispatch_suspend, diff --git a/crates/gpui/src/platform/mac/events.rs b/crates/gpui_macos/src/events.rs similarity index 63% rename from crates/gpui/src/platform/mac/events.rs rename to crates/gpui_macos/src/events.rs index 7a12e8d3d7ccb2e8a2f7b32b81c24a29f650e6e2..5970488a17fbf9395f4ba29f5b98a135f6d55f7f 100644 --- a/crates/gpui/src/platform/mac/events.rs +++ b/crates/gpui_macos/src/events.rs @@ -1,13 +1,13 @@ -use crate::{ +use gpui::{ Capslock, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseExitEvent, MouseMoveEvent, MousePressureEvent, MouseUpEvent, NavigationDirection, Pixels, PlatformInput, PressureStage, ScrollDelta, ScrollWheelEvent, - TouchPhase, - platform::mac::{ - LMGetKbdType, NSStringExt, TISCopyCurrentKeyboardLayoutInputSource, - TISGetInputSourceProperty, UCKeyTranslate, kTISPropertyUnicodeKeyLayoutData, - }, - point, px, + TouchPhase, point, px, +}; + +use crate::{ + LMGetKbdType, NSStringExt, TISCopyCurrentKeyboardLayoutInputSource, TISGetInputSourceProperty, + UCKeyTranslate, kTISPropertyUnicodeKeyLayoutData, }; use cocoa::{ appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType}, @@ -101,217 +101,215 @@ unsafe fn read_modifiers(native_event: id) -> Modifiers { } } -impl PlatformInput { - pub(crate) unsafe fn from_native( - native_event: id, - window_height: Option, - ) -> Option { - unsafe { - let event_type = native_event.eventType(); +pub(crate) unsafe fn platform_input_from_native( + native_event: id, + window_height: Option, +) -> Option { + unsafe { + let event_type = native_event.eventType(); - // Filter out event types that aren't in the NSEventType enum. - // See https://github.com/servo/cocoa-rs/issues/155#issuecomment-323482792 for details. - match event_type as u64 { - 0 | 21 | 32 | 33 | 35 | 36 | 37 => { - return None; - } - _ => {} + // Filter out event types that aren't in the NSEventType enum. + // See https://github.com/servo/cocoa-rs/issues/155#issuecomment-323482792 for details. + match event_type as u64 { + 0 | 21 | 32 | 33 | 35 | 36 | 37 => { + return None; } + _ => {} + } - match event_type { - NSEventType::NSFlagsChanged => { - Some(Self::ModifiersChanged(ModifiersChangedEvent { + match event_type { + NSEventType::NSFlagsChanged => { + Some(PlatformInput::ModifiersChanged(ModifiersChangedEvent { + modifiers: read_modifiers(native_event), + capslock: Capslock { + on: native_event + .modifierFlags() + .contains(NSEventModifierFlags::NSAlphaShiftKeyMask), + }, + })) + } + NSEventType::NSKeyDown => Some(PlatformInput::KeyDown(KeyDownEvent { + keystroke: parse_keystroke(native_event), + is_held: native_event.isARepeat() == YES, + prefer_character_input: false, + })), + NSEventType::NSKeyUp => Some(PlatformInput::KeyUp(KeyUpEvent { + keystroke: parse_keystroke(native_event), + })), + NSEventType::NSLeftMouseDown + | NSEventType::NSRightMouseDown + | NSEventType::NSOtherMouseDown => { + let button = match native_event.buttonNumber() { + 0 => MouseButton::Left, + 1 => MouseButton::Right, + 2 => MouseButton::Middle, + 3 => MouseButton::Navigate(NavigationDirection::Back), + 4 => MouseButton::Navigate(NavigationDirection::Forward), + // Other mouse buttons aren't tracked currently + _ => return None, + }; + window_height.map(|window_height| { + PlatformInput::MouseDown(MouseDownEvent { + button, + position: point( + px(native_event.locationInWindow().x as f32), + // MacOS screen coordinates are relative to bottom left + window_height - px(native_event.locationInWindow().y as f32), + ), modifiers: read_modifiers(native_event), - capslock: Capslock { - on: native_event - .modifierFlags() - .contains(NSEventModifierFlags::NSAlphaShiftKeyMask), - }, - })) - } - NSEventType::NSKeyDown => Some(Self::KeyDown(KeyDownEvent { - keystroke: parse_keystroke(native_event), - is_held: native_event.isARepeat() == YES, - prefer_character_input: false, - })), - NSEventType::NSKeyUp => Some(Self::KeyUp(KeyUpEvent { - keystroke: parse_keystroke(native_event), - })), - NSEventType::NSLeftMouseDown - | NSEventType::NSRightMouseDown - | NSEventType::NSOtherMouseDown => { - let button = match native_event.buttonNumber() { - 0 => MouseButton::Left, - 1 => MouseButton::Right, - 2 => MouseButton::Middle, - 3 => MouseButton::Navigate(NavigationDirection::Back), - 4 => MouseButton::Navigate(NavigationDirection::Forward), - // Other mouse buttons aren't tracked currently - _ => return None, - }; - window_height.map(|window_height| { - Self::MouseDown(MouseDownEvent { - button, - position: point( - px(native_event.locationInWindow().x as f32), - // MacOS screen coordinates are relative to bottom left - window_height - px(native_event.locationInWindow().y as f32), - ), - modifiers: read_modifiers(native_event), - click_count: native_event.clickCount() as usize, - first_mouse: false, - }) + click_count: native_event.clickCount() as usize, + first_mouse: false, }) - } - NSEventType::NSLeftMouseUp - | NSEventType::NSRightMouseUp - | NSEventType::NSOtherMouseUp => { - let button = match native_event.buttonNumber() { - 0 => MouseButton::Left, - 1 => MouseButton::Right, - 2 => MouseButton::Middle, - 3 => MouseButton::Navigate(NavigationDirection::Back), - 4 => MouseButton::Navigate(NavigationDirection::Forward), - // Other mouse buttons aren't tracked currently - _ => return None, - }; - - window_height.map(|window_height| { - Self::MouseUp(MouseUpEvent { - button, - position: point( - px(native_event.locationInWindow().x as f32), - window_height - px(native_event.locationInWindow().y as f32), - ), - modifiers: read_modifiers(native_event), - click_count: native_event.clickCount() as usize, - }) - }) - } - NSEventType::NSEventTypePressure => { - let stage = native_event.stage(); - let pressure = native_event.pressure(); - - window_height.map(|window_height| { - Self::MousePressure(MousePressureEvent { - stage: match stage { - 1 => PressureStage::Normal, - 2 => PressureStage::Force, - _ => PressureStage::Zero, - }, - pressure, - modifiers: read_modifiers(native_event), - position: point( - px(native_event.locationInWindow().x as f32), - window_height - px(native_event.locationInWindow().y as f32), - ), - }) + }) + } + NSEventType::NSLeftMouseUp + | NSEventType::NSRightMouseUp + | NSEventType::NSOtherMouseUp => { + let button = match native_event.buttonNumber() { + 0 => MouseButton::Left, + 1 => MouseButton::Right, + 2 => MouseButton::Middle, + 3 => MouseButton::Navigate(NavigationDirection::Back), + 4 => MouseButton::Navigate(NavigationDirection::Forward), + // Other mouse buttons aren't tracked currently + _ => return None, + }; + + window_height.map(|window_height| { + PlatformInput::MouseUp(MouseUpEvent { + button, + position: point( + px(native_event.locationInWindow().x as f32), + window_height - px(native_event.locationInWindow().y as f32), + ), + modifiers: read_modifiers(native_event), + click_count: native_event.clickCount() as usize, }) - } - // Some mice (like Logitech MX Master) send navigation buttons as swipe events - NSEventType::NSEventTypeSwipe => { - let navigation_direction = match native_event.phase() { - NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() { - x if x > 0.0 => Some(NavigationDirection::Back), - x if x < 0.0 => Some(NavigationDirection::Forward), - _ => return None, + }) + } + NSEventType::NSEventTypePressure => { + let stage = native_event.stage(); + let pressure = native_event.pressure(); + + window_height.map(|window_height| { + PlatformInput::MousePressure(MousePressureEvent { + stage: match stage { + 1 => PressureStage::Normal, + 2 => PressureStage::Force, + _ => PressureStage::Zero, }, - _ => return None, - }; - - match navigation_direction { - Some(direction) => window_height.map(|window_height| { - Self::MouseDown(MouseDownEvent { - button: MouseButton::Navigate(direction), - position: point( - px(native_event.locationInWindow().x as f32), - window_height - px(native_event.locationInWindow().y as f32), - ), - modifiers: read_modifiers(native_event), - click_count: 1, - first_mouse: false, - }) - }), - _ => None, - } - } - NSEventType::NSScrollWheel => window_height.map(|window_height| { - let phase = match native_event.phase() { - NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { - TouchPhase::Started - } - NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, - _ => TouchPhase::Moved, - }; - - let raw_data = point( - native_event.scrollingDeltaX() as f32, - native_event.scrollingDeltaY() as f32, - ); - - let delta = if native_event.hasPreciseScrollingDeltas() == YES { - ScrollDelta::Pixels(raw_data.map(px)) - } else { - ScrollDelta::Lines(raw_data) - }; - - Self::ScrollWheel(ScrollWheelEvent { + pressure, + modifiers: read_modifiers(native_event), position: point( px(native_event.locationInWindow().x as f32), window_height - px(native_event.locationInWindow().y as f32), ), - delta, - touch_phase: phase, - modifiers: read_modifiers(native_event), }) - }), - NSEventType::NSLeftMouseDragged - | NSEventType::NSRightMouseDragged - | NSEventType::NSOtherMouseDragged => { - let pressed_button = match native_event.buttonNumber() { - 0 => MouseButton::Left, - 1 => MouseButton::Right, - 2 => MouseButton::Middle, - 3 => MouseButton::Navigate(NavigationDirection::Back), - 4 => MouseButton::Navigate(NavigationDirection::Forward), - // Other mouse buttons aren't tracked currently + }) + } + // Some mice (like Logitech MX Master) send navigation buttons as swipe events + NSEventType::NSEventTypeSwipe => { + let navigation_direction = match native_event.phase() { + NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() { + x if x > 0.0 => Some(NavigationDirection::Back), + x if x < 0.0 => Some(NavigationDirection::Forward), _ => return None, - }; - - window_height.map(|window_height| { - Self::MouseMove(MouseMoveEvent { - pressed_button: Some(pressed_button), + }, + _ => return None, + }; + + match navigation_direction { + Some(direction) => window_height.map(|window_height| { + PlatformInput::MouseDown(MouseDownEvent { + button: MouseButton::Navigate(direction), position: point( px(native_event.locationInWindow().x as f32), window_height - px(native_event.locationInWindow().y as f32), ), modifiers: read_modifiers(native_event), + click_count: 1, + first_mouse: false, }) - }) + }), + _ => None, } - NSEventType::NSMouseMoved => window_height.map(|window_height| { - Self::MouseMove(MouseMoveEvent { - position: point( - px(native_event.locationInWindow().x as f32), - window_height - px(native_event.locationInWindow().y as f32), - ), - pressed_button: None, - modifiers: read_modifiers(native_event), - }) - }), - NSEventType::NSMouseExited => window_height.map(|window_height| { - Self::MouseExited(MouseExitEvent { + } + NSEventType::NSScrollWheel => window_height.map(|window_height| { + let phase = match native_event.phase() { + NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { + TouchPhase::Started + } + NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, + _ => TouchPhase::Moved, + }; + + let raw_data = point( + native_event.scrollingDeltaX() as f32, + native_event.scrollingDeltaY() as f32, + ); + + let delta = if native_event.hasPreciseScrollingDeltas() == YES { + ScrollDelta::Pixels(raw_data.map(px)) + } else { + ScrollDelta::Lines(raw_data) + }; + + PlatformInput::ScrollWheel(ScrollWheelEvent { + position: point( + px(native_event.locationInWindow().x as f32), + window_height - px(native_event.locationInWindow().y as f32), + ), + delta, + touch_phase: phase, + modifiers: read_modifiers(native_event), + }) + }), + NSEventType::NSLeftMouseDragged + | NSEventType::NSRightMouseDragged + | NSEventType::NSOtherMouseDragged => { + let pressed_button = match native_event.buttonNumber() { + 0 => MouseButton::Left, + 1 => MouseButton::Right, + 2 => MouseButton::Middle, + 3 => MouseButton::Navigate(NavigationDirection::Back), + 4 => MouseButton::Navigate(NavigationDirection::Forward), + // Other mouse buttons aren't tracked currently + _ => return None, + }; + + window_height.map(|window_height| { + PlatformInput::MouseMove(MouseMoveEvent { + pressed_button: Some(pressed_button), position: point( px(native_event.locationInWindow().x as f32), window_height - px(native_event.locationInWindow().y as f32), ), - - pressed_button: None, modifiers: read_modifiers(native_event), }) - }), - _ => None, + }) } + NSEventType::NSMouseMoved => window_height.map(|window_height| { + PlatformInput::MouseMove(MouseMoveEvent { + position: point( + px(native_event.locationInWindow().x as f32), + window_height - px(native_event.locationInWindow().y as f32), + ), + pressed_button: None, + modifiers: read_modifiers(native_event), + }) + }), + NSEventType::NSMouseExited => window_height.map(|window_height| { + PlatformInput::MouseExited(MouseExitEvent { + position: point( + px(native_event.locationInWindow().x as f32), + window_height - px(native_event.locationInWindow().y as f32), + ), + + pressed_button: None, + modifiers: read_modifiers(native_event), + }) + }), + _ => None, } } } @@ -320,7 +318,7 @@ unsafe fn parse_keystroke(native_event: id) -> Keystroke { unsafe { use cocoa::appkit::*; - let mut characters = native_event + let characters = native_event .charactersIgnoringModifiers() .to_str() .to_string(); diff --git a/crates/gpui/src/platform/mac.rs b/crates/gpui_macos/src/gpui_macos.rs similarity index 73% rename from crates/gpui/src/platform/mac.rs rename to crates/gpui_macos/src/gpui_macos.rs index 1c019b8ccebb7cf9dbd03fbf47055bf3a6518d20..b9b55430b81fc7848d4e2be06e8cf49564c3c11a 100644 --- a/crates/gpui/src/platform/mac.rs +++ b/crates/gpui_macos/src/gpui_macos.rs @@ -1,5 +1,9 @@ -//! Macos screen have a y axis that goings up from the bottom of the screen and +#![cfg(target_os = "macos")] +//! macOS platform implementation for GPUI. +//! +//! macOS screens have a y axis that goes up from the bottom of the screen and //! an origin at the bottom left of the main display. + mod dispatcher; mod display; mod display_link; @@ -13,7 +17,6 @@ mod screen_capture; mod metal_atlas; pub mod metal_renderer; -use core_video::image_buffer::CVImageBuffer; use metal_renderer as renderer; #[cfg(feature = "font-kit")] @@ -26,10 +29,9 @@ mod platform; mod window; mod window_appearance; -use crate::{DevicePixels, Pixels, Size, px, size}; use cocoa::{ base::{id, nil}, - foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, + foundation::{NSAutoreleasePool, NSNotFound, NSString, NSUInteger}, }; use objc::runtime::{BOOL, NO, YES}; @@ -48,8 +50,7 @@ pub(crate) use window::*; #[cfg(feature = "font-kit")] pub(crate) use text_system::*; -/// A frame of video captured from a screen. -pub(crate) type PlatformScreenCaptureFrame = CVImageBuffer; +pub use platform::MacPlatform; trait BoolExt { fn to_objc(self) -> BOOL; @@ -133,26 +134,3 @@ unsafe impl objc::Encode for NSRange { unsafe fn ns_string(string: &str) -> id { unsafe { NSString::alloc(nil).init_str(string).autorelease() } } - -impl From for Size { - fn from(value: NSSize) -> Self { - Size { - width: px(value.width as f32), - height: px(value.height as f32), - } - } -} - -impl From for Size { - fn from(rect: NSRect) -> Self { - let NSSize { width, height } = rect.size; - size(width.into(), height.into()) - } -} - -impl From for Size { - fn from(rect: NSRect) -> Self { - let NSSize { width, height } = rect.size; - size(DevicePixels(width as i32), DevicePixels(height as i32)) - } -} diff --git a/crates/gpui/src/platform/mac/keyboard.rs b/crates/gpui_macos/src/keyboard.rs similarity index 99% rename from crates/gpui/src/platform/mac/keyboard.rs rename to crates/gpui_macos/src/keyboard.rs index 14097312468cbb732b46f004dbb0970c26f6e821..68c497f06799d64f21aeb1a5a95cfcc167aeade0 100644 --- a/crates/gpui/src/platform/mac/keyboard.rs +++ b/crates/gpui_macos/src/keyboard.rs @@ -3,9 +3,9 @@ use std::ffi::{CStr, c_void}; use objc::{msg_send, runtime::Object, sel, sel_impl}; -use crate::{KeybindingKeystroke, Keystroke, PlatformKeyboardLayout, PlatformKeyboardMapper}; +use gpui::{KeybindingKeystroke, Keystroke, PlatformKeyboardLayout, PlatformKeyboardMapper}; -use super::{ +use crate::{ TISCopyCurrentKeyboardLayoutInputSource, TISGetInputSourceProperty, kTISPropertyInputSourceID, kTISPropertyLocalizedName, }; diff --git a/crates/gpui/src/platform/mac/metal_atlas.rs b/crates/gpui_macos/src/metal_atlas.rs similarity index 85% rename from crates/gpui/src/platform/mac/metal_atlas.rs rename to crates/gpui_macos/src/metal_atlas.rs index ad2e355bed440dd27ebf0e784a4b5cf9c83f111a..a741db75f77701f63407539979bdf3ecf08524dc 100644 --- a/crates/gpui/src/platform/mac/metal_atlas.rs +++ b/crates/gpui_macos/src/metal_atlas.rs @@ -1,11 +1,11 @@ -use crate::{ - AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas, - Point, Size, platform::AtlasTextureList, -}; use anyhow::{Context as _, Result}; use collections::FxHashMap; use derive_more::{Deref, DerefMut}; use etagere::BucketedAtlasAllocator; +use gpui::{ + AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTextureList, AtlasTile, Bounds, DevicePixels, + PlatformAtlas, Point, Size, +}; use metal::Device; use parking_lot::Mutex; use std::borrow::Cow; @@ -164,7 +164,7 @@ impl MetalAtlasState { index: index.unwrap_or(texture_list.textures.len()) as u32, kind, }, - allocator: etagere::BucketedAtlasAllocator::new(size.into()), + allocator: etagere::BucketedAtlasAllocator::new(size_to_etagere(size)), metal_texture: AssertSend(metal_texture), live_atlas_keys: 0, }; @@ -183,9 +183,9 @@ impl MetalAtlasState { fn texture(&self, id: AtlasTextureId) -> &MetalAtlasTexture { let textures = match id.kind { - crate::AtlasTextureKind::Monochrome => &self.monochrome_textures, - crate::AtlasTextureKind::Polychrome => &self.polychrome_textures, - crate::AtlasTextureKind::Subpixel => unreachable!(), + AtlasTextureKind::Monochrome => &self.monochrome_textures, + AtlasTextureKind::Polychrome => &self.polychrome_textures, + AtlasTextureKind::Subpixel => unreachable!(), }; textures[id.index as usize].as_ref().unwrap() } @@ -200,12 +200,12 @@ struct MetalAtlasTexture { impl MetalAtlasTexture { fn allocate(&mut self, size: Size) -> Option { - let allocation = self.allocator.allocate(size.into())?; + let allocation = self.allocator.allocate(size_to_etagere(size))?; let tile = AtlasTile { texture_id: self.id, tile_id: allocation.id.into(), bounds: Bounds { - origin: allocation.rectangle.min.into(), + origin: point_from_etagere(allocation.rectangle.min), size, }, padding: 0, @@ -247,36 +247,14 @@ impl MetalAtlasTexture { } } -impl From> for etagere::Size { - fn from(size: Size) -> Self { - etagere::Size::new(size.width.into(), size.height.into()) - } +fn size_to_etagere(size: Size) -> etagere::Size { + etagere::Size::new(size.width.into(), size.height.into()) } -impl From for Point { - fn from(value: etagere::Point) -> Self { - Point { - x: DevicePixels::from(value.x), - y: DevicePixels::from(value.y), - } - } -} - -impl From for Size { - fn from(size: etagere::Size) -> Self { - Size { - width: DevicePixels::from(size.width), - height: DevicePixels::from(size.height), - } - } -} - -impl From for Bounds { - fn from(rectangle: etagere::Rectangle) -> Self { - Bounds { - origin: rectangle.min.into(), - size: rectangle.size().into(), - } +fn point_from_etagere(value: etagere::Point) -> Point { + Point { + x: DevicePixels::from(value.x), + y: DevicePixels::from(value.y), } } diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui_macos/src/metal_renderer.rs similarity index 99% rename from crates/gpui/src/platform/mac/metal_renderer.rs rename to crates/gpui_macos/src/metal_renderer.rs index e33b1169f10afe025ee506f89eeac132bdcf8bfc..17ed3543124c4f527c3bc75cff2e192c12003975 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui_macos/src/metal_renderer.rs @@ -1,9 +1,4 @@ -use super::metal_atlas::MetalAtlas; -use crate::{ - AtlasTextureId, Background, Bounds, ContentMask, DevicePixels, MonochromeSprite, PaintSurface, - Path, Point, PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size, - Surface, Underline, point, size, -}; +use crate::metal_atlas::MetalAtlas; use anyhow::Result; use block::ConcreteBlock; use cocoa::{ @@ -11,6 +6,11 @@ use cocoa::{ foundation::{NSSize, NSUInteger}, quartzcore::AutoresizingMask, }; +use gpui::{ + AtlasTextureId, Background, Bounds, ContentMask, DevicePixels, MonochromeSprite, PaintSurface, + Path, Point, PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size, + Surface, Underline, point, size, +}; #[cfg(any(test, feature = "test-support"))] use image::RgbaImage; @@ -30,7 +30,7 @@ use parking_lot::Mutex; use std::{cell::Cell, ffi::c_void, mem, ptr, sync::Arc}; // Exported to metal -pub(crate) type PointF = crate::Point; +pub(crate) type PointF = gpui::Point; #[cfg(not(feature = "runtime_shaders"))] const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); @@ -40,14 +40,14 @@ const SHADERS_SOURCE_FILE: &str = include_str!(concat!(env!("OUT_DIR"), "/stitch // https://developer.apple.com/documentation/metal/mtldevice/1433355-supportstexturesamplecount const PATH_SAMPLE_COUNT: u32 = 4; -pub type Context = Arc>; -pub type Renderer = MetalRenderer; +pub(crate) type Context = Arc>; +pub(crate) type Renderer = MetalRenderer; -pub unsafe fn new_renderer( +pub(crate) unsafe fn new_renderer( context: self::Context, _native_window: *mut c_void, _native_view: *mut c_void, - _bounds: crate::Size, + _bounds: gpui::Size, transparent: bool, ) -> Renderer { MetalRenderer::new(context, transparent) @@ -349,7 +349,7 @@ impl MetalRenderer { self.path_intermediate_texture = Some(self.device.new_texture(&texture_descriptor)); if self.path_sample_count > 1 { - let mut msaa_descriptor = texture_descriptor; + let msaa_descriptor = texture_descriptor; msaa_descriptor.set_texture_type(metal::MTLTextureType::D2Multisample); msaa_descriptor.set_storage_mode(metal::MTLStorageMode::Private); msaa_descriptor.set_sample_count(self.path_sample_count as _); diff --git a/crates/gpui/src/platform/mac/open_type.rs b/crates/gpui_macos/src/open_type.rs similarity index 99% rename from crates/gpui/src/platform/mac/open_type.rs rename to crates/gpui_macos/src/open_type.rs index ff501df15f671318548a3959bd6b966f97e051b1..048ba13dd133d146ccb824247b303fde87ef455b 100644 --- a/crates/gpui/src/platform/mac/open_type.rs +++ b/crates/gpui_macos/src/open_type.rs @@ -1,6 +1,5 @@ #![allow(unused, non_upper_case_globals)] -use crate::{FontFallbacks, FontFeatures}; use cocoa::appkit::CGFloat; use core_foundation::{ array::{ @@ -25,6 +24,7 @@ use core_text::{ }, }; use font_kit::font::Font as FontKitFont; +use gpui::{FontFallbacks, FontFeatures}; use std::ptr; pub fn apply_features_and_fallbacks( diff --git a/crates/gpui/src/platform/mac/pasteboard.rs b/crates/gpui_macos/src/pasteboard.rs similarity index 97% rename from crates/gpui/src/platform/mac/pasteboard.rs rename to crates/gpui_macos/src/pasteboard.rs index 38710951f15b25515d906afc738c5b971b1bb135..aceb635194402cdb203aed0f27aae78fa42be32d 100644 --- a/crates/gpui/src/platform/mac/pasteboard.rs +++ b/crates/gpui_macos/src/pasteboard.rs @@ -9,10 +9,8 @@ use cocoa::{ use objc::{msg_send, runtime::Object, sel, sel_impl}; use strum::IntoEnumIterator as _; -use crate::{ - ClipboardEntry, ClipboardItem, ClipboardString, Image, ImageFormat, asset_cache::hash, - platform::mac::ns_string, -}; +use crate::ns_string; +use gpui::{ClipboardEntry, ClipboardItem, ClipboardString, Image, ImageFormat, hash}; pub struct Pasteboard { inner: id, @@ -77,7 +75,7 @@ impl Pasteboard { } fn read_image(&self, format: ImageFormat) -> Option { - let mut ut_type: UTType = format.into(); + let ut_type: UTType = format.into(); unsafe { let types: id = self.inner.types(); @@ -304,7 +302,7 @@ impl UTType { mod tests { use cocoa::{appkit::NSPasteboardTypeString, foundation::NSData}; - use crate::{ClipboardEntry, ClipboardItem, ClipboardString}; + use gpui::{ClipboardEntry, ClipboardItem, ClipboardString}; use super::*; diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui_macos/src/platform.rs similarity index 97% rename from crates/gpui/src/platform/mac/platform.rs rename to crates/gpui_macos/src/platform.rs index c990042a6e3d02f6284f14dc77b348bd8a6addf7..c982f6da191f6b657e51238d8b6ac3d11f724149 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui_macos/src/platform.rs @@ -1,12 +1,6 @@ -use super::{ - BoolExt, MacKeyboardLayout, MacKeyboardMapper, events::key_to_native, ns_string, renderer, -}; use crate::{ - Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, ForegroundExecutor, - KeyContext, Keymap, MacDispatcher, MacDisplay, MacWindow, Menu, MenuItem, OsMenu, OwnedMenu, - PathPromptOptions, Platform, PlatformDisplay, PlatformKeyboardLayout, PlatformKeyboardMapper, - PlatformTextSystem, PlatformWindow, Result, SystemMenuType, Task, ThermalState, - WindowAppearance, WindowParams, platform::mac::pasteboard::Pasteboard, + BoolExt, MacDispatcher, MacDisplay, MacKeyboardLayout, MacKeyboardMapper, MacWindow, + events::key_to_native, ns_string, pasteboard::Pasteboard, renderer, }; use anyhow::{Context as _, anyhow}; use block::ConcreteBlock; @@ -31,6 +25,12 @@ use core_foundation::{ }; use ctor::ctor; use futures::channel::oneshot; +use gpui::{ + Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, ForegroundExecutor, + KeyContext, Keymap, Menu, MenuItem, OsMenu, OwnedMenu, PathPromptOptions, Platform, + PlatformDisplay, PlatformKeyboardLayout, PlatformKeyboardMapper, PlatformTextSystem, + PlatformWindow, Result, SystemMenuType, Task, ThermalState, WindowAppearance, WindowParams, +}; use itertools::Itertools; use objc::{ class, @@ -154,7 +154,7 @@ unsafe fn build_classes() { } } -pub(crate) struct MacPlatform(Mutex); +pub struct MacPlatform(Mutex); pub(crate) struct MacPlatformState { background_executor: BackgroundExecutor, @@ -180,14 +180,14 @@ pub(crate) struct MacPlatformState { } impl MacPlatform { - pub(crate) fn new(headless: bool) -> Self { + pub fn new(headless: bool) -> Self { let dispatcher = Arc::new(MacDispatcher::new()); #[cfg(feature = "font-kit")] let text_system = Arc::new(crate::MacTextSystem::new()); #[cfg(not(feature = "font-kit"))] - let text_system = Arc::new(crate::NoopTextSystem::new()); + let text_system = Arc::new(gpui::NoopTextSystem::new()); let keyboard_layout = MacKeyboardLayout::new(); let keyboard_mapper = Rc::new(MacKeyboardMapper::new(keyboard_layout.id())); @@ -321,14 +321,14 @@ impl MacPlatform { .map(|binding| binding.keystrokes()); let selector = match os_action { - Some(crate::OsAction::Cut) => selector("cut:"), - Some(crate::OsAction::Copy) => selector("copy:"), - Some(crate::OsAction::Paste) => selector("paste:"), - Some(crate::OsAction::SelectAll) => selector("selectAll:"), + Some(gpui::OsAction::Cut) => selector("cut:"), + Some(gpui::OsAction::Copy) => selector("copy:"), + Some(gpui::OsAction::Paste) => selector("paste:"), + Some(gpui::OsAction::SelectAll) => selector("selectAll:"), // "undo:" and "redo:" are always disabled in our case, as // we don't have a NSTextView/NSTextField to enable them on. - Some(crate::OsAction::Undo) => selector("handleGPUIMenuItem:"), - Some(crate::OsAction::Redo) => selector("handleGPUIMenuItem:"), + Some(gpui::OsAction::Undo) => selector("handleGPUIMenuItem:"), + Some(gpui::OsAction::Redo) => selector("handleGPUIMenuItem:"), None => selector("handleGPUIMenuItem:"), }; @@ -448,7 +448,7 @@ impl Platform for MacPlatform { self.0.lock().background_executor.clone() } - fn foreground_executor(&self) -> crate::ForegroundExecutor { + fn foreground_executor(&self) -> gpui::ForegroundExecutor { self.0.lock().foreground_executor.clone() } @@ -493,7 +493,7 @@ impl Platform for MacPlatform { // this, we make quitting the application asynchronous so that we aren't holding borrows to // the app state on the stack when we actually terminate the app. - use super::dispatcher::{dispatch_get_main_queue, dispatch_sys::dispatch_async_f}; + use crate::dispatcher::{dispatch_get_main_queue, dispatch_sys::dispatch_async_f}; unsafe { dispatch_async_f(dispatch_get_main_queue(), ptr::null_mut(), Some(quit)); @@ -587,14 +587,14 @@ impl Platform for MacPlatform { #[cfg(feature = "screen-capture")] fn is_screen_capture_supported(&self) -> bool { let min_version = cocoa::foundation::NSOperatingSystemVersion::new(12, 3, 0); - super::is_macos_version_at_least(min_version) + crate::is_macos_version_at_least(min_version) } #[cfg(feature = "screen-capture")] fn screen_capture_sources( &self, - ) -> oneshot::Receiver>>> { - super::screen_capture::get_sources() + ) -> oneshot::Receiver>>> { + crate::screen_capture::get_sources() } fn active_window(&self) -> Option { @@ -626,7 +626,7 @@ impl Platform for MacPlatform { unsafe { let app = NSApplication::sharedApplication(nil); let appearance: id = msg_send![app, effectiveAppearance]; - WindowAppearance::from_native(appearance) + crate::window_appearance::window_appearance_from_native(appearance) } } @@ -1261,7 +1261,7 @@ extern "C" fn on_thermal_state_change(this: &mut Object, _: Sel, _: id) { // Defer to the next run loop iteration to avoid re-entrant borrows of the App RefCell, // as NSNotificationCenter delivers this notification synchronously and it may fire while // the App is already borrowed (same pattern as quit() above). - use super::dispatcher::{dispatch_get_main_queue, dispatch_sys::dispatch_async_f}; + use crate::dispatcher::{dispatch_get_main_queue, dispatch_sys::dispatch_async_f}; let platform = unsafe { get_mac_platform(this) }; let platform_ptr = platform as *const MacPlatform as *mut c_void; @@ -1367,7 +1367,7 @@ extern "C" fn menu_will_open(this: &mut Object, _: Sel, _: id) { extern "C" fn handle_dock_menu(this: &mut Object, _: Sel, _: id) -> id { unsafe { let platform = get_mac_platform(this); - let mut state = platform.0.lock(); + let state = platform.0.lock(); if let Some(id) = state.dock_menu { id } else { diff --git a/crates/gpui/src/platform/mac/screen_capture.rs b/crates/gpui_macos/src/screen_capture.rs similarity index 97% rename from crates/gpui/src/platform/mac/screen_capture.rs rename to crates/gpui_macos/src/screen_capture.rs index 4b80a87d32f45540c76790065514f29cc7f93b3f..a7eaa3e140ab7111b985051fc31963689a060f6f 100644 --- a/crates/gpui/src/platform/mac/screen_capture.rs +++ b/crates/gpui_macos/src/screen_capture.rs @@ -1,9 +1,4 @@ -use super::ns_string; -use crate::{ - DevicePixels, ForegroundExecutor, SharedString, SourceMetadata, - platform::{ScreenCaptureFrame, ScreenCaptureSource, ScreenCaptureStream}, - size, -}; +use crate::ns_string; use anyhow::{Result, anyhow}; use block::ConcreteBlock; use cocoa::{ @@ -18,6 +13,10 @@ use core_graphics::display::{ }; use ctor::ctor; use futures::channel::oneshot; +use gpui::{ + DevicePixels, ForegroundExecutor, ScreenCaptureFrame, ScreenCaptureSource, ScreenCaptureStream, + SharedString, SourceMetadata, size, +}; use media::core_media::{CMSampleBuffer, CMSampleBufferRef}; use metal::NSInteger; use objc::{ @@ -29,7 +28,7 @@ use objc::{ }; use std::{cell::RefCell, ffi::c_void, mem, ptr, rc::Rc}; -use super::NSStringExt; +use crate::NSStringExt; #[derive(Clone)] pub struct MacScreenCaptureSource { @@ -116,7 +115,7 @@ impl ScreenCaptureSource for MacScreenCaptureSource { let _: () = msg_send![configuration, release]; let _: () = msg_send![delegate, release]; - let (mut tx, rx) = oneshot::channel(); + let (tx, rx) = oneshot::channel(); let mut error: id = nil; let _: () = msg_send![stream, addStreamOutput:output type:SCStreamOutputTypeScreen sampleHandlerQueue:0 error:&mut error as *mut id]; @@ -243,11 +242,11 @@ unsafe fn screen_id_to_human_label() -> HashMap { pub(crate) fn get_sources() -> oneshot::Receiver>>> { unsafe { - let (mut tx, rx) = oneshot::channel(); + let (tx, rx) = oneshot::channel(); let tx = Rc::new(RefCell::new(Some(tx))); let screen_id_to_label = screen_id_to_human_label(); let block = ConcreteBlock::new(move |shareable_content: id, error: id| { - let Some(mut tx) = tx.borrow_mut().take() else { + let Some(tx) = tx.borrow_mut().take() else { return; }; diff --git a/crates/gpui/src/platform/mac/shaders.metal b/crates/gpui_macos/src/shaders.metal similarity index 100% rename from crates/gpui/src/platform/mac/shaders.metal rename to crates/gpui_macos/src/shaders.metal diff --git a/crates/gpui/src/platform/mac/text_system.rs b/crates/gpui_macos/src/text_system.rs similarity index 89% rename from crates/gpui/src/platform/mac/text_system.rs rename to crates/gpui_macos/src/text_system.rs index c72271f24fe4ea3750e7aa1d18cadf786cac741e..2511bcf12dc240bf11d2c050579a6c06ebb155ed 100644 --- a/crates/gpui/src/platform/mac/text_system.rs +++ b/crates/gpui_macos/src/text_system.rs @@ -1,9 +1,3 @@ -use crate::{ - Bounds, DevicePixels, Font, FontFallbacks, FontFeatures, FontId, FontMetrics, FontRun, - FontStyle, FontWeight, GlyphId, LineLayout, Pixels, PlatformTextSystem, Point, - RenderGlyphParams, Result, SUBPIXEL_VARIANTS_X, ShapedGlyph, ShapedRun, SharedString, Size, - TextRenderingMode, point, px, size, swap_rgba_pa_to_bgra, -}; use anyhow::anyhow; use cocoa::appkit::CGFloat; use collections::HashMap; @@ -39,16 +33,22 @@ use font_kit::{ source::SystemSource, sources::mem::MemSource, }; +use gpui::{ + Bounds, DevicePixels, Font, FontFallbacks, FontFeatures, FontId, FontMetrics, FontRun, + FontStyle, FontWeight, GlyphId, LineLayout, Pixels, PlatformTextSystem, RenderGlyphParams, + Result, SUBPIXEL_VARIANTS_X, ShapedGlyph, ShapedRun, SharedString, Size, TextRenderingMode, + point, px, size, swap_rgba_pa_to_bgra, +}; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use pathfinder_geometry::{ rect::{RectF, RectI}, transform2d::Transform2F, - vector::{Vector2F, Vector2I}, + vector::Vector2F, }; use smallvec::SmallVec; use std::{borrow::Cow, char, convert::TryFrom, sync::Arc}; -use super::open_type::apply_features_and_fallbacks; +use crate::open_type::apply_features_and_fallbacks; #[allow(non_upper_case_globals)] const kCGImageAlphaOnly: u32 = 7; @@ -159,8 +159,8 @@ impl PlatformTextSystem for MacTextSystem { let ix = font_kit::matching::find_best_match( &candidate_properties, &font_kit::properties::Properties { - style: font.style.into(), - weight: font.weight.into(), + style: fontkit_style(font.style), + weight: fontkit_weight(font.weight), stretch: Default::default(), }, )?; @@ -172,13 +172,13 @@ impl PlatformTextSystem for MacTextSystem { } fn font_metrics(&self, font_id: FontId) -> FontMetrics { - self.0.read().fonts[font_id.0].metrics().into() + font_kit_metrics_to_metrics(self.0.read().fonts[font_id.0].metrics()) } fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result> { - Ok(self.0.read().fonts[font_id.0] - .typographic_bounds(glyph_id.0)? - .into()) + Ok(bounds_from_rect( + self.0.read().fonts[font_id.0].typographic_bounds(glyph_id.0)?, + )) } fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result> { @@ -241,7 +241,7 @@ impl MacTextSystemState { features: &FontFeatures, fallbacks: Option<&FontFallbacks>, ) -> Result> { - let name = crate::text_system::font_name_with_fallbacks(name, ".AppleSystemUIFont"); + let name = gpui::font_name_with_fallbacks(name, ".AppleSystemUIFont"); let mut font_ids = SmallVec::new(); let family = self @@ -321,7 +321,9 @@ impl MacTextSystemState { } fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result> { - Ok(self.fonts[font_id.0].advance(glyph_id.0)?.into()) + Ok(size_from_vector2f( + self.fonts[font_id.0].advance(glyph_id.0)?, + )) } fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option { @@ -357,15 +359,13 @@ impl MacTextSystemState { fn raster_bounds(&self, params: &RenderGlyphParams) -> Result> { let font = &self.fonts[params.font_id.0]; let scale = Transform2F::from_scale(params.scale_factor); - Ok(font - .raster_bounds( - params.glyph_id.0, - params.font_size.into(), - scale, - HintingOptions::None, - font_kit::canvas::RasterizationOptions::GrayscaleAa, - )? - .into()) + Ok(bounds_from_rect_i(font.raster_bounds( + params.glyph_id.0, + params.font_size.into(), + scale, + HintingOptions::None, + font_kit::canvas::RasterizationOptions::GrayscaleAa, + )?)) } fn rasterize_glyph( @@ -480,12 +480,12 @@ impl MacTextSystemState { let font = &self.fonts[run.font_id.0]; let font_metrics = font.metrics(); - let font_scale = font_size.0 / font_metrics.units_per_em as f32; + let font_scale = f32::from(font_size) / font_metrics.units_per_em as f32; max_ascent = max_ascent.max(font_metrics.ascent * font_scale); max_descent = max_descent.max(-font_metrics.descent * font_scale); let font_size = if break_ligature { - px(font_size.0.next_up()) + px(f32::from(font_size).next_up()) } else { font_size }; @@ -514,7 +514,7 @@ impl MacTextSystemState { }; let font_id = self.id_for_native_font(font); - let mut glyphs = match runs.last_mut() { + let glyphs = match runs.last_mut() { Some(run) if run.font_id == font_id => &mut run.glyphs, _ => { runs.push(ShapedRun { @@ -530,7 +530,7 @@ impl MacTextSystemState { .zip(run.positions().iter()) .zip(run.string_indices().iter()) { - let mut glyph_utf16_ix = usize::try_from(glyph_utf16_ix).unwrap(); + let glyph_utf16_ix = usize::try_from(glyph_utf16_ix).unwrap(); if ix_converter.utf16_ix > glyph_utf16_ix { // We cannot reuse current index converter, as it can only seek forward. Restart the search. ix_converter = StringIndexConverter::new(text); @@ -586,80 +586,68 @@ impl<'a> StringIndexConverter<'a> { } } -impl From for FontMetrics { - fn from(metrics: Metrics) -> Self { - FontMetrics { - units_per_em: metrics.units_per_em, - ascent: metrics.ascent, - descent: metrics.descent, - line_gap: metrics.line_gap, - underline_position: metrics.underline_position, - underline_thickness: metrics.underline_thickness, - cap_height: metrics.cap_height, - x_height: metrics.x_height, - bounding_box: metrics.bounding_box.into(), - } - } -} - -impl From for Bounds { - fn from(rect: RectF) -> Self { - Bounds { - origin: point(rect.origin_x(), rect.origin_y()), - size: size(rect.width(), rect.height()), - } - } -} - -impl From for Bounds { - fn from(rect: RectI) -> Self { - Bounds { - origin: point(DevicePixels(rect.origin_x()), DevicePixels(rect.origin_y())), - size: size(DevicePixels(rect.width()), DevicePixels(rect.height())), - } - } -} - -impl From for Size { - fn from(value: Vector2I) -> Self { - size(value.x().into(), value.y().into()) +fn font_kit_metrics_to_metrics(metrics: Metrics) -> FontMetrics { + FontMetrics { + units_per_em: metrics.units_per_em, + ascent: metrics.ascent, + descent: metrics.descent, + line_gap: metrics.line_gap, + underline_position: metrics.underline_position, + underline_thickness: metrics.underline_thickness, + cap_height: metrics.cap_height, + x_height: metrics.x_height, + bounding_box: bounds_from_rect(metrics.bounding_box), } } -impl From for Bounds { - fn from(rect: RectI) -> Self { - Bounds { - origin: point(rect.origin_x(), rect.origin_y()), - size: size(rect.width(), rect.height()), - } +fn bounds_from_rect(rect: RectF) -> Bounds { + Bounds { + origin: point(rect.origin_x(), rect.origin_y()), + size: size(rect.width(), rect.height()), } } -impl From> for Vector2I { - fn from(size: Point) -> Self { - Vector2I::new(size.x as i32, size.y as i32) +fn bounds_from_rect_i(rect: RectI) -> Bounds { + Bounds { + origin: point(DevicePixels(rect.origin_x()), DevicePixels(rect.origin_y())), + size: size(DevicePixels(rect.width()), DevicePixels(rect.height())), } } -impl From for Size { - fn from(vec: Vector2F) -> Self { - size(vec.x(), vec.y()) - } +// impl From for Size { +// fn from(value: Vector2I) -> Self { +// size(value.x().into(), value.y().into()) +// } +// } + +// impl From for Bounds { +// fn from(rect: RectI) -> Self { +// Bounds { +// origin: point(rect.origin_x(), rect.origin_y()), +// size: size(rect.width(), rect.height()), +// } +// } +// } + +// impl From> for Vector2I { +// fn from(size: Point) -> Self { +// Vector2I::new(size.x as i32, size.y as i32) +// } +// } + +fn size_from_vector2f(vec: Vector2F) -> Size { + size(vec.x(), vec.y()) } -impl From for FontkitWeight { - fn from(value: FontWeight) -> Self { - FontkitWeight(value.0) - } +fn fontkit_weight(value: FontWeight) -> FontkitWeight { + FontkitWeight(value.0) } -impl From for FontkitStyle { - fn from(style: FontStyle) -> Self { - match style { - FontStyle::Normal => FontkitStyle::Normal, - FontStyle::Italic => FontkitStyle::Italic, - FontStyle::Oblique => FontkitStyle::Oblique, - } +fn fontkit_style(style: FontStyle) -> FontkitStyle { + match style { + FontStyle::Normal => FontkitStyle::Normal, + FontStyle::Italic => FontkitStyle::Italic, + FontStyle::Oblique => FontkitStyle::Oblique, } } @@ -706,7 +694,8 @@ mod lenient_font_attributes { #[cfg(test)] mod tests { - use crate::{FontRun, GlyphId, MacTextSystem, PlatformTextSystem, font, px}; + use crate::MacTextSystem; + use gpui::{FontRun, GlyphId, PlatformTextSystem, font, px}; #[test] fn test_layout_line_bom_char() { diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui_macos/src/window.rs similarity index 97% rename from crates/gpui/src/platform/mac/window.rs rename to crates/gpui_macos/src/window.rs index 5a93fe0fd570c1980b6ec104592a7726942a5fd0..0d4edc28e8d6c79742760ab5ae0be12d944244db 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui_macos/src/window.rs @@ -1,13 +1,7 @@ -use super::{BoolExt, MacDisplay, NSRange, NSStringExt, ns_string, renderer}; use crate::{ - AnyWindowHandle, BackgroundExecutor, Bounds, Capslock, DisplayLink, ExternalPaths, - FileDropEvent, ForegroundExecutor, KeyDownEvent, Keystroke, Modifiers, ModifiersChangedEvent, - MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas, - PlatformDisplay, PlatformInput, PlatformWindow, Point, PromptButton, PromptLevel, - RequestFrameOptions, SharedString, Size, SystemWindowTab, WindowAppearance, - WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowKind, WindowParams, - dispatch_get_main_queue, dispatch_sys::dispatch_async_f, platform::PlatformInputHandler, point, - px, size, + BoolExt, DisplayLink, MacDisplay, NSRange, NSStringExt, dispatch_get_main_queue, + dispatcher::dispatch_sys::dispatch_async_f, events::platform_input_from_native, ns_string, + renderer, }; #[cfg(any(test, feature = "test-support"))] use anyhow::Result; @@ -28,6 +22,15 @@ use cocoa::{ NSUserDefaults, }, }; +use gpui::{ + AnyWindowHandle, BackgroundExecutor, Bounds, Capslock, ExternalPaths, FileDropEvent, + ForegroundExecutor, KeyDownEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, + MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay, + PlatformInput, PlatformInputHandler, PlatformWindow, Point, PromptButton, PromptLevel, + RequestFrameOptions, SharedString, Size, SystemWindowTab, WindowAppearance, + WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowKind, WindowParams, point, + px, size, +}; #[cfg(any(test, feature = "test-support"))] use image::RgbaImage; @@ -408,7 +411,7 @@ struct MacWindowState { display_link: Option, renderer: renderer::Renderer, request_frame_callback: Option>, - event_callback: Option crate::DispatchEventResult>>, + event_callback: Option gpui::DispatchEventResult>>, activate_callback: Option>, resize_callback: Option, f32)>>, moved_callback: Option>, @@ -514,9 +517,14 @@ impl MacWindowState { } fn is_maximized(&self) -> bool { + fn rect_to_size(rect: NSRect) -> Size { + let NSSize { width, height } = rect.size; + size(width.into(), height.into()) + } + unsafe { let bounds = self.bounds(); - let screen_size = self.native_window.screen().visibleFrame().into(); + let screen_size = rect_to_size(self.native_window.screen().visibleFrame()); bounds.size == screen_size } } @@ -532,7 +540,7 @@ impl MacWindowState { let mut window_frame = unsafe { NSWindow::frame(self.native_window) }; let screen = unsafe { NSWindow::screen(self.native_window) }; if screen == nil { - return Bounds::new(point(px(0.), px(0.)), crate::DEFAULT_WINDOW_SIZE); + return Bounds::new(point(px(0.), px(0.)), gpui::DEFAULT_WINDOW_SIZE); } let screen_frame = unsafe { NSScreen::frame(screen) }; @@ -674,11 +682,14 @@ impl MacWindow { let window_rect = NSRect::new( NSPoint::new( - screen_frame.origin.x + bounds.origin.x.0 as f64, + screen_frame.origin.x + bounds.origin.x.as_f32() as f64, screen_frame.origin.y - + (display.bounds().size.height - bounds.origin.y).0 as f64, + + (display.bounds().size.height - bounds.origin.y).as_f32() as f64, + ), + NSSize::new( + bounds.size.width.as_f32() as f64, + bounds.size.height.as_f32() as f64, ), - NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), ); let native_window = native_window.initWithContentRect_styleMask_backing_defer_screen_( @@ -717,7 +728,7 @@ impl MacWindow { renderer_context, native_window as *mut _, native_view as *mut _, - bounds.size.map(|pixels| pixels.0), + bounds.size.map(|pixels| pixels.as_f32()), false, ), request_frame_callback: None, @@ -1029,8 +1040,8 @@ impl PlatformWindow for MacWindow { .spawn(async move { unsafe { window.setContentSize_(NSSize { - width: size.width.0 as f64, - height: size.height.0 as f64, + width: size.width.as_f32() as f64, + height: size.height.as_f32() as f64, }); } }) @@ -1103,7 +1114,7 @@ impl PlatformWindow for MacWindow { fn appearance(&self) -> WindowAppearance { unsafe { let appearance: id = msg_send![self.0.lock().native_window, effectiveAppearance]; - WindowAppearance::from_native(appearance) + crate::window_appearance::window_appearance_from_native(appearance) } } @@ -1227,7 +1238,7 @@ impl PlatformWindow for MacWindow { if answer.is_cancel() { // Bind Escape Key to Cancel Button - if let Some(key) = std::char::from_u32(super::events::ESCAPE_KEY as u32) { + if let Some(key) = std::char::from_u32(crate::events::ESCAPE_KEY as u32) { let _: () = msg_send![button, setKeyEquivalent: ns_string(&key.to_string())]; } @@ -1443,7 +1454,7 @@ impl PlatformWindow for MacWindow { self.0.as_ref().lock().request_frame_callback = Some(callback); } - fn on_input(&self, callback: Box crate::DispatchEventResult>) { + fn on_input(&self, callback: Box gpui::DispatchEventResult>) { self.0.as_ref().lock().event_callback = Some(callback); } @@ -1532,7 +1543,7 @@ impl PlatformWindow for MacWindow { self.0.as_ref().lock().toggle_tab_bar_callback = Some(callback); } - fn draw(&self, scene: &crate::Scene) { + fn draw(&self, scene: &gpui::Scene) { let mut this = self.0.lock(); this.renderer.draw(scene); } @@ -1541,7 +1552,7 @@ impl PlatformWindow for MacWindow { self.0.lock().renderer.sprite_atlas().clone() } - fn gpu_specs(&self) -> Option { + fn gpu_specs(&self) -> Option { None } @@ -1613,13 +1624,13 @@ impl PlatformWindow for MacWindow { unsafe { let app = NSApplication::sharedApplication(nil); - let mut event: id = msg_send![app, currentEvent]; + let event: id = msg_send![app, currentEvent]; let _: () = msg_send![window, performWindowDragWithEvent: event]; } } #[cfg(any(test, feature = "test-support"))] - fn render_to_image(&self, scene: &crate::Scene) -> Result { + fn render_to_image(&self, scene: &gpui::Scene) -> Result { let mut this = self.0.lock(); this.renderer.render_to_image(scene) } @@ -1742,7 +1753,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: let mut lock = window_state.as_ref().lock(); let window_height = lock.content_size().height; - let event = unsafe { PlatformInput::from_native(native_event, Some(window_height)) }; + let event = unsafe { platform_input_from_native(native_event, Some(window_height)) }; let Some(event) = event else { return NO; @@ -1760,7 +1771,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: }; match event { - PlatformInput::KeyDown(mut key_down_event) => { + PlatformInput::KeyDown(key_down_event) => { // For certain keystrokes, macOS will first dispatch a "key equivalent" event. // If that event isn't handled, it will then dispatch a "key down" event. GPUI // makes no distinction between these two types of events, so we need to ignore @@ -1859,7 +1870,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { let weak_window_state = Arc::downgrade(&window_state); let mut lock = window_state.as_ref().lock(); let window_height = lock.content_size().height; - let event = unsafe { PlatformInput::from_native(native_event, Some(window_height)) }; + let event = unsafe { platform_input_from_native(native_event, Some(window_height)) }; if let Some(mut event) = event { match &mut event { @@ -2023,7 +2034,7 @@ extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) { extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: id) { let window_state = unsafe { get_window_state(this) }; - let mut lock = window_state.as_ref().lock(); + let lock = window_state.as_ref().lock(); let min_version = NSOperatingSystemVersion::new(15, 3, 0); @@ -2082,7 +2093,7 @@ extern "C" fn window_did_change_screen(this: &Object, _: Sel, _: id) { extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) { let window_state = unsafe { get_window_state(this) }; - let mut lock = window_state.lock(); + let lock = window_state.lock(); let is_active = unsafe { lock.native_window.isKeyWindow() == YES }; // When opening a pop-up while the application isn't active, Cocoa sends a spurious @@ -2188,13 +2199,20 @@ extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) { } extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { + fn convert(value: NSSize) -> Size { + Size { + width: px(value.width as f32), + height: px(value.height as f32), + } + } + let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.as_ref().lock(); - let new_size = Size::::from(size); + let new_size = convert(size); let old_size = unsafe { let old_frame: NSRect = msg_send![this, frame]; - Size::::from(old_frame.size) + convert(old_frame.size) }; if old_size == new_size { @@ -2289,12 +2307,15 @@ extern "C" fn first_rect_for_character_range( |bounds| { NSRect::new( NSPoint::new( - frame.origin.x + bounds.origin.x.0 as f64, + frame.origin.x + bounds.origin.x.as_f32() as f64, frame.origin.y + frame.size.height - - bounds.origin.y.0 as f64 - - bounds.size.height.0 as f64, + - bounds.origin.y.as_f32() as f64 + - bounds.size.height.as_f32() as f64, + ), + NSSize::new( + bounds.size.width.as_f32() as f64, + bounds.size.height.as_f32() as f64, ), - NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), ) }, ) @@ -2397,7 +2418,7 @@ extern "C" fn do_command_by_selector(this: &Object, _: Sel, _: Sel) { let mut event_callback = lock.event_callback.take(); drop(lock); - if let Some((keystroke, mut callback)) = keystroke.zip(event_callback.as_mut()) { + if let Some((keystroke, callback)) = keystroke.zip(event_callback.as_mut()) { let handled = (callback)(PlatformInput::KeyDown(KeyDownEvent { keystroke, is_held: false, @@ -2532,7 +2553,7 @@ fn send_file_drop_event( ) -> bool { let mut window_state = window_state.lock(); let window_event_callback = window_state.event_callback.as_mut(); - if let Some(mut callback) = window_event_callback { + if let Some(callback) = window_event_callback { let external_files_dragged = match file_drop_event { FileDropEvent::Entered { .. } => Some(true), FileDropEvent::Exited => Some(false), diff --git a/crates/gpui_macos/src/window_appearance.rs b/crates/gpui_macos/src/window_appearance.rs new file mode 100644 index 0000000000000000000000000000000000000000..02704bb0fc22dd72de1dc9f92dc10c9cbdc0abf9 --- /dev/null +++ b/crates/gpui_macos/src/window_appearance.rs @@ -0,0 +1,35 @@ +use cocoa::{ + appkit::{NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight}, + base::id, + foundation::NSString, +}; +use gpui::WindowAppearance; +use objc::{msg_send, sel, sel_impl}; +use std::ffi::CStr; + +pub(crate) unsafe fn window_appearance_from_native(appearance: id) -> WindowAppearance { + let name: id = msg_send![appearance, name]; + unsafe { + if name == NSAppearanceNameVibrantLight { + WindowAppearance::VibrantLight + } else if name == NSAppearanceNameVibrantDark { + WindowAppearance::VibrantDark + } else if name == NSAppearanceNameAqua { + WindowAppearance::Light + } else if name == NSAppearanceNameDarkAqua { + WindowAppearance::Dark + } else { + println!( + "unknown appearance: {:?}", + CStr::from_ptr(name.UTF8String()) + ); + WindowAppearance::Light + } + } +} + +#[link(name = "AppKit", kind = "framework")] +unsafe extern "C" { + pub static NSAppearanceNameAqua: id; + pub static NSAppearanceNameDarkAqua: id; +} diff --git a/crates/gpui_platform/Cargo.toml b/crates/gpui_platform/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..5cf81c304283690f78871b830f6180c75ad6a34a --- /dev/null +++ b/crates/gpui_platform/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "gpui_platform" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "Apache-2.0" + +[lints] +workspace = true + +[lib] +path = "src/gpui_platform.rs" + +[features] +default = [] +font-kit = ["gpui_macos/font-kit"] +test-support = ["gpui/test-support"] +screen-capture = ["gpui/screen-capture", "gpui_macos/screen-capture", "gpui_windows/screen-capture", "gpui_linux/screen-capture"] +wayland = ["gpui_linux/wayland"] +x11 = ["gpui_linux/x11"] + +[dependencies] +gpui.workspace = true + +[target.'cfg(target_os = "macos")'.dependencies] +gpui_macos.workspace = true + +[target.'cfg(target_os = "windows")'.dependencies] +gpui_windows.workspace = true + +[target.'cfg(any(target_os = "linux", target_os = "freebsd"))'.dependencies] +gpui_linux.workspace = true diff --git a/crates/gpui_platform/LICENSE-APACHE b/crates/gpui_platform/LICENSE-APACHE new file mode 120000 index 0000000000000000000000000000000000000000..1cd601d0a3affae83854be02a0afdec3b7a9ec4d --- /dev/null +++ b/crates/gpui_platform/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/gpui_platform/src/gpui_platform.rs b/crates/gpui_platform/src/gpui_platform.rs new file mode 100644 index 0000000000000000000000000000000000000000..c8f45efd6d84f38159e4a659514c1ad7a8a8f364 --- /dev/null +++ b/crates/gpui_platform/src/gpui_platform.rs @@ -0,0 +1,150 @@ +//! Convenience crate that re-exports GPUI's platform traits and the +//! `current_platform` constructor so consumers don't need `#[cfg]` gating. + +pub use gpui::Platform; + +use std::rc::Rc; + +/// Returns a background executor for the current platform. +pub fn background_executor() -> gpui::BackgroundExecutor { + current_platform(true).background_executor() +} + +pub fn application() -> gpui::Application { + gpui::Application::with_platform(current_platform(false)) +} + +pub fn headless() -> gpui::Application { + gpui::Application::with_platform(current_platform(true)) +} + +/// Returns the default [`Platform`] for the current OS. +pub fn current_platform(headless: bool) -> Rc { + #[cfg(target_os = "macos")] + { + Rc::new(gpui_macos::MacPlatform::new(headless)) + } + + #[cfg(target_os = "windows")] + { + Rc::new( + gpui_windows::WindowsPlatform::new(headless) + .expect("failed to initialize Windows platform"), + ) + } + + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + { + gpui_linux::current_platform(headless) + } +} + +#[cfg(all(test, target_os = "macos"))] +mod tests { + use super::*; + use gpui::{AppContext, Empty, VisualTestAppContext}; + use std::cell::RefCell; + use std::time::Duration; + + // Note: All VisualTestAppContext tests are ignored by default because they require + // the macOS main thread. Standard Rust tests run on worker threads, which causes + // SIGABRT when interacting with macOS AppKit/Cocoa APIs. + // + // To run these tests, use: + // cargo test -p gpui visual_test_context -- --ignored --test-threads=1 + + #[test] + #[ignore] // Requires macOS main thread + fn test_foreground_tasks_run_with_run_until_parked() { + let mut cx = VisualTestAppContext::new(current_platform(false)); + + let task_ran = Rc::new(RefCell::new(false)); + + // Spawn a foreground task via the App's spawn method + // This should use our TestDispatcher, not the MacDispatcher + { + let task_ran = task_ran.clone(); + cx.update(|cx| { + cx.spawn(async move |_| { + *task_ran.borrow_mut() = true; + }) + .detach(); + }); + } + + // The task should not have run yet + assert!(!*task_ran.borrow()); + + // Run until parked should execute the foreground task + cx.run_until_parked(); + + // Now the task should have run + assert!(*task_ran.borrow()); + } + + #[test] + #[ignore] // Requires macOS main thread + fn test_advance_clock_triggers_delayed_tasks() { + let mut cx = VisualTestAppContext::new(current_platform(false)); + + let task_ran = Rc::new(RefCell::new(false)); + + // Spawn a task that waits for a timer + { + let task_ran = task_ran.clone(); + let executor = cx.background_executor.clone(); + cx.update(|cx| { + cx.spawn(async move |_| { + executor.timer(Duration::from_millis(500)).await; + *task_ran.borrow_mut() = true; + }) + .detach(); + }); + } + + // Run until parked - the task should be waiting on the timer + cx.run_until_parked(); + assert!(!*task_ran.borrow()); + + // Advance clock past the timer duration + cx.advance_clock(Duration::from_millis(600)); + + // Now the task should have completed + assert!(*task_ran.borrow()); + } + + #[test] + #[ignore] // Requires macOS main thread - window creation fails on test threads + fn test_window_spawn_uses_test_dispatcher() { + let mut cx = VisualTestAppContext::new(current_platform(false)); + + let task_ran = Rc::new(RefCell::new(false)); + + let window = cx + .open_offscreen_window_default(|_, cx| cx.new(|_| Empty)) + .expect("Failed to open window"); + + // Spawn a task via window.spawn - this is the critical test case + // for tooltip behavior, as tooltips use window.spawn for delayed show + { + let task_ran = task_ran.clone(); + cx.update_window(window.into(), |_, window, cx| { + window + .spawn(cx, async move |_| { + *task_ran.borrow_mut() = true; + }) + .detach(); + }) + .ok(); + } + + // The task should not have run yet + assert!(!*task_ran.borrow()); + + // Run until parked should execute the foreground task spawned via window + cx.run_until_parked(); + + // Now the task should have run + assert!(*task_ran.borrow()); + } +} diff --git a/crates/gpui_wgpu/Cargo.toml b/crates/gpui_wgpu/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..a3664fe59e9c51f5b9e68f63c67d30aa502bd737 --- /dev/null +++ b/crates/gpui_wgpu/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "gpui_wgpu" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "Apache-2.0" + +[lints] +workspace = true + +[lib] +path = "src/gpui_wgpu.rs" + +[target.'cfg(not(target_os = "windows"))'.dependencies] +gpui.workspace = true +anyhow.workspace = true +bytemuck = "1" +collections.workspace = true +etagere = "0.2" +log.workspace = true +parking_lot.workspace = true +profiling.workspace = true +raw-window-handle = "0.6" +smol.workspace = true +util.workspace = true +wgpu.workspace = true diff --git a/crates/gpui_wgpu/LICENSE-APACHE b/crates/gpui_wgpu/LICENSE-APACHE new file mode 120000 index 0000000000000000000000000000000000000000..1cd601d0a3affae83854be02a0afdec3b7a9ec4d --- /dev/null +++ b/crates/gpui_wgpu/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/gpui_wgpu/src/gpui_wgpu.rs b/crates/gpui_wgpu/src/gpui_wgpu.rs new file mode 100644 index 0000000000000000000000000000000000000000..8a1eb576ed01475973e92f37b05ca3ee393daf66 --- /dev/null +++ b/crates/gpui_wgpu/src/gpui_wgpu.rs @@ -0,0 +1,8 @@ +#![cfg(not(target_os = "windows"))] +mod wgpu_atlas; +mod wgpu_context; +mod wgpu_renderer; + +pub use wgpu_atlas::*; +pub use wgpu_context::*; +pub use wgpu_renderer::*; diff --git a/crates/gpui/src/platform/wgpu/shaders.wgsl b/crates/gpui_wgpu/src/shaders.wgsl similarity index 100% rename from crates/gpui/src/platform/wgpu/shaders.wgsl rename to crates/gpui_wgpu/src/shaders.wgsl diff --git a/crates/gpui/src/platform/wgpu/wgpu_atlas.rs b/crates/gpui_wgpu/src/wgpu_atlas.rs similarity index 97% rename from crates/gpui/src/platform/wgpu/wgpu_atlas.rs rename to crates/gpui_wgpu/src/wgpu_atlas.rs index f9e4aecc370434cc659afc75e2abd64d7202c98b..d3614ea126e3d3f7c4e83b645b0d4ac0d77e548e 100644 --- a/crates/gpui/src/platform/wgpu/wgpu_atlas.rs +++ b/crates/gpui_wgpu/src/wgpu_atlas.rs @@ -1,10 +1,10 @@ -use crate::{ - AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas, - Point, Size, platform::AtlasTextureList, -}; use anyhow::Result; use collections::FxHashMap; use etagere::{BucketedAtlasAllocator, size2}; +use gpui::{ + AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTextureList, AtlasTile, Bounds, DevicePixels, + PlatformAtlas, Point, Size, +}; use parking_lot::Mutex; use std::{borrow::Cow, ops, sync::Arc}; @@ -19,7 +19,7 @@ fn etagere_point_to_device(point: etagere::Point) -> Point { } } -pub(crate) struct WgpuAtlas(Mutex); +pub struct WgpuAtlas(Mutex); struct PendingUpload { id: AtlasTextureId, @@ -40,7 +40,7 @@ pub struct WgpuTextureInfo { } impl WgpuAtlas { - pub(crate) fn new(device: Arc, queue: Arc) -> Self { + pub fn new(device: Arc, queue: Arc) -> Self { WgpuAtlas(Mutex::new(WgpuAtlasState { device, queue, diff --git a/crates/gpui/src/platform/wgpu/wgpu_context.rs b/crates/gpui_wgpu/src/wgpu_context.rs similarity index 100% rename from crates/gpui/src/platform/wgpu/wgpu_context.rs rename to crates/gpui_wgpu/src/wgpu_context.rs diff --git a/crates/gpui/src/platform/wgpu/wgpu_renderer.rs b/crates/gpui_wgpu/src/wgpu_renderer.rs similarity index 99% rename from crates/gpui/src/platform/wgpu/wgpu_renderer.rs rename to crates/gpui_wgpu/src/wgpu_renderer.rs index 972d6f586341985e53327e3c7588e4b362f8dfba..f443f12dd54e599ad97d583b8ebf7f70b0c8f7ea 100644 --- a/crates/gpui/src/platform/wgpu/wgpu_renderer.rs +++ b/crates/gpui_wgpu/src/wgpu_renderer.rs @@ -1,10 +1,10 @@ -use super::{WgpuAtlas, WgpuContext}; -use crate::{ +use crate::{WgpuAtlas, WgpuContext}; +use bytemuck::{Pod, Zeroable}; +use gpui::{ AtlasTextureId, Background, Bounds, DevicePixels, GpuSpecs, MonochromeSprite, Path, Point, PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size, SubpixelSprite, Underline, get_gamma_correction_ratios, }; -use bytemuck::{Pod, Zeroable}; use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use std::num::NonZeroU64; use std::sync::Arc; diff --git a/crates/gpui_windows/Cargo.toml b/crates/gpui_windows/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..992a47dce9e8ff9be5ff588215866af0171125ce --- /dev/null +++ b/crates/gpui_windows/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "gpui_windows" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "Apache-2.0" + +[lints] +workspace = true + +[lib] +path = "src/gpui_windows.rs" + +[features] +default = ["gpui/default"] +test-support = ["gpui/test-support"] +screen-capture = ["gpui/screen-capture", "scap"] + +[dependencies] +gpui.workspace = true + +[target.'cfg(target_os = "windows")'.dependencies] +anyhow.workspace = true +collections.workspace = true +etagere = "0.2" +futures.workspace = true +image.workspace = true +itertools.workspace = true +log.workspace = true +parking_lot.workspace = true +rand.workspace = true +raw-window-handle = "0.6" +smallvec.workspace = true +util.workspace = true +uuid.workspace = true +windows.workspace = true +windows-core.workspace = true +windows-numerics = "0.2" +windows-registry = "0.5" + +[target.'cfg(target_os = "windows")'.dependencies.scap] +workspace = true +optional = true + +[target.'cfg(target_os = "windows")'.build-dependencies] +windows-registry = "0.5" diff --git a/crates/gpui_windows/LICENSE-APACHE b/crates/gpui_windows/LICENSE-APACHE new file mode 120000 index 0000000000000000000000000000000000000000..1cd601d0a3affae83854be02a0afdec3b7a9ec4d --- /dev/null +++ b/crates/gpui_windows/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/gpui_windows/build.rs b/crates/gpui_windows/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..1db95715e26daf9ab0ca5097183a763cf3aa8340 --- /dev/null +++ b/crates/gpui_windows/build.rs @@ -0,0 +1,242 @@ +#![allow(clippy::disallowed_methods, reason = "build scripts are exempt")] + +fn main() { + #[cfg(target_os = "windows")] + { + // Compile HLSL shaders + #[cfg(not(debug_assertions))] + compile_shaders(); + } +} + +#[cfg(all(target_os = "windows", not(debug_assertions)))] +mod shader_compilation { + use std::{ + fs, + io::Write, + path::{Path, PathBuf}, + process::{self, Command}, + }; + + pub fn compile_shaders() { + let shader_path = + PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("src/shaders.hlsl"); + let out_dir = std::env::var("OUT_DIR").unwrap(); + + println!("cargo:rerun-if-changed={}", shader_path.display()); + + // Check if fxc.exe is available + let fxc_path = find_fxc_compiler(); + + // Define all modules + let modules = [ + "quad", + "shadow", + "path_rasterization", + "path_sprite", + "underline", + "monochrome_sprite", + "subpixel_sprite", + "polychrome_sprite", + ]; + + let rust_binding_path = format!("{}/shaders_bytes.rs", out_dir); + if Path::new(&rust_binding_path).exists() { + fs::remove_file(&rust_binding_path) + .expect("Failed to remove existing Rust binding file"); + } + for module in modules { + compile_shader_for_module( + module, + &out_dir, + &fxc_path, + shader_path.to_str().unwrap(), + &rust_binding_path, + ); + } + + { + let shader_path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("src/color_text_raster.hlsl"); + compile_shader_for_module( + "emoji_rasterization", + &out_dir, + &fxc_path, + shader_path.to_str().unwrap(), + &rust_binding_path, + ); + } + } + + /// Locate `binary` in the newest installed Windows SDK. + pub fn find_latest_windows_sdk_binary( + binary: &str, + ) -> Result, Box> { + let key = windows_registry::LOCAL_MACHINE + .open("SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0")?; + + let install_folder: String = key.get_string("InstallationFolder")?; // "C:\Program Files (x86)\Windows Kits\10\" + let install_folder_bin = Path::new(&install_folder).join("bin"); + + let mut versions: Vec<_> = std::fs::read_dir(&install_folder_bin)? + .flatten() + .filter(|entry| entry.path().is_dir()) + .filter_map(|entry| entry.file_name().into_string().ok()) + .collect(); + + versions.sort_by_key(|s| { + s.split('.') + .filter_map(|p| p.parse().ok()) + .collect::>() + }); + + let arch = match std::env::consts::ARCH { + "x86_64" => "x64", + "aarch64" => "arm64", + _ => Err(format!( + "Unsupported architecture: {}", + std::env::consts::ARCH + ))?, + }; + + if let Some(highest_version) = versions.last() { + return Ok(Some( + install_folder_bin + .join(highest_version) + .join(arch) + .join(binary), + )); + } + + Ok(None) + } + + /// You can set the `GPUI_FXC_PATH` environment variable to specify the path to the fxc.exe compiler. + fn find_fxc_compiler() -> String { + // Check environment variable + if let Ok(path) = std::env::var("GPUI_FXC_PATH") + && Path::new(&path).exists() + { + return path; + } + + // Try to find in PATH + // NOTE: This has to be `where.exe` on Windows, not `where`, it must be ended with `.exe` + if let Ok(output) = std::process::Command::new("where.exe") + .arg("fxc.exe") + .output() + && output.status.success() + { + let path = String::from_utf8_lossy(&output.stdout); + return path.trim().to_string(); + } + + if let Ok(Some(path)) = find_latest_windows_sdk_binary("fxc.exe") { + return path.to_string_lossy().into_owned(); + } + + panic!("Failed to find fxc.exe"); + } + + fn compile_shader_for_module( + module: &str, + out_dir: &str, + fxc_path: &str, + shader_path: &str, + rust_binding_path: &str, + ) { + // Compile vertex shader + let output_file = format!("{}/{}_vs.h", out_dir, module); + let const_name = format!("{}_VERTEX_BYTES", module.to_uppercase()); + compile_shader_impl( + fxc_path, + &format!("{module}_vertex"), + &output_file, + &const_name, + shader_path, + "vs_4_1", + ); + generate_rust_binding(&const_name, &output_file, rust_binding_path); + + // Compile fragment shader + let output_file = format!("{}/{}_ps.h", out_dir, module); + let const_name = format!("{}_FRAGMENT_BYTES", module.to_uppercase()); + compile_shader_impl( + fxc_path, + &format!("{module}_fragment"), + &output_file, + &const_name, + shader_path, + "ps_4_1", + ); + generate_rust_binding(&const_name, &output_file, rust_binding_path); + } + + fn compile_shader_impl( + fxc_path: &str, + entry_point: &str, + output_path: &str, + var_name: &str, + shader_path: &str, + target: &str, + ) { + let output = Command::new(fxc_path) + .args([ + "/T", + target, + "/E", + entry_point, + "/Fh", + output_path, + "/Vn", + var_name, + "/O3", + shader_path, + ]) + .output(); + + match output { + Ok(result) => { + if result.status.success() { + return; + } + println!( + "cargo::error=Shader compilation failed for {}:\n{}", + entry_point, + String::from_utf8_lossy(&result.stderr) + ); + process::exit(1); + } + Err(e) => { + println!("cargo::error=Failed to run fxc for {}: {}", entry_point, e); + process::exit(1); + } + } + } + + fn generate_rust_binding(const_name: &str, head_file: &str, output_path: &str) { + let header_content = fs::read_to_string(head_file).expect("Failed to read header file"); + let const_definition = { + let global_var_start = header_content.find("const BYTE").unwrap(); + let global_var = &header_content[global_var_start..]; + let equal = global_var.find('=').unwrap(); + global_var[equal + 1..].trim() + }; + let rust_binding = format!( + "const {}: &[u8] = &{}\n", + const_name, + const_definition.replace('{', "[").replace('}', "]") + ); + let mut options = fs::OpenOptions::new() + .create(true) + .append(true) + .open(output_path) + .expect("Failed to open Rust binding file"); + options + .write_all(rust_binding.as_bytes()) + .expect("Failed to write Rust binding file"); + } +} + +#[cfg(all(target_os = "windows", not(debug_assertions)))] +use shader_compilation::compile_shaders; diff --git a/crates/gpui/src/platform/windows/alpha_correction.hlsl b/crates/gpui_windows/src/alpha_correction.hlsl similarity index 100% rename from crates/gpui/src/platform/windows/alpha_correction.hlsl rename to crates/gpui_windows/src/alpha_correction.hlsl diff --git a/crates/gpui/src/platform/windows/clipboard.rs b/crates/gpui_windows/src/clipboard.rs similarity index 96% rename from crates/gpui/src/platform/windows/clipboard.rs rename to crates/gpui_windows/src/clipboard.rs index 6e110650e09c4dba4580bd8139b34eee6934b005..c2b8c0ff30c4d9e4c99c9d8c69ffcbf3da19211b 100644 --- a/crates/gpui/src/platform/windows/clipboard.rs +++ b/crates/gpui_windows/src/clipboard.rs @@ -18,7 +18,7 @@ use windows::Win32::{ }; use windows_core::PCWSTR; -use crate::{ +use gpui::{ ClipboardEntry, ClipboardItem, ClipboardString, ExternalPaths, Image, ImageFormat, hash, }; @@ -229,7 +229,8 @@ fn write_image_to_clipboard(item: &Image) -> Result<()> { } fn convert_image_to_png_format(bytes: &[u8], image_format: ImageFormat) -> Result> { - let image = image::load_from_memory_with_format(bytes, image_format.into())?; + let image = + image::load_from_memory_with_format(bytes, gpui_image_format_to_image(image_format))?; let mut output_buf = Vec::new(); image.write_to( &mut std::io::Cursor::new(&mut output_buf), @@ -440,17 +441,15 @@ where Some(result) } -impl From for image::ImageFormat { - fn from(value: ImageFormat) -> Self { - match value { - ImageFormat::Png => image::ImageFormat::Png, - ImageFormat::Jpeg => image::ImageFormat::Jpeg, - ImageFormat::Webp => image::ImageFormat::WebP, - ImageFormat::Gif => image::ImageFormat::Gif, - // TODO: ImageFormat::Svg - ImageFormat::Bmp => image::ImageFormat::Bmp, - ImageFormat::Tiff => image::ImageFormat::Tiff, - _ => unreachable!(), - } +fn gpui_image_format_to_image(value: ImageFormat) -> image::ImageFormat { + match value { + ImageFormat::Png => image::ImageFormat::Png, + ImageFormat::Jpeg => image::ImageFormat::Jpeg, + ImageFormat::Webp => image::ImageFormat::WebP, + ImageFormat::Gif => image::ImageFormat::Gif, + // TODO: ImageFormat::Svg + ImageFormat::Bmp => image::ImageFormat::Bmp, + ImageFormat::Tiff => image::ImageFormat::Tiff, + _ => unreachable!(), } } diff --git a/crates/gpui/src/platform/windows/color_text_raster.hlsl b/crates/gpui_windows/src/color_text_raster.hlsl similarity index 100% rename from crates/gpui/src/platform/windows/color_text_raster.hlsl rename to crates/gpui_windows/src/color_text_raster.hlsl diff --git a/crates/gpui/src/platform/windows/destination_list.rs b/crates/gpui_windows/src/destination_list.rs similarity index 99% rename from crates/gpui/src/platform/windows/destination_list.rs rename to crates/gpui_windows/src/destination_list.rs index 54ae089c3db6dd96f9a3faa45b397320d6cc98f3..d6967c01d2410fa5cfa6a5ed7b255a6a6872238f 100644 --- a/crates/gpui/src/platform/windows/destination_list.rs +++ b/crates/gpui_windows/src/destination_list.rs @@ -20,7 +20,7 @@ use windows::{ core::{GUID, HSTRING, Interface}, }; -use crate::{Action, MenuItem, SharedString}; +use gpui::{Action, MenuItem, SharedString}; pub(crate) struct JumpList { pub(crate) dock_menus: Vec, diff --git a/crates/gpui/src/platform/windows/direct_write.rs b/crates/gpui_windows/src/direct_write.rs similarity index 97% rename from crates/gpui/src/platform/windows/direct_write.rs rename to crates/gpui_windows/src/direct_write.rs index fb3afacb6348a9859b6a50b5f2a02e934718a70a..5cdd01f70af58728e1af6a72485f1175854b1af9 100644 --- a/crates/gpui/src/platform/windows/direct_write.rs +++ b/crates/gpui_windows/src/direct_write.rs @@ -24,6 +24,7 @@ use windows::{ use windows_numerics::Vector2; use crate::*; +use gpui::*; #[derive(Debug)] struct FontInfo { @@ -468,7 +469,7 @@ impl DirectWriteState { let family = if family == SYSTEM_UI_FONT_NAME { system_ui_font_name } else { - font_name_with_fallbacks_shared(&family, &system_ui_font_name) + gpui::font_name_with_fallbacks_shared(&family, &system_ui_font_name) }; let fontset = unsafe { collection.GetFontSet().log_err()? }; let font_family_h = HSTRING::from(family.as_str()); @@ -476,9 +477,9 @@ impl DirectWriteState { fontset .GetMatchingFonts( &font_family_h, - weight.into(), + font_weight_to_dwrite(weight), DWRITE_FONT_STRETCH_NORMAL, - style.into(), + font_style_to_dwrite(style), ) .log_err()? }; @@ -542,7 +543,7 @@ impl DirectWriteState { font_info.font_face.GetWeight(), font_info.font_face.GetStyle(), DWRITE_FONT_STRETCH_NORMAL, - font_size.0, + font_size.as_f32(), &components.locale, )? .cast()?; @@ -569,7 +570,7 @@ impl DirectWriteState { layout }; - let (mut ascent, mut descent) = { + let (ascent, descent) = { let mut first_metrics = [DWRITE_LINE_METRICS::default(); 4]; let mut line_count = 0u32; text_layout.GetLineMetrics(Some(&mut first_metrics), &mut line_count)?; @@ -594,9 +595,9 @@ impl DirectWriteState { text_layout.SetFontCollection(collection, text_range)?; text_layout.SetFontFamilyName(&font_info.font_family_h, text_range)?; let font_size = if break_ligatures { - font_size.0.next_up() + font_size.as_f32().next_up() } else { - font_size.0 + font_size.as_f32() }; text_layout.SetFontSize(font_size, text_range)?; text_layout.SetFontStyle(font_info.font_face.GetStyle(), text_range)?; @@ -673,7 +674,7 @@ impl DirectWriteState { let offset = [DWRITE_GLYPH_OFFSET::default()]; let glyph_run = DWRITE_GLYPH_RUN { fontFace: ManuallyDrop::new(Some(unsafe { std::ptr::read(&***font.font_face) })), - fontEmSize: params.font_size.0, + fontEmSize: params.font_size.as_f32(), glyphCount: 1, glyphIndices: glyph_id.as_ptr(), glyphAdvances: advance.as_ptr(), @@ -691,14 +692,15 @@ impl DirectWriteState { }; let baseline_origin_x = params.subpixel_variant.x as f32 / SUBPIXEL_VARIANTS_X as f32 / params.scale_factor; - let baseline_origin_y = - params.subpixel_variant.y as f32 / SUBPIXEL_VARIANTS_Y as f32 / params.scale_factor; + let baseline_origin_y = params.subpixel_variant.y as f32 + / gpui::SUBPIXEL_VARIANTS_Y as f32 + / params.scale_factor; let mut rendering_mode = DWRITE_RENDERING_MODE1::default(); let mut grid_fit_mode = DWRITE_GRID_FIT_MODE::default(); unsafe { font.font_face.GetRecommendedRenderingMode( - params.font_size.0, + params.font_size.as_f32(), // Using 96 as scale is applied by the transform 96.0, 96.0, @@ -904,7 +906,7 @@ impl DirectWriteState { }]; let glyph_run = DWRITE_GLYPH_RUN { fontFace: ManuallyDrop::new(Some(unsafe { std::ptr::read(&***font.font_face) })), - fontEmSize: params.font_size.0, + fontEmSize: params.font_size.as_f32(), glyphCount: 1, glyphIndices: glyph_id.as_ptr(), glyphAdvances: advance.as_ptr(), @@ -1525,7 +1527,7 @@ impl IDWriteTextRenderer_Impl for TextRenderer_Impl { let cluster_map = unsafe { std::slice::from_raw_parts(desc.clusterMap, desc.stringLength as usize) }; - let mut cluster_analyzer = ClusterAnalyzer::new(cluster_map, glyph_count); + let cluster_analyzer = ClusterAnalyzer::new(cluster_map, glyph_count); let mut utf16_idx = desc.textPosition as usize; let mut glyph_idx = 0; let mut glyphs = Vec::with_capacity(glyph_count); @@ -1642,37 +1644,29 @@ impl<'a> StringIndexConverter<'a> { } } -impl Into for FontStyle { - fn into(self) -> DWRITE_FONT_STYLE { - match self { - FontStyle::Normal => DWRITE_FONT_STYLE_NORMAL, - FontStyle::Italic => DWRITE_FONT_STYLE_ITALIC, - FontStyle::Oblique => DWRITE_FONT_STYLE_OBLIQUE, - } +fn font_style_to_dwrite(style: FontStyle) -> DWRITE_FONT_STYLE { + match style { + FontStyle::Normal => DWRITE_FONT_STYLE_NORMAL, + FontStyle::Italic => DWRITE_FONT_STYLE_ITALIC, + FontStyle::Oblique => DWRITE_FONT_STYLE_OBLIQUE, } } -impl From for FontStyle { - fn from(value: DWRITE_FONT_STYLE) -> Self { - match value.0 { - 0 => FontStyle::Normal, - 1 => FontStyle::Italic, - 2 => FontStyle::Oblique, - _ => unreachable!(), - } +fn font_style_from_dwrite(value: DWRITE_FONT_STYLE) -> FontStyle { + match value.0 { + 0 => FontStyle::Normal, + 1 => FontStyle::Italic, + 2 => FontStyle::Oblique, + _ => unreachable!(), } } -impl Into for FontWeight { - fn into(self) -> DWRITE_FONT_WEIGHT { - DWRITE_FONT_WEIGHT(self.0 as i32) - } +fn font_weight_to_dwrite(weight: FontWeight) -> DWRITE_FONT_WEIGHT { + DWRITE_FONT_WEIGHT(weight.0 as i32) } -impl From for FontWeight { - fn from(value: DWRITE_FONT_WEIGHT) -> Self { - FontWeight(value.0 as f32) - } +fn font_weight_from_dwrite(value: DWRITE_FONT_WEIGHT) -> FontWeight { + FontWeight(value.0 as f32) } fn get_font_names_from_collection( @@ -1707,8 +1701,8 @@ fn font_face_to_font(font_face: &IDWriteFontFace3, locale: &HSTRING) -> Option); @@ -230,7 +230,7 @@ impl DirectXAtlasState { kind, }, bytes_per_pixel, - allocator: etagere::BucketedAtlasAllocator::new(size.into()), + allocator: etagere::BucketedAtlasAllocator::new(device_size_to_etagere(size)), texture, view, live_atlas_keys: 0, @@ -246,13 +246,13 @@ impl DirectXAtlasState { fn texture(&self, id: AtlasTextureId) -> &DirectXAtlasTexture { match id.kind { - crate::AtlasTextureKind::Monochrome => &self.monochrome_textures[id.index as usize] + AtlasTextureKind::Monochrome => &self.monochrome_textures[id.index as usize] .as_ref() .unwrap(), - crate::AtlasTextureKind::Polychrome => &self.polychrome_textures[id.index as usize] + AtlasTextureKind::Polychrome => &self.polychrome_textures[id.index as usize] .as_ref() .unwrap(), - crate::AtlasTextureKind::Subpixel => { + AtlasTextureKind::Subpixel => { &self.subpixel_textures[id.index as usize].as_ref().unwrap() } } @@ -261,12 +261,12 @@ impl DirectXAtlasState { impl DirectXAtlasTexture { fn allocate(&mut self, size: Size) -> Option { - let allocation = self.allocator.allocate(size.into())?; + let allocation = self.allocator.allocate(device_size_to_etagere(size))?; let tile = AtlasTile { texture_id: self.id, tile_id: allocation.id.into(), bounds: Bounds { - origin: allocation.rectangle.min.into(), + origin: etagere_point_to_device(allocation.rectangle.min), size, }, padding: 0, @@ -309,17 +309,13 @@ impl DirectXAtlasTexture { } } -impl From> for etagere::Size { - fn from(size: Size) -> Self { - etagere::Size::new(size.width.into(), size.height.into()) - } +fn device_size_to_etagere(size: Size) -> etagere::Size { + etagere::Size::new(size.width.into(), size.height.into()) } -impl From for Point { - fn from(value: etagere::Point) -> Self { - Point { - x: DevicePixels::from(value.x), - y: DevicePixels::from(value.y), - } +fn etagere_point_to_device(value: etagere::Point) -> Point { + Point { + x: DevicePixels::from(value.x), + y: DevicePixels::from(value.y), } } diff --git a/crates/gpui/src/platform/windows/directx_devices.rs b/crates/gpui_windows/src/directx_devices.rs similarity index 100% rename from crates/gpui/src/platform/windows/directx_devices.rs rename to crates/gpui_windows/src/directx_devices.rs diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui_windows/src/directx_renderer.rs similarity index 99% rename from crates/gpui/src/platform/windows/directx_renderer.rs rename to crates/gpui_windows/src/directx_renderer.rs index 79b79c551383c6ecc498e99c0e06c40e65db0e44..ae8b54046c8823a67a185885b1e1f50cea922281 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui_windows/src/directx_renderer.rs @@ -19,12 +19,9 @@ use windows::{ core::Interface, }; -use crate::{ - platform::windows::directx_renderer::shader_resources::{ - RawShaderBytes, ShaderModule, ShaderTarget, - }, - *, -}; +use crate::directx_renderer::shader_resources::{RawShaderBytes, ShaderModule, ShaderTarget}; +use crate::*; +use gpui::*; pub(crate) const DISABLE_DIRECT_COMPOSITION: &str = "GPUI_DISABLE_DIRECT_COMPOSITION"; const RENDER_TARGET_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM; @@ -741,7 +738,7 @@ impl DirectXRenderer { let render_params: IDWriteRenderingParams1 = factory.CreateRenderingParams().unwrap().cast().unwrap(); FontInfo { - gamma_ratios: get_gamma_correction_ratios(render_params.GetGamma()), + gamma_ratios: gpui::get_gamma_correction_ratios(render_params.GetGamma()), grayscale_enhanced_contrast: render_params.GetGrayscaleEnhancedContrast(), subpixel_enhanced_contrast: render_params.GetEnhancedContrast(), } diff --git a/crates/gpui/src/platform/windows/dispatcher.rs b/crates/gpui_windows/src/dispatcher.rs similarity index 92% rename from crates/gpui/src/platform/windows/dispatcher.rs rename to crates/gpui_windows/src/dispatcher.rs index 3da9c30372e5dabcc3067d11909f6e88b7188bbb..060cdb7ba626133b9c201980e54bd0479694faa6 100644 --- a/crates/gpui/src/platform/windows/dispatcher.rs +++ b/crates/gpui_windows/src/dispatcher.rs @@ -21,10 +21,10 @@ use windows::{ }, }; -use crate::{ - GLOBAL_THREAD_TIMINGS, HWND, PlatformDispatcher, Priority, PriorityQueueSender, - RunnableVariant, SafeHwnd, THREAD_TIMINGS, TaskTiming, ThreadTaskTimings, TimerResolutionGuard, - WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD, profiler, +use crate::{HWND, SafeHwnd, WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD}; +use gpui::{ + GLOBAL_THREAD_TIMINGS, PlatformDispatcher, Priority, PriorityQueueSender, RunnableVariant, + THREAD_TIMINGS, TaskTiming, ThreadTaskTimings, TimerResolutionGuard, }; pub(crate) struct WindowsDispatcher { @@ -96,14 +96,14 @@ impl WindowsDispatcher { start, end: None, }; - profiler::add_task_timing(timing); + gpui::profiler::add_task_timing(timing); runnable.run(); let end = Instant::now(); timing.end = Some(end); - profiler::add_task_timing(timing); + gpui::profiler::add_task_timing(timing); } } @@ -113,7 +113,7 @@ impl PlatformDispatcher for WindowsDispatcher { ThreadTaskTimings::convert(&global_thread_timings) } - fn get_current_thread_timings(&self) -> crate::ThreadTaskTimings { + fn get_current_thread_timings(&self) -> gpui::ThreadTaskTimings { THREAD_TIMINGS.with(|timings| { let timings = timings.lock(); let thread_name = timings.thread_name.clone(); @@ -126,7 +126,7 @@ impl PlatformDispatcher for WindowsDispatcher { vec.extend_from_slice(s1); vec.extend_from_slice(s2); - crate::ThreadTaskTimings { + gpui::ThreadTaskTimings { thread_name, thread_id: std::thread::current().id(), timings: vec, @@ -207,10 +207,8 @@ impl PlatformDispatcher for WindowsDispatcher { unsafe { timeBeginPeriod(1); } - TimerResolutionGuard { - cleanup: Some(Box::new(|| unsafe { - timeEndPeriod(1); - })), - } + util::defer(Box::new(|| unsafe { + timeEndPeriod(1); + })) } } diff --git a/crates/gpui/src/platform/windows/display.rs b/crates/gpui_windows/src/display.rs similarity index 94% rename from crates/gpui/src/platform/windows/display.rs rename to crates/gpui_windows/src/display.rs index f26ba835908ff1d14e76ddc5430cd8498f4b7a00..1931a6949fdf648e4b65d9e89bb500ef71459f68 100644 --- a/crates/gpui/src/platform/windows/display.rs +++ b/crates/gpui_windows/src/display.rs @@ -15,7 +15,8 @@ use windows::{ core::*, }; -use crate::{Bounds, DevicePixels, DisplayId, Pixels, PlatformDisplay, logical_point, point, size}; +use crate::logical_point; +use gpui::{Bounds, DevicePixels, DisplayId, Pixels, PlatformDisplay, point, size}; #[derive(Debug, Clone, Copy)] pub(crate) struct WindowsDisplay { @@ -34,7 +35,9 @@ unsafe impl Sync for WindowsDisplay {} impl WindowsDisplay { pub(crate) fn new(display_id: DisplayId) -> Option { - let screen = available_monitors().into_iter().nth(display_id.0 as _)?; + let screen = available_monitors() + .into_iter() + .nth(u32::from(display_id) as _)?; let info = get_monitor_info(screen).log_err()?; let monitor_size = info.monitorInfo.rcMonitor; let work_area = info.monitorInfo.rcWork; @@ -63,7 +66,7 @@ impl WindowsDisplay { (work_area.right - work_area.left) as f32 / scale_factor, (work_area.bottom - work_area.top) as f32 / scale_factor, ) - .map(crate::px), + .map(gpui::px), }, physical_bounds: Bounds { origin: point(monitor_size.left.into(), monitor_size.top.into()), @@ -90,7 +93,7 @@ impl WindowsDisplay { Ok(WindowsDisplay { handle: monitor, - display_id: DisplayId(display_id as _), + display_id: DisplayId::new(display_id as _), scale_factor, bounds: Bounds { origin: logical_point( @@ -106,7 +109,7 @@ impl WindowsDisplay { (work_area.right - work_area.left) as f32 / scale_factor, (work_area.bottom - work_area.top) as f32 / scale_factor, ) - .map(crate::px), + .map(gpui::px), }, physical_bounds: Bounds { origin: point(monitor_size.left.into(), monitor_size.top.into()), @@ -145,7 +148,7 @@ impl WindowsDisplay { (work_area.right - work_area.left) as f32 / scale_factor, (work_area.bottom - work_area.top) as f32 / scale_factor, ) - .map(crate::px), + .map(gpui::px), }, physical_bounds: Bounds { origin: point(monitor_size.left.into(), monitor_size.top.into()), @@ -173,8 +176,8 @@ impl WindowsDisplay { pub fn check_given_bounds(&self, bounds: Bounds) -> bool { let center = bounds.center(); let center = POINT { - x: (center.x.0 * self.scale_factor) as i32, - y: (center.y.0 * self.scale_factor) as i32, + x: (center.x.as_f32() * self.scale_factor) as i32, + y: (center.y.as_f32() * self.scale_factor) as i32, }; let monitor = unsafe { MonitorFromPoint(center, MONITOR_DEFAULTTONULL) }; if monitor.is_invalid() { @@ -193,7 +196,7 @@ impl WindowsDisplay { .enumerate() .filter_map(|(id, handle)| { Some(Rc::new( - WindowsDisplay::new_with_handle_and_id(handle, DisplayId(id as _)).ok()?, + WindowsDisplay::new_with_handle_and_id(handle, DisplayId::new(id as _)).ok()?, ) as Rc) }) .collect() diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui_windows/src/events.rs similarity index 98% rename from crates/gpui/src/platform/windows/events.rs rename to crates/gpui_windows/src/events.rs index 871be1b3fd318ac4da68fb83059818b619e053bb..6bc7b73cc756b44b08ddf7abc5f668681c03dcb9 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui_windows/src/events.rs @@ -18,6 +18,7 @@ use windows::{ }; use crate::*; +use gpui::*; pub(crate) const WM_GPUI_CURSOR_STYLE_CHANGED: u32 = WM_USER + 1; pub(crate) const WM_GPUI_CLOSE_ONE_WINDOW: u32 = WM_USER + 2; @@ -127,13 +128,13 @@ impl WindowsWindowInner { ); self.state.origin.set(origin); let size = self.state.logical_size.get(); - let center_x = origin.x.0 + size.width.0 / 2.; - let center_y = origin.y.0 + size.height.0 / 2.; + let center_x = origin.x.as_f32() + size.width.as_f32() / 2.; + let center_y = origin.y.as_f32() + size.height.as_f32() / 2.; let monitor_bounds = self.state.display.get().bounds(); - if center_x < monitor_bounds.left().0 - || center_x > monitor_bounds.right().0 - || center_y < monitor_bounds.top().0 - || center_y > monitor_bounds.bottom().0 + if center_x < monitor_bounds.left().as_f32() + || center_x > monitor_bounds.right().as_f32() + || center_y < monitor_bounds.top().as_f32() + || center_y > monitor_bounds.bottom().as_f32() { // center of the window may have moved to another monitor let monitor = unsafe { MonitorFromWindow(handle, MONITOR_DEFAULTTONULL) }; @@ -160,10 +161,10 @@ impl WindowsWindowInner { unsafe { let minmax_info = &mut *(lparam.0 as *mut MINMAXINFO); - minmax_info.ptMinTrackSize.x = - min_size.width.scale(scale_factor).0 as i32 + boarder_offset.width_offset.get(); - minmax_info.ptMinTrackSize.y = - min_size.height.scale(scale_factor).0 as i32 + boarder_offset.height_offset.get(); + minmax_info.ptMinTrackSize.x = min_size.width.scale(scale_factor).as_f32() as i32 + + boarder_offset.width_offset.get(); + minmax_info.ptMinTrackSize.y = min_size.height.scale(scale_factor).as_f32() as i32 + + boarder_offset.height_offset.get(); } Some(0) } @@ -577,9 +578,9 @@ impl WindowsWindowInner { let caret_position = input_handler.bounds_for_range(caret_range.range)?; Some(POINT { // logical to physical - x: (caret_position.origin.x.0 * scale_factor) as i32, - y: (caret_position.origin.y.0 * scale_factor) as i32 - + ((caret_position.size.height.0 * scale_factor) as i32 / 2), + x: (caret_position.origin.x.as_f32() * scale_factor) as i32, + y: (caret_position.origin.y.as_f32() * scale_factor) as i32 + + ((caret_position.size.height.as_f32() * scale_factor) as i32 / 2), }) }) } diff --git a/crates/gpui/src/platform/windows.rs b/crates/gpui_windows/src/gpui_windows.rs similarity index 80% rename from crates/gpui/src/platform/windows.rs rename to crates/gpui_windows/src/gpui_windows.rs index 9cd1a7d05f4bcc6aa097db5dad64bdbc502575fc..af7408569ab1c88fc5f433795da99354942d89f2 100644 --- a/crates/gpui/src/platform/windows.rs +++ b/crates/gpui_windows/src/gpui_windows.rs @@ -1,3 +1,5 @@ +#![cfg(target_os = "windows")] + mod clipboard; mod destination_list; mod direct_write; @@ -32,9 +34,6 @@ pub(crate) use vsync::*; pub(crate) use window::*; pub(crate) use wrapper::*; -pub(crate) use windows::Win32::Foundation::HWND; +pub use platform::WindowsPlatform; -#[cfg(feature = "screen-capture")] -pub(crate) type PlatformScreenCaptureFrame = scap::frame::Frame; -#[cfg(not(feature = "screen-capture"))] -pub(crate) type PlatformScreenCaptureFrame = (); +pub(crate) use windows::Win32::Foundation::HWND; diff --git a/crates/gpui/src/platform/windows/keyboard.rs b/crates/gpui_windows/src/keyboard.rs similarity index 99% rename from crates/gpui/src/platform/windows/keyboard.rs rename to crates/gpui_windows/src/keyboard.rs index 627988be5701f6d2725d3f6042e9f994ef9e6d5b..8164bc1564d48b4adcb23deb40e91ee28a00a656 100644 --- a/crates/gpui/src/platform/windows/keyboard.rs +++ b/crates/gpui_windows/src/keyboard.rs @@ -10,7 +10,7 @@ use windows::Win32::UI::{ WindowsAndMessaging::KL_NAMELENGTH, }; -use crate::{ +use gpui::{ KeybindingKeystroke, Keystroke, Modifiers, PlatformKeyboardLayout, PlatformKeyboardMapper, }; @@ -316,7 +316,8 @@ const CANDIDATE_VKEYS: &[VIRTUAL_KEY] = &[ #[cfg(test)] mod tests { - use crate::{Keystroke, Modifiers, PlatformKeyboardMapper, WindowsKeyboardMapper}; + use crate::WindowsKeyboardMapper; + use gpui::{Keystroke, Modifiers, PlatformKeyboardMapper}; #[test] fn test_keyboard_mapper() { diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui_windows/src/platform.rs similarity index 98% rename from crates/gpui/src/platform/windows/platform.rs rename to crates/gpui_windows/src/platform.rs index b1eb15e47d3ec6ca45333da688d01175754bb128..182107138579be858272329a75a9daededd438e4 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui_windows/src/platform.rs @@ -28,8 +28,9 @@ use windows::{ }; use crate::*; +use gpui::*; -pub(crate) struct WindowsPlatform { +pub struct WindowsPlatform { inner: Rc, raw_window_handles: Arc>>, // The below members will never change throughout the entire lifecycle of the app. @@ -93,7 +94,7 @@ impl WindowsPlatformState { } impl WindowsPlatform { - pub(crate) fn new(headless: bool) -> Result { + pub fn new(headless: bool) -> Result { unsafe { OleInitialize(None).context("unable to initialize Windows OLE")?; } @@ -111,7 +112,7 @@ impl WindowsPlatform { } else { ( None, - Arc::new(crate::NoopTextSystem::new()) as Arc, + Arc::new(gpui::NoopTextSystem::new()) as Arc, None, ) }; @@ -195,7 +196,7 @@ impl WindowsPlatform { }) } - pub fn window_from_hwnd(&self, hwnd: HWND) -> Option> { + pub(crate) fn window_from_hwnd(&self, hwnd: HWND) -> Option> { self.raw_window_handles .read() .iter() @@ -452,7 +453,7 @@ impl Platform for WindowsPlatform { reason = "We are restarting ourselves, using std command thus is fine" )] let restart_process = - util::command::new_std_command(util::shell::get_windows_system_shell()) + ::util::command::new_std_command(::util::shell::get_windows_system_shell()) .arg("-command") .arg(script) .spawn(); @@ -496,7 +497,7 @@ impl Platform for WindowsPlatform { fn screen_capture_sources( &self, ) -> oneshot::Receiver>>> { - crate::platform::scap_screen_capture::scap_screen_sources(&self.foreground_executor) + gpui::scap_screen_capture::scap_screen_sources(&self.foreground_executor) } fn active_window(&self) -> Option { @@ -683,7 +684,7 @@ impl Platform for WindowsPlatform { } fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Task> { - let mut password = password.to_vec(); + let password = password.to_vec(); let mut username = username.encode_utf16().chain(Some(0)).collect_vec(); let mut target_name = windows_credentials_target_name(url) .encode_utf16() @@ -714,7 +715,7 @@ impl Platform for WindowsPlatform { } fn read_credentials(&self, url: &str) -> Task)>>> { - let mut target_name = windows_credentials_target_name(url) + let target_name = windows_credentials_target_name(url) .encode_utf16() .chain(Some(0)) .collect_vec(); @@ -756,7 +757,7 @@ impl Platform for WindowsPlatform { } fn delete_credentials(&self, url: &str) -> Task> { - let mut target_name = windows_credentials_target_name(url) + let target_name = windows_credentials_target_name(url) .encode_utf16() .chain(Some(0)) .collect_vec(); @@ -1340,7 +1341,8 @@ unsafe extern "system" fn window_procedure( #[cfg(test)] mod tests { - use crate::{ClipboardItem, read_from_clipboard, write_to_clipboard}; + use crate::{read_from_clipboard, write_to_clipboard}; + use gpui::ClipboardItem; #[test] fn test_clipboard() { diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui_windows/src/shaders.hlsl similarity index 100% rename from crates/gpui/src/platform/windows/shaders.hlsl rename to crates/gpui_windows/src/shaders.hlsl diff --git a/crates/gpui/src/platform/windows/system_settings.rs b/crates/gpui_windows/src/system_settings.rs similarity index 100% rename from crates/gpui/src/platform/windows/system_settings.rs rename to crates/gpui_windows/src/system_settings.rs diff --git a/crates/gpui/src/platform/windows/util.rs b/crates/gpui_windows/src/util.rs similarity index 95% rename from crates/gpui/src/platform/windows/util.rs rename to crates/gpui_windows/src/util.rs index bbb219165730ff033089269737ce3925ae9e7a89..fe5093dede385ce73a41e14f733b849e4480dab5 100644 --- a/crates/gpui/src/platform/windows/util.rs +++ b/crates/gpui_windows/src/util.rs @@ -11,10 +11,11 @@ use windows::{ Foundation::*, Graphics::Dwm::*, System::LibraryLoader::LoadLibraryA, UI::WindowsAndMessaging::*, }, - core::{BOOL, HSTRING, PCSTR}, + core::{BOOL, PCSTR}, }; use crate::*; +use gpui::*; pub(crate) trait HiLoWord { fn hiword(&self) -> u16; @@ -174,17 +175,6 @@ fn is_color_light(color: &Color) -> bool { ((5 * color.G as u32) + (2 * color.R as u32) + color.B as u32) > (8 * 128) } -pub(crate) fn show_error(title: &str, content: String) { - let _ = unsafe { - MessageBoxW( - None, - &HSTRING::from(content), - &HSTRING::from(title), - MB_ICONERROR | MB_SYSTEMMODAL, - ) - }; -} - pub(crate) fn with_dll_library(dll_name: PCSTR, f: F) -> Result where F: FnOnce(HMODULE) -> Result, diff --git a/crates/gpui/src/platform/windows/vsync.rs b/crates/gpui_windows/src/vsync.rs similarity index 100% rename from crates/gpui/src/platform/windows/vsync.rs rename to crates/gpui_windows/src/vsync.rs diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui_windows/src/window.rs similarity index 98% rename from crates/gpui/src/platform/windows/window.rs rename to crates/gpui_windows/src/window.rs index 26ce31a9978d45456b404b2401f6df152172a8e0..02653d7e53a4356979b81897b39ab0393bbf54a9 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui_windows/src/window.rs @@ -27,6 +27,7 @@ use windows::{ }; use crate::*; +use gpui::*; pub(crate) struct WindowsWindow(pub Rc); @@ -342,7 +343,7 @@ impl WindowsWindowInner { #[derive(Default)] pub(crate) struct Callbacks { pub(crate) request_frame: Cell>>, - pub(crate) input: Cell DispatchEventResult>>>, + pub(crate) input: Cell DispatchEventResult>>>, pub(crate) active_status_change: Cell>>, pub(crate) hovered_status_change: Cell>>, pub(crate) resize: Cell, f32)>>>, @@ -576,8 +577,7 @@ impl PlatformWindow for WindowsWindow { fn resize(&mut self, size: Size) { let hwnd = self.0.hwnd; - let bounds = - crate::bounds(self.bounds().origin, size).to_device_pixels(self.scale_factor()); + let bounds = gpui::bounds(self.bounds().origin, size).to_device_pixels(self.scale_factor()); let rect = calculate_window_rect(bounds, &self.state.border_offset); self.0 @@ -663,15 +663,15 @@ impl PlatformWindow for WindowsWindow { let title; let main_icon; match level { - crate::PromptLevel::Info => { + PromptLevel::Info => { title = windows::core::w!("Info"); main_icon = TD_INFORMATION_ICON; } - crate::PromptLevel::Warning => { + PromptLevel::Warning => { title = windows::core::w!("Warning"); main_icon = TD_WARNING_ICON; } - crate::PromptLevel::Critical => { + PromptLevel::Critical => { title = windows::core::w!("Critical"); main_icon = TD_ERROR_ICON; } @@ -935,9 +935,9 @@ impl PlatformWindow for WindowsWindow { fn update_ime_position(&self, bounds: Bounds) { let scale_factor = self.state.scale_factor.get(); let caret_position = POINT { - x: (bounds.origin.x.0 * scale_factor) as i32, - y: (bounds.origin.y.0 * scale_factor) as i32 - + ((bounds.size.height.0 * scale_factor) as i32 / 2), + x: (bounds.origin.x.as_f32() * scale_factor) as i32, + y: (bounds.origin.y.as_f32() * scale_factor) as i32 + + ((bounds.size.height.as_f32() * scale_factor) as i32 / 2), }; self.0.update_ime_position(self.0.hwnd, caret_position); @@ -1476,12 +1476,12 @@ fn set_non_rude_hwnd(hwnd: HWND, non_rude: bool) { #[cfg(test)] mod tests { use super::ClickState; - use crate::{DevicePixels, MouseButton, point}; + use gpui::{DevicePixels, MouseButton, point}; use std::time::Duration; #[test] fn test_double_click_interval() { - let mut state = ClickState::new(); + let state = ClickState::new(); assert_eq!( state.update(MouseButton::Left, point(DevicePixels(0), DevicePixels(0))), 1 @@ -1509,7 +1509,7 @@ mod tests { #[test] fn test_double_click_spatial_tolerance() { - let mut state = ClickState::new(); + let state = ClickState::new(); assert_eq!( state.update(MouseButton::Left, point(DevicePixels(-3), DevicePixels(0))), 1 diff --git a/crates/gpui/src/platform/windows/wrapper.rs b/crates/gpui_windows/src/wrapper.rs similarity index 100% rename from crates/gpui/src/platform/windows/wrapper.rs rename to crates/gpui_windows/src/wrapper.rs diff --git a/crates/livekit_client/Cargo.toml b/crates/livekit_client/Cargo.toml index a1f1d4e6dfa542fd911a438b09d0073ba2ab3f66..e4c530bbcb3864cf2557f15ef02ddbe7e81852c7 100644 --- a/crates/livekit_client/Cargo.toml +++ b/crates/livekit_client/Cargo.toml @@ -26,7 +26,7 @@ audio.workspace = true collections.workspace = true cpal.workspace = true futures.workspace = true -gpui = { workspace = true, features = ["screen-capture", "x11", "wayland", "windows-manifest"] } +gpui = { workspace = true, features = ["screen-capture", "x11", "wayland"] } gpui_tokio.workspace = true http_client_tls.workspace = true image.workspace = true @@ -63,6 +63,7 @@ objc.workspace = true [dev-dependencies] collections = { workspace = true, features = ["test-support"] } gpui = { workspace = true, features = ["test-support"] } +gpui_platform.workspace = true sha2.workspace = true simplelog.workspace = true diff --git a/crates/livekit_client/examples/test_app.rs b/crates/livekit_client/examples/test_app.rs index 2366d0f8a6cae3be9ed6a6a68b7b8372c74db264..06b9a1402a5c313117dfe559d1f293b6393c6172 100644 --- a/crates/livekit_client/examples/test_app.rs +++ b/crates/livekit_client/examples/test_app.rs @@ -23,7 +23,7 @@ actions!(livekit_client, [Quit]); fn main() { SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); - gpui::Application::new().run(|cx| { + gpui_platform::application().run(|cx| { #[cfg(any(test, feature = "test-support"))] println!("USING TEST LIVEKIT"); diff --git a/crates/markdown/Cargo.toml b/crates/markdown/Cargo.toml index f58df4da86784d626b7428b60133475dc952aa8e..c923d3f704488a5364707486d25181188f74f166 100644 --- a/crates/markdown/Cargo.toml +++ b/crates/markdown/Cargo.toml @@ -38,6 +38,7 @@ assets.workspace = true env_logger.workspace = true fs = {workspace = true, features = ["test-support"]} gpui = { workspace = true, features = ["test-support"] } +gpui_platform.workspace = true language = { workspace = true, features = ["test-support"] } languages = { workspace = true, features = ["load-grammars"] } node_runtime.workspace = true diff --git a/crates/markdown/examples/markdown.rs b/crates/markdown/examples/markdown.rs index c8d67eda038b35e529e6b1a36bc20bf5af757afa..aa132443ee69201f0f1eba7b69c9627aee8f27e7 100644 --- a/crates/markdown/examples/markdown.rs +++ b/crates/markdown/examples/markdown.rs @@ -1,5 +1,5 @@ use assets::Assets; -use gpui::{Application, Entity, KeyBinding, StyleRefinement, WindowOptions, prelude::*, rgb}; +use gpui::{Entity, KeyBinding, StyleRefinement, WindowOptions, prelude::*, rgb}; use language::LanguageRegistry; use markdown::{Markdown, MarkdownElement, MarkdownStyle}; use node_runtime::NodeRuntime; @@ -35,7 +35,7 @@ Remember, markdown processors may have slight differences and extensions, so alw pub fn main() { env_logger::init(); - Application::new().with_assets(Assets).run(|cx| { + gpui_platform::application().with_assets(Assets).run(|cx| { let store = SettingsStore::test(cx); cx.set_global(store); cx.bind_keys([KeyBinding::new("cmd-c", markdown::Copy, None)]); diff --git a/crates/markdown/examples/markdown_as_child.rs b/crates/markdown/examples/markdown_as_child.rs index 775e2a141a849636512264dda2628e28254c8e2b..b25b075dd3cb04ed949e1e30ed724c3b5f3088d1 100644 --- a/crates/markdown/examples/markdown_as_child.rs +++ b/crates/markdown/examples/markdown_as_child.rs @@ -1,5 +1,5 @@ use assets::Assets; -use gpui::{Application, Entity, KeyBinding, Length, StyleRefinement, WindowOptions, rgb}; +use gpui::{Entity, KeyBinding, Length, StyleRefinement, WindowOptions, rgb}; use language::LanguageRegistry; use markdown::{Markdown, MarkdownElement, MarkdownStyle}; use node_runtime::NodeRuntime; @@ -19,7 +19,7 @@ wow so cool pub fn main() { env_logger::init(); - Application::new().with_assets(Assets).run(|cx| { + gpui_platform::application().with_assets(Assets).run(|cx| { let store = SettingsStore::test(cx); cx.set_global(store); cx.bind_keys([KeyBinding::new("cmd-c", markdown::Copy, None)]); diff --git a/crates/project_benchmarks/Cargo.toml b/crates/project_benchmarks/Cargo.toml index fbf2ec73cc53beeffc7be495e3d5d5b8c5dc735c..e449bdb889f22f5184dfaa11c665d69c2894690a 100644 --- a/crates/project_benchmarks/Cargo.toml +++ b/crates/project_benchmarks/Cargo.toml @@ -10,7 +10,8 @@ askpass.workspace = true clap.workspace = true client.workspace = true futures.workspace = true -gpui = { workspace = true, features = ["windows-manifest"] } +gpui.workspace = true +gpui_platform.workspace = true http_client = { workspace = true, features = ["test-support"]} language.workspace = true node_runtime.workspace = true diff --git a/crates/project_benchmarks/src/main.rs b/crates/project_benchmarks/src/main.rs index 6ac14a6dc88f45832ed41d54f66b34f7dc853f24..cdeb8ed780eceaac2dccb1ff2d8066049d134876 100644 --- a/crates/project_benchmarks/src/main.rs +++ b/crates/project_benchmarks/src/main.rs @@ -5,7 +5,7 @@ use askpass::EncryptedPassword; use clap::Parser; use client::{Client, UserStore}; use futures::channel::oneshot; -use gpui::{AppContext as _, Application}; +use gpui::AppContext as _; use http_client::FakeHttpClient; use language::LanguageRegistry; use node_runtime::NodeRuntime; @@ -125,7 +125,7 @@ fn main() -> Result<(), anyhow::Error> { None, ) }?; - Application::headless().run(|cx| { + gpui_platform::headless().run(|cx| { release_channel::init_test(semver::Version::new(0, 0, 0), ReleaseChannel::Dev, cx); settings::init(cx); let client = Client::production(cx); diff --git a/crates/remote_server/Cargo.toml b/crates/remote_server/Cargo.toml index dcefdf80afb649264d23dc1db96c93d392d6489d..fa1aa541c35a516787dd379aa31fc43458586432 100644 --- a/crates/remote_server/Cargo.toml +++ b/crates/remote_server/Cargo.toml @@ -38,7 +38,8 @@ futures.workspace = true git.workspace = true git_hosting_providers.workspace = true git2 = { workspace = true, features = ["vendored-libgit2"] } -gpui = { workspace = true, features = ["windows-manifest"] } +gpui.workspace = true +gpui_platform.workspace = true gpui_tokio.workspace = true http_client.workspace = true image.workspace = true diff --git a/crates/remote_server/src/server.rs b/crates/remote_server/src/server.rs index 234275719494f39298ae3168b63975da64135315..12af7f954927d8d99146c5a6fb1cf5461f0c6bb6 100644 --- a/crates/remote_server/src/server.rs +++ b/crates/remote_server/src/server.rs @@ -449,7 +449,7 @@ pub fn execute_run( init_paths()?; let startup_time = Instant::now(); - let app = gpui::Application::headless(); + let app = gpui_platform::headless(); let pid = std::process::id(); let id = pid.to_string(); app.background_executor() diff --git a/crates/storybook/Cargo.toml b/crates/storybook/Cargo.toml index 1c8dc3611e79fc7cd0f10b49cb6d581611a729db..b1d512559526a00021f5339707c1e24a3110ff15 100644 --- a/crates/storybook/Cargo.toml +++ b/crates/storybook/Cargo.toml @@ -20,6 +20,7 @@ dialoguer = { version = "0.11.0", features = ["fuzzy-select"] } editor.workspace = true fuzzy.workspace = true gpui = { workspace = true, default-features = true } +gpui_platform.workspace = true indoc.workspace = true language.workspace = true log.workspace = true diff --git a/crates/storybook/src/storybook.rs b/crates/storybook/src/storybook.rs index 89cf0155e12d717f92708b5656dc5c5c3ddbc4a5..b8f659146c29162c25b94ca65d05770b4c08921b 100644 --- a/crates/storybook/src/storybook.rs +++ b/crates/storybook/src/storybook.rs @@ -65,45 +65,47 @@ fn main() { }); let theme_name = args.theme.unwrap_or("One Dark".to_string()); - gpui::Application::new().with_assets(Assets).run(move |cx| { - load_embedded_fonts(cx).unwrap(); - - cx.set_global(GlobalColors(Arc::new(Colors::default()))); - - let http_client = ReqwestClient::user_agent("zed_storybook").unwrap(); - cx.set_http_client(Arc::new(http_client)); - - settings::init(cx); - theme::init(theme::LoadThemes::All(Box::new(Assets)), cx); - - let selector = story_selector; - - let mut theme_settings = ThemeSettings::get_global(cx).clone(); - theme_settings.theme = - theme::ThemeSelection::Static(settings::ThemeName(theme_name.into())); - ThemeSettings::override_global(theme_settings, cx); - - editor::init(cx); - init(cx); - load_storybook_keymap(cx); - cx.set_menus(app_menus()); - - let size = size(px(1500.), px(780.)); - let bounds = Bounds::centered(None, size, cx); - let _window = cx.open_window( - WindowOptions { - window_bounds: Some(WindowBounds::Windowed(bounds)), - ..Default::default() - }, - move |window, cx| { - theme::setup_ui_font(window, cx); - - cx.new(|cx| StoryWrapper::new(selector.story(window, cx))) - }, - ); - - cx.activate(true); - }); + gpui_platform::application() + .with_assets(Assets) + .run(move |cx| { + load_embedded_fonts(cx).unwrap(); + + cx.set_global(GlobalColors(Arc::new(Colors::default()))); + + let http_client = ReqwestClient::user_agent("zed_storybook").unwrap(); + cx.set_http_client(Arc::new(http_client)); + + settings::init(cx); + theme::init(theme::LoadThemes::All(Box::new(Assets)), cx); + + let selector = story_selector; + + let mut theme_settings = ThemeSettings::get_global(cx).clone(); + theme_settings.theme = + theme::ThemeSelection::Static(settings::ThemeName(theme_name.into())); + ThemeSettings::override_global(theme_settings, cx); + + editor::init(cx); + init(cx); + load_storybook_keymap(cx); + cx.set_menus(app_menus()); + + let size = size(px(1500.), px(780.)); + let bounds = Bounds::centered(None, size, cx); + let _window = cx.open_window( + WindowOptions { + window_bounds: Some(WindowBounds::Windowed(bounds)), + ..Default::default() + }, + move |window, cx| { + theme::setup_ui_font(window, cx); + + cx.new(|cx| StoryWrapper::new(selector.story(window, cx))) + }, + ); + + cx.activate(true); + }); } #[derive(Clone)] diff --git a/crates/worktree_benchmarks/Cargo.toml b/crates/worktree_benchmarks/Cargo.toml index 29681573adc9da43e579342194b971770f0a8743..7ff9a69eca321ecdd24c3beb9b76f2cc71fae969 100644 --- a/crates/worktree_benchmarks/Cargo.toml +++ b/crates/worktree_benchmarks/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true [dependencies] fs.workspace = true -gpui = { workspace = true, features = ["windows-manifest"] } +gpui_platform.workspace = true settings.workspace = true worktree.workspace = true diff --git a/crates/worktree_benchmarks/src/main.rs b/crates/worktree_benchmarks/src/main.rs index 9dc5a45249b4fa111766946759daebb349531672..079867b5e824919b9ea8a25a1578cfa53d93dda2 100644 --- a/crates/worktree_benchmarks/src/main.rs +++ b/crates/worktree_benchmarks/src/main.rs @@ -4,7 +4,6 @@ use std::{ }; use fs::RealFs; -use gpui::Application; use settings::WorktreeId; use worktree::Worktree; @@ -15,7 +14,7 @@ fn main() { ); return; }; - let app = Application::headless(); + let app = gpui_platform::headless(); app.run(|cx| { settings::init(cx); diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 7aa6bc29e1393067d2111be5477b6b18c09076a5..548bdb0357dd393fb63b53867f8cbbdc11c6a3ce 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -15,7 +15,7 @@ workspace = true tracy = ["ztracing/tracy"] test-support = [ "gpui/test-support", - "gpui/screen-capture", + "gpui_platform/screen-capture", "dep:image", "dep:semver", "workspace/test-support", @@ -29,7 +29,7 @@ test-support = [ ] visual-tests = [ "gpui/test-support", - "gpui/screen-capture", + "gpui_platform/screen-capture", "dep:image", "dep:semver", "dep:tempfile", @@ -120,9 +120,8 @@ system_specs.workspace = true gpui = { workspace = true, features = [ "wayland", "x11", - "font-kit", - "windows-manifest", ] } +gpui_platform = {workspace = true, features=["screen-capture", "font-kit", "wayland", "x11"]} image = { workspace = true, optional = true } semver = { workspace = true, optional = true } tempfile = { workspace = true, optional = true } @@ -241,7 +240,7 @@ ashpd.workspace = true call = { workspace = true, features = ["test-support"] } dap = { workspace = true, features = ["test-support"] } editor = { workspace = true, features = ["test-support"] } -gpui = { workspace = true, features = ["test-support", "screen-capture"] } +gpui = { workspace = true, features = ["test-support"] } image_viewer = { workspace = true, features = ["test-support"] } itertools.workspace = true language = { workspace = true, features = ["test-support"] } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 68b0a78fca658a2dccd8f6e1e667bf8631cad1c7..d2ccf7b04c3a14efdefa2ca6dbfc0db138d48b02 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -22,6 +22,7 @@ use futures::{StreamExt, channel::oneshot, future}; use git::GitHostingProviderRegistry; use git_ui::clone::clone_and_open; use gpui::{App, AppContext, Application, AsyncApp, Focusable as _, QuitMode, UpdateGlobal as _}; +use gpui_platform; use gpui_tokio::Tokio; use language::LanguageRegistry; @@ -98,7 +99,7 @@ fn files_not_created_on_launch(errors: HashMap>) { .collect::>().join("\n\n"); eprintln!("{message}: {error_details}"); - Application::new() + Application::with_platform(gpui_platform::current_platform(false)) .with_quit_mode(QuitMode::Explicit) .run(move |cx| { if let Ok(window) = cx.open_window(gpui::WindowOptions::default(), |_, cx| { @@ -297,7 +298,8 @@ fn main() { #[cfg(windows)] check_for_conpty_dll(); - let app = Application::new().with_assets(Assets); + let app = + Application::with_platform(gpui_platform::current_platform(false)).with_assets(Assets); let system_id = app.background_executor().spawn(system_id()); let installation_id = app.background_executor().spawn(installation_id()); diff --git a/crates/zed/src/visual_test_runner.rs b/crates/zed/src/visual_test_runner.rs index ba6d18a80a102f40a4f62bba992fab7639987fc1..36d23ec114e6b52048fbc595917beef20a0dae69 100644 --- a/crates/zed/src/visual_test_runner.rs +++ b/crates/zed/src/visual_test_runner.rs @@ -150,7 +150,10 @@ fn main() { fn run_visual_tests(project_path: PathBuf, update_baseline: bool) -> Result<()> { // Create the visual test context with deterministic task scheduling // Use real Assets so that SVG icons render properly - let mut cx = VisualTestAppContext::with_asset_source(Arc::new(Assets)); + let mut cx = VisualTestAppContext::with_asset_source( + gpui_platform::current_platform(false), + Arc::new(Assets), + ); // Load embedded fonts (IBM Plex Sans, Lilex, etc.) so UI renders with correct fonts cx.update(|cx| { diff --git a/crates/zed/src/zed/visual_tests.rs b/crates/zed/src/zed/visual_tests.rs index 5f725d9fd844563e6fedbcfa669b65f2b7346061..0aab800eaf0e8664a875751d0b1df1abce98c945 100644 --- a/crates/zed/src/zed/visual_tests.rs +++ b/crates/zed/src/zed/visual_tests.rs @@ -426,7 +426,7 @@ mod tests { #[test] #[ignore] fn test_visual_test_smoke() { - let mut cx = VisualTestAppContext::new(); + let mut cx = VisualTestAppContext::new(gpui_platform::current_platform(false)); let _window = cx .open_offscreen_window_default(|_, cx| cx.new(|_| Empty)) @@ -438,7 +438,7 @@ mod tests { #[test] #[ignore] fn test_workspace_opens() { - let mut cx = VisualTestAppContext::new(); + let mut cx = VisualTestAppContext::new(gpui_platform::current_platform(false)); let app_state = init_visual_test(&mut cx); smol::block_on(async { @@ -479,7 +479,7 @@ mod tests { #[test] #[ignore] fn test_workspace_screenshot() { - let mut cx = VisualTestAppContext::new(); + let mut cx = VisualTestAppContext::new(gpui_platform::current_platform(false)); let app_state = init_visual_test(&mut cx); smol::block_on(async { diff --git a/typos.toml b/typos.toml index f2240ad01b84c59cf3ce4cb538f5b0b19bfe343e..6f76cc75d25add39d841c07bbde82f93514adac5 100644 --- a/typos.toml +++ b/typos.toml @@ -36,10 +36,10 @@ extend-exclude = [ "extensions/proto/extension.toml", "extensions/proto/src/language_servers/protols.rs", # Windows likes its abbreviations. - "crates/gpui/src/platform/windows/directx_renderer.rs", - "crates/gpui/src/platform/windows/events.rs", - "crates/gpui/src/platform/windows/direct_write.rs", - "crates/gpui/src/platform/windows/window.rs", + "crates/gpui_windows/src/directx_renderer.rs", + "crates/gpui_windows/src/events.rs", + "crates/gpui_windows/src/direct_write.rs", + "crates/gpui_windows/src/window.rs", # Some typos in the base mdBook CSS. "docs/theme/css/", # Spellcheck triggers on `|Fixe[sd]|` regex part. @@ -57,7 +57,7 @@ extend-exclude = [ # Some multibuffer test cases have word fragments that register as typos "crates/multi_buffer/src/multi_buffer_tests.rs", # Macos apis - "crates/gpui/src/platform/mac/dispatcher.rs", + "crates/gpui_macos/src/dispatcher.rs", # Tests contain partially incomplete words (by design) "crates/edit_prediction_cli/src/split_commit.rs", # Eval examples contain intentionally partial words (e.g. "secur" for "secure")