mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2025-10-31 22:25:29 -04:00
project: Optimize the project structure
This commit is contained in:
parent
9718e87b2d
commit
7eac47b857
9 changed files with 2 additions and 2 deletions
735
src/IM.h
Normal file
735
src/IM.h
Normal file
|
|
@ -0,0 +1,735 @@
|
|||
#ifdef IM
|
||||
#include <assert.h>
|
||||
#include <wlr/types/wlr_text_input_v3.h>
|
||||
#include <wlr/types/wlr_input_method_v2.h>
|
||||
|
||||
#ifdef HANDWRITE
|
||||
#include <handwrite-unstable-v1-protocol.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The relay structure manages the relationship between text-input and
|
||||
* input_method interfaces on a given seat. Multiple text-input interfaces may
|
||||
* be bound to a relay, but at most one will be focused (receiving events) at
|
||||
* a time. At most one input-method interface may be bound to the seat. The
|
||||
* relay manages life cycle of both sides. When both sides are present and
|
||||
* focused, the relay passes messages between them.
|
||||
*
|
||||
* Text input focus is a subset of keyboard focus - if the text-input is
|
||||
* in the focused state, wl_keyboard sent an enter as well. However, having
|
||||
* wl_keyboard focused doesn't mean that text-input will be focused.
|
||||
*/
|
||||
// 这个relay这一层结构嵌套其实在dwl这里没啥用,暴露出结构成员定义作全局变量代码会更清晰,更符合dwl的风格
|
||||
// 但这个代码最初是日本人从sway那边抄过来的,sway的架构比较大,我猜会不会是考虑到会有两个input_method实例才这么定义
|
||||
// 为了考虑万一以后哪个版本要扩充,就保留外层的结构
|
||||
struct dwl_input_method_relay {
|
||||
struct wl_list text_inputs; // dwl_text_input::link
|
||||
struct wlr_input_method_v2 *input_method; // doesn't have to be present
|
||||
|
||||
struct dwl_input_popup *popup;
|
||||
|
||||
struct wl_listener text_input_new;
|
||||
|
||||
struct wl_listener input_method_new;
|
||||
struct wl_listener input_method_commit;
|
||||
struct wl_listener input_method_destroy;
|
||||
struct wl_listener input_method_new_popup_surface;
|
||||
struct wl_listener input_method_grab_keyboard;
|
||||
struct wl_listener input_method_keyboard_grab_destroy;
|
||||
};
|
||||
|
||||
struct dwl_text_input {
|
||||
struct dwl_input_method_relay *relay;
|
||||
|
||||
struct wlr_text_input_v3 *input;
|
||||
// The surface getting seat's focus. Stored for when text-input cannot
|
||||
// be sent an enter event immediately after getting focus, e.g. when
|
||||
// there's no input method available. Cleared once text-input is entered.
|
||||
struct wlr_surface *pending_focused_surface;
|
||||
|
||||
struct wl_list link;
|
||||
|
||||
struct wl_listener pending_focused_surface_destroy;
|
||||
|
||||
struct wl_listener text_input_enable;
|
||||
//struct wl_listener text_input_commit;
|
||||
//struct wl_listener text_input_disable;
|
||||
struct wl_listener text_input_destroy;
|
||||
};
|
||||
|
||||
|
||||
struct dwl_input_popup {
|
||||
struct dwl_input_method_relay *relay;
|
||||
struct wlr_input_popup_surface_v2 *popup_surface;
|
||||
|
||||
//struct wlr_scene_node *scene;
|
||||
struct wlr_scene_tree *scene;
|
||||
//struct wlr_scene_node *scene_surface;
|
||||
struct wlr_scene_tree *scene_surface;
|
||||
|
||||
int x, y;
|
||||
bool visible;
|
||||
|
||||
|
||||
struct wl_listener popup_map;
|
||||
struct wl_listener popup_unmap;
|
||||
struct wl_listener popup_destroy;
|
||||
//struct wl_listener popup_surface_commit;
|
||||
//struct wl_listener focused_surface_unmap;
|
||||
};
|
||||
|
||||
|
||||
void dwl_input_method_relay_init(struct dwl_input_method_relay *relay);
|
||||
// Updates currently focused surface. Surface must belong to the same
|
||||
// seat.
|
||||
void dwl_input_method_relay_set_focus(struct dwl_input_method_relay *relay,
|
||||
struct wlr_surface *surface);
|
||||
|
||||
static void handle_im_grab_keyboard(struct wl_listener *listener, void *data);
|
||||
static void handle_im_keyboard_grab_destroy(struct wl_listener *listener,
|
||||
void *data);
|
||||
static void input_popup_update(struct dwl_input_popup *popup);
|
||||
static struct dwl_text_input *relay_get_focused_text_input(struct dwl_input_method_relay *relay);
|
||||
|
||||
struct wlr_input_method_manager_v2 *input_method_manager;
|
||||
struct wlr_text_input_manager_v3 *text_input_manager;
|
||||
struct dwl_input_method_relay *input_relay;
|
||||
// static int NO_printstatus=0; // i suspect that printstatus will make dwl hang with fcitx5
|
||||
|
||||
#ifdef HANDWRITE
|
||||
static void receive_handwrite_text_from_handwrite_input_app(struct wl_client *client, struct wl_resource *resource, const char *text){
|
||||
struct dwl_text_input *text_input;
|
||||
|
||||
wlr_log(WLR_INFO,"receive_handwrite_text_from_handwrite_input_app called with:%s",text);
|
||||
text_input = relay_get_focused_text_input(input_relay);
|
||||
|
||||
if (text_input){
|
||||
wlr_log(WLR_INFO,"receive_handwrite_text_from_handwrite_input_app will commit %s",text);
|
||||
wlr_text_input_v3_send_commit_string(text_input->input,text);
|
||||
wlr_text_input_v3_send_done(text_input->input);
|
||||
}else wlr_log(WLR_INFO, "no focused text_input for handwrite");
|
||||
}
|
||||
|
||||
const struct zwp_handwrite_v1_interface handwrite_interface_impl = {
|
||||
.send_handwrite_text = receive_handwrite_text_from_handwrite_input_app,
|
||||
};
|
||||
|
||||
// struct wl_client* handwrite_app=NULL;//TODO: multiple handwrite app instance?
|
||||
// void zwp_handwrite_v1_handle_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id){
|
||||
// wlr_log(WLR_INFO,"zwp_handwrite_v1_handle_bind called");
|
||||
// handwrite_app = client;
|
||||
// struct wl_resource *resource = wl_resource_create(client, &zwp_handwrite_v1_interface, zwp_handwrite_v1_interface.version, id);
|
||||
// wl_resource_set_implementation(resource, &handwrite_interface_impl, NULL, NULL);
|
||||
// }
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get keyboard grab of the seat from sway_keyboard if we should forward events
|
||||
* to it.
|
||||
*
|
||||
* Returns NULL if the keyboard is not grabbed by an input method,
|
||||
* or if event is from virtual keyboard
|
||||
*/
|
||||
static struct wlr_input_method_keyboard_grab_v2 *keyboard_get_im_grab(KeyboardGroup* kb) {
|
||||
struct wlr_input_method_v2 *input_method = input_relay->input_method;
|
||||
|
||||
if (!input_method){
|
||||
wlr_log(WLR_DEBUG, "keypress keyboard_get_im_grab return NULL:no input_method");
|
||||
return NULL;
|
||||
} else if (!input_method->keyboard_grab){
|
||||
wlr_log(WLR_DEBUG, "keypress keyboard_get_im_grab return NULL:no input_method->keyboard_grab");
|
||||
return NULL;
|
||||
} else if (kb != kb_group) {
|
||||
wlr_log(WLR_DEBUG, "keypress keyboard_get_im_grab return NULL:virtual_keyboard");
|
||||
return NULL;
|
||||
} else return input_method->keyboard_grab;
|
||||
}
|
||||
|
||||
static void handle_im_grab_keyboard(struct wl_listener *listener, void *data) {
|
||||
struct dwl_input_method_relay *relay = wl_container_of(listener, relay,
|
||||
input_method_grab_keyboard);
|
||||
//wl_container_of 宏的第二个参数sample, 这里是relay,无须是已经初始化的变量,只要是返回值类型的变量就可以了,这里就是dwl_input_method_relay类型的变量
|
||||
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data;
|
||||
|
||||
// send modifier state to grab
|
||||
struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(seat);
|
||||
if (active_keyboard){
|
||||
wlr_log(WLR_INFO,"im_grab_keyboard");
|
||||
wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab,active_keyboard);
|
||||
wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab, &active_keyboard->modifiers);
|
||||
}
|
||||
else
|
||||
wlr_log(WLR_INFO,"im_grab_keyboard but no active keyboard");
|
||||
|
||||
|
||||
wl_signal_add(&keyboard_grab->events.destroy,
|
||||
&relay->input_method_keyboard_grab_destroy);
|
||||
relay->input_method_keyboard_grab_destroy.notify =
|
||||
handle_im_keyboard_grab_destroy;
|
||||
}
|
||||
|
||||
static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, void *data) {
|
||||
struct dwl_input_method_relay *relay = wl_container_of(listener, relay,
|
||||
input_method_keyboard_grab_destroy);
|
||||
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data;
|
||||
wlr_log(WLR_DEBUG,"im_keyboard_grab_destroy");
|
||||
wl_list_remove(&relay->input_method_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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct dwl_text_input *relay_get_focusable_text_input(
|
||||
struct dwl_input_method_relay *relay) {
|
||||
struct dwl_text_input *text_input = NULL;
|
||||
wl_list_for_each(text_input, &relay->text_inputs, link) {
|
||||
if (text_input->pending_focused_surface) {
|
||||
return text_input;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dwl_text_input *relay_get_focused_text_input(
|
||||
struct dwl_input_method_relay *relay) {
|
||||
struct dwl_text_input *text_input = NULL;
|
||||
wl_list_for_each(text_input, &relay->text_inputs, link) {
|
||||
if (text_input->input->focused_surface) {
|
||||
return text_input;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void handle_im_commit(struct wl_listener *listener, void *data) {
|
||||
struct wlr_input_method_v2 *context;
|
||||
|
||||
struct dwl_input_method_relay *relay = wl_container_of(listener, relay,
|
||||
input_method_commit);
|
||||
|
||||
struct dwl_text_input *text_input = relay_get_focused_text_input(relay);
|
||||
if (!text_input) {
|
||||
return;
|
||||
}
|
||||
|
||||
context = data;
|
||||
assert(context == relay->input_method);
|
||||
if (context->current.preedit.text) {
|
||||
wlr_text_input_v3_send_preedit_string(text_input->input,
|
||||
context->current.preedit.text,
|
||||
context->current.preedit.cursor_begin,
|
||||
context->current.preedit.cursor_end);
|
||||
wlr_log(WLR_DEBUG,"preedit_text: %s", context->current.preedit.text);
|
||||
}
|
||||
if (context->current.commit_text) {
|
||||
wlr_text_input_v3_send_commit_string(text_input->input,
|
||||
context->current.commit_text);
|
||||
wlr_log(WLR_DEBUG,"commit_text: %s", context->current.commit_text);
|
||||
}
|
||||
if (context->current.delete.before_length
|
||||
|| context->current.delete.after_length) {
|
||||
wlr_text_input_v3_send_delete_surrounding_text(text_input->input,
|
||||
context->current.delete.before_length,
|
||||
context->current.delete.after_length);
|
||||
}
|
||||
wlr_text_input_v3_send_done(text_input->input);
|
||||
}
|
||||
|
||||
static void text_input_set_pending_focused_surface(
|
||||
struct dwl_text_input *text_input, struct wlr_surface *surface) {
|
||||
wl_list_remove(&text_input->pending_focused_surface_destroy.link);
|
||||
text_input->pending_focused_surface = surface;
|
||||
|
||||
if (surface) {
|
||||
wl_signal_add(&surface->events.destroy,
|
||||
&text_input->pending_focused_surface_destroy);
|
||||
} else {
|
||||
wl_list_init(&text_input->pending_focused_surface_destroy.link);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_im_destroy(struct wl_listener *listener, void *data) {
|
||||
struct dwl_text_input *text_input;
|
||||
|
||||
struct dwl_input_method_relay *relay = wl_container_of(listener, relay,
|
||||
input_method_destroy);
|
||||
struct wlr_input_method_v2 *context = data;
|
||||
wlr_log(WLR_INFO,"IM destroy");
|
||||
assert(context == relay->input_method);
|
||||
|
||||
wl_list_remove(&relay->input_method_commit.link);
|
||||
wl_list_remove(&relay->input_method_grab_keyboard.link);
|
||||
wl_list_remove(&relay->input_method_new_popup_surface.link);
|
||||
wl_list_remove(&relay->input_method_destroy.link);
|
||||
|
||||
relay->input_method = NULL;
|
||||
|
||||
text_input = relay_get_focused_text_input(relay);
|
||||
if (text_input) {
|
||||
// keyboard focus is still there, so keep the surface at hand in case
|
||||
// the input method returns
|
||||
text_input_set_pending_focused_surface(text_input,
|
||||
text_input->input->focused_surface);
|
||||
wlr_text_input_v3_send_leave(text_input->input);
|
||||
}
|
||||
}
|
||||
|
||||
static void relay_send_im_state(struct dwl_input_method_relay *relay,
|
||||
struct wlr_text_input_v3 *input) {
|
||||
struct wlr_input_method_v2 *input_method = relay->input_method;
|
||||
if (!input_method) {
|
||||
wlr_log(WLR_INFO, "Sending IM_DONE but im is gone");
|
||||
return;
|
||||
}
|
||||
// TODO: only send each of those if they were modified
|
||||
wlr_input_method_v2_send_surrounding_text(input_method,
|
||||
input->current.surrounding.text, input->current.surrounding.cursor,
|
||||
input->current.surrounding.anchor);
|
||||
wlr_input_method_v2_send_text_change_cause(input_method,
|
||||
input->current.text_change_cause);
|
||||
wlr_input_method_v2_send_content_type(input_method,
|
||||
input->current.content_type.hint, input->current.content_type.purpose);
|
||||
wlr_input_method_v2_send_done(input_method);
|
||||
// TODO: pass intent, display popup size
|
||||
}
|
||||
|
||||
static void handle_text_input_enable(struct wl_listener *listener, void *data) {
|
||||
struct dwl_text_input *text_input = wl_container_of(listener, text_input,
|
||||
text_input_enable);
|
||||
if (text_input->relay->input_method == NULL) {
|
||||
wlr_log(WLR_INFO, "text_input_enable but input method is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_log(WLR_INFO,"text_input_enable");
|
||||
#ifdef XWAYLAND
|
||||
wlr_input_method_v2_send_activate(text_input->relay->input_method);
|
||||
wlr_log(WLR_INFO,"input_method activate for xwayland");
|
||||
#endif
|
||||
|
||||
relay_send_im_state(text_input->relay, text_input->input);
|
||||
}
|
||||
|
||||
/* static void handle_text_input_commit(struct wl_listener *listener, */
|
||||
/* void *data) { */
|
||||
/* struct dwl_text_input *text_input = wl_container_of(listener, text_input, */
|
||||
/* text_input_commit); */
|
||||
/* if (!text_input->input->current_enabled) { */
|
||||
/* wlr_log(WLR_INFO, "text_input_commit but not enabled"); */
|
||||
/* return; */
|
||||
/* } */
|
||||
/* if (text_input->relay->input_method == NULL) { */
|
||||
/* wlr_log(WLR_INFO, "text_input_commit but input method is NULL"); */
|
||||
/* return; */
|
||||
/* } */
|
||||
/* wlr_log(WLR_DEBUG, "text_input_commit"); */
|
||||
/* relay_send_im_state(text_input->relay, text_input->input); */
|
||||
/* } */
|
||||
|
||||
static void relay_disable_text_input(struct dwl_input_method_relay *relay,
|
||||
struct dwl_text_input *text_input) {
|
||||
if (relay->input_method == NULL) {
|
||||
wlr_log(WLR_INFO, "text_input_disable, but input method is NULL");
|
||||
return;
|
||||
}
|
||||
wlr_log(WLR_INFO,"text_input_disable");
|
||||
|
||||
#ifdef XWAYLAND
|
||||
// https://gitee.com/guyuming76/dwl/commit/59328d6ecbbef1b1cd6e5ea8d90d78ccddd5c263
|
||||
wlr_input_method_v2_send_deactivate(relay->input_method);
|
||||
wlr_log(WLR_INFO,"input_method deactivate for xwayland");
|
||||
#endif
|
||||
//but if you keep the line above while remove the line below, input Chinese in geogebra(xwayland) won't work
|
||||
relay_send_im_state(relay, text_input->input);
|
||||
}
|
||||
|
||||
|
||||
static void handle_text_input_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct dwl_text_input *text_input = wl_container_of(listener, text_input,
|
||||
text_input_destroy);
|
||||
|
||||
if (text_input->input->current_enabled) {
|
||||
wlr_log(WLR_INFO,"text_input_destroy when still enabled");
|
||||
relay_disable_text_input(text_input->relay, text_input);
|
||||
}
|
||||
else {
|
||||
wlr_log(WLR_INFO,"text_input_destroy");
|
||||
}
|
||||
|
||||
text_input_set_pending_focused_surface(text_input, NULL);
|
||||
//wl_list_remove(&text_input->text_input_commit.link);
|
||||
wl_list_remove(&text_input->text_input_destroy.link);
|
||||
//wl_list_remove(&text_input->text_input_disable.link);
|
||||
wl_list_remove(&text_input->text_input_enable.link);
|
||||
wl_list_remove(&text_input->link);
|
||||
free(text_input);
|
||||
}
|
||||
|
||||
static void handle_pending_focused_surface_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct dwl_text_input *text_input = wl_container_of(listener, text_input,
|
||||
pending_focused_surface_destroy);
|
||||
struct wlr_surface *surface = data;
|
||||
assert(text_input->pending_focused_surface == surface);
|
||||
text_input->pending_focused_surface = NULL;
|
||||
wl_list_remove(&text_input->pending_focused_surface_destroy.link);
|
||||
wl_list_init(&text_input->pending_focused_surface_destroy.link);
|
||||
}
|
||||
|
||||
|
||||
static void relay_handle_text_input_new(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct dwl_input_method_relay *relay = wl_container_of(listener, relay,
|
||||
text_input_new);
|
||||
struct wlr_text_input_v3 *wlr_text_input = data;
|
||||
if (seat != wlr_text_input->seat) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct dwl_text_input *input;
|
||||
input = calloc(1, sizeof(*input));
|
||||
if (!input) {
|
||||
wlr_log(WLR_ERROR, "dwl_text_input calloc failed");
|
||||
return;
|
||||
}
|
||||
wlr_log(WLR_INFO, "dwl_text_input calloc");
|
||||
input->input = wlr_text_input;
|
||||
input->relay = relay;
|
||||
|
||||
wl_list_insert(&relay->text_inputs, &input->link);
|
||||
|
||||
input->text_input_enable.notify = handle_text_input_enable;
|
||||
wl_signal_add(&wlr_text_input->events.enable, &input->text_input_enable);
|
||||
|
||||
//input->text_input_commit.notify = handle_text_input_commit;
|
||||
//wl_signal_add(&text_input->events.commit, &input->text_input_commit);
|
||||
|
||||
/* input->text_input_disable.notify = handle_text_input_disable; */
|
||||
/* wl_signal_add(&text_input->events.disable, &input->text_input_disable); */
|
||||
|
||||
input->text_input_destroy.notify = handle_text_input_destroy;
|
||||
wl_signal_add(&wlr_text_input->events.destroy, &input->text_input_destroy);
|
||||
|
||||
input->pending_focused_surface_destroy.notify =
|
||||
handle_pending_focused_surface_destroy;
|
||||
wl_list_init(&input->pending_focused_surface_destroy.link);
|
||||
}
|
||||
|
||||
|
||||
static LayerSurface* layer_surface_from_wlr_layer_surface_v1(
|
||||
struct wlr_layer_surface_v1* layer_surface) {
|
||||
return layer_surface->data;
|
||||
}
|
||||
|
||||
|
||||
static void get_parent_and_output_box(struct wlr_surface *focused_surface,
|
||||
struct wlr_box *parent, struct wlr_box *output_box) {
|
||||
struct wlr_output *output;
|
||||
struct wlr_box output_box_tmp;
|
||||
struct wlr_layer_surface_v1 *layer_surface;
|
||||
|
||||
if ((layer_surface=wlr_layer_surface_v1_try_from_wlr_surface(focused_surface))) {
|
||||
LayerSurface* layer =
|
||||
layer_surface_from_wlr_layer_surface_v1(layer_surface);
|
||||
output = layer->layer_surface->output;
|
||||
wlr_output_layout_get_box(output_layout, output,&output_box_tmp);
|
||||
*parent = layer->geom;
|
||||
parent->x += output_box_tmp.x;
|
||||
parent->y += output_box_tmp.y;
|
||||
wlr_log(WLR_INFO,"get_parent_and_output_box layersurface output_box_tmp->x %d y %d",output_box_tmp.x, output_box_tmp.y);
|
||||
wlr_log(WLR_INFO,"get_parent_and_output_box layersurface parent->x %d y %d",parent->x,parent->y);
|
||||
} else {
|
||||
//Client *client = client_from_wlr_surface(focused_surface);
|
||||
Client *client = NULL;
|
||||
LayerSurface *l = NULL;
|
||||
toplevel_from_wlr_surface(focused_surface, &client, &l);
|
||||
|
||||
output = wlr_output_layout_output_at(output_layout,
|
||||
client->geom.x, client->geom.y);
|
||||
wlr_output_layout_get_box(output_layout, output,&output_box_tmp);
|
||||
|
||||
parent->x = client->geom.x + client->bw;
|
||||
parent->y = client->geom.y + client->bw;
|
||||
parent->width = client->geom.width;
|
||||
parent->height = client->geom.height;
|
||||
wlr_log(WLR_INFO,"get_parent_and_output_box client output_box_tmp->x %d y %d",output_box_tmp.x, output_box_tmp.y);
|
||||
wlr_log(WLR_INFO,"get_parent_and_output_box client client->geom.x %d y %d",client->geom.x,client->geom.y);
|
||||
wlr_log(WLR_INFO,"get_parent_and_output_box client client->bw %d",client->bw);
|
||||
wlr_log(WLR_INFO,"get_parent_and_output_box client parent->x %d y %d",parent->x,parent->y);
|
||||
}
|
||||
|
||||
//*output_box = output_box_tmp;
|
||||
memcpy(output_box,&output_box_tmp,sizeof(struct wlr_box));
|
||||
wlr_log(WLR_INFO,"get_parent_and_output_box output_box x %d y %d width %d height %d",output_box->x,output_box->y,output_box->width,output_box->height);
|
||||
}
|
||||
|
||||
// 如果当前focused wlr_text_input_v3.features 满足 WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE, 不含这个feature就弹出在父窗口左上角
|
||||
// 根据 wlr_text_input_v3.current.cursor_rectangle 计算出一个wlr_box
|
||||
// 再调用 wlr_input_popup_surface_v2_send_text_input_rectangle 和 wlr_scene_node_set_position
|
||||
static void input_popup_update(struct dwl_input_popup *popup) {
|
||||
struct wlr_surface* focused_surface;
|
||||
struct wlr_box output_box, parent, cursor;
|
||||
int x1, x2, y1, y2, x, y, available_right, available_left, available_down,
|
||||
available_up, popup_width, popup_height;
|
||||
bool cursor_rect, x1_in_bounds, y1_in_bounds, x2_in_bounds, y2_in_bounds;
|
||||
|
||||
struct dwl_text_input *text_input =
|
||||
relay_get_focused_text_input(popup->relay);
|
||||
if (!text_input|| !text_input->input->focused_surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: https://gitlab.freedesktop.org/wlroots/wlroots/-/commit/743da5c0ae723098fe772aadb93810f60e700ab9
|
||||
|
||||
if (!popup->popup_surface->surface->mapped) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor_rect = text_input->input->current.features
|
||||
& WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE;
|
||||
|
||||
focused_surface = text_input->input->focused_surface;
|
||||
cursor = text_input->input->current.cursor_rectangle;
|
||||
|
||||
get_parent_and_output_box(focused_surface, &parent, &output_box);
|
||||
|
||||
popup_width = popup->popup_surface->surface->current.width;
|
||||
popup_height = popup->popup_surface->surface->current.height;
|
||||
|
||||
if (!cursor_rect) {
|
||||
cursor.x = 0;
|
||||
cursor.y = 0;
|
||||
cursor.width = parent.width;
|
||||
cursor.height = parent.height;
|
||||
wlr_log(WLR_INFO,"input_popup_update !cursor_rect");
|
||||
|
||||
popup->x=parent.x;
|
||||
popup->y=parent.y;
|
||||
popup->visible=true;
|
||||
}
|
||||
else {
|
||||
wlr_log(WLR_INFO,"input_popup_update cursor x %d y %d width %d height %d",cursor.x,cursor.y,cursor.width,cursor.height);
|
||||
|
||||
x1 = parent.x + cursor.x;
|
||||
x2 = parent.x + cursor.x + cursor.width;
|
||||
y1 = parent.y + cursor.y;
|
||||
y2 = parent.y + cursor.y + cursor.height;
|
||||
x = x1;
|
||||
y = y2;
|
||||
|
||||
wlr_log(WLR_INFO,"input_popup_update x1 %d x2 %d y1 %d y2 %d; x %d y %d",x1,x2,y1,y2,x,y);
|
||||
available_right = output_box.x + output_box.width - x1;
|
||||
available_left = x2 - output_box.x;
|
||||
if (available_right < popup_width && available_left > available_right) {
|
||||
x = x2 - popup_width;
|
||||
wlr_log(WLR_INFO,"input_popup_update available_left %d popup_width %d available_right %d; x %d",available_left,popup_width,available_right,x);
|
||||
}
|
||||
|
||||
available_down = output_box.y + output_box.height - y2;
|
||||
available_up = y1 - output_box.y;
|
||||
if (available_down < popup_height && available_up > available_down) {
|
||||
y = y1 - popup_height;
|
||||
wlr_log(WLR_INFO,"input_popup_update available up %d popup_height %d available_down %d; y %d",available_up,popup_height,available_down,y);
|
||||
}
|
||||
|
||||
popup->x = x;
|
||||
popup->y = y;
|
||||
|
||||
// Hide popup if cursor position is completely out of bounds
|
||||
x1_in_bounds = (cursor.x >= 0 && cursor.x < parent.width);
|
||||
y1_in_bounds = (cursor.y >= 0 && cursor.y < parent.height);
|
||||
x2_in_bounds = (cursor.x + cursor.width >= 0
|
||||
&& cursor.x + cursor.width < parent.width);
|
||||
y2_in_bounds = (cursor.y + cursor.height >= 0
|
||||
&& cursor.y + cursor.height < parent.height);
|
||||
popup->visible =
|
||||
(x1_in_bounds && y1_in_bounds) || (x2_in_bounds && y2_in_bounds);
|
||||
|
||||
struct wlr_box box = {
|
||||
.x = x1 - x,
|
||||
.y = y1 - y,
|
||||
.width = cursor.width,
|
||||
.height = cursor.height,
|
||||
};
|
||||
wlr_input_popup_surface_v2_send_text_input_rectangle(
|
||||
popup->popup_surface, &box);
|
||||
wlr_log(WLR_INFO,"input_popup_update send_text_input_rect box.x %d box.y %d",box.x,box.y);
|
||||
|
||||
}
|
||||
|
||||
wlr_log(WLR_INFO,"input_popup_update x %d y %d visible %s",popup->x,popup->y,popup->visible?"true":"false");
|
||||
wlr_scene_node_set_position(&popup->scene->node, popup->x, popup->y);
|
||||
}
|
||||
|
||||
static void handle_im_popup_map(struct wl_listener *listener, void *data) {
|
||||
struct dwl_input_popup *popup =
|
||||
wl_container_of(listener, popup, popup_map);
|
||||
|
||||
wlr_log(WLR_INFO, "IM_popup_map");
|
||||
|
||||
//popup->scene = &wlr_scene_tree_create(layers[LyrIMPopup])->node;
|
||||
popup->scene = wlr_scene_tree_create(layers[LyrIMPopup]);
|
||||
popup->scene_surface = wlr_scene_subsurface_tree_create(popup->scene,popup->popup_surface->surface);
|
||||
//popup->scene_surface = &wlr_scene_subsurface_tree_create(popup->scene->parent,popup->popup_surface->surface)->node;
|
||||
//popup->scene_surface->data = popup;
|
||||
popup->scene_surface->node.data = popup;
|
||||
|
||||
input_popup_update(popup);
|
||||
|
||||
//wlr_scene_node_set_position(popup->scene, popup->x, popup->y);
|
||||
}
|
||||
|
||||
static void handle_im_popup_unmap(struct wl_listener *listener, void *data) {
|
||||
struct dwl_input_popup *popup =
|
||||
wl_container_of(listener, popup, popup_unmap);
|
||||
//input_popup_update(popup);
|
||||
|
||||
wlr_log(WLR_INFO,"im_popup_unmap");
|
||||
wlr_scene_node_destroy(&popup->scene->node);
|
||||
}
|
||||
|
||||
static void handle_im_popup_destroy(struct wl_listener *listener, void *data) {
|
||||
struct dwl_input_method_relay *relay;
|
||||
struct dwl_input_popup *popup =
|
||||
wl_container_of(listener, popup, popup_destroy);
|
||||
|
||||
wlr_log(WLR_INFO,"im_popup_destroy");
|
||||
|
||||
wl_list_remove(&popup->popup_destroy.link);
|
||||
wl_list_remove(&popup->popup_unmap.link);
|
||||
wl_list_remove(&popup->popup_map.link);
|
||||
|
||||
relay=popup->relay;
|
||||
free(popup->relay->popup);
|
||||
relay->popup=NULL;
|
||||
}
|
||||
|
||||
|
||||
static void handle_im_new_popup_surface(struct wl_listener *listener, void *data) {
|
||||
// struct dwl_text_input* text_input;
|
||||
|
||||
struct dwl_input_method_relay *relay = wl_container_of(listener, relay,
|
||||
input_method_new_popup_surface);
|
||||
struct dwl_input_popup *popup = calloc(1, sizeof(*popup));
|
||||
|
||||
wlr_log(WLR_INFO, "IM_new_popup_surface");
|
||||
relay->popup = popup;
|
||||
|
||||
popup->relay = relay;
|
||||
popup->popup_surface = data;
|
||||
popup->popup_surface->data = popup;
|
||||
|
||||
|
||||
wl_signal_add(&popup->popup_surface->surface->events.map, &popup->popup_map);
|
||||
popup->popup_map.notify = handle_im_popup_map;
|
||||
|
||||
wl_signal_add(&popup->popup_surface->surface->events.unmap, &popup->popup_unmap);
|
||||
popup->popup_unmap.notify = handle_im_popup_unmap;
|
||||
|
||||
wl_signal_add(
|
||||
&popup->popup_surface->events.destroy, &popup->popup_destroy);
|
||||
popup->popup_destroy.notify = handle_im_popup_destroy;
|
||||
}
|
||||
|
||||
|
||||
static void relay_handle_input_method_new(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct dwl_text_input *text_input;
|
||||
|
||||
struct dwl_input_method_relay *relay = wl_container_of(listener, relay,
|
||||
input_method_new);
|
||||
|
||||
struct wlr_input_method_v2 *input_method = data;
|
||||
if (seat != input_method->seat) {
|
||||
wlr_log(WLR_INFO,"input_method_new Seat does not match");
|
||||
return;
|
||||
}
|
||||
|
||||
if (relay->input_method != NULL) {
|
||||
wlr_log(WLR_INFO, "input_method_new Attempted to connect second input method to a seat");
|
||||
wlr_input_method_v2_send_unavailable(input_method);
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_log(WLR_INFO,"input_method_new");
|
||||
|
||||
relay->input_method = input_method;
|
||||
wl_signal_add(&relay->input_method->events.commit,
|
||||
&relay->input_method_commit);
|
||||
relay->input_method_commit.notify = handle_im_commit;
|
||||
wl_signal_add(&relay->input_method->events.new_popup_surface,
|
||||
&relay->input_method_new_popup_surface);
|
||||
relay->input_method_new_popup_surface.notify = handle_im_new_popup_surface;
|
||||
wl_signal_add(&relay->input_method->events.grab_keyboard,
|
||||
&relay->input_method_grab_keyboard);
|
||||
relay->input_method_grab_keyboard.notify = handle_im_grab_keyboard;
|
||||
wl_signal_add(&relay->input_method->events.destroy,
|
||||
&relay->input_method_destroy);
|
||||
relay->input_method_destroy.notify = handle_im_destroy;
|
||||
|
||||
wlr_input_method_v2_send_activate(relay->input_method);
|
||||
|
||||
text_input = relay_get_focusable_text_input(relay);
|
||||
if (text_input) {
|
||||
wlr_text_input_v3_send_enter(text_input->input,
|
||||
text_input->pending_focused_surface);
|
||||
text_input_set_pending_focused_surface(text_input, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void dwl_input_method_relay_init(struct dwl_input_method_relay *relay) {
|
||||
wl_list_init(&relay->text_inputs);
|
||||
|
||||
relay->popup=NULL;
|
||||
|
||||
relay->text_input_new.notify = relay_handle_text_input_new;
|
||||
wl_signal_add(&text_input_manager->events.text_input,
|
||||
&relay->text_input_new);
|
||||
|
||||
relay->input_method_new.notify = relay_handle_input_method_new;
|
||||
wl_signal_add(&input_method_manager->events.input_method,
|
||||
&relay->input_method_new);
|
||||
}
|
||||
|
||||
void dwl_input_method_relay_set_focus(struct dwl_input_method_relay *relay,
|
||||
struct wlr_surface *surface) {
|
||||
struct dwl_text_input *text_input;
|
||||
wl_list_for_each(text_input, &relay->text_inputs, link) {
|
||||
if (text_input->pending_focused_surface) {
|
||||
assert(text_input->input->focused_surface == NULL);
|
||||
if (surface != text_input->pending_focused_surface) {
|
||||
text_input_set_pending_focused_surface(text_input, NULL);
|
||||
}
|
||||
} else if (text_input->input->focused_surface) {
|
||||
assert(text_input->pending_focused_surface == NULL);
|
||||
if (surface != text_input->input->focused_surface) {
|
||||
relay_disable_text_input(relay, text_input);
|
||||
wlr_text_input_v3_send_leave(text_input->input);
|
||||
wlr_log(WLR_INFO, "wlr_text_input_send_leave");
|
||||
} else {
|
||||
wlr_log(WLR_INFO, "IM relay set_focus already focused");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (surface
|
||||
&& wl_resource_get_client(text_input->input->resource)
|
||||
== wl_resource_get_client(surface->resource)) {
|
||||
if (relay->input_method) {
|
||||
wlr_text_input_v3_send_enter(text_input->input, surface);
|
||||
wlr_log(WLR_INFO, "wlr_text_input_send_enter");
|
||||
if (relay->popup) input_popup_update(relay->popup);
|
||||
} else {
|
||||
text_input_set_pending_focused_surface(text_input, surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
416
src/client.h
Normal file
416
src/client.h
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* Attempt to consolidate unavoidable suck into one file, away from dwl.c. This
|
||||
* file is not meant to be pretty. We use a .h file with static inline
|
||||
* functions instead of a separate .c module, or function pointers like sway, so
|
||||
* that they will simply compile out if the chosen #defines leave them unused.
|
||||
*/
|
||||
|
||||
/* Leave these functions first; they're used in the others */
|
||||
static inline int
|
||||
client_is_x11(Client *c)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
return c->type == X11;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct wlr_surface *
|
||||
client_surface(Client *c)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return c->surface.xwayland->surface;
|
||||
#endif
|
||||
return c->surface.xdg->surface;
|
||||
}
|
||||
|
||||
static inline int
|
||||
toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)
|
||||
{
|
||||
struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface;
|
||||
struct wlr_surface *root_surface;
|
||||
struct wlr_layer_surface_v1 *layer_surface;
|
||||
Client *c = NULL;
|
||||
LayerSurface *l = NULL;
|
||||
int type = -1;
|
||||
#ifdef XWAYLAND
|
||||
struct wlr_xwayland_surface *xsurface;
|
||||
#endif
|
||||
|
||||
if (!s)
|
||||
return -1;
|
||||
root_surface = wlr_surface_get_root_surface(s);
|
||||
|
||||
#ifdef XWAYLAND
|
||||
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) {
|
||||
c = xsurface->data;
|
||||
type = c->type;
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) {
|
||||
l = layer_surface->data;
|
||||
type = LayerShell;
|
||||
goto end;
|
||||
}
|
||||
|
||||
xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface);
|
||||
while (xdg_surface) {
|
||||
tmp_xdg_surface = NULL;
|
||||
switch (xdg_surface->role) {
|
||||
case WLR_XDG_SURFACE_ROLE_POPUP:
|
||||
if (!xdg_surface->popup || !xdg_surface->popup->parent)
|
||||
return -1;
|
||||
|
||||
tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
|
||||
|
||||
if (!tmp_xdg_surface)
|
||||
return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl);
|
||||
|
||||
xdg_surface = tmp_xdg_surface;
|
||||
break;
|
||||
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
|
||||
c = xdg_surface->data;
|
||||
type = c->type;
|
||||
goto end;
|
||||
case WLR_XDG_SURFACE_ROLE_NONE:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
if (pl)
|
||||
*pl = l;
|
||||
if (pc)
|
||||
*pc = c;
|
||||
return type;
|
||||
}
|
||||
|
||||
/* The others */
|
||||
static inline void
|
||||
client_activate_surface(struct wlr_surface *s, int activated)
|
||||
{
|
||||
struct wlr_xdg_toplevel *toplevel;
|
||||
#ifdef XWAYLAND
|
||||
struct wlr_xwayland_surface *xsurface;
|
||||
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) {
|
||||
wlr_xwayland_surface_activate(xsurface, activated);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s)))
|
||||
wlr_xdg_toplevel_set_activated(toplevel, activated);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
client_set_bounds(Client *c, int32_t width, int32_t height)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return 0;
|
||||
#endif
|
||||
if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >=
|
||||
XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0
|
||||
&& (c->bounds.width != width || c->bounds.height != height)) {
|
||||
c->bounds.width = width;
|
||||
c->bounds.height = height;
|
||||
return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
client_get_appid(Client *c)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return c->surface.xwayland->class ? c->surface.xwayland->class : "broken";
|
||||
#endif
|
||||
return c->surface.xdg->toplevel->app_id ? c->surface.xdg->toplevel->app_id : "broken";
|
||||
}
|
||||
|
||||
static inline int
|
||||
client_get_pid(Client *c)
|
||||
{
|
||||
pid_t pid;
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return c->surface.xwayland->pid;
|
||||
#endif
|
||||
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
|
||||
return pid;
|
||||
}
|
||||
|
||||
static inline void
|
||||
client_get_clip(Client *c, struct wlr_box *clip)
|
||||
{
|
||||
*clip = (struct wlr_box){
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = c->geom.width - c->bw,
|
||||
.height = c->geom.height - c->bw,
|
||||
};
|
||||
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return;
|
||||
#endif
|
||||
|
||||
clip->x = c->surface.xdg->geometry.x;
|
||||
clip->y = c->surface.xdg->geometry.y;
|
||||
}
|
||||
|
||||
static inline void
|
||||
client_get_geometry(Client *c, struct wlr_box *geom)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c)) {
|
||||
geom->x = c->surface.xwayland->x;
|
||||
geom->y = c->surface.xwayland->y;
|
||||
geom->width = c->surface.xwayland->width;
|
||||
geom->height = c->surface.xwayland->height;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
*geom = c->surface.xdg->geometry;
|
||||
}
|
||||
|
||||
static inline Client *
|
||||
client_get_parent(Client *c)
|
||||
{
|
||||
Client *p = NULL;
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c)) {
|
||||
if (c->surface.xwayland->parent)
|
||||
toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL);
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
if (c->surface.xdg->toplevel->parent)
|
||||
toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline int
|
||||
client_has_children(Client *c)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return !wl_list_empty(&c->surface.xwayland->children);
|
||||
#endif
|
||||
/* surface.xdg->link is never empty because it always contains at least the
|
||||
* surface itself. */
|
||||
return wl_list_length(&c->surface.xdg->link) > 1;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
client_get_title(Client *c)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return c->surface.xwayland->title ? c->surface.xwayland->title : "broken";
|
||||
#endif
|
||||
return c->surface.xdg->toplevel->title ? c->surface.xdg->toplevel->title : "broken";
|
||||
}
|
||||
|
||||
static inline int
|
||||
client_is_float_type(Client *c)
|
||||
{
|
||||
struct wlr_xdg_toplevel *toplevel;
|
||||
struct wlr_xdg_toplevel_state state;
|
||||
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c)) {
|
||||
struct wlr_xwayland_surface *surface = c->surface.xwayland;
|
||||
xcb_size_hints_t *size_hints = surface->size_hints;
|
||||
if (surface->modal)
|
||||
return 1;
|
||||
|
||||
if (wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DIALOG)
|
||||
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH)
|
||||
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLBAR)
|
||||
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
|
||||
&& (size_hints->max_width == size_hints->min_width
|
||||
|| size_hints->max_height == size_hints->min_height);
|
||||
}
|
||||
#endif
|
||||
|
||||
toplevel = c->surface.xdg->toplevel;
|
||||
state = toplevel->current;
|
||||
return toplevel->parent || (state.min_width != 0 && state.min_height != 0
|
||||
&& (state.min_width == state.max_width
|
||||
|| state.min_height == state.max_height));
|
||||
}
|
||||
|
||||
static inline int
|
||||
client_is_rendered_on_mon(Client *c, Monitor *m)
|
||||
{
|
||||
/* This is needed for when you don't want to check formal assignment,
|
||||
* but rather actual displaying of the pixels.
|
||||
* Usually VISIBLEON suffices and is also faster. */
|
||||
struct wlr_surface_output *s;
|
||||
int unused_lx, unused_ly;
|
||||
if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly))
|
||||
return 0;
|
||||
wl_list_for_each(s, &client_surface(c)->current_outputs, link)
|
||||
if (s->output == m->wlr_output)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
client_is_stopped(Client *c)
|
||||
{
|
||||
int pid;
|
||||
siginfo_t in = {0};
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
|
||||
if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) {
|
||||
/* This process is not our child process, while is very unluckely that
|
||||
* it is stopped, in order to do not skip frames assume that it is. */
|
||||
if (errno == ECHILD)
|
||||
return 1;
|
||||
} else if (in.si_pid) {
|
||||
if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
|
||||
return 1;
|
||||
if (in.si_code == CLD_CONTINUED)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
client_is_unmanaged(Client *c)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return c->surface.xwayland->override_redirect;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
|
||||
{
|
||||
if (kb)
|
||||
wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes,
|
||||
kb->num_keycodes, &kb->modifiers);
|
||||
else
|
||||
wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
static inline void
|
||||
client_send_close(Client *c)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c)) {
|
||||
wlr_xwayland_surface_close(c->surface.xwayland);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel);
|
||||
}
|
||||
|
||||
static inline void
|
||||
client_set_border_color(Client *c, const float color[static 4])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; i++)
|
||||
wlr_scene_rect_set_color(c->border[i], color);
|
||||
}
|
||||
|
||||
static inline void
|
||||
client_set_fullscreen(Client *c, int fullscreen)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c)) {
|
||||
wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen);
|
||||
}
|
||||
|
||||
static inline void
|
||||
client_set_scale(struct wlr_surface *s, float scale)
|
||||
{
|
||||
wlr_fractional_scale_v1_notify_scale(s, scale);
|
||||
wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale));
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
client_set_size(Client *c, uint32_t width, uint32_t height)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c)) {
|
||||
wlr_xwayland_surface_configure(c->surface.xwayland,
|
||||
c->geom.x + c->bw, c->geom.y + c->bw, width, height);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if ((int32_t)width == c->surface.xdg->toplevel->current.width
|
||||
&& (int32_t)height == c->surface.xdg->toplevel->current.height)
|
||||
return 0;
|
||||
return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
|
||||
}
|
||||
|
||||
static inline void
|
||||
client_set_tiled(Client *c, uint32_t edges)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c)) {
|
||||
wlr_xwayland_surface_set_maximized(c->surface.xwayland,
|
||||
edges != WLR_EDGE_NONE, edges != WLR_EDGE_NONE);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (wl_resource_get_version(c->surface.xdg->toplevel->resource)
|
||||
>= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
|
||||
wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
|
||||
} else {
|
||||
wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
client_set_suspended(Client *c, int suspended)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return;
|
||||
#endif
|
||||
|
||||
wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
|
||||
}
|
||||
|
||||
static inline int
|
||||
client_wants_focus(Client *c)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
return client_is_unmanaged(c)
|
||||
&& wlr_xwayland_surface_override_redirect_wants_focus(c->surface.xwayland)
|
||||
&& wlr_xwayland_surface_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
client_wants_fullscreen(Client *c)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return c->surface.xwayland->fullscreen;
|
||||
#endif
|
||||
return c->surface.xdg->toplevel->requested.fullscreen;
|
||||
}
|
||||
40
src/dispatch.h
Normal file
40
src/dispatch.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
void minized(const Arg *arg);
|
||||
void restore_minized(const Arg *arg);
|
||||
void toggle_scratchpad(const Arg *arg);
|
||||
void focusdir(const Arg *arg);
|
||||
void toggleoverview(const Arg *arg);
|
||||
void set_proportion(const Arg *arg);
|
||||
void increase_proportion(const Arg *arg);
|
||||
void switch_proportion_preset(const Arg *arg);
|
||||
void zoom(const Arg *arg);
|
||||
void tagsilent(const Arg *arg);
|
||||
void tagtoleft(const Arg *arg);
|
||||
void tagtoright(const Arg *arg);
|
||||
void viewtoleft(const Arg *arg);
|
||||
void viewtoright(const Arg *arg);
|
||||
void viewtoleft_have_client(const Arg *arg);
|
||||
void viewtoright_have_client(const Arg *arg);
|
||||
void togglefloating(const Arg *arg);
|
||||
void togglefullscreen(const Arg *arg);
|
||||
void togglemaxmizescreen(const Arg *arg);
|
||||
void togglegaps(const Arg *arg);
|
||||
void tagmon(const Arg *arg);
|
||||
void spawn(const Arg *arg);
|
||||
void spawn_on_empty(const Arg *arg);
|
||||
void setlayout(const Arg *arg);
|
||||
void switch_layout(const Arg *arg);
|
||||
void setmfact(const Arg *arg);
|
||||
void setsmfact(const Arg *arg);
|
||||
void quit(const Arg *arg);
|
||||
void moveresize(const Arg *arg);
|
||||
void exchange_client(const Arg *arg);
|
||||
void killclient(const Arg *arg);
|
||||
void toggleglobal(const Arg *arg);
|
||||
void incnmaster(const Arg *arg);
|
||||
void incgaps(const Arg *arg);
|
||||
void focusmon(const Arg *arg);
|
||||
void focusstack(const Arg *arg);
|
||||
void chvt(const Arg *arg);
|
||||
void reload_config(const Arg *arg);
|
||||
void movewin(const Arg *arg);
|
||||
void resizewin(const Arg *arg);
|
||||
7466
src/maomao.c
Normal file
7466
src/maomao.c
Normal file
File diff suppressed because it is too large
Load diff
1405
src/parse_config.h
Normal file
1405
src/parse_config.h
Normal file
File diff suppressed because it is too large
Load diff
153
src/preset_config.h
Normal file
153
src/preset_config.h
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/* speedie's maomao config */
|
||||
|
||||
#define COLOR(hex) \
|
||||
{((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f, \
|
||||
((hex >> 8) & 0xFF) / 255.0f, (hex & 0xFF) / 255.0f}
|
||||
|
||||
/* animaion */
|
||||
char *animation_type_open = "slide"; // 是否启用动画 //slide,zoom
|
||||
char *animation_type_close = "slide"; // 是否启用动画 //slide,zoom
|
||||
int animations = 1; // 是否启用动画
|
||||
char animation_fade_in = 1; // Enable animation fade in
|
||||
float zoom_initial_ratio = 0.5; // 动画起始窗口比例
|
||||
float fadein_begin_opacity = 0.5; // Begin opac window ratio for animations
|
||||
float fadeout_begin_opacity = 0.5; // Begin opac window ratio for animations
|
||||
uint32_t animation_duration_move = 500; // Animation move speed
|
||||
uint32_t animation_duration_open = 400; // Animation open speed
|
||||
uint32_t animation_duration_tag = 300; // Animation tag speed
|
||||
uint32_t animation_duration_close = 300; // Animation close speed
|
||||
double animation_curve_move[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线
|
||||
double animation_curve_open[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线
|
||||
double animation_curve_tag[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线
|
||||
double animation_curve_close[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线
|
||||
|
||||
/* appearance */
|
||||
unsigned int axis_bind_apply_timeout = 100; // 滚轮绑定动作的触发的时间间隔
|
||||
unsigned int focus_on_activate = 1; // 收到窗口激活请求是否自动跳转聚焦
|
||||
unsigned int new_is_master = 1; // 新窗口是否插在头部
|
||||
double default_mfact = 0.55f; // master 窗口比例
|
||||
double default_smfact = 0.5f; // 第一个stack窗口比例
|
||||
unsigned int default_nmaster = 1; // 默认master数量
|
||||
/* logging */
|
||||
int log_level = WLR_ERROR;
|
||||
unsigned int numlockon = 1; // 是否打开右边小键盘
|
||||
unsigned int capslock = 0; // 是否启用快捷键
|
||||
|
||||
unsigned int ov_tab_mode = 0; // alt tab切换模式
|
||||
unsigned int hotarea_size = 10; // 热区大小,10x10
|
||||
unsigned int enable_hotarea = 1; // 是否启用鼠标热区
|
||||
int smartgaps = 0; /* 1 means no outer gap when there is only one window */
|
||||
int sloppyfocus = 1; /* focus follows mouse */
|
||||
unsigned int gappih = 5; /* horiz inner gap between windows */
|
||||
unsigned int gappiv = 5; /* vert inner gap between windows */
|
||||
unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */
|
||||
unsigned int gappov = 10; /* vert outer gap between windows and screen edge */
|
||||
|
||||
int scroller_structs = 20;
|
||||
float scroller_default_proportion = 0.9;
|
||||
float scroller_default_proportion_single = 1.0;
|
||||
int scroller_focus_center = 0;
|
||||
int scroller_prefer_center = 0;
|
||||
int focus_cross_monitor = 0;
|
||||
int focus_cross_tag = 0;
|
||||
|
||||
unsigned int swipe_min_threshold = 20;
|
||||
|
||||
|
||||
int bypass_surface_visibility =
|
||||
0; /* 1 means idle inhibitors will disable idle tracking even if it's
|
||||
surface isn't visible */
|
||||
unsigned int borderpx = 4; /* border pixel of windows */
|
||||
float rootcolor[] = COLOR(0x323232ff);
|
||||
float bordercolor[] = COLOR(0x444444ff);
|
||||
float focuscolor[] = COLOR(0xc66b25ff);
|
||||
float maxmizescreencolor[] = COLOR(0x89aa61ff);
|
||||
float urgentcolor[] = COLOR(0xad401fff);
|
||||
float scratchpadcolor[] = COLOR(0x516c93ff);
|
||||
float globalcolor[] = COLOR(0xb153a7ff);
|
||||
// char *cursor_theme = "Bibata-Modern-Ice";
|
||||
|
||||
int overviewgappi = 5; /* overview时 窗口与边缘 缝隙大小 */
|
||||
int overviewgappo = 30; /* overview时 窗口与窗口 缝隙大小 */
|
||||
|
||||
/* To conform the xdg-protocol, set the alpha to zero to restore the old
|
||||
* behavior */
|
||||
float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0};
|
||||
|
||||
int warpcursor = 1; /* Warp cursor to focused client */
|
||||
|
||||
/* layout(s) */
|
||||
Layout overviewlayout = {"", overview, "overview"};
|
||||
|
||||
Layout layouts[] = {
|
||||
// 最少两个,不能删除少于两个
|
||||
/* symbol arrange function name */
|
||||
{"S", scroller, "scroller"}, // 滚动布局
|
||||
{"T", tile, "tile"}, // 堆栈布局
|
||||
{"G", grid, "grid"}, {"M", monocle, "monocle"},
|
||||
{"D", dwindle, "dwindle"}, {"P", spiral, "spiral"},
|
||||
};
|
||||
|
||||
/* keyboard */
|
||||
struct xkb_rule_names xkb_rules = {
|
||||
/* can specify fields: rules, model, layout, variant, options */
|
||||
/* example:
|
||||
.options = "ctrl:nocaps",
|
||||
*/
|
||||
.options = NULL,
|
||||
};
|
||||
|
||||
int repeat_rate = 25;
|
||||
int repeat_delay = 600;
|
||||
|
||||
/* Trackpad */
|
||||
int tap_to_click = 1;
|
||||
int tap_and_drag = 1;
|
||||
int drag_lock = 1;
|
||||
int mouse_natural_scrolling = 0;
|
||||
int trackpad_natural_scrolling = 0;
|
||||
int disable_while_typing = 1;
|
||||
int left_handed = 0;
|
||||
int middle_button_emulation = 0;
|
||||
/* You can choose between:
|
||||
LIBINPUT_CONFIG_SCROLL_NO_SCROLL
|
||||
LIBINPUT_CONFIG_SCROLL_2FG
|
||||
LIBINPUT_CONFIG_SCROLL_EDGE
|
||||
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN
|
||||
*/
|
||||
enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
|
||||
|
||||
/* You can choose between:
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_NONE
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER
|
||||
*/
|
||||
enum libinput_config_click_method click_method =
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
|
||||
|
||||
/* You can choose between:
|
||||
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED
|
||||
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED
|
||||
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE
|
||||
*/
|
||||
uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
|
||||
|
||||
/* You can choose between:
|
||||
LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT
|
||||
LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE
|
||||
*/
|
||||
enum libinput_config_accel_profile accel_profile =
|
||||
LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
|
||||
double accel_speed = 0.0;
|
||||
/* You can choose between:
|
||||
LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle
|
||||
LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right
|
||||
*/
|
||||
enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;
|
||||
|
||||
/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
|
||||
#define MODKEY WLR_MODIFIER_ALT
|
||||
|
||||
static const char *tags[] = {
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
};
|
||||
51
src/util.c
Normal file
51
src/util.c
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/* See LICENSE.dwm file for copyright and license details. */
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
void
|
||||
die(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
|
||||
fputc(' ', stderr);
|
||||
perror(NULL);
|
||||
} else {
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void *
|
||||
ecalloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (!(p = calloc(nmemb, size)))
|
||||
die("calloc:");
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
fd_set_nonblock(int fd) {
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
if (flags < 0) {
|
||||
perror("fcntl(F_GETFL):");
|
||||
return -1;
|
||||
}
|
||||
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
perror("fcntl(F_SETFL):");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
5
src/util.h
Normal file
5
src/util.h
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
/* See LICENSE.dwm file for copyright and license details. */
|
||||
|
||||
void die(const char *fmt, ...);
|
||||
void *ecalloc(size_t nmemb, size_t size);
|
||||
int fd_set_nonblock(int fd);
|
||||
Loading…
Add table
Add a link
Reference in a new issue