mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-03-19 20:20:18 +00:00
Update maingui.c
This commit is contained in:
committed by
GitHub
parent
24a5c3b50d
commit
fa1912bb5d
@@ -76,6 +76,13 @@ enum
|
|||||||
#define TAG_IRC 0 /* server, channel, dialog */
|
#define TAG_IRC 0 /* server, channel, dialog */
|
||||||
#define TAG_UTIL 1 /* dcc, notify, chanlist */
|
#define TAG_UTIL 1 /* dcc, notify, chanlist */
|
||||||
|
|
||||||
|
static void mg_apply_emoji_fallback_widget (GtkWidget *widget);
|
||||||
|
static void mg_apply_emoji_primary_widget (GtkWidget *widget);
|
||||||
|
static gchar *mg_font_string_with_emoji_fallback (const gchar *font_string);
|
||||||
|
static void mg_emoji_button_cb (GtkWidget *widget, session_gui *gui);
|
||||||
|
static GtkWidget *mg_create_emoji_menu (session_gui *gui);
|
||||||
|
static void mg_emoji_insert_cb (GtkMenuItem *item, session_gui *gui);
|
||||||
|
|
||||||
static void mg_create_entry (session *sess, GtkWidget *box);
|
static void mg_create_entry (session *sess, GtkWidget *box);
|
||||||
static void mg_create_search (session *sess, GtkWidget *box);
|
static void mg_create_search (session *sess, GtkWidget *box);
|
||||||
static void mg_link_irctab (session *sess, int focus);
|
static void mg_link_irctab (session *sess, int focus);
|
||||||
@@ -2082,6 +2089,7 @@ mg_create_chanmodebuttons (session_gui *gui, GtkWidget *box)
|
|||||||
gtk_entry_set_max_length (GTK_ENTRY (gui->key_entry), 23);
|
gtk_entry_set_max_length (GTK_ENTRY (gui->key_entry), 23);
|
||||||
gtk_widget_set_size_request (gui->key_entry, 115, -1);
|
gtk_widget_set_size_request (gui->key_entry, 115, -1);
|
||||||
gtk_box_pack_start (GTK_BOX (box), gui->key_entry, 0, 0, 0);
|
gtk_box_pack_start (GTK_BOX (box), gui->key_entry, 0, 0, 0);
|
||||||
|
mg_apply_emoji_fallback_widget (gui->key_entry);
|
||||||
g_signal_connect (G_OBJECT (gui->key_entry), "activate",
|
g_signal_connect (G_OBJECT (gui->key_entry), "activate",
|
||||||
G_CALLBACK (mg_key_entry_cb), NULL);
|
G_CALLBACK (mg_key_entry_cb), NULL);
|
||||||
|
|
||||||
@@ -2094,6 +2102,7 @@ mg_create_chanmodebuttons (session_gui *gui, GtkWidget *box)
|
|||||||
gtk_entry_set_max_length (GTK_ENTRY (gui->limit_entry), 10);
|
gtk_entry_set_max_length (GTK_ENTRY (gui->limit_entry), 10);
|
||||||
gtk_widget_set_size_request (gui->limit_entry, 30, -1);
|
gtk_widget_set_size_request (gui->limit_entry, 30, -1);
|
||||||
gtk_box_pack_start (GTK_BOX (box), gui->limit_entry, 0, 0, 0);
|
gtk_box_pack_start (GTK_BOX (box), gui->limit_entry, 0, 0, 0);
|
||||||
|
mg_apply_emoji_fallback_widget (gui->limit_entry);
|
||||||
g_signal_connect (G_OBJECT (gui->limit_entry), "activate",
|
g_signal_connect (G_OBJECT (gui->limit_entry), "activate",
|
||||||
G_CALLBACK (mg_limit_entry_cb), NULL);
|
G_CALLBACK (mg_limit_entry_cb), NULL);
|
||||||
|
|
||||||
@@ -2183,6 +2192,7 @@ mg_create_topicbar (session *sess, GtkWidget *box)
|
|||||||
gtk_widget_set_name (topic, "zoitechat-inputbox");
|
gtk_widget_set_name (topic, "zoitechat-inputbox");
|
||||||
sexy_spell_entry_set_checked (SEXY_SPELL_ENTRY (topic), FALSE);
|
sexy_spell_entry_set_checked (SEXY_SPELL_ENTRY (topic), FALSE);
|
||||||
gtk_container_add (GTK_CONTAINER (hbox), topic);
|
gtk_container_add (GTK_CONTAINER (hbox), topic);
|
||||||
|
mg_apply_emoji_fallback_widget (topic);
|
||||||
g_signal_connect (G_OBJECT (topic), "activate",
|
g_signal_connect (G_OBJECT (topic), "activate",
|
||||||
G_CALLBACK (mg_topic_cb), 0);
|
G_CALLBACK (mg_topic_cb), 0);
|
||||||
|
|
||||||
@@ -2301,6 +2311,7 @@ void
|
|||||||
mg_update_xtext (GtkWidget *wid)
|
mg_update_xtext (GtkWidget *wid)
|
||||||
{
|
{
|
||||||
GtkXText *xtext = GTK_XTEXT (wid);
|
GtkXText *xtext = GTK_XTEXT (wid);
|
||||||
|
gchar *font_with_emoji;
|
||||||
|
|
||||||
gtk_xtext_set_palette (xtext, colors);
|
gtk_xtext_set_palette (xtext, colors);
|
||||||
gtk_xtext_set_max_lines (xtext, prefs.hex_text_max_lines);
|
gtk_xtext_set_max_lines (xtext, prefs.hex_text_max_lines);
|
||||||
@@ -2309,11 +2320,16 @@ mg_update_xtext (GtkWidget *wid)
|
|||||||
gtk_xtext_set_show_marker (xtext, prefs.hex_text_show_marker);
|
gtk_xtext_set_show_marker (xtext, prefs.hex_text_show_marker);
|
||||||
gtk_xtext_set_show_separator (xtext, prefs.hex_text_indent ? prefs.hex_text_show_sep : 0);
|
gtk_xtext_set_show_separator (xtext, prefs.hex_text_indent ? prefs.hex_text_show_sep : 0);
|
||||||
gtk_xtext_set_indent (xtext, prefs.hex_text_indent);
|
gtk_xtext_set_indent (xtext, prefs.hex_text_indent);
|
||||||
if (!gtk_xtext_set_font (xtext, prefs.hex_text_font))
|
|
||||||
|
/* Ensure emoji-capable fallback for the main chat buffer font */
|
||||||
|
font_with_emoji = mg_font_string_with_emoji_fallback (prefs.hex_text_font);
|
||||||
|
if (!gtk_xtext_set_font (xtext, font_with_emoji))
|
||||||
{
|
{
|
||||||
|
g_free (font_with_emoji);
|
||||||
fe_message ("Failed to open any font. I'm out of here!", FE_MSG_WAIT | FE_MSG_ERROR);
|
fe_message ("Failed to open any font. I'm out of here!", FE_MSG_WAIT | FE_MSG_ERROR);
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
g_free (font_with_emoji);
|
||||||
|
|
||||||
gtk_xtext_refresh (xtext);
|
gtk_xtext_refresh (xtext);
|
||||||
}
|
}
|
||||||
@@ -2792,6 +2808,202 @@ mg_inputbox_rightclick (GtkEntry *entry, GtkWidget *menu)
|
|||||||
mg_create_color_menu (menu, NULL);
|
mg_create_color_menu (menu, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- *
|
||||||
|
* Emoji font handling (GTK2)
|
||||||
|
*
|
||||||
|
* Goal: prefer color emoji fonts when available, without changing existing
|
||||||
|
* font size/style/weight, and without breaking user-configured fonts.
|
||||||
|
* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static const char *mg_emoji_family_fallback =
|
||||||
|
"Noto Color Emoji, Segoe UI Emoji, Apple Color Emoji, Twemoji Mozilla, EmojiOne Color";
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
mg_family_already_has_emoji (const gchar *family)
|
||||||
|
{
|
||||||
|
if (!family || !*family)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* cheap but effective */
|
||||||
|
return (strstr (family, "Noto Color Emoji") != NULL) ||
|
||||||
|
(strstr (family, "Segoe UI Emoji") != NULL) ||
|
||||||
|
(strstr (family, "Apple Color Emoji") != NULL) ||
|
||||||
|
(strstr (family, "Twemoji") != NULL) ||
|
||||||
|
(strstr (family, "EmojiOne") != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PangoFontDescription *
|
||||||
|
mg_fontdesc_with_fallback (const PangoFontDescription *base_desc, gboolean emoji_first)
|
||||||
|
{
|
||||||
|
PangoFontDescription *desc;
|
||||||
|
const gchar *base_family;
|
||||||
|
gchar *family_list;
|
||||||
|
|
||||||
|
if (!base_desc)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
desc = pango_font_description_copy (base_desc);
|
||||||
|
base_family = pango_font_description_get_family (desc);
|
||||||
|
|
||||||
|
if (mg_family_already_has_emoji (base_family))
|
||||||
|
return desc;
|
||||||
|
|
||||||
|
if (emoji_first)
|
||||||
|
{
|
||||||
|
family_list = g_strdup_printf ("%s, %s",
|
||||||
|
mg_emoji_family_fallback,
|
||||||
|
(base_family && *base_family) ? base_family : "Sans");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
family_list = g_strdup_printf ("%s, %s",
|
||||||
|
(base_family && *base_family) ? base_family : "Sans",
|
||||||
|
mg_emoji_family_fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
pango_font_description_set_family (desc, family_list);
|
||||||
|
g_free (family_list);
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_apply_emoji_fallback_widget (GtkWidget *widget)
|
||||||
|
{
|
||||||
|
GtkStyle *style;
|
||||||
|
PangoFontDescription *desc;
|
||||||
|
|
||||||
|
if (!widget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
style = gtk_widget_get_style (widget);
|
||||||
|
if (!style || !style->font_desc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
desc = mg_fontdesc_with_fallback (style->font_desc, FALSE);
|
||||||
|
if (!desc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
gtk_widget_modify_font (widget, desc);
|
||||||
|
pango_font_description_free (desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_apply_emoji_primary_widget (GtkWidget *widget)
|
||||||
|
{
|
||||||
|
GtkStyle *style;
|
||||||
|
PangoFontDescription *desc;
|
||||||
|
|
||||||
|
if (!widget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
style = gtk_widget_get_style (widget);
|
||||||
|
if (!style || !style->font_desc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
desc = mg_fontdesc_with_fallback (style->font_desc, TRUE);
|
||||||
|
if (!desc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
gtk_widget_modify_font (widget, desc);
|
||||||
|
pango_font_description_free (desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gchar *
|
||||||
|
mg_font_string_with_emoji_fallback (const gchar *font_string)
|
||||||
|
{
|
||||||
|
PangoFontDescription *base;
|
||||||
|
PangoFontDescription *with_fallback;
|
||||||
|
gchar *out;
|
||||||
|
|
||||||
|
/* Keep existing behavior if unset, but still allow emoji fallback */
|
||||||
|
base = pango_font_description_from_string (font_string && *font_string ? font_string : "Sans 10");
|
||||||
|
with_fallback = mg_fontdesc_with_fallback (base, FALSE);
|
||||||
|
|
||||||
|
out = pango_font_description_to_string (with_fallback ? with_fallback : base);
|
||||||
|
|
||||||
|
if (with_fallback)
|
||||||
|
pango_font_description_free (with_fallback);
|
||||||
|
pango_font_description_free (base);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- *
|
||||||
|
* Emoji picker (optional UI sugar)
|
||||||
|
* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_emoji_insert_cb (GtkMenuItem *item, session_gui *gui)
|
||||||
|
{
|
||||||
|
const char *emoji = g_object_get_data (G_OBJECT (item), "emoji");
|
||||||
|
gint pos;
|
||||||
|
|
||||||
|
if (!emoji || !gui || !gui->input_box)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pos = SPELL_ENTRY_GET_POS (gui->input_box);
|
||||||
|
gtk_editable_insert_text (GTK_EDITABLE (gui->input_box), emoji, -1, &pos);
|
||||||
|
gtk_editable_set_position (GTK_EDITABLE (gui->input_box), pos);
|
||||||
|
gtk_widget_grab_focus (gui->input_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *
|
||||||
|
mg_create_emoji_menu (session_gui *gui)
|
||||||
|
{
|
||||||
|
/* VS16 (emoji presentation). No, it does not need a space. */
|
||||||
|
#define VS16 "\xEF\xB8\x8F"
|
||||||
|
static const char *emoji_list[] = {
|
||||||
|
"😀","😃","😄","😁","😆","😂","🤣","😊","😇","😉","😍",
|
||||||
|
"🥰","😘","😜","🤪","😎","🤩","🤔","🤨","😐","😶","🙄",
|
||||||
|
"😏","😣","😥","😮","😯","😪","😴","😌","😔","😢",
|
||||||
|
"😭","😤","😠","😡","🤬","🥺","😳","🤗","🤭","🤫",
|
||||||
|
"🤐","😷","🤒","🤕","🤢","🤮","🥵","🥶","🥴","🤯",
|
||||||
|
"👍"VS16,"👎"VS16,"👏"VS16,"🙌"VS16,"🙏"VS16,"💪"VS16,
|
||||||
|
"👀"VS16,"💯"VS16,"✅"VS16,"❌"VS16,"🎉"VS16,"🔥"VS16,
|
||||||
|
"❤","💔","💖","💙","💚","💛","💜","🧡","🤍","🖤",
|
||||||
|
"⭐"VS16,"🌟","✨","⚡"VS16,"☀","🌈","☕"VS16,"🍕",
|
||||||
|
"🍔","🍟","🍣","🍩","🎂","🍺","🍷","🎁","🎈","🎯",
|
||||||
|
"🎵","🎶","🎮","🚀","✈","🚗","🚕","🚲","🏡","🌍",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
#undef VS16
|
||||||
|
|
||||||
|
GtkWidget *menu;
|
||||||
|
const int columns = 8;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
menu = gtk_menu_new ();
|
||||||
|
|
||||||
|
for (i = 0; emoji_list[i]; i++)
|
||||||
|
{
|
||||||
|
GtkWidget *item = gtk_menu_item_new_with_label (emoji_list[i]);
|
||||||
|
int row = i / columns;
|
||||||
|
int col = i % columns;
|
||||||
|
|
||||||
|
g_object_set_data_full (G_OBJECT (item), "emoji", g_strdup (emoji_list[i]), g_free);
|
||||||
|
g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (mg_emoji_insert_cb), gui);
|
||||||
|
|
||||||
|
/* Prefer emoji fonts for the label itself */
|
||||||
|
mg_apply_emoji_primary_widget (item);
|
||||||
|
|
||||||
|
gtk_menu_attach (GTK_MENU (menu), item, col, col + 1, row, row + 1);
|
||||||
|
gtk_widget_show (item);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_connect (G_OBJECT (menu), "selection-done", G_CALLBACK (gtk_widget_destroy), NULL);
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_emoji_button_cb (GtkWidget *widget, session_gui *gui)
|
||||||
|
{
|
||||||
|
GtkWidget *menu;
|
||||||
|
|
||||||
|
menu = mg_create_emoji_menu (gui);
|
||||||
|
gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ());
|
||||||
|
}
|
||||||
|
|
||||||
/* Search bar adapted from Conspire's by William Pitcock */
|
/* Search bar adapted from Conspire's by William Pitcock */
|
||||||
|
|
||||||
#define SEARCH_CHANGE 1
|
#define SEARCH_CHANGE 1
|
||||||
@@ -2933,6 +3145,7 @@ mg_create_search(session *sess, GtkWidget *box)
|
|||||||
gui->shentry = entry = gtk_entry_new();
|
gui->shentry = entry = gtk_entry_new();
|
||||||
gtk_box_pack_start(GTK_BOX(gui->shbox), entry, FALSE, FALSE, 0);
|
gtk_box_pack_start(GTK_BOX(gui->shbox), entry, FALSE, FALSE, 0);
|
||||||
gtk_widget_set_size_request (gui->shentry, 180, -1);
|
gtk_widget_set_size_request (gui->shentry, 180, -1);
|
||||||
|
mg_apply_emoji_fallback_widget (entry);
|
||||||
gui->search_changed_signal = g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(search_handle_change), sess);
|
gui->search_changed_signal = g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(search_handle_change), sess);
|
||||||
g_signal_connect (G_OBJECT (entry), "key_press_event", G_CALLBACK (search_handle_esc), sess);
|
g_signal_connect (G_OBJECT (entry), "key_press_event", G_CALLBACK (search_handle_esc), sess);
|
||||||
g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(mg_search_handle_next), sess);
|
g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(mg_search_handle_next), sess);
|
||||||
@@ -2979,7 +3192,7 @@ mg_create_search(session *sess, GtkWidget *box)
|
|||||||
static void
|
static void
|
||||||
mg_create_entry (session *sess, GtkWidget *box)
|
mg_create_entry (session *sess, GtkWidget *box)
|
||||||
{
|
{
|
||||||
GtkWidget *hbox, *but, *entry;
|
GtkWidget *hbox, *but, *entry, *emoji_button;
|
||||||
session_gui *gui = sess->gui;
|
session_gui *gui = sess->gui;
|
||||||
|
|
||||||
hbox = gtk_hbox_new (FALSE, 0);
|
hbox = gtk_hbox_new (FALSE, 0);
|
||||||
@@ -3004,7 +3217,7 @@ mg_create_entry (session *sess, GtkWidget *box)
|
|||||||
G_CALLBACK (mg_inputbox_cb), gui);
|
G_CALLBACK (mg_inputbox_cb), gui);
|
||||||
g_signal_connect (G_OBJECT (entry), "changed",
|
g_signal_connect (G_OBJECT (entry), "changed",
|
||||||
G_CALLBACK (key_check_replace_on_change), NULL);
|
G_CALLBACK (key_check_replace_on_change), NULL);
|
||||||
gtk_container_add (GTK_CONTAINER (hbox), entry);
|
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
|
||||||
|
|
||||||
gtk_widget_set_name (entry, "zoitechat-inputbox");
|
gtk_widget_set_name (entry, "zoitechat-inputbox");
|
||||||
g_signal_connect (G_OBJECT (entry), "key_press_event",
|
g_signal_connect (G_OBJECT (entry), "key_press_event",
|
||||||
@@ -3019,6 +3232,18 @@ mg_create_entry (session *sess, GtkWidget *box)
|
|||||||
|
|
||||||
if (prefs.hex_gui_input_style)
|
if (prefs.hex_gui_input_style)
|
||||||
mg_apply_entry_style (entry);
|
mg_apply_entry_style (entry);
|
||||||
|
|
||||||
|
/* Make emoji render in the input box regardless of chosen font */
|
||||||
|
mg_apply_emoji_fallback_widget (entry);
|
||||||
|
|
||||||
|
/* Optional emoji button (kept since you already added it) */
|
||||||
|
emoji_button = gtk_button_new_with_label ("😊");
|
||||||
|
gtk_button_set_relief (GTK_BUTTON (emoji_button), GTK_RELIEF_NONE);
|
||||||
|
gtk_widget_set_can_focus (emoji_button, FALSE);
|
||||||
|
gtk_widget_set_tooltip_text (emoji_button, _("Insert emoji"));
|
||||||
|
mg_apply_emoji_primary_widget (emoji_button);
|
||||||
|
g_signal_connect (G_OBJECT (emoji_button), "clicked", G_CALLBACK (mg_emoji_button_cb), gui);
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox), emoji_button, FALSE, FALSE, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
Reference in New Issue
Block a user