@ -32,11 +32,13 @@
# include <wayland-client.h>
# include <wayland-egl.h>
# include <wayland-cursor.h>
# include "compositor.h"
# include "gl-renderer.h"
# include "../shared/image-loader.h"
# include "../shared/os-compatibility.h"
# include "../shared/cairo-util.h"
struct wayland_compositor {
struct weston_compositor base ;
@ -57,9 +59,10 @@ struct wayland_compositor {
uint32_t event_mask ;
} parent ;
struct {
int32_t top , bottom , left , right ;
} border ;
struct theme * theme ;
cairo_device_t * frame_device ;
struct wl_cursor_theme * cursor_theme ;
struct wl_cursor * cursor ;
struct wl_list inputs ;
} ;
@ -74,6 +77,16 @@ struct wayland_output {
struct wl_egl_window * egl_window ;
} parent ;
int keyboard_count ;
struct frame * frame ;
struct {
cairo_surface_t * top ;
cairo_surface_t * left ;
cairo_surface_t * right ;
cairo_surface_t * bottom ;
} border ;
struct weston_mode mode ;
} ;
@ -87,40 +100,22 @@ struct wayland_input {
struct wl_pointer * pointer ;
struct wl_keyboard * keyboard ;
struct wl_touch * touch ;
struct {
struct wl_surface * surface ;
int32_t hx , hy ;
} cursor ;
} parent ;
uint32_t key_serial ;
uint32_t enter_serial ;
int focus ;
struct wayland_output * output ;
struct wayland_output * keyboard_focus ;
} ;
struct gl_renderer_interface * gl_renderer ;
static void
create_border ( struct wayland_compositor * c )
{
pixman_image_t * image ;
int32_t edges [ 4 ] ;
image = load_image ( DATADIR " /weston/border.png " ) ;
if ( ! image ) {
weston_log ( " couldn't load border image \n " ) ;
return ;
}
edges [ 0 ] = c - > border . left ;
edges [ 1 ] = c - > border . right ;
edges [ 2 ] = c - > border . top ;
edges [ 3 ] = c - > border . bottom ;
gl_renderer - > set_border ( & c - > base , pixman_image_get_width ( image ) ,
pixman_image_get_height ( image ) ,
pixman_image_get_data ( image ) , edges ) ;
pixman_image_unref ( image ) ;
}
static void
frame_done ( void * data , struct wl_callback * callback , uint32_t time )
{
@ -159,8 +154,14 @@ draw_initial_frame(struct wayland_output *output)
int fd ;
void * data ;
width = output - > mode . width + c - > border . left + c - > border . right ;
height = output - > mode . height + c - > border . top + c - > border . bottom ;
if ( output - > frame ) {
width = frame_width ( output - > frame ) ;
height = frame_height ( output - > frame ) ;
} else {
width = output - > mode . width ;
height = output - > mode . height ;
}
stride = width * 4 ;
size = height * stride ;
@ -196,6 +197,76 @@ draw_initial_frame(struct wayland_output *output)
wl_surface_damage ( surface , 0 , 0 , 1 , 1 ) ;
}
static void
wayland_output_update_gl_border ( struct wayland_output * output )
{
int32_t ix , iy , iwidth , iheight , fwidth , fheight ;
cairo_t * cr ;
if ( ! output - > frame )
return ;
if ( ! ( frame_status ( output - > frame ) & FRAME_STATUS_REPAINT ) )
return ;
fwidth = frame_width ( output - > frame ) ;
fheight = frame_height ( output - > frame ) ;
frame_interior ( output - > frame , & ix , & iy , & iwidth , & iheight ) ;
if ( ! output - > border . top )
output - > border . top =
cairo_image_surface_create ( CAIRO_FORMAT_ARGB32 ,
fwidth , iy ) ;
cr = cairo_create ( output - > border . top ) ;
frame_repaint ( output - > frame , cr ) ;
cairo_destroy ( cr ) ;
gl_renderer - > output_set_border ( & output - > base , GL_RENDERER_BORDER_TOP ,
fwidth , iy ,
cairo_image_surface_get_stride ( output - > border . top ) / 4 ,
cairo_image_surface_get_data ( output - > border . top ) ) ;
if ( ! output - > border . left )
output - > border . left =
cairo_image_surface_create ( CAIRO_FORMAT_ARGB32 ,
ix , 1 ) ;
cr = cairo_create ( output - > border . left ) ;
cairo_translate ( cr , 0 , - iy ) ;
frame_repaint ( output - > frame , cr ) ;
cairo_destroy ( cr ) ;
gl_renderer - > output_set_border ( & output - > base , GL_RENDERER_BORDER_LEFT ,
ix , 1 ,
cairo_image_surface_get_stride ( output - > border . left ) / 4 ,
cairo_image_surface_get_data ( output - > border . left ) ) ;
if ( ! output - > border . right )
output - > border . right =
cairo_image_surface_create ( CAIRO_FORMAT_ARGB32 ,
fwidth - ( ix + iwidth ) , 1 ) ;
cr = cairo_create ( output - > border . right ) ;
cairo_translate ( cr , - ( iwidth + ix ) , - iy ) ;
frame_repaint ( output - > frame , cr ) ;
cairo_destroy ( cr ) ;
gl_renderer - > output_set_border ( & output - > base , GL_RENDERER_BORDER_RIGHT ,
fwidth - ( ix + iwidth ) , 1 ,
cairo_image_surface_get_stride ( output - > border . right ) / 4 ,
cairo_image_surface_get_data ( output - > border . right ) ) ;
if ( ! output - > border . bottom )
output - > border . bottom =
cairo_image_surface_create ( CAIRO_FORMAT_ARGB32 ,
fwidth , fheight - ( iy + iheight ) ) ;
cr = cairo_create ( output - > border . bottom ) ;
cairo_translate ( cr , 0 , - ( iy + iheight ) ) ;
frame_repaint ( output - > frame , cr ) ;
cairo_destroy ( cr ) ;
gl_renderer - > output_set_border ( & output - > base , GL_RENDERER_BORDER_BOTTOM ,
fwidth , fheight - ( iy + iheight ) ,
cairo_image_surface_get_stride ( output - > border . bottom ) / 4 ,
cairo_image_surface_get_data ( output - > border . bottom ) ) ;
}
static void
wayland_output_start_repaint_loop ( struct weston_output * output_base )
{
@ -232,6 +303,8 @@ wayland_output_repaint(struct weston_output *output_base,
callback = wl_surface_frame ( output - > parent . surface ) ;
wl_callback_add_listener ( callback , & frame_listener , output ) ;
wayland_output_update_gl_border ( output ) ;
ec - > renderer - > repaint_output ( & output - > base , damage ) ;
pixman_region32_subtract ( & ec - > primary_plane . damage ,
@ -247,6 +320,18 @@ wayland_output_destroy(struct weston_output *output_base)
gl_renderer - > output_destroy ( output_base ) ;
wl_egl_window_destroy ( output - > parent . egl_window ) ;
wl_surface_destroy ( output - > parent . surface ) ;
wl_shell_surface_destroy ( output - > parent . shell_surface ) ;
if ( output - > frame ) {
frame_destroy ( output - > frame ) ;
cairo_surface_destroy ( output - > border . top ) ;
cairo_surface_destroy ( output - > border . left ) ;
cairo_surface_destroy ( output - > border . right ) ;
cairo_surface_destroy ( output - > border . bottom ) ;
}
weston_output_destroy ( & output - > base ) ;
free ( output ) ;
return ;
@ -259,6 +344,8 @@ wayland_compositor_create_output(struct wayland_compositor *c,
int width , int height )
{
struct wayland_output * output ;
int32_t fx , fy , fwidth , fheight ;
struct wl_region * region ;
output = zalloc ( sizeof * output ) ;
if ( output = = NULL )
@ -281,14 +368,25 @@ wayland_compositor_create_output(struct wayland_compositor *c,
weston_output_move ( & output - > base , 0 , 0 ) ;
if ( ! c - > theme )
c - > theme = theme_create ( ) ;
output - > frame = frame_create ( c - > theme , width , height ,
FRAME_BUTTON_CLOSE , " Weston " ) ;
frame_resize_inside ( output - > frame , width , height ) ;
frame_interior ( output - > frame , & fx , & fy , NULL , NULL ) ;
fwidth = frame_width ( output - > frame ) ;
fheight = frame_height ( output - > frame ) ;
weston_log ( " Creating %dx%d wayland output (%dx%d actual) \n " ,
width , height , fwidth , fheight ) ;
output - > parent . surface =
wl_compositor_create_surface ( c - > parent . compositor ) ;
wl_surface_set_user_data ( output - > parent . surface , output ) ;
output - > parent . egl_window =
wl_egl_window_create ( output - > parent . surface ,
width + c - > border . left + c - > border . right ,
height + c - > border . top + c - > border . bottom ) ;
fwidth , fheight ) ;
if ( ! output - > parent . egl_window ) {
weston_log ( " failure to create wl_egl_window \n " ) ;
goto cleanup_output ;
@ -298,6 +396,23 @@ wayland_compositor_create_output(struct wayland_compositor *c,
output - > parent . egl_window ) < 0 )
goto cleanup_window ;
output - > base . border . left = fx ;
output - > base . border . top = fy ;
output - > base . border . right = fwidth - width - fx ;
output - > base . border . bottom = fheight - height - fy ;
frame_input_rect ( output - > frame , & fx , & fy , & fwidth , & fheight ) ;
region = wl_compositor_create_region ( c - > parent . compositor ) ;
wl_region_add ( region , fx , fy , fwidth , fheight ) ;
wl_surface_set_input_region ( output - > parent . surface , region ) ;
wl_region_destroy ( region ) ;
frame_opaque_rect ( output - > frame , & fx , & fy , & fwidth , & fheight ) ;
region = wl_compositor_create_region ( c - > parent . compositor ) ;
wl_region_add ( region , fx , fy , fwidth , fheight ) ;
wl_surface_set_opaque_region ( output - > parent . surface , region ) ;
wl_region_destroy ( region ) ;
output - > parent . draw_initial_frame = 1 ;
output - > parent . shell_surface =
wl_shell_get_shell_surface ( c - > parent . shell ,
@ -392,47 +507,72 @@ static const struct wl_output_listener output_listener = {
display_handle_mode
} ;
/* parent input interface */
static void
check_focus ( struct wayland_input * input , wl_fixed_t x , wl_fixed_t y )
input_set_cursor ( struct wayland_input * input )
{
struct wayland_compositor * c = input - > compositor ;
int width , height , inside ;
width = input - > output - > mode . width ;
height = input - > output - > mode . height ;
struct wl_buffer * buffer ;
struct wl_cursor_image * image ;
inside = c - > border . left < = wl_fixed_to_int ( x ) & &
wl_fixed_to_int ( x ) < width + c - > border . left & &
c - > border . top < = wl_fixed_to_int ( y ) & &
wl_fixed_to_int ( y ) < height + c - > border . top ;
if ( ! input - > compositor - > cursor )
return ; /* Couldn't load the cursor. Can't set it */
if ( ! input - > focus & & inside ) {
notify_pointer_focus ( & input - > base , & input - > output - > base ,
x - wl_fixed_from_int ( c - > border . left ) ,
y = wl_fixed_from_int ( c - > border . top ) ) ;
wl_pointer_set_cursor ( input - > parent . pointer ,
input - > enter_serial , NULL , 0 , 0 ) ;
} else if ( input - > focus & & ! inside ) {
notify_pointer_focus ( & input - > base , NULL , 0 , 0 ) ;
/* FIXME: Should set default cursor here. */
}
image = input - > compositor - > cursor - > images [ 0 ] ;
buffer = wl_cursor_image_get_buffer ( image ) ;
input - > focus = inside ;
wl_pointer_set_cursor ( input - > parent . pointer , input - > enter_serial ,
input - > parent . cursor . surface ,
image - > hotspot_x , image - > hotspot_y ) ;
wl_surface_attach ( input - > parent . cursor . surface , buffer , 0 , 0 ) ;
wl_surface_damage ( input - > parent . cursor . surface , 0 , 0 ,
image - > width , image - > height ) ;
wl_surface_commit ( input - > parent . cursor . surface ) ;
}
/* parent input interface */
static void
input_handle_pointer_enter ( void * data , struct wl_pointer * pointer ,
uint32_t serial , struct wl_surface * surface ,
wl_fixed_t x , wl_fixed_t y )
{
struct wayland_input * input = data ;
int32_t fx , fy ;
enum theme_location location ;
/* XXX: If we get a modifier event immediately before the focus,
* we should try to keep the same serial . */
input - > enter_serial = serial ;
input - > output = wl_surface_get_user_data ( surface ) ;
check_focus ( input , x , y ) ;
if ( input - > output - > frame ) {
location = frame_pointer_enter ( input - > output - > frame , input ,
wl_fixed_to_int ( x ) ,
wl_fixed_to_int ( y ) ) ;
frame_interior ( input - > output - > frame , & fx , & fy , NULL , NULL ) ;
x - = wl_fixed_from_int ( fx ) ;
y - = wl_fixed_from_int ( fy ) ;
if ( frame_status ( input - > output - > frame ) & FRAME_STATUS_REPAINT )
weston_output_schedule_repaint ( & input - > output - > base ) ;
} else {
location = THEME_LOCATION_CLIENT_AREA ;
}
x + = wl_fixed_from_int ( input - > output - > base . x ) ;
y + = wl_fixed_from_int ( input - > output - > base . y ) ;
if ( location = = THEME_LOCATION_CLIENT_AREA ) {
input - > focus = 1 ;
notify_pointer_focus ( & input - > base , & input - > output - > base , x , y ) ;
wl_pointer_set_cursor ( input - > parent . pointer ,
input - > enter_serial , NULL , 0 , 0 ) ;
} else {
input - > focus = 0 ;
notify_pointer_focus ( & input - > base , NULL , 0 , 0 ) ;
input_set_cursor ( input ) ;
}
}
static void
@ -441,6 +581,13 @@ input_handle_pointer_leave(void *data, struct wl_pointer *pointer,
{
struct wayland_input * input = data ;
if ( input - > output - > frame ) {
frame_pointer_leave ( input - > output - > frame , input ) ;
if ( frame_status ( input - > output - > frame ) & FRAME_STATUS_REPAINT )
weston_output_schedule_repaint ( & input - > output - > base ) ;
}
notify_pointer_focus ( & input - > base , NULL , 0 , 0 ) ;
input - > output = NULL ;
input - > focus = 0 ;
@ -451,15 +598,39 @@ input_handle_motion(void *data, struct wl_pointer *pointer,
uint32_t time , wl_fixed_t x , wl_fixed_t y )
{
struct wayland_input * input = data ;
struct wayland_compositor * c = input - > compositor ;
int32_t fx , fy ;
enum theme_location location ;
if ( input - > output - > frame ) {
location = frame_pointer_motion ( input - > output - > frame , input ,
wl_fixed_to_int ( x ) ,
wl_fixed_to_int ( y ) ) ;
frame_interior ( input - > output - > frame , & fx , & fy , NULL , NULL ) ;
x - = wl_fixed_from_int ( fx ) ;
y - = wl_fixed_from_int ( fy ) ;
if ( frame_status ( input - > output - > frame ) & FRAME_STATUS_REPAINT )
weston_output_schedule_repaint ( & input - > output - > base ) ;
} else {
location = THEME_LOCATION_CLIENT_AREA ;
}
check_focus ( input , x , y ) ;
if ( input - > focus )
notify_motion ( & input - > base , time ,
x - wl_fixed_from_int ( c - > border . left ) -
input - > base . pointer - > x ,
y - wl_fixed_from_int ( c - > border . top ) -
input - > base . pointer - > y ) ;
x + = wl_fixed_from_int ( input - > output - > base . x ) ;
y + = wl_fixed_from_int ( input - > output - > base . y ) ;
if ( input - > focus & & location ! = THEME_LOCATION_CLIENT_AREA ) {
input_set_cursor ( input ) ;
notify_pointer_focus ( & input - > base , NULL , 0 , 0 ) ;
input - > focus = 0 ;
} else if ( ! input - > focus & & location = = THEME_LOCATION_CLIENT_AREA ) {
wl_pointer_set_cursor ( input - > parent . pointer ,
input - > enter_serial , NULL , 0 , 0 ) ;
notify_pointer_focus ( & input - > base , & input - > output - > base , x , y ) ;
input - > focus = 1 ;
}
if ( location = = THEME_LOCATION_CLIENT_AREA )
notify_motion_absolute ( & input - > base , time , x , y ) ;
}
static void
@ -469,8 +640,36 @@ input_handle_button(void *data, struct wl_pointer *pointer,
{
struct wayland_input * input = data ;
enum wl_pointer_button_state state = state_w ;
enum frame_button_state fstate ;
enum theme_location location ;
if ( input - > output - > frame ) {
fstate = state = = WL_POINTER_BUTTON_STATE_PRESSED ?
FRAME_BUTTON_PRESSED : FRAME_BUTTON_RELEASED ;
location = frame_pointer_button ( input - > output - > frame , input ,
button , fstate ) ;
if ( frame_status ( input - > output - > frame ) & FRAME_STATUS_MOVE ) {
notify_button ( & input - > base , time , button , state ) ;
wl_shell_surface_move ( input - > output - > parent . shell_surface ,
input - > parent . seat , serial ) ;
frame_status_clear ( input - > output - > frame ,
FRAME_STATUS_MOVE ) ;
return ;
}
if ( frame_status ( input - > output - > frame ) & FRAME_STATUS_CLOSE )
wl_display_terminate ( input - > compositor - > base . wl_display ) ;
if ( frame_status ( input - > output - > frame ) & FRAME_STATUS_REPAINT )
weston_output_schedule_repaint ( & input - > output - > base ) ;
} else {
location = THEME_LOCATION_CLIENT_AREA ;
}
if ( location = = THEME_LOCATION_CLIENT_AREA )
notify_button ( & input - > base , time , button , state ) ;
}
static void
@ -542,6 +741,28 @@ input_handle_keyboard_enter(void *data,
struct wl_array * keys )
{
struct wayland_input * input = data ;
struct wayland_output * focus ;
focus = input - > keyboard_focus ;
if ( focus ) {
/* This shouldn't happen */
focus - > keyboard_count - - ;
if ( ! focus - > keyboard_count & & focus - > frame )
frame_unset_flag ( focus - > frame , FRAME_FLAG_ACTIVE ) ;
if ( frame_status ( focus - > frame ) & FRAME_STATUS_REPAINT )
weston_output_schedule_repaint ( & focus - > base ) ;
}
input - > keyboard_focus = wl_surface_get_user_data ( surface ) ;
input - > keyboard_focus - > keyboard_count + + ;
focus = input - > keyboard_focus ;
if ( focus - > frame ) {
frame_set_flag ( focus - > frame , FRAME_FLAG_ACTIVE ) ;
if ( frame_status ( focus - > frame ) & FRAME_STATUS_REPAINT )
weston_output_schedule_repaint ( & focus - > base ) ;
}
/* XXX: If we get a modifier event immediately before the focus,
* we should try to keep the same serial . */
@ -556,8 +777,22 @@ input_handle_keyboard_leave(void *data,
struct wl_surface * surface )
{
struct wayland_input * input = data ;
struct wayland_output * focus ;
notify_keyboard_focus_out ( & input - > base ) ;
focus = input - > keyboard_focus ;
if ( ! focus )
return ; /* This shouldn't happen */
focus - > keyboard_count - - ;
if ( ! focus - > keyboard_count & & focus - > frame ) {
frame_unset_flag ( focus - > frame , FRAME_FLAG_ACTIVE ) ;
if ( frame_status ( focus - > frame ) & FRAME_STATUS_REPAINT )
weston_output_schedule_repaint ( & focus - > base ) ;
}
input - > keyboard_focus = NULL ;
}
static void
@ -654,6 +889,9 @@ display_add_seat(struct wayland_compositor *c, uint32_t id)
wl_seat_add_listener ( input - > parent . seat , & seat_listener , input ) ;
wl_seat_set_user_data ( input - > parent . seat , input ) ;
input - > parent . cursor . surface =
wl_compositor_create_surface ( c - > parent . compositor ) ;
}
static void
@ -731,6 +969,37 @@ wayland_destroy(struct weston_compositor *ec)
free ( ec ) ;
}
static const char * left_ptrs [ ] = {
" left_ptr " ,
" default " ,
" top_left_arrow " ,
" left-arrow "
} ;
static void
create_cursor ( struct wayland_compositor * c , struct weston_config * config )
{
struct weston_config_section * s ;
int size ;
char * theme = NULL ;
unsigned int i ;
s = weston_config_get_section ( config , " shell " , NULL , NULL ) ;
weston_config_section_get_string ( s , " cursor-theme " , & theme , NULL ) ;
weston_config_section_get_int ( s , " cursor-size " , & size , 32 ) ;
c - > cursor_theme = wl_cursor_theme_load ( theme , size , c - > parent . shm ) ;
c - > cursor = NULL ;
for ( i = 0 ; ! c - > cursor & & i < ARRAY_LENGTH ( left_ptrs ) ; + + i )
c - > cursor = wl_cursor_theme_get_cursor ( c - > cursor_theme ,
left_ptrs [ i ] ) ;
if ( ! c - > cursor ) {
fprintf ( stderr , " could not load left cursor \n " ) ;
return ;
}
}
static struct weston_compositor *
wayland_compositor_create ( struct wl_display * display ,
int width , int height , const char * display_name ,
@ -759,7 +1028,9 @@ wayland_compositor_create(struct wl_display *display,
wl_list_init ( & c - > inputs ) ;
c - > parent . registry = wl_display_get_registry ( c - > parent . wl_display ) ;
wl_registry_add_listener ( c - > parent . registry , & registry_listener , c ) ;
wl_display_dispatch ( c - > parent . wl_display ) ;
wl_display_roundtrip ( c - > parent . wl_display ) ;
create_cursor ( c , config ) ;
c - > base . wl_display = display ;
@ -776,19 +1047,10 @@ wayland_compositor_create(struct wl_display *display,
c - > base . destroy = wayland_destroy ;
c - > base . restore = wayland_restore ;
c - > border . top = 30 ;
c - > border . bottom = 24 ;
c - > border . left = 25 ;
c - > border . right = 26 ;
/* requires border fields */
if ( wayland_compositor_create_output ( c , width , height ) < 0 )
goto err_gl ;
/* requires gl_renderer->output_state_create called
* by wayland_compositor_create_output */
create_border ( c ) ;
loop = wl_display_get_event_loop ( c - > base . wl_display ) ;
fd = wl_display_get_fd ( c - > parent . wl_display ) ;