diff --git a/README.md b/README.md index 8e982b6..b321be5 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ cd wlroots meson build -Dprefix=/usr sudo ninja -C build install -git clone https://github.com/wlrfx/scenefx.git +git clone -b 0.4.1 https://github.com/wlrfx/scenefx.git cd scenefx meson build -Dprefix=/usr sudo ninja -C build install @@ -189,7 +189,10 @@ Here's an example of using the modules in a flake: inputs.nixpkgs.follows = "nixpkgs"; }; flake-parts.url = "github:hercules-ci/flake-parts"; - mango.url = "github:DreamMaoMao/mango"; + mango = { + url = "github:DreamMaoMao/mango"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = inputs@{ self, flake-parts, ... }: diff --git a/meson.build b/meson.build index 041a1fd..b02e0fd 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.5', + version : '0.10.6', ) subdir('protocols') diff --git a/nix/nixos-modules.nix b/nix/nixos-modules.nix index 5d0aa61..3381102 100644 --- a/nix/nixos-modules.nix +++ b/nix/nixos-modules.nix @@ -26,6 +26,25 @@ in { xdg.portal = { enable = lib.mkDefault true; + config = { + mango = { + default = [ + "gtk" + ]; + # except those + "org.freedesktop.impl.portal.Secret" = ["gnome-keyring"]; + "org.freedesktop.impl.portal.ScreenCast" = ["wlr"]; + "org.freedesktop.impl.portal.ScreenShot" = ["wlr"]; + + # wlr does not have this interface + "org.freedesktop.impl.portal.Inhibit" = []; + }; + }; + extraPortals = with pkgs; [ + xdg-desktop-portal-wlr + xdg-desktop-portal-gtk + ]; + wlr.enable = lib.mkDefault true; configPackages = [cfg.package]; diff --git a/src/animation/client.h b/src/animation/client.h index a5236f0..c4a21e7 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -463,7 +463,7 @@ struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) { int offsetx = 0, offsety = 0, offsetw = 0, offseth = 0; struct ivec2 offset = {0, 0, 0, 0}; - if (!ISTILED(c) && !c->animation.tagining && !c->animation.tagouted && + if (!ISSCROLLTILED(c) && !c->animation.tagining && !c->animation.tagouted && !c->animation.tagouting) return offset; @@ -484,7 +484,7 @@ struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) { 需要主要border超出屏幕的时候不计算如偏差之内而是 要等窗口表面超出才开始计算偏差 */ - if (ISTILED(c) || c->animation.tagining || c->animation.tagouted || + if (ISSCROLLTILED(c) || c->animation.tagining || c->animation.tagouted || c->animation.tagouting) { if (left_out_offset > 0) { offsetx = GEZERO(left_out_offset - bw); @@ -512,7 +512,7 @@ struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) { offset.height = offseth; if ((clip_box->width + bw <= 0 || clip_box->height + bw <= 0) && - (ISTILED(c) || c->animation.tagouting || c->animation.tagining)) { + (ISSCROLLTILED(c) || c->animation.tagouting || c->animation.tagining)) { c->is_clip_to_hide = true; wlr_scene_node_set_enabled(&c->scene->node, false); } else if (c->is_clip_to_hide && VISIBLEON(c, c->mon)) { diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 074660b..a58a106 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -2274,35 +2274,53 @@ void parse_config_line(Config *config, const char *line) { void parse_config_file(Config *config, const char *file_path) { FILE *file; - // 检查路径是否以 ~/ 开头 - if (file_path[0] == '~' && (file_path[1] == '/' || file_path[1] == '\0')) { + char full_path[1024]; + + if (file_path[0] == '.' && file_path[1] == '/') { + // Relative path + + const char *mangoconfig = getenv("MANGOCONFIG"); + if (mangoconfig && mangoconfig[0] != '\0') { + snprintf(full_path, sizeof(full_path), "%s/%s", mangoconfig, + file_path + 1); + } else { + const char *home = getenv("HOME"); + if (!home) { + fprintf(stderr, "Error: HOME environment variable not set.\n"); + return; + } + snprintf(full_path, sizeof(full_path), "%s/.config/mango/%s", home, + file_path + 1); + } + file = fopen(full_path, "r"); + + } else if (file_path[0] == '~' && + (file_path[1] == '/' || file_path[1] == '\0')) { + // Home directory + const char *home = getenv("HOME"); if (!home) { fprintf(stderr, "Error: HOME environment variable not set.\n"); return; } - - // 构建完整路径(家目录 + / + 原路径去掉 ~) - char full_path[1024]; snprintf(full_path, sizeof(full_path), "%s%s", home, file_path + 1); - file = fopen(full_path, "r"); - if (!file) { - perror("Error opening file"); - return; - } + } else { + // Absolute path file = fopen(file_path, "r"); - if (!file) { - perror("Error opening file"); - return; - } + } + + if (!file) { + perror("Error opening file"); + return; } char line[512]; while (fgets(line, sizeof(line), file)) { - if (line[0] == '#' || line[0] == '\n') + if (line[0] == '#' || line[0] == '\n') { continue; + } parse_config_line(config, line); } @@ -3110,6 +3128,12 @@ void reapply_monitor_rules(void) { } } +void reapply_cursor_style(void) { + if (cursor_mgr) + wlr_xcursor_manager_destroy(cursor_mgr); + cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, cursor_size); +} + void reapply_border(void) { Client *c = NULL; @@ -3211,6 +3235,7 @@ void reset_option(void) { set_env(); run_exec(); + reapply_cursor_style(); reapply_border(); reapply_keyboard(); reapply_pointer(); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index c812bf1..d79a7c6 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -80,8 +80,12 @@ int defaultgaps(const Arg *arg) { int exchange_client(const Arg *arg) { Client *c = selmon->sel; - if (!c || c->isfloating || c->isfullscreen || c->ismaximizescreen) + if (!c || c->isfloating) return 0; + + if ((c->isfullscreen || c->ismaximizescreen) && !is_scroller_layout(c->mon)) + return 0; + exchange_two_client(c, direction_select(arg)); return 0; } @@ -497,7 +501,7 @@ int setlayout(const Arg *arg) { for (jk = 0; jk < LENGTH(layouts); jk++) { if (strcmp(layouts[jk].name, arg->v) == 0) { selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[jk]; - + clear_fullscreen_and_maximized_state(selmon); arrange(selmon, false); printstatus(); return 0; @@ -901,7 +905,7 @@ int switch_layout(const Arg *arg) { break; } } - + clear_fullscreen_and_maximized_state(selmon); arrange(selmon, false); printstatus(); return 0; @@ -912,6 +916,7 @@ int switch_layout(const Arg *arg) { selmon->pertag->ltidxs[selmon->pertag->curtag]->name) == 0) { selmon->pertag->ltidxs[selmon->pertag->curtag] = jk == LENGTH(layouts) - 1 ? &layouts[0] : &layouts[jk + 1]; + clear_fullscreen_and_maximized_state(selmon); arrange(selmon, false); printstatus(); return 0; diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index 6b0c4c5..15b2376 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -258,6 +258,7 @@ void dwl_ipc_output_set_layout(struct wl_client *client, index = 0; monitor->pertag->ltidxs[monitor->pertag->curtag] = &layouts[index]; + clear_fullscreen_and_maximized_state(monitor); arrange(monitor, false); printstatus(); } diff --git a/src/fetch/client.h b/src/fetch/client.h index f81dea7..c2b0abd 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -326,11 +326,12 @@ Client *direction_select(const Arg *arg) { return NULL; if (tc && (tc->isfullscreen || tc->ismaximizescreen) && - !is_scroller_layout(selmon)) { + (!is_scroller_layout(selmon) || tc->isfloating)) { return NULL; } - return find_client_by_direction(tc, arg, true, is_scroller_layout(selmon)); + return find_client_by_direction( + tc, arg, true, is_scroller_layout(selmon) && !selmon->isoverview); } /* We probably should change the name of this, it sounds like diff --git a/src/fetch/common.h b/src/fetch/common.h index 33d7272..41dc994 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -115,6 +115,10 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, surface = wlr_scene_surface_try_from_buffer( wlr_scene_buffer_from_node(node)) ->surface; + else if (node->type == WLR_SCENE_NODE_RECT) { + surface = NULL; + break; + } /* start from the topmost layer, find a sureface that can be focused by pointer, diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index ff517cc..2385c84 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -301,8 +301,7 @@ void scroller(Monitor *m) { for (i = 0; i < n; i++) { c = tempClients[i]; if (root_client == c) { - if (!c->is_pending_open_animation && - c->geom.x >= m->w.x + scroller_structs && + if (c->geom.x >= m->w.x + scroller_structs && c->geom.x + c->geom.width <= m->w.x + m->w.width - scroller_structs) { need_scroller = false; diff --git a/src/layout/vertical.h b/src/layout/vertical.h index cef0e3b..7eb9529 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -263,8 +263,7 @@ void vertical_scroller(Monitor *m) { for (i = 0; i < n; i++) { c = tempClients[i]; if (root_client == c) { - if (!c->is_pending_open_animation && - c->geom.y >= m->w.y + scroller_structs && + if (c->geom.y >= m->w.y + scroller_structs && c->geom.y + c->geom.height <= m->w.y + m->w.height - scroller_structs) { need_scroller = false; diff --git a/src/mango.c b/src/mango.c index 7754b86..c02cfec 100644 --- a/src/mango.c +++ b/src/mango.c @@ -739,6 +739,7 @@ static void refresh_monitors_workspaces_status(Monitor *m); static void init_client_properties(Client *c); static float *get_border_color(Client *c); static void request_fresh_all_monitors(void); +static void clear_fullscreen_and_maximized_state(Monitor *m); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -936,11 +937,25 @@ void applybounds(Client *c, struct wlr_box *bbox) { c->geom.y = bbox->y; } +void clear_fullscreen_and_maximized_state(Monitor *m) { + Client *fc = NULL; + wl_list_for_each(fc, &clients, link) { + if (fc && VISIBLEON(fc, m) && ISFULLSCREEN(fc)) { + clear_fullscreen_flag(fc); + } + } +} + /*清除全屏标志,还原全屏时清0的border*/ void clear_fullscreen_flag(Client *c) { - if (is_scroller_layout(c->mon)) + if ((c->mon->pertag->ltidxs[get_tags_first_tag_num(c->tags)]->id == + SCROLLER || + c->mon->pertag->ltidxs[get_tags_first_tag_num(c->tags)]->id == + VERTICAL_SCROLLER) && + !c->isfloating) { return; + } if (c->isfullscreen) { setfullscreen(c, false); @@ -2205,6 +2220,15 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { } // 刷新布局,让窗口能感应到exclude_zone变化以及设置独占表面 arrangelayers(l->mon); + + // 按需交互layer需要像正常窗口一样抢占非独占layer的焦点 + if (!exclusive_focus && + l->layer_surface->current.keyboard_interactive == + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { + focusclient(NULL, 0); + client_notify_enter(l->layer_surface->surface, + wlr_seat_get_keyboard(seat)); + } } void commitlayersurfacenotify(struct wl_listener *listener, void *data) { @@ -3723,7 +3747,7 @@ mapnotify(struct wl_listener *listener, void *data) { // tile at the top wl_list_insert(&clients, &c->link); // 新窗口是master,头部入栈 else if (selmon && is_scroller_layout(selmon) && - selmon->visible_tiling_clients > 0) { + selmon->visible_scroll_tiling_clients > 0) { if (selmon->sel && ISSCROLLTILED(selmon->sel) && VISIBLEON(selmon->sel, selmon)) { @@ -4557,7 +4581,7 @@ void setmaximizescreen(Client *c, int maximizescreen) { maximizescreen_box.width = c->mon->w.width - 2 * gappoh; maximizescreen_box.height = c->mon->w.height - 2 * gappov; wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 - if (!is_scroller_layout(c->mon)) + if (!is_scroller_layout(c->mon) || c->isfloating) resize(c, maximizescreen_box, 0); c->ismaximizescreen = 1; } else { @@ -4567,9 +4591,8 @@ void setmaximizescreen(Client *c, int maximizescreen) { setfloating(c, 1); } - wlr_scene_node_reparent(&c->scene->node, layers[maximizescreen ? LyrTile - : c->isfloating ? LyrTop - : LyrTile]); + wlr_scene_node_reparent(&c->scene->node, + layers[c->isfloating ? LyrTop : LyrTile]); if (!c->ismaximizescreen) { set_size_per(c->mon, c); } @@ -4615,7 +4638,7 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 c->bw = 0; wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 - if (!is_scroller_layout(c->mon)) + if (!is_scroller_layout(c->mon) || c->isfloating) resize(c, c->mon->m, 1); c->isfullscreen = 1; } else { @@ -5191,7 +5214,11 @@ unsigned int want_restore_fullscreen(Client *target_client) { Client *c = NULL; wl_list_for_each(c, &clients, link) { if (c && c != target_client && c->tags == target_client->tags && - c == selmon->sel) { + c == selmon->sel && + c->mon->pertag->ltidxs[get_tags_first_tag_num(c->tags)]->id != + SCROLLER && + c->mon->pertag->ltidxs[get_tags_first_tag_num(c->tags)]->id != + VERTICAL_SCROLLER) { return 0; } }