diff --git a/gnome/ChangeLog b/gnome/ChangeLog index b29a1e7f5..3b1851d0d 100644 --- a/gnome/ChangeLog +++ b/gnome/ChangeLog @@ -1,3 +1,20 @@ +1998-11-01 Federico Mena Quintero + + * gdesktop-icon.h (DesktopIcon): Added a child item for stippling + the icon when it is selected. + + * gdesktop-icon.c (desktop_icon_select): Show/hide the stippling + as appropriate. + + * gdesktop.c (desktop_icon_info_event): Handler for events on + desktop icons. + (select_icon): New function that handles icon selection based on + mouse clicks and modifier keys. + + * gdesktop.c (struct desktop_icon_info): Added a type field to the + structure. It specifies the type of icon (file, directory), and + is used to determine the DnD and menu behavior. + 1998-10-30 Federico Mena Quintero * gdesktop.c: We are now using the new desktop icon code. It is diff --git a/gnome/gdesktop-icon.c b/gnome/gdesktop-icon.c index 62db171b7..9dd32b2ef 100644 --- a/gnome/gdesktop-icon.c +++ b/gnome/gdesktop-icon.c @@ -15,6 +15,13 @@ #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); @@ -88,6 +95,8 @@ canvas_size_allocated (GtkWidget *widget, GtkAllocation *allocation, gpointer da static void desktop_icon_init (DesktopIcon *dicon) { + GdkBitmap *stipple; + /* Set the window policy */ gtk_window_set_policy (GTK_WINDOW (dicon), TRUE, TRUE, TRUE); @@ -119,6 +128,14 @@ desktop_icon_init (DesktopIcon *dicon) 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); @@ -130,9 +147,13 @@ desktop_icon_init (DesktopIcon *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); @@ -150,6 +171,12 @@ desktop_icon_realize (GtkWidget *widget) | 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 file. Does not re-create the window shape for the desktop @@ -385,6 +412,12 @@ desktop_icon_reshape (DesktopIcon *dicon) "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); @@ -393,3 +426,25 @@ desktop_icon_reshape (DesktopIcon *dicon) gtk_widget_set_usize (GTK_WIDGET (dicon), dicon->width, dicon->height); create_window_shape (dicon, icon_width, icon_height, text_width, 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); +} diff --git a/gnome/gdesktop-icon.h b/gnome/gdesktop-icon.h index f9ec47a4e..a1008c067 100644 --- a/gnome/gdesktop-icon.h +++ b/gnome/gdesktop-icon.h @@ -36,6 +36,7 @@ struct _DesktopIcon { GnomeCanvasItem *icon; /* The item that contains the icon */ GnomeCanvasItem *text; /* The item that contains the editable text */ + GnomeCanvasItem *stipple; /* The rectangle used as a stipple when the icon is selected */ int width, height; /* Total size of the window */ @@ -63,6 +64,9 @@ void desktop_icon_set_text (DesktopIcon *dicon, char *text); /* Makes the desktop icon reshape itself (for when the global desktop_use_shaped_icons flag changes) */ void desktop_icon_reshape (DesktopIcon *dicon); +/* Selects or unselects the icon based on the value of sel (TRUE is selected, FALSE is unselected) */ +void desktop_icon_select (DesktopIcon *dicon, int sel); + END_GNOME_DECLS diff --git a/gnome/gdesktop.c b/gnome/gdesktop.c index efd984750..95bcf2eec 100644 --- a/gnome/gdesktop.c +++ b/gnome/gdesktop.c @@ -20,11 +20,19 @@ #define DESKTOP_DIR_NAME "desktop" +/* Types of desktop icons */ +enum icon_type { + ICON_FILE, /* Denotes a file (or symlink to a file) */ + ICON_DIRECTORY /* Denotes a directory (or symlink to one) */ +}; + + /* This structure defines the information carried by a desktop icon */ struct desktop_icon_info { GtkWidget *dicon; /* The desktop icon widget */ int x, y; /* Position in the desktop */ char *filename; /* The file this icon refers to (relative to the desktop_directory) */ + enum icon_type type; /* Type of icon, used to determine menu and DnD behavior */ int selected : 1; /* Is the icon selected? */ }; @@ -152,6 +160,101 @@ desktop_icon_info_place (struct desktop_icon_info *dii, int auto_pos, int xpos, gtk_widget_set_uposition (dii->dicon, xpos, ypos); } +/* Unselects all the desktop icons */ +static void +unselect_all (void) +{ + GList *l; + struct desktop_icon_info *dii; + + for (l = desktop_icons; l; l = l->next) { + dii = l->data; + + if (dii->selected) { + desktop_icon_select (dii->dicon, FALSE); + dii->selected = FALSE; + } + } +} + +/* Handles icon selection and unselection due to button presses */ +static void +select_icon (struct desktop_icon_info *dii, GdkEventButton *event) +{ + if (!(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK))) { + /* Click on an unselected icon unselects everything and selects the icon */ + unselect_all (); + desktop_icon_select (dii->dicon, TRUE); + dii->selected = TRUE; + } else if (event->state & GDK_SHIFT_MASK) { + ; /* FIXME: handle range selection */ + } else if (event->state & GDK_CONTROL_MASK) { + /* Control-click on an icon toggles its selected state */ + desktop_icon_select (dii->dicon, !dii->selected); + dii->selected = !dii->selected; + } +} + +/* Handler for events on desktop icons. The on_text flag specifies whether the event ocurred on the + * text item in the icon or not. + */ +static gint +desktop_icon_info_event (struct desktop_icon_info *dii, GdkEvent *event, int on_text) +{ + int retval; + + retval = FALSE; + + switch (event->type) { + case GDK_BUTTON_PRESS: + if ((event->button.button == 1) && !(on_text && dii->selected)) { + select_icon (dii, (GdkEventButton *) event); + retval = TRUE; + } else if (event->button.button == 3) + retval = TRUE; /* FIXME: display menu */ + + break; + + case GDK_2BUTTON_PRESS: + if (event->button.button != 1) + break; + + /* FIXME: activate icon */ + + retval = TRUE; + break; + + default: + break; + } + + /* If we handled the event, do not pass it on to the icon text item */ + + if (on_text && retval) + gtk_signal_emit_stop_by_name (GTK_OBJECT (DESKTOP_ICON (dii->dicon)->text), + "event"); + + return retval; +} + +/* Handler for button presses on the images on desktop icons. The desktop icon info structure is + * passed in the user data. + */ +static gint +icon_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data) +{ + return desktop_icon_info_event (data, event, FALSE); +} + +/* Handler for button presses on the text on desktop icons. The desktop icon info structure is + * passed in the user data. + */ +static gint +text_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data) +{ + return desktop_icon_info_event (data, event, TRUE); +} + /* Creates a new desktop icon. The filename is the pruned filename inside the desktop directory. * If auto_pos is true, then the function will look for a place to position the icon automatically, * else it will use the specified coordinates. It does not show the icon. @@ -162,20 +265,44 @@ desktop_icon_info_new (char *filename, int auto_pos, int xpos, int ypos) struct desktop_icon_info *dii; char *full_name; char *icon_name; + struct stat s; full_name = g_concat_dir_and_file (desktop_directory, filename); + + if (mc_stat (full_name, &s) != 0) { + g_warning ("Could not stat %s; will not use a desktop icon", full_name); + g_free (full_name); + return NULL; + } + + /* Create the icon structure */ + icon_name = meta_get_icon_for_file (full_name); dii = g_new (struct desktop_icon_info, 1); dii->dicon = desktop_icon_new (icon_name, filename); dii->filename = g_strdup (filename); + dii->type = S_ISDIR (s.st_mode) ? ICON_DIRECTORY : ICON_FILE; dii->selected = FALSE; g_free (full_name); g_free (icon_name); - desktop_icon_info_place (dii, auto_pos, xpos, ypos); + /* Connect to the icon's signals */ + gtk_signal_connect (GTK_OBJECT (DESKTOP_ICON (dii->dicon)->icon), "event", + (GtkSignalFunc) icon_event, + dii); + gtk_signal_connect (GTK_OBJECT (DESKTOP_ICON (dii->dicon)->text), "event", + (GtkSignalFunc) text_event, + dii); + gtk_signal_connect (GTK_OBJECT (DESKTOP_ICON (dii->dicon)->stipple), "event", + (GtkSignalFunc) icon_event, + dii); + + /* Place the icon and append it to the list */ + + desktop_icon_info_place (dii, auto_pos, xpos, ypos); desktop_icons = g_list_append (desktop_icons, dii); return dii;