mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-03-10 07:50:19 +00:00
Merge pull request #61 from ZoiteChat/theme_updates
fixed some theming issues with Windows build aka dark mode etc. fixed chat message lag when channel had large scrollback.
This commit is contained in:
@@ -19,7 +19,7 @@ else:
|
||||
if not hasattr(sys, 'argv'):
|
||||
sys.argv = ['<zoitechat>']
|
||||
|
||||
VERSION = b'2.0' # Sync with zoitechat.__version__
|
||||
VERSION = b'2.18.0-pre1' # Sync with zoitechat.__version__
|
||||
PLUGIN_NAME = ffi.new('char[]', b'Python')
|
||||
PLUGIN_DESC = ffi.new('char[]', b'Python %d.%d scripting interface' % (sys.version_info[0], sys.version_info[1]))
|
||||
PLUGIN_VERSION = ffi.new('char[]', VERSION)
|
||||
@@ -591,4 +591,4 @@ def _on_plugin_deinit():
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return 1
|
||||
return 1
|
||||
|
||||
@@ -3783,9 +3783,19 @@ cmd_url (struct session *sess, char *tbuf, char *word[], char *word_eol[])
|
||||
|
||||
if (zoitechat_import_theme (theme_path, &error))
|
||||
{
|
||||
message = g_strdup_printf (_("Theme \"%s\" imported."), basename);
|
||||
fe_message (message, FE_MSG_INFO);
|
||||
g_free (message);
|
||||
if (zoitechat_apply_theme (basename, &error))
|
||||
{
|
||||
message = g_strdup_printf (_("Theme \"%s\" imported and applied."), basename);
|
||||
fe_message (message, FE_MSG_INFO);
|
||||
handle_command (sess, "gui apply", FALSE);
|
||||
g_free (message);
|
||||
}
|
||||
else
|
||||
{
|
||||
fe_message (error ? error->message : _("Theme imported, but failed to apply."),
|
||||
FE_MSG_ERROR);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -247,6 +247,85 @@ zoitechat_remote_win32 (void)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static gboolean
|
||||
zoitechat_copy_theme_file (const char *src, const char *dest, GError **error)
|
||||
{
|
||||
char *data = NULL;
|
||||
gsize len = 0;
|
||||
|
||||
if (!g_file_get_contents (src, &data, &len, error))
|
||||
return FALSE;
|
||||
|
||||
if (!g_file_set_contents (dest, data, len, error))
|
||||
{
|
||||
g_free (data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free (data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
zoitechat_apply_theme (const char *theme_name, GError **error)
|
||||
{
|
||||
char *theme_dir;
|
||||
char *colors_src;
|
||||
char *colors_dest;
|
||||
char *events_src;
|
||||
char *events_dest;
|
||||
gboolean ok = FALSE;
|
||||
|
||||
if (!theme_name || !*theme_name)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
||||
_("No theme name specified."));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
theme_dir = g_build_filename (get_xdir (), "themes", theme_name, NULL);
|
||||
colors_src = g_build_filename (theme_dir, "colors.conf", NULL);
|
||||
colors_dest = g_build_filename (get_xdir (), "colors.conf", NULL);
|
||||
events_src = g_build_filename (theme_dir, "pevents.conf", NULL);
|
||||
events_dest = g_build_filename (get_xdir (), "pevents.conf", NULL);
|
||||
|
||||
if (!g_file_test (colors_src, G_FILE_TEST_IS_REGULAR))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
_("This theme is missing a colors.conf file."));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!zoitechat_copy_theme_file (colors_src, colors_dest, error))
|
||||
goto cleanup;
|
||||
|
||||
if (g_file_test (events_src, G_FILE_TEST_IS_REGULAR))
|
||||
{
|
||||
if (!zoitechat_copy_theme_file (events_src, events_dest, error))
|
||||
goto cleanup;
|
||||
}
|
||||
else if (g_file_test (events_dest, G_FILE_TEST_EXISTS))
|
||||
{
|
||||
if (g_unlink (events_dest) != 0)
|
||||
{
|
||||
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
||||
_("Failed to remove existing event settings."));
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ok = TRUE;
|
||||
|
||||
cleanup:
|
||||
g_free (events_dest);
|
||||
g_free (events_src);
|
||||
g_free (colors_dest);
|
||||
g_free (colors_src);
|
||||
g_free (theme_dir);
|
||||
return ok;
|
||||
}
|
||||
|
||||
gboolean
|
||||
zoitechat_import_theme (const char *path, GError **error)
|
||||
{
|
||||
@@ -754,9 +833,19 @@ irc_init (session *sess)
|
||||
|
||||
if (zoitechat_import_theme (theme_path, &error))
|
||||
{
|
||||
message = g_strdup_printf (_("Theme \"%s\" imported."), basename);
|
||||
fe_message (message, FE_MSG_INFO);
|
||||
g_free (message);
|
||||
if (zoitechat_apply_theme (basename, &error))
|
||||
{
|
||||
message = g_strdup_printf (_("Theme \"%s\" imported and applied."), basename);
|
||||
fe_message (message, FE_MSG_INFO);
|
||||
handle_command (sess, "gui apply", FALSE);
|
||||
g_free (message);
|
||||
}
|
||||
else
|
||||
{
|
||||
fe_message (error ? error->message : _("Theme imported, but failed to apply."),
|
||||
FE_MSG_ERROR);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -796,9 +885,19 @@ irc_init (session *sess)
|
||||
|
||||
if (zoitechat_import_theme (theme_path, &error))
|
||||
{
|
||||
message = g_strdup_printf (_("Theme \"%s\" imported."), basename);
|
||||
fe_message (message, FE_MSG_INFO);
|
||||
g_free (message);
|
||||
if (zoitechat_apply_theme (basename, &error))
|
||||
{
|
||||
message = g_strdup_printf (_("Theme \"%s\" imported and applied."), basename);
|
||||
fe_message (message, FE_MSG_INFO);
|
||||
handle_command (sess, "gui apply", FALSE);
|
||||
g_free (message);
|
||||
}
|
||||
else
|
||||
{
|
||||
fe_message (error ? error->message : _("Theme imported, but failed to apply."),
|
||||
FE_MSG_ERROR);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
gboolean zoitechat_theme_path_from_arg (const char *arg, char **path_out);
|
||||
gboolean zoitechat_import_theme (const char *path, GError **error);
|
||||
gboolean zoitechat_apply_theme (const char *theme_name, GError **error);
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
#ifdef __APPLE__
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <dwmapi.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -285,6 +286,8 @@ const char cursor_color_rc[] =
|
||||
"}"
|
||||
"widget \"*.zoitechat-inputbox\" style : application \"xc-ib-st\"";
|
||||
|
||||
InputStyle *create_input_style (InputStyle *style);
|
||||
|
||||
static const char adwaita_workaround_rc[] =
|
||||
"style \"zoitechat-input-workaround\""
|
||||
"{"
|
||||
@@ -301,6 +304,85 @@ static const char adwaita_workaround_rc[] =
|
||||
"}"
|
||||
"widget \"*.zoitechat-inputbox\" style \"zoitechat-input-workaround\"";
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
|
||||
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
fe_win32_high_contrast_is_enabled (void)
|
||||
{
|
||||
HIGHCONTRASTW hc;
|
||||
|
||||
ZeroMemory (&hc, sizeof (hc));
|
||||
hc.cbSize = sizeof (hc);
|
||||
if (!SystemParametersInfoW (SPI_GETHIGHCONTRAST, sizeof (hc), &hc, 0))
|
||||
return FALSE;
|
||||
|
||||
return (hc.dwFlags & HCF_HIGHCONTRASTON) != 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fe_win32_try_get_system_dark (gboolean *prefer_dark)
|
||||
{
|
||||
DWORD value = 1;
|
||||
DWORD value_size = sizeof (value);
|
||||
LSTATUS status;
|
||||
|
||||
status = RegGetValueW (HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
L"AppsUseLightTheme",
|
||||
RRF_RT_REG_DWORD,
|
||||
NULL,
|
||||
&value,
|
||||
&value_size);
|
||||
if (status != ERROR_SUCCESS)
|
||||
status = RegGetValueW (HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
L"SystemUsesLightTheme",
|
||||
RRF_RT_REG_DWORD,
|
||||
NULL,
|
||||
&value,
|
||||
&value_size);
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
*prefer_dark = (value == 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fe_win32_apply_native_titlebar (GtkWidget *window, gboolean dark_mode)
|
||||
{
|
||||
HWND hwnd;
|
||||
BOOL use_dark;
|
||||
|
||||
if (!window || !gtk_widget_get_realized (window))
|
||||
return;
|
||||
|
||||
hwnd = gdk_win32_window_get_handle (gtk_widget_get_window (window));
|
||||
if (!hwnd)
|
||||
return;
|
||||
|
||||
if (fe_win32_high_contrast_is_enabled ())
|
||||
return;
|
||||
|
||||
use_dark = dark_mode ? TRUE : FALSE;
|
||||
DwmSetWindowAttribute (hwnd,
|
||||
DWMWA_USE_IMMERSIVE_DARK_MODE,
|
||||
&use_dark,
|
||||
sizeof (use_dark));
|
||||
}
|
||||
#else
|
||||
static void
|
||||
fe_win32_apply_native_titlebar (GtkWidget *window, gboolean dark_mode)
|
||||
{
|
||||
(void) window;
|
||||
(void) dark_mode;
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
fe_system_prefers_dark (void)
|
||||
{
|
||||
@@ -309,42 +391,16 @@ fe_system_prefers_dark (void)
|
||||
char *theme_name = NULL;
|
||||
#ifdef G_OS_WIN32
|
||||
gboolean have_win_pref = FALSE;
|
||||
|
||||
if (fe_win32_high_contrast_is_enabled ())
|
||||
return FALSE;
|
||||
#endif
|
||||
|
||||
if (!settings)
|
||||
return FALSE;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
{
|
||||
DWORD value = 1;
|
||||
DWORD value_size = sizeof (value);
|
||||
LSTATUS status;
|
||||
|
||||
status = RegGetValueW (HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
L"AppsUseLightTheme",
|
||||
RRF_RT_REG_DWORD,
|
||||
NULL,
|
||||
&value,
|
||||
&value_size);
|
||||
if (status != ERROR_SUCCESS)
|
||||
status = RegGetValueW (HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
L"SystemUsesLightTheme",
|
||||
RRF_RT_REG_DWORD,
|
||||
NULL,
|
||||
&value,
|
||||
&value_size);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
prefer_dark = (value == 0);
|
||||
have_win_pref = TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
have_win_pref = fe_win32_try_get_system_dark (&prefer_dark);
|
||||
if (!have_win_pref)
|
||||
#endif
|
||||
if (g_object_class_find_property (G_OBJECT_GET_CLASS (settings),
|
||||
@@ -371,6 +427,46 @@ fe_system_prefers_dark (void)
|
||||
|
||||
static gboolean auto_dark_mode_enabled = FALSE;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
static void
|
||||
fe_apply_windows_theme (gboolean dark)
|
||||
{
|
||||
GtkSettings *settings = gtk_settings_get_default ();
|
||||
|
||||
if (settings && g_object_class_find_property (G_OBJECT_GET_CLASS (settings),
|
||||
"gtk-application-prefer-dark-theme"))
|
||||
{
|
||||
g_object_set (settings, "gtk-application-prefer-dark-theme", dark, NULL);
|
||||
}
|
||||
|
||||
#if HAVE_GTK3
|
||||
{
|
||||
static GtkCssProvider *win_theme_provider = NULL;
|
||||
GdkScreen *screen = gdk_screen_get_default ();
|
||||
const char *css =
|
||||
"window.zoitechat-dark, .zoitechat-dark {"
|
||||
"background-color: #202020;"
|
||||
"color: #f0f0f0;"
|
||||
"}"
|
||||
"window.zoitechat-light, .zoitechat-light {"
|
||||
"background-color: #f6f6f6;"
|
||||
"color: #101010;"
|
||||
"}";
|
||||
|
||||
if (!win_theme_provider)
|
||||
win_theme_provider = gtk_css_provider_new ();
|
||||
|
||||
gtk_css_provider_load_from_data (win_theme_provider, css, -1, NULL);
|
||||
if (screen)
|
||||
gtk_style_context_add_provider_for_screen (
|
||||
screen,
|
||||
GTK_STYLE_PROVIDER (win_theme_provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
fe_auto_dark_mode_changed (GtkSettings *settings, GParamSpec *pspec, gpointer data)
|
||||
{
|
||||
@@ -388,7 +484,7 @@ fe_auto_dark_mode_changed (GtkSettings *settings, GParamSpec *pspec, gpointer da
|
||||
return;
|
||||
|
||||
auto_dark_mode_enabled = enabled;
|
||||
palette_apply_dark_mode (enabled);
|
||||
fe_apply_theme_for_mode (ZOITECHAT_DARK_MODE_AUTO, NULL);
|
||||
setup_apply_real (0, TRUE, FALSE, FALSE);
|
||||
}
|
||||
|
||||
@@ -404,6 +500,48 @@ fe_refresh_auto_dark_mode (void)
|
||||
fe_auto_dark_mode_changed (NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
fe_apply_theme_for_mode (unsigned int mode, gboolean *palette_changed)
|
||||
{
|
||||
gboolean enabled = fe_dark_mode_is_enabled_for (mode);
|
||||
gboolean changed = palette_apply_dark_mode (enabled);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
fe_apply_windows_theme (enabled);
|
||||
#endif
|
||||
|
||||
if (palette_changed)
|
||||
*palette_changed = changed;
|
||||
|
||||
if (input_style)
|
||||
create_input_style (input_style);
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void
|
||||
fe_apply_theme_to_toplevel (GtkWidget *window)
|
||||
{
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
#if defined(G_OS_WIN32) && HAVE_GTK3
|
||||
{
|
||||
GtkStyleContext *context = gtk_widget_get_style_context (window);
|
||||
gboolean dark = fe_dark_mode_is_enabled ();
|
||||
|
||||
if (context)
|
||||
{
|
||||
gtk_style_context_remove_class (context, "zoitechat-dark");
|
||||
gtk_style_context_remove_class (context, "zoitechat-light");
|
||||
gtk_style_context_add_class (context, dark ? "zoitechat-dark" : "zoitechat-light");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
fe_win32_apply_native_titlebar (window, fe_dark_mode_is_enabled ());
|
||||
}
|
||||
|
||||
gboolean
|
||||
fe_dark_mode_is_enabled_for (unsigned int mode)
|
||||
{
|
||||
@@ -415,7 +553,7 @@ fe_dark_mode_is_enabled_for (unsigned int mode)
|
||||
return FALSE;
|
||||
case ZOITECHAT_DARK_MODE_AUTO:
|
||||
default:
|
||||
return fe_system_prefers_dark ();
|
||||
return auto_dark_mode_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,7 +763,11 @@ fe_init (void)
|
||||
GtkSettings *settings;
|
||||
|
||||
palette_load ();
|
||||
palette_apply_dark_mode (fe_dark_mode_is_enabled ());
|
||||
settings = gtk_settings_get_default ();
|
||||
if (settings)
|
||||
auto_dark_mode_enabled = fe_system_prefers_dark ();
|
||||
|
||||
fe_apply_theme_for_mode (prefs.hex_gui_dark_mode, NULL);
|
||||
key_init ();
|
||||
pixmaps_init ();
|
||||
|
||||
@@ -639,12 +781,10 @@ fe_init (void)
|
||||
input_style = create_input_style (gtk_style_new ());
|
||||
#endif
|
||||
|
||||
settings = gtk_settings_get_default ();
|
||||
if (settings)
|
||||
{
|
||||
auto_dark_mode_enabled = fe_system_prefers_dark ();
|
||||
g_signal_connect (settings, "notify::gtk-application-prefer-dark-theme",
|
||||
G_CALLBACK (fe_auto_dark_mode_changed), NULL);
|
||||
G_CALLBACK (fe_auto_dark_mode_changed), NULL);
|
||||
g_signal_connect (settings, "notify::gtk-theme-name",
|
||||
G_CALLBACK (fe_auto_dark_mode_changed), NULL);
|
||||
}
|
||||
|
||||
@@ -211,6 +211,8 @@ gboolean fe_dark_mode_is_enabled (void);
|
||||
gboolean fe_dark_mode_is_enabled_for (unsigned int mode);
|
||||
void fe_set_auto_dark_mode_state (gboolean enabled);
|
||||
void fe_refresh_auto_dark_mode (void);
|
||||
gboolean fe_apply_theme_for_mode (unsigned int mode, gboolean *palette_changed);
|
||||
void fe_apply_theme_to_toplevel (GtkWidget *window);
|
||||
|
||||
#define SPELL_ENTRY_GET_TEXT(e) ((char *)(gtk_entry_get_text (GTK_ENTRY(e))))
|
||||
#define SPELL_ENTRY_SET_TEXT(e,txt) gtk_entry_set_text(GTK_ENTRY(e),txt)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Configuration">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
@@ -30,24 +30,24 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\common;$(ZoiteChatLib);$(DepsRoot)\include;$(OpenSslInclude);$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\common;$(ZoiteChatLib);$(DepsRoot)\include;$(OpenSslInclude);$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>$(DepLibs);$(ZoiteChatLib)common.lib;wbemuuid.lib;comsupp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>$(DepLibs);$(ZoiteChatLib)common.lib;wbemuuid.lib;comsupp.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\common;$(ZoiteChatLib);$(DepsRoot)\include;$(OpenSslInclude);$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\common;$(ZoiteChatLib);$(DepsRoot)\include;$(OpenSslInclude);$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>$(DepLibs);$(ZoiteChatLib)common.lib;wbemuuid.lib;comsupp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>$(DepLibs);$(ZoiteChatLib)common.lib;wbemuuid.lib;comsupp.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
@@ -3944,6 +3944,7 @@ mg_create_topwindow (session *sess)
|
||||
mg_place_userlist_and_chanview (sess->gui);
|
||||
|
||||
gtk_widget_show (win);
|
||||
fe_apply_theme_to_toplevel (win);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
parent_win = gtk_widget_get_window (win);
|
||||
@@ -4118,6 +4119,7 @@ mg_create_tabwindow (session *sess)
|
||||
mg_place_userlist_and_chanview (sess->gui);
|
||||
|
||||
gtk_widget_show (win);
|
||||
fe_apply_theme_to_toplevel (win);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
parent_win = gtk_widget_get_window (win);
|
||||
@@ -4141,6 +4143,8 @@ mg_apply_setup (void)
|
||||
((xtext_buffer *)sess->res->buffer)->needs_recalc = TRUE;
|
||||
if (!sess->gui->is_tab || !done_main)
|
||||
mg_place_userlist_and_chanview (sess->gui);
|
||||
if (sess->gui->window)
|
||||
fe_apply_theme_to_toplevel (sess->gui->window);
|
||||
if (sess->gui->is_tab)
|
||||
done_main = TRUE;
|
||||
list = list->next;
|
||||
|
||||
@@ -77,6 +77,7 @@ zoitechat_gtk_ldflags = []
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
zoitechat_gtk_sources += 'notifications/notification-windows.c'
|
||||
zoitechat_gtk_deps += cc.find_library('dwmapi', required: true)
|
||||
|
||||
# TODO: mingw doesn't have these headers or libs
|
||||
# add_languages('cpp')
|
||||
|
||||
@@ -2045,22 +2045,6 @@ setup_theme_show_message (GtkMessageType message_type, const char *primary)
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
setup_theme_copy_file (const char *src, const char *dest, GError **error)
|
||||
{
|
||||
GFile *src_file;
|
||||
GFile *dest_file;
|
||||
gboolean success;
|
||||
|
||||
src_file = g_file_new_for_path (src);
|
||||
dest_file = g_file_new_for_path (dest);
|
||||
success = g_file_copy (src_file, dest_file, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, error);
|
||||
g_object_unref (src_file);
|
||||
g_object_unref (dest_file);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static void
|
||||
setup_theme_populate (setup_theme_ui *ui)
|
||||
{
|
||||
@@ -2138,11 +2122,6 @@ setup_theme_apply_cb (GtkWidget *button, gpointer user_data)
|
||||
GtkWidget *dialog;
|
||||
gint response;
|
||||
char *theme;
|
||||
char *theme_dir = NULL;
|
||||
char *colors_src = NULL;
|
||||
char *colors_dest = NULL;
|
||||
char *events_src = NULL;
|
||||
char *events_dest = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
theme = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (ui->combo));
|
||||
@@ -2161,40 +2140,13 @@ setup_theme_apply_cb (GtkWidget *button, gpointer user_data)
|
||||
return;
|
||||
}
|
||||
|
||||
theme_dir = g_build_filename (get_xdir (), "themes", theme, NULL);
|
||||
colors_src = g_build_filename (theme_dir, "colors.conf", NULL);
|
||||
colors_dest = g_build_filename (get_xdir (), "colors.conf", NULL);
|
||||
|
||||
if (!g_file_test (colors_src, G_FILE_TEST_IS_REGULAR))
|
||||
{
|
||||
setup_theme_show_message (GTK_MESSAGE_ERROR, _("This theme is missing a colors.conf file."));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!setup_theme_copy_file (colors_src, colors_dest, &error))
|
||||
if (!zoitechat_apply_theme (theme, &error))
|
||||
{
|
||||
setup_theme_show_message (GTK_MESSAGE_ERROR, error ? error->message : _("Failed to apply theme."));
|
||||
g_clear_error (&error);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
events_src = g_build_filename (theme_dir, "pevents.conf", NULL);
|
||||
events_dest = g_build_filename (get_xdir (), "pevents.conf", NULL);
|
||||
|
||||
if (g_file_test (events_src, G_FILE_TEST_IS_REGULAR))
|
||||
{
|
||||
if (!setup_theme_copy_file (events_src, events_dest, &error))
|
||||
{
|
||||
setup_theme_show_message (GTK_MESSAGE_ERROR, error ? error->message : _("Failed to apply event settings."));
|
||||
g_clear_error (&error);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else if (g_file_test (events_dest, G_FILE_TEST_EXISTS))
|
||||
{
|
||||
g_unlink (events_dest);
|
||||
}
|
||||
|
||||
palette_load ();
|
||||
palette_apply_dark_mode (fe_dark_mode_is_enabled ());
|
||||
color_change = TRUE;
|
||||
@@ -2203,11 +2155,6 @@ setup_theme_apply_cb (GtkWidget *button, gpointer user_data)
|
||||
setup_theme_show_message (GTK_MESSAGE_INFO, _("Theme applied. Some changes may require a restart to take full effect."));
|
||||
|
||||
cleanup:
|
||||
g_free (events_dest);
|
||||
g_free (events_src);
|
||||
g_free (colors_dest);
|
||||
g_free (colors_src);
|
||||
g_free (theme_dir);
|
||||
g_free (theme);
|
||||
}
|
||||
|
||||
@@ -3059,7 +3006,9 @@ setup_apply (struct zoitechatprefs *pr)
|
||||
* the preference flips but the palette stays the same (aka: "nothing happens").
|
||||
*/
|
||||
{
|
||||
gboolean pal_changed = palette_apply_dark_mode (fe_dark_mode_is_enabled_for (prefs.hex_gui_dark_mode));
|
||||
gboolean pal_changed = FALSE;
|
||||
|
||||
fe_apply_theme_for_mode (prefs.hex_gui_dark_mode, &pal_changed);
|
||||
if (prefs.hex_gui_dark_mode != old_dark_mode || pal_changed)
|
||||
color_change = TRUE;
|
||||
}
|
||||
|
||||
@@ -195,6 +195,8 @@ static void gtk_xtext_search_textentry_fini (gpointer, gpointer);
|
||||
static void gtk_xtext_search_fini (xtext_buffer *);
|
||||
static gboolean gtk_xtext_search_init (xtext_buffer *buf, const gchar *text, gtk_xtext_search_flags flags, GError **perr);
|
||||
static char * gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent, int *ret_off, int *ret_len, GSList **slp);
|
||||
static gboolean gtk_xtext_word_select_char (const unsigned char *ch);
|
||||
static gboolean gtk_xtext_get_word_select_range (GtkXText *xtext, int x, int y, textentry **ret_ent, int *ret_off, int *ret_len);
|
||||
|
||||
static inline void
|
||||
gtk_xtext_cursor_unref (GdkCursor *cursor)
|
||||
@@ -1856,10 +1858,12 @@ gtk_xtext_selection_draw (GtkXText * xtext, GdkEventMotion * event, gboolean ren
|
||||
if (xtext->word_select)
|
||||
{
|
||||
/* a word selection cannot be started if the cursor is out of bounds in gtk_xtext_button_press */
|
||||
gtk_xtext_get_word (xtext, low_x, low_y, NULL, &low_offs, NULL, NULL);
|
||||
if (!gtk_xtext_get_word_select_range (xtext, low_x, low_y, NULL, &low_offs, NULL))
|
||||
gtk_xtext_get_word (xtext, low_x, low_y, NULL, &low_offs, NULL, NULL);
|
||||
|
||||
/* in case the cursor is out of bounds we keep offset_end from gtk_xtext_find_char and fix the length */
|
||||
if (gtk_xtext_get_word (xtext, high_x, high_y, NULL, &high_offs, &high_len, NULL) == NULL)
|
||||
if (!gtk_xtext_get_word_select_range (xtext, high_x, high_y, NULL, &high_offs, &high_len) &&
|
||||
gtk_xtext_get_word (xtext, high_x, high_y, NULL, &high_offs, &high_len, NULL) == NULL)
|
||||
high_len = high_offs == high_ent->str_len? 0: -1; /* -1 for the space, 0 if at the end */
|
||||
high_offs += high_len;
|
||||
if (low_y < 0)
|
||||
@@ -2134,6 +2138,57 @@ gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent,
|
||||
return word;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_xtext_word_select_char (const unsigned char *ch)
|
||||
{
|
||||
gunichar uc;
|
||||
|
||||
if (!ch || !*ch)
|
||||
return FALSE;
|
||||
|
||||
uc = g_utf8_get_char_validated ((const gchar *)ch, -1);
|
||||
if (uc == (gunichar)-1 || uc == (gunichar)-2)
|
||||
return FALSE;
|
||||
return g_unichar_isalnum (uc) || uc == '_' || uc == '-';
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_xtext_get_word_select_range (GtkXText *xtext, int x, int y, textentry **ret_ent, int *ret_off, int *ret_len)
|
||||
{
|
||||
textentry *ent;
|
||||
int offset;
|
||||
unsigned char *start, *end;
|
||||
|
||||
ent = gtk_xtext_find_char (xtext, x, y, &offset, NULL);
|
||||
if (!ent || offset < 0 || offset >= ent->str_len)
|
||||
return FALSE;
|
||||
|
||||
start = ent->str + offset;
|
||||
end = g_utf8_find_next_char (start, ent->str + ent->str_len);
|
||||
if (!gtk_xtext_word_select_char (start))
|
||||
return FALSE;
|
||||
|
||||
while (start > ent->str)
|
||||
{
|
||||
unsigned char *prev = g_utf8_find_prev_char (ent->str, start);
|
||||
if (!prev || !gtk_xtext_word_select_char (prev))
|
||||
break;
|
||||
start = prev;
|
||||
}
|
||||
|
||||
while (end && end < ent->str + ent->str_len && gtk_xtext_word_select_char (end))
|
||||
end = g_utf8_find_next_char (end, ent->str + ent->str_len);
|
||||
|
||||
if (ret_ent)
|
||||
*ret_ent = ent;
|
||||
if (ret_off)
|
||||
*ret_off = (int)(start - ent->str);
|
||||
if (ret_len)
|
||||
*ret_len = (int)(end - start);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_xtext_unrender_hilight (GtkXText *xtext)
|
||||
{
|
||||
@@ -2581,7 +2636,8 @@ gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event)
|
||||
if (event->type == GDK_2BUTTON_PRESS) /* WORD select */
|
||||
{
|
||||
gtk_xtext_check_mark_stamp (xtext, mask);
|
||||
if (gtk_xtext_get_word (xtext, x, y, &ent, &offset, &len, 0))
|
||||
if (gtk_xtext_get_word_select_range (xtext, x, y, &ent, &offset, &len) ||
|
||||
gtk_xtext_get_word (xtext, x, y, &ent, &offset, &len, 0))
|
||||
{
|
||||
if (len == 0)
|
||||
return FALSE;
|
||||
@@ -4324,6 +4380,21 @@ gtk_xtext_nth (GtkXText *xtext, int line, int *subline)
|
||||
static int
|
||||
gtk_xtext_render_ents (GtkXText * xtext, textentry * enta, textentry * entb)
|
||||
{
|
||||
/*
|
||||
* On GTK3 (especially Wayland), event handlers are outside ::draw and direct
|
||||
* window painting may not be presented immediately. Queue a frame instead so
|
||||
* selections appear right away.
|
||||
*/
|
||||
#if HAVE_GTK3
|
||||
if (xtext->draw_cr == NULL)
|
||||
{
|
||||
GtkWidget *w = GTK_WIDGET (xtext);
|
||||
if (gtk_widget_get_realized (w))
|
||||
gtk_widget_queue_draw (w);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
textentry *ent, *orig_ent, *tmp_ent;
|
||||
int line;
|
||||
int lines_max;
|
||||
@@ -5355,10 +5426,16 @@ gtk_xtext_append_entry (xtext_buffer *buf, textentry * ent, time_t stamp)
|
||||
g_source_remove (buf->xtext->io_tag);
|
||||
buf->xtext->io_tag = 0;
|
||||
}
|
||||
buf->xtext->add_io_tag = g_timeout_add (REFRESH_TIMEOUT * 2,
|
||||
(GSourceFunc)
|
||||
gtk_xtext_render_page_timeout,
|
||||
buf->xtext);
|
||||
/* When at the bottom of the buffer, render immediately so long
|
||||
* scrollback doesn't delay newly-sent messages appearing.
|
||||
* Otherwise, keep idle batching to avoid extra redraws while
|
||||
* scrolling around old content. */
|
||||
if (buf->scrollbar_down)
|
||||
gtk_xtext_render_page_timeout (buf->xtext);
|
||||
else
|
||||
buf->xtext->add_io_tag = g_idle_add ((GSourceFunc)
|
||||
gtk_xtext_render_page_timeout,
|
||||
buf->xtext);
|
||||
}
|
||||
}
|
||||
if (buf->scrollbar_down)
|
||||
@@ -5390,6 +5467,7 @@ gtk_xtext_append_indent (xtext_buffer *buf,
|
||||
int space;
|
||||
int tempindent;
|
||||
int left_width;
|
||||
int min_indent;
|
||||
|
||||
if (left_len == -1)
|
||||
left_len = strlen (left_text);
|
||||
@@ -5428,24 +5506,32 @@ gtk_xtext_append_indent (xtext_buffer *buf,
|
||||
else
|
||||
space = 0;
|
||||
|
||||
min_indent = MARGIN + space;
|
||||
|
||||
/* do we need to auto adjust the separator position? */
|
||||
if (buf->xtext->auto_indent &&
|
||||
buf->indent < buf->xtext->max_auto_indent &&
|
||||
ent->indent < MARGIN + space)
|
||||
ent->indent < min_indent)
|
||||
{
|
||||
tempindent = MARGIN + space + buf->xtext->space_width + left_width;
|
||||
tempindent = min_indent + buf->xtext->space_width + left_width;
|
||||
|
||||
if (tempindent > buf->indent)
|
||||
/* Ignore tiny one-pixel style nudges.
|
||||
* They can trigger expensive full-width recalculations and are
|
||||
* perceived as a slight delay when sending messages with indenting on. */
|
||||
if (tempindent > buf->indent + buf->xtext->space_width)
|
||||
buf->indent = tempindent;
|
||||
|
||||
if (buf->indent > buf->xtext->max_auto_indent)
|
||||
buf->indent = buf->xtext->max_auto_indent;
|
||||
|
||||
gtk_xtext_fix_indent (buf);
|
||||
gtk_xtext_recalc_widths (buf, FALSE);
|
||||
if (buf->indent > ent->indent + left_width + buf->xtext->space_width)
|
||||
{
|
||||
gtk_xtext_fix_indent (buf);
|
||||
gtk_xtext_recalc_widths (buf, FALSE);
|
||||
|
||||
ent->indent = (buf->indent - left_width) - buf->xtext->space_width;
|
||||
buf->xtext->force_render = TRUE;
|
||||
ent->indent = (buf->indent - left_width) - buf->xtext->space_width;
|
||||
buf->xtext->force_render = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_xtext_append_entry (buf, ent, stamp);
|
||||
|
||||
Reference in New Issue
Block a user