1 Commits

Author SHA1 Message Date
a4afb420ca New Emoji Menu and Emoji Version 17.0 support. 2026-07-10 16:30:54 -06:00
14 changed files with 70 additions and 159 deletions

View File

@@ -119,9 +119,8 @@ jobs:
cp -a /usr/lib/x86_64-linux-gnu/libpython3*.so* AppDir/usr/lib/x86_64-linux-gnu/ cp -a /usr/lib/x86_64-linux-gnu/libpython3*.so* AppDir/usr/lib/x86_64-linux-gnu/
fi fi
# The emoji font is not bundled on Linux; the AppImage uses the test -f AppDir/usr/share/fonts/zoitechat/NotoColorEmoji.ttf
# host system's emoji font (e.g. fonts-noto-color-emoji). test -f AppDir/usr/share/doc/zoitechat/fonts/OFL.txt
test ! -e AppDir/usr/share/fonts/zoitechat/NotoColorEmoji.ttf
if [ -d "/usr/lib/x86_64-linux-gnu/gtk-3.0/modules" ]; then if [ -d "/usr/lib/x86_64-linux-gnu/gtk-3.0/modules" ]; then
install -d AppDir/usr/lib/x86_64-linux-gnu/gtk-3.0 install -d AppDir/usr/lib/x86_64-linux-gnu/gtk-3.0
@@ -185,6 +184,14 @@ jobs:
export GTK_PATH="$gtk_path_entries${GTK_PATH:+:$GTK_PATH}" export GTK_PATH="$gtk_path_entries${GTK_PATH:+:$GTK_PATH}"
fi fi
if [ -d "$APPDIR/etc/fonts" ]; then
export FONTCONFIG_SYSROOT="$APPDIR"
export FONTCONFIG_PATH="$APPDIR/etc/fonts${FONTCONFIG_PATH:+:$FONTCONFIG_PATH}"
if [ -f "$APPDIR/etc/fonts/fonts.conf" ]; then
export FONTCONFIG_FILE="$APPDIR/etc/fonts/fonts.conf"
fi
fi
if [ -d "$APPDIR/usr/lib/x86_64-linux-gnu/zoitechat/plugins" ]; then if [ -d "$APPDIR/usr/lib/x86_64-linux-gnu/zoitechat/plugins" ]; then
export ZOITECHAT_LIBDIR="$APPDIR/usr/lib/x86_64-linux-gnu/zoitechat/plugins" export ZOITECHAT_LIBDIR="$APPDIR/usr/lib/x86_64-linux-gnu/zoitechat/plugins"
elif [ -d "$APPDIR/usr/lib/zoitechat/plugins" ]; then elif [ -d "$APPDIR/usr/lib/zoitechat/plugins" ]; then

View File

@@ -5,14 +5,9 @@ Unicode Emoji 17.0. It is vendored from Debian's
`fonts-noto-color-emoji` 2.051 package, built from the corresponding `fonts-noto-color-emoji` 2.051 package, built from the corresponding
Google Noto Emoji release. Google Noto Emoji release.
The font is bundled only with Windows builds, where it is installed Official ZoiteChat packages install the font inside the application and
inside the application and registered only for the ZoiteChat process. register it only for the ZoiteChat process. It is not installed as a
It is not installed as a global operating-system font. global operating-system font.
Linux (and other Unix) builds do not install this file. They rely on
the emoji font provided by the operating system instead — typically the
distribution's Noto Color Emoji package (`fonts-noto-color-emoji` on
Debian/Ubuntu, `google-noto-color-emoji-fonts` on Fedora).
Upstream release: https://github.com/googlefonts/noto-emoji/releases/tag/v2.051 Upstream release: https://github.com/googlefonts/noto-emoji/releases/tag/v2.051

View File

@@ -3,11 +3,7 @@ if get_option('plugin')
endif endif
if get_option('gtk-frontend') if get_option('gtk-frontend')
# The bundled emoji font ships only with Windows builds; Linux and other subdir('fonts')
# Unix systems use the system emoji font package instead.
if host_machine.system() == 'windows'
subdir('fonts')
endif
subdir('icons') subdir('icons')
subdir('misc') subdir('misc')
subdir('man') subdir('man')

