mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-03-10 07:50:19 +00:00
@@ -437,7 +437,7 @@ const struct prefs vars[] =
|
||||
{"gui_tab_dialogs", P_OFFINT (hex_gui_tab_dialogs), TYPE_BOOL},
|
||||
{"gui_tab_dots", P_OFFINT (hex_gui_tab_dots), TYPE_BOOL},
|
||||
{"gui_tab_icons", P_OFFINT (hex_gui_tab_icons), TYPE_BOOL},
|
||||
{"gui_dark_mode", P_OFFINT (hex_gui_dark_mode), TYPE_BOOL},
|
||||
{"gui_dark_mode", P_OFFINT (hex_gui_dark_mode), TYPE_INT},
|
||||
{"gui_tab_layout", P_OFFINT (hex_gui_tab_layout), TYPE_INT},
|
||||
{"gui_tab_middleclose", P_OFFINT (hex_gui_tab_middleclose), TYPE_BOOL},
|
||||
{"gui_tab_newtofront", P_OFFINT (hex_gui_tab_newtofront), TYPE_INT},
|
||||
|
||||
@@ -83,6 +83,10 @@ gboolean zoitechat_import_theme (const char *path, GError **error);
|
||||
#define USERNAMELEN 10
|
||||
#define HIDDEN_CHAR 8 /* invisible character for xtext */
|
||||
|
||||
#define ZOITECHAT_DARK_MODE_AUTO 0
|
||||
#define ZOITECHAT_DARK_MODE_DARK 1
|
||||
#define ZOITECHAT_DARK_MODE_LIGHT 2
|
||||
|
||||
struct nbexec
|
||||
{
|
||||
int myfd;
|
||||
|
||||
@@ -117,7 +117,11 @@ cv_tree_init (chanview *cv)
|
||||
view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (cv->store));
|
||||
gtk_widget_set_name (view, "zoitechat-tree");
|
||||
if (cv->style)
|
||||
gtk_widget_set_style (view, cv->style);
|
||||
{
|
||||
gtk_widget_modify_base (view, GTK_STATE_NORMAL, &cv->style->base[GTK_STATE_NORMAL]);
|
||||
gtk_widget_modify_text (view, GTK_STATE_NORMAL, &cv->style->text[GTK_STATE_NORMAL]);
|
||||
gtk_widget_modify_font (view, cv->style->font_desc);
|
||||
}
|
||||
/*gtk_widget_modify_base (view, GTK_STATE_NORMAL, &colors[COL_BG]);*/
|
||||
gtk_widget_set_can_focus (view, FALSE);
|
||||
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
|
||||
|
||||
@@ -122,7 +122,7 @@ chanview_apply_theme (chanview *cv)
|
||||
return;
|
||||
|
||||
w = GTK_WIDGET (tv->tree);
|
||||
if (prefs.hex_gui_dark_mode)
|
||||
if (fe_dark_mode_is_enabled () || prefs.hex_gui_dark_mode == ZOITECHAT_DARK_MODE_LIGHT)
|
||||
{
|
||||
gtk_widget_modify_base (w, GTK_STATE_NORMAL, &colors[COL_BG]);
|
||||
gtk_widget_modify_text (w, GTK_STATE_NORMAL, &colors[COL_FG]);
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
#include <canberra.h>
|
||||
#endif
|
||||
|
||||
GdkPixmap *channelwin_pix;
|
||||
cairo_surface_t *channelwin_pix;
|
||||
|
||||
#ifdef USE_LIBCANBERRA
|
||||
static ca_context *ca_con;
|
||||
@@ -270,6 +270,88 @@ static const char adwaita_workaround_rc[] =
|
||||
"}"
|
||||
"widget \"*.zoitechat-inputbox\" style \"zoitechat-input-workaround\"";
|
||||
|
||||
static gboolean
|
||||
fe_system_prefers_dark (void)
|
||||
{
|
||||
GtkSettings *settings = gtk_settings_get_default ();
|
||||
gboolean prefer_dark = FALSE;
|
||||
char *theme_name = NULL;
|
||||
|
||||
if (!settings)
|
||||
return FALSE;
|
||||
|
||||
if (g_object_class_find_property (G_OBJECT_GET_CLASS (settings),
|
||||
"gtk-application-prefer-dark-theme"))
|
||||
{
|
||||
g_object_get (settings, "gtk-application-prefer-dark-theme", &prefer_dark, NULL);
|
||||
}
|
||||
|
||||
if (!prefer_dark)
|
||||
{
|
||||
g_object_get (settings, "gtk-theme-name", &theme_name, NULL);
|
||||
if (theme_name)
|
||||
{
|
||||
char *lower = g_ascii_strdown (theme_name, -1);
|
||||
if (g_str_has_suffix (lower, "-dark") || g_strrstr (lower, "dark"))
|
||||
prefer_dark = TRUE;
|
||||
g_free (lower);
|
||||
g_free (theme_name);
|
||||
}
|
||||
}
|
||||
|
||||
return prefer_dark;
|
||||
}
|
||||
|
||||
static gboolean auto_dark_mode_enabled = FALSE;
|
||||
|
||||
static void
|
||||
fe_auto_dark_mode_changed (GtkSettings *settings, GParamSpec *pspec, gpointer data)
|
||||
{
|
||||
gboolean enabled;
|
||||
|
||||
(void) settings;
|
||||
(void) pspec;
|
||||
(void) data;
|
||||
|
||||
if (prefs.hex_gui_dark_mode != ZOITECHAT_DARK_MODE_AUTO)
|
||||
return;
|
||||
|
||||
enabled = fe_system_prefers_dark ();
|
||||
if (enabled == auto_dark_mode_enabled)
|
||||
return;
|
||||
|
||||
auto_dark_mode_enabled = enabled;
|
||||
palette_apply_dark_mode (enabled);
|
||||
setup_apply_real (0, TRUE, FALSE, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
fe_set_auto_dark_mode_state (gboolean enabled)
|
||||
{
|
||||
auto_dark_mode_enabled = enabled;
|
||||
}
|
||||
|
||||
gboolean
|
||||
fe_dark_mode_is_enabled_for (unsigned int mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case ZOITECHAT_DARK_MODE_DARK:
|
||||
return TRUE;
|
||||
case ZOITECHAT_DARK_MODE_LIGHT:
|
||||
return FALSE;
|
||||
case ZOITECHAT_DARK_MODE_AUTO:
|
||||
default:
|
||||
return fe_system_prefers_dark ();
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
fe_dark_mode_is_enabled (void)
|
||||
{
|
||||
return fe_dark_mode_is_enabled_for (prefs.hex_gui_dark_mode);
|
||||
}
|
||||
|
||||
GtkStyle *
|
||||
create_input_style (GtkStyle *style)
|
||||
{
|
||||
@@ -316,8 +398,10 @@ create_input_style (GtkStyle *style)
|
||||
void
|
||||
fe_init (void)
|
||||
{
|
||||
GtkSettings *settings;
|
||||
|
||||
palette_load ();
|
||||
palette_apply_dark_mode (prefs.hex_gui_dark_mode);
|
||||
palette_apply_dark_mode (fe_dark_mode_is_enabled ());
|
||||
key_init ();
|
||||
pixmaps_init ();
|
||||
|
||||
@@ -326,6 +410,16 @@ fe_init (void)
|
||||
#endif
|
||||
channelwin_pix = pixmap_load_from_file (prefs.hex_text_background);
|
||||
input_style = create_input_style (gtk_style_new ());
|
||||
|
||||
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_signal_connect (settings, "notify::gtk-theme-name",
|
||||
G_CALLBACK (fe_auto_dark_mode_changed), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_GTK_MAC
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <cairo.h>
|
||||
|
||||
#ifdef HAVE_GTK_MAC
|
||||
#include <gtkosxapplication.h>
|
||||
@@ -178,8 +179,12 @@ typedef struct session_gui
|
||||
|
||||
} session_gui;
|
||||
|
||||
extern GdkPixmap *channelwin_pix;
|
||||
extern GdkPixmap *dialogwin_pix;
|
||||
extern cairo_surface_t *channelwin_pix;
|
||||
extern cairo_surface_t *dialogwin_pix;
|
||||
|
||||
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);
|
||||
|
||||
#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)
|
||||
|
||||
@@ -803,6 +803,7 @@ key_dialog_show ()
|
||||
GtkWidget *vbox, *box;
|
||||
GtkWidget *view, *xtext;
|
||||
GtkListStore *store;
|
||||
XTextColor xtext_palette[XTEXT_COLS];
|
||||
char buf[128];
|
||||
|
||||
if (key_dialog)
|
||||
@@ -816,7 +817,8 @@ key_dialog_show ()
|
||||
NULL, 600, 360, &vbox, 0);
|
||||
|
||||
view = key_dialog_treeview_new (vbox);
|
||||
xtext = gtk_xtext_new (colors, 0);
|
||||
palette_get_xtext_colors (xtext_palette, XTEXT_COLS);
|
||||
xtext = gtk_xtext_new (xtext_palette, 0);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), xtext, FALSE, TRUE, 2);
|
||||
gtk_xtext_set_font (GTK_XTEXT (xtext), prefs.hex_text_font);
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ gtkutil_check_file (char *filename, struct file_req *freq)
|
||||
}
|
||||
else
|
||||
{
|
||||
GFileInfo *fi = g_file_query_info (file, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
|
||||
GFileInfo *fi = g_file_query_info (file, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
|
||||
|
||||
if (fi != NULL)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,10 @@
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gdk/gdkcairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "../common/zoitechat.h"
|
||||
#include "../common/fe.h"
|
||||
@@ -82,6 +85,136 @@ 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 inline void
|
||||
mg_set_source_color (cairo_t *cr, const XTextColor *color)
|
||||
{
|
||||
cairo_set_source_rgba (cr, color->red, color->green, color->blue, color->alpha);
|
||||
}
|
||||
|
||||
static inline guint16
|
||||
mg_color_component_to_pango (double value)
|
||||
{
|
||||
if (value < 0.0)
|
||||
value = 0.0;
|
||||
if (value > 1.0)
|
||||
value = 1.0;
|
||||
|
||||
return (guint16)(value * 65535.0 + 0.5);
|
||||
}
|
||||
|
||||
static void
|
||||
mg_pixbuf_destroy (guchar *pixels, gpointer data)
|
||||
{
|
||||
g_free (pixels);
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
mg_pixbuf_from_surface (cairo_surface_t *surface, int width, int height)
|
||||
{
|
||||
const unsigned char *src;
|
||||
int src_stride;
|
||||
int rowstride;
|
||||
guchar *pixels;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
if (!surface || width <= 0 || height <= 0)
|
||||
return NULL;
|
||||
|
||||
src = cairo_image_surface_get_data (surface);
|
||||
src_stride = cairo_image_surface_get_stride (surface);
|
||||
rowstride = width * 4;
|
||||
pixels = g_malloc ((gsize)rowstride * height);
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
const unsigned char *src_row = src + (y * src_stride);
|
||||
guchar *dest_row = pixels + (y * rowstride);
|
||||
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
guint8 a;
|
||||
guint8 r;
|
||||
guint8 g;
|
||||
guint8 b;
|
||||
const unsigned char *src_px = src_row + (x * 4);
|
||||
guchar *dest_px = dest_row + (x * 4);
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
b = src_px[0];
|
||||
g = src_px[1];
|
||||
r = src_px[2];
|
||||
a = src_px[3];
|
||||
#else
|
||||
a = src_px[0];
|
||||
r = src_px[1];
|
||||
g = src_px[2];
|
||||
b = src_px[3];
|
||||
#endif
|
||||
|
||||
if (a)
|
||||
{
|
||||
r = (guint8)((r * 255 + (a / 2)) / a);
|
||||
g = (guint8)((g * 255 + (a / 2)) / a);
|
||||
b = (guint8)((b * 255 + (a / 2)) / a);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = g = b = 0;
|
||||
}
|
||||
|
||||
dest_px[0] = r;
|
||||
dest_px[1] = g;
|
||||
dest_px[2] = b;
|
||||
dest_px[3] = a;
|
||||
}
|
||||
}
|
||||
|
||||
return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8,
|
||||
width, height, rowstride, mg_pixbuf_destroy, NULL);
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
mg_pixbuf_from_window (GdkWindow *window, int width, int height)
|
||||
{
|
||||
int src_width;
|
||||
int src_height;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
if (!window)
|
||||
return NULL;
|
||||
|
||||
src_width = gdk_window_get_width (window);
|
||||
src_height = gdk_window_get_height (window);
|
||||
if (width <= 0 || height <= 0)
|
||||
{
|
||||
width = src_width;
|
||||
height = src_height;
|
||||
}
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return NULL;
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
|
||||
{
|
||||
cairo_surface_destroy (surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cr = cairo_create (surface);
|
||||
gdk_cairo_set_source_window (cr, window, 0.0, 0.0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
pixbuf = mg_pixbuf_from_surface (surface, width, height);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
static void mg_create_entry (session *sess, GtkWidget *box);
|
||||
static void mg_create_search (session *sess, GtkWidget *box);
|
||||
#ifdef G_OS_WIN32
|
||||
@@ -106,7 +239,7 @@ static PangoAttrList *newmsg_list;
|
||||
static PangoAttrList *plain_list = NULL;
|
||||
|
||||
static PangoAttrList *
|
||||
mg_attr_list_create (GdkColor *col, int size)
|
||||
mg_attr_list_create (const XTextColor *col, int size)
|
||||
{
|
||||
PangoAttribute *attr;
|
||||
PangoAttrList *list;
|
||||
@@ -115,7 +248,10 @@ mg_attr_list_create (GdkColor *col, int size)
|
||||
|
||||
if (col)
|
||||
{
|
||||
attr = pango_attr_foreground_new (col->red, col->green, col->blue);
|
||||
attr = pango_attr_foreground_new (
|
||||
mg_color_component_to_pango (col->red),
|
||||
mg_color_component_to_pango (col->green),
|
||||
mg_color_component_to_pango (col->blue));
|
||||
attr->start_index = 0;
|
||||
attr->end_index = 0xffff;
|
||||
pango_attr_list_insert (list, attr);
|
||||
@@ -135,6 +271,8 @@ mg_attr_list_create (GdkColor *col, int size)
|
||||
static void
|
||||
mg_create_tab_colors (void)
|
||||
{
|
||||
XTextColor gui_palette[MAX_COL + 1];
|
||||
|
||||
if (plain_list)
|
||||
{
|
||||
pango_attr_list_unref (plain_list);
|
||||
@@ -144,11 +282,12 @@ mg_create_tab_colors (void)
|
||||
pango_attr_list_unref (away_list);
|
||||
}
|
||||
|
||||
palette_get_xtext_colors (gui_palette, G_N_ELEMENTS (gui_palette));
|
||||
plain_list = mg_attr_list_create (NULL, prefs.hex_gui_tab_small);
|
||||
newdata_list = mg_attr_list_create (&colors[COL_NEW_DATA], prefs.hex_gui_tab_small);
|
||||
nickseen_list = mg_attr_list_create (&colors[COL_HILIGHT], prefs.hex_gui_tab_small);
|
||||
newmsg_list = mg_attr_list_create (&colors[COL_NEW_MSG], prefs.hex_gui_tab_small);
|
||||
away_list = mg_attr_list_create (&colors[COL_AWAY], FALSE);
|
||||
newdata_list = mg_attr_list_create (&gui_palette[COL_NEW_DATA], prefs.hex_gui_tab_small);
|
||||
nickseen_list = mg_attr_list_create (&gui_palette[COL_HILIGHT], prefs.hex_gui_tab_small);
|
||||
newmsg_list = mg_attr_list_create (&gui_palette[COL_NEW_MSG], prefs.hex_gui_tab_small);
|
||||
away_list = mg_attr_list_create (&gui_palette[COL_AWAY], FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2314,8 +2453,10 @@ mg_update_xtext (GtkWidget *wid)
|
||||
{
|
||||
GtkXText *xtext = GTK_XTEXT (wid);
|
||||
const gchar *font_name;
|
||||
XTextColor xtext_palette[XTEXT_COLS];
|
||||
|
||||
gtk_xtext_set_palette (xtext, colors);
|
||||
palette_get_xtext_colors (xtext_palette, XTEXT_COLS);
|
||||
gtk_xtext_set_palette (xtext, xtext_palette);
|
||||
gtk_xtext_set_max_lines (xtext, prefs.hex_text_max_lines);
|
||||
gtk_xtext_set_background (xtext, channelwin_pix);
|
||||
gtk_xtext_set_wordwrap (xtext, prefs.hex_text_wordwrap);
|
||||
@@ -2340,6 +2481,7 @@ mg_create_textarea (session *sess, GtkWidget *box)
|
||||
{
|
||||
GtkWidget *inbox, *vbox, *frame;
|
||||
GtkXText *xtext;
|
||||
XTextColor xtext_palette[XTEXT_COLS];
|
||||
session_gui *gui = sess->gui;
|
||||
static const GtkTargetEntry dnd_targets[] =
|
||||
{
|
||||
@@ -2360,7 +2502,8 @@ mg_create_textarea (session *sess, GtkWidget *box)
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
||||
gtk_container_add (GTK_CONTAINER (inbox), frame);
|
||||
|
||||
gui->xtext = gtk_xtext_new (colors, TRUE);
|
||||
palette_get_xtext_colors (xtext_palette, XTEXT_COLS);
|
||||
gui->xtext = gtk_xtext_new (xtext_palette, TRUE);
|
||||
xtext = GTK_XTEXT (gui->xtext);
|
||||
gtk_xtext_set_max_indent (xtext, prefs.hex_text_max_indent);
|
||||
gtk_xtext_set_thin_separator (xtext, prefs.hex_text_thin_sep);
|
||||
@@ -2496,7 +2639,7 @@ mg_create_userlist (session_gui *gui, GtkWidget *box)
|
||||
|
||||
if (prefs.hex_gui_ulist_style)
|
||||
{
|
||||
gtk_widget_set_style (ulist, input_style);
|
||||
gtk_widget_modify_font (ulist, input_style->font_desc);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2507,7 +2650,7 @@ mg_create_userlist (session_gui *gui, GtkWidget *box)
|
||||
* - When "Dark mode" is enabled, we also force the user list to use the
|
||||
* palette colors so it doesn't stay blindingly white on GTK2 themes.
|
||||
*/
|
||||
if (prefs.hex_gui_ulist_style || prefs.hex_gui_dark_mode)
|
||||
if (prefs.hex_gui_ulist_style || fe_dark_mode_is_enabled ())
|
||||
{
|
||||
gtk_widget_modify_base (ulist, GTK_STATE_NORMAL, &colors[COL_BG]);
|
||||
gtk_widget_modify_text (ulist, GTK_STATE_NORMAL, &colors[COL_FG]);
|
||||
@@ -4053,18 +4196,20 @@ gboolean
|
||||
mg_drag_begin_cb (GtkWidget *widget, GdkDragContext *context, gpointer userdata)
|
||||
{
|
||||
int width, height;
|
||||
GdkColormap *cmap;
|
||||
GdkPixbuf *pix, *pix2;
|
||||
GdkWindow *window;
|
||||
|
||||
/* ignore file drops */
|
||||
if (!mg_is_gui_target (context))
|
||||
return FALSE;
|
||||
|
||||
cmap = gtk_widget_get_colormap (widget);
|
||||
width = gdk_window_get_width (gtk_widget_get_window (widget));
|
||||
height = gdk_window_get_height (gtk_widget_get_window (widget));
|
||||
window = gtk_widget_get_window (widget);
|
||||
width = gdk_window_get_width (window);
|
||||
height = gdk_window_get_height (window);
|
||||
|
||||
pix = gdk_pixbuf_get_from_drawable (NULL, gtk_widget_get_window (widget), cmap, 0, 0, 0, 0, width, height);
|
||||
pix = mg_pixbuf_from_window (window, width, height);
|
||||
if (!pix)
|
||||
return FALSE;
|
||||
pix2 = gdk_pixbuf_scale_simple (pix, width * 4 / 5, height / 2, GDK_INTERP_HYPER);
|
||||
g_object_unref (pix);
|
||||
|
||||
@@ -4115,12 +4260,11 @@ mg_drag_drop_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, guint
|
||||
gboolean
|
||||
mg_drag_motion_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, guint time, gpointer scbar)
|
||||
{
|
||||
GdkGC *gc;
|
||||
GdkColor col;
|
||||
GdkGCValues val;
|
||||
XTextColor col;
|
||||
cairo_t *cr;
|
||||
int half, width, height;
|
||||
int ox, oy;
|
||||
GdkDrawable *draw;
|
||||
GdkWindow *window;
|
||||
GtkAllocation allocation;
|
||||
|
||||
/* ignore file drops */
|
||||
@@ -4134,55 +4278,57 @@ mg_drag_motion_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, gui
|
||||
oy = allocation.y;
|
||||
width = allocation.width;
|
||||
height = allocation.height;
|
||||
draw = gtk_widget_get_window (widget);
|
||||
window = gtk_widget_get_window (widget);
|
||||
}
|
||||
else
|
||||
{
|
||||
ox = oy = 0;
|
||||
width = gdk_window_get_width (gtk_widget_get_window (widget));
|
||||
height = gdk_window_get_height (gtk_widget_get_window (widget));
|
||||
draw = gtk_widget_get_window (widget);
|
||||
window = gtk_widget_get_window (widget);
|
||||
width = gdk_window_get_width (window);
|
||||
height = gdk_window_get_height (window);
|
||||
}
|
||||
|
||||
val.subwindow_mode = GDK_INCLUDE_INFERIORS;
|
||||
val.graphics_exposures = 0;
|
||||
val.function = GDK_XOR;
|
||||
|
||||
gc = gdk_gc_new_with_values (gtk_widget_get_window (widget), &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW | GDK_GC_FUNCTION);
|
||||
col.red = rand() % 0xffff;
|
||||
col.green = rand() % 0xffff;
|
||||
col.blue = rand() % 0xffff;
|
||||
gdk_colormap_alloc_color (gtk_widget_get_colormap (widget), &col, FALSE, TRUE);
|
||||
gdk_gc_set_foreground (gc, &col);
|
||||
col.red = (double)rand () / (double)RAND_MAX;
|
||||
col.green = (double)rand () / (double)RAND_MAX;
|
||||
col.blue = (double)rand () / (double)RAND_MAX;
|
||||
col.alpha = 1.0;
|
||||
cr = gdk_cairo_create (window);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_XOR);
|
||||
mg_set_source_color (cr, &col);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
|
||||
half = height / 2;
|
||||
|
||||
#if 0
|
||||
/* are both tree/userlist on the same side? */
|
||||
GtkPaned *paned;
|
||||
paned = (GtkPaned *)widget->parent->parent;
|
||||
if (paned->child1 != NULL && paned->child2 != NULL)
|
||||
{
|
||||
gdk_draw_rectangle (draw, gc, 0, 1, 2, width - 3, height - 4);
|
||||
gdk_draw_rectangle (draw, gc, 0, 0, 1, width - 1, height - 2);
|
||||
g_object_unref (gc);
|
||||
cairo_rectangle (cr, 1 + ox, 2 + oy, width - 3, height - 4);
|
||||
cairo_rectangle (cr, 0 + ox, 1 + oy, width - 1, height - 2);
|
||||
cairo_stroke (cr);
|
||||
cairo_destroy (cr);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (y < half)
|
||||
{
|
||||
gdk_draw_rectangle (draw, gc, FALSE, 1 + ox, 2 + oy, width - 3, half - 4);
|
||||
gdk_draw_rectangle (draw, gc, FALSE, 0 + ox, 1 + oy, width - 1, half - 2);
|
||||
cairo_rectangle (cr, 1 + ox, 2 + oy, width - 3, half - 4);
|
||||
cairo_rectangle (cr, 0 + ox, 1 + oy, width - 1, half - 2);
|
||||
cairo_stroke (cr);
|
||||
gtk_widget_queue_draw_area (widget, ox, half + oy, width, height - half);
|
||||
}
|
||||
else
|
||||
{
|
||||
gdk_draw_rectangle (draw, gc, FALSE, 0 + ox, half + 1 + oy, width - 1, half - 2);
|
||||
gdk_draw_rectangle (draw, gc, FALSE, 1 + ox, half + 2 + oy, width - 3, half - 4);
|
||||
cairo_rectangle (cr, 0 + ox, half + 1 + oy, width - 1, half - 2);
|
||||
cairo_rectangle (cr, 1 + ox, half + 2 + oy, width - 3, half - 4);
|
||||
cairo_stroke (cr);
|
||||
gtk_widget_queue_draw_area (widget, ox, oy, width, half);
|
||||
}
|
||||
|
||||
g_object_unref (gc);
|
||||
cairo_destroy (cr);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,18 @@
|
||||
#include "../common/cfgfiles.h"
|
||||
#include "../common/typedef.h"
|
||||
|
||||
static XTextColor
|
||||
palette_color_from_gdk (const GdkColor *color)
|
||||
{
|
||||
XTextColor result;
|
||||
|
||||
result.red = color->red / 65535.0;
|
||||
result.green = color->green / 65535.0;
|
||||
result.blue = color->blue / 65535.0;
|
||||
result.alpha = 1.0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GdkColor colors[] = {
|
||||
/* colors for xtext */
|
||||
@@ -143,6 +155,18 @@ static const GdkColor dark_colors[MAX_COL + 1] = {
|
||||
{0, 0xf4f4, 0x4747, 0x4747}, /* 41 COL_SPELL (spellcheck underline) */
|
||||
};
|
||||
|
||||
void
|
||||
palette_get_xtext_colors (XTextColor *palette, size_t palette_len)
|
||||
{
|
||||
size_t i;
|
||||
size_t count = palette_len < G_N_ELEMENTS (colors) ? palette_len : G_N_ELEMENTS (colors);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
palette[i] = palette_color_from_gdk (&colors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
palette_user_set_color (int idx, const GdkColor *col)
|
||||
{
|
||||
@@ -287,20 +311,21 @@ palette_save (void)
|
||||
char prefname[256];
|
||||
const GdkColor *lightpal = colors;
|
||||
const GdkColor *darkpal = NULL;
|
||||
gboolean dark_mode_active = fe_dark_mode_is_enabled ();
|
||||
|
||||
/* If we're currently in dark mode, keep colors.conf's legacy keys as the user's light palette. */
|
||||
if (prefs.hex_gui_dark_mode && user_colors_valid)
|
||||
if (dark_mode_active && user_colors_valid)
|
||||
lightpal = user_colors;
|
||||
|
||||
/* If we're currently in light mode, ensure the snapshot stays in sync. */
|
||||
if (!prefs.hex_gui_dark_mode)
|
||||
if (!dark_mode_active)
|
||||
{
|
||||
memcpy (user_colors, colors, sizeof (user_colors));
|
||||
user_colors_valid = TRUE;
|
||||
}
|
||||
|
||||
/* If dark mode is enabled but we haven't snapshotted a custom dark palette yet, capture it now. */
|
||||
if (prefs.hex_gui_dark_mode && !dark_user_colors_valid)
|
||||
if (dark_mode_active && !dark_user_colors_valid)
|
||||
{
|
||||
memcpy (dark_user_colors, colors, sizeof (dark_user_colors));
|
||||
dark_user_colors_valid = TRUE;
|
||||
@@ -308,7 +333,7 @@ palette_save (void)
|
||||
|
||||
if (dark_user_colors_valid)
|
||||
darkpal = dark_user_colors;
|
||||
else if (prefs.hex_gui_dark_mode)
|
||||
else if (dark_mode_active)
|
||||
darkpal = colors; /* current dark palette (likely defaults) */
|
||||
|
||||
fh = zoitechat_open_file ("colors.conf", O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
|
||||
@@ -399,4 +424,3 @@ palette_apply_dark_mode (gboolean enable)
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#ifndef HEXCHAT_PALETTE_H
|
||||
#define HEXCHAT_PALETTE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "xtext-color.h"
|
||||
|
||||
extern GdkColor colors[];
|
||||
|
||||
#define COL_MARK_FG 32
|
||||
@@ -59,4 +63,6 @@ void palette_dark_set_color (int idx, const GdkColor *col);
|
||||
*/
|
||||
gboolean palette_apply_dark_mode (gboolean enable);
|
||||
|
||||
void palette_get_xtext_colors (XTextColor *palette, size_t palette_len);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <cairo.h>
|
||||
|
||||
GdkPixbuf *pix_ulist_voice;
|
||||
GdkPixbuf *pix_ulist_halfop;
|
||||
@@ -49,26 +50,89 @@ GdkPixbuf *pix_tree_util;
|
||||
GdkPixbuf *pix_book;
|
||||
GdkPixbuf *pix_zoitechat;
|
||||
|
||||
static GdkPixmap *
|
||||
static cairo_surface_t *
|
||||
pixbuf_to_cairo_surface (GdkPixbuf *pixbuf)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
gboolean has_alpha;
|
||||
int width;
|
||||
int height;
|
||||
int src_stride;
|
||||
int dest_stride;
|
||||
int n_channels;
|
||||
const guchar *src_pixels;
|
||||
unsigned char *dest_pixels;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
|
||||
|
||||
width = gdk_pixbuf_get_width (pixbuf);
|
||||
height = gdk_pixbuf_get_height (pixbuf);
|
||||
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
|
||||
n_channels = gdk_pixbuf_get_n_channels (pixbuf);
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
|
||||
{
|
||||
cairo_surface_destroy (surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
src_stride = gdk_pixbuf_get_rowstride (pixbuf);
|
||||
src_pixels = gdk_pixbuf_get_pixels (pixbuf);
|
||||
dest_stride = cairo_image_surface_get_stride (surface);
|
||||
dest_pixels = cairo_image_surface_get_data (surface);
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
const guchar *src_row = src_pixels + (y * src_stride);
|
||||
guint32 *dest_row = (guint32 *)(dest_pixels + (y * dest_stride));
|
||||
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
const guchar *src = src_row + (x * n_channels);
|
||||
guchar alpha = has_alpha ? src[3] : 0xff;
|
||||
guchar red = src[0];
|
||||
guchar green = src[1];
|
||||
guchar blue = src[2];
|
||||
guchar premul_red = (guchar)((red * alpha + 127) / 255);
|
||||
guchar premul_green = (guchar)((green * alpha + 127) / 255);
|
||||
guchar premul_blue = (guchar)((blue * alpha + 127) / 255);
|
||||
|
||||
dest_row[x] = ((guint32)alpha << 24) |
|
||||
((guint32)premul_red << 16) |
|
||||
((guint32)premul_green << 8) |
|
||||
((guint32)premul_blue);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_surface_mark_dirty (surface);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
pixmap_load_from_file_real (char *file)
|
||||
{
|
||||
GdkPixbuf *img;
|
||||
GdkPixmap *pixmap;
|
||||
cairo_surface_t *surface;
|
||||
|
||||
img = gdk_pixbuf_new_from_file (file, 0);
|
||||
if (!img)
|
||||
return NULL;
|
||||
gdk_pixbuf_render_pixmap_and_mask (img, &pixmap, NULL, 128);
|
||||
|
||||
surface = pixbuf_to_cairo_surface (img);
|
||||
g_object_unref (img);
|
||||
|
||||
return pixmap;
|
||||
return surface;
|
||||
}
|
||||
|
||||
GdkPixmap *
|
||||
cairo_surface_t *
|
||||
pixmap_load_from_file (char *filename)
|
||||
{
|
||||
char buf[256];
|
||||
GdkPixmap *pix;
|
||||
cairo_surface_t *pix;
|
||||
|
||||
if (filename[0] == '\0')
|
||||
return NULL;
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#ifndef HEXCHAT_PIXMAPS_H
|
||||
#define HEXCHAT_PIXMAPS_H
|
||||
|
||||
#include <cairo.h>
|
||||
|
||||
extern GdkPixbuf *pix_ulist_voice;
|
||||
extern GdkPixbuf *pix_ulist_halfop;
|
||||
extern GdkPixbuf *pix_ulist_op;
|
||||
@@ -40,7 +42,7 @@ extern GdkPixbuf *pix_tree_util;
|
||||
extern GdkPixbuf *pix_book;
|
||||
extern GdkPixbuf *pix_zoitechat;
|
||||
|
||||
extern GdkPixmap *pixmap_load_from_file (char *file);
|
||||
extern cairo_surface_t *pixmap_load_from_file (char *file);
|
||||
extern void pixmaps_init (void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -101,6 +101,7 @@ void
|
||||
open_rawlog (struct server *serv)
|
||||
{
|
||||
GtkWidget *bbox, *scrolledwindow, *vbox;
|
||||
XTextColor xtext_palette[XTEXT_COLS];
|
||||
char tbuf[256];
|
||||
|
||||
if (serv->gui->rawlog_window)
|
||||
@@ -120,7 +121,8 @@ open_rawlog (struct server *serv)
|
||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), scrolledwindow);
|
||||
|
||||
serv->gui->rawlog_textlist = gtk_xtext_new (colors, 0);
|
||||
palette_get_xtext_colors (xtext_palette, XTEXT_COLS);
|
||||
serv->gui->rawlog_textlist = gtk_xtext_new (xtext_palette, 0);
|
||||
gtk_container_add (GTK_CONTAINER (scrolledwindow), serv->gui->rawlog_textlist);
|
||||
gtk_xtext_set_font (GTK_XTEXT (serv->gui->rawlog_textlist), prefs.hex_text_font);
|
||||
GTK_XTEXT (serv->gui->rawlog_textlist)->ignore_hidden = 1;
|
||||
|
||||
@@ -58,7 +58,6 @@ static int last_selected_row = 0; /* sound row */
|
||||
static gboolean color_change;
|
||||
static struct zoitechatprefs setup_prefs;
|
||||
static GSList *color_selector_widgets;
|
||||
static GtkWidget *dark_mode_toggle_widget;
|
||||
static GtkWidget *cancel_button;
|
||||
static GtkWidget *font_dialog = NULL;
|
||||
void setup_apply_real (int new_pix, int do_ulist, int do_layout, int do_identd);
|
||||
@@ -348,22 +347,30 @@ static const setting tabs_settings[] =
|
||||
|
||||
static const setting color_settings[] =
|
||||
{
|
||||
{ST_TOGGLE, N_("Messages"), P_OFFINTNL(hex_text_stripcolor_msg), 0, 0, 0},
|
||||
{ST_TOGGLE, N_("Scrollback"), P_OFFINTNL(hex_text_stripcolor_replay), 0, 0, 0},
|
||||
{ST_TOGGLE, N_("Topic"), P_OFFINTNL(hex_text_stripcolor_topic), 0, 0, 0},
|
||||
{ST_TOGGLE, N_("Messages"), P_OFFINTNL(hex_text_stripcolor_msg), 0, 0, 0},
|
||||
{ST_TOGGLE, N_("Scrollback"), P_OFFINTNL(hex_text_stripcolor_replay), 0, 0, 0},
|
||||
{ST_TOGGLE, N_("Topic"), P_OFFINTNL(hex_text_stripcolor_topic), 0, 0, 0},
|
||||
|
||||
{ST_END, 0, 0, 0, 0, 0}
|
||||
{ST_END, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static const char *const dark_mode_modes[] =
|
||||
{
|
||||
N_("Auto (system)"),
|
||||
N_("Dark"),
|
||||
N_("Light"),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const setting dark_mode_setting =
|
||||
{
|
||||
ST_TOGGLE,
|
||||
N_("Enable dark mode"),
|
||||
P_OFFINTNL(hex_gui_dark_mode),
|
||||
N_("Applies ZoiteChat's built-in dark palette to the chat buffer, channel list, and user list.\n"
|
||||
"This includes message colors, selection colors, and interface highlights.\n"),
|
||||
0,
|
||||
0
|
||||
ST_MENU,
|
||||
N_("Dark mode:"),
|
||||
P_OFFINTNL(hex_gui_dark_mode),
|
||||
N_("Choose how ZoiteChat selects its color palette for the chat buffer, channel list, and user list.\n"
|
||||
"This includes message colors, selection colors, and interface highlights.\n"),
|
||||
dark_mode_modes,
|
||||
0
|
||||
};
|
||||
|
||||
static const char *const dccaccept[] =
|
||||
@@ -1440,12 +1447,65 @@ setup_color_selectors_set_sensitive (gboolean sensitive)
|
||||
}
|
||||
|
||||
static void
|
||||
setup_dark_mode_ui_toggle_cb (GtkToggleButton *but, gpointer userdata)
|
||||
setup_dark_mode_menu_cb (GtkWidget *cbox, const setting *set)
|
||||
{
|
||||
(void) but;
|
||||
(void) userdata;
|
||||
/* Keep color selectors usable even when dark mode is enabled. */
|
||||
setup_color_selectors_set_sensitive (TRUE);
|
||||
setup_menu_cb (cbox, set);
|
||||
/* Keep color selectors usable even when dark mode is enabled. */
|
||||
setup_color_selectors_set_sensitive (TRUE);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
setup_create_dark_mode_menu (GtkWidget *table, int row, const setting *set)
|
||||
{
|
||||
GtkWidget *wid, *cbox, *box;
|
||||
const char **text = (const char **)set->list;
|
||||
int i;
|
||||
|
||||
wid = gtk_label_new (_(set->label));
|
||||
gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
|
||||
gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
|
||||
GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
|
||||
|
||||
cbox = gtk_combo_box_text_new ();
|
||||
|
||||
for (i = 0; text[i]; i++)
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cbox), _(text[i]));
|
||||
|
||||
gtk_combo_box_set_active (GTK_COMBO_BOX (cbox),
|
||||
setup_get_int (&setup_prefs, set) - set->extra);
|
||||
g_signal_connect (G_OBJECT (cbox), "changed",
|
||||
G_CALLBACK (setup_dark_mode_menu_cb), (gpointer)set);
|
||||
|
||||
box = gtk_hbox_new (0, 0);
|
||||
gtk_box_pack_start (GTK_BOX (box), cbox, 0, 0, 0);
|
||||
gtk_table_attach (GTK_TABLE (table), box, 3, 4, row, row + 1,
|
||||
GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
|
||||
|
||||
return cbox;
|
||||
}
|
||||
|
||||
static void
|
||||
setup_color_button_apply (GtkWidget *button, const GdkColor *color)
|
||||
{
|
||||
GtkWidget *target = g_object_get_data (G_OBJECT (button), "zoitechat-color-box");
|
||||
GtkStateType states[] = {
|
||||
GTK_STATE_NORMAL,
|
||||
GTK_STATE_PRELIGHT,
|
||||
GTK_STATE_ACTIVE,
|
||||
GTK_STATE_SELECTED,
|
||||
GTK_STATE_INSENSITIVE
|
||||
};
|
||||
guint i;
|
||||
GtkWidget *apply_widget = GTK_IS_WIDGET (target) ? target : button;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (states); i++)
|
||||
gtk_widget_modify_bg (apply_widget, states[i], color);
|
||||
|
||||
if (apply_widget != button)
|
||||
for (i = 0; i < G_N_ELEMENTS (states); i++)
|
||||
gtk_widget_modify_bg (button, states[i], color);
|
||||
|
||||
gtk_widget_queue_draw (button);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1454,8 +1514,6 @@ setup_color_ok_cb (GtkWidget *button, GtkWidget *dialog)
|
||||
GtkColorSelectionDialog *cdialog = GTK_COLOR_SELECTION_DIALOG (dialog);
|
||||
GdkColor *col;
|
||||
GdkColor old_color;
|
||||
GtkStyle *style;
|
||||
|
||||
col = g_object_get_data (G_OBJECT (button), "c");
|
||||
old_color = *col;
|
||||
|
||||
@@ -1473,19 +1531,16 @@ setup_color_ok_cb (GtkWidget *button, GtkWidget *dialog)
|
||||
|
||||
gdk_colormap_alloc_color (gtk_widget_get_colormap (button), col, TRUE, TRUE);
|
||||
|
||||
style = gtk_style_new ();
|
||||
style->bg[0] = *col;
|
||||
gtk_widget_set_style (button, style);
|
||||
g_object_unref (style);
|
||||
setup_color_button_apply (button, col);
|
||||
|
||||
/* is this line correct?? */
|
||||
gdk_colormap_free_colors (gtk_widget_get_colormap (button), &old_color, 1);
|
||||
|
||||
/* Persist custom colors for the palette the user is editing. */
|
||||
if (setup_prefs.hex_gui_dark_mode)
|
||||
palette_dark_set_color ((int)(col - colors), col);
|
||||
else
|
||||
palette_user_set_color ((int)(col - colors), col);
|
||||
/* Persist custom colors for the palette the user is editing. */
|
||||
if (fe_dark_mode_is_enabled_for (setup_prefs.hex_gui_dark_mode))
|
||||
palette_dark_set_color ((int)(col - colors), col);
|
||||
else
|
||||
palette_user_set_color ((int)(col - colors), col);
|
||||
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
@@ -1528,26 +1583,41 @@ static void
|
||||
setup_create_color_button (GtkWidget *table, int num, int row, int col)
|
||||
{
|
||||
GtkWidget *but;
|
||||
GtkStyle *style;
|
||||
GtkWidget *label;
|
||||
GtkWidget *box;
|
||||
GtkWidget *alignment;
|
||||
char buf[64];
|
||||
|
||||
if (num > 31)
|
||||
strcpy (buf, "<span size=\"x-small\"> </span>");
|
||||
strcpy (buf, "<span size=\"x-small\">  </span>");
|
||||
else if (num < 10)
|
||||
sprintf (buf, "<span size=\"x-small\"> %d</span>", num);
|
||||
else
|
||||
/* 12345678901 23456789 01 23456789 */
|
||||
sprintf (buf, "<span size=\"x-small\">%d</span>", num);
|
||||
but = gtk_button_new_with_label (" ");
|
||||
gtk_label_set_markup (GTK_LABEL (gtk_bin_get_child (GTK_BIN (but))), buf);
|
||||
but = gtk_button_new ();
|
||||
label = gtk_label_new (" ");
|
||||
gtk_label_set_markup (GTK_LABEL (label), buf);
|
||||
box = gtk_event_box_new ();
|
||||
gtk_event_box_set_visible_window (GTK_EVENT_BOX (box), TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (box), label);
|
||||
gtk_container_add (GTK_CONTAINER (but), box);
|
||||
alignment = gtk_bin_get_child (GTK_BIN (but));
|
||||
if (GTK_IS_ALIGNMENT (alignment))
|
||||
{
|
||||
gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 1.0, 1.0);
|
||||
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 0, 0);
|
||||
}
|
||||
gtk_widget_show (label);
|
||||
gtk_widget_show (box);
|
||||
/* win32 build uses this to turn off themeing */
|
||||
g_object_set_data (G_OBJECT (but), "zoitechat-color", (gpointer)1);
|
||||
g_object_set_data (G_OBJECT (but), "zoitechat-color-box", box);
|
||||
gtk_table_attach (GTK_TABLE (table), but, col, col+1, row, row+1,
|
||||
GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
|
||||
GTK_SHRINK, GTK_SHRINK, 0, 0);
|
||||
g_signal_connect (G_OBJECT (but), "clicked",
|
||||
G_CALLBACK (setup_color_cb), GINT_TO_POINTER (num));
|
||||
style = gtk_style_new ();
|
||||
style->bg[GTK_STATE_NORMAL] = colors[num];
|
||||
gtk_widget_set_style (but, style);
|
||||
g_object_unref (style);
|
||||
setup_color_button_apply (but, &colors[num]);
|
||||
|
||||
/* Track all color selector widgets (used for dark mode UI behavior). */
|
||||
color_selector_widgets = g_slist_prepend (color_selector_widgets, but);
|
||||
@@ -1580,11 +1650,10 @@ setup_create_other_color (char *text, int num, int row, GtkWidget *tab)
|
||||
static GtkWidget *
|
||||
setup_create_color_page (void)
|
||||
{
|
||||
color_selector_widgets = NULL;
|
||||
dark_mode_toggle_widget = NULL;
|
||||
color_selector_widgets = NULL;
|
||||
|
||||
GtkWidget *tab, *box, *label;
|
||||
int i;
|
||||
GtkWidget *tab, *box, *label;
|
||||
int i;
|
||||
|
||||
box = gtk_vbox_new (FALSE, 0);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (box), 6);
|
||||
@@ -1625,15 +1694,13 @@ setup_create_color_page (void)
|
||||
|
||||
setup_create_other_color (_("New data:"), COL_NEW_DATA, 9, tab);
|
||||
setup_create_other_colorR (_("Marker line:"), COL_MARKER, 9, tab);
|
||||
setup_create_other_color (_("New message:"), COL_NEW_MSG, 10, tab);
|
||||
setup_create_other_colorR (_("Away user:"), COL_AWAY, 10, tab);
|
||||
setup_create_other_color (_("Highlight:"), COL_HILIGHT, 11, tab);
|
||||
setup_create_other_colorR (_("Spell checker:"), COL_SPELL, 11, tab);
|
||||
dark_mode_toggle_widget = setup_create_toggleL (tab, 13, &dark_mode_setting);
|
||||
g_signal_connect (G_OBJECT (dark_mode_toggle_widget), "toggled",
|
||||
G_CALLBACK (setup_dark_mode_ui_toggle_cb), NULL);
|
||||
setup_color_selectors_set_sensitive (TRUE);
|
||||
setup_create_header (tab, 15, N_("Color Stripping"));
|
||||
setup_create_other_color (_("New message:"), COL_NEW_MSG, 10, tab);
|
||||
setup_create_other_colorR (_("Away user:"), COL_AWAY, 10, tab);
|
||||
setup_create_other_color (_("Highlight:"), COL_HILIGHT, 11, tab);
|
||||
setup_create_other_colorR (_("Spell checker:"), COL_SPELL, 11, tab);
|
||||
setup_create_dark_mode_menu (tab, 13, &dark_mode_setting);
|
||||
setup_color_selectors_set_sensitive (TRUE);
|
||||
setup_create_header (tab, 15, N_("Color Stripping"));
|
||||
|
||||
/* label = gtk_label_new (_("Strip colors from:"));
|
||||
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
|
||||
@@ -1809,9 +1876,9 @@ setup_theme_apply_cb (GtkWidget *button, gpointer user_data)
|
||||
g_unlink (events_dest);
|
||||
}
|
||||
|
||||
palette_load ();
|
||||
palette_apply_dark_mode (prefs.hex_gui_dark_mode);
|
||||
color_change = TRUE;
|
||||
palette_load ();
|
||||
palette_apply_dark_mode (fe_dark_mode_is_enabled ());
|
||||
color_change = TRUE;
|
||||
setup_apply_real (0, TRUE, FALSE, FALSE);
|
||||
|
||||
setup_theme_show_message (GTK_MESSAGE_INFO, _("Theme applied. Some changes may require a restart to take full effect."));
|
||||
@@ -2372,15 +2439,15 @@ setup_apply_to_sess (session_gui *gui)
|
||||
chanview_apply_theme ((chanview *) gui->chanview);
|
||||
|
||||
if (prefs.hex_gui_ulist_style)
|
||||
gtk_widget_set_style (gui->user_tree, input_style);
|
||||
gtk_widget_modify_font (gui->user_tree, input_style->font_desc);
|
||||
|
||||
if (prefs.hex_gui_ulist_style || prefs.hex_gui_dark_mode)
|
||||
{
|
||||
gtk_widget_modify_base (gui->user_tree, GTK_STATE_NORMAL, &colors[COL_BG]);
|
||||
if (prefs.hex_gui_dark_mode)
|
||||
gtk_widget_modify_text (gui->user_tree, GTK_STATE_NORMAL, &colors[COL_FG]);
|
||||
else
|
||||
gtk_widget_modify_text (gui->user_tree, GTK_STATE_NORMAL, NULL);
|
||||
if (prefs.hex_gui_ulist_style || fe_dark_mode_is_enabled ())
|
||||
{
|
||||
gtk_widget_modify_base (gui->user_tree, GTK_STATE_NORMAL, &colors[COL_BG]);
|
||||
if (fe_dark_mode_is_enabled ())
|
||||
gtk_widget_modify_text (gui->user_tree, GTK_STATE_NORMAL, &colors[COL_FG]);
|
||||
else
|
||||
gtk_widget_modify_text (gui->user_tree, GTK_STATE_NORMAL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2449,7 +2516,7 @@ setup_apply_real (int new_pix, int do_ulist, int do_layout, int do_identd)
|
||||
if (new_pix)
|
||||
{
|
||||
if (channelwin_pix)
|
||||
g_object_unref (channelwin_pix);
|
||||
cairo_surface_destroy (channelwin_pix);
|
||||
channelwin_pix = pixmap_load_from_file (prefs.hex_text_background);
|
||||
}
|
||||
|
||||
@@ -2579,14 +2646,17 @@ setup_apply (struct zoitechatprefs *pr)
|
||||
* "Dark mode" applies ZoiteChat's built-in dark palette to the chat views.
|
||||
*
|
||||
* IMPORTANT: don't short-circuit this call.
|
||||
* We MUST run palette_apply_dark_mode() when the toggle changes, otherwise
|
||||
* the preference flips but the palette stays the same (aka: "nothing happens").
|
||||
*/
|
||||
{
|
||||
gboolean pal_changed = palette_apply_dark_mode (prefs.hex_gui_dark_mode);
|
||||
if (prefs.hex_gui_dark_mode != old_dark_mode || pal_changed)
|
||||
color_change = TRUE;
|
||||
}
|
||||
* We MUST run palette_apply_dark_mode() when the setting changes, otherwise
|
||||
* 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));
|
||||
if (prefs.hex_gui_dark_mode != old_dark_mode || pal_changed)
|
||||
color_change = TRUE;
|
||||
}
|
||||
|
||||
if (prefs.hex_gui_dark_mode == ZOITECHAT_DARK_MODE_AUTO)
|
||||
fe_set_auto_dark_mode_state (fe_dark_mode_is_enabled_for (ZOITECHAT_DARK_MODE_AUTO));
|
||||
|
||||
#ifdef WIN32
|
||||
/* merge hex_font_main and hex_font_alternative into hex_font_normal */
|
||||
@@ -2683,12 +2753,11 @@ setup_close_cb (GtkWidget *win, GtkWidget **swin)
|
||||
{
|
||||
*swin = NULL;
|
||||
|
||||
if (color_selector_widgets)
|
||||
{
|
||||
g_slist_free (color_selector_widgets);
|
||||
color_selector_widgets = NULL;
|
||||
dark_mode_toggle_widget = NULL;
|
||||
}
|
||||
if (color_selector_widgets)
|
||||
{
|
||||
g_slist_free (color_selector_widgets);
|
||||
color_selector_widgets = NULL;
|
||||
}
|
||||
|
||||
if (font_dialog)
|
||||
{
|
||||
|
||||
@@ -438,6 +438,7 @@ void
|
||||
pevent_dialog_show ()
|
||||
{
|
||||
GtkWidget *vbox, *hbox, *wid, *pane;
|
||||
XTextColor xtext_palette[XTEXT_COLS];
|
||||
|
||||
if (pevent_dialog)
|
||||
{
|
||||
@@ -462,7 +463,8 @@ pevent_dialog_show ()
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (wid), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), wid, FALSE, TRUE, 0);
|
||||
|
||||
pevent_dialog_twid = gtk_xtext_new (colors, 0);
|
||||
palette_get_xtext_colors (xtext_palette, XTEXT_COLS);
|
||||
pevent_dialog_twid = gtk_xtext_new (xtext_palette, 0);
|
||||
gtk_widget_set_sensitive (pevent_dialog_twid, FALSE);
|
||||
gtk_widget_set_size_request (pevent_dialog_twid, -1, 75);
|
||||
gtk_container_add (GTK_CONTAINER (wid), pevent_dialog_twid);
|
||||
|
||||
20
src/fe-gtk/xtext-color.h
Normal file
20
src/fe-gtk/xtext-color.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/* ZoiteChat
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef HEXCHAT_XTEXT_COLOR_H
|
||||
#define HEXCHAT_XTEXT_COLOR_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double red;
|
||||
double green;
|
||||
double blue;
|
||||
double alpha;
|
||||
} XTextColor;
|
||||
|
||||
#endif
|
||||
@@ -54,13 +54,16 @@
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkcairo.h>
|
||||
#include <gdk/gdkwin32.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <gdk/gdkcairo.h>
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
#include <gdk/gdkx.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <pango/pangocairo.h>
|
||||
|
||||
/* is delimiter */
|
||||
#define is_del(c) \
|
||||
@@ -147,7 +150,109 @@ 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);
|
||||
|
||||
#define xtext_draw_bg(xt,x,y,w,h) gdk_draw_rectangle(xt->draw_buf, xt->bgc, 1, x, y, w, h);
|
||||
static inline void
|
||||
xtext_set_source_color (cairo_t *cr, const XTextColor *color, gdouble alpha)
|
||||
{
|
||||
cairo_set_source_rgba (cr, color->red, color->green,
|
||||
color->blue, color->alpha * alpha);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
xtext_surface_from_window (GdkWindow *window)
|
||||
{
|
||||
cairo_surface_t *surface = NULL;
|
||||
int width;
|
||||
int height;
|
||||
cairo_t *cr;
|
||||
|
||||
if (!window)
|
||||
return NULL;
|
||||
|
||||
width = gdk_window_get_width (window);
|
||||
height = gdk_window_get_height (window);
|
||||
if (width <= 0 || height <= 0)
|
||||
return NULL;
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
|
||||
{
|
||||
cairo_surface_destroy (surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cr = cairo_create (surface);
|
||||
gdk_cairo_set_source_window (cr, window, 0.0, 0.0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static cairo_t *
|
||||
xtext_create_context (GtkXText *xtext)
|
||||
{
|
||||
if (xtext->draw_surface)
|
||||
return cairo_create (xtext->draw_surface);
|
||||
|
||||
return gdk_cairo_create (xtext->draw_window);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xtext_draw_rectangle (GtkXText *xtext, cairo_t *cr, const XTextColor *color, int x, int y, int width, int height)
|
||||
{
|
||||
cairo_save (cr);
|
||||
|
||||
xtext_set_source_color (cr, color, 1.0);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_rectangle (cr, (double)x, (double)y, (double)width, (double)height);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xtext_draw_line (GtkXText *xtext, cairo_t *cr, const XTextColor *color, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
cairo_save (cr);
|
||||
|
||||
/* Disable antialiasing for crispy 1-pixel lines */
|
||||
cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
|
||||
xtext_set_source_color (cr, color, 1.0);
|
||||
cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
cairo_move_to (cr, x1, y1);
|
||||
cairo_line_to (cr, x2, y2);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xtext_draw_bg_offset (GtkXText *xtext, int x, int y, int width, int height, int tile_x, int tile_y)
|
||||
{
|
||||
cairo_t *cr = xtext_create_context (xtext);
|
||||
|
||||
if (xtext->background_surface)
|
||||
{
|
||||
cairo_set_source_surface (cr, xtext->background_surface, tile_x, tile_y);
|
||||
cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
|
||||
cairo_rectangle (cr, (double)x, (double)y, (double)width, (double)height);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
xtext_draw_rectangle (xtext, cr, &xtext->bgc, x, y, width, height);
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xtext_draw_bg (GtkXText *xtext, int x, int y, int width, int height)
|
||||
{
|
||||
xtext_draw_bg_offset (xtext, x, y, width, height, xtext->ts_x, xtext->ts_y);
|
||||
}
|
||||
|
||||
/* ======================================= */
|
||||
/* ============ PANGO BACKEND ============ */
|
||||
@@ -354,77 +459,53 @@ backend_get_text_width_slp (GtkXText *xtext, guchar *str, GSList *slp)
|
||||
return width;
|
||||
}
|
||||
|
||||
/* simplified version of gdk_draw_layout_line_with_colors() */
|
||||
|
||||
static void
|
||||
xtext_draw_layout_line (GdkDrawable *drawable,
|
||||
GdkGC *gc,
|
||||
gint x,
|
||||
gint y,
|
||||
PangoLayoutLine *line)
|
||||
{
|
||||
GSList *tmp_list = line->runs;
|
||||
PangoRectangle logical_rect;
|
||||
gint x_off = 0;
|
||||
|
||||
while (tmp_list)
|
||||
{
|
||||
PangoLayoutRun *run = tmp_list->data;
|
||||
|
||||
pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
|
||||
NULL, &logical_rect);
|
||||
|
||||
gdk_draw_glyphs (drawable, gc, run->item->analysis.font,
|
||||
x + x_off / PANGO_SCALE, y, run->glyphs);
|
||||
|
||||
x_off += logical_rect.width;
|
||||
tmp_list = tmp_list->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
backend_draw_text_emph (GtkXText *xtext, int dofill, GdkGC *gc, int x, int y,
|
||||
backend_draw_text_emph (GtkXText *xtext, gboolean dofill, int x, int y,
|
||||
char *str, int len, int str_width, int emphasis)
|
||||
{
|
||||
GdkGCValues val;
|
||||
GdkColor col;
|
||||
cairo_t *cr;
|
||||
PangoLayoutLine *line;
|
||||
|
||||
cr = xtext_create_context (xtext);
|
||||
|
||||
pango_layout_set_attributes (xtext->layout, attr_lists[emphasis]);
|
||||
pango_layout_set_text (xtext->layout, str, len);
|
||||
|
||||
if (dofill)
|
||||
{
|
||||
gdk_gc_get_values (gc, &val);
|
||||
col.pixel = val.background.pixel;
|
||||
gdk_gc_set_foreground (gc, &col);
|
||||
gdk_draw_rectangle (xtext->draw_buf, gc, 1, x, y -
|
||||
xtext_draw_rectangle (xtext, cr, &xtext->bgc, x, y -
|
||||
xtext->font->ascent, str_width, xtext->fontsize);
|
||||
col.pixel = val.foreground.pixel;
|
||||
gdk_gc_set_foreground (gc, &col);
|
||||
}
|
||||
|
||||
line = pango_layout_get_lines (xtext->layout)->data;
|
||||
xtext_set_source_color (cr, &xtext->fgc, 1.0);
|
||||
line = pango_layout_get_line_readonly (xtext->layout, 0);
|
||||
|
||||
xtext_draw_layout_line (xtext->draw_buf, gc, x, y, line);
|
||||
cairo_save (cr);
|
||||
cairo_move_to (cr, x, y);
|
||||
pango_cairo_show_layout_line (cr, line);
|
||||
cairo_restore (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
xtext_set_fg (GtkXText *xtext, GdkGC *gc, int index)
|
||||
xtext_set_fg (GtkXText *xtext, int index)
|
||||
{
|
||||
gdk_gc_set_foreground (gc, &xtext->palette[index]);
|
||||
xtext->fgc = xtext->palette[index];
|
||||
}
|
||||
|
||||
static void
|
||||
xtext_set_bg (GtkXText *xtext, GdkGC *gc, int index)
|
||||
xtext_set_bg (GtkXText *xtext, int index)
|
||||
{
|
||||
gdk_gc_set_background (gc, &xtext->palette[index]);
|
||||
xtext->bgc = xtext->palette[index];
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_xtext_init (GtkXText * xtext)
|
||||
{
|
||||
xtext->pixmap = NULL;
|
||||
xtext->background_surface = NULL;
|
||||
xtext->draw_window = NULL;
|
||||
xtext->draw_surface = NULL;
|
||||
xtext->io_tag = 0;
|
||||
xtext->add_io_tag = 0;
|
||||
xtext->scroll_tag = 0;
|
||||
@@ -545,7 +626,7 @@ gtk_xtext_adjustment_changed (GtkAdjustment * adj, GtkXText * xtext)
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_xtext_new (GdkColor palette[], int separator)
|
||||
gtk_xtext_new (const XTextColor *palette, int separator)
|
||||
{
|
||||
GtkXText *xtext;
|
||||
|
||||
@@ -584,10 +665,10 @@ gtk_xtext_destroy (GtkObject * object)
|
||||
xtext->io_tag = 0;
|
||||
}
|
||||
|
||||
if (xtext->pixmap)
|
||||
if (xtext->background_surface)
|
||||
{
|
||||
g_object_unref (xtext->pixmap);
|
||||
xtext->pixmap = NULL;
|
||||
cairo_surface_destroy (xtext->background_surface);
|
||||
xtext->background_surface = NULL;
|
||||
}
|
||||
|
||||
if (xtext->font)
|
||||
@@ -605,41 +686,6 @@ gtk_xtext_destroy (GtkObject * object)
|
||||
xtext->adj = NULL;
|
||||
}
|
||||
|
||||
if (xtext->bgc)
|
||||
{
|
||||
g_object_unref (xtext->bgc);
|
||||
xtext->bgc = NULL;
|
||||
}
|
||||
|
||||
if (xtext->fgc)
|
||||
{
|
||||
g_object_unref (xtext->fgc);
|
||||
xtext->fgc = NULL;
|
||||
}
|
||||
|
||||
if (xtext->light_gc)
|
||||
{
|
||||
g_object_unref (xtext->light_gc);
|
||||
xtext->light_gc = NULL;
|
||||
}
|
||||
|
||||
if (xtext->dark_gc)
|
||||
{
|
||||
g_object_unref (xtext->dark_gc);
|
||||
xtext->dark_gc = NULL;
|
||||
}
|
||||
|
||||
if (xtext->thin_gc)
|
||||
{
|
||||
g_object_unref (xtext->thin_gc);
|
||||
xtext->thin_gc = NULL;
|
||||
}
|
||||
|
||||
if (xtext->marker_gc)
|
||||
{
|
||||
g_object_unref (xtext->marker_gc);
|
||||
xtext->marker_gc = NULL;
|
||||
}
|
||||
|
||||
if (xtext->hand_cursor)
|
||||
{
|
||||
@@ -680,9 +726,6 @@ gtk_xtext_realize (GtkWidget * widget)
|
||||
{
|
||||
GtkXText *xtext;
|
||||
GdkWindowAttr attributes;
|
||||
GdkGCValues val;
|
||||
GdkColor col;
|
||||
GdkColormap *cmap;
|
||||
|
||||
gtk_widget_set_realized (widget, TRUE);
|
||||
xtext = GTK_XTEXT (widget);
|
||||
@@ -697,8 +740,7 @@ gtk_xtext_realize (GtkWidget * widget)
|
||||
GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
|
||||
| GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK;
|
||||
|
||||
cmap = gtk_widget_get_colormap (widget);
|
||||
attributes.colormap = cmap;
|
||||
attributes.colormap = gtk_widget_get_colormap (widget);
|
||||
attributes.visual = gtk_widget_get_visual (widget);
|
||||
|
||||
widget->window = gdk_window_new (widget->parent->window, &attributes,
|
||||
@@ -709,60 +751,42 @@ gtk_xtext_realize (GtkWidget * widget)
|
||||
|
||||
xtext->depth = gdk_window_get_visual (widget->window)->depth;
|
||||
|
||||
val.subwindow_mode = GDK_INCLUDE_INFERIORS;
|
||||
val.graphics_exposures = 0;
|
||||
|
||||
xtext->bgc = gdk_gc_new_with_values (widget->window, &val,
|
||||
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
|
||||
xtext->fgc = gdk_gc_new_with_values (widget->window, &val,
|
||||
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
|
||||
xtext->light_gc = gdk_gc_new_with_values (widget->window, &val,
|
||||
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
|
||||
xtext->dark_gc = gdk_gc_new_with_values (widget->window, &val,
|
||||
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
|
||||
xtext->thin_gc = gdk_gc_new_with_values (widget->window, &val,
|
||||
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
|
||||
xtext->marker_gc = gdk_gc_new_with_values (widget->window, &val,
|
||||
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
|
||||
|
||||
/* for the separator bar (light) */
|
||||
col.red = 0xffff; col.green = 0xffff; col.blue = 0xffff;
|
||||
gdk_colormap_alloc_color (cmap, &col, FALSE, TRUE);
|
||||
gdk_gc_set_foreground (xtext->light_gc, &col);
|
||||
xtext->light_gc.red = 1.0;
|
||||
xtext->light_gc.green = 1.0;
|
||||
xtext->light_gc.blue = 1.0;
|
||||
xtext->light_gc.alpha = 1.0;
|
||||
|
||||
/* for the separator bar (dark) */
|
||||
col.red = 0x1111; col.green = 0x1111; col.blue = 0x1111;
|
||||
gdk_colormap_alloc_color (cmap, &col, FALSE, TRUE);
|
||||
gdk_gc_set_foreground (xtext->dark_gc, &col);
|
||||
xtext->dark_gc.red = 0x1111 / 65535.0;
|
||||
xtext->dark_gc.green = 0x1111 / 65535.0;
|
||||
xtext->dark_gc.blue = 0x1111 / 65535.0;
|
||||
xtext->dark_gc.alpha = 1.0;
|
||||
|
||||
/* for the separator bar (thinline) */
|
||||
col.red = 0x8e38; col.green = 0x8e38; col.blue = 0x9f38;
|
||||
gdk_colormap_alloc_color (cmap, &col, FALSE, TRUE);
|
||||
gdk_gc_set_foreground (xtext->thin_gc, &col);
|
||||
xtext->thin_gc.red = 0x8e38 / 65535.0;
|
||||
xtext->thin_gc.green = 0x8e38 / 65535.0;
|
||||
xtext->thin_gc.blue = 0x9f38 / 65535.0;
|
||||
xtext->thin_gc.alpha = 1.0;
|
||||
|
||||
/* for the marker bar (marker) */
|
||||
gdk_gc_set_foreground (xtext->marker_gc, &xtext->palette[XTEXT_MARKER]);
|
||||
xtext->marker_gc = xtext->palette[XTEXT_MARKER];
|
||||
|
||||
xtext_set_fg (xtext, xtext->fgc, XTEXT_FG);
|
||||
xtext_set_bg (xtext, xtext->fgc, XTEXT_BG);
|
||||
xtext_set_fg (xtext, xtext->bgc, XTEXT_BG);
|
||||
xtext_set_fg (xtext, XTEXT_FG);
|
||||
xtext_set_bg (xtext, XTEXT_BG);
|
||||
|
||||
/* draw directly to window */
|
||||
xtext->draw_buf = widget->window;
|
||||
xtext->draw_window = widget->window;
|
||||
|
||||
if (xtext->pixmap)
|
||||
if (xtext->background_surface)
|
||||
{
|
||||
gdk_gc_set_tile (xtext->bgc, xtext->pixmap);
|
||||
gdk_gc_set_ts_origin (xtext->bgc, 0, 0);
|
||||
xtext->ts_x = xtext->ts_y = 0;
|
||||
gdk_gc_set_fill (xtext->bgc, GDK_TILED);
|
||||
}
|
||||
|
||||
xtext->hand_cursor = gdk_cursor_new_for_display (gdk_window_get_display (widget->window), GDK_HAND1);
|
||||
xtext->resize_cursor = gdk_cursor_new_for_display (gdk_window_get_display (widget->window), GDK_LEFT_SIDE);
|
||||
|
||||
gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
|
||||
widget->style = gtk_style_attach (widget->style, widget->window);
|
||||
|
||||
backend_init (xtext);
|
||||
}
|
||||
@@ -971,7 +995,7 @@ static void
|
||||
gtk_xtext_draw_sep (GtkXText * xtext, int y)
|
||||
{
|
||||
int x, height;
|
||||
GdkGC *light, *dark;
|
||||
cairo_t *cr;
|
||||
|
||||
if (y == -1)
|
||||
{
|
||||
@@ -985,31 +1009,37 @@ gtk_xtext_draw_sep (GtkXText * xtext, int y)
|
||||
/* draw the separator line */
|
||||
if (xtext->separator && xtext->buffer->indent)
|
||||
{
|
||||
light = xtext->light_gc;
|
||||
dark = xtext->dark_gc;
|
||||
const XTextColor *light = &xtext->light_gc;
|
||||
const XTextColor *dark = &xtext->dark_gc;
|
||||
cr = xtext_create_context (xtext);
|
||||
|
||||
x = xtext->buffer->indent - ((xtext->space_width + 1) / 2);
|
||||
if (x < 1)
|
||||
{
|
||||
cairo_destroy (cr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (xtext->thinline)
|
||||
{
|
||||
if (xtext->moving_separator)
|
||||
gdk_draw_line (xtext->draw_buf, light, x, y, x, y + height);
|
||||
xtext_draw_line (xtext, cr, light, x, y, x, y + height);
|
||||
else
|
||||
gdk_draw_line (xtext->draw_buf, xtext->thin_gc, x, y, x, y + height);
|
||||
xtext_draw_line (xtext, cr, &xtext->thin_gc, x, y, x, y + height);
|
||||
} else
|
||||
{
|
||||
if (xtext->moving_separator)
|
||||
{
|
||||
gdk_draw_line (xtext->draw_buf, light, x - 1, y, x - 1, y + height);
|
||||
gdk_draw_line (xtext->draw_buf, dark, x, y, x, y + height);
|
||||
xtext_draw_line (xtext, cr, light, x - 1, y, x - 1, y + height);
|
||||
xtext_draw_line (xtext, cr, dark, x, y, x, y + height);
|
||||
} else
|
||||
{
|
||||
gdk_draw_line (xtext->draw_buf, dark, x - 1, y, x - 1, y + height);
|
||||
gdk_draw_line (xtext->draw_buf, light, x, y, x, y + height);
|
||||
xtext_draw_line (xtext, cr, dark, x - 1, y, x - 1, y + height);
|
||||
xtext_draw_line (xtext, cr, light, x, y, x, y + height);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1017,6 +1047,7 @@ static void
|
||||
gtk_xtext_draw_marker (GtkXText * xtext, textentry * ent, int y)
|
||||
{
|
||||
int x, width, render_y;
|
||||
cairo_t *cr;
|
||||
|
||||
if (!xtext->marker) return;
|
||||
|
||||
@@ -1033,7 +1064,9 @@ gtk_xtext_draw_marker (GtkXText * xtext, textentry * ent, int y)
|
||||
x = 0;
|
||||
width = GTK_WIDGET (xtext)->allocation.width;
|
||||
|
||||
gdk_draw_line (xtext->draw_buf, xtext->marker_gc, x, render_y, x + width, render_y);
|
||||
cr = xtext_create_context (xtext);
|
||||
xtext_draw_line (xtext, cr, &xtext->marker_gc, x, render_y, x + width, render_y);
|
||||
cairo_destroy (cr);
|
||||
|
||||
if (gtk_window_has_toplevel_focus (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (xtext)))))
|
||||
{
|
||||
@@ -2551,11 +2584,13 @@ gtk_xtext_text_width (GtkXText *xtext, unsigned char *text, int len)
|
||||
|
||||
static int
|
||||
gtk_xtext_render_flush (GtkXText * xtext, int x, int y, unsigned char *str,
|
||||
int len, GdkGC *gc, int *emphasis)
|
||||
int len, int *emphasis)
|
||||
{
|
||||
int str_width, dofill;
|
||||
GdkDrawable *pix = NULL;
|
||||
cairo_surface_t *surface = NULL;
|
||||
int dest_x = 0, dest_y = 0;
|
||||
int tile_x = xtext->ts_x;
|
||||
int tile_y = xtext->ts_y;
|
||||
|
||||
if (xtext->dont_render || len < 1 || xtext->hidden)
|
||||
return 0;
|
||||
@@ -2579,39 +2614,40 @@ gtk_xtext_render_flush (GtkXText * xtext, int x, int y, unsigned char *str,
|
||||
goto dounder;
|
||||
}
|
||||
|
||||
pix = gdk_pixmap_new (xtext->draw_buf, str_width, xtext->fontsize, xtext->depth);
|
||||
if (pix)
|
||||
surface = gdk_window_create_similar_surface (GTK_WIDGET (xtext)->window,
|
||||
CAIRO_CONTENT_COLOR_ALPHA, str_width, xtext->fontsize);
|
||||
if (surface)
|
||||
{
|
||||
dest_x = x;
|
||||
dest_y = y - xtext->font->ascent;
|
||||
|
||||
gdk_gc_set_ts_origin (xtext->bgc, xtext->ts_x - x, xtext->ts_y - dest_y);
|
||||
tile_x = xtext->ts_x - x;
|
||||
tile_y = xtext->ts_y - dest_y;
|
||||
|
||||
x = 0;
|
||||
y = xtext->font->ascent;
|
||||
xtext->draw_buf = pix;
|
||||
xtext->draw_surface = surface;
|
||||
}
|
||||
|
||||
dofill = TRUE;
|
||||
|
||||
/* backcolor is always handled by XDrawImageString */
|
||||
if (!xtext->backcolor && xtext->pixmap)
|
||||
if (!xtext->backcolor && xtext->background_surface)
|
||||
{
|
||||
/* draw the background pixmap behind the text - CAUSES FLICKER HERE!! */
|
||||
xtext_draw_bg (xtext, x, y - xtext->font->ascent, str_width,
|
||||
xtext->fontsize);
|
||||
/* draw the background surface behind the text - CAUSES FLICKER HERE!! */
|
||||
xtext_draw_bg_offset (xtext, x, y - xtext->font->ascent, str_width,
|
||||
xtext->fontsize, tile_x, tile_y);
|
||||
dofill = FALSE; /* already drawn the background */
|
||||
}
|
||||
|
||||
backend_draw_text_emph (xtext, dofill, gc, x, y, str, len, str_width, *emphasis);
|
||||
backend_draw_text_emph (xtext, dofill, x, y, str, len, str_width, *emphasis);
|
||||
|
||||
if (pix)
|
||||
if (surface)
|
||||
{
|
||||
GdkRectangle clip;
|
||||
GdkRectangle dest;
|
||||
cairo_t *cr;
|
||||
|
||||
gdk_gc_set_ts_origin (xtext->bgc, xtext->ts_x, xtext->ts_y);
|
||||
xtext->draw_buf = GTK_WIDGET (xtext)->window;
|
||||
xtext->draw_surface = NULL;
|
||||
clip.x = xtext->clip_x;
|
||||
clip.y = xtext->clip_y;
|
||||
clip.width = xtext->clip_x2 - xtext->clip_x;
|
||||
@@ -2624,24 +2660,36 @@ gtk_xtext_render_flush (GtkXText * xtext, int x, int y, unsigned char *str,
|
||||
|
||||
if (gdk_rectangle_intersect (&clip, &dest, &dest))
|
||||
/* dump the DB to window, but only within the clip_x/x2/y/y2 */
|
||||
gdk_draw_drawable (xtext->draw_buf, xtext->bgc, pix,
|
||||
dest.x - dest_x, dest.y - dest_y,
|
||||
dest.x, dest.y, dest.width, dest.height);
|
||||
g_object_unref (pix);
|
||||
{
|
||||
cr = xtext_create_context (xtext);
|
||||
cairo_save (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_source_surface (cr, surface, dest_x, dest_y);
|
||||
cairo_rectangle (cr, dest.x, dest.y, dest.width, dest.height);
|
||||
cairo_fill (cr);
|
||||
cairo_restore (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
if (xtext->strikethrough)
|
||||
{
|
||||
cairo_t *cr;
|
||||
/* pango_attr_strikethrough_new does not render in the custom widget so we need to reinvent the wheel */
|
||||
y = dest_y + (xtext->fontsize / 2);
|
||||
gdk_draw_line (xtext->draw_buf, gc, dest_x, y, dest_x + str_width - 1, y);
|
||||
cr = xtext_create_context (xtext);
|
||||
xtext_draw_line (xtext, cr, &xtext->fgc, dest_x, y, dest_x + str_width - 1, y);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
if (xtext->underline)
|
||||
{
|
||||
dounder:
|
||||
{
|
||||
cairo_t *cr;
|
||||
|
||||
if (pix)
|
||||
if (surface)
|
||||
y = dest_y + xtext->font->ascent + 1;
|
||||
else
|
||||
{
|
||||
@@ -2649,7 +2697,10 @@ dounder:
|
||||
dest_x = x;
|
||||
}
|
||||
/* draw directly to window, it's out of the range of our DB */
|
||||
gdk_draw_line (xtext->draw_buf, gc, dest_x, y, dest_x + str_width - 1, y);
|
||||
cr = xtext_create_context (xtext);
|
||||
xtext_draw_line (xtext, cr, &xtext->fgc, dest_x, y, dest_x + str_width - 1, y);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
}
|
||||
|
||||
return str_width;
|
||||
@@ -2668,9 +2719,9 @@ gtk_xtext_reset (GtkXText * xtext, int mark, int attribs)
|
||||
{
|
||||
xtext->backcolor = FALSE;
|
||||
if (xtext->col_fore != XTEXT_FG)
|
||||
xtext_set_fg (xtext, xtext->fgc, XTEXT_FG);
|
||||
xtext_set_fg (xtext, XTEXT_FG);
|
||||
if (xtext->col_back != XTEXT_BG)
|
||||
xtext_set_bg (xtext, xtext->fgc, XTEXT_BG);
|
||||
xtext_set_bg (xtext, XTEXT_BG);
|
||||
}
|
||||
xtext->col_fore = XTEXT_FG;
|
||||
xtext->col_back = XTEXT_BG;
|
||||
@@ -2738,14 +2789,13 @@ gtk_xtext_search_offset (xtext_buffer *buf, textentry *ent, unsigned int off)
|
||||
|
||||
/* render a single line, which WONT wrap, and parse mIRC colors */
|
||||
|
||||
#define RENDER_FLUSH x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, emphasis)
|
||||
#define RENDER_FLUSH x += gtk_xtext_render_flush (xtext, x, y, pstr, j, emphasis)
|
||||
|
||||
static int
|
||||
gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
|
||||
unsigned char *str, int len, int win_width, int indent,
|
||||
int line, int left_only, int *x_size_ret, int *emphasis)
|
||||
{
|
||||
GdkGC *gc;
|
||||
int i = 0, x = indent, j = 0;
|
||||
unsigned char *pstr = str;
|
||||
int col_num, tmp;
|
||||
@@ -2760,13 +2810,11 @@ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
|
||||
|
||||
offset = str - ent->str;
|
||||
|
||||
gc = xtext->fgc; /* our foreground GC */
|
||||
|
||||
if (ent->mark_start != -1 &&
|
||||
ent->mark_start <= i + offset && ent->mark_end > i + offset)
|
||||
{
|
||||
xtext_set_bg (xtext, gc, XTEXT_MARK_BG);
|
||||
xtext_set_fg (xtext, gc, XTEXT_MARK_FG);
|
||||
xtext_set_bg (xtext, XTEXT_MARK_BG);
|
||||
xtext_set_fg (xtext, XTEXT_MARK_FG);
|
||||
xtext->backcolor = TRUE;
|
||||
mark = TRUE;
|
||||
}
|
||||
@@ -2840,7 +2888,7 @@ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
|
||||
col_num = col_num % XTEXT_MIRC_COLS;
|
||||
xtext->col_fore = col_num;
|
||||
if (!mark)
|
||||
xtext_set_fg (xtext, gc, col_num);
|
||||
xtext_set_fg (xtext, col_num);
|
||||
}
|
||||
} else
|
||||
{
|
||||
@@ -2870,7 +2918,7 @@ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
|
||||
else
|
||||
xtext->backcolor = TRUE;
|
||||
if (!mark)
|
||||
xtext_set_bg (xtext, gc, col_num);
|
||||
xtext_set_bg (xtext, col_num);
|
||||
xtext->col_back = col_num;
|
||||
} else
|
||||
{
|
||||
@@ -2880,7 +2928,7 @@ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
|
||||
if (col_num > XTEXT_MAX_COLOR)
|
||||
col_num = col_num % XTEXT_MIRC_COLS;
|
||||
if (!mark)
|
||||
xtext_set_fg (xtext, gc, col_num);
|
||||
xtext_set_fg (xtext, col_num);
|
||||
xtext->col_fore = col_num;
|
||||
}
|
||||
xtext->parsing_backcolor = FALSE;
|
||||
@@ -2904,14 +2952,14 @@ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
|
||||
{
|
||||
if (k & GTK_MATCH_CUR)
|
||||
{
|
||||
xtext_set_bg (xtext, gc, XTEXT_MARK_BG);
|
||||
xtext_set_fg (xtext, gc, XTEXT_MARK_FG);
|
||||
xtext_set_bg (xtext, XTEXT_MARK_BG);
|
||||
xtext_set_fg (xtext, XTEXT_MARK_FG);
|
||||
xtext->backcolor = TRUE;
|
||||
srch_mark = TRUE;
|
||||
} else
|
||||
{
|
||||
xtext_set_bg (xtext, gc, xtext->col_back);
|
||||
xtext_set_fg (xtext, gc, xtext->col_fore);
|
||||
xtext_set_bg (xtext, xtext->col_back);
|
||||
xtext_set_fg (xtext, xtext->col_fore);
|
||||
xtext->backcolor = (xtext->col_back != XTEXT_BG)? TRUE: FALSE;
|
||||
srch_mark = FALSE;
|
||||
}
|
||||
@@ -2921,15 +2969,15 @@ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
|
||||
xtext->underline = (k & GTK_MATCH_CUR)? TRUE: FALSE;
|
||||
if (k & (GTK_MATCH_START | GTK_MATCH_MID))
|
||||
{
|
||||
xtext_set_bg (xtext, gc, XTEXT_MARK_BG);
|
||||
xtext_set_fg (xtext, gc, XTEXT_MARK_FG);
|
||||
xtext_set_bg (xtext, XTEXT_MARK_BG);
|
||||
xtext_set_fg (xtext, XTEXT_MARK_FG);
|
||||
xtext->backcolor = TRUE;
|
||||
srch_mark = TRUE;
|
||||
}
|
||||
if (k & GTK_MATCH_END)
|
||||
{
|
||||
xtext_set_bg (xtext, gc, xtext->col_back);
|
||||
xtext_set_fg (xtext, gc, xtext->col_fore);
|
||||
xtext_set_bg (xtext, xtext->col_back);
|
||||
xtext_set_fg (xtext, xtext->col_fore);
|
||||
xtext->backcolor = (xtext->col_back != XTEXT_BG)? TRUE: FALSE;
|
||||
srch_mark = FALSE;
|
||||
xtext->underline = FALSE;
|
||||
@@ -2952,8 +3000,8 @@ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
|
||||
xtext->col_back = tmp;
|
||||
if (!mark)
|
||||
{
|
||||
xtext_set_fg (xtext, gc, xtext->col_fore);
|
||||
xtext_set_bg (xtext, gc, xtext->col_back);
|
||||
xtext_set_fg (xtext, xtext->col_fore);
|
||||
xtext_set_bg (xtext, xtext->col_back);
|
||||
}
|
||||
if (xtext->col_back != XTEXT_BG)
|
||||
xtext->backcolor = TRUE;
|
||||
@@ -3040,7 +3088,7 @@ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
|
||||
/* have we been told to stop rendering at this point? */
|
||||
if (xtext->jump_out_offset > 0 && xtext->jump_out_offset <= (i + offset))
|
||||
{
|
||||
gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, emphasis);
|
||||
gtk_xtext_render_flush (xtext, x, y, pstr, j, emphasis);
|
||||
ret = 0; /* skip the rest of the lines, we're done. */
|
||||
j = 0;
|
||||
break;
|
||||
@@ -3074,8 +3122,8 @@ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
|
||||
RENDER_FLUSH;
|
||||
pstr += j;
|
||||
j = 0;
|
||||
xtext_set_bg (xtext, gc, XTEXT_MARK_BG);
|
||||
xtext_set_fg (xtext, gc, XTEXT_MARK_FG);
|
||||
xtext_set_bg (xtext, XTEXT_MARK_BG);
|
||||
xtext_set_fg (xtext, XTEXT_MARK_FG);
|
||||
xtext->backcolor = TRUE;
|
||||
if (srch_underline)
|
||||
{
|
||||
@@ -3090,8 +3138,8 @@ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
|
||||
RENDER_FLUSH;
|
||||
pstr += j;
|
||||
j = 0;
|
||||
xtext_set_bg (xtext, gc, xtext->col_back);
|
||||
xtext_set_fg (xtext, gc, xtext->col_fore);
|
||||
xtext_set_bg (xtext, xtext->col_back);
|
||||
xtext_set_fg (xtext, xtext->col_fore);
|
||||
if (xtext->col_back != XTEXT_BG)
|
||||
xtext->backcolor = TRUE;
|
||||
else
|
||||
@@ -3106,8 +3154,8 @@ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
|
||||
|
||||
if (mark || srch_mark)
|
||||
{
|
||||
xtext_set_bg (xtext, gc, xtext->col_back);
|
||||
xtext_set_fg (xtext, gc, xtext->col_fore);
|
||||
xtext_set_bg (xtext, xtext->col_back);
|
||||
xtext_set_fg (xtext, xtext->col_fore);
|
||||
if (xtext->col_back != XTEXT_BG)
|
||||
xtext->backcolor = TRUE;
|
||||
else
|
||||
@@ -3431,7 +3479,7 @@ gtk_xtext_render_line (GtkXText * xtext, textentry * ent, int line,
|
||||
}
|
||||
|
||||
void
|
||||
gtk_xtext_set_palette (GtkXText * xtext, GdkColor palette[])
|
||||
gtk_xtext_set_palette (GtkXText * xtext, const XTextColor *palette)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -3442,11 +3490,10 @@ gtk_xtext_set_palette (GtkXText * xtext, GdkColor palette[])
|
||||
|
||||
if (gtk_widget_get_realized (GTK_WIDGET(xtext)))
|
||||
{
|
||||
xtext_set_fg (xtext, xtext->fgc, XTEXT_FG);
|
||||
xtext_set_bg (xtext, xtext->fgc, XTEXT_BG);
|
||||
xtext_set_fg (xtext, xtext->bgc, XTEXT_BG);
|
||||
xtext_set_fg (xtext, XTEXT_FG);
|
||||
xtext_set_bg (xtext, XTEXT_BG);
|
||||
|
||||
gdk_gc_set_foreground (xtext->marker_gc, &xtext->palette[XTEXT_MARKER]);
|
||||
xtext->marker_gc = xtext->palette[XTEXT_MARKER];
|
||||
}
|
||||
xtext->col_fore = XTEXT_FG;
|
||||
xtext->col_back = XTEXT_BG;
|
||||
@@ -3530,37 +3577,23 @@ gtk_xtext_set_font (GtkXText *xtext, char *name)
|
||||
}
|
||||
|
||||
void
|
||||
gtk_xtext_set_background (GtkXText * xtext, GdkPixmap * pixmap)
|
||||
gtk_xtext_set_background (GtkXText * xtext, cairo_surface_t *surface)
|
||||
{
|
||||
GdkGCValues val;
|
||||
|
||||
if (xtext->pixmap)
|
||||
if (xtext->background_surface)
|
||||
{
|
||||
g_object_unref (xtext->pixmap);
|
||||
xtext->pixmap = NULL;
|
||||
cairo_surface_destroy (xtext->background_surface);
|
||||
xtext->background_surface = NULL;
|
||||
}
|
||||
|
||||
dontscroll (xtext->buffer);
|
||||
xtext->pixmap = pixmap;
|
||||
if (surface)
|
||||
{
|
||||
xtext->background_surface = cairo_surface_reference (surface);
|
||||
}
|
||||
|
||||
if (pixmap != 0)
|
||||
if (surface && gtk_widget_get_realized (GTK_WIDGET(xtext)))
|
||||
{
|
||||
g_object_ref (pixmap);
|
||||
if (gtk_widget_get_realized (GTK_WIDGET(xtext)))
|
||||
{
|
||||
gdk_gc_set_tile (xtext->bgc, pixmap);
|
||||
gdk_gc_set_ts_origin (xtext->bgc, 0, 0);
|
||||
xtext->ts_x = xtext->ts_y = 0;
|
||||
gdk_gc_set_fill (xtext->bgc, GDK_TILED);
|
||||
}
|
||||
} else if (gtk_widget_get_realized (GTK_WIDGET(xtext)))
|
||||
{
|
||||
g_object_unref (xtext->bgc);
|
||||
val.subwindow_mode = GDK_INCLUDE_INFERIORS;
|
||||
val.graphics_exposures = 0;
|
||||
xtext->bgc = gdk_gc_new_with_values (GTK_WIDGET (xtext)->window,
|
||||
&val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
|
||||
xtext_set_fg (xtext, xtext->bgc, XTEXT_BG);
|
||||
xtext->ts_x = xtext->ts_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3812,7 +3845,8 @@ gtk_xtext_render_page (GtkXText * xtext)
|
||||
if (xtext->buffer->indent < MARGIN)
|
||||
xtext->buffer->indent = MARGIN; /* 2 pixels is our left margin */
|
||||
|
||||
gdk_drawable_get_size (GTK_WIDGET (xtext)->window, &width, &height);
|
||||
width = gdk_window_get_width (GTK_WIDGET (xtext)->window);
|
||||
height = gdk_window_get_height (GTK_WIDGET (xtext)->window);
|
||||
|
||||
if (width < 34 || height < xtext->fontsize || width < xtext->buffer->indent + 32)
|
||||
return;
|
||||
@@ -3837,30 +3871,70 @@ gtk_xtext_render_page (GtkXText * xtext)
|
||||
xtext->buffer->last_pixel_pos = pos;
|
||||
|
||||
#ifndef __APPLE__
|
||||
if (!xtext->pixmap && abs (overlap) < height)
|
||||
if (!xtext->background_surface && abs (overlap) < height)
|
||||
{
|
||||
GdkRectangle area;
|
||||
cairo_t *cr;
|
||||
int src_x = 0;
|
||||
int src_y = 0;
|
||||
int dest_x = 0;
|
||||
int dest_y = 0;
|
||||
int copy_height = 0;
|
||||
|
||||
/* so the obscured regions are exposed */
|
||||
gdk_gc_set_exposures (xtext->fgc, TRUE);
|
||||
if (overlap < 1) /* DOWN */
|
||||
{
|
||||
int remainder;
|
||||
cairo_surface_t *surface;
|
||||
|
||||
gdk_draw_drawable (xtext->draw_buf, xtext->fgc, xtext->draw_buf,
|
||||
0, -overlap, 0, 0, width, height + overlap);
|
||||
src_y = -overlap;
|
||||
dest_y = 0;
|
||||
copy_height = height + overlap;
|
||||
cr = xtext_create_context (xtext);
|
||||
cairo_save (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
surface = xtext_surface_from_window (GTK_WIDGET (xtext)->window);
|
||||
if (!surface)
|
||||
{
|
||||
cairo_restore (cr);
|
||||
cairo_destroy (cr);
|
||||
goto full_redraw;
|
||||
}
|
||||
cairo_set_source_surface (cr, surface, dest_x - src_x, dest_y - src_y);
|
||||
cairo_surface_destroy (surface);
|
||||
cairo_rectangle (cr, dest_x, dest_y, width, copy_height);
|
||||
cairo_fill (cr);
|
||||
cairo_restore (cr);
|
||||
cairo_destroy (cr);
|
||||
remainder = ((height - xtext->font->descent) % xtext->fontsize) +
|
||||
xtext->font->descent;
|
||||
area.y = (height + overlap) - remainder;
|
||||
area.height = remainder - overlap;
|
||||
} else
|
||||
{
|
||||
gdk_draw_drawable (xtext->draw_buf, xtext->fgc, xtext->draw_buf,
|
||||
0, 0, 0, overlap, width, height - overlap);
|
||||
cairo_surface_t *surface;
|
||||
|
||||
src_y = 0;
|
||||
dest_y = overlap;
|
||||
copy_height = height - overlap;
|
||||
cr = xtext_create_context (xtext);
|
||||
cairo_save (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
surface = xtext_surface_from_window (GTK_WIDGET (xtext)->window);
|
||||
if (!surface)
|
||||
{
|
||||
cairo_restore (cr);
|
||||
cairo_destroy (cr);
|
||||
goto full_redraw;
|
||||
}
|
||||
cairo_set_source_surface (cr, surface, dest_x - src_x, dest_y - src_y);
|
||||
cairo_surface_destroy (surface);
|
||||
cairo_rectangle (cr, dest_x, dest_y, width, copy_height);
|
||||
cairo_fill (cr);
|
||||
cairo_restore (cr);
|
||||
cairo_destroy (cr);
|
||||
area.y = 0;
|
||||
area.height = overlap;
|
||||
}
|
||||
gdk_gc_set_exposures (xtext->fgc, FALSE);
|
||||
|
||||
if (area.height > 0)
|
||||
{
|
||||
@@ -3873,6 +3947,7 @@ gtk_xtext_render_page (GtkXText * xtext)
|
||||
}
|
||||
#endif
|
||||
|
||||
full_redraw:
|
||||
width -= MARGIN;
|
||||
lines_max = ((height + xtext->pixel_offset) / xtext->fontsize) + 1;
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#define HEXCHAT_XTEXT_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <cairo.h>
|
||||
#include "xtext-color.h"
|
||||
|
||||
#define GTK_TYPE_XTEXT (gtk_xtext_get_type ())
|
||||
#define GTK_XTEXT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_XTEXT, GtkXText))
|
||||
@@ -130,8 +132,9 @@ struct _GtkXText
|
||||
xtext_buffer *selection_buffer;
|
||||
|
||||
GtkAdjustment *adj;
|
||||
GdkPixmap *pixmap; /* 0 = use palette[19] */
|
||||
GdkDrawable *draw_buf; /* points to ->window */
|
||||
cairo_surface_t *background_surface; /* 0 = use palette[19] */
|
||||
GdkWindow *draw_window; /* points to ->window */
|
||||
cairo_surface_t *draw_surface; /* temporary surface for offscreen draws */
|
||||
GdkCursor *hand_cursor;
|
||||
GdkCursor *resize_cursor;
|
||||
|
||||
@@ -142,13 +145,13 @@ struct _GtkXText
|
||||
int last_win_h;
|
||||
int last_win_w;
|
||||
|
||||
GdkGC *bgc; /* backing pixmap */
|
||||
GdkGC *fgc; /* text foreground color */
|
||||
GdkGC *light_gc; /* sep bar */
|
||||
GdkGC *dark_gc;
|
||||
GdkGC *thin_gc;
|
||||
GdkGC *marker_gc;
|
||||
GdkColor palette[XTEXT_COLS];
|
||||
XTextColor bgc; /* text background color */
|
||||
XTextColor fgc; /* text foreground color */
|
||||
XTextColor light_gc; /* sep bar */
|
||||
XTextColor dark_gc;
|
||||
XTextColor thin_gc;
|
||||
XTextColor marker_gc;
|
||||
XTextColor palette[XTEXT_COLS];
|
||||
|
||||
gint io_tag; /* for delayed refresh events */
|
||||
gint add_io_tag; /* "" when adding new text */
|
||||
@@ -252,15 +255,15 @@ struct _GtkXTextClass
|
||||
void (*set_scroll_adjustments) (GtkXText *xtext, GtkAdjustment *hadj, GtkAdjustment *vadj);
|
||||
};
|
||||
|
||||
GtkWidget *gtk_xtext_new (GdkColor palette[], int separator);
|
||||
GtkWidget *gtk_xtext_new (const XTextColor *palette, int separator);
|
||||
void gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len, time_t stamp);
|
||||
void gtk_xtext_append_indent (xtext_buffer *buf,
|
||||
unsigned char *left_text, int left_len,
|
||||
unsigned char *right_text, int right_len,
|
||||
time_t stamp);
|
||||
int gtk_xtext_set_font (GtkXText *xtext, char *name);
|
||||
void gtk_xtext_set_background (GtkXText * xtext, GdkPixmap * pixmap);
|
||||
void gtk_xtext_set_palette (GtkXText * xtext, GdkColor palette[]);
|
||||
void gtk_xtext_set_background (GtkXText * xtext, cairo_surface_t *surface);
|
||||
void gtk_xtext_set_palette (GtkXText * xtext, const XTextColor *palette);
|
||||
void gtk_xtext_clear (xtext_buffer *buf, int lines);
|
||||
void gtk_xtext_save (GtkXText * xtext, int fh);
|
||||
void gtk_xtext_refresh (GtkXText * xtext);
|
||||
|
||||
Reference in New Issue
Block a user