[digesting_libdecor] swap out with fixed component indexes

main
Allen Webster 2026-02-28 11:34:43 -08:00
parent 4f8388f544
commit e0498157b9
2 changed files with 269 additions and 441 deletions

View File

@ -105,8 +105,8 @@ pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
seat->pointer_focus = surface;
if (own_proxy(surface)){
ctx.active = border_component_from_wl_surface(surface);
if (ctx.active){
ctx.active = component_slot_from_wl_surface(surface);
if (ctx.active != 0){
draw_decoration();
wl_surface_commit(ctx.wl_surface);
}
@ -116,15 +116,10 @@ pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
struct wl_cursor_image *image = seat->current_cursor->images[0];
struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
wl_surface_attach(seat->cursor_surface, buffer, 0, 0);
wl_surface_set_buffer_scale(seat->cursor_surface, seat->cursor_scale);
wl_surface_damage_buffer(seat->cursor_surface, 0, 0,
image->width * seat->cursor_scale,
image->height * seat->cursor_scale);
wl_surface_set_buffer_scale(seat->cursor_surface, 1);
wl_surface_damage_buffer(seat->cursor_surface, 0, 0, image->width, image->height);
wl_surface_commit(seat->cursor_surface);
wl_pointer_set_cursor(seat->wl_pointer, seat->serial,
seat->cursor_surface,
image->hotspot_x / seat->cursor_scale,
image->hotspot_y / seat->cursor_scale);
wl_pointer_set_cursor(seat->wl_pointer, seat->serial, seat->cursor_surface, image->hotspot_x, image->hotspot_y);
}
}
}
@ -162,20 +157,15 @@ pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time,
struct wl_cursor_image *image = seat->current_cursor->images[0];
struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
wl_surface_attach(seat->cursor_surface, buffer, 0, 0);
wl_surface_set_buffer_scale(seat->cursor_surface, seat->cursor_scale);
wl_surface_damage_buffer(seat->cursor_surface, 0, 0,
image->width * seat->cursor_scale,
image->height * seat->cursor_scale);
wl_surface_set_buffer_scale(seat->cursor_surface, 1);
wl_surface_damage_buffer(seat->cursor_surface, 0, 0, image->width, image->height);
wl_surface_commit(seat->cursor_surface);
wl_pointer_set_cursor(seat->wl_pointer, seat->serial,
seat->cursor_surface,
image->hotspot_x / seat->cursor_scale,
image->hotspot_y / seat->cursor_scale);
wl_pointer_set_cursor(seat->wl_pointer, seat->serial, seat->cursor_surface, image->hotspot_x, image->hotspot_y);
}
}
/* avoid warnings after decoration has been turned off */
if (!GTK_IS_WIDGET(ctx.header) || ctx.active->type != HEADER){
if (!GTK_IS_WIDGET(ctx.header) || ctx.active != COMPONENT_SLOT_HEADER){
ctx.hdr_focus.type = HEADER_NONE;
}
@ -191,18 +181,14 @@ pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time,
draw_title_bar();
wl_surface_commit(ctx.wl_surface);
switch (ctx.titlebar_gesture.state) {
case TITLEBAR_GESTURE_STATE_BUTTON_PRESSED:
if (ctx.titlebar_gesture.state == TITLEBAR_GESTURE_STATE_BUTTON_PRESSED){
if (ctx.titlebar_gesture.first_pressed_button == BTN_LEFT){
if (ABS((double)seat->pointer_x - (double)ctx.titlebar_gesture.pressed_x) > ctx.drag_threshold ||
ABS((double)seat->pointer_y - (double)ctx.titlebar_gesture.pressed_y) > ctx.drag_threshold){
xdg_toplevel_move(ctx.xdg_toplevel, seat->wl_seat, ctx.titlebar_gesture.pressed_serial);
int xd = ABS(seat->pointer_x - ctx.titlebar_gesture.pressed_x);
int yd = ABS(seat->pointer_y - ctx.titlebar_gesture.pressed_y);
if (xd > ctx.drag_threshold || yd > ctx.drag_threshold){
xdg_toplevel_move(ctx.xdg_toplevel, seat->wl_seat, ctx.titlebar_gesture.serial);
}
}
case TITLEBAR_GESTURE_STATE_INIT:
case TITLEBAR_GESTURE_STATE_CONSUMED:
case TITLEBAR_GESTURE_STATE_DISCARDED:
break;
}
}
}
@ -212,17 +198,16 @@ pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
uint32_t time, uint32_t button, uint32_t state){
struct seat *seat = data;
if (seat->pointer_focus && own_proxy(seat->pointer_focus)){
switch (ctx.active->type) {
case SHADOW: {
enum libdecor_resize_edge edge =
component_edge(ctx.active, seat->pointer_x, seat->pointer_y, SHADOW_MARGIN);
switch (ctx.active){
case COMPONENT_SLOT_SHADOW: {
enum libdecor_resize_edge edge = component_edge(COMPONENT_SLOT_SHADOW, seat->pointer_x, seat->pointer_y);
if (edge != LIBDECOR_RESIZE_EDGE_NONE &&
(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){
libdecor_frame_resize(seat->wl_seat, serial, edge);
xdg_toplevel_resize(ctx.xdg_toplevel, seat->wl_seat, serial, xdg_edge_from_edge(edge));
}
}break;
case HEADER: {
case COMPONENT_SLOT_HEADER: {
switch (ctx.titlebar_gesture.state){
case TITLEBAR_GESTURE_STATE_INIT: {
if (state == WL_POINTER_BUTTON_STATE_PRESSED){
@ -245,7 +230,7 @@ pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
ctx.titlebar_gesture.first_pressed_time = time;
ctx.titlebar_gesture.pressed_x = seat->pointer_x;
ctx.titlebar_gesture.pressed_y = seat->pointer_y;
ctx.titlebar_gesture.pressed_serial = serial;
ctx.titlebar_gesture.serial = serial;
ctx.titlebar_gesture.state = TITLEBAR_GESTURE_STATE_BUTTON_PRESSED;
}
}
@ -361,7 +346,7 @@ touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial,
if (surface != 0 && own_proxy(surface)){
seat->touch_focus = surface;
ctx.touch_active = border_component_from_wl_surface(surface);
ctx.touch_active = component_slot_from_wl_surface(surface);
if (ctx.touch_active){
update_touch_focus(seat, x, y);
@ -370,13 +355,16 @@ touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial,
draw_decoration();
wl_surface_commit(ctx.wl_surface);
enum libdecor_resize_edge edge = LIBDECOR_RESIZE_EDGE_NONE;
switch (ctx.touch_active->type) {
case SHADOW: {
edge = component_edge(ctx.touch_active, wl_fixed_to_int(x), wl_fixed_to_int(y), SHADOW_MARGIN);
switch (ctx.touch_active){
case COMPONENT_SLOT_SHADOW: {
enum libdecor_resize_edge edge = component_edge(COMPONENT_SLOT_SHADOW, wl_fixed_to_int(x), wl_fixed_to_int(y));
if (edge != LIBDECOR_RESIZE_EDGE_NONE &&
(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){
xdg_toplevel_resize(ctx.xdg_toplevel, seat->wl_seat, serial, xdg_edge_from_edge(edge));
}
}break;
case HEADER: {
case COMPONENT_SLOT_HEADER: {
switch (ctx.hdr_focus.type){
case HEADER_MIN:
case HEADER_MAX:
@ -405,10 +393,6 @@ touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial,
default: break;
}
if (edge != LIBDECOR_RESIZE_EDGE_NONE &&
(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)) {
libdecor_frame_resize(seat->wl_seat, serial, edge);
}
}
}
}
@ -418,7 +402,7 @@ touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time,
struct seat *seat = data;
if (seat->touch_focus && own_proxy(seat->touch_focus)){
if (ctx.touch_active != 0){
if (ctx.touch_active->type == HEADER){
if (ctx.touch_active == COMPONENT_SLOT_HEADER){
switch (ctx.hdr_focus.type) {
case HEADER_MIN: {
if (ctx.frame_capabilities & LIBDECOR_ACTION_MINIMIZE){
@ -562,7 +546,6 @@ wl_registry_global(void *data, struct wl_registry *wl_registry,
}
seat = calloc(1, sizeof *seat);
seat->cursor_scale = 1;
wl_list_insert(&ctx.seat_list, &seat->link);
seat->wl_seat = wl_registry_bind(ctx.wl_registry, name, &wl_seat_interface, 3);
wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
@ -660,17 +643,16 @@ xdg_toplevel_close(void *user_data, struct xdg_toplevel *xdg_toplevel){
#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION
static void
xdg_toplevel_configure_bounds(void *user_data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height){
int left = 0, top = 0, right = 0, bottom = 0;
if (ctx.visible != 0 &&
xdg_toplevel_configure_bounds(void *user_data, struct xdg_toplevel *xdg_toplevel, int32_t w, int32_t h){
int32_t inner_w = w;
int32_t inner_h = h;
if (ctx.visible &&
ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
libdecor_plugin_gtk_frame_get_border_size(0, &left, &right, &top, &bottom);
Bounds2D border_size = border_size_from_window_state(0);
inner_w -= border_size.x[0] + border_size.x[1];
inner_h -= border_size.y[0] + border_size.y[1];
}
width -= left + right;
height -= top + bottom;
//
// event to user (inner_w,inner_h)
}
#endif
@ -940,8 +922,10 @@ int main(){
zxdg_toplevel_decoration_v1_add_listener(ctx.toplevel_decoration, &xdg_toplevel_decoration_listener, 0);
}
ctx.content_limits.min_width = 80;
ctx.content_limits.min_height = 60;
ctx.size_bounds.x[0] = 80;
ctx.size_bounds.y[0] = 60;
ctx.size_bounds.x[1] = (1 << 30);
ctx.size_bounds.y[1] = (1 << 30);
xdg_toplevel_set_app_id(ctx.xdg_toplevel, "demo");
xdg_toplevel_set_title(ctx.xdg_toplevel, "Example Window");
@ -1140,56 +1124,32 @@ int main(){
//#include "libdecor.c"
static void
constrain_content_size(int *width, int *height){
const struct libdecor_limits lim = ctx.content_limits;
if (lim.min_width > 0)
*width = MAX(lim.min_width, *width);
if (lim.max_width > 0)
*width = MIN(*width, lim.max_width);
if (lim.min_height > 0)
*height = MAX(lim.min_height, *height);
if (lim.max_height > 0)
*height = MIN(*height, lim.max_height);
}
static void
frame_get_window_size_for(struct libdecor_state *state, int *window_width, int *window_height){
*window_width = state->content_width;
*window_height = state->content_height;
if (ctx.visible && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
int left, right, top, bottom;
libdecor_plugin_gtk_frame_get_border_size(ctx.frame_window_state, &left, &right, &top, &bottom);
*window_width += left + right;
*window_height += top + bottom;
Bounds2D border_size = border_size_from_window_state(ctx.frame_window_state);
*window_width += border_size.x[0] + border_size.x[1];
*window_height += border_size.y[0] + border_size.y[1];
}
}
static void
frame_set_window_geometry(int32_t content_width, int32_t content_height){
int x, y, width, height;
frame_set_window_geometry(int32_t w, int32_t h){
Extent2D extent = {0};
extent.w = w;
extent.w = h;
if (ctx.visible != 0 &&
ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
int left, right, top, bottom;
libdecor_plugin_gtk_frame_get_border_size(ctx.frame_window_state, &left, &right, &top, &bottom);
x = -left;
y = -top;
width = content_width + left + right;
height = content_height + top + bottom;
}
else{
x = 0;
y = 0;
width = content_width;
height = content_height;
if (ctx.visible && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
Bounds2D border_size = border_size_from_window_state(ctx.frame_window_state);
extent.x = -border_size.x[0];
extent.y = -border_size.y[0];
extent.w = w + border_size.x[0] + border_size.x[1];
extent.h = h + border_size.y[0] + border_size.y[1];
}
xdg_surface_set_window_geometry(ctx.xdg_surface, x, y, width, height);
xdg_surface_set_window_geometry(ctx.xdg_surface, extent.x, extent.y, extent.w, extent.h);
}
bool
@ -1206,23 +1166,32 @@ libdecor_configuration_get_content_size(struct libdecor_configuration *configura
if (ctx.visible != 0 &&
ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
int left, right, top, bottom;
ctx.frame_window_state = configuration->window_state;
if (configuration->has_window_state){
libdecor_plugin_gtk_frame_get_border_size(configuration->window_state, &left, &right, &top, &bottom);
Bounds2D border_size = border_size_from_window_state(configuration->window_state);
*width -= border_size.x[0] + border_size.x[1];
*height -= border_size.y[0] + border_size.y[1];
}
else{
return false;
}
*width -= (left + right);
*height -= (top + bottom);
}
/* constrain content dimensions manually */
if (!(configuration->window_state & LIBDECOR_WINDOW_STATE_NON_FLOATING)) {
constrain_content_size(width, height);
// TODO(allen):
if (ctx.size_bounds.x[0] > 0){
*width = MAX(ctx.size_bounds.x[0], *width);
}
if (ctx.size_bounds.x[1] > 0){
*width = MIN(*width, ctx.size_bounds.x[1]);
}
if (ctx.size_bounds.y[0] > 0){
*height = MAX(ctx.size_bounds.y[0], *height);
}
if (ctx.size_bounds.y[1] > 0){
*height = MIN(*height, ctx.size_bounds.y[1]);
}
}
return true;
@ -1253,7 +1222,7 @@ libdecor_frame_set_visibility(bool visible){
ctx.frame_content_height > 0){
if (ctx.visible != 0 &&
ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
libdecor_plugin_gtk_frame_commit(0, 0);
libdecor_plugin_gtk_frame_commit();
}
else{
libdecor_plugin_gtk_frame_free();
@ -1265,52 +1234,21 @@ libdecor_frame_set_visibility(bool visible){
}
}
void
libdecor_frame_translate_coordinate(int content_x, int content_y, int *frame_x, int *frame_y){
*frame_x = content_x;
*frame_y = content_y;
if (ctx.visible != 0 &&
ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
int left, top;
libdecor_plugin_gtk_frame_get_border_size(0, &left, 0, &top, 0);
*frame_x += left;
*frame_y += top;
}
}
enum xdg_toplevel_resize_edge
edge_to_xdg_edge(enum libdecor_resize_edge edge)
{
static enum xdg_toplevel_resize_edge
xdg_edge_from_edge(enum libdecor_resize_edge edge){
enum xdg_toplevel_resize_edge result = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
switch (edge) {
case LIBDECOR_RESIZE_EDGE_NONE:
return XDG_TOPLEVEL_RESIZE_EDGE_NONE;
case LIBDECOR_RESIZE_EDGE_TOP:
return XDG_TOPLEVEL_RESIZE_EDGE_TOP;
case LIBDECOR_RESIZE_EDGE_BOTTOM:
return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
case LIBDECOR_RESIZE_EDGE_LEFT:
return XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
case LIBDECOR_RESIZE_EDGE_TOP_LEFT:
return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
case LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT:
return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
case LIBDECOR_RESIZE_EDGE_RIGHT:
return XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
case LIBDECOR_RESIZE_EDGE_TOP_RIGHT:
return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
case LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT:
return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
default: case LIBDECOR_RESIZE_EDGE_NONE: break;
case LIBDECOR_RESIZE_EDGE_TOP: result = XDG_TOPLEVEL_RESIZE_EDGE_TOP; break;
case LIBDECOR_RESIZE_EDGE_BOTTOM: result = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; break;
case LIBDECOR_RESIZE_EDGE_LEFT: result = XDG_TOPLEVEL_RESIZE_EDGE_LEFT; break;
case LIBDECOR_RESIZE_EDGE_TOP_LEFT: result = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; break;
case LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT: result = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; break;
case LIBDECOR_RESIZE_EDGE_RIGHT: result = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; break;
case LIBDECOR_RESIZE_EDGE_TOP_RIGHT: result = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; break;
case LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT: result = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; break;
}
abort();
}
void
libdecor_frame_resize(struct wl_seat *wl_seat, uint32_t serial, enum libdecor_resize_edge edge){
enum xdg_toplevel_resize_edge xdg_edge;
xdg_edge = edge_to_xdg_edge(edge);
xdg_toplevel_resize(ctx.xdg_toplevel, wl_seat, serial, xdg_edge);
return(result);
}
void
@ -1344,19 +1282,19 @@ libdecor_frame_commit(int w, int h, struct libdecor_configuration *configuration
* configure event is received, we have to manually set the min/max
* limits with the configured content size afterwards. */
if (!(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){
ctx.content_limits.min_width = ctx.frame_content_width;
ctx.content_limits.min_height = ctx.frame_content_height;
ctx.content_limits.max_width = ctx.frame_content_width;
ctx.content_limits.max_height = ctx.frame_content_height;
ctx.size_bounds.x[0] = ctx.frame_content_width;
ctx.size_bounds.y[0] = ctx.frame_content_height;
ctx.size_bounds.x[1] = ctx.frame_content_width;
ctx.size_bounds.y[1] = ctx.frame_content_height;
}
if (ctx.content_limits.min_width > 0 &&
ctx.content_limits.min_height > 0){
if (ctx.size_bounds.x[0] > 0 &&
ctx.size_bounds.y[0] > 0){
struct libdecor_state state_min;
int win_min_width, win_min_height;
state_min.content_width = ctx.content_limits.min_width;
state_min.content_height = ctx.content_limits.min_height;
state_min.content_width = ctx.size_bounds.x[0];
state_min.content_height = ctx.size_bounds.y[0];
state_min.window_state = state.window_state;
frame_get_window_size_for(&state_min, &win_min_width, &win_min_height);
@ -1366,13 +1304,13 @@ libdecor_frame_commit(int w, int h, struct libdecor_configuration *configuration
xdg_toplevel_set_min_size(ctx.xdg_toplevel, 0, 0);
}
if (ctx.content_limits.max_width > 0 &&
ctx.content_limits.max_height > 0){
if (ctx.size_bounds.x[1] > 0 &&
ctx.size_bounds.y[1] > 0){
struct libdecor_state state_max;
int win_max_width, win_max_height;
state_max.content_width = ctx.content_limits.max_width;
state_max.content_height = ctx.content_limits.max_height;
state_max.content_width = ctx.size_bounds.x[1];
state_max.content_height = ctx.size_bounds.y[1];
state_max.window_state = state.window_state;
frame_get_window_size_for(&state_max, &win_max_width, &win_max_height);
@ -1384,9 +1322,9 @@ libdecor_frame_commit(int w, int h, struct libdecor_configuration *configuration
}
/* switch between decoration modes */
if (ctx.visible != 0 &&
if (ctx.visible &&
ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
libdecor_plugin_gtk_frame_commit(&state, configuration);
libdecor_plugin_gtk_frame_commit();
}
else{
libdecor_plugin_gtk_frame_free();
@ -1931,8 +1869,8 @@ libdecor_plugin_gtk_frame_free(void){
g_clear_pointer(&ctx.header, gtk_widget_destroy);
g_clear_pointer(&ctx.window, gtk_widget_destroy);
free_border_component(&ctx.headerbar);
free_border_component(&ctx.shadow);
free_border_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]);
free_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]);
ctx.shadow_showing = false;
g_clear_pointer(&ctx.shadow_blur, cairo_surface_destroy);
@ -1949,44 +1887,21 @@ hide_border_component(struct border_component *border_component){
}
}
static struct border_component *
border_component_from_wl_surface(const struct wl_surface *surface){
struct border_component *result = 0;
if (ctx.shadow.wl_surface == surface){
result = &ctx.shadow;
static enum component_slot
component_slot_from_wl_surface(const struct wl_surface *surface){
enum component_slot result = 0;
for (int i = 1; i < COMPONENT_SLOT_COUNT; i += 1){
if (ctx.component_slot[i].wl_surface == surface){
result = i;
break;
}
else if (ctx.headerbar.wl_surface == surface){
result = &ctx.headerbar;
}
return(result);
}
static void
redraw_scale(struct border_component *cmpnt){
struct surface_output *surface_output;
int scale = 1;
bool need_commit = false;
if (cmpnt->wl_surface != 0){
if (scale != cmpnt->scale){
cmpnt->scale = scale;
if ((ctx.decoration_type != DECORATION_TYPE_NONE) &&
(cmpnt->type != SHADOW || ctx.shadow_showing)){
draw_border_component(cmpnt);
need_commit = true;
}
}
}
if (need_commit){
wl_surface_commit(ctx.wl_surface);
}
}
static void
ensure_component(struct border_component *cmpnt){
if (cmpnt->wl_surface == 0){
cmpnt->scale = 1;
cmpnt->wl_surface = wl_compositor_create_surface(ctx.wl_compositor);
wl_proxy_set_tag((struct wl_proxy *)cmpnt->wl_surface, &libdecor_gtk_proxy_tag);
cmpnt->wl_subsurface = wl_subcompositor_get_subsurface(ctx.wl_subcompositor, cmpnt->wl_surface, ctx.wl_surface);
@ -1997,12 +1912,13 @@ static void
ensure_title_bar_surfaces(void){
GtkStyleContext *context_hdr;
ctx.headerbar.type = HEADER;
ctx.headerbar.opaque = false;
ensure_component(&ctx.headerbar);
ctx.component_slot[COMPONENT_SLOT_HEADER].slot = COMPONENT_SLOT_HEADER;
ctx.component_slot[COMPONENT_SLOT_HEADER].opaque = false;
ensure_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]);
if (ctx.shadow.wl_surface){
wl_subsurface_place_above(ctx.headerbar.wl_subsurface, ctx.shadow.wl_surface);
if (ctx.component_slot[COMPONENT_SLOT_SHADOW].wl_surface){
wl_subsurface_place_above(ctx.component_slot[COMPONENT_SLOT_HEADER].wl_subsurface,
ctx.component_slot[COMPONENT_SLOT_SHADOW].wl_surface);
}
if (GTK_IS_WIDGET(ctx.header)){
@ -2038,7 +1954,7 @@ ensure_title_bar_surfaces(void){
}
static Extent2D
extent2d_from_component(enum component component){
extent2d_from_component_type(enum component_slot slot){
Extent2D result = {0};
int width = ctx.frame_content_width;
int height = ctx.frame_content_height;
@ -2048,17 +1964,17 @@ extent2d_from_component(enum component component){
title_height = gtk_widget_get_allocated_height(ctx.header);
}
switch (component){
case NONE: break;
switch (slot){
default: case COMPONENT_SLOT_NONE: break;
case SHADOW: {
case COMPONENT_SLOT_SHADOW: {
result.x = -(int)SHADOW_MARGIN;
result.y = -(int)(SHADOW_MARGIN + title_height);
result.w = width + 2*SHADOW_MARGIN;
result.h = title_height + height + 2*SHADOW_MARGIN;
}break;
case HEADER: {
case COMPONENT_SLOT_HEADER: {
result.x = 0;
result.y = -title_height;
result.w = gtk_widget_get_allocated_width(ctx.header);
@ -2217,9 +2133,9 @@ draw_header_button(cairo_t *cr, cairo_surface_t *surface,
static void
set_component_input_region(struct border_component *border_component){
if (border_component->type == SHADOW && ctx.shadow_showing){
if (border_component->slot == COMPONENT_SLOT_SHADOW && ctx.shadow_showing){
struct wl_region *input_region;
Extent2D extent = extent2d_from_component(border_component->type);
Extent2D extent = extent2d_from_component_type(border_component->slot);
/*
* the input region is the outer surface size minus the inner
@ -2237,19 +2153,17 @@ static void
draw_border_component(struct border_component *border_component){
struct buffer *old_buffer;
struct buffer *buffer = 0;
int scale = border_component->scale;
enum component component = border_component->type;
if (border_component->wl_surface != 0){
Extent2D extent = extent2d_from_component(component);
Extent2D extent = extent2d_from_component_type(border_component->slot);
set_component_input_region(border_component);
old_buffer = border_component->buffer;
if (old_buffer != 0){
if (!old_buffer->in_use &&
old_buffer->buffer_width == extent.w*scale &&
old_buffer->buffer_height == extent.h*scale){
old_buffer->buffer_width == extent.w &&
old_buffer->buffer_height == extent.h){
buffer = old_buffer;
}
else{
@ -2268,8 +2182,8 @@ draw_border_component(struct border_component *border_component){
void *data;
enum wl_shm_format buf_fmt;
buffer_width = width * scale;
buffer_height = height * scale;
buffer_width = width;
buffer_height = height;
stride = buffer_width * 4;
size = stride * buffer_height;
@ -2292,7 +2206,6 @@ draw_border_component(struct border_component *border_component){
buffer->data_size = size;
buffer->width = width;
buffer->height = height;
buffer->scale = scale;
buffer->buffer_width = buffer_width;
buffer->buffer_height = buffer_height;
}
@ -2308,12 +2221,12 @@ draw_border_component(struct border_component *border_component){
cairo_surface_t *surface = cairo_image_surface_create_for_data(buffer->data, CAIRO_FORMAT_ARGB32,
buffer->buffer_width, buffer->buffer_height, stride);
cairo_t *cr = cairo_create(surface);
cairo_surface_set_device_scale(surface, buffer->scale, buffer->scale);
cairo_surface_set_device_scale(surface, 1, 1);
switch (component) {
case NONE: break;
switch (border_component->slot){
default: case COMPONENT_SLOT_NONE: break;
case SHADOW: {
case COMPONENT_SLOT_SHADOW: {
render_shadow(cr, ctx.shadow_blur,
-(int)SHADOW_MARGIN/2, -(int)SHADOW_MARGIN/2,
buffer->width + SHADOW_MARGIN, buffer->height + SHADOW_MARGIN,
@ -2323,7 +2236,7 @@ draw_border_component(struct border_component *border_component){
cairo_fill(cr);
}break;
case HEADER: {
case COMPONENT_SLOT_HEADER: {
/* background */
{
GtkAllocation allocation;
@ -2381,10 +2294,10 @@ draw_border_component(struct border_component *border_component){
}
wl_surface_attach(border_component->wl_surface, buffer->wl_buffer, 0, 0);
wl_surface_set_buffer_scale(border_component->wl_surface, buffer->scale);
wl_surface_set_buffer_scale(border_component->wl_surface, 1);
buffer->in_use = true;
wl_surface_commit(border_component->wl_surface);
wl_surface_damage_buffer(border_component->wl_surface, 0, 0, extent.w*scale, extent.h*scale);
wl_surface_damage_buffer(border_component->wl_surface, 0, 0, extent.w, extent.h);
wl_subsurface_set_position(border_component->wl_subsurface, extent.x, extent.y);
border_component->buffer = buffer;
@ -2422,25 +2335,25 @@ draw_title_bar(void){
gtk_header_bar_set_title(GTK_HEADER_BAR(ctx.header), "");
gtk_widget_get_preferred_width(ctx.header, NULL, &pref_width);
gtk_header_bar_set_title(GTK_HEADER_BAR(ctx.header), ctx.title);
if (ctx.content_limits.min_width < pref_width){
ctx.content_limits.min_width = pref_width;
if (ctx.size_bounds.x[0] < pref_width){
ctx.size_bounds.x[0] = pref_width;
}
if (ctx.content_limits.max_width != 0 &&
ctx.content_limits.max_width < ctx.content_limits.min_width){
ctx.content_limits.max_width = ctx.content_limits.min_width;
if (ctx.size_bounds.x[1] != 0 &&
ctx.size_bounds.x[1] < ctx.size_bounds.x[0]){
ctx.size_bounds.x[1] = ctx.size_bounds.x[0];
}
W = ctx.frame_content_width;
H = ctx.frame_content_height;
if (W < ctx.content_limits.min_width){
W = ctx.content_limits.min_width;
if (W < ctx.size_bounds.x[0]){
W = ctx.size_bounds.x[0];
libdecor_frame_commit(W, H, NULL);
}
else{
/* set default height */
gtk_widget_get_preferred_height(ctx.header, 0, &allocation.height);
gtk_widget_size_allocate(ctx.header, &allocation);
draw_border_component(&ctx.headerbar);
draw_border_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]);
}
}
@ -2448,23 +2361,23 @@ static void
draw_decoration(void){
switch (ctx.decoration_type){
case DECORATION_TYPE_NONE: {
hide_border_component(&ctx.shadow);
hide_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]);
ctx.shadow_showing = false;
hide_border_component(&ctx.headerbar);
hide_border_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]);
}break;
case DECORATION_TYPE_ALL: {
ctx.shadow.type = SHADOW;
ctx.shadow.opaque = false;
ensure_component(&ctx.shadow);
draw_border_component(&ctx.shadow);
ctx.component_slot[COMPONENT_SLOT_SHADOW].slot = COMPONENT_SLOT_SHADOW;
ctx.component_slot[COMPONENT_SLOT_SHADOW].opaque = false;
ensure_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]);
draw_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]);
ctx.shadow_showing = true;
ensure_title_bar_surfaces();
draw_title_bar();
}break;
case DECORATION_TYPE_TITLE_ONLY: {
hide_border_component(&ctx.shadow);
hide_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]);
ctx.shadow_showing = false;
ensure_title_bar_surfaces();
draw_title_bar();
@ -2489,7 +2402,7 @@ decoration_type_from_window_state(enum libdecor_window_state window_state){
}
static void
libdecor_plugin_gtk_frame_commit(struct libdecor_state *state, struct libdecor_configuration *configuration){
libdecor_plugin_gtk_frame_commit(void){
enum libdecor_window_state old_window_state;
enum libdecor_window_state new_window_state;
int old_content_width, old_content_height;
@ -2522,63 +2435,24 @@ libdecor_plugin_gtk_frame_commit(struct libdecor_state *state, struct libdecor_c
/* set fixed window size */
if (!(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){
ctx.content_limits.min_width = ctx.gtk_content_width;
ctx.content_limits.min_height = ctx.gtk_content_height;
ctx.content_limits.max_width = ctx.gtk_content_width;
ctx.content_limits.max_height = ctx.gtk_content_height;
ctx.size_bounds.x[0] = ctx.gtk_content_width;
ctx.size_bounds.y[0] = ctx.gtk_content_height;
ctx.size_bounds.x[1] = ctx.gtk_content_width;
ctx.size_bounds.y[1] = ctx.gtk_content_height;
}
}
}
static void
update_component_focus(struct wl_surface *surface, struct seat *seat){
static struct border_component *border_component;
static struct border_component *child_component;
static struct border_component *focus_component;
border_component = border_component_from_wl_surface(surface);
focus_component = border_component;
wl_list_for_each(child_component, &border_component->child_components, link) {
Extent2D extent = extent2d_from_component(child_component->type);
if (seat->pointer_x >= extent.x && seat->pointer_x < extent.x + extent.w &&
seat->pointer_y >= extent.y && seat->pointer_y < extent.y + extent.h) {
focus_component = child_component;
break;
}
}
if (ctx.grab){
ctx.active = ctx.grab;
}
else{
ctx.active = focus_component;
}
ctx.focus = focus_component;
}
static void
libdecor_plugin_gtk_frame_get_border_size(enum libdecor_window_state window_state,
int *left, int *right, int *top, int *bottom){
if (left){
*left = 0;
}
if (right){
*right = 0;
}
if (bottom){
*bottom = 0;
}
if (top) {
static Bounds2D
border_size_from_window_state(enum libdecor_window_state window_state){
Bounds2D border_size = {0};
switch (decoration_type_from_window_state(window_state)) {
case DECORATION_TYPE_NONE: {
*top = 0;
}break;
case DECORATION_TYPE_NONE: break;
case DECORATION_TYPE_ALL: {
ctx.shadow.type = SHADOW;
ctx.shadow.opaque = false;
ensure_component(&ctx.shadow);
ctx.component_slot[COMPONENT_SLOT_SHADOW].slot = COMPONENT_SLOT_SHADOW;
ctx.component_slot[COMPONENT_SLOT_SHADOW].opaque = false;
ensure_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]);
} G_GNUC_FALLTHROUGH;
case DECORATION_TYPE_TITLE_ONLY: {
@ -2586,118 +2460,88 @@ libdecor_plugin_gtk_frame_get_border_size(enum libdecor_window_state window_stat
ensure_title_bar_surfaces();
}
gtk_widget_show_all(ctx.window);
gtk_widget_get_preferred_height(ctx.header, NULL, top);
gtk_widget_get_preferred_height(ctx.header, 0, &border_size.y[0]);
}break;
}
}
return(border_size);
}
enum libdecor_resize_edge
component_edge(const struct border_component *cmpnt,
const int pointer_x, const int pointer_y,
const int margin){
const bool top = pointer_y < margin * 2;
const bool bottom = pointer_y > (cmpnt->buffer->height - margin * 2);
const bool left = pointer_x < margin * 2;
const bool right = pointer_x > (cmpnt->buffer->width - margin * 2);
component_edge(enum component_slot slot, int x, int y){
static const enum libdecor_resize_edge box[9] = {
LIBDECOR_RESIZE_EDGE_TOP_LEFT , LIBDECOR_RESIZE_EDGE_TOP , LIBDECOR_RESIZE_EDGE_TOP_RIGHT ,
LIBDECOR_RESIZE_EDGE_LEFT, LIBDECOR_RESIZE_EDGE_NONE , LIBDECOR_RESIZE_EDGE_RIGHT ,
LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT, LIBDECOR_RESIZE_EDGE_BOTTOM, LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT,
};
if (top){
if (left)
return LIBDECOR_RESIZE_EDGE_TOP_LEFT;
else if (right)
return LIBDECOR_RESIZE_EDGE_TOP_RIGHT;
else
return LIBDECOR_RESIZE_EDGE_TOP;
}
else if (bottom){
if (left)
return LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT;
else if (right)
return LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT;
else
return LIBDECOR_RESIZE_EDGE_BOTTOM;
}
else if (left){
return LIBDECOR_RESIZE_EDGE_LEFT;
}
else if (right){
return LIBDECOR_RESIZE_EDGE_RIGHT;
}
else{
return LIBDECOR_RESIZE_EDGE_NONE;
}
enum libdecor_resize_edge result = 0;
struct buffer *buffer = 0;
if (slot < COMPONENT_SLOT_COUNT){
buffer = ctx.component_slot[slot].buffer;
}
static bool
update_local_cursor(struct seat *seat){
bool result = false;
if (buffer != 0){
int w = buffer->width;
int h = buffer->height;
if (seat->pointer_focus == 0){
seat->current_cursor = seat->cursor_left_ptr;
}
else{
if (own_proxy(seat->pointer_focus)){
if (!ctx.active){
seat->current_cursor = seat->cursor_left_ptr;
}
else{
bool theme_updated = false;
{
int scale = 1;
if (seat->cursor_theme == 0 || seat->cursor_scale != scale){
struct wl_cursor_theme *theme;
int top = (y < 2*SHADOW_MARGIN);
int bottom = (!top && y > (w - 2*SHADOW_MARGIN));
int left = (x < 2*SHADOW_MARGIN);
int right = (!left && x > (h - 2*SHADOW_MARGIN));
seat->cursor_scale = scale;
theme = wl_cursor_theme_load(ctx.cursor_theme_name, ctx.cursor_size*scale, ctx.wl_shm);
if (theme != 0){
if (seat->cursor_theme){
wl_cursor_theme_destroy(seat->cursor_theme);
}
seat->cursor_theme = theme;
for (unsigned int i = 0; i < ARRAY_LENGTH(cursor_names); i++) {
seat->cursors[i] = wl_cursor_theme_get_cursor(seat->cursor_theme, cursor_names[i]);
}
seat->cursor_left_ptr = wl_cursor_theme_get_cursor(seat->cursor_theme, "left_ptr");
seat->current_cursor = seat->cursor_left_ptr;
theme_updated = true;
}
}
}
struct wl_cursor *wl_cursor = NULL;
if (ctx.active->type == SHADOW && ctx.shadow_showing &&
(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){
enum libdecor_resize_edge edge;
edge = component_edge(ctx.active, seat->pointer_x, seat->pointer_y, SHADOW_MARGIN);
if (edge != LIBDECOR_RESIZE_EDGE_NONE){
wl_cursor = seat->cursors[edge - 1];
}
}
else{
wl_cursor = seat->cursor_left_ptr;
}
if (seat->current_cursor != wl_cursor) {
seat->current_cursor = wl_cursor;
result = true;
}
else{
result = theme_updated;
}
}
}
int i = 4 + 3*(bottom - top) + (right - left);
result = box[i];
}
return(result);
}
static bool
update_local_cursor(struct seat *seat){
bool cursor_updated = false;
seat->current_cursor = seat->cursor_left_ptr;
if (own_proxy(seat->pointer_focus)){
if (ctx.active != 0){
if (seat->cursor_theme == 0){
struct wl_cursor_theme *theme = wl_cursor_theme_load(ctx.cursor_theme_name, ctx.cursor_size, ctx.wl_shm);
if (theme != 0){
seat->cursor_theme = theme;
for (unsigned int i = 0; i < ARRAY_LENGTH(cursor_names); i += 1){
seat->cursors[i] = wl_cursor_theme_get_cursor(theme, cursor_names[i]);
}
seat->cursor_left_ptr = wl_cursor_theme_get_cursor(seat->cursor_theme, "left_ptr");
seat->current_cursor = seat->cursor_left_ptr;
cursor_updated = true;
}
}
struct wl_cursor *wl_cursor = seat->cursor_left_ptr;
if (ctx.active == COMPONENT_SLOT_SHADOW &&
(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){
enum libdecor_resize_edge edge = component_edge(COMPONENT_SLOT_SHADOW, seat->pointer_x, seat->pointer_y);
if (edge != LIBDECOR_RESIZE_EDGE_NONE){
wl_cursor = seat->cursors[edge - 1];
}
}
if (seat->current_cursor != wl_cursor) {
seat->current_cursor = wl_cursor;
cursor_updated = true;
}
}
}
return(cursor_updated);
}
static void
update_touch_focus(struct seat *seat, wl_fixed_t x, wl_fixed_t y){
if (GTK_IS_WIDGET(ctx.header) && ctx.touch_active->type == HEADER){
if (GTK_IS_WIDGET(ctx.header) && ctx.touch_active == COMPONENT_SLOT_HEADER){
struct header_element_data new_focus = get_header_focus(GTK_HEADER_BAR(ctx.header), wl_fixed_to_int(x), wl_fixed_to_int(y));
if (ctx.hdr_focus.widget != new_focus.widget){
ctx.hdr_focus = new_focus;

View File

@ -59,6 +59,11 @@ typedef struct Extent2D{
int h;
} Extent2D;
typedef struct Bounds2D{
int x[2];
int y[2];
} Bounds2D;
// libdecor.h
struct libdecor_configuration;
@ -122,13 +127,6 @@ enum libdecor_wm_capabilities {
// libdecor-plugin.h
struct libdecor_limits {
int min_width;
int min_height;
int max_width;
int max_height;
};
enum header_element {
HEADER_NONE,
HEADER_FULL, /* entire header bar */
@ -159,22 +157,19 @@ enum decoration_type {
DECORATION_TYPE_TITLE_ONLY
};
enum component {
NONE = 0,
SHADOW,
HEADER,
enum component_slot {
COMPONENT_SLOT_NONE,
COMPONENT_SLOT_SHADOW,
COMPONENT_SLOT_HEADER,
COMPONENT_SLOT_COUNT
};
struct border_component {
enum component type;
enum component_slot slot;
struct wl_surface *wl_surface;
struct wl_subsurface *wl_subsurface;
struct buffer *buffer;
bool opaque;
int scale;
struct wl_list child_components; /* border_component::link */
struct wl_list link; /* border_component::child_components */
};
// #include "libdecor.c"
@ -228,7 +223,6 @@ struct seat {
struct wl_surface *cursor_surface;
struct wl_cursor *current_cursor;
int cursor_scale;
struct wl_cursor_theme *cursor_theme;
/* cursors for resize edges and corners */
@ -259,7 +253,6 @@ struct buffer {
size_t data_size;
int width;
int height;
int scale;
int buffer_width;
int buffer_height;
};
@ -275,14 +268,9 @@ enum titlebar_gesture {
void libdecor_frame_set_visibility(bool visible);
void libdecor_frame_show_window_menu(struct wl_seat *wl_seat, uint32_t serial, int x, int y);
void libdecor_frame_translate_coordinate(int surface_x, int surface_y, int *frame_x, int *frame_y);
void libdecor_frame_resize(struct wl_seat *wl_seat, uint32_t serial, enum libdecor_resize_edge edge);
void libdecor_frame_move(struct wl_seat *wl_seat, uint32_t serial);
void libdecor_frame_commit(int w, int h, struct libdecor_configuration *configuration);
void libdecor_frame_set_fullscreen(struct wl_output *output);
void libdecor_frame_unset_fullscreen(void);
void libdecor_frame_map(void);
bool libdecor_configuration_get_content_size(struct libdecor_configuration *configuration, int *width, int *height);
@ -313,24 +301,25 @@ static void do_map(void);
static const char *libdecor_gtk_proxy_tag = "libdecor-gtk";
static void libdecor_plugin_gtk_frame_free(void);
static void libdecor_plugin_gtk_frame_commit(struct libdecor_state *state, struct libdecor_configuration *configuration);
static void libdecor_plugin_gtk_frame_get_border_size(enum libdecor_window_state window_state, int *left, int *right, int *top, int *bottom);
static void libdecor_plugin_gtk_frame_commit(void);
static Bounds2D border_size_from_window_state(enum libdecor_window_state window_state);
static bool update_local_cursor(struct seat *seat);
static void draw_decoration(void);
static void draw_header_button(cairo_t *cr, cairo_surface_t *surface, enum header_element button_type);
static void redraw_scale(struct border_component *cmpnt);
static void buffer_free(struct buffer *buffer);
static void draw_border_component(struct border_component *border_component);
static bool own_proxy(void *proxy);
static struct border_component * border_component_from_wl_surface(const struct wl_surface *surface);
static enum component_slot component_slot_from_wl_surface(const struct wl_surface *surface);
static struct header_element_data get_header_focus(const GtkHeaderBar *header_bar, const int x, const int y);
static void draw_title_bar(void);
enum libdecor_resize_edge component_edge(const struct border_component *cmpnt, const int pointer_x, const int pointer_y, const int margin);
enum libdecor_resize_edge component_edge(const enum component_slot slot, const int pointer_x, const int pointer_y);
static void toggle_maximized(void);
static void update_touch_focus(struct seat *seat, wl_fixed_t x, wl_fixed_t y);
static enum xdg_toplevel_resize_edge xdg_edge_from_edge(enum libdecor_resize_edge edge);
// digesting_libdecor
typedef struct Ctx{
@ -375,7 +364,7 @@ typedef struct Ctx{
//struct libdecor_frame_private;
char *title;
struct libdecor_limits content_limits;
Bounds2D size_bounds;
struct xdg_toplevel *parent;
struct libdecor_configuration *pending_configuration;
@ -391,8 +380,6 @@ typedef struct Ctx{
enum libdecor_capabilities frame_capabilities;
enum libdecor_wm_capabilities wm_capabilities;
/* original limits for interactive resize */
struct libdecor_limits interactive_limits;
bool visible;
//struct libdecor_frame_gtk;
@ -405,20 +392,17 @@ typedef struct Ctx{
enum libdecor_capabilities gtk_capabilities;
struct border_component *active;
struct border_component *touch_active;
struct border_component *focus;
struct border_component *grab;
enum component_slot active;
enum component_slot touch_active;
enum component_slot focus;
enum component_slot grab;
struct border_component component_slot[COMPONENT_SLOT_COUNT];
bool shadow_showing;
struct border_component shadow;
GtkWidget *window; /* offscreen window for rendering */
GtkWidget *header; /* header bar with widgets */
struct border_component headerbar;
GtkWidget *window;
GtkWidget *header;
struct header_element_data hdr_focus;
/* store pre-processed shadow tile */
cairo_surface_t *shadow_blur;
struct {
@ -426,9 +410,9 @@ typedef struct Ctx{
int button_pressed_count;
uint32_t first_pressed_button;
uint32_t first_pressed_time;
double pressed_x;
double pressed_y;
uint32_t pressed_serial;
int pressed_x;
int pressed_y;
uint32_t serial;
} titlebar_gesture;
} Ctx;