显示窗口

This commit is contained in:
2025-08-22 15:47:58 +08:00
parent 2a7ab324be
commit c3bcb7ddd2
9 changed files with 274 additions and 14 deletions

View File

@@ -92,3 +92,4 @@ const uint32_t dpi_fallback = 96;
const uint32_t bar_y_padding = 1; const uint32_t bar_y_padding = 1;
const uint32_t tag_x_padding = 10; const uint32_t tag_x_padding = 10;
const uint32_t border_width = 1;

View File

@@ -2,6 +2,8 @@
#include <stdint.h> #include <stdint.h>
#include "types.h"
typedef enum event_type_t { typedef enum event_type_t {
EVENT_TYPE_MAPPING_NOTIFY, EVENT_TYPE_MAPPING_NOTIFY,
EVENT_TYPE_KEY_PRESS, EVENT_TYPE_KEY_PRESS,
@@ -35,6 +37,13 @@ typedef struct button_press_event_t {
typedef struct configure_request_event_t { typedef struct configure_request_event_t {
event_type_t type; event_type_t type;
xcb_window_t window;
xcb_window_t parent;
xcb_window_t sibling;
int32_t x, y;
uint32_t width, height, border_width;
uint32_t value_mask;
uint8_t stack_mode;
} configure_request_event_t; } configure_request_event_t;
typedef struct configure_notify_event_t { typedef struct configure_notify_event_t {
@@ -43,6 +52,8 @@ typedef struct configure_notify_event_t {
typedef struct map_request_event_t { typedef struct map_request_event_t {
event_type_t type; event_type_t type;
xcb_window_t window;
xcb_window_t parent;
} map_request_event_t; } map_request_event_t;
typedef struct unmap_notify_event_t { typedef struct unmap_notify_event_t {

View File

@@ -38,11 +38,12 @@ struct monitor_t {
struct client_t { struct client_t {
char name[256]; char name[256];
int32_t x, y; int32_t x, y, old_x, old_y;
uint32_t width, height, border_width; uint32_t width, height, border_width, old_width, old_height, old_border_width;
uint32_t tags; uint32_t tags;
bool fullscreen; bool fullscreen;
bool floating; bool floating;
bool maximize;
monitor_t *monitor; monitor_t *monitor;
client_t *next; client_t *next;

View File

@@ -5,8 +5,11 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include "types.h" #include "types.h"
#define WINDOW_NONE XCB_WINDOW_NONE
bool has_other_wm_running(void); bool has_other_wm_running(void);
int get_xcb_connection_fd(void); int get_xcb_connection_fd(void);
void flush_xcb_connection(void); void flush_xcb_connection(void);
@@ -17,7 +20,27 @@ typedef enum cursor_t {
cursor_move = XC_fleur, cursor_move = XC_fleur,
} cursor_t; } cursor_t;
void change_window_cursor(xcb_window_t window, cursor_t cursor); void change_window_cursor(xcb_window_t window, cursor_t cursor);
void set_root_cursor(cursor_t cursor); xcb_window_t get_root_window(void);
bool get_window_visible(xcb_window_t window);
xcb_window_t get_transient_window_for(xcb_window_t window);
typedef struct window_geometry_t {
int32_t x, y;
uint32_t width, height, border_width;
} window_geometry_t;
/**
* @brief 获取窗口的几何信息
* @returns 返回几何信息指针,使用完后记得使用 free 释放内存
*/
window_geometry_t *get_window_geometry(xcb_window_t window);
void map_window(xcb_window_t window);
/**
* @brief 获取窗口名
* @returns 返回窗口名字符串指针,使用完后记得使用 free 释放内存
*/
char *get_window_name(xcb_window_t window);
void init_window_event_mask(xcb_window_t window);
void change_window_border_color(xcb_window_t window, uint32_t argb);
typedef struct bar_cairo_params_t { typedef struct bar_cairo_params_t {
xcb_connection_t *conn; xcb_connection_t *conn;
@@ -32,6 +55,8 @@ bar_cairo_params_t *create_bar_window(int16_t x, int16_t y, uint16_t width,
uint16_t height, uint32_t background_argb, uint16_t height, uint32_t background_argb,
cursor_t cursor); cursor_t cursor);
void destroy_window(xcb_window_t window); void destroy_window(xcb_window_t window);
void configure_window(xcb_window_t window, int32_t x, int32_t y, uint32_t width,
uint32_t height, uint32_t border_width);
typedef struct monitor_rect_t monitor_rect_t; typedef struct monitor_rect_t monitor_rect_t;
struct monitor_rect_t { struct monitor_rect_t {

View File

@@ -34,6 +34,15 @@ static void update_bars(void);
static void init_xcb_event_loop(void); static void init_xcb_event_loop(void);
static void xcb_event_handler(generic_event_t *event, void *user_data); static void xcb_event_handler(generic_event_t *event, void *user_data);
static void key_press(key_press_event_t *event); static void key_press(key_press_event_t *event);
static void configure_request(configure_request_event_t *event);
static void map_request(map_request_event_t *event);
static void manage_window(xcb_window_t window);
static void update_client_name(client_t *client);
static void apply_rules(client_t *client);
static void attach_client(client_t *client);
static void show_hide_client(client_t *client);
static void apply_monitor_layout(monitor_t *monitor);
static client_t *get_client_of_window(xcb_window_t window);
static gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition, static gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition,
gpointer userdata); gpointer userdata);
static void cleanup(void); static void cleanup(void);
@@ -50,6 +59,7 @@ static uint32_t dpi = dpi_fallback;
static uint32_t bar_y_pad = bar_y_padding; static uint32_t bar_y_pad = bar_y_padding;
static uint32_t tag_x_pad = tag_x_padding; static uint32_t tag_x_pad = tag_x_padding;
static uint32_t bar_height = 0; static uint32_t bar_height = 0;
static uint32_t border_px = border_width;
static bool need_restart = false; static bool need_restart = false;
@@ -358,6 +368,7 @@ void get_xresource_config(void) {
get_xresource_uint32("zswm.font_size", &font_size); get_xresource_uint32("zswm.font_size", &font_size);
get_xresource_uint32("zswm.bar_y_padding", &bar_y_pad); get_xresource_uint32("zswm.bar_y_padding", &bar_y_pad);
get_xresource_uint32("zswm.tag_x_padding", &tag_x_pad); get_xresource_uint32("zswm.tag_x_padding", &tag_x_pad);
get_xresource_uint32("zswm.border_width", &border_px);
printf("dpi: %u, font family: %s, font size: %u\n", dpi, font_family, printf("dpi: %u, font family: %s, font size: %u\n", dpi, font_family,
font_size); font_size);
@@ -383,9 +394,17 @@ void init_xcb_event_loop(void) {
void xcb_event_handler(generic_event_t *event, void *user_data) { void xcb_event_handler(generic_event_t *event, void *user_data) {
switch (event->type) { switch (event->type) {
case EVENT_TYPE_KEY_PRESS: #define EVENT(type, callback) \
key_press((key_press_event_t *)event); case type: \
break; callback((void *)event); \
break
EVENT(EVENT_TYPE_KEY_PRESS, key_press);
EVENT(EVENT_TYPE_CONFIGURE_REQUEST, configure_request);
EVENT(EVENT_TYPE_MAP_REQUEST, map_request);
#undef EVENT
default: default:
break; break;
} }
@@ -402,6 +421,93 @@ void key_press(key_press_event_t *event) {
} }
} }
void configure_request(configure_request_event_t *event) {
client_t *client = get_client_of_window(event->window);
if (!client) {
configure_window(event->window, event->x, event->y, event->width,
event->height, event->border_width);
flush_xcb_connection();
return;
}
printf("window: %u, parent: %u, sibling: %u\n", event->window, event->parent,
event->sibling);
printf("x: %d, y: %d, w: %u, h: %u, bw: %u\n", event->x, event->y,
event->width, event->height, event->border_width);
printf("mask: %u, stack: %u\n", event->value_mask, event->stack_mode);
}
void map_request(map_request_event_t *event) {
if (!get_window_visible(event->window)) return;
if (get_client_of_window(event->window)) return;
if (event->parent != get_root_window()) return;
manage_window(event->window);
}
void manage_window(xcb_window_t window) {
window_geometry_t *geometry = get_window_geometry(window);
client_t *c = ecalloc(1, sizeof(client_t));
c->window = window;
c->x = c->old_x = geometry->x;
c->y = c->old_y = geometry->y;
c->width = c->old_width = geometry->width;
c->height = c->old_height = geometry->height;
c->old_border_width = geometry->border_width;
c->border_width = border_px;
update_client_name(c);
printf("== manage window: %u\n", window);
printf("== x: %d, y: %d, w: %u, h: %u, bw: %u\n", c->x, c->y, c->width,
c->height, c->border_width);
xcb_window_t tw = get_transient_window_for(window);
client_t *tc = NULL;
if (tw != WINDOW_NONE && (tc = get_client_of_window(tw))) {
c->monitor = tc->monitor;
c->tags = tc->tags;
} else {
c->monitor = current_monitor;
apply_rules(c);
}
attach_client(c);
apply_monitor_layout(c->monitor);
init_window_event_mask(window);
change_window_border_color(window, color_set->border_color.argb);
map_window(window);
show_hide_client(c);
flush_xcb_connection();
update_bars();
}
void update_client_name(client_t *client) {
char *name = get_window_name(client->window);
strncpy(client->name, name, sizeof(client->name) - 1);
free(name);
}
void apply_rules(client_t *client) { /* TODO: */ }
void attach_client(client_t *client) {
client->next = client->monitor->clients;
client->monitor->clients = client;
}
void show_hide_client(client_t *client) { /* TODO: */ }
void apply_monitor_layout(monitor_t *monitor) { /* TODO: */ }
client_t *get_client_of_window(xcb_window_t window) {
for (monitor_t *m = monitors; m; m = m->next) {
for (client_t *c = m->clients; c; c = c->next) {
if (c->window == window) return c;
}
}
return NULL;
}
gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition, gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition,
gpointer userdata) { gpointer userdata) {
if (condition & (G_IO_HUP | G_IO_ERR)) { if (condition & (G_IO_HUP | G_IO_ERR)) {
@@ -456,7 +562,7 @@ int main(int argc, char *argv[]) {
init_monitors(); init_monitors();
init_color_set(); init_color_set();
init_monitor_bar(); init_monitor_bar();
set_root_cursor(cursor_normal); change_window_cursor(get_root_window(), cursor_normal);
init_wallpaper(); init_wallpaper();
update_bars(); update_bars();

View File

@@ -36,15 +36,32 @@ static void convert_event(xcb_generic_event_t *xcb_event,
case XCB_BUTTON_PRESS: case XCB_BUTTON_PRESS:
event->type = EVENT_TYPE_BUTTON_PRESS; event->type = EVENT_TYPE_BUTTON_PRESS;
break; break;
case XCB_CONFIGURE_REQUEST: case XCB_CONFIGURE_REQUEST: {
event->type = EVENT_TYPE_CONFIGURE_REQUEST; xcb_configure_request_event_t *ev =
(xcb_configure_request_event_t *)xcb_event;
event->configure_request.type = EVENT_TYPE_CONFIGURE_REQUEST;
event->configure_request.window = ev->window;
event->configure_request.parent = ev->parent;
event->configure_request.sibling = ev->sibling;
event->configure_request.x = ev->x;
event->configure_request.y = ev->y;
event->configure_request.width = ev->width;
event->configure_request.height = ev->height;
event->configure_request.border_width = ev->border_width;
event->configure_request.value_mask = ev->value_mask;
event->configure_request.stack_mode = ev->stack_mode;
break; break;
}
case XCB_CONFIGURE_NOTIFY: case XCB_CONFIGURE_NOTIFY:
event->type = EVENT_TYPE_CONFIGURE_NOTIFY; event->type = EVENT_TYPE_CONFIGURE_NOTIFY;
break; break;
case XCB_MAP_REQUEST: case XCB_MAP_REQUEST: {
event->type = EVENT_TYPE_MAP_REQUEST; xcb_map_request_event_t *ev = (xcb_map_request_event_t *)xcb_event;
event->map_request.type = EVENT_TYPE_MAP_REQUEST;
event->map_request.window = ev->window;
event->map_request.parent = ev->parent;
break; break;
}
case XCB_UNMAP_NOTIFY: case XCB_UNMAP_NOTIFY:
event->type = EVENT_TYPE_UNMAP_NOTIFY; event->type = EVENT_TYPE_UNMAP_NOTIFY;
break; break;

View File

@@ -5,6 +5,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb_ewmh.h>
#include <xcb/xcb_icccm.h> #include <xcb/xcb_icccm.h>
#include <xcb/xproto.h> #include <xcb/xproto.h>
@@ -155,6 +157,21 @@ bar_cairo_params_t *create_bar_window(int16_t x, int16_t y, uint16_t width,
void destroy_window(xcb_window_t window) { xcb_destroy_window(conn, window); } void destroy_window(xcb_window_t window) { xcb_destroy_window(conn, window); }
void configure_window(xcb_window_t window, int32_t x, int32_t y, uint32_t width,
uint32_t height, uint32_t border_width) {
xcb_config_window_t config_mask =
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH |
XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH;
xcb_params_configure_window_t window_config = {
.x = x,
.y = y,
.width = width,
.height = height,
.border_width = border_width,
};
xcb_aux_configure_window(conn, window, config_mask, &window_config);
}
void change_window_cursor(xcb_window_t window, cursor_t cursor) { void change_window_cursor(xcb_window_t window, cursor_t cursor) {
xcb_change_window_attributes_value_list_t value_list = { xcb_change_window_attributes_value_list_t value_list = {
.cursor = get_xcb_cursor(cursor), .cursor = get_xcb_cursor(cursor),
@@ -163,6 +180,86 @@ void change_window_cursor(xcb_window_t window, cursor_t cursor) {
xcb_flush(conn); xcb_flush(conn);
} }
void set_root_cursor(cursor_t cursor) { xcb_window_t get_root_window(void) { return screen->root; }
change_window_cursor(screen->root, cursor);
bool get_window_visible(xcb_window_t window) {
xcb_get_window_attributes_cookie_t cookie =
xcb_get_window_attributes(conn, window);
xcb_get_window_attributes_reply_t *reply =
xcb_get_window_attributes_reply(conn, cookie, NULL);
bool visible =
!reply->override_redirect && reply->map_state != XCB_MAP_STATE_UNVIEWABLE;
free(reply);
return visible;
}
xcb_window_t get_transient_window_for(xcb_window_t window) {
xcb_window_t transient_for = XCB_NONE;
xcb_get_property_cookie_t cookie =
xcb_icccm_get_wm_transient_for(conn, window);
xcb_icccm_get_wm_transient_for_reply(conn, cookie, &transient_for, NULL);
return transient_for;
}
window_geometry_t *get_window_geometry(xcb_window_t window) {
xcb_get_geometry_cookie_t cookie = xcb_get_geometry(conn, window);
xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(conn, cookie, NULL);
window_geometry_t *geometry = ecalloc(1, sizeof(window_geometry_t));
geometry->x = reply->x;
geometry->y = reply->y;
geometry->width = reply->width;
geometry->height = reply->height;
geometry->border_width = reply->border_width;
free(reply);
return geometry;
}
void map_window(xcb_window_t window) {
xcb_map_window(conn, window);
xcb_map_subwindows(conn, window);
}
char *get_window_name(xcb_window_t window) {
xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_name(ewmh, window);
xcb_ewmh_get_utf8_strings_reply_t reply;
xcb_ewmh_get_wm_name_reply(ewmh, cookie, &reply, NULL);
if (reply.strings_len) {
char *name = ecalloc(reply.strings_len + 1, sizeof(char));
strncpy(name, reply.strings, reply.strings_len);
return name;
}
cookie = xcb_icccm_get_wm_name(conn, window);
xcb_icccm_get_text_property_reply_t prop;
xcb_icccm_get_wm_name_reply(conn, cookie, &prop, NULL);
if (prop.name_len) {
char *name = ecalloc(prop.name_len + 1, sizeof(char));
strncpy(name, prop.name, prop.name_len);
return name;
}
{
const char *broken = "broken";
char *name = ecalloc(strlen(broken) + 1, sizeof(char));
strncpy(name, broken, strlen(broken));
return name;
}
}
void init_window_event_mask(xcb_window_t window) {
xcb_cw_t change_mask = XCB_CW_EVENT_MASK;
xcb_params_cw_t params = {
.event_mask = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE |
XCB_EVENT_MASK_PROPERTY_CHANGE |
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
};
xcb_aux_change_window_attributes(conn, window, change_mask, &params);
}
void change_window_border_color(xcb_window_t window, uint32_t argb) {
xcb_params_cw_t params = {.border_pixel = argb};
xcb_aux_change_window_attributes(conn, window, XCB_CW_BORDER_PIXEL, &params);
} }

View File

@@ -1,9 +1,11 @@
#pragma once #pragma once
#include <xcb/xcb_ewmh.h>
#include <xcb/xcb_keysyms.h> #include <xcb/xcb_keysyms.h>
#include "xcb.h" #include "xcb.h"
extern xcb_ewmh_connection_t *ewmh;
extern xcb_connection_t *conn; extern xcb_connection_t *conn;
extern xcb_screen_t *screen; extern xcb_screen_t *screen;
extern xcb_key_symbols_t *key_symbols; extern xcb_key_symbols_t *key_symbols;

View File

@@ -170,7 +170,7 @@ void set_wallpaper(uint32_t *wallpaper_data) {
xcb_flush(conn); xcb_flush(conn);
} }
static xcb_ewmh_connection_t *ewmh = NULL; xcb_ewmh_connection_t *ewmh = NULL;
static bool ewmh_init_failed = false; static bool ewmh_init_failed = false;
static xcb_window_t wm_check_window = XCB_NONE; static xcb_window_t wm_check_window = XCB_NONE;
static void init_ewmh_extension(void) { static void init_ewmh_extension(void) {