diff --git a/src/action.c b/src/action.c index 4486b18..b44695e 100644 --- a/src/action.c +++ b/src/action.c @@ -81,3 +81,9 @@ void toggle_client_floating(const user_action_arg_t *arg) { client_set_floating(wm.client_focused, !wm.client_focused->floating); } + +void toggle_client_fullscreen(const user_action_arg_t *arg) { + if (!wm.client_focused) return; + + client_set_fullscreen(wm.client_focused, !wm.client_focused->fullscreen); +} diff --git a/src/action.h b/src/action.h index b8b95af..80670dd 100644 --- a/src/action.h +++ b/src/action.h @@ -56,3 +56,4 @@ void spawn(const user_action_arg_t *arg); void quit(const user_action_arg_t *arg); void raise_or_run(const user_action_arg_t *arg); void toggle_client_floating(const user_action_arg_t *arg); +void toggle_client_fullscreen(const user_action_arg_t *arg); diff --git a/src/atoms-list.txt b/src/atoms-list.txt index 9c9feac..d79c7ae 100644 --- a/src/atoms-list.txt +++ b/src/atoms-list.txt @@ -14,4 +14,7 @@ _NET_CLIENT_LIST _NET_WM_DESKTOP _NET_WM_NAME _NET_WM_ICON_NAME +_NET_WM_STATE +_NET_WM_STATE_FULLSCREEN +_NET_SUPPORTED _NET_SUPPORTING_WM_CHECK diff --git a/src/atoms.c b/src/atoms.c index 9456363..a7e50e3 100644 --- a/src/atoms.c +++ b/src/atoms.c @@ -1,9 +1,12 @@ #include "atoms.h" +#include +#include #include #include "atoms-intern.h" #include "utils.h" +#include "wm.h" void atoms_init(xcb_connection_t *conn) { xcb_intern_atom_cookie_t cookies[countof(ATOM_LIST)]; @@ -12,12 +15,25 @@ void atoms_init(xcb_connection_t *conn) { cookies[i] = xcb_intern_atom_unchecked(conn, false, atom.len, atom.name); } + atom_item_t *atom = nullptr; + uint32_t supported_length = 0; + xcb_atom_t supported_list[countof(ATOM_LIST)] = {XCB_ATOM_NONE}; + xcb_intern_atom_reply_t *reply = nullptr; for (int i = 0; i < countof(ATOM_LIST); i++) { reply = xcb_intern_atom_reply(conn, cookies[i], nullptr); if (reply) { - *ATOM_LIST[i].atom = reply->atom; + atom = &ATOM_LIST[i]; + *atom->atom = reply->atom; p_delete(&reply); + + if (strstr(atom->name, "_NET_") == atom->name) { + supported_list[supported_length++] = *atom->atom; + } } } + + xcb_change_property(wm.xcb_conn, XCB_PROP_MODE_REPLACE, wm.screen->root, + _NET_SUPPORTED, XCB_ATOM_ATOM, 32, supported_length, + supported_list); } diff --git a/src/client.c b/src/client.c index 32c840e..916eddc 100644 --- a/src/client.c +++ b/src/client.c @@ -362,6 +362,28 @@ void client_set_floating(client_t *client, bool floating) { monitor_arrange(client->monitor); } +void client_set_fullscreen(client_t *client, bool fullscreen) { + if (client->fullscreen == fullscreen) return; + + client->fullscreen = fullscreen; + if (fullscreen) { + xcb_change_property(wm.xcb_conn, XCB_PROP_MODE_REPLACE, client->window, + _NET_WM_STATE, XCB_ATOM_ATOM, 32, 1, + &_NET_WM_STATE_FULLSCREEN); + client->old_border_width = client->border_width; + client_change_border_width(client, 0); + client_apply_geometry(client, client->monitor->geometry); + client_stack_raise(client); + } else { + xcb_change_property(wm.xcb_conn, XCB_PROP_MODE_REPLACE, client->window, + _NET_WM_STATE, XCB_ATOM_ATOM, 32, 0, 0); + client_change_border_width(client, client->old_border_width); + client_apply_geometry(client, client->old_geometry); + monitor_arrange(client->monitor); + } + client_focus(client); +} + static void update_client_list(void) { xcb_connection_t *conn = wm.xcb_conn; xcb_window_t root = wm.screen->root; diff --git a/src/default_config.h b/src/default_config.h index ee99d83..4f36e88 100644 --- a/src/default_config.h +++ b/src/default_config.h @@ -88,6 +88,7 @@ static const keyboard_t key_list[] = { {modifier_super, XK_o, send_client_to_next_monitor, {0}}, {modifier_super | modifier_control, XK_space, toggle_client_floating, {0}}, + {modifier_super, XK_f, toggle_client_fullscreen, {0}}, }; static const layout_t layout_list[] = { diff --git a/src/event.c b/src/event.c index 08fbf59..22e5b2b 100644 --- a/src/event.c +++ b/src/event.c @@ -144,6 +144,27 @@ static void client_message(xcb_client_message_event_t *ev) { client_focus(c); return; } + } else if (ev->type == _NET_WM_STATE) { + /** + * _NET_WM_STATE 协议数据格式为 + * data.data32 = { + * action, // 操作类型(添加/移除/切换) + * property1, // 第一个状态原子(如_NET_WM_STATE_FULLSCREEN) + * property2, // 第二个状态原子(可选,通常为0) + * 0, // 预留字段(固定为0) + * 0 // 预留字段(固定为0) + * }; + * action 值可能为 + * _NET_WM_STATE_ADD(1)​​:添加全屏状态,窗口进入全屏模式 + * _NET_WM_STATE_REMOVE(0):移除全屏状态,窗口退出全屏模式 + * _NET_WM_STATE_TOGGLE(2):切换全屏状态(若当前全屏则退出,反之进入) + */ + if (ev->data.data32[1] == _NET_WM_STATE_FULLSCREEN || + ev->data.data32[2] == _NET_WM_STATE_FULLSCREEN) { + bool fullscreen = ev->data.data32[0]; + if (ev->data.data32[0] == 2) fullscreen = !c->fullscreen; + client_set_fullscreen(c, fullscreen); + } } }