diff --git a/pidgin/pidginavatar.h b/pidgin/pidginavatar.h
--- a/pidgin/pidginavatar.h
+++ b/pidgin/pidginavatar.h
@@ -45,8 +45,7 @@ G_BEGIN_DECLS
  */
 
 #define PIDGIN_TYPE_AVATAR (pidgin_avatar_get_type())
-G_DECLARE_FINAL_TYPE(PidginAvatar, pidgin_avatar,
-                     PIDGIN, AVATAR, GtkEventBox)
+G_DECLARE_FINAL_TYPE(PidginAvatar, pidgin_avatar, PIDGIN, AVATAR, GtkBox)
 
 /**
  * pidgin_avatar_new:
# HG changeset patch
# Node ID ea94f1ca4f3e
# Parent  701213b11b96
diff --git a/pidgin/pidginavatar.c b/pidgin/pidginavatar.c
--- a/pidgin/pidginavatar.c
+++ b/pidgin/pidginavatar.c
@@ -25,7 +25,7 @@
 #include "pidgin/pidginavatar.h"
 
 struct _PidginAvatar {
-	GtkEventBox parent;
+	GtkBox parent;
 
 	GtkWidget *icon;
 
@@ -45,7 +45,7 @@ enum {
 };
 static GParamSpec *properties[N_PROPERTIES] = {NULL, };
 
-G_DEFINE_TYPE(PidginAvatar, pidgin_avatar, GTK_TYPE_EVENT_BOX)
+G_DEFINE_TYPE(PidginAvatar, pidgin_avatar, GTK_TYPE_BOX)
 
 /******************************************************************************
  * Actions
@@ -67,9 +67,11 @@ pidgin_avatar_save_response_cb(GtkNative
 
 	if(icon != NULL) {
 		GtkFileChooser *chooser = GTK_FILE_CHOOSER(native);
+		GFile *file = NULL;
 		gchar *filename = NULL;
 
-		filename = gtk_file_chooser_get_filename(chooser);
+		file = gtk_file_chooser_get_file(chooser);
+		filename = g_file_get_path(file);
 
 		purple_buddy_icon_save_to_filename(icon, filename, NULL);
 
@@ -99,7 +101,7 @@ pidgin_avatar_save_cb(GSimpleAction *act
 	name = purple_buddy_get_name(avatar->buddy);
 	filename = g_strdup_printf("%s.%s", purple_normalize(account, name), ext);
 
-	window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(avatar)));
+	window = GTK_WINDOW(gtk_widget_get_root(GTK_WIDGET(avatar)));
 	native = gtk_file_chooser_native_new(_("Save Avatar"),
 	                                     window,
 	                                     GTK_FILE_CHOOSER_ACTION_SAVE,
@@ -110,8 +112,7 @@ pidgin_avatar_save_cb(GSimpleAction *act
 
 	chooser = GTK_FILE_CHOOSER(native);
 
-	gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE);
-	gtk_file_chooser_set_filename(chooser, filename);
+	gtk_file_chooser_set_current_name(chooser, filename);
 	g_free(filename);
 
 	gtk_native_dialog_show(GTK_NATIVE_DIALOG(native));
@@ -123,6 +124,7 @@ pidgin_avatar_set_custom_response_cb(Gtk
 {
 	PidginAvatar *avatar = PIDGIN_AVATAR(data);
 	GtkFileChooser *chooser = GTK_FILE_CHOOSER(native);
+	GFile *file = NULL;
 	gchar *filename = NULL;
 
 	if(response != GTK_RESPONSE_ACCEPT || !PURPLE_IS_BUDDY(avatar->buddy)) {
@@ -131,7 +133,8 @@ pidgin_avatar_set_custom_response_cb(Gtk
 		return;
 	}
 
-	filename = gtk_file_chooser_get_filename(chooser);
+	file = gtk_file_chooser_get_file(chooser);
+	filename = g_file_get_path(file);
 	if(filename != NULL) {
 		PurpleContact *contact = purple_buddy_get_contact(avatar->buddy);
 		PurpleBlistNode *node = PURPLE_BLIST_NODE(contact);
@@ -150,7 +153,7 @@ pidgin_avatar_set_custom_cb(GSimpleActio
 	GtkFileChooserNative *native = NULL;
 	GtkWindow *window = NULL;
 
-	window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(avatar)));
+	window = GTK_WINDOW(gtk_widget_get_root(GTK_WIDGET(avatar)));
 	native = gtk_file_chooser_native_new(_("Set Custom Avatar"),
 	                                     window,
 	                                     GTK_FILE_CHOOSER_ACTION_OPEN,
@@ -275,8 +278,8 @@ pidgin_avatar_update(PidginAvatar *avata
 
 	if(GDK_IS_PIXBUF_ANIMATION(avatar->animation)) {
 		if(avatar->animate) {
-			gtk_image_set_from_animation(GTK_IMAGE(avatar->icon),
-			                             avatar->animation);
+			gtk_image_set_from_pixbuf(GTK_IMAGE(avatar->icon),
+			                          GDK_PIXBUF(avatar->animation));
 		} else {
 			GdkPixbuf *frame = NULL;
 
@@ -295,7 +298,10 @@ pidgin_avatar_update(PidginAvatar *avata
  * Callbacks
  *****************************************************************************/
 static gboolean
