static void thunar_icon_renderer_render (GtkCellRenderer *renderer, GdkWindow *window, GtkWidget *widget, GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area, GtkCellRendererState flags) { ThunarClipboardManager *clipboard; ThunarFileIconState icon_state; ThunarIconRenderer *icon_renderer = THUNAR_ICON_RENDERER (renderer); ThunarIconFactory *icon_factory; GtkIconSource *icon_source; GtkIconTheme *icon_theme; GdkRectangle emblem_area; GdkRectangle icon_area; GdkRectangle draw_area; GtkStateType state; GdkPixbuf *emblem; GdkPixbuf *icon; GdkPixbuf *temp; GList *emblems; GList *lp; gint max_emblems; gint position; if (G_UNLIKELY (icon_renderer->file == NULL)) return; /* determine the icon state */ icon_state = (icon_renderer->drop_file != icon_renderer->file) ? renderer->is_expanded ? THUNAR_FILE_ICON_STATE_OPEN : THUNAR_FILE_ICON_STATE_DEFAULT : THUNAR_FILE_ICON_STATE_DROP; /* load the main icon */ icon_theme = gtk_icon_theme_get_for_screen (gdk_drawable_get_screen (window)); icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme); icon = thunar_icon_factory_load_file_icon (icon_factory, icon_renderer->file, icon_state, icon_renderer->size); if (G_UNLIKELY (icon == NULL)) { g_object_unref (G_OBJECT (icon_factory)); return; } /* pre-light the item if we're dragging about it */ if (G_UNLIKELY (icon_state == THUNAR_FILE_ICON_STATE_DROP)) flags |= GTK_CELL_RENDERER_PRELIT; /* determine the real icon size */ icon_area.width = gdk_pixbuf_get_width (icon); icon_area.height = gdk_pixbuf_get_height (icon); /* scale down the icon on-demand */ if (G_UNLIKELY (icon_area.width > cell_area->width || icon_area.height > cell_area->height)) { /* scale down to fit */ temp = exo_gdk_pixbuf_scale_down (icon, TRUE, cell_area->width, cell_area->height); g_object_unref (G_OBJECT (icon)); icon = temp; /* determine the icon dimensions again */ icon_area.width = gdk_pixbuf_get_width (icon); icon_area.height = gdk_pixbuf_get_height (icon); } icon_area.x = cell_area->x + (cell_area->width - icon_area.width) / 2; icon_area.y = cell_area->y + (cell_area->height - icon_area.height) / 2; /* check whether the icon is affected by the expose event */ if (gdk_rectangle_intersect (expose_area, &icon_area, &draw_area)) { /* use a translucent icon to represent cutted and hidden files to the user */ clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (widget)); if (thunar_clipboard_manager_has_cutted_file (clipboard, icon_renderer->file)) { /* 50% translucent for cutted files */ temp = exo_gdk_pixbuf_lucent (icon, 50); g_object_unref (G_OBJECT (icon)); icon = temp; } else if (thunar_file_is_hidden (icon_renderer->file)) { /* 75% translucent for hidden files */ temp = exo_gdk_pixbuf_lucent (icon, 75); g_object_unref (G_OBJECT (icon)); icon = temp; } g_object_unref (G_OBJECT (clipboard)); /* colorize the icon if we should follow the selection state */ if ((flags & (GTK_CELL_RENDERER_SELECTED | GTK_CELL_RENDERER_PRELIT)) != 0 && icon_renderer->follow_state) { if ((flags & GTK_CELL_RENDERER_SELECTED) != 0) { state = GTK_WIDGET_HAS_FOCUS (widget) ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE; temp = exo_gdk_pixbuf_colorize (icon, &widget->style->base[state]); g_object_unref (G_OBJECT (icon)); icon = temp; } if ((flags & GTK_CELL_RENDERER_PRELIT) != 0) { temp = exo_gdk_pixbuf_spotlight (icon); g_object_unref (G_OBJECT (icon)); icon = temp; } } /* check if we should render an insensitive icon */ if (G_UNLIKELY (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE || !renderer->sensitive)) { /* allocate an icon source */ icon_source = gtk_icon_source_new (); gtk_icon_source_set_pixbuf (icon_source, icon); gtk_icon_source_set_size_wildcarded (icon_source, FALSE); gtk_icon_source_set_size (icon_source, GTK_ICON_SIZE_SMALL_TOOLBAR); /* render the insensitive icon */ temp = gtk_style_render_icon (widget->style, icon_source, gtk_widget_get_direction (widget), GTK_STATE_INSENSITIVE, -1, widget, "gtkcellrendererpixbuf"); g_object_unref (G_OBJECT (icon)); icon = temp; /* release the icon source */ gtk_icon_source_free (icon_source); } /* render the invalid parts of the icon */ gdk_draw_pixbuf (window, widget->style->black_gc, icon, draw_area.x - icon_area.x, draw_area.y - icon_area.y, draw_area.x, draw_area.y, draw_area.width, draw_area.height, GDK_RGB_DITHER_NORMAL, 0, 0); } /* release the file's icon */ g_object_unref (G_OBJECT (icon)); /* check if we should render emblems as well */ if (G_LIKELY (icon_renderer->emblems)) { /* display the primary emblem as well (if any) */ emblems = thunar_file_get_emblem_names (icon_renderer->file); if (G_UNLIKELY (emblems != NULL)) { /* render up to four emblems for sizes from 48 onwards, else up to 2 emblems */ max_emblems = (icon_renderer->size < 48) ? 2 : 4; /* render the emblems */ for (lp = emblems, position = 0; lp != NULL && position < max_emblems; lp = lp->next) { /* check if we have the emblem in the icon theme */ emblem = thunar_icon_factory_load_icon (icon_factory, lp->data, icon_renderer->size, NULL, FALSE); if (G_UNLIKELY (emblem == NULL)) continue; /* determine the dimensions of the emblem */ emblem_area.width = gdk_pixbuf_get_width (emblem); emblem_area.height = gdk_pixbuf_get_height (emblem); /* shrink insane emblems */ if (G_UNLIKELY (MAX (emblem_area.width, emblem_area.height) > MIN ((2 * icon_renderer->size) / 3, 36))) { /* scale down the emblem */ temp = exo_gdk_pixbuf_scale_ratio (emblem, MIN ((2 * icon_renderer->size) / 3, 36)); g_object_unref (G_OBJECT (emblem)); emblem = temp; /* determine the size again */ emblem_area.width = gdk_pixbuf_get_width (emblem); emblem_area.height = gdk_pixbuf_get_height (emblem); } /* determine a good position for the emblem, depending on the position index */ switch (position) { case 0: /* right/bottom */ emblem_area.x = MIN (icon_area.x + icon_area.width - emblem_area.width / 2, cell_area->x + cell_area->width - emblem_area.width); emblem_area.y = MIN (icon_area.y + icon_area.height - emblem_area.height / 2, cell_area->y + cell_area->height -emblem_area.height); break; case 1: /* left/bottom */ emblem_area.x = MAX (icon_area.x - emblem_area.width / 2, cell_area->x); emblem_area.y = MIN (icon_area.y + icon_area.height - emblem_area.height / 2, cell_area->y + cell_area->height -emblem_area.height); break; case 2: /* left/top */ emblem_area.x = MAX (icon_area.x - emblem_area.width / 2, cell_area->x); emblem_area.y = MAX (icon_area.y - emblem_area.height / 2, cell_area->y); break; case 3: /* right/top */ emblem_area.x = MIN (icon_area.x + icon_area.width - emblem_area.width / 2, cell_area->x + cell_area->width - emblem_area.width); emblem_area.y = MAX (icon_area.y - emblem_area.height / 2, cell_area->y); break; default: _thunar_assert_not_reached (); } /* render the emblem */ if (gdk_rectangle_intersect (expose_area, &emblem_area, &draw_area)) { gdk_draw_pixbuf (window, widget->style->black_gc, emblem, draw_area.x - emblem_area.x, draw_area.y - emblem_area.y, draw_area.x, draw_area.y, draw_area.width, draw_area.height, GDK_RGB_DITHER_NORMAL, 0, 0); } /* release the emblem */ g_object_unref (G_OBJECT (emblem)); /* advance the position index */ ++position; } /* release the emblem name list */ g_list_free (emblems); } } /* release our reference on the icon factory */ g_object_unref (G_OBJECT (icon_factory)); }
static void thunar_location_entry_button_clicked (GtkWidget *button, ThunarLocationEntry *location_entry) { ThunarShortcutsModel *model; ThunarIconFactory *icon_factory; ThunarVfsVolume *volume; GtkIconTheme *icon_theme; const gchar *icon_name; GtkTreeIter iter; ThunarFile *file; GtkWidget *image; GtkWidget *item; GtkWidget *menu; GdkPixbuf *icon; gint icon_size; gint width; _thunar_return_if_fail (THUNAR_IS_LOCATION_ENTRY (location_entry)); _thunar_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); /* allocate a new menu */ menu = gtk_menu_new (); /* determine the icon theme and factory */ icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (button)); icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme); /* determine the icon size for menus */ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_size, &icon_size); /* load the menu items from the shortcuts model */ model = thunar_shortcuts_model_get_default (); if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter)) { do { /* determine the file and volume for the item */ gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_FILE, &file, THUNAR_SHORTCUTS_MODEL_COLUMN_VOLUME, &volume, -1); /* check if we have a separator here */ if (G_UNLIKELY (file == NULL && volume == NULL)) { /* generate a separator the menu */ item = gtk_separator_menu_item_new (); } else if (G_UNLIKELY (volume != NULL)) { /* generate an image menu item for the volume */ item = gtk_image_menu_item_new_with_label (thunar_vfs_volume_get_name (volume)); /* load the icon for the volume */ icon_name = thunar_vfs_volume_lookup_icon_name (volume, icon_theme); icon = thunar_icon_factory_load_icon (icon_factory, icon_name, icon_size, NULL, FALSE); if (G_LIKELY (icon != NULL)) { /* generate an image for the menu item */ image = gtk_image_new_from_pixbuf (icon); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); g_object_unref (G_OBJECT (icon)); gtk_widget_show (image); } } else { /* generate an image menu item for the file */ item = gtk_image_menu_item_new_with_label (thunar_file_get_display_name (file)); /* load the icon for the file and generate the image for the menu item */ icon = thunar_icon_factory_load_file_icon (icon_factory, file, THUNAR_FILE_ICON_STATE_DEFAULT, icon_size); image = gtk_image_new_from_pixbuf (icon); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); g_object_unref (G_OBJECT (icon)); gtk_widget_show (image); } /* connect the file and volume to the item */ g_object_set_data_full (G_OBJECT (item), I_("thunar-vfs-volume"), volume, g_object_unref); g_object_set_data_full (G_OBJECT (item), I_("thunar-file"), file, g_object_unref); /* append the new item to the menu */ g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (thunar_location_entry_item_activated), location_entry); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter)); } /* make sure the menu has atleast the same width as the location entry */ width = GTK_WIDGET (location_entry)->allocation.width - 2 * gtk_container_get_border_width (GTK_CONTAINER (location_entry)); if (G_LIKELY (menu->allocation.width < width)) gtk_widget_set_size_request (menu, width, -1); /* select the first visible or selectable item in the menu */ gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), TRUE); /* enable the button, making sure that we do not recurse on the "clicked" signal by temporarily blocking the handler */ g_signal_handlers_block_by_func (G_OBJECT (button), G_CALLBACK (thunar_location_entry_button_clicked), location_entry); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); g_signal_handlers_unblock_by_func (G_OBJECT (button), G_CALLBACK (thunar_location_entry_button_clicked), location_entry); /* run the menu, taking ownership over the menu object */ thunar_gtk_menu_run (GTK_MENU (menu), button, menu_position, location_entry, 1, gtk_get_current_event_time ()); /* disable the button, making sure that we do not recurse on the "clicked" signal by temporarily blocking the handler */ g_signal_handlers_block_by_func (G_OBJECT (button), G_CALLBACK (thunar_location_entry_button_clicked), location_entry); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE); g_signal_handlers_unblock_by_func (G_OBJECT (button), G_CALLBACK (thunar_location_entry_button_clicked), location_entry); /* clean up */ g_object_unref (G_OBJECT (icon_factory)); g_object_unref (G_OBJECT (model)); }