View File

@@ -66,7 +66,8 @@
], ],
"post-install": [ "post-install": [
"install -d /app/extensions", "install -d /app/extensions",
"test ! -e /app/share/fonts/zoitechat/NotoColorEmoji.ttf" "test -f /app/share/fonts/zoitechat/NotoColorEmoji.ttf",
"test -f /app/share/doc/zoitechat/fonts/OFL.txt"
], ],
"sources": [ "sources": [
{ {

View File

@@ -20,6 +20,7 @@ libcanberra_dep = dependency('libcanberra', version: '>= 0.22',
required: get_option('libcanberra')) required: get_option('libcanberra'))
dbus_dep = dependency('gio-2.0', required: get_option('dbus')) dbus_dep = dependency('gio-2.0', required: get_option('dbus'))
libsecret_dep = dependency('libsecret-1', required: false) libsecret_dep = dependency('libsecret-1', required: false)
fontconfig_dep = dependency('fontconfig', required: false)
global_deps = [] global_deps = []
if cc.get_id() == 'msvc' if cc.get_id() == 'msvc'
@@ -35,6 +36,9 @@ config_h.set_quoted('PACKAGE_NAME', meson.project_name())
config_h.set_quoted('GETTEXT_PACKAGE', 'zoitechat') config_h.set_quoted('GETTEXT_PACKAGE', 'zoitechat')
config_h.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), config_h.set_quoted('LOCALEDIR', join_paths(get_option('prefix'),
get_option('datadir'), 'locale')) get_option('datadir'), 'locale'))
config_h.set_quoted('ZOITECHAT_EMOJI_FONT_FILE',
join_paths(get_option('prefix'), get_option('datadir'), 'fonts',
'zoitechat', 'NotoColorEmoji.ttf'))
config_h.set10('ENABLE_NLS', true) config_h.set10('ENABLE_NLS', true)
# Optional features # Optional features
@@ -42,6 +46,7 @@ config_h.set('USE_OPENSSL', libssl_dep.found())
config_h.set('USE_LIBCANBERRA', libcanberra_dep.found()) config_h.set('USE_LIBCANBERRA', libcanberra_dep.found())
config_h.set('USE_DBUS', dbus_dep.found()) config_h.set('USE_DBUS', dbus_dep.found())
config_h.set('HAVE_LIBSECRET', libsecret_dep.found()) config_h.set('HAVE_LIBSECRET', libsecret_dep.found())
config_h.set('HAVE_FONTCONFIG', fontconfig_dep.found())
config_h.set('USE_PLUGIN', get_option('plugin')) config_h.set('USE_PLUGIN', get_option('plugin'))
config_h.set('USE_GTK_FRONTEND', get_option('gtk-frontend')) config_h.set('USE_GTK_FRONTEND', get_option('gtk-frontend'))

View File

@@ -31,7 +31,6 @@ BuildRequires: pkgconfig(lua)
BuildRequires: pkgconfig(openssl) >= 0.9.8 BuildRequires: pkgconfig(openssl) >= 0.9.8
BuildRequires: pkgconfig(python3) BuildRequires: pkgconfig(python3)
Requires: google-noto-color-emoji-fonts
Requires: hicolor-icon-theme Requires: hicolor-icon-theme
Requires: iso-codes Requires: iso-codes

View File

@@ -40,7 +40,7 @@
#define DEF_FONT "Monospace 9" #define DEF_FONT "Monospace 9"
#ifdef WIN32 #ifdef WIN32
#define DEF_FONT_ALTER "Segoe UI Emoji,Segoe UI Symbol,Arial Unicode MS,Lucida Sans Unicode,Meiryo,Symbola,Unifont" #define DEF_FONT_ALTER "Segoe UI Emoji,Arial Unicode MS,Lucida Sans Unicode,Meiryo,Symbola,Unifont"
#else #else
#define DEF_FONT_ALTER "Arial Unicode MS,Segoe UI Emoji,Lucida Sans Unicode,Meiryo,Symbola,Unifont" #define DEF_FONT_ALTER "Arial Unicode MS,Segoe UI Emoji,Lucida Sans Unicode,Meiryo,Symbola,Unifont"
#endif #endif

View File

@@ -109,58 +109,6 @@ static void server_disconnect (session * sess, int sendquit, int err);
static int server_cleanup (server * serv); static int server_cleanup (server * serv);
static void server_connect (server *serv, char *hostname, int port, int no_login); static void server_connect (server *serv, char *hostname, int port, int no_login);
typedef struct
{
server *serv;
char hostname[128];
int port;
} reconnect_password_prompt;
static gboolean
server_login_uses_password_sasl (int logintype)
{
return logintype == LOGIN_SASL ||
logintype == LOGIN_SASL_SCRAM_SHA_1 ||
logintype == LOGIN_SASL_SCRAM_SHA_256 ||
logintype == LOGIN_SASL_SCRAM_SHA_512;
}
static void
server_reconnect_password_cb (int cancel, char *text, void *userdata)
{
reconnect_password_prompt *prompt = userdata;
if (!cancel && is_server (prompt->serv) && !prompt->serv->connected && !prompt->serv->connecting && prompt->serv->server_session)
{
prompt->serv->password[0] = 0;
if (text && *text)
safe_strcpy (prompt->serv->password, text, sizeof (prompt->serv->password));
server_connect (prompt->serv, prompt->hostname, prompt->port, FALSE);
}
g_free (prompt);
}
static gboolean
server_prompt_reconnect_password (server *serv)
{
reconnect_password_prompt *prompt;
char *msg;
ircnet *net = serv->network;
if (!net || !(net->flags & FLAG_PROMPT_PASSWORD) || !server_login_uses_password_sasl (serv->loginmethod))
return FALSE;
prompt = g_new0 (reconnect_password_prompt, 1);
prompt->serv = serv;
safe_strcpy (prompt->hostname, serv->hostname, sizeof (prompt->hostname));
prompt->port = serv->port;
msg = g_strdup_printf (_("Enter SASL password for %s:"), net->name ? net->name : _("this network"));
fe_get_password (msg, server_reconnect_password_cb, prompt);
g_free (msg);
return TRUE;
}
static void static void
write_error (char *message, GError **error) write_error (char *message, GError **error)
{ {
@@ -786,8 +734,7 @@ timeout_auto_reconnect (server *serv)
serv->recondelay_tag = 0; serv->recondelay_tag = 0;
if (!serv->connected && !serv->connecting && serv->server_session) if (!serv->connected && !serv->connecting && serv->server_session)
{ {
if (!server_prompt_reconnect_password (serv)) server_connect (serv, serv->hostname, serv->port, FALSE);
server_connect (serv, serv->hostname, serv->port, FALSE);
} }
} }
return 0; /* returning 0 should remove the timeout handler */ return 0; /* returning 0 should remove the timeout handler */

View File

@@ -472,34 +472,6 @@ get_cpu_arch (void)
return sysinfo_get_build_arch (); return sysinfo_get_build_arch ();
} }
/* RtlGetVersion is used because GetVersionEx reports a version capped by
* the compatibility manifest rather than the real one. */
gboolean
win32_is_windows_8_or_newer (void)
{
typedef LONG (WINAPI *rtl_get_version_func) (PRTL_OSVERSIONINFOW);
rtl_get_version_func rtl_get_version;
RTL_OSVERSIONINFOW version;
HMODULE ntdll;
ntdll = GetModuleHandleW (L"ntdll.dll");
if (ntdll == NULL)
return FALSE;
rtl_get_version = (rtl_get_version_func) GetProcAddress (ntdll, "RtlGetVersion");
if (rtl_get_version == NULL)
return FALSE;
memset (&version, 0, sizeof (version));
version.dwOSVersionInfoSize = sizeof (version);
if (rtl_get_version (&version) != 0)
return FALSE;
/* Windows 8 is 6.2; Windows 7 is 6.1 */
return version.dwMajorVersion > 6 ||
(version.dwMajorVersion == 6 && version.dwMinorVersion >= 2);
}
char * char *
get_sys_str (int with_cpu) get_sys_str (int with_cpu)
{ {

View File

@@ -65,7 +65,6 @@ int waitline (int sok, char *buf, int bufsize, int);
#ifdef WIN32 #ifdef WIN32
int waitline2 (GIOChannel *source, char *buf, int bufsize); int waitline2 (GIOChannel *source, char *buf, int bufsize);
int get_cpu_arch (void); int get_cpu_arch (void);
gboolean win32_is_windows_8_or_newer (void);
#else #else
#define waitline2(source,buf,size) waitline(serv->childread,buf,size,0) #define waitline2(source,buf,size) waitline(serv->childread,buf,size,0)
#endif #endif

View File

@@ -31,7 +31,6 @@
#include "../common/zoitechatc.h" #include "../common/zoitechatc.h"
#include "../common/cfgfiles.h" #include "../common/cfgfiles.h"
#include "../common/emoji-data.h" #include "../common/emoji-data.h"
#include "../common/util.h"
#include "emoji-picker.h" #include "emoji-picker.h"
#include "preferences-persistence.h" #include "preferences-persistence.h"
@@ -153,7 +152,13 @@ emoji_picker_ensure_css (void)
{ {
static gboolean done = FALSE; static gboolean done = FALSE;
GtkCssProvider *provider; GtkCssProvider *provider;
const char *css =
if (done)
return;
done = TRUE;
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider,
".zc-emoji-cell {" ".zc-emoji-cell {"
" font-family: \"Noto Color Emoji\", \"Segoe UI Emoji\"," " font-family: \"Noto Color Emoji\", \"Segoe UI Emoji\","
" \"Apple Color Emoji\", \"Twemoji Mozilla\", \"EmojiOne Color\";" " \"Apple Color Emoji\", \"Twemoji Mozilla\", \"EmojiOne Color\";"
@@ -163,41 +168,20 @@ emoji_picker_ensure_css (void)
".zc-emoji-cell-small {" ".zc-emoji-cell-small {"
" font-family: \"Noto Color Emoji\", \"Segoe UI Emoji\"," " font-family: \"Noto Color Emoji\", \"Segoe UI Emoji\","
" \"Apple Color Emoji\", \"Twemoji Mozilla\", \"EmojiOne Color\";" " \"Apple Color Emoji\", \"Twemoji Mozilla\", \"EmojiOne Color\";"
"}"; "}",
-1, NULL);
if (done)
return;
done = TRUE;
#ifdef G_OS_WIN32
/* Windows 7 cannot render color emoji fonts; its emoji live in the
* monochrome Segoe UI Symbol font. */
if (!win32_is_windows_8_or_newer ())
css =
".zc-emoji-cell {"
" font-family: \"Segoe UI Symbol\";"
" font-size: 15pt;"
" padding: 2px;"
"}"
".zc-emoji-cell-small {"
" font-family: \"Segoe UI Symbol\";"
"}";
#endif
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, css, -1, NULL);
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_unref (provider); g_object_unref (provider);
} }
static GtkWidget * static GtkWidget *
emoji_label_new (const char *sequence, gboolean small_cell) emoji_label_new (const char *sequence, gboolean small)
{ {
GtkWidget *label = gtk_label_new (sequence); GtkWidget *label = gtk_label_new (sequence);
gtk_style_context_add_class (gtk_widget_get_style_context (label), gtk_style_context_add_class (gtk_widget_get_style_context (label),
small_cell ? "zc-emoji-cell-small" : "zc-emoji-cell"); small ? "zc-emoji-cell-small" : "zc-emoji-cell");
return label; return label;
} }

View File

