swc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/swc
Log | Files | Refs | README | LICENSE

commit 300de285384cdf277c25941854807c449d416375
parent 0dc0ed350e20a22189a4f31e7dba2ee5dd52167c
Author: Michael Forney <mforney@mforney.org>
Date:   Thu, 16 Jan 2014 18:06:26 -0800

Move common state to swc_view

Diffstat:
Mlibswc/compositor.c | 355++++++++++++++++++++++++++++++++-----------------------------------------------
Mlibswc/compositor.h | 2+-
Mlibswc/pointer.c | 19+++++--------------
Mlibswc/shell_surface.c | 9+++++----
Mlibswc/surface.c | 138++++++++++++++++++++++++++++++++++---------------------------------------------
Mlibswc/surface.h | 12+-----------
Mlibswc/view.c | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlibswc/view.h | 42+++++++++++++++++++++++++++++++++---------
Mlibswc/window.c | 3++-
Mlibswc/xwm.c | 3++-
10 files changed, 374 insertions(+), 329 deletions(-)

diff --git a/libswc/compositor.c b/libswc/compositor.c @@ -23,6 +23,7 @@ struct view { struct swc_view base; + struct wl_listener event_listener; struct swc_compositor * compositor; struct swc_surface * surface; @@ -40,9 +41,7 @@ struct view bool damaged; } border; - bool mapped; - - struct wl_listener surface_event_listener; + struct wl_list link; }; /* Rendering {{{ */ @@ -51,50 +50,39 @@ struct render_target { struct wld_buffer * buffer; struct swc_rectangle geometry; + uint32_t mask; }; -static void repaint_surface(struct render_target * target, - struct swc_surface * surface, - pixman_region32_t * damage) +static void repaint_view(struct render_target * target, struct view * view, + pixman_region32_t * damage) { - pixman_region32_t surface_damage; - pixman_region32_t border_damage; - pixman_region32_t surface_region; - struct view * view = (void *) surface->view; + pixman_region32_t view_region, view_damage, border_damage; + const struct swc_rectangle * geometry = &view->base.geometry; - if (!surface->state.buffer) + if (!view->base.buffer) return; - pixman_region32_init_with_extents(&surface_damage, &view->extents); + pixman_region32_init_rect(&view_region, geometry->x, geometry->y, + geometry->width, geometry->height); + pixman_region32_init_with_extents(&view_damage, &view->extents); pixman_region32_init(&border_damage); - pixman_region32_init_rect - (&surface_region, surface->geometry.x, surface->geometry.y, - surface->geometry.width, surface->geometry.height); - pixman_region32_intersect(&surface_damage, &surface_damage, damage); - pixman_region32_subtract(&surface_damage, &surface_damage, &view->clip); - pixman_region32_subtract(&border_damage, &surface_damage, &surface_region); - pixman_region32_intersect(&surface_damage, &surface_damage, - &surface_region); + pixman_region32_intersect(&view_damage, &view_damage, damage); + pixman_region32_subtract(&view_damage, &view_damage, &view->clip); + pixman_region32_subtract(&border_damage, &view_damage, &view_region); + pixman_region32_intersect(&view_damage, &view_damage, &view_region); - pixman_region32_fini(&surface_region); + pixman_region32_fini(&view_region); - if (pixman_region32_not_empty(&surface_damage)) + if (pixman_region32_not_empty(&view_damage)) { - DEBUG("\tDRM surface %u { x: %d, y: %d, w: %u, h: %u }\n", - wl_resource_get_id(surface->resource), - surface->geometry.x, surface->geometry.y, - surface->geometry.width, surface->geometry.height); - - pixman_region32_translate(&surface_damage, - -surface->geometry.x, -surface->geometry.y); - wld_copy_region(swc.drm->renderer, surface->state.buffer->wld, - surface->geometry.x - target->geometry.x, - surface->geometry.y - target->geometry.y, - &surface_damage); + pixman_region32_translate(&view_damage, -geometry->x, -geometry->y); + wld_copy_region(swc.drm->renderer, view->base.buffer->wld, + geometry->x - target->geometry.x, + geometry->y - target->geometry.y, &view_damage); } - pixman_region32_fini(&surface_damage); + pixman_region32_fini(&view_damage); /* Draw border */ if (pixman_region32_not_empty(&border_damage)) @@ -112,9 +100,9 @@ static void repaint_surface(struct render_target * target, static void renderer_repaint(struct render_target * target, pixman_region32_t * damage, pixman_region32_t * base_damage, - struct wl_list * surfaces) + struct wl_list * views) { - struct swc_surface * surface; + struct view * view; DEBUG("Rendering to target { x: %d, y: %d, w: %u, h: %u }\n", target->geometry.x, target->geometry.y, @@ -128,20 +116,21 @@ static void renderer_repaint(struct render_target * target, wld_fill_region(swc.drm->renderer, 0xff000000, base_damage); } - wl_list_for_each_reverse(surface, surfaces, link) + wl_list_for_each_reverse(view, views, link) { - if (swc_rectangle_overlap(&target->geometry, &surface->geometry)) - repaint_surface(target, surface, damage); + if (view->base.screens & target->mask) + repaint_view(target, view, damage); } wld_flush(swc.drm->renderer); } -static void renderer_attach(struct view * view, struct swc_buffer * buffer) +static bool renderer_attach(struct view * view, struct swc_buffer * buffer) { + return true; } -static void renderer_flush_surface(struct swc_surface * surface) +static void renderer_flush_view(struct view * view) { } @@ -150,12 +139,11 @@ static void renderer_flush_surface(struct swc_surface * surface) /* Surface Views {{{ */ /** - * Adds damage from the region below a surface, taking into account it's clip + * Adds damage from the region below a view, taking into account it's clip * region, to the region specified by `damage'. */ -static void damage_below_surface(struct swc_surface * surface) +static void damage_below_view(struct view * view) { - struct view * view = (void *) surface->view; struct swc_compositor * compositor = view->compositor; pixman_region32_t damage_below; @@ -169,101 +157,40 @@ static void damage_below_surface(struct swc_surface * surface) /** * Completely damages the surface and its border. */ -static void damage_surface(struct swc_surface * surface) +static void damage_view(struct view * view) { - struct view * view = (void *) surface->view; - printf("damaging surface\n"); - - pixman_region32_fini(&surface->state.damage); - pixman_region32_init_rect(&surface->state.damage, 0, 0, - surface->geometry.width, - surface->geometry.height); + damage_below_view(view); view->border.damaged = true; } -static void update_extents(struct swc_surface * surface) +static void update_extents(struct view * view) { - struct view * view = (void *) surface->view; - - view->extents.x1 = surface->geometry.x - view->border.width; - view->extents.y1 = surface->geometry.y - view->border.width; - view->extents.x2 = surface->geometry.x + surface->geometry.width + view->extents.x1 = view->base.geometry.x - view->border.width; + view->extents.y1 = view->base.geometry.y - view->border.width; + view->extents.x2 = view->base.geometry.x + view->base.geometry.width + view->border.width; - view->extents.y2 = surface->geometry.y + surface->geometry.height + view->extents.y2 = view->base.geometry.y + view->base.geometry.height + view->border.width; /* Damage border. */ view->border.damaged = true; } -static void update_screens(struct swc_surface * surface) +static bool update(struct swc_view * base) { - struct view * view = (void *) surface->view; - uint32_t old_screens = surface->screens, new_screens = 0, - entered_screens, left_screens, changed_screens; + struct view * view = (void *) base; struct swc_screen_internal * screen; - struct swc_output * output; - struct wl_client * client; - struct wl_resource * resource; - if (view->mapped) - { - wl_list_for_each(screen, &swc.screens, link) - { - if (swc_rectangle_overlap(&screen->base.geometry, &surface->geometry)) - new_screens |= swc_screen_mask(screen); - } - } - - if (new_screens == old_screens) - return; - - entered_screens = new_screens & ~old_screens; - left_screens = old_screens & ~new_screens; - changed_screens = old_screens ^ new_screens; + if (!view->base.visible) + return false; wl_list_for_each(screen, &swc.screens, link) { - if (!(changed_screens & swc_screen_mask(screen))) - continue; - - output = CONTAINER_OF(screen->outputs.next, typeof(*output), link); - client = wl_resource_get_client(surface->resource); - resource = wl_resource_find_for_client(&output->resources, client); - - if (resource) - { - if (entered_screens & swc_screen_mask(screen)) - wl_surface_send_enter(surface->resource, resource); - else if (left_screens & swc_screen_mask(screen)) - wl_surface_send_leave(surface->resource, resource); - } + if (view->base.screens & swc_screen_mask(screen)) + swc_compositor_schedule_update(view->compositor, screen); } - surface->screens = new_screens; -} - -static void update(struct swc_view * view); - -static void handle_surface_event(struct wl_listener * listener, void * data) -{ - struct view * view - = CONTAINER_OF(listener, typeof(*view), surface_event_listener); - struct swc_event * event = data; - struct swc_surface_event_data * event_data = event->data; - struct swc_surface * surface = event_data->surface; - - switch (event->type) - { - case SWC_SURFACE_EVENT_TYPE_RESIZE: - damage_below_surface(surface); - - update_extents(surface); - update(&view->base); - update_screens(surface); - - break; - } + return true; } static void remove_(struct swc_view * base) @@ -271,69 +198,84 @@ static void remove_(struct swc_view * base) struct view * view = (void *) base; swc_compositor_surface_hide(view->surface); - wl_list_remove(&view->surface_event_listener.link); pixman_region32_fini(&view->clip); free(view); } -static void attach(struct swc_view * base, struct swc_buffer * buffer) +static bool attach(struct swc_view * base, struct swc_buffer * buffer) { struct view * view = (void *) base; - renderer_attach(view, buffer); + if (!renderer_attach(view, buffer)) + return false; + + return true; } -static void update(struct swc_view * base) +static bool move(struct swc_view * base, int32_t x, int32_t y) { struct view * view = (void *) base; - struct swc_screen_internal * screen; - - if (!view->mapped) - return; - wl_list_for_each(screen, &swc.screens, link) + if (view->base.visible) { - if (view->surface->screens & swc_screen_mask(screen)) - swc_compositor_schedule_update(view->compositor, screen); + damage_below_view(view); + update(&view->base); } + + return true; } -static void move(struct swc_view * base, int32_t x, int32_t y) +static void resize(struct swc_view * base) { struct view * view = (void *) base; - struct swc_surface * surface = view->surface; - - if (x == surface->geometry.x && y == surface->geometry.y) - return; - - if (view->mapped) - damage_below_surface(surface); - surface->geometry.x = x; - surface->geometry.y = y; - - update_extents(surface); - - if (view->mapped) + if (view->base.visible) { - /* Assume worst-case no clipping until we draw the next frame (in case - * the surface gets moved again before that). */ - pixman_region32_init(&view->clip); - - damage_below_surface(surface); - update(&view->base); - update_screens(surface); + damage_below_view(view); update(&view->base); } } -const struct swc_view_impl view_impl = { - .remove = &remove_, - .attach = &attach, +const static struct swc_view_impl view_impl = { .update = &update, - .move = &move + .attach = &attach, + .move = &move, + .resize = &resize, + .remove = &remove_, }; +static void handle_view_event(struct wl_listener * listener, void * data) +{ + struct view * view = CONTAINER_OF(listener, typeof(*view), event_listener); + struct swc_event * event = data; + + switch (event->type) + { + case SWC_VIEW_EVENT_MOVED: + update_extents(view); + + if (view->base.visible) + { + /* Assume worst-case no clipping until we draw the next frame (in case + * the surface gets moved again before that). */ + pixman_region32_init(&view->clip); + + damage_below_view(view); + update(&view->base); + } + break; + case SWC_VIEW_EVENT_RESIZED: + update_extents(view); + + if (view->base.visible) + { + damage_below_view(view); + update(&view->base); + } + break; + } +} + bool swc_compositor_add_surface(struct swc_compositor * compositor, struct swc_surface * surface) { @@ -345,18 +287,18 @@ bool swc_compositor_add_surface(struct swc_compositor * compositor, return false; swc_view_initialize(&view->base, &view_impl); + view->base.visible = false; + view->event_listener.notify = &handle_view_event; + wl_signal_add(&view->base.event_signal, &view->event_listener); view->compositor = compositor; view->surface = surface; - view->mapped = false; - view->extents.x1 = surface->geometry.x; - view->extents.y1 = surface->geometry.y; - view->extents.x2 = surface->geometry.x + surface->geometry.width; - view->extents.y2 = surface->geometry.y + surface->geometry.height; + view->extents.x1 = 0; + view->extents.y1 = 0; + view->extents.x2 = 0; + view->extents.y2 = 0; view->border.width = 0; view->border.color = 0x000000; view->border.damaged = false; - view->surface_event_listener.notify = &handle_surface_event; - wl_signal_add(&surface->event_signal, &view->surface_event_listener); pixman_region32_init(&view->clip); swc_surface_set_view(surface, &view->base); @@ -366,26 +308,23 @@ bool swc_compositor_add_surface(struct swc_compositor * compositor, void swc_compositor_surface_show(struct swc_surface * surface) { struct view * view = (void *) surface->view; - struct swc_compositor * compositor = view->compositor; if (view->base.impl != &view_impl) return; - if (view->mapped) + if (view->base.visible) return; printf("showing surface %u\n", wl_resource_get_id(surface->resource)); - view->mapped = true; - /* Assume worst-case no clipping until we draw the next frame (in case the * surface gets moved before that. */ pixman_region32_clear(&view->clip); - damage_surface(surface); - update_screens(surface); + damage_view(view); + swc_view_set_visibility(&view->base, true); update(&view->base); - wl_list_insert(&compositor->surfaces, &surface->link); + wl_list_insert(&view->compositor->views, &view->link); } void swc_compositor_surface_hide(struct swc_surface * surface) @@ -395,17 +334,15 @@ void swc_compositor_surface_hide(struct swc_surface * surface) if (view->base.impl != &view_impl) return; - if (!view->mapped) + if (!view->base.visible) return; /* Update all the outputs the surface was on. */ update(&view->base); - view->mapped = false; - - damage_below_surface(surface); - update_screens(surface); - wl_list_remove(&surface->link); + damage_below_view(view); + swc_view_set_visibility(&view->base, false); + wl_list_remove(&view->link); } void swc_compositor_surface_set_border_width(struct swc_surface * surface, @@ -421,7 +358,7 @@ void swc_compositor_surface_set_border_width(struct swc_surface * surface, /* XXX: Damage above surface for transparent surfaces? */ - update_extents(surface); + update_extents(view); update(&view->base); } @@ -445,63 +382,61 @@ void swc_compositor_surface_set_border_color(struct swc_surface * surface, static void calculate_damage(struct swc_compositor * compositor) { - struct swc_surface * surface; struct view * view; - pixman_region32_t surface_opaque; + pixman_region32_t surface_opaque, * surface_damage; pixman_region32_clear(&compositor->opaque); pixman_region32_init(&surface_opaque); - /* Go through surfaces top-down to calculate clipping regions. */ - wl_list_for_each(surface, &compositor->surfaces, link) + /* Go through views top-down to calculate clipping regions. */ + wl_list_for_each(view, &compositor->views, link) { - view = (void *) surface->view; - /* Clip the surface by the opaque region covering it. */ pixman_region32_copy(&view->clip, &compositor->opaque); /* Translate the opaque region to global coordinates. */ - pixman_region32_copy(&surface_opaque, &surface->state.opaque); - pixman_region32_translate(&surface_opaque, surface->geometry.x, - surface->geometry.y); + pixman_region32_copy(&surface_opaque, &view->surface->state.opaque); + pixman_region32_translate(&surface_opaque, + view->base.geometry.x, view->base.geometry.y); /* Add the surface's opaque region to the accumulated opaque * region. */ pixman_region32_union(&compositor->opaque, &compositor->opaque, &surface_opaque); - if (pixman_region32_not_empty(&surface->state.damage)) + surface_damage = &view->surface->state.damage; + + if (pixman_region32_not_empty(surface_damage)) { - renderer_flush_surface(surface); + renderer_flush_view(view); /* Translate surface damage to global coordinates. */ - pixman_region32_translate(&surface->state.damage, - surface->geometry.x, - surface->geometry.y); + pixman_region32_translate + (surface_damage, view->base.geometry.x, view->base.geometry.y); /* Add the surface damage to the compositor damage. */ pixman_region32_union(&compositor->damage, &compositor->damage, - &surface->state.damage); - pixman_region32_clear(&surface->state.damage); + surface_damage); + pixman_region32_clear(surface_damage); } if (view->border.damaged) { - pixman_region32_t border_region, surface_region; + pixman_region32_t border_region, view_region; pixman_region32_init_with_extents(&border_region, &view->extents); pixman_region32_init_rect - (&surface_region, surface->geometry.x, surface->geometry.y, - surface->geometry.width, surface->geometry.height); + (&view_region, view->base.geometry.x, view->base.geometry.y, + view->base.geometry.width, view->base.geometry.height); pixman_region32_subtract(&border_region, &border_region, - &surface_region); + &view_region); pixman_region32_union(&compositor->damage, &compositor->damage, &border_region); pixman_region32_fini(&border_region); - pixman_region32_fini(&surface_region); + pixman_region32_fini(&view_region); view->border.damaged = false; } @@ -527,9 +462,9 @@ static void repaint_screen(struct swc_compositor * compositor, target.geometry.y = screen->base.geometry.y + output->framebuffer_plane.y; target.geometry.width = target.buffer->width; target.geometry.height = target.buffer->height; + target.mask = swc_screen_mask(screen); - renderer_repaint(&target, damage, &base_damage, - &compositor->surfaces); + renderer_repaint(&target, damage, &base_damage, &compositor->views); pixman_region32_fini(&base_damage); @@ -607,20 +542,20 @@ static void handle_focus(struct swc_pointer * pointer) { /* XXX: Temporary hack */ struct swc_compositor * compositor = swc.compositor; - struct swc_surface * surface; + struct view * view; int32_t x, y; - wl_list_for_each(surface, &compositor->surfaces, link) + wl_list_for_each(view, &compositor->views, link) { x = wl_fixed_to_int(pointer->x); y = wl_fixed_to_int(pointer->y); - if (swc_rectangle_contains_point(&surface->geometry, x, y) - && pixman_region32_contains_point(&surface->state.input, - x - surface->geometry.x, - y - surface->geometry.y, NULL)) + if (swc_rectangle_contains_point(&view->base.geometry, x, y) + && pixman_region32_contains_point(&view->surface->state.input, + x - view->base.geometry.x, + y - view->base.geometry.y, NULL)) { - swc_pointer_set_focus(pointer, surface); + swc_pointer_set_focus(pointer, view->surface); return; } } @@ -645,14 +580,14 @@ static void handle_drm_event(struct wl_listener * listener, void * data) case SWC_DRM_PAGE_FLIP: { struct swc_drm_event_data * event_data = event->data; - struct swc_surface * surface; + struct view * view; compositor->pending_flips &= ~SWC_OUTPUT_MASK(event_data->output); if (compositor->pending_flips == 0) { - wl_list_for_each(surface, &compositor->surfaces, link) - swc_view_frame(surface->view, event_data->time); + wl_list_for_each(view, &compositor->views, link) + swc_view_frame(&view->base, event_data->time); } /* If we had scheduled updates that couldn't run because we were @@ -744,7 +679,7 @@ bool swc_compositor_initialize(struct swc_compositor * compositor, pixman_region32_init(&compositor->damage); pixman_region32_init(&compositor->opaque); - wl_list_init(&compositor->surfaces); + wl_list_init(&compositor->views); swc_add_key_binding(SWC_MOD_CTRL | SWC_MOD_ALT, XKB_KEY_BackSpace, &handle_terminate, display); diff --git a/libswc/compositor.h b/libswc/compositor.h @@ -10,7 +10,7 @@ struct swc_screen_internal; struct swc_compositor { struct wl_display * display; - struct wl_list surfaces; + struct wl_list views; /* Internal state related to repainting the screen. */ struct diff --git a/libswc/pointer.c b/libswc/pointer.c @@ -1,6 +1,7 @@ #include "pointer.h" #include "event.h" #include "util.h" +#include "view.h" #include <stdio.h> #include <assert.h> @@ -19,8 +20,8 @@ static void enter(struct swc_input_focus_handler * handler, display = wl_client_get_display(client); serial = wl_display_next_serial(display); - surface_x = pointer->x - wl_fixed_from_int(surface->geometry.x); - surface_y = pointer->y - wl_fixed_from_int(surface->geometry.y); + surface_x = pointer->x - wl_fixed_from_int(surface->view->geometry.x); + surface_y = pointer->y - wl_fixed_from_int(surface->view->geometry.y); printf("-> pointer.enter: %p (%d, %d)\n", resource, surface_x, surface_y); wl_pointer_send_enter(resource, serial, surface->resource, @@ -135,8 +136,6 @@ static void set_cursor(struct wl_client * client, if (surface) { - surface->geometry.x = wl_fixed_to_int(pointer->x) - hotspot_x; - surface->geometry.y = wl_fixed_to_int(pointer->y) - hotspot_y; wl_resource_add_destroy_listener(surface->resource, &pointer->cursor.destroy_listener); } @@ -218,20 +217,12 @@ void swc_pointer_handle_relative_motion { wl_fixed_t surface_x, surface_y; surface_x = pointer->x - - wl_fixed_from_int(pointer->focus.surface->geometry.x); + - wl_fixed_from_int(pointer->focus.surface->view->geometry.x); surface_y = pointer->y - - wl_fixed_from_int(pointer->focus.surface->geometry.y); + - wl_fixed_from_int(pointer->focus.surface->view->geometry.y); wl_pointer_send_motion(pointer->focus.resource, time, surface_x, surface_y); - - if (pointer->cursor.surface) - { - swc_surface_move - (pointer->cursor.surface, - wl_fixed_to_int(pointer->x) - pointer->cursor.hotspot_x, - wl_fixed_to_int(pointer->y) - pointer->cursor.hotspot_y); - } } } diff --git a/libswc/shell_surface.c b/libswc/shell_surface.c @@ -26,6 +26,7 @@ #include "swc.h" #include "surface.h" #include "util.h" +#include "view.h" #include "window.h" #include <stdlib.h> @@ -87,8 +88,8 @@ static void set_transient(struct wl_client * client, = wl_resource_get_user_data(resource); struct swc_surface * parent = wl_resource_get_user_data(parent_resource); - swc_surface_move(shell_surface->window.surface, - parent->geometry.x + x, parent->geometry.y + y); + swc_view_move(shell_surface->window.surface->view, + parent->view->geometry.x + x, parent->view->geometry.y + y); swc_compositor_surface_show(shell_surface->window.surface); /* XXX: Handle transient */ @@ -111,8 +112,8 @@ static void set_popup(struct wl_client * client, struct wl_resource * resource, = wl_resource_get_user_data(resource); struct swc_surface * parent = wl_resource_get_user_data(parent_resource); - swc_surface_move(shell_surface->window.surface, - parent->geometry.x + x, parent->geometry.y + y); + swc_view_move(shell_surface->window.surface->view, + parent->view->geometry.x + x, parent->view->geometry.y + y); swc_compositor_surface_show(shell_surface->window.surface); /* XXX: Handle popup */ diff --git a/libswc/surface.c b/libswc/surface.c @@ -24,7 +24,10 @@ #include "surface.h" #include "buffer.h" #include "event.h" +#include "internal.h" +#include "output.h" #include "region.h" +#include "screen.h" #include "util.h" #include "view.h" #include "wayland_buffer.h" @@ -33,37 +36,6 @@ #include <stdio.h> #include <wld/wld.h> -static void set_size(struct swc_surface * surface, - uint32_t width, uint32_t height) -{ - /* Check if the surface was resized. */ - if (width != surface->geometry.width || height != surface->geometry.height) - { - struct swc_surface_event_data data = { - .surface = surface, - .resize = { - .old_width = surface->geometry.width, - .old_height = surface->geometry.height, - .new_width = width, - .new_height = height - } - }; - - surface->geometry.width = width; - surface->geometry.height = height; - - pixman_region32_intersect_rect - (&surface->state.opaque, &surface->state.opaque, - 0, 0, width, height); - pixman_region32_intersect_rect - (&surface->state.damage, &surface->state.damage, - 0, 0, width, height); - - swc_send_event(&surface->event_signal, - SWC_SURFACE_EVENT_TYPE_RESIZE, &data); - } -} - /** * Removes a buffer from a surface state. */ @@ -73,21 +45,12 @@ static void handle_buffer_destroy(struct wl_listener * listener, void * data) state = CONTAINER_OF(listener, typeof(*state), buffer_destroy_listener); state->buffer = NULL; - - if (state->current) - { - struct swc_surface * surface; - - surface = CONTAINER_OF(state, typeof(*surface), state); - set_size(surface, 0, 0); - } } -static void state_initialize(struct swc_surface_state * state, bool current) +static void state_initialize(struct swc_surface_state * state) { state->buffer = NULL; state->buffer_destroy_listener.notify = &handle_buffer_destroy; - state->current = current; pixman_region32_init(&state->damage); pixman_region32_init(&state->opaque); @@ -232,6 +195,7 @@ static void set_input_region(struct wl_client * client, static void commit(struct wl_client * client, struct wl_resource * resource) { struct swc_surface * surface = wl_resource_get_user_data(resource); + struct wld_buffer * buffer; /* Attach */ if (surface->pending.commit & SWC_SURFACE_COMMIT_ATTACH) @@ -243,24 +207,17 @@ static void commit(struct wl_client * client, struct wl_resource * resource) swc_wayland_buffer_release(current_buffer); state_set_buffer(&surface->state, surface->pending.state.buffer); - - /* Determine size of buffer. */ - if (current_buffer) - { - set_size(surface, - current_buffer->wld->width, current_buffer->wld->height); - } - else - set_size(surface, 0, 0); } + buffer = surface->state.buffer ? surface->state.buffer->wld : NULL; + /* Damage */ if (surface->pending.commit & SWC_SURFACE_COMMIT_DAMAGE) { pixman_region32_intersect_rect(&surface->pending.state.damage, &surface->pending.state.damage, 0, 0, - surface->geometry.width, - surface->geometry.height); + buffer ? buffer->width : 0, + buffer ? buffer->height : 0); pixman_region32_union(&surface->state.damage, &surface->state.damage, &surface->pending.state.damage); pixman_region32_clear(&surface->pending.state.damage); @@ -271,8 +228,8 @@ static void commit(struct wl_client * client, struct wl_resource * resource) { pixman_region32_intersect_rect(&surface->state.opaque, &surface->pending.state.opaque, 0, 0, - surface->geometry.width, - surface->geometry.height); + buffer ? buffer->width : 0, + buffer ? buffer->height : 0); } /* Input */ @@ -293,8 +250,8 @@ static void commit(struct wl_client * client, struct wl_resource * resource) if (surface->view) { if (surface->pending.commit & SWC_SURFACE_COMMIT_ATTACH) - surface->view->impl->attach(surface->view, surface->state.buffer); - surface->view->impl->update(surface->view); + swc_view_attach(surface->view, surface->state.buffer); + swc_view_update(surface->view); } surface->pending.commit = 0; @@ -335,6 +292,9 @@ static void surface_destroy(struct wl_resource * resource) state_finish(&surface->state); state_finish(&surface->pending.state); + if (surface->view) + wl_list_remove(&surface->view_listener.link); + printf("freeing surface %p\n", surface); free(surface); } @@ -362,6 +322,46 @@ static void handle_view_event(struct wl_listener * listener, void * data) wl_list_init(&surface->state.frame_callbacks); break; } + case SWC_VIEW_EVENT_SCREENS_CHANGED: + { + struct swc_screen_internal * screen; + struct swc_output * output; + struct wl_client * client; + struct wl_resource * resource; + uint32_t entered = event_data->screens_changed.entered, + left = event_data->screens_changed.left; + + client = wl_resource_get_client(surface->resource); + + wl_list_for_each(screen, &swc.screens, link) + { + if (!((entered | left) & swc_screen_mask(screen))) + continue; + + wl_list_for_each(output, &screen->outputs, link) + { + resource = wl_resource_find_for_client + (&output->resources, client); + + if (resource) + { + if (entered & swc_screen_mask(screen)) + wl_surface_send_enter(surface->resource, resource); + else if (left & swc_screen_mask(screen)) + wl_surface_send_leave(surface->resource, resource); + } + } + } + break; + } + case SWC_VIEW_EVENT_RESIZED: + pixman_region32_intersect_rect + (&surface->state.opaque, &surface->state.opaque, 0, 0, + surface->view->geometry.width, surface->view->geometry.height); + pixman_region32_intersect_rect + (&surface->state.damage, &surface->state.damage, 0, 0, + surface->view->geometry.width, surface->view->geometry.height); + break; } } @@ -383,19 +383,13 @@ struct swc_surface * swc_surface_new(struct wl_client * client, return NULL; /* Initialize the surface. */ - surface->screens = 0; - surface->geometry.x = 0; - surface->geometry.y = 0; - surface->geometry.width = 0; - surface->geometry.height = 0; surface->pending.commit = 0; surface->window = NULL; surface->view = NULL; surface->view_listener.notify = &handle_view_event; - surface->view_state = NULL; - state_initialize(&surface->state, true); - state_initialize(&surface->pending.state, false); + state_initialize(&surface->state); + state_initialize(&surface->pending.state); wl_signal_init(&surface->event_signal); @@ -425,20 +419,8 @@ void swc_surface_set_view(struct swc_surface * surface, struct swc_view * view) if (view) { wl_signal_add(&view->event_signal, &surface->view_listener); - surface->view->impl->attach(surface->view, surface->state.buffer); - surface->view->impl->update(surface->view); + swc_view_attach(view, surface->state.buffer); + swc_view_update(surface->view); } } -void swc_surface_update(struct swc_surface * surface) -{ - if (surface->view) - surface->view->impl->update(surface->view); -} - -void swc_surface_move(struct swc_surface * surface, int32_t x, int32_t y) -{ - if (surface->view) - surface->view->impl->move(surface->view, x, y); -} - diff --git a/libswc/surface.h b/libswc/surface.h @@ -24,8 +24,7 @@ #ifndef SWC_SURFACE_H #define SWC_SURFACE_H -#include "swc.h" - +#include <stdbool.h> #include <wayland-server.h> #include <pixman.h> @@ -58,7 +57,6 @@ struct swc_surface_state { struct swc_buffer * buffer; struct wl_listener buffer_destroy_listener; - bool current; /* The region that needs to be repainted. */ pixman_region32_t damage; @@ -88,10 +86,6 @@ struct swc_surface struct swc_window * window; struct swc_view * view; struct wl_listener view_listener; - void * view_state; - - uint32_t screens; - struct swc_rectangle geometry; struct wl_signal event_signal; struct wl_list link; @@ -102,9 +96,5 @@ struct swc_surface * swc_surface_new(struct wl_client * client, void swc_surface_set_view(struct swc_surface * surface, struct swc_view * view); -void swc_surface_update(struct swc_surface * surface); - -void swc_surface_move(struct swc_surface * surface, int32_t x, int32_t y); - #endif diff --git a/libswc/view.c b/libswc/view.c @@ -22,17 +22,137 @@ */ #include "view.h" +#include "buffer.h" #include "event.h" +#include "internal.h" +#include "screen.h" +#include "util.h" + +#include <wld/wld.h> + +static void update_screens(struct swc_view * view) +{ + struct swc_view_event_data data = { .view = view }; + uint32_t old = view->screens, new = 0; + struct swc_screen_internal * screen; + + if (view->visible) + { + wl_list_for_each(screen, &swc.screens, link) + { + if (swc_rectangle_overlap(&screen->base.geometry, &view->geometry)) + new |= swc_screen_mask(screen); + } + } + + if (new == old) + return; + + view->screens = new; + + data.screens_changed.entered = new & ~old; + data.screens_changed.left = old & ~new; + swc_send_event(&view->event_signal, SWC_VIEW_EVENT_SCREENS_CHANGED, &data); +} + +static void set_size(struct swc_view * view, uint32_t width, uint32_t height) +{ + if (view->geometry.width != width || view->geometry.height != height) + { + struct swc_view_event_data data = { .view = view }; + + if (view->impl->resize) + view->impl->resize(view); + + view->geometry.width = width; + view->geometry.height = height; + update_screens(view); + + swc_send_event(&view->event_signal, SWC_VIEW_EVENT_RESIZED, &data); + } +} + +static void handle_buffer_destroy(struct wl_listener * listener, void * data) +{ + struct swc_view * view + = CONTAINER_OF(listener, typeof(*view), buffer_destroy_listener); + + view->impl->attach(view, NULL); + view->buffer = NULL; + set_size(view, 0, 0); +} void swc_view_initialize(struct swc_view * view, const struct swc_view_impl * impl) { view->impl = impl; + view->visible = true; + view->geometry.x = 0; + view->geometry.y = 0; + view->geometry.width = 0; + view->geometry.height = 0; + view->buffer = NULL; + view->buffer_destroy_listener.notify = &handle_buffer_destroy; + view->screens = 0; wl_signal_init(&view->event_signal); } void swc_view_finalize(struct swc_view * view) { + if (view->buffer) + wl_list_remove(&view->buffer_destroy_listener.link); +} + +bool swc_view_attach(struct swc_view * view, struct swc_buffer * buffer) +{ + if (view->impl->attach(view, buffer)) + { + if (view->buffer) + wl_list_remove(&view->buffer_destroy_listener.link); + + if (buffer) + { + wl_signal_add(&buffer->destroy_signal, + &view->buffer_destroy_listener); + set_size(view, buffer->wld->width, buffer->wld->height); + } + else + set_size(view, 0, 0); + + view->buffer = buffer; + return true; + } + else + return false; +} + +bool swc_view_update(struct swc_view * view) +{ + return view->impl->update(view); +} + +bool swc_view_move(struct swc_view * view, int32_t x, int32_t y) +{ + struct swc_view_event_data data = { .view = view }; + + if (x == view->geometry.x && y == view->geometry.y) + return true; + + if (!view->impl->move || !view->impl->move(view, x, y)) + return false; + + view->geometry.x = x; + view->geometry.y = y; + update_screens(view); + swc_send_event(&view->event_signal, SWC_VIEW_EVENT_MOVED, &data); + + return true; +} + +void swc_view_set_visibility(struct swc_view * view, bool visible) +{ + view->visible = visible; + update_screens(view); } void swc_view_frame(struct swc_view * view, uint32_t time) diff --git a/libswc/view.h b/libswc/view.h @@ -26,12 +26,20 @@ #include "swc.h" -struct swc_buffer; - enum swc_view_event { /* Sent when the view has displayed the next frame. */ SWC_VIEW_EVENT_FRAME, + + /* Sent when the origin of the view has moved. */ + SWC_VIEW_EVENT_MOVED, + + /* Sent when the view's size changes. This occurs when a buffer of + * different dimensions is attached to the view. */ + SWC_VIEW_EVENT_RESIZED, + + /* Sent when the set of screens the view is visible on changes. */ + SWC_VIEW_EVENT_SCREENS_CHANGED }; struct swc_view_event_data @@ -43,6 +51,11 @@ struct swc_view_event_data { uint32_t time; } frame; + + struct + { + uint32_t left, entered; + } screens_changed; }; }; @@ -51,21 +64,28 @@ struct swc_view const struct swc_view_impl * impl; struct wl_signal event_signal; + bool visible; + uint32_t screens; + + struct swc_rectangle geometry; + struct swc_buffer * buffer; + struct wl_listener buffer_destroy_listener; }; struct swc_view_impl { - /* Called when a source is removed from the view. */ - void (* remove)(struct swc_view * view); + /* Called when the view should present a new frame. */ + bool (* update)(struct swc_view * view); /* Called when a new buffer is attached to the view. */ - void (* attach)(struct swc_view * view, struct swc_buffer * buffer); + bool (* attach)(struct swc_view * view, struct swc_buffer * buffer); - /* Called when the view should present a new frame. */ - void (* update)(struct swc_view * view); + bool (* move)(struct swc_view * view, int32_t x, int32_t y); - /* Move the view to the specified coordinates. */ - void (* move)(struct swc_view * view, int32_t x, int32_t y); + void (* resize)(struct swc_view * view); + + /* Called when a source is removed from the view. */ + void (* remove)(struct swc_view * view); }; void swc_view_initialize(struct swc_view * view, @@ -73,6 +93,10 @@ void swc_view_initialize(struct swc_view * view, void swc_view_finalize(struct swc_view * view); +bool swc_view_attach(struct swc_view * view, struct swc_buffer * buffer); +bool swc_view_update(struct swc_view * view); +bool swc_view_move(struct swc_view * view, int32_t x, int32_t y); +void swc_view_set_visibility(struct swc_view * view, bool visible); void swc_view_frame(struct swc_view * view, uint32_t time); #endif diff --git a/libswc/window.c b/libswc/window.c @@ -29,6 +29,7 @@ #include "seat.h" #include "swc.h" #include "util.h" +#include "view.h" #include <stdlib.h> #include <string.h> @@ -97,7 +98,7 @@ void swc_window_set_geometry(struct swc_window * window, if (INTERNAL(window)->impl->configure) INTERNAL(window)->impl->configure(window, geometry); - swc_surface_move(INTERNAL(window)->surface, geometry->x, geometry->y); + swc_view_move(INTERNAL(window)->surface->view, geometry->x, geometry->y); } EXPORT diff --git a/libswc/xwm.c b/libswc/xwm.c @@ -27,6 +27,7 @@ #include "surface.h" #include "swc.h" #include "util.h" +#include "view.h" #include "window.h" #include <stdio.h> @@ -341,7 +342,7 @@ void swc_xwm_manage_window(xcb_window_t id, struct swc_surface * surface) if ((geometry_reply = xcb_get_geometry_reply(xwm.connection, geometry_cookie, NULL))) { - swc_surface_move(surface, geometry_reply->x, geometry_reply->y); + swc_view_move(surface->view, geometry_reply->x, geometry_reply->y); } if (entry->override_redirect)