Compare commits
10 Commits
323a0f3711
...
5b41eb97cd
| Author | SHA1 | Date | |
|---|---|---|---|
|
5b41eb97cd
|
|||
|
cecd7dc2d9
|
|||
|
92a810f345
|
|||
|
9f8b2453fa
|
|||
|
4428eb056d
|
|||
|
fb0999df90
|
|||
|
41a2289c96
|
|||
|
9b7c3a67ef
|
|||
|
ab3d441928
|
|||
|
94d3be12ec
|
@@ -43,6 +43,7 @@ add_executable(${APP_NAME}
|
||||
${SOURCE_DIR}/xres.c
|
||||
${SOURCE_DIR}/status.c
|
||||
${SOURCE_DIR}/audio.c
|
||||
${SOURCE_DIR}/rect.c
|
||||
)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
22
src/action.c
22
src/action.c
@@ -65,7 +65,7 @@ void raise_or_run(const user_action_arg_t *arg) {
|
||||
if (client && client == wm.client_focused) return;
|
||||
|
||||
if (client) {
|
||||
wm.current_monitor = client->monitor;
|
||||
wm_set_current_monitor(client->monitor, true);
|
||||
monitor_select_tag(client->monitor, client->tags);
|
||||
client_stack_raise(client);
|
||||
client_focus(client);
|
||||
@@ -118,3 +118,23 @@ void kill_client(const user_action_arg_t *arg) {
|
||||
client_kill(wm.client_focused);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据 client 的当前状态切换 client 下一状态
|
||||
* @description 如果当前 client 被遮挡了或者最小化了,则显示出来,否则最小化
|
||||
*/
|
||||
void change_client_state_dwim(const user_action_arg_t *arg) {
|
||||
client_t *client = (client_t *)arg->ptr;
|
||||
if (!client) return;
|
||||
|
||||
if (client != wm.client_stack_list &&
|
||||
client_get_obscured_state(client, wm.client_stack_list) !=
|
||||
obscured_none) {
|
||||
client_stack_raise(client);
|
||||
client_focus(client);
|
||||
return;
|
||||
}
|
||||
|
||||
client_set_minimize(client, !client->minimize);
|
||||
if (!client->minimize) client_stack_raise(client);
|
||||
}
|
||||
|
||||
@@ -63,3 +63,4 @@ void toggle_client_fullscreen(const user_action_arg_t *arg);
|
||||
void toggle_client_maximize(const user_action_arg_t *arg);
|
||||
void toggle_client_minimize(const user_action_arg_t *arg);
|
||||
void kill_client(const user_action_arg_t *arg);
|
||||
void change_client_state_dwim(const user_action_arg_t *arg);
|
||||
|
||||
77
src/client.c
77
src/client.c
@@ -10,6 +10,7 @@
|
||||
#include "atoms-extern.h"
|
||||
#include "base.h"
|
||||
#include "monitor.h"
|
||||
#include "rect.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "wm.h"
|
||||
@@ -158,9 +159,12 @@ static inline void client_init_geometry(client_t *c) {
|
||||
client_change_border_width(c, wm.border_width);
|
||||
}
|
||||
|
||||
static void client_init_tag_by_wm_desktop(client_t *client) {
|
||||
static void client_init_tag_by_wm_desktop(client_t *client, uint32_t tag_mask) {
|
||||
uint32_t tag_index = 0;
|
||||
if (!xwindow_get_wm_desktop(client->window, &tag_index)) return;
|
||||
if (!xwindow_get_wm_desktop(client->window, &tag_index)) {
|
||||
goto tag_fallback;
|
||||
}
|
||||
|
||||
for (monitor_t *m = wm.monitor_list; m; m = m->next) {
|
||||
for (tag_t *tag = m->tag_list; tag; tag = tag->next) {
|
||||
if (tag->index == tag_index) {
|
||||
@@ -170,6 +174,9 @@ static void client_init_tag_by_wm_desktop(client_t *client) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tag_fallback:
|
||||
client->tags = tag_mask;
|
||||
}
|
||||
|
||||
static void set_window_event_mask(xcb_window_t window, bool clean) {
|
||||
@@ -223,15 +230,14 @@ void client_manage(xcb_window_t window,
|
||||
if (c->transient_for_window && (transient_for_client = client_get_by_window(
|
||||
c->transient_for_window))) {
|
||||
c->monitor = transient_for_client->monitor;
|
||||
c->tags = transient_for_client->tags;
|
||||
client_init_tag_by_wm_desktop(c, transient_for_client->tags);
|
||||
} else {
|
||||
c->monitor = wm.current_monitor;
|
||||
c->tags = c->monitor->selected_tag->mask;
|
||||
client_init_tag_by_wm_desktop(c, c->monitor->selected_tag->mask);
|
||||
client_apply_rules(c, wm.rules, wm.rules_count);
|
||||
}
|
||||
|
||||
client_init_geometry(c);
|
||||
client_init_tag_by_wm_desktop(c);
|
||||
client_tags_apply(c);
|
||||
}
|
||||
|
||||
@@ -262,6 +268,8 @@ void client_manage(xcb_window_t window,
|
||||
char **client_get_task_title(client_t *client) {
|
||||
if (client->net_name) return &client->net_name;
|
||||
if (client->name) return &client->name;
|
||||
if (client->instance) return &client->instance;
|
||||
if (client->class) return &client->class;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -274,9 +282,11 @@ bool client_need_layout(client_t *client) {
|
||||
}
|
||||
|
||||
void client_send_to_tag(client_t *client, uint32_t tag_mask) {
|
||||
if (client->tags == tag_mask) return;
|
||||
client->tags = tag_mask;
|
||||
client_tags_apply(client);
|
||||
monitor_select_tag(client->monitor, tag_mask);
|
||||
monitor_arrange(client->monitor);
|
||||
monitor_draw_bar(client->monitor);
|
||||
}
|
||||
|
||||
void client_send_to_monitor(client_t *client, monitor_t *monitor) {
|
||||
@@ -292,7 +302,7 @@ void client_send_to_monitor(client_t *client, monitor_t *monitor) {
|
||||
client->tags = monitor->selected_tag->mask;
|
||||
client_add_to_tag(client, monitor->selected_tag);
|
||||
|
||||
wm.current_monitor = monitor;
|
||||
wm_set_current_monitor(monitor, true);
|
||||
monitor_arrange(m);
|
||||
monitor_arrange(monitor);
|
||||
monitor_draw_bar(m);
|
||||
@@ -576,7 +586,7 @@ void client_apply_workarea_geometry(client_t *client, area_t geometry) {
|
||||
x = workarea.x + workarea.width - width - client->border_width * 2;
|
||||
}
|
||||
if (y + height + client->border_width * 2 > workarea.y + workarea.height) {
|
||||
y = workarea.y + workarea.width - height - client->border_width * 2;
|
||||
y = workarea.y + workarea.height - height - client->border_width * 2;
|
||||
}
|
||||
|
||||
area_t rect = {.x = x, .y = y, .width = width, .height = height};
|
||||
@@ -604,7 +614,7 @@ void client_apply_rules(client_t *client, const rule_t rules[],
|
||||
client->tags = t->mask;
|
||||
|
||||
if (r->switch_to_tag) {
|
||||
wm.current_monitor = m;
|
||||
wm_set_current_monitor(m, true);
|
||||
m->selected_tag = t;
|
||||
|
||||
logger("++ switch to tag: %u\n", t->index);
|
||||
@@ -634,6 +644,8 @@ void client_focus(client_t *client) {
|
||||
}
|
||||
|
||||
void client_stack_raise(client_t *client) {
|
||||
if (wm.client_stack_list == client) return;
|
||||
|
||||
client_detach_stack(client);
|
||||
client_attach_stack(client);
|
||||
wm_restack_clients();
|
||||
@@ -642,3 +654,50 @@ void client_stack_raise(client_t *client) {
|
||||
bool client_is_visible(client_t *client) {
|
||||
return client->tags & client->monitor->selected_tag->mask;
|
||||
}
|
||||
|
||||
static inline rect_t client_to_rect(client_t *client) {
|
||||
return (rect_t){
|
||||
.x1 = client->geometry.x,
|
||||
.y1 = client->geometry.y,
|
||||
.x2 = client->geometry.x + (int32_t)client_width(client),
|
||||
.y2 = client->geometry.y + (int32_t)client_height(client),
|
||||
};
|
||||
}
|
||||
|
||||
obscured_t client_get_obscured_state(client_t *client, client_t *client_stack) {
|
||||
if (!client || !client_stack) return obscured_none;
|
||||
|
||||
rect_t source = client_to_rect(client);
|
||||
size_t clip_count = 0;
|
||||
size_t clip_capacity = 0;
|
||||
rect_t *clips = nullptr;
|
||||
|
||||
bool has_overlap = false;
|
||||
for (client_t *c = client_stack; c; c = c->stack_next) {
|
||||
if (c == client) break;
|
||||
if (c->minimize || !client_is_visible(c)) continue;
|
||||
|
||||
rect_t clip = client_to_rect(c);
|
||||
if (!rect_intersection(source, clip, nullptr)) continue;
|
||||
|
||||
has_overlap = true;
|
||||
if (clip_count == clip_capacity) {
|
||||
clip_capacity = clip_capacity ? clip_capacity * 2 : 4;
|
||||
p_realloc(&clips, clip_capacity);
|
||||
}
|
||||
clips[clip_count++] = clip;
|
||||
}
|
||||
|
||||
if (!has_overlap) {
|
||||
p_delete(&clips);
|
||||
return obscured_none;
|
||||
}
|
||||
|
||||
rect_t *remaining = nullptr;
|
||||
size_t remaining_count =
|
||||
rect_subtract_many(source, clips, clip_count, &remaining);
|
||||
|
||||
p_delete(&clips);
|
||||
p_delete(&remaining);
|
||||
return remaining_count == 0 ? obscured_fully : obscured_partially;
|
||||
}
|
||||
|
||||
@@ -61,6 +61,13 @@ void client_stack_raise(client_t *client);
|
||||
|
||||
bool client_is_visible(client_t *client);
|
||||
|
||||
typedef enum obscured_t {
|
||||
obscured_none,
|
||||
obscured_partially,
|
||||
obscured_fully,
|
||||
} obscured_t;
|
||||
obscured_t client_get_obscured_state(client_t *client, client_t *client_stack);
|
||||
|
||||
static inline uint16_t client_width(client_t *c) {
|
||||
return c->geometry.width + c->border_width * 2;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,13 @@ static const char *const active_border_color = "#005577";
|
||||
|
||||
static const button_t button_list[] = {
|
||||
{click_tag, modifier_none, button_left, select_tag_of_current_monitor, {0}},
|
||||
{click_client_name, modifier_none, button_left, toggle_client_minimize, {0}},
|
||||
{
|
||||
click_client_name,
|
||||
modifier_none,
|
||||
button_left,
|
||||
change_client_state_dwim,
|
||||
{0},
|
||||
},
|
||||
};
|
||||
|
||||
#define TAGKEYS(KEY, TAG) \
|
||||
|
||||
25
src/event.c
25
src/event.c
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "action.h"
|
||||
#include "atoms-extern.h"
|
||||
#include "base.h"
|
||||
#include "client.h"
|
||||
#include "default_config.h"
|
||||
#include "monitor.h"
|
||||
@@ -34,7 +35,7 @@ static void button_press(xcb_button_press_event_t *ev) {
|
||||
|
||||
if (!monitor) return;
|
||||
|
||||
wm.current_monitor = monitor;
|
||||
wm_set_current_monitor(monitor, false);
|
||||
if (ev->event_x >= monitor->tag_extent.start &&
|
||||
ev->event_x <= monitor->tag_extent.end) {
|
||||
click_area = click_tag;
|
||||
@@ -118,6 +119,11 @@ static void key_press(xcb_key_press_event_t *ev) {
|
||||
for (int i = 0; i < countof(key_list); i++) {
|
||||
keyboard_t key = key_list[i];
|
||||
if (keysym == key.keysym && ev->state == key.modifiers && key.func) {
|
||||
/* 查询光标所在屏幕并将其设置为当前屏幕 */
|
||||
point_t point = {.x = ev->root_x, .y = ev->root_y};
|
||||
monitor_t *monitor = wm_get_monitor_by_point(point);
|
||||
wm_set_current_monitor(monitor, false);
|
||||
|
||||
key.func(&key.arg);
|
||||
return;
|
||||
}
|
||||
@@ -188,7 +194,7 @@ static void client_message(xcb_client_message_event_t *ev) {
|
||||
|
||||
switch (ev->data.data32[0]) {
|
||||
case 2: /* 来自 pager */
|
||||
wm.current_monitor = c->monitor;
|
||||
wm_set_current_monitor(c->monitor, true);
|
||||
monitor_select_tag(c->monitor, t->mask);
|
||||
client_focus(c);
|
||||
break;
|
||||
@@ -293,6 +299,19 @@ static void expose(xcb_expose_event_t *ev) {
|
||||
xcb_flush(wm.xcb_conn);
|
||||
}
|
||||
|
||||
static void enter_notify(xcb_enter_notify_event_t *ev) {
|
||||
client_t *client = client_get_by_window(ev->event);
|
||||
if (!client || wm.client_focused == client) return;
|
||||
|
||||
client_focus(client);
|
||||
}
|
||||
|
||||
static void focus_in(xcb_focus_in_event_t *ev) {
|
||||
client_t *client = client_get_by_window(ev->event);
|
||||
if (!client) return;
|
||||
wm_set_current_monitor(client->monitor, ev->mode != XCB_NOTIFY_MODE_NORMAL);
|
||||
}
|
||||
|
||||
static void handle_xcb_event(xcb_generic_event_t *event) {
|
||||
uint8_t event_type = XCB_EVENT_RESPONSE_TYPE(event);
|
||||
const char *label = xcb_event_get_label(event_type);
|
||||
@@ -316,6 +335,8 @@ static void handle_xcb_event(xcb_generic_event_t *event) {
|
||||
EVENT(XCB_PROPERTY_NOTIFY, property_notify);
|
||||
EVENT(XCB_UNMAP_NOTIFY, unmap_notify);
|
||||
EVENT(XCB_DESTROY_NOTIFY, destroy_notify);
|
||||
EVENT(XCB_ENTER_NOTIFY, enter_notify);
|
||||
EVENT(XCB_FOCUS_IN, focus_in);
|
||||
|
||||
#undef EVENT
|
||||
}
|
||||
|
||||
@@ -361,14 +361,13 @@ void monitor_save_cursor_point(monitor_t *monitor) {
|
||||
}
|
||||
|
||||
void monitor_restore_cursor_point(monitor_t *monitor) {
|
||||
if (monitor->position_inited) {
|
||||
xcursor_set_pointer_position(monitor->cursor_position);
|
||||
return;
|
||||
if (!monitor->position_inited) {
|
||||
point_t point = xcursor_query_pointer_position();
|
||||
monitor_t *m = wm_get_monitor_by_point(point);
|
||||
monitor->cursor_position.x = point.x - m->geometry.x + monitor->geometry.x;
|
||||
monitor->cursor_position.y = point.y - m->geometry.y + monitor->geometry.y;
|
||||
monitor->position_inited = true;
|
||||
}
|
||||
|
||||
point_t point = xcursor_query_pointer_position();
|
||||
monitor_t *m = wm_get_monitor_by_point(point);
|
||||
monitor->cursor_position.x = point.x - m->geometry.x + monitor->geometry.x;
|
||||
monitor->cursor_position.y = point.y - m->geometry.y + monitor->geometry.y;
|
||||
monitor->position_inited = true;
|
||||
xcursor_set_pointer_position(monitor->cursor_position);
|
||||
}
|
||||
|
||||
155
src/rect.c
Normal file
155
src/rect.c
Normal file
@@ -0,0 +1,155 @@
|
||||
#include "rect.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
static inline bool rect_valid(rect_t rect) {
|
||||
return rect.x1 < rect.x2 && rect.y1 < rect.y2;
|
||||
}
|
||||
|
||||
/* 将一个合法矩形追加到动态矩形数组中。 */
|
||||
static inline void rect_list_append(rect_t **list, size_t *length,
|
||||
size_t *capacity, rect_t rect) {
|
||||
if (!rect_valid(rect)) return;
|
||||
|
||||
if (*length == *capacity) {
|
||||
*capacity = *capacity ? *capacity * 2 : 4;
|
||||
p_realloc(list, *capacity);
|
||||
}
|
||||
(*list)[(*length)++] = rect;
|
||||
}
|
||||
|
||||
bool rect_intersection(rect_t a, rect_t b, rect_t *intersection) {
|
||||
if (!rect_valid(a) || !rect_valid(b)) return false;
|
||||
|
||||
rect_t overlap = {
|
||||
.x1 = MAX(a.x1, b.x1),
|
||||
.y1 = MAX(a.y1, b.y1),
|
||||
.x2 = MIN(a.x2, b.x2),
|
||||
.y2 = MIN(a.y2, b.y2),
|
||||
};
|
||||
if (!rect_valid(overlap)) return false;
|
||||
|
||||
if (intersection) *intersection = overlap;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t rect_subtract(rect_t source, rect_t clip, rect_t remaining[4]) {
|
||||
if (!rect_valid(source)) return 0;
|
||||
|
||||
rect_t overlap;
|
||||
if (!rect_intersection(source, clip, &overlap)) {
|
||||
if (remaining) remaining[0] = source;
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
/*
|
||||
* source: [sx1,sx2) x [sy1,sy2)
|
||||
* overlap: [ox1,ox2) x [oy1,oy2) = source 与 clip 的交集
|
||||
*
|
||||
* y=sy1 ┌───────────────────────────────────────────┐
|
||||
* │ TOP │
|
||||
* │ UL UR │
|
||||
* y=oy1 ├───────────────┬───────────────┬───────────┤
|
||||
* │ LEFT │ OVERLAP │ RIGHT │
|
||||
* y=oy2 ├───────────────┴───────────────┴───────────┤
|
||||
* │ LL LR │
|
||||
* │ BOTTOM │
|
||||
* y=sy2 └───────────────────────────────────────────┘
|
||||
* x=sx1 x=ox1 x=ox2 x=sx2
|
||||
*
|
||||
* 角块归属:
|
||||
* UL、UR 属于 TOP
|
||||
* LL、LR 属于 BOTTOM
|
||||
* LEFT/RIGHT 只覆盖 y ∈ [oy1, oy2),因此不会包含四个角块。
|
||||
*/
|
||||
rect_t parts[] = {
|
||||
/* top */
|
||||
{
|
||||
.x1 = source.x1,
|
||||
.y1 = source.y1,
|
||||
.x2 = source.x2,
|
||||
.y2 = overlap.y1,
|
||||
},
|
||||
/* bottom */
|
||||
{
|
||||
.x1 = source.x1,
|
||||
.y1 = overlap.y2,
|
||||
.x2 = source.x2,
|
||||
.y2 = source.y2,
|
||||
},
|
||||
/* left */
|
||||
{
|
||||
.x1 = source.x1,
|
||||
.y1 = overlap.y1,
|
||||
.x2 = overlap.x1,
|
||||
.y2 = overlap.y2,
|
||||
},
|
||||
/* right */
|
||||
{
|
||||
.x1 = overlap.x2,
|
||||
.y1 = overlap.y1,
|
||||
.x2 = source.x2,
|
||||
.y2 = overlap.y2,
|
||||
},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < countof(parts); i++) {
|
||||
if (!rect_valid(parts[i])) continue;
|
||||
if (remaining) remaining[count] = parts[i];
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t rect_subtract_many(rect_t source, const rect_t clips[],
|
||||
size_t clip_count, rect_t **remaining) {
|
||||
/*
|
||||
* 实现说明:
|
||||
* 初始剩余集合为 {source},然后依次处理每个 clip:
|
||||
* 1) 用 clip 去减当前集合中的每个碎片
|
||||
* 2) 将产生的新碎片合并到 next 集合
|
||||
* 3) 用 next 替换 current,进入下一轮
|
||||
* 最终 current 即 source - clips[0] - clips[1] - ... 的结果。
|
||||
*/
|
||||
if (remaining) *remaining = nullptr;
|
||||
if (!rect_valid(source)) return 0;
|
||||
|
||||
size_t current_length = 1;
|
||||
size_t current_capacity = 1;
|
||||
rect_t *current = p_new(rect_t, current_capacity);
|
||||
current[0] = source;
|
||||
|
||||
if (clips) {
|
||||
for (size_t i = 0; i < clip_count && current_length > 0; i++) {
|
||||
rect_t clip = clips[i];
|
||||
if (!rect_valid(clip)) continue;
|
||||
|
||||
size_t next_length = 0;
|
||||
size_t next_capacity = current_length ? current_length : 1;
|
||||
rect_t *next = p_new(rect_t, next_capacity);
|
||||
|
||||
for (size_t j = 0; j < current_length; j++) {
|
||||
rect_t fragments[4];
|
||||
size_t fragment_count = rect_subtract(current[j], clip, fragments);
|
||||
for (size_t k = 0; k < fragment_count; k++) {
|
||||
rect_list_append(&next, &next_length, &next_capacity, fragments[k]);
|
||||
}
|
||||
}
|
||||
|
||||
p_delete(¤t);
|
||||
current = next;
|
||||
current_length = next_length;
|
||||
current_capacity = next_capacity;
|
||||
}
|
||||
}
|
||||
|
||||
if (remaining) {
|
||||
*remaining = current;
|
||||
} else {
|
||||
p_delete(¤t);
|
||||
}
|
||||
|
||||
return current_length;
|
||||
}
|
||||
41
src/rect.h
Normal file
41
src/rect.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct rect_t {
|
||||
int32_t x1;
|
||||
int32_t y1;
|
||||
int32_t x2;
|
||||
int32_t y2;
|
||||
} rect_t;
|
||||
|
||||
bool rect_intersection(rect_t a, rect_t b, rect_t *intersection);
|
||||
size_t rect_subtract(rect_t source, rect_t clip, rect_t remaining[4]);
|
||||
/**
|
||||
* @brief 从 source 中按顺序减去 clips 中的多个矩形
|
||||
* @param source 源矩形
|
||||
* @param clips 要减去的矩形数组,可为 nullptr
|
||||
* @param clip_count clips 的长度
|
||||
* @param remaining 输出剩余矩形数组;若不为 nullptr,则由函数分配内存并由调用方释放
|
||||
* @return 剩余矩形数量
|
||||
*
|
||||
* @code{.c}
|
||||
* rect_t source = {.x1 = 0, .y1 = 0, .x2 = 100, .y2 = 80};
|
||||
* rect_t clips[] = {
|
||||
* {.x1 = 10, .y1 = 10, .x2 = 40, .y2 = 40},
|
||||
* {.x1 = 30, .y1 = 20, .x2 = 70, .y2 = 60},
|
||||
* };
|
||||
*
|
||||
* rect_t *remaining = nullptr;
|
||||
* size_t count = rect_subtract_many(source, clips, 2, &remaining);
|
||||
*
|
||||
* for (size_t i = 0; i < count; i++) {
|
||||
* // use remaining[i]
|
||||
* }
|
||||
*
|
||||
* free(remaining);
|
||||
* @endcode
|
||||
*/
|
||||
size_t rect_subtract_many(rect_t source, const rect_t clips[],
|
||||
size_t clip_count, rect_t **remaining);
|
||||
@@ -90,10 +90,14 @@ static inline void logger(const char *format, ...) {
|
||||
|
||||
#ifdef MIN
|
||||
#undef MIN
|
||||
#endif
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifdef MAX
|
||||
#undef MAX
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
33
src/wm.c
33
src/wm.c
@@ -517,6 +517,20 @@ void wm_restack_clients(void) {
|
||||
xcb_flush(wm.xcb_conn);
|
||||
}
|
||||
|
||||
void wm_set_current_monitor(monitor_t *monitor, bool restore_cursor) {
|
||||
if (!monitor || wm.current_monitor == monitor) return;
|
||||
|
||||
point_t point = xcursor_query_pointer_position();
|
||||
monitor_t *point_monitor = wm_get_monitor_by_point(point);
|
||||
if (point_monitor == wm.current_monitor) {
|
||||
point_monitor->cursor_position = point;
|
||||
point_monitor->position_inited = true;
|
||||
}
|
||||
|
||||
wm.current_monitor = monitor;
|
||||
if (restore_cursor) monitor_restore_cursor_point(monitor);
|
||||
}
|
||||
|
||||
static inline int intersect(area_t area, monitor_t *m) {
|
||||
return MAX(0, MIN(area.x + area.width, m->geometry.x + m->geometry.width) -
|
||||
MAX(area.x, m->geometry.x)) *
|
||||
@@ -524,7 +538,12 @@ static inline int intersect(area_t area, monitor_t *m) {
|
||||
MAX(area.y, m->geometry.y));
|
||||
}
|
||||
|
||||
monitor_t *wm_get_monitor_by_area(area_t area) {
|
||||
monitor_t *__attribute__((returns_nonnull)) wm_get_monitor_by_area(
|
||||
area_t area) {
|
||||
if (wm.current_monitor == nullptr) {
|
||||
fatal("wm_get_monitor_by_area: current monitor is nullptr");
|
||||
}
|
||||
|
||||
monitor_t *monitor = wm.current_monitor;
|
||||
int temp_area, max_area = 0;
|
||||
for (monitor_t *m = wm.monitor_list; m; m = m->next) {
|
||||
@@ -537,14 +556,10 @@ monitor_t *wm_get_monitor_by_area(area_t area) {
|
||||
return monitor;
|
||||
}
|
||||
|
||||
monitor_t *wm_get_monitor_by_point(point_t point) {
|
||||
for (monitor_t *m = wm.monitor_list; m; m = m->next) {
|
||||
if (m->geometry.x <= point.x &&
|
||||
point.x < m->geometry.x + m->geometry.width) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return wm.monitor_list;
|
||||
monitor_t *__attribute__((returns_nonnull)) wm_get_monitor_by_point(
|
||||
point_t point) {
|
||||
area_t area = {.x = point.x, .y = point.y, .width = 1, .height = 1};
|
||||
return wm_get_monitor_by_area(area);
|
||||
}
|
||||
|
||||
monitor_t *wm_get_monitor_by_window(xcb_window_t window) {
|
||||
|
||||
6
src/wm.h
6
src/wm.h
@@ -57,7 +57,9 @@ extern wm_t wm;
|
||||
void wm_restart(void);
|
||||
void wm_quit(void);
|
||||
void wm_restack_clients(void);
|
||||
monitor_t *wm_get_monitor_by_area(area_t area);
|
||||
monitor_t *wm_get_monitor_by_point(point_t point);
|
||||
void wm_set_current_monitor(monitor_t *monitor, bool restore_cursor);
|
||||
monitor_t *__attribute__((returns_nonnull)) wm_get_monitor_by_area(area_t area);
|
||||
monitor_t *__attribute__((returns_nonnull)) wm_get_monitor_by_point(
|
||||
point_t point);
|
||||
monitor_t *wm_get_monitor_by_window(xcb_window_t window);
|
||||
monitor_t *wm_get_next_monitor(monitor_t *monitor);
|
||||
|
||||
Reference in New Issue
Block a user