mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-04-01 02:00:19 +00:00
Compare commits
17 Commits
bb36651548
...
zoitechat-
| Author | SHA1 | Date | |
|---|---|---|---|
| ec4d698021 | |||
|
|
da06c71389 | ||
| 0f508bf438 | |||
| 97dd7c5d57 | |||
|
|
78219bf9e1 | ||
|
|
1c30cbfab1 | ||
| ac33dc5250 | |||
| 8de5db18d6 | |||
|
|
913aa49df4 | ||
| 5e4633ee53 | |||
|
|
30e573d87a | ||
| 9e91d60bb1 | |||
|
|
069652a5f1 | ||
|
|
ab1e25bfb1 | ||
|
|
862aa0ede5 | ||
| f75c27c843 | |||
| 687b5fb40d |
@@ -1,6 +1,30 @@
|
||||
ZoiteChat ChangeLog
|
||||
=================
|
||||
|
||||
2.18.0~pre6 (2026-03-30)
|
||||
|
||||
- Applied app theme CSS to the menubar consistently across the app.
|
||||
- Restored horizontal separator lines in menus.
|
||||
- Improved Windows installer VC++ redistributable handling by failing loudly when missing and using the official Microsoft download endpoint.
|
||||
- Fixed Windows locale path resolution in both GTK and text frontends.
|
||||
- Fixed duplicate dialog buttons persisting in the UI.
|
||||
- Fixed GTK auto-replace cursor snapback.
|
||||
- Restored hiding of formatting control bytes so only formatted output is shown.
|
||||
- Added one-click client SSL certificate tools, including generation with P-256 certificates.
|
||||
- Added client SSL certificate import support in the network editor.
|
||||
- Added 99-color support.
|
||||
- Fixed xtext link hit-testing coordinates.
|
||||
- Fixed short-palette fallback clobbering tab colors.
|
||||
- Lazy-loads Preferences pages on first open for faster dialog startup.
|
||||
- Removed unused UI icons.
|
||||
- Added a None option for resetting the GTK3 theme back to system/default behavior.
|
||||
- Added channel-only mode to Ctrl+F search.
|
||||
- Disabled disk info in sysinfo.
|
||||
- Wrapped the topic bar in a scroller with bounded height.
|
||||
- Added close buttons to tabs.
|
||||
- Fixed fallback GTK menu highlight states.
|
||||
- Applied configured font preferences to the topic bar, channel tree, user list, and input box.
|
||||
|
||||
2.18.0~pre5 (2026-03-22)
|
||||
------------------------
|
||||
- Overhauled preferences/config saving: fully staged and transactional, debounced
|
||||
|
||||
@@ -29,7 +29,47 @@
|
||||
<id>zoitechat.desktop</id>
|
||||
</provides>
|
||||
<releases>
|
||||
<release date="2026-03-22" version="2.18.0~pre5">
|
||||
<release date="2026-03-30" version="2.18.0~pre6">
|
||||
<description>
|
||||
<p>GTK theme and UI:</p>
|
||||
<ul>
|
||||
<li>Applied app theme CSS to the menubar consistently across the app.</li>
|
||||
<li>Restored horizontal separator lines in menus.</li>
|
||||
<li>Fixed duplicate dialog buttons persisting in the UI.</li>
|
||||
<li>Fixed GTK auto-replace cursor snapback.</li>
|
||||
<li>Restored hiding of formatting control bytes so only formatted output is shown.</li>
|
||||
<li>Fixed xtext link hit-testing coordinates.</li>
|
||||
<li>Fixed short-palette fallback clobbering tab colors.</li>
|
||||
<li>Added a None option for resetting the GTK3 theme back to system/default behavior.</li>
|
||||
<li>Wrapped the topic bar in a scroller with bounded height.</li>
|
||||
<li>Fixed fallback GTK menu highlight states.</li>
|
||||
<li>Applied configured font preferences to the topic bar, channel tree, user list, and input box.</li>
|
||||
<li>Removed unused UI icons.</li>
|
||||
<li>Added close buttons to tabs.</li>
|
||||
</ul>
|
||||
<p>Preferences and search:</p>
|
||||
<ul>
|
||||
<li>Lazy-loads Preferences pages on first open for faster dialog startup.</li>
|
||||
<li>Added channel-only mode to Ctrl+F search.</li>
|
||||
</ul>
|
||||
<p>Security and certificates:</p>
|
||||
<ul>
|
||||
<li>Added one-click client SSL certificate tools, including generation with P-256 certificates.</li>
|
||||
<li>Added client SSL certificate import support in the network editor.</li>
|
||||
</ul>
|
||||
<p>Windows and packaging:</p>
|
||||
<ul>
|
||||
<li>Improved Windows installer VC++ redistributable handling by failing loudly when missing and using the official Microsoft download endpoint.</li>
|
||||
<li>Fixed Windows locale path resolution in both GTK and text frontends.</li>
|
||||
</ul>
|
||||
<p>Other changes:</p>
|
||||
<ul>
|
||||
<li>Added 99-color support.</li>
|
||||
<li>Disabled disk info in sysinfo.</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release date="2026-03-22" version="2.18.0~pre5">
|
||||
<description>
|
||||
<p>Preferences and config saving:</p>
|
||||
<ul>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
project('zoitechat', 'c',
|
||||
version: '2.18.0~pre5',
|
||||
version: '2.18.0~pre6',
|
||||
meson_version: '>= 0.55.0',
|
||||
default_options: [
|
||||
'c_std=c17',
|
||||
|
||||
@@ -19,7 +19,7 @@ else:
|
||||
if not hasattr(sys, 'argv'):
|
||||
sys.argv = ['<zoitechat>']
|
||||
|
||||
VERSION = b'2.18.0~pre5'
|
||||
VERSION = b'2.18.0~pre6'
|
||||
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)
|
||||
|
||||
@@ -41,7 +41,7 @@ static zoitechat_plugin *ph;
|
||||
static char name[] = "Sysinfo";
|
||||
static char desc[] = "Display info about your hardware and OS";
|
||||
static char version[] = "1.0";
|
||||
static char sysinfo_help[] = "SysInfo Usage:\n /SYSINFO [-e|-o] [CLIENT|UI|OS|CPU|RAM|DISK|GPU|CHIPSET|SOUND|ETHERNET|UPTIME], print various details about your system or print a summary without arguments\n /SYSINFO SET <variable>\n";
|
||||
static char sysinfo_help[] = "SysInfo Usage:\n /SYSINFO [-e|-o] [CLIENT|UI|OS|CPU|RAM|STORAGE|GPU|CHIPSET|SOUND|ETHERNET|UPTIME], print various details about your system or print a summary without arguments\n /SYSINFO SET <variable>\n";
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -68,7 +68,7 @@ static hwinfo hwinfos[] = {
|
||||
{"os", "OS", sysinfo_backend_get_os},
|
||||
{"cpu", "CPU", sysinfo_backend_get_cpu},
|
||||
{"memory", "Memory", sysinfo_backend_get_memory},
|
||||
{"storage", "Storage", sysinfo_backend_get_disk},
|
||||
{"storage", "Storage", sysinfo_backend_get_disk, TRUE},
|
||||
{"gpu", "GPU", sysinfo_backend_get_gpu},
|
||||
{"chipset", "CHIPSET", sysinfo_backend_get_chipset, TRUE},
|
||||
{"sound", "Sound", sysinfo_backend_get_sound, TRUE},
|
||||
|
||||
@@ -27,8 +27,6 @@ typedef struct
|
||||
GtkWidget *b2; /* button2 */
|
||||
} tabview;
|
||||
|
||||
#define ICON_CHANVIEW_CLOSE "gtk-close"
|
||||
|
||||
static void chanview_populate (chanview *cv);
|
||||
|
||||
/* ignore "toggled" signal? */
|
||||
@@ -334,12 +332,6 @@ tab_scroll_cb (GtkWidget *widget, GdkEventScroll *event, gpointer cv)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
cv_tabs_xclick_cb (GtkWidget *button, chanview *cv)
|
||||
{
|
||||
cv->cb_xbutton (cv, cv->focused, cv->focused->tag, cv->focused->userdata);
|
||||
}
|
||||
|
||||
/* make a Scroll (arrow) button */
|
||||
|
||||
static GtkWidget *
|
||||
@@ -384,7 +376,6 @@ cv_tabs_init (chanview *cv)
|
||||
GtkWidget *box, *hbox = NULL;
|
||||
GtkWidget *viewport;
|
||||
GtkWidget *outer;
|
||||
GtkWidget *button;
|
||||
|
||||
if (cv->vertical)
|
||||
{
|
||||
@@ -451,11 +442,6 @@ cv_tabs_init (chanview *cv)
|
||||
gtk_box_pack_start (GTK_BOX (outer), ((tabview *)cv)->b1, 0, 0, 0);
|
||||
}
|
||||
|
||||
button = gtkutil_button (outer, ICON_CHANVIEW_CLOSE, NULL, cv_tabs_xclick_cb,
|
||||
cv, 0);
|
||||
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
|
||||
gtk_widget_set_can_focus (button, FALSE);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (cv->box), outer);
|
||||
}
|
||||
|
||||
@@ -659,20 +645,129 @@ tab_toggled_cb (GtkToggleButton *tab, chan *ch)
|
||||
static gboolean
|
||||
tab_click_cb (GtkWidget *wid, GdkEventButton *event, chan *ch)
|
||||
{
|
||||
GtkWidget *close_button;
|
||||
gint close_x;
|
||||
gint close_y;
|
||||
GtkAllocation close_alloc;
|
||||
|
||||
if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
|
||||
{
|
||||
close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button");
|
||||
if (close_button &&
|
||||
gtk_widget_translate_coordinates (close_button, wid, 0, 0, &close_x, &close_y))
|
||||
{
|
||||
gtk_widget_get_allocation (close_button, &close_alloc);
|
||||
if (event->x >= close_x && event->x < close_x + close_alloc.width &&
|
||||
event->y >= close_y && event->y < close_y + close_alloc.height)
|
||||
{
|
||||
ch->cv->cb_xbutton (ch->cv, ch, ch->tag, ch->userdata);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ch->cv->cb_contextmenu (ch->cv, ch, ch->tag, ch->userdata, event);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tab_close_motion_cb (GtkWidget *wid, GdkEventMotion *event, chan *ch)
|
||||
{
|
||||
GtkWidget *close_button;
|
||||
gint close_x;
|
||||
gint close_y;
|
||||
GtkAllocation close_alloc;
|
||||
gboolean hover = FALSE;
|
||||
|
||||
close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button");
|
||||
if (close_button &&
|
||||
gtk_widget_translate_coordinates (close_button, wid, 0, 0, &close_x, &close_y))
|
||||
{
|
||||
gtk_widget_get_allocation (close_button, &close_alloc);
|
||||
hover = event->x >= close_x && event->x < close_x + close_alloc.width &&
|
||||
event->y >= close_y && event->y < close_y + close_alloc.height;
|
||||
}
|
||||
|
||||
if (hover)
|
||||
{
|
||||
GdkCursor *cursor;
|
||||
gtk_widget_set_state_flags (close_button, GTK_STATE_FLAG_PRELIGHT, TRUE);
|
||||
if (gtk_widget_get_window (wid))
|
||||
{
|
||||
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (wid), GDK_HAND2);
|
||||
gdk_window_set_cursor (gtk_widget_get_window (wid), cursor);
|
||||
g_object_unref (cursor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_unset_state_flags (close_button, GTK_STATE_FLAG_PRELIGHT);
|
||||
if (gtk_widget_get_window (wid))
|
||||
gdk_window_set_cursor (gtk_widget_get_window (wid), NULL);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tab_close_leave_cb (GtkWidget *wid, GdkEventCrossing *event, chan *ch)
|
||||
{
|
||||
GtkWidget *close_button;
|
||||
|
||||
close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button");
|
||||
if (close_button)
|
||||
gtk_widget_unset_state_flags (close_button, GTK_STATE_FLAG_PRELIGHT);
|
||||
if (gtk_widget_get_window (wid))
|
||||
gdk_window_set_cursor (gtk_widget_get_window (wid), NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
tab_get_label (GtkWidget *tab)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = g_object_get_data (G_OBJECT (tab), "tab-label");
|
||||
if (label)
|
||||
return label;
|
||||
|
||||
return gtk_bin_get_child (GTK_BIN (tab));
|
||||
}
|
||||
|
||||
static void *
|
||||
cv_tabs_add (chanview *cv, chan *ch, char *name, GtkTreeIter *parent)
|
||||
{
|
||||
GtkWidget *but;
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *label;
|
||||
GtkWidget *close_button;
|
||||
GtkWidget *close_icon;
|
||||
|
||||
but = gtk_toggle_button_new_with_label (name);
|
||||
but = gtk_toggle_button_new ();
|
||||
gtk_widget_set_name (but, "zoitechat-tab");
|
||||
gtk_widget_set_size_request (but, -1, 18);
|
||||
gtk_widget_add_events (but, GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
label = gtk_label_new (name);
|
||||
close_button = gtk_button_new ();
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (close_button), "flat");
|
||||
close_icon = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_MENU);
|
||||
gtk_image_set_pixel_size (GTK_IMAGE (close_icon), 8);
|
||||
gtk_button_set_always_show_image (GTK_BUTTON (close_button), TRUE);
|
||||
gtk_widget_set_can_focus (close_button, FALSE);
|
||||
gtk_container_add (GTK_CONTAINER (close_button), close_icon);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
|
||||
gtk_container_add (GTK_CONTAINER (but), hbox);
|
||||
g_object_set_data (G_OBJECT (but), "tab-label", label);
|
||||
g_object_set_data (G_OBJECT (but), "tab-close-button", close_button);
|
||||
g_object_set_data (G_OBJECT (but), "c", ch);
|
||||
/* used to trap right-clicks */
|
||||
g_signal_connect (G_OBJECT (but), "button-press-event",
|
||||
G_CALLBACK (tab_click_cb), ch);
|
||||
g_signal_connect (G_OBJECT (but), "motion-notify-event",
|
||||
G_CALLBACK (tab_close_motion_cb), ch);
|
||||
g_signal_connect (G_OBJECT (but), "leave-notify-event",
|
||||
G_CALLBACK (tab_close_leave_cb), ch);
|
||||
/* avoid prelights */
|
||||
g_signal_connect (G_OBJECT (but), "enter-notify-event",
|
||||
G_CALLBACK (tab_ignore_cb), NULL);
|
||||
@@ -684,6 +779,7 @@ cv_tabs_add (chanview *cv, chan *ch, char *name, GtkTreeIter *parent)
|
||||
g_signal_connect (G_OBJECT (but), "toggled",
|
||||
G_CALLBACK (tab_toggled_cb), ch);
|
||||
g_object_set_data (G_OBJECT (but), "u", ch->userdata);
|
||||
gtk_widget_show_all (hbox);
|
||||
|
||||
tab_add_real (cv, but, ch);
|
||||
|
||||
@@ -892,7 +988,7 @@ cv_tabs_cleanup (chanview *cv)
|
||||
static void
|
||||
cv_tabs_set_color (chan *ch, PangoAttrList *list)
|
||||
{
|
||||
gtk_label_set_attributes (GTK_LABEL (gtk_bin_get_child (GTK_BIN (ch->impl))), list);
|
||||
gtk_label_set_attributes (GTK_LABEL (tab_get_label (ch->impl)), list);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -901,16 +997,16 @@ cv_tabs_rename (chan *ch, char *name)
|
||||
PangoAttrList *attr;
|
||||
GtkWidget *tab = ch->impl;
|
||||
|
||||
attr = gtk_label_get_attributes (GTK_LABEL (gtk_bin_get_child (GTK_BIN (tab))));
|
||||
attr = gtk_label_get_attributes (GTK_LABEL (tab_get_label (tab)));
|
||||
if (attr)
|
||||
pango_attr_list_ref (attr);
|
||||
|
||||
gtk_button_set_label (GTK_BUTTON (tab), name);
|
||||
gtk_label_set_text (GTK_LABEL (tab_get_label (tab)), name);
|
||||
gtk_widget_queue_resize (gtk_widget_get_parent(gtk_widget_get_parent(gtk_widget_get_parent(tab))));
|
||||
|
||||
if (attr)
|
||||
{
|
||||
gtk_label_set_attributes (GTK_LABEL (gtk_bin_get_child (GTK_BIN (tab))), attr);
|
||||
gtk_label_set_attributes (GTK_LABEL (tab_get_label (tab)), attr);
|
||||
pango_attr_list_unref (attr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2968,10 +2968,73 @@ mg_create_dialogbuttons (GtkWidget *box)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mg_configure_topic_scroller (GtkWidget *scroller, GtkWidget *topic)
|
||||
{
|
||||
PangoContext *context;
|
||||
PangoFontMetrics *metrics;
|
||||
int line_height;
|
||||
int min_height;
|
||||
int max_height;
|
||||
|
||||
context = gtk_widget_get_pango_context (topic);
|
||||
metrics = pango_context_get_metrics (context,
|
||||
pango_context_get_font_description (context),
|
||||
pango_context_get_language (context));
|
||||
line_height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
|
||||
pango_font_metrics_get_descent (metrics));
|
||||
pango_font_metrics_unref (metrics);
|
||||
|
||||
if (line_height <= 0)
|
||||
line_height = 16;
|
||||
|
||||
min_height = line_height + 8;
|
||||
max_height = line_height * 4 + 8;
|
||||
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
|
||||
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller), GTK_SHADOW_NONE);
|
||||
gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (scroller), TRUE);
|
||||
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (scroller), min_height);
|
||||
gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (scroller), max_height);
|
||||
}
|
||||
|
||||
void
|
||||
mg_apply_session_font_prefs (session_gui *gui)
|
||||
{
|
||||
const PangoFontDescription *font = NULL;
|
||||
GtkWidget *topic_scroller;
|
||||
|
||||
if (!gui)
|
||||
return;
|
||||
|
||||
if (input_style)
|
||||
font = input_style->font_desc;
|
||||
|
||||
if (gui->topic_entry)
|
||||
{
|
||||
theme_manager_apply_entry_palette (gui->topic_entry, font);
|
||||
topic_scroller = gtk_widget_get_parent (gui->topic_entry);
|
||||
if (topic_scroller && GTK_IS_SCROLLED_WINDOW (topic_scroller))
|
||||
mg_configure_topic_scroller (topic_scroller, gui->topic_entry);
|
||||
}
|
||||
|
||||
if (gui->input_box && prefs.hex_gui_input_style)
|
||||
theme_manager_apply_entry_palette (gui->input_box, font);
|
||||
|
||||
if (gui->chanview)
|
||||
chanview_apply_theme (gui->chanview);
|
||||
|
||||
if (gui->user_tree)
|
||||
theme_manager_apply_userlist_style (gui->user_tree,
|
||||
theme_manager_get_userlist_palette_behavior (font));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mg_create_topicbar (session *sess, GtkWidget *box)
|
||||
{
|
||||
GtkWidget *vbox, *hbox, *mode_hbox, *topic, *bbox;
|
||||
GtkWidget *vbox, *hbox, *mode_hbox, *topic, *bbox, *topic_scroller;
|
||||
session_gui *gui = sess->gui;
|
||||
|
||||
gui->topic_bar = vbox = mg_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
|
||||
@@ -2984,12 +3047,15 @@ mg_create_topicbar (session *sess, GtkWidget *box)
|
||||
sess->res->tab = NULL;
|
||||
|
||||
gui->topic_entry = topic = gtk_text_view_new ();
|
||||
gtk_widget_set_name (topic, "zoitechat-inputbox");
|
||||
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (topic), GTK_WRAP_WORD_CHAR);
|
||||
gtk_widget_set_name (topic, "zoitechat-topicbox");
|
||||
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (topic), GTK_WRAP_WORD);
|
||||
gtk_text_view_set_left_margin (GTK_TEXT_VIEW (topic), 4);
|
||||
gtk_text_view_set_right_margin (GTK_TEXT_VIEW (topic), 4);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), topic, TRUE, TRUE, 0);
|
||||
mg_apply_emoji_fallback_widget (topic);
|
||||
topic_scroller = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (topic_scroller), topic);
|
||||
theme_manager_apply_entry_palette (topic, input_style ? input_style->font_desc : NULL);
|
||||
mg_configure_topic_scroller (topic_scroller, topic);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), topic_scroller, TRUE, TRUE, 0);
|
||||
gtk_widget_add_events (topic, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
|
||||
g_signal_connect (G_OBJECT (topic), "key-press-event",
|
||||
|
||||
@@ -37,6 +37,7 @@ GtkWidget *mg_create_generic_tab (char *name, char *title, int force_toplevel, i
|
||||
void mg_set_title (GtkWidget *button, char *title);
|
||||
void mg_set_access_icon (session_gui *gui, GdkPixbuf *pix, gboolean away);
|
||||
void mg_apply_setup (void);
|
||||
void mg_apply_session_font_prefs (session_gui *gui);
|
||||
void mg_close_sess (session *);
|
||||
void mg_tab_close (session *sess);
|
||||
void mg_detach (session *sess, int mode);
|
||||
|
||||
@@ -91,6 +91,7 @@ static GtkWidget *edit_label_real;
|
||||
static GtkWidget *edit_label_user;
|
||||
static GtkWidget *edit_trees[N_TREES];
|
||||
static GtkWidget *edit_button_cert_generate;
|
||||
static GtkWidget *edit_button_cert_import;
|
||||
static GtkWidget *edit_button_cert_info;
|
||||
static GtkWidget *edit_button_cert_delete;
|
||||
|
||||
@@ -135,12 +136,98 @@ servlist_update_cert_buttons (ircnet *net)
|
||||
|
||||
if (edit_button_cert_generate)
|
||||
gtk_widget_set_visible (edit_button_cert_generate, !has_cert);
|
||||
if (edit_button_cert_import)
|
||||
gtk_widget_set_visible (edit_button_cert_import, !has_cert);
|
||||
if (edit_button_cert_info)
|
||||
gtk_widget_set_visible (edit_button_cert_info, has_cert);
|
||||
if (edit_button_cert_delete)
|
||||
gtk_widget_set_visible (edit_button_cert_delete, has_cert);
|
||||
}
|
||||
|
||||
static void
|
||||
servlist_import_client_cert_cb (GtkWidget *button, gpointer userdata)
|
||||
{
|
||||
ircnet *net = (ircnet *)userdata;
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *message;
|
||||
GtkFileFilter *filter;
|
||||
char *cert_dir;
|
||||
char *cert_file;
|
||||
char *source_file;
|
||||
char *contents;
|
||||
gsize length;
|
||||
|
||||
if (!net || !net->name || !net->name[0])
|
||||
return;
|
||||
|
||||
dialog = gtk_file_chooser_dialog_new (_("Import Client Certificate"),
|
||||
GTK_WINDOW (edit_win),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
||||
_("_Open"), GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, _("Certificate files"));
|
||||
gtk_file_filter_add_pattern (filter, "*.pem");
|
||||
gtk_file_filter_add_pattern (filter, "*.crt");
|
||||
gtk_file_filter_add_pattern (filter, "*.cer");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, _("All files"));
|
||||
gtk_file_filter_add_pattern (filter, "*");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
|
||||
theme_manager_attach_window (dialog);
|
||||
|
||||
if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
gtk_widget_destroy (dialog);
|
||||
return;
|
||||
}
|
||||
|
||||
source_file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
|
||||
gtk_widget_destroy (dialog);
|
||||
if (!source_file)
|
||||
return;
|
||||
|
||||
cert_dir = g_build_filename (get_xdir (), "certs", NULL);
|
||||
cert_file = servlist_get_cert_file (net);
|
||||
contents = NULL;
|
||||
length = 0;
|
||||
|
||||
if (cert_file &&
|
||||
g_mkdir_with_parents (cert_dir, 0700) == 0 &&
|
||||
g_file_get_contents (source_file, &contents, &length, NULL) &&
|
||||
g_file_set_contents (cert_file, contents, length, NULL))
|
||||
{
|
||||
chmod (cert_file, 0600);
|
||||
servlist_update_cert_buttons (net);
|
||||
message = gtk_message_dialog_new (GTK_WINDOW (edit_win),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_INFO,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
_("Client certificate imported for \"%s\"."),
|
||||
net->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
message = gtk_message_dialog_new (GTK_WINDOW (edit_win),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
_("Failed to import client certificate for \"%s\"."),
|
||||
net->name);
|
||||
}
|
||||
|
||||
theme_manager_attach_window (message);
|
||||
g_signal_connect_swapped (message, "response", G_CALLBACK (gtk_widget_destroy), message);
|
||||
gtk_widget_show (message);
|
||||
|
||||
g_free (contents);
|
||||
g_free (cert_file);
|
||||
g_free (cert_dir);
|
||||
g_free (source_file);
|
||||
}
|
||||
|
||||
static void
|
||||
servlist_generate_client_cert_cb (GtkWidget *button, gpointer userdata)
|
||||
{
|
||||
@@ -165,6 +252,7 @@ servlist_generate_client_cert_cb (GtkWidget *button, gpointer userdata)
|
||||
gboolean success;
|
||||
gint status;
|
||||
char *argv[20];
|
||||
char **envp;
|
||||
|
||||
if (!net || !net->name || !net->name[0])
|
||||
return;
|
||||
@@ -187,6 +275,7 @@ servlist_generate_client_cert_cb (GtkWidget *button, gpointer userdata)
|
||||
crt_len = 0;
|
||||
success = FALSE;
|
||||
status = 0;
|
||||
envp = g_environ_unsetenv (g_get_environ (), "LD_LIBRARY_PATH");
|
||||
|
||||
if (g_mkdir_with_parents (cert_dir, 0700) == 0 &&
|
||||
g_file_set_contents (openssl_conf, conf_data, -1, NULL))
|
||||
@@ -212,7 +301,7 @@ servlist_generate_client_cert_cb (GtkWidget *button, gpointer userdata)
|
||||
argv[18] = subject;
|
||||
argv[19] = NULL;
|
||||
|
||||
spawned = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
||||
spawned = g_spawn_sync (NULL, argv, envp, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
||||
&stdout_data, &stderr_data, &status, NULL);
|
||||
if (spawned && g_spawn_check_exit_status (status, NULL) &&
|
||||
g_file_get_contents (key_file, &key_data, &key_len, NULL) &&
|
||||
@@ -267,6 +356,7 @@ servlist_generate_client_cert_cb (GtkWidget *button, gpointer userdata)
|
||||
g_free (openssl_conf);
|
||||
g_free (cert_file);
|
||||
g_free (cert_dir);
|
||||
g_strfreev (envp);
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
@@ -284,6 +374,7 @@ servlist_cert_info_cb (GtkWidget *button, gpointer userdata)
|
||||
gboolean spawned;
|
||||
gint status;
|
||||
char *argv[12];
|
||||
char **envp;
|
||||
|
||||
cert_file = servlist_get_cert_file (net);
|
||||
if (!cert_file)
|
||||
@@ -292,6 +383,7 @@ servlist_cert_info_cb (GtkWidget *button, gpointer userdata)
|
||||
stdout_data = NULL;
|
||||
stderr_data = NULL;
|
||||
status = 0;
|
||||
envp = g_environ_unsetenv (g_get_environ (), "LD_LIBRARY_PATH");
|
||||
argv[0] = "openssl";
|
||||
argv[1] = "x509";
|
||||
argv[2] = "-in";
|
||||
@@ -305,7 +397,7 @@ servlist_cert_info_cb (GtkWidget *button, gpointer userdata)
|
||||
argv[10] = "-sha256";
|
||||
argv[11] = NULL;
|
||||
|
||||
spawned = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
||||
spawned = g_spawn_sync (NULL, argv, envp, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
||||
&stdout_data, &stderr_data, &status, NULL);
|
||||
|
||||
if (spawned && g_spawn_check_exit_status (status, NULL) && stdout_data && stdout_data[0])
|
||||
@@ -336,6 +428,7 @@ servlist_cert_info_cb (GtkWidget *button, gpointer userdata)
|
||||
g_free (stdout_data);
|
||||
g_free (stderr_data);
|
||||
g_free (cert_file);
|
||||
g_strfreev (envp);
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
@@ -2285,6 +2378,11 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
|
||||
G_CALLBACK (servlist_generate_client_cert_cb), net);
|
||||
gtk_box_pack_start (GTK_BOX (hbox_cert_buttons), edit_button_cert_generate, FALSE, FALSE, 0);
|
||||
|
||||
edit_button_cert_import = gtk_button_new_with_mnemonic (_("Import client SSL cert"));
|
||||
g_signal_connect (G_OBJECT (edit_button_cert_import), "clicked",
|
||||
G_CALLBACK (servlist_import_client_cert_cb), net);
|
||||
gtk_box_pack_start (GTK_BOX (hbox_cert_buttons), edit_button_cert_import, FALSE, FALSE, 0);
|
||||
|
||||
edit_button_cert_info = gtk_button_new_with_mnemonic (_("Client SSL cert info"));
|
||||
g_signal_connect (G_OBJECT (edit_button_cert_info), "clicked",
|
||||
G_CALLBACK (servlist_cert_info_cb), net);
|
||||
|
||||
@@ -2066,7 +2066,7 @@ setup_apply_to_sess (session_gui *gui)
|
||||
{
|
||||
mg_update_xtext (gui->xtext);
|
||||
|
||||
theme_preferences_apply_to_session (gui, input_style);
|
||||
mg_apply_session_font_prefs (gui);
|
||||
|
||||
if (prefs.hex_gui_ulist_buttons)
|
||||
gtk_widget_show (gui->button_box);
|
||||
|
||||
@@ -367,6 +367,12 @@ theme_css_build_toplevel_classes (void)
|
||||
"color: @theme_fg_color;"
|
||||
"border-color: @theme_bg_color;"
|
||||
"}"
|
||||
"window.%s menuitem:hover, window.%s menuitem:selected {"
|
||||
"background-color: @theme_selected_bg_color;"
|
||||
"background-image: none;"
|
||||
"color: @theme_selected_fg_color;"
|
||||
"border-color: @theme_selected_bg_color;"
|
||||
"}"
|
||||
"window.%s, window.%s:backdrop, .%s {"
|
||||
"background-color: #f6f6f6;"
|
||||
"color: #101010;"
|
||||
@@ -377,6 +383,12 @@ theme_css_build_toplevel_classes (void)
|
||||
"background-image: none;"
|
||||
"color: @theme_fg_color;"
|
||||
"border-color: @theme_bg_color;"
|
||||
"}"
|
||||
"window.%s menuitem:hover, window.%s menuitem:selected {"
|
||||
"background-color: @theme_selected_bg_color;"
|
||||
"background-image: none;"
|
||||
"color: @theme_selected_fg_color;"
|
||||
"border-color: @theme_selected_bg_color;"
|
||||
"}",
|
||||
theme_css_selector_dark_class,
|
||||
theme_css_selector_dark_class,
|
||||
@@ -387,6 +399,10 @@ theme_css_build_toplevel_classes (void)
|
||||
theme_css_selector_dark_class,
|
||||
theme_css_selector_dark_class,
|
||||
theme_css_selector_dark_class,
|
||||
theme_css_selector_dark_class,
|
||||
theme_css_selector_dark_class,
|
||||
theme_css_selector_light_class,
|
||||
theme_css_selector_light_class,
|
||||
theme_css_selector_light_class,
|
||||
theme_css_selector_light_class,
|
||||
theme_css_selector_light_class,
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.18.0~pre5
|
||||
2.18.0~pre6
|
||||
|
||||
Reference in New Issue
Block a user