mirror of
https://cagebreak.project-repo.co/cagebreak.git
synced 2026-08-09 15:19:11 +02:00
Switch to wlr_scene api
This commit is contained in:
parent
38fee7ea71
commit
c5800b2223
23 changed files with 404 additions and 1290 deletions
73
cagebreak.c
73
cagebreak.c
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
31
keybinding.c
31
keybinding.c
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
102
message.c
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
476
output.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
26
output.h
26
output.h
|
|
@ -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
277
render.c
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
9
render.h
9
render.h
|
|
@ -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
88
seat.c
|
|
@ -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
1
seat.h
|
|
@ -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;
|
||||
|
|
|
|||
2
server.c
2
server.c
|
|
@ -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"
|
||||
|
|
|
|||
7
server.h
7
server.h
|
|
@ -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
3
util.c
|
|
@ -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
197
view.c
|
|
@ -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
53
view.h
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
249
xdg_shell.c
249
xdg_shell.c
|
|
@ -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
|
||||
|
|
|
|||
12
xdg_shell.h
12
xdg_shell.h
|
|
@ -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 {
|
||||
|
|
|
|||
59
xwayland.c
59
xwayland.c
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue