Merge lp:~robert-ancell/unity-settings-daemon/xrandr into lp:unity-settings-daemon
- xrandr
- Merge into trunk
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 |
Related bugs: |
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
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
- 4047. By Robert Ancell
-
Build-dep on libgl1-mesa-dev
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:4047
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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:/
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
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.
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.
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
Robert Ancell (robert-ancell) wrote : | # |
See lp:~robert-ancell/unity-control-center/xrandr for associated u-c-c MP.
Robert Ancell (robert-ancell) wrote : | # |
See lp:~robert-ancell/unity-settings-daemon/idle for idle code removal.
Robert Ancell (robert-ancell) wrote : | # |
The decision was made to continue with this method - please review.
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
Tim Lunn (darkxst) wrote : | # |
This lgtm, lots of cut+paste and a bit of renaming, don't think it will cause any issues
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-
** (unity-
(unity-
(unity-
(unity-
When trying to apply a change to the display configuration I get
GDBus.
in a dialog.
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=
Also we need <https:/
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
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:4049
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 4050. By Robert Ancell
-
Add symbols file
Robert Ancell (robert-ancell) wrote : | # |
I've updated this branch to now use a shared library that is also used by unity-control-
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
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:4050
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:4051
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 4052. By Robert Ancell
-
Move libunity-
settings- daemon into its own package so we can build unity-control- center without installing unity-settings- daemon
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:4052
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Iain Lane (laney) wrote : | # |
I didn't have problems with the latest branches, thanks for the work
Preview Diff
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 | + |
FAILED: Continuous integration, rev:4046 jenkins. qa.ubuntu. com/job/ unity-settings- daemon- ci/30/ jenkins. qa.ubuntu. com/job/ unity-settings- daemon- utopic- amd64-ci/ 4/console jenkins. qa.ubuntu. com/job/ unity-settings- daemon- utopic- armhf-ci/ 4/console jenkins. qa.ubuntu. com/job/ unity-settings- daemon- utopic- i386-ci/ 4/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity- settings- daemon- ci/30/rebuild
http://