mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
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:
parent
cf296f26b1
commit
2777dfc533
@ -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 \
|
||||
|
98
src/core/monitor-private.h
Normal file
98
src/core/monitor-private.h
Normal 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
432
src/core/monitor.c
Normal 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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user