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