# HG changeset patch
# Node ID d76125944b07
# Parent  04a97e6730d2
diff --git a/ChangeLog.API b/ChangeLog.API
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -1059,6 +1059,7 @@
 		* pidgin_dialog_get_vbox_with_properties
 		* pidgin_dialogs_alias_contact
 		* pidgin_dialogs_destroy_all
+		* pidgin_dialogs_im
 		* pidgin_dialogs_log
 		* pidgin_dialogs_merge_groups
 		* pidgin_dialogs_remove_buddy
diff --git a/pidgin/gtkdialogs.h b/pidgin/gtkdialogs.h
--- a/pidgin/gtkdialogs.h
+++ b/pidgin/gtkdialogs.h
@@ -33,9 +33,6 @@
 G_BEGIN_DECLS
 
 PIDGIN_AVAILABLE_IN_ALL
-void pidgin_dialogs_im(void);
-
-PIDGIN_AVAILABLE_IN_ALL
 void pidgin_dialogs_im_with_user(PurpleAccount *account, const char *username);
 
 PIDGIN_AVAILABLE_IN_ALL
diff --git a/pidgin/gtkdialogs.c b/pidgin/gtkdialogs.c
--- a/pidgin/gtkdialogs.c
+++ b/pidgin/gtkdialogs.c
@@ -33,81 +33,6 @@
 #include "gtkutils.h"
 #include "pidgincore.h"
 
-static void
-pidgin_dialogs_im_cb(G_GNUC_UNUSED gpointer data, PurpleRequestPage *page) {
-	PurpleAccount *account;
-	const char *username;
-
-	account = purple_request_page_get_account(page, "account");
-	username = purple_request_page_get_string(page,  "screenname");
-
-	pidgin_dialogs_im_with_user(account, username);
-}
-
-static gboolean
-pidgin_dialogs_im_name_validator(PurpleRequestField *field, char **errmsg,
-                                 gpointer data)
-{
-	PurpleRequestFieldAccount *account_field = data;
-	PurpleAccount *account;
-	PurpleProtocol *protocol;
-	const char *username;
-	gboolean valid = FALSE;
-
-	account = purple_request_field_account_get_value(account_field);
-	protocol = purple_account_get_protocol(account);
-	username = purple_request_field_string_get_value(PURPLE_REQUEST_FIELD_STRING(field));
-
-	if (username) {
-		valid = purple_validate(protocol, username);
-	}
-
-	if (errmsg && !valid)
-		*errmsg = g_strdup(_("Invalid username"));
-
-	return valid;
-}
-
-void
-pidgin_dialogs_im(void)
-{
-	PurpleRequestPage *page;
-	PurpleRequestGroup *group;
-	PurpleRequestField *username_field = NULL;
-	PurpleRequestField *account_field = NULL;
-
-	page = purple_request_page_new();
-
-	group = purple_request_group_new(NULL);
-	purple_request_page_add_group(page, group);
-
-	account_field = purple_request_field_account_new("account", _("_Account"),
-	                                                 NULL);
-	purple_request_field_set_type_hint(account_field, "account");
-	purple_request_field_set_visible(account_field,
-		(purple_connections_get_all() != NULL &&
-		 purple_connections_get_all()->next != NULL));
-	purple_request_field_set_required(account_field, TRUE);
-	purple_request_group_add_field(group, account_field);
-
-	purple_request_field_set_validator(username_field,
-	                                   pidgin_dialogs_im_name_validator,
-	                                   account_field, NULL);
-
-	username_field = purple_request_field_string_new("screenname", _("_Name"),
-	                                                 NULL, FALSE);
-	purple_request_field_set_type_hint(username_field, "screenname");
-	purple_request_field_set_required(username_field, TRUE);
-	purple_request_group_add_field(group, username_field);
-
-	purple_request_fields(
-	        purple_blist_get_default(), _("New Instant Message"), NULL,
-	        _("Please enter the username or alias of the person "
-	          "you would like to IM."),
-	        page, _("OK"), G_CALLBACK(pidgin_dialogs_im_cb), _("Cancel"),
-	        NULL, NULL, NULL);
-}
-
 void
 pidgin_dialogs_im_with_user(PurpleAccount *account, const char *username)
 {
diff --git a/pidgin/meson.build b/pidgin/meson.build
--- a/pidgin/meson.build
+++ b/pidgin/meson.build
@@ -41,6 +41,7 @@
 	'pidgindisplayitem.c',
 	'pidgindisplaywindow.c',
 	'pidginiconname.c',
+	'pidginimwindow.c',
 	'pidgininfopane.c',
 	'pidgininvitedialog.c',
 	'pidginkeypad.c',
@@ -102,6 +103,7 @@
 	'pidgindisplaywindow.h',
 	'pidgindebug.h',
 	'pidginiconname.h',
+	'pidginimwindow.h',
 	'pidgininfopane.h',
 	'pidgininvitedialog.h',
 	'pidginkeypad.h',
diff --git a/pidgin/pidginapplication.c b/pidgin/pidginapplication.c
--- a/pidgin/pidginapplication.c
+++ b/pidgin/pidginapplication.c
@@ -45,6 +45,7 @@
 #include "pidgincore.h"
 #include "pidgindebug.h"
 #include "pidgindisplaywindow.h"
+#include "pidginimwindow.h"
 #include "pidginpluginsdialog.h"
 #include "pidginpluginsmenu.h"
 #include "pidginprefs.h"
@@ -468,7 +469,16 @@
                                G_GNUC_UNUSED GVariant *parameter,
                                G_GNUC_UNUSED gpointer data)
 {
-	pidgin_dialogs_im();
+	PidginApplication *application = data;
+	static GtkWidget *dialog = NULL;
+
+	if(!PIDGIN_IS_IM_WINDOW(dialog)) {
+		dialog = pidgin_im_window_new();
+		g_object_add_weak_pointer(G_OBJECT(dialog), (gpointer)&dialog);
+	}
+
+	pidgin_application_present_transient_window(application,
+	                                            GTK_WINDOW(dialog));
 }
 
 static void
