diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index cd9bd8d..e1a1d5d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,17 +1,24 @@ --- name: Bug report -about: Something in dwl isn't working correctly -title: '' -labels: 'A: bug' -assignees: '' - +about: Something in maomaowm isn't working correctly +title: "" +labels: "A: bug" +assignees: "" --- ## Info -dwl version: + + + + +maomao version: wlroots version: + ## Description + diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 84b1f04..43e8bad 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -15,13 +15,13 @@ jobs: # 禁用自动标记 stale(仅手动标记的 issue 会被处理) days-before-issue-stale: -1 # 手动标记后,14 天后关闭 - days-before-issue-close: 14 + days-before-issue-close: 7 # 使用的标签(必须和你手动添加的标签一致) stale-issue-label: "stale" # 自动关闭时自动加上的标签 close-issue-label: "automatic-closing" # 关闭时的提示信息 - close-issue-message: "This issue was closed because it was marked as stale and had no activity for 14 days." + close-issue-message: "Sorry,this issue was closed because it was marked as stale and had no activity for 7 days." # 禁用 PR 处理 days-before-pr-stale: -1 days-before-pr-close: -1 diff --git a/README.md b/README.md index ec5aa7a..e4c8e84 100644 --- a/README.md +++ b/README.md @@ -9,14 +9,15 @@ This project is developed based on [dwl](https://codeberg.org/dwl/dwl/), 2. **Feature Highlights** - Besides basic WM functionality, maomao provides: - - Smooth and customizable animations - - Excellent input method support - - Flexible window layouts with easy switching - - Rich window states: swallow, minimize, maximize, unglobal, global, fakefullscreen, overlay... + - Base tag not workspace(supports separate window layouts for each tag) + - Smooth and customizable complete animations(window open/move/close, tag enter/leave) + - Excellent input method support(text input v2/v3) + - Flexible window layouts with easy switching(scroller,master,monocle,spiral..etc) + - Rich window states(swallow, minimize, maximize, unglobal, global, fakefullscreen, overlay...etc) - Simple yet powerful external configuration - -3. **Philosophy** - - *Maomao* has no rigid design ideology—you could call it an eclectic hybrid of various compositors. + - Sway like scratchpad and named scratchpad + - Minimize window to scratchpad + - Hycov like overview Master-Stack Layout @@ -26,10 +27,7 @@ Scroller Layout https://github.com/user-attachments/assets/c9bf9415-fad1-4400-bcdc-3ad2d76de85a -# Features - -- Tag-based instead of workspace-based (supports separate window layouts for each tag) -- Supported layouts: +# Supported layouts - Tile - Scroller - Monocle @@ -38,17 +36,6 @@ https://github.com/user-attachments/assets/c9bf9415-fad1-4400-bcdc-3ad2d76de85a - Spiral - Deck -# Special Features - -- Hycov-like overview -- Foreign-toplevel protocol support (for dunst, waybar wlr taskbar) -- Minimize window to waybar (like hych) -- Sway-style scratchpad and Named scratchpad -- Text-input-v2/v3 protocol for fcitx5 -- Window animations (move/open/close/tag) -- Alt-tab window switching -- scroller layout - # install ## depend @@ -188,6 +175,4 @@ Here's an example of using the modules in a flake: - https://codeberg.org/dwl/dwl - basal dwl feature -- https://github.com/labwc/labwc - sample of text-input protocol - - https://github.com/swaywm/sway - sample of wayland protocol diff --git a/flake.nix b/flake.nix index 2581d89..6dfc25c 100644 --- a/flake.nix +++ b/flake.nix @@ -58,6 +58,6 @@ devShells.default = maomaowm.overrideAttrs shellOverride; formatter = treefmtEval.config.build.wrapper; }; - systems = ["x86_64-linux"]; + systems = ["x86_64-linux" "aarch64-linux"]; }; } diff --git a/meson.build b/meson.build index e2d181b..ae7f80c 100644 --- a/meson.build +++ b/meson.build @@ -71,7 +71,6 @@ endif executable('maomao', 'src/maomao.c', 'src/common/util.c', - 'src/common/mem.c', wayland_sources, dependencies : [ libm, diff --git a/src/common/mem.c b/src/common/mem.c deleted file mode 100644 index e464cd0..0000000 --- a/src/common/mem.c +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Based on labwc (https://github.com/labwc/labwc) */ -#define _POSIX_C_SOURCE 200809L -#include "mem.h" -#include -#include -#include - -static void die_if_null(void *ptr) { - if (!ptr) { - perror("Failed to allocate memory"); - exit(EXIT_FAILURE); - } -} - -void *xzalloc(size_t size) { - if (!size) { - return NULL; - } - void *ptr = calloc(1, size); - die_if_null(ptr); - return ptr; -} - -void *xrealloc(void *ptr, size_t size) { - if (!size) { - free(ptr); - return NULL; - } - ptr = realloc(ptr, size); - die_if_null(ptr); - return ptr; -} - -char *xstrdup(const char *str) { - assert(str); - char *copy = strdup(str); - die_if_null(copy); - return copy; -} diff --git a/src/common/mem.h b/src/common/mem.h deleted file mode 100644 index 1163c1e..0000000 --- a/src/common/mem.h +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Based on labwc (https://github.com/labwc/labwc) */ -#include - -/* - * As defined in busybox, weston, etc. - * Allocates zero-filled memory; calls exit() on error. - * Returns NULL only if (size == 0). - */ -void *xzalloc(size_t size); - -/* - * Type-safe macros in the style of C++ new/new[]. - * Both allocate zero-filled memory for object(s) the same size as - * , which may be either a type name or value expression. - * - * znew() allocates space for one object. - * znew_n() allocates space for an array of objects. - * - * Examples: - * struct wlr_box *box = znew(*box); - * char *buf = znew_n(char, 80); - */ -#define znew(expr) ((__typeof__(expr) *)xzalloc(sizeof(expr))) -#define znew_n(expr, n) ((__typeof__(expr) *)xzalloc((n) * sizeof(expr))) - -/* - * As defined in FreeBSD. - * Like realloc(), but calls exit() on error. - * Returns NULL only if (size == 0). - * Does NOT zero-fill memory. - */ -void *xrealloc(void *ptr, size_t size); - -/* malloc() is a specific case of realloc() */ -#define xmalloc(size) xrealloc(NULL, (size)) - -/* - * As defined in FreeBSD. - * Allocates a copy of ; calls exit() on error. - * Requires (str != NULL) and never returns NULL. - */ -char *xstrdup(const char *str); - -/* - * Same as ptr = xstrdup(str) but free - * before assigning the result. - */ -#define xstrdup_replace(ptr, str) \ - do { \ - free(ptr); \ - (ptr) = xstrdup(str); \ - } while (0) - -/* - * Frees memory pointed to by and sets to NULL. - * Does nothing if is already NULL. - */ -#define zfree(ptr) \ - do { \ - free(ptr); \ - (ptr) = NULL; \ - } while (0) diff --git a/src/common/util.c b/src/common/util.c index b5dd267..ccc6e41 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -52,6 +52,11 @@ int fd_set_nonblock(int fd) { int regex_match(const char *pattern, const char *str) { int errnum; PCRE2_SIZE erroffset; + + if (!pattern || !str) { + return 0; + } + pcre2_code *re = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, PCRE2_UTF, // 启用 UTF-8 支持 &errnum, &erroffset, NULL); diff --git a/src/config/preset_config.h b/src/config/preset.h similarity index 100% rename from src/config/preset_config.h rename to src/config/preset.h diff --git a/src/ext-protocol/all.h b/src/ext-protocol/all.h new file mode 100644 index 0000000..c657e0d --- /dev/null +++ b/src/ext-protocol/all.h @@ -0,0 +1,3 @@ +#include "dwl-ipc.h" +#include "foreign-toplevel.h" +#include "text-input.h" \ No newline at end of file diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h new file mode 100644 index 0000000..d05c72c --- /dev/null +++ b/src/ext-protocol/dwl-ipc.h @@ -0,0 +1,267 @@ +#include "dwl-ipc-unstable-v2-protocol.h" + +static void dwl_ipc_manager_bind(struct wl_client *client, void *data, + unsigned int version, unsigned int id); +static void dwl_ipc_manager_destroy(struct wl_resource *resource); +static void dwl_ipc_manager_get_output(struct wl_client *client, + struct wl_resource *resource, + unsigned int id, + struct wl_resource *output); +static void dwl_ipc_manager_release(struct wl_client *client, + struct wl_resource *resource); +static void dwl_ipc_output_destroy(struct wl_resource *resource); +static void dwl_ipc_output_printstatus(Monitor *monitor); +static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output); +static void dwl_ipc_output_set_client_tags(struct wl_client *client, + struct wl_resource *resource, + unsigned int and_tags, + unsigned int xor_tags); +static void dwl_ipc_output_set_layout(struct wl_client *client, + struct wl_resource *resource, + unsigned int index); +static void dwl_ipc_output_set_tags(struct wl_client *client, + struct wl_resource *resource, + unsigned int tagmask, + unsigned int toggle_tagset); +static void dwl_ipc_output_quit(struct wl_client *client, + struct wl_resource *resource); +static void dwl_ipc_output_dispatch(struct wl_client *client, + struct wl_resource *resource, + const char *dispatch, const char *arg1, + const char *arg2, const char *arg3, + const char *arg4, const char *arg5); +static void dwl_ipc_output_release(struct wl_client *client, + struct wl_resource *resource); + +/* global event handlers */ +static struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = { + .release = dwl_ipc_manager_release, + .get_output = dwl_ipc_manager_get_output}; +static struct zdwl_ipc_output_v2_interface dwl_output_implementation = { + .release = dwl_ipc_output_release, + .set_tags = dwl_ipc_output_set_tags, + .quit = dwl_ipc_output_quit, + .dispatch = dwl_ipc_output_dispatch, + .set_layout = dwl_ipc_output_set_layout, + .set_client_tags = dwl_ipc_output_set_client_tags}; + +void dwl_ipc_manager_bind(struct wl_client *client, void *data, + unsigned int version, unsigned int id) { + struct wl_resource *manager_resource = + wl_resource_create(client, &zdwl_ipc_manager_v2_interface, version, id); + if (!manager_resource) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(manager_resource, + &dwl_manager_implementation, NULL, + dwl_ipc_manager_destroy); + + zdwl_ipc_manager_v2_send_tags(manager_resource, LENGTH(tags)); + + for (unsigned int i = 0; i < LENGTH(layouts); i++) + zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol); +} + +void dwl_ipc_manager_destroy(struct wl_resource *resource) { + /* No state to destroy */ +} + +void dwl_ipc_manager_get_output(struct wl_client *client, + struct wl_resource *resource, unsigned int id, + struct wl_resource *output) { + DwlIpcOutput *ipc_output; + struct wlr_output *op = wlr_output_from_resource(output); + if (!op) + return; + Monitor *monitor = op->data; + struct wl_resource *output_resource = + wl_resource_create(client, &zdwl_ipc_output_v2_interface, + wl_resource_get_version(resource), id); + if (!output_resource) + return; + + ipc_output = ecalloc(1, sizeof(*ipc_output)); + ipc_output->resource = output_resource; + ipc_output->mon = monitor; + wl_resource_set_implementation(output_resource, &dwl_output_implementation, + ipc_output, dwl_ipc_output_destroy); + wl_list_insert(&monitor->dwl_ipc_outputs, &ipc_output->link); + dwl_ipc_output_printstatus_to(ipc_output); +} + +void dwl_ipc_manager_release(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void dwl_ipc_output_destroy(struct wl_resource *resource) { + DwlIpcOutput *ipc_output = wl_resource_get_user_data(resource); + wl_list_remove(&ipc_output->link); + free(ipc_output); +} + +void dwl_ipc_output_printstatus(Monitor *monitor) { + DwlIpcOutput *ipc_output; + wl_list_for_each(ipc_output, &monitor->dwl_ipc_outputs, link) + dwl_ipc_output_printstatus_to(ipc_output); +} + +void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { + Monitor *monitor = ipc_output->mon; + Client *c, *focused; + int tagmask, state, numclients, focused_client, tag; + const char *title, *appid, *symbol; + focused = focustop(monitor); + zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon); + + for (tag = 0; tag < LENGTH(tags); tag++) { + numclients = state = focused_client = 0; + tagmask = 1 << tag; + if ((tagmask & monitor->tagset[monitor->seltags]) != 0) + state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE; + wl_list_for_each(c, &clients, link) { + if (c->mon != monitor) + continue; + if (!(c->tags & tagmask)) + continue; + if (c == focused) + focused_client = 1; + if (c->isurgent) + state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT; + numclients++; + } + zdwl_ipc_output_v2_send_tag(ipc_output->resource, tag, state, + numclients, focused_client); + } + + title = focused ? client_get_title(focused) : ""; + appid = focused ? client_get_appid(focused) : ""; + symbol = monitor->pertag->ltidxs[monitor->pertag->curtag]->symbol; + + zdwl_ipc_output_v2_send_layout( + ipc_output->resource, + monitor->pertag->ltidxs[monitor->pertag->curtag] - layouts); + zdwl_ipc_output_v2_send_title(ipc_output->resource, title ? title : broken); + zdwl_ipc_output_v2_send_appid(ipc_output->resource, appid ? appid : broken); + zdwl_ipc_output_v2_send_layout_symbol(ipc_output->resource, symbol); + if (wl_resource_get_version(ipc_output->resource) >= + ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION) { + zdwl_ipc_output_v2_send_fullscreen(ipc_output->resource, + focused ? focused->isfullscreen : 0); + } + if (wl_resource_get_version(ipc_output->resource) >= + ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { + zdwl_ipc_output_v2_send_floating(ipc_output->resource, + focused ? focused->isfloating : 0); + } + if (wl_resource_get_version(ipc_output->resource) >= + ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { + zdwl_ipc_output_v2_send_x(ipc_output->resource, + focused ? focused->geom.x : 0); + } + if (wl_resource_get_version(ipc_output->resource) >= + ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { + zdwl_ipc_output_v2_send_y(ipc_output->resource, + focused ? focused->geom.y : 0); + } + if (wl_resource_get_version(ipc_output->resource) >= + ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { + zdwl_ipc_output_v2_send_width(ipc_output->resource, + focused ? focused->geom.width : 0); + } + if (wl_resource_get_version(ipc_output->resource) >= + ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { + zdwl_ipc_output_v2_send_height(ipc_output->resource, + focused ? focused->geom.height : 0); + } + zdwl_ipc_output_v2_send_frame(ipc_output->resource); +} + +void dwl_ipc_output_set_client_tags(struct wl_client *client, + struct wl_resource *resource, + unsigned int and_tags, + unsigned int xor_tags) { + DwlIpcOutput *ipc_output; + Monitor *monitor; + Client *selected_client; + unsigned int newtags = 0; + + ipc_output = wl_resource_get_user_data(resource); + if (!ipc_output) + return; + + monitor = ipc_output->mon; + selected_client = focustop(monitor); + if (!selected_client) + return; + + newtags = (selected_client->tags & and_tags) ^ xor_tags; + if (!newtags) + return; + + selected_client->tags = newtags; + if (selmon == monitor) + focusclient(focustop(monitor), 1); + arrange(selmon, false); + printstatus(); +} + +void dwl_ipc_output_set_layout(struct wl_client *client, + struct wl_resource *resource, + unsigned int index) { + DwlIpcOutput *ipc_output; + Monitor *monitor; + + ipc_output = wl_resource_get_user_data(resource); + if (!ipc_output) + return; + + monitor = ipc_output->mon; + if (index >= LENGTH(layouts)) + index = 0; + + monitor->pertag->ltidxs[monitor->pertag->curtag] = &layouts[index]; + arrange(monitor, false); + printstatus(); +} + +void dwl_ipc_output_set_tags(struct wl_client *client, + struct wl_resource *resource, unsigned int tagmask, + unsigned int toggle_tagset) { + DwlIpcOutput *ipc_output; + Monitor *monitor; + unsigned int newtags = tagmask & TAGMASK; + + ipc_output = wl_resource_get_user_data(resource); + if (!ipc_output) + return; + monitor = ipc_output->mon; + + view_in_mon(&(Arg){.ui = newtags}, true, monitor); +} + +void dwl_ipc_output_quit(struct wl_client *client, + struct wl_resource *resource) { + quit(&(Arg){0}); +} + +void dwl_ipc_output_dispatch(struct wl_client *client, + struct wl_resource *resource, const char *dispatch, + const char *arg1, const char *arg2, + const char *arg3, const char *arg4, + const char *arg5) { + + void (*func)(const Arg *); + Arg arg; + func = parse_func_name((char *)dispatch, &arg, (char *)arg1, (char *)arg2, + (char *)arg3, (char *)arg4, (char *)arg5); + if (func) { + func(&arg); + } +} + +void dwl_ipc_output_release(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} diff --git a/src/ext-protocol/foreign-toplevel.h b/src/ext-protocol/foreign-toplevel.h new file mode 100644 index 0000000..d2ee5ef --- /dev/null +++ b/src/ext-protocol/foreign-toplevel.h @@ -0,0 +1,105 @@ +#include + +static struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager; + +static void handle_foreign_activate_request(struct wl_listener *listener, + void *data); +static void handle_foreign_fullscreen_request(struct wl_listener *listener, + void *data); +static void handle_foreign_close_request(struct wl_listener *listener, + void *data); +static void handle_foreign_destroy(struct wl_listener *listener, void *data); + +void handle_foreign_activate_request(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, foreign_activate_request); + unsigned int target; + + if (c && c->swallowing) + return; + + if (c && !c->isminied && c == selmon->sel) { + set_minized(c); + return; + } + + if (c->isminied) { + c->is_in_scratchpad = 0; + c->isnamedscratchpand = 0; + c->is_scratchpad_show = 0; + setborder_color(c); + show_hide_client(c); + return; + } + + target = get_tags_first_tag(c->tags); + view(&(Arg){.ui = target}, true); + focusclient(c, 1); + wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, true); +} + +void handle_foreign_fullscreen_request(struct wl_listener *listener, + void *data) { + return; +} + +void handle_foreign_close_request(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, foreign_close_request); + if (c) { + pending_kill_client(c); + } +} + +void handle_foreign_destroy(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, foreign_destroy); + if (c) { + wl_list_remove(&c->foreign_activate_request.link); + wl_list_remove(&c->foreign_fullscreen_request.link); + wl_list_remove(&c->foreign_close_request.link); + wl_list_remove(&c->foreign_destroy.link); + } +} + +void remove_foreign_topleve(Client *c) { + wlr_foreign_toplevel_handle_v1_destroy(c->foreign_toplevel); + c->foreign_toplevel = NULL; +} + +void add_foreign_toplevel(Client *c) { + if (!c || !c->mon || !c->mon->wlr_output || !c->mon->wlr_output->enabled) + return; + + c->foreign_toplevel = + wlr_foreign_toplevel_handle_v1_create(foreign_toplevel_manager); + // 监听来自外部对于窗口的事件请求 + if (c->foreign_toplevel) { + LISTEN(&(c->foreign_toplevel->events.request_activate), + &c->foreign_activate_request, handle_foreign_activate_request); + LISTEN(&(c->foreign_toplevel->events.request_fullscreen), + &c->foreign_fullscreen_request, + handle_foreign_fullscreen_request); + LISTEN(&(c->foreign_toplevel->events.request_close), + &c->foreign_close_request, handle_foreign_close_request); + LISTEN(&(c->foreign_toplevel->events.destroy), &c->foreign_destroy, + handle_foreign_destroy); + // 设置外部顶层句柄的id为应用的id + const char *appid; + appid = client_get_appid(c); + if (appid) + wlr_foreign_toplevel_handle_v1_set_app_id(c->foreign_toplevel, + appid); + // 设置外部顶层句柄的title为应用的title + const char *title; + title = client_get_title(c); + if (title) + wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, + title); + // 设置外部顶层句柄的显示监视器为当前监视器 + wlr_foreign_toplevel_handle_v1_output_enter(c->foreign_toplevel, + c->mon->wlr_output); + } +} + +void reset_foreign_tolevel(Client *c) { + remove_foreign_topleve(c); + add_foreign_toplevel(c); +} diff --git a/src/text_input/ime.h b/src/ext-protocol/text-input.h similarity index 63% rename from src/text_input/ime.h rename to src/ext-protocol/text-input.h index 38cbb4b..ee647a2 100644 --- a/src/text_input/ime.h +++ b/src/ext-protocol/text-input.h @@ -1,46 +1,17 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Based on labwc (https://github.com/labwc/labwc) */ - -#include "../common/mem.h" #include #include #include -#define DWL_SET_MAX_SIZE 16 - -#define SAME_CLIENT(wlr_obj1, wlr_obj2) \ - (wl_resource_get_client((wlr_obj1)->resource) == \ - wl_resource_get_client((wlr_obj2)->resource)) - -struct dwl_set { - uint32_t values[DWL_SET_MAX_SIZE]; - int size; -}; - -/* - * The relay structure manages the relationship between text-inputs and - * input-method on a given seat. Multiple text-inputs may be bound to a relay, - * but at most one will be "active" (communicating with input-method) at a time. - * At most one input-method may be bound to the seat. When an input-method and - * an active text-input is present, the relay passes messages between them. - */ -struct input_method_relay { - struct wl_list text_inputs; /* struct text_input.link */ +struct dwl_input_method_relay { + struct wl_list text_inputs; struct wlr_input_method_v2 *input_method; struct wlr_surface *focused_surface; - struct dwl_set forwarded_pressed_keys; struct wlr_keyboard_modifiers forwarded_modifiers; - /* - * Text-input which is enabled by the client and communicating with - * input-method. - * This must be NULL if input-method is not present. - * Its client must be the same as that of focused_surface. - */ struct text_input *active_text_input; - struct wl_list popups; /* input_method_popup.link */ + struct wl_list popups; struct wlr_scene_tree *popup_tree; struct wl_listener new_text_input; @@ -55,19 +26,19 @@ struct input_method_relay { struct wl_listener focused_surface_destroy; }; -struct input_method_popup { +struct dwl_input_method_popup { struct wlr_input_popup_surface_v2 *popup_surface; struct wlr_scene_tree *tree; struct wlr_scene_tree *scene_surface; - struct input_method_relay *relay; - struct wl_list link; /* input_method_relay.popups */ + struct dwl_input_method_relay *relay; + struct wl_list link; struct wl_listener destroy; struct wl_listener commit; }; struct text_input { - struct input_method_relay *relay; + struct dwl_input_method_relay *relay; struct wlr_text_input_v3 *input; struct wl_list link; @@ -79,61 +50,23 @@ struct text_input { struct wlr_input_method_manager_v2 *input_method_manager; struct wlr_text_input_manager_v3 *text_input_manager; -struct input_method_relay *input_method_relay; +struct dwl_input_method_relay *dwl_input_method_relay; -/* - * Forward key event to keyboard grab of the seat from the keyboard - * if the keyboard grab exists. - * Returns true if the key event was forwarded. - */ -bool input_method_keyboard_grab_forward_key( - KeyboardGroup *keyboard, struct wlr_keyboard_key_event *event); +/*-------------------封装给外部调用-------------------------------*/ +bool dwl_im_keyboard_grab_forward_key(KeyboardGroup *keyboard, + struct wlr_keyboard_key_event *event); -/* - * Forward modifier state to keyboard grab of the seat from the keyboard - * if the keyboard grab exists. - * Returns true if the modifier state was forwarded. - */ -bool input_method_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard); +bool dwl_im_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard); -struct input_method_relay *input_method_relay_create(); +struct dwl_input_method_relay *dwl_im_relay_create(); -void input_method_relay_finish(struct input_method_relay *relay); +void dwl_im_relay_finish(struct dwl_input_method_relay *relay); -/* Updates currently focused surface. Surface must belong to the same seat. */ -void input_method_relay_set_focus(struct input_method_relay *relay, - struct wlr_surface *surface); - -bool dwl_set_contains(struct dwl_set *set, uint32_t value) { - for (int i = 0; i < set->size; ++i) { - if (set->values[i] == value) { - return true; - } - } - return false; -} - -void dwl_set_add(struct dwl_set *set, uint32_t value) { - if (dwl_set_contains(set, value)) { - return; - } - if (set->size >= DWL_SET_MAX_SIZE) { - wlr_log(WLR_ERROR, "dwl_set size exceeded"); - return; - } - set->values[set->size++] = value; -} - -void dwl_set_remove(struct dwl_set *set, uint32_t value) { - for (int i = 0; i < set->size; ++i) { - if (set->values[i] == value) { - --set->size; - set->values[i] = set->values[set->size]; - return; - } - } -} +void dwl_im_relay_set_focus(struct dwl_input_method_relay *relay, + struct wlr_surface *surface); +/*----------------------------------------------------------*/ +/*------------------协议内部代码------------------------------*/ Monitor *output_from_wlr_output(struct wlr_output *wlr_output) { Monitor *m; wl_list_for_each(m, &mons, link) { @@ -153,46 +86,34 @@ Monitor *output_nearest_to(int lx, int ly) { wlr_output_layout_output_at(output_layout, closest_x, closest_y)); } -bool output_is_usable(Monitor *m) { - /* output_is_usable(NULL) is safe and returns false */ - return m && m->wlr_output->enabled; -} +bool output_is_usable(Monitor *m) { return m && m->wlr_output->enabled; } static bool is_keyboard_emulated_by_input_method(struct wlr_keyboard *keyboard, struct wlr_input_method_v2 *input_method) { + struct wlr_virtual_keyboard_v1 *virtual_keyboard; if (!keyboard || !input_method) { return false; } - struct wlr_virtual_keyboard_v1 *virtual_keyboard = - wlr_input_device_get_virtual_keyboard(&keyboard->base); + virtual_keyboard = wlr_input_device_get_virtual_keyboard(&keyboard->base); - return virtual_keyboard && SAME_CLIENT(virtual_keyboard, input_method); + return virtual_keyboard && + wl_resource_get_client(virtual_keyboard->resource) == + wl_resource_get_client(input_method->resource); } -/* - * Get keyboard grab of the seat from keyboard if we should forward events - * to it. - */ static struct wlr_input_method_keyboard_grab_v2 * get_keyboard_grab(KeyboardGroup *keyboard) { - struct wlr_input_method_v2 *input_method = input_method_relay->input_method; + struct wlr_input_method_v2 *input_method = + dwl_input_method_relay->input_method; if (!input_method || !input_method->keyboard_grab) { return NULL; } - // labwc not need this , but maomao need if (keyboard != kb_group) return NULL; - /* - * Input-methods often use virtual keyboard to send raw key signals - * instead of sending encoded text via set_preedit_string and - * commit_string. We should not forward those key events back to the - * input-method so key events don't loop between the compositor and - * the input-method. - */ if (is_keyboard_emulated_by_input_method(&keyboard->wlr_group->keyboard, input_method)) { return NULL; @@ -201,24 +122,14 @@ get_keyboard_grab(KeyboardGroup *keyboard) { return input_method->keyboard_grab; } -bool input_method_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard) { +bool dwl_im_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard) { struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = get_keyboard_grab(keyboard); - struct wlr_keyboard_modifiers *forwarded_modifiers = - &input_method_relay->forwarded_modifiers; struct wlr_keyboard_modifiers *modifiers = &keyboard->wlr_group->keyboard.modifiers; - if (forwarded_modifiers->depressed == modifiers->depressed && - forwarded_modifiers->latched == modifiers->latched && - forwarded_modifiers->locked == modifiers->locked && - forwarded_modifiers->group == modifiers->group) { - return false; - } - if (keyboard_grab) { - *forwarded_modifiers = keyboard->wlr_group->keyboard.modifiers; wlr_input_method_keyboard_grab_v2_set_keyboard( keyboard_grab, &keyboard->wlr_group->keyboard); wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab, @@ -229,26 +140,12 @@ bool input_method_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard) { } } -bool input_method_keyboard_grab_forward_key( - KeyboardGroup *keyboard, struct wlr_keyboard_key_event *event) { - /* - * We should not forward key-release events without corresponding - * key-press events forwarded - */ - struct dwl_set *pressed_keys = &input_method_relay->forwarded_pressed_keys; - if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED && - !dwl_set_contains(pressed_keys, event->keycode)) { - return false; - } +bool dwl_im_keyboard_grab_forward_key(KeyboardGroup *keyboard, + struct wlr_keyboard_key_event *event) { struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = get_keyboard_grab(keyboard); if (keyboard_grab) { - if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { - dwl_set_add(pressed_keys, event->keycode); - } else { - dwl_set_remove(pressed_keys, event->keycode); - } wlr_input_method_keyboard_grab_v2_set_keyboard( keyboard_grab, &keyboard->wlr_group->keyboard); wlr_input_method_keyboard_grab_v2_send_key( @@ -259,16 +156,13 @@ bool input_method_keyboard_grab_forward_key( } } -/* - * update_text_inputs_focused_surface() should be called beforehand to set - * right text-inputs to choose from. - */ static struct text_input * -get_active_text_input(struct input_method_relay *relay) { +get_active_text_input(struct dwl_input_method_relay *relay) { + struct text_input *text_input; + if (!relay->input_method) { return NULL; } - struct text_input *text_input; wl_list_for_each(text_input, &relay->text_inputs, link) { if (text_input->input->focused_surface && text_input->input->current_enabled) { @@ -278,11 +172,7 @@ get_active_text_input(struct input_method_relay *relay) { return NULL; } -/* - * Updates active text-input and activates/deactivates the input-method if the - * value is changed. - */ -static void update_active_text_input(struct input_method_relay *relay) { +static void update_active_text_input(struct dwl_input_method_relay *relay) { struct text_input *active_text_input = get_active_text_input(relay); if (relay->input_method && relay->active_text_input != active_text_input) { @@ -297,23 +187,16 @@ static void update_active_text_input(struct input_method_relay *relay) { relay->active_text_input = active_text_input; } -/* - * Updates focused surface of text-inputs and sends enter/leave events to - * the text-inputs whose focused surface is changed. - * When input-method is present, text-inputs whose client is the same as the - * relay's focused surface also have that focused surface. Clients can then - * send enable request on a text-input which has the focused surface to make - * the text-input active and start communicating with input-method. - */ static void -update_text_inputs_focused_surface(struct input_method_relay *relay) { +update_text_inputs_focused_surface(struct dwl_input_method_relay *relay) { struct text_input *text_input; wl_list_for_each(text_input, &relay->text_inputs, link) { struct wlr_text_input_v3 *input = text_input->input; struct wlr_surface *new_focused_surface; if (relay->input_method && relay->focused_surface && - SAME_CLIENT(input, relay->focused_surface)) { + wl_resource_get_client(input->resource) == + wl_resource_get_client(relay->focused_surface->resource)) { new_focused_surface = relay->focused_surface; } else { new_focused_surface = NULL; @@ -331,19 +214,26 @@ update_text_inputs_focused_surface(struct input_method_relay *relay) { } } -static void update_popup_position(struct input_method_popup *popup) { - struct input_method_relay *relay = popup->relay; +static void update_popup_position(struct dwl_input_method_popup *popup) { + struct dwl_input_method_relay *relay = popup->relay; struct text_input *text_input = relay->active_text_input; + struct wlr_box cursor_rect; + struct wlr_xdg_surface *xdg_surface; + struct wlr_layer_surface_v1 *layer_surface; + struct wlr_scene_tree *tree; + Monitor *output; + struct wlr_xdg_positioner_rules pointer_rules; + struct wlr_box output_box; + int lx, ly; + struct wlr_box popup_box; if (!text_input || !relay->focused_surface || !popup->popup_surface->surface->mapped) { return; } - struct wlr_box cursor_rect; - struct wlr_xdg_surface *xdg_surface = - wlr_xdg_surface_try_from_wlr_surface(relay->focused_surface); - struct wlr_layer_surface_v1 *layer_surface = + xdg_surface = wlr_xdg_surface_try_from_wlr_surface(relay->focused_surface); + layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(relay->focused_surface); if ((text_input->input->current.features & @@ -351,20 +241,12 @@ static void update_popup_position(struct input_method_popup *popup) { (xdg_surface || layer_surface)) { cursor_rect = text_input->input->current.cursor_rectangle; - /* - * wlr_surface->data is: - * - for XDG surfaces: view->content_tree - * - for layer surfaces: dwl_layer_surface->scene_layer_surface->tree - * - for layer popups: dwl_layer_popup->scene_tree - */ - struct wlr_scene_tree *tree = relay->focused_surface->data; - int lx, ly; + tree = relay->focused_surface->data; wlr_scene_node_coords(&tree->node, &lx, &ly); cursor_rect.x += lx; cursor_rect.y += ly; if (xdg_surface) { - /* Take into account invisible xdg-shell CSD borders */ cursor_rect.x -= xdg_surface->geometry.x; cursor_rect.y -= xdg_surface->geometry.y; } @@ -372,16 +254,13 @@ static void update_popup_position(struct input_method_popup *popup) { cursor_rect = (struct wlr_box){0}; } - Monitor *output = output_nearest_to(cursor_rect.x, cursor_rect.y); + output = output_nearest_to(cursor_rect.x, cursor_rect.y); if (!output_is_usable(output)) { - wlr_log(WLR_ERROR, "Cannot position IME popup (unusable output)"); return; } - struct wlr_box output_box; wlr_output_layout_get_box(output_layout, output->wlr_output, &output_box); - /* Use xdg-positioner utilities to position popup */ - struct wlr_xdg_positioner_rules rules = { + pointer_rules = (struct wlr_xdg_positioner_rules){ .anchor_rect = cursor_rect, .anchor = XDG_POSITIONER_ANCHOR_BOTTOM_LEFT, .gravity = XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT, @@ -394,12 +273,11 @@ static void update_popup_position(struct input_method_popup *popup) { XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X, }; - struct wlr_box popup_box; - wlr_xdg_positioner_rules_get_geometry(&rules, &popup_box); - wlr_xdg_positioner_rules_unconstrain_box(&rules, &output_box, &popup_box); + wlr_xdg_positioner_rules_get_geometry(&pointer_rules, &popup_box); + wlr_xdg_positioner_rules_unconstrain_box(&pointer_rules, &output_box, + &popup_box); wlr_scene_node_set_position(&popup->tree->node, popup_box.x, popup_box.y); - /* Make sure IME popups are always on top, above layer-shell surfaces */ wlr_scene_node_raise_to_top(&relay->popup_tree->node); wlr_input_popup_surface_v2_send_text_input_rectangle( @@ -411,8 +289,8 @@ static void update_popup_position(struct input_method_popup *popup) { }); } -static void update_popups_position(struct input_method_relay *relay) { - struct input_method_popup *popup; +static void update_popups_position(struct dwl_input_method_relay *relay) { + struct dwl_input_method_popup *popup; wl_list_for_each(popup, &relay->popups, link) { update_popup_position(popup); } @@ -420,12 +298,13 @@ static void update_popups_position(struct input_method_relay *relay) { static void handle_input_method_commit(struct wl_listener *listener, void *data) { - struct input_method_relay *relay = + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, input_method_commit); struct wlr_input_method_v2 *input_method = data; + struct text_input *text_input; assert(relay->input_method == input_method); - struct text_input *text_input = relay->active_text_input; + text_input = relay->active_text_input; if (!text_input) { return; } @@ -451,13 +330,12 @@ static void handle_input_method_commit(struct wl_listener *listener, static void handle_keyboard_grab_destroy(struct wl_listener *listener, void *data) { - struct input_method_relay *relay = + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, keyboard_grab_destroy); struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; wl_list_remove(&relay->keyboard_grab_destroy.link); if (keyboard_grab->keyboard) { - /* Send modifier state to original client */ wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat, &keyboard_grab->keyboard->modifiers); } @@ -465,7 +343,7 @@ static void handle_keyboard_grab_destroy(struct wl_listener *listener, static void handle_input_method_grab_keyboard(struct wl_listener *listener, void *data) { - struct input_method_relay *relay = + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, input_method_grab_keyboard); struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; @@ -473,14 +351,10 @@ static void handle_input_method_grab_keyboard(struct wl_listener *listener, if (!is_keyboard_emulated_by_input_method(active_keyboard, relay->input_method)) { - /* Send modifier state to grab */ wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab, active_keyboard); } - relay->forwarded_pressed_keys = (struct dwl_set){0}; - relay->forwarded_modifiers = (struct wlr_keyboard_modifiers){0}; - relay->keyboard_grab_destroy.notify = handle_keyboard_grab_destroy; wl_signal_add(&keyboard_grab->events.destroy, &relay->keyboard_grab_destroy); @@ -488,7 +362,7 @@ static void handle_input_method_grab_keyboard(struct wl_listener *listener, static void handle_input_method_destroy(struct wl_listener *listener, void *data) { - struct input_method_relay *relay = + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, input_method_destroy); assert(relay->input_method == data); wl_list_remove(&relay->input_method_commit.link); @@ -503,7 +377,7 @@ static void handle_input_method_destroy(struct wl_listener *listener, static void handle_popup_surface_destroy(struct wl_listener *listener, void *data) { - struct input_method_popup *popup = + struct dwl_input_method_popup *popup = wl_container_of(listener, popup, destroy); wlr_scene_node_destroy(&popup->tree->node); wl_list_remove(&popup->destroy.link); @@ -514,16 +388,18 @@ static void handle_popup_surface_destroy(struct wl_listener *listener, static void handle_popup_surface_commit(struct wl_listener *listener, void *data) { - struct input_method_popup *popup = wl_container_of(listener, popup, commit); + struct dwl_input_method_popup *popup = + wl_container_of(listener, popup, commit); update_popup_position(popup); } static void handle_input_method_new_popup_surface(struct wl_listener *listener, void *data) { - struct input_method_relay *relay = + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, input_method_new_popup_surface); - struct input_method_popup *popup = znew(*popup); + struct dwl_input_method_popup *popup = + ecalloc(1, sizeof(struct dwl_input_method_popup)); popup->popup_surface = data; popup->relay = relay; @@ -534,11 +410,6 @@ static void handle_input_method_new_popup_surface(struct wl_listener *listener, wl_signal_add(&popup->popup_surface->surface->events.commit, &popup->commit); - // popup->tree = wlr_scene_subsurface_tree_create( - // relay->popup_tree, popup->popup_surface->surface); - // node_descriptor_create(&popup->tree->node, dwl_NODE_DESC_IME_POPUP, - // NULL); - popup->tree = wlr_scene_tree_create(layers[LyrIMPopup]); popup->scene_surface = wlr_scene_subsurface_tree_create( popup->tree, popup->popup_surface->surface); @@ -550,7 +421,7 @@ static void handle_input_method_new_popup_surface(struct wl_listener *listener, } static void handle_new_input_method(struct wl_listener *listener, void *data) { - struct input_method_relay *relay = + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, new_input_method); struct wlr_input_method_v2 *input_method = data; if (seat != input_method->seat) { @@ -558,7 +429,6 @@ static void handle_new_input_method(struct wl_listener *listener, void *data) { } if (relay->input_method) { - wlr_log(WLR_INFO, "Attempted to connect second input method to a seat"); wlr_input_method_v2_send_unavailable(input_method); return; } @@ -587,14 +457,12 @@ static void handle_new_input_method(struct wl_listener *listener, void *data) { update_active_text_input(relay); } -/* Conveys state from active text-input to input-method */ -static void send_state_to_input_method(struct input_method_relay *relay) { - assert(relay->active_text_input && relay->input_method); +static void send_state_to_input_method(struct dwl_input_method_relay *relay) { struct wlr_input_method_v2 *input_method = relay->input_method; struct wlr_text_input_v3 *input = relay->active_text_input->input; + assert(relay->active_text_input && relay->input_method); - /* TODO: only send each of those if they were modified */ if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT) { wlr_input_method_v2_send_surrounding_text( input_method, input->current.surrounding.text, @@ -614,7 +482,7 @@ static void send_state_to_input_method(struct input_method_relay *relay) { static void handle_text_input_enable(struct wl_listener *listener, void *data) { struct text_input *text_input = wl_container_of(listener, text_input, enable); - struct input_method_relay *relay = text_input->relay; + struct dwl_input_method_relay *relay = text_input->relay; update_active_text_input(relay); if (relay->active_text_input == text_input) { @@ -627,18 +495,14 @@ static void handle_text_input_disable(struct wl_listener *listener, void *data) { struct text_input *text_input = wl_container_of(listener, text_input, disable); - /* - * When the focus is moved between surfaces from different clients and - * then the old client sends "disable" event, the relay ignores it and - * doesn't deactivate the input-method. - */ + update_active_text_input(text_input->relay); } static void handle_text_input_commit(struct wl_listener *listener, void *data) { struct text_input *text_input = wl_container_of(listener, text_input, commit); - struct input_method_relay *relay = text_input->relay; + struct dwl_input_method_relay *relay = text_input->relay; if (relay->active_text_input == text_input) { update_popups_position(relay); @@ -660,14 +524,15 @@ static void handle_text_input_destroy(struct wl_listener *listener, } static void handle_new_text_input(struct wl_listener *listener, void *data) { - struct input_method_relay *relay = + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, new_text_input); struct wlr_text_input_v3 *wlr_text_input = data; + struct text_input *text_input = ecalloc(1, sizeof(struct text_input)); + if (seat != wlr_text_input->seat) { return; } - struct text_input *text_input = znew(*text_input); text_input->input = wlr_text_input; text_input->relay = relay; wl_list_insert(&relay->text_inputs, &text_input->link); @@ -687,22 +552,18 @@ static void handle_new_text_input(struct wl_listener *listener, void *data) { update_text_inputs_focused_surface(relay); } -/* - * Usually this function is not called because the client destroys the surface - * role (like xdg_toplevel) first and input_method_relay_set_focus() is called - * before wl_surface is destroyed. - */ static void handle_focused_surface_destroy(struct wl_listener *listener, void *data) { - struct input_method_relay *relay = + struct dwl_input_method_relay *relay = wl_container_of(listener, relay, focused_surface_destroy); assert(relay->focused_surface == data); - input_method_relay_set_focus(relay, NULL); + dwl_im_relay_set_focus(relay, NULL); } -struct input_method_relay *input_method_relay_create() { - struct input_method_relay *relay = znew(*relay); +struct dwl_input_method_relay *dwl_im_relay_create() { + struct dwl_input_method_relay *relay = + ecalloc(1, sizeof(struct dwl_input_method_relay)); wl_list_init(&relay->text_inputs); wl_list_init(&relay->popups); relay->popup_tree = wlr_scene_tree_create(&scene->tree); @@ -720,16 +581,15 @@ struct input_method_relay *input_method_relay_create() { return relay; } -void input_method_relay_finish(struct input_method_relay *relay) { +void dwl_im_relay_finish(struct dwl_input_method_relay *relay) { wl_list_remove(&relay->new_text_input.link); wl_list_remove(&relay->new_input_method.link); free(relay); } -void input_method_relay_set_focus(struct input_method_relay *relay, - struct wlr_surface *surface) { +void dwl_im_relay_set_focus(struct dwl_input_method_relay *relay, + struct wlr_surface *surface) { if (relay->focused_surface == surface) { - wlr_log(WLR_INFO, "The surface is already focused"); return; } @@ -744,4 +604,4 @@ void input_method_relay_set_focus(struct input_method_relay *relay, update_text_inputs_focused_surface(relay); update_active_text_input(relay); -} \ No newline at end of file +} diff --git a/src/maomao.c b/src/maomao.c index 7954827..b7adad2 100644 --- a/src/maomao.c +++ b/src/maomao.c @@ -87,10 +87,7 @@ #include #include #endif - #include "common/util.h" -#include "dwl-ipc-unstable-v2-protocol.h" -#include /* macros */ #define MAX(A, B) ((A) > (B) ? (A) : (B)) @@ -151,11 +148,11 @@ enum { enum { UP, DOWN, LEFT, RIGHT, UNDIR }; /* smartmovewin */ enum { NONE, OPEN, MOVE, CLOSE, TAG }; -struct vec2 { +struct dvec2 { double x, y; }; -struct uvec2 { +struct ivec2 { int x, y; }; @@ -203,6 +200,7 @@ struct dwl_animation { typedef struct Pertag Pertag; typedef struct Monitor Monitor; +struct wlr_foreign_toplevel_handle_v1; typedef struct { float width_scale; @@ -502,38 +500,7 @@ static void destroysessionlock(struct wl_listener *listener, void *data); static void destroykeyboardgroup(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); static void setcursorshape(struct wl_listener *listener, void *data); -static void dwl_ipc_manager_bind(struct wl_client *client, void *data, - unsigned int version, unsigned int id); -static void dwl_ipc_manager_destroy(struct wl_resource *resource); -static void dwl_ipc_manager_get_output(struct wl_client *client, - struct wl_resource *resource, - unsigned int id, - struct wl_resource *output); -static void dwl_ipc_manager_release(struct wl_client *client, - struct wl_resource *resource); -static void dwl_ipc_output_destroy(struct wl_resource *resource); -static void dwl_ipc_output_printstatus(Monitor *monitor); -static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output); -static void dwl_ipc_output_set_client_tags(struct wl_client *client, - struct wl_resource *resource, - unsigned int and_tags, - unsigned int xor_tags); -static void dwl_ipc_output_set_layout(struct wl_client *client, - struct wl_resource *resource, - unsigned int index); -static void dwl_ipc_output_set_tags(struct wl_client *client, - struct wl_resource *resource, - unsigned int tagmask, - unsigned int toggle_tagset); -static void dwl_ipc_output_quit(struct wl_client *client, - struct wl_resource *resource); -static void dwl_ipc_output_dispatch(struct wl_client *client, - struct wl_resource *resource, - const char *dispatch, const char *arg1, - const char *arg2, const char *arg3, - const char *arg4, const char *arg5); -static void dwl_ipc_output_release(struct wl_client *client, - struct wl_resource *resource); + static void focusclient(Client *c, int lift); static void setborder_color(Client *c); @@ -636,14 +603,6 @@ static void show_scratchpad(Client *c); static void show_hide_client(Client *c); static void tag_client(const Arg *arg, Client *target_client); -static void handle_foreign_activate_request(struct wl_listener *listener, - void *data); -static void handle_foreign_fullscreen_request(struct wl_listener *listener, - void *data); -static void handle_foreign_close_request(struct wl_listener *listener, - void *data); -static void handle_foreign_destroy(struct wl_listener *listener, void *data); - static struct wlr_box setclient_coordinate_center(Client *c, struct wlr_box geom, int offsetx, int offsety); @@ -670,6 +629,7 @@ static int hidecursor(void *data); static bool check_hit_no_border(Client *c); static void reset_keyboard_layout(void); static void client_update_oldmonname_record(Client *c, Monitor *m); +static void pending_kill_client(Client *c); #include "data/static_keymap.h" #include "dispatch/dispatch.h" @@ -683,7 +643,6 @@ static void *exclusive_focus; static struct wl_display *dpy; static struct wl_event_loop *event_loop; static struct wlr_relative_pointer_manager_v1 *pointer_manager; -static struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager; static struct wlr_backend *backend; static struct wlr_backend *headless_backend; static struct wlr_scene *scene; @@ -745,10 +704,10 @@ static double swipe_dy = 0; bool render_border = true; -struct vec2 *baked_points_move; -struct vec2 *baked_points_open; -struct vec2 *baked_points_tag; -struct vec2 *baked_points_close; +struct dvec2 *baked_points_move; +struct dvec2 *baked_points_open; +struct dvec2 *baked_points_tag; +struct dvec2 *baked_points_close; static struct wl_event_source *hide_source; static bool cursor_hidden = false; @@ -759,7 +718,7 @@ static struct { int hotspot_y; } last_cursor; -#include "config/preset_config.h" +#include "config/preset.h" struct Pertag { unsigned int curtag, prevtag; /* current and previous tag */ @@ -770,18 +729,6 @@ struct Pertag { *ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */ }; -/* global event handlers */ -static struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = { - .release = dwl_ipc_manager_release, - .get_output = dwl_ipc_manager_get_output}; -static struct zdwl_ipc_output_v2_interface dwl_output_implementation = { - .release = dwl_ipc_output_release, - .set_tags = dwl_ipc_output_set_tags, - .quit = dwl_ipc_output_quit, - .dispatch = dwl_ipc_output_dispatch, - .set_layout = dwl_ipc_output_set_layout, - .set_client_tags = dwl_ipc_output_set_client_tags}; - static struct wl_listener cursor_axis = {.notify = axisnotify}; static struct wl_listener cursor_button = {.notify = buttonpress}; static struct wl_listener cursor_frame = {.notify = cursorframe}; @@ -829,11 +776,11 @@ static struct wlr_xwayland *xwayland; #include "client/client.h" #include "config/parse_config.h" +#include "ext-protocol/all.h" #include "layout/layout.h" -#include "text_input/ime.h" -struct vec2 calculate_animation_curve_at(double t, int type) { - struct vec2 point; +struct dvec2 calculate_animation_curve_at(double t, int type) { + struct dvec2 point; double *animation_curve; if (type == MOVE) { animation_curve = animation_curve_move; @@ -886,7 +833,7 @@ double find_animation_curve_at(double t, int type) { unsigned int up = BAKED_POINTS_COUNT - 1; unsigned int middle = (up + down) / 2; - struct vec2 *baked_points; + struct dvec2 *baked_points; if (type == MOVE) { baked_points = baked_points_move; } else if (type == OPEN) { @@ -1247,10 +1194,10 @@ enum corner_location set_client_corner_location(Client *c) { return current_corner_location; } -struct uvec2 clip_to_hide(Client *c, struct wlr_box *clip_box) { +struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) { int offsetx = 0; int offsety = 0; - struct uvec2 offset; + struct ivec2 offset; offset.x = 0; offset.y = 0; @@ -1315,8 +1262,8 @@ void client_apply_clip(Client *c) { if (c->iskilling || !client_surface(c)->mapped) return; struct wlr_box clip_box; - struct uvec2 offset; bool should_render_client_surface = false; + struct ivec2 offset; animationScale scale_data; struct wlr_box surface_clip; enum corner_location current_corner_location = @@ -1564,51 +1511,6 @@ void show_scratchpad(Client *c) { setborder_color(c); } -void remove_foreign_topleve(Client *c) { - wlr_foreign_toplevel_handle_v1_destroy(c->foreign_toplevel); - c->foreign_toplevel = NULL; -} - -void add_foreign_toplevel(Client *c) { - if (!c || !c->mon || !c->mon->wlr_output || !c->mon->wlr_output->enabled) - return; - - c->foreign_toplevel = - wlr_foreign_toplevel_handle_v1_create(foreign_toplevel_manager); - // 监听来自外部对于窗口的事件请求 - if (c->foreign_toplevel) { - LISTEN(&(c->foreign_toplevel->events.request_activate), - &c->foreign_activate_request, handle_foreign_activate_request); - LISTEN(&(c->foreign_toplevel->events.request_fullscreen), - &c->foreign_fullscreen_request, - handle_foreign_fullscreen_request); - LISTEN(&(c->foreign_toplevel->events.request_close), - &c->foreign_close_request, handle_foreign_close_request); - LISTEN(&(c->foreign_toplevel->events.destroy), &c->foreign_destroy, - handle_foreign_destroy); - // 设置外部顶层句柄的id为应用的id - const char *appid; - appid = client_get_appid(c); - if (appid) - wlr_foreign_toplevel_handle_v1_set_app_id(c->foreign_toplevel, - appid); - // 设置外部顶层句柄的title为应用的title - const char *title; - title = client_get_title(c); - if (title) - wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, - title); - // 设置外部顶层句柄的显示监视器为当前监视器 - wlr_foreign_toplevel_handle_v1_output_enter(c->foreign_toplevel, - c->mon->wlr_output); - } -} - -void reset_foreign_tolevel(Client *c) { - remove_foreign_topleve(c); - add_foreign_toplevel(c); -} - pid_t getparentprocess(pid_t p) { unsigned int v = 0; @@ -1643,9 +1545,12 @@ Client *termforwin(Client *w) { if (!w->pid || w->isterm || w->noswallow) return NULL; - wl_list_for_each(c, &fstack, - flink) if (c->isterm && !c->swallowing && c->pid && - isdescprocess(c->pid, w->pid)) return c; + wl_list_for_each(c, &fstack, flink) { + if (c->isterm && !c->swallowing && c->pid && + isdescprocess(c->pid, w->pid)) { + return c; + } + } return NULL; } @@ -3014,7 +2919,7 @@ void cleanup(void) { destroykeyboardgroup(&kb_group->destroy, NULL); - input_method_relay_finish(input_method_relay); + dwl_im_relay_finish(dwl_input_method_relay); /* If it's not destroyed manually it will cause a use-after-free of * wlr_seat. Destroy it until it's fixed in the wlroots side */ @@ -3876,227 +3781,6 @@ Monitor *dirtomon(enum wlr_direction dir) { return selmon; } -void dwl_ipc_manager_bind(struct wl_client *client, void *data, - unsigned int version, unsigned int id) { - struct wl_resource *manager_resource = - wl_resource_create(client, &zdwl_ipc_manager_v2_interface, version, id); - if (!manager_resource) { - wl_client_post_no_memory(client); - return; - } - wl_resource_set_implementation(manager_resource, - &dwl_manager_implementation, NULL, - dwl_ipc_manager_destroy); - - zdwl_ipc_manager_v2_send_tags(manager_resource, LENGTH(tags)); - - for (unsigned int i = 0; i < LENGTH(layouts); i++) - zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol); -} - -void dwl_ipc_manager_destroy(struct wl_resource *resource) { - /* No state to destroy */ -} - -void dwl_ipc_manager_get_output(struct wl_client *client, - struct wl_resource *resource, unsigned int id, - struct wl_resource *output) { - DwlIpcOutput *ipc_output; - struct wlr_output *op = wlr_output_from_resource(output); - if (!op) - return; - Monitor *monitor = op->data; - struct wl_resource *output_resource = - wl_resource_create(client, &zdwl_ipc_output_v2_interface, - wl_resource_get_version(resource), id); - if (!output_resource) - return; - - ipc_output = ecalloc(1, sizeof(*ipc_output)); - ipc_output->resource = output_resource; - ipc_output->mon = monitor; - wl_resource_set_implementation(output_resource, &dwl_output_implementation, - ipc_output, dwl_ipc_output_destroy); - wl_list_insert(&monitor->dwl_ipc_outputs, &ipc_output->link); - dwl_ipc_output_printstatus_to(ipc_output); -} - -void dwl_ipc_manager_release(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void dwl_ipc_output_destroy(struct wl_resource *resource) { - DwlIpcOutput *ipc_output = wl_resource_get_user_data(resource); - wl_list_remove(&ipc_output->link); - free(ipc_output); -} - -void dwl_ipc_output_printstatus(Monitor *monitor) { - DwlIpcOutput *ipc_output; - wl_list_for_each(ipc_output, &monitor->dwl_ipc_outputs, link) - dwl_ipc_output_printstatus_to(ipc_output); -} - -void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { - Monitor *monitor = ipc_output->mon; - Client *c, *focused; - int tagmask, state, numclients, focused_client, tag; - const char *title, *appid, *symbol; - focused = focustop(monitor); - zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon); - - for (tag = 0; tag < LENGTH(tags); tag++) { - numclients = state = focused_client = 0; - tagmask = 1 << tag; - if ((tagmask & monitor->tagset[monitor->seltags]) != 0) - state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE; - wl_list_for_each(c, &clients, link) { - if (c->mon != monitor) - continue; - if (!(c->tags & tagmask)) - continue; - if (c == focused) - focused_client = 1; - if (c->isurgent) - state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT; - numclients++; - } - zdwl_ipc_output_v2_send_tag(ipc_output->resource, tag, state, - numclients, focused_client); - } - - title = focused ? client_get_title(focused) : ""; - appid = focused ? client_get_appid(focused) : ""; - symbol = monitor->pertag->ltidxs[monitor->pertag->curtag]->symbol; - - zdwl_ipc_output_v2_send_layout( - ipc_output->resource, - monitor->pertag->ltidxs[monitor->pertag->curtag] - layouts); - zdwl_ipc_output_v2_send_title(ipc_output->resource, title ? title : broken); - zdwl_ipc_output_v2_send_appid(ipc_output->resource, appid ? appid : broken); - zdwl_ipc_output_v2_send_layout_symbol(ipc_output->resource, symbol); - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION) { - zdwl_ipc_output_v2_send_fullscreen(ipc_output->resource, - focused ? focused->isfullscreen : 0); - } - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { - zdwl_ipc_output_v2_send_floating(ipc_output->resource, - focused ? focused->isfloating : 0); - } - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { - zdwl_ipc_output_v2_send_x(ipc_output->resource, - focused ? focused->geom.x : 0); - } - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { - zdwl_ipc_output_v2_send_y(ipc_output->resource, - focused ? focused->geom.y : 0); - } - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { - zdwl_ipc_output_v2_send_width(ipc_output->resource, - focused ? focused->geom.width : 0); - } - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { - zdwl_ipc_output_v2_send_height(ipc_output->resource, - focused ? focused->geom.height : 0); - } - zdwl_ipc_output_v2_send_frame(ipc_output->resource); -} - -void dwl_ipc_output_set_client_tags(struct wl_client *client, - struct wl_resource *resource, - unsigned int and_tags, - unsigned int xor_tags) { - DwlIpcOutput *ipc_output; - Monitor *monitor; - Client *selected_client; - unsigned int newtags = 0; - - ipc_output = wl_resource_get_user_data(resource); - if (!ipc_output) - return; - - monitor = ipc_output->mon; - selected_client = focustop(monitor); - if (!selected_client) - return; - - newtags = (selected_client->tags & and_tags) ^ xor_tags; - if (!newtags) - return; - - selected_client->tags = newtags; - if (selmon == monitor) - focusclient(focustop(monitor), 1); - arrange(selmon, false); - printstatus(); -} - -void dwl_ipc_output_set_layout(struct wl_client *client, - struct wl_resource *resource, - unsigned int index) { - DwlIpcOutput *ipc_output; - Monitor *monitor; - - ipc_output = wl_resource_get_user_data(resource); - if (!ipc_output) - return; - - monitor = ipc_output->mon; - if (index >= LENGTH(layouts)) - index = 0; - - monitor->pertag->ltidxs[monitor->pertag->curtag] = &layouts[index]; - arrange(monitor, false); - printstatus(); -} - -void dwl_ipc_output_set_tags(struct wl_client *client, - struct wl_resource *resource, unsigned int tagmask, - unsigned int toggle_tagset) { - DwlIpcOutput *ipc_output; - Monitor *monitor; - unsigned int newtags = tagmask & TAGMASK; - - ipc_output = wl_resource_get_user_data(resource); - if (!ipc_output) - return; - monitor = ipc_output->mon; - - view_in_mon(&(Arg){.ui = newtags}, true, monitor); -} - -void dwl_ipc_output_quit(struct wl_client *client, - struct wl_resource *resource) { - quit(&(Arg){0}); -} - -void dwl_ipc_output_dispatch(struct wl_client *client, - struct wl_resource *resource, const char *dispatch, - const char *arg1, const char *arg2, - const char *arg3, const char *arg4, - const char *arg5) { - - void (*func)(const Arg *); - Arg arg; - func = parse_func_name((char *)dispatch, &arg, (char *)arg1, (char *)arg2, - (char *)arg3, (char *)arg4, (char *)arg5); - if (func) { - func(&arg); - } -} - -void dwl_ipc_output_release(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - void focusclient(Client *c, int lift) { struct wlr_surface *old_keyboard_focus_surface = seat->keyboard_state.focused_surface; @@ -4196,7 +3880,7 @@ void focusclient(Client *c, int lift) { NULL; // 这个很关键,因为很多地方用到当前窗口做计算,不重置成NULL就会到处有野指针 // clear text input focus state - input_method_relay_set_focus(input_method_relay, NULL); + dwl_im_relay_set_focus(dwl_input_method_relay, NULL); wlr_seat_keyboard_notify_clear_focus(seat); return; } @@ -4208,7 +3892,7 @@ void focusclient(Client *c, int lift) { client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); // set text input focus - input_method_relay_set_focus(input_method_relay, client_surface(c)); + dwl_im_relay_set_focus(dwl_input_method_relay, client_surface(c)); /* Activate the new client */ client_activate_surface(client_surface(c), 1); } @@ -4558,7 +4242,7 @@ void keypress(struct wl_listener *listener, void *data) { if (hit_global) { return; } - if (!input_method_keyboard_grab_forward_key(group, event)) { + if (!dwl_im_keyboard_grab_forward_key(group, event)) { wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); /* Pass unhandled keycodes along to the client. */ wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, @@ -4571,7 +4255,7 @@ void keypressmod(struct wl_listener *listener, void *data) { * pressed. We simply communicate this to the client. */ KeyboardGroup *group = wl_container_of(listener, group, modifiers); - if (!input_method_keyboard_grab_forward_modifiers(group)) { + if (!dwl_im_keyboard_grab_forward_modifiers(group)) { wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); /* Send modifiers to the client. */ wlr_seat_keyboard_notify_modifiers( @@ -6463,55 +6147,6 @@ void show_hide_client(Client *c) { wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, true); } -void handle_foreign_activate_request(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, foreign_activate_request); - unsigned int target; - - if (c && c->swallowing) - return; - - if (c && !c->isminied && c == selmon->sel) { - set_minized(c); - return; - } - - if (c->isminied) { - c->is_in_scratchpad = 0; - c->isnamedscratchpand = 0; - c->is_scratchpad_show = 0; - setborder_color(c); - show_hide_client(c); - return; - } - - target = get_tags_first_tag(c->tags); - view(&(Arg){.ui = target}, true); - focusclient(c, 1); - wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, true); -} - -void handle_foreign_fullscreen_request(struct wl_listener *listener, - void *data) { - return; -} - -void handle_foreign_close_request(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, foreign_close_request); - if (c) { - pending_kill_client(c); - } -} - -void handle_foreign_destroy(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, foreign_destroy); - if (c) { - wl_list_remove(&c->foreign_activate_request.link); - wl_list_remove(&c->foreign_fullscreen_request.link); - wl_list_remove(&c->foreign_close_request.link); - wl_list_remove(&c->foreign_destroy.link); - } -} - void create_output(struct wlr_backend *backend, void *data) { bool *done = data; if (*done) { @@ -6821,8 +6456,8 @@ void setup(void) { input_method_manager = wlr_input_method_manager_v2_create(dpy); text_input_manager = wlr_text_input_manager_v3_create(dpy); - input_method_relay = calloc(1, sizeof(*input_method_relay)); - input_method_relay = input_method_relay_create(); + dwl_input_method_relay = calloc(1, sizeof(*dwl_input_method_relay)); + dwl_input_method_relay = dwl_im_relay_create(); wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, dwl_ipc_manager_bind);