Compare commits
8 Commits
42ee022a0e
...
7405544c61
| Author | SHA1 | Date | |
|---|---|---|---|
|
7405544c61
|
|||
|
4ca37760e8
|
|||
|
503135830e
|
|||
|
8171cbb472
|
|||
|
489ae4bf2a
|
|||
|
5039ce457e
|
|||
|
db917c1293
|
|||
|
e7447f8aaa
|
@@ -1,5 +1,10 @@
|
|||||||
cmake_minimum_required(VERSION 3.24)
|
cmake_minimum_required(VERSION 3.24)
|
||||||
|
|
||||||
|
# use GNU23
|
||||||
|
set(CMAKE_C_STANDARD 23)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_C_EXTENSIONS ON)
|
||||||
|
|
||||||
set(APP_NAME "zdwm")
|
set(APP_NAME "zdwm")
|
||||||
set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||||
set(BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
set(BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
@@ -34,11 +39,9 @@ add_executable(${APP_NAME}
|
|||||||
${SOURCE_DIR}/action.c
|
${SOURCE_DIR}/action.c
|
||||||
${SOURCE_DIR}/xkb.c
|
${SOURCE_DIR}/xkb.c
|
||||||
${SOURCE_DIR}/atoms.c
|
${SOURCE_DIR}/atoms.c
|
||||||
|
${SOURCE_DIR}/layout.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# use C23
|
|
||||||
set_property(TARGET ${APP_NAME} PROPERTY C_STANDARD 23)
|
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
|
|
||||||
pkg_check_modules(deps REQUIRED
|
pkg_check_modules(deps REQUIRED
|
||||||
|
|||||||
106
src/client.c
106
src/client.c
@@ -1,5 +1,6 @@
|
|||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_aux.h>
|
#include <xcb/xcb_aux.h>
|
||||||
@@ -7,6 +8,7 @@
|
|||||||
#include <xcb/xproto.h>
|
#include <xcb/xproto.h>
|
||||||
|
|
||||||
#include "atoms-extern.h"
|
#include "atoms-extern.h"
|
||||||
|
#include "monitor.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "wm.h"
|
#include "wm.h"
|
||||||
@@ -48,17 +50,65 @@ static void client_detach_stack(client_t *client) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task_in_tag_t *client_get_task_in_tag(client_t *client, tag_t *tag) {
|
||||||
|
for (task_in_tag_t *task = tag->task_list; task; task = task->next) {
|
||||||
|
if (task->client == client) return task;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void client_add_to_tag(client_t *client, tag_t *tag) {
|
||||||
|
if (client_get_task_in_tag(client, tag)) return;
|
||||||
|
|
||||||
|
task_in_tag_t *task = p_new(task_in_tag_t, 1);
|
||||||
|
task->client = client;
|
||||||
|
task->next = tag->task_list;
|
||||||
|
tag->task_list = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void client_remove_from_tag(client_t *client, tag_t *tag) {
|
||||||
|
for (task_in_tag_t **task = &tag->task_list; *task; task = &(*task)->next) {
|
||||||
|
if ((*task)->client != client) continue;
|
||||||
|
p_delete(task);
|
||||||
|
*task = (*task)->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void client_wipe(client_t *client) {
|
||||||
|
p_delete(&client->class);
|
||||||
|
p_delete(&client->instance);
|
||||||
|
p_delete(&client->name);
|
||||||
|
p_delete(&client->icon_name);
|
||||||
|
p_delete(&client->net_name);
|
||||||
|
p_delete(&client->net_icon_name);
|
||||||
|
p_delete(&client->role);
|
||||||
|
p_delete(&client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void client_tags_apply(client_t *client) {
|
||||||
|
for (tag_t *tag = client->monitor->tag_list; tag; tag = tag->next) {
|
||||||
|
if (client->tags & tag->mask) {
|
||||||
|
client_add_to_tag(client, tag);
|
||||||
|
} else {
|
||||||
|
client_remove_from_tag(client, tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->tags == 0) client_wipe(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void client_update_names(client_t *c) {
|
||||||
|
xwindow_get_text_property(c->window, WM_NAME, &c->name);
|
||||||
|
xwindow_get_text_property(c->window, WM_ICON_NAME, &c->icon_name);
|
||||||
|
xwindow_get_text_property(c->window, _NET_WM_NAME, &c->net_name);
|
||||||
|
xwindow_get_text_property(c->window, _NET_WM_ICON_NAME, &c->net_icon_name);
|
||||||
|
}
|
||||||
|
|
||||||
void client_manage(xcb_window_t window,
|
void client_manage(xcb_window_t window,
|
||||||
xcb_get_geometry_reply_t *geometry_reply) {
|
xcb_get_geometry_reply_t *geometry_reply) {
|
||||||
client_t *c = p_new(client_t, 1);
|
client_t *c = p_new(client_t, 1);
|
||||||
c->window = window;
|
c->window = window;
|
||||||
|
|
||||||
c->name = xwindow_get_text_property(c->window, WM_NAME);
|
|
||||||
c->icon_name = xwindow_get_text_property(c->window, WM_ICON_NAME);
|
|
||||||
c->net_name = xwindow_get_text_property(c->window, _NET_WM_NAME);
|
|
||||||
c->net_icon_name = xwindow_get_text_property(c->window, _NET_WM_ICON_NAME);
|
|
||||||
c->role = xwindow_get_text_property(c->window, WM_WINDOW_ROLE);
|
|
||||||
|
|
||||||
client_attach_list(c);
|
client_attach_list(c);
|
||||||
client_attach_stack(c);
|
client_attach_stack(c);
|
||||||
|
|
||||||
@@ -71,6 +121,7 @@ void client_manage(xcb_window_t window,
|
|||||||
c->instance = strdup(prop.instance_name);
|
c->instance = strdup(prop.instance_name);
|
||||||
xcb_icccm_get_wm_class_reply_wipe(&prop);
|
xcb_icccm_get_wm_class_reply_wipe(&prop);
|
||||||
}
|
}
|
||||||
|
xwindow_get_text_property(c->window, WM_WINDOW_ROLE, &c->role);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -88,8 +139,11 @@ void client_manage(xcb_window_t window,
|
|||||||
c->monitor = wm.current_monitor;
|
c->monitor = wm.current_monitor;
|
||||||
c->tags = c->monitor->selected_tag->mask;
|
c->tags = c->monitor->selected_tag->mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client_tags_apply(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
monitor_arrange(c->monitor);
|
||||||
{
|
{
|
||||||
const xcb_params_cw_t params = {
|
const xcb_params_cw_t params = {
|
||||||
.event_mask = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE |
|
.event_mask = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE |
|
||||||
@@ -101,9 +155,49 @@ void client_manage(xcb_window_t window,
|
|||||||
xcb_map_window(wm.xcb_conn, window);
|
xcb_map_window(wm.xcb_conn, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client_update_names(c);
|
||||||
|
monitor_draw_bar(c->monitor);
|
||||||
xcb_flush(wm.xcb_conn);
|
xcb_flush(wm.xcb_conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char **client_get_task_title(client_t *client) {
|
||||||
|
if (client->net_icon_name) return &client->net_icon_name;
|
||||||
|
if (client->net_name) return &client->net_name;
|
||||||
|
if (client->icon_name) return &client->icon_name;
|
||||||
|
if (client->name) return &client->name;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool client_need_layout(client_t *client) {
|
||||||
|
if (client->floating || client->fullscreen || client->maximize ||
|
||||||
|
client->minimize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void client_move_to(client_t *client, int16_t x, int16_t y) {
|
||||||
|
client->geometry.x = x;
|
||||||
|
client->geometry.y = y;
|
||||||
|
uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
|
||||||
|
const xcb_params_configure_window_t params = {.x = x, .y = y};
|
||||||
|
xcb_aux_configure_window(wm.xcb_conn, client->window, mask, ¶ms);
|
||||||
|
logger("== client 0x%x move to x: %d, y: %d\n", client->window, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void client_resize(client_t *client, uint16_t width, uint16_t height) {
|
||||||
|
client->geometry.width = width;
|
||||||
|
client->geometry.height = height;
|
||||||
|
uint16_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
|
||||||
|
const xcb_params_configure_window_t params = {
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
};
|
||||||
|
xcb_aux_configure_window(wm.xcb_conn, client->window, mask, ¶ms);
|
||||||
|
logger("== client 0x%x resize to width: %d, height: %d\n", client->window,
|
||||||
|
width, height);
|
||||||
|
}
|
||||||
|
|
||||||
bool client_is_visible(client_t *client) {
|
bool client_is_visible(client_t *client) {
|
||||||
return client->tags & client->monitor->selected_tag->mask;
|
return client->tags & client->monitor->selected_tag->mask;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,11 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
client_t *client_get_by_window(xcb_window_t window);
|
client_t *client_get_by_window(xcb_window_t window);
|
||||||
|
task_in_tag_t *client_get_task_in_tag(client_t *client, tag_t *tag);
|
||||||
void client_manage(xcb_window_t window,
|
void client_manage(xcb_window_t window,
|
||||||
xcb_get_geometry_reply_t *geometry_reply);
|
xcb_get_geometry_reply_t *geometry_reply);
|
||||||
|
char **client_get_task_title(client_t *client);
|
||||||
|
bool client_need_layout(client_t *client);
|
||||||
|
|
||||||
void client_send_to_tag(client_t *client, uint32_t tag_mask);
|
void client_send_to_tag(client_t *client, uint32_t tag_mask);
|
||||||
void client_send_to_monitor(client_t *client, monitor_t *monitor);
|
void client_send_to_monitor(client_t *client, monitor_t *monitor);
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "action.h"
|
#include "action.h"
|
||||||
|
#include "layout.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
static const char *const font_family = "monospace";
|
static const char *const font_family = "monospace";
|
||||||
static const int font_size = 10;
|
static const int font_size = 10;
|
||||||
@@ -26,9 +28,14 @@ static const button_t button_list[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const char launcher[] =
|
static const char launcher[] =
|
||||||
"rofi -show combi -modes window,drun,run,ssh,combi,windowcd";
|
"rofi -show combi -modes combi -combi-modes window,drun,run,ssh,windowcd";
|
||||||
static const keyboard_t key_list[] = {
|
static const keyboard_t key_list[] = {
|
||||||
{modifier_alt, XK_p, spawn, {.ptr = launcher}},
|
{modifier_alt, XK_p, spawn, {.ptr = launcher}},
|
||||||
{modifier_alt, XK_q, quit, {.b = false}},
|
{modifier_alt, XK_q, quit, {.b = false}},
|
||||||
{modifier_alt, XK_r, quit, {.b = true}},
|
{modifier_alt, XK_r, quit, {.b = true}},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const layout_t layout_list[] = {
|
||||||
|
{.symbol = "[M]", .arrange = monocle},
|
||||||
|
{.symbol = "><=", .arrange = nullptr},
|
||||||
|
};
|
||||||
|
|||||||
30
src/event.c
30
src/event.c
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <string.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_event.h>
|
#include <xcb/xcb_event.h>
|
||||||
#include <xcb/xcb_keysyms.h>
|
#include <xcb/xcb_keysyms.h>
|
||||||
@@ -10,12 +10,15 @@
|
|||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
#include "action.h"
|
#include "action.h"
|
||||||
|
#include "atoms-extern.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "default_config.h"
|
#include "default_config.h"
|
||||||
|
#include "monitor.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "wm.h"
|
#include "wm.h"
|
||||||
#include "xkb.h"
|
#include "xkb.h"
|
||||||
|
#include "xwindow.h"
|
||||||
|
|
||||||
static void button_press(xcb_button_press_event_t *ev) {
|
static void button_press(xcb_button_press_event_t *ev) {
|
||||||
click_area_t click_area = click_none;
|
click_area_t click_area = click_none;
|
||||||
@@ -72,7 +75,7 @@ static void key_press(xcb_key_press_event_t *ev) {
|
|||||||
xcb_keysym_t keysym = xcb_key_press_lookup_keysym(wm.key_symbols, ev, 0);
|
xcb_keysym_t keysym = xcb_key_press_lookup_keysym(wm.key_symbols, ev, 0);
|
||||||
char key_name[16];
|
char key_name[16];
|
||||||
if (xkb_keysym_get_name(keysym, key_name, sizeof(key_name)) != -1) {
|
if (xkb_keysym_get_name(keysym, key_name, sizeof(key_name)) != -1) {
|
||||||
printf("key %s: %s\n", is_press ? "press" : "release", key_name);
|
logger("key %s: %s\n", is_press ? "press" : "release", key_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_press) return;
|
if (!is_press) return;
|
||||||
@@ -116,10 +119,30 @@ static void map_request(xcb_map_request_event_t *ev) {
|
|||||||
p_delete(&wa_reply);
|
p_delete(&wa_reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void property_notify(xcb_property_notify_event_t *ev) {
|
||||||
|
client_t *client = client_get_by_window(ev->window);
|
||||||
|
if (client == nullptr) return;
|
||||||
|
|
||||||
|
if (ev->atom == WM_NAME) {
|
||||||
|
xwindow_get_text_property(ev->window, ev->atom, &client->name);
|
||||||
|
monitor_draw_bar(client->monitor);
|
||||||
|
} else if (ev->atom == WM_ICON_NAME) {
|
||||||
|
if (client->icon_name) p_delete(&client->icon_name);
|
||||||
|
xwindow_get_text_property(ev->window, ev->atom, &client->icon_name);
|
||||||
|
monitor_draw_bar(client->monitor);
|
||||||
|
} else if (ev->atom == _NET_WM_NAME) {
|
||||||
|
xwindow_get_text_property(ev->window, ev->atom, &client->net_name);
|
||||||
|
monitor_draw_bar(client->monitor);
|
||||||
|
} else if (ev->atom == _NET_WM_ICON_NAME) {
|
||||||
|
xwindow_get_text_property(ev->window, ev->atom, &client->net_icon_name);
|
||||||
|
monitor_draw_bar(client->monitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_xcb_event(xcb_generic_event_t *event) {
|
static void handle_xcb_event(xcb_generic_event_t *event) {
|
||||||
uint8_t event_type = XCB_EVENT_RESPONSE_TYPE(event);
|
uint8_t event_type = XCB_EVENT_RESPONSE_TYPE(event);
|
||||||
const char *label = xcb_event_get_label(event_type);
|
const char *label = xcb_event_get_label(event_type);
|
||||||
printf("event type: %u[%s], xkb_event: %u\n", event_type, label,
|
logger("event type: %u[%s], xkb_event: %u\n", event_type, label,
|
||||||
wm.event_base_xkb);
|
wm.event_base_xkb);
|
||||||
|
|
||||||
switch (event_type) {
|
switch (event_type) {
|
||||||
@@ -133,6 +156,7 @@ static void handle_xcb_event(xcb_generic_event_t *event) {
|
|||||||
EVENT(XCB_KEY_RELEASE, key_press);
|
EVENT(XCB_KEY_RELEASE, key_press);
|
||||||
EVENT(XCB_CONFIGURE_REQUEST, configure_request);
|
EVENT(XCB_CONFIGURE_REQUEST, configure_request);
|
||||||
EVENT(XCB_MAP_REQUEST, map_request);
|
EVENT(XCB_MAP_REQUEST, map_request);
|
||||||
|
EVENT(XCB_PROPERTY_NOTIFY, property_notify);
|
||||||
|
|
||||||
#undef EVENT
|
#undef EVENT
|
||||||
}
|
}
|
||||||
|
|||||||
19
src/layout.c
Normal file
19
src/layout.c
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "layout.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
void monocle(tag_t *tag) {
|
||||||
|
logger("== monocle tag: %s start ==\n", tag->name);
|
||||||
|
for (task_in_tag_t *task = tag->task_list; task; task = task->next) {
|
||||||
|
if (!client_need_layout(task->client)) continue;
|
||||||
|
task->geometry = task->client->monitor->workarea;
|
||||||
|
logger("== window 0x%x: x: %d, y: %d, width: %u, height: %u\n",
|
||||||
|
task->client->window, task->geometry.x, task->geometry.y,
|
||||||
|
task->geometry.width, task->geometry.height);
|
||||||
|
}
|
||||||
|
logger("== monocle tag: %s end ==\n", tag->name);
|
||||||
|
}
|
||||||
5
src/layout.h
Normal file
5
src/layout.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
void monocle(tag_t *tag);
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <xcb/xcb_aux.h>
|
#include <xcb/xcb_aux.h>
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
#include "client.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
@@ -27,6 +28,10 @@ uint32_t monitor_initialize_tag(monitor_t *monitor, const char **tags,
|
|||||||
tag->mask = 1u << i;
|
tag->mask = 1u << i;
|
||||||
tag->index = tag_index_start_at + tag_count;
|
tag->index = tag_index_start_at + tag_count;
|
||||||
|
|
||||||
|
if (wm.layout_count > 0 && wm.layout_list) {
|
||||||
|
tag->layout = &wm.layout_list[0];
|
||||||
|
}
|
||||||
|
|
||||||
if (prev_tag) {
|
if (prev_tag) {
|
||||||
prev_tag->next = tag;
|
prev_tag->next = tag;
|
||||||
} else {
|
} else {
|
||||||
@@ -118,7 +123,7 @@ void monitor_init_bar(monitor_t *monitor) {
|
|||||||
|
|
||||||
uint16_t width = monitor->geometry.width;
|
uint16_t width = monitor->geometry.width;
|
||||||
monitor->workarea.x = monitor->geometry.x;
|
monitor->workarea.x = monitor->geometry.x;
|
||||||
monitor->workarea.y = monitor->geometry.y;
|
monitor->workarea.y = monitor->geometry.y + wm.bar_height;
|
||||||
monitor->workarea.width = width;
|
monitor->workarea.width = width;
|
||||||
monitor->workarea.height = monitor->geometry.height - wm.bar_height;
|
monitor->workarea.height = monitor->geometry.height - wm.bar_height;
|
||||||
monitor->bar_window = window;
|
monitor->bar_window = window;
|
||||||
@@ -174,6 +179,52 @@ static void monitor_draw_tags(monitor_t *monitor) {
|
|||||||
monitor->tag_extent.end = x;
|
monitor->tag_extent.end = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void monitor_draw_layout_symbol(monitor_t *monitor) {
|
||||||
|
const layout_t *layout = monitor->selected_tag->layout;
|
||||||
|
if (layout && layout->symbol) {
|
||||||
|
color_t *color = &wm.color_set.tag_color;
|
||||||
|
int width = 0;
|
||||||
|
text_get_size(layout->symbol, &width, nullptr);
|
||||||
|
area_t area = {
|
||||||
|
.x = monitor->tag_extent.end,
|
||||||
|
.y = monitor->geometry.y,
|
||||||
|
.width = width + 2 * wm.padding.tag_x,
|
||||||
|
.height = wm.bar_height,
|
||||||
|
};
|
||||||
|
monitor->layout_symbol_extent.start = area.x;
|
||||||
|
monitor->layout_symbol_extent.end = area.x + area.width;
|
||||||
|
draw_text(monitor->bar_cr, layout->symbol, color, area, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void monitor_draw_tasks(monitor_t *monitor) {
|
||||||
|
task_in_tag_t *task_list = monitor->selected_tag->task_list;
|
||||||
|
if (!task_list) return;
|
||||||
|
|
||||||
|
uint16_t task_count = 0;
|
||||||
|
for (task_in_tag_t *task = task_list; task; task = task->next) ++task_count;
|
||||||
|
if (task_count == 0) return;
|
||||||
|
|
||||||
|
int16_t x = monitor->layout_symbol_extent.end;
|
||||||
|
uint16_t task_width = (monitor->geometry.width - x) / task_count;
|
||||||
|
for (task_in_tag_t *task = task_list; task; task = task->next) {
|
||||||
|
task->bar_extent.start = x;
|
||||||
|
task->bar_extent.end = x + task_width;
|
||||||
|
x += task_width;
|
||||||
|
|
||||||
|
char **title = client_get_task_title(task->client);
|
||||||
|
if (title == nullptr || *title == nullptr) continue;
|
||||||
|
color_t *color = &wm.color_set.active_tag_color;
|
||||||
|
area_t area = {
|
||||||
|
.x = task->bar_extent.start,
|
||||||
|
.y = monitor->geometry.y,
|
||||||
|
.width = task_width,
|
||||||
|
.height = wm.bar_height,
|
||||||
|
};
|
||||||
|
draw_text(monitor->bar_cr, *title, color, area, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void monitor_draw_bar(monitor_t *monitor) {
|
void monitor_draw_bar(monitor_t *monitor) {
|
||||||
cairo_t *cr = monitor->bar_cr;
|
cairo_t *cr = monitor->bar_cr;
|
||||||
uint16_t height = wm.bar_height;
|
uint16_t height = wm.bar_height;
|
||||||
@@ -186,4 +237,32 @@ void monitor_draw_bar(monitor_t *monitor) {
|
|||||||
draw_background(cr, &wm.color_set.bar_bg, bar_area);
|
draw_background(cr, &wm.color_set.bar_bg, bar_area);
|
||||||
|
|
||||||
monitor_draw_tags(monitor);
|
monitor_draw_tags(monitor);
|
||||||
|
monitor_draw_layout_symbol(monitor);
|
||||||
|
monitor_draw_tasks(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void monitor_arrange(monitor_t *monitor) {
|
||||||
|
tag_t *tag = monitor->selected_tag;
|
||||||
|
if (tag->layout && tag->layout->arrange) tag->layout->arrange(tag);
|
||||||
|
|
||||||
|
for (client_t *c = wm.client_list; c; c = c->next) {
|
||||||
|
task_in_tag_t *task = client_get_task_in_tag(c, tag);
|
||||||
|
if (task) {
|
||||||
|
if (task->geometry.x != c->geometry.x ||
|
||||||
|
task->geometry.y != c->geometry.y) {
|
||||||
|
client_move_to(c, task->geometry.x, task->geometry.y);
|
||||||
|
}
|
||||||
|
if (task->geometry.width != c->geometry.width ||
|
||||||
|
task->geometry.height != c->geometry.height) {
|
||||||
|
client_resize(c, task->geometry.width, task->geometry.height);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int16_t x = -c->geometry.width;
|
||||||
|
int16_t y = -c->geometry.height;
|
||||||
|
if (x != c->geometry.x || y != c->geometry.y) {
|
||||||
|
client_move_to(c, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xcb_flush(wm.xcb_conn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ void monitor_select_tag(monitor_t *monitor, uint32_t tag_mask);
|
|||||||
void monitor_clean(monitor_t *monitor);
|
void monitor_clean(monitor_t *monitor);
|
||||||
void monitor_init_bar(monitor_t *monitor);
|
void monitor_init_bar(monitor_t *monitor);
|
||||||
void monitor_draw_bar(monitor_t *monitor);
|
void monitor_draw_bar(monitor_t *monitor);
|
||||||
|
void monitor_arrange(monitor_t *monitor);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
static PangoContext *context = nullptr;
|
static PangoContext *context = nullptr;
|
||||||
static PangoLayout *layout = nullptr;
|
static PangoLayout *layout = nullptr;
|
||||||
@@ -29,7 +30,7 @@ static PangoAttrList *attr_list = nullptr;
|
|||||||
* @return layout 高度,可用于确定 bar 高度
|
* @return layout 高度,可用于确定 bar 高度
|
||||||
*/
|
*/
|
||||||
int text_init_pango_layout(const char *family, uint32_t size, uint32_t dpi) {
|
int text_init_pango_layout(const char *family, uint32_t size, uint32_t dpi) {
|
||||||
printf("family: %s, size: %u, dpi: %u\n", family, size, dpi);
|
logger("family: %s, size: %u, dpi: %u\n", family, size, dpi);
|
||||||
|
|
||||||
static const char *layout_family = nullptr;
|
static const char *layout_family = nullptr;
|
||||||
static uint32_t layout_size = 0;
|
static uint32_t layout_size = 0;
|
||||||
@@ -38,7 +39,7 @@ int text_init_pango_layout(const char *family, uint32_t size, uint32_t dpi) {
|
|||||||
|
|
||||||
if (layout_family != nullptr && strcmp(layout_family, family) == 0 &&
|
if (layout_family != nullptr && strcmp(layout_family, family) == 0 &&
|
||||||
layout_size == size && layout_dpi == dpi) {
|
layout_size == size && layout_dpi == dpi) {
|
||||||
printf("text pango layout config cached\n");
|
logger("text pango layout config cached\n");
|
||||||
return text_height;
|
return text_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ struct monitor_t {
|
|||||||
cairo_t *bar_cr;
|
cairo_t *bar_cr;
|
||||||
|
|
||||||
extent_in_bar_t tag_extent;
|
extent_in_bar_t tag_extent;
|
||||||
|
extent_in_bar_t layout_symbol_extent;
|
||||||
|
|
||||||
xcb_window_t bar_window;
|
xcb_window_t bar_window;
|
||||||
};
|
};
|
||||||
@@ -68,7 +69,7 @@ struct tag_t {
|
|||||||
extent_in_bar_t bar_extent;
|
extent_in_bar_t bar_extent;
|
||||||
tag_t *next;
|
tag_t *next;
|
||||||
char *name;
|
char *name;
|
||||||
layout_t *layout;
|
const layout_t *layout;
|
||||||
task_in_tag_t *task_list;
|
task_in_tag_t *task_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
17
src/utils.h
17
src/utils.h
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -70,3 +72,18 @@ void _warn(int line, const char *function, const char *file, const char *format,
|
|||||||
...) __attribute__((format(printf, 4, 5)));
|
...) __attribute__((format(printf, 4, 5)));
|
||||||
|
|
||||||
const char *current_time_str(void);
|
const char *current_time_str(void);
|
||||||
|
|
||||||
|
#if defined(RELEASE)
|
||||||
|
#define logger(format, ...)
|
||||||
|
#elif defined(LOG_FILE)
|
||||||
|
static inline void logger(const char *format, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
FILE *log_file = fopen(LOG_FILE, "a+t");
|
||||||
|
vfprintf(log_file, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
fclose(log_file);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define logger(format, ...) printf(format, ##__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|||||||
14
src/wm.c
14
src/wm.c
@@ -273,13 +273,15 @@ void wm_clean(void) {
|
|||||||
|
|
||||||
static void wm_setup(void) {
|
static void wm_setup(void) {
|
||||||
wm.padding.tag_x = tag_x_padding;
|
wm.padding.tag_x = tag_x_padding;
|
||||||
|
wm.layout_list = layout_list;
|
||||||
|
wm.layout_count = (uint16_t)countof(layout_list);
|
||||||
|
|
||||||
wm_init_color_set();
|
wm_init_color_set();
|
||||||
|
|
||||||
int font_height = text_init_pango_layout(font_family, font_size, default_dpi);
|
int font_height = text_init_pango_layout(font_family, font_size, default_dpi);
|
||||||
wm.bar_height = (uint16_t)font_height + 2 * bar_y_padding;
|
wm.bar_height = (uint16_t)font_height + 2 * bar_y_padding;
|
||||||
|
|
||||||
printf("font height: %d, bar height: %u\n", font_height, wm.bar_height);
|
logger("font height: %d, bar height: %u\n", font_height, wm.bar_height);
|
||||||
|
|
||||||
uint32_t tag_count = 0;
|
uint32_t tag_count = 0;
|
||||||
for (monitor_t *m = wm.monitor_list; m; m = m->next) {
|
for (monitor_t *m = wm.monitor_list; m; m = m->next) {
|
||||||
@@ -335,17 +337,17 @@ void wm_quit(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void debug_show_monitor_list(void) {
|
static void debug_show_monitor_list(void) {
|
||||||
printf("\n========================== monitors ==========================\n");
|
logger("\n========================== monitors ==========================\n");
|
||||||
for (monitor_t *m = wm.monitor_list; m; m = m->next) {
|
for (monitor_t *m = wm.monitor_list; m; m = m->next) {
|
||||||
printf("x: %4d, y: %4d, width: %4u, height: %4u -> monitor[%s]\n",
|
logger("x: %4d, y: %4d, width: %4u, height: %4u -> monitor[%s]\n",
|
||||||
m->geometry.x, m->geometry.y, m->geometry.width, m->geometry.height,
|
m->geometry.x, m->geometry.y, m->geometry.width, m->geometry.height,
|
||||||
m->name);
|
m->name);
|
||||||
printf("x: %4d, y: %4d, width: %4u, height: %4u -> workarea[%s]: %u\n",
|
logger("x: %4d, y: %4d, width: %4u, height: %4u -> workarea[%s]: %u\n",
|
||||||
m->workarea.x, m->workarea.y, m->workarea.width, m->workarea.height,
|
m->workarea.x, m->workarea.y, m->workarea.width, m->workarea.height,
|
||||||
m->name, wm.bar_height);
|
m->name, wm.bar_height);
|
||||||
printf("tag extend: [%d, %d]\n", m->tag_extent.start, m->tag_extent.end);
|
logger("tag extend: [%d, %d]\n", m->tag_extent.start, m->tag_extent.end);
|
||||||
for (const tag_t *tag = m->tag_list; tag; tag = tag->next) {
|
for (const tag_t *tag = m->tag_list; tag; tag = tag->next) {
|
||||||
printf("tag[%u]: %4u, \"%s\", [%d, %d]\n", tag->index, tag->mask,
|
logger("tag[%u]: %4u, \"%s\", [%d, %d]\n", tag->index, tag->mask,
|
||||||
tag->name, tag->bar_extent.start, tag->bar_extent.end);
|
tag->name, tag->bar_extent.start, tag->bar_extent.end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
src/wm.h
2
src/wm.h
@@ -9,6 +9,7 @@
|
|||||||
typedef struct wm_t {
|
typedef struct wm_t {
|
||||||
padding_t padding;
|
padding_t padding;
|
||||||
uint16_t bar_height;
|
uint16_t bar_height;
|
||||||
|
uint16_t layout_count;
|
||||||
|
|
||||||
bool need_restart;
|
bool need_restart;
|
||||||
GMainLoop *loop;
|
GMainLoop *loop;
|
||||||
@@ -18,6 +19,7 @@ typedef struct wm_t {
|
|||||||
client_t *client_focused;
|
client_t *client_focused;
|
||||||
monitor_t *monitor_list;
|
monitor_t *monitor_list;
|
||||||
monitor_t *current_monitor;
|
monitor_t *current_monitor;
|
||||||
|
const layout_t *layout_list;
|
||||||
|
|
||||||
xcb_connection_t *xcb_conn;
|
xcb_connection_t *xcb_conn;
|
||||||
xcb_screen_t *screen;
|
xcb_screen_t *screen;
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ void xkb_init(void) {
|
|||||||
wm.xcb_conn, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION,
|
wm.xcb_conn, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION,
|
||||||
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, nullptr, nullptr, &wm.event_base_xkb,
|
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, nullptr, nullptr, &wm.event_base_xkb,
|
||||||
nullptr);
|
nullptr);
|
||||||
printf("xkb base event: %u\n", wm.event_base_xkb);
|
logger("xkb base event: %u\n", wm.event_base_xkb);
|
||||||
if (!wm.have_xkb) {
|
if (!wm.have_xkb) {
|
||||||
warn("XKB not found or not supported");
|
warn("XKB not found or not supported");
|
||||||
xkb_init_keymap();
|
xkb_init_keymap();
|
||||||
@@ -182,7 +182,7 @@ static void xkb_schedule_refresh(void) {
|
|||||||
void xkb_handle_event(xcb_generic_event_t *event) {
|
void xkb_handle_event(xcb_generic_event_t *event) {
|
||||||
assert(wm.have_xkb);
|
assert(wm.have_xkb);
|
||||||
|
|
||||||
printf("xkb event type: %u\n", event->pad0);
|
logger("xkb event type: %u\n", event->pad0);
|
||||||
|
|
||||||
/* XKB 中没有对应所有事件的泛型类型,xcb_generic_event_t 类型中的 pad0
|
/* XKB 中没有对应所有事件的泛型类型,xcb_generic_event_t 类型中的 pad0
|
||||||
* 字段对应 XKB 事件中的 xkbType 字段,故用该字段判断 XKB 事件类型 */
|
* 字段对应 XKB 事件中的 xkbType 字段,故用该字段判断 XKB 事件类型 */
|
||||||
@@ -205,7 +205,7 @@ void xkb_handle_event(xcb_generic_event_t *event) {
|
|||||||
state_notify_event->baseGroup, state_notify_event->latchedGroup,
|
state_notify_event->baseGroup, state_notify_event->latchedGroup,
|
||||||
state_notify_event->lockedGroup);
|
state_notify_event->lockedGroup);
|
||||||
|
|
||||||
printf("changed: %u\n",
|
logger("changed: %u\n",
|
||||||
state_notify_event->changed & XCB_XKB_STATE_PART_GROUP_STATE);
|
state_notify_event->changed & XCB_XKB_STATE_PART_GROUP_STATE);
|
||||||
if (state_notify_event->changed & XCB_XKB_STATE_PART_GROUP_STATE) {
|
if (state_notify_event->changed & XCB_XKB_STATE_PART_GROUP_STATE) {
|
||||||
xkb_schedule_refresh();
|
xkb_schedule_refresh();
|
||||||
|
|||||||
@@ -177,27 +177,29 @@ void xwindow_focus(xcb_window_t window) {
|
|||||||
* 获取目标窗口的文本属性
|
* 获取目标窗口的文本属性
|
||||||
* @param window 目标窗口
|
* @param window 目标窗口
|
||||||
* @param property 属性名
|
* @param property 属性名
|
||||||
* @returns 返回的信息使用后记得使用 free 释放
|
* @param out 返回的信息使用后记得使用 free 释放
|
||||||
*/
|
*/
|
||||||
char *xwindow_get_text_property(xcb_window_t window, xcb_atom_t property) {
|
void xwindow_get_text_property(xcb_window_t window, xcb_atom_t property,
|
||||||
|
char **out) {
|
||||||
|
if (out == nullptr) return;
|
||||||
|
|
||||||
xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(
|
xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(
|
||||||
wm.xcb_conn, false, window, property, XCB_ATOM_STRING, 0, UINT32_MAX);
|
wm.xcb_conn, false, window, property, XCB_ATOM_STRING, 0, UINT32_MAX);
|
||||||
xcb_get_property_reply_t *reply =
|
xcb_get_property_reply_t *reply =
|
||||||
xcb_get_property_reply(wm.xcb_conn, cookie, nullptr);
|
xcb_get_property_reply(wm.xcb_conn, cookie, nullptr);
|
||||||
int length = xcb_get_property_value_length(reply);
|
int length = xcb_get_property_value_length(reply);
|
||||||
|
char *value = xcb_get_property_value(reply);
|
||||||
char *value = nullptr;
|
|
||||||
|
|
||||||
if (reply &&
|
if (reply &&
|
||||||
(reply->type == XCB_ATOM_STRING || reply->type == UTF8_STRING ||
|
(reply->type == XCB_ATOM_STRING || reply->type == UTF8_STRING ||
|
||||||
reply->type == COMPOUND_TEXT) &&
|
reply->type == COMPOUND_TEXT) &&
|
||||||
reply->format == 8 && length) {
|
reply->format == 8 && length &&
|
||||||
value = p_new(char, length + 1);
|
(*out == nullptr || strncmp(*out, value, length) != 0)) {
|
||||||
memcpy(value, xcb_get_property_value(reply), length);
|
if (*out) p_delete(out);
|
||||||
value[length] = '\0';
|
*out = p_new(char, length + 1);
|
||||||
|
memcpy(*out, value, length);
|
||||||
|
(*out)[length] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
p_delete(&reply);
|
p_delete(&reply);
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ void xwindow_grab_keys(xcb_window_t window, const keyboard_t *keys,
|
|||||||
int keys_length);
|
int keys_length);
|
||||||
bool xwindow_send_event(xcb_window_t window, xcb_atom_t atom);
|
bool xwindow_send_event(xcb_window_t window, xcb_atom_t atom);
|
||||||
void xwindow_focus(xcb_window_t window);
|
void xwindow_focus(xcb_window_t window);
|
||||||
char *xwindow_get_text_property(xcb_window_t window, xcb_atom_t property);
|
void xwindow_get_text_property(xcb_window_t window, xcb_atom_t property,
|
||||||
|
char **out);
|
||||||
|
|
||||||
#define xwindow_set_name_static(window, name) \
|
#define xwindow_set_name_static(window, name) \
|
||||||
xcb_icccm_set_wm_name(wm.xcb_conn, window, XCB_ATOM_STRING, 8, \
|
xcb_icccm_set_wm_name(wm.xcb_conn, window, XCB_ATOM_STRING, 8, \
|
||||||
|
|||||||
Reference in New Issue
Block a user