r496: Many internal changes to the Options system.
[rox-filer.git] / ROX-Filer / src / gtksavebox.c
blob9abbf981551a52161d28360ae6b4d3214b0f82c2
1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #include "config.h"
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
33 #include "gdk/gdkkeysyms.h"
35 #include "gtksavebox.h"
36 #include "gtk/gtkwidget.h"
37 #include "gtk/gtkalignment.h"
38 #include "gtk/gtkdnd.h"
39 #include "gtk/gtkbutton.h"
40 #include "gtk/gtksignal.h"
41 #include "gtk/gtkpixmap.h"
42 #include "gtk/gtkhbox.h"
43 #include "gtk/gtkeventbox.h"
44 #include "gtk/gtkentry.h"
45 #include "gtk/gtkhseparator.h"
46 #include "gtk/gtkvbox.h"
47 #include "gtk/gtkdialog.h"
48 #include "gtk/gtklabel.h"
50 #include "support.h"
52 /* Signals:
54 * gint save_to_file (GtkSavebox *savebox, guchar *pathname)
55 * Save the data to disk using this pathname. Return GTK_XDS_SAVED
56 * on success, or GTK_XDS_SAVE_ERROR on failure (and report the error
57 * to the user somehow). DO NOT mark the data unmodified or change
58 * the pathname for the file - this might be a scrap file transfer.
60 * void saved_to_uri (GtkSavebox *savebox, guchar *uri)
61 * The data is saved and safe. Mark the file as unmodified and update
62 * the pathname/uri for the file to the one given.
64 * void save_done (GtkSavebox *savebox)
65 * The save operation is over. Close the savebox. This signal is sent
66 * regardless of whether the data is now 'safe', but not if no data
67 * has been sent.
70 enum
72 SAVE_TO_FILE,
73 SAVED_TO_URI,
74 SAVE_DONE,
76 LAST_SIGNAL
79 static guint savebox_signals[LAST_SIGNAL] = { 0 };
81 static GtkWidgetClass *parent_class = NULL;
83 /* Longest possible XdndDirectSave0 property value */
84 #define XDS_MAXURILEN 4096
86 static GdkAtom XdndDirectSave;
87 static GdkAtom text_plain;
88 static GdkAtom xa_string;
90 static void gtk_savebox_class_init (GtkSaveboxClass *klass);
91 static void gtk_savebox_init (GtkSavebox *savebox);
92 static void button_press_over_icon (GtkWidget *drag_box,
93 GdkEventButton *event,
94 GtkSavebox *savebox);
95 static void drag_data_get (GtkWidget *widget,
96 GdkDragContext *context,
97 GtkSelectionData *selection_data,
98 guint info,
99 guint32 time);
100 static guchar *read_xds_property (GdkDragContext *context,
101 gboolean delete);
102 static void write_xds_property (GdkDragContext *context,
103 guchar *value);
104 static void drag_end (GtkWidget *widget,
105 GdkDragContext *context);
106 static void do_save (GtkWidget *widget,
107 GtkSavebox *savebox);
108 static gint delete_event (GtkWidget *widget,
109 GdkEventAny *event);
110 static gint key_press_event (GtkWidget *widget,
111 GdkEventKey *event);
112 static void cancel_clicked (GtkWidget *widget,
113 GtkSavebox *savebox);
116 GtkType
117 gtk_savebox_get_type (void)
119 static GtkType savebox_type = 0;
121 if (!savebox_type)
123 static const GtkTypeInfo savebox_info =
125 "GtkSavebox",
126 sizeof (GtkSavebox),
127 sizeof (GtkSaveboxClass),
128 (GtkClassInitFunc) gtk_savebox_class_init,
129 (GtkObjectInitFunc) gtk_savebox_init,
130 /* reserved_1 */ NULL,
131 /* reserved_2 */ NULL,
132 (GtkClassInitFunc) NULL,
135 savebox_type = gtk_type_unique (GTK_TYPE_WINDOW, &savebox_info);
138 return savebox_type;
141 static void
142 gtk_savebox_class_init (GtkSaveboxClass *class)
144 GtkObjectClass *object_class = (GtkObjectClass *) class;
145 GtkWidgetClass *widget_class = (GtkWidgetClass *) class;
147 XdndDirectSave = gdk_atom_intern ("XdndDirectSave0", FALSE);
148 text_plain = gdk_atom_intern ("text/plain", FALSE);
149 xa_string = gdk_atom_intern ("STRING", FALSE);
151 parent_class = gtk_type_class(gtk_window_get_type());
153 class->save_to_file = NULL;
154 widget_class->delete_event = delete_event;
155 widget_class->key_press_event = key_press_event;
157 savebox_signals[SAVE_TO_FILE] = gtk_signal_new ("save_to_file",
158 GTK_RUN_LAST,
159 object_class->type,
160 GTK_SIGNAL_OFFSET (GtkSaveboxClass,
161 save_to_file),
162 gtk_marshal_INT__POINTER,
163 GTK_TYPE_INT, 1,
164 GTK_TYPE_POINTER);
166 savebox_signals[SAVED_TO_URI] = gtk_signal_new ("saved_to_uri",
167 GTK_RUN_LAST,
168 object_class->type,
169 GTK_SIGNAL_OFFSET (GtkSaveboxClass,
170 saved_to_uri),
171 gtk_marshal_NONE__POINTER,
172 GTK_TYPE_NONE, 1,
173 GTK_TYPE_POINTER);
175 savebox_signals[SAVE_DONE] = gtk_signal_new ("save_done",
176 GTK_RUN_LAST,
177 object_class->type,
178 GTK_SIGNAL_OFFSET (GtkSaveboxClass,
179 save_done),
180 gtk_marshal_NONE__NONE,
181 GTK_TYPE_NONE, 0);
183 gtk_object_class_add_signals (object_class, savebox_signals, LAST_SIGNAL);
186 static void
187 gtk_savebox_init (GtkSavebox *savebox)
189 GtkWidget *hbox, *button, *alignment;
190 GtkTargetEntry targets[] = { {"XdndDirectSave0", 0, GTK_TARGET_XDS} };
192 savebox->targets = gtk_target_list_new (targets,
193 sizeof (targets) / sizeof (*targets));
194 savebox->icon = NULL;
196 GTK_WINDOW (savebox)->type = GTK_WINDOW_DIALOG;
197 gtk_window_set_title (GTK_WINDOW (savebox), _("Save As:"));
198 gtk_window_set_position (GTK_WINDOW (savebox), GTK_WIN_POS_MOUSE);
199 gtk_container_set_border_width (GTK_CONTAINER (savebox), 4);
201 savebox->vbox = gtk_vbox_new (FALSE, 0);
202 gtk_container_add (GTK_CONTAINER (savebox), savebox->vbox);
204 alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
205 gtk_box_pack_start (GTK_BOX (savebox->vbox), alignment, TRUE, TRUE, 0);
207 savebox->drag_box = gtk_event_box_new ();
208 gtk_container_set_border_width (GTK_CONTAINER (savebox->drag_box), 4);
209 gtk_widget_add_events (savebox->drag_box, GDK_BUTTON_PRESS_MASK);
210 gtk_signal_connect (GTK_OBJECT (savebox->drag_box), "button_press_event",
211 GTK_SIGNAL_FUNC (button_press_over_icon), savebox);
212 gtk_signal_connect (GTK_OBJECT (savebox), "drag_end",
213 GTK_SIGNAL_FUNC (drag_end), savebox);
214 gtk_signal_connect (GTK_OBJECT (savebox), "drag_data_get",
215 GTK_SIGNAL_FUNC (drag_data_get), savebox);
216 gtk_container_add (GTK_CONTAINER (alignment), savebox->drag_box);
218 savebox->entry = gtk_entry_new ();
219 gtk_signal_connect (GTK_OBJECT (savebox->entry), "activate",
220 GTK_SIGNAL_FUNC (do_save), savebox);
221 gtk_box_pack_start (GTK_BOX (savebox->vbox), savebox->entry, FALSE, TRUE, 4);
223 hbox = gtk_hbox_new (TRUE, 0);
224 gtk_box_pack_start (GTK_BOX (savebox->vbox), hbox, FALSE, TRUE, 0);
226 button = gtk_button_new_with_label (_("OK"));
227 gtk_signal_connect (GTK_OBJECT (button), "clicked",
228 GTK_SIGNAL_FUNC (do_save), savebox);
229 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
230 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
231 gtk_window_set_default (GTK_WINDOW (savebox), button);
233 button = gtk_button_new_with_label (_("Cancel"));
234 gtk_signal_connect (GTK_OBJECT (button), "clicked",
235 GTK_SIGNAL_FUNC (cancel_clicked), savebox);
236 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
237 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
239 gtk_widget_show_all (savebox->vbox);
241 gtk_widget_grab_focus (savebox->entry);
244 GtkWidget*
245 gtk_savebox_new (void)
247 GtkSavebox *savebox;
249 savebox = gtk_type_new (gtk_savebox_get_type ());
251 return GTK_WIDGET (savebox);
254 void
255 gtk_savebox_set_icon (GtkSavebox *savebox, GdkPixmap *pixmap, GdkPixmap *mask)
257 g_return_if_fail (savebox != NULL);
258 g_return_if_fail (GTK_IS_SAVEBOX (savebox));
259 g_return_if_fail (pixmap != NULL);
261 if (savebox->icon)
262 gtk_pixmap_set (GTK_PIXMAP (savebox->icon), pixmap, mask);
263 else
265 savebox->icon = gtk_pixmap_new (pixmap, mask);
266 gtk_container_add (GTK_CONTAINER (savebox->drag_box), savebox->icon);
267 gtk_widget_show(savebox->icon);
271 void
272 gtk_savebox_set_pathname (GtkSavebox *savebox, gchar *pathname)
274 gchar *slash;
275 gint leaf;
277 g_return_if_fail (savebox != NULL);
278 g_return_if_fail (GTK_IS_SAVEBOX (savebox));
279 g_return_if_fail (pathname != NULL);
281 gtk_entry_set_text (GTK_ENTRY (savebox->entry), pathname);
283 slash = strrchr (pathname, '/');
285 leaf = slash ? slash - pathname + 1 : 0;
287 /* Gtk+ doesn't seem to scroll the entry properly without this... */
288 gtk_widget_realize (savebox->entry);
289 gtk_entry_set_position (GTK_ENTRY (savebox->entry), -1);
291 gtk_entry_select_region (GTK_ENTRY (savebox->entry), leaf, -1);
294 static void
295 button_press_over_icon (GtkWidget *drag_box, GdkEventButton *event,
296 GtkSavebox *savebox)
298 GdkDragContext *context;
299 GdkPixmap *pixmap, *mask;
300 guchar *uri = NULL, *leafname;
302 g_return_if_fail (savebox != NULL);
303 g_return_if_fail (GTK_IS_SAVEBOX (savebox));
304 g_return_if_fail (event != NULL);
305 g_return_if_fail (savebox->icon != NULL);
307 savebox->using_xds = FALSE;
308 savebox->data_sent = FALSE;
309 context = gtk_drag_begin (GTK_WIDGET (savebox),
310 savebox->targets, GDK_ACTION_COPY,
311 event->button, (GdkEvent *) event);
313 uri = gtk_entry_get_text (GTK_ENTRY (savebox->entry));
314 if (uri && *uri)
316 leafname = strrchr (uri, '/');
317 if (leafname)
318 leafname++;
319 else
320 leafname = uri;
322 else
323 leafname = _("Unnamed");
325 write_xds_property (context, leafname);
327 gtk_pixmap_get (GTK_PIXMAP (savebox->icon), &pixmap, &mask);
328 gtk_drag_set_icon_pixmap (context,
329 gtk_widget_get_colormap (savebox->icon),
330 pixmap,
331 mask,
332 event->x, event->y);
336 static void
337 drag_data_get (GtkWidget *widget,
338 GdkDragContext *context,
339 GtkSelectionData *selection_data,
340 guint info,
341 guint32 time)
343 GtkSavebox *savebox;
344 guchar to_send = 'E';
345 guchar *uri;
346 guchar *pathname;
348 g_return_if_fail (widget != NULL);
349 g_return_if_fail (GTK_IS_SAVEBOX (widget));
350 g_return_if_fail (context != NULL);
351 g_return_if_fail (selection_data != NULL);
353 savebox = GTK_SAVEBOX (widget);
355 /* We're only concerned with the XDS protocol. Responding to other requests
356 * (including application/octet-stream) is the job of the application.
358 if (info != GTK_TARGET_XDS)
360 /* Assume that the data will be/has been sent */
361 savebox->data_sent = TRUE;
362 return;
365 uri = read_xds_property (context, FALSE);
367 if (uri)
369 gint result = GTK_XDS_NO_HANDLER;
371 pathname = get_local_path (uri);
372 if (!pathname)
373 to_send = 'F'; /* Not on the local machine */
374 else
376 gtk_signal_emit (GTK_OBJECT (widget),
377 savebox_signals[SAVE_TO_FILE],
378 pathname, &result);
380 if (result == GTK_XDS_SAVED)
382 savebox->data_sent = TRUE;
383 to_send = 'S';
385 else if (result != GTK_XDS_SAVE_ERROR)
386 g_warning ("No handler for saving to a file.\n");
388 g_free (uri);
391 else
393 g_warning (_("Remote application wants to use Direct Save, but I can't "
394 "read the XdndDirectSave0 (type text/plain) property.\n"));
397 if (to_send != 'E')
398 savebox->using_xds = TRUE;
399 gtk_selection_data_set (selection_data, xa_string, 8, &to_send, 1);
402 static guchar *
403 read_xds_property (GdkDragContext *context, gboolean delete)
405 guchar *prop_text;
406 guint length;
407 guchar *retval = NULL;
409 g_return_val_if_fail (context != NULL, NULL);
411 if (gdk_property_get (context->source_window, XdndDirectSave, text_plain,
412 0, XDS_MAXURILEN, delete,
413 NULL, NULL, &length, &prop_text)
414 && prop_text)
416 /* Terminate the string */
417 retval = g_realloc (prop_text, length + 1);
418 retval[length] = '\0';
421 return retval;
424 static void
425 write_xds_property (GdkDragContext *context, guchar *value)
427 if (value)
429 gdk_property_change (context->source_window, XdndDirectSave,
430 text_plain, 8, GDK_PROP_MODE_REPLACE,
431 value, strlen (value));
433 else
434 gdk_property_delete (context->source_window, XdndDirectSave);
437 static void drag_end (GtkWidget *widget, GdkDragContext *context)
439 g_return_if_fail (widget != NULL);
440 g_return_if_fail (GTK_IS_SAVEBOX (widget));
441 g_return_if_fail (context != NULL);
443 if (GTK_SAVEBOX (widget)->using_xds)
445 guchar *uri;
446 uri = read_xds_property (context, TRUE);
448 if (uri)
450 guchar *path;
452 path = get_local_path (uri);
454 gtk_signal_emit (GTK_OBJECT (widget),
455 savebox_signals[SAVED_TO_URI],
456 path ? path : uri);
457 g_free(uri);
460 else
461 write_xds_property (context, NULL);
463 if (GTK_SAVEBOX (widget)->data_sent)
464 gtk_signal_emit (GTK_OBJECT (widget), savebox_signals[SAVE_DONE]);
467 static void cancel_clicked (GtkWidget *widget, GtkSavebox *savebox)
469 gtk_signal_emit (GTK_OBJECT (savebox), savebox_signals[SAVE_DONE]);
472 /* User has clicked Save or pressed Return... */
473 static void do_save (GtkWidget *widget, GtkSavebox *savebox)
475 gint result = GTK_XDS_NO_HANDLER;
476 guchar *pathname, *uri;
478 g_return_if_fail (savebox != NULL);
479 g_return_if_fail (GTK_IS_SAVEBOX (savebox));
481 uri = gtk_entry_get_text (GTK_ENTRY (savebox->entry));
482 pathname = get_local_path (uri);
484 if (!pathname)
486 GtkWidget *dialog, *label, *button;
488 dialog = gtk_dialog_new ();
489 GTK_WINDOW (dialog)->type = GTK_WINDOW_DIALOG;
491 label = gtk_label_new (_("Drag the icon to a directory viewer\n"
492 "(or enter a full pathname)"));
493 gtk_misc_set_padding (GTK_MISC (label), 8, 32);
495 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
496 label, TRUE, TRUE, 4);
498 button = gtk_button_new_with_label (_("OK"));
499 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
500 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
501 gtk_widget_destroy, GTK_OBJECT (dialog));
502 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
503 button, TRUE, TRUE, 32);
504 gtk_window_set_default (GTK_WINDOW (dialog), button);
506 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
508 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
510 gtk_widget_show_all (dialog);
512 return;
515 g_return_if_fail (pathname != NULL);
517 gtk_signal_emit (GTK_OBJECT (savebox), savebox_signals[SAVE_TO_FILE],
518 pathname, &result);
520 if (result == GTK_XDS_SAVED)
522 gtk_signal_emit (GTK_OBJECT (savebox), savebox_signals[SAVED_TO_URI],
523 pathname);
524 gtk_signal_emit (GTK_OBJECT (savebox), savebox_signals[SAVE_DONE]);
526 else if (result == GTK_XDS_NO_HANDLER)
527 g_warning ("No handler for saving to a file.\n");
530 static gint
531 delete_event(GtkWidget *widget, GdkEventAny *event)
533 g_return_val_if_fail (widget != NULL, FALSE);
535 gtk_signal_emit (GTK_OBJECT (widget), savebox_signals[SAVE_DONE]);
537 return TRUE;
540 static gint
541 key_press_event(GtkWidget *widget, GdkEventKey *event)
543 gint (*parent_handler)(GtkWidget *widget, GdkEventKey *event);
545 g_return_val_if_fail (widget != NULL, FALSE);
547 if (event->keyval == GDK_Escape)
549 gtk_signal_emit (GTK_OBJECT (widget), savebox_signals[SAVE_DONE]);
550 return TRUE;
553 parent_handler = GTK_WIDGET_CLASS (parent_class)->key_press_event;
555 if (parent_handler)
556 return parent_handler (widget, event);
558 return FALSE;