mirror of
https://github.com/labwc/labwc.git
synced 2026-04-06 07:15:40 -04:00
Support xwayland window title bar dragging
This commit is contained in:
parent
4c53bd8bf9
commit
83c3492c87
7 changed files with 109 additions and 42 deletions
4
Makefile
4
Makefile
|
|
@ -13,9 +13,11 @@ ASAN_FLAGS = -O0 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynami
|
||||||
WP = `pkg-config --variable=pkgdatadir wayland-protocols`
|
WP = `pkg-config --variable=pkgdatadir wayland-protocols`
|
||||||
WS = `pkg-config --variable=wayland_scanner wayland-scanner`
|
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
|
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)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
xdg-shell-protocol.h:
|
xdg-shell-protocol.h:
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
labwc is a wayland compositor based on wlroots
|
labwc is a wayland compositor based on wlroots
|
||||||
|
|
||||||
[https://imgur.com/rb2hJh3](https://imgur.com/rb2hJh3)
|
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
- wlroots
|
- wlroots
|
||||||
|
|
@ -15,7 +13,6 @@ labwc is a wayland compositor based on wlroots
|
||||||
Alt+Escape Exit labwc
|
Alt+Escape Exit labwc
|
||||||
Alt+F2 Cycle between windows
|
Alt+F2 Cycle between windows
|
||||||
Alt+F3 Launch dmenu
|
Alt+F3 Launch dmenu
|
||||||
Alt+F6 Move window
|
|
||||||
Alt+F12 Print all views (helpful if run from X11)
|
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
|
[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
|
[openbox](https://github.com/danakj/openbox) - 53k LOC
|
||||||
|
|
||||||
|
|
|
||||||
39
deco.c
Normal file
39
deco.c
Normal 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
13
labwc.h
|
|
@ -33,7 +33,6 @@
|
||||||
#define XWL_TITLEBAR_HEIGHT (10)
|
#define XWL_TITLEBAR_HEIGHT (10)
|
||||||
#define XWL_WINDOW_BORDER (3)
|
#define XWL_WINDOW_BORDER (3)
|
||||||
|
|
||||||
/* For brevity's sake, struct members are annotated where they are used. */
|
|
||||||
enum cursor_mode {
|
enum cursor_mode {
|
||||||
TINYWL_CURSOR_PASSTHROUGH,
|
TINYWL_CURSOR_PASSTHROUGH,
|
||||||
TINYWL_CURSOR_MOVE,
|
TINYWL_CURSOR_MOVE,
|
||||||
|
|
@ -84,6 +83,11 @@ struct output {
|
||||||
|
|
||||||
enum view_type { LAB_XDG_SHELL_VIEW, LAB_XWAYLAND_VIEW };
|
enum view_type { LAB_XDG_SHELL_VIEW, LAB_XWAYLAND_VIEW };
|
||||||
|
|
||||||
|
enum deco_part {
|
||||||
|
LAB_DECO_NONE,
|
||||||
|
LAB_DECO_PART_TOP
|
||||||
|
};
|
||||||
|
|
||||||
struct view {
|
struct view {
|
||||||
enum view_type type;
|
enum view_type type;
|
||||||
struct wl_list link;
|
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_configure(struct wl_listener *listener, void *data);
|
||||||
void xwl_surface_new(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 view_focus_last_toplevel(struct server *server);
|
||||||
void focus_view(struct view *view, struct wlr_surface *surface);
|
void focus_view(struct view *view, struct wlr_surface *surface);
|
||||||
void view_focus_next_toplevel(struct server *server);
|
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);
|
bool is_toplevel(struct view *view);
|
||||||
struct view *desktop_view_at(struct server *server, double lx, double ly,
|
struct view *desktop_view_at(struct server *server, double lx, double ly,
|
||||||
struct wlr_surface **surface, double *sx,
|
struct wlr_surface **surface, double *sx,
|
||||||
double *sy);
|
double *sy, int *view_area);
|
||||||
|
|
||||||
/* TODO: try to refactor to remove from header file */
|
/* TODO: try to refactor to remove from header file */
|
||||||
struct view *first_toplevel(struct server *server);
|
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);
|
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 */
|
#endif /* LABWC_H */
|
||||||
|
|
|
||||||
29
output.c
29
output.c
|
|
@ -1,9 +1,5 @@
|
||||||
#include "labwc.h"
|
#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 render_data {
|
||||||
struct wlr_output *output;
|
struct wlr_output *output;
|
||||||
struct wlr_renderer *renderer;
|
struct wlr_renderer *renderer;
|
||||||
|
|
@ -13,32 +9,19 @@ struct render_data {
|
||||||
|
|
||||||
static void render_decorations(struct wlr_output *output, struct view *view)
|
static void render_decorations(struct wlr_output *output, struct view *view)
|
||||||
{
|
{
|
||||||
if (!view->surface)
|
if (!view_want_deco(view))
|
||||||
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)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
struct wlr_box box = {
|
struct wlr_box box = deco_max_extents(view);
|
||||||
.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,
|
|
||||||
};
|
|
||||||
|
|
||||||
float matrix[9];
|
float matrix[9];
|
||||||
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
|
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
|
||||||
output->transform_matrix);
|
output->transform_matrix);
|
||||||
|
|
||||||
float color[] = { 0.2, 0.2, 0.7, 0.9 };
|
float color[] = { 0.2, 0.2, 0.7, 0.9 };
|
||||||
wlr_render_quad_with_matrix(view->server->renderer, color, matrix);
|
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,
|
static void render_surface(struct wlr_surface *surface, int sx, int sy,
|
||||||
|
|
|
||||||
17
server.c
17
server.c
|
|
@ -252,9 +252,10 @@ static void process_cursor_motion(struct server *server, uint32_t time)
|
||||||
double sx, sy;
|
double sx, sy;
|
||||||
struct wlr_seat *seat = server->seat;
|
struct wlr_seat *seat = server->seat;
|
||||||
struct wlr_surface *surface = NULL;
|
struct wlr_surface *surface = NULL;
|
||||||
|
int view_area;
|
||||||
struct view *view = desktop_view_at(server, server->cursor->x,
|
struct view *view = desktop_view_at(server, server->cursor->x,
|
||||||
server->cursor->y, &surface, &sx,
|
server->cursor->y, &surface, &sx,
|
||||||
&sy);
|
&sy, &view_area);
|
||||||
if (!view) {
|
if (!view) {
|
||||||
/* If there's no view under the cursor, set the cursor image to
|
/* If there's no view under the cursor, set the cursor image to
|
||||||
* a default. This is what makes the cursor image appear when
|
* 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(
|
wlr_xcursor_manager_set_cursor_image(
|
||||||
server->cursor_mgr, "left_ptr", server->cursor);
|
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) {
|
if (surface) {
|
||||||
bool focus_changed = seat->pointer_state.focused_surface !=
|
bool focus_changed = seat->pointer_state.focused_surface !=
|
||||||
surface;
|
surface;
|
||||||
|
|
@ -332,9 +339,10 @@ void server_cursor_button(struct wl_listener *listener, void *data)
|
||||||
event->button, event->state);
|
event->button, event->state);
|
||||||
double sx, sy;
|
double sx, sy;
|
||||||
struct wlr_surface *surface;
|
struct wlr_surface *surface;
|
||||||
|
int view_area;
|
||||||
struct view *view = desktop_view_at(server, server->cursor->x,
|
struct view *view = desktop_view_at(server, server->cursor->x,
|
||||||
server->cursor->y, &surface, &sx,
|
server->cursor->y, &surface, &sx,
|
||||||
&sy);
|
&sy, &view_area);
|
||||||
if (event->state == WLR_BUTTON_RELEASED) {
|
if (event->state == WLR_BUTTON_RELEASED) {
|
||||||
/* If you released any buttons, we exit interactive move/resize
|
/* If you released any buttons, we exit interactive move/resize
|
||||||
* mode. */
|
* mode. */
|
||||||
|
|
@ -342,6 +350,11 @@ void server_cursor_button(struct wl_listener *listener, void *data)
|
||||||
} else {
|
} else {
|
||||||
/* Focus that client if the button was _pressed_ */
|
/* Focus that client if the button was _pressed_ */
|
||||||
focus_view(view, surface);
|
focus_view(view, surface);
|
||||||
|
switch (view_area) {
|
||||||
|
case LAB_DECO_PART_TOP:
|
||||||
|
begin_interactive(view, TINYWL_CURSOR_MOVE, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
44
view.c
44
view.c
|
|
@ -1,5 +1,21 @@
|
||||||
#include "labwc.h"
|
#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)
|
static struct view *last_toplevel(struct server *server)
|
||||||
{
|
{
|
||||||
struct view *view;
|
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 server *server = view->server;
|
||||||
struct wlr_surface *focused_surface =
|
struct wlr_surface *focused_surface =
|
||||||
server->seat->pointer_state.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->grabbed_view = view;
|
||||||
server->cursor_mode = mode;
|
server->cursor_mode = mode;
|
||||||
|
|
||||||
|
|
@ -216,7 +228,7 @@ static bool view_at(struct view *view, double lx, double ly,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_surface != NULL) {
|
if (_surface) {
|
||||||
*sx = _sx;
|
*sx = _sx;
|
||||||
*sy = _sy;
|
*sy = _sy;
|
||||||
*surface = _surface;
|
*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 view *desktop_view_at(struct server *server, double lx, double ly,
|
||||||
struct wlr_surface **surface, double *sx,
|
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
|
* This iterates over all of our surfaces and attempts to find one under
|
||||||
* top-to-bottom. */
|
* 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;
|
struct view *view;
|
||||||
wl_list_for_each (view, &server->views, link) {
|
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 view;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue