This repository has been archived on 2020-04-11. You can view files and clone it, but cannot push or open issues or pull requests.
gnoemoe/gnoemoe/gm-support.c

837 lines
19 KiB
C
Raw Normal View History

2005-11-07 10:56:25 +01:00
#ifdef HAVE_CONFIG_H
2006-01-10 01:42:09 +01:00
#include <config.h>
2005-11-07 10:56:25 +01:00
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <locale.h>
#include <sys/mman.h>
#include <fcntl.h>
2005-11-07 10:56:25 +01:00
#include <gtk/gtk.h>
#include <regex.h>
#include <libgnome/gnome-url.h>
#include <libgnomevfs/gnome-vfs.h>
#include <errno.h>
#include "gm-support.h"
#include "gm-debug.h"
#include "gm-pixbuf.h"
2005-11-19 14:09:12 +01:00
#include "gm-string.h"
#include "gm-color-table.h"
#include "gm-app.h"
2005-11-07 10:56:25 +01:00
#define URL_REGEXP "(((mailto|news|telnet|nttp|file|http|sftp|ftp|https|dav|callto)://)|(www|ftp)[-A-Za-z0-9]*\\.)[-A-Za-z0-9\\.@:]+[^]''\\.}>\\) ,\\/\\\"\\!]+(:[0-9]*)?(/|/[-A-Za-z0-9_\\$\\.\\+\\!\\*\\(\\),;:@&=\\?/~\\#\\%]*[^]'\\.}>\\) ,\\\"\\!])?"
static regex_t url_regexp;
gchar *
gm_fix_decimal_point(gchar *line, int len) {
int i;
struct lconv *l = localeconv();
if (l->decimal_point[0] == '.') {
return line;
}
for (i = 0; i < len; i++) {
if (line[i] == '.') {
line[i] = l->decimal_point[0];
}
}
return line;
}
gchar *
gm_fix_decimal_point_rev(gchar *line, int len) {
int i;
struct lconv *l = localeconv();
2005-11-07 10:56:25 +01:00
for (i = 0; i < len; i++) {
if (line[i] == l->decimal_point[0]) {
line[i] = '.';
}
}
2005-11-07 10:56:25 +01:00
return line;
2005-11-07 10:56:25 +01:00
}
gchar *
2005-11-19 14:09:12 +01:00
gm_ansi_strip(gchar *s) {
gchar *ptr, *fptr;
gunichar c;
ptr = s;
fptr = s;
while (*ptr != '\0') {
c = g_utf8_get_char(ptr);
// Escape sequence, advance to character after 'm'
if (c == '\x1B') {
gm_string_skip_till((const gchar **)(&ptr), "m");
} else if (c != '\x07') {
// Store any other character (excluding bell char)
fptr += g_unichar_to_utf8(c, fptr);
}
if (*ptr != '\0') {
ptr = g_utf8_next_char(ptr);
}
}
*fptr = '\0';
return s;
2005-11-07 10:56:25 +01:00
}
int
gm_garray_length(gchar **s) {
gchar **iter = s;
while (*iter++ != NULL)
;
return *iter - *s - 1;
2005-11-07 10:56:25 +01:00
}
void gm_g_list_free_simple(GList *s) {
GList *tmp;
2005-11-07 10:56:25 +01:00
for (tmp = s; tmp; tmp = tmp->next) {
g_free(tmp->data);
}
2005-11-07 10:56:25 +01:00
g_list_free(s);
2005-11-07 10:56:25 +01:00
}
gchar *
gm_g_list_find_simple(GList *s, gchar *f) {
GList *tmp;
2005-11-07 10:56:25 +01:00
for (tmp = s; tmp; tmp = tmp->next) {
if (strcmp(tmp->data, f) == 0) {
return tmp->data;
}
}
2005-11-07 10:56:25 +01:00
return NULL;
2005-11-07 10:56:25 +01:00
}
2006-03-29 14:23:28 +02:00
gint
2005-11-07 10:56:25 +01:00
gm_dialog(gchar * message, GtkMessageType messagebox_type,
2006-03-29 14:23:28 +02:00
gint buttons_type, GtkWindow * parent) {
GtkWidget *dlg;
2006-03-29 14:23:28 +02:00
gint result;
dlg = gtk_message_dialog_new(parent,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2006-03-29 14:23:28 +02:00
messagebox_type, buttons_type, message, NULL);
result = gtk_dialog_run(GTK_DIALOG(dlg));
gtk_widget_destroy(dlg);
2006-03-29 14:23:28 +02:00
return result;
2005-11-07 10:56:25 +01:00
}
2006-03-29 14:23:28 +02:00
gint
2005-11-07 10:56:25 +01:00
gm_error_dialog(gchar * message, GtkWindow * parent) {
2006-03-29 14:23:28 +02:00
return gm_dialog(message, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, parent);
2005-11-07 10:56:25 +01:00
}
2006-03-29 14:23:28 +02:00
gint
2005-11-07 10:56:25 +01:00
gm_warning_dialog(gchar * message, GtkWindow * parent) {
2006-03-29 14:23:28 +02:00
return gm_dialog(message, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, parent);
2005-11-07 10:56:25 +01:00
}
2006-03-29 14:23:28 +02:00
gint
2005-11-07 10:56:25 +01:00
gm_info_dialog(gchar * message, GtkWindow * parent) {
2006-03-29 14:23:28 +02:00
return gm_dialog(message, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, parent);
2005-11-07 10:56:25 +01:00
}
2006-03-29 14:23:28 +02:00
gint
2005-11-07 10:56:25 +01:00
gm_question_dialog(gchar * message, GtkWindow * parent) {
2006-03-29 14:23:28 +02:00
return gm_dialog(message, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, parent);
2005-11-07 10:56:25 +01:00
}
void
gm_do_events() {
while (gtk_events_pending()) {
gtk_main_iteration();
}
2005-11-07 10:56:25 +01:00
}
void
gm_directory_remove_all(const gchar * path, gboolean remove_self) {
GDir *cDir;
gchar *name;
gchar *newPath;
if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
// Iterate through the files and do the right thingie
if ((cDir = g_dir_open(path, 0, NULL))) {
while ((name = (gchar *) (g_dir_read_name(cDir))) != NULL) {
newPath = g_strconcat(path, "/", name, NULL);
gm_directory_remove_all(newPath, TRUE);
g_free(newPath);
}
g_dir_close(cDir);
}
}
2005-11-07 10:56:25 +01:00
if (remove_self) {
// Its a file, or just empty! MUST...BE...REMOVEEEED!
remove(path);
}
2005-11-07 10:56:25 +01:00
}
gint
gm_url_regex_match(const gchar *msg, int len, GArray *start, GArray *end) {
static gboolean inited = FALSE;
regmatch_t matches[1];
gint ret = 0, num_matches = 0, offset = 0;
gchar *tmp;
gint s;
if (!inited) {
memset(&url_regexp, 0, sizeof (regex_t));
regcomp(&url_regexp, URL_REGEXP, REG_EXTENDED);
inited = TRUE;
}
tmp = g_strndup(msg, len);
while (!ret) {
ret = regexec(&url_regexp, (char *)(tmp + offset), 1, matches, 0);
if (ret == 0) {
if (matches[0].rm_so > matches[0].rm_eo) {
break;
}
num_matches++;
s = matches[0].rm_so + offset;
offset = matches[0].rm_eo + offset;
g_array_append_val(start, s);
g_array_append_val(end, offset);
}
}
g_free(tmp);
return num_matches;
}
void
gm_open_url(const gchar *url) {
if (url == NULL || *url == '\0') {
2005-11-07 10:56:25 +01:00
return;
}
/* gnome_url_show doesn't work when there's no protocol, so we might
* need to add one.
*/
if (strstr(url, "://") == NULL) {
2005-11-07 10:56:25 +01:00
gchar *tmp;
tmp = g_strconcat("http://", url, NULL);
2005-11-07 10:56:25 +01:00
gnome_url_show(tmp, NULL);
g_free(tmp);
2005-11-07 10:56:25 +01:00
return;
}
gnome_url_show(url, NULL);
2005-11-07 10:56:25 +01:00
}
void
gm_fetch_handle_free(GmFetchHandle *g) {
2006-01-08 17:33:48 +01:00
GList *tmp;
g_free(g->cur_file_name);
for (tmp = g->source_uri; tmp; tmp = tmp->next) {
gnome_vfs_uri_unref((GnomeVFSURI*)(tmp->data));
}
2005-11-07 10:56:25 +01:00
g_list_free(g->source_uri);
2006-01-08 17:33:48 +01:00
for (tmp = g->dest_uri; tmp; tmp = tmp->next) {
gnome_vfs_uri_unref((GnomeVFSURI*)(tmp->data));
}
2005-11-07 10:56:25 +01:00
g_list_free(g->dest_uri);
g_free(g);
}
GmFetchHandle *
gm_fetch_handle_create(GFunc cb, gpointer user_data) {
2006-01-08 17:33:48 +01:00
GmFetchHandle *g = g_new0(GmFetchHandle, 1);
g->cb = cb;
g->user_data = user_data;
2005-11-07 10:56:25 +01:00
g->prev_status = GNOME_VFS_XFER_PROGRESS_STATUS_OK;
g->cur_phase = -1;
g->prev_phase = -1;
g->cur_file = -1;
g->prev_file = -1;
2006-01-08 17:33:48 +01:00
2005-11-07 10:56:25 +01:00
return g;
}
gint
gm_fetch_progress(GnomeVFSAsyncHandle *handle,
GnomeVFSXferProgressInfo *info,
GmFetchHandle *g) {
gchar *name;
gchar const *err;
2005-11-07 10:56:25 +01:00
g->cur_phase = info->phase;
g->cur_file = info->file_index;
g->files_total = info->files_total;
g->bytes_total = info->bytes_total;
g->file_size = info->file_size;
g->bytes_copied = info->bytes_copied;
g->total_bytes_copied = info->total_bytes_copied;
g->status = info->status;
2006-01-08 17:33:48 +01:00
if (g->aborted) {
g->cb(g, g->user_data);
gm_fetch_handle_free(g);
return FALSE;
}
2005-11-07 10:56:25 +01:00
if (info->target_name != NULL) {
if (g->cur_file_name && strcmp(g->cur_file_name, info->target_name) != 0) {
g->cur_phase = GNOME_VFS_XFER_PHASE_FILECOMPLETED;
g->cb(g, g->user_data);
g->cur_phase = info->phase;
2005-11-07 10:56:25 +01:00
g_free(g->cur_file_name);
g->cur_file_name = NULL;
}
if (!g->cur_file_name) {
g->cur_file_name = g_strdup(info->target_name);
}
}
2005-11-07 10:56:25 +01:00
if (info->status == GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE) {
name = gnome_vfs_get_local_path_from_uri(info->target_name);
gm_debug_msg(DEBUG_DEFAULT, "GmFetchProgress: asking for overwriting "
"%s: yes", name);
2005-11-07 10:56:25 +01:00
g->prev_status = GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE;
return GNOME_VFS_XFER_OVERWRITE_ACTION_REPLACE;
} else if (info->status == GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR) {
name = gnome_vfs_get_local_path_from_uri(info->target_name);
err = gnome_vfs_result_to_string(info->vfs_status);
2005-11-07 10:56:25 +01:00
gdk_threads_enter();
gm_debug_msg(DEBUG_DEFAULT, "GmFetchProgress: error for %s: %s", name,
err);
g->cb(g, g->user_data);
gdk_threads_leave();
2005-11-07 10:56:25 +01:00
g_free(g->cur_file_name);
g->cur_file_name = NULL;
2005-11-07 10:56:25 +01:00
g->prev_status = GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR;
g_free(name);
2005-11-07 10:56:25 +01:00
return GNOME_VFS_XFER_ERROR_ACTION_SKIP;
}
2005-11-07 10:56:25 +01:00
if (info->phase == GNOME_VFS_XFER_PHASE_COMPLETED) {
if (g->cur_file_name != NULL) {
g->cur_phase = GNOME_VFS_XFER_PHASE_FILECOMPLETED;
g->cb(g, g->user_data);
g->cur_phase = info->phase;
}
2005-11-07 10:56:25 +01:00
g->done = TRUE;
g->cb(g, g->user_data);
gm_fetch_handle_free(g);
return TRUE;
}
2005-11-07 10:56:25 +01:00
g->prev_status = info->status;
2005-11-07 10:56:25 +01:00
return TRUE;
2005-11-07 10:56:25 +01:00
}
gint
gm_fetch_interact(GnomeVFSXferProgressInfo *info, gpointer user_data) {
return 1;
2005-11-07 10:56:25 +01:00
}
GmFetchHandle *
gm_fetch(const GList *source, const GList *dest,
GFunc cb, gpointer user_data) {
GmFetchHandle *g = gm_fetch_handle_create(cb, user_data);
gchar *uri;
GnomeVFSResult ret;
for (; source; source = source->next) {
uri = (gchar *)(source->data);
g->source_uri = g_list_append(g->source_uri, gnome_vfs_uri_new(uri));
}
for (; dest; dest = dest->next) {
uri = (gchar *)(dest->data);
g->dest_uri = g_list_append(g->dest_uri, gnome_vfs_uri_new(uri));
}
ret = gnome_vfs_async_xfer(&(g->handle), g->source_uri, g->dest_uri,
GNOME_VFS_XFER_DEFAULT|GNOME_VFS_XFER_RECURSIVE,
GNOME_VFS_XFER_ERROR_MODE_QUERY,
GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
GNOME_VFS_PRIORITY_DEFAULT,
(GnomeVFSAsyncXferProgressCallback)gm_fetch_progress,
g, gm_fetch_interact, g);
return g;
2005-11-07 10:56:25 +01:00
}
gboolean
gm_is_end_scrolled(GtkScrolledWindow *wnd, guint charHeight) {
GtkAdjustment *ad = gtk_scrolled_window_get_vadjustment(wnd);
return ((ad->page_size + ad->value) >= ad->upper - (double)charHeight);
2005-11-07 10:56:25 +01:00
}
void
gm_scroll_end(GtkTextView *view, gboolean needs) {
GtkTextBuffer *buf;
GtkTextMark *mark;
GtkTextIter iter;
if (!needs) {
return;
}
buf = gtk_text_view_get_buffer(view);
mark = gtk_text_buffer_get_mark(buf, "end-of-buffer");
if (mark == NULL) {
gtk_text_buffer_get_end_iter(buf, &iter);
mark = gtk_text_buffer_create_mark(buf, "end-of-buffer", &iter, FALSE);
}
gtk_text_view_scroll_to_mark(view, mark, 0.0, TRUE, 1.0, 1.0);
2005-11-07 10:56:25 +01:00
}
#define MAX_BUF 1024
gchar *
gm_read_file(const gchar *fname) {
int fd;
gchar *tmp, *mapped;
long bytes_total = 0;
2005-11-07 10:56:25 +01:00
if (!fname) {
return NULL;
}
2005-11-07 10:56:25 +01:00
fd = open(fname, O_RDONLY);
2005-11-07 10:56:25 +01:00
if (fd == -1) {
gm_debug_msg(DEBUG_DEFAULT, "GmReadFile: file (%s) could not be read: "
"%s", fname, strerror(errno));
return NULL;
}
bytes_total = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
if (bytes_total == (off_t)-1) {
close(fd);
return NULL;
}
mapped = mmap(0, bytes_total, PROT_READ, MAP_PRIVATE, fd, 0);
if (mapped == MAP_FAILED) {
close(fd);
2005-11-07 10:56:25 +01:00
gm_debug_msg(DEBUG_DEFAULT, "GmReadFile: error while mapping file: %s",
strerror(errno));
return NULL;
}
if (g_utf8_validate(mapped, bytes_total, NULL)) {
// Easy, this is utf8!
tmp = g_strndup(mapped, bytes_total);
} else {
// Try locale
tmp = g_locale_to_utf8(mapped, bytes_total, NULL, NULL, NULL);
if (!tmp) {
// Now we're getting desperate... try ISO-8859-15
tmp = g_convert(mapped, bytes_total, "UTF-8", "ISO-8859-15", NULL,
NULL, NULL);
}
if (!tmp) {
// OMG try one last conversion to ISO-8859-1
tmp = g_convert(mapped, bytes_total, "UTF-8", "ISO-8859-1", NULL,
NULL, NULL);
}
}
munmap(mapped, bytes_total);
close(fd);
return tmp;
2005-11-07 10:56:25 +01:00
}
GtkWidget *
gm_create_tab_label(const gchar *icon, const gchar *caption, gboolean has_exit,
GmLabelInfo *info) {
/* First create the gbox (size 3) which will contain an icon, a label and a
exit button if has_exit is true */
GtkWidget *hboxTabLabel;
gint h, w;
GtkRcStyle *rcstyle;
hboxTabLabel = gtk_hbox_new(FALSE, 4);
2005-11-07 10:56:25 +01:00
gtk_widget_show(hboxTabLabel);
gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &w, &h);
2005-11-07 10:56:25 +01:00
info->image_icon = gtk_image_new_from_pixbuf(
gm_pixbuf_get_at_size(icon, w, h));
gtk_widget_set_size_request(info->image_icon, w, h);
2005-11-07 10:56:25 +01:00
gtk_widget_show(info->image_icon);
gtk_box_pack_start(GTK_BOX(hboxTabLabel), info->image_icon, TRUE, TRUE, 0);
info->label_name = gtk_label_new(caption);
gtk_widget_show(info->label_name);
gtk_box_pack_start(GTK_BOX(hboxTabLabel), info->label_name, FALSE, FALSE, 0);
if (has_exit) {
info->button_exit = gtk_button_new();
gtk_widget_show(info->button_exit);
gtk_box_pack_end(GTK_BOX(hboxTabLabel), info->button_exit , FALSE,
FALSE, 0);
gtk_button_set_relief(GTK_BUTTON(info->button_exit), GTK_RELIEF_NONE);
2005-11-07 10:56:25 +01:00
gtk_button_set_focus_on_click(GTK_BUTTON(info->button_exit), FALSE);
gtk_widget_set_size_request(info->button_exit, w + 2, h + 2);
rcstyle = gtk_rc_style_new();
rcstyle->xthickness = rcstyle->ythickness = 0;
gtk_widget_modify_style(info->button_exit, rcstyle);
gtk_rc_style_unref(rcstyle);
info->image_exit = gtk_image_new_from_stock(GTK_STOCK_CLOSE,
2005-11-07 10:56:25 +01:00
GTK_ICON_SIZE_MENU);
gtk_widget_show(info->image_exit);
gtk_container_add(GTK_CONTAINER(info->button_exit), info->image_exit);
}
return hboxTabLabel;
}
void
gm_widget_destroy_data(GtkWidget *caller, GtkWidget *destroyer) {
if (GTK_IS_WIDGET(destroyer)) {
gtk_widget_destroy(destroyer);
}
2005-11-07 10:56:25 +01:00
}
const gchar *
gm_default_charset() {
static const gchar *loc = NULL;
if (loc == NULL) {
g_get_charset(&loc);
}
if (loc == NULL || *loc == 0) {
loc = "ISO-8859-15";
}
2005-11-07 10:56:25 +01:00
return loc;
2005-11-07 10:56:25 +01:00
}
void
gm_notebook_focus_from_label(GtkNotebook *note, gchar *caption) {
int p = gtk_notebook_get_n_pages(note);
int i;
GtkWidget *child;
for (i = 0; i < p; i++) {
child = gtk_notebook_get_nth_page(note, i);
if (!g_strcasecmp(gtk_notebook_get_tab_label_text(note, child),
caption)) {
gtk_notebook_set_current_page(note, i);
break;
}
}
}
2006-03-31 22:28:12 +02:00
GtkWidget *
gm_find_parent(GtkWidget *widget, GType parent_type) {
if (widget == NULL) {
return NULL;
}
if (G_TYPE_CHECK_INSTANCE_TYPE(widget, parent_type)) {
return widget;
}
return gm_find_parent(gtk_widget_get_parent(widget), parent_type);
}
* VERSION CHANGED TO 2.0.9 * po/POTFILES.in: added gnoemoe/dialogs/gm-world-paste-dialog.c and ui/gm-world-paste.glade * po/nl.po: added translations * ui/Makefile.am: * ui/gm-ui.xml: * ui/gm-world-paste.glade: new paste dialog * gnoemoe/mcp/Makefile.include: added gm-cell-renderer-text.[ch] * gnoemoe/mcp/gm-cell-renderer-text.[ch]: new cell renderer for rendering userlist * gnoemoe/mcp/gm-mcp-vmoo-client.c: update metrics in timeout so to reduce the number of updates when resizing * gnoemoe/mcp/gm-mcp-icecrew-serverinfo.c: max version set to 1.0 (1.0 does not actively request the info because it will be send on initialization). Set menu item invisible instead of insensitive when there is no info available * gnoemoe/mcp/gm-mcp-icecrew-userlist.c: fixed menu item substitution * gnoemoe/mcp/gm-mcp-vmoo-userlist.c: removed support for status because it doesn't really support it * gm-mcp-userlist-view.[ch]: moved column constants to header. Render items with new gm-cell-renderer-text. * gnoemoe/mcp/gm-mcp-icecrew-playerdb.[ch]: made gm_mcp_icecrew_playerdb_players public * gnoemoe/dialogs/Makefile.include: added gm-world-paste-dialog * gnoemoe/dialogs/gm-world-paste-dialog.[ch]: new paste dialog * gnoemoe/dialogs/gm-world-properties-dialog.c: * gnoemoe/dialogs/gm-world-logs-dialog.c: fixed leaking tree stores * gnoemoe/widgets/Makefile.include: added gm-commands.[ch] * gnoemoe/widgets/gm-commands.[ch]: new file for handling action activation (removed from gm-app-view) * gnoemoe/widgets/gm-world-view.c: fixed userlist size restore * gnoemoe/widgets/gm-app-view.c: removed action handlers * gnoemoe/gm-support.[ch]: added gm_find_child * gnoemoe/gm-world.c: removed debug message * gnoemoe/gm-ui.h: changed actions to gm-commands
2006-04-23 16:51:04 +02:00
GtkWidget *
gm_find_child(GtkWidget *widget, GType parent_type) {
GList *children, *child;
if (widget == NULL) {
return NULL;
}
if (G_TYPE_CHECK_INSTANCE_TYPE(widget, parent_type)) {
return widget;
}
if (GTK_IS_CONTAINER(widget)) {
children = gtk_container_get_children(GTK_CONTAINER(widget));
widget = NULL;
for (child = children; child; child = child->next) {
widget = gm_find_child(GTK_WIDGET(child->data), parent_type);
if (widget) {
break;
}
}
g_list_free(children);
return widget;
} else {
return NULL;
}
}
2006-03-31 22:28:12 +02:00
2005-11-07 10:56:25 +01:00
gchar *
2006-02-06 19:39:19 +01:00
gm_convert_with_fallback(gchar const *text, gssize len, gchar const *from,
gchar const *to, gchar const *fallback) {
2005-11-07 10:56:25 +01:00
gchar *res;
gsize read, written;
GString *str = g_string_new("");
// TODO: use g_iconv instead of g_convert
2006-02-06 19:39:19 +01:00
while ((res = g_convert(text, len, to, from, &read, &written, NULL))
2005-11-07 10:56:25 +01:00
== NULL) {
2006-02-06 19:39:19 +01:00
res = g_convert(text, read, to, from, NULL, NULL, NULL);
2005-11-07 10:56:25 +01:00
str = g_string_append(str, res);
str = g_string_append(str, fallback);
text = text + read + 1;
if (len != -1)
len = len - read - 1;
}
str = g_string_append(str, res);
g_free(res);
res = str->str;
g_string_free(str, FALSE);
return res;
}
2006-02-06 19:39:19 +01:00
gchar *
gm_from_utf8_with_fallback(gchar const *text, gssize len, gchar const *to,
gchar const *fallback) {
return gm_convert_with_fallback(text, len, "UTF-8", to, fallback);
}
gchar *
gm_to_utf8_with_fallback(gchar const *text, gssize len, gchar const *from,
gchar const *fallback) {
return gm_convert_with_fallback(text, len, from, "UTF-8", fallback);
}
GtkWidget *
gm_container_item(GtkContainer *cnt, GType type) {
GList *child_first = gtk_container_get_children(cnt);
GList *child;
GtkWidget *result = NULL;
for (child = child_first; child; child = child->next) {
if (G_TYPE_CHECK_INSTANCE_TYPE(child->data, type)) {
result = GTK_WIDGET(child->data);
break;
} else if (GTK_IS_CONTAINER(child->data)) {
if ((result = gm_container_item(
GTK_CONTAINER(child->data), type))) {
break;
}
}
}
g_list_free(child_first);
return result;
}
static void
modify_cursor_color(GtkWidget *textview, GdkColor *color) {
static const char cursor_color_rc[] =
"style \"svs-cc\"\n"
"{\n"
"GtkTextView::cursor-color=\"#%04x%04x%04x\"\n"
"}\n"
"widget \"*.%s\" style : application \"svs-cc\"\n";
const gchar *name;
gchar *rc_temp;
name = gtk_widget_get_name(textview);
if (!name) {
gtk_widget_set_name(textview, "GmSchemedTextView");
name = gtk_widget_get_name(textview);
}
g_return_if_fail(name != NULL);
if (color != NULL) {
rc_temp = g_strdup_printf(cursor_color_rc, color->red, color->green,
color->blue, name);
} else {
GtkRcStyle *rc_style;
rc_style = gtk_widget_get_modifier_style(textview);
rc_temp = g_strdup_printf(cursor_color_rc,
rc_style->text[GTK_STATE_NORMAL].red,
rc_style->text[GTK_STATE_NORMAL].green,
rc_style->text[GTK_STATE_NORMAL].blue,
name);
}
gtk_rc_parse_string(rc_temp);
gtk_widget_reset_rc_styles(textview);
g_free(rc_temp);
}
void
on_color_changed(GmColorTable *table, gchar const *color, GtkWidget *widget) {
GdkColor col;
g_object_set_data(G_OBJECT(widget), "gm_schemed_modifying_style",
GINT_TO_POINTER(1));
if (strcmp(color, "fg_default") == 0) {
gm_color_table_get(table, color, &col);
gtk_widget_modify_text(widget, GTK_STATE_NORMAL, &col);
// Modify the cursor color
if (GTK_IS_TEXT_VIEW(widget)) {
modify_cursor_color(widget, &col);
}
} else if (strcmp(color, "bg_default") == 0) {
gm_color_table_get(table, color, &col);
gtk_widget_modify_base(widget, GTK_STATE_NORMAL, &col);
}
g_object_set_data(G_OBJECT(widget), "gm_schemed_modifying_style",
GINT_TO_POINTER(0));
}
void
on_font_changed(GmColorTable *table, gchar const *font, GtkWidget *widget) {
PangoFontDescription *desc = pango_font_description_from_string(font);
if (desc) {
gtk_widget_modify_font(widget, desc);
pango_font_description_free(desc);
}
}
void
on_style_set(GtkWidget *widget, GtkStyle *prev, gpointer user_data) {
GmSchemedFlags flags = GPOINTER_TO_INT(user_data);
GmColorTable *table = GM_COLOR_TABLE(g_object_get_data(G_OBJECT(widget),
"gm_color_table"));
gpointer modifying = g_object_get_data(G_OBJECT(widget),
"gm_schemed_modifying_style");
if (modifying != NULL && GPOINTER_TO_INT(modifying) == 1) {
return;
}
if (flags & GM_SCHEMED_COLORS) {
on_color_changed(table, "fg_default", widget);
on_color_changed(table, "bg_default", widget);
}
if (flags & GM_SCHEMED_FONT) {
on_font_changed(table, gm_color_table_font_description(table), widget);
}
}
void
on_widget_destroy(GtkWidget *widget, gpointer data) {
GmSchemedFlags flags = GPOINTER_TO_INT(data);
GmColorTable *table = GM_COLOR_TABLE(g_object_get_data(G_OBJECT(widget),
"gm_color_table"));
if (flags & GM_SCHEMED_COLORS) {
g_signal_handlers_disconnect_by_func(table,
G_CALLBACK(on_color_changed), widget);
}
if (flags & GM_SCHEMED_FONT) {
g_signal_handlers_disconnect_by_func(table,
G_CALLBACK(on_font_changed), widget);
}
//g_signal_handlers_disconnect_by_func(widget, G_CALLBACK(on_style_set),
// data);
g_signal_handlers_disconnect_by_func(widget, G_CALLBACK(on_widget_destroy),
data);
}
void
gm_register_schemed(GtkWidget *widget, GmColorTable *table,
GmSchemedFlags flags) {
gpointer data = g_object_get_data(G_OBJECT(widget), "gm_color_table");
if (data != NULL) {
on_widget_destroy(widget, GINT_TO_POINTER(flags));
}
if (table == NULL) {
return;
}
g_object_set_data(G_OBJECT(widget), "gm_color_table", table);
if (flags & GM_SCHEMED_COLORS) {
g_signal_connect(table, "color-changed",
G_CALLBACK(on_color_changed), widget);
on_color_changed(table, "fg_default", widget);
on_color_changed(table, "bg_default", widget);
}
if (flags & GM_SCHEMED_FONT) {
g_signal_connect(table, "font-changed",
G_CALLBACK(on_font_changed), widget);
on_font_changed(table, gm_color_table_font_description(table), widget);
}
//g_signal_connect(widget, "style-set",
// G_CALLBACK(on_style_set), GINT_TO_POINTER(flags));
g_signal_connect(widget, "destroy",
G_CALLBACK(on_widget_destroy), GINT_TO_POINTER(flags));
}