/* * A GtkCheckMenuItem that uses a GtkSwitch to show its 'active' property * * Copyright © 2012 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 . * * Author: Charles Kerr */ #include "idoswitchmenuitem.h" #include "idoactionhelper.h" static void ido_switch_menu_finalize (GObject * item); static gboolean ido_switch_menu_button_release_event (GtkWidget * widget, GdkEventButton * event); typedef struct { GtkWidget * box; GtkWidget * content_area; GtkWidget * label; GtkWidget * image; GtkWidget * switch_w; GtkWidget * accelerator; } IdoSwitchMenuItemPrivate; /*** **** Life Cycle ***/ G_DEFINE_TYPE_WITH_PRIVATE (IdoSwitchMenuItem, ido_switch_menu_item, GTK_TYPE_CHECK_MENU_ITEM) static void ido_switch_menu_item_class_init (IdoSwitchMenuItemClass *klass) { GObjectClass * gobject_class; GtkWidgetClass * widget_class; GtkCheckMenuItemClass * check_class; gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = ido_switch_menu_finalize; widget_class = GTK_WIDGET_CLASS (klass); widget_class->button_release_event = ido_switch_menu_button_release_event; check_class = GTK_CHECK_MENU_ITEM_CLASS (klass); check_class->draw_indicator = NULL; } static void ido_switch_menu_item_init (IdoSwitchMenuItem *item) { IdoSwitchMenuItemPrivate *priv = ido_switch_menu_item_get_instance_private(item); priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); priv->content_area = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); priv->switch_w = gtk_switch_new (); gtk_box_pack_start (GTK_BOX (priv->box), priv->content_area, TRUE, TRUE, 0); gtk_box_pack_end (GTK_BOX (priv->box), priv->switch_w, FALSE, FALSE, 0); gtk_container_add (GTK_CONTAINER (item), priv->box); gtk_widget_show_all (priv->box); g_object_bind_property (item, "active", priv->switch_w, "active", G_BINDING_SYNC_CREATE); } /*** **** Don't popdown the menu immediately after clicking on a switch... **** wait a moment so the user can see the GtkSwitch be toggled. ***/ static gboolean popdown_later_cb (gpointer widget) { GtkWidget * parent = gtk_widget_get_parent (widget); if (GTK_IS_MENU (parent)) { gtk_menu_shell_deactivate (GTK_MENU_SHELL(parent)); } g_object_unref (widget); return FALSE; /* only call this cb once */ } static gboolean ido_switch_menu_button_release_event (GtkWidget * widget, GdkEventButton * event) { gtk_menu_item_activate (GTK_MENU_ITEM(widget)); g_timeout_add (500, popdown_later_cb, g_object_ref(widget)); return TRUE; /* stop the event so that it doesn't trigger popdown() */ } /** * ido_switch_menu_item_new: * * Creates a new #IdoSwitchMenuItem * * Return Value: a new #IdoSwitchMenuItem. **/ GtkWidget * ido_switch_menu_item_new (void) { return g_object_new (IDO_TYPE_SWITCH_MENU_ITEM, NULL); } /** * ido_switch_menu_item_get_content_area: * @item: The #IdoSwitchMenuItem. * * Get the #GtkContainer to add additional widgets into. * * This function is dperecated. * * Return Value: (transfer none): The #GtkContainer to add additional widgets into. **/ GtkContainer * ido_switch_menu_item_get_content_area (IdoSwitchMenuItem * item) { static gboolean warned = FALSE; g_return_val_if_fail (IDO_IS_SWITCH_MENU_ITEM(item), NULL); IdoSwitchMenuItemPrivate *priv = ido_switch_menu_item_get_instance_private(item); if (!warned) { g_warning ("%s is deprecated. Please don't use it, especially if you're using" "ido_switch_menu_set_{label,icon}()", G_STRFUNC); warned = TRUE; } return GTK_CONTAINER (priv->content_area); } /** * ido_switch_menu_item_set_label: * @item: a #IdoSwitchMenuItem. * @label: a string to set as the label of @item * * Set the label of @item to @label. **/ void ido_switch_menu_item_set_label (IdoSwitchMenuItem *item, const gchar *label) { IdoSwitchMenuItemPrivate *priv; g_return_if_fail (IDO_IS_SWITCH_MENU_ITEM (item)); g_return_if_fail (label != NULL); priv = ido_switch_menu_item_get_instance_private(item); if (priv->label == NULL) { priv->label = gtk_label_new (NULL); gtk_widget_set_halign (priv->label, GTK_ALIGN_START); gtk_widget_show (priv->label); gtk_box_pack_start (GTK_BOX (priv->content_area), priv->label, TRUE, TRUE, 0); } gtk_label_set_text (GTK_LABEL (priv->label), label); } /** * ido_switch_menu_item_set_accelerator: * @item: a #IdoSwitchMenuItem. * @accelerator: a string to set as the accelerator of @item * * Set the accelerator of @item to @accelerator. **/ void ido_switch_menu_item_set_accelerator (IdoSwitchMenuItem *item, const gchar *accelerator) { IdoSwitchMenuItemPrivate *priv; g_return_if_fail (IDO_IS_SWITCH_MENU_ITEM (item)); g_return_if_fail (accelerator != NULL); priv = ido_switch_menu_item_get_instance_private (item); if (priv->accelerator == NULL) { priv->accelerator = gtk_label_new (NULL); gtk_widget_set_halign (priv->accelerator, GTK_ALIGN_END); GtkStyleContext *pContext = gtk_widget_get_style_context (priv->accelerator); gtk_style_context_add_class (pContext, "accelerator"); gtk_widget_show (priv->accelerator); gtk_box_pack_end (GTK_BOX (priv->content_area), priv->accelerator, FALSE, FALSE, 6); } guint nKey; GdkModifierType cType; gtk_accelerator_parse (accelerator, &nKey, &cType); gchar *sText = gtk_accelerator_get_label (nKey, cType); gtk_label_set_text (GTK_LABEL (priv->accelerator), sText); } /** * ido_switch_menu_item_set_icon: * @item: a #IdoSwitchMenuItem. * @icon: (allow-none): a #GIcon * * Set the icon of @item to @icon. **/ void ido_switch_menu_item_set_icon (IdoSwitchMenuItem *item, GIcon *icon) { IdoSwitchMenuItemPrivate *priv; g_return_if_fail (IDO_IS_SWITCH_MENU_ITEM (item)); g_return_if_fail (icon == NULL || G_IS_ICON (icon)); priv = ido_switch_menu_item_get_instance_private(item); if (icon) { if (priv->image == NULL) { priv->image = gtk_image_new (); gtk_widget_show (priv->image); gtk_box_pack_start (GTK_BOX (priv->content_area), priv->image, FALSE, FALSE, 0); } gtk_image_set_from_gicon (GTK_IMAGE (priv->image), icon, GTK_ICON_SIZE_MENU); } else if (priv->image) { gtk_image_clear (GTK_IMAGE (priv->image)); } } static void ido_source_menu_item_state_changed (IdoActionHelper *helper, GVariant *state, gpointer user_data) { IdoSwitchMenuItem *item = IDO_SWITCH_MENU_ITEM (user_data); if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN)) gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_variant_get_boolean (state)); } static void ido_switch_menu_item_activate(IdoSwitchMenuItem *self, gpointer user_data) { g_return_if_fail(IDO_IS_SWITCH_MENU_ITEM(self)); IdoActionHelper *helper = user_data; IdoSwitchMenuItemPrivate *priv = ido_switch_menu_item_get_instance_private(self); gboolean active = gtk_switch_get_active(GTK_SWITCH(priv->switch_w)); ido_action_helper_activate_with_parameter(helper, g_variant_new_boolean(active)); } GtkMenuItem * ido_switch_menu_item_new_from_menu_model (GMenuItem *menuitem, GActionGroup *actions) { GtkMenuItem *item; gchar *label; GVariant *serialized_icon; gchar *action = NULL; item = g_object_new (IDO_TYPE_SWITCH_MENU_ITEM, NULL); if (g_menu_item_get_attribute (menuitem, "label", "s", &label)) { ido_switch_menu_item_set_label (IDO_SWITCH_MENU_ITEM (item), label); g_free (label); } gchar *sAccelerator; gboolean bAccelerator = g_menu_item_get_attribute (menuitem, "accel", "s", &sAccelerator); if (bAccelerator) { ido_switch_menu_item_set_accelerator (IDO_SWITCH_MENU_ITEM (item), sAccelerator); g_free (sAccelerator); } serialized_icon = g_menu_item_get_attribute_value (menuitem, "icon", NULL); if (serialized_icon) { GIcon *icon; icon = g_icon_deserialize (serialized_icon); if (icon) { ido_switch_menu_item_set_icon (IDO_SWITCH_MENU_ITEM (item), icon); g_object_unref (icon); } g_variant_unref (serialized_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(item, "activate", G_CALLBACK(ido_switch_menu_item_activate), helper); g_signal_connect_swapped (item, "destroy", G_CALLBACK (g_object_unref), helper); g_free (action); } return item; } static void ido_switch_menu_finalize (GObject * item) { /* no-op */ }