📄 main.c
字号:
/*cellwriter -- a character recognition input methodCopyright (C) 2007 Michael Levin <risujin@risujin.org>This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.*/#include "config.h"#include "common.h"#include <stdlib.h>#include <string.h>#include <signal.h>#include <stdio.h>#include <errno.h>#ifdef HAVE_GNOME#include <libgnome/libgnome.h>#endif/* recognize.c */extern int strength_sum;void recognize_init(void);void recognize_sync(void);void samples_write(void);void sample_read(void);void update_enabled_samples(void);int samples_loaded(void);/* cellwidget.c */extern int training, corrections, rewrites, characters, inputs;void cell_widget_cleanup(void);/* options.c */void options_sync(void);/* keyevent.c */extern int key_recycles, key_overwrites, key_disable_overwrite;int key_event_init(void);void key_event_cleanup(void);void bad_keycodes_write(void);void bad_keycodes_read(void);/* Variable argument parsing*/char *nvav(int *plen, const char *fmt, va_list va){ static char buffer[2][16000]; static int which; int len; which = !which; len = g_vsnprintf(buffer[which], sizeof(buffer[which]), fmt, va); if (plen) *plen = len; return buffer[which];}char *nva(int *plen, const char *fmt, ...){ va_list va; char *string; va_start(va, fmt); string = nvav(plen, fmt, va); va_end(va); return string;}char *va(const char *fmt, ...){ va_list va; char *string; va_start(va, fmt); string = nvav(NULL, fmt, va); va_end(va); return string;}/* GDK colors*/static int check_color_range(int value){ if (value < 0) value = 0; if (value > 65535) value = 65535; return value;}void scale_gdk_color(const GdkColor *base, GdkColor *out, double value){ out->red = check_color_range(base->red * value); out->green = check_color_range(base->green * value); out->blue = check_color_range(base->blue * value);}void gdk_color_to_hsl(const GdkColor *src, double *hue, double *sat, double *lit)/* Source: http://en.wikipedia.org/wiki/HSV_color_space #Conversion_from_RGB_to_HSL_or_HSV */{ double max = src->red, min = src->red; /* Find largest and smallest channel */ if (src->green > max) max = src->green; if (src->green < min) min = src->green; if (src->blue > max) max = src->blue; if (src->blue < min) min = src->blue; /* Hue depends on max/min */ if (max == min) *hue = 0; else if (max == src->red) { *hue = (src->green - src->blue) / (max - min) / 6.; if (*hue < 0.) *hue += 1.; } else if (max == src->green) *hue = ((src->blue - src->red) / (max - min) + 2.) / 6.; else if (max == src->blue) *hue = ((src->red - src->green) / (max - min) + 4.) / 6.; /* Lightness */ *lit = (max + min) / 2 / 65535; /* Saturation depends on lightness */ if (max == min) *sat = 0.; else if (*lit <= 0.5) *sat = (max - min) / (max + min); else *sat = (max - min) / (65535 * 2 - (max + min));}void hsl_to_gdk_color(GdkColor *src, double hue, double sat, double lit)/* Source: http://en.wikipedia.org/wiki/HSV_color_space #Conversion_from_RGB_to_HSL_or_HSV */{ double q, p, t[3]; int i; /* Clamp ranges */ if (hue < 0) hue -= (int)hue - 1.; if (hue > 1) hue -= (int)hue; if (sat < 0) sat = 0; if (sat > 1) sat = 1; if (lit < 0) lit = 0; if (lit > 1) lit = 1; /* Special case for gray */ if (sat == 0.) { src->red = lit * 65535; src->green = lit * 65535; src->blue = lit * 65535; return; } q = (lit < 0.5) ? lit * (1 + sat) : lit + sat - (lit * sat); p = 2 * lit - q; t[0] = hue + 1 / 3.; t[1] = hue; t[2] = hue - 1 / 3.; for (i = 0; i < 3; i++) { if (t[i] < 0.) t[i] += 1.; if (t[i] > 1.) t[i] -= 1.; if (t[i] >= 2 / 3.) t[i] = p; else if (t[i] >= 0.5) t[i] = p + ((q - p) * 6 * (2 / 3. - t[i])); else if (t[i] >= 1 / 6.) t[i] = q; else t[i] = p + ((q - p) * 6 * t[i]); } src->red = t[0] * 65535; src->green = t[1] * 65535; src->blue = t[2] * 65535;}void shade_gdk_color(const GdkColor *base, GdkColor *out, double value){ double hue, sat, lit; gdk_color_to_hsl(base, &hue, &sat, &lit); sat *= value; lit += value - 1.; hsl_to_gdk_color(out, hue, sat, lit);}void highlight_gdk_color(const GdkColor *base, GdkColor *out, double value)/* Shades brighter or darker depending on the luminance of the base color */{ double lum = (0.3 * base->red + 0.59 * base->green + 0.11 * base->blue) / 65535; value = lum < 0.5 ? 1. + value : 1. - value; shade_gdk_color(base, out, value);}/* Profile*//* Profile format version */#define PROFILE_VERSION 0int profile_read_only, keyboard_only = FALSE;static GIOChannel *channel;static char profile_buf[4096], *profile_end = NULL, profile_swap, *force_profile = NULL, *profile_tmp = NULL;static int force_read_only;static int is_space(int ch){ return ch == ' ' || ch == '\t' || ch == '\r';}static int profile_open_channel(const char *type, const char *path)/* Tries to open a profile channel, returns TRUE if it succeeds */{ GError *error = NULL; if (!g_file_test(path, G_FILE_TEST_IS_REGULAR) && g_file_test(path, G_FILE_TEST_EXISTS)) { g_warning("Failed to open %s profile '%s': Not a regular file", type, path); return FALSE; } channel = g_io_channel_new_file(path, profile_read_only ? "r" : "w", &error); if (!error) return TRUE; g_warning("Failed to open %s profile '%s' for %s: %s", type, path, profile_read_only ? "reading" : "writing", error->message); g_error_free(error); return FALSE;}static void create_user_dir(void)/* Make sure the user directory exists */{ char *path; path = g_build_filename(g_get_home_dir(), "." PACKAGE, NULL); if (g_mkdir_with_parents(path, 0755)) g_warning("Failed to create user directory '%s'", path); g_free(path);}static int profile_open_read(void)/* Open the profile file for reading. Returns TRUE if the profile was opened successfully. */{ char *path; profile_read_only = TRUE; /* Try opening a command-line specified profile first */ if (force_profile && profile_open_channel("command-line specified", force_profile)) return TRUE; /* Open user's profile */ path = g_build_filename(g_get_home_dir(), "." PACKAGE, "profile", NULL); if (profile_open_channel("user's", path)) { g_free(path); return TRUE; } g_free(path); /* Open system profile */ path = g_build_filename(PKGDATADIR, "profile", NULL); if (profile_open_channel("system", path)) { g_free(path); return TRUE; } g_free(path); return FALSE;}static int profile_open_write(void)/* Open a temporary profile file for writing. Returns TRUE if the profile was opened successfully. */{ GError *error; gint fd; if (force_read_only) { g_debug("Not saving profile, opened in read-only mode"); return FALSE; } profile_read_only = FALSE; /* Open a temporary file as a channel */ error = NULL; fd = g_file_open_tmp(PACKAGE ".XXXXXX", &profile_tmp, &error); if (error) { g_warning("Failed to open tmp file while saving " "profile: %s", error->message); return FALSE; } channel = g_io_channel_unix_new(fd); if (!channel) { g_warning("Failed to create channel from temporary file"); return FALSE; } return TRUE;}static int move_file(char *from, char *to)/* The standard library rename() cannot move across filesystems so we need a function that can emulate that. This function will copy a file, byte-by-byte but is not as safe as rename(). */{ GError *error = NULL; GIOChannel *src_channel, *dest_channel; gchar buffer[4096]; /* Open source file for reading */ src_channel = g_io_channel_new_file(from, "r", &error); if (error) { g_warning("move_file() failed to open src '%s': %s", from, error->message); return FALSE; } /* Open destination file for writing */ dest_channel = g_io_channel_new_file(to, "w", &error); if (error) { g_warning("move_file() failed to open dest '%s': %s", to, error->message); g_io_channel_unref(src_channel); return FALSE; } /* Copy data in blocks */ for (;;) { gsize bytes_read, bytes_written; /* Read a block in */ g_io_channel_read_chars(src_channel, buffer, sizeof (buffer), &bytes_read, &error); if (bytes_read < 1 || error) break; /* Write the block out */ g_io_channel_write_chars(dest_channel, buffer, bytes_read, &bytes_written, &error); if (bytes_written < bytes_read || error) { g_warning("move_file() error writing to '%s': %s", to, error->message); g_io_channel_unref(src_channel); g_io_channel_unref(dest_channel); return FALSE; } } /* Close channels */ g_io_channel_unref(src_channel); g_io_channel_unref(dest_channel); g_debug("move_file() copied '%s' to '%s'", from, to); /* Should be safe to delete the old file now */ if (remove(from)) log_errno("move_file() failed to delete src"); return TRUE;}static int profile_close(void)/* Close the currently open profile and, if we just wrote the profile to a temporary file, move it in place of the old profile */{ char *path = NULL; if (!channel) return FALSE; g_io_channel_unref(channel); if (!profile_tmp || profile_read_only) return TRUE; /* For some bizarre reason we may not have managed to create the temporary file */ if (!g_file_test(profile_tmp, G_FILE_TEST_EXISTS)) { g_warning("Tmp profile '%s' does not exist", profile_tmp); return FALSE; } /* Use command-line specified profile path first then the user's home directory profile */ path = force_profile; if (!path) path = g_build_filename(g_get_home_dir(), "." PACKAGE, "profile", NULL); if (g_file_test(path, G_FILE_TEST_EXISTS)) { g_message("Replacing '%s' with '%s'", path, profile_tmp); /* Don't write over non-regular files */ if (!g_file_test(path, G_FILE_TEST_IS_REGULAR)) { g_warning("Old profile '%s' is not a regular file", path); goto error_recovery; } /* Remove the old profile */ if (remove(path)) { log_errno("Failed to delete old profile"); goto error_recovery; } } else g_message("Creating new profile '%s'", path); /* Move the temporary profile file in place of the old one */ if (rename(profile_tmp, path)) { log_errno("rename() failed to move tmp profile in place"); if (!move_file(profile_tmp, path)) goto error_recovery; } if (path != force_profile) g_free(path); return TRUE;error_recovery: g_warning("Recover tmp profile at '%s'", profile_tmp); return FALSE;}const char *profile_read(void)/* Read a token from the open profile */{ GError *error = NULL; char *token; if (!channel) return ""; if (!profile_end) profile_end = profile_buf; *profile_end = profile_swap;seek_profile_end: /* Get the next token from the buffer */ for (; is_space(*profile_end); profile_end++);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -