Split monitor handling into an helper object

Create a new singleton object, MetaMonitorManager, which deals
with reading the XRandR configuration and in the future applying
the new one.
This is required because xwayland will not bind the xserver interface
until he has seen the current wl_outputs, so we can't wait
until MetaScreen is built to expose them.
This commit is contained in:
Giovanni Campagna 2013-07-18 14:45:48 +02:00
parent cf296f26b1
commit 2777dfc533
8 changed files with 596 additions and 326 deletions

View File

@ -125,6 +125,8 @@ libmutter_la_SOURCES = \
core/main.c \
core/meta-cursor-tracker.c \
core/meta-cursor-tracker-private.h \
core/monitor.c \
core/monitor-private.h \
core/mutter-Xatomtype.h \
core/place.c \
core/place.h \

View File

@ -0,0 +1,98 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/**
* \file screen-private.h Handling of monitor configuration
*
* Managing multiple monitors
* This file contains structures and functions that handle
* multiple monitors, including reading the current configuration
* and available hardware, and applying it.
*
* This interface is private to mutter, API users should look
* at MetaScreen instead.
*/
/*
* Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2003 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
* Copyright (C) 2013 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_MONITOR_PRIVATE_H
#define META_MONITOR_PRIVATE_H
#include "display-private.h"
#include <meta/screen.h>
#include "stack-tracker.h"
#include "ui.h"
#include <cogl/cogl.h>
typedef struct _MetaOutput MetaOutput;
typedef struct _MetaMonitorInfo MetaMonitorInfo;
struct _MetaOutput
{
MetaMonitorInfo *monitor;
char *name;
int width_mm;
int height_mm;
CoglSubpixelOrder subpixel_order;
};
struct _MetaMonitorInfo
{
int number;
int xinerama_index;
MetaRectangle rect;
gboolean is_primary;
gboolean in_fullscreen;
float refresh_rate;
/* The primary or first output for this crtc, 0 if we can't figure out.
This is a XID when using XRandR, otherwise a KMS id (not implemented) */
glong output_id;
};
#define META_TYPE_MONITOR_MANAGER (meta_monitor_manager_get_type ())
#define META_MONITOR_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManager))
#define META_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass))
#define META_IS_MONITOR_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER))
#define META_IS_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER))
#define META_MONITOR_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass))
typedef struct _MetaMonitorManagerClass MetaMonitorManagerClass;
typedef struct _MetaMonitorManager MetaMonitorManager;
GType meta_monitor_manager_get_type (void);
void meta_monitor_manager_initialize (Display *display);
MetaMonitorManager *meta_monitor_manager_get (void);
MetaMonitorInfo *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
int *n_infos);
MetaOutput *meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
int *n_outputs);
int meta_monitor_manager_get_primary_index (MetaMonitorManager *manager);
void meta_monitor_manager_invalidate (MetaMonitorManager *manager);
#endif

432
src/core/monitor.c Normal file
View File

@ -0,0 +1,432 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2001, 2002 Havoc Pennington
* Copyright (C) 2002, 2003 Red Hat Inc.
* Some ICCCM manager selection code derived from fvwm2,
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
* Copyright (C) 2003 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
* Copyright (C) 2013 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "config.h"
#include <clutter/clutter.h>
#ifdef HAVE_RANDR
#include <X11/extensions/Xrandr.h>
#endif
#include "monitor-private.h"
#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
#endif
struct _MetaMonitorManager
{
GObject parent_instance;
/* Outputs refers to physical screens,
while monitor_infos refer to logical ones (aka CRTC)
They can be different if two outputs are
in clone mode
*/
MetaOutput *outputs;
int primary_monitor_index;
int n_outputs;
MetaMonitorInfo *monitor_infos;
int n_monitor_infos;
#ifdef HAVE_RANDR
Display *xdisplay;
#endif
};
struct _MetaMonitorManagerClass
{
GObjectClass parent_class;
};
enum {
MONITORS_CHANGED,
SIGNALS_LAST
};
static int signals[SIGNALS_LAST];
G_DEFINE_TYPE (MetaMonitorManager, meta_monitor_manager, G_TYPE_OBJECT);
static void
make_dummy_monitor_config (MetaMonitorManager *manager)
{
manager->monitor_infos = g_new0 (MetaMonitorInfo, 1);
manager->n_monitor_infos = 1;
manager->monitor_infos[0].number = 0;
manager->monitor_infos[0].xinerama_index = 0;
manager->monitor_infos[0].rect.x = 0;
manager->monitor_infos[0].rect.y = 0;
if (manager->xdisplay)
{
Screen *screen = ScreenOfDisplay (manager->xdisplay,
DefaultScreen (manager->xdisplay));
manager->monitor_infos[0].rect.width = WidthOfScreen (screen);
manager->monitor_infos[0].rect.height = HeightOfScreen (screen);
}
else
{
manager->monitor_infos[0].rect.width = 1024;
manager->monitor_infos[0].rect.height = 768;
}
manager->monitor_infos[0].refresh_rate = 60.0f;
manager->monitor_infos[0].is_primary = TRUE;
manager->monitor_infos[0].in_fullscreen = -1;
manager->monitor_infos[0].output_id = 1;
manager->outputs = g_new0 (MetaOutput, 1);
manager->n_outputs = 1;
manager->outputs[0].monitor = &manager->monitor_infos[0];
manager->outputs[0].name = g_strdup ("LVDS");
manager->outputs[0].width_mm = 222;
manager->outputs[0].height_mm = 125;
manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
}
#ifdef HAVE_RANDR
/* In the case of multiple outputs of a single crtc (mirroring), we consider one of the
* outputs the "main". This is the one we consider "owning" the windows, so if
* the mirroring is changed to a dual monitor setup then the windows are moved to the
* crtc that now has that main output. If one of the outputs is the primary that is
* always the main, otherwise we just use the first.
*/
static void
find_main_output_for_crtc (MetaMonitorManager *manager,
XRRScreenResources *resources,
XRRCrtcInfo *crtc,
MetaMonitorInfo *info,
GArray *outputs)
{
XRROutputInfo *output;
RROutput primary_output;
int i;
primary_output = XRRGetOutputPrimary (manager->xdisplay,
DefaultRootWindow (manager->xdisplay));
for (i = 0; i < crtc->noutput; i++)
{
output = XRRGetOutputInfo (manager->xdisplay, resources, crtc->outputs[i]);
if (output->connection != RR_Disconnected)
{
MetaOutput meta_output;
meta_output.name = g_strdup (output->name);
meta_output.width_mm = output->mm_width;
meta_output.height_mm = output->mm_height;
meta_output.subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
g_array_append_val (outputs, meta_output);
if (crtc->outputs[i] == primary_output)
{
info->output_id = crtc->outputs[i];
info->is_primary = TRUE;
manager->primary_monitor_index = info->number;
}
else if (info->output_id == 0)
{
info->output_id = crtc->outputs[i];
}
}
XRRFreeOutputInfo (output);
}
}
static void
read_monitor_infos_from_xrandr (MetaMonitorManager *manager)
{
XRRScreenResources *resources;
GArray *outputs;
int i, j;
resources = XRRGetScreenResourcesCurrent (manager->xdisplay,
DefaultRootWindow (manager->xdisplay));
if (!resources)
return make_dummy_monitor_config (manager);
outputs = g_array_new (FALSE, TRUE, sizeof (MetaOutput));
manager->n_outputs = 0;
manager->n_monitor_infos = resources->ncrtc;
manager->monitor_infos = g_new0 (MetaMonitorInfo, manager->n_monitor_infos);
for (i = 0; i < resources->ncrtc; i++)
{
XRRCrtcInfo *crtc;
MetaMonitorInfo *info;
crtc = XRRGetCrtcInfo (manager->xdisplay, resources, resources->crtcs[i]);
info = &manager->monitor_infos[i];
info->number = i;
info->rect.x = crtc->x;
info->rect.y = crtc->y;
info->rect.width = crtc->width;
info->rect.height = crtc->height;
info->in_fullscreen = -1;
for (j = 0; j < resources->nmode; j++)
{
if (resources->modes[j].id == crtc->mode)
info->refresh_rate = (resources->modes[j].dotClock /
((float)resources->modes[j].hTotal *
resources->modes[j].vTotal));
}
find_main_output_for_crtc (manager, resources, crtc, info, outputs);
XRRFreeCrtcInfo (crtc);
}
manager->n_outputs = outputs->len;
manager->outputs = (void*)g_array_free (outputs, FALSE);
XRRFreeScreenResources (resources);
}
#endif
typedef struct {
GArray *monitor_infos;
GArray *outputs;
} ReadMonitorCoglClosure;
static void
read_monitor_from_cogl_helper (CoglOutput *output,
void *user_data)
{
ReadMonitorCoglClosure *closure = user_data;
MetaMonitorInfo info;
MetaOutput meta_output;
info.number = closure->monitor_infos->len;
info.rect.x = cogl_output_get_x (output);
info.rect.y = cogl_output_get_y (output);
info.rect.width = cogl_output_get_width (output);
info.rect.height = cogl_output_get_height (output);
info.refresh_rate = cogl_output_get_refresh_rate (output);
info.is_primary = (info.number == 0);
info.in_fullscreen = -1;
info.output_id = 0; /* unknown */
g_array_append_val (closure->monitor_infos, info);
meta_output.monitor = &g_array_index (closure->monitor_infos,
MetaMonitorInfo,
closure->monitor_infos->len - 1);
meta_output.name = NULL;
meta_output.width_mm = cogl_output_get_mm_width (output);
meta_output.height_mm = cogl_output_get_mm_height (output);
meta_output.subpixel_order = cogl_output_get_subpixel_order (output);
g_array_append_val (closure->outputs, meta_output);
}
static void
read_monitor_infos_from_cogl (MetaMonitorManager *manager)
{
ReadMonitorCoglClosure closure;
ClutterBackend *backend;
CoglContext *cogl_context;
CoglRenderer *cogl_renderer;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
closure.monitor_infos = g_array_new (FALSE, TRUE, sizeof (MetaMonitorInfo));
closure.outputs = g_array_new (FALSE, TRUE, sizeof (MetaOutput));
cogl_renderer_foreach_output (cogl_renderer,
read_monitor_from_cogl_helper, &closure);
manager->n_monitor_infos = closure.monitor_infos->len;
manager->monitor_infos = (void*)g_array_free (closure.monitor_infos, FALSE);
manager->n_outputs = closure.outputs->len;
manager->outputs = (void*)g_array_free (closure.outputs, FALSE);
manager->primary_monitor_index = 0;
}
/*
* meta_has_dummy_output:
*
* Returns TRUE if the only available monitor is the dummy one
* backing the ClutterStage window.
*/
static gboolean
has_dummy_output (void)
{
MetaWaylandCompositor *compositor;
if (!meta_is_wayland_compositor ())
return FALSE;
/* FIXME: actually, even in EGL-KMS mode, Cogl does not
expose the outputs through CoglOutput - yet */
compositor = meta_wayland_compositor_get_default ();
return !meta_wayland_compositor_is_native (compositor);
}
static void
meta_monitor_manager_init (MetaMonitorManager *manager)
{
}
static void
read_current_config (MetaMonitorManager *manager)
{
if (has_dummy_output ())
return make_dummy_monitor_config (manager);
#ifdef HAVE_RANDR
if (!meta_is_wayland_compositor ())
return read_monitor_infos_from_xrandr (manager);
#endif
return read_monitor_infos_from_cogl (manager);
}
static MetaMonitorManager *
meta_monitor_manager_new (Display *display)
{
MetaMonitorManager *manager;
manager = g_object_new (META_TYPE_MONITOR_MANAGER, NULL);
manager->xdisplay = display;
read_current_config (manager);
return manager;
}
static void
free_output_array (MetaOutput *old_outputs,
int n_old_outputs)
{
int i;
for (i = 0; i < n_old_outputs; i++)
g_free (old_outputs[i].name);
g_free (old_outputs);
}
static void
meta_monitor_manager_finalize (GObject *object)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
free_output_array (manager->outputs, manager->n_outputs);
g_free (manager->monitor_infos);
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object);
}
static void
meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_monitor_manager_finalize;
signals[MONITORS_CHANGED] =
g_signal_new ("monitors-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static MetaMonitorManager *global_manager;
void
meta_monitor_manager_initialize (Display *display)
{
global_manager = meta_monitor_manager_new (display);
}
MetaMonitorManager *
meta_monitor_manager_get (void)
{
g_assert (global_manager != NULL);
return global_manager;
}
MetaMonitorInfo *
meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
int *n_infos)
{
*n_infos = manager->n_monitor_infos;
return manager->monitor_infos;
}
MetaOutput *
meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
int *n_outputs)
{
*n_outputs = manager->n_outputs;
return manager->outputs;
}
int
meta_monitor_manager_get_primary_index (MetaMonitorManager *manager)
{
return manager->primary_monitor_index;
}
void
meta_monitor_manager_invalidate (MetaMonitorManager *manager)
{
MetaOutput *old_outputs;
MetaMonitorInfo *old_monitor_infos;
int n_old_outputs;
/* Save the old monitor infos, so they stay valid during the update */
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_monitor_infos = manager->monitor_infos;
read_current_config (manager);
g_signal_emit (manager, signals[MONITORS_CHANGED], 0);
g_free (old_monitor_infos);
free_output_array (old_outputs, n_old_outputs);
}

