nautilus/libnautilus-extensions/nautilus-image.c
John Sullivan a9542b9563 reviewed by: Rebecca Schulman <rebecka@eazel.com>
Fixed bug 4899 (Bookmark for nonexistent file can cause
	infinite loop at startup)

	Changed NautilusBookmark's internal logic so that it doesn't
	keep around a file object for known non-existent URIs. The
	trick is to get it to notice when the URI is no longer non-existent
	and get a fresh file object then. This is done imperfectly, but
	the new symptom is very minor and deferrable (wrote it up as bug 4906).

	* libnautilus-extensions/nautilus-bookmark.c:
	(nautilus_bookmark_connect_file): Don't get a new NautilusFile
	object if we know the URI doesn't exist; instead just set the
	missing-bookmark icon. Also made it safe to call this routine
	when there's already a file object in hand (just bails out early).
	(nautilus_bookmark_get_icon), (nautilus_bookmark_get_uri):
	Call nautilus_bookmark_connect_file so that it will connect to a
	now-existing file if possible (and thus	get the right icon).
	Since callers that try to activate the bookmark will call get_uri,
	one way to kick a reincarnated bookmark's icon into appearing is
	to select it in a menu.
	(nautilus_bookmark_get_pixbuf): Call nautilus_bookmark_get_icon to
	benefit from its connect_file logic.


	Fixed bug 3847 (Icon in properties window flashes while
	folder count increments)

	* libnautilus-extensions/nautilus-image.c:
	(nautilus_image_set_pixbuf): Don't call gtk_widget_queue_resize if
	the pixbuf hasn't changed.


	Fixed bug 1454 (Properties dialog needs mucho tweaking)

	Mostly this was changes to match Arlo's design that he gave me
	ages ago. I also fixed a few other problems.

	* libnautilus-extensions/nautilus-file.c:
	(nautilus_file_get_date_as_string): Change format of date
	strings from "<date> <time>" to "<date> at <time>" to match
	Arlo's design.
	* src/file-manager/fm-properties-window.c:
	(attach_label): Now handles requests for a bold font.
	(attach_value_label): Renamed from attach_left_aligned_label, use bold
	font here.
	(attach_value_field),(attach_directory_contents_value_field):
	updated for name change.
	(attach_right_aligned_label): Removed, guts moved to caller.
	(attach_title_field): Use bold font here.
	(attach_option_menu): New helper function to share code between
	attach_group_menu and attach_owner_menu; now uses gtk_alignment
	to make the menu be minimally-sized and left-aligned.
	(attach_group_menu), (attach_owner_menu): Use attach_option_menu.
	(attach_separator): New helper function to install a separator
	across both columns of a properties window table.
	(create_basic_page): Use gtk_alignment to make the icon right-aligned;
	make the blank row above date rows be standard height.
	(create_emblems_page): Changed layout so name appears below emblem
	rather than to its right; this matches Customize window and allows
	the Properties window to be a smaller width, which looks much better
	for the other panes. Also, the emblems are now layed out lrtb instead of
	tblr.
	(add_permissions_column_label): Make these labels bold.
	(add_special_execution_flags): Attach a separator.
	(get_adjusted_permissions_row): Helper function to account for the "special
	flags" rows, which are not always displayed.
	(create_permissions_page): Deploy get_adjusted_permissions_row wherever a
	raw row number was used; insert separators.
	(create_properties_window): Allow window to be stretched, since the emblems
	don't all fit at initial window height (so user can stretch rather than
	scrolling if desired).
2000-11-30 23:39:36 +00:00

