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-10-01 17:21:12 +00:00
use drm ::control ::crtc ;
2017-09-17 20:37:54 +00:00
use drm ::control ::encoder ::Info as EncoderInfo ;
2017-09-27 20:44:08 +00:00
use drm ::result ::Error as DrmError ;
2017-09-13 20:51:35 +00:00
use glium ::Surface ;
2017-09-22 12:56:59 +00:00
use helpers ::{ init_shell , GliumDrawer , MyWindowMap , Roles , SurfaceData } ;
2017-09-20 15:09:37 +00:00
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-28 19:57:02 +00:00
use smithay ::wayland ::compositor ::{ CompositorToken , SubsurfaceRole , TraversalAction } ;
use smithay ::wayland ::compositor ::roles ::Role ;
use smithay ::wayland ::shell ::ShellState ;
use smithay ::wayland ::shm ::init_shm_global ;
2017-09-22 12:56:59 +00:00
use std ::cell ::RefCell ;
2017-09-13 20:51:35 +00:00
use std ::fs ::OpenOptions ;
2017-09-22 12:56:59 +00:00
use std ::rc ::Rc ;
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 ( | |
2017-09-27 20:44:08 +00:00
* res_handles . filter_crtcs ( encoder_info . possible_crtcs ( ) )
2017-09-17 20:37:54 +00:00
. iter ( )
2017-09-27 20:44:08 +00:00
. next ( )
2017-09-17 20:37:54 +00:00
. 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-10-01 17:21:12 +00:00
{
// Initialize the hardware backend
let renderer = device
. create_backend ( crtc , mode , vec! [ connector_info . handle ( ) ] )
. unwrap ( ) ;
/*
* Initialize glium
* /
let mut frame = renderer . draw ( ) ;
frame . clear_color ( 0.8 , 0.8 , 0.9 , 1.0 ) ;
frame . finish ( ) . unwrap ( ) ;
}
2017-09-13 20:51:35 +00:00
/*
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-22 12:56:59 +00:00
let ( compositor_token , shell_state_token , window_map ) = init_shell ( & mut event_loop , log . clone ( ) ) ;
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-10-01 17:21:12 +00:00
let device_token = event_loop . state ( ) . insert ( device ) ;
2017-09-20 15:09:37 +00:00
let _source = drm_device_bind (
& mut event_loop ,
2017-10-01 17:21:12 +00:00
device_token ,
2017-09-20 15:09:37 +00:00
DrmHandlerImpl {
shell_state_token ,
compositor_token ,
2017-09-22 12:56:59 +00:00
window_map : window_map . clone ( ) ,
2017-09-20 15:09:37 +00:00
logger : log ,
} ,
) . unwrap ( ) ;
2017-09-13 20:51:35 +00:00
2017-09-22 12:56:59 +00:00
loop {
event_loop . dispatch ( Some ( 16 ) ) . unwrap ( ) ;
display . flush_clients ( ) ;
window_map . borrow_mut ( ) . refresh ( ) ;
}
2017-09-13 20:51:35 +00:00
}
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-22 12:56:59 +00:00
window_map : Rc < RefCell < MyWindowMap > > ,
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 {
2017-10-01 17:21:12 +00:00
fn ready ( & mut self , evlh : & mut EventLoopHandle , device : & StateToken < DrmDevice < GliumDrawer < DrmBackend > > > ,
crtc : & crtc ::Handle , _frame : u32 , _duration : Duration ) {
2017-09-20 17:48:58 +00:00
let state = evlh . state ( ) ;
2017-10-01 17:21:12 +00:00
let dev = state . get ( device ) ;
let drawer = dev . backend_for_crtc ( crtc ) . unwrap ( ) ;
2017-09-20 17:48:58 +00:00
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:53:56 +00:00
let screen_dimensions = drawer . get_framebuffer_dimensions ( ) ;
2017-09-22 12:56:59 +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 ) | {
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 ;
}
drawer . render (
& mut frame ,
contents ,
( w , h ) ,
( x , y ) ,
screen_dimensions ,
) ;
TraversalAction ::DoChildren ( ( x , y ) )
} else {
// we are not display, so our children are neither
TraversalAction ::SkipChildren
2017-09-13 20:51:35 +00:00
}
2017-09-22 12:56:59 +00:00
} ,
)
. unwrap ( ) ;
}
} ) ;
2017-09-13 20:51:35 +00:00
}
frame . finish ( ) . unwrap ( ) ;
}
2017-10-01 17:21:12 +00:00
fn error ( & mut self , _evlh : & mut EventLoopHandle , _device : & StateToken < DrmDevice < GliumDrawer < DrmBackend > > > ,
2017-09-27 20:44:08 +00:00
error : DrmError ) {
2017-09-14 21:20:48 +00:00
panic! ( " {:?} " , error ) ;
2017-09-13 20:51:35 +00:00
}
}