gtk: import display configuration from gnome-desktop

This commit is contained in:
Marc-André Lureau 2011-03-16 20:14:09 +01:00
parent 07a3d7b2cd
commit a2ad8d1bed
12 changed files with 5926 additions and 10 deletions

View File

@ -166,7 +166,7 @@ if test "x$with_sasl" != "xno"; then
SASL_LIBS="$SASL_LIBS -lsasl"
else
AC_MSG_ERROR([You must install the Cyrus SASL development package in order to compile GTK-VNC])
fi
fi
CFLAGS="$old_cflags"
LIBS="$old_libs"
if test "x$with_sasl2" = "xyes" -o "x$with_sasl" = "xyes" ; then
@ -211,6 +211,24 @@ PKG_CHECK_MODULES(GTK, gtk+-$GTK_API_VERSION >= $GTK_REQUIRED)
AC_SUBST(GTK_CFLAGS)
AC_SUBST(GTK_LIBS)
PKG_CHECK_MODULES(XRANDR, x11 xrandr)
AC_SUBST(XRANDR_CFLAGS)
AC_SUBST(XRANDR_LIBS)
AC_DEFINE(HAVE_RANDR, 1, [Define if the xrandr library is present])
AC_ARG_WITH(pnp-ids-path,
[AC_HELP_STRING([--with-pnp-ids-path],
[Specify the path to pnp.ids @<:@default=(internal)@:>@])],,
[with_pnp_ids_path="\${pnpdatadir}/pnp.ids"])
AM_CONDITIONAL(USE_INTERNAL_PNP_IDS, test "x$with_pnp_ids_path" = "x\${pnpdatadir}/pnp.ids")
PNP_IDS=$with_pnp_ids_path
AC_SUBST(PNP_IDS)
if test "x$with_pnp_ids_path" = "x\${pnpdatadir}/pnp.ids"; then
EXTERNAL_PNP_IDS="no (internal)"
else
EXTERNAL_PNP_IDS="$with_pnp_ids_path"
fi
PKG_CHECK_MODULES(GLIB2, glib-2.0 >= 2.22)
AC_SUBST(GLIB2_CFLAGS)
AC_SUBST(GLIB2_LIBS)

View File

@ -43,6 +43,7 @@ SPICE_COMMON_CPPFLAGS = \
-DG_LOG_DOMAIN=\"GSpice\" \
-DSW_CANVAS_CACHE \
-DSPICE_GTK_LOCALEDIR=\"${SPICE_GTK_LOCALEDIR}\" \
-DPNP_IDS=\""$(PNP_IDS)"\"\
\
-I$(COMMON_DIR) \
-I$(CLIENT_DIR) \
@ -253,15 +254,31 @@ libspice_client_glibinclude_HEADERS = \
$(NULL)
spicy_SOURCES = \
spicy.c \
spice-cmdline.h \
spice-cmdline.c \
spicy_SOURCES = \
spicy.c \
display/edid.h \
display/edid-parse.c \
display/display-name.c \
display/gnome-rr-config.c \
display/gnome-rr-config.h \
display/gnome-rr-output-info.c \
display/gnome-rr-output-info.h \
display/gnome-rr-private.h \
display/gnome-rr.c \
display/gnome-rr.h \
spice-cmdline.h \
spice-cmdline.c \
$(NULL)
spicy_LDADD = \
libspice-client-gtk-$(SPICE_GTK_API_VERSION).la \
libspice-client-glib-2.0.la \
$(XRANDR_LIBS) \
$(NULL)
spicy_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(XRANDR_CFLAGS) \
$(NULL)

299
gtk/display/display-name.c Normal file
View File

