--- a/pidgin/meson.build Mon Apr 03 10:02:25 2023 -0500
+++ b/pidgin/meson.build Mon Apr 03 23:09:36 2023 -0500
@@ -55,6 +55,7 @@
'pidginprotocolchooser.c',
+ 'pidginstatusdisplay.c', 'pidginstatusprimitivechooser.c',
@@ -122,6 +123,7 @@
'pidginprotocolchooser.h',
+ 'pidginstatusdisplay.h', 'pidginstatusprimitivechooser.h',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidginstatusdisplay.c Mon Apr 03 23:09:36 2023 -0500
@@ -0,0 +1,274 @@
+ * 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 + * 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 <glib/gi18n-lib.h> +#include "pidginstatusdisplay.h" +#include "pidginiconname.h" +struct _PidginStatusDisplay { + PurpleStatusPrimitive primitive; + PurpleSavedStatus *status; +static GParamSpec *properties[PROP_LAST] = {NULL}; +/****************************************************************************** + *****************************************************************************/ +pidgin_status_display_refresh(PidginStatusDisplay *display) { + const char *icon_name = NULL; + if(display->status != NULL) { + PurpleSavedStatus *status = display->status; + PurpleStatusPrimitive primitive; + primitive = purple_savedstatus_get_primitive_type(status); + icon_name = pidgin_icon_name_from_status_primitive(primitive, NULL); + text = g_string_new(purple_savedstatus_get_title(status)); + /* Transient statuses do not have a title, so the savedstatus API + * returns the message when purple_savedstatus_get_title() is called, + * so we don't need to get the message a second time. + if(!purple_savedstatus_is_transient(status)) { + const char *message = NULL; + message = purple_savedstatus_get_message(status); + char *stripped = purple_markup_strip_html(message); + purple_util_chrreplace(stripped, '\n', ' '); + g_string_append_printf(text, " - %s", stripped); + label = g_string_free(text, FALSE); + } else if(display->primitive != PURPLE_STATUS_UNSET) { + icon_name = pidgin_icon_name_from_status_primitive(display->primitive, + label = g_strdup(purple_primitive_get_name_from_type(display->primitive)); + gtk_image_set_from_icon_name(display->image, icon_name); + gtk_label_set_text(display->label, label); +/****************************************************************************** + * GObject implementation + *****************************************************************************/ +G_DEFINE_TYPE(PidginStatusDisplay, pidgin_status_display, GTK_TYPE_BOX) +pidgin_status_display_get_property(GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) + PidginStatusDisplay *display = PIDGIN_STATUS_DISPLAY(object); + g_value_set_enum(value, + pidgin_status_display_get_primitive(display)); + case PROP_SAVED_STATUS: + g_value_set_pointer(value, + pidgin_status_display_get_saved_status(display)); + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); +pidgin_status_display_set_property(GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) + PidginStatusDisplay *display = PIDGIN_STATUS_DISPLAY(object); + pidgin_status_display_set_primitive(display, + g_value_get_enum(value)); + case PROP_SAVED_STATUS: + pidgin_status_display_set_saved_status(display, + g_value_get_pointer(value)); + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); +pidgin_status_display_class_init(PidginStatusDisplayClass *klass) { + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + obj_class->get_property = pidgin_status_display_get_property; + obj_class->set_property = pidgin_status_display_set_property; + * PidginStatusDisplay:primitive: + * The status primitive that is currently displayed. + properties[PROP_PRIMITIVE] = g_param_spec_enum( + "primitive", "primitive", + "The status primitive that is currently displayed.", + PURPLE_TYPE_STATUS_PRIMITIVE, PURPLE_STATUS_UNSET, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + * PidginStatusDisplay:saved-status: + * The saved status that is currently displayed. + properties[PROP_SAVED_STATUS] = g_param_spec_pointer( + "saved-status", "saved-status", + "The saved status that is currently displayed.", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(obj_class, PROP_LAST, properties); + gtk_widget_class_set_template_from_resource( + widget_class, "/im/pidgin/Pidgin3/Status/display.ui"); + gtk_widget_class_bind_template_child(widget_class, PidginStatusDisplay, + gtk_widget_class_bind_template_child(widget_class, PidginStatusDisplay, +pidgin_status_display_init(PidginStatusDisplay *display) { + gtk_widget_init_template(GTK_WIDGET(display)); +/****************************************************************************** + *****************************************************************************/ +pidgin_status_display_new(void) { + return g_object_new(PIDGIN_TYPE_STATUS_DISPLAY, NULL); +pidgin_status_display_new_for_primitive(PurpleStatusPrimitive primitive) { + return g_object_new(PIDGIN_TYPE_STATUS_DISPLAY, + "primitive", primitive, +pidgin_status_display_new_for_saved_status(PurpleSavedStatus *status) { + return g_object_new(PIDGIN_TYPE_STATUS_DISPLAY, + "saved-status", status, +pidgin_status_display_get_primitive(PidginStatusDisplay *display) { + g_return_val_if_fail(PIDGIN_IS_STATUS_DISPLAY(display), + return display->primitive; +pidgin_status_display_set_primitive(PidginStatusDisplay *display, + PurpleStatusPrimitive primitive) + g_return_if_fail(PIDGIN_IS_STATUS_DISPLAY(display)); + g_object_freeze_notify(G_OBJECT(display)); + display->status = NULL; + g_object_notify_by_pspec(G_OBJECT(display), properties[PROP_SAVED_STATUS]); + if(display->primitive != primitive) { + display->primitive = primitive; + g_object_notify_by_pspec(G_OBJECT(display), + properties[PROP_PRIMITIVE]); + pidgin_status_display_refresh(display); + g_object_thaw_notify(G_OBJECT(display)); +pidgin_status_display_get_saved_status(PidginStatusDisplay *display) { + g_return_val_if_fail(PIDGIN_IS_STATUS_DISPLAY(display), NULL); + return display->status; +pidgin_status_display_set_saved_status(PidginStatusDisplay *display, + PurpleSavedStatus *status) + g_return_if_fail(PIDGIN_IS_STATUS_DISPLAY(display)); + g_object_freeze_notify(G_OBJECT(display)); + display->primitive = PURPLE_STATUS_UNSET; + g_object_notify_by_pspec(G_OBJECT(display), properties[PROP_PRIMITIVE]); + if(display->status != status) { + display->status = status; + g_object_notify_by_pspec(G_OBJECT(display), + properties[PROP_SAVED_STATUS]); + pidgin_status_display_refresh(display); + g_object_thaw_notify(G_OBJECT(display)); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidginstatusdisplay.h Mon Apr 03 23:09:36 2023 -0500
@@ -0,0 +1,129 @@
+ * 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 + * 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" +#ifndef PIDGIN_STATUS_DISPLAY_H +#define PIDGIN_STATUS_DISPLAY_H +#define PIDGIN_TYPE_STATUS_DISPLAY (pidgin_status_display_get_type()) +G_DECLARE_FINAL_TYPE(PidginStatusDisplay, pidgin_status_display, + PIDGIN, STATUS_DISPLAY, GtkBox) + * pidgin_status_display_new: + * Creates a display for a status. + * Returns: (transfer full): The status display. +GtkWidget *pidgin_status_display_new(void); + * pidgin_status_display_new_for_primitive: + * @primitive: The status primitive to display. + * Creates a display for a status primitive. + * Returns: (transfer full): The status display. +GtkWidget *pidgin_status_display_new_for_primitive(PurpleStatusPrimitive primitive); + * pidgin_status_display_new_for_saved_status: + * @status: The status to display. + * Creates a display for a saved status. + * Returns: (transfer full): The status display. +GtkWidget *pidgin_status_display_new_for_saved_status(PurpleSavedStatus *status); + * pidgin_status_display_get_primitive: + * @display: The display. + * Gets the currently displayed status primitive. + * Returns: (transfer none): Returns the [type@Purple.StatusPrimitive] that is +PurpleStatusPrimitive pidgin_status_display_get_primitive(PidginStatusDisplay *display); + * pidgin_status_display_set_primitive: + * @display: The display. + * @primitive: The status primitive to display. + * Sets the currently displayed status primitive. + * If a saved status was previously set, it will be unset. +void pidgin_status_display_set_primitive(PidginStatusDisplay *display, PurpleStatusPrimitive primitive); + * pidgin_status_display_get_saved_status: + * @display: The display. + * Gets the currently displayed saved status. + * Returns: (transfer none): Returns the [type@Purple.SavedStatus] that is +PurpleSavedStatus *pidgin_status_display_get_saved_status(PidginStatusDisplay *display); + * pidgin_status_display_set_saved_status: + * @display: The display. + * @status: The saved status to display. + * Sets the currently displayed saved status. + * If a status primitive was previously set, it will be unset. +void pidgin_status_display_set_saved_status(PidginStatusDisplay *display, PurpleSavedStatus *status); +#endif /* PIDGIN_STATUS_DISPLAY_H */ --- a/pidgin/pidginstatusmanager.c Mon Apr 03 10:02:25 2023 -0500
+++ b/pidgin/pidginstatusmanager.c Mon Apr 03 23:09:36 2023 -0500
@@ -125,12 +125,11 @@
PurpleStatusPrimitive primitive;
- const gchar *icon_name = NULL, *type = NULL;
+ const char *type = NULL; message = purple_markup_strip_html(purple_savedstatus_get_message(status));
primitive = purple_savedstatus_get_primitive_type(status);
- icon_name = pidgin_icon_name_from_status_primitive(primitive, NULL);
type = purple_primitive_get_name_from_type(primitive);
/* PurpleSavedStatus is a boxed type, so it can't be put in a GListModel;
@@ -140,7 +139,6 @@
g_object_set_data_full(wrapper, "title",
g_strdup(purple_savedstatus_get_title(status)),
- g_object_set_data_full(wrapper, "icon-name", g_strdup(icon_name), g_free);
g_object_set_data_full(wrapper, "type", g_strdup(type), g_free);
g_object_set_data_full(wrapper, "message", g_strdup(message), g_free);
@@ -208,6 +206,21 @@
+static PurpleStatusPrimitive +pidgin_status_manager_lookup_primitive_cb(G_GNUC_UNUSED GObject *self, + G_GNUC_UNUSED gpointer data) + PurpleStatusPrimitive primitive = PURPLE_STATUS_UNSET; + if(G_IS_OBJECT(wrapper)) { + PurpleSavedStatus *status = g_object_get_data(wrapper, "savedstatus"); + primitive = purple_savedstatus_get_primitive_type(status); pidgin_status_manager_sort_data_cb(GObject *wrapper, const char *name,
G_GNUC_UNUSED gpointer data)
@@ -388,6 +401,8 @@
gtk_widget_class_bind_template_callback(widget_class,
pidgin_status_manager_response_cb);
gtk_widget_class_bind_template_callback(widget_class,
+ pidgin_status_manager_lookup_primitive_cb); + gtk_widget_class_bind_template_callback(widget_class, pidgin_status_manager_lookup_text_data_cb);
gtk_widget_class_bind_template_callback(widget_class,
pidgin_status_manager_sort_data_cb);
--- a/pidgin/pidginstatusprimitivechooser.c Mon Apr 03 10:02:25 2023 -0500
+++ b/pidgin/pidginstatusprimitivechooser.c Mon Apr 03 23:09:36 2023 -0500
@@ -32,64 +32,21 @@
/******************************************************************************
*****************************************************************************/
static PurpleStatusPrimitive
-pidgin_status_primitive_chooser_primitive_from_string(const char *str) {
- if(purple_strequal(str, "offline")) {
- return PURPLE_STATUS_OFFLINE;
- } else if(purple_strequal(str, "available")) {
- return PURPLE_STATUS_AVAILABLE;
- } else if(purple_strequal(str, "unavailable")) {
- return PURPLE_STATUS_UNAVAILABLE;
- } else if(purple_strequal(str, "invisible")) {
- return PURPLE_STATUS_INVISIBLE;
- } else if(purple_strequal(str, "away")) {
- return PURPLE_STATUS_AWAY;
- } else if(purple_strequal(str, "extended-away")) {
- return PURPLE_STATUS_EXTENDED_AWAY;
- return PURPLE_STATUS_UNSET;
-/******************************************************************************
- *****************************************************************************/
-pidgin_status_primitive_chooser_icon_name_cb(G_GNUC_UNUSED GObject *self,
+pidgin_status_primitive_chooser_primitive_cb(G_GNUC_UNUSED GObject *self, G_GNUC_UNUSED gpointer data)
PurpleStatusPrimitive primitive = PURPLE_STATUS_UNSET;
- const char *value = NULL;
- if(!GTK_IS_STRING_OBJECT(object)) {
+ if(GTK_IS_STRING_OBJECT(object)) { + const char *value = gtk_string_object_get_string(object); + primitive = purple_primitive_get_type_from_id(value); - value = gtk_string_object_get_string(object);
- primitive = pidgin_status_primitive_chooser_primitive_from_string(value);
- return g_strdup(pidgin_icon_name_from_status_primitive(primitive, NULL));
-pidgin_status_primitive_chooser_label_cb(G_GNUC_UNUSED GObject *self,
- GtkStringObject *object,
- G_GNUC_UNUSED gpointer data)
- PurpleStatusPrimitive primitive = PURPLE_STATUS_UNSET;
- const char *value = NULL;
- if(!GTK_IS_STRING_OBJECT(object)) {
- value = gtk_string_object_get_string(object);
- primitive = pidgin_status_primitive_chooser_primitive_from_string(value);
- return g_strdup(purple_primitive_get_name_from_type(primitive));
/******************************************************************************
@@ -109,9 +66,7 @@
widget_class, "/im/pidgin/Pidgin3/statusprimitivechooser.ui");
gtk_widget_class_bind_template_callback(widget_class,
- pidgin_status_primitive_chooser_icon_name_cb);
- gtk_widget_class_bind_template_callback(widget_class,
- pidgin_status_primitive_chooser_label_cb);
+ pidgin_status_primitive_chooser_primitive_cb); /******************************************************************************
@@ -133,7 +88,7 @@
selected = adw_combo_row_get_selected_item(ADW_COMBO_ROW(chooser));
value = gtk_string_object_get_string(selected);
- return pidgin_status_primitive_chooser_primitive_from_string(value);
+ return purple_primitive_get_type_from_id(value); @@ -152,7 +107,7 @@
const char *value = NULL;
value = gtk_string_list_get_string(list, i);
- candidate = pidgin_status_primitive_chooser_primitive_from_string(value);
+ candidate = purple_primitive_get_type_from_id(value); if(primitive == candidate) {
adw_combo_row_set_selected(ADW_COMBO_ROW(chooser), i);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/resources/Status/display.ui Mon Apr 03 23:09:36 2023 -0500
@@ -0,0 +1,38 @@
+<?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 Lesser General Public +License along with this library; if not, see <https://www.gnu.org/licenses/>. + <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="PidginStatusDisplay" parent="GtkBox"> + <property name="css-classes">body</property> + <property name="orientation">horizontal</property> + <property name="spacing">6</property> + <object class="GtkImage" id="image"/> + <object class="GtkLabel" id="label"/> --- a/pidgin/resources/Status/manager.ui Mon Apr 03 10:02:25 2023 -0500
+++ b/pidgin/resources/Status/manager.ui Mon Apr 03 23:09:36 2023 -0500
@@ -107,28 +107,12 @@
<template class="GtkListItem">
- <object class="GtkBox">
- <property name="orientation">horizontal</property>
- <object class="GtkImage">
- <binding name="icon-name">
- <closure type="gchararray" function="pidgin_status_manager_lookup_text_data_cb">
- <lookup name="item">GtkListItem</lookup>
- <constant type="gchararray">icon-name</constant>
- <object class="GtkLabel">
- <closure type="gchararray" function="pidgin_status_manager_lookup_text_data_cb">
- <lookup name="item">GtkListItem</lookup>
- <constant type="gchararray">type</constant>
+ <object class="PidginStatusDisplay"> + <binding name="primitive"> + <closure type="PurpleStatusPrimitive" function="pidgin_status_manager_lookup_primitive_cb"> + <lookup name="item">GtkListItem</lookup> --- a/pidgin/resources/pidgin.gresource.xml Mon Apr 03 10:02:25 2023 -0500
+++ b/pidgin/resources/pidgin.gresource.xml Mon Apr 03 23:09:36 2023 -0500
@@ -39,6 +39,7 @@
<file compressed="true" preprocess="xml-stripblanks">Protocols/detailed-view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">Roomlist/roomlist.ui</file>
<file compressed="true" preprocess="xml-stripblanks">Status/box.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks">Status/display.ui</file> <file compressed="true" preprocess="xml-stripblanks">Status/editor.ui</file>
<file compressed="true" preprocess="xml-stripblanks">Status/manager.ui</file>
<file compressed="true" preprocess="xml-stripblanks">Whiteboard/whiteboard.ui</file>
--- a/pidgin/resources/statusprimitivechooser.ui Mon Apr 03 10:02:25 2023 -0500
+++ b/pidgin/resources/statusprimitivechooser.ui Mon Apr 03 23:09:36 2023 -0500
@@ -33,28 +33,12 @@
<template class="GtkListItem">
- <object class="GtkBox">
- <property name="orientation">horizontal</property>
- <property name="spacing">6</property>
- <object class="GtkImage">
- <binding name="icon-name">
- <closure type="gchararray" function="pidgin_status_primitive_chooser_icon_name_cb">
- <lookup name="item">GtkListItem</lookup>
- <object class="GtkLabel">
- <property name="xalign">0</property>
- <closure type="gchararray" function="pidgin_status_primitive_chooser_label_cb">
- <lookup name="item">GtkListItem</lookup>
+ <object class="PidginStatusDisplay"> + <binding name="primitive"> + <closure type="PurpleStatusPrimitive" function="pidgin_status_primitive_chooser_primitive_cb"> + <lookup name="item">GtkListItem</lookup> @@ -71,7 +55,7 @@
- <item>extended-away</item>
+ <item>extended_away</item>