ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gtkbfc/gtkbfc.c
Revision: 1.13
Committed: Sat Aug 18 13:51:16 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.12: +20 -11 lines
Log Message:
be a tad safer w.r.t. races

File Contents

# User Rev Content
1 root 1.6 /* this file is publiched under the gnu gpl license, version 3 or any later */
2    
3 root 1.1 #define _GNU_SOURCE
4    
5     #include <dlfcn.h>
6     #include <glib.h>
7     #include <gtk/gtk.h>
8     #include <stdlib.h>
9 root 1.4 #include <string.h>
10     #include <unistd.h>
11     #include <sys/types.h>
12     #include <sys/stat.h>
13     #include <fcntl.h>
14 root 1.1
15     static char *helper = "/etc/gtkbfc-helper";
16    
17     static GObject *(*old_constructor) (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties);
18    
19 root 1.4 static gchar *last_path;
20    
21 root 1.9 #if 0
22     # define DEBUG(stmt) stmt;
23     #else
24     # define DEBUG(stmt)
25     #endif
26 root 1.8
27 root 1.4 /////////////////////////////////////////////////////////////////////////////
28    
29     gchar *gtk_file_chooser_get_filename (GtkFileChooser *chooser)
30     {
31 root 1.12 DEBUG ((printf ("gtk_file_chooser_get_filename<%s>\n", last_path)))
32 root 1.4 return g_strdup (last_path ? last_path : "/nonex1st4nt");
33     }
34    
35     gboolean gtk_file_chooser_select_filename (GtkFileChooser *chooser, const char *filename)
36     {
37     return 1;
38     }
39    
40     void gtk_file_chooser_unselect_all (GtkFileChooser *chooser)
41     {
42     }
43    
44     gboolean gtk_file_chooser_set_filename (GtkFileChooser *chooser, const char *filename)
45     {
46     return 1;
47     }
48    
49     void gtk_file_chooser_set_current_name (GtkFileChooser *chooser, const char *filename)
50     {
51     }
52    
53     GSList *gtk_file_chooser_get_filenames (GtkFileChooser *chooser)
54     {
55     GSList *rv = 0;
56     rv = g_slist_prepend (rv, gtk_file_chooser_get_filename (chooser));
57     return rv;
58     }
59    
60     gboolean gtk_file_chooser_set_current_folder (GtkFileChooser *chooser, const gchar *folder)
61     {
62     return 1;
63     }
64    
65     gchar * gtk_file_chooser_get_current_folder (GtkFileChooser *chooser)
66     {
67 root 1.8 DEBUG ((printf ("gtk_file_chooser_get_current_folder\n")))
68 root 1.10 return g_strdup ("/tmp/gtkbfc");
69 root 1.4 }
70    
71     /////////////////////////////////////////////////////////////////////////////
72    
73     static const gchar *
74     from_uri (const gchar *uri)
75     {
76     const gchar *rv = uri;
77    
78     if (uri && uri == strstr (uri, "file:///"))
79     rv = uri + 7;
80    
81     return rv;
82     }
83    
84     static gchar *
85 root 1.7 to_uri (gchar *file)
86 root 1.4 {
87     gchar *rv = NULL;
88    
89     if (file)
90     {
91     GString *str = g_string_new ("file://");
92    
93     str = g_string_append (str, file);
94     rv = g_strdup (str->str);
95     g_string_free (str, TRUE);
96     g_free (file);
97     }
98    
99     return rv;
100     }
101    
102     static GSList *
103     to_uris (GSList *files)
104     {
105     GSList *item = files;
106    
107     for (; item; item = g_slist_next (item))
108     {
109     GString *str = g_string_new ("file://");
110     gchar *cur = item->data;
111    
112     str = g_string_append (str, cur);
113     item->data = g_string_free (str, FALSE);
114     g_free (cur);
115     }
116    
117     return files;
118     }
119    
120 root 1.7 gchar *gtk_file_chooser_get_uri (GtkFileChooser *chooser)
121 root 1.4 {
122 root 1.8 gchar *uri = to_uri(gtk_file_chooser_get_filename (chooser));
123 root 1.12 DEBUG ((printf ("gtk_file_chooser_get_uri<%s>\n", uri)));
124 root 1.8 return uri;
125 root 1.4 }
126    
127     gboolean gtk_file_chooser_set_uri (GtkFileChooser *chooser, const char *uri)
128     {
129     return gtk_file_chooser_set_filename (chooser, from_uri (uri));
130     }
131    
132     GSList *gtk_file_chooser_get_uris (GtkFileChooser *chooser)
133     {
134     return to_uris (gtk_file_chooser_get_filenames (chooser));
135     }
136    
137     gboolean gtk_file_chooser_set_current_folder_uri(GtkFileChooser *chooser, const gchar *uri)
138     {
139     return gtk_file_chooser_set_current_folder (chooser, from_uri (uri));
140     }
141    
142     gchar *gtk_file_chooser_get_current_folder_uri (GtkFileChooser *chooser)
143     {
144     return to_uri (gtk_file_chooser_get_current_folder (chooser));
145     }
146    
147     /////////////////////////////////////////////////////////////////////////////
148    
149 root 1.12 static gboolean disable_cb (gpointer data)
150 root 1.4 {
151 root 1.10 ((void (*)(void *, const char *)) dlsym (RTLD_NEXT, "gtk_file_chooser_set_filename"))(GTK_FILE_CHOOSER (data), "/tmp/gtkbfc/empty");
152 root 1.13
153     GtkWidget *toplevel = gtk_widget_get_toplevel (data);
154     if (toplevel) gtk_widget_set_sensitive (toplevel, 0);
155    
156     gtk_widget_unref (data);
157    
158 root 1.4 return FALSE;
159     }
160    
161     static gboolean read_result (GIOChannel *source, GIOCondition condition, gpointer data)
162     {
163 root 1.7 if (last_path)
164     {
165     g_free (last_path);
166     last_path = 0;
167     }
168    
169 root 1.4 g_io_channel_read_to_end (source, &last_path, 0, 0);
170     g_io_channel_unref (source);
171 root 1.8
172 root 1.13 GtkWidget *toplevel = gtk_widget_get_toplevel (data);
173     if (toplevel) gtk_widget_set_sensitive (toplevel, 1);
174 root 1.12
175     if (!last_path || *last_path != '/')
176     {
177     DEBUG ((printf ("read_result cancel\n")))
178     g_free (last_path);
179     last_path = 0;
180     }
181     else
182     {
183     DEBUG ((printf ("read_result<%s>\n", last_path)))
184     gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (data), FALSE);
185     g_signal_emit_by_name (GTK_FILE_CHOOSER (data), "file-activated");
186     }
187 root 1.8
188 root 1.13 gtk_widget_unref (data);
189    
190 root 1.4 return FALSE;
191     }
192    
193 root 1.13 static gboolean map_cb (GtkWidget *widget, gpointer user_data)
194 root 1.1 {
195 root 1.5 gchar *argv[10];
196 root 1.4 gboolean save = 0;
197 root 1.5 char xid [40];
198 root 1.1
199     argv [0] = helper;
200 root 1.3
201     switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (widget)))
202     {
203 root 1.4 case GTK_FILE_CHOOSER_ACTION_SAVE: argv [1] = "save "; save = 1;break;
204     case GTK_FILE_CHOOSER_ACTION_OPEN: argv [1] = "load "; break;
205     case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER: argv [1] = "mkdir "; save = 1; break;
206 root 1.3 case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER: argv [1] = "cd "; break;
207 root 1.13 default: argv [1] = "<unknown action> "; break;
208 root 1.3 }
209    
210 root 1.5 GdkWindow *w = gtk_widget_get_parent_window (GTK_WIDGET (widget));
211    
212     snprintf (xid, 80, "%lu", (unsigned long)(w ? gdk_x11_drawable_get_xid (w) : 0));
213     argv [2] = xid;
214     argv [3] = 0;
215 root 1.1
216 root 1.4 mkdir ("/tmp/gtkbfc", 0777);
217     close (open ("/tmp/gtkbfc/empty", O_WRONLY|O_CREAT|O_TRUNC, 0666));
218    
219 root 1.10 ((void (*)(void *, const char *)) dlsym (RTLD_NEXT, "gtk_file_chooser_set_filename"))(GTK_FILE_CHOOSER (widget), "/tmp/gtkbfc/empty");
220 root 1.4
221     gint stdout_fd = -1;
222    
223 root 1.13 gtk_widget_ref (widget); disable_cb (widget);
224    
225 root 1.4 if (g_spawn_async_with_pipes (0, argv, 0, 0, 0, 0, 0, 0, &stdout_fd, 0, 0))
226 root 1.1 {
227 root 1.4 GIOChannel *channel = g_io_channel_unix_new (stdout_fd);
228 root 1.13
229     gtk_widget_ref (widget); g_io_add_watch (channel, G_IO_IN | G_IO_ERR | G_IO_HUP, read_result, widget);
230    
231     // disable again in an idle handler, to get around race conditions
232     gtk_widget_ref (widget); g_idle_add (disable_cb, widget);
233 root 1.1 }
234     }
235    
236     static GObject *new_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties)
237     {
238     GObject *ob = old_constructor (type, n_construct_properties, construct_properties);
239 root 1.13 g_signal_connect_after (ob, "map", G_CALLBACK (map_cb), 0);
240 root 1.1 return ob;
241     }
242    
243     __attribute__ ((constructor))
244     static void init ()
245     {
246 root 1.3 g_type_init ();
247 root 1.1
248 root 1.3 GType type = GTK_TYPE_FILE_CHOOSER_WIDGET;
249     GObjectClass *klass = g_type_class_ref (type);
250 root 1.1
251 root 1.3 old_constructor = klass->constructor;
252     klass->constructor = new_constructor;
253 root 1.1 }
254