csd
This commit is contained in:
parent
4f1a13f11f
commit
0667b031cc
12 changed files with 723 additions and 522 deletions
|
|
@ -1,5 +0,0 @@
|
|||
pub mod move_grab;
|
||||
pub use move_grab::MoveSurfaceGrab;
|
||||
|
||||
pub mod resize_grab;
|
||||
pub use resize_grab::ResizeSurfaceGrab;
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
//! Move grab is the state of a composer during which the client window is being dragged around.
|
||||
//!
|
||||
//! eg. Usually whenever a user clicks on the app's titlebar and starts dragging, the compositors
|
||||
//! enters a MoveSurfaceGrab state.
|
||||
|
||||
use crate::{render::DecoratedWindow, State};
|
||||
use smithay::{
|
||||
desktop::Window,
|
||||
input::pointer::{
|
||||
AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||
GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData,
|
||||
MotionEvent, PointerGrab, PointerInnerHandle, RelativeMotionEvent,
|
||||
},
|
||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||
utils::{Logical, Point},
|
||||
};
|
||||
|
||||
pub struct MoveSurfaceGrab {
|
||||
pub start_data: PointerGrabStartData<State>,
|
||||
pub window: DecoratedWindow,
|
||||
pub initial_window_location: Point<i32, Logical>,
|
||||
}
|
||||
|
||||
impl PointerGrab<State> for MoveSurfaceGrab {
|
||||
fn motion(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
_focus: Option<(WlSurface, Point<f64, Logical>)>,
|
||||
event: &MotionEvent,
|
||||
) {
|
||||
// While the grab is active, no client has pointer focus
|
||||
handle.motion(data, None, event);
|
||||
|
||||
let delta = event.location - self.start_data.location;
|
||||
let new_location = self.initial_window_location.to_f64() + delta;
|
||||
data.space
|
||||
.map_element(self.window.clone(), new_location.to_i32_round(), true);
|
||||
}
|
||||
|
||||
fn relative_motion(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
focus: Option<(WlSurface, Point<f64, Logical>)>,
|
||||
event: &RelativeMotionEvent,
|
||||
) {
|
||||
handle.relative_motion(data, focus, event);
|
||||
}
|
||||
|
||||
fn button(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &ButtonEvent,
|
||||
) {
|
||||
handle.button(data, event);
|
||||
|
||||
// The button is a button code as defined in the
|
||||
// Linux kernel's linux/input-event-codes.h header file, e.g. BTN_LEFT.
|
||||
const BTN_LEFT: u32 = 0x110;
|
||||
|
||||
if !handle.current_pressed().contains(&BTN_LEFT) {
|
||||
// No more buttons are pressed, release the grab.
|
||||
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||
}
|
||||
}
|
||||
|
||||
fn axis(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
details: AxisFrame,
|
||||
) {
|
||||
handle.axis(data, details)
|
||||
}
|
||||
|
||||
fn frame(&mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>) {
|
||||
handle.frame(data);
|
||||
}
|
||||
|
||||
fn gesture_swipe_begin(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureSwipeBeginEvent,
|
||||
) {
|
||||
handle.gesture_swipe_begin(data, event)
|
||||
}
|
||||
|
||||
fn gesture_swipe_update(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureSwipeUpdateEvent,
|
||||
) {
|
||||
handle.gesture_swipe_update(data, event)
|
||||
}
|
||||
|
||||
fn gesture_swipe_end(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureSwipeEndEvent,
|
||||
) {
|
||||
handle.gesture_swipe_end(data, event)
|
||||
}
|
||||
|
||||
fn gesture_pinch_begin(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GesturePinchBeginEvent,
|
||||
) {
|
||||
handle.gesture_pinch_begin(data, event)
|
||||
}
|
||||
|
||||
fn gesture_pinch_update(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GesturePinchUpdateEvent,
|
||||
) {
|
||||
handle.gesture_pinch_update(data, event)
|
||||
}
|
||||
|
||||
fn gesture_pinch_end(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GesturePinchEndEvent,
|
||||
) {
|
||||
handle.gesture_pinch_end(data, event)
|
||||
}
|
||||
|
||||
fn gesture_hold_begin(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureHoldBeginEvent,
|
||||
) {
|
||||
handle.gesture_hold_begin(data, event)
|
||||
}
|
||||
|
||||
fn gesture_hold_end(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureHoldEndEvent,
|
||||
) {
|
||||
handle.gesture_hold_end(data, event)
|
||||
}
|
||||
|
||||
fn start_data(&self) -> &PointerGrabStartData<State> {
|
||||
&self.start_data
|
||||
}
|
||||
|
||||
fn unset(&mut self, _data: &mut State) {}
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
use smithay::{
|
||||
desktop::{layer_map_for_output, LayerSurface},
|
||||
output::Output,
|
||||
wayland::shell::wlr_layer::WlrLayerShellHandler,
|
||||
utils::SERIAL_COUNTER,
|
||||
wayland::shell::wlr_layer::{KeyboardInteractivity, Layer, WlrLayerShellHandler},
|
||||
};
|
||||
use wayland_server::protocol::wl_output::WlOutput;
|
||||
|
||||
|
|
@ -24,9 +25,20 @@ impl WlrLayerShellHandler for State {
|
|||
.and_then(Output::from_resource)
|
||||
.unwrap_or_else(|| self.space.outputs().next().unwrap().clone());
|
||||
let mut map = layer_map_for_output(&output);
|
||||
map.map_layer(&LayerSurface::new(surface.clone(), namespace))
|
||||
.unwrap();
|
||||
let layer_surface = LayerSurface::new(surface.clone(), namespace);
|
||||
map.map_layer(&layer_surface).unwrap();
|
||||
surface.send_configure();
|
||||
|
||||
let state = layer_surface.cached_state();
|
||||
|
||||
if layer_surface.can_receive_keyboard_focus() {
|
||||
let keyboard = self.seat.get_keyboard().unwrap();
|
||||
keyboard.set_focus(
|
||||
self,
|
||||
Some(surface.wl_surface().clone()),
|
||||
SERIAL_COUNTER.next_serial(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn layer_destroyed(&mut self, surface: smithay::wayland::shell::wlr_layer::LayerSurface) {
|
||||
|
|
|
|||
|
|
@ -2,14 +2,10 @@ use smithay::utils::Point;
|
|||
use smithay::wayland::seat::WaylandFocus;
|
||||
use smithay::{
|
||||
desktop::{
|
||||
find_popup_root_surface, get_popup_toplevel_coords, layer_map_for_output,
|
||||
PopupKeyboardGrab, PopupKind, PopupManager, PopupPointerGrab, PopupUngrabStrategy, Space,
|
||||
Window, WindowSurfaceType,
|
||||
},
|
||||
input::{
|
||||
pointer::{Focus, GrabStartData as PointerGrabStartData},
|
||||
Seat,
|
||||
find_popup_root_surface, get_popup_toplevel_coords, PopupKeyboardGrab, PopupKind,
|
||||
PopupManager, PopupPointerGrab, PopupUngrabStrategy, Space, Window,
|
||||
},
|
||||
input::{pointer::Focus, Seat},
|
||||
output::Output,
|
||||
reexports::{
|
||||
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||
|
|
@ -29,11 +25,7 @@ use smithay::{
|
|||
};
|
||||
use wayland_server::protocol::wl_output;
|
||||
|
||||
use crate::{
|
||||
grabs::{MoveSurfaceGrab, ResizeSurfaceGrab},
|
||||
render::DecoratedWindow,
|
||||
state::State,
|
||||
};
|
||||
use crate::{state::State, window::DecoratedWindow};
|
||||
|
||||
impl XdgShellHandler for State {
|
||||
fn xdg_shell_state(&mut self) -> &mut XdgShellState {
|
||||
|
|
@ -72,35 +64,19 @@ impl XdgShellHandler for State {
|
|||
}
|
||||
|
||||
fn move_request(&mut self, surface: ToplevelSurface, seat: wl_seat::WlSeat, serial: Serial) {
|
||||
let seat = Seat::from_resource(&seat).unwrap();
|
||||
let seat: Seat<State> = Seat::from_resource(&seat).unwrap();
|
||||
|
||||
let wl_surface = surface.wl_surface();
|
||||
|
||||
if let Some(start_data) = check_grab(&seat, wl_surface, serial) {
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
let window = self
|
||||
.space
|
||||
.elements()
|
||||
.filter(|w| w.window.toplevel().is_some())
|
||||
.find(|w| w.window.toplevel().unwrap().wl_surface() == wl_surface)
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
let window = self
|
||||
.space
|
||||
.elements()
|
||||
.filter(|w| w.window.toplevel().is_some())
|
||||
.find(|w| w.window.toplevel().unwrap().wl_surface() == wl_surface)
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
if window.is_fullscreen() {
|
||||
return;
|
||||
}
|
||||
|
||||
let initial_window_location = self.space.element_location(&window).unwrap();
|
||||
|
||||
let grab = MoveSurfaceGrab {
|
||||
start_data,
|
||||
window: window.clone(),
|
||||
initial_window_location,
|
||||
};
|
||||
|
||||
pointer.set_grab(self, grab, serial, Focus::Clear);
|
||||
}
|
||||
window.do_move_grab(self, &seat, &surface, serial, false);
|
||||
}
|
||||
|
||||
fn resize_request(
|
||||
|
|
@ -110,42 +86,19 @@ impl XdgShellHandler for State {
|
|||
serial: Serial,
|
||||
edges: xdg_toplevel::ResizeEdge,
|
||||
) {
|
||||
let seat = Seat::from_resource(&seat).unwrap();
|
||||
let seat: Seat<State> = Seat::from_resource(&seat).unwrap();
|
||||
|
||||
let wl_surface = surface.wl_surface();
|
||||
|
||||
if let Some(start_data) = check_grab(&seat, wl_surface, serial) {
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
let window = self
|
||||
.space
|
||||
.elements()
|
||||
.filter(|w| w.window.toplevel().is_some())
|
||||
.find(|w| w.window.toplevel().unwrap().wl_surface() == wl_surface)
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
let window = self
|
||||
.space
|
||||
.elements()
|
||||
.filter(|w| w.window.toplevel().is_some())
|
||||
.find(|w| w.window.toplevel().unwrap().wl_surface() == wl_surface)
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
if window.is_fullscreen() {
|
||||
return;
|
||||
}
|
||||
let initial_window_location = self.space.element_location(&window).unwrap();
|
||||
let initial_window_size = window.window.geometry().size;
|
||||
|
||||
surface.with_pending_state(|state| {
|
||||
state.states.set(xdg_toplevel::State::Resizing);
|
||||
});
|
||||
|
||||
surface.send_pending_configure();
|
||||
|
||||
let grab = ResizeSurfaceGrab::start(
|
||||
start_data,
|
||||
window.window.clone(),
|
||||
edges.into(),
|
||||
Rectangle::new(initial_window_location, initial_window_size),
|
||||
);
|
||||
|
||||
pointer.set_grab(self, grab, serial, Focus::Clear);
|
||||
}
|
||||
window.do_resize_grab(self, &seat, &surface, serial, edges, false);
|
||||
}
|
||||
|
||||
fn grab(&mut self, surface: PopupSurface, seat: wl_seat::WlSeat, serial: Serial) {
|
||||
|
|
@ -342,29 +295,6 @@ impl XdgShellHandler for State {
|
|||
// fn parent_changed(&mut self, surface: ToplevelSurface) {}
|
||||
}
|
||||
|
||||
fn check_grab(
|
||||
seat: &Seat<State>,
|
||||
surface: &WlSurface,
|
||||
serial: Serial,
|
||||
) -> Option<PointerGrabStartData<State>> {
|
||||
let pointer = seat.get_pointer()?;
|
||||
|
||||
// Check that this surface has a click grab.
|
||||
if !pointer.has_grab(serial) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let start_data = pointer.grab_start_data()?;
|
||||
|
||||
let (focus, _) = start_data.focus.as_ref()?;
|
||||
// If the focus was for a different surface, ignore the request.
|
||||
if !focus.id().same_client_as(&surface.id()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(start_data)
|
||||
}
|
||||
|
||||
/// Should be called on `WlSurface::commit`
|
||||
pub fn handle_commit(popups: &mut PopupManager, space: &Space<Window>, surface: &WlSurface) {
|
||||
// Handle toplevel commits.
|
||||
|
|
|
|||
51
src/input.rs
51
src/input.rs
|
|
@ -1,14 +1,14 @@
|
|||
use smithay::desktop::space::SpaceElement;
|
||||
use smithay::reexports::x11rb::protocol::xkb::SALockControls;
|
||||
use smithay::{
|
||||
backend::input::{
|
||||
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputBackend, InputEvent,
|
||||
KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent,
|
||||
},
|
||||
desktop::layer_map_for_output,
|
||||
input::{
|
||||
keyboard::FilterResult,
|
||||
pointer::{AxisFrame, ButtonEvent, MotionEvent},
|
||||
},
|
||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||
utils::SERIAL_COUNTER,
|
||||
};
|
||||
|
||||
|
|
@ -57,29 +57,20 @@ impl State {
|
|||
}
|
||||
InputEvent::PointerButton { event, .. } => {
|
||||
let pointer = self.seat.get_pointer().unwrap();
|
||||
let keyboard = self.seat.get_keyboard().unwrap();
|
||||
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
|
||||
let button = event.button_code();
|
||||
|
||||
let button_state = event.state();
|
||||
let seat = self.seat.clone();
|
||||
|
||||
let mut dragged_windows = vec![];
|
||||
|
||||
if ButtonState::Pressed == button_state && !pointer.is_grabbed() {
|
||||
let mut actv_window = None;
|
||||
if let Some((window, _loc)) = self
|
||||
.space
|
||||
.element_under(pointer.current_location())
|
||||
.map(|(w, l)| (w.clone(), l))
|
||||
{
|
||||
self.space.raise_element(&window, true);
|
||||
if let Some(toplevel) = window.window.toplevel() {
|
||||
keyboard.set_focus(self, Some(toplevel.wl_surface().clone()), serial);
|
||||
}
|
||||
actv_window = Some(window.clone());
|
||||
} else {
|
||||
keyboard.set_focus(self, Option::<WlSurface>::None, serial);
|
||||
}
|
||||
|
||||
self.update_focus(serial, &mut actv_window);
|
||||
|
||||
self.space.elements().for_each(|window| {
|
||||
window.window.set_activated(false);
|
||||
|
|
@ -87,21 +78,17 @@ impl State {
|
|||
if actv_window.window == window.window {
|
||||
window.window.set_activated(true);
|
||||
}
|
||||
}
|
||||
if let Some(toplevel) = window.window.toplevel() {
|
||||
toplevel.send_pending_configure();
|
||||
}
|
||||
});
|
||||
self.space.elements().for_each(|window| {
|
||||
window.window.set_activated(false);
|
||||
if let Some(actv_window) = actv_window.as_ref() {
|
||||
if actv_window.window == window.window {
|
||||
window.window.set_activated(true);
|
||||
/* window ssd actions */
|
||||
if window.decorated() {
|
||||
let mut loc = pointer.current_location();
|
||||
let window_loc = self.space.element_geometry(window).unwrap();
|
||||
loc.x -= (window_loc.loc.x - window.bbox().loc.x) as f64;
|
||||
loc.y -= (window_loc.loc.y - window.bbox().loc.y) as f64;
|
||||
if window.in_ssd(&loc) {
|
||||
dragged_windows.push((window.clone(), loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(toplevel) = window.window.toplevel() {
|
||||
toplevel.send_pending_configure();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -115,6 +102,12 @@ impl State {
|
|||
},
|
||||
);
|
||||
pointer.frame(self);
|
||||
|
||||
for (window, loc) in &dragged_windows.clone() {
|
||||
if let Some(toplevel) = window.window.toplevel() {
|
||||
window.do_ssd_action(self, &seat, toplevel, serial, &loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
InputEvent::PointerAxis { event, .. } => {
|
||||
let source = event.source();
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@
|
|||
mod handlers;
|
||||
|
||||
mod audio;
|
||||
mod grabs;
|
||||
mod input;
|
||||
pub mod render;
|
||||
mod state;
|
||||
pub mod window;
|
||||
mod winit;
|
||||
mod xwayland;
|
||||
|
||||
|
|
|
|||
60
src/state.rs
60
src/state.rs
|
|
@ -1,8 +1,8 @@
|
|||
use crate::{audio::SystemAudioPlayer, render::DecoratedWindow};
|
||||
use crate::{audio::SystemAudioPlayer, window::DecoratedWindow};
|
||||
use std::{ffi::OsString, sync::Arc};
|
||||
|
||||
use smithay::{
|
||||
desktop::{PopupManager, Space, Window, WindowSurfaceType},
|
||||
desktop::{layer_map_for_output, PopupManager, Space, Window, WindowSurfaceType},
|
||||
input::{Seat, SeatState},
|
||||
reexports::{
|
||||
calloop::{generic::Generic, Interest, LoopHandle, Mode, PostAction},
|
||||
|
|
@ -12,13 +12,16 @@ use smithay::{
|
|||
Display, DisplayHandle,
|
||||
},
|
||||
},
|
||||
utils::{Logical, Point},
|
||||
utils::{Logical, Point, Serial},
|
||||
wayland::{
|
||||
compositor::{CompositorClientState, CompositorState},
|
||||
fixes::FixesState,
|
||||
output::OutputManagerState,
|
||||
selection::data_device::DataDeviceState,
|
||||
shell::{wlr_layer::WlrLayerShellState, xdg::XdgShellState},
|
||||
shell::{
|
||||
wlr_layer::{Layer, WlrLayerShellState},
|
||||
xdg::{decoration::XdgDecorationState, XdgShellState},
|
||||
},
|
||||
shm::ShmState,
|
||||
socket::ListeningSocketSource,
|
||||
xdg_activation::XdgActivationState,
|
||||
|
|
@ -53,7 +56,7 @@ pub struct State {
|
|||
|
||||
// xdg
|
||||
pub xdg_shell_state: XdgShellState,
|
||||
// pub xdg_decoration_state: XdgDecorationState,
|
||||
pub xdg_decoration_state: XdgDecorationState,
|
||||
pub xdg_activation_state: XdgActivationState,
|
||||
pub xdg_toplevel_icon_manager_state: XdgToplevelIconManager,
|
||||
pub xdg_toplevel_tag_manager_state: XdgToplevelTagManager,
|
||||
|
|
@ -85,7 +88,7 @@ impl State {
|
|||
let xdg_shell_state = XdgShellState::new::<Self>(&dh);
|
||||
|
||||
let xdg_shell_state = XdgShellState::new::<Self>(&dh);
|
||||
// let xdg_decoration_state = XdgDecorationState::new::<Self>(&dh);
|
||||
let xdg_decoration_state = XdgDecorationState::new::<Self>(&dh);
|
||||
let xdg_activation_state = XdgActivationState::new::<Self>(&dh);
|
||||
let xdg_toplevel_icon_manager_state = XdgToplevelIconManager::new::<Self>(&dh);
|
||||
let xdg_toplevel_tag_manager_state = XdgToplevelTagManager::new::<Self>(&dh);
|
||||
|
|
@ -156,7 +159,7 @@ impl State {
|
|||
output_manager_state,
|
||||
wlr_layer_shell_state,
|
||||
|
||||
// xdg_decoration_state,
|
||||
xdg_decoration_state,
|
||||
xdg_activation_state,
|
||||
xdg_toplevel_icon_manager_state,
|
||||
xdg_toplevel_tag_manager_state,
|
||||
|
|
@ -223,6 +226,49 @@ impl State {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn update_focus(&mut self, serial: Serial, actv_window: &mut Option<DecoratedWindow>) {
|
||||
/* layer map under? */
|
||||
let pointer = self.seat.get_pointer().unwrap();
|
||||
let keyboard = self.seat.get_keyboard().unwrap();
|
||||
let output = self.space.outputs().next().unwrap().clone();
|
||||
let map = layer_map_for_output(&output);
|
||||
|
||||
let layers_p1 = vec![Layer::Overlay, Layer::Top];
|
||||
let layers_p2 = vec![Layer::Bottom, Layer::Background];
|
||||
|
||||
keyboard.set_focus(self, Option::<WlSurface>::None, serial);
|
||||
|
||||
for l in layers_p1 {
|
||||
if let Some(layer) = map.layer_under(l, pointer.current_location()) {
|
||||
if layer.can_receive_keyboard_focus() {
|
||||
keyboard.set_focus(self, Some(layer.wl_surface().clone()), serial);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((window, _loc)) = self
|
||||
.space
|
||||
.element_under(pointer.current_location())
|
||||
.map(|(w, l)| (w.clone(), l))
|
||||
{
|
||||
self.space.raise_element(&window, true);
|
||||
if let Some(toplevel) = window.window.toplevel() {
|
||||
keyboard.set_focus(self, Some(toplevel.wl_surface().clone()), serial);
|
||||
}
|
||||
*actv_window = Some(window.clone());
|
||||
return;
|
||||
}
|
||||
|
||||
for l in layers_p2 {
|
||||
if let Some(layer) = map.layer_under(l, pointer.current_location()) {
|
||||
if layer.can_receive_keyboard_focus() {
|
||||
keyboard.set_focus(self, Some(layer.wl_surface().clone()), serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn_clients() {
|
||||
/* todo: read from shit */
|
||||
std::process::Command::new("startmde").spawn().ok();
|
||||
|
|
|
|||
|
|
@ -1,26 +1,268 @@
|
|||
//! Resize grab is the state of a composer during which the client window is being resized.
|
||||
//!
|
||||
//! eg. Usually whenever a user clicks on the app's border and starts dragging, the compositors
|
||||
//! enters a ResizeSurfaceGrab state.
|
||||
|
||||
use crate::State;
|
||||
use smithay::input::pointer::GrabStartData as PointerGrabStartData;
|
||||
use smithay::utils::Rectangle;
|
||||
use smithay::wayland::shell::xdg::ToplevelSurface;
|
||||
use smithay::{
|
||||
desktop::{Space, Window},
|
||||
utils::Size,
|
||||
wayland::{compositor, shell::xdg::SurfaceCachedState},
|
||||
};
|
||||
use smithay::{
|
||||
input::pointer::{
|
||||
AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||
GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData,
|
||||
MotionEvent, PointerGrab, PointerInnerHandle, RelativeMotionEvent,
|
||||
GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent, PointerGrab,
|
||||
PointerInnerHandle, RelativeMotionEvent,
|
||||
},
|
||||
reexports::{
|
||||
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||
wayland_server::protocol::wl_surface::WlSurface,
|
||||
},
|
||||
utils::{Logical, Point, Rectangle, Size},
|
||||
wayland::{compositor, shell::xdg::SurfaceCachedState},
|
||||
utils::{Logical, Point},
|
||||
};
|
||||
use smithay::{
|
||||
input::{pointer::Focus, Seat},
|
||||
utils::Serial,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
|
||||
use crate::State;
|
||||
use wayland_protocols::xdg::shell::server::xdg_toplevel;
|
||||
use wayland_server::{protocol::wl_surface::WlSurface, Resource};
|
||||
|
||||
use super::DecoratedWindow;
|
||||
|
||||
impl DecoratedWindow {
|
||||
pub fn do_move_grab(
|
||||
&self,
|
||||
state: &mut State,
|
||||
seat: &Seat<State>,
|
||||
surface: &ToplevelSurface,
|
||||
serial: Serial,
|
||||
do_override: bool,
|
||||
) {
|
||||
let wl_surface = surface.wl_surface();
|
||||
if let Some(start_data) = check_grab(&seat, wl_surface, serial, do_override) {
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
if self.is_fullscreen() {
|
||||
return;
|
||||
}
|
||||
|
||||
let initial_window_location = state.space.element_location(&self).unwrap();
|
||||
|
||||
let grab = MoveSurfaceGrab {
|
||||
start_data,
|
||||
window: self.clone(),
|
||||
initial_window_location,
|
||||
};
|
||||
|
||||
pointer.set_grab(state, grab, serial, Focus::Clear);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_resize_grab(
|
||||
&self,
|
||||
state: &mut State,
|
||||
seat: &Seat<State>,
|
||||
surface: &ToplevelSurface,
|
||||
serial: Serial,
|
||||
edges: xdg_toplevel::ResizeEdge,
|
||||
do_override: bool,
|
||||
) {
|
||||
let wl_surface = surface.wl_surface();
|
||||
if let Some(start_data) = check_grab(&seat, wl_surface, serial, do_override) {
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
|
||||
if self.is_fullscreen() {
|
||||
return;
|
||||
}
|
||||
let initial_window_location = state.space.element_location(&self).unwrap();
|
||||
let initial_window_size = self.window.geometry().size;
|
||||
|
||||
surface.with_pending_state(|state| {
|
||||
state.states.set(xdg_toplevel::State::Resizing);
|
||||
});
|
||||
|
||||
surface.send_pending_configure();
|
||||
|
||||
let grab = ResizeSurfaceGrab::start(
|
||||
start_data,
|
||||
self.window.clone(),
|
||||
edges.into(),
|
||||
Rectangle::new(initial_window_location, initial_window_size),
|
||||
);
|
||||
|
||||
pointer.set_grab(state, grab, serial, Focus::Clear);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_grab(
|
||||
seat: &Seat<State>,
|
||||
surface: &WlSurface,
|
||||
serial: Serial,
|
||||
do_override: bool,
|
||||
) -> Option<PointerGrabStartData<State>> {
|
||||
let pointer = seat.get_pointer()?;
|
||||
|
||||
if !do_override {
|
||||
// Check that this surface has a click grab.
|
||||
if !pointer.has_grab(serial) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let start_data = pointer.grab_start_data()?;
|
||||
|
||||
if !do_override {
|
||||
let (focus, _) = start_data.focus.as_ref()?;
|
||||
// If the focus was for a different surface, ignore the request.
|
||||
if !focus.id().same_client_as(&surface.id()) && !do_override {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
Some(start_data)
|
||||
}
|
||||
|
||||
pub struct MoveSurfaceGrab {
|
||||
pub start_data: PointerGrabStartData<State>,
|
||||
pub window: DecoratedWindow,
|
||||
pub initial_window_location: Point<i32, Logical>,
|
||||
}
|
||||
|
||||
impl PointerGrab<State> for MoveSurfaceGrab {
|
||||
fn motion(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
_focus: Option<(WlSurface, Point<f64, Logical>)>,
|
||||
event: &MotionEvent,
|
||||
) {
|
||||
// While the grab is active, no client has pointer focus
|
||||
handle.motion(data, None, event);
|
||||
|
||||
let delta = event.location - self.start_data.location;
|
||||
let new_location = self.initial_window_location.to_f64() + delta;
|
||||
data.space
|
||||
.map_element(self.window.clone(), new_location.to_i32_round(), true);
|
||||
}
|
||||
|
||||
fn relative_motion(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
focus: Option<(WlSurface, Point<f64, Logical>)>,
|
||||
event: &RelativeMotionEvent,
|
||||
) {
|
||||
handle.relative_motion(data, focus, event);
|
||||
}
|
||||
|
||||
fn button(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &ButtonEvent,
|
||||
) {
|
||||
handle.button(data, event);
|
||||
|
||||
// The button is a button code as defined in the
|
||||
// Linux kernel's linux/input-event-codes.h header file, e.g. BTN_LEFT.
|
||||
const BTN_LEFT: u32 = 0x110;
|
||||
|
||||
if !handle.current_pressed().contains(&BTN_LEFT) {
|
||||
// No more buttons are pressed, release the grab.
|
||||
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||
}
|
||||
}
|
||||
|
||||
fn axis(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
details: AxisFrame,
|
||||
) {
|
||||
handle.axis(data, details)
|
||||
}
|
||||
|
||||
fn frame(&mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>) {
|
||||
handle.frame(data);
|
||||
}
|
||||
|
||||
fn gesture_swipe_begin(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureSwipeBeginEvent,
|
||||
) {
|
||||
handle.gesture_swipe_begin(data, event)
|
||||
}
|
||||
|
||||
fn gesture_swipe_update(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureSwipeUpdateEvent,
|
||||
) {
|
||||
handle.gesture_swipe_update(data, event)
|
||||
}
|
||||
|
||||
fn gesture_swipe_end(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureSwipeEndEvent,
|
||||
) {
|
||||
handle.gesture_swipe_end(data, event)
|
||||
}
|
||||
|
||||
fn gesture_pinch_begin(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GesturePinchBeginEvent,
|
||||
) {
|
||||
handle.gesture_pinch_begin(data, event)
|
||||
}
|
||||
|
||||
fn gesture_pinch_update(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GesturePinchUpdateEvent,
|
||||
) {
|
||||
handle.gesture_pinch_update(data, event)
|
||||
}
|
||||
|
||||
fn gesture_pinch_end(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GesturePinchEndEvent,
|
||||
) {
|
||||
handle.gesture_pinch_end(data, event)
|
||||
}
|
||||
|
||||
fn gesture_hold_begin(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureHoldBeginEvent,
|
||||
) {
|
||||
handle.gesture_hold_begin(data, event)
|
||||
}
|
||||
|
||||
fn gesture_hold_end(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureHoldEndEvent,
|
||||
) {
|
||||
handle.gesture_hold_end(data, event)
|
||||
}
|
||||
|
||||
fn start_data(&self) -> &PointerGrabStartData<State> {
|
||||
&self.start_data
|
||||
}
|
||||
|
||||
fn unset(&mut self, _data: &mut State) {}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ResizeEdge: u32 {
|
||||
|
|
@ -2,13 +2,13 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::State;
|
||||
use cairo::{Context, Format, ImageSurface};
|
||||
use parking_lot::Mutex;
|
||||
use smithay::backend::allocator::Fourcc;
|
||||
use smithay::backend::renderer::element::memory::MemoryRenderBuffer;
|
||||
use smithay::desktop::layer_map_for_output;
|
||||
use smithay::desktop::utils::send_frames_surface_tree;
|
||||
use smithay::utils::{Logical, Transform};
|
||||
use smithay::wayland::commit_timing::CommitTimerBarrierStateUserData;
|
||||
use smithay::wayland::seat::WaylandFocus;
|
||||
use smithay::{
|
||||
backend::renderer::{
|
||||
damage::OutputDamageTracker,
|
||||
|
|
@ -26,17 +26,19 @@ use smithay::{
|
|||
};
|
||||
use wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode;
|
||||
|
||||
use self::ssd::{
|
||||
SSD_BORDER_FRAME_BOTTOM, SSD_BORDER_FRAME_LEFT, SSD_BORDER_FRAME_RIGHT, SSD_BORDER_FRAME_TOP,
|
||||
};
|
||||
|
||||
pub mod grab;
|
||||
pub mod ssd;
|
||||
|
||||
render_elements! {
|
||||
pub OutputElement<R> where R: ImportMem + ImportDmaWl + ImportMemWl;
|
||||
Window=WaylandSurfaceRenderElement<R>,
|
||||
Border=MemoryRenderBufferRenderElement<R>,
|
||||
}
|
||||
|
||||
const CSD_BORDER_FRAME_LEFT: f64 = 5.0;
|
||||
const CSD_BORDER_FRAME_RIGHT: f64 = 5.0;
|
||||
const CSD_BORDER_FRAME_TOP: f64 = 23.0;
|
||||
const CSD_BORDER_FRAME_BOTTOM: f64 = 4.0;
|
||||
|
||||
pub struct DecoratedWindow {
|
||||
pub window: Window,
|
||||
title: Mutex<String>,
|
||||
|
|
@ -73,7 +75,6 @@ impl Clone for DecoratedWindow {
|
|||
|
||||
impl DecoratedWindow {
|
||||
pub fn new(window: Window, decorations: bool) -> Self {
|
||||
// let surface = ImageSurface::create(Format::ARgb32, width, height).unwrap();
|
||||
Self {
|
||||
window,
|
||||
title: Mutex::new(String::new()),
|
||||
|
|
@ -104,7 +105,7 @@ impl DecoratedWindow {
|
|||
*self.fullscreen.lock() = fs;
|
||||
}
|
||||
|
||||
fn decorated(&self) -> bool {
|
||||
pub fn decorated(&self) -> bool {
|
||||
let mut b = *self.decorations.lock();
|
||||
if let Some(toplevel) = self.window.toplevel() {
|
||||
toplevel.with_pending_state(|f| {
|
||||
|
|
@ -115,179 +116,6 @@ impl DecoratedWindow {
|
|||
}
|
||||
b
|
||||
}
|
||||
|
||||
fn render_border(&self, width: i32, height: i32) -> (Vec<u8>, i32) {
|
||||
let mut surface = ImageSurface::create(Format::ARgb32, width, height).unwrap();
|
||||
let stride = surface.stride();
|
||||
|
||||
{
|
||||
let ctx = Context::new(&surface).unwrap(); // scoped — see note below
|
||||
ctx.set_source_rgba(0.2, 0.2, 0.2, 1.0);
|
||||
ctx.set_line_width(1.0);
|
||||
|
||||
let (w, h) = (width as f64, height as f64);
|
||||
|
||||
macro_rules! do_box {
|
||||
($x:expr, $y:expr, $col:expr, $w:expr, $h:expr) => {
|
||||
ctx.rectangle(($x) as f64, ($y) as f64, ($w) as f64, ($h) as f64);
|
||||
ctx.set_source_rgb(($col) as f64, ($col) as f64, ($col) as f64);
|
||||
ctx.fill().unwrap();
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! do_line {
|
||||
($off:expr, $col:expr) => {
|
||||
ctx.move_to($off, $off);
|
||||
ctx.line_to($off, h - $off);
|
||||
ctx.set_source_rgb($col, $col, $col);
|
||||
ctx.stroke().unwrap();
|
||||
ctx.move_to($off, $off);
|
||||
ctx.line_to(w - $off, $off);
|
||||
ctx.set_source_rgb($col, $col, $col);
|
||||
ctx.stroke().unwrap();
|
||||
};
|
||||
}
|
||||
|
||||
ctx.set_antialias(cairo::Antialias::None);
|
||||
|
||||
/* border */
|
||||
do_box!(0.0, 0.0, 0.14901961, w, h);
|
||||
do_box!(1.0, 1.0, 0.55686275, w - 2.0, h - 2.0);
|
||||
do_box!(2.0, 2.0, 0.82352941, w - 4.0, h - 4.0);
|
||||
do_box!(3.0, 3.0, 0.93333333, w - 6.0, h - 6.0);
|
||||
do_box!(4.0, 4.0, 1.0, w - 8.0, h - 8.0);
|
||||
do_box!(4.0, 4.0, 0.14901961, w - 9.0, h - 9.0);
|
||||
do_line!(1.0, 1.0);
|
||||
do_line!(2.0, 0.93333333);
|
||||
do_line!(3.0, 0.82352941);
|
||||
do_line!(4.0, 0.55686275);
|
||||
do_line!(5.0, 0.14901961);
|
||||
for y in 0..18 {
|
||||
let y = y as f64;
|
||||
let a = FloatColor {
|
||||
r: 0.2627451,
|
||||
g: 0.37254902,
|
||||
b: 0.49411765,
|
||||
};
|
||||
let b = FloatColor {
|
||||
r: 0.05490196,
|
||||
g: 0.17254902,
|
||||
b: 0.30588235,
|
||||
};
|
||||
let c = lerp_color(a, b, y / 18.0);
|
||||
|
||||
ctx.set_source_rgb(c.r, c.g, c.b);
|
||||
|
||||
ctx.move_to(5.0, y + 6.0);
|
||||
ctx.line_to(w as f64 - 5.0, y + 6.0);
|
||||
ctx.stroke().unwrap();
|
||||
}
|
||||
|
||||
/* icon */
|
||||
do_box!(5, 5, 1, 18, 18);
|
||||
do_box!(6, 6, 0.35294118, 17, 17);
|
||||
do_box!(6, 6, 0.82352941, 16, 16);
|
||||
|
||||
/* close */
|
||||
do_box!(
|
||||
w - 18.0 - CSD_BORDER_FRAME_LEFT,
|
||||
CSD_BORDER_FRAME_BOTTOM + 1.0,
|
||||
1,
|
||||
18,
|
||||
18
|
||||
);
|
||||
do_box!(
|
||||
w - 17.0 - CSD_BORDER_FRAME_LEFT,
|
||||
CSD_BORDER_FRAME_BOTTOM + 2.0,
|
||||
0.35294118,
|
||||
17,
|
||||
17
|
||||
);
|
||||
do_box!(
|
||||
w - 17.0 - CSD_BORDER_FRAME_LEFT,
|
||||
CSD_BORDER_FRAME_BOTTOM + 2.0,
|
||||
0.82352941,
|
||||
16,
|
||||
16
|
||||
);
|
||||
do_box!(
|
||||
w - 17.0 - CSD_BORDER_FRAME_LEFT + 5.0,
|
||||
CSD_BORDER_FRAME_BOTTOM + 7.0,
|
||||
0,
|
||||
6,
|
||||
6
|
||||
);
|
||||
do_box!(
|
||||
w - 17.0 - CSD_BORDER_FRAME_LEFT + 6.0,
|
||||
CSD_BORDER_FRAME_BOTTOM + 8.0,
|
||||
0.82352941,
|
||||
4,
|
||||
4
|
||||
);
|
||||
|
||||
/* maxim */
|
||||
do_box!(
|
||||
w - 36.0 - CSD_BORDER_FRAME_LEFT,
|
||||
CSD_BORDER_FRAME_BOTTOM + 1.0,
|
||||
1,
|
||||
18,
|
||||
18
|
||||
);
|
||||
do_box!(
|
||||
w - 35.0 - CSD_BORDER_FRAME_LEFT,
|
||||
CSD_BORDER_FRAME_BOTTOM + 2.0,
|
||||
0.35294118,
|
||||
17,
|
||||
17
|
||||
);
|
||||
do_box!(
|
||||
w - 35.0 - CSD_BORDER_FRAME_LEFT,
|
||||
CSD_BORDER_FRAME_BOTTOM + 2.0,
|
||||
0.82352941,
|
||||
16,
|
||||
16
|
||||
);
|
||||
do_box!(
|
||||
w - 35.0 - CSD_BORDER_FRAME_LEFT + 5.0,
|
||||
CSD_BORDER_FRAME_BOTTOM + 7.0,
|
||||
0,
|
||||
6,
|
||||
6
|
||||
);
|
||||
do_box!(
|
||||
w - 35.0 - CSD_BORDER_FRAME_LEFT,
|
||||
CSD_BORDER_FRAME_BOTTOM + 9.0,
|
||||
0.82352941,
|
||||
16,
|
||||
2
|
||||
);
|
||||
do_box!(
|
||||
w - 35.0 - CSD_BORDER_FRAME_LEFT + 7.0,
|
||||
CSD_BORDER_FRAME_BOTTOM + 4.0,
|
||||
0.82352941,
|
||||
2,
|
||||
14
|
||||
);
|
||||
do_box!(
|
||||
w - 35.0 - CSD_BORDER_FRAME_LEFT + 6.0,
|
||||
CSD_BORDER_FRAME_BOTTOM + 8.0,
|
||||
0.82352941,
|
||||
4,
|
||||
4
|
||||
);
|
||||
|
||||
/* title */
|
||||
ctx.set_antialias(cairo::Antialias::Best);
|
||||
ctx.move_to(28.0, 19.0);
|
||||
ctx.set_font_size(12.0);
|
||||
ctx.select_font_face("", cairo::FontSlant::Normal, cairo::FontWeight::Normal);
|
||||
ctx.text_path(&self.title.lock().clone());
|
||||
ctx.fill().unwrap();
|
||||
} // ctx dropped here
|
||||
|
||||
surface.flush();
|
||||
(surface.data().unwrap().to_vec(), stride)
|
||||
}
|
||||
}
|
||||
|
||||
impl SpaceElement for DecoratedWindow {
|
||||
|
|
@ -295,8 +123,10 @@ impl SpaceElement for DecoratedWindow {
|
|||
let mut bbox = self.window.bbox_with_popups();
|
||||
|
||||
if self.decorated() {
|
||||
bbox.loc.x -= 5;
|
||||
bbox.loc.y -= 24;
|
||||
bbox.loc.x -= SSD_BORDER_FRAME_LEFT as i32;
|
||||
bbox.loc.y -= SSD_BORDER_FRAME_TOP as i32;
|
||||
bbox.size.w += (SSD_BORDER_FRAME_LEFT + SSD_BORDER_FRAME_RIGHT) as i32;
|
||||
bbox.size.h += (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM) as i32;
|
||||
}
|
||||
|
||||
bbox
|
||||
|
|
@ -306,7 +136,11 @@ impl SpaceElement for DecoratedWindow {
|
|||
&self,
|
||||
point: &smithay::utils::Point<f64, smithay::utils::Logical>,
|
||||
) -> bool {
|
||||
self.window.is_in_input_region(point)
|
||||
if !self.window.is_in_input_region(point) {
|
||||
return self.in_ssd(point);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_activate(&self, activated: bool) {
|
||||
|
|
@ -326,6 +160,12 @@ impl SpaceElement for DecoratedWindow {
|
|||
*self.output.lock() = None;
|
||||
self.window.output_leave(output)
|
||||
}
|
||||
|
||||
fn z_index(&self) -> u8 {
|
||||
smithay::desktop::space::RenderZindex::Overlay as u8
|
||||
}
|
||||
|
||||
fn refresh(&self) {}
|
||||
}
|
||||
|
||||
impl IsAlive for DecoratedWindow {
|
||||
|
|
@ -373,7 +213,7 @@ where
|
|||
|
||||
let width = bg_rect.size.w;
|
||||
let height = bg_rect.size.h;
|
||||
let data = self.render_border(width, height);
|
||||
let data = self.render_csd(width, height);
|
||||
let buffer = MemoryRenderBuffer::from_slice(
|
||||
&data.0,
|
||||
Fourcc::Argb8888,
|
||||
|
|
@ -400,19 +240,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
struct FloatColor {
|
||||
r: f64,
|
||||
g: f64,
|
||||
b: f64,
|
||||
}
|
||||
fn lerp_color(a: FloatColor, b: FloatColor, t: f64) -> FloatColor {
|
||||
return FloatColor {
|
||||
r: a.r + (b.r - a.r) * t,
|
||||
g: a.g + (b.g - a.g) * t,
|
||||
b: a.b + (b.b - a.b) * t,
|
||||
};
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn render(
|
||||
&self,
|
||||
|
|
@ -422,12 +249,15 @@ impl State {
|
|||
damage_tracker: &mut OutputDamageTracker,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
self.space.elements().for_each(|window| {
|
||||
window.window.send_frame(
|
||||
&output,
|
||||
self.start_time.elapsed(),
|
||||
Some(Duration::ZERO),
|
||||
|_, _| Some(output.clone()),
|
||||
)
|
||||
if let Some(surface) = window.window.wl_surface() {
|
||||
send_frames_surface_tree(
|
||||
&surface,
|
||||
&output,
|
||||
self.start_time.elapsed(),
|
||||
Some(Duration::ZERO),
|
||||
|_, _| Some(output.clone()),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
self.space.outputs().for_each(|output| {
|
||||
|
|
@ -435,13 +265,13 @@ impl State {
|
|||
map.arrange();
|
||||
|
||||
map.layers().for_each(|layer| {
|
||||
layer.layer_surface().send_pending_configure();
|
||||
layer.send_frame(
|
||||
send_frames_surface_tree(
|
||||
layer.wl_surface(),
|
||||
&output,
|
||||
self.start_time.elapsed(),
|
||||
Some(Duration::ZERO),
|
||||
|_, _| Some(output.clone()),
|
||||
)
|
||||
);
|
||||
})
|
||||
});
|
||||
|
||||
314
src/window/ssd.rs
Normal file
314
src/window/ssd.rs
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
use cairo::{Context, Format, ImageSurface};
|
||||
use smithay::{
|
||||
input::Seat,
|
||||
output::Scale,
|
||||
utils::{Logical, Point, Serial},
|
||||
wayland::shell::xdg::ToplevelSurface,
|
||||
};
|
||||
use wayland_protocols::xdg::shell::server::xdg_toplevel;
|
||||
|
||||
use crate::State;
|
||||
|
||||
use super::DecoratedWindow;
|
||||
|
||||
pub const SSD_BORDER_FRAME_LEFT: f64 = 5.0;
|
||||
pub const SSD_BORDER_FRAME_RIGHT: f64 = 5.0;
|
||||
pub const SSD_BORDER_FRAME_TOP: f64 = 23.0;
|
||||
pub const SSD_BORDER_FRAME_BOTTOM: f64 = 4.0;
|
||||
|
||||
struct FloatColor {
|
||||
r: f64,
|
||||
g: f64,
|
||||
b: f64,
|
||||
}
|
||||
fn lerp_color(a: FloatColor, b: FloatColor, t: f64) -> FloatColor {
|
||||
return FloatColor {
|
||||
r: a.r + (b.r - a.r) * t,
|
||||
g: a.g + (b.g - a.g) * t,
|
||||
b: a.b + (b.b - a.b) * t,
|
||||
};
|
||||
}
|
||||
|
||||
impl DecoratedWindow {
|
||||
pub fn in_ssd(&self, point: &Point<f64, Logical>) -> bool {
|
||||
let loc = self.window.bbox();
|
||||
return (point.x < loc.loc.x as f64 && point.x > loc.loc.x as f64 - SSD_BORDER_FRAME_LEFT)
|
||||
|| (point.x > loc.size.w as f64
|
||||
&& point.x
|
||||
< (loc.size.w as f64 + (SSD_BORDER_FRAME_LEFT + SSD_BORDER_FRAME_RIGHT)))
|
||||
|| point.y < loc.loc.y as f64 && point.y > loc.loc.y as f64 - SSD_BORDER_FRAME_TOP
|
||||
|| (point.y > loc.size.h as f64
|
||||
&& point.y
|
||||
< (loc.size.h as f64 + (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM)));
|
||||
}
|
||||
|
||||
pub fn do_ssd_action(
|
||||
&self,
|
||||
state: &mut State,
|
||||
seat: &Seat<State>,
|
||||
surface: &ToplevelSurface,
|
||||
serial: Serial,
|
||||
point: &Point<f64, Logical>,
|
||||
) {
|
||||
let loc = self.window.bbox();
|
||||
/* leftmost */
|
||||
let leftmost =
|
||||
point.x < loc.loc.x as f64 && point.x > loc.loc.x as f64 - SSD_BORDER_FRAME_LEFT;
|
||||
let rightmost = point.x > loc.size.w as f64
|
||||
&& point.x < (loc.size.w as f64 + (SSD_BORDER_FRAME_LEFT + SSD_BORDER_FRAME_RIGHT));
|
||||
let topmost =
|
||||
point.y < loc.loc.y as f64 && point.y > loc.loc.y as f64 - SSD_BORDER_FRAME_TOP;
|
||||
let bottommost = point.y > loc.size.h as f64
|
||||
&& point.y < (loc.size.h as f64 + (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM));
|
||||
if leftmost {
|
||||
self.do_resize_grab(
|
||||
state,
|
||||
seat,
|
||||
surface,
|
||||
serial,
|
||||
{
|
||||
if topmost {
|
||||
xdg_toplevel::ResizeEdge::TopLeft
|
||||
} else if bottommost {
|
||||
xdg_toplevel::ResizeEdge::BottomLeft
|
||||
} else {
|
||||
xdg_toplevel::ResizeEdge::Left
|
||||
}
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
||||
/* rightmost */
|
||||
else if rightmost {
|
||||
self.do_resize_grab(
|
||||
state,
|
||||
seat,
|
||||
surface,
|
||||
serial,
|
||||
if topmost {
|
||||
xdg_toplevel::ResizeEdge::TopRight
|
||||
} else if bottommost {
|
||||
xdg_toplevel::ResizeEdge::BottomRight
|
||||
} else {
|
||||
xdg_toplevel::ResizeEdge::Right
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
||||
/* topmost */
|
||||
else if topmost {
|
||||
/* title bar */
|
||||
if point.y < loc.loc.y as f64
|
||||
&& point.y > loc.loc.y as f64 - (SSD_BORDER_FRAME_TOP - 5.0)
|
||||
{
|
||||
self.do_move_grab(state, seat, surface, serial, true)
|
||||
} else {
|
||||
/* topmost edge */
|
||||
self.do_resize_grab(
|
||||
state,
|
||||
seat,
|
||||
surface,
|
||||
serial,
|
||||
if leftmost {
|
||||
xdg_toplevel::ResizeEdge::TopLeft
|
||||
} else if rightmost {
|
||||
xdg_toplevel::ResizeEdge::TopRight
|
||||
} else {
|
||||
xdg_toplevel::ResizeEdge::Top
|
||||
},
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
/* bottommost */
|
||||
else if bottommost {
|
||||
self.do_resize_grab(
|
||||
state,
|
||||
seat,
|
||||
surface,
|
||||
serial,
|
||||
if leftmost {
|
||||
xdg_toplevel::ResizeEdge::BottomLeft
|
||||
} else if rightmost {
|
||||
xdg_toplevel::ResizeEdge::BottomRight
|
||||
} else {
|
||||
xdg_toplevel::ResizeEdge::Bottom
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_csd(&self, width: i32, height: i32) -> (Vec<u8>, i32) {
|
||||
let mut surface = ImageSurface::create(Format::ARgb32, width, height).unwrap();
|
||||
let stride = surface.stride();
|
||||
|
||||
{
|
||||
let ctx = Context::new(&surface).unwrap(); // scoped — see note below
|
||||
ctx.set_source_rgba(0.2, 0.2, 0.2, 1.0);
|
||||
ctx.set_line_width(1.0);
|
||||
|
||||
let (w, h) = (width as f64, height as f64);
|
||||
|
||||
macro_rules! do_box {
|
||||
($x:expr, $y:expr, $col:expr, $w:expr, $h:expr) => {
|
||||
ctx.rectangle(($x) as f64, ($y) as f64, ($w) as f64, ($h) as f64);
|
||||
ctx.set_source_rgb(($col) as f64, ($col) as f64, ($col) as f64);
|
||||
ctx.fill().unwrap();
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! do_line {
|
||||
($off:expr, $col:expr) => {
|
||||
ctx.move_to($off, $off);
|
||||
ctx.line_to($off, h - $off);
|
||||
ctx.set_source_rgb($col, $col, $col);
|
||||
ctx.stroke().unwrap();
|
||||
ctx.move_to($off, $off);
|
||||
ctx.line_to(w - $off, $off);
|
||||
ctx.set_source_rgb($col, $col, $col);
|
||||
ctx.stroke().unwrap();
|
||||
};
|
||||
}
|
||||
|
||||
ctx.set_antialias(cairo::Antialias::None);
|
||||
|
||||
/* border */
|
||||
do_box!(0.0, 0.0, 0.14901961, w, h);
|
||||
do_box!(1.0, 1.0, 0.55686275, w - 2.0, h - 2.0);
|
||||
do_box!(2.0, 2.0, 0.82352941, w - 4.0, h - 4.0);
|
||||
do_box!(3.0, 3.0, 0.93333333, w - 6.0, h - 6.0);
|
||||
do_box!(4.0, 4.0, 1.0, w - 8.0, h - 8.0);
|
||||
do_box!(4.0, 4.0, 0.14901961, w - 9.0, h - 9.0);
|
||||
do_line!(1.0, 1.0);
|
||||
do_line!(2.0, 0.93333333);
|
||||
do_line!(3.0, 0.82352941);
|
||||
do_line!(4.0, 0.55686275);
|
||||
do_line!(5.0, 0.14901961);
|
||||
for y in 0..18 {
|
||||
let y = y as f64;
|
||||
let a = FloatColor {
|
||||
r: 0.2627451,
|
||||
g: 0.37254902,
|
||||
b: 0.49411765,
|
||||
};
|
||||
let b = FloatColor {
|
||||
r: 0.05490196,
|
||||
g: 0.17254902,
|
||||
b: 0.30588235,
|
||||
};
|
||||
let c = lerp_color(a, b, y / 18.0);
|
||||
|
||||
ctx.set_source_rgb(c.r, c.g, c.b);
|
||||
|
||||
ctx.move_to(5.0, y + 6.0);
|
||||
ctx.line_to(w as f64 - 5.0, y + 6.0);
|
||||
ctx.stroke().unwrap();
|
||||
}
|
||||
|
||||
/* icon */
|
||||
do_box!(5, 5, 1, 18, 18);
|
||||
do_box!(6, 6, 0.35294118, 17, 17);
|
||||
do_box!(6, 6, 0.82352941, 16, 16);
|
||||
|
||||
/* close */
|
||||
do_box!(
|
||||
w - 18.0 - SSD_BORDER_FRAME_LEFT,
|
||||
SSD_BORDER_FRAME_BOTTOM + 1.0,
|
||||
1,
|
||||
18,
|
||||
18
|
||||
);
|
||||
do_box!(
|
||||
w - 17.0 - SSD_BORDER_FRAME_LEFT,
|
||||
SSD_BORDER_FRAME_BOTTOM + 2.0,
|
||||
0.35294118,
|
||||
17,
|
||||
17
|
||||
);
|
||||
do_box!(
|
||||
w - 17.0 - SSD_BORDER_FRAME_LEFT,
|
||||
SSD_BORDER_FRAME_BOTTOM + 2.0,
|
||||
0.82352941,
|
||||
16,
|
||||
16
|
||||
);
|
||||
do_box!(
|
||||
w - 17.0 - SSD_BORDER_FRAME_LEFT + 5.0,
|
||||
SSD_BORDER_FRAME_BOTTOM + 7.0,
|
||||
0,
|
||||
6,
|
||||
6
|
||||
);
|
||||
do_box!(
|
||||
w - 17.0 - SSD_BORDER_FRAME_LEFT + 6.0,
|
||||
SSD_BORDER_FRAME_BOTTOM + 8.0,
|
||||
0.82352941,
|
||||
4,
|
||||
4
|
||||
);
|
||||
|
||||
/* maxim */
|
||||
do_box!(
|
||||
w - 36.0 - SSD_BORDER_FRAME_LEFT,
|
||||
SSD_BORDER_FRAME_BOTTOM + 1.0,
|
||||
1,
|
||||
18,
|
||||
18
|
||||
);
|
||||
do_box!(
|
||||
w - 35.0 - SSD_BORDER_FRAME_LEFT,
|
||||
SSD_BORDER_FRAME_BOTTOM + 2.0,
|
||||
0.35294118,
|
||||
17,
|
||||
17
|
||||
);
|
||||
do_box!(
|
||||
w - 35.0 - SSD_BORDER_FRAME_LEFT,
|
||||
SSD_BORDER_FRAME_BOTTOM + 2.0,
|
||||
0.82352941,
|
||||
16,
|
||||
16
|
||||
);
|
||||
do_box!(
|
||||
w - 35.0 - SSD_BORDER_FRAME_LEFT + 5.0,
|
||||
SSD_BORDER_FRAME_BOTTOM + 7.0,
|
||||
0,
|
||||
6,
|
||||
6
|
||||
);
|
||||
do_box!(
|
||||
w - 35.0 - SSD_BORDER_FRAME_LEFT,
|
||||
SSD_BORDER_FRAME_BOTTOM + 9.0,
|
||||
0.82352941,
|
||||
16,
|
||||
2
|
||||
);
|
||||
do_box!(
|
||||
w - 35.0 - SSD_BORDER_FRAME_LEFT + 7.0,
|
||||
SSD_BORDER_FRAME_BOTTOM + 4.0,
|
||||
0.82352941,
|
||||
2,
|
||||
14
|
||||
);
|
||||
do_box!(
|
||||
w - 35.0 - SSD_BORDER_FRAME_LEFT + 6.0,
|
||||
SSD_BORDER_FRAME_BOTTOM + 8.0,
|
||||
0.82352941,
|
||||
4,
|
||||
4
|
||||
);
|
||||
|
||||
/* title */
|
||||
ctx.set_antialias(cairo::Antialias::Best);
|
||||
ctx.move_to(28.0, 19.0);
|
||||
ctx.set_font_size(12.0);
|
||||
ctx.select_font_face("", cairo::FontSlant::Normal, cairo::FontWeight::Normal);
|
||||
ctx.text_path(&self.title.lock().clone());
|
||||
ctx.fill().unwrap();
|
||||
} // ctx dropped here
|
||||
|
||||
surface.flush();
|
||||
(surface.data().unwrap().to_vec(), stride)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ use smithay::{
|
|||
winit::{self, WinitEvent},
|
||||
},
|
||||
output::{Mode, Output, PhysicalProperties, Subpixel},
|
||||
utils::{Rectangle, Transform},
|
||||
utils::{Rectangle, Transform, SERIAL_COUNTER},
|
||||
};
|
||||
|
||||
use crate::State;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use smithay::{
|
|||
};
|
||||
use wayland_server::DisplayHandle;
|
||||
|
||||
use crate::{render::DecoratedWindow, state::State};
|
||||
use crate::{state::State, window::DecoratedWindow};
|
||||
|
||||
pub struct XWaylandState {
|
||||
pub xwm: Option<X11Wm>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue