Compare commits

...

4 Commits

10 changed files with 144 additions and 22 deletions

View File

@@ -80,11 +80,17 @@ const rule_t rules[] = {
}, },
}; };
#define MODIFIER_ANY XCB_MOD_MASK_ANY
#define SUPER XCB_MOD_MASK_4 #define SUPER XCB_MOD_MASK_4
#define ALT XCB_MOD_MASK_1 #define ALT XCB_MOD_MASK_1
#define CTRL XCB_MOD_MASK_CONTROL #define CTRL XCB_MOD_MASK_CONTROL
#define SHIFT XCB_MOD_MASK_SHIFT #define SHIFT XCB_MOD_MASK_SHIFT
#define BUTTON_ANY XCB_BUTTON_INDEX_ANY
#define BUTTON_LEFT XCB_BUTTON_INDEX_1
#define BUTTON_RIGHT XCB_BUTTON_INDEX_2
#define BUTTON_MIDDLE XCB_BUTTON_INDEX_3
const char launcher[] = const char launcher[] =
"rofi -show combi -modes window,drun,run,ssh,combi,windowcd"; "rofi -show combi -modes window,drun,run,ssh,combi,windowcd";
const keybinding_t keys[] = { const keybinding_t keys[] = {
@@ -142,6 +148,11 @@ const keybinding_t keys[] = {
{SUPER | SHIFT, XK_9, move_to_tag, {.ui = 1 << 8}}, {SUPER | SHIFT, XK_9, move_to_tag, {.ui = 1 << 8}},
}; };
const button_t buttons[] = {
{click_tag, 0, BUTTON_LEFT, select_tag, {0}},
{click_tag, SUPER, BUTTON_LEFT, move_to_tag, {0}},
};
const char *const bar_bg = "#222222"; const char *const bar_bg = "#222222";
const char *const tag_bg = "#222222"; const char *const tag_bg = "#222222";
const char *const active_tag_bg = "#005577"; const char *const active_tag_bg = "#005577";
@@ -164,6 +175,7 @@ const char *const active_border_color = "#005577";
const char *const default_font_family = "sans-serif, monospace"; const char *const default_font_family = "sans-serif, monospace";
const uint32_t default_font_size = 10; const uint32_t default_font_size = 10;
const uint32_t dpi_fallback = 96; const uint32_t dpi_fallback = 96;
const uint32_t refresh_rate = 60;
const uint32_t bar_y_padding = 1; const uint32_t bar_y_padding = 1;
const uint32_t tag_x_padding = 10; const uint32_t tag_x_padding = 10;

View File

@@ -100,6 +100,7 @@ typedef struct motion_notify_event_t {
xcb_window_t window; xcb_window_t window;
int32_t x; int32_t x;
int32_t y; int32_t y;
uint32_t time; /* 时间戳单位ms */
} motion_notify_event_t; } motion_notify_event_t;
typedef struct enter_notify_event_t { typedef struct enter_notify_event_t {

View File

@@ -33,6 +33,9 @@ struct monitor_t {
client_t *clients_stack; client_t *clients_stack;
client_t *selected_client; client_t *selected_client;
int32_t pointer_x; /* 记录光标 x 坐标位置 */
int32_t pointer_y; /* 记录光标 y 坐标位置 */
xcb_window_t bar_window; xcb_window_t bar_window;
}; };
@@ -180,3 +183,20 @@ typedef struct icons_t {
icon_res_t cpu; icon_res_t cpu;
icon_res_t clock; icon_res_t clock;
} icons_t; } icons_t;
typedef enum click_area_t {
click_tag,
click_layout_symbol,
click_window_title,
click_status,
click_client_window,
click_root_win,
} click_area_t;
typedef struct button_t {
click_area_t click_area;
uint16_t modifiers;
uint8_t button;
void (*func)(const user_action_arg_t *);
const user_action_arg_t arg;
} button_t;

View File

