Switch to wlr_scene api

This commit is contained in:
project-repo 2022-01-26 19:36:10 +01:00
commit c5800b2223
23 changed files with 404 additions and 1290 deletions

View file

@ -17,9 +17,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include <wayland-server-core.h>
#include <wayland-client.h>
#include <wlr/backend.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_cursor.h>
@ -28,6 +32,8 @@
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_viewporter.h>
#include <wlr/types/wlr_presentation_time.h>
#include <wlr/types/wlr_idle_inhibit_v1.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_screencopy_v1.h>
@ -133,9 +139,6 @@ usage(FILE *file, const char *const cage) {
"\n"
" -r\t Rotate the output 90 degrees clockwise, specify up to three "
"times\n"
#ifdef DEBUG
" -D\t Turn on damage tracking debugging\n"
#endif
" -h\t Display this help message\n"
" -v\t Show the version number and exit\n"
" -s\t Show information about the current setup and exit\n",
@ -145,11 +148,7 @@ usage(FILE *file, const char *const cage) {
static bool
parse_args(struct cg_server *server, int argc, char *argv[]) {
int c;
#ifdef DEBUG
while((c = getopt(argc, argv, "rDhvs")) != -1) {
#else
while((c = getopt(argc, argv, "rhvs")) != -1) {
#endif
switch(c) {
case 'r':
server->output_transform++;
@ -157,11 +156,6 @@ parse_args(struct cg_server *server, int argc, char *argv[]) {
server->output_transform = WL_OUTPUT_TRANSFORM_NORMAL;
}
break;
#ifdef DEBUG
case 'D':
server->debug_damage_tracking = true;
break;
#endif
case 'h':
usage(stdout, argv[0]);
return false;
@ -245,7 +239,6 @@ main(int argc, char *argv[]) {
struct wl_event_source *sigterm_source = NULL;
struct wl_event_source *sigalrm_source = NULL;
struct wlr_backend *backend = NULL;
struct wlr_renderer *renderer = NULL;
struct wlr_compositor *compositor = NULL;
struct wlr_data_device_manager *data_device_manager = NULL;
struct wlr_server_decoration_manager *server_decoration_manager = NULL;
@ -253,6 +246,8 @@ main(int argc, char *argv[]) {
struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager = NULL;
struct wlr_screencopy_manager_v1 *screencopy_manager = NULL;
struct wlr_data_control_manager_v1 *data_control_manager = NULL;
struct wlr_viewporter *viewporter = NULL;
struct wlr_presentation *presentation = NULL;
struct wlr_xdg_output_manager_v1 *output_manager = NULL;
struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL;
struct wlr_xdg_shell *xdg_shell = NULL;
@ -353,10 +348,23 @@ main(int argc, char *argv[]) {
goto end;
}
renderer = wlr_backend_get_renderer(backend);
wlr_renderer_init_wl_display(renderer, server.wl_display);
server.renderer = wlr_renderer_autocreate(backend);
if (!server.renderer) {
wlr_log(WLR_ERROR, "Unable to create the wlroots renderer");
ret = 1;
goto end;
}
server.bg_color = (float[4]){0, 0, 0, 1};
server.allocator = wlr_allocator_autocreate(server.backend, server.renderer);
if (!server.allocator) {
wlr_log(WLR_ERROR, "Unable to create the wlroots allocator");
ret = 1;
goto end;
}
wlr_renderer_init_wl_display(server.renderer, server.wl_display);
server.bg_color = (float[4]){0, 0, 1, 1};
wl_list_init(&server.outputs);
wl_list_init(&server.disabled_outputs);
@ -373,7 +381,15 @@ main(int argc, char *argv[]) {
goto end;
}
compositor = wlr_compositor_create(server.wl_display, renderer);
server.scene = wlr_scene_create();
if (!server.scene) {
wlr_log(WLR_ERROR, "Unable to create scene");
ret = 1;
goto end;
}
wlr_scene_attach_output_layout(server.scene, server.output_layout);
compositor = wlr_compositor_create(server.wl_display, server.renderer);
if(!compositor) {
wlr_log(WLR_ERROR, "Unable to create the wlroots compositor");
ret = 1;
@ -467,6 +483,29 @@ main(int argc, char *argv[]) {
goto end;
}
viewporter = wlr_viewporter_create(server.wl_display);
if (!viewporter) {
wlr_log(WLR_ERROR, "Unable to create the viewporter interface");
ret = 1;
goto end;
}
presentation = wlr_presentation_create(server.wl_display, server.backend);
if (!presentation) {
wlr_log(WLR_ERROR, "Unable to create the presentation interface");
ret = 1;
goto end;
}
wlr_scene_set_presentation(server.scene, presentation);
export_dmabuf_manager = wlr_export_dmabuf_manager_v1_create(server.wl_display);
if (!export_dmabuf_manager) {
wlr_log(WLR_ERROR, "Unable to create the export DMABUF manager");
ret = 1;
goto end;
}
screencopy_manager = wlr_screencopy_manager_v1_create(server.wl_display);
if(!screencopy_manager) {
wlr_log(WLR_ERROR, "Unable to create the screencopy manager");

View file

@ -4,7 +4,7 @@
#include "seat.h"
#include "server.h"
#include <wayland-server-core.h>
#include <wlr/types/wlr_box.h>
#include <wlr/util/box.h>
struct cg_input_manager *
input_manager_create(struct cg_server *server);

View file

@ -7,6 +7,7 @@
#include <wlr/backend/session.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/util/log.h>
#include "input.h"
@ -196,21 +197,13 @@ swap_tile(struct cg_tile *tile,
swap_tile->view = tmp_view;
if(tile->view != NULL) {
view_maximize(tile->view, tile);
view_damage_whole(tile->view);
} else {
wlr_output_damage_add_box(tile->workspace->output->damage, &tile->tile);
}
workspace_focus_tile(
server->curr_output->workspaces[server->curr_output->curr_workspace],
swap_tile);
if(swap_tile->view != NULL) {
view_maximize(swap_tile->view, swap_tile);
view_damage_whole(swap_tile->view);
} else {
wlr_output_damage_add_box(tile->workspace->output->damage,
&swap_tile->tile);
}
seat_set_focus(server->seat, swap_tile->view);
ipc_send_event(
tile->workspace->output->server,
@ -363,12 +356,7 @@ resize(struct cg_tile *tile, const struct cg_tile *parent, int coord_offset,
old_height = tile->tile.height, old_width = tile->tile.width;
*get_coord(tile) += coord_offset;
*get_dim(tile) += dim_offset;
struct wlr_box damage_box = {
.x = old_x,
.y = old_y,
.width = tile->tile.x - old_x == 0 ? tile->tile.width : coord_offset,
.height = tile->tile.y == 0 ? tile->tile.height : coord_offset};
wlr_output_damage_add_box(tile->workspace->output->damage, &damage_box);
if(tile->view != NULL) {
view_maximize(tile->view, tile);
}
@ -699,8 +687,6 @@ keybinding_cycle_views(struct cg_server *server, bool reverse) {
return;
}
wlr_output_damage_add_box(curr_workspace->output->damage,
&curr_workspace->focused_tile->tile);
/* Prevent seat_set_focus from reordering the views */
curr_workspace->focused_tile->view = wl_container_of(
next_view->link.prev, curr_workspace->focused_tile->view, link);
@ -743,10 +729,9 @@ keybinding_switch_ws(struct cg_server *server, uint32_t ws) {
}
struct cg_output *output = server->curr_output;
uint32_t old_ws = server->curr_output->curr_workspace;
output->curr_workspace = ws;
workspace_focus(output,ws);
seat_set_focus(server->seat,
server->curr_output->workspaces[ws]->focused_tile->view);
wlr_output_damage_add_whole(output->damage);
message_printf(server->curr_output, "Workspace %d", ws + 1);
ipc_send_event(output->server,
"switch_ws(old_workspace:%d,new_workspace:%d,output:%s)",
@ -794,7 +779,6 @@ keybinding_move_view_to_cycle_output(struct cg_server *server, bool reverse) {
server->curr_output->workspaces[server->curr_output->curr_workspace]
->focused_tile->view = NULL;
keybinding_cycle_views(server, false);
view_damage_whole(view);
if(server->curr_output->workspaces[server->curr_output->curr_workspace]
->focused_tile->view == NULL) {
seat_set_focus(server->seat, NULL);
@ -864,7 +848,7 @@ keybinding_set_nws(struct cg_server *server, int nws) {
}
if(output->curr_workspace >= nws) {
output->curr_workspace = nws - 1;
workspace_focus(output,nws-1);
}
}
server->nws = nws;
@ -908,6 +892,13 @@ keybinding_set_background(struct cg_server *server, float *bg) {
server->bg_color[0] = bg[0];
server->bg_color[1] = bg[1];
server->bg_color[2] = bg[2];
struct cg_output *it=NULL;
wl_list_for_each(it,&server->outputs,link) {
wlr_scene_rect_set_color(it->bg, server->bg_color);
}
wl_list_for_each(it,&server->disabled_outputs,link) {
wlr_scene_rect_set_color(it->bg, server->bg_color);
}
}
void

View file

@ -53,12 +53,11 @@ if is_freebsd
)
endif
wlroots = dependency('wlroots', version: ['>=0.14.1', '< 0.15.0'])
wlroots = dependency('wlroots', version: ['>=0.14.1', '< 0.16.0'])
wayland_protos = dependency('wayland-protocols', version: '>=1.14')
wayland_server = dependency('wayland-server')
wayland_cursor = dependency('wayland-cursor')
wayland_client = dependency('wayland-client')
pixman = dependency('pixman-1')
xkbcommon = dependency('xkbcommon')
cairo = dependency('cairo')
pango = dependency('pango')
@ -132,7 +131,6 @@ cagebreak_source_strings = [
'workspace.c',
'output.c',
'parse.c',
'render.c',
'seat.c',
'util.c',
'view.c',
@ -150,7 +148,6 @@ cagebreak_header_strings = [
'workspace.h',
'output.h',
'parse.h',
'render.h',
'seat.h',
'server.h',
'util.h',
@ -194,7 +191,6 @@ cagebreak_dependencies_dict = {
'libinput': [libinput,true],
'libevdev': [libevdev,true],
'libudev': [libudev,true],
'pixman': [pixman,true],
'pango': [pango,true],
'cairo': [cairo,true],
'pangocairo': [pangocairo,true],
@ -212,7 +208,6 @@ reproducible_build_versions = {
'libinput': '1.19.2',
'libevdev': '1.12.0',
'libudev': '249',
'pixman': '0.40.0',
'pango': '1.50.0',
'cairo': '1.17.4',
'pangocairo': '1.50.0',

102
message.c
View file

@ -2,11 +2,16 @@
#include <drm_fourcc.h>
#include <pango/pangocairo.h>
#include <unistd.h>
#include <wayland-client.h>
#include <wlr/backend.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/util/log.h>
#include <sys/mman.h>
#include <wlr/render/allocator.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/render/drm_format_set.h>
#include "message.h"
#include "output.h"
@ -14,6 +19,62 @@
#include "server.h"
#include "util.h"
struct msg_buffer {
struct wlr_buffer base;
void *data;
uint32_t format;
size_t stride;
};
static void msg_buffer_destroy(struct wlr_buffer *wlr_buffer) {
struct msg_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
free(buffer->data);
free(buffer);
}
static bool msg_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer,
uint32_t flags, void **data, uint32_t *format, size_t *stride) {
struct msg_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
if(data != NULL) {
*data = (void *)buffer->data;
}
if(format != NULL) {
*format = buffer->format;
}
if(stride != NULL) {
*stride = buffer->stride;
}
return true;
}
static void msg_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) {
// This space is intentionally left blank
}
static const struct wlr_buffer_impl msg_buffer_impl = {
.destroy = msg_buffer_destroy,
.begin_data_ptr_access = msg_buffer_begin_data_ptr_access,
.end_data_ptr_access = msg_buffer_end_data_ptr_access,
};
static struct msg_buffer *msg_buffer_create(uint32_t width, uint32_t height, uint32_t stride) {
struct msg_buffer *buffer = calloc(1, sizeof(*buffer));
if (buffer == NULL) {
return NULL;
}
wlr_buffer_init(&buffer->base, &msg_buffer_impl, width, height);
buffer->format = DRM_FORMAT_ARGB8888;
buffer->stride = stride;
buffer->data = malloc(buffer->stride * height);
if (buffer->data == NULL) {
free(buffer);
return NULL;
}
return buffer;
}
cairo_subpixel_order_t
to_cairo_subpixel_order(const enum wl_output_subpixel subpixel) {
switch(subpixel) {
@ -31,12 +92,11 @@ to_cairo_subpixel_order(const enum wl_output_subpixel subpixel) {
return CAIRO_SUBPIXEL_ORDER_DEFAULT;
}
struct wlr_texture *
struct msg_buffer *
create_message_texture(const char *string, const struct cg_output *output) {
const int WIDTH_PADDING = 8;
const int HEIGHT_PADDING = 2;
struct wlr_texture *texture;
double scale = output->wlr_output->scale;
int width = 0;
int height = 0;
@ -89,14 +149,21 @@ create_message_texture(const char *string, const struct cg_output *output) {
cairo_surface_flush(surface);
unsigned char *data = cairo_image_surface_get_data(surface);
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
struct wlr_renderer *renderer =
wlr_backend_get_renderer(output->wlr_output->backend);
texture = wlr_texture_from_pixels(renderer, DRM_FORMAT_ARGB8888, stride,
width, height, data);
struct msg_buffer *buf=msg_buffer_create(width, height,stride);
void *data_ptr;
if(!wlr_buffer_begin_data_ptr_access(&buf->base, WLR_BUFFER_DATA_PTR_ACCESS_WRITE,&data_ptr,NULL,NULL)) {
wlr_log(WLR_ERROR, "Failed to get pointer access to message buffer");
return NULL;
}
memcpy(data_ptr,data,stride*height);
wlr_buffer_end_data_ptr_access(&buf->base);
cairo_surface_destroy(surface);
g_object_unref(pango);
cairo_destroy(cairo);
return texture;
return buf;
}
#if CG_HAS_FANALYZE
@ -112,8 +179,8 @@ message_set_output(struct cg_output *output, const char *string,
free(box);
return;
}
message->message = create_message_texture(string, output);
if(!message->message) {
struct msg_buffer *buf = create_message_texture(string, output);
if(!buf) {
wlr_log(WLR_ERROR, "Could not create message texture");
free(box);
free(message);
@ -122,8 +189,8 @@ message_set_output(struct cg_output *output, const char *string,
message->position = box;
wl_list_insert(&output->messages, &message->link);
int width = message->message->width;
int height = message->message->height;
int width = buf->base.width;
int height = buf->base.height;
message->position->width = width;
message->position->height = height;
switch(align) {
@ -149,7 +216,13 @@ message_set_output(struct cg_output *output, const char *string,
default:
break;
}
wlr_output_damage_add_box(output->damage, message->position);
message->message=wlr_scene_buffer_create(&output->scene_output->scene->node,&buf->base);
wlr_scene_node_raise_to_top(&message->message->node);
wlr_scene_node_set_enabled(&message->message->node,true);
struct wlr_box *outp_box = wlr_output_layout_get_box(
output->server->output_layout, output->wlr_output);
wlr_scene_node_set_position(&message->message->node, message->position->x+outp_box->x, message->position->y+outp_box->y);
}
void
@ -206,9 +279,10 @@ message_clear(struct cg_output *output) {
struct cg_message *message, *tmp;
wl_list_for_each_safe(message, tmp, &output->messages, link) {
wl_list_remove(&message->link);
wlr_output_damage_add_box(output->damage, message->position);
wlr_texture_destroy(message->message);
struct wlr_buffer *buf=message->message->buffer;
wlr_scene_node_destroy(&message->message->node);
free(message->position);
buf->impl->destroy(buf);
free(message);
}
}

View file

@ -6,7 +6,7 @@
struct cg_output;
struct wlr_box;
struct wlr_texture;
struct wlr_buffer;
enum cg_message_align {
CG_MESSAGE_TOP_LEFT,
@ -25,7 +25,8 @@ struct cg_message_config {
struct cg_message {
struct wlr_box *position;
struct wlr_texture *message;
struct wlr_scene_buffer *message;
struct wl_surface *surface;
struct wl_list link;
};

476
output.c
View file

@ -27,6 +27,7 @@
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/util/log.h>
#include <wlr/util/region.h>
#include <wlr/xwayland.h>
@ -34,7 +35,6 @@
#include "keybinding.h"
#include "message.h"
#include "output.h"
#include "render.h"
#include "seat.h"
#include "server.h"
#include "util.h"
@ -44,367 +44,6 @@
#include "xwayland.h"
#endif
static void
output_for_each_surface(struct cg_output *output,
cg_surface_iterator_func_t iterator, void *user_data);
struct surface_iterator_data {
cg_surface_iterator_func_t user_iterator;
void *user_data;
struct cg_output *output;
/* Output-local coordinates. */
double ox, oy;
};
static bool
intersects_with_output(struct cg_output *output,
const struct wlr_output_layout *output_layout,
const struct wlr_box *surface_box) {
/* Since the surface_box's x- and y-coordinates are already output local,
* the x- and y-coordinates of this box need to be 0 for this function to
* work correctly. */
struct wlr_box output_box = {0};
wlr_output_effective_resolution(output->wlr_output, &output_box.width,
&output_box.height);
struct wlr_box intersection;
return wlr_box_intersection(&intersection, &output_box, surface_box);
}
static void
output_for_each_surface_iterator(struct wlr_surface *surface, int sx, int sy,
void *user_data) {
struct surface_iterator_data *data = user_data;
struct cg_output *output = data->output;
if(!wlr_surface_has_buffer(surface)) {
return;
}
struct wlr_box surface_box = {
.x = data->ox + sx + surface->sx,
.y = data->oy + sy + surface->sy,
.width = surface->current.width,
.height = surface->current.height,
};
if(!intersects_with_output(output, output->server->output_layout,
&surface_box)) {
return;
}
data->user_iterator(data->output, surface, &surface_box, data->user_data);
}
void
output_surface_for_each_surface(struct cg_output *output,
struct wlr_surface *surface, double ox,
double oy, cg_surface_iterator_func_t iterator,
void *user_data) {
struct surface_iterator_data data = {
.user_iterator = iterator,
.user_data = user_data,
.output = output,
.ox = ox,
.oy = oy,
};
wlr_surface_for_each_surface(surface, output_for_each_surface_iterator,
&data);
}
static void
output_view_for_each_surface(struct cg_output *output, struct cg_view *view,
cg_surface_iterator_func_t iterator,
void *user_data) {
struct surface_iterator_data data = {
.user_iterator = iterator,
.user_data = user_data,
.output = output,
.ox = view->ox,
.oy = view->oy,
};
view_for_each_surface(view, output_for_each_surface_iterator, &data);
}
void
output_view_for_each_popup(struct cg_output *output, struct cg_view *view,
cg_surface_iterator_func_t iterator,
void *user_data) {
struct surface_iterator_data data = {
.user_iterator = iterator,
.user_data = user_data,
.output = output,
.ox = view->ox,
.oy = view->oy,
};
view_for_each_popup(view, output_for_each_surface_iterator, &data);
}
void
output_drag_icons_for_each_surface(struct cg_output *output,
struct wl_list *drag_icons,
cg_surface_iterator_func_t iterator,
void *user_data) {
struct cg_drag_icon *drag_icon;
wl_list_for_each(drag_icon, drag_icons, link) {
if(drag_icon->wlr_drag_icon->mapped) {
double ox = drag_icon->lx;
double oy = drag_icon->ly;
wlr_output_layout_output_coords(output->server->output_layout,
output->wlr_output, &ox, &oy);
output_surface_for_each_surface(output,
drag_icon->wlr_drag_icon->surface,
ox, oy, iterator, user_data);
}
}
}
static void
output_for_each_surface(struct cg_output *output,
cg_surface_iterator_func_t iterator, void *user_data) {
struct cg_view *view;
wl_list_for_each_reverse(
view, &output->workspaces[output->curr_workspace]->views, link) {
output_view_for_each_surface(output, view, iterator, user_data);
}
wl_list_for_each_reverse(
view, &output->workspaces[output->curr_workspace]->unmanaged_views,
link) {
output_view_for_each_surface(output, view, iterator, user_data);
}
output_drag_icons_for_each_surface(
output, &output->server->seat->drag_icons, iterator, user_data);
}
struct send_frame_done_data {
struct timespec when;
};
static void
send_frame_done_iterator(struct cg_output *output, struct wlr_surface *surface,
struct wlr_box *box, void *user_data) {
struct send_frame_done_data *data = user_data;
wlr_surface_send_frame_done(surface, &data->when);
}
static void
send_frame_done(struct cg_output *output, struct send_frame_done_data *data) {
output_for_each_surface(output, send_frame_done_iterator, data);
}
struct damage_data {
bool whole;
};
static void
count_surface_iterator(struct cg_output *output, struct wlr_surface *surface,
struct wlr_box *_box, void *data) {
size_t *n = data;
(*n)++;
}
static bool
scan_out_primary_view(struct cg_output *output) {
struct cg_server *server = output->server;
struct wlr_output *wlr_output = output->wlr_output;
if(!wl_list_empty(&output->messages)) {
return false;
}
struct cg_drag_icon *drag_icon;
wl_list_for_each(drag_icon, &server->seat->drag_icons, link) {
if(drag_icon->wlr_drag_icon->mapped) {
return false;
}
}
struct cg_workspace *ws = output->workspaces[output->curr_workspace];
if(ws->focused_tile->next != ws->focused_tile) {
return false;
}
struct cg_view *view = ws->focused_tile->view;
if(view == NULL || view->wlr_surface == NULL) {
return false;
}
size_t n_surfaces = 0;
output_view_for_each_surface(output, view, count_surface_iterator,
&n_surfaces);
if(n_surfaces > 1) {
return false;
}
#if CG_HAS_XWAYLAND
if(view->type == CG_XWAYLAND_VIEW) {
struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view);
if(!wl_list_empty(&xwayland_view->xwayland_surface->children) ||
!wl_list_empty(&view->workspace->unmanaged_views)) {
return false;
}
}
#endif
struct wlr_surface *surface = view->wlr_surface;
if(!surface->buffer) {
return false;
}
if((float)surface->current.scale != wlr_output->scale ||
surface->current.transform != wlr_output->transform) {
return false;
}
wlr_output_attach_buffer(wlr_output, &surface->buffer->base);
if(!wlr_output_test(wlr_output)) {
return false;
}
return wlr_output_commit(wlr_output);
}
static void
damage_surface_iterator(struct cg_output *output, struct wlr_surface *surface,
struct wlr_box *box, void *user_data) {
struct wlr_output *wlr_output = output->wlr_output;
struct damage_data *data = (struct damage_data *)user_data;
bool whole = data->whole;
scale_box(box, output->wlr_output->scale);
if(whole) {
wlr_output_damage_add_box(output->damage, box);
} else if(pixman_region32_not_empty(&surface->buffer_damage)) {
pixman_region32_t damage;
pixman_region32_init(&damage);
wlr_surface_get_effective_damage(surface, &damage);
if(ceil(wlr_output->scale) > surface->current.scale) {
/* When scaling up a surface it'll become
blurry, so we need to expand the damage
region. */
wlr_region_expand(&damage, &damage,
ceil(wlr_output->scale) - surface->current.scale);
}
pixman_region32_translate(&damage, box->x, box->y);
wlr_output_damage_add(output->damage, &damage);
pixman_region32_fini(&damage);
}
}
void
output_damage_surface(struct cg_output *output, struct wlr_surface *surface,
double ox, double oy, bool whole) {
struct damage_data data = {
.whole = whole,
};
output_surface_for_each_surface(output, surface, ox, oy,
damage_surface_iterator, &data);
}
static void
handle_output_damage_frame(struct wl_listener *listener, void *data) {
struct cg_output *output = wl_container_of(listener, output, damage_frame);
struct send_frame_done_data frame_data = {0};
if(!output->wlr_output->enabled) {
return;
}
bool scanned_out = scan_out_primary_view(output);
if(scanned_out && !output->last_scanned_out_view) {
wlr_log(WLR_DEBUG, "Scanning out primary view");
}
if(output->last_scanned_out_view && !scanned_out) {
wlr_log(WLR_DEBUG, "Stopping primary view scan out");
wlr_output_damage_add_whole(output->damage);
output->last_scanned_out_view = NULL;
}
if(output->last_scanned_out_view &&
output->last_scanned_out_view != seat_get_focus(output->server->seat)) {
wlr_output_damage_add_whole(output->damage);
}
if(scanned_out) {
output->last_scanned_out_view =
output->workspaces[output->curr_workspace]->focused_tile->view;
}
if(scanned_out) {
goto frame_done;
}
bool needs_frame;
pixman_region32_t damage;
pixman_region32_init(&damage);
if(!wlr_output_damage_attach_render(output->damage, &needs_frame,
&damage)) {
wlr_log(WLR_ERROR, "Cannot make damage output current");
goto damage_finish;
}
if(!needs_frame) {
wlr_output_rollback(output->wlr_output);
goto damage_finish;
}
output_render(output, &damage);
damage_finish:
pixman_region32_fini(&damage);
frame_done:
clock_gettime(CLOCK_MONOTONIC, &frame_data.when);
send_frame_done(output, &frame_data);
}
static void
handle_output_commit(struct wl_listener *listener, void *data) {
struct cg_output *output = wl_container_of(listener, output, commit);
struct wlr_output_event_commit *event = data;
if(!output->wlr_output->enabled || output->workspaces == NULL) {
return;
}
if(event->committed &
(WLR_OUTPUT_STATE_TRANSFORM | WLR_OUTPUT_STATE_SCALE)) {
struct cg_view *view;
wl_list_for_each(
view, &output->workspaces[output->curr_workspace]->views, link) {
if(view_is_visible(view)) {
view_maximize(view, view->tile);
}
}
}
}
static void
handle_output_mode(struct wl_listener *listener, void *data) {
struct cg_output *output = wl_container_of(listener, output, mode);
if(!output->wlr_output->enabled || output->workspaces == NULL) {
return;
}
struct cg_view *view;
wl_list_for_each(view, &output->workspaces[output->curr_workspace]->views,
link) {
if(view_is_visible(view)) {
view_maximize(view, view->tile);
}
}
}
void
output_clear(struct cg_output *output) {
struct cg_server *server = output->server;
@ -485,8 +124,7 @@ output_destroy(struct cg_output *output) {
wl_list_remove(&output->destroy.link);
wl_list_remove(&output->mode.link);
wl_list_remove(&output->commit.link);
wl_list_remove(&output->damage_frame.link);
wl_list_remove(&output->damage_destroy.link);
wl_list_remove(&output->frame.link);
output_clear(output);
@ -513,17 +151,22 @@ output_destroy(struct cg_output *output) {
}
static void
handle_output_damage_destroy(struct wl_listener *listener, void *data) {
struct cg_output *output =
wl_container_of(listener, output, damage_destroy);
handle_output_destroy(struct wl_listener *listener, void *data) {
struct cg_output *output = wl_container_of(listener, output, destroy);
output_destroy(output);
}
static void
handle_output_destroy(struct wl_listener *listener, void *data) {
struct cg_output *output = wl_container_of(listener, output, destroy);
wlr_output_damage_destroy(output->damage);
output_destroy(output);
handle_output_frame(struct wl_listener *listener, void *data) {
struct cg_output *output=wl_container_of(listener, output, frame);
if(!output->wlr_output->enabled) {
return;
}
wlr_scene_output_commit(output->scene_output);
struct timespec now={0};
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_scene_output_send_frame_done(output->scene_output, &now);
}
struct cg_output_config *
@ -570,6 +213,19 @@ output_set_mode(struct wlr_output *output, int width, int height,
wlr_log(WLR_DEBUG, "Assigning configured mode to %s", output->name);
}
wlr_output_set_mode(output, best);
if(!wlr_output_test(output)) {
wlr_log(WLR_ERROR, "Unable to assign configured mode to %s, picking arbitrary available mode",output->name);
struct wlr_output_mode *mode;
wl_list_for_each(mode, &output->modes, link) {
if(mode == best) {
continue;
}
wlr_output_set_mode(output, mode);
if(wlr_output_test(output)) {
break;
}
}
}
}
void
@ -642,6 +298,59 @@ output_configure(struct cg_server *server, struct cg_output *output) {
wlr_output_commit(wlr_output);
}
}
struct wlr_scene_output *scene_output;
wl_list_for_each(scene_output,&output->server->scene->outputs,link) {
if(scene_output->output == wlr_output) {
output->scene_output=scene_output;
break;
}
}
if(output->bg!=NULL) {
wlr_scene_node_destroy(&output->bg->node);
}
output->bg=wlr_scene_rect_create(&output->scene_output->scene->node, output->wlr_output->width,output->wlr_output->height, server->bg_color);
struct wlr_box *box = wlr_output_layout_get_box(
server->output_layout, output->wlr_output);
wlr_scene_node_set_position(&output->bg->node, box->x, box->y);
wlr_scene_node_lower_to_bottom(&output->bg->node);
}
static void
handle_output_commit(struct wl_listener *listener, void *data) {
struct cg_output *output = wl_container_of(listener, output, commit);
struct wlr_output_event_commit *event = data;
if(!output->wlr_output->enabled || output->workspaces == NULL) {
return;
}
if(event->committed &
(WLR_OUTPUT_STATE_TRANSFORM | WLR_OUTPUT_STATE_SCALE)) {
struct cg_view *view;
wl_list_for_each(
view, &output->workspaces[output->curr_workspace]->views, link) {
if(view_is_visible(view)) {
view_maximize(view, view->tile);
}
}
}
}
static void
handle_output_mode(struct wl_listener *listener, void *data) {
struct cg_output *output = wl_container_of(listener, output, mode);
if(!output->wlr_output->enabled || output->workspaces == NULL) {
return;
}
struct cg_view *view;
wl_list_for_each(view, &output->workspaces[output->curr_workspace]->views,
link) {
if(view_is_visible(view)) {
view_maximize(view, view->tile);
}
}
}
#if CG_HAS_FANALYZE
@ -653,6 +362,11 @@ handle_new_output(struct wl_listener *listener, void *data) {
struct cg_server *server = wl_container_of(listener, server, new_output);
struct wlr_output *wlr_output = data;
if(!wlr_output_init_render(wlr_output,server->allocator,server->renderer)) {
wlr_log(WLR_ERROR, "Failed to initialize output rendering");
return;
}
struct cg_output *output = calloc(1, sizeof(struct cg_output));
if(!output) {
wlr_log(WLR_ERROR, "Failed to allocate output");
@ -661,7 +375,6 @@ handle_new_output(struct wl_listener *listener, void *data) {
output->wlr_output = wlr_output;
output->server = server;
output->damage = wlr_output_damage_create(wlr_output);
output->last_scanned_out_view = NULL;
struct cg_output_priorities *it;
@ -675,7 +388,6 @@ handle_new_output(struct wl_listener *listener, void *data) {
wlr_output_set_transform(wlr_output, server->output_transform);
output->workspaces = NULL;
output->curr_workspace = 0;
wl_list_init(&output->messages);
if(!wlr_xcursor_manager_load(server->seat->xcursor_manager,
@ -687,7 +399,6 @@ handle_new_output(struct wl_listener *listener, void *data) {
output_insert(server, output);
output_configure(server, output);
wlr_output_damage_add_whole(output->damage);
output->workspaces = malloc(server->nws * sizeof(struct cg_workspace *));
for(unsigned int i = 0; i < server->nws; ++i) {
@ -701,6 +412,9 @@ handle_new_output(struct wl_listener *listener, void *data) {
wl_list_init(&output->workspaces[i]->unmanaged_views);
}
wlr_scene_node_raise_to_top(&output->workspaces[0]->scene->node);
workspace_focus(output,0);
/* We are the first output. Set the current output to this one. */
if(server->curr_output == NULL) {
server->curr_output = output;
@ -709,16 +423,14 @@ handle_new_output(struct wl_listener *listener, void *data) {
DEFAULT_XCURSOR, server->seat->cursor);
wlr_cursor_warp(server->seat->cursor, NULL, 0, 0);
output->mode.notify = handle_output_mode;
wl_signal_add(&wlr_output->events.mode, &output->mode);
output->commit.notify = handle_output_commit;
wl_signal_add(&wlr_output->events.commit, &output->commit);
output->destroy.notify = handle_output_destroy;
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
output->damage_frame.notify = handle_output_damage_frame;
wl_signal_add(&output->damage->events.frame, &output->damage_frame);
output->damage_destroy.notify = handle_output_damage_destroy;
wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
output->frame.notify = handle_output_frame;
wl_signal_add(&wlr_output->events.frame, &output->frame);
output->commit.notify = handle_output_commit;
wl_signal_add(&wlr_output->events.commit, &output->commit);
output->mode.notify = handle_output_mode;
wl_signal_add(&wlr_output->events.mode, &output->mode);
ipc_send_event(server, "new_output(output:%s,priority:%d)",
output->wlr_output->name, output->priority);
}

View file

@ -2,24 +2,23 @@
#define CG_OUTPUT_H
#include <wayland-server-core.h>
#include <wlr/types/wlr_box.h>
#include <wlr/util/box.h>
struct cg_server;
struct cg_view;
struct wlr_output;
struct wlr_output_damage;
struct wlr_surface;
struct cg_output {
struct cg_server *server;
struct wlr_output *wlr_output;
struct wlr_output_damage *damage;
struct wlr_scene_output *scene_output;
struct wlr_scene_rect *bg;
struct wl_listener mode;
struct wl_listener commit;
struct wl_listener destroy;
struct wl_listener damage_frame;
struct wl_listener damage_destroy;
struct wl_listener frame;
struct cg_workspace **workspaces;
struct wl_list messages;
int curr_workspace;
@ -56,23 +55,6 @@ handle_new_output(struct wl_listener *listener, void *data);
void
output_configure(struct cg_server *server, struct cg_output *output);
void
output_surface_for_each_surface(struct cg_output *output,
struct wlr_surface *surface, double ox,
double oy, cg_surface_iterator_func_t iterator,
void *user_data);
void
output_view_for_each_popup(struct cg_output *output, struct cg_view *view,
cg_surface_iterator_func_t iterator,
void *user_data);
void
output_drag_icons_for_each_surface(struct cg_output *output,
struct wl_list *drag_icons,
cg_surface_iterator_func_t iterator,
void *user_data);
void
output_damage_surface(struct cg_output *output, struct wlr_surface *surface,
double ox, double oy, bool whole);
void
output_set_window_title(struct cg_output *output, const char *title);
#endif

277
render.c
View file

@ -1,277 +0,0 @@
/*
* Cagebreak: A Wayland tiling compositor.
*
* Copyright (C) 2020-2022 The Cagebreak Authors
* Copyright (C) 2018-2020 Jente Hidskes
* Copyright (C) 2019 The Sway authors
*
* See the LICENSE file accompanying this file.
*/
#include <stdlib.h>
#include <wayland-server-core.h>
#include <wlr/backend.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_box.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/util/log.h>
#include <wlr/util/region.h>
#include "message.h"
#include "output.h"
#include "seat.h"
#include "server.h"
#include "util.h"
#include "view.h"
#include "workspace.h"
static void
scissor_output(struct wlr_output *output, pixman_box32_t *rect) {
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
struct wlr_box box = {
.x = rect->x1,
.y = rect->y1,
.width = rect->x2 - rect->x1,
.height = rect->y2 - rect->y1,
};
int output_width, output_height;
wlr_output_transformed_resolution(output, &output_width, &output_height);
enum wl_output_transform transform =
wlr_output_transform_invert(output->transform);
wlr_box_transform(&box, &box, transform, output_width, output_height);
wlr_renderer_scissor(renderer, &box);
}
struct render_data {
pixman_region32_t *damage;
int tile_width, tile_height;
};
static void
render_texture(struct wlr_output *wlr_output, pixman_region32_t *output_damage,
struct wlr_texture *texture, const struct wlr_box *box,
const float matrix[static 9]) {
struct wlr_renderer *renderer =
wlr_backend_get_renderer(wlr_output->backend);
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_union_rect(&damage, &damage, box->x, box->y, box->width,
box->height);
pixman_region32_intersect(&damage, &damage, output_damage);
if(!pixman_region32_not_empty(&damage)) {
goto damage_finish;
}
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for(int i = 0; i < nrects; i++) {
scissor_output(wlr_output, &rects[i]);
wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0F);
}
damage_finish:
pixman_region32_fini(&damage);
}
static void
render_surface_iterator(struct cg_output *output, struct wlr_surface *surface,
struct wlr_box *box, void *user_data) {
struct render_data *data = user_data;
struct wlr_output *wlr_output = output->wlr_output;
pixman_region32_t *output_damage = data->damage;
struct wlr_texture *texture = wlr_surface_get_texture(surface);
if(!texture) {
wlr_log(WLR_DEBUG, "Cannot obtain surface texture");
return;
}
scale_box(box, wlr_output->scale);
float matrix[9];
enum wl_output_transform transform =
wlr_output_transform_invert(surface->current.transform);
wlr_matrix_project_box(matrix, box, transform, 0.0F,
wlr_output->transform_matrix);
if(data->tile_width != 0) {
box->width =
box->width > data->tile_width ? data->tile_width : box->width;
}
if(data->tile_height != 0) {
box->height =
box->height > data->tile_height ? data->tile_height : box->height;
}
render_texture(wlr_output, output_damage, texture, box, matrix);
}
static void
render_drag_icons(struct cg_output *output, pixman_region32_t *damage,
struct wl_list *drag_icons) {
struct render_data data = {
.damage = damage,
.tile_width = 0,
.tile_height = 0,
};
output_drag_icons_for_each_surface(output, drag_icons,
render_surface_iterator, &data);
}
/**
* Render all toplevels without descending into popups.
*/
static void
render_view_toplevels(struct cg_view *view, struct cg_output *output,
pixman_region32_t *damage) {
struct render_data data = {
.damage = damage,
.tile_width = 0,
.tile_height = 0,
};
struct cg_tile *view_tile = view_get_tile(view);
if(view_tile != NULL) {
if(view_tile->tile.width != view->wlr_surface->current.width ||
view_tile->tile.height != view->wlr_surface->current.height) {
view_damage_whole(view);
}
data.tile_width = view_tile->tile.width;
data.tile_height = view_tile->tile.height;
}
double ox, oy;
ox = view->ox;
oy = view->oy;
output_surface_for_each_surface(output, view->wlr_surface, ox, oy,
render_surface_iterator, &data);
}
static void
render_popup_iterator(struct cg_output *output, struct wlr_surface *surface,
struct wlr_box *box, void *data) {
/* Render this popup's surface. */
render_surface_iterator(output, surface, box, data);
/* Render this popup's child toplevels. */
output_surface_for_each_surface(output, surface, box->x, box->y,
render_surface_iterator, data);
}
static void
render_view_popups(struct cg_view *view, struct cg_output *output,
pixman_region32_t *damage) {
struct render_data data = {
.damage = damage,
.tile_width = 0,
.tile_height = 0,
};
output_view_for_each_popup(output, view, render_popup_iterator, &data);
}
void
output_render(struct cg_output *output, pixman_region32_t *damage) {
struct cg_server *server = output->server;
struct wlr_output *wlr_output = output->wlr_output;
struct wlr_renderer *renderer =
wlr_backend_get_renderer(wlr_output->backend);
if(!renderer) {
wlr_log(WLR_DEBUG, "Expected the output backend to have a renderer");
return;
}
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
if(!pixman_region32_not_empty(damage)) {
wlr_log(WLR_DEBUG, "Output isn't damaged but needs a buffer swap");
goto renderer_end;
}
#ifdef DEBUG
if(server->debug_damage_tracking) {
wlr_renderer_clear(renderer, (float[]){1.0F, 0.0F, 0.0F, 1.0F});
}
#endif
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
for(int i = 0; i < nrects; i++) {
scissor_output(wlr_output, &rects[i]);
wlr_renderer_clear(renderer, server->bg_color);
}
bool first = true;
for(struct cg_tile *tile =
output->workspaces[output->curr_workspace]->focused_tile;
first ||
tile != output->workspaces[output->curr_workspace]->focused_tile;
tile = tile->next) {
first = false;
/* Only render visible views */
if(tile->view != NULL) {
render_view_toplevels(tile->view, output, damage);
}
}
struct cg_view *view;
wl_list_for_each_reverse(
view, &output->workspaces[output->curr_workspace]->unmanaged_views,
link) {
render_view_toplevels(view, output, damage);
}
struct cg_view *focused_view = seat_get_focus(server->seat);
if(focused_view != NULL) {
render_view_popups(focused_view, output, damage);
}
struct cg_message *message;
wl_list_for_each_reverse(message, &output->messages, link) {
float matrix[9];
wlr_matrix_project_box(matrix, message->position,
WL_OUTPUT_TRANSFORM_NORMAL, 0.0F,
wlr_output->transform_matrix);
render_texture(output->wlr_output, damage, message->message,
message->position, matrix);
}
render_drag_icons(output, damage, &server->seat->drag_icons);
renderer_end:
/* Draw software cursor in case hardware cursors aren't
available. This is a no-op when they are. */
wlr_output_render_software_cursors(wlr_output, damage);
wlr_renderer_scissor(renderer, NULL);
wlr_renderer_end(renderer);
int output_width, output_height;
wlr_output_transformed_resolution(wlr_output, &output_width,
&output_height);
pixman_region32_t frame_damage;
pixman_region32_init(&frame_damage);
enum wl_output_transform transform =
wlr_output_transform_invert(wlr_output->transform);
wlr_region_transform(&frame_damage, &output->damage->current, transform,
output_width, output_height);
#ifdef DEBUG
if(server->debug_damage_tracking) {
pixman_region32_union_rect(&frame_damage, &frame_damage, 0, 0,
output_width, output_height);
}
#endif
wlr_output_set_damage(wlr_output, &frame_damage);
pixman_region32_fini(&frame_damage);
if(!wlr_output_commit(wlr_output)) {
wlr_log(WLR_ERROR, "Could not commit output");
}
}

View file

@ -1,9 +0,0 @@
#ifndef CG_RENDER_H
#define CG_RENDER_H
struct cg_output;
void
output_render(struct cg_output *output, pixman_region32_t *damage);
#endif

88
seat.c
View file

@ -22,6 +22,7 @@
#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_keyboard_group.h>
#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_touch.h>
@ -46,67 +47,22 @@
static void
drag_icon_update_position(struct cg_drag_icon *drag_icon);
/* XDG toplevels may have nested surfaces, such as popup windows for context
* menus or tooltips. This function tests if any of those are underneath the
* coordinates lx and ly (in output Layout Coordinates). If so, it sets the
* surface pointer to that wlr_surface and the sx and sy coordinates to the
* coordinates relative to that surface's top-left corner. */
static bool
view_at(const struct cg_view *view, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
struct wlr_box *output_layout_box = wlr_output_layout_get_box(
view->server->output_layout, view->workspace->output->wlr_output);
if(output_layout_box == NULL) {
return false;
}
double view_sx = lx - view->ox - output_layout_box->x;
double view_sy = ly - view->oy - output_layout_box->y;
double _sx, _sy;
struct wlr_surface *_surface =
view_wlr_surface_at(view, view_sx, view_sy, &_sx, &_sy);
if(_surface != NULL) {
*sx = _sx;
*sy = _sy;
*surface = _surface;
return true;
}
return false;
}
/* If desktop_view_at returns a view, there is also a
* surface. There cannot be a surface without a view, either. It's
* both or nothing. */
static struct cg_view *
desktop_view_at(const struct cg_server *server, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
struct cg_view *view;
wl_list_for_each(
view,
&server->curr_output->workspaces[server->curr_output->curr_workspace]
->unmanaged_views,
link) {
if(view_at(view, lx, ly, surface, sx, sy)) {
return view;
}
struct wlr_scene_node *node=wlr_scene_node_at(&server->scene->node, lx,ly,sx,sy);
if(node == NULL || node->type != WLR_SCENE_NODE_SURFACE) {
return NULL;
}
*surface = wlr_scene_surface_from_node(node)->surface;
bool first = true;
for(struct cg_tile *tile =
server->curr_output->workspaces[server->curr_output->curr_workspace]
->focused_tile;
first ||
server->curr_output->workspaces[server->curr_output->curr_workspace]
->focused_tile != tile;
tile = tile->next) {
first = false;
if(tile->view != NULL && view_at(tile->view, lx, ly, surface, sx, sy)) {
return tile->view;
}
while(node != NULL && node->data == NULL) {
node=node->parent;
}
return NULL;
return node->data;
}
static void
@ -720,26 +676,12 @@ handle_cursor_motion(struct wl_listener *listener, void *data) {
wlr_idle_notify_activity(seat->server->idle, seat->seat);
}
static void
drag_icon_damage(struct cg_drag_icon *drag_icon) {
struct cg_output *output;
wl_list_for_each(output, &drag_icon->seat->server->outputs, link) {
struct wlr_box *output_layout_box = wlr_output_layout_get_box(
output->server->output_layout, output->wlr_output);
output_damage_surface(output, drag_icon->wlr_drag_icon->surface,
drag_icon->lx - output_layout_box->x,
drag_icon->ly - output_layout_box->y, true);
}
}
static void
drag_icon_update_position(struct cg_drag_icon *drag_icon) {
struct wlr_drag_icon *wlr_icon = drag_icon->wlr_drag_icon;
struct cg_seat *seat = drag_icon->seat;
struct wlr_touch_point *point;
drag_icon_damage(drag_icon);
switch(wlr_icon->drag->grab_type) {
case WLR_DRAG_GRAB_KEYBOARD:
return;
@ -756,8 +698,7 @@ drag_icon_update_position(struct cg_drag_icon *drag_icon) {
drag_icon->ly = seat->touch_ly;
break;
}
drag_icon_damage(drag_icon);
wlr_scene_node_set_position(drag_icon->scene_node, drag_icon->lx, drag_icon->ly);
}
static void
@ -765,9 +706,9 @@ handle_drag_icon_destroy(struct wl_listener *listener, void *_data) {
struct cg_drag_icon *drag_icon =
wl_container_of(listener, drag_icon, destroy);
drag_icon_damage(drag_icon);
wl_list_remove(&drag_icon->link);
wl_list_remove(&drag_icon->destroy.link);
wlr_scene_node_destroy(drag_icon->scene_node);
free(drag_icon);
}
@ -813,6 +754,11 @@ handle_start_drag(struct wl_listener *listener, void *data) {
}
drag_icon->seat = seat;
drag_icon->wlr_drag_icon = wlr_drag_icon;
drag_icon->scene_node = wlr_scene_subsurface_tree_create(&seat->server->scene->node, wlr_drag_icon->surface);
if(!drag_icon->scene_node) {
free(drag_icon);
return;
}
drag_icon->destroy.notify = handle_drag_icon_destroy;
wl_signal_add(&wlr_drag_icon->events.destroy, &drag_icon->destroy);
@ -1038,5 +984,9 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) {
NULL);
}
wlr_scene_node_raise_to_top(view->scene_node);
process_cursor_motion(seat, -1);
struct wlr_box *box = wlr_output_layout_get_box(
server->output_layout, view->workspace->output->wlr_output);
wlr_scene_node_set_position(&view->workspace->output->bg->node, box->x, box->y);
}

1
seat.h
View file

@ -85,6 +85,7 @@ struct cg_drag_icon {
struct wl_list link; // seat::drag_icons
struct cg_seat *seat;
struct wlr_drag_icon *wlr_drag_icon;
struct wlr_scene_node *scene_node;
/* The drag icon has a position in layout coordinates. */
double lx, ly;

View file

@ -12,7 +12,7 @@
#include <stdio.h>
#include <string.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_box.h>
#include <wlr/util/box.h>
#include <wlr/types/wlr_output.h>
#include "input_manager.h"

View file

@ -35,6 +35,10 @@ struct cg_server {
struct wl_listener new_output;
struct wl_list output_priorities;
struct wlr_renderer *renderer;
struct wlr_allocator *allocator;
struct wlr_scene *scene;
struct wl_listener xdg_toplevel_decoration;
struct wl_listener new_xdg_shell_surface;
#if CG_HAS_XWAYLAND
@ -56,9 +60,6 @@ struct cg_server {
float *bg_color;
uint32_t views_curr_id;
uint32_t tiles_curr_id;
#ifdef DEBUG
bool debug_damage_tracking;
#endif
};
void

3
util.c
View file

@ -7,10 +7,11 @@
* See the LICENSE file accompanying this file.
*/
#include <wlr/types/wlr_box.h>
#include <wlr/util/box.h>
#include "util.h"
#include <stdlib.h>
#include <math.h>
int
scale_length(int length, int offset, double scale) {

197
view.c
View file

@ -12,11 +12,13 @@
#include <stdbool.h>
#include <string.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_box.h>
#include <wlr/util/box.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_output_layout.h>
#include "ipc_server.h"
#include "output.h"
@ -50,118 +52,6 @@ view_get_prev_view(struct cg_view *view) {
return prev;
}
void
view_damage_child(struct cg_view_child *child, bool whole) {
if(child->view != NULL) {
view_damage_part(child->view);
}
}
static void
view_child_handle_commit(struct wl_listener *listener, void *_data) {
struct cg_view_child *child = wl_container_of(listener, child, commit);
view_damage_child(child, false);
}
static void
subsurface_create(struct cg_view_child *parent, struct cg_view *view,
struct wlr_subsurface *wlr_subsurface);
static void
view_child_handle_new_subsurface(struct wl_listener *listener, void *data) {
struct cg_view_child *child =
wl_container_of(listener, child, new_subsurface);
struct wlr_subsurface *wlr_subsurface = data;
subsurface_create(child, child->view, wlr_subsurface);
}
void
view_child_finish(struct cg_view_child *child) {
if(!child) {
return;
}
if(child->view != NULL) {
view_damage_child(child, true);
}
struct cg_view_child *subchild, *tmpchild;
wl_list_for_each_safe(subchild, tmpchild, &child->children, parent_link) {
subchild->parent = NULL;
wl_list_remove(&subchild->parent_link);
}
wl_list_remove(&child->link);
if(child->parent != NULL) {
wl_list_remove(&child->parent_link);
}
wl_list_remove(&child->commit.link);
wl_list_remove(&child->new_subsurface.link);
}
void
view_child_init(struct cg_view_child *child, struct cg_view_child *parent,
struct cg_view *view, struct wlr_surface *wlr_surface) {
child->view = view;
child->parent = parent;
if(parent != NULL) {
wl_list_insert(&parent->children, &child->parent_link);
}
child->wlr_surface = wlr_surface;
wl_list_init(&child->children);
child->commit.notify = view_child_handle_commit;
wl_signal_add(&wlr_surface->events.commit, &child->commit);
child->new_subsurface.notify = view_child_handle_new_subsurface;
wl_signal_add(&wlr_surface->events.new_subsurface, &child->new_subsurface);
wl_list_insert(&view->children, &child->link);
}
static void
subsurface_destroy(struct cg_view_child *child) {
if(!child) {
return;
}
struct cg_subsurface *subsurface = (struct cg_subsurface *)child;
wl_list_remove(&subsurface->destroy.link);
view_child_finish(&subsurface->view_child);
free(subsurface);
}
static void
subsurface_handle_destroy(struct wl_listener *listener, void *_data) {
struct cg_subsurface *subsurface =
wl_container_of(listener, subsurface, destroy);
struct cg_view_child *view_child = (struct cg_view_child *)subsurface;
subsurface_destroy(view_child);
}
static void
subsurface_create(struct cg_view_child *parent, struct cg_view *view,
struct wlr_subsurface *wlr_subsurface) {
struct cg_subsurface *subsurface = calloc(1, sizeof(struct cg_subsurface));
if(!subsurface) {
return;
}
view_child_init(&subsurface->view_child, parent, view,
wlr_subsurface->surface);
subsurface->view_child.destroy = subsurface_destroy;
subsurface->wlr_subsurface = wlr_subsurface;
subsurface->destroy.notify = subsurface_handle_destroy;
wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
}
static void
handle_new_subsurface(struct wl_listener *listener, void *data) {
struct cg_view *view = wl_container_of(listener, view, new_subsurface);
struct wlr_subsurface *wlr_subsurface = data;
subsurface_create(NULL, view, wlr_subsurface);
}
char *
view_get_title(const struct cg_view *view) {
const char *title = view->impl->get_title(view);
@ -196,28 +86,6 @@ view_is_visible(const struct cg_view *view) {
return view_get_tile(view) != NULL;
}
void
view_damage(struct cg_view *view, bool whole) {
struct cg_tile *view_tile = view_get_tile(view);
if(view_tile != NULL &&
(view->wlr_surface->current.width != view_tile->tile.width ||
view->wlr_surface->current.height != view_tile->tile.height)) {
view_maximize(view, view_tile);
}
output_damage_surface(view->workspace->output, view->wlr_surface, view->ox,
view->oy, whole);
}
void
view_damage_part(struct cg_view *view) {
view_damage(view, false);
}
void
view_damage_whole(struct cg_view *view) {
view_damage(view, true);
}
void
view_activate(struct cg_view *view, bool activate) {
if(view != NULL) {
@ -229,25 +97,13 @@ void
view_maximize(struct cg_view *view, struct cg_tile *tile) {
view->ox = tile->tile.x;
view->oy = tile->tile.y;
struct wlr_box *box = wlr_output_layout_get_box(
view->server->output_layout, view->workspace->output->wlr_output);
wlr_scene_node_set_position(view->scene_node, view->ox+box->x, view->oy+box->y);
view->impl->maximize(view, tile->tile.width, tile->tile.height);
view->tile = tile;
}
void
view_for_each_surface(struct cg_view *view,
wlr_surface_iterator_func_t iterator, void *data) {
view->impl->for_each_surface(view, iterator, data);
}
void
view_for_each_popup(struct cg_view *view, wlr_surface_iterator_func_t iterator,
void *data) {
if(!view->impl->for_each_popup) {
return;
}
view->impl->for_each_popup(view, iterator, data);
}
void
view_unmap(struct cg_view *view) {
@ -261,19 +117,13 @@ view_unmap(struct cg_view *view) {
return;
}
struct cg_view_child *child, *tmp;
wl_list_for_each_safe(child, tmp, &view->children, link) {
child->destroy(child);
}
wlr_scene_node_destroy(view->scene_node);
#if CG_HAS_XWAYLAND
if((view->type != CG_XWAYLAND_VIEW || xwayland_view_should_manage(view)))
#endif
{
struct cg_tile *view_tile = view_get_tile(view);
if(view_tile != NULL) {
wlr_output_damage_add_box(view_tile->workspace->output->damage,
&view_tile->tile);
}
struct cg_view *prev = view_get_prev_view(view);
if(view == view->server->seat->focused_view) {
seat_set_focus(view->server->seat, prev);
@ -285,8 +135,6 @@ view_unmap(struct cg_view *view) {
}
view_tile = view_get_tile(view);
if(view_tile != NULL) {
wlr_output_damage_add_box(view_tile->workspace->output->damage,
&view_tile->tile);
view_tile->view = prev;
if(prev != NULL) {
view_maximize(prev, view_tile);
@ -295,7 +143,6 @@ view_unmap(struct cg_view *view) {
}
#if CG_HAS_XWAYLAND
else {
view_damage_whole(view);
if(view->server->seat->seat->keyboard_state.focused_surface == NULL ||
view->server->seat->seat->keyboard_state.focused_surface ==
view->wlr_surface) {
@ -307,7 +154,6 @@ view_unmap(struct cg_view *view) {
wl_list_remove(&view->link);
wl_list_remove(&view->new_subsurface.link);
view->wlr_surface = NULL;
ipc_send_event(view->workspace->server,
"view_unmap(view_id:%d,tile_id:%d,workspace:%d,output:%s,"
@ -321,21 +167,12 @@ view_map(struct cg_view *view, struct wlr_surface *surface,
struct cg_output *output = ws->output;
view->wlr_surface = surface;
struct wlr_subsurface *subsurface;
wl_list_for_each(subsurface, &view->wlr_surface->subsurfaces_above,
parent_link) {
subsurface_create(NULL, view, subsurface);
view->scene_node=wlr_scene_subsurface_tree_create(&ws->scene->node, surface);
if(!view->scene_node) {
wl_resource_post_no_memory(surface->resource);
return;
}
wl_list_for_each(subsurface, &view->wlr_surface->subsurfaces_below,
parent_link) {
subsurface_create(NULL, view, subsurface);
}
view->new_subsurface.notify = handle_new_subsurface;
wl_signal_add(&view->wlr_surface->events.new_subsurface,
&view->new_subsurface);
view->scene_node->data=view;
view->workspace = ws;
#if CG_HAS_XWAYLAND
@ -381,12 +218,4 @@ view_init(struct cg_view *view, enum cg_view_type type,
view->impl = impl;
view->id = server->views_curr_id;
++server->views_curr_id;
wl_list_init(&view->children);
}
struct wlr_surface *
view_wlr_surface_at(const struct cg_view *view, double sx, double sy,
double *sub_x, double *sub_y) {
return view->impl->wlr_surface_at(view, sx, sy, sub_x, sub_y);
}

53
view.h
View file

@ -21,9 +21,9 @@ struct cg_view {
struct cg_workspace *workspace;
struct cg_server *server;
struct wl_list link; // server::views
struct wl_list children; // cg_view_child::link
struct wlr_surface *wlr_surface;
struct cg_tile *tile;
struct wlr_scene_node *scene_node;
/* The view has a position in output coordinates. */
int ox, oy;
@ -31,7 +31,6 @@ struct cg_view {
enum cg_view_type type;
const struct cg_view_impl *impl;
struct wl_listener new_subsurface;
uint32_t id;
};
@ -42,34 +41,6 @@ struct cg_view_impl {
void (*close)(struct cg_view *view);
void (*maximize)(struct cg_view *view, int width, int height);
void (*destroy)(struct cg_view *view);
void (*for_each_surface)(struct cg_view *view,
wlr_surface_iterator_func_t iterator, void *data);
void (*for_each_popup)(struct cg_view *view,
wlr_surface_iterator_func_t iterator, void *data);
struct wlr_surface *(*wlr_surface_at)(const struct cg_view *view, double sx,
double sy, double *sub_x,
double *sub_y);
};
struct cg_view_child {
struct cg_view *view;
struct cg_view_child *parent;
struct wl_list children;
struct wlr_surface *wlr_surface;
struct wl_list link;
struct wl_list parent_link;
struct wl_listener commit;
struct wl_listener new_subsurface;
void (*destroy)(struct cg_view_child *child);
};
struct cg_subsurface {
struct cg_view_child view_child;
struct wlr_subsurface *wlr_subsurface;
struct wl_listener destroy;
};
char *
@ -81,20 +52,8 @@ view_is_primary(const struct cg_view *view);
bool
view_is_visible(const struct cg_view *view);
void
view_damage_part(struct cg_view *view);
void
view_damage_whole(struct cg_view *view);
void
view_damage_child(struct cg_view_child *view, bool whole);
void
view_activate(struct cg_view *view, bool activate);
void
view_for_each_surface(struct cg_view *view,
wlr_surface_iterator_func_t iterator, void *data);
void
view_for_each_popup(struct cg_view *view, wlr_surface_iterator_func_t iterator,
void *data);
void
view_unmap(struct cg_view *view);
void
view_maximize(struct cg_view *view, struct cg_tile *tile);
@ -106,16 +65,6 @@ view_destroy(struct cg_view *view);
void
view_init(struct cg_view *view, enum cg_view_type type,
const struct cg_view_impl *impl, struct cg_server *server);
struct wlr_surface *
view_wlr_surface_at(const struct cg_view *view, double sx, double sy,
double *sub_x, double *sub_y);
void
view_child_finish(struct cg_view_child *child);
void
view_child_init(struct cg_view_child *child, struct cg_view_child *parent,
struct cg_view *view, struct wlr_surface *wlr_surface);
struct cg_view *
view_get_prev_view(struct cg_view *view);

View file

@ -13,6 +13,7 @@
#include <wayland-server-core.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/util/log.h>
#include <wlr/types/wlr_scene.h>
#include "message.h"
#include "output.h"
@ -57,6 +58,7 @@ full_screen_workspace(struct cg_output *output) {
}
workspace->server = output->server;
workspace->num = -1;
workspace->scene = wlr_scene_tree_create(&output->scene_output->scene->node);
if(full_screen_workspace_tiles(output->server->output_layout,
output->wlr_output, workspace,
&output->server->tiles_curr_id) != 0) {
@ -95,3 +97,10 @@ workspace_free(struct cg_workspace *workspace) {
workspace_free_tiles(workspace);
free(workspace);
}
void
workspace_focus(struct cg_output *outp, int ws) {
wlr_scene_node_place_above(&outp->bg->node,&outp->workspaces[outp->curr_workspace]->scene->node);
wlr_scene_node_place_above(&outp->workspaces[ws]->scene->node,&outp->bg->node);
outp->curr_workspace=ws;
}

View file

@ -1,7 +1,7 @@
#ifndef CG_WORKSPACE_H
#define CG_WORKSPACE_H
#include <wlr/types/wlr_box.h>
#include <wlr/util/box.h>
struct cg_output;
struct cg_server;
@ -20,6 +20,7 @@ struct cg_workspace {
struct wl_list views;
struct wl_list unmanaged_views;
struct cg_output *output;
struct wlr_scene_tree *scene;
struct cg_tile *focused_tile;
uint32_t num;
@ -38,5 +39,7 @@ void
workspace_free(struct cg_workspace *workspace);
void
workspace_focus_tile(struct cg_workspace *ws, struct cg_tile *tile);
void
workspace_focus(struct cg_output *outp, int ws);
#endif

View file

@ -10,13 +10,15 @@
#define _POSIX_C_SOURCE 200809L
#include <stdbool.h>
#include <assert.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_box.h>
#include <wlr/util/box.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/edges.h>
#include <wlr/util/log.h>
#include <wlr/types/wlr_scene.h>
#include "output.h"
#include "server.h"
@ -24,10 +26,29 @@
#include "workspace.h"
#include "xdg_shell.h"
static struct cg_view *
popup_get_view(struct wlr_xdg_popup *popup) {
while(true) {
if(popup->parent == NULL || !wlr_surface_is_xdg_surface(popup->parent)) {
return NULL;
}
struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(popup->parent);
switch(xdg_surface->role) {
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
return xdg_surface->data;
case WLR_XDG_SURFACE_ROLE_POPUP:
popup=xdg_surface->popup;
break;
case WLR_XDG_SURFACE_ROLE_NONE:
return NULL;
}
}
}
static void
xdg_decoration_handle_destroy(struct wl_listener *listener, void *_data) {
struct cg_xdg_decoration *xdg_decoration =
wl_container_of(listener, xdg_decoration, destroy);
xdg_decoration_handle_destroy(struct wl_listener *listener, void *data)
{
struct cg_xdg_decoration *xdg_decoration = wl_container_of(listener, xdg_decoration, destroy);
wl_list_remove(&xdg_decoration->destroy.link);
wl_list_remove(&xdg_decoration->request_mode.link);
@ -53,54 +74,8 @@ xdg_decoration_handle_request_mode(struct wl_listener *listener, void *_data) {
#endif
static void
xdg_popup_destroy(struct cg_view_child *child) {
if(!child) {
return;
}
view_damage_child(child, true);
struct cg_xdg_popup *popup = (struct cg_xdg_popup *)child;
wl_list_remove(&popup->destroy.link);
wl_list_remove(&popup->map.link);
wl_list_remove(&popup->unmap.link);
wl_list_remove(&popup->new_popup.link);
view_child_finish(&popup->view_child);
free(popup);
}
static void
handle_xdg_popup_map(struct wl_listener *listener, void *_data) {
struct cg_xdg_popup *popup = wl_container_of(listener, popup, map);
view_damage_whole(popup->view_child.view);
}
static void
handle_xdg_popup_unmap(struct wl_listener *listener, void *_data) {
struct cg_xdg_popup *popup = wl_container_of(listener, popup, unmap);
view_damage_whole(popup->view_child.view);
}
static void
handle_xdg_popup_destroy(struct wl_listener *listener, void *_data) {
struct cg_xdg_popup *popup = wl_container_of(listener, popup, destroy);
struct cg_view_child *view_child = (struct cg_view_child *)popup;
xdg_popup_destroy(view_child);
}
static void
xdg_popup_create(struct cg_view *view, struct wlr_xdg_popup *wlr_popup);
static void
popup_handle_new_xdg_popup(struct wl_listener *listener, void *data) {
struct cg_xdg_popup *popup = wl_container_of(listener, popup, new_popup);
struct wlr_xdg_popup *wlr_popup = data;
xdg_popup_create(popup->view_child.view, wlr_popup);
}
static void
popup_unconstrain(struct cg_xdg_popup *popup) {
struct cg_view *view = popup->view_child.view;
struct wlr_box *popup_box = &popup->wlr_popup->geometry;
popup_unconstrain(struct cg_view *view, struct wlr_xdg_popup *popup) {
struct wlr_box *popup_box = &popup->geometry;
struct wlr_output_layout *output_layout = view->server->output_layout;
struct wlr_box *view_output_box = wlr_output_layout_get_box(
@ -116,37 +91,7 @@ popup_unconstrain(struct cg_xdg_popup *popup) {
.width = output_box->width,
.height = output_box->height};
wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &output_toplevel_box);
}
static void
xdg_popup_create(struct cg_view *view, struct wlr_xdg_popup *wlr_popup) {
struct cg_xdg_popup *popup = calloc(1, sizeof(struct cg_xdg_popup));
if(!popup) {
return;
}
popup->wlr_popup = wlr_popup;
view_child_init(&popup->view_child, NULL, view, wlr_popup->base->surface);
popup->view_child.destroy = xdg_popup_destroy;
popup->destroy.notify = handle_xdg_popup_destroy;
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
popup->map.notify = handle_xdg_popup_map;
wl_signal_add(&wlr_popup->base->events.map, &popup->map);
popup->unmap.notify = handle_xdg_popup_unmap;
wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap);
popup->new_popup.notify = popup_handle_new_xdg_popup;
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
popup_unconstrain(popup);
}
static void
handle_new_xdg_popup(struct wl_listener *listener, void *data) {
struct cg_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, new_popup);
struct wlr_xdg_popup *wlr_popup = data;
xdg_popup_create(&xdg_shell_view->view, wlr_popup);
wlr_xdg_popup_unconstrain_from_box(popup, &output_toplevel_box);
}
static struct cg_xdg_shell_view *
@ -206,31 +151,6 @@ destroy(struct cg_view *view) {
free(xdg_shell_view);
}
static void
for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator,
void *data) {
struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view);
wlr_xdg_surface_for_each_surface(xdg_shell_view->xdg_surface, iterator,
data);
}
static void
for_each_popup(struct cg_view *view, wlr_surface_iterator_func_t iterator,
void *data) {
struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view);
wlr_xdg_surface_for_each_popup_surface(xdg_shell_view->xdg_surface,
iterator, data);
}
static struct wlr_surface *
wlr_surface_at(const struct cg_view *view, double sx, double sy, double *sub_x,
double *sub_y) {
const struct cg_xdg_shell_view *xdg_shell_view =
xdg_shell_view_from_const_view(view);
return wlr_xdg_surface_surface_at(xdg_shell_view->xdg_surface, sx, sy,
sub_x, sub_y);
}
static void
handle_xdg_shell_surface_request_fullscreen(struct wl_listener *listener,
void *data) {
@ -241,23 +161,12 @@ handle_xdg_shell_surface_request_fullscreen(struct wl_listener *listener,
event->fullscreen);
}
static void
handle_xdg_shell_surface_commit(struct wl_listener *listener, void *_data) {
struct cg_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, commit);
struct cg_view *view = &xdg_shell_view->view;
view_damage_part(view);
}
static void
handle_xdg_shell_surface_unmap(struct wl_listener *listener, void *_data) {
struct cg_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, unmap);
struct cg_view *view = &xdg_shell_view->view;
wl_list_remove(&xdg_shell_view->new_popup.link);
wl_list_remove(&xdg_shell_view->commit.link);
view_unmap(view);
}
@ -267,17 +176,9 @@ handle_xdg_shell_surface_map(struct wl_listener *listener, void *_data) {
wl_container_of(listener, xdg_shell_view, map);
struct cg_view *view = &xdg_shell_view->view;
xdg_shell_view->commit.notify = handle_xdg_shell_surface_commit;
wl_signal_add(&xdg_shell_view->xdg_surface->surface->events.commit,
&xdg_shell_view->commit);
xdg_shell_view->new_popup.notify = handle_new_xdg_popup;
wl_signal_add(&xdg_shell_view->xdg_surface->events.new_popup,
&xdg_shell_view->new_popup);
view_map(view, xdg_shell_view->xdg_surface->surface,
view->server->curr_output
->workspaces[view->server->curr_output->curr_workspace]);
view_damage_whole(view);
}
static void
@ -301,43 +202,75 @@ static const struct cg_view_impl xdg_shell_view_impl = {
.activate = activate,
.close = close,
.maximize = maximize,
.destroy = destroy,
.for_each_surface = for_each_surface,
.for_each_popup = for_each_popup,
.wlr_surface_at = wlr_surface_at,
.destroy = destroy
};
void
handle_xdg_shell_surface_new(struct wl_listener *listener, void *data) {
struct cg_server *server =
wl_container_of(listener, server, new_xdg_shell_surface);
handle_xdg_shell_surface_new(struct wl_listener *listener, void *data)
{
struct cg_server *server = wl_container_of(listener, server, new_xdg_shell_surface);
struct wlr_xdg_surface *xdg_surface = data;
if(xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
return;
switch (xdg_surface->role) {
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:;
struct cg_xdg_shell_view *xdg_shell_view = calloc(1, sizeof(struct cg_xdg_shell_view));
if (!xdg_shell_view) {
wlr_log(WLR_ERROR, "Failed to allocate XDG Shell view");
return;
}
view_init(&xdg_shell_view->view, CG_XDG_SHELL_VIEW, &xdg_shell_view_impl,server);
xdg_shell_view->xdg_surface = xdg_surface;
xdg_shell_view->map.notify = handle_xdg_shell_surface_map;
wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
xdg_shell_view->unmap.notify = handle_xdg_shell_surface_unmap;
wl_signal_add(&xdg_surface->events.unmap, &xdg_shell_view->unmap);
xdg_shell_view->destroy.notify = handle_xdg_shell_surface_destroy;
wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy);
xdg_shell_view->request_fullscreen.notify = handle_xdg_shell_surface_request_fullscreen;
wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &xdg_shell_view->request_fullscreen);
xdg_surface->data = xdg_shell_view;
break;
case WLR_XDG_SURFACE_ROLE_POPUP:;
struct wlr_xdg_popup *popup = xdg_surface->popup;
struct cg_view *view = popup_get_view(popup);
if (view == NULL) {
return;
}
struct wlr_scene_node *parent_scene_node = NULL;
struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface(popup->parent);
switch (parent->role) {
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:;
parent_scene_node = view->scene_node;
break;
case WLR_XDG_SURFACE_ROLE_POPUP:
parent_scene_node = parent->data;
break;
case WLR_XDG_SURFACE_ROLE_NONE:
break;
}
if (parent_scene_node == NULL) {
return;
}
struct wlr_scene_node *popup_scene_node = wlr_scene_xdg_surface_create(parent_scene_node, xdg_surface);
if (popup_scene_node == NULL) {
wlr_log(WLR_ERROR, "Failed to allocate scene-graph node for XDG popup");
return;
}
popup_unconstrain(view, popup);
xdg_surface->data = popup_scene_node;
break;
case WLR_XDG_SURFACE_ROLE_NONE:
assert(false); // unreachable
}
struct cg_xdg_shell_view *xdg_shell_view =
calloc(1, sizeof(struct cg_xdg_shell_view));
if(!xdg_shell_view) {
wlr_log(WLR_ERROR, "Failed to allocate XDG Shell view");
return;
}
view_init(&xdg_shell_view->view, CG_XDG_SHELL_VIEW, &xdg_shell_view_impl,
server);
xdg_shell_view->xdg_surface = xdg_surface;
xdg_shell_view->map.notify = handle_xdg_shell_surface_map;
wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
xdg_shell_view->unmap.notify = handle_xdg_shell_surface_unmap;
wl_signal_add(&xdg_surface->events.unmap, &xdg_shell_view->unmap);
xdg_shell_view->destroy.notify = handle_xdg_shell_surface_destroy;
wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy);
xdg_shell_view->request_fullscreen.notify =
handle_xdg_shell_surface_request_fullscreen;
wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
&xdg_shell_view->request_fullscreen);
}
void

View file

@ -10,19 +10,7 @@ struct cg_xdg_shell_view {
struct wl_listener destroy;
struct wl_listener unmap;
struct wl_listener map;
struct wl_listener commit;
struct wl_listener request_fullscreen;
struct wl_listener new_popup;
};
struct cg_xdg_popup {
struct cg_view_child view_child;
struct wlr_xdg_popup *wlr_popup;
struct wl_listener destroy;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener new_popup;
};
struct cg_xdg_decoration {

View file

@ -10,7 +10,7 @@
#include <X11/Xutil.h>
#include <stdbool.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_box.h>
#include <wlr/util/box.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/util/log.h>
@ -72,29 +72,15 @@ close(struct cg_view *view) {
static void
maximize(struct cg_view *view, int width, int height) {
struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view);
struct cg_output *output = view->workspace->output;
struct wlr_box *box = wlr_output_layout_get_box(
view->server->output_layout, view->workspace->output->wlr_output);
struct wlr_xwayland_surface_size_hints *hints =
xwayland_view->xwayland_surface->size_hints;
if(hints != NULL && hints->flags & PMaxSize) {
if(width > hints->max_width) {
wlr_output_damage_add_box(output->damage,
&(struct wlr_box){.x = view->ox + box->x,
.y = view->oy + box->y,
.width = width,
.height = height});
width = hints->max_width;
}
if(height > hints->max_height) {
wlr_output_damage_add_box(output->damage,
&(struct wlr_box){.x = view->ox + box->x,
.y = view->oy + box->y,
.width = width,
.height = height});
height = hints->max_height;
}
}
@ -110,18 +96,6 @@ destroy(struct cg_view *view) {
free(xwayland_view);
}
static void
for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator,
void *data) {
wlr_surface_for_each_surface(view->wlr_surface, iterator, data);
}
static struct wlr_surface *
wlr_surface_at(const struct cg_view *view, double sx, double sy, double *sub_x,
double *sub_y) {
return wlr_surface_surface_at(view->wlr_surface, sx, sy, sub_x, sub_y);
}
static void
handle_xwayland_surface_request_fullscreen(struct wl_listener *listener,
void *data) {
@ -133,33 +107,12 @@ handle_xwayland_surface_request_fullscreen(struct wl_listener *listener,
xwayland_surface->fullscreen);
}
static void
handle_xwayland_surface_commit(struct wl_listener *listener, void *_data) {
struct cg_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, commit);
struct cg_view *view = &xwayland_view->view;
/* xwayland surface has moved */
if(xwayland_view->xwayland_surface->x != view->ox ||
xwayland_view->xwayland_surface->y != view->oy) {
output_damage_surface(view->workspace->output, view->wlr_surface,
view->ox, view->oy, true);
view->ox = xwayland_view->xwayland_surface->x;
view->oy = xwayland_view->xwayland_surface->y;
output_damage_surface(view->workspace->output, view->wlr_surface,
view->ox, view->oy, true);
} else {
view_damage_part(view);
}
}
static void
handle_xwayland_surface_unmap(struct wl_listener *listener, void *_data) {
struct cg_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, unmap);
struct cg_view *view = &xwayland_view->view;
wl_list_remove(&xwayland_view->commit.link);
view_unmap(view);
}
@ -174,15 +127,9 @@ handle_xwayland_surface_map(struct wl_listener *listener, void *_data) {
view->oy = xwayland_view->xwayland_surface->y;
}
xwayland_view->commit.notify = handle_xwayland_surface_commit;
wl_signal_add(&xwayland_view->xwayland_surface->surface->events.commit,
&xwayland_view->commit);
view_map(view, xwayland_view->xwayland_surface->surface,
view->server->curr_output
->workspaces[view->server->curr_output->curr_workspace]);
view_damage_whole(view);
}
static void
@ -207,10 +154,6 @@ static const struct cg_view_impl xwayland_view_impl = {
.close = close,
.maximize = maximize,
.destroy = destroy,
.for_each_surface = for_each_surface,
/* XWayland doesn't have a separate popup iterator. */
.for_each_popup = NULL,
.wlr_surface_at = wlr_surface_at,
};
void

View file

@ -10,7 +10,6 @@ struct cg_xwayland_view {
struct wl_listener destroy;
struct wl_listener unmap;
struct wl_listener map;
struct wl_listener commit;
struct wl_listener request_fullscreen;
};