mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
Handle 'lost' unmanaged xsurfaces + improve cursor handling
This commit is contained in:
parent
5862b65f89
commit
a2523081e2
6 changed files with 135 additions and 76 deletions
|
|
@ -143,9 +143,6 @@ struct server {
|
|||
struct seat seat;
|
||||
struct wlr_scene *scene;
|
||||
|
||||
/* Tree for all non-layer xdg/xwayland-shell surfaces */
|
||||
struct wlr_scene_tree *view_tree;
|
||||
|
||||
/* cursor interactive */
|
||||
enum input_mode input_mode;
|
||||
struct view *grabbed_view;
|
||||
|
|
@ -157,8 +154,16 @@ struct server {
|
|||
struct view *ssd_focused_view;
|
||||
struct ssd_hover_state ssd_hover_state;
|
||||
|
||||
struct wlr_scene_tree *osd_tree;
|
||||
/* Tree for all non-layer xdg/xwayland-shell surfaces */
|
||||
struct wlr_scene_tree *view_tree;
|
||||
#if HAVE_XWAYLAND
|
||||
/* Tree for unmanaged xsurfaces without initialized view (usually popups) */
|
||||
struct wlr_scene_tree *unmanaged_tree;
|
||||
#endif
|
||||
/* Tree for built in menu */
|
||||
struct wlr_scene_tree *menu_tree;
|
||||
/* Tree for built in OSD / app switcher */
|
||||
struct wlr_scene_tree *osd_tree;
|
||||
|
||||
struct wl_list outputs;
|
||||
struct wl_listener new_output;
|
||||
|
|
@ -415,9 +420,29 @@ bool isfocusable(struct view *view);
|
|||
|
||||
/**
|
||||
* desktop_node_and_view_at - find view and scene_node at (lx, ly)
|
||||
* Note: If node points to layer-surface, view_area will be set
|
||||
* to LAB_SSD_LAYER_SURFACE, if view points to another surface
|
||||
* view_area will be LAB_SSD_CLIENT
|
||||
*
|
||||
* Behavior if node points to a surface:
|
||||
* - If surface is a layer-surface, *view_area will be
|
||||
* set to LAB_SSD_LAYER_SURFACE and view will be NULL.
|
||||
*
|
||||
* - If surface is a 'lost' unmanaged xsurface (one
|
||||
* with a never-mapped parent view), *view_area will
|
||||
* be set to LAB_SSD_UNMANAGED and view will be NULL.
|
||||
*
|
||||
* 'Lost' unmanaged xsurfaces are usually caused by
|
||||
* X11 applications opening popups without setting
|
||||
* the main window as parent. Example: VLC submenus.
|
||||
*
|
||||
* - Any other surface will cause *view_area be set to
|
||||
* LAB_SSD_CLIENT and return the attached view.
|
||||
*
|
||||
* Behavior if node points to internal elements:
|
||||
* - *view_area will be set to the appropiate enum value
|
||||
* and view will be NULL if the node is not part of the SSD.
|
||||
*
|
||||
* If no node is found for the given layout coordinates,
|
||||
* *view_area will be set to LAB_SSD_ROOT and view will be NULL.
|
||||
*
|
||||
*/
|
||||
struct view *desktop_node_and_view_at(struct server *server, double lx,
|
||||
double ly, struct wlr_scene_node **scene_node, double *sx, double *sy,
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ enum ssd_part_type {
|
|||
LAB_SSD_MENU,
|
||||
LAB_SSD_OSD,
|
||||
LAB_SSD_LAYER_SURFACE,
|
||||
LAB_SSD_UNMANAGED,
|
||||
LAB_SSD_END_MARKER
|
||||
};
|
||||
|
||||
|
|
|
|||
103
src/cursor.c
103
src/cursor.c
|
|
@ -12,6 +12,17 @@
|
|||
#include "ssd.h"
|
||||
#include "config/mousebind.h"
|
||||
|
||||
static bool
|
||||
is_surface(enum ssd_part_type view_area)
|
||||
{
|
||||
return view_area == LAB_SSD_CLIENT
|
||||
|| view_area == LAB_SSD_LAYER_SURFACE
|
||||
#if HAVE_XWAYLAND
|
||||
|| view_area == LAB_SSD_UNMANAGED
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
cursor_rebase(struct seat *seat, uint32_t time_msec)
|
||||
{
|
||||
|
|
@ -22,7 +33,7 @@ cursor_rebase(struct seat *seat, uint32_t time_msec)
|
|||
|
||||
desktop_node_and_view_at(seat->server, seat->cursor->x,
|
||||
seat->cursor->y, &node, &sx, &sy, &view_area);
|
||||
if (view_area == LAB_SSD_CLIENT || view_area == LAB_SSD_LAYER_SURFACE) {
|
||||
if (is_surface(view_area)) {
|
||||
surface = wlr_scene_surface_from_node(node)->surface;
|
||||
}
|
||||
|
||||
|
|
@ -198,7 +209,7 @@ process_cursor_motion(struct server *server, uint32_t time)
|
|||
&sx, &sy, &view_area);
|
||||
|
||||
struct wlr_surface *surface = NULL;
|
||||
if (view_area == LAB_SSD_CLIENT || view_area == LAB_SSD_LAYER_SURFACE) {
|
||||
if (is_surface(view_area)) {
|
||||
surface = wlr_scene_surface_from_node(node)->surface;
|
||||
}
|
||||
|
||||
|
|
@ -206,11 +217,9 @@ process_cursor_motion(struct server *server, uint32_t time)
|
|||
uint32_t resize_edges = ssd_resize_edges(view_area);
|
||||
|
||||
/* Set cursor */
|
||||
if (!view) {
|
||||
/* root, etc. */
|
||||
if (view_area == LAB_SSD_ROOT || view_area == LAB_SSD_MENU) {
|
||||
cursor_set(&server->seat, XCURSOR_DEFAULT);
|
||||
} else {
|
||||
if (resize_edges) {
|
||||
} else if (resize_edges) {
|
||||
cursor_name_set_by_server = true;
|
||||
cursor_set(&server->seat,
|
||||
wlr_xcursor_get_resize_name(resize_edges));
|
||||
|
|
@ -219,11 +228,11 @@ process_cursor_motion(struct server *server, uint32_t time)
|
|||
cursor_set(&server->seat, XCURSOR_DEFAULT);
|
||||
cursor_name_set_by_server = true;
|
||||
} else if (cursor_name_set_by_server) {
|
||||
/* window content */
|
||||
/* xdg/xwindow window content */
|
||||
/* layershell or unmanaged */
|
||||
cursor_set(&server->seat, XCURSOR_DEFAULT);
|
||||
cursor_name_set_by_server = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (view_area == LAB_SSD_MENU) {
|
||||
menu_process_cursor_motion(server->menu_current, node);
|
||||
|
|
@ -496,6 +505,13 @@ handle_release_mousebinding(struct view *view, struct server *server,
|
|||
break;
|
||||
}
|
||||
continue;
|
||||
case MOUSE_ACTION_DRAG:
|
||||
if (mousebind->pressed_in_context) {
|
||||
/* Swallow the release event as well as the press one */
|
||||
activated_any = true;
|
||||
activated_any_frame |= mousebind->context == LAB_SSD_FRAME;
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
|
@ -565,6 +581,9 @@ handle_press_mousebinding(struct view *view, struct server *server,
|
|||
* counted as a DOUBLECLICK.
|
||||
*/
|
||||
if (!double_click) {
|
||||
/* Swallow the press event as well as the release one */
|
||||
activated_any = true;
|
||||
activated_any_frame |= mousebind->context == LAB_SSD_FRAME;
|
||||
mousebind->pressed_in_context = true;
|
||||
}
|
||||
continue;
|
||||
|
|
@ -601,7 +620,15 @@ cursor_button(struct wl_listener *listener, void *data)
|
|||
double sx, sy;
|
||||
struct wlr_scene_node *node;
|
||||
enum ssd_part_type view_area = LAB_SSD_NONE;
|
||||
uint32_t resize_edges;
|
||||
uint32_t resize_edges = 0;
|
||||
|
||||
/**
|
||||
* Used in WLR_BUTTON_RELEASED, set on WLR_BUTTON_PRESSED
|
||||
*
|
||||
* Automatically initialized with 0 / false and
|
||||
* checkpatch.pl complains when done manually.
|
||||
*/
|
||||
static bool close_menu;
|
||||
|
||||
/* bindings to the Frame context swallow mouse events if activated */
|
||||
bool triggered_frame_binding = false;
|
||||
|
|
@ -611,7 +638,7 @@ cursor_button(struct wl_listener *listener, void *data)
|
|||
&sx, &sy, &view_area);
|
||||
|
||||
struct wlr_surface *surface = NULL;
|
||||
if (view_area == LAB_SSD_CLIENT || view_area == LAB_SSD_LAYER_SURFACE) {
|
||||
if (is_surface(view_area)) {
|
||||
surface = wlr_scene_surface_from_node(node)->surface;
|
||||
}
|
||||
|
||||
|
|
@ -622,9 +649,17 @@ cursor_button(struct wl_listener *listener, void *data)
|
|||
/* handle _release_ */
|
||||
if (event->state == WLR_BUTTON_RELEASED) {
|
||||
if (server->input_mode == LAB_INPUT_STATE_MENU) {
|
||||
if (close_menu) {
|
||||
if (server->menu_current) {
|
||||
menu_close(server->menu_current);
|
||||
server->menu_current = NULL;
|
||||
}
|
||||
server->input_mode = LAB_INPUT_STATE_PASSTHROUGH;
|
||||
cursor_rebase(&server->seat, event->time_msec);
|
||||
close_menu = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
damage_all_outputs(server);
|
||||
if (server->input_mode != LAB_INPUT_STATE_PASSTHROUGH) {
|
||||
/* Exit interactive move/resize/menu mode. */
|
||||
if (server->grabbed_view == view) {
|
||||
|
|
@ -634,56 +669,33 @@ cursor_button(struct wl_listener *listener, void *data)
|
|||
server->grabbed_view = NULL;
|
||||
}
|
||||
cursor_rebase(&server->seat, event->time_msec);
|
||||
}
|
||||
|
||||
/* Handle _release_ on root window */
|
||||
if (!view) {
|
||||
handle_release_mousebinding(NULL, server, event->button,
|
||||
modifiers, LAB_SSD_ROOT, 0);
|
||||
return;
|
||||
}
|
||||
goto mousebindings;
|
||||
}
|
||||
|
||||
/* Handle _press */
|
||||
if (server->input_mode == LAB_INPUT_STATE_MENU) {
|
||||
if (!server->menu_current) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"on mouse button input_mode STATE_MENU but no current menu");
|
||||
} else if (view_area != LAB_SSD_MENU) {
|
||||
menu_close(server->menu_current);
|
||||
server->menu_current = NULL;
|
||||
} else if (!menu_call_actions(server->menu_current, node)) {
|
||||
/* Action was not successfull, maybe this menu has a submenu */
|
||||
return;
|
||||
if (view_area != LAB_SSD_MENU) {
|
||||
/* We close the menu on release so we don't leak a stray release */
|
||||
close_menu = true;
|
||||
} else if (menu_call_actions(server->menu_current, node)) {
|
||||
/* Action was successfull, may fail if item contains a submenu */
|
||||
close_menu = true;
|
||||
}
|
||||
/* TODO: following causes stray release */
|
||||
/* Maybe add LAB_INPUT_STATE_IGNORE_MOUSE_RELEASE ? */
|
||||
server->input_mode = LAB_INPUT_STATE_PASSTHROUGH;
|
||||
cursor_rebase(&server->seat, event->time_msec);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle _press_ on a layer surface */
|
||||
if (view_area == LAB_SSD_LAYER_SURFACE && surface) {
|
||||
if (!wlr_surface_is_layer_surface(surface)) {
|
||||
return;
|
||||
}
|
||||
if (view_area == LAB_SSD_LAYER_SURFACE) {
|
||||
struct wlr_layer_surface_v1 *layer =
|
||||
wlr_layer_surface_v1_from_wlr_surface(surface);
|
||||
if (layer->current.keyboard_interactive) {
|
||||
seat_set_focus_layer(&server->seat, layer);
|
||||
}
|
||||
wlr_seat_pointer_notify_button(seat->seat, event->time_msec,
|
||||
event->button, event->state);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle _press_ on root window */
|
||||
if (!view) {
|
||||
handle_press_mousebinding(NULL, server,
|
||||
event->button, modifiers, LAB_SSD_ROOT, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (view) {
|
||||
/* Determine closest resize edges in case action is Resize */
|
||||
resize_edges = ssd_resize_edges(view_area);
|
||||
if (!resize_edges) {
|
||||
|
|
@ -692,6 +704,7 @@ cursor_button(struct wl_listener *listener, void *data)
|
|||
resize_edges |= server->seat.cursor->y < view->y + view->h / 2
|
||||
? WLR_EDGE_TOP : WLR_EDGE_BOTTOM;
|
||||
}
|
||||
}
|
||||
|
||||
mousebindings:
|
||||
if (event->state == WLR_BUTTON_RELEASED) {
|
||||
|
|
@ -703,7 +716,7 @@ mousebindings:
|
|||
server, event->button, modifiers,
|
||||
view_area, resize_edges);
|
||||
}
|
||||
if (!triggered_frame_binding) {
|
||||
if (surface && !triggered_frame_binding) {
|
||||
/* Notify client with pointer focus of button press */
|
||||
wlr_seat_pointer_notify_button(seat->seat, event->time_msec,
|
||||
event->button, event->state);
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ desktop_node_and_view_at(struct server *server, double lx, double ly,
|
|||
|
||||
*scene_node = node;
|
||||
if (!node) {
|
||||
*view_area = LAB_SSD_NONE;
|
||||
*view_area = LAB_SSD_ROOT;
|
||||
return NULL;
|
||||
}
|
||||
if (node->type == WLR_SCENE_NODE_SURFACE) {
|
||||
|
|
@ -276,6 +276,12 @@ desktop_node_and_view_at(struct server *server, double lx, double ly,
|
|||
*view_area = LAB_SSD_LAYER_SURFACE;
|
||||
return NULL;
|
||||
}
|
||||
#if HAVE_XWAYLAND
|
||||
if (node->parent == &server->unmanaged_tree->node) {
|
||||
*view_area = LAB_SSD_UNMANAGED;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
struct wlr_scene_node *osd = &server->osd_tree->node;
|
||||
struct wlr_scene_node *menu = &server->menu_tree->node;
|
||||
|
|
|
|||
|
|
@ -224,8 +224,11 @@ server_init(struct server *server)
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
server->view_tree = wlr_scene_tree_create(&server->scene->node);
|
||||
server->osd_tree = wlr_scene_tree_create(&server->scene->node);
|
||||
#if HAVE_XWAYLAND
|
||||
server->unmanaged_tree = wlr_scene_tree_create(&server->scene->node);
|
||||
#endif
|
||||
server->menu_tree = wlr_scene_tree_create(&server->scene->node);
|
||||
server->osd_tree = wlr_scene_tree_create(&server->scene->node);
|
||||
wlr_scene_attach_output_layout(server->scene, server->output_layout);
|
||||
|
||||
/*
|
||||
|
|
@ -406,6 +409,8 @@ server_start(struct server *server)
|
|||
void
|
||||
server_finish(struct server *server)
|
||||
{
|
||||
|
||||
/* TODO: clean up various scene_tree nodes */
|
||||
#if HAVE_XWAYLAND
|
||||
wlr_xwayland_destroy(server->xwayland);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ parent_view(struct server *server, struct wlr_xwayland_surface *surface)
|
|||
}
|
||||
struct view *view;
|
||||
wl_list_for_each(view, &server->views, link) {
|
||||
if (view->surface == s->surface) {
|
||||
if (view->xwayland_surface == s) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
|
@ -59,11 +59,20 @@ unmanaged_handle_map(struct wl_listener *listener, void *data)
|
|||
seat_focus_surface(&unmanaged->server->seat, xsurface->surface);
|
||||
}
|
||||
|
||||
int lx = unmanaged->lx;
|
||||
int ly = unmanaged->ly;
|
||||
struct wlr_scene_node *parent, *node;
|
||||
struct view *view = parent_view(unmanaged->server, xsurface);
|
||||
struct wlr_scene_node *node = wlr_scene_subsurface_tree_create(
|
||||
view->scene_node, xsurface->surface);
|
||||
wlr_scene_node_set_position(node, unmanaged->lx - view->x,
|
||||
unmanaged->ly - view->y);
|
||||
if (!view || !view->scene_tree) {
|
||||
parent = &view->server->unmanaged_tree->node;
|
||||
} else {
|
||||
lx -= view->x;
|
||||
ly -= view->y;
|
||||
parent = &view->scene_tree->node;
|
||||
}
|
||||
/* node will be destroyed automatically once surface is destroyed */
|
||||
node = &wlr_scene_surface_create(parent, xsurface->surface)->node;
|
||||
wlr_scene_node_set_position(node, lx, ly);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue