G_CALLBACK (pixbuf_from_avatar_size_prepared_cb),
&data);
- if (!gdk_pixbuf_loader_write (loader, avatar->data, avatar->len, &error)) {
+ if (avatar->len == 0) {
+ g_warning ("Avatar has 0 length");
+ return NULL;
+ } else if (!gdk_pixbuf_loader_write (loader, avatar->data, avatar->len, &error)) {
g_warning ("Couldn't write avatar image:%p with "
"length:%" G_GSIZE_FORMAT " to pixbuf loader: %s",
avatar->data, avatar->len, error->message);
GSimpleAsyncResult *result;
guint width;
guint height;
+ struct SizeData size_data;
+ GdkPixbufLoader *loader;
+ GCancellable *cancellable;
+ guint8 data[512];
} PixbufAvatarFromIndividualClosure;
static PixbufAvatarFromIndividualClosure *
pixbuf_avatar_from_individual_closure_new (FolksIndividual *individual,
GSimpleAsyncResult *result,
gint width,
- gint height)
+ gint height,
+ GCancellable *cancellable)
{
PixbufAvatarFromIndividualClosure *closure;
closure->result = g_object_ref (result);
closure->width = width;
closure->height = height;
+ if (cancellable != NULL)
+ closure->cancellable = g_object_ref (cancellable);
return closure;
}
pixbuf_avatar_from_individual_closure_free (
PixbufAvatarFromIndividualClosure *closure)
{
+ g_clear_object (&closure->cancellable);
+ tp_clear_object (&closure->loader);
g_object_unref (closure->individual);
g_object_unref (closure->result);
g_free (closure);
}
static void
-avatar_file_load_contents_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
+avatar_icon_load_close_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GFile *file = G_FILE (object);
- PixbufAvatarFromIndividualClosure *closure = user_data;
- char *data = NULL;
- gsize data_size;
- struct SizeData size_data;
GError *error = NULL;
- GdkPixbufLoader *loader = NULL;
- if (!g_file_load_contents_finish (file, result, &data, &data_size,
- NULL, &error)) {
- DEBUG ("failed to load avatar from file: %s",
- error->message);
- g_simple_async_result_set_from_error (closure->result, error);
- goto out;
- }
+ g_input_stream_close_finish (G_INPUT_STREAM (object), result, &error);
- size_data.width = closure->width;
- size_data.height = closure->height;
- size_data.preserve_aspect_ratio = TRUE;
+ if (error != NULL) {
+ DEBUG ("Failed to close pixbuf stream: %s", error->message);
+ g_error_free (error);
+ }
+}
- loader = gdk_pixbuf_loader_new ();
+static void
+avatar_icon_load_read_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GInputStream *stream = G_INPUT_STREAM (object);
+ PixbufAvatarFromIndividualClosure *closure = user_data;
+ gssize n_read;
+ GError *error = NULL;
- g_signal_connect (loader, "size-prepared",
- G_CALLBACK (pixbuf_from_avatar_size_prepared_cb),
- &size_data);
+ /* Finish reading this chunk from the stream */
+ n_read = g_input_stream_read_finish (stream, result, &error);
+ if (error != NULL) {
+ DEBUG ("Failed to finish read from pixbuf stream: %s",
+ error->message);
+ g_simple_async_result_set_from_error (closure->result, error);
+ goto out_close;
+ }
- if (!gdk_pixbuf_loader_write (loader, (guchar *) data, data_size,
- &error)) {
+ /* Write the chunk to the pixbuf loader */
+ if (!gdk_pixbuf_loader_write (closure->loader, (guchar *) closure->data,
+ n_read, &error)) {
DEBUG ("Failed to write to pixbuf loader: %s",
error ? error->message : "No error given");
g_simple_async_result_set_from_error (closure->result, error);
+ goto out_close;
+ }
+
+ if (n_read == 0) {
+ /* EOF? */
+ if (!gdk_pixbuf_loader_close (closure->loader, &error)) {
+ DEBUG ("Failed to close pixbuf loader: %s",
+ error ? error->message : "No error given");
+ g_simple_async_result_set_from_error (closure->result, error);
+ goto out;
+ }
+
+ /* We're done. */
+ g_simple_async_result_set_op_res_gpointer (closure->result,
+ avatar_pixbuf_from_loader (closure->loader),
+ g_object_unref);
+
goto out;
+ } else {
+ /* Loop round and read another chunk. */
+ g_input_stream_read_async (stream, closure->data,
+ G_N_ELEMENTS (closure->data),
+ G_PRIORITY_DEFAULT, closure->cancellable,
+ avatar_icon_load_read_cb, closure);
+
+ return;
}
- if (!gdk_pixbuf_loader_close (loader, &error)) {
- DEBUG ("Failed to close pixbuf loader: %s",
- error ? error->message : "No error given");
+
+out_close:
+ /* We must close the pixbuf loader before unreffing it. */
+ gdk_pixbuf_loader_close (closure->loader, NULL);
+
+out:
+ /* Close the file for safety (even though it should be
+ * automatically closed when the stream is finalised). */
+ g_input_stream_close_async (stream, G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback) avatar_icon_load_close_cb, NULL);
+
+ g_simple_async_result_complete (closure->result);
+
+ g_clear_error (&error);
+ pixbuf_avatar_from_individual_closure_free (closure);
+}
+
+static void
+avatar_icon_load_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GLoadableIcon *icon = G_LOADABLE_ICON (object);
+ PixbufAvatarFromIndividualClosure *closure = user_data;
+ GInputStream *stream;
+ GError *error = NULL;
+
+ stream = g_loadable_icon_load_finish (icon, result, NULL, &error);
+ if (error != NULL) {
+ DEBUG ("Failed to open avatar stream: %s", error->message);
g_simple_async_result_set_from_error (closure->result, error);
goto out;
}
- g_simple_async_result_set_op_res_gpointer (closure->result,
- avatar_pixbuf_from_loader (loader), g_object_unref);
+ closure->size_data.width = closure->width;
+ closure->size_data.height = closure->height;
+ closure->size_data.preserve_aspect_ratio = TRUE;
+
+ /* Load the data into a pixbuf loader in chunks. */
+ closure->loader = gdk_pixbuf_loader_new ();
+
+ g_signal_connect (closure->loader, "size-prepared",
+ G_CALLBACK (pixbuf_from_avatar_size_prepared_cb),
+ &(closure->size_data));
+
+ /* Begin to read the first chunk. */
+ g_input_stream_read_async (stream, closure->data,
+ G_N_ELEMENTS (closure->data),
+ G_PRIORITY_DEFAULT, closure->cancellable,
+ avatar_icon_load_read_cb, closure);
+
+ g_object_unref (stream);
+
+ return;
out:
g_simple_async_result_complete (closure->result);
g_clear_error (&error);
- g_free (data);
- tp_clear_object (&loader);
+ tp_clear_object (&stream);
pixbuf_avatar_from_individual_closure_free (closure);
}
GAsyncReadyCallback callback,
gpointer user_data)
{
- GFile *avatar_file;
+ GLoadableIcon *avatar_icon;
GSimpleAsyncResult *result;
PixbufAvatarFromIndividualClosure *closure;
callback, user_data,
empathy_pixbuf_avatar_from_individual_scaled_async);
- avatar_file =
+ avatar_icon =
folks_avatar_details_get_avatar (FOLKS_AVATAR_DETAILS (individual));
- if (avatar_file == NULL)
- goto out;
+ if (avatar_icon == NULL) {
+ g_simple_async_result_set_error (result, TP_ERRORS,
+ TP_ERROR_INVALID_ARGUMENT, "no avatar found");
+
+ g_simple_async_result_complete (result);
+ g_object_unref (result);
+ return;
+ }
closure = pixbuf_avatar_from_individual_closure_new (individual, result,
- width, height);
- if (closure == NULL)
- goto out;
+ width, height,
+ cancellable);
- g_file_load_contents_async (avatar_file, cancellable,
- avatar_file_load_contents_cb, closure);
+ g_return_if_fail (closure != NULL);
- g_object_unref (result);
+ g_loadable_icon_load_async (avatar_icon, width, cancellable,
+ avatar_icon_load_cb, closure);
- return;
-
-out:
- g_simple_async_result_set_op_res_gpointer (result, NULL, NULL);
- g_simple_async_result_complete (result);
g_object_unref (result);
}
}
icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, size, 0);
+ if (icon_info == NULL)
+ return NULL;
+
ret = g_strdup (gtk_icon_info_get_filename (icon_info));
gtk_icon_info_free (icon_info);
factory = empathy_ft_factory_dup_singleton ();
- empathy_ft_factory_new_transfer_outgoing (factory, contact, file);
+ empathy_ft_factory_new_transfer_outgoing (factory, contact, file,
+ empathy_get_current_action_time ());
uri = g_file_get_uri (file);
manager = gtk_recent_manager_get_default ();
gtk_widget_destroy (GTK_WIDGET (widget));
}
+static gboolean
+filter_cb (const GtkFileFilterInfo *filter_info,
+ gpointer data)
+{
+ /* filter out socket files */
+ return tp_strdiff (filter_info->mime_type, "inode/socket");
+}
+
+static GtkFileFilter *
+create_file_filter (void)
+{
+ GtkFileFilter *filter;
+
+ filter = gtk_file_filter_new ();
+
+ gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_MIME_TYPE, filter_cb,
+ NULL, NULL);
+
+ return filter;
+}
+
void
empathy_send_file_with_file_chooser (EmpathyContact *contact)
{
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (widget),
g_get_home_dir ());
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget),
+ create_file_filter ());
+
g_signal_connect (widget, "response",
G_CALLBACK (file_manager_send_file_response_cb),
g_object_ref (contact));
_("Insufficient free space to save file"));
char *file_size_str, *free_space_str;
- file_size_str = g_format_size_for_display (file_size);
- free_space_str = g_format_size_for_display (free_space);
+ file_size_str = g_format_size (file_size);
+ free_space_str = g_format_size (free_space);
gtk_message_dialog_format_secondary_text (
GTK_MESSAGE_DIALOG (message),
return retval;
}
-GtkWidget *
-empathy_create_dtmf_dialpad (GObject *self,
- GCallback dtmf_button_pressed_cb,
- GCallback dtmf_button_released_cb)
-{
- GtkWidget *table;
- int i;
- GQuark button_quark;
- struct {
- const gchar *label;
- const gchar *sublabel;
- TpDTMFEvent event;
- } dtmfbuttons[] = { { "1", "", TP_DTMF_EVENT_DIGIT_1 },
- { "2", "abc", TP_DTMF_EVENT_DIGIT_2 },
- { "3", "def", TP_DTMF_EVENT_DIGIT_3 },
- { "4", "ghi", TP_DTMF_EVENT_DIGIT_4 },
- { "5", "jkl", TP_DTMF_EVENT_DIGIT_5 },
- { "6", "mno", TP_DTMF_EVENT_DIGIT_6 },
- { "7", "pqrs", TP_DTMF_EVENT_DIGIT_7 },
- { "8", "tuv", TP_DTMF_EVENT_DIGIT_8 },
- { "9", "wxyz", TP_DTMF_EVENT_DIGIT_9 },
- { "#", "", TP_DTMF_EVENT_HASH },
- { "0", "", TP_DTMF_EVENT_DIGIT_0 },
- { "*", "", TP_DTMF_EVENT_ASTERISK },
- { NULL, } };
-
- button_quark = g_quark_from_static_string (EMPATHY_DTMF_BUTTON_ID);
-
- table = gtk_table_new (4, 3, TRUE);
-
- for (i = 0; dtmfbuttons[i].label != NULL; i++)
+void
+empathy_launch_program (const gchar *dir,
+ const gchar *name,
+ const gchar *args)
+{
+ GdkDisplay *display;
+ GError *error = NULL;
+ gchar *path, *cmd;
+ GAppInfo *app_info;
+ GdkAppLaunchContext *context = NULL;
+
+ /* Try to run from source directory if possible */
+ path = g_build_filename (g_getenv ("EMPATHY_SRCDIR"), "src",
+ name, NULL);
+
+ if (!g_file_test (path, G_FILE_TEST_EXISTS))
+ {
+ g_free (path);
+ path = g_build_filename (dir, name, NULL);
+ }
+
+ if (args != NULL)
+ cmd = g_strconcat (path, " ", args, NULL);
+ else
+ cmd = g_strdup (path);
+
+ app_info = g_app_info_create_from_commandline (cmd, NULL, 0, &error);
+ if (app_info == NULL)
+ {
+ DEBUG ("Failed to create app info: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ display = gdk_display_get_default ();
+ context = gdk_display_get_app_launch_context (display);
+
+ if (!g_app_info_launch (app_info, NULL, (GAppLaunchContext *) context,
+ &error))
{
- GtkWidget *vbox = gtk_vbox_new (FALSE, 0);
- GtkWidget *button = gtk_button_new ();
- GtkWidget *label;
- gchar *str;
-
- gtk_container_add (GTK_CONTAINER (button), vbox);
-
- /* main label */
- label = gtk_label_new ("");
- str = g_strdup_printf ("<span size='x-large'>%s</span>",
- dtmfbuttons[i].label);
- gtk_label_set_markup (GTK_LABEL (label), str);
- g_free (str);
-
- gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 3);
-
- /* sub label */
- label = gtk_label_new ("");
- str = g_strdup_printf (
- "<span foreground='#555555'>%s</span>",
- dtmfbuttons[i].sublabel);
- gtk_label_set_markup (GTK_LABEL (label), str);
- g_free (str);
-
- gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
-
- gtk_table_attach (GTK_TABLE (table), button, i % 3, i % 3 + 1,
- i/3, i/3 + 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 1, 1);
-
- g_object_set_qdata (G_OBJECT (button), button_quark,
- GUINT_TO_POINTER (dtmfbuttons[i].event));
-
- g_signal_connect (G_OBJECT (button), "pressed",
- dtmf_button_pressed_cb, self);
- g_signal_connect (G_OBJECT (button), "released",
- dtmf_button_released_cb, self);
+ g_warning ("Failed to launch %s: %s", name, error->message);
+ g_error_free (error);
+ goto out;
}
- return table;
+out:
+ tp_clear_object (&app_info);
+ tp_clear_object (&context);
+ g_free (path);
+ g_free (cmd);
+}
+
+/* Most of the workspace manipulation code has been copied from libwnck
+ * Copyright (C) 2001 Havoc Pennington
+ * Copyright (C) 2005-2007 Vincent Untz
+ */
+static void
+_wnck_activate_workspace (Screen *screen,
+ int new_active_space,
+ Time timestamp)
+{
+ Display *display;
+ Window root;
+ XEvent xev;
+
+ display = DisplayOfScreen (screen);
+ root = RootWindowOfScreen (screen);
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = display;
+ xev.xclient.window = root;
+ xev.xclient.message_type = gdk_x11_get_xatom_by_name ("_NET_CURRENT_DESKTOP");
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = new_active_space;
+ xev.xclient.data.l[1] = timestamp;
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+
+ gdk_error_trap_push ();
+ XSendEvent (display, root, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+ XSync (display, False);
+ gdk_error_trap_pop_ignored ();
+}
+
+static gboolean
+_wnck_get_cardinal (Screen *screen,
+ Window xwindow,
+ Atom atom,
+ int *val)
+{
+ Display *display;
+ Atom type;
+ int format;
+ gulong nitems;
+ gulong bytes_after;
+ gulong *num;
+ int err, result;
+
+ display = DisplayOfScreen (screen);
+
+ *val = 0;
+
+ gdk_error_trap_push ();
+ type = None;
+ result = XGetWindowProperty (display, xwindow, atom,
+ 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, (void *) &num);
+ err = gdk_error_trap_pop ();
+ if (err != Success ||
+ result != Success)
+ return FALSE;
+
+ if (type != XA_CARDINAL)
+ {
+ XFree (num);
+ return FALSE;
+ }
+
+ *val = *num;
+
+ XFree (num);
+
+ return TRUE;
+}
+
+static int
+window_get_workspace (Screen *xscreen,
+ Window win)
+{
+ int number;
+
+ if (!_wnck_get_cardinal (xscreen, win,
+ gdk_x11_get_xatom_by_name ("_NET_WM_DESKTOP"), &number))
+ return -1;
+
+ return number;
+}
+
+/* Ask X to move to the desktop on which @window currently is
+ * and the present @window. */
+void
+empathy_move_to_window_desktop (GtkWindow *window,
+ guint32 timestamp)
+{
+ GdkScreen *screen;
+ Screen *xscreen;
+ GdkWindow *gdk_window;
+ int workspace;
+
+ screen = gtk_window_get_screen (window);
+ xscreen = gdk_x11_screen_get_xscreen (screen);
+ gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
+
+ workspace = window_get_workspace (xscreen,
+ gdk_x11_window_get_xid (gdk_window));
+ if (workspace == -1)
+ goto out;
+
+ _wnck_activate_workspace (xscreen, workspace, timestamp);
+
+out:
+ gtk_window_present_with_time (window, timestamp);
}