diff --git a/ChangeLog b/ChangeLog index 0cc4bcc525..a35b1d441a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Fri Sep 17 14:04:34 2004 Jonathan Blandford + + * panel-applet/NMWirelessApplet.c: Redo the menu item code. + + * panel-applet/menu-item.[ch]: Wireless menu item. + 2004-09-15 John (J5) Palmieri * info-daemon/NetworkManagerInfo.conf diff --git a/panel-applet/Makefile.am b/panel-applet/Makefile.am index 9a38c7da8c..17928ade99 100644 --- a/panel-applet/Makefile.am +++ b/panel-applet/Makefile.am @@ -20,6 +20,12 @@ NMWirelessApplet_SOURCES = \ NMWirelessApplet.h \ NMWirelessAppletDbus.c \ NMWirelessAppletDbus.h \ + menu-info.c \ + menu-info.h \ + gtkcellview.c \ + gtkcellview.h \ + gtkcellrendererprogress.c \ + gtkcellrendererprogress.h \ $(NULL) NMWirelessApplet_LDADD = \ diff --git a/panel-applet/NMWirelessApplet.c b/panel-applet/NMWirelessApplet.c index 8f8348279a..86181b8468 100644 --- a/panel-applet/NMWirelessApplet.c +++ b/panel-applet/NMWirelessApplet.c @@ -45,6 +45,7 @@ #include "config.h" #include "NMWirelessApplet.h" #include "NMWirelessAppletDbus.h" +#include "menu-info.h" #define CFG_UPDATE_INTERVAL 1 #define NM_GCONF_WIRELESS_NETWORKS_PATH "/system/networking/wireless/networks" @@ -565,7 +566,7 @@ static void nmwa_menu_add_text_item (GtkWidget *menu, char *text) * Add a network device to the menu * */ -static void nmwa_menu_add_device_item (GtkWidget *menu, GdkPixbuf *icon, char *name, char *nm_device, gboolean current, gpointer user_data) +static void nmwa_menu_add_device_item (GtkWidget *menu, GdkPixbuf *icon, char *name, char *nm_device, gboolean current, NMWirelessApplet *applet) { GtkWidget *menu_item; GtkWidget *label; @@ -577,99 +578,31 @@ static void nmwa_menu_add_device_item (GtkWidget *menu, GdkPixbuf *icon, char *n g_return_if_fail (name != NULL); g_return_if_fail (nm_device != NULL); - menu_item = gtk_menu_item_new (); - hbox = gtk_hbox_new (FALSE, 5); + menu_item = gtk_check_menu_item_new (); + hbox = gtk_hbox_new (FALSE, 2); gtk_container_add (GTK_CONTAINER (menu_item), hbox); gtk_widget_show (hbox); if ((image = gtk_image_new_from_pixbuf (icon))) { - gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); gtk_widget_show (image); + gtk_size_group_add_widget (applet->image_size_group, image); } label = gtk_label_new (name); if (current) { - char *markup = g_strdup_printf ("%s", name); + char *markup = g_markup_printf_escaped ("%s", name); gtk_label_set_markup (GTK_LABEL (label), markup); g_free (markup); } gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); gtk_widget_show (label); g_object_set_data (G_OBJECT (menu_item), "device", g_strdup (nm_device)); - g_signal_connect(G_OBJECT (menu_item), "activate", G_CALLBACK(nmwa_menu_item_activate), user_data); - - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); - gtk_widget_show (menu_item); -} - - -/* - * nmwa_menu_add_network - * - * Add a wireless network menu item - * - */ -static void nmwa_menu_add_network (GtkWidget *menu, GdkPixbuf *key, NetworkDevice *dev, - WirelessNetwork *net, gpointer user_data) -{ - GtkWidget *menu_item; - GtkWidget *label; - GtkWidget *hbox; - GtkWidget *foo; - GtkWidget *progress; - float percent; - - g_return_if_fail (menu != NULL); - g_return_if_fail (net != NULL); - g_return_if_fail (dev != NULL); - - menu_item = gtk_menu_item_new (); - hbox = gtk_hbox_new (FALSE, 5); - gtk_container_add (GTK_CONTAINER (menu_item), hbox); - gtk_widget_show (hbox); - - /* Add spacing container */ - foo = gtk_hbox_new (FALSE, 5); - gtk_widget_set_size_request (foo, 7, -1); - gtk_box_pack_start (GTK_BOX (hbox), foo, FALSE, FALSE, 2); - gtk_widget_show (foo); - - label = gtk_label_new (net->essid); - if (net->active) - { - char *markup = g_strdup_printf ("%s", net->essid); - gtk_label_set_markup (GTK_LABEL (label), markup); - g_free (markup); - } - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 2); - gtk_widget_show (label); - - progress = gtk_progress_bar_new (); - percent = ((float)net->strength / (float)100); - percent = (percent < 0 ? 0 : (percent > 1.0 ? 1.0 : percent)); - gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress), percent); - gtk_box_pack_start (GTK_BOX (hbox), progress, TRUE, TRUE, 0); - gtk_widget_show (progress); - - if (net->encrypted) - { - GtkWidget *image; - - if ((image = gtk_image_new_from_pixbuf (key))) - { - gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 2); - gtk_widget_show (image); - } - } - - g_object_set_data (G_OBJECT (menu_item), "network", g_strdup (net->essid)); - g_object_set_data (G_OBJECT (menu_item), "nm_device", g_strdup (dev->nm_device)); - g_signal_connect(G_OBJECT (menu_item), "activate", G_CALLBACK(nmwa_menu_item_activate), user_data); + g_signal_connect(G_OBJECT (menu_item), "activate", G_CALLBACK(nmwa_menu_item_activate), applet); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); gtk_widget_show (menu_item); @@ -682,7 +615,8 @@ static void nmwa_menu_add_network (GtkWidget *menu, GdkPixbuf *key, NetworkDevic */ static void nmwa_menu_device_add_networks (GtkWidget *menu, NetworkDevice *dev, NMWirelessApplet *applet) { - GSList *element; + GSList *list; + gboolean has_encrypted = FALSE; g_return_if_fail (menu != NULL); g_return_if_fail (applet != NULL); @@ -691,21 +625,45 @@ static void nmwa_menu_device_add_networks (GtkWidget *menu, NetworkDevice *dev, if (dev->type != DEVICE_TYPE_WIRELESS_ETHERNET) return; - element = dev->networks; - if (!element) - nmwa_menu_add_text_item (menu, _("There are no wireless networks...")); - else + if (dev->networks == NULL) { - /* Add all networks in our network list to the menu */ - while (element) - { - WirelessNetwork *net = (WirelessNetwork *)(element->data); + nmwa_menu_add_text_item (menu, _("There are no wireless networks...")); + return; + } - if (net) - nmwa_menu_add_network (menu, applet->key_pixbuf, dev, net, applet); + /* Check for any security */ + for (list = dev->networks; list; list = list->next) + { + WirelessNetwork *network = list->data; - element = g_slist_next (element); - } + if (FALSE && !has_encrypted)//BADHACKTOTEST + { // REMOVE! + network->encrypted = TRUE; // REMOVE! + network->active = TRUE; // REMOVE! + } // REMOVE! + + if (network->encrypted) + has_encrypted = TRUE; + } + + /* Add all networks in our network list to the menu */ + for (list = dev->networks; list; list = list->next) + { + GtkWidget *menu_item; + WirelessNetwork *net; + + net = (WirelessNetwork *) list->data; + + menu_item = nm_menu_wireless_new (applet->image_size_group, + applet->encryption_size_group); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + nm_menu_wireless_update (NM_MENU_WIRELESS (menu_item), net, has_encrypted); + + g_object_set_data (G_OBJECT (menu_item), "network", g_strdup (net->essid)); + g_object_set_data (G_OBJECT (menu_item), "nm_device", g_strdup (dev->nm_device)); + g_signal_connect(G_OBJECT (menu_item), "activate", G_CALLBACK (nmwa_menu_item_activate), applet); + + gtk_widget_show (menu_item); } } @@ -873,6 +831,8 @@ static void nmwa_setup_widgets (NMWirelessApplet *applet) gtk_menu_item_set_submenu (GTK_MENU_ITEM(applet->toplevel_menu), applet->menu); g_signal_connect (applet->menu, "button_press_event", G_CALLBACK (do_not_eat_button_press), NULL); + applet->image_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + applet->encryption_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); gtk_widget_show (menu_bar); gtk_widget_show (applet->toplevel_menu); gtk_widget_show (applet->menu); @@ -1018,10 +978,33 @@ static gboolean nmwa_fill (NMWirelessApplet *applet) return (TRUE); } +static void +setup_stock (void) +{ + GtkIconFactory *ifactory; + GtkIconSet *iset; + GtkIconSource *isource; + static gboolean initted = FALSE; + + if (initted) + return; + + ifactory = gtk_icon_factory_new (); + iset = gtk_icon_set_new (); + isource = gtk_icon_source_new (); + gtk_icon_source_set_icon_name (isource, "gnome-lockscreen"); + gtk_icon_set_add_source (iset, isource); + gtk_icon_factory_add (ifactory, "gnome-lockscreen", iset); + gtk_icon_factory_add_default (ifactory); + + initted = TRUE; +} + static gboolean nmwa_factory (NMWirelessApplet *applet, const gchar *iid, gpointer data) { gboolean retval = FALSE; + setup_stock (); if (!strcmp (iid, "OAFIID:NMWirelessApplet")) retval = nmwa_fill (applet); diff --git a/panel-applet/NMWirelessApplet.h b/panel-applet/NMWirelessApplet.h index 90887130d5..933c49202c 100644 --- a/panel-applet/NMWirelessApplet.h +++ b/panel-applet/NMWirelessApplet.h @@ -117,13 +117,15 @@ typedef struct GSList *devices; NetworkDevice *active_device; AppletState applet_state; - + /* Direct UI elements */ GtkWidget *pixmap; GtkWidget *box; GtkWidget *about_dialog; GtkWidget *menu; GtkWidget *toplevel_menu; + GtkSizeGroup *image_size_group; + GtkSizeGroup *encryption_size_group; } NMWirelessApplet; diff --git a/panel-applet/gtkcellrendererprogress.c b/panel-applet/gtkcellrendererprogress.c new file mode 100644 index 0000000000..63b54215c6 --- /dev/null +++ b/panel-applet/gtkcellrendererprogress.c @@ -0,0 +1,379 @@ +/* gtkcellrendererprogress.c + * Copyright (C) 2002 Naba Kumar + * heavily modified by Jörgen Scheibengruber + * heavily modified by Marco Pesenti Gritti + * + * This 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. + * + * This 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 this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* + * Modified by the GTK+ Team and others 1997-2004. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include + +#include "gtkcellrendererprogress.h" +#define _(x) (x) +#define P_(x) (x) +#define Q_(x) (x) +#define N_(x) (x) + +#define GTK_CELL_RENDERER_PROGRESS_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \ + GTK_TYPE_CELL_RENDERER_PROGRESS, \ + GtkCellRendererProgressPrivate)) + +enum +{ + PROP_0, + PROP_VALUE, + PROP_TEXT +}; + +struct _GtkCellRendererProgressPrivate +{ + gint value; + gchar *text; + gchar *label; + gint min_h; + gint min_w; +}; + +static void gtk_cell_renderer_progress_finalize (GObject *object); +static void gtk_cell_renderer_progress_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void gtk_cell_renderer_progress_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_cell_renderer_progress_set_value (GtkCellRendererProgress *cellprogress, + gint value); +static void gtk_cell_renderer_progress_set_text (GtkCellRendererProgress *cellprogress, + const gchar *text); +static void compute_dimensions (GtkCellRenderer *cell, + GtkWidget *widget, + const gchar *text, + gint *width, + gint *height); +static void gtk_cell_renderer_progress_get_size (GtkCellRenderer *cell, + GtkWidget *widget, + GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, + gint *width, + gint *height); +static void gtk_cell_renderer_progress_render (GtkCellRenderer *cell, + GdkWindow *window, + GtkWidget *widget, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GdkRectangle *expose_area, + guint flags); + + +G_DEFINE_TYPE (GtkCellRendererProgress, gtk_cell_renderer_progress, GTK_TYPE_CELL_RENDERER); + +static void +gtk_cell_renderer_progress_class_init (GtkCellRendererProgressClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass); + + object_class->finalize = gtk_cell_renderer_progress_finalize; + object_class->get_property = gtk_cell_renderer_progress_get_property; + object_class->set_property = gtk_cell_renderer_progress_set_property; + + cell_class->get_size = gtk_cell_renderer_progress_get_size; + cell_class->render = gtk_cell_renderer_progress_render; + + /** + * GtkCellRendererProgress:value: + * + * The "value" property determines the percentage to which the + * progress bar will be "filled in". + * + * Since: 2.6 + **/ + g_object_class_install_property (object_class, + PROP_VALUE, + g_param_spec_int ("value", + P_("Value"), + P_("Value of the progress bar"), + 0, 100, 0, + G_PARAM_READWRITE)); + + /** + * GtkCellRendererProgress:text: + * + * The "text" property determines the label which will be drawn + * over the progress bar. Setting this property to %NULL causes the default + * label to be displayed. Setting this property to an empty string causes + * no label to be displayed. + * + * Since: 2.6 + **/ + g_object_class_install_property (object_class, + PROP_TEXT, + g_param_spec_string ("text", + P_("Text"), + P_("Text on the progress bar"), + NULL, + G_PARAM_READWRITE)); + + g_type_class_add_private (object_class, + sizeof (GtkCellRendererProgressPrivate)); +} + +static void +gtk_cell_renderer_progress_init (GtkCellRendererProgress *cellprogress) +{ + cellprogress->priv = GTK_CELL_RENDERER_PROGRESS_GET_PRIVATE (cellprogress); + cellprogress->priv->value = 0; + cellprogress->priv->text = NULL; + cellprogress->priv->label = NULL; + cellprogress->priv->min_w = -1; + cellprogress->priv->min_h = -1; +} + + +/** + * gtk_cell_renderer_progress_new: + * + * Creates a new #GtkCellRendererProgress. + * + * Return value: the new cell renderer + * + * Since: 2.6 + **/ +GtkCellRenderer* +gtk_cell_renderer_progress_new (void) +{ + return GTK_CELL_RENDERER (g_object_new (GTK_TYPE_CELL_RENDERER_PROGRESS, NULL)); +} + +static void +gtk_cell_renderer_progress_finalize (GObject *object) +{ + GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object); + + g_free (cellprogress->priv->text); + g_free (cellprogress->priv->label); + + G_OBJECT_CLASS (gtk_cell_renderer_progress_parent_class)->finalize (object); +} + +static void +gtk_cell_renderer_progress_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object); + + switch (param_id) + { + case PROP_VALUE: + g_value_set_int (value, cellprogress->priv->value); + break; + case PROP_TEXT: + g_value_set_string (value, cellprogress->priv->text); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + } +} + +static void +gtk_cell_renderer_progress_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object); + + switch (param_id) + { + case PROP_VALUE: + gtk_cell_renderer_progress_set_value (cellprogress, + g_value_get_int (value)); + break; + case PROP_TEXT: + gtk_cell_renderer_progress_set_text (cellprogress, + g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + } +} + +static void +gtk_cell_renderer_progress_set_value (GtkCellRendererProgress *cellprogress, + gint value) +{ + gchar *text; + + cellprogress->priv->value = value; + + if (cellprogress->priv->text) + text = g_strdup (cellprogress->priv->text); + else + text = g_strdup_printf (Q_("progress bar label|%d %%"), + cellprogress->priv->value); + + g_free (cellprogress->priv->label); + cellprogress->priv->label = text; +} + +static void +gtk_cell_renderer_progress_set_text (GtkCellRendererProgress *cellprogress, + const gchar *text) +{ + gchar *new_text; + + new_text = g_strdup (text); + g_free (cellprogress->priv->text); + cellprogress->priv->text = new_text; + + /* Update the label */ + gtk_cell_renderer_progress_set_value (cellprogress, cellprogress->priv->value); +} + +static void +compute_dimensions (GtkCellRenderer *cell, + GtkWidget *widget, + const gchar *text, + gint *width, + gint *height) +{ + PangoRectangle logical_rect; + PangoLayout *layout; + + layout = gtk_widget_create_pango_layout (widget, text); + pango_layout_get_pixel_extents (layout, NULL, &logical_rect); + + if (width) + *width = logical_rect.width + cell->xpad * 2 + widget->style->xthickness * 2; + + if (height) + *height = logical_rect.height + cell->ypad * 2 + widget->style->ythickness * 2; + + g_object_unref (G_OBJECT (layout)); +} + +static void +gtk_cell_renderer_progress_get_size (GtkCellRenderer *cell, + GtkWidget *widget, + GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, + gint *width, + gint *height) +{ + GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (cell); + gint w, h; + gchar *text; + + if (cellprogress->priv->min_w < 0) + { + text = g_strdup_printf (Q_("progress bar label|%d %%"), 100); + compute_dimensions (cell, widget, text, + &cellprogress->priv->min_w, + &cellprogress->priv->min_h); + g_free (text); + } + + compute_dimensions (cell, widget, cellprogress->priv->label, &w, &h); + + if (width) + *width = MAX (cellprogress->priv->min_w, w); + + if (height) + *height = MIN (cellprogress->priv->min_h, h); +} + +static void +gtk_cell_renderer_progress_render (GtkCellRenderer *cell, + GdkWindow *window, + GtkWidget *widget, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GdkRectangle *expose_area, + guint flags) +{ + GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (cell); + GdkGC *gc; + PangoLayout *layout; + PangoRectangle logical_rect; + gint x, y, w, h, perc_w, pos; + GdkRectangle clip; + gboolean is_rtl; + + is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL; + + gc = gdk_gc_new (window); + + x = cell_area->x + cell->xpad; + y = cell_area->y + cell->ypad; + + w = cell_area->width - cell->xpad * 2; + h = cell_area->height - cell->ypad * 2; + + gdk_gc_set_rgb_fg_color (gc, &widget->style->fg[GTK_STATE_NORMAL]); + gdk_draw_rectangle (window, gc, TRUE, x, y, w, h); + + x += widget->style->xthickness; + y += widget->style->ythickness; + w -= widget->style->xthickness * 2; + h -= widget->style->ythickness * 2; + gdk_gc_set_rgb_fg_color (gc, &widget->style->bg[GTK_STATE_NORMAL]); + gdk_draw_rectangle (window, gc, TRUE, x, y, w, h); + + gdk_gc_set_rgb_fg_color (gc, &widget->style->bg[GTK_STATE_SELECTED]); + perc_w = w * MAX (0, cellprogress->priv->value) / 100; + gdk_draw_rectangle (window, gc, TRUE, is_rtl ? (x + w - perc_w) : x, y, perc_w, h); + + layout = gtk_widget_create_pango_layout (widget, cellprogress->priv->label); + pango_layout_get_pixel_extents (layout, NULL, &logical_rect); + + pos = (w - logical_rect.width)/2; + + clip.x = x; + clip.y = y; + clip.width = is_rtl ? w - perc_w : perc_w; + clip.height = h; + + gtk_paint_layout (widget->style, window, + is_rtl ? GTK_STATE_NORMAL : GTK_STATE_SELECTED, + FALSE, &clip, widget, "progressbar", + x + pos, y + (h - logical_rect.height)/2, + layout); + + clip.x = clip.x + clip.width; + clip.width = w - clip.width; + + gtk_paint_layout (widget->style, window, + is_rtl ? GTK_STATE_SELECTED : GTK_STATE_NORMAL, + FALSE, &clip, widget, "progressbar", + x + pos, y + (h - logical_rect.height)/2, + layout); + + g_object_unref (G_OBJECT (layout)); + g_object_unref (G_OBJECT (gc)); +} + diff --git a/panel-applet/gtkcellrendererprogress.h b/panel-applet/gtkcellrendererprogress.h new file mode 100644 index 0000000000..dddc71ea80 --- /dev/null +++ b/panel-applet/gtkcellrendererprogress.h @@ -0,0 +1,69 @@ +/* gtkcellrendererprogress.h + * Copyright (C) 2002 Naba Kumar + * modified by Jörgen Scheibengruber + * + * This 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. + * + * This 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 this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* + * Modified by the GTK+ Team and others 1997-2004. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GTK_CELL_RENDERER_PROGRESS_H__ +#define __GTK_CELL_RENDERER_PROGRESS_H__ + +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_CELL_RENDERER_PROGRESS (gtk_cell_renderer_progress_get_type ()) +#define GTK_CELL_RENDERER_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_RENDERER_PROGRESS, GtkCellRendererProgress)) +#define GTK_CELL_RENDERER_PROGRESS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_CELL_RENDERER_PROGRESS, GtkCellRendererProgressClass)) +#define GTK_IS_CELL_RENDERER_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_RENDERER_PROGRESS)) +#define GTK_IS_CELL_RENDERER_PROGRESS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CELL_RENDERER_PROGRESS)) +#define GTK_CELL_RENDERER_PROGRESS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CELL_RENDERER_PROGRESS, GtkCellRendererProgressClass)) + +typedef struct _GtkCellRendererProgress GtkCellRendererProgress; +typedef struct _GtkCellRendererProgressClass GtkCellRendererProgressClass; +typedef struct _GtkCellRendererProgressPrivate GtkCellRendererProgressPrivate; + +struct _GtkCellRendererProgress +{ + GtkCellRenderer parent_instance; + + /*< private >*/ + GtkCellRendererProgressPrivate *priv; +}; + +struct _GtkCellRendererProgressClass +{ + GtkCellRendererClass parent_class; + + /* Padding for future expansion */ + void (*_gtk_reserved1) (void); + void (*_gtk_reserved2) (void); + void (*_gtk_reserved3) (void); + void (*_gtk_reserved4) (void); +}; + +GType gtk_cell_renderer_progress_get_type (void); +GtkCellRenderer* gtk_cell_renderer_progress_new (void); + +G_END_DECLS + +#endif /* __GTK_CELL_RENDERER_PROGRESS_H__ */ diff --git a/panel-applet/gtkcellview.c b/panel-applet/gtkcellview.c new file mode 100644 index 0000000000..91d0b4354d --- /dev/null +++ b/panel-applet/gtkcellview.c @@ -0,0 +1,1009 @@ +/* gtkellview.c + * Copyright (C) 2002, 2003 Kristian Rietveld + * + * This 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. + * + * This 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 this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gtkcellview.h" +#include +#include +#include +#include +#include +#define _(x) (x) +#define P_(x) (x) +#define Q_(x) (x) +#define N_(x) (x) + +typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo; +struct _GtkCellViewCellInfo +{ + GtkCellRenderer *cell; + + gint requested_width; + gint real_width; + guint expand : 1; + guint pack : 1; + + GSList *attributes; + + GtkCellLayoutDataFunc func; + gpointer func_data; + GDestroyNotify destroy; +}; + +struct _GtkCellViewPrivate +{ + GtkTreeModel *model; + GtkTreeRowReference *displayed_row; + GList *cell_list; + gint spacing; + + GdkColor background; + gboolean background_set; +}; + + +static void gtk_cell_view_class_init (GtkCellViewClass *klass); +static void gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface); +static void gtk_cell_view_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void gtk_cell_view_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_cell_view_init (GtkCellView *cellview); +static void gtk_cell_view_finalize (GObject *object); +static void gtk_cell_view_style_set (GtkWidget *widget, + GtkStyle *previous_style); +static void gtk_cell_view_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_cell_view_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gboolean gtk_cell_view_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_cell_view_set_valuesv (GtkCellView *cellview, + GtkCellRenderer *renderer, + va_list args); +static GtkCellViewCellInfo *gtk_cell_view_get_cell_info (GtkCellView *cellview, + GtkCellRenderer *renderer); + + +static void gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout, + GtkCellRenderer *renderer, + gboolean expand); +static void gtk_cell_view_cell_layout_pack_end (GtkCellLayout *layout, + GtkCellRenderer *renderer, + gboolean expand); +static void gtk_cell_view_cell_layout_add_attribute (GtkCellLayout *layout, + GtkCellRenderer *renderer, + const gchar *attribute, + gint column); +static void gtk_cell_view_cell_layout_clear (GtkCellLayout *layout); +static void gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout *layout, + GtkCellRenderer *renderer); +static void gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout *layout, + GtkCellRenderer *cell, + GtkCellLayoutDataFunc func, + gpointer func_data, + GDestroyNotify destroy); +static void gtk_cell_view_cell_layout_reorder (GtkCellLayout *layout, + GtkCellRenderer *cell, + gint position); + + +#define GTK_CELL_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_VIEW, GtkCellViewPrivate)) + +enum +{ + PROP_0, + PROP_BACKGROUND, + PROP_BACKGROUND_GDK, + PROP_BACKGROUND_SET +}; + +static GtkObjectClass *parent_class = NULL; + + +GType +gtk_cell_view_get_type (void) +{ + static GType cell_view_type = 0; + + if (!cell_view_type) + { + static const GTypeInfo cell_view_info = + { + sizeof (GtkCellViewClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gtk_cell_view_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkCellView), + 0, + (GInstanceInitFunc) gtk_cell_view_init + }; + + static const GInterfaceInfo cell_layout_info = + { + (GInterfaceInitFunc) gtk_cell_view_cell_layout_init, + NULL, + NULL + }; + + cell_view_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkCellView", + &cell_view_info, 0); + + g_type_add_interface_static (cell_view_type, GTK_TYPE_CELL_LAYOUT, + &cell_layout_info); + } + + return cell_view_type; +} + +static void +gtk_cell_view_class_init (GtkCellViewClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->get_property = gtk_cell_view_get_property; + gobject_class->set_property = gtk_cell_view_set_property; + gobject_class->finalize = gtk_cell_view_finalize; + + widget_class->expose_event = gtk_cell_view_expose; + widget_class->size_allocate = gtk_cell_view_size_allocate; + widget_class->size_request = gtk_cell_view_size_request; + widget_class->style_set = gtk_cell_view_style_set; + + /* properties */ + g_object_class_install_property (gobject_class, + PROP_BACKGROUND, + g_param_spec_string ("background", + P_("Background color name"), + P_("Background color as a string"), + NULL, + G_PARAM_WRITABLE)); + g_object_class_install_property (gobject_class, + PROP_BACKGROUND_GDK, + g_param_spec_boxed ("background_gdk", + P_("Background color"), + P_("Background color as a GdkColor"), + GDK_TYPE_COLOR, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + +#define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE)) + + ADD_SET_PROP ("background_set", PROP_BACKGROUND_SET, + P_("Background set"), + P_("Whether this tag affects the background color")); + + g_type_class_add_private (gobject_class, sizeof (GtkCellViewPrivate)); +} + +static void +gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface) +{ + iface->pack_start = gtk_cell_view_cell_layout_pack_start; + iface->pack_end = gtk_cell_view_cell_layout_pack_end; + iface->clear = gtk_cell_view_cell_layout_clear; + iface->add_attribute = gtk_cell_view_cell_layout_add_attribute; + iface->set_cell_data_func = gtk_cell_view_cell_layout_set_cell_data_func; + iface->clear_attributes = gtk_cell_view_cell_layout_clear_attributes; + iface->reorder = gtk_cell_view_cell_layout_reorder; +} + +static void +gtk_cell_view_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GtkCellView *view = GTK_CELL_VIEW (object); + + switch (param_id) + { + case PROP_BACKGROUND_GDK: + { + GdkColor color; + + color = view->priv->background; + + g_value_set_boxed (value, &color); + } + break; + case PROP_BACKGROUND_SET: + g_value_set_boolean (value, view->priv->background_set); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gtk_cell_view_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkCellView *view = GTK_CELL_VIEW (object); + + switch (param_id) + { + case PROP_BACKGROUND: + { + GdkColor color; + + if (!g_value_get_string (value)) + gtk_cell_view_set_background_color (view, NULL); + else if (gdk_color_parse (g_value_get_string (value), &color)) + gtk_cell_view_set_background_color (view, &color); + else + g_warning ("Don't know color `%s'", g_value_get_string (value)); + + g_object_notify (object, "background_gdk"); + } + break; + case PROP_BACKGROUND_GDK: + gtk_cell_view_set_background_color (view, g_value_get_boxed (value)); + break; + case PROP_BACKGROUND_SET: + view->priv->background_set = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gtk_cell_view_init (GtkCellView *cellview) +{ + GTK_WIDGET_SET_FLAGS (cellview, GTK_NO_WINDOW); + + cellview->priv = GTK_CELL_VIEW_GET_PRIVATE (cellview); +} + +static void +gtk_cell_view_style_set (GtkWidget *widget, + GtkStyle *previous_style) +{ + if (previous_style && GTK_WIDGET_REALIZED (widget)) + gdk_window_set_background (widget->window, + &widget->style->base[GTK_WIDGET_STATE (widget)]); +} + +static void +gtk_cell_view_finalize (GObject *object) +{ + GtkCellView *cellview = GTK_CELL_VIEW (object); + + gtk_cell_view_cell_layout_clear (GTK_CELL_LAYOUT (cellview)); + + if (cellview->priv->model) + g_object_unref (cellview->priv->model); + + if (cellview->priv->displayed_row) + gtk_tree_row_reference_free (cellview->priv->displayed_row); + + (* G_OBJECT_CLASS (parent_class)->finalize) (object); +} + +static void +gtk_cell_view_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GList *i; + gboolean first_cell = TRUE; + GtkCellView *cellview; + + cellview = GTK_CELL_VIEW (widget); + + requisition->width = 0; + requisition->height = 0; + + if (cellview->priv->displayed_row) + gtk_cell_view_set_cell_data (cellview); + + for (i = cellview->priv->cell_list; i; i = i->next) + { + gint width, height; + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; + + if (!info->cell->visible) + continue; + + if (!first_cell) + requisition->width += cellview->priv->spacing; + + gtk_cell_renderer_get_size (info->cell, widget, NULL, NULL, NULL, + &width, &height); + + info->requested_width = width; + requisition->width += width; + requisition->height = MAX (requisition->height, height); + + first_cell = FALSE; + } +} + +static void +gtk_cell_view_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GList *i; + gint expand_cell_count = 0; + gint full_requested_width = 0; + gint extra_space; + GtkCellView *cellview; + + widget->allocation = *allocation; + + cellview = GTK_CELL_VIEW (widget); + + /* checking how much extra space we have */ + for (i = cellview->priv->cell_list; i; i = i->next) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; + + if (!info->cell->visible) + continue; + + if (info->expand) + expand_cell_count++; + + full_requested_width += info->requested_width; + } + + extra_space = widget->allocation.width - full_requested_width; + if (extra_space < 0) + extra_space = 0; + else if (extra_space > 0 && expand_cell_count > 0) + extra_space /= expand_cell_count; + + /* iterate list for PACK_START cells */ + for (i = cellview->priv->cell_list; i; i = i->next) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; + + if (info->pack == GTK_PACK_END) + continue; + + if (!info->cell->visible) + continue; + + info->real_width = info->requested_width + (info->expand?extra_space:0); + } + + /* iterate list for PACK_END cells */ + for (i = cellview->priv->cell_list; i; i = i->next) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; + + if (info->pack == GTK_PACK_START) + continue; + + if (!info->cell->visible) + continue; + + info->real_width = info->requested_width + (info->expand?extra_space:0); + } +} + +static gboolean +gtk_cell_view_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GList *i; + GtkCellView *cellview; + GdkRectangle area; + GtkCellRendererState state; + gboolean rtl = (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL); + + cellview = GTK_CELL_VIEW (widget); + + if (! GTK_WIDGET_DRAWABLE (widget)) + return FALSE; + + /* "blank" background */ + if (cellview->priv->background_set) + { + GdkGC *gc; + + gc = gdk_gc_new (GTK_WIDGET (cellview)->window); + gdk_gc_set_rgb_fg_color (gc, &cellview->priv->background); + + gdk_draw_rectangle (GTK_WIDGET (cellview)->window, + gc, + TRUE, + + /*0, 0,*/ + widget->allocation.x, + widget->allocation.y, + + widget->allocation.width, + widget->allocation.height); + + g_object_unref (G_OBJECT (gc)); + } + + /* set cell data (if available) */ + if (cellview->priv->displayed_row) + gtk_cell_view_set_cell_data (cellview); + else if (cellview->priv->model) + return FALSE; + + /* render cells */ + area = widget->allocation; + + /* we draw on our very own window, initialize x and y to zero */ + area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0); + area.y = widget->allocation.y; + + if (GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) + state = GTK_CELL_RENDERER_PRELIT; + else + state = 0; + + /* PACK_START */ + for (i = cellview->priv->cell_list; i; i = i->next) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; + + if (info->pack == GTK_PACK_END) + continue; + + if (!info->cell->visible) + continue; + + area.width = info->real_width; + if (rtl) + area.x -= area.width; + + gtk_cell_renderer_render (info->cell, + event->window, + widget, + /* FIXME! */ + &area, &area, &event->area, state); + + if (!rtl) + area.x += info->real_width; + } + + area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width); + + /* PACK_END */ + for (i = cellview->priv->cell_list; i; i = i->next) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; + + if (info->pack == GTK_PACK_START) + continue; + + if (!info->cell->visible) + continue; + + area.width = info->real_width; + if (!rtl) + area.x -= area.width; + + gtk_cell_renderer_render (info->cell, + widget->window, + widget, + /* FIXME ! */ + &area, &area, &event->area, state); + if (rtl) + area.x += info->real_width; + } + + return FALSE; +} + +static GtkCellViewCellInfo * +gtk_cell_view_get_cell_info (GtkCellView *cellview, + GtkCellRenderer *renderer) +{ + GList *i; + + for (i = cellview->priv->cell_list; i; i = i->next) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; + + if (info->cell == renderer) + return info; + } + + return NULL; +} + +void +gtk_cell_view_set_cell_data (GtkCellView *cellview) +{ + GList *i; + GtkTreeIter iter; + GtkTreePath *path; + + g_return_if_fail (cellview->priv->displayed_row != NULL); + + path = gtk_tree_row_reference_get_path (cellview->priv->displayed_row); + if (!path) + return; + + gtk_tree_model_get_iter (cellview->priv->model, &iter, path); + gtk_tree_path_free (path); + + for (i = cellview->priv->cell_list; i; i = i->next) + { + GSList *j; + GtkCellViewCellInfo *info = i->data; + + g_object_freeze_notify (G_OBJECT (info->cell)); + + for (j = info->attributes; j && j->next; j = j->next->next) + { + gchar *property = j->data; + gint column = GPOINTER_TO_INT (j->next->data); + GValue value = {0, }; + + gtk_tree_model_get_value (cellview->priv->model, &iter, + column, &value); + g_object_set_property (G_OBJECT (info->cell), + property, &value); + g_value_unset (&value); + } + + if (info->func) + (* info->func) (GTK_CELL_LAYOUT (cellview), + info->cell, + cellview->priv->model, + &iter, + info->func_data); + + g_object_thaw_notify (G_OBJECT (info->cell)); + } +} + +/* GtkCellLayout implementation */ +static void +gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout, + GtkCellRenderer *renderer, + gboolean expand) +{ + GtkCellViewCellInfo *info; + GtkCellView *cellview = GTK_CELL_VIEW (layout); + + g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer)); + + g_object_ref (G_OBJECT (renderer)); + gtk_object_sink (GTK_OBJECT (renderer)); + + info = g_new0 (GtkCellViewCellInfo, 1); + info->cell = renderer; + info->expand = expand ? TRUE : FALSE; + info->pack = GTK_PACK_START; + + cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info); +} + +static void +gtk_cell_view_cell_layout_pack_end (GtkCellLayout *layout, + GtkCellRenderer *renderer, + gboolean expand) +{ + GtkCellViewCellInfo *info; + GtkCellView *cellview = GTK_CELL_VIEW (layout); + + g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer)); + + g_object_ref (G_OBJECT (renderer)); + gtk_object_sink (GTK_OBJECT (renderer)); + + info = g_new0 (GtkCellViewCellInfo, 1); + info->cell = renderer; + info->expand = expand ? TRUE : FALSE; + info->pack = GTK_PACK_END; + + cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info); +} + +static void +gtk_cell_view_cell_layout_add_attribute (GtkCellLayout *layout, + GtkCellRenderer *renderer, + const gchar *attribute, + gint column) +{ + GtkCellViewCellInfo *info; + GtkCellView *cellview = GTK_CELL_VIEW (layout); + + g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); + info = gtk_cell_view_get_cell_info (cellview, renderer); + g_return_if_fail (info != NULL); + + info->attributes = g_slist_prepend (info->attributes, + GINT_TO_POINTER (column)); + info->attributes = g_slist_prepend (info->attributes, + g_strdup (attribute)); +} + +static void +gtk_cell_view_cell_layout_clear (GtkCellLayout *layout) +{ + GtkCellView *cellview = GTK_CELL_VIEW (layout); + + g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); + + while (cellview->priv->cell_list) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)cellview->priv->cell_list->data; + + gtk_cell_view_cell_layout_clear_attributes (layout, info->cell); + g_object_unref (G_OBJECT (info->cell)); + g_free (info); + cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list, + cellview->priv->cell_list); + } +} + +static void +gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout *layout, + GtkCellRenderer *cell, + GtkCellLayoutDataFunc func, + gpointer func_data, + GDestroyNotify destroy) +{ + GtkCellView *cellview = GTK_CELL_VIEW (layout); + GtkCellViewCellInfo *info; + + g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); + + info = gtk_cell_view_get_cell_info (cellview, cell); + g_return_if_fail (info != NULL); + + if (info->destroy) + { + GDestroyNotify d = info->destroy; + + info->destroy = NULL; + d (info->func_data); + } + + info->func = func; + info->func_data = func_data; + info->destroy = destroy; +} + +static void +gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout *layout, + GtkCellRenderer *renderer) +{ + GtkCellViewCellInfo *info; + GtkCellView *cellview = GTK_CELL_VIEW (layout); + GSList *list; + + g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + + info = gtk_cell_view_get_cell_info (cellview, renderer); + g_return_if_fail (info != NULL); + + list = info->attributes; + while (list && list->next) + { + g_free (list->data); + list = list->next->next; + } + + g_slist_free (info->attributes); + info->attributes = NULL; +} + +static void +gtk_cell_view_cell_layout_reorder (GtkCellLayout *layout, + GtkCellRenderer *cell, + gint position) +{ + GList *link; + GtkCellViewCellInfo *info; + GtkCellView *cellview = GTK_CELL_VIEW (layout); + + g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); + g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); + + info = gtk_cell_view_get_cell_info (cellview, cell); + + g_return_if_fail (info != NULL); + g_return_if_fail (position >= 0); + + link = g_list_find (cellview->priv->cell_list, info); + + g_return_if_fail (link != NULL); + + cellview->priv->cell_list = g_list_remove_link (cellview->priv->cell_list, + link); + cellview->priv->cell_list = g_list_insert (cellview->priv->cell_list, + info, position); + + gtk_widget_queue_draw (GTK_WIDGET (cellview)); +} + +/* public API */ +GtkWidget * +gtk_cell_view_new (void) +{ + GtkCellView *cellview; + + cellview = GTK_CELL_VIEW (g_object_new (gtk_cell_view_get_type (), NULL)); + + return GTK_WIDGET (cellview); +} + +GtkWidget * +gtk_cell_view_new_with_text (const gchar *text) +{ + GtkCellView *cellview; + GtkCellRenderer *renderer; + GValue value = {0, }; + + cellview = GTK_CELL_VIEW (gtk_cell_view_new ()); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview), + renderer, TRUE); + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, text); + gtk_cell_view_set_values (cellview, renderer, "text", &value, NULL); + g_value_unset (&value); + + return GTK_WIDGET (cellview); +} + +GtkWidget * +gtk_cell_view_new_with_markup (const gchar *markup) +{ + GtkCellView *cellview; + GtkCellRenderer *renderer; + GValue value = {0, }; + + cellview = GTK_CELL_VIEW (gtk_cell_view_new ()); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview), + renderer, TRUE); + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, markup); + gtk_cell_view_set_values (cellview, renderer, "markup", &value, NULL); + g_value_unset (&value); + + return GTK_WIDGET (cellview); +} + +GtkWidget * +gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf) +{ + GtkCellView *cellview; + GtkCellRenderer *renderer; + GValue value = {0, }; + + cellview = GTK_CELL_VIEW (gtk_cell_view_new ()); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview), + renderer, TRUE); + + g_value_init (&value, GDK_TYPE_PIXBUF); + g_value_set_object (&value, pixbuf); + gtk_cell_view_set_values (cellview, renderer, "pixbuf", &value, NULL); + g_value_unset (&value); + + return GTK_WIDGET (cellview); +} + +void +gtk_cell_view_set_value (GtkCellView *cell_view, + GtkCellRenderer *renderer, + gchar *property, + GValue *value) +{ + g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + + g_object_set_property (G_OBJECT (renderer), property, value); + + /* force resize and redraw */ + gtk_widget_queue_resize (GTK_WIDGET (cell_view)); + gtk_widget_queue_draw (GTK_WIDGET (cell_view)); +} + +static void +gtk_cell_view_set_valuesv (GtkCellView *cell_view, + GtkCellRenderer *renderer, + va_list args) +{ + gchar *attribute; + GValue *value; + + attribute = va_arg (args, gchar *); + + while (attribute) + { + value = va_arg (args, GValue *); + gtk_cell_view_set_value (cell_view, renderer, attribute, value); + attribute = va_arg (args, gchar *); + } +} + +void +gtk_cell_view_set_values (GtkCellView *cell_view, + GtkCellRenderer *renderer, + ...) +{ + va_list args; + + g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + g_return_if_fail (gtk_cell_view_get_cell_info (cell_view, renderer)); + + va_start (args, renderer); + gtk_cell_view_set_valuesv (cell_view, renderer, args); + va_end (args); +} + +void +gtk_cell_view_set_model (GtkCellView *cell_view, + GtkTreeModel *model) +{ + g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); + g_return_if_fail (GTK_IS_TREE_MODEL (model)); + + if (cell_view->priv->model) + { + if (cell_view->priv->displayed_row) + gtk_tree_row_reference_free (cell_view->priv->displayed_row); + cell_view->priv->displayed_row = NULL; + + g_object_unref (G_OBJECT (cell_view->priv->model)); + cell_view->priv->model = NULL; + } + + cell_view->priv->model = model; + + if (cell_view->priv->model) + g_object_ref (G_OBJECT (cell_view->priv->model)); +} + +/** + * gtk_cell_view_set_displayed_row: + * @cell_view: a #GtkCellView + * @path: a #GtkTreePath or %NULL to unset. + * + * Sets the row of the model that is currently displayed + * by the #GtkCellView. If the path is unset, then the + * contents of the cellview "stick" at their last value; + * this is not normally a desired result, but may be + * a needed intermediate state if say, the model for + * the #GtkCellView becomes temporarily empty. + **/ +void +gtk_cell_view_set_displayed_row (GtkCellView *cell_view, + GtkTreePath *path) +{ + g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); + g_return_if_fail (GTK_IS_TREE_MODEL (cell_view->priv->model)); + + if (cell_view->priv->displayed_row) + gtk_tree_row_reference_free (cell_view->priv->displayed_row); + + if (path) + { + cell_view->priv->displayed_row = + gtk_tree_row_reference_new (cell_view->priv->model, path); + } + else + cell_view->priv->displayed_row = NULL; + + /* force resize and redraw */ + gtk_widget_queue_resize (GTK_WIDGET (cell_view)); + gtk_widget_queue_draw (GTK_WIDGET (cell_view)); +} + +GtkTreePath * +gtk_cell_view_get_displayed_row (GtkCellView *cell_view) +{ + g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL); + + if (!cell_view->priv->displayed_row) + return NULL; + + return gtk_tree_row_reference_get_path (cell_view->priv->displayed_row); +} + +gboolean +gtk_cell_view_get_size_of_row (GtkCellView *cell_view, + GtkTreePath *path, + GtkRequisition *requisition) +{ + GtkTreeRowReference *tmp; + + g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), FALSE); + g_return_val_if_fail (path != NULL, FALSE); + g_return_val_if_fail (requisition != NULL, FALSE); + + tmp = cell_view->priv->displayed_row; + cell_view->priv->displayed_row = + gtk_tree_row_reference_new (cell_view->priv->model, path); + + gtk_cell_view_size_request (GTK_WIDGET (cell_view), requisition); + + gtk_tree_row_reference_free (cell_view->priv->displayed_row); + cell_view->priv->displayed_row = tmp; + + return TRUE; +} + +void +gtk_cell_view_set_background_color (GtkCellView *view, + const GdkColor *color) +{ + g_return_if_fail (GTK_IS_CELL_VIEW (view)); + + if (color) + { + if (!view->priv->background_set) + { + view->priv->background_set = TRUE; + g_object_notify (G_OBJECT (view), "background_set"); + } + + view->priv->background = *color; + } + else + { + if (view->priv->background_set) + { + view->priv->background_set = FALSE; + g_object_notify (G_OBJECT (view), "background_set"); + } + } +} + +GList * +gtk_cell_view_get_cell_renderers (GtkCellView *cell_view) +{ + GList *retval = NULL, *list; + + g_return_val_if_fail (cell_view != NULL, NULL); + + for (list = cell_view->priv->cell_list; list; list = list->next) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data; + + retval = g_list_prepend (retval, info->cell); + } + + return g_list_reverse (retval); +} diff --git a/panel-applet/gtkcellview.h b/panel-applet/gtkcellview.h new file mode 100644 index 0000000000..844d505f80 --- /dev/null +++ b/panel-applet/gtkcellview.h @@ -0,0 +1,84 @@ +/* gtkcellview.h + * Copyright (C) 2002, 2003 Kristian Rietveld + * + * This 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. + * + * This 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 this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_CELL_VIEW_H__ +#define __GTK_CELL_VIEW_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_CELL_VIEW (gtk_cell_view_get_type ()) +#define GTK_CELL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_VIEW, GtkCellView)) +#define GTK_CELL_VIEW_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), GTK_TYPE_CELL_VIEW, GtkCellViewClass)) +#define GTK_IS_CELL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_VIEW)) +#define GTK_IS_CELL_VIEW_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), GTK_TYPE_CELL_VIEW)) +#define GTK_CELL_VIEW_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), GTK_TYPE_CELL_VIEW, GtkCellViewClass)) + +typedef struct _GtkCellView GtkCellView; +typedef struct _GtkCellViewClass GtkCellViewClass; +typedef struct _GtkCellViewPrivate GtkCellViewPrivate; + +struct _GtkCellView +{ + GtkWidget parent_instance; + + /*< private >*/ + GtkCellViewPrivate *priv; +}; + +struct _GtkCellViewClass +{ + GtkWidgetClass parent_class; +}; + +GType gtk_cell_view_get_type (void); +GtkWidget *gtk_cell_view_new (void); +GtkWidget *gtk_cell_view_new_with_text (const gchar *text); +GtkWidget *gtk_cell_view_new_with_markup (const gchar *markup); +GtkWidget *gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf); + + +void gtk_cell_view_set_value (GtkCellView *cell_view, + GtkCellRenderer *renderer, + gchar *property, + GValue *value); +void gtk_cell_view_set_values (GtkCellView *cell_view, + GtkCellRenderer *renderer, + ...); + +void gtk_cell_view_set_model (GtkCellView *cell_view, + GtkTreeModel *model); +void gtk_cell_view_set_displayed_row (GtkCellView *cell_view, + GtkTreePath *path); +GtkTreePath *gtk_cell_view_get_displayed_row (GtkCellView *cell_view); +gboolean gtk_cell_view_get_size_of_row (GtkCellView *cell_view, + GtkTreePath *path, + GtkRequisition *requisition); + +void gtk_cell_view_set_background_color (GtkCellView *cell_view, + const GdkColor *color); +void gtk_cell_view_set_cell_data (GtkCellView *cellview); +GList *gtk_cell_view_get_cell_renderers (GtkCellView *cellview); + +G_END_DECLS + +#endif /* __GTK_CELL_VIEW_H__ */ diff --git a/panel-applet/menu-info.c b/panel-applet/menu-info.c new file mode 100644 index 0000000000..7b9527eaa3 --- /dev/null +++ b/panel-applet/menu-info.c @@ -0,0 +1,171 @@ +/* menu-info.c - Class to represent the + * + * Jonathan Blandford + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * This also uses code from eel-vfs-extentions available under the LGPL: + * Authors: Darin Adler + * Pavel Cisler + * Mike Fleming + * John Sullivan + * + * (C) Copyright 2004 Red Hat, Inc. + * Copyright (C) 1999, 2000 Eazel, Inc. + */ +#include "menu-info.h" +#include "gtkcellview.h" +#include "gtkcellrendererprogress.h" + +G_DEFINE_TYPE (NMMenuWireless, nm_menu_wireless, GTK_TYPE_CHECK_MENU_ITEM); + +static void +nm_menu_wireless_init (NMMenuWireless *menu_info) +{ + GtkWidget *hbox; + + gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (menu_info), TRUE); + hbox = gtk_hbox_new (FALSE, 2); + menu_info->spacer = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (menu_info->spacer), GTK_SHADOW_NONE); + menu_info->label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (menu_info->label), 0.0, 0.5); + menu_info->security_image = gtk_image_new (); + + gtk_container_add (GTK_CONTAINER (menu_info), hbox); + gtk_box_pack_start (GTK_BOX (hbox), menu_info->spacer, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), menu_info->label, TRUE, TRUE, 0); + menu_info->cell_view = gtk_cell_view_new (); + menu_info->progress_bar = g_object_new (GTK_TYPE_CELL_RENDERER_PROGRESS, + "text", "", + NULL); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (menu_info->cell_view), + GTK_CELL_RENDERER (menu_info->progress_bar), + TRUE); + gtk_box_pack_start (GTK_BOX (hbox), menu_info->cell_view, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (hbox), menu_info->security_image, FALSE, FALSE, 0); + + /* We don't show all the widgets, but we do show a few */ + gtk_widget_show (menu_info->spacer); + gtk_widget_show (menu_info->label); + gtk_widget_show (menu_info->cell_view); + gtk_widget_show (hbox); +} + +static void +nm_menu_wireless_class_init (NMMenuWirelessClass *menu_info_class) +{ +} + +GtkWidget * +nm_menu_wireless_new (GtkSizeGroup *image_size_group, + GtkSizeGroup *encryption_size_group) +{ + GtkWidget *retval = g_object_new (nm_menu_wireless_get_type (), NULL); + + gtk_size_group_add_widget (image_size_group, + NM_MENU_WIRELESS (retval)->spacer); + gtk_size_group_add_widget (encryption_size_group, + NM_MENU_WIRELESS (retval)->security_image); + + return retval; +} + +/* has_encrypted means that the wireless network has an encrypted + * area, and thus we need to allow for spacing. + */ +void +nm_menu_wireless_update (NMMenuWireless *menu_info, + WirelessNetwork *network, + gboolean has_encrypted) +{ + char *display_essid; + + display_essid = nm_menu_wireless_escape_essid_for_display (network->essid); + if (network->active) + { + char *markup_essid; + markup_essid = g_markup_printf_escaped ("%s", display_essid); + gtk_label_set_markup (GTK_LABEL (menu_info->label), markup_essid); + g_free (markup_essid); + } + else + { + gtk_label_set_text (GTK_LABEL (menu_info->label), display_essid); + } + + g_free (display_essid); + g_object_set (G_OBJECT (menu_info->progress_bar), + "value", CLAMP ((int) network->strength, 0, 100), + NULL); + + /* Deal with the encrypted icon */ + g_object_set (menu_info->security_image, "visible", has_encrypted, NULL); + + if (network->encrypted) + gtk_image_set_from_stock (GTK_IMAGE (menu_info->security_image), "gnome-lockscreen", GTK_ICON_SIZE_MENU); + else + gtk_image_set_from_stock (GTK_IMAGE (menu_info->security_image), NULL, GTK_ICON_SIZE_MENU); +} + + +/* This is copied from eel. + */ +static char * +eel_make_valid_utf8 (const char *name) +{ + GString *string; + const char *remainder, *invalid; + int remaining_bytes, valid_bytes; + + string = NULL; + remainder = name; + remaining_bytes = strlen (name); + + while (remaining_bytes != 0) { + if (g_utf8_validate (remainder, remaining_bytes, &invalid)) { + break; + } + valid_bytes = invalid - remainder; + + if (string == NULL) { + string = g_string_sized_new (remaining_bytes); + } + g_string_append_len (string, remainder, valid_bytes); + g_string_append_c (string, '?'); + + remaining_bytes -= valid_bytes + 1; + remainder = invalid + 1; + } + + if (string == NULL) { + return g_strdup (name); + } + + g_string_append (string, remainder); + g_string_append (string, _(" (invalid Unicode)")); + g_assert (g_utf8_validate (string->str, -1, NULL)); + + return g_string_free (string, FALSE); +} + +char * +nm_menu_wireless_escape_essid_for_display (const char *essid) +{ + if (g_utf8_validate (essid, -1, NULL)) + return g_strdup (essid); + else + return eel_make_valid_utf8 (essid); +} diff --git a/panel-applet/menu-info.h b/panel-applet/menu-info.h new file mode 100644 index 0000000000..d2a24a1241 --- /dev/null +++ b/panel-applet/menu-info.h @@ -0,0 +1,59 @@ +/* menu-info.h: Simple menu item for the Applet to use + * + * Jonathan Blandford + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2004 Red Hat, Inc. + */ + +#ifndef MENU_INFO_H +#define MENU_INFO_H + + +#include +#include "NMWirelessApplet.h" + +#define NM_TYPE_MENU_WIRELESS (nm_menu_wireless_get_type ()) +#define NM_MENU_WIRELESS(widget) (G_TYPE_CHECK_INSTANCE_CAST ((widget), NM_TYPE_MENU_WIRELESS, NMMenuWireless)) + +typedef struct +{ + GtkCheckMenuItemClass parent_class; +} NMMenuWirelessClass; + +typedef struct +{ + GtkCheckMenuItem parent; + GtkWidget *spacer; + GtkWidget *cell_view; + GtkWidget *label; + GtkWidget *security_image; + GObject *progress_bar; +} NMMenuWireless; + + +GType nm_menu_wireless_get_type (void); +GtkWidget *nm_menu_wireless_new (GtkSizeGroup *image_size_group, + GtkSizeGroup *encryption_size_group); +void nm_menu_wireless_update (NMMenuWireless *menu_info, + WirelessNetwork *network, + gboolean has_encrypted); + +/* Helper function; escapes an essid for human readable display. */ +char *nm_menu_wireless_escape_essid_for_display (const char *essid); + + +#endif /* MENU_INFO_H */