2014-04-22 18:03:40 -04:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 Red Hat
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* Written by:
|
|
|
|
* Jasper St. Pierre <jstpierre@mecheye.net>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "meta-wayland-outputs.h"
|
|
|
|
|
|
|
|
#include "meta-wayland-private.h"
|
2015-01-30 08:51:18 -05:00
|
|
|
#include "meta-monitor-manager-private.h"
|
2014-04-22 18:03:40 -04:00
|
|
|
|
2014-04-26 04:27:34 -04:00
|
|
|
#include <string.h>
|
|
|
|
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 02:49:52 -05:00
|
|
|
enum {
|
|
|
|
OUTPUT_DESTROYED,
|
|
|
|
|
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint signals[LAST_SIGNAL];
|
|
|
|
|
2015-04-17 05:17:46 -04:00
|
|
|
G_DEFINE_TYPE (MetaWaylandOutput, meta_wayland_output, G_TYPE_OBJECT)
|
|
|
|
|
2014-04-22 18:03:40 -04:00
|
|
|
static void
|
|
|
|
output_resource_destroy (struct wl_resource *res)
|
|
|
|
{
|
|
|
|
MetaWaylandOutput *wayland_output;
|
|
|
|
|
|
|
|
wayland_output = wl_resource_get_user_data (res);
|
2015-07-01 01:18:45 -04:00
|
|
|
if (!wayland_output)
|
|
|
|
return;
|
|
|
|
|
2014-04-22 18:03:40 -04:00
|
|
|
wayland_output->resources = g_list_remove (wayland_output->resources, res);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bind_output (struct wl_client *client,
|
|
|
|
void *data,
|
|
|
|
guint32 version,
|
|
|
|
guint32 id)
|
|
|
|
{
|
|
|
|
MetaWaylandOutput *wayland_output = data;
|
2015-03-30 21:12:04 -04:00
|
|
|
MetaMonitorInfo *monitor_info = wayland_output->monitor_info;
|
2014-04-22 18:03:40 -04:00
|
|
|
struct wl_resource *resource;
|
|
|
|
guint mode_flags;
|
2015-03-30 21:12:04 -04:00
|
|
|
MetaOutput *output = monitor_info->outputs[0];
|
2014-04-22 18:03:40 -04:00
|
|
|
|
2014-08-04 10:24:59 -04:00
|
|
|
resource = wl_resource_create (client, &wl_output_interface, version, id);
|
2014-04-22 18:03:40 -04:00
|
|
|
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);
|
|
|
|
|
2015-03-30 21:12:04 -04:00
|
|
|
meta_verbose ("Binding monitor %p/%s (%u, %u, %u, %u) x %f\n",
|
|
|
|
monitor_info, output->name,
|
|
|
|
monitor_info->rect.x, monitor_info->rect.y,
|
|
|
|
monitor_info->rect.width, monitor_info->rect.height,
|
|
|
|
monitor_info->refresh_rate);
|
2014-04-22 18:03:40 -04:00
|
|
|
|
2014-08-05 16:11:48 -04:00
|
|
|
wl_output_send_geometry (resource,
|
2015-03-30 21:12:04 -04:00
|
|
|
(int)monitor_info->rect.x,
|
|
|
|
(int)monitor_info->rect.y,
|
|
|
|
monitor_info->width_mm,
|
|
|
|
monitor_info->height_mm,
|
2014-08-05 16:11:48 -04:00
|
|
|
/* Cogl values reflect XRandR values,
|
|
|
|
and so does wayland */
|
|
|
|
output->subpixel_order,
|
|
|
|
output->vendor,
|
|
|
|
output->product,
|
|
|
|
output->crtc->transform);
|
2014-04-22 18:03:40 -04:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2014-08-05 16:11:48 -04:00
|
|
|
wl_output_send_mode (resource,
|
|
|
|
mode_flags,
|
2015-03-30 21:12:04 -04:00
|
|
|
(int)monitor_info->rect.width,
|
|
|
|
(int)monitor_info->rect.height,
|
KMS/Wayland: Correct refresh rate units
On the wire, Wayland specifies the refresh rate in milliHz. Mutter sends
the refresh rate in Hz, which confuses clients, e.g. weston-info:
interface: 'wl_output', version: 2, name: 4
mode:
width: 2560 px, height: 1440 px, refresh: 0 Hz,
flags: current preferred
interface: 'wl_output', version: 2, name: 5
mode:
width: 3200 px, height: 1800 px, refresh: 0 Hz,
flags: current preferred
and xrandr:
XWAYLAND0 connected 2560x1440+3200+0 600mm x 340mm
2560x1440@0.1Hz 0.05*+
XWAYLAND1 connected 3200x1800+0+0 290mm x 170mm
3200x1800@0.1Hz 0.03*+
Export the refresh rate in the correct units. For improved precision,
perform the KMS intermediate calculations in milliHz as well, and
account for interlaced/doublescan modes.
This is also consistent with what GTK+ expects:
timings->refresh_interval = 16667; /* default to 1/60th of a second */
/* We pick a random output out of the outputs that the window touches
* The rate here is in milli-hertz */
int refresh_rate = _gdk_wayland_screen_get_output_refresh_rate (wayland_display->screen,
impl->outputs->data);
if (refresh_rate != 0)
timings->refresh_interval = G_GINT64_CONSTANT(1000000000) / refresh_rate;
Where the 'refresh_rate' given is exactly what's come off the wire.
1000000000/60000 comes out as 16667, whereas divided by 60 is ...
substantially less.
https://bugzilla.gnome.org/show_bug.cgi?id=758653
2015-11-25 07:56:18 -05:00
|
|
|
(int)(monitor_info->refresh_rate * 1000));
|
2014-04-22 18:03:40 -04:00
|
|
|
|
2014-05-12 17:00:49 -04:00
|
|
|
if (version >= WL_OUTPUT_SCALE_SINCE_VERSION)
|
2014-08-05 16:11:48 -04:00
|
|
|
wl_output_send_scale (resource, output->scale);
|
2014-04-26 04:27:34 -04:00
|
|
|
|
2014-05-12 17:00:49 -04:00
|
|
|
if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
|
2014-08-05 16:11:48 -04:00
|
|
|
wl_output_send_done (resource);
|
2014-04-22 18:03:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wayland_output_destroy_notify (gpointer data)
|
|
|
|
{
|
|
|
|
MetaWaylandOutput *wayland_output = data;
|
|
|
|
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 02:49:52 -05:00
|
|
|
g_signal_emit (wayland_output, signals[OUTPUT_DESTROYED], 0);
|
2015-04-17 05:17:46 -04:00
|
|
|
g_object_unref (wayland_output);
|
2014-04-22 18:03:40 -04:00
|
|
|
}
|
|
|
|
|
2014-07-10 17:39:47 -04:00
|
|
|
static inline enum wl_output_transform
|
|
|
|
wl_output_transform_from_meta_monitor_transform (MetaMonitorTransform transform)
|
|
|
|
{
|
|
|
|
/* The enums are the same. */
|
|
|
|
return (enum wl_output_transform) transform;
|
|
|
|
}
|
|
|
|
|
2014-04-22 18:03:40 -04:00
|
|
|
static void
|
|
|
|
wayland_output_update_for_output (MetaWaylandOutput *wayland_output,
|
2015-03-30 21:12:04 -04:00
|
|
|
MetaMonitorInfo *monitor_info)
|
2014-04-22 18:03:40 -04:00
|
|
|
{
|
|
|
|
GList *iter;
|
|
|
|
guint mode_flags;
|
2015-03-30 21:12:04 -04:00
|
|
|
MetaOutput *output = monitor_info->outputs[0];
|
2014-07-10 17:39:47 -04:00
|
|
|
enum wl_output_transform wl_transform = wl_output_transform_from_meta_monitor_transform (output->crtc->transform);
|
2014-04-22 18:03:40 -04:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2015-03-30 21:12:04 -04:00
|
|
|
if (wayland_output->x != monitor_info->rect.x ||
|
|
|
|
wayland_output->y != monitor_info->rect.y ||
|
2014-07-10 17:39:47 -04:00
|
|
|
wayland_output->transform != wl_transform)
|
2014-04-22 18:03:40 -04:00
|
|
|
{
|
2015-02-22 13:37:55 -05:00
|
|
|
wl_output_send_geometry (resource,
|
2015-03-30 21:12:04 -04:00
|
|
|
(int)monitor_info->rect.x,
|
|
|
|
(int)monitor_info->rect.y,
|
|
|
|
monitor_info->width_mm,
|
|
|
|
monitor_info->height_mm,
|
2015-02-22 13:37:55 -05:00
|
|
|
output->subpixel_order,
|
|
|
|
output->vendor,
|
|
|
|
output->product,
|
|
|
|
wl_transform);
|
2014-04-22 18:03:40 -04:00
|
|
|
}
|
|
|
|
|
2015-02-22 13:37:55 -05:00
|
|
|
wl_output_send_mode (resource,
|
|
|
|
mode_flags,
|
2015-03-30 21:12:04 -04:00
|
|
|
(int)monitor_info->rect.width,
|
|
|
|
(int)monitor_info->rect.height,
|
KMS/Wayland: Correct refresh rate units
On the wire, Wayland specifies the refresh rate in milliHz. Mutter sends
the refresh rate in Hz, which confuses clients, e.g. weston-info:
interface: 'wl_output', version: 2, name: 4
mode:
width: 2560 px, height: 1440 px, refresh: 0 Hz,
flags: current preferred
interface: 'wl_output', version: 2, name: 5
mode:
width: 3200 px, height: 1800 px, refresh: 0 Hz,
flags: current preferred
and xrandr:
XWAYLAND0 connected 2560x1440+3200+0 600mm x 340mm
2560x1440@0.1Hz 0.05*+
XWAYLAND1 connected 3200x1800+0+0 290mm x 170mm
3200x1800@0.1Hz 0.03*+
Export the refresh rate in the correct units. For improved precision,
perform the KMS intermediate calculations in milliHz as well, and
account for interlaced/doublescan modes.
This is also consistent with what GTK+ expects:
timings->refresh_interval = 16667; /* default to 1/60th of a second */
/* We pick a random output out of the outputs that the window touches
* The rate here is in milli-hertz */
int refresh_rate = _gdk_wayland_screen_get_output_refresh_rate (wayland_display->screen,
impl->outputs->data);
if (refresh_rate != 0)
timings->refresh_interval = G_GINT64_CONSTANT(1000000000) / refresh_rate;
Where the 'refresh_rate' given is exactly what's come off the wire.
1000000000/60000 comes out as 16667, whereas divided by 60 is ...
substantially less.
https://bugzilla.gnome.org/show_bug.cgi?id=758653
2015-11-25 07:56:18 -05:00
|
|
|
(int)(monitor_info->refresh_rate * 1000));
|
2014-04-22 18:03:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* It's very important that we change the output pointer here, as
|
|
|
|
the old structure is about to be freed by MetaMonitorManager */
|
2015-03-30 21:12:04 -04:00
|
|
|
wayland_output->monitor_info = monitor_info;
|
|
|
|
wayland_output->x = monitor_info->rect.x;
|
|
|
|
wayland_output->y = monitor_info->rect.y;
|
2014-07-10 17:39:47 -04:00
|
|
|
wayland_output->transform = wl_transform;
|
2014-04-22 18:03:40 -04:00
|
|
|
}
|
|
|
|
|
2015-04-17 05:17:46 -04:00
|
|
|
static MetaWaylandOutput *
|
|
|
|
meta_wayland_output_new (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
MetaWaylandOutput *wayland_output;
|
|
|
|
|
|
|
|
wayland_output = g_object_new (META_TYPE_WAYLAND_OUTPUT, NULL);
|
|
|
|
wayland_output->global = wl_global_create (compositor->wayland_display,
|
|
|
|
&wl_output_interface,
|
|
|
|
META_WL_OUTPUT_VERSION,
|
|
|
|
wayland_output, bind_output);
|
|
|
|
|
|
|
|
return wayland_output;
|
|
|
|
}
|
|
|
|
|
2014-04-22 18:03:40 -04:00
|
|
|
static GHashTable *
|
|
|
|
meta_wayland_compositor_update_outputs (MetaWaylandCompositor *compositor,
|
|
|
|
MetaMonitorManager *monitors)
|
|
|
|
{
|
2015-03-30 21:12:04 -04:00
|
|
|
unsigned int i;
|
2014-04-22 18:03:40 -04:00
|
|
|
GHashTable *new_table;
|
2015-03-30 21:12:04 -04:00
|
|
|
MetaMonitorInfo *monitor_infos;
|
|
|
|
unsigned int n_monitor_infos;
|
2014-04-22 18:03:40 -04:00
|
|
|
|
2015-03-30 21:12:04 -04:00
|
|
|
monitor_infos = meta_monitor_manager_get_monitor_infos (monitors, &n_monitor_infos);
|
2014-04-22 18:03:40 -04:00
|
|
|
new_table = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify);
|
|
|
|
|
2015-03-30 21:12:04 -04:00
|
|
|
for (i = 0; i < n_monitor_infos; i++)
|
2014-04-22 18:03:40 -04:00
|
|
|
{
|
2015-03-30 21:12:04 -04:00
|
|
|
MetaMonitorInfo *info = &monitor_infos[i];
|
2014-04-22 18:03:40 -04:00
|
|
|
MetaWaylandOutput *wayland_output;
|
|
|
|
|
2015-03-30 21:12:04 -04:00
|
|
|
if (info->winsys_id == 0)
|
|
|
|
continue;
|
|
|
|
wayland_output = g_hash_table_lookup (compositor->outputs, GSIZE_TO_POINTER (info->winsys_id));
|
2014-04-22 18:03:40 -04:00
|
|
|
|
|
|
|
if (wayland_output)
|
|
|
|
{
|
2015-03-30 21:12:04 -04:00
|
|
|
g_hash_table_steal (compositor->outputs, GSIZE_TO_POINTER (info->winsys_id));
|
2014-04-22 18:03:40 -04:00
|
|
|
}
|
|
|
|
else
|
2015-04-17 05:17:46 -04:00
|
|
|
wayland_output = meta_wayland_output_new (compositor);
|
2014-04-22 18:03:40 -04:00
|
|
|
|
2015-03-30 21:12:04 -04:00
|
|
|
wayland_output_update_for_output (wayland_output, info);
|
|
|
|
g_hash_table_insert (new_table, GSIZE_TO_POINTER (info->winsys_id), wayland_output);
|
2014-04-22 18:03:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
g_hash_table_destroy (compositor->outputs);
|
|
|
|
return new_table;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_monitors_changed (MetaMonitorManager *monitors,
|
|
|
|
MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
|
|
|
|
}
|
|
|
|
|
2015-04-17 05:17:46 -04:00
|
|
|
static void
|
|
|
|
meta_wayland_output_init (MetaWaylandOutput *wayland_output)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_output_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MetaWaylandOutput *wayland_output = META_WAYLAND_OUTPUT (object);
|
2015-07-01 01:18:45 -04:00
|
|
|
GList *l;
|
2015-04-17 05:17:46 -04:00
|
|
|
|
|
|
|
wl_global_destroy (wayland_output->global);
|
2015-07-01 01:18:45 -04:00
|
|
|
|
|
|
|
/* Make sure the wl_output destructor doesn't try to access MetaWaylandOutput
|
|
|
|
* after we have freed it.
|
|
|
|
*/
|
|
|
|
for (l = wayland_output->resources; l; l = l->next)
|
|
|
|
{
|
|
|
|
struct wl_resource *output_resource = l->data;
|
|
|
|
|
|
|
|
wl_resource_set_user_data (output_resource, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free (wayland_output->resources);
|
2015-04-17 05:17:46 -04:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_wayland_output_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_output_class_init (MetaWaylandOutputClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
object_class->finalize = meta_wayland_output_finalize;
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 02:49:52 -05:00
|
|
|
|
|
|
|
signals[OUTPUT_DESTROYED] = g_signal_new ("output-destroyed",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
G_TYPE_NONE, 0);
|
2015-04-17 05:17:46 -04:00
|
|
|
}
|
|
|
|
|
2014-04-22 18:03:40 -04:00
|
|
|
void
|
|
|
|
meta_wayland_outputs_init (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *monitors;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|