~robert-ancell/unity-settings-daemon/fix-shell-watch

« back to all changes in this revision

Viewing changes to plugins/xrandr/gsd-xrandr-manager.c

  • Committer: CI Train Bot
  • Author(s): Alberto Milone
  • Date: 2015-08-25 09:09:30 UTC
  • mfrom: (4089.1.3 unity-settings-daemon)
  • Revision ID: ci-train-bot@canonical.com-20150825090930-5lca9p68ghcdlrxm
Make touchscreen mapping non-blocking, and kill it if it takes more than 3 seconds; finally, in case of failure, try again after a few seconds. This helps on resume from S3 (LP: #1471708). Fixes: #1471708
Approved by: Iain Lane

Show diffs side-by-side

added added

removed removed

Lines of Context:
129
129
        gchar *main_touchscreen_name;
130
130
};
131
131
 
 
132
typedef struct {
 
133
        int mapping_pid;
 
134
        guint mapping_kill_id;
 
135
        guint mapping_retry_id;
 
136
        gboolean mapping_killed;
 
137
} TouchMappingPrivate;
 
138
 
132
139
static const GsdRRRotation possible_rotations[] = {
133
140
        GSD_RR_ROTATION_0,
134
141
        GSD_RR_ROTATION_90,
157
164
 
158
165
static FILE *log_file;
159
166
 
 
167
/* Wait before retrying */
 
168
static const int RETRY_TIMEOUT = 5;
 
169
/* Wait before timing out */
 
170
static const int MAPPING_TIMEOUT = 3;
 
171
 
160
172
static GsdRROutput * input_info_find_size_match (GsdXrandrManager *manager, GsdRRScreen *rr_screen);
161
 
static int map_touch_to_output (GsdRRScreen *screen, int device_id, GsdRROutputInfo *output);
162
 
static void do_touchscreen_mapping (GsdXrandrManager *manager);
 
173
static int map_touch_to_output (GsdXrandrManager *manager, GsdRROutputInfo *output);
 
174
static gboolean do_touchscreen_mapping (GsdXrandrManager *manager);
163
175
 
164
176
static void
165
177
log_open (void)
2179
2191
        XFreeDeviceList (device_info);
2180
2192
}
2181
2193
 
 
2194
/* Kill a mapping process */
 
2195
static gboolean
 
2196
cb_mapping_child_kill (gpointer data)
 
2197
{
 
2198
        int kill_status;
 
2199
 
 
2200
        gchar *message = NULL;
 
2201
        TouchMappingPrivate *mapping_data = (TouchMappingPrivate*) data;
 
2202
 
 
2203
        message = g_strdup_printf ("Killing touchscreen mapping process %d after %d second(s) timeout...",
 
2204
                                    mapping_data->mapping_pid, MAPPING_TIMEOUT);
 
2205
 
 
2206
        if (!message) {
 
2207
                g_error ("Failed to allocate memory to log the killing of the mapping process");
 
2208
                goto out;
 
2209
        }
 
2210
 
 
2211
        g_warning ("%s", message);
 
2212
 
 
2213
        g_free (message);
 
2214
 
 
2215
        kill_status = kill (mapping_data->mapping_pid, SIGTERM);
 
2216
 
 
2217
        /* Mark as killed */
 
2218
        mapping_data->mapping_killed = TRUE;
 
2219
 
 
2220
        g_debug ("Kill status %d...", kill_status);
 
2221
 
 
2222
        if (kill_status != 0)
 
2223
                g_error ("Failed to kill mapping process: %s", strerror (errno));
 
2224
 
 
2225
out:
 
2226
        return G_SOURCE_REMOVE;
 
2227
}
 
2228
 
 
2229
/* Clean up spawned processes when they are done */
 
2230
static void
 
2231
cb_mapping_child_watch (GPid  pid,
 
2232
                        gint  status,
 
2233
                        gpointer data)
 
2234
{
 
2235
        TouchMappingPrivate *mapping_data = (TouchMappingPrivate*) data;
 
2236
 
 
2237
        g_debug ("Cleaning up spawned mapping");
 
2238
 
 
2239
        /* Close pid */
 
2240
        g_spawn_close_pid (pid);
 
2241
 
 
2242
        /* No need to kill a process that ended */
 
2243
        if (mapping_data->mapping_kill_id > 0) {
 
2244
                g_debug ("Cancelling killing of process that ended");
 
2245
                g_source_remove (mapping_data->mapping_kill_id);
 
2246
        }
 
2247
 
 
2248
        /* No need to retry if it succeeded */
 
2249
        if (!mapping_data->mapping_killed) {
 
2250
                g_debug ("Cancelling retry id %d", mapping_data->mapping_retry_id);
 
2251
                g_source_remove (mapping_data->mapping_retry_id);
 
2252
        }
 
2253
 
 
2254
        /* Free mapping data */
 
2255
        g_slice_free (TouchMappingPrivate, mapping_data);
 
2256
        mapping_data = NULL;
 
2257
}
 
2258
 
2182
2259
static int
2183
 
map_touch_to_output (GsdRRScreen *screen, int device_id,
2184
 
                     GsdRROutputInfo *output)
 
