mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-23 12:56:51 +03:00
f55d906c37
* gdesktop-icon.c : Attach a desktop_icon wmclass to the desktop icons to allow even more wizardry with the desktop icons, mainly to exclude them from window lists, don't decorate them, skip desktops and other boring stuff.
443 lines
12 KiB
C
443 lines
12 KiB
C
/* Desktop icon widget for the Midnight Commander
|
|
*
|
|
* Copyright (C) 1998 The Free Software Foundation
|
|
*
|
|
* Author: Federico Mena <federico@nuclecu.unam.mx>
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <gnome.h>
|
|
#include "gdesktop-icon.h"
|
|
#include "gdesktop.h"
|
|
|
|
|
|
/* Spacing between icon and text */
|
|
#define SPACING 2
|
|
|
|
|
|
/* The 50% gray stipple for selected icons */
|
|
#define gray50_width 2
|
|
#define gray50_height 2
|
|
static char gray50_bits[] = {
|
|
0x02, 0x01, };
|
|
|
|
|
|
static void desktop_icon_class_init (DesktopIconClass *class);
|
|
static void desktop_icon_init (DesktopIcon *dicon);
|
|
static void desktop_icon_realize (GtkWidget *widget);
|
|
|
|
|
|
static GtkWindowClass *parent_class;
|
|
|
|
|
|
/**
|
|
* desktop_icon_get_type
|
|
*
|
|
* Returns the Gtk type assigned to the DesktopIcon class.
|
|
*/
|
|
GtkType
|
|
desktop_icon_get_type (void)
|
|
{
|
|
static GtkType desktop_icon_type = 0;
|
|
|
|
if (!desktop_icon_type) {
|
|
GtkTypeInfo desktop_icon_info = {
|
|
"DesktopIcon",
|
|
sizeof (DesktopIcon),
|
|
sizeof (DesktopIconClass),
|
|
(GtkClassInitFunc) desktop_icon_class_init,
|
|
(GtkObjectInitFunc) desktop_icon_init,
|
|
NULL, /* reserved_1 */
|
|
NULL, /* reserved_2 */
|
|
(GtkClassInitFunc) NULL
|
|
};
|
|
|
|
desktop_icon_type = gtk_type_unique (gtk_window_get_type (), &desktop_icon_info);
|
|
}
|
|
|
|
return desktop_icon_type;
|
|
}
|
|
|
|
static void
|
|
desktop_icon_class_init (DesktopIconClass *class)
|
|
{
|
|
GtkObjectClass *object_class;
|
|
GtkWidgetClass *widget_class;
|
|
|
|
object_class = (GtkObjectClass *) class;
|
|
widget_class = (GtkWidgetClass *) class;
|
|
|
|
parent_class = gtk_type_class (gtk_window_get_type ());
|
|
|
|
widget_class->realize = desktop_icon_realize;
|
|
}
|
|
|
|
/* Callback used when the size of the icon text item changes */
|
|
static void
|
|
size_changed (GnomeIconTextItem *text, gpointer data)
|
|
{
|
|
DesktopIcon *dicon;
|
|
|
|
dicon = DESKTOP_ICON (data);
|
|
|
|
desktop_icon_reshape (dicon);
|
|
}
|
|
|
|
/* Callback used when the desktop icon's canvas is size_allocated. We reset the canvas scrolling
|
|
* region here, instead of doing it when the window shape changes, to avoid flicker.
|
|
*/
|
|
static void
|
|
canvas_size_allocated (GtkWidget *widget, GtkAllocation *allocation, gpointer data)
|
|
{
|
|
gnome_canvas_set_scroll_region (GNOME_CANVAS (widget), 0, 0, allocation->width, allocation->height);
|
|
}
|
|
|
|
static void
|
|
desktop_icon_init (DesktopIcon *dicon)
|
|
{
|
|
GdkBitmap *stipple;
|
|
|
|
/* Set the window policy */
|
|
|
|
gtk_window_set_policy (GTK_WINDOW (dicon), TRUE, TRUE, TRUE);
|
|
gtk_window_set_wmclass (GTK_WINDOW (dicon), "desktop_icon", "gmc");
|
|
/* Create the canvas */
|
|
|
|
gtk_widget_push_visual (gdk_imlib_get_visual ());
|
|
gtk_widget_push_colormap (gdk_imlib_get_colormap ());
|
|
|
|
dicon->canvas = gnome_canvas_new ();
|
|
gtk_signal_connect (GTK_OBJECT (dicon->canvas), "size_allocate",
|
|
(GtkSignalFunc) canvas_size_allocated,
|
|
NULL);
|
|
|
|
gtk_widget_pop_colormap ();
|
|
gtk_widget_pop_visual ();
|
|
|
|
gtk_container_add (GTK_CONTAINER (dicon), dicon->canvas);
|
|
gtk_widget_show (dicon->canvas);
|
|
|
|
/* Create the icon and the text items */
|
|
|
|
dicon->icon = gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS (dicon->canvas)),
|
|
gnome_canvas_image_get_type (),
|
|
"anchor", GTK_ANCHOR_NW,
|
|
NULL);
|
|
|
|
dicon->text = gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS (dicon->canvas)),
|
|
gnome_icon_text_item_get_type (),
|
|
NULL);
|
|
|
|
stipple = gdk_bitmap_create_from_data (NULL, gray50_bits, gray50_width, gray50_height);
|
|
dicon->stipple = gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS (dicon->canvas)),
|
|
gnome_canvas_rect_get_type (),
|
|
"fill_stipple", stipple,
|
|
NULL);
|
|
gnome_canvas_item_hide (dicon->stipple);
|
|
gdk_bitmap_unref (stipple);
|
|
|
|
dicon->w_changed_id = gtk_signal_connect (GTK_OBJECT (dicon->text), "width_changed",
|
|
(GtkSignalFunc) size_changed,
|
|
dicon);
|
|
dicon->h_changed_id = gtk_signal_connect (GTK_OBJECT (dicon->text), "height_changed",
|
|
(GtkSignalFunc) size_changed,
|
|
dicon);
|
|
}
|
|
|
|
static void
|
|
desktop_icon_realize (GtkWidget *widget)
|
|
{
|
|
DesktopIcon *dicon;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (IS_DESKTOP_ICON (widget));
|
|
|
|
dicon = DESKTOP_ICON (widget);
|
|
|
|
if (GTK_WIDGET_CLASS (parent_class)->realize)
|
|
(* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
|
|
|
|
/* Set the window decorations to none and hints to the appropriate combination */
|
|
|
|
gdk_window_set_decorations (widget->window, 0);
|
|
gdk_window_set_functions (widget->window, 0);
|
|
|
|
gnome_win_hints_init ();
|
|
|
|
if (gnome_win_hints_wm_exists ()) {
|
|
gnome_win_hints_set_layer (widget, WIN_LAYER_DESKTOP);
|
|
gnome_win_hints_set_state (widget, WIN_STATE_FIXED_POSITION | WIN_STATE_ARRANGE_IGNORE);
|
|
gnome_win_hints_set_hints (widget,
|
|
(WIN_HINTS_SKIP_FOCUS
|
|
| WIN_HINTS_SKIP_WINLIST
|
|
| WIN_HINTS_SKIP_TASKBAR));
|
|
}
|
|
|
|
/* Set the stipple color now that we have a style */
|
|
|
|
gnome_canvas_item_set (dicon->stipple,
|
|
"fill_color_gdk", &widget->style->bg[GTK_STATE_SELECTED],
|
|
NULL);
|
|
}
|
|
|
|
/* Sets the icon from the specified image. Does not re-create the window shape for the desktop
|
|
* icon.
|
|
*/
|
|
static void
|
|
set_icon (DesktopIcon *dicon, GdkImlibImage *im)
|
|
{
|
|
GdkImlibImage *old_im;
|
|
GtkArg arg;
|
|
|
|
/* Destroy the old image if it exists */
|
|
|
|
arg.name = "image";
|
|
gtk_object_getv (GTK_OBJECT (dicon->icon), 1, &arg);
|
|
|
|
old_im = GTK_VALUE_POINTER (arg);
|
|
|
|
gnome_canvas_item_set (dicon->icon,
|
|
"image", im,
|
|
"width", (double) im->rgb_width,
|
|
"height", (double) im->rgb_height,
|
|
NULL);
|
|
|
|
if (old_im)
|
|
gdk_imlib_destroy_image (old_im);
|
|
}
|
|
|
|
/* Sets the text in the desktop icon, but does not re-create its window shape. */
|
|
static void
|
|
set_text (DesktopIcon *dicon, char *text)
|
|
{
|
|
GtkArg arg;
|
|
int icon_height;
|
|
|
|
arg.name = "height";
|
|
gtk_object_getv (GTK_OBJECT (dicon->icon), 1, &arg);
|
|
icon_height = GTK_VALUE_DOUBLE (arg);
|
|
|
|
gtk_signal_handler_block (GTK_OBJECT (dicon->text), dicon->w_changed_id);
|
|
gtk_signal_handler_block (GTK_OBJECT (dicon->text), dicon->h_changed_id);
|
|
|
|
gnome_icon_text_item_configure (GNOME_ICON_TEXT_ITEM (dicon->text),
|
|
0, icon_height + SPACING,
|
|
DESKTOP_SNAP_X,
|
|
DESKTOP_ICON_FONT,
|
|
text,
|
|
TRUE);
|
|
|
|
gtk_signal_handler_unblock (GTK_OBJECT (dicon->text), dicon->w_changed_id);
|
|
gtk_signal_handler_unblock (GTK_OBJECT (dicon->text), dicon->h_changed_id);
|
|
}
|
|
|
|
/**
|
|
* desktop_icon_new
|
|
* @image: Imlib image with the icon.
|
|
* @text: Text to use for the icon.
|
|
*
|
|
* Creates a new desktop icon widget with the specified icon image and text. The icon has to be
|
|
* positioned at the desired place.
|
|
*
|
|
* Returns the newly-created desktop icon widget.
|
|
*/
|
|
GtkWidget *
|
|
desktop_icon_new (GdkImlibImage *image, char *text)
|
|
{
|
|
DesktopIcon *dicon;
|
|
|
|
g_return_val_if_fail (image != NULL, NULL);
|
|
g_return_val_if_fail (text != NULL, NULL);
|
|
|
|
dicon = gtk_type_new (desktop_icon_get_type ());
|
|
|
|
set_icon (dicon, image);
|
|
set_text (dicon, text);
|
|
desktop_icon_reshape (dicon);
|
|
|
|
return GTK_WIDGET (dicon);
|
|
}
|
|
|
|
/**
|
|
* desktop_icon_set_icon
|
|
* @dicon: The desktop icon to set the icon for
|
|
* @image: Imlib image with the icon.
|
|
*
|
|
* Sets a new icon for an existing desktop icon.
|
|
*/
|
|
void
|
|
desktop_icon_set_icon (DesktopIcon *dicon, GdkImlibImage *image)
|
|
{
|
|
g_return_if_fail (dicon != NULL);
|
|
g_return_if_fail (IS_DESKTOP_ICON (dicon));
|
|
g_return_if_fail (image != NULL);
|
|
|
|
set_icon (dicon, image);
|
|
desktop_icon_reshape (dicon);
|
|
}
|
|
|
|
/**
|
|
* desktop_icon_set_text
|
|
* @dicon: The desktop icon to set the text for
|
|
* @text: The new text to use for the icon's title
|
|
*
|
|
* Sets a new title for an existing desktop icon.
|
|
*/
|
|
void
|
|
desktop_icon_set_text (DesktopIcon *dicon, char *text)
|
|
{
|
|
g_return_if_fail (dicon != NULL);
|
|
g_return_if_fail (IS_DESKTOP_ICON (dicon));
|
|
g_return_if_fail (text != NULL);
|
|
|
|
set_text (dicon, text);
|
|
desktop_icon_reshape (dicon);
|
|
}
|
|
|
|
/* Computes and sets a new window shape for the desktop icon */
|
|
static void
|
|
create_window_shape (DesktopIcon *dicon, int icon_width, int icon_height, int text_width, int text_height)
|
|
{
|
|
GdkImlibImage *im;
|
|
GdkBitmap *mask;
|
|
GdkBitmap *im_mask;
|
|
GdkGC *mgc;
|
|
GdkColor c;
|
|
|
|
/* Create the initial mask and clear it */
|
|
|
|
mask = gdk_pixmap_new (GTK_WIDGET (dicon)->window, dicon->width, dicon->height, 1);
|
|
|
|
mgc = gdk_gc_new (mask);
|
|
c.pixel = 0;
|
|
gdk_gc_set_foreground (mgc, &c);
|
|
gdk_draw_rectangle (mask, mgc, TRUE, 0, 0, dicon->width, dicon->height);
|
|
|
|
c.pixel = 1;
|
|
gdk_gc_set_foreground (mgc, &c);
|
|
|
|
/* Paint the mask of the image */
|
|
|
|
im = GNOME_CANVAS_IMAGE (dicon->icon)->im;
|
|
gdk_imlib_render (im, icon_width, icon_height);
|
|
im_mask = gdk_imlib_move_mask (im);
|
|
|
|
if (im_mask && desktop_use_shaped_icons) {
|
|
gdk_draw_pixmap (mask,
|
|
mgc,
|
|
im_mask,
|
|
0, 0,
|
|
(dicon->width - icon_width) / 2, 0,
|
|
icon_width, icon_height);
|
|
gdk_imlib_free_bitmap (im_mask);
|
|
} else
|
|
gdk_draw_rectangle (mask, mgc, TRUE,
|
|
(dicon->width - icon_width) / 2, 0,
|
|
icon_width, icon_height);
|
|
|
|
/* Fill the area for the text */
|
|
|
|
gdk_draw_rectangle (mask, mgc, TRUE,
|
|
(dicon->width - text_width) / 2,
|
|
icon_height + SPACING,
|
|
text_width, text_height);
|
|
|
|
if (!GTK_WIDGET_REALIZED (dicon))
|
|
gtk_widget_realize (GTK_WIDGET (dicon));
|
|
|
|
gtk_widget_shape_combine_mask (GTK_WIDGET (dicon), mask, 0, 0);
|
|
gdk_bitmap_unref (mask);
|
|
gdk_gc_unref (mgc);
|
|
}
|
|
|
|
/**
|
|
* desktop_icon_reshape
|
|
* @dicon: The desktop icon whose shape will be recalculated
|
|
*
|
|
* Recomputes the window shape for the specified desktop icon. This needs to be called only when
|
|
* the global desktop_use_shaped_icons flag changes.
|
|
*/
|
|
void
|
|
desktop_icon_reshape (DesktopIcon *dicon)
|
|
{
|
|
GtkArg args[2];
|
|
int icon_width, icon_height;
|
|
int text_width, text_height;
|
|
double x1, y1, x2, y2;
|
|
|
|
g_return_if_fail (dicon != NULL);
|
|
g_return_if_fail (IS_DESKTOP_ICON (dicon));
|
|
|
|
/* Get size of icon image */
|
|
|
|
args[0].name = "width";
|
|
args[1].name = "height";
|
|
gtk_object_getv (GTK_OBJECT (dicon->icon), 2, args);
|
|
icon_width = GTK_VALUE_DOUBLE (args[0]);
|
|
icon_height = GTK_VALUE_DOUBLE (args[0]);
|
|
|
|
/* Get size of icon text */
|
|
|
|
gnome_canvas_item_get_bounds (dicon->text, &x1, &y1, &x2, &y2);
|
|
|
|
text_width = x2 - x1 + 1;
|
|
text_height = y2 - y1 + 1;
|
|
|
|
/* Calculate new size of widget */
|
|
|
|
dicon->width = MAX (icon_width, DESKTOP_SNAP_X);
|
|
dicon->height = icon_height + SPACING + text_height;
|
|
|
|
/* Set new position of children */
|
|
|
|
gnome_canvas_item_set (dicon->icon,
|
|
"x", (dicon->width - icon_width) / 2.0,
|
|
"y", 0.0,
|
|
NULL);
|
|
gnome_canvas_item_set (dicon->stipple,
|
|
"x1", 0.0,
|
|
"y1", 0.0,
|
|
"x2", (double) dicon->width,
|
|
"y2", (double) icon_height,
|
|
NULL);
|
|
|
|
gnome_icon_text_item_setxy (GNOME_ICON_TEXT_ITEM (dicon->text), 0, icon_height + SPACING);
|
|
|
|
/* Create and set the window shape */
|
|
|
|
gtk_widget_set_usize (GTK_WIDGET (dicon), dicon->width, dicon->height);
|
|
create_window_shape (dicon, icon_width, icon_height, text_width, text_height);
|
|
|
|
dicon->icon_x = (int) ((dicon->width - icon_width) / 2.0 + 0.5);
|
|
dicon->icon_y = 0;
|
|
dicon->icon_w = icon_width;
|
|
dicon->icon_h = icon_height;
|
|
|
|
dicon->text_x = x1;
|
|
dicon->text_y = y1;
|
|
dicon->text_w = text_width;
|
|
dicon->text_h = text_height;
|
|
}
|
|
|
|
/**
|
|
* desktop_icon_select
|
|
* @dicon: The desktop icon which will be selected/unselected
|
|
* @sel: TRUE if icon should be selected, FALSE if it should be unselected
|
|
*
|
|
* Selects or unselects the icon. This means setting the selection flag of the icon text item as
|
|
* appropriate, and displaying the icon image as selected or not.
|
|
*/
|
|
void
|
|
desktop_icon_select (DesktopIcon *dicon, int sel)
|
|
{
|
|
g_return_if_fail (dicon != NULL);
|
|
g_return_if_fail (IS_DESKTOP_ICON (dicon));
|
|
|
|
if (sel)
|
|
gnome_canvas_item_show (dicon->stipple);
|
|
else
|
|
gnome_canvas_item_hide (dicon->stipple);
|
|
|
|
gnome_icon_text_item_select (GNOME_ICON_TEXT_ITEM (dicon->text), sel);
|
|
}
|