Merge branch 'main' into spelling_fix

This commit is contained in:
Yujon Pradhananga 2026-02-12 21:09:20 +05:45 committed by GitHub
commit da3830df0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 319 additions and 85 deletions

View file

@ -24,18 +24,7 @@ This project's development is based on [dwl](https://codeberg.org/dwl/dwl/).
- Hycov-like overview - Hycov-like overview
- Window effects from scenefx (blur, shadow, corner radius, opacity) - Window effects from scenefx (blur, shadow, corner radius, opacity)
Master-Stack Layout https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f
https://github.com/user-attachments/assets/a9d4776e-b50b-48fb-94ce-651d8a749b8a
Scroller Layout
https://github.com/user-attachments/assets/c9bf9415-fad1-4400-bcdc-3ad2d76de85a
Layer animation
https://github.com/user-attachments/assets/014c893f-115c-4ae9-8342-f9ae3e9a0df0
# Our discord # Our discord
[mangowc](https://discord.gg/CPjbDxesh5) [mangowc](https://discord.gg/CPjbDxesh5)

View file

@ -240,12 +240,11 @@ bind=CTRL+ALT,Left,resizewin,-50,+0
bind=CTRL+ALT,Right,resizewin,+50,+0 bind=CTRL+ALT,Right,resizewin,+50,+0
# Mouse Button Bindings # Mouse Button Bindings
# NONE mode key only work in ov mode # btn_left and btn_right can't bind none mod key
mousebind=SUPER,btn_left,moveresize,curmove mousebind=SUPER,btn_left,moveresize,curmove
mousebind=NONE,btn_middle,togglemaximizescreen,0 mousebind=NONE,btn_middle,togglemaximizescreen,0
mousebind=SUPER,btn_right,moveresize,curresize mousebind=SUPER,btn_right,moveresize,curresize
mousebind=NONE,btn_left,toggleoverview,1
mousebind=NONE,btn_right,killclient,0
# Axis Bindings # Axis Bindings
axisbind=SUPER,UP,viewtoleft_have_client axisbind=SUPER,UP,viewtoleft_have_client

View file

@ -1,5 +1,5 @@
project('mango', ['c', 'cpp'], project('mango', ['c', 'cpp'],
version : '0.12.0', version : '0.12.1',
) )
subdir('protocols') subdir('protocols')

View file

@ -500,12 +500,48 @@ static const struct wl_registry_listener registry_listener = {
static void usage(void) { static void usage(void) {
fprintf(stderr, fprintf(stderr,
"usage:" "mmsg - MangoWC IPC\n"
"\t%s [-OTLq]\n" "\n"
"\t%s [-o <output>] -s [-t <tags>] [-l <layout>] [-c <tags>] [-d " "SYNOPSIS:\n"
"\tmmsg [-OTLq]\n"
"\tmmsg [-o <output>] -s [-t <tags>] [-l <layout>] [-c <tags>] [-d "
"<cmd>,<arg1>,<arg2>,<arg3>,<arg4>,<arg5>]\n" "<cmd>,<arg1>,<arg2>,<arg3>,<arg4>,<arg5>]\n"
"\t%s [-o <output>] (-g | -w) [-OotlcvmfxekbA]\n", "\tmmsg [-o <output>] (-g | -w) [-OotlcvmfxekbA]\n"
argv0, argv0, argv0); "\n"
"OPERATION MODES:\n"
"\t-g Get values (tags, layout, focused client)\n"
"\t-s Set values (switch tags, layouts)\n"
"\t-w Watch mode (stream events)\n"
"\n"
"GENERAL OPTIONS:\n"
"\t-O Get all output (monitor) information\n"
"\t-T Get number of tags\n"
"\t-L Get all available layouts\n"
"\t-q Quit MangoWC\n"
"\t-o <output> Select output (monitor)\n"
"\n"
"GET OPTIONS (used with -g or -w):\n"
"\t-O Get output name\n"
"\t-o Get output (monitor) focus information\n"
"\t-t Get selected tags\n"
"\t-l Get current layout\n"
"\t-c Get title and appid of focused clients\n"
"\t-v Get visibility of statusbar\n"
"\t-m Get fullscreen status\n"
"\t-f Get floating status\n"
"\t-x Get focused client geometry\n"
"\t-e Get name of last focused layer\n"
"\t-k Get current keyboard layout\n"
"\t-b Get current keybind mode\n"
"\t-A Get scale factor of monitor\n"
"\n"
"SET OPTIONS (used with -s):\n"
"\t-o <output> Select output (monitor)\n"
"\t-t <tags> Set selected tags (can be used with [+-^.] "
"modifiers)\n"
"\t-l <layout> Set current layout\n"
"\t-c <tags> Get title and appid of focused client\n"
"\t-d <cmd>,<args...> Dispatch internal command (max 5 args)\n");
exit(2); exit(2);
} }

View file

@ -89,6 +89,7 @@ typedef struct {
int32_t isterm; int32_t isterm;
int32_t allow_csd; int32_t allow_csd;
int32_t force_maximize; int32_t force_maximize;
int32_t force_tiled_state;
int32_t force_tearing; int32_t force_tearing;
int32_t noswallow; int32_t noswallow;
int32_t noblur; int32_t noblur;
@ -102,6 +103,7 @@ typedef struct {
typedef struct { typedef struct {
const char *name; // Monitor name const char *name; // Monitor name
char *make, *model, *serial; // may be NULL
int32_t rr; // Rotate and flip (assume integer) int32_t rr; // Rotate and flip (assume integer)
float scale; // Monitor scale factor float scale; // Monitor scale factor
int32_t x, y; // Monitor position int32_t x, y; // Monitor position
@ -157,6 +159,9 @@ typedef struct {
int32_t id; int32_t id;
char *layout_name; char *layout_name;
char *monitor_name; char *monitor_name;
char *monitor_make;
char *monitor_model;
char *monitor_serial;
float mfact; float mfact;
int32_t nmaster; int32_t nmaster;
int32_t no_render_border; int32_t no_render_border;
@ -362,7 +367,7 @@ typedef struct {
typedef int32_t (*FuncType)(const Arg *); typedef int32_t (*FuncType)(const Arg *);
Config config; Config config;
void parse_config_file(Config *config, const char *file_path); bool parse_config_file(Config *config, const char *file_path, bool must_exist);
// Helper function to trim whitespace from start and end of a string // Helper function to trim whitespace from start and end of a string
void trim_whitespace(char *str) { void trim_whitespace(char *str) {
@ -1774,6 +1779,9 @@ bool parse_option(Config *config, char *key, char *value) {
// 设置默认值 // 设置默认值
rule->name = NULL; rule->name = NULL;
rule->make = NULL;
rule->model = NULL;
rule->serial = NULL;
rule->rr = 0; rule->rr = 0;
rule->scale = 1.0f; rule->scale = 1.0f;
rule->x = INT32_MAX; rule->x = INT32_MAX;
@ -1797,6 +1805,12 @@ bool parse_option(Config *config, char *key, char *value) {
if (strcmp(key, "name") == 0) { if (strcmp(key, "name") == 0) {
rule->name = strdup(val); rule->name = strdup(val);
} else if (strcmp(key, "make") == 0) {
rule->make = strdup(val);
} else if (strcmp(key, "model") == 0) {
rule->model = strdup(val);
} else if (strcmp(key, "serial") == 0) {
rule->serial = strdup(val);
} else if (strcmp(key, "rr") == 0) { } else if (strcmp(key, "rr") == 0) {
rule->rr = CLAMP_INT(atoi(val), 0, 7); rule->rr = CLAMP_INT(atoi(val), 0, 7);
} else if (strcmp(key, "scale") == 0) { } else if (strcmp(key, "scale") == 0) {
@ -1845,6 +1859,9 @@ bool parse_option(Config *config, char *key, char *value) {
rule->id = 0; rule->id = 0;
rule->layout_name = NULL; rule->layout_name = NULL;
rule->monitor_name = NULL; rule->monitor_name = NULL;
rule->monitor_make = NULL;
rule->monitor_model = NULL;
rule->monitor_serial = NULL;
rule->nmaster = 0; rule->nmaster = 0;
rule->mfact = 0.0f; rule->mfact = 0.0f;
rule->no_render_border = 0; rule->no_render_border = 0;
@ -1868,6 +1885,12 @@ bool parse_option(Config *config, char *key, char *value) {
rule->layout_name = strdup(val); rule->layout_name = strdup(val);
} else if (strcmp(key, "monitor_name") == 0) { } else if (strcmp(key, "monitor_name") == 0) {
rule->monitor_name = strdup(val); rule->monitor_name = strdup(val);
} else if (strcmp(key, "monitor_make") == 0) {
rule->monitor_make = strdup(val);
} else if (strcmp(key, "monitor_model") == 0) {
rule->monitor_model = strdup(val);
} else if (strcmp(key, "monitor_serial") == 0) {
rule->monitor_serial = strdup(val);
} else if (strcmp(key, "no_render_border") == 0) { } else if (strcmp(key, "no_render_border") == 0) {
rule->no_render_border = CLAMP_INT(atoi(val), 0, 1); rule->no_render_border = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "no_hide") == 0) { } else if (strcmp(key, "no_hide") == 0) {
@ -1989,6 +2012,7 @@ bool parse_option(Config *config, char *key, char *value) {
rule->isterm = -1; rule->isterm = -1;
rule->allow_csd = -1; rule->allow_csd = -1;
rule->force_maximize = -1; rule->force_maximize = -1;
rule->force_tiled_state = -1;
rule->force_tearing = -1; rule->force_tearing = -1;
rule->noswallow = -1; rule->noswallow = -1;
rule->noblur = -1; rule->noblur = -1;
@ -2101,6 +2125,8 @@ bool parse_option(Config *config, char *key, char *value) {
rule->allow_csd = atoi(val); rule->allow_csd = atoi(val);
} else if (strcmp(key, "force_maximize") == 0) { } else if (strcmp(key, "force_maximize") == 0) {
rule->force_maximize = atoi(val); rule->force_maximize = atoi(val);
} else if (strcmp(key, "force_tiled_state") == 0) {
rule->force_tiled_state = atoi(val);
} else if (strcmp(key, "force_tearing") == 0) { } else if (strcmp(key, "force_tearing") == 0) {
rule->force_tearing = atoi(val); rule->force_tearing = atoi(val);
} else if (strcmp(key, "noswallow") == 0) { } else if (strcmp(key, "noswallow") == 0) {
@ -2359,6 +2385,17 @@ bool parse_option(Config *config, char *key, char *value) {
binding->arg.v = NULL; binding->arg.v = NULL;
binding->arg.v2 = NULL; binding->arg.v2 = NULL;
binding->arg.v3 = NULL; binding->arg.v3 = NULL;
// TODO: remove this in next version
if (binding->mod == 0 &&
(binding->button == BTN_LEFT || binding->button == BTN_RIGHT)) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m \033[31m%s\033[33m can't "
"bind to \033[31m%s\033[33m mod key\n",
button_str, mod_str);
return false;
}
binding->func = binding->func =
parse_func_name(func_name, &binding->arg, arg_value, arg_value2, parse_func_name(func_name, &binding->arg, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5); arg_value3, arg_value4, arg_value5);
@ -2376,6 +2413,7 @@ bool parse_option(Config *config, char *key, char *value) {
free(binding->arg.v3); free(binding->arg.v3);
binding->arg.v3 = NULL; binding->arg.v3 = NULL;
} }
if (!binding->func) if (!binding->func)
fprintf(stderr, fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Unknown " "\033[1m\033[31m[ERROR]:\033[33m Unknown "
@ -2610,8 +2648,10 @@ bool parse_option(Config *config, char *key, char *value) {
config->gesture_bindings_count++; config->gesture_bindings_count++;
} }
} else if (strncmp(key, "source-optional", 15) == 0) {
parse_config_file(config, value, false);
} else if (strncmp(key, "source", 6) == 0) { } else if (strncmp(key, "source", 6) == 0) {
parse_config_file(config, value); parse_config_file(config, value, true);
} else { } else {
fprintf(stderr, fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Unknown keyword: " "\033[1m\033[31m[ERROR]:\033[33m Unknown keyword: "
@ -2639,7 +2679,7 @@ bool parse_config_line(Config *config, const char *line) {
return parse_option(config, key, value); return parse_option(config, key, value);
} }
void parse_config_file(Config *config, const char *file_path) { bool parse_config_file(Config *config, const char *file_path, bool must_exist) {
FILE *file; FILE *file;
char full_path[1024]; char full_path[1024];
@ -2658,7 +2698,7 @@ void parse_config_file(Config *config, const char *file_path) {
fprintf(stderr, fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m HOME environment " "\033[1m\033[31m[ERROR]:\033[33m HOME environment "
"variable not set.\n"); "variable not set.\n");
return; return false;
} }
snprintf(full_path, sizeof(full_path), "%s/.config/mango/%s", home, snprintf(full_path, sizeof(full_path), "%s/.config/mango/%s", home,
file_path + 1); file_path + 1);
@ -2673,7 +2713,7 @@ void parse_config_file(Config *config, const char *file_path) {
if (!home) { if (!home) {
fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m HOME environment " fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m HOME environment "
"variable not set.\n"); "variable not set.\n");
return; return false;
} }
snprintf(full_path, sizeof(full_path), "%s%s", home, file_path + 1); snprintf(full_path, sizeof(full_path), "%s%s", home, file_path + 1);
file = fopen(full_path, "r"); file = fopen(full_path, "r");
@ -2684,23 +2724,29 @@ void parse_config_file(Config *config, const char *file_path) {
} }
if (!file) { if (!file) {
if (must_exist) {
fprintf(stderr, fprintf(stderr,
"\033[1;31m\033[1;33m[ERROR]:\033[0m Failed to open " "\033[1;31m\033[1;33m[ERROR]:\033[0m Failed to open "
"config file: %s\n", "config file: %s\n",
file_path); file_path);
return; return false;
} else {
return true;
}
} }
char line[512]; char line[512];
bool parse_correct = true; bool parse_correct = true;
bool parse_line_correct = true;
uint32_t line_count = 0; uint32_t line_count = 0;
while (fgets(line, sizeof(line), file)) { while (fgets(line, sizeof(line), file)) {
line_count++; line_count++;
if (line[0] == '#' || line[0] == '\n') { if (line[0] == '#' || line[0] == '\n') {
continue; continue;
} }
parse_correct = parse_config_line(config, line); parse_line_correct = parse_config_line(config, line);
if (!parse_correct) { if (!parse_line_correct) {
parse_correct = false;
fprintf(stderr, fprintf(stderr,
"\033[1;31m╰─\033[1;33m[Index]\033[0m " "\033[1;31m╰─\033[1;33m[Index]\033[0m "
"\033[1;36m%s\033[0m:\033[1;35m%d\033[0m\n" "\033[1;36m%s\033[0m:\033[1;35m%d\033[0m\n"
@ -2710,6 +2756,7 @@ void parse_config_file(Config *config, const char *file_path) {
} }
fclose(file); fclose(file);
return parse_correct;
} }
void free_circle_layout(Config *config) { void free_circle_layout(Config *config) {
@ -2904,6 +2951,12 @@ void free_config(void) {
free((void *)config.tag_rules[i].layout_name); free((void *)config.tag_rules[i].layout_name);
if (config.tag_rules[i].monitor_name) if (config.tag_rules[i].monitor_name)
free((void *)config.tag_rules[i].monitor_name); free((void *)config.tag_rules[i].monitor_name);
if (config.tag_rules[i].monitor_make)
free((void *)config.tag_rules[i].monitor_make);
if (config.tag_rules[i].monitor_model)
free((void *)config.tag_rules[i].monitor_model);
if (config.tag_rules[i].monitor_serial)
free((void *)config.tag_rules[i].monitor_serial);
} }
free(config.tag_rules); free(config.tag_rules);
config.tag_rules = NULL; config.tag_rules = NULL;
@ -2915,6 +2968,12 @@ void free_config(void) {
for (int32_t i = 0; i < config.monitor_rules_count; i++) { for (int32_t i = 0; i < config.monitor_rules_count; i++) {
if (config.monitor_rules[i].name) if (config.monitor_rules[i].name)
free((void *)config.monitor_rules[i].name); free((void *)config.monitor_rules[i].name);
if (config.monitor_rules[i].make)
free((void *)config.monitor_rules[i].make);
if (config.monitor_rules[i].model)
free((void *)config.monitor_rules[i].model);
if (config.monitor_rules[i].serial)
free((void *)config.monitor_rules[i].serial);
} }
free(config.monitor_rules); free(config.monitor_rules);
config.monitor_rules = NULL; config.monitor_rules = NULL;
@ -3369,7 +3428,7 @@ void set_default_key_bindings(Config *config) {
config->key_bindings_count += default_key_bindings_count; config->key_bindings_count += default_key_bindings_count;
} }
void parse_config(void) { bool parse_config(void) {
char filename[1024]; char filename[1024];
@ -3422,7 +3481,7 @@ void parse_config(void) {
const char *homedir = getenv("HOME"); const char *homedir = getenv("HOME");
if (!homedir) { if (!homedir) {
// 如果获取失败,则无法继续 // 如果获取失败,则无法继续
return; return false;
} }
// 构建日志文件路径 // 构建日志文件路径
snprintf(filename, sizeof(filename), "%s/.config/mango/config.conf", snprintf(filename, sizeof(filename), "%s/.config/mango/config.conf",
@ -3436,10 +3495,12 @@ void parse_config(void) {
} }
} }
bool parse_correct = true;
set_value_default(); set_value_default();
parse_config_file(&config, filename); parse_correct = parse_config_file(&config, filename, true);
set_default_key_bindings(&config); set_default_key_bindings(&config);
override_config(); override_config();
return parse_correct;
} }
void reset_blur_params(void) { void reset_blur_params(void) {
@ -3477,6 +3538,7 @@ void reapply_monitor_rules(void) {
struct wlr_output_state state; struct wlr_output_state state;
struct wlr_output_mode *internal_mode = NULL; struct wlr_output_mode *internal_mode = NULL;
wlr_output_state_init(&state); wlr_output_state_init(&state);
bool match_rule = false;
wl_list_for_each(m, &mons, link) { wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled) { if (!m->wlr_output->enabled) {
@ -3488,8 +3550,40 @@ void reapply_monitor_rules(void) {
break; break;
mr = &config.monitor_rules[ji]; mr = &config.monitor_rules[ji];
if (regex_match(mr->name, m->wlr_output->name)) {
// 检查是否匹配的变量
match_rule = true;
// 检查四个标识字段的匹配
if (mr->name != NULL) {
if (!regex_match(mr->name, m->wlr_output->name)) {
match_rule = false;
}
}
if (mr->make != NULL) {
if (m->wlr_output->make == NULL ||
strcmp(mr->make, m->wlr_output->make) != 0) {
match_rule = false;
}
}
if (mr->model != NULL) {
if (m->wlr_output->model == NULL ||
strcmp(mr->model, m->wlr_output->model) != 0) {
match_rule = false;
}
}
if (mr->serial != NULL) {
if (m->wlr_output->serial == NULL ||
strcmp(mr->serial, m->wlr_output->serial) != 0) {
match_rule = false;
}
}
// 只有当所有指定的标识都匹配时才应用规则
if (match_rule) {
mx = mr->x == INT32_MAX ? m->m.x : mr->x; mx = mr->x == INT32_MAX ? m->m.x : mr->x;
my = mr->y == INT32_MAX ? m->m.y : mr->y; my = mr->y == INT32_MAX ? m->m.y : mr->y;
vrr = mr->vrr >= 0 ? mr->vrr : 0; vrr = mr->vrr >= 0 ? mr->vrr : 0;
@ -3623,6 +3717,7 @@ void parse_tagrule(Monitor *m) {
int32_t i, jk; int32_t i, jk;
ConfigTagRule tr; ConfigTagRule tr;
Client *c = NULL; Client *c = NULL;
bool match_rule = false;
for (i = 0; i <= LENGTH(tags); i++) { for (i = 0; i <= LENGTH(tags); i++) {
m->pertag->nmasters[i] = default_nmaster; m->pertag->nmasters[i] = default_nmaster;
@ -3633,9 +3728,36 @@ void parse_tagrule(Monitor *m) {
tr = config.tag_rules[i]; tr = config.tag_rules[i];
if (config.tag_rules_count > 0 && match_rule = true;
(!tr.monitor_name ||
regex_match(tr.monitor_name, m->wlr_output->name))) { if (tr.monitor_name != NULL) {
if (!regex_match(tr.monitor_name, m->wlr_output->name)) {
match_rule = false;
}
}
if (tr.monitor_make != NULL) {
if (m->wlr_output->make == NULL ||
strcmp(tr.monitor_make, m->wlr_output->make) != 0) {
match_rule = false;
}
}
if (tr.monitor_model != NULL) {
if (m->wlr_output->model == NULL ||
strcmp(tr.monitor_model, m->wlr_output->model) != 0) {
match_rule = false;
}
}
if (tr.monitor_serial != NULL) {
if (m->wlr_output->serial == NULL ||
strcmp(tr.monitor_serial, m->wlr_output->serial) != 0) {
match_rule = false;
}
}
if (config.tag_rules_count > 0 && match_rule) {
for (jk = 0; jk < LENGTH(layouts); jk++) { for (jk = 0; jk < LENGTH(layouts); jk++) {
if (tr.layout_name && if (tr.layout_name &&

View file

@ -907,9 +907,7 @@ int32_t switch_keyboard_layout(const Arg *arg) {
uint32_t latched = keyboard->modifiers.latched; uint32_t latched = keyboard->modifiers.latched;
uint32_t locked = keyboard->modifiers.locked; uint32_t locked = keyboard->modifiers.locked;
wlr_keyboard_set_keymap(keyboard, keyboard->keymap);
wlr_keyboard_notify_modifiers(keyboard, depressed, latched, locked, next); wlr_keyboard_notify_modifiers(keyboard, depressed, latched, locked, next);
keyboard->modifiers.group = 0;
// 7. 更新 seat // 7. 更新 seat
wlr_seat_set_keyboard(seat, keyboard); wlr_seat_set_keyboard(seat, keyboard);
@ -923,10 +921,7 @@ int32_t switch_keyboard_layout(const Arg *arg) {
struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data; struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data;
wlr_keyboard_set_keymap(tkb, keyboard->keymap);
wlr_keyboard_notify_modifiers(tkb, depressed, latched, locked, next); wlr_keyboard_notify_modifiers(tkb, depressed, latched, locked, next);
tkb->modifiers.group = 0;
// 7. 更新 seat // 7. 更新 seat
wlr_seat_set_keyboard(seat, tkb); wlr_seat_set_keyboard(seat, tkb);
wlr_seat_keyboard_notify_modifiers(seat, &tkb->modifiers); wlr_seat_keyboard_notify_modifiers(seat, &tkb->modifiers);

View file

@ -3,6 +3,7 @@
*/ */
#include "wlr-layer-shell-unstable-v1-protocol.h" #include "wlr-layer-shell-unstable-v1-protocol.h"
#include "wlr/util/box.h" #include "wlr/util/box.h"
#include "wlr/util/edges.h"
#include <getopt.h> #include <getopt.h>
#include <libinput.h> #include <libinput.h>
#include <limits.h> #include <limits.h>
@ -390,6 +391,7 @@ struct Client {
int32_t isterm, noswallow; int32_t isterm, noswallow;
int32_t allow_csd; int32_t allow_csd;
int32_t force_maximize; int32_t force_maximize;
int32_t force_tiled_state;
pid_t pid; pid_t pid;
Client *swallowing, *swallowedby; Client *swallowing, *swallowedby;
bool is_clip_to_hide; bool is_clip_to_hide;
@ -942,6 +944,8 @@ static struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor = {
.notify = handle_keyboard_shortcuts_inhibit_new_inhibitor}; .notify = handle_keyboard_shortcuts_inhibit_new_inhibitor};
#ifdef XWAYLAND #ifdef XWAYLAND
static void fix_xwayland_unmanaged_coordinate(Client *c);
static int32_t synckeymap(void *data);
static void activatex11(struct wl_listener *listener, void *data); static void activatex11(struct wl_listener *listener, void *data);
static void configurex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data);
static void createnotifyx11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data);
@ -953,6 +957,7 @@ static void setgeometrynotify(struct wl_listener *listener, void *data);
static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11};
static struct wl_listener xwayland_ready = {.notify = xwaylandready}; static struct wl_listener xwayland_ready = {.notify = xwaylandready};
static struct wlr_xwayland *xwayland; static struct wlr_xwayland *xwayland;
static struct wl_event_source *sync_keymap;
#endif #endif
#include "animation/client.h" #include "animation/client.h"
@ -1281,6 +1286,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) {
APPLY_INT_PROP(c, r, isterm); APPLY_INT_PROP(c, r, isterm);
APPLY_INT_PROP(c, r, allow_csd); APPLY_INT_PROP(c, r, allow_csd);
APPLY_INT_PROP(c, r, force_maximize); APPLY_INT_PROP(c, r, force_maximize);
APPLY_INT_PROP(c, r, force_tiled_state);
APPLY_INT_PROP(c, r, force_tearing); APPLY_INT_PROP(c, r, force_tearing);
APPLY_INT_PROP(c, r, noswallow); APPLY_INT_PROP(c, r, noswallow);
APPLY_INT_PROP(c, r, nofocus); APPLY_INT_PROP(c, r, nofocus);
@ -1369,6 +1375,14 @@ void applyrules(Client *c) {
Monitor *mon = parent && parent->mon ? parent->mon : selmon; Monitor *mon = parent && parent->mon ? parent->mon : selmon;
c->isfloating = client_is_float_type(c) || parent; c->isfloating = client_is_float_type(c) || parent;
#ifdef XWAYLAND
if (c->isfloating && client_is_x11(c)) {
fix_xwayland_unmanaged_coordinate(c);
c->float_geom = c->geom;
}
#endif
if (!(appid = client_get_appid(c))) if (!(appid = client_get_appid(c)))
appid = broken; appid = broken;
if (!(title = client_get_title(c))) if (!(title = client_get_title(c)))
@ -1996,14 +2010,21 @@ buttonpress(struct wl_listener *listener, void *data) {
if (config.mouse_bindings_count < 1) if (config.mouse_bindings_count < 1)
break; break;
m = &config.mouse_bindings[ji]; m = &config.mouse_bindings[ji];
if (selmon->isoverview && event->button == BTN_LEFT && c) {
toggleoverview(&(Arg){.i = 1});
return;
}
if (selmon->isoverview && event->button == BTN_RIGHT && c) {
pending_kill_client(c);
return;
}
if (CLEANMASK(mods) == CLEANMASK(m->mod) && if (CLEANMASK(mods) == CLEANMASK(m->mod) &&
event->button == m->button && m->func && event->button == m->button && m->func &&
(selmon->isoverview == 1 || m->button == BTN_MIDDLE) && c) { (CLEANMASK(m->mod) != 0 ||
m->func(&m->arg); (event->button != BTN_LEFT && event->button != BTN_RIGHT))) {
return;
} else if (CLEANMASK(mods) == CLEANMASK(m->mod) &&
event->button == m->button && m->func &&
CLEANMASK(m->mod) != 0) {
m->func(&m->arg); m->func(&m->arg);
return; return;
} }
@ -2429,9 +2450,6 @@ void commitnotify(struct wl_listener *listener, void *data) {
setmon(c, NULL, 0, setmon(c, NULL, 0,
true); /* Make sure to reapply rules in mapnotify() */ true); /* Make sure to reapply rules in mapnotify() */
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT |
WLR_EDGE_RIGHT);
uint32_t serial = wlr_xdg_surface_schedule_configure(c->surface.xdg); uint32_t serial = wlr_xdg_surface_schedule_configure(c->surface.xdg);
if (serial > 0) { if (serial > 0) {
c->configure_serial = serial; c->configure_serial = serial;
@ -2728,6 +2746,7 @@ void createmon(struct wl_listener *listener, void *data) {
Monitor *m = NULL; Monitor *m = NULL;
struct wlr_output_mode *internal_mode = NULL; struct wlr_output_mode *internal_mode = NULL;
bool custom_monitor_mode = false; bool custom_monitor_mode = false;
bool match_rule = false;
if (!wlr_output_init_render(wlr_output, alloc, drw)) if (!wlr_output_init_render(wlr_output, alloc, drw))
return; return;
@ -2768,7 +2787,39 @@ void createmon(struct wl_listener *listener, void *data) {
break; break;
r = &config.monitor_rules[ji]; r = &config.monitor_rules[ji];
if (regex_match(r->name, wlr_output->name)) {
// 检查是否匹配的变量
match_rule = true;
// 检查四个标识字段的匹配
if (r->name != NULL) {
if (!regex_match(r->name, m->wlr_output->name)) {
match_rule = false;
}
}
if (r->make != NULL) {
if (m->wlr_output->make == NULL ||
strcmp(r->make, m->wlr_output->make) != 0) {
match_rule = false;
}
}
if (r->model != NULL) {
if (m->wlr_output->model == NULL ||
strcmp(r->model, m->wlr_output->model) != 0) {
match_rule = false;
}
}
if (r->serial != NULL) {
if (m->wlr_output->serial == NULL ||
strcmp(r->serial, m->wlr_output->serial) != 0) {
match_rule = false;
}
}
if (match_rule) {
m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x; m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x;
m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y; m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y;
vrr = r->vrr >= 0 ? r->vrr : 0; vrr = r->vrr >= 0 ? r->vrr : 0;
@ -3419,7 +3470,10 @@ void requestmonstate(struct wl_listener *listener, void *data) {
void inputdevice(struct wl_listener *listener, void *data) { void inputdevice(struct wl_listener *listener, void *data) {
/* This event is raised by the backend when a new input device becomes /* This event is raised by the backend when a new input device becomes
* available. */ * available.
* when the backend is a headless backend, this event will never be
* triggered.
*/
struct wlr_input_device *device = data; struct wlr_input_device *device = data;
uint32_t caps; uint32_t caps;
@ -3490,11 +3544,6 @@ keybinding(uint32_t state, bool locked, uint32_t mods, xkb_keysym_t sym,
int32_t ji; int32_t ji;
int32_t isbreak = 0; int32_t isbreak = 0;
// not allow modifier keys to be used as a keybinding
if (keycode == 50 || keycode == 37 || keycode == 133 || keycode == 64 ||
keycode == 62 || keycode == 108 || keycode == 105 || keycode == 134)
return false;
if (is_keyboard_shortcut_inhibitor(seat->keyboard_state.focused_surface)) { if (is_keyboard_shortcut_inhibitor(seat->keyboard_state.focused_surface)) {
return false; return false;
} }
@ -3816,6 +3865,7 @@ void init_client_properties(Client *c) {
c->isterm = 0; c->isterm = 0;
c->allow_csd = 0; c->allow_csd = 0;
c->force_maximize = 0; c->force_maximize = 0;
c->force_tiled_state = 1;
c->force_tearing = 0; c->force_tearing = 0;
c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE;
c->scroller_proportion_single = 0.0f; c->scroller_proportion_single = 0.0f;
@ -3873,18 +3923,19 @@ mapnotify(struct wl_listener *listener, void *data) {
*/ */
if (client_is_unmanaged(c)) { if (client_is_unmanaged(c)) {
/* Unmanaged clients always are floating */ /* Unmanaged clients always are floating */
#ifdef XWAYLAND
if (client_is_x11(c)) {
fix_xwayland_unmanaged_coordinate(c);
LISTEN(&c->surface.xwayland->events.set_geometry, &c->set_geometry,
setgeometrynotify);
}
#endif
wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]);
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
if (client_wants_focus(c)) { if (client_wants_focus(c)) {
focusclient(c, 1); focusclient(c, 1);
exclusive_focus = c; exclusive_focus = c;
} }
#ifdef XWAYLAND
if (client_is_x11(c)) {
LISTEN(&c->surface.xwayland->events.set_geometry, &c->set_geometry,
setgeometrynotify);
}
#endif
return; return;
} }
@ -3930,8 +3981,10 @@ mapnotify(struct wl_listener *listener, void *data) {
applyrules(c); applyrules(c);
if (!c->isfloating || c->force_tiled_state) {
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT |
WLR_EDGE_RIGHT); WLR_EDGE_RIGHT);
}
// apply buffer effects of client // apply buffer effects of client
wlr_scene_node_for_each_buffer(&c->scene_surface->node, wlr_scene_node_for_each_buffer(&c->scene_surface->node,
@ -4282,8 +4335,8 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
uint32_t time) { uint32_t time) {
struct timespec now; struct timespec now;
if (sloppyfocus && !start_drag_window && c && time && if (sloppyfocus && !start_drag_window && c && time && c->scene &&
c->scene->node.enabled && !c->animation.tagging_in && c->scene->node.enabled && !c->animation.tagining &&
(surface != seat->pointer_state.focused_surface) && (surface != seat->pointer_state.focused_surface) &&
!client_is_unmanaged(c) && VISIBLEON(c, c->mon)) !client_is_unmanaged(c) && VISIBLEON(c, c->mon))
focusclient(c, 0); focusclient(c, 0);
@ -4756,6 +4809,13 @@ setfloating(Client *c, int32_t floating) {
if (!c->force_maximize) if (!c->force_maximize)
client_set_maximized(c, false); client_set_maximized(c, false);
if (!c->isfloating || c->force_tiled_state) {
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT |
WLR_EDGE_RIGHT);
} else {
client_set_tiled(c, WLR_EDGE_NONE);
}
arrange(c->mon, false, false); arrange(c->mon, false, false);
setborder_color(c); setborder_color(c);
printstatus(); printstatus();
@ -5177,7 +5237,7 @@ void setup(void) {
if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) { if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) {
wlr_drm_create(dpy, drw); wlr_drm_create(dpy, drw);
wlr_scene_set_linux_dmabuf_v1( wlr_scene_set_linux_dmabuf_v1(
scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw)); scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw));
} }
if (syncobj_enable && (drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 && if (syncobj_enable && (drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 &&
@ -5324,7 +5384,6 @@ void setup(void) {
&request_set_cursor_shape); &request_set_cursor_shape);
hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy),
hidecursor, cursor); hidecursor, cursor);
/* /*
* Configures a seat, which is a single "seat" at which a user sits and * Configures a seat, which is a single "seat" at which a user sits and
* operates the computer. This conceptually includes up to one keyboard, * operates the computer. This conceptually includes up to one keyboard,
@ -5416,6 +5475,8 @@ void setup(void) {
fprintf(stderr, fprintf(stderr,
"failed to setup XWayland X server, continuing without it\n"); "failed to setup XWayland X server, continuing without it\n");
} }
sync_keymap = wl_event_loop_add_timer(wl_display_get_event_loop(dpy),
synckeymap, NULL);
#endif #endif
} }
@ -5490,6 +5551,9 @@ void overview_backup(Client *c) {
c->ismaximizescreen = 0; c->ismaximizescreen = 0;
} }
c->bw = c->isnoborder ? 0 : borderpx; c->bw = c->isnoborder ? 0 : borderpx;
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT |
WLR_EDGE_RIGHT);
} }
// overview切回到普通视图还原窗口的状态 // overview切回到普通视图还原窗口的状态
@ -5529,6 +5593,10 @@ void overview_restore(Client *c, const Arg *arg) {
!c->isfullscreen) { // 如果是在ov模式中创建的窗口,没有bw记录 !c->isfullscreen) { // 如果是在ov模式中创建的窗口,没有bw记录
c->bw = c->isnoborder ? 0 : borderpx; c->bw = c->isnoborder ? 0 : borderpx;
} }
if (c->isfloating && !c->force_tiled_state) {
client_set_tiled(c, WLR_EDGE_NONE);
}
} }
void handlecursoractivity(void) { void handlecursoractivity(void) {
@ -5973,6 +6041,8 @@ void handle_keyboard_shortcuts_inhibit_new_inhibitor(
void virtualkeyboard(struct wl_listener *listener, void *data) { void virtualkeyboard(struct wl_listener *listener, void *data) {
struct wlr_virtual_keyboard_v1 *kb = data; struct wlr_virtual_keyboard_v1 *kb = data;
/* virtual keyboards shouldn't share keyboard group */ /* virtual keyboards shouldn't share keyboard group */
wlr_seat_set_capabilities(seat,
seat->capabilities | WL_SEAT_CAPABILITY_KEYBOARD);
KeyboardGroup *group = createkeyboardgroup(); KeyboardGroup *group = createkeyboardgroup();
/* Set the keymap to match the group keymap */ /* Set the keymap to match the group keymap */
wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap);
@ -5984,8 +6054,7 @@ void virtualkeyboard(struct wl_listener *listener, void *data) {
} }
void warp_cursor(const Client *c) { void warp_cursor(const Client *c) {
if (cursor->x < c->geom.x || cursor->x > c->geom.x + c->geom.width || if (INSIDEMON(c)) {
cursor->y < c->geom.y || cursor->y > c->geom.y + c->geom.height) {
wlr_cursor_warp_closest(cursor, NULL, c->geom.x + c->geom.width / 2.0, wlr_cursor_warp_closest(cursor, NULL, c->geom.x + c->geom.width / 2.0,
c->geom.y + c->geom.height / 2.0); c->geom.y + c->geom.height / 2.0);
motionnotify(0, NULL, 0, 0, 0, 0); motionnotify(0, NULL, 0, 0, 0, 0);
@ -6003,7 +6072,8 @@ void warp_cursor_to_selmon(Monitor *m) {
void virtualpointer(struct wl_listener *listener, void *data) { void virtualpointer(struct wl_listener *listener, void *data) {
struct wlr_virtual_pointer_v1_new_pointer_event *event = data; struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
struct wlr_input_device *device = &event->new_pointer->pointer.base; struct wlr_input_device *device = &event->new_pointer->pointer.base;
wlr_seat_set_capabilities(seat,
seat->capabilities | WL_SEAT_CAPABILITY_POINTER);
wlr_cursor_attach_input_device(cursor, device); wlr_cursor_attach_input_device(cursor, device);
if (event->suggested_output) if (event->suggested_output)
wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); wlr_cursor_map_input_to_output(cursor, device, event->suggested_output);
@ -6012,6 +6082,26 @@ void virtualpointer(struct wl_listener *listener, void *data) {
} }
#ifdef XWAYLAND #ifdef XWAYLAND
void fix_xwayland_unmanaged_coordinate(Client *c) {
if (!selmon)
return;
// 1. 如果窗口已经在当前活动显示器内,直接返回
if (c->geom.x >= selmon->m.x && c->geom.x < selmon->m.x + selmon->m.width &&
c->geom.y >= selmon->m.y && c->geom.y < selmon->m.y + selmon->m.height)
return;
c->geom = setclient_coordinate_center(c, selmon, c->geom, 0, 0);
}
int32_t synckeymap(void *data) {
reset_keyboard_layout();
// we only need to sync keymap once
wlr_log(WLR_INFO, "timer to synckeymap done");
wl_event_source_timer_update(sync_keymap, 0);
return 0;
}
void activatex11(struct wl_listener *listener, void *data) { void activatex11(struct wl_listener *listener, void *data) {
Client *c = wl_container_of(listener, c, activate); Client *c = wl_container_of(listener, c, activate);
bool need_arrange = false; bool need_arrange = false;
@ -6142,6 +6232,10 @@ void xwaylandready(struct wl_listener *listener, void *data) {
xwayland, xcursor->images[0]->buffer, xcursor->images[0]->width * 4, xwayland, xcursor->images[0]->buffer, xcursor->images[0]->width * 4,
xcursor->images[0]->width, xcursor->images[0]->height, xcursor->images[0]->width, xcursor->images[0]->height,
xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y);
/* xwayland can't auto sync the keymap, so we do it manually
and we need to wait the xwayland completely inited
*/
wl_event_source_timer_update(sync_keymap, 500);
} }
static void setgeometrynotify(struct wl_listener *listener, void *data) { static void setgeometrynotify(struct wl_listener *listener, void *data) {
@ -6168,8 +6262,7 @@ int32_t main(int32_t argc, char *argv[]) {
} else if (c == 'c') { } else if (c == 'c') {
cli_config_path = optarg; cli_config_path = optarg;
} else if (c == 'p') { } else if (c == 'p') {
parse_config(); return parse_config() ? EXIT_SUCCESS : EXIT_FAILURE;
return EXIT_SUCCESS;
} else { } else {
goto usage; goto usage;
} }