X-Git-Url: https://git.0d.be/?p=empathy.git;a=blobdiff_plain;f=libempathy-gtk%2Fempathy-ui-utils.c;h=4503a39cc22f67f12cb613e3d1be4f55df183d46;hp=e91ac62913c50e6b473e4c7c3cb144bee180eeaa;hb=4d2d5a1622f93b69af195d7e3c4d4cb424dbec6e;hpb=7deb4ea20b08eab10473f2620c90f6b896d5af10 diff --git a/libempathy-gtk/empathy-ui-utils.c b/libempathy-gtk/empathy-ui-utils.c index e91ac629..4503a39c 100644 --- a/libempathy-gtk/empathy-ui-utils.c +++ b/libempathy-gtk/empathy-ui-utils.c @@ -38,10 +38,9 @@ #include #include -#include - #include "empathy-ui-utils.h" #include "empathy-images.h" +#include "empathy-smiley-manager.h" #include "empathy-conf.h" #define DEBUG_FLAG EMPATHY_DEBUG_OTHER @@ -51,14 +50,6 @@ #include #include -#define SCHEMES "(https?|s?ftps?|nntp|news|javascript|about|ghelp|apt|telnet|"\ - "file|webcal|mailto)" -#define BODY "([^\\ \\n]+)" -#define END_BODY "([^\\ \\n]*[^,;\?><()\\ \"\\.\\n])" -#define URI_REGEX "("SCHEMES"://"END_BODY")" \ - "|((mailto:)?"BODY"@"BODY"\\."END_BODY")"\ - "|((www|ftp)\\."END_BODY")" - void empathy_gtk_init (void) { @@ -74,19 +65,6 @@ empathy_gtk_init (void) initialized = TRUE; } -GRegex * -empathy_uri_regex_dup_singleton (void) -{ - static GRegex *uri_regex = NULL; - - /* We intentionally leak the regex so it's not recomputed */ - if (!uri_regex) { - uri_regex = g_regex_new (URI_REGEX, 0, 0, NULL); - } - - return g_regex_ref (uri_regex); -} - static GtkBuilder * builder_get_file_valist (const gchar *filename, const gchar *first_object, @@ -101,9 +79,19 @@ builder_get_file_valist (const gchar *filename, gui = gtk_builder_new (); if (!gtk_builder_add_from_file (gui, filename, &error)) { - g_critical ("GtkBuilder Error: %s", error->message); + g_critical ("GtkBuilder Error (%s): %s", + filename, error->message); g_clear_error (&error); g_object_unref (gui); + + /* we need to iterate and set all of the pointers to NULL */ + for (name = first_object; name; + name = va_arg (args, const gchar *)) { + object_ptr = va_arg (args, GObject**); + + *object_ptr = NULL; + } + return NULL; } @@ -144,13 +132,13 @@ empathy_builder_connect (GtkBuilder *gui, { va_list args; const gchar *name; - const gchar *signal; + const gchar *sig; GObject *object; GCallback callback; va_start (args, first_object); for (name = first_object; name; name = va_arg (args, const gchar *)) { - signal = va_arg (args, const gchar *); + sig = va_arg (args, const gchar *); callback = va_arg (args, GCallback); object = gtk_builder_get_object (gui, name); @@ -159,7 +147,7 @@ empathy_builder_connect (GtkBuilder *gui, continue; } - g_signal_connect (object, signal, callback, user_data); + g_signal_connect (object, sig, callback, user_data); } va_end (args); @@ -182,16 +170,6 @@ empathy_builder_unref_and_keep_widget (GtkBuilder *gui, return widget; } -const gchar * -empathy_icon_name_from_account (EmpathyAccount *account) -{ - McProfile *profile; - - profile = empathy_account_get_profile (account); - - return mc_profile_get_icon_name (profile); -} - const gchar * empathy_icon_name_for_presence (TpConnectionPresenceType presence) { @@ -229,6 +207,21 @@ empathy_icon_name_for_contact (EmpathyContact *contact) return empathy_icon_name_for_presence (presence); } +const gchar * +empathy_protocol_name_for_contact (EmpathyContact *contact) +{ + TpAccount *account; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + account = empathy_contact_get_account (contact); + if (account == NULL) { + return NULL; + } + + return tp_account_get_icon_name (account); +} + GdkPixbuf * empathy_pixbuf_from_data (gchar *data, gsize data_size) @@ -252,7 +245,7 @@ empathy_pixbuf_from_data_and_mime (gchar *data, } loader = gdk_pixbuf_loader_new (); - if (!gdk_pixbuf_loader_write (loader, data, data_size, &error)) { + if (!gdk_pixbuf_loader_write (loader, (guchar *) data, data_size, &error)) { DEBUG ("Failed to write to pixbuf loader: %s", error ? error->message : "No error given"); goto out; @@ -489,6 +482,104 @@ empathy_pixbuf_avatar_from_contact_scaled (EmpathyContact *contact, return empathy_pixbuf_from_avatar_scaled (avatar, width, height); } +GdkPixbuf * +empathy_pixbuf_contact_status_icon (EmpathyContact *contact, + gboolean show_protocol) +{ + const gchar *icon_name; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + icon_name = empathy_icon_name_for_contact (contact); + + if (icon_name == NULL) { + return NULL; + } + return empathy_pixbuf_contact_status_icon_with_icon_name (contact, + icon_name, + show_protocol); +} + +GdkPixbuf * +empathy_pixbuf_contact_status_icon_with_icon_name (EmpathyContact *contact, + const gchar *icon_name, + gboolean show_protocol) +{ + GdkPixbuf *pix_status; + GdkPixbuf *pix_protocol; + gchar *icon_filename; + gint height, width; + gint numerator, denominator; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + g_return_val_if_fail (icon_name != NULL, NULL); + + numerator = 3; + denominator = 4; + + icon_filename = empathy_filename_from_icon_name (icon_name, + GTK_ICON_SIZE_MENU); + if (icon_filename == NULL) { + DEBUG ("icon name: %s could not be found\n", icon_name); + return NULL; + } + + pix_status = gdk_pixbuf_new_from_file (icon_filename, NULL); + + g_free (icon_filename); + + if (pix_status == NULL) { + DEBUG ("Could not open icon %s\n", icon_filename); + return NULL; + } + + if (!show_protocol) + return pix_status; + + height = gdk_pixbuf_get_height (pix_status); + width = gdk_pixbuf_get_width (pix_status); + + pix_protocol = empathy_pixbuf_protocol_from_contact_scaled (contact, + width * numerator / denominator, + height * numerator / denominator); + + if (pix_protocol == NULL) { + return pix_status; + } + gdk_pixbuf_composite (pix_protocol, pix_status, + 0, height - height * numerator / denominator, + width * numerator / denominator, height * numerator / denominator, + 0, height - height * numerator / denominator, + 1, 1, + GDK_INTERP_BILINEAR, 255); + + g_object_unref (pix_protocol); + + return pix_status; +} + +GdkPixbuf * +empathy_pixbuf_protocol_from_contact_scaled (EmpathyContact *contact, + gint width, + gint height) +{ + TpAccount *account; + gchar *filename; + GdkPixbuf *pixbuf = NULL; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + account = empathy_contact_get_account (contact); + filename = empathy_filename_from_icon_name (tp_account_get_icon_name (account), + GTK_ICON_SIZE_MENU); + if (filename != NULL) { + pixbuf = gdk_pixbuf_new_from_file_at_size (filename, width, height, NULL); + g_free (filename); + } + + return pixbuf; +} + GdkPixbuf * empathy_pixbuf_scale_down_if_necessary (GdkPixbuf *pixbuf, gint max_size) { @@ -1282,7 +1373,8 @@ empathy_window_iconify (GtkWindow *window, GtkStatusIcon *status_icon) XChangeProperty (dpy, GDK_WINDOW_XID (gdk_window), - gdk_x11_get_xatom_by_name_for_display (gdk_drawable_get_display (gdk_window), + gdk_x11_get_xatom_by_name_for_display ( + gdk_drawable_get_display (gdk_window), "_NET_WM_ICON_GEOMETRY"), XA_CARDINAL, 32, PropModeReplace, (guchar *)&data, 4); @@ -1293,27 +1385,38 @@ empathy_window_iconify (GtkWindow *window, GtkStatusIcon *status_icon) /* Takes care of moving the window to the current workspace. */ void -empathy_window_present (GtkWindow *window, - gboolean steal_focus) +empathy_window_present (GtkWindow *window) { + GdkWindow *gdk_window; guint32 timestamp; g_return_if_fail (GTK_IS_WINDOW (window)); - /* There are three cases: hidden, visible, visible on another - * workspace. - */ - - if (!empathy_window_get_is_visible (window)) { - /* Hide it so present brings it to the current workspace. */ - gtk_widget_hide (GTK_WIDGET (window)); + /* Move the window to the current workspace before trying to show it. + * This is the behaviour people expect when clicking on the statusbar icon. */ + gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); + if (gdk_window) { + gint x, y; + gint w, h; + + /* Has no effect if the WM has viewports, like compiz */ + gdk_x11_window_move_to_current_desktop (gdk_window); + + /* If window is still off-screen, hide it to force it to + * reposition on the current workspace. */ + gtk_window_get_position (window, &x, &y); + gtk_window_get_size (window, &w, &h); + if (!EMPATHY_RECT_IS_ON_SCREEN (x, y, w, h)) + gtk_widget_hide (GTK_WIDGET (window)); } timestamp = gtk_get_current_event_time (); + if (timestamp == 0) + /* No event, fallback to _NET_WM_USER_TIME */ + timestamp = gdk_x11_display_get_user_time (gdk_display_get_default ()); + gtk_window_present_with_time (window, timestamp); gtk_window_set_skip_taskbar_hint (window, FALSE); - /* FIXME: This shouldn't be required as gtk_window_present's doc says - * it deiconify automatically. */ gtk_window_deiconify (window); } @@ -1326,32 +1429,53 @@ empathy_get_toplevel_window (GtkWidget *widget) toplevel = gtk_widget_get_toplevel (widget); if (GTK_IS_WINDOW (toplevel) && - GTK_WIDGET_TOPLEVEL (toplevel)) { + gtk_widget_is_toplevel (toplevel)) { return GTK_WINDOW (toplevel); } return NULL; } -/* The URL opening code can't handle schemeless strings, so we try to be - * smart and add http if there is no scheme or doesn't look like a mail - * address. This should work in most cases, and let us click on strings - * like "www.gnome.org". +/** empathy_make_absolute_url_len: + * @url: an url + * @len: a length + * + * Same as #empathy_make_absolute_url but for a limited string length */ -static gchar * -fixup_url (const gchar *url) +gchar * +empathy_make_absolute_url_len (const gchar *url, + guint len) { + g_return_val_if_fail (url != NULL, NULL); + if (g_str_has_prefix (url, "ghelp:") || g_str_has_prefix (url, "mailto:") || strstr (url, ":/")) { - return NULL; + return g_strndup (url, len); } if (strstr (url, "@")) { - return g_strdup_printf ("mailto:%s", url); + return g_strdup_printf ("mailto:%.*s", len, url); } - return g_strdup_printf ("http://%s", url); + return g_strdup_printf ("http://%.*s", len, url); +} + +/** empathy_make_absolute_url: + * @url: an url + * + * The URL opening code can't handle schemeless strings, so we try to be + * smart and add http if there is no scheme or doesn't look like a mail + * address. This should work in most cases, and let us click on strings + * like "www.gnome.org". + * + * Returns: a newly allocated url with proper mailto: or http:// prefix, use + * g_free when your are done with it + */ +gchar * +empathy_make_absolute_url (const gchar *url) +{ + return empathy_make_absolute_url_len (url, strlen (url)); } void @@ -1361,12 +1485,12 @@ empathy_url_show (GtkWidget *parent, gchar *real_url; GError *error = NULL; - real_url = fixup_url (url); - if (real_url) { - url = real_url; - } + g_return_if_fail (parent == NULL || GTK_IS_WIDGET (parent)); + g_return_if_fail (url != NULL); + + real_url = empathy_make_absolute_url (url); - gtk_show_uri (gtk_widget_get_screen (parent), url, + gtk_show_uri (parent ? gtk_widget_get_screen (parent) : NULL, real_url, gtk_get_current_event_time (), &error); if (error) { @@ -1412,16 +1536,55 @@ empathy_link_button_new (const gchar *url, } void -empathy_toggle_button_set_state_quietly (GtkWidget *widget, - GCallback callback, - gpointer user_data, - gboolean active) +empathy_send_file (EmpathyContact *contact, GFile *file) +{ + EmpathyFTFactory *factory; + GtkRecentManager *manager; + gchar *uri; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + g_return_if_fail (G_IS_FILE (file)); + + factory = empathy_ft_factory_dup_singleton (); + + empathy_ft_factory_new_transfer_outgoing (factory, contact, file); + + uri = g_file_get_uri (file); + manager = gtk_recent_manager_get_default (); + gtk_recent_manager_add_item (manager, uri); + g_free (uri); + + g_object_unref (factory); +} + +void +empathy_send_file_from_uri_list (EmpathyContact *contact, const gchar *uri_list) { - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget)); + const gchar *nl; + GFile *file; + + /* Only handle a single file for now. It would be wicked cool to be + able to do multiple files, offering to zip them or whatever like + nautilus-sendto does. Note that text/uri-list is defined to have + each line terminated by \r\n, but we can be tolerant of applications + that only use \n or don't terminate single-line entries. + */ + nl = strstr (uri_list, "\r\n"); + if (!nl) { + nl = strchr (uri_list, '\n'); + } + if (nl) { + gchar *uri = g_strndup (uri_list, nl - uri_list); + file = g_file_new_for_uri (uri); + g_free (uri); + } + else { + file = g_file_new_for_uri (uri_list); + } + + empathy_send_file (contact, file); - g_signal_handlers_block_by_func (widget, callback, user_data); - g_object_set (widget, "active", active, NULL); - g_signal_handlers_unblock_by_func (widget, callback, user_data); + g_object_unref (file); } static void @@ -1429,25 +1592,13 @@ file_manager_send_file_response_cb (GtkDialog *widget, gint response_id, EmpathyContact *contact) { - EmpathyFTFactory *factory; GFile *file; - gchar *uri; - GtkRecentManager *manager; if (response_id == GTK_RESPONSE_OK) { file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (widget)); - uri = g_file_get_uri (file); - - factory = empathy_ft_factory_dup_singleton (); - - empathy_ft_factory_new_transfer_outgoing (factory, contact, - file); - manager = gtk_recent_manager_get_default (); - gtk_recent_manager_add_item (manager, uri); + empathy_send_file (contact, file); - g_free (uri); - g_object_unref (factory); g_object_unref (file); } @@ -1479,10 +1630,15 @@ empathy_send_file_with_file_chooser (EmpathyContact *contact) gtk_widget_show (button); gtk_dialog_add_action_widget (GTK_DIALOG (widget), button, GTK_RESPONSE_OK); - GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_set_can_default (button, TRUE); gtk_dialog_set_default_response (GTK_DIALOG (widget), GTK_RESPONSE_OK); + gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), FALSE); + + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (widget), + g_get_home_dir ()); + g_signal_connect (widget, "response", G_CALLBACK (file_manager_send_file_response_cb), contact); @@ -1521,6 +1677,7 @@ void empathy_receive_file_with_file_chooser (EmpathyFTHandler *handler) { GtkWidget *widget; + const gchar *dir; widget = gtk_file_chooser_dialog_new (_("Select a destination"), NULL, @@ -1535,8 +1692,16 @@ empathy_receive_file_with_file_chooser (EmpathyFTHandler *handler) gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (widget), TRUE); + dir = g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD); + if (dir == NULL) + /* Fallback to $HOME if $XDG_DOWNLOAD_DIR is not set */ + dir = g_get_home_dir (); + + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (widget), dir); + g_signal_connect (widget, "response", G_CALLBACK (file_manager_receive_file_response_cb), handler); gtk_widget_show (widget); -} \ No newline at end of file +} +