From 9e53010ff7d613b7d46f9bd43e9a7e95bce14deb Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Thu, 13 Nov 2025 19:28:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A3=80=E6=B5=8B=E5=B1=8F=E5=B9=95=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/types.h | 2 + src/utils.c | 17 +++++++- src/utils.h | 32 ++++++++++++++ src/wm.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 169 insertions(+), 2 deletions(-) diff --git a/src/types.h b/src/types.h index e9effce..41d3d97 100644 --- a/src/types.h +++ b/src/types.h @@ -53,6 +53,8 @@ struct monitor_t { tag_t *tag_list; tag_t *selected_tag; + char *name; + xcb_window_t bar_window; }; diff --git a/src/utils.c b/src/utils.c index 9154906..d64f68f 100644 --- a/src/utils.c +++ b/src/utils.c @@ -19,7 +19,8 @@ const char *current_time_str(void) { return buffer; } -/** Print error and exit with EXIT_FAILURE code. +/** + * Print error and exit with EXIT_FAILURE code. */ void _fatal(int line, const char *fct, const char *file, const char *fmt, ...) { va_list ap; @@ -32,3 +33,17 @@ void _fatal(int line, const char *fct, const char *file, const char *fmt, ...) { fprintf(stderr, "\n"); exit(EXIT_FAILURE); } + +/** + * Print error message on stderr + */ +void _warn(int line, const char *fct, const char *file, const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + const char *format = "(WW) [%s] %s\n%s:%d:%s:\n"; + fprintf(stderr, format, APP_NAME, current_time_str(), file, line, fct); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +} diff --git a/src/utils.h b/src/utils.h index 8050922..411344f 100644 --- a/src/utils.h +++ b/src/utils.h @@ -7,8 +7,10 @@ #define countof(foo) (ssizeof(foo) / ssizeof(foo[0])) #define p_alloc_nr(x) (((x) + 16) * 3 / 2) +#define p_new(type, count) ((type *)xmalloc(sizeof(type) * (count))) #define p_clear(p, count) ((void)memset((p), 0, sizeof(*(p)) * (count))) #define p_realloc(pp, count) xrealloc((void *)(pp), sizeof(**(pp)) * (count)) +#define p_dup(p, count) xmemdup((p), sizeof(*(p)) * (count)) #define p_delete(mem_p) \ do { \ @@ -46,6 +48,16 @@ static inline void xrealloc(void **ptr, ssize_t newsize) { } } +/** + * Duplicate a memory zone. + * @param src The source. + * @param size The source size. + * @return The memory address of the copy. + */ +static inline void *xmemdup(const void *src, ssize_t size) { + return memcpy(xmalloc(size), src, size); +} + /** * @brief NULL resistant strlen. * @@ -57,10 +69,30 @@ static inline void xrealloc(void **ptr, ssize_t newsize) { */ static inline ssize_t a_strlen(const char *s) { return s ? strlen(s) : 0; } +/** \brief \c NULL resistant strdup. + * + * The a_strdup() function returns a pointer to a new string, which is a + * duplicate of \c s. Memory should be freed using p_delete(). + * + * \warning when s is \c "", it returns NULL ! + * + * \param[in] s the string to duplicate. + * \return a pointer to the duplicated string. + */ +static inline char *a_strdup(const char *s) { + ssize_t len = a_strlen(s); + return len ? p_dup(s, len + 1) : NULL; +} + #define fatal(format, ...) \ _fatal(__LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__) void _fatal(int line, const char *function, const char *file, const char *format, ...) __attribute__((noreturn)) __attribute__((format(printf, 4, 5))); +#define warn(format, ...) \ + _fatal(__LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__) +void _warn(int line, const char *function, const char *file, const char *format, + ...) __attribute__((format(printf, 4, 5))); + const char *current_time_str(void); diff --git a/src/wm.c b/src/wm.c index 856fc49..6ad12e0 100644 --- a/src/wm.c +++ b/src/wm.c @@ -18,6 +18,7 @@ #include "backtrace.h" #include "buffer.h" +#include "types.h" #include "utils.h" static void wm_setup_signal(void); @@ -123,7 +124,113 @@ void wm_check_xcb_extensions(void) { wm.have_randr = query && query->present; } -void wm_detect_monitor(void) {} +static bool wm_detect_monitor_by_randr(void) { + xcb_randr_get_monitors_cookie_t monitors_cookie = + xcb_randr_get_monitors(wm.xcb_conn, wm.screen->root, 1); + xcb_randr_get_monitors_reply_t *monitors_reply = + xcb_randr_get_monitors_reply(wm.xcb_conn, monitors_cookie, NULL); + if (monitors_reply == NULL) { + warn("RandR get monitor failed"); + return false; + } + + monitor_t *prev_monitor = NULL; + xcb_randr_monitor_info_iterator_t monitor_iter; + for (monitor_iter = xcb_randr_get_monitors_monitors_iterator(monitors_reply); + monitor_iter.rem; xcb_randr_monitor_info_next(&monitor_iter)) { + monitor_t *monitor = p_new(monitor_t, 1); + monitor->geometry.x = monitor_iter.data->x; + monitor->geometry.y = monitor_iter.data->y; + monitor->geometry.width = monitor_iter.data->width; + monitor->geometry.height = monitor_iter.data->height; + + xcb_get_atom_name_cookie_t name_cookie = + xcb_get_atom_name_unchecked(wm.xcb_conn, monitor_iter.data->name); + xcb_get_atom_name_reply_t *name_reply = + xcb_get_atom_name_reply(wm.xcb_conn, name_cookie, NULL); + + if (name_reply) { + char *name = xcb_get_atom_name_name(name_reply); + int length = xcb_get_atom_name_name_length(name_reply); + monitor->name = memcpy(p_new(char, length + 1), name, length); + monitor->name[length] = '\0'; + p_delete(&name_reply); + } else { + monitor->name = a_strdup("unknown"); + } + + if (prev_monitor) { + prev_monitor->next = monitor; + } else { + wm.monitor_list = monitor; + prev_monitor = monitor; + } + } + + return true; +} + +static bool wm_detect_monitor_by_xinerama(void) { + xcb_xinerama_is_active_cookie_t active_cookie = + xcb_xinerama_is_active(wm.xcb_conn); + xcb_xinerama_is_active_reply_t *active_reply = + xcb_xinerama_is_active_reply(wm.xcb_conn, active_cookie, NULL); + if (!active_reply || !active_reply->state) { + p_delete(&active_reply); + return false; + } + + xcb_xinerama_query_screens_cookie_t screens_cookie = + xcb_xinerama_query_screens(wm.xcb_conn); + xcb_xinerama_query_screens_reply_t *screens_reply = + xcb_xinerama_query_screens_reply(wm.xcb_conn, screens_cookie, NULL); + + if (screens_reply == NULL) return false; + + int count = xcb_xinerama_query_screens_screen_info_length(screens_reply); + if (count <= 0) { + p_delete(&screens_reply); + return false; + } + + xcb_xinerama_screen_info_t *screen_info = + xcb_xinerama_query_screens_screen_info(screens_reply); + + monitor_t *prev_monitor = NULL; + for (int i = 0; i < count; i++) { + monitor_t *monitor = p_new(monitor_t, 1); + monitor->geometry.x = screen_info[i].x_org; + monitor->geometry.y = screen_info[i].y_org; + monitor->geometry.width = screen_info[i].width; + monitor->geometry.height = screen_info[i].height; + + if (prev_monitor) { + prev_monitor->next = monitor; + } else { + wm.monitor_list = monitor; + prev_monitor = monitor; + } + } + p_delete(&screens_reply); + + return true; +} + +void wm_detect_monitor(void) { + if (wm.have_randr && wm_detect_monitor_by_randr()) return; + if (wm.have_xinerama && wm_detect_monitor_by_xinerama()) return; + + if (wm.screen == NULL) fatal("cannot detect monitor info"); + + monitor_t *monitor = p_new(monitor_t, 1); + monitor->geometry.x = 0; + monitor->geometry.y = 0; + monitor->geometry.width = wm.screen->width_in_pixels; + monitor->geometry.height = wm.screen->height_in_pixels; + + wm.monitor_list = monitor; +} + void wm_scan_clients(void) {} void wm_restart(void) { @@ -138,6 +245,15 @@ void wm_quit(void) { } } +static void debug_show_monitor_list(void) { + printf("\n========================== monitors ==========================\n"); + for (monitor_t *m = wm.monitor_list; m; m = m->next) { + printf("x: %4d, y: %4d, width: %4u, height: %4u -> monitor[%s]\n", + m->geometry.x, m->geometry.y, m->geometry.width, m->geometry.height, + m->name); + } +} + int main(int argc, char *argv[]) { p_clear(&wm, 1); cmd_argv = argv; @@ -148,6 +264,8 @@ int main(int argc, char *argv[]) { wm_detect_monitor(); + debug_show_monitor_list(); + if (wm.loop == NULL) { wm.loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(wm.loop);