支持 client 窗口浮动
This commit is contained in:
@@ -75,3 +75,9 @@ void raise_or_run(const user_action_arg_t *arg) {
|
||||
user_action_arg_t arguments = {.ptr = command};
|
||||
spawn(&arguments);
|
||||
}
|
||||
|
||||
void toggle_client_floating(const user_action_arg_t *arg) {
|
||||
if (!wm.client_focused) return;
|
||||
|
||||
client_set_floating(wm.client_focused, !wm.client_focused->floating);
|
||||
}
|
||||
|
||||
@@ -55,3 +55,4 @@ void send_client_to_next_monitor(const user_action_arg_t *arg);
|
||||
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);
|
||||
|
||||
62
src/client.c
62
src/client.c
@@ -178,11 +178,12 @@ 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->geometry.x = geometry_reply->x;
|
||||
c->geometry.y = geometry_reply->y;
|
||||
c->geometry.width = geometry_reply->width;
|
||||
c->geometry.height = geometry_reply->height;
|
||||
c->border_width = geometry_reply->border_width;
|
||||
c->old_geometry.x = geometry_reply->x;
|
||||
c->old_geometry.y = geometry_reply->y;
|
||||
c->old_geometry.width = geometry_reply->width;
|
||||
c->old_geometry.height = geometry_reply->height;
|
||||
c->geometry = c->old_geometry;
|
||||
c->old_border_width = geometry_reply->border_width;
|
||||
|
||||
{
|
||||
const xcb_params_cw_t params = {
|
||||
@@ -345,6 +346,22 @@ void client_update_wm_hints(client_t *client) {
|
||||
}
|
||||
}
|
||||
|
||||
void client_set_floating(client_t *client, bool floating) {
|
||||
if (client->floating == floating || client->fullscreen) return;
|
||||
|
||||
logger("== client set floating: %s\n", floating ? "true" : "false");
|
||||
logger("== old geometry: x -> %d, y -> %d, width -> %u, height -> %u\n",
|
||||
client->old_geometry.x, client->old_geometry.y,
|
||||
client->old_geometry.width, client->old_geometry.height);
|
||||
client->floating = floating;
|
||||
if (floating) {
|
||||
client_apply_workarea_geometry(client, client->old_geometry);
|
||||
client->old_geometry = client->geometry;
|
||||
}
|
||||
|
||||
monitor_arrange(client->monitor);
|
||||
}
|
||||
|
||||
static void update_client_list(void) {
|
||||
xcb_connection_t *conn = wm.xcb_conn;
|
||||
xcb_window_t root = wm.screen->root;
|
||||
@@ -379,17 +396,36 @@ void client_unmanage(client_t *client) {
|
||||
xcb_flush(wm.xcb_conn);
|
||||
}
|
||||
|
||||
void client_apply_task_geometry(client_t *client, task_in_tag_t *task) {
|
||||
if (!client || !task || client != task->client) return;
|
||||
void client_apply_geometry(client_t *client, area_t geometry) {
|
||||
if (client->geometry.x != geometry.x || client->geometry.y != geometry.y) {
|
||||
client_move_to(client, geometry.x, geometry.y);
|
||||
}
|
||||
if (client->geometry.width != geometry.width ||
|
||||
client->geometry.height != geometry.height) {
|
||||
client_resize(client, geometry.width, geometry.height);
|
||||
}
|
||||
}
|
||||
|
||||
if (task->geometry.x != client->geometry.x ||
|
||||
task->geometry.y != client->geometry.y) {
|
||||
client_move_to(client, task->geometry.x, task->geometry.y);
|
||||
/**
|
||||
* @brief 调整 client 的几何信息但需让 client 任在其 monitor 的 workarea 中
|
||||
* @param client 要调整几何信息的 client
|
||||
* @param geometry 目标几何信息
|
||||
*/
|
||||
void client_apply_workarea_geometry(client_t *client, area_t geometry) {
|
||||
area_t workarea = client->monitor->workarea;
|
||||
uint16_t width = MIN(geometry.width, workarea.width);
|
||||
uint16_t height = MIN(geometry.height, workarea.height);
|
||||
int16_t x = MAX(geometry.x, workarea.x);
|
||||
int16_t y = MAX(geometry.y, workarea.y);
|
||||
if (x + width + client->border_width * 2 > workarea.x + workarea.width) {
|
||||
x = workarea.x + workarea.width - width - client->border_width * 2;
|
||||
}
|
||||
if (task->geometry.width != client->geometry.width ||
|
||||
task->geometry.height != client->geometry.height) {
|
||||
client_resize(client, task->geometry.width, task->geometry.height);
|
||||
if (y + height + client->border_width * 2 > workarea.y + workarea.height) {
|
||||
y = workarea.y + workarea.width - height - client->border_width * 2;
|
||||
}
|
||||
|
||||
area_t rect = {.x = x, .y = y, .width = width, .height = height};
|
||||
client_apply_geometry(client, rect);
|
||||
}
|
||||
|
||||
void client_focus(client_t *client) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "types.h"
|
||||
|
||||
client_t *client_get_by_window(xcb_window_t window);
|
||||
client_t *client_get_next_by_class(client_t *current,const char *class);
|
||||
client_t *client_get_next_by_class(client_t *current, const char *class);
|
||||
task_in_tag_t *client_get_task_in_tag(client_t *client, tag_t *tag);
|
||||
task_in_tag_t *client_get_next_task_in_tag(client_t *client, tag_t *tag);
|
||||
task_in_tag_t *client_get_previous_task_in_tag(client_t *client, tag_t *tag);
|
||||
@@ -48,7 +48,8 @@ void client_set_leader_window(client_t *client, xcb_window_t leader_window);
|
||||
|
||||
void client_kill(client_t *client);
|
||||
void client_unmanage(client_t *client);
|
||||
void client_apply_task_geometry(client_t *client, task_in_tag_t *task);
|
||||
void client_apply_geometry(client_t *client, area_t geometry);
|
||||
void client_apply_workarea_geometry(client_t *client, area_t geometry);
|
||||
|
||||
void client_focus(client_t *client);
|
||||
void client_stack_raise(client_t *client);
|
||||
|
||||
@@ -86,6 +86,8 @@ static const keyboard_t key_list[] = {
|
||||
TAGKEYS(XK_9, 1 << 8),
|
||||
|
||||
{modifier_super, XK_o, send_client_to_next_monitor, {0}},
|
||||
|
||||
{modifier_super | modifier_control, XK_space, toggle_client_floating, {0}},
|
||||
};
|
||||
|
||||
static const layout_t layout_list[] = {
|
||||
|
||||
@@ -68,7 +68,7 @@ static void configure_request(xcb_configure_request_event_t *ev) {
|
||||
task->geometry.width = ev->width;
|
||||
if (ev->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
|
||||
task->geometry.height = ev->height;
|
||||
client_apply_task_geometry(client, task);
|
||||
client_apply_geometry(client, task->geometry);
|
||||
}
|
||||
} else {
|
||||
uint16_t value_mask = ev->value_mask;
|
||||
|
||||
@@ -274,7 +274,11 @@ void monitor_arrange(monitor_t *monitor) {
|
||||
|
||||
task_in_tag_t *task = client_get_task_in_tag(c, tag);
|
||||
if (task) {
|
||||
client_apply_task_geometry(c, task);
|
||||
if (client_need_layout(c)) {
|
||||
client_apply_geometry(c, task->geometry);
|
||||
} else {
|
||||
client_apply_geometry(c, c->geometry);
|
||||
}
|
||||
} else {
|
||||
int16_t x = -client_width(c);
|
||||
int16_t y = -client_height(c);
|
||||
|
||||
@@ -26,9 +26,11 @@ struct client_t {
|
||||
monitor_t *monitor;
|
||||
uint32_t tags;
|
||||
|
||||
area_t old_geometry;
|
||||
area_t geometry;
|
||||
color_t *border_color;
|
||||
uint16_t border_width;
|
||||
uint16_t old_border_width;
|
||||
color_t *border_color;
|
||||
|
||||
bool floating;
|
||||
bool fullscreen;
|
||||
|
||||
@@ -88,6 +88,11 @@ static inline void logger(const char *format, ...) {
|
||||
#define logger(format, ...) printf(format, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef MIN
|
||||
#undef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifdef MAX
|
||||
#undef MAX
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
Reference in New Issue
Block a user