Merge lp:~albertomilone/unity-settings-daemon/lp1287341-14.10 into lp:unity-settings-daemon/14.04
- lp1287341-14.10
- Merge into 14.04
Proposed by
Sebastien Bacher
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/14.04 |
Diff against target: |
381 lines (+295/-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 (+224/-0) |
To merge this branch: | bzr merge lp:~albertomilone/unity-settings-daemon/lp1287341-14.10 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sebastien Bacher | Approve | ||
Review via email: mp+222071@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
- 4048. By Alberto Milone
-
gsd-xrandr-
manager. c: do not try to map an invalid touch device on initialisation Fixes LP: #1326636
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-05 11:56:47 +0000 | |||
4 | @@ -1,3 +1,22 @@ | |||
5 | 1 | unity-settings-daemon (14.04.0+14.04.20140414-0ubuntu2) UNRELEASED; urgency=medium | ||
6 | 2 | |||
7 | 3 | [ Alberto Milone ] | ||
8 | 4 | * gsd-xrandr-manager.c: | ||
9 | 5 | - Add support for mapping the main touchscreen onto the laptop | ||
10 | 6 | display (LP: #1287341). | ||
11 | 7 | This makes sure that the input device knows exactly the area | ||
12 | 8 | that represents the display when the screen configuration | ||
13 | 9 | changes. Note: this doesn't cover the tablet use case. | ||
14 | 10 | - Add support for matching displays with touch input devices | ||
15 | 11 | according to the reported size. This is particularly | ||
16 | 12 | useful on systems that don't use embedded display connectors | ||
17 | 13 | i.e. all-in-one systems such as the Dell Optiplex 9030 AIO. | ||
18 | 14 | - This work is a partial backport of the upstream work on | ||
19 | 15 | touchscreens. When we finally sync with the upstream code | ||
20 | 16 | we can drop this. | ||
21 | 17 | |||
22 | 18 | -- Alberto Milone <alberto.milone@canonical.com> Fri, 23 May 2014 12:01:11 +0200 | ||
23 | 19 | |||
24 | 1 | unity-settings-daemon (14.04.0+14.04.20140414-0ubuntu1) trusty; urgency=low | 20 | unity-settings-daemon (14.04.0+14.04.20140414-0ubuntu1) trusty; urgency=low |
25 | 2 | 21 | ||
26 | 3 | [ Dmitry Shachnev ] | 22 | [ Dmitry Shachnev ] |
27 | 4 | 23 | ||
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-05 11:56:47 +0000 | |||
31 | @@ -34,6 +34,11 @@ | |||
32 | 34 | #define INPUT_DEVICES_SCHEMA "org.gnome.settings-daemon.peripherals.input-devices" | 34 | #define INPUT_DEVICES_SCHEMA "org.gnome.settings-daemon.peripherals.input-devices" |
33 | 35 | #define KEY_HOTPLUG_COMMAND "hotplug-command" | 35 | #define KEY_HOTPLUG_COMMAND "hotplug-command" |
34 | 36 | 36 | ||
35 | 37 | #define ABS_MT_X "Abs MT Position X" | ||
36 | 38 | #define ABS_MT_Y "Abs MT Position Y" | ||
37 | 39 | #define ABS_X "Abs X" | ||
38 | 40 | #define ABS_Y "Abs Y" | ||
39 | 41 | |||
40 | 37 | typedef gboolean (* InfoIdentifyFunc) (XDeviceInfo *device_info); | 42 | typedef gboolean (* InfoIdentifyFunc) (XDeviceInfo *device_info); |
41 | 38 | typedef gboolean (* DeviceIdentifyFunc) (XDevice *xdevice); | 43 | typedef gboolean (* DeviceIdentifyFunc) (XDevice *xdevice); |
42 | 39 | 44 | ||
43 | @@ -571,3 +576,47 @@ | |||
44 | 571 | 576 | ||
45 | 572 | return ret; | 577 | return ret; |
46 | 573 | } | 578 | } |
47 | 579 | |||
48 | 580 | gboolean | ||
49 | 581 | xdevice_get_dimensions (int deviceid, | ||
50 | 582 | guint *width, | ||
51 | 583 | guint *height) | ||
52 | 584 | { | ||
53 | 585 | GdkDisplay *display = gdk_display_get_default (); | ||
54 | 586 | XIDeviceInfo *info; | ||
55 | 587 | guint *value, w, h; | ||
56 | 588 | int i, n_info; | ||
57 | 589 | |||
58 | 590 | info = XIQueryDevice (GDK_DISPLAY_XDISPLAY (display), deviceid, &n_info); | ||
59 | 591 | *width = *height = w = h = 0; | ||
60 | 592 | |||
61 | 593 | if (!info) | ||
62 | 594 | return FALSE; | ||
63 | 595 | |||
64 | 596 | for (i = 0; i < info->num_classes; i++) { | ||
65 | 597 | XIValuatorClassInfo *valuator_info; | ||
66 | 598 | |||
67 | 599 | if (info->classes[i]->type != XIValuatorClass) | ||
68 | 600 | continue; | ||
69 | 601 | |||
70 | 602 | valuator_info = (XIValuatorClassInfo *) info->classes[i]; | ||
71 | 603 | |||
72 | 604 | if (valuator_info->label == gdk_x11_get_xatom_by_name_for_display (display, ABS_X) || | ||
73 | 605 | valuator_info->label == gdk_x11_get_xatom_by_name_for_display (display, ABS_MT_X)) | ||
74 | 606 | value = &w; | ||
75 | 607 | else if (valuator_info->label == gdk_x11_get_xatom_by_name_for_display (display, ABS_Y) || | ||
76 | 608 | valuator_info->label == gdk_x11_get_xatom_by_name_for_display (display, ABS_MT_Y)) | ||
77 | 609 | value = &h; | ||
78 | 610 | else | ||
79 | 611 | continue; | ||
80 | 612 | |||
81 | 613 | *value = (valuator_info->max - valuator_info->min) * 1000 / valuator_info->resolution; | ||
82 | 614 | } | ||
83 | 615 | |||
84 | 616 | *width = w; | ||
85 | 617 | *height = h; | ||
86 | 618 | |||
87 | 619 | XIFreeDeviceInfo (info); | ||
88 | 620 | |||
89 | 621 | return (w != 0 && h != 0); | ||
90 | 622 | } | ||
91 | 574 | 623 | ||
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-05 11:56:47 +0000 | |||
95 | @@ -81,6 +81,9 @@ | |||
96 | 81 | GList * get_disabled_devices (GdkDeviceManager *manager); | 81 | GList * get_disabled_devices (GdkDeviceManager *manager); |
97 | 82 | char * xdevice_get_device_node (int deviceid); | 82 | char * xdevice_get_device_node (int deviceid); |
98 | 83 | int xdevice_get_last_tool_id (int deviceid); | 83 | int xdevice_get_last_tool_id (int deviceid); |
99 | 84 | gboolean xdevice_get_dimensions (int deviceid, | ||
100 | 85 | guint *width, | ||
101 | 86 | guint *height); | ||
102 | 84 | 87 | ||
103 | 85 | G_END_DECLS | 88 | G_END_DECLS |
104 | 86 | 89 | ||
105 | 87 | 90 | ||
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-05 11:56:47 +0000 | |||
109 | @@ -127,6 +127,9 @@ | |||
110 | 127 | #ifdef HAVE_WACOM | 127 | #ifdef HAVE_WACOM |
111 | 128 | WacomDeviceDatabase *wacom_db; | 128 | WacomDeviceDatabase *wacom_db; |
112 | 129 | #endif /* HAVE_WACOM */ | 129 | #endif /* HAVE_WACOM */ |
113 | 130 | |||
114 | 131 | int main_touchscreen_id; | ||
115 | 132 | gchar *main_touchscreen_name; | ||
116 | 130 | }; | 133 | }; |
117 | 131 | 134 | ||
118 | 132 | static const GnomeRRRotation possible_rotations[] = { | 135 | static const GnomeRRRotation possible_rotations[] = { |
119 | @@ -157,6 +160,10 @@ | |||
120 | 157 | 160 | ||
121 | 158 | static FILE *log_file; | 161 | static FILE *log_file; |
122 | 159 | 162 | ||
123 | 163 | static GnomeRROutput * input_info_find_size_match (GsdXrandrManager *manager, GnomeRRScreen *rr_screen); | ||
124 | 164 | static int map_touch_to_output (GnomeRRScreen *screen, int device_id, GnomeRROutputInfo *output); | ||
125 | 165 | static void do_touchscreen_mapping (GsdXrandrManager *manager); | ||
126 | 166 | |||
127 | 160 | static void | 167 | static void |
128 | 161 | log_open (void) | 168 | log_open (void) |
129 | 162 | { | 169 | { |
130 | @@ -1818,6 +1825,12 @@ | |||
131 | 1818 | use_stored_configuration_or_auto_configure_outputs (manager, config_timestamp); | 1825 | use_stored_configuration_or_auto_configure_outputs (manager, config_timestamp); |
132 | 1819 | } | 1826 | } |
133 | 1820 | 1827 | ||
134 | 1828 | if (priv->main_touchscreen_id != -1) { | ||
135 | 1829 | /* Set mapping of input devices onto displays */ | ||
136 | 1830 | log_msg ("\nSetting touchscreen mapping on RandR event\n"); | ||
137 | 1831 | do_touchscreen_mapping (manager); | ||
138 | 1832 | } | ||
139 | 1833 | |||
140 | 1821 | log_close (); | 1834 | log_close (); |
141 | 1822 | } | 1835 | } |
142 | 1823 | 1836 | ||
143 | @@ -2033,6 +2046,206 @@ | |||
144 | 2033 | } | 2046 | } |
145 | 2034 | } | 2047 | } |
146 | 2035 | 2048 | ||
147 | 2049 | static gboolean | ||
148 | 2050 | matches_name (GnomeRROutputInfo *output, GnomeRROutput *to_match) | ||
149 | 2051 | { | ||
150 | 2052 | return (g_strcmp0 (gnome_rr_output_info_get_name (output), | ||
151 | 2053 | gnome_rr_output_get_name (to_match) ) == 0); | ||
152 | 2054 | } | ||
153 | 2055 | |||
154 | 2056 | static gint | ||
155 | 2057 | monitor_for_output (GnomeRROutput *output) | ||
156 | 2058 | { | ||
157 | 2059 | GdkScreen *screen = gdk_screen_get_default (); | ||
158 | 2060 | GnomeRRCrtc *crtc = gnome_rr_output_get_crtc (output); | ||
159 | 2061 | gint x, y; | ||
160 | 2062 | |||
161 | 2063 | if (!crtc) | ||
162 | 2064 | return -1; | ||
163 | 2065 | |||
164 | 2066 | gnome_rr_crtc_get_position (crtc, &x, &y); | ||
165 | 2067 | |||
166 | 2068 | return gdk_screen_get_monitor_at_point (screen, x, y); | ||
167 | 2069 | } | ||
168 | 2070 | |||
169 | 2071 | static gboolean | ||
170 | 2072 | output_get_dimensions (GnomeRROutput *output, | ||
171 | 2073 | guint *width, | ||
172 | 2074 | guint *height) | ||
173 | 2075 | { | ||
174 | 2076 | GdkScreen *screen = gdk_screen_get_default (); | ||
175 | 2077 | gint monitor_num; | ||
176 | 2078 | |||
177 | 2079 | monitor_num = monitor_for_output (output); | ||
178 | 2080 | |||
179 | 2081 | if (monitor_num < 0) | ||
180 | 2082 | return FALSE; | ||
181 | 2083 | |||
182 | 2084 | *width = gdk_screen_get_monitor_width_mm (screen, monitor_num); | ||
183 | 2085 | *height = gdk_screen_get_monitor_height_mm (screen, monitor_num); | ||
184 | 2086 | return TRUE; | ||
185 | 2087 | } | ||
186 | 2088 | |||
187 | 2089 | static GnomeRROutput * | ||
188 | 2090 | input_info_find_size_match (GsdXrandrManager *manager, GnomeRRScreen *rr_screen) | ||
189 | 2091 | { | ||
190 | 2092 | guint i, input_width, input_height, output_width, output_height; | ||
191 | 2093 | gdouble min_width_diff, min_height_diff; | ||
192 | 2094 | GnomeRROutput **outputs, *match = NULL; | ||
193 | 2095 | GsdXrandrManagerPrivate *priv = manager->priv; | ||
194 | 2096 | |||
195 | 2097 | g_return_val_if_fail (rr_screen != NULL, NULL); | ||
196 | 2098 | |||
197 | 2099 | if (!xdevice_get_dimensions (priv->main_touchscreen_id, | ||
198 | 2100 | &input_width, &input_height)) | ||
199 | 2101 | return NULL; | ||
200 | 2102 | |||
201 | 2103 | /* Restrict the matches to be below a narrow percentage */ | ||
202 | 2104 | min_width_diff = min_height_diff = 0.05; | ||
203 | 2105 | |||
204 | 2106 | g_debug ("Input device '%s' has %dx%d mm", | ||
205 | 2107 | priv->main_touchscreen_name, input_width, input_height); | ||
206 | 2108 | |||
207 | 2109 | outputs = gnome_rr_screen_list_outputs (rr_screen); | ||
208 | 2110 | |||
209 | 2111 | for (i = 0; outputs[i] != NULL; i++) { | ||
210 | 2112 | gdouble width_diff, height_diff; | ||
211 | 2113 | if (!output_get_dimensions (outputs[i], &output_width, &output_height)) | ||
212 | 2114 | continue; | ||
213 | 2115 | |||
214 | 2116 | width_diff = ABS (1 - ((gdouble) output_width / input_width)); | ||
215 | 2117 | height_diff = ABS (1 - ((gdouble) output_height / input_height)); | ||
216 | 2118 | |||
217 | 2119 | g_debug ("Output '%s' has size %dx%d mm, deviation from " | ||
218 | 2120 | "input device size: %.2f width, %.2f height ", | ||
219 | 2121 | gnome_rr_output_get_name (outputs[i]), | ||
220 | 2122 | output_width, output_height, width_diff, height_diff); | ||
221 | 2123 | |||
222 | 2124 | if (width_diff <= min_width_diff && height_diff <= min_height_diff) { | ||
223 | 2125 | match = outputs[i]; | ||
224 | 2126 | min_width_diff = width_diff; | ||
225 | 2127 | min_height_diff = height_diff; | ||
226 | 2128 | } | ||
227 | 2129 | } | ||
228 | 2130 | |||
229 | 2131 | if (match) { | ||
230 | 2132 | g_debug ("Output '%s' is considered a best size match (%.2f / %.2f)", | ||
231 | 2133 | gnome_rr_output_get_name (match), | ||
232 | 2134 | min_width_diff, min_height_diff); | ||
233 | 2135 | } else { | ||
234 | 2136 | g_debug ("No input/output size match was found\n"); | ||
235 | 2137 | } | ||
236 | 2138 | |||
237 | 2139 | return match; | ||
238 | 2140 | } | ||
239 | 2141 | |||
240 | 2142 | static GnomeRROutputInfo * | ||
241 | 2143 | get_mappable_output_info (GsdXrandrManager *manager, GnomeRRScreen *screen, GnomeRRConfig *config) | ||
242 | 2144 | { | ||
243 | 2145 | int i; | ||
244 | 2146 | GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); | ||
245 | 2147 | |||
246 | 2148 | GnomeRROutput *size_match = NULL; | ||
247 | 2149 | |||
248 | 2150 | size_match = input_info_find_size_match (manager, screen); | ||
249 | 2151 | |||
250 | 2152 | for (i = 0; outputs[i] != NULL; i++) { | ||
251 | 2153 | if (is_laptop (screen, outputs[i]) || (size_match && matches_name (outputs[i], size_match))) | ||
252 | 2154 | return outputs[i]; | ||
253 | 2155 | } | ||
254 | 2156 | |||
255 | 2157 | return NULL; | ||
256 | 2158 | } | ||
257 | 2159 | |||
258 | 2160 | static void | ||
259 | 2161 | set_touchscreen_id (GsdXrandrManager *manager) | ||
260 | 2162 | { | ||
261 | 2163 | GsdXrandrManagerPrivate *priv = manager->priv; | ||
262 | 2164 | XDeviceInfo *device_info; | ||
263 | 2165 | int n_devices; | ||
264 | 2166 | int i; | ||
265 | 2167 | |||
266 | 2168 | device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), | ||
267 | 2169 | &n_devices); | ||
268 | 2170 | if (device_info == NULL) | ||
269 | 2171 | return; | ||
270 | 2172 | |||
271 | 2173 | for (i = 0; i < n_devices; i++) { | ||
272 | 2174 | if (device_info_is_touchscreen (&device_info[i])) { | ||
273 | 2175 | /* Let's deal only with the 1st touchscreen */ | ||
274 | 2176 | priv->main_touchscreen_id = (int)device_info[i].id; | ||
275 | 2177 | priv->main_touchscreen_name = g_strdup (device_info[i].name); | ||
276 | 2178 | break; | ||
277 | 2179 | } | ||
278 | 2180 | } | ||
279 | 2181 | |||
280 | 2182 | XFreeDeviceList (device_info); | ||
281 | 2183 | } | ||
282 | 2184 | |||
283 | 2185 | static int | ||
284 | 2186 | map_touch_to_output (GnomeRRScreen *screen, int device_id, | ||
285 | 2187 | GnomeRROutputInfo *output) | ||
286 | 2188 | { | ||
287 | 2189 | int status = 0; | ||
288 | 2190 | char command[100]; | ||
289 | 2191 | gchar *name = gnome_rr_output_info_get_name (output); | ||
290 | 2192 | |||
291 | 2193 | if (!name) { | ||
292 | 2194 | g_debug ("Failure to map screen with missing name"); | ||
293 | 2195 | status = 1; | ||
294 | 2196 | goto out; | ||
295 | 2197 | } | ||
296 | 2198 | |||
297 | 2199 | if (gnome_rr_output_info_is_active(output)) { | ||
298 | 2200 | g_debug ("Mapping touchscreen %d onto output %s", | ||
299 | 2201 | device_id, name); | ||
300 | 2202 | sprintf (command, "xinput --map-to-output %d %s", | ||
301 | 2203 | device_id, name); | ||
302 | 2204 | status = system (command); | ||
303 | 2205 | } | ||
304 | 2206 | else { | ||
305 | 2207 | g_debug ("No need to map %d onto output %s. The output is off", | ||
306 | 2208 | device_id, name); | ||
307 | 2209 | } | ||
308 | 2210 | |||
309 | 2211 | out: | ||
310 | 2212 | return (status == 0); | ||
311 | 2213 | } | ||
312 | 2214 | |||
313 | 2215 | static void | ||
314 | 2216 | do_touchscreen_mapping (GsdXrandrManager *manager) | ||
315 | 2217 | { | ||
316 | 2218 | GsdXrandrManagerPrivate *priv = manager->priv; | ||
317 | 2219 | GnomeRRScreen *screen = priv->rw_screen; | ||
318 | 2220 | GnomeRRConfig *current; | ||
319 | 2221 | GnomeRROutputInfo *laptop_output; | ||
320 | 2222 | |||
321 | 2223 | if (!supports_xinput_devices ()) | ||
322 | 2224 | return; | ||
323 | 2225 | |||
324 | 2226 | current = gnome_rr_config_new_current (screen, NULL); | ||
325 | 2227 | laptop_output = get_mappable_output_info (manager, screen, current); | ||
326 | 2228 | |||
327 | 2229 | if (laptop_output == NULL) { | ||
328 | 2230 | g_debug ("No laptop screen detected"); | ||
329 | 2231 | goto out; | ||
330 | 2232 | } | ||
331 | 2233 | |||
332 | 2234 | if (priv->main_touchscreen_id != -1) { | ||
333 | 2235 | /* Set initial mapping */ | ||
334 | 2236 | g_debug ("Setting initial touchscreen mapping"); | ||
335 | 2237 | map_touch_to_output (screen, | ||
336 | 2238 | priv->main_touchscreen_id, | ||
337 | 2239 | laptop_output); | ||
338 | 2240 | } | ||
339 | 2241 | else { | ||
340 | 2242 | g_debug ("No main touchscreen detected"); | ||
341 | 2243 | } | ||
342 | 2244 | |||
343 | 2245 | out: | ||
344 | 2246 | g_object_unref (current); | ||
345 | 2247 | } | ||
346 | 2248 | |||
347 | 2036 | gboolean | 2249 | gboolean |
348 | 2037 | gsd_xrandr_manager_start (GsdXrandrManager *manager, | 2250 | gsd_xrandr_manager_start (GsdXrandrManager *manager, |
349 | 2038 | GError **error) | 2251 | GError **error) |
350 | @@ -2071,6 +2284,11 @@ | |||
351 | 2071 | if (!apply_default_configuration_from_file (manager, GDK_CURRENT_TIME)) | 2284 | if (!apply_default_configuration_from_file (manager, GDK_CURRENT_TIME)) |
352 | 2072 | apply_default_boot_configuration (manager, GDK_CURRENT_TIME); | 2285 | apply_default_boot_configuration (manager, GDK_CURRENT_TIME); |
353 | 2073 | 2286 | ||
354 | 2287 | /* Initialise touchscreen mapping */ | ||
355 | 2288 | set_touchscreen_id (manager); | ||
356 | 2289 | if (manager->priv->main_touchscreen_id != -1) | ||
357 | 2290 | do_touchscreen_mapping (manager); | ||
358 | 2291 | |||
359 | 2074 | log_msg ("State of screen after initial configuration:\n"); | 2292 | log_msg ("State of screen after initial configuration:\n"); |
360 | 2075 | log_screen (manager->priv->rw_screen); | 2293 | log_screen (manager->priv->rw_screen); |
361 | 2076 | 2294 | ||
362 | @@ -2127,6 +2345,8 @@ | |||
363 | 2127 | } | 2345 | } |
364 | 2128 | #endif /* HAVE_WACOM */ | 2346 | #endif /* HAVE_WACOM */ |
365 | 2129 | 2347 | ||
366 | 2348 | g_free (manager->priv->main_touchscreen_name); | ||
367 | 2349 | |||
368 | 2130 | log_open (); | 2350 | log_open (); |
369 | 2131 | log_msg ("STOPPING XRANDR PLUGIN\n------------------------------------------------------------\n"); | 2351 | log_msg ("STOPPING XRANDR PLUGIN\n------------------------------------------------------------\n"); |
370 | 2132 | log_close (); | 2352 | log_close (); |
371 | @@ -2149,6 +2369,10 @@ | |||
372 | 2149 | 2369 | ||
373 | 2150 | manager->priv->current_fn_f7_config = -1; | 2370 | manager->priv->current_fn_f7_config = -1; |
374 | 2151 | manager->priv->fn_f7_configs = NULL; | 2371 | manager->priv->fn_f7_configs = NULL; |
375 | 2372 | |||
376 | 2373 | /* For touchscreen mapping */ | ||
377 | 2374 | manager->priv->main_touchscreen_id = -1; | ||
378 | 2375 | manager->priv->main_touchscreen_name = NULL; | ||
379 | 2152 | } | 2376 | } |
380 | 2153 | 2377 | ||
381 | 2154 | static void | 2378 | static void |
let's sru that one