r51: Delete now updates the filer windows as things disappear.
[rox-filer.git] / ROX-Filer / src / gui_support.c
blobb983e93c7cd9e3a2b5141e0112927db3fdebac12
1 /* vi: set cindent:
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * By Thomas Leonard, <tal197@ecs.soton.ac.uk>.
6 */
8 /* gui_support.c - general (GUI) support routines */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/param.h>
14 #include <stdarg.h>
15 #include <errno.h>
17 #include <glib.h>
18 #include <X11/Xlib.h>
19 #include <X11/Xatom.h>
20 #include <gdk/gdk.h>
22 #include "main.h"
23 #include "gui_support.h"
25 static GdkAtom xa_win_state;
26 static GdkAtom xa_win_layer;
27 static GdkAtom xa_win_hints;
28 static GdkAtom xa_cardinal;
30 void gui_support_init()
32 xa_win_state = gdk_atom_intern("_WIN_STATE", FALSE);
33 xa_win_layer = gdk_atom_intern("_WIN_LAYER", FALSE);
34 xa_win_hints = gdk_atom_intern("_WIN_HINTS", FALSE);
35 xa_cardinal = gdk_atom_intern("CARDINAL", FALSE);
38 static void choice_clicked(GtkWidget *widget, gpointer number)
40 int *choice_return;
42 choice_return = gtk_object_get_data(GTK_OBJECT(widget),
43 "choice_return");
45 if (choice_return)
46 *choice_return = (int) number;
49 /* Open a modal dialog box showing a message.
50 * The user can choose from a selection of buttons at the bottom.
51 * Returns -1 if the window is destroyed, or the number of the button
52 * if one is clicked (starting from zero).
54 int get_choice(char *title,
55 char *message,
56 int number_of_buttons, ...)
58 GtkWidget *dialog;
59 GtkWidget *vbox, *action_area, *separator;
60 GtkWidget *text, *text_container;
61 GtkWidget *button;
62 int i, retval;
63 va_list ap;
64 int choice_return;
66 dialog = gtk_window_new(GTK_WINDOW_DIALOG);
67 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
68 gtk_window_set_title(GTK_WINDOW(dialog), title);
69 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
71 vbox = gtk_vbox_new(FALSE, 0);
72 gtk_container_add(GTK_CONTAINER(dialog), vbox);
74 action_area = gtk_hbox_new(TRUE, 5);
75 gtk_container_set_border_width(GTK_CONTAINER(action_area), 10);
76 gtk_box_pack_end(GTK_BOX(vbox), action_area, FALSE, TRUE, 0);
78 separator = gtk_hseparator_new ();
79 gtk_box_pack_end(GTK_BOX(vbox), separator, FALSE, TRUE, 0);
81 text = gtk_label_new(message);
82 gtk_label_set_line_wrap(GTK_LABEL(text), TRUE);
83 text_container = gtk_event_box_new();
84 gtk_container_set_border_width(GTK_CONTAINER(text_container), 32);
85 gtk_container_add(GTK_CONTAINER(text_container), text);
87 gtk_box_pack_start(GTK_BOX(vbox),
88 text_container,
89 TRUE, TRUE, 0);
91 va_start(ap, number_of_buttons);
93 for (i = 0; i < number_of_buttons; i++)
95 button = gtk_button_new_with_label(va_arg(ap, char *));
96 gtk_object_set_data(GTK_OBJECT(button), "choice_return",
97 &choice_return);
98 gtk_box_pack_start(GTK_BOX(action_area),
99 button,
100 TRUE, TRUE, 16);
101 gtk_signal_connect(GTK_OBJECT(button), "clicked",
102 choice_clicked, (gpointer) i);
104 if (!i)
105 gtk_widget_grab_focus(button);
107 va_end(ap);
109 gtk_object_set_data(GTK_OBJECT(dialog), "choice_return",
110 &choice_return);
111 gtk_signal_connect(GTK_OBJECT(dialog), "destroy", choice_clicked,
112 (gpointer) -1);
114 choice_return = -2;
116 gtk_widget_show_all(dialog);
118 while (choice_return == -2)
119 g_main_iteration(TRUE);
121 retval = choice_return;
123 if (retval != -1)
124 gtk_widget_destroy(dialog);
126 return retval;
129 /* Display a message in a window */
130 void report_error(char *title, char *message)
132 g_return_if_fail(message != NULL);
134 if (!title)
135 title = "Error";
137 get_choice(title, message, 1, "OK");
140 void set_cardinal_property(GdkWindow *window, GdkAtom prop, guint32 value)
142 gdk_property_change(window, prop, xa_cardinal, 32,
143 GDK_PROP_MODE_REPLACE, (gchar *) &value, 1);
146 void make_panel_window(GdkWindow *window)
148 static gboolean need_init = TRUE;
149 static GdkAtom xa_state;
151 if (need_init)
153 xa_state = gdk_atom_intern("_WIN_STATE", FALSE);
154 need_init = FALSE;
157 gdk_window_set_decorations(window, 0);
158 gdk_window_set_functions(window, 0);
160 set_cardinal_property(window, xa_state,
161 WIN_STATE_STICKY | WIN_STATE_HIDDEN |
162 WIN_STATE_FIXED_POSITION | WIN_STATE_ARRANGE_IGNORE);
165 gint hide_dialog_event(GtkWidget *widget, GdkEvent *event, gpointer window)
167 gtk_widget_hide((GtkWidget *) window);
169 return TRUE;
172 static gboolean error_idle_cb(gpointer data)
174 char **error = (char **) data;
176 report_error(error[0], error[1]);
177 g_free(error[0]);
178 g_free(error[1]);
179 error[0] = error[1] = NULL;
181 if (--number_of_windows == 0)
182 gtk_main_quit();
184 return FALSE;
187 /* Display an error next time we are idle */
188 void delayed_error(char *title, char *error)
190 static char *delayed_error_data[2] = {NULL, NULL};
191 gboolean already_open;
193 g_return_if_fail(error != NULL);
195 already_open = delayed_error_data[1] != NULL;
197 g_free(delayed_error_data[0]);
198 g_free(delayed_error_data[1]);
200 delayed_error_data[0] = g_strdup(title);
201 delayed_error_data[1] = g_strdup(error);
203 if (already_open)
204 return;
206 gtk_idle_add(error_idle_cb, delayed_error_data);
208 number_of_windows++;
211 /* Load the file into memory. Return TRUE on success.
212 * Block is zero terminated (but this is not included in the length).
214 gboolean load_file(char *pathname, char **data_out, long *length_out)
216 FILE *file;
217 long length;
218 char *buffer;
219 gboolean retval = FALSE;
221 file = fopen(pathname, "r");
223 if (!file)
225 delayed_error("Opening file for DND", g_strerror(errno));
226 return FALSE;
229 fseek(file, 0, SEEK_END);
230 length = ftell(file);
232 buffer = malloc(length + 1);
233 if (buffer)
235 fseek(file, 0, SEEK_SET);
236 fread(buffer, 1, length, file);
238 if (ferror(file))
240 delayed_error("Loading file for DND",
241 g_strerror(errno));
242 g_free(buffer);
244 else
246 *data_out = buffer;
247 *length_out = length;
248 buffer[length] = '\0';
249 retval = TRUE;
252 else
253 delayed_error("Loading file for DND",
254 "Can't allocate memory for buffer to "
255 "transfer this file");
257 fclose(file);
259 return retval;