From 9df007468539fa9fe85612eedf0af44dd64f3c98 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 29 Aug 2001 02:20:02 +0000 Subject: [PATCH] add default icon 2001-08-28 Havoc Pennington * demos/gtk-demo/main.c (setup_default_icon): add default icon * gtk/gtkradiobutton.c (gtk_radio_button_new_with_mnemonic): warning fix (gtk_radio_button_new_with_label): warning fix * gtk/gtkdnd.c: used some random GtkImage private structs, update to reflect GtkImage changes * gdk/x11/gdkwindow-x11.c (gdk_window_set_icon_list): don't check whether the hint is supported, just always set the icon. A task list might want to use it even if the WM doesn't, and the WM may change over time. Also, XDeleteProperty() if list == NULL. * gtk/gtkwindow.c (gtk_window_set_icon_list) (gtk_window_get_icon_list) (gtk_window_set_icon) (gtk_window_get_icon) (gtk_window_set_default_icon_list) (gtk_window_get_default_icon_list): new functions * gtk/gtk-boxed.defs (GtkIconSet): add GtkIconSet * gtk/gtkimage.c: Implement property support, bug #59408 * gtk/gtkcontainer.c (gtk_container_add): make the warning message on reparent-without-removing-first a bit more helpful. Let's just destroy this FAQ. --- ChangeLog | 32 + ChangeLog.pre-2-0 | 32 + ChangeLog.pre-2-10 | 32 + ChangeLog.pre-2-2 | 32 + ChangeLog.pre-2-4 | 32 + ChangeLog.pre-2-6 | 32 + ChangeLog.pre-2-8 | 32 + demos/gtk-demo/main.c | 54 ++ docs/reference/gdk/tmpl/windows.sgml | 1 + docs/reference/gtk/tmpl/gtk-unused.sgml | 14 + docs/reference/gtk/tmpl/gtkbutton.sgml | 10 + docs/reference/gtk/tmpl/gtkimage.sgml | 50 ++ docs/reference/gtk/tmpl/gtkmenubar.sgml | 5 +- docs/reference/gtk/tmpl/gtkmenuitem.sgml | 2 +- docs/reference/gtk/tmpl/gtktreeselection.sgml | 8 - docs/reference/gtk/tmpl/gtkwindow.sgml | 5 + gdk/gdkwindow.h | 2 +- gdk/x11/gdkwindow-x11.c | 38 +- gtk/gtk-boxed.defs | 5 + gtk/gtkcontainer.c | 3 +- gtk/gtkdnd.c | 9 +- gtk/gtkimage.c | 433 ++++++++++++-- gtk/gtkimage.h | 10 +- gtk/gtkradiobutton.c | 4 +- gtk/gtkwindow.c | 552 +++++++++++++++++- gtk/gtkwindow.h | 9 + 26 files changed, 1352 insertions(+), 86 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4852923f9..fc414261b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +2001-08-28 Havoc Pennington + + * demos/gtk-demo/main.c (setup_default_icon): add default icon + + * gtk/gtkradiobutton.c (gtk_radio_button_new_with_mnemonic): + warning fix + (gtk_radio_button_new_with_label): warning fix + + * gtk/gtkdnd.c: used some random GtkImage private structs, + update to reflect GtkImage changes + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_icon_list): don't check + whether the hint is supported, just always set the icon. A task + list might want to use it even if the WM doesn't, and the WM may + change over time. Also, XDeleteProperty() if list == NULL. + + * gtk/gtkwindow.c (gtk_window_set_icon_list) + (gtk_window_get_icon_list) + (gtk_window_set_icon) + (gtk_window_get_icon) + (gtk_window_set_default_icon_list) + (gtk_window_get_default_icon_list): + new functions + + * gtk/gtk-boxed.defs (GtkIconSet): add GtkIconSet + + * gtk/gtkimage.c: Implement property support, bug #59408 + + * gtk/gtkcontainer.c (gtk_container_add): make the warning message + on reparent-without-removing-first a bit more helpful. + Let's just destroy this FAQ. + Tue Aug 28 21:37:11 2001 Matthias Clasen * demos/gtk-demo/appwindow.c (do_appwindow): Use g_signal_connect_object diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 4852923f9..fc414261b 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,35 @@ +2001-08-28 Havoc Pennington + + * demos/gtk-demo/main.c (setup_default_icon): add default icon + + * gtk/gtkradiobutton.c (gtk_radio_button_new_with_mnemonic): + warning fix + (gtk_radio_button_new_with_label): warning fix + + * gtk/gtkdnd.c: used some random GtkImage private structs, + update to reflect GtkImage changes + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_icon_list): don't check + whether the hint is supported, just always set the icon. A task + list might want to use it even if the WM doesn't, and the WM may + change over time. Also, XDeleteProperty() if list == NULL. + + * gtk/gtkwindow.c (gtk_window_set_icon_list) + (gtk_window_get_icon_list) + (gtk_window_set_icon) + (gtk_window_get_icon) + (gtk_window_set_default_icon_list) + (gtk_window_get_default_icon_list): + new functions + + * gtk/gtk-boxed.defs (GtkIconSet): add GtkIconSet + + * gtk/gtkimage.c: Implement property support, bug #59408 + + * gtk/gtkcontainer.c (gtk_container_add): make the warning message + on reparent-without-removing-first a bit more helpful. + Let's just destroy this FAQ. + Tue Aug 28 21:37:11 2001 Matthias Clasen * demos/gtk-demo/appwindow.c (do_appwindow): Use g_signal_connect_object diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 4852923f9..fc414261b 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,35 @@ +2001-08-28 Havoc Pennington + + * demos/gtk-demo/main.c (setup_default_icon): add default icon + + * gtk/gtkradiobutton.c (gtk_radio_button_new_with_mnemonic): + warning fix + (gtk_radio_button_new_with_label): warning fix + + * gtk/gtkdnd.c: used some random GtkImage private structs, + update to reflect GtkImage changes + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_icon_list): don't check + whether the hint is supported, just always set the icon. A task + list might want to use it even if the WM doesn't, and the WM may + change over time. Also, XDeleteProperty() if list == NULL. + + * gtk/gtkwindow.c (gtk_window_set_icon_list) + (gtk_window_get_icon_list) + (gtk_window_set_icon) + (gtk_window_get_icon) + (gtk_window_set_default_icon_list) + (gtk_window_get_default_icon_list): + new functions + + * gtk/gtk-boxed.defs (GtkIconSet): add GtkIconSet + + * gtk/gtkimage.c: Implement property support, bug #59408 + + * gtk/gtkcontainer.c (gtk_container_add): make the warning message + on reparent-without-removing-first a bit more helpful. + Let's just destroy this FAQ. + Tue Aug 28 21:37:11 2001 Matthias Clasen * demos/gtk-demo/appwindow.c (do_appwindow): Use g_signal_connect_object diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 4852923f9..fc414261b 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,35 @@ +2001-08-28 Havoc Pennington + + * demos/gtk-demo/main.c (setup_default_icon): add default icon + + * gtk/gtkradiobutton.c (gtk_radio_button_new_with_mnemonic): + warning fix + (gtk_radio_button_new_with_label): warning fix + + * gtk/gtkdnd.c: used some random GtkImage private structs, + update to reflect GtkImage changes + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_icon_list): don't check + whether the hint is supported, just always set the icon. A task + list might want to use it even if the WM doesn't, and the WM may + change over time. Also, XDeleteProperty() if list == NULL. + + * gtk/gtkwindow.c (gtk_window_set_icon_list) + (gtk_window_get_icon_list) + (gtk_window_set_icon) + (gtk_window_get_icon) + (gtk_window_set_default_icon_list) + (gtk_window_get_default_icon_list): + new functions + + * gtk/gtk-boxed.defs (GtkIconSet): add GtkIconSet + + * gtk/gtkimage.c: Implement property support, bug #59408 + + * gtk/gtkcontainer.c (gtk_container_add): make the warning message + on reparent-without-removing-first a bit more helpful. + Let's just destroy this FAQ. + Tue Aug 28 21:37:11 2001 Matthias Clasen * demos/gtk-demo/appwindow.c (do_appwindow): Use g_signal_connect_object diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 4852923f9..fc414261b 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,35 @@ +2001-08-28 Havoc Pennington + + * demos/gtk-demo/main.c (setup_default_icon): add default icon + + * gtk/gtkradiobutton.c (gtk_radio_button_new_with_mnemonic): + warning fix + (gtk_radio_button_new_with_label): warning fix + + * gtk/gtkdnd.c: used some random GtkImage private structs, + update to reflect GtkImage changes + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_icon_list): don't check + whether the hint is supported, just always set the icon. A task + list might want to use it even if the WM doesn't, and the WM may + change over time. Also, XDeleteProperty() if list == NULL. + + * gtk/gtkwindow.c (gtk_window_set_icon_list) + (gtk_window_get_icon_list) + (gtk_window_set_icon) + (gtk_window_get_icon) + (gtk_window_set_default_icon_list) + (gtk_window_get_default_icon_list): + new functions + + * gtk/gtk-boxed.defs (GtkIconSet): add GtkIconSet + + * gtk/gtkimage.c: Implement property support, bug #59408 + + * gtk/gtkcontainer.c (gtk_container_add): make the warning message + on reparent-without-removing-first a bit more helpful. + Let's just destroy this FAQ. + Tue Aug 28 21:37:11 2001 Matthias Clasen * demos/gtk-demo/appwindow.c (do_appwindow): Use g_signal_connect_object diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 4852923f9..fc414261b 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,35 @@ +2001-08-28 Havoc Pennington + + * demos/gtk-demo/main.c (setup_default_icon): add default icon + + * gtk/gtkradiobutton.c (gtk_radio_button_new_with_mnemonic): + warning fix + (gtk_radio_button_new_with_label): warning fix + + * gtk/gtkdnd.c: used some random GtkImage private structs, + update to reflect GtkImage changes + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_icon_list): don't check + whether the hint is supported, just always set the icon. A task + list might want to use it even if the WM doesn't, and the WM may + change over time. Also, XDeleteProperty() if list == NULL. + + * gtk/gtkwindow.c (gtk_window_set_icon_list) + (gtk_window_get_icon_list) + (gtk_window_set_icon) + (gtk_window_get_icon) + (gtk_window_set_default_icon_list) + (gtk_window_get_default_icon_list): + new functions + + * gtk/gtk-boxed.defs (GtkIconSet): add GtkIconSet + + * gtk/gtkimage.c: Implement property support, bug #59408 + + * gtk/gtkcontainer.c (gtk_container_add): make the warning message + on reparent-without-removing-first a bit more helpful. + Let's just destroy this FAQ. + Tue Aug 28 21:37:11 2001 Matthias Clasen * demos/gtk-demo/appwindow.c (do_appwindow): Use g_signal_connect_object diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 4852923f9..fc414261b 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,35 @@ +2001-08-28 Havoc Pennington + + * demos/gtk-demo/main.c (setup_default_icon): add default icon + + * gtk/gtkradiobutton.c (gtk_radio_button_new_with_mnemonic): + warning fix + (gtk_radio_button_new_with_label): warning fix + + * gtk/gtkdnd.c: used some random GtkImage private structs, + update to reflect GtkImage changes + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_icon_list): don't check + whether the hint is supported, just always set the icon. A task + list might want to use it even if the WM doesn't, and the WM may + change over time. Also, XDeleteProperty() if list == NULL. + + * gtk/gtkwindow.c (gtk_window_set_icon_list) + (gtk_window_get_icon_list) + (gtk_window_set_icon) + (gtk_window_get_icon) + (gtk_window_set_default_icon_list) + (gtk_window_get_default_icon_list): + new functions + + * gtk/gtk-boxed.defs (GtkIconSet): add GtkIconSet + + * gtk/gtkimage.c: Implement property support, bug #59408 + + * gtk/gtkcontainer.c (gtk_container_add): make the warning message + on reparent-without-removing-first a bit more helpful. + Let's just destroy this FAQ. + Tue Aug 28 21:37:11 2001 Matthias Clasen * demos/gtk-demo/appwindow.c (do_appwindow): Use g_signal_connect_object diff --git a/demos/gtk-demo/main.c b/demos/gtk-demo/main.c index bea2c29a7..954795e23 100644 --- a/demos/gtk-demo/main.c +++ b/demos/gtk-demo/main.c @@ -722,6 +722,58 @@ create_tree (void) return tree_view; } +static void +setup_default_icon (void) +{ + GdkPixbuf *pixbuf; + + /* Try in current directory, in case we haven't yet been installed + * (would be wrong in a real app) + */ + pixbuf = gdk_pixbuf_new_from_file ("./gtk-logo-rgb.gif", NULL); + + if (pixbuf == NULL) + { + GError *err; + + err = NULL; + pixbuf = gdk_pixbuf_new_from_file (DEMOCODEDIR"/gtk-logo-rgb.gif", + &err); + + /* Ignoring this error (passing NULL instead of &err above) + * would probably be reasonable for most apps. We're just + * showing off. + */ + if (err) + { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, 0, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "Failed to read icon file "DEMOCODEDIR"/gtk-logo-rgb.gif: %s", + err->message); + g_error_free (err); + + gtk_signal_connect (GTK_OBJECT (dialog), + "response", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + NULL); + } + } + + if (pixbuf) + { + GList *list; + + list = NULL; + list = g_list_append (list, pixbuf); + gtk_window_set_default_icon_list (list); + g_list_free (list); + g_object_unref (G_OBJECT (pixbuf)); + } +} + int main (int argc, char **argv) { @@ -744,6 +796,8 @@ main (int argc, char **argv) /* -- End of hack -- */ gtk_init (&argc, &argv); + + setup_default_icon (); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "GTK+ Code Demos"); diff --git a/docs/reference/gdk/tmpl/windows.sgml b/docs/reference/gdk/tmpl/windows.sgml index c21b8f46f..6ea5f66ef 100644 --- a/docs/reference/gdk/tmpl/windows.sgml +++ b/docs/reference/gdk/tmpl/windows.sgml @@ -793,6 +793,7 @@ Windows @window: @pixbufs: + @Returns: diff --git a/docs/reference/gtk/tmpl/gtk-unused.sgml b/docs/reference/gtk/tmpl/gtk-unused.sgml index 884d5f890..ac2f00a2e 100644 --- a/docs/reference/gtk/tmpl/gtk-unused.sgml +++ b/docs/reference/gtk/tmpl/gtk-unused.sgml @@ -953,6 +953,14 @@ produce superscript and subscript. + + + + + +@GTK_TREE_SELECTION_SINGLE: +@GTK_TREE_SELECTION_MULTI: + the #GtkAdjustment which sets the range of the scale. @@ -1034,6 +1042,12 @@ If the window shrinks automatically when widgets within it shrink. + + + + + + It will either copy data into an existing argument or allocate a new argument diff --git a/docs/reference/gtk/tmpl/gtkbutton.sgml b/docs/reference/gtk/tmpl/gtkbutton.sgml index c182e2bff..b7609bf4b 100644 --- a/docs/reference/gtk/tmpl/gtkbutton.sgml +++ b/docs/reference/gtk/tmpl/gtkbutton.sgml @@ -181,3 +181,13 @@ there is actually a #GtkLabel inside of the #GtkButton. The #GtkReliefStyle as outlined in gtk_button_set_relief(). + + + + + + + + + + diff --git a/docs/reference/gtk/tmpl/gtkimage.sgml b/docs/reference/gtk/tmpl/gtkimage.sgml index 4b9efb9cf..7c9a6e400 100644 --- a/docs/reference/gtk/tmpl/gtkimage.sgml +++ b/docs/reference/gtk/tmpl/gtkimage.sgml @@ -278,3 +278,53 @@ Gets the GtkImage @mask: a GDKBitmap that indicates which parts of the image should be transparent. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/reference/gtk/tmpl/gtkmenubar.sgml b/docs/reference/gtk/tmpl/gtkmenubar.sgml index 0eb6db21f..3b22a5872 100644 --- a/docs/reference/gtk/tmpl/gtkmenubar.sgml +++ b/docs/reference/gtk/tmpl/gtkmenubar.sgml @@ -44,10 +44,11 @@ Adds a new #GtkMenuItem to the end of the GtkMenuBar Adds a new #GtkMenuItem to the beginning of the GtkMenuBar -@menu_child: +@menu: +@child: the #GtkMenuItem to add +@menu_child: @menu_bar: a #GtkMenuBar -@child: the #GtkMenuItem to add diff --git a/docs/reference/gtk/tmpl/gtkmenuitem.sgml b/docs/reference/gtk/tmpl/gtkmenuitem.sgml index 48d372e68..a937734e6 100644 --- a/docs/reference/gtk/tmpl/gtkmenuitem.sgml +++ b/docs/reference/gtk/tmpl/gtkmenuitem.sgml @@ -131,7 +131,7 @@ Emits the "activate" signal on the given item @allocation: - + Sets the menu item to be right-justified. Only useful for menu bars. diff --git a/docs/reference/gtk/tmpl/gtktreeselection.sgml b/docs/reference/gtk/tmpl/gtktreeselection.sgml index 7769ab1a5..e3108cd12 100644 --- a/docs/reference/gtk/tmpl/gtktreeselection.sgml +++ b/docs/reference/gtk/tmpl/gtktreeselection.sgml @@ -14,14 +14,6 @@ GtkTreeSelection - - - - - -@GTK_TREE_SELECTION_SINGLE: -@GTK_TREE_SELECTION_MULTI: - diff --git a/docs/reference/gtk/tmpl/gtkwindow.sgml b/docs/reference/gtk/tmpl/gtkwindow.sgml index 3fb16a1c6..b601a6e9b 100644 --- a/docs/reference/gtk/tmpl/gtkwindow.sgml +++ b/docs/reference/gtk/tmpl/gtkwindow.sgml @@ -549,3 +549,8 @@ The position of the window. + + + + + diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index e6f6bf5a7..75a83fe4d 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -444,7 +444,7 @@ GdkEventMask gdk_window_get_events (GdkWindow *window); void gdk_window_set_events (GdkWindow *window, GdkEventMask event_mask); -gboolean gdk_window_set_icon_list (GdkWindow *window, +void gdk_window_set_icon_list (GdkWindow *window, GList *pixbufs); void gdk_window_set_icon (GdkWindow *window, GdkWindow *icon_window, diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index 169cdb3a1..60e936241 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -2325,7 +2325,6 @@ gdk_window_set_override_redirect (GdkWindow *window, * gdk_window_set_icon_list: * @window: The #GdkWindow toplevel window to set the icon of. * @pixbufs: A list of pixbufs, of different sizes. - * @Returns: %TRUE if the icons were set, false otherwise * * Sets a list of icons for the window. One of these will be used * to represent the window when it has been iconified. The icon is @@ -2335,12 +2334,8 @@ gdk_window_set_override_redirect (GdkWindow *window, * image quality since the window manager may only need to scale the * icon by a small amount or not at all. * - * On the X11 backend this call might fail if the window manager - * doesn't support the Extended Window Manager Hints. Then this - * function returns FALSE, and the application should fall back - * to #gdk_window_set_icon(). **/ -gboolean +void gdk_window_set_icon_list (GdkWindow *window, GList *pixbufs) { @@ -2354,14 +2349,10 @@ gdk_window_set_icon_list (GdkWindow *window, gint x, y; gint n_channels; - g_return_val_if_fail (window != NULL, FALSE); - g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + g_return_if_fail (GDK_IS_WINDOW (window)); if (GDK_WINDOW_DESTROYED (window)) - return FALSE; - - if (!gdk_net_wm_supports (gdk_atom_intern ("_NET_WM_ICON", FALSE))) - return FALSE; + return; l = pixbufs; size = 0; @@ -2418,14 +2409,21 @@ gdk_window_set_icon_list (GdkWindow *window, l = g_list_next (l); } - XChangeProperty (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), - gdk_atom_intern ("_NET_WM_ICON", FALSE), - XA_CARDINAL, 32, - PropModeReplace, - (guchar*) data, size); - - return TRUE; + if (size > 0) + { + XChangeProperty (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + gdk_atom_intern ("_NET_WM_ICON", FALSE), + XA_CARDINAL, 32, + PropModeReplace, + (guchar*) data, size); + } + else + { + XDeleteProperty (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + gdk_atom_intern ("_NET_WM_ICON", FALSE)); + } } void diff --git a/gtk/gtk-boxed.defs b/gtk/gtk-boxed.defs index b702db10d..1f1a997b5 100644 --- a/gtk/gtk-boxed.defs +++ b/gtk/gtk-boxed.defs @@ -23,6 +23,11 @@ gtk_requisition_free "sizeof(GtkRequisition)") +(define-boxed GtkIconSet + gtk_icon_set_ref + gtk_icon_set_unref + "sizeof(GtkIconSet)") + ;; TextView (define-boxed GtkTextIter diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index ccda2e663..b9e35d47d 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -858,7 +858,8 @@ gtk_container_add (GtkContainer *container, if (widget->parent != NULL) { g_warning ("Attempting to add a widget with type %s to a container of " - "type %s, but the widget is already inside a container of type %s", + "type %s, but the widget is already inside a container of type %s, " + "the GTK+ FAQ at http://www.gtk.org/faq/ explains how to reparent a widget.", g_type_name (G_OBJECT_TYPE (widget)), g_type_name (G_OBJECT_TYPE (container)), g_type_name (G_OBJECT_TYPE (widget->parent))); diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c index cd3f14cb1..d78688cc0 100644 --- a/gtk/gtkdnd.c +++ b/gtk/gtkdnd.c @@ -78,6 +78,7 @@ struct _GtkDragSourceSite GtkImagePixbufData pixbuf; GtkImageStockData stock; } icon_data; + GdkBitmap *icon_mask; GdkColormap *colormap; /* Colormap for drag icon */ @@ -1941,8 +1942,8 @@ gtk_drag_source_unset_icon (GtkDragSourceSite *site) case GTK_IMAGE_PIXMAP: if (site->icon_data.pixmap.pixmap) gdk_pixmap_unref (site->icon_data.pixmap.pixmap); - if (site->icon_data.pixmap.mask) - gdk_pixmap_unref (site->icon_data.pixmap.mask); + if (site->icon_mask) + gdk_pixmap_unref (site->icon_mask); break; case GTK_IMAGE_PIXBUF: g_object_unref (G_OBJECT (site->icon_data.pixbuf.pixbuf)); @@ -1999,7 +2000,7 @@ gtk_drag_source_set_icon (GtkWidget *widget, site->icon_type = GTK_IMAGE_PIXMAP; site->icon_data.pixmap.pixmap = pixmap; - site->icon_data.pixmap.mask = mask; + site->icon_mask = mask; site->colormap = colormap; } @@ -2683,7 +2684,7 @@ gtk_drag_source_event_cb (GtkWidget *widget, gtk_drag_set_icon_pixmap (context, site->colormap, site->icon_data.pixmap.pixmap, - site->icon_data.pixmap.mask, + site->icon_mask, -2, -2); break; case GTK_IMAGE_PIXBUF: diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c index 509d569c5..bef35eccb 100644 --- a/gtk/gtkimage.c +++ b/gtk/gtkimage.c @@ -28,8 +28,11 @@ #include "gtkimage.h" #include "gtkiconfactory.h" #include "gtkstock.h" +#include "gtkintl.h" #include +#define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON + static void gtk_image_class_init (GtkImageClass *klass); static void gtk_image_init (GtkImage *image); static gint gtk_image_expose (GtkWidget *widget, @@ -44,8 +47,32 @@ static void gtk_image_update_size (GtkImage *image, gint image_width, gint image_height); +static void gtk_image_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_image_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + static gpointer parent_class; +enum +{ + PROP_0, + PROP_PIXBUF, + PROP_PIXMAP, + PROP_IMAGE, + PROP_MASK, + PROP_FILE, + PROP_STOCK, + PROP_ICON_SET, + PROP_ICON_SIZE, + PROP_PIXBUF_ANIMATION, + PROP_STORAGE_TYPE +}; + GtkType gtk_image_get_type (void) { @@ -74,20 +101,109 @@ gtk_image_get_type (void) static void gtk_image_class_init (GtkImageClass *class) { + GObjectClass *gobject_class; GtkObjectClass *object_class; GtkWidgetClass *widget_class; parent_class = g_type_class_peek_parent (class); - object_class = (GtkObjectClass *) class; + gobject_class = G_OBJECT_CLASS (class); + + gobject_class->set_property = gtk_image_set_property; + gobject_class->get_property = gtk_image_get_property; + + object_class = GTK_OBJECT_CLASS (class); object_class->destroy = gtk_image_destroy; - widget_class = (GtkWidgetClass*) class; - + widget_class = GTK_WIDGET_CLASS (class); + widget_class->expose_event = gtk_image_expose; widget_class->size_request = gtk_image_size_request; widget_class->unmap = gtk_image_unmap; + + g_object_class_install_property (gobject_class, + PROP_PIXBUF, + g_param_spec_object ("pixbuf", + _("Pixbuf"), + _("A GdkPixbuf to display."), + GDK_TYPE_PIXBUF, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_PIXMAP, + g_param_spec_object ("pixmap", + _("Pixmap"), + _("A GdkPixmap to display."), + GDK_TYPE_PIXMAP, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_IMAGE, + g_param_spec_object ("image", + _("Image"), + _("A GdkImage to display."), + GDK_TYPE_IMAGE, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_MASK, + g_param_spec_object ("mask", + _("Mask"), + _("Mask bitmap to use with GdkImage or GdkPixmap"), + GDK_TYPE_PIXMAP, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_FILE, + g_param_spec_string ("file", + _("Filename"), + _("Filename to load and siplay."), + NULL, + G_PARAM_WRITABLE)); + + + g_object_class_install_property (gobject_class, + PROP_STOCK, + g_param_spec_string ("stock", + _("Stock ID"), + _("Stock ID for a stock image to display."), + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_ICON_SET, + g_param_spec_boxed ("icon_set", + _("Icon set"), + _("Icon set to display."), + GTK_TYPE_ICON_SET, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_ICON_SIZE, + g_param_spec_int ("icon_size", + _("Icon size"), + _("Size to use for stock icon or icon set."), + 0, G_MAXINT, + DEFAULT_ICON_SIZE, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_PIXBUF_ANIMATION, + g_param_spec_object ("pixbuf_animation", + _("Animation"), + _("GdkPixbufAnimation to display."), + GDK_TYPE_PIXBUF_ANIMATION, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_STORAGE_TYPE, + g_param_spec_enum ("storage_type", + _("Storage type"), + _("The representation being used for image data."), + GTK_TYPE_IMAGE_TYPE, + GTK_IMAGE_EMPTY, + G_PARAM_READABLE)); } static void @@ -96,6 +212,8 @@ gtk_image_init (GtkImage *image) GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW); image->storage_type = GTK_IMAGE_EMPTY; + image->icon_size = DEFAULT_ICON_SIZE; + image->mask = NULL; } static void @@ -108,6 +226,167 @@ gtk_image_destroy (GtkObject *object) GTK_OBJECT_CLASS (parent_class)->destroy (object); } +static void +gtk_image_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkImage *image; + + image = GTK_IMAGE (object); + + switch (prop_id) + { + case PROP_PIXBUF: + gtk_image_set_from_pixbuf (image, + g_value_get_object (value)); + break; + case PROP_PIXMAP: + gtk_image_set_from_pixmap (image, + g_value_get_object (value), + image->mask); + break; + case PROP_IMAGE: + gtk_image_set_from_image (image, + g_value_get_object (value), + image->mask); + break; + case PROP_MASK: + if (image->storage_type == GTK_IMAGE_PIXMAP) + gtk_image_set_from_pixmap (image, + image->data.pixmap.pixmap, + g_value_get_object (value)); + else if (image->storage_type == GTK_IMAGE_IMAGE) + gtk_image_set_from_image (image, + image->data.image.image, + g_value_get_object (value)); + else + { + GdkBitmap *mask; + + mask = g_value_get_object (value); + + if (mask) + g_object_ref (G_OBJECT (mask)); + + gtk_image_reset (image); + + image->mask = mask; + } + break; + case PROP_FILE: + gtk_image_set_from_file (image, + g_value_get_string (value)); + break; + case PROP_STOCK: + gtk_image_set_from_stock (image, g_value_get_string (value), + image->icon_size); + break; + case PROP_ICON_SET: + gtk_image_set_from_icon_set (image, g_value_get_boxed (value), + image->icon_size); + break; + case PROP_ICON_SIZE: + if (image->storage_type == GTK_IMAGE_STOCK) + gtk_image_set_from_stock (image, + image->data.stock.stock_id, + g_value_get_int (value)); + else if (image->storage_type == GTK_IMAGE_ICON_SET) + gtk_image_set_from_icon_set (image, + image->data.icon_set.icon_set, + g_value_get_int (value)); + else + /* Save to be used when STOCK or ICON_SET property comes in */ + image->icon_size = g_value_get_int (value); + break; + case PROP_PIXBUF_ANIMATION: + gtk_image_set_from_animation (image, + g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_image_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkImage *image; + + image = GTK_IMAGE (object); + + /* The "getter" functions whine if you try to get the wrong + * storage type. This function is instead robust against that, + * so that GUI builders don't have to jump through hoops + * to avoid g_warning + */ + + switch (prop_id) + { + case PROP_PIXBUF: + if (image->storage_type != GTK_IMAGE_PIXBUF) + g_value_set_object (value, NULL); + else + g_value_set_object (value, + gtk_image_get_pixbuf (image)); + break; + case PROP_PIXMAP: + if (image->storage_type != GTK_IMAGE_PIXMAP) + g_value_set_object (value, NULL); + else + g_value_set_object (value, + image->data.pixmap.pixmap); + break; + case PROP_MASK: + g_value_set_object (value, image->mask); + break; + case PROP_IMAGE: + if (image->storage_type != GTK_IMAGE_IMAGE) + g_value_set_object (value, NULL); + else + g_value_set_object (value, + image->data.image.image); + break; + case PROP_STOCK: + if (image->storage_type != GTK_IMAGE_STOCK) + g_value_set_string (value, NULL); + else + g_value_set_string (value, + image->data.stock.stock_id); + break; + case PROP_ICON_SET: + if (image->storage_type != GTK_IMAGE_ICON_SET) + g_value_set_boxed (value, NULL); + else + g_value_set_boxed (value, + image->data.icon_set.icon_set); + break; + case PROP_ICON_SIZE: + g_value_set_int (value, image->icon_size); + break; + case PROP_PIXBUF_ANIMATION: + if (image->storage_type != GTK_IMAGE_ANIMATION) + g_value_set_object (value, NULL); + else + g_value_set_object (value, + image->data.anim.anim); + break; + case PROP_STORAGE_TYPE: + g_value_set_enum (value, image->storage_type); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + /** * gtk_image_new_from_pixmap: @@ -328,6 +607,8 @@ gtk_image_set_from_pixmap (GtkImage *image, GDK_IS_PIXMAP (pixmap)); g_return_if_fail (mask == NULL || GDK_IS_PIXMAP (mask)); + + g_object_freeze_notify (G_OBJECT (image)); if (pixmap) g_object_ref (G_OBJECT (pixmap)); @@ -337,6 +618,8 @@ gtk_image_set_from_pixmap (GtkImage *image, gtk_image_reset (image); + image->mask = mask; + if (pixmap) { int width; @@ -345,18 +628,16 @@ gtk_image_set_from_pixmap (GtkImage *image, image->storage_type = GTK_IMAGE_PIXMAP; image->data.pixmap.pixmap = pixmap; - image->data.pixmap.mask = mask; gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height); gtk_image_update_size (image, width, height); } - else - { - /* Clean up the mask if pixmap was NULL */ - if (mask) - g_object_unref (G_OBJECT (mask)); - } + + g_object_notify (G_OBJECT (image), "pixmap"); + g_object_notify (G_OBJECT (image), "mask"); + + g_object_thaw_notify (G_OBJECT (image)); } /** @@ -379,6 +660,7 @@ gtk_image_set_from_image (GtkImage *image, g_return_if_fail (mask == NULL || GDK_IS_PIXMAP (mask)); + g_object_freeze_notify (G_OBJECT (image)); if (gdk_image) g_object_ref (G_OBJECT (gdk_image)); @@ -393,7 +675,7 @@ gtk_image_set_from_image (GtkImage *image, image->storage_type = GTK_IMAGE_IMAGE; image->data.image.image = gdk_image; - image->data.image.mask = mask; + image->mask = mask; gtk_image_update_size (image, gdk_image->width, gdk_image->height); } @@ -403,6 +685,11 @@ gtk_image_set_from_image (GtkImage *image, if (mask) g_object_unref (G_OBJECT (mask)); } + + g_object_notify (G_OBJECT (image), "image"); + g_object_notify (G_OBJECT (image), "mask"); + + g_object_thaw_notify (G_OBJECT (image)); } /** @@ -421,11 +708,16 @@ gtk_image_set_from_file (GtkImage *image, g_return_if_fail (GTK_IS_IMAGE (image)); g_return_if_fail (filename != NULL); + + g_object_freeze_notify (G_OBJECT (image)); gtk_image_reset (image); if (filename == NULL) - return; + { + g_object_thaw_notify (G_OBJECT (image)); + return; + } anim = gdk_pixbuf_animation_new_from_file (filename, NULL); @@ -434,6 +726,7 @@ gtk_image_set_from_file (GtkImage *image, gtk_image_set_from_stock (image, GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_BUTTON); + g_object_thaw_notify (G_OBJECT (image)); return; } @@ -453,6 +746,8 @@ gtk_image_set_from_file (GtkImage *image, } g_object_unref (G_OBJECT (anim)); + + g_object_thaw_notify (G_OBJECT (image)); } /** @@ -470,6 +765,8 @@ gtk_image_set_from_pixbuf (GtkImage *image, g_return_if_fail (GTK_IS_IMAGE (image)); g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf)); + + g_object_freeze_notify (G_OBJECT (image)); if (pixbuf) g_object_ref (G_OBJECT (pixbuf)); @@ -486,6 +783,10 @@ gtk_image_set_from_pixbuf (GtkImage *image, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf)); } + + g_object_notify (G_OBJECT (image), "pixbuf"); + + g_object_thaw_notify (G_OBJECT (image)); } /** @@ -502,22 +803,34 @@ gtk_image_set_from_stock (GtkImage *image, const gchar *stock_id, GtkIconSize size) { + gchar *new_id; + g_return_if_fail (GTK_IS_IMAGE (image)); + + g_object_freeze_notify (G_OBJECT (image)); + + /* in case stock_id == image->data.stock.stock_id */ + new_id = g_strdup (stock_id); gtk_image_reset (image); - if (stock_id) - { + if (new_id) + { image->storage_type = GTK_IMAGE_STOCK; - image->data.stock.stock_id = g_strdup (stock_id); - image->data.stock.size = size; + image->data.stock.stock_id = new_id; + image->icon_size = size; /* Size is demand-computed in size request method * if we're a stock image, since changing the * style impacts the size request */ } + + g_object_notify (G_OBJECT (image), "stock"); + g_object_notify (G_OBJECT (image), "icon_size"); + + g_object_thaw_notify (G_OBJECT (image)); } /** @@ -536,6 +849,8 @@ gtk_image_set_from_icon_set (GtkImage *image, { g_return_if_fail (GTK_IS_IMAGE (image)); + g_object_freeze_notify (G_OBJECT (image)); + if (icon_set) gtk_icon_set_ref (icon_set); @@ -546,12 +861,17 @@ gtk_image_set_from_icon_set (GtkImage *image, image->storage_type = GTK_IMAGE_ICON_SET; image->data.icon_set.icon_set = icon_set; - image->data.icon_set.size = size; + image->icon_size = size; /* Size is demand-computed in size request method * if we're an icon set */ } + + g_object_notify (G_OBJECT (image), "icon_set"); + g_object_notify (G_OBJECT (image), "icon_size"); + + g_object_thaw_notify (G_OBJECT (image)); } /** @@ -569,6 +889,8 @@ gtk_image_set_from_animation (GtkImage *image, g_return_if_fail (GTK_IS_IMAGE (image)); g_return_if_fail (animation == NULL || GDK_IS_PIXBUF_ANIMATION (animation)); + + g_object_freeze_notify (G_OBJECT (image)); if (animation) g_object_ref (G_OBJECT (animation)); @@ -587,6 +909,10 @@ gtk_image_set_from_animation (GtkImage *image, gdk_pixbuf_animation_get_width (animation), gdk_pixbuf_animation_get_height (animation)); } + + g_object_notify (G_OBJECT (image), "pixbuf_animation"); + + g_object_thaw_notify (G_OBJECT (image)); } /** @@ -633,7 +959,7 @@ gtk_image_get_pixmap (GtkImage *image, *pixmap = image->data.pixmap.pixmap; if (mask) - *mask = image->data.pixmap.mask; + *mask = image->mask; } /** @@ -661,7 +987,7 @@ gtk_image_get_image (GtkImage *image, *gdk_image = image->data.image.image; if (mask) - *mask = image->data.image.mask; + *mask = image->mask; } /** @@ -719,7 +1045,7 @@ gtk_image_get_stock (GtkImage *image, *stock_id = image->data.stock.stock_id; if (size) - *size = image->data.stock.size; + *size = image->icon_size; } /** @@ -746,7 +1072,7 @@ gtk_image_get_icon_set (GtkImage *image, *icon_set = image->data.icon_set.icon_set; if (size) - *size = image->data.icon_set.size; + *size = image->icon_size; } /** @@ -899,14 +1225,14 @@ gtk_image_expose (GtkWidget *widget, switch (image->storage_type) { case GTK_IMAGE_PIXMAP: - mask = image->data.pixmap.mask; + mask = image->mask; gdk_drawable_get_size (image->data.pixmap.pixmap, &image_bound.width, &image_bound.height); break; case GTK_IMAGE_IMAGE: - mask = image->data.image.mask; + mask = image->mask; image_bound.width = image->data.image.image->width; image_bound.height = image->data.image.image->height; break; @@ -919,7 +1245,7 @@ gtk_image_expose (GtkWidget *widget, case GTK_IMAGE_STOCK: stock_pixbuf = gtk_widget_render_icon (widget, image->data.stock.stock_id, - image->data.stock.size, + image->icon_size, NULL); if (stock_pixbuf) { @@ -934,7 +1260,7 @@ gtk_image_expose (GtkWidget *widget, widget->style, gtk_widget_get_direction (widget), GTK_WIDGET_STATE (widget), - image->data.icon_set.size, + image->icon_size, widget, NULL); @@ -1070,26 +1396,44 @@ gtk_image_expose (GtkWidget *widget, static void gtk_image_clear (GtkImage *image) { + g_object_freeze_notify (G_OBJECT (image)); + + if (image->storage_type != GTK_IMAGE_EMPTY) + g_object_notify (G_OBJECT (image), "storage_type"); + + if (image->mask) + { + g_object_unref (G_OBJECT (image->mask)); + image->mask = NULL; + g_object_notify (G_OBJECT (image), "mask"); + } + + if (image->icon_size != DEFAULT_ICON_SIZE) + { + image->icon_size = DEFAULT_ICON_SIZE; + g_object_notify (G_OBJECT (image), "icon_size"); + } + switch (image->storage_type) { case GTK_IMAGE_PIXMAP: if (image->data.pixmap.pixmap) g_object_unref (G_OBJECT (image->data.pixmap.pixmap)); - - if (image->data.pixmap.mask) - g_object_unref (G_OBJECT (image->data.pixmap.mask)); - + image->data.pixmap.pixmap = NULL; + + g_object_notify (G_OBJECT (image), "pixmap"); + break; case GTK_IMAGE_IMAGE: if (image->data.image.image) g_object_unref (G_OBJECT (image->data.image.image)); - - if (image->data.image.mask) - g_object_unref (G_OBJECT (image->data.image.mask)); - + image->data.image.image = NULL; + + g_object_notify (G_OBJECT (image), "image"); + break; case GTK_IMAGE_PIXBUF: @@ -1097,26 +1441,39 @@ gtk_image_clear (GtkImage *image) if (image->data.pixbuf.pixbuf) g_object_unref (G_OBJECT (image->data.pixbuf.pixbuf)); + g_object_notify (G_OBJECT (image), "pixbuf"); + break; case GTK_IMAGE_STOCK: g_free (image->data.stock.stock_id); + + image->data.stock.stock_id = NULL; + g_object_notify (G_OBJECT (image), "stock"); break; case GTK_IMAGE_ICON_SET: if (image->data.icon_set.icon_set) gtk_icon_set_unref (image->data.icon_set.icon_set); + image->data.icon_set.icon_set = NULL; + g_object_notify (G_OBJECT (image), "icon_set"); break; case GTK_IMAGE_ANIMATION: if (image->data.anim.frame_timeout) g_source_remove (image->data.anim.frame_timeout); - + if (image->data.anim.anim) - g_object_unref (G_OBJECT (image->data.anim.anim)); + g_object_unref (G_OBJECT (image->data.anim.anim)); + + image->data.anim.frame_timeout = 0; + image->data.anim.anim = NULL; + + g_object_notify (G_OBJECT (image), "pixbuf_animation"); + break; case GTK_IMAGE_EMPTY: @@ -1128,6 +1485,8 @@ gtk_image_clear (GtkImage *image) image->storage_type = GTK_IMAGE_EMPTY; memset (&image->data, '\0', sizeof (image->data)); + + g_object_thaw_notify (G_OBJECT (image)); } static void @@ -1158,7 +1517,7 @@ gtk_image_size_request (GtkWidget *widget, case GTK_IMAGE_STOCK: pixbuf = gtk_widget_render_icon (GTK_WIDGET (image), image->data.stock.stock_id, - image->data.stock.size, + image->icon_size, NULL); break; @@ -1167,7 +1526,7 @@ gtk_image_size_request (GtkWidget *widget, widget->style, gtk_widget_get_direction (widget), GTK_WIDGET_STATE (widget), - image->data.icon_set.size, + image->icon_size, widget, NULL); break; diff --git a/gtk/gtkimage.h b/gtk/gtkimage.h index b528ef4ac..ddd4ebd44 100644 --- a/gtk/gtkimage.h +++ b/gtk/gtkimage.h @@ -57,13 +57,11 @@ typedef struct _GtkImageAnimationData GtkImageAnimationData; struct _GtkImagePixmapData { GdkPixmap *pixmap; - GdkBitmap *mask; }; struct _GtkImageImageData { GdkImage *image; - GdkBitmap *mask; }; struct _GtkImagePixbufData @@ -74,13 +72,11 @@ struct _GtkImagePixbufData struct _GtkImageStockData { gchar *stock_id; - GtkIconSize size; }; struct _GtkImageIconSetData { GtkIconSet *icon_set; - GtkIconSize size; }; struct _GtkImageAnimationData @@ -116,6 +112,12 @@ struct _GtkImage GtkImageIconSetData icon_set; GtkImageAnimationData anim; } data; + + /* Only used with GTK_IMAGE_PIXMAP, GTK_IMAGE_IMAGE */ + GdkBitmap *mask; + + /* Only used with GTK_IMAGE_STOCK, GTK_IMAGE_ICON_SET */ + GtkIconSize icon_size; }; struct _GtkImageClass diff --git a/gtk/gtkradiobutton.c b/gtk/gtkradiobutton.c index 8d9ed1e48..cc9b573e2 100644 --- a/gtk/gtkradiobutton.c +++ b/gtk/gtkradiobutton.c @@ -220,7 +220,7 @@ gtk_radio_button_new_with_label (GSList *group, radio_button = g_object_new (GTK_TYPE_RADIO_BUTTON, "label", label, NULL) ; if (group) - gtk_radio_button_set_group (radio_button, group); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radio_button), group); return radio_button; } @@ -246,7 +246,7 @@ gtk_radio_button_new_with_mnemonic (GSList *group, radio_button = g_object_new (GTK_TYPE_RADIO_BUTTON, "label", label, "use_underline", TRUE, NULL); if (group) - gtk_radio_button_set_group (radio_button, group); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radio_button), group); return radio_button; } diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 1ee20e322..1dd7530cc 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -64,7 +64,7 @@ enum { /* Construct */ PROP_TYPE, - /* Style Props */ + /* Normal Props */ PROP_TITLE, PROP_ALLOW_SHRINK, PROP_ALLOW_GROW, @@ -74,10 +74,21 @@ enum { PROP_DEFAULT_WIDTH, PROP_DEFAULT_HEIGHT, PROP_DESTROY_WITH_PARENT, - + PROP_ICON, + LAST_ARG }; +typedef struct +{ + GList *icon_list; + GdkPixmap *icon_pixmap; + GdkPixmap *icon_mask; + guint realized : 1; + guint using_default_icon : 1; + guint using_parent_icon : 1; +} GtkWindowIconInfo; + typedef struct { GdkGeometry geometry; /* Last set of geometry hints we set */ GdkWindowHints flags; @@ -217,11 +228,17 @@ static void gtk_window_set_default_size_internal (GtkWindow *window, gboolean change_height, gint height); +static void gtk_window_realize_icon (GtkWindow *window); +static void gtk_window_unrealize_icon (GtkWindow *window); static GSList *toplevel_list = NULL; static GHashTable *mnemonic_hash_table = NULL; static GtkBinClass *parent_class = NULL; static guint window_signals[LAST_SIGNAL] = { 0 }; +static GList *default_icon_list = NULL; +/* FIXME need to be per-screen */ +static GdkPixmap *default_icon_pixmap = NULL; +static GdkPixmap *default_icon_mask = NULL; static void gtk_window_set_property (GObject *object, guint prop_id, @@ -349,7 +366,7 @@ gtk_window_class_init (GtkWindowClass *klass) GTK_WINDOW_TOPLEVEL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - /* Style Props */ + /* Regular Props */ g_object_class_install_property (gobject_class, PROP_TITLE, g_param_spec_string ("title", @@ -427,8 +444,14 @@ gtk_window_class_init (GtkWindowClass *klass) FALSE, G_PARAM_READWRITE)); - /* Style props are set or not */ - + g_object_class_install_property (gobject_class, + PROP_ICON, + g_param_spec_object ("icon", + _("Icon"), + _("Icon for this window"), + GDK_TYPE_PIXBUF, + G_PARAM_READWRITE)); + window_signals[SET_FOCUS] = g_signal_new ("set_focus", G_TYPE_FROM_CLASS (object_class), @@ -651,6 +674,11 @@ gtk_window_set_property (GObject *object, case PROP_DESTROY_WITH_PARENT: gtk_window_set_destroy_with_parent (window, g_value_get_boolean (value)); break; + case PROP_ICON: + gtk_window_set_icon (window, + g_value_get_object (value)); + break; + default: break; } @@ -707,6 +735,10 @@ gtk_window_get_property (GObject *object, case PROP_DESTROY_WITH_PARENT: g_value_set_boolean (value, window->destroy_with_parent); break; + case PROP_ICON: + g_value_set_object (value, + G_OBJECT (gtk_window_get_icon (window))); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1705,6 +1737,505 @@ gtk_window_get_decorated (GtkWindow *window) return window->decorated; } +static void +gdk_pixbuf_render_pixmap_and_mask_with_colormap (GdkPixbuf *pixbuf, + GdkPixmap **pixmap_return, + GdkBitmap **mask_return, + int alpha_threshold, + GdkColormap *cmap) +{ + g_return_if_fail (pixbuf != NULL); + + if (pixmap_return) + { + GdkGC *gc; + + *pixmap_return = gdk_pixmap_new (NULL, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), + gdk_colormap_get_visual (cmap)->depth); + gdk_drawable_set_colormap (GDK_DRAWABLE (*pixmap_return), + cmap); + gc = gdk_gc_new (*pixmap_return); + gdk_pixbuf_render_to_drawable (pixbuf, *pixmap_return, gc, + 0, 0, 0, 0, + gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), + GDK_RGB_DITHER_NORMAL, + 0, 0); + gdk_gc_unref (gc); + } + + if (mask_return) + { + if (gdk_pixbuf_get_has_alpha (pixbuf)) + { + *mask_return = gdk_pixmap_new (NULL, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), 1); + + gdk_pixbuf_render_threshold_alpha (pixbuf, *mask_return, + 0, 0, 0, 0, + gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), + alpha_threshold); + } + else + *mask_return = NULL; + } +} + +static GtkWindowIconInfo* +get_icon_info (GtkWindow *window) +{ + return g_object_get_data (G_OBJECT (window), + "gtk-window-icon-info"); +} + +static GtkWindowIconInfo* +ensure_icon_info (GtkWindow *window) +{ + GtkWindowIconInfo *info; + + info = get_icon_info (window); + + if (info == NULL) + { + info = g_new0 (GtkWindowIconInfo, 1); + g_object_set_data_full (G_OBJECT (window), + "gtk-window-icon-info", + info, + g_free); + } + + return info; +} + +static void +get_pixmap_and_mask (GtkWindowIconInfo *parent_info, + gboolean is_default_list, + GList *icon_list, + GdkPixmap **pmap_return, + GdkBitmap **mask_return) +{ + GdkPixbuf *best_icon; + GList *tmp_list; + int best_size; + + *pmap_return = NULL; + *mask_return = NULL; + + if (is_default_list && + default_icon_pixmap != NULL) + { + /* Use shared icon pixmap (eventually will be stored on the + * GdkScreen) + */ + if (default_icon_pixmap) + g_object_ref (G_OBJECT (default_icon_pixmap)); + if (default_icon_mask) + g_object_ref (G_OBJECT (default_icon_mask)); + + *pmap_return = default_icon_pixmap; + *mask_return = default_icon_mask; + } + else if (parent_info && parent_info->icon_pixmap) + { + if (parent_info->icon_pixmap) + g_object_ref (G_OBJECT (parent_info->icon_pixmap)); + if (parent_info->icon_mask) + g_object_ref (G_OBJECT (parent_info->icon_mask)); + + *pmap_return = parent_info->icon_pixmap; + *mask_return = parent_info->icon_mask; + } + else + { +#define IDEAL_SIZE 48 + + best_size = G_MAXINT; + best_icon = NULL; + tmp_list = icon_list; + while (tmp_list != NULL) + { + GdkPixbuf *pixbuf = tmp_list->data; + int this; + + /* average width and height - if someone passes in a rectangular + * icon they deserve what they get. + */ + this = gdk_pixbuf_get_width (pixbuf) + gdk_pixbuf_get_height (pixbuf); + this /= 2; + + if (best_icon == NULL) + { + best_icon = pixbuf; + best_size = this; + } + else + { + /* icon is better if it's 32 pixels or larger, and closer to + * the ideal size than the current best. + */ + if (this >= 32 && + (ABS (best_size - IDEAL_SIZE) < + ABS (this - IDEAL_SIZE))) + { + best_icon = pixbuf; + best_size = this; + } + } + + tmp_list = tmp_list->next; + } + + if (best_icon) + gdk_pixbuf_render_pixmap_and_mask_with_colormap (best_icon, + pmap_return, + mask_return, + 128, + gdk_colormap_get_system ()); + + /* Save pmap/mask for others to use if appropriate */ + if (parent_info) + { + parent_info->icon_pixmap = *pmap_return; + parent_info->icon_mask = *mask_return; + + if (parent_info->icon_pixmap) + g_object_ref (G_OBJECT (parent_info->icon_pixmap)); + if (parent_info->icon_mask) + g_object_ref (G_OBJECT (parent_info->icon_mask)); + } + else if (is_default_list) + { + default_icon_pixmap = *pmap_return; + default_icon_mask = *mask_return; + + if (default_icon_pixmap) + g_object_add_weak_pointer (G_OBJECT (default_icon_pixmap), + (gpointer*)&default_icon_pixmap); + if (default_icon_mask) + g_object_add_weak_pointer (G_OBJECT (default_icon_mask), + (gpointer*)&default_icon_mask); + } + } +} + +static void +gtk_window_realize_icon (GtkWindow *window) +{ + GtkWidget *widget; + GtkWindowIconInfo *info; + GList *icon_list; + + widget = GTK_WIDGET (window); + + g_return_if_fail (widget->window != NULL); + + /* no point setting an icon on override-redirect */ + if (window->type == GTK_WINDOW_POPUP) + return; + + icon_list = NULL; + + info = ensure_icon_info (window); + + if (info->realized) + return; + + g_return_if_fail (info->icon_pixmap == NULL); + g_return_if_fail (info->icon_mask == NULL); + + info->using_default_icon = FALSE; + info->using_parent_icon = FALSE; + + icon_list = info->icon_list; + + /* Inherit from transient parent */ + if (icon_list == NULL && window->transient_parent) + { + icon_list = ensure_icon_info (window->transient_parent)->icon_list; + if (icon_list) + info->using_parent_icon = TRUE; + } + + /* Inherit from default */ + if (icon_list == NULL) + { + icon_list = default_icon_list; + if (icon_list) + info->using_default_icon = TRUE; + } + + gdk_window_set_icon_list (widget->window, icon_list); + + get_pixmap_and_mask (info->using_parent_icon ? + ensure_icon_info (window->transient_parent) : NULL, + info->using_default_icon, + icon_list, + &info->icon_pixmap, + &info->icon_mask); + + /* This is a slight ICCCM violation since it's a color pixmap not + * a bitmap, but everyone does it. + */ + gdk_window_set_icon (widget->window, + NULL, + info->icon_pixmap, + info->icon_mask); + + info->realized = TRUE; +} + +static void +gtk_window_unrealize_icon (GtkWindow *window) +{ + GtkWindowIconInfo *info; + GtkWidget *widget; + + widget = GTK_WIDGET (window); + + info = get_icon_info (window); + + if (info == NULL) + return; + + if (info->icon_pixmap) + g_object_unref (G_OBJECT (info->icon_pixmap)); + + if (info->icon_mask) + g_object_unref (G_OBJECT (info->icon_mask)); + + info->icon_pixmap = NULL; + info->icon_mask = NULL; + + /* We don't clear the properties on the window, just figure the + * window is going away. + */ + + info->realized = FALSE; +} + +/** + * gtk_window_set_icon_list: + * @window: a #GtkWindow + * @list: list of #GdkPixbuf + * + * Sets up the icon representing a #GtkWindow. The icon is used when + * the window is minimized (also known as iconified). Some window + * managers or desktop environments may also place it in the window + * frame, or display it in other contexts. + * + * gtk_window_set_icon_list() allows you to pass in the same icon in + * several hand-drawn sizes. The list should contain the natural sizes + * your icon is available in; that is, don't scale the image before + * passing it to GTK+. Scaling is postponed until the last minute, + * when the desired final size is known, to allow best quality. + * + * By passing several sizes, you may improve the final image quality + * of the icon, by reducing or eliminating automatic image scaling. + * + * Recommended sizes to provide: 16x16, 32x32, 48x48 at minimum, and + * larger images (64x64, 128x128) if you have them. + * + * See also gtk_window_set_default_icon_list() to set the icon + * for all windows in your application in one go. + * + * Note that transient windows (those who have been set transient for another + * window using gtk_window_set_transient_for()) will inherit their + * icon from their transient parent. So there's no need to explicitly + * set the icon on transient windows. + **/ +void +gtk_window_set_icon_list (GtkWindow *window, + GList *list) +{ + GtkWindowIconInfo *info; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + info = ensure_icon_info (window); + + if (info->icon_list == list) /* check for NULL mostly */ + return; + + g_list_foreach (info->icon_list, + (GFunc) g_object_unref, NULL); + + g_list_free (info->icon_list); + + info->icon_list = g_list_copy (list); + g_list_foreach (info->icon_list, + (GFunc) g_object_ref, NULL); + + g_object_notify (G_OBJECT (window), "icon_list"); + + gtk_window_unrealize_icon (window); + + if (GTK_WIDGET_REALIZED (window)) + gtk_window_realize_icon (window); + + /* We could try to update our transient children, but I don't think + * it's really worth it. If we did it, the best way would probably + * be to have children connect to notify::icon_list + */ +} + +/** + * gtk_window_get_icon_list: + * @window: a #GtkWindow + * + * Retrieves the list of icons set by gtk_window_set_icon_list(). + * The list is copied, but the reference count on each + * member won't be incremented. + * + * Return value: copy of window's icon list + **/ +GList* +gtk_window_get_icon_list (GtkWindow *window) +{ + GtkWindowIconInfo *info; + + g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); + + info = get_icon_info (window); + + if (info) + return g_list_copy (info->icon_list); + else + return NULL; +} + +/** + * gtk_window_set_icon: + * @window: a #GtkWindow + * @icon: icon image, or %NULL + * + * Sets up the icon representing a #GtkWindow. This icon is used when + * the window is minimized (also known as iconified). Some window + * managers or desktop environments may also place it in the window + * frame, or display it in other contexts. + * + * The icon should be provided in whatever size it was naturally + * drawn; that is, don't scale the image before passing it to + * GTK+. Scaling is postponed until the last minute, when the desired + * final size is known, to allow best quality. + * + * If you have your icon hand-drawn in multiple sizes, use + * gtk_window_set_icon_list(). Then the best size will be used. + * + * This function is equivalent to calling gtk_window_set_icon_list() + * with a 1-element list. + * + * See also gtk_window_set_default_icon_list() to set the icon + * for all windows in your application in one go. + **/ +void +gtk_window_set_icon (GtkWindow *window, + GdkPixbuf *icon) +{ + GList *list; + + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (icon == NULL || GDK_IS_PIXBUF (icon)); + + list = NULL; + list = g_list_append (list, icon); + gtk_window_set_icon_list (window, list); + g_list_free (list); +} + +/** + * gtk_window_get_icon: + * @window: a #GtkWindow + * + * Gets the value set by gtk_window_set_icon() (or if you've + * called gtk_window_set_icon_list(), gets the first icon in + * the icon list). + * + * Return value: icon for window + **/ +GdkPixbuf* +gtk_window_get_icon (GtkWindow *window) +{ + GtkWindowIconInfo *info; + + info = get_icon_info (window); + if (info && info->icon_list) + return GDK_PIXBUF (info->icon_list->data); + else + return NULL; +} + +/** + * gtk_window_set_default_icon_list: + * @list: a list of #GdkPixbuf + * + * Sets an icon list to be used as fallback for windows that haven't + * had gtk_window_set_icon_list() called on them to set up a + * window-specific icon list. This function allows you to set up the + * icon for all windows in your app at once. + * + * See gtk_window_set_icon_list() for more details. + * + **/ +void +gtk_window_set_default_icon_list (GList *list) +{ + GList *toplevels; + GList *tmp_list; + if (list == default_icon_list) + return; + + if (default_icon_pixmap) + g_object_unref (G_OBJECT (default_icon_pixmap)); + if (default_icon_mask) + g_object_unref (G_OBJECT (default_icon_mask)); + + default_icon_pixmap = NULL; + default_icon_mask = NULL; + + g_list_foreach (default_icon_list, + (GFunc) g_object_unref, NULL); + + g_list_free (default_icon_list); + + default_icon_list = g_list_copy (list); + g_list_foreach (default_icon_list, + (GFunc) g_object_ref, NULL); + + /* Update all toplevels */ + toplevels = gtk_window_list_toplevels (); + tmp_list = toplevels; + while (tmp_list != NULL) + { + GtkWindowIconInfo *info; + GtkWindow *w = tmp_list->data; + + info = get_icon_info (w); + if (info && info->using_default_icon) + { + gtk_window_unrealize_icon (w); + if (GTK_WIDGET_REALIZED (w)) + gtk_window_realize_icon (w); + } + + tmp_list = tmp_list->next; + } + g_list_free (toplevels); +} + +/** + * gtk_window_get_default_icon_list: + * + * Gets the value set by gtk_window_set_default_icon_list(). + * The list is a copy and should be freed with g_list_free(), + * but the pixbufs in the list have not had their reference count + * incremented. + * + * Return value: copy of default icon list + **/ +GList* +gtk_window_get_default_icon_list (void) +{ + return g_list_copy (default_icon_list); +} + static void gtk_window_set_default_size_internal (GtkWindow *window, gboolean change_width, @@ -2256,10 +2787,13 @@ gtk_window_destroy (GtkObject *object) g_return_if_fail (GTK_IS_WINDOW (object)); window = GTK_WINDOW (object); - + if (window->transient_parent) gtk_window_set_transient_for (window, NULL); + /* frees the icons */ + gtk_window_set_icon_list (window, NULL); + if (window->has_user_ref_count) { window->has_user_ref_count = FALSE; @@ -2632,6 +3166,9 @@ gtk_window_realize (GtkWidget *widget) gdk_window_set_modal_hint (widget->window, TRUE); else gdk_window_set_modal_hint (widget->window, FALSE); + + /* Icons */ + gtk_window_realize_icon (window); } static void @@ -2668,6 +3205,9 @@ gtk_window_unrealize (GtkWidget *widget) gdk_window_destroy (window->frame); window->frame = NULL; } + + /* Icons */ + gtk_window_unrealize_icon (window); (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); } diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h index 457fbdb51..2f7474425 100644 --- a/gtk/gtkwindow.h +++ b/gtk/gtkwindow.h @@ -206,6 +206,15 @@ void gtk_window_set_decorated (GtkWindow *window, gboolean setting); gboolean gtk_window_get_decorated (GtkWindow *window); +void gtk_window_set_icon_list (GtkWindow *window, + GList *list); +GList* gtk_window_get_icon_list (GtkWindow *window); +void gtk_window_set_icon (GtkWindow *window, + GdkPixbuf *icon); +GdkPixbuf* gtk_window_get_icon (GtkWindow *window); +void gtk_window_set_default_icon_list (GList *list); +GList* gtk_window_get_default_icon_list (void); + /* If window is set modal, input will be grabbed when show and released when hide */ void gtk_window_set_modal (GtkWindow *window, gboolean modal); -- 2.43.2