/*
* Copyright 2013 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* Authors:
* Lars Uebernickel
*/
#include "idosourcemenuitem.h"
#include
#include "idodetaillabel.h"
#include "idoactionhelper.h"
typedef GtkMenuItemClass IdoSourceMenuItemClass;
struct _IdoSourceMenuItem
{
GtkMenuItem parent;
GtkWidget *icon;
GtkWidget *label;
GtkWidget *detail;
gint64 time;
guint timer_id;
};
G_DEFINE_TYPE (IdoSourceMenuItem, ido_source_menu_item, GTK_TYPE_MENU_ITEM);
static void
ido_source_menu_item_constructed (GObject *object)
{
IdoSourceMenuItem *item = IDO_SOURCE_MENU_ITEM (object);
GtkWidget *grid;
gint icon_width;
gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, NULL);
item->icon = g_object_ref (gtk_image_new ());
gtk_widget_set_margin_left (item->icon, icon_width);
gtk_widget_set_margin_right (item->icon, 6);
item->label = g_object_ref (gtk_label_new (""));
gtk_label_set_max_width_chars (GTK_LABEL (item->label), 40);
gtk_label_set_ellipsize (GTK_LABEL (item->label), PANGO_ELLIPSIZE_END);
gtk_misc_set_alignment (GTK_MISC (item->label), 0.0, 0.5);
item->detail = g_object_ref (ido_detail_label_new (""));
gtk_widget_set_halign (item->detail, GTK_ALIGN_END);
gtk_widget_set_hexpand (item->detail, TRUE);
gtk_style_context_add_class (gtk_widget_get_style_context (item->detail), "accelerator");
grid = gtk_grid_new ();
gtk_grid_attach (GTK_GRID (grid), item->icon, 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), item->label, 1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), item->detail, 2, 0, 1, 1);
gtk_container_add (GTK_CONTAINER (object), grid);
gtk_widget_show_all (grid);
G_OBJECT_CLASS (ido_source_menu_item_parent_class)->constructed (object);
}
static gchar *
ido_source_menu_item_time_span_string (gint64 timestamp)
{
gchar *str;
gint64 span;
gint hours;
gint minutes;
span = MAX (g_get_real_time () - timestamp, 0) / G_USEC_PER_SEC;
hours = span / 3600;
minutes = (span / 60) % 60;
if (hours == 0)
{
/* TRANSLATORS: number of minutes that have passed */
str = g_strdup_printf (ngettext ("%d min", "%d min", minutes), minutes);
}
else
{
/* TRANSLATORS: number of hours that have passed */
str = g_strdup_printf (ngettext ("%d h", "%d h", hours), hours);
}
return str;
}
static void
ido_source_menu_item_set_detail_time (IdoSourceMenuItem *self,
gint64 time)
{
gchar *str;
self->time = time;
str = ido_source_menu_item_time_span_string (self->time);
ido_detail_label_set_text (IDO_DETAIL_LABEL (self->detail), str);
g_free (str);
}
static gboolean
ido_source_menu_item_update_time (gpointer data)
{
IdoSourceMenuItem *self = data;
ido_source_menu_item_set_detail_time (self, self->time);
return TRUE;
}
static void
ido_source_menu_item_dispose (GObject *object)
{
IdoSourceMenuItem *self = IDO_SOURCE_MENU_ITEM (object);
if (self->timer_id != 0)
{
g_source_remove (self->timer_id);
self->timer_id = 0;
}
g_clear_object (&self->icon);
g_clear_object (&self->label);
g_clear_object (&self->detail);
G_OBJECT_CLASS (ido_source_menu_item_parent_class)->dispose (object);
}
static void
ido_source_menu_item_class_init (IdoSourceMenuItemClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = ido_source_menu_item_constructed;
object_class->dispose = ido_source_menu_item_dispose;
}
static void
ido_source_menu_item_init (IdoSourceMenuItem *self)
{
}
static void
ido_source_menu_item_set_label (IdoSourceMenuItem *item,
const gchar *label)
{
gtk_label_set_label (GTK_LABEL (item->label), label ? label : "");
}
static void
ido_source_menu_item_set_icon (IdoSourceMenuItem *item,
GIcon *icon)
{
if (icon)
gtk_image_set_from_gicon (GTK_IMAGE (item->icon), icon, GTK_ICON_SIZE_MENU);
else
gtk_image_clear (GTK_IMAGE (item->icon));
}
static void
ido_source_menu_item_activate (GtkMenuItem *item,
gpointer user_data)
{
IdoActionHelper *helper = user_data;
/* The parameter signifies whether this source was activated (TRUE) or
* dismissed (FALSE). Since there's no UI to dismiss a gtkmenuitem,
* this always passes TRUE. */
ido_action_helper_activate_with_parameter (helper, g_variant_new_boolean (TRUE));
}
static void
ido_source_menu_item_state_changed (IdoActionHelper *helper,
GVariant *state,
gpointer user_data)
{
IdoSourceMenuItem *item = user_data;
guint32 count;
gint64 time;
const gchar *str;
if (item->timer_id != 0)
{
g_source_remove (item->timer_id);
item->timer_id = 0;
}
g_return_if_fail (g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)")));
g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL);
if (count != 0)
ido_detail_label_set_count (IDO_DETAIL_LABEL (item->detail), count);
else if (time != 0)
{
ido_source_menu_item_set_detail_time (item, time);
item->timer_id = g_timeout_add_seconds (59, ido_source_menu_item_update_time, item);
}
else if (str != NULL && *str)
ido_detail_label_set_text (IDO_DETAIL_LABEL (item->detail), str);
}
GtkMenuItem *
ido_source_menu_item_new_from_menu_model (GMenuItem *menuitem,
GActionGroup *actions)
{
GtkMenuItem *item;
GVariant *serialized_icon;
GIcon *icon = NULL;
gchar *label;
gchar *action = NULL;
item = g_object_new (IDO_TYPE_SOURCE_MENU_ITEM, NULL);
if (g_menu_item_get_attribute (menuitem, "label", "s", &label))
{
ido_source_menu_item_set_label (IDO_SOURCE_MENU_ITEM (item), label);
g_free (label);
}
serialized_icon = g_menu_item_get_attribute_value (menuitem, "icon", NULL);
if (serialized_icon)
{
icon = g_icon_deserialize (serialized_icon);
g_variant_unref (serialized_icon);
}
ido_source_menu_item_set_icon (IDO_SOURCE_MENU_ITEM (item), icon);
if (g_menu_item_get_attribute (menuitem, "action", "s", &action))
{
IdoActionHelper *helper;
helper = ido_action_helper_new (GTK_WIDGET (item), actions, action, NULL);
g_signal_connect (helper, "action-state-changed",
G_CALLBACK (ido_source_menu_item_state_changed), item);
g_signal_connect_object (item, "activate",
G_CALLBACK (ido_source_menu_item_activate), helper,
0);
g_signal_connect_swapped (item, "destroy", G_CALLBACK (g_object_unref), helper);
g_free (action);
}
if (icon)
g_object_unref (icon);
return item;
}