1use crate::{
8 ActivityGuard, AppLifecyclePhase, BackgroundExecutor, ClipboardItem, ClipboardReadError,
9 CursorStyle, ForegroundExecutor, GpuAdapterInfo, GpuPreference, MenuCommandId,
10 PathPromptOptions, PlatformDisplay, PlatformGestures, PlatformKeyboardLayout,
11 PlatformKeyboardMapper, PlatformMenu, PlatformMenuItem, PlatformWindow, ScreenCaptureSource,
12 SystemNotification, SystemNotificationResponse, Task, ThermalState, WindowAppearance,
13 WindowButtonLayout, WindowId, WindowParams,
14};
15use anyhow::Result;
16use futures::channel::oneshot;
17use gpui_engine::{DmaBufCapabilities, PlatformTextSystem};
18use smallvec::SmallVec;
19use std::{
20 ffi::OsString,
21 path::{Path, PathBuf},
22 rc::Rc,
23 sync::Arc,
24};
25
26#[cfg(any(target_os = "linux", target_os = "freebsd"))]
30#[inline]
31pub fn guess_compositor() -> &'static str {
32 if std::env::var_os("ZED_HEADLESS").is_some() {
33 return "Headless";
34 }
35
36 #[cfg(feature = "wayland")]
37 let wayland_display = std::env::var_os("WAYLAND_DISPLAY");
38 #[cfg(not(feature = "wayland"))]
39 let wayland_display: Option<std::ffi::OsString> = None;
40
41 #[cfg(feature = "x11")]
42 let x11_display = std::env::var_os("DISPLAY");
43 #[cfg(not(feature = "x11"))]
44 let x11_display: Option<std::ffi::OsString> = None;
45
46 let use_wayland = wayland_display.is_some_and(|display| !display.is_empty());
47 let use_x11 = x11_display.is_some_and(|display| !display.is_empty());
48
49 if use_wayland {
50 "Wayland"
51 } else if use_x11 {
52 "X11"
53 } else {
54 "Headless"
55 }
56}
57
58#[expect(missing_docs)]
59pub trait Platform: 'static {
60 fn background_executor(&self) -> BackgroundExecutor;
61 fn foreground_executor(&self) -> ForegroundExecutor;
62 fn text_system(&self) -> Arc<dyn PlatformTextSystem>;
63
64 fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>);
65 fn quit(&self);
66 fn restart(&self, binary_path: Option<PathBuf>, arguments: Vec<OsString>);
67 fn activate(&self, ignoring_other_apps: bool);
68 fn hide(&self);
69 fn hide_other_apps(&self);
70 fn unhide_other_apps(&self);
71
72 fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>>;
73 fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>>;
74 fn active_window(&self) -> Option<WindowId>;
75 fn window_stack(&self) -> Option<Vec<WindowId>> {
76 None
77 }
78
79 fn is_screen_capture_supported(&self) -> bool {
80 false
81 }
82
83 fn screen_capture_sources(
84 &self,
85 ) -> oneshot::Receiver<anyhow::Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
86 let (sources_tx, sources_rx) = oneshot::channel();
87 sources_tx
88 .send(Err(anyhow::anyhow!(
89 "gpui was compiled without the screen-capture feature"
90 )))
91 .ok();
92 sources_rx
93 }
94
95 fn open_window(
96 &self,
97 handle: WindowId,
98 options: WindowParams,
99 ) -> anyhow::Result<Box<dyn PlatformWindow>>;
100
101 fn window_appearance(&self) -> WindowAppearance;
103
104 fn set_window_appearance(&self, _appearance: Option<WindowAppearance>) {}
113
114 fn set_gpu_preference(&self, _preference: GpuPreference) {}
120
121 fn enumerate_gpus(&self) -> Vec<GpuAdapterInfo> {
132 vec![GpuAdapterInfo::single()]
133 }
134
135 fn dmabuf_capabilities(&self) -> Option<DmaBufCapabilities> {
141 None
142 }
143
144 fn active_gpu(&self) -> Option<GpuAdapterInfo> {
150 None
151 }
152
153 fn button_layout(&self) -> Option<WindowButtonLayout> {
155 None
156 }
157
158 fn open_url(&self, url: &str);
159 fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>);
160 fn register_url_scheme(&self, url: &str) -> Task<Result<()>>;
161
162 fn prompt_for_paths(
163 &self,
164 options: PathPromptOptions,
165 ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>>;
166 fn prompt_for_new_path(
167 &self,
168 directory: &Path,
169 suggested_name: Option<&str>,
170 ) -> oneshot::Receiver<Result<Option<PathBuf>>>;
171 fn can_select_mixed_files_and_dirs(&self) -> bool;
172 fn reveal_path(&self, path: &Path);
173 fn open_with_system(&self, path: &Path);
174
175 fn on_quit(&self, callback: Box<dyn FnMut() -> bool>);
176 fn on_reopen(&self, callback: Box<dyn FnMut()>);
177 fn on_system_sleep(&self, callback: Box<dyn FnMut()>);
179 fn on_system_wake(&self, callback: Box<dyn FnMut()>);
181
182 fn on_app_lifecycle(&self, _callback: Box<dyn FnMut(AppLifecyclePhase)>) {}
192
193 fn on_memory_warning(&self, _callback: Box<dyn FnMut()>) {}
198
199 fn gestures(&self) -> Option<Rc<dyn PlatformGestures>> {
203 None
204 }
205
206 fn set_menus(&self, menus: Vec<PlatformMenu>);
207
208 fn set_dock_menu(&self, menu: Vec<PlatformMenuItem>);
209 fn perform_dock_menu_action(&self, _action: usize) {}
210 fn add_recent_document(&self, _path: &Path) {}
211 fn update_jump_list(
212 &self,
213 _menus: Vec<PlatformMenuItem>,
214 _entries: Vec<SmallVec<[PathBuf; 2]>>,
215 ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> {
216 Task::ready(Vec::new())
217 }
218 fn on_app_menu_action(&self, callback: Box<dyn FnMut(MenuCommandId)>);
219 fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>);
220 fn on_validate_app_menu_command(&self, callback: Box<dyn FnMut(MenuCommandId) -> bool>);
221
222 fn thermal_state(&self) -> ThermalState;
223 fn on_thermal_state_change(&self, callback: Box<dyn FnMut()>);
224 fn prevent_idle_sleep(&self, reason: &str) -> Task<Result<ActivityGuard>>;
225
226 fn set_app_identity(&self, identifier: &str, name: &str) {
233 _ = (identifier, name);
234 }
235
236 fn show_system_notification(&self, notification: SystemNotification) {
243 _ = notification;
244 }
245
246 fn dismiss_system_notification(&self, tag: &str) {
251 _ = tag;
252 }
253
254 fn on_system_notification_response(
260 &self,
261 callback: Box<dyn FnMut(SystemNotificationResponse)>,
262 ) {
263 _ = callback;
264 }
265
266 fn compositor_name(&self) -> &'static str {
267 ""
268 }
269 fn app_path(&self) -> Result<PathBuf>;
270 fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf>;
271
272 fn set_cursor_style(&self, style: CursorStyle);
273
274 fn hide_cursor_until_mouse_moves(&self);
277
278 fn is_cursor_visible(&self) -> bool;
280
281 fn should_auto_hide_scrollbars(&self) -> bool;
282
283 fn read_from_clipboard(&self) -> Option<ClipboardItem>;
284 fn write_to_clipboard(&self, item: ClipboardItem);
285
286 fn read_from_clipboard_async(&self) -> Task<Result<Option<ClipboardItem>, ClipboardReadError>> {
294 Task::ready(Ok(self.read_from_clipboard()))
295 }
296
297 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
298 fn read_from_primary(&self) -> Option<ClipboardItem>;
299 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
300 fn write_to_primary(&self, item: ClipboardItem);
301
302 #[cfg(target_os = "macos")]
303 fn read_from_find_pasteboard(&self) -> Option<ClipboardItem>;
304 #[cfg(target_os = "macos")]
305 fn write_to_find_pasteboard(&self, item: ClipboardItem);
306
307 fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Task<Result<()>>;
308 fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>>;
309 fn delete_credentials(&self, url: &str) -> Task<Result<()>>;
310
311 fn keyboard_layout(&self) -> Box<dyn PlatformKeyboardLayout>;
312 fn keyboard_mapper(&self) -> Rc<dyn PlatformKeyboardMapper>;
313 fn on_keyboard_layout_change(&self, callback: Box<dyn FnMut()>);
314}