/* 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 .
*
* Authors: Alexander Larsson
*/
#include
#include "nautilus-ui-utilities.h"
#include "nautilus-icon-info.h"
#include "nautilus-application.h"
#include
#include
#include
#include
#include
/**
* nautilus_gmenu_set_from_model:
* @target_menu: the #GMenu to be filled
* @source_model: (nullable): a #GMenuModel to copy items from
*
* This will replace the content of @target_menu with a copy of all items from
* @source_model.
*
* If the @source_model is empty (i.e., its item count is 0), or if it is %NULL,
* then the @target_menu is left empty.
*/
void
nautilus_gmenu_set_from_model (GMenu *target_menu,
GMenuModel *source_model)
{
g_return_if_fail (G_IS_MENU (target_menu));
g_return_if_fail (source_model == NULL || G_IS_MENU_MODEL (source_model));
/* First, empty the menu... */
g_menu_remove_all (target_menu);
/* ...then, repopulate it (maybe). */
if (source_model != NULL)
{
gint n_items;
n_items = g_menu_model_get_n_items (source_model);
for (gint i = 0; i < n_items; i++)
{
g_autoptr (GMenuItem) item = NULL;
item = g_menu_item_new_from_model (source_model, i);
g_menu_append_item (target_menu, item);
}
}
}
/**
* nautilus_g_menu_model_find_by_string:
* @model: the #GMenuModel with items to search
* @attribute: the menu item attribute to compare with
* @string: the string to match the value of @attribute
*
* This will search for an item in the model which has got the @attribute and
* whose value is equal to @string.
*
* It is assumed that @attribute has the a GVariant format string "s".
*
* Returns: The index of the first match in the model, or -1 if no item matches.
*/
gint
nautilus_g_menu_model_find_by_string (GMenuModel *model,
const gchar *attribute,
const gchar *string)
{
gint item_index = -1;
gint n_items;
n_items = g_menu_model_get_n_items (model);
for (gint i = 0; i < n_items; i++)
{
g_autofree gchar *value = NULL;
if (g_menu_model_get_item_attribute (model, i, attribute, "s", &value) &&
g_strcmp0 (value, string) == 0)
{
item_index = i;
break;
}
}
return item_index;
}
/**
* nautilus_g_menu_replace_string_in_item:
* @menu: the #GMenu to modify
* @i: the position of the item to change
* @attribute: the menu item attribute to change
* @string: the string to change the value of @attribute to
*
* This will replace the item at @position with a new item which is identical
* except that it has @attribute set to @string.
*
* This is useful e.g. when want to change the menu model of a #GtkPopover and
* you have a pointer to its menu model but not to the popover itself, so you
* can't just set a new model. With this method, the GtkPopover is notified of
* changes in its model and updates its contents accordingly.
*
* It is assumed that @attribute has the a GVariant format string "s".
*/
void
nautilus_g_menu_replace_string_in_item (GMenu *menu,
gint i,
const gchar *attribute,
const gchar *string)
{
g_autoptr (GMenuItem) item = NULL;
g_return_if_fail (i != -1);
item = g_menu_item_new_from_model (G_MENU_MODEL (menu), i);
g_return_if_fail (item != NULL);
if (string != NULL)
{
g_menu_item_set_attribute (item, attribute, "s", string);
}
else
{
g_menu_item_set_attribute (item, attribute, NULL);
}
g_menu_remove (menu, i);
g_menu_insert_item (menu, i, item);
}
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 (GtkSnapshot *snapshot,
gdouble width,
gdouble height)
{
g_autoptr (GdkTexture) left_texture = NULL;
g_autoptr (GdkTexture) right_texture = NULL;
int holes_width, holes_height;
if (!ensure_filmholes ())
{
return;
}
holes_width = gdk_pixbuf_get_width (filmholes_left);
holes_height = gdk_pixbuf_get_height (filmholes_left);
/* Left */
gtk_snapshot_push_repeat (snapshot,
&GRAPHENE_RECT_INIT (0, 0, holes_width, height),
NULL);
left_texture = gdk_texture_new_for_pixbuf (filmholes_left);
gtk_snapshot_append_texture (snapshot,
left_texture,
&GRAPHENE_RECT_INIT (0, 0, holes_width, holes_height));
gtk_snapshot_pop (snapshot);
/* Right */
gtk_snapshot_push_repeat (snapshot,
&GRAPHENE_RECT_INIT (width - holes_width, 0, holes_width, height),
NULL);
right_texture = gdk_texture_new_for_pixbuf (filmholes_right);
gtk_snapshot_append_texture (snapshot,
right_texture,
&GRAPHENE_RECT_INIT (width - holes_width, 0, holes_width, holes_height));
gtk_snapshot_pop (snapshot);
}
gboolean
nautilus_date_time_is_between_dates (GDateTime *date,
GDateTime *initial_date,
GDateTime *end_date)
{
gboolean in_between;
/* Silently ignore errors */
if (date == NULL || g_date_time_to_unix (date) == 0)
{
return FALSE;
}
/* For the end date, we want to make end_date inclusive,
* for that the difference between the start of the day and the in_between
* has to be more than -1 day
*/
in_between = g_date_time_difference (date, initial_date) > 0 &&
g_date_time_difference (end_date, date) / G_TIME_SPAN_DAY > -1;
return in_between;
}
static const gchar *
get_text_for_days_ago (gint days,
gboolean prefix_with_since)
{
if (days < 7)
{
/* days */
return prefix_with_since ?
ngettext ("Since %d day ago", "Since %d days ago", days) :
ngettext ("%d day ago", "%d days ago", days);
}
if (days < 30)
{
/* weeks */
return prefix_with_since ?
ngettext ("Since last week", "Since %d weeks ago", days / 7) :
ngettext ("Last week", "%d weeks ago", days / 7);
}
if (days < 365)
{
/* months */
return prefix_with_since ?
ngettext ("Since last month", "Since %d months ago", days / 30) :
ngettext ("Last month", "%d months ago", days / 30);
}
/* years */
return prefix_with_since ?
ngettext ("Since last year", "Since %d years ago", days / 365) :
ngettext ("Last year", "%d years ago", days / 365);
}
gchar *
get_text_for_date_range (GPtrArray *date_range,
gboolean prefix_with_since)
{
gint days;
gint normalized;
GDateTime *initial_date;
GDateTime *end_date;
gchar *formatted_date;
gchar *label;
if (!date_range)
{
return NULL;
}
initial_date = g_ptr_array_index (date_range, 0);
end_date = g_ptr_array_index (date_range, 1);
days = g_date_time_difference (end_date, initial_date) / G_TIME_SPAN_DAY;
formatted_date = g_date_time_format (initial_date, "%x");
if (days < 1)
{
label = g_strdup (formatted_date);
}
else
{
if (days < 7)
{
/* days */
normalized = days;
}
else if (days < 30)
{
/* weeks */
normalized = days / 7;
}
else if (days < 365)
{
/* months */
normalized = days / 30;
}
else
{
/* years */
normalized = days / 365;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
label = g_strdup_printf (get_text_for_days_ago (days,
prefix_with_since),
normalized);
#pragma GCC diagnostic pop
}
g_free (formatted_date);
return label;
}
AdwMessageDialog *
show_dialog (const gchar *primary_text,
const gchar *secondary_text,
GtkWindow *parent,
GtkMessageType type)
{
GtkWidget *dialog;
g_return_val_if_fail (parent != NULL, NULL);
dialog = adw_message_dialog_new (parent, primary_text, secondary_text);
adw_message_dialog_add_response (ADW_MESSAGE_DIALOG (dialog), "ok", _("_OK"));
adw_message_dialog_set_default_response (ADW_MESSAGE_DIALOG (dialog), "ok");
gtk_window_present (GTK_WINDOW (dialog));
return ADW_MESSAGE_DIALOG (dialog);
}
static void
notify_unmount_done (GMountOperation *op,
const gchar *message)
{
NautilusApplication *application;
gchar *notification_id;
application = nautilus_application_get_default ();
notification_id = g_strdup_printf ("nautilus-mount-operation-%p", op);
nautilus_application_withdraw_notification (application, notification_id);
if (message != NULL)
{
GNotification *unplug;
GIcon *icon;
gchar **strings;
strings = g_strsplit (message, "\n", 0);
icon = g_themed_icon_new ("media-removable-symbolic");
unplug = g_notification_new (strings[0]);
g_notification_set_body (unplug, strings[1]);
g_notification_set_icon (unplug, icon);
nautilus_application_send_notification (application, notification_id, unplug);
g_object_unref (unplug);
g_object_unref (icon);
g_strfreev (strings);
}
g_free (notification_id);
}
static void
notify_unmount_show (GMountOperation *op,
const gchar *message)
{
NautilusApplication *application;
GNotification *unmount;
gchar *notification_id;
GIcon *icon;
gchar **strings;
application = nautilus_application_get_default ();
strings = g_strsplit (message, "\n", 0);
icon = g_themed_icon_new ("media-removable");
unmount = g_notification_new (strings[0]);
g_notification_set_body (unmount, strings[1]);
g_notification_set_icon (unmount, icon);
g_notification_set_priority (unmount, G_NOTIFICATION_PRIORITY_URGENT);
notification_id = g_strdup_printf ("nautilus-mount-operation-%p", op);
nautilus_application_send_notification (application, notification_id, unmount);
g_object_unref (unmount);
g_object_unref (icon);
g_strfreev (strings);
g_free (notification_id);
}
void
show_unmount_progress_cb (GMountOperation *op,
const gchar *message,
gint64 time_left,
gint64 bytes_left,
gpointer user_data)
{
if (bytes_left == 0)
{
notify_unmount_done (op, message);
}
else
{
notify_unmount_show (op, message);
}
}
void
show_unmount_progress_aborted_cb (GMountOperation *op,
gpointer user_data)
{
notify_unmount_done (op, NULL);
}