Integrate the monitor manager with wayland

Use the right backend when running as a wayland compositor,
export the data to wayland clients, and use it to keep the stage
appropriately sized.
This commit is contained in:
Giovanni Campagna 2013-08-19 11:12:42 +02:00
parent aa15c09d54
commit 9a4783e364
6 changed files with 209 additions and 92 deletions

View File

@ -668,6 +668,9 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
{ {
wayland_compositor = meta_wayland_compositor_get_default (); wayland_compositor = meta_wayland_compositor_get_default ();
info->stage = wayland_compositor->stage; info->stage = wayland_compositor->stage;
meta_screen_get_size (screen, &width, &height);
clutter_actor_set_size (info->stage, width, height);
} }
else else
{ {
@ -1416,18 +1419,25 @@ meta_compositor_sync_screen_size (MetaCompositor *compositor,
guint width, guint width,
guint height) guint height)
{ {
MetaDisplay *display = meta_screen_get_display (screen);
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
if (meta_is_wayland_compositor ()) if (meta_is_wayland_compositor ())
{ {
/* It's not clear at the moment how we will be dealing with screen /* FIXME: when we support a sliced stage, this is the place to do it
* resizing as a Wayland compositor so for now just abort if we But! This is not the place to apply KMS config, here we only
* hit this code. */ notify Clutter/Cogl/GL that the framebuffer sizes changed.
g_critical ("Unexpected call to meta_compositor_sync_screen_size() "
"when running as a wayland compositor"); And because for now clutter does not do sliced, we use one
framebuffer the size of the whole screen, and when running on
bare metal MetaMonitorManager will do the necessary tricks to
show the right portions on the right screens.
*/
clutter_actor_set_size (info->stage, width, height);
} }
else else
{ {
MetaDisplay *display = meta_screen_get_display (screen);
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
Display *xdisplay; Display *xdisplay;
Window xwin; Window xwin;
@ -1438,12 +1448,12 @@ meta_compositor_sync_screen_size (MetaCompositor *compositor,
xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
XResizeWindow (xdisplay, xwin, width, height); XResizeWindow (xdisplay, xwin, width, height);
}
meta_verbose ("Changed size for stage on screen %d to %dx%d\n", meta_verbose ("Changed size for stage on screen %d to %dx%d\n",
meta_screen_get_screen_number (screen), meta_screen_get_screen_number (screen),
width, height); width, height);
} }
}
static void static void
frame_callback (CoglOnscreen *onscreen, frame_callback (CoglOnscreen *onscreen,

View File

@ -474,6 +474,15 @@ make_logical_config (MetaMonitorManager *manager)
manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE); manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE);
} }
static GType
get_default_backend (void)
{
if (meta_is_wayland_compositor ())
return META_TYPE_MONITOR_MANAGER; /* FIXME: KMS */
else
return META_TYPE_MONITOR_MANAGER_XRANDR;
}
static MetaMonitorManager * static MetaMonitorManager *
meta_monitor_manager_new (void) meta_monitor_manager_new (void)
{ {
@ -483,7 +492,7 @@ meta_monitor_manager_new (void)
env = g_getenv ("META_DEBUG_MULTIMONITOR"); env = g_getenv ("META_DEBUG_MULTIMONITOR");
if (env == NULL) if (env == NULL)
type = META_TYPE_MONITOR_MANAGER_XRANDR; type = get_default_backend ();
else if (strcmp (env, "xrandr") == 0) else if (strcmp (env, "xrandr") == 0)
type = META_TYPE_MONITOR_MANAGER_XRANDR; type = META_TYPE_MONITOR_MANAGER_XRANDR;
else else

View File

@ -676,6 +676,7 @@ meta_screen_new (MetaDisplay *display,
screen->xroot = xroot; screen->xroot = xroot;
screen->rect.x = screen->rect.y = 0; screen->rect.x = screen->rect.y = 0;
if (!meta_is_wayland_compositor ())
meta_monitor_manager_initialize (); meta_monitor_manager_initialize ();
manager = meta_monitor_manager_get (); manager = meta_monitor_manager_get ();

View File

@ -112,26 +112,6 @@ typedef struct
struct wl_listener surface_destroy_listener; struct wl_listener surface_destroy_listener;
} MetaWaylandShellSurface; } MetaWaylandShellSurface;
typedef struct
{
guint32 flags;
int width;
int height;
int refresh;
} MetaWaylandMode;
typedef struct
{
struct wl_object wayland_output;
int x;
int y;
int width_mm;
int height_mm;
/* XXX: with sliced stages we'd reference a CoglFramebuffer here. */
GList *modes;
} MetaWaylandOutput;
typedef struct typedef struct
{ {
GSource source; GSource source;
@ -155,7 +135,7 @@ struct _MetaWaylandCompositor
struct wl_event_loop *wayland_loop; struct wl_event_loop *wayland_loop;
GMainLoop *init_loop; GMainLoop *init_loop;
ClutterActor *stage; ClutterActor *stage;
GList *outputs; GHashTable *outputs;
GSource *wayland_event_source; GSource *wayland_event_source;
GList *surfaces; GList *surfaces;
struct wl_list frame_callbacks; struct wl_list frame_callbacks;

View File

@ -55,6 +55,7 @@ meta_wayland_stage_class_init (MetaWaylandStageClass *klass)
static void static void
meta_wayland_stage_init (MetaWaylandStage *self) meta_wayland_stage_init (MetaWaylandStage *self)
{ {
clutter_stage_set_user_resizable (CLUTTER_STAGE (self), FALSE);
} }
ClutterActor * ClutterActor *

View File

@ -50,6 +50,7 @@
#include <meta/main.h> #include <meta/main.h>
#include "frame.h" #include "frame.h"
#include "meta-idle-monitor-private.h" #include "meta-idle-monitor-private.h"
#include "monitor-private.h"
static MetaWaylandCompositor _meta_wayland_compositor; static MetaWaylandCompositor _meta_wayland_compositor;
@ -629,84 +630,186 @@ meta_wayland_compositor_create_region (struct wl_client *wayland_client,
region->region = cairo_region_create (); region->region = cairo_region_create ();
} }
typedef struct {
MetaOutput *output;
struct wl_global *global;
int x, y;
enum wl_output_transform transform;
GList *resources;
} MetaWaylandOutput;
static void
output_resource_destroy (struct wl_resource *res)
{
MetaWaylandOutput *wayland_output;
wayland_output = wl_resource_get_user_data (res);
wayland_output->resources = g_list_remove (wayland_output->resources, res);
}
static void static void
bind_output (struct wl_client *client, bind_output (struct wl_client *client,
void *data, void *data,
guint32 version, guint32 version,
guint32 id) guint32 id)
{ {
MetaWaylandOutput *output = data; MetaWaylandOutput *wayland_output = data;
struct wl_resource *resource = MetaOutput *output = wayland_output->output;
wl_resource_create (client, &wl_output_interface, version, id); struct wl_resource *resource;
GList *l; guint mode_flags;
resource = wl_resource_create (client, &wl_output_interface, version, id);
wayland_output->resources = g_list_prepend (wayland_output->resources, resource);
wl_resource_set_user_data (resource, wayland_output);
wl_resource_set_destructor (resource, output_resource_destroy);
meta_verbose ("Binding output %p/%s (%u, %u, %u, %u) x %f\n",
output, output->name,
output->crtc->rect.x, output->crtc->rect.y,
output->crtc->rect.width, output->crtc->rect.height,
output->crtc->current_mode->refresh_rate);
wl_resource_post_event (resource, wl_resource_post_event (resource,
WL_OUTPUT_GEOMETRY, WL_OUTPUT_GEOMETRY,
output->x, output->y, (int)output->crtc->rect.x,
(int)output->crtc->rect.y,
output->width_mm, output->width_mm,
output->height_mm, output->height_mm,
0, /* subpixel: unknown */ /* Cogl values reflect XRandR values,
"unknown", /* make */ and so does wayland */
"unknown"); /* model */ output->subpixel_order,
output->vendor,
output->product,
output->crtc->transform);
g_assert (output->crtc->current_mode != NULL);
mode_flags = WL_OUTPUT_MODE_CURRENT;
if (output->crtc->current_mode == output->preferred_mode)
mode_flags |= WL_OUTPUT_MODE_PREFERRED;
for (l = output->modes; l; l = l->next)
{
MetaWaylandMode *mode = l->data;
wl_resource_post_event (resource, wl_resource_post_event (resource,
WL_OUTPUT_MODE, WL_OUTPUT_MODE,
mode->flags, mode_flags,
mode->width, (int)output->crtc->current_mode->width,
mode->height, (int)output->crtc->current_mode->height,
mode->refresh); (int)output->crtc->current_mode->refresh_rate);
}
if (version >= 2)
wl_resource_post_event (resource,
WL_OUTPUT_DONE);
} }
static void static void
meta_wayland_compositor_create_output (MetaWaylandCompositor *compositor, wayland_output_destroy_notify (gpointer data)
int x,
int y,
int width,
int height,
int width_mm,
int height_mm)
{ {
MetaWaylandOutput *output = g_slice_new0 (MetaWaylandOutput); MetaWaylandOutput *wayland_output = data;
MetaWaylandMode *mode; GList *resources;
float final_width, final_height;
/* XXX: eventually we will support sliced stages and an output should /* Make sure the destructors don't mess with the list */
* correspond to a slice/CoglFramebuffer, but for now we only support resources = wayland_output->resources;
* one output so we make sure it always matches the size of the stage wayland_output->resources = NULL;
*/
clutter_actor_set_size (compositor->stage, width, height);
/* Read back the actual size we were given. wl_global_destroy (wayland_output->global);
* XXX: This really needs re-thinking later though so we know the g_list_free (resources);
* correct output geometry to use. */
clutter_actor_get_size (compositor->stage, &final_width, &final_height);
width = final_width;
height = final_height;
output->wayland_output.interface = &wl_output_interface; g_slice_free (MetaWaylandOutput, wayland_output);
}
output->x = x; static void
output->y = y; wayland_output_update_for_output (MetaWaylandOutput *wayland_output,
output->width_mm = width_mm; MetaOutput *output)
output->height_mm = height_mm; {
GList *iter;
guint mode_flags;
wl_global_create (compositor->wayland_display, g_assert (output->crtc->current_mode != NULL);
mode_flags = WL_OUTPUT_MODE_CURRENT;
if (output->crtc->current_mode == output->preferred_mode)
mode_flags |= WL_OUTPUT_MODE_PREFERRED;
for (iter = wayland_output->resources; iter; iter = iter->next)
{
struct wl_resource *resource = iter->data;
if (wayland_output->x != output->crtc->rect.x ||
wayland_output->y != output->crtc->rect.y ||
wayland_output->transform != output->crtc->transform)
{
wl_resource_post_event (resource,
WL_OUTPUT_GEOMETRY,
(int)output->crtc->rect.x,
(int)output->crtc->rect.y,
output->width_mm,
output->height_mm,
output->subpixel_order,
output->vendor,
output->product,
output->crtc->transform);
}
wl_resource_post_event (resource,
WL_OUTPUT_MODE,
mode_flags,
(int)output->crtc->current_mode->width,
(int)output->crtc->current_mode->height,
(int)output->crtc->current_mode->refresh_rate);
}
/* It's very important that we change the output pointer here, as
the old structure is about to be freed by MetaMonitorManager */
wayland_output->output = output;
wayland_output->x = output->crtc->rect.x;
wayland_output->y = output->crtc->rect.y;
wayland_output->transform = output->crtc->transform;
}
static GHashTable *
meta_wayland_compositor_update_outputs (MetaWaylandCompositor *compositor,
MetaMonitorManager *monitors)
{
MetaOutput *outputs;
unsigned int i, n_outputs;
GHashTable *new_table;
outputs = meta_monitor_manager_get_outputs (monitors, &n_outputs);
new_table = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify);
for (i = 0; i < n_outputs; i++)
{
MetaOutput *output = &outputs[i];
MetaWaylandOutput *wayland_output;
/* wayland does not expose disabled outputs */
if (output->crtc == NULL)
{
g_hash_table_remove (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
continue;
}
wayland_output = g_hash_table_lookup (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
if (wayland_output)
{
g_hash_table_steal (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
}
else
{
wayland_output = g_slice_new0 (MetaWaylandOutput);
wayland_output->global = wl_global_create (compositor->wayland_display,
&wl_output_interface, 2, &wl_output_interface, 2,
output, bind_output); wayland_output, bind_output);
}
mode = g_slice_new0 (MetaWaylandMode); wayland_output_update_for_output (wayland_output, output);
mode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED; g_hash_table_insert (new_table, GSIZE_TO_POINTER (output->output_id), wayland_output);
mode->width = width; }
mode->height = height;
mode->refresh = 60;
output->modes = g_list_prepend (output->modes, mode); g_hash_table_destroy (compositor->outputs);
return new_table;
compositor->outputs = g_list_prepend (compositor->outputs, output);
} }
const static struct wl_compositor_interface meta_wayland_compositor_interface = { const static struct wl_compositor_interface meta_wayland_compositor_interface = {
@ -1413,11 +1516,19 @@ event_emission_hook_cb (GSignalInvocationHint *ihint,
return TRUE /* stay connected */; return TRUE /* stay connected */;
} }
static void
on_monitors_changed (MetaMonitorManager *monitors,
MetaWaylandCompositor *compositor)
{
compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
}
void void
meta_wayland_init (void) meta_wayland_init (void)
{ {
MetaWaylandCompositor *compositor = &_meta_wayland_compositor; MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
guint event_signal; guint event_signal;
MetaMonitorManager *monitors;
memset (compositor, 0, sizeof (MetaWaylandCompositor)); memset (compositor, 0, sizeof (MetaWaylandCompositor));
@ -1457,8 +1568,15 @@ meta_wayland_init (void)
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS) if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
g_error ("Failed to initialize Clutter"); g_error ("Failed to initialize Clutter");
meta_monitor_manager_initialize ();
monitors = meta_monitor_manager_get ();
g_signal_connect (monitors, "monitors-changed",
G_CALLBACK (on_monitors_changed), compositor);
compositor->outputs = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify);
compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
compositor->stage = meta_wayland_stage_new (); compositor->stage = meta_wayland_stage_new ();
clutter_stage_set_user_resizable (CLUTTER_STAGE (compositor->stage), FALSE);
g_signal_connect_after (compositor->stage, "paint", g_signal_connect_after (compositor->stage, "paint",
G_CALLBACK (paint_finished_cb), compositor); G_CALLBACK (paint_finished_cb), compositor);
g_signal_connect (compositor->stage, "destroy", g_signal_connect (compositor->stage, "destroy",
@ -1483,8 +1601,6 @@ meta_wayland_init (void)
compositor, /* hook_data */ compositor, /* hook_data */
NULL /* data_destroy */); NULL /* data_destroy */);
meta_wayland_compositor_create_output (compositor, 0, 0, 1024, 600, 222, 125);
if (wl_global_create (compositor->wayland_display, if (wl_global_create (compositor->wayland_display,
&wl_shell_interface, 1, &wl_shell_interface, 1,
compositor, bind_shell) == NULL) compositor, bind_shell) == NULL)