4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@users.sourceforge.net>.
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>
34 #include <X11/Xatom.h>
41 #include "gui_support.h"
44 GdkFont
*item_font
= NULL
;
45 GdkFont
*fixed_font
= NULL
;
46 GtkStyle
*fixed_style
= NULL
;
48 GdkColor red
= {0, 0xffff, 0, 0};
49 GdkGC
*red_gc
= NULL
; /* Not automatically initialised */
50 gint screen_width
, screen_height
;
52 static GdkAtom xa_cardinal
;
54 void gui_support_init()
56 fixed_font
= gdk_font_load("fixed");
57 item_font
= gtk_widget_get_default_style()->font
;
59 fixed_style
= gtk_style_copy(gtk_widget_get_default_style());
60 fixed_style
->font
= fixed_font
;
62 fixed_width
= gdk_string_width(fixed_font
, "m");
64 xa_cardinal
= gdk_atom_intern("CARDINAL", FALSE
);
66 gdk_color_alloc(gtk_widget_get_default_colormap(), &red
);
68 /* This call starts returning strange values after a while, so get
69 * the result here during init.
71 gdk_window_get_size(GDK_ROOT_PARENT(), &screen_width
, &screen_height
);
74 static void choice_clicked(GtkWidget
*widget
, gpointer number
)
78 choice_return
= gtk_object_get_data(GTK_OBJECT(widget
),
82 *choice_return
= (int) number
;
85 /* Open a modal dialog box showing a message.
86 * The user can choose from a selection of buttons at the bottom.
87 * Returns -1 if the window is destroyed, or the number of the button
88 * if one is clicked (starting from zero).
90 int get_choice(char *title
,
92 int number_of_buttons
, ...)
95 GtkWidget
*vbox
, *action_area
, *separator
;
96 GtkWidget
*text
, *text_container
;
97 GtkWidget
*button
= NULL
;
102 dialog
= gtk_window_new(GTK_WINDOW_DIALOG
);
103 gtk_window_set_modal(GTK_WINDOW(dialog
), TRUE
);
104 gtk_window_set_title(GTK_WINDOW(dialog
), title
);
105 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_CENTER
);
107 vbox
= gtk_vbox_new(FALSE
, 0);
108 gtk_container_add(GTK_CONTAINER(dialog
), vbox
);
110 action_area
= gtk_hbox_new(TRUE
, 5);
111 gtk_container_set_border_width(GTK_CONTAINER(action_area
), 10);
112 gtk_box_pack_end(GTK_BOX(vbox
), action_area
, FALSE
, TRUE
, 0);
114 separator
= gtk_hseparator_new ();
115 gtk_box_pack_end(GTK_BOX(vbox
), separator
, FALSE
, TRUE
, 0);
117 text
= gtk_label_new(message
);
118 gtk_label_set_line_wrap(GTK_LABEL(text
), TRUE
);
119 text_container
= gtk_event_box_new();
120 gtk_container_set_border_width(GTK_CONTAINER(text_container
), 32);
121 gtk_container_add(GTK_CONTAINER(text_container
), text
);
123 gtk_box_pack_start(GTK_BOX(vbox
),
127 va_start(ap
, number_of_buttons
);
129 for (i
= 0; i
< number_of_buttons
; i
++)
131 button
= gtk_button_new_with_label(va_arg(ap
, char *));
132 gtk_object_set_data(GTK_OBJECT(button
), "choice_return",
134 gtk_box_pack_start(GTK_BOX(action_area
),
137 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
138 choice_clicked
, (gpointer
) i
);
140 gtk_window_set_focus(GTK_WINDOW(dialog
), button
);
143 gtk_widget_grab_focus(button
);
147 gtk_object_set_data(GTK_OBJECT(dialog
), "choice_return",
149 gtk_signal_connect(GTK_OBJECT(dialog
), "destroy", choice_clicked
,
154 gtk_widget_show_all(dialog
);
156 while (choice_return
== -2)
157 g_main_iteration(TRUE
);
159 retval
= choice_return
;
162 gtk_widget_destroy(dialog
);
167 /* Display a message in a window */
168 void report_error(char *title
, char *message
)
170 g_return_if_fail(message
!= NULL
);
175 get_choice(title
, message
, 1, "OK");
178 void set_cardinal_property(GdkWindow
*window
, GdkAtom prop
, guint32 value
)
180 gdk_property_change(window
, prop
, xa_cardinal
, 32,
181 GDK_PROP_MODE_REPLACE
, (gchar
*) &value
, 1);
184 /* NB: Also used for pinned icons.
185 * TODO: Set the level here too.
187 void make_panel_window(GdkWindow
*window
)
189 static gboolean need_init
= TRUE
;
190 static GdkAtom xa_state
;
194 xa_state
= gdk_atom_intern("_WIN_STATE", FALSE
);
198 gdk_window_set_decorations(window
, 0);
199 gdk_window_set_functions(window
, 0);
201 set_cardinal_property(window
, xa_state
,
202 WIN_STATE_STICKY
| WIN_STATE_HIDDEN
|
203 WIN_STATE_FIXED_POSITION
| WIN_STATE_ARRANGE_IGNORE
);
206 gint
hide_dialog_event(GtkWidget
*widget
, GdkEvent
*event
, gpointer window
)
208 gtk_widget_hide((GtkWidget
*) window
);
213 static gboolean
error_idle_cb(gpointer data
)
215 char **error
= (char **) data
;
217 report_error(error
[0], error
[1]);
220 error
[0] = error
[1] = NULL
;
222 if (--number_of_windows
== 0)
228 /* Display an error next time we are idle */
229 void delayed_error(char *title
, char *error
)
231 static char *delayed_error_data
[2] = {NULL
, NULL
};
232 gboolean already_open
;
234 g_return_if_fail(error
!= NULL
);
236 already_open
= delayed_error_data
[1] != NULL
;
238 g_free(delayed_error_data
[0]);
239 g_free(delayed_error_data
[1]);
241 delayed_error_data
[0] = g_strdup(title
);
242 delayed_error_data
[1] = g_strdup(error
);
247 gtk_idle_add(error_idle_cb
, delayed_error_data
);
252 /* Load the file into memory. Return TRUE on success.
253 * Block is zero terminated (but this is not included in the length).
255 gboolean
load_file(char *pathname
, char **data_out
, long *length_out
)
260 gboolean retval
= FALSE
;
262 file
= fopen(pathname
, "r");
268 message
= g_strdup_printf("open(%s): %s",
269 pathname
, g_strerror(errno
));
270 delayed_error(PROJECT
, message
);
275 fseek(file
, 0, SEEK_END
);
276 length
= ftell(file
);
278 buffer
= malloc(length
+ 1);
281 fseek(file
, 0, SEEK_SET
);
282 fread(buffer
, 1, length
, file
);
288 tmp
= g_strdup_printf("%s: %s\n",
289 pathname
, g_strerror(errno
));
290 delayed_error(_("Error reading file"), tmp
);
297 *length_out
= length
;
298 buffer
[length
] = '\0';
303 delayed_error(PROJECT
,
304 _("Can't allocate memory for buffer to "
312 GtkWidget
*new_help_button(HelpFunc show_help
, gpointer data
)
316 b
= gtk_button_new();
317 gtk_button_set_relief(GTK_BUTTON(b
), GTK_RELIEF_NONE
);
318 icon
= gtk_pixmap_new(im_help
->pixmap
, im_help
->mask
);
319 gtk_container_add(GTK_CONTAINER(b
), icon
);
320 gtk_signal_connect_object(GTK_OBJECT(b
), "clicked", show_help
, data
);
322 GTK_WIDGET_UNSET_FLAGS(b
, GTK_CAN_FOCUS
);
327 /* Read file into memory. Call parse_line(guchar *line) for each line
328 * in the file. Callback returns NULL on success, or an error message
329 * if something went wrong. Only the first error is displayed to the user.
331 void parse_file(char *path
, ParseFunc
*parse_line
)
335 gboolean seen_error
= FALSE
;
337 if (load_file(path
, &data
, &length
))
343 while (line
&& *line
)
345 eol
= strchr(line
, '\n');
349 error
= parse_line(line
);
351 if (error
&& !seen_error
)
355 message
= g_string_new(NULL
);
356 g_string_sprintf(message
,
357 _("Error in '%s' file at line %d: "
359 "This may be due to upgrading from a previous version of "
360 "ROX-Filer. Open the Options window and click on Save.\n"
361 "Further errors will be ignored."),
365 delayed_error(PROJECT
, message
->str
);
366 g_string_free(message
, TRUE
);
379 /* Sets up a proxy window for DnD on the specified X window.
380 * Courtesy of Owen Taylor (taken from gmc).
382 gboolean
setup_xdnd_proxy(guint32 xid
, GdkWindow
*proxy_window
)
384 GdkAtom xdnd_proxy_atom
;
388 unsigned long nitems
, after
;
391 guint32 old_warnings
;
393 XGrabServer(GDK_DISPLAY());
395 xdnd_proxy_atom
= gdk_atom_intern("XdndProxy", FALSE
);
396 proxy_xid
= GDK_WINDOW_XWINDOW(proxy_window
);
400 old_warnings
= gdk_error_warnings
;
403 gdk_error_warnings
= 0;
405 /* Check if somebody else already owns drops on the root window */
407 XGetWindowProperty(GDK_DISPLAY(), xid
,
409 1, False
, AnyPropertyType
,
410 &type
, &format
, &nitems
, &after
,
411 (guchar
**) &proxy_data
);
415 if (format
== 32 && nitems
== 1)
421 /* The property was set, now check if the window it points to exists
422 * and has a XdndProxy property pointing to itself.
426 XGetWindowProperty(GDK_DISPLAY(), proxy
,
428 1, False
, AnyPropertyType
,
429 &type
, &format
, &nitems
, &after
,
430 (guchar
**) &proxy_data
);
432 if (!gdk_error_code
&& type
!= None
)
434 if (format
== 32 && nitems
== 1)
435 if (*proxy_data
!= proxy
)
446 /* OK, we can set the property to point to us */
448 XChangeProperty(GDK_DISPLAY(), xid
,
450 gdk_atom_intern("WINDOW", FALSE
),
452 (guchar
*) &proxy_xid
, 1);
456 gdk_error_warnings
= old_warnings
;
458 XUngrabServer(GDK_DISPLAY());
463 /* Mark our window as a valid proxy window with a XdndProxy
464 * property pointing recursively;
466 XChangeProperty(GDK_DISPLAY(), proxy_xid
,
468 gdk_atom_intern("WINDOW", FALSE
),
470 (guchar
*) &proxy_xid
, 1);
476 /* xid is the window (usually the root) which points to the proxy */
477 void release_xdnd_proxy(guint32 xid
)
479 GdkAtom xdnd_proxy_atom
;
481 xdnd_proxy_atom
= gdk_atom_intern("XdndProxy", FALSE
);
483 XDeleteProperty(GDK_DISPLAY(), xid
, xdnd_proxy_atom
);
486 /* Looks for the proxy window to get root window clicks from the window
487 * manager. Taken from gmc. NULL if there is no proxy window.
489 GdkWindow
*find_click_proxy_window(void)
491 GdkAtom click_proxy_atom
;
494 unsigned long nitems
, after
;
497 guint32 old_warnings
;
498 GdkWindow
*proxy_gdk_window
;
500 XGrabServer(GDK_DISPLAY());
502 click_proxy_atom
= gdk_atom_intern("_WIN_DESKTOP_BUTTON_PROXY", FALSE
);
506 old_warnings
= gdk_error_warnings
;
509 gdk_error_warnings
= 0;
511 /* Check if the proxy window exists */
513 XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
515 1, False
, AnyPropertyType
,
516 &type
, &format
, &nitems
, &after
,
517 (guchar
**) &proxy_data
);
521 if (format
== 32 && nitems
== 1)
527 /* If the property was set, check if the window it points to exists
528 * and has a _WIN_DESKTOP_BUTTON_PROXY property pointing to itself.
533 XGetWindowProperty(GDK_DISPLAY(), proxy
,
535 1, False
, AnyPropertyType
,
536 &type
, &format
, &nitems
, &after
,
537 (guchar
**) &proxy_data
);
539 if (!gdk_error_code
&& type
!= None
)
541 if (format
== 32 && nitems
== 1)
542 if (*proxy_data
!= proxy
)
552 gdk_error_warnings
= old_warnings
;
554 XUngrabServer(GDK_DISPLAY());
558 proxy_gdk_window
= gdk_window_foreign_new(proxy
);
560 proxy_gdk_window
= NULL
;
562 return proxy_gdk_window
;
565 /* Returns the position of the pointer.
566 * TRUE if any modifier keys or mouse buttons are pressed.
568 gboolean
get_pointer_xy(int *x
, int *y
)
574 XQueryPointer(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
575 &root
, &child
, x
, y
, &win_x
, &win_y
, &mask
);
580 #define DECOR_BORDER 32
582 /* Centre the window at these coords */
583 void centre_window(GdkWindow
*window
, int x
, int y
)
587 g_return_if_fail(window
!= NULL
);
589 gdk_window_get_size(window
, &w
, &h
);
594 gdk_window_move(window
,
595 CLAMP(x
, DECOR_BORDER
, screen_width
- w
- DECOR_BORDER
),
596 CLAMP(y
, DECOR_BORDER
, screen_height
- h
- DECOR_BORDER
));