@ -0,0 +1,299 @@
/*
* Copyright 2007 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Author: Soren Sandmann <sandmann@redhat.com> */
#include <config.h>
#include <glib/gi18n-lib.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "edid.h"
typedef struct Vendor Vendor;
struct Vendor
{
const char vendor_id[4];
const char vendor_name[28];
};
/* This list of vendor codes derived from lshw
*
* http://ezix.org/project/wiki/HardwareLiSter
*
* Note: we now prefer to use data coming from hwdata (and shipped with
* gnome-desktop). See
* http://git.fedorahosted.org/git/?p=hwdata.git;a=blob_plain;f=pnp.ids;hb=HEAD
* All contributions to the list of vendors should go there.
*/
static const struct Vendor vendors[] =
{
{ "AIC", "AG Neovo" },
{ "ACR", "Acer" },
{ "DEL", "DELL" },
{ "SAM", "SAMSUNG" },
{ "SNY", "SONY" },
{ "SEC", "Epson" },
{ "WAC", "Wacom" },
{ "NEC", "NEC" },
{ "CMO", "CMO" }, /* Chi Mei */
{ "BNQ", "BenQ" },
{ "ABP", "Advansys" },
{ "ACC", "Accton" },
{ "ACE", "Accton" },
{ "ADP", "Adaptec" },
{ "ADV", "AMD" },
{ "AIR", "AIR" },
{ "AMI", "AMI" },
{ "ASU", "ASUS" },
{ "ATI", "ATI" },
{ "ATK", "Allied Telesyn" },
{ "AZT", "Aztech" },
{ "BAN", "Banya" },
{ "BRI", "Boca Research" },
{ "BUS", "Buslogic" },
{ "CCI", "Cache Computers Inc." },
{ "CHA", "Chase" },
{ "CMD", "CMD Technology, Inc." },
{ "COG", "Cogent" },
{ "CPQ", "Compaq" },
{ "CRS", "Crescendo" },
{ "CSC", "Crystal" },
{ "CSI", "CSI" },
{ "CTL", "Creative Labs" },
{ "DBI", "Digi" },
{ "DEC", "Digital Equipment" },
{ "DBK", "Databook" },
{ "EGL", "Eagle Technology" },
{ "ELS", "ELSA" },
{ "ESS", "ESS" },
{ "FAR", "Farallon" },
{ "FDC", "Future Domain" },
{ "HWP", "Hewlett-Packard" },
{ "IBM", "IBM" },
{ "INT", "Intel" },
{ "ISA", "Iomega" },
{ "LEN", "Lenovo" },
{ "MDG", "Madge" },
{ "MDY", "Microdyne" },
{ "MET", "Metheus" },
{ "MIC", "Micronics" },
{ "MLX", "Mylex" },
{ "NVL", "Novell" },
{ "OLC", "Olicom" },
{ "PRO", "Proteon" },
{ "RII", "Racal" },
{ "RTL", "Realtek" },
{ "SCM", "SCM" },
{ "SKD", "SysKonnect" },
{ "SGI", "SGI" },
{ "SMC", "SMC" },
{ "SNI", "Siemens Nixdorf" },
{ "STL", "Stallion Technologies" },
{ "SUN", "Sun" },
{ "SUP", "SupraExpress" },
{ "SVE", "SVEC" },
{ "TCC", "Thomas-Conrad" },
{ "TCI", "Tulip" },
{ "TCM", "3Com" },
{ "TCO", "Thomas-Conrad" },
{ "TEC", "Tecmar" },
{ "TRU", "Truevision" },
{ "TOS", "Toshiba" },
{ "TYN", "Tyan" },
{ "UBI", "Ungermann-Bass" },
{ "USC", "UltraStor" },
{ "VDM", "Vadem" },
{ "VMI", "Vermont" },
{ "WDC", "Western Digital" },
{ "ZDS", "Zeos" },
/* From http://faydoc.tripod.com/structures/01/0136.htm */
{ "ACT", "Targa" },
{ "ADI", "ADI" },
{ "AOC", "AOC Intl" },
{ "API", "Acer America" },
{ "APP", "Apple Computer" },
{ "ART", "ArtMedia" },
{ "AST", "AST Research" },
{ "CPL", "Compal" },
{ "CTX", "Chuntex Electronic Co." },
{ "DPC", "Delta Electronics" },
{ "DWE", "Daewoo" },
{ "ECS", "ELITEGROUP" },
{ "EIZ", "EIZO" },
{ "FCM", "Funai" },
{ "GSM", "LG Electronics" },
{ "GWY", "Gateway 2000" },
{ "HEI", "Hyundai" },
{ "HIT", "Hitachi" },
{ "HSL", "Hansol" },
{ "HTC", "Hitachi" },
{ "ICL", "Fujitsu ICL" },
{ "IVM", "Idek Iiyama" },
{ "KFC", "KFC Computek" },
{ "LKM", "ADLAS" },
{ "LNK", "LINK Tech" },
{ "LTN", "Lite-On" },
{ "MAG", "MAG InnoVision" },
{ "MAX", "Maxdata" },
{ "MEI", "Panasonic" },
{ "MEL", "Mitsubishi" },
{ "MIR", "miro" },
{ "MTC", "MITAC" },
{ "NAN", "NANAO" },
{ "NEC", "NEC Tech" },
{ "NOK", "Nokia" },
{ "OQI", "OPTIQUEST" },
{ "PBN", "Packard Bell" },
{ "PGS", "Princeton" },
{ "PHL", "Philips" },
{ "REL", "Relisys" },
{ "SDI", "Samtron" },
{ "SMI", "Smile" },
{ "SPT", "Sceptre" },
{ "SRC", "Shamrock Technology" },
{ "STP", "Sceptre" },
{ "TAT", "Tatung" },
{ "TRL", "Royal Information Company" },
{ "TSB", "Toshiba, Inc." },
{ "UNM", "Unisys" },
{ "VSC", "ViewSonic" },
{ "WTC", "Wen Tech" },
{ "ZCM", "Zenith Data Systems" },
{ "???", "Unknown" },
};
static GHashTable *pnp_ids = NULL;
static void
read_pnp_ids (void)
{
gchar *contents;
gchar **lines;
gchar *line;
gchar *code, *name;
gint i;
if (pnp_ids)
return;
pnp_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
if (g_file_get_contents (PNP_IDS, &contents, NULL, NULL))
{
lines = g_strsplit (contents, "\n", -1);
for (i = 0; lines[i]; i++)
{
line = lines[i];
if (line[0] && line[1] && line[2] && line[3] == '\t' && line[4])
{
code = line;
line[3] = '\0';
name = line + 4;
g_hash_table_insert (pnp_ids, code, name);
}
}
g_free (lines);
g_free (contents);
}
}
static const char *
find_vendor (const char *code)
{
const char *vendor_name;
int i;
read_pnp_ids ();
vendor_name = g_hash_table_lookup (pnp_ids, code);
if (vendor_name)
return vendor_name;
for (i = 0; i < sizeof (vendors) / sizeof (vendors[0]); ++i)
{
const Vendor *v = &(vendors[i]);
if (strcmp (v->vendor_id, code) == 0)
return v->vendor_name;
}
return code;
};
char *
make_display_name (const MonitorInfo *info)
{
const char *vendor;
int width_mm, height_mm, inches;
if (info)
{
vendor = find_vendor (info->manufacturer_code);
}
else
{
/* Translators: "Unknown" here is used to identify a monitor for which
* we don't know the vendor. When a vendor is known, the name of the
* vendor is used. */
vendor = C_("Monitor vendor", "Unknown");
}
if (info && info->width_mm != -1 && info->height_mm)
{
width_mm = info->width_mm;
height_mm = info->height_mm;
}
else if (info && info->n_detailed_timings)
{
width_mm = info->detailed_timings[0].width_mm;
height_mm = info->detailed_timings[0].height_mm;
}
else
{
width_mm = -1;
height_mm = -1;
}
if (width_mm != -1 && height_mm != -1)
{
double d = sqrt (width_mm * width_mm + height_mm * height_mm);
inches = (int)(d / 25.4 + 0.5);
}
else
{
inches = -1;
}
if (inches > 0)
return g_strdup_printf ("%s %d\"", vendor, inches);
else
return g_strdup (vendor);
}

540
gtk/display/edid-parse.c Normal file
View File

