添加窗口规则支持
This commit is contained in:
69
src/client.c
69
src/client.c
@@ -140,6 +140,8 @@ static inline void client_update_names(client_t *c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void client_init_geometry(client_t *c) {
|
static inline void client_init_geometry(client_t *c) {
|
||||||
|
if (c->maximize || c->fullscreen) return;
|
||||||
|
|
||||||
area_t workarea = c->monitor->workarea;
|
area_t workarea = c->monitor->workarea;
|
||||||
if (c->geometry.x + client_width(c) > workarea.x + workarea.width) {
|
if (c->geometry.x + client_width(c) > workarea.x + workarea.width) {
|
||||||
c->geometry.x = workarea.x + workarea.width - client_width(c);
|
c->geometry.x = workarea.x + workarea.width - client_width(c);
|
||||||
@@ -221,6 +223,7 @@ void client_manage(xcb_window_t window,
|
|||||||
} else {
|
} else {
|
||||||
c->monitor = wm.current_monitor;
|
c->monitor = wm.current_monitor;
|
||||||
c->tags = c->monitor->selected_tag->mask;
|
c->tags = c->monitor->selected_tag->mask;
|
||||||
|
client_apply_rules(c, wm.rules, wm.rules_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
client_init_geometry(c);
|
client_init_geometry(c);
|
||||||
@@ -496,13 +499,22 @@ void client_unmanage(client_t *client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void client_apply_geometry(client_t *client, area_t geometry) {
|
void client_apply_geometry(client_t *client, area_t geometry) {
|
||||||
if (client->geometry.x != geometry.x || client->geometry.y != geometry.y) {
|
uint16_t mask = 0;
|
||||||
client_move_to(client, geometry.x, geometry.y);
|
const xcb_params_configure_window_t params = {
|
||||||
}
|
.x = geometry.x,
|
||||||
if (client->geometry.width != geometry.width ||
|
.y = geometry.y,
|
||||||
client->geometry.height != geometry.height) {
|
.width = geometry.width,
|
||||||
client_resize(client, geometry.width, geometry.height);
|
.height = geometry.height,
|
||||||
|
};
|
||||||
|
if (client->geometry.x != geometry.x) mask |= XCB_CONFIG_WINDOW_X;
|
||||||
|
if (client->geometry.y != geometry.y) mask |= XCB_CONFIG_WINDOW_Y;
|
||||||
|
if (client->geometry.width != geometry.width) mask |= XCB_CONFIG_WINDOW_WIDTH;
|
||||||
|
if (client->geometry.height != geometry.height) {
|
||||||
|
mask |= XCB_CONFIG_WINDOW_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client->geometry = geometry;
|
||||||
|
xcb_aux_configure_window(wm.xcb_conn, client->window, mask, ¶ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -527,6 +539,51 @@ void client_apply_workarea_geometry(client_t *client, area_t geometry) {
|
|||||||
client_apply_geometry(client, rect);
|
client_apply_geometry(client, rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void client_apply_rules(client_t *client, const rule_t rules[],
|
||||||
|
size_t rules_count) {
|
||||||
|
for (size_t i = 0; i < rules_count; i++) {
|
||||||
|
const rule_t *r = &rules[i];
|
||||||
|
if (!((!r->role || (client->role && strstr(client->role, r->role))) &&
|
||||||
|
(!r->class || (client->class && strstr(client->class, r->class))))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
client->fullscreen = r->fullscreen;
|
||||||
|
client->maximize = r->maximize;
|
||||||
|
client->floating = r->floating;
|
||||||
|
|
||||||
|
for (monitor_t *m = wm.monitor_list; m; m = m->next) {
|
||||||
|
for (tag_t *t = m->tag_list; t; t = t->next) {
|
||||||
|
if (t->index != r->tag_index) continue;
|
||||||
|
|
||||||
|
client->monitor = m;
|
||||||
|
client->tags = t->mask;
|
||||||
|
|
||||||
|
if (r->switch_to_tag) {
|
||||||
|
wm.current_monitor = m;
|
||||||
|
m->selected_tag = t;
|
||||||
|
|
||||||
|
logger("++ switch to tag: %u\n", t->index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->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);
|
||||||
|
} else if (client->maximize) {
|
||||||
|
xcb_atom_t max_atoms[] = {
|
||||||
|
_NET_WM_STATE_MAXIMIZED_HORZ,
|
||||||
|
_NET_WM_STATE_MAXIMIZED_VERT,
|
||||||
|
};
|
||||||
|
xcb_change_property(wm.xcb_conn, XCB_PROP_MODE_REPLACE, client->window,
|
||||||
|
_NET_WM_STATE, XCB_ATOM_ATOM, 32, countof(max_atoms),
|
||||||
|
max_atoms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void client_focus(client_t *client) {
|
void client_focus(client_t *client) {
|
||||||
wm.client_focused = client;
|
wm.client_focused = client;
|
||||||
xwindow_focus(client ? client->window : XCB_WINDOW_NONE);
|
xwindow_focus(client ? client->window : XCB_WINDOW_NONE);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
@@ -52,6 +53,8 @@ void client_kill(client_t *client);
|
|||||||
void client_unmanage(client_t *client);
|
void client_unmanage(client_t *client);
|
||||||
void client_apply_geometry(client_t *client, area_t geometry);
|
void client_apply_geometry(client_t *client, area_t geometry);
|
||||||
void client_apply_workarea_geometry(client_t *client, area_t geometry);
|
void client_apply_workarea_geometry(client_t *client, area_t geometry);
|
||||||
|
void client_apply_rules(client_t *client, const rule_t rules[],
|
||||||
|
size_t rules_count);
|
||||||
|
|
||||||
void client_focus(client_t *client);
|
void client_focus(client_t *client);
|
||||||
void client_stack_raise(client_t *client);
|
void client_stack_raise(client_t *client);
|
||||||
|
|||||||
@@ -104,3 +104,11 @@ static const char *const autostart_list[] = {
|
|||||||
"fcitx5 -d",
|
"fcitx5 -d",
|
||||||
nullptr,
|
nullptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const rule_t rules[] = {
|
||||||
|
{.role = "dialog", .tag_index = -1, .floating = true},
|
||||||
|
{.class = "firefox", .tag_index = 1, .maximize = true},
|
||||||
|
{.class = "Google-chrome", .tag_index = 1, .maximize = true},
|
||||||
|
{.class = "mpv", .tag_index = 3, .switch_to_tag = true, .fullscreen = true},
|
||||||
|
{.class = "Emacs", .tag_index = 10, .switch_to_tag = true, .maximize = true},
|
||||||
|
};
|
||||||
|
|||||||
20
src/event.c
20
src/event.c
@@ -139,10 +139,22 @@ static void client_message(xcb_client_message_event_t *ev) {
|
|||||||
for (tag_t *t = c->monitor->tag_list; t; t = t->next) {
|
for (tag_t *t = c->monitor->tag_list; t; t = t->next) {
|
||||||
if ((t->mask & c->tags) == 0) continue;
|
if ((t->mask & c->tags) == 0) continue;
|
||||||
|
|
||||||
wm.current_monitor = c->monitor;
|
logger("== _NET_ACTIVE_WINDOW: %s[%u]\n", c->class, ev->data.data32[0]);
|
||||||
monitor_select_tag(c->monitor, t->mask);
|
|
||||||
client_focus(c);
|
switch (ev->data.data32[0]) {
|
||||||
return;
|
case 2: /* 来自 pager */
|
||||||
|
wm.current_monitor = c->monitor;
|
||||||
|
monitor_select_tag(c->monitor, t->mask);
|
||||||
|
client_focus(c);
|
||||||
|
break;
|
||||||
|
case 1: /* 来自应用程序 */
|
||||||
|
c->urgent = true;
|
||||||
|
monitor_draw_bar(c->monitor);
|
||||||
|
break;
|
||||||
|
case 0: /* 来自老版本标志 */
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (ev->type == _NET_WM_STATE) {
|
} else if (ev->type == _NET_WM_STATE) {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -69,12 +69,14 @@ void monitor_select_tag(monitor_t *monitor, uint32_t tag_mask) {
|
|||||||
|
|
||||||
for (task_in_tag_t *task = monitor->selected_tag->task_list; task;
|
for (task_in_tag_t *task = monitor->selected_tag->task_list; task;
|
||||||
task = task->next) {
|
task = task->next) {
|
||||||
if (task->client->floating || task->client->size_freeze) {
|
if (task->client->floating || task->client->size_freeze ||
|
||||||
|
!monitor->selected_tag->layout->arrange) {
|
||||||
task->geometry = task->client->geometry;
|
task->geometry = task->client->geometry;
|
||||||
|
task->client->old_geometry = task->client->geometry;
|
||||||
}
|
}
|
||||||
if (task->client->fullscreen || task->client->maximize ||
|
if (task->client->fullscreen || task->client->maximize ||
|
||||||
task->client->minimize) {
|
task->client->minimize) {
|
||||||
task->geometry = task->client->old_geometry;
|
task->geometry = task->client->geometry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,25 +282,24 @@ void monitor_arrange(monitor_t *monitor) {
|
|||||||
tag_t *tag = monitor->selected_tag;
|
tag_t *tag = monitor->selected_tag;
|
||||||
if (tag->layout && tag->layout->arrange) tag->layout->arrange(tag);
|
if (tag->layout && tag->layout->arrange) tag->layout->arrange(tag);
|
||||||
|
|
||||||
for (client_t *c = wm.client_list; c; c = c->next) {
|
for (client_t *c = wm.client_stack_list; c; c = c->stack_next) {
|
||||||
if (c->monitor != monitor) continue;
|
if (c->monitor != monitor || c->minimize) continue;
|
||||||
|
|
||||||
task_in_tag_t *task = client_get_task_in_tag(c, tag);
|
task_in_tag_t *task = client_get_task_in_tag(c, tag);
|
||||||
if (task) {
|
if (task) {
|
||||||
if (c->minimize) continue;
|
if (client_need_layout(c)) {
|
||||||
if (c->fullscreen) {
|
client_apply_geometry(c, task->geometry);
|
||||||
|
} else if (c->fullscreen) {
|
||||||
client_apply_geometry(c, c->monitor->geometry);
|
client_apply_geometry(c, c->monitor->geometry);
|
||||||
} else if (c->maximize) {
|
} else if (c->maximize) {
|
||||||
client_apply_geometry(c, c->monitor->workarea);
|
client_apply_geometry(c, c->monitor->workarea);
|
||||||
} else {
|
} else {
|
||||||
client_apply_geometry(c, task->geometry);
|
client_move_to(c, task->geometry.x, task->geometry.y);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int16_t x = -client_width(c);
|
int16_t x = -client_width(c);
|
||||||
int16_t y = -client_height(c);
|
int16_t y = -client_height(c);
|
||||||
if (x != c->geometry.x || y != c->geometry.y) {
|
client_move_to(c, x, y);
|
||||||
client_move_to(c, x, y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xcb_flush(wm.xcb_conn);
|
xcb_flush(wm.xcb_conn);
|
||||||
|
|||||||
10
src/types.h
10
src/types.h
@@ -100,3 +100,13 @@ typedef struct padding_t {
|
|||||||
uint16_t bar_y;
|
uint16_t bar_y;
|
||||||
uint16_t tag_x;
|
uint16_t tag_x;
|
||||||
} padding_t;
|
} padding_t;
|
||||||
|
|
||||||
|
typedef struct rule_t {
|
||||||
|
const char *role;
|
||||||
|
const char *class;
|
||||||
|
uint32_t tag_index;
|
||||||
|
bool switch_to_tag;
|
||||||
|
bool fullscreen;
|
||||||
|
bool maximize;
|
||||||
|
bool floating;
|
||||||
|
} rule_t;
|
||||||
|
|||||||
3
src/wm.c
3
src/wm.c
@@ -338,6 +338,9 @@ static void wm_setup(void) {
|
|||||||
wm.layout_list = layout_list;
|
wm.layout_list = layout_list;
|
||||||
wm.layout_count = (uint16_t)countof(layout_list);
|
wm.layout_count = (uint16_t)countof(layout_list);
|
||||||
|
|
||||||
|
wm.rules = rules;
|
||||||
|
wm.rules_count = countof(rules);
|
||||||
|
|
||||||
wm_get_xres_config();
|
wm_get_xres_config();
|
||||||
wm_init_color_set();
|
wm_init_color_set();
|
||||||
|
|
||||||
|
|||||||
2
src/wm.h
2
src/wm.h
@@ -27,6 +27,8 @@ typedef struct wm_t {
|
|||||||
char *font_family;
|
char *font_family;
|
||||||
uint32_t font_size;
|
uint32_t font_size;
|
||||||
uint32_t dpi;
|
uint32_t dpi;
|
||||||
|
const rule_t *rules;
|
||||||
|
uint32_t rules_count;
|
||||||
|
|
||||||
xcb_connection_t *xcb_conn;
|
xcb_connection_t *xcb_conn;
|
||||||
xcb_screen_t *screen;
|
xcb_screen_t *screen;
|
||||||
|
|||||||
Reference in New Issue
Block a user