@@ -34,6 +34,10 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#ifdef HAVE_FONTCONFIG
#include <fontconfig/fontconfig.h>
#endif
#include "../common/zoitechat.h" #include "../common/zoitechat.h"
#include "../common/fe.h" #include "../common/fe.h"
#include "../common/util.h" #include "../common/util.h"
@@ -102,11 +106,9 @@ static const GOptionEntry gopt_entries[] =
{NULL} {NULL}
}; };
/* The emoji font is only bundled with Windows builds; other platforms
* rely on the operating system's emoji font (e.g. the distribution's
* Noto Color Emoji package on Linux). */
#ifdef WIN32 #ifdef WIN32
static gunichar2 *win32_private_emoji_font; static gunichar2 *win32_private_emoji_font;
#endif
static char * static char *
fe_bundled_emoji_font_path (void) fe_bundled_emoji_font_path (void)
@@ -117,6 +119,7 @@ fe_bundled_emoji_font_path (void)
override_path = g_getenv ("ZOITECHAT_EMOJI_FONT"); override_path = g_getenv ("ZOITECHAT_EMOJI_FONT");
if (override_path && *override_path) if (override_path && *override_path)
font_path = g_strdup (override_path); font_path = g_strdup (override_path);
#ifdef WIN32
else else
{ {
char *base_path; char *base_path;
@@ -129,6 +132,19 @@ fe_bundled_emoji_font_path (void)
g_free (base_path); g_free (base_path);
} }
} }
#elif defined(HAVE_FONTCONFIG)
else
{
const char *appdir;
appdir = g_getenv ("APPDIR");
if (appdir && *appdir)
font_path = g_build_filename (appdir, "usr", "share", "fonts",
"zoitechat", "NotoColorEmoji.ttf", NULL);
else
font_path = g_strdup (ZOITECHAT_EMOJI_FONT_FILE);
}
#endif
if (font_path && !g_file_test (font_path, G_FILE_TEST_IS_REGULAR)) if (font_path && !g_file_test (font_path, G_FILE_TEST_IS_REGULAR))
{ {
@@ -144,15 +160,6 @@ fe_register_bundled_emoji_font (void)
{ {
char *font_path; char *font_path;
/* Windows 7 cannot render color emoji fonts, so the bundled Noto
* Color Emoji font is not registered there; emoji rendering falls
* back to the monochrome Segoe UI Symbol glyphs instead. */
if (!win32_is_windows_8_or_newer ())
{
g_debug ("Windows 7 detected; using Segoe UI Symbol for emoji");
return;
}
font_path = fe_bundled_emoji_font_path (); font_path = fe_bundled_emoji_font_path ();
if (!font_path) if (!font_path)
{ {
@@ -160,6 +167,7 @@ fe_register_bundled_emoji_font (void)
return; return;
} }
#ifdef WIN32
win32_private_emoji_font = g_utf8_to_utf16 (font_path, -1, NULL, NULL, NULL); win32_private_emoji_font = g_utf8_to_utf16 (font_path, -1, NULL, NULL, NULL);
if (!win32_private_emoji_font || if (!win32_private_emoji_font ||
AddFontResourceExW ((LPCWSTR) win32_private_emoji_font, FR_PRIVATE, NULL) == 0) AddFontResourceExW ((LPCWSTR) win32_private_emoji_font, FR_PRIVATE, NULL) == 0)
@@ -167,6 +175,10 @@ fe_register_bundled_emoji_font (void)
g_warning ("Unable to register bundled emoji font: %s", font_path); g_warning ("Unable to register bundled emoji font: %s", font_path);
g_clear_pointer (&win32_private_emoji_font, g_free); g_clear_pointer (&win32_private_emoji_font, g_free);
} }
#elif defined(HAVE_FONTCONFIG)
if (!FcConfigAppFontAddFile (NULL, (const FcChar8 *) font_path))
g_warning ("Unable to register bundled emoji font: %s", font_path);
#endif
g_free (font_path); g_free (font_path);
} }
@@ -174,13 +186,14 @@ fe_register_bundled_emoji_font (void)
static void static void
fe_unregister_bundled_emoji_font (void) fe_unregister_bundled_emoji_font (void)
{ {
#ifdef WIN32
if (win32_private_emoji_font) if (win32_private_emoji_font)
{ {
RemoveFontResourceExW ((LPCWSTR) win32_private_emoji_font, FR_PRIVATE, NULL); RemoveFontResourceExW ((LPCWSTR) win32_private_emoji_font, FR_PRIVATE, NULL);
g_clear_pointer (&win32_private_emoji_font, g_free); g_clear_pointer (&win32_private_emoji_font, g_free);
} }
}
#endif #endif
}
#ifdef WIN32 #ifdef WIN32
static void static void
@@ -519,9 +532,9 @@ fe_args (int argc, char *argv[])
return 0; return 0;
} }
#ifdef WIN32
fe_register_bundled_emoji_font (); fe_register_bundled_emoji_font ();
#ifdef WIN32
win32_set_gsettings_schema_dir (); win32_set_gsettings_schema_dir ();
win32_set_appusermodelid (); win32_set_appusermodelid ();
win32_configure_pixbuf_loaders (); win32_configure_pixbuf_loaders ();
@@ -696,9 +709,7 @@ fe_main (void)
#endif #endif
gtk_main (); gtk_main ();
#ifdef WIN32
fe_unregister_bundled_emoji_font (); fe_unregister_bundled_emoji_font ();
#endif
/* sleep for 2 seconds so any QUIT messages are not lost. The */ /* sleep for 2 seconds so any QUIT messages are not lost. The */
/* GUI is closed at this point, so the user doesn't even know! */ /* GUI is closed at this point, so the user doesn't even know! */