@ -0,0 +1,540 @@
/*
* Copyright 2007 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Author: Soren Sandmann <sandmann@redhat.com> */
#include "edid.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <glib.h>
static int
get_bit (int in, int bit)
{
return (in & (1 << bit)) >> bit;
}
static int
get_bits (int in, int begin, int end)
{
int mask = (1 << (end - begin + 1)) - 1;
return (in >> begin) & mask;
}
static int
decode_header (const uchar *edid)
{
if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0)
return TRUE;
return FALSE;
}
static int
decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info)
{
int is_model_year;
/* Manufacturer Code */
info->manufacturer_code[0] = get_bits (edid[0x08], 2, 6);
info->manufacturer_code[1] = get_bits (edid[0x08], 0, 1) << 3;
info->manufacturer_code[1] |= get_bits (edid[0x09], 5, 7);
info->manufacturer_code[2] = get_bits (edid[0x09], 0, 4);
info->manufacturer_code[3] = '\0';
info->manufacturer_code[0] += 'A' - 1;
info->manufacturer_code[1] += 'A' - 1;
info->manufacturer_code[2] += 'A' - 1;
/* Product Code */
info->product_code = edid[0x0b] << 8 | edid[0x0a];
/* Serial Number */
info->serial_number =
edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24;
/* Week and Year */
is_model_year = FALSE;
switch (edid[0x10])
{
case 0x00:
info->production_week = -1;
break;
case 0xff:
info->production_week = -1;
is_model_year = TRUE;
break;
default:
info->production_week = edid[0x10];
break;
}
if (is_model_year)
{
info->production_year = -1;
info->model_year = 1990 + edid[0x11];
}
else
{
info->production_year = 1990 + edid[0x11];
info->model_year = -1;
}
return TRUE;
}
static int
decode_edid_version (const uchar *edid, MonitorInfo *info)
{
info->major_version = edid[0x12];
info->minor_version = edid[0x13];
return TRUE;
}
static int
decode_display_parameters (const uchar *edid, MonitorInfo *info)
{
/* Digital vs Analog */
info->is_digital = get_bit (edid[0x14], 7);
if (info->is_digital)
{
int bits;
static const int bit_depth[8] =
{
-1, 6, 8, 10, 12, 14, 16, -1
};
static const Interface interfaces[6] =
{
UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT
};
bits = get_bits (edid[0x14], 4, 6);
info->connector.digital.bits_per_primary = bit_depth[bits];
bits = get_bits (edid[0x14], 0, 3);
if (bits <= 5)
info->connector.digital.interface = interfaces[bits];
else
info->connector.digital.interface = UNDEFINED;
}
else
{
int bits = get_bits (edid[0x14], 5, 6);
static const double levels[][3] =
{
{ 0.7, 0.3, 1.0 },
{ 0.714, 0.286, 1.0 },
{ 1.0, 0.4, 1.4 },
{ 0.7, 0.0, 0.7 },
};
info->connector.analog.video_signal_level = levels[bits][0];
info->connector.analog.sync_signal_level = levels[bits][1];
info->connector.analog.total_signal_level = levels[bits][2];
info->connector.analog.blank_to_black = get_bit (edid[0x14], 4);
info->connector.analog.separate_hv_sync = get_bit (edid[0x14], 3);
info->connector.analog.composite_sync_on_h = get_bit (edid[0x14], 2);
info->connector.analog.composite_sync_on_green = get_bit (edid[0x14], 1);
info->connector.analog.serration_on_vsync = get_bit (edid[0x14], 0);
}
/* Screen Size / Aspect Ratio */
if (edid[0x15] == 0 && edid[0x16] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = -1.0;
}
else if (edid[0x16] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = 100.0 / (edid[0x15] + 99);
}
else if (edid[0x15] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = 100.0 / (edid[0x16] + 99);
info->aspect_ratio = 1/info->aspect_ratio; /* portrait */
}
else
{
info->width_mm = 10 * edid[0x15];
info->height_mm = 10 * edid[0x16];
}
/* Gamma */
if (edid[0x17] == 0xFF)
info->gamma = -1.0;
else
info->gamma = (edid[0x17] + 100.0) / 100.0;
/* Features */
info->standby = get_bit (edid[0x18], 7);
info->suspend = get_bit (edid[0x18], 6);
info->active_off = get_bit (edid[0x18], 5);
if (info->is_digital)
{
info->connector.digital.rgb444 = TRUE;
if (get_bit (edid[0x18], 3))
info->connector.digital.ycrcb444 = 1;
if (get_bit (edid[0x18], 4))
info->connector.digital.ycrcb422 = 1;
}
else
{
int bits = get_bits (edid[0x18], 3, 4);
ColorType color_type[4] =
{
MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR
};
info->connector.analog.color_type = color_type[bits];
}
info->srgb_is_standard = get_bit (edid[0x18], 2);
/* In 1.3 this is called "has preferred timing" */
info->preferred_timing_includes_native = get_bit (edid[0x18], 1);
/* FIXME: In 1.3 this indicates whether the monitor accepts GTF */
info->continuous_frequency = get_bit (edid[0x18], 0);
return TRUE;
}
static double
decode_fraction (int high, int low)
{
double result = 0.0;
int i;
high = (high << 2) | low;
for (i = 0; i < 10; ++i)
result += get_bit (high, i) * pow (2, i - 10);
return result;
}
static int
decode_color_characteristics (const uchar *edid, MonitorInfo *info)
{
info->red_x = decode_fraction (edid[0x1b], get_bits (edid[0x19], 6, 7));
info->red_y = decode_fraction (edid[0x1c], get_bits (edid[0x19], 5, 4));
info->green_x = decode_fraction (edid[0x1d], get_bits (edid[0x19], 2, 3));
info->green_y = decode_fraction (edid[0x1e], get_bits (edid[0x19], 0, 1));
info->blue_x = decode_fraction (edid[0x1f], get_bits (edid[0x1a], 6, 7));
info->blue_y = decode_fraction (edid[0x20], get_bits (edid[0x1a], 4, 5));
info->white_x = decode_fraction (edid[0x21], get_bits (edid[0x1a], 2, 3));
info->white_y = decode_fraction (edid[0x22], get_bits (edid[0x1a], 0, 1));
return TRUE;
}
static int
decode_established_timings (const uchar *edid, MonitorInfo *info)
{
static const Timing established[][8] =
{
{
{ 800, 600, 60 },
{ 800, 600, 56 },
{ 640, 480, 75 },
{ 640, 480, 72 },
{ 640, 480, 67 },
{ 640, 480, 60 },
{ 720, 400, 88 },
{ 720, 400, 70 }
},
{
{ 1280, 1024, 75 },
{ 1024, 768, 75 },
{ 1024, 768, 70 },
{ 1024, 768, 60 },
{ 1024, 768, 87 },
{ 832, 624, 75 },
{ 800, 600, 75 },
{ 800, 600, 72 }
},
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1152, 870, 75 }
},
};
int i, j, idx;
idx = 0;
for (i = 0; i < 3; ++i)
{
for (j = 0; j < 8; ++j)
{
int byte = edid[0x23 + i];
if (get_bit (byte, j) && established[i][j].frequency != 0)
info->established[idx++] = established[i][j];
}
}
return TRUE;
}
static int
decode_standard_timings (const uchar *edid, MonitorInfo *info)
{
int i;
for (i = 0; i < 8; i++)
{
int first = edid[0x26 + 2 * i];
int second = edid[0x27 + 2 * i];
if (first != 0x01 && second != 0x01)
{
int w = 8 * (first + 31);
int h = 0;
switch (get_bits (second, 6, 7))
{
case 0x00: h = (w / 16) * 10; break;
case 0x01: h = (w / 4) * 3; break;
case 0x02: h = (w / 5) * 4; break;
case 0x03: h = (w / 16) * 9; break;
}
info->standard[i].width = w;
info->standard[i].height = h;
info->standard[i].frequency = get_bits (second, 0, 5) + 60;
}
}
return TRUE;
}
static void
decode_lf_string (const uchar *s, int n_chars, char *result)
{
int i;
for (i = 0; i < n_chars; ++i)
{
if (s[i] == 0x0a)
{
*result++ = '\0';
break;
}
else if (s[i] == 0x00)
{
/* Convert embedded 0's to spaces */
*result++ = ' ';
}
else
{
*result++ = s[i];
}
}
}
static void
decode_display_descriptor (const uchar *desc,
MonitorInfo *info)
{
switch (desc[0x03])
{
case 0xFC:
decode_lf_string (desc + 5, 13, info->dsc_product_name);
break;
case 0xFF:
decode_lf_string (desc + 5, 13, info->dsc_serial_number);
break;
case 0xFE:
decode_lf_string (desc + 5, 13, info->dsc_string);
break;
case 0xFD:
/* Range Limits */
break;
case 0xFB:
/* Color Point */
break;
case 0xFA:
/* Timing Identifications */
break;
case 0xF9:
/* Color Management */
break;
case 0xF8:
/* Timing Codes */
break;
case 0xF7:
/* Established Timings */
break;
case 0x10:
break;
}
}
static void
decode_detailed_timing (const uchar *timing,
DetailedTiming *detailed)
{
int bits;
StereoType stereo[] =
{
NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT,
TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN,
FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE
};
detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000;
detailed->h_addr = timing[0x02] | ((timing[0x04] & 0xf0) << 4);
detailed->h_blank = timing[0x03] | ((timing[0x04] & 0x0f) << 8);
detailed->v_addr = timing[0x05] | ((timing[0x07] & 0xf0) << 4);
detailed->v_blank = timing[0x06] | ((timing[0x07] & 0x0f) << 8);
detailed->h_front_porch = timing[0x08] | get_bits (timing[0x0b], 6, 7) << 8;
detailed->h_sync = timing[0x09] | get_bits (timing[0x0b], 4, 5) << 8;
detailed->v_front_porch =
get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4;
detailed->v_sync =
get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4;
detailed->width_mm = timing[0x0c] | get_bits (timing[0x0e], 4, 7) << 8;
detailed->height_mm = timing[0x0d] | get_bits (timing[0x0e], 0, 3) << 8;
detailed->right_border = timing[0x0f];
detailed->top_border = timing[0x10];
detailed->interlaced = get_bit (timing[0x11], 7);
/* Stereo */
bits = get_bits (timing[0x11], 5, 6) << 1 | get_bit (timing[0x11], 0);
detailed->stereo = stereo[bits];
/* Sync */
bits = timing[0x11];
detailed->digital_sync = get_bit (bits, 4);
if (detailed->digital_sync)
{
detailed->connector.digital.composite = !get_bit (bits, 3);
if (detailed->connector.digital.composite)
{
detailed->connector.digital.serrations = get_bit (bits, 2);
detailed->connector.digital.negative_vsync = FALSE;
}
else
{
detailed->connector.digital.serrations = FALSE;
detailed->connector.digital.negative_vsync = !get_bit (bits, 2);
}
detailed->connector.digital.negative_hsync = !get_bit (bits, 0);
}
else
{
detailed->connector.analog.bipolar = get_bit (bits, 3);
detailed->connector.analog.serrations = get_bit (bits, 2);
detailed->connector.analog.sync_on_green = !get_bit (bits, 1);
}
}
static int
decode_descriptors (const uchar *edid, MonitorInfo *info)
{
int i;
int timing_idx;
timing_idx = 0;
for (i = 0; i < 4; ++i)
{
int index = 0x36 + i * 18;
if (edid[index + 0] == 0x00 && edid[index + 1] == 0x00)
{
decode_display_descriptor (edid + index, info);
}
else
{
decode_detailed_timing (
edid + index, &(info->detailed_timings[timing_idx++]));
}
}
info->n_detailed_timings = timing_idx;
return TRUE;
}
static void
decode_check_sum (const uchar *edid,
MonitorInfo *info)
{
int i;
uchar check = 0;
for (i = 0; i < 128; ++i)
check += edid[i];
info->checksum = check;
}
MonitorInfo *
decode_edid (const uchar *edid)
{
MonitorInfo *info = g_new0 (MonitorInfo, 1);
decode_check_sum (edid, info);
if (decode_header (edid)
&& decode_vendor_and_product_identification (edid, info)
&& decode_edid_version (edid, info)
&& decode_display_parameters (edid, info)
&& decode_color_characteristics (edid, info)
&& decode_established_timings (edid, info)
&& decode_standard_timings (edid, info)
&& decode_descriptors (edid, info))
{
return info;
}
else
{
g_free (info);
return NULL;
}
}

