📄 main.c
字号:
#include <config.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <gtk/gtk.h>#include <glib/gstdio.h>#include <demos.h>static GtkTextBuffer *info_buffer;static GtkTextBuffer *source_buffer;static gchar *current_file = NULL;enum { TITLE_COLUMN, FILENAME_COLUMN, FUNC_COLUMN, ITALIC_COLUMN, NUM_COLUMNS};typedef struct _CallbackData CallbackData;struct _CallbackData{ GtkTreeModel *model; GtkTreePath *path;};#ifdef G_OS_WIN32#undef DEMOCODEDIRstatic char *get_democodedir (void){ static char *result = NULL; if (result == NULL) { result = g_win32_get_package_installation_directory (NULL, NULL); if (result == NULL) result = "unknown-location"; result = g_strconcat (result, "\\share\\gtk-2.0\\demo", NULL); } return result;}#define DEMOCODEDIR get_democodedir ()#endif/** * demo_find_file: * @base: base filename * @err: location to store error, or %NULL. * * Looks for @base first in the current directory, then in the * location GTK+ where it will be installed on make install, * returns the first file found. * * Return value: the filename, if found or %NULL **/gchar *demo_find_file (const char *base, GError **err){ g_return_val_if_fail (err == NULL || *err == NULL, NULL); if (g_file_test ("gtk-logo-rgb.gif", G_FILE_TEST_EXISTS) && g_file_test (base, G_FILE_TEST_EXISTS)) return g_strdup (base); else { char *filename = g_build_filename (DEMOCODEDIR, base, NULL); if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_NOENT, "Cannot find demo data file \"%s\"", base); g_free (filename); return NULL; } return filename; }}static voidwindow_closed_cb (GtkWidget *window, gpointer data){ CallbackData *cbdata = data; GtkTreeIter iter; gboolean italic; gtk_tree_model_get_iter (cbdata->model, &iter, cbdata->path); gtk_tree_model_get (GTK_TREE_MODEL (cbdata->model), &iter, ITALIC_COLUMN, &italic, -1); if (italic) gtk_tree_store_set (GTK_TREE_STORE (cbdata->model), &iter, ITALIC_COLUMN, !italic, -1); gtk_tree_path_free (cbdata->path); g_free (cbdata);}gbooleanread_line (FILE *stream, GString *str){ int n_read = 0; #ifdef HAVE_FLOCKFILE flockfile (stream);#endif g_string_truncate (str, 0); while (1) { int c; #ifdef HAVE_FLOCKFILE c = getc_unlocked (stream);#else c = getc (stream);#endif if (c == EOF) goto done; else n_read++; switch (c) { case '\r': case '\n': {#ifdef HAVE_FLOCKFILE int next_c = getc_unlocked (stream);#else int next_c = getc (stream);#endif if (!(next_c == EOF || (c == '\r' && next_c == '\n') || (c == '\n' && next_c == '\r'))) ungetc (next_c, stream); goto done; } default: g_string_append_c (str, c); } } done:#ifdef HAVE_FLOCKFILE funlockfile (stream);#endif return n_read > 0;}/* Stupid syntax highlighting. * * No regex was used in the making of this highlighting. * It should only work for simple cases. This is good, as * that's all we should have in the demos. *//* This code should not be used elsewhere, except perhaps as an example of how * to iterate through a text buffer. */enum { STATE_NORMAL, STATE_IN_COMMENT};static gchar *tokens[] ={ "/*", "\"", NULL};static gchar *types[] ={ "static", "const ", "void", "gint", "int ", "char ", "gchar ", "gfloat", "float", "gint8", "gint16", "gint32", "guint", "guint8", "guint16", "guint32", "guchar", "glong", "gboolean" , "gshort", "gushort", "gulong", "gdouble", "gldouble", "gpointer", "NULL", "GList", "GSList", "FALSE", "TRUE", "FILE ", "GtkObject ", "GtkColorSelection ", "GtkWidget ", "GtkButton ", "GdkColor ", "GdkRectangle ", "GdkEventExpose ", "GdkGC ", "GdkPixbufLoader ", "GdkPixbuf ", "GError", "size_t", NULL};static gchar *control[] ={ " if ", " while ", " else", " do ", " for ", "?", ":", "return ", "goto ", NULL};voidparse_chars (gchar *text, gchar **end_ptr, gint *state, gchar **tag, gboolean start){ gint i; gchar *next_token; /* Handle comments first */ if (*state == STATE_IN_COMMENT) { *end_ptr = strstr (text, "*/"); if (*end_ptr) { *end_ptr += 2; *state = STATE_NORMAL; *tag = "comment"; } return; } *tag = NULL; *end_ptr = NULL; /* check for comment */ if (!strncmp (text, "/*", 2)) { *end_ptr = strstr (text, "*/"); if (*end_ptr) *end_ptr += 2; else *state = STATE_IN_COMMENT; *tag = "comment"; return; } /* check for preprocessor defines */ if (*text == '#' && start) { *end_ptr = NULL; *tag = "preprocessor"; return; } /* functions */ if (start && * text != '\t' && *text != ' ' && *text != '{' && *text != '}') { if (strstr (text, "(")) { *end_ptr = strstr (text, "("); *tag = "function"; return; } } /* check for types */ for (i = 0; types[i] != NULL; i++) if (!strncmp (text, types[i], strlen (types[i]))) { *end_ptr = text + strlen (types[i]); *tag = "type"; return; } /* check for control */ for (i = 0; control[i] != NULL; i++) if (!strncmp (text, control[i], strlen (control[i]))) { *end_ptr = text + strlen (control[i]); *tag = "control"; return; } /* check for string */ if (text[0] == '"') { gint maybe_escape = FALSE; *end_ptr = text + 1; *tag = "string"; while (**end_ptr != '\000') { if (**end_ptr == '\"' && !maybe_escape) { *end_ptr += 1; return; } if (**end_ptr == '\\') maybe_escape = TRUE; else maybe_escape = FALSE; *end_ptr += 1; } return; } /* not at the start of a tag. Find the next one. */ for (i = 0; tokens[i] != NULL; i++) { next_token = strstr (text, tokens[i]); if (next_token) { if (*end_ptr) *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token; else *end_ptr = next_token; } } for (i = 0; types[i] != NULL; i++) { next_token = strstr (text, types[i]); if (next_token) { if (*end_ptr) *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token; else *end_ptr = next_token; } } for (i = 0; control[i] != NULL; i++) { next_token = strstr (text, control[i]); if (next_token) { if (*end_ptr) *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token; else *end_ptr = next_token; } }}/* While not as cool as c-mode, this will do as a quick attempt at highlighting */static voidfontify (void){ GtkTextIter start_iter, next_iter, tmp_iter; gint state; gchar *text; gchar *start_ptr, *end_ptr; gchar *tag; state = STATE_NORMAL; gtk_text_buffer_get_iter_at_offset (source_buffer, &start_iter, 0); next_iter = start_iter; while (gtk_text_iter_forward_line (&next_iter)) { gboolean start = TRUE; start_ptr = text = gtk_text_iter_get_text (&start_iter, &next_iter); do { parse_chars (start_ptr, &end_ptr, &state, &tag, start); start = FALSE; if (end_ptr) { tmp_iter = start_iter; gtk_text_iter_forward_chars (&tmp_iter, end_ptr - start_ptr); } else { tmp_iter = next_iter; } if (tag) gtk_text_buffer_apply_tag_by_name (source_buffer, tag, &start_iter, &tmp_iter); start_iter = tmp_iter; start_ptr = end_ptr; } while (end_ptr); g_free (text); start_iter = next_iter; }}voidload_file (const gchar *filename){ FILE *file; GtkTextIter start, end; char *full_filename; GError *err = NULL; GString *buffer = g_string_new (NULL); int state = 0; gboolean in_para = 0; if (current_file && !strcmp (current_file, filename)) { g_string_free (buffer, TRUE); return; } g_free (current_file); current_file = g_strdup (filename); gtk_text_buffer_get_bounds (info_buffer, &start, &end);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -