nautilus/libnautilus-private/nautilus-ui-utilities.c
Cosimo Cecchi f69c6a7f78 ui-utilities: use libgd to frame images
This fixes problems with framed thumbnail size under some circumstances,
since by passing a lager than expected icon to list view, we would be
causing another scale of the thumbnail.
2015-05-24 19:36:00 -07:00

328 lines
8.2 KiB
C

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* nautilus-ui-utilities.c - helper functions for GtkUIManager stuff
Copyright (C) 2004 Red Hat, 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,
see <http://www.gnu.org/licenses/>.
Authors: Alexander Larsson <alexl@redhat.com>
*/
#include <config.h>
#include "nautilus-ui-utilities.h"
#include "nautilus-icon-info.h"
#include <eel/eel-graphic-effects.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
#include <libgd/gd.h>
#include <string.h>
static GMenuModel *
find_gmenu_model (GMenuModel *model,
const gchar *model_id)
{
gint i, n_items;
GMenuModel *insertion_model = NULL;
n_items = g_menu_model_get_n_items (model);
for (i = 0; i < n_items && !insertion_model; i++) {
gchar *id = NULL;
if (g_menu_model_get_item_attribute (model, i, "id", "s", &id) &&
g_strcmp0 (id, model_id) == 0) {
insertion_model = g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION);
if (!insertion_model)
insertion_model = g_menu_model_get_item_link (model, i, G_MENU_LINK_SUBMENU);
} else {
GMenuModel *submodel;
GMenuModel *submenu;
gint j, j_items;
submodel = g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION);
if (!submodel)
submodel = g_menu_model_get_item_link (model, i, G_MENU_LINK_SUBMENU);
if (!submodel)
continue;
j_items = g_menu_model_get_n_items (submodel);
for (j = 0; j < j_items; j++) {
submenu = g_menu_model_get_item_link (submodel, j, G_MENU_LINK_SUBMENU);
if (submenu) {
insertion_model = find_gmenu_model (submenu, model_id);
g_object_unref (submenu);
}
if (insertion_model)
break;
}
g_object_unref (submodel);
}
g_free (id);
}
return insertion_model;
}
/*
* The original GMenu is modified adding to the section @submodel_name
* the items in @gmenu_to_merge.
* @gmenu_to_merge should be a list of menu items.
*/
void
nautilus_gmenu_merge (GMenu *original,
GMenu *gmenu_to_merge,
const gchar *submodel_name,
gboolean prepend)
{
gint i, n_items;
GMenuModel *submodel;
GMenuItem *item;
g_return_if_fail (G_IS_MENU (original));
g_return_if_fail (G_IS_MENU (gmenu_to_merge));
submodel = find_gmenu_model (G_MENU_MODEL (original), submodel_name);
g_return_if_fail (submodel != NULL);
n_items = g_menu_model_get_n_items (G_MENU_MODEL (gmenu_to_merge));
for (i = 0; i < n_items; i++) {
item = g_menu_item_new_from_model (G_MENU_MODEL (gmenu_to_merge), i);
if (prepend)
g_menu_prepend_item (G_MENU (submodel), item);
else
g_menu_append_item (G_MENU (submodel), item);
g_object_unref (item);
}
g_object_unref (submodel);
}
/*
* The GMenu @menu is modified adding to the section @submodel_name
* the item @item.
*/
void
nautilus_gmenu_add_item_in_submodel (GMenu *menu,
GMenuItem *item,
const gchar *submodel_name,
gboolean prepend)
{
GMenuModel *submodel;
g_return_if_fail (G_IS_MENU (menu));
g_return_if_fail (G_IS_MENU_ITEM (item));
submodel = find_gmenu_model (G_MENU_MODEL (menu), submodel_name);
g_return_if_fail (submodel != NULL);
if (prepend)
g_menu_prepend_item (G_MENU (submodel), item);
else
g_menu_append_item (G_MENU (submodel), item);
g_object_unref (submodel);
}
void
nautilus_gmenu_replace_section (GMenu *menu,
const gchar *section_id,
GMenuModel *section)
{
GMenuModel *orig_section;
GMenuItem *item;
gint idx;
orig_section = find_gmenu_model (G_MENU_MODEL (menu), section_id);
g_return_if_fail (orig_section != NULL);
g_menu_remove_all (G_MENU (orig_section));
for (idx = 0; idx < g_menu_model_get_n_items (section); idx++) {
item = g_menu_item_new_from_model (section, idx);
g_menu_append_item (G_MENU (orig_section), item);
g_object_unref (item);
}
g_object_unref (orig_section);
}
void
nautilus_pop_up_context_menu (GtkWidget *parent,
GMenu *menu,
GdkEventButton *event)
{
GtkWidget *gtk_menu;
int button;
g_return_if_fail (G_IS_MENU (menu));
g_return_if_fail (GTK_IS_WIDGET (parent));
gtk_menu = gtk_menu_new_from_model (G_MENU_MODEL (menu));
gtk_menu_attach_to_widget (GTK_MENU (gtk_menu), parent, NULL);
/* The event button needs to be 0 if we're popping up this menu from
* a button release, else a 2nd click outside the menu with any button
* other than the one that invoked the menu will be ignored (instead
* of dismissing the menu). This is a subtle fragility of the GTK menu code.
*/
if (event) {
button = event->type == GDK_BUTTON_RELEASE
? 0
: event->button;
} else {
button = 0;
}
gtk_menu_popup (GTK_MENU (gtk_menu), /* menu */
NULL, /* parent_menu_shell */
NULL, /* parent_menu_item */
NULL, /* popup_position_func */
NULL, /* popup_position_data */
button, /* button */
event ? event->time : gtk_get_current_event_time ()); /* activate_time */
g_object_ref_sink (gtk_menu);
g_object_unref (gtk_menu);
}
char *
nautilus_escape_action_name (const char *action_name,
const char *prefix)
{
GString *s;
if (action_name == NULL) {
return NULL;
}
s = g_string_new (prefix);
while (*action_name != 0) {
switch (*action_name) {
case '\\':
g_string_append (s, "\\\\");
break;
case '/':
g_string_append (s, "\\s");
break;
case '&':
g_string_append (s, "\\a");
break;
case '"':
g_string_append (s, "\\q");
break;
case ' ':
g_string_append (s, "+");
break;
case '(':
g_string_append (s, "#");
break;
case ')':
g_string_append (s, "^");
break;
case ':':
g_string_append (s, "\\\\");
break;
default:
g_string_append_c (s, *action_name);
}
action_name ++;
}
return g_string_free (s, FALSE);
}
#define NAUTILUS_THUMBNAIL_FRAME_LEFT 3
#define NAUTILUS_THUMBNAIL_FRAME_TOP 3
#define NAUTILUS_THUMBNAIL_FRAME_RIGHT 3
#define NAUTILUS_THUMBNAIL_FRAME_BOTTOM 3
void
nautilus_ui_frame_image (GdkPixbuf **pixbuf)
{
GtkBorder border;
GdkPixbuf *pixbuf_with_frame;
border.left = NAUTILUS_THUMBNAIL_FRAME_LEFT;
border.top = NAUTILUS_THUMBNAIL_FRAME_TOP;
border.right = NAUTILUS_THUMBNAIL_FRAME_RIGHT;
border.bottom = NAUTILUS_THUMBNAIL_FRAME_BOTTOM;
pixbuf_with_frame = gd_embed_image_in_frame (*pixbuf,
"resource:///org/gnome/nautilus/icons/thumbnail_frame.png",
&border, &border);
g_object_unref (*pixbuf);
*pixbuf = pixbuf_with_frame;
}
static GdkPixbuf *filmholes_left = NULL;
static GdkPixbuf *filmholes_right = NULL;
static gboolean
ensure_filmholes (void)
{
if (filmholes_left == NULL) {
filmholes_left = gdk_pixbuf_new_from_resource ("/org/gnome/nautilus/icons/filmholes.png", NULL);
}
if (filmholes_right == NULL &&
filmholes_left != NULL) {
filmholes_right = gdk_pixbuf_flip (filmholes_left, TRUE);
}
return (filmholes_left && filmholes_right);
}
void
nautilus_ui_frame_video (GdkPixbuf **pixbuf)
{
int width, height;
int holes_width, holes_height;
int i;
if (!ensure_filmholes ())
return;
width = gdk_pixbuf_get_width (*pixbuf);
height = gdk_pixbuf_get_height (*pixbuf);
holes_width = gdk_pixbuf_get_width (filmholes_left);
holes_height = gdk_pixbuf_get_height (filmholes_left);
for (i = 0; i < height; i += holes_height) {
gdk_pixbuf_composite (filmholes_left, *pixbuf, 0, i,
MIN (width, holes_width),
MIN (height - i, holes_height),
0, i, 1, 1, GDK_INTERP_NEAREST, 255);
}
for (i = 0; i < height; i += holes_height) {
gdk_pixbuf_composite (filmholes_right, *pixbuf,
width - holes_width, i,
MIN (width, holes_width),
MIN (height - i, holes_height),
width - holes_width, i,
1, 1, GDK_INTERP_NEAREST, 255);
}
}