194
gtk/display/edid.h Normal file
View File

@ -0,0 +1,194 @@
/* edid.h
*
* Copyright 2007, 2008, Red Hat, Inc.
*
* This file is part of the Gnome Library.
*
* The Gnome Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The Gnome Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with the Gnome Library; see the file COPYING.LIB. If not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Soren Sandmann <sandmann@redhat.com>
*/
#ifndef EDID_H
#define EDID_H
typedef unsigned char uchar;
typedef struct MonitorInfo MonitorInfo;
typedef struct Timing Timing;
typedef struct DetailedTiming DetailedTiming;
typedef enum
{
UNDEFINED,
DVI,
HDMI_A,
HDMI_B,
MDDI,
DISPLAY_PORT
} Interface;
typedef enum
{
UNDEFINED_COLOR,
MONOCHROME,
RGB,
OTHER_COLOR
} ColorType;
typedef enum
{
NO_STEREO,
FIELD_RIGHT,
FIELD_LEFT,
TWO_WAY_RIGHT_ON_EVEN,
TWO_WAY_LEFT_ON_EVEN,
FOUR_WAY_INTERLEAVED,
SIDE_BY_SIDE
} StereoType;
struct Timing
{
int width;
int height;
int frequency;
};
struct DetailedTiming
{
int pixel_clock;
int h_addr;
int h_blank;
int h_sync;
int h_front_porch;
int v_addr;
int v_blank;
int v_sync;
int v_front_porch;
int width_mm;
int height_mm;
int right_border;
int top_border;
int interlaced;
StereoType stereo;
int digital_sync;
union
{
struct
{
int bipolar;
int serrations;
int sync_on_green;
} analog;
struct
{
int composite;
int serrations;
int negative_vsync;
int negative_hsync;
} digital;
} connector;
};
struct MonitorInfo
{
int checksum;
char manufacturer_code[4];
int product_code;
unsigned int serial_number;
int production_week; /* -1 if not specified */
int production_year; /* -1 if not specified */
int model_year; /* -1 if not specified */
int major_version;
int minor_version;
int is_digital;
union
{
struct
{
int bits_per_primary;
Interface interface;
int rgb444;
int ycrcb444;
int ycrcb422;
} digital;
struct
{
double video_signal_level;
double sync_signal_level;
double total_signal_level;
int blank_to_black;
int separate_hv_sync;
int composite_sync_on_h;
int composite_sync_on_green;
int serration_on_vsync;
ColorType color_type;
} analog;
} connector;
int width_mm; /* -1 if not specified */
int height_mm; /* -1 if not specified */
double aspect_ratio; /* -1.0 if not specififed */
double gamma; /* -1.0 if not specified */
int standby;
int suspend;
int active_off;
int srgb_is_standard;
int preferred_timing_includes_native;
int continuous_frequency;
double red_x;
double red_y;
double green_x;
double green_y;
double blue_x;
double blue_y;
double white_x;
double white_y;
Timing established[24]; /* Terminated by 0x0x0 */
Timing standard[8];
int n_detailed_timings;
DetailedTiming detailed_timings[4]; /* If monitor has a preferred
* mode, it is the first one
* (whether it has, is
* determined by the
* preferred_timing_includes
* bit.
*/
/* Optional product description */
char dsc_serial_number[14];
char dsc_product_name[14];
char dsc_string[14]; /* Unspecified ASCII data */
};
MonitorInfo *decode_edid (const uchar *data);
char *make_display_name (const MonitorInfo *info);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,150 @@
/* gnome-rr-config.h
* -*- c-basic-offset: 4 -*-
*
* Copyright 2007, 2008, Red Hat, Inc.
* Copyright 2010 Giovanni Campagna
*
* This file is part of the Gnome Library.
*
* The Gnome Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The Gnome Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with the Gnome Library; see the file COPYING.LIB. If not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Soren Sandmann <sandmann@redhat.com>
*/
#ifndef GNOME_RR_CONFIG_H
#define GNOME_RR_CONFIG_H
#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
#error gnome-rr-config.h is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-rr-config.h
#endif
#include <glib.h>
#include <glib-object.h>
#include "gnome-rr.h"
typedef struct GnomeRROutputInfoPrivate GnomeRROutputInfoPrivate;
typedef struct GnomeRRConfigPrivate GnomeRRConfigPrivate;
typedef struct
{
GObject parent;
/*< private >*/
GnomeRROutputInfoPrivate *priv;
} GnomeRROutputInfo;
typedef struct
{
GObjectClass parent_class;
} GnomeRROutputInfoClass;
#define GNOME_TYPE_RR_OUTPUT_INFO (gnome_rr_output_info_get_type())
#define GNOME_RR_OUTPUT_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_RR_OUTPUT_INFO, GnomeRROutputInfo))
#define GNOME_IS_RR_OUTPUT_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_RR_OUTPUT_INFO))
#define GNOME_RR_OUTPUT_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_RR_OUTPUT_INFO, GnomeRROutputInfoClass))
#define GNOME_IS_RR_OUTPUT_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_RR_OUTPUT_INFO))
#define GNOME_RR_OUTPUT_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_RR_OUTPUT_INFO, GnomeRROutputInfoClass))
GType gnome_rr_output_info_get_type (void);
char *gnome_rr_output_info_get_name (GnomeRROutputInfo *self);
gboolean gnome_rr_output_info_is_active (GnomeRROutputInfo *self);
void gnome_rr_output_info_set_active (GnomeRROutputInfo *self, gboolean active);
void gnome_rr_output_info_get_geometry (GnomeRROutputInfo *self, int *x, int *y, int *width, int *height);
void gnome_rr_output_info_set_geometry (GnomeRROutputInfo *self, int x, int y, int width, int height);
int gnome_rr_output_info_get_refresh_rate (GnomeRROutputInfo *self);
void gnome_rr_output_info_set_refresh_rate (GnomeRROutputInfo *self, int rate);
GnomeRRRotation gnome_rr_output_info_get_rotation (GnomeRROutputInfo *self);
void gnome_rr_output_info_set_rotation (GnomeRROutputInfo *self, GnomeRRRotation rotation);
gboolean gnome_rr_output_info_is_connected (GnomeRROutputInfo *self);
void gnome_rr_output_info_get_vendor (GnomeRROutputInfo *self, gchar* vendor);
guint gnome_rr_output_info_get_product (GnomeRROutputInfo *self);
guint gnome_rr_output_info_get_serial (GnomeRROutputInfo *self);
double gnome_rr_output_info_get_aspect_ratio (GnomeRROutputInfo *self);
char *gnome_rr_output_info_get_display_name (GnomeRROutputInfo *self);
gboolean gnome_rr_output_info_get_primary (GnomeRROutputInfo *self);
void gnome_rr_output_info_set_primary (GnomeRROutputInfo *self, gboolean primary);
int gnome_rr_output_info_get_preferred_width (GnomeRROutputInfo *self);
int gnome_rr_output_info_get_preferred_height (GnomeRROutputInfo *self);
typedef struct
{
GObject parent;
/*< private >*/
GnomeRRConfigPrivate *priv;
} GnomeRRConfig;
typedef struct
{
GObjectClass parent_class;
} GnomeRRConfigClass;
#define GNOME_TYPE_RR_CONFIG (gnome_rr_config_get_type())
#define GNOME_RR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_RR_CONFIG, GnomeRRConfig))
#define GNOME_IS_RR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_RR_CONFIG))
#define GNOME_RR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_RR_CONFIG, GnomeRRConfigClass))
#define GNOME_IS_RR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_RR_CONFIG))
#define GNOME_RR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_RR_CONFIG, GnomeRRConfigClass))
GType gnome_rr_config_get_type (void);
GnomeRRConfig *gnome_rr_config_new_current (GnomeRRScreen *screen,
GError **error);
GnomeRRConfig *gnome_rr_config_new_stored (GnomeRRScreen *screen,
GError **error);
gboolean gnome_rr_config_load_current (GnomeRRConfig *self,
GError **error);
gboolean gnome_rr_config_load_filename (GnomeRRConfig *self,
const gchar *filename,
GError **error);
gboolean gnome_rr_config_match (GnomeRRConfig *config1,
GnomeRRConfig *config2);
gboolean gnome_rr_config_equal (GnomeRRConfig *config1,
GnomeRRConfig *config2);
gboolean gnome_rr_config_save (GnomeRRConfig *configuration,
GError **error);
void gnome_rr_config_sanitize (GnomeRRConfig *configuration);
gboolean gnome_rr_config_ensure_primary (GnomeRRConfig *configuration);
gboolean gnome_rr_config_apply_with_time (GnomeRRConfig *configuration,
GnomeRRScreen *screen,
guint32 timestamp,
GError **error);
gboolean gnome_rr_config_apply_from_filename_with_time (GnomeRRScreen *screen,
const char *filename,
guint32 timestamp,
GError **error);
gboolean gnome_rr_config_applicable (GnomeRRConfig *configuration,
GnomeRRScreen *screen,
GError **error);
gboolean gnome_rr_config_get_clone (GnomeRRConfig *configuration);
void gnome_rr_config_set_clone (GnomeRRConfig *configuration, gboolean clone);
GnomeRROutputInfo **gnome_rr_config_get_outputs (GnomeRRConfig *configuration);
char *gnome_rr_config_get_backup_filename (void);
char *gnome_rr_config_get_intended_filename (void);
#endif

