2017-09-13 20:51:35 +00:00
extern crate drm ;
#[ macro_use ]
extern crate glium ;
extern crate rand ;
#[ macro_use(define_roles) ]
extern crate smithay ;
extern crate wayland_server ;
#[ 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 } ;
2017-09-17 20:37:54 +00:00
use drm ::control ::encoder ::Info as EncoderInfo ;
2017-09-13 20:51:35 +00:00
use glium ::Surface ;
2017-09-20 15:09:37 +00:00
use helpers ::{ shell_implementation , surface_implementation , GliumDrawer , Roles , SurfaceData } ;
use slog ::{ Drain , Logger } ;
2017-09-20 17:48:58 +00:00
use smithay ::backend ::drm ::{ drm_device_bind , DrmBackend , DrmDevice , DrmHandler } ;
2017-09-13 20:51:35 +00:00
use smithay ::backend ::graphics ::egl ::EGLGraphicsBackend ;
2017-09-20 15:09:37 +00:00
use smithay ::compositor ::{ compositor_init , CompositorToken , SubsurfaceRole , TraversalAction } ;
2017-09-13 20:51:35 +00:00
use smithay ::compositor ::roles ::Role ;
2017-09-20 15:09:37 +00:00
use smithay ::shell ::{ shell_init , ShellState } ;
use smithay ::shm ::init_shm_global ;
2017-09-21 17:05:59 +00:00
use std ::borrow ::Borrow ;
2017-09-13 20:51:35 +00:00
use std ::fs ::OpenOptions ;
use std ::io ::Error as IoError ;
2017-09-14 20:32:53 +00:00
use std ::time ::Duration ;
2017-09-20 15:09:37 +00:00
use wayland_server ::{ EventLoopHandle , StateToken } ;
2017-09-13 20:51:35 +00:00
fn main ( ) {
// A logger facility, here we use the terminal for this example
let log = Logger ::root (
slog_async ::Async ::default ( slog_term ::term_full ( ) . fuse ( ) ) . fuse ( ) ,
o! ( ) ,
) ;
// Initialize the wayland server
let ( mut display , mut event_loop ) = wayland_server ::create_display ( ) ;
2017-09-14 21:20:48 +00:00
/*
* Initialize the drm backend
* /
2017-09-13 20:51:35 +00:00
// "Find" a suitable drm device
let mut options = OpenOptions ::new ( ) ;
options . read ( true ) ;
options . write ( true ) ;
2017-09-20 17:48:58 +00:00
let mut device : DrmDevice < GliumDrawer < DrmBackend > > =
2017-09-13 20:51:35 +00:00
DrmDevice ::new_from_file ( options . clone ( ) . open ( " /dev/dri/card0 " ) . unwrap ( ) , log . clone ( ) ) . unwrap ( ) ;
// Get a set of all modesetting resource handles (excluding planes):
let res_handles = device . resource_handles ( ) . unwrap ( ) ;
// Use first connected connector
let connector_info = res_handles
. connectors ( )
. iter ( )
. map ( | conn | {
ConnectorInfo ::load_from_device ( & device , * conn ) . unwrap ( )
} )
. find ( | conn | conn . connection_state ( ) = = ConnectorState ::Connected )
. unwrap ( ) ;
2017-09-17 20:37:54 +00:00
// Use the first encoder
let encoder_info = EncoderInfo ::load_from_device ( & device , connector_info . encoders ( ) [ 0 ] ) . unwrap ( ) ;
// use the connected crtc if any
let crtc = encoder_info . current_crtc ( )
// or use the first one that is compatible with the encoder
. unwrap_or_else ( | |
* res_handles . crtcs ( )
. iter ( )
. find ( | crtc | encoder_info . supports_crtc ( * * crtc ) )
. unwrap ( ) ) ;
2017-09-13 20:51:35 +00:00
// Assuming we found a good connector and loaded the info into `connector_info`
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.)
2017-09-14 21:20:48 +00:00
// Initialize the hardware backend
2017-09-20 17:48:58 +00:00
let renderer_token = device
. create_backend ( & mut event_loop , crtc , mode , vec! [ connector_info . handle ( ) ] )
2017-09-13 20:51:35 +00:00
. unwrap ( ) ;
/*
2017-09-20 15:09:37 +00:00
* Initialize the globals
2017-09-13 20:51:35 +00:00
* /
2017-09-20 15:09:37 +00:00
init_shm_global ( & mut event_loop , vec! [ ] , log . clone ( ) ) ;
2017-09-13 20:51:35 +00:00
2017-09-20 15:09:37 +00:00
let ( compositor_token , _ , _ ) =
compositor_init ( & mut event_loop , surface_implementation ( ) , ( ) , log . clone ( ) ) ;
2017-09-13 20:51:35 +00:00
2017-09-20 15:09:37 +00:00
let ( shell_state_token , _ , _ ) = shell_init (
& mut event_loop ,
compositor_token ,
shell_implementation ( ) ,
2017-09-13 20:51:35 +00:00
compositor_token ,
log . clone ( ) ,
2017-09-20 15:09:37 +00:00
) ;
2017-09-13 20:51:35 +00:00
/*
* Initialize glium
* /
2017-09-20 17:48:58 +00:00
{
let drawer = event_loop . state ( ) . get ( & renderer_token ) ;
let mut frame = drawer . draw ( ) ;
frame . clear_color ( 0.8 , 0.8 , 0.9 , 1.0 ) ;
frame . finish ( ) . unwrap ( ) ;
}
2017-09-13 20:51:35 +00:00
/*
* Add a listening socket :
* /
let name = display . add_socket_auto ( ) . unwrap ( ) . into_string ( ) . unwrap ( ) ;
println! ( " Listening on socket: {} " , name ) ;
2017-09-14 21:20:48 +00:00
/*
* Register the DrmDevice on the EventLoop
* /
2017-09-20 15:09:37 +00:00
let _source = drm_device_bind (
& mut event_loop ,
device ,
DrmHandlerImpl {
shell_state_token ,
compositor_token ,
logger : log ,
} ,
) . unwrap ( ) ;
2017-09-13 20:51:35 +00:00
event_loop . run ( ) . unwrap ( ) ;
}
pub struct DrmHandlerImpl {
2017-09-20 15:09:37 +00:00
shell_state_token : StateToken < ShellState < SurfaceData , Roles , ( ) , ( ) > > ,
compositor_token : CompositorToken < SurfaceData , Roles , ( ) > ,
2017-09-13 20:51:35 +00:00
logger : ::slog ::Logger ,
}
2017-09-20 17:48:58 +00:00
impl DrmHandler < GliumDrawer < DrmBackend > > for DrmHandlerImpl {
fn ready ( & mut self , evlh : & mut EventLoopHandle , _device : & mut DrmDevice < GliumDrawer < DrmBackend > > ,
backend : & StateToken < GliumDrawer < DrmBackend > > , _frame : u32 , _duration : Duration ) {
let state = evlh . state ( ) ;
let drawer = state . get ( backend ) ;
let mut frame = drawer . draw ( ) ;
2017-09-13 20:51:35 +00:00
frame . clear_color ( 0.8 , 0.8 , 0.9 , 1.0 ) ;
// redraw the frame, in a simple but inneficient way
{
2017-09-21 17:05:59 +00:00
let screen_dimensions = ( drawer . borrow ( ) as & DrmBackend ) . get_framebuffer_dimensions ( ) ;
2017-09-20 15:09:37 +00:00
for toplevel_surface in state . get ( & self . shell_state_token ) . toplevel_surfaces ( ) {
2017-09-13 20:51:35 +00:00
if let Some ( wl_surface ) = toplevel_surface . get_surface ( ) {
// this surface is a root of a subsurface tree that needs to be drawn
let initial_place = self . compositor_token
. with_surface_data ( wl_surface , | data | data . user_data . location . unwrap_or ( ( 0 , 0 ) ) ) ;
self . compositor_token
. with_surface_tree (
wl_surface ,
initial_place ,
| _surface , attributes , role , & ( mut x , mut y ) | {
if let Some ( ( ref contents , ( w , h ) ) ) = attributes . user_data . buffer {
// there is actually something to draw !
if let Ok ( subdata ) = Role ::< SubsurfaceRole > ::data ( role ) {
x + = subdata . x ;
y + = subdata . y ;
}
2017-09-20 17:48:58 +00:00
drawer . render ( & mut frame , contents , ( w , h ) , ( x , y ) , screen_dimensions ) ;
2017-09-13 20:51:35 +00:00
TraversalAction ::DoChildren ( ( x , y ) )
} else {
// we are not display, so our children are neither
TraversalAction ::SkipChildren
}
} ,
)
. unwrap ( ) ;
}
}
}
frame . finish ( ) . unwrap ( ) ;
}
2017-09-20 17:48:58 +00:00
fn error ( & mut self , _evlh : & mut EventLoopHandle , _device : & mut DrmDevice < GliumDrawer < DrmBackend > > ,
error : IoError ) {
2017-09-14 21:20:48 +00:00
panic! ( " {:?} " , error ) ;
2017-09-13 20:51:35 +00:00
}
}