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
// Copyright 2014-2021 The winit contributors
// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
#![cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
use std::{os::raw::c_int, sync::Arc};
// XConnection utilities
#[doc(hidden)]
pub use crate::platform_impl::x11;
pub use crate::platform_impl::{hit_test, EventLoop as UnixEventLoop};
use crate::{
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
platform_impl::{x11::xdisplay::XError, Parent},
window::{Window, WindowBuilder},
};
use self::x11::xdisplay::XConnection;
/// Additional methods on `EventLoop` that are specific to Unix.
pub trait EventLoopBuilderExtUnix {
/// Whether to allow the event loop to be created off of the main thread.
///
/// By default, the window is only allowed to be created on the main
/// thread, to make platform compatibility easier.
///
/// # `Window` caveats
///
/// Note that any `Window` created on the new thread will be destroyed when the thread
/// terminates. Attempting to use a `Window` after its parent thread terminates has
/// unspecified, although explicitly not undefined, behavior.
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
}
impl<T> EventLoopBuilderExtUnix for EventLoopBuilder<T> {
#[inline]
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
self.platform_specific.any_thread = any_thread;
self
}
}
/// Additional methods on `Window` that are specific to Unix.
pub trait WindowExtUnix {
/// Returns the `gtk::ApplicatonWindow` from gtk crate that is used by this window.
fn gtk_window(&self) -> >k::ApplicationWindow;
/// Returns the vertical `gtk::Box` that is added by default as the sole child of this window.
/// Returns `None` if the default vertical `gtk::Box` creation was disabled by [`WindowBuilderExtUnix::with_default_vbox`].
fn default_vbox(&self) -> Option<>k::Box>;
/// Whether to show the window icon in the taskbar or not.
fn set_skip_taskbar(&self, skip: bool);
}
impl WindowExtUnix for Window {
fn gtk_window(&self) -> >k::ApplicationWindow {
&self.window.window
}
fn default_vbox(&self) -> Option<>k::Box> {
self.window.default_vbox.as_ref()
}
fn set_skip_taskbar(&self, skip: bool) {
self.window.set_skip_taskbar(skip);
}
}
pub trait WindowBuilderExtUnix {
/// Whether to create the window icon with the taskbar icon or not.
fn with_skip_taskbar(self, skip: bool) -> WindowBuilder;
/// Set this window as a transient dialog for `parent`
/// <https://gtk-rs.org/gtk3-rs/stable/latest/docs/gdk/struct.Window.html#method.set_transient_for>
fn with_transient_for(self, parent: gtk::ApplicationWindow) -> WindowBuilder;
/// Whether to enable or disable the internal draw for transparent window.
///
/// When tranparent attribute is enabled, we will call `connect_draw` and draw a transparent background.
/// For anyone who wants to draw the background themselves, set this to `false`.
/// Default is `true`.
fn with_transparent_draw(self, draw: bool) -> WindowBuilder;
/// Whether to enable or disable the double buffered rendering of the window.
///
/// Default is `true`.
fn with_double_buffered(self, double_buffered: bool) -> WindowBuilder;
/// Whether to enable the rgba visual for the window.
///
/// Default is `false` but is always `true` if [`WindowAttributes::transparent`](crate::window::WindowAttributes::transparent) is `true`
fn with_rgba_visual(self, rgba_visual: bool) -> WindowBuilder;
/// Wether to set this window as app paintable
///
/// <https://docs.gtk.org/gtk3/method.Widget.set_app_paintable.html>
///
/// Default is `false` but is always `true` if [`WindowAttributes::transparent`](crate::window::WindowAttributes::transparent) is `true`
fn with_app_paintable(self, app_paintable: bool) -> WindowBuilder;
/// Whether to set cursor moved event. Cursor event is suited for native GUI frameworks and
/// games. But it can block gtk's own pipeline occasionally. Turn this off can help Gtk looks
/// smoother.
///
/// Default is `true`.
fn with_cursor_moved_event(self, cursor_moved: bool) -> WindowBuilder;
/// Whether to create a vertical `gtk::Box` and add it as the sole child of this window.
/// Created by default.
fn with_default_vbox(self, add: bool) -> WindowBuilder;
}
impl WindowBuilderExtUnix for WindowBuilder {
fn with_skip_taskbar(mut self, skip: bool) -> WindowBuilder {
self.platform_specific.skip_taskbar = skip;
self
}
fn with_transient_for(mut self, parent: gtk::ApplicationWindow) -> WindowBuilder {
self.platform_specific.parent = Parent::ChildOf(parent);
self
}
fn with_transparent_draw(mut self, draw: bool) -> WindowBuilder {
self.platform_specific.auto_transparent = draw;
self
}
fn with_double_buffered(mut self, double_buffered: bool) -> WindowBuilder {
self.platform_specific.double_buffered = double_buffered;
self
}
fn with_rgba_visual(mut self, rgba_visual: bool) -> WindowBuilder {
self.platform_specific.rgba_visual = rgba_visual;
self
}
fn with_app_paintable(mut self, app_paintable: bool) -> WindowBuilder {
self.platform_specific.app_paintable = app_paintable;
self
}
fn with_cursor_moved_event(mut self, cursor_moved: bool) -> WindowBuilder {
self.platform_specific.cursor_moved = cursor_moved;
self
}
fn with_default_vbox(mut self, add: bool) -> WindowBuilder {
self.platform_specific.default_vbox = add;
self
}
}
/// Additional methods on `EventLoopWindowTarget` that are specific to Unix.
pub trait EventLoopWindowTargetExtUnix {
/// True if the `EventLoopWindowTarget` uses Wayland.
fn is_wayland(&self) -> bool;
/// True if the `EventLoopWindowTarget` uses X11.
fn is_x11(&self) -> bool;
fn xlib_xconnection(&self) -> Option<Arc<XConnection>>;
// /// Returns a pointer to the `wl_display` object of wayland that is used by this
// /// `EventLoopWindowTarget`.
// ///
// /// Returns `None` if the `EventLoop` doesn't use wayland (if it uses xlib for example).
// ///
// /// The pointer will become invalid when the winit `EventLoop` is destroyed.
// fn wayland_display(&self) -> Option<*mut raw::c_void>;
}
impl<T> EventLoopWindowTargetExtUnix for EventLoopWindowTarget<T> {
#[inline]
fn is_wayland(&self) -> bool {
self.p.is_wayland()
}
#[inline]
fn is_x11(&self) -> bool {
!self.p.is_wayland()
}
#[inline]
fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
if self.is_x11() {
if let Ok(xconn) = XConnection::new(Some(x_error_callback)) {
Some(Arc::new(xconn))
} else {
None
}
} else {
None
}
}
// #[inline]
// fn wayland_display(&self) -> Option<*mut raw::c_void> {
// match self.p {
// LinuxEventLoopWindowTarget::Wayland(ref p) => {
// Some(p.display().get_display_ptr() as *mut _)
// }
// #[cfg(feature = "x11")]
// _ => None,
// }
// }
}
unsafe extern "C" fn x_error_callback(
_display: *mut x11::ffi::Display,
event: *mut x11::ffi::XErrorEvent,
) -> c_int {
let error = XError {
// TODO get the error text as description
description: String::new(),
error_code: (*event).error_code,
request_code: (*event).request_code,
minor_code: (*event).minor_code,
};
error!("X11 error: {:#?}", error);
// Fun fact: this return value is completely ignored.
0
}