Merge lp:~albertomilone/unity-settings-daemon/lp1287341-14.10 into lp:unity-settings-daemon

Proposed by Alberto Milone
Status: Merged
Approved by: Sebastien Bacher
Approved revision: 4047
Merged at revision: 4041
Proposed branch: lp:~albertomilone/unity-settings-daemon/lp1287341-14.10
Merge into: lp:unity-settings-daemon
Diff against target: 380 lines (+294/-0)
4 files modified
debian/changelog (+19/-0)
plugins/common/gsd-input-helper.c (+49/-0)
plugins/common/gsd-input-helper.h (+3/-0)
plugins/xrandr/gsd-xrandr-manager.c (+223/-0)
To merge this branch: bzr merge lp:~albertomilone/unity-settings-daemon/lp1287341-14.10
Reviewer Review Type Date Requested Status
Sebastien Bacher Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+222011@code.launchpad.net

Commit message

gsd-xrandr-manager.c: add support for mapping the main touchscreen onto the main display

This makes sure that the touch input device knows exactly the
area that represents the display when the screen configuration
changes.

We give the highest priority to outputs that use an embedded
display connector such as LVDS or eDP. If no embedded connector
can be found, we try to match the size reported by the touch
input device with the size reported by the EDID of the display.

Note: this doesn't cover the tablet use case.

This is a partial backport of the upstream code. I haven't
backported the new device mapper, as that's something that
would be best handled with a full sync with upstream (it's
too much code to backport).

Fixes LP: #1287341

Description of the change

gsd-xrandr-manager.c: add support for mapping the main touchscreen onto the main display

This makes sure that the touch input device knows exactly the
area that represents the display when the screen configuration
changes.

We give the highest priority to outputs that use an embedded
display connector such as LVDS or eDP. If no embedded connector
can be found, we try to match the size reported by the touch
input device with the size reported by the EDID of the display.

Note: this doesn't cover the tablet use case.

This is a partial backport of the upstream code. I haven't
backported the new device mapper, as that's something that
would be best handled with a full sync with upstream (it's
too much code to backport).

Fixes LP: #1287341

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:4046
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~albertomilone/unity-settings-daemon/lp1287341-14.10/+merge/222011/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity-settings-daemon-ci/27/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-settings-daemon-utopic-amd64-ci/1
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-settings-daemon-utopic-armhf-ci/1
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-settings-daemon-utopic-i386-ci/1

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity-settings-daemon-ci/27/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Sebastien Bacher (seb128) wrote :

Thanks for the work

Some review nitpicks:

> static int map_touch_to_output(GnomeRRScreen *screen, int device_id, GnomeRROutputInfo *output);

lacks a space before the function name and the parenthesis

> static void do_touchscreen_mapping(GsdXrandrManager *manager);

same

> do_touchscreen_mapping(manager);

same

> log_msg("\nSetting touchscreen mapping on RandR event\n");

same

> if (manager->priv->main_touchscreen_name)
> g_free(manager->priv->main_touchscreen_name);

no need to check if the value is null, g_free does that for you

Looks fine to looks otherwise, can you just clean those out? Then I'm going to handle the landing

review: Needs Fixing
4047. By Alberto Milone on 2014-06-04

gsd-xrandr-manager.c: clean up as per seb128's suggestions

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Sebastien Bacher (seb128) wrote :

