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/.
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"
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
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
,
95 static void drag_data_get (GtkWidget
*widget
,
96 GdkDragContext
*context
,
97 GtkSelectionData
*selection_data
,
100 static guchar
*read_xds_property (GdkDragContext
*context
,
102 static void write_xds_property (GdkDragContext
*context
,
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
,
110 static gint
key_press_event (GtkWidget
*widget
,
112 static void cancel_clicked (GtkWidget
*widget
,
113 GtkSavebox
*savebox
);
117 gtk_savebox_get_type (void)
119 static GtkType savebox_type
= 0;
123 static const GtkTypeInfo savebox_info
=
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
);
141 #ifndef GTK_CLASS_TYPE
142 # define GTK_CLASS_TYPE(c) (c->type)
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",
163 GTK_CLASS_TYPE(object_class
),
164 GTK_SIGNAL_OFFSET (GtkSaveboxClass
,
166 gtk_marshal_INT__POINTER
,
170 savebox_signals
[SAVED_TO_URI
] = gtk_signal_new ("saved_to_uri",
172 GTK_CLASS_TYPE(object_class
),
173 GTK_SIGNAL_OFFSET (GtkSaveboxClass
,
175 gtk_marshal_NONE__POINTER
,
179 savebox_signals
[SAVE_DONE
] = gtk_signal_new ("save_done",
181 GTK_CLASS_TYPE(object_class
),
182 GTK_SIGNAL_OFFSET (GtkSaveboxClass
,
184 gtk_marshal_NONE__NONE
,
188 gtk_object_class_add_signals (object_class
, savebox_signals
, LAST_SIGNAL
);
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
);
251 gtk_savebox_new (void)
255 savebox
= gtk_type_new (gtk_savebox_get_type ());
257 return GTK_WIDGET (savebox
);
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
);
268 gtk_pixmap_set (GTK_PIXMAP (savebox
->icon
), pixmap
, mask
);
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
);
278 gtk_savebox_set_pathname (GtkSavebox
*savebox
, gchar
*pathname
)
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);
301 button_press_over_icon (GtkWidget
*drag_box
, GdkEventButton
*event
,
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
));
322 leafname
= strrchr (uri
, '/');
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
),
343 drag_data_get (GtkWidget
*widget
,
344 GdkDragContext
*context
,
345 GtkSelectionData
*selection_data
,
350 guchar to_send
= 'E';
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
;
371 uri
= read_xds_property (context
, FALSE
);
375 gint result
= GTK_XDS_NO_HANDLER
;
377 pathname
= get_local_path (uri
);
379 to_send
= 'F'; /* Not on the local machine */
382 gtk_signal_emit (GTK_OBJECT (widget
),
383 savebox_signals
[SAVE_TO_FILE
],
386 if (result
== GTK_XDS_SAVED
)
388 savebox
->data_sent
= TRUE
;
391 else if (result
!= GTK_XDS_SAVE_ERROR
)
392 g_warning ("No handler for saving to a file.\n");
399 g_warning (_("Remote application wants to use Direct Save, but I can't "
400 "read the XdndDirectSave0 (type text/plain) property.\n"));
404 savebox
->using_xds
= TRUE
;
405 gtk_selection_data_set (selection_data
, xa_string
, 8, &to_send
, 1);
409 read_xds_property (GdkDragContext
*context
, gboolean
delete)
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
)
422 /* Terminate the string */
423 retval
= g_realloc (prop_text
, length
+ 1);
424 retval
[length
] = '\0';
431 write_xds_property (GdkDragContext
*context
, guchar
*value
)
435 gdk_property_change (context
->source_window
, XdndDirectSave
,
436 text_plain
, 8, GDK_PROP_MODE_REPLACE
,
437 value
, strlen (value
));
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
)
452 uri
= read_xds_property (context
, TRUE
);
458 path
= get_local_path (uri
);
460 gtk_signal_emit (GTK_OBJECT (widget
),
461 savebox_signals
[SAVED_TO_URI
],
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
);
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
);
521 g_return_if_fail (pathname
!= NULL
);
523 gtk_signal_emit (GTK_OBJECT (savebox
), savebox_signals
[SAVE_TO_FILE
],
526 if (result
== GTK_XDS_SAVED
)
528 gtk_signal_emit (GTK_OBJECT (savebox
), savebox_signals
[SAVED_TO_URI
],
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");
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
]);
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
]);
559 parent_handler
= GTK_WIDGET_CLASS (parent_class
)->key_press_event
;
562 return parent_handler (widget
, event
);