Commit c275426f authored by Evangelos Ribeiro Tzaras's avatar Evangelos Ribeiro Tzaras
Browse files

Merge branch 'rel_0.3.1-1' into 'pureos/byzantium'

Document and release 0.3.1-1pureos1

See merge request Librem5/debs/pkg-chatty!2
parents b5a07007 16ce91ee
chatty (0.3.1-1pureos1) byzantium; urgency=medium
* Upload to byzantium
-- Evangelos Ribeiro Tzaras <evangelos.tzaras@puri.sm> Sun, 30 May 2021 00:45:35 +0200
chatty (0.3.1-1) experimental; urgency=medium
* New upstream version 0.3.1
-- Evangelos Ribeiro Tzaras <devrtz-debian@fortysixandtwo.eu> Sat, 29 May 2021 21:02:08 +0200
chatty (0.3.0-1pureos1) byzantium; urgency=medium
* d/librem5-ci.yml: Add CI pipeline definitions
......
project(
'chatty', 'c', 'cpp',
version: '0.3.0',
version: '0.3.1',
meson_version: '>= 0.46.0',
)
......
This diff is collapsed.
......@@ -57,6 +57,9 @@ struct _ChattyApplication
char *uri;
guint open_uri_id;
gulong delete_id;
gulong open_chat_id;
gboolean daemon;
gboolean show_window;
gboolean enable_debug;
......@@ -239,6 +242,9 @@ chatty_application_finalize (GObject *object)
{
ChattyApplication *self = (ChattyApplication *)object;
g_clear_signal_handler (&self->open_chat_id, self->manager);
g_clear_signal_handler (&self->delete_id, self->main_window);
g_clear_handle_id (&self->open_uri_id, g_source_remove);
g_clear_object (&self->manager);
......@@ -374,15 +380,15 @@ chatty_application_activate (GApplication *application)
g_object_add_weak_pointer (G_OBJECT (self->main_window), (gpointer *)&self->main_window);
}
if (self->daemon)
g_signal_connect (G_OBJECT (self->main_window),
"delete-event",
G_CALLBACK (gtk_widget_hide_on_delete),
NULL);
if (self->daemon && !self->delete_id)
self->delete_id = g_signal_connect (self->main_window, "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete),
NULL);
g_signal_connect_object (self->manager, "open-chat",
G_CALLBACK (application_open_chat), self,
G_CONNECT_SWAPPED);
if (!self->open_chat_id)
self->open_chat_id = g_signal_connect_swapped (self->manager, "open-chat",
G_CALLBACK (application_open_chat),
self);
if (self->show_window)
gtk_window_present (GTK_WINDOW (self->main_window));
......
......@@ -154,6 +154,15 @@ chatty_avatar_set_item (ChattyAvatar *self,
g_return_if_fail (CHATTY_IS_AVATAR (self));
g_return_if_fail (!item || CHATTY_IS_ITEM (item));
if (self->item) {
g_signal_handlers_disconnect_by_func (self->item,
g_clear_object,
&self->item);
g_signal_handlers_disconnect_by_func (self->item,
avatar_changed_cb,
self);
}
if (!g_set_object (&self->item, item))
return;
......
......@@ -47,6 +47,9 @@ struct _ChattyChatView
GtkTextBuffer *message_input_buffer;
GtkAdjustment *vadjustment;
/* Signal ids */
GBinding *history_binding;
ChattyChat *chat;
char *last_message_id; /* id of last sent message, currently used only for SMS */
guint refresh_typing_id;
......@@ -88,28 +91,6 @@ enum {
static guint signals[N_SIGNALS];
static gboolean
chat_view_time_is_same_day (time_t time_a,
time_t time_b)
{
struct tm *tm;
int day_a, day_b;
if (difftime (time_a, time_b) > SECONDS_PER_DAY)
return FALSE;
tm = localtime (&time_a);
day_a = tm->tm_yday;
tm = localtime (&time_b);
day_b = tm->tm_yday;
if (day_a == day_b)
return TRUE;
return FALSE;
}
static gboolean
chat_view_hash_table_match_item (gpointer key,
gpointer value,
......@@ -321,12 +302,26 @@ messages_items_changed_cb (ChattyChatView *self,
if (added == 0)
return;
/* Don't hide footers in group chats */
if (!chatty_chat_is_im (self->chat))
return;
list = GTK_LIST_BOX (self->message_list);
/* Hide duplicate author labels in group chats */
if (!chatty_chat_is_im (self->chat) ||
CHATTY_IS_MA_CHAT (self->chat)) {
for (gint i = position; i < position + added; i++) {
next_row = gtk_list_box_get_row_at_index (list, i + 1);
if (!next_row)
break;
row = gtk_list_box_get_row_at_index (list, i);
msg = chatty_message_row_get_item (CHATTY_MESSAGE_ROW (row));
next_msg = chatty_message_row_get_item (CHATTY_MESSAGE_ROW (next_row));
if (chatty_message_user_matches (msg, next_msg))
chatty_message_row_hide_user_detail (CHATTY_MESSAGE_ROW (next_row));
}
}
for (gint i = position; i < position + added; i++) {
next_row = gtk_list_box_get_row_at_index (list, i + 1);
......@@ -340,11 +335,8 @@ messages_items_changed_cb (ChattyChatView *self,
next_msg = chatty_message_row_get_item (CHATTY_MESSAGE_ROW (next_row));
next_time = chatty_message_get_time (next_msg);
/*
* Hide time if the message following the current one belong to the same
* day
*/
if (chat_view_time_is_same_day (time, next_time))
/* Hide footer of the previous message if both have same time (in minutes) */
if (time / 60 == next_time / 60)
chatty_message_row_hide_footer (CHATTY_MESSAGE_ROW (row));
}
}
......@@ -807,6 +799,20 @@ chatty_chat_view_set_chat (ChattyChatView *self,
g_return_if_fail (CHATTY_IS_CHAT_VIEW (self));
g_return_if_fail (CHATTY_IS_CHAT (chat));
if (self->chat && chat != self->chat) {
g_signal_handlers_disconnect_by_func (chatty_chat_get_messages (self->chat),
messages_items_changed_cb,
self);
g_signal_handlers_disconnect_by_func (self->chat,
chat_encrypt_changed_cb,
self);
g_signal_handlers_disconnect_by_func (self->chat,
chat_buddy_typing_changed_cb,
self);
g_clear_object (&self->history_binding);
}
if (!g_set_object (&self->chat, chat))
return;
......@@ -817,22 +823,19 @@ chatty_chat_view_set_chat (ChattyChatView *self,
chatty_chat_get_messages (self->chat),
(GtkListBoxCreateWidgetFunc)chat_view_message_row_new,
self, NULL);
g_signal_connect_object (chatty_chat_get_messages (self->chat),
"items-changed",
G_CALLBACK (messages_items_changed_cb),
self,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
g_signal_connect_object (self->chat, "notify::encrypt",
G_CALLBACK (chat_encrypt_changed_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (self->chat, "notify::buddy-typing",
G_CALLBACK (chat_buddy_typing_changed_cb),
self,
G_CONNECT_SWAPPED);
g_object_bind_property (self->chat, "loading-history",
self->loading_spinner, "active",
G_BINDING_SYNC_CREATE);
g_signal_connect_swapped (chatty_chat_get_messages (self->chat),
"items-changed",
G_CALLBACK (messages_items_changed_cb),
self);
g_signal_connect_swapped (self->chat, "notify::encrypt",
G_CALLBACK (chat_encrypt_changed_cb),
self);
g_signal_connect_swapped (self->chat, "notify::buddy-typing",
G_CALLBACK (chat_buddy_typing_changed_cb),
self);
self->history_binding = g_object_bind_property (self->chat, "loading-history",
self->loading_spinner, "active",
G_BINDING_SYNC_CREATE);
chat_encrypt_changed_cb (self);
chat_buddy_typing_changed_cb (self);
......
......@@ -8,8 +8,6 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <math.h>
#include "purple.h"
#include "chatty-icons.h"
......@@ -43,360 +41,33 @@ chatty_icon_pixbuf_from_data (const guchar *buf,
return g_object_ref (pixbuf);
}
GdkPixbuf *
chatty_icon_shape_pixbuf_circular (GdkPixbuf *pixbuf)
{
cairo_format_t format;
cairo_surface_t *surface;
cairo_t *cr;
GdkPixbuf *ret;
int width, height, size;
format = CAIRO_FORMAT_ARGB32;
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
size = (width >= height) ? width : height;
surface = cairo_image_surface_create (format, size, size);
cr = cairo_create (surface);
cairo_set_antialias (cr, CAIRO_ANTIALIAS_SUBPIXEL);
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
cairo_arc (cr,
size / 2,
size / 2,
size / 2,
0,
2 * M_PI);
cairo_fill (cr);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_arc (cr,
size / 2,
size / 2,
size / 2,
0,
2 * M_PI);
cairo_clip (cr);
cairo_paint (cr);
ret = gdk_pixbuf_get_from_surface (surface,
0,
0,
size,
size);
cairo_surface_destroy (surface);
cairo_destroy (cr);
return ret;
}
GdkPixbuf *
chatty_icon_get_buddy_icon (PurpleBlistNode *node,
const char *name,
guint size,
const char *color,
gboolean greyed)
chatty_icon_get_buddy_icon (PurpleBlistNode *node)
{
// TODO needs to be detangled and segregated
gsize len;
PurpleBuddy *buddy = NULL;
PurpleGroup *group = NULL;
const guchar *data = NULL;
GdkPixbuf *buf = NULL, *ret = NULL;
cairo_surface_t *surface;
cairo_t *cr;
GdkPixbuf *buf = NULL;
PurpleBuddyIcon *icon = NULL;
PurpleAccount *account = NULL;
PurpleContact *contact = NULL;
PurpleStoredImage *custom_img;
PurplePluginProtocolInfo *prpl_info = NULL;
const char *symbol = NULL;
gint orig_width,
orig_height,
scale_width,
scale_height;
float scale_size;
gchar *sub_str;
gdouble color_r;
gdouble color_g;
gdouble color_b;
g_return_val_if_fail (color, NULL);
// convert colors for drawing the cairo background
if (color) {
sub_str = g_utf8_substring (color, 0, 2);
color_r = (gdouble)g_ascii_strtoll (sub_str, NULL, 16) / 255;
g_free (sub_str);
sub_str = g_utf8_substring (color, 2, 4);
color_g = (gdouble)g_ascii_strtoll (sub_str, NULL, 16) / 255;
g_free (sub_str);
sub_str = g_utf8_substring (color, 4, 6);
color_b = (gdouble)g_ascii_strtoll (sub_str, NULL, 16) / 255;
g_free (sub_str);
}
// get the buddy and retrieve an icon if available
if (node) {
if (PURPLE_BLIST_NODE_IS_CONTACT (node)) {
buddy = purple_contact_get_priority_buddy ((PurpleContact*)node);
symbol = "avatar-default-symbolic";
contact = (PurpleContact*)node;
} else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
buddy = (PurpleBuddy*)node;
symbol = "avatar-default-symbolic";
contact = purple_buddy_get_contact (buddy);
} else if (PURPLE_BLIST_NODE_IS_GROUP(node)) {
group = (PurpleGroup*)node;
} else if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
buddy = (PurpleBuddy*)node;
symbol = "system-users-symbolic";
} else {
return NULL;
}
if(account && account->gc) {
prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(account->gc->prpl);
}
if (contact) {
custom_img = purple_buddy_icons_node_find_custom_icon ((PurpleBlistNode*)contact);
} else {
custom_img = purple_buddy_icons_node_find_custom_icon (node);
}
if (custom_img) {
data = purple_imgstore_get_data (custom_img);
len = purple_imgstore_get_size (custom_img);
}
purple_imgstore_unref (custom_img);
if (data == NULL && buddy && PURPLE_BLIST_NODE_IS_BUDDY(node)) {
icon = purple_buddy_icons_find (buddy->account, buddy->name);
if (icon) {
data = purple_buddy_icon_get_data (icon, &len);
}
}
if (data != NULL) {
buf = chatty_icon_pixbuf_from_data (data, len);
purple_buddy_icon_unref (icon);
// create a grey background to make buddy icons
// look nicer that don't have square format
color_r = color_g = color_b = 0.7;
} else {
GtkIconTheme *icon_theme;
icon_theme = gtk_icon_theme_get_default ();
buf = gtk_icon_theme_load_icon (icon_theme,
symbol,
size,
0,
NULL);
}
}
// create an avatar with the initial of the
// buddy name if there is no icon available
if (data == NULL && name != NULL) {
PangoFontDescription *font_desc;
PangoLayout *layout;
int width = size;
int height = size;
int pango_width, pango_height;
char tmp[4];
char *initial_char;
g_autofree char *font = NULL;
g_utf8_strncpy (tmp, name, 1);
initial_char = g_utf8_strup (tmp, 1);
surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
cr = cairo_create (surface);
cairo_set_source_rgb (cr, color_r, color_g, color_b);
cairo_paint (cr);
cairo_set_source_rgb (cr, 0.95, 0.95, 0.95);
font = g_strdup_printf ("Sans %d", (int)ceil (size / 2.5));
layout = pango_cairo_create_layout (cr);
pango_layout_set_text (layout, initial_char, -1);
font_desc = pango_font_description_from_string (font);
pango_layout_set_font_description (layout, font_desc);
pango_font_description_free (font_desc);
pango_layout_get_size (layout, &pango_width, &pango_height);
cairo_translate (cr, size/2, size/2);
cairo_move_to (cr,
-((double)pango_width / PANGO_SCALE) / 2,
-((double)pango_height / PANGO_SCALE) / 2);
pango_cairo_show_layout (cr, layout);
buf = gdk_pixbuf_get_from_surface (surface,
0,
0,
width,
height);
cairo_surface_destroy (surface);
g_object_unref (layout);
cairo_destroy (cr);
g_free (initial_char);
}
if (!buf) {
if (!node || !PURPLE_BLIST_NODE_IS_CHAT (node))
return NULL;
}
if (greyed) {
gboolean offline = FALSE, idle = FALSE;
if (buddy) {
PurplePresence *presence = purple_buddy_get_presence(buddy);
if (!PURPLE_BUDDY_IS_ONLINE(buddy))
offline = TRUE;
if (purple_presence_is_idle(presence))
idle = TRUE;
} else if (group) {
if (purple_blist_get_group_online_count (group) == 0)
offline = TRUE;
}
if (offline) {
gdk_pixbuf_saturate_and_pixelate (buf, buf, 0.0, FALSE);
}
if (idle) {
gdk_pixbuf_saturate_and_pixelate (buf, buf, 0.25, FALSE);
}
}
scale_width = orig_width = gdk_pixbuf_get_width (buf);
scale_height = orig_height = gdk_pixbuf_get_height (buf);
if (prpl_info &&
prpl_info->icon_spec.scale_rules & PURPLE_ICON_SCALE_DISPLAY) {
purple_buddy_icon_get_scale_size (&prpl_info->icon_spec,
&scale_width,
&scale_height);
}
scale_size = (float)size;
if (size) {
GdkPixbuf *tmpbuf;
if (scale_height > scale_width) {
scale_width = scale_size * (double)scale_width / (double)scale_height;
scale_height = scale_size;
} else {
scale_height = scale_size * (double)scale_height / (double)scale_width;
scale_width = scale_size;
}
tmpbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, scale_width, scale_height);
gdk_pixbuf_fill (tmpbuf, 0x00000000);
gdk_pixbuf_scale (buf, tmpbuf, 0, 0,
scale_width, scale_height,
0, 0,
(double)scale_width / (double)orig_width,
(double)scale_height / (double)orig_height,
GDK_INTERP_BILINEAR);
custom_img = purple_buddy_icons_node_find_custom_icon (node);
ret = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, scale_size, scale_size);
gdk_pixbuf_fill (ret, 0x00000000);
gdk_pixbuf_copy_area (tmpbuf,
0, 0,
scale_width, scale_height,
ret,
(scale_size - scale_width) / 2,
(scale_size - scale_height) / 2);
g_object_unref (G_OBJECT(tmpbuf));
} else {
ret = gdk_pixbuf_scale_simple (buf,
scale_width,
scale_height,
GDK_INTERP_HYPER);
}
g_object_unref (G_OBJECT(buf));
return chatty_icon_shape_pixbuf_circular (ret);
}
/* Altered from do_colorshift in gnome-panel */
void
chatty_icon_do_alphashift (GdkPixbuf *pixbuf,
int shift)
{
gint i, j;
gint width, height, padding;
guchar *pixels;
int val;
if (!gdk_pixbuf_get_has_alpha (pixbuf)) {
return;
}
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
padding = gdk_pixbuf_get_rowstride (pixbuf) - width * 4;
pixels = gdk_pixbuf_get_pixels (pixbuf);
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
pixels++;
pixels++;
pixels++;
val = *pixels - shift;
*(pixels++) = CLAMP(val, 0, 255);
}
pixels += padding;
if (custom_img) {
data = purple_imgstore_get_data (custom_img);
len = purple_imgstore_get_size (custom_img);
}
}
GIcon *
chatty_icon_get_gicon_from_pixbuf (GdkPixbuf *pixbuf)
{
GIcon *icon;
g_autoptr(GBytes) bytes = NULL;
g_autofree char *buffer = NULL;
gsize size;
g_autoptr(GError) error = NULL;
gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &size, "png", &error, NULL);
purple_imgstore_unref (custom_img);
if (error != NULL) {
g_debug ("%s: Could not save pixbuf to buffer: %s", __func__, error->message);
if (data != NULL) {
buf = chatty_icon_pixbuf_from_data (data, len);
purple_buddy_icon_unref (icon);
return NULL;
return buf;
}
bytes = g_bytes_new (buffer, size);
icon = g_bytes_icon_new (bytes);
return icon;
return NULL;
}
......@@ -10,22 +10,8 @@
#include "purple.h"
typedef enum
{
CHATTY_ICON_SIZE_SMALL = 28,
CHATTY_ICON_SIZE_MEDIUM = 36,
CHATTY_ICON_SIZE_LARGE = 96
} ChattyPurpleIconSize;