r716: More Gtk+-2.0 changes.
[rox-filer.git] / ROX-Filer / src / gtksavebox.c
blobd63ce258ae6dd0b59ca8380826db09e8dded2c37
1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1991-the ROX-Filer team.
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 #ifndef GTK_CLASS_TYPE
142 # define GTK_CLASS_TYPE(c) (c->type)
143 #endif
145 static void
146 gtk_savebox_class_init (GtkSaveboxClass *class)
148 GtkObjectClass *object_class = (GtkObjectClass *) class;
149 GtkWidgetClass *widget_class = (GtkWidgetClass *) class;
151 XdndDirectSave = gdk_atom_intern ("XdndDirectSave0", FALSE);
152 text_plain = gdk_atom_intern ("text/plain", FALSE);
153 xa_string = gdk_atom_intern ("STRING", FALSE);
155 parent_class = gtk_type_class(gtk_window_get_type());
157 class->save_to_file = NULL;
158 widget_class->delete_event = delete_event;
159 widget_class->key_press_event = key_press_event;
161 savebox_signals[SAVE_TO_FILE] = gtk_signal_new ("save_to_file",
162 GTK_RUN_LAST,
163 GTK_CLASS_TYPE(object_class),
164 GTK_SIGNAL_OFFSET (GtkSaveboxClass,
165 save_to_file),
166 gtk_marshal_INT__POINTER,
167 GTK_TYPE_INT, 1,
168 GTK_TYPE_POINTER);
170 savebox_signals[SAVED_TO_URI] = gtk_signal_new ("saved_to_uri",
171 GTK_RUN_LAST,
172 GTK_CLASS_TYPE(object_class),
173 GTK_SIGNAL_OFFSET (GtkSaveboxClass,
174 saved_to_uri),
175 gtk_marshal_NONE__POINTER,
176 GTK_TYPE_NONE, 1,
177 GTK_TYPE_POINTER);
179 savebox_signals[SAVE_DONE] = gtk_signal_new ("save_done",
180 GTK_RUN_LAST,
181 GTK_CLASS_TYPE(object_class),
182 GTK_SIGNAL_OFFSET (GtkSaveboxClass,
183 save_done),
184 gtk_marshal_NONE__NONE,
185 GTK_TYPE_NONE, 0);
187 #ifndef GTK2
188 gtk_object_class_add_signals (object_class, savebox_signals, LAST_SIGNAL);
189 #endif
192 static void
193 gtk_savebox_init (GtkSavebox *savebox)
195 GtkWidget *hbox, *button, *alignment;
196 GtkTargetEntry targets[] = { {"XdndDirectSave0", 0, GTK_TARGET_XDS} };
198 savebox->targets = gtk_target_list_new (targets,
199 sizeof (targets) / sizeof (*targets));
200 savebox->icon = NULL;
202 GTK_WINDOW (savebox)->type = GTK_WINDOW_DIALOG;
203 gtk_window_set_title (GTK_WINDOW (savebox), _("Save As:"));
204 gtk_window_set_position (GTK_WINDOW (savebox), GTK_WIN_POS_MOUSE);
205 gtk_container_set_border_width (GTK_CONTAINER (savebox), 4);
207 savebox->vbox = gtk_vbox_new (FALSE, 0);
208 gtk_container_add (GTK_CONTAINER (savebox), savebox->vbox);
210 alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
211 gtk_box_pack_start (GTK_BOX (savebox->vbox), alignment, TRUE, TRUE, 0);
213 savebox->drag_box = gtk_event_box_new ();
214 gtk_container_set_border_width (GTK_CONTAINER (savebox->drag_box), 4);
215 gtk_widget_add_events (savebox->drag_box, GDK_BUTTON_PRESS_MASK);
216 gtk_signal_connect (GTK_OBJECT (savebox->drag_box), "button_press_event",
217 GTK_SIGNAL_FUNC (button_press_over_icon), savebox);
218 gtk_signal_connect (GTK_OBJECT (savebox), "drag_end",
219 GTK_SIGNAL_FUNC (drag_end), savebox);
220 gtk_signal_connect (GTK_OBJECT (savebox), "drag_data_get",
221 GTK_SIGNAL_FUNC (drag_data_get), savebox);
222 gtk_container_add (GTK_CONTAINER (alignment), savebox->drag_box);
224 savebox->entry = gtk_entry_new ();
225 gtk_signal_connect (GTK_OBJECT (savebox->entry), "activate",
226 GTK_SIGNAL_FUNC (do_save), savebox);
227 gtk_box_pack_start (GTK_BOX (savebox->vbox), savebox->entry, FALSE, TRUE, 4);
229 hbox = gtk_hbox_new (TRUE, 0);
230 gtk_box_pack_end (GTK_BOX (savebox->vbox), hbox, FALSE, TRUE, 0);
232 button = gtk_button_new_with_label (_("OK"));
233 gtk_signal_connect (GTK_OBJECT (button), "clicked",
234 GTK_SIGNAL_FUNC (do_save), savebox);
235 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
236 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
237 gtk_window_set_default (GTK_WINDOW (savebox), button);
239 button = gtk_button_new_with_label (_("Cancel"));
240 gtk_signal_connect (GTK_OBJECT (button), "clicked",
241 GTK_SIGNAL_FUNC (cancel_clicked), savebox);
242 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
243 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
245 gtk_widget_show_all (savebox->vbox);
247 gtk_widget_grab_focus (savebox->entry);
250 GtkWidget*
251 gtk_savebox_new (void)
253 GtkSavebox *savebox;
255 savebox = gtk_type_new (gtk_savebox_get_type ());
257 return GTK_WIDGET (savebox);
260 void
261 gtk_savebox_set_icon (GtkSavebox *savebox, GdkPixmap *pixmap, GdkPixmap *mask)
263 g_return_if_fail (savebox != NULL);
264 g_return_if_fail (GTK_IS_SAVEBOX (savebox));
265 g_return_if_fail (pixmap != NULL);
267 if (savebox->icon)
268 gtk_pixmap_set (GTK_PIXMAP (savebox->icon), pixmap, mask);
269 else
271 savebox->icon = gtk_pixmap_new (pixmap, mask);
272 gtk_container_add (GTK_CONTAINER (savebox->drag_box), savebox->icon);
273 gtk_widget_show(savebox->icon);
277 void
278 gtk_savebox_set_pathname (GtkSavebox *savebox, gchar *pathname)
280 gchar *slash;
281 gint leaf;
283 g_return_if_fail (savebox != NULL);
284 g_return_if_fail (GTK_IS_SAVEBOX (savebox));
285 g_return_if_fail (pathname != NULL);
287 gtk_entry_set_text (GTK_ENTRY (savebox->entry), pathname);
289 slash = strrchr (pathname, '/');
291 leaf = slash ? slash - pathname + 1 : 0;
293 /* Gtk+ doesn't seem to scroll the entry properly without this... */
294 gtk_widget_realize (savebox->entry);
295 gtk_entry_set_position (GTK_ENTRY (savebox->entry), -1);
297 gtk_entry_select_region (GTK_ENTRY (savebox->entry), leaf, -1);
300 static void
301 button_press_over_icon (GtkWidget *drag_box, GdkEventButton *event,
302 GtkSavebox *savebox)
304 GdkDragContext *context;
305 GdkPixmap *pixmap, *mask;
306 guchar *uri = NULL, *leafname;
308 g_return_if_fail (savebox != NULL);
309 g_return_if_fail (GTK_IS_SAVEBOX (savebox));
310 g_return_if_fail (event != NULL);
311 g_return_if_fail (savebox->icon != NULL);
313 savebox->using_xds = FALSE;
314 savebox->data_sent = FALSE;
315 context = gtk_drag_begin (GTK_WIDGET (savebox),
316 savebox->targets, GDK_ACTION_COPY,
317 event->button, (GdkEvent *) event);
319 uri = gtk_entry_get_text (GTK_ENTRY (savebox->entry));
320 if (uri && *uri)
322 leafname = strrchr (uri, '/');
323 if (leafname)
324 leafname++;
325 else
326 leafname = uri;
328 else
329 leafname = _("Unnamed");
331 write_xds_property (context, leafname);
333 gtk_pixmap_get (GTK_PIXMAP (savebox->icon), &pixmap, &mask);
334 gtk_drag_set_icon_pixmap (context,
335 gtk_widget_get_colormap (savebox->icon),
336 pixmap,
337 mask,
338 event->x, event->y);
342 static void
343 drag_data_get (GtkWidget *widget,
344 GdkDragContext *context,
345 GtkSelectionData *selection_data,
346 guint info,
347 guint32 time)
349 GtkSavebox *savebox;
350 guchar to_send = 'E';
351 guchar *uri;
352 guchar *pathname;
354 g_return_if_fail (widget != NULL);
355 g_return_if_fail (GTK_IS_SAVEBOX (widget));
356 g_return_if_fail (context != NULL);
357 g_return_if_fail (selection_data != NULL);
359 savebox = GTK_SAVEBOX (widget);
361 /* We're only concerned with the XDS protocol. Responding to other requests
362 * (including application/octet-stream) is the job of the application.
364 if (info != GTK_TARGET_XDS)
366 /* Assume that the data will be/has been sent */
367 savebox->data_sent = TRUE;
368 return;
371 uri = read_xds_property (context, FALSE);
373 if (uri)
375 gint result = GTK_XDS_NO_HANDLER;
377 pathname = get_local_path (uri);
378 if (!pathname)
379 to_send = 'F'; /* Not on the local machine */
380 else
382 gtk_signal_emit (GTK_OBJECT (widget),
383 savebox_signals[SAVE_TO_FILE],
384 pathname, &result);
386 if (result == GTK_XDS_SAVED)
388 savebox->data_sent = TRUE;
389 to_send = 'S';
391 else if (result != GTK_XDS_SAVE_ERROR)
392 g_warning ("No handler for saving to a file.\n");
394 g_free (uri);
397 else
399 g_warning (_("Remote application wants to use Direct Save, but I can't "
400 "read the XdndDirectSave0 (type text/plain) property.\n"));
403 if (to_send != 'E')
404 savebox->using_xds = TRUE;
405 gtk_selection_data_set (selection_data, xa_string, 8, &to_send, 1);
408 static guchar *
409 read_xds_property (GdkDragContext *context, gboolean delete)
411 guchar *prop_text;
412 guint length;
413 guchar *retval = NULL;
415 g_return_val_if_fail (context != NULL, NULL);
417 if (gdk_property_get (context->source_window, XdndDirectSave, text_plain,
418 0, XDS_MAXURILEN, delete,
419 NULL, NULL, &length, &prop_text)
420 && prop_text)
422 /* Terminate the string */
423 retval = g_realloc (prop_text, length + 1);
424 retval[length] = '\0';
427 return retval;
430 static void
431 write_xds_property (GdkDragContext *context, guchar *value)
433 if (value)
435 gdk_property_change (context->source_window, XdndDirectSave,
436 text_plain, 8, GDK_PROP_MODE_REPLACE,
437 value, strlen (value));
439 else
440 gdk_property_delete (context->source_window, XdndDirectSave);
443 static void drag_end (GtkWidget *widget, GdkDragContext *context)
445 g_return_if_fail (widget != NULL);
446 g_return_if_fail (GTK_IS_SAVEBOX (widget));
447 g_return_if_fail (context != NULL);
449 if (GTK_SAVEBOX (widget)->using_xds)
451 guchar *uri;
452 uri = read_xds_property (context, TRUE);
454 if (uri)
456 guchar *path;
458 path = get_local_path (uri);
460 gtk_signal_emit (GTK_OBJECT (widget),
461 savebox_signals[SAVED_TO_URI],
462 path ? path : uri);
463 g_free(uri);
466 else
467 write_xds_property (context, NULL);
469 if (GTK_SAVEBOX (widget)->data_sent)
470 gtk_signal_emit (GTK_OBJECT (widget), savebox_signals[SAVE_DONE]);
473 static void cancel_clicked (GtkWidget *widget, GtkSavebox *savebox)
475 gtk_signal_emit (GTK_OBJECT (savebox), savebox_signals[SAVE_DONE]);
478 /* User has clicked Save or pressed Return... */
479 static void do_save (GtkWidget *widget, GtkSavebox *savebox)
481 gint result = GTK_XDS_NO_HANDLER;
482 guchar *pathname, *uri;
484 g_return_if_fail (savebox != NULL);
485 g_return_if_fail (GTK_IS_SAVEBOX (savebox));
487 uri = gtk_entry_get_text (GTK_ENTRY (savebox->entry));
488 pathname = get_local_path (uri);
490 if (!pathname)
492 GtkWidget *dialog, *label, *button;
494 dialog = gtk_dialog_new ();
495 GTK_WINDOW (dialog)->type = GTK_WINDOW_DIALOG;
497 label = gtk_label_new (_("Drag the icon to a directory viewer\n"
498 "(or enter a full pathname)"));
499 gtk_misc_set_padding (GTK_MISC (label), 8, 32);
501 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
502 label, TRUE, TRUE, 4);
504 button = gtk_button_new_with_label (_("OK"));
505 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
506 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
507 GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT (dialog));
508 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
509 button, TRUE, TRUE, 32);
510 gtk_window_set_default (GTK_WINDOW (dialog), button);
512 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
514 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
516 gtk_widget_show_all (dialog);
518 return;
521 g_return_if_fail (pathname != NULL);
523 gtk_signal_emit (GTK_OBJECT (savebox), savebox_signals[SAVE_TO_FILE],
524 pathname, &result);
526 if (result == GTK_XDS_SAVED)
528 gtk_signal_emit (GTK_OBJECT (savebox), savebox_signals[SAVED_TO_URI],
529 pathname);
530 gtk_signal_emit (GTK_OBJECT (savebox), savebox_signals[SAVE_DONE]);
532 else if (result == GTK_XDS_NO_HANDLER)
533 g_warning ("No handler for saving to a file.\n");
536 static gint
537 delete_event(GtkWidget *widget, GdkEventAny *event)
539 g_return_val_if_fail (widget != NULL, FALSE);
541 gtk_signal_emit (GTK_OBJECT (widget), savebox_signals[SAVE_DONE]);
543 return TRUE;
546 static gint
547 key_press_event(GtkWidget *widget, GdkEventKey *event)
549 gint (*parent_handler)(GtkWidget *widget, GdkEventKey *event);
551 g_return_val_if_fail (widget != NULL, FALSE);
553 if (event->keyval == GDK_Escape)
555 gtk_signal_emit (GTK_OBJECT (widget), savebox_signals[SAVE_DONE]);
556 return TRUE;
559 parent_handler = GTK_WIDGET_CLASS (parent_class)->key_press_event;
561 if (parent_handler)
562 return parent_handler (widget, event);
564 return FALSE;