]> Pileus Git - ~andy/gtk/blob - gtk/gtkmountoperation-x11.c
Miscellaneous string fixes
[~andy/gtk] / gtk / gtkmountoperation-x11.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* GTK - The GIMP Toolkit
3  * Copyright (C) David Zeuthen <davidz@redhat.com>
4  * Copyright (C) 2001 Havoc Pennington
5  * Copyright (C) 2005-2007 Vincent Untz
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GTK+ Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28  */
29
30 #include "config.h"
31
32 #include <string.h>
33 #include <stdlib.h>
34 #include <gio/gio.h>
35 #include "x11/gdkx.h"
36 #include <X11/Xatom.h>
37 #include <gtk/gtkicontheme.h>
38 #include "gtkintl.h"
39
40 /* for the kill(2) system call and errno - POSIX.1-2001 and later */
41 #include <sys/types.h>
42 #include <signal.h>
43 #include <errno.h>
44
45 #include "gtkmountoperationprivate.h"
46
47 /* ---------------------------------------------------------------------------------------------------- */
48 /* these functions are based on code from libwnck (LGPLv2) */
49
50 static gboolean get_window_list   (Display   *xdisplay,
51                                    Window     xwindow,
52                                    Atom       atom,
53                                    Window   **windows,
54                                    int       *len);
55
56 static char*    get_utf8_property (Display   *xdisplay,
57                                    Window     xwindow,
58                                    Atom       atom);
59
60 static gboolean get_cardinal      (Display   *xdisplay,
61                                    Window     xwindow,
62                                    Atom       atom,
63                                    int       *val);
64
65 static gboolean read_rgb_icon     (Display   *xdisplay,
66                                    Window     xwindow,
67                                    int        ideal_width,
68                                    int        ideal_height,
69                                    int       *width,
70                                    int       *height,
71                                    guchar   **pixdata);
72
73
74 static gboolean
75 get_cardinal (Display *xdisplay,
76               Window   xwindow,
77               Atom     atom,
78               int     *val)
79 {
80   Atom type;
81   int format;
82   gulong nitems;
83   gulong bytes_after;
84   gulong *num;
85   int err, result;
86
87   *val = 0;
88
89   gdk_error_trap_push ();
90   type = None;
91   result = XGetWindowProperty (xdisplay,
92                                xwindow,
93                                atom,
94                                0, G_MAXLONG,
95                                False, XA_CARDINAL, &type, &format, &nitems,
96                                &bytes_after, (void*)&num);
97   XSync (xdisplay, False);
98   err = gdk_error_trap_pop ();
99
100   if (err != Success ||
101       result != Success)
102     return FALSE;
103
104   if (type != XA_CARDINAL)
105     {
106       XFree (num);
107       return FALSE;
108     }
109
110   *val = *num;
111
112   XFree (num);
113
114   return TRUE;
115 }
116
117 static char*
118 get_utf8_property (Display *xdisplay,
119                    Window   xwindow,
120                    Atom     atom)
121 {
122   Atom type;
123   int format;
124   gulong nitems;
125   gulong bytes_after;
126   gchar *val;
127   int err, result;
128   char *retval;
129   Atom utf8_string;
130
131   utf8_string = gdk_x11_get_xatom_by_name ("UTF8_STRING");
132
133   gdk_error_trap_push ();
134   type = None;
135   val = NULL;
136   result = XGetWindowProperty (xdisplay,
137                                xwindow,
138                                atom,
139                                0, G_MAXLONG,
140                                False, utf8_string,
141                                &type, &format, &nitems,
142                                &bytes_after, (guchar **)&val);
143   XSync (xdisplay, False);
144   err = gdk_error_trap_pop ();
145
146   if (err != Success ||
147       result != Success)
148     return NULL;
149
150   if (type != utf8_string ||
151       format != 8 ||
152       nitems == 0)
153     {
154       if (val)
155         XFree (val);
156       return NULL;
157     }
158
159   if (!g_utf8_validate (val, nitems, NULL))
160     {
161       g_warning ("Property %s contained invalid UTF-8\n",
162                  gdk_x11_get_xatom_name (atom));
163       XFree (val);
164       return NULL;
165     }
166
167   retval = g_strndup (val, nitems);
168
169   XFree (val);
170
171   return retval;
172 }
173
174 static gboolean
175 find_largest_sizes (gulong *data,
176                     gulong  nitems,
177                     int    *width,
178                     int    *height)
179 {
180   *width = 0;
181   *height = 0;
182
183   while (nitems > 0)
184     {
185       int w, h;
186       gboolean replace;
187
188       replace = FALSE;
189
190       if (nitems < 3)
191         return FALSE; /* no space for w, h */
192
193       w = data[0];
194       h = data[1];
195
196       if (nitems < ((w * h) + 2))
197         return FALSE; /* not enough data */
198
199       *width = MAX (w, *width);
200       *height = MAX (h, *height);
201
202       data += (w * h) + 2;
203       nitems -= (w * h) + 2;
204     }
205
206   return TRUE;
207 }
208
209 static gboolean
210 find_best_size (gulong  *data,
211                 gulong   nitems,
212                 int      ideal_width,
213                 int      ideal_height,
214                 int     *width,
215                 int     *height,
216                 gulong **start)
217 {
218   int best_w;
219   int best_h;
220   gulong *best_start;
221   int max_width, max_height;
222
223   *width = 0;
224   *height = 0;
225   *start = NULL;
226
227   if (!find_largest_sizes (data, nitems, &max_width, &max_height))
228     return FALSE;
229
230   if (ideal_width < 0)
231     ideal_width = max_width;
232   if (ideal_height < 0)
233     ideal_height = max_height;
234
235   best_w = 0;
236   best_h = 0;
237   best_start = NULL;
238
239   while (nitems > 0)
240     {
241       int w, h;
242       gboolean replace;
243
244       replace = FALSE;
245
246       if (nitems < 3)
247         return FALSE; /* no space for w, h */
248
249       w = data[0];
250       h = data[1];
251
252       if (nitems < ((w * h) + 2))
253         break; /* not enough data */
254
255       if (best_start == NULL)
256         {
257           replace = TRUE;
258         }
259       else
260         {
261           /* work with averages */
262           const int ideal_size = (ideal_width + ideal_height) / 2;
263           int best_size = (best_w + best_h) / 2;
264           int this_size = (w + h) / 2;
265
266           /* larger than desired is always better than smaller */
267           if (best_size < ideal_size &&
268               this_size >= ideal_size)
269             replace = TRUE;
270           /* if we have too small, pick anything bigger */
271           else if (best_size < ideal_size &&
272                    this_size > best_size)
273             replace = TRUE;
274           /* if we have too large, pick anything smaller
275            * but still >= the ideal
276            */
277           else if (best_size > ideal_size &&
278                    this_size >= ideal_size &&
279                    this_size < best_size)
280             replace = TRUE;
281         }
282
283       if (replace)
284         {
285           best_start = data + 2;
286           best_w = w;
287           best_h = h;
288         }
289
290       data += (w * h) + 2;
291       nitems -= (w * h) + 2;
292     }
293
294   if (best_start)
295     {
296       *start = best_start;
297       *width = best_w;
298       *height = best_h;
299       return TRUE;
300     }
301   else
302     return FALSE;
303 }
304
305 static void
306 argbdata_to_pixdata (gulong  *argb_data,
307                      int      len,
308                      guchar **pixdata)
309 {
310   guchar *p;
311   int i;
312
313   *pixdata = g_new (guchar, len * 4);
314   p = *pixdata;
315
316   /* One could speed this up a lot. */
317   i = 0;
318   while (i < len)
319     {
320       guint argb;
321       guint rgba;
322
323       argb = argb_data[i];
324       rgba = (argb << 8) | (argb >> 24);
325
326       *p = rgba >> 24;
327       ++p;
328       *p = (rgba >> 16) & 0xff;
329       ++p;
330       *p = (rgba >> 8) & 0xff;
331       ++p;
332       *p = rgba & 0xff;
333       ++p;
334
335       ++i;
336     }
337 }
338
339 static gboolean
340 read_rgb_icon (Display   *xdisplay,
341                Window     xwindow,
342                int        ideal_width,
343                int        ideal_height,
344                int       *width,
345                int       *height,
346                guchar   **pixdata)
347 {
348   Atom type;
349   int format;
350   gulong nitems;
351   gulong bytes_after;
352   int result, err;
353   gulong *data;
354   gulong *best;
355   int w, h;
356
357   gdk_error_trap_push ();
358   type = None;
359   data = NULL;
360   result = XGetWindowProperty (xdisplay,
361                                xwindow,
362                                gdk_x11_get_xatom_by_name ("_NET_WM_ICON"),
363                                0, G_MAXLONG,
364                                False, XA_CARDINAL, &type, &format, &nitems,
365                                &bytes_after, (void*)&data);
366
367   XSync (xdisplay, False);
368   err = gdk_error_trap_pop ();
369
370   if (err != Success ||
371       result != Success)
372     return FALSE;
373
374   if (type != XA_CARDINAL)
375     {
376       XFree (data);
377       return FALSE;
378     }
379
380   if (!find_best_size (data, nitems,
381                        ideal_width, ideal_height,
382                        &w, &h, &best))
383     {
384       XFree (data);
385       return FALSE;
386     }
387
388   *width = w;
389   *height = h;
390
391   argbdata_to_pixdata (best, w * h, pixdata);
392
393   XFree (data);
394
395   return TRUE;
396 }
397
398 static void
399 free_pixels (guchar *pixels, gpointer data)
400 {
401   g_free (pixels);
402 }
403
404 static GdkPixbuf*
405 scaled_from_pixdata (guchar *pixdata,
406                      int     w,
407                      int     h,
408                      int     new_w,
409                      int     new_h)
410 {
411   GdkPixbuf *src;
412   GdkPixbuf *dest;
413
414   src = gdk_pixbuf_new_from_data (pixdata,
415                                   GDK_COLORSPACE_RGB,
416                                   TRUE,
417                                   8,
418                                   w, h, w * 4,
419                                   free_pixels,
420                                   NULL);
421
422   if (src == NULL)
423     return NULL;
424
425   if (w != h)
426     {
427       GdkPixbuf *tmp;
428       int size;
429
430       size = MAX (w, h);
431
432       tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size, size);
433
434       if (tmp != NULL)
435         {
436           gdk_pixbuf_fill (tmp, 0);
437           gdk_pixbuf_copy_area (src, 0, 0, w, h,
438                                 tmp,
439                                 (size - w) / 2, (size - h) / 2);
440
441           g_object_unref (src);
442           src = tmp;
443         }
444     }
445
446   if (w != new_w || h != new_h)
447     {
448       dest = gdk_pixbuf_scale_simple (src, new_w, new_h, GDK_INTERP_BILINEAR);
449
450       g_object_unref (G_OBJECT (src));
451     }
452   else
453     {
454       dest = src;
455     }
456
457   return dest;
458 }
459
460 static gboolean
461 get_window_list (Display  *xdisplay,
462                  Window    xwindow,
463                  Atom      atom,
464                  Window  **windows,
465                  int      *len)
466 {
467   Atom type;
468   int format;
469   gulong nitems;
470   gulong bytes_after;
471   Window *data;
472   int err, result;
473
474   *windows = NULL;
475   *len = 0;
476
477   gdk_error_trap_push ();
478   type = None;
479   result = XGetWindowProperty (xdisplay,
480                                xwindow,
481                                atom,
482                                0, G_MAXLONG,
483                                False, XA_WINDOW, &type, &format, &nitems,
484                                &bytes_after, (void*)&data);
485   XSync (xdisplay, False);
486   err = gdk_error_trap_pop ();
487
488   if (err != Success ||
489       result != Success)
490     return FALSE;
491
492   if (type != XA_WINDOW)
493     {
494       XFree (data);
495       return FALSE;
496     }
497
498   *windows = g_new (Window, nitems);
499   memcpy (*windows, data, sizeof (Window) * nitems);
500   *len = nitems;
501
502   XFree (data);
503
504   return TRUE;
505 }
506
507
508 /* ---------------------------------------------------------------------------------------------------- */
509
510 struct _GtkMountOperationLookupContext
511 {
512   /* Hash from pid (gint) -> XID (gint)
513    *
514    * Note that XIDs are at most 27 bits - however, also note that sizeof(XID) == 8 on
515    * x86_64 - that's just xlib brokenness. So it's safe to stuff the XID into a pointer.
516    */
517   GHashTable *pid_to_window;
518   GdkDisplay *display;
519 };
520
521 GtkMountOperationLookupContext *
522 _gtk_mount_operation_lookup_context_get (GdkDisplay *display)
523 {
524   GtkMountOperationLookupContext *context;
525   Window *mapping;
526   gint mapping_length;
527   gint n;
528
529   context = g_new0 (GtkMountOperationLookupContext, 1);
530
531   context->pid_to_window = g_hash_table_new (g_direct_hash, g_direct_equal);
532   context->display = display;
533
534   mapping = NULL;
535   mapping_length = 0;
536   get_window_list (GDK_DISPLAY_XDISPLAY (context->display),
537                    GDK_ROOT_WINDOW(),
538                    gdk_x11_get_xatom_by_name_for_display (context->display,
539                                                           "_NET_CLIENT_LIST"),
540                    &mapping,
541                    &mapping_length);
542   for (n = 0; n < mapping_length; n++)
543     {
544       gint pid;
545
546       if (!get_cardinal (GDK_DISPLAY_XDISPLAY (context->display),
547                          mapping[n],
548                          gdk_x11_get_xatom_by_name_for_display (context->display,
549                                                                 "_NET_WM_PID"),
550                          &pid))
551         continue;
552
553       g_hash_table_insert (context->pid_to_window,
554                            GINT_TO_POINTER (pid),
555                            GINT_TO_POINTER ((gint) mapping[n]));
556     }
557   g_free (mapping);
558
559   return context;
560 }
561
562 void
563 _gtk_mount_operation_lookup_context_free (GtkMountOperationLookupContext *context)
564 {
565   g_hash_table_unref (context->pid_to_window);
566   g_free (context);
567 }
568
569 /* ---------------------------------------------------------------------------------------------------- */
570
571 #ifdef __linux__
572
573 static GPid
574 pid_get_parent (GPid pid)
575 {
576   GPid ppid;
577   gchar **tokens;
578   gchar *stat_filename;
579   gchar *stat_contents;
580   gsize stat_len;
581
582   ppid = 0;
583   tokens = NULL;
584   stat_contents = NULL;
585   stat_filename = NULL;
586
587   /* fail if trying to get the parent of the init process (no such thing) */
588   if (pid == 1)
589       goto out;
590
591   stat_filename = g_strdup_printf ("/proc/%d/status", pid);
592   if (g_file_get_contents (stat_filename,
593                            &stat_contents,
594                            &stat_len,
595                            NULL))
596     {
597       guint n;
598
599       tokens = g_strsplit (stat_contents, "\n", 0);
600
601       for (n = 0; tokens[n] != NULL; n++)
602         {
603           if (g_str_has_prefix (tokens[n], "PPid:"))
604             {
605               gchar *endp;
606
607               endp = NULL;
608               ppid = strtoll (tokens[n] + sizeof "PPid:" - 1, &endp, 10);
609               if (endp == NULL || *endp != '\0')
610                 {
611                   g_warning ("Error parsing contents of `%s'. Parent pid is malformed.",
612                              stat_filename);
613                   ppid = 0;
614                   goto out;
615                 }
616
617               break;
618             }
619         }
620     }
621
622  out:
623   g_strfreev (tokens);
624   g_free (stat_contents);
625   g_free (stat_filename);
626
627   return ppid;
628 }
629
630 static gchar *
631 pid_get_env (GPid         pid,
632              const gchar *key)
633 {
634   gchar *ret;
635   gchar *env_filename;
636   gchar *env;
637   gsize env_len;
638   gsize key_len;
639   gchar *end;
640
641   ret = NULL;
642
643   key_len = strlen (key);
644
645   env_filename = g_strdup_printf ("/proc/%d/environ", pid);
646   if (g_file_get_contents (env_filename,
647                            &env,
648                            &env_len,
649                            NULL))
650     {
651       guint n;
652
653       /* /proc/<pid>/environ in Linux is split at '\0' points, g_strsplit() can't handle that... */
654       n = 0;
655       while (TRUE)
656         {
657           if (env[n] == '\0' || n >= env_len)
658             break;
659
660           if (g_str_has_prefix (env + n, key) && (*(env + n + key_len) == '='))
661             {
662               ret = g_strdup (env + n + key_len + 1);
663
664               /* skip invalid UTF-8 */
665               if (!g_utf8_validate (ret, -1, (const gchar **) &end))
666                 *end = '\0';
667               break;
668             }
669
670           for (; env[n] != '\0' && n < env_len; n++)
671             ;
672           n++;
673         }
674       g_free (env);
675     }
676   g_free (env_filename);
677
678   return ret;
679 }
680
681 static gchar *
682 pid_get_command_line (GPid pid)
683 {
684   gchar *cmdline_filename;
685   gchar *cmdline_contents;
686   gsize cmdline_len;
687   guint n;
688   gchar *end;
689
690   cmdline_contents = NULL;
691
692   cmdline_filename = g_strdup_printf ("/proc/%d/cmdline", pid);
693   if (!g_file_get_contents (cmdline_filename,
694                             &cmdline_contents,
695                             &cmdline_len,
696                             NULL))
697     goto out;
698
699   /* /proc/<pid>/cmdline separates args by NUL-bytes - replace with spaces */
700   for (n = 0; n < cmdline_len - 1; n++)
701     {
702       if (cmdline_contents[n] == '\0')
703         cmdline_contents[n] = ' ';
704     }
705
706   /* skip invalid UTF-8 */
707   if (!g_utf8_validate (cmdline_contents, -1, (const gchar **) &end))
708       *end = '\0';
709
710  out:
711   g_free (cmdline_filename);
712
713   return cmdline_contents;
714 }
715
716 /* ---------------------------------------------------------------------------------------------------- */
717 #else
718
719 /* TODO: please implement for your OS - must return valid UTF-8 */
720
721 static GPid
722 pid_get_parent (GPid pid)
723 {
724   return 0;
725 }
726
727 static gchar *
728 pid_get_env (GPid         pid,
729              const gchar *key)
730 {
731   return NULL;
732 }
733
734 static gchar *
735 pid_get_command_line (GPid pid)
736 {
737   return NULL;
738 }
739
740 #endif
741
742 /* ---------------------------------------------------------------------------------------------------- */
743
744 static gchar *
745 get_name_for_window_with_pid (GtkMountOperationLookupContext *context,
746                               GPid                            pid)
747 {
748   Window window;
749   Window windowid_window;
750   gchar *ret;
751
752   ret = NULL;
753
754   window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
755   if (window == None)
756     {
757       gchar *windowid_value;
758
759       /* check for $WINDOWID (set by terminals) and see if we can get the title that way */
760       windowid_value = pid_get_env (pid, "WINDOWID");
761       if (windowid_value != NULL)
762         {
763           gchar *endp;
764
765           endp = NULL;
766           windowid_window = (Window) g_ascii_strtoll (windowid_value, &endp, 10);
767           if (endp != NULL || *endp == '\0')
768             {
769               window = windowid_window;
770             }
771           g_free (windowid_value);
772         }
773
774       /* otherwise, check for parents */
775       if (window == None)
776         {
777           do
778             {
779               pid = pid_get_parent (pid);
780               if (pid == 0)
781                 break;
782
783               window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
784               if (window != None)
785                 break;
786             }
787           while (TRUE);
788         }
789     }
790
791   if (window != None)
792     {
793       ret = get_utf8_property (GDK_DISPLAY_XDISPLAY (context->display),
794                                window,
795                                gdk_x11_get_xatom_by_name_for_display (context->display,
796                                                                       "_NET_WM_NAME"));
797       if (ret == NULL)
798         ret = get_utf8_property (GDK_DISPLAY_XDISPLAY (context->display),
799                                  window, gdk_x11_get_xatom_by_name_for_display (context->display,
800                                                                                 "_NET_WM_ICON_NAME"));
801     }
802
803   return ret;
804 }
805
806 /* ---------------------------------------------------------------------------------------------------- */
807
808 static GdkPixbuf *
809 get_pixbuf_for_window_with_pid (GtkMountOperationLookupContext *context,
810                                 GPid                            pid,
811                                 gint                            size_pixels)
812 {
813   Window window;
814   GdkPixbuf *ret;
815
816   ret = NULL;
817
818   window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
819   if (window == None)
820     {
821       /* otherwise, check for parents */
822       do
823         {
824           pid = pid_get_parent (pid);
825           if (pid == 0)
826             break;
827
828           window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
829           if (window != None)
830             break;
831         }
832       while (TRUE);
833     }
834
835   if (window != None)
836     {
837       gint    width;
838       gint    height;
839       guchar *pixdata;
840
841       if (read_rgb_icon (GDK_DISPLAY_XDISPLAY (context->display),
842                          window,
843                          size_pixels, size_pixels,
844                          &width, &height,
845                          &pixdata))
846         {
847           /* steals pixdata */
848           ret = scaled_from_pixdata (pixdata,
849                                      width, height,
850                                      size_pixels, size_pixels);
851         }
852     }
853
854   return ret;
855 }
856
857 /* ---------------------------------------------------------------------------------------------------- */
858
859 static const gchar *well_known_commands[] =
860 {
861   /* translators: this string is a name for the 'less' command */
862   "less", N_("Terminal Pager"),
863   "top", N_("Top Command"),
864   "bash", N_("Bourne Again Shell"),
865   "sh", N_("Bourne Shell"),
866   "zsh", N_("Z Shell"),
867   NULL,
868 };
869
870 gboolean
871 _gtk_mount_operation_lookup_info (GtkMountOperationLookupContext *context,
872                                   GPid                            pid,
873                                   gint                            size_pixels,
874                                   gchar                         **out_name,
875                                   gchar                         **out_command_line,
876                                   GdkPixbuf                     **out_pixbuf)
877 {
878   g_return_val_if_fail (out_name != NULL && *out_name == NULL, FALSE);
879   g_return_val_if_fail (out_command_line != NULL && *out_command_line == NULL, FALSE);
880   g_return_val_if_fail (out_pixbuf != NULL && *out_pixbuf == NULL, FALSE);
881
882   /* We perform two different lookups for name and icon size.. this is
883    * because we want the name from the window with WINDOWID and this
884    * normally does not give you an icon
885    *
886    * (the canonical example is a tab in gnome-terminal - the shell/command running
887    *  in the shell will have WINDOWID set - but this window won't have an icon - so
888    *  we want to continue up until the gnome-terminal window so we can get that icon)
889    */
890
891   *out_command_line = pid_get_command_line (pid);
892
893   *out_name = get_name_for_window_with_pid (context, pid);
894
895   *out_pixbuf = get_pixbuf_for_window_with_pid (context, pid, size_pixels);
896
897   /* if we didn't manage to find the name via X, fall back to the basename
898    * of the first element of the command line and, for maximum geek-comfort,
899    * map a few well-known commands to proper translated names
900    */
901   if (*out_name == NULL && *out_command_line != NULL &&
902       strlen (*out_command_line) > 0 && (*out_command_line)[0] != ' ')
903     {
904       guint n;
905       gchar *s;
906       gchar *p;
907
908       /* find the first character after the first argument */
909       s = strchr (*out_command_line, ' ');
910       if (s == NULL)
911         s = *out_command_line + strlen (*out_command_line);
912
913       for (p = s; p > *out_command_line; p--)
914         {
915           if (*p == '/')
916             {
917               p++;
918               break;
919             }
920         }
921
922       *out_name = g_strndup (p, s - p);
923
924       for (n = 0; well_known_commands[n] != NULL; n += 2)
925         {
926           /* sometimes the command is prefixed with a -, e.g. '-bash' instead
927            * of 'bash' - handle that as well
928            */
929           if ((strcmp (well_known_commands[n], *out_name) == 0) ||
930               ((*out_name)[0] == '-' && (strcmp (well_known_commands[n], (*out_name) + 1) == 0)))
931             {
932               g_free (*out_name);
933               *out_name = g_strdup (_(well_known_commands[n+1]));
934               break;
935             }
936         }
937     }
938
939   return TRUE;
940 }
941
942 gboolean
943 _gtk_mount_operation_kill_process (GPid      pid,
944                                    GError  **error)
945 {
946   gboolean ret;
947
948   ret = TRUE;
949
950   if (kill ((pid_t) pid, SIGTERM) != 0)
951     {
952       int errsv = errno;
953
954       /* TODO: On EPERM, we could use a setuid helper using polkit (very easy to implement
955        *       via pkexec(1)) to allow the user to e.g. authenticate to gain the authorization
956        *       to kill the process. But that's not how things currently work.
957        */
958
959       ret = FALSE;
960       g_set_error (error,
961                    G_IO_ERROR,
962                    g_io_error_from_errno (errsv),
963                    _("Cannot end process with PID %d: %s"),
964                    pid,
965                    g_strerror (errsv));
966     }
967
968   return ret;
969 }