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 } ;
use smithay ::backend ::libinput ::{ libinput_bind , LibinputInputBackend , LibinputSessionInterface ,
PointerAxisEvent as LibinputPointerAxisEvent } ;
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-01-12 14:49:55 +00:00
use wayland_server ::{ Display , EventLoopHandle , StateProxy , StateToken } ;
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-01-12 14:49:55 +00:00
fn on_seat_created ( & mut self , _evlh : & mut EventLoopHandle , _ : & input ::Seat ) {
2017-11-07 00:18:52 +00:00
/* we just create a single static one */
}
2018-01-12 14:49:55 +00:00
fn on_seat_destroyed ( & mut self , _evlh : & mut EventLoopHandle , _ : & input ::Seat ) {
2017-11-07 00:18:52 +00:00
/* we just create a single static one */
}
2018-01-12 14:49:55 +00:00
fn on_seat_changed ( & mut self , _evlh : & mut EventLoopHandle , _ : & input ::Seat ) {
2017-11-07 00:18:52 +00:00
/* we just create a single static one */
}
2018-01-12 14:49:55 +00:00
fn on_keyboard_key (
& mut self , _evlh : & mut EventLoopHandle , _ : & 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-01-07 21:30:38 +00:00
self . keyboard
2018-01-27 12:07:35 +00:00
. input ( keycode , state , serial , move | modifiers , keysym | {
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-01-27 12:50:24 +00:00
} else if modifiers . ctrl & & modifiers . alt & & keysym = = xkb ::KEY_XF86Switch_VT_1
& & state = = KeyState ::Pressed
{
2018-01-27 12:07:35 +00:00
info! ( log , " Trying to switch to vt 1 " ) ;
if let Err ( err ) = session . change_vt ( 1 ) {
error! ( log , " Error switching to vt 1: {} " , err ) ;
}
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-01-12 14:49:55 +00:00
fn on_pointer_move (
& mut self , _evlh : & mut EventLoopHandle , _ : & 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-01-12 14:49:55 +00:00
fn on_pointer_move_absolute (
& mut self , _evlh : & mut EventLoopHandle , _ : & 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-01-12 14:49:55 +00:00
fn on_pointer_button (
& mut self , _evlh : & mut EventLoopHandle , _ : & 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-01-12 14:49:55 +00:00
fn on_pointer_axis (
& mut self , _evlh : & mut EventLoopHandle , _ : & input ::Seat , evt : LibinputPointerAxisEvent
) {
2017-11-07 00:18:52 +00:00
let axis = match evt . axis ( ) {
input ::Axis ::Vertical = > wayland_server ::protocol ::wl_pointer ::Axis ::VerticalScroll ,
input ::Axis ::Horizontal = > wayland_server ::protocol ::wl_pointer ::Axis ::HorizontalScroll ,
} ;
self . pointer . axis ( axis , evt . amount ( ) , evt . time ( ) ) ;
}
2018-01-12 14:49:55 +00:00
fn on_touch_down (
& mut self , _evlh : & mut EventLoopHandle , _ : & input ::Seat , _ : event ::touch ::TouchDownEvent
) {
2017-11-07 00:18:52 +00:00
/* not done in this example */
}
2018-01-12 14:49:55 +00:00
fn on_touch_motion (
& mut self , _evlh : & mut EventLoopHandle , _ : & input ::Seat , _ : event ::touch ::TouchMotionEvent
) {
2017-11-07 00:18:52 +00:00
/* not done in this example */
}
2018-01-12 14:49:55 +00:00
fn on_touch_up ( & mut self , _evlh : & mut EventLoopHandle , _ : & input ::Seat , _ : event ::touch ::TouchUpEvent ) {
2017-11-07 00:18:52 +00:00
/* not done in this example */
}
2018-01-12 14:49:55 +00:00
fn on_touch_cancel (
& mut self , _evlh : & mut EventLoopHandle , _ : & input ::Seat , _ : event ::touch ::TouchCancelEvent
) {
2017-11-07 00:18:52 +00:00
/* not done in this example */
}
2018-01-12 14:49:55 +00:00
fn on_touch_frame (
& mut self , _evlh : & mut EventLoopHandle , _ : & input ::Seat , _ : event ::touch ::TouchFrameEvent
) {
2017-11-07 00:18:52 +00:00
/* not done in this example */
}
2018-01-12 14:49:55 +00:00
fn on_input_config_changed ( & mut self , _evlh : & mut EventLoopHandle , _ : & 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
let ( mut display , mut event_loop ) = wayland_server ::create_display ( ) ;
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-01-05 19:04:46 +00:00
let display = Rc ::new ( display ) ;
2017-10-01 17:21:12 +00:00
/*
* Initialize the compositor
* /
init_shm_global ( & mut event_loop , vec! [ ] , log . clone ( ) ) ;
2018-01-07 21:30:38 +00:00
let ( compositor_token , _shell_state_token , window_map ) =
init_shell ( & mut event_loop , 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-07 21:30:38 +00:00
let udev_token = UdevBackend ::new (
& mut event_loop ,
& 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
let udev_session_id = notifier . register ( udev_token . clone ( ) ) ;
2017-11-07 00:18:52 +00:00
let ( seat_token , _ ) = Seat ::new ( & mut event_loop , session . seat ( ) . into ( ) , log . clone ( ) ) ;
let pointer = event_loop . state ( ) . get_mut ( & seat_token ) . add_pointer ( ) ;
let keyboard = event_loop
. state ( )
. get_mut ( & seat_token )
. add_keyboard ( " " , " " , " " , None , 1000 , 500 )
. expect ( " Failed to initialize the keyboard " ) ;
let ( output_token , _output_global ) = Output ::new (
& mut event_loop ,
" 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
event_loop
. state ( )
. get_mut ( & output_token )
. change_current_state (
Some ( Mode {
width : w as i32 ,
height : h as i32 ,
refresh : 60_000 ,
} ) ,
None ,
None ,
) ;
event_loop
. state ( )
. get_mut ( & output_token )
. set_preferred ( Mode {
width : w as i32 ,
height : h as i32 ,
refresh : 60_000 ,
} ) ;
/*
* 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 ) ;
2017-11-07 00:18:52 +00:00
let libinput_session_id = notifier . register ( libinput_context . clone ( ) ) ;
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-01-12 14:49:55 +00:00
libinput_backend . set_handler (
& mut event_loop ,
LibinputInputHandler {
log : log . clone ( ) ,
pointer ,
keyboard ,
window_map : window_map . clone ( ) ,
pointer_location ,
screen_size : ( w , h ) ,
serial : 0 ,
2018-01-27 12:07:35 +00:00
session : session ,
2018-01-12 14:49:55 +00:00
running : running . clone ( ) ,
} ,
) ;
2017-11-07 00:18:52 +00:00
let libinput_event_source = libinput_bind ( libinput_backend , & mut event_loop ) . unwrap ( ) ;
2018-01-27 12:07:35 +00:00
let session_event_source = auto_session_bind ( notifier , & mut event_loop ) . unwrap ( ) ;
2017-10-01 17:21:12 +00:00
let udev_event_source = udev_backend_bind ( & mut event_loop , udev_token ) . 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 {
display . flush_clients ( ) ;
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
let udev_token = udev_event_source . remove ( ) ;
let udev = event_loop . state ( ) . remove ( udev_token ) ;
udev . close ( event_loop . state ( ) ) ;
}
struct UdevHandlerImpl {
2018-01-05 19:04:46 +00:00
compositor_token : CompositorToken < SurfaceData , Roles , Rc < RefCell < Option < EGLDisplay > > > > ,
active_egl_context : Rc < RefCell < Option < EGLDisplay > > > ,
backends : HashMap < u64 , Rc < RefCell < HashMap < crtc ::Handle , GliumDrawer < DrmBackend < SessionFdDrmDevice > > > > > > ,
display : Rc < Display > ,
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 (
& self , device : & mut DrmDevice < SessionFdDrmDevice >
) -> 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
. 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-01-07 21:30:38 +00:00
fn device_added < ' a , S : Into < StateProxy < ' a > > > (
& mut self , _state : S , 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 {
* self . active_egl_context . borrow_mut ( ) = device . bind_wl_display ( & * self . display ) . ok ( ) ;
}
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-01-07 21:30:38 +00:00
fn device_changed < ' a , S : Into < StateProxy < ' a > > > (
& mut self , state : S , device : & StateToken < DrmDevice < SessionFdDrmDevice > >
) {
2018-01-05 19:04:46 +00:00
//quick and dirt, just re-init all backends
2017-10-01 17:21:12 +00:00
let mut state = state . into ( ) ;
2018-01-05 19:04:46 +00:00
let backends = self . backends . get ( & state . get ( device ) . device_id ( ) ) . unwrap ( ) ;
* backends . borrow_mut ( ) = self . scan_connectors ( state . get_mut ( device ) ) ;
2017-10-01 17:21:12 +00:00
}
2018-01-07 21:30:38 +00:00
fn device_removed < ' a , S : Into < StateProxy < ' a > > > (
& mut self , state : S , device : & StateToken < DrmDevice < SessionFdDrmDevice > >
) {
2018-01-05 19:04:46 +00:00
let state = state . into ( ) ;
let device = state . get ( device ) ;
// 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
}
fn error < ' a , S : Into < StateProxy < ' a > > > ( & mut self , _state : S , error : IoError ) {
error! ( self . logger , " {:?} " , error ) ;
}
}
pub struct DrmHandlerImpl {
2018-01-05 19:04:46 +00:00
compositor_token : CompositorToken < SurfaceData , Roles , Rc < RefCell < Option < EGLDisplay > > > > ,
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 (
& mut self , _device : & mut DrmDevice < SessionFdDrmDevice > , crtc : crtc ::Handle , _frame : u32 ,
_duration : Duration ,
) {
2018-01-05 19:04:46 +00:00
if let Some ( drawer ) = self . backends . borrow ( ) . get ( & crtc ) {
{
let ( x , y ) = * self . pointer_location . borrow ( ) ;
let _ = drawer . set_cursor_position ( x . trunc ( ) . abs ( ) as u32 , y . trunc ( ) . abs ( ) as u32 ) ;
}
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
{
let screen_dimensions = drawer . 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 ) {
x + = subdata . x ;
y + = subdata . y ;
}
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-01-07 21:30:38 +00:00
fn error ( & mut self , _device : & mut DrmDevice < SessionFdDrmDevice > , error : DrmError ) {
2017-10-01 17:21:12 +00:00
error! ( self . logger , " {:?} " , error ) ;
}
}