573 lines
15 KiB
C

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* nautilus-image.c - A widget to display a alpha composited pixbufs.
Copyright (C) 1999, 2000 Eazel, Inc.
The Gnome Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The Gnome 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the Gnome Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Authors: Ramiro Estrugo <ramiro@eazel.com>
*/
#include <config.h>
#include "nautilus-image.h"
#include "nautilus-glib-extensions.h"
#include "nautilus-gtk-macros.h"
#include "nautilus-gdk-extensions.h"
#include "nautilus-gdk-pixbuf-extensions.h"
/* Arguments */
enum
{
ARG_0,
ARG_BACKGROUND_COLOR,
ARG_BACKGROUND_TYPE,
ARG_IMAGE,
ARG_PLACEMENT_TYPE,
};
/* Detail member struct */
struct _NautilusImageDetail
{
GdkPixbuf *pixbuf;
guchar overall_alpha;
NautilusImageAlphaMode alpha_mode;
};
/* GtkObjectClass methods */
static void nautilus_image_initialize_class (NautilusImageClass *image_class);
static void nautilus_image_initialize (NautilusImage *image);
static void nautilus_image_destroy (GtkObject *object);
static void nautilus_image_set_arg (GtkObject *object,
GtkArg *arg,
guint arg_id);
static void nautilus_image_get_arg (GtkObject *object,
GtkArg *arg,
guint arg_id);
/* GtkWidgetClass methods */
static void nautilus_image_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void nautilus_image_draw (GtkWidget *widget,
GdkRectangle *area);
/* GtkWidgetClass event methods */
static gint nautilus_image_expose_event (GtkWidget *widget,
GdkEventExpose *event);
/* NautilusBufferedWidgetClass methods */
static void render_buffer_pixbuf (NautilusBufferedWidget *buffered_widget,
GdkPixbuf *buffer,
int horizontal_offset,
int vertical_offset);
static void nautilus_image_paint (NautilusImage *image,
const GdkRectangle *area);
NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusImage, nautilus_image, NAUTILUS_TYPE_BUFFERED_WIDGET)
/* Class init methods */
static void
nautilus_image_initialize_class (NautilusImageClass *image_class)
{
GtkObjectClass *object_class = GTK_OBJECT_CLASS (image_class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (image_class);
NautilusBufferedWidgetClass *buffered_widget_class = NAUTILUS_BUFFERED_WIDGET_CLASS (image_class);
#if 0
/* Arguments */
gtk_object_add_arg_type ("NautilusImage::placement_type",
GTK_TYPE_ENUM,
GTK_ARG_READWRITE,
ARG_PLACEMENT_TYPE);
gtk_object_add_arg_type ("NautilusImage::background_type",
GTK_TYPE_ENUM,
GTK_ARG_READWRITE,
ARG_BACKGROUND_TYPE);
gtk_object_add_arg_type ("NautilusImage::background_color",
GTK_TYPE_UINT,
GTK_ARG_READWRITE,
ARG_BACKGROUND_COLOR);
gtk_object_add_arg_type ("NautilusImage::image",
GTK_TYPE_OBJECT,
GTK_ARG_READWRITE,
ARG_IMAGE);
#endif
/* GtkObjectClass */
object_class->destroy = nautilus_image_destroy;
object_class->set_arg = nautilus_image_set_arg;
object_class->get_arg = nautilus_image_get_arg;
/* GtkWidgetClass */
widget_class->size_request = nautilus_image_size_request;
widget_class->draw = nautilus_image_draw;
widget_class->expose_event = nautilus_image_expose_event;
/* NautilusBufferedWidgetClass */
buffered_widget_class->render_buffer_pixbuf = render_buffer_pixbuf;
}
void
nautilus_image_initialize (NautilusImage *image)
{
image->detail = g_new (NautilusImageDetail, 1);
image->detail->pixbuf = NULL;
image->detail->overall_alpha = 255;
image->detail->alpha_mode = NAUTILUS_IMAGE_FULL_ALPHA;
}
/* GtkObjectClass methods */
static void
nautilus_image_destroy (GtkObject *object)
{
NautilusImage *image;
g_return_if_fail (object != NULL);
g_return_if_fail (NAUTILUS_IS_IMAGE (object));
image = NAUTILUS_IMAGE (object);
nautilus_gdk_pixbuf_unref_if_not_null (image->detail->pixbuf);
image->detail->pixbuf = NULL;
g_free (image->detail);
/* Chain destroy */
NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object));
}
static void
nautilus_image_set_arg (GtkObject *object,
GtkArg *arg,
guint arg_id)
{
NautilusImage *image;
g_return_if_fail (object != NULL);
g_return_if_fail (NAUTILUS_IS_IMAGE (object));
image = NAUTILUS_IMAGE (object);
#if 0
switch (arg_id)
{
case ARG_PLACEMENT_TYPE:
image->detail->placement_type = GTK_VALUE_ENUM (*arg);
break;
case ARG_BACKGROUND_TYPE:
image->detail->background_type = GTK_VALUE_ENUM (*arg);
break;
case ARG_BACKGROUND_COLOR:
image->detail->background_color = GTK_VALUE_UINT (*arg);
break;
case ARG_IMAGE:
nautilus_image_set_pixbuf (image, (GdkPixbuf*) GTK_VALUE_OBJECT (*arg));
break;
default:
g_assert_not_reached ();
}
#endif
}
static void
nautilus_image_get_arg (GtkObject *object,
GtkArg *arg,
guint arg_id)
{
NautilusImage *image;
g_return_if_fail (object != NULL);
g_return_if_fail (NAUTILUS_IS_IMAGE (object));
image = NAUTILUS_IMAGE (object);
#if 0
switch (arg_id)
{
case ARG_PLACEMENT_TYPE:
GTK_VALUE_ENUM (*arg) = image->detail->placement_type;
break;
case ARG_BACKGROUND_TYPE:
GTK_VALUE_ENUM (*arg) = image->detail->background_type;
break;
case ARG_BACKGROUND_COLOR:
GTK_VALUE_UINT (*arg) = image->detail->background_color;
break;
case ARG_IMAGE:
GTK_VALUE_OBJECT (*arg) = (GtkObject *) nautilus_image_get_pixbuf (image);
break;
default:
g_assert_not_reached ();
}
#endif
}
/* GtkWidgetClass methods */
static void
nautilus_image_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
NautilusImage *image;
GtkMisc *misc;
guint pixbuf_width = 0;
guint pixbuf_height = 0;
g_return_if_fail (widget != NULL);
g_return_if_fail (NAUTILUS_IS_IMAGE (widget));
g_return_if_fail (requisition != NULL);
image = NAUTILUS_IMAGE (widget);
misc = GTK_MISC (widget);
if (image->detail->pixbuf != NULL) {
pixbuf_width = gdk_pixbuf_get_width (image->detail->pixbuf);
pixbuf_height = gdk_pixbuf_get_height (image->detail->pixbuf);
}
requisition->width = MAX (2, pixbuf_width);
requisition->height = MAX (2, pixbuf_height);
requisition->width += misc->xpad * 2;
requisition->height += misc->ypad * 2;
}
static void
nautilus_image_draw (GtkWidget *widget, GdkRectangle *area)
{
NautilusImage *image;
g_return_if_fail (NAUTILUS_IS_IMAGE (widget));
g_return_if_fail (area != NULL);
g_return_if_fail (GTK_WIDGET_REALIZED (widget));
image = NAUTILUS_IMAGE (widget);
if (image->detail->alpha_mode == NAUTILUS_IMAGE_FULL_ALPHA) {
NAUTILUS_CALL_PARENT_CLASS (GTK_WIDGET_CLASS, draw, (widget, area));
}
else {
nautilus_image_paint (image, area);
}
}
static gint
nautilus_image_expose_event (GtkWidget *widget, GdkEventExpose *event)
{
NautilusImage *image;
g_return_val_if_fail (NAUTILUS_IS_IMAGE (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
image = NAUTILUS_IMAGE (widget);
if (image->detail->alpha_mode == NAUTILUS_IMAGE_FULL_ALPHA) {
return NAUTILUS_CALL_PARENT_CLASS (GTK_WIDGET_CLASS, expose_event, (widget, event));
}
else {
nautilus_image_paint (image, &event->area);
}
return TRUE;
}
/* Private NautilusImage things */
static void
render_buffer_pixbuf (NautilusBufferedWidget *buffered_widget,
GdkPixbuf *buffer,
int horizontal_offset,
int vertical_offset)
{
NautilusImage *image;
GtkWidget *widget;
g_return_if_fail (NAUTILUS_IS_IMAGE (buffered_widget));
g_return_if_fail (buffer != NULL);
image = NAUTILUS_IMAGE (buffered_widget);
widget = GTK_WIDGET (buffered_widget);
if (image->detail->pixbuf != NULL) {
gint x;
gint y;
guint width = gdk_pixbuf_get_width (image->detail->pixbuf);
guint height = gdk_pixbuf_get_height (image->detail->pixbuf);
if (width <= widget->allocation.width) {
x = (widget->allocation.width - width) / 2;
}
else {
x = - (width - widget->allocation.width) / 2;
}
x += horizontal_offset;
if (height <= widget->allocation.height) {
y = (widget->allocation.height - height) / 2;
}
else {
y = - (height - widget->allocation.height) / 2;
}
y += vertical_offset;
gdk_pixbuf_composite (image->detail->pixbuf,
buffer,
x,
y,
width,
height,
(double) x,
(double) y,
1.0,
1.0,
GDK_INTERP_BILINEAR,
image->detail->overall_alpha);
}
}
static void
nautilus_image_paint (NautilusImage *image,
const GdkRectangle *area)
{
g_return_if_fail (NAUTILUS_IS_IMAGE (image));
g_return_if_fail (area != NULL);
g_return_if_fail (image->detail->alpha_mode == NAUTILUS_IMAGE_THRESHOLD_ALPHA);
if (!GTK_WIDGET_REALIZED (image)) {
return;
}
if (image->detail->pixbuf != NULL) {
GtkWidget *widget;
gint x;
gint y;
guint width = gdk_pixbuf_get_width (image->detail->pixbuf);
guint height = gdk_pixbuf_get_height (image->detail->pixbuf);
widget = GTK_WIDGET (image);
if (width <= widget->allocation.width) {
x = (widget->allocation.width - width) / 2;
}
else {
x = - (width - widget->allocation.width) / 2;
}
if (height <= widget->allocation.height) {
y = (widget->allocation.height - height) / 2;
}
else {
y = - (height - widget->allocation.height) / 2;
}
x += widget->allocation.x;
y += widget->allocation.y;
gdk_pixbuf_render_to_drawable_alpha (image->detail->pixbuf,
widget->window,
0,
0,
x,
y,
width,
height,
GDK_PIXBUF_ALPHA_BILEVEL,
128,
GDK_RGB_DITHER_NORMAL,
x,
y);
}
}
/* Public NautilusImage */
GtkWidget *
nautilus_image_new (void)
{
return gtk_widget_new (nautilus_image_get_type (), NULL);
}
/* cover routine to allocate an image widget from the passed in image file path */
GtkWidget *
nautilus_image_new_from_file (const char* filename)
{
GtkWidget *image_widget;
GdkPixbuf *pixbuf;
pixbuf = gdk_pixbuf_new_from_file (filename);
image_widget = nautilus_image_new ();
nautilus_image_set_pixbuf (NAUTILUS_IMAGE (image_widget), pixbuf);
gdk_pixbuf_unref (pixbuf);
return image_widget;
}
void
nautilus_image_set_pixbuf (NautilusImage *image, GdkPixbuf *pixbuf)
{
g_return_if_fail (NAUTILUS_IS_IMAGE (image));
if (pixbuf != image->detail->pixbuf)
{
nautilus_gdk_pixbuf_unref_if_not_null (image->detail->pixbuf);
nautilus_gdk_pixbuf_ref_if_not_null (pixbuf);
image->detail->pixbuf = pixbuf;
gtk_widget_queue_resize (GTK_WIDGET (image));
}
}
GdkPixbuf*
nautilus_image_get_pixbuf (const NautilusImage *image)
{
g_return_val_if_fail (NAUTILUS_IS_IMAGE (image), NULL);
nautilus_gdk_pixbuf_ref_if_not_null (image->detail->pixbuf);
return image->detail->pixbuf;
}
void
nautilus_image_set_overall_alpha (NautilusImage *image,
guchar pixbuf_alpha)
{
g_return_if_fail (NAUTILUS_IS_IMAGE (image));
image->detail->overall_alpha = pixbuf_alpha;
nautilus_buffered_widget_clear_buffer (NAUTILUS_BUFFERED_WIDGET (image));
gtk_widget_queue_draw (GTK_WIDGET (image));
}
/**
* nautilus_image_set_alpha_mode:
*
* @image: A NautilusImage
* @alpha_mode: The new alpha mode
*
* Change the rendering mode for the widget. In FULL_ALPHA mode, the
* widget's background will be peeked to do full alpha compositing.
* In THRESHOLD_ALPHA mode, all compositing is done by thresholding
* GdkPixbuf operations - this is more effecient, but doesnt look as
* smooth.
*/
void
nautilus_image_set_alpha_mode (NautilusImage *image,
NautilusImageAlphaMode alpha_mode)
{
g_return_if_fail (NAUTILUS_IS_IMAGE (image));
g_return_if_fail (alpha_mode >= NAUTILUS_IMAGE_FULL_ALPHA);
g_return_if_fail (alpha_mode <= NAUTILUS_IMAGE_THRESHOLD_ALPHA);
if (alpha_mode != image->detail->alpha_mode)
{
image->detail->alpha_mode = alpha_mode;
nautilus_buffered_widget_clear_buffer (NAUTILUS_BUFFERED_WIDGET (image));
gtk_widget_queue_draw (GTK_WIDGET (image));
}
}
/**
* nautilus_image_get_alpha_mode:
*
* @image: A NautilusImage
*
* Return value: The current alpha mode.
*/
NautilusImageAlphaMode
nautilus_image_get_alpha_mode (const NautilusImage *image)
{
g_return_val_if_fail (NAUTILUS_IS_IMAGE (image), 0);
return image->detail->alpha_mode;
}
/**
* nautilus_image_new_loaded:
*
* @text: Text or NULL
* @family: Font family or NULL
* @weight: Font weight or NULL
* @font_size: Font size in pixels
* @drop_shadow_offset: Drop shadow offset
* @drop_shadow_color: Drop shadow color
* @text_color: Text color
* @xpadding: Amount to pad image in the x direction.
* @ypadding: Amount to pad image in the y direction.
* @vertical_offset: Amount to offset the image vertically.
* @horizontal_offset: Amount to offset the image horizontally.
* @background_color: Background color.
* @tile_pixbuf: Pixbuf to use for tile or NULL
*
* Return value: Newly created image with all the given values.
*/
GtkWidget *
nautilus_image_new_loaded (GdkPixbuf *pixbuf,
gint xpadding,
gint ypadding,
guint vertical_offset,
guint horizontal_offset,
guint32 background_color,
GdkPixbuf *tile_pixbuf)
{
NautilusImage *image;
image = NAUTILUS_IMAGE (nautilus_image_new ());
nautilus_buffered_widget_set_background_type (NAUTILUS_BUFFERED_WIDGET (image), NAUTILUS_BACKGROUND_SOLID);
nautilus_buffered_widget_set_background_color (NAUTILUS_BUFFERED_WIDGET (image), background_color);
nautilus_buffered_widget_set_vertical_offset (NAUTILUS_BUFFERED_WIDGET (image), vertical_offset);
nautilus_buffered_widget_set_horizontal_offset (NAUTILUS_BUFFERED_WIDGET (image), horizontal_offset);
gtk_misc_set_padding (GTK_MISC (image), xpadding, ypadding);
if (pixbuf != NULL) {
nautilus_image_set_pixbuf (image, pixbuf);
}
if (tile_pixbuf != NULL) {
nautilus_buffered_widget_set_tile_pixbuf (NAUTILUS_BUFFERED_WIDGET (image), tile_pixbuf);
}
return GTK_WIDGET (image);
}