View File

@ -38,34 +38,7 @@
#include <X11/Xutil.h>
#include "stack-tracker.h"
#include "ui.h"
#include <cogl/cogl.h>
typedef struct _MetaOutput MetaOutput;
typedef struct _MetaMonitorInfo MetaMonitorInfo;
struct _MetaOutput
{
MetaMonitorInfo *monitor;
char *name;
int width_mm;
int height_mm;
CoglSubpixelOrder subpixel_order;
};
struct _MetaMonitorInfo
{
int number;
int xinerama_index;
MetaRectangle rect;
gboolean is_primary;
gboolean in_fullscreen;
float refresh_rate;
/* The primary or first output for this crtc, 0 if we can't figure out.
This is a XID when using XRandR, otherwise a KMS id (not implemented) */
glong output_id;
};
#include "monitor-private.h"
typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
gpointer user_data);
@ -119,16 +92,9 @@ struct _MetaScreen
Atom wm_sn_atom;
guint32 wm_sn_timestamp;
/* Outputs refers to physical screens,
while monitor_infos refer to logical ones (aka CRTC)
They can be different if two outputs are
in clone mode
*/
MetaOutput *outputs;
MetaMonitorInfo *monitor_infos;
int primary_monitor_index;
int n_outputs;
int n_monitor_infos;
int primary_monitor_index;
gboolean has_xinerama_indices;
/* Cache the current monitor */

