diff --git a/digesting_libdecor.c b/digesting_libdecor.c index a7fea02..4a258a0 100755 --- a/digesting_libdecor.c +++ b/digesting_libdecor.c @@ -376,7 +376,7 @@ border_component_reallocate(struct border_component *component, int w, int h){ component->wl_buffer = 0; } if (component->data != 0){ - munmap(component->data, component->data_size); + cmunmap(component->data, component->data_size); component->data = 0; } component->data_size = 0; diff --git a/wayland_egl.c b/wayland_egl.c index d33957c..ced3329 100755 --- a/wayland_egl.c +++ b/wayland_egl.c @@ -75,29 +75,78 @@ const struct xdg_wm_base_listener xdg_wm_base_listener = { xdg_wm_base_ping }; +#define SHADOW_MARGIN 20 +#define SHADOW_THICK 10 + static void pointer_enter(void *udata, struct wl_pointer *wl_pointer, uint32_t serial, - struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y){ + struct wl_surface *surface, wl_fixed_t fx, wl_fixed_t fy){ + int x = ctx.p[0] = wl_fixed_to_int(fx); + int y = ctx.p[1] = wl_fixed_to_int(fy); + ctx.hover = surface; + if (surface == ctx.main_wl_surface){ + printf("pointer_enter (main) %d,%d\n", x, y); + } + else if (surface == ctx.shadow_wl_surface){ + printf("pointer_enter (shadow) %d,%d\n", x, y); + } + else{ + printf("pointer_enter (unidentified) %d,%d\n", x, y); + ctx.hover = 0; + } + ctx.hover_serial = serial; } static void pointer_leave(void *udata, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface){ + if (surface == ctx.main_wl_surface){ + printf("pointer_leave (main)\n"); + } + else if (surface == ctx.shadow_wl_surface){ + printf("pointer_leave (shadow)\n"); + } + else{ + printf("pointer_leave (unidentified)\n"); + } + ctx.hover = 0; } static void pointer_motion(void *udata, struct wl_pointer *wl_pointer, uint32_t time, - wl_fixed_t surface_x, wl_fixed_t surface_y){ + wl_fixed_t fx, wl_fixed_t fy){ + int x = ctx.p[0] = wl_fixed_to_int(fx); + int y = ctx.p[1] = wl_fixed_to_int(fy); + printf("pointer_motion %d,%d\n", x, y); } static void pointer_button(void *udata, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state){ + char *state_str = (state == 1?"press":"release"); + if (button == BTN_LEFT){ + printf("pointer_button (left) %s\n", state_str); + } + else if (button == BTN_RIGHT){ + printf("pointer_button (right) %s\n", state_str); + } + else if (button == BTN_MIDDLE){ + printf("pointer_button (middle) %s\n", state_str); + } + else{ + printf("pointer_button (unidentified) %s\n", state_str); + } + if (state){ + ctx.button = button; + ctx.button_serial = serial; + } } static void pointer_axis(void *udata, struct wl_pointer *wl_pointer, - uint32_t time, uint32_t axis, wl_fixed_t value){ + uint32_t time, uint32_t axis, wl_fixed_t fv){ + int v = wl_fixed_to_int(fv); + printf("pointer_axis %u,%d\n", axis, v); } const struct wl_pointer_listener pointer_listener = { @@ -287,10 +336,10 @@ int main(){ ctx.main_xdg_toplevel = xdg_surface_get_toplevel(ctx.main_xdg_surface); xdg_toplevel_add_listener(ctx.main_xdg_toplevel, &xdg_toplevel_listener, 0); - ctx.config.dim[0] = 640; - ctx.config.dim[1] = 480; ctx.control_flags = ~0; + ctx.dim[0] = 640; + ctx.dim[1] = 480; ctx.config_staged.decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; if (ctx.zxdg_decoration_manager != 0){ ctx.main_zxdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(ctx.zxdg_decoration_manager, ctx.main_xdg_toplevel); @@ -313,37 +362,9 @@ int main(){ ctx.shadow_wl_surface, ctx.main_wl_surface); - { - int dim[2] = {640, 25}; - - int stride = 4*dim[0]; - uint64_t size = 4*dim[0]*dim[1]; - - int fd = os_create_anonymous_file(size); - if (fd >= 0){ - void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (data != MAP_FAILED){ - struct wl_shm_pool *pool = wl_shm_create_pool(ctx.wl_shm, fd, size); - struct wl_buffer *wl_buffer = wl_shm_pool_create_buffer(pool, 0, dim[0], dim[1], stride, - WL_SHM_FORMAT_ARGB8888); - wl_shm_pool_destroy(pool); - - ctx.shadow_wl_buffer = wl_buffer; - ctx.shadow_data = data; - ctx.shadow_size = size; - for (int i = 0; i < 2; i += 1){ - ctx.shadow_dim[i] = dim[i]; - } - } - - close(fd); - } - } - /* window egl */ ctx.main_wl_egl_window = wl_egl_window_create(ctx.main_wl_surface, - ctx.config.dim[0], - ctx.config.dim[1]); + ctx.dim[0], ctx.dim[1]); EGLConfig configs[64]; EGLint config_cap = sizeof(configs)/sizeof(*configs); @@ -434,61 +455,180 @@ int main(){ /* window sizing */ CSD_Frame csd_frame = {0}; - int32_t csd_dim[2]; + int32_t csd_dim[2] = {0}; { if (csd){ csd_frame = csd_impl_calculate_frame(); } for (int i = 0; i < 2; i += 1){ csd_dim[i] = csd_frame.border[i][0] + csd_frame.border[i][1]; + } + for (int i = 0; i < 2; i += 1){ int32_t d = ctx.config.dim[i] - csd_dim[i]; + if (!ctx.handled_first_size){ + d = ctx.dim[i]; + ctx.config.dim[i] = d + csd_dim[i]; + } d = ClampBot(d, ctx.mmbox[i][0]); d = ClampTop(d, ctx.mmbox[i][1]); d = ClampBot(d, csd_frame.minbox[i]); ctx.dim[i] = d; } + ctx.handled_first_size = 1; } - /* window frame render */ - if (csd){ - uint32_t *pxl = (uint32_t*)ctx.shadow_data; - for (int32_t y = 0; y < ctx.shadow_dim[1]; y += 1){ - for (int32_t x = 0; x < ctx.shadow_dim[0]; x += 1){ - *pxl = 0xFFFF0000; - pxl += 1; + /* frame cursor & interaction */ + CursorShape cursor_shape = CursorShape_Pointer; + if (ctx.control_flags & WindowControlFlag_Resize){ + static const CursorShape cursor_box[] = { + CursorShape_Resize_TopLeft, CursorShape_Resize_Top, CursorShape_Resize_TopRight, + CursorShape_Resize_Left, CursorShape_Pointer, CursorShape_Resize_Right, + CursorShape_Resize_BottomLeft, CursorShape_Resize_Bottom, CursorShape_Resize_BottomRight, + }; + + static const enum xdg_toplevel_resize_edge xedge_box[] = { + XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT, XDG_TOPLEVEL_RESIZE_EDGE_TOP, XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT, + XDG_TOPLEVEL_RESIZE_EDGE_LEFT, XDG_TOPLEVEL_RESIZE_EDGE_NONE, XDG_TOPLEVEL_RESIZE_EDGE_RIGHT, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT, + }; + + int l = (ctx.p[0] < SHADOW_MARGIN); + int r = (!l && ctx.p[0] >= ctx.dim[0] + SHADOW_MARGIN); + int t = (ctx.p[1] < SHADOW_MARGIN); + int b = (!t && ctx.p[1] >= ctx.dim[1] + SHADOW_MARGIN); + int loc = 3*(b - t) + (r - l); + cursor_shape = cursor_box[4 + loc]; + if (ctx.button == BTN_LEFT){ + ctx.button = 0; + if (loc != 0){ + xdg_toplevel_resize(ctx.main_xdg_toplevel, ctx.wl_seat, + ctx.button_serial, xedge_box[4 + loc]); + } + else{ + xdg_toplevel_move(ctx.main_xdg_toplevel, ctx.wl_seat, + ctx.button_serial); } } } - /* window frame commit */ + /* window frame render */ if (csd){ + if (ctx.shadow_data != 0){ + munmap(ctx.shadow_data, ctx.shadow_size); + ctx.shadow_data = 0; + } + if (ctx.shadow_wl_buffer != 0){ + wl_buffer_destroy(ctx.shadow_wl_buffer); + ctx.shadow_wl_buffer = 0; + } + + { + int dim[2]; + for (int i = 0; i < 2; i += 1){ + dim[i] = ctx.dim[i] + SHADOW_MARGIN*2; + } + + int stride = 4*dim[0]; + uint64_t size = 4*dim[0]*dim[1]; + + int fd = os_create_anonymous_file(size); + if (fd >= 0){ + void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data != MAP_FAILED){ + struct wl_shm_pool *pool = wl_shm_create_pool(ctx.wl_shm, fd, size); + struct wl_buffer *wl_buffer = + wl_shm_pool_create_buffer(pool, 0, dim[0], dim[1], + stride, WL_SHM_FORMAT_ARGB8888); + wl_shm_pool_destroy(pool); + + ctx.shadow_wl_buffer = wl_buffer; + ctx.shadow_data = data; + ctx.shadow_size = size; + for (int i = 0; i < 2; i += 1){ + ctx.shadow_dim[i] = dim[i]; + } + } + + close(fd); + } + } + + uint32_t *pxl = (uint32_t*)ctx.shadow_data; + for (int32_t y = 0; y < ctx.shadow_dim[1]; y += 1){ + for (int32_t x = 0; x < ctx.shadow_dim[0]; x += 1){ + *pxl = 0; + + { + int x0 = SHADOW_MARGIN - SHADOW_THICK; + int y0 = SHADOW_MARGIN - SHADOW_THICK; + int x1 = x0 + ctx.dim[0] + SHADOW_THICK*2; + int y1 = y0 + ctx.dim[1] + SHADOW_THICK*2; + + if (x0 <= x && x < x1 && y0 <= y && y < y1){ + int xd0 = x - x0; + int xd1 = x1 - x - 1; + int yd0 = y - y0; + int yd1 = y1 - y - 1; + int d = Min(Min(xd0, xd1), Min(yd0, yd1)); + + if (d < SHADOW_THICK){ + int c = d*0xFF/SHADOW_THICK; + ((uint8_t*)pxl)[0] = 0; + ((uint8_t*)pxl)[1] = 0; + ((uint8_t*)pxl)[2] = 0; + ((uint8_t*)pxl)[3] = c; + } + } + } + pxl += 1; + } + } + + { + struct wl_region *region = wl_compositor_create_region(ctx.wl_compositor); + wl_region_add(region, 0, 0, ctx.shadow_dim[0], ctx.shadow_dim[1]); + wl_region_subtract(region, SHADOW_MARGIN, SHADOW_MARGIN, + ctx.dim[0], ctx.dim[1]); + wl_surface_set_input_region(ctx.shadow_wl_surface, region); + wl_region_destroy(region); + } + { wl_surface_attach(ctx.shadow_wl_surface, ctx.shadow_wl_buffer, 0, 0); wl_surface_set_buffer_scale(ctx.shadow_wl_surface, 1); wl_surface_damage_buffer(ctx.shadow_wl_surface, 0, 0, ctx.shadow_dim[0], ctx.shadow_dim[1]); - wl_subsurface_set_position(ctx.shadow_wl_subsurface, 0, -25); + wl_subsurface_set_position(ctx.shadow_wl_subsurface, -SHADOW_MARGIN, -SHADOW_MARGIN); wl_surface_commit(ctx.shadow_wl_surface); } - - if (!(ctx.control_flags & WindowControlFlag_Resize)){ - xdg_toplevel_set_min_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]); - xdg_toplevel_set_max_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]); - } - else{ - for (int i = 0; i < 2; i += 1){ - int32_t mw = ClampBot(ctx.mmbox[0][i], csd_frame.minbox[i]) + csd_dim[0]; - int32_t mh = ctx.mmbox[1][i] + csd_dim[1]; - if (i == 0){ - xdg_toplevel_set_min_size(ctx.main_xdg_toplevel, mw, mh); - } - else{ - xdg_toplevel_set_max_size(ctx.main_xdg_toplevel, mw, mh); - } + } + + /* window frame commit */ + if (!(ctx.control_flags & WindowControlFlag_Resize)){ + xdg_toplevel_set_min_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]); + xdg_toplevel_set_max_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]); + } + else{ + for (int i = 0; i < 2; i += 1){ + int32_t mw = ClampBot(ctx.mmbox[0][i], csd_frame.minbox[i]) + csd_dim[0]; + int32_t mh = ctx.mmbox[1][i] + csd_dim[1]; + if (i == 0){ + xdg_toplevel_set_min_size(ctx.main_xdg_toplevel, mw, mh); + } + else{ + xdg_toplevel_set_max_size(ctx.main_xdg_toplevel, mw, mh); } } } + xdg_surface_set_window_geometry(ctx.main_xdg_surface, + -csd_frame.border[0][0], + -csd_frame.border[1][0], + ctx.dim[0] + csd_dim[0], + ctx.dim[1] + csd_dim[1]); + + wl_egl_window_resize(ctx.main_wl_egl_window, ctx.dim[0], ctx.dim[1], 0, 0); + /* app update & render */ { if (ctx.close_signal){ @@ -496,13 +636,29 @@ int main(){ } glDrawBuffer(GL_BACK); - glViewport(0, 0, ctx.config.dim[0], ctx.config.dim[1]); + glViewport(0, 0, ctx.dim[0], ctx.dim[1]); glClearColor(0.40f, 0.90f, 0.15f, 1.f); glClear(GL_COLOR_BUFFER_BIT); } - eglSwapBuffers(ctx.egl_display, ctx.main_egl_surface); wl_surface_commit(ctx.main_wl_surface); + + /* commit new cursor */ + { + struct wl_cursor *cursor = ctx.wl_cursors[cursor_shape]; + if (cursor != 0){ + struct wl_cursor_image *cursor_image = cursor->images[0]; + struct wl_buffer *cursor_buffer = wl_cursor_image_get_buffer(cursor_image); + wl_surface_set_buffer_scale(ctx.cursor_surface, 1); + wl_surface_attach(ctx.cursor_surface, cursor_buffer, 0, 0); + wl_surface_damage_buffer(ctx.cursor_surface, 0, 0, + cursor_image->width, cursor_image->height); + wl_surface_commit(ctx.cursor_surface); + wl_pointer_set_cursor(ctx.wl_pointer, ctx.hover_serial, ctx.cursor_surface, + cursor_image->hotspot_x, cursor_image->hotspot_y); + } + } + } return(0); @@ -515,7 +671,11 @@ csd_impl_calculate_frame(void){ CSD_Frame frame = {0}; bool show_title = (!(ctx.config.flags & WindowFlag_IsFullscreen)); if (show_title){ - frame.border[1][0] = 25; + for (int i = 0; i < 2; i += 1){ + for (int j = 0; j < 2; j += 1){ + frame.border[i][j] = SHADOW_MARGIN; + } + } } return(frame); } diff --git a/wayland_egl.h b/wayland_egl.h index 0922776..df5cb69 100644 --- a/wayland_egl.h +++ b/wayland_egl.h @@ -22,7 +22,9 @@ typedef struct CursorTheme{ int size; } CursorTheme; +typedef uint32_t CursorShape; enum{ + CursorShape_Hidden, CursorShape_Pointer, CursorShape_Resize_Top, CursorShape_Resize_Bottom, @@ -125,6 +127,13 @@ typedef struct Ctx{ Config config_staged; int32_t mmbox[2][2]; // [0][]:x [1][]:y [][0]:min [][1]:max int32_t dim[2]; + + uint32_t hover_serial; + uint32_t button_serial; + struct wl_surface *hover; + int32_t p[2]; + uint32_t button; + int handled_first_size; } Ctx;