]> Pileus Git - ~andy/gtk/blob - gtk/gtkmountoperation-x11.c
Merge branch 'bgo593793-filechooser-recent-folders-master'
[~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 #if defined(__OpenBSD__)
46 #include <kvm.h>
47 #include <fcntl.h>
48 #include <sys/sysctl.h>
49 #endif
50
51 #include "gtkmountoperationprivate.h"
52
53 /* ---------------------------------------------------------------------------------------------------- */
54 /* these functions are based on code from libwnck (LGPLv2) */
55
56 static gboolean get_window_list   (Display   *xdisplay,
57                                    Window     xwindow,
58                                    Atom       atom,
59                                    Window   **windows,
60                                    int       *len);
61
62 static char*    get_utf8_property (Display   *xdisplay,
63                                    Window     xwindow,
64                                    Atom       atom);
65
66 static gboolean get_cardinal      (Display   *xdisplay,
67                                    Window     xwindow,
68                                    Atom       atom,
69                                    int       *val);
70
71 static gboolean read_rgb_icon     (Display   *xdisplay,
72                                    Window     xwindow,
73                                    int        ideal_width,
74                                    int        ideal_height,
75                                    int       *width,
76                                    int       *height,
77                                    guchar   **pixdata);
78
79
80 static gboolean
81 get_cardinal (Display *xdisplay,
82               Window   xwindow,
83               Atom     atom,
84               int     *val)
85 {
86   Atom type;
87   int format;
88   gulong nitems;
89   gulong bytes_after;
90   gulong *num;
91   int err, result;
92
93   *val = 0;
94
95   gdk_error_trap_push ();
96   type = None;
97   result = XGetWindowProperty (xdisplay,
98                                xwindow,
99                                atom,
100                                0, G_MAXLONG,
101                                False, XA_CARDINAL, &type, &format, &nitems,
102                                &bytes_after, (void*)&num);
103   XSync (xdisplay, False);
104   err = gdk_error_trap_pop ();
105
106   if (err != Success ||
107       result != Success)
108     return FALSE;
109
110   if (type != XA_CARDINAL)
111     {
112       XFree (num);
113       return FALSE;
114     }
115
116   *val = *num;
117
118   XFree (num);
119
120   return TRUE;
121 }
122
123 static char*
124 get_utf8_property (Display *xdisplay,
125                    Window   xwindow,
126                    Atom     atom)
127 {
128   Atom type;
129   int format;
130   gulong nitems;
131   gulong bytes_after;
132   gchar *val;
133   int err, result;
134   char *retval;
135   Atom utf8_string;
136
137   utf8_string = gdk_x11_get_xatom_by_name ("UTF8_STRING");
138
139   gdk_error_trap_push ();
140   type = None;
141   val = NULL;
142   result = XGetWindowProperty (xdisplay,
143                                xwindow,
144                                atom,
145                                0, G_MAXLONG,
146                                False, utf8_string,
147                                &type, &format, &nitems,
148                                &bytes_after, (guchar **)&val);
149   XSync (xdisplay, False);
150   err = gdk_error_trap_pop ();
151
152   if (err != Success ||
153       result != Success)
154     return NULL;
155
156   if (type != utf8_string ||
157       format != 8 ||
158       nitems == 0)
159     {
160       if (val)
161         XFree (val);
162       return NULL;
163     }
164
165   if (!g_utf8_validate (val, nitems, NULL))
166     {
167       g_warning ("Property %s contained invalid UTF-8\n",
168                  gdk_x11_get_xatom_name (atom));
169       XFree (val);
170       return NULL;
171     }
172
173   retval = g_strndup (val, nitems);
174
175   XFree (val);
176
177   return retval;
178 }
179
180 static gboolean
181 find_largest_sizes (gulong *data,
182                     gulong  nitems,
183                     int    *width,
184                     int    *height)
185 {
186   *width = 0;
187   *height = 0;
188
189   while (nitems > 0)
190     {
191       int w, h;
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
721 #elif defined(__OpenBSD__)
722
723 /* ---------------------------------------------------------------------------------------------------- */
724
725 static GPid
726 pid_get_parent (GPid pid)
727 {
728   struct kinfo_proc *proc;
729   int count;
730   kvm_t *kvm;
731   GPid ppid = 0;
732
733   kvm = kvm_openfiles (NULL, NULL, NULL, KVM_NO_FILES, NULL);
734   if (kvm == NULL)
735     return 0;
736
737   proc = kvm_getprocs (kvm, KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &count);
738   if (count == 1)
739     ppid = proc->p_ppid;
740
741   kvm_close (kvm);
742   return ppid;
743 }
744
745 static gchar *
746 pid_get_env (GPid pid, const gchar *key)
747 {
748   kvm_t *kvm;
749   struct kinfo_proc *proc;
750   char **strs;
751   char *ret;
752   char *end;
753   int key_len;
754   int count;
755   int i;
756
757   kvm = kvm_openfiles (NULL, NULL, NULL, KVM_NO_FILES, NULL);
758   if (kvm == NULL)
759     return NULL;
760
761   key_len = strlen (key);
762
763   ret = NULL;
764   proc = kvm_getprocs (kvm, KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &count);
765   if (proc != NULL)
766     {
767       strs = kvm_getenvv (kvm, proc, 0);
768       for (i = 0; strs[i] != NULL; i++)
769         {
770           if (g_str_has_prefix (strs[i], key) && (*(strs[i] + key_len) == '='))
771             {
772               ret = g_strdup (strs[i] + key_len + 1);
773
774               /* skip invalid UTF-8 */
775               if (!g_utf8_validate (ret, -1, (const gchar **) &end))
776                 *end = '\0';
777               break;
778             }
779         }
780     }
781
782   kvm_close (kvm);
783   return ret;
784 }
785
786 static gchar *
787 pid_get_command_line (GPid pid)
788 {
789   kvm_t *kvm;
790   struct kinfo_proc *proc;
791   int count;
792   char **strs;
793   char *ret;
794   char *end;
795
796   kvm = kvm_openfiles (NULL, NULL, NULL, KVM_NO_FILES, NULL);
797   if (kvm == NULL)
798     return NULL;
799
800   proc = kvm_getprocs (kvm, KERN_PROC_PID, pid, sizeof (struct kinfo_proc), &count);
801   if (proc == NULL)
802     return NULL;
803
804   strs = kvm_getargv (kvm, proc, 0);
805   ret = g_strjoinv (" ", strs);
806   /* skip invalid UTF-8 */
807   if (!g_utf8_validate (ret, -1, (const gchar **) &end))
808     *end = '\0';
809
810   kvm_close (kvm);
811   return ret;
812 }
813
814 #else
815
816 /* TODO: please implement for your OS - must return valid UTF-8 */
817
818 static GPid
819 pid_get_parent (GPid pid)
820 {
821   return 0;
822 }
823
824 static gchar *
825 pid_get_env (GPid         pid,
826              const gchar *key)
827 {
828   return NULL;
829 }
830
831 static gchar *
832 pid_get_command_line (GPid pid)
833 {
834   return NULL;
835 }
836
837 #endif
838
839 /* ---------------------------------------------------------------------------------------------------- */
840
841 static gchar *
842 get_name_for_window_with_pid (GtkMountOperationLookupContext *context,
843                               GPid                            pid)
844 {
845   Window window;
846   Window windowid_window;
847   gchar *ret;
848
849   ret = NULL;
850
851   window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
852   if (window == None)
853     {
854       gchar *windowid_value;
855
856       /* check for $WINDOWID (set by terminals) and see if we can get the title that way */
857       windowid_value = pid_get_env (pid, "WINDOWID");
858       if (windowid_value != NULL)
859         {
860           gchar *endp;
861
862           endp = NULL;
863           windowid_window = (Window) g_ascii_strtoll (windowid_value, &endp, 10);
864           if (endp != NULL || *endp == '\0')
865             {
866               window = windowid_window;
867             }
868           g_free (windowid_value);
869         }
870
871       /* otherwise, check for parents */
872       if (window == None)
873         {
874           do
875             {
876               pid = pid_get_parent (pid);
877               if (pid == 0)
878                 break;
879
880               window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
881               if (window != None)
882                 break;
883             }
884           while (TRUE);
885         }
886     }
887
888   if (window != None)
889     {
890       ret = get_utf8_property (GDK_DISPLAY_XDISPLAY (context->display),
891                                window,
892                                gdk_x11_get_xatom_by_name_for_display (context->display,
893                                                                       "_NET_WM_NAME"));
894       if (ret == NULL)
895         ret = get_utf8_property (GDK_DISPLAY_XDISPLAY (context->display),
896                                  window, gdk_x11_get_xatom_by_name_for_display (context->display,
897                                                                                 "_NET_WM_ICON_NAME"));
898     }
899
900   return ret;
901 }
902
903 /* ---------------------------------------------------------------------------------------------------- */
904
905 static GdkPixbuf *
906 get_pixbuf_for_window_with_pid (GtkMountOperationLookupContext *context,
907                                 GPid                            pid,
908                                 gint                            size_pixels)
909 {
910   Window window;
911   GdkPixbuf *ret;
912
913   ret = NULL;
914
915   window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
916   if (window == None)
917     {
918       /* otherwise, check for parents */
919       do
920         {
921           pid = pid_get_parent (pid);
922           if (pid == 0)
923             break;
924
925           window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
926           if (window != None)
927             break;
928         }
929       while (TRUE);
930     }
931
932   if (window != None)
933     {
934       gint    width;
935       gint    height;
936       guchar *pixdata;
937
938       if (read_rgb_icon (GDK_DISPLAY_XDISPLAY (context->display),
939                          window,
940                          size_pixels, size_pixels,
941                          &width, &height,
942                          &pixdata))
943         {
944           /* steals pixdata */
945           ret = scaled_from_pixdata (pixdata,
946                                      width, height,
947                                      size_pixels, size_pixels);
948         }
949     }
950
951   return ret;
952 }
953
954 /* ---------------------------------------------------------------------------------------------------- */
955
956 static const gchar *well_known_commands[] =
957 {
958   /* translators: this string is a name for the 'less' command */
959   "less", N_("Terminal Pager"),
960   "top", N_("Top Command"),
961   "bash", N_("Bourne Again Shell"),
962   "sh", N_("Bourne Shell"),
963   "zsh", N_("Z Shell"),
964   NULL,
965 };
966
967 gboolean
968 _gtk_mount_operation_lookup_info (GtkMountOperationLookupContext *context,
969                                   GPid                            pid,
970                                   gint                            size_pixels,
971                                   gchar                         **out_name,
972                                   gchar                         **out_command_line,
973                                   GdkPixbuf                     **out_pixbuf)
974 {
975   g_return_val_if_fail (out_name != NULL && *out_name == NULL, FALSE);
976   g_return_val_if_fail (out_command_line != NULL && *out_command_line == NULL, FALSE);
977   g_return_val_if_fail (out_pixbuf != NULL && *out_pixbuf == NULL, FALSE);
978
979   /* We perform two different lookups for name and icon size.. this is
980    * because we want the name from the window with WINDOWID and this
981    * normally does not give you an icon
982    *
983    * (the canonical example is a tab in gnome-terminal - the shell/command running
984    *  in the shell will have WINDOWID set - but this window won't have an icon - so
985    *  we want to continue up until the gnome-terminal window so we can get that icon)
986    */
987
988   *out_command_line = pid_get_command_line (pid);
989
990   *out_name = get_name_for_window_with_pid (context, pid);
991
992   *out_pixbuf = get_pixbuf_for_window_with_pid (context, pid, size_pixels);
993
994   /* if we didn't manage to find the name via X, fall back to the basename
995    * of the first element of the command line and, for maximum geek-comfort,
996    * map a few well-known commands to proper translated names
997    */
998   if (*out_name == NULL && *out_command_line != NULL &&
999       strlen (*out_command_line) > 0 && (*out_command_line)[0] != ' ')
1000     {
1001       guint n;
1002       gchar *s;
1003       gchar *p;
1004
1005       /* find the first character after the first argument */
1006       s = strchr (*out_command_line, ' ');
1007       if (s == NULL)
1008         s = *out_command_line + strlen (*out_command_line);
1009
1010       for (p = s; p > *out_command_line; p--)
1011         {
1012           if (*p == '/')
1013             {
1014               p++;
1015               break;
1016             }
1017         }
1018
1019       *out_name = g_strndup (p, s - p);
1020
1021       for (n = 0; well_known_commands[n] != NULL; n += 2)
1022         {
1023           /* sometimes the command is prefixed with a -, e.g. '-bash' instead
1024            * of 'bash' - handle that as well
1025            */
1026           if ((strcmp (well_known_commands[n], *out_name) == 0) ||
1027               ((*out_name)[0] == '-' && (strcmp (well_known_commands[n], (*out_name) + 1) == 0)))
1028             {
1029               g_free (*out_name);
1030               *out_name = g_strdup (_(well_known_commands[n+1]));
1031               break;
1032             }
1033         }
1034     }
1035
1036   return TRUE;
1037 }
1038
1039 gboolean
1040 _gtk_mount_operation_kill_process (GPid      pid,
1041                                    GError  **error)
1042 {
1043   gboolean ret;
1044
1045   ret = TRUE;
1046
1047   if (kill ((pid_t) pid, SIGTERM) != 0)
1048     {
1049       int errsv = errno;
1050
1051       /* TODO: On EPERM, we could use a setuid helper using polkit (very easy to implement
1052        *       via pkexec(1)) to allow the user to e.g. authenticate to gain the authorization
1053        *       to kill the process. But that's not how things currently work.
1054        */
1055
1056       ret = FALSE;
1057       g_set_error (error,
1058                    G_IO_ERROR,
1059                    g_io_error_from_errno (errsv),
1060                    _("Cannot end process with PID %d: %s"),
1061                    pid,
1062                    g_strerror (errsv));
1063     }
1064
1065   return ret;
1066 }