Compare commits
16 Commits
e7a0945a93
...
arch_refac
| Author | SHA1 | Date | |
|---|---|---|---|
|
b8ca575458
|
|||
|
6b2f0e3218
|
|||
|
d7d16f1ac8
|
|||
|
88129293a0
|
|||
|
7b7b6d807f
|
|||
|
80b091a806
|
|||
|
89f11d1e24
|
|||
|
ceb40b434d
|
|||
|
272139f34f
|
|||
|
583b1fa382
|
|||
|
612c2367ca
|
|||
|
88e589cc9e
|
|||
|
c609d15d77
|
|||
|
d47ca9cf1a
|
|||
|
e39eb245b6
|
|||
|
3c5cfd3ead
|
1
.clangd
1
.clangd
@@ -2,3 +2,4 @@
|
|||||||
|
|
||||||
Completion:
|
Completion:
|
||||||
ArgumentLists: None
|
ArgumentLists: None
|
||||||
|
HeaderInsertion: Never
|
||||||
|
|||||||
9
Makefile
9
Makefile
@@ -1,16 +1,11 @@
|
|||||||
MAKEFILE_ABS_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
MAKEFILE_ABS_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||||
MAKEFILE_DIR := $(dir $(MAKEFILE_ABS_PATH))
|
MAKEFILE_DIR := $(dir $(MAKEFILE_ABS_PATH))
|
||||||
PWD_DIR := $(CURDIR)/
|
|
||||||
BUILD_DIR := $(addprefix $(MAKEFILE_DIR),build)
|
BUILD_DIR := $(addprefix $(MAKEFILE_DIR),build)
|
||||||
SRC_DIR := $(addprefix $(MAKEFILE_DIR),/)
|
SRC_DIR := $(addprefix $(MAKEFILE_DIR),/)
|
||||||
|
|
||||||
TARGET_NAME := zdwm
|
TARGET_NAME := zdwm
|
||||||
TARGET := $(addprefix $(MAKEFILE_DIR),$(TARGET_NAME))
|
TARGET := $(addprefix $(MAKEFILE_DIR),$(TARGET_NAME))
|
||||||
|
|
||||||
ifneq ($(PWD_DIR),$(MAKEFILE_DIR))
|
|
||||||
TARGET := $(addprefix $(MAKEFILE_DIR),$(TARGET_NAME))
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
$(TARGET_NAME): build
|
$(TARGET_NAME): build
|
||||||
|
|
||||||
@@ -19,10 +14,10 @@ clean:
|
|||||||
${RM} -r $(BUILD_DIR)
|
${RM} -r $(BUILD_DIR)
|
||||||
|
|
||||||
run:
|
run:
|
||||||
-$(shell Xephyr :3 -screen 1920x1080 -dpi `xrdb -get Xft.dpi` &)
|
Xephyr :3 -screen 1920x1080 -dpi `xrdb -get Xft.dpi`
|
||||||
|
|
||||||
run_multiple_screen:
|
run_multiple_screen:
|
||||||
-$(shell Xephyr :3 -screen 1920x1080 -screen 1920x1080 +xinerama -dpi `xrdb -get Xft.dpi` &)
|
Xephyr :3 -screen 1920x1080 -screen 1920x1080 +xinerama -dpi `xrdb -get Xft.dpi`
|
||||||
|
|
||||||
wm: $(TARGET_NAME)
|
wm: $(TARGET_NAME)
|
||||||
DISPLAY=:3 $(TARGET)
|
DISPLAY=:3 $(TARGET)
|
||||||
|
|||||||
@@ -195,6 +195,8 @@ backend_t *backend_create(const char *display_name) {
|
|||||||
void backend_destroy(backend_t *backend) {
|
void backend_destroy(backend_t *backend) {
|
||||||
if (!backend) return;
|
if (!backend) return;
|
||||||
|
|
||||||
|
tray_cleanup(backend);
|
||||||
|
|
||||||
p_delete(&backend->config_list.cfgs);
|
p_delete(&backend->config_list.cfgs);
|
||||||
p_clear(&backend->config_list, 1);
|
p_clear(&backend->config_list, 1);
|
||||||
|
|
||||||
@@ -556,6 +558,7 @@ static void backend_merge_effects(
|
|||||||
switch (e->type) {
|
switch (e->type) {
|
||||||
case ZDWM_EFFECT_MAP_WINDOW:
|
case ZDWM_EFFECT_MAP_WINDOW:
|
||||||
window_list_push(&backend->map, e->as.map.window);
|
window_list_push(&backend->map, e->as.map.window);
|
||||||
|
window_list_push(&backend->configure, e->as.map.window);
|
||||||
break;
|
break;
|
||||||
case ZDWM_EFFECT_UNMAP_WINDOW:
|
case ZDWM_EFFECT_UNMAP_WINDOW:
|
||||||
window_list_push(&backend->unmap, e->as.unmap.window);
|
window_list_push(&backend->unmap, e->as.unmap.window);
|
||||||
@@ -610,6 +613,9 @@ static void backend_merge_effects(
|
|||||||
case ZDWM_EFFECT_CONFIGURE_WINDOW:
|
case ZDWM_EFFECT_CONFIGURE_WINDOW:
|
||||||
merge_window_configure_params(backend, &e->as.configure);
|
merge_window_configure_params(backend, &e->as.configure);
|
||||||
break;
|
break;
|
||||||
|
case ZDWM_EFFECT_CONFIGURE_NOTIFY:
|
||||||
|
window_list_push(&backend->configure, e->as.configure_notify.window);
|
||||||
|
break;
|
||||||
case ZDWM_EFFECT_CHANGE_BORDER_COLOR: {
|
case ZDWM_EFFECT_CHANGE_BORDER_COLOR: {
|
||||||
xcb_change_window_attributes_value_list_t value = {
|
xcb_change_window_attributes_value_list_t value = {
|
||||||
.border_pixel = e->as.change_border_color.color->argb
|
.border_pixel = e->as.change_border_color.color->argb
|
||||||
@@ -641,6 +647,46 @@ static void backend_merge_effects(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void batch_send_configure_notify(
|
||||||
|
xcb_connection_t *conn,
|
||||||
|
xcb_window_t *windows,
|
||||||
|
size_t count
|
||||||
|
) {
|
||||||
|
if (count == 0) return;
|
||||||
|
|
||||||
|
auto cookie_list = p_new(xcb_get_geometry_cookie_t, count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
auto window = windows[i];
|
||||||
|
cookie_list[i] = xcb_get_geometry(conn, window);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t event_mask = XCB_EVENT_MASK_STRUCTURE_NOTIFY;
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
auto window = windows[i];
|
||||||
|
auto cookie = cookie_list[i];
|
||||||
|
auto reply = xcb_get_geometry_reply(conn, cookie, nullptr);
|
||||||
|
if (!reply) continue;
|
||||||
|
|
||||||
|
xcb_configure_notify_event_t ev = {
|
||||||
|
.response_type = XCB_CONFIGURE_NOTIFY,
|
||||||
|
.event = window,
|
||||||
|
.window = window,
|
||||||
|
.above_sibling = XCB_WINDOW_NONE,
|
||||||
|
.x = reply->x,
|
||||||
|
.y = reply->y,
|
||||||
|
.width = reply->width,
|
||||||
|
.height = reply->height,
|
||||||
|
.border_width = reply->border_width,
|
||||||
|
.override_redirect = false,
|
||||||
|
};
|
||||||
|
xcb_send_event(conn, false, window, event_mask, (char *)&ev);
|
||||||
|
p_delete(&reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
p_delete(&cookie_list);
|
||||||
|
}
|
||||||
|
|
||||||
static void backend_batch_apply_effects(backend_t *backend) {
|
static void backend_batch_apply_effects(backend_t *backend) {
|
||||||
xcb_connection_t *conn = backend->conn;
|
xcb_connection_t *conn = backend->conn;
|
||||||
if (backend->unmap.count) {
|
if (backend->unmap.count) {
|
||||||
@@ -670,6 +716,12 @@ static void backend_batch_apply_effects(backend_t *backend) {
|
|||||||
|
|
||||||
backend_apply_window_configure_list(backend);
|
backend_apply_window_configure_list(backend);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto windows = backend->configure.windows;
|
||||||
|
auto count = backend->configure.count;
|
||||||
|
batch_send_configure_notify(conn, windows, count);
|
||||||
|
}
|
||||||
|
|
||||||
if (backend->update_focus) {
|
if (backend->update_focus) {
|
||||||
backend_focus_window(backend, backend->focus_window);
|
backend_focus_window(backend, backend->focus_window);
|
||||||
}
|
}
|
||||||
@@ -685,6 +737,7 @@ bool backend_apply_effect(
|
|||||||
window_list_reset(&backend->unmap);
|
window_list_reset(&backend->unmap);
|
||||||
window_list_reset(&backend->map);
|
window_list_reset(&backend->map);
|
||||||
window_list_reset(&backend->kill);
|
window_list_reset(&backend->kill);
|
||||||
|
window_list_reset(&backend->configure);
|
||||||
|
|
||||||
backend_merge_effects(backend, effects, effect_count);
|
backend_merge_effects(backend, effects, effect_count);
|
||||||
backend_batch_apply_effects(backend);
|
backend_batch_apply_effects(backend);
|
||||||
@@ -846,7 +899,15 @@ backend_bar_window_t backend_create_bar_window(
|
|||||||
fatal("cannot create cairo context: %s", cairo_status_to_string(statue));
|
fatal("cannot create cairo context: %s", cairo_status_to_string(statue));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enable_tray) tray_init(backend, window_id, width, height);
|
if (enable_tray) {
|
||||||
|
tray_host_window_t host_window = {
|
||||||
|
.window = window_id,
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
.bg_pixel = bg_pixel,
|
||||||
|
};
|
||||||
|
tray_init(backend, host_window);
|
||||||
|
}
|
||||||
|
|
||||||
return (backend_bar_window_t){
|
return (backend_bar_window_t){
|
||||||
.window_id = window_id,
|
.window_id = window_id,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <xcb/xproto.h>
|
#include <xcb/xproto.h>
|
||||||
|
|
||||||
#include "backend/x11/common.h"
|
#include "backend/x11/common.h"
|
||||||
|
#include "backend/x11/tray.h"
|
||||||
#include "backend/x11/window.h"
|
#include "backend/x11/window.h"
|
||||||
#include "base/memory.h"
|
#include "base/memory.h"
|
||||||
#include "interface/backend.h"
|
#include "interface/backend.h"
|
||||||
@@ -189,6 +190,8 @@ static bool handle_map_request(
|
|||||||
event_t *event,
|
event_t *event,
|
||||||
const xcb_map_request_event_t *xcb_event
|
const xcb_map_request_event_t *xcb_event
|
||||||
) {
|
) {
|
||||||
|
if (tray_handle_map_request(backend, xcb_event)) return false;
|
||||||
|
|
||||||
event->type = ZDWM_EVENT_WINDOW_MAP_REQUEST;
|
event->type = ZDWM_EVENT_WINDOW_MAP_REQUEST;
|
||||||
return populate_window_event(
|
return populate_window_event(
|
||||||
backend,
|
backend,
|
||||||
@@ -202,6 +205,8 @@ static bool handle_unmap_notify(
|
|||||||
event_t *event,
|
event_t *event,
|
||||||
const xcb_unmap_notify_event_t *xcb_event
|
const xcb_unmap_notify_event_t *xcb_event
|
||||||
) {
|
) {
|
||||||
|
if (tray_handle_unmap_notify(backend, xcb_event)) return false;
|
||||||
|
|
||||||
event->type = ZDWM_EVENT_WINDOW_REMOVE;
|
event->type = ZDWM_EVENT_WINDOW_REMOVE;
|
||||||
event->as.window_remove.window = xcb_event->window;
|
event->as.window_remove.window = xcb_event->window;
|
||||||
if (XCB_EVENT_SENT(xcb_event)) {
|
if (XCB_EVENT_SENT(xcb_event)) {
|
||||||
@@ -218,6 +223,8 @@ static bool handle_destroy_notify(
|
|||||||
event_t *event,
|
event_t *event,
|
||||||
const xcb_destroy_notify_event_t *xcb_event
|
const xcb_destroy_notify_event_t *xcb_event
|
||||||
) {
|
) {
|
||||||
|
if (tray_handle_destroy_notify(backend, xcb_event)) return false;
|
||||||
|
|
||||||
event->type = ZDWM_EVENT_WINDOW_REMOVE;
|
event->type = ZDWM_EVENT_WINDOW_REMOVE;
|
||||||
event->as.window_remove.window = xcb_event->window;
|
event->as.window_remove.window = xcb_event->window;
|
||||||
event->as.window_remove.reason = ZDWM_WINDOW_REMOVE_DESTROY;
|
event->as.window_remove.reason = ZDWM_WINDOW_REMOVE_DESTROY;
|
||||||
@@ -230,6 +237,8 @@ static bool handle_configure_request(
|
|||||||
event_t *event,
|
event_t *event,
|
||||||
const xcb_configure_request_event_t *xcb_event
|
const xcb_configure_request_event_t *xcb_event
|
||||||
) {
|
) {
|
||||||
|
if (tray_handle_configure_request(backend, xcb_event)) return false;
|
||||||
|
|
||||||
event->type = ZDWM_EVENT_CONFIGURE_REQUEST;
|
event->type = ZDWM_EVENT_CONFIGURE_REQUEST;
|
||||||
auto data = &event->as.configure_request;
|
auto data = &event->as.configure_request;
|
||||||
data->window = xcb_event->window;
|
data->window = xcb_event->window;
|
||||||
@@ -341,6 +350,8 @@ static bool handle_property_notify(
|
|||||||
event_t *event,
|
event_t *event,
|
||||||
const xcb_property_notify_event_t *xcb_event
|
const xcb_property_notify_event_t *xcb_event
|
||||||
) {
|
) {
|
||||||
|
if (tray_handle_property_notify(backend, xcb_event)) return false;
|
||||||
|
|
||||||
auto window_id = xcb_event->window;
|
auto window_id = xcb_event->window;
|
||||||
if (
|
if (
|
||||||
xcb_event->atom == backend->atoms.WM_NAME ||
|
xcb_event->atom == backend->atoms.WM_NAME ||
|
||||||
@@ -419,6 +430,8 @@ static bool handle_client_message(
|
|||||||
event_t *event,
|
event_t *event,
|
||||||
const xcb_client_message_event_t *xcb_event
|
const xcb_client_message_event_t *xcb_event
|
||||||
) {
|
) {
|
||||||
|
if (tray_handle_client_message(backend, xcb_event)) return false;
|
||||||
|
|
||||||
auto atoms = &backend->atoms;
|
auto atoms = &backend->atoms;
|
||||||
|
|
||||||
if (xcb_event->type == atoms->_NET_ACTIVE_WINDOW) {
|
if (xcb_event->type == atoms->_NET_ACTIVE_WINDOW) {
|
||||||
|
|||||||
@@ -47,6 +47,8 @@
|
|||||||
|
|
||||||
#define ATOM_LIST(X) \
|
#define ATOM_LIST(X) \
|
||||||
X(MANAGER) \
|
X(MANAGER) \
|
||||||
|
X(_NET_SYSTEM_TRAY_OPCODE) \
|
||||||
|
X(_XEMBED) \
|
||||||
\
|
\
|
||||||
X(COMPOUND_TEXT) \
|
X(COMPOUND_TEXT) \
|
||||||
X(UTF8_STRING) \
|
X(UTF8_STRING) \
|
||||||
@@ -113,6 +115,7 @@ typedef struct backend_t {
|
|||||||
window_list_t unmap;
|
window_list_t unmap;
|
||||||
window_list_t map;
|
window_list_t map;
|
||||||
window_list_t kill;
|
window_list_t kill;
|
||||||
|
window_list_t configure;
|
||||||
|
|
||||||
tray_host_t *tray;
|
tray_host_t *tray;
|
||||||
} backend_t;
|
} backend_t;
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
#include "backend/x11/tray.h"
|
#include "backend/x11/tray.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
#include <xcb/xcb_aux.h>
|
||||||
#include <xcb/xproto.h>
|
#include <xcb/xproto.h>
|
||||||
#include <zdwm/types.h>
|
#include <zdwm/types.h>
|
||||||
|
|
||||||
#include "backend/x11/window.h"
|
#include "backend/x11/window.h"
|
||||||
|
#include "base/array.h"
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "base/memory.h"
|
#include "base/memory.h"
|
||||||
@@ -15,6 +18,24 @@
|
|||||||
#include "interface/types.h"
|
#include "interface/types.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
typedef enum tray_opcode_t {
|
||||||
|
SYSTEM_TRAY_REQUEST_DOCK = 0,
|
||||||
|
SYSTEM_TRAY_BEGIN_MESSAGE = 1,
|
||||||
|
SYSTEM_TRAY_CANCEL_MESSAGE = 2,
|
||||||
|
} tray_opcode_t;
|
||||||
|
|
||||||
|
typedef enum xembed_message_t {
|
||||||
|
XEMBED_EMBEDDED_NOTIFY = 0,
|
||||||
|
} xembed_message_t;
|
||||||
|
|
||||||
|
static constexpr auto XEMBED_VERSION = 0;
|
||||||
|
|
||||||
|
typedef struct tray_icon_t {
|
||||||
|
xcb_window_t window;
|
||||||
|
int32_t natural_width;
|
||||||
|
int32_t natural_height;
|
||||||
|
} tray_icon_t;
|
||||||
|
|
||||||
typedef struct tray_host_t {
|
typedef struct tray_host_t {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
bool initialized;
|
bool initialized;
|
||||||
@@ -22,7 +43,11 @@ typedef struct tray_host_t {
|
|||||||
xcb_window_t host_window;
|
xcb_window_t host_window;
|
||||||
xcb_window_t container;
|
xcb_window_t container;
|
||||||
int32_t icon_size;
|
int32_t icon_size;
|
||||||
|
|
||||||
|
tray_icon_t *icons;
|
||||||
size_t icon_count;
|
size_t icon_count;
|
||||||
|
size_t icon_capacity;
|
||||||
|
|
||||||
tray_icons_change_cb_t icon_change_cb;
|
tray_icons_change_cb_t icon_change_cb;
|
||||||
void *cb_user_data;
|
void *cb_user_data;
|
||||||
} tray_host_t;
|
} tray_host_t;
|
||||||
@@ -37,6 +62,118 @@ static tray_host_t *get_tray_host(void *handle) {
|
|||||||
return tray;
|
return tray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t tray_find_icon(tray_host_t *tray, xcb_window_t window) {
|
||||||
|
for (size_t i = 0; i < tray->icon_count; ++i) {
|
||||||
|
if (tray->icons[i].window == window) return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SIZE_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static tray_icon_t *tray_get_icon(tray_host_t *tray, xcb_window_t window) {
|
||||||
|
for (size_t i = 0; i < tray->icon_count; ++i) {
|
||||||
|
auto icon = &tray->icons[i];
|
||||||
|
if (icon->window == window) return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void tray_dispatch_callback(tray_host_t *tray) {
|
||||||
|
assert(tray);
|
||||||
|
if (tray->icon_change_cb) tray->icon_change_cb(tray->cb_user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tray_release_icon_window(backend_t *backend, tray_icon_t *icon) {
|
||||||
|
if (!icon || icon->window == XCB_WINDOW_NONE) return;
|
||||||
|
|
||||||
|
auto tray = get_tray_host(backend);
|
||||||
|
if (!tray || !tray->initialized) return;
|
||||||
|
|
||||||
|
auto conn = backend->conn;
|
||||||
|
auto root = backend->screen->root;
|
||||||
|
auto window = icon->window;
|
||||||
|
auto mask = XCB_CW_EVENT_MASK;
|
||||||
|
xcb_params_cw_t params = {.event_mask = XCB_EVENT_MASK_NO_EVENT};
|
||||||
|
xcb_change_save_set(conn, XCB_SET_MODE_DELETE, window);
|
||||||
|
xcb_aux_change_window_attributes(conn, window, mask, ¶ms);
|
||||||
|
xcb_reparent_window(conn, window, root, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tray_remove_icon_by_index(
|
||||||
|
backend_t *backend,
|
||||||
|
size_t index,
|
||||||
|
bool release_window
|
||||||
|
) {
|
||||||
|
auto tray = backend->tray;
|
||||||
|
if (index >= tray->icon_count) return;
|
||||||
|
|
||||||
|
auto icon = &tray->icons[index];
|
||||||
|
if (release_window) tray_release_icon_window(backend, icon);
|
||||||
|
|
||||||
|
array_erase(tray->icons, tray->icon_count, index);
|
||||||
|
tray_dispatch_callback(tray);
|
||||||
|
}
|
||||||
|
|
||||||
|
static zdwm_size_t tray_get_icon_size(tray_host_t *tray, size_t index) {
|
||||||
|
auto target_size = MAX(tray->icon_size, (int32_t)1);
|
||||||
|
auto natural_width = tray->icons[index].natural_width;
|
||||||
|
auto natural_height = tray->icons[index].natural_height;
|
||||||
|
|
||||||
|
if (natural_width == 0) natural_width = target_size;
|
||||||
|
if (natural_height == 0) natural_height = target_size;
|
||||||
|
|
||||||
|
double width_scale = (double)target_size / (double)natural_width;
|
||||||
|
double height_scale = (double)target_size / (double)natural_height;
|
||||||
|
auto scale = MIN(width_scale, height_scale);
|
||||||
|
zdwm_size_t size = {
|
||||||
|
.width = (int32_t)(natural_width * scale),
|
||||||
|
.height = (int32_t)(natural_height * scale),
|
||||||
|
};
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tray_layout_icons(backend_t *backend, int32_t start_x) {
|
||||||
|
auto tray = get_tray_host(backend);
|
||||||
|
if (!tray || !tray->initialized) return;
|
||||||
|
if (tray->container == XCB_WINDOW_NONE) return;
|
||||||
|
|
||||||
|
auto conn = backend->conn;
|
||||||
|
if (tray->icon_count == 0) {
|
||||||
|
xcb_unmap_window(conn, tray->container);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto height = tray->icon_size;
|
||||||
|
auto width = height * (int32_t)tray->icon_count;
|
||||||
|
xcb_configure_window_value_list_t value_list = {
|
||||||
|
.x = start_x,
|
||||||
|
.y = 0,
|
||||||
|
.width = (uint32_t)width,
|
||||||
|
.height = (uint32_t)height,
|
||||||
|
};
|
||||||
|
uint16_t value_mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
|
||||||
|
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
|
||||||
|
xcb_configure_window_aux(conn, tray->container, value_mask, &value_list);
|
||||||
|
xcb_map_window(conn, tray->container);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < tray->icon_count; ++i) {
|
||||||
|
auto window = tray->icons[i].window;
|
||||||
|
auto icon_size = tray_get_icon_size(tray, i);
|
||||||
|
value_mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
|
||||||
|
auto offset_x = height * (int32_t)i;
|
||||||
|
value_list = (xcb_configure_window_value_list_t){
|
||||||
|
.x = offset_x + (icon_size.width - height) / 2,
|
||||||
|
.y = (icon_size.height - height) / 2,
|
||||||
|
.width = icon_size.width,
|
||||||
|
.height = icon_size.height,
|
||||||
|
.border_width = 0,
|
||||||
|
};
|
||||||
|
xcb_configure_window_aux(conn, window, value_mask, &value_list);
|
||||||
|
xcb_map_window(conn, window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static window_id_t tray_host_window(void *handle) {
|
static window_id_t tray_host_window(void *handle) {
|
||||||
auto tray = get_tray_host(handle);
|
auto tray = get_tray_host(handle);
|
||||||
if (!tray) return ZDWM_WINDOW_ID_INVALID;
|
if (!tray) return ZDWM_WINDOW_ID_INVALID;
|
||||||
@@ -60,10 +197,7 @@ static void tray_place(void *handle, int32_t x) {
|
|||||||
auto tray = get_tray_host(handle);
|
auto tray = get_tray_host(handle);
|
||||||
if (!tray) return;
|
if (!tray) return;
|
||||||
|
|
||||||
auto conn = ((backend_t *)handle)->conn;
|
tray_layout_icons((backend_t *)handle, x);
|
||||||
uint16_t value_mask = XCB_CONFIG_WINDOW_X;
|
|
||||||
xcb_configure_window_value_list_t value_list = {.x = x};
|
|
||||||
xcb_configure_window_aux(conn, tray->container, value_mask, &value_list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -104,12 +238,6 @@ static bool tray_intern_selection_atom(tray_host_t *tray, backend_t *backend) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct tray_host_window_t {
|
|
||||||
xcb_window_t window;
|
|
||||||
int32_t width;
|
|
||||||
int32_t height;
|
|
||||||
} tray_host_window_t;
|
|
||||||
|
|
||||||
static bool tray_create_container_window(
|
static bool tray_create_container_window(
|
||||||
tray_host_t *tray,
|
tray_host_t *tray,
|
||||||
backend_t *backend,
|
backend_t *backend,
|
||||||
@@ -117,15 +245,31 @@ static bool tray_create_container_window(
|
|||||||
) {
|
) {
|
||||||
auto conn = backend->conn;
|
auto conn = backend->conn;
|
||||||
auto window_id = xcb_generate_id(conn);
|
auto window_id = xcb_generate_id(conn);
|
||||||
|
auto depth = backend->screen->root_depth;
|
||||||
|
auto visual_id = backend->screen->root_visual;
|
||||||
|
|
||||||
|
static xcb_colormap_t colormap = XCB_NONE;
|
||||||
|
if (colormap == XCB_NONE) {
|
||||||
|
colormap = xcb_generate_id(conn);
|
||||||
|
auto root = backend->screen->root;
|
||||||
|
uint8_t alloc = XCB_COLORMAP_ALLOC_NONE;
|
||||||
|
xcb_create_colormap(conn, alloc, colormap, root, visual_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t value_mask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL |
|
||||||
|
XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK |
|
||||||
|
XCB_CW_COLORMAP;
|
||||||
xcb_create_window_value_list_t value_list = {
|
xcb_create_window_value_list_t value_list = {
|
||||||
|
.background_pixel = host_window.bg_pixel,
|
||||||
|
.border_pixel = 0,
|
||||||
.override_redirect = true,
|
.override_redirect = true,
|
||||||
.event_mask =
|
.event_mask =
|
||||||
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_STRUCTURE_NOTIFY
|
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_STRUCTURE_NOTIFY,
|
||||||
|
.colormap = colormap,
|
||||||
};
|
};
|
||||||
auto cookie = xcb_create_window_aux_checked(
|
auto cookie = xcb_create_window_aux_checked(
|
||||||
conn,
|
conn,
|
||||||
XCB_COPY_FROM_PARENT,
|
depth,
|
||||||
window_id,
|
window_id,
|
||||||
host_window.window,
|
host_window.window,
|
||||||
(int16_t)host_window.width,
|
(int16_t)host_window.width,
|
||||||
@@ -134,8 +278,8 @@ static bool tray_create_container_window(
|
|||||||
(uint16_t)MAX(1, host_window.height),
|
(uint16_t)MAX(1, host_window.height),
|
||||||
0,
|
0,
|
||||||
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||||
XCB_COPY_FROM_PARENT,
|
visual_id,
|
||||||
XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK,
|
value_mask,
|
||||||
&value_list
|
&value_list
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -210,12 +354,7 @@ static void tray_broadcast_manager(tray_host_t *tray, backend_t *backend) {
|
|||||||
xcb_send_event(conn, false, root, event_mask, (char *)&event);
|
xcb_send_event(conn, false, root, event_mask, (char *)&event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_init(
|
void tray_init(backend_t *backend, tray_host_window_t host_window) {
|
||||||
backend_t *backend,
|
|
||||||
xcb_window_t host_window,
|
|
||||||
int32_t host_width,
|
|
||||||
int32_t host_height
|
|
||||||
) {
|
|
||||||
auto tray = get_tray_host(backend);
|
auto tray = get_tray_host(backend);
|
||||||
if (!tray) {
|
if (!tray) {
|
||||||
tray = p_new(tray_host_t, 1);
|
tray = p_new(tray_host_t, 1);
|
||||||
@@ -226,20 +365,242 @@ void tray_init(
|
|||||||
|
|
||||||
if (!tray_intern_selection_atom(tray, backend)) return;
|
if (!tray_intern_selection_atom(tray, backend)) return;
|
||||||
|
|
||||||
tray_host_window_t host_window_params = {
|
if (!tray_create_container_window(tray, backend, host_window)) return;
|
||||||
.window = host_window,
|
|
||||||
.width = host_width,
|
|
||||||
.height = host_height
|
|
||||||
};
|
|
||||||
if (!tray_create_container_window(tray, backend, host_window_params)) return;
|
|
||||||
if (!tray_take_selection_owner(tray, backend)) {
|
if (!tray_take_selection_owner(tray, backend)) {
|
||||||
/* TODO: cleanup tray */
|
tray_cleanup(backend);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tray->enabled = true;
|
tray->enabled = true;
|
||||||
tray->initialized = true;
|
tray->initialized = true;
|
||||||
|
tray->host_window = host_window.window;
|
||||||
|
tray->icon_size = host_window.height;
|
||||||
|
|
||||||
tray_broadcast_manager(tray, backend);
|
tray_broadcast_manager(tray, backend);
|
||||||
|
tray_layout_icons(backend, host_window.width);
|
||||||
xcb_flush(backend->conn);
|
xcb_flush(backend->conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tray_cleanup(backend_t *backend) {
|
||||||
|
auto tray = backend->tray;
|
||||||
|
if (!tray) return;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < tray->icon_count; ++i) {
|
||||||
|
tray_release_icon_window(backend, &tray->icons[i]);
|
||||||
|
}
|
||||||
|
p_delete(&tray->icons);
|
||||||
|
tray->icon_count = 0;
|
||||||
|
tray->icon_capacity = 0;
|
||||||
|
|
||||||
|
auto conn = backend->conn;
|
||||||
|
|
||||||
|
auto atom = tray->selection_atom;
|
||||||
|
if (atom != XCB_ATOM_NONE) {
|
||||||
|
xcb_set_selection_owner(conn, XCB_WINDOW_NONE, atom, XCB_CURRENT_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tray->container != XCB_WINDOW_NONE) {
|
||||||
|
xcb_destroy_window(conn, tray->container);
|
||||||
|
}
|
||||||
|
|
||||||
|
p_clear(backend->tray, 1);
|
||||||
|
p_delete(&backend->tray);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tray_select_icon_events(xcb_connection_t *conn, xcb_window_t window) {
|
||||||
|
xcb_params_cw_t params = {
|
||||||
|
.event_mask =
|
||||||
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE,
|
||||||
|
};
|
||||||
|
uint32_t mask = XCB_CW_EVENT_MASK;
|
||||||
|
xcb_aux_change_window_attributes(conn, window, mask, ¶ms);
|
||||||
|
xcb_clear_area(conn, false, window, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reference:
|
||||||
|
* https://specifications.freedesktop.org/xembed/latest-single/#id-1.7.4 */
|
||||||
|
typedef struct xembed_message_data_t {
|
||||||
|
uint32_t message; /* message opcode */
|
||||||
|
uint32_t detail; /* message detail */
|
||||||
|
uint32_t data1; /* message data 1 */
|
||||||
|
uint32_t data2; /* message data 2 */
|
||||||
|
} xembed_message_data_t;
|
||||||
|
|
||||||
|
static void tray_send_xembed_message(
|
||||||
|
backend_t *backend,
|
||||||
|
xcb_window_t window,
|
||||||
|
xembed_message_data_t message
|
||||||
|
) {
|
||||||
|
auto conn = backend->conn;
|
||||||
|
auto message_type = backend->atoms._XEMBED;
|
||||||
|
|
||||||
|
xcb_client_message_event_t event = {
|
||||||
|
.response_type = XCB_CLIENT_MESSAGE,
|
||||||
|
.format = 32,
|
||||||
|
.window = window,
|
||||||
|
.type = message_type,
|
||||||
|
.data.data32 = {
|
||||||
|
[0] = XCB_CURRENT_TIME,
|
||||||
|
[1] = message.message,
|
||||||
|
[2] = message.detail,
|
||||||
|
[3] = message.data1,
|
||||||
|
[4] = message.data2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
uint32_t event_mask = XCB_EVENT_MASK_NO_EVENT;
|
||||||
|
xcb_send_event(conn, false, window, event_mask, (char *)&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tray_add_icon(backend_t *backend, xcb_window_t window) {
|
||||||
|
if (window == XCB_WINDOW_NONE) return;
|
||||||
|
|
||||||
|
auto tray = get_tray_host(backend);
|
||||||
|
if (!tray || !tray->initialized || tray_get_icon(tray, window)) return;
|
||||||
|
|
||||||
|
rect_t geometry = {0};
|
||||||
|
if (!window_get_geometry(backend, window, &geometry)) return;
|
||||||
|
|
||||||
|
auto icon = array_push(tray->icons, tray->icon_count, tray->icon_capacity);
|
||||||
|
*icon = (tray_icon_t){
|
||||||
|
.window = window,
|
||||||
|
.natural_width = geometry.width,
|
||||||
|
.natural_height = geometry.height,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto conn = backend->conn;
|
||||||
|
auto container = tray->container;
|
||||||
|
xembed_message_data_t message = {
|
||||||
|
.message = XEMBED_EMBEDDED_NOTIFY,
|
||||||
|
.detail = 0,
|
||||||
|
.data1 = container,
|
||||||
|
.data2 = XEMBED_VERSION,
|
||||||
|
};
|
||||||
|
xcb_change_save_set(conn, XCB_SET_MODE_INSERT, window);
|
||||||
|
xcb_reparent_window(conn, window, tray->container, 0, 0);
|
||||||
|
tray_select_icon_events(conn, window);
|
||||||
|
tray_send_xembed_message(backend, window, message);
|
||||||
|
xcb_map_window(conn, window);
|
||||||
|
tray_dispatch_callback(tray);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tray_handle_client_message(
|
||||||
|
backend_t *backend,
|
||||||
|
const xcb_client_message_event_t *ev
|
||||||
|
) {
|
||||||
|
auto tray = get_tray_host(backend);
|
||||||
|
if (!tray || !tray->enabled || !tray->initialized) return false;
|
||||||
|
if (ev->window != tray->container && ev->window != backend->screen->root) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto opcode = ev->data.data32[1];
|
||||||
|
switch (opcode) {
|
||||||
|
case SYSTEM_TRAY_REQUEST_DOCK:
|
||||||
|
auto window = ev->data.data32[2];
|
||||||
|
tray_add_icon(backend, window);
|
||||||
|
break;
|
||||||
|
case SYSTEM_TRAY_BEGIN_MESSAGE:
|
||||||
|
case SYSTEM_TRAY_CANCEL_MESSAGE:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_flush(backend->conn);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tray_handle_configure_request(
|
||||||
|
backend_t *backend,
|
||||||
|
const xcb_configure_request_event_t *ev
|
||||||
|
) {
|
||||||
|
auto tray = get_tray_host(backend);
|
||||||
|
if (!tray || !tray->initialized) return false;
|
||||||
|
|
||||||
|
if (ev->window == tray->container) {
|
||||||
|
tray_dispatch_callback(tray);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto icon = tray_get_icon(tray, ev->window);
|
||||||
|
if (!icon) return false;
|
||||||
|
|
||||||
|
if ((ev->value_mask & XCB_CONFIG_WINDOW_WIDTH) && ev->width > 0) {
|
||||||
|
icon->natural_width = (int32_t)ev->width;
|
||||||
|
}
|
||||||
|
if ((ev->value_mask & XCB_CONFIG_WINDOW_HEIGHT) && ev->height > 0) {
|
||||||
|
icon->natural_height = (int32_t)ev->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
tray_dispatch_callback(tray);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tray_handle_map_request(
|
||||||
|
backend_t *backend,
|
||||||
|
const xcb_map_request_event_t *ev
|
||||||
|
) {
|
||||||
|
auto tray = get_tray_host(backend);
|
||||||
|
if (!tray || !tray->initialized) return false;
|
||||||
|
|
||||||
|
auto conn = backend->conn;
|
||||||
|
if (ev->window == tray->container) {
|
||||||
|
tray_dispatch_callback(tray);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto icon = tray_get_icon(tray, ev->window);
|
||||||
|
if (!icon && ev->parent != tray->container) return false;
|
||||||
|
|
||||||
|
xcb_map_window(conn, ev->window);
|
||||||
|
xcb_flush(conn);
|
||||||
|
|
||||||
|
tray_dispatch_callback(tray);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tray_handle_property_notify(
|
||||||
|
backend_t *backend,
|
||||||
|
const xcb_property_notify_event_t *ev
|
||||||
|
) {
|
||||||
|
auto tray = get_tray_host(backend);
|
||||||
|
if (!tray || !tray->initialized) return false;
|
||||||
|
|
||||||
|
if (ev->window == XCB_WINDOW_NONE) return false;
|
||||||
|
if (ev->window == tray->container) return true;
|
||||||
|
return tray_get_icon(tray, ev->window) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tray_handle_unmap_notify(
|
||||||
|
backend_t *backend,
|
||||||
|
const xcb_unmap_notify_event_t *ev
|
||||||
|
) {
|
||||||
|
auto tray = get_tray_host(backend);
|
||||||
|
if (!tray || !tray->initialized) return false;
|
||||||
|
|
||||||
|
auto index = tray_find_icon(tray, ev->window);
|
||||||
|
if (index == SIZE_MAX) return ev->window == tray->container;
|
||||||
|
|
||||||
|
tray_remove_icon_by_index(backend, index, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tray_handle_destroy_notify(
|
||||||
|
backend_t *backend,
|
||||||
|
const xcb_destroy_notify_event_t *ev
|
||||||
|
) {
|
||||||
|
auto tray = get_tray_host(backend);
|
||||||
|
if (!tray || !tray->initialized) return false;
|
||||||
|
|
||||||
|
if (ev->window == tray->container) {
|
||||||
|
tray_cleanup(backend);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto index = tray_find_icon(tray, ev->window);
|
||||||
|
if (index == SIZE_MAX) return false;
|
||||||
|
|
||||||
|
tray_remove_icon_by_index(backend, index, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,9 +9,37 @@ extern const tray_api_t tray_api;
|
|||||||
|
|
||||||
typedef struct backend_t backend_t;
|
typedef struct backend_t backend_t;
|
||||||
|
|
||||||
void tray_init(
|
typedef struct tray_host_window_t {
|
||||||
|
xcb_window_t window;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
uint32_t bg_pixel;
|
||||||
|
} tray_host_window_t;
|
||||||
|
|
||||||
|
void tray_init(backend_t *backend, tray_host_window_t host_window);
|
||||||
|
void tray_cleanup(backend_t *backend);
|
||||||
|
|
||||||
|
bool tray_handle_client_message(
|
||||||
backend_t *backend,
|
backend_t *backend,
|
||||||
xcb_window_t host_window,
|
const xcb_client_message_event_t *ev
|
||||||
int32_t host_width,
|
);
|
||||||
int32_t host_height
|
bool tray_handle_configure_request(
|
||||||
|
backend_t *backend,
|
||||||
|
const xcb_configure_request_event_t *ev
|
||||||
|
);
|
||||||
|
bool tray_handle_map_request(
|
||||||
|
backend_t *backend,
|
||||||
|
const xcb_map_request_event_t *ev
|
||||||
|
);
|
||||||
|
bool tray_handle_property_notify(
|
||||||
|
backend_t *backend,
|
||||||
|
const xcb_property_notify_event_t *ev
|
||||||
|
);
|
||||||
|
bool tray_handle_unmap_notify(
|
||||||
|
backend_t *backend,
|
||||||
|
const xcb_unmap_notify_event_t *ev
|
||||||
|
);
|
||||||
|
bool tray_handle_destroy_notify(
|
||||||
|
backend_t *backend,
|
||||||
|
const xcb_destroy_notify_event_t *ev
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ bool config_defaults_build(
|
|||||||
RAISE_OR_RUN(default_mode, Super("e"), editor);
|
RAISE_OR_RUN(default_mode, Super("e"), editor);
|
||||||
RAISE_OR_RUN(default_mode, Super("q"), browser);
|
RAISE_OR_RUN(default_mode, Super("q"), browser);
|
||||||
RAISE_OR_RUN(default_mode, Super("a"), chrome);
|
RAISE_OR_RUN(default_mode, Super("a"), chrome);
|
||||||
BIND_DEFAULT(Super("f"), {.type = ZDWM_ACTION_WINDOW_TOGGLE_FLOATING});
|
BIND_DEFAULT(Super("f"), {.type = ZDWM_ACTION_WINDOW_TOGGLE_FULLSCREEN});
|
||||||
BIND_DEFAULT(Super("m"), {.type = ZDWM_ACTION_WINDOW_TOGGLE_MAXIMIZE});
|
BIND_DEFAULT(Super("m"), {.type = ZDWM_ACTION_WINDOW_TOGGLE_MAXIMIZE});
|
||||||
BIND_DEFAULT(
|
BIND_DEFAULT(
|
||||||
Super("Control+space"),
|
Super("Control+space"),
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ typedef enum command_type_t {
|
|||||||
ZDWM_COMMAND_RAISE_WINDOW,
|
ZDWM_COMMAND_RAISE_WINDOW,
|
||||||
ZDWM_COMMAND_WITHDRAW_WINDOW,
|
ZDWM_COMMAND_WITHDRAW_WINDOW,
|
||||||
ZDWM_COMMAND_CONFIGURE_WINDOW,
|
ZDWM_COMMAND_CONFIGURE_WINDOW,
|
||||||
|
ZDWM_COMMAND_NOTIFY_CONFIGURE,
|
||||||
ZDWM_COMMAND_CHANGE_WINDOW_STATE,
|
ZDWM_COMMAND_CHANGE_WINDOW_STATE,
|
||||||
ZDWM_COMMAND_START_MOVE_WINDOW,
|
ZDWM_COMMAND_START_MOVE_WINDOW,
|
||||||
ZDWM_COMMAND_STOP_MOVE_WINDOW,
|
ZDWM_COMMAND_STOP_MOVE_WINDOW,
|
||||||
@@ -102,6 +103,7 @@ typedef struct command_t {
|
|||||||
only_window_data_t raise;
|
only_window_data_t raise;
|
||||||
only_window_data_t withdraw;
|
only_window_data_t withdraw;
|
||||||
configure_data_t configure;
|
configure_data_t configure;
|
||||||
|
only_window_data_t notify_configure;
|
||||||
window_state_change_command_t state_change;
|
window_state_change_command_t state_change;
|
||||||
start_interaction_command_t move;
|
start_interaction_command_t move;
|
||||||
start_interaction_command_t resize;
|
start_interaction_command_t resize;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "core/binding.h"
|
#include "core/binding.h"
|
||||||
#include "core/layout.h"
|
#include "core/layout.h"
|
||||||
#include "core/state.h"
|
#include "core/state.h"
|
||||||
|
#include "core/window.h"
|
||||||
|
|
||||||
#define FOR_EACH_LISTENER(FIELD, BODY) \
|
#define FOR_EACH_LISTENER(FIELD, BODY) \
|
||||||
do { \
|
do { \
|
||||||
@@ -117,7 +118,7 @@ static bool listeners_window_snapshot(
|
|||||||
*out = (zdwm_window_t){
|
*out = (zdwm_window_t){
|
||||||
.workspace = window->workspace_id,
|
.workspace = window->workspace_id,
|
||||||
.id = window->id,
|
.id = window->id,
|
||||||
.title = window->title,
|
.title = window_get_showing_title(window),
|
||||||
.focused = workspace->focused_window_id == window->id,
|
.focused = workspace->focused_window_id == window->id,
|
||||||
.urgent = window->urgent,
|
.urgent = window->urgent,
|
||||||
.skip_taskbar = window->skip_taskbar,
|
.skip_taskbar = window->skip_taskbar,
|
||||||
|
|||||||
@@ -121,6 +121,16 @@ void plan_push_resize_effect(plan_t *plan, window_id_t window_id) {
|
|||||||
plan_push_effect(plan, &effect);
|
plan_push_effect(plan, &effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void plan_push_configure_notify_effect(plan_t *plan, window_id_t window_id) {
|
||||||
|
if (window_id_invalid(window_id)) return;
|
||||||
|
|
||||||
|
effect_t effect = {
|
||||||
|
.type = ZDWM_EFFECT_CONFIGURE_NOTIFY,
|
||||||
|
.as.configure_notify.window = window_id,
|
||||||
|
};
|
||||||
|
plan_push_effect(plan, &effect);
|
||||||
|
}
|
||||||
|
|
||||||
void plan_push_fullscreen_effect(
|
void plan_push_fullscreen_effect(
|
||||||
plan_t *plan,
|
plan_t *plan,
|
||||||
window_id_t window_id,
|
window_id_t window_id,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ void plan_push_kill_effect(plan_t *plan, window_id_t window_id);
|
|||||||
void plan_push_withdraw_effect(plan_t *plan, window_id_t window_id);
|
void plan_push_withdraw_effect(plan_t *plan, window_id_t window_id);
|
||||||
void plan_push_move_effect(plan_t *plan, window_id_t window_id);
|
void plan_push_move_effect(plan_t *plan, window_id_t window_id);
|
||||||
void plan_push_resize_effect(plan_t *plan, window_id_t window_id);
|
void plan_push_resize_effect(plan_t *plan, window_id_t window_id);
|
||||||
|
void plan_push_configure_notify_effect(plan_t *plan, window_id_t window_id);
|
||||||
void plan_push_fullscreen_effect(
|
void plan_push_fullscreen_effect(
|
||||||
plan_t *plan,
|
plan_t *plan,
|
||||||
window_id_t window_id,
|
window_id_t window_id,
|
||||||
|
|||||||
@@ -771,6 +771,15 @@ static void route_window_state_request(
|
|||||||
command_buffer_push(out, &change_window_state_cmd);
|
command_buffer_push(out, &change_window_state_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_notify_configure_command(command_buffer_t *out, window_id_t window) {
|
||||||
|
command_t notify_cmd = {
|
||||||
|
.type = ZDWM_COMMAND_NOTIFY_CONFIGURE,
|
||||||
|
.as.notify_configure = {.window = window},
|
||||||
|
};
|
||||||
|
command_buffer_push(out, ¬ify_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
static void route_configure_request(
|
static void route_configure_request(
|
||||||
state_t *state,
|
state_t *state,
|
||||||
const configure_data_t *data,
|
const configure_data_t *data,
|
||||||
@@ -788,6 +797,7 @@ static void route_configure_request(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!state_workspace_show(state, window->workspace_id)) return;
|
if (!state_workspace_show(state, window->workspace_id)) return;
|
||||||
|
add_notify_configure_command(out, data->window);
|
||||||
if (window_need_layout(window)) return;
|
if (window_need_layout(window)) return;
|
||||||
auto workspace = state_workspace_get(state, window->workspace_id);
|
auto workspace = state_workspace_get(state, window->workspace_id);
|
||||||
if (layout_get(layouts, workspace->layout_id)) return;
|
if (layout_get(layouts, workspace->layout_id)) return;
|
||||||
@@ -938,10 +948,13 @@ static void 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;
|
||||||
auto workspace_id = command->workspace;
|
auto workspace_id = command->workspace;
|
||||||
|
auto workspace = state_workspace_get(state, workspace_id);
|
||||||
|
auto old_focused_window = workspace->focused_window_id;
|
||||||
state_window_set_workspace(state, window_id, workspace_id);
|
state_window_set_workspace(state, window_id, workspace_id);
|
||||||
set_foucs_window(ctx, workspace_id, window_id, plan);
|
set_foucs_window(ctx, workspace_id, window_id, plan);
|
||||||
plan_push_grab_button_effect(plan, window_id);
|
plan_push_grab_button_effect(plan, window_id);
|
||||||
push_window_list_effect(state, plan);
|
push_window_list_effect(state, plan);
|
||||||
|
listeners_notify_window_updated(ctx->listeners, state, old_focused_window);
|
||||||
listeners_notify_window_added(ctx->listeners, state, window_id);
|
listeners_notify_window_added(ctx->listeners, state, window_id);
|
||||||
|
|
||||||
if (window_should_fix_size(window)) {
|
if (window_should_fix_size(window)) {
|
||||||
@@ -950,7 +963,6 @@ static void manage_window(
|
|||||||
state_window_set_floating(state, window_id, command->floating);
|
state_window_set_floating(state, window_id, command->floating);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto workspace = state_workspace_get(state, workspace_id);
|
|
||||||
auto need_layout = window_need_layout(window);
|
auto need_layout = window_need_layout(window);
|
||||||
auto layout_func = layout_get(ctx->layouts, workspace->layout_id);
|
auto layout_func = layout_get(ctx->layouts, workspace->layout_id);
|
||||||
|
|
||||||
@@ -1690,6 +1702,9 @@ void policy_apply_command(
|
|||||||
case ZDWM_COMMAND_CONFIGURE_WINDOW:
|
case ZDWM_COMMAND_CONFIGURE_WINDOW:
|
||||||
configure_window(state, &cmd->as.configure, plan);
|
configure_window(state, &cmd->as.configure, plan);
|
||||||
break;
|
break;
|
||||||
|
case ZDWM_COMMAND_NOTIFY_CONFIGURE:
|
||||||
|
plan_push_configure_notify_effect(plan, cmd->as.notify_configure.window);
|
||||||
|
break;
|
||||||
case ZDWM_COMMAND_CHANGE_WINDOW_STATE:
|
case ZDWM_COMMAND_CHANGE_WINDOW_STATE:
|
||||||
change_window_state(ctx, &cmd->as.state_change, plan);
|
change_window_state(ctx, &cmd->as.state_change, plan);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -145,3 +145,11 @@ bool window_can_resize(const window_t *window) {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *window_get_showing_title(const window_t *window) {
|
||||||
|
if (window->title) return window->title;
|
||||||
|
if (window->instance_name) return window->instance_name;
|
||||||
|
if (window->class_name) return window->class_name;
|
||||||
|
if (window->app_id) return window->app_id;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|||||||
@@ -67,3 +67,4 @@ bool window_need_resize(const window_t *window, int32_t width, int32_t height);
|
|||||||
bool window_should_has_border(const window_t *window);
|
bool window_should_has_border(const window_t *window);
|
||||||
bool window_should_fix_size(const window_t *window);
|
bool window_should_fix_size(const window_t *window);
|
||||||
bool window_can_resize(const window_t *window);
|
bool window_can_resize(const window_t *window);
|
||||||
|
const char *window_get_showing_title(const window_t *window);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ typedef enum effect_type_t {
|
|||||||
ZDWM_EFFECT_MAXIMIZE_WINDOW,
|
ZDWM_EFFECT_MAXIMIZE_WINDOW,
|
||||||
ZDWM_EFFECT_FULLSCREEN_WINDOW,
|
ZDWM_EFFECT_FULLSCREEN_WINDOW,
|
||||||
ZDWM_EFFECT_CONFIGURE_WINDOW,
|
ZDWM_EFFECT_CONFIGURE_WINDOW,
|
||||||
|
ZDWM_EFFECT_CONFIGURE_NOTIFY,
|
||||||
ZDWM_EFFECT_CHANGE_BORDER_COLOR,
|
ZDWM_EFFECT_CHANGE_BORDER_COLOR,
|
||||||
ZDWM_EFFECT_CHANGE_WINDOW_LIST,
|
ZDWM_EFFECT_CHANGE_WINDOW_LIST,
|
||||||
ZDWM_EFFECT_RESTACK_WINDOWS,
|
ZDWM_EFFECT_RESTACK_WINDOWS,
|
||||||
@@ -86,6 +87,7 @@ typedef struct effect_t {
|
|||||||
effect_bool_window_t maximize;
|
effect_bool_window_t maximize;
|
||||||
effect_bool_window_t fullscreen;
|
effect_bool_window_t fullscreen;
|
||||||
configure_data_t configure;
|
configure_data_t configure;
|
||||||
|
only_window_data_t configure_notify;
|
||||||
effect_change_border_color_t change_border_color;
|
effect_change_border_color_t change_border_color;
|
||||||
effect_window_list_t change_window_list;
|
effect_window_list_t change_window_list;
|
||||||
effect_window_list_t restack_windows;
|
effect_window_list_t restack_windows;
|
||||||
|
|||||||
Reference in New Issue
Block a user