2017-10-01 17:21:12 +00:00
extern crate drm ;
#[ macro_use ]
extern crate glium ;
2017-11-07 00:18:52 +00:00
extern crate image ;
2018-01-07 21:30:38 +00:00
extern crate input as libinput ;
extern crate rand ;
2017-10-01 17:21:12 +00:00
#[ macro_use(define_roles) ]
extern crate smithay ;
2018-01-07 21:30:38 +00:00
extern crate udev ;
2017-10-01 17:21:12 +00:00
extern crate wayland_server ;
2018-01-07 21:30:38 +00:00
extern crate xkbcommon ;
2017-10-01 17:21:12 +00:00
#[ macro_use ]
extern crate slog ;
extern crate slog_async ;
extern crate slog_term ;
mod helpers ;
use drm ::control ::{ Device as ControlDevice , ResourceInfo } ;
use drm ::control ::connector ::{ Info as ConnectorInfo , State as ConnectorState } ;
use drm ::control ::crtc ;
2018-01-07 21:30:38 +00:00
use drm ::control ::encoder ::Info as EncoderInfo ;
2017-10-01 17:21:12 +00:00
use drm ::result ::Error as DrmError ;
2018-01-05 19:04:46 +00:00
use glium ::{ Blend , Surface } ;
2018-01-07 21:30:38 +00:00
use helpers ::{ init_shell , Buffer , GliumDrawer , MyWindowMap , Roles , SurfaceData } ;
2017-11-07 00:18:52 +00:00
use image ::{ ImageBuffer , Rgba } ;
2018-01-07 21:30:38 +00:00
use libinput ::{ event , Device as LibinputDevice , Libinput } ;
2017-11-07 00:18:52 +00:00
use libinput ::event ::keyboard ::KeyboardEventTrait ;
2017-10-01 17:21:12 +00:00
use slog ::{ Drain , Logger } ;
2018-01-07 21:30:38 +00:00
use smithay ::backend ::drm ::{ DevPath , DrmBackend , DrmDevice , DrmHandler } ;
2017-11-07 00:18:52 +00:00
use smithay ::backend ::graphics ::GraphicsBackend ;
2017-10-01 17:21:12 +00:00
use smithay ::backend ::graphics ::egl ::EGLGraphicsBackend ;
2018-01-07 21:30:38 +00:00
use smithay ::backend ::graphics ::egl ::wayland ::{ EGLDisplay , EGLWaylandExtensions , Format } ;
use smithay ::backend ::input ::{ self , Event , InputBackend , InputHandler , KeyState , KeyboardKeyEvent ,
PointerAxisEvent , PointerButtonEvent } ;
2018-03-22 15:09:58 +00:00
use smithay ::backend ::libinput ::{ libinput_bind , LibinputInputBackend , LibinputSessionInterface } ;
2017-11-07 00:18:52 +00:00
use smithay ::backend ::session ::{ Session , SessionNotifier } ;
2018-01-27 12:07:35 +00:00
use smithay ::backend ::session ::auto ::{ auto_session_bind , AutoSession } ;
2018-01-07 21:30:38 +00:00
use smithay ::backend ::udev ::{ primary_gpu , udev_backend_bind , SessionFdDrmDevice , UdevBackend , UdevHandler } ;
2017-10-01 17:21:12 +00:00
use smithay ::wayland ::compositor ::{ CompositorToken , SubsurfaceRole , TraversalAction } ;
use smithay ::wayland ::compositor ::roles ::Role ;
2017-11-07 00:18:52 +00:00
use smithay ::wayland ::output ::{ Mode , Output , PhysicalProperties } ;
use smithay ::wayland ::seat ::{ KeyboardHandle , PointerHandle , Seat } ;
2017-10-01 17:21:12 +00:00
use smithay ::wayland ::shm ::init_shm_global ;
use std ::cell ::RefCell ;
2018-01-05 19:04:46 +00:00
use std ::collections ::HashMap ;
2018-01-27 12:06:48 +00:00
use std ::env ;
2017-10-01 17:21:12 +00:00
use std ::io ::Error as IoError ;
2018-01-07 21:30:38 +00:00
use std ::path ::PathBuf ;
use std ::process ::Command ;
2017-10-01 17:21:12 +00:00
use std ::rc ::Rc ;
2017-11-25 12:28:49 +00:00
use std ::sync ::Arc ;
2017-10-01 17:21:12 +00:00
use std ::sync ::atomic ::{ AtomicBool , Ordering } ;
use std ::time ::Duration ;
2018-04-22 09:58:39 +00:00
use wayland_server ::Display ;
use wayland_server ::commons ::downcast_impl ;
2017-11-07 00:18:52 +00:00
use wayland_server ::protocol ::{ wl_output , wl_pointer } ;
2018-01-07 21:30:38 +00:00
use xkbcommon ::xkb ::keysyms as xkb ;
2017-11-07 00:18:52 +00:00
struct LibinputInputHandler {
log : Logger ,
pointer : PointerHandle ,
keyboard : KeyboardHandle ,
window_map : Rc < RefCell < MyWindowMap > > ,
2017-11-25 12:28:49 +00:00
pointer_location : Rc < RefCell < ( f64 , f64 ) > > ,
2017-11-07 00:18:52 +00:00
screen_size : ( u32 , u32 ) ,
serial : u32 ,
2018-01-27 12:07:35 +00:00
session : AutoSession ,
2017-11-07 00:18:52 +00:00
running : Arc < AtomicBool > ,
}
impl LibinputInputHandler {
fn next_serial ( & mut self ) -> u32 {
self . serial + = 1 ;
self . serial
}
}
impl InputHandler < LibinputInputBackend > for LibinputInputHandler {
2018-04-22 09:58:39 +00:00
fn on_seat_created ( & mut self , _ : & input ::Seat ) {
2017-11-07 00:18:52 +00:00
/* we just create a single static one */
}
2018-04-22 09:58:39 +00:00
fn on_seat_destroyed ( & mut self , _ : & input ::Seat ) {
2017-11-07 00:18:52 +00:00
/* we just create a single static one */
}
2018-04-22 09:58:39 +00:00
fn on_seat_changed ( & mut self , _ : & input ::Seat ) {
2017-11-07 00:18:52 +00:00
/* we just create a single static one */
}
2018-04-22 09:58:39 +00:00
fn on_keyboard_key ( & mut self , _ : & input ::Seat , evt : event ::keyboard ::KeyboardKeyEvent ) {
2017-11-07 00:18:52 +00:00
let keycode = evt . key ( ) ;
let state = evt . state ( ) ;
debug! ( self . log , " key " ; " keycode " = > keycode , " state " = > format! ( " {:?} " , state ) ) ;
2017-11-25 12:27:52 +00:00
let serial = self . next_serial ( ) ;
2018-01-27 12:07:35 +00:00
// we cannot borrow `self` into the closure, because we need self.keyboard.
// but rust does not borrow all fields separately, so we need to do that manually...
let running = & self . running ;
let mut session = & mut self . session ;
let log = & self . log ;
2018-04-22 09:58:39 +00:00
let time = Event ::time ( & evt ) ;
2018-01-07 21:30:38 +00:00
self . keyboard
2018-04-22 09:58:39 +00:00
. input ( keycode , state , serial , time , move | modifiers , keysym | {
2018-01-27 12:07:35 +00:00
debug! ( log , " keysym " ; " state " = > format! ( " {:?} " , state ) , " mods " = > format! ( " {:?} " , modifiers ) , " keysym " = > xkbcommon ::xkb ::keysym_get_name ( keysym ) ) ;
2018-01-27 12:50:24 +00:00
if modifiers . ctrl & & modifiers . alt & & keysym = = xkb ::KEY_BackSpace
& & state = = KeyState ::Pressed
{
2018-01-27 12:07:35 +00:00
info! ( log , " Stopping example using Ctrl+Alt+Backspace " ) ;
running . store ( false , Ordering ::SeqCst ) ;
false
} else if modifiers . logo & & keysym = = xkb ::KEY_q {
info! ( log , " Stopping example using Logo+Q " ) ;
running . store ( false , Ordering ::SeqCst ) ;
false
2018-02-20 17:33:37 +00:00
} else if modifiers . ctrl & & modifiers . alt & & keysym > = xkb ::KEY_XF86Switch_VT_1
& & keysym < = xkb ::KEY_XF86Switch_VT_12
2018-01-27 12:50:24 +00:00
& & state = = KeyState ::Pressed
{
2018-02-20 17:33:37 +00:00
let vt = ( keysym - xkb ::KEY_XF86Switch_VT_1 + 1 ) as i32 ;
info! ( log , " Trying to switch to vt {} " , vt ) ;
if let Err ( err ) = session . change_vt ( vt ) {
error! ( log , " Error switching to vt {}: {} " , vt , err ) ;
2018-01-27 12:07:35 +00:00
}
2018-01-07 21:30:38 +00:00
false
} else if modifiers . logo & & keysym = = xkb ::KEY_Return & & state = = KeyState ::Pressed {
2018-01-27 12:07:35 +00:00
info! ( log , " Launching terminal " ) ;
2018-01-07 21:30:38 +00:00
let _ = Command ::new ( " weston-terminal " ) . spawn ( ) ;
false
} else {
true
}
} ) ;
2017-11-07 00:18:52 +00:00
}
2018-04-22 09:58:39 +00:00
fn on_pointer_move ( & mut self , _ : & input ::Seat , evt : event ::pointer ::PointerMotionEvent ) {
2017-11-07 00:18:52 +00:00
let ( x , y ) = ( evt . dx ( ) , evt . dy ( ) ) ;
let serial = self . next_serial ( ) ;
2017-11-25 12:28:49 +00:00
let mut location = self . pointer_location . borrow_mut ( ) ;
2017-11-07 00:18:52 +00:00
location . 0 + = x ;
location . 1 + = y ;
2018-01-07 21:30:38 +00:00
let under = self . window_map
. borrow ( )
. get_surface_under ( ( location . 0 , location . 1 ) ) ;
2017-11-07 00:18:52 +00:00
self . pointer . motion (
under . as_ref ( ) . map ( | & ( ref s , ( x , y ) ) | ( s , x , y ) ) ,
serial ,
evt . time ( ) ,
) ;
}
2018-04-22 09:58:39 +00:00
fn on_pointer_move_absolute ( & mut self , _ : & input ::Seat , evt : event ::pointer ::PointerMotionAbsoluteEvent ) {
2018-01-07 21:30:38 +00:00
let ( x , y ) = (
evt . absolute_x_transformed ( self . screen_size . 0 ) ,
evt . absolute_y_transformed ( self . screen_size . 1 ) ,
) ;
2017-11-25 12:28:49 +00:00
* self . pointer_location . borrow_mut ( ) = ( x , y ) ;
2017-11-07 00:18:52 +00:00
let serial = self . next_serial ( ) ;
let under = self . window_map . borrow ( ) . get_surface_under ( ( x , y ) ) ;
self . pointer . motion (
under . as_ref ( ) . map ( | & ( ref s , ( x , y ) ) | ( s , x , y ) ) ,
serial ,
evt . time ( ) ,
) ;
}
2018-04-22 09:58:39 +00:00
fn on_pointer_button ( & mut self , _ : & input ::Seat , evt : event ::pointer ::PointerButtonEvent ) {
2017-11-07 00:18:52 +00:00
let serial = self . next_serial ( ) ;
let button = evt . button ( ) ;
let state = match evt . state ( ) {
input ::MouseButtonState ::Pressed = > {
// change the keyboard focus
let under = self . window_map
. borrow_mut ( )
2017-11-25 12:28:49 +00:00
. get_surface_and_bring_to_top ( * self . pointer_location . borrow ( ) ) ;
2017-11-07 00:18:52 +00:00
self . keyboard
. set_focus ( under . as_ref ( ) . map ( | & ( ref s , _ ) | s ) , serial ) ;
wl_pointer ::ButtonState ::Pressed
}
input ::MouseButtonState ::Released = > wl_pointer ::ButtonState ::Released ,
} ;
self . pointer . button ( button , state , serial , evt . time ( ) ) ;
}
2018-04-22 09:58:39 +00:00
fn on_pointer_axis ( & mut self , _ : & input ::Seat , evt : event ::pointer ::PointerAxisEvent ) {
2018-03-20 15:29:22 +00:00
let source = match evt . source ( ) {
2018-03-22 15:09:58 +00:00
input ::AxisSource ::Continuous = > wayland_server ::protocol ::wl_pointer ::AxisSource ::Continuous ,
input ::AxisSource ::Finger = > wayland_server ::protocol ::wl_pointer ::AxisSource ::Finger ,
input ::AxisSource ::Wheel | input ::AxisSource ::WheelTilt = > {
wayland_server ::protocol ::wl_pointer ::AxisSource ::Wheel
}
2018-03-20 15:29:22 +00:00
} ;
2018-03-22 15:09:58 +00:00
let horizontal_amount = evt . amount ( & input ::Axis ::Horizontal )
. unwrap_or_else ( | | evt . amount_discrete ( & input ::Axis ::Horizontal ) . unwrap ( ) * 3.0 ) ;
let vertical_amount = evt . amount ( & input ::Axis ::Vertical )
. unwrap_or_else ( | | evt . amount_discrete ( & input ::Axis ::Vertical ) . unwrap ( ) * 3.0 ) ;
let horizontal_amount_discrete = evt . amount_discrete ( & input ::Axis ::Horizontal ) ;
let vertical_amount_discrete = evt . amount_discrete ( & input ::Axis ::Vertical ) ;
2018-03-20 15:29:22 +00:00
{
let mut event = self . pointer . axis ( ) ;
2018-03-22 15:09:58 +00:00
event . source ( source ) ;
if horizontal_amount ! = 0.0 {
event . value (
wayland_server ::protocol ::wl_pointer ::Axis ::HorizontalScroll ,
horizontal_amount ,
evt . time ( ) ,
) ;
if let Some ( discrete ) = horizontal_amount_discrete {
event . discrete (
wayland_server ::protocol ::wl_pointer ::Axis ::HorizontalScroll ,
discrete as i32 ,
) ;
}
} else if source = = wayland_server ::protocol ::wl_pointer ::AxisSource ::Finger {
event . stop (
wayland_server ::protocol ::wl_pointer ::Axis ::HorizontalScroll ,
evt . time ( ) ,
) ;
}
if vertical_amount ! = 0.0 {
event . value (
wayland_server ::protocol ::wl_pointer ::Axis ::VerticalScroll ,
vertical_amount ,
evt . time ( ) ,
) ;
if let Some ( discrete ) = vertical_amount_discrete {
event . discrete (
wayland_server ::protocol ::wl_pointer ::Axis ::VerticalScroll ,
discrete as i32 ,
) ;
}
} else if source = = wayland_server ::protocol ::wl_pointer ::AxisSource ::Finger {
event . stop (
wayland_server ::protocol ::wl_pointer ::Axis ::VerticalScroll ,
evt . time ( ) ,
) ;
2018-03-20 15:29:22 +00:00
}
2018-03-20 16:35:02 +00:00
event . done ( ) ;
2018-03-20 15:29:22 +00:00
}
2017-11-07 00:18:52 +00:00
}
2018-04-22 09:58:39 +00:00
fn on_touch_down ( & mut self , _ : & input ::Seat , _ : event ::touch ::TouchDownEvent ) {
2017-11-07 00:18:52 +00:00
/* not done in this example */
}
2018-04-22 09:58:39 +00:00
fn on_touch_motion ( & mut self , _ : & input ::Seat , _ : event ::touch ::TouchMotionEvent ) {
2017-11-07 00:18:52 +00:00
/* not done in this example */
}
2018-04-22 09:58:39 +00:00
fn on_touch_up ( & mut self , _ : & input ::Seat , _ : event ::touch ::TouchUpEvent ) {
2017-11-07 00:18:52 +00:00
/* not done in this example */
}
2018-04-22 09:58:39 +00:00
fn on_touch_cancel ( & mut self , _ : & input ::Seat , _ : event ::touch ::TouchCancelEvent ) {
2017-11-07 00:18:52 +00:00
/* not done in this example */
}
2018-04-22 09:58:39 +00:00
fn on_touch_frame ( & mut self , _ : & input ::Seat , _ : event ::touch ::TouchFrameEvent ) {
2017-11-07 00:18:52 +00:00
/* not done in this example */
}
2018-04-22 09:58:39 +00:00
fn on_input_config_changed ( & mut self , _ : & mut [ LibinputDevice ] ) {
2017-11-07 00:18:52 +00:00
/* not done in this example */
}
}
2017-10-01 17:21:12 +00:00
fn main ( ) {
2018-01-05 19:04:46 +00:00
let active_egl_context = Rc ::new ( RefCell ::new ( None ) ) ;
2017-10-01 17:21:12 +00:00
// A logger facility, here we use the terminal for this example
let log = Logger ::root (
2018-01-07 21:30:38 +00:00
slog_term ::FullFormat ::new ( slog_term ::PlainSyncDecorator ::new ( std ::io ::stdout ( ) ) )
. build ( )
. fuse ( ) ,
2017-10-01 17:21:12 +00:00
o! ( ) ,
) ;
// Initialize the wayland server
2018-04-22 09:58:39 +00:00
let ( mut display , mut event_loop ) = wayland_server ::Display ::new ( ) ;
2017-10-01 17:21:12 +00:00
2018-01-05 19:04:46 +00:00
/*
* Add a listening socket
* /
let name = display . add_socket_auto ( ) . unwrap ( ) . into_string ( ) . unwrap ( ) ;
println! ( " Listening on socket: {} " , name ) ;
2018-01-27 12:06:48 +00:00
env ::set_var ( " WAYLAND_DISPLAY " , name ) ;
2018-04-22 09:58:39 +00:00
let display = Rc ::new ( RefCell ::new ( display ) ) ;
2018-01-05 19:04:46 +00:00
2017-10-01 17:21:12 +00:00
/*
* Initialize the compositor
* /
2018-04-22 09:58:39 +00:00
init_shm_global (
& mut display . borrow_mut ( ) ,
event_loop . token ( ) ,
vec! [ ] ,
log . clone ( ) ,
) ;
2017-10-01 17:21:12 +00:00
2018-04-23 09:40:41 +00:00
let ( compositor_token , _ , _ , window_map ) = init_shell (
2018-04-22 09:58:39 +00:00
& mut display . borrow_mut ( ) ,
event_loop . token ( ) ,
log . clone ( ) ,
active_egl_context . clone ( ) ,
) ;
2017-10-01 17:21:12 +00:00
/*
2018-01-27 12:07:35 +00:00
* Initialize session
2017-10-01 17:21:12 +00:00
* /
2018-01-27 12:07:35 +00:00
let ( session , mut notifier ) = AutoSession ::new ( log . clone ( ) ) . unwrap ( ) ;
2017-10-01 17:21:12 +00:00
let running = Arc ::new ( AtomicBool ::new ( true ) ) ;
2017-11-25 12:28:49 +00:00
let pointer_location = Rc ::new ( RefCell ::new ( ( 0.0 , 0.0 ) ) ) ;
2017-11-07 00:18:52 +00:00
2017-10-01 17:21:12 +00:00
/*
* Initialize the udev backend
* /
2017-12-07 14:20:33 +00:00
let context = udev ::Context ::new ( ) . unwrap ( ) ;
2018-01-05 19:04:46 +00:00
let seat = session . seat ( ) ;
let primary_gpu = primary_gpu ( & context , & seat ) . unwrap_or_default ( ) ;
2017-11-07 00:18:52 +00:00
let bytes = include_bytes! ( " resources/cursor2.rgba " ) ;
2018-01-31 16:23:05 +00:00
let mut udev_backend = UdevBackend ::new (
2018-04-22 09:58:39 +00:00
event_loop . token ( ) ,
2018-01-07 21:30:38 +00:00
& context ,
session . clone ( ) ,
UdevHandlerImpl {
2017-10-01 17:21:12 +00:00
compositor_token ,
2018-01-05 19:04:46 +00:00
active_egl_context ,
backends : HashMap ::new ( ) ,
display : display . clone ( ) ,
primary_gpu ,
2017-10-01 17:21:12 +00:00
window_map : window_map . clone ( ) ,
2017-11-07 00:18:52 +00:00
pointer_location : pointer_location . clone ( ) ,
pointer_image : ImageBuffer ::from_raw ( 64 , 64 , bytes . to_vec ( ) ) . unwrap ( ) ,
2017-10-01 17:21:12 +00:00
logger : log . clone ( ) ,
2018-01-07 21:30:38 +00:00
} ,
log . clone ( ) ,
) . unwrap ( ) ;
2017-10-01 17:21:12 +00:00
2018-01-31 16:23:05 +00:00
let udev_session_id = notifier . register ( & mut udev_backend ) ;
2017-11-07 00:18:52 +00:00
2018-04-22 09:58:39 +00:00
let ( mut w_seat , _ ) = Seat ::new (
& mut display . borrow_mut ( ) ,
event_loop . token ( ) ,
session . seat ( ) . into ( ) ,
log . clone ( ) ,
) ;
2017-11-07 00:18:52 +00:00
2018-04-22 09:58:39 +00:00
let pointer = w_seat . add_pointer ( ) ;
let keyboard = w_seat
2017-11-07 00:18:52 +00:00
. add_keyboard ( " " , " " , " " , None , 1000 , 500 )
. expect ( " Failed to initialize the keyboard " ) ;
2018-04-22 09:58:39 +00:00
let ( output , _output_global ) = Output ::new (
& mut display . borrow_mut ( ) ,
event_loop . token ( ) ,
2017-11-07 00:18:52 +00:00
" Drm " . into ( ) ,
PhysicalProperties {
width : 0 ,
height : 0 ,
subpixel : wl_output ::Subpixel ::Unknown ,
maker : " Smithay " . into ( ) ,
model : " Generic DRM " . into ( ) ,
} ,
log . clone ( ) ,
) ;
let ( w , h ) = ( 1920 , 1080 ) ; // Hardcode full-hd res
2018-04-22 09:58:39 +00:00
output . change_current_state (
Some ( Mode {
2017-11-07 00:18:52 +00:00
width : w as i32 ,
height : h as i32 ,
refresh : 60_000 ,
2018-04-22 09:58:39 +00:00
} ) ,
None ,
None ,
) ;
output . set_preferred ( Mode {
width : w as i32 ,
height : h as i32 ,
refresh : 60_000 ,
} ) ;
2017-11-07 00:18:52 +00:00
/*
* Initialize libinput backend
* /
2018-01-27 12:50:24 +00:00
let mut libinput_context =
Libinput ::new_from_udev ::< LibinputSessionInterface < AutoSession > > ( session . clone ( ) . into ( ) , & context ) ;
2018-01-31 16:23:05 +00:00
let libinput_session_id = notifier . register ( & mut libinput_context ) ;
2017-11-25 12:28:49 +00:00
libinput_context . udev_assign_seat ( & seat ) . unwrap ( ) ;
2017-11-07 00:18:52 +00:00
let mut libinput_backend = LibinputInputBackend ::new ( libinput_context , log . clone ( ) ) ;
2018-04-22 09:58:39 +00:00
libinput_backend . set_handler ( LibinputInputHandler {
log : log . clone ( ) ,
pointer ,
keyboard ,
window_map : window_map . clone ( ) ,
pointer_location ,
screen_size : ( w , h ) ,
serial : 0 ,
session : session ,
running : running . clone ( ) ,
} ) ;
let libinput_event_source = libinput_bind ( libinput_backend , event_loop . token ( ) )
2018-02-21 19:26:10 +00:00
. map_err ( | ( err , _ ) | err )
. unwrap ( ) ;
2017-11-07 00:18:52 +00:00
2018-04-22 09:58:39 +00:00
let session_event_source = auto_session_bind ( notifier , & event_loop . token ( ) )
2018-02-21 19:26:10 +00:00
. map_err ( | ( err , _ ) | err )
. unwrap ( ) ;
2018-04-22 09:58:39 +00:00
let udev_event_source = udev_backend_bind ( & event_loop . token ( ) , udev_backend )
2018-02-21 19:26:10 +00:00
. map_err ( | ( err , _ ) | err )
. unwrap ( ) ;
2017-11-07 00:18:52 +00:00
2017-10-01 17:21:12 +00:00
while running . load ( Ordering ::SeqCst ) {
2018-01-07 20:48:49 +00:00
if let Err ( _ ) = event_loop . dispatch ( Some ( 16 ) ) {
running . store ( false , Ordering ::SeqCst ) ;
} else {
2018-04-22 09:58:39 +00:00
display . borrow_mut ( ) . flush_clients ( ) ;
2018-01-07 20:48:49 +00:00
window_map . borrow_mut ( ) . refresh ( ) ;
}
2017-10-01 17:21:12 +00:00
}
2017-11-07 00:18:52 +00:00
println! ( " Bye Bye " ) ;
2018-01-28 17:18:06 +00:00
let mut notifier = session_event_source . unbind ( ) ;
2017-10-01 17:21:12 +00:00
notifier . unregister ( udev_session_id ) ;
2017-11-07 00:18:52 +00:00
notifier . unregister ( libinput_session_id ) ;
libinput_event_source . remove ( ) ;
2017-10-01 17:21:12 +00:00
2018-01-31 16:23:05 +00:00
// destroy the udev backend freeing the drm devices
2018-04-24 09:00:39 +00:00
//
// udev_event_source.remove() returns a Box<Implementation<..>>, downcast_impl
// allows us to cast it back to its original type, storing it back into its original
// variable to simplify type inference.
2018-04-22 09:58:39 +00:00
udev_backend = * ( downcast_impl ( udev_event_source . remove ( ) ) . unwrap_or_else ( | _ | unreachable! ( ) ) ) ;
udev_backend . close ( ) ;
2017-10-01 17:21:12 +00:00
}
struct UdevHandlerImpl {
2018-04-22 09:58:39 +00:00
compositor_token : CompositorToken < SurfaceData , Roles > ,
2018-01-05 19:04:46 +00:00
active_egl_context : Rc < RefCell < Option < EGLDisplay > > > ,
backends : HashMap < u64 , Rc < RefCell < HashMap < crtc ::Handle , GliumDrawer < DrmBackend < SessionFdDrmDevice > > > > > > ,
2018-04-22 09:58:39 +00:00
display : Rc < RefCell < Display > > ,
2018-01-05 19:04:46 +00:00
primary_gpu : Option < PathBuf > ,
2017-10-01 17:21:12 +00:00
window_map : Rc < RefCell < MyWindowMap > > ,
2017-11-25 12:28:49 +00:00
pointer_location : Rc < RefCell < ( f64 , f64 ) > > ,
2017-11-07 00:18:52 +00:00
pointer_image : ImageBuffer < Rgba < u8 > , Vec < u8 > > ,
2017-10-01 17:21:12 +00:00
logger : ::slog ::Logger ,
}
impl UdevHandlerImpl {
2018-01-07 21:30:38 +00:00
pub fn scan_connectors (
2018-04-22 09:58:39 +00:00
& self ,
device : & mut DrmDevice < SessionFdDrmDevice > ,
2018-01-07 21:30:38 +00:00
) -> HashMap < crtc ::Handle , GliumDrawer < DrmBackend < SessionFdDrmDevice > > > {
2017-10-01 17:21:12 +00:00
// Get a set of all modesetting resource handles (excluding planes):
let res_handles = device . resource_handles ( ) . unwrap ( ) ;
// Use first connected connector
let connector_infos : Vec < ConnectorInfo > = res_handles
. connectors ( )
. iter ( )
2018-01-07 21:30:38 +00:00
. map ( | conn | ConnectorInfo ::load_from_device ( device , * conn ) . unwrap ( ) )
2017-10-01 17:21:12 +00:00
. filter ( | conn | conn . connection_state ( ) = = ConnectorState ::Connected )
. inspect ( | conn | info! ( self . logger , " Connected: {:?} " , conn . connector_type ( ) ) )
. collect ( ) ;
2018-01-05 19:04:46 +00:00
let mut backends = HashMap ::new ( ) ;
2017-10-01 17:21:12 +00:00
// very naive way of finding good crtc/encoder/connector combinations. This problem is np-complete
for connector_info in connector_infos {
2018-01-07 21:30:38 +00:00
let encoder_infos = connector_info
. encoders ( )
. iter ( )
. flat_map ( | encoder_handle | EncoderInfo ::load_from_device ( device , * encoder_handle ) )
. collect ::< Vec < EncoderInfo > > ( ) ;
2017-10-01 17:21:12 +00:00
for encoder_info in encoder_infos {
for crtc in res_handles . filter_crtcs ( encoder_info . possible_crtcs ( ) ) {
2018-01-05 19:04:46 +00:00
if ! backends . contains_key ( & crtc ) {
2017-10-01 17:21:12 +00:00
let mode = connector_info . modes ( ) [ 0 ] ; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.)
2018-01-07 21:30:38 +00:00
// create a backend
let renderer = GliumDrawer ::from (
device
. create_backend ( crtc , mode , vec! [ connector_info . handle ( ) ] )
. unwrap ( ) ,
) ;
2017-10-01 17:21:12 +00:00
2017-11-07 00:18:52 +00:00
// create cursor
2018-01-07 21:30:38 +00:00
renderer
2018-02-26 17:29:52 +00:00
. borrow ( )
2018-01-07 21:30:38 +00:00
. set_cursor_representation ( & self . pointer_image , ( 2 , 2 ) )
. unwrap ( ) ;
2017-11-07 00:18:52 +00:00
2017-10-01 17:21:12 +00:00
// render first frame
{
let mut frame = renderer . draw ( ) ;
frame . clear_color ( 0.8 , 0.8 , 0.9 , 1.0 ) ;
frame . finish ( ) . unwrap ( ) ;
}
2018-01-05 19:04:46 +00:00
backends . insert ( crtc , renderer ) ;
2017-10-01 17:21:12 +00:00
break ;
}
}
}
}
2018-01-05 19:04:46 +00:00
backends
2017-10-01 17:21:12 +00:00
}
}
2018-01-05 19:04:46 +00:00
impl UdevHandler < DrmHandlerImpl > for UdevHandlerImpl {
2018-04-22 09:58:39 +00:00
fn device_added ( & mut self , device : & mut DrmDevice < SessionFdDrmDevice > ) -> Option < DrmHandlerImpl > {
2018-01-05 19:04:46 +00:00
// init hardware acceleration on the primary gpu.
if device . dev_path ( ) . and_then ( | path | path . canonicalize ( ) . ok ( ) ) = = self . primary_gpu {
2018-04-22 09:58:39 +00:00
* self . active_egl_context . borrow_mut ( ) = device . bind_wl_display ( & * self . display . borrow ( ) ) . ok ( ) ;
2018-01-05 19:04:46 +00:00
}
let backends = Rc ::new ( RefCell ::new ( self . scan_connectors ( device ) ) ) ;
self . backends . insert ( device . device_id ( ) , backends . clone ( ) ) ;
2017-10-01 17:21:12 +00:00
Some ( DrmHandlerImpl {
compositor_token : self . compositor_token . clone ( ) ,
2018-01-05 19:04:46 +00:00
backends ,
2017-10-01 17:21:12 +00:00
window_map : self . window_map . clone ( ) ,
2017-11-07 00:18:52 +00:00
pointer_location : self . pointer_location . clone ( ) ,
2017-10-01 17:21:12 +00:00
logger : self . logger . clone ( ) ,
} )
}
2018-04-22 09:58:39 +00:00
fn device_changed ( & mut self , device : & mut DrmDevice < SessionFdDrmDevice > ) {
2018-01-05 19:04:46 +00:00
//quick and dirt, just re-init all backends
2018-01-31 16:23:05 +00:00
let backends = self . backends . get ( & device . device_id ( ) ) . unwrap ( ) ;
* backends . borrow_mut ( ) = self . scan_connectors ( device ) ;
2017-10-01 17:21:12 +00:00
}
2018-04-22 09:58:39 +00:00
fn device_removed ( & mut self , device : & mut DrmDevice < SessionFdDrmDevice > ) {
2018-01-05 19:04:46 +00:00
// drop the backends on this side
self . backends . remove ( & device . device_id ( ) ) ;
// don't use hardware acceleration anymore, if this was the primary gpu
if device . dev_path ( ) . and_then ( | path | path . canonicalize ( ) . ok ( ) ) = = self . primary_gpu {
* self . active_egl_context . borrow_mut ( ) = None ;
}
2017-10-01 17:21:12 +00:00
}
2018-04-22 09:58:39 +00:00
fn error ( & mut self , error : IoError ) {
2017-10-01 17:21:12 +00:00
error! ( self . logger , " {:?} " , error ) ;
}
}
pub struct DrmHandlerImpl {
2018-04-22 09:58:39 +00:00
compositor_token : CompositorToken < SurfaceData , Roles > ,
2018-01-05 19:04:46 +00:00
backends : Rc < RefCell < HashMap < crtc ::Handle , GliumDrawer < DrmBackend < SessionFdDrmDevice > > > > > ,
2017-10-01 17:21:12 +00:00
window_map : Rc < RefCell < MyWindowMap > > ,
2017-11-25 12:28:49 +00:00
pointer_location : Rc < RefCell < ( f64 , f64 ) > > ,
2017-10-01 17:21:12 +00:00
logger : ::slog ::Logger ,
}
2018-01-05 19:04:46 +00:00
impl DrmHandler < SessionFdDrmDevice > for DrmHandlerImpl {
2018-01-07 21:30:38 +00:00
fn ready (
2018-04-22 09:58:39 +00:00
& mut self ,
_device : & mut DrmDevice < SessionFdDrmDevice > ,
crtc : crtc ::Handle ,
_frame : u32 ,
_duration : Duration ,
2018-01-07 21:30:38 +00:00
) {
2018-01-05 19:04:46 +00:00
if let Some ( drawer ) = self . backends . borrow ( ) . get ( & crtc ) {
{
let ( x , y ) = * self . pointer_location . borrow ( ) ;
2018-02-26 17:29:52 +00:00
let _ = drawer
. borrow ( )
. set_cursor_position ( x . trunc ( ) . abs ( ) as u32 , y . trunc ( ) . abs ( ) as u32 ) ;
2018-01-05 19:04:46 +00:00
}
let mut frame = drawer . draw ( ) ;
frame . clear_color ( 0.8 , 0.8 , 0.9 , 1.0 ) ;
// redraw the frame, in a simple but inneficient way
{
2018-02-26 17:29:52 +00:00
let screen_dimensions = drawer . borrow ( ) . get_framebuffer_dimensions ( ) ;
2018-01-07 21:30:38 +00:00
self . window_map . borrow ( ) . with_windows_from_bottom_to_top (
| toplevel_surface , initial_place | {
if let Some ( wl_surface ) = toplevel_surface . get_surface ( ) {
// this surface is a root of a subsurface tree that needs to be drawn
self . compositor_token
. with_surface_tree_upward (
wl_surface ,
initial_place ,
| _surface , attributes , role , & ( mut x , mut y ) | {
// there is actually something to draw !
if attributes . user_data . texture . is_none ( ) {
let mut remove = false ;
match attributes . user_data . buffer {
Some ( Buffer ::Egl { ref images } ) = > {
match images . format {
Format ::RGB | Format ::RGBA = > {
attributes . user_data . texture =
drawer . texture_from_egl ( & images ) ;
}
_ = > {
// we don't handle the more complex formats here.
attributes . user_data . texture = None ;
remove = true ;
}
} ;
}
Some ( Buffer ::Shm { ref data , ref size } ) = > {
attributes . user_data . texture =
Some ( drawer . texture_from_mem ( data , * size ) ) ;
}
_ = > { }
}
if remove {
attributes . user_data . buffer = None ;
}
2018-01-05 19:04:46 +00:00
}
2018-01-07 21:30:38 +00:00
if let Some ( ref texture ) = attributes . user_data . texture {
if let Ok ( subdata ) = Role ::< SubsurfaceRole > ::data ( role ) {
2018-04-22 09:58:39 +00:00
x + = subdata . location . 0 ;
y + = subdata . location . 1 ;
2018-01-07 21:30:38 +00:00
}
info! ( self . logger , " Render window " ) ;
drawer . render_texture (
& mut frame ,
texture ,
match * attributes . user_data . buffer . as_ref ( ) . unwrap ( ) {
Buffer ::Egl { ref images } = > images . y_inverted ,
Buffer ::Shm { .. } = > false ,
} ,
match * attributes . user_data . buffer . as_ref ( ) . unwrap ( ) {
Buffer ::Egl { ref images } = > {
( images . width , images . height )
}
Buffer ::Shm { ref size , .. } = > * size ,
} ,
( x , y ) ,
screen_dimensions ,
Blend ::alpha_blending ( ) ,
) ;
TraversalAction ::DoChildren ( ( x , y ) )
} else {
// we are not display, so our children are neither
TraversalAction ::SkipChildren
2017-10-01 17:21:12 +00:00
}
2018-01-07 21:30:38 +00:00
} ,
)
. unwrap ( ) ;
}
} ,
) ;
2018-01-05 19:04:46 +00:00
}
if let Err ( err ) = frame . finish ( ) {
error! ( self . logger , " Error during rendering: {:?} " , err ) ;
}
2017-10-01 17:21:12 +00:00
}
}
2018-04-22 09:58:39 +00:00
fn error ( & mut self , _device : & mut DrmDevice < SessionFdDrmDevice > , error : DrmError ) {
2017-10-01 17:21:12 +00:00
error! ( self . logger , " {:?} " , error ) ;
}
}