显示窗口
This commit is contained in:
@@ -2,5 +2,13 @@ _XKB_RULES_NAMES
|
||||
|
||||
WM_PROTOCOLS
|
||||
WM_TAKE_FOCUS
|
||||
WM_NAME
|
||||
WM_ICON_NAME
|
||||
WM_WINDOW_ROLE
|
||||
|
||||
UTF8_STRING
|
||||
COMPOUND_TEXT
|
||||
|
||||
_NET_ACTIVE_WINDOW
|
||||
_NET_WM_NAME
|
||||
_NET_WM_ICON_NAME
|
||||
|
||||
108
src/client.c
108
src/client.c
@@ -1 +1,109 @@
|
||||
#include "client.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_aux.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
#include "atoms-extern.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "wm.h"
|
||||
#include "xwindow.h"
|
||||
|
||||
client_t *client_get_by_window(xcb_window_t window) {
|
||||
for (client_t *c = wm.client_list; c; c = c->next) {
|
||||
if (c->window == window) return c;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void client_attach_list(client_t *client) {
|
||||
client->next = wm.client_list;
|
||||
wm.client_list = client;
|
||||
}
|
||||
|
||||
static void client_detach_list(client_t *client) {
|
||||
for (client_t **c = &wm.client_list; *c && *c != client; c = &(*c)->next) {
|
||||
*c = client->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void client_attach_stack(client_t *client) {
|
||||
client->stack_next = wm.client_stack_list;
|
||||
wm.client_stack_list = client;
|
||||
}
|
||||
|
||||
static void client_detach_stack(client_t *client) {
|
||||
client_t **tc = &wm.client_stack_list;
|
||||
for (; *tc && *tc != client; tc = &(*tc)->stack_next);
|
||||
*tc = client->stack_next;
|
||||
|
||||
if (client == wm.client_focused) {
|
||||
client_t *t = wm.client_stack_list;
|
||||
for (; t && !client_is_visible(t); t = t->stack_next);
|
||||
wm.client_focused = t;
|
||||
}
|
||||
}
|
||||
|
||||
void client_manage(xcb_window_t window,
|
||||
xcb_get_geometry_reply_t *geometry_reply) {
|
||||
client_t *c = p_new(client_t, 1);
|
||||
c->window = window;
|
||||
|
||||
c->name = xwindow_get_text_property(c->window, WM_NAME);
|
||||
c->icon_name = xwindow_get_text_property(c->window, WM_ICON_NAME);
|
||||
c->net_name = xwindow_get_text_property(c->window, _NET_WM_NAME);
|
||||
c->net_icon_name = xwindow_get_text_property(c->window, _NET_WM_ICON_NAME);
|
||||
c->role = xwindow_get_text_property(c->window, WM_WINDOW_ROLE);
|
||||
|
||||
client_attach_list(c);
|
||||
client_attach_stack(c);
|
||||
|
||||
{
|
||||
xcb_icccm_get_wm_class_reply_t prop;
|
||||
xcb_get_property_cookie_t cookie =
|
||||
xcb_icccm_get_wm_class_unchecked(wm.xcb_conn, c->window);
|
||||
if (xcb_icccm_get_wm_class_reply(wm.xcb_conn, cookie, &prop, nullptr)) {
|
||||
c->class = strdup(prop.class_name);
|
||||
c->instance = strdup(prop.instance_name);
|
||||
xcb_icccm_get_wm_class_reply_wipe(&prop);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
xcb_get_property_cookie_t cookie =
|
||||
xcb_icccm_get_wm_transient_for_unchecked(wm.xcb_conn, window);
|
||||
xcb_icccm_get_wm_transient_for_reply(wm.xcb_conn, cookie,
|
||||
&c->transient_for_window, nullptr);
|
||||
|
||||
client_t *transient_for_client = nullptr;
|
||||
if (c->transient_for_window && (transient_for_client = client_get_by_window(
|
||||
c->transient_for_window))) {
|
||||
c->monitor = transient_for_client->monitor;
|
||||
c->tags = transient_for_client->tags;
|
||||
} else {
|
||||
c->monitor = wm.current_monitor;
|
||||
c->tags = c->monitor->selected_tag->mask;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const 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(wm.xcb_conn, window, XCB_CW_EVENT_MASK,
|
||||
¶ms);
|
||||
xcb_map_window(wm.xcb_conn, window);
|
||||
}
|
||||
|
||||
xcb_flush(wm.xcb_conn);
|
||||
}
|
||||
|
||||
bool client_is_visible(client_t *client) {
|
||||
return client->tags & client->monitor->selected_tag->mask;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
#include "color.h"
|
||||
#include "types.h"
|
||||
|
||||
void client_manage(xcb_window_t window);
|
||||
client_t *client_get_by_window(xcb_window_t window);
|
||||
void client_manage(xcb_window_t window,
|
||||
xcb_get_geometry_reply_t *geometry_reply);
|
||||
|
||||
void client_send_to_tag(client_t *client, uint32_t tag_mask);
|
||||
void client_send_to_monitor(client_t *client, monitor_t *monitor);
|
||||
|
||||
50
src/event.c
50
src/event.c
@@ -10,6 +10,7 @@
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "action.h"
|
||||
#include "client.h"
|
||||
#include "default_config.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
@@ -49,6 +50,23 @@ static void button_press(xcb_button_press_event_t *ev) {
|
||||
}
|
||||
}
|
||||
|
||||
static void configure_request(xcb_configure_request_event_t *ev) {
|
||||
client_t *client = client_get_by_window(ev->window);
|
||||
if (!client) {
|
||||
uint16_t value_mask = ev->value_mask;
|
||||
xcb_configure_window_value_list_t value_list = {
|
||||
.x = ev->x,
|
||||
.y = ev->y,
|
||||
.width = ev->width,
|
||||
.height = ev->height,
|
||||
.border_width = ev->border_width,
|
||||
.sibling = ev->sibling,
|
||||
.stack_mode = ev->stack_mode,
|
||||
};
|
||||
xcb_configure_window_aux(wm.xcb_conn, ev->window, value_mask, &value_list);
|
||||
}
|
||||
}
|
||||
|
||||
static void key_press(xcb_key_press_event_t *ev) {
|
||||
bool is_press = XCB_EVENT_RESPONSE_TYPE(ev) == XCB_KEY_PRESS;
|
||||
xcb_keysym_t keysym = xcb_key_press_lookup_keysym(wm.key_symbols, ev, 0);
|
||||
@@ -68,6 +86,36 @@ static void key_press(xcb_key_press_event_t *ev) {
|
||||
}
|
||||
}
|
||||
|
||||
static void map_request(xcb_map_request_event_t *ev) {
|
||||
xcb_get_window_attributes_cookie_t wa_cookie =
|
||||
xcb_get_window_attributes_unchecked(wm.xcb_conn, ev->window);
|
||||
xcb_get_window_attributes_reply_t *wa_reply =
|
||||
xcb_get_window_attributes_reply(wm.xcb_conn, wa_cookie, nullptr);
|
||||
|
||||
if (!wa_reply) return;
|
||||
if (wa_reply->override_redirect) {
|
||||
p_delete(&wa_reply);
|
||||
return;
|
||||
}
|
||||
|
||||
client_t *c = client_get_by_window(ev->window);
|
||||
if (!c) {
|
||||
xcb_get_geometry_cookie_t geo_cookie =
|
||||
xcb_get_geometry(wm.xcb_conn, ev->window);
|
||||
xcb_get_geometry_reply_t *geo_reply =
|
||||
xcb_get_geometry_reply(wm.xcb_conn, geo_cookie, nullptr);
|
||||
if (!geo_reply) {
|
||||
p_delete(&wa_reply);
|
||||
return;
|
||||
}
|
||||
|
||||
client_manage(ev->window, geo_reply);
|
||||
p_delete(&geo_reply);
|
||||
}
|
||||
|
||||
p_delete(&wa_reply);
|
||||
}
|
||||
|
||||
static void handle_xcb_event(xcb_generic_event_t *event) {
|
||||
uint8_t event_type = XCB_EVENT_RESPONSE_TYPE(event);
|
||||
const char *label = xcb_event_get_label(event_type);
|
||||
@@ -83,6 +131,8 @@ static void handle_xcb_event(xcb_generic_event_t *event) {
|
||||
EVENT(XCB_BUTTON_PRESS, button_press);
|
||||
EVENT(XCB_KEY_PRESS, key_press);
|
||||
EVENT(XCB_KEY_RELEASE, key_press);
|
||||
EVENT(XCB_CONFIGURE_REQUEST, configure_request);
|
||||
EVENT(XCB_MAP_REQUEST, map_request);
|
||||
|
||||
#undef EVENT
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "xwindow.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_aux.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
@@ -171,3 +172,32 @@ void xwindow_focus(xcb_window_t window) {
|
||||
xwindow_send_event(window, WM_TAKE_FOCUS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取目标窗口的文本属性
|
||||
* @param window 目标窗口
|
||||
* @param property 属性名
|
||||
* @returns 返回的信息使用后记得使用 free 释放
|
||||
*/
|
||||
char *xwindow_get_text_property(xcb_window_t window, xcb_atom_t property) {
|
||||
xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(
|
||||
wm.xcb_conn, false, window, property, XCB_ATOM_STRING, 0, UINT32_MAX);
|
||||
xcb_get_property_reply_t *reply =
|
||||
xcb_get_property_reply(wm.xcb_conn, cookie, nullptr);
|
||||
int length = xcb_get_property_value_length(reply);
|
||||
|
||||
char *value = nullptr;
|
||||
|
||||
if (reply &&
|
||||
(reply->type == XCB_ATOM_STRING || reply->type == UTF8_STRING ||
|
||||
reply->type == COMPOUND_TEXT) &&
|
||||
reply->format == 8 && length) {
|
||||
value = p_new(char, length + 1);
|
||||
memcpy(value, xcb_get_property_value(reply), length);
|
||||
value[length] = '\0';
|
||||
}
|
||||
|
||||
p_delete(&reply);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ void xwindow_grab_keys(xcb_window_t window, const keyboard_t *keys,
|
||||
int keys_length);
|
||||
bool xwindow_send_event(xcb_window_t window, xcb_atom_t atom);
|
||||
void xwindow_focus(xcb_window_t window);
|
||||
char *xwindow_get_text_property(xcb_window_t window, xcb_atom_t property);
|
||||
|
||||
#define xwindow_set_name_static(window, name) \
|
||||
xcb_icccm_set_wm_name(wm.xcb_conn, window, XCB_ATOM_STRING, 8, \
|
||||
|
||||
Reference in New Issue
Block a user