diff --git a/pidgin/pidginimwindow.h b/pidgin/pidginimwindow.h
new file mode 100644
--- /dev/null
+++ b/pidgin/pidginimwindow.h
@@ -0,0 +1,65 @@
+/*
+ * Pidgin - Internet Messenger
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(PIDGIN_GLOBAL_HEADER_INSIDE) && !defined(PIDGIN_COMPILATION)
+# error "only <pidgin.h> may be included directly"
+#endif
+
+#ifndef PIDGIN_IM_WINDOW_H
+#define PIDGIN_IM_WINDOW_H
+
+#include <glib.h>
+
+#include <gtk/gtk.h>
+
+#include <adwaita.h>
+
+#include "pidginversion.h"
+
+G_BEGIN_DECLS
+
+/**
+ * PidginIMWindow:
+ *
+ * A window used to start a new direct message.
+ *
+ * Since: 3.0.0
+ */
+
+#define PIDGIN_TYPE_IM_WINDOW (pidgin_im_window_get_type())
+
+PIDGIN_AVAILABLE_IN_3_0
+G_DECLARE_FINAL_TYPE(PidginIMWindow, pidgin_im_window,
+                     PIDGIN, IM_WINDOW, AdwMessageDialog)
+
+/**
+ * pidgin_im_window_new:
+ *
+ * Creates a new #PidginIMWindow instance.
+ *
+ * Returns: (transfer full): The new #PidginIMWindow instance.
+ */
+GtkWidget *pidgin_im_window_new(void);
+
+G_END_DECLS
+
+#endif /* PIDGIN_IM_WINDOW_H */
diff --git a/pidgin/pidginimwindow.c b/pidgin/pidginimwindow.c
new file mode 100644
--- /dev/null
+++ b/pidgin/pidginimwindow.c
@@ -0,0 +1,143 @@
+/*
+ * Pidgin - Internet Messenger
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <purple.h>
+
+#include "pidginimwindow.h"
+
+#include "pidginaccountrow.h"
+
+struct _PidginIMWindow {
+	AdwMessageDialog parent;
+
+	GtkCustomFilter *filter;
+
+	GtkWidget *account;
+	GtkWidget *username;
+};
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static gboolean
+pidgin_im_window_filter_accounts(gpointer item, G_GNUC_UNUSED gpointer data) {
+	if(PURPLE_IS_ACCOUNT(item)) {
+		PurpleAccount *account = PURPLE_ACCOUNT(item);
+		PurpleProtocol *protocol = purple_account_get_protocol(account);
+
+		if(PURPLE_IS_PROTOCOL(protocol)) {
+			return PURPLE_PROTOCOL_IMPLEMENTS(protocol, CONVERSATION,
+			                                  send_message_async);
+		}
+	}
+
+	return FALSE;
+
+}
+
+/******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static void
+pidgin_im_window_username_changed_cb(GtkEditable *self, gpointer data) {
+	const char *text = NULL;
+	gboolean enabled = FALSE;
+
+	text = gtk_editable_get_text(self);
+	enabled = !purple_strempty(text);
+
+	adw_message_dialog_set_response_enabled(data, "okay", enabled);
+}
+
+static void
+pidgin_im_window_response_cb(AdwMessageDialog *self,
+                             const char *response,
+                             G_GNUC_UNUSED gpointer data)
+{
+	PidginIMWindow *window = PIDGIN_IM_WINDOW(self);
+	PurpleAccount *account = NULL;
+	PurpleConversation *im = NULL;
+	PurpleConversationManager *manager = NULL;
+	const char *username = NULL;
+
+	if(!purple_strequal(response, "okay")) {
+		return;
+	}
+
+	account = pidgin_account_row_get_account(PIDGIN_ACCOUNT_ROW(window->account)) ;
+	username = gtk_editable_get_text(GTK_EDITABLE(window->username));
+
+	manager = purple_conversation_manager_get_default();
+	im = purple_conversation_manager_find_im(manager, account, username);
+
+	if(!PURPLE_IS_IM_CONVERSATION(im)) {
+		/* This constructor automagically registers the conversation with the
+		 * manager.
+		 */
+		purple_im_conversation_new(account, username);
+	}
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+G_DEFINE_TYPE(PidginIMWindow, pidgin_im_window, ADW_TYPE_MESSAGE_DIALOG)
+
+static void
+pidgin_im_window_init(PidginIMWindow *window) {
+	gtk_widget_init_template(GTK_WIDGET(window));
+
+	gtk_custom_filter_set_filter_func(window->filter,
+	                                  pidgin_im_window_filter_accounts,
+	                                  NULL, NULL);
+}
+
+static void
+pidgin_im_window_class_init(PidginIMWindowClass *klass) {
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+	gtk_widget_class_set_template_from_resource(
+		widget_class,
+		"/im/pidgin/Pidgin3/imwindow.ui"
+	);
+
+	gtk_widget_class_bind_template_child(widget_class, PidginIMWindow,
+	                                     filter);
+
+	gtk_widget_class_bind_template_child(widget_class, PidginIMWindow,
+	                                     account);
+	gtk_widget_class_bind_template_child(widget_class, PidginIMWindow,
+	                                     username);
+
+	gtk_widget_class_bind_template_callback(widget_class,
+	                                        pidgin_im_window_username_changed_cb);
+	gtk_widget_class_bind_template_callback(widget_class,
+	                                        pidgin_im_window_response_cb);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+GtkWidget *
+pidgin_im_window_new(void) {
+	return g_object_new(PIDGIN_TYPE_IM_WINDOW, NULL);
+}
diff --git a/pidgin/resources/imwindow.ui b/pidgin/resources/imwindow.ui
new file mode 100644
--- /dev/null
+++ b/pidgin/resources/imwindow.ui
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Pidgin - Internet Messenger
+Copyright (C) Pidgin Developers <devel@pidgin.im>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this library; if not, see <https://www.gnu.org/licenses/>.
+-->
+<interface>
+  <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="PidginIMWindow" parent="AdwMessageDialog">
+    <property name="heading" translatable="yes">New Instant Message</property>
+    <property name="body" translatable="yes">Please enter the username or alias of the person you would like to IM.</property>
+    <property name="extra-child">
+      <object class="AdwPreferencesGroup">
+        <property name="vexpand">true</property>
+        <property name="hexpand">true</property>
+        <child>
+          <object class="PidginAccountRow" id="account">
+            <property name="filter">
+              <object class="GtkEveryFilter">
+                <child>
+                  <object class="GtkCustomFilter" id="filter"/>
+                </child>
+                <child>
+                  <object class="PidginAccountFilterConnected"/>
+                </child>
+              </object>
+            </property>
+          </object>
+        </child>
+        <child>
+          <object class="AdwEntryRow" id="username">
+            <property name="focusable">no</property>
+            <property name="title" translatable="yes">_Username</property>
+            <property name="use-underline">yes</property>
+            <property name="activates-default">yes</property>
+            <signal name="changed" handler="pidgin_im_window_username_changed_cb"/>
+          </object>
+        </child>
+      </object>
+    </property>
+    <property name="default-response">okay</property>
+    <property name="close-response">cancel</property>
+    <responses>
+      <response id="cancel" translatable="yes">_Cancel</response>
+      <response id="okay" translatable="yes" appearance="suggested" enabled="false">_Okay</response>
+    </responses>
+    <signal name="response" handler="pidgin_im_window_response_cb"/>
+  </template>
+</interface>
diff --git a/pidgin/resources/pidgin.gresource.xml b/pidgin/resources/pidgin.gresource.xml
--- a/pidgin/resources/pidgin.gresource.xml
+++ b/pidgin/resources/pidgin.gresource.xml
@@ -43,6 +43,7 @@
     <file compressed="true" preprocess="xml-stripblanks">channeljoindialog.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">contactlistitem.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">conversationmemberlistitem.ui</file>
+    <file compressed="true" preprocess="xml-stripblanks">imwindow.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">presenceicon.ui</file>
     <file>icons/16x16/status/pidgin-user-available.png</file>
     <file>icons/16x16/status/pidgin-user-away.png</file>
