[Goodies-commits] r7312 - in xfce4-screenshooter/trunk: . lib
Jerome Guelfucci
jeromeg at xfce.org
Mon May 4 16:54:59 CEST 2009
Author: jeromeg
Date: 2009-05-04 14:54:59 +0000 (Mon, 04 May 2009)
New Revision: 7312
Added:
xfce4-screenshooter/trunk/lib/sexy-url-label.c
xfce4-screenshooter/trunk/lib/sexy-url-label.h
Modified:
xfce4-screenshooter/trunk/ChangeLog
xfce4-screenshooter/trunk/lib/Makefile.am
xfce4-screenshooter/trunk/lib/screenshooter-zimagez.c
xfce4-screenshooter/trunk/lib/screenshooter-zimagez.h
Log:
* lib/sexy-url-label.{c,h}: add the sexy_url_label taken from
libsexy.
* lib/screenshooter-zimagez.{c,h}:
- add a link to ZimageZ so that users can create an account easily.
- add tooltips for the different entries.
- if one of the fiels is empty when the dialog is validated, show it
again and ask the user to fill all the fields.
- plug some leaks and fix a double free issue.
Modified: xfce4-screenshooter/trunk/ChangeLog
===================================================================
--- xfce4-screenshooter/trunk/ChangeLog 2009-05-04 11:13:35 UTC (rev 7311)
+++ xfce4-screenshooter/trunk/ChangeLog 2009-05-04 14:54:59 UTC (rev 7312)
@@ -1,5 +1,16 @@
2009-05-04 jeromeg
+ * lib/sexy-url-label.{c,h}: add the sexy_url_label taken from
+ libsexy.
+ * lib/screenshooter-zimagez.{c,h}:
+ - add a link to ZimageZ so that users can create an account easily.
+ - add tooltips for the different entries.
+ - if one of the fiels is empty when the dialog is validated, show it
+ again and ask the user to fill all the fields.
+ - plug some leaks and fix a double free issue.
+
+2009-05-04 jeromeg
+
* lib/screenshooter-zimagez.c:
- (screenshooter_upload_to_zimagez):
+ use a GtkTable to improve the layout.
Modified: xfce4-screenshooter/trunk/lib/Makefile.am
===================================================================
--- xfce4-screenshooter/trunk/lib/Makefile.am 2009-05-04 11:13:35 UTC (rev 7311)
+++ xfce4-screenshooter/trunk/lib/Makefile.am 2009-05-04 14:54:59 UTC (rev 7312)
@@ -5,6 +5,7 @@
libscreenshooter.h \
screenshooter-global.h \
screenshooter-utils.c screenshooter-utils.h \
+ sexy-url-label.c sexy-url-label.h \
screenshooter-capture.c screenshooter-capture.h \
screenshooter-dialogs.c screenshooter-dialogs.h \
screenshooter-actions.c screenshooter-actions.h \
Modified: xfce4-screenshooter/trunk/lib/screenshooter-zimagez.c
===================================================================
--- xfce4-screenshooter/trunk/lib/screenshooter-zimagez.c 2009-05-04 11:13:35 UTC (rev 7311)
+++ xfce4-screenshooter/trunk/lib/screenshooter-zimagez.c 2009-05-04 14:54:59 UTC (rev 7312)
@@ -51,10 +51,13 @@
static void
open_url_hook (GtkLinkButton *button,
const gchar *link,
- gpointer user_data);
+ gpointer user_data);
+static void
+open_zimagez_link (gpointer unused);
+
/* Private */
@@ -87,12 +90,19 @@
if (!g_spawn_command_line_async (command, &error))
{
- TRACE ("An error occured");
+ TRACE ("An error occured when opening the URL");
xfce_err (error->message);
g_error_free (error);
}
}
+
+
+
+static void open_zimagez_link (gpointer unused)
+{
+ open_url_hook (NULL, "http://www.zimagez.com", NULL);
+}
/* Public */
@@ -180,10 +190,17 @@
/* Create the information label */
- information_label =
- gtk_label_new (_("Please file the following fields with your ZimageZ© \n"
- "user name, passsword and details about the screenshot."));
+ information_label = sexy_url_label_new ();
+ /* Note for translators : make sure to put the <a>....</a> on the first line */
+ sexy_url_label_set_markup (SEXY_URL_LABEL (information_label),
+ _("Please file the following fields with your "
+ "<a href=\"http://www.zimagez.com\">ZimageZ©</a> \n"
+ "user name, passsword and details about the screenshot."));
+
+ g_signal_connect_swapped (G_OBJECT (information_label), "url-activated",
+ G_CALLBACK (open_zimagez_link), NULL);
+
gtk_misc_set_alignment (GTK_MISC (information_label), 0, 0);
gtk_container_add (GTK_CONTAINER (vbox), information_label);
@@ -211,6 +228,11 @@
/* Create the user entry */
user_entry = gtk_entry_new ();
+ gtk_widget_set_tooltip_text (user_entry,
+ _("Your Zimagez user name, if you do not have one yet"
+ "please create one on the Web page linked above"));
+
+
gtk_table_attach_defaults (GTK_TABLE (table), user_entry, 1, 2, 0, 1);
/* Create the password label */
@@ -227,6 +249,8 @@
/* Create the password entry */
password_entry = gtk_entry_new ();
+ gtk_widget_set_tooltip_text (password_entry, _("The password for the user above"));
+
gtk_entry_set_visibility (GTK_ENTRY (password_entry), FALSE);
gtk_table_attach_defaults (GTK_TABLE (table), password_entry, 1, 2, 1, 2);
@@ -245,6 +269,10 @@
/* Create the title entry */
title_entry = gtk_entry_new ();
+ gtk_widget_set_tooltip_text (title_entry,
+ _("The title of the screenshot, it will be used when"
+ " displaying the screenshot on ZimageZ"));
+
gtk_table_attach_defaults (GTK_TABLE (table), title_entry, 1, 2, 2, 3);
/* Create the comment label */
@@ -261,6 +289,10 @@
/* Create the comment entry */
comment_entry = gtk_entry_new ();
+ gtk_widget_set_tooltip_text (title_entry,
+ _("A comment on the screenshot, it will be used when"
+ " displaying the screenshot on ZimageZ"));
+
gtk_table_attach_defaults (GTK_TABLE (table), comment_entry, 1, 2, 3, 4);
/* Show the widgets of the dialog main box*/
@@ -300,15 +332,38 @@
password = g_strdup (gtk_entry_get_text (GTK_ENTRY (password_entry)));
title = g_strdup (gtk_entry_get_text (GTK_ENTRY (title_entry)));
comment = g_strdup (gtk_entry_get_text (GTK_ENTRY (comment_entry)));
+
+ if ((dialog_response == GTK_RESPONSE_OK) && (g_str_equal (user, "") ||
+ g_str_equal (password, "") ||
+ g_str_equal (title, "") ||
+ g_str_equal (comment, "")))
+ {
+ TRACE ("One of the fields was empty, let the user file it.");
+
+ gtk_label_set_markup (GTK_LABEL (information_label),
+ _("<span weight=\"bold\" foreground=\"darkred\" "
+ "stretch=\"semiexpanded\">You must fill all the "
+ " fields.</span>"));
+
+ g_free (user);
+ g_free (password);
+ g_free (title);
+ g_free (comment);
+
+ continue;
+ }
+ else
+ {
+ TRACE ("All fields were filed");
+ gtk_widget_hide (dialog);
+ }
- gtk_widget_hide (dialog);
-
while (gtk_events_pending ())
gtk_main_iteration_do (FALSE);
- encoded_password = g_strreverse (rot13 (password));
+ encoded_password = g_strdup (g_strreverse (rot13 (password)));
- TRACE ("User: %s Password: %s", user, encoded_password);
+ TRACE ("User: %s", user);
/* Start the user session */
TRACE ("Call the login method");
@@ -384,6 +439,9 @@
}
xmlrpc_DECREF (resultP);
+
+ g_free (password);
+ g_free (encoded_password);
/* Get the contents of the image file and encode it to base64 */
g_file_get_contents (image_path, &data, &data_length, NULL);
@@ -397,6 +455,10 @@
"(sssss)", encoded_data, file_name, title, comment,
login_response);
+ g_free (user);
+ g_free (title);
+ g_free (comment);
+
if (warn_if_fault_occurred (&env))
{
xmlrpc_env_clean (&env);
@@ -408,9 +470,9 @@
/* If the response is a boolean, there was an error */
if (xmlrpc_value_type (resultP) == XMLRPC_TYPE_BOOL)
{
- xmlrpc_bool response;
+ xmlrpc_bool response_upload;
- xmlrpc_read_bool (&env, resultP, &response);
+ xmlrpc_read_bool (&env, resultP, &response_upload);
if (warn_if_fault_occurred (&env))
{
@@ -420,7 +482,7 @@
return NULL;
}
- if (!response)
+ if (!response_upload)
{
xfce_err (_("An error occurred while uploading the screenshot."));
Modified: xfce4-screenshooter/trunk/lib/screenshooter-zimagez.h
===================================================================
--- xfce4-screenshooter/trunk/lib/screenshooter-zimagez.h 2009-05-04 11:13:35 UTC (rev 7311)
+++ xfce4-screenshooter/trunk/lib/screenshooter-zimagez.h 2009-05-04 14:54:59 UTC (rev 7312)
@@ -31,6 +31,7 @@
#include <xmlrpc-c/client.h>
#include "screenshooter-utils.h"
+#include "sexy-url-label.h"
gchar *screenshooter_upload_to_zimagez (const gchar *image_path);
Added: xfce4-screenshooter/trunk/lib/sexy-url-label.c
===================================================================
--- xfce4-screenshooter/trunk/lib/sexy-url-label.c (rev 0)
+++ xfce4-screenshooter/trunk/lib/sexy-url-label.c 2009-05-04 14:54:59 UTC (rev 7312)
@@ -0,0 +1,845 @@
+/*
+ * @file libsexy/sexy-url-label.c URL Label
+ *
+ * @Copyright (C) 2007 Benedikt Meurer <benny at xfce.org>
+ * @Copyright (C) 2005-2006 Christian Hammond
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "sexy-url-label.h"
+
+#define SEXY_URL_LABEL_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), SEXY_TYPE_URL_LABEL, \
+ SexyUrlLabelPrivate))
+
+typedef struct
+{
+ int start;
+ int end;
+ const gchar *url;
+
+} SexyUrlLabelLink;
+
+typedef struct
+{
+ GList *links;
+ GList *urls;
+ SexyUrlLabelLink *active_link;
+ GtkWidget *popup_menu;
+ GdkWindow *event_window;
+
+ int layout_x;
+ int layout_y;
+
+ size_t wrap_width;
+
+ GString *temp_markup_result;
+
+} SexyUrlLabelPrivate;
+
+/*
+ * NOTE: This *MUST* match the LabelWrapWidth struct in gtklabel.c.
+ */
+typedef struct
+{
+ gint width;
+ PangoFontDescription *font_desc;
+
+} LabelWrapWidth;
+
+enum
+{
+ URL_ACTIVATED,
+ LAST_SIGNAL
+};
+
+static void sexy_url_label_finalize(GObject *obj);
+static void sexy_url_label_realize(GtkWidget *widget);
+static void sexy_url_label_unrealize(GtkWidget *widget);
+static void sexy_url_label_map(GtkWidget *widget);
+static void sexy_url_label_unmap(GtkWidget *widget);
+static void sexy_url_label_size_allocate(GtkWidget *widget,
+ GtkAllocation *allocation);
+static gboolean sexy_url_label_motion_notify_event(GtkWidget *widget,
+ GdkEventMotion *event);
+static gboolean sexy_url_label_leave_notify_event(GtkWidget *widget,
+ GdkEventCrossing *event);
+static gboolean sexy_url_label_button_press_event(GtkWidget *widget,
+ GdkEventButton *event);
+
+static void open_link_activate_cb(GtkMenuItem *menu_item,
+ SexyUrlLabel *url_label);
+static void copy_link_activate_cb(GtkMenuItem *menu_item,
+ SexyUrlLabel *url_label);
+
+static void sexy_url_label_clear_links(SexyUrlLabel *url_label);
+static void sexy_url_label_clear_urls(SexyUrlLabel *url_label);
+static void sexy_url_label_rescan_label(SexyUrlLabel *url_label);
+
+static GtkLabelClass *parent_class = NULL;
+static guint signals[LAST_SIGNAL] = {0};
+
+G_DEFINE_TYPE(SexyUrlLabel, sexy_url_label, GTK_TYPE_LABEL);
+
+static void
+sexy_url_label_class_init(SexyUrlLabelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+ parent_class = g_type_class_peek_parent(klass);
+
+ object_class->finalize = sexy_url_label_finalize;
+
+ widget_class->realize = sexy_url_label_realize;
+ widget_class->unrealize = sexy_url_label_unrealize;
+ widget_class->map = sexy_url_label_map;
+ widget_class->unmap = sexy_url_label_unmap;
+ widget_class->size_allocate = sexy_url_label_size_allocate;
+ widget_class->motion_notify_event = sexy_url_label_motion_notify_event;
+ widget_class->leave_notify_event = sexy_url_label_leave_notify_event;
+ widget_class->button_press_event = sexy_url_label_button_press_event;
+
+ g_type_class_add_private(klass, sizeof(SexyUrlLabelPrivate));
+
+ /**
+ * SexyUrlLabel::url-activated:
+ * @url_label: The label on which the signal was emitted.
+ * @url: The URL which was activated.
+ *
+ * The ::url-activated signal is emitted when a URL in the label was
+ * clicked.
+ */
+ signals[URL_ACTIVATED] =
+ g_signal_new("url_activated",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET(SexyUrlLabelClass, url_activated),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+}
+
+static void
+selectable_changed_cb(SexyUrlLabel *url_label)
+{
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ if (priv->event_window != NULL)
+ gdk_window_raise(priv->event_window);
+}
+
+static void
+sexy_url_label_init(SexyUrlLabel *url_label)
+{
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+ GtkWidget *item;
+ GtkWidget *image;
+
+ priv->links = NULL;
+ priv->active_link = NULL;
+ priv->event_window = NULL;
+
+ g_signal_connect(G_OBJECT(url_label), "notify::selectable",
+ G_CALLBACK(selectable_changed_cb), NULL);
+
+ priv->popup_menu = gtk_menu_new();
+
+ /* Open Link */
+ item = gtk_image_menu_item_new_with_mnemonic("_Open Link");
+ gtk_widget_show(item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(priv->popup_menu), item);
+
+ g_signal_connect(G_OBJECT(item), "activate",
+ G_CALLBACK(open_link_activate_cb), url_label);
+
+ image = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
+ gtk_widget_show(image);
+
+ /* Copy Link Address */
+ item = gtk_image_menu_item_new_with_mnemonic("Copy _Link Address");
+ gtk_widget_show(item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(priv->popup_menu), item);
+
+ g_signal_connect(G_OBJECT(item), "activate",
+ G_CALLBACK(copy_link_activate_cb), url_label);
+
+ image = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
+ gtk_widget_show(image);
+}
+
+static void
+sexy_url_label_finalize(GObject *obj)
+{
+ SexyUrlLabel *url_label = SEXY_URL_LABEL(obj);
+
+ sexy_url_label_clear_links(url_label);
+ sexy_url_label_clear_urls(url_label);
+
+ if (G_OBJECT_CLASS(parent_class)->finalize != NULL)
+ G_OBJECT_CLASS(parent_class)->finalize(obj);
+}
+
+static gboolean
+sexy_url_label_motion_notify_event(GtkWidget *widget, GdkEventMotion *event)
+{
+ SexyUrlLabel *url_label = (SexyUrlLabel *)widget;
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+ PangoLayout *layout = gtk_label_get_layout(GTK_LABEL(url_label));
+ GdkModifierType state;
+ gboolean found = FALSE;
+ GList *l;
+ int index, trailing;
+ int x, y;
+ SexyUrlLabelLink *link = NULL;
+
+ if (event->is_hint)
+ gdk_window_get_pointer(event->window, &x, &y, &state);
+ else
+ {
+ x = event->x;
+ y = event->y;
+ state = event->state;
+ }
+
+ if (pango_layout_xy_to_index(layout,
+ (x - priv->layout_x) * PANGO_SCALE,
+ (y - priv->layout_y) * PANGO_SCALE,
+ &index, &trailing))
+ {
+ for (l = priv->links; l != NULL; l = l->next)
+ {
+ link = (SexyUrlLabelLink *)l->data;
+
+ if (index >= link->start && index <= link->end)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (found)
+ {
+ if (priv->active_link == NULL)
+ {
+ GdkCursor *cursor;
+
+ cursor = gdk_cursor_new_for_display(
+ gtk_widget_get_display(widget), GDK_HAND2);
+ gdk_window_set_cursor(priv->event_window, cursor);
+ gdk_cursor_unref(cursor);
+
+ priv->active_link = link;
+ }
+ }
+ else
+ {
+ if (priv->active_link != NULL)
+ {
+ if (gtk_label_get_selectable(GTK_LABEL(url_label)))
+ {
+ GdkCursor *cursor;
+
+ cursor = gdk_cursor_new_for_display(
+ gtk_widget_get_display(widget), GDK_XTERM);
+ gdk_window_set_cursor(priv->event_window, cursor);
+ gdk_cursor_unref(cursor);
+ }
+ else
+ gdk_window_set_cursor(priv->event_window, NULL);
+
+ priv->active_link = NULL;
+ }
+ }
+
+ /*
+ * Another beautiful libsexy hack. This one prevents the callback
+ * from going "Oh boy, they clicked and dragged! Let's select more of
+ * the text!"
+ */
+ if (priv->active_link != NULL)
+ event->state = 0;
+
+ GTK_WIDGET_CLASS(parent_class)->motion_notify_event(widget, event);
+
+ return FALSE;
+}
+
+static gboolean
+sexy_url_label_leave_notify_event(GtkWidget *widget, GdkEventCrossing *event)
+{
+ SexyUrlLabel *url_label = (SexyUrlLabel *)widget;
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ if (GTK_WIDGET_CLASS(parent_class)->leave_notify_event != NULL)
+ GTK_WIDGET_CLASS(parent_class)->leave_notify_event(widget, event);
+
+ if (event->mode == GDK_CROSSING_NORMAL)
+ {
+ gdk_window_set_cursor(priv->event_window, NULL);
+ priv->active_link = NULL;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+sexy_url_label_button_press_event(GtkWidget *widget, GdkEventButton *event)
+{
+ SexyUrlLabel *url_label = (SexyUrlLabel *)widget;
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ if (priv->active_link == NULL)
+ {
+ return GTK_WIDGET_CLASS(parent_class)->button_press_event(widget,
+ event);
+ }
+
+ if (event->button == 1)
+ {
+ g_signal_emit(url_label, signals[URL_ACTIVATED], 0,
+ priv->active_link->url);
+ }
+ else if (event->button == 3)
+ {
+ gtk_menu_popup(GTK_MENU(priv->popup_menu), NULL, NULL, NULL, NULL,
+ event->button, event->time);
+ }
+
+ return TRUE;
+}
+
+static void
+update_wrap_width(SexyUrlLabel *url_label, size_t wrap_width)
+{
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+ LabelWrapWidth *wrap_width_data;
+ GtkStyle *style;
+
+ if (wrap_width == 0 || !gtk_label_get_line_wrap(GTK_LABEL(url_label)))
+ return;
+
+#if 0
+ pango_layout_set_width(gtk_label_get_layout(GTK_LABEL(url_label)),
+ wrap_width * PANGO_SCALE);
+#endif
+ style = GTK_WIDGET(url_label)->style;
+ wrap_width_data = g_object_get_data(G_OBJECT(style),
+ "gtk-label-wrap-width");
+
+ if (wrap_width_data != NULL &&
+ (size_t) wrap_width_data->width != wrap_width * PANGO_SCALE)
+ {
+ wrap_width_data->width = wrap_width * PANGO_SCALE;
+ priv->wrap_width = wrap_width;
+ g_object_unref(GTK_LABEL(url_label)->layout);
+ GTK_LABEL(url_label)->layout = NULL;
+ gtk_label_get_layout(GTK_LABEL(url_label));
+ gtk_widget_queue_resize(GTK_WIDGET(url_label));
+ }
+}
+
+static void
+sexy_url_label_realize(GtkWidget *widget)
+{
+ SexyUrlLabel *url_label = (SexyUrlLabel *)widget;
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+
+ GTK_WIDGET_CLASS(parent_class)->realize(widget);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->allocation.height;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.wclass = GDK_INPUT_ONLY;
+ attributes.event_mask = gtk_widget_get_events(widget);
+ attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_POINTER_MOTION_HINT_MASK |
+ GDK_LEAVE_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK);
+ attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+ priv->event_window =
+ gdk_window_new(gtk_widget_get_parent_window(widget), &attributes,
+ attributes_mask);
+ gdk_window_set_user_data(priv->event_window, widget);
+}
+
+static void
+sexy_url_label_unrealize(GtkWidget *widget)
+{
+ SexyUrlLabel *url_label = (SexyUrlLabel *)widget;
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ if (priv->event_window != NULL)
+ {
+ gdk_window_set_user_data(priv->event_window, NULL);
+ gdk_window_destroy(priv->event_window);
+ priv->event_window = NULL;
+ }
+
+ GTK_WIDGET_CLASS(parent_class)->unrealize(widget);
+}
+
+static void
+sexy_url_label_map(GtkWidget *widget)
+{
+ SexyUrlLabel *url_label = (SexyUrlLabel *)widget;
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ GTK_WIDGET_CLASS(parent_class)->map(widget);
+
+ if (priv->event_window != NULL)
+ gdk_window_show(priv->event_window);
+}
+
+static void
+sexy_url_label_unmap(GtkWidget *widget)
+{
+ SexyUrlLabel *url_label = (SexyUrlLabel *)widget;
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ if (priv->event_window != NULL)
+ gdk_window_hide(priv->event_window);
+
+ GTK_WIDGET_CLASS(parent_class)->map(widget);
+}
+
+static void
+sexy_url_label_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
+{
+ SexyUrlLabel *url_label = (SexyUrlLabel *)widget;
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+#if 0
+ {
+ LabelWrapWidth *wrap_width_data;
+ GtkStyle *style;
+ style = GTK_WIDGET(url_label)->style;
+ wrap_width_data = g_object_get_data(G_OBJECT(style),
+ "gtk-label-wrap-width");
+ if (wrap_width_data != NULL)
+ printf("wrap width = %d\n", wrap_width_data->width / PANGO_SCALE);
+ }
+#endif
+ update_wrap_width(url_label, allocation->width);
+ GTK_WIDGET_CLASS(parent_class)->size_allocate(widget, allocation);
+ pango_layout_set_width(gtk_label_get_layout(GTK_LABEL(url_label)),
+ allocation->width * PANGO_SCALE);
+
+ if (GTK_WIDGET_REALIZED(widget))
+ {
+ gdk_window_move_resize(priv->event_window,
+ allocation->x, allocation->y,
+ allocation->width, allocation->height);
+ }
+
+ sexy_url_label_rescan_label(url_label);
+}
+
+static void
+open_link_activate_cb(GtkMenuItem *menu_item, SexyUrlLabel *url_label)
+{
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ if (priv->active_link == NULL)
+ return;
+
+ g_signal_emit(url_label, signals[URL_ACTIVATED], 0, priv->active_link->url);
+}
+
+static void
+copy_link_activate_cb(GtkMenuItem *menu_item, SexyUrlLabel *url_label)
+{
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+ GtkClipboard *clipboard;
+
+ if (priv->active_link == NULL)
+ return;
+
+ clipboard = gtk_widget_get_clipboard(GTK_WIDGET(url_label),
+ GDK_SELECTION_PRIMARY);
+
+ gtk_clipboard_set_text(clipboard, priv->active_link->url,
+ strlen(priv->active_link->url));
+}
+
+/**
+ * sexy_url_label_new
+ *
+ * Creates a new SexyUrlLabel widget.
+ *
+ * Returns: a new #SexyUrlLabel.
+ */
+GtkWidget *
+sexy_url_label_new(void)
+{
+ return g_object_new(SEXY_TYPE_URL_LABEL, NULL);
+}
+
+static void
+sexy_url_label_clear_links(SexyUrlLabel *url_label)
+{
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ if (priv->links == NULL)
+ return;
+
+ g_list_foreach(priv->links, (GFunc)g_free, NULL);
+ g_list_free(priv->links);
+ priv->links = NULL;
+}
+
+static void
+sexy_url_label_clear_urls(SexyUrlLabel *url_label)
+{
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ if (priv->urls == NULL)
+ return;
+
+ g_list_foreach(priv->urls, (GFunc)g_free, NULL);
+ g_list_free(priv->urls);
+ priv->urls = NULL;
+}
+
+static void
+sexy_url_label_rescan_label(SexyUrlLabel *url_label)
+{
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+ PangoLayout *layout = gtk_label_get_layout(GTK_LABEL(url_label));
+ PangoAttrList *list = pango_layout_get_attributes(layout);
+ PangoAttrIterator *iter;
+ GList *url_list;
+
+ sexy_url_label_clear_links(url_label);
+
+ if (list == NULL)
+ return;
+
+ iter = pango_attr_list_get_iterator(list);
+
+ gtk_label_get_layout_offsets(GTK_LABEL(url_label),
+ &priv->layout_x, &priv->layout_y);
+
+ priv->layout_x -= GTK_WIDGET(url_label)->allocation.x;
+ priv->layout_y -= GTK_WIDGET(url_label)->allocation.y;
+
+ url_list = priv->urls;
+
+ do
+ {
+ PangoAttribute *underline;
+ PangoAttribute *color;
+
+ underline = pango_attr_iterator_get(iter, PANGO_ATTR_UNDERLINE);
+ color = pango_attr_iterator_get(iter, PANGO_ATTR_FOREGROUND);
+
+ if (underline != NULL && color != NULL)
+ {
+ gint start, end;
+ PangoRectangle start_pos;
+ PangoRectangle end_pos;
+ SexyUrlLabelLink *link;
+
+ pango_attr_iterator_range(iter, &start, &end);
+ pango_layout_index_to_pos(layout, start, &start_pos);
+ pango_layout_index_to_pos(layout, end, &end_pos);
+
+ link = g_new0(SexyUrlLabelLink, 1);
+ link->start = start;
+ link->end = end;
+ link->url = (const gchar *)url_list->data;
+ priv->links = g_list_append(priv->links, link);
+
+ url_list = url_list->next;
+ }
+
+ } while (pango_attr_iterator_next(iter));
+
+ pango_attr_iterator_destroy (iter);
+}
+
+static void
+start_element_handler(GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ SexyUrlLabel *url_label = SEXY_URL_LABEL(user_data);
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ if (!strcmp(element_name, "a"))
+ {
+ const gchar *url = NULL;
+ int line_number;
+ int char_number;
+ int i;
+
+ g_markup_parse_context_get_position(context, &line_number,
+ &char_number);
+
+ for (i = 0; attribute_names[i] != NULL; i++)
+ {
+ const gchar *attr = attribute_names[i];
+
+ if (!strcmp(attr, "href"))
+ {
+ if (url != NULL)
+ {
+ g_set_error(error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "Attribute '%s' occurs twice on <a> tag "
+ "on line %d char %d, may only occur once",
+ attribute_names[i], line_number, char_number);
+ return;
+ }
+
+ url = attribute_values[i];
+ }
+ else
+ {
+ g_set_error(error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
+ "Attribute '%s' is not allowed on the <a> tag "
+ "on line %d char %d",
+ attribute_names[i], line_number, char_number);
+ return;
+ }
+ }
+
+ if (url == NULL)
+ {
+ g_set_error(error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "Attribute 'href' was missing on the <a> tag "
+ "on line %d char %d",
+ line_number, char_number);
+ return;
+ }
+
+ g_string_append(priv->temp_markup_result,
+ "<span color=\"blue\" underline=\"single\">");
+
+ priv->urls = g_list_append(priv->urls, g_strdup(url));
+ }
+ else
+ {
+ int i;
+
+ g_string_append_printf(priv->temp_markup_result,
+ "<%s", element_name);
+
+ for (i = 0; attribute_names[i] != NULL; i++)
+ {
+ const gchar *attr = attribute_names[i];
+ const gchar *value = attribute_values[i];
+
+ g_string_append_printf(priv->temp_markup_result,
+ " %s=\"%s\"",
+ attr, value);
+ }
+
+ g_string_append_c(priv->temp_markup_result, '>');
+ }
+}
+
+static void
+end_element_handler(GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ SexyUrlLabel *url_label = SEXY_URL_LABEL(user_data);
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ if (!strcmp(element_name, "a"))
+ {
+ g_string_append(priv->temp_markup_result, "</span>");
+ }
+ else
+ {
+ g_string_append_printf(priv->temp_markup_result,
+ "</%s>", element_name);
+ }
+}
+
+static void
+text_handler(GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ SexyUrlLabel *url_label = SEXY_URL_LABEL(user_data);
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ gchar *newtext = g_markup_escape_text (text, text_len);
+ g_string_append_len(priv->temp_markup_result, newtext, strlen (newtext));
+ g_free (newtext);
+}
+
+static const GMarkupParser markup_parser =
+{
+ start_element_handler,
+ end_element_handler,
+ text_handler,
+ NULL,
+ NULL
+};
+
+static gboolean
+xml_isspace(char c)
+{
+ return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
+}
+
+static gboolean
+parse_custom_markup(SexyUrlLabel *url_label, const gchar *markup,
+ gchar **ret_markup)
+{
+ GMarkupParseContext *context = NULL;
+ SexyUrlLabelPrivate *priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+ GError *error = NULL;
+ const gchar *p, *end;
+ gboolean needs_root = TRUE;
+ gsize length;
+
+ g_return_val_if_fail(markup != NULL, FALSE);
+ g_return_val_if_fail(ret_markup != NULL, FALSE);
+
+ priv->temp_markup_result = g_string_new(NULL);
+
+ length = strlen(markup);
+ p = markup;
+ end = markup + length;
+
+ while (p != end && xml_isspace(*p))
+ p++;
+
+ if (end - p >= 8 && strncmp(p, "<markup>", 8) == 0)
+ needs_root = FALSE;
+
+ context = g_markup_parse_context_new(&markup_parser, 0, url_label, NULL);
+
+ if (needs_root)
+ {
+ if (!g_markup_parse_context_parse(context, "<markup>", -1, &error))
+ goto failed;
+ }
+
+ if (!g_markup_parse_context_parse(context, markup, strlen(markup), &error))
+ goto failed;
+
+ if (needs_root)
+ {
+ if (!g_markup_parse_context_parse(context, "</markup>", -1, &error))
+ goto failed;
+ }
+
+ if (!g_markup_parse_context_end_parse(context, &error))
+ goto failed;
+
+ if (error != NULL)
+ g_error_free(error);
+
+ g_markup_parse_context_free(context);
+
+ *ret_markup = g_string_free(priv->temp_markup_result, FALSE);
+ priv->temp_markup_result = NULL;
+
+ return TRUE;
+
+failed:
+ fprintf(stderr, "Unable to parse markup: %s\n", error->message);
+ g_error_free(error);
+
+ g_string_free(priv->temp_markup_result, TRUE);
+ priv->temp_markup_result = NULL;
+
+ g_markup_parse_context_free(context);
+ return FALSE;
+}
+
+/**
+ * sexy_url_label_set_markup
+ * @url_label: A #SexyUrlLabel.
+ * @markup: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
+ *
+ * Parses @markup which is marked up with the <link
+ * linkend="PangoMarkupFormat">Pango text markup language</link> as well as
+ * HTML-style hyperlinks, setting the label's text and attribute list based
+ * on the parse results. If the @markup is external data, you may need to
+ * escape it with g_markup_escape_text() or g_markup_printf_escaped()
+ */
+void
+sexy_url_label_set_markup(SexyUrlLabel *url_label, const gchar *markup)
+{
+ SexyUrlLabelPrivate *priv;
+ gchar *new_markup;
+
+ g_return_if_fail(SEXY_IS_URL_LABEL(url_label));
+
+ priv = SEXY_URL_LABEL_GET_PRIVATE(url_label);
+
+ sexy_url_label_clear_links(url_label);
+ sexy_url_label_clear_urls(url_label);
+
+ if (markup == NULL || *markup == '\0')
+ {
+ gtk_label_set_markup(GTK_LABEL(url_label), "");
+ return;
+ }
+
+ if (parse_custom_markup(url_label, markup, &new_markup))
+ {
+ gtk_label_set_markup(GTK_LABEL(url_label), new_markup);
+ g_free(new_markup);
+ }
+ else
+ {
+ gtk_label_set_markup(GTK_LABEL(url_label), "");
+ }
+
+ sexy_url_label_rescan_label(url_label);
+
+ update_wrap_width(url_label, priv->wrap_width);
+}
Added: xfce4-screenshooter/trunk/lib/sexy-url-label.h
===================================================================
--- xfce4-screenshooter/trunk/lib/sexy-url-label.h (rev 0)
+++ xfce4-screenshooter/trunk/lib/sexy-url-label.h 2009-05-04 14:54:59 UTC (rev 7312)
@@ -0,0 +1,74 @@
+/*
+ * @file libsexy/sexy-url-label.h URL Label
+ *
+ * @Copyright (C) 2007 Benedikt Meurer <benny at xfce.org>
+ * @Copyright (C) 2005-2006 Christian Hammond
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 _SEXY_URL_LABEL_H_
+#define _SEXY_URL_LABEL_H_
+
+typedef struct _SexyUrlLabel SexyUrlLabel;
+typedef struct _SexyUrlLabelClass SexyUrlLabelClass;
+
+#include <gtk/gtk.h>
+
+#define SEXY_TYPE_URL_LABEL (sexy_url_label_get_type())
+#define SEXY_URL_LABEL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), SEXY_TYPE_URL_LABEL, SexyUrlLabel))
+#define SEXY_URL_LABEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), SEXY_TYPE_URL_LABEL, SexyUrlLabelClass))
+#define SEXY_IS_URL_LABEL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), SEXY_TYPE_URL_LABEL))
+#define SEXY_IS_URL_LABEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), SEXY_TYPE_URL_LABEL))
+#define SEXY_URL_LABEL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), SEXY_TYPE_URL_LABEL, SexyUrlLabelClass))
+
+struct _SexyUrlLabel
+{
+ GtkLabel parent_object;
+
+ void (*gtk_reserved1)(void);
+ void (*gtk_reserved2)(void);
+ void (*gtk_reserved3)(void);
+ void (*gtk_reserved4)(void);
+};
+
+struct _SexyUrlLabelClass
+{
+ GtkLabelClass parent_class;
+
+ /* Signals */
+ void (*url_activated)(SexyUrlLabel *url_label, const gchar *url);
+
+ void (*gtk_reserved1)(void);
+ void (*gtk_reserved2)(void);
+ void (*gtk_reserved3)(void);
+ void (*gtk_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType sexy_url_label_get_type(void);
+
+GtkWidget *sexy_url_label_new(void);
+void sexy_url_label_set_markup(SexyUrlLabel *url_label, const gchar *markup);
+
+G_END_DECLS
+
+#endif /* _SEXY_URL_LABEL_H_ */
More information about the Goodies-commits
mailing list