From b3c534bdeb82f31d1a30d609b2fe42c128d9b560 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Fri, 8 Dec 2023 18:04:07 +0100 Subject: Add class hint, wm name, window type --- include/mgl/window/window.h | 7 +++++++ src/window/window.c | 48 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/include/mgl/window/window.h b/include/mgl/window/window.h index cbcdb1a..12a7aef 100644 --- a/include/mgl/window/window.h +++ b/include/mgl/window/window.h @@ -60,6 +60,11 @@ struct mgl_window { int num_monitors; }; +typedef enum { + MGL_WINDOW_TYPE_NORMAL, + MGL_WINDOW_TYPE_DIALOG +} mgl_window_type; + /* TODO: Some of these parameters only apply to new window */ typedef struct { mgl_vec2i position; @@ -71,6 +76,8 @@ typedef struct { bool override_redirect; /* false by default */ bool support_alpha; /* support alpha for the window, false by default */ mgl_color background_color; /* default: black */ + const char *class_name; + mgl_window_type window_type; /* default: normal */ } mgl_window_create_params; typedef enum { diff --git a/src/window/window.c b/src/window/window.c index 72f8598..ba4e8d5 100644 --- a/src/window/window.c +++ b/src/window/window.c @@ -69,7 +69,12 @@ typedef struct { Atom image_gif_atom; Atom incr_atom; Atom net_wm_state_atom; - Atom wm_state_fullscreen_atom; + Atom net_wm_state_fullscreen_atom; + Atom net_wm_state_above_atom; + Atom net_wm_name_atom; + Atom net_wm_window_type_atom; + Atom net_wm_window_type_normal_atom; + Atom net_wm_window_type_dialog_atom; Cursor default_cursor; Cursor invisible_cursor; unsigned int prev_keycode_pressed; @@ -160,7 +165,12 @@ static int x11_context_init(x11_context *self, bool alpha) { self->image_gif_atom = XInternAtom(context->connection, "image/gif", False); self->incr_atom = XInternAtom(context->connection, "INCR", False); self->net_wm_state_atom = XInternAtom(context->connection, "_NET_WM_STATE", False); - self->wm_state_fullscreen_atom = XInternAtom(context->connection, "_NET_WM_STATE_FULLSCREEN", False); + self->net_wm_state_fullscreen_atom = XInternAtom(context->connection, "_NET_WM_STATE_FULLSCREEN", False); + self->net_wm_state_above_atom = XInternAtom(context->connection, "_NET_WM_STATE_ABOVE", False); + self->net_wm_name_atom = XInternAtom(context->connection, "_NET_WM_NAME", False); + self->net_wm_window_type_atom = XInternAtom(context->connection, "_NET_WM_WINDOW_TYPE", False); + self->net_wm_window_type_normal_atom = XInternAtom(context->connection, "_NET_WM_WINDOW_TYPE_NORMAL", False); + self->net_wm_window_type_dialog_atom = XInternAtom(context->connection, "_NET_WM_WINDOW_TYPE_DIALOG", False); self->default_cursor = None; self->invisible_cursor = None; @@ -473,6 +483,22 @@ static unsigned long mgl_color_to_x11_pixel(mgl_color color) { return ((uint32_t)color.a << 24) | ((uint32_t)color.r << 16) | ((uint32_t)color.g << 8) | (uint32_t)color.b; } +static void mgl_set_window_type(mgl_window *self, mgl_window_type window_type) { + mgl_context *context = mgl_get_context(); + x11_context *x11_context = self->context; + switch(window_type) { + case MGL_WINDOW_TYPE_NORMAL: { + XChangeProperty(context->connection, self->window, x11_context->net_wm_window_type_atom, XA_ATOM, 32, PropModeReplace, (unsigned char*)&x11_context->net_wm_window_type_normal_atom, 1L); + break; + } + case MGL_WINDOW_TYPE_DIALOG: { + XChangeProperty(context->connection, self->window, x11_context->net_wm_window_type_atom, XA_ATOM, 32, PropModeReplace, (unsigned char*)&x11_context->net_wm_window_type_dialog_atom, 1L); + XChangeProperty(context->connection, self->window, x11_context->net_wm_state_atom, XA_ATOM, 32, PropModeReplace, (unsigned char*)&x11_context->net_wm_state_above_atom, 1L); + break; + } + } +} + static int mgl_window_init(mgl_window *self, const char *title, const mgl_window_create_params *params, Window existing_window) { self->window = 0; self->context = NULL; @@ -573,7 +599,7 @@ static int mgl_window_init(mgl_window *self, const char *title, const mgl_window return -1; } - XStoreName(context->connection, self->window, title); + mgl_window_set_title(self, title); if(!hide_window) XMapWindow(context->connection, self->window); } @@ -594,6 +620,14 @@ static int mgl_window_init(mgl_window *self, const char *title, const mgl_window 32, PropModeReplace, (const unsigned char*)&pid, 1); } + if(params && params->class_name) { + XClassHint class_hint = { params->class_name, params->class_name }; + XSetClassHint(context->connection, self->window, &class_hint); + } + + mgl_window_type window_type = params ? params->window_type : MGL_WINDOW_TYPE_NORMAL; + mgl_set_window_type(self, window_type); + XFlush(context->connection); /* TODO: Check for failure? */ @@ -1306,7 +1340,11 @@ void mgl_window_close(mgl_window *self) { void mgl_window_set_title(mgl_window *self, const char *title) { mgl_context *context = mgl_get_context(); + x11_context *x11_context = self->context; + XStoreName(context->connection, self->window, title); + XChangeProperty(context->connection, self->window, x11_context->net_wm_name_atom, x11_context->utf8_string_atom, 8, PropModeReplace, (unsigned char*)title, strlen(title)); + XFlush(context->connection); } void mgl_window_set_cursor_visible(mgl_window *self, bool visible) { @@ -1341,7 +1379,7 @@ void mgl_window_set_fullscreen(mgl_window *self, bool fullscreen) { xev.xclient.message_type = x11_context->net_wm_state_atom; xev.xclient.format = 32; xev.xclient.data.l[0] = fullscreen ? 1 : 0; - xev.xclient.data.l[1] = x11_context->wm_state_fullscreen_atom; + xev.xclient.data.l[1] = x11_context->net_wm_state_fullscreen_atom; xev.xclient.data.l[2] = 0; xev.xclient.data.l[3] = 1; xev.xclient.data.l[4] = 0; @@ -1365,7 +1403,7 @@ bool mgl_window_is_fullscreen(const mgl_window *self) { unsigned long remaining_bytes = 0; unsigned char *data = NULL; if(XGetWindowProperty(context->connection, self->window, x11_context->net_wm_state_atom, 0, 1024, False, PropertyNewValue, &type, &format, &items, &remaining_bytes, &data) == Success && data) { - is_fullscreen = format == 32 && *(unsigned long*)data == x11_context->wm_state_fullscreen_atom; + is_fullscreen = format == 32 && *(unsigned long*)data == x11_context->net_wm_state_fullscreen_atom; XFree(data); } return is_fullscreen; -- cgit v1.2.3