Compare commits

..

3 Commits

2 changed files with 125 additions and 208 deletions

View File

@ -560,40 +560,33 @@ const struct wl_registry_listener wl_registry_listener = {
static void static void
xdg_surface_configure(void *user_data, struct xdg_surface *xdg_surface, uint32_t serial){ xdg_surface_configure(void *user_data, struct xdg_surface *xdg_surface, uint32_t serial){
struct libdecor_configuration *configuration; struct libdecor_configuration config = {0};
if (ctx.has_pending_config){
configuration = ctx.pending_configuration; ctx.has_pending_config = 0;
ctx.pending_configuration = 0; config = ctx.pending_config;
if (configuration == 0){
configuration = calloc(1, sizeof *configuration);
} }
config.serial = serial;
configuration->serial = serial;
{ {
int w = ctx.w; int w = ctx.w;
int h = ctx.h; int h = ctx.h;
bool got_size = false; bool got_size = false;
if (configuration->has_window_state && if (config.initialized &&
configuration->has_size && config.window_width != 0 &&
configuration->window_width != 0 && config.window_height != 0){
configuration->window_height != 0){
w = configuration->window_width; w = config.window_width;
h = configuration->window_height; h = config.window_height;
if (ctx.visible && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){ if (ctx.visible && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
ctx.frame_window_state = configuration->window_state; ctx.frame_window_state = config.window_state;
Sides2D border_size = border_size_from_window_state(configuration->window_state); Sides2D border_size = border_size_from_window_state(config.window_state);
w -= border_size.x[0] + border_size.x[1]; w -= border_size.x[0] + border_size.x[1];
h -= border_size.y[0] + border_size.y[1]; h -= border_size.y[0] + border_size.y[1];
} }
/* constrain content dimensions manually */ if (!(config.window_state & LIBDECOR_WINDOW_STATE_NON_FLOATING)){
if (!(configuration->window_state & LIBDECOR_WINDOW_STATE_NON_FLOATING)) {
// TODO(allen):
if (ctx.size_bounds.x[0] > 0){ if (ctx.size_bounds.x[0] > 0){
w = MAX(ctx.size_bounds.x[0], w); w = MAX(ctx.size_bounds.x[0], w);
} }
@ -608,23 +601,13 @@ xdg_surface_configure(void *user_data, struct xdg_surface *xdg_surface, uint32_t
} }
} }
got_size = true;
}
if (got_size){
ctx.w = w; ctx.w = w;
ctx.h = h; ctx.h = h;
} }
if (!ctx.configured){
ctx.configured = 1;
libdecor_frame_commit(w, h, configuration);
}
else{
ctx.has_cached_config = 1;
ctx.cached_config = *configuration;
}
}
free(configuration); ctx.has_cached_config = 1;
ctx.cached_config = config;
}
} }
const struct xdg_surface_listener xdg_surface_listener = { const struct xdg_surface_listener xdg_surface_listener = {
@ -661,12 +644,11 @@ xdg_toplevel_configure(void *user_data, struct xdg_toplevel *xdg_toplevel,
} }
} }
ctx.pending_configuration = calloc(1, sizeof *ctx.pending_configuration); ctx.has_pending_config = true;
ctx.pending_configuration->has_size = true; ctx.pending_config.initialized = true;
ctx.pending_configuration->window_width = width; ctx.pending_config.window_width = width;
ctx.pending_configuration->window_height = height; ctx.pending_config.window_height = height;
ctx.pending_configuration->has_window_state = true; ctx.pending_config.window_state = window_state;
ctx.pending_configuration->window_state = window_state;
} }
static void static void
@ -1097,7 +1079,13 @@ int main(){
if (ctx.has_cached_config){ if (ctx.has_cached_config){
ctx.has_cached_config = 0; ctx.has_cached_config = 0;
libdecor_frame_commit(ctx.w, ctx.h, &ctx.cached_config); if (ctx.cached_config.initialized){
ctx.frame_window_state = ctx.cached_config.window_state;
}
ctx.frame_content_width = ctx.w;
ctx.frame_content_height = ctx.h;
libdecor_frame_commit();
xdg_surface_ack_configure(ctx.xdg_surface, ctx.cached_config.serial);
} }
/* (nodocs-wl_egl) */ /* (nodocs-wl_egl) */
@ -1203,99 +1191,6 @@ free_border_component(struct border_component *border_component){
border_component->height = 0; border_component->height = 0;
} }
void
update_client_side_rendering_state(void){
if (ctx.visible && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
enum libdecor_window_state old_window_state;
enum libdecor_window_state new_window_state;
int old_content_width, old_content_height;
int new_content_width, new_content_height;
enum decoration_type old_decoration_type;
enum decoration_type new_decoration_type;
old_window_state = ctx.gtk_window_state;
new_window_state = ctx.frame_window_state;
old_content_width = ctx.gtk_content_width;
old_content_height = ctx.gtk_content_height;
new_content_width = ctx.frame_content_width;
new_content_height = ctx.frame_content_height;
old_decoration_type = ctx.decoration_type;
new_decoration_type = decoration_type_from_window_state(new_window_state);
if (old_decoration_type != new_decoration_type ||
old_content_width != new_content_width ||
old_content_height != new_content_height ||
old_window_state != new_window_state){
ctx.gtk_content_width = new_content_width;
ctx.gtk_content_height = new_content_height;
ctx.gtk_window_state = new_window_state;
ctx.decoration_type = new_decoration_type;
draw_decoration();
/* set fixed window size */
if (!(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){
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;
}
}
}
else{
g_clear_pointer(&ctx.header, gtk_widget_destroy);
g_clear_pointer(&ctx.window, gtk_widget_destroy);
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.title, free);
ctx.decoration_type = DECORATION_TYPE_NONE;
}
{
Extent2D extent = {0};
extent.w = ctx.frame_content_width;
extent.h = ctx.frame_content_height;
if (ctx.visible && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
Sides2D 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 += border_size.x[0] + border_size.x[1];
extent.h += border_size.y[0] + border_size.y[1];
}
xdg_surface_set_window_geometry(ctx.xdg_surface, extent.x, extent.y, extent.w, extent.h);
}
}
void
libdecor_frame_set_visibility(bool visible){
ctx.visible = visible;
if (ctx.decoration_manager != 0 &&
ctx.toplevel_decoration != 0 &&
ctx.has_decoration_mode &&
ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE){
zxdg_toplevel_decoration_v1_set_mode(ctx.toplevel_decoration,
ctx.visible ?
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE :
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
}
if (ctx.frame_content_width > 0 &&
ctx.frame_content_height > 0){
update_client_side_rendering_state();
wl_surface_commit(ctx.wl_surface);
}
}
static enum xdg_toplevel_resize_edge static enum xdg_toplevel_resize_edge
xdg_edge_from_edge(enum libdecor_resize_edge edge){ xdg_edge_from_edge(enum libdecor_resize_edge edge){
enum xdg_toplevel_resize_edge result = XDG_TOPLEVEL_RESIZE_EDGE_NONE; enum xdg_toplevel_resize_edge result = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
@ -1324,54 +1219,79 @@ libdecor_frame_unset_fullscreen(void){
} }
void void
libdecor_frame_commit(int w, int h, struct libdecor_configuration *configuration){ libdecor_frame_commit(void){
if (configuration != 0 && configuration->has_window_state){ Sides2D border_size = border_size_from_window_state(ctx.frame_window_state);
ctx.frame_window_state = configuration->window_state;
bool csd = false;
if (ctx.visible &&
ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
csd = true;
} }
Sides2D border_size = border_size_from_window_state(ctx.frame_window_state); if (!(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){
int border_added_w = border_size.x[0] + border_size.x[1]; int mw = ctx.frame_content_width;
int border_added_h = border_size.y[0] + border_size.y[1]; int mh = ctx.frame_content_height;
xdg_toplevel_set_min_size(ctx.xdg_toplevel, mw, mh);
xdg_toplevel_set_max_size(ctx.xdg_toplevel, mw, mh);
}
struct libdecor_state state = {0}; else{
state.content_width = w; int csd_added_w = 0;
state.content_height = h; int csd_added_h = 0;
state.window_state = ctx.frame_window_state; if (csd){
csd_added_w = border_size.x[0] + border_size.x[1];
ctx.frame_content_width = state.content_width; csd_added_h = border_size.y[0] + border_size.y[1];
ctx.frame_content_height = state.content_height;
{
if (!(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){
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;
} }
for (int i = 0; i < 2; i += 1){ for (int i = 0; i < 2; i += 1){
int w = 0; int mw = 0;
int h = 0; int mh = 0;
if (ctx.size_bounds.x[i] > 0 && ctx.size_bounds.y[i] > 0){ if (ctx.size_bounds.x[i] > 0 && ctx.size_bounds.y[i] > 0){
w = ctx.size_bounds.x[i]; mw = ctx.size_bounds.x[i] + csd_added_w;
h = ctx.size_bounds.y[i]; mh = ctx.size_bounds.y[i] + csd_added_h;
if (ctx.visible && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
w += border_added_w;
h += border_added_h;
}
} }
if (i == 0){ if (i == 0){
xdg_toplevel_set_min_size(ctx.xdg_toplevel, w, h); xdg_toplevel_set_min_size(ctx.xdg_toplevel, mw, mh);
} }
else{ else{
xdg_toplevel_set_max_size(ctx.xdg_toplevel, w, h); xdg_toplevel_set_max_size(ctx.xdg_toplevel, mw, mh);
} }
} }
} }
update_client_side_rendering_state(); if (csd){
ctx.gtk_content_width = ctx.frame_content_width;
ctx.gtk_content_height = ctx.frame_content_height;
ctx.gtk_window_state = ctx.frame_window_state;
ctx.decoration_type = decoration_type_from_window_state(ctx.frame_window_state);
if (configuration != 0){ draw_decoration();
xdg_surface_ack_configure(ctx.xdg_surface, configuration->serial); }
else{
g_clear_pointer(&ctx.header, gtk_widget_destroy);
g_clear_pointer(&ctx.window, gtk_widget_destroy);
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.title, free);
ctx.decoration_type = DECORATION_TYPE_NONE;
}
{
Extent2D extent = {0};
extent.w = ctx.frame_content_width;
extent.h = ctx.frame_content_height;
if (csd){
extent.x = -border_size.x[0];
extent.y = -border_size.y[0];
extent.w += border_size.x[0] + border_size.x[1];
extent.h += border_size.y[0] + border_size.y[1];
}
xdg_surface_set_window_geometry(ctx.xdg_surface, extent.x, extent.y, extent.w, extent.h);
} }
} }
@ -2118,6 +2038,7 @@ draw_border_component(enum component_slot slot){
if (slot < COMPONENT_SLOT_COUNT && if (slot < COMPONENT_SLOT_COUNT &&
ctx.component_slot[slot].wl_surface != 0){ ctx.component_slot[slot].wl_surface != 0){
Extent2D extent = extent2d_from_component_slot(slot); Extent2D extent = extent2d_from_component_slot(slot);
if (slot == COMPONENT_SLOT_SHADOW && ctx.shadow_showing){ if (slot == COMPONENT_SLOT_SHADOW && ctx.shadow_showing){
struct wl_region *input_region; struct wl_region *input_region;
Extent2D extent = extent2d_from_component_slot(COMPONENT_SLOT_SHADOW); Extent2D extent = extent2d_from_component_slot(COMPONENT_SLOT_SHADOW);
@ -2181,7 +2102,7 @@ draw_border_component(enum component_slot slot){
cairo_surface_set_device_scale(surface, 1, 1); cairo_surface_set_device_scale(surface, 1, 1);
switch (slot){ switch (slot){
default: case COMPONENT_SLOT_NONE: break; default:break;
case COMPONENT_SLOT_SHADOW: { case COMPONENT_SLOT_SHADOW: {
render_shadow(cr, ctx.shadow_blur, render_shadow(cr, ctx.shadow_blur,
@ -2197,26 +2118,24 @@ draw_border_component(enum component_slot slot){
/* background */ /* background */
{ {
GtkAllocation allocation; GtkAllocation allocation;
GtkStyleContext* style;
gtk_widget_get_allocation(GTK_WIDGET(ctx.header), &allocation); gtk_widget_get_allocation(GTK_WIDGET(ctx.header), &allocation);
style = gtk_widget_get_style_context(ctx.header); GtkStyleContext* style = gtk_widget_get_style_context(ctx.header);
gtk_render_background(style, cr, allocation.x, allocation.y, allocation.width, allocation.height); gtk_render_background(style, cr, allocation.x, allocation.y, allocation.width, allocation.height);
} }
/* title */ /* title */
{ {
GtkWidget *label; GtkWidget *label = find_widget_by_type(ctx.header, HEADER_TITLE).widget;
GtkAllocation allocation;
cairo_surface_t *label_surface = NULL;
cairo_t *cr;
label = find_widget_by_type(ctx.header, HEADER_TITLE).widget; GtkAllocation allocation;
gtk_widget_get_allocation(label, &allocation); gtk_widget_get_allocation(label, &allocation);
label_surface = cairo_surface_create_for_rectangle(surface, allocation.x, allocation.y, allocation.width, allocation.height);
cr = cairo_create(label_surface); cairo_surface_t *label_surface = cairo_surface_create_for_rectangle(surface, allocation.x, allocation.y, allocation.width, allocation.height);
cairo_t *cr2 = cairo_create(label_surface);
gtk_widget_size_allocate(label, &allocation); gtk_widget_size_allocate(label, &allocation);
gtk_widget_draw(label, cr); gtk_widget_draw(label, cr2);
cairo_destroy(cr); cairo_destroy(cr2);
cairo_surface_destroy(label_surface); cairo_surface_destroy(label_surface);
} }
@ -2238,7 +2157,7 @@ draw_border_component(enum component_slot slot){
nbuttons += 1; nbuttons += 1;
} }
for (size_t i = 0; i < nbuttons; i += 1){ for (int i = 0; i < nbuttons; i += 1){
enum header_element button_type = buttons[i]; enum header_element button_type = buttons[i];
draw_header_button(cr, surface, button_type); draw_header_button(cr, surface, button_type);
} }
@ -2263,11 +2182,8 @@ draw_border_component(enum component_slot slot){
static void static void
draw_title_bar(void){ draw_title_bar(void){
GtkAllocation allocation = {0, 0, ctx.gtk_content_width, 0};
enum libdecor_window_state state; enum libdecor_window_state state;
GtkStyleContext *style; GtkStyleContext *style;
int pref_width;
int W, H;
state = ctx.frame_window_state; state = ctx.frame_window_state;
style = gtk_widget_get_style_context(ctx.window); style = gtk_widget_get_style_context(ctx.window);
@ -2288,26 +2204,28 @@ draw_title_bar(void){
gtk_widget_show_all(ctx.window); gtk_widget_show_all(ctx.window);
/* set default width, using an empty title to estimate its smallest admissible value */ int pref_width;
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), "");
gtk_header_bar_set_title(GTK_HEADER_BAR(ctx.header), ctx.title); gtk_widget_get_preferred_width(ctx.header, NULL, &pref_width);
if (ctx.size_bounds.x[0] < pref_width){ gtk_header_bar_set_title(GTK_HEADER_BAR(ctx.header), ctx.title);
ctx.size_bounds.x[0] = pref_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; ctx.size_bounds.x[0] = CLAMP_BOT(ctx.size_bounds.x[0], pref_width);
H = ctx.frame_content_height; if (ctx.size_bounds.x[1] != 0){
if (W < ctx.size_bounds.x[0]){ ctx.size_bounds.x[1] = CLAMP_BOT(ctx.size_bounds.x[1], ctx.size_bounds.x[0]);
W = ctx.size_bounds.x[0]; }
libdecor_frame_commit(W, H, NULL);
int w = ctx.frame_content_width;
int h = ctx.frame_content_height;
if (w < ctx.size_bounds.x[0]){
w = ctx.size_bounds.x[0];
ctx.frame_content_width = w;
ctx.frame_content_height = h;
libdecor_frame_commit();
} }
else{ else{
/* set default height */ GtkAllocation allocation = {0, 0, ctx.gtk_content_width, 0};
gtk_widget_get_preferred_height(ctx.header, 0, &allocation.height); gtk_widget_get_preferred_height(ctx.header, 0, &allocation.height);
gtk_widget_size_allocate(ctx.header, &allocation); gtk_widget_size_allocate(ctx.header, &allocation);
draw_border_component(COMPONENT_SLOT_HEADER); draw_border_component(COMPONENT_SLOT_HEADER);

View File

@ -45,6 +45,9 @@
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define CLAMP_BOT(a, b) MAX(a, b)
#define CLAMP_TOP(a, b) MIN(a, b)
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
#define STREQL(a,b) (((a)==0 && (b)==0) || \ #define STREQL(a,b) (((a)==0 && (b)==0) || \
@ -184,13 +187,10 @@ struct libdecor_state {
int content_height; int content_height;
}; };
struct libdecor_configuration { struct libdecor_configuration{
bool initialized;
uint32_t serial; uint32_t serial;
bool has_window_state;
enum libdecor_window_state window_state; enum libdecor_window_state window_state;
bool has_size;
int window_width; int window_width;
int window_height; int window_height;
}; };
@ -250,10 +250,9 @@ enum titlebar_gesture {
// libdecor.h // libdecor.h
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_show_window_menu(struct wl_seat *wl_seat, uint32_t serial, int x, int y);
void libdecor_frame_commit(int w, int h, struct libdecor_configuration *configuration); void libdecor_frame_commit(void);
void libdecor_frame_set_fullscreen(struct wl_output *output); void libdecor_frame_set_fullscreen(struct wl_output *output);
void libdecor_frame_unset_fullscreen(void); void libdecor_frame_unset_fullscreen(void);
@ -336,7 +335,6 @@ typedef struct Ctx{
struct xdg_toplevel *xdg_toplevel; struct xdg_toplevel *xdg_toplevel;
struct zxdg_toplevel_decoration_v1 *toplevel_decoration; struct zxdg_toplevel_decoration_v1 *toplevel_decoration;
struct wl_egl_window *wl_egl_window; struct wl_egl_window *wl_egl_window;
int configured;
int w; int w;
int h; int h;
int close_signal; int close_signal;
@ -346,13 +344,14 @@ typedef struct Ctx{
int has_cached_config; int has_cached_config;
struct libdecor_configuration cached_config; struct libdecor_configuration cached_config;
int has_pending_config;
struct libdecor_configuration pending_config;
//struct libdecor_frame_private; //struct libdecor_frame_private;
char *title; char *title;
Sides2D size_bounds; Sides2D size_bounds;
struct xdg_toplevel *parent; struct xdg_toplevel *parent;
struct libdecor_configuration *pending_configuration;
int frame_content_width; int frame_content_width;
int frame_content_height; int frame_content_height;