Support xwayland window title bar dragging

This commit is contained in:
Johan Malm 2020-05-04 22:21:30 +01:00
parent 4c53bd8bf9
commit 83c3492c87
7 changed files with 109 additions and 42 deletions

View file

@ -13,9 +13,11 @@ ASAN_FLAGS = -O0 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynami
WP = `pkg-config --variable=pkgdatadir wayland-protocols`
WS = `pkg-config --variable=wayland_scanner wayland-scanner`
OBJS = main.o xdg.o view.o xwl.o server.o output.o dbg.o deco.o
all: labwc
labwc: xdg-shell-protocol.o main.o xdg.o view.o xwl.o server.o output.o dbg.o
labwc: xdg-shell-protocol.o $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
xdg-shell-protocol.h:

View file

@ -2,8 +2,6 @@
labwc is a wayland compositor based on wlroots
[https://imgur.com/rb2hJh3](https://imgur.com/rb2hJh3)
## Dependencies
- wlroots
@ -15,7 +13,6 @@ labwc is a wayland compositor based on wlroots
Alt+Escape Exit labwc
Alt+F2 Cycle between windows
Alt+F3 Launch dmenu
Alt+F6 Move window
Alt+F12 Print all views (helpful if run from X11)
```
@ -47,7 +44,7 @@ In terms of size comparison of these two giants, it's worth reflecting on the si
[sway](https://github.com/swaywm/sway) - 37k LOC
[rootston](https://github.com/swaywm/wlroots/tree/master/rootston) - 7k LOC
[rootston]() - 7k LOC
[openbox](https://github.com/danakj/openbox) - 53k LOC

39
deco.c Normal file
View file

@ -0,0 +1,39 @@
#include "labwc.h"
struct wlr_box deco_max_extents(struct view *view)
{
struct wlr_box box = {
.x = view->x - XWL_WINDOW_BORDER,
.y = view->y - XWL_TITLEBAR_HEIGHT - XWL_WINDOW_BORDER,
.width = view->surface->current.width + 2 * XWL_WINDOW_BORDER,
.height = view->surface->current.height + XWL_TITLEBAR_HEIGHT +
2 * XWL_WINDOW_BORDER,
};
return box;
}
struct wlr_box deco_box(struct view *view, enum deco_part deco_part)
{
struct wlr_box box = { .x = 0, .y = 0, .width = 0, .height = 0 };
if (!view)
return;
switch (deco_part) {
case LAB_DECO_PART_TOP:
box.x = view->x - XWL_WINDOW_BORDER;
box.y = view->y - XWL_TITLEBAR_HEIGHT - XWL_WINDOW_BORDER;
box.width = view->surface->current.width + 2 * XWL_WINDOW_BORDER;
box.height = XWL_TITLEBAR_HEIGHT + XWL_WINDOW_BORDER;
break;
}
return box;
}
enum deco_part deco_at(struct view *view, double lx, double ly)
{
struct wlr_box box;
box = deco_box(view, LAB_DECO_PART_TOP);
if (wlr_box_contains_point(&box, lx, ly))
return LAB_DECO_PART_TOP;
return LAB_DECO_NONE;
}

13
labwc.h
View file

@ -33,7 +33,6 @@
#define XWL_TITLEBAR_HEIGHT (10)
#define XWL_WINDOW_BORDER (3)
/* For brevity's sake, struct members are annotated where they are used. */
enum cursor_mode {
TINYWL_CURSOR_PASSTHROUGH,
TINYWL_CURSOR_MOVE,
@ -84,6 +83,11 @@ struct output {
enum view_type { LAB_XDG_SHELL_VIEW, LAB_XWAYLAND_VIEW };
enum deco_part {
LAB_DECO_NONE,
LAB_DECO_PART_TOP
};
struct view {
enum view_type type;
struct wl_list link;
@ -131,6 +135,7 @@ void xwl_surface_destroy(struct wl_listener *listener, void *data);
void xwl_surface_configure(struct wl_listener *listener, void *data);
void xwl_surface_new(struct wl_listener *listener, void *data);
bool view_want_deco(struct view *view);
void view_focus_last_toplevel(struct server *server);
void focus_view(struct view *view, struct wlr_surface *surface);
void view_focus_next_toplevel(struct server *server);
@ -139,7 +144,7 @@ void begin_interactive(struct view *view, enum cursor_mode mode,
bool is_toplevel(struct view *view);
struct view *desktop_view_at(struct server *server, double lx, double ly,
struct wlr_surface **surface, double *sx,
double *sy);
double *sy, int *view_area);
/* TODO: try to refactor to remove from header file */
struct view *first_toplevel(struct server *server);
@ -157,4 +162,8 @@ void output_frame(struct wl_listener *listener, void *data);
void dbg_show_views(struct server *server);
struct wlr_box deco_max_extents(struct view *view);
struct wlr_box deco_box(struct view *view, enum deco_part deco_part);
enum deco_part deco_at(struct view *view, double lx, double ly);
#endif /* LABWC_H */

View file

@ -1,9 +1,5 @@
#include "labwc.h"
/*
* Used to move all of the data necessary to render a surface from the
* top-level frame handler to the per-surface render function.
*/
struct render_data {
struct wlr_output *output;
struct wlr_renderer *renderer;
@ -13,32 +9,19 @@ struct render_data {
static void render_decorations(struct wlr_output *output, struct view *view)
{
if (!view->surface)
return;
if (view->type != LAB_XWAYLAND_VIEW)
return;
if (!is_toplevel(view))
return;
if (view->xwayland_surface->override_redirect)
return;
if (view->xwayland_surface->decorations !=
WLR_XWAYLAND_SURFACE_DECORATIONS_ALL)
if (!view_want_deco(view))
return;
struct wlr_box box = {
.x = view->x - XWL_WINDOW_BORDER,
.y = view->y - XWL_TITLEBAR_HEIGHT - XWL_WINDOW_BORDER,
.width = view->surface->current.width + 2 * XWL_WINDOW_BORDER,
.height = view->surface->current.height + XWL_TITLEBAR_HEIGHT +
2 * XWL_WINDOW_BORDER,
};
struct wlr_box box = deco_max_extents(view);
float matrix[9];
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
output->transform_matrix);
float color[] = { 0.2, 0.2, 0.7, 0.9 };
wlr_render_quad_with_matrix(view->server->renderer, color, matrix);
box = deco_box(view, LAB_DECO_PART_TOP);
float color2[] = { 0.7, 0.2, 0.2, 0.9 };
wlr_render_rect(view->server->renderer, &box, color2, output->transform_matrix);
}
static void render_surface(struct wlr_surface *surface, int sx, int sy,

View file

@ -252,9 +252,10 @@ static void process_cursor_motion(struct server *server, uint32_t time)
double sx, sy;
struct wlr_seat *seat = server->seat;
struct wlr_surface *surface = NULL;
int view_area;
struct view *view = desktop_view_at(server, server->cursor->x,
server->cursor->y, &surface, &sx,
&sy);
&sy, &view_area);
if (!view) {
/* If there's no view under the cursor, set the cursor image to
* a default. This is what makes the cursor image appear when
@ -262,6 +263,12 @@ static void process_cursor_motion(struct server *server, uint32_t time)
wlr_xcursor_manager_set_cursor_image(
server->cursor_mgr, "left_ptr", server->cursor);
}
switch (view_area) {
case LAB_DECO_PART_TOP:
wlr_xcursor_manager_set_cursor_image(
server->cursor_mgr, "left_ptr", server->cursor);
break;
}
if (surface) {
bool focus_changed = seat->pointer_state.focused_surface !=
surface;
@ -332,9 +339,10 @@ void server_cursor_button(struct wl_listener *listener, void *data)
event->button, event->state);
double sx, sy;
struct wlr_surface *surface;
int view_area;
struct view *view = desktop_view_at(server, server->cursor->x,
server->cursor->y, &surface, &sx,
&sy);
&sy, &view_area);
if (event->state == WLR_BUTTON_RELEASED) {
/* If you released any buttons, we exit interactive move/resize
* mode. */
@ -342,6 +350,11 @@ void server_cursor_button(struct wl_listener *listener, void *data)
} else {
/* Focus that client if the button was _pressed_ */
focus_view(view, surface);
switch (view_area) {
case LAB_DECO_PART_TOP:
begin_interactive(view, TINYWL_CURSOR_MOVE, 0);
break;
}
}
}

44
view.c
View file

@ -1,5 +1,21 @@
#include "labwc.h"
bool view_want_deco(struct view *view)
{
if (!view->surface)
return false;
if (view->type != LAB_XWAYLAND_VIEW)
return false;
if (!is_toplevel(view))
return false;
if (view->xwayland_surface->override_redirect)
return false;
if (view->xwayland_surface->decorations !=
WLR_XWAYLAND_SURFACE_DECORATIONS_ALL)
return false;
return true;
}
static struct view *last_toplevel(struct server *server)
{
struct view *view;
@ -127,10 +143,6 @@ void begin_interactive(struct view *view, enum cursor_mode mode, uint32_t edges)
struct server *server = view->server;
struct wlr_surface *focused_surface =
server->seat->pointer_state.focused_surface;
if (view->surface != focused_surface) {
/* Deny move/resize requests from unfocused clients. */
return;
}
server->grabbed_view = view;
server->cursor_mode = mode;
@ -216,7 +228,7 @@ static bool view_at(struct view *view, double lx, double ly,
break;
}
if (_surface != NULL) {
if (_surface) {
*sx = _sx;
*sy = _sy;
*surface = _surface;
@ -227,16 +239,28 @@ static bool view_at(struct view *view, double lx, double ly,
struct view *desktop_view_at(struct server *server, double lx, double ly,
struct wlr_surface **surface, double *sx,
double *sy)
double *sy, int *view_area)
{
/* This iterates over all of our surfaces and attempts to find one under
* the cursor. This relies on server->views being ordered from
* top-to-bottom. */
/*
* This iterates over all of our surfaces and attempts to find one under
* the cursor. It relies on server->views being ordered from
* top-to-bottom.
*/
struct wlr_box border_box = {
.x = 0, .y = 0,
.width = 0, .height = 0,
};
struct view *view;
wl_list_for_each (view, &server->views, link) {
if (view_at(view, lx, ly, surface, sx, sy)) {
if (view_at(view, lx, ly, surface, sx, sy))
return view;
if (!view_want_deco(view))
continue;
if (deco_at(view, lx, ly) == LAB_DECO_PART_TOP) {
*view_area = LAB_DECO_PART_TOP;
return view;
}
}
return NULL;
}