1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
//! The [`Platform`] trait implemented by each platform backend.
//!
//! `gpui` drives an application through a `dyn Platform`; backends
//! (`gpui_macos`, `gpui_linux`, `gpui_windows`, `gpui_web`) implement it
//! without depending on the framework itself.
use crate::{
ActivityGuard, AppLifecyclePhase, BackgroundExecutor, ClipboardItem, ClipboardReadError,
CursorStyle, ForegroundExecutor, GpuAdapterInfo, GpuPreference, MenuCommandId,
PathPromptOptions, PlatformDisplay, PlatformGestures, PlatformKeyboardLayout,
PlatformKeyboardMapper, PlatformMenu, PlatformMenuItem, PlatformWindow, ScreenCaptureSource,
SystemNotification, SystemNotificationResponse, Task, ThermalState, WindowAppearance,
WindowButtonLayout, WindowId, WindowParams,
};
use anyhow::Result;
use futures::channel::oneshot;
use gpui_engine::{DmaBufCapabilities, PlatformTextSystem};
use smallvec::SmallVec;
use std::{
ffi::OsString,
path::{Path, PathBuf},
rc::Rc,
sync::Arc,
};
// TODO(jk): return an enum instead of a string
/// Return which compositor we're guessing we'll use.
/// Does not attempt to connect to the given compositor.
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
#[inline]
pub fn guess_compositor() -> &'static str {
if std::env::var_os("ZED_HEADLESS").is_some() {
return "Headless";
}
#[cfg(feature = "wayland")]
let wayland_display = std::env::var_os("WAYLAND_DISPLAY");
#[cfg(not(feature = "wayland"))]
let wayland_display: Option<std::ffi::OsString> = None;
#[cfg(feature = "x11")]
let x11_display = std::env::var_os("DISPLAY");
#[cfg(not(feature = "x11"))]
let x11_display: Option<std::ffi::OsString> = None;
let use_wayland = wayland_display.is_some_and(|display| !display.is_empty());
let use_x11 = x11_display.is_some_and(|display| !display.is_empty());
if use_wayland {
"Wayland"
} else if use_x11 {
"X11"
} else {
"Headless"
}
}
#[expect(missing_docs)]
pub trait Platform: 'static {
fn background_executor(&self) -> BackgroundExecutor;
fn foreground_executor(&self) -> ForegroundExecutor;
fn text_system(&self) -> Arc<dyn PlatformTextSystem>;
fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>);
fn quit(&self);
fn restart(&self, binary_path: Option<PathBuf>, arguments: Vec<OsString>);
fn activate(&self, ignoring_other_apps: bool);
fn hide(&self);
fn hide_other_apps(&self);
fn unhide_other_apps(&self);
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>>;
fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>>;
fn active_window(&self) -> Option<WindowId>;
fn window_stack(&self) -> Option<Vec<WindowId>> {
None
}
fn is_screen_capture_supported(&self) -> bool {
false
}
fn screen_capture_sources(
&self,
) -> oneshot::Receiver<anyhow::Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
let (sources_tx, sources_rx) = oneshot::channel();
sources_tx
.send(Err(anyhow::anyhow!(
"gpui was compiled without the screen-capture feature"
)))
.ok();
sources_rx
}
fn open_window(
&self,
handle: WindowId,
options: WindowParams,
) -> anyhow::Result<Box<dyn PlatformWindow>>;
/// Returns the appearance of the application's windows.
fn window_appearance(&self) -> WindowAppearance;
/// Overrides the appearance (light/dark) applied to the app's windows, independent
/// of the OS-wide setting. Pass `None` to clear the override and follow the system
/// again. The override is reflected by [`Platform::window_appearance`].
///
/// Currently only implemented on macOS, where it sets `NSApplication.appearance` so
/// the native window chrome (the window border and titlebar) of every window matches
/// a dark app theme even when the system is in light mode (or vice versa). A no-op on
/// other platforms.
fn set_window_appearance(&self, _appearance: Option<WindowAppearance>) {}
/// States which GPU the application prefers the renderer to run on.
///
/// The device is process-wide and chosen before the first window, so this has to be set before
/// the application runs. A backend that cannot choose ignores it. See decision `0008` in the
/// project record, `decisions/0008-gpu-preference-and-enumeration.md`.
fn set_gpu_preference(&self, _preference: GpuPreference) {}
/// The adapters the application could render on.
///
/// Enumeration happens without creating a device, so this is safe to call before
/// [`run`](Self::run) and is what a preferences panel reads; it is also the list a
/// [`GpuPreference::Custom`] selector chooses from. The order is the platform's; a caller that
/// wants a particular one states a preference rather than indexing into this list.
///
/// A backend that cannot enumerate returns **one** synthesized entry rather than an empty list:
/// the identity contract is that every reported adapter has a permanent part and a session, and
/// a single-GPU platform should still answer "which GPU" with "the GPU".
fn enumerate_gpus(&self) -> Vec<GpuAdapterInfo> {
vec![GpuAdapterInfo::single()]
}
/// What the renderer can import as a dma-buf surface, once it has a device.
///
/// Answered on the device the renderer already made — no device is created — and `None` before
/// the first window or on a platform whose surfaces are not dma-bufs. A producer uses it to
/// choose a layout rather than discover a refusal at import time.
fn dmabuf_capabilities(&self) -> Option<DmaBufCapabilities> {
None
}
/// The adapter the renderer actually chose, once it has chosen one.
///
/// The device is process-wide and selected before the first window, so the answer is `None`
/// until a window has created one; after that it is the adapter every window draws through. A
/// platform that cannot report it returns `None`.
fn active_gpu(&self) -> Option<GpuAdapterInfo> {
None
}
/// Returns the window button layout configuration when supported.
fn button_layout(&self) -> Option<WindowButtonLayout> {
None
}
fn open_url(&self, url: &str);
fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>);
fn register_url_scheme(&self, url: &str) -> Task<Result<()>>;
fn prompt_for_paths(
&self,
options: PathPromptOptions,
) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>>;
fn prompt_for_new_path(
&self,
directory: &Path,
suggested_name: Option<&str>,
) -> oneshot::Receiver<Result<Option<PathBuf>>>;
fn can_select_mixed_files_and_dirs(&self) -> bool;
fn reveal_path(&self, path: &Path);
fn open_with_system(&self, path: &Path);
fn on_quit(&self, callback: Box<dyn FnMut() -> bool>);
fn on_reopen(&self, callback: Box<dyn FnMut()>);
/// Registers the callback invoked when the system is about to sleep.
fn on_system_sleep(&self, callback: Box<dyn FnMut()>);
/// Registers the callback invoked when the system resumes from sleep.
fn on_system_wake(&self, callback: Box<dyn FnMut()>);
// Mobile platform methods. On mobile the OS owns the application
// lifecycle: apps are backgrounded, foregrounded, and killed at the
// system's discretion, and must react rather than decide.
/// Registers a callback invoked whenever the application's lifecycle
/// phase changes. See [`AppLifecyclePhase`] for the phase vocabulary and
/// its mapping onto iOS and Android.
///
/// Desktop platforms never invoke this.
fn on_app_lifecycle(&self, _callback: Box<dyn FnMut(AppLifecyclePhase)>) {}
/// Registers a callback invoked when the OS signals memory pressure
/// (iOS `didReceiveMemoryWarning`, Android `onTrimMemory`).
///
/// Desktop platforms never invoke this.
fn on_memory_warning(&self, _callback: Box<dyn FnMut()>) {}
/// The platform's gesture recognition services, if it provides any
/// beyond gpui's portable recognizers. See
/// [`PlatformGestures`](crate::PlatformGestures).
fn gestures(&self) -> Option<Rc<dyn PlatformGestures>> {
None
}
fn set_menus(&self, menus: Vec<PlatformMenu>);
fn set_dock_menu(&self, menu: Vec<PlatformMenuItem>);
fn perform_dock_menu_action(&self, _action: usize) {}
fn add_recent_document(&self, _path: &Path) {}
fn update_jump_list(
&self,
_menus: Vec<PlatformMenuItem>,
_entries: Vec<SmallVec<[PathBuf; 2]>>,
) -> Task<Vec<SmallVec<[PathBuf; 2]>>> {
Task::ready(Vec::new())
}
fn on_app_menu_action(&self, callback: Box<dyn FnMut(MenuCommandId)>);
fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>);
fn on_validate_app_menu_command(&self, callback: Box<dyn FnMut(MenuCommandId) -> bool>);
fn thermal_state(&self) -> ThermalState;
fn on_thermal_state_change(&self, callback: Box<dyn FnMut()>);
fn prevent_idle_sleep(&self, reason: &str) -> Task<Result<ActivityGuard>>;
/// Sets the application's process-wide identity and user-visible name.
///
/// The identifier is used for platform identity mechanisms such as the
/// Windows AppUserModelID. The name is used wherever the operating system
/// presents the application to the user. Call this once, early in startup,
/// before opening windows or posting notifications.
fn set_app_identity(&self, identifier: &str, name: &str) {
_ = (identifier, name);
}
/// Posts a notification to the operating system's notification center.
///
/// Posting a notification whose [`SystemNotification::tag`] matches an
/// earlier one replaces that notification where the platform supports it.
/// No-op on platforms without notification support, or when delivery is
/// unavailable (e.g. authorization was denied).
fn show_system_notification(&self, notification: SystemNotification) {
_ = notification;
}
/// Removes the delivered or pending notification with this tag.
///
/// Best-effort: some platforms cannot retract a notification once shown,
/// in which case it ages out of the notification center on its own.
fn dismiss_system_notification(&self, tag: &str) {
_ = tag;
}
/// Registers the callback invoked when the user activates a system
/// notification, either by clicking its body or one of its action
/// buttons.
///
/// Implementations must invoke the callback on the main thread.
fn on_system_notification_response(
&self,
callback: Box<dyn FnMut(SystemNotificationResponse)>,
) {
_ = callback;
}
fn compositor_name(&self) -> &'static str {
""
}
fn app_path(&self) -> Result<PathBuf>;
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf>;
fn set_cursor_style(&self, style: CursorStyle);
/// Hides the mouse cursor until the user moves the mouse over one of
/// this application's windows.
fn hide_cursor_until_mouse_moves(&self);
/// Returns whether the mouse cursor is currently visible.
fn is_cursor_visible(&self) -> bool;
fn should_auto_hide_scrollbars(&self) -> bool;
fn read_from_clipboard(&self) -> Option<ClipboardItem>;
fn write_to_clipboard(&self, item: ClipboardItem);
/// Reads the clipboard, resolving once its contents are available.
///
/// Most platforms read synchronously and return a ready task. Platforms
/// whose clipboard access is inherently asynchronous and permission-gated
/// (e.g. the browser's async clipboard API) override this method; on those
/// platforms [`Platform::read_from_clipboard`] cannot return the clipboard
/// contents, so callers that can await should prefer this method.
fn read_from_clipboard_async(&self) -> Task<Result<Option<ClipboardItem>, ClipboardReadError>> {
Task::ready(Ok(self.read_from_clipboard()))
}
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn read_from_primary(&self) -> Option<ClipboardItem>;
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn write_to_primary(&self, item: ClipboardItem);
#[cfg(target_os = "macos")]
fn read_from_find_pasteboard(&self) -> Option<ClipboardItem>;
#[cfg(target_os = "macos")]
fn write_to_find_pasteboard(&self, item: ClipboardItem);
fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Task<Result<()>>;
fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>>;
fn delete_credentials(&self, url: &str) -> Task<Result<()>>;
fn keyboard_layout(&self) -> Box<dyn PlatformKeyboardLayout>;
fn keyboard_mapper(&self) -> Rc<dyn PlatformKeyboardMapper>;
fn on_keyboard_layout_change(&self, callback: Box<dyn FnMut()>);
}