添加快捷键将窗口移动到其他 tag 和 monitor
This commit is contained in:
@@ -11,3 +11,5 @@ void focus_monitor(const user_action_arg_t *arg);
|
||||
void raise_or_run(const user_action_arg_t *arg);
|
||||
void toggle_mute(const user_action_arg_t *arg);
|
||||
void change_volume(const user_action_arg_t *arg);
|
||||
void move_to_monitor(const user_action_arg_t *arg);
|
||||
void move_to_tag(const user_action_arg_t *arg);
|
||||
|
||||
11
src/config.h
11
src/config.h
@@ -96,6 +96,7 @@ const keybinding_t keys[] = {
|
||||
{ALT, XK_k, focus_stack, {.b = false}},
|
||||
{SUPER | SHIFT, XK_j, focus_monitor, {.b = true}},
|
||||
{SUPER | SHIFT, XK_k, focus_monitor, {.b = false}},
|
||||
{SUPER, XK_o, move_to_monitor, {.b = true}},
|
||||
|
||||
{
|
||||
SUPER,
|
||||
@@ -128,6 +129,16 @@ const keybinding_t keys[] = {
|
||||
{SUPER, XK_7, select_tag, {.ui = 1 << 6}},
|
||||
{SUPER, XK_8, select_tag, {.ui = 1 << 7}},
|
||||
{SUPER, XK_9, select_tag, {.ui = 1 << 8}},
|
||||
|
||||
{SUPER | SHIFT, XK_1, move_to_tag, {.ui = 1 << 0}},
|
||||
{SUPER | SHIFT, XK_2, move_to_tag, {.ui = 1 << 1}},
|
||||
{SUPER | SHIFT, XK_3, move_to_tag, {.ui = 1 << 2}},
|
||||
{SUPER | SHIFT, XK_4, move_to_tag, {.ui = 1 << 3}},
|
||||
{SUPER | SHIFT, XK_5, move_to_tag, {.ui = 1 << 4}},
|
||||
{SUPER | SHIFT, XK_6, move_to_tag, {.ui = 1 << 5}},
|
||||
{SUPER | SHIFT, XK_7, move_to_tag, {.ui = 1 << 6}},
|
||||
{SUPER | SHIFT, XK_8, move_to_tag, {.ui = 1 << 7}},
|
||||
{SUPER | SHIFT, XK_9, move_to_tag, {.ui = 1 << 8}},
|
||||
};
|
||||
|
||||
const char *const bar_bg = "#222222";
|
||||
|
||||
@@ -128,6 +128,7 @@ typedef enum atom_t {
|
||||
atom_net_wm_fullscreen,
|
||||
atom__xrootpmap_id,
|
||||
atom_esetroot_pmap_id,
|
||||
atom_zswm_client_info, /* 自定义属性,用于存储所在 monitor 和 tags */
|
||||
} atom_t;
|
||||
xcb_atom_t get_xcb_atom(atom_t atom);
|
||||
bool send_event(xcb_window_t window, atom_t atom);
|
||||
@@ -139,6 +140,13 @@ typedef enum wm_state_t {
|
||||
int32_t get_window_state(xcb_window_t window);
|
||||
void set_window_state(xcb_window_t window, wm_state_t state);
|
||||
void set_window_list(xcb_window_t *list, uint32_t length);
|
||||
typedef struct client_info_t {
|
||||
uint32_t tags;
|
||||
uint32_t monitor_index;
|
||||
} client_tag_info_t;
|
||||
bool get_window_tag(xcb_window_t window, client_tag_info_t *client_info);
|
||||
void set_window_tag(xcb_window_t window, client_tag_info_t *client_info);
|
||||
void remove_window_tag(xcb_window_t window);
|
||||
|
||||
bool get_pointer_position(int32_t *x, int32_t *y);
|
||||
|
||||
|
||||
99
src/main.c
99
src/main.c
@@ -70,9 +70,12 @@ static void apply_monitor_layout(monitor_t *monitor);
|
||||
static client_t *get_client_of_window(xcb_window_t window);
|
||||
static monitor_t *get_monitor_of_window(xcb_window_t window);
|
||||
static monitor_t *get_monitor_by_direction(bool forward);
|
||||
static void send_client_to_monitor(client_t *client, monitor_t *monitor);
|
||||
static void set_client_tag_prop(client_t *client);
|
||||
static bool apply_initial_client_tag(client_t *client);
|
||||
static gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition,
|
||||
gpointer userdata);
|
||||
static void cleanup(void);
|
||||
static void cleanup(bool will_restart);
|
||||
|
||||
static monitor_t *monitors = NULL;
|
||||
static monitor_t *current_monitor = NULL;
|
||||
@@ -194,6 +197,31 @@ void change_volume(const user_action_arg_t *arg) {
|
||||
change_pulse_volume(arg->i);
|
||||
}
|
||||
|
||||
void move_to_monitor(const user_action_arg_t *arg) {
|
||||
if (!current_monitor->selected_client || !monitors->next) return;
|
||||
|
||||
bool forward = arg->b;
|
||||
monitor_t *monitor = get_monitor_by_direction(forward);
|
||||
send_client_to_monitor(current_monitor->selected_client, monitor);
|
||||
}
|
||||
|
||||
void move_to_tag(const user_action_arg_t *arg) {
|
||||
if (!current_monitor || !current_monitor->selected_client) return;
|
||||
|
||||
uint32_t tag_mask = 0;
|
||||
for (uint32_t i = 0; i < g_strv_length(current_monitor->tags); i++) {
|
||||
tag_mask |= 1 << i;
|
||||
}
|
||||
uint32_t target_tag = arg->ui & tag_mask;
|
||||
if (!target_tag) return;
|
||||
|
||||
client_t *client = current_monitor->selected_client;
|
||||
client->tags = target_tag;
|
||||
set_client_tag_prop(client);
|
||||
focus(NULL);
|
||||
arrange(current_monitor);
|
||||
}
|
||||
|
||||
/* 调试函数,开发完成后删除 */
|
||||
static void print_monitor_list_info(monitor_t *monitor_list) {
|
||||
logger("========================= monitor info =========================\n");
|
||||
@@ -365,6 +393,9 @@ void init_wallpaper(void) {
|
||||
}
|
||||
wallpaper_cr = cr;
|
||||
cairo_surface_destroy(surface);
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1);
|
||||
cairo_paint(cr);
|
||||
refresh_root_window();
|
||||
|
||||
wallpaper_config = parse_wallpaper_config();
|
||||
if (!wallpaper_config) return;
|
||||
@@ -805,11 +836,13 @@ void manage_window(xcb_window_t window) {
|
||||
if (tw != WINDOW_NONE && (tc = get_client_of_window(tw))) {
|
||||
c->monitor = tc->monitor;
|
||||
c->tags = tc->tags;
|
||||
} else {
|
||||
} else if (!apply_initial_client_tag(c)) {
|
||||
c->monitor = current_monitor;
|
||||
apply_rules(c);
|
||||
}
|
||||
|
||||
set_client_tag_prop(c);
|
||||
|
||||
set_window_event_mask(window, false);
|
||||
change_window_border_color(window, color_set->border_color.argb);
|
||||
|
||||
@@ -915,8 +948,12 @@ void apply_rules(client_t *client) {
|
||||
}
|
||||
|
||||
if (!client->tags) {
|
||||
client->monitor = current_monitor;
|
||||
client->tags = current_monitor->selected_tags;
|
||||
client_tag_info_t client_info;
|
||||
if (get_window_tag(client->window, &client_info)) {
|
||||
} else {
|
||||
client->monitor = current_monitor;
|
||||
client->tags = current_monitor->selected_tags;
|
||||
}
|
||||
}
|
||||
if (switch_to_tag) {
|
||||
current_monitor = client->monitor;
|
||||
@@ -972,6 +1009,7 @@ void arrange(monitor_t *monitor) {
|
||||
apply_monitor_layout(monitor);
|
||||
}
|
||||
}
|
||||
flush_xcb_connection();
|
||||
}
|
||||
|
||||
void restack(monitor_t *monitor) {
|
||||
@@ -1121,6 +1159,53 @@ monitor_t *get_monitor_by_direction(bool forward) {
|
||||
return m;
|
||||
}
|
||||
|
||||
void send_client_to_monitor(client_t *client, monitor_t *monitor) {
|
||||
if (client->monitor == monitor) return;
|
||||
|
||||
unfocus(client, true);
|
||||
detach_client(client);
|
||||
detach_stack_client(client);
|
||||
client->monitor = monitor;
|
||||
client->tags = monitor->selected_tags;
|
||||
attach_client(client);
|
||||
attach_stack_client(client);
|
||||
set_client_tag_prop(client);
|
||||
focus(client);
|
||||
arrange(NULL);
|
||||
}
|
||||
|
||||
void set_client_tag_prop(client_t *client) {
|
||||
client_tag_info_t info = {
|
||||
.tags = client->tags,
|
||||
.monitor_index = client->monitor->index,
|
||||
};
|
||||
set_window_tag(client->window, &info);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置 client 的初始 tag 信息
|
||||
* @returns 成功返回 true 否则返回 false
|
||||
*/
|
||||
bool apply_initial_client_tag(client_t *client) {
|
||||
client_tag_info_t client_tag_info;
|
||||
if (!get_window_tag(client->window, &client_tag_info)) return false;
|
||||
|
||||
for (monitor_t *m = monitors; m; m = m->next) {
|
||||
if (client_tag_info.monitor_index == m->index) {
|
||||
uint32_t tag_mask = 0;
|
||||
for (uint32_t i = 0; i < g_strv_length(m->tags); i++) tag_mask |= 1 << i;
|
||||
uint32_t target_tag = tag_mask & client_tag_info.tags;
|
||||
if (target_tag) {
|
||||
client->monitor = m;
|
||||
client->tags = target_tag;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition,
|
||||
gpointer userdata) {
|
||||
if (condition & (G_IO_HUP | G_IO_ERR)) {
|
||||
@@ -1132,7 +1217,7 @@ gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition,
|
||||
return true;
|
||||
}
|
||||
|
||||
void cleanup(void) {
|
||||
void cleanup(bool will_restart) {
|
||||
clean_status();
|
||||
|
||||
g_main_loop_unref(loop);
|
||||
@@ -1142,6 +1227,7 @@ void cleanup(void) {
|
||||
client_t *c = m->clients;
|
||||
while (m) {
|
||||
while (c) {
|
||||
if (!will_restart) remove_window_tag(c->window);
|
||||
client_t *tc = c->next;
|
||||
unmanage_client(c, false);
|
||||
c = tc;
|
||||
@@ -1181,6 +1267,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
loop = g_main_loop_new(NULL, FALSE);
|
||||
|
||||
logger("========================== ZSWM START ==========================\n");
|
||||
setup_xcb();
|
||||
init_monitors();
|
||||
init_color_set();
|
||||
@@ -1215,7 +1302,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
g_main_loop_run(loop);
|
||||
|
||||
cleanup();
|
||||
cleanup(need_restart);
|
||||
|
||||
if (need_restart) {
|
||||
need_restart = false;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_ewmh.h>
|
||||
@@ -30,6 +31,7 @@ static atom_map_t atom_map[] = {
|
||||
{.atom = atom_net_wm_fullscreen, .name = "_NET_WM_STATE_FULLSCREEN"},
|
||||
{.atom = atom__xrootpmap_id, .name = "_XROOTPMAP_ID"},
|
||||
{.atom = atom_esetroot_pmap_id, .name = "ESETROOT_PMAP_ID"},
|
||||
{.atom = atom_zswm_client_info, .name = "ZSWM_CLIENT_INFO"},
|
||||
};
|
||||
|
||||
void init_icccm_extension(void) {
|
||||
@@ -84,6 +86,7 @@ void init_ewmh_extension(void) {
|
||||
xcb_change_property(conn, mode, screen->root, ewmh->_NET_SUPPORTED, atom, 32,
|
||||
LENGTH(supported), supported);
|
||||
xcb_delete_property(conn, screen->root, ewmh->_NET_CLIENT_LIST);
|
||||
xcb_delete_property(conn, screen->root, get_xcb_atom(atom_zswm_client_info));
|
||||
}
|
||||
|
||||
void clean_ewmh_extension(void) {
|
||||
@@ -171,3 +174,29 @@ void set_window_list(xcb_window_t *list, uint32_t length) {
|
||||
}
|
||||
xcb_ewmh_set_client_list(ewmh, screen_nbr, length, list);
|
||||
}
|
||||
|
||||
bool get_window_tag(xcb_window_t window, client_tag_info_t *client_info) {
|
||||
xcb_get_property_cookie_t cookie =
|
||||
xcb_get_property(conn, 0, window, get_xcb_atom(atom_zswm_client_info),
|
||||
XCB_ATOM_CARDINAL, 0, 2);
|
||||
xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
|
||||
int length = xcb_get_property_value_length(reply);
|
||||
if (length >= 2) {
|
||||
uint32_t *data = xcb_get_property_value(reply);
|
||||
client_info->tags = data[0];
|
||||
client_info->monitor_index = data[1];
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void set_window_tag(xcb_window_t window, client_tag_info_t *client_info) {
|
||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, window,
|
||||
get_xcb_atom(atom_zswm_client_info), XCB_ATOM_CARDINAL,
|
||||
32, 2, client_info);
|
||||
}
|
||||
|
||||
void remove_window_tag(xcb_window_t window) {
|
||||
xcb_delete_property(conn, window, get_xcb_atom(atom_zswm_client_info));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user