View File

@ -0,0 +1,246 @@
/* gnome-rr-output-info.c
* -*- c-basic-offset: 4 -*-
*
* Copyright 2010 Giovanni Campagna
*
* This file is part of the Gnome Desktop Library.
*
* The Gnome Desktop Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The Gnome Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with the Gnome Desktop Library; see the file COPYING.LIB. If not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <config.h>
#include "gnome-rr-config.h"
#include "edid.h"
#include "gnome-rr-private.h"
G_DEFINE_TYPE (GnomeRROutputInfo, gnome_rr_output_info, G_TYPE_OBJECT)
static void
gnome_rr_output_info_init (GnomeRROutputInfo *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GNOME_TYPE_RR_OUTPUT_INFO, GnomeRROutputInfoPrivate);
self->priv->name = NULL;
self->priv->on = FALSE;
self->priv->display_name = NULL;
}
static void
gnome_rr_output_info_finalize (GObject *gobject)
{
GnomeRROutputInfo *self = GNOME_RR_OUTPUT_INFO (gobject);
g_free (self->priv->name);
g_free (self->priv->display_name);
G_OBJECT_CLASS (gnome_rr_output_info_parent_class)->finalize (gobject);
}
static void
gnome_rr_output_info_class_init (GnomeRROutputInfoClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (GnomeRROutputInfoPrivate));
gobject_class->finalize = gnome_rr_output_info_finalize;
}
/**
* gnome_rr_output_info_get_name:
*
* Returns: (transfer none): the output name
*/
char *gnome_rr_output_info_get_name (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), NULL);
return self->priv->name;
}
/**
* gnome_rr_output_info_is_active:
*
* Returns: whether there is a CRTC assigned to this output (i.e. a signal is being sent to it)
*/
gboolean gnome_rr_output_info_is_active (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), FALSE);
return self->priv->on;
}
void gnome_rr_output_info_set_active (GnomeRROutputInfo *self, gboolean active)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
self->priv->on = active;
}
/**
* gnome_rr_output_info_get_geometry:
*
* @self: a #GnomeRROutputInfo
* @x: (out) (allow-none):
* @y: (out) (allow-none):
* @width: (out) (allow-none):
* @height: (out) (allow-none):
*/
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 (x)
*x = self->priv->x;
if (y)
*y = self->priv->y;
if (width)
*width = self->priv->width;
if (height)
*height = self->priv->height;
}
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));
self->priv->x = x;
self->priv->y = y;
self->priv->width = width;
self->priv->height = height;
}
int gnome_rr_output_info_get_refresh_rate (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return self->priv->rate;
}
void gnome_rr_output_info_set_refresh_rate (GnomeRROutputInfo *self, int rate)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
self->priv->rate = rate;
}
GnomeRRRotation gnome_rr_output_info_get_rotation (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), GNOME_RR_ROTATION_0);
return self->priv->rotation;
}
void gnome_rr_output_info_set_rotation (GnomeRROutputInfo *self, GnomeRRRotation rotation)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
self->priv->rotation = rotation;
}
/**
* gnome_rr_output_info_is_connected:
*
* Returns: whether the output is physically connected to a monitor
*/
gboolean gnome_rr_output_info_is_connected (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), FALSE);
return self->priv->connected;
}
/**
* gnome_rr_output_info_get_vendor:
*
* @self: a #GnomeRROutputInfo
* @vendor: (out caller-allocates) (array fixed-size=4):
*/
void gnome_rr_output_info_get_vendor (GnomeRROutputInfo *self, gchar* vendor)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
g_return_if_fail (vendor != NULL);
vendor[0] = self->priv->vendor[0];
vendor[1] = self->priv->vendor[1];
vendor[2] = self->priv->vendor[2];
vendor[3] = self->priv->vendor[3];
}
guint gnome_rr_output_info_get_product (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return self->priv->product;
}
guint gnome_rr_output_info_get_serial (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return self->priv->serial;
}
double gnome_rr_output_info_get_aspect_ratio (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return self->priv->aspect;
}
/**
* gnome_rr_output_info_get_display_name:
*
* Returns: (transfer none): the display name of this output
*/
char *gnome_rr_output_info_get_display_name (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), NULL);
return self->priv->display_name;
}
gboolean gnome_rr_output_info_get_primary (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), FALSE);
return self->priv->primary;
}
void gnome_rr_output_info_set_primary (GnomeRROutputInfo *self, gboolean primary)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
self->priv->primary = primary;
}
int gnome_rr_output_info_get_preferred_width (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return self->priv->pref_width;
}
int gnome_rr_output_info_get_preferred_height (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return self->priv->pref_height;
}

