Merge lp:~robert-ancell/unity-settings-daemon/xrandr into lp:unity-settings-daemon

Proposed by Robert Ancell
Status: Merged
Approved by: Iain Lane
Approved revision: 4052
Merged at revision: 4046
Proposed branch: lp:~robert-ancell/unity-settings-daemon/xrandr
Merge into: lp:unity-settings-daemon
Diff against target: 11698 lines (+8776/-587)
42 files modified
configure.ac (+10/-0)
data/Makefile.am (+2/-1)
data/libunity-settings-daemon.pc.in (+12/-0)
debian/control (+19/-1)
debian/libunity-settings-daemon1.install (+1/-0)
debian/libunity-settings-daemon1.symbols (+105/-0)
debian/rules (+1/-1)
debian/unity-settings-daemon-dev.install (+1/-0)
debian/unity-settings-daemon.install (+0/-1)
gnome-settings-daemon/Makefile.am (+48/-0)
gnome-settings-daemon/check_gl_texture_size.c (+86/-0)
gnome-settings-daemon/display-name.c (+144/-0)
gnome-settings-daemon/edid-parse.c (+540/-0)
gnome-settings-daemon/edid.h (+195/-0)
gnome-settings-daemon/edid_parse.c (+540/-0)
gnome-settings-daemon/gnome-settings-manager.c (+3/-5)
gnome-settings-daemon/gsd-idle-monitor.c (+616/-0)
gnome-settings-daemon/gsd-idle-monitor.h (+81/-0)
gnome-settings-daemon/gsd-pnp-ids.c (+341/-0)
gnome-settings-daemon/gsd-pnp-ids.h (+58/-0)
gnome-settings-daemon/gsd-rr-config.c (+2091/-0)
gnome-settings-daemon/gsd-rr-config.h (+151/-0)
gnome-settings-daemon/gsd-rr-output-info.c (+242/-0)
gnome-settings-daemon/gsd-rr-private.h (+79/-0)
gnome-settings-daemon/gsd-rr.c (+2622/-0)
gnome-settings-daemon/gsd-rr.h (+222/-0)
plugins/color/Makefile.am (+1/-0)
plugins/color/gcm-edid.c (+4/-4)
plugins/color/gsd-color-manager.c (+81/-83)
plugins/cursor/Makefile.am (+2/-0)
plugins/cursor/gsd-cursor-manager.c (+10/-12)
plugins/orientation/gsd-orientation-manager.c (+8/-10)
plugins/power/Makefile.am (+2/-0)
plugins/power/gpm-common.c (+59/-61)
plugins/power/gpm-common.h (+12/-10)
plugins/power/gsd-power-manager.c (+39/-41)
plugins/power/gsdpowerenums.py (+0/-9)
plugins/wacom/Makefile.am (+4/-0)
plugins/wacom/gsd-wacom-device.c (+67/-68)
plugins/wacom/gsd-wacom-manager.c (+6/-7)
plugins/xrandr/Makefile.am (+1/-0)
plugins/xrandr/gsd-xrandr-manager.c (+270/-273)
To merge this branch: bzr merge lp:~robert-ancell/unity-settings-daemon/xrandr
Reviewer Review Type Date Requested Status
Iain Lane Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+224548@code.launchpad.net

Commit message

Move libgnome-desktop RandR code into u-s-d since newer versions remove this unstable API

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
4047. By Robert Ancell

Build-dep on libgl1-mesa-dev

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Tim Lunn (darkxst) wrote :

You also need to copy the idle monitor code across to u-s-d, since while the api for idle monitor still exists within gnome-desktop it is just using dbus calls into mutter where the actual code lives (since 3.10)

https://git.gnome.org/browse/gnome-desktop/commit/?id=545c774e967fa2f21f9b8ee1acbb50bffcee01d0

Revision history for this message
Sebastien Bacher (seb128) wrote :

Just adding up for discussion, Tim commented on IRC as well saying that he thinks it would less work to just take the new gnome-desktop (there are pending merge requests to port u-s-d/u-c-c to the new api) and ship the upstream code as a standalone service (he worked on that before trusty and that seems to be working). That's something we might consider trying

Revision history for this message
Robert Ancell (robert-ancell) wrote :

It's certainly an option. I feel the daemon is going to be some cost for little benefit because we're only really interested in the X case for u-s-d/u-c-c. For the Mir case it seems likely that u-s-d/u-c-c wouldn't exist. So why not talk to X directly?

Also discussed was forking libgnome-desktop into a special lib for u-s-d/u-c-c. That would reduce the duplication and keep the behaviour the same.

Revision history for this message
Robert Ancell (robert-ancell) wrote :

Laney expressed an interest in continuing the daemon method from bug 1228765. I'm OK with that if he wants to do the work. We can leave these MPs open until we decide if that method is worth completing.

Revision history for this message
Robert Ancell (robert-ancell) wrote :

> You also need to copy the idle monitor code across to u-s-d

Sure, though that can be a separate MP

Revision history for this message
Robert Ancell (robert-ancell) wrote :
Revision history for this message
Robert Ancell (robert-ancell) wrote :
Revision history for this message
Robert Ancell (robert-ancell) wrote :

The decision was made to continue with this method - please review.

Revision history for this message
Sebastien Bacher (seb128) wrote :

That's quite some changes to review, but mostly a copy of existing code, not I don't think it needs a detailled code review. The changes look fine to me on principle but we should give that a proper round of testing, including multimonitor setups and screensaver/idle usecases

Revision history for this message
Tim Lunn (darkxst) wrote :

This lgtm, lots of cut+paste and a bit of renaming, don't think it will cause any issues

Revision history for this message
Iain Lane (laney) wrote :

I just tried this, and there's some bugs

I don't get the right theme in gtk2 apps or context menus apps (get Raleigh instead). u-s-d.log says:

  ** (unity-settings-daemon:9923): WARNING **: You can only run one xsettings manager at a time; exiting

  ** (unity-settings-daemon:9923): WARNING **: Unable to start gnome_xsettings manager: Could not initialize xsettings manager.

  (unity-settings-daemon:9923): GLib-GObject-WARNING **: cannot register existing type 'GsdIdleMonitor'

  (unity-settings-daemon:9923): GLib-GObject-CRITICAL **: g_type_add_interface_static: assertion 'G_TYPE_IS_INSTANTIATABLE (instance_type)' failed

  (unity-settings-daemon:9923): GLib-CRITICAL **: g_once_init_leave: assertion 'result != 0' failed

When trying to apply a change to the display configuration I get

  GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such interface 'org.gnome.SettingsDaemon.XRANDR_2' on object at path /org/gnome/SettingsDaemon/XRANDR

in a dialog.

review: Needs Fixing
Revision history for this message
Iain Lane (laney) wrote :

xsettings> I don't know why, but there's now a lightdm-owned u-s-d running on my system after I log in. Killing that manually gets rid of this one. Still don't get media keys or a theme though.

GsdIdleMonitor> Seems to be a bug, not sure what's wrong right now but you can see where it's happening with G_DEBUG=fatal-warnings.

Also we need <https://code.launchpad.net/~darkxst/unity-settings-daemon/xkb/+merge/224919> after building with new gnome-desktop.

Revision history for this message
Robert Ancell (robert-ancell) wrote :

This doesn't work because the four plugins all have copies of the GsdRRConfig class (and others) and try and register it multiple times. If the code is to be shared it needs to go into a shared library or have multiple copies with different names (seems impractical here).

4048. By Robert Ancell

Move RR code into a shared library so multiple modules don't define the same classes. Also add the Idle monitor

4049. By Robert Ancell

Package libunity-settings-daemon

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4050. By Robert Ancell

Add symbols file

Revision history for this message
Robert Ancell (robert-ancell) wrote :

I've updated this branch to now use a shared library that is also used by unity-control-center (https://code.launchpad.net/~robert-ancell/unity-control-center/libusd/+merge/232676).

This solution works better because it means that multiple modules can use the functionality without duplicating symbols. This is also more similar to us bringing libgnome-desktop into u-s-d - we can continue to copy over parts that libgnome-desktop changes in the future.

4051. By Robert Ancell

Merge with trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4052. By Robert Ancell

Move libunity-settings-daemon into its own package so we can build unity-control-center without installing unity-settings-daemon

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Iain Lane (laney) wrote :

