]> Pileus Git - ~andy/gtk/blob - gtk/gtkmountoperation-x11.c
Strip "Custom." prefix when getting default options from cups.
[~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 <stdlib.h>
47 #include <sys/param.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 kp;
730   size_t len;
731   GPid ppid;
732
733   int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid,
734                 sizeof(struct kinfo_proc), 0 };
735
736   if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) == -1)
737       return (-1);
738   mib[5] = (len / sizeof(struct kinfo_proc));
739
740   if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) < 0)
741       return -1;
742
743   ppid = kp.p_ppid;
744
745   return ppid;
746 }
747
748 static gchar *
749 pid_get_env (GPid pid, const gchar *key)
750 {
751   size_t len = PATH_MAX;
752   char **strs = NULL;
753   char *ret;
754   char *end;
755   int key_len;
756   int i;
757
758   int mib[] = { CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ENV };
759
760   strs = (char **)realloc(strs, len);
761
762   key_len = strlen (key);
763
764   ret = NULL;
765   if (sysctl(mib, nitems(mib), strs, &len, NULL, 0) != -1)
766     {
767       for (i = 0; strs[i] != NULL; i++)
768         {
769           if (g_str_has_prefix (strs[i], key) && (*(strs[i] + key_len) == '='))
770             {
771               ret = g_strdup (strs[i] + key_len + 1);
772
773               /* skip invalid UTF-8 */
774               if (!g_utf8_validate (ret, -1, (const gchar **) &end))
775                 *end = '\0';
776               break;
777             }
778         }
779     }
780
781   g_free (strs);
782   return ret;
783 }
784
785 static gchar *
786 pid_get_command_line (GPid pid)
787 {
788   size_t len = PATH_MAX;
789   char **strs = NULL;
790   char *ret = NULL;
791   char *end;
792
793   int mib[] = { CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV };
794
795   strs = (char **)realloc(strs, len);
796
797   if (sysctl(mib, nitems(mib), strs, &len, NULL, 0) == -1) {
798     g_free (strs);
799     return ret;
800   }
801
802   ret = g_strjoinv (" ", strs);
803   /* skip invalid UTF-8 */
804   if (!g_utf8_validate (ret, -1, (const gchar **) &end))
805     *end = '\0';
806
807   g_free (strs);
808   return ret;
809 }
810
811 #else
812
813 /* TODO: please implement for your OS - must return valid UTF-8 */
814
815 static GPid
816 pid_get_parent (GPid pid)
817 {
818   return 0;
819 }
820
821 static gchar *
822 pid_get_env (GPid         pid,
823              const gchar *key)
824 {
825   return NULL;
826 }
827
828 static gchar *
829 pid_get_command_line (GPid pid)
830 {
831   return NULL;
832 }
833
834 #endif
835
836 /* ---------------------------------------------------------------------------------------------------- */
837
838 static gchar *
839 get_name_for_window_with_pid (GtkMountOperationLookupContext *context,
840                               GPid                            pid)
841 {
842   Window window;
843   Window windowid_window;
844   gchar *ret;
845
846   ret = NULL;
847
848   window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
849   if (window == None)
850     {
851       gchar *windowid_value;
852
853       /* check for $WINDOWID (set by terminals) and see if we can get the title that way */
854       windowid_value = pid_get_env (pid, "WINDOWID");
855       if (windowid_value != NULL)
856         {
857           gchar *endp;
858
859           endp = NULL;
860           windowid_window = (Window) g_ascii_strtoll (windowid_value, &endp, 10);
861           if (endp != NULL || *endp == '\0')
862             {
863               window = windowid_window;
864             }
865           g_free (windowid_value);
866         }
867
868       /* otherwise, check for parents */
869       if (window == None)
870         {
871           do
872             {
873               pid = pid_get_parent (pid);
874               if (pid == 0)
875                 break;
876
877               window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
878               if (window != None)
879                 break;
880             }
881           while (TRUE);
882         }
883     }
884
885   if (window != None)
886     {
887       ret = get_utf8_property (GDK_DISPLAY_XDISPLAY (context->display),
888                                window,
889                                gdk_x11_get_xatom_by_name_for_display (context->display,
890                                                                       "_NET_WM_NAME"));
891       if (ret == NULL)
892         ret = get_utf8_property (GDK_DISPLAY_XDISPLAY (context->display),
893                                  window, gdk_x11_get_xatom_by_name_for_display (context->display,
894                                                                                 "_NET_WM_ICON_NAME"));
895     }
896
897   return ret;
898 }
899
900 /* ---------------------------------------------------------------------------------------------------- */
901
902 static GdkPixbuf *
903 get_pixbuf_for_window_with_pid (GtkMountOperationLookupContext *context,
904                                 GPid                            pid,
905                                 gint                            size_pixels)
906 {
907   Window window;
908   GdkPixbuf *ret;
909
910   ret = NULL;
911
912   window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
913   if (window == None)
914     {
915       /* otherwise, check for parents */
916       do
917         {
918           pid = pid_get_parent (pid);
919           if (pid == 0)
920             break;
921
922           window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
923           if (window != None)
924             break;
925         }
926       while (TRUE);
927     }
928
929   if (window != None)
930     {
931       gint    width;
932       gint    height;
933       guchar *pixdata;
934
935       if (read_rgb_icon (GDK_DISPLAY_XDISPLAY (context->display),
936                          window,
937                          size_pixels, size_pixels,
938                          &width, &height,
939                          &pixdata))
940         {
941           /* steals pixdata */
942           ret = scaled_from_pixdata (pixdata,
943                                      width, height,
944                                      size_pixels, size_pixels);
945         }
946     }
947
948   return ret;
949 }
950
951 /* ---------------------------------------------------------------------------------------------------- */
952
953 static const gchar *well_known_commands[] =
954 {
955   /* translators: this string is a name for the 'less' command */
956   "less", N_("Terminal Pager"),
957   "top", N_("Top Command"),
958   "bash", N_("Bourne Again Shell"),
959   "sh", N_("Bourne Shell"),
960   "zsh", N_("Z Shell"),
961   NULL,
962 };
963
964 gboolean
965 _gtk_mount_operation_lookup_info (GtkMountOperationLookupContext *context,
966                                   GPid                            pid,
967                                   gint                            size_pixels,
968                                   gchar                         **out_name,
969                                   gchar                         **out_command_line,
970                                   GdkPixbuf                     **out_pixbuf)
971 {
972   g_return_val_if_fail (out_name != NULL && *out_name == NULL, FALSE);
973   g_return_val_if_fail (out_command_line != NULL && *out_command_line == NULL, FALSE);
974   g_return_val_if_fail (out_pixbuf != NULL && *out_pixbuf == NULL, FALSE);
975
976   /* We perform two different lookups for name and icon size.. this is
977    * because we want the name from the window with WINDOWID and this
978    * normally does not give you an icon
979    *
980    * (the canonical example is a tab in gnome-terminal - the shell/command running
981    *  in the shell will have WINDOWID set - but this window won't have an icon - so
982    *  we want to continue up until the gnome-terminal window so we can get that icon)
983    */
984
985   *out_command_line = pid_get_command_line (pid);
986
987   *out_name = get_name_for_window_with_pid (context, pid);
988
989   *out_pixbuf = get_pixbuf_for_window_with_pid (context, pid, size_pixels);
990
991   /* if we didn't manage to find the name via X, fall back to the basename
992    * of the first element of the command line and, for maximum geek-comfort,
993    * map a few well-known commands to proper translated names
994    */
995   if (*out_name == NULL && *out_command_line != NULL &&
996       strlen (*out_command_line) > 0 && (*out_command_line)[0] != ' ')
997     {
998       guint n;
999       gchar *s;
1000       gchar *p;
1001
1002       /* find the first character after the first argument */
1003       s = strchr (*out_command_line, ' ');
1004       if (s == NULL)
1005         s = *out_command_line + strlen (*out_command_line);
1006
1007       for (p = s; p > *out_command_line; p--)
1008         {
1009           if (*p == '/')
1010             {
1011               p++;
1012               break;
1013             }
1014         }
1015
1016       *out_name = g_strndup (p, s - p);
1017
1018       for (n = 0; well_known_commands[n] != NULL; n += 2)
1019         {
1020           /* sometimes the command is prefixed with a -, e.g. '-bash' instead
1021            * of 'bash' - handle that as well
1022            */
1023           if ((strcmp (well_known_commands[n], *out_name) == 0) ||
1024               ((*out_name)[0] == '-' && (strcmp (well_known_commands[n], (*out_name) + 1) == 0)))
1025             {
1026               g_free (*out_name);
1027               *out_name = g_strdup (_(well_known_commands[n+1]));
1028               break;
1029             }
1030         }
1031     }
1032
1033   return TRUE;
1034 }
1035
1036 gboolean
1037 _gtk_mount_operation_kill_process (GPid      pid,
1038                                    GError  **error)
1039 {
1040   gboolean ret;
1041
1042   ret = TRUE;
1043
1044   if (kill ((pid_t) pid, SIGTERM) != 0)
1045     {
1046       int errsv = errno;
1047
1048       /* TODO: On EPERM, we could use a setuid helper using polkit (very easy to implement
1049        *       via pkexec(1)) to allow the user to e.g. authenticate to gain the authorization
1050        *       to kill the process. But that's not how things currently work.
1051        */
1052
1053       ret = FALSE;
1054       g_set_error (error,
1055                    G_IO_ERROR,
1056                    g_io_error_from_errno (errsv),
1057                    _("Cannot end process with PID %d: %s"),
1058                    pid,
1059                    g_strerror (errsv));
1060     }
1061
1062   return ret;
1063 }