1use crate::{
8 ActivityGuard, AppLifecyclePhase, BackgroundExecutor, ClipboardItem, ClipboardReadError,
9 CursorStyle, ForegroundExecutor, MenuCommandId, PathPromptOptions, PlatformDisplay,
10 PlatformGestures, PlatformKeyboardLayout, PlatformKeyboardMapper, PlatformMenu,
11 PlatformMenuItem, PlatformWindow, ScreenCaptureSource, SystemNotification,
12 SystemNotificationResponse, Task, ThermalState, WindowAppearance, WindowButtonLayout, WindowId,
13 WindowParams,
14};
15use anyhow::Result;
16use futures::channel::oneshot;
17use gpui_engine::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 button_layout(&self) -> Option<WindowButtonLayout> {
116 None
117 }
118
119 fn open_url(&self, url: &str);
120 fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>);
121 fn register_url_scheme(&self, url: &str) -> Task<Result<()>>;
122
123 fn prompt_for_paths(
124 &self,
125 options: PathPromptOptions,
126 ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>>;
127 fn prompt_for_new_path(
128 &self,
129 directory: &Path,
130 suggested_name: Option<&str>,
131 ) -> oneshot::Receiver<Result<Option<PathBuf>>>;
132 fn can_select_mixed_files_and_dirs(&self) -> bool;
133 fn reveal_path(&self, path: &Path);
134 fn open_with_system(&self, path: &Path);
135
136 fn on_quit(&self, callback: Box<dyn FnMut() -> bool>);
137 fn on_reopen(&self, callback: Box<dyn FnMut()>);
138 fn on_system_sleep(&self, callback: Box<dyn FnMut()>);
140 fn on_system_wake(&self, callback: Box<dyn FnMut()>);
142
143 fn on_app_lifecycle(&self, _callback: Box<dyn FnMut(AppLifecyclePhase)>) {}
153
154 fn on_memory_warning(&self, _callback: Box<dyn FnMut()>) {}
159
160 fn gestures(&self) -> Option<Rc<dyn PlatformGestures>> {
164 None
165 }
166
167 fn set_menus(&self, menus: Vec<PlatformMenu>);
168
169 fn set_dock_menu(&self, menu: Vec<PlatformMenuItem>);
170 fn perform_dock_menu_action(&self, _action: usize) {}
171 fn add_recent_document(&self, _path: &Path) {}
172 fn update_jump_list(
173 &self,
174 _menus: Vec<PlatformMenuItem>,
175 _entries: Vec<SmallVec<[PathBuf; 2]>>,
176 ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> {
177 Task::ready(Vec::new())
178 }
179 fn on_app_menu_action(&self, callback: Box<dyn FnMut(MenuCommandId)>);
180 fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>);
181 fn on_validate_app_menu_command(&self, callback: Box<dyn FnMut(MenuCommandId) -> bool>);
182
183 fn thermal_state(&self) -> ThermalState;
184 fn on_thermal_state_change(&self, callback: Box<dyn FnMut()>);
185 fn prevent_idle_sleep(&self, reason: &str) -> Task<Result<ActivityGuard>>;
186
187 fn set_app_identity(&self, identifier: &str, name: &str) {
194 _ = (identifier, name);
195 }
196
197 fn show_system_notification(&self, notification: SystemNotification) {
204 _ = notification;
205 }
206
207 fn dismiss_system_notification(&self, tag: &str) {
212 _ = tag;
213 }
214
215 fn on_system_notification_response(
221 &self,
222 callback: Box<dyn FnMut(SystemNotificationResponse)>,
223 ) {
224 _ = callback;
225 }
226
227 fn compositor_name(&self) -> &'static str {
228 ""
229 }
230 fn app_path(&self) -> Result<PathBuf>;
231 fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf>;
232
233 fn set_cursor_style(&self, style: CursorStyle);
234
235 fn hide_cursor_until_mouse_moves(&self);
238
239 fn is_cursor_visible(&self) -> bool;
241
242 fn should_auto_hide_scrollbars(&self) -> bool;
243
244 fn read_from_clipboard(&self) -> Option<ClipboardItem>;
245 fn write_to_clipboard(&self, item: ClipboardItem);
246
247 fn read_from_clipboard_async(&self) -> Task<Result<Option<ClipboardItem>, ClipboardReadError>> {
255 Task::ready(Ok(self.read_from_clipboard()))
256 }
257
258 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
259 fn read_from_primary(&self) -> Option<ClipboardItem>;
260 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
261 fn write_to_primary(&self, item: ClipboardItem);
262
263 #[cfg(target_os = "macos")]
264 fn read_from_find_pasteboard(&self) -> Option<ClipboardItem>;
265 #[cfg(target_os = "macos")]
266 fn write_to_find_pasteboard(&self, item: ClipboardItem);
267
268 fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Task<Result<()>>;
269 fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>>;
270 fn delete_credentials(&self, url: &str) -> Task<Result<()>>;
271
272 fn keyboard_layout(&self) -> Box<dyn PlatformKeyboardLayout>;
273 fn keyboard_mapper(&self) -> Rc<dyn PlatformKeyboardMapper>;
274 fn on_keyboard_layout_change(&self, callback: Box<dyn FnMut()>);
275}