View File

@@ -4363,21 +4363,12 @@ mg_inputbox_rightclick (GtkEntry *entry, GtkWidget *menu)
* font size/style/weight, and without breaking user-configured fonts. * font size/style/weight, and without breaking user-configured fonts.
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
static const char * static const char *mg_emoji_family_fallback =
mg_emoji_family_fallback (void)
{
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
/* Windows 7 cannot render color emoji fonts; its emoji live in the "Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji, Apple Color Emoji, Twemoji Mozilla, EmojiOne Color";
* monochrome Segoe UI Symbol font. Windows 8 and newer use the
* bundled Noto Color Emoji font. */
if (!win32_is_windows_8_or_newer ())
return "Segoe UI Symbol";
return "Noto Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Apple Color Emoji, Twemoji Mozilla, EmojiOne Color";
#else #else
return "Noto Color Emoji, Segoe UI Emoji, Apple Color Emoji, Twemoji Mozilla, EmojiOne Color"; "Noto Color Emoji, Segoe UI Emoji, Apple Color Emoji, Twemoji Mozilla, EmojiOne Color";
#endif #endif
}
static gboolean static gboolean
mg_family_already_has_emoji (const gchar *family) mg_family_already_has_emoji (const gchar *family)
@@ -4412,14 +4403,14 @@ mg_fontdesc_with_fallback (const PangoFontDescription *base_desc, gboolean emoji
if (emoji_first) if (emoji_first)
{ {
family_list = g_strdup_printf ("%s, %s", family_list = g_strdup_printf ("%s, %s",
mg_emoji_family_fallback (), mg_emoji_family_fallback,
(base_family && *base_family) ? base_family : "Sans"); (base_family && *base_family) ? base_family : "Sans");
} }
else else
{ {
family_list = g_strdup_printf ("%s, %s", family_list = g_strdup_printf ("%s, %s",
(base_family && *base_family) ? base_family : "Sans", (base_family && *base_family) ? base_family : "Sans",
mg_emoji_family_fallback ()); mg_emoji_family_fallback);
} }
pango_font_description_set_family (desc, family_list); pango_font_description_set_family (desc, family_list);

View File

@@ -49,6 +49,10 @@ zoitechat_gtk_deps = [
libgmodule_dep, # used by libsexy libgmodule_dep, # used by libsexy
] ]
if fontconfig_dep.found()
zoitechat_gtk_deps += fontconfig_dep
endif
gtk_dep = dependency('gtk+-3.0', version: '>= 3.22') gtk_dep = dependency('gtk+-3.0', version: '>= 3.22')
zoitechat_theme_deps = [gtk_dep, zoitechat_common_dep] zoitechat_theme_deps = [gtk_dep, zoitechat_common_dep]