commit 0dc0ed3

Michael Forney  ·  2014-01-17 03:52:26 +0000 UTC
parent 4d25523
Implement screens
15 files changed,  +318, -185
+44, -69
  1@@ -7,6 +7,7 @@
  2 #include "output.h"
  3 #include "pointer.h"
  4 #include "region.h"
  5+#include "screen.h"
  6 #include "seat.h"
  7 #include "surface.h"
  8 #include "util.h"
  9@@ -195,50 +196,51 @@ static void update_extents(struct swc_surface * surface)
 10     view->border.damaged = true;
 11 }
 12 
 13-static void update_outputs(struct swc_surface * surface)
 14+static void update_screens(struct swc_surface * surface)
 15 {
 16     struct view * view = (void *) surface->view;
 17-    struct swc_compositor * compositor = view->compositor;
 18-    uint32_t old_outputs = surface->outputs, new_outputs = 0,
 19-             entered_outputs, left_outputs, changed_outputs;
 20+    uint32_t old_screens = surface->screens, new_screens = 0,
 21+             entered_screens, left_screens, changed_screens;
 22+    struct swc_screen_internal * screen;
 23     struct swc_output * output;
 24     struct wl_client * client;
 25     struct wl_resource * resource;
 26 
 27     if (view->mapped)
 28     {
 29-        wl_list_for_each(output, &compositor->outputs, link)
 30+        wl_list_for_each(screen, &swc.screens, link)
 31         {
 32-            if (swc_rectangle_overlap(&output->geometry, &surface->geometry))
 33-                new_outputs |= SWC_OUTPUT_MASK(output);
 34+            if (swc_rectangle_overlap(&screen->base.geometry, &surface->geometry))
 35+                new_screens |= swc_screen_mask(screen);
 36         }
 37     }
 38 
 39-    if (new_outputs == old_outputs)
 40+    if (new_screens == old_screens)
 41         return;
 42 
 43-    entered_outputs = new_outputs & ~old_outputs;
 44-    left_outputs = old_outputs & ~new_outputs;
 45-    changed_outputs = old_outputs ^ new_outputs;
 46+    entered_screens = new_screens & ~old_screens;
 47+    left_screens = old_screens & ~new_screens;
 48+    changed_screens = old_screens ^ new_screens;
 49 
 50-    wl_list_for_each(output, &compositor->outputs, link)
 51+    wl_list_for_each(screen, &swc.screens, link)
 52     {
 53-        if (!(changed_outputs & SWC_OUTPUT_MASK(output)))
 54+        if (!(changed_screens & swc_screen_mask(screen)))
 55             continue;
 56 
 57+        output = CONTAINER_OF(screen->outputs.next, typeof(*output), link);
 58         client = wl_resource_get_client(surface->resource);
 59         resource = wl_resource_find_for_client(&output->resources, client);
 60 
 61         if (resource)
 62         {
 63-            if (entered_outputs & SWC_OUTPUT_MASK(output))
 64+            if (entered_screens & swc_screen_mask(screen))
 65                 wl_surface_send_enter(surface->resource, resource);
 66-            else if (left_outputs & SWC_OUTPUT_MASK(output))
 67+            else if (left_screens & swc_screen_mask(screen))
 68                 wl_surface_send_leave(surface->resource, resource);
 69         }
 70     }
 71 
 72-    surface->outputs = new_outputs;
 73+    surface->screens = new_screens;
 74 }
 75 
 76 static void update(struct swc_view * view);
 77@@ -258,7 +260,7 @@ static void handle_surface_event(struct wl_listener * listener, void * data)
 78 
 79             update_extents(surface);
 80             update(&view->base);
 81-            update_outputs(surface);
 82+            update_screens(surface);
 83 
 84             break;
 85     }
 86@@ -284,16 +286,15 @@ static void attach(struct swc_view * base, struct swc_buffer * buffer)
 87 static void update(struct swc_view * base)
 88 {
 89     struct view * view = (void *) base;
 90-    struct swc_compositor * compositor = view->compositor;
 91-    struct swc_output * output;
 92+    struct swc_screen_internal * screen;
 93 
 94     if (!view->mapped)
 95         return;
 96 
 97-    wl_list_for_each(output, &compositor->outputs, link)
 98+    wl_list_for_each(screen, &swc.screens, link)
 99     {
100-        if (view->surface->outputs & SWC_OUTPUT_MASK(output))
101-            swc_compositor_schedule_update(compositor, output);
102+        if (view->surface->screens & swc_screen_mask(screen))
103+            swc_compositor_schedule_update(view->compositor, screen);
104     }
105 }
106 
107@@ -321,7 +322,7 @@ static void move(struct swc_view * base, int32_t x, int32_t y)
108 
109         damage_below_surface(surface);
110         update(&view->base);
111-        update_outputs(surface);
112+        update_screens(surface);
113         update(&view->base);
114     }
115 }
116@@ -382,7 +383,7 @@ void swc_compositor_surface_show(struct swc_surface * surface)
117     pixman_region32_clear(&view->clip);
118 
119     damage_surface(surface);
120-    update_outputs(surface);
121+    update_screens(surface);
122     update(&view->base);
123     wl_list_insert(&compositor->surfaces, &surface->link);
124 }
125@@ -403,7 +404,7 @@ void swc_compositor_surface_hide(struct swc_surface * surface)
126     view->mapped = false;
127 
128     damage_below_surface(surface);
129-    update_outputs(surface);
130+    update_screens(surface);
131     wl_list_remove(&surface->link);
132 }
133 
134@@ -509,10 +510,12 @@ static void calculate_damage(struct swc_compositor * compositor)
135     pixman_region32_fini(&surface_opaque);
136 }
137 
138-static void repaint_output(struct swc_compositor * compositor,
139-                           struct swc_output * output,
140+static void repaint_screen(struct swc_compositor * compositor,
141+                           struct swc_screen_internal * screen,
142                            pixman_region32_t * damage)
143 {
144+    struct swc_output * output
145+        = CONTAINER_OF(screen->outputs.next, typeof(*output), link);
146     pixman_region32_t base_damage;
147     struct render_target target;
148 
149@@ -520,10 +523,8 @@ static void repaint_output(struct swc_compositor * compositor,
150     pixman_region32_subtract(&base_damage, damage, &compositor->opaque);
151 
152     target.buffer = swc_plane_get_buffer(&output->framebuffer_plane);
153-    target.geometry.x = output->framebuffer_plane.output->geometry.x
154-        + output->framebuffer_plane.x;
155-    target.geometry.y = output->framebuffer_plane.output->geometry.y
156-        + output->framebuffer_plane.y;
157+    target.geometry.x = screen->base.geometry.x + output->framebuffer_plane.x;
158+    target.geometry.y = screen->base.geometry.y + output->framebuffer_plane.y;
159     target.geometry.width = target.buffer->width;
160     target.geometry.height = target.buffer->height;
161 
162@@ -539,12 +540,13 @@ static void repaint_output(struct swc_compositor * compositor,
163 static void update_output_damage(struct swc_output * output,
164                                  pixman_region32_t * damage)
165 {
166+    struct swc_rectangle * geometry = &output->screen->base.geometry;
167+
168     pixman_region32_union
169         (&output->current_damage, &output->current_damage, damage);
170     pixman_region32_intersect_rect
171         (&output->current_damage, &output->current_damage,
172-         output->geometry.x, output->geometry.y,
173-         output->geometry.width, output->geometry.height);
174+         geometry->x, geometry->y, geometry->width, geometry->height);
175 }
176 
177 static void flush_output_damage(struct swc_output * output,
178@@ -564,6 +566,7 @@ static void flush_output_damage(struct swc_output * output,
179 static void perform_update(void * data)
180 {
181     struct swc_compositor * compositor = data;
182+    struct swc_screen_internal * screen;
183     struct swc_output * output;
184     pixman_region32_t damage;
185     uint32_t updates = compositor->scheduled_updates
186@@ -577,19 +580,20 @@ static void perform_update(void * data)
187     calculate_damage(compositor);
188     pixman_region32_init(&damage);
189 
190-    wl_list_for_each(output, &compositor->outputs, link)
191+    wl_list_for_each(screen, &swc.screens, link)
192     {
193-        if (!(compositor->scheduled_updates & SWC_OUTPUT_MASK(output)))
194+        if (!(compositor->scheduled_updates & swc_screen_mask(screen)))
195             continue;
196 
197+        output = CONTAINER_OF(screen->outputs.next, typeof(*output), link);
198         update_output_damage(output, &compositor->damage);
199 
200         /* Don't repaint the output if it is waiting for a page flip. */
201-        if (compositor->pending_flips & SWC_OUTPUT_MASK(output))
202+        if (compositor->pending_flips & swc_screen_mask(screen))
203             continue;
204 
205         flush_output_damage(output, &damage);
206-        repaint_output(compositor, output, &damage);
207+        repaint_screen(compositor, screen, &damage);
208     }
209 
210     pixman_region32_fini(&damage);
211@@ -725,7 +729,6 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
212                                struct wl_display * display,
213                                struct wl_event_loop * event_loop)
214 {
215-    struct wl_list * outputs;
216     uint32_t keysym;
217 
218     compositor->display = display;
219@@ -739,20 +742,6 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
220 
221     wl_signal_add(&swc.drm->event_signal, &compositor->drm_listener);
222 
223-    outputs = swc_drm_create_outputs();
224-
225-    if (outputs)
226-    {
227-        wl_list_init(&compositor->outputs);
228-        wl_list_insert_list(&compositor->outputs, outputs);
229-        free(outputs);
230-    }
231-    else
232-    {
233-        printf("could not create outputs\n");
234-        return false;
235-    }
236-
237     pixman_region32_init(&compositor->damage);
238     pixman_region32_init(&compositor->opaque);
239     wl_list_init(&compositor->surfaces);
240@@ -774,38 +763,24 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
241 
242 void swc_compositor_finish(struct swc_compositor * compositor)
243 {
244-    struct swc_output * output, * tmp;
245-
246-    wl_list_for_each_safe(output, tmp, &compositor->outputs, link)
247-    {
248-        swc_output_finish(output);
249-        free(output);
250-    }
251 }
252 
253 void swc_compositor_add_globals(struct swc_compositor * compositor,
254                                 struct wl_display * display)
255 {
256-    struct swc_output * output;
257-
258     wl_global_create(display, &wl_compositor_interface, 3, compositor,
259                      &bind_compositor);
260-
261-    wl_list_for_each(output, &compositor->outputs, link)
262-    {
263-        swc_output_add_globals(output, display);
264-    }
265 }
266 
267 void swc_compositor_schedule_update(struct swc_compositor * compositor,
268-                                    struct swc_output * output)
269+                                    struct swc_screen_internal * screen)
270 {
271     bool update_scheduled = compositor->scheduled_updates != 0;
272 
273-    if (compositor->scheduled_updates & SWC_OUTPUT_MASK(output))
274+    if (compositor->scheduled_updates & swc_screen_mask(screen))
275         return;
276 
277-    compositor->scheduled_updates |= SWC_OUTPUT_MASK(output);
278+    compositor->scheduled_updates |= swc_screen_mask(screen);
279 
280     if (!update_scheduled)
281     {
+2, -4
 1@@ -5,13 +5,11 @@
 2 
 3 #include <wayland-server.h>
 4 
 5-struct swc_output;
 6+struct swc_screen_internal;
 7 
 8 struct swc_compositor
 9 {
10     struct wl_display * display;
11-
12-    struct wl_list outputs;
13     struct wl_list surfaces;
14 
15     /* Internal state related to repainting the screen. */
16@@ -44,7 +42,7 @@ void swc_compositor_add_globals(struct swc_compositor * compositor,
17                                 struct wl_display * display);
18 
19 void swc_compositor_schedule_update(struct swc_compositor * compositor,
20-                                    struct swc_output * output);
21+                                    struct swc_screen_internal * screen);
22 
23 bool swc_compositor_add_surface(struct swc_compositor * compositor,
24                                 struct swc_surface * surface);
+17, -40
  1@@ -25,6 +25,7 @@
  2 #include "event.h"
  3 #include "internal.h"
  4 #include "output.h"
  5+#include "screen.h"
  6 #include "wayland_buffer.h"
  7 
  8 #include <stdio.h>
  9@@ -47,7 +48,7 @@ static struct
 10     uint32_t id;
 11     char * path;
 12 
 13-    uint32_t taken_output_ids;
 14+    uint32_t taken_ids;
 15 
 16     struct wl_global * global;
 17     struct wl_event_source * event_source;
 18@@ -248,7 +249,7 @@ static bool find_available_crtc(drmModeRes * resources,
 19 
 20 static bool find_available_id(uint32_t * id)
 21 {
 22-    uint32_t index = __builtin_ffsl(~drm.taken_output_ids);
 23+    uint32_t index = __builtin_ffsl(~drm.taken_ids);
 24 
 25     if (index == 0)
 26         return false;
 27@@ -335,7 +336,7 @@ bool swc_drm_initialize(const char * seat_name)
 28         goto error0;
 29     }
 30 
 31-    drm.taken_output_ids = 0;
 32+    drm.taken_ids = 0;
 33     drm.path = strdup(udev_device_get_devnode(drm_device));
 34     udev_device_unref(drm_device);
 35     swc.drm->fd = swc_launch_open_device(drm.path, O_RDWR | O_CLOEXEC);
 36@@ -402,25 +403,19 @@ void swc_drm_finalize()
 37     close(swc.drm->fd);
 38 }
 39 
 40-struct wl_list * swc_drm_create_outputs()
 41+bool swc_drm_create_screens(struct wl_list * screens)
 42 {
 43     drmModeRes * resources;
 44     drmModeConnector * connector;
 45     drmModeCrtc * crtc;
 46     uint32_t index;
 47-    uint32_t x = 0;
 48     struct swc_output * output;
 49-    struct wl_list * outputs;
 50     uint32_t taken_crtcs = 0;
 51 
 52-    outputs = malloc(sizeof(struct wl_list));
 53-    wl_list_init(outputs);
 54-
 55-    resources = drmModeGetResources(swc.drm->fd);
 56-    if (!resources)
 57+    if (!(resources = drmModeGetResources(swc.drm->fd)))
 58     {
 59         printf("couldn't get DRM resources\n");
 60-        goto error;
 61+        return false;
 62     }
 63 
 64     printf("crtc count: %u\n", resources->count_crtcs);
 65@@ -444,7 +439,8 @@ struct wl_list * swc_drm_create_outputs()
 66         drmModeFreeEncoder(encoder);
 67     }
 68 
 69-    for (index = 0; index < resources->count_connectors; ++index)
 70+    for (index = 0; index < resources->count_connectors;
 71+         ++index, drmModeFreeConnector(connector))
 72     {
 73         connector = drmModeGetConnector(swc.drm->fd,
 74                                         resources->connectors[index]);
 75@@ -472,41 +468,22 @@ struct wl_list * swc_drm_create_outputs()
 76                 break;
 77             }
 78 
 79-            output = malloc(sizeof(struct swc_output));
 80-
 81-            output->geometry.x = x;
 82-            output->geometry.y = 0;
 83-
 84-            if (!swc_output_initialize(output, id,
 85-                                       resources->crtcs[crtc_index], connector))
 86-            {
 87-                drmModeFreeConnector(connector);
 88-                free(output);
 89+            if (!(output = swc_output_new(resources->crtcs[crtc_index], connector)))
 90                 continue;
 91-            }
 92+
 93+            output->screen = swc_screen_new(resources->crtcs[crtc_index],
 94+                                            output);
 95+            output->screen->id = id;
 96 
 97             taken_crtcs |= 1 << crtc_index;
 98-            drm.taken_output_ids |= 1 << id;
 99+            drm.taken_ids |= 1 << id;
100 
101-            wl_list_insert(outputs, &output->link);
102-            x += output->geometry.width;
103+            wl_list_insert(screens, &output->screen->link);
104         }
105-
106-        drmModeFreeConnector(connector);
107     }
108 
109     drmModeFreeResources(resources);
110 
111-    if (wl_list_empty(outputs))
112-    {
113-        printf("couldn't find any outputs\n");
114-        goto error;
115-    }
116-
117-    return outputs;
118-
119-  error:
120-    free(outputs);
121-    return NULL;
122+    return true;
123 }
124 
+1, -1
1@@ -27,7 +27,7 @@ struct swc_drm
2 bool swc_drm_initialize(const char * seat);
3 void swc_drm_finalize();
4 
5-struct wl_list * swc_drm_create_outputs();
6+bool swc_drm_create_screens(struct wl_list * screens);
7 
8 #endif
9 
+3, -0
 1@@ -24,6 +24,8 @@
 2 #ifndef SWC_INTERNAL_H
 3 #define SWC_INTERNAL_H
 4 
 5+#include <wayland-util.h>
 6+
 7 struct swc
 8 {
 9     struct wl_display * display;
10@@ -34,6 +36,7 @@ struct swc
11 
12     const struct swc_seat_global * const seat;
13     const struct swc_bindings_global * const bindings;
14+    struct wl_list screens;
15     struct swc_compositor * compositor;
16     struct swc_shm * const shm;
17     struct swc_drm * const drm;
+2, -1
 1@@ -59,7 +59,8 @@ SWC_SOURCES +=                      \
 2     libswc/window.c                 \
 3     libswc/shell.c                  \
 4     libswc/shell_surface.c          \
 5-    libswc/bindings.c
 6+    libswc/bindings.c               \
 7+    libswc/screen.c
 8 
 9 ifeq ($(ENABLE_XWAYLAND),1)
10 $(dir)_CFLAGS += -DENABLE_XWAYLAND
+37, -26
  1@@ -2,6 +2,7 @@
  2 #include "drm.h"
  3 #include "internal.h"
  4 #include "mode.h"
  5+#include "screen.h"
  6 #include "util.h"
  7 
  8 #include <stdio.h>
  9@@ -14,6 +15,7 @@ static void bind_output(struct wl_client * client, void * data,
 10                         uint32_t version, uint32_t id)
 11 {
 12     struct swc_output * output = data;
 13+    struct swc_screen_internal * screen = output->screen;
 14     struct swc_mode * mode;
 15     struct wl_resource * resource;
 16     uint32_t flags;
 17@@ -26,9 +28,10 @@ static void bind_output(struct wl_client * client, void * data,
 18                                    &swc_remove_resource);
 19     wl_list_insert(&output->resources, wl_resource_get_link(resource));
 20 
 21-    wl_output_send_geometry(resource, output->geometry.x, output->geometry.y,
 22-        output->physical_width, output->physical_height, 0, "unknown",
 23-        "unknown", WL_OUTPUT_TRANSFORM_NORMAL);
 24+    wl_output_send_geometry
 25+        (resource, screen->base.geometry.x, screen->base.geometry.y,
 26+         output->physical_width, output->physical_height, 0, "unknown",
 27+         "unknown", WL_OUTPUT_TRANSFORM_NORMAL);
 28 
 29     wl_array_for_each(mode, &output->modes)
 30     {
 31@@ -46,18 +49,29 @@ static void bind_output(struct wl_client * client, void * data,
 32         wl_output_send_done(resource);
 33 }
 34 
 35-bool swc_output_initialize(struct swc_output * output,
 36-                           uint32_t id, uint32_t crtc_id,
 37-                           drmModeConnector * connector)
 38+struct swc_output * swc_output_new(uint32_t crtc_id, drmModeConnector * connector)
 39 {
 40+    struct swc_output * output;
 41     drmModeEncoder * encoder;
 42     drmModeCrtc * current_crtc;
 43     struct swc_mode * modes;
 44     uint32_t index;
 45 
 46-    printf("initializing output with id: %u\n", id);
 47+    if (!(output = malloc(sizeof *output)))
 48+    {
 49+        ERROR("Failed to allocated output\n");
 50+        goto error0;
 51+    }
 52+
 53+    output->global = wl_global_create(swc.display, &wl_output_interface, 2,
 54+                                      output, &bind_output);
 55+
 56+    if (!output->global)
 57+    {
 58+        ERROR("Failed to create output global\n");
 59+        goto error1;
 60+    }
 61 
 62-    output->id = id;
 63     output->physical_width = connector->mmWidth;
 64     output->physical_height = connector->mmHeight;
 65 
 66@@ -66,8 +80,8 @@ bool swc_output_initialize(struct swc_output * output,
 67     pixman_region32_init(&output->current_damage);
 68     pixman_region32_init(&output->previous_damage);
 69 
 70-    output->crtc_id = crtc_id;
 71-    output->connector_id = connector->connector_id;
 72+    output->crtc = crtc_id;
 73+    output->connector = connector->connector_id;
 74 
 75     /* Determine the current CRTC of this output. */
 76     encoder = drmModeGetEncoder(swc.drm->fd, connector->encoder_id);
 77@@ -90,9 +104,6 @@ bool swc_output_initialize(struct swc_output * output,
 78     if (output->preferred_mode)
 79         output->current_mode = output->preferred_mode;
 80 
 81-    output->geometry.width = output->current_mode->width;
 82-    output->geometry.height = output->current_mode->height;
 83-
 84     output->original_state.crtc = current_crtc;
 85 
 86     /* Create output planes */
 87@@ -100,22 +111,26 @@ bool swc_output_initialize(struct swc_output * output,
 88                               &swc_framebuffer_plane, output))
 89     {
 90         printf("failed to initialize framebuffer plane\n");
 91-        goto error_base;
 92+        goto error2;
 93     }
 94 
 95     if (!swc_plane_initialize(&output->cursor_plane, &swc_cursor_plane, output))
 96     {
 97         printf("failed to initialize cursor plane\n");
 98-        goto error_base;
 99+        goto error2;
100     }
101 
102-    return true;
103+    return output;
104 
105-  error_base:
106-    return false;
107+  error2:
108+    wl_global_destroy(output->global);
109+  error1:
110+    free(output);
111+  error0:
112+    return NULL;
113 }
114 
115-void swc_output_finish(struct swc_output * output)
116+void swc_output_destroy(struct swc_output * output)
117 {
118     struct swc_mode * mode;
119     drmModeCrtc * crtc = output->original_state.crtc;
120@@ -125,13 +140,9 @@ void swc_output_finish(struct swc_output * output)
121     wl_array_release(&output->modes);
122 
123     drmModeSetCrtc(swc.drm->fd, crtc->crtc_id, crtc->buffer_id, crtc->x,
124-                   crtc->y, &output->connector_id, 1, &crtc->mode);
125+                   crtc->y, &output->connector, 1, &crtc->mode);
126     drmModeFreeCrtc(crtc);
127-}
128-
129-void swc_output_add_globals(struct swc_output * output,
130-                            struct wl_display * display)
131-{
132-    wl_global_create(display, &wl_output_interface, 2, output, &bind_output);
133+    wl_global_destroy(output->global);
134+    free(output);
135 }
136 
+7, -15
 1@@ -8,16 +8,13 @@
 2 #include <wayland-util.h>
 3 #include <xf86drmMode.h>
 4 
 5-#define SWC_OUTPUT_MASK(output) (1 << (output)->id)
 6-
 7 struct wl_display;
 8 
 9 struct swc_output
10 {
11-    uint32_t id;
12+    struct swc_screen_internal * screen;
13 
14-    /* The geometry of this output */
15-    struct swc_rectangle geometry;
16+    /* The physical dimensions (in mm) of this output */
17     uint32_t physical_width, physical_height;
18 
19     struct wl_array modes;
20@@ -29,26 +26,21 @@ struct swc_output
21 
22     pixman_region32_t current_damage, previous_damage;
23 
24-    /* The CRTC and connector we are using to drive this output */
25-    uint32_t crtc_id;
26-    uint32_t connector_id;
27+    /* The DRM connector corresponding to this output */
28+    uint32_t crtc, connector;
29 
30     struct
31     {
32         drmModeCrtc * crtc;
33     } original_state;
34 
35+    struct wl_global * global;
36     struct wl_list resources;
37     struct wl_list link;
38 };
39 
40-bool swc_output_initialize(struct swc_output * output, uint32_t id, uint32_t crtc_id,
41-                           drmModeConnector * connector);
42-
43-void swc_output_finish(struct swc_output * output);
44-
45-void swc_output_add_globals(struct swc_output * output,
46-                            struct wl_display * display);
47+struct swc_output * swc_output_new(uint32_t crtc_id, drmModeConnector * connector);
48+void swc_output_destroy(struct swc_output * output);
49 
50 #endif
51 
+8, -6
 1@@ -26,6 +26,7 @@
 2 #include "internal.h"
 3 #include "mode.h"
 4 #include "output.h"
 5+#include "screen.h"
 6 
 7 #include <stdlib.h>
 8 #include <stdio.h>
 9@@ -43,8 +44,8 @@ static bool framebuffer_initialize(struct swc_plane * plane)
10 {
11     struct framebuffer * fb = swc_double_buffer_front(&plane->double_buffer);
12 
13-    return drmModeSetCrtc(swc.drm->fd, plane->output->crtc_id,
14-                          fb->id, 0, 0, &plane->output->connector_id, 1,
15+    return drmModeSetCrtc(swc.drm->fd, plane->output->crtc,
16+                          fb->id, 0, 0, &plane->output->connector, 1,
17                           &plane->output->current_mode->info) == 0;
18 }
19 
20@@ -59,7 +60,8 @@ static void * framebuffer_create_buffer(struct swc_plane * plane)
21         goto error0;
22 
23     buffer = wld_create_buffer(swc.drm->context,
24-                               output->geometry.width, output->geometry.height,
25+                               output->screen->base.geometry.width,
26+                               output->screen->base.geometry.height,
27                                WLD_FORMAT_XRGB8888);
28 
29     if (!buffer)
30@@ -109,7 +111,7 @@ static bool framebuffer_flip(struct swc_plane * plane)
31     struct swc_output * output = plane->output;
32     struct framebuffer * fb = swc_double_buffer_back(&plane->double_buffer);
33 
34-    return drmModePageFlip(swc.drm->fd, output->crtc_id, fb->id,
35+    return drmModePageFlip(swc.drm->fd, output->crtc, fb->id,
36                            DRM_MODE_PAGE_FLIP_EVENT, output) == 0;
37 }
38 
39@@ -149,13 +151,13 @@ static bool cursor_flip(struct swc_plane * plane)
40     union wld_object object;
41 
42     wld_export(buffer, WLD_DRM_OBJECT_HANDLE, &object);
43-    return drmModeSetCursor(swc.drm->fd, plane->output->crtc_id,
44+    return drmModeSetCursor(swc.drm->fd, plane->output->crtc,
45                             object.u32, 64, 64) == 0;
46 }
47 
48 static bool cursor_move(struct swc_plane * plane, int32_t x, int32_t y)
49 {
50-    return drmModeMoveCursor(swc.drm->fd, plane->output->crtc_id, x, y) == 0;
51+    return drmModeMoveCursor(swc.drm->fd, plane->output->crtc, x, y) == 0;
52 }
53 
54 const struct swc_plane_interface swc_cursor_plane = {
+94, -0
 1@@ -0,0 +1,94 @@
 2+/* swc: libswc/screen.c
 3+ *
 4+ * Copyright (c) 2013, 2014 Michael Forney
 5+ *
 6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
 7+ * of this software and associated documentation files (the "Software"), to deal
 8+ * in the Software without restriction, including without limitation the rights
 9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+ * SOFTWARE.
23+ */
24+
25+#include "screen.h"
26+#include "drm.h"
27+#include "internal.h"
28+#include "mode.h"
29+#include "output.h"
30+
31+#include <stdlib.h>
32+#include <sys/param.h>
33+
34+#define INTERNAL(screen) ((struct swc_screen_internal *) (screen))
35+
36+bool swc_screens_initialize()
37+{
38+    wl_list_init(&swc.screens);
39+
40+    if (!swc_drm_create_screens(&swc.screens))
41+        return false;
42+
43+    if (wl_list_empty(&swc.screens))
44+        return false;
45+
46+    return true;
47+}
48+
49+void swc_screens_finalize()
50+{
51+    struct swc_screen_internal * screen, * tmp;
52+
53+    wl_list_for_each_safe(screen, tmp, &swc.screens, link)
54+        free(screen);
55+}
56+
57+struct swc_screen_internal * swc_screen_new(uint32_t crtc,
58+                                            struct swc_output * output)
59+{
60+    struct swc_screen_internal * screen;
61+    int32_t x = 0;
62+
63+    /* Simple heuristic for initial screen positioning. */
64+    wl_list_for_each(screen, &swc.screens, link)
65+        x = MAX(x, screen->base.geometry.x + screen->base.geometry.width);
66+
67+    if (!(screen = malloc(sizeof *screen)))
68+        goto error0;
69+
70+    screen->base.geometry.x = x;
71+    screen->base.geometry.y = 0;
72+    screen->base.geometry.width = output->preferred_mode->width;
73+    screen->base.geometry.height = output->preferred_mode->height;
74+    screen->base.usable_geometry = screen->base.geometry;
75+    wl_signal_init(&screen->base.event_signal);
76+    wl_list_init(&screen->outputs);
77+    wl_list_insert(&INTERNAL(screen)->outputs, &output->link);
78+
79+    swc.manager->new_screen(&screen->base);
80+
81+    return screen;
82+
83+  error0:
84+    return NULL;
85+}
86+
87+void swc_screen_destroy(struct swc_screen_internal * screen)
88+{
89+    struct swc_output * output, * next;
90+
91+    wl_list_for_each_safe(output, next, &screen->outputs, link)
92+        swc_output_destroy(output);
93+    free(screen);
94+}
95+
+56, -0
 1@@ -0,0 +1,56 @@
 2+/* swc: libswc/screen.h
 3+ *
 4+ * Copyright (c) 2013, 2014 Michael Forney
 5+ *
 6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
 7+ * of this software and associated documentation files (the "Software"), to deal
 8+ * in the Software without restriction, including without limitation the rights
 9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+ * SOFTWARE.
23+ */
24+
25+#ifndef SWC_SCREEN_H
26+#define SWC_SCREEN_H
27+
28+#include "swc.h"
29+
30+#include <wayland-util.h>
31+
32+struct swc_output;
33+
34+struct swc_screen_internal
35+{
36+    struct swc_screen base;
37+
38+    uint8_t id;
39+
40+    struct wl_list outputs;
41+    struct wl_list modifiers;
42+    struct wl_list link;
43+};
44+
45+bool swc_screens_initialize();
46+void swc_screens_finalize();
47+
48+struct swc_screen_internal * swc_screen_new(uint32_t crtc,
49+                                            struct swc_output * output);
50+void swc_screen_destroy(struct swc_screen_internal * screen);
51+static inline uint32_t swc_screen_mask(struct swc_screen_internal * screen)
52+{
53+    return 1 << screen->id;
54+}
55+
56+#endif
57+
+1, -1
1@@ -383,7 +383,7 @@ struct swc_surface * swc_surface_new(struct wl_client * client,
2         return NULL;
3 
4     /* Initialize the surface. */
5-    surface->outputs = 0;
6+    surface->screens = 0;
7     surface->geometry.x = 0;
8     surface->geometry.y = 0;
9     surface->geometry.width = 0;
+1, -1
1@@ -90,7 +90,7 @@ struct swc_surface
2     struct wl_listener view_listener;
3     void * view_state;
4 
5-    uint32_t outputs;
6+    uint32_t screens;
7     struct swc_rectangle geometry;
8 
9     struct wl_signal event_signal;
+28, -17
  1@@ -28,11 +28,12 @@
  2 #include "drm.h"
  3 #include "internal.h"
  4 #include "keyboard.h"
  5-#include "output.h"
  6 #include "pointer.h"
  7+#include "screen.h"
  8 #include "seat.h"
  9 #include "shell.h"
 10 #include "shm.h"
 11+#include "util.h"
 12 #include "window.h"
 13 #ifdef ENABLE_XWAYLAND
 14 # include "xserver.h"
 15@@ -57,7 +58,8 @@ struct swc swc = {
 16 static void setup_compositor()
 17 {
 18     pixman_region32_t pointer_region;
 19-    struct swc_output * output;
 20+    struct swc_screen_internal * screen;
 21+    struct swc_rectangle * geometry;
 22 
 23     wl_list_insert(&swc.seat->keyboard->handlers,
 24                    &swc.bindings->keyboard_handler->link);
 25@@ -68,12 +70,12 @@ static void setup_compositor()
 26     /* Calculate pointer region */
 27     pixman_region32_init(&pointer_region);
 28 
 29-    wl_list_for_each(output, &compositor.outputs, link)
 30+    wl_list_for_each(screen, &swc.screens, link)
 31     {
 32+        geometry = &screen->base.geometry;
 33         pixman_region32_union_rect(&pointer_region, &pointer_region,
 34-                                   output->geometry.x, output->geometry.y,
 35-                                   output->geometry.width,
 36-                                   output->geometry.height);
 37+                                   geometry->x, geometry->y,
 38+                                   geometry->width, geometry->height);
 39     }
 40 
 41     swc_pointer_set_region(swc.seat->pointer, &pointer_region);
 42@@ -108,10 +110,16 @@ bool swc_initialize(struct wl_display * display,
 43         goto error2;
 44     }
 45 
 46+    if (!swc_screens_initialize())
 47+    {
 48+        ERROR("Could not initialize screens\n");
 49+        goto error3;
 50+    }
 51+
 52     if (!swc_compositor_initialize(&compositor, display, swc.event_loop))
 53     {
 54         ERROR("Could not initialize compositor\n");
 55-        goto error3;
 56+        goto error4;
 57     }
 58 
 59     swc_compositor_add_globals(&compositor, display);
 60@@ -119,32 +127,32 @@ bool swc_initialize(struct wl_display * display,
 61     if (!swc_data_device_manager_initialize())
 62     {
 63         ERROR("Could not initialize data device manager\n");
 64-        goto error4;
 65+        goto error5;
 66     }
 67 
 68     if (!swc_seat_initialize())
 69     {
 70         ERROR("Could not initialize seat\n");
 71-        goto error5;
 72+        goto error6;
 73     }
 74 
 75     if (!swc_bindings_initialize())
 76     {
 77         ERROR("Could not initialize bindings\n");
 78-        goto error6;
 79+        goto error7;
 80     }
 81 
 82     if (!swc_shell_initialize())
 83     {
 84         ERROR("Could not initialize shell\n");
 85-        goto error7;
 86+        goto error8;
 87     }
 88 
 89 #ifdef ENABLE_XWAYLAND
 90     if (!swc_xserver_initialize())
 91     {
 92         ERROR("Could not initialize xwayland\n");
 93-        goto error8;
 94+        goto error9;
 95     }
 96 #endif
 97 
 98@@ -152,16 +160,18 @@ bool swc_initialize(struct wl_display * display,
 99 
100     return true;
101 
102-  error8:
103+  error9:
104     swc_shell_finalize();
105-  error7:
106+  error8:
107     swc_bindings_finalize();
108-  error6:
109+  error7:
110     swc_seat_finalize();
111-  error5:
112+  error6:
113     swc_data_device_manager_finalize();
114-  error4:
115+  error5:
116     swc_compositor_finish(&compositor);
117+  error4:
118+    swc_screens_finalize();
119   error3:
120     swc_shm_finalize();
121   error2:
122@@ -183,6 +193,7 @@ void swc_finalize()
123     swc_seat_finalize();
124     swc_data_device_manager_finalize();
125     swc_compositor_finish(&compositor);
126+    swc_screens_finalize();
127     swc_shm_finalize();
128     swc_drm_finalize();
129     udev_unref(swc.udev);
+17, -4
 1@@ -134,12 +134,25 @@ void swc_window_set_border(struct swc_window * window,
 2 enum
 3 {
 4     /**
 5-     * Sent when either the total_geometry or usable_geometry of the screen has
 6+     * Sent when the screen is about to be destroyed.
 7+     *
 8+     * After this event is sent, the screen is not longer valid.
 9+     */
10+    SWC_SCREEN_DESTROYED,
11+
12+    /**
13+     * Sent when the total area of the screen is changed.
14+     */
15+    SWC_SCREEN_GEOMETRY_CHANGED,
16+
17+    /**
18+     * Sent when the geometry of the screen available for laying out windows is
19      * changed.
20      *
21-     * The data member of this event points to the rectangle which changed.
22+     * Display servers should respond to this event by making sure all visible
23+     * windows are within this area.
24      */
25-    SWC_SCREEN_GEOMETRY_CHANGED
26+    SWC_SCREEN_USABLE_GEOMETRY_CHANGED
27 };
28 
29 struct swc_screen
30@@ -149,7 +162,7 @@ struct swc_screen
31     /**
32      * The total area of the screen.
33      */
34-    struct swc_rectangle total_geometry;
35+    struct swc_rectangle geometry;
36 
37     /**
38      * The area of the screen available for placing windows.