-pidgin_avatar_button_press_handler(GtkWidget *widget, GdkEventButton *event,
+pidgin_avatar_button_press_handler(G_GNUC_UNUSED GtkGestureClick *event,
+                                   G_GNUC_UNUSED gint n_press,
+                                   gdouble x,
+                                   gdouble y,
                                    gpointer data)
 {
 	PidginAvatar *avatar = PIDGIN_AVATAR(data);
@@ -303,18 +309,13 @@ pidgin_avatar_button_press_handler(GtkWi
 	GtkWidget *menu = NULL;
 	GMenuModel *model = NULL;
 
-	if(!gdk_event_triggers_context_menu((GdkEvent *)event)) {
-		return FALSE;
-	}
-
 	builder = gtk_builder_new_from_resource("/im/pidgin/Pidgin3/Avatar/menu.ui");
 	model = (GMenuModel *)gtk_builder_get_object(builder, "menu");
 
-	menu = gtk_popover_menu_new();
-	gtk_popover_bind_model(GTK_POPOVER(menu), model, NULL);
-	gtk_popover_set_relative_to(GTK_POPOVER(menu), GTK_WIDGET(avatar));
+	menu = gtk_popover_menu_new_from_model(model);
+	gtk_widget_set_parent(menu, GTK_WIDGET(avatar));
 	gtk_popover_set_pointing_to(GTK_POPOVER(menu),
-	                            &(const GdkRectangle){(int)event->x, (int)event->y, 0, 0});
+	                            &(const GdkRectangle){(int)x, (int)y, 0, 0});
 
 	g_clear_object(&builder);
 
@@ -351,10 +352,12 @@ pidgin_avatar_conversation_updated(GObje
 }
 
 static gboolean
-pidgin_avatar_enter_notify_handler(GtkWidget *widget, GdkEvent *event,
+pidgin_avatar_enter_notify_handler(G_GNUC_UNUSED GtkEventControllerMotion *event,
+                                   G_GNUC_UNUSED gdouble x,
+                                   G_GNUC_UNUSED gdouble y,
                                    gpointer data)
 {
-	PidginAvatar *avatar = PIDGIN_AVATAR(widget);
+	PidginAvatar *avatar = PIDGIN_AVATAR(data);
 
 	pidgin_avatar_set_animate(avatar, TRUE);
 
@@ -362,10 +365,10 @@ pidgin_avatar_enter_notify_handler(GtkWi
 }
 
 static gboolean
-pidgin_avatar_leave_notify_handler(GtkWidget *widget, GdkEvent *event,
-                                   gpointer user_data)
+pidgin_avatar_leave_notify_handler(G_GNUC_UNUSED GtkEventControllerMotion *event,
+                                   gpointer data)
 {
-	PidginAvatar *avatar = PIDGIN_AVATAR(widget);
+	PidginAvatar *avatar = PIDGIN_AVATAR(data);
 
 	pidgin_avatar_set_animate(avatar, FALSE);
 
@@ -528,8 +531,8 @@ pidgin_avatar_set_animate(PidginAvatar *
 
 	if(GDK_IS_PIXBUF_ANIMATION(avatar->animation)) {
 		if(avatar->animate) {
-			gtk_image_set_from_animation(GTK_IMAGE(avatar->icon),
-			                             avatar->animation);
+			gtk_image_set_from_pixbuf(GTK_IMAGE(avatar->icon),
+			                          GDK_PIXBUF(avatar->animation));
 		} else {
 			GdkPixbuf *frame = NULL;
 
diff --git a/pidgin/resources/Avatar/avatar.ui b/pidgin/resources/Avatar/avatar.ui
--- a/pidgin/resources/Avatar/avatar.ui
+++ b/pidgin/resources/Avatar/avatar.ui
@@ -20,25 +20,29 @@ Foundation, Inc., 51 Franklin Street, Fi
 
 -->
 <interface>
-  <requires lib="gtk+" version="3.22"/>
+  <requires lib="gtk" version="4.0"/>
   <!-- interface-license-type gplv2 -->
   <!-- interface-name Pidgin -->
   <!-- interface-description Internet Messenger -->
   <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
-  <template class="PidginAvatar" parent="GtkEventBox">
-    <property name="visible">True</property>
-    <property name="can-focus">False</property>
-    <property name="events">GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
-    <signal name="button-press-event" handler="pidgin_avatar_button_press_handler" object="PidginAvatar" swapped="no"/>
-    <signal name="enter-notify-event" handler="pidgin_avatar_enter_notify_handler" swapped="no"/>
-    <signal name="leave-notify-event" handler="pidgin_avatar_leave_notify_handler" swapped="no"/>
+  <template class="PidginAvatar" parent="GtkBox">
     <child>
       <object class="GtkImage" id="icon">
-        <property name="visible">True</property>
-        <property name="can-focus">False</property>
         <property name="icon-name">image-missing</property>
         <property name="icon_size">3</property>
       </object>
     </child>
+    <child>
+      <object class="GtkGestureClick">
+        <property name="button">3</property>
+        <signal name="pressed" handler="pidgin_avatar_button_press_handler" object="PidginAvatar" swapped="no"/>
+      </object>
+    </child>
+    <child>
+      <object class="GtkEventControllerMotion">
+        <signal name="enter" handler="pidgin_avatar_enter_notify_handler" object="PidginAvatar" swapped="no"/>
+        <signal name="leave" handler="pidgin_avatar_leave_notify_handler" object="PidginAvatar" swapped="no"/>
+      </object>
+    </child>
   </template>
 </interface>
diff --git a/pidgin/resources/Avatar/menu.ui b/pidgin/resources/Avatar/menu.ui
--- a/pidgin/resources/Avatar/menu.ui
+++ b/pidgin/resources/Avatar/menu.ui
@@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fi
 
 -->
 <interface>
-  <requires lib="gtk+" version="3.22"/>
+  <requires lib="gtk" version="4.0"/>
   <!-- interface-license-type gplv2 -->
   <!-- interface-name Pidgin -->
   <!-- interface-description Internet Messenger -->
