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

# Content
1 /* this file is publiched under the gnu gpl license, version 3 or any later */
2
3 #define _GNU_SOURCE
4
5 #include <dlfcn.h>
6 #include <glib.h>
7 #include <gtk/gtk.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14
15 static char *helper = "/etc/gtkbfc-helper";
16
17 static GObject *(*old_constructor) (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties);
18
19 static gchar *last_path;
20
21 #if 0
22 # define DEBUG(stmt) stmt;
23 #else
24 # define DEBUG(stmt)
25 #endif
26
27 /////////////////////////////////////////////////////////////////////////////
28
29 gchar *gtk_file_chooser_get_filename (GtkFileChooser *chooser)
30 {
31 DEBUG ((printf ("gtk_file_chooser_get_filename<%s>\n", last_path)))
32 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 DEBUG ((printf ("gtk_file_chooser_get_current_folder\n")))
68 return g_strdup ("/tmp/gtkbfc");
69 }
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 to_uri (gchar *file)
86 {
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 gchar *gtk_file_chooser_get_uri (GtkFileChooser *chooser)
121 {
122 gchar *uri = to_uri(gtk_file_chooser_get_filename (chooser));
123 DEBUG ((printf ("gtk_file_chooser_get_uri<%s>\n", uri)));
124 return uri;
125 }
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 static gboolean disable_cb (gpointer data)
150 {
151 ((void (*)(void *, const char *)) dlsym (RTLD_NEXT, "gtk_file_chooser_set_filename"))(GTK_FILE_CHOOSER (data), "/tmp/gtkbfc/empty");
152
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 return FALSE;
159 }
160
161 static gboolean read_result (GIOChannel *source, GIOCondition condition, gpointer data)
162 {
163 if (last_path)
164 {
165 g_free (last_path);
166 last_path = 0;
167 }
168
169 g_io_channel_read_to_end (source, &last_path, 0, 0);
170 g_io_channel_unref (source);
171
172 GtkWidget *toplevel = gtk_widget_get_toplevel (data);
173 if (toplevel) gtk_widget_set_sensitive (toplevel, 1);
174
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
188 gtk_widget_unref (data);
189
190 return FALSE;
191 }
192
193 static gboolean map_cb (GtkWidget *widget, gpointer user_data)
194 {
195 gchar *argv[10];
196 gboolean save = 0;
197 char xid [40];
198
199 argv [0] = helper;
200
201 switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (widget)))
202 {
203 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 case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER: argv [1] = "cd "; break;
207 default: argv [1] = "<unknown action> "; break;
208 }
209
210 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
216 mkdir ("/tmp/gtkbfc", 0777);
217 close (open ("/tmp/gtkbfc/empty", O_WRONLY|O_CREAT|O_TRUNC, 0666));
218
219 ((void (*)(void *, const char *)) dlsym (RTLD_NEXT, "gtk_file_chooser_set_filename"))(GTK_FILE_CHOOSER (widget), "/tmp/gtkbfc/empty");
220
221 gint stdout_fd = -1;
222
223 gtk_widget_ref (widget); disable_cb (widget);
224
225 if (g_spawn_async_with_pipes (0, argv, 0, 0, 0, 0, 0, 0, &stdout_fd, 0, 0))
226 {
227 GIOChannel *channel = g_io_channel_unix_new (stdout_fd);
228
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 }
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 g_signal_connect_after (ob, "map", G_CALLBACK (map_cb), 0);
240 return ob;
241 }
242
243 __attribute__ ((constructor))
244 static void init ()
245 {
246 g_type_init ();
247
248 GType type = GTK_TYPE_FILE_CHOOSER_WIDGET;
249 GObjectClass *klass = g_type_class_ref (type);
250
251 old_constructor = klass->constructor;
252 klass->constructor = new_constructor;
253 }
254