thanks

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2014-04-14 10:13:11 +0000
3+++ debian/changelog 2014-06-04 14:09:46 +0000
4@@ -1,3 +1,22 @@
5+unity-settings-daemon (14.04.0+14.04.20140414-0ubuntu2) UNRELEASED; urgency=medium
6+
7+ [ Alberto Milone ]
8+ * gsd-xrandr-manager.c:
9+ - Add support for mapping the main touchscreen onto the laptop
10+ display (LP: #1287341).
11+ This makes sure that the input device knows exactly the area
12+ that represents the display when the screen configuration
13+ changes. Note: this doesn't cover the tablet use case.
14+ - Add support for matching displays with touch input devices
15+ according to the reported size. This is particularly
16+ useful on systems that don't use embedded display connectors
17+ i.e. all-in-one systems such as the Dell Optiplex 9030 AIO.
18+ - This work is a partial backport of the upstream work on
19+ touchscreens. When we finally sync with the upstream code
20+ we can drop this.
21+
22+ -- Alberto Milone <alberto.milone@canonical.com> Fri, 23 May 2014 12:01:11 +0200
23+
24 unity-settings-daemon (14.04.0+14.04.20140414-0ubuntu1) trusty; urgency=low
25
26 [ Dmitry Shachnev ]
27
28=== modified file 'plugins/common/gsd-input-helper.c'
29--- plugins/common/gsd-input-helper.c 2013-02-07 04:14:22 +0000
30+++ plugins/common/gsd-input-helper.c 2014-06-04 14:09:46 +0000
31@@ -34,6 +34,11 @@
32 #define INPUT_DEVICES_SCHEMA "org.gnome.settings-daemon.peripherals.input-devices"
33 #define KEY_HOTPLUG_COMMAND "hotplug-command"
34
35+#define ABS_MT_X "Abs MT Position X"
36+#define ABS_MT_Y "Abs MT Position Y"
37+#define ABS_X "Abs X"
38+#define ABS_Y "Abs Y"
39+
40 typedef gboolean (* InfoIdentifyFunc) (XDeviceInfo *device_info);
41 typedef gboolean (* DeviceIdentifyFunc) (XDevice *xdevice);
42
43@@ -571,3 +576,47 @@
44
45 return ret;
46 }
47+
48+gboolean
49+xdevice_get_dimensions (int deviceid,
50+ guint *width,
51+ guint *height)
52+{
53+ GdkDisplay *display = gdk_display_get_default ();
54+ XIDeviceInfo *info;
55+ guint *value, w, h;
56+ int i, n_info;
57+
58+ info = XIQueryDevice (GDK_DISPLAY_XDISPLAY (display), deviceid, &n_info);
59+ *width = *height = w = h = 0;
60+
61+ if (!info)
62+ return FALSE;
63+
64+ for (i = 0; i < info->num_classes; i++) {
65+ XIValuatorClassInfo *valuator_info;
66+
67+ if (info->classes[i]->type != XIValuatorClass)
68+ continue;
69+
70+ valuator_info = (XIValuatorClassInfo *) info->classes[i];
71+
72+ if (valuator_info->label == gdk_x11_get_xatom_by_name_for_display (display, ABS_X) ||
73+ valuator_info->label == gdk_x11_get_xatom_by_name_for_display (display, ABS_MT_X))
74+ value = &w;
75+ else if (valuator_info->label == gdk_x11_get_xatom_by_name_for_display (display, ABS_Y) ||
76+ valuator_info->label == gdk_x11_get_xatom_by_name_for_display (display, ABS_MT_Y))
77+ value = &h;
78+ else
79+ continue;
80+
81+ *value = (valuator_info->max - valuator_info->min) * 1000 / valuator_info->resolution;
82+ }
83+
84+ *width = w;
85+ *height = h;
86+
87+ XIFreeDeviceInfo (info);
88+
89+ return (w != 0 && h != 0);
90+}
91
92=== modified file 'plugins/common/gsd-input-helper.h'
93--- plugins/common/gsd-input-helper.h 2013-01-21 17:01:42 +0000
94+++ plugins/common/gsd-input-helper.h 2014-06-04 14:09:46 +0000
95@@ -81,6 +81,9 @@
96 GList * get_disabled_devices (GdkDeviceManager *manager);
97 char * xdevice_get_device_node (int deviceid);
98 int xdevice_get_last_tool_id (int deviceid);
99+gboolean xdevice_get_dimensions (int deviceid,
100+ guint *width,
101+ guint *height);
102
103 G_END_DECLS
104
105
106=== modified file 'plugins/xrandr/gsd-xrandr-manager.c'
107--- plugins/xrandr/gsd-xrandr-manager.c 2013-12-04 23:55:26 +0000
108+++ plugins/xrandr/gsd-xrandr-manager.c 2014-06-04 14:09:46 +0000
109@@ -127,6 +127,9 @@
110 #ifdef HAVE_WACOM
111 WacomDeviceDatabase *wacom_db;
112 #endif /* HAVE_WACOM */
113+
114+ int main_touchscreen_id;
115+ gchar *main_touchscreen_name;
116 };
117
118 static const GnomeRRRotation possible_rotations[] = {
119@@ -157,6 +160,10 @@
120
121 static FILE *log_file;
122
123+static GnomeRROutput * input_info_find_size_match (GsdXrandrManager *manager, GnomeRRScreen *rr_screen);
124+static int map_touch_to_output (GnomeRRScreen *screen, int device_id, GnomeRROutputInfo *output);
125+static void do_touchscreen_mapping (GsdXrandrManager *manager);
126+
127 static void
128 log_open (void)
129 {
130@@ -1818,6 +1825,12 @@
131 use_stored_configuration_or_auto_configure_outputs (manager, config_timestamp);
132 }
133
134+ if (priv->main_touchscreen_id != -1) {
135+ /* Set mapping of input devices onto displays */
136+ log_msg ("\nSetting touchscreen mapping on RandR event\n");
137+ do_touchscreen_mapping (manager);
138+ }
139+
140 log_close ();
141 }
142
143@@ -2033,6 +2046,206 @@
144 }
145 }
146
147+static gboolean
148+matches_name (GnomeRROutputInfo *output, GnomeRROutput *to_match)
149+{
150+ return (g_strcmp0 (gnome_rr_output_info_get_name (output),
151+ gnome_rr_output_get_name (to_match) ) == 0);
152+}
153+
154+static gint
155+monitor_for_output (GnomeRROutput *output)
156+{
157+ GdkScreen *screen = gdk_screen_get_default ();
158+ GnomeRRCrtc *crtc = gnome_rr_output_get_crtc (output);
159+ gint x, y;
160+
161+ if (!crtc)
162+ return -1;
163+
164+ gnome_rr_crtc_get_position (crtc, &x, &y);
165+
166+ return gdk_screen_get_monitor_at_point (screen, x, y);
167+}
168+
169+static gboolean
170+output_get_dimensions (GnomeRROutput *output,
171+ guint *width,
172+ guint *height)
173+{
174+ GdkScreen *screen = gdk_screen_get_default ();
175+ gint monitor_num;
176+
177+ monitor_num = monitor_for_output (output);
178+
179+ if (monitor_num < 0)
180+ return FALSE;
181+
182+ *width = gdk_screen_get_monitor_width_mm (screen, monitor_num);
183+ *height = gdk_screen_get_monitor_height_mm (screen, monitor_num);
184+ return TRUE;
185+}
186+
187+static GnomeRROutput *
188+input_info_find_size_match (GsdXrandrManager *manager, GnomeRRScreen *rr_screen)
189+{
190+ guint i, input_width, input_height, output_width, output_height;
191+ gdouble min_width_diff, min_height_diff;
192+ GnomeRROutput **outputs, *match = NULL;
193+ GsdXrandrManagerPrivate *priv = manager->priv;
194+
195+ g_return_val_if_fail (rr_screen != NULL, NULL);
196+
197+ if (!xdevice_get_dimensions (priv->main_touchscreen_id,
198+ &input_width, &input_height))
199+ return NULL;
200+
201+ /* Restrict the matches to be below a narrow percentage */
202+ min_width_diff = min_height_diff = 0.05;
203+
204+ g_debug ("Input device '%s' has %dx%d mm",
205+ priv->main_touchscreen_name, input_width, input_height);
206+
207+ outputs = gnome_rr_screen_list_outputs (rr_screen);
208+
209+ for (i = 0; outputs[i] != NULL; i++) {
210+ gdouble width_diff, height_diff;
211+ if (!output_get_dimensions (outputs[i], &output_width, &output_height))
212+ continue;
213+
214+ width_diff = ABS (1 - ((gdouble) output_width / input_width));
215+ height_diff = ABS (1 - ((gdouble) output_height / input_height));
216+
217+ g_debug ("Output '%s' has size %dx%d mm, deviation from "
218+ "input device size: %.2f width, %.2f height ",
219+ gnome_rr_output_get_name (outputs[i]),
220+ output_width, output_height, width_diff, height_diff);
221+
222+ if (width_diff <= min_width_diff && height_diff <= min_height_diff) {
223+ match = outputs[i];
224+ min_width_diff = width_diff;
225+ min_height_diff = height_diff;
226+ }
227+ }
228+
229+ if (match) {
230+ g_debug ("Output '%s' is considered a best size match (%.2f / %.2f)",
231+ gnome_rr_output_get_name (match),
232+ min_width_diff, min_height_diff);
233+ } else {
234+ g_debug ("No input/output size match was found\n");
235+ }
236+
237+ return match;
238+}
239+
240+static GnomeRROutputInfo *
241+get_mappable_output_info (GsdXrandrManager *manager, GnomeRRScreen *screen, GnomeRRConfig *config)
242+{
243+ int i;
244+ GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config);
245+
246+ GnomeRROutput *size_match = NULL;
247+
248+ size_match = input_info_find_size_match (manager, screen);
249+
250+ for (i = 0; outputs[i] != NULL; i++) {
251+ if (is_laptop (screen, outputs[i]) || (size_match && matches_name (outputs[i], size_match)))
252+ return outputs[i];
253+ }
254+
255+ return NULL;
256+}
257+
258+static void
259+set_touchscreen_id (GsdXrandrManager *manager)
260+{
261+ GsdXrandrManagerPrivate *priv = manager->priv;
262+ XDeviceInfo *device_info;
263+ int n_devices;
264+ int i;
265+
266+ device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
267+ &n_devices);
268+ if (device_info == NULL)
269+ return;
270+
271+ for (i = 0; i < n_devices; i++) {
272+ if (device_info_is_touchscreen (&device_info[i])) {
273+ /* Let's deal only with the 1st touchscreen */
274+ priv->main_touchscreen_id = (int)device_info[i].id;
275+ priv->main_touchscreen_name = g_strdup (device_info[i].name);
276+ break;
277+ }
278+ }
279+
280+ XFreeDeviceList (device_info);
281+}
282+
283+static int
284+map_touch_to_output (GnomeRRScreen *screen, int device_id,
285+ GnomeRROutputInfo *output)
286+{
287+ int status = 0;
288+ char command[100];
289+ gchar *name = gnome_rr_output_info_get_name (output);
290+
291+ if (!name) {
292+ g_debug ("Failure to map screen with missing name");
293+ status = 1;
294+ goto out;
295+ }
296+
297+ if (gnome_rr_output_info_is_active(output)) {
298+ g_debug ("Mapping touchscreen %d onto output %s",
299+ device_id, name);
300+ sprintf (command, "xinput --map-to-output %d %s",
301+ device_id, name);
302+ status = system (command);
303+ }
304+ else {
305+ g_debug ("No need to map %d onto output %s. The output is off",
306+ device_id, name);
307+ }
308+
309+out:
310+ return (status == 0);
311+}
312+
313+static void
314+do_touchscreen_mapping (GsdXrandrManager *manager)
315+{
316+ GsdXrandrManagerPrivate *priv = manager->priv;
317+ GnomeRRScreen *screen = priv->rw_screen;
318+ GnomeRRConfig *current;
319+ GnomeRROutputInfo *laptop_output;
320+
321+ if (!supports_xinput_devices ())
322+ return;
323+
324+ current = gnome_rr_config_new_current (screen, NULL);
325+ laptop_output = get_mappable_output_info (manager, screen, current);
326+
327+ if (laptop_output == NULL) {
328+ g_debug ("No laptop screen detected");
329+ goto out;
330+ }
331+
332+ if (priv->main_touchscreen_id != -1) {
333+ /* Set initial mapping */
334+ g_debug ("Setting initial touchscreen mapping");
335+ map_touch_to_output (screen,
336+ priv->main_touchscreen_id,
337+ laptop_output);
338+ }
339+ else {
340+ g_debug ("No main touchscreen detected");
341+ }
342+
343+out:
344+ g_object_unref (current);
345+}
346+
347 gboolean
348 gsd_xrandr_manager_start (GsdXrandrManager *manager,
349 GError **error)
350@@ -2071,6 +2284,10 @@
351 if (!apply_default_configuration_from_file (manager, GDK_CURRENT_TIME))
352 apply_default_boot_configuration (manager, GDK_CURRENT_TIME);
353
354+ /* Initialise touchscreen mapping */
355+ set_touchscreen_id (manager);
356+ do_touchscreen_mapping (manager);
357+
358 log_msg ("State of screen after initial configuration:\n");
359 log_screen (manager->priv->rw_screen);
360
361@@ -2127,6 +2344,8 @@
362 }
363 #endif /* HAVE_WACOM */
364
365+ g_free (manager->priv->main_touchscreen_name);
366+
367 log_open ();
368 log_msg ("STOPPING XRANDR PLUGIN\n------------------------------------------------------------\n");
369 log_close ();
370@@ -2149,6 +2368,10 @@
371
372 manager->priv->current_fn_f7_config = -1;
373 manager->priv->fn_f7_configs = NULL;
374+
375+ /* For touchscreen mapping */
376+ manager->priv->main_touchscreen_id = -1;
377+ manager->priv->main_touchscreen_name = NULL;
378 }
379
380 static void

Subscribers

People subscribed via source and target branches