@@ -153,8 +153,12 @@ void set_window_tag(xcb_window_t window, client_tag_info_t *client_info);
void remove_window_tag(xcb_window_t window); void remove_window_tag(xcb_window_t window);
bool get_pointer_position(int32_t *x, int32_t *y); bool get_pointer_position(int32_t *x, int32_t *y);
void set_pointer_position(int32_t x, int32_t y);
/** /**
* @brief 非阻塞检查特定事件掩码(模拟 XCheckMaskEvent * @brief 非阻塞检查特定事件掩码(模拟 XCheckMaskEvent
*/ */
bool xcb_check_mask_event(xcb_event_mask_t event_mask); bool xcb_check_mask_event(xcb_event_mask_t event_mask);
void ungrab_any_button(xcb_window_t window);
void grab_button(xcb_window_t window, uint8_t button, uint16_t modifiers);

View File

@@ -25,6 +25,8 @@
static void init_monitors(void); static void init_monitors(void);
static char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index); static char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index);
static void record_mointor_pointer_position(int32_t x, int32_t y,
uint32_t timestamp);
static void init_wallpaper(void); static void init_wallpaper(void);
static gboolean update_wallpaper(gpointer user_data); static gboolean update_wallpaper(gpointer user_data);
static void set_wallpaper_by_index(uint32_t index, wallpaper_config_t *config, static void set_wallpaper_by_index(uint32_t index, wallpaper_config_t *config,
@@ -57,6 +59,7 @@ static void focus_in(focus_in_event_t *event);
static void property_notify(property_notify_event_t *event); static void property_notify(property_notify_event_t *event);
static void client_message(client_message_event_t *event); static void client_message(client_message_event_t *event);
static void manage_window(xcb_window_t window); static void manage_window(xcb_window_t window);
static void grab_buttons_for_client(client_t *client, bool focused);
static void unmanage_client(client_t *client, bool destroyed); static void unmanage_client(client_t *client, bool destroyed);
static void update_client_list(void); static void update_client_list(void);
static void update_client_name(client_t *client); static void update_client_name(client_t *client);
@@ -96,6 +99,7 @@ static event_adapter_t *adapter = NULL;
static char *font_family = NULL; static char *font_family = NULL;
static uint32_t font_size = default_font_size; static uint32_t font_size = default_font_size;
static uint32_t dpi = dpi_fallback; static uint32_t dpi = dpi_fallback;
static uint32_t fps = refresh_rate;
static uint32_t bar_y_pad = bar_y_padding; static uint32_t bar_y_pad = bar_y_padding;
static uint32_t tag_x_pad = tag_x_padding; static uint32_t tag_x_pad = tag_x_padding;
static uint32_t layout_symbol_x_pad = layout_symbol_x_padding; static uint32_t layout_symbol_x_pad = layout_symbol_x_padding;
@@ -174,7 +178,8 @@ void focus_monitor(const user_action_arg_t *arg) {
unfocus(current_monitor->selected_client, false); unfocus(current_monitor->selected_client, false);
current_monitor = monitor; current_monitor = monitor;
focus(NULL); focus(NULL);
/* TODO: 调整鼠标光标 */
set_pointer_position(monitor->pointer_x, monitor->pointer_y);
} }
void raise_or_run(const user_action_arg_t *arg) { void raise_or_run(const user_action_arg_t *arg) {
@@ -187,6 +192,8 @@ void raise_or_run(const user_action_arg_t *arg) {
logger("==== raise client: %s, window: 0x%x\n", client->name, logger("==== raise client: %s, window: 0x%x\n", client->name,
client->window); client->window);
current_monitor = client->monitor; current_monitor = client->monitor;
set_pointer_position(current_monitor->pointer_x,
current_monitor->pointer_y);
argument.ui = client->tags; argument.ui = client->tags;
select_tag(&argument); select_tag(&argument);
focus(client); focus(client);
@@ -231,19 +238,22 @@ void move_to_tag(const user_action_arg_t *arg) {
arrange(current_monitor); arrange(current_monitor);
} }
static void print_monitor_info(monitor_t *monitor) {
logger("========== mon[%u]:\n", monitor->index);
logger("x: %d, y: %d, width: %u, height: %u, pointer x: %d, pointer y: %d\n",
monitor->monitor_x, monitor->monitor_y, monitor->monitor_width,
monitor->monitor_height, monitor->pointer_x, monitor->pointer_y);
logger("mon[%u] tags: ", monitor->index);
for (int i = 0; monitor->tags[i]; i++) {
logger("%s%s", i > 0 ? ", " : "", monitor->tags[i]);
}
logger("\n");
}
/* 调试函数,开发完成后删除 */ /* 调试函数,开发完成后删除 */
static void print_monitor_list_info(monitor_t *monitor_list) { static void print_monitor_list_info(monitor_t *monitor_list) {
logger("========================= monitor info =========================\n"); logger("========================= monitor info =========================\n");
for (monitor_t *m = monitor_list; m; m = m->next) { for (monitor_t *m = monitor_list; m; m = m->next) print_monitor_info(m);
logger("========== mon[%u]:\n", m->index);
logger("x: %d, y: %d, width: %u, height: %u\n", m->monitor_x, m->monitor_y,
m->monitor_width, m->monitor_height);
logger("mon[%u] tags: ", m->index);
for (int i = 0; m->tags[i]; i++) {
logger("%s%s", i > 0 ? ", " : "", m->tags[i]);
}
logger("\n");
}
logger("======================= monitor info end =======================\n"); logger("======================= monitor info end =======================\n");
} }
static void print_color(const char *prompt, const color_t *color) { static void print_color(const char *prompt, const color_t *color) {
@@ -356,6 +366,25 @@ void init_monitors(void) {
m->tags = get_monitor_tags(i, m->index); m->tags = get_monitor_tags(i, m->index);
m->selected_tags = 0x1; m->selected_tags = 0x1;
} }
int32_t x, y;
if (get_pointer_position(&x, &y)) {
monitor_t *monitor = rect_to_monitor(monitors, x, y, 1, 1);
print_monitor_info(monitor);
int32_t offset_x = x - monitor->monitor_x;
int32_t offset_y = y - monitor->monitor_y;
logger("==== init monitor pointer position ====\n");
logger("x: %d, y: %d, offset_x: %d, offset_y: %d\n", x, y, offset_x,
offset_y);
logger("== init monitor pointer position end ==\n");
for (monitor_t *m = monitors; m; m = m->next) {
m->pointer_x = m->monitor_x + offset_x;
m->pointer_y = m->monitor_y + offset_y;
}
}
} }
char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index) { char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index) {
@@ -385,6 +414,15 @@ char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index) {
return g_strv_builder_unref_to_strv(builder); return g_strv_builder_unref_to_strv(builder);
} }
void record_mointor_pointer_position(int32_t x, int32_t y, uint32_t timestamp) {
static uint32_t last_timestamp = 0;
if ((timestamp - last_timestamp) < (1000 / fps)) return;
monitor_t *monitor = rect_to_monitor(monitors, x, y, 1, 1);
monitor->pointer_x = x;
monitor->pointer_x = y;
}
void init_wallpaper(void) { void init_wallpaper(void) {
bar_cairo_params_t *p = prepare_wallpaper_surface_params(); bar_cairo_params_t *p = prepare_wallpaper_surface_params();
rect_size_t *screen_size = get_screen_size(); rect_size_t *screen_size = get_screen_size();
@@ -693,6 +731,7 @@ void init_monitor_bar(void) {
void get_xresource_config(void) { void get_xresource_config(void) {
get_xresource_uint32("Xft.dpi", &dpi); get_xresource_uint32("Xft.dpi", &dpi);
get_xresource_uint32("zswm.fps", &fps);
get_xresource_string("zswm.font_family", &font_family, default_font_family); get_xresource_string("zswm.font_family", &font_family, default_font_family);
get_xresource_uint32("zswm.font_size", &font_size); get_xresource_uint32("zswm.font_size", &font_size);
get_xresource_uint32("zswm.bar_y_padding", &bar_y_pad); get_xresource_uint32("zswm.bar_y_padding", &bar_y_pad);
@@ -847,6 +886,8 @@ void expose(expose_event_t *event) {
} }
void motion_notify(motion_notify_event_t *event) { void motion_notify(motion_notify_event_t *event) {
record_mointor_pointer_position(event->root_x, event->root_y, event->time);
if (event->window != get_root_window()) return; if (event->window != get_root_window()) return;
static monitor_t *mon = NULL; static monitor_t *mon = NULL;
@@ -954,6 +995,8 @@ void client_message(client_message_event_t *event) {
const user_action_arg_t arg = {.ui = target_tag}; const user_action_arg_t arg = {.ui = target_tag};
current_monitor = client->monitor; current_monitor = client->monitor;
set_pointer_position(current_monitor->pointer_x,
current_monitor->pointer_y);
select_tag(&arg); select_tag(&arg);
focus(client); focus(client);
restack(current_monitor); restack(current_monitor);
@@ -988,8 +1031,10 @@ void manage_window(xcb_window_t window) {
} }
set_client_tag_prop(c); set_client_tag_prop(c);
grab_buttons_for_client(c, false);
set_window_event_mask(window, false); set_window_event_mask(window, false);
change_window_border_color(window, color_set->border_color.argb); change_window_border_color(window, color_set->border_color.argb);
attach_client(c); attach_client(c);
@@ -1006,6 +1051,18 @@ void manage_window(xcb_window_t window) {
focus(NULL); focus(NULL);
} }
void grab_buttons_for_client(client_t *client, bool focused) {
ungrab_any_button(client->window);
if (!focused) grab_button(client->window, BUTTON_ANY, MODIFIER_ANY);
for (int i = 0; i < LENGTH(buttons); i++) {
if (buttons[i].click_area == click_client_window) {
grab_button(client->window, buttons[i].button, buttons[i].modifiers);
}
}
}
void unmanage_client(client_t *client, bool destroyed) { void unmanage_client(client_t *client, bool destroyed) {
monitor_t *monitor = client->monitor; monitor_t *monitor = client->monitor;
@@ -1098,6 +1155,8 @@ void apply_rules(client_t *client) {
} }
if (switch_to_tag) { if (switch_to_tag) {
current_monitor = client->monitor; current_monitor = client->monitor;
set_pointer_position(current_monitor->pointer_x,
current_monitor->pointer_y);
current_monitor->selected_tags = client->tags; current_monitor->selected_tags = client->tags;
} }
@@ -1187,6 +1246,7 @@ void focus(client_t *client) {
if (client->monitor != current_monitor) current_monitor = client->monitor; if (client->monitor != current_monitor) current_monitor = client->monitor;
detach_stack_client(client); detach_stack_client(client);
attach_stack_client(client); attach_stack_client(client);
grab_buttons_for_client(client, true);
change_window_border_color(client->window, change_window_border_color(client->window,
color_set->active_border_color.argb); color_set->active_border_color.argb);
focus_window(client->window); focus_window(client->window);
@@ -1200,6 +1260,7 @@ void focus(client_t *client) {
void unfocus(client_t *client, bool set_focus) { void unfocus(client_t *client, bool set_focus) {
if (!client) return; if (!client) return;
grab_buttons_for_client(client, false);
change_window_border_color(client->window, color_set->border_color.argb); change_window_border_color(client->window, color_set->border_color.argb);
if (set_focus) focus_window(WINDOW_NONE); if (set_focus) focus_window(WINDOW_NONE);
} }

View File

@@ -2,11 +2,14 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "types.h"
double get_time() { double get_time() {
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
@@ -105,11 +108,11 @@ void extract_color_channel(const uint32_t rgba, double *red, double *green,
*alpha = COLOR_SPLIT(rgba, 0); *alpha = COLOR_SPLIT(rgba, 0);
} }
#define INTERSECT(x, y, w, h, m) \ #define INTERSECT(x, y, w, h, m) \
(MAX(0, MIN((x) + (w), (m)->window_x + (m)->window_width) - \ (MAX(0, MIN((x) + (w), (m)->monitor_x + (int)(m)->monitor_width) - \
MAX((x), (m)->window_x)) * \ MAX((x), (m)->monitor_x)) * \
MAX(0, MIN((y) + (h), (m)->window_y + (m)->window_height) - \ MAX(0, MIN((y) + (h), (m)->monitor_y + (int)(m)->monitor_height) - \
MAX((y), (m)->window_y))) MAX((y), (m)->monitor_y)))
monitor_t *rect_to_monitor(monitor_t *monitors, int32_t x, int32_t y, monitor_t *rect_to_monitor(monitor_t *monitors, int32_t x, int32_t y,
uint32_t width, uint32_t height) { uint32_t width, uint32_t height) {
monitor_t *r = monitors; monitor_t *r = monitors;

View File

@@ -89,6 +89,7 @@ static void convert_event(xcb_generic_event_t *xcb_event,
event->motiion_notify.window = ev->event; event->motiion_notify.window = ev->event;
event->motiion_notify.x = ev->event_x; event->motiion_notify.x = ev->event_x;
event->motiion_notify.y = ev->event_y; event->motiion_notify.y = ev->event_y;
event->motiion_notify.time = ev->time;
break; break;
} }
case XCB_ENTER_NOTIFY: { case XCB_ENTER_NOTIFY: {

View File

@@ -43,7 +43,8 @@ void get_window_class_instance(xcb_window_t window,
xcb_icccm_get_wm_class_reply_t prop; xcb_icccm_get_wm_class_reply_t prop;
const char *class = NULL; const char *class = NULL;
const char *instance = NULL; const char *instance = NULL;
if (xcb_icccm_get_wm_class_reply(conn, cookie, &prop, NULL)) { bool has_reply = xcb_icccm_get_wm_class_reply(conn, cookie, &prop, NULL);
if (has_reply) {
class = prop.class_name; class = prop.class_name;
instance = prop.instance_name; instance = prop.instance_name;
} else { } else {
@@ -54,7 +55,7 @@ void get_window_class_instance(xcb_window_t window,
strncpy(class_instance->class, class, LENGTH(class_instance->class)); strncpy(class_instance->class, class, LENGTH(class_instance->class));
strncpy(class_instance->instance, instance, LENGTH(class_instance->instance)); strncpy(class_instance->instance, instance, LENGTH(class_instance->instance));
xcb_icccm_get_wm_class_reply_wipe(&prop); if (has_reply) xcb_icccm_get_wm_class_reply_wipe(&prop);
} }
static visual_t *find_alpha_visual() { static visual_t *find_alpha_visual() {
@@ -361,3 +362,15 @@ void set_window_fullscreen_state(xcb_window_t window, bool fullscreen) {
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, window, atom, xcb_change_property(conn, XCB_PROP_MODE_REPLACE, window, atom,
XCB_ATOM_WINDOW, 32, data_len, &atom); XCB_ATOM_WINDOW, 32, data_len, &atom);
} }
void ungrab_any_button(xcb_window_t window) {
xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, window, XCB_MOD_MASK_ANY);
}
void grab_button(xcb_window_t window, uint8_t button, uint16_t modifiers) {
uint8_t owner_events = false; /* 事件仅发送给抓取者,不发送给其他窗口 */
uint16_t event_mask =
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE;
xcb_grab_button(conn, owner_events, window, event_mask, XCB_GRAB_MODE_SYNC,
XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, button, modifiers);
}

View File

@@ -182,14 +182,16 @@ bool get_window_tag(xcb_window_t window, client_tag_info_t *client_info) {
XCB_ATOM_CARDINAL, 0, 2); XCB_ATOM_CARDINAL, 0, 2);
xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL); xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
int length = xcb_get_property_value_length(reply); int length = xcb_get_property_value_length(reply);
if (length >= 2) { bool result = length >= 2;
if (result) {
uint32_t *data = xcb_get_property_value(reply); uint32_t *data = xcb_get_property_value(reply);
client_info->tags = data[0]; client_info->tags = data[0];
client_info->monitor_index = data[1]; client_info->monitor_index = data[1];
return true;
} else {
return false;
} }
free(reply);
return result;
} }
void set_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) {

View File

@@ -337,6 +337,11 @@ bool get_pointer_position(int32_t *x, int32_t *y) {
return false; return false;
} }
void set_pointer_position(int32_t x, int32_t y) {
xcb_warp_pointer(conn, XCB_WINDOW_NONE, screen->root, 0, 0, 1, 1, x, y);
xcb_flush(conn);
}
bool xcb_check_mask_event(xcb_event_mask_t event_mask) { bool xcb_check_mask_event(xcb_event_mask_t event_mask) {
xcb_generic_event_t *event = xcb_poll_for_event(conn); xcb_generic_event_t *event = xcb_poll_for_event(conn);
if (!event) return false; if (!event) return false;