pidgin/pidgin

Add copy button to Build Information sections

15 months ago, Elliott Sales de Andrade
b4747dfd7c34
Parents fea856f5eda6
Children 5bda87b90d8d
Add copy button to Build Information sections

These buttons on each group allow exporting the sections to the clipboard in a markdown format.
The Copy All button allows exporting everything.

Note that this information is purposely _not_ translated as I expect it to primarily be used for debugging by us in bug reports.

Testing Done:
Opened About dialog, clicked all the Copy buttons and confirmed their contents; clicked the Copy All button and confirmed everything was there.

Reviewed at https://reviews.imfreedom.org/r/2196/
--- a/pidgin/pidginabout.c Mon Jan 16 22:07:30 2023 -0600
+++ b/pidgin/pidginabout.c Mon Jan 16 22:08:46 2023 -0600
@@ -235,6 +235,25 @@
GTK_MICRO_VERSION);
}
+static char *
+pidgin_about_dialog_copy_build_info(void) {
+ char *info = NULL;
+
+ info = g_strdup_printf(
+ "Build Information\n"
+ "=================\n"
+ "Commit Hash: %s\n"
+ "Purple Version: %u.%u.%u\n"
+ "GLib Version: %u.%u.%u\n"
+ "GTK Version: %u.%u.%u\n",
+ REVISION,
+ PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION,
+ GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION,
+ GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
+
+ return info;
+}
+
static void
pidgin_about_dialog_load_runtime_info(PidginAboutDialog *about) {
/* add the purple version */
@@ -259,6 +278,23 @@
gtk_get_micro_version());
}
+static char *
+pidgin_about_dialog_copy_runtime_info(void) {
+ char *info = NULL;
+
+ info = g_strdup_printf(
+ "Runtime Information\n"
+ "===================\n"
+ "Purple Version: %u.%u.%u\n"
+ "GLib Version: %u.%u.%u\n"
+ "GTK Version: %u.%u.%u\n",
+ purple_major_version, purple_minor_version, purple_micro_version,
+ glib_major_version, glib_minor_version, glib_micro_version,
+ gtk_get_major_version(), gtk_get_minor_version(), gtk_get_micro_version());
+
+ return info;
+}
+
static void
pidgin_about_dialog_load_gtk_settings(PidginAboutDialog *about) {
gchar *cursor_theme_name = NULL, *theme_name = NULL;
@@ -328,6 +364,69 @@
g_free(theme_name);
}
+static char *
+pidgin_about_dialog_copy_gtk_settings(void) {
+ char *cursor_theme_name = NULL, *theme_name = NULL;
+ char *icon_theme_name = NULL;
+ char *im_module = NULL;
+ char *sound_theme_name = NULL;
+ gboolean enable_animations = FALSE;
+ gboolean shell_shows_app_menu = FALSE, shell_shows_menubar = FALSE;
+ GString *info = NULL;
+
+ /* get the settings we're interested in */
+ g_object_get(
+ gtk_settings_get_default(),
+ "gtk-cursor-theme-name", &cursor_theme_name,
+ "gtk-enable-animations", &enable_animations,
+ "gtk-icon-theme-name", &icon_theme_name,
+ "gtk-im-module", &im_module,
+ "gtk-shell-shows-app-menu", &shell_shows_app_menu,
+ "gtk-shell-shows-menubar", &shell_shows_menubar,
+ "gtk-sound-theme-name", &sound_theme_name,
+ "gtk-theme-name", &theme_name,
+ NULL);
+
+ info = g_string_new(
+ "GTK Settings\n"
+ "============\n");
+
+ g_string_append_printf(
+ info, "gtk-cursor-theme-name: %s\n",
+ (cursor_theme_name != NULL) ? cursor_theme_name : _("(not set)"));
+
+ g_string_append_printf(info, "gtk-enable-animations: %s\n",
+ enable_animations ? _("yes") : _("no"));
+
+ g_string_append_printf(
+ info, "gtk-icon-theme-name: %s\n",
+ (icon_theme_name != NULL) ? icon_theme_name : _("(not set)"));
+
+ g_string_append_printf(info, "gtk-im-module: %s\n",
+ (im_module != NULL) ? im_module : _("(not set)"));
+
+ g_string_append_printf(info, "gtk-shell-shows-app-menu: %s\n",
+ shell_shows_app_menu ? _("yes") : _("no"));
+
+ g_string_append_printf(info, "gtk-shell-shows-menubar: %s\n",
+ shell_shows_menubar ? _("yes") : _("no"));
+
+ g_string_append_printf(
+ info, "gtk-sound-theme-name: %s\n",
+ (sound_theme_name != NULL) ? sound_theme_name : _("(not set)"));
+
+ g_string_append_printf(info, "gtk-theme-name: %s\n",
+ (theme_name != NULL) ? theme_name : _("(not set)"));
+
+ g_free(cursor_theme_name);
+ g_free(icon_theme_name);
+ g_free(im_module);
+ g_free(sound_theme_name);
+ g_free(theme_name);
+
+ return g_string_free(info, FALSE);
+}
+
static void
pidgin_about_dialog_load_plugin_search_paths(PidginAboutDialog *about) {
GList *paths = NULL;
@@ -343,6 +442,27 @@
}
}
+static char *
+pidgin_about_dialog_copy_plugin_search_paths(void) {
+ GList *paths = NULL;
+ GPluginManager *manager = gplugin_manager_get_default();
+ GString *info = NULL;
+
+ info = g_string_new(
+ "Plugin Search Paths\n"
+ "===================\n");
+
+ /* add the search paths */
+ paths = gplugin_manager_get_paths(manager);
+ while(paths != NULL) {
+ g_string_append_printf(info, "- %s\n", (char *)paths->data);
+
+ paths = paths->next;
+ }
+
+ return g_string_free(info, FALSE);
+}
+
static void
pidgin_about_dialog_load_conf_path_info(PidginAboutDialog *about) {
/* add the cache directory path */
@@ -358,6 +478,23 @@
purple_data_dir());
}
+static char *
+pidgin_about_dialog_copy_conf_path_info(void) {
+ char *info = NULL;
+
+ info = g_strdup_printf(
+ "Runtime Directories\n"
+ "===================\n"
+ "Cache: %s\n"
+ "Configuration: %s\n"
+ "Data: %s\n",
+ purple_cache_dir(),
+ purple_config_dir(),
+ purple_data_dir());
+
+ return info;
+}
+
static void
pidgin_about_dialog_add_build_args(PidginAboutDialog *about,
const char *build_args)
@@ -382,6 +519,42 @@
g_strfreev(splits);
}
+static char *
+pidgin_about_dialog_copy_build_args(const char *build_args) {
+ char **splits = NULL;
+ GString *info = NULL;
+
+ info = g_string_new(
+ "Meson Arguments\n"
+ "===============\n");
+
+ /* Walk through the arguments and add them */
+ splits = g_strsplit(build_args, " ", -1);
+ for(gint idx = 0; splits[idx]; idx++) {
+ char **value_split = g_strsplit(splits[idx], "=", 2);
+ char *value = NULL;
+
+ if(value_split[0] == NULL || value_split[0][0] == '\0') {
+ continue;
+ }
+
+ if(value_split[1] != NULL) {
+ value = purple_unescape_text(value_split[1]);
+ } else {
+ value = NULL;
+ }
+
+ g_string_append_printf(info, "%s: %s\n", value_split[0], value);
+
+ g_free(value);
+ g_strfreev(value_split);
+ }
+
+ g_strfreev(splits);
+
+ return g_string_free(info, FALSE);
+}
+
static void
pidgin_about_dialog_load_build_configuration(PidginAboutDialog *about) {
pidgin_about_dialog_load_build_info(about);
@@ -418,6 +591,73 @@
gtk_show_uri(GTK_WINDOW(data), url, GDK_CURRENT_TIME);
}
+static void
+pidgin_about_dialog_copy_button_cb(GtkButton *button,
+ gpointer data)
+{
+ PidginAboutDialog *about = NULL;
+ GdkClipboard *clipboard = NULL;
+ char *info = NULL;
+
+ about = PIDGIN_ABOUT_DIALOG(gtk_widget_get_root(GTK_WIDGET(button)));
+
+ if(data == about->build_info_group) {
+ info = pidgin_about_dialog_copy_build_info();
+ } else if(data == about->runtime_info_group) {
+ info = pidgin_about_dialog_copy_runtime_info();
+ } else if(data == about->gtk_settings_group) {
+ info = pidgin_about_dialog_copy_gtk_settings();
+ } else if(data == about->plugin_search_paths_group) {
+ info = pidgin_about_dialog_copy_plugin_search_paths();
+ } else if(data == about->conf_path_info_group) {
+ info = pidgin_about_dialog_copy_conf_path_info();
+#ifdef MESON_ARGS
+ } else if(data == about->build_args_group) {
+ info = pidgin_about_dialog_copy_build_args(MESON_ARGS);
+#endif
+ } else {
+ GString *everything = g_string_new(NULL);
+
+ info = pidgin_about_dialog_copy_build_info();
+ g_string_append(everything, info);
+ g_string_append_c(everything, '\n');
+ g_free(info);
+
+ info = pidgin_about_dialog_copy_runtime_info();
+ g_string_append(everything, info);
+ g_string_append_c(everything, '\n');
+ g_free(info);
+
+ info = pidgin_about_dialog_copy_conf_path_info();
+ g_string_append(everything, info);
+ g_string_append_c(everything, '\n');
+ g_free(info);
+
+ info = pidgin_about_dialog_copy_gtk_settings();
+ g_string_append(everything, info);
+ g_string_append_c(everything, '\n');
+ g_free(info);
+
+ info = pidgin_about_dialog_copy_plugin_search_paths();
+ g_string_append(everything, info);
+ g_free(info);
+
+#ifdef MESON_ARGS
+ g_string_append_c(everything, '\n');
+ info = pidgin_about_dialog_copy_build_args(MESON_ARGS);
+ g_string_append(everything, info);
+ g_free(info);
+#endif
+
+ info = g_string_free(everything, FALSE);
+ }
+
+ clipboard = gtk_widget_get_clipboard(GTK_WIDGET(about));
+ gdk_clipboard_set_text(clipboard, info);
+
+ g_free(info);
+}
+
/******************************************************************************
* GObject Implementation
*****************************************************************************/
@@ -461,6 +701,8 @@
pidgin_about_dialog_response_cb);
gtk_widget_class_bind_template_callback(widget_class,
pidgin_about_dialog_open_url_cb);
+ gtk_widget_class_bind_template_callback(widget_class,
+ pidgin_about_dialog_copy_button_cb);
}
static void
--- a/pidgin/resources/About/about.ui Mon Jan 16 22:07:30 2023 -0600
+++ b/pidgin/resources/About/about.ui Mon Jan 16 22:08:46 2023 -0600
@@ -122,34 +122,93 @@
<property name="child">
<object class="AdwPreferencesPage">
<child>
+ <object class="GtkButton" id="copy_all_button">
+ <property name="css-classes">pill</property>
+ <property name="halign">center</property>
+ <property name="valign">end</property>
+ <property name="child">
+ <object class="AdwButtonContent">
+ <property name="icon-name">edit-copy-symbolic</property>
+ <property name="label" translatable="1">_Copy All</property>
+ <property name="use-underline">1</property>
+ </object>
+ </property>
+ <signal name="clicked" handler="pidgin_about_dialog_copy_button_cb" swapped="no"/>
+ </object>
+ </child>
+ <!-- AdwPreferencesPage doesn't track non-AdwPreferencesGroup children, so manually remove when it's destroyed. -->
+ <signal name="destroy" handler="gtk_widget_unparent" object="copy_all_button" swapped="yes"/>
+ <child>
<object class="AdwPreferencesGroup" id="build_info_group">
<property name="title" translatable="1">Build Information</property>
+ <child type="header-suffix">
+ <object class="GtkButton">
+ <property name="css-classes">flat</property>
+ <property name="icon-name">edit-copy-symbolic</property>
+ <signal name="clicked" handler="pidgin_about_dialog_copy_button_cb" object="build_info_group" swapped="no"/>
+ </object>
+ </child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="runtime_info_group">
<property name="title" translatable="1">Runtime Information</property>
+ <child type="header-suffix">
+ <object class="GtkButton">
+ <property name="css-classes">flat</property>
+ <property name="icon-name">edit-copy-symbolic</property>
+ <signal name="clicked" handler="pidgin_about_dialog_copy_button_cb" object="runtime_info_group" swapped="no"/>
+ </object>
+ </child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="conf_path_info_group">
<property name="title" translatable="1">Runtime Directories</property>
+ <child type="header-suffix">
+ <object class="GtkButton">
+ <property name="css-classes">flat</property>
+ <property name="icon-name">edit-copy-symbolic</property>
+ <signal name="clicked" handler="pidgin_about_dialog_copy_button_cb" object="conf_path_info_group" swapped="no"/>
+ </object>
+ </child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="gtk_settings_group">
<property name="title" translatable="1">GTK Settings</property>
+ <child type="header-suffix">
+ <object class="GtkButton">
+ <property name="css-classes">flat</property>
+ <property name="icon-name">edit-copy-symbolic</property>
+ <signal name="clicked" handler="pidgin_about_dialog_copy_button_cb" object="gtk_settings_group" swapped="no"/>
+ </object>
+ </child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="plugin_search_paths_group">
<property name="title" translatable="1">Plugin Search Paths</property>
+ <child type="header-suffix">
+ <object class="GtkButton">
+ <property name="css-classes">flat</property>
+ <property name="icon-name">edit-copy-symbolic</property>
+ <signal name="clicked" handler="pidgin_about_dialog_copy_button_cb" object="plugin_search_paths_group" swapped="no"/>
+ </object>
+ </child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="build_args_group">
<property name="title" translatable="1">Meson Arguments</property>
<property name="visible">0</property>
+ <child type="header-suffix">
+ <object class="GtkButton">
+ <property name="css-classes">flat</property>
+ <property name="icon-name">edit-copy-symbolic</property>
+ <signal name="clicked" handler="pidgin_about_dialog_copy_button_cb" object="build_args_group" swapped="no"/>
+ </object>
+ </child>
</object>
</child>
</object>