It looks like it's just going to be getting the subsurface offsets

main
Allen Webster 2026-03-05 18:52:57 -08:00
parent d7770effea
commit 070ab2f42f
2 changed files with 212 additions and 164 deletions

View File

@ -1032,39 +1032,29 @@ csd_gtk_update_and_render(void){
CSD_Window *window = &ctx.window; CSD_Window *window = &ctx.window;
CSD_GTK_Window *gtk_window = &ctx.gtk_window; CSD_GTK_Window *gtk_window = &ctx.gtk_window;
if (window->control_flags & CSD_WindowControlFlag_Resize){ /* determine cursor location information */
static const CSD_CursorShape cursor_box[] = { enum{
CSD_CursorShape_Resize_TopLeft, CSD_CursorShape_Resize_Top, CSD_CursorShape_Resize_TopRight, LOCATION_NULL, LOCATION_SHADOW, LOCATION_TITLEBAR,
CSD_CursorShape_Resize_Left, CSD_CursorShape_Pointer, CSD_CursorShape_Resize_Right,
CSD_CursorShape_Resize_BottomLeft, CSD_CursorShape_Resize_Bottom, CSD_CursorShape_Resize_BottomRight,
}; };
CSD_U32 cursor_loc = LOCATION_NULL;
static const enum xdg_toplevel_resize_edge xedge_box[] = { CSD_S32 cursor_shadow_loc = 0;
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,
};
CSD_S32 l = (seat->hover_p[0] < 0); CSD_S32 l = (seat->hover_p[0] < 0);
CSD_S32 r = (!l && seat->hover_p[0] >= window->dim[0]); CSD_S32 r = (!l && seat->hover_p[0] >= window->dim[0]);
CSD_S32 t = (seat->hover_p[1] < -window->csd_frame.border[1][0]); CSD_S32 t = (seat->hover_p[1] < -window->csd_frame.border[1][0]);
CSD_S32 b = (!t && seat->hover_p[1] >= window->dim[1]); CSD_S32 b = (!t && seat->hover_p[1] >= window->dim[1]);
CSD_S32 loc = 3*(b - t) + (r - l); cursor_shadow_loc = 3*(b - t) + (r - l);
seat->cursor_shape = cursor_box[4 + loc]; }
if (ctx.has_event && if (cursor_shadow_loc != 0){
ctx.event_button == BTN_LEFT && cursor_loc = LOCATION_SHADOW;
ctx.event_button_state == 1){
ctx.has_event = 0;
if (loc != 0){
xdg_toplevel_resize(window->main_xdg_toplevel, seat->wl_seat,
seat->serial, xedge_box[4 + loc]);
} }
else if (seat->hover_p[1] < 0){ else if (seat->hover_p[1] < 0){
xdg_toplevel_move(window->main_xdg_toplevel, seat->wl_seat, seat->serial); cursor_loc = LOCATION_TITLEBAR;
}
} }
} }
/* draw shadow */
{ {
CSD_SubSurface *subsurface = &gtk_window->shadow; CSD_SubSurface *subsurface = &gtk_window->shadow;
@ -1108,6 +1098,26 @@ csd_gtk_update_and_render(void){
csd_subsurface_commit(subsurface); csd_subsurface_commit(subsurface);
} }
/* setup buttons */
enum{
HEADER_BUTTON_NULL,
HEADER_BUTTON_MIN, HEADER_BUTTON_MAX, HEADER_BUTTON_CLOSE,
HEADER_BUTTON_COUNT
};
static char* header_button_name[] = {
0, ".minimize", ".maximize", ".close"
};
CSD_B32 header_button_active[] = {
/*NULL*/ 0,
/*MIN*/ (window->control_flags & CSD_WindowControlFlag_Min),
/*MAX*/ ((window->control_flags & CSD_WindowControlFlag_Max) &&
(window->control_flags & CSD_WindowControlFlag_Resize)),
/*CLOSE*/ (window->control_flags & CSD_WindowControlFlag_Close)
};
CSD_U32 header_button_hover = 0;
/* draw frame */
{ {
CSD_SubSurface *subsurface = &gtk_window->titlebar; CSD_SubSurface *subsurface = &gtk_window->titlebar;
@ -1153,7 +1163,7 @@ csd_gtk_update_and_render(void){
cairo_t *cr = cairo_create(cr_surface); cairo_t *cr = cairo_create(cr_surface);
cairo_surface_set_device_scale(cr_surface, 1, 1); cairo_surface_set_device_scale(cr_surface, 1, 1);
/* background */ /* draw background */
{ {
GtkAllocation allocation; GtkAllocation allocation;
gtk_widget_get_allocation(GTK_WIDGET(gtk_window->header), &allocation); gtk_widget_get_allocation(GTK_WIDGET(gtk_window->header), &allocation);
@ -1163,7 +1173,7 @@ csd_gtk_update_and_render(void){
allocation.width, allocation.height); allocation.width, allocation.height);
} }
/* title */ /* draw title */
{ {
GtkWidget *label_title = GtkWidget *label_title =
csd_gtk__widget_from_name(gtk_window->header, "label.title:"); csd_gtk__widget_from_name(gtk_window->header, "label.title:");
@ -1181,72 +1191,63 @@ csd_gtk_update_and_render(void){
cairo_surface_destroy(cr_label_surface); cairo_surface_destroy(cr_label_surface);
} }
/* buttons */ /* draw buttons */
CSD_U32 buttons[3] = {0}; for (CSD_U32 i = 1; i < HEADER_BUTTON_COUNT; i += 1){
int button_count = 0; if (header_button_active[i]){
if (window->control_flags & CSD_WindowControlFlag_Min){
buttons[button_count] = 0;
button_count += 1;
}
if ((window->control_flags & CSD_WindowControlFlag_Max) &&
(window->control_flags & CSD_WindowControlFlag_Resize)){
buttons[button_count] = 1;
button_count += 1;
}
if (window->control_flags & CSD_WindowControlFlag_Close){
buttons[button_count] = 2;
button_count += 1;
}
for (int i = 0; i < button_count; i += 1){
CSD_U32 button_code = buttons[i];
char *button_name = "";
char *icon_name = ""; char *icon_name = "";
switch (button_code){ switch (i){
case 0: { case HEADER_BUTTON_MIN: {
button_name = ".minimize";
icon_name = "window-minimize-symbolic"; icon_name = "window-minimize-symbolic";
}break; }break;
case 1: { case HEADER_BUTTON_MAX: {
button_name = ".maximize";
icon_name = ((window->config.flags & CSD_WindowFlag_IsMax) ? icon_name = ((window->config.flags & CSD_WindowFlag_IsMax) ?
"window-restore-symbolic" : "window-maximize-symbolic"); "window-restore-symbolic" : "window-maximize-symbolic");
}break; }break;
case 2: { case HEADER_BUTTON_CLOSE: {
button_name = ".close";
icon_name = "window-close-symbolic"; icon_name = "window-close-symbolic";
}break; }break;
} }
GtkWidget *button_widget = GtkWidget *widget =
csd_gtk__widget_from_name(gtk_window->header, button_name); csd_gtk__widget_from_name(gtk_window->header, header_button_name[i]);
if (button_widget != 0){ if (widget != 0){
GtkStyleContext *style = gtk_widget_get_style_context(button_widget); /* layout */
GtkAllocation rect;
gtk_widget_get_clip(widget, &rect);
/* check pointer hover */
CSD_B32 is_hovered = 0;
{
CSD_S32 x0 = rect.x;
CSD_S32 y0 = rect.y - title_dim[1];
CSD_S32 x1 = rect.x + rect.width;
CSD_S32 y1 = rect.y + rect.height - title_dim[1];
if (x0 <= seat->hover_p[0] && seat->hover_p[0] < x1 &&
y0 <= seat->hover_p[1] && seat->hover_p[1] < y1){
header_button_hover = i;
is_hovered = 1;
}
}
/* change style based on window state and focus */ /* change style based on window state and focus */
GtkStyleContext *style = gtk_widget_get_style_context(widget);
GtkStateFlags style_state = 0; GtkStateFlags style_state = 0;
if (!(window->config.flags & CSD_WindowFlag_IsActivated)){ if (!(window->config.flags & CSD_WindowFlag_IsActivated)){
style_state |= GTK_STATE_FLAG_BACKDROP; style_state |= GTK_STATE_FLAG_BACKDROP;
} }
if (gtk_window->hover_button_code == button_code){ if (is_hovered){
style_state |= GTK_STATE_FLAG_PRELIGHT; style_state |= GTK_STATE_FLAG_PRELIGHT;
if (gtk_window->active_button_code == button_code){ if (i == gtk_window->active_header_button){
style_state |= GTK_STATE_FLAG_ACTIVE; style_state |= GTK_STATE_FLAG_ACTIVE;
} }
} }
/* background */ /* background */
GtkAllocation allocation;
gtk_widget_get_clip(button_widget, &allocation);
gtk_style_context_save(style); gtk_style_context_save(style);
gtk_style_context_set_state(style, style_state); gtk_style_context_set_state(style, style_state);
gtk_render_background(style, cr, allocation.x, allocation.y, gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height);
allocation.width, allocation.height); gtk_render_frame(style, cr, rect.x, rect.y, rect.width, rect.height);
gtk_render_frame(style, cr, allocation.x, allocation.y,
allocation.width, allocation.height);
gtk_style_context_restore(style); gtk_style_context_restore(style);
/* get scale */ /* get scale */
@ -1255,7 +1256,7 @@ csd_gtk_update_and_render(void){
int scale = (sx + sy)/2.0; int scale = (sx + sy)/2.0;
/* get original icon dimensions */ /* get original icon dimensions */
GtkWidget *icon_widget = gtk_bin_get_child(GTK_BIN(button_widget)); GtkWidget *icon_widget = gtk_bin_get_child(GTK_BIN(widget));
/* icon info */ /* icon info */
gint icon_width, icon_height; gint icon_width, icon_height;
@ -1284,37 +1285,30 @@ csd_gtk_update_and_render(void){
width = CSD_ClampBot(width, icon_width); width = CSD_ClampBot(width, icon_width);
height = CSD_ClampBot(height, icon_height); height = CSD_ClampBot(height, icon_height);
gint left = 0;
gint top = 0;
gint right = 0;
gint bottom = 0;
GtkBorder border; GtkBorder border;
gtk_style_context_get_border(style, gtk_style_context_get_state(style), &border); gtk_style_context_get_border(style, gtk_style_context_get_state(style), &border);
left += border.left;
right += border.right;
top += border.top;
bottom += border.bottom;
GtkBorder padding; GtkBorder padding;
gtk_style_context_get_padding(style, gtk_style_context_get_state(style), &padding); gtk_style_context_get_padding(style, gtk_style_context_get_state(style), &padding);
left += padding.left;
right += padding.right; gint left = border.left + padding.left;
top += padding.top; gint right = border.right + padding.right;
bottom += padding.bottom; gint top = border.top + padding.top;
gint bottom = border.bottom + padding.bottom;
width += left + right; width += left + right;
height += top + bottom; height += top + bottom;
gtk_render_icon_surface(gtk_widget_get_style_context(icon_widget), gtk_render_icon_surface(gtk_widget_get_style_context(icon_widget),
cr, icon_surface, cr, icon_surface,
allocation.x + (width - icon_width)/2, rect.x + (width - icon_width)/2,
allocation.y + (height - icon_height)/2); rect.y + (height - icon_height)/2);
cairo_paint(cr); cairo_paint(cr);
cairo_surface_destroy(icon_surface); cairo_surface_destroy(icon_surface);
g_object_unref(icon_pixbuf); g_object_unref(icon_pixbuf);
} }
} }
}
cairo_destroy(cr); cairo_destroy(cr);
cairo_surface_destroy(cr_surface); cairo_surface_destroy(cr_surface);
@ -1323,6 +1317,62 @@ csd_gtk_update_and_render(void){
csd_subsurface_set_position(subsurface, 0, -window->csd_frame.border[1][0]); csd_subsurface_set_position(subsurface, 0, -window->csd_frame.border[1][0]);
csd_subsurface_commit(subsurface); csd_subsurface_commit(subsurface);
} }
/* process events */
if (ctx.has_event){
/* handle left-button press */
if (ctx.event_button == BTN_LEFT &&
ctx.event_button_state == 1){
switch (cursor_loc){
default: case LOCATION_NULL: break;
case LOCATION_SHADOW: {
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,
};
xdg_toplevel_resize(window->main_xdg_toplevel, seat->wl_seat,
seat->serial, xedge_box[4 + cursor_shadow_loc]);
ctx.has_event = 0;
}break;
case LOCATION_TITLEBAR: {
if (header_button_hover == 0){
xdg_toplevel_move(window->main_xdg_toplevel, seat->wl_seat, seat->serial);
}
else{
gtk_window->active_header_button = header_button_hover;
}
ctx.has_event = 0;
}break;
}
}
/* handle left-button release */
if (ctx.event_button == BTN_LEFT &&
ctx.event_button_state == 0){
if (gtk_window->active_header_button != 0 &&
gtk_window->active_header_button == header_button_hover){
// activate button effect here
}
gtk_window->active_header_button = 0;
}
}
/* set cursor shape */
if (window->control_flags & CSD_WindowControlFlag_Resize){
static const CSD_CursorShape cursor_box[] = {
CSD_CursorShape_Resize_TopLeft, CSD_CursorShape_Resize_Top, CSD_CursorShape_Resize_TopRight,
CSD_CursorShape_Resize_Left, CSD_CursorShape_Pointer, CSD_CursorShape_Resize_Right,
CSD_CursorShape_Resize_BottomLeft, CSD_CursorShape_Resize_Bottom, CSD_CursorShape_Resize_BottomRight,
};
seat->cursor_shape = cursor_box[4 + cursor_shadow_loc];
}
else{
seat->cursor_shape = CSD_CursorShape_Pointer;
}
} }
/* cairo shadow rendering */ /* cairo shadow rendering */

View File

@ -167,16 +167,14 @@ typedef struct CSD_GTK_Ctx{
} CSD_GTK_Ctx; } CSD_GTK_Ctx;
typedef struct CSD_GTK_Window{ typedef struct CSD_GTK_Window{
CSD_S32 double_click_time_ms;
CSD_SubSurface titlebar; CSD_SubSurface titlebar;
CSD_SubSurface shadow; CSD_SubSurface shadow;
GtkWidget *window; GtkWidget *window;
GtkWidget *header; GtkWidget *header;
CSD_U32 hover_button_code; CSD_S32 double_click_time_ms;
CSD_U32 active_button_code; CSD_U32 active_header_button;
} CSD_GTK_Window; } CSD_GTK_Window;
/* csd gtk implementation */ /* csd gtk implementation */