[gnome-desktop] gnome-rr: add tiled monitor support
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-desktop] gnome-rr: add tiled monitor support
- Date: Wed, 1 Jul 2015 08:45:54 +0000 (UTC)
commit 40a5b4c9522c19cc5bbb2f5262c5e8347b581f87
Author: Dave Airlie <airlied redhat com>
Date: Tue Oct 14 13:03:29 2014 +1000
gnome-rr: add tiled monitor support
This adds the interfaces to allow for tiled
monitor support via gnome-desktop.
1) add output config get/set tiled geometry/rotation support
These hide under the standard APIs, and just set the
state for the tiled outputs by setting the primary
tile up.
2) add output config API to get primary tile
3) add tile flags to modes - add gather function
to create tiled modes for primary outputs.
https://bugzilla.gnome.org/show_bug.cgi?id=750311
libgnome-desktop/gnome-rr-config.c | 9 +
libgnome-desktop/gnome-rr-config.h | 2 +
libgnome-desktop/gnome-rr-debug.c | 10 +-
libgnome-desktop/gnome-rr-output-info.c | 275 ++++++++++++++++++++++++++++++-
libgnome-desktop/gnome-rr-private.h | 29 ++++
libgnome-desktop/gnome-rr.c | 155 +++++++++++++++++-
libgnome-desktop/gnome-rr.h | 1 +
7 files changed, 476 insertions(+), 5 deletions(-)
---
diff --git a/libgnome-desktop/gnome-rr-config.c b/libgnome-desktop/gnome-rr-config.c
index f21eb36..f300ee7 100644
--- a/libgnome-desktop/gnome-rr-config.c
+++ b/libgnome-desktop/gnome-rr-config.c
@@ -164,6 +164,15 @@ gnome_rr_config_load_current (GnomeRRConfig *config, GError **error)
output->priv->name = g_strdup (gnome_rr_output_get_name (rr_output));
output->priv->connected = TRUE;
output->priv->display_name = g_strdup (gnome_rr_output_get_display_name (rr_output));
+ output->priv->config = config;
+ output->priv->is_tiled = _gnome_rr_output_get_tile_info (rr_output,
+ &output->priv->tile);
+ if (output->priv->is_tiled)
+ {
+ _gnome_rr_output_get_tiled_display_size (rr_output, NULL, NULL,
+ &output->priv->total_tiled_width,
+ &output->priv->total_tiled_height);
+ }
if (!output->priv->connected)
{
diff --git a/libgnome-desktop/gnome-rr-config.h b/libgnome-desktop/gnome-rr-config.h
index bfd3e14..333d705 100644
--- a/libgnome-desktop/gnome-rr-config.h
+++ b/libgnome-desktop/gnome-rr-config.h
@@ -91,6 +91,8 @@ int gnome_rr_output_info_get_preferred_height (GnomeRROutputInfo *self);
gboolean gnome_rr_output_info_get_underscanning (GnomeRROutputInfo *self);
void gnome_rr_output_info_set_underscanning (GnomeRROutputInfo *self, gboolean underscanning);
+gboolean gnome_rr_output_info_is_primary_tile (GnomeRROutputInfo *self);
+
typedef struct _GnomeRRConfig GnomeRRConfig;
typedef struct _GnomeRRConfigClass GnomeRRConfigClass;
typedef struct _GnomeRRConfigPrivate GnomeRRConfigPrivate;
diff --git a/libgnome-desktop/gnome-rr-debug.c b/libgnome-desktop/gnome-rr-debug.c
index 5530f46..682e721 100644
--- a/libgnome-desktop/gnome-rr-debug.c
+++ b/libgnome-desktop/gnome-rr-debug.c
@@ -31,7 +31,8 @@ print_output (GnomeRROutput *output, const char *message)
gsize len = 0;
const guint8 *result = NULL;
int width_mm, height_mm;
-
+ GnomeRRMode **modes;
+ int i;
g_print ("[%s]", gnome_rr_output_get_name (output));
if (message)
g_print (" (%s)", message);
@@ -63,6 +64,13 @@ print_output (GnomeRROutput *output, const char *message)
g_free (serial);
}
+ modes = gnome_rr_output_list_modes (output);
+ for (i = 0; modes[i] != NULL; ++i) {
+ g_print ("\t mode: %dx%d%s\n",
+ gnome_rr_mode_get_width (modes[i]),
+ gnome_rr_mode_get_height (modes[i]),
+ gnome_rr_mode_get_is_tiled (modes[i]) ? " (tiled)" : "");
+ }
g_print ("\n");
}
diff --git a/libgnome-desktop/gnome-rr-output-info.c b/libgnome-desktop/gnome-rr-output-info.c
index ff8ce78..d50dfa8 100644
--- a/libgnome-desktop/gnome-rr-output-info.c
+++ b/libgnome-desktop/gnome-rr-output-info.c
@@ -98,6 +98,72 @@ void gnome_rr_output_info_set_active (GnomeRROutputInfo *self, gboolean active)
self->priv->on = active;
}
+static void gnome_rr_output_info_get_tiled_geometry (GnomeRROutputInfo *self,
+ int *x,
+ int *y,
+ int *width,
+ int *height)
+{
+ GnomeRROutputInfo **outputs;
+ gboolean active;
+ int i;
+ int ht, vt;
+ int total_w = 0, total_h = 0;
+
+ outputs = gnome_rr_config_get_outputs (self->priv->config);
+
+ /*
+ * iterate over all the outputs from 0,0 -> h,v
+ * find the output for each tile,
+ * if it is the 0 tile, store the x/y offsets.
+ * if the tile is active, add the tile to the total w/h
+ * for the output if the tile is in the 0 row or 0 column.
+ */
+ for (ht = 0; ht < self->priv->tile.max_horiz_tiles; ht++)
+ {
+ for (vt = 0; vt < self->priv->tile.max_vert_tiles; vt++)
+ {
+ for (i = 0; outputs[i]; i++)
+ {
+ GnomeRRTile *this_tile = &outputs[i]->priv->tile;
+
+ if (!outputs[i]->priv->is_tiled)
+ continue;
+
+ if (this_tile->group_id != self->priv->tile.group_id)
+ continue;
+
+ if (this_tile->loc_horiz != ht ||
+ this_tile->loc_vert != vt)
+ continue;
+
+ if (vt == 0 && ht == 0)
+ {
+ if (x)
+ *x = outputs[i]->priv->x;
+ if (y)
+ *y = outputs[i]->priv->y;
+ }
+
+ active = gnome_rr_output_info_is_active (outputs[i]);
+ if (!active)
+ continue;
+
+ if (this_tile->loc_horiz == 0)
+ total_h += outputs[i]->priv->height;
+
+ if (this_tile->loc_vert == 0)
+ total_w += outputs[i]->priv->width;
+ }
+ }
+ }
+
+ if (width)
+ *width = total_w;
+ if (height)
+ *height = total_h;
+}
+
/**
* gnome_rr_output_info_get_geometry:
* @self: a #GnomeRROutputInfo
@@ -105,11 +171,20 @@ void gnome_rr_output_info_set_active (GnomeRROutputInfo *self, gboolean active)
* @y: (out) (allow-none):
* @width: (out) (allow-none):
* @height: (out) (allow-none):
+ *
+ * Get the geometry for the monitor connected to the specified output.
+ * If the monitor is a tiled monitor, it returns the geometry for the complete monitor.
*/
void gnome_rr_output_info_get_geometry (GnomeRROutputInfo *self, int *x, int *y, int *width, int *height)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
+ if (self->priv->is_tiled)
+ {
+ gnome_rr_output_info_get_tiled_geometry (self, x, y, width, height);
+ return;
+ }
+
if (x)
*x = self->priv->x;
if (y)
@@ -120,10 +195,106 @@ void gnome_rr_output_info_get_geometry (GnomeRROutputInfo *self, int *x, int *y,
*height = self->priv->height;
}
-void gnome_rr_output_info_set_geometry (GnomeRROutputInfo *self, int x, int y, int width, int height)
+static void gnome_rr_output_info_set_tiled_geometry (GnomeRROutputInfo *self, int x, int y, int width, int
height)
+{
+ GnomeRROutputInfo **outputs;
+ gboolean primary_tile_only = FALSE;
+ int ht, vt, i;
+ int x_off;
+
+ primary_tile_only = TRUE;
+
+ if (width == self->priv->total_tiled_width &&
+ height == self->priv->total_tiled_height)
+ primary_tile_only = FALSE;
+
+ outputs = gnome_rr_config_get_outputs (self->priv->config);
+ /*
+ * iterate over all the outputs from 0,0 -> h,v
+ * find the output for each tile,
+ * if only the primary tile is being set, disable
+ * the non-primary tiles, and set the output up
+ * for tile 0 only.
+ * if all tiles are being set, then store the
+ * dimensions for this tile, and increase the offsets.
+ * y_off is reset per column of tiles,
+ * addx is incremented for the first row of tiles
+ * to set the correct x offset.
+ */
+ x_off = 0;
+ for (ht = 0; ht < self->priv->tile.max_horiz_tiles; ht++)
+ {
+ int y_off = 0;
+ int addx = 0;
+ for (vt = 0; vt < self->priv->tile.max_vert_tiles; vt++)
+ {
+ for (i = 0; outputs[i]; i++)
+ {
+ GnomeRRTile *this_tile = &outputs[i]->priv->tile;
+
+ if (!outputs[i]->priv->is_tiled)
+ continue;
+
+ if (this_tile->group_id != self->priv->tile.group_id)
+ continue;
+
+ if (this_tile->loc_horiz != ht ||
+ this_tile->loc_vert != vt)
+ continue;
+
+ /* for primary tile only configs turn off non-primary
+ tiles - turn them on for tiled ones */
+ if (ht != 0 || vt != 0)
+ outputs[i]->priv->on = !primary_tile_only;
+
+ if (primary_tile_only)
+ {
+ if (ht == 0 && vt == 0)
+ {
+ outputs[i]->priv->x = x;
+ outputs[i]->priv->y = y;
+ outputs[i]->priv->width = width;
+ outputs[i]->priv->height = height;
+ }
+ }
+ else
+ {
+ outputs[i]->priv->x = x + x_off;
+ outputs[i]->priv->y = y + y_off;
+ outputs[i]->priv->width = this_tile->width;
+ outputs[i]->priv->height = this_tile->height;
+
+ y_off += this_tile->height;
+ if (vt == 0)
+ addx = this_tile->width;
+ }
+ }
+ }
+ x_off += addx;
+ }
+}
+
+/**
+ * gnome_rr_output_info_set_geometry:
+ * @self: a #GnomeRROutputInfo
+ * @x: x offset for monitor
+ * @y: y offset for monitor
+ * @width: monitor width
+ * @height: monitor height
+ *
+ * Set the geometry for the monitor connected to the specified output.
+ * If the monitor is a tiled monitor, it sets the geometry for the complete monitor.
+ */
+
+void gnome_rr_output_info_set_geometry (GnomeRROutputInfo *self, int x, int y, int width, int height)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
+ if (self->priv->is_tiled)
+ {
+ gnome_rr_output_info_set_tiled_geometry (self, x, y, width, height);
+ return;
+ }
self->priv->x = x;
self->priv->y = y;
self->priv->width = width;
@@ -151,10 +322,90 @@ GnomeRRRotation gnome_rr_output_info_get_rotation (GnomeRROutputInfo *self)
return self->priv->rotation;
}
+static void gnome_rr_output_info_set_tiled_rotation (GnomeRROutputInfo *self, GnomeRRRotation rotation)
+{
+ GnomeRROutputInfo **outputs;
+ int x_off;
+ int base_x = 0, base_y = 0;
+ int ht, vt;
+ int i;
+
+ outputs = gnome_rr_config_get_outputs (self->priv->config);
+ x_off = 0;
+ /*
+ * iterate over all the outputs from 0,0 -> h,v
+ * find the output for each tile,
+ * for all tiles set the rotation,
+ * for the 0 tile use the base X/Y offsets
+ * for non-0 tile, rotate the offsets of each
+ * tile so things display correctly.
+ */
+ for (ht = 0; ht < self->priv->tile.max_horiz_tiles; ht++)
+ {
+ int y_off = 0;
+ int addx = 0;
+ for (vt = 0; vt < self->priv->tile.max_vert_tiles; vt++)
+ {
+ for (i = 0; outputs[i] != NULL; i++)
+ {
+ GnomeRRTile *this_tile = &outputs[i]->priv->tile;
+ int new_x, new_y;
+
+ if (!outputs[i]->priv->is_tiled)
+ continue;
+
+ if (this_tile->group_id != self->priv->tile.group_id)
+ continue;
+
+ if (this_tile->loc_horiz != ht ||
+ this_tile->loc_vert != vt)
+ continue;
+
+ /* set tile rotation */
+ outputs[i]->priv->rotation = rotation;
+
+ /* for non-zero tiles - change the offsets */
+ if (ht == 0 && vt == 0)
+ {
+ base_x = outputs[i]->priv->x;
+ base_y = outputs[i]->priv->y;
+ }
+ else
+ {
+ if ((rotation & GNOME_RR_ROTATION_90) || (rotation & GNOME_RR_ROTATION_270))
+ {
+ new_x = base_x + y_off;
+ new_y = base_y + x_off;
+ }
+ else
+ {
+ new_x = base_x + x_off;
+ new_y = base_y + y_off;
+ }
+ outputs[i]->priv->x = new_x;
+ outputs[i]->priv->y = new_y;
+ outputs[i]->priv->width = this_tile->width;
+ outputs[i]->priv->height = this_tile->height;
+ }
+
+ y_off += this_tile->height;
+ if (vt == 0)
+ addx = this_tile->width;
+ }
+ }
+ x_off += addx;
+ }
+}
+
void gnome_rr_output_info_set_rotation (GnomeRROutputInfo *self, GnomeRRRotation rotation)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
+ if (self->priv->is_tiled)
+ {
+ gnome_rr_output_info_set_tiled_rotation (self, rotation);
+ return;
+ }
self->priv->rotation = rotation;
}
@@ -266,3 +517,25 @@ void gnome_rr_output_info_set_underscanning (GnomeRROutputInfo *self,
self->priv->underscanning = underscanning;
}
+
+/**
+ * gnome_rr_output_info_is_primary_tile
+ * @self: a #GnomeRROutputInfo
+ *
+ * Returns: %TRUE if the specified output is connected to
+ * the primary tile of a monitor or to an untiled monitor,
+ * %FALSE if the output is connected to a secondary tile.
+ */
+gboolean gnome_rr_output_info_is_primary_tile(GnomeRROutputInfo *self)
+{
+ g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), FALSE);
+
+ if (!self->priv->is_tiled)
+ return TRUE;
+
+ if (self->priv->tile.loc_horiz == 0 &&
+ self->priv->tile.loc_vert == 0)
+ return TRUE;
+
+ return FALSE;
+}
diff --git a/libgnome-desktop/gnome-rr-private.h b/libgnome-desktop/gnome-rr-private.h
index acf6497..e721e39 100644
--- a/libgnome-desktop/gnome-rr-private.h
+++ b/libgnome-desktop/gnome-rr-private.h
@@ -51,6 +51,20 @@ struct GnomeRRScreenPrivate
MetaDBusDisplayConfig *proxy;
};
+#define UNDEFINED_GROUP_ID 0
+struct GnomeRRTile {
+ guint group_id;
+ guint flags;
+ guint max_horiz_tiles;
+ guint max_vert_tiles;
+ guint loc_horiz;
+ guint loc_vert;
+ guint width;
+ guint height;
+};
+
+typedef struct GnomeRRTile GnomeRRTile;
+
struct _GnomeRROutputInfoPrivate
{
char * name;
@@ -74,6 +88,14 @@ struct _GnomeRROutputInfoPrivate
char * display_name;
gboolean primary;
gboolean underscanning;
+
+ gboolean is_tiled;
+ GnomeRRTile tile;
+
+ int total_tiled_width;
+ int total_tiled_height;
+ /* ptr back to info */
+ GnomeRRConfig *config;
};
struct _GnomeRRConfigPrivate
@@ -91,4 +113,11 @@ gboolean _gnome_rr_screen_apply_configuration (GnomeRRScreen *screen,
GVariant *outputs,
GError **error);
+
+gboolean _gnome_rr_output_get_tile_info (GnomeRROutput *output,
+ GnomeRRTile *tile);
+gboolean _gnome_rr_output_get_tiled_display_size (GnomeRROutput *output,
+ int *tile_w, int *tile_h,
+ int *width, int *height);
+
#endif
diff --git a/libgnome-desktop/gnome-rr.c b/libgnome-desktop/gnome-rr.c
index 099cd68..2c56d5c 100644
--- a/libgnome-desktop/gnome-rr.c
+++ b/libgnome-desktop/gnome-rr.c
@@ -81,6 +81,7 @@ struct GnomeRROutput
gboolean is_primary;
gboolean is_presentation;
gboolean is_underscanning;
+ GnomeRRTile tile_info;
};
struct GnomeRRCrtc
@@ -100,6 +101,7 @@ struct GnomeRRCrtc
int gamma_size;
};
+#define UNDEFINED_MODE_ID 0
struct GnomeRRMode
{
ScreenInfo * info;
@@ -108,6 +110,7 @@ struct GnomeRRMode
int width;
int height;
int freq; /* in mHz */
+ gboolean tiled;
};
/* GnomeRRCrtc */
@@ -280,6 +283,98 @@ has_similar_mode (GnomeRROutput *output, GnomeRRMode *mode)
return FALSE;
}
+gboolean
+_gnome_rr_output_get_tiled_display_size (GnomeRROutput *output,
+ int *tile_w, int *tile_h,
+ int *total_width, int *total_height)
+{
+ GnomeRRTile tile;
+ int ht, vt, i;
+ int total_h = 0, total_w = 0;
+
+ if (!_gnome_rr_output_get_tile_info (output, &tile))
+ return FALSE;
+
+ if (tile.loc_horiz != 0 ||
+ tile.loc_vert != 0)
+ return FALSE;
+
+ if (tile_w)
+ *tile_w = tile.width;
+ if (tile_h)
+ *tile_h = tile.height;
+
+ for (ht = 0; ht < tile.max_horiz_tiles; ht++)
+ {
+ for (vt = 0; vt < tile.max_vert_tiles; vt++)
+ {
+ for (i = 0; output->info->outputs[i]; i++)
+ {
+ GnomeRRTile this_tile;
+
+ if (!_gnome_rr_output_get_tile_info (output->info->outputs[i], &this_tile))
+ continue;
+
+ if (this_tile.group_id != tile.group_id)
+ continue;
+
+ if (this_tile.loc_horiz != ht ||
+ this_tile.loc_vert != vt)
+ continue;
+
+ if (this_tile.loc_horiz == 0)
+ total_h += this_tile.height;
+
+ if (this_tile.loc_vert == 0)
+ total_w += this_tile.width;
+ }
+ }
+ }
+
+ *total_width = total_w;
+ *total_height = total_h;
+ return TRUE;
+}
+
+static void
+gather_tile_modes_output (ScreenInfo *info, GnomeRROutput *output)
+{
+ GPtrArray *a;
+ GnomeRRMode *mode;
+ int width, height;
+ int tile_w, tile_h;
+ int i;
+
+ if (!_gnome_rr_output_get_tiled_display_size (output, &tile_w, &tile_h,
+ &width, &height))
+ return;
+
+ /* now stick the mode into the modelist */
+ a = g_ptr_array_new ();
+ mode = mode_new (info, UNDEFINED_MODE_ID);
+ mode->winsys_id = 0;
+ mode->width = width;
+ mode->height = height;
+ mode->freq = 0;
+ mode->tiled = TRUE;
+
+ g_ptr_array_add (a, mode);
+ for (i = 0; output->modes[i]; i++)
+ g_ptr_array_add (a, output->modes[i]);
+
+ g_ptr_array_add (a, NULL);
+ output->modes = (GnomeRRMode **)g_ptr_array_free (a, FALSE);
+}
+
+static void
+gather_tile_modes (ScreenInfo *info)
+{
+ int i;
+
+ for (i = 0; info->outputs[i]; i++)
+ gather_tile_modes_output (info, info->outputs[i]);
+}
+
static void
gather_clone_modes (ScreenInfo *info)
{
@@ -410,6 +505,8 @@ fill_screen_info_from_resources (ScreenInfo *info,
}
gather_clone_modes (info);
+
+ gather_tile_modes (info);
}
static gboolean
@@ -1197,7 +1294,7 @@ output_initialize (GnomeRROutput *output, GVariant *info)
{
GPtrArray *a;
GVariantIter *crtcs, *clones, *modes;
- GVariant *properties, *edid;
+ GVariant *properties, *edid, *tile;
int current_crtc_id;
guint id;
@@ -1276,6 +1373,18 @@ output_initialize (GnomeRROutput *output, GVariant *info)
else
g_variant_lookup (properties, "edid-file", "s", &output->edid_file);
+ if ((tile = g_variant_lookup_value (properties, "tile", G_VARIANT_TYPE ("(uuuuuuuu)"))))
+ {
+ g_variant_get (tile, "(uuuuuuuu)",
+ &output->tile_info.group_id, &output->tile_info.flags,
+ &output->tile_info.max_horiz_tiles, &output->tile_info.max_vert_tiles,
+ &output->tile_info.loc_horiz, &output->tile_info.loc_vert,
+ &output->tile_info.width, &output->tile_info.height);
+ g_variant_unref (tile);
+ }
+ else
+ memset(&output->tile_info, 0, sizeof(output->tile_info));
+
if (output->is_primary)
output->info->primary = output;
}
@@ -1556,12 +1665,24 @@ GnomeRRMode *
gnome_rr_output_get_current_mode (GnomeRROutput *output)
{
GnomeRRCrtc *crtc;
-
+ GnomeRRMode *mode;
g_return_val_if_fail (output != NULL, NULL);
if ((crtc = gnome_rr_output_get_crtc (output)))
+ {
+ int total_w, total_h, tile_w, tile_h;
+ mode = gnome_rr_crtc_get_current_mode (crtc);
+
+ if (_gnome_rr_output_get_tiled_display_size (output, &tile_w, &tile_h, &total_w, &total_h))
+ {
+ if (mode->width == tile_w &&
+ mode->height == tile_h) {
+ if (output->modes[0]->tiled)
+ return output->modes[0];
+ }
+ }
return gnome_rr_crtc_get_current_mode (crtc);
-
+ }
return NULL;
}
@@ -1887,6 +2008,20 @@ gnome_rr_mode_get_height (GnomeRRMode *mode)
return mode->height;
}
+/**
+ * gnome_rr_mode_get_is_tiled:
+ * @mode: a #GnomeRRMode
+ *
+ * Returns TRUE if this mode is a tiled
+ * mode created for span a tiled monitor.
+ */
+gboolean
+gnome_rr_mode_get_is_tiled (GnomeRRMode *mode)
+{
+ g_return_val_if_fail (mode != NULL, FALSE);
+ return mode->tiled;
+}
+
static void
mode_initialize (GnomeRRMode *mode, GVariant *info)
{
@@ -2040,3 +2175,17 @@ gnome_rr_output_get_is_underscanning (GnomeRROutput *output)
g_assert(output != NULL);
return output->is_underscanning;
}
+
+gboolean
+_gnome_rr_output_get_tile_info (GnomeRROutput *output,
+ GnomeRRTile *tile)
+{
+ if (output->tile_info.group_id == UNDEFINED_GROUP_ID)
+ return FALSE;
+
+ if (!tile)
+ return FALSE;
+
+ *tile = output->tile_info;
+ return TRUE;
+}
diff --git a/libgnome-desktop/gnome-rr.h b/libgnome-desktop/gnome-rr.h
index 742edbb..94caf42 100644
--- a/libgnome-desktop/gnome-rr.h
+++ b/libgnome-desktop/gnome-rr.h
@@ -178,6 +178,7 @@ guint32 gnome_rr_mode_get_id (GnomeRRMode *mode)
guint gnome_rr_mode_get_width (GnomeRRMode *mode);
guint gnome_rr_mode_get_height (GnomeRRMode *mode);
int gnome_rr_mode_get_freq (GnomeRRMode *mode);
+gboolean gnome_rr_mode_get_is_tiled (GnomeRRMode *mode);
/* GnomeRRCrtc */
guint32 gnome_rr_crtc_get_id (GnomeRRCrtc *crtc);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]