compositor: Send out more detailed output events
authorKristian Høgsberg <krh@bitplanet.net>
Tue, 21 Jun 2011 15:16:58 +0000 (11:16 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Tue, 21 Jun 2011 15:16:58 +0000 (11:16 -0400)
clients/screenshot.c
clients/window.c
compositor/compositor-drm.c
compositor/compositor-wayland.c
compositor/compositor-x11.c
compositor/compositor.c
compositor/compositor.h
compositor/screenshooter.c
compositor/shell.c

index 574f525..b6ca48e 100644 (file)
@@ -45,8 +45,24 @@ static int output_width, output_height;
 
 static void
 display_handle_geometry(void *data,
-                       struct wl_output *output,
-                       int32_t x, int32_t y, int32_t width, int32_t height)
+                       struct wl_output *wl_output,
+                       int x,
+                       int y,
+                       int physical_width,
+                       int physical_height,
+                       int subpixel,
+                       const char *make,
+                       const char *model)
+{
+}
+
+static void
+display_handle_mode(void *data,
+                   struct wl_output *wl_output,
+                   uint32_t flags,
+                   int width,
+                   int height,
+                   int refresh)
 {
        output_width = width;
        output_height = height;
@@ -54,6 +70,7 @@ display_handle_geometry(void *data,
 
 static const struct wl_output_listener output_listener = {
        display_handle_geometry,
+       display_handle_mode
 };
 
 static void
index 612e5b3..4ef7b9e 100644 (file)
@@ -1573,19 +1573,37 @@ static const struct wl_compositor_listener compositor_listener = {
 
 static void
 display_handle_geometry(void *data,
-                       struct wl_output *output,
-                       int32_t x, int32_t y, int32_t width, int32_t height)
+                       struct wl_output *wl_output,
+                       int x, int y,
+                       int physical_width,
+                       int physical_height,
+                       int subpixel,
+                       const char *make,
+                       const char *model)
 {
        struct display *display = data;
 
        display->screen_allocation.x = x;
        display->screen_allocation.y = y;
+}
+
+static void
+display_handle_mode(void *data,
+                   struct wl_output *wl_output,
+                   uint32_t flags,
+                   int width,
+                   int height,
+                   int refresh)
+{
+       struct display *display = data;
+
        display->screen_allocation.width = width;
        display->screen_allocation.height = height;
 }
 
 static const struct wl_output_listener output_listener = {
        display_handle_geometry,
+       display_handle_mode
 };
 
 static void
index 9fc5b49..6e9de4a 100644 (file)
@@ -49,10 +49,14 @@ struct drm_compositor {
        PFNEGLEXPORTDRMIMAGEMESA export_drm_image;
 };
 
+struct drm_mode {
+       struct wlsc_mode base;
+       drmModeModeInfo mode_info;
+};
+
 struct drm_output {
        struct wlsc_output   base;
 
-       drmModeModeInfo mode;
        uint32_t crtc_id;
        uint32_t connector_id;
        GLuint rbo[2];
@@ -146,8 +150,8 @@ drm_output_prepare_scanout_surface(struct wlsc_output *output_base,
 
        if (es->x != output->base.x ||
            es->y != output->base.y ||
-           es->width != output->base.width ||
-           es->height != output->base.height ||
+           es->width != output->base.current->width ||
+           es->height != output->base.current->height ||
            es->image == EGL_NO_IMAGE_KHR)
                return -1;
 
@@ -158,7 +162,8 @@ drm_output_prepare_scanout_surface(struct wlsc_output *output_base,
                return -1;
 
        ret = drmModeAddFB(c->drm.fd,
-                          output->base.width, output->base.height,
+                          output->base.current->width,
+                          output->base.current->height,
                           32, 32, stride, handle, &fb_id);
 
        if (ret)
@@ -192,7 +197,8 @@ drm_output_set_cursor(struct wlsc_output *output_base,
 
        pixman_region32_intersect_rect(&cursor_region, &cursor_region,
                                       output->base.x, output->base.y,
-                                      output->base.width, output->base.height);
+                                      output->base.current->width,
+                                      output->base.current->height);
 
        if (!pixman_region32_not_empty(&cursor_region)) {
                ret = 0;
@@ -319,6 +325,46 @@ static drmModeModeInfo builtin_1024x768 = {
        "1024x768"
 };
 
+
+static int
+drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
+{
+       struct drm_mode *mode;
+
+       mode = malloc(sizeof *mode);
+       if (mode == NULL)
+               return -1;
+
+       mode->base.flags = 0;
+       mode->base.width = info->hdisplay;
+       mode->base.height = info->vdisplay;
+       mode->base.refresh = info->vrefresh;
+       mode->mode_info = *info;
+       wl_list_insert(output->base.mode_list.prev, &mode->base.link);
+
+       return 0;
+}
+
+static int
+drm_subpixel_to_wayland(int drm_value)
+{
+       switch (drm_value) {
+       default:
+       case DRM_MODE_SUBPIXEL_UNKNOWN:
+               return WL_OUTPUT_SUBPIXEL_UNKNOWN;
+       case DRM_MODE_SUBPIXEL_NONE:
+               return WL_OUTPUT_SUBPIXEL_NONE;
+       case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
+               return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
+       case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
+               return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
+       case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
+               return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
+       case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
+               return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
+       }
+}
+
 static int
 create_output_for_connector(struct drm_compositor *ec,
                            drmModeRes *resources,
@@ -326,8 +372,8 @@ create_output_for_connector(struct drm_compositor *ec,
                            int x, int y)
 {
        struct drm_output *output;
+       struct drm_mode *drm_mode;
        drmModeEncoder *encoder;
-       drmModeModeInfo *mode;
        int i, ret;
        EGLint handle, stride, attribs[] = {
                EGL_WIDTH,              0,
@@ -337,15 +383,6 @@ create_output_for_connector(struct drm_compositor *ec,
                EGL_NONE
        };
 
-       output = malloc(sizeof *output);
-       if (output == NULL)
-               return -1;
-
-       if (connector->count_modes > 0) 
-               mode = &connector->modes[0];
-       else
-               mode = &builtin_1024x768;
-
        encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[0]);
        if (encoder == NULL) {
                fprintf(stderr, "No encoder for connector.\n");
@@ -362,16 +399,39 @@ create_output_for_connector(struct drm_compositor *ec,
                return -1;
        }
 
+       output = malloc(sizeof *output);
+       if (output == NULL)
+               return -1;
+
        memset(output, 0, sizeof *output);
-       wlsc_output_init(&output->base, &ec->base, x, y,
-                        mode->hdisplay, mode->vdisplay, 0);
+       output->base.x = x;
+       output->base.y = y;
+       output->base.mm_width = connector->mmWidth;
+       output->base.mm_height = connector->mmHeight;
+       output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
+       output->base.make = "unknown";
+       output->base.model = "unknown";
+       wl_list_init(&output->base.mode_list);
 
        output->crtc_id = resources->crtcs[i];
        ec->crtc_allocator |= (1 << output->crtc_id);
-
        output->connector_id = connector->connector_id;
        ec->connector_allocator |= (1 << output->connector_id);
-       output->mode = *mode;
+
+       for (i = 0; i < connector->count_modes; i++)
+               drm_output_add_mode(output, &connector->modes[i]);
+       if (connector->count_modes == 0)
+               drm_output_add_mode(output, &builtin_1024x768);
+
+       drm_mode = container_of(output->base.mode_list.next,
+                               struct drm_mode, base.link);
+       output->base.current = &drm_mode->base;
+       drm_mode->base.flags =
+               WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+
+       wlsc_output_init(&output->base, &ec->base, x, y, 200, 100, 0);
+
+       wl_list_insert(ec->base.output_list.prev, &output->base.link);
 
        drmModeFreeEncoder(encoder);
 
@@ -379,8 +439,8 @@ create_output_for_connector(struct drm_compositor *ec,
        for (i = 0; i < 2; i++) {
                glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
 
-               attribs[1] = output->base.width;
-               attribs[3] = output->base.height;
+               attribs[1] = output->base.current->width;
+               attribs[3] = output->base.current->height;
                output->image[i] =
                        ec->create_drm_image(ec->base.display, attribs);
                ec->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
@@ -389,7 +449,8 @@ create_output_for_connector(struct drm_compositor *ec,
                                     NULL, &handle, &stride);
 
                ret = drmModeAddFB(ec->drm.fd,
-                                  output->base.width, output->base.height,
+                                  output->base.current->width,
+                                  output->base.current->height,
                                   32, 32, stride, handle, &output->fb_id[i]);
                if (ret) {
                        fprintf(stderr, "failed to add fb %d: %m\n", i);
@@ -404,7 +465,8 @@ create_output_for_connector(struct drm_compositor *ec,
                                  output->rbo[output->current]);
        ret = drmModeSetCrtc(ec->drm.fd, output->crtc_id,
                             output->fb_id[output->current ^ 1], 0, 0,
-                            &output->connector_id, 1, &output->mode);
+                            &output->connector_id, 1,
+                            &drm_mode->mode_info);
        if (ret) {
                fprintf(stderr, "failed to set mode: %m\n");
                return -1;
@@ -417,8 +479,6 @@ create_output_for_connector(struct drm_compositor *ec,
                drm_output_prepare_scanout_surface;
        output->base.set_hardware_cursor = drm_output_set_cursor;
 
-       wl_list_insert(ec->base.output_list.prev, &output->base.link);
-
        return 0;
 }
 
@@ -449,7 +509,7 @@ create_outputs(struct drm_compositor *ec, int option_connector)
                                return -1;
 
                x += container_of(ec->base.output_list.prev, struct wlsc_output,
-                                 link)->width;
+                                 link)->current->width;
 
                drmModeFreeConnector(connector);
        }
@@ -530,7 +590,7 @@ update_outputs(struct drm_compositor *ec)
 
                        /* XXX: not yet needed, we die with 0 outputs */
                        if (!wl_list_empty(&ec->base.output_list))
-                               x = last_output->x + last_output->width;
+                               x = last_output->x + last_output->current->width;
                        else
                                x = 0;
                        y = 0;
@@ -558,7 +618,7 @@ update_outputs(struct drm_compositor *ec)
                                disconnects &= ~(1 << output->connector_id);
                                printf("connector %d disconnected\n",
                                       output->connector_id);
-                               x_offset += output->base.width;
+                               x_offset += output->base.current->width;
                                destroy_output(output);
                        }
                }
index 750e3e7..f547c62 100644 (file)
@@ -67,6 +67,7 @@ struct wayland_output {
                struct wl_egl_window    *egl_window;
        } parent;
        EGLSurface egl_surface;
+       struct wlsc_mode        mode;
 };
 
 struct wayland_input {
@@ -222,8 +223,18 @@ wayland_compositor_create_output(struct wayland_compositor *c,
                return -1;
        memset(output, 0, sizeof *output);
 
+       output->mode.flags =
+               WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+       output->mode.width = width;
+       output->mode.height = height;
+       output->mode.refresh = 60;
+       wl_list_init(&output->base.mode_list);
+       wl_list_insert(&output->base.mode_list, &output->mode.link);
+
+       output->base.current = &output->mode;
        wlsc_output_init(&output->base, &c->base, 0, 0, width, height,
                         WL_OUTPUT_FLIPPED);
+
        output->parent.surface =
                wl_compositor_create_surface(c->parent.compositor);
        wl_surface_set_user_data(output->parent.surface, output);
@@ -281,20 +292,38 @@ cleanup_output:
 /* parent output interface */
 static void
 display_handle_geometry(void *data,
-                       struct wl_output *output,
-                       int32_t x, int32_t y,
-                       int32_t width, int32_t height)
+                       struct wl_output *wl_output,
+                       int x,
+                       int y,
+                       int physical_width,
+                       int physical_height,
+                       int subpixel,
+                       const char *make,
+                       const char *model)
 {
        struct wayland_compositor *c = data;
 
        c->parent.screen_allocation.x = x;
        c->parent.screen_allocation.y = y;
+}
+
+static void
+display_handle_mode(void *data,
+                   struct wl_output *wl_output,
+                   uint32_t flags,
+                   int width,
+                   int height,
+                   int refresh)
+{
+       struct wayland_compositor *c = data;
+
        c->parent.screen_allocation.width = width;
        c->parent.screen_allocation.height = height;
 }
 
 static const struct wl_output_listener output_listener = {
        display_handle_geometry,
+       display_handle_mode
 };
 
 /* parent shell interface */
index 52d094b..0e9fed7 100644 (file)
@@ -71,6 +71,7 @@ struct x11_output {
 
        xcb_window_t            window;
        EGLSurface              egl_surface;
+       struct wlsc_mode        mode;
 };
 
 struct x11_input {
@@ -330,6 +331,16 @@ x11_compositor_create_output(struct x11_compositor *c,
                return -1;
 
        memset(output, 0, sizeof *output);
+
+       output->mode.flags =
+               WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+       output->mode.width = width;
+       output->mode.height = height;
+       output->mode.refresh = 60;
+       wl_list_init(&output->base.mode_list);
+       wl_list_insert(&output->base.mode_list, &output->mode.link);
+
+       output->base.current = &output->mode;
        wlsc_output_init(&output->base, &c->base, 0, 0, width, height,
                         WL_OUTPUT_FLIPPED);
 
index 510f556..5c14b49 100644 (file)
@@ -402,7 +402,8 @@ background_create(struct wlsc_output *output, const char *filename)
 
        background = wlsc_surface_create(output->compositor,
                                         output->x, output->y,
-                                        output->width, output->height);
+                                        output->current->width,
+                                        output->current->height);
        if (background == NULL)
                return NULL;
 
@@ -609,7 +610,8 @@ wlsc_output_damage(struct wlsc_output *output)
        pixman_region32_union_rect(&compositor->damage_region,
                                   &compositor->damage_region,
                                   output->x, output->y,
-                                  output->width, output->height);
+                                  output->current->width,
+                                  output->current->height);
        wlsc_compositor_schedule_repaint(compositor);
 }
 
@@ -647,8 +649,8 @@ fade_output(struct wlsc_output *output,
        surface.compositor = compositor;
        surface.x = output->x;
        surface.y = output->y;
-       surface.width = output->width;
-       surface.height = output->height;
+       surface.width = output->current->width;
+       surface.height = output->current->height;
        surface.texture = GL_NONE;
        surface.transform = NULL;
 
@@ -675,7 +677,7 @@ wlsc_output_repaint(struct wlsc_output *output)
 
        output->prepare_render(output);
 
-       glViewport(0, 0, output->width, output->height);
+       glViewport(0, 0, output->current->width, output->current->height);
 
        glUseProgram(ec->texture_shader.program);
        glUniformMatrix4fv(ec->texture_shader.proj_uniform,
@@ -687,7 +689,8 @@ wlsc_output_repaint(struct wlsc_output *output)
        pixman_region32_intersect_rect(&new_damage,
                                       &ec->damage_region,
                                       output->x, output->y,
-                                      output->width, output->height);
+                                      output->current->width,
+                                      output->current->height);
        pixman_region32_subtract(&ec->damage_region,
                                 &ec->damage_region, &new_damage);
        pixman_region32_union(&total_damage, &new_damage,
@@ -717,8 +720,8 @@ wlsc_output_repaint(struct wlsc_output *output)
        }
 
        if (es->fullscreen_output == output) {
-               if (es->width < output->width ||
-                   es->height < output->height)
+               if (es->width < output->current->width ||
+                   es->height < output->current->height)
                        glClear(GL_COLOR_BUFFER_BIT);
                wlsc_surface_draw(es, output, &total_damage);
        } else {
@@ -838,8 +841,8 @@ wlsc_surface_assign_output(struct wlsc_surface *es)
        es->output = NULL;
 
        wl_list_for_each(output, &ec->output_list, link) {
-               if (output->x < es->x && es->x < output->x + output->width &&
-                   output->y < es->y && es->y < output->y + output->height) {
+               if (output->x < es->x && es->x < output->x + output->current->width &&
+                   output->y < es->y && es->y < output->y + output->current->height) {
                        if (output != tmp)
                                printf("assiging surface %p to output %p\n",
                                       es, output);
@@ -1091,10 +1094,10 @@ notify_motion(struct wl_input_device *device, uint32_t time, int x, int y)
        wlsc_compositor_wake(ec);
 
        wl_list_for_each(output, &ec->output_list, link) {
-               if (output->x <= x && x <= output->x + output->width)
+               if (output->x <= x && x <= output->x + output->current->width)
                        x_valid = 1;
 
-               if (output->y <= y && y <= output->y + output->height)
+               if (output->y <= y && y <= output->y + output->current->height)
                        y_valid = 1;
 
                /* FIXME: calculate this only on output addition/deletion */
@@ -1103,10 +1106,10 @@ notify_motion(struct wl_input_device *device, uint32_t time, int x, int y)
                if (output->y < min_y)
                        min_y = output->y;
 
-               if (output->x + output->width > max_x)
-                       max_x = output->x + output->width;
-               if (output->y + output->height > max_y)
-                       max_y = output->y + output->height;
+               if (output->x + output->current->width > max_x)
+                       max_x = output->x + output->current->width;
+               if (output->y + output->current->height > max_y)
+                       max_y = output->y + output->current->height;
        }
        
        if (!x_valid) {
@@ -1461,11 +1464,23 @@ wlsc_output_post_geometry(struct wl_client *client,
 {
        struct wlsc_output *output =
                container_of(global, struct wlsc_output, object);
+       struct wlsc_mode *mode;
 
        wl_client_post_event(client, global,
                             WL_OUTPUT_GEOMETRY,
-                            output->x, output->y,
-                            output->width, output->height);
+                            output->x,
+                            output->y,
+                            output->mm_width,
+                            output->mm_height,
+                            output->subpixel,
+                            output->make, output->model);
+
+       wl_list_for_each (mode, &output->mode_list, link) {
+               wl_client_post_event(client, global,
+                                    WL_OUTPUT_MODE,
+                                    mode->flags,
+                                    mode->width, mode->height, mode->refresh);
+       }
 }
 
 static const char vertex_shader[] =
@@ -1603,17 +1618,19 @@ wlsc_output_move(struct wlsc_output *output, int x, int y)
 
        wlsc_matrix_init(&output->matrix);
        wlsc_matrix_translate(&output->matrix,
-                             -output->x - output->width / 2.0,
-                             -output->y - output->height / 2.0, 0);
+                             -output->x - output->current->width / 2.0,
+                             -output->y - output->current->height / 2.0, 0);
 
        flip = (output->flags & WL_OUTPUT_FLIPPED) ? -1 : 1;
        wlsc_matrix_scale(&output->matrix,
-                         2.0 / output->width,
-                         flip * 2.0 / output->height, 1);
+                         2.0 / output->current->width,
+                         flip * 2.0 / output->current->height, 1);
 
        pixman_region32_union_rect(&c->damage_region,
                                   &c->damage_region,
-                                  x, y, output->width, output->height);
+                                  x, y,
+                                  output->current->width,
+                                  output->current->height);
 }
 
 WL_EXPORT void
@@ -1623,8 +1640,8 @@ wlsc_output_init(struct wlsc_output *output, struct wlsc_compositor *c,
        output->compositor = c;
        output->x = x;
        output->y = y;
-       output->width = width;
-       output->height = height;
+       output->mm_width = width;
+       output->mm_height = height;
 
        output->background =
                background_create(output, option_background);
index 2546d58..d68eb9a 100644 (file)
@@ -53,18 +53,31 @@ struct wlsc_transform {
 struct wlsc_surface;
 struct wlsc_input_device;
 
+struct wlsc_mode {
+       uint32_t flags;
+       int32_t width, height;
+       uint32_t refresh;
+       struct wl_list link;
+};
+
 struct wlsc_output {
        struct wl_object object;
        struct wl_list link;
        struct wlsc_compositor *compositor;
        struct wlsc_surface *background;
        struct wlsc_matrix matrix;
-       int32_t x, y, width, height;
+       int32_t x, y, mm_width, mm_height;
        pixman_region32_t previous_damage_region;
        uint32_t flags;
        int repaint_needed;
        int finished;
 
+       char *make, *model;
+       uint32_t subpixel;
+       
+       struct wlsc_mode *current;
+       struct wl_list mode_list;
+
        int (*prepare_render)(struct wlsc_output *output);
        int (*present)(struct wlsc_output *output);
        int (*prepare_scanout_surface)(struct wlsc_output *output,
index ee1ccf6..4d7660d 100644 (file)
@@ -36,11 +36,12 @@ screenshooter_shoot(struct wl_client *client,
        if (!wl_buffer_is_shm(buffer))
                return;
 
-       if (buffer->width < output->width || buffer->height < output->height)
+       if (buffer->width < output->current->width ||
+           buffer->height < output->current->height)
                return;
 
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
-       glReadPixels(0, 0, output->width, output->height,
+       glReadPixels(0, 0, output->current->width, output->current->height,
                     GL_RGBA, GL_UNSIGNED_BYTE,
                     wl_shm_buffer_get_data(buffer));
 }
index 577aa57..388ccac 100644 (file)
@@ -301,8 +301,8 @@ shell_set_fullscreen(struct wl_client *client,
 
        es->saved_x = es->x;
        es->saved_y = es->y;
-       es->x = (output->width - es->width) / 2;
-       es->y = (output->height - es->height) / 2;
+       es->x = (output->current->width - es->width) / 2;
+       es->y = (output->current->height - es->height) / 2;
        es->fullscreen_output = output;
        wlsc_surface_damage(es);
        es->map_type = WLSC_SURFACE_MAP_FULLSCREEN;
@@ -807,8 +807,8 @@ static void
 attach(struct wlsc_shell *shell, struct wlsc_surface *es)
 {
        if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
-               es->x = (es->fullscreen_output->width - es->width) / 2;
-               es->y = (es->fullscreen_output->height - es->height) / 2;
+               es->x = (es->fullscreen_output->current->width - es->width) / 2;
+               es->y = (es->fullscreen_output->current->height - es->height) / 2;
        }
 }