From 60cface2275f5610f87deb3331f96b1080f68b45 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Wed, 8 Jun 2022 09:28:46 +0200 Subject: [PATCH 01/30] Snake and gradient examples --- examples/Gradients.ml | 44 ++++++++++++++++++++ examples/SimpleSnakeGame.ml | 83 +++++++++++++++++++++++++++++++++++++ examples/dune | 16 +++++++ 3 files changed, 143 insertions(+) create mode 100644 examples/Gradients.ml create mode 100644 examples/SimpleSnakeGame.ml diff --git a/examples/Gradients.ml b/examples/Gradients.ml new file mode 100644 index 00000000..8e1bb030 --- /dev/null +++ b/examples/Gradients.ml @@ -0,0 +1,44 @@ +open OcamlCanvas +open Float + + +let interpInt x1 x2 t = + int_of_float ((1. -. t)*.(float_of_int x1) +. t*.(float_of_int x2)) +let interpColor c1 c2 t = + let r1, g1, b1 = Color.to_rgb c1 and r2, g2, b2 = Color.to_rgb c2 in + Color.of_rgb (interpInt r1 r2 t) (interpInt g1 g2 t) (interpInt b1 b2 t) +let hsv_to_rgb h s v = + let c = v *. s in + let m = v -. c in + let x = c *. (1. -. abs( ( (rem (h /. 60.) 2.) -. 1.))) in + let r,g,b = match(h) with + |a when a < 60. -> c,x,0. + |a when a < 120. -> x,c,0. + |a when a < 180. -> 0.,c,x + |a when a < 240. -> 0.,x,c + |a when a < 300. -> x,0.,c + |_ -> c,0.,x + in Color.of_rgb (int_of_float((r +. m)*.255.)) (int_of_float((g +. m)*.255.)) (int_of_float((b +. m)*.255.)) + +open Int64 + +let () = + Backend.(init default_options); + let c = Canvas.createFramed "test" ~pos:(960-640,540-360) ~size:(1280,720) in + Canvas.setFillColor c Color.white; + Canvas.fillRect c ~pos:(0.,0.) ~size:(1280.,720.); + Canvas.show c; + let r = ref (-1.) in + Backend.run(function + |Frame { canvas = c; timestamp = _ } -> + r := !r +. 1. /. 60.; + Canvas.setFillColor c (hsv_to_rgb (!r *. 36.) 1. 1.); + Canvas.fillRect c ~pos:(128. *. !r,0.) ~size:(128., 360.); + Canvas.setFillColor c (interpColor Color.black Color.white (!r *. 0.1)); + Canvas.fillRect c ~pos:(128. *. !r,360.) ~size:(128., 360.); + true; + |_ -> + false; + )(function () -> + Printf.printf "Goodbye !\n" + ) \ No newline at end of file diff --git a/examples/SimpleSnakeGame.ml b/examples/SimpleSnakeGame.ml new file mode 100644 index 00000000..b81e3b86 --- /dev/null +++ b/examples/SimpleSnakeGame.ml @@ -0,0 +1,83 @@ +open OcamlCanvas +open Int64 +open Random + +let buildBackground c = + Canvas.setFillColor c Color.black; + Canvas.fillRect c ~pos:(0.,0.) ~size:(500.,500.); + Canvas.setFillColor c Color.white; + Canvas.fillRect c ~pos:(0.,0.) ~size:(500.,10.); + Canvas.fillRect c ~pos:(0.,490.) ~size:(500.,10.); + Canvas.fillRect c ~pos:(0.,0.) ~size:(10.,500.); + Canvas.fillRect c ~pos:(490.,0.) ~size:(10.,500.); + () + +let placeBlock c (x,y) col = + Canvas.setFillColor c col; + Canvas.fillRect c ~pos:(x *. 10. , y *. 10.) ~size:(10.,10.); + () + +let rec drawSnake c s = match(s) with + |[] -> () + |h::t -> placeBlock c h Color.orange; drawSnake c t + +let rec moveSnake s p = match(s) with + |[] -> [] + |h::t -> p::(moveSnake t h) + +let sumCoord (a,b) (c,d) = (a +. c,b +. d) + +let moveSnakeDirection s d = match(s) with + |[] -> [] + |h::t -> moveSnake s (sumCoord d h) + +let snakeHitSelf s = match(s) with + |[] -> false + |h::t -> (List.mem h t) +let snakeHitWall s = let h::t = s in let (x,y) = h in (x < 1.) or (x > 48.) or (y < 1.) or (y > 48.) + + +let () = + Random.self_init(); + Backend.(init default_options); + let c = Canvas.createFramed "test" ~pos:(960-250,540-250) ~size:(500,500) in + Canvas.show c; + let r = ref (-1.) in + let snake = ref [(6.,8.);(6.,7.)] and currentDirection = ref (0.,1.) and foodLocation = ref(24.,24.) in + Backend.run(function + |KeyAction { canvas = c; timestamp = _; + key = KeyUpArrow; char; flags = _; state = Down } -> + let (x,y) = !currentDirection in + if (y = 0.) then currentDirection := (0.,-1.); + true; + |KeyAction { canvas = c; timestamp = _; + key = KeyDownArrow; char; flags = _; state = Down } -> + let (x,y) = !currentDirection in + if (y = 0.) then currentDirection := (0.,1.); + true; + |KeyAction { canvas = c; timestamp = _; + key = KeyLeftArrow; char; flags = _; state = Down } -> + let (x,y) = !currentDirection in + if (x = 0.) then currentDirection := (-1.,0.); + true; + |KeyAction { canvas = c; timestamp = _; + key = KeyRightArrow; char; flags = _; state = Down } -> + let (x,y) = !currentDirection in + if (x = 0.) then currentDirection := (1.,0.); + true; + + |Frame { canvas = c; timestamp = _ } -> + r := !r +. 1. /. 60.; + buildBackground c; + let h::t = !snake in + if ((sumCoord h !currentDirection) = !foodLocation) then (snake := !foodLocation::!snake; foodLocation := (2. +. float_of_int (Random.int 47),2. +. float_of_int (Random.int 47))); + if !r > 0.033 then (r := 0.; snake := moveSnakeDirection !snake !currentDirection); + if (snakeHitSelf !snake or snakeHitWall !snake) then Backend.stop(); + drawSnake c !snake; + placeBlock c !foodLocation Color.green; + true; + |_ -> + false; + )(function () -> + Printf.printf "Goodbye !\n" + ) \ No newline at end of file diff --git a/examples/dune b/examples/dune index 70c20502..3ca013a6 100644 --- a/examples/dune +++ b/examples/dune @@ -14,3 +14,19 @@ (modules test_canvas) (libraries ocaml-canvas) ) + +(executable + (name Gradients) + (public_name Gradients) + (modes byte_complete native js) + (modules Gradients) + (libraries ocaml-canvas) +) + +(executable + (name SimpleSnakeGame) + (public_name Snake) + (modes byte_complete native js) + (modules SimpleSnakeGame) + (libraries ocaml-canvas) +) From 953d84a8d56a3d1932331a85bde211ca9c1e5b8c Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Mon, 13 Jun 2022 11:59:52 +0200 Subject: [PATCH 02/30] Implemented wl_surface.c --- src/implem/wayland/wl_surface.c | 55 +++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/src/implem/wayland/wl_surface.c b/src/implem/wayland/wl_surface.c index 7365a160..60c32f1b 100644 --- a/src/implem/wayland/wl_surface.c +++ b/src/implem/wayland/wl_surface.c @@ -33,6 +33,10 @@ typedef struct surface_impl_wl_t { impl_type_t type; struct wl_buffer *wl_buffer; struct wl_surface *wl_surface; + + //data for destruction + uint8_t* color_data; + uint32_t color_data_size; } surface_impl_wl_t; static void @@ -106,7 +110,7 @@ surface_create_wl_impl( // _surface_create_wl_image(..., width, height, &s->data, ...); - uint32_t shm_pool_size = width * height * 4 * 2; + uint32_t shm_pool_size = width * height * 4; int fd = _allocate_shm_file(shm_pool_size); uint8_t *pool_data = (uint8_t *)mmap(NULL, shm_pool_size, PROT_READ | PROT_WRITE, @@ -117,21 +121,19 @@ surface_create_wl_impl( close(fd); // fd no longer needed at this point struct wl_buffer *wl_buffer = - wl_shm_pool_create_buffer(pool, 0 /* offset */, width, height, width * 4, - WL_SHM_FORMAT_XRGB8888); // or ARGB for alpha + wl_shm_pool_create_buffer(pool, 0, width, height, width * 4, + WL_SHM_FORMAT_ARGB8888); // or ARGB for alpha // or pool could be kept... wl_shm_pool_destroy(pool); // the buffer keeps a reference to the pool so it's ok to destroy -// do that when destroying buffer - //munmap(state->data, size); - - - impl->type = IMPL_WAYLAND; impl->wl_buffer = wl_buffer; impl->wl_surface = wl_target->wl_surface; *data = (color_t_ *)pool_data; + impl->color_data = (uint8_t*)pool_data; + impl->color_data_size = width * height * 4; + return impl; } @@ -143,10 +145,13 @@ surface_destroy_wl_impl( assert(impl != NULL); assert(impl->type == IMPL_WAYLAND); - // TODO + munmap(impl->color_data,impl->color_data_size); + wl_buffer_destroy(impl->wl_buffer); + wl_surface_destroy(impl->wl_surface); + } -/* + static void _raw_surface_copy( color_t_ *s_data, @@ -170,10 +175,11 @@ _raw_surface_copy( } } } -*/ + bool surface_resize_wl_impl( + wl_target_t *wl_target, surface_impl_wl_t *impl, int32_t s_width, int32_t s_height, @@ -182,6 +188,7 @@ surface_resize_wl_impl( int32_t d_height, color_t_ **d_data) { + assert(wl_target != NULL); assert(impl != NULL); assert(s_width > 0); assert(s_height > 0); @@ -192,8 +199,30 @@ surface_resize_wl_impl( assert(d_data != NULL); assert(*d_data == NULL); - // TODO - return false; + + //Destroy old buffer + wl_buffer_destroy(impl->wl_buffer); + //Create a new shared memory slot with the correct size + uint32_t shm_pool_size = d_width * d_height * 4; + int fd = _allocate_shm_file(shm_pool_size); + uint8_t *pool_data = (uint8_t *)mmap(NULL, shm_pool_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + + struct wl_shm_pool *pool = wl_shm_create_pool(wl_target->wl_shm, + fd, shm_pool_size); + close(fd); + //Create buffer and get data handle + impl->wl_buffer = wl_shm_pool_create_buffer(pool,0,d_width,d_height,d_width*4,WL_SHM_FORMAT_ARGB8888); + *d_data = (color_t_ *)pool_data; + //Copy data + _raw_surface_copy(*s_data,s_width,s_height,*d_data,d_width,d_height); + //Delete old data + munmap(s_data,s_width * s_height * 4); + //Fill impl + impl->color_data = (uint8_t*)d_data; + impl->color_data_size = d_width * d_height * 4; + return true; } void From cdc804ead4b67dfefa85c4c17d66f1fa7317a371 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Tue, 14 Jun 2022 10:23:35 +0200 Subject: [PATCH 03/30] Wayland backend --- src/implem/backend.c | 2 +- src/implem/surface.c | 14 +- src/implem/wayland/wl_backend.c | 109 ++++++++----- src/implem/wayland/wl_backend.h | 2 +- src/implem/wayland/wl_backend_internal.h | 4 + src/implem/wayland/wl_surface.c | 19 +-- src/implem/wayland/wl_surface.h | 2 +- src/implem/wayland/wl_window.c | 191 ++--------------------- src/implem/wayland/wl_window_internal.h | 3 + 9 files changed, 115 insertions(+), 231 deletions(-) diff --git a/src/implem/backend.c b/src/implem/backend.c index a7c1094a..317227fd 100644 --- a/src/implem/backend.c +++ b/src/implem/backend.c @@ -133,7 +133,7 @@ backend_init( case_GDI(result = gdi_backend_init()); case_QUARTZ(result = qtz_backend_init()); case_X11(result = x11_backend_init()); - case_WAYLAND(/*result = wl_backend_init()*/); + case_WAYLAND(result = wl_backend_init()); default_ignore(); } diff --git a/src/implem/surface.c b/src/implem/surface.c index 52b2f2b7..131293fb 100644 --- a/src/implem/surface.c +++ b/src/implem/surface.c @@ -137,7 +137,12 @@ surface_destroy( } if (s->data) { - free(s->data); + switch_IMPL() { + case_WAYLAND(munmap(s->data,s->width * s->height * 4)); + default: + free(s->data); + break; + } } free(s); @@ -191,7 +196,12 @@ surface_resize( _surface_copy_to_buffer(s, data, width, height); - free(s->data); + switch_IMPL() { + case_WAYLAND(munmap(s->data,s->width * s->height * 4)); + default: + free(s->data); + break; + } } else { diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 82654360..47f3bfac 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -29,22 +29,22 @@ wl_backend_t *wl_back = NULL; -/* + static hash_t -_x11_wid_hash( - const xcb_window_t *wid) +_wl_wid_hash( + const struct wl_surface *surf) { - return (hash_t)(uintptr_t)*wid; + return (hash_t)(uintptr_t)surf; } static bool -_x11_wid_equal( - const xcb_window_t *wid1, - const xcb_window_t *wid2) +_wl_wid_equal( + const struct wl_surface *surf1, + const struct wl_surface *surf2) { - return (*wid1) == (*wid2); + return (surf1) == (surf2); } -*/ + static void @@ -130,6 +130,11 @@ _wl_xdg_toplevel_close_handler( void *data, struct xdg_toplevel *xdg_toplevel) { + struct wl_window_t *wl_window = data; + event_t evt; + evt.type = EVENT_CLOSE; + evt.target = wl_window; + event_notify(wl_back->listener,&evt); printf("top level close\n"); } @@ -158,6 +163,8 @@ _wl_pointer_enter_handler( wl_back->cursor_surface, wl_back->cursor_image->hotspot_x, wl_back->cursor_image->hotspot_y); + event_t evt; + } static void @@ -178,7 +185,7 @@ _wl_pointer_motion_handler( wl_fixed_t x, wl_fixed_t y) { - + } static void @@ -190,6 +197,7 @@ _wl_pointer_button_handler( uint32_t button, uint32_t state) { + printf("button: 0x%x state: %d\n", button, state); } @@ -231,15 +239,15 @@ wl_backend_init( } /* Map from WL windows IDs to window objects */ -/* - wl_back->wid_to_win = ht_new((key_hash_fun_t *)_wl_wid_hash, + + wl_back->surf_to_win = ht_new((key_hash_fun_t *)_wl_wid_hash, (key_equal_fun_t *)_wl_wid_equal, 32); - if (wl_back->wid_to_win == NULL) { + if (wl_back->surf_to_win == NULL) { wl_backend_terminate(); return false; } -*/ + /* Connect to Wayland server */ @@ -253,9 +261,6 @@ wl_backend_init( wl_back->registry = wl_display_get_registry(wl_back->display); wl_registry_add_listener(wl_back->registry, &_wl_registry_listener, wl_back); - /* Is this necessary ? */ - //wl_display_dispatch(wl_back->display); // Process incoming events - /* Force sync so registry listener are run (this calls dispatch until sync processed) */ wl_display_roundtrip(wl_back->display); /* Block until requests processed by server */ @@ -312,26 +317,63 @@ wl_backend_terminate( wl_display_roundtrip(wl_back->display); wl_display_disconnect(wl_back->display); -/* - if (wl_back->wid_to_win != NULL) { - ht_delete(wl_back->wid_to_win); + + if (wl_back->surf_to_win != NULL) { + ht_delete(wl_back->surf_to_win); } -*/ + free(wl_back); wl_back = NULL; } +//TODO : Clean this up if it's not needed +static const struct wl_callback_listener wl_callback_listener; +static void wl_callback_handle_frame(void* data, struct wl_callback* wl_callback, uint32_t time) +{ + struct wl_window_t *wl_window = data; + wl_callback_destroy(wl_callback); + wl_window->wl_callback = wl_surface_frame(wl_window->wl_surface); + wl_callback_add_listener(wl_window->wl_callback,&wl_callback_listener,wl_window); + //Trigger event + event_t evt; + evt.type = EVENT_FRAME; + //TODO : More precise clock + evt.time = time; + if (wl_window->base.visible) + { + //Attaches buffer and commits surface currently attached to this document + evt.target = data; + if (event_notify(wl_back->listener,&evt)) + { + evt.type = EVENT_PRESENT; + event_notify(wl_back->listener,&evt); + } + } + wl_surface_damage(wl_window->wl_surface,0,0,1280,720); + wl_surface_commit(wl_window->wl_surface); + + + +} + +static const struct wl_callback_listener wl_callback_listener = +{ + .done = wl_callback_handle_frame +}; + void wl_backend_add_window( wl_window_t *w) { assert(w != NULL); -/* - assert(w->wid != XCB_WINDOW_NONE); - ht_add(wl_back->wid_to_win, (void *)&(w->wid), (void *)w); -*/ + ht_add(wl_back->surf_to_win,(void*)&(w->wl_surface), (void*)w); + //create a callback for the window + w->wl_callback = wl_surface_frame(w->wl_surface); + wl_callback_add_listener(w->wl_callback,&wl_callback_listener,w); + wl_callback_handle_frame(w,w->wl_callback,0); + xdg_toplevel_add_listener(w->xdg_toplevel,&_wl_xdg_toplevel_listener,w); } void @@ -339,20 +381,16 @@ wl_backend_remove_window( const wl_window_t *w) { assert(w != NULL); -/* - assert(w->wid != XCB_WINDOW_NONE); - ht_remove(wl_back->wid_to_win, (void *)&(w->wid)); -*/ + ht_remove(wl_back->surf_to_win,(void*)&(w->wl_surface)); } wl_window_t * wl_backend_get_window( - int wid) + const struct wl_surface* wl_surface) { - assert(wid != 0); + assert(wl_surface != 0); -// return (wl_window_t *)ht_find(wl_back->wid_to_win, (void *)&wid); - return NULL; + return (wl_window_t *)ht_find(wl_back->surf_to_win, (void *)&wl_surface); } void @@ -376,14 +414,11 @@ void wl_backend_run( void) { -// wl_window_t *w = NULL; -// xcb_event_t e; -// event_t evt; wl_back->running = true; while (wl_display_dispatch(wl_back->display) >= 0) { - /* Handle events */ + //Events are handled separately. This loop is left empty on purpose. } } diff --git a/src/implem/wayland/wl_backend.h b/src/implem/wayland/wl_backend.h index 85613a72..77552c15 100644 --- a/src/implem/wayland/wl_backend.h +++ b/src/implem/wayland/wl_backend.h @@ -40,7 +40,7 @@ wl_backend_remove_window( wl_window_t * wl_backend_get_window( - int wid); + const struct wl_surface *surf); void wl_backend_set_listener( diff --git a/src/implem/wayland/wl_backend_internal.h b/src/implem/wayland/wl_backend_internal.h index 1ed74643..b1a031a6 100644 --- a/src/implem/wayland/wl_backend_internal.h +++ b/src/implem/wayland/wl_backend_internal.h @@ -22,6 +22,10 @@ typedef struct wl_backend_t { + + //Look up hashmap + hashtable_t *surf_to_win; + bool running; event_listener_t *listener; diff --git a/src/implem/wayland/wl_surface.c b/src/implem/wayland/wl_surface.c index 60c32f1b..f717abb6 100644 --- a/src/implem/wayland/wl_surface.c +++ b/src/implem/wayland/wl_surface.c @@ -20,8 +20,9 @@ #include #include #include -#include #include +#include + #include "../config.h" #include "../color.h" @@ -33,10 +34,6 @@ typedef struct surface_impl_wl_t { impl_type_t type; struct wl_buffer *wl_buffer; struct wl_surface *wl_surface; - - //data for destruction - uint8_t* color_data; - uint32_t color_data_size; } surface_impl_wl_t; static void @@ -131,9 +128,9 @@ surface_create_wl_impl( impl->wl_buffer = wl_buffer; impl->wl_surface = wl_target->wl_surface; *data = (color_t_ *)pool_data; - impl->color_data = (uint8_t*)pool_data; - impl->color_data_size = width * height * 4; - + wl_surface_attach(impl->wl_surface, impl->wl_buffer, 0, 0); + wl_surface_damage(impl->wl_surface,0,0,width,height); + wl_surface_commit(impl->wl_surface); return impl; } @@ -145,7 +142,6 @@ surface_destroy_wl_impl( assert(impl != NULL); assert(impl->type == IMPL_WAYLAND); - munmap(impl->color_data,impl->color_data_size); wl_buffer_destroy(impl->wl_buffer); wl_surface_destroy(impl->wl_surface); @@ -219,9 +215,6 @@ surface_resize_wl_impl( _raw_surface_copy(*s_data,s_width,s_height,*d_data,d_width,d_height); //Delete old data munmap(s_data,s_width * s_height * 4); - //Fill impl - impl->color_data = (uint8_t*)d_data; - impl->color_data_size = d_width * d_height * 4; return true; } @@ -236,8 +229,8 @@ surface_present_wl_impl( assert(present_data != NULL); assert(width > 0); assert(height > 0); - wl_surface_attach(impl->wl_surface, impl->wl_buffer, 0, 0); + wl_surface_damage(impl->wl_surface,0,0,width,height); wl_surface_commit(impl->wl_surface); } diff --git a/src/implem/wayland/wl_surface.h b/src/implem/wayland/wl_surface.h index 1e2392ff..b6996ed6 100644 --- a/src/implem/wayland/wl_surface.h +++ b/src/implem/wayland/wl_surface.h @@ -13,8 +13,8 @@ #include #include +#include -#include #include "../color.h" #include "wl_target.h" diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 307e2e12..d5594fd5 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -29,47 +29,13 @@ #include "wl_window_internal.h" -/* -// common to all windows -static void -_wl_window_set_wm_class( - wl_window_t *window, - const char *res_name, - const char *res_class) -{ - assert(window != NULL); - assert(window->wid != XCB_WINDOW_NONE); - assert(res_name != NULL); - assert(res_class != NULL); - - size_t class_len = strlen(res_name) + 1 + strlen(res_class) + 1; - char *class_hint = (car *)calloc(class_len, sizeof(char)); - if (class_hint == NULL) { - return; - } - - strcpy(class_hint, res_name); - strcpy(class_hint + strlen(res_name) + 1, res_class); - - // Window class - ISO-8859-1 - xcb_change_property(wl_back->c, XCB_PROP_MODE_REPLACE, window->wid, - XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, - class_len, class_hint); - - free(class_hint); -} -*/ static void _wl_window_update_position( wl_window_t *window) { assert(window != NULL); -/* - assert(window->wid != XCB_WINDOW_NONE); - xcb_configure_window(wl_back->c, window->wid, - XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, - (int32_t[]){ window->x, window->y }); -*/ + + //TODO } static void @@ -78,12 +44,11 @@ _wl_xdg_surface_configure( struct xdg_surface *xdg_surface, uint32_t serial) { - //wl_window_t *window = (wl_window_t *)data; + wl_window_t *window = (wl_window_t *)data; xdg_surface_ack_configure(xdg_surface, serial); - - //struct wl_buffer *buffer = draw_frame(window); //wl_surface_attach(window->wl_surface, buffer, 0, 0); - //wl_surface_commit(window->wl_surface); + if (window->wl_surface) + wl_surface_commit(window->wl_surface); } static const struct xdg_surface_listener @@ -91,6 +56,8 @@ _wl_xdg_surface_listener = { .configure = _wl_xdg_surface_configure, }; + + wl_window_t * wl_window_create( bool decorated, @@ -121,111 +88,9 @@ wl_window_create( xdg_toplevel_set_title(window->xdg_toplevel, title); } - wl_display_roundtrip(wl_back->display); - - xdg_surface_set_window_geometry(window->xdg_surface, - window->base.x, window->base.y, - window->base.width, window->base.height); - - wl_display_roundtrip(wl_back->display); -/* - // Create the WL window - window->wid = xcb_generate_id(wl_back->c); - xcb_create_window(wl_back->c, - XCB_COPY_FROM_PARENT, // depth - window->wid, // window id - wl_back->screen->root, // parent window - window->x, window->y, // position (ignored) - window->width, window->height, // size (ignored) - 0, // border width (ignored) - XCB_WINDOW_CLASS_INPUT_OUTPUT, - wl_back->screen->root_visual, // display format - XCB_CW_BACK_PIXEL | - XCB_CW_BORDER_PIXEL | - XCB_CW_EVENT_MASK, - (uint32_t[]){ - wl_back->screen->white_pixel, - wl_back->screen->black_pixel, - // XCB_EVENT_MASK_NO_EVENT | - XCB_EVENT_MASK_KEY_PRESS | - XCB_EVENT_MASK_KEY_RELEASE | - XCB_EVENT_MASK_BUTTON_PRESS | - XCB_EVENT_MASK_BUTTON_RELEASE | - XCB_EVENT_MASK_ENTER_WINDOW | - XCB_EVENT_MASK_LEAVE_WINDOW | - XCB_EVENT_MASK_POINTER_MOTION | - // XCB_EVENT_MASK_POINTER_MOTION_HINT | - // XCB_EVENT_MASK_BUTTON_1_MOTION | - // XCB_EVENT_MASK_BUTTON_2_MOTION | - // XCB_EVENT_MASK_BUTTON_3_MOTION | - // XCB_EVENT_MASK_BUTTON_4_MOTION | - // XCB_EVENT_MASK_BUTTON_5_MOTION | - // XCB_EVENT_MASK_BUTTON_MOTION | - XCB_EVENT_MASK_KEYMAP_STATE | - XCB_EVENT_MASK_EXPOSURE | - XCB_EVENT_MASK_VISIBILITY_CHANGE | - XCB_EVENT_MASK_STRUCTURE_NOTIFY | - // XCB_EVENT_MASK_RESIZE_REDIRECT | // Don't use - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | - // XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | - XCB_EVENT_MASK_FOCUS_CHANGE | - XCB_EVENT_MASK_PROPERTY_CHANGE | - XCB_EVENT_MASK_COLOR_MAP_CHANGE | - // XCB_EVENT_MASK_OWNER_GRAB_BUTTON | - 0 }); - - // Create graphic context - window->cid = xcb_generate_id(wl_back->c); - xcb_create_gc(wl_back->c, window->cid, window->wid, - XCB_GC_GRAPHICS_EXPOSURES, (uint32_t[]){ 1 }); - - // Set the title - const char *t = (title != NULL) ? title : ""; - _wl_window_set_wm_class(window, "OCaml-Canvas", "OCaml-Canvas"); - wl_window_set_title(window, t); - - // Set the various protocols to support - xcb_change_property(wl_back->c, XCB_PROP_MODE_PREPEND, window->wid, - wl_back->WM_PROTOCOLS, XCB_ATOM_ATOM, - 32, 4, (xcb_atom_t[]){ - wl_back->WM_DELETE_WINDOW, - wl_back->WM_TAKE_FOCUS, - wl_back->_NET_WM_PING, - wl_back->_NET_WM_SYNC_REQUEST - }); - - // Set the owner pid - pid_t pid = getpid(); - xcb_change_property(wl_back->c, XCB_PROP_MODE_REPLACE, window->wid, - wl_back->_NET_WM_PID, XCB_ATOM_CARDINAL, - 32, 1, &pid); - - // Motif hints to disable decorations - if (window->decorated == false) { - xcb_change_property(wl_back->c, XCB_PROP_MODE_REPLACE, window->wid, - wl_back->_MOTIF_WM_HINTS, wl_back->_MOTIF_WM_HINTS, - 32, 5, (uint32_t[]){ 0x02, 0x00, 0x00, 0x00, 0x00 }); -*//* - xcb_change_property(wl_back->c, XCB_PROP_MODE_REPLACE, window->wid, - wl_back->_NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, - 32, 1, (uint32_t[]){ wl_back->_NET_WM_WINDOW_TYPE_SPLASH }); -*//* - } - -*//* - xcb_change_property(wl_back->c, XCB_PROP_MODE_REPLACE, window->wid, - XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, - 32, 1, &(wl_back->screen->root)); -*//* - - // Add to managed winddows wl_backend_add_window(window); -*//* - // Flush any pending request - xcb_flush(wl_back->c); -*/ return window; } @@ -234,11 +99,9 @@ wl_window_destroy( wl_window_t *window) { assert(window != NULL); -/* - assert(window->wid != XCB_WINDOW_NONE); - wl_backend_remove_window(window); - xcb_destroy_window(wl_back->c, window->wid); -*/ + xdg_toplevel_destroy(window->xdg_toplevel); + xdg_surface_destroy(window->xdg_surface); + wl_surface_destroy(window->wl_surface); free(window); } @@ -257,28 +120,10 @@ wl_window_set_title( const char *title) { assert(window != NULL); -// assert(window->wid != XCB_WINDOW_NONE); assert(title != NULL); -/* - // Regular window name - ISO-8859-1 - xcb_change_property(wl_back->c, XCB_PROP_MODE_REPLACE, window->wid, - XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, - strlen(title), title); - - // Regular window name - UTF8 - xcb_change_property(wl_back->c, XCB_PROP_MODE_REPLACE, window->wid, - wl_back->_NET_WM_NAME, wl_back->UTF8_STRING, 8, - strlen(title), title); - - // Iconified window name - ISO-8859-1 - xcb_change_property(wl_back->c, XCB_PROP_MODE_REPLACE, window->wid, - XCB_ATOM_WM_ICON_NAME, XCB_ATOM_STRING, 8, - strlen(title), title); - - // Iconified window name - UTF8 - xcb_change_property(wl_back->c, XCB_PROP_MODE_REPLACE, window->wid, - wl_back->_NET_WM_ICON_NAME, wl_back->UTF8_STRING, 8, - strlen(title), title);*/ + assert(window->xdg_toplevel != NULL); + + xdg_toplevel_set_title(window->xdg_toplevel,title); } void @@ -288,14 +133,11 @@ wl_window_set_size( int32_t height) { assert(window != NULL); -// assert(window->wid != XCB_WINDOW_NONE); window->base.width = clip_i32_to_i16(width); - window->base.height = clip_i32_to_i16(height);/* - xcb_configure_window(wl_back->c, window->wid, - XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, - (uint32_t[]){ window->width, window->height });*/ + window->base.height = clip_i32_to_i16(height); } +//Not allowed to set on Wayland void wl_window_set_position( wl_window_t *window, @@ -303,7 +145,6 @@ wl_window_set_position( int32_t y) { assert(window != NULL); -// assert(window->wid != XCB_WINDOW_NONE); window->base.x = clip_i32_to_i16(x); window->base.y = clip_i32_to_i16(y); _wl_window_update_position(window); @@ -314,8 +155,6 @@ wl_window_show( wl_window_t *window) { assert(window != NULL); -// assert(window->wid != XCB_WINDOW_NONE); -// xcb_map_window(wl_back->c, window->wid); _wl_window_update_position(window); } diff --git a/src/implem/wayland/wl_window_internal.h b/src/implem/wayland/wl_window_internal.h index af7b4027..fd6c3a0f 100644 --- a/src/implem/wayland/wl_window_internal.h +++ b/src/implem/wayland/wl_window_internal.h @@ -15,6 +15,8 @@ #include "xdg-shell-client-protocol.h" #include "../window_internal.h" +#include "wl_surface.h" + typedef struct wl_window_t { @@ -25,6 +27,7 @@ typedef struct wl_window_t { struct wl_surface *wl_surface; struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; + struct wl_callback *wl_callback; // struct wl_buffer *wl_buffer; } wl_window_t; From 10135a00803ceef4f625613b556326a9f2796c91 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Wed, 15 Jun 2022 13:04:36 +0200 Subject: [PATCH 04/30] Made surface object store a pointer to the SHM object to avoid needing the target for a resize --- src/implem/wayland/wl_surface.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/implem/wayland/wl_surface.c b/src/implem/wayland/wl_surface.c index f717abb6..4013a28d 100644 --- a/src/implem/wayland/wl_surface.c +++ b/src/implem/wayland/wl_surface.c @@ -120,7 +120,7 @@ surface_create_wl_impl( struct wl_buffer *wl_buffer = wl_shm_pool_create_buffer(pool, 0, width, height, width * 4, WL_SHM_FORMAT_ARGB8888); // or ARGB for alpha - + wl_buffer_set_user_data(wl_buffer,wl_target->wl_shm); // or pool could be kept... wl_shm_pool_destroy(pool); // the buffer keeps a reference to the pool so it's ok to destroy @@ -142,8 +142,8 @@ surface_destroy_wl_impl( assert(impl != NULL); assert(impl->type == IMPL_WAYLAND); + //Surface is attached to the window. Its destruction is left for the window destroy function wl_buffer_destroy(impl->wl_buffer); - wl_surface_destroy(impl->wl_surface); } @@ -175,7 +175,6 @@ _raw_surface_copy( bool surface_resize_wl_impl( - wl_target_t *wl_target, surface_impl_wl_t *impl, int32_t s_width, int32_t s_height, @@ -184,7 +183,6 @@ surface_resize_wl_impl( int32_t d_height, color_t_ **d_data) { - assert(wl_target != NULL); assert(impl != NULL); assert(s_width > 0); assert(s_height > 0); @@ -195,9 +193,13 @@ surface_resize_wl_impl( assert(d_data != NULL); assert(*d_data == NULL); - + //Acquire Shm object (needed to recreate a new buffer) + struct wl_shm* wl_shm = wl_buffer_get_user_data(impl->wl_buffer); + //Destroy old buffer - wl_buffer_destroy(impl->wl_buffer); + if (impl->wl_buffer) + wl_buffer_destroy(impl->wl_buffer); + //Create a new shared memory slot with the correct size uint32_t shm_pool_size = d_width * d_height * 4; int fd = _allocate_shm_file(shm_pool_size); @@ -205,16 +207,17 @@ surface_resize_wl_impl( PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - struct wl_shm_pool *pool = wl_shm_create_pool(wl_target->wl_shm, + + + struct wl_shm_pool *pool = wl_shm_create_pool(wl_shm, fd, shm_pool_size); close(fd); //Create buffer and get data handle impl->wl_buffer = wl_shm_pool_create_buffer(pool,0,d_width,d_height,d_width*4,WL_SHM_FORMAT_ARGB8888); + wl_buffer_set_user_data(impl->wl_buffer,wl_shm); *d_data = (color_t_ *)pool_data; //Copy data _raw_surface_copy(*s_data,s_width,s_height,*d_data,d_width,d_height); - //Delete old data - munmap(s_data,s_width * s_height * 4); return true; } From 5282488055d1b823aeb35025d7b023028904d8c4 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Wed, 15 Jun 2022 13:06:16 +0200 Subject: [PATCH 05/30] Wayland mouse and keyboard support. --- src/discover/discover.ml | 4 +- src/implem/wayland/wl_backend.c | 241 +++++++++++++++++------ src/implem/wayland/wl_backend.h | 8 - src/implem/wayland/wl_backend_internal.h | 15 +- src/implem/wayland/wl_keyboard.h | 104 ++++++++++ src/implem/wayland/wl_window.c | 2 + 6 files changed, 304 insertions(+), 70 deletions(-) create mode 100644 src/implem/wayland/wl_keyboard.h diff --git a/src/discover/discover.ml b/src/discover/discover.ml index 4ca07fe6..b3c604cb 100644 --- a/src/discover/discover.ml +++ b/src/discover/discover.ml @@ -35,8 +35,8 @@ let x11_config c = let wl_config c = let cflags, libs = - query_or_default c "wayland-client wayland-cursor" - [] [ "-lwayland-client"; "-lwayland-cursor" ] + query_or_default c "wayland-client wayland-cursor xkbcommon" + [] [ "-lwayland-client"; "-lwayland-cursor"; "-lxkbcommon" ] in "-DHAS_WAYLAND" :: cflags, "-lrt" :: libs diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 47f3bfac..015ceec6 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -16,37 +16,37 @@ #include #include #include +#include + #include #include #include "xdg-shell-client-protocol.h" +#include +#include +#include +#include +#include + -#include "../hashtable.h" #include "../event.h" #include "wl_backend.h" #include "wl_backend_internal.h" #include "wl_window_internal.h" +#include "wl_keyboard.h" + wl_backend_t *wl_back = NULL; -static hash_t -_wl_wid_hash( - const struct wl_surface *surf) -{ - return (hash_t)(uintptr_t)surf; -} -static bool -_wl_wid_equal( - const struct wl_surface *surf1, - const struct wl_surface *surf2) +int64_t _wl_get_time() { - return (surf1) == (surf2); + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec/1000000 + ts.tv_nsec/(1000); } - - static void _wl_registry_global( void *data, @@ -135,6 +135,7 @@ _wl_xdg_toplevel_close_handler( evt.type = EVENT_CLOSE; evt.target = wl_window; event_notify(wl_back->listener,&evt); + printf("top level close\n"); } @@ -159,10 +160,16 @@ _wl_pointer_enter_handler( wl_fixed_t y) { wl_backend_t *wl_back = (wl_backend_t *)data; + wl_back->mouse_posx = x; + wl_back->mouse_posy = y; wl_pointer_set_cursor(pointer, serial, wl_back->cursor_surface, wl_back->cursor_image->hotspot_x, wl_back->cursor_image->hotspot_y); + if (surface) + wl_back->focus_window = wl_surface_get_user_data(surface); + else + wl_back->focus_window = NULL; event_t evt; } @@ -185,7 +192,16 @@ _wl_pointer_motion_handler( wl_fixed_t x, wl_fixed_t y) { - + wl_backend_t *wl_back = (wl_backend_t *)data; + wl_back->mouse_posx = x; + wl_back->mouse_posy = y; + event_t evt; + evt.type = EVENT_CURSOR; + evt.time = _wl_get_time(); + evt.target = wl_back->focus_window; + evt.desc.cursor.x = x/256; + evt.desc.cursor.y = y/256; + event_notify(wl_back->listener, &evt); } static void @@ -197,7 +213,16 @@ _wl_pointer_button_handler( uint32_t button, uint32_t state) { - + wl_backend_t *wl_back = (wl_backend_t *)data; + event_t evt; + evt.type = EVENT_BUTTON; + evt.time = _wl_get_time(); + evt.target = wl_back->focus_window; + evt.desc.button.button = (button == 0) ? BUTTON_LEFT : BUTTON_RIGHT; + evt.desc.button.state = (state == WL_POINTER_BUTTON_STATE_PRESSED) ? BUTTON_DOWN : BUTTON_UP; + evt.desc.button.x = wl_back->mouse_posx / 256; + evt.desc.button.y = wl_back->mouse_posy / 256; + event_notify(wl_back->listener, &evt); printf("button: 0x%x state: %d\n", button, state); } @@ -212,6 +237,111 @@ _wl_pointer_axis_handler( } + + +//Keyboard event handlers + +static void +_wl_keyboard_enter_handler( + void *data, + struct wl_keyboard *keyboard, + uint32_t serial, + struct wl_surface *surface, + struct wl_array *keys +) +{ + wl_backend_t *wl_back = (wl_backend_t *)data; + if (surface) + wl_back->focus_window = wl_surface_get_user_data(surface); + else //happens for some reason when the window gets destroyed + wl_back->focus_window = NULL; +} + +static void +_wl_keyboard_leave_handler( + void *data, + struct wl_keyboard *keyboard, + uint32_t serial, + struct wl_surface *surface) +{ + wl_back->focus_window = NULL; +} + +static void +_wl_keyboard_key_handler( + void *data, + struct wl_keyboard *keyboard, + uint32_t serial, + uint32_t time, + uint32_t key, + enum wl_keyboard_key_state state +) +{ + wl_backend_t *wl_back = (wl_backend_t *)data; + char buf[128]; + xkb_state_key_get_utf8(wl_back->xkb_state, key+8, buf, sizeof(buf)); + event_t evt; + evt.target = wl_back->focus_window; + evt.time = _wl_get_time(); + evt.type = EVENT_KEY; + evt.desc.key.code = sym_to_keycode[key]; + evt.desc.key.char_ = buf[0]; + evt.desc.key.state = (state == WL_KEYBOARD_KEY_STATE_RELEASED) ? KEY_UP : KEY_DOWN; + event_notify(wl_back->listener,&evt); +} + +static void +_wl_keyboard_keymap_handler( + void *data, + struct wl_keyboard *keyboard, + uint32_t format, + int32_t fd, + uint32_t size +) +{ + assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); + wl_backend_t *wl_back = (wl_backend_t *)data; + + char *map_shm = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + assert(map_shm != MAP_FAILED); + + wl_back->xkb_keymap = xkb_keymap_new_from_string(wl_back->xkb_context,map_shm,XKB_KEYMAP_FORMAT_TEXT_V1,XKB_KEYMAP_COMPILE_NO_FLAGS); + munmap(map_shm,size); + + close(fd); + + printf("Set up keymap \n"); + + wl_back->xkb_state = xkb_state_new(wl_back->xkb_keymap); + +} +static void +_wl_keyboard_modifiers_handler( + void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + uint32_t depressed, + uint32_t latched, + uint32_t locked, + uint32_t group +) +{ + wl_backend_t *wl_back = (wl_backend_t *)data; + xkb_state_update_mask(wl_back->xkb_state, + depressed, latched, locked, 0, 0, group); +} +static void +_wl_keyboard_repeat_info_handler( + void *data, + struct wl_keyboard *wl_keyboard, + int32_t rate, + int32_t delay +) +{ + +} + + const struct wl_pointer_listener _wl_pointer_listener = { @@ -222,6 +352,18 @@ _wl_pointer_listener = .axis = _wl_pointer_axis_handler, }; +const struct wl_keyboard_listener +_wl_keyboard_listener = +{ + .enter = _wl_keyboard_enter_handler, + .key = _wl_keyboard_key_handler, + .keymap = _wl_keyboard_keymap_handler, + .leave = _wl_keyboard_leave_handler, + .modifiers = _wl_keyboard_modifiers_handler, + .repeat_info = _wl_keyboard_repeat_info_handler +}; + + @@ -238,16 +380,6 @@ wl_backend_init( return false; } - /* Map from WL windows IDs to window objects */ - - wl_back->surf_to_win = ht_new((key_hash_fun_t *)_wl_wid_hash, - (key_equal_fun_t *)_wl_wid_equal, - 32); - if (wl_back->surf_to_win == NULL) { - wl_backend_terminate(); - return false; - } - /* Connect to Wayland server */ @@ -270,7 +402,15 @@ wl_backend_init( /* Retrieve the pointer and add listener */ wl_back->pointer = wl_seat_get_pointer(wl_back->seat); - wl_pointer_add_listener(wl_back->pointer, &_wl_pointer_listener, wl_back); + if (wl_back->pointer) + wl_pointer_add_listener(wl_back->pointer, &_wl_pointer_listener, wl_back); + /* Retrieve the keyboard, iinitiate xkb_context and add listener */ + wl_back->keyboard = wl_seat_get_keyboard(wl_back->seat); + if (wl_back->keyboard) + { + wl_back->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + wl_keyboard_add_listener(wl_back->keyboard,&_wl_keyboard_listener,wl_back); + } /* Force sync */ wl_display_roundtrip(wl_back->display); @@ -308,8 +448,17 @@ wl_backend_terminate( /* Destroy globals */ xdg_wm_base_destroy(wl_back->xdg_wm_base); wl_shm_destroy(wl_back->shm); - wl_pointer_release(wl_back->pointer); - wl_pointer_destroy(wl_back->pointer); + if (wl_back->pointer) { + wl_pointer_release(wl_back->pointer); + wl_pointer_destroy(wl_back->pointer); + } + if (wl_back->keyboard) { + wl_keyboard_release(wl_back->keyboard); + wl_keyboard_destroy(wl_back->keyboard); + xkb_state_ref(wl_back->xkb_state); + xkb_keymap_unref(wl_back->xkb_keymap); + xkb_context_unref(wl_back->xkb_context); + } wl_seat_release(wl_back->seat); wl_seat_destroy(wl_back->seat); wl_compositor_destroy(wl_back->compositor); @@ -318,11 +467,6 @@ wl_backend_terminate( wl_display_disconnect(wl_back->display); - if (wl_back->surf_to_win != NULL) { - ht_delete(wl_back->surf_to_win); - } - - free(wl_back); wl_back = NULL; @@ -333,14 +477,15 @@ static const struct wl_callback_listener wl_callback_listener; static void wl_callback_handle_frame(void* data, struct wl_callback* wl_callback, uint32_t time) { struct wl_window_t *wl_window = data; - wl_callback_destroy(wl_callback); - wl_window->wl_callback = wl_surface_frame(wl_window->wl_surface); - wl_callback_add_listener(wl_window->wl_callback,&wl_callback_listener,wl_window); + if (wl_callback) { + wl_callback_destroy(wl_callback); + wl_window->wl_callback = wl_surface_frame(wl_window->wl_surface); + wl_callback_add_listener(wl_window->wl_callback,&wl_callback_listener,wl_window); + } //Trigger event event_t evt; evt.type = EVENT_FRAME; - //TODO : More precise clock - evt.time = time; + evt.time = _wl_get_time(); if (wl_window->base.visible) { //Attaches buffer and commits surface currently attached to this document @@ -368,7 +513,6 @@ wl_backend_add_window( wl_window_t *w) { assert(w != NULL); - ht_add(wl_back->surf_to_win,(void*)&(w->wl_surface), (void*)w); //create a callback for the window w->wl_callback = wl_surface_frame(w->wl_surface); wl_callback_add_listener(w->wl_callback,&wl_callback_listener,w); @@ -376,23 +520,6 @@ wl_backend_add_window( xdg_toplevel_add_listener(w->xdg_toplevel,&_wl_xdg_toplevel_listener,w); } -void -wl_backend_remove_window( - const wl_window_t *w) -{ - assert(w != NULL); - ht_remove(wl_back->surf_to_win,(void*)&(w->wl_surface)); -} - -wl_window_t * -wl_backend_get_window( - const struct wl_surface* wl_surface) -{ - assert(wl_surface != 0); - - return (wl_window_t *)ht_find(wl_back->surf_to_win, (void *)&wl_surface); -} - void wl_backend_set_listener( event_listener_t *listener) diff --git a/src/implem/wayland/wl_backend.h b/src/implem/wayland/wl_backend.h index 77552c15..a3c5e69c 100644 --- a/src/implem/wayland/wl_backend.h +++ b/src/implem/wayland/wl_backend.h @@ -34,14 +34,6 @@ void wl_backend_add_window( wl_window_t *w); -void -wl_backend_remove_window( - const wl_window_t *w); - -wl_window_t * -wl_backend_get_window( - const struct wl_surface *surf); - void wl_backend_set_listener( event_listener_t *listener); diff --git a/src/implem/wayland/wl_backend_internal.h b/src/implem/wayland/wl_backend_internal.h index b1a031a6..8268a06c 100644 --- a/src/implem/wayland/wl_backend_internal.h +++ b/src/implem/wayland/wl_backend_internal.h @@ -16,6 +16,7 @@ #include #include #include "xdg-shell-client-protocol.h" +#include #include "../hashtable.h" #include "../event.h" @@ -23,9 +24,6 @@ typedef struct wl_backend_t { - //Look up hashmap - hashtable_t *surf_to_win; - bool running; event_listener_t *listener; @@ -35,6 +33,7 @@ typedef struct wl_backend_t { struct wl_compositor *compositor; struct wl_seat *seat; struct wl_pointer *pointer; + struct wl_keyboard *keyboard; struct wl_shm *shm; struct xdg_wm_base *xdg_wm_base; @@ -44,6 +43,16 @@ typedef struct wl_backend_t { struct wl_cursor_image *cursor_image; struct wl_buffer *cursor_buffer; struct wl_surface *cursor_surface; + wl_window_t *focus_window; + + /*Keyboard objects*/ + struct xkb_keymap *xkb_keymap; + struct xkb_state *xkb_state; + struct xkb_context *xkb_context; + + /*Mouse objects*/ + wl_fixed_t mouse_posx; + wl_fixed_t mouse_posy; } wl_backend_t; diff --git a/src/implem/wayland/wl_keyboard.h b/src/implem/wayland/wl_keyboard.h new file mode 100644 index 00000000..be6862d3 --- /dev/null +++ b/src/implem/wayland/wl_keyboard.h @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifndef __WL_KEYBOARD_H +#define __WL_KEYBOARD_H +#include "../event.h" + +//TODO : Complete the list/ Test on other keyboards +static const key_code_t sym_to_keycode[256] = +{ +[1] = KEY_ESCAPE, +[59] = KEY_F1, +[60] = KEY_F2, +[61] = KEY_F3, +[62] = KEY_F4, +[63] = KEY_F5, +[64] = KEY_F6, +[65] = KEY_F7, +[66] = KEY_F8, +[67] = KEY_F9, +[68] = KEY_F10, +[87] = KEY_F11, +[88] = KEY_F12, +[99] = KEY_PRINTSCREEN, +[119] = KEY_PAUSE, +[41] = KEY_GRAVE_TILDE, +[2] = KEY_1_EXCLAMATION, +[3] = KEY_2_AT, +[4] = KEY_3_NUMBER, +[5] = KEY_4_DOLLAR, +[6] = KEY_5_PERCENT, +[7] = KEY_6_CARET, +[8] = KEY_7_AMPERSAND, +[9] = KEY_8_ASTERISK, +[10] = KEY_9_LPARENTHESIS, +[11] = KEY_0_RPARENTHESIS, +[12] = KEY_MINUS_UNDERSCORE, +[13] = KEY_EQUAL_PLUS, +[14] = KEY_BACKSPACE, +[15] = KEY_TAB, +[16] = KEY_Q, +[17] = KEY_W, +[18] = KEY_E, +[19] = KEY_R, +[20] = KEY_T, +[21] = KEY_Y, +[22] = KEY_U, +[23] = KEY_I, +[24] = KEY_O, +[25] = KEY_P, +[26] = KEY_LBRACKET_CURLY, +[27] = KEY_RBRACKET_CURLY, +[43] = KEY_BACKSLASH_PIPE, +[58] = KEY_CAPSLOCK, +[30] = KEY_A, +[31] = KEY_S, +[32] = KEY_D, +[33] = KEY_F, +[34] = KEY_G, +[35] = KEY_H, +[36] = KEY_J, +[37] = KEY_K, +[38] = KEY_L, +[39] = KEY_SEMICOLON_COLON, +[40] = KEY_QUOTE_DOUBLEQUOTE, +[28] = KEY_RETURN, +[42] = KEY_LSHIFT, +[44] = KEY_Z, +[45] = KEY_X, +[46] = KEY_C, +[47] = KEY_V, +[48] = KEY_B, +[49] = KEY_N, +[50] = KEY_M, +[51] = KEY_COMMA_LESS, +[52] = KEY_PERIOD_GREATER, +[53] = KEY_SLASH_QUESTION, +[54] = KEY_RSHIFT, +[29] = KEY_LCONTROL, +[56] = KEY_LALT, +[57] = KEY_SPACEBAR, +[100] = KEY_RALT, +[127] = KEY_MENU, +[97] = KEY_RCONTROL, +[110] = KEY_INSERT, +[102] = KEY_HOME, +[104] = KEY_PAGEUP, +[111] = KEY_DELETEFORWARD, +[107] = KEY_END, +[109] = KEY_PAGEDOWN, +[103] = KEY_UPARROW, +[105] = KEY_LEFTARROW, +[108] = KEY_DOWNARROW, +[106] = KEY_RIGHTARROW +}; + +#endif /* __WL_KEYBOARD_H */ \ No newline at end of file diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index d5594fd5..82b6d21a 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -80,6 +80,7 @@ wl_window_create( window->base.height = clip_i32_to_i16(max(1, height)); window->wl_surface = wl_compositor_create_surface(wl_back->compositor); + wl_surface_set_user_data(window->wl_surface,window); window->xdg_surface = xdg_wm_base_get_xdg_surface(wl_back->xdg_wm_base, window->wl_surface); xdg_surface_add_listener(window->xdg_surface, &_wl_xdg_surface_listener, &window); @@ -99,6 +100,7 @@ wl_window_destroy( wl_window_t *window) { assert(window != NULL); + wl_callback_destroy(window->wl_callback); xdg_toplevel_destroy(window->xdg_toplevel); xdg_surface_destroy(window->xdg_surface); wl_surface_destroy(window->wl_surface); From f45952f3ea01eacbe194a49af1289f9c09f4cf16 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Wed, 15 Jun 2022 17:27:32 +0200 Subject: [PATCH 06/30] Implemented window hiding. Fixed some formatting issues. --- src/implem/wayland/wl_backend.c | 132 +++++++++--------------- src/implem/wayland/wl_surface.c | 5 - src/implem/wayland/wl_window.c | 66 +++++++++--- src/implem/wayland/wl_window_internal.h | 2 - 4 files changed, 99 insertions(+), 106 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 015ceec6..8d5c3716 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -112,44 +112,6 @@ _wl_xdg_wm_base_listener = - - -static void -_wl_xdg_toplevel_configure_handler( - void *data, - struct xdg_toplevel *xdg_toplevel, - int32_t width, - int32_t height, - struct wl_array *states) -{ - printf("top level configure: %dx%d\n", width, height); -} - -static void -_wl_xdg_toplevel_close_handler( - void *data, - struct xdg_toplevel *xdg_toplevel) -{ - struct wl_window_t *wl_window = data; - event_t evt; - evt.type = EVENT_CLOSE; - evt.target = wl_window; - event_notify(wl_back->listener,&evt); - - printf("top level close\n"); -} - -const struct xdg_toplevel_listener -_wl_xdg_toplevel_listener = -{ - .configure = _wl_xdg_toplevel_configure_handler, - .close = _wl_xdg_toplevel_close_handler, -}; - - - - - static void _wl_pointer_enter_handler( void *data, @@ -192,16 +154,18 @@ _wl_pointer_motion_handler( wl_fixed_t x, wl_fixed_t y) { - wl_backend_t *wl_back = (wl_backend_t *)data; - wl_back->mouse_posx = x; - wl_back->mouse_posy = y; - event_t evt; - evt.type = EVENT_CURSOR; - evt.time = _wl_get_time(); - evt.target = wl_back->focus_window; - evt.desc.cursor.x = x/256; - evt.desc.cursor.y = y/256; - event_notify(wl_back->listener, &evt); + if (wl_back->focus_window && wl_back->focus_window->base.visible) { + wl_backend_t *wl_back = (wl_backend_t *)data; + wl_back->mouse_posx = x; + wl_back->mouse_posy = y; + event_t evt; + evt.type = EVENT_CURSOR; + evt.time = _wl_get_time(); + evt.target = wl_back->focus_window; + evt.desc.cursor.x = x/256; + evt.desc.cursor.y = y/256; + event_notify(wl_back->listener, &evt); + } } static void @@ -213,17 +177,21 @@ _wl_pointer_button_handler( uint32_t button, uint32_t state) { - wl_backend_t *wl_back = (wl_backend_t *)data; - event_t evt; - evt.type = EVENT_BUTTON; - evt.time = _wl_get_time(); - evt.target = wl_back->focus_window; - evt.desc.button.button = (button == 0) ? BUTTON_LEFT : BUTTON_RIGHT; - evt.desc.button.state = (state == WL_POINTER_BUTTON_STATE_PRESSED) ? BUTTON_DOWN : BUTTON_UP; - evt.desc.button.x = wl_back->mouse_posx / 256; - evt.desc.button.y = wl_back->mouse_posy / 256; - event_notify(wl_back->listener, &evt); - printf("button: 0x%x state: %d\n", button, state); + //When the focus screen is hidden with a key down event for example, the key up event will still trigger. This check mitigates that. + if (wl_back->focus_window && wl_back->focus_window->base.visible) { + wl_backend_t *wl_back = (wl_backend_t *)data; + event_t evt; + evt.type = EVENT_BUTTON; + evt.time = _wl_get_time(); + evt.target = wl_back->focus_window; + //TODO : Support other buttons + evt.desc.button.button = (button == 0) ? BUTTON_LEFT : BUTTON_RIGHT; + evt.desc.button.state = (state == WL_POINTER_BUTTON_STATE_PRESSED) ? BUTTON_DOWN : BUTTON_UP; + evt.desc.button.x = wl_back->mouse_posx / 256; + evt.desc.button.y = wl_back->mouse_posy / 256; + event_notify(wl_back->listener, &evt); + printf("button: 0x%x state: %d\n", button, state); + } } static void @@ -277,17 +245,18 @@ _wl_keyboard_key_handler( enum wl_keyboard_key_state state ) { - wl_backend_t *wl_back = (wl_backend_t *)data; - char buf[128]; - xkb_state_key_get_utf8(wl_back->xkb_state, key+8, buf, sizeof(buf)); - event_t evt; - evt.target = wl_back->focus_window; - evt.time = _wl_get_time(); - evt.type = EVENT_KEY; - evt.desc.key.code = sym_to_keycode[key]; - evt.desc.key.char_ = buf[0]; - evt.desc.key.state = (state == WL_KEYBOARD_KEY_STATE_RELEASED) ? KEY_UP : KEY_DOWN; - event_notify(wl_back->listener,&evt); + if (wl_back->focus_window && wl_back->focus_window->base.visible) { + wl_backend_t *wl_back = (wl_backend_t *)data; + uint32_t pressedKeyCharacter = xkb_state_key_get_utf32(wl_back->xkb_state, key+8); + event_t evt; + evt.target = wl_back->focus_window; + evt.time = _wl_get_time(); + evt.type = EVENT_KEY; + evt.desc.key.code = sym_to_keycode[key]; + evt.desc.key.char_ = pressedKeyCharacter; + evt.desc.key.state = (state == WL_KEYBOARD_KEY_STATE_RELEASED) ? KEY_UP : KEY_DOWN; + event_notify(wl_back->listener,&evt); + } } static void @@ -338,7 +307,7 @@ _wl_keyboard_repeat_info_handler( int32_t delay ) { - + } @@ -406,8 +375,7 @@ wl_backend_init( wl_pointer_add_listener(wl_back->pointer, &_wl_pointer_listener, wl_back); /* Retrieve the keyboard, iinitiate xkb_context and add listener */ wl_back->keyboard = wl_seat_get_keyboard(wl_back->seat); - if (wl_back->keyboard) - { + if (wl_back->keyboard) { wl_back->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); wl_keyboard_add_listener(wl_back->keyboard,&_wl_keyboard_listener,wl_back); } @@ -472,9 +440,11 @@ wl_backend_terminate( wl_back = NULL; } -//TODO : Clean this up if it's not needed static const struct wl_callback_listener wl_callback_listener; -static void wl_callback_handle_frame(void* data, struct wl_callback* wl_callback, uint32_t time) +static void wl_callback_handle_frame( + void* data, + struct wl_callback* wl_callback, + uint32_t time) { struct wl_window_t *wl_window = data; if (wl_callback) { @@ -486,21 +456,14 @@ static void wl_callback_handle_frame(void* data, struct wl_callback* wl_callback event_t evt; evt.type = EVENT_FRAME; evt.time = _wl_get_time(); - if (wl_window->base.visible) - { - //Attaches buffer and commits surface currently attached to this document - evt.target = data; + if (wl_window->base.visible) { + evt.target = (wl_window_t*)data; if (event_notify(wl_back->listener,&evt)) { evt.type = EVENT_PRESENT; event_notify(wl_back->listener,&evt); } } - wl_surface_damage(wl_window->wl_surface,0,0,1280,720); - wl_surface_commit(wl_window->wl_surface); - - - } static const struct wl_callback_listener wl_callback_listener = @@ -517,7 +480,6 @@ wl_backend_add_window( w->wl_callback = wl_surface_frame(w->wl_surface); wl_callback_add_listener(w->wl_callback,&wl_callback_listener,w); wl_callback_handle_frame(w,w->wl_callback,0); - xdg_toplevel_add_listener(w->xdg_toplevel,&_wl_xdg_toplevel_listener,w); } void diff --git a/src/implem/wayland/wl_surface.c b/src/implem/wayland/wl_surface.c index 4013a28d..ef613bf3 100644 --- a/src/implem/wayland/wl_surface.c +++ b/src/implem/wayland/wl_surface.c @@ -128,9 +128,6 @@ surface_create_wl_impl( impl->wl_buffer = wl_buffer; impl->wl_surface = wl_target->wl_surface; *data = (color_t_ *)pool_data; - wl_surface_attach(impl->wl_surface, impl->wl_buffer, 0, 0); - wl_surface_damage(impl->wl_surface,0,0,width,height); - wl_surface_commit(impl->wl_surface); return impl; } @@ -207,8 +204,6 @@ surface_resize_wl_impl( PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - - struct wl_shm_pool *pool = wl_shm_create_pool(wl_shm, fd, shm_pool_size); close(fd); diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 82b6d21a..117cc630 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -34,7 +34,6 @@ _wl_window_update_position( wl_window_t *window) { assert(window != NULL); - //TODO } @@ -46,9 +45,6 @@ _wl_xdg_surface_configure( { wl_window_t *window = (wl_window_t *)data; xdg_surface_ack_configure(xdg_surface, serial); - //wl_surface_attach(window->wl_surface, buffer, 0, 0); - if (window->wl_surface) - wl_surface_commit(window->wl_surface); } static const struct xdg_surface_listener @@ -56,6 +52,37 @@ _wl_xdg_surface_listener = { .configure = _wl_xdg_surface_configure, }; +static void +_wl_xdg_toplevel_configure_handler( + void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height, + struct wl_array *states) +{ + printf("top level configure: %dx%d\n", width, height); +} + +static void +_wl_xdg_toplevel_close_handler( + void *data, + struct xdg_toplevel *xdg_toplevel) +{ + struct wl_window_t *wl_window = data; + event_t evt; + evt.type = EVENT_CLOSE; + evt.target = wl_window; + event_notify(wl_back->listener,&evt); +} + +const struct xdg_toplevel_listener +_wl_xdg_toplevel_listener = +{ + .configure = _wl_xdg_toplevel_configure_handler, + .close = _wl_xdg_toplevel_close_handler, +}; + + wl_window_t * @@ -81,14 +108,6 @@ wl_window_create( window->wl_surface = wl_compositor_create_surface(wl_back->compositor); wl_surface_set_user_data(window->wl_surface,window); - window->xdg_surface = - xdg_wm_base_get_xdg_surface(wl_back->xdg_wm_base, window->wl_surface); - xdg_surface_add_listener(window->xdg_surface, &_wl_xdg_surface_listener, &window); - window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface); - if (title != NULL) { - xdg_toplevel_set_title(window->xdg_toplevel, title); - } - wl_backend_add_window(window); @@ -157,7 +176,17 @@ wl_window_show( wl_window_t *window) { assert(window != NULL); + if (window->base.visible) { + window->xdg_surface = + xdg_wm_base_get_xdg_surface(wl_back->xdg_wm_base, window->wl_surface); + xdg_surface_add_listener(window->xdg_surface, &_wl_xdg_surface_listener, &window); + window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface); + xdg_toplevel_add_listener(window->xdg_toplevel,&_wl_xdg_toplevel_listener,window); + window->base.visible = true; + wl_surface_commit(window->wl_surface); + } _wl_window_update_position(window); + } void @@ -165,8 +194,17 @@ wl_window_hide( wl_window_t *window) { assert(window != NULL); -// assert(window->wid != XCB_WINDOW_NONE); -// xcb_unmap_window(wl_back->c, window->wid); + //unmap xdg_toplevel and surface + if (window->xdg_surface) + xdg_surface_destroy(window->xdg_surface); + if (window->xdg_toplevel) + xdg_toplevel_destroy(window->xdg_toplevel); + window->xdg_surface = NULL; + window->xdg_toplevel = NULL; + window->base.visible = false; + //Cannot recreate the XDG Surface from a surface with an attached buffer. + wl_surface_attach(window->wl_surface,NULL,0,0); + wl_surface_commit(window->wl_surface); } #else diff --git a/src/implem/wayland/wl_window_internal.h b/src/implem/wayland/wl_window_internal.h index fd6c3a0f..0ee13775 100644 --- a/src/implem/wayland/wl_window_internal.h +++ b/src/implem/wayland/wl_window_internal.h @@ -15,7 +15,6 @@ #include "xdg-shell-client-protocol.h" #include "../window_internal.h" -#include "wl_surface.h" typedef struct wl_window_t { @@ -28,7 +27,6 @@ typedef struct wl_window_t { struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; struct wl_callback *wl_callback; -// struct wl_buffer *wl_buffer; } wl_window_t; From 03eb44e9da968f85545bc2bd9a86dfd9383607e4 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Thu, 16 Jun 2022 13:01:34 +0200 Subject: [PATCH 07/30] Simple client side decoration setup --- src/dune | 2 +- src/implem/wayland/wl_backend.c | 38 ++++-- src/implem/wayland/wl_backend_internal.h | 3 +- src/implem/wayland/wl_decoration.c | 158 +++++++++++++++++++++++ src/implem/wayland/wl_decoration.h | 46 +++++++ src/implem/wayland/wl_window.c | 9 +- src/implem/wayland/wl_window_internal.h | 9 +- 7 files changed, 251 insertions(+), 14 deletions(-) create mode 100644 src/implem/wayland/wl_decoration.c create mode 100644 src/implem/wayland/wl_decoration.h diff --git a/src/dune b/src/dune index af88e7b7..fa4c9d75 100644 --- a/src/dune +++ b/src/dune @@ -15,7 +15,7 @@ gdi_keyboard gdi_backend gdi_target gdi_window gdi_surface qtz_keyboard qtz_backend qtz_target qtz_window qtz_surface x11_keysym x11_keyboard x11_backend x11_target x11_window x11_surface - wl_backend wl_target wl_window wl_surface xdg-shell-protocol + wl_backend wl_target wl_window wl_surface wl_decoration xdg-shell-protocol window surface path arc polygon polygonize poly_render font_desc gdi_font qtz_font ft_font font diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 8d5c3716..076d0f60 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -17,16 +17,16 @@ #include #include #include - +#include +#include +#include +#include #include #include #include "xdg-shell-client-protocol.h" #include -#include -#include -#include -#include + #include "../event.h" @@ -72,6 +72,9 @@ printf("Global: %s\n", interface); } else if (strcmp(interface, wl_shm_interface.name) == 0) { wl_back->shm = (struct wl_shm *) wl_registry_bind(registry, id, &wl_shm_interface, 1); + } else if (strcmp(interface, wl_subcompositor_interface.name) == 0) { + wl_back->subcompositor = (struct wl_subcompositor*) + wl_registry_bind(registry, id, &wl_subcompositor_interface,version); } } @@ -129,9 +132,16 @@ _wl_pointer_enter_handler( wl_back->cursor_image->hotspot_x, wl_back->cursor_image->hotspot_y); if (surface) - wl_back->focus_window = wl_surface_get_user_data(surface); + { + wl_back->focus_window = (wl_window_t*)wl_surface_get_user_data(surface); + if (surface == wl_back->focus_window->decoration->wl_surface) + wl_back->inside_decor = 1; + } else + { wl_back->focus_window = NULL; + wl_back->inside_decor = 1; + } event_t evt; } @@ -143,7 +153,8 @@ _wl_pointer_leave_handler( uint32_t serial, struct wl_surface *surface) { - + wl_backend_t *wl_back = (wl_backend_t *)data; + wl_back->inside_decor = 0; } static void @@ -178,20 +189,27 @@ _wl_pointer_button_handler( uint32_t state) { //When the focus screen is hidden with a key down event for example, the key up event will still trigger. This check mitigates that. - if (wl_back->focus_window && wl_back->focus_window->base.visible) { + if (wl_back->focus_window && wl_back->focus_window->base.visible && !wl_back->inside_decor) { wl_backend_t *wl_back = (wl_backend_t *)data; event_t evt; evt.type = EVENT_BUTTON; evt.time = _wl_get_time(); evt.target = wl_back->focus_window; //TODO : Support other buttons - evt.desc.button.button = (button == 0) ? BUTTON_LEFT : BUTTON_RIGHT; + //TODO : Find a way to get RMB's code (is it always 272?) + evt.desc.button.button = (button == 272) ? BUTTON_LEFT : BUTTON_RIGHT; evt.desc.button.state = (state == WL_POINTER_BUTTON_STATE_PRESSED) ? BUTTON_DOWN : BUTTON_UP; evt.desc.button.x = wl_back->mouse_posx / 256; evt.desc.button.y = wl_back->mouse_posy / 256; event_notify(wl_back->listener, &evt); printf("button: 0x%x state: %d\n", button, state); } + + if (wl_back->inside_decor && state == WL_POINTER_BUTTON_STATE_PRESSED && button == 272) + { + printf("henlo"); + xdg_toplevel_move(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial); + } } static void @@ -373,6 +391,7 @@ wl_backend_init( wl_back->pointer = wl_seat_get_pointer(wl_back->seat); if (wl_back->pointer) wl_pointer_add_listener(wl_back->pointer, &_wl_pointer_listener, wl_back); + wl_back->inside_decor = 0; /* Retrieve the keyboard, iinitiate xkb_context and add listener */ wl_back->keyboard = wl_seat_get_keyboard(wl_back->seat); if (wl_back->keyboard) { @@ -460,6 +479,7 @@ static void wl_callback_handle_frame( evt.target = (wl_window_t*)data; if (event_notify(wl_back->listener,&evt)) { + wl_decoration_present(wl_window->decoration); evt.type = EVENT_PRESENT; event_notify(wl_back->listener,&evt); } diff --git a/src/implem/wayland/wl_backend_internal.h b/src/implem/wayland/wl_backend_internal.h index 8268a06c..5b1a5bef 100644 --- a/src/implem/wayland/wl_backend_internal.h +++ b/src/implem/wayland/wl_backend_internal.h @@ -31,6 +31,7 @@ typedef struct wl_backend_t { struct wl_display *display; struct wl_registry *registry; struct wl_compositor *compositor; + struct wl_subcompositor *subcompositor; struct wl_seat *seat; struct wl_pointer *pointer; struct wl_keyboard *keyboard; @@ -53,7 +54,7 @@ typedef struct wl_backend_t { /*Mouse objects*/ wl_fixed_t mouse_posx; wl_fixed_t mouse_posy; - + uint8_t inside_decor; } wl_backend_t; extern wl_backend_t *wl_back; diff --git a/src/implem/wayland/wl_decoration.c b/src/implem/wayland/wl_decoration.c new file mode 100644 index 00000000..93864951 --- /dev/null +++ b/src/implem/wayland/wl_decoration.c @@ -0,0 +1,158 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifdef HAS_WAYLAND + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "wl_decoration.h" +#include "wl_backend.h" +#include "wl_backend_internal.h" + + + +//TODO : Factor this between surface and decoration +static void +_randname( + char *buf) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + long r = ts.tv_nsec; + for (int i = 0; i < 6; ++i) { + buf[i] = 'A'+(r&15)+(r&16)*2; + r >>= 5; + } +} +//TODO : Factor this between surface and decoration +static int +_create_shm_file() +{ + int retries = 100; + do { + char name[] = "/canvas_shm-XXXXXX"; + _randname(name + sizeof(name) - 7); + --retries; + int fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600); + if (fd >= 0) { + shm_unlink(name); + return fd; + } + } while (retries > 0 && errno == EEXIST); + return -1; +} +//TODO : Factor this between surface and decoration +static int +_allocate_shm_file( + size_t size) +{ + int fd = _create_shm_file(); + if (fd < 0) + return -1; + int ret; + do { + ret = ftruncate(fd, size); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + close(fd); + return -1; + } + return fd; +} + + + +wl_decoration_t* +wl_decoration_create( + struct wl_surface *parent, + uint32_t width +) +{ + + //TODO : Make this adapt to screen + uint32_t _decor_height = 40; + + assert(parent != NULL); + wl_decoration_t *decor = (wl_decoration_t*)calloc(1, sizeof(wl_decoration_t)); + if (decor == NULL) + return NULL; + decor->wl_surface = wl_compositor_create_surface(wl_back->compositor); + decor->wl_subsurface = wl_subcompositor_get_subsurface(wl_back->subcompositor,decor->wl_surface,parent); + + //TODO : Factor this between surface and decoration + uint32_t shm_pool_size = width * _decor_height * 4; + int fd = _allocate_shm_file(shm_pool_size); + uint8_t *pool_data = (uint8_t *)mmap(NULL, shm_pool_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + + struct wl_shm_pool *pool = wl_shm_create_pool(wl_back->shm, + fd, shm_pool_size); + close(fd); + + struct wl_buffer *wl_buffer = + wl_shm_pool_create_buffer(pool, 0, width, _decor_height, width * 4, + WL_SHM_FORMAT_ARGB8888); // or ARGB for alpha + wl_shm_pool_destroy(pool); + + //TODO : Improve the design + for (int i = 0;i < width*_decor_height;i++) + { + pool_data[4*i] = 0; + pool_data[4*i + 1] = 0; + pool_data[4*i + 2] = 0; + pool_data[4*i + 3] = 255; + } + + munmap(pool_data,shm_pool_size); + + wl_surface_attach(decor->wl_surface,wl_buffer,0,0); + wl_subsurface_set_position(decor->wl_subsurface,0,-_decor_height); + decor->background_buffer = wl_buffer; + + return decor; +} + +void +wl_decoration_destroy( + wl_decoration_t *decoration +) +{ + assert(decoration != NULL); + assert(decoration->background_buffer != NULL); + assert(decoration->wl_subsurface != NULL); + assert(decoration->wl_surface != NULL); + + wl_buffer_destroy(decoration->background_buffer); + wl_subsurface_destroy(decoration->wl_subsurface); + wl_surface_destroy(decoration->wl_surface); +} + +void +wl_decoration_present( + wl_decoration_t* decoration +) +{ + wl_surface_commit(decoration->wl_surface); +} + + +#endif /*HAS_WAYLAND*/ \ No newline at end of file diff --git a/src/implem/wayland/wl_decoration.h b/src/implem/wayland/wl_decoration.h new file mode 100644 index 00000000..54dbc7b5 --- /dev/null +++ b/src/implem/wayland/wl_decoration.h @@ -0,0 +1,46 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifndef __WL_DECORATION_H +#define __WL_DECORATION_H + +#include +#include +#include + +#include + +#include "../color.h" + +typedef struct wl_decoration_t { + struct wl_surface *wl_surface; + struct wl_subsurface *wl_subsurface; + struct wl_buffer *background_buffer; +} wl_decoration_t; + +wl_decoration_t* +wl_decoration_create( + struct wl_surface *parent, + uint32_t width +); + +void +wl_decoration_destroy( + wl_decoration_t *decoration +); + +void +wl_decoration_present( + wl_decoration_t* decoration +); + + + +#endif /* __WL_DECORATION_H */ \ No newline at end of file diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 117cc630..27a94ef6 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -106,9 +106,14 @@ wl_window_create( window->base.width = clip_i32_to_i16(max(1, width)); window->base.height = clip_i32_to_i16(max(1, height)); + window->title = title; + window->wl_surface = wl_compositor_create_surface(wl_back->compositor); wl_surface_set_user_data(window->wl_surface,window); + window->decoration = wl_decoration_create(window->wl_surface,width); + wl_surface_set_user_data(window->decoration->wl_surface,window); + wl_backend_add_window(window); return window; @@ -122,6 +127,7 @@ wl_window_destroy( wl_callback_destroy(window->wl_callback); xdg_toplevel_destroy(window->xdg_toplevel); xdg_surface_destroy(window->xdg_surface); + wl_decoration_destroy(window->decoration); wl_surface_destroy(window->wl_surface); free(window); } @@ -182,8 +188,9 @@ wl_window_show( xdg_surface_add_listener(window->xdg_surface, &_wl_xdg_surface_listener, &window); window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface); xdg_toplevel_add_listener(window->xdg_toplevel,&_wl_xdg_toplevel_listener,window); + xdg_toplevel_set_title(window->xdg_toplevel,window->title); window->base.visible = true; - wl_surface_commit(window->wl_surface); + wl_surface_commit(window->wl_surface); } _wl_window_update_position(window); diff --git a/src/implem/wayland/wl_window_internal.h b/src/implem/wayland/wl_window_internal.h index 0ee13775..43528e77 100644 --- a/src/implem/wayland/wl_window_internal.h +++ b/src/implem/wayland/wl_window_internal.h @@ -15,18 +15,23 @@ #include "xdg-shell-client-protocol.h" #include "../window_internal.h" - +#include "wl_decoration.h" typedef struct wl_window_t { /* Common to all windows */ window_t base; - /* Specific to Quartz windows */ + /* Specific to Wayland windows */ struct wl_surface *wl_surface; struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; struct wl_callback *wl_callback; + const char *title; + + /*Client Side Decorations*/ + //TODO : Check if KDE is used before enabling this + wl_decoration_t *decoration; } wl_window_t; From a0c474df72a3013dd2646d56db9c8cf8bfb6af60 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Fri, 17 Jun 2022 13:41:32 +0200 Subject: [PATCH 08/30] Decoration title rendering --- src/implem/wayland/wl_backend.c | 1 - src/implem/wayland/wl_decoration.c | 88 +++++++++++++++++++++++++++++- src/implem/wayland/wl_decoration.h | 11 +++- src/implem/wayland/wl_window.c | 2 +- 4 files changed, 97 insertions(+), 5 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 076d0f60..f73934b6 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -207,7 +207,6 @@ _wl_pointer_button_handler( if (wl_back->inside_decor && state == WL_POINTER_BUTTON_STATE_PRESSED && button == 272) { - printf("henlo"); xdg_toplevel_move(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial); } } diff --git a/src/implem/wayland/wl_decoration.c b/src/implem/wayland/wl_decoration.c index 93864951..d65605eb 100644 --- a/src/implem/wayland/wl_decoration.c +++ b/src/implem/wayland/wl_decoration.c @@ -23,12 +23,18 @@ #include #include +#include +#include FT_FREETYPE_H + #include "wl_decoration.h" #include "wl_backend.h" #include "wl_backend_internal.h" + + + //TODO : Factor this between surface and decoration static void _randname( @@ -78,12 +84,89 @@ _allocate_shm_file( return fd; } +void +_wl_decoration_render_title( + uint8_t *target, + uint32_t width, + uint32_t height, + const char* title +) +{ + assert(target != NULL); + assert(title != NULL); + + FT_Library library; + FT_Face face; + + uint32_t error = FT_Init_FreeType(&library); + if (error) + return; + error = FT_New_Face(library,"/usr/share/fonts/truetype/ubuntu/Ubuntu-B.ttf",0,&face); + if (error) + return; + error = FT_Set_Pixel_Sizes(face,0,16); + uint32_t i = 0; + uint32_t pen_x = 16; + uint32_t pen_y = 25; + for (int i = 0;i < strlen(title);i++) + { + FT_UInt glyph_index; + glyph_index = FT_Get_Char_Index(face,title[i]); + error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); + if (error) + continue; + error = FT_Render_Glyph(face->glyph,FT_RENDER_MODE_NORMAL); + if (error) + continue; + printf("%d\n",face->glyph->bitmap.rows); + for (int r = 0; r < face->glyph->bitmap.rows;r++) + { + int di = pen_y - face->glyph->bitmap_top + r; + if (di < 0) + continue; + else if (di > height) + break; + for (int c = 0; c < face->glyph->bitmap.width;c++) + { + int dj = pen_x + face->glyph->bitmap_left + c; + if (dj < 0) + continue; + if (dj > width) + break; + int s_idx = r * face->glyph->bitmap.pitch + c; + uint8_t alpha = face->glyph->bitmap.buffer[s_idx]; + int d_idx = dj + width*di; + if (alpha == 255) + { + target[4*d_idx] = 255; + target[4*d_idx + 1] = 255; + target[4*d_idx + 2] = 255; + target[4*d_idx + 3] = 255; + } + else if (alpha > 0) + { + target[4*d_idx] = (alpha * 255 + (255 - alpha)*(target[4*d_idx]))/255; + target[4*d_idx + 1] = (alpha * 255 + (255 - alpha)*(target[4*d_idx]))/255; + target[4*d_idx + 2] = (alpha * 255 + (255 - alpha)*(target[4*d_idx]))/255; + target[4*d_idx + 3] = 255; + } + } + } + pen_x += face->glyph->advance.x >> 6; + pen_y += face->glyph->advance.y >> 6; + } + + FT_Done_Face(face); + FT_Done_FreeType(library); + +} wl_decoration_t* wl_decoration_create( struct wl_surface *parent, - uint32_t width + uint32_t width, + const char* title ) { @@ -121,7 +204,7 @@ wl_decoration_create( pool_data[4*i + 2] = 0; pool_data[4*i + 3] = 255; } - + _wl_decoration_render_title(pool_data,width,_decor_height,title); munmap(pool_data,shm_pool_size); wl_surface_attach(decor->wl_surface,wl_buffer,0,0); @@ -144,6 +227,7 @@ wl_decoration_destroy( wl_buffer_destroy(decoration->background_buffer); wl_subsurface_destroy(decoration->wl_subsurface); wl_surface_destroy(decoration->wl_surface); + free(decoration); } void diff --git a/src/implem/wayland/wl_decoration.h b/src/implem/wayland/wl_decoration.h index 54dbc7b5..58a06d38 100644 --- a/src/implem/wayland/wl_decoration.h +++ b/src/implem/wayland/wl_decoration.h @@ -28,7 +28,8 @@ typedef struct wl_decoration_t { wl_decoration_t* wl_decoration_create( struct wl_surface *parent, - uint32_t width + uint32_t width, + const char* title ); void @@ -41,6 +42,14 @@ wl_decoration_present( wl_decoration_t* decoration ); +void +_wl_decoration_render_title( + uint8_t *target, + uint32_t width, + uint32_t height, + const char* title +); + #endif /* __WL_DECORATION_H */ \ No newline at end of file diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 27a94ef6..b74a2001 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -111,7 +111,7 @@ wl_window_create( window->wl_surface = wl_compositor_create_surface(wl_back->compositor); wl_surface_set_user_data(window->wl_surface,window); - window->decoration = wl_decoration_create(window->wl_surface,width); + window->decoration = wl_decoration_create(window->wl_surface,width,title); wl_surface_set_user_data(window->decoration->wl_surface,window); wl_backend_add_window(window); From acd94b2ed64764cfbd79493271d1a0576ddd0bd8 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Fri, 17 Jun 2022 16:05:35 +0200 Subject: [PATCH 09/30] Refactored some parts common between surface and decoration --- src/dune | 2 +- src/implem/wayland/wl_decoration.c | 70 ++------------------ src/implem/wayland/wl_memory.c | 101 +++++++++++++++++++++++++++++ src/implem/wayland/wl_memory.h | 22 +++++++ src/implem/wayland/wl_surface.c | 87 +++---------------------- 5 files changed, 136 insertions(+), 146 deletions(-) create mode 100644 src/implem/wayland/wl_memory.c create mode 100644 src/implem/wayland/wl_memory.h diff --git a/src/dune b/src/dune index fa4c9d75..c51b61c8 100644 --- a/src/dune +++ b/src/dune @@ -15,7 +15,7 @@ gdi_keyboard gdi_backend gdi_target gdi_window gdi_surface qtz_keyboard qtz_backend qtz_target qtz_window qtz_surface x11_keysym x11_keyboard x11_backend x11_target x11_window x11_surface - wl_backend wl_target wl_window wl_surface wl_decoration xdg-shell-protocol + wl_backend wl_memory wl_target wl_window wl_surface wl_decoration xdg-shell-protocol window surface path arc polygon polygonize poly_render font_desc gdi_font qtz_font ft_font font diff --git a/src/implem/wayland/wl_decoration.c b/src/implem/wayland/wl_decoration.c index d65605eb..93ff8278 100644 --- a/src/implem/wayland/wl_decoration.c +++ b/src/implem/wayland/wl_decoration.c @@ -29,61 +29,12 @@ #include "wl_decoration.h" #include "wl_backend.h" #include "wl_backend_internal.h" +#include "wl_memory.h" - -//TODO : Factor this between surface and decoration -static void -_randname( - char *buf) -{ - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - long r = ts.tv_nsec; - for (int i = 0; i < 6; ++i) { - buf[i] = 'A'+(r&15)+(r&16)*2; - r >>= 5; - } -} -//TODO : Factor this between surface and decoration -static int -_create_shm_file() -{ - int retries = 100; - do { - char name[] = "/canvas_shm-XXXXXX"; - _randname(name + sizeof(name) - 7); - --retries; - int fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600); - if (fd >= 0) { - shm_unlink(name); - return fd; - } - } while (retries > 0 && errno == EEXIST); - return -1; -} -//TODO : Factor this between surface and decoration -static int -_allocate_shm_file( - size_t size) -{ - int fd = _create_shm_file(); - if (fd < 0) - return -1; - int ret; - do { - ret = ftruncate(fd, size); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - close(fd); - return -1; - } - return fd; -} - void _wl_decoration_render_title( uint8_t *target, @@ -180,21 +131,8 @@ wl_decoration_create( decor->wl_surface = wl_compositor_create_surface(wl_back->compositor); decor->wl_subsurface = wl_subcompositor_get_subsurface(wl_back->subcompositor,decor->wl_surface,parent); - //TODO : Factor this between surface and decoration - uint32_t shm_pool_size = width * _decor_height * 4; - int fd = _allocate_shm_file(shm_pool_size); - uint8_t *pool_data = (uint8_t *)mmap(NULL, shm_pool_size, - PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - - struct wl_shm_pool *pool = wl_shm_create_pool(wl_back->shm, - fd, shm_pool_size); - close(fd); - - struct wl_buffer *wl_buffer = - wl_shm_pool_create_buffer(pool, 0, width, _decor_height, width * 4, - WL_SHM_FORMAT_ARGB8888); // or ARGB for alpha - wl_shm_pool_destroy(pool); + uint8_t *pool_data = NULL; + struct wl_buffer *wl_buffer = wl_create_buffer(width,_decor_height,&pool_data); //TODO : Improve the design for (int i = 0;i < width*_decor_height;i++) @@ -205,7 +143,7 @@ wl_decoration_create( pool_data[4*i + 3] = 255; } _wl_decoration_render_title(pool_data,width,_decor_height,title); - munmap(pool_data,shm_pool_size); + munmap(pool_data,width * _decor_height * 4); wl_surface_attach(decor->wl_surface,wl_buffer,0,0); wl_subsurface_set_position(decor->wl_subsurface,0,-_decor_height); diff --git a/src/implem/wayland/wl_memory.c b/src/implem/wayland/wl_memory.c new file mode 100644 index 00000000..a94f6d74 --- /dev/null +++ b/src/implem/wayland/wl_memory.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifdef HAS_WAYLAND + +#include +#include +#include +#include +#include + +#include + +#include "wl_backend.h" +#include "wl_backend_internal.h" + +static void +_randname( + char *buf) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + long r = ts.tv_nsec; + for (int i = 0; i < 6; ++i) { + buf[i] = 'A'+(r&15)+(r&16)*2; + r >>= 5; + } +} + +static int +_create_shm_file() +{ + int retries = 100; + do { + char name[] = "/canvas_shm-XXXXXX"; + _randname(name + sizeof(name) - 7); + --retries; + int fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600); + if (fd >= 0) { + shm_unlink(name); + return fd; + } + } while (retries > 0 && errno == EEXIST); + return -1; +} +static int +_allocate_shm_file( + size_t size) +{ + int fd = _create_shm_file(); + if (fd < 0) + return -1; + int ret; + do { + ret = ftruncate(fd, size); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + close(fd); + return -1; + } + return fd; +} + +struct wl_buffer* wl_create_buffer( + uint32_t width, + uint32_t height, + uint8_t **data +) +{ + assert(data != NULL); + assert(width > 0); + assert(height > 0); + + uint32_t shm_pool_size = width * height * 4; + int fd = _allocate_shm_file(shm_pool_size); + *data = (uint8_t *)mmap(NULL, shm_pool_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + + struct wl_shm_pool *pool = wl_shm_create_pool(wl_back->shm, + fd, shm_pool_size); + + close(fd); + + struct wl_buffer *wl_buffer = + wl_shm_pool_create_buffer(pool, 0, width, height, width * 4, + WL_SHM_FORMAT_ARGB8888); // or ARGB for alpha + wl_shm_pool_destroy(pool); + + + return wl_buffer; +} + +#endif /*HAS_WAYLAND*/ \ No newline at end of file diff --git a/src/implem/wayland/wl_memory.h b/src/implem/wayland/wl_memory.h new file mode 100644 index 00000000..43c2fbaf --- /dev/null +++ b/src/implem/wayland/wl_memory.h @@ -0,0 +1,22 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifndef __WL_MEMORY_H +#define __WL_MEMORY_H + +#include + +struct wl_buffer* wl_create_buffer( + uint32_t width, + uint32_t height, + uint8_t **data +); + +#endif /*__WL_MEMORY_H*/ \ No newline at end of file diff --git a/src/implem/wayland/wl_surface.c b/src/implem/wayland/wl_surface.c index ef613bf3..4fa0388e 100644 --- a/src/implem/wayland/wl_surface.c +++ b/src/implem/wayland/wl_surface.c @@ -28,6 +28,7 @@ #include "../color.h" #include "wl_backend.h" #include "wl_window.h" +#include "wl_memory.h" #include "wl_target.h" typedef struct surface_impl_wl_t { @@ -36,53 +37,6 @@ typedef struct surface_impl_wl_t { struct wl_surface *wl_surface; } surface_impl_wl_t; -static void -_randname( - char *buf) -{ - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - long r = ts.tv_nsec; - for (int i = 0; i < 6; ++i) { - buf[i] = 'A'+(r&15)+(r&16)*2; - r >>= 5; - } -} - -static int -_create_shm_file() -{ - int retries = 100; - do { - char name[] = "/canvas_shm-XXXXXX"; - _randname(name + sizeof(name) - 7); - --retries; - int fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600); - if (fd >= 0) { - shm_unlink(name); - return fd; - } - } while (retries > 0 && errno == EEXIST); - return -1; -} - -static int -_allocate_shm_file( - size_t size) -{ - int fd = _create_shm_file(); - if (fd < 0) - return -1; - int ret; - do { - ret = ftruncate(fd, size); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - close(fd); - return -1; - } - return fd; -} surface_impl_wl_t * surface_create_wl_impl( @@ -105,24 +59,10 @@ surface_create_wl_impl( return NULL; } - // _surface_create_wl_image(..., width, height, &s->data, ...); + uint8_t *pool_data = NULL; + struct wl_buffer *wl_buffer = wl_create_buffer(width,height,&pool_data); - uint32_t shm_pool_size = width * height * 4; - int fd = _allocate_shm_file(shm_pool_size); - uint8_t *pool_data = (uint8_t *)mmap(NULL, shm_pool_size, - PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - - struct wl_shm_pool *pool = wl_shm_create_pool(wl_target->wl_shm, - fd, shm_pool_size); - close(fd); // fd no longer needed at this point - - struct wl_buffer *wl_buffer = - wl_shm_pool_create_buffer(pool, 0, width, height, width * 4, - WL_SHM_FORMAT_ARGB8888); // or ARGB for alpha wl_buffer_set_user_data(wl_buffer,wl_target->wl_shm); -// or pool could be kept... - wl_shm_pool_destroy(pool); // the buffer keeps a reference to the pool so it's ok to destroy impl->type = IMPL_WAYLAND; impl->wl_buffer = wl_buffer; @@ -190,29 +130,18 @@ surface_resize_wl_impl( assert(d_data != NULL); assert(*d_data == NULL); - //Acquire Shm object (needed to recreate a new buffer) - struct wl_shm* wl_shm = wl_buffer_get_user_data(impl->wl_buffer); //Destroy old buffer if (impl->wl_buffer) wl_buffer_destroy(impl->wl_buffer); - - //Create a new shared memory slot with the correct size - uint32_t shm_pool_size = d_width * d_height * 4; - int fd = _allocate_shm_file(shm_pool_size); - uint8_t *pool_data = (uint8_t *)mmap(NULL, shm_pool_size, - PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - - struct wl_shm_pool *pool = wl_shm_create_pool(wl_shm, - fd, shm_pool_size); - close(fd); - //Create buffer and get data handle - impl->wl_buffer = wl_shm_pool_create_buffer(pool,0,d_width,d_height,d_width*4,WL_SHM_FORMAT_ARGB8888); - wl_buffer_set_user_data(impl->wl_buffer,wl_shm); + //Create new buffer + uint8_t *pool_data = NULL; + impl->wl_buffer = wl_create_buffer(d_width,d_height,&pool_data); *d_data = (color_t_ *)pool_data; //Copy data _raw_surface_copy(*s_data,s_width,s_height,*d_data,d_width,d_height); + //Delete old data ? + munmap(s_data,s_width * s_height * 4); return true; } From 59c2556d2731509e887d25061c3fa8105a1c2c24 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Fri, 17 Jun 2022 16:41:02 +0200 Subject: [PATCH 10/30] Added close button --- src/implem/wayland/wl_backend.c | 24 ++++++++++----- src/implem/wayland/wl_backend_internal.h | 8 ++++- src/implem/wayland/wl_decoration.c | 37 ++++++++++++++++++++---- src/implem/wayland/wl_decoration.h | 13 ++++----- src/implem/wayland/wl_window.c | 1 + 5 files changed, 62 insertions(+), 21 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index f73934b6..0aa72ace 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -135,12 +135,14 @@ _wl_pointer_enter_handler( { wl_back->focus_window = (wl_window_t*)wl_surface_get_user_data(surface); if (surface == wl_back->focus_window->decoration->wl_surface) - wl_back->inside_decor = 1; + wl_back->inside_decor_location = DECOR_REGION_BAR; + else if (surface == wl_back->focus_window->decoration->wl_closebutton_surface) + wl_back->inside_decor_location = DECOR_REGION_CLOSE_BUTTON; } else { wl_back->focus_window = NULL; - wl_back->inside_decor = 1; + wl_back->inside_decor_location = DECOR_REGION_OUTSIDE; } event_t evt; @@ -154,7 +156,7 @@ _wl_pointer_leave_handler( struct wl_surface *surface) { wl_backend_t *wl_back = (wl_backend_t *)data; - wl_back->inside_decor = 0; + wl_back->inside_decor_location = DECOR_REGION_OUTSIDE; } static void @@ -189,7 +191,7 @@ _wl_pointer_button_handler( uint32_t state) { //When the focus screen is hidden with a key down event for example, the key up event will still trigger. This check mitigates that. - if (wl_back->focus_window && wl_back->focus_window->base.visible && !wl_back->inside_decor) { + if (wl_back->focus_window && wl_back->focus_window->base.visible && !wl_back->inside_decor_location) { wl_backend_t *wl_back = (wl_backend_t *)data; event_t evt; evt.type = EVENT_BUTTON; @@ -205,9 +207,17 @@ _wl_pointer_button_handler( printf("button: 0x%x state: %d\n", button, state); } - if (wl_back->inside_decor && state == WL_POINTER_BUTTON_STATE_PRESSED && button == 272) + if (state == WL_POINTER_BUTTON_STATE_PRESSED && button == 272) { - xdg_toplevel_move(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial); + if (wl_back->inside_decor_location == DECOR_REGION_BAR) + xdg_toplevel_move(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial); + else if (wl_back->inside_decor_location == DECOR_REGION_CLOSE_BUTTON) + { + event_t evt; + evt.type = EVENT_CLOSE; + evt.target = wl_back->focus_window; + event_notify(wl_back->listener,&evt); + } } } @@ -390,7 +400,7 @@ wl_backend_init( wl_back->pointer = wl_seat_get_pointer(wl_back->seat); if (wl_back->pointer) wl_pointer_add_listener(wl_back->pointer, &_wl_pointer_listener, wl_back); - wl_back->inside_decor = 0; + wl_back->inside_decor_location = DECOR_REGION_OUTSIDE; /* Retrieve the keyboard, iinitiate xkb_context and add listener */ wl_back->keyboard = wl_seat_get_keyboard(wl_back->seat); if (wl_back->keyboard) { diff --git a/src/implem/wayland/wl_backend_internal.h b/src/implem/wayland/wl_backend_internal.h index 5b1a5bef..b35315d5 100644 --- a/src/implem/wayland/wl_backend_internal.h +++ b/src/implem/wayland/wl_backend_internal.h @@ -21,6 +21,12 @@ #include "../hashtable.h" #include "../event.h" +enum DECORATION_REGION { + DECOR_REGION_OUTSIDE = 0, + DECOR_REGION_BAR = 1, + DECOR_REGION_CLOSE_BUTTON = 2, +}; + typedef struct wl_backend_t { @@ -54,7 +60,7 @@ typedef struct wl_backend_t { /*Mouse objects*/ wl_fixed_t mouse_posx; wl_fixed_t mouse_posy; - uint8_t inside_decor; + enum DECORATION_REGION inside_decor_location; } wl_backend_t; extern wl_backend_t *wl_back; diff --git a/src/implem/wayland/wl_decoration.c b/src/implem/wayland/wl_decoration.c index 93ff8278..3d893729 100644 --- a/src/implem/wayland/wl_decoration.c +++ b/src/implem/wayland/wl_decoration.c @@ -33,7 +33,28 @@ - +void +_wl_decoration_close_button( + wl_decoration_t *decor, + uint32_t size +) +{ + decor->wl_closebutton_surface = wl_compositor_create_surface(wl_back->compositor); + decor->wl_closebutton_subsurface = wl_subcompositor_get_subsurface(wl_back->subcompositor, + decor->wl_closebutton_surface, + decor->wl_surface); + uint8_t *data = NULL; + decor->wl_closebutton_buffer = wl_create_buffer(size,size,&data); + for (int i = 0; i < size*size;i++) + { + data[4*i] = 0; + data[4*i + 1] = 0; + data[4*i + 2] = 255; + data[4*i + 3] = 255; + } + munmap(data,size * size * 4); + wl_surface_attach(decor->wl_closebutton_surface,decor->wl_closebutton_buffer,0,0); +} void _wl_decoration_render_title( @@ -144,11 +165,13 @@ wl_decoration_create( } _wl_decoration_render_title(pool_data,width,_decor_height,title); munmap(pool_data,width * _decor_height * 4); - wl_surface_attach(decor->wl_surface,wl_buffer,0,0); wl_subsurface_set_position(decor->wl_subsurface,0,-_decor_height); decor->background_buffer = wl_buffer; + _wl_decoration_close_button(decor,30); + wl_subsurface_set_position(decor->wl_closebutton_subsurface,width - 40,5); + return decor; } @@ -158,13 +181,14 @@ wl_decoration_destroy( ) { assert(decoration != NULL); - assert(decoration->background_buffer != NULL); - assert(decoration->wl_subsurface != NULL); - assert(decoration->wl_surface != NULL); - + + wl_buffer_destroy(decoration->wl_closebutton_buffer); + wl_subsurface_destroy(decoration->wl_closebutton_subsurface); + wl_surface_destroy(decoration->wl_closebutton_surface); wl_buffer_destroy(decoration->background_buffer); wl_subsurface_destroy(decoration->wl_subsurface); wl_surface_destroy(decoration->wl_surface); + free(decoration); } @@ -174,6 +198,7 @@ wl_decoration_present( ) { wl_surface_commit(decoration->wl_surface); + wl_surface_commit(decoration->wl_closebutton_surface); } diff --git a/src/implem/wayland/wl_decoration.h b/src/implem/wayland/wl_decoration.h index 58a06d38..a15517c7 100644 --- a/src/implem/wayland/wl_decoration.h +++ b/src/implem/wayland/wl_decoration.h @@ -23,6 +23,11 @@ typedef struct wl_decoration_t { struct wl_surface *wl_surface; struct wl_subsurface *wl_subsurface; struct wl_buffer *background_buffer; + + struct wl_surface *wl_closebutton_surface; + struct wl_subsurface *wl_closebutton_subsurface; + struct wl_buffer *wl_closebutton_buffer; + } wl_decoration_t; wl_decoration_t* @@ -42,13 +47,7 @@ wl_decoration_present( wl_decoration_t* decoration ); -void -_wl_decoration_render_title( - uint8_t *target, - uint32_t width, - uint32_t height, - const char* title -); + diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index b74a2001..46507d2a 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -113,6 +113,7 @@ wl_window_create( window->decoration = wl_decoration_create(window->wl_surface,width,title); wl_surface_set_user_data(window->decoration->wl_surface,window); + wl_surface_set_user_data(window->decoration->wl_closebutton_surface,window); wl_backend_add_window(window); From 51eae1b359324d93af5217d0c4de44a5f5c912fa Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Tue, 21 Jun 2022 11:12:01 +0200 Subject: [PATCH 11/30] Resize WIP --- src/implem/wayland/wl_backend.c | 27 ++++++++++++++++++++++--- src/implem/wayland/wl_window.c | 17 +++++++++++++--- src/implem/wayland/wl_window_internal.h | 1 + 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 0aa72ace..29e5371c 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -209,8 +209,21 @@ _wl_pointer_button_handler( if (state == WL_POINTER_BUTTON_STATE_PRESSED && button == 272) { - if (wl_back->inside_decor_location == DECOR_REGION_BAR) - xdg_toplevel_move(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial); + const wl_fixed_t margin = 5 * 256; + uint32_t resizeEdge = XDG_TOPLEVEL_RESIZE_EDGE_NONE; + if (wl_back->inside_decor_location == DECOR_REGION_BAR && wl_back->mouse_posy < margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_TOP; + else if (!wl_back->inside_decor_location && wl_back->mouse_posy > wl_back->focus_window->base.height*256 - margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; + if (wl_back->mouse_posx < margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_LEFT; + else if (wl_back->mouse_posx > wl_back->focus_window->base.width*256 - margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; + if (resizeEdge != XDG_TOPLEVEL_RESIZE_EDGE_NONE) + { + //xdg_toplevel_move(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial); + xdg_toplevel_resize(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial,resizeEdge); + } else if (wl_back->inside_decor_location == DECOR_REGION_CLOSE_BUTTON) { event_t evt; @@ -480,8 +493,16 @@ static void wl_callback_handle_frame( wl_window->wl_callback = wl_surface_frame(wl_window->wl_surface); wl_callback_add_listener(wl_window->wl_callback,&wl_callback_listener,wl_window); } - //Trigger event event_t evt; + if (wl_window->pending_resize) + { + evt.desc.resize.width = wl_window->base.width; + evt.desc.resize.height = wl_window->base.height; + evt.target = wl_window; + evt.type = EVENT_RESIZE; + event_notify(wl_back->listener,&evt); + } + //Trigger event evt.type = EVENT_FRAME; evt.time = _wl_get_time(); if (wl_window->base.visible) { diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 46507d2a..6865c734 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -29,6 +29,7 @@ #include "wl_window_internal.h" + static void _wl_window_update_position( wl_window_t *window) @@ -60,7 +61,18 @@ _wl_xdg_toplevel_configure_handler( int32_t height, struct wl_array *states) { + struct wl_window_t *wl_window = data; printf("top level configure: %dx%d\n", width, height); + uint8_t* p; + bool resizing = false; + wl_array_for_each(p,states) if(*p == XDG_TOPLEVEL_STATE_RESIZING) resizing = true; + bool movedEnough = abs(width - wl_window->base.width) > 10; + movedEnough |= abs(height - wl_window->base.height) > 10; + if (resizing && movedEnough) + { + wl_window->pending_resize = true; + wl_window_set_size(wl_window,width,height); + } } static void @@ -107,6 +119,7 @@ wl_window_create( window->base.height = clip_i32_to_i16(max(1, height)); window->title = title; + window->pending_resize = false; window->wl_surface = wl_compositor_create_surface(wl_back->compositor); wl_surface_set_user_data(window->wl_surface,window); @@ -183,14 +196,13 @@ wl_window_show( wl_window_t *window) { assert(window != NULL); - if (window->base.visible) { + if (!window->xdg_surface) { window->xdg_surface = xdg_wm_base_get_xdg_surface(wl_back->xdg_wm_base, window->wl_surface); xdg_surface_add_listener(window->xdg_surface, &_wl_xdg_surface_listener, &window); window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface); xdg_toplevel_add_listener(window->xdg_toplevel,&_wl_xdg_toplevel_listener,window); xdg_toplevel_set_title(window->xdg_toplevel,window->title); - window->base.visible = true; wl_surface_commit(window->wl_surface); } _wl_window_update_position(window); @@ -209,7 +221,6 @@ wl_window_hide( xdg_toplevel_destroy(window->xdg_toplevel); window->xdg_surface = NULL; window->xdg_toplevel = NULL; - window->base.visible = false; //Cannot recreate the XDG Surface from a surface with an attached buffer. wl_surface_attach(window->wl_surface,NULL,0,0); wl_surface_commit(window->wl_surface); diff --git a/src/implem/wayland/wl_window_internal.h b/src/implem/wayland/wl_window_internal.h index 43528e77..9d7983e3 100644 --- a/src/implem/wayland/wl_window_internal.h +++ b/src/implem/wayland/wl_window_internal.h @@ -32,6 +32,7 @@ typedef struct wl_window_t { /*Client Side Decorations*/ //TODO : Check if KDE is used before enabling this wl_decoration_t *decoration; + bool pending_resize; } wl_window_t; From fe0ff2d413375051e4a1c618522f316fcca7cf8f Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Tue, 21 Jun 2022 17:12:21 +0200 Subject: [PATCH 12/30] Fixed resize memory problems --- src/implem/wayland/wl_backend.c | 14 ++++------ src/implem/wayland/wl_surface.c | 46 ++++++++++++++++++++++++++------- src/implem/wayland/wl_window.c | 2 ++ 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 29e5371c..9e61fdcc 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -219,11 +219,16 @@ _wl_pointer_button_handler( resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_LEFT; else if (wl_back->mouse_posx > wl_back->focus_window->base.width*256 - margin) resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; + if (resizeEdge != XDG_TOPLEVEL_RESIZE_EDGE_NONE) { //xdg_toplevel_move(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial); xdg_toplevel_resize(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial,resizeEdge); } + else if (wl_back->inside_decor_location == DECOR_REGION_BAR) + { + xdg_toplevel_move(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial); + } else if (wl_back->inside_decor_location == DECOR_REGION_CLOSE_BUTTON) { event_t evt; @@ -494,15 +499,6 @@ static void wl_callback_handle_frame( wl_callback_add_listener(wl_window->wl_callback,&wl_callback_listener,wl_window); } event_t evt; - if (wl_window->pending_resize) - { - evt.desc.resize.width = wl_window->base.width; - evt.desc.resize.height = wl_window->base.height; - evt.target = wl_window; - evt.type = EVENT_RESIZE; - event_notify(wl_back->listener,&evt); - } - //Trigger event evt.type = EVENT_FRAME; evt.time = _wl_get_time(); if (wl_window->base.visible) { diff --git a/src/implem/wayland/wl_surface.c b/src/implem/wayland/wl_surface.c index 4fa0388e..8ffe631c 100644 --- a/src/implem/wayland/wl_surface.c +++ b/src/implem/wayland/wl_surface.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,8 @@ #include "../config.h" #include "../color.h" #include "wl_backend.h" +#include "wl_backend_internal.h" +#include "wl_window_internal.h" #include "wl_window.h" #include "wl_memory.h" #include "wl_target.h" @@ -38,6 +41,29 @@ typedef struct surface_impl_wl_t { } surface_impl_wl_t; + +static void +wl_buffer_release(void *data, struct wl_buffer *wl_buffer) +{ + //process resize requests here? + struct wl_window_t *wl_window = data; + event_t evt; + if (wl_window->pending_resize) + { + evt.desc.resize.width = wl_window->base.width; + evt.desc.resize.height = wl_window->base.height; + evt.target = wl_window; + evt.type = EVENT_RESIZE; + event_notify(wl_back->listener,&evt); + wl_window->pending_resize = false; + } +} + +static const struct wl_buffer_listener wl_buffer_listener = { + .release = wl_buffer_release, +}; + + surface_impl_wl_t * surface_create_wl_impl( wl_target_t *wl_target, @@ -61,8 +87,7 @@ surface_create_wl_impl( uint8_t *pool_data = NULL; struct wl_buffer *wl_buffer = wl_create_buffer(width,height,&pool_data); - - wl_buffer_set_user_data(wl_buffer,wl_target->wl_shm); + wl_buffer_add_listener(wl_buffer,&wl_buffer_listener,wl_surface_get_user_data(wl_target->wl_surface)); impl->type = IMPL_WAYLAND; impl->wl_buffer = wl_buffer; @@ -100,10 +125,11 @@ _raw_surface_copy( assert(d_data != NULL); assert(d_width > 0); assert(d_height > 0); + uint32_t min_width = d_width < s_width ? d_width : s_width; uint32_t min_height = d_height < s_height ? d_height : s_height; - for (size_t i = 0; i < min_height; ++i) { - for (size_t j = 0; j < min_width; ++j) { + for (size_t i = 0; i < min_height; i++) { + for (size_t j = 0; j < min_width; j++) { d_data[i * d_width + j] = s_data[i * s_width + j]; } } @@ -130,18 +156,18 @@ surface_resize_wl_impl( assert(d_data != NULL); assert(*d_data == NULL); - - //Destroy old buffer - if (impl->wl_buffer) - wl_buffer_destroy(impl->wl_buffer); + wl_surface_attach(impl->wl_surface,NULL,0,0); //Create new buffer uint8_t *pool_data = NULL; - impl->wl_buffer = wl_create_buffer(d_width,d_height,&pool_data); + struct wl_buffer* newBuffer = wl_create_buffer(d_width,d_height,&pool_data); *d_data = (color_t_ *)pool_data; //Copy data _raw_surface_copy(*s_data,s_width,s_height,*d_data,d_width,d_height); //Delete old data ? - munmap(s_data,s_width * s_height * 4); + wl_buffer_destroy(impl->wl_buffer); + munmap(*s_data,s_width * s_height * 4); + wl_buffer_add_listener(newBuffer,&wl_buffer_listener,wl_surface_get_user_data(impl->wl_surface)); + impl->wl_buffer = newBuffer; return true; } diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 6865c734..63d1d1b7 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -203,6 +203,8 @@ wl_window_show( window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface); xdg_toplevel_add_listener(window->xdg_toplevel,&_wl_xdg_toplevel_listener,window); xdg_toplevel_set_title(window->xdg_toplevel,window->title); + //Need to attach any buffer here... + wl_surface_attach(window->wl_surface,window->decoration->wl_closebutton_buffer,0,0); wl_surface_commit(window->wl_surface); } _wl_window_update_position(window); From 3df780b7f94401511ea91836a51f2051b790d3a0 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Tue, 21 Jun 2022 17:41:48 +0200 Subject: [PATCH 13/30] Decorations react to resize --- src/implem/wayland/wl_decoration.c | 63 +++++++++++++++++++++--------- src/implem/wayland/wl_decoration.h | 7 +++- src/implem/wayland/wl_memory.c | 4 +- src/implem/wayland/wl_surface.c | 14 +++++-- 4 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/implem/wayland/wl_decoration.c b/src/implem/wayland/wl_decoration.c index 3d893729..5f27814c 100644 --- a/src/implem/wayland/wl_decoration.c +++ b/src/implem/wayland/wl_decoration.c @@ -30,6 +30,7 @@ #include "wl_backend.h" #include "wl_backend_internal.h" #include "wl_memory.h" +#include "../unicode.h" @@ -80,10 +81,15 @@ _wl_decoration_render_title( uint32_t i = 0; uint32_t pen_x = 16; uint32_t pen_y = 25; - for (int i = 0;i < strlen(title);i++) + while(*title) { + uint32_t chr = decode_utf8_char(&title); + if (pen_x > width - 30 - 16) + break; + if (pen_x > width - 30 - 32) + chr = 0x0000002e; FT_UInt glyph_index; - glyph_index = FT_Get_Char_Index(face,title[i]); + glyph_index = FT_Get_Char_Index(face,chr); error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if (error) continue; @@ -133,6 +139,26 @@ _wl_decoration_render_title( } +struct wl_buffer* +_wl_decoration_background( + uint32_t width, + const char* title +) +{ + uint32_t _decor_height = 40; + uint8_t *pool_data = NULL; + struct wl_buffer *wl_buffer = wl_create_buffer(width,_decor_height,&pool_data); + for (int i = 0;i < width*_decor_height;i++) + { + pool_data[4*i] = 0; + pool_data[4*i + 1] = 0; + pool_data[4*i + 2] = 0; + pool_data[4*i + 3] = 255; + } + _wl_decoration_render_title(pool_data,width,_decor_height,title); + munmap(pool_data,width * _decor_height * 4); + return wl_buffer; +} wl_decoration_t* wl_decoration_create( @@ -141,7 +167,6 @@ wl_decoration_create( const char* title ) { - //TODO : Make this adapt to screen uint32_t _decor_height = 40; @@ -151,27 +176,12 @@ wl_decoration_create( return NULL; decor->wl_surface = wl_compositor_create_surface(wl_back->compositor); decor->wl_subsurface = wl_subcompositor_get_subsurface(wl_back->subcompositor,decor->wl_surface,parent); - - uint8_t *pool_data = NULL; - struct wl_buffer *wl_buffer = wl_create_buffer(width,_decor_height,&pool_data); - - //TODO : Improve the design - for (int i = 0;i < width*_decor_height;i++) - { - pool_data[4*i] = 0; - pool_data[4*i + 1] = 0; - pool_data[4*i + 2] = 0; - pool_data[4*i + 3] = 255; - } - _wl_decoration_render_title(pool_data,width,_decor_height,title); - munmap(pool_data,width * _decor_height * 4); + struct wl_buffer *wl_buffer = _wl_decoration_background(width,title); wl_surface_attach(decor->wl_surface,wl_buffer,0,0); wl_subsurface_set_position(decor->wl_subsurface,0,-_decor_height); decor->background_buffer = wl_buffer; - _wl_decoration_close_button(decor,30); wl_subsurface_set_position(decor->wl_closebutton_subsurface,width - 40,5); - return decor; } @@ -202,4 +212,19 @@ wl_decoration_present( } +void +wl_decoration_resize( + wl_decoration_t* decor, + uint32_t width, + const char* title +) +{ + wl_buffer_destroy(decor->background_buffer); + decor->background_buffer = _wl_decoration_background(width,title); + wl_surface_attach(decor->wl_surface,decor->background_buffer,0,0); + wl_subsurface_set_position(decor->wl_closebutton_subsurface,width - 40,5); +} + + + #endif /*HAS_WAYLAND*/ \ No newline at end of file diff --git a/src/implem/wayland/wl_decoration.h b/src/implem/wayland/wl_decoration.h index a15517c7..a68a8fe3 100644 --- a/src/implem/wayland/wl_decoration.h +++ b/src/implem/wayland/wl_decoration.h @@ -47,7 +47,12 @@ wl_decoration_present( wl_decoration_t* decoration ); - +void +wl_decoration_resize( + wl_decoration_t* decoration, + uint32_t width, + const char* title +); diff --git a/src/implem/wayland/wl_memory.c b/src/implem/wayland/wl_memory.c index a94f6d74..cfde6bfa 100644 --- a/src/implem/wayland/wl_memory.c +++ b/src/implem/wayland/wl_memory.c @@ -59,7 +59,7 @@ _allocate_shm_file( return -1; int ret; do { - ret = ftruncate(fd, size); + ret = posix_fallocate(fd,0, size); } while (ret < 0 && errno == EINTR); if (ret < 0) { close(fd); @@ -79,7 +79,7 @@ struct wl_buffer* wl_create_buffer( assert(height > 0); uint32_t shm_pool_size = width * height * 4; - int fd = _allocate_shm_file(shm_pool_size); + int fd = _allocate_shm_file(width*height*4); *data = (uint8_t *)mmap(NULL, shm_pool_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); diff --git a/src/implem/wayland/wl_surface.c b/src/implem/wayland/wl_surface.c index 8ffe631c..8dc8fff7 100644 --- a/src/implem/wayland/wl_surface.c +++ b/src/implem/wayland/wl_surface.c @@ -33,6 +33,7 @@ #include "wl_window.h" #include "wl_memory.h" #include "wl_target.h" +#include "wl_decoration.h" typedef struct surface_impl_wl_t { impl_type_t type; @@ -50,6 +51,9 @@ wl_buffer_release(void *data, struct wl_buffer *wl_buffer) event_t evt; if (wl_window->pending_resize) { + //resize decorations + wl_decoration_resize(wl_window->decoration,wl_window->base.width,wl_window->title); + //resize surface evt.desc.resize.width = wl_window->base.width; evt.desc.resize.height = wl_window->base.height; evt.target = wl_window; @@ -128,11 +132,15 @@ _raw_surface_copy( uint32_t min_width = d_width < s_width ? d_width : s_width; uint32_t min_height = d_height < s_height ? d_height : s_height; - for (size_t i = 0; i < min_height; i++) { - for (size_t j = 0; j < min_width; j++) { - d_data[i * d_width + j] = s_data[i * s_width + j]; + for (size_t i = 0; i < d_height; i++) { + for (size_t j = 0; j < d_width; j++) { + if (i < min_height && j < min_width) + d_data[i * d_width + j] = s_data[i * s_width + j]; + else + d_data[i * d_width + j] = color_black; } } + } From 627d7833de126291ea78cc26286c45e1206f6fec Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Wed, 22 Jun 2022 14:52:32 +0200 Subject: [PATCH 14/30] Moved resize time from buffer release to before drawing --- src/implem/wayland/wl_backend.c | 12 ++++++++++++ src/implem/wayland/wl_surface.c | 16 ++-------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 9e61fdcc..58268285 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -499,6 +499,18 @@ static void wl_callback_handle_frame( wl_callback_add_listener(wl_window->wl_callback,&wl_callback_listener,wl_window); } event_t evt; + if (wl_window->pending_resize) + { + //resize decorations + wl_decoration_resize(wl_window->decoration,wl_window->base.width,wl_window->title); + //resize surface + evt.desc.resize.width = wl_window->base.width; + evt.desc.resize.height = wl_window->base.height; + evt.target = wl_window; + evt.type = EVENT_RESIZE; + event_notify(wl_back->listener,&evt); + wl_window->pending_resize = false; + } evt.type = EVENT_FRAME; evt.time = _wl_get_time(); if (wl_window->base.visible) { diff --git a/src/implem/wayland/wl_surface.c b/src/implem/wayland/wl_surface.c index 8dc8fff7..4da88d69 100644 --- a/src/implem/wayland/wl_surface.c +++ b/src/implem/wayland/wl_surface.c @@ -46,21 +46,9 @@ typedef struct surface_impl_wl_t { static void wl_buffer_release(void *data, struct wl_buffer *wl_buffer) { - //process resize requests here? + //handle buffer release event (maybe useful later) struct wl_window_t *wl_window = data; - event_t evt; - if (wl_window->pending_resize) - { - //resize decorations - wl_decoration_resize(wl_window->decoration,wl_window->base.width,wl_window->title); - //resize surface - evt.desc.resize.width = wl_window->base.width; - evt.desc.resize.height = wl_window->base.height; - evt.target = wl_window; - evt.type = EVENT_RESIZE; - event_notify(wl_back->listener,&evt); - wl_window->pending_resize = false; - } + } static const struct wl_buffer_listener wl_buffer_listener = { From 1ea160b0530e3690d0018f19bc1e88a6786b67c1 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Wed, 22 Jun 2022 15:40:08 +0200 Subject: [PATCH 15/30] Allow disabling of decorations --- src/implem/wayland/wl_backend.c | 24 ++++++++++++++++-------- src/implem/wayland/wl_surface.c | 1 - src/implem/wayland/wl_window.c | 17 ++++++++++------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 58268285..95ded404 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -134,10 +134,15 @@ _wl_pointer_enter_handler( if (surface) { wl_back->focus_window = (wl_window_t*)wl_surface_get_user_data(surface); - if (surface == wl_back->focus_window->decoration->wl_surface) - wl_back->inside_decor_location = DECOR_REGION_BAR; - else if (surface == wl_back->focus_window->decoration->wl_closebutton_surface) - wl_back->inside_decor_location = DECOR_REGION_CLOSE_BUTTON; + if (wl_back->focus_window->base.decorated) + { + if (surface == wl_back->focus_window->decoration->wl_surface) + wl_back->inside_decor_location = DECOR_REGION_BAR; + else if (surface == wl_back->focus_window->decoration->wl_closebutton_surface) + wl_back->inside_decor_location = DECOR_REGION_CLOSE_BUTTON; + } + else + wl_back->inside_decor_location = DECOR_REGION_OUTSIDE; } else { @@ -211,7 +216,9 @@ _wl_pointer_button_handler( { const wl_fixed_t margin = 5 * 256; uint32_t resizeEdge = XDG_TOPLEVEL_RESIZE_EDGE_NONE; - if (wl_back->inside_decor_location == DECOR_REGION_BAR && wl_back->mouse_posy < margin) + if (wl_back->focus_window->base.decorated && wl_back->inside_decor_location == DECOR_REGION_BAR && wl_back->mouse_posy < margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_TOP; + else if (!wl_back->focus_window->base.decorated && wl_back->mouse_posy < margin) resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_TOP; else if (!wl_back->inside_decor_location && wl_back->mouse_posy > wl_back->focus_window->base.height*256 - margin) resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; @@ -219,7 +226,6 @@ _wl_pointer_button_handler( resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_LEFT; else if (wl_back->mouse_posx > wl_back->focus_window->base.width*256 - margin) resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; - if (resizeEdge != XDG_TOPLEVEL_RESIZE_EDGE_NONE) { //xdg_toplevel_move(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial); @@ -502,7 +508,8 @@ static void wl_callback_handle_frame( if (wl_window->pending_resize) { //resize decorations - wl_decoration_resize(wl_window->decoration,wl_window->base.width,wl_window->title); + if (wl_window->base.decorated) + wl_decoration_resize(wl_window->decoration,wl_window->base.width,wl_window->title); //resize surface evt.desc.resize.width = wl_window->base.width; evt.desc.resize.height = wl_window->base.height; @@ -517,7 +524,8 @@ static void wl_callback_handle_frame( evt.target = (wl_window_t*)data; if (event_notify(wl_back->listener,&evt)) { - wl_decoration_present(wl_window->decoration); + if (wl_window->base.decorated) + wl_decoration_present(wl_window->decoration); evt.type = EVENT_PRESENT; event_notify(wl_back->listener,&evt); } diff --git a/src/implem/wayland/wl_surface.c b/src/implem/wayland/wl_surface.c index 4da88d69..992acca2 100644 --- a/src/implem/wayland/wl_surface.c +++ b/src/implem/wayland/wl_surface.c @@ -33,7 +33,6 @@ #include "wl_window.h" #include "wl_memory.h" #include "wl_target.h" -#include "wl_decoration.h" typedef struct surface_impl_wl_t { impl_type_t type; diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 63d1d1b7..652bfdaa 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -123,11 +123,12 @@ wl_window_create( window->wl_surface = wl_compositor_create_surface(wl_back->compositor); wl_surface_set_user_data(window->wl_surface,window); - - window->decoration = wl_decoration_create(window->wl_surface,width,title); - wl_surface_set_user_data(window->decoration->wl_surface,window); - wl_surface_set_user_data(window->decoration->wl_closebutton_surface,window); - + if (window->base.decorated) + { + window->decoration = wl_decoration_create(window->wl_surface,width,title); + wl_surface_set_user_data(window->decoration->wl_surface,window); + wl_surface_set_user_data(window->decoration->wl_closebutton_surface,window); + } wl_backend_add_window(window); return window; @@ -141,7 +142,8 @@ wl_window_destroy( wl_callback_destroy(window->wl_callback); xdg_toplevel_destroy(window->xdg_toplevel); xdg_surface_destroy(window->xdg_surface); - wl_decoration_destroy(window->decoration); + if (window->base.decorated) + wl_decoration_destroy(window->decoration); wl_surface_destroy(window->wl_surface); free(window); } @@ -204,7 +206,8 @@ wl_window_show( xdg_toplevel_add_listener(window->xdg_toplevel,&_wl_xdg_toplevel_listener,window); xdg_toplevel_set_title(window->xdg_toplevel,window->title); //Need to attach any buffer here... - wl_surface_attach(window->wl_surface,window->decoration->wl_closebutton_buffer,0,0); + if (window->base.decorated) + wl_surface_attach(window->wl_surface,window->decoration->wl_closebutton_buffer,0,0); wl_surface_commit(window->wl_surface); } _wl_window_update_position(window); From 2c642b962dde5919849ce045c374960d234b8b8b Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Wed, 22 Jun 2022 15:55:09 +0200 Subject: [PATCH 16/30] Added resize direction checks --- src/implem/wayland/wl_backend.c | 2 +- src/implem/wayland/wl_backend_internal.h | 1 + src/implem/wayland/wl_window.c | 8 ++++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 95ded404..fd8a2ceb 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -226,9 +226,9 @@ _wl_pointer_button_handler( resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_LEFT; else if (wl_back->mouse_posx > wl_back->focus_window->base.width*256 - margin) resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; + wl_back->current_resize_edge = resizeEdge; if (resizeEdge != XDG_TOPLEVEL_RESIZE_EDGE_NONE) { - //xdg_toplevel_move(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial); xdg_toplevel_resize(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial,resizeEdge); } else if (wl_back->inside_decor_location == DECOR_REGION_BAR) diff --git a/src/implem/wayland/wl_backend_internal.h b/src/implem/wayland/wl_backend_internal.h index b35315d5..6079145d 100644 --- a/src/implem/wayland/wl_backend_internal.h +++ b/src/implem/wayland/wl_backend_internal.h @@ -61,6 +61,7 @@ typedef struct wl_backend_t { wl_fixed_t mouse_posx; wl_fixed_t mouse_posy; enum DECORATION_REGION inside_decor_location; + enum xdg_toplevel_resize_edge current_resize_edge; } wl_backend_t; extern wl_backend_t *wl_back; diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 652bfdaa..e84708a7 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -71,7 +71,11 @@ _wl_xdg_toplevel_configure_handler( if (resizing && movedEnough) { wl_window->pending_resize = true; - wl_window_set_size(wl_window,width,height); + //This check solves some issues when using the Ubuntu compositor while having decorations activated + if (wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_RIGHT || wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_LEFT) + wl_window->base.width = clip_i32_to_i16(width); + if (wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_TOP || wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM) + wl_window->base.height = clip_i32_to_i16(height); } } @@ -112,7 +116,7 @@ wl_window_create( } window->base.visible = false; - window->base.decorated = decorated; + window->base.decorated = false; window->base.x = clip_i32_to_i16(x); window->base.y = clip_i32_to_i16(y); window->base.width = clip_i32_to_i16(max(1, width)); From 6c9806586bc4060c970886cfbc212cff99e87b7a Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Wed, 22 Jun 2022 16:24:14 +0200 Subject: [PATCH 17/30] Removed dependency on the decoration close button, a dummy buffer is instead used --- src/implem/wayland/wl_window.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index e84708a7..3119146a 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -27,6 +27,7 @@ #include "wl_backend_internal.h" #include "wl_target.h" #include "wl_window_internal.h" +#include "wl_memory.h" @@ -210,8 +211,10 @@ wl_window_show( xdg_toplevel_add_listener(window->xdg_toplevel,&_wl_xdg_toplevel_listener,window); xdg_toplevel_set_title(window->xdg_toplevel,window->title); //Need to attach any buffer here... - if (window->base.decorated) - wl_surface_attach(window->wl_surface,window->decoration->wl_closebutton_buffer,0,0); + uint8_t *dummy_data = NULL; + struct wl_buffer *dummy = wl_create_buffer(1,1,&dummy_data); + munmap(dummy_data,4); + wl_surface_attach(window->wl_surface,dummy,0,0); wl_surface_commit(window->wl_surface); } _wl_window_update_position(window); From 0be4c718f010b72677ad4612afdf92f096e8a2fd Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Wed, 22 Jun 2022 17:20:06 +0200 Subject: [PATCH 18/30] Cursor changes in resize region --- src/implem/wayland/wl_backend.c | 89 +++++++++++++++++++++++++++------ src/implem/wayland/wl_window.c | 2 +- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index fd8a2ceb..63653783 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -40,13 +40,48 @@ wl_backend_t *wl_back = NULL; -int64_t _wl_get_time() +int64_t +_wl_get_time() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return ts.tv_sec/1000000 + ts.tv_nsec/(1000); } +void +_wl_find_resize_edge() +{ + const wl_fixed_t margin = 10 * 256; + uint32_t resizeEdge = XDG_TOPLEVEL_RESIZE_EDGE_NONE; + if (wl_back->focus_window->base.decorated && wl_back->inside_decor_location == DECOR_REGION_BAR && wl_back->mouse_posy < margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_TOP; + else if (!wl_back->focus_window->base.decorated && wl_back->mouse_posy < margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_TOP; + else if (!wl_back->inside_decor_location && wl_back->mouse_posy > wl_back->focus_window->base.height*256 - margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; + if (wl_back->mouse_posx < margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_LEFT; + else if (wl_back->mouse_posx > wl_back->focus_window->base.width*256 - margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; + wl_back->current_resize_edge = resizeEdge; +} + +void +_wl_change_cursor( + const char* cursorName +) +{ + wl_back->cursor = + wl_cursor_theme_get_cursor(wl_back->cursor_theme, cursorName); + wl_back->cursor_image = wl_back->cursor->images[0]; + wl_back->cursor_buffer = wl_cursor_image_get_buffer(wl_back->cursor_image); + wl_surface_attach(wl_back->cursor_surface, wl_back->cursor_buffer, 0, 0); + wl_surface_damage(wl_back->cursor_surface,0,0,24,24); + wl_surface_commit(wl_back->cursor_surface); +} + + + static void _wl_registry_global( void *data, @@ -183,6 +218,42 @@ _wl_pointer_motion_handler( evt.desc.cursor.x = x/256; evt.desc.cursor.y = y/256; event_notify(wl_back->listener, &evt); + _wl_find_resize_edge(); + //TODO : Make it change only if cursor actually changes + switch (wl_back->current_resize_edge) + { + case XDG_TOPLEVEL_RESIZE_EDGE_NONE: + _wl_change_cursor("left_ptr"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: + _wl_change_cursor("bottom_side"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP: + _wl_change_cursor("top_side"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT: + _wl_change_cursor("right_side"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_LEFT: + _wl_change_cursor("left_side"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT: + _wl_change_cursor("top_left_corner"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT: + _wl_change_cursor("top_right_corner"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT: + _wl_change_cursor("bottom_left_corner"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT: + _wl_change_cursor("bottom_right_corner"); + break; + default: + break; + } + + } } @@ -216,20 +287,10 @@ _wl_pointer_button_handler( { const wl_fixed_t margin = 5 * 256; uint32_t resizeEdge = XDG_TOPLEVEL_RESIZE_EDGE_NONE; - if (wl_back->focus_window->base.decorated && wl_back->inside_decor_location == DECOR_REGION_BAR && wl_back->mouse_posy < margin) - resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_TOP; - else if (!wl_back->focus_window->base.decorated && wl_back->mouse_posy < margin) - resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_TOP; - else if (!wl_back->inside_decor_location && wl_back->mouse_posy > wl_back->focus_window->base.height*256 - margin) - resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; - if (wl_back->mouse_posx < margin) - resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_LEFT; - else if (wl_back->mouse_posx > wl_back->focus_window->base.width*256 - margin) - resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; - wl_back->current_resize_edge = resizeEdge; - if (resizeEdge != XDG_TOPLEVEL_RESIZE_EDGE_NONE) + _wl_find_resize_edge(); + if (wl_back->current_resize_edge != XDG_TOPLEVEL_RESIZE_EDGE_NONE) { - xdg_toplevel_resize(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial,resizeEdge); + xdg_toplevel_resize(wl_back->focus_window->xdg_toplevel,wl_back->seat,serial,wl_back->current_resize_edge); } else if (wl_back->inside_decor_location == DECOR_REGION_BAR) { diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 3119146a..a5faab07 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -117,7 +117,7 @@ wl_window_create( } window->base.visible = false; - window->base.decorated = false; + window->base.decorated = decorated; window->base.x = clip_i32_to_i16(x); window->base.y = clip_i32_to_i16(y); window->base.width = clip_i32_to_i16(max(1, width)); From 5c7906d6e8705599a00bc57f032c0edc5e6dc603 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Thu, 23 Jun 2022 13:06:34 +0200 Subject: [PATCH 19/30] Backend stop, focus, middle mouse button --- src/implem/wayland/wl_backend.c | 93 ++++++++++++++---------- src/implem/wayland/wl_backend.h | 4 + src/implem/wayland/wl_backend_internal.h | 4 + src/implem/wayland/wl_window.c | 26 ++++++- 4 files changed, 88 insertions(+), 39 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 63653783..5906222c 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -219,39 +219,42 @@ _wl_pointer_motion_handler( evt.desc.cursor.y = y/256; event_notify(wl_back->listener, &evt); _wl_find_resize_edge(); - //TODO : Make it change only if cursor actually changes - switch (wl_back->current_resize_edge) + if (wl_back->current_resize_edge != wl_back->old_resize_edge) { - case XDG_TOPLEVEL_RESIZE_EDGE_NONE: - _wl_change_cursor("left_ptr"); - break; - case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: - _wl_change_cursor("bottom_side"); - break; - case XDG_TOPLEVEL_RESIZE_EDGE_TOP: - _wl_change_cursor("top_side"); - break; - case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT: - _wl_change_cursor("right_side"); - break; - case XDG_TOPLEVEL_RESIZE_EDGE_LEFT: - _wl_change_cursor("left_side"); - break; - case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT: - _wl_change_cursor("top_left_corner"); - break; - case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT: - _wl_change_cursor("top_right_corner"); - break; - case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT: - _wl_change_cursor("bottom_left_corner"); - break; - case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT: - _wl_change_cursor("bottom_right_corner"); - break; - default: - break; + switch (wl_back->current_resize_edge) + { + case XDG_TOPLEVEL_RESIZE_EDGE_NONE: + _wl_change_cursor("left_ptr"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: + _wl_change_cursor("bottom_side"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP: + _wl_change_cursor("top_side"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT: + _wl_change_cursor("right_side"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_LEFT: + _wl_change_cursor("left_side"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT: + _wl_change_cursor("top_left_corner"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT: + _wl_change_cursor("top_right_corner"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT: + _wl_change_cursor("bottom_left_corner"); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT: + _wl_change_cursor("bottom_right_corner"); + break; + default: + break; + } } + wl_back->old_resize_edge = wl_back->current_resize_edge; } @@ -273,9 +276,20 @@ _wl_pointer_button_handler( evt.type = EVENT_BUTTON; evt.time = _wl_get_time(); evt.target = wl_back->focus_window; - //TODO : Support other buttons - //TODO : Find a way to get RMB's code (is it always 272?) - evt.desc.button.button = (button == 272) ? BUTTON_LEFT : BUTTON_RIGHT; + switch (button) + { + case 272: + evt.desc.button.button = BUTTON_LEFT; + break; + case 273: + evt.desc.button.button = BUTTON_RIGHT; + break; + case 274: + evt.desc.button.button = BUTTON_MIDDLE; + break; + default: + break; + } evt.desc.button.state = (state == WL_POINTER_BUTTON_STATE_PRESSED) ? BUTTON_DOWN : BUTTON_UP; evt.desc.button.x = wl_back->mouse_posx / 256; evt.desc.button.y = wl_back->mouse_posy / 256; @@ -332,7 +346,12 @@ _wl_keyboard_enter_handler( { wl_backend_t *wl_back = (wl_backend_t *)data; if (surface) - wl_back->focus_window = wl_surface_get_user_data(surface); + { + if (wl_surface_get_user_data(surface) != wl_back->focus_window) + { + wl_back->focus_window = wl_surface_get_user_data(surface); + } + } else //happens for some reason when the window gets destroyed wl_back->focus_window = NULL; } @@ -344,7 +363,6 @@ _wl_keyboard_leave_handler( uint32_t serial, struct wl_surface *surface) { - wl_back->focus_window = NULL; } static void @@ -542,6 +560,7 @@ wl_backend_terminate( } wl_seat_release(wl_back->seat); wl_seat_destroy(wl_back->seat); + wl_subcompositor_destroy(wl_back->subcompositor); wl_compositor_destroy(wl_back->compositor); wl_registry_destroy(wl_back->registry); wl_display_roundtrip(wl_back->display); @@ -633,7 +652,7 @@ wl_backend_run( wl_back->running = true; - while (wl_display_dispatch(wl_back->display) >= 0) { + while (wl_display_dispatch(wl_back->display) >= 0 && wl_back->running) { //Events are handled separately. This loop is left empty on purpose. } diff --git a/src/implem/wayland/wl_backend.h b/src/implem/wayland/wl_backend.h index a3c5e69c..45ce22f6 100644 --- a/src/implem/wayland/wl_backend.h +++ b/src/implem/wayland/wl_backend.h @@ -22,6 +22,10 @@ typedef struct wl_backend_t wl_backend_t; +int64_t +_wl_get_time( + void); + bool wl_backend_init( void); diff --git a/src/implem/wayland/wl_backend_internal.h b/src/implem/wayland/wl_backend_internal.h index 6079145d..5fef4976 100644 --- a/src/implem/wayland/wl_backend_internal.h +++ b/src/implem/wayland/wl_backend_internal.h @@ -50,7 +50,10 @@ typedef struct wl_backend_t { struct wl_cursor_image *cursor_image; struct wl_buffer *cursor_buffer; struct wl_surface *cursor_surface; + //The focus window is the window where input will be relayed, it can differ from the activated window. wl_window_t *focus_window; + //The activated window is the "focused" window for the wayland server. + wl_window_t *activated_window; /*Keyboard objects*/ struct xkb_keymap *xkb_keymap; @@ -62,6 +65,7 @@ typedef struct wl_backend_t { wl_fixed_t mouse_posy; enum DECORATION_REGION inside_decor_location; enum xdg_toplevel_resize_edge current_resize_edge; + enum xdg_toplevel_resize_edge old_resize_edge; } wl_backend_t; extern wl_backend_t *wl_back; diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index a5faab07..9aa31612 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -30,7 +30,6 @@ #include "wl_memory.h" - static void _wl_window_update_position( wl_window_t *window) @@ -66,7 +65,30 @@ _wl_xdg_toplevel_configure_handler( printf("top level configure: %dx%d\n", width, height); uint8_t* p; bool resizing = false; - wl_array_for_each(p,states) if(*p == XDG_TOPLEVEL_STATE_RESIZING) resizing = true; + wl_array_for_each(p,states) + { + if(*p == XDG_TOPLEVEL_STATE_RESIZING) + resizing = true; + if (*p == XDG_TOPLEVEL_STATE_ACTIVATED) + { + if (wl_back->activated_window && wl_back->activated_window != wl_window) + { + event_t evt; + evt.desc.focus.inout = FOCUS_OUT; + evt.time = _wl_get_time(); + evt.target = wl_window; + evt.type = EVENT_FOCUS; + event_notify(wl_back->listener,&evt); + } + event_t evt; + evt.desc.focus.inout = FOCUS_IN; + evt.time = _wl_get_time(); + evt.target = wl_window; + evt.type = EVENT_FOCUS; + event_notify(wl_back->listener,&evt); + wl_back->activated_window = wl_window; + } + } bool movedEnough = abs(width - wl_window->base.width) > 10; movedEnough |= abs(height - wl_window->base.height) > 10; if (resizing && movedEnough) From 0d1860305833e0c16316f7d3849cde3bdc0f3a88 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Thu, 23 Jun 2022 14:31:06 +0200 Subject: [PATCH 20/30] Added XDG decoration protocol --- src/implem/wayland/xdg_decor_protocol.c | 75 +++++ src/implem/wayland/xdg_decor_protocol.h | 378 ++++++++++++++++++++++++ 2 files changed, 453 insertions(+) create mode 100644 src/implem/wayland/xdg_decor_protocol.c create mode 100644 src/implem/wayland/xdg_decor_protocol.h diff --git a/src/implem/wayland/xdg_decor_protocol.c b/src/implem/wayland/xdg_decor_protocol.c new file mode 100644 index 00000000..9c2d471c --- /dev/null +++ b/src/implem/wayland/xdg_decor_protocol.c @@ -0,0 +1,75 @@ +/* Generated by wayland-scanner 1.20.0 */ + +/* + * Copyright © 2018 Simon Ser + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface xdg_toplevel_interface; +extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; + +static const struct wl_interface *xdg_decoration_unstable_v1_types[] = { + NULL, + &zxdg_toplevel_decoration_v1_interface, + &xdg_toplevel_interface, +}; + +static const struct wl_message zxdg_decoration_manager_v1_requests[] = { + { "destroy", "", xdg_decoration_unstable_v1_types + 0 }, + { "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_decoration_manager_v1_interface = { + "zxdg_decoration_manager_v1", 1, + 2, zxdg_decoration_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = { + { "destroy", "", xdg_decoration_unstable_v1_types + 0 }, + { "set_mode", "u", xdg_decoration_unstable_v1_types + 0 }, + { "unset_mode", "", xdg_decoration_unstable_v1_types + 0 }, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_events[] = { + { "configure", "u", xdg_decoration_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_toplevel_decoration_v1_interface = { + "zxdg_toplevel_decoration_v1", 1, + 3, zxdg_toplevel_decoration_v1_requests, + 1, zxdg_toplevel_decoration_v1_events, +}; + diff --git a/src/implem/wayland/xdg_decor_protocol.h b/src/implem/wayland/xdg_decor_protocol.h new file mode 100644 index 00000000..be8879fe --- /dev/null +++ b/src/implem/wayland/xdg_decor_protocol.h @@ -0,0 +1,378 @@ +/* Generated by wayland-scanner 1.20.0 */ + +#ifndef XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_decoration_unstable_v1 The xdg_decoration_unstable_v1 protocol + * @section page_ifaces_xdg_decoration_unstable_v1 Interfaces + * - @subpage page_iface_zxdg_decoration_manager_v1 - window decoration manager + * - @subpage page_iface_zxdg_toplevel_decoration_v1 - decoration object for a toplevel surface + * @section page_copyright_xdg_decoration_unstable_v1 Copyright + *
+ *
+ * Copyright © 2018 Simon Ser
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct xdg_toplevel; +struct zxdg_decoration_manager_v1; +struct zxdg_toplevel_decoration_v1; + +#ifndef ZXDG_DECORATION_MANAGER_V1_INTERFACE +#define ZXDG_DECORATION_MANAGER_V1_INTERFACE +/** + * @page page_iface_zxdg_decoration_manager_v1 zxdg_decoration_manager_v1 + * @section page_iface_zxdg_decoration_manager_v1_desc Description + * + * This interface allows a compositor to announce support for server-side + * decorations. + * + * A window decoration is a set of window controls as deemed appropriate by + * the party managing them, such as user interface components used to move, + * resize and change a window's state. + * + * A client can use this protocol to request being decorated by a supporting + * compositor. + * + * If compositor and client do not negotiate the use of a server-side + * decoration using this protocol, clients continue to self-decorate as they + * see fit. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + * @section page_iface_zxdg_decoration_manager_v1_api API + * See @ref iface_zxdg_decoration_manager_v1. + */ +/** + * @defgroup iface_zxdg_decoration_manager_v1 The zxdg_decoration_manager_v1 interface + * + * This interface allows a compositor to announce support for server-side + * decorations. + * + * A window decoration is a set of window controls as deemed appropriate by + * the party managing them, such as user interface components used to move, + * resize and change a window's state. + * + * A client can use this protocol to request being decorated by a supporting + * compositor. + * + * If compositor and client do not negotiate the use of a server-side + * decoration using this protocol, clients continue to self-decorate as they + * see fit. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + */ +extern const struct wl_interface zxdg_decoration_manager_v1_interface; +#endif +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE +#define ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE +/** + * @page page_iface_zxdg_toplevel_decoration_v1 zxdg_toplevel_decoration_v1 + * @section page_iface_zxdg_toplevel_decoration_v1_desc Description + * + * The decoration object allows the compositor to toggle server-side window + * decorations for a toplevel surface. The client can request to switch to + * another mode. + * + * The xdg_toplevel_decoration object must be destroyed before its + * xdg_toplevel. + * @section page_iface_zxdg_toplevel_decoration_v1_api API + * See @ref iface_zxdg_toplevel_decoration_v1. + */ +/** + * @defgroup iface_zxdg_toplevel_decoration_v1 The zxdg_toplevel_decoration_v1 interface + * + * The decoration object allows the compositor to toggle server-side window + * decorations for a toplevel surface. The client can request to switch to + * another mode. + * + * The xdg_toplevel_decoration object must be destroyed before its + * xdg_toplevel. + */ +extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; +#endif + +#define ZXDG_DECORATION_MANAGER_V1_DESTROY 0 +#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION 1 + + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + */ +#define ZXDG_DECORATION_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_decoration_manager_v1 + */ +#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_decoration_manager_v1 */ +static inline void +zxdg_decoration_manager_v1_set_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_decoration_manager_v1, user_data); +} + +/** @ingroup iface_zxdg_decoration_manager_v1 */ +static inline void * +zxdg_decoration_manager_v1_get_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_decoration_manager_v1); +} + +static inline uint32_t +zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1); +} + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + * + * Destroy the decoration manager. This doesn't destroy objects created + * with the manager. + */ +static inline void +zxdg_decoration_manager_v1_destroy(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1, + ZXDG_DECORATION_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + * + * Create a new decoration object associated with the given toplevel. + * + * Creating an xdg_toplevel_decoration from an xdg_toplevel which has a + * buffer attached or committed is a client error, and any attempts by a + * client to attach or manipulate a buffer prior to the first + * xdg_toplevel_decoration.configure event must also be treated as + * errors. + */ +static inline struct zxdg_toplevel_decoration_v1 * +zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1, + ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, &zxdg_toplevel_decoration_v1_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), 0, NULL, toplevel); + + return (struct zxdg_toplevel_decoration_v1 *) id; +} + +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM +#define ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM +enum zxdg_toplevel_decoration_v1_error { + /** + * xdg_toplevel has a buffer attached before configure + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER = 0, + /** + * xdg_toplevel already has a decoration object + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED = 1, + /** + * xdg_toplevel destroyed before the decoration object + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED = 2, +}; +#endif /* ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM */ + +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM +#define ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * window decoration modes + * + * These values describe window decoration modes. + */ +enum zxdg_toplevel_decoration_v1_mode { + /** + * no server-side window decoration + */ + ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1, + /** + * server-side window decoration + */ + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2, +}; +#endif /* ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM */ + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * @struct zxdg_toplevel_decoration_v1_listener + */ +struct zxdg_toplevel_decoration_v1_listener { + /** + * suggest a surface change + * + * The configure event asks the client to change its decoration + * mode. The configured state should not be applied immediately. + * Clients must send an ack_configure in response to this event. + * See xdg_surface.configure and xdg_surface.ack_configure for + * details. + * + * A configure event can be sent at any time. The specified mode + * must be obeyed by the client. + * @param mode the decoration mode + */ + void (*configure)(void *data, + struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, + uint32_t mode); +}; + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +static inline int +zxdg_toplevel_decoration_v1_add_listener(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, + const struct zxdg_toplevel_decoration_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_decoration_v1, + (void (**)(void)) listener, data); +} + +#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY 0 +#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE 1 +#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE 2 + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_toplevel_decoration_v1 */ +static inline void +zxdg_toplevel_decoration_v1_set_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1, user_data); +} + +/** @ingroup iface_zxdg_toplevel_decoration_v1 */ +static inline void * +zxdg_toplevel_decoration_v1_get_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1); +} + +static inline uint32_t +zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Switch back to a mode without any server-side decorations at the next + * commit. + */ +static inline void +zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Set the toplevel surface decoration mode. This informs the compositor + * that the client prefers the provided decoration mode. + * + * After requesting a decoration mode, the compositor will respond by + * emitting an xdg_surface.configure event. The client should then update + * its content, drawing it without decorations if the received mode is + * server-side decorations. The client must also acknowledge the configure + * when committing the new content (see xdg_surface.ack_configure). + * + * The compositor can decide not to use the client's mode and enforce a + * different mode instead. + * + * Clients whose decoration mode depend on the xdg_toplevel state may send + * a set_mode request in response to an xdg_surface.configure event and wait + * for the next xdg_surface.configure event to prevent unwanted state. + * Such clients are responsible for preventing configure loops and must + * make sure not to send multiple successive set_mode requests with the + * same decoration mode. + */ +static inline void +zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0, mode); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Unset the toplevel surface decoration mode. This informs the compositor + * that the client doesn't prefer a particular decoration mode. + * + * This request has the same semantics as set_mode. + */ +static inline void +zxdg_toplevel_decoration_v1_unset_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0); +} + +#ifdef __cplusplus +} +#endif + +#endif From 7f0813462404f6f57a26ee1d610d883e759ad45d Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Thu, 23 Jun 2022 15:06:38 +0200 Subject: [PATCH 21/30] Added server side decorations --- src/implem/wayland/wl_backend.c | 43 ++++++++++++------- src/implem/wayland/wl_backend_internal.h | 2 + src/implem/wayland/wl_decoration.c | 2 +- src/implem/wayland/wl_window.c | 13 +++++- src/implem/wayland/wl_window_internal.h | 8 +++- ..._decor_protocol.c => xdg-decor-protocol.c} | 0 ..._decor_protocol.h => xdg-decor-protocol.h} | 0 7 files changed, 47 insertions(+), 21 deletions(-) rename src/implem/wayland/{xdg_decor_protocol.c => xdg-decor-protocol.c} (100%) rename src/implem/wayland/{xdg_decor_protocol.h => xdg-decor-protocol.h} (100%) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 5906222c..e4276b46 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -51,19 +51,25 @@ _wl_get_time() void _wl_find_resize_edge() { - const wl_fixed_t margin = 10 * 256; - uint32_t resizeEdge = XDG_TOPLEVEL_RESIZE_EDGE_NONE; - if (wl_back->focus_window->base.decorated && wl_back->inside_decor_location == DECOR_REGION_BAR && wl_back->mouse_posy < margin) - resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_TOP; - else if (!wl_back->focus_window->base.decorated && wl_back->mouse_posy < margin) - resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_TOP; - else if (!wl_back->inside_decor_location && wl_back->mouse_posy > wl_back->focus_window->base.height*256 - margin) - resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; - if (wl_back->mouse_posx < margin) - resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_LEFT; - else if (wl_back->mouse_posx > wl_back->focus_window->base.width*256 - margin) - resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; - wl_back->current_resize_edge = resizeEdge; + + if (wl_back->focus_window->base.decorated && HAS_SERVER_DECORATION) + { + wl_back->current_resize_edge = XDG_TOPLEVEL_RESIZE_EDGE_NONE; + return; + } + const wl_fixed_t margin = 10 * 256; + uint32_t resizeEdge = XDG_TOPLEVEL_RESIZE_EDGE_NONE; + if (wl_back->focus_window->base.decorated && wl_back->inside_decor_location == DECOR_REGION_BAR && wl_back->mouse_posy < margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_TOP; + else if (!wl_back->focus_window->base.decorated && wl_back->mouse_posy < margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_TOP; + else if (!wl_back->inside_decor_location && wl_back->mouse_posy > wl_back->focus_window->base.height*256 - margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; + if (wl_back->mouse_posx < margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_LEFT; + else if (wl_back->mouse_posx > wl_back->focus_window->base.width*256 - margin) + resizeEdge |= XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; + wl_back->current_resize_edge = resizeEdge; } void @@ -110,6 +116,9 @@ printf("Global: %s\n", interface); } else if (strcmp(interface, wl_subcompositor_interface.name) == 0) { wl_back->subcompositor = (struct wl_subcompositor*) wl_registry_bind(registry, id, &wl_subcompositor_interface,version); + } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { + wl_back->zxdg_decoration_manager_v1 = (struct zxdg_decoration_manager_v1*) + wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface,version); } } @@ -169,7 +178,7 @@ _wl_pointer_enter_handler( if (surface) { wl_back->focus_window = (wl_window_t*)wl_surface_get_user_data(surface); - if (wl_back->focus_window->base.decorated) + if (wl_back->focus_window->base.decorated && !HAS_SERVER_DECORATION) { if (surface == wl_back->focus_window->decoration->wl_surface) wl_back->inside_decor_location = DECOR_REGION_BAR; @@ -560,6 +569,8 @@ wl_backend_terminate( } wl_seat_release(wl_back->seat); wl_seat_destroy(wl_back->seat); + if (wl_back->zxdg_decoration_manager_v1) + zxdg_decoration_manager_v1_destroy(wl_back->zxdg_decoration_manager_v1); wl_subcompositor_destroy(wl_back->subcompositor); wl_compositor_destroy(wl_back->compositor); wl_registry_destroy(wl_back->registry); @@ -588,7 +599,7 @@ static void wl_callback_handle_frame( if (wl_window->pending_resize) { //resize decorations - if (wl_window->base.decorated) + if (wl_window->base.decorated && !HAS_SERVER_DECORATION) wl_decoration_resize(wl_window->decoration,wl_window->base.width,wl_window->title); //resize surface evt.desc.resize.width = wl_window->base.width; @@ -604,7 +615,7 @@ static void wl_callback_handle_frame( evt.target = (wl_window_t*)data; if (event_notify(wl_back->listener,&evt)) { - if (wl_window->base.decorated) + if (wl_window->base.decorated && !HAS_SERVER_DECORATION) wl_decoration_present(wl_window->decoration); evt.type = EVENT_PRESENT; event_notify(wl_back->listener,&evt); diff --git a/src/implem/wayland/wl_backend_internal.h b/src/implem/wayland/wl_backend_internal.h index 5fef4976..334abbf1 100644 --- a/src/implem/wayland/wl_backend_internal.h +++ b/src/implem/wayland/wl_backend_internal.h @@ -16,6 +16,7 @@ #include #include #include "xdg-shell-client-protocol.h" +#include "xdg-decor-protocol.h" #include #include "../hashtable.h" @@ -43,6 +44,7 @@ typedef struct wl_backend_t { struct wl_keyboard *keyboard; struct wl_shm *shm; struct xdg_wm_base *xdg_wm_base; + struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1; /* Objects */ struct wl_cursor_theme *cursor_theme; /* contains wl_cursors */ diff --git a/src/implem/wayland/wl_decoration.c b/src/implem/wayland/wl_decoration.c index 5f27814c..0726210a 100644 --- a/src/implem/wayland/wl_decoration.c +++ b/src/implem/wayland/wl_decoration.c @@ -74,7 +74,7 @@ _wl_decoration_render_title( uint32_t error = FT_Init_FreeType(&library); if (error) return; - error = FT_New_Face(library,"/usr/share/fonts/truetype/ubuntu/Ubuntu-B.ttf",0,&face); + error = FT_New_Face(library,"/home/hachem/Minchou.otf",0,&face); if (error) return; error = FT_Set_Pixel_Sizes(face,0,16); diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 9aa31612..0e4cdcad 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -21,6 +21,7 @@ #include #include "xdg-shell-client-protocol.h" +#include "xdg-decor-protocol.h" #include "../util.h" #include "wl_backend.h" @@ -30,6 +31,7 @@ #include "wl_memory.h" + static void _wl_window_update_position( wl_window_t *window) @@ -139,7 +141,7 @@ wl_window_create( } window->base.visible = false; - window->base.decorated = decorated; + window->base.decorated = false; window->base.x = clip_i32_to_i16(x); window->base.y = clip_i32_to_i16(y); window->base.width = clip_i32_to_i16(max(1, width)); @@ -150,7 +152,7 @@ wl_window_create( window->wl_surface = wl_compositor_create_surface(wl_back->compositor); wl_surface_set_user_data(window->wl_surface,window); - if (window->base.decorated) + if (window->base.decorated && !HAS_SERVER_DECORATION) { window->decoration = wl_decoration_create(window->wl_surface,width,title); wl_surface_set_user_data(window->decoration->wl_surface,window); @@ -169,6 +171,8 @@ wl_window_destroy( wl_callback_destroy(window->wl_callback); xdg_toplevel_destroy(window->xdg_toplevel); xdg_surface_destroy(window->xdg_surface); + if (window->server_decor) + zxdg_toplevel_decoration_v1_destroy(window->server_decor); if (window->base.decorated) wl_decoration_destroy(window->decoration); wl_surface_destroy(window->wl_surface); @@ -232,6 +236,11 @@ wl_window_show( window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface); xdg_toplevel_add_listener(window->xdg_toplevel,&_wl_xdg_toplevel_listener,window); xdg_toplevel_set_title(window->xdg_toplevel,window->title); + if (window->base.decorated && HAS_SERVER_DECORATION) + { + window->server_decor = zxdg_decoration_manager_v1_get_toplevel_decoration(wl_back->zxdg_decoration_manager_v1,window->xdg_toplevel); + zxdg_toplevel_decoration_v1_set_mode(window->server_decor,ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } //Need to attach any buffer here... uint8_t *dummy_data = NULL; struct wl_buffer *dummy = wl_create_buffer(1,1,&dummy_data); diff --git a/src/implem/wayland/wl_window_internal.h b/src/implem/wayland/wl_window_internal.h index 9d7983e3..30e3b248 100644 --- a/src/implem/wayland/wl_window_internal.h +++ b/src/implem/wayland/wl_window_internal.h @@ -13,10 +13,13 @@ #include #include "xdg-shell-client-protocol.h" - +#include "xdg-decor-protocol.h" #include "../window_internal.h" #include "wl_decoration.h" +#define HAS_SERVER_DECORATION (wl_back->zxdg_decoration_manager_v1 != NULL) + + typedef struct wl_window_t { /* Common to all windows */ @@ -30,8 +33,9 @@ typedef struct wl_window_t { const char *title; /*Client Side Decorations*/ - //TODO : Check if KDE is used before enabling this wl_decoration_t *decoration; + /*Server Side Decorations*/ + struct zxdg_toplevel_decoration_v1 *server_decor; bool pending_resize; } wl_window_t; diff --git a/src/implem/wayland/xdg_decor_protocol.c b/src/implem/wayland/xdg-decor-protocol.c similarity index 100% rename from src/implem/wayland/xdg_decor_protocol.c rename to src/implem/wayland/xdg-decor-protocol.c diff --git a/src/implem/wayland/xdg_decor_protocol.h b/src/implem/wayland/xdg-decor-protocol.h similarity index 100% rename from src/implem/wayland/xdg_decor_protocol.h rename to src/implem/wayland/xdg-decor-protocol.h From 437ee62f21d3639083ebce0367290699fe7db149 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Thu, 23 Jun 2022 15:07:25 +0200 Subject: [PATCH 22/30] Linking --- src/dune | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dune b/src/dune index c51b61c8..3512a857 100644 --- a/src/dune +++ b/src/dune @@ -15,7 +15,7 @@ gdi_keyboard gdi_backend gdi_target gdi_window gdi_surface qtz_keyboard qtz_backend qtz_target qtz_window qtz_surface x11_keysym x11_keyboard x11_backend x11_target x11_window x11_surface - wl_backend wl_memory wl_target wl_window wl_surface wl_decoration xdg-shell-protocol + wl_backend wl_memory wl_target wl_window wl_surface wl_decoration xdg-shell-protocol xdg-decor-protocol window surface path arc polygon polygonize poly_render font_desc gdi_font qtz_font ft_font font From d5c879af0f2099ab3f552ea6a11cb3f0f4a9551b Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Thu, 23 Jun 2022 15:26:30 +0200 Subject: [PATCH 23/30] Server side decoration fixes --- src/implem/wayland/wl_window.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 0e4cdcad..8a251e78 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -71,7 +71,7 @@ _wl_xdg_toplevel_configure_handler( { if(*p == XDG_TOPLEVEL_STATE_RESIZING) resizing = true; - if (*p == XDG_TOPLEVEL_STATE_ACTIVATED) + else if (*p == XDG_TOPLEVEL_STATE_ACTIVATED) { if (wl_back->activated_window && wl_back->activated_window != wl_window) { @@ -97,9 +97,9 @@ _wl_xdg_toplevel_configure_handler( { wl_window->pending_resize = true; //This check solves some issues when using the Ubuntu compositor while having decorations activated - if (wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_RIGHT || wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_LEFT) + if (wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_RIGHT || wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_LEFT || HAS_SERVER_DECORATION) wl_window->base.width = clip_i32_to_i16(width); - if (wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_TOP || wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM) + if (wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_TOP || wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM || HAS_SERVER_DECORATION) wl_window->base.height = clip_i32_to_i16(height); } } @@ -141,7 +141,7 @@ wl_window_create( } window->base.visible = false; - window->base.decorated = false; + window->base.decorated = decorated; window->base.x = clip_i32_to_i16(x); window->base.y = clip_i32_to_i16(y); window->base.width = clip_i32_to_i16(max(1, width)); @@ -173,7 +173,7 @@ wl_window_destroy( xdg_surface_destroy(window->xdg_surface); if (window->server_decor) zxdg_toplevel_decoration_v1_destroy(window->server_decor); - if (window->base.decorated) + if (window->base.decorated && !HAS_SERVER_DECORATION) wl_decoration_destroy(window->decoration); wl_surface_destroy(window->wl_surface); free(window); From 86f15be73372fc2651ad220a0444c2cb2c2b1f56 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Thu, 23 Jun 2022 17:37:56 +0200 Subject: [PATCH 24/30] Min Max buttons --- src/implem/wayland/wl_backend.c | 20 +++++++++- src/implem/wayland/wl_backend_internal.h | 5 +++ src/implem/wayland/wl_decoration.c | 49 +++++++++++++++++------- src/implem/wayland/wl_decoration.h | 8 ++++ src/implem/wayland/wl_window.c | 12 ++++++ 5 files changed, 80 insertions(+), 14 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index e4276b46..d25c3ae5 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -52,7 +52,7 @@ void _wl_find_resize_edge() { - if (wl_back->focus_window->base.decorated && HAS_SERVER_DECORATION) + if (wl_back->focus_window->base.decorated && HAS_SERVER_DECORATION || wl_back->inside_decor_location != DECOR_REGION_OUTSIDE && wl_back->inside_decor_location != DECOR_REGION_BAR) { wl_back->current_resize_edge = XDG_TOPLEVEL_RESIZE_EDGE_NONE; return; @@ -184,6 +184,10 @@ _wl_pointer_enter_handler( wl_back->inside_decor_location = DECOR_REGION_BAR; else if (surface == wl_back->focus_window->decoration->wl_closebutton_surface) wl_back->inside_decor_location = DECOR_REGION_CLOSE_BUTTON; + else if (surface == wl_back->focus_window->decoration->wl_maxbutton_surface) + wl_back->inside_decor_location = DECOR_REGION_MAX_BUTTON; + else if (surface == wl_back->focus_window->decoration->wl_minbutton_surface) + wl_back->inside_decor_location = DECOR_REGION_MIN_BUTTON; } else wl_back->inside_decor_location = DECOR_REGION_OUTSIDE; @@ -326,6 +330,20 @@ _wl_pointer_button_handler( evt.target = wl_back->focus_window; event_notify(wl_back->listener,&evt); } + else if (wl_back->inside_decor_location == DECOR_REGION_MIN_BUTTON) + { + xdg_toplevel_set_minimized(wl_back->focus_window->xdg_toplevel); + } + else if (wl_back->inside_decor_location == DECOR_REGION_MAX_BUTTON) + { + if (!wl_back->maximized) + xdg_toplevel_set_maximized(wl_back->focus_window->xdg_toplevel); + else + xdg_toplevel_unset_maximized(wl_back->focus_window->xdg_toplevel); + wl_back->maximized = !wl_back->maximized; + if (!wl_back->maximized) + wl_back->demaximize = true; + } } } diff --git a/src/implem/wayland/wl_backend_internal.h b/src/implem/wayland/wl_backend_internal.h index 334abbf1..ab9a27a9 100644 --- a/src/implem/wayland/wl_backend_internal.h +++ b/src/implem/wayland/wl_backend_internal.h @@ -26,6 +26,8 @@ enum DECORATION_REGION { DECOR_REGION_OUTSIDE = 0, DECOR_REGION_BAR = 1, DECOR_REGION_CLOSE_BUTTON = 2, + DECOR_REGION_MAX_BUTTON = 3, + DECOR_REGION_MIN_BUTTON = 4, }; typedef struct wl_backend_t { @@ -68,6 +70,9 @@ typedef struct wl_backend_t { enum DECORATION_REGION inside_decor_location; enum xdg_toplevel_resize_edge current_resize_edge; enum xdg_toplevel_resize_edge old_resize_edge; + bool maximized; + bool demaximize; + } wl_backend_t; extern wl_backend_t *wl_back; diff --git a/src/implem/wayland/wl_decoration.c b/src/implem/wayland/wl_decoration.c index 0726210a..70da865c 100644 --- a/src/implem/wayland/wl_decoration.c +++ b/src/implem/wayland/wl_decoration.c @@ -35,26 +35,32 @@ void -_wl_decoration_close_button( +_wl_decoration_button( wl_decoration_t *decor, - uint32_t size + struct wl_surface **surface, + struct wl_subsurface **subsurface, + struct wl_buffer **buffer, + uint32_t size, + uint8_t r, + uint8_t g, + uint8_t b ) { - decor->wl_closebutton_surface = wl_compositor_create_surface(wl_back->compositor); - decor->wl_closebutton_subsurface = wl_subcompositor_get_subsurface(wl_back->subcompositor, - decor->wl_closebutton_surface, + *surface = wl_compositor_create_surface(wl_back->compositor); + *subsurface = wl_subcompositor_get_subsurface(wl_back->subcompositor, + *surface, decor->wl_surface); uint8_t *data = NULL; - decor->wl_closebutton_buffer = wl_create_buffer(size,size,&data); + *buffer = wl_create_buffer(size,size,&data); for (int i = 0; i < size*size;i++) { - data[4*i] = 0; - data[4*i + 1] = 0; - data[4*i + 2] = 255; + data[4*i] = b; + data[4*i + 1] = g; + data[4*i + 2] = r; data[4*i + 3] = 255; } munmap(data,size * size * 4); - wl_surface_attach(decor->wl_closebutton_surface,decor->wl_closebutton_buffer,0,0); + wl_surface_attach(*surface,*buffer,0,0); } void @@ -84,9 +90,9 @@ _wl_decoration_render_title( while(*title) { uint32_t chr = decode_utf8_char(&title); - if (pen_x > width - 30 - 16) + if (pen_x > width - 30 - 16 - 70) break; - if (pen_x > width - 30 - 32) + if (pen_x > width - 30 - 32 - 70) chr = 0x0000002e; FT_UInt glyph_index; glyph_index = FT_Get_Char_Index(face,chr); @@ -180,8 +186,12 @@ wl_decoration_create( wl_surface_attach(decor->wl_surface,wl_buffer,0,0); wl_subsurface_set_position(decor->wl_subsurface,0,-_decor_height); decor->background_buffer = wl_buffer; - _wl_decoration_close_button(decor,30); + _wl_decoration_button(decor,&decor->wl_closebutton_surface,&decor->wl_closebutton_subsurface,&decor->wl_closebutton_buffer,30,255,0,0); wl_subsurface_set_position(decor->wl_closebutton_subsurface,width - 40,5); + _wl_decoration_button(decor,&decor->wl_maxbutton_surface,&decor->wl_maxbutton_subsurface,&decor->wl_maxbutton_buffer,30,0,255,0); + wl_subsurface_set_position(decor->wl_maxbutton_subsurface,width - 75,5); + _wl_decoration_button(decor,&decor->wl_minbutton_surface,&decor->wl_minbutton_subsurface,&decor->wl_minbutton_buffer,30,0,0,255); + wl_subsurface_set_position(decor->wl_minbutton_subsurface,width - 110,5); return decor; } @@ -195,6 +205,15 @@ wl_decoration_destroy( wl_buffer_destroy(decoration->wl_closebutton_buffer); wl_subsurface_destroy(decoration->wl_closebutton_subsurface); wl_surface_destroy(decoration->wl_closebutton_surface); + + wl_buffer_destroy(decoration->wl_minbutton_buffer); + wl_subsurface_destroy(decoration->wl_minbutton_subsurface); + wl_surface_destroy(decoration->wl_minbutton_surface); + + wl_buffer_destroy(decoration->wl_maxbutton_buffer); + wl_subsurface_destroy(decoration->wl_maxbutton_subsurface); + wl_surface_destroy(decoration->wl_maxbutton_surface); + wl_buffer_destroy(decoration->background_buffer); wl_subsurface_destroy(decoration->wl_subsurface); wl_surface_destroy(decoration->wl_surface); @@ -209,6 +228,8 @@ wl_decoration_present( { wl_surface_commit(decoration->wl_surface); wl_surface_commit(decoration->wl_closebutton_surface); + wl_surface_commit(decoration->wl_minbutton_surface); + wl_surface_commit(decoration->wl_maxbutton_surface); } @@ -223,6 +244,8 @@ wl_decoration_resize( decor->background_buffer = _wl_decoration_background(width,title); wl_surface_attach(decor->wl_surface,decor->background_buffer,0,0); wl_subsurface_set_position(decor->wl_closebutton_subsurface,width - 40,5); + wl_subsurface_set_position(decor->wl_maxbutton_subsurface,width - 75,5); + wl_subsurface_set_position(decor->wl_minbutton_subsurface,width - 110,5); } diff --git a/src/implem/wayland/wl_decoration.h b/src/implem/wayland/wl_decoration.h index a68a8fe3..c1b21309 100644 --- a/src/implem/wayland/wl_decoration.h +++ b/src/implem/wayland/wl_decoration.h @@ -28,6 +28,14 @@ typedef struct wl_decoration_t { struct wl_subsurface *wl_closebutton_subsurface; struct wl_buffer *wl_closebutton_buffer; + struct wl_surface *wl_minbutton_surface; + struct wl_subsurface *wl_minbutton_subsurface; + struct wl_buffer *wl_minbutton_buffer; + + struct wl_surface *wl_maxbutton_surface; + struct wl_subsurface *wl_maxbutton_subsurface; + struct wl_buffer *wl_maxbutton_buffer; + } wl_decoration_t; wl_decoration_t* diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 8a251e78..204b3b2f 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -67,10 +67,13 @@ _wl_xdg_toplevel_configure_handler( printf("top level configure: %dx%d\n", width, height); uint8_t* p; bool resizing = false; + bool maximizing = false; wl_array_for_each(p,states) { if(*p == XDG_TOPLEVEL_STATE_RESIZING) resizing = true; + else if (*p == XDG_TOPLEVEL_STATE_MAXIMIZED) + maximizing = true; else if (*p == XDG_TOPLEVEL_STATE_ACTIVATED) { if (wl_back->activated_window && wl_back->activated_window != wl_window) @@ -102,6 +105,13 @@ _wl_xdg_toplevel_configure_handler( if (wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_TOP || wl_back->current_resize_edge & XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM || HAS_SERVER_DECORATION) wl_window->base.height = clip_i32_to_i16(height); } + else if (maximizing || wl_back->demaximize) + { + wl_window->base.width = clip_i32_to_i16(width); + wl_window->base.height = clip_i32_to_i16(height); + wl_window->pending_resize = true; + wl_back->demaximize = false; + } } static void @@ -157,6 +167,8 @@ wl_window_create( window->decoration = wl_decoration_create(window->wl_surface,width,title); wl_surface_set_user_data(window->decoration->wl_surface,window); wl_surface_set_user_data(window->decoration->wl_closebutton_surface,window); + wl_surface_set_user_data(window->decoration->wl_minbutton_surface,window); + wl_surface_set_user_data(window->decoration->wl_maxbutton_surface,window); } wl_backend_add_window(window); From d14989a8c4d7a16b8ae826522a85be34d5f4f3c4 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Fri, 24 Jun 2022 15:39:42 +0200 Subject: [PATCH 25/30] Removed examples from wayland branch --- examples/Gradients.ml | 44 -------------------- examples/SimpleSnakeGame.ml | 83 ------------------------------------- examples/dune | 16 ------- 3 files changed, 143 deletions(-) delete mode 100644 examples/Gradients.ml delete mode 100644 examples/SimpleSnakeGame.ml diff --git a/examples/Gradients.ml b/examples/Gradients.ml deleted file mode 100644 index 8e1bb030..00000000 --- a/examples/Gradients.ml +++ /dev/null @@ -1,44 +0,0 @@ -open OcamlCanvas -open Float - - -let interpInt x1 x2 t = - int_of_float ((1. -. t)*.(float_of_int x1) +. t*.(float_of_int x2)) -let interpColor c1 c2 t = - let r1, g1, b1 = Color.to_rgb c1 and r2, g2, b2 = Color.to_rgb c2 in - Color.of_rgb (interpInt r1 r2 t) (interpInt g1 g2 t) (interpInt b1 b2 t) -let hsv_to_rgb h s v = - let c = v *. s in - let m = v -. c in - let x = c *. (1. -. abs( ( (rem (h /. 60.) 2.) -. 1.))) in - let r,g,b = match(h) with - |a when a < 60. -> c,x,0. - |a when a < 120. -> x,c,0. - |a when a < 180. -> 0.,c,x - |a when a < 240. -> 0.,x,c - |a when a < 300. -> x,0.,c - |_ -> c,0.,x - in Color.of_rgb (int_of_float((r +. m)*.255.)) (int_of_float((g +. m)*.255.)) (int_of_float((b +. m)*.255.)) - -open Int64 - -let () = - Backend.(init default_options); - let c = Canvas.createFramed "test" ~pos:(960-640,540-360) ~size:(1280,720) in - Canvas.setFillColor c Color.white; - Canvas.fillRect c ~pos:(0.,0.) ~size:(1280.,720.); - Canvas.show c; - let r = ref (-1.) in - Backend.run(function - |Frame { canvas = c; timestamp = _ } -> - r := !r +. 1. /. 60.; - Canvas.setFillColor c (hsv_to_rgb (!r *. 36.) 1. 1.); - Canvas.fillRect c ~pos:(128. *. !r,0.) ~size:(128., 360.); - Canvas.setFillColor c (interpColor Color.black Color.white (!r *. 0.1)); - Canvas.fillRect c ~pos:(128. *. !r,360.) ~size:(128., 360.); - true; - |_ -> - false; - )(function () -> - Printf.printf "Goodbye !\n" - ) \ No newline at end of file diff --git a/examples/SimpleSnakeGame.ml b/examples/SimpleSnakeGame.ml deleted file mode 100644 index b81e3b86..00000000 --- a/examples/SimpleSnakeGame.ml +++ /dev/null @@ -1,83 +0,0 @@ -open OcamlCanvas -open Int64 -open Random - -let buildBackground c = - Canvas.setFillColor c Color.black; - Canvas.fillRect c ~pos:(0.,0.) ~size:(500.,500.); - Canvas.setFillColor c Color.white; - Canvas.fillRect c ~pos:(0.,0.) ~size:(500.,10.); - Canvas.fillRect c ~pos:(0.,490.) ~size:(500.,10.); - Canvas.fillRect c ~pos:(0.,0.) ~size:(10.,500.); - Canvas.fillRect c ~pos:(490.,0.) ~size:(10.,500.); - () - -let placeBlock c (x,y) col = - Canvas.setFillColor c col; - Canvas.fillRect c ~pos:(x *. 10. , y *. 10.) ~size:(10.,10.); - () - -let rec drawSnake c s = match(s) with - |[] -> () - |h::t -> placeBlock c h Color.orange; drawSnake c t - -let rec moveSnake s p = match(s) with - |[] -> [] - |h::t -> p::(moveSnake t h) - -let sumCoord (a,b) (c,d) = (a +. c,b +. d) - -let moveSnakeDirection s d = match(s) with - |[] -> [] - |h::t -> moveSnake s (sumCoord d h) - -let snakeHitSelf s = match(s) with - |[] -> false - |h::t -> (List.mem h t) -let snakeHitWall s = let h::t = s in let (x,y) = h in (x < 1.) or (x > 48.) or (y < 1.) or (y > 48.) - - -let () = - Random.self_init(); - Backend.(init default_options); - let c = Canvas.createFramed "test" ~pos:(960-250,540-250) ~size:(500,500) in - Canvas.show c; - let r = ref (-1.) in - let snake = ref [(6.,8.);(6.,7.)] and currentDirection = ref (0.,1.) and foodLocation = ref(24.,24.) in - Backend.run(function - |KeyAction { canvas = c; timestamp = _; - key = KeyUpArrow; char; flags = _; state = Down } -> - let (x,y) = !currentDirection in - if (y = 0.) then currentDirection := (0.,-1.); - true; - |KeyAction { canvas = c; timestamp = _; - key = KeyDownArrow; char; flags = _; state = Down } -> - let (x,y) = !currentDirection in - if (y = 0.) then currentDirection := (0.,1.); - true; - |KeyAction { canvas = c; timestamp = _; - key = KeyLeftArrow; char; flags = _; state = Down } -> - let (x,y) = !currentDirection in - if (x = 0.) then currentDirection := (-1.,0.); - true; - |KeyAction { canvas = c; timestamp = _; - key = KeyRightArrow; char; flags = _; state = Down } -> - let (x,y) = !currentDirection in - if (x = 0.) then currentDirection := (1.,0.); - true; - - |Frame { canvas = c; timestamp = _ } -> - r := !r +. 1. /. 60.; - buildBackground c; - let h::t = !snake in - if ((sumCoord h !currentDirection) = !foodLocation) then (snake := !foodLocation::!snake; foodLocation := (2. +. float_of_int (Random.int 47),2. +. float_of_int (Random.int 47))); - if !r > 0.033 then (r := 0.; snake := moveSnakeDirection !snake !currentDirection); - if (snakeHitSelf !snake or snakeHitWall !snake) then Backend.stop(); - drawSnake c !snake; - placeBlock c !foodLocation Color.green; - true; - |_ -> - false; - )(function () -> - Printf.printf "Goodbye !\n" - ) \ No newline at end of file diff --git a/examples/dune b/examples/dune index 3ca013a6..70c20502 100644 --- a/examples/dune +++ b/examples/dune @@ -14,19 +14,3 @@ (modules test_canvas) (libraries ocaml-canvas) ) - -(executable - (name Gradients) - (public_name Gradients) - (modes byte_complete native js) - (modules Gradients) - (libraries ocaml-canvas) -) - -(executable - (name SimpleSnakeGame) - (public_name Snake) - (modes byte_complete native js) - (modules SimpleSnakeGame) - (libraries ocaml-canvas) -) From 9f80d01ad7ea7ff2484ff785a3f280765db7d8c9 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Mon, 27 Jun 2022 10:41:21 +0200 Subject: [PATCH 26/30] Refactored surface destruction --- src/implem/surface.c | 4 ++-- src/implem/wayland/wl_surface.c | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/implem/surface.c b/src/implem/surface.c index 131293fb..a55b3cae 100644 --- a/src/implem/surface.c +++ b/src/implem/surface.c @@ -138,7 +138,7 @@ surface_destroy( if (s->data) { switch_IMPL() { - case_WAYLAND(munmap(s->data,s->width * s->height * 4)); + case_WAYLAND(s->data = NULL;); default: free(s->data); break; @@ -197,7 +197,7 @@ surface_resize( _surface_copy_to_buffer(s, data, width, height); switch_IMPL() { - case_WAYLAND(munmap(s->data,s->width * s->height * 4)); + case_WAYLAND(s->data = NULL); default: free(s->data); break; diff --git a/src/implem/wayland/wl_surface.c b/src/implem/wayland/wl_surface.c index 992acca2..947304cb 100644 --- a/src/implem/wayland/wl_surface.c +++ b/src/implem/wayland/wl_surface.c @@ -38,6 +38,8 @@ typedef struct surface_impl_wl_t { impl_type_t type; struct wl_buffer *wl_buffer; struct wl_surface *wl_surface; + uint8_t *data; + uint32_t size; } surface_impl_wl_t; @@ -83,6 +85,8 @@ surface_create_wl_impl( impl->type = IMPL_WAYLAND; impl->wl_buffer = wl_buffer; impl->wl_surface = wl_target->wl_surface; + impl->data = pool_data; + impl->size = width * height * 4; *data = (color_t_ *)pool_data; return impl; @@ -97,7 +101,7 @@ surface_destroy_wl_impl( //Surface is attached to the window. Its destruction is left for the window destroy function wl_buffer_destroy(impl->wl_buffer); - + munmap(impl->data,impl->size); } @@ -163,6 +167,8 @@ surface_resize_wl_impl( munmap(*s_data,s_width * s_height * 4); wl_buffer_add_listener(newBuffer,&wl_buffer_listener,wl_surface_get_user_data(impl->wl_surface)); impl->wl_buffer = newBuffer; + impl->data = pool_data; + impl->size = d_width * d_height * 4; return true; } From fd06b920058e464eba897eb545e5da1015981acb Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Mon, 27 Jun 2022 10:59:14 +0200 Subject: [PATCH 27/30] Added asserts and the HAS_WAYLAND conditional to xdg-decor-protocol --- src/implem/wayland/wl_backend.c | 26 +++++++++++++++++++++++-- src/implem/wayland/wl_decoration.c | 14 +++++++++++++ src/implem/wayland/xdg-decor-protocol.c | 3 +++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index d25c3ae5..83c09a79 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -51,7 +51,6 @@ _wl_get_time() void _wl_find_resize_edge() { - if (wl_back->focus_window->base.decorated && HAS_SERVER_DECORATION || wl_back->inside_decor_location != DECOR_REGION_OUTSIDE && wl_back->inside_decor_location != DECOR_REGION_BAR) { wl_back->current_resize_edge = XDG_TOPLEVEL_RESIZE_EDGE_NONE; @@ -96,6 +95,8 @@ _wl_registry_global( const char *interface, uint32_t version) { + assert(data != NULL); + assert(registry != NULL); wl_backend_t *wl_back = (wl_backend_t *)data; @@ -168,6 +169,8 @@ _wl_pointer_enter_handler( wl_fixed_t x, wl_fixed_t y) { + assert(data != NULL); + assert(pointer != NULL); wl_backend_t *wl_back = (wl_backend_t *)data; wl_back->mouse_posx = x; wl_back->mouse_posy = y; @@ -208,6 +211,8 @@ _wl_pointer_leave_handler( uint32_t serial, struct wl_surface *surface) { + assert(data != NULL); + assert(pointer != NULL); wl_backend_t *wl_back = (wl_backend_t *)data; wl_back->inside_decor_location = DECOR_REGION_OUTSIDE; } @@ -220,6 +225,8 @@ _wl_pointer_motion_handler( wl_fixed_t x, wl_fixed_t y) { + assert(data != NULL); + assert(pointer != NULL); if (wl_back->focus_window && wl_back->focus_window->base.visible) { wl_backend_t *wl_back = (wl_backend_t *)data; wl_back->mouse_posx = x; @@ -282,6 +289,8 @@ _wl_pointer_button_handler( uint32_t button, uint32_t state) { + assert(pointer != NULL); + assert(data != NULL); //When the focus screen is hidden with a key down event for example, the key up event will still trigger. This check mitigates that. if (wl_back->focus_window && wl_back->focus_window->base.visible && !wl_back->inside_decor_location) { wl_backend_t *wl_back = (wl_backend_t *)data; @@ -371,6 +380,8 @@ _wl_keyboard_enter_handler( struct wl_array *keys ) { + assert(data != NULL); + assert(keyboard != NULL); wl_backend_t *wl_back = (wl_backend_t *)data; if (surface) { @@ -390,6 +401,8 @@ _wl_keyboard_leave_handler( uint32_t serial, struct wl_surface *surface) { + assert(data != NULL); + assert(keyboard != NULL); } static void @@ -402,6 +415,8 @@ _wl_keyboard_key_handler( enum wl_keyboard_key_state state ) { + assert(data != NULL); + assert(keyboard != NULL); if (wl_back->focus_window && wl_back->focus_window->base.visible) { wl_backend_t *wl_back = (wl_backend_t *)data; uint32_t pressedKeyCharacter = xkb_state_key_get_utf32(wl_back->xkb_state, key+8); @@ -425,6 +440,8 @@ _wl_keyboard_keymap_handler( uint32_t size ) { + assert(data != NULL); + assert(keyboard != NULL); assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); wl_backend_t *wl_back = (wl_backend_t *)data; @@ -452,6 +469,8 @@ _wl_keyboard_modifiers_handler( uint32_t group ) { + assert(data != NULL); + assert(wl_keyboard != NULL); wl_backend_t *wl_back = (wl_backend_t *)data; xkb_state_update_mask(wl_back->xkb_state, depressed, latched, locked, 0, 0, group); @@ -464,7 +483,8 @@ _wl_keyboard_repeat_info_handler( int32_t delay ) { - + assert(data != NULL); + assert(wl_keyboard != NULL); } @@ -607,6 +627,8 @@ static void wl_callback_handle_frame( struct wl_callback* wl_callback, uint32_t time) { + assert(data != NULL); + assert(wl_callback != NULL); struct wl_window_t *wl_window = data; if (wl_callback) { wl_callback_destroy(wl_callback); diff --git a/src/implem/wayland/wl_decoration.c b/src/implem/wayland/wl_decoration.c index 70da865c..408c6ddd 100644 --- a/src/implem/wayland/wl_decoration.c +++ b/src/implem/wayland/wl_decoration.c @@ -46,6 +46,14 @@ _wl_decoration_button( uint8_t b ) { + assert(decor != NULL); + assert (surface != NULL); + assert(*surface == NULL); + assert(subsurface != NULL); + assert(*subsurface == NULL); + assert(buffer != NULL); + assert(*buffer == NULL); + *surface = wl_compositor_create_surface(wl_back->compositor); *subsurface = wl_subcompositor_get_subsurface(wl_back->subcompositor, *surface, @@ -151,6 +159,7 @@ _wl_decoration_background( const char* title ) { + assert(title != NULL); uint32_t _decor_height = 40; uint8_t *pool_data = NULL; struct wl_buffer *wl_buffer = wl_create_buffer(width,_decor_height,&pool_data); @@ -173,6 +182,8 @@ wl_decoration_create( const char* title ) { + assert(parent != NULL); + assert(title != NULL); //TODO : Make this adapt to screen uint32_t _decor_height = 40; @@ -226,6 +237,8 @@ wl_decoration_present( wl_decoration_t* decoration ) { + assert(decoration != NULL); + assert(decoration->wl_surface != NULL); wl_surface_commit(decoration->wl_surface); wl_surface_commit(decoration->wl_closebutton_surface); wl_surface_commit(decoration->wl_minbutton_surface); @@ -240,6 +253,7 @@ wl_decoration_resize( const char* title ) { + assert(decor != NULL); wl_buffer_destroy(decor->background_buffer); decor->background_buffer = _wl_decoration_background(width,title); wl_surface_attach(decor->wl_surface,decor->background_buffer,0,0); diff --git a/src/implem/wayland/xdg-decor-protocol.c b/src/implem/wayland/xdg-decor-protocol.c index 9c2d471c..b336e44b 100644 --- a/src/implem/wayland/xdg-decor-protocol.c +++ b/src/implem/wayland/xdg-decor-protocol.c @@ -1,3 +1,5 @@ +#ifdef HAS_WAYLAND + /* Generated by wayland-scanner 1.20.0 */ /* @@ -73,3 +75,4 @@ WL_PRIVATE const struct wl_interface zxdg_toplevel_decoration_v1_interface = { 1, zxdg_toplevel_decoration_v1_events, }; +#endif /* HAS_WAYLAND */ \ No newline at end of file From 2fd0963f292da679def585e1582be3a7c6e5c877 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Mon, 27 Jun 2022 11:58:26 +0200 Subject: [PATCH 28/30] Modifiers + more fixes --- src/implem/wayland/wl_backend.c | 31 +++++++++++++++++++++++++++---- src/implem/wayland/wl_memory.h | 2 ++ src/implem/wayland/wl_window.c | 11 ++++++++--- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index 83c09a79..f8f4c9d4 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -45,11 +45,13 @@ _wl_get_time() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec/1000000 + ts.tv_nsec/(1000); + return ts.tv_sec*1000000 + ts.tv_nsec/(1000); } -void -_wl_find_resize_edge() +static void +_wl_find_resize_edge( + void +) { if (wl_back->focus_window->base.decorated && HAS_SERVER_DECORATION || wl_back->inside_decor_location != DECOR_REGION_OUTSIDE && wl_back->inside_decor_location != DECOR_REGION_BAR) { @@ -71,7 +73,7 @@ _wl_find_resize_edge() wl_back->current_resize_edge = resizeEdge; } -void +static void _wl_change_cursor( const char* cursorName ) @@ -417,6 +419,8 @@ _wl_keyboard_key_handler( { assert(data != NULL); assert(keyboard != NULL); + assert(wl_back->xkb_state != NULL); + if (wl_back->focus_window && wl_back->focus_window->base.visible) { wl_backend_t *wl_back = (wl_backend_t *)data; uint32_t pressedKeyCharacter = xkb_state_key_get_utf32(wl_back->xkb_state, key+8); @@ -427,6 +431,25 @@ _wl_keyboard_key_handler( evt.desc.key.code = sym_to_keycode[key]; evt.desc.key.char_ = pressedKeyCharacter; evt.desc.key.state = (state == WL_KEYBOARD_KEY_STATE_RELEASED) ? KEY_UP : KEY_DOWN; + + //modifiers + key_modifier_t mods = MOD_NONE; + if (xkb_state_mod_name_is_active(wl_back->xkb_state,XKB_MOD_NAME_SHIFT,XKB_STATE_MODS_EFFECTIVE)) + mods |= MOD_SHIFT; + if (xkb_state_mod_name_is_active(wl_back->xkb_state,XKB_MOD_NAME_NUM,XKB_STATE_MODS_EFFECTIVE)) + mods |= MOD_NUMLOCK; + if (xkb_state_mod_name_is_active(wl_back->xkb_state,XKB_MOD_NAME_CAPS,XKB_STATE_MODS_EFFECTIVE)) + mods |= MOD_CAPSLOCK; + if (xkb_state_mod_name_is_active(wl_back->xkb_state,XKB_MOD_NAME_ALT,XKB_STATE_MODS_EFFECTIVE)) + mods |= MOD_ALT; + if (xkb_state_mod_name_is_active(wl_back->xkb_state,XKB_MOD_NAME_CTRL,XKB_STATE_MODS_EFFECTIVE)) + mods |= MOD_CTRL; + if (xkb_state_mod_name_is_active(wl_back->xkb_state,XKB_MOD_NAME_LOGO,XKB_STATE_MODS_EFFECTIVE)) + mods |= MOD_META; + + evt.desc.key.modifiers = mods; + + event_notify(wl_back->listener,&evt); } } diff --git a/src/implem/wayland/wl_memory.h b/src/implem/wayland/wl_memory.h index 43c2fbaf..a2c7afe5 100644 --- a/src/implem/wayland/wl_memory.h +++ b/src/implem/wayland/wl_memory.h @@ -11,6 +11,8 @@ #ifndef __WL_MEMORY_H #define __WL_MEMORY_H +#include "stdint.h" + #include struct wl_buffer* wl_create_buffer( diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 204b3b2f..0accdcf7 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -24,6 +24,7 @@ #include "xdg-decor-protocol.h" #include "../util.h" +#include "../unicode.h" #include "wl_backend.h" #include "wl_backend_internal.h" #include "wl_target.h" @@ -31,7 +32,6 @@ #include "wl_memory.h" - static void _wl_window_update_position( wl_window_t *window) @@ -46,6 +46,8 @@ _wl_xdg_surface_configure( struct xdg_surface *xdg_surface, uint32_t serial) { + assert(data != NULL); + assert(xdg_surface != NULL); wl_window_t *window = (wl_window_t *)data; xdg_surface_ack_configure(xdg_surface, serial); } @@ -63,6 +65,8 @@ _wl_xdg_toplevel_configure_handler( int32_t height, struct wl_array *states) { + assert(data != NULL); + assert(xdg_toplevel != NULL); struct wl_window_t *wl_window = data; printf("top level configure: %dx%d\n", width, height); uint8_t* p; @@ -119,6 +123,8 @@ _wl_xdg_toplevel_close_handler( void *data, struct xdg_toplevel *xdg_toplevel) { + assert(data != NULL); + assert(xdg_toplevel != NULL); struct wl_window_t *wl_window = data; event_t evt; evt.type = EVENT_CLOSE; @@ -156,8 +162,7 @@ wl_window_create( window->base.y = clip_i32_to_i16(y); window->base.width = clip_i32_to_i16(max(1, width)); window->base.height = clip_i32_to_i16(max(1, height)); - - window->title = title; + window->title = strndup(title,strlen(title)); window->pending_resize = false; window->wl_surface = wl_compositor_create_surface(wl_back->compositor); From 6f39813575d4701eebc0e962c1a937f46f8a3491 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Mon, 27 Jun 2022 12:11:14 +0200 Subject: [PATCH 29/30] Refactored keyboard file --- src/dune | 2 +- src/implem/wayland/wl_backend.c | 2 +- src/implem/wayland/wl_keyboard.c | 114 +++++++++++++++++++++++++++++++ src/implem/wayland/wl_keyboard.h | 93 ++----------------------- 4 files changed, 121 insertions(+), 90 deletions(-) create mode 100644 src/implem/wayland/wl_keyboard.c diff --git a/src/dune b/src/dune index 3512a857..1b2609f4 100644 --- a/src/dune +++ b/src/dune @@ -15,7 +15,7 @@ gdi_keyboard gdi_backend gdi_target gdi_window gdi_surface qtz_keyboard qtz_backend qtz_target qtz_window qtz_surface x11_keysym x11_keyboard x11_backend x11_target x11_window x11_surface - wl_backend wl_memory wl_target wl_window wl_surface wl_decoration xdg-shell-protocol xdg-decor-protocol + wl_backend wl_memory wl_target wl_window wl_surface wl_decoration wl_keyboard xdg-shell-protocol xdg-decor-protocol window surface path arc polygon polygonize poly_render font_desc gdi_font qtz_font ft_font font diff --git a/src/implem/wayland/wl_backend.c b/src/implem/wayland/wl_backend.c index f8f4c9d4..45692d8e 100644 --- a/src/implem/wayland/wl_backend.c +++ b/src/implem/wayland/wl_backend.c @@ -428,7 +428,7 @@ _wl_keyboard_key_handler( evt.target = wl_back->focus_window; evt.time = _wl_get_time(); evt.type = EVENT_KEY; - evt.desc.key.code = sym_to_keycode[key]; + evt.desc.key.code = wl_translate_sym_to_keycode(key); evt.desc.key.char_ = pressedKeyCharacter; evt.desc.key.state = (state == WL_KEYBOARD_KEY_STATE_RELEASED) ? KEY_UP : KEY_DOWN; diff --git a/src/implem/wayland/wl_keyboard.c b/src/implem/wayland/wl_keyboard.c new file mode 100644 index 00000000..fd38f3ab --- /dev/null +++ b/src/implem/wayland/wl_keyboard.c @@ -0,0 +1,114 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifdef HAS_WAYLAND + +#include "wl_keyboard.h" + +key_code_t +wl_translate_sym_to_keycode( + uint8_t sym +) +{ + //TODO : Complete the list/ Test on other keyboards + const key_code_t sym_to_keycode[256] = + { + [1] = KEY_ESCAPE, + [59] = KEY_F1, + [60] = KEY_F2, + [61] = KEY_F3, + [62] = KEY_F4, + [63] = KEY_F5, + [64] = KEY_F6, + [65] = KEY_F7, + [66] = KEY_F8, + [67] = KEY_F9, + [68] = KEY_F10, + [87] = KEY_F11, + [88] = KEY_F12, + [99] = KEY_PRINTSCREEN, + [119] = KEY_PAUSE, + [41] = KEY_GRAVE_TILDE, + [2] = KEY_1_EXCLAMATION, + [3] = KEY_2_AT, + [4] = KEY_3_NUMBER, + [5] = KEY_4_DOLLAR, + [6] = KEY_5_PERCENT, + [7] = KEY_6_CARET, + [8] = KEY_7_AMPERSAND, + [9] = KEY_8_ASTERISK, + [10] = KEY_9_LPARENTHESIS, + [11] = KEY_0_RPARENTHESIS, + [12] = KEY_MINUS_UNDERSCORE, + [13] = KEY_EQUAL_PLUS, + [14] = KEY_BACKSPACE, + [15] = KEY_TAB, + [16] = KEY_Q, + [17] = KEY_W, + [18] = KEY_E, + [19] = KEY_R, + [20] = KEY_T, + [21] = KEY_Y, + [22] = KEY_U, + [23] = KEY_I, + [24] = KEY_O, + [25] = KEY_P, + [26] = KEY_LBRACKET_CURLY, + [27] = KEY_RBRACKET_CURLY, + [43] = KEY_BACKSLASH_PIPE, + [58] = KEY_CAPSLOCK, + [30] = KEY_A, + [31] = KEY_S, + [32] = KEY_D, + [33] = KEY_F, + [34] = KEY_G, + [35] = KEY_H, + [36] = KEY_J, + [37] = KEY_K, + [38] = KEY_L, + [39] = KEY_SEMICOLON_COLON, + [40] = KEY_QUOTE_DOUBLEQUOTE, + [28] = KEY_RETURN, + [42] = KEY_LSHIFT, + [44] = KEY_Z, + [45] = KEY_X, + [46] = KEY_C, + [47] = KEY_V, + [48] = KEY_B, + [49] = KEY_N, + [50] = KEY_M, + [51] = KEY_COMMA_LESS, + [52] = KEY_PERIOD_GREATER, + [53] = KEY_SLASH_QUESTION, + [54] = KEY_RSHIFT, + [29] = KEY_LCONTROL, + [56] = KEY_LALT, + [57] = KEY_SPACEBAR, + [100] = KEY_RALT, + [127] = KEY_MENU, + [97] = KEY_RCONTROL, + [110] = KEY_INSERT, + [102] = KEY_HOME, + [104] = KEY_PAGEUP, + [111] = KEY_DELETEFORWARD, + [107] = KEY_END, + [109] = KEY_PAGEDOWN, + [103] = KEY_UPARROW, + [105] = KEY_LEFTARROW, + [108] = KEY_DOWNARROW, + [106] = KEY_RIGHTARROW + }; + return sym_to_keycode[sym]; +} + + + + +#endif /*HAS_WAYLAND*/ \ No newline at end of file diff --git a/src/implem/wayland/wl_keyboard.h b/src/implem/wayland/wl_keyboard.h index be6862d3..93d007a7 100644 --- a/src/implem/wayland/wl_keyboard.h +++ b/src/implem/wayland/wl_keyboard.h @@ -12,93 +12,10 @@ #define __WL_KEYBOARD_H #include "../event.h" -//TODO : Complete the list/ Test on other keyboards -static const key_code_t sym_to_keycode[256] = -{ -[1] = KEY_ESCAPE, -[59] = KEY_F1, -[60] = KEY_F2, -[61] = KEY_F3, -[62] = KEY_F4, -[63] = KEY_F5, -[64] = KEY_F6, -[65] = KEY_F7, -[66] = KEY_F8, -[67] = KEY_F9, -[68] = KEY_F10, -[87] = KEY_F11, -[88] = KEY_F12, -[99] = KEY_PRINTSCREEN, -[119] = KEY_PAUSE, -[41] = KEY_GRAVE_TILDE, -[2] = KEY_1_EXCLAMATION, -[3] = KEY_2_AT, -[4] = KEY_3_NUMBER, -[5] = KEY_4_DOLLAR, -[6] = KEY_5_PERCENT, -[7] = KEY_6_CARET, -[8] = KEY_7_AMPERSAND, -[9] = KEY_8_ASTERISK, -[10] = KEY_9_LPARENTHESIS, -[11] = KEY_0_RPARENTHESIS, -[12] = KEY_MINUS_UNDERSCORE, -[13] = KEY_EQUAL_PLUS, -[14] = KEY_BACKSPACE, -[15] = KEY_TAB, -[16] = KEY_Q, -[17] = KEY_W, -[18] = KEY_E, -[19] = KEY_R, -[20] = KEY_T, -[21] = KEY_Y, -[22] = KEY_U, -[23] = KEY_I, -[24] = KEY_O, -[25] = KEY_P, -[26] = KEY_LBRACKET_CURLY, -[27] = KEY_RBRACKET_CURLY, -[43] = KEY_BACKSLASH_PIPE, -[58] = KEY_CAPSLOCK, -[30] = KEY_A, -[31] = KEY_S, -[32] = KEY_D, -[33] = KEY_F, -[34] = KEY_G, -[35] = KEY_H, -[36] = KEY_J, -[37] = KEY_K, -[38] = KEY_L, -[39] = KEY_SEMICOLON_COLON, -[40] = KEY_QUOTE_DOUBLEQUOTE, -[28] = KEY_RETURN, -[42] = KEY_LSHIFT, -[44] = KEY_Z, -[45] = KEY_X, -[46] = KEY_C, -[47] = KEY_V, -[48] = KEY_B, -[49] = KEY_N, -[50] = KEY_M, -[51] = KEY_COMMA_LESS, -[52] = KEY_PERIOD_GREATER, -[53] = KEY_SLASH_QUESTION, -[54] = KEY_RSHIFT, -[29] = KEY_LCONTROL, -[56] = KEY_LALT, -[57] = KEY_SPACEBAR, -[100] = KEY_RALT, -[127] = KEY_MENU, -[97] = KEY_RCONTROL, -[110] = KEY_INSERT, -[102] = KEY_HOME, -[104] = KEY_PAGEUP, -[111] = KEY_DELETEFORWARD, -[107] = KEY_END, -[109] = KEY_PAGEDOWN, -[103] = KEY_UPARROW, -[105] = KEY_LEFTARROW, -[108] = KEY_DOWNARROW, -[106] = KEY_RIGHTARROW -}; + +key_code_t +wl_translate_sym_to_keycode( + uint8_t sym +); #endif /* __WL_KEYBOARD_H */ \ No newline at end of file From b9ea6f3a694c1a20f11842bb4f862068517d2036 Mon Sep 17 00:00:00 2001 From: Hachem Ben Abdelbaki Date: Mon, 27 Jun 2022 13:42:55 +0200 Subject: [PATCH 30/30] Frameless window fix --- src/implem/wayland/wl_window.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/implem/wayland/wl_window.c b/src/implem/wayland/wl_window.c index 0accdcf7..5487dbcd 100644 --- a/src/implem/wayland/wl_window.c +++ b/src/implem/wayland/wl_window.c @@ -155,6 +155,10 @@ wl_window_create( if (window == NULL) { return NULL; } + + //Allows creation of frameless windows... + if (title == NULL) + title = ""; window->base.visible = false; window->base.decorated = decorated; @@ -162,7 +166,10 @@ wl_window_create( window->base.y = clip_i32_to_i16(y); window->base.width = clip_i32_to_i16(max(1, width)); window->base.height = clip_i32_to_i16(max(1, height)); - window->title = strndup(title,strlen(title)); + //Magic 256... + printf("%s\n",title); + window->title = strndup(title,256); + printf("%s\n",title); window->pending_resize = false; window->wl_surface = wl_compositor_create_surface(wl_back->compositor);