I didn't have problems with the latest branches, thanks for the work

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2014-02-15 08:33:21 +0000
3+++ configure.ac 2014-08-29 10:24:26 +0000
4@@ -55,6 +55,8 @@
5 UPOWER_REQUIRED_VERSION=0.9.11
6 IBUS_REQUIRED_VERSION=1.4.99
7 GSETTINGS_DESKTOP_SCHEMAS_REQUIRED_VERSION=3.7.2.1
8+XRANDR_REQUIRED_VERSION=1.3
9+XEXT_REQUIRED_VERSION=1.1
10
11 EXTRA_COMPILE_WARNINGS(yes)
12
13@@ -140,6 +142,13 @@
14 PKG_CHECK_MODULES(COMMON, x11 kbproto xi)
15
16 dnl ---------------------------------------------------------------------------
17+dnl - libunity-settings-daemon
18+dnl ---------------------------------------------------------------------------
19+
20+PKG_CHECK_MODULES(LIBUNITY_SETTINGS_DAEMON, gtk+-3.0 >= $GTK_REQUIRED_VERSION xrandr >= $XRANDR_REQUIRED_VERSION xext >= $XEXT_REQUIRED_VERSION)
21+PKG_CHECK_MODULES(CHECK_GL_TEXTURE_SIZE, gl x11)
22+
23+dnl ---------------------------------------------------------------------------
24 dnl - automount
25 dnl ---------------------------------------------------------------------------
26
27@@ -521,6 +530,7 @@
28 data/Makefile
29 data/unity-settings-daemon.pc
30 data/unity-settings-daemon-uninstalled.pc
31+data/libunity-settings-daemon.pc
32 po/Makefile.in
33 man/Makefile
34 tests/Makefile
35
36=== modified file 'data/Makefile.am'
37--- data/Makefile.am 2014-02-06 10:43:50 +0000
38+++ data/Makefile.am 2014-08-29 10:24:26 +0000
39@@ -16,7 +16,7 @@
40 $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@.tmp && mv $@.tmp $@
41
42 pkgconfigdir = $(libdir)/pkgconfig
43-pkgconfig_DATA = unity-settings-daemon.pc
44+pkgconfig_DATA = unity-settings-daemon.pc libunity-settings-daemon.pc
45
46 @INTLTOOL_XML_NOMERGE_RULE@
47
48@@ -25,6 +25,7 @@
49 $(desktop_in_files) \
50 $(gsettings_ENUM_FILES) \
51 unity-settings-daemon.pc.in \
52+ libunity-settings-daemon.pc.in \
53 $(api_DATA) \
54 $(NULL)
55
56
57=== added file 'data/libunity-settings-daemon.pc.in'
58--- data/libunity-settings-daemon.pc.in 1970-01-01 00:00:00 +0000
59+++ data/libunity-settings-daemon.pc.in 2014-08-29 10:24:26 +0000
60@@ -0,0 +1,12 @@
61+prefix=@prefix@
62+exec_prefix=@exec_prefix@
63+libdir=@libdir@
64+includedir=@includedir@
65+libexecdir=@libexecdir@
66+
67+Name: libunity-settings-daemon
68+Description: Helper library for accessing settings
69+Requires: glib-2.0 gdk-3.0
70+Version: @VERSION@
71+Libs: -L${libdir} -lunity-settings-daemon
72+Cflags: -I${includedir}/unity-settings-daemon-@GSD_API_VERSION@
73
74=== modified file 'debian/control'
75--- debian/control 2014-02-26 18:25:15 +0000
76+++ debian/control 2014-08-29 10:24:26 +0000
77@@ -40,7 +40,8 @@
78 libgnomekbd-dev (>= 3.5.1),
79 libxklavier-dev,
80 libsystemd-login-dev (>= 183),
81- libibus-1.0-dev (>= 1.5.0)
82+ libibus-1.0-dev (>= 1.5.0),
83+ libgl1-mesa-dev,
84 Standards-Version: 3.9.3
85
86 Package: unity-settings-daemon
87@@ -95,3 +96,20 @@
88 Description: Headers for building applications communicating with unity-settings-daemon
89 This package contains header files required to build applications that
90 communicate with the Unity settings daemon over D-Bus.
91+
92+Package: libunity-settings-daemon1
93+Architecture: any
94+Depends: ${shlibs:Depends},
95+ ${misc:Depends},
96+ libglib2.0-dev,
97+ libgtk-3-dev
98+Description: Helper library for accessing settings
99+ This package contains a helper library for unity-control-center
100+
101+Package: libunity-settings-daemon-dev
102+Architecture: any
103+Depends: ${shlibs:Depends},
104+ ${misc:Depends},
105+ libunity-settings-daemon1 (= ${binary:Version})
106+Description: Helper library for accessing settings (development files)
107+ This package contains a headers for using libunity-settings-daemon
108
109=== added file 'debian/libunity-settings-daemon1.install'
110--- debian/libunity-settings-daemon1.install 1970-01-01 00:00:00 +0000
111+++ debian/libunity-settings-daemon1.install 2014-08-29 10:24:26 +0000
112@@ -0,0 +1,1 @@
113+usr/lib/libunity-settings-daemon.so.*
114
115=== added file 'debian/libunity-settings-daemon1.symbols'
116--- debian/libunity-settings-daemon1.symbols 1970-01-01 00:00:00 +0000
117+++ debian/libunity-settings-daemon1.symbols 2014-08-29 10:24:26 +0000
118@@ -0,0 +1,105 @@
119+libunity-settings-daemon.so.1 libunity-settings-daemon1 #MINVER#
120+ gsd_idle_monitor_add_idle_watch@Base 14.04.0
121+ gsd_idle_monitor_add_user_active_watch@Base 14.04.0
122+ gsd_idle_monitor_get_idletime@Base 14.04.0
123+ gsd_idle_monitor_get_type@Base 14.04.0
124+ gsd_idle_monitor_new@Base 14.04.0
125+ gsd_idle_monitor_new_for_device@Base 14.04.0
126+ gsd_idle_monitor_remove_watch@Base 14.04.0
127+ gsd_pnp_ids_get_pnp_id@Base 14.04.0
128+ gsd_pnp_ids_get_type@Base 14.04.0
129+ gsd_pnp_ids_new@Base 14.04.0
130+ gsd_rr_config_applicable@Base 14.04.0
131+ gsd_rr_config_apply_from_filename_with_time@Base 14.04.0
132+ gsd_rr_config_apply_with_time@Base 14.04.0
133+ gsd_rr_config_ensure_primary@Base 14.04.0
134+ gsd_rr_config_equal@Base 14.04.0
135+ gsd_rr_config_get_backup_filename@Base 14.04.0
136+ gsd_rr_config_get_clone@Base 14.04.0
137+ gsd_rr_config_get_intended_filename@Base 14.04.0
138+ gsd_rr_config_get_outputs@Base 14.04.0
139+ gsd_rr_config_get_type@Base 14.04.0
140+ gsd_rr_config_load_current@Base 14.04.0
141+ gsd_rr_config_load_filename@Base 14.04.0
142+ gsd_rr_config_match@Base 14.04.0
143+ gsd_rr_config_new_current@Base 14.04.0
144+ gsd_rr_config_new_stored@Base 14.04.0
145+ gsd_rr_config_sanitize@Base 14.04.0
146+ gsd_rr_config_save@Base 14.04.0
147+ gsd_rr_config_set_clone@Base 14.04.0
148+ gsd_rr_crtc_can_drive_output@Base 14.04.0
149+ gsd_rr_crtc_get_current_mode@Base 14.04.0
150+ gsd_rr_crtc_get_current_rotation@Base 14.04.0
151+ gsd_rr_crtc_get_gamma@Base 14.04.0
152+ gsd_rr_crtc_get_id@Base 14.04.0
153+ gsd_rr_crtc_get_position@Base 14.04.0
154+ gsd_rr_crtc_get_rotations@Base 14.04.0
155+ gsd_rr_crtc_get_type@Base 14.04.0
156+ gsd_rr_crtc_set_config_with_time@Base 14.04.0
157+ gsd_rr_crtc_set_gamma@Base 14.04.0
158+ gsd_rr_crtc_supports_rotation@Base 14.04.0
159+ gsd_rr_error_quark@Base 14.04.0
160+ gsd_rr_mode_get_freq@Base 14.04.0
161+ gsd_rr_mode_get_height@Base 14.04.0
162+ gsd_rr_mode_get_id@Base 14.04.0
163+ gsd_rr_mode_get_type@Base 14.04.0
164+ gsd_rr_mode_get_width@Base 14.04.0
165+ gsd_rr_output_can_clone@Base 14.04.0
166+ gsd_rr_output_get_backlight@Base 14.04.0
167+ gsd_rr_output_get_backlight_max@Base 14.04.0
168+ gsd_rr_output_get_backlight_min@Base 14.04.0
169+ gsd_rr_output_get_connector_type@Base 14.04.0
170+ gsd_rr_output_get_crtc@Base 14.04.0
171+ gsd_rr_output_get_current_mode@Base 14.04.0
172+ gsd_rr_output_get_display_name@Base 14.04.0
173+ gsd_rr_output_get_edid_data@Base 14.04.0
174+ gsd_rr_output_get_height_mm@Base 14.04.0
175+ gsd_rr_output_get_id@Base 14.04.0
176+ gsd_rr_output_get_ids_from_edid@Base 14.04.0
177+ gsd_rr_output_get_is_primary@Base 14.04.0
178+ gsd_rr_output_get_name@Base 14.04.0
179+ gsd_rr_output_get_position@Base 14.04.0
180+ gsd_rr_output_get_preferred_mode@Base 14.04.0
181+ gsd_rr_output_get_type@Base 14.04.0
182+ gsd_rr_output_get_width_mm@Base 14.04.0
183+ gsd_rr_output_info_get_aspect_ratio@Base 14.04.0
184+ gsd_rr_output_info_get_display_name@Base 14.04.0
185+ gsd_rr_output_info_get_geometry@Base 14.04.0
186+ gsd_rr_output_info_get_name@Base 14.04.0
187+ gsd_rr_output_info_get_preferred_height@Base 14.04.0
188+ gsd_rr_output_info_get_preferred_width@Base 14.04.0
189+ gsd_rr_output_info_get_primary@Base 14.04.0
190+ gsd_rr_output_info_get_product@Base 14.04.0
191+ gsd_rr_output_info_get_refresh_rate@Base 14.04.0
192+ gsd_rr_output_info_get_rotation@Base 14.04.0
193+ gsd_rr_output_info_get_serial@Base 14.04.0
194+ gsd_rr_output_info_get_type@Base 14.04.0
195+ gsd_rr_output_info_get_vendor@Base 14.04.0
196+ gsd_rr_output_info_is_active@Base 14.04.0
197+ gsd_rr_output_info_is_connected@Base 14.04.0
198+ gsd_rr_output_info_set_active@Base 14.04.0
199+ gsd_rr_output_info_set_geometry@Base 14.04.0
200+ gsd_rr_output_info_set_primary@Base 14.04.0
201+ gsd_rr_output_info_set_refresh_rate@Base 14.04.0
202+ gsd_rr_output_info_set_rotation@Base 14.04.0
203+ gsd_rr_output_is_connected@Base 14.04.0
204+ gsd_rr_output_is_laptop@Base 14.04.0
205+ gsd_rr_output_list_modes@Base 14.04.0
206+ gsd_rr_output_set_backlight@Base 14.04.0
207+ gsd_rr_output_supports_mode@Base 14.04.0
208+ gsd_rr_screen_get_crtc_by_id@Base 14.04.0
209+ gsd_rr_screen_get_dpms_mode@Base 14.04.0
210+ gsd_rr_screen_get_output_by_id@Base 14.04.0
211+ gsd_rr_screen_get_output_by_name@Base 14.04.0
212+ gsd_rr_screen_get_ranges@Base 14.04.0
213+ gsd_rr_screen_get_timestamps@Base 14.04.0
214+ gsd_rr_screen_get_type@Base 14.04.0
215+ gsd_rr_screen_list_clone_modes@Base 14.04.0
216+ gsd_rr_screen_list_crtcs@Base 14.04.0
217+ gsd_rr_screen_list_modes@Base 14.04.0
218+ gsd_rr_screen_list_outputs@Base 14.04.0
219+ gsd_rr_screen_new@Base 14.04.0
220+ gsd_rr_screen_refresh@Base 14.04.0
221+ gsd_rr_screen_set_dpms_mode@Base 14.04.0
222+ gsd_rr_screen_set_primary_output@Base 14.04.0
223+ gsd_rr_screen_set_size@Base 14.04.0
224
225=== modified file 'debian/rules'
226--- debian/rules 2013-12-04 23:55:26 +0000
227+++ debian/rules 2014-08-29 10:24:26 +0000
228@@ -6,7 +6,7 @@
229
230 LDFLAGS += -Wl,-O1 -Wl,-z,defs -Wl,--warn-unresolved-symbols -Wl,--as-needed
231
232-DEB_DH_MAKESHLIBS_ARGS_ALL += --no-act
233+DEB_DH_MAKESHLIBS_ARGS_ALL += -X/usr/lib/unity-settings-daemon-1.0
234 DEB_CONFIGURE_SCRIPT := ./autogen.sh
235 DEB_CONFIGURE_EXTRA_FLAGS = --enable-systemd --disable-packagekit --enable-ibus
236
237
238=== modified file 'debian/unity-settings-daemon-dev.install'
239--- debian/unity-settings-daemon-dev.install 2013-12-04 23:55:26 +0000
240+++ debian/unity-settings-daemon-dev.install 2014-08-29 10:24:26 +0000
241@@ -1,2 +1,3 @@
242 usr/include
243 usr/lib/pkgconfig
244+usr/lib/libunity-settings-daemon.so
245
246=== modified file 'debian/unity-settings-daemon.install'
247--- debian/unity-settings-daemon.install 2014-02-06 10:43:50 +0000
248+++ debian/unity-settings-daemon.install 2014-08-29 10:24:26 +0000
249@@ -5,4 +5,3 @@
250 usr/share/unity-settings-daemon
251 usr/share/polkit-1
252 debian/source_unity-settings-daemon.py /usr/share/apport/package-hooks
253-
254
255=== modified file 'gnome-settings-daemon/Makefile.am'
256--- gnome-settings-daemon/Makefile.am 2013-12-04 23:55:26 +0000
257+++ gnome-settings-daemon/Makefile.am 2014-08-29 10:24:26 +0000
258@@ -5,6 +5,7 @@
259 -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
260 -DLIBEXECDIR=\""$(libexecdir)"\" \
261 -DGNOME_SETTINGS_PLUGINDIR=\""$(plugindir)"\" \
262+ -I$(top_srcdir)/plugins/common/ \
263 $(WARN_CFLAGS) \
264 $(DISABLE_DEPRECATED_CFLAGS) \
265 $(SETTINGS_DAEMON_CFLAGS) \
266@@ -14,6 +15,52 @@
267
268 privlibdir = $(pkglibdir)-$(GSD_API_VERSION)
269
270+lib_LTLIBRARIES = libunity-settings-daemon.la
271+libexec_PROGRAMS = check_gl_texture_size
272+
273+libunity_settings_daemon_la_SOURCES = \
274+ gsd-pnp-ids.c \
275+ gsd-pnp-ids.h \
276+ gsd-rr.c \
277+ gsd-rr.h \
278+ gsd-rr-config.c \
279+ gsd-rr-config.h \
280+ gsd-rr-output-info.c \
281+ gsd-rr-private.h \
282+ display-name.c \
283+ edid-parse.c \
284+ edid.h \
285+ gsd-idle-monitor.c \
286+ gsd-idle-monitor.h
287+
288+libunity_settings_daemon_include_HEADERS = \
289+ gsd-pnp-ids.h \
290+ gsd-rr.h \
291+ gsd-rr-config.h \
292+ gsd-idle-monitor.h
293+
294+libunity_settings_daemon_includedir = $(includedir)/unity-settings-daemon-$(GSD_API_VERSION)/libunity-settings-daemon
295+
296+libunity_settings_daemon_la_CFLAGS = \
297+ -DLIBEXECDIR=\""$(libexecdir)\"" \
298+ -DPNP_IDS=\""$(datadir)/hwdata/pnp.ids"\" \
299+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
300+ $(LIBUNITY_SETTINGS_DAEMON_CFLAGS)
301+
302+libunity_settings_daemon_la_LIBADD = \
303+ -lm \
304+ $(LIBUNITY_SETTINGS_DAEMON_LIBS)
305+
306+libunity_settings_daemon_la_LDFLAGS = \
307+ -version-info 1:0:0 \
308+ -export-symbols-regex \^gsd_.*
309+
310+check_gl_texture_size_CPPFLAGS = \
311+ $(CHECK_GL_TEXTURE_SIZE_CFLAGS)
312+
313+check_gl_texture_size_LDADD = \
314+ $(CHECK_GL_TEXTURE_SIZE_LIBS)
315+
316 privlib_LTLIBRARIES = \
317 libgsd.la \
318 $(NULL)
319@@ -84,6 +131,7 @@
320
321 unity_settings_daemon_LDADD = \
322 libgsd.la \
323+ libunity-settings-daemon.la \
324 $(SETTINGS_DAEMON_LIBS) \
325 $(LIBNOTIFY_LIBS) \
326 $(GNOME_DESKTOP_LIBS) \
327
328=== added file 'gnome-settings-daemon/check_gl_texture_size.c'
329--- gnome-settings-daemon/check_gl_texture_size.c 1970-01-01 00:00:00 +0000
330+++ gnome-settings-daemon/check_gl_texture_size.c 2014-08-29 10:24:26 +0000
331@@ -0,0 +1,86 @@
332+#include <stdio.h>
333+#include <stdlib.h>
334+
335+#include <unistd.h>
336+
337+#include <X11/Xlib.h>
338+#include <GL/gl.h>
339+#include <GL/glx.h>
340+
341+int main (int argc, char **argv)
342+{
343+ Display *dpy = XOpenDisplay (NULL);
344+
345+ Window win;
346+ int attribSingle[] = {
347+ GLX_RGBA,
348+ GLX_RED_SIZE, 1,
349+ GLX_GREEN_SIZE, 1,
350+ GLX_BLUE_SIZE, 1,
351+ None };
352+
353+ int attribDouble[] = {
354+ GLX_RGBA,
355+ GLX_RED_SIZE, 1,
356+ GLX_GREEN_SIZE, 1,
357+ GLX_BLUE_SIZE, 1,
358+ GLX_DOUBLEBUFFER,
359+ None };
360+
361+ XSetWindowAttributes attr;
362+ unsigned long mask;
363+ GLXContext ctx = NULL;
364+ XVisualInfo *visinfo;
365+
366+ int exit_status = EXIT_SUCCESS;
367+
368+ GLint max_texture_size = 0;
369+
370+ if (!dpy) {
371+ /* We have, for some reason, been unable to connect to X
372+ * Bail cleanly, and leave a little note */
373+ fprintf (stderr, "check_gl_texture_size: Unable to open display %s", getenv("DISPLAY"));
374+ exit (EXIT_FAILURE);
375+ }
376+
377+ visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), attribSingle);
378+ if (!visinfo)
379+ visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), attribDouble);
380+
381+ if (visinfo)
382+ ctx = glXCreateContext (dpy, visinfo, NULL, GL_TRUE);
383+
384+ if (!visinfo) {
385+ exit_status = EXIT_FAILURE;
386+ goto child_out;
387+ }
388+
389+ if (!ctx) {
390+ XFree (visinfo);
391+ exit_status = EXIT_FAILURE;
392+ goto child_out;
393+ }
394+
395+ attr.background_pixel = 0;
396+ attr.border_pixel = 0;
397+ attr.colormap = XCreateColormap (dpy, DefaultRootWindow (dpy),
398+ visinfo->visual, AllocNone);
399+ attr.event_mask = StructureNotifyMask | ExposureMask;
400+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
401+ win = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0, 100, 100,
402+ 0, visinfo->depth, InputOutput,
403+ visinfo->visual, mask, &attr);
404+
405+ if (!glXMakeCurrent (dpy, win, ctx)) {
406+ exit_status = EXIT_FAILURE;
407+ goto child_out;
408+ }
409+
410+ glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_texture_size);
411+
412+ printf ("%u", max_texture_size);
413+
414+child_out:
415+ XCloseDisplay (dpy);
416+ exit (exit_status);
417+}
418
419=== added file 'gnome-settings-daemon/display-name.c'
420--- gnome-settings-daemon/display-name.c 1970-01-01 00:00:00 +0000
421+++ gnome-settings-daemon/display-name.c 2014-08-29 10:24:26 +0000
422@@ -0,0 +1,144 @@
423+/*
424+ * Copyright 2007 Red Hat, Inc.
425+ *
426+ * Permission is hereby granted, free of charge, to any person obtaining a
427+ * copy of this software and associated documentation files (the "Software"),
428+ * to deal in the Software without restriction, including without limitation
429+ * on the rights to use, copy, modify, merge, publish, distribute, sub
430+ * license, and/or sell copies of the Software, and to permit persons to whom
431+ * the Software is furnished to do so, subject to the following conditions:
432+ *
433+ * The above copyright notice and this permission notice (including the next
434+ * paragraph) shall be included in all copies or substantial portions of the
435+ * Software.
436+ *
437+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
438+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
439+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
440+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
441+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
442+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
443+ */
444+
445+/* Author: Soren Sandmann <sandmann@redhat.com> */
446+
447+#include <config.h>
448+#include <glib/gi18n-lib.h>
449+#include <stdlib.h>
450+#include <math.h>
451+#include <stdio.h>
452+#include <string.h>
453+#include <glib.h>
454+
455+#include "gsd-pnp-ids.h"
456+#include "edid.h"
457+
458+static const char *
459+find_vendor (const char *code)
460+{
461+ const char *vendor_name;
462+ GsdPnpIds *pnp_ids;
463+
464+ pnp_ids = gsd_pnp_ids_new ();
465+ vendor_name = gsd_pnp_ids_get_pnp_id (pnp_ids, code);
466+ g_object_unref (pnp_ids);
467+
468+ if (vendor_name)
469+ return vendor_name;
470+
471+ return code;
472+}
473+
474+static const double known_diagonals[] = {
475+ 12.1,
476+ 13.3,
477+ 15.6
478+};
479+
480+static char *
481+diagonal_to_str (double d)
482+{
483+ int i;
484+
485+ for (i = 0; i < G_N_ELEMENTS (known_diagonals); i++)
486+ {
487+ double delta;
488+
489+ delta = fabs(known_diagonals[i] - d);
490+ if (delta < 0.1)
491+ return g_strdup_printf ("%0.1lf\"", known_diagonals[i]);
492+ }
493+
494+ return g_strdup_printf ("%d\"", (int) (d + 0.5));
495+}
496+
497+char *
498+make_display_size_string (int width_mm,
499+ int height_mm)
500+{
501+ char *inches = NULL;
502+
503+ if (width_mm > 0 && height_mm > 0)
504+ {
505+ double d = sqrt (width_mm * width_mm + height_mm * height_mm);
506+
507+ inches = diagonal_to_str (d / 25.4);
508+ }
509+
510+ return inches;
511+}
512+
513+char *
514+make_display_name (const MonitorInfo *info)
515+{
516+ const char *vendor;
517+ int width_mm, height_mm;
518+ char *inches, *ret;
519+
520+ if (info)
521+ {
522+ vendor = find_vendor (info->manufacturer_code);
523+ }
524+ else
525+ {
526+ /* Translators: "Unknown" here is used to identify a monitor for which
527+ * we don't know the vendor. When a vendor is known, the name of the
528+ * vendor is used. */
529+ vendor = C_("Monitor vendor", "Unknown");
530+ }
531+
532+ if (info && info->width_mm != -1 && info->height_mm)
533+ {
534+ width_mm = info->width_mm;
535+ height_mm = info->height_mm;
536+ }
537+ else if (info && info->n_detailed_timings)
538+ {
539+ width_mm = info->detailed_timings[0].width_mm;
540+ height_mm = info->detailed_timings[0].height_mm;
541+ }
542+ else
543+ {
544+ width_mm = -1;
545+ height_mm = -1;
546+ }
547+
548+ if (width_mm != -1 && height_mm != -1)
549+ {
550+ double d = sqrt (width_mm * width_mm + height_mm * height_mm);
551+
552+ inches = diagonal_to_str (d / 25.4);
553+ }
554+ else
555+ {
556+ inches = NULL;
557+ }
558+
559+ if (!inches)
560+ return g_strdup (vendor);
561+
562+ ret = g_strdup_printf ("%s %s", vendor, inches);
563+ g_free (inches);
564+
565+ return ret;
566+}
567
568=== added file 'gnome-settings-daemon/edid-parse.c'
569--- gnome-settings-daemon/edid-parse.c 1970-01-01 00:00:00 +0000
570+++ gnome-settings-daemon/edid-parse.c 2014-08-29 10:24:26 +0000
571@@ -0,0 +1,540 @@
572+/*
573+ * Copyright 2007 Red Hat, Inc.
574+ *
575+ * Permission is hereby granted, free of charge, to any person obtaining a
576+ * copy of this software and associated documentation files (the "Software"),
577+ * to deal in the Software without restriction, including without limitation
578+ * on the rights to use, copy, modify, merge, publish, distribute, sub
579+ * license, and/or sell copies of the Software, and to permit persons to whom
580+ * the Software is furnished to do so, subject to the following conditions:
581+ *
582+ * The above copyright notice and this permission notice (including the next
583+ * paragraph) shall be included in all copies or substantial portions of the
584+ * Software.
585+ *
586+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
587+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
588+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
589+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
590+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
591+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
592+ */
593+
594+/* Author: Soren Sandmann <sandmann@redhat.com> */
595+
596+#include "edid.h"
597+#include <stdlib.h>
598+#include <string.h>
599+#include <math.h>
600+#include <glib.h>
601+
602+static int
603+get_bit (int in, int bit)
604+{
605+ return (in & (1 << bit)) >> bit;
606+}
607+
608+static int
609+get_bits (int in, int begin, int end)
610+{
611+ int mask = (1 << (end - begin + 1)) - 1;
612+
613+ return (in >> begin) & mask;
614+}
615+
616+static int
617+decode_header (const uchar *edid)
618+{
619+ if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0)
620+ return TRUE;
621+ return FALSE;
622+}
623+
624+static int
625+decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info)
626+{
627+ int is_model_year;
628+
629+ /* Manufacturer Code */
630+ info->manufacturer_code[0] = get_bits (edid[0x08], 2, 6);
631+ info->manufacturer_code[1] = get_bits (edid[0x08], 0, 1) << 3;
632+ info->manufacturer_code[1] |= get_bits (edid[0x09], 5, 7);
633+ info->manufacturer_code[2] = get_bits (edid[0x09], 0, 4);
634+ info->manufacturer_code[3] = '\0';
635+
636+ info->manufacturer_code[0] += 'A' - 1;
637+ info->manufacturer_code[1] += 'A' - 1;
638+ info->manufacturer_code[2] += 'A' - 1;
639+
640+ /* Product Code */
641+ info->product_code = edid[0x0b] << 8 | edid[0x0a];
642+
643+ /* Serial Number */
644+ info->serial_number =
645+ edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24;
646+
647+ /* Week and Year */
648+ is_model_year = FALSE;
649+ switch (edid[0x10])
650+ {
651+ case 0x00:
652+ info->production_week = -1;
653+ break;
654+
655+ case 0xff:
656+ info->production_week = -1;
657+ is_model_year = TRUE;
658+ break;
659+
660+ default:
661+ info->production_week = edid[0x10];
662+ break;
663+ }
664+
665+ if (is_model_year)
666+ {
667+ info->production_year = -1;
668+ info->model_year = 1990 + edid[0x11];
669+ }
670+ else
671+ {
672+ info->production_year = 1990 + edid[0x11];
673+ info->model_year = -1;
674+ }
675+
676+ return TRUE;
677+}
678+
679+static int
680+decode_edid_version (const uchar *edid, MonitorInfo *info)
681+{
682+ info->major_version = edid[0x12];
683+ info->minor_version = edid[0x13];
684+
685+ return TRUE;
686+}
687+
688+static int
689+decode_display_parameters (const uchar *edid, MonitorInfo *info)
690+{
691+ /* Digital vs Analog */
692+ info->is_digital = get_bit (edid[0x14], 7);
693+
694+ if (info->is_digital)
695+ {
696+ int bits;
697+
698+ static const int bit_depth[8] =
699+ {
700+ -1, 6, 8, 10, 12, 14, 16, -1
701+ };
702+
703+ static const Interface interfaces[6] =
704+ {
705+ UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT
706+ };
707+
708+ bits = get_bits (edid[0x14], 4, 6);
709+ info->connector.digital.bits_per_primary = bit_depth[bits];
710+
711+ bits = get_bits (edid[0x14], 0, 3);
712+
713+ if (bits <= 5)
714+ info->connector.digital.interface = interfaces[bits];
715+ else
716+ info->connector.digital.interface = UNDEFINED;
717+ }
718+ else
719+ {
720+ int bits = get_bits (edid[0x14], 5, 6);
721+
722+ static const double levels[][3] =
723+ {
724+ { 0.7, 0.3, 1.0 },
725+ { 0.714, 0.286, 1.0 },
726+ { 1.0, 0.4, 1.4 },
727+ { 0.7, 0.0, 0.7 },
728+ };
729+
730+ info->connector.analog.video_signal_level = levels[bits][0];
731+ info->connector.analog.sync_signal_level = levels[bits][1];
732+ info->connector.analog.total_signal_level = levels[bits][2];
733+
734+ info->connector.analog.blank_to_black = get_bit (edid[0x14], 4);
735+
736+ info->connector.analog.separate_hv_sync = get_bit (edid[0x14], 3);
737+ info->connector.analog.composite_sync_on_h = get_bit (edid[0x14], 2);
738+ info->connector.analog.composite_sync_on_green = get_bit (edid[0x14], 1);
739+
740+ info->connector.analog.serration_on_vsync = get_bit (edid[0x14], 0);
741+ }
742+
743+ /* Screen Size / Aspect Ratio */
744+ if (edid[0x15] == 0 && edid[0x16] == 0)
745+ {
746+ info->width_mm = -1;
747+ info->height_mm = -1;
748+ info->aspect_ratio = -1.0;
749+ }
750+ else if (edid[0x16] == 0)
751+ {
752+ info->width_mm = -1;
753+ info->height_mm = -1;
754+ info->aspect_ratio = 100.0 / (edid[0x15] + 99);
755+ }
756+ else if (edid[0x15] == 0)
757+ {
758+ info->width_mm = -1;
759+ info->height_mm = -1;
760+ info->aspect_ratio = 100.0 / (edid[0x16] + 99);
761+ info->aspect_ratio = 1/info->aspect_ratio; /* portrait */
762+ }
763+ else
764+ {
765+ info->width_mm = 10 * edid[0x15];
766+ info->height_mm = 10 * edid[0x16];
767+ }
768+
769+ /* Gamma */
770+ if (edid[0x17] == 0xFF)
771+ info->gamma = -1.0;
772+ else
773+ info->gamma = (edid[0x17] + 100.0) / 100.0;
774+
775+ /* Features */
776+ info->standby = get_bit (edid[0x18], 7);
777+ info->suspend = get_bit (edid[0x18], 6);
778+ info->active_off = get_bit (edid[0x18], 5);
779+
780+ if (info->is_digital)
781+ {
782+ info->connector.digital.rgb444 = TRUE;
783+ if (get_bit (edid[0x18], 3))
784+ info->connector.digital.ycrcb444 = 1;
785+ if (get_bit (edid[0x18], 4))
786+ info->connector.digital.ycrcb422 = 1;
787+ }
788+ else
789+ {
790+ int bits = get_bits (edid[0x18], 3, 4);
791+ ColorType color_type[4] =
792+ {
793+ MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR
794+ };
795+
796+ info->connector.analog.color_type = color_type[bits];
797+ }
798+
799+ info->srgb_is_standard = get_bit (edid[0x18], 2);
800+
801+ /* In 1.3 this is called "has preferred timing" */
802+ info->preferred_timing_includes_native = get_bit (edid[0x18], 1);
803+
804+ /* FIXME: In 1.3 this indicates whether the monitor accepts GTF */
805+ info->continuous_frequency = get_bit (edid[0x18], 0);
806+ return TRUE;
807+}
808+
809+static double
810+decode_fraction (int high, int low)
811+{
812+ double result = 0.0;
813+ int i;
814+
815+ high = (high << 2) | low;
816+
817+ for (i = 0; i < 10; ++i)
818+ result += get_bit (high, i) * pow (2, i - 10);
819+
820+ return result;
821+}
822+
823+static int
824+decode_color_characteristics (const uchar *edid, MonitorInfo *info)
825+{
826+ info->red_x = decode_fraction (edid[0x1b], get_bits (edid[0x19], 6, 7));
827+ info->red_y = decode_fraction (edid[0x1c], get_bits (edid[0x19], 5, 4));
828+ info->green_x = decode_fraction (edid[0x1d], get_bits (edid[0x19], 2, 3));
829+ info->green_y = decode_fraction (edid[0x1e], get_bits (edid[0x19], 0, 1));
830+ info->blue_x = decode_fraction (edid[0x1f], get_bits (edid[0x1a], 6, 7));
831+ info->blue_y = decode_fraction (edid[0x20], get_bits (edid[0x1a], 4, 5));
832+ info->white_x = decode_fraction (edid[0x21], get_bits (edid[0x1a], 2, 3));
833+ info->white_y = decode_fraction (edid[0x22], get_bits (edid[0x1a], 0, 1));
834+
835+ return TRUE;
836+}
837+
838+static int
839+decode_established_timings (const uchar *edid, MonitorInfo *info)
840+{
841+ static const Timing established[][8] =
842+ {
843+ {
844+ { 800, 600, 60 },
845+ { 800, 600, 56 },
846+ { 640, 480, 75 },
847+ { 640, 480, 72 },
848+ { 640, 480, 67 },
849+ { 640, 480, 60 },
850+ { 720, 400, 88 },
851+ { 720, 400, 70 }
852+ },
853+ {
854+ { 1280, 1024, 75 },
855+ { 1024, 768, 75 },
856+ { 1024, 768, 70 },
857+ { 1024, 768, 60 },
858+ { 1024, 768, 87 },
859+ { 832, 624, 75 },
860+ { 800, 600, 75 },
861+ { 800, 600, 72 }
862+ },
863+ {
864+ { 0, 0, 0 },
865+ { 0, 0, 0 },
866+ { 0, 0, 0 },
867+ { 0, 0, 0 },
868+ { 0, 0, 0 },
869+ { 0, 0, 0 },
870+ { 0, 0, 0 },
871+ { 1152, 870, 75 }
872+ },
873+ };
874+
875+ int i, j, idx;
876+
877+ idx = 0;
878+ for (i = 0; i < 3; ++i)
879+ {
880+ for (j = 0; j < 8; ++j)
881+ {
882+ int byte = edid[0x23 + i];
883+
884+ if (get_bit (byte, j) && established[i][j].frequency != 0)
885+ info->established[idx++] = established[i][j];
886+ }
887+ }
888+ return TRUE;
889+}
890+
891+static int
892+decode_standard_timings (const uchar *edid, MonitorInfo *info)
893+{
894+ int i;
895+
896+ for (i = 0; i < 8; i++)
897+ {
898+ int first = edid[0x26 + 2 * i];
899+ int second = edid[0x27 + 2 * i];
900+
901+ if (first != 0x01 && second != 0x01)
902+ {
903+ int w = 8 * (first + 31);
904+ int h = 0;
905+
906+ switch (get_bits (second, 6, 7))
907+ {
908+ case 0x00: h = (w / 16) * 10; break;
909+ case 0x01: h = (w / 4) * 3; break;
910+ case 0x02: h = (w / 5) * 4; break;
911+ case 0x03: h = (w / 16) * 9; break;
912+ }
913+
914+ info->standard[i].width = w;
915+ info->standard[i].height = h;
916+ info->standard[i].frequency = get_bits (second, 0, 5) + 60;
917+ }
918+ }
919+
920+ return TRUE;
921+}
922+
923+static void
924+decode_lf_string (const uchar *s, int n_chars, char *result)
925+{
926+ int i;
927+ for (i = 0; i < n_chars; ++i)
928+ {
929+ if (s[i] == 0x0a)
930+ {
931+ *result++ = '\0';
932+ break;
933+ }
934+ else if (s[i] == 0x00)
935+ {
936+ /* Convert embedded 0's to spaces */
937+ *result++ = ' ';
938+ }
939+ else
940+ {
941+ *result++ = s[i];
942+ }
943+ }
944+}
945+
946+static void
947+decode_display_descriptor (const uchar *desc,
948+ MonitorInfo *info)
949+{
950+ switch (desc[0x03])
951+ {
952+ case 0xFC:
953+ decode_lf_string (desc + 5, 13, info->dsc_product_name);
954+ break;
955+ case 0xFF:
956+ decode_lf_string (desc + 5, 13, info->dsc_serial_number);
957+ break;
958+ case 0xFE:
959+ decode_lf_string (desc + 5, 13, info->dsc_string);
960+ break;
961+ case 0xFD:
962+ /* Range Limits */
963+ break;
964+ case 0xFB:
965+ /* Color Point */
966+ break;
967+ case 0xFA:
968+ /* Timing Identifications */
969+ break;
970+ case 0xF9:
971+ /* Color Management */
972+ break;
973+ case 0xF8:
974+ /* Timing Codes */
975+ break;
976+ case 0xF7:
977+ /* Established Timings */
978+ break;
979+ case 0x10:
980+ break;
981+ }
982+}
983+
984+static void
985+decode_detailed_timing (const uchar *timing,
986+ DetailedTiming *detailed)
987+{
988+ int bits;
989+ StereoType stereo[] =
990+ {
991+ NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT,
992+ TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN,
993+ FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE
994+ };
995+
996+ detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000;
997+ detailed->h_addr = timing[0x02] | ((timing[0x04] & 0xf0) << 4);
998+ detailed->h_blank = timing[0x03] | ((timing[0x04] & 0x0f) << 8);
999+ detailed->v_addr = timing[0x05] | ((timing[0x07] & 0xf0) << 4);
1000+ detailed->v_blank = timing[0x06] | ((timing[0x07] & 0x0f) << 8);
1001+ detailed->h_front_porch = timing[0x08] | get_bits (timing[0x0b], 6, 7) << 8;
1002+ detailed->h_sync = timing[0x09] | get_bits (timing[0x0b], 4, 5) << 8;
1003+ detailed->v_front_porch =
1004+ get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4;
1005+ detailed->v_sync =
1006+ get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4;
1007+ detailed->width_mm = timing[0x0c] | get_bits (timing[0x0e], 4, 7) << 8;
1008+ detailed->height_mm = timing[0x0d] | get_bits (timing[0x0e], 0, 3) << 8;
1009+ detailed->right_border = timing[0x0f];
1010+ detailed->top_border = timing[0x10];
1011+
1012+ detailed->interlaced = get_bit (timing[0x11], 7);
1013+
1014+ /* Stereo */
1015+ bits = get_bits (timing[0x11], 5, 6) << 1 | get_bit (timing[0x11], 0);
1016+ detailed->stereo = stereo[bits];
1017+
1018+ /* Sync */
1019+ bits = timing[0x11];
1020+
1021+ detailed->digital_sync = get_bit (bits, 4);
1022+ if (detailed->digital_sync)
1023+ {
1024+ detailed->connector.digital.composite = !get_bit (bits, 3);
1025+
1026+ if (detailed->connector.digital.composite)
1027+ {
1028+ detailed->connector.digital.serrations = get_bit (bits, 2);
1029+ detailed->connector.digital.negative_vsync = FALSE;
1030+ }
1031+ else
1032+ {
1033+ detailed->connector.digital.serrations = FALSE;
1034+ detailed->connector.digital.negative_vsync = !get_bit (bits, 2);
1035+ }
1036+
1037+ detailed->connector.digital.negative_hsync = !get_bit (bits, 0);
1038+ }
1039+ else
1040+ {
1041+ detailed->connector.analog.bipolar = get_bit (bits, 3);
1042+ detailed->connector.analog.serrations = get_bit (bits, 2);
1043+ detailed->connector.analog.sync_on_green = !get_bit (bits, 1);
1044+ }
1045+}
1046+
1047+static int
1048+decode_descriptors (const uchar *edid, MonitorInfo *info)
1049+{
1050+ int i;
1051+ int timing_idx;
1052+
1053+ timing_idx = 0;
1054+
1055+ for (i = 0; i < 4; ++i)
1056+ {
1057+ int index = 0x36 + i * 18;
1058+
1059+ if (edid[index + 0] == 0x00 && edid[index + 1] == 0x00)
1060+ {
1061+ decode_display_descriptor (edid + index, info);
1062+ }
1063+ else
1064+ {
1065+ decode_detailed_timing (
1066+ edid + index, &(info->detailed_timings[timing_idx++]));
1067+ }
1068+ }
1069+
1070+ info->n_detailed_timings = timing_idx;
1071+
1072+ return TRUE;
1073+}
1074+
1075+static void
1076+decode_check_sum (const uchar *edid,
1077+ MonitorInfo *info)
1078+{
1079+ int i;
1080+ uchar check = 0;
1081+
1082+ for (i = 0; i < 128; ++i)
1083+ check += edid[i];
1084+
1085+ info->checksum = check;
1086+}
1087+
1088+MonitorInfo *
1089+decode_edid (const uchar *edid)
1090+{
1091+ MonitorInfo *info = g_new0 (MonitorInfo, 1);
1092+
1093+ decode_check_sum (edid, info);
1094+
1095+ if (decode_header (edid)
1096+ && decode_vendor_and_product_identification (edid, info)
1097+ && decode_edid_version (edid, info)
1098+ && decode_display_parameters (edid, info)
1099+ && decode_color_characteristics (edid, info)
1100+ && decode_established_timings (edid, info)
1101+ && decode_standard_timings (edid, info)
1102+ && decode_descriptors (edid, info))
1103+ {
1104+ return info;
1105+ }
1106+ else
1107+ {
1108+ g_free (info);
1109+ return NULL;
1110+ }
1111+}
1112
1113=== added file 'gnome-settings-daemon/edid.h'
1114--- gnome-settings-daemon/edid.h 1970-01-01 00:00:00 +0000
1115+++ gnome-settings-daemon/edid.h 2014-08-29 10:24:26 +0000
1116@@ -0,0 +1,195 @@
1117+/* edid.h
1118+ *
1119+ * Copyright 2007, 2008, Red Hat, Inc.
1120+ *
1121+ * This file is part of the Gnome Library.
1122+ *
1123+ * The Gnome Library is free software; you can redistribute it and/or
1124+ * modify it under the terms of the GNU Library General Public License as
1125+ * published by the Free Software Foundation; either version 2 of the
1126+ * License, or (at your option) any later version.
1127+ *
1128+ * The Gnome Library is distributed in the hope that it will be useful,
1129+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1130+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1131+ * Library General Public License for more details.
1132+ *
1133+ * You should have received a copy of the GNU Library General Public
1134+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
1135+ * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1136+ * Boston, MA 02110-1301, USA.
1137+ *
1138+ * Author: Soren Sandmann <sandmann@redhat.com>
1139+ */
1140+
1141+#ifndef EDID_H
1142+#define EDID_H
1143+
1144+typedef unsigned char uchar;
1145+typedef struct MonitorInfo MonitorInfo;
1146+typedef struct Timing Timing;
1147+typedef struct DetailedTiming DetailedTiming;
1148+
1149+typedef enum
1150+{
1151+ UNDEFINED,
1152+ DVI,
1153+ HDMI_A,
1154+ HDMI_B,
1155+ MDDI,
1156+ DISPLAY_PORT
1157+} Interface;
1158+
1159+typedef enum
1160+{
1161+ UNDEFINED_COLOR,
1162+ MONOCHROME,
1163+ RGB,
1164+ OTHER_COLOR
1165+} ColorType;
1166+
1167+typedef enum
1168+{
1169+ NO_STEREO,
1170+ FIELD_RIGHT,
1171+ FIELD_LEFT,
1172+ TWO_WAY_RIGHT_ON_EVEN,
1173+ TWO_WAY_LEFT_ON_EVEN,
1174+ FOUR_WAY_INTERLEAVED,
1175+ SIDE_BY_SIDE
1176+} StereoType;
1177+
1178+struct Timing
1179+{
1180+ int width;
1181+ int height;
1182+ int frequency;
1183+};
1184+
1185+struct DetailedTiming
1186+{
1187+ int pixel_clock;
1188+ int h_addr;
1189+ int h_blank;
1190+ int h_sync;
1191+ int h_front_porch;
1192+ int v_addr;
1193+ int v_blank;
1194+ int v_sync;
1195+ int v_front_porch;
1196+ int width_mm;
1197+ int height_mm;
1198+ int right_border;
1199+ int top_border;
1200+ int interlaced;
1201+ StereoType stereo;
1202+
1203+ int digital_sync;
1204+ union
1205+ {
1206+ struct
1207+ {
1208+ int bipolar;
1209+ int serrations;
1210+ int sync_on_green;
1211+ } analog;
1212+
1213+ struct
1214+ {
1215+ int composite;
1216+ int serrations;
1217+ int negative_vsync;
1218+ int negative_hsync;
1219+ } digital;
1220+ } connector;
1221+};
1222+
1223+struct MonitorInfo
1224+{
1225+ int checksum;
1226+ char manufacturer_code[4];
1227+ int product_code;
1228+ unsigned int serial_number;
1229+
1230+ int production_week; /* -1 if not specified */
1231+ int production_year; /* -1 if not specified */
1232+ int model_year; /* -1 if not specified */
1233+
1234+ int major_version;
1235+ int minor_version;
1236+
1237+ int is_digital;
1238+
1239+ union
1240+ {
1241+ struct
1242+ {
1243+ int bits_per_primary;
1244+ Interface interface;
1245+ int rgb444;
1246+ int ycrcb444;
1247+ int ycrcb422;
1248+ } digital;
1249+
1250+ struct
1251+ {
1252+ double video_signal_level;
1253+ double sync_signal_level;
1254+ double total_signal_level;
1255+
1256+ int blank_to_black;
1257+
1258+ int separate_hv_sync;
1259+ int composite_sync_on_h;
1260+ int composite_sync_on_green;
1261+ int serration_on_vsync;
1262+ ColorType color_type;
1263+ } analog;
1264+ } connector;
1265+
1266+ int width_mm; /* -1 if not specified */
1267+ int height_mm; /* -1 if not specified */
1268+ double aspect_ratio; /* -1.0 if not specififed */
1269+
1270+ double gamma; /* -1.0 if not specified */
1271+
1272+ int standby;
1273+ int suspend;
1274+ int active_off;
1275+
1276+ int srgb_is_standard;
1277+ int preferred_timing_includes_native;
1278+ int continuous_frequency;
1279+
1280+ double red_x;
1281+ double red_y;
1282+ double green_x;
1283+ double green_y;
1284+ double blue_x;
1285+ double blue_y;
1286+ double white_x;
1287+ double white_y;
1288+
1289+ Timing established[24]; /* Terminated by 0x0x0 */
1290+ Timing standard[8];
1291+
1292+ int n_detailed_timings;
1293+ DetailedTiming detailed_timings[4]; /* If monitor has a preferred
1294+ * mode, it is the first one
1295+ * (whether it has, is
1296+ * determined by the
1297+ * preferred_timing_includes
1298+ * bit.
1299+ */
1300+
1301+ /* Optional product description */
1302+ char dsc_serial_number[14];
1303+ char dsc_product_name[14];
1304+ char dsc_string[14]; /* Unspecified ASCII data */
1305+};
1306+
1307+MonitorInfo *decode_edid (const uchar *data);
1308+char *make_display_name (const MonitorInfo *info);
1309+char *make_display_size_string (int width_mm, int height_mm);
1310+
1311+#endif
1312
1313=== added file 'gnome-settings-daemon/edid_parse.c'
1314--- gnome-settings-daemon/edid_parse.c 1970-01-01 00:00:00 +0000
1315+++ gnome-settings-daemon/edid_parse.c 2014-08-29 10:24:26 +0000
1316@@ -0,0 +1,540 @@
1317+/*
1318+ * Copyright 2007 Red Hat, Inc.
1319+ *
1320+ * Permission is hereby granted, free of charge, to any person obtaining a
1321+ * copy of this software and associated documentation files (the "Software"),
1322+ * to deal in the Software without restriction, including without limitation
1323+ * on the rights to use, copy, modify, merge, publish, distribute, sub
1324+ * license, and/or sell copies of the Software, and to permit persons to whom
1325+ * the Software is furnished to do so, subject to the following conditions:
1326+ *
1327+ * The above copyright notice and this permission notice (including the next
1328+ * paragraph) shall be included in all copies or substantial portions of the
1329+ * Software.
1330+ *
1331+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1332+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1333+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1334+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
1335+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1336+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1337+ */
1338+
1339+/* Author: Soren Sandmann <sandmann@redhat.com> */
1340+
1341+#include "edid.h"
1342+#include <stdlib.h>
1343+#include <string.h>
1344+#include <math.h>
1345+#include <glib.h>
1346+
1347+static int
1348+get_bit (int in, int bit)
1349+{
1350+ return (in & (1 << bit)) >> bit;
1351+}
1352+
1353+static int
1354+get_bits (int in, int begin, int end)
1355+{
1356+ int mask = (1 << (end - begin + 1)) - 1;
1357+
1358+ return (in >> begin) & mask;
1359+}
1360+
1361+static int
1362+decode_header (const uchar *edid)
1363+{
1364+ if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0)
1365+ return TRUE;
1366+ return FALSE;
1367+}
1368+
1369+static int
1370+decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info)
1371+{
1372+ int is_model_year;
1373+
1374+ /* Manufacturer Code */
1375+ info->manufacturer_code[0] = get_bits (edid[0x08], 2, 6);
1376+ info->manufacturer_code[1] = get_bits (edid[0x08], 0, 1) << 3;
1377+ info->manufacturer_code[1] |= get_bits (edid[0x09], 5, 7);
1378+ info->manufacturer_code[2] = get_bits (edid[0x09], 0, 4);
1379+ info->manufacturer_code[3] = '\0';
1380+
1381+ info->manufacturer_code[0] += 'A' - 1;
1382+ info->manufacturer_code[1] += 'A' - 1;
1383+ info->manufacturer_code[2] += 'A' - 1;
1384+
1385+ /* Product Code */
1386+ info->product_code = edid[0x0b] << 8 | edid[0x0a];
1387+
1388+ /* Serial Number */
1389+ info->serial_number =
1390+ edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24;
1391+
1392+ /* Week and Year */
1393+ is_model_year = FALSE;
1394+ switch (edid[0x10])
1395+ {
1396+ case 0x00:
1397+ info->production_week = -1;
1398+ break;
1399+
1400+ case 0xff:
1401+ info->production_week = -1;
1402+ is_model_year = TRUE;
1403+ break;
1404+
1405+ default:
1406+ info->production_week = edid[0x10];
1407+ break;
1408+ }
1409+
1410+ if (is_model_year)
1411+ {
1412+ info->production_year = -1;
1413+ info->model_year = 1990 + edid[0x11];
1414+ }
1415+ else
1416+ {
1417+ info->production_year = 1990 + edid[0x11];
1418+ info->model_year = -1;
1419+ }
1420+
1421+ return TRUE;
1422+}
1423+
1424+static int
1425+decode_edid_version (const uchar *edid, MonitorInfo *info)
1426+{
1427+ info->major_version = edid[0x12];
1428+ info->minor_version = edid[0x13];
1429+
1430+ return TRUE;
1431+}
1432+
1433+static int
1434+decode_display_parameters (const uchar *edid, MonitorInfo *info)
1435+{
1436+ /* Digital vs Analog */
1437+ info->is_digital = get_bit (edid[0x14], 7);
1438+
1439+ if (info->is_digital)
1440+ {
1441+ int bits;
1442+
1443+ static const int bit_depth[8] =
1444+ {
1445+ -1, 6, 8, 10, 12, 14, 16, -1
1446+ };
1447+
1448+ static const Interface interfaces[6] =
1449+ {
1450+ UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT
1451+ };
1452+
1453+ bits = get_bits (edid[0x14], 4, 6);
1454+ info->connector.digital.bits_per_primary = bit_depth[bits];
1455+
1456+ bits = get_bits (edid[0x14], 0, 3);
1457+
1458+ if (bits <= 5)
1459+ info->connector.digital.interface = interfaces[bits];
1460+ else
1461+ info->connector.digital.interface = UNDEFINED;
1462+ }
1463+ else
1464+ {
1465+ int bits = get_bits (edid[0x14], 5, 6);
1466+
1467+ static const double levels[][3] =
1468+ {
1469+ { 0.7, 0.3, 1.0 },
1470+ { 0.714, 0.286, 1.0 },
1471+ { 1.0, 0.4, 1.4 },
1472+ { 0.7, 0.0, 0.7 },
1473+ };
1474+
1475+ info->connector.analog.video_signal_level = levels[bits][0];
1476+ info->connector.analog.sync_signal_level = levels[bits][1];
1477+ info->connector.analog.total_signal_level = levels[bits][2];
1478+
1479+ info->connector.analog.blank_to_black = get_bit (edid[0x14], 4);
1480+
1481+ info->connector.analog.separate_hv_sync = get_bit (edid[0x14], 3);
1482+ info->connector.analog.composite_sync_on_h = get_bit (edid[0x14], 2);
1483+ info->connector.analog.composite_sync_on_green = get_bit (edid[0x14], 1);
1484+
1485+ info->connector.analog.serration_on_vsync = get_bit (edid[0x14], 0);
1486+ }
1487+
1488+ /* Screen Size / Aspect Ratio */
1489+ if (edid[0x15] == 0 && edid[0x16] == 0)
1490+ {
1491+ info->width_mm = -1;
1492+ info->height_mm = -1;
1493+ info->aspect_ratio = -1.0;
1494+ }
1495+ else if (edid[0x16] == 0)
1496+ {
1497+ info->width_mm = -1;
1498+ info->height_mm = -1;
1499+ info->aspect_ratio = 100.0 / (edid[0x15] + 99);
1500+ }
1501+ else if (edid[0x15] == 0)
1502+ {
1503+ info->width_mm = -1;
1504+ info->height_mm = -1;
1505+ info->aspect_ratio = 100.0 / (edid[0x16] + 99);
1506+ info->aspect_ratio = 1/info->aspect_ratio; /* portrait */
1507+ }
1508+ else
1509+ {
1510+ info->width_mm = 10 * edid[0x15];
1511+ info->height_mm = 10 * edid[0x16];
1512+ }
1513+
1514+ /* Gamma */
1515+ if (edid[0x17] == 0xFF)
1516+ info->gamma = -1.0;
1517+ else
1518+ info->gamma = (edid[0x17] + 100.0) / 100.0;
1519+
1520+ /* Features */
1521+ info->standby = get_bit (edid[0x18], 7);
1522+ info->suspend = get_bit (edid[0x18], 6);
1523+ info->active_off = get_bit (edid[0x18], 5);
1524+
1525+ if (info->is_digital)
1526+ {
1527+ info->connector.digital.rgb444 = TRUE;
1528+ if (get_bit (edid[0x18], 3))
1529+ info->connector.digital.ycrcb444 = 1;
1530+ if (get_bit (edid[0x18], 4))
1531+ info->connector.digital.ycrcb422 = 1;
1532+ }
1533+ else
1534+ {
1535+ int bits = get_bits (edid[0x18], 3, 4);
1536+ ColorType color_type[4] =
1537+ {
1538+ MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR
1539+ };
1540+
1541+ info->connector.analog.color_type = color_type[bits];
1542+ }
1543+
1544+ info->srgb_is_standard = get_bit (edid[0x18], 2);
1545+
1546+ /* In 1.3 this is called "has preferred timing" */
1547+ info->preferred_timing_includes_native = get_bit (edid[0x18], 1);
1548+
1549+ /* FIXME: In 1.3 this indicates whether the monitor accepts GTF */
1550+ info->continuous_frequency = get_bit (edid[0x18], 0);
1551+ return TRUE;
1552+}
1553+
1554+static double
1555+decode_fraction (int high, int low)
1556+{
1557+ double result = 0.0;
1558+ int i;
1559+
1560+ high = (high << 2) | low;
1561+
1562+ for (i = 0; i < 10; ++i)
1563+ result += get_bit (high, i) * pow (2, i - 10);
1564+
1565+ return result;
1566+}
1567+
1568+static int
1569+decode_color_characteristics (const uchar *edid, MonitorInfo *info)
1570+{
1571+ info->red_x = decode_fraction (edid[0x1b], get_bits (edid[0x19], 6, 7));
1572+ info->red_y = decode_fraction (edid[0x1c], get_bits (edid[0x19], 5, 4));
1573+ info->green_x = decode_fraction (edid[0x1d], get_bits (edid[0x19], 2, 3));
1574+ info->green_y = decode_fraction (edid[0x1e], get_bits (edid[0x19], 0, 1));
1575+ info->blue_x = decode_fraction (edid[0x1f], get_bits (edid[0x1a], 6, 7));
1576+ info->blue_y = decode_fraction (edid[0x20], get_bits (edid[0x1a], 4, 5));
1577+ info->white_x = decode_fraction (edid[0x21], get_bits (edid[0x1a], 2, 3));
1578+ info->white_y = decode_fraction (edid[0x22], get_bits (edid[0x1a], 0, 1));
1579+
1580+ return TRUE;
1581+}
1582+
1583+static int
1584+decode_established_timings (const uchar *edid, MonitorInfo *info)
1585+{
1586+ static const Timing established[][8] =
1587+ {
1588+ {
1589+ { 800, 600, 60 },
1590+ { 800, 600, 56 },
1591+ { 640, 480, 75 },
1592+ { 640, 480, 72 },
1593+ { 640, 480, 67 },
1594+ { 640, 480, 60 },
1595+ { 720, 400, 88 },
1596+ { 720, 400, 70 }
1597+ },
1598+ {
1599+ { 1280, 1024, 75 },
1600+ { 1024, 768, 75 },
1601+ { 1024, 768, 70 },
1602+ { 1024, 768, 60 },
1603+ { 1024, 768, 87 },
1604+ { 832, 624, 75 },
1605+ { 800, 600, 75 },
1606+ { 800, 600, 72 }
1607+ },
1608+ {
1609+ { 0, 0, 0 },
1610+ { 0, 0, 0 },
1611+ { 0, 0, 0 },
1612+ { 0, 0, 0 },
1613+ { 0, 0, 0 },
1614+ { 0, 0, 0 },
1615+ { 0, 0, 0 },
1616+ { 1152, 870, 75 }
1617+ },
1618+ };
1619+
1620+ int i, j, idx;
1621+
1622+ idx = 0;
1623+ for (i = 0; i < 3; ++i)
1624+ {
1625+ for (j = 0; j < 8; ++j)
1626+ {
1627+ int byte = edid[0x23 + i];
1628+
1629+ if (get_bit (byte, j) && established[i][j].frequency != 0)
1630+ info->established[idx++] = established[i][j];
1631+ }
1632+ }
1633+ return TRUE;
1634+}
1635+
1636+static int
1637+decode_standard_timings (const uchar *edid, MonitorInfo *info)
1638+{
1639+ int i;
1640+
1641+ for (i = 0; i < 8; i++)
1642+ {
1643+ int first = edid[0x26 + 2 * i];
1644+ int second = edid[0x27 + 2 * i];
1645+
1646+ if (first != 0x01 && second != 0x01)
1647+ {
1648+ int w = 8 * (first + 31);
1649+ int h = 0;
1650+
1651+ switch (get_bits (second, 6, 7))
1652+ {
1653+ case 0x00: h = (w / 16) * 10; break;
1654+ case 0x01: h = (w / 4) * 3; break;
1655+ case 0x02: h = (w / 5) * 4; break;
1656+ case 0x03: h = (w / 16) * 9; break;
1657+ }
1658+
1659+ info->standard[i].width = w;
1660+ info->standard[i].height = h;
1661+ info->standard[i].frequency = get_bits (second, 0, 5) + 60;
1662+ }
1663+ }
1664+
1665+ return TRUE;
1666+}
1667+
1668+static void
1669+decode_lf_string (const uchar *s, int n_chars, char *result)
1670+{
1671+ int i;
1672+ for (i = 0; i < n_chars; ++i)
1673+ {
1674+ if (s[i] == 0x0a)
1675+ {
1676+ *result++ = '\0';
1677+ break;
1678+ }
1679+ else if (s[i] == 0x00)
1680+ {
1681+ /* Convert embedded 0's to spaces */
1682+ *result++ = ' ';
1683+ }
1684+ else
1685+ {
1686+ *result++ = s[i];
1687+ }
1688+ }
1689+}
1690+
1691+static void
1692+decode_display_descriptor (const uchar *desc,
1693+ MonitorInfo *info)
1694+{
1695+ switch (desc[0x03])
1696+ {
1697+ case 0xFC:
1698+ decode_lf_string (desc + 5, 13, info->dsc_product_name);
1699+ break;
1700+ case 0xFF:
1701+ decode_lf_string (desc + 5, 13, info->dsc_serial_number);
1702+ break;
1703+ case 0xFE:
1704+ decode_lf_string (desc + 5, 13, info->dsc_string);
1705+ break;
1706+ case 0xFD:
1707+ /* Range Limits */
1708+ break;
1709+ case 0xFB:
1710+ /* Color Point */
1711+ break;
1712+ case 0xFA:
1713+ /* Timing Identifications */
1714+ break;
1715+ case 0xF9:
1716+ /* Color Management */
1717+ break;
1718+ case 0xF8:
1719+ /* Timing Codes */
1720+ break;
1721+ case 0xF7:
1722+ /* Established Timings */
1723+ break;
1724+ case 0x10:
1725+ break;
1726+ }
1727+}
1728+
1729+static void
1730+decode_detailed_timing (const uchar *timing,
1731+ DetailedTiming *detailed)
1732+{
1733+ int bits;
1734+ StereoType stereo[] =
1735+ {
1736+ NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT,
1737+ TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN,
1738+ FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE
1739+ };
1740+
1741+ detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000;
1742+ detailed->h_addr = timing[0x02] | ((timing[0x04] & 0xf0) << 4);
1743+ detailed->h_blank = timing[0x03] | ((timing[0x04] & 0x0f) << 8);
1744+ detailed->v_addr = timing[0x05] | ((timing[0x07] & 0xf0) << 4);
1745+ detailed->v_blank = timing[0x06] | ((timing[0x07] & 0x0f) << 8);
1746+ detailed->h_front_porch = timing[0x08] | get_bits (timing[0x0b], 6, 7) << 8;
1747+ detailed->h_sync = timing[0x09] | get_bits (timing[0x0b], 4, 5) << 8;
1748+ detailed->v_front_porch =
1749+ get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4;
1750+ detailed->v_sync =
1751+ get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4;
1752+ detailed->width_mm = timing[0x0c] | get_bits (timing[0x0e], 4, 7) << 8;
1753+ detailed->height_mm = timing[0x0d] | get_bits (timing[0x0e], 0, 3) << 8;
1754+ detailed->right_border = timing[0x0f];
1755+ detailed->top_border = timing[0x10];
1756+
1757+ detailed->interlaced = get_bit (timing[0x11], 7);
1758+
1759+ /* Stereo */
1760+ bits = get_bits (timing[0x11], 5, 6) << 1 | get_bit (timing[0x11], 0);
1761+ detailed->stereo = stereo[bits];
1762+
1763+ /* Sync */
1764+ bits = timing[0x11];
1765+
1766+ detailed->digital_sync = get_bit (bits, 4);
1767+ if (detailed->digital_sync)
1768+ {
1769+ detailed->connector.digital.composite = !get_bit (bits, 3);
1770+
1771+ if (detailed->connector.digital.composite)
1772+ {
1773+ detailed->connector.digital.serrations = get_bit (bits, 2);
1774+ detailed->connector.digital.negative_vsync = FALSE;
1775+ }
1776+ else
1777+ {
1778+ detailed->connector.digital.serrations = FALSE;
1779+ detailed->connector.digital.negative_vsync = !get_bit (bits, 2);
1780+ }
1781+
1782+ detailed->connector.digital.negative_hsync = !get_bit (bits, 0);
1783+ }
1784+ else
1785+ {
1786+ detailed->connector.analog.bipolar = get_bit (bits, 3);
1787+ detailed->connector.analog.serrations = get_bit (bits, 2);
1788+ detailed->connector.analog.sync_on_green = !get_bit (bits, 1);
1789+ }
1790+}
1791+
1792+static int
1793+decode_descriptors (const uchar *edid, MonitorInfo *info)
1794+{
1795+ int i;
1796+ int timing_idx;
1797+
1798+ timing_idx = 0;
1799+
1800+ for (i = 0; i < 4; ++i)
1801+ {
1802+ int index = 0x36 + i * 18;
1803+
1804+ if (edid[index + 0] == 0x00 && edid[index + 1] == 0x00)
1805+ {
1806+ decode_display_descriptor (edid + index, info);
1807+ }
1808+ else
1809+ {
1810+ decode_detailed_timing (
1811+ edid + index, &(info->detailed_timings[timing_idx++]));
1812+ }
1813+ }
1814+
1815+ info->n_detailed_timings = timing_idx;
1816+
1817+ return TRUE;
1818+}
1819+
1820+static void
1821+decode_check_sum (const uchar *edid,
1822+ MonitorInfo *info)
1823+{
1824+ int i;
1825+ uchar check = 0;
1826+
1827+ for (i = 0; i < 128; ++i)
1828+ check += edid[i];
1829+
1830+ info->checksum = check;
1831+}
1832+
1833+MonitorInfo *
1834+decode_edid (const uchar *edid)
1835+{
1836+ MonitorInfo *info = g_new0 (MonitorInfo, 1);
1837+
1838+ decode_check_sum (edid, info);
1839+
1840+ if (decode_header (edid)
1841+ && decode_vendor_and_product_identification (edid, info)
1842+ && decode_edid_version (edid, info)
1843+ && decode_display_parameters (edid, info)
1844+ && decode_color_characteristics (edid, info)
1845+ && decode_established_timings (edid, info)
1846+ && decode_standard_timings (edid, info)
1847+ && decode_descriptors (edid, info))
1848+ {
1849+ return info;
1850+ }
1851+ else
1852+ {
1853+ g_free (info);
1854+ return NULL;
1855+ }
1856+}
1857
1858=== modified file 'gnome-settings-daemon/gnome-settings-manager.c'
1859--- gnome-settings-daemon/gnome-settings-manager.c 2012-12-19 16:19:59 +0000
1860+++ gnome-settings-daemon/gnome-settings-manager.c 2014-08-29 10:24:26 +0000
1861@@ -30,13 +30,11 @@
1862 #include <glib-object.h>
1863 #include <gio/gio.h>
1864
1865-#define GNOME_DESKTOP_USE_UNSTABLE_API
1866-#include <libgnome-desktop/gnome-pnp-ids.h>
1867-
1868 #include "gnome-settings-plugin.h"
1869 #include "gnome-settings-plugin-info.h"
1870 #include "gnome-settings-manager.h"
1871 #include "gnome-settings-profile.h"
1872+#include "gsd-pnp-ids.h"
1873
1874 #define DEFAULT_SETTINGS_PREFIX "org.gnome.settings-daemon"
1875
1876@@ -64,7 +62,7 @@
1877 GDBusConnection *connection;
1878 GSettings *settings;
1879 char **whitelist;
1880- GnomePnpIds *pnp_ids;
1881+ GsdPnpIds *pnp_ids;
1882 GSList *plugins;
1883 };
1884
1885@@ -399,7 +397,7 @@
1886 }
1887
1888 g_debug ("loading PNPIDs");
1889- manager->priv->pnp_ids = gnome_pnp_ids_new ();
1890+ manager->priv->pnp_ids = gsd_pnp_ids_new ();
1891
1892 gnome_settings_profile_start ("initializing plugins");
1893 manager->priv->settings = g_settings_new (DEFAULT_SETTINGS_PREFIX ".plugins");
1894
1895=== added file 'gnome-settings-daemon/gsd-idle-monitor.c'
1896--- gnome-settings-daemon/gsd-idle-monitor.c 1970-01-01 00:00:00 +0000
1897+++ gnome-settings-daemon/gsd-idle-monitor.c 2014-08-29 10:24:26 +0000
1898@@ -0,0 +1,616 @@
1899+/* -*- mode: C; c-file-style: "linux"; indent-tabs-mode: t -*-
1900+ *
1901+ * Adapted from gnome-session/gnome-session/gs-idle-monitor.c
1902+ *
1903+ * Copyright (C) 2012 Red Hat, Inc.
1904+ *
1905+ * This program is free software; you can redistribute it and/or modify
1906+ * it under the terms of the GNU General Public License as published by
1907+ * the Free Software Foundation; either version 2 of the License, or
1908+ * (at your option) any later version.
1909+ *
1910+ * This program is distributed in the hope that it will be useful,
1911+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1912+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1913+ * GNU General Public License for more details.
1914+ *
1915+ * You should have received a copy of the GNU General Public License
1916+ * along with this program; if not, write to the Free Software
1917+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1918+ */
1919+
1920+#include "config.h"
1921+
1922+#include <time.h>
1923+#include <string.h>
1924+
1925+#include <X11/Xlib.h>
1926+#include <X11/extensions/sync.h>
1927+
1928+#include <glib.h>
1929+#include <gdk/gdkx.h>
1930+#include <gdk/gdk.h>
1931+
1932+#include "gsd-idle-monitor.h"
1933+
1934+#define GSD_IDLE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_IDLE_MONITOR, GsdIdleMonitorPrivate))
1935+
1936+G_STATIC_ASSERT(sizeof(unsigned long) == sizeof(gpointer));
1937+
1938+struct _GsdIdleMonitorPrivate
1939+{
1940+ Display *display;
1941+
1942+ GHashTable *watches;
1943+ GHashTable *alarms;
1944+ int sync_event_base;
1945+ XSyncCounter counter;
1946+
1947+ XSyncAlarm user_active_alarm;
1948+
1949+ GdkDevice *device;
1950+};
1951+
1952+typedef struct
1953+{
1954+ GsdIdleMonitor *monitor;
1955+ guint id;
1956+ GsdIdleMonitorWatchFunc callback;
1957+ gpointer user_data;
1958+ GDestroyNotify notify;
1959+ XSyncAlarm xalarm;
1960+} GsdIdleMonitorWatch;
1961+
1962+enum
1963+{
1964+ PROP_0,
1965+ PROP_DEVICE,
1966+ PROP_LAST,
1967+};
1968+
1969+static GParamSpec *obj_props[PROP_LAST];
1970+
1971+static void gsd_idle_monitor_initable_iface_init (GInitableIface *iface);
1972+
1973+G_DEFINE_TYPE_WITH_CODE (GsdIdleMonitor, gsd_idle_monitor, G_TYPE_OBJECT,
1974+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
1975+ gsd_idle_monitor_initable_iface_init))
1976+
1977+static gint64
1978+_xsyncvalue_to_int64 (XSyncValue value)
1979+{
1980+ return ((guint64) XSyncValueHigh32 (value)) << 32
1981+ | (guint64) XSyncValueLow32 (value);
1982+}
1983+
1984+#define GINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, value, ((guint64)value) >> 32)
1985+
1986+static XSyncAlarm
1987+_xsync_alarm_set (GsdIdleMonitor *monitor,
1988+ XSyncTestType test_type,
1989+ guint64 interval,
1990+ gboolean want_events)
1991+{
1992+ XSyncAlarmAttributes attr;
1993+ XSyncValue delta;
1994+ guint flags;
1995+
1996+ flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType |
1997+ XSyncCAValue | XSyncCADelta | XSyncCAEvents;
1998+
1999+ XSyncIntToValue (&delta, 0);
2000+ attr.trigger.counter = monitor->priv->counter;
2001+ attr.trigger.value_type = XSyncAbsolute;
2002+ attr.delta = delta;
2003+ attr.events = want_events;
2004+
2005+ GINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
2006+ attr.trigger.test_type = test_type;
2007+ return XSyncCreateAlarm (monitor->priv->display, flags, &attr);
2008+}
2009+
2010+static void
2011+ensure_alarm_rescheduled (Display *dpy,
2012+ XSyncAlarm alarm)
2013+{
2014+ XSyncAlarmAttributes attr;
2015+
2016+ /* Some versions of Xorg have an issue where alarms aren't
2017+ * always rescheduled. Calling XSyncChangeAlarm, even
2018+ * without any attributes, will reschedule the alarm. */
2019+ XSyncChangeAlarm (dpy, alarm, 0, &attr);
2020+}
2021+
2022+static void
2023+set_alarm_enabled (Display *dpy,
2024+ XSyncAlarm alarm,
2025+ gboolean enabled)
2026+{
2027+ XSyncAlarmAttributes attr;
2028+ attr.events = enabled;
2029+ XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr);
2030+}
2031+
2032+static void
2033+fire_watch (gpointer data,
2034+ gpointer user_data)
2035+{
2036+ GsdIdleMonitorWatch *watch = data;
2037+ XSyncAlarm alarm = (XSyncAlarm) user_data;
2038+ GsdIdleMonitor *monitor;
2039+
2040+ if (watch->xalarm != alarm) {
2041+ return;
2042+ }
2043+
2044+ monitor = watch->monitor;
2045+ g_object_ref (monitor);
2046+
2047+ if (watch->callback) {
2048+ watch->callback (watch->monitor,
2049+ watch->id,
2050+ watch->user_data);
2051+ }
2052+
2053+ if (watch->xalarm == monitor->priv->user_active_alarm) {
2054+ gsd_idle_monitor_remove_watch (monitor, watch->id);
2055+ }
2056+
2057+ g_object_unref (monitor);
2058+}
2059+
2060+static void
2061+handle_alarm_notify_event (GsdIdleMonitor *monitor,
2062+ XSyncAlarmNotifyEvent *alarm_event)
2063+{
2064+ XSyncAlarm alarm;
2065+ GList *watches;
2066+ gboolean has_alarm;
2067+
2068+ if (alarm_event->state != XSyncAlarmActive) {
2069+ return;
2070+ }
2071+
2072+ alarm = alarm_event->alarm;
2073+
2074+ has_alarm = FALSE;
2075+
2076+ if (alarm == monitor->priv->user_active_alarm) {
2077+ set_alarm_enabled (monitor->priv->display,
2078+ alarm,
2079+ FALSE);
2080+ has_alarm = TRUE;
2081+ } else if (g_hash_table_contains (monitor->priv->alarms, (gpointer) alarm)) {
2082+ ensure_alarm_rescheduled (monitor->priv->display,
2083+ alarm);
2084+ has_alarm = TRUE;
2085+ }
2086+
2087+ if (has_alarm) {
2088+ watches = g_hash_table_get_values (monitor->priv->watches);
2089+
2090+ g_list_foreach (watches,
2091+ fire_watch,
2092+ (gpointer) alarm);
2093+
2094+ g_list_free (watches);
2095+ }
2096+}
2097+
2098+static GdkFilterReturn
2099+xevent_filter (GdkXEvent *xevent,
2100+ GdkEvent *event,
2101+ GsdIdleMonitor *monitor)
2102+{
2103+ XEvent *ev;
2104+ XSyncAlarmNotifyEvent *alarm_event;
2105+
2106+ ev = xevent;
2107+ if (ev->xany.type != monitor->priv->sync_event_base + XSyncAlarmNotify) {
2108+ return GDK_FILTER_CONTINUE;
2109+ }
2110+
2111+ alarm_event = xevent;
2112+ handle_alarm_notify_event (monitor, alarm_event);
2113+
2114+ return GDK_FILTER_CONTINUE;
2115+}
2116+
2117+static char *
2118+counter_name_for_device (GdkDevice *device)
2119+{
2120+ if (device) {
2121+ gint device_id = gdk_x11_device_get_id (device);
2122+ if (device_id > 0)
2123+ return g_strdup_printf ("DEVICEIDLETIME %d", device_id);
2124+ }
2125+
2126+ return g_strdup ("IDLETIME");
2127+}
2128+
2129+static XSyncCounter
2130+find_idletime_counter (GsdIdleMonitor *monitor)
2131+{
2132+ int i;
2133+ int ncounters;
2134+ XSyncSystemCounter *counters;
2135+ XSyncCounter counter = None;
2136+ char *counter_name;
2137+
2138+ counter_name = counter_name_for_device (monitor->priv->device);
2139+ counters = XSyncListSystemCounters (monitor->priv->display, &ncounters);
2140+ for (i = 0; i < ncounters; i++) {
2141+ if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0) {
2142+ counter = counters[i].counter;
2143+ break;
2144+ }
2145+ }
2146+ XSyncFreeSystemCounterList (counters);
2147+ g_free (counter_name);
2148+
2149+ return counter;
2150+}
2151+
2152+static guint32
2153+get_next_watch_serial (void)
2154+{
2155+ static guint32 serial = 0;
2156+ g_atomic_int_inc (&serial);
2157+ return serial;
2158+}
2159+
2160+static void
2161+idle_monitor_watch_free (GsdIdleMonitorWatch *watch)
2162+{
2163+ GsdIdleMonitor *monitor;
2164+
2165+ if (watch == NULL) {
2166+ return;
2167+ }
2168+
2169+ monitor = watch->monitor;
2170+
2171+ if (watch->notify != NULL) {
2172+ watch->notify (watch->user_data);
2173+ }
2174+
2175+ if (watch->xalarm != monitor->priv->user_active_alarm) {
2176+ XSyncDestroyAlarm (monitor->priv->display, watch->xalarm);
2177+ g_hash_table_remove (monitor->priv->alarms, (gpointer) watch->xalarm);
2178+ }
2179+
2180+ g_slice_free (GsdIdleMonitorWatch, watch);
2181+}
2182+
2183+static void
2184+init_xsync (GsdIdleMonitor *monitor)
2185+{
2186+ int sync_error_base;
2187+ int res;
2188+ int major;
2189+ int minor;
2190+
2191+ res = XSyncQueryExtension (monitor->priv->display,
2192+ &monitor->priv->sync_event_base,
2193+ &sync_error_base);
2194+ if (! res) {
2195+ g_warning ("GsdIdleMonitor: Sync extension not present");
2196+ return;
2197+ }
2198+
2199+ res = XSyncInitialize (monitor->priv->display, &major, &minor);
2200+ if (! res) {
2201+ g_warning ("GsdIdleMonitor: Unable to initialize Sync extension");
2202+ return;
2203+ }
2204+
2205+ monitor->priv->counter = find_idletime_counter (monitor);
2206+ /* IDLETIME counter not found? */
2207+ if (monitor->priv->counter == None)
2208+ return;
2209+
2210+ monitor->priv->user_active_alarm = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1, FALSE);
2211+
2212+ gdk_window_add_filter (NULL, (GdkFilterFunc)xevent_filter, monitor);
2213+}
2214+
2215+static void
2216+gsd_idle_monitor_dispose (GObject *object)
2217+{
2218+ GsdIdleMonitor *monitor;
2219+
2220+ monitor = GSD_IDLE_MONITOR (object);
2221+
2222+ g_clear_pointer (&monitor->priv->watches, g_hash_table_destroy);
2223+ g_clear_pointer (&monitor->priv->alarms, g_hash_table_destroy);
2224+ g_clear_object (&monitor->priv->device);
2225+
2226+ if (monitor->priv->user_active_alarm != None) {
2227+ XSyncDestroyAlarm (monitor->priv->display, monitor->priv->user_active_alarm);
2228+ monitor->priv->user_active_alarm = None;
2229+ }
2230+
2231+ gdk_window_remove_filter (NULL, (GdkFilterFunc)xevent_filter, monitor);
2232+
2233+ G_OBJECT_CLASS (gsd_idle_monitor_parent_class)->dispose (object);
2234+}
2235+
2236+static void
2237+gsd_idle_monitor_get_property (GObject *object,
2238+ guint prop_id,
2239+ GValue *value,
2240+ GParamSpec *pspec)
2241+{
2242+ GsdIdleMonitor *monitor = GSD_IDLE_MONITOR (object);
2243+ switch (prop_id)
2244+ {
2245+ case PROP_DEVICE:
2246+ g_value_set_object (value, monitor->priv->device);
2247+ break;
2248+ default:
2249+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2250+ break;
2251+ }
2252+}
2253+
2254+static void
2255+gsd_idle_monitor_set_property (GObject *object,
2256+ guint prop_id,
2257+ const GValue *value,
2258+ GParamSpec *pspec)
2259+{
2260+ GsdIdleMonitor *monitor = GSD_IDLE_MONITOR (object);
2261+ switch (prop_id)
2262+ {
2263+ case PROP_DEVICE:
2264+ monitor->priv->device = g_value_dup_object (value);
2265+ break;
2266+ default:
2267+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2268+ break;
2269+ }
2270+}
2271+
2272+static void
2273+gsd_idle_monitor_constructed (GObject *object)
2274+{
2275+ GsdIdleMonitor *monitor = GSD_IDLE_MONITOR (object);
2276+
2277+ monitor->priv->display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
2278+ init_xsync (monitor);
2279+}
2280+
2281+static gboolean
2282+gsd_idle_monitor_initable_init (GInitable *initable,
2283+ GCancellable *cancellable,
2284+ GError **error)
2285+{
2286+ GsdIdleMonitor *monitor;
2287+
2288+ monitor = GSD_IDLE_MONITOR (initable);
2289+
2290+ if (monitor->priv->counter == None) {
2291+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
2292+ "Per-device idletime is not supported");
2293+ return FALSE;
2294+ }
2295+
2296+ return TRUE;
2297+}
2298+
2299+static void
2300+gsd_idle_monitor_initable_iface_init (GInitableIface *iface)
2301+{
2302+ iface->init = gsd_idle_monitor_initable_init;
2303+}
2304+
2305+static void
2306+gsd_idle_monitor_class_init (GsdIdleMonitorClass *klass)
2307+{
2308+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
2309+
2310+ object_class->dispose = gsd_idle_monitor_dispose;
2311+ object_class->constructed = gsd_idle_monitor_constructed;
2312+ object_class->get_property = gsd_idle_monitor_get_property;
2313+ object_class->set_property = gsd_idle_monitor_set_property;
2314+
2315+ /**
2316+ * GsdIdleMonitor:device:
2317+ *
2318+ * The device to listen to idletime on.
2319+ */
2320+ obj_props[PROP_DEVICE] =
2321+ g_param_spec_object ("device",
2322+ "Device",
2323+ "The device to listen to idletime on",
2324+ GDK_TYPE_DEVICE,
2325+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
2326+ g_object_class_install_property (object_class, PROP_DEVICE, obj_props[PROP_DEVICE]);
2327+
2328+ g_type_class_add_private (klass, sizeof (GsdIdleMonitorPrivate));
2329+}
2330+
2331+static void
2332+gsd_idle_monitor_init (GsdIdleMonitor *monitor)
2333+{
2334+ monitor->priv = GSD_IDLE_MONITOR_GET_PRIVATE (monitor);
2335+
2336+ monitor->priv->watches = g_hash_table_new_full (NULL,
2337+ NULL,
2338+ NULL,
2339+ (GDestroyNotify)idle_monitor_watch_free);
2340+
2341+ monitor->priv->alarms = g_hash_table_new (NULL, NULL);
2342+}
2343+
2344+/**
2345+ * gsd_idle_monitor_new:
2346+ *
2347+ * Returns: a new #GsdIdleMonitor that tracks the server-global
2348+ * idletime for all devices. To track device-specific idletime,
2349+ * use gsd_idle_monitor_new_for_device().
2350+ */
2351+GsdIdleMonitor *
2352+gsd_idle_monitor_new (void)
2353+{
2354+ return GSD_IDLE_MONITOR (g_initable_new (GSD_TYPE_IDLE_MONITOR, NULL, NULL, NULL));
2355+}
2356+
2357+/**
2358+ * gsd_idle_monitor_new_for_device:
2359+ * @device: A #GdkDevice to get the idle time for.
2360+ *
2361+ * Returns: a new #GsdIdleMonitor that tracks the device-specific
2362+ * idletime for @device. If device-specific idletime is not available,
2363+ * %NULL is returned, and @error is set. To track server-global
2364+ * idletime for all devices, use gsd_idle_monitor_new().
2365+ */
2366+GsdIdleMonitor *
2367+gsd_idle_monitor_new_for_device (GdkDevice *device)
2368+{
2369+ return GSD_IDLE_MONITOR (g_initable_new (GSD_TYPE_IDLE_MONITOR, NULL, NULL,
2370+ "device", device, NULL));
2371+}
2372+
2373+static GsdIdleMonitorWatch *
2374+make_watch (GsdIdleMonitor *monitor,
2375+ XSyncAlarm xalarm,
2376+ GsdIdleMonitorWatchFunc callback,
2377+ gpointer user_data,
2378+ GDestroyNotify notify)
2379+{
2380+ GsdIdleMonitorWatch *watch;
2381+
2382+ watch = g_slice_new0 (GsdIdleMonitorWatch);
2383+ watch->monitor = monitor;
2384+ watch->id = get_next_watch_serial ();
2385+ watch->callback = callback;
2386+ watch->user_data = user_data;
2387+ watch->notify = notify;
2388+ watch->xalarm = xalarm;
2389+
2390+ g_hash_table_insert (monitor->priv->watches,
2391+ GUINT_TO_POINTER (watch->id),
2392+ watch);
2393+ return watch;
2394+}
2395+
2396+/**
2397+ * gsd_idle_monitor_add_idle_watch:
2398+ * @monitor: A #GsdIdleMonitor
2399+ * @interval_msec: The idletime interval, in milliseconds
2400+ * @callback: (allow-none): The callback to call when the user has
2401+ * accumulated @interval_msec milliseconds of idle time.
2402+ * @user_data: (allow-none): The user data to pass to the callback
2403+ * @notify: A #GDestroyNotify
2404+ *
2405+ * Returns: a watch id
2406+ *
2407+ * Adds a watch for a specific idle time. The callback will be called
2408+ * when the user has accumulated @interval_msec milliseconds of idle time.
2409+ * This function will return an ID that can either be passed to
2410+ * gsd_idle_monitor_remove_watch(), or can be used to tell idle time
2411+ * watches apart if you have more than one.
2412+ *
2413+ * Also note that this function will only care about positive transitions
2414+ * (user's idle time exceeding a certain time). If you want to know about
2415+ * when the user has become active, use
2416+ * gsd_idle_monitor_add_user_active_watch().
2417+ */
2418+guint
2419+gsd_idle_monitor_add_idle_watch (GsdIdleMonitor *monitor,
2420+ guint64 interval_msec,
2421+ GsdIdleMonitorWatchFunc callback,
2422+ gpointer user_data,
2423+ GDestroyNotify notify)
2424+{
2425+ GsdIdleMonitorWatch *watch;
2426+
2427+ g_return_val_if_fail (GSD_IS_IDLE_MONITOR (monitor), 0);
2428+
2429+ watch = make_watch (monitor,
2430+ _xsync_alarm_set (monitor, XSyncPositiveTransition, interval_msec, TRUE),
2431+ callback,
2432+ user_data,
2433+ notify);
2434+
2435+ g_hash_table_add (monitor->priv->alarms,
2436+ (gpointer) watch->xalarm);
2437+
2438+ return watch->id;
2439+}
2440+
2441+/**
2442+ * gsd_idle_monitor_add_user_active_watch:
2443+ * @monitor: A #GsdIdleMonitor
2444+ * @callback: (allow-none): The callback to call when the user is
2445+ * active again.
2446+ * @user_data: (allow-none): The user data to pass to the callback
2447+ * @notify: A #GDestroyNotify
2448+ *
2449+ * Returns: a watch id
2450+ *
2451+ * Add a one-time watch to know when the user is active again.
2452+ * Note that this watch is one-time and will de-activate after the
2453+ * function is called, for efficiency purposes. It's most convenient
2454+ * to call this when an idle watch, as added by
2455+ * gsd_idle_monitor_add_idle_watch(), has triggered.
2456+ */
2457+guint
2458+gsd_idle_monitor_add_user_active_watch (GsdIdleMonitor *monitor,
2459+ GsdIdleMonitorWatchFunc callback,
2460+ gpointer user_data,
2461+ GDestroyNotify notify)
2462+{
2463+ GsdIdleMonitorWatch *watch;
2464+
2465+ g_return_val_if_fail (GSD_IS_IDLE_MONITOR (monitor), 0);
2466+
2467+ set_alarm_enabled (monitor->priv->display,
2468+ monitor->priv->user_active_alarm,
2469+ TRUE);
2470+
2471+ watch = make_watch (monitor,
2472+ monitor->priv->user_active_alarm,
2473+ callback,
2474+ user_data,
2475+ notify);
2476+
2477+ return watch->id;
2478+}
2479+
2480+/**
2481+ * gsd_idle_monitor_remove_watch:
2482+ * @monitor: A #GsdIdleMonitor
2483+ * @id: A watch ID
2484+ *
2485+ * Removes an idle time watcher, previously added by
2486+ * gsd_idle_monitor_add_idle_watch() or
2487+ * gsd_idle_monitor_add_user_active_watch().
2488+ */
2489+void
2490+gsd_idle_monitor_remove_watch (GsdIdleMonitor *monitor,
2491+ guint id)
2492+{
2493+ g_return_if_fail (GSD_IS_IDLE_MONITOR (monitor));
2494+
2495+ g_hash_table_remove (monitor->priv->watches,
2496+ GUINT_TO_POINTER (id));
2497+}
2498+
2499+/**
2500+ * gsd_idle_monitor_get_idletime:
2501+ * @monitor: A #GsdIdleMonitor
2502+ *
2503+ * Returns: The current idle time, in milliseconds, or -1 for not supported
2504+ */
2505+gint64
2506+gsd_idle_monitor_get_idletime (GsdIdleMonitor *monitor)
2507+{
2508+ XSyncValue value;
2509+
2510+ if (!XSyncQueryCounter (monitor->priv->display, monitor->priv->counter, &value))
2511+ return -1;
2512+
2513+ return _xsyncvalue_to_int64 (value);
2514+}
2515
2516=== added file 'gnome-settings-daemon/gsd-idle-monitor.h'
2517--- gnome-settings-daemon/gsd-idle-monitor.h 1970-01-01 00:00:00 +0000
2518+++ gnome-settings-daemon/gsd-idle-monitor.h 2014-08-29 10:24:26 +0000
2519@@ -0,0 +1,81 @@
2520+/* -*- mode: C; c-file-style: "linux"; indent-tabs-mode: t -*-
2521+ *
2522+ * Adapted from gnome-session/gnome-session/gs-idle-monitor.h
2523+ *
2524+ * Copyright (C) 2012 Red Hat, Inc.
2525+ *
2526+ * This program is free software; you can redistribute it and/or modify
2527+ * it under the terms of the GNU General Public License as published by
2528+ * the Free Software Foundation; either version 2 of the License, or
2529+ * (at your option) any later version.
2530+ *
2531+ * This program is distributed in the hope that it will be useful,
2532+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2533+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2534+ * GNU General Public License for more details.
2535+ *
2536+ * You should have received a copy of the GNU General Public License
2537+ * along with this program; if not, write to the Free Software
2538+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2539+ *
2540+ * Authors: William Jon McCann <mccann@jhu.edu>
2541+ */
2542+
2543+#ifndef __GSD_IDLE_MONITOR_H__
2544+#define __GSD_IDLE_MONITOR_H__
2545+
2546+#include <glib-object.h>
2547+#include <gdk/gdk.h>
2548+
2549+G_BEGIN_DECLS
2550+
2551+#define GSD_TYPE_IDLE_MONITOR (gsd_idle_monitor_get_type ())
2552+#define GSD_IDLE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_IDLE_MONITOR, GsdIdleMonitor))
2553+#define GSD_IDLE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_IDLE_MONITOR, GsdIdleMonitorClass))
2554+#define GSD_IS_IDLE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_IDLE_MONITOR))
2555+#define GSD_IS_IDLE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_IDLE_MONITOR))
2556+#define GSD_IDLE_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_IDLE_MONITOR, GsdIdleMonitorClass))
2557+
2558+typedef struct _GsdIdleMonitor GsdIdleMonitor;
2559+typedef struct _GsdIdleMonitorClass GsdIdleMonitorClass;
2560+typedef struct _GsdIdleMonitorPrivate GsdIdleMonitorPrivate;
2561+
2562+struct _GsdIdleMonitor
2563+{
2564+ GObject parent;
2565+ GsdIdleMonitorPrivate *priv;
2566+};
2567+
2568+struct _GsdIdleMonitorClass
2569+{
2570+ GObjectClass parent_class;
2571+};
2572+
2573+typedef void (*GsdIdleMonitorWatchFunc) (GsdIdleMonitor *monitor,
2574+ guint id,
2575+ gpointer user_data);
2576+
2577+GType gsd_idle_monitor_get_type (void);
2578+
2579+GsdIdleMonitor * gsd_idle_monitor_new (void);
2580+GsdIdleMonitor * gsd_idle_monitor_new_for_device (GdkDevice *device);
2581+
2582+guint gsd_idle_monitor_add_idle_watch (GsdIdleMonitor *monitor,
2583+ guint64 interval_msec,
2584+ GsdIdleMonitorWatchFunc callback,
2585+ gpointer user_data,
2586+ GDestroyNotify notify);
2587+
2588+guint gsd_idle_monitor_add_user_active_watch (GsdIdleMonitor *monitor,
2589+ GsdIdleMonitorWatchFunc callback,
2590+ gpointer user_data,
2591+ GDestroyNotify notify);
2592+
2593+void gsd_idle_monitor_remove_watch (GsdIdleMonitor *monitor,
2594+ guint id);
2595+
2596+gint64 gsd_idle_monitor_get_idletime (GsdIdleMonitor *monitor);
2597+
2598+G_END_DECLS
2599+
2600+#endif /* __GSD_IDLE_MONITOR_H__ */
2601
2602=== added file 'gnome-settings-daemon/gsd-pnp-ids.c'
2603--- gnome-settings-daemon/gsd-pnp-ids.c 1970-01-01 00:00:00 +0000
2604+++ gnome-settings-daemon/gsd-pnp-ids.c 2014-08-29 10:24:26 +0000
2605@@ -0,0 +1,341 @@
2606+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2607+ *
2608+ * Copyright (C) 2009-2011 Richard Hughes <richard@hughsie.com>
2609+ *
2610+ * This program is free software; you can redistribute it and/or modify
2611+ * it under the terms of the GNU General Public License as published by
2612+ * the Free Software Foundation; either version 2 of the License, or
2613+ * (at your option) any later version.
2614+ *
2615+ * This program is distributed in the hope that it will be useful,
2616+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2617+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2618+ * GNU General Public License for more details.
2619+ *
2620+ * You should have received a copy of the GNU General Public License
2621+ * along with this program; if not, write to the Free Software
2622+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2623+ */
2624+
2625+#include "config.h"
2626+
2627+#include <glib-object.h>
2628+
2629+#include "gsd-pnp-ids.h"
2630+
2631+static void gsd_pnp_ids_finalize (GObject *object);
2632+
2633+#define GSD_PNP_IDS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_PNP_IDS, GsdPnpIdsPrivate))
2634+
2635+struct _GsdPnpIdsPrivate
2636+{
2637+ gchar *table_data;
2638+ GHashTable *pnp_table;
2639+};
2640+
2641+static gpointer gsd_pnp_ids_object = NULL;
2642+
2643+G_DEFINE_TYPE (GsdPnpIds, gsd_pnp_ids, G_TYPE_OBJECT)
2644+
2645+typedef struct Vendor Vendor;
2646+struct Vendor
2647+{
2648+ const char vendor_id[4];
2649+ const char vendor_name[28];
2650+};
2651+
2652+/* This list of vendor codes derived from lshw
2653+ *
2654+ * http://ezix.org/project/wiki/HardwareLiSter
2655+ *
2656+ * Note: we now prefer to use data coming from hwdata (and shipped with
2657+ * gnome-desktop). See
2658+ * http://git.fedorahosted.org/git/?p=hwdata.git;a=blob_plain;f=pnp.ids;hb=HEAD
2659+ * All contributions to the list of vendors should go there.
2660+ */
2661+static const struct Vendor vendors[] =
2662+{
2663+ { "AIC", "AG Neovo" },
2664+ { "ACR", "Acer" },
2665+ { "DEL", "DELL" },
2666+ { "SAM", "SAMSUNG" },
2667+ { "SNY", "SONY" },
2668+ { "SEC", "Epson" },
2669+ { "WAC", "Wacom" },
2670+ { "NEC", "NEC" },
2671+ { "CMO", "CMO" }, /* Chi Mei */
2672+ { "BNQ", "BenQ" },
2673+
2674+ { "ABP", "Advansys" },
2675+ { "ACC", "Accton" },
2676+ { "ACE", "Accton" },
2677+ { "ADP", "Adaptec" },
2678+ { "ADV", "AMD" },
2679+ { "AIR", "AIR" },
2680+ { "AMI", "AMI" },
2681+ { "ASU", "ASUS" },
2682+ { "ATI", "ATI" },
2683+ { "ATK", "Allied Telesyn" },
2684+ { "AZT", "Aztech" },
2685+ { "BAN", "Banya" },
2686+ { "BRI", "Boca Research" },
2687+ { "BUS", "Buslogic" },
2688+ { "CCI", "Cache Computers Inc." },
2689+ { "CHA", "Chase" },
2690+ { "CMD", "CMD Technology, Inc." },
2691+ { "COG", "Cogent" },
2692+ { "CPQ", "Compaq" },
2693+ { "CRS", "Crescendo" },
2694+ { "CSC", "Crystal" },
2695+ { "CSI", "CSI" },
2696+ { "CTL", "Creative Labs" },
2697+ { "DBI", "Digi" },
2698+ { "DEC", "Digital Equipment" },
2699+ { "DBK", "Databook" },
2700+ { "EGL", "Eagle Technology" },
2701+ { "ELS", "ELSA" },
2702+ { "ESS", "ESS" },
2703+ { "FAR", "Farallon" },
2704+ { "FDC", "Future Domain" },
2705+ { "HWP", "Hewlett-Packard" },
2706+ { "IBM", "IBM" },
2707+ { "INT", "Intel" },
2708+ { "ISA", "Iomega" },
2709+ { "LEN", "Lenovo" },
2710+ { "MDG", "Madge" },
2711+ { "MDY", "Microdyne" },
2712+ { "MET", "Metheus" },
2713+ { "MIC", "Micronics" },
2714+ { "MLX", "Mylex" },
2715+ { "NVL", "Novell" },
2716+ { "OLC", "Olicom" },
2717+ { "PRO", "Proteon" },
2718+ { "RII", "Racal" },
2719+ { "RTL", "Realtek" },
2720+ { "SCM", "SCM" },
2721+ { "SKD", "SysKonnect" },
2722+ { "SGI", "SGI" },
2723+ { "SMC", "SMC" },
2724+ { "SNI", "Siemens Nixdorf" },
2725+ { "STL", "Stallion Technologies" },
2726+ { "SUN", "Sun" },
2727+ { "SUP", "SupraExpress" },
2728+ { "SVE", "SVEC" },
2729+ { "TCC", "Thomas-Conrad" },
2730+ { "TCI", "Tulip" },
2731+ { "TCM", "3Com" },
2732+ { "TCO", "Thomas-Conrad" },
2733+ { "TEC", "Tecmar" },
2734+ { "TRU", "Truevision" },
2735+ { "TOS", "Toshiba" },
2736+ { "TYN", "Tyan" },
2737+ { "UBI", "Ungermann-Bass" },
2738+ { "USC", "UltraStor" },
2739+ { "VDM", "Vadem" },
2740+ { "VMI", "Vermont" },
2741+ { "WDC", "Western Digital" },
2742+ { "ZDS", "Zeos" },
2743+
2744+ /* From http://faydoc.tripod.com/structures/01/0136.htm */
2745+ { "ACT", "Targa" },
2746+ { "ADI", "ADI" },
2747+ { "AOC", "AOC Intl" },
2748+ { "API", "Acer America" },
2749+ { "APP", "Apple Computer" },
2750+ { "ART", "ArtMedia" },
2751+ { "AST", "AST Research" },
2752+ { "CPL", "Compal" },
2753+ { "CTX", "Chuntex Electronic Co." },
2754+ { "DPC", "Delta Electronics" },
2755+ { "DWE", "Daewoo" },
2756+ { "ECS", "ELITEGROUP" },
2757+ { "EIZ", "EIZO" },
2758+ { "FCM", "Funai" },
2759+ { "GSM", "LG Electronics" },
2760+ { "GWY", "Gateway 2000" },
2761+ { "HEI", "Hyundai" },
2762+ { "HIT", "Hitachi" },
2763+ { "HSL", "Hansol" },
2764+ { "HTC", "Hitachi" },
2765+ { "ICL", "Fujitsu ICL" },
2766+ { "IVM", "Idek Iiyama" },
2767+ { "KFC", "KFC Computek" },
2768+ { "LKM", "ADLAS" },
2769+ { "LNK", "LINK Tech" },
2770+ { "LTN", "Lite-On" },
2771+ { "MAG", "MAG InnoVision" },
2772+ { "MAX", "Maxdata" },
2773+ { "MEI", "Panasonic" },
2774+ { "MEL", "Mitsubishi" },
2775+ { "MIR", "miro" },
2776+ { "MTC", "MITAC" },
2777+ { "NAN", "NANAO" },
2778+ { "NEC", "NEC Tech" },
2779+ { "NOK", "Nokia" },
2780+ { "OQI", "OPTIQUEST" },
2781+ { "PBN", "Packard Bell" },
2782+ { "PGS", "Princeton" },
2783+ { "PHL", "Philips" },
2784+ { "REL", "Relisys" },
2785+ { "SDI", "Samtron" },
2786+ { "SMI", "Smile" },
2787+ { "SPT", "Sceptre" },
2788+ { "SRC", "Shamrock Technology" },
2789+ { "STP", "Sceptre" },
2790+ { "TAT", "Tatung" },
2791+ { "TRL", "Royal Information Company" },
2792+ { "TSB", "Toshiba, Inc." },
2793+ { "UNM", "Unisys" },
2794+ { "VSC", "ViewSonic" },
2795+ { "WTC", "Wen Tech" },
2796+ { "ZCM", "Zenith Data Systems" },
2797+
2798+ { "???", "Unknown" },
2799+};
2800+
2801+static gboolean
2802+gsd_pnp_ids_load (GsdPnpIds *pnp_ids, GError **error)
2803+{
2804+ gchar *retval = NULL;
2805+ GsdPnpIdsPrivate *priv = pnp_ids->priv;
2806+ guint i;
2807+
2808+ /* load the contents */
2809+ g_debug ("loading: %s", PNP_IDS);
2810+ if (g_file_get_contents (PNP_IDS, &priv->table_data, NULL, error) == FALSE)
2811+ return FALSE;
2812+
2813+ /* parse into lines */
2814+ retval = priv->table_data;
2815+ for (i = 0; priv->table_data[i] != '\0'; i++) {
2816+
2817+ /* ignore */
2818+ if (priv->table_data[i] != '\n')
2819+ continue;
2820+
2821+ /* convert newline to NULL */
2822+ priv->table_data[i] = '\0';
2823+
2824+ /* the ID to text is a fixed offset */
2825+ if (retval[0] && retval[1] && retval[2] && retval[3] == '\t' && retval[4]) {
2826+ retval[3] = '\0';
2827+ g_hash_table_insert (priv->pnp_table,
2828+ retval,
2829+ retval+4);
2830+ retval = &priv->table_data[i+1];
2831+ }
2832+ }
2833+
2834+ g_debug ("Added %i items to the vendor hashtable", i);
2835+
2836+ return TRUE;
2837+}
2838+
2839+static const char *
2840+find_vendor (const char *pnp_id)
2841+{
2842+ guint i;
2843+
2844+ for (i = 0; i < G_N_ELEMENTS (vendors); i++) {
2845+ if (g_strcmp0 (vendors[i].vendor_id, pnp_id) == 0)
2846+ return vendors[i].vendor_name;
2847+ }
2848+
2849+ return NULL;
2850+}
2851+
2852+/**
2853+ * gsd_pnp_ids_get_pnp_id:
2854+ * @pnp_ids: a #GsdPnpIds object
2855+ * @pnp_id: the PNP ID to look for
2856+ *
2857+ * Find the full manufacturer name for the given PNP ID.
2858+ *
2859+ * Returns: (transfer full): a new string representing the manufacturer name,
2860+ * or %NULL when not found.
2861+ */
2862+gchar *
2863+gsd_pnp_ids_get_pnp_id (GsdPnpIds *pnp_ids, const gchar *pnp_id)
2864+{
2865+ GsdPnpIdsPrivate *priv = pnp_ids->priv;
2866+ const char *found;
2867+ GError *error = NULL;
2868+ guint size;
2869+
2870+ g_return_val_if_fail (GSD_IS_PNP_IDS (pnp_ids), NULL);
2871+ g_return_val_if_fail (pnp_id != NULL, NULL);
2872+
2873+ /* if table is empty, try to load it */
2874+ size = g_hash_table_size (priv->pnp_table);
2875+ if (size == 0) {
2876+ if (gsd_pnp_ids_load (pnp_ids, &error) == FALSE) {
2877+ g_warning ("Failed to load PNP ids: %s", error->message);
2878+ g_error_free (error);
2879+ return NULL;
2880+ }
2881+ }
2882+
2883+ /* look this up in the table */
2884+ found = g_hash_table_lookup (priv->pnp_table, pnp_id);
2885+ if (found == NULL) {
2886+ found = find_vendor (pnp_id);
2887+ if (found == NULL)
2888+ return NULL;
2889+ }
2890+
2891+ return g_strdup (found);
2892+}
2893+
2894+static void
2895+gsd_pnp_ids_class_init (GsdPnpIdsClass *klass)
2896+{
2897+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
2898+ object_class->finalize = gsd_pnp_ids_finalize;
2899+ g_type_class_add_private (klass, sizeof (GsdPnpIdsPrivate));
2900+}
2901+
2902+static void
2903+gsd_pnp_ids_init (GsdPnpIds *pnp_ids)
2904+{
2905+ pnp_ids->priv = GSD_PNP_IDS_GET_PRIVATE (pnp_ids);
2906+
2907+ /* we don't keep malloc'd data in the hash; instead we read it
2908+ * out into priv->table_data and then link to it in the hash */
2909+ pnp_ids->priv->pnp_table = g_hash_table_new_full (g_str_hash,
2910+ g_str_equal,
2911+ NULL,
2912+ NULL);
2913+}
2914+
2915+static void
2916+gsd_pnp_ids_finalize (GObject *object)
2917+{
2918+ GsdPnpIds *pnp_ids = GSD_PNP_IDS (object);
2919+ GsdPnpIdsPrivate *priv = pnp_ids->priv;
2920+
2921+ g_free (priv->table_data);
2922+ g_hash_table_unref (priv->pnp_table);
2923+
2924+ G_OBJECT_CLASS (gsd_pnp_ids_parent_class)->finalize (object);
2925+}
2926+
2927+/**
2928+ * gsd_pnp_ids_new:
2929+ *
2930+ * Returns a reference to a #GsdPnpIds object, or creates
2931+ * a new one if none have been created.
2932+ *
2933+ * Returns: (transfer full): a #GsdPnpIds object.
2934+ */
2935+GsdPnpIds *
2936+gsd_pnp_ids_new (void)
2937+{
2938+ if (gsd_pnp_ids_object != NULL) {
2939+ g_object_ref (gsd_pnp_ids_object);
2940+ } else {
2941+ gsd_pnp_ids_object = g_object_new (GSD_TYPE_PNP_IDS, NULL);
2942+ g_object_add_weak_pointer (gsd_pnp_ids_object, &gsd_pnp_ids_object);
2943+ }
2944+ return GSD_PNP_IDS (gsd_pnp_ids_object);
2945+}
2946+
2947
2948=== added file 'gnome-settings-daemon/gsd-pnp-ids.h'
2949--- gnome-settings-daemon/gsd-pnp-ids.h 1970-01-01 00:00:00 +0000
2950+++ gnome-settings-daemon/gsd-pnp-ids.h 2014-08-29 10:24:26 +0000
2951@@ -0,0 +1,58 @@
2952+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2953+ *
2954+ * Copyright (C) 2009-2010 Richard Hughes <richard@hughsie.com>
2955+ *
2956+ * This program is free software; you can redistribute it and/or modify
2957+ * it under the terms of the GNU General Public License as published by
2958+ * the Free Software Foundation; either version 2 of the License, or
2959+ * (at your option) any later version.
2960+ *
2961+ * This program is distributed in the hope that it will be useful,
2962+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2963+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2964+ * GNU General Public License for more details.
2965+ *
2966+ * You should have received a copy of the GNU General Public License
2967+ * along with this program; if not, write to the Free Software
2968+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2969+ */
2970+
2971+#ifndef __GSD_PNP_IDS_H
2972+#define __GSD_PNP_IDS_H
2973+
2974+#include <glib-object.h>
2975+
2976+G_BEGIN_DECLS
2977+
2978+#define GSD_TYPE_PNP_IDS (gsd_pnp_ids_get_type ())
2979+#define GSD_PNP_IDS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_PNP_IDS, GsdPnpIds))
2980+#define GSD_PNP_IDS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_PNP_IDS, GsdPnpIdsClass))
2981+#define GSD_IS_PNP_IDS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_PNP_IDS))
2982+#define GSD_IS_PNP_IDS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_PNP_IDS))
2983+#define GSD_PNP_IDS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_PNP_IDS, GsdPnpIdsClass))
2984+#define GSD_PNP_IDS_ERROR (gsd_pnp_ids_error_quark ())
2985+
2986+typedef struct _GsdPnpIdsPrivate GsdPnpIdsPrivate;
2987+typedef struct _GsdPnpIds GsdPnpIds;
2988+typedef struct _GsdPnpIdsClass GsdPnpIdsClass;
2989+
2990+struct _GsdPnpIds
2991+{
2992+ GObject parent;
2993+ GsdPnpIdsPrivate *priv;
2994+};
2995+
2996+struct _GsdPnpIdsClass
2997+{
2998+ GObjectClass parent_class;
2999+};
3000+
3001+GType gsd_pnp_ids_get_type (void);
3002+GsdPnpIds *gsd_pnp_ids_new (void);
3003+gchar *gsd_pnp_ids_get_pnp_id (GsdPnpIds *pnp_ids,
3004+ const gchar *pnp_id);
3005+
3006+G_END_DECLS
3007+
3008+#endif /* __GSD_PNP_IDS_H */
3009+
3010
3011=== added file 'gnome-settings-daemon/gsd-rr-config.c'
3012--- gnome-settings-daemon/gsd-rr-config.c 1970-01-01 00:00:00 +0000
3013+++ gnome-settings-daemon/gsd-rr-config.c 2014-08-29 10:24:26 +0000
3014@@ -0,0 +1,2091 @@
3015+/* gnome-rr-config.c
3016+ * -*- c-basic-offset: 4 -*-
3017+ *
3018+ * Copyright 2007, 2008, Red Hat, Inc.
3019+ * Copyright 2010 Giovanni Campagna
3020+ *
3021+ * This file is part of the Gnome Library.
3022+ *
3023+ * The Gnome Library is free software; you can redistribute it and/or
3024+ * modify it under the terms of the GNU Library General Public License as
3025+ * published by the Free Software Foundation; either version 2 of the
3026+ * License, or (at your option) any later version.
3027+ *
3028+ * The Gnome Library is distributed in the hope that it will be useful,
3029+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3030+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3031+ * Library General Public License for more details.
3032+ *
3033+ * You should have received a copy of the GNU Library General Public
3034+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
3035+ * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
3036+ * Boston, MA 02110-1301, USA.
3037+ *
3038+ * Author: Soren Sandmann <sandmann@redhat.com>
3039+ */
3040+
3041+#include <config.h>
3042+#include <glib/gi18n-lib.h>
3043+#include <stdlib.h>
3044+#include <string.h>
3045+#include <glib.h>
3046+#include <glib/gstdio.h>
3047+
3048+#include <X11/Xlib.h>
3049+#include <gdk/gdkx.h>
3050+
3051+#include <unistd.h>
3052+#include <sys/wait.h>
3053+#include <signal.h>
3054+
3055+#include "gsd-rr-config.h"
3056+
3057+#include "edid.h"
3058+#include "gsd-rr-private.h"
3059+
3060+#define CONFIG_INTENDED_BASENAME "monitors.xml"
3061+#define CONFIG_BACKUP_BASENAME "monitors.xml.backup"
3062+
3063+/* Look for DPI_FALLBACK in:
3064+ * http://git.gnome.org/browse/gnome-settings-daemon/tree/plugins/xsettings/gsd-xsettings-manager.c
3065+ * for the reasoning */
3066+#define DPI_FALLBACK 96.0
3067+
3068+/* In version 0 of the config file format, we had several <configuration>
3069+ * toplevel elements and no explicit version number. So, the filed looked
3070+ * like
3071+ *
3072+ * <configuration>
3073+ * ...
3074+ * </configuration>
3075+ * <configuration>
3076+ * ...
3077+ * </configuration>
3078+ *
3079+ * Since version 1 of the config file, the file has a toplevel <monitors>
3080+ * element to group all the configurations. That element has a "version"
3081+ * attribute which is an integer. So, the file looks like this:
3082+ *
3083+ * <monitors version="1">
3084+ * <configuration>
3085+ * ...
3086+ * </configuration>
3087+ * <configuration>
3088+ * ...
3089+ * </configuration>
3090+ * </monitors>
3091+ */
3092+
3093+/* A helper wrapper around the GMarkup parser stuff */
3094+static gboolean parse_file_gmarkup (const gchar *file,
3095+ const GMarkupParser *parser,
3096+ gpointer data,
3097+ GError **err);
3098+
3099+typedef struct CrtcAssignment CrtcAssignment;
3100+
3101+static gboolean crtc_assignment_apply (CrtcAssignment *assign,
3102+ guint32 timestamp,
3103+ GError **error);
3104+static CrtcAssignment *crtc_assignment_new (GsdRRScreen *screen,
3105+ GsdRROutputInfo **outputs,
3106+ GError **error);
3107+static void crtc_assignment_free (CrtcAssignment *assign);
3108+
3109+enum {
3110+ PROP_0,
3111+ PROP_SCREEN,
3112+ PROP_LAST
3113+};
3114+
3115+G_DEFINE_TYPE (GsdRRConfig, gsd_rr_config, G_TYPE_OBJECT)
3116+
3117+typedef struct Parser Parser;
3118+
3119+/* Parser for monitor configurations */
3120+struct Parser
3121+{
3122+ int config_file_version;
3123+ GsdRROutputInfo * output;
3124+ GsdRRConfig * configuration;
3125+ GPtrArray * outputs;
3126+ GPtrArray * configurations;
3127+ GQueue * stack;
3128+};
3129+
3130+static int
3131+parse_int (const char *text)
3132+{
3133+ return strtol (text, NULL, 0);
3134+}
3135+
3136+static guint
3137+parse_uint (const char *text)
3138+{
3139+ return strtoul (text, NULL, 0);
3140+}
3141+
3142+static gboolean
3143+stack_is (Parser *parser,
3144+ const char *s1,
3145+ ...)
3146+{
3147+ GList *stack = NULL;
3148+ const char *s;
3149+ GList *l1, *l2;
3150+ va_list args;
3151+
3152+ stack = g_list_prepend (stack, (gpointer)s1);
3153+
3154+ va_start (args, s1);
3155+
3156+ s = va_arg (args, const char *);
3157+ while (s)
3158+ {
3159+ stack = g_list_prepend (stack, (gpointer)s);
3160+ s = va_arg (args, const char *);
3161+ }
3162+
3163+ l1 = stack;
3164+ l2 = parser->stack->head;
3165+
3166+ while (l1 && l2)
3167+ {
3168+ if (strcmp (l1->data, l2->data) != 0)
3169+ {
3170+ g_list_free (stack);
3171+ return FALSE;
3172+ }
3173+
3174+ l1 = l1->next;
3175+ l2 = l2->next;
3176+ }
3177+
3178+ g_list_free (stack);
3179+
3180+ return (!l1 && !l2);
3181+}
3182+
3183+static void
3184+handle_start_element (GMarkupParseContext *context,
3185+ const gchar *name,
3186+ const gchar **attr_names,
3187+ const gchar **attr_values,
3188+ gpointer user_data,
3189+ GError **err)
3190+{
3191+ Parser *parser = user_data;
3192+
3193+ if (strcmp (name, "output") == 0)
3194+ {
3195+ int i;
3196+ g_assert (parser->output == NULL);
3197+
3198+ parser->output = g_object_new (GSD_TYPE_RR_OUTPUT_INFO, NULL);
3199+ parser->output->priv->rotation = 0;
3200+
3201+ for (i = 0; attr_names[i] != NULL; ++i)
3202+ {
3203+ if (strcmp (attr_names[i], "name") == 0)
3204+ {
3205+ parser->output->priv->name = g_strdup (attr_values[i]);
3206+ break;
3207+ }
3208+ }
3209+
3210+ if (!parser->output->priv->name)
3211+ {
3212+ /* This really shouldn't happen, but it's better to make
3213+ * something up than to crash later.
3214+ */
3215+ g_warning ("Malformed monitor configuration file");
3216+
3217+ parser->output->priv->name = g_strdup ("default");
3218+ }
3219+ parser->output->priv->connected = FALSE;
3220+ parser->output->priv->on = FALSE;
3221+ parser->output->priv->primary = FALSE;
3222+ }
3223+ else if (strcmp (name, "configuration") == 0)
3224+ {
3225+ g_assert (parser->configuration == NULL);
3226+
3227+ parser->configuration = g_object_new (GSD_TYPE_RR_CONFIG, NULL);
3228+ parser->configuration->priv->clone = FALSE;
3229+ parser->configuration->priv->outputs = NULL;
3230+ }
3231+ else if (strcmp (name, "monitors") == 0)
3232+ {
3233+ int i;
3234+
3235+ for (i = 0; attr_names[i] != NULL; i++)
3236+ {
3237+ if (strcmp (attr_names[i], "version") == 0)
3238+ {
3239+ parser->config_file_version = parse_int (attr_values[i]);
3240+ break;
3241+ }
3242+ }
3243+ }
3244+
3245+ g_queue_push_tail (parser->stack, g_strdup (name));
3246+}
3247+
3248+static void
3249+handle_end_element (GMarkupParseContext *context,
3250+ const gchar *name,
3251+ gpointer user_data,
3252+ GError **err)
3253+{
3254+ Parser *parser = user_data;
3255+
3256+ if (strcmp (name, "output") == 0)
3257+ {
3258+ /* If no rotation properties were set, just use GSD_RR_ROTATION_0 */
3259+ if (parser->output->priv->rotation == 0)
3260+ parser->output->priv->rotation = GSD_RR_ROTATION_0;
3261+
3262+ g_ptr_array_add (parser->outputs, parser->output);
3263+
3264+ parser->output = NULL;
3265+ }
3266+ else if (strcmp (name, "configuration") == 0)
3267+ {
3268+ g_ptr_array_add (parser->outputs, NULL);
3269+ parser->configuration->priv->outputs =
3270+ (GsdRROutputInfo **)g_ptr_array_free (parser->outputs, FALSE);
3271+ parser->outputs = g_ptr_array_new ();
3272+ g_ptr_array_add (parser->configurations, parser->configuration);
3273+ parser->configuration = NULL;
3274+ }
3275+
3276+ g_free (g_queue_pop_tail (parser->stack));
3277+}
3278+
3279+#define TOPLEVEL_ELEMENT (parser->config_file_version > 0 ? "monitors" : NULL)
3280+
3281+static void
3282+handle_text (GMarkupParseContext *context,
3283+ const gchar *text,
3284+ gsize text_len,
3285+ gpointer user_data,
3286+ GError **err)
3287+{
3288+ Parser *parser = user_data;
3289+
3290+ if (stack_is (parser, "vendor", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
3291+ {
3292+ parser->output->priv->connected = TRUE;
3293+
3294+ strncpy ((gchar*) parser->output->priv->vendor, text, 3);
3295+ parser->output->priv->vendor[3] = 0;
3296+ }
3297+ else if (stack_is (parser, "clone", "configuration", TOPLEVEL_ELEMENT, NULL))
3298+ {
3299+ if (strcmp (text, "yes") == 0)
3300+ parser->configuration->priv->clone = TRUE;
3301+ }
3302+ else if (stack_is (parser, "product", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
3303+ {
3304+ parser->output->priv->connected = TRUE;
3305+
3306+ parser->output->priv->product = parse_int (text);
3307+ }
3308+ else if (stack_is (parser, "serial", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
3309+ {
3310+ parser->output->priv->connected = TRUE;
3311+
3312+ parser->output->priv->serial = parse_uint (text);
3313+ }
3314+ else if (stack_is (parser, "width", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
3315+ {
3316+ parser->output->priv->on = TRUE;
3317+
3318+ parser->output->priv->width = parse_int (text);
3319+ }
3320+ else if (stack_is (parser, "x", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
3321+ {
3322+ parser->output->priv->on = TRUE;
3323+
3324+ parser->output->priv->x = parse_int (text);
3325+ }
3326+ else if (stack_is (parser, "y", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
3327+ {
3328+ parser->output->priv->on = TRUE;
3329+
3330+ parser->output->priv->y = parse_int (text);
3331+ }
3332+ else if (stack_is (parser, "height", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
3333+ {
3334+ parser->output->priv->on = TRUE;
3335+
3336+ parser->output->priv->height = parse_int (text);
3337+ }
3338+ else if (stack_is (parser, "rate", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
3339+ {
3340+ parser->output->priv->on = TRUE;
3341+
3342+ parser->output->priv->rate = parse_int (text);
3343+ }
3344+ else if (stack_is (parser, "rotation", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
3345+ {
3346+ if (strcmp (text, "normal") == 0)
3347+ {
3348+ parser->output->priv->rotation |= GSD_RR_ROTATION_0;
3349+ }
3350+ else if (strcmp (text, "left") == 0)
3351+ {
3352+ parser->output->priv->rotation |= GSD_RR_ROTATION_90;
3353+ }
3354+ else if (strcmp (text, "upside_down") == 0)
3355+ {
3356+ parser->output->priv->rotation |= GSD_RR_ROTATION_180;
3357+ }
3358+ else if (strcmp (text, "right") == 0)
3359+ {
3360+ parser->output->priv->rotation |= GSD_RR_ROTATION_270;
3361+ }
3362+ }
3363+ else if (stack_is (parser, "reflect_x", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
3364+ {
3365+ if (strcmp (text, "yes") == 0)
3366+ {
3367+ parser->output->priv->rotation |= GSD_RR_REFLECT_X;
3368+ }
3369+ }
3370+ else if (stack_is (parser, "reflect_y", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
3371+ {
3372+ if (strcmp (text, "yes") == 0)
3373+ {
3374+ parser->output->priv->rotation |= GSD_RR_REFLECT_Y;
3375+ }
3376+ }
3377+ else if (stack_is (parser, "primary", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
3378+ {
3379+ if (strcmp (text, "yes") == 0)
3380+ {
3381+ parser->output->priv->primary = TRUE;
3382+ }
3383+ }
3384+ else
3385+ {
3386+ /* Ignore other properties so we can expand the format in the future */
3387+ }
3388+}
3389+
3390+static void
3391+parser_free (Parser *parser)
3392+{
3393+ int i;
3394+ GList *list;
3395+
3396+ g_assert (parser != NULL);
3397+
3398+ if (parser->output)
3399+ g_object_unref (parser->output);
3400+
3401+ if (parser->configuration)
3402+ g_object_unref (parser->configuration);
3403+
3404+ for (i = 0; i < parser->outputs->len; ++i)
3405+ {
3406+ GsdRROutputInfo *output = parser->outputs->pdata[i];
3407+
3408+ g_object_unref (output);
3409+ }
3410+
3411+ g_ptr_array_free (parser->outputs, TRUE);
3412+
3413+ for (i = 0; i < parser->configurations->len; ++i)
3414+ {
3415+ GsdRRConfig *config = parser->configurations->pdata[i];
3416+
3417+ g_object_unref (config);
3418+ }
3419+
3420+ g_ptr_array_free (parser->configurations, TRUE);
3421+
3422+ for (list = parser->stack->head; list; list = list->next)
3423+ g_free (list->data);
3424+ g_queue_free (parser->stack);
3425+
3426+ g_free (parser);
3427+}
3428+
3429+static GsdRRConfig **
3430+configurations_read_from_file (const gchar *filename, GError **error)
3431+{
3432+ Parser *parser = g_new0 (Parser, 1);
3433+ GsdRRConfig **result;
3434+ GMarkupParser callbacks = {
3435+ handle_start_element,
3436+ handle_end_element,
3437+ handle_text,
3438+ NULL, /* passthrough */
3439+ NULL, /* error */
3440+ };
3441+
3442+ parser->config_file_version = 0;
3443+ parser->configurations = g_ptr_array_new ();
3444+ parser->outputs = g_ptr_array_new ();
3445+ parser->stack = g_queue_new ();
3446+
3447+ if (!parse_file_gmarkup (filename, &callbacks, parser, error))
3448+ {
3449+ result = NULL;
3450+
3451+ g_assert (parser->outputs);
3452+ goto out;
3453+ }
3454+
3455+ g_assert (parser->outputs);
3456+
3457+ g_ptr_array_add (parser->configurations, NULL);
3458+ result = (GsdRRConfig **)g_ptr_array_free (parser->configurations, FALSE);
3459+ parser->configurations = g_ptr_array_new ();
3460+
3461+ g_assert (parser->outputs);
3462+out:
3463+ parser_free (parser);
3464+
3465+ return result;
3466+}
3467+
3468+static void
3469+gsd_rr_config_init (GsdRRConfig *self)
3470+{
3471+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GSD_TYPE_RR_CONFIG, GsdRRConfigPrivate);
3472+
3473+ self->priv->clone = FALSE;
3474+ self->priv->screen = NULL;
3475+ self->priv->outputs = NULL;
3476+}
3477+
3478+static void
3479+gsd_rr_config_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *property)
3480+{
3481+ GsdRRConfig *self = GSD_RR_CONFIG (gobject);
3482+
3483+ switch (property_id) {
3484+ case PROP_SCREEN:
3485+ self->priv->screen = g_value_dup_object (value);
3486+ return;
3487+ default:
3488+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, property);
3489+ }
3490+}
3491+
3492+static void
3493+gsd_rr_config_finalize (GObject *gobject)
3494+{
3495+ GsdRRConfig *self = GSD_RR_CONFIG (gobject);
3496+
3497+ if (self->priv->screen)
3498+ g_object_unref (self->priv->screen);
3499+
3500+ if (self->priv->outputs) {
3501+ int i;
3502+
3503+ for (i = 0; self->priv->outputs[i] != NULL; i++) {
3504+ GsdRROutputInfo *output = self->priv->outputs[i];
3505+ g_object_unref (output);
3506+ }
3507+ g_free (self->priv->outputs);
3508+ }
3509+
3510+ G_OBJECT_CLASS (gsd_rr_config_parent_class)->finalize (gobject);
3511+}
3512+
3513+gboolean
3514+gsd_rr_config_load_current (GsdRRConfig *config, GError **error)
3515+{
3516+ GPtrArray *a;
3517+ GsdRROutput **rr_outputs;
3518+ int i;
3519+ int clone_width = -1;
3520+ int clone_height = -1;
3521+ int last_x;
3522+
3523+ g_return_val_if_fail (GSD_IS_RR_CONFIG (config), FALSE);
3524+
3525+ a = g_ptr_array_new ();
3526+ rr_outputs = gsd_rr_screen_list_outputs (config->priv->screen);
3527+
3528+ config->priv->clone = FALSE;
3529+
3530+ for (i = 0; rr_outputs[i] != NULL; ++i)
3531+ {
3532+ GsdRROutput *rr_output = rr_outputs[i];
3533+ GsdRROutputInfo *output = g_object_new (GSD_TYPE_RR_OUTPUT_INFO, NULL);
3534+ GsdRRMode *mode = NULL;
3535+ const guint8 *edid_data = gsd_rr_output_get_edid_data (rr_output, NULL);
3536+ GsdRRCrtc *crtc;
3537+
3538+ output->priv->name = g_strdup (gsd_rr_output_get_name (rr_output));
3539+ output->priv->connected = gsd_rr_output_is_connected (rr_output);
3540+ output->priv->display_name = g_strdup (gsd_rr_output_get_display_name (rr_output));
3541+
3542+ if (!output->priv->connected)
3543+ {
3544+ output->priv->x = -1;
3545+ output->priv->y = -1;
3546+ output->priv->width = -1;
3547+ output->priv->height = -1;
3548+ output->priv->rate = -1;
3549+ output->priv->rotation = GSD_RR_ROTATION_0;
3550+ }
3551+ else
3552+ {
3553+ MonitorInfo *info = NULL;
3554+
3555+ if (edid_data)
3556+ info = decode_edid (edid_data);
3557+
3558+ if (info)
3559+ {
3560+ memcpy (output->priv->vendor, info->manufacturer_code,
3561+ sizeof (output->priv->vendor));
3562+
3563+ output->priv->product = info->product_code;
3564+ output->priv->serial = info->serial_number;
3565+ output->priv->aspect = info->aspect_ratio;
3566+ }
3567+ else
3568+ {
3569+ strcpy (output->priv->vendor, "???");
3570+ output->priv->product = 0;
3571+ output->priv->serial = 0;
3572+ }
3573+ g_free (info);
3574+
3575+ crtc = gsd_rr_output_get_crtc (rr_output);
3576+ mode = crtc? gsd_rr_crtc_get_current_mode (crtc) : NULL;
3577+
3578+ if (crtc && mode)
3579+ {
3580+ output->priv->on = TRUE;
3581+
3582+ gsd_rr_crtc_get_position (crtc, &output->priv->x, &output->priv->y);
3583+ output->priv->width = gsd_rr_mode_get_width (mode);
3584+ output->priv->height = gsd_rr_mode_get_height (mode);
3585+ output->priv->rate = gsd_rr_mode_get_freq (mode);
3586+ output->priv->rotation = gsd_rr_crtc_get_current_rotation (crtc);
3587+
3588+ if (output->priv->x == 0 && output->priv->y == 0) {
3589+ if (clone_width == -1) {
3590+ clone_width = output->priv->width;
3591+ clone_height = output->priv->height;
3592+ } else if (clone_width == output->priv->width &&
3593+ clone_height == output->priv->height) {
3594+ config->priv->clone = TRUE;
3595+ }
3596+ }
3597+ }
3598+ else
3599+ {
3600+ output->priv->on = FALSE;
3601+ config->priv->clone = FALSE;
3602+ }
3603+
3604+ /* Get preferred size for the monitor */
3605+ mode = gsd_rr_output_get_preferred_mode (rr_output);
3606+
3607+ if (!mode)
3608+ {
3609+ GsdRRMode **modes = gsd_rr_output_list_modes (rr_output);
3610+
3611+ /* FIXME: we should pick the "best" mode here, where best is
3612+ * sorted wrt
3613+ *
3614+ * - closest aspect ratio
3615+ * - mode area
3616+ * - refresh rate
3617+ * - We may want to extend randrwrap so that get_preferred
3618+ * returns that - although that could also depend on
3619+ * the crtc.
3620+ */
3621+ if (modes[0])
3622+ mode = modes[0];
3623+ }
3624+
3625+ if (mode)
3626+ {
3627+ output->priv->pref_width = gsd_rr_mode_get_width (mode);
3628+ output->priv->pref_height = gsd_rr_mode_get_height (mode);
3629+ }
3630+ else
3631+ {
3632+ /* Pick some random numbers. This should basically never happen */
3633+ output->priv->pref_width = 1024;
3634+ output->priv->pref_height = 768;
3635+ }
3636+ }
3637+
3638+ output->priv->primary = gsd_rr_output_get_is_primary (rr_output);
3639+
3640+ g_ptr_array_add (a, output);
3641+ }
3642+
3643+ g_ptr_array_add (a, NULL);
3644+
3645+ config->priv->outputs = (GsdRROutputInfo **)g_ptr_array_free (a, FALSE);
3646+
3647+ /* Walk the outputs computing the right-most edge of all
3648+ * lit-up displays
3649+ */
3650+ last_x = 0;
3651+ for (i = 0; config->priv->outputs[i] != NULL; ++i)
3652+ {
3653+ GsdRROutputInfo *output = config->priv->outputs[i];
3654+
3655+ if (output->priv->on)
3656+ {
3657+ last_x = MAX (last_x, output->priv->x + output->priv->width);
3658+ }
3659+ }
3660+
3661+ /* Now position all off displays to the right of the
3662+ * on displays
3663+ */
3664+ for (i = 0; config->priv->outputs[i] != NULL; ++i)
3665+ {
3666+ GsdRROutputInfo *output = config->priv->outputs[i];
3667+
3668+ if (output->priv->connected && !output->priv->on)
3669+ {
3670+ output->priv->x = last_x;
3671+ last_x = output->priv->x + output->priv->width;
3672+ }
3673+ }
3674+
3675+ g_assert (gsd_rr_config_match (config, config));
3676+
3677+ return TRUE;
3678+}
3679+
3680+gboolean
3681+gsd_rr_config_load_filename (GsdRRConfig *result, const char *filename, GError **error)
3682+{
3683+ GsdRRConfig *current;
3684+ GsdRRConfig **configs;
3685+ gboolean found = FALSE;
3686+
3687+ g_return_val_if_fail (GSD_IS_RR_CONFIG (result), FALSE);
3688+ g_return_val_if_fail (filename != NULL, FALSE);
3689+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
3690+
3691+ current = gsd_rr_config_new_current (result->priv->screen, error);
3692+
3693+ configs = configurations_read_from_file (filename, error);
3694+
3695+ if (configs)
3696+ {
3697+ int i;
3698+
3699+ for (i = 0; configs[i] != NULL; ++i)
3700+ {
3701+ if (gsd_rr_config_match (configs[i], current))
3702+ {
3703+ int j;
3704+ GPtrArray *array;
3705+ result->priv->clone = configs[i]->priv->clone;
3706+
3707+ array = g_ptr_array_new ();
3708+ for (j = 0; configs[i]->priv->outputs[j] != NULL; j++) {
3709+ g_object_ref (configs[i]->priv->outputs[j]);
3710+ g_ptr_array_add (array, configs[i]->priv->outputs[j]);
3711+ }
3712+ g_ptr_array_add (array, NULL);
3713+ result->priv->outputs = (GsdRROutputInfo **) g_ptr_array_free (array, FALSE);
3714+
3715+ found = TRUE;
3716+ break;
3717+ }
3718+ g_object_unref (configs[i]);
3719+ }
3720+ g_free (configs);
3721+
3722+ if (!found)
3723+ g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_NO_MATCHING_CONFIG,
3724+ _("none of the saved display configurations matched the active configuration"));
3725+ }
3726+
3727+ g_object_unref (current);
3728+ return found;
3729+}
3730+
3731+static void
3732+gsd_rr_config_class_init (GsdRRConfigClass *klass)
3733+{
3734+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3735+
3736+ g_type_class_add_private (klass, sizeof (GsdRROutputInfoPrivate));
3737+
3738+ gobject_class->set_property = gsd_rr_config_set_property;
3739+ gobject_class->finalize = gsd_rr_config_finalize;
3740+
3741+ g_object_class_install_property (gobject_class, PROP_SCREEN,
3742+ g_param_spec_object ("screen", "Screen", "The GsdRRScreen this config applies to", GSD_TYPE_RR_SCREEN,
3743+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
3744+}
3745+
3746+GsdRRConfig *
3747+gsd_rr_config_new_current (GsdRRScreen *screen, GError **error)
3748+{
3749+ GsdRRConfig *self = g_object_new (GSD_TYPE_RR_CONFIG, "screen", screen, NULL);
3750+
3751+ if (gsd_rr_config_load_current (self, error))
3752+ return self;
3753+ else
3754+ {
3755+ g_object_unref (self);
3756+ return NULL;
3757+ }
3758+}
3759+
3760+GsdRRConfig *
3761+gsd_rr_config_new_stored (GsdRRScreen *screen, GError **error)
3762+{
3763+ GsdRRConfig *self = g_object_new (GSD_TYPE_RR_CONFIG, "screen", screen, NULL);
3764+ char *filename;
3765+ gboolean success;
3766+
3767+ filename = gsd_rr_config_get_intended_filename ();
3768+
3769+ success = gsd_rr_config_load_filename (self, filename, error);
3770+
3771+ g_free (filename);
3772+
3773+ if (success)
3774+ return self;
3775+ else
3776+ {
3777+ g_object_unref (self);
3778+ return NULL;
3779+ }
3780+}
3781+
3782+static gboolean
3783+parse_file_gmarkup (const gchar *filename,
3784+ const GMarkupParser *parser,
3785+ gpointer data,
3786+ GError **err)
3787+{
3788+ GMarkupParseContext *context = NULL;
3789+ gchar *contents = NULL;
3790+ gboolean result = TRUE;
3791+ gsize len;
3792+
3793+ if (!g_file_get_contents (filename, &contents, &len, err))
3794+ {
3795+ result = FALSE;
3796+ goto out;
3797+ }
3798+
3799+ context = g_markup_parse_context_new (parser, 0, data, NULL);
3800+
3801+ if (!g_markup_parse_context_parse (context, contents, len, err))
3802+ {
3803+ result = FALSE;
3804+ goto out;
3805+ }
3806+
3807+ if (!g_markup_parse_context_end_parse (context, err))
3808+ {
3809+ result = FALSE;
3810+ goto out;
3811+ }
3812+
3813+out:
3814+ if (contents)
3815+ g_free (contents);
3816+
3817+ if (context)
3818+ g_markup_parse_context_free (context);
3819+
3820+ return result;
3821+}
3822+
3823+static gboolean
3824+output_match (GsdRROutputInfo *output1, GsdRROutputInfo *output2)
3825+{
3826+ g_assert (GSD_IS_RR_OUTPUT_INFO (output1));
3827+ g_assert (GSD_IS_RR_OUTPUT_INFO (output2));
3828+
3829+ if (strcmp (output1->priv->name, output2->priv->name) != 0)
3830+ return FALSE;
3831+
3832+ if (strcmp (output1->priv->vendor, output2->priv->vendor) != 0)
3833+ return FALSE;
3834+
3835+ if (output1->priv->product != output2->priv->product)
3836+ return FALSE;
3837+
3838+ if (output1->priv->serial != output2->priv->serial)
3839+ return FALSE;
3840+
3841+ if (output1->priv->connected != output2->priv->connected)
3842+ return FALSE;
3843+
3844+ return TRUE;
3845+}
3846+
3847+static gboolean
3848+output_equal (GsdRROutputInfo *output1, GsdRROutputInfo *output2)
3849+{
3850+ g_assert (GSD_IS_RR_OUTPUT_INFO (output1));
3851+ g_assert (GSD_IS_RR_OUTPUT_INFO (output2));
3852+
3853+ if (!output_match (output1, output2))
3854+ return FALSE;
3855+
3856+ if (output1->priv->on != output2->priv->on)
3857+ return FALSE;
3858+
3859+ if (output1->priv->on)
3860+ {
3861+ if (output1->priv->width != output2->priv->width)
3862+ return FALSE;
3863+
3864+ if (output1->priv->height != output2->priv->height)
3865+ return FALSE;
3866+
3867+ if (output1->priv->rate != output2->priv->rate)
3868+ return FALSE;
3869+
3870+ if (output1->priv->x != output2->priv->x)
3871+ return FALSE;
3872+
3873+ if (output1->priv->y != output2->priv->y)
3874+ return FALSE;
3875+
3876+ if (output1->priv->rotation != output2->priv->rotation)
3877+ return FALSE;
3878+ }
3879+
3880+ return TRUE;
3881+}
3882+
3883+static GsdRROutputInfo *
3884+find_output (GsdRRConfig *config, const char *name)
3885+{
3886+ int i;
3887+
3888+ for (i = 0; config->priv->outputs[i] != NULL; ++i)
3889+ {
3890+ GsdRROutputInfo *output = config->priv->outputs[i];
3891+
3892+ if (strcmp (name, output->priv->name) == 0)
3893+ return output;
3894+ }
3895+
3896+ return NULL;
3897+}
3898+
3899+/* Match means "these configurations apply to the same hardware
3900+ * setups"
3901+ */
3902+gboolean
3903+gsd_rr_config_match (GsdRRConfig *c1, GsdRRConfig *c2)
3904+{
3905+ int i;
3906+ g_return_val_if_fail (GSD_IS_RR_CONFIG (c1), FALSE);
3907+ g_return_val_if_fail (GSD_IS_RR_CONFIG (c2), FALSE);
3908+
3909+ for (i = 0; c1->priv->outputs[i] != NULL; ++i)
3910+ {
3911+ GsdRROutputInfo *output1 = c1->priv->outputs[i];
3912+ GsdRROutputInfo *output2;
3913+
3914+ output2 = find_output (c2, output1->priv->name);
3915+ if (!output2 || !output_match (output1, output2))
3916+ return FALSE;
3917+ }
3918+
3919+ return TRUE;
3920+}
3921+
3922+/* Equal means "the configurations will result in the same
3923+ * modes being set on the outputs"
3924+ */
3925+gboolean
3926+gsd_rr_config_equal (GsdRRConfig *c1,
3927+ GsdRRConfig *c2)
3928+{
3929+ int i;
3930+ g_return_val_if_fail (GSD_IS_RR_CONFIG (c1), FALSE);
3931+ g_return_val_if_fail (GSD_IS_RR_CONFIG (c2), FALSE);
3932+
3933+ for (i = 0; c1->priv->outputs[i] != NULL; ++i)
3934+ {
3935+ GsdRROutputInfo *output1 = c1->priv->outputs[i];
3936+ GsdRROutputInfo *output2;
3937+
3938+ output2 = find_output (c2, output1->priv->name);
3939+ if (!output2 || !output_equal (output1, output2))
3940+ return FALSE;
3941+ }
3942+
3943+ return TRUE;
3944+}
3945+
3946+static GsdRROutputInfo **
3947+make_outputs (GsdRRConfig *config)
3948+{
3949+ GPtrArray *outputs;
3950+ GsdRROutputInfo *first_on;
3951+ int i;
3952+
3953+ outputs = g_ptr_array_new ();
3954+
3955+ first_on = NULL;
3956+
3957+ for (i = 0; config->priv->outputs[i] != NULL; ++i)
3958+ {
3959+ GsdRROutputInfo *old = config->priv->outputs[i];
3960+ GsdRROutputInfo *new = g_object_new (GSD_TYPE_RR_OUTPUT_INFO, NULL);
3961+ *(new->priv) = *(old->priv);
3962+ if (old->priv->name)
3963+ new->priv->name = g_strdup (old->priv->name);
3964+ if (old->priv->display_name)
3965+ new->priv->display_name = g_strdup (old->priv->display_name);
3966+
3967+ if (old->priv->on && !first_on)
3968+ first_on = old;
3969+
3970+ if (config->priv->clone && new->priv->on)
3971+ {
3972+ g_assert (first_on);
3973+
3974+ new->priv->width = first_on->priv->width;
3975+ new->priv->height = first_on->priv->height;
3976+ new->priv->rotation = first_on->priv->rotation;
3977+ new->priv->x = 0;
3978+ new->priv->y = 0;
3979+ }
3980+
3981+ g_ptr_array_add (outputs, new);
3982+ }
3983+
3984+ g_ptr_array_add (outputs, NULL);
3985+
3986+ return (GsdRROutputInfo **)g_ptr_array_free (outputs, FALSE);
3987+}
3988+
3989+gboolean
3990+gsd_rr_config_applicable (GsdRRConfig *configuration,
3991+ GsdRRScreen *screen,
3992+ GError **error)
3993+{
3994+ GsdRROutputInfo **outputs;
3995+ CrtcAssignment *assign;
3996+ gboolean result;
3997+ int i;
3998+
3999+ g_return_val_if_fail (GSD_IS_RR_CONFIG (configuration), FALSE);
4000+ g_return_val_if_fail (GSD_IS_RR_SCREEN (screen), FALSE);
4001+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
4002+
4003+ outputs = make_outputs (configuration);
4004+ assign = crtc_assignment_new (screen, outputs, error);
4005+
4006+ if (assign)
4007+ {
4008+ result = TRUE;
4009+ crtc_assignment_free (assign);
4010+ }
4011+ else
4012+ {
4013+ result = FALSE;
4014+ }
4015+
4016+ for (i = 0; outputs[i] != NULL; i++) {
4017+ g_object_unref (outputs[i]);
4018+ }
4019+
4020+ return result;
4021+}
4022+
4023+/* Database management */
4024+
4025+static void
4026+ensure_config_directory (void)
4027+{
4028+ g_mkdir_with_parents (g_get_user_config_dir (), 0700);
4029+}
4030+
4031+char *
4032+gsd_rr_config_get_backup_filename (void)
4033+{
4034+ ensure_config_directory ();
4035+ return g_build_filename (g_get_user_config_dir (), CONFIG_BACKUP_BASENAME, NULL);
4036+}
4037+
4038+char *
4039+gsd_rr_config_get_intended_filename (void)
4040+{
4041+ ensure_config_directory ();
4042+ return g_build_filename (g_get_user_config_dir (), CONFIG_INTENDED_BASENAME, NULL);
4043+}
4044+
4045+static const char *
4046+get_rotation_name (GsdRRRotation r)
4047+{
4048+ if (r & GSD_RR_ROTATION_0)
4049+ return "normal";
4050+ if (r & GSD_RR_ROTATION_90)
4051+ return "left";
4052+ if (r & GSD_RR_ROTATION_180)
4053+ return "upside_down";
4054+ if (r & GSD_RR_ROTATION_270)
4055+ return "right";
4056+
4057+ return "normal";
4058+}
4059+
4060+static const char *
4061+yes_no (int x)
4062+{
4063+ return x? "yes" : "no";
4064+}
4065+
4066+static const char *
4067+get_reflect_x (GsdRRRotation r)
4068+{
4069+ return yes_no (r & GSD_RR_REFLECT_X);
4070+}
4071+
4072+static const char *
4073+get_reflect_y (GsdRRRotation r)
4074+{
4075+ return yes_no (r & GSD_RR_REFLECT_Y);
4076+}
4077+
4078+static void
4079+emit_configuration (GsdRRConfig *config,
4080+ GString *string)
4081+{
4082+ int j;
4083+
4084+ g_string_append_printf (string, " <configuration>\n");
4085+
4086+ g_string_append_printf (string, " <clone>%s</clone>\n", yes_no (config->priv->clone));
4087+
4088+ for (j = 0; config->priv->outputs[j] != NULL; ++j)
4089+ {
4090+ GsdRROutputInfo *output = config->priv->outputs[j];
4091+
4092+ g_string_append_printf (
4093+ string, " <output name=\"%s\">\n", output->priv->name);
4094+
4095+ if (output->priv->connected && *output->priv->vendor != '\0')
4096+ {
4097+ g_string_append_printf (
4098+ string, " <vendor>%s</vendor>\n", output->priv->vendor);
4099+ g_string_append_printf (
4100+ string, " <product>0x%04x</product>\n", output->priv->product);
4101+ g_string_append_printf (
4102+ string, " <serial>0x%08x</serial>\n", output->priv->serial);
4103+ }
4104+
4105+ /* An unconnected output which is on does not make sense */
4106+ if (output->priv->connected && output->priv->on)
4107+ {
4108+ g_string_append_printf (
4109+ string, " <width>%d</width>\n", output->priv->width);
4110+ g_string_append_printf (
4111+ string, " <height>%d</height>\n", output->priv->height);
4112+ g_string_append_printf (
4113+ string, " <rate>%d</rate>\n", output->priv->rate);
4114+ g_string_append_printf (
4115+ string, " <x>%d</x>\n", output->priv->x);
4116+ g_string_append_printf (
4117+ string, " <y>%d</y>\n", output->priv->y);
4118+ g_string_append_printf (
4119+ string, " <rotation>%s</rotation>\n", get_rotation_name (output->priv->rotation));
4120+ g_string_append_printf (
4121+ string, " <reflect_x>%s</reflect_x>\n", get_reflect_x (output->priv->rotation));
4122+ g_string_append_printf (
4123+ string, " <reflect_y>%s</reflect_y>\n", get_reflect_y (output->priv->rotation));
4124+ g_string_append_printf (
4125+ string, " <primary>%s</primary>\n", yes_no (output->priv->primary));
4126+ }
4127+
4128+ g_string_append_printf (string, " </output>\n");
4129+ }
4130+
4131+ g_string_append_printf (string, " </configuration>\n");
4132+}
4133+
4134+void
4135+gsd_rr_config_sanitize (GsdRRConfig *config)
4136+{
4137+ int i;
4138+ int x_offset, y_offset;
4139+ gboolean found;
4140+
4141+ /* Offset everything by the top/left-most coordinate to
4142+ * make sure the configuration starts at (0, 0)
4143+ */
4144+ x_offset = y_offset = G_MAXINT;
4145+ for (i = 0; config->priv->outputs[i]; ++i)
4146+ {
4147+ GsdRROutputInfo *output = config->priv->outputs[i];
4148+
4149+ if (output->priv->on)
4150+ {
4151+ x_offset = MIN (x_offset, output->priv->x);
4152+ y_offset = MIN (y_offset, output->priv->y);
4153+ }
4154+ }
4155+
4156+ for (i = 0; config->priv->outputs[i]; ++i)
4157+ {
4158+ GsdRROutputInfo *output = config->priv->outputs[i];
4159+
4160+ if (output->priv->on)
4161+ {
4162+ output->priv->x -= x_offset;
4163+ output->priv->y -= y_offset;
4164+ }
4165+ }
4166+
4167+ /* Only one primary, please */
4168+ found = FALSE;
4169+ for (i = 0; config->priv->outputs[i]; ++i)
4170+ {
4171+ if (config->priv->outputs[i]->priv->primary)
4172+ {
4173+ if (found)
4174+ {
4175+ config->priv->outputs[i]->priv->primary = FALSE;
4176+ }
4177+ else
4178+ {
4179+ found = TRUE;
4180+ }
4181+ }
4182+ }
4183+}
4184+
4185+gboolean
4186+gsd_rr_config_ensure_primary (GsdRRConfig *configuration)
4187+{
4188+ int i;
4189+ GsdRROutputInfo *laptop;
4190+ GsdRROutputInfo *top_left;
4191+ gboolean found;
4192+ GsdRRConfigPrivate *priv;
4193+
4194+ g_return_val_if_fail (GSD_IS_RR_CONFIG (configuration), FALSE);
4195+
4196+ laptop = NULL;
4197+ top_left = NULL;
4198+ found = FALSE;
4199+ priv = configuration->priv;
4200+
4201+ for (i = 0; priv->outputs[i] != NULL; ++i) {
4202+ GsdRROutputInfo *info = priv->outputs[i];
4203+
4204+ if (!info->priv->on) {
4205+ info->priv->primary = FALSE;
4206+ continue;
4207+ }
4208+
4209+ /* ensure only one */
4210+ if (info->priv->primary) {
4211+ if (found) {
4212+ info->priv->primary = FALSE;
4213+ } else {
4214+ found = TRUE;
4215+ }
4216+ }
4217+
4218+ if (top_left == NULL
4219+ || (info->priv->x < top_left->priv->x
4220+ && info->priv->y < top_left->priv->y)) {
4221+ top_left = info;
4222+ }
4223+ if (laptop == NULL
4224+ && _gsd_rr_output_name_is_laptop (info->priv->name)) {
4225+ /* shame we can't find the connector type
4226+ as with gsd_rr_output_is_laptop */
4227+ laptop = info;
4228+ }
4229+ }
4230+
4231+ if (!found) {
4232+ if (laptop != NULL) {
4233+ laptop->priv->primary = TRUE;
4234+ } else if (top_left != NULL) {
4235+ /* Note: top_left can be NULL if all outputs are off */
4236+ top_left->priv->primary = TRUE;
4237+ }
4238+ }
4239+
4240+ return !found;
4241+}
4242+
4243+gboolean
4244+gsd_rr_config_save (GsdRRConfig *configuration, GError **error)
4245+{
4246+ GsdRRConfig **configurations;
4247+ GString *output;
4248+ int i;
4249+ gchar *intended_filename;
4250+ gchar *backup_filename;
4251+ gboolean result;
4252+
4253+ g_return_val_if_fail (GSD_IS_RR_CONFIG (configuration), FALSE);
4254+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
4255+
4256+ output = g_string_new ("");
4257+
4258+ backup_filename = gsd_rr_config_get_backup_filename ();
4259+ intended_filename = gsd_rr_config_get_intended_filename ();
4260+
4261+ configurations = configurations_read_from_file (intended_filename, NULL); /* NULL-GError */
4262+
4263+ g_string_append_printf (output, "<monitors version=\"1\">\n");
4264+
4265+ if (configurations)
4266+ {
4267+ for (i = 0; configurations[i] != NULL; ++i)
4268+ {
4269+ if (!gsd_rr_config_match (configurations[i], configuration))
4270+ emit_configuration (configurations[i], output);
4271+ g_object_unref (configurations[i]);
4272+ }
4273+
4274+ g_free (configurations);
4275+ }
4276+
4277+ emit_configuration (configuration, output);
4278+
4279+ g_string_append_printf (output, "</monitors>\n");
4280+
4281+ /* backup the file first */
4282+ rename (intended_filename, backup_filename); /* no error checking because the intended file may not even exist */
4283+
4284+ result = g_file_set_contents (intended_filename, output->str, -1, error);
4285+
4286+ if (!result)
4287+ rename (backup_filename, intended_filename); /* no error checking because the backup may not even exist */
4288+
4289+ g_free (backup_filename);
4290+ g_free (intended_filename);
4291+
4292+ return result;
4293+}
4294+
4295+gboolean
4296+gsd_rr_config_apply_with_time (GsdRRConfig *config,
4297+ GsdRRScreen *screen,
4298+ guint32 timestamp,
4299+ GError **error)
4300+{
4301+ CrtcAssignment *assignment;
4302+ GsdRROutputInfo **outputs;
4303+ gboolean result = FALSE;
4304+ int i;
4305+
4306+ g_return_val_if_fail (GSD_IS_RR_CONFIG (config), FALSE);
4307+ g_return_val_if_fail (GSD_IS_RR_SCREEN (screen), FALSE);
4308+
4309+ outputs = make_outputs (config);
4310+
4311+ assignment = crtc_assignment_new (screen, outputs, error);
4312+
4313+ for (i = 0; outputs[i] != NULL; i++)
4314+ g_object_unref (outputs[i]);
4315+ g_free (outputs);
4316+
4317+ if (assignment)
4318+ {
4319+ if (crtc_assignment_apply (assignment, timestamp, error))
4320+ result = TRUE;
4321+
4322+ crtc_assignment_free (assignment);
4323+
4324+ gdk_flush ();
4325+ }
4326+
4327+ return result;
4328+}
4329+
4330+/* gsd_rr_config_apply_from_filename_with_time:
4331+ * @screen: A #GsdRRScreen
4332+ * @filename: Path of the file to look in for stored RANDR configurations.
4333+ * @timestamp: X server timestamp from the event that causes the screen configuration to change (a user's button press, for example)
4334+ * @error: Location to store error, or %NULL
4335+ *
4336+ * Loads the file in @filename and looks for suitable matching RANDR
4337+ * configurations in the file; if one is found, that configuration will be
4338+ * applied to the current set of RANDR outputs.
4339+ *
4340+ * Typically, @filename is the result of gsd_rr_config_get_intended_filename() or
4341+ * gsd_rr_config_get_backup_filename().
4342+ *
4343+ * Returns: TRUE if the RANDR configuration was loaded and applied from
4344+ * the specified file, or FALSE otherwise:
4345+ *
4346+ * If the file in question is loaded successfully but the configuration cannot
4347+ * be applied, the @error will have a domain of #GSD_RR_ERROR. Note that an
4348+ * error code of #GSD_RR_ERROR_NO_MATCHING_CONFIG is not a real error; it
4349+ * simply means that there were no stored configurations that match the current
4350+ * set of RANDR outputs.
4351+ *
4352+ * If the file in question cannot be loaded, the @error will have a domain of
4353+ * #G_FILE_ERROR. Note that an error code of G_FILE_ERROR_NOENT is not really
4354+ * an error, either; it means that there was no stored configuration file and so
4355+ * nothing is changed.
4356+ */
4357+gboolean
4358+gsd_rr_config_apply_from_filename_with_time (GsdRRScreen *screen, const char *filename, guint32 timestamp, GError **error)
4359+{
4360+ GsdRRConfig *stored;
4361+
4362+ g_return_val_if_fail (GSD_IS_RR_SCREEN (screen), FALSE);
4363+ g_return_val_if_fail (filename != NULL, FALSE);
4364+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
4365+
4366+ stored = g_object_new (GSD_TYPE_RR_CONFIG, "screen", screen, NULL);
4367+
4368+ if (gsd_rr_config_load_filename (stored, filename, error))
4369+ {
4370+ gboolean result;
4371+
4372+ gsd_rr_config_ensure_primary (stored);
4373+ result = gsd_rr_config_apply_with_time (stored, screen, timestamp, error);
4374+
4375+ g_object_unref (stored);
4376+ return result;
4377+ }
4378+ else
4379+ {
4380+ g_object_unref (stored);
4381+ return FALSE;
4382+ }
4383+}
4384+
4385+/**
4386+ * gsd_rr_config_get_outputs:
4387+ *
4388+ * Returns: (array zero-terminated=1) (element-type GnomeDesktop.RROutputInfo) (transfer none): the output configuration for this #GsdRRConfig
4389+ */
4390+GsdRROutputInfo **
4391+gsd_rr_config_get_outputs (GsdRRConfig *self)
4392+{
4393+ g_return_val_if_fail (GSD_IS_RR_CONFIG (self), NULL);
4394+
4395+ return self->priv->outputs;
4396+}
4397+
4398+/**
4399+ * gsd_rr_config_get_clone:
4400+ *
4401+ * Returns: whether at least two outputs are at (0, 0) offset and they
4402+ * have the same width/height. Those outputs are of course connected and on
4403+ * (i.e. they have a CRTC assigned).
4404+ */
4405+gboolean
4406+gsd_rr_config_get_clone (GsdRRConfig *self)
4407+{
4408+ g_return_val_if_fail (GSD_IS_RR_CONFIG (self), FALSE);
4409+
4410+ return self->priv->clone;
4411+}
4412+
4413+void
4414+gsd_rr_config_set_clone (GsdRRConfig *self, gboolean clone)
4415+{
4416+ g_return_if_fail (GSD_IS_RR_CONFIG (self));
4417+
4418+ self->priv->clone = clone;
4419+}
4420+
4421+/*
4422+ * CRTC assignment
4423+ */
4424+typedef struct CrtcInfo CrtcInfo;
4425+
4426+struct CrtcInfo
4427+{
4428+ GsdRRMode *mode;
4429+ int x;
4430+ int y;
4431+ GsdRRRotation rotation;
4432+ GPtrArray *outputs;
4433+};
4434+
4435+struct CrtcAssignment
4436+{
4437+ GsdRRScreen *screen;
4438+ GHashTable *info;
4439+ GsdRROutput *primary;
4440+};
4441+
4442+static gboolean
4443+can_clone (CrtcInfo *info,
4444+ GsdRROutput *output)
4445+{
4446+ int i;
4447+
4448+ for (i = 0; i < info->outputs->len; ++i)
4449+ {
4450+ GsdRROutput *clone = info->outputs->pdata[i];
4451+
4452+ if (!gsd_rr_output_can_clone (clone, output))
4453+ return FALSE;
4454+ }
4455+
4456+ return TRUE;
4457+}
4458+
4459+static gboolean
4460+crtc_assignment_assign (CrtcAssignment *assign,
4461+ GsdRRCrtc *crtc,
4462+ GsdRRMode *mode,
4463+ int x,
4464+ int y,
4465+ GsdRRRotation rotation,
4466+ gboolean primary,
4467+ GsdRROutput *output,
4468+ GError **error)
4469+{
4470+ CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
4471+ guint32 crtc_id;
4472+ const char *output_name;
4473+
4474+ crtc_id = gsd_rr_crtc_get_id (crtc);
4475+ output_name = gsd_rr_output_get_name (output);
4476+
4477+ if (!gsd_rr_crtc_can_drive_output (crtc, output))
4478+ {
4479+ g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
4480+ _("CRTC %d cannot drive output %s"), crtc_id, output_name);
4481+ return FALSE;
4482+ }
4483+
4484+ if (!gsd_rr_output_supports_mode (output, mode))
4485+ {
4486+ g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
4487+ _("output %s does not support mode %dx%d@%dHz"),
4488+ output_name,
4489+ gsd_rr_mode_get_width (mode),
4490+ gsd_rr_mode_get_height (mode),
4491+ gsd_rr_mode_get_freq (mode));
4492+ return FALSE;
4493+ }
4494+
4495+ if (!gsd_rr_crtc_supports_rotation (crtc, rotation))
4496+ {
4497+ g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
4498+ _("CRTC %d does not support rotation=%s"),
4499+ crtc_id,
4500+ get_rotation_name (rotation));
4501+ return FALSE;
4502+ }
4503+
4504+ if (info)
4505+ {
4506+ if (!(info->mode == mode &&
4507+ info->x == x &&
4508+ info->y == y &&
4509+ info->rotation == rotation))
4510+ {
4511+ g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
4512+ _("output %s does not have the same parameters as another cloned output:\n"
4513+ "existing mode = %d, new mode = %d\n"
4514+ "existing coordinates = (%d, %d), new coordinates = (%d, %d)\n"
4515+ "existing rotation = %s, new rotation = %s"),
4516+ output_name,
4517+ gsd_rr_mode_get_id (info->mode), gsd_rr_mode_get_id (mode),
4518+ info->x, info->y,
4519+ x, y,
4520+ get_rotation_name (info->rotation), get_rotation_name (rotation));
4521+ return FALSE;
4522+ }
4523+
4524+ if (!can_clone (info, output))
4525+ {
4526+ g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
4527+ _("cannot clone to output %s"),
4528+ output_name);
4529+ return FALSE;
4530+ }
4531+
4532+ g_ptr_array_add (info->outputs, output);
4533+
4534+ if (primary && !assign->primary)
4535+ {
4536+ assign->primary = output;
4537+ }
4538+
4539+ return TRUE;
4540+ }
4541+ else
4542+ {
4543+ CrtcInfo *info = g_new0 (CrtcInfo, 1);
4544+
4545+ info->mode = mode;
4546+ info->x = x;
4547+ info->y = y;
4548+ info->rotation = rotation;
4549+ info->outputs = g_ptr_array_new ();
4550+
4551+ g_ptr_array_add (info->outputs, output);
4552+
4553+ g_hash_table_insert (assign->info, crtc, info);
4554+
4555+ if (primary && !assign->primary)
4556+ {
4557+ assign->primary = output;
4558+ }
4559+
4560+ return TRUE;
4561+ }
4562+}
4563+
4564+static void
4565+crtc_assignment_unassign (CrtcAssignment *assign,
4566+ GsdRRCrtc *crtc,
4567+ GsdRROutput *output)
4568+{
4569+ CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
4570+
4571+ if (info)
4572+ {
4573+ g_ptr_array_remove (info->outputs, output);
4574+
4575+ if (assign->primary == output)
4576+ {
4577+ assign->primary = NULL;
4578+ }
4579+
4580+ if (info->outputs->len == 0)
4581+ g_hash_table_remove (assign->info, crtc);
4582+ }
4583+}
4584+
4585+static void
4586+crtc_assignment_free (CrtcAssignment *assign)
4587+{
4588+ g_hash_table_destroy (assign->info);
4589+
4590+ g_free (assign);
4591+}
4592+
4593+typedef struct {
4594+ guint32 timestamp;
4595+ gboolean has_error;
4596+ GError **error;
4597+} ConfigureCrtcState;
4598+
4599+static void
4600+configure_crtc (gpointer key,
4601+ gpointer value,
4602+ gpointer data)
4603+{
4604+ GsdRRCrtc *crtc = key;
4605+ CrtcInfo *info = value;
4606+ ConfigureCrtcState *state = data;
4607+
4608+ if (state->has_error)
4609+ return;
4610+
4611+ if (!gsd_rr_crtc_set_config_with_time (crtc,
4612+ state->timestamp,
4613+ info->x, info->y,
4614+ info->mode,
4615+ info->rotation,
4616+ (GsdRROutput **)info->outputs->pdata,
4617+ info->outputs->len,
4618+ state->error))
4619+ state->has_error = TRUE;
4620+}
4621+
4622+static gboolean
4623+mode_is_rotated (CrtcInfo *info)
4624+{
4625+ if ((info->rotation & GSD_RR_ROTATION_270) ||
4626+ (info->rotation & GSD_RR_ROTATION_90))
4627+ {
4628+ return TRUE;
4629+ }
4630+ return FALSE;
4631+}
4632+
4633+static gboolean
4634+crtc_is_rotated (GsdRRCrtc *crtc)
4635+{
4636+ GsdRRRotation r = gsd_rr_crtc_get_current_rotation (crtc);
4637+
4638+ if ((r & GSD_RR_ROTATION_270) ||
4639+ (r & GSD_RR_ROTATION_90))
4640+ {
4641+ return TRUE;
4642+ }
4643+
4644+ return FALSE;
4645+}
4646+
4647+static void
4648+accumulate_error (GString *accumulated_error, GError *error)
4649+{
4650+ g_string_append_printf (accumulated_error, " %s\n", error->message);
4651+ g_error_free (error);
4652+}
4653+
4654+/* Check whether the given set of settings can be used
4655+ * at the same time -- ie. whether there is an assignment
4656+ * of CRTC's to outputs.
4657+ *
4658+ * Brute force - the number of objects involved is small
4659+ * enough that it doesn't matter.
4660+ */
4661+static gboolean
4662+real_assign_crtcs (GsdRRScreen *screen,
4663+ GsdRROutputInfo **outputs,
4664+ CrtcAssignment *assignment,
4665+ GError **error)
4666+{
4667+ GsdRRCrtc **crtcs = gsd_rr_screen_list_crtcs (screen);
4668+ GsdRROutputInfo *output;
4669+ int i;
4670+ gboolean tried_mode;
4671+ GError *my_error;
4672+ GString *accumulated_error;
4673+ gboolean success;
4674+
4675+ output = *outputs;
4676+ if (!output)
4677+ return TRUE;
4678+
4679+ /* It is always allowed for an output to be turned off */
4680+ if (!output->priv->on)
4681+ {
4682+ return real_assign_crtcs (screen, outputs + 1, assignment, error);
4683+ }
4684+
4685+ success = FALSE;
4686+ tried_mode = FALSE;
4687+ accumulated_error = g_string_new (NULL);
4688+
4689+ for (i = 0; crtcs[i] != NULL; ++i)
4690+ {
4691+ GsdRRCrtc *crtc = crtcs[i];
4692+ int crtc_id = gsd_rr_crtc_get_id (crtc);
4693+ int pass;
4694+
4695+ g_string_append_printf (accumulated_error,
4696+ _("Trying modes for CRTC %d\n"),
4697+ crtc_id);
4698+
4699+ /* Make two passes, one where frequencies must match, then
4700+ * one where they don't have to
4701+ */
4702+ for (pass = 0; pass < 2; ++pass)
4703+ {
4704+ GsdRROutput *gsd_rr_output = gsd_rr_screen_get_output_by_name (screen, output->priv->name);
4705+ GsdRRMode **modes = gsd_rr_output_list_modes (gsd_rr_output);
4706+ int j;
4707+
4708+ for (j = 0; modes[j] != NULL; ++j)
4709+ {
4710+ GsdRRMode *mode = modes[j];
4711+ int mode_width;
4712+ int mode_height;
4713+ int mode_freq;
4714+
4715+ mode_width = gsd_rr_mode_get_width (mode);
4716+ mode_height = gsd_rr_mode_get_height (mode);
4717+ mode_freq = gsd_rr_mode_get_freq (mode);
4718+
4719+ g_string_append_printf (accumulated_error,
4720+ _("CRTC %d: trying mode %dx%d@%dHz with output at %dx%d@%dHz (pass %d)\n"),
4721+ crtc_id,
4722+ mode_width, mode_height, mode_freq,
4723+ output->priv->width, output->priv->height, output->priv->rate,
4724+ pass);
4725+
4726+ if (mode_width == output->priv->width &&
4727+ mode_height == output->priv->height &&
4728+ (pass == 1 || mode_freq == output->priv->rate))
4729+ {
4730+ tried_mode = TRUE;
4731+
4732+ my_error = NULL;
4733+ if (crtc_assignment_assign (
4734+ assignment, crtc, modes[j],
4735+ output->priv->x, output->priv->y,
4736+ output->priv->rotation,
4737+ output->priv->primary,
4738+ gsd_rr_output,
4739+ &my_error))
4740+ {
4741+ my_error = NULL;
4742+ if (real_assign_crtcs (screen, outputs + 1, assignment, &my_error)) {
4743+ success = TRUE;
4744+ goto out;
4745+ } else
4746+ accumulate_error (accumulated_error, my_error);
4747+
4748+ crtc_assignment_unassign (assignment, crtc, gsd_rr_output);
4749+ } else
4750+ accumulate_error (accumulated_error, my_error);
4751+ }
4752+ }
4753+ }
4754+ }
4755+
4756+out:
4757+
4758+ if (success)
4759+ g_string_free (accumulated_error, TRUE);
4760+ else {
4761+ char *str;
4762+
4763+ str = g_string_free (accumulated_error, FALSE);
4764+
4765+ if (tried_mode)
4766+ g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
4767+ _("could not assign CRTCs to outputs:\n%s"),
4768+ str);
4769+ else
4770+ g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_CRTC_ASSIGNMENT,
4771+ _("none of the selected modes were compatible with the possible modes:\n%s"),
4772+ str);
4773+
4774+ g_free (str);
4775+ }
4776+
4777+ return success;
4778+}
4779+
4780+static void
4781+crtc_info_free (CrtcInfo *info)
4782+{
4783+ g_ptr_array_free (info->outputs, TRUE);
4784+ g_free (info);
4785+}
4786+
4787+static void
4788+get_required_virtual_size (CrtcAssignment *assign, int *width, int *height)
4789+{
4790+ GList *active_crtcs = g_hash_table_get_keys (assign->info);
4791+ GList *list;
4792+ int d;
4793+
4794+ if (!width)
4795+ width = &d;
4796+ if (!height)
4797+ height = &d;
4798+
4799+ /* Compute size of the screen */
4800+ *width = *height = 1;
4801+ for (list = active_crtcs; list != NULL; list = list->next)
4802+ {
4803+ GsdRRCrtc *crtc = list->data;
4804+ CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
4805+ int w, h;
4806+
4807+ w = gsd_rr_mode_get_width (info->mode);
4808+ h = gsd_rr_mode_get_height (info->mode);
4809+
4810+ if (mode_is_rotated (info))
4811+ {
4812+ int tmp = h;
4813+ h = w;
4814+ w = tmp;
4815+ }
4816+
4817+ *width = MAX (*width, info->x + w);
4818+ *height = MAX (*height, info->y + h);
4819+ }
4820+
4821+ g_list_free (active_crtcs);
4822+}
4823+
4824+static gboolean
4825+unity_running (void)
4826+{
4827+ const gchar *desktop_environment = g_getenv ("DESKTOP_SESSION");
4828+
4829+ return !g_strcmp0 (desktop_environment, "ubuntu");
4830+}
4831+
4832+static gint _max_texture_size_cache = -1;
4833+
4834+static gint
4835+get_max_texture_size (GsdRRScreen *screen)
4836+{
4837+ if (_max_texture_size_cache != -1)
4838+ {
4839+ return _max_texture_size_cache;
4840+ } else {
4841+ /*
4842+ * Spawn a second process to check the GL texture limits
4843+ * We do this across a process boundary to ensure that crashes
4844+ * in the GL driver (which are unfortunately common) don't take
4845+ * down the app.
4846+ */
4847+ int pipe_fd[2];
4848+ pid_t canary_pid;
4849+
4850+ char * const canary_argv[] = { LIBEXECDIR "/check_gl_texture_size", NULL };
4851+ char *canary_env[2];
4852+ char display_env[80];
4853+
4854+ snprintf (display_env, sizeof (display_env), "DISPLAY=%s", DisplayString (screen->priv->xdisplay));
4855+ canary_env[0] = display_env;
4856+ canary_env[1] = NULL;
4857+
4858+
4859+ if (pipe (pipe_fd) == -1)
4860+ {
4861+ _max_texture_size_cache = 0;
4862+ return 0;
4863+ }
4864+ canary_pid = fork ();
4865+ if (canary_pid == -1)
4866+ {
4867+ _max_texture_size_cache = 0;
4868+ return 0;
4869+ }
4870+
4871+ if (canary_pid == 0)
4872+ {
4873+ close (pipe_fd[0]);
4874+ dup2 (pipe_fd[1], 1);
4875+ close (pipe_fd[1]);
4876+
4877+ execve (canary_argv[0], canary_argv, canary_env);
4878+ } else {
4879+ char buffer[10];
4880+ gint max_texture_size;
4881+ int child_status;
4882+ int num_char;
4883+ struct timespec fifty_msec = {0, 50000000};
4884+ int wait_count = 0;
4885+
4886+ close (pipe_fd[1]);
4887+
4888+ /* Empirical testing suggests this check takes < 150msec on my
4889+ * crappy Atom netbook with slow rotating HDD. A 500msec timeout
4890+ * should be generous while not being *too* long if it triggers.
4891+ *
4892+ * Do a sleep/poll dance because we're a library and there's no
4893+ * guarantee that waiting on SIGCHLD won't stomp over a client's
4894+ * set up.
4895+ */
4896+ while (waitpid (canary_pid, &child_status, WNOHANG) == 0 && wait_count < 10) {
4897+ g_debug ("Waiting for GL_MAX_TEXTURE_SIZE helper...");
4898+ nanosleep (&fifty_msec, NULL);
4899+ wait_count++;
4900+ }
4901+
4902+ if (WIFEXITED (child_status) && WEXITSTATUS (child_status) == EXIT_SUCCESS)
4903+ {
4904+ if ((num_char = read (pipe_fd[0], buffer, sizeof(buffer) - 1)) <= 0)
4905+ {
4906+ g_warning ("Failed to read GL_MAX_TEXTURE_SIZE from helper.");
4907+ max_texture_size = 0;
4908+ } else {
4909+ buffer[num_char] = '\0';
4910+ sscanf (buffer, "%u", &max_texture_size);
4911+ /*
4912+ * Sanity check the numbers. No hardware I know of has a
4913+ * GL_MAX_TEXTURE_SIZE smaller than 1024.
4914+ */
4915+ if (max_texture_size < 1024)
4916+ max_texture_size = 0;
4917+ }
4918+ } else {
4919+ if (wait_count == 10) {
4920+ g_warning ("Timed out waiting for GL_MAX_TEXTURE_SIZE helper");
4921+
4922+ /* Ensure we don't leave processes sitting around. Who knows what they're doing? */
4923+ kill (canary_pid, SIGTERM);
4924+ waitpid (canary_pid, &child_status, 0);
4925+ } else {
4926+ g_warning ("GL_MAX_TEXTURE_SIZE helper quit unexpectedly");
4927+ }
4928+ max_texture_size = 0;
4929+ }
4930+
4931+ close (pipe_fd[0]);
4932+ g_debug ("Found GL_MAX_TEXTURE_SIZE of %u", max_texture_size);
4933+ _max_texture_size_cache = max_texture_size;
4934+ return _max_texture_size_cache;
4935+ }
4936+ }
4937+}
4938+
4939+static CrtcAssignment *
4940+crtc_assignment_new (GsdRRScreen *screen, GsdRROutputInfo **outputs, GError **error)
4941+{
4942+ CrtcAssignment *assignment = g_new0 (CrtcAssignment, 1);
4943+
4944+ assignment->info = g_hash_table_new_full (
4945+ g_direct_hash, g_direct_equal, NULL, (GFreeFunc)crtc_info_free);
4946+
4947+ if (real_assign_crtcs (screen, outputs, assignment, error))
4948+ {
4949+ int width, height;
4950+ int min_width, max_width, min_height, max_height;
4951+ int max_texture_size;
4952+
4953+ get_required_virtual_size (assignment, &width, &height);
4954+
4955+ gsd_rr_screen_get_ranges (
4956+ screen, &min_width, &max_width, &min_height, &max_height);
4957+
4958+ if (width < min_width || width > max_width ||
4959+ height < min_height || height > max_height)
4960+ {
4961+ g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_BOUNDS_ERROR,
4962+ /* Translators: the "requested", "minimum", and
4963+ * "maximum" words here are not keywords; please
4964+ * translate them as usual. */
4965+ _("required virtual size does not fit available size: "
4966+ "requested=(%d, %d), minimum=(%d, %d), maximum=(%d, %d)"),
4967+ width, height,
4968+ min_width, min_height,
4969+ max_width, max_height);
4970+ goto fail;
4971+ }
4972+
4973+ /* Hack:
4974+ * This should either be solved by
4975+ * (a) Allowing the compositor to veto RandR changes
4976+ * (b) Fixing the compositor
4977+ *
4978+ * Nethier of these are feasible at this point, so just fix Unity.
4979+ */
4980+
4981+ if (unity_running ())
4982+ {
4983+ max_texture_size = get_max_texture_size (screen);
4984+ if (max_texture_size > 0 && (width > max_texture_size || height > max_texture_size))
4985+ {
4986+ g_set_error (error, GSD_RR_ERROR, GSD_RR_ERROR_BOUNDS_ERROR,
4987+ _("Requested size (%d, %d) exceeds 3D hardware limit (%d, %d).\n"
4988+ "You must either rearrange the displays so that they fit within a (%d, %d) square."),
4989+ width, height, max_texture_size, max_texture_size,
4990+ max_texture_size, max_texture_size);
4991+ goto fail;
4992+ }
4993+ }
4994+
4995+
4996+ assignment->screen = screen;
4997+
4998+ return assignment;
4999+ }
5000+
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches