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