2260
map_touch_to_output (GsdXrandrManager *manager, GsdRROutputInfo *output)
2185
2261
{
2186
 
        int status = 0;
2187
 
        char command[100];
 
2262
        TouchMappingPrivate *mapping_data = NULL;
 
2263
        gchar *command_str = NULL;
 
2264
        GError **error = NULL;
 
2265
        gboolean success = FALSE;
 
2266
        gchar **command = NULL;
 
2267
 
 
2268
        GsdXrandrManagerPrivate *priv = manager->priv;
2188
2269
        gchar *name = gsd_rr_output_info_get_name (output);
2189
2270
 
2190
2271
        if (!name) {
2191
2272
                g_debug ("Failure to map screen with missing name");
2192
 
                status = 1;
2193
2273
                goto out;
2194
2274
        }
2195
2275
 
2196
 
        if (gsd_rr_output_info_is_active(output)) {
 
2276
        if (gsd_rr_output_info_is_active (output)) {
2197
2277
                g_debug ("Mapping touchscreen %d onto output %s",
2198
 
                         device_id, name);
2199
 
                sprintf (command, "xinput  --map-to-output %d %s",
2200
 
                         device_id, name);
2201
 
                status = system (command);
 
2278
                         priv->main_touchscreen_id, name);
 
2279
 
 
2280
                command_str = g_strdup_printf ("/usr/bin/xinput --map-to-output %d %s",
 
2281
                                               priv->main_touchscreen_id, name);
 
2282
 
 
2283
                if (!command_str)
 
2284
                        goto out;
 
2285
 
 
2286
                if (!g_shell_parse_argv (command_str, NULL, &command, NULL))
 
2287
                        goto out;
 
2288
 
 
2289
                /* Each spawned process gets its own mapping data */
 
2290
                mapping_data = g_slice_new (TouchMappingPrivate);
 
2291
                if (!mapping_data) {
 
2292
                        g_error ("Touchscreen mapping resource allocation failed");
 
2293
                        goto out;
 
2294
                }
 
2295
                /* Initialise mapping data */
 
2296
                mapping_data->mapping_pid = -1;
 
2297
                mapping_data->mapping_kill_id = 0;
 
2298
                mapping_data->mapping_retry_id = 0;
 
2299
                mapping_data->mapping_killed = FALSE;
 
2300
 
 
2301
                success = g_spawn_async (NULL,
 
2302
                                         command,
 
2303
                                         NULL,
 
2304
                                         G_SPAWN_DO_NOT_REAP_CHILD,
 
2305
                                         NULL,
 
2306
                                         NULL,
 
2307
                                         &(mapping_data->mapping_pid),
 
2308
                                         error);
 
2309
                g_strfreev (command);
 
2310
 
 
2311
                if (success) {
 
2312
                        g_debug ("Touchscreen mapping spawn succeeded");
 
2313
 
 
2314
                        /* Clean up after child is done */
 
2315
                        g_child_watch_add (mapping_data->mapping_pid, (GChildWatchFunc) cb_mapping_child_watch,
 
2316
                                           mapping_data);
 
2317
                        /* Kill the child after n seconds */
 
2318
                        mapping_data->mapping_kill_id = g_timeout_add_seconds (MAPPING_TIMEOUT,
 
2319
                                                                               (GSourceFunc) cb_mapping_child_kill,
 
2320
                                                                               mapping_data);
 
2321
                        /* Set potential retry */
 
2322
                        g_debug ("Retrying in %d second(s)", RETRY_TIMEOUT+MAPPING_TIMEOUT);
 
2323
                        mapping_data->mapping_retry_id = g_timeout_add_seconds (RETRY_TIMEOUT+MAPPING_TIMEOUT,
 
2324
                                                                                (GSourceFunc) do_touchscreen_mapping,
 
2325
                                                                                manager);
 
2326
                        g_debug ("Retry id: %d", mapping_data->mapping_retry_id);
 
2327
                }
 
2328
                else {
 
2329
                        g_error ("Touchscreen mapping failed");
 
2330
                        if (error != NULL)
 
2331
                                g_error ("%s", (*error)->message);
 
2332
                        g_clear_error (error);
 
2333
 
 
2334
                        /* Free mapping data */
 
2335
                        g_slice_free(TouchMappingPrivate, mapping_data);
 
2336
                        mapping_data = NULL;
 
2337
                }
2202
2338
        }
2203
2339
        else {
2204
2340
                g_debug ("No need to map %d onto output %s. The output is off",
2205
 
                         device_id, name);
 
2341
                         priv->main_touchscreen_id, name);
2206
2342
        }
2207
2343
 
2208
2344
out:
2209
 
        return (status == 0);
 
2345
        g_free (command_str);
 
2346
 
 
2347
        return success;
2210
2348
}
2211
2349
 
2212
 
static void
 
2350
static gboolean
2213
2351
do_touchscreen_mapping (GsdXrandrManager *manager)
2214
2352
{
2215
2353
        GsdXrandrManagerPrivate *priv = manager->priv;
2231
2369
        if (priv->main_touchscreen_id != -1) {
2232
2370
                /* Set initial mapping */
2233
2371
                g_debug ("Setting initial touchscreen mapping");
2234
 
                map_touch_to_output (screen,
2235
 
                                     priv->main_touchscreen_id,
2236
 
                                     laptop_output);
 
2372
                map_touch_to_output (manager, laptop_output);
2237
2373
        }
2238
2374
        else {
2239
2375
                g_debug ("No main touchscreen detected");
2241
2377
 
2242
2378
out:
2243
2379
        g_object_unref (current);
 
2380
 
 
2381
        return G_SOURCE_REMOVE;
2244
2382
}
2245
2383
 
2246
2384
gboolean