Compare commits
6 Commits
fd843dc826
...
1e3a571619
| Author | SHA1 | Date | |
|---|---|---|---|
|
1e3a571619
|
|||
|
d4c03fcfbd
|
|||
|
663db3412f
|
|||
|
af4a45a342
|
|||
|
413e68f572
|
|||
|
3121b49d1b
|
@@ -453,6 +453,9 @@ bool backend_apply_effect(
|
|||||||
window_configure_t *cfgs = p_new(window_configure_t, effect_count);
|
window_configure_t *cfgs = p_new(window_configure_t, effect_count);
|
||||||
size_t cfg_count = 0;
|
size_t cfg_count = 0;
|
||||||
|
|
||||||
|
bool focus_window_changed = false;
|
||||||
|
xcb_window_t focus_window = XCB_WINDOW_NONE;
|
||||||
|
|
||||||
for (size_t i = 0; i < effect_count; ++i) {
|
for (size_t i = 0; i < effect_count; ++i) {
|
||||||
const effect_t *e = &effects[i];
|
const effect_t *e = &effects[i];
|
||||||
switch (e->type) {
|
switch (e->type) {
|
||||||
@@ -463,7 +466,8 @@ bool backend_apply_effect(
|
|||||||
xcb_unmap_window(conn, e->as.unmap.window);
|
xcb_unmap_window(conn, e->as.unmap.window);
|
||||||
break;
|
break;
|
||||||
case ZDWM_EFFECT_FOCUS_WINDOW:
|
case ZDWM_EFFECT_FOCUS_WINDOW:
|
||||||
backend_focus_window(backend, e->as.focus.window);
|
focus_window = e->as.focus.window;
|
||||||
|
focus_window_changed = true;
|
||||||
break;
|
break;
|
||||||
case ZDWM_EFFECT_MOVE_WINDOW: {
|
case ZDWM_EFFECT_MOVE_WINDOW: {
|
||||||
window_configure_t *cfg =
|
window_configure_t *cfg =
|
||||||
@@ -514,6 +518,8 @@ bool backend_apply_effect(
|
|||||||
}
|
}
|
||||||
p_delete(&cfgs);
|
p_delete(&cfgs);
|
||||||
|
|
||||||
|
if (focus_window_changed) backend_focus_window(backend, focus_window);
|
||||||
|
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "core/event.h"
|
#include "core/event.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_event.h>
|
#include <xcb/xcb_event.h>
|
||||||
@@ -71,6 +72,18 @@ static window_geometry_mode_t geometry_mode_from_states(
|
|||||||
return ZDWM_GEOMETRY_NORMAL;
|
return ZDWM_GEOMETRY_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool urgent_from_states(
|
||||||
|
const atoms_t *atoms,
|
||||||
|
const xcb_atom_t *state_atoms,
|
||||||
|
uint32_t state_count
|
||||||
|
) {
|
||||||
|
for (uint32_t i = 0; i < state_count; ++i) {
|
||||||
|
if (state_atoms[i] == atoms->_NET_WM_STATE_DEMANDS_ATTENTION) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool handle_map_request(
|
static bool handle_map_request(
|
||||||
backend_t *backend,
|
backend_t *backend,
|
||||||
event_t *event,
|
event_t *event,
|
||||||
@@ -127,6 +140,9 @@ static bool handle_map_request(
|
|||||||
state_count,
|
state_count,
|
||||||
&ev->props.state_count
|
&ev->props.state_count
|
||||||
);
|
);
|
||||||
|
if (!ev->urgent) {
|
||||||
|
ev->urgent = urgent_from_states(atoms, state_atoms, state_count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p_delete(&state_atoms);
|
p_delete(&state_atoms);
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
X(_NET_WM_STATE_MAXIMIZED_VERT) \
|
X(_NET_WM_STATE_MAXIMIZED_VERT) \
|
||||||
X(_NET_WM_STATE_MAXIMIZED_HORZ) \
|
X(_NET_WM_STATE_MAXIMIZED_HORZ) \
|
||||||
\
|
\
|
||||||
|
X(_NET_WM_STATE_DEMANDS_ATTENTION) \
|
||||||
|
\
|
||||||
X(_NET_WM_WINDOW_TYPE) \
|
X(_NET_WM_WINDOW_TYPE) \
|
||||||
X(_NET_WM_WINDOW_TYPE_NORMAL) \
|
X(_NET_WM_WINDOW_TYPE_NORMAL) \
|
||||||
X(_NET_WM_WINDOW_TYPE_DESKTOP) \
|
X(_NET_WM_WINDOW_TYPE_DESKTOP) \
|
||||||
|
|||||||
@@ -5,14 +5,6 @@
|
|||||||
|
|
||||||
#include "core/types.h"
|
#include "core/types.h"
|
||||||
|
|
||||||
typedef uint32_t dirty_mask_t;
|
|
||||||
|
|
||||||
typedef enum dirty_flags_t : dirty_mask_t {
|
|
||||||
ZDWM_DIRTY_NONE = 0,
|
|
||||||
ZDWM_DIRTY_LAYOUT = 1u << 0, /* 需要重新计算布局 */
|
|
||||||
ZDWM_DIRTY_OUTPUT = 1u << 1, /* 当前 output 有变更 */
|
|
||||||
} dirty_flags_t;
|
|
||||||
|
|
||||||
typedef enum effect_type_t {
|
typedef enum effect_type_t {
|
||||||
ZDWM_EFFECT_MAP_WINDOW = 1,
|
ZDWM_EFFECT_MAP_WINDOW = 1,
|
||||||
ZDWM_EFFECT_UNMAP_WINDOW,
|
ZDWM_EFFECT_UNMAP_WINDOW,
|
||||||
@@ -74,7 +66,7 @@ typedef struct plan_t {
|
|||||||
effect_t *effects;
|
effect_t *effects;
|
||||||
size_t count;
|
size_t count;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
dirty_mask_t dirty_flags;
|
bool need_relayout;
|
||||||
} plan_t;
|
} plan_t;
|
||||||
|
|
||||||
void plan_reset(plan_t *plan);
|
void plan_reset(plan_t *plan);
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ static workspace_id_t derive_window_workspace(const state_t *state) {
|
|||||||
return state->outputs[state->current_output_index].current_workspace_id;
|
return state->outputs[state->current_output_index].current_workspace_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool route_map_request(
|
static void route_map_request(
|
||||||
const state_t *state,
|
const state_t *state,
|
||||||
const rules_t *rules,
|
const rules_t *rules,
|
||||||
const window_map_request_event_t *e,
|
const window_map_request_event_t *e,
|
||||||
command_buffer_t *out
|
command_buffer_t *out
|
||||||
) {
|
) {
|
||||||
if (state_window_get(state, e->window)) return false;
|
if (state_window_get(state, e->window)) return;
|
||||||
|
|
||||||
window_layer_type_t layer_type = window_classify_layer(&e->props);
|
window_layer_type_t layer_type = window_classify_layer(&e->props);
|
||||||
if (e->transient_for != ZDWM_WINDOW_ID_INVALID) {
|
if (e->transient_for != ZDWM_WINDOW_ID_INVALID) {
|
||||||
@@ -91,11 +91,9 @@ static bool route_map_request(
|
|||||||
command_buffer_push(out, &switch_workspace_cmd);
|
command_buffer_push(out, &switch_workspace_cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool policy_route_event(
|
void policy_route_event(
|
||||||
const policy_context_t *ctx,
|
const policy_context_t *ctx,
|
||||||
const event_t *event,
|
const event_t *event,
|
||||||
command_buffer_t *out
|
command_buffer_t *out
|
||||||
@@ -104,14 +102,14 @@ bool policy_route_event(
|
|||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case ZDWM_EVENT_WINDOW_MAP_REQUEST: {
|
case ZDWM_EVENT_WINDOW_MAP_REQUEST: {
|
||||||
auto rules = ctx->rules;
|
auto rules = ctx->rules;
|
||||||
return route_map_request(state, rules, &event->as.window_map_request, out);
|
route_map_request(state, rules, &event->as.window_map_request, out);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool manage_window(
|
static void manage_window(
|
||||||
const policy_context_t *ctx,
|
const policy_context_t *ctx,
|
||||||
const manage_window_command_t *command,
|
const manage_window_command_t *command,
|
||||||
plan_t *plan
|
plan_t *plan
|
||||||
@@ -120,66 +118,100 @@ static bool manage_window(
|
|||||||
auto window = state_window_add(state, &command->info);
|
auto window = state_window_add(state, &command->info);
|
||||||
auto window_id = window->id;
|
auto window_id = window->id;
|
||||||
state_window_set_workspace(state, window_id, command->workspace);
|
state_window_set_workspace(state, window_id, command->workspace);
|
||||||
|
state_workspace_set_focused_window(state, command->workspace, window_id);
|
||||||
state_window_set_floating(state, window_id, command->floating);
|
state_window_set_floating(state, window_id, command->floating);
|
||||||
|
|
||||||
if (!state_workspace_show(state, command->workspace)) return false;
|
if (!state_workspace_show(state, command->workspace)) return;
|
||||||
|
|
||||||
effect_t map_effect = {
|
effect_t map_effect = {
|
||||||
.type = ZDWM_EFFECT_MAP_WINDOW,
|
.type = ZDWM_EFFECT_MAP_WINDOW,
|
||||||
.as.map.window = window_id,
|
.as.map.window = window_id,
|
||||||
};
|
};
|
||||||
|
effect_t focus_effect = {
|
||||||
|
.type = ZDWM_EFFECT_FOCUS_WINDOW,
|
||||||
|
.as.focus.window = window_id,
|
||||||
|
};
|
||||||
plan_push_effect(plan, &map_effect);
|
plan_push_effect(plan, &map_effect);
|
||||||
|
plan_push_effect(plan, &focus_effect);
|
||||||
|
|
||||||
if (window_need_layout(window)) {
|
if (window_need_layout(window)) {
|
||||||
plan->dirty_flags |= ZDWM_DIRTY_LAYOUT;
|
plan->need_relayout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool switch_workspace(
|
static void add_switch_workspace_effects(
|
||||||
|
const state_t *state,
|
||||||
|
workspace_id_t old_workspace,
|
||||||
|
workspace_id_t new_workspace,
|
||||||
|
plan_t *plan
|
||||||
|
) {
|
||||||
|
for (size_t i = 0; i < state->window_count; ++i) {
|
||||||
|
window_t *window = &state->windows[i];
|
||||||
|
if (window->sticky) continue;
|
||||||
|
|
||||||
|
if (window->workspace_id == old_workspace) {
|
||||||
|
effect_t unmap_effect = {
|
||||||
|
.type = ZDWM_EFFECT_UNMAP_WINDOW,
|
||||||
|
.as.unmap.window = window->id,
|
||||||
|
};
|
||||||
|
plan_push_effect(plan, &unmap_effect);
|
||||||
|
} else if (window->workspace_id == new_workspace) {
|
||||||
|
effect_t map_effect = {
|
||||||
|
.type = ZDWM_EFFECT_MAP_WINDOW,
|
||||||
|
.as.unmap.window = window->id,
|
||||||
|
};
|
||||||
|
plan_push_effect(plan, &map_effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const workspace_t *workspace = state_workspace_get(state, new_workspace);
|
||||||
|
if (!workspace) return;
|
||||||
|
|
||||||
|
effect_t focus_effect = {
|
||||||
|
.type = ZDWM_EFFECT_FOCUS_WINDOW,
|
||||||
|
.as.focus.window = workspace->focused_window_id
|
||||||
|
};
|
||||||
|
plan_push_effect(plan, &focus_effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_workspace(
|
||||||
state_t *state,
|
state_t *state,
|
||||||
const switch_workspace_command_t *command,
|
const switch_workspace_command_t *command,
|
||||||
plan_t *plan
|
plan_t *plan
|
||||||
) {
|
) {
|
||||||
auto output_id = command->output;
|
auto output_id = command->output;
|
||||||
auto workspace_id = command->workspace;
|
auto workspace_id = command->workspace;
|
||||||
|
workspace_id_t old_workspace = ZDWM_WORKSPACE_ID_INVALID;
|
||||||
|
|
||||||
if (state_output_set_current_workspace(state, output_id, workspace_id)) {
|
if (state_output_set_current_workspace(
|
||||||
plan->dirty_flags |= ZDWM_DIRTY_LAYOUT;
|
state,
|
||||||
|
output_id,
|
||||||
|
workspace_id,
|
||||||
|
&old_workspace
|
||||||
|
)) {
|
||||||
|
plan->need_relayout = true;
|
||||||
|
add_switch_workspace_effects(state, old_workspace, workspace_id, plan);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state_set_current_output(state, output_id)) {
|
state_set_current_output(state, output_id);
|
||||||
plan->dirty_flags |= ZDWM_DIRTY_OUTPUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: 后续考虑加上 ewmh 相关副作用 */
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool policy_apply_command(
|
void policy_apply_command(
|
||||||
const policy_context_t *ctx,
|
const policy_context_t *ctx,
|
||||||
const command_buffer_t *command_buffer,
|
const command_buffer_t *command_buffer,
|
||||||
plan_t *plan
|
plan_t *plan
|
||||||
) {
|
) {
|
||||||
bool has_effect = false;
|
auto state = ctx->state;
|
||||||
auto state = ctx->state;
|
|
||||||
for (size_t i = 0; i < command_buffer->count; ++i) {
|
for (size_t i = 0; i < command_buffer->count; ++i) {
|
||||||
auto cmd = &command_buffer->items[i];
|
auto cmd = &command_buffer->items[i];
|
||||||
switch (cmd->type) {
|
switch (cmd->type) {
|
||||||
case ZDWM_COMMAND_MANAGE_WINDOW:
|
case ZDWM_COMMAND_MANAGE_WINDOW:
|
||||||
if (manage_window(ctx, &cmd->as.manage_window, plan)) {
|
manage_window(ctx, &cmd->as.manage_window, plan);
|
||||||
has_effect = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ZDWM_COMMAND_SWITCH_WORKSPACE:
|
case ZDWM_COMMAND_SWITCH_WORKSPACE:
|
||||||
if (switch_workspace(state, &cmd->as.switch_workspace, plan)) {
|
switch_workspace(state, &cmd->as.switch_workspace, plan);
|
||||||
has_effect = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return has_effect;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,8 @@ typedef struct policy_context_t {
|
|||||||
* @param ctx 策略上下文
|
* @param ctx 策略上下文
|
||||||
* @param event 需要翻译的事件
|
* @param event 需要翻译的事件
|
||||||
* @param out 命令输出缓冲区,路由产生的命令追加到此处
|
* @param out 命令输出缓冲区,路由产生的命令追加到此处
|
||||||
*
|
|
||||||
* @return true 产生了至少一条需要执行的命令
|
|
||||||
* @return false 产生了至少一条需要执行的命令
|
|
||||||
*/
|
*/
|
||||||
bool policy_route_event(
|
void policy_route_event(
|
||||||
const policy_context_t *ctx,
|
const policy_context_t *ctx,
|
||||||
const event_t *event,
|
const event_t *event,
|
||||||
command_buffer_t *out
|
command_buffer_t *out
|
||||||
@@ -33,11 +30,8 @@ bool policy_route_event(
|
|||||||
* @param ctx 策略上下文
|
* @param ctx 策略上下文
|
||||||
* @param command_buffer 待应用的命令序列
|
* @param command_buffer 待应用的命令序列
|
||||||
* @param plan 副作用累积器,记录后端需要执行的操作
|
* @param plan 副作用累积器,记录后端需要执行的操作
|
||||||
*
|
|
||||||
* @return true 产生了至少一项后端副作用
|
|
||||||
* @return false 无副作用产生
|
|
||||||
*/
|
*/
|
||||||
bool policy_apply_command(
|
void policy_apply_command(
|
||||||
const policy_context_t *ctx,
|
const policy_context_t *ctx,
|
||||||
const command_buffer_t *command_buffer,
|
const command_buffer_t *command_buffer,
|
||||||
plan_t *plan
|
plan_t *plan
|
||||||
|
|||||||
@@ -265,7 +265,8 @@ void state_output_set_workarea(
|
|||||||
bool state_output_set_current_workspace(
|
bool state_output_set_current_workspace(
|
||||||
state_t *state,
|
state_t *state,
|
||||||
output_id_t output_id,
|
output_id_t output_id,
|
||||||
workspace_id_t workspace_id
|
workspace_id_t workspace_id,
|
||||||
|
workspace_id_t *old_workspace_id
|
||||||
) {
|
) {
|
||||||
output_t *output = (output_t *)state_output_get(state, output_id);
|
output_t *output = (output_t *)state_output_get(state, output_id);
|
||||||
if (!output) return false;
|
if (!output) return false;
|
||||||
@@ -274,6 +275,7 @@ bool state_output_set_current_workspace(
|
|||||||
|
|
||||||
if (output->current_workspace_id == workspace_id) return false;
|
if (output->current_workspace_id == workspace_id) return false;
|
||||||
|
|
||||||
|
if (old_workspace_id) *old_workspace_id = output->current_workspace_id;
|
||||||
output->current_workspace_id = workspace_id;
|
output->current_workspace_id = workspace_id;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,16 +123,19 @@ void state_output_set_workarea(
|
|||||||
/**
|
/**
|
||||||
* @brief 设置 output 的当前 workspace
|
* @brief 设置 output 的当前 workspace
|
||||||
*
|
*
|
||||||
* @param state 状态实例指针
|
* @param state 状态实例指针
|
||||||
* @param output_id 需要切换的当前 workspace 的 output 的 id
|
* @param output_id 需要切换的当前 workspace 的 output 的 id
|
||||||
* @param workspace_id 目标 workspace 的 id
|
* @param workspace_id 目标 workspace 的 id
|
||||||
|
* @param old_workspace_id 用于输出变更之前 output 显示的 workspace ,
|
||||||
|
* 如果不关心,可以传 nullptr
|
||||||
*
|
*
|
||||||
* @return 若 workspace 需要切换返回 true ,否则返回 false
|
* @return 若 workspace 需要切换返回 true ,否则返回 false
|
||||||
*/
|
*/
|
||||||
bool state_output_set_current_workspace(
|
bool state_output_set_current_workspace(
|
||||||
state_t *state,
|
state_t *state,
|
||||||
output_id_t output_id,
|
output_id_t output_id,
|
||||||
workspace_id_t workspace_id
|
workspace_id_t workspace_id,
|
||||||
|
workspace_id_t *old_workspace_id
|
||||||
);
|
);
|
||||||
size_t state_output_count(const state_t *state);
|
size_t state_output_count(const state_t *state);
|
||||||
bool state_output_valid(const state_t *state, output_id_t id);
|
bool state_output_valid(const state_t *state, output_id_t id);
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ void window_set_geometry_mode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void window_set_floating(window_t *window, bool floating) {
|
void window_set_floating(window_t *window, bool floating) {
|
||||||
|
if (!floating && (window->fixed_size || window->sticky)) return;
|
||||||
|
|
||||||
window->floating = floating;
|
window->floating = floating;
|
||||||
if (floating) window->float_rect = window->frame_rect;
|
if (floating) window->float_rect = window->frame_rect;
|
||||||
}
|
}
|
||||||
@@ -121,9 +123,7 @@ void window_take_metadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool window_need_layout(const window_t *window) {
|
bool window_need_layout(const window_t *window) {
|
||||||
if (window->sticky || window->floating) {
|
if (window->floating) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (window->geometry_mode) {
|
switch (window->geometry_mode) {
|
||||||
case ZDWM_GEOMETRY_FULLSCREEN:
|
case ZDWM_GEOMETRY_FULLSCREEN:
|
||||||
|
|||||||
Reference in New Issue
Block a user