[wayland_gtk_egl] full feature set up and running, some steps towards multi-seat support (not tested)

main
Allen Webster 2026-03-06 14:53:27 -08:00
parent 070ab2f42f
commit e0584cc5ea
2 changed files with 285 additions and 202 deletions

View File

@ -85,25 +85,22 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = {
static void static void
pointer_enter(void *udata, struct wl_pointer *wl_pointer, CSD_U32 serial, pointer_enter(void *udata, struct wl_pointer *wl_pointer, CSD_U32 serial,
struct wl_surface *surface, wl_fixed_t fx, wl_fixed_t fy){ struct wl_surface *surface, wl_fixed_t fx, wl_fixed_t fy){
CSD_Seat *seat = &ctx.seat;
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;
CSD_S32 surface_off[2] = {0}; CSD_S32 surface_off[2] = {0};
if (surface == window->main_wl_surface){ if (csd_gtk_calc_surface_off(gtk_window, surface, surface_off)){
// surface_off = {0,0} // handled by gtk frame
} }
else if (surface == gtk_window->titlebar.wl_surface){ else if (surface == window->main_wl_surface){
memcpy(surface_off, gtk_window->titlebar.p, sizeof(surface_off)); // app's surface_off = {0,0}
}
else if (surface == gtk_window->shadow.wl_surface){
memcpy(surface_off, gtk_window->shadow.p, sizeof(surface_off));
} }
CSD_Seat *seat = &ctx.seat;
seat->hover_surface = surface; seat->hover_surface = surface;
seat->serial = serial;
seat->hover_p[0] = surface_off[0] + wl_fixed_to_int(fx); seat->hover_p[0] = surface_off[0] + wl_fixed_to_int(fx);
seat->hover_p[1] = surface_off[1] + wl_fixed_to_int(fy); seat->hover_p[1] = surface_off[1] + wl_fixed_to_int(fy);
seat->serial = serial;
} }
static void static void
@ -117,20 +114,16 @@ pointer_leave(void *udata, struct wl_pointer *wl_pointer,
static void static void
pointer_motion(void *udata, struct wl_pointer *wl_pointer, pointer_motion(void *udata, struct wl_pointer *wl_pointer,
CSD_U32 time, wl_fixed_t fx, wl_fixed_t fy){ CSD_U32 time, wl_fixed_t fx, wl_fixed_t fy){
CSD_Seat *seat = &ctx.seat;
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;
CSD_Seat *seat = &ctx.seat;
CSD_S32 surface_off[2] = {0}; CSD_S32 surface_off[2] = {0};
if (seat->hover_surface == window->main_wl_surface){ if (csd_gtk_calc_surface_off(gtk_window, seat->hover_surface, surface_off)){
// surface_off = {0,0} // handled by gtk frame
} }
else if (seat->hover_surface == gtk_window->titlebar.wl_surface){ else if (seat->hover_surface == window->main_wl_surface){
memcpy(surface_off, gtk_window->titlebar.p, sizeof(surface_off)); // app's surface_off = {0,0}
}
else if (seat->hover_surface == gtk_window->shadow.wl_surface){
memcpy(surface_off, gtk_window->shadow.p, sizeof(surface_off));
} }
seat->hover_p[0] = surface_off[0] + wl_fixed_to_int(fx); seat->hover_p[0] = surface_off[0] + wl_fixed_to_int(fx);
@ -154,7 +147,7 @@ pointer_button(void *udata, struct wl_pointer *wl_pointer,
static void static void
pointer_axis(void *udata, struct wl_pointer *wl_pointer, pointer_axis(void *udata, struct wl_pointer *wl_pointer,
CSD_U32 time, CSD_U32 axis, wl_fixed_t fv){ CSD_U32 time, CSD_U32 axis, wl_fixed_t fv){
int v = wl_fixed_to_int(fv); CSD_S32 v = wl_fixed_to_int(fv);
} }
static const struct wl_pointer_listener pointer_listener = { static const struct wl_pointer_listener pointer_listener = {
@ -217,7 +210,8 @@ registry_global(void *udata, struct wl_registry *wl_registry,
else if (strcmp(interface, "wl_seat") == 0){ else if (strcmp(interface, "wl_seat") == 0){
CSD_Seat *seat = &ctx.seat; CSD_Seat *seat = &ctx.seat;
if (seat->wl_seat == 0){ if (seat->wl_seat == 0){
seat->wl_seat = wl_registry_bind(ctx.wl_registry, name, &wl_seat_interface, 3); seat->wl_seat = wl_registry_bind(ctx.wl_registry, name,
&wl_seat_interface, 3);
wl_seat_add_listener(seat->wl_seat, &seat_listener, 0); wl_seat_add_listener(seat->wl_seat, &seat_listener, 0);
seat->cursor_surface = wl_compositor_create_surface(ctx.wl_compositor); seat->cursor_surface = wl_compositor_create_surface(ctx.wl_compositor);
} }
@ -246,7 +240,8 @@ static const struct xdg_surface_listener xdg_surface_listener = {
static void static void
xdg_toplevel_configure(void *udata, struct xdg_toplevel *xdg_toplevel, xdg_toplevel_configure(void *udata, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height, struct wl_array *states){ int32_t width, int32_t height,
struct wl_array *states){
CSD_Window *window = &ctx.window; CSD_Window *window = &ctx.window;
if (width != 0 && height != 0){ if (width != 0 && height != 0){
window->config_staged.dim[0] = width; window->config_staged.dim[0] = width;
@ -353,42 +348,18 @@ int main(){
/* create a window */ /* create a window */
{ {
/* window main surface */ /* window main surface */
CSD_Window *window = &ctx.window; csd_window_init(&ctx.window);
window->main_wl_surface = wl_compositor_create_surface(ctx.wl_compositor);
window->main_xdg_surface = xdg_wm_base_get_xdg_surface(ctx.xdg_wm_base, window->main_wl_surface);
xdg_surface_add_listener(window->main_xdg_surface, &xdg_surface_listener, 0);
window->main_xdg_toplevel = xdg_surface_get_toplevel(window->main_xdg_surface);
xdg_toplevel_add_listener(window->main_xdg_toplevel, &xdg_toplevel_listener, 0);
window->control_flags = ~0;
window->dim[0] = 640;
window->dim[1] = 480;
window->config_staged.decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
if (ctx.zxdg_decoration_manager != 0){
window->main_zxdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(ctx.zxdg_decoration_manager, window->main_xdg_toplevel);
zxdg_toplevel_decoration_v1_add_listener(window->main_zxdg_toplevel_decoration, &zxdg_toplevel_decoration_listener, 0);
}
for (int k = 0; k < 2; k += 1){
window->mmbox[k][0] = 0;
window->mmbox[k][1] = (1 << 30);
}
xdg_toplevel_set_app_id(window->main_xdg_toplevel, "demo");
xdg_toplevel_set_title(window->main_xdg_toplevel, "Example Window");
wl_surface_commit(window->main_wl_surface);
/* window subsurface */
ctx.gtk_window.shadow = csd_subsurface_new();
ctx.gtk_window.titlebar = csd_subsurface_new();
/* window gtk */ /* window gtk */
csd_gtk_window_init(); csd_gtk_window_init(&ctx.gtk_window);
}
/* window egl */
/* window egl */
{
CSD_Window *window = &ctx.window;
ctx.main_wl_egl_window = wl_egl_window_create(window->main_wl_surface, ctx.main_wl_egl_window = wl_egl_window_create(window->main_wl_surface,
window->dim[0], window->dim[1]); window->dim[0],
window->dim[1]);
EGLConfig configs[64]; EGLConfig configs[64];
EGLint config_cap = sizeof(configs)/sizeof(*configs); EGLint config_cap = sizeof(configs)/sizeof(*configs);
@ -406,7 +377,8 @@ int main(){
EGL_STENCIL_SIZE, 8, EGL_STENCIL_SIZE, 8,
EGL_NONE, EGL_NONE,
}; };
eglChooseConfig(ctx.egl_display, attributes, configs, config_cap, &config_count); eglChooseConfig(ctx.egl_display, attributes,
configs, config_cap, &config_count);
} }
{ {
@ -415,7 +387,9 @@ int main(){
EGL_NONE, EGL_NONE,
}; };
for (EGLint i = 0; i < config_count; i += 1){ for (EGLint i = 0; i < config_count; i += 1){
ctx.main_egl_surface = eglCreateWindowSurface(ctx.egl_display, configs[i], ctx.main_wl_egl_window, attributes); ctx.main_egl_surface =
eglCreateWindowSurface(ctx.egl_display, configs[i],
ctx.main_wl_egl_window, attributes);
if (ctx.main_egl_surface != EGL_NO_SURFACE){ if (ctx.main_egl_surface != EGL_NO_SURFACE){
break; break;
} }
@ -468,75 +442,29 @@ int main(){
} }
} }
{ /* setup seats list for frame */
CSD_Window *window = &ctx.window; CSD_Seat *seats[] = {&ctx.seat};
CSD_U32 seat_count = 1;
/* apply config */
if (window->config.serial != window->config_staged.serial){ for (CSD_U32 si = 0; si < seat_count; si += 1){
window->config = window->config_staged; seats[si]->cursor_shape = CSD_CursorShape_Hidden;
xdg_surface_ack_configure(window->main_xdg_surface, window->config.serial);
}
int csd = (window->config.decoration_mode ==
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
/* window sizing */
memset(&window->csd_frame, 0, sizeof window->csd_frame);
memset(window->csd_dim, 0, sizeof window->csd_dim);
if (csd){
window->csd_frame = csd_gtk_calculate_frame();
}
for (int i = 0; i < 2; i += 1){
window->csd_dim[i] = window->csd_frame.border[i][0] + window->csd_frame.border[i][1];
}
for (int i = 0; i < 2; i += 1){
int32_t d = window->config.dim[i] - window->csd_dim[i];
if (!window->handled_first_size){
d = window->dim[i];
window->config.dim[i] = d + window->csd_dim[i];
}
d = CSD_ClampBot(d, window->mmbox[i][0]);
d = CSD_ClampTop(d, window->mmbox[i][1]);
d = CSD_ClampBot(d, window->csd_frame.minbox[i]);
window->dim[i] = d;
}
window->handled_first_size = 1;
/* window size commit */
if (!(window->control_flags & CSD_WindowControlFlag_Resize)){
xdg_toplevel_set_min_size(window->main_xdg_toplevel,
window->dim[0], window->dim[1]);
xdg_toplevel_set_max_size(window->main_xdg_toplevel,
window->dim[0], window->dim[1]);
}
else{
for (int i = 0; i < 2; i += 1){
int32_t mw = window->csd_dim[0] + CSD_ClampBot(window->mmbox[0][i],
window->csd_frame.minbox[i]);
int32_t mh = window->mmbox[1][i] + window->csd_dim[1];
if (i == 0){
xdg_toplevel_set_min_size(window->main_xdg_toplevel, mw, mh);
}
else{
xdg_toplevel_set_max_size(window->main_xdg_toplevel, mw, mh);
}
}
}
xdg_surface_set_window_geometry(window->main_xdg_surface,
-window->csd_frame.border[0][0],
-window->csd_frame.border[1][0],
window->dim[0] + window->csd_dim[0],
window->dim[1] + window->csd_dim[1]);
wl_egl_window_resize(ctx.main_wl_egl_window,
window->dim[0], window->dim[1], 0, 0);
} }
/* apply new window config */
csd_window_apply_new_config(&ctx.window);
/* calculate csd frame */
CSD_Frame csd_frame = csd_gtk_calc_frame(&ctx.window, &ctx.gtk_window);
/* window size update */
csd_window_size_update(&ctx.window, &csd_frame);
/* egl size update */
wl_egl_window_resize(ctx.main_wl_egl_window,
ctx.window.dim[0], ctx.window.dim[1], 0, 0);
/* frame update and render */ /* frame update and render */
{ csd_gtk_update_and_render(&ctx.window, &ctx.gtk_window, seats, seat_count);
CSD_Seat *seat = &ctx.seat;
seat->cursor_shape = CSD_CursorShape_Pointer;
csd_gtk_update_and_render();
}
/* app update & render */ /* app update & render */
{ {
@ -544,6 +472,19 @@ int main(){
if (ctx.close_signal){ if (ctx.close_signal){
exit_loop = 1; exit_loop = 1;
} }
else if (ctx.minimize_signal){
ctx.minimize_signal = 0;
xdg_toplevel_set_minimized(window->main_xdg_toplevel);
}
else if (ctx.maximize_signal){
ctx.maximize_signal = 0;
if (window->config.flags & CSD_WindowFlag_IsMax){
xdg_toplevel_unset_maximized(window->main_xdg_toplevel);
}
else{
xdg_toplevel_set_maximized(window->main_xdg_toplevel);
}
}
glDrawBuffer(GL_BACK); glDrawBuffer(GL_BACK);
glViewport(0, 0, window->dim[0], window->dim[1]); glViewport(0, 0, window->dim[0], window->dim[1]);
@ -560,7 +501,6 @@ int main(){
/* commit new cursor */ /* commit new cursor */
{ {
CSD_Seat *seat = &ctx.seat; CSD_Seat *seat = &ctx.seat;
CSD_Window *window = &ctx.window;
struct wl_cursor *cursor = ctx.wl_cursors[seat->cursor_shape]; struct wl_cursor *cursor = ctx.wl_cursors[seat->cursor_shape];
if (cursor != 0){ if (cursor != 0){
struct wl_cursor_image *cursor_image = cursor->images[0]; struct wl_cursor_image *cursor_image = cursor->images[0];
@ -583,6 +523,103 @@ int main(){
/* csd helpers */ /* csd helpers */
static void
csd_window_init(CSD_Window *window){
window->main_wl_surface = wl_compositor_create_surface(ctx.wl_compositor);
window->main_xdg_surface = xdg_wm_base_get_xdg_surface(ctx.xdg_wm_base, window->main_wl_surface);
xdg_surface_add_listener(window->main_xdg_surface, &xdg_surface_listener, 0);
window->main_xdg_toplevel = xdg_surface_get_toplevel(window->main_xdg_surface);
xdg_toplevel_add_listener(window->main_xdg_toplevel, &xdg_toplevel_listener, 0);
window->control_flags = ~0;
window->dim[0] = 640;
window->dim[1] = 480;
window->config_staged.decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
if (ctx.zxdg_decoration_manager != 0){
window->main_zxdg_toplevel_decoration =
zxdg_decoration_manager_v1_get_toplevel_decoration(ctx.zxdg_decoration_manager,
window->main_xdg_toplevel);
zxdg_toplevel_decoration_v1_add_listener(window->main_zxdg_toplevel_decoration,
&zxdg_toplevel_decoration_listener, 0);
}
for (int k = 0; k < 2; k += 1){
window->mmbox[k][0] = 1;
window->mmbox[k][1] = (1 << 30);
}
xdg_toplevel_set_app_id(window->main_xdg_toplevel, "demo");
xdg_toplevel_set_title(window->main_xdg_toplevel, "Example Window");
wl_surface_commit(window->main_wl_surface);
}
static void
csd_window_apply_new_config(CSD_Window *window){
if (window->config.serial != window->config_staged.serial){
window->config = window->config_staged;
xdg_surface_ack_configure(window->main_xdg_surface, window->config.serial);
}
}
static void
csd_window_size_update(CSD_Window *window, CSD_Frame *csd_frame){
/* window sizing */
memset(&window->csd_frame, 0, sizeof window->csd_frame);
memset(window->csd_dim, 0, sizeof window->csd_dim);
if (window->config.decoration_mode ==
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){
window->csd_frame = *csd_frame;
for (CSD_U32 i = 0; i < 2; i += 1){
window->csd_dim[i] = (csd_frame->border[i][0] +
csd_frame->border[i][1]);
}
}
for (CSD_U32 i = 0; i < 2; i += 1){
int32_t d = window->config.dim[i] - window->csd_dim[i];
if (!window->handled_first_size){
d = window->dim[i];
window->config.dim[i] = d + window->csd_dim[i];
}
d = CSD_ClampBot(d, window->mmbox[i][0]);
d = CSD_ClampTop(d, window->mmbox[i][1]);
d = CSD_ClampBot(d, window->csd_frame.minbox[i]);
window->dim[i] = d;
}
window->handled_first_size = 1;
/* window size commit */
if (!(window->control_flags & CSD_WindowControlFlag_Resize)){
xdg_toplevel_set_min_size(window->main_xdg_toplevel,
window->dim[0], window->dim[1]);
xdg_toplevel_set_max_size(window->main_xdg_toplevel,
window->dim[0], window->dim[1]);
}
else{
for (CSD_S32 i = 0; i < 2; i += 1){
CSD_S32 m[2];
for (CSD_S32 k = 0; k < 2; k += 1){
m[k] = window->mmbox[k][i];
if (i == 0){
m[k] = CSD_ClampBot(m[k], window->csd_frame.minbox[k]);
}
m[k] += window->csd_dim[k];
}
if (i == 0){
xdg_toplevel_set_min_size(window->main_xdg_toplevel, m[0], m[1]);
}
else{
xdg_toplevel_set_max_size(window->main_xdg_toplevel, m[0], m[1]);
}
}
}
xdg_surface_set_window_geometry(window->main_xdg_surface,
-window->csd_frame.border[0][0],
-window->csd_frame.border[1][0],
window->dim[0] + window->csd_dim[0],
window->dim[1] + window->csd_dim[1]);
}
static CSD_SubSurface static CSD_SubSurface
csd_subsurface_new(void){ csd_subsurface_new(void){
CSD_Window *window = &ctx.window; CSD_Window *window = &ctx.window;
@ -957,8 +994,9 @@ csd_gtk_init(void){
} }
static void static void
csd_gtk_window_init(void){ csd_gtk_window_init(CSD_GTK_Window *gtk_window){
CSD_GTK_Window *gtk_window = &ctx.gtk_window; gtk_window->shadow = csd_subsurface_new();
gtk_window->titlebar = csd_subsurface_new();
gtk_window->header = gtk_header_bar_new(); gtk_window->header = gtk_header_bar_new();
gtk_window->window = gtk_offscreen_window_new(); gtk_window->window = gtk_offscreen_window_new();
@ -981,11 +1019,9 @@ csd_gtk_window_init(void){
} }
static CSD_Frame static CSD_Frame
csd_gtk_calculate_frame(void){ csd_gtk_calc_frame(CSD_Window *window, CSD_GTK_Window *gtk_window){
CSD_Window *window = &ctx.window;
CSD_GTK_Window *gtk_window = &ctx.gtk_window;
CSD_Frame frame = {0}; CSD_Frame frame = {0};
bool show_title = (!(window->config.flags & CSD_WindowFlag_IsFullscreen)); CSD_B32 show_title = (!(window->config.flags & CSD_WindowFlag_IsFullscreen));
if (show_title){ if (show_title){
gtk_widget_get_preferred_height(gtk_window->header, 0, &frame.border[1][0]); gtk_widget_get_preferred_height(gtk_window->header, 0, &frame.border[1][0]);
gtk_header_bar_set_title(GTK_HEADER_BAR(gtk_window->header), ""); gtk_header_bar_set_title(GTK_HEADER_BAR(gtk_window->header), "");
@ -995,6 +1031,21 @@ csd_gtk_calculate_frame(void){
return(frame); return(frame);
} }
static CSD_B32
csd_gtk_calc_surface_off(CSD_GTK_Window *gtk_window, struct wl_surface *surface,
CSD_S32 *off){
CSD_B32 result = 0;
if (surface == gtk_window->titlebar.wl_surface){
memcpy(off, gtk_window->titlebar.p, sizeof(gtk_window->titlebar.p));
result = 1;
}
else if (surface == gtk_window->shadow.wl_surface){
memcpy(off, gtk_window->shadow.p, sizeof(gtk_window->shadow.p));
result = 1;
}
return(result);
}
typedef struct CSD_GTK_FindWidgetVars{ typedef struct CSD_GTK_FindWidgetVars{
char *name; char *name;
GtkWidget *widget; GtkWidget *widget;
@ -1027,30 +1078,57 @@ csd_gtk__widget_from_name(GtkWidget *root, char *name){
#define SHADOW_MARGIN 24 #define SHADOW_MARGIN 24
static void static void
csd_gtk_update_and_render(void){ csd_gtk_update_and_render(CSD_Window *window, CSD_GTK_Window *gtk_window,
CSD_Seat *seat = &ctx.seat; CSD_Seat **seats, CSD_U32 seat_count){
CSD_Window *window = &ctx.window;
CSD_GTK_Window *gtk_window = &ctx.gtk_window;
/* determine cursor location information */ /* 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)
};
/* per-cursor locals */
enum{ enum{
LOCATION_NULL, LOCATION_SHADOW, LOCATION_TITLEBAR, LOCATION_NULL, LOCATION_SHADOW, LOCATION_TITLEBAR,
}; };
CSD_U32 cursor_loc = LOCATION_NULL; struct CursorVars{
CSD_S32 cursor_shadow_loc = 0; CSD_U32 loc;
{ CSD_S32 shadow_loc;
{ CSD_U32 header_button_hover;
CSD_S32 l = (seat->hover_p[0] < 0); } CursorVars;
CSD_S32 r = (!l && seat->hover_p[0] >= window->dim[0]); struct CursorVars *cursors = alloca(sizeof(struct CursorVars)*seat_count);
CSD_S32 t = (seat->hover_p[1] < -window->csd_frame.border[1][0]); memset(cursors, 0, sizeof(struct CursorVars)*seat_count);
CSD_S32 b = (!t && seat->hover_p[1] >= window->dim[1]);
cursor_shadow_loc = 3*(b - t) + (r - l); /* determine cursor location information */
} for (CSD_U32 si = 0; si < seat_count; si += 1){
if (cursor_shadow_loc != 0){ CSD_Seat *seat = seats[si];
cursor_loc = LOCATION_SHADOW;
} if (seat->hover_surface == window->main_wl_surface ||
else if (seat->hover_p[1] < 0){ seat->hover_surface == gtk_window->titlebar.wl_surface ||
cursor_loc = LOCATION_TITLEBAR; seat->hover_surface == gtk_window->shadow.wl_surface){
CSD_B32 l = (seat->hover_p[0] < 0);
CSD_B32 r = (!l && seat->hover_p[0] >= window->dim[0]);
CSD_B32 t = (seat->hover_p[1] < -window->csd_frame.border[1][0]);
CSD_B32 b = (!t && seat->hover_p[1] >= window->dim[1]);
cursors[si].shadow_loc = 3*(b - t) + (r - l);
if (cursors[si].shadow_loc != 0){
cursors[si].loc = LOCATION_SHADOW;
}
else if (seat->hover_p[1] < 0){
cursors[si].loc = LOCATION_TITLEBAR;
}
} }
} }
@ -1098,25 +1176,6 @@ 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 */ /* draw frame */
{ {
CSD_SubSurface *subsurface = &gtk_window->titlebar; CSD_SubSurface *subsurface = &gtk_window->titlebar;
@ -1216,17 +1275,21 @@ csd_gtk_update_and_render(void){
GtkAllocation rect; GtkAllocation rect;
gtk_widget_get_clip(widget, &rect); gtk_widget_get_clip(widget, &rect);
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];
/* check pointer hover */ /* check pointer hover */
CSD_B32 is_hovered = 0; CSD_B32 is_hovered = 0;
{ for (CSD_U32 si = 0; si < seat_count; si += 1){
CSD_S32 x0 = rect.x; if (cursors[si].loc == LOCATION_TITLEBAR){
CSD_S32 y0 = rect.y - title_dim[1]; CSD_Seat *seat = seats[si];
CSD_S32 x1 = rect.x + rect.width; if (x0 <= seat->hover_p[0] && seat->hover_p[0] < x1 &&
CSD_S32 y1 = rect.y + rect.height - title_dim[1]; y0 <= seat->hover_p[1] && seat->hover_p[1] < y1){
if (x0 <= seat->hover_p[0] && seat->hover_p[0] < x1 && cursors[si].header_button_hover = i;
y0 <= seat->hover_p[1] && seat->hover_p[1] < y1){ is_hovered = 1;
header_button_hover = i; }
is_hovered = 1;
} }
} }
@ -1324,26 +1387,30 @@ csd_gtk_update_and_render(void){
/* handle left-button press */ /* handle left-button press */
if (ctx.event_button == BTN_LEFT && if (ctx.event_button == BTN_LEFT &&
ctx.event_button_state == 1){ ctx.event_button_state == 1){
switch (cursor_loc){ CSD_U32 si = 0;
switch (cursors[si].loc){
default: case LOCATION_NULL: break; default: case LOCATION_NULL: break;
case LOCATION_SHADOW: { case LOCATION_SHADOW: {
#define X(N) XDG_TOPLEVEL_RESIZE_EDGE_##N
static const enum xdg_toplevel_resize_edge xedge_box[] = { 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, X(TOP_LEFT), X(TOP), X(TOP_RIGHT),
XDG_TOPLEVEL_RESIZE_EDGE_LEFT, XDG_TOPLEVEL_RESIZE_EDGE_NONE, XDG_TOPLEVEL_RESIZE_EDGE_RIGHT, X(LEFT), X(NONE), X(RIGHT),
XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT, X(BOTTOM_LEFT), X(BOTTOM), X(BOTTOM_RIGHT),
}; };
xdg_toplevel_resize(window->main_xdg_toplevel, seat->wl_seat, #undef X
seat->serial, xedge_box[4 + cursor_shadow_loc]); xdg_toplevel_resize(window->main_xdg_toplevel, seats[si]->wl_seat,
seats[si]->serial, xedge_box[4 + cursors[si].shadow_loc]);
ctx.has_event = 0; ctx.has_event = 0;
}break; }break;
case LOCATION_TITLEBAR: { case LOCATION_TITLEBAR: {
if (header_button_hover == 0){ if (cursors[si].header_button_hover == 0){
xdg_toplevel_move(window->main_xdg_toplevel, seat->wl_seat, seat->serial); xdg_toplevel_move(window->main_xdg_toplevel,
seats[si]->wl_seat, seats[si]->serial);
} }
else{ else{
gtk_window->active_header_button = header_button_hover; gtk_window->active_header_button = cursors[si].header_button_hover;
} }
ctx.has_event = 0; ctx.has_event = 0;
}break; }break;
@ -1353,25 +1420,31 @@ csd_gtk_update_and_render(void){
/* handle left-button release */ /* handle left-button release */
if (ctx.event_button == BTN_LEFT && if (ctx.event_button == BTN_LEFT &&
ctx.event_button_state == 0){ ctx.event_button_state == 0){
CSD_U32 si = 0;
if (gtk_window->active_header_button != 0 && if (gtk_window->active_header_button != 0 &&
gtk_window->active_header_button == header_button_hover){ gtk_window->active_header_button == cursors[si].header_button_hover){
// activate button effect here switch (gtk_window->active_header_button){
case HEADER_BUTTON_MIN: { ctx.minimize_signal = 1; } break;
case HEADER_BUTTON_MAX: { ctx.maximize_signal = 1; } break;
case HEADER_BUTTON_CLOSE: { ctx.close_signal = 1; } break;
}
gtk_window->active_header_button = 0;
} }
gtk_window->active_header_button = 0;
} }
} }
/* set cursor shape */ /* set cursor shape */
if (window->control_flags & CSD_WindowControlFlag_Resize){ for (CSD_U32 si = 0; si < seat_count; si += 1){
static const CSD_CursorShape cursor_box[] = { if (window->control_flags & CSD_WindowControlFlag_Resize){
CSD_CursorShape_Resize_TopLeft, CSD_CursorShape_Resize_Top, CSD_CursorShape_Resize_TopRight, #define X(N) CSD_CursorShape_##N
CSD_CursorShape_Resize_Left, CSD_CursorShape_Pointer, CSD_CursorShape_Resize_Right, static const CSD_CursorShape cursor_box[] = {
CSD_CursorShape_Resize_BottomLeft, CSD_CursorShape_Resize_Bottom, CSD_CursorShape_Resize_BottomRight, X(Resize_TopLeft), X(Resize_Top), X(Resize_TopRight),
}; X(Resize_Left), X(Pointer), X(Resize_Right),
seat->cursor_shape = cursor_box[4 + cursor_shadow_loc]; X(Resize_BottomLeft), X(Resize_Bottom), X(Resize_BottomRight),
} };
else{ #undef X
seat->cursor_shape = CSD_CursorShape_Pointer; seats[si]->cursor_shape = cursor_box[4 + cursors[si].shadow_loc];
}
} }
} }

View File

@ -133,6 +133,10 @@ typedef struct CSD_Seat{
/* csd helpers */ /* csd helpers */
static void csd_window_init(CSD_Window *window);
static void csd_window_apply_new_config(CSD_Window *window);
static void csd_window_size_update(CSD_Window *window, CSD_Frame *csd_frame);
static CSD_SubSurface csd_subsurface_new(void); static CSD_SubSurface csd_subsurface_new(void);
static void csd_subsurface_buffer_clear(CSD_SubSurface *subsurface); static void csd_subsurface_buffer_clear(CSD_SubSurface *subsurface);
static void csd_subsurface_buffer_alloc(CSD_SubSurface *subsurface, CSD_S32 dim[2]); static void csd_subsurface_buffer_alloc(CSD_SubSurface *subsurface, CSD_S32 dim[2]);
@ -180,10 +184,14 @@ typedef struct CSD_GTK_Window{
/* csd gtk implementation */ /* csd gtk implementation */
static void csd_gtk_init(void); static void csd_gtk_init(void);
static void csd_gtk_window_init(void); static void csd_gtk_window_init(CSD_GTK_Window *gtk_window);
static CSD_Frame csd_gtk_calculate_frame(void); static CSD_Frame csd_gtk_calc_frame(CSD_Window *window, CSD_GTK_Window *gtk_window);
static CSD_B32 csd_gtk_calc_surface_off(CSD_GTK_Window *gtk_window,
struct wl_surface *surface,
CSD_S32 *off);
static void csd_gtk_update_and_render(void); static void csd_gtk_update_and_render(CSD_Window *window, CSD_GTK_Window *gtk_window,
CSD_Seat **seats, CSD_U32 seat_count);
/* csd gtk cairo shadow rendering */ /* csd gtk cairo shadow rendering */
@ -198,6 +206,8 @@ static void csd_gtk_render_shadow(cairo_t *cr, cairo_surface_t *surface,
typedef struct Ctx{ typedef struct Ctx{
/* the rest */ /* the rest */
CSD_B32 close_signal; CSD_B32 close_signal;
CSD_B32 minimize_signal;
CSD_B32 maximize_signal;
CSD_B32 has_event; CSD_B32 has_event;
CSD_U32 event_button; CSD_U32 event_button;