View File

@ -52,10 +52,6 @@
#include <X11/extensions/Xinerama.h>
#ifdef HAVE_RANDR
#include <X11/extensions/Xrandr.h>
#endif
#include <X11/Xatom.h>
#include <locale.h>
#include <string.h>
@ -80,6 +76,9 @@ static void meta_screen_sn_event (SnMonitorEvent *event,
void *user_data);
#endif
static void on_monitors_changed (MetaMonitorManager *manager,
MetaScreen *screen);
enum
{
PROP_N_WORKSPACES = 1,
@ -354,54 +353,6 @@ set_wm_icon_size_hint (MetaScreen *screen)
#undef N_VALS
}
/*
* meta_has_dummy_output:
*
* Returns TRUE if the only available monitor is the dummy one
* backing the ClutterStage window.
*/
static gboolean
has_dummy_output (void)
{
MetaWaylandCompositor *compositor;
if (!meta_is_wayland_compositor ())
return FALSE;
/* FIXME: actually, even in EGL-KMS mode, Cogl does not
expose the outputs through CoglOutput - yet */
compositor = meta_wayland_compositor_get_default ();
return !meta_wayland_compositor_is_native (compositor);
}
static void
make_dummy_monitor_config (MetaScreen *screen)
{
screen->outputs = g_new0 (MetaOutput, 1);
screen->n_outputs = 1;
screen->outputs[0].name = g_strdup ("LVDS");
screen->outputs[0].width_mm = 222;
screen->outputs[0].height_mm = 125;
screen->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
screen->monitor_infos = g_new0 (MetaMonitorInfo, 1);
screen->n_monitor_infos = 1;
screen->monitor_infos[0].number = 0;
screen->monitor_infos[0].xinerama_index = 0;
screen->monitor_infos[0].rect.x = 0;
screen->monitor_infos[0].rect.y = 0;
screen->monitor_infos[0].rect.width = screen->rect.width;
screen->monitor_infos[0].rect.height = screen->rect.height;
screen->monitor_infos[0].refresh_rate = 60.0f;
screen->monitor_infos[0].is_primary = TRUE;
screen->monitor_infos[0].in_fullscreen = -1;
screen->monitor_infos[0].output_id = 1;
screen->has_xinerama_indices = TRUE;
}
static void
meta_screen_ensure_xinerama_indices (MetaScreen *screen)
{
@ -462,179 +413,11 @@ meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
return -1;
}
#ifdef HAVE_RANDR
/* In the case of multiple outputs of a single crtc (mirroring), we consider one of the
* outputs the "main". This is the one we consider "owning" the windows, so if
* the mirroring is changed to a dual monitor setup then the windows are moved to the
* crtc that now has that main output. If one of the outputs is the primary that is
* always the main, otherwise we just use the first.
*/
static void
find_main_output_for_crtc (MetaScreen *screen,
XRRScreenResources *resources,
XRRCrtcInfo *crtc,
MetaMonitorInfo *info,
GArray *outputs)
{
XRROutputInfo *output;
RROutput primary_output;
int i;
primary_output = XRRGetOutputPrimary (screen->display->xdisplay, screen->xroot);
for (i = 0; i < crtc->noutput; i++)
{
output = XRRGetOutputInfo (screen->display->xdisplay, resources, crtc->outputs[i]);
if (output->connection != RR_Disconnected)
{
MetaOutput meta_output;
meta_output.name = g_strdup (output->name);
meta_output.width_mm = output->mm_width;
meta_output.height_mm = output->mm_height;
meta_output.subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
g_array_append_val (outputs, meta_output);
if (crtc->outputs[i] == primary_output)
{
info->output_id = crtc->outputs[i];
info->is_primary = TRUE;
screen->primary_monitor_index = info->number;
}
else if (info->output_id == 0)
{
info->output_id = crtc->outputs[i];
}
}
XRRFreeOutputInfo (output);
}
}
static void
read_monitor_infos_from_xrandr (MetaScreen *screen)
{
XRRScreenResources *resources;
GArray *outputs;
int i, j;
resources = XRRGetScreenResourcesCurrent (screen->display->xdisplay, screen->xroot);
if (!resources)
return make_dummy_monitor_config (screen);
outputs = g_array_new (FALSE, TRUE, sizeof (MetaOutput));
screen->n_outputs = 0;
screen->n_monitor_infos = resources->ncrtc;
screen->monitor_infos = g_new0 (MetaMonitorInfo, screen->n_monitor_infos);
for (i = 0; i < resources->ncrtc; i++)
{
XRRCrtcInfo *crtc;
MetaMonitorInfo *info;
crtc = XRRGetCrtcInfo (screen->display->xdisplay, resources, resources->crtcs[i]);
info = &screen->monitor_infos[i];
info->number = i;
info->rect.x = crtc->x;
info->rect.y = crtc->y;
info->rect.width = crtc->width;
info->rect.height = crtc->height;
info->in_fullscreen = -1;
for (j = 0; j < resources->nmode; j++)
{
if (resources->modes[j].id == crtc->mode)
info->refresh_rate = (resources->modes[j].dotClock /
((float)resources->modes[j].hTotal *
resources->modes[j].vTotal));
}
find_main_output_for_crtc (screen, resources, crtc, info, outputs);
XRRFreeCrtcInfo (crtc);
}
screen->n_outputs = outputs->len;
screen->outputs = (void*)g_array_free (outputs, FALSE);
XRRFreeScreenResources (resources);
}
#endif
typedef struct {
GArray *monitor_infos;
GArray *outputs;
} ReadMonitorCoglClosure;
static void
read_monitor_from_cogl_helper (CoglOutput *output,
void *user_data)
{
ReadMonitorCoglClosure *closure = user_data;
MetaMonitorInfo info;
MetaOutput meta_output;
info.number = closure->monitor_infos->len;
info.rect.x = cogl_output_get_x (output);
info.rect.y = cogl_output_get_y (output);
info.rect.width = cogl_output_get_width (output);
info.rect.height = cogl_output_get_height (output);
info.refresh_rate = cogl_output_get_refresh_rate (output);
info.is_primary = (info.number == 0);
info.in_fullscreen = -1;
info.output_id = 0; /* unknown */
g_array_append_val (closure->monitor_infos, info);
meta_output.monitor = &g_array_index (closure->monitor_infos,
MetaMonitorInfo,
closure->monitor_infos->len - 1);
meta_output.name = NULL;
meta_output.width_mm = cogl_output_get_mm_width (output);
meta_output.height_mm = cogl_output_get_mm_height (output);
meta_output.subpixel_order = cogl_output_get_subpixel_order (output);
g_array_append_val (closure->outputs, meta_output);
}
static void
read_monitor_infos_from_cogl (MetaScreen *screen)
{
ReadMonitorCoglClosure closure;
ClutterBackend *backend;
CoglContext *cogl_context;
CoglRenderer *cogl_renderer;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
closure.monitor_infos = g_array_new (FALSE, TRUE, sizeof (MetaMonitorInfo));
closure.outputs = g_array_new (FALSE, TRUE, sizeof (MetaOutput));
cogl_renderer_foreach_output (cogl_renderer,
read_monitor_from_cogl_helper, &closure);
screen->n_monitor_infos = closure.monitor_infos->len;
screen->monitor_infos = (void*)g_array_free (closure.monitor_infos, FALSE);
screen->n_outputs = closure.outputs->len;
screen->outputs = (void*)g_array_free (closure.outputs, FALSE);
screen->primary_monitor_index = 0;
}
static void
reload_monitor_infos (MetaScreen *screen)
{
GList *tmp;
MetaMonitorManager *manager;
tmp = screen->workspaces;
while (tmp != NULL)
@ -648,23 +431,15 @@ reload_monitor_infos (MetaScreen *screen)
/* Any previous screen->monitor_infos or screen->outputs is freed by the caller */
screen->outputs = NULL;
screen->n_outputs = 0;
screen->monitor_infos = NULL;
screen->n_monitor_infos = 0;
screen->last_monitor_index = 0;
screen->has_xinerama_indices = FALSE;
screen->display->monitor_cache_invalidated = TRUE;
if (has_dummy_output ())
return make_dummy_monitor_config (screen);
manager = meta_monitor_manager_get ();
#ifdef HAVE_RANDR
if (!meta_is_wayland_compositor ())
return read_monitor_infos_from_xrandr (screen);
#endif
return read_monitor_infos_from_cogl (screen);
screen->monitor_infos = meta_monitor_manager_get_monitor_infos (manager,
&screen->n_monitor_infos);
screen->primary_monitor_index = meta_monitor_manager_get_primary_index (manager);
}
/* The guard window allows us to leave minimized windows mapped so
@ -942,8 +717,19 @@ meta_screen_new (MetaDisplay *display,
screen->compositor_data = NULL;
screen->guard_window = None;
{
MetaMonitorManager *manager;
if (!meta_is_wayland_compositor ())
meta_monitor_manager_initialize (screen->display->xdisplay);
reload_monitor_infos (screen);
manager = meta_monitor_manager_get ();
g_signal_connect (manager, "monitors-changed",
G_CALLBACK (on_monitors_changed), screen);
}
meta_cursor_tracker_get_for_screen (screen);
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
@ -1029,12 +815,6 @@ meta_screen_new (MetaDisplay *display,
meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
screen->number, screen->screen_name, screen->xroot);
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
meta_wayland_compositor_init_screen (compositor,
screen);
#endif
return screen;
}
@ -3087,18 +2867,17 @@ meta_screen_resize (MetaScreen *screen,
int width,
int height)
{
GSList *windows, *tmp;
MetaOutput *old_outputs;
MetaMonitorInfo *old_monitor_infos;
int n_old_outputs, i;
screen->rect.width = width;
screen->rect.height = height;
/* Save the old monitor infos, so they stay valid during the update */
old_outputs = screen->outputs;
n_old_outputs = screen->n_outputs;
old_monitor_infos = screen->monitor_infos;
meta_monitor_manager_invalidate (meta_monitor_manager_get ());
}
static void
on_monitors_changed (MetaMonitorManager *manager,
MetaScreen *screen)
{
GSList *tmp, *windows;
reload_monitor_infos (screen);
set_desktop_geometry_hint (screen);
@ -3110,8 +2889,8 @@ meta_screen_resize (MetaScreen *screen,
changes.x = 0;
changes.y = 0;
changes.width = width;
changes.height = height;
changes.width = screen->rect.width;
changes.height = screen->rect.height;
XConfigureWindow(screen->display->xdisplay,
screen->guard_window,
@ -3121,7 +2900,8 @@ meta_screen_resize (MetaScreen *screen,
if (screen->display->compositor)
meta_compositor_sync_screen_size (screen->display->compositor,
screen, width, height);
screen,
screen->rect.width, screen->rect.height);
/* Queue a resize on all the windows */
meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
@ -3137,16 +2917,11 @@ meta_screen_resize (MetaScreen *screen,
meta_window_update_for_monitors_changed (window);
}
g_free (old_monitor_infos);
g_slist_free (windows);
meta_screen_queue_check_fullscreen (screen);
g_signal_emit (screen, screen_signals[MONITORS_CHANGED], 0);
for (i = 0; i < n_old_outputs; i++)
g_free (old_outputs[i].name);
g_free (old_outputs);
}
void

View File

@ -130,7 +130,6 @@ typedef struct
struct _MetaWaylandCompositor
{
MetaScreen *screen;
GList *outputs;
struct wl_display *wayland_display;
@ -340,9 +339,6 @@ void meta_wayland_finalize (void);
* API after meta_wayland_init() has been called. */
MetaWaylandCompositor *meta_wayland_compositor_get_default (void);
void meta_wayland_compositor_init_screen (MetaWaylandCompositor *compositor,
MetaScreen *screen);
void meta_wayland_compositor_repick (MetaWaylandCompositor *compositor);
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,

View File

@ -661,21 +661,25 @@ bind_output (struct wl_client *client,
(int)output->monitor->rect.height,
(int)output->monitor->refresh_rate);
if (version >= 2)
wl_resource_post_event (resource,
WL_OUTPUT_DONE);
}
static void
meta_wayland_compositor_create_outputs (MetaWaylandCompositor *compositor)
meta_wayland_compositor_create_outputs (MetaWaylandCompositor *compositor,
MetaMonitorManager *monitors)
{
MetaScreen *screen = compositor->screen;
int i;
MetaOutput *outputs;
int i, n_outputs;
for (i = 0; i < screen->n_outputs; i++)
outputs = meta_monitor_manager_get_outputs (monitors, &n_outputs);
for (i = 0; i < n_outputs; i++)
compositor->outputs = g_list_prepend (compositor->outputs,
wl_global_create (compositor->wayland_display,
&wl_output_interface, 2,
&screen->outputs[i], bind_output));
&outputs[i], bind_output));
}
const static struct wl_compositor_interface meta_wayland_compositor_interface = {
@ -1414,6 +1418,14 @@ on_evdev_device_open (const char *path,
path, flags, error);
}
static void
on_monitors_changed (MetaMonitorManager *monitors,
MetaWaylandCompositor *compositor)
{
g_list_free_full (compositor->outputs, (GDestroyNotify) wl_global_destroy);
meta_wayland_compositor_create_outputs (compositor, monitors);
}
void
meta_wayland_init (void)
{
@ -1423,6 +1435,7 @@ meta_wayland_init (void)
CoglContext *cogl_context;
CoglRenderer *cogl_renderer;
int weston_launch_fd;
MetaMonitorManager *monitors;
memset (compositor, 0, sizeof (MetaWaylandCompositor));
@ -1520,12 +1533,20 @@ meta_wayland_init (void)
}
compositor->stage = meta_wayland_stage_new ();
/* FIXME */
clutter_actor_set_size (CLUTTER_ACTOR (compositor->stage), 1024, 768);
clutter_stage_set_user_resizable (CLUTTER_STAGE (compositor->stage), FALSE);
g_signal_connect_after (compositor->stage, "paint",
G_CALLBACK (paint_finished_cb), compositor);
g_signal_connect (compositor->stage, "destroy",
G_CALLBACK (stage_destroy_cb), NULL);
meta_monitor_manager_initialize (NULL);
monitors = meta_monitor_manager_get ();
g_signal_connect (monitors, "monitors-changed",
G_CALLBACK (on_monitors_changed), compositor);
meta_wayland_compositor_create_outputs (compositor, monitors);
meta_wayland_data_device_manager_init (compositor->wayland_display);
compositor->seat = meta_wayland_seat_new (compositor->wayland_display,
@ -1594,23 +1615,3 @@ meta_wayland_compositor_is_native (MetaWaylandCompositor *compositor)
{
return compositor->drm_fd >= 0;
}
static void
on_monitors_changed (MetaScreen *screen,
MetaWaylandCompositor *compositor)
{
g_list_free_full (compositor->outputs, (GDestroyNotify) wl_global_destroy);
meta_wayland_compositor_create_outputs (compositor);
}
void
meta_wayland_compositor_init_screen (MetaWaylandCompositor *compositor,
MetaScreen *screen)
{
compositor->screen = screen;
g_signal_connect (compositor->screen, "monitors-changed",
G_CALLBACK (on_monitors_changed), compositor);
meta_wayland_compositor_create_outputs (compositor);
}