File kanjipad-2.0.0-gtk3.patch of Package kanjipad
diff -urN kanjipad-2.0.0/kanjipad.c kanjipad-2.0.0.gtk3/kanjipad.c
--- kanjipad-2.0.0/kanjipad.c 2002-08-26 03:00:54.000000000 +0800
+++ kanjipad-2.0.0.gtk3/kanjipad.c 2026-02-15 11:04:35.868409625 +0800
@@ -1,6 +1,8 @@
/* KanjiPad - Japanese handwriting recognition front end
* Copyright (C) 1997 Owen Taylor
*
+ * Ported to GTK+ 3
+ *
* 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
@@ -23,23 +25,27 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <glib/gstdio.h>
+#include <math.h>
#include "kanjipad.h"
+#ifndef BINDIR
+#define BINDIR "/usr/local/bin"
+#endif
+
typedef struct {
gchar d[2];
} kp_wchar;
#define WCHAR_EQ(a,b) (a.d[0] == b.d[0] && a.d[1] == b.d[1])
-/* Wait for child process? */
-
/* user interface elements */
-static GdkPixmap *kpixmap;
+static cairo_surface_t *ksurface = NULL;
GtkWidget *karea;
GtkWidget *clear_button;
GtkWidget *lookup_button;
-GtkItemFactory *factory;
+GtkWidget *main_window;
#define MAX_GUESSES 10
kp_wchar kanjiguess[MAX_GUESSES];
@@ -56,38 +62,29 @@
static char *data_file = NULL;
static char *progname;
-static void exit_callback ();
-static void copy_callback ();
-static void save_callback ();
-static void clear_callback ();
-static void look_up_callback ();
-static void annotate_callback ();
+static GActionGroup *action_group = NULL;
-static void update_sensitivity ();
+/* Function declarations */
+static void exit_activated (GSimpleAction *action, GVariant *parameter, gpointer data);
+static void copy_activated (GSimpleAction *action, GVariant *parameter, gpointer data);
+static void save_activated (GSimpleAction *action, GVariant *parameter, gpointer data);
+static void clear_activated (GSimpleAction *action, GVariant *parameter, gpointer data);
+static void look_up_activated (GSimpleAction *action, GVariant *parameter, gpointer data);
+static void annotate_activated (GSimpleAction *action, GVariant *parameter, gpointer data);
+static void update_sensitivity (void);
+static void karea_draw (GtkWidget *w);
-static GtkItemFactoryEntry menu_items[] =
+/* Pad area changed callback - called from pad_area.c */
+void
+pad_area_changed_callback (PadArea *area)
{
- { "/_File", NULL, NULL, 0, "<Branch>" },
- { "/File/_Quit", NULL, exit_callback, 0, "<StockItem>", GTK_STOCK_QUIT },
-
- { "/_Edit", NULL, NULL, 0, "<Branch>" },
- { "/Edit/_Copy", NULL, copy_callback, 0, "<StockItem>", GTK_STOCK_COPY },
-
- { "/_Character", NULL, NULL, 0, "<Branch>" },
- { "/Character/_Lookup", "<control>L", look_up_callback },
- { "/Character/_Clear", "<control>X", clear_callback },
- { "/Character/_Save", "<control>S", save_callback },
- { "/Character/sep1", NULL, NULL, 0, "<Separator>" },
-
- { "/Character/_Annotate", NULL, annotate_callback, 0, "<CheckItem>" },
-};
-
-static int nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
+ update_sensitivity ();
+}
static void
karea_get_char_size (GtkWidget *widget,
- int *width,
- int *height)
+ int *width,
+ int *height)
{
PangoLayout *layout = gtk_widget_create_pango_layout (widget, "\xe6\xb6\x88");
pango_layout_get_pixel_size (layout, width, height);
@@ -110,7 +107,7 @@
if (!string_utf)
{
g_printerr ("Cannot convert string from EUC-JP to UTF-8: %s\n",
- err->message);
+ err->message);
exit (1);
}
@@ -119,88 +116,123 @@
static void
karea_draw_character (GtkWidget *w,
- int index,
- int selected)
+ int index,
+ int selected)
{
+ cairo_t *cr;
PangoLayout *layout;
gchar *string_utf;
gint char_width, char_height;
- gint x;
+ gint x, y;
+ GtkStyleContext *context = gtk_widget_get_style_context (w);
+ GtkAllocation allocation;
+ gtk_widget_get_allocation (w, &allocation);
karea_get_char_size (w, &char_width, &char_height);
+ if (!ksurface)
+ return;
+
+ cr = cairo_create (ksurface);
+
+ y = (char_height + 6) * index;
+
if (selected >= 0)
{
- gdk_draw_rectangle (kpixmap,
- selected ? w->style->bg_gc[GTK_STATE_SELECTED] :
- w->style->white_gc,
- TRUE,
- 0, (char_height + 6) *index, w->allocation.width - 1, char_height + 5);
+ if (selected)
+ {
+ /* Selected state - use theme color */
+ gtk_style_context_save (context);
+ gtk_style_context_set_state (context, GTK_STATE_FLAG_SELECTED);
+ gtk_render_background (context, cr, 0, y,
+ allocation.width - 1,
+ char_height + 5);
+ gtk_style_context_restore (context);
+ }
+ else
+ {
+ /* Unselected - white background */
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_rectangle (cr, 0, y,
+ allocation.width - 1,
+ char_height + 5);
+ cairo_fill (cr);
+ }
}
string_utf = utf8_for_char (kanjiguess[index]);
layout = gtk_widget_create_pango_layout (w, string_utf);
g_free (string_utf);
- x = (w->allocation.width - char_width) / 2;
+ x = (allocation.width - char_width) / 2;
+
+ if (selected > 0)
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ else
+ cairo_set_source_rgb (cr, 0, 0, 0);
+
+ cairo_move_to (cr, x, y + 3);
+ pango_cairo_show_layout (cr, layout);
- gdk_draw_layout (kpixmap,
- (selected > 0) ? w->style->white_gc :
- w->style->black_gc,
- x, (char_height + 6) * index + 3, layout);
g_object_unref (layout);
+ cairo_destroy (cr);
}
-
static void
karea_draw (GtkWidget *w)
{
- gint width = w->allocation.width;
- gint height = w->allocation.height;
+ GtkAllocation allocation;
int i;
- gdk_draw_rectangle (kpixmap,
- w->style->white_gc, TRUE,
- 0, 0, width, height);
+ if (!ksurface)
+ return;
+
+ gtk_widget_get_allocation (w, &allocation);
+
+ cairo_t *cr = cairo_create (ksurface);
+ /* Clear with white background */
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
+ cairo_fill (cr);
+
+ cairo_destroy (cr);
- for (i=0; i<num_guesses; i++)
+ /* Draw all guess characters */
+ for (i = 0; i < num_guesses; i++)
{
if (WCHAR_EQ (kselected, kanjiguess[i]))
- karea_draw_character (w, i, 1);
+ karea_draw_character (w, i, 1);
else
- karea_draw_character (w, i, -1);
+ karea_draw_character (w, i, -1);
}
gtk_widget_queue_draw (w);
}
-static int
-karea_configure_event (GtkWidget *w, GdkEventConfigure *event)
+static gboolean
+karea_draw_cb (GtkWidget *w, cairo_t *cr, gpointer data)
{
- if (kpixmap)
- g_object_unref (kpixmap);
-
- kpixmap = gdk_pixmap_new (w->window, event->width, event->height, -1);
-
- karea_draw (w);
+ if (ksurface)
+ {
+ cairo_set_source_surface (cr, ksurface, 0, 0);
+ cairo_paint (cr);
+ }
- return TRUE;
+ return FALSE;
}
-static int
-karea_expose_event (GtkWidget *w, GdkEventExpose *event)
+static void
+karea_resize_cb (GtkWidget *w, GtkAllocation *allocation, gpointer data)
{
- if (!kpixmap)
- return 0;
+ if (ksurface)
+ cairo_surface_destroy (ksurface);
- gdk_draw_drawable (w->window,
- w->style->fg_gc[GTK_STATE_NORMAL], kpixmap,
- event->area.x, event->area.y,
- event->area.x, event->area.y,
- event->area.width, event->area.height);
-
- return 0;
+ ksurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ allocation->width,
+ allocation->height);
+
+ karea_draw (w);
}
static int
@@ -209,20 +241,20 @@
int i;
if (kselected.d[0] || kselected.d[1])
{
- for (i=0; i<num_guesses; i++)
- {
- if (WCHAR_EQ (kselected, kanjiguess[i]))
- {
- karea_draw_character (w, i, 0);
- }
- }
+ for (i = 0; i < num_guesses; i++)
+ {
+ if (WCHAR_EQ (kselected, kanjiguess[i]))
+ {
+ karea_draw_character (w, i, 0);
+ }
+ }
}
return TRUE;
}
static void
karea_primary_clear (GtkClipboard *clipboard,
- gpointer owner)
+ gpointer owner)
{
GtkWidget *w = owner;
@@ -235,9 +267,9 @@
static void
karea_primary_get (GtkClipboard *clipboard,
- GtkSelectionData *selection_data,
- guint info,
- gpointer owner)
+ GtkSelectionData *selection_data,
+ guint info,
+ gpointer owner)
{
if (kselected.d[0] || kselected.d[1])
{
@@ -247,12 +279,13 @@
}
}
-static int
-karea_button_press_event (GtkWidget *w, GdkEventButton *event)
+static gboolean
+karea_button_press_cb (GtkWidget *w, GdkEventButton *event, gpointer data)
{
int j;
gint char_height;
GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
+ GtkAllocation allocation;
static const GtkTargetEntry targets[] = {
{ "STRING", 0, 0 },
@@ -261,6 +294,7 @@
{ "UTF8_STRING", 0, 0 }
};
+ gtk_widget_get_allocation (w, &allocation);
karea_erase_selection (w);
karea_get_char_size (w, NULL, &char_height);
@@ -272,15 +306,15 @@
karea_draw_character (w, j, 1);
if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
- karea_primary_get, karea_primary_clear, G_OBJECT (w)))
- karea_primary_clear (clipboard, w);
+ karea_primary_get, karea_primary_clear, G_OBJECT (w)))
+ karea_primary_clear (clipboard, w);
}
else
{
kselected.d[0] = 0;
kselected.d[1] = 0;
if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (w))
- gtk_clipboard_clear (clipboard);
+ gtk_clipboard_clear (clipboard);
}
update_sensitivity ();
@@ -289,14 +323,16 @@
return TRUE;
}
-static void
-exit_callback (GtkWidget *w)
+/* Action callbacks */
+
+static void
+exit_activated (GSimpleAction *action, GVariant *parameter, gpointer data)
{
exit (0);
}
-static void
-copy_callback (GtkWidget *w)
+static void
+copy_activated (GSimpleAction *action, GVariant *parameter, gpointer data)
{
if (kselected.d[0] || kselected.d[1])
{
@@ -306,10 +342,9 @@
}
}
-static void
-look_up_callback (GtkWidget *w)
+static void
+look_up_activated (GSimpleAction *action, GVariant *parameter, gpointer data)
{
- /* kill 'HUP',$engine_pid; */
GList *tmp_list;
GString *message = g_string_new (NULL);
GError *err = NULL;
@@ -317,44 +352,45 @@
tmp_list = pad_area->strokes;
while (tmp_list)
{
- GList *stroke_list = tmp_list->data;
- while (stroke_list)
- {
- gint16 x = ((GdkPoint *)stroke_list->data)->x;
- gint16 y = ((GdkPoint *)stroke_list->data)->y;
- g_string_append_printf (message, "%d %d ", x, y);
- stroke_list = stroke_list->next;
- }
- g_string_append (message, "\n");
- tmp_list = tmp_list->next;
+ GList *stroke_list = tmp_list->data;
+ while (stroke_list)
+ {
+ gint16 x = ((GdkPoint *)stroke_list->data)->x;
+ gint16 y = ((GdkPoint *)stroke_list->data)->y;
+ g_string_append_printf (message, "%d %d ", x, y);
+ stroke_list = stroke_list->next;
+ }
+ g_string_append (message, "\n");
+ tmp_list = tmp_list->next;
}
g_string_append (message, "\n");
+
if (g_io_channel_write_chars (to_engine,
- message->str, message->len,
- NULL, &err) != G_IO_STATUS_NORMAL)
+ message->str, message->len,
+ NULL, &err) != G_IO_STATUS_NORMAL)
{
g_printerr ("Cannot write message to engine: %s\n",
- err->message);
+ err->message);
exit (1);
}
if (g_io_channel_flush (to_engine, &err) != G_IO_STATUS_NORMAL)
{
g_printerr ("Error flushing message to engine: %s\n",
- err->message);
+ err->message);
exit (1);
}
- g_string_free (message, FALSE);
+ g_string_free (message, TRUE);
}
-static void
-clear_callback (GtkWidget *w)
+static void
+clear_activated (GSimpleAction *action, GVariant *parameter, gpointer data)
{
pad_area_clear (pad_area);
}
-static void
-save_callback (GtkWidget *w)
+static void
+save_activated (GSimpleAction *action, GVariant *parameter, gpointer data)
{
static int unknownID = 0;
static FILE *samples = NULL;
@@ -366,21 +402,21 @@
if (!samples)
{
if (!(samples = fopen("samples.dat", "a")))
- g_error ("Can't open 'samples.dat': %s", g_strerror(errno));
+ g_error ("Can't open 'samples.dat': %s", g_strerror(errno));
}
if (kselected.d[0] || kselected.d[1])
{
- for (i=0; i<num_guesses; i++)
- {
- if (WCHAR_EQ (kselected, kanjiguess[i]))
- found = TRUE;
- }
+ for (i = 0; i < num_guesses; i++)
+ {
+ if (WCHAR_EQ (kselected, kanjiguess[i]))
+ found = TRUE;
+ }
}
if (found)
- fprintf(samples,"%2x%2x %c%c\n", kselected.d[0], kselected.d[1],
- 0x80 | kselected.d[0], 0x80 | kselected.d[1]);
+ fprintf(samples, "%2x%2x %c%c\n", kselected.d[0], kselected.d[1],
+ 0x80 | kselected.d[0], 0x80 | kselected.d[1]);
else
{
fprintf (samples, "0000 ??%d\n", unknownID);
@@ -391,53 +427,58 @@
tmp_list = pad_area->strokes;
while (tmp_list)
{
- GList *stroke_list = tmp_list->data;
- while (stroke_list)
- {
- gint16 x = ((GdkPoint *)stroke_list->data)->x;
- gint16 y = ((GdkPoint *)stroke_list->data)->y;
- fprintf(samples, "%d %d ", x, y);
- stroke_list = stroke_list->next;
- }
- fprintf(samples, "\n");
- tmp_list = tmp_list->next;
+ GList *stroke_list = tmp_list->data;
+ while (stroke_list)
+ {
+ gint16 x = ((GdkPoint *)stroke_list->data)->x;
+ gint16 y = ((GdkPoint *)stroke_list->data)->y;
+ fprintf(samples, "%d %d ", x, y);
+ stroke_list = stroke_list->next;
+ }
+ fprintf(samples, "\n");
+ tmp_list = tmp_list->next;
}
fprintf(samples, "\n");
fflush(samples);
}
static void
-annotate_callback ()
-{
- pad_area_set_annotate (pad_area, !pad_area->annotate);
-}
-
-void
-pad_area_changed_callback (PadArea *area)
-{
- update_sensitivity ();
-}
-
-static void
-update_path_sensitive (const gchar *path,
- gboolean sensitive)
+annotate_activated (GSimpleAction *action, GVariant *parameter, gpointer data)
{
- GtkWidget *widget = gtk_item_factory_get_widget (factory, path);
- gtk_widget_set_sensitive (widget, sensitive);
+ gboolean state = g_variant_get_boolean (parameter);
+ g_simple_action_set_state (action, parameter);
+ pad_area_set_annotate (pad_area, state);
}
static void
-update_sensitivity ()
+update_sensitivity (void)
{
gboolean have_selected = (kselected.d[0] || kselected.d[1]);
gboolean have_strokes = (pad_area->strokes != NULL);
- update_path_sensitive ("/Edit/Copy", have_selected);
- update_path_sensitive ("/Character/Lookup", have_strokes);
- gtk_widget_set_sensitive (lookup_button, have_strokes);
- update_path_sensitive ("/Character/Clear", have_strokes);
- gtk_widget_set_sensitive (clear_button, have_strokes);
- update_path_sensitive ("/Character/Save", have_strokes);
+ GAction *action;
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (main_window), "copy");
+ if (action)
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), have_selected);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (main_window), "lookup");
+ if (action)
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), have_strokes);
+
+ if (lookup_button)
+ gtk_widget_set_sensitive (lookup_button, have_strokes);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (main_window), "clear");
+ if (action)
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), have_strokes);
+
+ if (clear_button)
+ gtk_widget_set_sensitive (clear_button, have_strokes);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (main_window), "save");
+ if (action)
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), have_strokes);
}
#define BUFLEN 256
@@ -445,8 +486,7 @@
static gboolean
engine_input_handler (GIOChannel *source, GIOCondition condition, gpointer data)
{
- static gchar *p;
- static gchar *line;
+ gchar *line = NULL;
GError *err = NULL;
GIOStatus status;
int i;
@@ -465,28 +505,27 @@
exit (1);
break;
case G_IO_STATUS_AGAIN:
- g_assert_not_reached ();
- break;
+ return TRUE;
}
- if (line[0] == 'K')
+ if (line && line[0] == 'K')
{
unsigned int t1, t2;
- p = line+1;
- for (i=0; i<MAX_GUESSES; i++)
- {
- while (*p && isspace(*p)) p++;
- if (!*p || sscanf(p, "%2x%2x", &t1, &t2) != 2)
- {
- i--;
- break;
- }
- kanjiguess[i].d[0] = t1;
- kanjiguess[i].d[1] = t2;
- while (*p && !isspace(*p)) p++;
- }
- num_guesses = i+1;
- karea_draw(karea);
+ gchar *p = line + 1;
+
+ for (i = 0; i < MAX_GUESSES; i++)
+ {
+ while (*p && isspace(*p)) p++;
+ if (!*p || sscanf(p, "%2x%2x", &t1, &t2) != 2)
+ {
+ break;
+ }
+ kanjiguess[i].d[0] = t1;
+ kanjiguess[i].d[1] = t2;
+ while (*p && !isspace(*p)) p++;
+ }
+ num_guesses = i;
+ karea_draw (karea);
}
g_free (line);
@@ -496,7 +535,7 @@
/* Open the connection to the engine */
static void
-init_engine()
+init_engine(void)
{
gchar *argv[] = { BINDIR G_DIR_SEPARATOR_S "kpengine", "--data-file", NULL, NULL };
GError *err = NULL;
@@ -513,21 +552,23 @@
argv[1] = NULL;
if (!g_spawn_async_with_pipes (NULL, /* working directory */
- argv, NULL, /* argv, envp */
- 0,
- NULL, NULL, /* child_setup */
- &engine_pid, /* child pid */
- &stdin_fd, &stdout_fd, NULL,
- &err))
+ argv, NULL, /* argv, envp */
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL, NULL, /* child_setup */
+ &engine_pid, /* child pid */
+ &stdin_fd, &stdout_fd, NULL,
+ &err))
{
GtkWidget *dialog;
- dialog = gtk_message_dialog_new (NULL, 0,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK,
- "Could not start engine '%s': %s",
- argv[0], err->message);
+ dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "Could not start engine '%s': %s",
+ argv[0], err->message);
gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
g_error_free (err);
exit (1);
}
@@ -539,170 +580,244 @@
if (!(from_engine = g_io_channel_unix_new (stdout_fd)))
g_error ("Couldn't create pipe from child process: %s", g_strerror(errno));
+ /* Set encoding to binary to avoid conversion issues */
+ if (to_engine)
+ g_io_channel_set_encoding (to_engine, NULL, NULL);
+ if (from_engine)
+ g_io_channel_set_encoding (from_engine, NULL, NULL);
+
g_io_add_watch (from_engine, G_IO_IN, engine_input_handler, NULL);
}
+static void
+setup_actions (void)
+{
+ static const GActionEntry actions[] = {
+ { "quit", exit_activated, NULL, NULL, NULL },
+ { "copy", copy_activated, NULL, NULL, NULL },
+ { "lookup", look_up_activated, NULL, NULL, NULL },
+ { "clear", clear_activated, NULL, NULL, NULL },
+ { "save", save_activated, NULL, NULL, NULL },
+ { "annotate", NULL, NULL, "false", annotate_activated }
+ };
+
+ g_action_map_add_action_entries (G_ACTION_MAP (main_window),
+ actions, G_N_ELEMENTS (actions),
+ NULL);
+}
+
+static void
+setup_menu (void)
+{
+ GMenu *menu, *file_menu, *edit_menu, *char_menu;
+ GMenuItem *menu_item;
+
+ menu = g_menu_new ();
+ /* File menu */
+ file_menu = g_menu_new ();
+ menu_item = g_menu_item_new ("Quit", "win.quit");
+ g_menu_append_item (file_menu, menu_item);
+ g_object_unref (menu_item);
+
+ menu_item = g_menu_item_new_submenu ("_File", G_MENU_MODEL (file_menu));
+ g_menu_append_item (menu, menu_item);
+ g_object_unref (menu_item);
+ g_object_unref (file_menu);
+
+ /* Edit menu */
+ edit_menu = g_menu_new ();
+ menu_item = g_menu_item_new ("_Copy", "win.copy");
+ g_menu_append_item (edit_menu, menu_item);
+ g_object_unref (menu_item);
+
+ menu_item = g_menu_item_new_submenu ("_Edit", G_MENU_MODEL (edit_menu));
+ g_menu_append_item (menu, menu_item);
+ g_object_unref (menu_item);
+ g_object_unref (edit_menu);
+
+ /* Character menu */
+ char_menu = g_menu_new ();
+ menu_item = g_menu_item_new ("_Lookup", "win.lookup");
+ g_menu_append_item (char_menu, menu_item);
+ g_object_unref (menu_item);
+
+ menu_item = g_menu_item_new ("_Clear", "win.clear");
+ g_menu_append_item (char_menu, menu_item);
+ g_object_unref (menu_item);
+
+ menu_item = g_menu_item_new ("_Save", "win.save");
+ g_menu_append_item (char_menu, menu_item);
+ g_object_unref (menu_item);
+
+ menu_item = g_menu_item_new (NULL, NULL);
+ g_menu_item_set_attribute (menu_item, "section", "s", "sep");
+ g_menu_append_item (char_menu, menu_item);
+ g_object_unref (menu_item);
+
+ menu_item = g_menu_item_new ("_Annotate", "win.annotate");
+ g_menu_append_item (char_menu, menu_item);
+ g_object_unref (menu_item);
+
+ menu_item = g_menu_item_new_submenu ("_Character", G_MENU_MODEL (char_menu));
+ g_menu_append_item (menu, menu_item);
+ g_object_unref (menu_item);
+ g_object_unref (char_menu);
+
+ gtk_application_set_menubar (GTK_APPLICATION (g_application_get_default ()),
+ G_MENU_MODEL (menu));
+ g_object_unref (menu);
+}
+
/* Create Interface */
-void
-usage ()
+static void
+usage (void)
{
fprintf(stderr, "Usage: %s [-f/--data-file FILE]\n", progname);
exit (1);
}
-int
-main (int argc, char **argv)
+static void
+activate_cb (GtkApplication *app, gpointer user_data)
{
- GtkWidget *window;
GtkWidget *main_hbox;
GtkWidget *vseparator;
GtkWidget *button;
GtkWidget *main_vbox;
- GtkWidget *menubar;
GtkWidget *vbox;
GtkWidget *label;
+ GtkWidget *header;
+ GtkStyleContext *context;
- GtkAccelGroup *accel_group;
-
PangoFontDescription *font_desc;
- int i;
- char *p;
-
- p = progname = argv[0];
- while (*p)
- {
- if (*p == '/') progname = p+1;
- p++;
- }
-
- gtk_init (&argc, &argv);
-
- for (i=1; i<argc; i++)
- {
- if (!strcmp(argv[i], "--data-file") ||
- !strcmp(argv[i], "-f"))
- {
- i++;
- if (i < argc)
- data_file = argv[i];
- else
- usage();
- }
- else
- {
- usage();
- }
- }
-
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
- gtk_window_set_default_size (GTK_WINDOW (window), 350, 350);
-
- g_signal_connect (window, "destroy",
- G_CALLBACK (exit_callback), NULL);
-
- gtk_window_set_title (GTK_WINDOW(window), "KanjiPad");
- main_vbox = gtk_vbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (window), main_vbox);
- gtk_widget_show (main_vbox);
-
- /* Menu */
-
- accel_group = gtk_accel_group_new ();
- factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", accel_group);
- gtk_item_factory_create_items (factory, nmenu_items, menu_items, NULL);
-
- /* create a menubar */
- menubar = gtk_item_factory_get_widget (factory, "<main>");
- gtk_box_pack_start (GTK_BOX (main_vbox), menubar,
- FALSE, TRUE, 0);
- gtk_widget_show (menubar);
-
- /* Install the accelerator table in the main window */
- gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
-
- main_hbox = gtk_hbox_new (FALSE, 0);
- gtk_box_pack_start (GTK_BOX(main_vbox), main_hbox, TRUE, TRUE, 0);
- gtk_widget_show (main_hbox);
+ main_window = gtk_application_window_new (app);
+ gtk_window_set_title (GTK_WINDOW (main_window), "KanjiPad");
+ gtk_window_set_default_size (GTK_WINDOW (main_window), 350, 350);
+
+ /* Set up actions */
+ setup_actions ();
+
+ /* Create header bar */
+ header = gtk_header_bar_new ();
+ gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (header), TRUE);
+ gtk_header_bar_set_title (GTK_HEADER_BAR (header), "KanjiPad");
+ gtk_window_set_titlebar (GTK_WINDOW (main_window), header);
+
+ main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_container_add (GTK_CONTAINER (main_window), main_vbox);
+
+ main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 0);
/* Area for user to draw characters in */
-
pad_area = pad_area_create ();
-
gtk_box_pack_start (GTK_BOX (main_hbox), pad_area->widget, TRUE, TRUE, 0);
- gtk_widget_show (pad_area->widget);
- vseparator = gtk_vseparator_new();
+ vseparator = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
gtk_box_pack_start (GTK_BOX (main_hbox), vseparator, FALSE, FALSE, 0);
- gtk_widget_show (vseparator);
/* Area in which to draw guesses */
-
- vbox = gtk_vbox_new (FALSE, 0);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start (GTK_BOX (main_hbox), vbox, FALSE, FALSE, 0);
- gtk_widget_show (vbox);
- karea = gtk_drawing_area_new();
+ karea = gtk_drawing_area_new ();
+
+ g_signal_connect (karea, "draw",
+ G_CALLBACK (karea_draw_cb), NULL);
+ g_signal_connect (karea, "size-allocate",
+ G_CALLBACK (karea_resize_cb), NULL);
+ g_signal_connect (karea, "button-press-event",
+ G_CALLBACK (karea_button_press_cb), NULL);
+
+ gtk_widget_set_events (karea, GDK_BUTTON_PRESS_MASK);
- g_signal_connect (karea, "configure_event",
- G_CALLBACK (karea_configure_event), NULL);
- g_signal_connect (karea, "expose_event",
- G_CALLBACK (karea_expose_event), NULL);
- g_signal_connect (karea, "button_press_event",
- G_CALLBACK (karea_button_press_event), NULL);
-
- gtk_widget_set_events (karea, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
-
-#ifdef G_OS_WIN32
- font_desc = pango_font_description_from_string ("MS Gothic 18");
-#else
font_desc = pango_font_description_from_string ("Sans 18");
-#endif
- gtk_widget_modify_font (karea, font_desc);
+ gtk_widget_override_font (karea, font_desc);
+ pango_font_description_free (font_desc);
gtk_box_pack_start (GTK_BOX (vbox), karea, TRUE, TRUE, 0);
- gtk_widget_show (karea);
/* Buttons */
- label = gtk_label_new ("\xe5\xbc\x95");
- /* We have to set the alignment here, since GTK+ will fail
- * to get the width of the string appropriately...
- */
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_widget_modify_font (label, font_desc);
- gtk_widget_show (label);
+ context = gtk_widget_get_style_context (karea);
+ font_desc = pango_font_description_copy (gtk_style_context_get_font (context, GTK_STATE_FLAG_NORMAL));
+
+ label = gtk_label_new ("\xe5\xbc\x95"); /* "引" - Lookup */
+ gtk_widget_set_halign (label, GTK_ALIGN_START);
+ gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
+ gtk_widget_override_font (label, font_desc);
lookup_button = button = gtk_button_new ();
gtk_container_add (GTK_CONTAINER (button), label);
- g_signal_connect (button, "clicked",
- G_CALLBACK (look_up_callback), NULL);
+ g_signal_connect_swapped (button, "clicked",
+ G_CALLBACK (look_up_activated), NULL);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
- gtk_widget_show (button);
- label = gtk_label_new ("\xe6\xb6\x88");
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_widget_modify_font (label, font_desc);
- gtk_widget_show (label);
-
+ label = gtk_label_new ("\xe6\xb6\x88"); /* "消" - Clear */
+ gtk_widget_set_halign (label, GTK_ALIGN_START);
+ gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
+ gtk_widget_override_font (label, font_desc);
+
clear_button = button = gtk_button_new ();
gtk_container_add (GTK_CONTAINER (button), label);
- g_signal_connect (button, "clicked",
- G_CALLBACK (clear_callback), NULL);
+ g_signal_connect_swapped (button, "clicked",
+ G_CALLBACK (clear_activated), NULL);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
- gtk_widget_show (button);
-
- gtk_widget_show(window);
pango_font_description_free (font_desc);
+ /* Set initial sensitivity */
+ update_sensitivity ();
+
+ /* Set up menu */
+ setup_menu ();
+
+ gtk_widget_show_all (main_window);
+
+ /* Initialize engine after UI is created */
init_engine();
+}
+
+int
+main (int argc, char **argv)
+{
+ GtkApplication *app;
+ int status;
+ int i;
+ char *p;
+
+ p = progname = argv[0];
+ while (*p)
+ {
+ if (*p == '/') progname = p+1;
+ p++;
+ }
- gtk_main();
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp(argv[i], "--data-file") ||
+ !strcmp(argv[i], "-f"))
+ {
+ i++;
+ if (i < argc)
+ data_file = argv[i];
+ else
+ usage();
+ }
+ else
+ {
+ usage();
+ }
+ }
+
+ app = gtk_application_new ("org.gtk.kanjipad", G_APPLICATION_FLAGS_NONE);
+ g_signal_connect (app, "activate", G_CALLBACK (activate_cb), NULL);
+
+ status = g_application_run (G_APPLICATION (app), argc, argv);
+ g_object_unref (app);
- return 0;
+ return status;
}
diff -urN kanjipad-2.0.0/kanjipad.h kanjipad-2.0.0.gtk3/kanjipad.h
--- kanjipad-2.0.0/kanjipad.h 2002-03-16 08:09:45.000000000 +0800
+++ kanjipad-2.0.0.gtk3/kanjipad.h 2026-02-15 10:52:40.886573429 +0800
@@ -1,21 +1,22 @@
+#ifndef KANJIPAD_H
+#define KANJIPAD_H
+
#include <gtk/gtk.h>
typedef struct _PadArea PadArea;
struct _PadArea {
GtkWidget *widget;
-
- gint annotate;
- GList *strokes;
-
- /* Private */
- GdkPixmap *pixmap;
- GList *curstroke;
- int instroke;
+ GList *strokes; /* List of strokes (each stroke is a GList of GdkPoint) */
+ GList *curstroke; /* Current stroke being drawn */
+ gboolean instroke; /* Whether we're currently drawing a stroke */
+ gboolean annotate; /* Whether to show stroke numbers */
+ cairo_surface_t *surface; /* Backing surface for drawing */
};
-PadArea *pad_area_create ();
+PadArea *pad_area_create (void);
void pad_area_clear (PadArea *area);
-void pad_area_set_annotate (PadArea *area, gint annotate);
-
+void pad_area_set_annotate (PadArea *area, gboolean annotate);
void pad_area_changed_callback (PadArea *area);
+
+#endif
diff -urN kanjipad-2.0.0/Makefile kanjipad-2.0.0.gtk3/Makefile
--- kanjipad-2.0.0/Makefile 2026-02-15 11:09:55.169998892 +0800
+++ kanjipad-2.0.0.gtk3/Makefile 2026-02-15 10:50:55.828211226 +0800
@@ -1,8 +1,8 @@
OPTIMIZE=-g -Wall
#OPTIMIZE=-O2
-GTKINC=$(shell pkg-config --cflags gtk+-2.0) -DG_DISABLE_DEPRECATED
-GTKLIBS=$(shell pkg-config --libs gtk+-2.0)
+GTKINC=$(shell pkg-config --cflags gtk+-3.0) -DG_DISABLE_DEPRECATED
+GTKLIBS=$(shell pkg-config --libs gtk+-3.0)
GLIBLIBS=$(shell pkg-config --libs glib-2.0)
PREFIX=/usr/local
diff -urN kanjipad-2.0.0/padarea.c kanjipad-2.0.0.gtk3/padarea.c
--- kanjipad-2.0.0/padarea.c 2002-03-16 08:09:45.000000000 +0800
+++ kanjipad-2.0.0.gtk3/padarea.c 2026-02-15 11:06:58.735633667 +0800
@@ -3,6 +3,8 @@
#include <stdio.h>
#include <stdlib.h>
+extern void pad_area_changed_callback (PadArea *area);
+
static void
pad_area_free_stroke (GList *stroke)
{
@@ -15,147 +17,211 @@
g_list_free (stroke);
}
-
static void
-pad_area_annotate_stroke (PadArea *area, GList *stroke, gint index)
+pad_area_draw_stroke_number (PadArea *area, GList *stroke, gint index, cairo_t *cr)
{
GdkPoint *cur, *old;
+ GList *iter;
+ int num_points = g_list_length (stroke);
+
+ /* Need at least 2 points to calculate direction */
+ if (num_points < 2)
+ return;
+
+ /* Get first point */
+ iter = stroke;
+ old = (GdkPoint *)iter->data;
+
+ /* Find a point that's far enough from the first to get a direction */
+ iter = iter->next;
+ while (iter)
+ {
+ cur = (GdkPoint *)iter->data;
+ if (abs(cur->x - old->x) >= 5 || abs(cur->y - old->y) >= 5)
+ break;
+ iter = iter->next;
+ }
+
+ if (iter && cur)
+ {
+ char buffer[16];
+ PangoLayout *layout;
+ int swidth, sheight;
+ double x, y;
+ double r;
+ double dx = cur->x - old->x;
+ double dy = cur->y - old->y;
+ double dl = sqrt(dx*dx + dy*dy);
+ int sign = (dy <= dx) ? 1 : -1;
+ GtkAllocation allocation;
- /* Annotate the stroke with the stroke number - the algorithm
- * for placing the digit is pretty simple. The text is inscribed
- * in a circle tangent to the stroke. The circle will be above
- * and/or to the left of the line */
- if (stroke)
- {
- old = (GdkPoint *)stroke->data;
-
- do
- {
- cur = (GdkPoint *)stroke->data;
- stroke = stroke->next;
- }
- while (stroke && abs(cur->x - old->x) < 5 && abs (cur->y - old->y) < 5);
-
- if (stroke)
- {
- char buffer[16];
- PangoLayout *layout;
- int swidth, sheight;
- gint16 x, y;
- double r;
- double dx = cur->x - old->x;
- double dy = cur->y - old->y;
- double dl = sqrt(dx*dx+dy*dy);
- int sign = (dy <= dx) ? 1 : -1;
- GdkRectangle update_area;
-
- sprintf (buffer, "%d", index);
- layout = gtk_widget_create_pango_layout (area->widget, buffer);
- pango_layout_get_pixel_size (layout, &swidth, &sheight);
-
- r = sqrt(swidth*swidth + sheight*sheight);
-
- x = 0.5 + old->x + 0.5*r*dx/dl + sign * 0.5*r*dy/dl;
- y = 0.5 + old->y + 0.5*r*dy/dl - sign * 0.5*r*dx/dl;
-
- x -= swidth/2;
- y -= sheight/2;
-
- update_area.x = x;
- update_area.y = y;
- update_area.width = swidth;
- update_area.height = sheight;
-
- x = CLAMP (x, 0, area->widget->allocation.width - swidth);
- y = CLAMP (y, 0, area->widget->allocation.height - sheight);
-
- gdk_draw_layout (area->pixmap,
- area->widget->style->black_gc,
- x, y, layout);
-
- g_object_unref (layout);
+ gtk_widget_get_allocation (area->widget, &allocation);
+
+ sprintf (buffer, "%d", index);
+ layout = gtk_widget_create_pango_layout (area->widget, buffer);
+ pango_layout_get_pixel_size (layout, &swidth, &sheight);
- gdk_window_invalidate_rect (area->widget->window, &update_area, FALSE);
- }
+ r = sqrt(swidth*swidth + sheight*sheight);
+
+ x = old->x + 0.5 * r * dx/dl + sign * 0.5 * r * dy/dl;
+ y = old->y + 0.5 * r * dy/dl - sign * 0.5 * r * dx/dl;
+
+ x -= swidth/2;
+ y -= sheight/2;
+
+ /* Clamp to widget boundaries */
+ x = CLAMP (x, 0, allocation.width - swidth);
+ y = CLAMP (y, 0, allocation.height - sheight);
+
+ /* Draw the number */
+ cairo_move_to (cr, x, y);
+ pango_cairo_show_layout (cr, layout);
+
+ g_object_unref (layout);
}
}
-static void
-pad_area_init (PadArea *area)
+static void
+pad_area_redraw_surface (PadArea *area)
{
+ GtkAllocation allocation;
GList *tmp_list;
int index = 1;
+ cairo_t *cr;
- guint16 width = area->widget->allocation.width;
- guint16 height = area->widget->allocation.height;
-
- gdk_draw_rectangle (area->pixmap,
- area->widget->style->white_gc, TRUE,
- 0, 0, width, height);
-
+ if (!area->surface)
+ return;
+
+ gtk_widget_get_allocation (area->widget, &allocation);
+
+ cr = cairo_create (area->surface);
+
+ /* Clear with white background */
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
+ cairo_fill (cr);
+
+ /* Draw grid if annotate mode */
+ if (area->annotate)
+ {
+ int i;
+ cairo_set_source_rgb (cr, 0.7, 0.7, 1.0);
+ cairo_set_line_width (cr, 0.5);
+
+ for (i = 0; i < 20; i++)
+ {
+ cairo_move_to (cr, i * 20, 0);
+ cairo_line_to (cr, i * 20, allocation.height);
+ cairo_move_to (cr, 0, i * 20);
+ cairo_line_to (cr, allocation.width, i * 20);
+ }
+ cairo_stroke (cr);
+ }
+
+ /* Set line properties for strokes */
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_set_line_width (cr, 2.0);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+
+ /* Draw all completed strokes */
tmp_list = area->strokes;
while (tmp_list)
{
- GdkPoint *cur, *old;
GList *stroke_list = tmp_list->data;
-
- old = NULL;
-
+ GdkPoint *old = NULL;
+ GdkPoint *cur;
+
+ /* Draw stroke numbers if annotate mode */
if (area->annotate)
- pad_area_annotate_stroke (area, stroke_list, index);
-
+ {
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 0, 0, 1); /* Blue for numbers */
+ pad_area_draw_stroke_number (area, stroke_list, index, cr);
+ cairo_restore (cr);
+ }
+
+ /* Draw the stroke lines */
while (stroke_list)
- {
- cur = (GdkPoint *)stroke_list->data;
- if (old)
- gdk_draw_line (area->pixmap,
- area->widget->style->black_gc,
- old->x, old->y, cur->x, cur->y);
-
- old = cur;
- stroke_list = stroke_list->next;
- }
+ {
+ cur = (GdkPoint *)stroke_list->data;
+ if (old)
+ {
+ cairo_move_to (cr, old->x, old->y);
+ cairo_line_to (cr, cur->x, cur->y);
+ cairo_stroke (cr);
+ }
+
+ old = cur;
+ stroke_list = stroke_list->next;
+ }
tmp_list = tmp_list->next;
index++;
}
-
- gtk_widget_queue_draw (area->widget);
+ /* Draw current stroke if any */
+ if (area->curstroke)
+ {
+ GList *stroke_list = area->curstroke;
+ GdkPoint *old = NULL;
+ GdkPoint *cur;
+
+ while (stroke_list)
+ {
+ cur = (GdkPoint *)stroke_list->data;
+ if (old)
+ {
+ cairo_move_to (cr, old->x, old->y);
+ cairo_line_to (cr, cur->x, cur->y);
+ cairo_stroke (cr);
+ }
+
+ old = cur;
+ stroke_list = stroke_list->next;
+ }
+ }
+
+ cairo_destroy (cr);
+
+ /* Trigger redraw */
+ gtk_widget_queue_draw (area->widget);
}
-static int
-pad_area_configure_event (GtkWidget *w, GdkEventConfigure *event,
- PadArea *area)
+static gboolean
+pad_area_draw_cb (GtkWidget *w, cairo_t *cr, gpointer data)
{
- if (area->pixmap)
- g_object_unref (area->pixmap);
-
- area->pixmap = gdk_pixmap_new (w->window, event->width, event->height, -1);
-
- pad_area_init (area);
+ PadArea *area = (PadArea *)data;
- return TRUE;
+ if (area->surface)
+ {
+ cairo_set_source_surface (cr, area->surface, 0, 0);
+ cairo_paint (cr);
+ }
+
+ return FALSE;
}
-static int
-pad_area_expose_event (GtkWidget *w, GdkEventExpose *event, PadArea *area)
+static void
+pad_area_resize_cb (GtkWidget *w, GtkAllocation *allocation, gpointer data)
{
- if (!area->pixmap)
- return 0;
-
- gdk_draw_drawable (w->window,
- w->style->fg_gc[GTK_STATE_NORMAL], area->pixmap,
- event->area.x, event->area.y,
- event->area.x, event->area.y,
- event->area.width, event->area.height);
-
- return TRUE;
+ PadArea *area = (PadArea *)data;
+
+ if (area->surface)
+ cairo_surface_destroy (area->surface);
+
+ area->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ allocation->width,
+ allocation->height);
+
+ pad_area_redraw_surface (area);
}
-static int
-pad_area_button_press_event (GtkWidget *w, GdkEventButton *event, PadArea *area)
+static gboolean
+pad_area_button_press_cb (GtkWidget *w, GdkEventButton *event, gpointer data)
{
+ PadArea *area = (PadArea *)data;
+
if (event->button == 1)
{
GdkPoint *p = g_new (GdkPoint, 1);
@@ -163,110 +229,119 @@
p->y = event->y;
area->curstroke = g_list_append (area->curstroke, p);
area->instroke = TRUE;
+
+ /* Draw the point immediately */
+ pad_area_redraw_surface (area);
}
-
+
return TRUE;
}
-static int
-pad_area_button_release_event (GtkWidget *w, GdkEventButton *event, PadArea *area)
+static gboolean
+pad_area_button_release_cb (GtkWidget *w, GdkEventButton *event, gpointer data)
{
- if (area->annotate)
- pad_area_annotate_stroke (area, area->curstroke, g_list_length (area->strokes) + 1);
-
- area->strokes = g_list_append (area->strokes, area->curstroke);
- area->curstroke = NULL;
- area->instroke = FALSE;
-
- pad_area_changed_callback (area);
-
+ PadArea *area = (PadArea *)data;
+
+ if (area->instroke && area->curstroke)
+ {
+ /* Add the current stroke to the strokes list */
+ area->strokes = g_list_append (area->strokes, area->curstroke);
+ area->curstroke = NULL;
+ area->instroke = FALSE;
+
+ /* Redraw with the completed stroke */
+ pad_area_redraw_surface (area);
+
+ /* Notify that the drawing has changed */
+ pad_area_changed_callback (area);
+ }
+
return TRUE;
}
-static int
-pad_area_motion_event (GtkWidget *w, GdkEventMotion *event, PadArea *area)
+static gboolean
+pad_area_motion_cb (GtkWidget *w, GdkEventMotion *event, gpointer data)
{
- gint x,y;
+ PadArea *area = (PadArea *)data;
+ gdouble x, y;
GdkModifierType state;
-
+
+ /* In GTK 3, we can get coordinates directly from the event */
+ x = event->x;
+ y = event->y;
+ state = event->state;
+
+ /* If it's a hint event, we might need to get the device position,
+ * but modern GTK 3 usually provides coordinates directly */
if (event->is_hint)
{
- gdk_window_get_pointer (w->window, &x, &y, &state);
- }
- else
- {
- x = event->x;
- y = event->y;
- state = event->state;
+ gint int_x, int_y;
+ GdkDevice *device = gdk_event_get_device ((GdkEvent*)event);
+ if (device)
+ {
+ gdk_window_get_device_position (gtk_widget_get_window (w),
+ device,
+ &int_x, &int_y, &state);
+ x = int_x;
+ y = int_y;
+ }
}
-
- if (area->instroke && state & GDK_BUTTON1_MASK)
+
+ if (area->instroke && (state & GDK_BUTTON1_MASK))
{
- GdkRectangle rect;
- GdkPoint *p;
- int xmin, ymin, xmax, ymax;
- GdkPoint *old = (GdkPoint *)g_list_last (area->curstroke)->data;
-
- gdk_draw_line (area->pixmap, w->style->black_gc,
- old->x, old->y, x, y);
-
- if (old->x < x) { xmin = old->x; xmax = x; }
- else { xmin = x; xmax = old->x; }
-
- if (old->y < y) { ymin = old->y; ymax = y; }
- else { ymin = y; ymax = old->y; }
-
- rect.x = xmin - 1;
- rect.y = ymin = 1;
- rect.width = xmax - xmin + 2;
- rect.height = ymax - ymin + 2;
- gdk_window_invalidate_rect (w->window, &rect, FALSE);
-
- p = g_new (GdkPoint, 1);
+ GdkPoint *p = g_new (GdkPoint, 1);
p->x = x;
p->y = y;
area->curstroke = g_list_append (area->curstroke, p);
+
+ /* Redraw to show the new line segment */
+ pad_area_redraw_surface (area);
}
-
+
return TRUE;
}
-PadArea *pad_area_create ()
+PadArea *
+pad_area_create (void)
{
PadArea *area = g_new (PadArea, 1);
- area->widget = gtk_drawing_area_new();
- gtk_widget_set_size_request (area->widget, 100, 100);
-
- g_signal_connect (area->widget, "configure_event",
- G_CALLBACK (pad_area_configure_event), area);
- g_signal_connect (area->widget, "expose_event",
- G_CALLBACK (pad_area_expose_event), area);
- g_signal_connect (area->widget, "button_press_event",
- G_CALLBACK (pad_area_button_press_event), area);
- g_signal_connect (area->widget, "button_release_event",
- G_CALLBACK (pad_area_button_release_event), area);
- g_signal_connect (area->widget, "motion_notify_event",
- G_CALLBACK (pad_area_motion_event), area);
-
- gtk_widget_set_events (area->widget,
- GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
- | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK
- | GDK_POINTER_MOTION_HINT_MASK);
-
+ area->widget = gtk_drawing_area_new ();
+ gtk_widget_set_size_request (area->widget, 200, 200);
+
+ g_signal_connect (area->widget, "draw",
+ G_CALLBACK (pad_area_draw_cb), area);
+ g_signal_connect (area->widget, "size-allocate",
+ G_CALLBACK (pad_area_resize_cb), area);
+ g_signal_connect (area->widget, "button-press-event",
+ G_CALLBACK (pad_area_button_press_cb), area);
+ g_signal_connect (area->widget, "button-release-event",
+ G_CALLBACK (pad_area_button_release_cb), area);
+ g_signal_connect (area->widget, "motion-notify-event",
+ G_CALLBACK (pad_area_motion_cb), area);
+
+ gtk_widget_set_events (area->widget,
+ GDK_EXPOSURE_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_POINTER_MOTION_HINT_MASK);
+
area->strokes = NULL;
area->curstroke = NULL;
area->instroke = FALSE;
area->annotate = FALSE;
- area->pixmap = NULL;
-
+ area->surface = NULL;
+
return area;
}
-void pad_area_clear (PadArea *area)
+void
+pad_area_clear (PadArea *area)
{
GList *tmp_list;
-
+
+ /* Free all strokes */
tmp_list = area->strokes;
while (tmp_list)
{
@@ -275,34 +350,29 @@
}
g_list_free (area->strokes);
area->strokes = NULL;
-
-#if 0
- tmp_list = thinned;
- while (tmp_list)
+
+ /* Free current stroke if any */
+ if (area->curstroke)
{
- pad_area_free_stroke (tmp_list->data);
- tmp_list = tmp_list->next;
+ pad_area_free_stroke (area->curstroke);
+ area->curstroke = NULL;
}
- g_list_free (thinned);
- thinned = NULL;
-#endif
-
- g_list_free (area->curstroke);
- area->curstroke = NULL;
-
- pad_area_init (area);
-
- pad_area_changed_callback (area);
+
+ area->instroke = FALSE;
+
+ /* Redraw the empty surface */
+ pad_area_redraw_surface (area);
+
+ /* Notify that the drawing has changed */
+ pad_area_changed_callback (area);
}
-void pad_area_set_annotate (PadArea *area, gint annotate)
+void
+pad_area_set_annotate (PadArea *area, gboolean annotate)
{
if (area->annotate != annotate)
{
area->annotate = annotate;
- pad_area_init (area);
+ pad_area_redraw_surface (area);
}
}
-
-
-