diff options
author | Andy Hertzfeld <andy@src.gnome.org> | 2001-01-03 00:45:34 +0000 |
---|---|---|
committer | Andy Hertzfeld <andy@src.gnome.org> | 2001-01-03 00:45:34 +0000 |
commit | 82473e05df72f68affb44c951b18a82257139c11 (patch) | |
tree | 6db160fa93945dd00140c9bb70907a8ed657869e | |
parent | 0f3e5e583e6b8ebc1e981955d7e2ea63659a144e (diff) | |
download | nautilus-82473e05df72f68affb44c951b18a82257139c11.tar.gz |
first check-in to post-1_0 branch.
first check-in to post-1_0 branch.
add ability to embed Bonobo controls in the icon view.
created a new bonobo control that fetches and displays rss weblogs
plus miscellaneous optimizations and improvements
* components/Makefile.am:
* configure.in:
added new rss-control component
* components/hardware/nautilus-hardware-view.c:
(get_RAM_description), (get_IDE_description):
incorporated Bud's disk size calculation, plus tweaked the
RAM size calculation
* components/rss-control/.cvsignore:
* components/rss-control/Makefile.am:
* components/rss-control/nautilus-rss-control.oafinfo:
files for the new rss-control component
* components/rss-control/main.c: (rss_control_object_destroyed),
(rss_control_make_object), (main):
factory for the rss-control Bonobo component
* components/rss-control/nautilus-rss-control.c,h:
(nautilus_rss_control_initialize_class), (get_bonobo_properties),
(set_bonobo_properties), (nautilus_rss_control_initialize),
(nautilus_rss_control_clear_items), (nautilus_rss_control_destroy),
(nautilus_rss_control_get_control),
(nautilus_rss_control_set_title), (rss_logo_callback),
(rss_read_done_callback), (load_rss_file),
(nautilus_rss_control_set_uri), (draw_rss_logo_image),
(draw_rss_title), (draw_blue_line), (draw_rss_items),
(nautilus_rss_control_draw), (nautilus_rss_control_expose),
(nautilus_rss_control_button_press_event):
new bonobo control to fetch an rss file and display it.
* icons/Makefile.am:
* icons/bullet.png:
added a "bullet" image used in rss control, but it's generally
useful enough that I added it to the main icons
* libnautilus-extensions/nautilus-file-utilities.c:
(nautilus_get_user_main_directory):
deleted some code that's no longer relevant
* libnautilus-extensions/nautilus-icon-canvas-item.c,h:
(nautilus_icon_canvas_item_destroy),
(nautilus_icon_canvas_item_get_icon_width),
(nautilus_icon_canvas_item_get_icon_height),
(nautilus_icon_canvas_item_set_arg), (do_control_destroy),
(nautilus_icon_canvas_item_get_arg),
(nautilus_icon_canvas_item_get_image), (recompute_bounding_box),
(nautilus_icon_canvas_item_update_bounds),
(draw_or_measure_label_text), (emblem_layout_next),
(draw_pixbuf_aa), (nautilus_icon_canvas_item_draw),
(draw_or_measure_label_text_aa),
(nautilus_icon_canvas_item_render),
(nautilus_icon_canvas_item_bounds),
(nautilus_icon_canvas_item_get_icon_rectangle),
(get_icon_canvas_rectangle),
(nautilus_icon_canvas_item_set_smooth_font),
(nautilus_icon_canvas_item_get_control),
(nautilus_icon_canvas_item_set_control):
added support for widgets embedded in icon canvas items
* libnautilus-extensions/nautilus-icon-container.c,h:
(nautilus_icon_container_initialize_class),
(nautilus_icon_container_update_icon):
taught the icon container to ask for the control associated
with a file, and configured the canvas item with it if there
is one.
* libnautilus-extensions/nautilus-icon-dnd.c:
(nautilus_icon_dnd_begin_drag):
made it unref the image it fetches from the canvas item, so the
canvas item can generate custom images for controls.
* libnautilus-extensions/nautilus-link.c,h:
(nautilus_link_local_get_component_info):
fetch the activation and configuration strings associated with
a link file for string embedding.
* libnautilus-extensions/nautilus-metadata.h:
added metadata types for the activation and configuration data
* src/file-manager/fm-icon-view.c: (get_icon_control_callback),
(create_icon_container):
added signal to create a bonobo control associated with a file
and configure it, if there is one
* src/nautilus-sidebar-tabs.c: (nautilus_sidebar_tabs_hit_test),
(nautilus_sidebar_tabs_select_tab):
hit test invisible tabs to support the change below.
* src/nautilus-sidebar.c: (nautilus_sidebar_release_event):
implemented Bud's idea of toggling the visibility of the active
view by clicking on the tab again.
34 files changed, 1530 insertions, 199 deletions
@@ -1,3 +1,103 @@ +2001-01-02 Andy Hertzfeld <andy@eazel.com> + + first check-in to post-1_0 branch. + + add ability to embed Bonobo controls in the icon view. + created a new bonobo control that fetches and displays rss weblogs + plus miscellaneous optimizations and improvements + + * components/Makefile.am: + * configure.in: + added new rss-control component + + * components/hardware/nautilus-hardware-view.c: + (get_RAM_description), (get_IDE_description): + incorporated Bud's disk size calculation, plus tweaked the + RAM size calculation + + * components/rss-control/.cvsignore: + * components/rss-control/Makefile.am: + * components/rss-control/nautilus-rss-control.oafinfo: + files for the new rss-control component + + * components/rss-control/main.c: (rss_control_object_destroyed), + (rss_control_make_object), (main): + factory for the rss-control Bonobo component + + * components/rss-control/nautilus-rss-control.c,h: + (nautilus_rss_control_initialize_class), (get_bonobo_properties), + (set_bonobo_properties), (nautilus_rss_control_initialize), + (nautilus_rss_control_clear_items), (nautilus_rss_control_destroy), + (nautilus_rss_control_get_control), + (nautilus_rss_control_set_title), (rss_logo_callback), + (rss_read_done_callback), (load_rss_file), + (nautilus_rss_control_set_uri), (draw_rss_logo_image), + (draw_rss_title), (draw_blue_line), (draw_rss_items), + (nautilus_rss_control_draw), (nautilus_rss_control_expose), + (nautilus_rss_control_button_press_event): + new bonobo control to fetch an rss file and display it. + + * icons/Makefile.am: + * icons/bullet.png: + added a "bullet" image used in rss control, but it's generally + useful enough that I added it to the main icons + + * libnautilus-extensions/nautilus-file-utilities.c: + (nautilus_get_user_main_directory): + deleted some code that's no longer relevant + + * libnautilus-extensions/nautilus-icon-canvas-item.c,h: + (nautilus_icon_canvas_item_destroy), + (nautilus_icon_canvas_item_get_icon_width), + (nautilus_icon_canvas_item_get_icon_height), + (nautilus_icon_canvas_item_set_arg), (do_control_destroy), + (nautilus_icon_canvas_item_get_arg), + (nautilus_icon_canvas_item_get_image), (recompute_bounding_box), + (nautilus_icon_canvas_item_update_bounds), + (draw_or_measure_label_text), (emblem_layout_next), + (draw_pixbuf_aa), (nautilus_icon_canvas_item_draw), + (draw_or_measure_label_text_aa), + (nautilus_icon_canvas_item_render), + (nautilus_icon_canvas_item_bounds), + (nautilus_icon_canvas_item_get_icon_rectangle), + (get_icon_canvas_rectangle), + (nautilus_icon_canvas_item_set_smooth_font), + (nautilus_icon_canvas_item_get_control), + (nautilus_icon_canvas_item_set_control): + added support for widgets embedded in icon canvas items + + * libnautilus-extensions/nautilus-icon-container.c,h: + (nautilus_icon_container_initialize_class), + (nautilus_icon_container_update_icon): + taught the icon container to ask for the control associated + with a file, and configured the canvas item with it if there + is one. + + * libnautilus-extensions/nautilus-icon-dnd.c: + (nautilus_icon_dnd_begin_drag): + made it unref the image it fetches from the canvas item, so the + canvas item can generate custom images for controls. + + * libnautilus-extensions/nautilus-link.c,h: + (nautilus_link_local_get_component_info): + fetch the activation and configuration strings associated with + a link file for string embedding. + + * libnautilus-extensions/nautilus-metadata.h: + added metadata types for the activation and configuration data + + * src/file-manager/fm-icon-view.c: (get_icon_control_callback), + (create_icon_container): + added signal to create a bonobo control associated with a file + and configure it, if there is one + + * src/nautilus-sidebar-tabs.c: (nautilus_sidebar_tabs_hit_test), + (nautilus_sidebar_tabs_select_tab): + hit test invisible tabs to support the change below. + * src/nautilus-sidebar.c: (nautilus_sidebar_release_event): + implemented Bud's idea of toggling the visibility of the active + view by clicking on the tab again. + 2001-01-02 Darin Adler <darin@eazel.com> reviewed by: John Sullivan <sullivan@eazel.com> diff --git a/components/Makefile.am b/components/Makefile.am index c26cb7f68..03ab50ca8 100644 --- a/components/Makefile.am +++ b/components/Makefile.am @@ -26,6 +26,7 @@ SUBDIRS = \ loser \ music \ notes \ + rss-control \ sample \ text \ tree \ diff --git a/components/hardware/nautilus-hardware-view.c b/components/hardware/nautilus-hardware-view.c index e08543f79..ecd93911d 100644 --- a/components/hardware/nautilus-hardware-view.c +++ b/components/hardware/nautilus-hardware-view.c @@ -258,6 +258,7 @@ get_RAM_description (void) { char *temp_str, *num_str, *result; char* proc_data; + GnomeVFSFileSize ram_size; proc_data = read_proc_info("meminfo"); @@ -270,8 +271,14 @@ get_RAM_description (void) /* strip kbyte suffix */ temp_str[strlen(temp_str) - 3] = '\0'; - num_str = gnome_vfs_format_file_size_for_display (1024 * atol (temp_str)); - g_free (temp_str); + ram_size = (strtoul (temp_str, NULL, 10) + 500) / 1000; + if (ram_size > 1000) { + num_str = g_strdup_printf ("%Lu GB", ram_size / 1000); + } else { + num_str = g_strdup_printf ("%Lu MB", ram_size); + } + + g_free (temp_str); g_free (proc_data); @@ -311,10 +318,31 @@ get_IDE_description (const char *device) temp_str = read_proc_info(proc_file); temp_str[strlen(temp_str) - 1] = '\0'; - /* This converts & calcs the sectors into MB's */ - capacity = strtoul (temp_str, NULL, 10); - num_str = gnome_vfs_format_file_size_for_display (512 * capacity); - g_string_append(string_data, "\n"); + /* NOTE: this should be + * capacity = strtoul (...) + * num_str = gnome_vfs_format_file_size_for_display (512 * numsectors); + * + * (512 bytes per sector) + * + * but with large disks we overflow an unsigned long, which is the + * the type that gnome_vfs uses. + * + * ALSO, in keeping with disk manufacturer convention, disk sizes + * are quoted in powers of 10 (i.e., MB is 10^6, GB is 10^9). + * (see http://www.maxtor.com/technology/Digi_vs_Deci.html + * So as to not confuse the user too much, we will follow the + * same convention.) + * + */ + + capacity = (512 * (strtoul (temp_str, NULL, 10) / 1000)) / 1000; + if (capacity > 1000) { + num_str = g_strdup_printf ("%Lu GB", capacity / 1000); + } else { + num_str = g_strdup_printf ("%Lu MB", capacity); + } + + g_string_append(string_data, "\n"); g_string_append(string_data, num_str); g_free(temp_str); g_free(proc_file); diff --git a/components/rss-control/.cvsignore b/components/rss-control/.cvsignore new file mode 100644 index 000000000..9eeb873c6 --- /dev/null +++ b/components/rss-control/.cvsignore @@ -0,0 +1,5 @@ +.deps +.libs +Makefile +Makefile.in +nautilus-rss-control diff --git a/components/rss-control/Makefile.am b/components/rss-control/Makefile.am new file mode 100644 index 000000000..99ae8d1f8 --- /dev/null +++ b/components/rss-control/Makefile.am @@ -0,0 +1,45 @@ +NULL = + +SUBDIRS = + +INCLUDES = \ + -DPREFIX=\"$(prefix)\" \ + -DG_LOG_DOMAIN=\"Nautilus-RSS-Control\" \ + -DDATADIR=\""$(datadir)"\" \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + -I$(top_builddir)/libnautilus \ + -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ + $(GNOMEUI_CFLAGS) \ + $(GCONF_CFLAGS) \ + $(OAF_CFLAGS) \ + $(BONOBO_CFLAGS) \ + $(VFS_CFLAGS) + +oafdir = $(datadir)/oaf +oaf_DATA = \ + nautilus-rss-control.oafinfo + + +bin_PROGRAMS = \ + nautilus-rss-control + +nautilus_rss_control_SOURCES = \ + nautilus-rss-control.c \ + nautilus-rss-control.h \ + main.c + +nautilus_rss_control_LDADD = \ + $(top_builddir)/libnautilus/libnautilus.la \ + $(top_builddir)/libnautilus-extensions/libnautilus-extensions.la \ + $(BONOBO_LIBS) \ + $(GNOMEUI_LIBS) \ + $(GCONF_LIBS) \ + $(VFS_LIBS) \ + $(GNORBA_LIBS) + +OBJECT_DIRECTORY_LIBS = $(GNOME_LIBS) $(OAF_LIBS) + +EXTRA_DIST = \ + $(oaf_DATA) \ + $(NULL) diff --git a/components/rss-control/main.c b/components/rss-control/main.c new file mode 100644 index 000000000..5af15140c --- /dev/null +++ b/components/rss-control/main.c @@ -0,0 +1,120 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* + * Copyright (C) 2000 Eazel, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Andy Hertzfeld + */ + +/* main.c - main function and object activation function for the rss control component. */ + +#include <config.h> +#include "nautilus-rss-control.h" + +#include <bonobo.h> +#include <gnome.h> +#include <libgnomevfs/gnome-vfs.h> +#include <libnautilus-extensions/nautilus-debug.h> +#include <liboaf/liboaf.h> + +static int object_count = 0; + +static void +rss_control_object_destroyed(GtkObject *obj) +{ + object_count--; + if (object_count <= 0) { + gtk_main_quit (); + } +} + +static BonoboObject * +rss_control_make_object (BonoboGenericFactory *factory, + const char *iid, + void *closure) +{ + NautilusRSSControl *rss_control; + BonoboObject *bonobo_control; + + if (strcmp (iid, "OAFIID:nautilus_rss_control:1230")) { + return NULL; + } + + rss_control = NAUTILUS_RSS_CONTROL (gtk_object_new (NAUTILUS_TYPE_RSS_CONTROL, NULL)); + + object_count++; + + bonobo_control = nautilus_rss_control_get_control (rss_control); + + gtk_signal_connect (GTK_OBJECT (bonobo_control), "destroy", rss_control_object_destroyed, NULL); + return bonobo_control; +} + +int +main (int argc, char *argv[]) +{ + BonoboGenericFactory *factory; + CORBA_ORB orb; + char *registration_id; + + /* Make criticals and warnings stop in the debugger if + * NAUTILUS_DEBUG is set. Unfortunately, this has to be done + * explicitly for each domain. + */ + if (g_getenv ("NAUTILUS_DEBUG") != NULL) { + nautilus_make_warnings_and_criticals_stop_in_debugger + (G_LOG_DOMAIN, g_log_domain_glib, + "Bonobo", + "Gdk", + "GnomeUI", + "GnomeVFS", + "GnomeVFS-CORBA", + "GnomeVFS-pthread", + "Gtk", + "GdkPixbuf", + "Nautilus", + "Nautilus-Authenticate", + "Nautilus-Tree", + "ORBit", + NULL); + } + + gnome_init_with_popt_table("nautilus-rss-control", VERSION, + argc, argv, + oaf_popt_options, 0, NULL); + + orb = oaf_init (argc, argv); + + bonobo_init (orb, CORBA_OBJECT_NIL, CORBA_OBJECT_NIL); + + /* initialize gnome-vfs, etc */ + g_thread_init (NULL); + gnome_vfs_init (); + + registration_id = oaf_make_registration_id ("OAFIID:nautilus_rss_control_factory:1230", getenv ("DISPLAY")); + factory = bonobo_generic_factory_new_multi (registration_id, + rss_control_make_object, + NULL); + g_free (registration_id); + + + do { + bonobo_main (); + } while (object_count > 0); + + return 0; +} diff --git a/components/rss-control/nautilus-rss-control.c b/components/rss-control/nautilus-rss-control.c new file mode 100644 index 000000000..c128589b1 --- /dev/null +++ b/components/rss-control/nautilus-rss-control.c @@ -0,0 +1,594 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ + +/* + * Copyright (C) 2000 Eazel, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Andy Hertzfeld <andy@eazel.com> + * + */ + +/* this is the implementation of the rss control, which fetches an rss file through a uri, and + * displays it in the widget. + */ + +#include <config.h> +#include <gnome.h> +#include <liboaf/liboaf.h> + +#include <bonobo.h> + +#include "nautilus-rss-control.h" +#include <ghttp.h> + +#include <gnome-xml/parser.h> +#include <gnome-xml/xmlmemory.h> + +#include <libgnomevfs/gnome-vfs.h> + +#include <libnautilus-extensions/nautilus-file-utilities.h> +#include <libnautilus-extensions/nautilus-gdk-extensions.h> +#include <libnautilus-extensions/nautilus-gdk-pixbuf-extensions.h> +#include <libnautilus-extensions/nautilus-glib-extensions.h> +#include <libnautilus-extensions/nautilus-gtk-extensions.h> +#include <libnautilus-extensions/nautilus-gtk-macros.h> +#include <libnautilus-extensions/nautilus-scalable-font.h> +#include <libnautilus-extensions/nautilus-string.h> +#include <libnautilus-extensions/nautilus-xml-extensions.h> +#include <libnautilus-extensions/nautilus-font-factory.h> + +struct _NautilusRSSControlDetails { + char* rss_uri; + BonoboObject *control; + NautilusScalableFont *font; + + char* title; + GdkPixbuf *logo; + GdkPixbuf *bullet; + GList *items; +}; + + +static void nautilus_rss_control_initialize_class (NautilusRSSControlClass *klass); +static void nautilus_rss_control_initialize (NautilusRSSControl *view); +static void nautilus_rss_control_destroy (GtkObject *object); + +static void nautilus_rss_control_draw (GtkWidget *widget, GdkRectangle *box); +static int nautilus_rss_control_expose (GtkWidget *widget, GdkEventExpose *event); +static gboolean nautilus_rss_control_button_press_event (GtkWidget *widget, GdkEventButton *event); +static void nautilus_rss_control_set_uri (NautilusRSSControl *rss_control, const char *uri); + + + +NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusRSSControl, + nautilus_rss_control, + GTK_TYPE_EVENT_BOX) + + +static void +nautilus_rss_control_initialize_class (NautilusRSSControlClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = GTK_OBJECT_CLASS (klass); + widget_class = GTK_WIDGET_CLASS (klass); + + object_class->destroy = nautilus_rss_control_destroy; + + widget_class->draw = nautilus_rss_control_draw; + widget_class->expose_event = nautilus_rss_control_expose; + widget_class->button_press_event = nautilus_rss_control_button_press_event; +} + +/* routines to handle setting and getting the configuration properties of the Bonobo control */ + +enum { + PLACEHOLDER, + CONFIGURATION +} MyArgs; + + +static void +get_bonobo_properties (BonoboPropertyBag *bag, + BonoboArg *arg, + guint arg_id, + gpointer user_data) +{ + NautilusRSSControl *rss_control = NAUTILUS_RSS_CONTROL (user_data); + + switch (arg_id) { + + case CONFIGURATION: + { + BONOBO_ARG_SET_STRING (arg, rss_control->details->rss_uri); + break; + } + + default: + g_warning ("Unhandled arg %d", arg_id); + break; + } +} + +static void +set_bonobo_properties (BonoboPropertyBag *bag, + const BonoboArg *arg, + guint arg_id, + gpointer user_data) +{ + NautilusRSSControl *rss_control = NAUTILUS_RSS_CONTROL (user_data); + + switch (arg_id) { + + case CONFIGURATION: + { + char *uri; + + uri = BONOBO_ARG_GET_STRING (arg); + nautilus_rss_control_set_uri (rss_control, uri); + + break; + } + + default: + g_warning ("Unhandled arg %d", arg_id); + break; + } +} + +/* initialize ourselves by connecting to the location change signal and allocating our subviews */ +static void +nautilus_rss_control_initialize (NautilusRSSControl *rss_control) +{ + GtkWidget *frame; + char *bullet_path; + BonoboPropertyBag *property_bag; + + rss_control->details = g_new0 (NautilusRSSControlDetails, 1); + + /* set up the font */ + rss_control->details->font = NAUTILUS_SCALABLE_FONT (nautilus_scalable_font_new ("helvetica", "medium", NULL, NULL)); + + /* load the bullet used to display the items */ + bullet_path = nautilus_pixmap_file ("bullet.png"); + rss_control->details->bullet = gdk_pixbuf_new_from_file (bullet_path); + g_free (bullet_path); + + /* make the bonobo control */ + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type(GTK_FRAME (frame), GTK_SHADOW_OUT); + gtk_widget_show (frame); + gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET (rss_control)); + + rss_control->details->control = (BonoboObject*) bonobo_control_new (GTK_WIDGET (frame)); + + /* attach a property bag with the configure property */ + property_bag = bonobo_property_bag_new (get_bonobo_properties, set_bonobo_properties, rss_control); + bonobo_control_set_properties (BONOBO_CONTROL(rss_control->details->control), property_bag); + + bonobo_property_bag_add (property_bag, "configuration", 1, BONOBO_ARG_STRING, NULL, + "RSS Configuration", 0); + bonobo_object_unref (BONOBO_OBJECT (property_bag)); + + /* show the view itself */ + gtk_widget_show (GTK_WIDGET (rss_control)); + + /* set up the rss file (initially hardwired) */ + /* + nautilus_rss_control_set_uri (rss_control, "http://www.slashdot.org/slashdot.rdf"); + */ +} + +static void +nautilus_rss_control_clear_items (NautilusRSSControl *rss_control) +{ + if (rss_control->details->items != NULL) { + nautilus_g_list_free_deep (rss_control->details->items); + rss_control->details->items = NULL; + } +} + +static void +nautilus_rss_control_destroy (GtkObject *object) +{ + NautilusRSSControl *rss_control; + + rss_control = NAUTILUS_RSS_CONTROL (object); + g_free (rss_control->details->rss_uri); + g_free (rss_control->details->title); + + if (rss_control->details->logo != NULL) { + gdk_pixbuf_unref (rss_control->details->logo); + } + + if (rss_control->details->bullet != NULL) { + gdk_pixbuf_unref (rss_control->details->bullet); + } + + if (rss_control->details->items != NULL) { + nautilus_rss_control_clear_items (rss_control); + } + + if (rss_control->details->font) { + gtk_object_unref (GTK_OBJECT (rss_control->details->font)); + } + + g_free (rss_control->details); + + NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object)); +} + + +/* Component embedding support */ +BonoboObject * +nautilus_rss_control_get_control (NautilusRSSControl *rss_control) +{ + return rss_control->details->control; +} + +static void +nautilus_rss_control_set_title (NautilusRSSControl *rss_control, const char *title) +{ + if (nautilus_strcmp (rss_control->details->title, title) == 0) { + return; + } + + if (rss_control->details->title) { + g_free (rss_control->details->title); + } + if (title != NULL) { + rss_control->details->title = g_strdup (title); + } else { + rss_control->details->title = NULL; + + } + gtk_widget_queue_draw (GTK_WIDGET (rss_control)); +} + + +static void +rss_logo_callback (GnomeVFSResult error, GdkPixbuf *pixbuf, gpointer callback_data) +{ + NautilusRSSControl *rss_control; + + rss_control = NAUTILUS_RSS_CONTROL (callback_data); + if (rss_control->details->logo) { + gdk_pixbuf_unref (rss_control->details->logo); + } + + if (pixbuf != NULL) { + gdk_pixbuf_ref (pixbuf); + rss_control->details->logo = pixbuf; + gtk_widget_queue_draw (GTK_WIDGET (rss_control)); + } +} + +/* completion routine invoked when we've loaded the rss file uri. Parse the xml document, and + * then extract the various elements that we require */ + +static void +rss_read_done_callback (GnomeVFSResult result, + GnomeVFSFileSize file_size, + char *file_contents, + gpointer callback_data) +{ + xmlDocPtr rss_document; + xmlNodePtr image_node, channel_node; + xmlNodePtr current_node, title_node, uri_node; + char *image_uri, *title; + NautilusRSSControl *rss_control; + NautilusPixbufLoadHandle *load_image_handle; + + char *buffer; + + /* make sure the read was successful */ + if (result != GNOME_VFS_OK) { + g_assert (file_contents == NULL); + return; + } + + rss_control = NAUTILUS_RSS_CONTROL (callback_data); + + /* Parse the rss file with gnome-xml. The gnome-xml parser requires a zero-terminated array. */ + buffer = g_realloc (file_contents, file_size + 1); + buffer[file_size] = '\0'; + rss_document = xmlParseMemory (buffer, file_size); + g_free (buffer); + + /* extract the title and set it */ + channel_node = nautilus_xml_get_child_by_name (xmlDocGetRootElement (rss_document), "channel"); + if (channel_node != NULL) { + title_node = nautilus_xml_get_child_by_name (channel_node, "title"); + if (title_node != NULL) { + title = xmlNodeGetContent (title_node); + if (title != NULL) { + nautilus_rss_control_set_title (rss_control, title); + xmlFree (title); + } + } + } + + /* extract the image uri and, if found, load it asynchronously */ + image_node = nautilus_xml_get_child_by_name (xmlDocGetRootElement (rss_document), "image"); + if (image_node != NULL) { + uri_node = nautilus_xml_get_child_by_name (image_node, "url"); + if (uri_node != NULL) { + image_uri = xmlNodeGetContent (uri_node); + if (image_uri != NULL) { + load_image_handle = nautilus_gdk_pixbuf_load_async (image_uri, rss_logo_callback, rss_control); + xmlFree (image_uri); + } + } + } + + /* extract the items in a loop */ + nautilus_rss_control_clear_items (rss_control); + current_node = rss_document->root->childs; + while (current_node != NULL) { + if (nautilus_strcmp (current_node->name, "item") == 0) { + title_node = nautilus_xml_get_child_by_name (current_node, "title"); + if (title_node) { + title = xmlNodeGetContent (title_node); + rss_control->details->items = g_list_append (rss_control->details->items, g_strdup (title)); + xmlFree (title); + } + } + current_node = current_node->next; + } + + /* we're done, so free everything up */ + xmlFreeDoc (rss_document); + + /* schedule a redraw to reflect the new contents */ + gtk_widget_queue_draw (GTK_WIDGET (rss_control)); +} + +/* load the rs file asynchronously */ +static void +load_rss_file (NautilusRSSControl *rss_control) +{ + char *title; + /* load the uri asynchrounously, calling a completion routine when completed */ + nautilus_read_entire_file_async (rss_control->details->rss_uri, rss_read_done_callback, rss_control); + + /* put up a title that's displayed while we wait */ + title = g_strdup_printf ("Loading %s", rss_control->details->rss_uri); + nautilus_rss_control_set_title (rss_control, title); + g_free (title); +} + +/* set the uri and load it */ +static void +nautilus_rss_control_set_uri (NautilusRSSControl *rss_control, const char *uri) +{ + + if (nautilus_strcmp (rss_control->details->rss_uri, uri) == 0) { + return; + } + + if (rss_control->details->rss_uri != NULL) { + g_free (rss_control->details->rss_uri); + rss_control->details->rss_uri = NULL; + } + + if (uri != NULL) { + rss_control->details->rss_uri = g_strdup (uri); + load_rss_file (rss_control); + } +} + + + +/* draw the logo image */ +static int +draw_rss_logo_image (NautilusRSSControl *rss_control, GdkPixbuf *pixbuf, int offset) +{ + GtkWidget *widget; + int logo_width, logo_height; + int v_offset; + + widget = GTK_WIDGET (rss_control); + v_offset = offset; + + if (rss_control->details->logo != NULL) { + logo_width = gdk_pixbuf_get_width (rss_control->details->logo); + logo_height = gdk_pixbuf_get_height (rss_control->details->logo); + + gdk_pixbuf_composite (rss_control->details->logo, pixbuf, 2, v_offset, logo_width, logo_height, + 2, v_offset, 1.0, 1.0, GDK_PIXBUF_ALPHA_BILEVEL, 255); + v_offset += logo_height + 2; + } + + return v_offset; +} + +/* draw the title */ +static int +draw_rss_title (NautilusRSSControl *rss_control, GdkPixbuf *pixbuf, int v_offset) +{ + int title_width, title_height; + GtkWidget *widget; + + if (rss_control->details->title == NULL || rss_control->details->font == NULL) { + return v_offset; + } + + widget = GTK_WIDGET (rss_control); + + /* first, measure the text */ + nautilus_scalable_font_measure_text (rss_control->details->font, + 18, 18, + rss_control->details->title, strlen (rss_control->details->title), + &title_width, + &title_height); + + /* draw the name into the pixbuf using anti-aliased text */ + nautilus_scalable_font_draw_text (rss_control->details->font, pixbuf, + 4, v_offset, + NULL, + 18, 18, + rss_control->details->title, strlen (rss_control->details->title), + NAUTILUS_RGB_COLOR_BLACK, + NAUTILUS_OPACITY_NONE); + + return v_offset + title_height; +} + +/* utility for underlining an item - assumes the pixbuf has an alpha channel */ +static void +draw_blue_line (GdkPixbuf *pixbuf, int x, int y, int width) +{ + guchar *pixels_ptr; + int row_stride, line_width, pixbuf_width, i; + + line_width = width; + pixbuf_width = gdk_pixbuf_get_width (pixbuf); + if ((x + line_width) > pixbuf_width) { + line_width = pixbuf_width - x - 1; + } + row_stride = gdk_pixbuf_get_rowstride (pixbuf); + pixels_ptr = gdk_pixbuf_get_pixels (pixbuf); + + pixels_ptr += (4 * x) + (row_stride * y); + for (i = 0; i < line_width; i++) { + *pixels_ptr++ = 0; + *pixels_ptr++ = 0; + *pixels_ptr++ = 159; + *pixels_ptr++ = 255; + + } +} + +/* draw the items */ +static int +draw_rss_items (NautilusRSSControl *rss_control, GdkPixbuf *pixbuf, int v_offset) +{ + GList *current_item; + int bullet_width, bullet_height; + int text_width, text_height, maximum_height; + + maximum_height = GTK_WIDGET (rss_control)->allocation.height - 16; + + if (rss_control->details->bullet) { + bullet_width = gdk_pixbuf_get_width (rss_control->details->bullet); + bullet_height = gdk_pixbuf_get_height (rss_control->details->bullet); + } else { + bullet_width = 0; + bullet_height = 0; + } + + current_item = rss_control->details->items; + + while (current_item != NULL) { + /* draw the text */ + + nautilus_scalable_font_measure_text (rss_control->details->font, + 12, 12, + current_item->data, strlen (current_item->data), + &text_width, + &text_height); + + nautilus_scalable_font_draw_text (rss_control->details->font, pixbuf, + 20, v_offset, + NULL, + 12, 12, + current_item->data, strlen (current_item->data), + NAUTILUS_RGB_COLOR_BLACK, + NAUTILUS_OPACITY_NONE); + + /* draw a blue underline to make it look like a link */ + draw_blue_line (pixbuf, 20, v_offset + 11, text_width); + + /* draw the bullet */ + if (rss_control->details->bullet) { + gdk_pixbuf_composite (rss_control->details->bullet, pixbuf, 2, v_offset - 2, bullet_width, bullet_height, + 2, v_offset - 2, 1.0, 1.0, GDK_PIXBUF_ALPHA_BILEVEL, 192); + } + + v_offset += 15; + current_item = current_item->next; + if (v_offset > maximum_height) { + break; + } + + } + + return v_offset; +} + +/* handle drawing the control */ +static void +nautilus_rss_control_draw (GtkWidget *widget, GdkRectangle *box) +{ + NautilusRSSControl *control; + GdkPixbuf *temp_pixbuf; + int width, height, v_offset; + + /* allocate a pixbuf to draw into */ + width = widget->allocation.width; + height = widget->allocation.height; + + temp_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); + nautilus_gdk_pixbuf_fill_rectangle_with_color (temp_pixbuf, NULL, 0xFFEFEFEF); + + g_return_if_fail (widget != NULL); + g_return_if_fail (NAUTILUS_IS_RSS_CONTROL (widget)); + + control = NAUTILUS_RSS_CONTROL (widget); + + v_offset = draw_rss_logo_image (control, temp_pixbuf, 2); + v_offset = draw_rss_title (control, temp_pixbuf, v_offset); + v_offset += 6; + v_offset = draw_rss_items (control, temp_pixbuf, v_offset); + + /* blit the pixbuf to the drawable, then release it */ + gdk_pixbuf_render_to_drawable_alpha (temp_pixbuf, + widget->window, + 0, 0, + widget->allocation.x, widget->allocation.y, + width, height, + GDK_PIXBUF_ALPHA_BILEVEL, 128, + GDK_RGB_DITHER_MAX, + 0, 0); + + gdk_pixbuf_unref (temp_pixbuf); +} + +/* handle expose events */ +static int +nautilus_rss_control_expose (GtkWidget *widget, GdkEventExpose *event) +{ + GdkRectangle box; + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (NAUTILUS_IS_RSS_CONTROL (widget), FALSE); + + box.x = 0; box.y = 0; + box.width = widget->allocation.width; + box.height = widget->allocation.height; + + nautilus_rss_control_draw (widget, &box); + return FALSE; +} + +/* handle button press events */ +static gboolean +nautilus_rss_control_button_press_event (GtkWidget *widget, GdkEventButton *event) +{ + g_message ("button press"); + return FALSE; +} + diff --git a/components/rss-control/nautilus-rss-control.h b/components/rss-control/nautilus-rss-control.h new file mode 100644 index 000000000..e73c31bbc --- /dev/null +++ b/components/rss-control/nautilus-rss-control.h @@ -0,0 +1,54 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* + * Copyright (C) 2000 Eazel, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Andy Hertzfeld + */ + +/* header file for the rss control component */ + +#ifndef NAUTILUS_RSS_CONTROL_H +#define NAUTILUS_RSS_CONTROL_H + +#include <bonobo.h> +#include <gtk/gtkeventbox.h> +typedef struct _NautilusRSSControl NautilusRSSControl; +typedef struct _NautilusRSSControlClass NautilusRSSControlClass; + +#define NAUTILUS_TYPE_RSS_CONTROL (nautilus_rss_control_get_type ()) +#define NAUTILUS_RSS_CONTROL(obj) (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_RSS_CONTROL, NautilusRSSControl)) +#define NAUTILUS_RSS_CONTROL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_RSS_CONTROL, NautilusRSSControlClass)) +#define NAUTILUS_IS_RSS_CONTROL(obj) (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_RSS_CONTROL)) +#define NAUTILUS_IS_RSS_CONTROL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_RSS_CONTROL)) + +typedef struct _NautilusRSSControlDetails NautilusRSSControlDetails; + +struct _NautilusRSSControl { + GtkEventBox parent; + NautilusRSSControlDetails *details; +}; + +struct _NautilusRSSControlClass { + GtkEventBoxClass parent_class; +}; + +/* GtkObject support */ +GtkType nautilus_rss_control_get_type (void); +BonoboObject* nautilus_rss_control_get_control (NautilusRSSControl *rss_control); + +#endif /* NAUTILUS_RSS_CONTROL_H */ diff --git a/components/rss-control/nautilus-rss-control.oafinfo b/components/rss-control/nautilus-rss-control.oafinfo new file mode 100644 index 000000000..9d21acf6a --- /dev/null +++ b/components/rss-control/nautilus-rss-control.oafinfo @@ -0,0 +1,20 @@ +<oaf_info> + +<oaf_server iid="OAFIID:nautilus_rss_control_factory:1230" type="exe" location="nautilus-rss-control"> +<oaf_attribute name="repo_ids" type="stringv"> +<item value="IDL:Bonobo/GenericFactory:1.0"/> +</oaf_attribute> +<oaf_attribute name="name" type="string" value="rss control factory"/> +<oaf_attribute name="description" type="string" value="rss control object factory"/> +</oaf_server> + +<oaf_server iid="OAFIID:nautilus_rss_control:1230" type="factory" location="OAFIID:nautilus_rss_control_factory:1230"> +<oaf_attribute name="repo_ids" type="stringv"> +<item value="IDL:Bonobo/Control:1.0"/> +<item value="IDL:Bonobo/Unknown:1.0"/> +</oaf_attribute> +<oaf_attribute name="name" type="string" value="rss control"/> +<oaf_attribute name="description" type="string" value="nautilus rss control object"/> +</oaf_server> + +</oaf_info> diff --git a/configure.in b/configure.in index b820f87fc..0a353e521 100644 --- a/configure.in +++ b/configure.in @@ -795,6 +795,7 @@ components/notes/Makefile components/rpmview/Makefile components/sample/Makefile components/mozilla/Makefile +components/rss-control/Makefile components/services/Makefile components/services/trilobite/Makefile components/services/trilobite/idl/Makefile diff --git a/icons/Makefile.am b/icons/Makefile.am index 45e8f5579..ebf5909c0 100644 --- a/icons/Makefile.am +++ b/icons/Makefile.am @@ -11,6 +11,7 @@ icon_DATA =\ about_background.png \ audio.png \ backgrounds.png \ + bullet.png \ chit_frame.png \ colors.png \ computer.png \ diff --git a/icons/bullet.png b/icons/bullet.png Binary files differnew file mode 100644 index 000000000..b488acd55 --- /dev/null +++ b/icons/bullet.png diff --git a/libnautilus-extensions/nautilus-file-utilities.c b/libnautilus-extensions/nautilus-file-utilities.c index 2eb762eed..66f773338 100644 --- a/libnautilus-extensions/nautilus-file-utilities.c +++ b/libnautilus-extensions/nautilus-file-utilities.c @@ -614,22 +614,7 @@ nautilus_get_user_main_directory (void) image_uri); nautilus_file_unref (file); } - - /* now do the same for the about file */ - temp_str = g_strdup_printf ("%s/About.html", user_main_directory); - file_uri = gnome_vfs_get_uri_from_local_path (temp_str); - g_free (temp_str); - - file = nautilus_file_get (file_uri); - if (file != NULL) { - nautilus_file_set_metadata (file, - NAUTILUS_METADATA_KEY_CUSTOM_ICON, - NULL, - image_uri); - nautilus_file_unref (file); - } - g_free (file_uri); - + g_free (image_uri); /* install the default link set */ diff --git a/libnautilus-extensions/nautilus-icon-canvas-item.c b/libnautilus-extensions/nautilus-icon-canvas-item.c index d7c091785..ec61082aa 100644 --- a/libnautilus-extensions/nautilus-icon-canvas-item.c +++ b/libnautilus-extensions/nautilus-icon-canvas-item.c @@ -76,6 +76,10 @@ struct NautilusIconCanvasItemDetails { GdkFont *font; NautilusEmblemAttachPoints *attach_points; + /* stuff for controls; if this gets too big, we've put it in a separate struct */ + GtkWidget *control; /* optional Bonobo control*/ + guint control_destroy_id; + /* Size of the text at current font. */ int text_width; int text_height; @@ -89,7 +93,7 @@ struct NautilusIconCanvasItemDetails { guint is_highlighted_for_drop : 1; guint show_stretch_handles : 1; guint is_prelit : 1; - + guint in_control_destroy : 1; gboolean is_renaming; /* Font stuff whilst in smooth mode */ @@ -103,7 +107,7 @@ enum { ARG_EDITABLE_TEXT, ARG_ADDITIONAL_TEXT, ARG_FONT, - ARG_HIGHLIGHTED_FOR_SELECTION, + ARG_HIGHLIGHTED_FOR_SELECTION, ARG_HIGHLIGHTED_AS_KEYBOARD_FOCUS, ARG_HIGHLIGHTED_FOR_DROP, ARG_MODIFIER, @@ -318,6 +322,11 @@ nautilus_icon_canvas_item_destroy (GtkObject *object) gdk_font_unref (details->font); } + if (details->control && !details->in_control_destroy) { + gtk_signal_disconnect (GTK_OBJECT (details->control), details->control_destroy_id); + gtk_widget_destroy (details->control); + } + gtk_object_unref (GTK_OBJECT (icon_item->details->smooth_font)); icon_item->details->smooth_font = NULL; @@ -351,6 +360,28 @@ invalidate_text_dimensions (NautilusIconCanvasItem *item) item->details->text_height = -1; } +/* abstraction layer for icon width and height, to separate it from pixbuf with and height */ +static int +nautilus_icon_canvas_item_get_icon_width (NautilusIconCanvasItem *item) +{ + if (item->details->pixbuf == NULL) { + return NAUTILUS_ICON_SIZE_STANDARD; + } + + return gdk_pixbuf_get_width (item->details->pixbuf); +} + +static int +nautilus_icon_canvas_item_get_icon_height (NautilusIconCanvasItem *item) +{ + if (item->details->pixbuf == NULL) { + return NAUTILUS_ICON_SIZE_STANDARD; + } + + return gdk_pixbuf_get_height (item->details->pixbuf); +} + + /* Set_arg handler for the icon item. */ static void nautilus_icon_canvas_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) @@ -433,8 +464,7 @@ nautilus_icon_canvas_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) case ARG_SMOOTH_FONT_SIZE: nautilus_icon_canvas_item_set_smooth_font_size (NAUTILUS_ICON_CANVAS_ITEM (object), GTK_VALUE_UINT (*arg)); - break; - + break; default: g_warning ("nautilus_icons_view_item_item_set_arg on unknown argument"); return; @@ -443,12 +473,27 @@ nautilus_icon_canvas_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (object)); } +/* handler for the control's destroy signal */ +static void +do_control_destroy (GtkObject *object, gpointer data) +{ + NautilusIconCanvasItemDetails *details; + + details = NAUTILUS_ICON_CANVAS_ITEM (data)->details; + + details->in_control_destroy = TRUE; + + gtk_object_destroy (GTK_OBJECT (data)); +} + /* Get_arg handler for the icon item */ static void nautilus_icon_canvas_item_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) { NautilusIconCanvasItemDetails *details; + GnomeCanvasItem *item; + item = GNOME_CANVAS_ITEM (object); details = NAUTILUS_ICON_CANVAS_ITEM (object)->details; switch (arg_id) { @@ -496,12 +541,27 @@ GdkPixbuf * nautilus_icon_canvas_item_get_image (NautilusIconCanvasItem *item) { NautilusIconCanvasItemDetails *details; - + int width, height; + GdkPixbuf *pixbuf; + g_return_val_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item), NULL); details = item->details; - return details->pixbuf; + if (details->control) { + width = details->control->allocation.width; + height = details->control->allocation.height; + pixbuf = nautilus_gdk_pixbuf_get_from_window_safe (details->control->window, + details->control->allocation.x, + details->control->allocation.y, + details->control->allocation.width, + details->control->allocation.height); + } else { + pixbuf = details->pixbuf; + gdk_pixbuf_ref (pixbuf); + } + + return pixbuf; } void @@ -603,6 +663,12 @@ recompute_bounding_box (NautilusIconCanvasItem *icon_item) item->y1 = top_left.y; item->x2 = bottom_right.x; item->y2 = bottom_right.y; + + if (icon_item->details->control) + gtk_layout_move (GTK_LAYOUT (item->canvas), icon_item->details->control, + item->x1 + item->canvas->zoom_xofs, + item->y1 + item->canvas->zoom_yofs); + } void @@ -622,6 +688,16 @@ nautilus_icon_canvas_item_update_bounds (NautilusIconCanvasItem *item) return; } + /* if there is an embedded control, resize it appropriately */ + if (item->details->control) { + /* for now, size it the same as the underlying image */ + int image_width = nautilus_icon_canvas_item_get_icon_width (item); + int image_height = nautilus_icon_canvas_item_get_icon_height (item); + + gtk_widget_set_usize (item->details->control, + image_width, image_height); + } + /* Send out the bounds_changed signal and queue a redraw. */ nautilus_gnome_canvas_request_redraw_rectangle (GNOME_CANVAS_ITEM (item)->canvas, &before); @@ -766,7 +842,7 @@ draw_or_measure_label_text (NautilusIconCanvasItem *item, canvas_item = GNOME_CANVAS_ITEM (item); if (drawable != NULL) { - icon_width = details->pixbuf == NULL ? 0 : gdk_pixbuf_get_width (details->pixbuf); + icon_width = details->pixbuf == NULL ? 0 : nautilus_icon_canvas_item_get_icon_width (item); gc = gdk_gc_new (canvas_item->canvas->layout.bin_window); gdk_gc_get_values (gc, &save_gc); } @@ -1171,11 +1247,17 @@ emblem_layout_next (EmblemLayout *layout, /* Return the rectangle and pixbuf. */ *emblem_pixbuf = pixbuf; - emblem_rect->x0 = x - width / 2; - emblem_rect->y0 = y - height / 2; + if (layout->icon_item->details->control) { + emblem_rect->x0 = x; + emblem_rect->y0 = y; + } else { + emblem_rect->x0 = x - width / 2; + emblem_rect->y0 = y - height / 2; + } + emblem_rect->x1 = emblem_rect->x0 + width; emblem_rect->y1 = emblem_rect->y0 + height; - + return TRUE; } @@ -1214,35 +1296,7 @@ draw_pixbuf (GdkPixbuf *pixbuf, GdkDrawable *drawable, int x, int y) static void draw_pixbuf_aa (GdkPixbuf *pixbuf, GnomeCanvasBuf *buf, double affine[6], int x_offset, int y_offset) { - void (* affine_function) - (art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, - const art_u8 *src, int src_width, int src_height, int src_rowstride, - const double affine[6], - ArtFilterLevel level, - ArtAlphaGamma *alpha_gamma); - - affine[4] += x_offset; - affine[5] += y_offset; - - affine_function = gdk_pixbuf_get_has_alpha (pixbuf) - ? art_rgb_rgba_affine - : art_rgb_affine; - - (* affine_function) - (buf->buf, - buf->rect.x0, buf->rect.y0, - buf->rect.x1, buf->rect.y1, - buf->buf_rowstride, - gdk_pixbuf_get_pixels (pixbuf), - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf), - gdk_pixbuf_get_rowstride (pixbuf), - affine, - ART_FILTER_NEAREST, - NULL); - - affine[4] -= x_offset; - affine[5] -= y_offset; + nautilus_gnome_canvas_draw_pixbuf (buf, pixbuf, affine[4] + x_offset, affine[5] + y_offset); } /* shared code to highlight or dim the passed-in pixbuf */ @@ -1324,23 +1378,30 @@ nautilus_icon_canvas_item_draw (GnomeCanvasItem *item, GdkDrawable *drawable, icon_item = NAUTILUS_ICON_CANVAS_ITEM (item); details = icon_item->details; - /* Draw the pixbuf. */ - if (details->pixbuf == NULL) { - return; - } - /* Compute icon rectangle in drawable coordinates. */ - get_icon_canvas_rectangle (icon_item, &icon_rect); - icon_rect.x0 -= x; - icon_rect.y0 -= y; - icon_rect.x1 -= x; - icon_rect.y1 -= y; + /* draw the icon or widget */ + if (icon_item->details->control) { + gtk_widget_queue_draw (icon_item->details->control); + } else { + if (details->pixbuf != NULL) { + + /* Compute icon rectangle in drawable coordinates. */ + get_icon_canvas_rectangle (icon_item, &icon_rect); + icon_rect.x0 -= x; + icon_rect.y0 -= y; + icon_rect.x1 -= x; + icon_rect.y1 -= y; + + /* if the pre-lit or selection flag is set, make a pre-lit or darkened pixbuf and draw that instead */ + temp_pixbuf = map_pixbuf (icon_item); + draw_pixbuf (temp_pixbuf, drawable, icon_rect.x0, icon_rect.y0); + + if (temp_pixbuf != details->pixbuf) { + gdk_pixbuf_unref (temp_pixbuf); + } + + } - /* if the pre-lit or selection flag is set, make a pre-lit or darkened pixbuf and draw that instead */ - temp_pixbuf = map_pixbuf (icon_item); - draw_pixbuf (temp_pixbuf, drawable, icon_rect.x0, icon_rect.y0); - if (temp_pixbuf != details->pixbuf) { - gdk_pixbuf_unref (temp_pixbuf); } /* Draw the emblem pixbufs. */ @@ -1425,7 +1486,7 @@ draw_or_measure_label_text_aa (NautilusIconCanvasItem *item, if (destination_pixbuf == NULL ) { icon_width = 0; } else { - icon_width = details->pixbuf == NULL ? 0 : gdk_pixbuf_get_width (details->pixbuf); + icon_width = details->pixbuf == NULL ? 0 : nautilus_icon_canvas_item_get_icon_width (item); } max_text_width = floor (nautilus_icon_canvas_item_get_max_text_width (item)); @@ -1670,9 +1731,6 @@ nautilus_icon_canvas_item_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf) icon_item = NAUTILUS_ICON_CANVAS_ITEM (item); - /* map the pixbuf for selection or other effects */ - temp_pixbuf = map_pixbuf (icon_item); - /* Compute the affine transform, but force the scale to 1.0 * because the icon factory does the scaling for us. */ @@ -1689,13 +1747,19 @@ nautilus_icon_canvas_item_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf) buf->is_bg = FALSE; } - /* draw the icon */ - draw_pixbuf_aa (temp_pixbuf, buf, i2c, 0, 0); + /* draw the icon or widget */ + if (icon_item->details->control) { + gtk_widget_queue_draw (icon_item->details->control); + } else { + /* map the pixbuf for selection or other effects */ + temp_pixbuf = map_pixbuf (icon_item); + draw_pixbuf_aa (temp_pixbuf, buf, i2c, 0, 0); - if (temp_pixbuf != icon_item->details->pixbuf) { - gdk_pixbuf_unref (temp_pixbuf); + if (temp_pixbuf != icon_item->details->pixbuf) { + gdk_pixbuf_unref (temp_pixbuf); + } } - + /* draw the emblems */ get_icon_canvas_rectangle (icon_item, &icon_rect); @@ -1926,8 +1990,8 @@ nautilus_icon_canvas_item_bounds (GnomeCanvasItem *item, icon_rect.x1 = 0; icon_rect.y1 = 0; } else { - icon_rect.x1 = gdk_pixbuf_get_width (details->pixbuf); - icon_rect.y1 = gdk_pixbuf_get_height (details->pixbuf); + icon_rect.x1 = nautilus_icon_canvas_item_get_icon_width (icon_item); + icon_rect.y1 = nautilus_icon_canvas_item_get_icon_height (icon_item); } /* Compute text rectangle. */ @@ -1973,8 +2037,8 @@ nautilus_icon_canvas_item_get_icon_rectangle (NautilusIconCanvasItem *item, pixbuf = item->details->pixbuf; pixels_per_unit = GNOME_CANVAS_ITEM (item)->canvas->pixels_per_unit; - rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_width (pixbuf)) / pixels_per_unit; - rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_height (pixbuf)) / pixels_per_unit; + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : nautilus_icon_canvas_item_get_icon_width (item)) / pixels_per_unit; + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : nautilus_icon_canvas_item_get_icon_height (item)) / pixels_per_unit; } /* Get the rectangle of the icon only, in canvas coordinates. */ @@ -2000,8 +2064,8 @@ get_icon_canvas_rectangle (NautilusIconCanvasItem *item, pixbuf = item->details->pixbuf; - rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_width (pixbuf)); - rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_height (pixbuf)); + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : nautilus_icon_canvas_item_get_icon_width (item)); + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : nautilus_icon_canvas_item_get_icon_height (item)); } void @@ -2158,6 +2222,42 @@ nautilus_icon_canvas_item_set_smooth_font (NautilusIconCanvasItem *icon_item, } } +GtkWidget * +nautilus_icon_canvas_item_get_control (NautilusIconCanvasItem *icon_item) +{ + return icon_item->details->control; +} + +void +nautilus_icon_canvas_item_set_control (NautilusIconCanvasItem *icon_item, GtkWidget *control) +{ + GnomeCanvasItem *item; + + if (icon_item->details->control == control) { + return; + } + + item = GNOME_CANVAS_ITEM (icon_item); + if (icon_item->details->control) { + gtk_signal_disconnect (GTK_OBJECT (icon_item->details->control), icon_item->details->control_destroy_id); + gtk_container_remove (GTK_CONTAINER (item->canvas), icon_item->details->control); + icon_item->details->control = NULL; + } + + if (control) { + g_message ("adding control..."); + icon_item->details->control = control; + icon_item->details->control_destroy_id = gtk_signal_connect (GTK_OBJECT (control), + "destroy", + (GtkSignalFunc) do_control_destroy, + item); + gtk_widget_show (control); + gtk_layout_put (GTK_LAYOUT (item->canvas), control, + item->x1 + item->canvas->zoom_xofs, + item->y1 + item->canvas->zoom_yofs); + } +} + void nautilus_icon_canvas_item_set_smooth_font_size (NautilusIconCanvasItem *icon_item, guint font_size) diff --git a/libnautilus-extensions/nautilus-icon-canvas-item.h b/libnautilus-extensions/nautilus-icon-canvas-item.h index 8de5c8f23..c9d44375b 100644 --- a/libnautilus-extensions/nautilus-icon-canvas-item.h +++ b/libnautilus-extensions/nautilus-icon-canvas-item.h @@ -80,6 +80,10 @@ const char *nautilus_icon_canvas_item_get_editable_text (NautilusIconCanv void nautilus_icon_canvas_item_set_renaming (NautilusIconCanvasItem *icon_item, gboolean state); +GtkWidget * nautilus_icon_canvas_item_get_control (NautilusIconCanvasItem *icon_item); +void nautilus_icon_canvas_item_set_control (NautilusIconCanvasItem *icon_item, + GtkWidget *control); + /* geometry and hit testing */ gboolean nautilus_icon_canvas_item_hit_test_rectangle (NautilusIconCanvasItem *item, diff --git a/libnautilus-extensions/nautilus-icon-container.c b/libnautilus-extensions/nautilus-icon-container.c index c14dd664c..95e3852bf 100644 --- a/libnautilus-extensions/nautilus-icon-container.c +++ b/libnautilus-extensions/nautilus-icon-container.c @@ -160,6 +160,7 @@ enum { CONTEXT_CLICK_SELECTION, MIDDLE_CLICK, GET_CONTAINER_URI, + GET_ICON_CONTROL, GET_ICON_IMAGES, GET_ICON_TEXT, GET_ICON_URI, @@ -2974,6 +2975,16 @@ nautilus_icon_container_initialize_class (NautilusIconContainerClass *class) gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); + signals[GET_ICON_CONTROL] + = gtk_signal_new ("get_icon_control", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (NautilusIconContainerClass, + get_icon_control), + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); signals[GET_ICON_IMAGES] = gtk_signal_new ("get_icon_images", GTK_RUN_LAST, @@ -3528,9 +3539,10 @@ nautilus_icon_container_update_icon (NautilusIconContainer *container, GdkPixbuf *pixbuf, *emblem_pixbuf, *saved_pixbuf; GList *emblem_scalable_icons, *emblem_pixbufs, *p; char *editable_text, *additional_text; + GtkWidget *embedded_control; GdkFont *font; guint smooth_font_size; - + if (icon == NULL) { return; } @@ -3562,8 +3574,7 @@ nautilus_icon_container_update_icon (NautilusIconContainer *container, nautilus_scalable_icon_unref (scalable_icon); - /* in the rare case an image is too small, scale it up */ - + /* in the rare case an image is too small, scale it up */ width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); if (width < min_image_size || height < min_image_size) { @@ -3571,9 +3582,11 @@ nautilus_icon_container_update_icon (NautilusIconContainer *container, /* don't let it exceed the maximum width in the other dimension */ scale_factor = MIN (scale_factor, max_image_size / width); scale_factor = MIN (scale_factor, max_image_size / height); - + scaled_width = floor (width * scale_factor + .5); scaled_height = floor (height * scale_factor + .5); + + /* scale the image to the calculated size */ saved_pixbuf = pixbuf; pixbuf = gdk_pixbuf_scale_simple (pixbuf, scaled_width, scaled_height, GDK_INTERP_BILINEAR); gdk_pixbuf_unref (saved_pixbuf); @@ -3608,13 +3621,22 @@ nautilus_icon_container_update_icon (NautilusIconContainer *container, emblem_pixbufs = g_list_reverse (emblem_pixbufs); nautilus_scalable_icon_list_free (emblem_scalable_icons); + /* get the embedded control, if any */ + embedded_control = nautilus_icon_canvas_item_get_control (icon->item); + if (embedded_control == NULL) { + gtk_signal_emit (GTK_OBJECT (container), + signals[GET_ICON_CONTROL], + icon->data, + &embedded_control); + } + /* Get both editable and non-editable icon text */ gtk_signal_emit (GTK_OBJECT (container), signals[GET_ICON_TEXT], icon->data, &editable_text, &additional_text); - + /* If name of icon being renamed was changed from elsewhere, end renaming mode. * Alternatively, we could replace the characters in the editable text widget * with the new name, but that could cause timing problems if the user just @@ -3639,6 +3661,8 @@ nautilus_icon_container_update_icon (NautilusIconContainer *container, "smooth_font", details->smooth_label_font, NULL); + nautilus_icon_canvas_item_set_control (icon->item, embedded_control); + nautilus_icon_canvas_item_set_image (icon->item, pixbuf); nautilus_icon_canvas_item_set_attach_points (icon->item, &attach_points); nautilus_icon_canvas_item_set_emblems (icon->item, emblem_pixbufs); diff --git a/libnautilus-extensions/nautilus-icon-container.h b/libnautilus-extensions/nautilus-icon-container.h index a16d99e30..e551f184f 100644 --- a/libnautilus-extensions/nautilus-icon-container.h +++ b/libnautilus-extensions/nautilus-icon-container.h @@ -107,6 +107,10 @@ typedef struct { gboolean (* get_stored_icon_position) (NautilusIconContainer *container, NautilusIconData *data, NautilusIconPosition *position); + void + (* get_icon_control) (NautilusIconContainer *container, + NautilusIconData *data, + GtkWidget **control); NautilusScalableIcon * (* get_icon_images) (NautilusIconContainer *container, NautilusIconData *data, diff --git a/libnautilus-extensions/nautilus-icon-dnd.c b/libnautilus-extensions/nautilus-icon-dnd.c index 4098056b7..9eb050891 100644 --- a/libnautilus-extensions/nautilus-icon-dnd.c +++ b/libnautilus-extensions/nautilus-icon-dnd.c @@ -1257,6 +1257,7 @@ nautilus_icon_dnd_begin_drag (NautilusIconContainer *container, &pixmap_for_dragged_file, &mask_for_dragged_file, NAUTILUS_STANDARD_ALPHA_THRESHHOLD); + gdk_pixbuf_unref (pixbuf); /* compute the image's offset */ nautilus_icon_canvas_item_get_icon_rectangle diff --git a/libnautilus-extensions/nautilus-link.c b/libnautilus-extensions/nautilus-link.c index 407a29540..10edebecc 100644 --- a/libnautilus-extensions/nautilus-link.c +++ b/libnautilus-extensions/nautilus-link.c @@ -287,6 +287,35 @@ nautilus_link_local_get_additional_text (const char *path) (path, NAUTILUS_METADATA_KEY_EXTRA_TEXT); } +void nautilus_link_local_get_component_info (const char *path, + char **control_moniker, char **control_data) +{ + xmlDoc *document; + const char *mime_type; + + *control_moniker = NULL; + *control_data = NULL; + + /* Check mime type. Exit if it is not a nautilus link */ + mime_type = gnome_vfs_get_file_mime_type (path, NULL, FALSE); + if (strcmp (mime_type, "application/x-nautilus-link") != 0) { + return; + } + + document = xmlParseFile (path); + if (document != NULL) { + *control_moniker = xml_get_root_property (document, + NAUTILUS_METADATA_KEY_CONTROL_MONIKER); + + *control_data = xml_get_root_property (document, + NAUTILUS_METADATA_KEY_CONTROL_DATA); + + xmlFreeDoc (document); + } +} + + + /* utility to return the local pathname of a cached icon, given the leaf name */ /* if the icons directory hasn't been created yet, create it */ static char * diff --git a/libnautilus-extensions/nautilus-link.h b/libnautilus-extensions/nautilus-link.h index 1f707f0c7..6a6df0852 100644 --- a/libnautilus-extensions/nautilus-link.h +++ b/libnautilus-extensions/nautilus-link.h @@ -72,14 +72,21 @@ gboolean nautilus_link_local_set_link_uri (const char * none. Despite the fact that it takes a URI parameter, works only if * the file is local and does sync. I/O. */ -char * nautilus_link_local_get_additional_text (const char *path); +char * nautilus_link_local_get_additional_text (const char *path); /* Returns the image associated with a link file. Despite the fact * that it takes a URI parameter, works only if the file is local and * does sync. I/O on the link, although it does async. on the image * and caches if the image is remote. */ -char * nautilus_link_local_get_image_uri (const char *path); +char * nautilus_link_local_get_image_uri (const char *path); + +/* returns the moniker of the component associated with a link file, as well as configuration data. + * It works only if the file is local and does sync. I/O. + */ +void nautilus_link_local_get_component_info (const char *path, + char **control_moniker, + char **control_data); /* Returns the link type of a link file. * Works only if the file is local and does sync. I/O diff --git a/libnautilus-extensions/nautilus-metadata.h b/libnautilus-extensions/nautilus-metadata.h index 3de64b564..18f8a75e3 100644 --- a/libnautilus-extensions/nautilus-metadata.h +++ b/libnautilus-extensions/nautilus-metadata.h @@ -72,6 +72,9 @@ #define NAUTILUS_METADATA_KEY_ICON_SCALE "ICON_SCALE" #define NAUTILUS_METADATA_KEY_CUSTOM_ICON "CUSTOM_ICON" +#define NAUTILUS_METADATA_KEY_CONTROL_MONIKER "CONTROL_MONIKER" +#define NAUTILUS_METADATA_KEY_CONTROL_DATA "CONTROL_DATA" + /* per link file */ #define NAUTILUS_METADATA_KEY_EXTRA_TEXT "EXTRA_TEXT" diff --git a/libnautilus-private/nautilus-file-utilities.c b/libnautilus-private/nautilus-file-utilities.c index 2eb762eed..66f773338 100644 --- a/libnautilus-private/nautilus-file-utilities.c +++ b/libnautilus-private/nautilus-file-utilities.c @@ -614,22 +614,7 @@ nautilus_get_user_main_directory (void) image_uri); nautilus_file_unref (file); } - - /* now do the same for the about file */ - temp_str = g_strdup_printf ("%s/About.html", user_main_directory); - file_uri = gnome_vfs_get_uri_from_local_path (temp_str); - g_free (temp_str); - - file = nautilus_file_get (file_uri); - if (file != NULL) { - nautilus_file_set_metadata (file, - NAUTILUS_METADATA_KEY_CUSTOM_ICON, - NULL, - image_uri); - nautilus_file_unref (file); - } - g_free (file_uri); - + g_free (image_uri); /* install the default link set */ diff --git a/libnautilus-private/nautilus-icon-canvas-item.c b/libnautilus-private/nautilus-icon-canvas-item.c index d7c091785..ec61082aa 100644 --- a/libnautilus-private/nautilus-icon-canvas-item.c +++ b/libnautilus-private/nautilus-icon-canvas-item.c @@ -76,6 +76,10 @@ struct NautilusIconCanvasItemDetails { GdkFont *font; NautilusEmblemAttachPoints *attach_points; + /* stuff for controls; if this gets too big, we've put it in a separate struct */ + GtkWidget *control; /* optional Bonobo control*/ + guint control_destroy_id; + /* Size of the text at current font. */ int text_width; int text_height; @@ -89,7 +93,7 @@ struct NautilusIconCanvasItemDetails { guint is_highlighted_for_drop : 1; guint show_stretch_handles : 1; guint is_prelit : 1; - + guint in_control_destroy : 1; gboolean is_renaming; /* Font stuff whilst in smooth mode */ @@ -103,7 +107,7 @@ enum { ARG_EDITABLE_TEXT, ARG_ADDITIONAL_TEXT, ARG_FONT, - ARG_HIGHLIGHTED_FOR_SELECTION, + ARG_HIGHLIGHTED_FOR_SELECTION, ARG_HIGHLIGHTED_AS_KEYBOARD_FOCUS, ARG_HIGHLIGHTED_FOR_DROP, ARG_MODIFIER, @@ -318,6 +322,11 @@ nautilus_icon_canvas_item_destroy (GtkObject *object) gdk_font_unref (details->font); } + if (details->control && !details->in_control_destroy) { + gtk_signal_disconnect (GTK_OBJECT (details->control), details->control_destroy_id); + gtk_widget_destroy (details->control); + } + gtk_object_unref (GTK_OBJECT (icon_item->details->smooth_font)); icon_item->details->smooth_font = NULL; @@ -351,6 +360,28 @@ invalidate_text_dimensions (NautilusIconCanvasItem *item) item->details->text_height = -1; } +/* abstraction layer for icon width and height, to separate it from pixbuf with and height */ +static int +nautilus_icon_canvas_item_get_icon_width (NautilusIconCanvasItem *item) +{ + if (item->details->pixbuf == NULL) { + return NAUTILUS_ICON_SIZE_STANDARD; + } + + return gdk_pixbuf_get_width (item->details->pixbuf); +} + +static int +nautilus_icon_canvas_item_get_icon_height (NautilusIconCanvasItem *item) +{ + if (item->details->pixbuf == NULL) { + return NAUTILUS_ICON_SIZE_STANDARD; + } + + return gdk_pixbuf_get_height (item->details->pixbuf); +} + + /* Set_arg handler for the icon item. */ static void nautilus_icon_canvas_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) @@ -433,8 +464,7 @@ nautilus_icon_canvas_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) case ARG_SMOOTH_FONT_SIZE: nautilus_icon_canvas_item_set_smooth_font_size (NAUTILUS_ICON_CANVAS_ITEM (object), GTK_VALUE_UINT (*arg)); - break; - + break; default: g_warning ("nautilus_icons_view_item_item_set_arg on unknown argument"); return; @@ -443,12 +473,27 @@ nautilus_icon_canvas_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (object)); } +/* handler for the control's destroy signal */ +static void +do_control_destroy (GtkObject *object, gpointer data) +{ + NautilusIconCanvasItemDetails *details; + + details = NAUTILUS_ICON_CANVAS_ITEM (data)->details; + + details->in_control_destroy = TRUE; + + gtk_object_destroy (GTK_OBJECT (data)); +} + /* Get_arg handler for the icon item */ static void nautilus_icon_canvas_item_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) { NautilusIconCanvasItemDetails *details; + GnomeCanvasItem *item; + item = GNOME_CANVAS_ITEM (object); details = NAUTILUS_ICON_CANVAS_ITEM (object)->details; switch (arg_id) { @@ -496,12 +541,27 @@ GdkPixbuf * nautilus_icon_canvas_item_get_image (NautilusIconCanvasItem *item) { NautilusIconCanvasItemDetails *details; - + int width, height; + GdkPixbuf *pixbuf; + g_return_val_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item), NULL); details = item->details; - return details->pixbuf; + if (details->control) { + width = details->control->allocation.width; + height = details->control->allocation.height; + pixbuf = nautilus_gdk_pixbuf_get_from_window_safe (details->control->window, + details->control->allocation.x, + details->control->allocation.y, + details->control->allocation.width, + details->control->allocation.height); + } else { + pixbuf = details->pixbuf; + gdk_pixbuf_ref (pixbuf); + } + + return pixbuf; } void @@ -603,6 +663,12 @@ recompute_bounding_box (NautilusIconCanvasItem *icon_item) item->y1 = top_left.y; item->x2 = bottom_right.x; item->y2 = bottom_right.y; + + if (icon_item->details->control) + gtk_layout_move (GTK_LAYOUT (item->canvas), icon_item->details->control, + item->x1 + item->canvas->zoom_xofs, + item->y1 + item->canvas->zoom_yofs); + } void @@ -622,6 +688,16 @@ nautilus_icon_canvas_item_update_bounds (NautilusIconCanvasItem *item) return; } + /* if there is an embedded control, resize it appropriately */ + if (item->details->control) { + /* for now, size it the same as the underlying image */ + int image_width = nautilus_icon_canvas_item_get_icon_width (item); + int image_height = nautilus_icon_canvas_item_get_icon_height (item); + + gtk_widget_set_usize (item->details->control, + image_width, image_height); + } + /* Send out the bounds_changed signal and queue a redraw. */ nautilus_gnome_canvas_request_redraw_rectangle (GNOME_CANVAS_ITEM (item)->canvas, &before); @@ -766,7 +842,7 @@ draw_or_measure_label_text (NautilusIconCanvasItem *item, canvas_item = GNOME_CANVAS_ITEM (item); if (drawable != NULL) { - icon_width = details->pixbuf == NULL ? 0 : gdk_pixbuf_get_width (details->pixbuf); + icon_width = details->pixbuf == NULL ? 0 : nautilus_icon_canvas_item_get_icon_width (item); gc = gdk_gc_new (canvas_item->canvas->layout.bin_window); gdk_gc_get_values (gc, &save_gc); } @@ -1171,11 +1247,17 @@ emblem_layout_next (EmblemLayout *layout, /* Return the rectangle and pixbuf. */ *emblem_pixbuf = pixbuf; - emblem_rect->x0 = x - width / 2; - emblem_rect->y0 = y - height / 2; + if (layout->icon_item->details->control) { + emblem_rect->x0 = x; + emblem_rect->y0 = y; + } else { + emblem_rect->x0 = x - width / 2; + emblem_rect->y0 = y - height / 2; + } + emblem_rect->x1 = emblem_rect->x0 + width; emblem_rect->y1 = emblem_rect->y0 + height; - + return TRUE; } @@ -1214,35 +1296,7 @@ draw_pixbuf (GdkPixbuf *pixbuf, GdkDrawable *drawable, int x, int y) static void draw_pixbuf_aa (GdkPixbuf *pixbuf, GnomeCanvasBuf *buf, double affine[6], int x_offset, int y_offset) { - void (* affine_function) - (art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, - const art_u8 *src, int src_width, int src_height, int src_rowstride, - const double affine[6], - ArtFilterLevel level, - ArtAlphaGamma *alpha_gamma); - - affine[4] += x_offset; - affine[5] += y_offset; - - affine_function = gdk_pixbuf_get_has_alpha (pixbuf) - ? art_rgb_rgba_affine - : art_rgb_affine; - - (* affine_function) - (buf->buf, - buf->rect.x0, buf->rect.y0, - buf->rect.x1, buf->rect.y1, - buf->buf_rowstride, - gdk_pixbuf_get_pixels (pixbuf), - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf), - gdk_pixbuf_get_rowstride (pixbuf), - affine, - ART_FILTER_NEAREST, - NULL); - - affine[4] -= x_offset; - affine[5] -= y_offset; + nautilus_gnome_canvas_draw_pixbuf (buf, pixbuf, affine[4] + x_offset, affine[5] + y_offset); } /* shared code to highlight or dim the passed-in pixbuf */ @@ -1324,23 +1378,30 @@ nautilus_icon_canvas_item_draw (GnomeCanvasItem *item, GdkDrawable *drawable, icon_item = NAUTILUS_ICON_CANVAS_ITEM (item); details = icon_item->details; - /* Draw the pixbuf. */ - if (details->pixbuf == NULL) { - return; - } - /* Compute icon rectangle in drawable coordinates. */ - get_icon_canvas_rectangle (icon_item, &icon_rect); - icon_rect.x0 -= x; - icon_rect.y0 -= y; - icon_rect.x1 -= x; - icon_rect.y1 -= y; + /* draw the icon or widget */ + if (icon_item->details->control) { + gtk_widget_queue_draw (icon_item->details->control); + } else { + if (details->pixbuf != NULL) { + + /* Compute icon rectangle in drawable coordinates. */ + get_icon_canvas_rectangle (icon_item, &icon_rect); + icon_rect.x0 -= x; + icon_rect.y0 -= y; + icon_rect.x1 -= x; + icon_rect.y1 -= y; + + /* if the pre-lit or selection flag is set, make a pre-lit or darkened pixbuf and draw that instead */ + temp_pixbuf = map_pixbuf (icon_item); + draw_pixbuf (temp_pixbuf, drawable, icon_rect.x0, icon_rect.y0); + + if (temp_pixbuf != details->pixbuf) { + gdk_pixbuf_unref (temp_pixbuf); + } + + } - /* if the pre-lit or selection flag is set, make a pre-lit or darkened pixbuf and draw that instead */ - temp_pixbuf = map_pixbuf (icon_item); - draw_pixbuf (temp_pixbuf, drawable, icon_rect.x0, icon_rect.y0); - if (temp_pixbuf != details->pixbuf) { - gdk_pixbuf_unref (temp_pixbuf); } /* Draw the emblem pixbufs. */ @@ -1425,7 +1486,7 @@ draw_or_measure_label_text_aa (NautilusIconCanvasItem *item, if (destination_pixbuf == NULL ) { icon_width = 0; } else { - icon_width = details->pixbuf == NULL ? 0 : gdk_pixbuf_get_width (details->pixbuf); + icon_width = details->pixbuf == NULL ? 0 : nautilus_icon_canvas_item_get_icon_width (item); } max_text_width = floor (nautilus_icon_canvas_item_get_max_text_width (item)); @@ -1670,9 +1731,6 @@ nautilus_icon_canvas_item_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf) icon_item = NAUTILUS_ICON_CANVAS_ITEM (item); - /* map the pixbuf for selection or other effects */ - temp_pixbuf = map_pixbuf (icon_item); - /* Compute the affine transform, but force the scale to 1.0 * because the icon factory does the scaling for us. */ @@ -1689,13 +1747,19 @@ nautilus_icon_canvas_item_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf) buf->is_bg = FALSE; } - /* draw the icon */ - draw_pixbuf_aa (temp_pixbuf, buf, i2c, 0, 0); + /* draw the icon or widget */ + if (icon_item->details->control) { + gtk_widget_queue_draw (icon_item->details->control); + } else { + /* map the pixbuf for selection or other effects */ + temp_pixbuf = map_pixbuf (icon_item); + draw_pixbuf_aa (temp_pixbuf, buf, i2c, 0, 0); - if (temp_pixbuf != icon_item->details->pixbuf) { - gdk_pixbuf_unref (temp_pixbuf); + if (temp_pixbuf != icon_item->details->pixbuf) { + gdk_pixbuf_unref (temp_pixbuf); + } } - + /* draw the emblems */ get_icon_canvas_rectangle (icon_item, &icon_rect); @@ -1926,8 +1990,8 @@ nautilus_icon_canvas_item_bounds (GnomeCanvasItem *item, icon_rect.x1 = 0; icon_rect.y1 = 0; } else { - icon_rect.x1 = gdk_pixbuf_get_width (details->pixbuf); - icon_rect.y1 = gdk_pixbuf_get_height (details->pixbuf); + icon_rect.x1 = nautilus_icon_canvas_item_get_icon_width (icon_item); + icon_rect.y1 = nautilus_icon_canvas_item_get_icon_height (icon_item); } /* Compute text rectangle. */ @@ -1973,8 +2037,8 @@ nautilus_icon_canvas_item_get_icon_rectangle (NautilusIconCanvasItem *item, pixbuf = item->details->pixbuf; pixels_per_unit = GNOME_CANVAS_ITEM (item)->canvas->pixels_per_unit; - rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_width (pixbuf)) / pixels_per_unit; - rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_height (pixbuf)) / pixels_per_unit; + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : nautilus_icon_canvas_item_get_icon_width (item)) / pixels_per_unit; + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : nautilus_icon_canvas_item_get_icon_height (item)) / pixels_per_unit; } /* Get the rectangle of the icon only, in canvas coordinates. */ @@ -2000,8 +2064,8 @@ get_icon_canvas_rectangle (NautilusIconCanvasItem *item, pixbuf = item->details->pixbuf; - rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_width (pixbuf)); - rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_height (pixbuf)); + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : nautilus_icon_canvas_item_get_icon_width (item)); + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : nautilus_icon_canvas_item_get_icon_height (item)); } void @@ -2158,6 +2222,42 @@ nautilus_icon_canvas_item_set_smooth_font (NautilusIconCanvasItem *icon_item, } } +GtkWidget * +nautilus_icon_canvas_item_get_control (NautilusIconCanvasItem *icon_item) +{ + return icon_item->details->control; +} + +void +nautilus_icon_canvas_item_set_control (NautilusIconCanvasItem *icon_item, GtkWidget *control) +{ + GnomeCanvasItem *item; + + if (icon_item->details->control == control) { + return; + } + + item = GNOME_CANVAS_ITEM (icon_item); + if (icon_item->details->control) { + gtk_signal_disconnect (GTK_OBJECT (icon_item->details->control), icon_item->details->control_destroy_id); + gtk_container_remove (GTK_CONTAINER (item->canvas), icon_item->details->control); + icon_item->details->control = NULL; + } + + if (control) { + g_message ("adding control..."); + icon_item->details->control = control; + icon_item->details->control_destroy_id = gtk_signal_connect (GTK_OBJECT (control), + "destroy", + (GtkSignalFunc) do_control_destroy, + item); + gtk_widget_show (control); + gtk_layout_put (GTK_LAYOUT (item->canvas), control, + item->x1 + item->canvas->zoom_xofs, + item->y1 + item->canvas->zoom_yofs); + } +} + void nautilus_icon_canvas_item_set_smooth_font_size (NautilusIconCanvasItem *icon_item, guint font_size) diff --git a/libnautilus-private/nautilus-icon-canvas-item.h b/libnautilus-private/nautilus-icon-canvas-item.h index 8de5c8f23..c9d44375b 100644 --- a/libnautilus-private/nautilus-icon-canvas-item.h +++ b/libnautilus-private/nautilus-icon-canvas-item.h @@ -80,6 +80,10 @@ const char *nautilus_icon_canvas_item_get_editable_text (NautilusIconCanv void nautilus_icon_canvas_item_set_renaming (NautilusIconCanvasItem *icon_item, gboolean state); +GtkWidget * nautilus_icon_canvas_item_get_control (NautilusIconCanvasItem *icon_item); +void nautilus_icon_canvas_item_set_control (NautilusIconCanvasItem *icon_item, + GtkWidget *control); + /* geometry and hit testing */ gboolean nautilus_icon_canvas_item_hit_test_rectangle (NautilusIconCanvasItem *item, diff --git a/libnautilus-private/nautilus-icon-container.c b/libnautilus-private/nautilus-icon-container.c index c14dd664c..95e3852bf 100644 --- a/libnautilus-private/nautilus-icon-container.c +++ b/libnautilus-private/nautilus-icon-container.c @@ -160,6 +160,7 @@ enum { CONTEXT_CLICK_SELECTION, MIDDLE_CLICK, GET_CONTAINER_URI, + GET_ICON_CONTROL, GET_ICON_IMAGES, GET_ICON_TEXT, GET_ICON_URI, @@ -2974,6 +2975,16 @@ nautilus_icon_container_initialize_class (NautilusIconContainerClass *class) gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); + signals[GET_ICON_CONTROL] + = gtk_signal_new ("get_icon_control", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (NautilusIconContainerClass, + get_icon_control), + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); signals[GET_ICON_IMAGES] = gtk_signal_new ("get_icon_images", GTK_RUN_LAST, @@ -3528,9 +3539,10 @@ nautilus_icon_container_update_icon (NautilusIconContainer *container, GdkPixbuf *pixbuf, *emblem_pixbuf, *saved_pixbuf; GList *emblem_scalable_icons, *emblem_pixbufs, *p; char *editable_text, *additional_text; + GtkWidget *embedded_control; GdkFont *font; guint smooth_font_size; - + if (icon == NULL) { return; } @@ -3562,8 +3574,7 @@ nautilus_icon_container_update_icon (NautilusIconContainer *container, nautilus_scalable_icon_unref (scalable_icon); - /* in the rare case an image is too small, scale it up */ - + /* in the rare case an image is too small, scale it up */ width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); if (width < min_image_size || height < min_image_size) { @@ -3571,9 +3582,11 @@ nautilus_icon_container_update_icon (NautilusIconContainer *container, /* don't let it exceed the maximum width in the other dimension */ scale_factor = MIN (scale_factor, max_image_size / width); scale_factor = MIN (scale_factor, max_image_size / height); - + scaled_width = floor (width * scale_factor + .5); scaled_height = floor (height * scale_factor + .5); + + /* scale the image to the calculated size */ saved_pixbuf = pixbuf; pixbuf = gdk_pixbuf_scale_simple (pixbuf, scaled_width, scaled_height, GDK_INTERP_BILINEAR); gdk_pixbuf_unref (saved_pixbuf); @@ -3608,13 +3621,22 @@ nautilus_icon_container_update_icon (NautilusIconContainer *container, emblem_pixbufs = g_list_reverse (emblem_pixbufs); nautilus_scalable_icon_list_free (emblem_scalable_icons); + /* get the embedded control, if any */ + embedded_control = nautilus_icon_canvas_item_get_control (icon->item); + if (embedded_control == NULL) { + gtk_signal_emit (GTK_OBJECT (container), + signals[GET_ICON_CONTROL], + icon->data, + &embedded_control); + } + /* Get both editable and non-editable icon text */ gtk_signal_emit (GTK_OBJECT (container), signals[GET_ICON_TEXT], icon->data, &editable_text, &additional_text); - + /* If name of icon being renamed was changed from elsewhere, end renaming mode. * Alternatively, we could replace the characters in the editable text widget * with the new name, but that could cause timing problems if the user just @@ -3639,6 +3661,8 @@ nautilus_icon_container_update_icon (NautilusIconContainer *container, "smooth_font", details->smooth_label_font, NULL); + nautilus_icon_canvas_item_set_control (icon->item, embedded_control); + nautilus_icon_canvas_item_set_image (icon->item, pixbuf); nautilus_icon_canvas_item_set_attach_points (icon->item, &attach_points); nautilus_icon_canvas_item_set_emblems (icon->item, emblem_pixbufs); diff --git a/libnautilus-private/nautilus-icon-container.h b/libnautilus-private/nautilus-icon-container.h index a16d99e30..e551f184f 100644 --- a/libnautilus-private/nautilus-icon-container.h +++ b/libnautilus-private/nautilus-icon-container.h @@ -107,6 +107,10 @@ typedef struct { gboolean (* get_stored_icon_position) (NautilusIconContainer *container, NautilusIconData *data, NautilusIconPosition *position); + void + (* get_icon_control) (NautilusIconContainer *container, + NautilusIconData *data, + GtkWidget **control); NautilusScalableIcon * (* get_icon_images) (NautilusIconContainer *container, NautilusIconData *data, diff --git a/libnautilus-private/nautilus-icon-dnd.c b/libnautilus-private/nautilus-icon-dnd.c index 4098056b7..9eb050891 100644 --- a/libnautilus-private/nautilus-icon-dnd.c +++ b/libnautilus-private/nautilus-icon-dnd.c @@ -1257,6 +1257,7 @@ nautilus_icon_dnd_begin_drag (NautilusIconContainer *container, &pixmap_for_dragged_file, &mask_for_dragged_file, NAUTILUS_STANDARD_ALPHA_THRESHHOLD); + gdk_pixbuf_unref (pixbuf); /* compute the image's offset */ nautilus_icon_canvas_item_get_icon_rectangle diff --git a/libnautilus-private/nautilus-link.c b/libnautilus-private/nautilus-link.c index 407a29540..10edebecc 100644 --- a/libnautilus-private/nautilus-link.c +++ b/libnautilus-private/nautilus-link.c @@ -287,6 +287,35 @@ nautilus_link_local_get_additional_text (const char *path) (path, NAUTILUS_METADATA_KEY_EXTRA_TEXT); } +void nautilus_link_local_get_component_info (const char *path, + char **control_moniker, char **control_data) +{ + xmlDoc *document; + const char *mime_type; + + *control_moniker = NULL; + *control_data = NULL; + + /* Check mime type. Exit if it is not a nautilus link */ + mime_type = gnome_vfs_get_file_mime_type (path, NULL, FALSE); + if (strcmp (mime_type, "application/x-nautilus-link") != 0) { + return; + } + + document = xmlParseFile (path); + if (document != NULL) { + *control_moniker = xml_get_root_property (document, + NAUTILUS_METADATA_KEY_CONTROL_MONIKER); + + *control_data = xml_get_root_property (document, + NAUTILUS_METADATA_KEY_CONTROL_DATA); + + xmlFreeDoc (document); + } +} + + + /* utility to return the local pathname of a cached icon, given the leaf name */ /* if the icons directory hasn't been created yet, create it */ static char * diff --git a/libnautilus-private/nautilus-link.h b/libnautilus-private/nautilus-link.h index 1f707f0c7..6a6df0852 100644 --- a/libnautilus-private/nautilus-link.h +++ b/libnautilus-private/nautilus-link.h @@ -72,14 +72,21 @@ gboolean nautilus_link_local_set_link_uri (const char * none. Despite the fact that it takes a URI parameter, works only if * the file is local and does sync. I/O. */ -char * nautilus_link_local_get_additional_text (const char *path); +char * nautilus_link_local_get_additional_text (const char *path); /* Returns the image associated with a link file. Despite the fact * that it takes a URI parameter, works only if the file is local and * does sync. I/O on the link, although it does async. on the image * and caches if the image is remote. */ -char * nautilus_link_local_get_image_uri (const char *path); +char * nautilus_link_local_get_image_uri (const char *path); + +/* returns the moniker of the component associated with a link file, as well as configuration data. + * It works only if the file is local and does sync. I/O. + */ +void nautilus_link_local_get_component_info (const char *path, + char **control_moniker, + char **control_data); /* Returns the link type of a link file. * Works only if the file is local and does sync. I/O diff --git a/libnautilus-private/nautilus-metadata.h b/libnautilus-private/nautilus-metadata.h index 3de64b564..18f8a75e3 100644 --- a/libnautilus-private/nautilus-metadata.h +++ b/libnautilus-private/nautilus-metadata.h @@ -72,6 +72,9 @@ #define NAUTILUS_METADATA_KEY_ICON_SCALE "ICON_SCALE" #define NAUTILUS_METADATA_KEY_CUSTOM_ICON "CUSTOM_ICON" +#define NAUTILUS_METADATA_KEY_CONTROL_MONIKER "CONTROL_MONIKER" +#define NAUTILUS_METADATA_KEY_CONTROL_DATA "CONTROL_DATA" + /* per link file */ #define NAUTILUS_METADATA_KEY_EXTRA_TEXT "EXTRA_TEXT" diff --git a/src/file-manager/fm-icon-view.c b/src/file-manager/fm-icon-view.c index cedf700ff..c285d7a7f 100644 --- a/src/file-manager/fm-icon-view.c +++ b/src/file-manager/fm-icon-view.c @@ -28,6 +28,7 @@ #include "fm-desktop-icon-view.h" #include "fm-error-reporting.h" #include "fm-icon-text-window.h" +#include <bonobo/bonobo-widget.h> #include <bonobo/bonobo-ui-util.h> #include <ctype.h> #include <errno.h> @@ -1638,6 +1639,39 @@ get_icon_images_callback (NautilusIconContainer *container, return nautilus_icon_factory_get_icon_for_file (file, modifier, smooth_graphics); } +/* return the Bonobo control associated with the icon, if any */ +static void +get_icon_control_callback (NautilusIconContainer *container, + NautilusFile *file, + GtkWidget **control, + FMIconView *icon_view) +{ + Bonobo_UIContainer ui_container; + char *control_moniker, *control_data; + char *uri, *path; + *control = NULL; + + if (nautilus_file_is_nautilus_link (file)) { + uri = nautilus_file_get_uri (file); + path = gnome_vfs_get_local_path_from_uri (uri); + if (path != NULL) { + nautilus_link_local_get_component_info (path, &control_moniker, &control_data); + if (control_moniker) { + g_message ("got moniker %s", control_moniker); + ui_container = fm_directory_view_get_bonobo_ui_container (FM_DIRECTORY_VIEW (icon_view)); + *control = bonobo_widget_new_control (control_moniker, ui_container); + g_free (control_moniker); + } + if (control_data && strlen (control_data) > 0) { + bonobo_widget_set_property (BONOBO_WIDGET (*control), "configuration", control_data, NULL); + g_free (control_data); + } + g_free (path); + } + g_free (uri); + } +} + static char * get_icon_uri_callback (NautilusIconContainer *container, NautilusFile *file, @@ -2011,6 +2045,10 @@ create_icon_container (FMIconView *icon_view) GTK_SIGNAL_FUNC (get_icon_images_callback), icon_view); gtk_signal_connect (GTK_OBJECT (icon_container), + "get_icon_control", + GTK_SIGNAL_FUNC (get_icon_control_callback), + icon_view); + gtk_signal_connect (GTK_OBJECT (icon_container), "get_icon_uri", GTK_SIGNAL_FUNC (get_icon_uri_callback), icon_view); diff --git a/src/nautilus-information-panel.c b/src/nautilus-information-panel.c index 6cf041618..50d45549a 100644 --- a/src/nautilus-information-panel.c +++ b/src/nautilus-information-panel.c @@ -1018,9 +1018,13 @@ nautilus_sidebar_release_event (GtkWidget *widget, GdkEventButton *event) if (rounded_y >= GTK_WIDGET (sidebar->details->sidebar_tabs)->allocation.y) { which_tab = nautilus_sidebar_tabs_hit_test (sidebar_tabs, event->x, event->y); if (which_tab >= 0) { - nautilus_sidebar_tabs_select_tab (sidebar_tabs, which_tab); - nautilus_sidebar_activate_panel (sidebar, which_tab); - gtk_widget_queue_draw (widget); + if (which_tab == sidebar->details->selected_index) { + nautilus_sidebar_deactivate_panel (sidebar); + } else { + nautilus_sidebar_tabs_select_tab (sidebar_tabs, which_tab); + nautilus_sidebar_activate_panel (sidebar, which_tab); + gtk_widget_queue_draw (widget); + } } } diff --git a/src/nautilus-sidebar-tabs.c b/src/nautilus-sidebar-tabs.c index 95b13d4d7..1b93179a9 100644 --- a/src/nautilus-sidebar-tabs.c +++ b/src/nautilus-sidebar-tabs.c @@ -403,16 +403,17 @@ int nautilus_sidebar_tabs_hit_test (NautilusSidebarTabs *sidebar_tabs, int x, in /* loop through the items, seeing it the passed in point is in one of the rectangles */ tab_item = (TabItem*) current_item->data; + /* if (!tab_item->visible && current_item->next) { tab_item = (TabItem*) current_item->next->data; } - + */ result = -1; while (current_item != NULL) { tab_item = (TabItem*) current_item->data; rect_ptr = &tab_item->tab_rect; - if (tab_item->visible) { + if (TRUE /*tab_item->visible*/) { if ((x >= rect_ptr->x) && (x < rect_ptr->x + rect_ptr->width) && (y >= rect_ptr->y) && (y< rect_ptr->y + rect_ptr->height)) result = tab_item->notebook_page; @@ -1291,8 +1292,9 @@ nautilus_sidebar_tabs_select_tab (NautilusSidebarTabs *sidebar_tabs, int which_t for (next_tab = sidebar_tabs->details->tab_items; next_tab != NULL; next_tab = next_tab->next) { TabItem *item = next_tab->data; + item->visible = (item->notebook_page != which_tab); - item->prelit = FALSE; + item->prelit = FALSE; } recalculate_size(sidebar_tabs); diff --git a/src/nautilus-sidebar.c b/src/nautilus-sidebar.c index 6cf041618..50d45549a 100644 --- a/src/nautilus-sidebar.c +++ b/src/nautilus-sidebar.c @@ -1018,9 +1018,13 @@ nautilus_sidebar_release_event (GtkWidget *widget, GdkEventButton *event) if (rounded_y >= GTK_WIDGET (sidebar->details->sidebar_tabs)->allocation.y) { which_tab = nautilus_sidebar_tabs_hit_test (sidebar_tabs, event->x, event->y); if (which_tab >= 0) { - nautilus_sidebar_tabs_select_tab (sidebar_tabs, which_tab); - nautilus_sidebar_activate_panel (sidebar, which_tab); - gtk_widget_queue_draw (widget); + if (which_tab == sidebar->details->selected_index) { + nautilus_sidebar_deactivate_panel (sidebar); + } else { + nautilus_sidebar_tabs_select_tab (sidebar_tabs, which_tab); + nautilus_sidebar_activate_panel (sidebar, which_tab); + gtk_widget_queue_draw (widget); + } } } |