2023-08-01 11:06:35 -05:00
// SPDX-License-Identifier: GPL-3.0-or-later
2023-06-25 17:18:50 -05:00
2023-06-17 18:55:04 -05:00
use std ::{
2023-07-10 17:14:37 -05:00
cell ::RefCell ,
2023-06-17 18:55:04 -05:00
error ::Error ,
2023-06-29 11:58:33 -05:00
ffi ::OsString ,
2023-06-17 18:55:04 -05:00
os ::{ fd ::AsRawFd , unix ::net ::UnixStream } ,
2023-08-08 14:04:42 -05:00
path ::PathBuf ,
2023-06-21 14:48:38 -05:00
process ::Stdio ,
2023-07-16 20:44:18 -05:00
sync ::{ Arc , Mutex } ,
2023-07-24 11:43:47 -05:00
time ::Duration ,
2023-06-17 18:55:04 -05:00
} ;
2023-06-04 18:11:14 -05:00
2023-06-17 21:02:58 -05:00
use crate ::{
2023-06-21 14:48:38 -05:00
api ::{
2023-07-21 14:36:32 -05:00
msg ::{ Args , CallbackId , Msg , OutgoingMsg , Request , RequestId , RequestResponse } ,
2023-06-21 14:48:38 -05:00
PinnacleSocketSource ,
} ,
2023-07-24 11:43:47 -05:00
cursor ::Cursor ,
2023-06-17 21:02:58 -05:00
focus ::FocusState ,
2023-07-10 17:14:37 -05:00
grab ::resize_grab ::ResizeSurfaceState ,
2023-07-18 15:12:23 -05:00
tag ::Tag ,
2023-08-02 10:13:18 -05:00
window ::{
2023-08-11 10:08:38 -05:00
window_state ::{ LocationRequestState , Status } ,
2023-08-02 10:13:18 -05:00
WindowElement ,
} ,
2023-06-17 21:02:58 -05:00
} ;
2023-06-29 11:58:33 -05:00
use calloop ::futures ::Scheduler ;
use futures_lite ::AsyncBufReadExt ;
2023-06-02 16:01:48 -05:00
use smithay ::{
2023-06-09 20:29:17 -05:00
backend ::renderer ::element ::RenderElementStates ,
desktop ::{
2023-07-24 18:59:05 -05:00
space ::SpaceElement ,
2023-06-09 20:29:17 -05:00
utils ::{
surface_presentation_feedback_flags_from_states , surface_primary_scanout_output ,
OutputPresentationFeedback ,
} ,
2023-07-24 18:59:05 -05:00
PopupManager , Space ,
2023-06-09 20:29:17 -05:00
} ,
input ::{ keyboard ::XkbConfig , pointer ::CursorImageStatus , Seat , SeatState } ,
output ::Output ,
2023-06-02 16:01:48 -05:00
reexports ::{
2023-06-17 18:55:04 -05:00
calloop ::{
self , channel ::Event , generic ::Generic , Interest , LoopHandle , LoopSignal , Mode ,
PostAction ,
} ,
2023-06-02 16:01:48 -05:00
wayland_server ::{
backend ::{ ClientData , ClientId , DisconnectReason } ,
2023-07-10 17:14:37 -05:00
protocol ::wl_surface ::WlSurface ,
2023-07-27 17:31:40 -05:00
Display , DisplayHandle ,
2023-06-02 16:01:48 -05:00
} ,
} ,
2023-08-01 21:23:30 -05:00
utils ::{ Clock , IsAlive , Logical , Monotonic , Point , Size } ,
2023-06-02 16:01:48 -05:00
wayland ::{
2023-06-26 18:48:29 -05:00
compositor ::{ self , CompositorClientState , CompositorState } ,
2023-06-02 16:01:48 -05:00
data_device ::DataDeviceState ,
2023-06-09 20:29:17 -05:00
dmabuf ::DmabufFeedback ,
2023-06-04 18:11:14 -05:00
fractional_scale ::FractionalScaleManagerState ,
2023-06-02 16:01:48 -05:00
output ::OutputManagerState ,
2023-08-02 15:12:10 -05:00
primary_selection ::PrimarySelectionState ,
2023-08-04 18:48:10 -05:00
shell ::{
wlr_layer ::WlrLayerShellState ,
xdg ::{ XdgShellState , XdgToplevelSurfaceData } ,
} ,
2023-06-02 16:01:48 -05:00
shm ::ShmState ,
2023-06-09 20:29:17 -05:00
socket ::ListeningSocketSource ,
2023-06-04 18:11:14 -05:00
viewporter ::ViewporterState ,
2023-06-02 16:01:48 -05:00
} ,
2023-07-24 11:43:47 -05:00
xwayland ::{ X11Wm , XWayland , XWaylandEvent } ,
2023-06-02 16:01:48 -05:00
} ;
2023-06-15 16:43:33 -05:00
use crate ::{ backend ::Backend , input ::InputState } ;
2023-06-02 16:01:48 -05:00
2023-06-21 18:58:49 -05:00
/// The main state of the application.
2023-06-02 16:01:48 -05:00
pub struct State < B : Backend > {
pub backend_data : B ,
2023-06-07 12:12:54 -05:00
2023-06-02 16:01:48 -05:00
pub loop_signal : LoopSignal ,
2023-06-09 20:29:17 -05:00
pub loop_handle : LoopHandle < 'static , CalloopData < B > > ,
2023-07-27 17:31:40 -05:00
pub display_handle : DisplayHandle ,
2023-06-02 16:01:48 -05:00
pub clock : Clock < Monotonic > ,
2023-06-07 12:12:54 -05:00
2023-07-24 18:59:05 -05:00
pub space : Space < WindowElement > ,
2023-06-07 12:12:54 -05:00
pub move_mode : bool ,
2023-06-09 20:29:17 -05:00
pub socket_name : String ,
pub seat : Seat < State < B > > ,
2023-06-07 12:12:54 -05:00
2023-06-02 16:01:48 -05:00
pub compositor_state : CompositorState ,
pub data_device_state : DataDeviceState ,
pub seat_state : SeatState < Self > ,
pub shm_state : ShmState ,
pub output_manager_state : OutputManagerState ,
pub xdg_shell_state : XdgShellState ,
2023-06-04 18:11:14 -05:00
pub viewporter_state : ViewporterState ,
pub fractional_scale_manager_state : FractionalScaleManagerState ,
2023-08-02 15:12:10 -05:00
pub primary_selection_state : PrimarySelectionState ,
2023-08-04 18:48:10 -05:00
pub layer_shell_state : WlrLayerShellState ,
2023-08-02 15:12:10 -05:00
2023-06-15 16:43:33 -05:00
pub input_state : InputState ,
2023-06-17 18:55:04 -05:00
pub api_state : ApiState ,
2023-06-17 21:02:58 -05:00
pub focus_state : FocusState ,
2023-06-02 16:01:48 -05:00
2023-06-07 12:12:54 -05:00
pub popup_manager : PopupManager ,
pub cursor_status : CursorImageStatus ,
pub pointer_location : Point < f64 , Logical > ,
2023-08-02 18:18:51 -05:00
pub dnd_icon : Option < WlSurface > ,
2023-07-24 18:59:05 -05:00
pub windows : Vec < WindowElement > ,
2023-06-29 11:58:33 -05:00
pub async_scheduler : Scheduler < ( ) > ,
2023-07-11 11:59:38 -05:00
// TODO: move into own struct
// | basically just clean this mess up
pub output_callback_ids : Vec < CallbackId > ,
2023-07-24 11:43:47 -05:00
pub xwayland : XWayland ,
pub xwm : Option < X11Wm > ,
pub xdisplay : Option < u32 > ,
2023-06-02 16:01:48 -05:00
}
2023-06-05 21:08:37 -05:00
impl < B : Backend > State < B > {
2023-07-02 18:15:44 -05:00
pub fn handle_msg ( & mut self , msg : Msg ) {
2023-07-18 12:37:40 -05:00
// tracing::debug!("Got {msg:?}");
2023-07-02 18:15:44 -05:00
match msg {
Msg ::SetKeybind {
key ,
modifiers ,
callback_id ,
} = > {
tracing ::info! ( " set keybind: {:?}, {} " , modifiers , key ) ;
self . input_state
. keybinds
. insert ( ( modifiers . into ( ) , key ) , callback_id ) ;
}
2023-07-18 15:12:23 -05:00
Msg ::SetMousebind { button : _ } = > todo! ( ) ,
Msg ::CloseWindow { window_id } = > {
2023-07-18 21:10:43 -05:00
if let Some ( window ) = window_id . window ( self ) {
2023-07-24 18:59:05 -05:00
match window {
WindowElement ::Wayland ( window ) = > window . toplevel ( ) . send_close ( ) ,
WindowElement ::X11 ( surface ) = > {
surface . close ( ) . expect ( " failed to close x11 win " ) ;
}
}
2023-07-02 18:15:44 -05:00
}
}
2023-07-18 15:12:23 -05:00
Msg ::ToggleFloating { window_id } = > {
2023-07-18 21:10:43 -05:00
if let Some ( window ) = window_id . window ( self ) {
2023-07-02 18:15:44 -05:00
crate ::window ::toggle_floating ( self , & window ) ;
}
}
2023-06-09 20:29:17 -05:00
2023-07-02 18:15:44 -05:00
Msg ::Spawn {
command ,
callback_id ,
} = > {
self . handle_spawn ( command , callback_id ) ;
}
2023-06-28 16:41:36 -05:00
2023-07-18 21:10:43 -05:00
Msg ::SetWindowSize {
window_id ,
width ,
height ,
} = > {
let Some ( window ) = window_id . window ( self ) else { return } ;
2023-06-09 20:29:17 -05:00
2023-07-02 18:15:44 -05:00
// TODO: tiled vs floating
2023-07-24 18:59:05 -05:00
// FIXME: this will map unmapped windows at 0,0
let window_loc = self
. space
. element_location ( & window )
. unwrap_or ( ( 0 , 0 ) . into ( ) ) ;
2023-07-28 14:33:14 -05:00
let mut window_size = window . geometry ( ) . size ;
if let Some ( width ) = width {
window_size . w = width ;
}
if let Some ( height ) = height {
window_size . h = height ;
}
2023-08-07 11:25:36 -05:00
window . request_size_change ( & mut self . space , window_loc , window_size ) ;
2023-07-02 18:15:44 -05:00
}
Msg ::MoveWindowToTag { window_id , tag_id } = > {
2023-07-21 11:38:46 -05:00
let Some ( window ) = window_id . window ( self ) else { return } ;
let Some ( tag ) = tag_id . tag ( self ) else { return } ;
window . with_state ( | state | {
state . tags = vec! [ tag . clone ( ) ] ;
} ) ;
let Some ( output ) = tag . output ( self ) else { return } ;
2023-08-11 10:08:38 -05:00
self . update_windows ( & output ) ;
// self.re_layout(&output);
2023-07-02 18:15:44 -05:00
}
Msg ::ToggleTagOnWindow { window_id , tag_id } = > {
2023-07-21 11:38:46 -05:00
let Some ( window ) = window_id . window ( self ) else { return } ;
let Some ( tag ) = tag_id . tag ( self ) else { return } ;
window . with_state ( | state | {
if state . tags . contains ( & tag ) {
state . tags . retain ( | tg | tg ! = & tag ) ;
} else {
state . tags . push ( tag . clone ( ) ) ;
}
} ) ;
2023-06-21 14:48:38 -05:00
2023-07-21 11:38:46 -05:00
let Some ( output ) = tag . output ( self ) else { return } ;
2023-08-11 10:08:38 -05:00
self . update_windows ( & output ) ;
// self.re_layout(&output);
2023-07-02 18:15:44 -05:00
}
2023-08-11 18:48:51 -05:00
Msg ::SetStatus { window_id , status } = > {
let Some ( window ) = window_id . window ( self ) else { return } ;
window . set_status ( status ) ;
let outputs = self . space . outputs_for_element ( & window ) ;
self . focus_state . set_focus ( window ) ;
if let Some ( output ) = outputs . into_iter ( ) . next ( ) {
self . update_windows ( & output ) ;
}
}
// Tags ----------------------------------------
2023-07-21 11:38:46 -05:00
Msg ::ToggleTag { tag_id } = > {
2023-07-11 16:10:31 -05:00
tracing ::debug! ( " ToggleTag " ) ;
2023-07-21 11:38:46 -05:00
if let Some ( tag ) = tag_id . tag ( self ) {
tag . set_active ( ! tag . active ( ) ) ;
if let Some ( output ) = tag . output ( self ) {
2023-08-11 10:08:38 -05:00
self . update_windows ( & output ) ;
// self.re_layout(&output);
2023-07-21 11:38:46 -05:00
}
2023-07-11 16:10:31 -05:00
}
2023-07-02 18:15:44 -05:00
}
2023-07-21 11:38:46 -05:00
Msg ::SwitchToTag { tag_id } = > {
let Some ( tag ) = tag_id . tag ( self ) else { return } ;
let Some ( output ) = tag . output ( self ) else { return } ;
output . with_state ( | state | {
for op_tag in state . tags . iter_mut ( ) {
op_tag . set_active ( false ) ;
}
tag . set_active ( true ) ;
} ) ;
2023-08-11 10:08:38 -05:00
self . update_windows ( & output ) ;
// self.re_layout(&output);
2023-07-02 18:15:44 -05:00
}
2023-07-18 21:10:43 -05:00
Msg ::AddTags {
output_name ,
tag_names ,
} = > {
2023-07-04 21:27:23 -05:00
if let Some ( output ) = self
2023-07-11 11:59:38 -05:00
. space
. outputs ( )
. find ( | output | output . name ( ) = = output_name )
2023-07-04 21:27:23 -05:00
{
2023-07-10 17:14:37 -05:00
output . with_state ( | state | {
2023-07-18 21:10:43 -05:00
state . tags . extend ( tag_names . iter ( ) . cloned ( ) . map ( Tag ::new ) ) ;
2023-07-11 16:10:31 -05:00
tracing ::debug! ( " tags added, are now {:?} " , state . tags ) ;
2023-07-09 17:48:46 -05:00
} ) ;
2023-07-04 21:27:23 -05:00
}
2023-07-02 18:15:44 -05:00
}
2023-07-21 11:38:46 -05:00
Msg ::RemoveTags { tag_ids } = > {
let tags = tag_ids . into_iter ( ) . filter_map ( | tag_id | tag_id . tag ( self ) ) ;
for tag in tags {
let Some ( output ) = tag . output ( self ) else { continue } ;
2023-07-10 17:14:37 -05:00
output . with_state ( | state | {
2023-07-21 11:38:46 -05:00
state . tags . retain ( | tg | tg ! = & tag ) ;
2023-07-09 17:48:46 -05:00
} ) ;
}
2023-07-02 18:15:44 -05:00
}
2023-07-21 11:38:46 -05:00
Msg ::SetLayout { tag_id , layout } = > {
let Some ( tag ) = tag_id . tag ( self ) else { return } ;
tag . set_layout ( layout ) ;
let Some ( output ) = tag . output ( self ) else { return } ;
2023-08-11 10:08:38 -05:00
self . update_windows ( & output ) ;
// self.re_layout(&output);
2023-07-12 18:50:41 -05:00
}
2023-06-26 18:48:29 -05:00
2023-07-11 11:59:38 -05:00
Msg ::ConnectForAllOutputs { callback_id } = > {
let stream = self
. api_state
. stream
. as_ref ( )
. expect ( " Stream doesn't exist " ) ;
let mut stream = stream . lock ( ) . expect ( " Couldn't lock stream " ) ;
for output in self . space . outputs ( ) {
crate ::api ::send_to_client (
& mut stream ,
& OutgoingMsg ::CallCallback {
callback_id ,
args : Some ( Args ::ConnectForAllOutputs {
output_name : output . name ( ) ,
} ) ,
} ,
)
. expect ( " Send to client failed " ) ;
}
self . output_callback_ids . push ( callback_id ) ;
}
2023-08-04 13:45:38 -05:00
Msg ::SetOutputLocation { output_name , x , y } = > {
let Some ( output ) = output_name . output ( self ) else { return } ;
let mut loc = output . current_location ( ) ;
if let Some ( x ) = x {
loc . x = x ;
}
if let Some ( y ) = y {
loc . y = y ;
}
output . change_current_state ( None , None , None , Some ( loc ) ) ;
self . space . map_output ( & output , loc ) ;
tracing ::debug! ( " mapping output {} to {loc:?} " , output . name ( ) ) ;
2023-08-11 10:08:38 -05:00
self . update_windows ( & output ) ;
// self.re_layout(&output);
2023-08-04 13:45:38 -05:00
}
2023-07-11 11:59:38 -05:00
2023-07-02 18:15:44 -05:00
Msg ::Quit = > {
self . loop_signal . stop ( ) ;
}
2023-07-21 14:36:32 -05:00
Msg ::Request {
request_id ,
request ,
} = > {
self . handle_request ( request_id , request ) ;
2023-07-18 21:10:43 -05:00
}
}
}
2023-07-21 14:36:32 -05:00
fn handle_request ( & mut self , request_id : RequestId , request : Request ) {
2023-07-18 21:10:43 -05:00
let stream = self
. api_state
. stream
. as_ref ( )
. expect ( " Stream doesn't exist " ) ;
let mut stream = stream . lock ( ) . expect ( " Couldn't lock stream " ) ;
match request {
2023-07-19 20:11:15 -05:00
Request ::GetWindows = > {
2023-07-18 21:10:43 -05:00
let window_ids = self
. windows
. iter ( )
. map ( | win | win . with_state ( | state | state . id ) )
. collect ::< Vec < _ > > ( ) ;
// FIXME: figure out what to do if error
crate ::api ::send_to_client (
& mut stream ,
& OutgoingMsg ::RequestResponse {
2023-07-21 14:36:32 -05:00
request_id ,
2023-07-18 21:10:43 -05:00
response : RequestResponse ::Windows { window_ids } ,
} ,
)
. expect ( " Couldn't send to client " ) ;
}
2023-07-19 20:11:15 -05:00
Request ::GetWindowProps { window_id } = > {
let window = window_id . window ( self ) ;
let size = window
. as_ref ( )
2023-07-18 21:10:43 -05:00
. map ( | win | ( win . geometry ( ) . size . w , win . geometry ( ) . size . h ) ) ;
2023-07-19 20:11:15 -05:00
let loc = window
. as_ref ( )
. and_then ( | win | self . space . element_location ( win ) )
2023-07-18 21:10:43 -05:00
. map ( | loc | ( loc . x , loc . y ) ) ;
2023-07-25 10:23:34 -05:00
let ( class , title ) = window . as_ref ( ) . map_or ( ( None , None ) , | win | match & win {
WindowElement ::Wayland ( _ ) = > {
if let Some ( wl_surf ) = win . wl_surface ( ) {
compositor ::with_states ( & wl_surf , | states | {
let lock = states
. data_map
. get ::< XdgToplevelSurfaceData > ( )
. expect ( " XdgToplevelSurfaceData wasn't in surface's data map " )
. lock ( )
. expect ( " failed to acquire lock " ) ;
( lock . app_id . clone ( ) , lock . title . clone ( ) )
} )
} else {
( None , None )
}
}
WindowElement ::X11 ( surface ) = > ( Some ( surface . class ( ) ) , Some ( surface . title ( ) ) ) ,
} ) ;
2023-07-19 20:11:15 -05:00
let floating = window
. as_ref ( )
2023-08-11 10:08:38 -05:00
. map ( | win | win . with_state ( | state | state . status . is_floating ( ) ) ) ;
2023-07-19 20:11:15 -05:00
let focused = window . as_ref ( ) . and_then ( | win | {
self . focus_state
. current_focus ( ) // TODO: actual focus
. map ( | foc_win | win = = & foc_win )
} ) ;
2023-07-18 21:10:43 -05:00
crate ::api ::send_to_client (
& mut stream ,
& OutgoingMsg ::RequestResponse {
2023-07-21 14:36:32 -05:00
request_id ,
2023-07-19 20:11:15 -05:00
response : RequestResponse ::WindowProps {
size ,
loc ,
class ,
title ,
floating ,
focused ,
} ,
2023-07-18 21:10:43 -05:00
} ,
)
. expect ( " failed to send to client " ) ;
}
2023-07-19 18:55:22 -05:00
Request ::GetOutputs = > {
let output_names = self
2023-07-18 21:10:43 -05:00
. space
. outputs ( )
. map ( | output | output . name ( ) )
. collect ::< Vec < _ > > ( ) ;
crate ::api ::send_to_client (
& mut stream ,
& OutgoingMsg ::RequestResponse {
2023-07-21 14:36:32 -05:00
request_id ,
2023-07-19 18:55:22 -05:00
response : RequestResponse ::Outputs { output_names } ,
2023-07-18 21:10:43 -05:00
} ,
)
. expect ( " failed to send to client " ) ;
}
2023-07-19 18:55:22 -05:00
Request ::GetOutputProps { output_name } = > {
let output = self
2023-07-18 21:10:43 -05:00
. space
. outputs ( )
2023-07-19 18:55:22 -05:00
. find ( | output | output . name ( ) = = output_name ) ;
let res = output . as_ref ( ) . and_then ( | output | {
output . current_mode ( ) . map ( | mode | ( mode . size . w , mode . size . h ) )
} ) ;
let refresh_rate = output
. as_ref ( )
. and_then ( | output | output . current_mode ( ) . map ( | mode | mode . refresh ) ) ;
let model = output
. as_ref ( )
. map ( | output | output . physical_properties ( ) . model ) ;
let physical_size = output . as_ref ( ) . map ( | output | {
(
output . physical_properties ( ) . size . w ,
output . physical_properties ( ) . size . h ,
)
} ) ;
let make = output
. as_ref ( )
. map ( | output | output . physical_properties ( ) . make ) ;
let loc = output
. as_ref ( )
. map ( | output | ( output . current_location ( ) . x , output . current_location ( ) . y ) ) ;
let focused = self
2023-07-18 21:10:43 -05:00
. focus_state
. focused_output
. as_ref ( )
2023-07-19 18:55:22 -05:00
. and_then ( | foc_op | output . map ( | op | op = = foc_op ) ) ;
2023-07-20 15:22:22 -05:00
let tag_ids = output . as_ref ( ) . map ( | output | {
output . with_state ( | state | {
state . tags . iter ( ) . map ( | tag | tag . id ( ) ) . collect ::< Vec < _ > > ( )
} )
} ) ;
2023-07-18 21:10:43 -05:00
crate ::api ::send_to_client (
& mut stream ,
& OutgoingMsg ::RequestResponse {
2023-07-21 14:36:32 -05:00
request_id ,
2023-07-19 18:55:22 -05:00
response : RequestResponse ::OutputProps {
make ,
model ,
loc ,
res ,
refresh_rate ,
physical_size ,
focused ,
2023-07-20 15:22:22 -05:00
tag_ids ,
2023-07-19 18:55:22 -05:00
} ,
2023-07-18 21:10:43 -05:00
} ,
)
. expect ( " failed to send to client " ) ;
}
2023-07-20 16:05:26 -05:00
Request ::GetTags = > {
2023-07-19 18:55:22 -05:00
let tag_ids = self
2023-07-18 21:10:43 -05:00
. space
. outputs ( )
. flat_map ( | op | op . with_state ( | state | state . tags . clone ( ) ) )
2023-07-19 18:55:22 -05:00
. map ( | tag | tag . id ( ) )
. collect ::< Vec < _ > > ( ) ;
2023-07-21 14:36:32 -05:00
tracing ::debug! ( " GetTags: {:?} " , tag_ids ) ;
2023-07-19 18:55:22 -05:00
crate ::api ::send_to_client (
& mut stream ,
& OutgoingMsg ::RequestResponse {
2023-07-21 14:36:32 -05:00
request_id ,
2023-07-19 18:55:22 -05:00
response : RequestResponse ::Tags { tag_ids } ,
} ,
)
. expect ( " failed to send to client " ) ;
}
2023-07-20 16:05:26 -05:00
Request ::GetTagProps { tag_id } = > {
let tag = tag_id . tag ( self ) ;
let output_name = tag
. as_ref ( )
2023-07-19 18:55:22 -05:00
. and_then ( | tag | tag . output ( self ) )
. map ( | output | output . name ( ) ) ;
2023-07-20 16:05:26 -05:00
let active = tag . as_ref ( ) . map ( | tag | tag . active ( ) ) ;
let name = tag . as_ref ( ) . map ( | tag | tag . name ( ) ) ;
2023-07-19 18:55:22 -05:00
crate ::api ::send_to_client (
& mut stream ,
& OutgoingMsg ::RequestResponse {
2023-07-21 14:36:32 -05:00
request_id ,
2023-07-20 16:05:26 -05:00
response : RequestResponse ::TagProps {
active ,
name ,
output_name ,
} ,
2023-07-19 18:55:22 -05:00
} ,
)
. expect ( " failed to send to client " ) ;
2023-07-18 21:10:43 -05:00
}
2023-07-01 19:06:37 -05:00
}
2023-06-09 20:29:17 -05:00
}
2023-06-28 16:41:36 -05:00
pub fn handle_spawn ( & self , command : Vec < String > , callback_id : Option < CallbackId > ) {
2023-06-29 17:41:08 -05:00
let mut command = command . into_iter ( ) ;
let Some ( program ) = command . next ( ) else {
2023-06-28 16:41:36 -05:00
// TODO: notify that command was nothing
return ;
2023-06-29 17:41:08 -05:00
} ;
2023-06-28 16:41:36 -05:00
2023-06-29 17:41:08 -05:00
let program = OsString ::from ( program ) ;
let Ok ( mut child ) = async_process ::Command ::new ( & program )
2023-07-24 18:59:05 -05:00
. envs (
[ ( " WAYLAND_DISPLAY " , self . socket_name . clone ( ) ) ]
. into_iter ( )
. chain (
self . xdisplay . map ( | xdisp | ( " DISPLAY " , format! ( " : {xdisp} " ) ) )
)
)
2023-06-28 16:41:36 -05:00
. stdin ( if callback_id . is_some ( ) {
Stdio ::piped ( )
} else {
// piping to null because foot won't open without a callback_id
// otherwise
Stdio ::null ( )
} )
. stdout ( if callback_id . is_some ( ) {
Stdio ::piped ( )
} else {
Stdio ::null ( )
} )
. stderr ( if callback_id . is_some ( ) {
Stdio ::piped ( )
} else {
Stdio ::null ( )
} )
. args ( command )
. spawn ( )
2023-06-29 17:41:08 -05:00
else {
// TODO: notify user that program doesn't exist
tracing ::warn! ( " tried to run {}, but it doesn't exist " , program . to_string_lossy ( ) ) ;
return ;
} ;
2023-06-28 16:41:36 -05:00
if let Some ( callback_id ) = callback_id {
let stdout = child . stdout . take ( ) ;
let stderr = child . stderr . take ( ) ;
2023-07-02 18:15:44 -05:00
let stream_out = self
. api_state
. stream
. as_ref ( )
. expect ( " Stream doesn't exist " )
. clone ( ) ;
2023-06-28 16:41:36 -05:00
let stream_err = stream_out . clone ( ) ;
let stream_exit = stream_out . clone ( ) ;
if let Some ( stdout ) = stdout {
2023-06-29 11:58:33 -05:00
let future = async move {
// TODO: use BufReader::new().lines()
let mut reader = futures_lite ::io ::BufReader ::new ( stdout ) ;
2023-06-28 16:41:36 -05:00
loop {
let mut buf = String ::new ( ) ;
2023-06-29 11:58:33 -05:00
match reader . read_line ( & mut buf ) . await {
Ok ( 0 ) = > break ,
2023-06-28 16:41:36 -05:00
Ok ( _ ) = > {
2023-06-29 17:41:08 -05:00
let mut stream = stream_out . lock ( ) . expect ( " Couldn't lock stream " ) ;
2023-06-28 16:41:36 -05:00
crate ::api ::send_to_client (
& mut stream ,
& OutgoingMsg ::CallCallback {
callback_id ,
args : Some ( Args ::Spawn {
stdout : Some ( buf . trim_end_matches ( '\n' ) . to_string ( ) ) ,
stderr : None ,
exit_code : None ,
exit_msg : None ,
} ) ,
} ,
)
2023-06-29 17:41:08 -05:00
. expect ( " Send to client failed " ) ; // TODO: notify instead of crash
2023-06-28 16:41:36 -05:00
}
Err ( err ) = > {
2023-06-29 11:58:33 -05:00
tracing ::warn! ( " child read err: {err} " ) ;
2023-06-28 16:41:36 -05:00
break ;
2023-07-02 18:15:44 -05:00
}
2023-06-28 16:41:36 -05:00
}
}
2023-06-29 11:58:33 -05:00
} ;
2023-06-29 17:41:08 -05:00
// This is not important enough to crash on error, so just print the error instead
if let Err ( err ) = self . async_scheduler . schedule ( future ) {
tracing ::error! ( " Failed to schedule future: {err} " ) ;
}
2023-06-28 16:41:36 -05:00
}
if let Some ( stderr ) = stderr {
2023-06-29 11:58:33 -05:00
let future = async move {
let mut reader = futures_lite ::io ::BufReader ::new ( stderr ) ;
2023-06-28 16:41:36 -05:00
loop {
let mut buf = String ::new ( ) ;
2023-06-29 11:58:33 -05:00
match reader . read_line ( & mut buf ) . await {
Ok ( 0 ) = > break ,
2023-06-28 16:41:36 -05:00
Ok ( _ ) = > {
2023-06-29 17:41:08 -05:00
let mut stream = stream_err . lock ( ) . expect ( " Couldn't lock stream " ) ;
2023-06-28 16:41:36 -05:00
crate ::api ::send_to_client (
& mut stream ,
& OutgoingMsg ::CallCallback {
callback_id ,
args : Some ( Args ::Spawn {
stdout : None ,
stderr : Some ( buf . trim_end_matches ( '\n' ) . to_string ( ) ) ,
exit_code : None ,
exit_msg : None ,
} ) ,
} ,
)
2023-06-29 17:41:08 -05:00
. expect ( " Send to client failed " ) ; // TODO: notify instead of crash
2023-06-28 16:41:36 -05:00
}
Err ( err ) = > {
2023-06-29 11:58:33 -05:00
tracing ::warn! ( " child read err: {err} " ) ;
2023-06-28 16:41:36 -05:00
break ;
2023-07-02 18:15:44 -05:00
}
2023-06-28 16:41:36 -05:00
}
}
2023-06-29 11:58:33 -05:00
} ;
2023-06-29 17:41:08 -05:00
if let Err ( err ) = self . async_scheduler . schedule ( future ) {
tracing ::error! ( " Failed to schedule future: {err} " ) ;
}
2023-06-28 16:41:36 -05:00
}
2023-06-29 11:58:33 -05:00
let future = async move {
match child . status ( ) . await {
Ok ( exit_status ) = > {
2023-06-29 17:41:08 -05:00
let mut stream = stream_exit . lock ( ) . expect ( " Couldn't lock stream " ) ;
2023-06-29 11:58:33 -05:00
crate ::api ::send_to_client (
& mut stream ,
& OutgoingMsg ::CallCallback {
callback_id ,
args : Some ( Args ::Spawn {
stdout : None ,
stderr : None ,
exit_code : exit_status . code ( ) ,
exit_msg : Some ( exit_status . to_string ( ) ) ,
} ) ,
} ,
)
2023-06-29 17:41:08 -05:00
. expect ( " Send to client failed " ) ; // TODO: notify instead of crash
2023-06-29 11:58:33 -05:00
}
Err ( err ) = > {
tracing ::warn! ( " child wait() err: {err} " ) ;
}
2023-06-28 16:41:36 -05:00
}
2023-06-29 11:58:33 -05:00
} ;
2023-06-29 17:41:08 -05:00
if let Err ( err ) = self . async_scheduler . schedule ( future ) {
tracing ::error! ( " Failed to schedule future: {err} " ) ;
}
2023-06-28 16:41:36 -05:00
}
}
2023-07-02 10:26:07 -05:00
2023-07-11 16:10:31 -05:00
pub fn re_layout ( & mut self , output : & Output ) {
2023-07-18 21:10:43 -05:00
let windows = self
. windows
. iter ( )
. filter ( | win | {
win . with_state ( | state | {
state
. tags
. iter ( )
2023-07-19 18:55:22 -05:00
. any ( | tag | tag . output ( self ) . is_some_and ( | op | & op = = output ) )
2023-07-18 21:10:43 -05:00
} )
} )
. cloned ( )
. collect ::< Vec < _ > > ( ) ;
2023-07-10 17:14:37 -05:00
let ( render , do_not_render ) = output . with_state ( | state | {
2023-07-11 21:07:51 -05:00
let first_tag = state . focused_tags ( ) . next ( ) ;
if let Some ( first_tag ) = first_tag {
first_tag . layout ( ) . layout (
self . windows . clone ( ) ,
state . focused_tags ( ) . cloned ( ) . collect ( ) ,
2023-08-07 11:25:36 -05:00
& mut self . space ,
2023-07-11 16:10:31 -05:00
output ,
2023-07-11 21:07:51 -05:00
) ;
}
2023-07-11 16:10:31 -05:00
windows . iter ( ) . cloned ( ) . partition ::< Vec < _ > , _ > ( | win | {
2023-07-10 17:14:37 -05:00
win . with_state ( | win_state | {
2023-08-02 10:13:18 -05:00
win_state
. tags
. iter ( )
. any ( | tag | state . focused_tags ( ) . any ( | tg | tag = = tg ) )
2023-07-09 20:33:25 -05:00
} )
} )
} ) ;
2023-07-26 16:01:53 -05:00
tracing ::debug! (
" {} to render, {} to not render " ,
render . len ( ) ,
do_not_render . len ( )
) ;
2023-07-16 20:44:18 -05:00
let clone = render . clone ( ) ;
2023-07-09 20:33:25 -05:00
self . loop_handle . insert_idle ( | data | {
2023-08-02 10:13:18 -05:00
schedule_on_commit ( data , clone . clone ( ) , | dt | {
2023-07-16 20:44:18 -05:00
for win in do_not_render {
dt . state . space . unmap_elem ( & win ) ;
2023-07-26 16:01:53 -05:00
if let WindowElement ::X11 ( surface ) = win {
if ! surface . is_override_redirect ( ) {
surface . set_mapped ( false ) . expect ( " failed to unmap x11 win " ) ;
}
}
2023-07-02 10:26:07 -05:00
}
2023-07-02 18:15:44 -05:00
2023-08-11 10:08:38 -05:00
for ( win , rect ) in
clone
. into_iter ( )
. filter_map ( | win | match win . with_state ( | state | state . status ) {
Status ::Floating ( loc ) = > Some ( ( win , loc ) ) ,
_ = > None ,
} )
{
2023-08-02 19:45:56 -05:00
if let WindowElement ::X11 ( surface ) = & win {
2023-08-11 10:08:38 -05:00
if ! surface . is_override_redirect ( ) {
surface . set_mapped ( true ) . expect ( " failed to map x11 win " ) ;
}
2023-08-02 19:45:56 -05:00
}
2023-08-11 10:08:38 -05:00
dt . state . space . map_element ( win , rect . loc , false ) ;
2023-08-02 10:13:18 -05:00
}
} ) ;
} ) ;
2023-07-16 20:44:18 -05:00
}
}
2023-08-02 10:13:18 -05:00
2023-07-16 20:44:18 -05:00
/// Schedule something to be done when windows have finished committing and have become
/// idle.
2023-07-18 21:10:43 -05:00
pub fn schedule_on_commit < F , B : Backend > (
data : & mut CalloopData < B > ,
2023-07-24 18:59:05 -05:00
windows : Vec < WindowElement > ,
2023-07-18 21:10:43 -05:00
on_commit : F ,
) where
2023-07-16 20:44:18 -05:00
F : FnOnce ( & mut CalloopData < B > ) + 'static ,
{
2023-08-01 21:23:30 -05:00
for window in windows . iter ( ) . filter ( | win | win . alive ( ) ) {
2023-08-11 10:08:38 -05:00
if window . with_state ( | state | ! matches! ( state . loc_request_state , LocationRequestState ::Idle ) )
{
2023-08-11 18:48:51 -05:00
tracing ::debug! (
" window state is {:?} " ,
window . with_state ( | state | state . loc_request_state . clone ( ) )
) ;
2023-07-16 20:44:18 -05:00
data . state . loop_handle . insert_idle ( | data | {
schedule_on_commit ( data , windows , on_commit ) ;
} ) ;
return ;
}
2023-07-02 18:15:44 -05:00
}
2023-07-16 20:44:18 -05:00
on_commit ( data ) ;
2023-07-02 18:15:44 -05:00
}
2023-08-07 12:58:06 -05:00
// Schedule something to be done when `condition` returns true.
pub fn schedule < F1 , F2 , B : Backend > ( data : & mut CalloopData < B > , condition : F1 , run : F2 )
where
F1 : Fn ( & mut CalloopData < B > ) -> bool + 'static ,
F2 : FnOnce ( & mut CalloopData < B > ) + 'static ,
{
if ! condition ( data ) {
data . state . loop_handle . insert_idle ( | data | {
schedule ( data , condition , run ) ;
} ) ;
return ;
}
run ( data ) ;
}
2023-07-04 21:27:23 -05:00
impl < B : Backend > State < B > {
2023-07-02 18:15:44 -05:00
pub fn init (
2023-07-04 21:27:23 -05:00
backend_data : B ,
2023-07-02 18:15:44 -05:00
display : & mut Display < Self > ,
loop_signal : LoopSignal ,
2023-07-04 21:27:23 -05:00
loop_handle : LoopHandle < 'static , CalloopData < B > > ,
2023-07-02 18:15:44 -05:00
) -> Result < Self , Box < dyn Error > > {
let socket = ListeningSocketSource ::new_auto ( ) ? ;
let socket_name = socket . socket_name ( ) . to_os_string ( ) ;
std ::env ::set_var ( " WAYLAND_DISPLAY " , socket_name . clone ( ) ) ;
2023-08-06 19:41:48 -05:00
tracing ::info! (
" Set WAYLAND_DISPLAY to {} " ,
socket_name . clone ( ) . to_string_lossy ( )
) ;
2023-07-02 18:15:44 -05:00
// Opening a new process will use up a few file descriptors, around 10 for Alacritty, for
// example. Because of this, opening up only around 100 processes would exhaust the file
// descriptor limit on my system (Arch btw) and cause a "Too many open files" crash.
//
// To fix this, I just set the limit to be higher. As Pinnacle is the whole graphical
// environment, I *think* this is ok.
2023-08-06 19:41:48 -05:00
tracing ::info! ( " Trying to raise file descriptor limit... " ) ;
2023-07-02 18:15:44 -05:00
if let Err ( err ) = smithay ::reexports ::nix ::sys ::resource ::setrlimit (
smithay ::reexports ::nix ::sys ::resource ::Resource ::RLIMIT_NOFILE ,
65536 ,
65536 * 2 ,
) {
tracing ::error! ( " Could not raise fd limit: errno {err} " ) ;
2023-08-06 19:41:48 -05:00
} else {
tracing ::info! ( " Fd raise success! " ) ;
2023-07-02 18:15:44 -05:00
}
loop_handle . insert_source ( socket , | stream , _metadata , data | {
data . display
. handle ( )
. insert_client ( stream , Arc ::new ( ClientState ::default ( ) ) )
. expect ( " Could not insert client into loop handle " ) ;
} ) ? ;
loop_handle . insert_source (
Generic ::new (
display . backend ( ) . poll_fd ( ) . as_raw_fd ( ) ,
Interest ::READ ,
Mode ::Level ,
) ,
| _readiness , _metadata , data | {
data . display . dispatch_clients ( & mut data . state ) ? ;
Ok ( PostAction ::Continue )
} ,
) ? ;
let ( tx_channel , rx_channel ) = calloop ::channel ::channel ::< Msg > ( ) ;
// We want to replace the client if a new one pops up
// TODO: there should only ever be one client working at a time, and creating a new client
// | when one is already running should be impossible.
// INFO: this source try_clone()s the stream
2023-08-06 19:41:48 -05:00
// TODO: probably use anyhow or something
let socket_source = match PinnacleSocketSource ::new ( tx_channel ) {
Ok ( source ) = > source ,
Err ( err ) = > {
tracing ::error! ( " Failed to create the socket source: {err} " ) ;
Err ( err ) ?
}
} ;
loop_handle . insert_source ( socket_source , | stream , _ , data | {
2023-07-02 18:15:44 -05:00
if let Some ( old_stream ) = data
. state
. api_state
. stream
. replace ( Arc ::new ( Mutex ::new ( stream ) ) )
{
old_stream
. lock ( )
. expect ( " Couldn't lock old stream " )
. shutdown ( std ::net ::Shutdown ::Both )
. expect ( " Couldn't shutdown old stream " ) ;
}
} ) ? ;
let ( executor , sched ) =
calloop ::futures ::executor ::< ( ) > ( ) . expect ( " Couldn't create executor " ) ;
loop_handle . insert_source ( executor , | _ , _ , _ | { } ) ? ;
2023-08-08 14:04:42 -05:00
start_lua_config ( ) ? ;
2023-07-02 18:15:44 -05:00
let display_handle = display . handle ( ) ;
let mut seat_state = SeatState ::new ( ) ;
let mut seat = seat_state . new_wl_seat ( & display_handle , backend_data . seat_name ( ) ) ;
seat . add_pointer ( ) ;
seat . add_keyboard ( XkbConfig ::default ( ) , 200 , 25 ) ? ;
loop_handle . insert_idle ( | data | {
data . state
. loop_handle
. insert_source ( rx_channel , | msg , _ , data | match msg {
Event ::Msg ( msg ) = > data . state . handle_msg ( msg ) ,
Event ::Closed = > todo! ( ) ,
2023-07-02 10:26:07 -05:00
} )
2023-07-24 11:43:47 -05:00
. expect ( " failed to insert rx_channel into loop " ) ;
2023-07-02 10:26:07 -05:00
} ) ;
2023-07-24 18:59:05 -05:00
tracing ::debug! ( " before xwayland " ) ;
2023-07-24 11:43:47 -05:00
let xwayland = {
let ( xwayland , channel ) = XWayland ::new ( & display_handle ) ;
let clone = display_handle . clone ( ) ;
2023-07-24 18:59:05 -05:00
tracing ::debug! ( " inserting into loop " ) ;
let res = loop_handle . insert_source ( channel , move | event , _ , data | match event {
XWaylandEvent ::Ready {
connection ,
client ,
client_fd : _ ,
display ,
} = > {
tracing ::debug! ( " XWaylandEvent ready " ) ;
let mut wm = X11Wm ::start_wm (
data . state . loop_handle . clone ( ) ,
clone . clone ( ) ,
2023-07-24 11:43:47 -05:00
connection ,
client ,
2023-07-24 18:59:05 -05:00
)
. expect ( " failed to attach x11wm " ) ;
let cursor = Cursor ::load ( ) ;
let image = cursor . get_image ( 1 , Duration ::ZERO ) ;
wm . set_cursor (
& image . pixels_rgba ,
Size ::from ( ( image . width as u16 , image . height as u16 ) ) ,
Point ::from ( ( image . xhot as u16 , image . yhot as u16 ) ) ,
)
. expect ( " failed to set xwayland default cursor " ) ;
tracing ::debug! ( " setting xwm and xdisplay " ) ;
data . state . xwm = Some ( wm ) ;
data . state . xdisplay = Some ( display ) ;
}
XWaylandEvent ::Exited = > {
data . state . xwm . take ( ) ;
}
} ) ;
2023-07-24 11:43:47 -05:00
if let Err ( err ) = res {
tracing ::error! ( " Failed to insert XWayland source into loop: {err} " ) ;
}
xwayland
} ;
2023-07-24 18:59:05 -05:00
tracing ::debug! ( " after xwayland " ) ;
2023-07-24 11:43:47 -05:00
2023-07-02 18:15:44 -05:00
Ok ( Self {
backend_data ,
loop_signal ,
loop_handle ,
2023-07-27 17:31:40 -05:00
display_handle : display_handle . clone ( ) ,
2023-07-02 18:15:44 -05:00
clock : Clock ::< Monotonic > ::new ( ) ? ,
compositor_state : CompositorState ::new ::< Self > ( & display_handle ) ,
data_device_state : DataDeviceState ::new ::< Self > ( & display_handle ) ,
seat_state ,
pointer_location : ( 0.0 , 0.0 ) . into ( ) ,
shm_state : ShmState ::new ::< Self > ( & display_handle , vec! [ ] ) ,
2023-07-24 18:59:05 -05:00
space : Space ::< WindowElement > ::default ( ) ,
2023-07-02 18:15:44 -05:00
cursor_status : CursorImageStatus ::Default ,
output_manager_state : OutputManagerState ::new_with_xdg_output ::< Self > ( & display_handle ) ,
xdg_shell_state : XdgShellState ::new ::< Self > ( & display_handle ) ,
viewporter_state : ViewporterState ::new ::< Self > ( & display_handle ) ,
fractional_scale_manager_state : FractionalScaleManagerState ::new ::< Self > (
& display_handle ,
) ,
2023-08-02 15:12:10 -05:00
primary_selection_state : PrimarySelectionState ::new ::< Self > ( & display_handle ) ,
2023-08-04 18:48:10 -05:00
layer_shell_state : WlrLayerShellState ::new ::< Self > ( & display_handle ) ,
2023-08-02 15:12:10 -05:00
2023-07-02 18:15:44 -05:00
input_state : InputState ::new ( ) ,
api_state : ApiState ::new ( ) ,
focus_state : FocusState ::new ( ) ,
2023-07-02 17:10:15 -05:00
2023-07-02 18:15:44 -05:00
seat ,
2023-08-02 18:18:51 -05:00
dnd_icon : None ,
2023-07-02 18:15:44 -05:00
move_mode : false ,
socket_name : socket_name . to_string_lossy ( ) . to_string ( ) ,
popup_manager : PopupManager ::default ( ) ,
async_scheduler : sched ,
windows : vec ! [ ] ,
2023-07-11 11:59:38 -05:00
output_callback_ids : vec ! [ ] ,
2023-07-24 11:43:47 -05:00
xwayland ,
xwm : None ,
xdisplay : None ,
2023-07-02 18:15:44 -05:00
} )
2023-07-02 10:26:07 -05:00
}
2023-06-05 21:08:37 -05:00
}
2023-08-08 14:04:42 -05:00
fn start_lua_config ( ) -> Result < ( ) , Box < dyn std ::error ::Error > > {
// TODO: move all this into the lua api
let config_path = std ::env ::var ( " PINNACLE_CONFIG " )
. map ( PathBuf ::from )
. unwrap_or_else ( | _ | {
let default_path = std ::env ::var ( " XDG_CONFIG_HOME " ) . unwrap_or ( " ~/.config " . to_string ( ) ) ;
let mut default_path = PathBuf ::from ( default_path ) ;
default_path . push ( " pinnacle/init.lua " ) ;
default_path
} ) ;
let config_path = {
let path = shellexpand ::tilde ( & config_path . to_string_lossy ( ) . to_string ( ) ) . to_string ( ) ;
PathBuf ::from ( path )
} ;
if config_path . exists ( ) {
let lua_path = std ::env ::var ( " LUA_PATH " ) . unwrap_or_else ( | _ | {
tracing ::info! ( " LUA_PATH was not set, using empty string " ) ;
" " . to_string ( )
} ) ;
let mut local_lua_path = std ::env ::current_dir ( )
. expect ( " Couldn't get current dir " )
. to_string_lossy ( )
. to_string ( ) ;
local_lua_path . push_str ( " /api/lua " ) ; // TODO: get from crate root and do dynamically
let new_lua_path =
format! ( " {local_lua_path} /?.lua; {local_lua_path} /?/init.lua; {local_lua_path} /lib/?.lua; {local_lua_path} /lib/?/init.lua; {lua_path} " ) ;
let lua_cpath = std ::env ::var ( " LUA_CPATH " ) . unwrap_or_else ( | _ | {
tracing ::info! ( " LUA_CPATH was not set, using empty string " ) ;
" " . to_string ( )
} ) ;
let new_lua_cpath = format! ( " {local_lua_path} /lib/?.so; {lua_cpath} " ) ;
if let Err ( err ) = std ::process ::Command ::new ( " lua " )
. arg ( config_path )
. env ( " LUA_PATH " , new_lua_path )
. env ( " LUA_CPATH " , new_lua_cpath )
. spawn ( )
{
tracing ::error! ( " Failed to start Lua: {err} " ) ;
return Err ( err ) ? ;
}
Ok ( ( ) )
} else {
tracing ::error! ( " Could not find config {:?} " , config_path ) ;
if std ::env ::var ( " PINNACLE_CONFIG " ) . is_err ( ) {
tracing ::error! ( " Help: Run Pinnacle with PINNACLE_CONFIG set to a valid config file, or copy the provided example_config.lua to the path mentioned above. " ) ;
}
Err ( std ::io ::Error ::new (
std ::io ::ErrorKind ::Other ,
" No config found " ,
) ) ?
}
}
2023-06-09 20:29:17 -05:00
pub struct CalloopData < B : Backend > {
pub display : Display < State < B > > ,
pub state : State < B > ,
2023-06-02 16:01:48 -05:00
}
#[ derive(Default) ]
pub struct ClientState {
pub compositor_state : CompositorClientState ,
}
impl ClientData for ClientState {
fn initialized ( & self , _client_id : ClientId ) { }
fn disconnected ( & self , _client_id : ClientId , _reason : DisconnectReason ) { }
}
2023-06-09 20:29:17 -05:00
#[ derive(Debug, Copy, Clone) ]
pub struct SurfaceDmabufFeedback < ' a > {
pub render_feedback : & ' a DmabufFeedback ,
pub scanout_feedback : & ' a DmabufFeedback ,
}
2023-06-21 19:08:29 -05:00
// TODO: docs
2023-06-09 20:29:17 -05:00
pub fn take_presentation_feedback (
output : & Output ,
2023-07-24 18:59:05 -05:00
space : & Space < WindowElement > ,
2023-06-09 20:29:17 -05:00
render_element_states : & RenderElementStates ,
) -> OutputPresentationFeedback {
let mut output_presentation_feedback = OutputPresentationFeedback ::new ( output ) ;
space . elements ( ) . for_each ( | window | {
if space . outputs_for_element ( window ) . contains ( output ) {
window . take_presentation_feedback (
& mut output_presentation_feedback ,
surface_primary_scanout_output ,
| surface , _ | {
surface_presentation_feedback_flags_from_states ( surface , render_element_states )
} ,
) ;
}
} ) ;
2023-08-08 14:28:09 -05:00
let map = smithay ::desktop ::layer_map_for_output ( output ) ;
for layer_surface in map . layers ( ) {
layer_surface . take_presentation_feedback (
& mut output_presentation_feedback ,
surface_primary_scanout_output ,
| surface , _ | {
surface_presentation_feedback_flags_from_states ( surface , render_element_states )
} ,
) ;
}
2023-06-09 20:29:17 -05:00
output_presentation_feedback
}
2023-06-17 18:55:04 -05:00
2023-06-21 19:08:29 -05:00
/// State containing the config API's stream.
2023-06-17 21:02:58 -05:00
#[ derive(Default) ]
2023-06-17 18:55:04 -05:00
pub struct ApiState {
2023-07-11 11:59:38 -05:00
// TODO: this may not need to be in an arc mutex because of the move to async
2023-06-21 14:48:38 -05:00
pub stream : Option < Arc < Mutex < UnixStream > > > ,
2023-06-17 18:55:04 -05:00
}
2023-06-17 21:02:58 -05:00
impl ApiState {
pub fn new ( ) -> Self {
Default ::default ( )
}
}
2023-07-10 17:14:37 -05:00
pub trait WithState {
type State : Default ;
fn with_state < F , T > ( & self , func : F ) -> T
where
F : FnMut ( & mut Self ::State ) -> T ;
}
#[ derive(Default, Debug) ]
pub struct WlSurfaceState {
pub resize_state : ResizeSurfaceState ,
}
impl WithState for WlSurface {
type State = WlSurfaceState ;
fn with_state < F , T > ( & self , mut func : F ) -> T
where
F : FnMut ( & mut Self ::State ) -> T ,
{
compositor ::with_states ( self , | states | {
states
. data_map
. insert_if_missing ( RefCell ::< Self ::State > ::default ) ;
let state = states
. data_map
. get ::< RefCell < Self ::State > > ( )
. expect ( " This should never happen " ) ;
func ( & mut state . borrow_mut ( ) )
} )
}
}