r1466: Don't do manual stacking except with -o (confuses sawfish).
[rox-filer.git] / ROX-Filer / src / gui_support.c
blob8857efb4a2b2a546365d0aee54af54f1f596effb
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2002, the ROX-Filer team.
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)
10 * any later version.
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
15 * more details.
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 */
24 #include "config.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/param.h>
30 #include <stdarg.h>
31 #include <errno.h>
33 #include <X11/Xlib.h>
34 #include <X11/Xatom.h>
35 #include <gdk/gdkx.h>
36 #include <gdk/gdk.h>
37 #include <gdk/gdkkeysyms.h>
39 #include "global.h"
41 #include "main.h"
42 #include "gui_support.h"
43 #include "support.h"
44 #include "pixmaps.h"
45 #include "choices.h"
47 gint screen_width, screen_height;
49 static GdkAtom xa_cardinal;
51 static GtkWidget *current_dialog = NULL;
53 void gui_support_init()
55 xa_cardinal = gdk_atom_intern("CARDINAL", FALSE);
57 /* This call starts returning strange values after a while, so get
58 * the result here during init.
60 gdk_drawable_get_size(gdk_get_default_root_window(),
61 &screen_width, &screen_height);
64 /* Open a modal dialog box showing a message.
65 * The user can choose from a selection of buttons at the bottom.
66 * Returns -1 if the window is destroyed, or the number of the button
67 * if one is clicked (starting from zero).
69 * If a dialog is already open, returns -1 without waiting AND
70 * brings the current dialog to the front.
72 int get_choice(const char *title,
73 const char *message,
74 int number_of_buttons, ...)
76 GtkWidget *dialog;
77 GtkWidget *button = NULL;
78 int i, retval;
79 va_list ap;
81 if (current_dialog)
83 gtk_widget_hide(current_dialog);
84 gtk_widget_show(current_dialog);
85 return -1;
88 current_dialog = dialog = gtk_message_dialog_new(NULL,
89 GTK_DIALOG_MODAL,
90 GTK_MESSAGE_QUESTION,
91 GTK_BUTTONS_NONE,
92 "%s", message);
93 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
95 va_start(ap, number_of_buttons);
97 for (i = 0; i < number_of_buttons; i++)
98 button = gtk_dialog_add_button(GTK_DIALOG(current_dialog),
99 va_arg(ap, char *), i);
101 gtk_window_set_title(GTK_WINDOW(dialog), title);
102 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
104 gtk_dialog_set_default_response(GTK_DIALOG(dialog), i - 1);
106 va_end(ap);
108 retval = gtk_dialog_run(GTK_DIALOG(dialog));
109 if (retval == GTK_RESPONSE_NONE)
110 retval = -1;
111 gtk_widget_destroy(dialog);
113 current_dialog = NULL;
115 return retval;
118 void info_message(const char *message, ...)
120 GtkWidget *dialog;
121 va_list args;
122 gchar *s;
124 g_return_if_fail(message != NULL);
126 va_start(args, message);
127 s = g_strdup_vprintf(message, args);
128 va_end(args);
130 dialog = gtk_message_dialog_new(NULL,
131 GTK_DIALOG_MODAL,
132 GTK_MESSAGE_INFO,
133 GTK_BUTTONS_OK,
134 "%s", s);
135 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
136 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
137 gtk_dialog_run(GTK_DIALOG(dialog));
138 gtk_widget_destroy(dialog);
140 g_free(s);
143 /* Display a message in a window with "ROX-Filer" as title */
144 void report_error(const char *message, ...)
146 GtkWidget *dialog;
147 va_list args;
148 gchar *s;
150 g_return_if_fail(message != NULL);
152 va_start(args, message);
153 s = g_strdup_vprintf(message, args);
154 va_end(args);
156 dialog = gtk_message_dialog_new(NULL,
157 GTK_DIALOG_MODAL,
158 GTK_MESSAGE_ERROR,
159 GTK_BUTTONS_OK,
160 "%s", s);
161 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
162 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
163 gtk_dialog_run(GTK_DIALOG(dialog));
164 gtk_widget_destroy(dialog);
166 g_free(s);
169 void set_cardinal_property(GdkWindow *window, GdkAtom prop, guint32 value)
171 gdk_property_change(window, prop, xa_cardinal, 32,
172 GDK_PROP_MODE_REPLACE, (gchar *) &value, 1);
175 /* NB: Also used for pinned icons.
176 * TODO: Set the level here too.
178 void make_panel_window(GtkWidget *widget)
180 static gboolean need_init = TRUE;
181 static GdkAtom xa_state, xa_atom, xa_net_state, xa_hints, xa_win_hints;
182 static GdkAtom state_list[3];
183 GdkWindow *window = widget->window;
184 gint32 wm_hints_values[] = {1, False, 0, 0, 0, 0, 0, 0};
185 GdkAtom wm_protocols[2];
187 g_return_if_fail(window != NULL);
189 if (override_redirect)
191 gdk_window_set_override_redirect(window, TRUE);
192 return;
195 if (need_init)
197 xa_win_hints = gdk_atom_intern("_WIN_HINTS", FALSE);
198 xa_state = gdk_atom_intern("_WIN_STATE", FALSE);
199 xa_atom = gdk_atom_intern("ATOM", FALSE);
200 xa_net_state = gdk_atom_intern("_NET_WM_STATE", FALSE);
201 xa_hints = gdk_atom_intern("WM_HINTS", FALSE);
203 /* Note: Starting with Gtk+-1.3.12, Gtk+ converts GdkAtoms
204 * to X atoms automatically when the type is ATOM.
206 state_list[0] = gdk_atom_intern("_NET_WM_STATE_STICKY", FALSE);
207 state_list[1] = gdk_atom_intern("_NET_WM_STATE_SKIP_PAGER",
208 FALSE);
209 state_list[2] = gdk_atom_intern("_NET_WM_STATE_SKIP_TASKBAR",
210 FALSE);
212 need_init = FALSE;
215 gdk_window_set_decorations(window, 0);
216 gdk_window_set_functions(window, 0);
218 /* Note: DON'T do gtk_window_stick(). Setting the state via
219 * gdk will override our other atoms (pager/taskbar).
222 /* Don't hide panel/pinboard windows initially (WIN_STATE_HIDDEN).
223 * Needed for IceWM - Christopher Arndt <chris.arndt@web.de>
225 set_cardinal_property(window, xa_state,
226 WIN_STATE_STICKY |
227 WIN_STATE_FIXED_POSITION | WIN_STATE_ARRANGE_IGNORE);
229 set_cardinal_property(window, xa_win_hints,
230 WIN_HINTS_SKIP_FOCUS | WIN_HINTS_SKIP_WINLIST |
231 WIN_HINTS_SKIP_TASKBAR);
233 gdk_property_change(window, xa_net_state, xa_atom, 32,
234 GDK_PROP_MODE_APPEND, (guchar *) state_list, 3);
236 g_return_if_fail(window != NULL);
238 gdk_property_change(window, xa_hints, xa_hints, 32,
239 GDK_PROP_MODE_REPLACE, (guchar *) wm_hints_values,
240 sizeof(wm_hints_values) / sizeof(gint32));
242 wm_protocols[0] = gdk_atom_intern("WM_DELETE_WINDOW", FALSE);
243 wm_protocols[1] = gdk_atom_intern("_NET_WM_PING", FALSE);
244 gdk_property_change(window,
245 gdk_atom_intern("WM_PROTOCOLS", FALSE), xa_atom, 32,
246 GDK_PROP_MODE_REPLACE, (guchar *) wm_protocols,
247 sizeof(wm_protocols) / sizeof(GdkAtom));
250 static gboolean error_idle_cb(gpointer data)
252 char **error = (char **) data;
254 report_error("%s", *error);
255 g_free(*error);
256 *error = NULL;
258 if (--number_of_windows == 0)
259 gtk_main_quit();
261 return FALSE;
264 /* Display an error with "ROX-Filer" as title next time we are idle.
265 * If multiple errors are reported this way before the window is opened,
266 * all are displayed in a single window.
267 * If an error is reported while the error window is open, it is discarded.
269 void delayed_error(const char *error, ...)
271 static char *delayed_error_data = NULL;
272 char *old, *new;
273 va_list args;
275 g_return_if_fail(error != NULL);
277 old = delayed_error_data;
279 va_start(args, error);
280 new = g_strdup_vprintf(error, args);
281 va_end(args);
283 if (old)
285 delayed_error_data = g_strconcat(old,
286 _("\n---\n"),
287 new, NULL);
288 g_free(old);
289 g_free(new);
291 else
293 delayed_error_data = new;
294 gtk_idle_add(error_idle_cb, &delayed_error_data);
296 number_of_windows++;
300 /* Load the file into memory. Return TRUE on success.
301 * Block is zero terminated (but this is not included in the length).
303 gboolean load_file(const char *pathname, char **data_out, long *length_out)
305 gsize len;
306 GError *error = NULL;
308 if (!g_file_get_contents(pathname, data_out, &len, &error))
310 delayed_error("%s", error ? error->message : pathname);
311 g_error_free(error);
312 return FALSE;
315 if (length_out)
316 *length_out = len;
317 return TRUE;
320 GtkWidget *new_help_button(HelpFunc show_help, gpointer data)
322 GtkWidget *b, *icon;
324 b = gtk_button_new();
325 gtk_button_set_relief(GTK_BUTTON(b), GTK_RELIEF_NONE);
326 icon = gtk_image_new_from_pixbuf(im_help->pixbuf);
327 gtk_container_add(GTK_CONTAINER(b), icon);
328 g_signal_connect_swapped(b, "clicked", G_CALLBACK(show_help), data);
330 GTK_WIDGET_UNSET_FLAGS(b, GTK_CAN_FOCUS);
332 return b;
335 /* Read file into memory. Call parse_line(guchar *line) for each line
336 * in the file. Callback returns NULL on success, or an error message
337 * if something went wrong. Only the first error is displayed to the user.
339 void parse_file(const char *path, ParseFunc *parse_line)
341 char *data;
342 long length;
343 gboolean seen_error = FALSE;
345 if (load_file(path, &data, &length))
347 char *eol;
348 const char *error;
349 char *line = data;
350 int line_number = 1;
352 if (strncmp(data, "<?xml ", 6) == 0)
354 delayed_error(_("Attempt to read an XML file as "
355 "a text file. File '%s' may be "
356 "corrupted."), path);
357 return;
360 while (line && *line)
362 eol = strchr(line, '\n');
363 if (eol)
364 *eol = '\0';
366 error = parse_line(line);
368 if (error && !seen_error)
370 delayed_error(
371 _("Error in '%s' file at line %d: "
372 "\n\"%s\"\n"
373 "This may be due to upgrading from a previous version of "
374 "ROX-Filer. Open the Options window and click on Save.\n"
375 "Further errors will be ignored."),
376 path,
377 line_number,
378 error);
379 seen_error = TRUE;
382 if (!eol)
383 break;
384 line = eol + 1;
385 line_number++;
387 g_free(data);
391 /* Sets up a proxy window for DnD on the specified X window.
392 * Courtesy of Owen Taylor (taken from gmc).
394 gboolean setup_xdnd_proxy(guint32 xid, GdkWindow *proxy_window)
396 GdkAtom xdnd_proxy_atom;
397 Window proxy_xid;
398 Atom type;
399 int format;
400 unsigned long nitems, after;
401 Window *proxy_data;
402 Window proxy;
404 XGrabServer(GDK_DISPLAY());
406 xdnd_proxy_atom = gdk_atom_intern("XdndProxy", FALSE);
407 proxy_xid = GDK_WINDOW_XWINDOW(proxy_window);
408 type = None;
409 proxy = None;
411 gdk_error_trap_push();
413 /* Check if somebody else already owns drops on the root window */
415 XGetWindowProperty(GDK_DISPLAY(), xid,
416 gdk_x11_atom_to_xatom(xdnd_proxy_atom), 0,
417 1, False, AnyPropertyType,
418 &type, &format, &nitems, &after,
419 (guchar **) &proxy_data);
421 if (type != None)
423 if (format == 32 && nitems == 1)
424 proxy = *proxy_data;
426 XFree(proxy_data);
429 /* The property was set, now check if the window it points to exists
430 * and has a XdndProxy property pointing to itself.
432 if (proxy)
434 gint gdk_error_code;
436 XGetWindowProperty(GDK_DISPLAY(), proxy,
437 gdk_x11_atom_to_xatom(xdnd_proxy_atom),
438 0, 1, False, AnyPropertyType,
439 &type, &format, &nitems, &after,
440 (guchar **) &proxy_data);
442 gdk_error_code = gdk_error_trap_pop();
443 gdk_error_trap_push();
445 if (!gdk_error_code && type != None)
447 if (format == 32 && nitems == 1)
448 if (*proxy_data != proxy)
449 proxy = None;
451 XFree(proxy_data);
453 else
454 proxy = gdk_x11_atom_to_xatom(GDK_NONE);
457 if (!proxy)
459 /* OK, we can set the property to point to us */
460 /* TODO: Use gdk call? */
462 XChangeProperty(GDK_DISPLAY(), xid,
463 gdk_x11_atom_to_xatom(xdnd_proxy_atom),
464 gdk_x11_atom_to_xatom(gdk_atom_intern("WINDOW",
465 FALSE)),
466 32, PropModeReplace,
467 (guchar *) &proxy_xid, 1);
470 gdk_error_trap_pop();
472 XUngrabServer(GDK_DISPLAY());
473 gdk_flush();
475 if (!proxy)
477 /* Mark our window as a valid proxy window with a XdndProxy
478 * property pointing recursively;
480 XChangeProperty(GDK_DISPLAY(), proxy_xid,
481 gdk_x11_atom_to_xatom(xdnd_proxy_atom),
482 gdk_x11_atom_to_xatom(gdk_atom_intern("WINDOW",
483 FALSE)),
484 32, PropModeReplace,
485 (guchar *) &proxy_xid, 1);
488 return !proxy;
491 /* xid is the window (usually the root) which points to the proxy */
492 void release_xdnd_proxy(guint32 xid)
494 GdkAtom xdnd_proxy_atom;
496 xdnd_proxy_atom = gdk_atom_intern("XdndProxy", FALSE);
498 XDeleteProperty(GDK_DISPLAY(), xid,
499 gdk_x11_atom_to_xatom(xdnd_proxy_atom));
502 /* Looks for the proxy window to get root window clicks from the window
503 * manager. Taken from gmc. NULL if there is no proxy window.
505 GdkWindow *find_click_proxy_window(void)
507 GdkAtom click_proxy_atom;
508 Atom type;
509 int format;
510 unsigned long nitems, after;
511 Window *proxy_data;
512 Window proxy;
513 GdkWindow *proxy_gdk_window;
515 XGrabServer(GDK_DISPLAY());
517 click_proxy_atom = gdk_atom_intern("_WIN_DESKTOP_BUTTON_PROXY", FALSE);
518 type = None;
519 proxy = None;
521 gdk_error_trap_push();
523 /* Check if the proxy window exists */
525 XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
526 gdk_x11_atom_to_xatom(click_proxy_atom), 0,
527 1, False, AnyPropertyType,
528 &type, &format, &nitems, &after,
529 (guchar **) &proxy_data);
531 if (type != None)
533 if (format == 32 && nitems == 1)
534 proxy = *proxy_data;
536 XFree(proxy_data);
539 /* If the property was set, check if the window it points to exists
540 * and has a _WIN_DESKTOP_BUTTON_PROXY property pointing to itself.
543 if (proxy)
545 gint gdk_error_code;
546 XGetWindowProperty(GDK_DISPLAY(), proxy,
547 gdk_x11_atom_to_xatom(click_proxy_atom), 0,
548 1, False, AnyPropertyType,
549 &type, &format, &nitems, &after,
550 (guchar **) &proxy_data);
552 gdk_error_code = gdk_error_trap_pop();
553 gdk_error_trap_push();
555 if (!gdk_error_code && type != None)
557 if (format == 32 && nitems == 1)
558 if (*proxy_data != proxy)
559 proxy = gdk_x11_atom_to_xatom(GDK_NONE);
561 XFree(proxy_data);
563 else
564 proxy = gdk_x11_atom_to_xatom(GDK_NONE);
567 gdk_error_trap_pop();
569 XUngrabServer(GDK_DISPLAY());
570 gdk_flush();
572 if (proxy)
573 proxy_gdk_window = gdk_window_foreign_new(proxy);
574 else
575 proxy_gdk_window = NULL;
577 return proxy_gdk_window;
580 /* Returns the position of the pointer.
581 * TRUE if any modifier keys or mouse buttons are pressed.
583 gboolean get_pointer_xy(int *x, int *y)
585 unsigned int mask;
587 gdk_window_get_pointer(NULL, x, y, &mask);
589 return mask != 0;
592 #define DECOR_BORDER 32
594 /* Centre the window at these coords */
595 void centre_window(GdkWindow *window, int x, int y)
597 int w, h;
599 g_return_if_fail(window != NULL);
601 gdk_drawable_get_size(window, &w, &h);
603 x -= w / 2;
604 y -= h / 2;
606 gdk_window_move(window,
607 CLAMP(x, DECOR_BORDER, screen_width - w - DECOR_BORDER),
608 CLAMP(y, DECOR_BORDER, screen_height - h - DECOR_BORDER));
611 static GtkWidget *current_wink_widget = NULL;
612 static gint wink_timeout = -1; /* Called when it's time to stop */
613 static gulong wink_destroy; /* Called if the widget dies first */
615 static gboolean end_wink(gpointer data)
617 gtk_drag_unhighlight(current_wink_widget);
619 g_signal_handler_disconnect(current_wink_widget, wink_destroy);
621 current_wink_widget = NULL;
623 return FALSE;
626 static void cancel_wink(void)
628 gtk_timeout_remove(wink_timeout);
629 end_wink(NULL);
632 static void wink_widget_died(gpointer data)
634 current_wink_widget = NULL;
635 gtk_timeout_remove(wink_timeout);
638 /* Draw a black box around this widget, briefly.
639 * Note: uses the drag highlighting code for now.
641 void wink_widget(GtkWidget *widget)
643 g_return_if_fail(widget != NULL);
645 if (current_wink_widget)
646 cancel_wink();
648 current_wink_widget = widget;
649 gtk_drag_highlight(current_wink_widget);
651 wink_timeout = gtk_timeout_add(300, (GtkFunction) end_wink, NULL);
653 wink_destroy = g_signal_connect_swapped(widget, "destroy",
654 G_CALLBACK(wink_widget_died), NULL);
657 static gboolean idle_destroy_cb(GtkWidget *widget)
659 gtk_widget_unref(widget);
660 gtk_widget_destroy(widget);
661 return FALSE;
664 /* Destroy the widget in an idle callback */
665 void destroy_on_idle(GtkWidget *widget)
667 gtk_widget_ref(widget);
668 gtk_idle_add((GtkFunction) idle_destroy_cb, widget);
671 /* Spawn a child process (as spawn_full), and report errors.
672 * TRUE on success.
674 gboolean rox_spawn(const gchar *dir, const gchar **argv)
676 GError *error = NULL;
678 if (!g_spawn_async_with_pipes(dir, (gchar **) argv, NULL,
679 G_SPAWN_DO_NOT_REAP_CHILD |
680 G_SPAWN_SEARCH_PATH,
681 NULL, NULL, /* Child setup fn */
682 NULL, /* Child PID */
683 NULL, NULL, NULL, /* Standard pipes */
684 &error))
686 delayed_error("%s", error ? error->message : "(null)");
687 g_error_free(error);
689 return FALSE;
692 return TRUE;
695 GtkWidget *button_new_mixed(const char *stock, const char *message)
697 GtkWidget *button, *align, *image, *hbox, *label;
699 button = gtk_button_new();
700 label = gtk_label_new_with_mnemonic(message);
701 gtk_label_set_mnemonic_widget(GTK_LABEL(label), button);
703 image = gtk_image_new_from_stock(stock, GTK_ICON_SIZE_BUTTON);
704 hbox = gtk_hbox_new(FALSE, 2);
706 align = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
708 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
709 gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0);
711 gtk_container_add(GTK_CONTAINER(button), align);
712 gtk_container_add(GTK_CONTAINER(align), hbox);
713 gtk_widget_show_all(align);
715 return button;
718 /* Highlight entry in red if 'error' is TRUE */
719 void entry_set_error(GtkWidget *entry, gboolean error)
721 GdkColor red = {0, 0xffff, 0, 0};
722 static gboolean need_init = TRUE;
723 static GdkColor normal;
725 if (need_init)
727 normal = entry->style->text[GTK_STATE_NORMAL];
728 need_init = FALSE;
731 gtk_widget_modify_text(entry, GTK_STATE_NORMAL, error ? &red : &normal);
734 /* Change stacking position of higher to be just above lower */
735 void window_put_just_above(GdkWindow *higher, GdkWindow *lower)
737 if (override_redirect && lower)
739 XWindowChanges restack;
740 Window root, parent, w;
741 Window *children;
742 int nchildren;
744 gdk_error_trap_push();
746 restack.stack_mode = Above;
748 /* From gdk */
749 parent = GDK_WINDOW_XWINDOW(lower);
752 w = parent;
754 XQueryTree(gdk_display, w,
755 &root, &parent, &children, &nchildren);
756 if (children)
757 XFree(children);
759 while (parent != root);
761 restack.sibling = w;
763 parent = GDK_WINDOW_XWINDOW(higher);
766 w = parent;
768 XQueryTree(gdk_display, w,
769 &root, &parent, &children, &nchildren);
770 if (children)
771 XFree(children);
773 while (parent != root);
775 XConfigureWindow(gdk_display, w,
776 CWSibling | CWStackMode, &restack);
778 gdk_flush();
779 if (gdk_error_trap_pop())
780 g_warning("window_put_just_above()\n");
782 else
783 gdk_window_lower(higher); /* To bottom of stack */
786 /* Copied from Gtk */
787 static GtkFixedChild* fixed_get_child(GtkFixed *fixed, GtkWidget *widget)
789 GList *children;
791 children = fixed->children;
792 while (children)
794 GtkFixedChild *child;
796 child = children->data;
797 children = children->next;
799 if (child->widget == widget)
800 return child;
803 return NULL;
806 /* Like gtk_fixed_move(), except not insanely slow */
807 void fixed_move_fast(GtkFixed *fixed, GtkWidget *widget, int x, int y)
809 GtkFixedChild *child;
811 child = fixed_get_child(fixed, widget);
813 g_assert(child);
815 gtk_widget_freeze_child_notify(widget);
817 child->x = x;
818 gtk_widget_child_notify(widget, "x");
820 child->y = y;
821 gtk_widget_child_notify(widget, "y");
823 gtk_widget_thaw_child_notify(widget);
825 if (GTK_WIDGET_VISIBLE(widget) && GTK_WIDGET_VISIBLE(fixed))
827 int border_width = GTK_CONTAINER(fixed)->border_width;
828 GtkAllocation child_allocation;
829 GtkRequisition child_requisition;
831 gtk_widget_get_child_requisition(child->widget,
832 &child_requisition);
833 child_allocation.x = child->x + border_width;
834 child_allocation.y = child->y + border_width;
836 child_allocation.x += GTK_WIDGET(fixed)->allocation.x;
837 child_allocation.y += GTK_WIDGET(fixed)->allocation.y;
839 child_allocation.width = child_requisition.width;
840 child_allocation.height = child_requisition.height;
841 gtk_widget_size_allocate(child->widget, &child_allocation);