summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-10-14 13:03:29 +1000
committerBastien Nocera <hadess@hadess.net>2015-07-01 10:43:42 +0200
commit40a5b4c9522c19cc5bbb2f5262c5e8347b581f87 (patch)
treed55f178697fc6f3b77b8b1bd07d3696628030f4c
parent456d4817924fe72b0dea300b2b18800abf3251e2 (diff)
downloadgnome-desktop-40a5b4c9522c19cc5bbb2f5262c5e8347b581f87.tar.gz
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
-rw-r--r--libgnome-desktop/gnome-rr-config.c9
-rw-r--r--libgnome-desktop/gnome-rr-config.h2
-rw-r--r--libgnome-desktop/gnome-rr-debug.c10
-rw-r--r--libgnome-desktop/gnome-rr-output-info.c275
-rw-r--r--libgnome-desktop/gnome-rr-private.h29
-rw-r--r--libgnome-desktop/gnome-rr.c155
-rw-r--r--libgnome-desktop/gnome-rr.h1
7 files changed, 476 insertions, 5 deletions
diff --git a/libgnome-desktop/gnome-rr-config.c b/libgnome-desktop/gnome-rr-config.c
index f21eb367..f300ee7b 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 bfd3e14c..333d7055 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 5530f460..682e721e 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 ff8ce780..d50dfa89 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 acf64979..e721e39c 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 099cd685..2c56d5ca 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 742edbbb..94caf42c 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);