| 43 PROP_CONVERSATION, |
43 PROP_CONVERSATION, |
| 44 N_PROPERTIES, |
44 N_PROPERTIES, |
| 45 }; |
45 }; |
| 46 static GParamSpec *properties[N_PROPERTIES] = {NULL, }; |
46 static GParamSpec *properties[N_PROPERTIES] = {NULL, }; |
| 47 |
47 |
| 48 G_DEFINE_TYPE(PidginAvatar, pidgin_avatar, GTK_TYPE_EVENT_BOX) |
48 G_DEFINE_TYPE(PidginAvatar, pidgin_avatar, GTK_TYPE_BOX) |
| 49 |
49 |
| 50 /****************************************************************************** |
50 /****************************************************************************** |
| 51 * Actions |
51 * Actions |
| 52 *****************************************************************************/ |
52 *****************************************************************************/ |
| 53 static void |
53 static void |
| 65 |
65 |
| 66 icon = purple_buddy_get_icon(avatar->buddy); |
66 icon = purple_buddy_get_icon(avatar->buddy); |
| 67 |
67 |
| 68 if(icon != NULL) { |
68 if(icon != NULL) { |
| 69 GtkFileChooser *chooser = GTK_FILE_CHOOSER(native); |
69 GtkFileChooser *chooser = GTK_FILE_CHOOSER(native); |
| |
70 GFile *file = NULL; |
| 70 gchar *filename = NULL; |
71 gchar *filename = NULL; |
| 71 |
72 |
| 72 filename = gtk_file_chooser_get_filename(chooser); |
73 file = gtk_file_chooser_get_file(chooser); |
| |
74 filename = g_file_get_path(file); |
| 73 |
75 |
| 74 purple_buddy_icon_save_to_filename(icon, filename, NULL); |
76 purple_buddy_icon_save_to_filename(icon, filename, NULL); |
| 75 |
77 |
| 76 g_free(filename); |
78 g_free(filename); |
| 77 } |
79 } |
| 97 |
99 |
| 98 account = purple_buddy_get_account(avatar->buddy); |
100 account = purple_buddy_get_account(avatar->buddy); |
| 99 name = purple_buddy_get_name(avatar->buddy); |
101 name = purple_buddy_get_name(avatar->buddy); |
| 100 filename = g_strdup_printf("%s.%s", purple_normalize(account, name), ext); |
102 filename = g_strdup_printf("%s.%s", purple_normalize(account, name), ext); |
| 101 |
103 |
| 102 window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(avatar))); |
104 window = GTK_WINDOW(gtk_widget_get_root(GTK_WIDGET(avatar))); |
| 103 native = gtk_file_chooser_native_new(_("Save Avatar"), |
105 native = gtk_file_chooser_native_new(_("Save Avatar"), |
| 104 window, |
106 window, |
| 105 GTK_FILE_CHOOSER_ACTION_SAVE, |
107 GTK_FILE_CHOOSER_ACTION_SAVE, |
| 106 _("_Save"), |
108 _("_Save"), |
| 107 _("_Cancel")); |
109 _("_Cancel")); |
| 108 g_signal_connect(G_OBJECT(native), "response", |
110 g_signal_connect(G_OBJECT(native), "response", |
| 109 G_CALLBACK(pidgin_avatar_save_response_cb), avatar); |
111 G_CALLBACK(pidgin_avatar_save_response_cb), avatar); |
| 110 |
112 |
| 111 chooser = GTK_FILE_CHOOSER(native); |
113 chooser = GTK_FILE_CHOOSER(native); |
| 112 |
114 |
| 113 gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE); |
115 gtk_file_chooser_set_current_name(chooser, filename); |
| 114 gtk_file_chooser_set_filename(chooser, filename); |
|
| 115 g_free(filename); |
116 g_free(filename); |
| 116 |
117 |
| 117 gtk_native_dialog_show(GTK_NATIVE_DIALOG(native)); |
118 gtk_native_dialog_show(GTK_NATIVE_DIALOG(native)); |
| 118 } |
119 } |
| 119 |
120 |
| 121 pidgin_avatar_set_custom_response_cb(GtkNativeDialog *native, gint response, |
122 pidgin_avatar_set_custom_response_cb(GtkNativeDialog *native, gint response, |
| 122 gpointer data) |
123 gpointer data) |
| 123 { |
124 { |
| 124 PidginAvatar *avatar = PIDGIN_AVATAR(data); |
125 PidginAvatar *avatar = PIDGIN_AVATAR(data); |
| 125 GtkFileChooser *chooser = GTK_FILE_CHOOSER(native); |
126 GtkFileChooser *chooser = GTK_FILE_CHOOSER(native); |
| |
127 GFile *file = NULL; |
| 126 gchar *filename = NULL; |
128 gchar *filename = NULL; |
| 127 |
129 |
| 128 if(response != GTK_RESPONSE_ACCEPT || !PURPLE_IS_BUDDY(avatar->buddy)) { |
130 if(response != GTK_RESPONSE_ACCEPT || !PURPLE_IS_BUDDY(avatar->buddy)) { |
| 129 gtk_native_dialog_destroy(native); |
131 gtk_native_dialog_destroy(native); |
| 130 |
132 |
| 131 return; |
133 return; |
| 132 } |
134 } |
| 133 |
135 |
| 134 filename = gtk_file_chooser_get_filename(chooser); |
136 file = gtk_file_chooser_get_file(chooser); |
| |
137 filename = g_file_get_path(file); |
| 135 if(filename != NULL) { |
138 if(filename != NULL) { |
| 136 PurpleContact *contact = purple_buddy_get_contact(avatar->buddy); |
139 PurpleContact *contact = purple_buddy_get_contact(avatar->buddy); |
| 137 PurpleBlistNode *node = PURPLE_BLIST_NODE(contact); |
140 PurpleBlistNode *node = PURPLE_BLIST_NODE(contact); |
| 138 |
141 |
| 139 purple_buddy_icons_node_set_custom_icon_from_file(node, filename); |
142 purple_buddy_icons_node_set_custom_icon_from_file(node, filename); |
| 148 { |
151 { |
| 149 PidginAvatar *avatar = PIDGIN_AVATAR(data); |
152 PidginAvatar *avatar = PIDGIN_AVATAR(data); |
| 150 GtkFileChooserNative *native = NULL; |
153 GtkFileChooserNative *native = NULL; |
| 151 GtkWindow *window = NULL; |
154 GtkWindow *window = NULL; |
| 152 |
155 |
| 153 window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(avatar))); |
156 window = GTK_WINDOW(gtk_widget_get_root(GTK_WIDGET(avatar))); |
| 154 native = gtk_file_chooser_native_new(_("Set Custom Avatar"), |
157 native = gtk_file_chooser_native_new(_("Set Custom Avatar"), |
| 155 window, |
158 window, |
| 156 GTK_FILE_CHOOSER_ACTION_OPEN, |
159 GTK_FILE_CHOOSER_ACTION_OPEN, |
| 157 _("_Set Custom"), |
160 _("_Set Custom"), |
| 158 _("_Cancel")); |
161 _("_Cancel")); |
| 273 |
276 |
| 274 g_set_object(&avatar->animation, animation); |
277 g_set_object(&avatar->animation, animation); |
| 275 |
278 |
| 276 if(GDK_IS_PIXBUF_ANIMATION(avatar->animation)) { |
279 if(GDK_IS_PIXBUF_ANIMATION(avatar->animation)) { |
| 277 if(avatar->animate) { |
280 if(avatar->animate) { |
| 278 gtk_image_set_from_animation(GTK_IMAGE(avatar->icon), |
281 gtk_image_set_from_pixbuf(GTK_IMAGE(avatar->icon), |
| 279 avatar->animation); |
282 GDK_PIXBUF(avatar->animation)); |
| 280 } else { |
283 } else { |
| 281 GdkPixbuf *frame = NULL; |
284 GdkPixbuf *frame = NULL; |
| 282 |
285 |
| 283 frame = gdk_pixbuf_animation_get_static_image(avatar->animation); |
286 frame = gdk_pixbuf_animation_get_static_image(avatar->animation); |
| 284 |
287 |
| 293 |
296 |
| 294 /****************************************************************************** |
297 /****************************************************************************** |
| 295 * Callbacks |
298 * Callbacks |
| 296 *****************************************************************************/ |
299 *****************************************************************************/ |
| 297 static gboolean |
300 static gboolean |
| 298 pidgin_avatar_button_press_handler(GtkWidget *widget, GdkEventButton *event, |
301 pidgin_avatar_button_press_handler(G_GNUC_UNUSED GtkGestureClick *event, |
| |
302 G_GNUC_UNUSED gint n_press, |
| |
303 gdouble x, |
| |
304 gdouble y, |
| 299 gpointer data) |
305 gpointer data) |
| 300 { |
306 { |
| 301 PidginAvatar *avatar = PIDGIN_AVATAR(data); |
307 PidginAvatar *avatar = PIDGIN_AVATAR(data); |
| 302 GtkBuilder *builder = NULL; |
308 GtkBuilder *builder = NULL; |
| 303 GtkWidget *menu = NULL; |
309 GtkWidget *menu = NULL; |
| 304 GMenuModel *model = NULL; |
310 GMenuModel *model = NULL; |
| 305 |
311 |
| 306 if(!gdk_event_triggers_context_menu((GdkEvent *)event)) { |
|
| 307 return FALSE; |
|
| 308 } |
|
| 309 |
|
| 310 builder = gtk_builder_new_from_resource("/im/pidgin/Pidgin3/Avatar/menu.ui"); |
312 builder = gtk_builder_new_from_resource("/im/pidgin/Pidgin3/Avatar/menu.ui"); |
| 311 model = (GMenuModel *)gtk_builder_get_object(builder, "menu"); |
313 model = (GMenuModel *)gtk_builder_get_object(builder, "menu"); |
| 312 |
314 |
| 313 menu = gtk_popover_menu_new(); |
315 menu = gtk_popover_menu_new_from_model(model); |
| 314 gtk_popover_bind_model(GTK_POPOVER(menu), model, NULL); |
316 gtk_widget_set_parent(menu, GTK_WIDGET(avatar)); |
| 315 gtk_popover_set_relative_to(GTK_POPOVER(menu), GTK_WIDGET(avatar)); |
|
| 316 gtk_popover_set_pointing_to(GTK_POPOVER(menu), |
317 gtk_popover_set_pointing_to(GTK_POPOVER(menu), |
| 317 &(const GdkRectangle){(int)event->x, (int)event->y, 0, 0}); |
318 &(const GdkRectangle){(int)x, (int)y, 0, 0}); |
| 318 |
319 |
| 319 g_clear_object(&builder); |
320 g_clear_object(&builder); |
| 320 |
321 |
| 321 gtk_popover_popup(GTK_POPOVER(menu)); |
322 gtk_popover_popup(GTK_POPOVER(menu)); |
| 322 |
323 |
| 349 |
350 |
| 350 pidgin_avatar_update(avatar); |
351 pidgin_avatar_update(avatar); |
| 351 } |
352 } |
| 352 |
353 |
| 353 static gboolean |
354 static gboolean |
| 354 pidgin_avatar_enter_notify_handler(GtkWidget *widget, GdkEvent *event, |
355 pidgin_avatar_enter_notify_handler(G_GNUC_UNUSED GtkEventControllerMotion *event, |
| |
356 G_GNUC_UNUSED gdouble x, |
| |
357 G_GNUC_UNUSED gdouble y, |
| 355 gpointer data) |
358 gpointer data) |
| 356 { |
359 { |
| 357 PidginAvatar *avatar = PIDGIN_AVATAR(widget); |
360 PidginAvatar *avatar = PIDGIN_AVATAR(data); |
| 358 |
361 |
| 359 pidgin_avatar_set_animate(avatar, TRUE); |
362 pidgin_avatar_set_animate(avatar, TRUE); |
| 360 |
363 |
| 361 return FALSE; |
364 return FALSE; |
| 362 } |
365 } |
| 363 |
366 |
| 364 static gboolean |
367 static gboolean |
| 365 pidgin_avatar_leave_notify_handler(GtkWidget *widget, GdkEvent *event, |
368 pidgin_avatar_leave_notify_handler(G_GNUC_UNUSED GtkEventControllerMotion *event, |
| 366 gpointer user_data) |
369 gpointer data) |
| 367 { |
370 { |
| 368 PidginAvatar *avatar = PIDGIN_AVATAR(widget); |
371 PidginAvatar *avatar = PIDGIN_AVATAR(data); |
| 369 |
372 |
| 370 pidgin_avatar_set_animate(avatar, FALSE); |
373 pidgin_avatar_set_animate(avatar, FALSE); |
| 371 |
374 |
| 372 return FALSE; |
375 return FALSE; |
| 373 } |
376 } |
| 525 |
528 |
| 526 avatar->animate = animate; |
529 avatar->animate = animate; |
| 527 |
530 |
| 528 if(GDK_IS_PIXBUF_ANIMATION(avatar->animation)) { |
531 if(GDK_IS_PIXBUF_ANIMATION(avatar->animation)) { |
| 529 if(avatar->animate) { |
532 if(avatar->animate) { |
| 530 gtk_image_set_from_animation(GTK_IMAGE(avatar->icon), |
533 gtk_image_set_from_pixbuf(GTK_IMAGE(avatar->icon), |
| 531 avatar->animation); |
534 GDK_PIXBUF(avatar->animation)); |
| 532 } else { |
535 } else { |
| 533 GdkPixbuf *frame = NULL; |
536 GdkPixbuf *frame = NULL; |
| 534 |
537 |
| 535 frame = gdk_pixbuf_animation_get_static_image(avatar->animation); |
538 frame = gdk_pixbuf_animation_get_static_image(avatar->animation); |
| 536 |
539 |