View File

@ -0,0 +1,80 @@
#ifndef GNOME_RR_PRIVATE_H
#define GNOME_RR_PRIVATE_H
#ifdef HAVE_RANDR
#include <X11/extensions/Xrandr.h>
#endif
typedef struct ScreenInfo ScreenInfo;
struct ScreenInfo
{
int min_width;
int max_width;
int min_height;
int max_height;
#ifdef HAVE_RANDR
XRRScreenResources *resources;
#endif
GnomeRROutput ** outputs;
GnomeRRCrtc ** crtcs;
GnomeRRMode ** modes;
GnomeRRScreen * screen;
GnomeRRMode ** clone_modes;
#ifdef HAVE_RANDR
RROutput primary;
#endif
};
struct GnomeRRScreenPrivate
{
GdkScreen * gdk_screen;
GdkWindow * gdk_root;
Display * xdisplay;
Screen * xscreen;
Window xroot;
ScreenInfo * info;
int randr_event_base;
int rr_major_version;
int rr_minor_version;
Atom connector_type_atom;
};
struct GnomeRROutputInfoPrivate
{
char * name;
gboolean on;
int width;
int height;
int rate;
int x;
int y;
GnomeRRRotation rotation;
gboolean connected;
gchar vendor[4];
guint product;
guint serial;
double aspect;
int pref_width;
int pref_height;
char * display_name;
gboolean primary;
};
struct GnomeRRConfigPrivate
{
gboolean clone;
GnomeRRScreen *screen;
GnomeRROutputInfo **outputs;
};
#endif

2121
gtk/display/gnome-rr.c Normal file

