4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* gui_support.c - general (GUI) support routines */
29 #include <sys/param.h>
35 #include <X11/Xatom.h>
40 #include "gui_support.h"
43 GdkFont
*item_font
= NULL
;
44 GdkFont
*fixed_font
= NULL
;
45 GtkStyle
*fixed_style
= NULL
;
47 GdkColor red
= {0, 0xffff, 0, 0};
48 GdkGC
*red_gc
= NULL
; /* Not automatically initialised */
49 gint screen_width
, screen_height
;
51 static GdkAtom xa_cardinal
;
53 void gui_support_init()
55 fixed_font
= gdk_font_load("fixed");
56 item_font
= gtk_widget_get_default_style()->font
;
58 fixed_style
= gtk_style_copy(gtk_widget_get_default_style());
59 fixed_style
->font
= fixed_font
;
61 fixed_width
= gdk_string_width(fixed_font
, "m");
63 xa_cardinal
= gdk_atom_intern("CARDINAL", FALSE
);
65 gdk_color_alloc(gtk_widget_get_default_colormap(), &red
);
67 /* This call starts returning strange values after a while, so get
68 * the result here during init.
70 gdk_window_get_size(GDK_ROOT_PARENT(), &screen_width
, &screen_height
);
73 static void choice_clicked(GtkWidget
*widget
, gpointer number
)
77 choice_return
= gtk_object_get_data(GTK_OBJECT(widget
),
81 *choice_return
= (int) number
;
84 /* Open a modal dialog box showing a message.
85 * The user can choose from a selection of buttons at the bottom.
86 * Returns -1 if the window is destroyed, or the number of the button
87 * if one is clicked (starting from zero).
89 int get_choice(char *title
,
91 int number_of_buttons
, ...)
94 GtkWidget
*vbox
, *action_area
, *separator
;
95 GtkWidget
*text
, *text_container
;
96 GtkWidget
*button
= NULL
;
101 dialog
= gtk_window_new(GTK_WINDOW_DIALOG
);
102 gtk_window_set_modal(GTK_WINDOW(dialog
), TRUE
);
103 gtk_window_set_title(GTK_WINDOW(dialog
), title
);
104 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_CENTER
);
106 vbox
= gtk_vbox_new(FALSE
, 0);
107 gtk_container_add(GTK_CONTAINER(dialog
), vbox
);
109 action_area
= gtk_hbox_new(TRUE
, 5);
110 gtk_container_set_border_width(GTK_CONTAINER(action_area
), 10);
111 gtk_box_pack_end(GTK_BOX(vbox
), action_area
, FALSE
, TRUE
, 0);
113 separator
= gtk_hseparator_new ();
114 gtk_box_pack_end(GTK_BOX(vbox
), separator
, FALSE
, TRUE
, 0);
116 text
= gtk_label_new(message
);
117 gtk_label_set_line_wrap(GTK_LABEL(text
), TRUE
);
118 text_container
= gtk_event_box_new();
119 gtk_container_set_border_width(GTK_CONTAINER(text_container
), 32);
120 gtk_container_add(GTK_CONTAINER(text_container
), text
);
122 gtk_box_pack_start(GTK_BOX(vbox
),
126 va_start(ap
, number_of_buttons
);
128 for (i
= 0; i
< number_of_buttons
; i
++)
130 button
= gtk_button_new_with_label(va_arg(ap
, char *));
131 gtk_object_set_data(GTK_OBJECT(button
), "choice_return",
133 gtk_box_pack_start(GTK_BOX(action_area
),
136 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
137 choice_clicked
, (gpointer
) i
);
139 gtk_window_set_focus(GTK_WINDOW(dialog
), button
);
142 gtk_widget_grab_focus(button
);
146 gtk_object_set_data(GTK_OBJECT(dialog
), "choice_return",
148 gtk_signal_connect(GTK_OBJECT(dialog
), "destroy", choice_clicked
,
153 gtk_widget_show_all(dialog
);
155 while (choice_return
== -2)
156 g_main_iteration(TRUE
);
158 retval
= choice_return
;
161 gtk_widget_destroy(dialog
);
166 /* Display a message in a window */
167 void report_error(char *title
, char *message
)
169 g_return_if_fail(message
!= NULL
);
174 get_choice(title
, message
, 1, "OK");
177 void set_cardinal_property(GdkWindow
*window
, GdkAtom prop
, guint32 value
)
179 gdk_property_change(window
, prop
, xa_cardinal
, 32,
180 GDK_PROP_MODE_REPLACE
, (gchar
*) &value
, 1);
183 /* NB: Also used for pinned icons.
184 * TODO: Set the level here too.
186 void make_panel_window(GdkWindow
*window
)
188 static gboolean need_init
= TRUE
;
189 static GdkAtom xa_state
;
193 xa_state
= gdk_atom_intern("_WIN_STATE", FALSE
);
197 gdk_window_set_decorations(window
, 0);
198 gdk_window_set_functions(window
, 0);
200 set_cardinal_property(window
, xa_state
,
201 WIN_STATE_STICKY
| WIN_STATE_HIDDEN
|
202 WIN_STATE_FIXED_POSITION
| WIN_STATE_ARRANGE_IGNORE
);
205 gint
hide_dialog_event(GtkWidget
*widget
, GdkEvent
*event
, gpointer window
)
207 gtk_widget_hide((GtkWidget
*) window
);
212 static gboolean
error_idle_cb(gpointer data
)
214 char **error
= (char **) data
;
216 report_error(error
[0], error
[1]);
219 error
[0] = error
[1] = NULL
;
221 if (--number_of_windows
== 0)
227 /* Display an error next time we are idle */
228 void delayed_error(char *title
, char *error
)
230 static char *delayed_error_data
[2] = {NULL
, NULL
};
231 gboolean already_open
;
233 g_return_if_fail(error
!= NULL
);
235 already_open
= delayed_error_data
[1] != NULL
;
237 g_free(delayed_error_data
[0]);
238 g_free(delayed_error_data
[1]);
240 delayed_error_data
[0] = g_strdup(title
);
241 delayed_error_data
[1] = g_strdup(error
);
246 gtk_idle_add(error_idle_cb
, delayed_error_data
);
251 /* Load the file into memory. Return TRUE on success.
252 * Block is zero terminated (but this is not included in the length).
254 gboolean
load_file(char *pathname
, char **data_out
, long *length_out
)
259 gboolean retval
= FALSE
;
261 file
= fopen(pathname
, "r");
267 message
= g_strdup_printf("open(%s): %s",
268 pathname
, g_strerror(errno
));
269 delayed_error(PROJECT
, message
);
274 fseek(file
, 0, SEEK_END
);
275 length
= ftell(file
);
277 buffer
= malloc(length
+ 1);
280 fseek(file
, 0, SEEK_SET
);
281 fread(buffer
, 1, length
, file
);
287 tmp
= g_strdup_printf("%s: %s\n",
288 pathname
, g_strerror(errno
));
289 delayed_error(_("Error reading file"), tmp
);
296 *length_out
= length
;
297 buffer
[length
] = '\0';
302 delayed_error(PROJECT
,
303 _("Can't allocate memory for buffer to "
311 GtkWidget
*new_help_button(HelpFunc show_help
, gpointer data
)
315 b
= gtk_button_new();
316 gtk_button_set_relief(GTK_BUTTON(b
), GTK_RELIEF_NONE
);
317 icon
= gtk_pixmap_new(im_help
->pixmap
, im_help
->mask
);
318 gtk_container_add(GTK_CONTAINER(b
), icon
);
319 gtk_signal_connect_object(GTK_OBJECT(b
), "clicked", show_help
, data
);
321 GTK_WIDGET_UNSET_FLAGS(b
, GTK_CAN_FOCUS
);
326 /* Read file into memory. Call parse_line(guchar *line) for each line
327 * in the file. Callback returns NULL on success, or an error message
328 * if something went wrong. Only the first error is displayed to the user.
330 void parse_file(char *path
, ParseFunc
*parse_line
)
334 gboolean seen_error
= FALSE
;
336 if (load_file(path
, &data
, &length
))
342 while (line
&& *line
)
344 eol
= strchr(line
, '\n');
348 error
= parse_line(line
);
350 if (error
&& !seen_error
)
354 message
= g_string_new(NULL
);
355 g_string_sprintf(message
,
356 _("Error in '%s' file at line %d: "
358 "This may be due to upgrading from a previous version of "
359 "ROX-Filer. Open the Options window and click on Save.\n"
360 "Further errors will be ignored."),
364 delayed_error(PROJECT
, message
->str
);
365 g_string_free(message
, TRUE
);
378 /* Sets up a proxy window for DnD on the specified X window.
379 * Courtesy of Owen Taylor (taken from gmc).
381 gboolean
setup_xdnd_proxy(guint32 xid
, GdkWindow
*proxy_window
)
383 GdkAtom xdnd_proxy_atom
;
387 unsigned long nitems
, after
;
390 guint32 old_warnings
;
392 XGrabServer(GDK_DISPLAY());
394 xdnd_proxy_atom
= gdk_atom_intern("XdndProxy", FALSE
);
395 proxy_xid
= GDK_WINDOW_XWINDOW(proxy_window
);
399 old_warnings
= gdk_error_warnings
;
402 gdk_error_warnings
= 0;
404 /* Check if somebody else already owns drops on the root window */
406 XGetWindowProperty(GDK_DISPLAY(), xid
,
408 1, False
, AnyPropertyType
,
409 &type
, &format
, &nitems
, &after
,
410 (guchar
**) &proxy_data
);
414 if (format
== 32 && nitems
== 1)
420 /* The property was set, now check if the window it points to exists
421 * and has a XdndProxy property pointing to itself.
425 XGetWindowProperty(GDK_DISPLAY(), proxy
,
427 1, False
, AnyPropertyType
,
428 &type
, &format
, &nitems
, &after
,
429 (guchar
**) &proxy_data
);
431 if (!gdk_error_code
&& type
!= None
)
433 if (format
== 32 && nitems
== 1)
434 if (*proxy_data
!= proxy
)
445 /* OK, we can set the property to point to us */
447 XChangeProperty(GDK_DISPLAY(), xid
,
449 gdk_atom_intern("WINDOW", FALSE
),
451 (guchar
*) &proxy_xid
, 1);
455 gdk_error_warnings
= old_warnings
;
457 XUngrabServer(GDK_DISPLAY());
462 /* Mark our window as a valid proxy window with a XdndProxy
463 * property pointing recursively;
465 XChangeProperty(GDK_DISPLAY(), proxy_xid
,
467 gdk_atom_intern("WINDOW", FALSE
),
469 (guchar
*) &proxy_xid
, 1);
475 /* xid is the window (usually the root) which points to the proxy */
476 void release_xdnd_proxy(guint32 xid
)
478 GdkAtom xdnd_proxy_atom
;
480 xdnd_proxy_atom
= gdk_atom_intern("XdndProxy", FALSE
);
482 XDeleteProperty(GDK_DISPLAY(), xid
, xdnd_proxy_atom
);
485 /* Looks for the proxy window to get root window clicks from the window
486 * manager. Taken from gmc. NULL if there is no proxy window.
488 GdkWindow
*find_click_proxy_window(void)
490 GdkAtom click_proxy_atom
;
493 unsigned long nitems
, after
;
496 guint32 old_warnings
;
497 GdkWindow
*proxy_gdk_window
;
499 XGrabServer(GDK_DISPLAY());
501 click_proxy_atom
= gdk_atom_intern("_WIN_DESKTOP_BUTTON_PROXY", FALSE
);
505 old_warnings
= gdk_error_warnings
;
508 gdk_error_warnings
= 0;
510 /* Check if the proxy window exists */
512 XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
514 1, False
, AnyPropertyType
,
515 &type
, &format
, &nitems
, &after
,
516 (guchar
**) &proxy_data
);
520 if (format
== 32 && nitems
== 1)
526 /* If the property was set, check if the window it points to exists
527 * and has a _WIN_DESKTOP_BUTTON_PROXY property pointing to itself.
532 XGetWindowProperty(GDK_DISPLAY(), proxy
,
534 1, False
, AnyPropertyType
,
535 &type
, &format
, &nitems
, &after
,
536 (guchar
**) &proxy_data
);
538 if (!gdk_error_code
&& type
!= None
)
540 if (format
== 32 && nitems
== 1)
541 if (*proxy_data
!= proxy
)
551 gdk_error_warnings
= old_warnings
;
553 XUngrabServer(GDK_DISPLAY());
557 proxy_gdk_window
= gdk_window_foreign_new(proxy
);
559 proxy_gdk_window
= NULL
;
561 return proxy_gdk_window
;