mirror of
https://gitlab.gnome.org/GNOME/nautilus
synced 2024-11-05 16:04:31 +00:00
f69c6a7f78
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.
328 lines
8.2 KiB
C
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);
|
|
}
|
|
}
|