File diff suppressed because it is too large Load Diff

202
gtk/display/gnome-rr.h Normal file
View File

@ -0,0 +1,202 @@
/* gnome-rr.h
*
* Copyright 2007, 2008, Red Hat, Inc.
*
* This file is part of the Gnome Library.
*
* The Gnome Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The Gnome Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with the Gnome Library; see the file COPYING.LIB. If not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Soren Sandmann <sandmann@redhat.com>
*/
#ifndef GNOME_RR_H
#define GNOME_RR_H
#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
#error GnomeRR is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnomerr.h
#endif
#include <glib.h>
#include <gdk/gdk.h>
typedef struct GnomeRRScreenPrivate GnomeRRScreenPrivate;
typedef struct GnomeRROutput GnomeRROutput;
typedef struct GnomeRRCrtc GnomeRRCrtc;
typedef struct GnomeRRMode GnomeRRMode;
typedef struct {
GObject parent;
GnomeRRScreenPrivate* priv;
} GnomeRRScreen;
typedef struct {
GObjectClass parent_class;
void (* changed) (void);
} GnomeRRScreenClass;
typedef enum
{
GNOME_RR_ROTATION_0 = (1 << 0),
GNOME_RR_ROTATION_90 = (1 << 1),
GNOME_RR_ROTATION_180 = (1 << 2),
GNOME_RR_ROTATION_270 = (1 << 3),
GNOME_RR_REFLECT_X = (1 << 4),
GNOME_RR_REFLECT_Y = (1 << 5)
} GnomeRRRotation;
/* Error codes */
#define GNOME_RR_ERROR (gnome_rr_error_quark ())
GQuark gnome_rr_error_quark (void);
typedef enum {
GNOME_RR_ERROR_UNKNOWN, /* generic "fail" */
GNOME_RR_ERROR_NO_RANDR_EXTENSION, /* RANDR extension is not present */
GNOME_RR_ERROR_RANDR_ERROR, /* generic/undescribed error from the underlying XRR API */
GNOME_RR_ERROR_BOUNDS_ERROR, /* requested bounds of a CRTC are outside the maximum size */
GNOME_RR_ERROR_CRTC_ASSIGNMENT, /* could not assign CRTCs to outputs */
GNOME_RR_ERROR_NO_MATCHING_CONFIG, /* none of the saved configurations matched the current configuration */
} GnomeRRError;
#define GNOME_RR_CONNECTOR_TYPE_PANEL "Panel" /* This is a laptop's built-in LCD */
#define GNOME_TYPE_RR_SCREEN (gnome_rr_screen_get_type())
#define GNOME_RR_SCREEN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_RR_SCREEN, GnomeRRScreen))
#define GNOME_IS_RR_SCREEN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_RR_SCREEN))
#define GNOME_RR_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_RR_SCREEN, GnomeRRScreenClass))
#define GNOME_IS_RR_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_RR_SCREEN))
#define GNOME_RR_SCREEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_RR_SCREEN, GnomeRRScreenClass))
#define GNOME_TYPE_RR_OUTPUT (gnome_rr_output_get_type())
#define GNOME_TYPE_RR_CRTC (gnome_rr_crtc_get_type())
#define GNOME_TYPE_RR_MODE (gnome_rr_mode_get_type())
GType gnome_rr_screen_get_type (void);
GType gnome_rr_output_get_type (void);
GType gnome_rr_crtc_get_type (void);
GType gnome_rr_mode_get_type (void);
/* GnomeRRScreen */
GnomeRRScreen * gnome_rr_screen_new (GdkScreen *screen,
GError **error);
GnomeRROutput **gnome_rr_screen_list_outputs (GnomeRRScreen *screen);
GnomeRRCrtc ** gnome_rr_screen_list_crtcs (GnomeRRScreen *screen);
GnomeRRMode ** gnome_rr_screen_list_modes (GnomeRRScreen *screen);
GnomeRRMode ** gnome_rr_screen_list_clone_modes (GnomeRRScreen *screen);
void gnome_rr_screen_set_size (GnomeRRScreen *screen,
int width,
int height,
int mm_width,
int mm_height);
GnomeRRCrtc * gnome_rr_screen_get_crtc_by_id (GnomeRRScreen *screen,
guint32 id);
gboolean gnome_rr_screen_refresh (GnomeRRScreen *screen,
GError **error);
GnomeRROutput * gnome_rr_screen_get_output_by_id (GnomeRRScreen *screen,
guint32 id);
GnomeRROutput * gnome_rr_screen_get_output_by_name (GnomeRRScreen *screen,
const char *name);
void gnome_rr_screen_get_ranges (GnomeRRScreen *screen,
int *min_width,
int *max_width,
int *min_height,
int *max_height);
void gnome_rr_screen_get_timestamps (GnomeRRScreen *screen,
guint32 *change_timestamp_ret,
guint32 *config_timestamp_ret);
void gnome_rr_screen_set_primary_output (GnomeRRScreen *screen,
GnomeRROutput *output);
GnomeRRMode **gnome_rr_screen_create_clone_modes (GnomeRRScreen *screen);
/* GnomeRROutput */
guint32 gnome_rr_output_get_id (GnomeRROutput *output);
const char * gnome_rr_output_get_name (GnomeRROutput *output);
gboolean gnome_rr_output_is_connected (GnomeRROutput *output);
int gnome_rr_output_get_size_inches (GnomeRROutput *output);
int gnome_rr_output_get_width_mm (GnomeRROutput *outout);
int gnome_rr_output_get_height_mm (GnomeRROutput *output);
const guint8 * gnome_rr_output_get_edid_data (GnomeRROutput *output);
GnomeRRCrtc ** gnome_rr_output_get_possible_crtcs (GnomeRROutput *output);
GnomeRRMode * gnome_rr_output_get_current_mode (GnomeRROutput *output);
GnomeRRCrtc * gnome_rr_output_get_crtc (GnomeRROutput *output);
const char * gnome_rr_output_get_connector_type (GnomeRROutput *output);
gboolean gnome_rr_output_is_laptop (GnomeRROutput *output);
void gnome_rr_output_get_position (GnomeRROutput *output,
int *x,
int *y);
gboolean gnome_rr_output_can_clone (GnomeRROutput *output,
GnomeRROutput *clone);
GnomeRRMode ** gnome_rr_output_list_modes (GnomeRROutput *output);
GnomeRRMode * gnome_rr_output_get_preferred_mode (GnomeRROutput *output);
gboolean gnome_rr_output_supports_mode (GnomeRROutput *output,
GnomeRRMode *mode);
gboolean gnome_rr_output_get_is_primary (GnomeRROutput *output);
/* GnomeRRMode */
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);
/* GnomeRRCrtc */
guint32 gnome_rr_crtc_get_id (GnomeRRCrtc *crtc);
#ifndef GNOME_DISABLE_DEPRECATED
gboolean gnome_rr_crtc_set_config (GnomeRRCrtc *crtc,
int x,
int y,
GnomeRRMode *mode,
GnomeRRRotation rotation,
GnomeRROutput **outputs,
int n_outputs,
GError **error);
#endif
gboolean gnome_rr_crtc_set_config_with_time (GnomeRRCrtc *crtc,
guint32 timestamp,
int x,
int y,
GnomeRRMode *mode,
GnomeRRRotation rotation,
GnomeRROutput **outputs,
int n_outputs,
GError **error);
gboolean gnome_rr_crtc_can_drive_output (GnomeRRCrtc *crtc,
GnomeRROutput *output);
GnomeRRMode * gnome_rr_crtc_get_current_mode (GnomeRRCrtc *crtc);
void gnome_rr_crtc_get_position (GnomeRRCrtc *crtc,
int *x,
int *y);
GnomeRRRotation gnome_rr_crtc_get_current_rotation (GnomeRRCrtc *crtc);
GnomeRRRotation gnome_rr_crtc_get_rotations (GnomeRRCrtc *crtc);
gboolean gnome_rr_crtc_supports_rotation (GnomeRRCrtc *crtc,
GnomeRRRotation rotation);
gboolean gnome_rr_crtc_get_gamma (GnomeRRCrtc *crtc,
int *size,
unsigned short **red,
unsigned short **green,
unsigned short **blue);
void gnome_rr_crtc_set_gamma (GnomeRRCrtc *crtc,
int size,
unsigned short *red,
unsigned short *green,
unsigned short *blue);
#endif /* GNOME_RR_H */

View File

@ -22,11 +22,18 @@
#include <glib/gi18n.h>
#include <sys/stat.h>
#define GNOME_DESKTOP_USE_UNSTABLE_API 2
#include "display/gnome-rr.h"
#include "display/gnome-rr-config.h"
#include "spice-widget.h"
#include "spice-audio.h"
#include "spice-common.h"
#include "spice-cmdline.h"
#include "spice-cmdline.h"
/* config */
static gboolean fullscreen = false;
static gboolean version = false;
@ -52,6 +59,7 @@ struct spice_window {
GtkUIManager *ui;
bool fullscreen;
bool mouse_grabbed;
SpiceChannel *channel;
};
struct spice_connection {
@ -67,6 +75,8 @@ struct spice_connection {
static GMainLoop *mainloop;
static int connections;
static GKeyFile *keyfile;
static GnomeRRScreen *rrscreen;
static GnomeRRConfig *rrsaved;
static spice_connection *connection_new(void);
static void connection_connect(spice_connection *conn);
@ -369,7 +379,6 @@ static gboolean window_state_cb(GtkWidget *widget, GdkEventWindowState *event,
gpointer data)
{
struct spice_window *win = data;
if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
win->fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
if (win->fullscreen) {
@ -618,7 +627,38 @@ static void recent_item_activated_cb(GtkRecentChooser *chooser, gpointer data)
connection_connect(conn);
}
static spice_window *create_spice_window(spice_connection *conn, int id)
static void resolution_change(struct spice_window *win)
{
}
static void resolution_restore(struct spice_window *win)
{
}
static gboolean configure_event_cb(GtkWidget *widget,
GdkEventConfigure *event,
gpointer data)
{
gboolean resize_guest;
struct spice_window *win = data;
guint w, h;
g_object_get(win->spice, "resize-guest", &resize_guest, NULL);
if (resize_guest)
return FALSE;
g_object_get(win->channel, "width", &w, "height", &h, NULL);
g_message("test: %d %d win %d %d %d", w, h, event->width, event->height, win->fullscreen);
if (win->fullscreen) {
resolution_change(win);
} else {
resolution_restore(win);
}
return FALSE;
}
static spice_window *create_spice_window(spice_connection *conn, int id, SpiceChannel *channel)
{
char title[32];
struct spice_window *win;
@ -636,6 +676,7 @@ static spice_window *create_spice_window(spice_connection *conn, int id)
memset(win,0,sizeof(*win));
win->id = id;
win->conn = conn;
win->channel = channel;
g_message("create window (#%d)", win->id);
/* toplevel */
@ -682,6 +723,7 @@ static spice_window *create_spice_window(spice_connection *conn, int id)
/* spice display */
win->spice = GTK_WIDGET(spice_display_new(conn->session, id));
g_signal_connect(win->spice, "configure-event", G_CALLBACK(configure_event_cb), win);
seq = spice_grab_sequence_new_from_string("Shift+F12");
spice_display_set_grab_keys(SPICE_DISPLAY(win->spice), seq);
spice_grab_sequence_free(seq);
@ -905,7 +947,7 @@ static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data)
if (conn->wins[id] != NULL)
return;
SPICE_DEBUG("new display channel (#%d)", id);
conn->wins[id] = create_spice_window(conn, id);
conn->wins[id] = create_spice_window(conn, id, channel);
}
if (SPICE_IS_INPUTS_CHANNEL(channel)) {
@ -1013,6 +1055,28 @@ static void connection_destroy(spice_connection *conn)
g_main_loop_quit(mainloop);
}
static void
on_screen_changed(GnomeRRScreen *scr, gpointer data)
{
GError *error = NULL;
rrsaved = gnome_rr_config_new_current(rrscreen, &error);
if (!rrsaved) {
g_warning("Can't get current display config: %s", error->message);
goto end;
}
g_clear_error(&error);
if (!gnome_rr_config_apply_with_time(rrsaved, rrscreen,
gtk_get_current_event_time (), &error)) {
g_warning("Can't restore display config: %s", error->message);
}
g_clear_error(&error);
end:
g_clear_error(&error);
}
/* ------------------------------------------------------------------ */
static GOptionEntry cmd_entries[] = {
@ -1058,8 +1122,7 @@ int main(int argc, char *argv[])
if (!g_key_file_load_from_file(keyfile, conf_file,
G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, &error)) {
SPICE_DEBUG("Couldn't load configuration: %s", error->message);
g_error_free(error);
error = NULL;
g_clear_error(&error);
}
/* parse opts */
@ -1082,6 +1145,10 @@ int main(int argc, char *argv[])
g_type_init();
mainloop = g_main_loop_new(NULL, false);
rrscreen = gnome_rr_screen_new(gdk_screen_get_default (), &error);
g_warn_if_fail(rrscreen != NULL);
g_signal_connect(rrscreen, "changed", G_CALLBACK(on_screen_changed), NULL);
on_screen_changed(rrscreen, NULL);
conn = connection_new();
spice_cmdline_session_setup(conn->session);