aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2004-10-25 19:09:36 +0000
committerKeith Packard <keithp@keithp.com>2004-10-25 19:09:36 +0000
commit6df04a58f5078741ac7d5a66492814eec66f027a (patch)
treebd0db1ed504f56b12f116160062d1d7ac5883688
parentc905d1c40ad88707f549a56e631c4eaff756378b (diff)
downloadlibtwin-6df04a58f5078741ac7d5a66492814eec66f027a.tar.gz
Add dispatch stuff to manage timeouts, workprocs and files. Remove thread
stuff Split demos into separate files Make drawing origin match clip rectangle. twin_fedit Add glyph editor to CVS to preserve it Add scalable icons Separate 'closing' a subpath from 'finishing' a subpath; the former adds a point back to the start while the latter just leaves the path unclosed and prepares for a new subpath. Eliminate locking, add clipping. Clean up title drawing, use clipping Eliminate locking, use dispatch stuff
-rw-r--r--ChangeLog68
-rw-r--r--Makefile.am13
-rw-r--r--configure.ac4
-rw-r--r--twin.h149
-rw-r--r--twin_clock.c238
-rw-r--r--twin_clock.h33
-rw-r--r--twin_demo.c474
-rw-r--r--twin_demo.h33
-rw-r--r--twin_dispatch.c36
-rw-r--r--twin_draw.c107
-rw-r--r--twin_fedit/Makefile9
-rw-r--r--twin_fedit/nchars1021
-rw-r--r--twin_fedit/twin-fedit.c699
-rw-r--r--twin_fedit/twin-fedit.h103
-rw-r--r--twin_fedit/twin-sfit.c351
-rw-r--r--twin_file.c124
-rw-r--r--twin_icon.c184
-rw-r--r--twin_path.c78
-rw-r--r--twin_pixmap.c59
-rw-r--r--twin_poly.c16
-rw-r--r--twin_queue.c95
-rw-r--r--twin_screen.c13
-rw-r--r--twin_text.c86
-rw-r--r--twin_text.h33
-rw-r--r--twin_timeout.c127
-rw-r--r--twin_window.c134
-rw-r--r--twin_work.c82
-rw-r--r--twin_x11.c67
-rw-r--r--twin_x11.h3
-rw-r--r--twinint.h88
-rw-r--r--xtwin.c688
31 files changed, 4298 insertions, 917 deletions
diff --git a/ChangeLog b/ChangeLog
index f9340d8..63da4c2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,71 @@
+2004-10-25 Keith Packard <keithp@keithp.com>
+
+ * Makefile.am:
+ * configure.ac:
+ * twin_dispatch.c: (twin_dispatch):
+ * twin_file.c: (_twin_file_order), (_twin_run_file),
+ (twin_set_file), (twin_clear_file):
+ * twin_queue.c: (_twin_queue_insert), (_twin_queue_remove),
+ (_twin_queue_delete), (_twin_queue_set_order),
+ (_twin_queue_review_order):
+ * twin_timeout.c: (_twin_timeout_order), (_twin_queue_timeout),
+ (_twin_run_timeout), (twin_set_timeout), (twin_clear_timeout),
+ (_twin_timeout_delay), (twin_now):
+ * twin_work.c: (_twin_work_order), (_twin_queue_work),
+ (_twin_run_work), (twin_set_work), (twin_clear_work):
+ * twinint.h:
+ Add dispatch stuff to manage timeouts, workprocs and files.
+ Remove thread stuff
+
+ * twin.h:
+ * twin_clock.c: (twin_clock_set_transform), (twin_clock_hand),
+ (twin_clock_minute_angle), (twin_clock_face), (twin_clock_timeout),
+ (twin_clock_start):
+ * twin_clock.h:
+ * twin_demo.c: (twin_example_start), (twin_line_start),
+ (twin_circletext_start), (twin_quickbrown_start),
+ (twin_ascii_start), (twin_jelly_start), (twin_extents_start),
+ (twin_demo_start):
+ * twin_demo.h:
+ * twin_text.c: (twin_text_start):
+ * twin_text.h:
+ * xtwin.c: (main):
+ Split demos into separate files
+
+ * twin_draw.c: (twin_composite), (twin_fill):
+ Make drawing origin match clip rectangle.
+
+ * twin_fedit
+ Add glyph editor to CVS to preserve it
+
+ * twin_icon.c: (twin_icon_draw):
+ Add scalable icons
+
+ * twin_path.c: (_twin_path_sfinish), (_twin_path_smove),
+ (twin_path_close), (twin_path_circle), (twin_path_ellipse),
+ (twin_path_append), (twin_composite_path):
+ Separate 'closing' a subpath from 'finishing' a subpath; the
+ former adds a point back to the start while the latter just
+ leaves the path unclosed and prepares for a new subpath.
+
+ * twin_pixmap.c: (twin_pixmap_create), (twin_pixmap_show),
+ (twin_pixmap_hide), (twin_pixmap_clip), (twin_pixmap_current_clip),
+ (twin_pixmap_restore_clip), (twin_pixmap_reset_clip),
+ (twin_pixmap_damage), (twin_pixmap_move):
+ * twin_poly.c: (_twin_edge_build), (_span_fill), (_twin_edge_fill),
+ (twin_fill_path):
+ * twin_screen.c: (twin_screen_create):
+ Eliminate locking, add clipping.
+
+ * twin_window.c: (twin_window_create), (twin_window_configure),
+ (twin_window_frame):
+ Clean up title drawing, use clipping
+
+ * twin_x11.c: (twin_x11_read_events), (twin_x11_work),
+ (twin_x11_create), (twin_x11_destroy), (twin_x11_damage):
+ * twin_x11.h:
+ Eliminate locking, use dispatch stuff
+
2004-10-05 Keith Packard <keithp@keithp.com>
* Makefile.am:
diff --git a/Makefile.am b/Makefile.am
index af5f217..5a07773 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-CFLAGS=-g
+AM_CFLAGS=-O0 -g
INCLUDES= @X_CFLAGS@ @WARN_CFLAGS@
#libtwin_la_SOURCES = \
@@ -17,9 +17,12 @@ bin_PROGRAMS = xtwin
xtwin_SOURCES = \
twin.h \
twin_convolve.c \
+ twin_dispatch.c \
twin_draw.c \
twin_glyphs.c \
twin_hull.c \
+ twin_icon.c \
+ twin_file.c \
twin_fixed.c \
twin_font.c \
twin_geom.c \
@@ -31,11 +34,17 @@ xtwin_SOURCES = \
twin_primitive.c \
twin_screen.c \
twin_spline.c \
- twin_thread.c \
twin_trig.c \
twin_window.c \
twin_x11.c \
twinint.h \
+ twin_queue.c \
+ twin_timeout.c \
+ twin_work.c \
+ twinint.h \
+ twin_clock.c \
+ twin_text.c \
+ twin_demo.c \
xtwin.c
xtwin_LDADD = @X_LIBS@ -lm
diff --git a/configure.ac b/configure.ac
index ebe9981..ba83161 100644
--- a/configure.ac
+++ b/configure.ac
@@ -52,10 +52,6 @@ PKG_CHECK_MODULES(X, x11,
AC_SUBST(X_CFLAGS)
AC_SUBST(X_LIBS)
-AC_CHECK_LIB([pthread], [pthread_create])
-
-AC_CHECK_HEADERS([pthread.h])
-
#
#AC_ARG_WITH(freetype-config, [ --with-freetype-config=PROG Use FreeType configuration program PROG], freetype_config=$withval, freetype_config=yes)
#
diff --git a/twin.h b/twin.h
index 4cf2848..d5d4255 100644
--- a/twin.h
+++ b/twin.h
@@ -28,9 +28,6 @@
#include <stdlib.h>
#include <stdint.h>
#include <twin_def.h>
-#if HAVE_PTHREAD_H
-#include <pthread.h>
-#endif
typedef uint8_t twin_a8_t;
typedef uint16_t twin_a16_t;
@@ -43,19 +40,7 @@ typedef int16_t twin_style_t;
typedef int16_t twin_count_t;
typedef int16_t twin_keysym_t;
typedef int32_t twin_area_t;
-
-/*
- * Mutexes
- */
-#if HAVE_PTHREAD_H
-typedef pthread_mutex_t twin_mutex_t;
-typedef pthread_cond_t twin_cond_t;
-typedef pthread_t twin_thread_t;
-#else
-typedef int twin_mutext_t;
-typedef int twin_cond_t;
-typedef int twin_thread_t;
-#endif
+typedef int32_t twin_time_t;
#define TWIN_FALSE 0
#define TWIN_TRUE 1
@@ -120,6 +105,11 @@ typedef struct _twin_pixmap {
twin_coord_t height; /* pixels */
twin_coord_t stride; /* bytes */
/*
+ * Clipping - a single rectangle in pixmap coordinates.
+ * Drawing is done relative to this rectangle
+ */
+ twin_rect_t clip;
+ /*
* Pixels
*/
twin_pointer_t p;
@@ -176,7 +166,6 @@ typedef struct _twin_screen {
void (*damaged) (void *);
void *damaged_closure;
twin_count_t disable;
- twin_mutex_t screen_mutex;
/*
* Repaint function
*/
@@ -220,6 +209,9 @@ typedef int32_t twin_fixed_t; /* 16.16 format */
#define twin_fixed_to_double(f) ((double) (f) / 65536.0)
#define twin_int_to_fixed(i) ((twin_fixed_t) (i) << 16)
+#define twin_fixed_ceil(f) (((f) + 0xffff) & ~0xffff)
+#define twin_fixed_floor(f) ((f) & ~0xffff)
+#define twin_fixed_to_int(f) ((int) ((f) >> 16))
typedef struct _twin_point {
twin_fixed_t x, y;
@@ -328,12 +320,23 @@ typedef enum _twin_icon {
TwinIconMinimize,
TwinIconMaximize,
TwinIconClose,
+ TwinIconResize,
} twin_icon_t;
/*
* Widgets
*/
+typedef enum _twin_box_layout {
+ TwinLayoutHorz, TwinLayoutVert
+} twin_box_layout_t;
+
+typedef struct _twin_box {
+ twin_box_layout_t layout;
+ twin_rect_t geometry;
+
+} twin_box_t;
+
typedef struct {
twin_rect_t geometry;
} twin_widget_t;
@@ -343,6 +346,36 @@ typedef struct {
} twin_button_t;
/*
+ * Timeout and work procs return TWIN_TRUE to remain in the queue,
+ * timeout procs are called every 'delay' ms
+ */
+
+typedef twin_time_t (*twin_timeout_proc_t) (twin_time_t now,
+ void *closure);
+
+typedef twin_bool_t (*twin_work_proc_t) (void *closure);
+
+typedef enum _twin_file_op {
+ TWIN_READ = 1,
+ TWIN_WRITE = 2
+} twin_file_op_t;
+
+typedef twin_bool_t (*twin_file_proc_t) (int file,
+ twin_file_op_t ops,
+ void *closure);
+
+typedef void (*twin_block_proc_t) (void *closure);
+typedef void (*twin_wakeup_proc_t) (void *closure);
+
+#define twin_time_compare(a,op,b) (((a) - (b)) op 0)
+
+typedef struct _twin_timeout twin_timeout_t;
+typedef struct _twin_work twin_work_t;
+typedef struct _twin_file twin_file_t;
+typedef struct _twin_block twin_block_t;
+typedef struct _twin_wakeup twin_wakeup_t;
+
+/*
* twin_convolve.c
*/
void
@@ -351,6 +384,12 @@ twin_path_convolve (twin_path_t *dest,
twin_path_t *pen);
/*
+ * twin_dispatch.c
+ */
+void
+twin_dispatch (void);
+
+/*
* twin_draw.c
*/
@@ -385,6 +424,19 @@ void
twin_event_enqueue (const twin_event_t *event);
/*
+ * twin_file.c
+ */
+
+twin_file_t *
+twin_set_file (twin_file_proc_t file_proc,
+ int file,
+ twin_file_op_t ops,
+ void *closure);
+
+void
+twin_clear_file (twin_file_t *file);
+
+/*
* twin_fixed.c
*/
@@ -620,9 +672,23 @@ void
twin_pixmap_disable_update (twin_pixmap_t *pixmap);
void
-twin_pixmap_damage (twin_pixmap_t *pixmap,
- twin_coord_t x1, twin_coord_t y1,
- twin_coord_t x2, twin_coord_t y2);
+twin_pixmap_clip (twin_pixmap_t *pixmap,
+ twin_coord_t left, twin_coord_t top,
+ twin_coord_t right, twin_coord_t bottom);
+
+twin_rect_t
+twin_pixmap_current_clip (twin_pixmap_t *pixmap);
+
+void
+twin_pixmap_restore_clip (twin_pixmap_t *pixmap, twin_rect_t rect);
+
+void
+twin_pixmap_reset_clip (twin_pixmap_t *pixmap);
+
+void
+twin_pixmap_damage (twin_pixmap_t *pixmap,
+ twin_coord_t left, twin_coord_t top,
+ twin_coord_t right, twin_coord_t bottom);
void
twin_pixmap_lock (twin_pixmap_t *pixmap);
@@ -723,31 +789,21 @@ twin_path_curve (twin_path_t *path,
twin_fixed_t x3, twin_fixed_t y3);
/*
- * twin_thread.c
+ * twin_timeout.c
*/
-void
-twin_mutex_init (twin_mutex_t *mutex);
-
-void
-twin_mutex_lock (twin_mutex_t *mutex);
+#define twin_time_compare(a,op,b) (((a) - (b)) op 0)
-void
-twin_mutex_unlock (twin_mutex_t *mutex);
+twin_timeout_t *
+twin_set_timeout (twin_timeout_proc_t timeout_proc,
+ twin_time_t delay,
+ void *closure);
void
-twin_cond_init (twin_cond_t *cond);
+twin_clear_timeout (twin_timeout_t *timeout);
-void
-twin_cond_broadcast (twin_cond_t *cond);
-
-void
-twin_cond_wait (twin_cond_t *cond, twin_mutex_t *mutex);
-
-typedef void * (*twin_thread_func_t) (void *arg);
-
-int
-twin_thread_create (twin_thread_t *thread, twin_thread_func_t func, void *arg);
+twin_time_t
+twin_now (void);
/*
* twin_trig.c
@@ -806,5 +862,18 @@ twin_window_draw (twin_window_t *window);
twin_bool_t
twin_window_dispatch (twin_window_t *window, twin_event_t *event);
-
+/*
+ * twin_work.c
+ */
+
+#define TWIN_WORK_REDISPLAY 0
+
+twin_work_t *
+twin_set_work (twin_work_proc_t work_proc,
+ int priority,
+ void *closure);
+
+void
+twin_clear_work (twin_work_t *work);
+
#endif /* _TWIN_H_ */
diff --git a/twin_clock.c b/twin_clock.c
new file mode 100644
index 0000000..a8b6c9f
--- /dev/null
+++ b/twin_clock.c
@@ -0,0 +1,238 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <twin_clock.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+
+#define D(x) twin_double_to_fixed(x)
+
+#define TWIN_CLOCK_BACKGROUND 0xff3b80ae
+#define TWIN_CLOCK_HOUR 0x80808080
+#define TWIN_CLOCK_HOUR_OUT 0x30000000
+#define TWIN_CLOCK_MINUTE 0x80808080
+#define TWIN_CLOCK_MINUTE_OUT 0x30000000
+#define TWIN_CLOCK_SECOND 0x80808080
+#define TWIN_CLOCK_SECOND_OUT 0x30000000
+#define TWIN_CLOCK_TIC 0xffbababa
+#define TWIN_CLOCK_NUMBERS 0xffdedede
+#define TWIN_CLOCK_WATER 0x60200000
+#define TWIN_CLOCK_WATER_OUT 0x40404040
+#define TWIN_CLOCK_WATER_UNDER 0x60400000
+#define TWIN_CLOCK_BORDER 0xffbababa
+#define TWIN_CLOCK_BORDER_WIDTH D(0.01)
+
+static void
+twin_clock_set_transform (twin_window_t *clock,
+ twin_path_t *path)
+{
+ twin_fixed_t scale;
+
+ scale = (TWIN_FIXED_ONE - TWIN_CLOCK_BORDER_WIDTH * 3) / 2;
+ twin_path_scale (path,
+ (clock->client.right - clock->client.left) * scale,
+ (clock->client.bottom - clock->client.top) * scale);
+
+ twin_path_translate (path,
+ TWIN_FIXED_ONE + TWIN_CLOCK_BORDER_WIDTH * 3,
+ TWIN_FIXED_ONE + TWIN_CLOCK_BORDER_WIDTH * 3);
+
+ twin_path_rotate (path, -TWIN_ANGLE_90);
+}
+
+static void
+twin_clock_hand (twin_window_t *clock,
+ twin_angle_t angle,
+ twin_fixed_t len,
+ twin_fixed_t fill_width,
+ twin_fixed_t out_width,
+ twin_argb32_t fill_pixel,
+ twin_argb32_t out_pixel)
+{
+ twin_path_t *stroke = twin_path_create ();
+ twin_path_t *pen = twin_path_create ();
+ twin_path_t *path = twin_path_create ();
+ twin_matrix_t m;
+
+ twin_clock_set_transform (clock, stroke);
+
+ twin_path_rotate (stroke, angle);
+ twin_path_move (stroke, D(0), D(0));
+ twin_path_draw (stroke, len, D(0));
+
+ m = twin_path_current_matrix (stroke);
+ m.m[2][0] = 0;
+ m.m[2][1] = 0;
+ twin_path_set_matrix (pen, m);
+ twin_path_set_matrix (path, m);
+ twin_path_circle (pen, fill_width);
+ twin_path_convolve (path, stroke, pen);
+
+ twin_paint_path (clock->pixmap, fill_pixel, path);
+
+ twin_paint_stroke (clock->pixmap, out_pixel, path, out_width);
+
+ twin_path_destroy (path);
+ twin_path_destroy (pen);
+ twin_path_destroy (stroke);
+}
+
+static twin_angle_t
+twin_clock_minute_angle (int min)
+{
+ return min * TWIN_ANGLE_360 / 60;
+}
+
+static void
+twin_clock_face (twin_window_t *clock)
+{
+ twin_path_t *path = twin_path_create ();
+ int m;
+
+ twin_clock_set_transform (clock, path);
+
+ twin_path_move (path, 0, 0);
+ twin_path_circle (path, TWIN_FIXED_ONE);
+
+ twin_paint_path (clock->pixmap, TWIN_CLOCK_BACKGROUND, path);
+
+ twin_paint_stroke (clock->pixmap, TWIN_CLOCK_BORDER, path, TWIN_CLOCK_BORDER_WIDTH);
+
+ {
+ twin_state_t state = twin_path_save (path);
+ twin_text_metrics_t metrics;
+ twin_fixed_t height, width;
+ static char *label = "twin";
+
+ twin_path_empty (path);
+ twin_path_rotate (path, twin_degrees_to_angle (-11) + TWIN_ANGLE_90);
+ twin_path_set_font_size (path, D(0.5));
+ twin_path_set_font_style (path, TWIN_TEXT_UNHINTED|TWIN_TEXT_OBLIQUE);
+ twin_text_metrics_utf8 (path, label, &metrics);
+ height = metrics.ascent + metrics.descent;
+ width = metrics.right_side_bearing - metrics.left_side_bearing;
+
+ twin_path_move (path, -width / 2, metrics.ascent - height/2 + D(0.01));
+ twin_path_draw (path, width / 2, metrics.ascent - height/2 + D(0.01));
+ twin_paint_stroke (clock->pixmap, TWIN_CLOCK_WATER_UNDER, path, D(0.02));
+ twin_path_empty (path);
+
+ twin_path_move (path, -width / 2 - metrics.left_side_bearing, metrics.ascent - height/2);
+ twin_path_utf8 (path, label);
+ twin_paint_path (clock->pixmap, TWIN_CLOCK_WATER, path);
+ twin_path_restore (path, &state);
+ }
+
+ twin_path_set_font_size (path, D(0.2));
+ twin_path_set_font_style (path, TWIN_TEXT_UNHINTED);
+
+ for (m = 1; m <= 60; m++)
+ {
+ twin_state_t state = twin_path_save (path);
+ twin_path_rotate (path, twin_clock_minute_angle (m) + TWIN_ANGLE_90);
+ twin_path_empty (path);
+ if (m % 5 != 0)
+ {
+ twin_path_move (path, 0, -TWIN_FIXED_ONE);
+ twin_path_draw (path, 0, -D(0.9));
+ twin_paint_stroke (clock->pixmap, TWIN_CLOCK_TIC, path, D(0.01));
+ }
+ else
+ {
+ char hour[3];
+ twin_text_metrics_t metrics;
+ twin_fixed_t width;
+ twin_fixed_t left;
+
+ sprintf (hour, "%d", m / 5);
+ twin_text_metrics_utf8 (path, hour, &metrics);
+ width = metrics.right_side_bearing - metrics.left_side_bearing;
+ left = -width / 2 - metrics.left_side_bearing;
+ twin_path_move (path, left, -D(0.98) + metrics.ascent);
+ twin_path_utf8 (path, hour);
+ twin_paint_path (clock->pixmap, TWIN_CLOCK_NUMBERS, path);
+ }
+ twin_path_restore (path, &state);
+ }
+
+ twin_path_destroy (path);
+}
+
+static twin_time_t
+twin_clock_timeout (twin_time_t now, void *closure)
+{
+ twin_window_t *clock = closure;
+ struct timeval tv;
+ twin_angle_t second_angle, minute_angle, hour_angle;
+ struct tm t;
+
+ gettimeofday (&tv, NULL);
+
+ localtime_r(&tv.tv_sec, &t);
+
+ twin_pixmap_disable_update (clock->pixmap);
+ twin_fill (clock->pixmap, 0x00000000, TWIN_SOURCE,
+ clock->client.left, clock->client.top,
+ clock->client.right, clock->client.bottom);
+
+ twin_clock_face (clock);
+
+ second_angle = ((t.tm_sec * 100 + tv.tv_usec / 10000) *
+ TWIN_ANGLE_360) / 6000;
+ minute_angle = twin_clock_minute_angle (t.tm_min) + second_angle / 60;
+ hour_angle = (t.tm_hour * TWIN_ANGLE_360 + minute_angle) / 12;
+ twin_clock_hand (clock, hour_angle, D(0.4), D(0.07), D(0.01),
+ TWIN_CLOCK_HOUR, TWIN_CLOCK_HOUR_OUT);
+ twin_clock_hand (clock, minute_angle, D(0.8), D(0.05), D(0.01),
+ TWIN_CLOCK_MINUTE, TWIN_CLOCK_MINUTE_OUT);
+ twin_clock_hand (clock, second_angle, D(0.9), D(0.01), D(0.01),
+ TWIN_CLOCK_SECOND, TWIN_CLOCK_SECOND_OUT);
+
+ twin_pixmap_enable_update (clock->pixmap);
+
+ gettimeofday (&tv, NULL);
+
+ return 1000 - (tv.tv_usec / 1000);
+}
+
+void
+twin_clock_start (twin_screen_t *screen, const char *name, int x, int y, int w, int h)
+{
+ struct timeval tv;
+ twin_time_t to;
+ twin_window_t *clock = twin_window_create (screen, TWIN_ARGB32,
+ WindowApplication,
+ x, y, w, h);
+ twin_window_set_name (clock, name);
+ twin_clock_timeout (0, clock);
+ twin_window_show (clock);
+
+ gettimeofday (&tv, NULL);
+
+ to = 1000 - (tv.tv_usec / 1000);
+ (void) twin_set_timeout (twin_clock_timeout,
+ to,
+ clock);
+}
diff --git a/twin_clock.h b/twin_clock.h
new file mode 100644
index 0000000..00e1ff6
--- /dev/null
+++ b/twin_clock.h
@@ -0,0 +1,33 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TWIN_CLOCK_H_
+#define _TWIN_CLOCK_H_
+
+#include <twin.h>
+
+void
+twin_clock_start (twin_screen_t *screen, const char *name, int x, int y, int w, int h);
+
+#endif /* _TWIN_CLOCK_H_ */
diff --git a/twin_demo.c b/twin_demo.c
new file mode 100644
index 0000000..acf3328
--- /dev/null
+++ b/twin_demo.c
@@ -0,0 +1,474 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <twin_demo.h>
+
+#define D(x) twin_double_to_fixed(x)
+
+static int styles[] = {
+ TWIN_TEXT_ROMAN,
+ TWIN_TEXT_OBLIQUE,
+ TWIN_TEXT_BOLD,
+ TWIN_TEXT_BOLD|TWIN_TEXT_OBLIQUE
+};
+
+static void
+twin_example_start (twin_screen_t *screen, int x, int y, int w, int h)
+{
+ twin_window_t *window = twin_window_create (screen, TWIN_ARGB32,
+ WindowApplication,
+ x, y, w, h);
+ int wid = window->client.right - window->client.left;
+ int hei = window->client.bottom - window->client.top;
+ twin_pixmap_t *pixmap = window->pixmap;
+ twin_path_t *path = twin_path_create ();
+ twin_path_t *pen = twin_path_create ();
+ twin_pixmap_t *alpha = twin_pixmap_create (TWIN_A8, w, h);
+ twin_operand_t source, mask;
+
+ twin_fill (pixmap, 0xffffffff, TWIN_SOURCE, 0, 0, wid, hei);
+
+ twin_window_set_name (window, "example");
+
+ twin_path_circle (pen, D (1));
+
+ /* graphics here in path */
+
+ twin_fill_path (alpha, path, 0, 0);
+ twin_path_destroy (path);
+ twin_path_destroy (pen);
+ source.source_kind = TWIN_SOLID;
+ source.u.argb = 0xff000000;
+ mask.source_kind = TWIN_PIXMAP;
+ mask.u.pixmap = alpha;
+ twin_composite (pixmap, 0, 0,
+ &source, 0, 0, &mask, 0, 0, TWIN_OVER, w, h);
+ twin_pixmap_destroy (alpha);
+ twin_window_show (window);
+}
+
+static void
+twin_line_start (twin_screen_t *screen, int x, int y, int w, int h)
+{
+ twin_window_t *window = twin_window_create (screen, TWIN_ARGB32,
+ WindowApplication,
+ x, y, w, h);
+ int wid = window->client.right - window->client.left;
+ int hei = window->client.bottom - window->client.top;
+ twin_pixmap_t *pixmap = window->pixmap;
+ twin_path_t *path = twin_path_create ();
+ twin_path_t *pen = twin_path_create ();
+ twin_path_t *stroke = twin_path_create ();
+ twin_pixmap_t *alpha = twin_pixmap_create (TWIN_A8, w, h);
+ twin_operand_t source, mask;
+
+ twin_fill (pixmap, 0xffffffff, TWIN_SOURCE,
+ 0, 0, wid, hei);
+
+ twin_window_set_name (window, "line");
+
+ twin_path_circle (pen, D (1));
+
+ stroke = twin_path_create ();
+ pen = twin_path_create ();
+ twin_path_translate (stroke, D(100), D(100));
+
+/* twin_path_rotate (stroke, twin_degrees_to_angle (270)); */
+ twin_path_rotate (stroke, twin_degrees_to_angle (270));
+ twin_path_move (stroke, D(0), D(0));
+ twin_path_draw (stroke, D(100), D(0));
+ twin_path_set_matrix (pen, twin_path_current_matrix (stroke));
+ twin_path_circle (pen, D(20));
+ twin_path_convolve (path, stroke, pen);
+
+ twin_fill_path (alpha, path, 0, 0);
+ twin_path_destroy (path);
+ twin_path_destroy (pen);
+ twin_path_destroy (stroke);
+ source.source_kind = TWIN_SOLID;
+ source.u.argb = 0xff000000;
+ mask.source_kind = TWIN_PIXMAP;
+ mask.u.pixmap = alpha;
+ twin_composite (pixmap, 0, 0,
+ &source, 0, 0, &mask, 0, 0, TWIN_OVER, wid, hei);
+ twin_pixmap_destroy (alpha);
+ twin_window_show (window);
+}
+
+static void
+twin_circletext_start (twin_screen_t *screen, int x, int y, int w, int h)
+{
+ twin_window_t *window = twin_window_create (screen, TWIN_ARGB32,
+ WindowApplication,
+ x, y, w, h);
+ int wid = window->client.right - window->client.left;
+ int hei = window->client.bottom - window->client.top;
+ twin_pixmap_t *pixmap = window->pixmap;
+ twin_path_t *path = twin_path_create ();
+ twin_path_t *pen = twin_path_create ();
+ twin_pixmap_t *alpha = twin_pixmap_create (TWIN_A8, wid, hei);
+ int s;
+ twin_operand_t source, mask;
+
+ twin_fill (pixmap, 0xffffffff, TWIN_SOURCE,
+ 0, 0, wid, hei);
+ twin_window_set_name (window, "circletext");
+
+ twin_path_set_font_style (path, TWIN_TEXT_UNHINTED);
+ twin_path_circle (pen, D (1));
+
+ twin_path_translate (path, D(200), D(200));
+ twin_path_set_font_size (path, D(15));
+ for (s = 0; s < 41; s++)
+ {
+ twin_state_t state = twin_path_save (path);
+ twin_path_rotate (path, twin_degrees_to_angle (9 * s));
+ twin_path_move (path, D(100), D(0));
+ twin_path_utf8 (path, "Hello, world!");
+ twin_path_restore (path, &state);
+ }
+ twin_fill_path (alpha, path, 0, 0);
+ twin_path_destroy (path);
+ twin_path_destroy (pen);
+ source.source_kind = TWIN_SOLID;
+ source.u.argb = 0xff000000;
+ mask.source_kind = TWIN_PIXMAP;
+ mask.u.pixmap = alpha;
+ twin_composite (pixmap, 0, 0,
+ &source, 0, 0, &mask, 0, 0, TWIN_OVER, wid, hei);
+ twin_pixmap_destroy (alpha);
+ twin_window_show (window);
+}
+
+static void
+twin_quickbrown_start (twin_screen_t *screen, int x, int y, int w, int h)
+{
+ twin_window_t *window = twin_window_create (screen, TWIN_ARGB32,
+ WindowApplication,
+ x, y, w, h);
+ int wid = window->client.right - window->client.left;
+ int hei = window->client.bottom - window->client.top;
+ twin_pixmap_t *pixmap = window->pixmap;
+ twin_path_t *path = twin_path_create ();
+ twin_path_t *pen = twin_path_create ();
+ twin_pixmap_t *alpha = twin_pixmap_create (TWIN_A8, wid, hei);
+ twin_operand_t source, mask;
+ twin_fixed_t fx, fy;
+ int s;
+
+ twin_window_set_name (window, "Quick Brown");
+
+ twin_fill (pixmap, 0xffffffff, TWIN_SOURCE,
+ 0, 0, wid, hei);
+
+ twin_path_circle (pen, D (1));
+
+ fx = D(3);
+ fy = D(8);
+ for (s = 6; s < 36; s++)
+ {
+ twin_path_move (path, fx, fy);
+ twin_path_set_font_size (path, D(s));
+ twin_path_utf8 (path,
+ "the quick brown fox jumps over the lazy dog.");
+ twin_path_utf8 (path,
+ "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.");
+ fy += D(s);
+ }
+
+ twin_fill_path (alpha, path, 0, 0);
+ twin_path_destroy (path);
+ twin_path_destroy (pen);
+ source.source_kind = TWIN_SOLID;
+ source.u.argb = 0xff000000;
+ mask.source_kind = TWIN_PIXMAP;
+ mask.u.pixmap = alpha;
+ twin_composite (pixmap, 0, 0,
+ &source, 0, 0, &mask, 0, 0, TWIN_OVER, wid, hei);
+ twin_pixmap_destroy (alpha);
+ twin_window_show (window);
+}
+
+static void
+twin_ascii_start (twin_screen_t *screen, int x, int y, int w, int h)
+{
+ twin_window_t *window = twin_window_create (screen, TWIN_ARGB32,
+ WindowApplication,
+ x, y, w, h);
+ int wid = window->client.right - window->client.left;
+ int hei = window->client.bottom - window->client.top;
+ twin_pixmap_t *pixmap = window->pixmap;
+ twin_path_t *path = twin_path_create ();
+ twin_path_t *pen = twin_path_create ();
+ twin_pixmap_t *alpha = twin_pixmap_create (TWIN_A8, wid, hei);
+ twin_operand_t source, mask;
+ twin_fixed_t fx, fy;
+ int s;
+
+ twin_window_set_name (window, "ASCII");
+
+ twin_fill (pixmap, 0xffffffff, TWIN_SOURCE, 0, 0, wid, hei);
+ twin_path_circle (pen, D (1));
+
+ fx = D(3);
+ fy = D(8);
+ for (s = 6; s < 36; s += 6)
+ {
+ twin_path_set_font_size (path, D(s));
+ fy += D(s+2);
+ twin_path_move (path, fx, fy);
+ twin_path_utf8 (path,
+ " !\"#$%&'()*+,-./0123456789:;<=>?");
+ fy += D(s+2);
+ twin_path_move (path, fx, fy);
+ twin_path_utf8 (path,
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_");
+ fy += D(s+2);
+ twin_path_move (path, fx, fy);
+ twin_path_utf8 (path,
+ "`abcdefghijklmnopqrstuvwxyz{|}~");
+ fy += D(s+2);
+ }
+
+ twin_fill_path (alpha, path, 0, 0);
+ twin_path_destroy (path);
+ twin_path_destroy (pen);
+ source.source_kind = TWIN_SOLID;
+ source.u.argb = 0xff000000;
+ mask.source_kind = TWIN_PIXMAP;
+ mask.u.pixmap = alpha;
+ twin_composite (pixmap, 0, 0,
+ &source, 0, 0, &mask, 0, 0, TWIN_OVER, wid, hei);
+ twin_pixmap_destroy (alpha);
+ twin_window_show (window);
+}
+
+static void
+twin_jelly_start (twin_screen_t *screen, int x, int y, int w, int h)
+{
+ twin_window_t *window = twin_window_create (screen, TWIN_ARGB32,
+ WindowApplication,
+ x, y, w, h);
+ int wid = window->client.right - window->client.left;
+ int hei = window->client.bottom - window->client.top;
+ twin_pixmap_t *pixmap = window->pixmap;
+ twin_path_t *path = twin_path_create ();
+ twin_fixed_t fx, fy;
+ int s;
+
+ twin_window_set_name (window, "Jelly");
+
+ twin_fill (pixmap, 0xffffffff, TWIN_SOURCE,
+ 0, 0, wid, hei);
+
+ fx = D(3);
+ fy = D(8);
+ for (s = 6; s < 36; s += 2)
+ {
+ twin_path_set_font_size (path, D(s));
+ fy += D(s + 2);
+ twin_path_move (path, fx, fy);
+#define TEXT "jelly text"
+/* twin_path_set_font_style (path, TWIN_TEXT_UNHINTED); */
+ twin_path_utf8 (path, TEXT);
+ twin_paint_path (pixmap, 0xff000000, path);
+ twin_path_empty (path);
+ {
+ twin_text_metrics_t m;
+ twin_path_t *stroke = twin_path_create ();
+ twin_path_set_matrix (stroke, twin_path_current_matrix (path));
+ twin_text_metrics_utf8 (path, TEXT, &m);
+ twin_path_translate (stroke, TWIN_FIXED_HALF, TWIN_FIXED_HALF);
+ twin_path_move (stroke, fx, fy);
+ twin_path_draw (stroke, fx + m.width, fy);
+ twin_paint_stroke (pixmap, 0xffff0000, stroke, D(1));
+ twin_path_empty (stroke);
+ twin_path_move (stroke,
+ fx + m.left_side_bearing, fy - m.ascent);
+ twin_path_draw (stroke,
+ fx + m.right_side_bearing, fy - m.ascent);
+ twin_path_draw (stroke,
+ fx + m.right_side_bearing, fy + m.descent);
+ twin_path_draw (stroke,
+ fx + m.left_side_bearing, fy + m.descent);
+ twin_path_draw (stroke,
+ fx + m.left_side_bearing, fy - m.ascent);
+ twin_paint_stroke (pixmap, 0xff00ff00, stroke, D(1));
+ twin_path_destroy (stroke);
+ }
+ }
+ twin_window_show (window);
+}
+
+static void
+twin_extents_start (twin_screen_t *screen, const char *name, int x, int y, int w, int h)
+{
+}
+
+void
+twin_demo_start (twin_screen_t *screen, const char *name, int x, int y, int w, int h)
+{
+ twin_circletext_start (screen, x, y, w, h);
+ twin_line_start (screen, x += 20, y += 20, w, h);
+ twin_quickbrown_start (screen, x += 20, y += 20, w, h);
+ twin_ascii_start (screen, x += 20, y += 20, w, h);
+ twin_jelly_start (screen, x += 20, y += 20, w, h);
+#if 0
+
+#if 0
+ path = twin_path_create ();
+
+ twin_path_rotate (path, -TWIN_ANGLE_45);
+ twin_path_translate (path, D(10), D(2));
+ for (s = 0; s < 40; s++)
+ {
+ twin_path_rotate (path, TWIN_ANGLE_11_25 / 16);
+ twin_path_scale (path, D(1.125), D(1.125));
+ twin_path_move (path, D(0), D(0));
+ twin_path_draw (path, D(1), D(0));
+ twin_path_draw (path, D(1), D(1));
+ twin_path_draw (path, D(0), D(1));
+ }
+
+ twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, w, h);
+ twin_fill_path (alpha, path);
+
+ source.source_kind = TWIN_SOLID;
+ source.u.argb = 0xffff0000;
+ mask.source_kind = TWIN_PIXMAP;
+ mask.u.pixmap = alpha;
+ twin_composite (red, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
+ w, h);
+#endif
+
+#if 0
+ path = twin_path_create ();
+ stroke = twin_path_create ();
+
+ twin_path_translate (stroke, D(62), D(62));
+ twin_path_scale (stroke,D(60),D(60));
+ for (s = 0; s < 60; s++)
+ {
+ twin_state_t save = twin_path_save (stroke);
+ twin_angle_t a = s * TWIN_ANGLE_90 / 15;
+
+ twin_path_rotate (stroke, a);
+ twin_path_move (stroke, D(1), 0);
+ if (s % 5 == 0)
+ twin_path_draw (stroke, D(0.85), 0);
+ else
+ twin_path_draw (stroke, D(.98), 0);
+ twin_path_restore (stroke, &save);
+ }
+ twin_path_convolve (path, stroke, pen);
+ twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, w, h);
+ twin_fill_path (alpha, path);
+
+ source.source_kind = TWIN_SOLID;
+ source.u.argb = 0xffff0000;
+ mask.source_kind = TWIN_PIXMAP;
+ mask.u.pixmap = alpha;
+ twin_composite (red, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
+ w, h);
+#endif
+
+#if 0
+ path = twin_path_create ();
+ stroke = twin_path_create ();
+
+ twin_path_translate (stroke, D(100), D(100));
+ twin_path_scale (stroke, D(10), D(10));
+ twin_path_move (stroke, D(0), D(0));
+ twin_path_draw (stroke, D(10), D(0));
+ twin_path_convolve (path, stroke, pen);
+
+ twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, w, h);
+ twin_fill_path (alpha, path);
+
+ source.source_kind = TWIN_SOLID;
+ source.u.argb = 0xffff0000;
+ mask.source_kind = TWIN_PIXMAP;
+ mask.u.pixmap = alpha;
+ twin_composite (red, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
+ w, h);
+#endif
+
+#if 1
+ path = twin_path_create ();
+
+ stroke = twin_path_create ();
+
+ twin_path_move (stroke, D (10), D (40));
+ twin_path_draw (stroke, D (40), D (40));
+ twin_path_draw (stroke, D (10), D (10));
+ twin_path_move (stroke, D (10), D (50));
+ twin_path_draw (stroke, D (40), D (50));
+
+ twin_path_convolve (path, stroke, pen);
+ twin_path_destroy (stroke);
+
+ twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, w, h);
+ twin_fill_path (alpha, path, 0, 0);
+ source.source_kind = TWIN_SOLID;
+ source.u.argb = 0xff00ff00;
+ mask.source_kind = TWIN_PIXMAP;
+ mask.u.pixmap = alpha;
+ twin_composite (blue, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
+ 100, 100);
+
+ twin_path_destroy (path);
+
+ path = twin_path_create ();
+ stroke = twin_path_create ();
+
+ twin_path_move (stroke, D (50), D (50));
+ twin_path_curve (stroke, D (70), D (70), D (80), D (70), D (100), D (50));
+
+ twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, w, h);
+ twin_fill_path (alpha, stroke, 0, 0);
+
+ source.source_kind = TWIN_SOLID;
+ source.u.argb = 0xffff0000;
+ mask.source_kind = TWIN_PIXMAP;
+ mask.u.pixmap = alpha;
+ twin_composite (blue, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
+ 100, 100);
+
+ twin_path_convolve (path, stroke, pen);
+
+ twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, w, h);
+ twin_fill_path (alpha, path, 0, 0);
+
+ source.source_kind = TWIN_SOLID;
+ source.u.argb = 0xff0000ff;
+ mask.source_kind = TWIN_PIXMAP;
+ mask.u.pixmap = alpha;
+ twin_composite (blue, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
+ 100, 100);
+#endif
+
+ twin_window_show (redw);
+ twin_window_show (bluew);
+#endif
+}
diff --git a/twin_demo.h b/twin_demo.h
new file mode 100644
index 0000000..0c8a23d
--- /dev/null
+++ b/twin_demo.h
@@ -0,0 +1,33 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TWIN_DEMO_H_
+#define _TWIN_DEMO_H_
+
+#include <twin.h>
+
+void
+twin_demo_start (twin_screen_t *screen, const char *name, int x, int y, int w, int h);
+
+#endif /* _TWIN_DEMO_H_ */
diff --git a/twin_dispatch.c b/twin_dispatch.c
new file mode 100644
index 0000000..f8a00bc
--- /dev/null
+++ b/twin_dispatch.c
@@ -0,0 +1,36 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "twinint.h"
+
+void
+twin_dispatch (void)
+{
+ for (;;)
+ {
+ _twin_run_work ();
+ _twin_run_timeout ();
+ _twin_run_file (_twin_timeout_delay ());
+ }
+}
diff --git a/twin_draw.c b/twin_draw.c
index 9a8a2c6..146c5c3 100644
--- a/twin_draw.c
+++ b/twin_draw.c
@@ -275,68 +275,73 @@ twin_composite (twin_pixmap_t *dst,
{
twin_coord_t iy;
twin_coord_t left, right, top, bottom;
+ twin_coord_t sdx, sdy;
+ twin_source_u s;
+ dst_x += dst->clip.left;
+ dst_y += dst->clip.top;
left = dst_x;
right = dst_x + width;
top = dst_y;
bottom = dst_y + height;
- if (left < 0)
- left = 0;
- if (right > dst->width)
- right = dst->width;
- if (top < 0)
- top = 0;
- if (bottom > dst->height)
- bottom = dst->height;
+ /* clip */
+ if (left < dst->clip.left)
+ left = dst->clip.left;
+ if (right > dst->clip.right)
+ right = dst->clip.right;
+ if (top < dst->clip.top)
+ top = dst->clip.top;
+ if (bottom > dst->clip.bottom)
+ bottom = dst->clip.bottom;
+
if (left >= right || top >= bottom)
return;
- twin_pixmap_lock (dst);
+ if (src->source_kind == TWIN_PIXMAP)
+ {
+ src_x += src->u.pixmap->clip.left;
+ src_y += src->u.pixmap->clip.top;
+ }
+ else
+ s.c = src->u.argb;
+
+ sdx = src_x - dst_x;
+ sdy = src_y - dst_y;
+
if (msk)
{
twin_src_msk_op op;
- twin_source_u s, m;
- twin_coord_t sdx, sdy, mdx, mdy;
+ twin_source_u m;
+ twin_coord_t mdx, mdy;
+
+ if (msk->source_kind == TWIN_PIXMAP)
+ {
+ msk_x += msk->u.pixmap->clip.left;
+ msk_y += msk->u.pixmap->clip.top;
+ }
+ else
+ s.c = msk->u.argb;
- sdx = src_x - dst_x;
- sdy = src_y - dst_y;
mdx = msk_x - dst_x;
mdy = msk_y - dst_y;
-
op = comp3[operator][operand_index(src)][operand_index(msk)][dst->format];
- if (op)
- {
- if (src->source_kind == TWIN_SOLID)
- s.c = src->u.argb;
- if (msk->source_kind == TWIN_SOLID)
- s.c = msk->u.argb;
- for (iy = top; iy < bottom; iy++)
- {
- if (src->source_kind == TWIN_PIXMAP)
- s.p = twin_pixmap_pointer (src->u.pixmap, left+sdx, iy+sdy);
- if (msk->source_kind == TWIN_PIXMAP)
- m.p = twin_pixmap_pointer (msk->u.pixmap, left+mdx, iy+mdy);
- (*op) (twin_pixmap_pointer (dst, left, iy),
- s, m, right - left);
- }
- }
- else
+ for (iy = top; iy < bottom; iy++)
{
+ if (src->source_kind == TWIN_PIXMAP)
+ s.p = twin_pixmap_pointer (src->u.pixmap, left+sdx, iy+sdy);
+ if (msk->source_kind == TWIN_PIXMAP)
+ m.p = twin_pixmap_pointer (msk->u.pixmap, left+mdx, iy+mdy);
+ (*op) (twin_pixmap_pointer (dst, left, iy),
+ s, m, right - left);
}
}
else
{
twin_src_op op;
- twin_source_u s;
- twin_coord_t sdx, sdy;
-
- sdx = src_x - dst_x;
- sdy = src_y - dst_y;
op = comp2[operator][operand_index(src)][dst->format];
- if (src->source_kind == TWIN_SOLID)
- s.c = src->u.argb;
+
for (iy = top; iy < bottom; iy++)
{
if (src->source_kind == TWIN_PIXMAP)
@@ -346,7 +351,6 @@ twin_composite (twin_pixmap_t *dst,
}
}
twin_pixmap_damage (dst, left, top, right, bottom);
- twin_pixmap_unlock (dst);
}
/*
@@ -379,19 +383,24 @@ twin_fill (twin_pixmap_t *dst,
twin_source_u src;
twin_coord_t iy;
- twin_pixmap_lock (dst);
+ left += dst->clip.left;
+ right += dst->clip.left;
+ top += dst->clip.top;
+ bottom += dst->clip.top;
+ /* clip */
+ if (left < dst->clip.left)
+ left = dst->clip.left;
+ if (right > dst->clip.right)
+ right = dst->clip.right;
+ if (top < dst->clip.top)
+ top = dst->clip.top;
+ if (bottom > dst->clip.bottom)
+ bottom = dst->clip.bottom;
+ if (left >= right || top >= bottom)
+ return;
src.c = pixel;
- if (left < 0)
- left = 0;
- if (right > dst->width)
- right = dst->width;
- if (top < 0)
- top = 0;
- if (bottom > dst->height)
- bottom = dst->height;
op = fill[operator][dst->format];
for (iy = top; iy < bottom; iy++)
(*op) (twin_pixmap_pointer (dst, left, iy), src, right - left);
twin_pixmap_damage (dst, left, right, top, bottom);
- twin_pixmap_unlock (dst);
}
diff --git a/twin_fedit/Makefile b/twin_fedit/Makefile
new file mode 100644
index 0000000..eb21671
--- /dev/null
+++ b/twin_fedit/Makefile
@@ -0,0 +1,9 @@
+CFLAGS=$(shell pkg-config --cflags cairo) -g
+LIBS=$(shell pkg-config --libs cairo)
+
+OBJS=twin-fedit.o twin-sfit.o
+
+twin-fedit: $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+
+$(OBJS): twin-fedit.h
diff --git a/twin_fedit/nchars b/twin_fedit/nchars
new file mode 100644
index 0000000..2dc7c9b
--- /dev/null
+++ b/twin_fedit/nchars
@@ -0,0 +1,1021 @@
+/* 0x0 '\0' offset 0 */
+ 0, 24, 42, 0, 2, 4,
+ 0, 24, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 0, 0,
+ 'l', 0, -42,
+ 'l', 24, -42,
+ 'l', 24, 0,
+ 'l', 0, 0,
+ 'e',
+/* 0x20 ' ' offset 28 */
+ 0, 4, 0, 0, 2, 3,
+ -128, 0, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'e',
+/* 0x21 '!' offset 40 */
+ 0, 4, 42, 0, 3, 3,
+ 0, 2, 4, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 2, -42,
+ 'l', 2, -14,
+ 'm', 2, -4,
+ 'c', 1, -4, 0, -3, 0, -2,
+ 'c', 0, -1, 1, 0, 2, 0,
+ 'c', 3, 0, 4, -1, 4, -2,
+ 'c', 4, -3, 3, -4, 2, -4,
+ 'e',
+/* 0x22 '"' offset 90 */
+ 0, 16, 42, -28, 2, 3,
+ 0, 16, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, -28,
+ 'm', 16, -42,
+ 'l', 16, -28,
+ 'e',
+/* 0x23 '#' offset 114 */
+ 0, 30, 50, 14, 2, 5,
+ 0, 30, /* snap_x */
+ -24, -21, -15, -12, 0, /* snap_y */
+ 'm', 16, -50,
+ 'l', 2, 14,
+ 'm', 28, -50,
+ 'l', 14, 14,
+ 'm', 2, -24,
+ 'l', 30, -24,
+ 'm', 0, -12,
+ 'l', 28, -12,
+ 'e',
+/* 0x24 '$' offset 152 */
+ 0, 28, 50, 8, 4, 4,
+ 0, 10, 18, 28, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 10, -50,
+ 'l', 10, 8,
+ 'm', 18, -50,
+ 'l', 18, 8,
+ 'm', 28, -36,
+ 'c', 24, -42, 18, -42, 14, -42,
+ 'c', 10, -42, 0, -42, 0, -34,
+ 'c', 0, -25, 8, -24, 14, -22,
+ 'c', 20, -20, 28, -19, 28, -9,
+ 'c', 28, 0, 18, 0, 14, 0,
+ 'c', 10, 0, 4, 0, 0, -6,
+ 'e',
+/* 0x25 '%' offset 224 */
+ 0, 36, 42, 0, 4, 7,
+ 0, 14, 22, 36, /* snap_x */
+ -42, -38, -28, -21, -15, -14, 0, /* snap_y */
+ 'm', 36, -42,
+ 'l', 0, 0,
+ 'm', 10, -42,
+ 'c', 12, -41, 14, -40, 14, -36,
+ 'c', 14, -30, 11, -28, 6, -28,
+ 'c', 2, -28, 0, -30, 0, -34,
+ 'c', 0, -39, 3, -42, 8, -42,
+ 'l', 10, -42,
+ 'c', 18, -37, 28, -37, 36, -42,
+ 'm', 28, -14,
+ 'c', 24, -14, 22, -11, 22, -6,
+ 'c', 22, -2, 24, 0, 28, 0,
+ 'c', 33, 0, 36, -2, 36, -8,
+ 'c', 36, -12, 34, -14, 30, -14,
+ 'l', 28, -14,
+ 'e',
+/* 0x26 '&' offset 323 */
+ 0, 40, 42, 0, 4, 4,
+ 0, 10, 22, 40, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 40, -24,
+ 'c', 40, -27, 39, -28, 37, -28,
+ 'c', 29, -28, 32, 0, 12, 0,
+ 'c', 0, 0, 0, -8, 0, -10,
+ 'c', 0, -24, 22, -20, 22, -34,
+ 'c', 22, -45, 10, -45, 10, -34,
+ 'c', 10, -27, 25, 0, 36, 0,
+ 'c', 39, 0, 40, -1, 40, -4,
+ 'e',
+/* 0x27 ''' offset 390 */
+ 0, 4, 42, -30, 2, 3,
+ 0, 4, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 2, -38,
+ 'c', -1, -38, -1, -42, 2, -42,
+ 'c', 6, -42, 5, -33, 0, -30,
+ 'e',
+/* 0x28 '(' offset 419 */
+ 0, 14, 50, 14, 2, 3,
+ 0, 14, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 14, -50,
+ 'c', -5, -32, -5, -5, 14, 14,
+ 'e',
+/* 0x29 ')' offset 441 */
+ 0, 14, 50, 14, 2, 3,
+ 0, 14, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -50,
+ 'c', 19, -34, 19, -2, 0, 14,
+ 'e',
+/* 0x2a '*' offset 463 */
+ 0, 20, 30, -6, 3, 3,
+ 0, 10, 20, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 10, -30,
+ 'l', 10, -6,
+ 'm', 0, -24,
+ 'l', 20, -12,
+ 'm', 20, -24,
+ 'l', 0, -12,
+ 'e',
+/* 0x2b '+' offset 494 */
+ 0, 36, 36, 0, 3, 4,
+ 0, 18, 36, /* snap_x */
+ -21, -18, -15, 0, /* snap_y */
+ 'm', 18, -36,
+ 'l', 18, 0,
+ 'm', 0, -18,
+ 'l', 36, -18,
+ 'e',
+/* 0x2c ',' offset 520 */
+ 0, 4, 4, 8, 2, 3,
+ 0, 4, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 4, -2,
+ 'c', 4, 1, 0, 1, 0, -2,
+ 'c', 0, -5, 4, -5, 4, -2,
+ 'c', 4, 4, 2, 6, 0, 8,
+ 'e',
+/* 0x2d '-' offset 556 */
+ 0, 36, 18, -18, 2, 4,
+ 0, 36, /* snap_x */
+ -21, -18, -15, 0, /* snap_y */
+ 'm', 0, -18,
+ 'l', 36, -18,
+ 'e',
+/* 0x2e '.' offset 575 */
+ 0, 4, 4, 0, 2, 3,
+ 0, 4, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 2, -4,
+ 'c', -1, -4, -1, 0, 2, 0,
+ 'c', 5, 0, 5, -4, 2, -4,
+ 'e',
+/* 0x2f '/' offset 604 */
+ 0, 36, 50, 14, 2, 3,
+ 0, 36, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 36, -50,
+ 'l', 0, 14,
+ 'e',
+/* 0x30 '0' offset 622 */
+ 0, 28, 42, 0, 2, 4,
+ 0, 28, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 14, -42,
+ 'c', 9, -42, 0, -42, 0, -21,
+ 'c', 0, 0, 9, 0, 14, 0,
+ 'c', 19, 0, 28, 0, 28, -21,
+ 'c', 28, -42, 19, -42, 14, -42,
+ 'e',
+/* 0x31 '1' offset 666 */
+ 0, 10, 42, 0, 2, 3,
+ 0, 10, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -34,
+ 'c', 4, -35, 8, -38, 10, -42,
+ 'l', 10, 0,
+ 'e',
+/* 0x32 '2' offset 691 */
+ 0, 28, 42, 0, 4, 4,
+ 0, 2, 26, 28, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 2, -32,
+ 'c', 2, -34, 2, -42, 14, -42,
+ 'c', 26, -42, 26, -34, 26, -32,
+ 'c', 26, -30, 25, -25, 10, -10,
+ 'l', 0, 0,
+ 'l', 28, 0,
+ 'e',
+/* 0x33 '3' offset 736 */
+ 0, 28, 42, 0, 2, 5,
+ 0, 28, /* snap_x */
+ -42, -26, -21, -15, 0, /* snap_y */
+ 'm', 4, -42,
+ 'l', 26, -42,
+ 'l', 14, -26,
+ 'c', 21, -26, 28, -26, 28, -14,
+ 'c', 28, 0, 17, 0, 13, 0,
+ 'c', 8, 0, 3, -1, 0, -8,
+ 'e',
+/* 0x34 '4' offset 780 */
+ 0, 30, 42, 0, 3, 4,
+ 0, 20, 30, /* snap_x */
+ -21, -15, -14, 0, /* snap_y */
+ 'm', 20, -42,
+ 'l', 0, -14,
+ 'l', 30, -14,
+ 'm', 20, -42,
+ 'l', 20, 0,
+ 'e',
+/* 0x35 '5' offset 809 */
+ 0, 28, 42, 0, 2, 5,
+ 0, 28, /* snap_x */
+ -42, -28, -21, -15, 0, /* snap_y */
+ 'm', 24, -42,
+ 'l', 4, -42,
+ 'l', 2, -24,
+ 'c', 5, -27, 10, -28, 13, -28,
+ 'c', 16, -28, 28, -28, 28, -14,
+ 'c', 28, 0, 16, 0, 13, 0,
+ 'c', 10, 0, 3, 0, 0, -8,
+ 'e',
+/* 0x36 '6' offset 860 */
+ 0, 26, 42, 0, 2, 5,
+ 0, 26, /* snap_x */
+ -42, -26, -21, -15, 0, /* snap_y */
+ 'm', 24, -36,
+ 'c', 22, -41, 19, -42, 14, -42,
+ 'c', 9, -42, 0, -41, 0, -19,
+ 'c', 0, -1, 9, 0, 13, 0,
+ 'c', 18, 0, 26, -3, 26, -13,
+ 'c', 26, -18, 23, -26, 13, -26,
+ 'c', 10, -26, 1, -24, 0, -14,
+ 'e',
+/* 0x37 '7' offset 919 */
+ 0, 28, 42, 0, 2, 4,
+ 0, 28, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 28, -42,
+ 'l', 8, 0,
+ 'm', 0, -42,
+ 'l', 28, -42,
+ 'e',
+/* 0x38 '8' offset 944 */
+ 0, 28, 42, 0, 4, 4,
+ 0, 2, 26, 28, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 14, -42,
+ 'c', 5, -42, 2, -40, 2, -34,
+ 'c', 2, -18, 28, -32, 28, -11,
+ 'c', 28, 0, 18, 0, 14, 0,
+ 'c', 10, 0, 0, 0, 0, -11,
+ 'c', 0, -32, 26, -18, 26, -34,
+ 'c', 26, -40, 23, -42, 14, -42,
+ 'e',
+/* 0x39 '9' offset 1004 */
+ 0, 26, 42, 0, 2, 5,
+ 0, 26, /* snap_x */
+ -42, -21, -16, -15, 0, /* snap_y */
+ 'm', 26, -28,
+ 'c', 25, -16, 13, -16, 13, -16,
+ 'c', 8, -16, 0, -19, 0, -29,
+ 'c', 0, -34, 3, -42, 13, -42,
+ 'c', 24, -42, 26, -32, 26, -23,
+ 'c', 26, -14, 24, 0, 12, 0,
+ 'c', 7, 0, 4, -2, 2, -6,
+ 'e',
+/* 0x3a ':' offset 1063 */
+ 0, 4, 28, 0, 2, 3,
+ 0, 4, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 2, -28,
+ 'c', -1, -28, -1, -24, 2, -24,
+ 'c', 5, -24, 5, -28, 2, -28,
+ 'm', 2, -4,
+ 'c', -1, -4, -1, 0, 2, 0,
+ 'c', 5, 0, 5, -4, 2, -4,
+ 'e',
+/* 0x3b ';' offset 1109 */
+ 0, 4, 28, 8, 2, 3,
+ 0, 4, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 2, -28,
+ 'c', -1, -28, -1, -24, 2, -24,
+ 'c', 5, -24, 5, -28, 2, -28,
+ 'm', 4, -2,
+ 'c', 4, 1, 0, 1, 0, -2,
+ 'c', 0, -5, 4, -5, 4, -2,
+ 'c', 4, 3, 2, 6, 0, 8,
+ 'e',
+/* 0x3c '<' offset 1162 */
+ 0, 32, 36, 0, 2, 3,
+ 0, 32, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 32, -36,
+ 'l', 0, -18,
+ 'l', 32, 0,
+ 'e',
+/* 0x3d '=' offset 1183 */
+ 0, 36, 24, -12, 2, 5,
+ 0, 36, /* snap_x */
+ -24, -21, -15, -12, 0, /* snap_y */
+ 'm', 0, -24,
+ 'l', 36, -24,
+ 'm', 0, -12,
+ 'l', 36, -12,
+ 'e',
+/* 0x3e '>' offset 1209 */
+ 0, 32, 36, 0, 2, 3,
+ 0, 32, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -36,
+ 'l', 32, -18,
+ 'l', 0, 0,
+ 'e',
+/* 0x3f '?' offset 1230 */
+ 0, 24, 42, 0, 3, 4,
+ 0, 12, 24, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 0, -32,
+ 'c', 0, -34, 0, -42, 12, -42,
+ 'c', 24, -42, 24, -34, 24, -32,
+ 'c', 24, -29, 24, -24, 12, -20,
+ 'l', 12, -14,
+ 'm', 12, -4,
+ 'c', 9, -4, 9, 0, 12, 0,
+ 'c', 15, 0, 15, -4, 12, -4,
+ 'e',
+/* 0x40 '@' offset 1288 */
+ 0, 42, 42, 0, 1, 6,
+ 30, /* snap_x */
+ -42, -32, -21, -15, -10, 0, /* snap_y */
+ 'm', 30, -26,
+ 'c', 28, -31, 24, -32, 21, -32,
+ 'c', 10, -32, 10, -23, 10, -19,
+ 'c', 10, -13, 11, -10, 19, -10,
+ 'c', 30, -10, 28, -21, 30, -32,
+ 'c', 27, -10, 30, -10, 34, -10,
+ 'c', 41, -10, 42, -19, 42, -22,
+ 'c', 42, -34, 34, -42, 21, -42,
+ 'c', 9, -42, 0, -34, 0, -21,
+ 'c', 0, -9, 8, 0, 21, 0,
+ 'c', 30, 0, 34, -3, 36, -6,
+ 'e',
+/* 0x41 'A' offset 1375 */
+ 0, 32, 42, 0, 2, 4,
+ 0, 32, /* snap_x */
+ -21, -15, -14, 0, /* snap_y */
+ 'm', 16, -42,
+ 'l', 0, 0,
+ 'm', 16, -42,
+ 'l', 32, 0,
+ 'm', 6, -14,
+ 'l', 26, -14,
+ 'e',
+/* 0x42 'B' offset 1406 */
+ 0, 28, 42, 0, 2, 5,
+ 0, 28, /* snap_x */
+ -42, -22, -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 0, -42,
+ 'l', 18, -42,
+ 'c', 32, -42, 32, -22, 18, -22,
+ 'm', 0, -22,
+ 'l', 18, -22,
+ 'c', 32, -22, 32, 0, 18, 0,
+ 'l', 0, 0,
+ 'e',
+/* 0x43 'C' offset 1455 */
+ 0, 30, 42, 0, 2, 4,
+ 0, 30, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 30, -32,
+ 'c', 26, -42, 21, -42, 16, -42,
+ 'c', 2, -42, 0, -29, 0, -21,
+ 'c', 0, -13, 2, 0, 16, 0,
+ 'c', 21, 0, 26, 0, 30, -10,
+ 'e',
+/* 0x44 'D' offset 1499 */
+ 0, 28, 42, 0, 2, 4,
+ 0, 28, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 0, -42,
+ 'l', 14, -42,
+ 'c', 33, -42, 33, 0, 14, 0,
+ 'l', 0, 0,
+ 'e',
+/* 0x45 'E' offset 1534 */
+ 0, 26, 42, 0, 2, 5,
+ 0, 26, /* snap_x */
+ -42, -22, -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 0, -42,
+ 'l', 26, -42,
+ 'm', 0, -22,
+ 'l', 16, -22,
+ 'm', 0, 0,
+ 'l', 26, 0,
+ 'e',
+/* 0x46 'F' offset 1572 */
+ 0, 26, 42, 0, 2, 5,
+ 0, 26, /* snap_x */
+ -42, -22, -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 0, -42,
+ 'l', 26, -42,
+ 'm', 0, -22,
+ 'l', 16, -22,
+ 'e',
+/* 0x47 'G' offset 1604 */
+ 0, 30, 42, 0, 2, 5,
+ 0, 30, /* snap_x */
+ -42, -21, -16, -15, 0, /* snap_y */
+ 'm', 30, -32,
+ 'c', 26, -42, 21, -42, 16, -42,
+ 'c', 2, -42, 0, -29, 0, -21,
+ 'c', 0, -13, 2, 0, 16, 0,
+ 'c', 28, 0, 30, -7, 30, -16,
+ 'm', 20, -16,
+ 'l', 30, -16,
+ 'e',
+/* 0x48 'H' offset 1655 */
+ 0, 28, 42, 0, 2, 4,
+ 0, 28, /* snap_x */
+ -22, -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 28, -42,
+ 'l', 28, 0,
+ 'm', 0, -22,
+ 'l', 28, -22,
+ 'e',
+/* 0x49 'I' offset 1686 */
+ 0, 0, 42, 0, 1, 3,
+ 0, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'e',
+/* 0x4a 'J' offset 1703 */
+ 0, 20, 42, 0, 2, 3,
+ 0, 20, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 20, -42,
+ 'l', 20, -10,
+ 'c', 20, 3, 0, 3, 0, -10,
+ 'l', 0, -14,
+ 'e',
+/* 0x4b 'K' offset 1731 */
+ 0, 28, 42, 0, 2, 3,
+ 0, 28, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 28, -42,
+ 'l', 0, -14,
+ 'm', 10, -24,
+ 'l', 28, 0,
+ 'e',
+/* 0x4c 'L' offset 1761 */
+ 0, 24, 42, 0, 2, 3,
+ 0, 24, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 0, 0,
+ 'l', 24, 0,
+ 'e',
+/* 0x4d 'M' offset 1785 */
+ 0, 32, 42, 0, 2, 3,
+ 0, 32, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 0, -42,
+ 'l', 16, 0,
+ 'm', 32, -42,
+ 'l', 16, 0,
+ 'm', 32, -42,
+ 'l', 32, 0,
+ 'e',
+/* 0x4e 'N' offset 1821 */
+ 0, 28, 42, 0, 2, 3,
+ 0, 28, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 0, -42,
+ 'l', 28, 0,
+ 'm', 28, -42,
+ 'l', 28, 0,
+ 'e',
+/* 0x4f 'O' offset 1851 */
+ 0, 32, 42, 0, 2, 4,
+ 0, 32, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 16, -42,
+ 'c', 2, -42, 0, -29, 0, -21,
+ 'c', 0, -13, 2, 0, 16, 0,
+ 'c', 30, 0, 32, -13, 32, -21,
+ 'c', 32, -29, 30, -42, 16, -42,
+ 'e',
+/* 0x50 'P' offset 1895 */
+ 0, 28, 42, 0, 2, 5,
+ 0, 28, /* snap_x */
+ -42, -21, -20, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 0, -42,
+ 'l', 18, -42,
+ 'c', 32, -42, 32, -20, 18, -20,
+ 'l', 0, -20,
+ 'e',
+/* 0x51 'Q' offset 1931 */
+ 0, 32, 42, 4, 2, 4,
+ 0, 32, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 16, -42,
+ 'c', 2, -42, 0, -29, 0, -21,
+ 'c', 0, -13, 2, 0, 16, 0,
+ 'c', 30, 0, 32, -13, 32, -21,
+ 'c', 32, -29, 30, -42, 16, -42,
+ 'm', 18, -8,
+ 'l', 30, 4,
+ 'e',
+/* 0x52 'R' offset 1981 */
+ 0, 28, 42, 0, 2, 5,
+ 0, 28, /* snap_x */
+ -42, -22, -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 0, -42,
+ 'l', 18, -42,
+ 'c', 32, -42, 31, -22, 18, -22,
+ 'l', 0, -22,
+ 'm', 14, -22,
+ 'l', 28, 0,
+ 'e',
+/* 0x53 'S' offset 2023 */
+ 0, 28, 42, 0, 2, 4,
+ 0, 28, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 28, -36,
+ 'c', 25, -41, 21, -42, 14, -42,
+ 'c', 10, -42, 0, -42, 0, -34,
+ 'c', 0, -17, 28, -28, 28, -9,
+ 'c', 28, 0, 19, 0, 14, 0,
+ 'c', 7, 0, 3, -1, 0, -6,
+ 'e',
+/* 0x54 'T' offset 2074 */
+ 0, 28, 42, 0, 3, 4,
+ 0, 14, 28, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 14, -42,
+ 'l', 14, 0,
+ 'm', 0, -42,
+ 'l', 28, -42,
+ 'e',
+/* 0x55 'U' offset 2100 */
+ 0, 28, 42, 0, 2, 3,
+ 0, 28, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, -12,
+ 'c', 0, 4, 28, 4, 28, -12,
+ 'l', 28, -42,
+ 'e',
+/* 0x56 'V' offset 2128 */
+ 0, 32, 42, 0, 2, 3,
+ 0, 32, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 16, 0,
+ 'm', 32, -42,
+ 'l', 16, 0,
+ 'e',
+/* 0x57 'W' offset 2152 */
+ 0, 40, 42, 0, 2, 3,
+ 0, 40, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 10, 0,
+ 'm', 20, -42,
+ 'l', 10, 0,
+ 'm', 20, -42,
+ 'l', 30, 0,
+ 'm', 40, -42,
+ 'l', 30, 0,
+ 'e',
+/* 0x58 'X' offset 2188 */
+ 0, 28, 42, 0, 2, 3,
+ 0, 28, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 28, 0,
+ 'm', 28, -42,
+ 'l', 0, 0,
+ 'e',
+/* 0x59 'Y' offset 2212 */
+ 0, 32, 42, 0, 3, 3,
+ 0, 16, 32, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 16, -22,
+ 'l', 16, 0,
+ 'm', 32, -42,
+ 'l', 16, -22,
+ 'e',
+/* 0x5a 'Z' offset 2240 */
+ 0, 28, 42, 0, 2, 4,
+ 0, 28, /* snap_x */
+ -42, -21, -15, 0, /* snap_y */
+ 'm', 28, -42,
+ 'l', 0, 0,
+ 'm', 0, -42,
+ 'l', 28, -42,
+ 'm', 0, 0,
+ 'l', 28, 0,
+ 'e',
+/* 0x5b '[' offset 2271 */
+ 0, 14, 44, 0, 2, 4,
+ 0, 14, /* snap_x */
+ -44, -21, -15, 0, /* snap_y */
+ 'm', 14, -44,
+ 'l', 0, -44,
+ 'l', 0, 0,
+ 'l', 14, 0,
+ 'e',
+/* 0x5c '\' offset 2296 */
+ 0, 36, 50, 14, 2, 3,
+ 0, 36, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -50,
+ 'l', 36, 14,
+ 'e',
+/* 0x5d ']' offset 2314 */
+ 0, 14, 44, 0, 2, 4,
+ 0, 14, /* snap_x */
+ -44, -21, -15, 0, /* snap_y */
+ 'm', 0, -44,
+ 'l', 14, -44,
+ 'l', 14, 0,
+ 'l', 0, 0,
+ 'e',
+/* 0x5e '^' offset 2339 */
+ 0, 32, 46, -18, 2, 3,
+ 0, 32, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 16, -46,
+ 'l', 0, -18,
+ 'm', 16, -46,
+ 'l', 32, -18,
+ 'e',
+/* 0x5f '_' offset 2363 */
+ 0, 36, 0, 0, 2, 3,
+ 0, 36, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, 0,
+ 'l', 36, 0,
+ 'e',
+/* 0x60 '`' offset 2381 */
+ 0, 4, 42, -30, 2, 3,
+ 0, 4, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 4, -42,
+ 'c', 2, -40, 0, -39, 0, -32,
+ 'c', 0, -31, 1, -30, 2, -30,
+ 'c', 5, -30, 5, -34, 2, -34,
+ 'e',
+/* 0x61 'a' offset 2417 */
+ 0, 24, 28, 0, 2, 4,
+ 0, 24, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 24, -28,
+ 'l', 24, 0,
+ 'm', 24, -22,
+ 'c', 21, -27, 18, -28, 13, -28,
+ 'c', 2, -28, 0, -19, 0, -14,
+ 'c', 0, -9, 2, 0, 13, 0,
+ 'c', 18, 0, 21, -1, 24, -6,
+ 'e',
+/* 0x62 'b' offset 2467 */
+ 0, 24, 42, 0, 2, 4,
+ 0, 24, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 0, -22,
+ 'c', 3, -26, 6, -28, 11, -28,
+ 'c', 22, -28, 24, -19, 24, -14,
+ 'c', 24, -9, 22, 0, 11, 0,
+ 'c', 6, 0, 3, -2, 0, -6,
+ 'e',
+/* 0x63 'c' offset 2517 */
+ 0, 24, 28, 0, 2, 4,
+ 0, 24, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 24, -22,
+ 'c', 21, -26, 18, -28, 13, -28,
+ 'c', 2, -28, 0, -19, 0, -14,
+ 'c', 0, -9, 2, 0, 13, 0,
+ 'c', 18, 0, 21, -2, 24, -6,
+ 'e',
+/* 0x64 'd' offset 2561 */
+ 0, 24, 42, 0, 2, 4,
+ 0, 24, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 24, -42,
+ 'l', 24, 0,
+ 'm', 24, -22,
+ 'c', 21, -26, 18, -28, 13, -28,
+ 'c', 2, -28, 0, -19, 0, -14,
+ 'c', 0, -9, 2, 0, 13, 0,
+ 'c', 18, 0, 21, -2, 24, -6,
+ 'e',
+/* 0x65 'e' offset 2611 */
+ 0, 24, 28, 0, 2, 5,
+ 0, 24, /* snap_x */
+ -28, -21, -16, -15, 0, /* snap_y */
+ 'm', 0, -16,
+ 'l', 24, -16,
+ 'c', 24, -20, 24, -28, 13, -28,
+ 'c', 2, -28, 0, -19, 0, -14,
+ 'c', 0, -9, 2, 0, 13, 0,
+ 'c', 18, 0, 21, -2, 24, -6,
+ 'e',
+/* 0x66 'f' offset 2659 */
+ 0, 16, 42, 0, 3, 5,
+ 0, 6, 16, /* snap_x */
+ -42, -28, -21, -15, 0, /* snap_y */
+ 'm', 16, -42,
+ 'c', 8, -42, 6, -40, 6, -34,
+ 'l', 6, 0,
+ 'm', 0, -28,
+ 'l', 14, -28,
+ 'e',
+/* 0x67 'g' offset 2693 */
+ 0, 24, 28, 14, 2, 5,
+ 0, 24, /* snap_x */
+ -28, -21, -15, 0, 14, /* snap_y */
+ 'm', 24, -28,
+ 'l', 24, 4,
+ 'c', 23, 14, 16, 14, 13, 14,
+ 'c', 10, 14, 8, 14, 6, 12,
+ 'm', 24, -22,
+ 'c', 21, -26, 18, -28, 13, -28,
+ 'c', 2, -28, 0, -19, 0, -14,
+ 'c', 0, -9, 2, 0, 13, 0,
+ 'c', 18, 0, 21, -2, 24, -6,
+ 'e',
+/* 0x68 'h' offset 2758 */
+ 0, 22, 42, 0, 2, 4,
+ 0, 22, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 0, -20,
+ 'c', 8, -32, 22, -31, 22, -20,
+ 'l', 22, 0,
+ 'e',
+/* 0x69 'i' offset 2790 */
+ 0, 4, 44, 0, 3, 3,
+ 0, 2, 4, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'c', 0, -39, 4, -39, 4, -42,
+ 'c', 4, -45, 0, -45, 0, -42,
+ 'm', 2, -28,
+ 'l', 2, 0,
+ 'e',
+/* 0x6a 'j' offset 2826 */
+ -8, 4, 44, 14, 3, 4,
+ 0, 2, 4, /* snap_x */
+ -21, -15, 0, 14, /* snap_y */
+ 'm', 0, -42,
+ 'c', 0, -39, 4, -39, 4, -42,
+ 'c', 4, -45, 0, -45, 0, -42,
+ 'm', 2, -28,
+ 'l', 2, 6,
+ 'c', 2, 13, -1, 14, -8, 14,
+ 'e',
+/* 0x6b 'k' offset 2870 */
+ 0, 22, 42, 0, 2, 3,
+ 0, 22, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'm', 20, -28,
+ 'l', 0, -8,
+ 'm', 8, -16,
+ 'l', 22, 0,
+ 'e',
+/* 0x6c 'l' offset 2900 */
+ 0, 0, 42, 0, 1, 3,
+ 0, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -42,
+ 'l', 0, 0,
+ 'e',
+/* 0x6d 'm' offset 2917 */
+ 0, 44, 28, 0, 3, 4,
+ 0, 22, 44, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 0, -28,
+ 'l', 0, 0,
+ 'm', 0, -20,
+ 'c', 5, -29, 22, -33, 22, -20,
+ 'l', 22, 0,
+ 'm', 22, -20,
+ 'c', 27, -29, 44, -33, 44, -20,
+ 'l', 44, 0,
+ 'e',
+/* 0x6e 'n' offset 2963 */
+ 0, 22, 28, 0, 2, 4,
+ 0, 22, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 0, -28,
+ 'l', 0, 0,
+ 'm', 0, -20,
+ 'c', 4, -28, 22, -34, 22, -20,
+ 'l', 22, 0,
+ 'e',
+/* 0x6f 'o' offset 2995 */
+ 0, 26, 28, 0, 2, 4,
+ 0, 26, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 13, -28,
+ 'c', 2, -28, 0, -19, 0, -14,
+ 'c', 0, -9, 2, 0, 13, 0,
+ 'c', 24, 0, 26, -9, 26, -14,
+ 'c', 26, -19, 24, -28, 13, -28,
+ 'e',
+/* 0x70 'p' offset 3039 */
+ 0, 24, 28, 14, 2, 4,
+ 0, 24, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 0, -28,
+ 'l', 0, 14,
+ 'm', 0, -22,
+ 'c', 3, -26, 6, -28, 11, -28,
+ 'c', 22, -28, 24, -19, 24, -14,
+ 'c', 24, -9, 22, 0, 11, 0,
+ 'c', 6, 0, 3, -2, 0, -6,
+ 'e',
+/* 0x71 'q' offset 3089 */
+ 0, 24, 28, 14, 2, 4,
+ 0, 24, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 24, -28,
+ 'l', 24, 14,
+ 'm', 24, -22,
+ 'c', 21, -26, 18, -28, 13, -28,
+ 'c', 2, -28, 0, -19, 0, -14,
+ 'c', 0, -9, 2, 0, 13, 0,
+ 'c', 18, 0, 21, -2, 24, -6,
+ 'e',
+/* 0x72 'r' offset 3139 */
+ 0, 16, 28, 0, 2, 4,
+ 0, 16, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 0, -28,
+ 'l', 0, 0,
+ 'm', 0, -16,
+ 'c', 2, -27, 7, -28, 16, -28,
+ 'e',
+/* 0x73 's' offset 3168 */
+ 0, 22, 28, 0, 2, 4,
+ 0, 22, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 22, -22,
+ 'c', 22, -27, 16, -28, 11, -28,
+ 'c', 4, -28, 0, -26, 0, -22,
+ 'c', 0, -11, 22, -20, 22, -7,
+ 'c', 22, 0, 17, 0, 11, 0,
+ 'c', 6, 0, 0, -1, 0, -6,
+ 'e',
+/* 0x74 't' offset 3219 */
+ 0, 16, 42, 0, 3, 4,
+ 0, 6, 16, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 6, -42,
+ 'l', 6, -8,
+ 'c', 6, -2, 8, 0, 16, 0,
+ 'm', 0, -28,
+ 'l', 14, -28,
+ 'e',
+/* 0x75 'u' offset 3252 */
+ 0, 22, 28, 0, 2, 3,
+ 0, 22, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -28,
+ 'l', 0, -8,
+ 'c', 0, 6, 18, 0, 22, -8,
+ 'm', 22, -28,
+ 'l', 22, 0,
+ 'e',
+/* 0x76 'v' offset 3283 */
+ 0, 24, 28, 0, 2, 3,
+ 0, 24, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -28,
+ 'l', 12, 0,
+ 'm', 24, -28,
+ 'l', 12, 0,
+ 'e',
+/* 0x77 'w' offset 3307 */
+ 0, 32, 28, 0, 2, 3,
+ 0, 32, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -28,
+ 'l', 8, 0,
+ 'm', 16, -28,
+ 'l', 8, 0,
+ 'm', 16, -28,
+ 'l', 24, 0,
+ 'm', 32, -28,
+ 'l', 24, 0,
+ 'e',
+/* 0x78 'x' offset 3343 */
+ 0, 22, 28, 0, 2, 3,
+ 0, 22, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -28,
+ 'l', 22, 0,
+ 'm', 22, -28,
+ 'l', 0, 0,
+ 'e',
+/* 0x79 'y' offset 3367 */
+ -2, 24, 28, 14, 2, 4,
+ 0, 24, /* snap_x */
+ -21, -15, 0, 14, /* snap_y */
+ 'm', 0, -28,
+ 'l', 12, 0,
+ 'm', 24, -28,
+ 'l', 12, 0,
+ 'c', 6, 13, 0, 14, -2, 14,
+ 'e',
+/* 0x7a 'z' offset 3399 */
+ 0, 22, 28, 0, 2, 4,
+ 0, 22, /* snap_x */
+ -28, -21, -15, 0, /* snap_y */
+ 'm', 22, -28,
+ 'l', 0, 0,
+ 'm', 0, -28,
+ 'l', 22, -28,
+ 'm', 0, 0,
+ 'l', 22, 0,
+ 'e',
+/* 0x7b '{' offset 3430 */
+ 0, 16, 44, 0, 3, 5,
+ 0, 6, 16, /* snap_x */
+ -44, -24, -21, -15, 0, /* snap_y */
+ 'm', 16, -44,
+ 'c', 10, -44, 6, -42, 6, -36,
+ 'l', 6, -24,
+ 'l', 0, -24,
+ 'l', 6, -24,
+ 'l', 6, -8,
+ 'c', 6, -2, 10, 0, 16, 0,
+ 'e',
+/* 0x7c '|' offset 3474 */
+ 0, 0, 50, 14, 1, 3,
+ 0, /* snap_x */
+ -21, -15, 0, /* snap_y */
+ 'm', 0, -50,
+ 'l', 0, 14,
+ 'e',
+/* 0x7d '}' offset 3491 */
+ 0, 16, 44, 0, 3, 5,
+ 0, 10, 16, /* snap_x */
+ -44, -24, -21, -15, 0, /* snap_y */
+ 'm', 0, -44,
+ 'c', 6, -44, 10, -42, 10, -36,
+ 'l', 10, -24,
+ 'l', 16, -24,
+ 'l', 10, -24,
+ 'l', 10, -8,
+ 'c', 10, -2, 6, 0, 0, 0,
+ 'e',
+/* 0x7e '~' offset 3535 */
+ 0, 36, 24, -12, 2, 5,
+ 0, 36, /* snap_x */
+ -24, -21, -15, -12, 0, /* snap_y */
+ 'm', 0, -14,
+ 'c', 1, -21, 4, -24, 8, -24,
+ 'c', 18, -24, 18, -12, 28, -12,
+ 'c', 32, -12, 35, -15, 36, -22,
+ 'e',
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 28, 40, 90, 114, 152, 224, 323, 390,
+ 419, 441, 463, 494, 520, 556, 575, 604,
+ 622, 666, 691, 736, 780, 809, 860, 919,
+ 944, 1004, 1063, 1109, 1162, 1183, 1209, 1230,
+ 1288, 1375, 1406, 1455, 1499, 1534, 1572, 1604,
+ 1655, 1686, 1703, 1731, 1761, 1785, 1821, 1851,
+ 1895, 1931, 1981, 2023, 2074, 2100, 2128, 2152,
+ 2188, 2212, 2240, 2271, 2296, 2314, 2339, 2363,
+ 2381, 2417, 2467, 2517, 2561, 2611, 2659, 2693,
+ 2758, 2790, 2826, 2870, 2900, 2917, 2963, 2995,
+ 3039, 3089, 3139, 3168, 3219, 3252, 3283, 3307,
+ 3343, 3367, 3399, 3430, 3474, 3491, 3535, 0,
diff --git a/twin_fedit/twin-fedit.c b/twin_fedit/twin-fedit.c
new file mode 100644
index 0000000..b2de59e
--- /dev/null
+++ b/twin_fedit/twin-fedit.c
@@ -0,0 +1,699 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "twin-fedit.h"
+
+Display *dpy;
+Window win;
+Visual *visual;
+int depth;
+int width = 512;
+int height = 512;
+double scale = 8;
+cairo_t *cr;
+int offset;
+
+int offsets[1024];
+
+int
+init (int argc, char **argv)
+{
+ int scr;
+ XSetWindowAttributes wa;
+ XTextProperty wm_name, icon_name;
+ XSizeHints sizeHints;
+ XWMHints wmHints;
+ XClassHint classHints;
+ Atom wm_delete_window;
+
+ dpy = XOpenDisplay (0);
+ scr = DefaultScreen (dpy);
+ visual = DefaultVisual (dpy, scr);
+ depth = DefaultDepth (dpy, scr);
+
+ wa.background_pixel = WhitePixel (dpy,scr);
+ wa.event_mask = (KeyPressMask|
+ KeyReleaseMask|
+ ButtonPressMask|
+ ButtonReleaseMask|
+ PointerMotionMask|
+ ExposureMask|
+ StructureNotifyMask);
+
+ wm_name.value = (unsigned char *) argv[0];
+ wm_name.encoding = XA_STRING;
+ wm_name.format = 8;
+ wm_name.nitems = strlen (wm_name.value) + 1;
+ icon_name = wm_name;
+
+ win = XCreateWindow (dpy, RootWindow (dpy, scr),
+ 0, 0, width, height, 0,
+ depth, InputOutput,
+ visual, CWBackPixel|CWEventMask, &wa);
+ sizeHints.flags = 0;
+ wmHints.flags = InputHint;
+ wmHints.input = True;
+ classHints.res_name = argv[0];
+ classHints.res_class = argv[0];
+ XSetWMProperties (dpy, win,
+ &wm_name, &icon_name,
+ argv, argc,
+ &sizeHints, &wmHints, 0);
+ XSetWMProtocols (dpy, win, &wm_delete_window, 1);
+
+ XMapWindow (dpy, win);
+
+ cr = cairo_create ();
+
+ cairo_set_target_drawable (cr, dpy, win);
+
+ cairo_translate (cr, 150, 420);
+ cairo_scale (cr, scale, scale);
+
+ cairo_scale_font (cr, 2);
+ return 1;
+}
+
+cmd_t *
+copy_cmd (cmd_t *cmd)
+{
+ cmd_t *n = malloc (sizeof (cmd_t));
+ if (!cmd)
+ return 0;
+ *n = *cmd;
+ n->next = copy_cmd (cmd->next);
+ return n;
+}
+
+void
+free_cmd (cmd_t *cmd)
+{
+ if (cmd)
+ {
+ free_cmd (cmd->next);
+ free (cmd);
+ }
+}
+
+cmd_t **
+before (cmd_t **head, cmd_t *cmd)
+{
+ cmd_t **prev;
+
+ for (prev = head; *prev != cmd; prev = &(*prev)->next)
+ ;
+ return prev;
+}
+
+cmd_t *
+insert_cmd (cmd_t **prev)
+{
+ cmd_t *n = malloc (sizeof (cmd_t));
+
+ n->op = OpNoop;
+ n->next = *prev;
+ *prev = n;
+ return n;
+}
+
+void
+delete_cmd (cmd_t **head, cmd_t *cmd)
+{
+ while (*head != cmd)
+ head = &(*head)->next;
+ *head = cmd->next;
+ free (cmd);
+}
+
+void
+push (char_t *c)
+{
+ cmd_stack_t *s = malloc (sizeof (cmd_stack_t));
+
+ s->cmd = copy_cmd (c->cmd);
+ s->prev = c->stack;
+ c->stack = s;
+}
+
+void
+pop (char_t *c)
+{
+ cmd_stack_t *s = c->stack;
+ if (!s)
+ return;
+ free_cmd (c->cmd);
+ c->cmd = s->cmd;
+ c->stack = s->prev;
+ c->first = 0;
+ c->last = 0;
+ free (s);
+}
+
+
+cmd_t *
+append_cmd (char_t *c)
+{
+ cmd_t **prev;
+
+ for (prev = &c->cmd; *prev; prev = &(*prev)->next);
+ return insert_cmd (prev);
+}
+
+int commas (char *line)
+{
+ int n = 0;
+ char c;
+ while ((c = *line++))
+ if (c == ',')
+ ++n;
+ return n;
+}
+
+char_t *
+read_char (void)
+{
+ char_t *c = malloc (sizeof (char_t));
+ char line[1024];
+ char op;
+ cmd_t *cmd;
+ char *comma;
+
+ c->cmd = 0;
+ c->stack = 0;
+ c->first = 0;
+ c->last = 0;
+ while (fgets (line, sizeof (line), stdin))
+ {
+ if (line[0] == '/')
+ {
+ int ucs4;
+
+ if (sscanf (line + 5, "%x", &ucs4) == 1)
+ offsets[ucs4] = offset;
+ line[strlen(line)-3] = '\0';
+ printf ("%s offset %d */\n", line, offset);
+ continue;
+ }
+ if (line[0] != ' ' || line[4] != '\'')
+ {
+ offset += commas (line);
+ printf ("%s", line);
+ continue;
+ }
+ switch (line[5]) {
+ case 'm':
+ cmd = append_cmd (c);
+ cmd->op = OpMove;
+ sscanf (line + 8, "%lf, %lf", &cmd->pt[0].x, &cmd->pt[0].y);
+ break;
+ case 'l':
+ cmd = append_cmd (c);
+ cmd->op = OpLine;
+ sscanf (line + 8, "%lf, %lf", &cmd->pt[0].x, &cmd->pt[0].y);
+ break;
+ case 'c':
+ cmd = append_cmd (c);
+ cmd->op = OpCurve;
+ sscanf (line + 8, "%lf, %lf, %lf, %lf, %lf, %lf",
+ &cmd->pt[0].x, &cmd->pt[0].y,
+ &cmd->pt[1].x, &cmd->pt[1].y,
+ &cmd->pt[2].x, &cmd->pt[2].y);
+ break;
+ case 'e':
+ return c;
+ }
+ }
+ return 0;
+}
+
+#define DOT_SIZE 1
+
+void
+dot (cairo_t *cr, double x, double y, double red, double blue, double green, double alpha)
+{
+ cairo_set_rgb_color (cr, red, blue, green);
+ cairo_set_alpha (cr, alpha);
+ cairo_set_line_width (cr, 0.7);
+ cairo_arc (cr, x, y, DOT_SIZE, 0, M_PI * 2);
+ cairo_stroke (cr);
+}
+
+void
+spot (cairo_t *cr, double x, double y, double red, double blue, double green, double alpha)
+{
+ cairo_set_rgb_color (cr, red, blue, green);
+ cairo_set_alpha (cr, alpha);
+ cairo_arc (cr, x, y, DOT_SIZE, 0, M_PI * 2);
+ cairo_fill (cr);
+}
+
+void
+draw_char (char_t *c)
+{
+ cmd_t *cmd;
+ cmd_stack_t *s;
+ int i;
+
+ XClearArea (dpy, win, 0, 0, 0, 0, False);
+
+ for (cmd = c->cmd; cmd; cmd = cmd->next)
+ {
+ double alpha;
+ double tx, ty;
+ char buf[10];
+
+ if (cmd == c->first || cmd == c->last)
+ alpha = 1;
+ else
+ alpha = 0.5;
+
+ tx = cmd->pt[0].x;
+ ty = cmd->pt[0].y;
+ switch (cmd->op) {
+ case OpMove:
+ dot (cr, cmd->pt[0].x, cmd->pt[0].y, 1, 1, 0, alpha);
+ break;
+ case OpLine:
+ dot (cr, cmd->pt[0].x, cmd->pt[0].y, 1, 0, 0, alpha);
+ break;
+ case OpCurve:
+ dot (cr, cmd->pt[0].x, cmd->pt[0].y, 0, 0, 1, alpha);
+ dot (cr, cmd->pt[1].x, cmd->pt[1].y, 0, 0, 1, alpha);
+ dot (cr, cmd->pt[2].x, cmd->pt[2].y, 0, 1, 0, alpha);
+ tx = cmd->pt[2].x;
+ ty = cmd->pt[2].y;
+ break;
+ }
+ }
+ for (s = c->stack; s; s = s->prev)
+ if (!s->prev)
+ break;
+ if (s)
+ {
+ for (cmd = s->cmd; cmd; cmd = cmd->next)
+ {
+ double alpha = 1;
+
+ switch (cmd->op) {
+ case OpMove:
+ spot (cr, cmd->pt[0].x, cmd->pt[0].y, 1, 1, 0, alpha);
+ break;
+ case OpLine:
+ spot (cr, cmd->pt[0].x, cmd->pt[0].y, 1, 0, 0, alpha);
+ break;
+ case OpCurve:
+ spot (cr, cmd->pt[0].x, cmd->pt[0].y, 0, 0, 1, alpha);
+ spot (cr, cmd->pt[1].x, cmd->pt[1].y, 0, 0, 1, alpha);
+ spot (cr, cmd->pt[2].x, cmd->pt[2].y, 0, 1, 0, alpha);
+ break;
+ }
+ }
+ }
+ cairo_set_rgb_color (cr, 0, 0, 0);
+ cairo_set_alpha (cr, 1);
+ cairo_set_line_width (cr, 0.5);
+
+ for (cmd = c->cmd; cmd; cmd = cmd->next)
+ {
+ switch (cmd->op) {
+ case OpMove:
+ cairo_move_to (cr, cmd->pt[0].x, cmd->pt[0].y);
+ break;
+ case OpLine:
+ cairo_line_to (cr, cmd->pt[0].x, cmd->pt[0].y);
+ break;
+ case OpCurve:
+ cairo_curve_to (cr,
+ cmd->pt[0].x, cmd->pt[0].y,
+ cmd->pt[1].x, cmd->pt[1].y,
+ cmd->pt[2].x, cmd->pt[2].y);
+ break;
+ default:
+ abort ();
+ }
+ }
+ cairo_stroke (cr);
+
+ for (cmd = c->cmd, i = 0; cmd; cmd = cmd->next, i++)
+ {
+ double tx, ty;
+ char buf[10];
+
+ if (cmd->op == OpCurve)
+ {
+ tx = cmd->pt[2].x;
+ ty = cmd->pt[2].y;
+ }
+ else
+ {
+ tx = cmd->pt[0].x;
+ ty = cmd->pt[0].y;
+ }
+ {
+ cairo_save (cr);
+ if (cmd == c->first)
+ cairo_set_rgb_color (cr, 0, .5, 0);
+ else if (cmd == c->last)
+ cairo_set_rgb_color (cr, 0, 0, .5);
+ else
+ cairo_set_rgb_color (cr, 0, .5, .5);
+
+ cairo_set_alpha (cr, 1);
+ cairo_move_to (cr, tx - 2, ty + 3);
+ sprintf (buf, "%d", i);
+ cairo_show_text (cr, buf);
+ cairo_restore (cr);
+ }
+ }
+}
+
+cmd_t *
+pos_to_cmd (char_t *c, cmd_t *start, int ix, int iy)
+{
+ double x = ix, y = iy;
+ double best_err = 1;
+ cmd_t *cmd, *best_cmd = 0, *next;
+
+ cairo_inverse_transform_point (cr, &x, &y);
+ if (start)
+ start = start->next;
+ if (!start)
+ start = c->cmd;
+
+ cmd = start;
+ while (cmd)
+ {
+ int i = cmd->op == OpCurve ? 2 : 0;
+ double dx = cmd->pt[i].x - x;
+ double dy = cmd->pt[i].y - y;
+ double err = sqrt (dx * dx + dy * dy);
+
+ if (err < best_err)
+ {
+ best_err = err;
+ best_cmd = cmd;
+ }
+ if (cmd->next)
+ cmd = cmd->next;
+ else
+ cmd = c->cmd;
+ if (cmd == start)
+ cmd = 0;
+ }
+ return best_cmd;
+}
+
+int
+is_before (cmd_t *before, cmd_t *after)
+{
+ if (!before) return 0;
+ if (before->next == after) return 1;
+ return is_before (before->next, after);
+}
+
+void
+order (cmd_t **first_p, cmd_t **last_p)
+{
+ if (!is_before (*first_p, *last_p))
+ {
+ cmd_t *t = *first_p;
+ *first_p = *last_p;
+ *last_p = t;
+ }
+}
+
+void
+replace_with_spline (char_t *c, cmd_t *first, cmd_t *last)
+{
+ pts_t *pts = new_pts ();
+ int n;
+ spline_t s;
+ cmd_t *cmd, *next, *save;
+
+ order (&first, &last);
+ for (cmd = first; cmd != last->next; cmd = cmd->next)
+ {
+ int i = cmd->op == OpCurve ? 2 : 0;
+
+ add_pt (pts, &cmd->pt[i]);
+ }
+
+ s = fit (pts->pt, pts->n);
+
+ push (c);
+
+ save = last->next;
+
+ for (cmd = first->next; cmd != save; cmd = next)
+ {
+ next = cmd->next;
+ delete_cmd (&c->cmd, cmd);
+ }
+
+ cmd = insert_cmd (&first->next);
+
+ cmd->op = OpCurve;
+ cmd->pt[0] = s.b;
+ cmd->pt[1] = s.c;
+ cmd->pt[2] = s.d;
+
+ dispose_pts (pts);
+ c->first = c->last = 0;
+}
+
+void
+split (char_t *c, cmd_t *first, cmd_t *last)
+{
+ cmd_t *cmd;
+
+ push (c);
+ cmd = insert_cmd (&first->next);
+ cmd->op = OpLine;
+ cmd->pt[0] = lerp (&first->pt[0], &last->pt[0]);
+ if (last->op == OpMove)
+ {
+ cmd_t *extra = insert_cmd (&last->next);
+
+ extra->op = OpLine;
+ extra->pt[0] = last->pt[0];
+ last->pt[0] = cmd->pt[0];
+ }
+ c->first = c->last = 0;
+}
+
+void
+delete (char_t *c, cmd_t *first)
+{
+ push (c);
+ delete_cmd (&c->cmd, first);
+ c->first = c->last = 0;
+}
+
+void
+tweak_spline (char_t *c, cmd_t *first, int p2, double dx, double dy)
+{
+ int i = p2 ? 1 : 0;
+
+ push (c);
+ first->pt[i].x += dx;
+ first->pt[i].y += dy;
+}
+
+void
+undo (char_t *c)
+{
+ pop (c);
+}
+
+void
+button (char_t *c, XButtonEvent *bev)
+{
+ cmd_t *first = bev->button == 1 ? c->first : c->last;
+ cmd_t *where = pos_to_cmd (c, first, bev->x, bev->y);
+
+ if (!where)
+ {
+ XBell (dpy, 50);
+ return;
+ }
+ switch (bev->button) {
+ case 1:
+ c->first = where;
+ break;
+ case 2:
+ case 3:
+ c->last = where;
+ break;
+ }
+ draw_char (c);
+}
+
+void
+play (char_t *c)
+{
+ XEvent ev;
+ char key_string[10];
+
+ XClearArea (dpy, win, 0, 0, 0, 0, True);
+ for (;;)
+ {
+ XNextEvent (dpy, &ev);
+ switch (ev.type) {
+ case KeyPress:
+ if (XLookupString ((XKeyEvent *) &ev, key_string, sizeof (key_string), 0, 0) == 1) {
+ switch (key_string[0]) {
+ case 'q':
+ return;
+ case 'c':
+ XClearArea (dpy, ev.xkey.window, 0, 0, 0, 0, True);
+ break;
+ case 's':
+ if (c->first && c->last)
+ {
+ split (c, c->first, c->last);
+ draw_char (c);
+ }
+ break;
+ case 'u':
+ undo (c);
+ draw_char (c);
+ break;
+ case 'f':
+ if (c->first && c->last)
+ {
+ replace_with_spline (c, c->first, c->last);
+ draw_char (c);
+ }
+ break;
+ case 'd':
+ if (c->first)
+ {
+ delete (c, c->first);
+ draw_char (c);
+ }
+ break;
+ }
+ }
+ else
+ {
+ cmd_t *spline;
+
+ if (c->first && c->first->op == OpCurve)
+ spline = c->first;
+ else if (c->last && c->last->op == OpCurve)
+ spline = c->last;
+ else
+ spline = 0;
+ if (spline) {
+ switch (XKeycodeToKeysym (dpy, ev.xkey.keycode, 0)) {
+ case XK_Left:
+ tweak_spline (c, spline,
+ ev.xkey.state & ShiftMask,
+ -1, 0);
+ draw_char (c);
+ break;
+ case XK_Right:
+ tweak_spline (c, spline,
+ ev.xkey.state & ShiftMask,
+ 1, 0);
+ draw_char (c);
+ break;
+ case XK_Up:
+ tweak_spline (c, spline,
+ ev.xkey.state & ShiftMask,
+ 0, -1);
+ draw_char (c);
+ break;
+ case XK_Down:
+ tweak_spline (c, spline,
+ ev.xkey.state & ShiftMask,
+ 0, 1);
+ draw_char (c);
+ break;
+ }
+ }
+ }
+ break;
+ case Expose:
+ if (ev.xexpose.count == 0)
+ draw_char (c);
+ break;
+ case ButtonPress:
+ button (c, &ev.xbutton);
+ break;
+ }
+ }
+}
+
+void
+write_char (char_t *c)
+{
+ cmd_t *cmd;
+
+ for (cmd = c->cmd; cmd; cmd = cmd->next)
+ {
+ switch (cmd->op) {
+ case OpMove:
+ printf (" 'm', %g, %g,\n", cmd->pt[0].x, cmd->pt[0].y);
+ offset += 3;
+ break;
+ case OpLine:
+ printf (" 'l', %g, %g,\n", cmd->pt[0].x, cmd->pt[0].y);
+ offset += 3;
+ break;
+ case OpCurve:
+ printf (" 'c', %g, %g, %g, %g, %g, %g,\n",
+ cmd->pt[0].x, cmd->pt[0].y,
+ cmd->pt[1].x, cmd->pt[1].y,
+ cmd->pt[2].x, cmd->pt[2].y);
+ offset += 7;
+ break;
+ }
+ }
+ printf (" 'e',\n");
+ offset += 1;
+}
+
+int
+main (int argc, char **argv)
+{
+ char_t *c;
+ int ucs4;
+
+ if (!init (argc, argv))
+ exit (1);
+ while (c = read_char ())
+ {
+ play (c);
+ write_char (c);
+ }
+ for (ucs4 = 0; ucs4 < 0x80; ucs4++)
+ {
+ if ((ucs4 & 7) == 0) printf ("\n ");
+ printf (" %4d,", offsets[ucs4]);
+ }
+ printf ("\n");
+
+ exit (0);
+}
diff --git a/twin_fedit/twin-fedit.h b/twin_fedit/twin-fedit.h
new file mode 100644
index 0000000..ccc879d
--- /dev/null
+++ b/twin_fedit/twin-fedit.h
@@ -0,0 +1,103 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TWIN_FEDIT_H_
+#define _TWIN_FEDIT_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <cairo.h>
+#include <math.h>
+#include <X11/keysym.h>
+
+typedef enum _op { OpMove, OpLine, OpCurve, OpNoop } op_t;
+
+typedef struct { double x, y; } pt_t;
+
+typedef struct _cmd {
+ struct _cmd *next;
+ op_t op;
+ pt_t pt[3];
+} cmd_t;
+
+typedef struct _cmd_stack {
+ struct _cmd_stack *prev;
+ cmd_t *cmd;
+} cmd_stack_t;
+
+typedef struct _char {
+ cmd_t *cmd;
+ cmd_stack_t *stack;
+ cmd_t *first;
+ cmd_t *last;
+} char_t;
+
+typedef struct _pts_t {
+ int n;
+ int s;
+ pt_t *pt;
+} pts_t;
+
+typedef struct _spline {
+ pt_t a, b, c, d;
+} spline_t;
+
+spline_t fit (pt_t *p, int n);
+
+double
+min (double a, double b);
+
+double
+max (double a, double b);
+
+#define abs my_abs
+
+double
+abs (double a);
+
+pts_t *
+new_pts (void);
+
+void
+dispose_pts (pts_t *pts);
+
+void
+add_pt (pts_t *pts, pt_t *pt);
+
+double
+distance_to_point (pt_t * a, pt_t * b);
+
+double
+distance_to_line (pt_t * p, pt_t * p1, pt_t * p2);
+
+double
+distance_to_segment (pt_t * p, pt_t * p1, pt_t * p2);
+
+pt_t
+lerp (pt_t *a, pt_t *b);
+
+#endif /* _TWIN_FEDIT_H_ */
diff --git a/twin_fedit/twin-sfit.c b/twin_fedit/twin-sfit.c
new file mode 100644
index 0000000..d948e2a
--- /dev/null
+++ b/twin_fedit/twin-sfit.c
@@ -0,0 +1,351 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "twin-fedit.h"
+
+double
+min (double a, double b)
+{
+ return a < b ? a : b;
+}
+
+double
+max (double a, double b)
+{
+ return a > b ? a : b;
+}
+
+double
+abs (double a)
+{
+ return a < 0 ? -a : a;
+}
+
+pts_t *
+new_pts (void)
+{
+ pts_t *pts = malloc (sizeof (pts_t));
+
+ pts->n = 0;
+ pts->s = 0;
+ pts->pt = 0;
+}
+
+void
+dispose_pts (pts_t *pts)
+{
+ if (pts->pt)
+ free (pts->pt);
+ free (pts);
+}
+
+void
+add_pt (pts_t *pts, pt_t *pt)
+{
+ if (pts->n == pts->s)
+ {
+ int ns = pts->s ? pts->s * 2 : 16;
+ pt_t *npt;
+
+ if (pts->pt)
+ pts->pt = realloc (pts->pt, ns * sizeof (pt_t));
+ else
+ pts->pt = malloc (ns * sizeof (pt_t));
+ pts->s = ns;
+ }
+ pts->pt[pts->n++] = *pt;
+}
+
+double
+distance_to_point (pt_t * a, pt_t * b)
+{
+ double dx = (b->x - a->x);
+ double dy = (b->y - a->y);
+
+ return sqrt (dx*dx + dy*dy);
+}
+
+double
+distance_to_line (pt_t * p, pt_t * p1, pt_t * p2)
+{
+ /*
+ * Convert to normal form (AX + BY + C = 0)
+ *
+ * (X - x1) * (y2 - y1) = (Y - y1) * (x2 - x1)
+ *
+ * X * (y2 - y1) - Y * (x2 - x1) - x1 * (y2 - y1) + y1 * (x2 - x1) = 0
+ *
+ * A = (y2 - y1)
+ * B = (x1 - x2)
+ * C = (y1x2 - x1y2)
+ *
+ * distance² = (AX + BC + C)² / (A² + B²)
+ */
+ double A = p2->y - p1->y;
+ double B = p1->x - p2->x;
+ double C = (p1->y * p2->x - p1->x * p2->y);
+ double den, num;
+
+ num = A * p->x + B * p->y + C;
+ den = A * A + B * B;
+ if (den == 0)
+ return distance_to_point (p, p1);
+ else
+ return sqrt ((num * num) / den);
+}
+
+double
+distance_to_segment (pt_t * p, pt_t * p1, pt_t * p2)
+{
+ double dx, dy;
+ double pdx, pdy;
+ pt_t px;
+
+ /* intersection pt_t * (px):
+
+ px = p1 + u(p2 - p1)
+ (p - px) . (p2 - p1) = 0
+
+ Thus:
+
+ u = ((p - p1) . (p2 - p1)) / (||(p2 - p1)|| ^ 2);
+ */
+
+ dx = p2->x - p1->x;
+ dy = p2->y - p1->y;
+
+ if (dx == 0 && dy == 0)
+ return distance_to_point (p, p1);
+
+ pdx = p->x - p1->x;
+ pdy = p->y - p1->y;
+
+ double u = (pdx * dx + pdy * dy) / (dx*dx + dy*dy);
+
+ if (u <= 0)
+ return distance_to_point (p, p1);
+ else if (u >= 1)
+ return distance_to_point (p, p2);
+
+ px.x = p1->x + u * (p2->x - p1->x);
+ px.y = p1->y + u * (p2->y - p1->y);
+
+ return distance_to_point (p, &px);
+}
+
+double
+distance_to_segments (pt_t * p, pts_t *s)
+{
+ double m = distance_to_segment (p, &s->pt[0], &s->pt[1]);
+ int i;
+ for (i = 1; i < s->n - 1; i++)
+ {
+ double d = distance_to_segment (p, &s->pt[i], &s->pt[i+1]);
+ m = min (d, m);
+ }
+ return m;
+}
+
+pt_t
+lerp (pt_t *a, pt_t *b)
+{
+ pt_t p;
+
+ p.x = a->x + (b->x - a->x) / 2;
+ p.y = a->y + (b->y - a->y) / 2;
+ return p;
+}
+
+void
+dcj (spline_t *s, spline_t *s1, spline_t *s2)
+{
+ pt_t ab = lerp (&s->a, &s->b);
+ pt_t bc = lerp (&s->b, &s->c);
+ pt_t cd = lerp (&s->c, &s->d);
+ pt_t abbc = lerp (&ab, &bc);
+ pt_t bccd = lerp (&bc, &cd);
+ pt_t final = lerp (&abbc, &bccd);
+
+ s1->a = s->a;
+ s1->b = ab;
+ s1->c = abbc;
+ s1->d = final;
+
+ s2->a = final;
+ s2->b = bccd;
+ s2->c = cd;
+ s2->d = s->d;
+}
+
+
+double spline_error (spline_t *s)
+{
+ double berr, cerr;
+
+ berr = distance_to_line (&s->b, &s->a, &s->d);
+ cerr = distance_to_line (&s->c, &s->a, &s->d);
+ return max (berr, cerr);
+}
+
+void decomp (pts_t *pts, spline_t *s, double tolerance)
+{
+ if (spline_error (s) <= tolerance)
+ {
+ add_pt (pts, &s->a);
+ }
+ else
+ {
+ spline_t s1, s2;
+ dcj (s, &s1, &s2);
+ decomp (pts, &s1, tolerance);
+ decomp (pts, &s2, tolerance);
+ }
+}
+
+pts_t *decompose(spline_t *s, double tolerance)
+{
+ pts_t *result = new_pts ();
+
+ decomp (result, s, tolerance);
+ add_pt (result, &s->d);
+ return result;
+}
+
+
+double
+spline_fit_error (pt_t *p, int n, spline_t *s, double tolerance)
+{
+ pts_t *sp = decompose (s, tolerance);
+ double err = 0;
+ int i;
+
+ for (i = 0; i < n; i++)
+ {
+ double e = distance_to_segments (&p[i], sp);
+ err += e * e;
+ }
+ dispose_pts (sp);
+ return err;
+}
+
+pt_t
+lerp_a (pt_t *p1, pt_t *p2, double r)
+{
+ double dx = p2->x - p1->x;
+ double dy = p2->y - p1->y;
+ pt_t pt;
+
+ pt.x = p1->x + r * dx;
+ pt.y = p1->y + r * dy;
+ return pt;
+}
+
+double
+lerp_dist (pt_t *p1, pt_t *p2, double r)
+{
+ double dx = p2->x - p1->x;
+ double dy = p2->y - p1->y;
+
+ dx *= r;
+ dy *= r;
+ return sqrt (dx * dx + dy * dy);
+}
+
+spline_t fit (pt_t *p, int n)
+{
+ spline_t s;
+ spline_t best_s;
+
+ double dist;
+
+ double start_first;
+ double stop_first;
+ double start_last;
+ double stop_last;
+ double tol = 0.5;
+ double best_err = 10000;
+ double sbx_min;
+ double sbx_max;
+ double sby_min;
+ double sby_max;
+ double scx_min;
+ double scx_max;
+ double scy_min;
+ double scy_max;
+
+ s.a = p[0];
+ s.d = p[n - 1];
+
+ dist = floor (distance_to_point (&s.a, &s.d) + 0.5);
+
+ if (s.a.x < s.d.x)
+ {
+ sbx_min = s.a.x;
+ sbx_max = s.d.x;
+
+ scx_max = s.d.x;
+ scx_min = s.a.x;
+ }
+ else
+ {
+ sbx_max = s.a.x;
+ sbx_min = s.d.x;
+
+ scx_min = s.d.x;
+ scx_max = s.a.x;
+ }
+
+ if (s.a.y < s.d.y)
+ {
+ sby_min = s.a.y;
+ sby_max = s.d.y;
+
+ scy_max = s.d.y;
+ scy_min = s.a.y;
+ }
+ else
+ {
+ sby_max = s.a.y;
+ sby_min = s.d.y;
+
+ scy_min = s.d.y;
+ scy_max = s.a.y;
+ }
+
+ tol = 0.5;
+ for (s.b.x = sbx_min; s.b.x <= sbx_max; s.b.x += 1.0)
+ for (s.b.y = sby_min; s.b.y <= sby_max; s.b.y += 1.0)
+ for (s.c.x = scx_min; s.c.x <= scx_max; s.c.x += 1.0)
+ for (s.c.y = scy_min; s.c.y <= scy_max; s.c.y += 1.0)
+ {
+ double err = spline_fit_error (p, n, &s, tol);
+
+ if (err < best_err)
+ {
+ best_err = err;
+ best_s = s;
+ }
+ }
+ return best_s;
+}
diff --git a/twin_file.c b/twin_file.c
new file mode 100644
index 0000000..bc42762
--- /dev/null
+++ b/twin_file.c
@@ -0,0 +1,124 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "twinint.h"
+
+#include <sys/poll.h>
+#include <assert.h>
+#include <unistd.h>
+
+static twin_queue_t *head;
+
+static twin_order_t
+_twin_file_order (twin_queue_t *a, twin_queue_t *b)
+{
+ twin_file_t *af = (twin_file_t *) a;
+ twin_file_t *bf = (twin_file_t *) b;
+
+ if (af->file < bf->file)
+ return TWIN_BEFORE;
+ if (af->file > bf->file)
+ return TWIN_AFTER;
+ return TWIN_AT;
+}
+
+void
+_twin_run_file (twin_time_t delay)
+{
+ twin_file_t *first;
+ twin_file_t *file;
+ int n;
+ int i;
+ int r;
+ short events;
+ twin_file_op_t op;
+ struct pollfd *polls;
+
+ first = (twin_file_t *) _twin_queue_set_order (&head);
+ if (first)
+ {
+ for (file = first, n = 0; file; file = (twin_file_t *) file->queue.order, n++);
+ polls = malloc (n * sizeof (struct pollfd));
+ if (!polls)
+ return;
+ for (file = first, i = 0; file; file = (twin_file_t *) file->queue.order, i++)
+ {
+ short events = 0;
+
+ if (file->ops & TWIN_READ)
+ events |= POLLIN;
+ if (file->ops & TWIN_WRITE)
+ events |= POLLOUT;
+ polls[i].fd = file->file;
+ polls[i].events = events;
+ }
+ r = poll (polls, n, delay);
+ if (r > 0)
+ for (file = first, i = 0; file; file = (twin_file_t *) file->queue.order, i++)
+ {
+ events = polls[i].revents;
+ assert (polls[i].fd == file->file);
+ op = 0;
+ if (events & POLLIN)
+ op |= TWIN_READ;
+ if (events & POLLOUT)
+ op |= TWIN_WRITE;
+ if (op && !(*file->proc) (file->file, op, file->closure))
+ _twin_queue_delete (&head, &file->queue);
+ }
+ _twin_queue_review_order (&first->queue);
+ free (polls);
+ }
+ else
+ {
+ if (delay > 0)
+ usleep (delay * 1000);
+ }
+}
+
+twin_file_t *
+twin_set_file (twin_file_proc_t file_proc,
+ int fd,
+ twin_file_op_t ops,
+ void *closure)
+{
+ twin_file_t *file = malloc (sizeof (twin_file_t));
+
+ if (!file)
+ return 0;
+
+ file->file = fd;
+ file->proc = file_proc;
+ file->ops = ops;
+ file->closure = closure;
+
+ _twin_queue_insert (&head, _twin_file_order, &file->queue);
+ return file;
+}
+
+void
+twin_clear_file (twin_file_t *file)
+{
+ _twin_queue_delete (&head, &file->queue);
+}
diff --git a/twin_icon.c b/twin_icon.c
new file mode 100644
index 0000000..b6579b2
--- /dev/null
+++ b/twin_icon.c
@@ -0,0 +1,184 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "twinint.h"
+
+#define G(d) ((signed char) ((d) * 64))
+
+#define ICON_THIN (1.0/20.0)
+
+#define L(v) G(v + ICON_THIN/2)
+#define T(v) G(v + ICON_THIN/2)
+#define R(v) G(v - ICON_THIN/2)
+#define B(v) G(v - ICON_THIN/2)
+const signed char _twin_itable[] = {
+ /* Menu */
+#define TWIN_MENU_POS 0
+ 'm', L(0), T(0),
+ 'd', R(1), T(0),
+ 'd', R(1), B(1),
+ 'd', L(0), B(1),
+ 'x',
+ 's',
+ 'm', G(0.2), G(0.2),
+ 'd', G(0.8), G(0.2),
+ 's',
+ 'm', G(0.2), G(0.4),
+ 'd', G(0.8), G(0.4),
+ 's',
+ 'm', G(0.2), G(0.6),
+ 'd', G(0.8), G(0.6),
+ 's',
+ 'm', G(0.2), G(0.8),
+ 'd', G(0.8), G(0.8),
+ 's',
+ 'e',
+#define TWIN_MENU_LEN 43
+ /* Minimize */
+#define TWIN_MINIMIZE_POS TWIN_MENU_POS + TWIN_MENU_LEN
+ 'm', L(0), G(0.8),
+ 'd', L(0), B(1),
+ 'd', R(1), B(1),
+ 'd', R(1), G(0.8),
+ 'x',
+ 'w', G(0.05),
+ 'p',
+ 'e',
+#define TWIN_MINIMIZE_LEN 17
+ /* Maximize */
+#define TWIN_MAXIMIZE_POS TWIN_MINIMIZE_POS + TWIN_MINIMIZE_LEN
+ 'm', L(0), T(0),
+ 'd', L(0), G(0.2),
+ 'd', R(1), G(0.2),
+ 'd', R(1), T(0),
+ 'f',
+ 'm', L(0), T(0),
+ 'd', L(0), B(1),
+ 'd', R(1), B(1),
+ 'd', R(1), T(0),
+ 'x',
+ 's',
+ 'e',
+#define TWIN_MAXIMIZE_LEN 28
+ /* Close */
+#define TWIN_CLOSE_POS TWIN_MAXIMIZE_POS + TWIN_MAXIMIZE_LEN
+ 'm', L(0), T(0),
+ 'd', L(0), T(0.1),
+ 'd', G(0.4), G(0.5),
+ 'd', L(0), B(0.9),
+ 'd', L(0), B(1),
+ 'd', L(0.1), B(1),
+ 'd', G(0.5), G(0.6),
+ 'd', R(0.9), B(1),
+ 'd', R(1), B(1),
+ 'd', R(1), B(0.9),
+ 'd', G(0.6), G(0.5),
+ 'd', R(1), T(0.1),
+ 'd', R(1), T(0),
+ 'd', R(0.9), T(0),
+ 'd', G(0.5), G(0.4),
+ 'd', L(0.1), T(0),
+ 'x',
+ 'p',
+ 'e',
+#define TWIN_CLOSE_LEN 51
+ /* Resize */
+#define TWIN_RESIZE_POS TWIN_CLOSE_POS + TWIN_CLOSE_LEN
+ 'm', L(0), G(-0.8),
+ 'd', L(0), T(0),
+ 'd', G(-0.8), T(0),
+ 'd', G(-0.8), G(0.2),
+ 'd', G(0.2), G(0.2),
+ 'd', G(0.2), G(-0.8),
+ 'x',
+ 'p',
+ 'e',
+#define TWIN_RESIZE_LEN 21
+};
+
+const uint16_t _twin_icons[] = {
+ TWIN_MENU_POS,
+ TWIN_MINIMIZE_POS,
+ TWIN_MAXIMIZE_POS,
+ TWIN_CLOSE_POS,
+ TWIN_RESIZE_POS,
+};
+
+#define V(i) (g[i] << 10)
+
+#define TWIN_ICON_FILL 0xff808080
+#define TWIN_ICON_STROKE 0xff202020
+
+void
+twin_icon_draw (twin_pixmap_t *pixmap,
+ twin_icon_t icon,
+ twin_matrix_t matrix)
+{
+ twin_path_t *path = twin_path_create ();
+ const signed char *g = _twin_itable + _twin_icons[icon];
+ twin_fixed_t stroke_width = twin_double_to_fixed (ICON_THIN);
+
+ twin_path_set_matrix (path, matrix);
+ for (;;)
+ {
+ switch (*g++) {
+ case 'm':
+ twin_path_move (path, V(0), V(1));
+ g += 2;
+ continue;
+ case 'd':
+ twin_path_draw (path, V(0), V(1));
+ g += 2;
+ continue;
+ case 'c':
+ twin_path_curve (path, V(0), V(1), V(2), V(3), V(4), V(5));
+ g += 6;
+ continue;
+ case 'x':
+ twin_path_close (path);
+ continue;
+ case 'w':
+ stroke_width = V(0);
+ g+= 1;
+ continue;
+ case 'f':
+ twin_paint_path (pixmap, TWIN_ICON_FILL, path);
+ twin_path_empty (path);
+ continue;
+ case 's':
+ twin_paint_stroke (pixmap, TWIN_ICON_STROKE, path, stroke_width);
+ twin_path_empty (path);
+ continue;
+ case 'p':
+ twin_paint_path (pixmap, TWIN_ICON_FILL, path);
+ twin_paint_stroke (pixmap, TWIN_ICON_STROKE, path, stroke_width);
+ twin_path_empty (path);
+ continue;
+ case 'e':
+ break;
+ }
+ break;
+ }
+ twin_path_destroy (path);
+}
diff --git a/twin_path.c b/twin_path.c
index 74d527a..d2eade6 100644
--- a/twin_path.c
+++ b/twin_path.c
@@ -60,12 +60,44 @@ _twin_path_subpath_first_spoint (twin_path_t *path)
return path->points[start];
}
+void
+_twin_path_sfinish (twin_path_t *path)
+{
+ switch (_twin_current_subpath_len(path)) {
+ case 1:
+ path->npoints--;
+ case 0:
+ return;
+ }
+
+ if (path->nsublen == path->size_sublen)
+ {
+ int size_sublen;
+ int *sublen;
+
+ if (path->size_sublen > 0)
+ size_sublen = path->size_sublen * 2;
+ else
+ size_sublen = 1;
+ if (path->sublen)
+ sublen = realloc (path->sublen, size_sublen * sizeof (int));
+ else
+ sublen = malloc (size_sublen * sizeof (int));
+ if (!sublen)
+ return;
+ path->sublen = sublen;
+ path->size_sublen = size_sublen;
+ }
+ path->sublen[path->nsublen] = path->npoints;
+ path->nsublen++;
+}
+
void
_twin_path_smove (twin_path_t *path, twin_sfixed_t x, twin_sfixed_t y)
{
switch (_twin_current_subpath_len (path)) {
default:
- twin_path_close (path);
+ _twin_path_sfinish (path);
case 0:
_twin_path_sdraw (path, x, y);
break;
@@ -147,33 +179,17 @@ twin_path_rdraw (twin_path_t *path, twin_fixed_t dx, twin_fixed_t dy)
void
twin_path_close (twin_path_t *path)
{
+ twin_spoint_t f;
+
switch (_twin_current_subpath_len(path)) {
- case 1:
- path->npoints--;
case 0:
- return;
- }
-
- if (path->nsublen == path->size_sublen)
- {
- int size_sublen;
- int *sublen;
-
- if (path->size_sublen > 0)
- size_sublen = path->size_sublen * 2;
- else
- size_sublen = 1;
- if (path->sublen)
- sublen = realloc (path->sublen, size_sublen * sizeof (int));
- else
- sublen = malloc (size_sublen * sizeof (int));
- if (!sublen)
- return;
- path->sublen = sublen;
- path->size_sublen = size_sublen;
+ case 1:
+ break;
+ default:
+ f = _twin_path_subpath_first_spoint (path);
+ _twin_path_sdraw (path, f.x, f.y);
+ break;
}
- path->sublen[path->nsublen] = path->npoints;
- path->nsublen++;
}
#define twin_fixed_abs(f) ((f) < 0 ? -(f) : (f))
@@ -201,7 +217,7 @@ twin_path_circle (twin_path_t *path, twin_fixed_t radius)
center = _twin_path_current_spoint (path);
- twin_path_close (path);
+ _twin_path_sfinish (path);
max_radius = _twin_matrix_max_radius (&path->state.matrix);
@@ -224,7 +240,7 @@ twin_path_circle (twin_path_t *path, twin_fixed_t radius)
center.y + _twin_matrix_dy (&path->state.matrix, x, y));
}
- twin_path_close (path);
+ _twin_path_sfinish (path);
twin_path_set_matrix (path, save);
}
@@ -246,7 +262,7 @@ twin_path_ellipse (twin_path_t *path,
center = _twin_path_current_spoint (path);
- twin_path_close (path);
+ _twin_path_sfinish (path);
max_radius = _twin_matrix_max_radius (&path->state.matrix);
@@ -269,7 +285,7 @@ twin_path_ellipse (twin_path_t *path,
center.y + _twin_matrix_dy (&path->state.matrix, x, y));
}
- twin_path_close (path);
+ _twin_path_sfinish (path);
twin_path_set_matrix (path, save);
}
@@ -376,7 +392,7 @@ twin_path_append (twin_path_t *dst, twin_path_t *src)
{
if (s < src->nsublen && p == src->sublen[s])
{
- twin_path_close (dst);
+ _twin_path_sfinish (dst);
s++;
}
_twin_path_sdraw (dst, src->points[p].x, src->points[p].y);
@@ -435,7 +451,7 @@ twin_composite_path (twin_pixmap_t *dst,
twin_coord_t width, height;
twin_path_bounds (path, &bounds);
- if (bounds.left == bounds.right)
+ if (bounds.left >= bounds.right || bounds.top >= bounds.bottom)
return;
width = bounds.right - bounds.left;
height = bounds.bottom - bounds.top;
diff --git a/twin_pixmap.c b/twin_pixmap.c
index 74704b7..8077705 100644
--- a/twin_pixmap.c
+++ b/twin_pixmap.c
@@ -42,6 +42,9 @@ twin_pixmap_create (twin_format_t format,
pixmap->format = format;
pixmap->width = width;
pixmap->height = height;
+ pixmap->clip.left = pixmap->clip.top = 0;
+ pixmap->clip.right = pixmap->width;
+ pixmap->clip.bottom = pixmap->height;
pixmap->stride = stride;
pixmap->disable = 0;
pixmap->p.v = pixmap + 1;
@@ -94,8 +97,6 @@ twin_pixmap_show (twin_pixmap_t *pixmap,
if (pixmap->screen)
twin_pixmap_hide (pixmap);
- twin_screen_lock (screen);
-
pixmap->screen = screen;
if (lower)
@@ -116,7 +117,6 @@ twin_pixmap_show (twin_pixmap_t *pixmap,
}
twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height);
- twin_screen_unlock (screen);
}
void
@@ -127,7 +127,7 @@ twin_pixmap_hide (twin_pixmap_t *pixmap)
if (!screen)
return;
- twin_screen_lock (screen);
+
twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height);
if (pixmap->up)
@@ -148,7 +148,6 @@ twin_pixmap_hide (twin_pixmap_t *pixmap)
pixmap->down = 0;
if (pixmap->disable)
twin_screen_enable_update (screen);
- twin_screen_unlock (screen);
}
twin_pointer_t
@@ -183,30 +182,50 @@ twin_pixmap_disable_update (twin_pixmap_t *pixmap)
}
void
-twin_pixmap_damage (twin_pixmap_t *pixmap,
- twin_coord_t x1, twin_coord_t y1,
- twin_coord_t x2, twin_coord_t y2)
+twin_pixmap_clip (twin_pixmap_t *pixmap,
+ twin_coord_t left, twin_coord_t top,
+ twin_coord_t right, twin_coord_t bottom)
{
- if (pixmap->screen)
- twin_screen_damage (pixmap->screen,
- x1 + pixmap->x,
- y1 + pixmap->y,
- x2 + pixmap->x,
- y2 + pixmap->y);
+ if (left > pixmap->clip.left) pixmap->clip.left = left;
+ if (top > pixmap->clip.top) pixmap->clip.top = top;
+ if (right < pixmap->clip.right) pixmap->clip.right = right;
+ if (bottom < pixmap->clip.bottom) pixmap->clip.bottom = bottom;
+ if (pixmap->clip.left >= pixmap->clip.right)
+ pixmap->clip.right = pixmap->clip.left = 0;
+ if (pixmap->clip.top >= pixmap->clip.bottom)
+ pixmap->clip.bottom = pixmap->clip.top = 0;
+}
+
+twin_rect_t
+twin_pixmap_current_clip (twin_pixmap_t *pixmap)
+{
+ return pixmap->clip;
}
void
-twin_pixmap_lock (twin_pixmap_t *pixmap)
+twin_pixmap_restore_clip (twin_pixmap_t *pixmap, twin_rect_t rect)
{
- if (pixmap->screen)
- twin_screen_lock (pixmap->screen);
+ pixmap->clip = rect;
}
void
-twin_pixmap_unlock (twin_pixmap_t *pixmap)
+twin_pixmap_reset_clip (twin_pixmap_t *pixmap)
+{
+ pixmap->clip.left = 0; pixmap->clip.top = 0;
+ pixmap->clip.right = pixmap->width; pixmap->clip.bottom = pixmap->height;
+}
+
+void
+twin_pixmap_damage (twin_pixmap_t *pixmap,
+ twin_coord_t x1, twin_coord_t y1,
+ twin_coord_t x2, twin_coord_t y2)
{
if (pixmap->screen)
- twin_screen_unlock (pixmap->screen);
+ twin_screen_damage (pixmap->screen,
+ x1 + pixmap->x,
+ y1 + pixmap->y,
+ x2 + pixmap->x,
+ y2 + pixmap->y);
}
static twin_argb32_t
@@ -238,12 +257,10 @@ twin_pixmap_transparent (twin_pixmap_t *pixmap, twin_coord_t x, twin_coord_t y)
void
twin_pixmap_move (twin_pixmap_t *pixmap, twin_coord_t x, twin_coord_t y)
{
- twin_pixmap_lock (pixmap);
twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height);
pixmap->x = x;
pixmap->y = y;
twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height);
- twin_pixmap_unlock (pixmap);
}
twin_bool_t
diff --git a/twin_poly.c b/twin_poly.c
index 2de4023..075eb22 100644
--- a/twin_poly.c
+++ b/twin_poly.c
@@ -85,7 +85,7 @@ _twin_sfixed_grid_ceil (twin_sfixed_t f)
static int
_twin_edge_build (twin_spoint_t *vertices, int nvertices, twin_edge_t *edges,
- twin_sfixed_t dx, twin_sfixed_t dy)
+ twin_sfixed_t dx, twin_sfixed_t dy, twin_sfixed_t top_y)
{
int v, nv;
int tv, bv;
@@ -120,8 +120,8 @@ _twin_edge_build (twin_spoint_t *vertices, int nvertices, twin_edge_t *edges,
/* snap top to first grid point in pixmap */
y = _twin_sfixed_grid_ceil (vertices[tv].y + dy);
- if (y < TWIN_POLY_START)
- y = TWIN_POLY_START;
+ if (y < TWIN_POLY_START + top_y)
+ y = TWIN_POLY_START + top_y;
/* skip vertices which don't span a sample row */
if (y >= vertices[bv].y + dy)
@@ -206,8 +206,8 @@ _span_fill (twin_pixmap_t *pixmap,
int col;
/* clip to pixmap */
- if (left < 0)
- left = 0;
+ if (left < twin_int_to_sfixed (pixmap->clip.left))
+ left = twin_int_to_sfixed (pixmap->clip.left);
if (right > twin_int_to_sfixed (pixmap->width))
right = twin_int_to_sfixed (pixmap->width);
@@ -311,7 +311,7 @@ _twin_edge_fill (twin_pixmap_t *pixmap, twin_edge_t *edges, int nedges)
/* step down, clipping to pixmap */
y += TWIN_POLY_STEP;
- if (twin_sfixed_trunc (y) >= pixmap->height)
+ if (twin_sfixed_trunc (y) >= pixmap->clip.bottom)
break;
/* strip out dead edges */
@@ -363,6 +363,8 @@ twin_fill_path (twin_pixmap_t *pixmap, twin_path_t *path,
edges = malloc (sizeof (twin_edge_t) * nalloc);
p = 0;
nedges = 0;
+ dx += twin_int_to_sfixed (pixmap->clip.left);
+ dy += twin_int_to_sfixed (pixmap->clip.top);
for (s = 0; s <= path->nsublen; s++)
{
int sublen;
@@ -376,7 +378,7 @@ twin_fill_path (twin_pixmap_t *pixmap, twin_path_t *path,
if (npoints > 1)
{
n = _twin_edge_build (path->points + p, npoints, edges + nedges,
- sdx, sdy);
+ sdx, sdy, twin_int_to_sfixed (pixmap->clip.top));
p = sublen;
nedges += n;
}
diff --git a/twin_queue.c b/twin_queue.c
new file mode 100644
index 0000000..6900117
--- /dev/null
+++ b/twin_queue.c
@@ -0,0 +1,95 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "twinint.h"
+
+void
+_twin_queue_insert (twin_queue_t **head,
+ twin_queue_proc_t proc,
+ twin_queue_t *new)
+{
+ twin_queue_t **prev, *q;
+
+ for (prev = head; (q = *prev); prev = &q->next)
+ if ((*proc) (new, q) == TWIN_AFTER)
+ break;
+ new->next = *prev;
+ new->order = 0;
+ new->walking = TWIN_FALSE;
+ new->deleted = TWIN_FALSE;
+ *prev = new;
+}
+
+void
+_twin_queue_remove (twin_queue_t **head,
+ twin_queue_t *old)
+{
+ twin_queue_t **prev, *q;
+
+ for (prev = head; (q = *prev); prev = &q->next)
+ if (q == old)
+ {
+ *prev = q->next;
+ break;
+ }
+}
+
+void
+_twin_queue_delete (twin_queue_t **head,
+ twin_queue_t *old)
+{
+ _twin_queue_remove (head, old);
+ old->deleted = TWIN_TRUE;
+ if (!old->walking)
+ free (old);
+}
+
+twin_queue_t *
+_twin_queue_set_order (twin_queue_t **head)
+{
+ twin_queue_t *first = *head;
+ twin_queue_t *q;
+
+ for (q = first; q; q = q->next)
+ {
+ q->order = q->next;
+ q->walking = TWIN_TRUE;
+ }
+ return first;
+}
+
+void
+_twin_queue_review_order (twin_queue_t *first)
+{
+ twin_queue_t *q, *o;
+
+ for (q = first; q; q = o)
+ {
+ o = q->order;
+ q->order = 0;
+ q->walking = TWIN_FALSE;
+ if (q->deleted)
+ free (q);
+ }
+}
diff --git a/twin_screen.c b/twin_screen.c
index 8a6f8b8..592df06 100644
--- a/twin_screen.c
+++ b/twin_screen.c
@@ -44,7 +44,6 @@ twin_screen_create (twin_coord_t width,
screen->damaged_closure = NULL;
screen->disable = 0;
screen->background = 0;
- twin_mutex_init (&screen->screen_mutex);
screen->put_begin = put_begin;
screen->put_span = put_span;
screen->closure = closure;
@@ -54,18 +53,6 @@ twin_screen_create (twin_coord_t width,
}
void
-twin_screen_lock (twin_screen_t *screen)
-{
- twin_mutex_lock (&screen->screen_mutex);
-}
-
-void
-twin_screen_unlock (twin_screen_t *screen)
-{
- twin_mutex_unlock (&screen->screen_mutex);
-}
-
-void
twin_screen_destroy (twin_screen_t *screen)
{
while (screen->bottom)
diff --git a/twin_text.c b/twin_text.c
new file mode 100644
index 0000000..161e4d5
--- /dev/null
+++ b/twin_text.c
@@ -0,0 +1,86 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <twin_text.h>
+
+#define D(x) twin_double_to_fixed(x)
+
+void
+twin_text_start (twin_screen_t *screen, const char *name, int x, int y, int w, int h)
+{
+ twin_window_t *text = twin_window_create (screen, TWIN_ARGB32,
+ WindowApplication,
+ x,y,w,h);
+ twin_fixed_t fx, fy;
+ static const char *lines[] = {
+ "Fourscore and seven years ago our fathers brought forth on",
+ "this continent a new nation, conceived in liberty and",
+ "dedicated to the proposition that all men are created equal.",
+ "",
+ "Now we are engaged in a great civil war, testing whether that",
+ "nation or any nation so conceived and so dedicated can long",
+ "endure. We are met on a great battlefield of that war. We",
+ "have come to dedicate a portion of it as a final resting",
+ "place for those who died here that the nation might live.",
+ "This we may, in all propriety do. But in a larger sense, we",
+ "cannot dedicate, we cannot consecrate, we cannot hallow this",
+ "ground. The brave men, living and dead who struggled here",
+ "have hallowed it far above our poor power to add or detract.",
+ "The world will little note nor long remember what we say here,",
+ "but it can never forget what they did here.",
+ "",
+ "It is rather for us the living, we here be dedicated to the",
+ "great task remaining before us--that from these honored",
+ "dead we take increased devotion to that cause for which they",
+ "here gave the last full measure of devotion--that we here",
+ "highly resolve that these dead shall not have died in vain, that",
+ "this nation shall have a new birth of freedom, and that",
+ "government of the people, by the people, for the people shall",
+ "not perish from the earth.",
+ 0
+ };
+ const char **l;
+ twin_path_t *path;
+
+ twin_window_set_name(text, name);
+ path = twin_path_create ();
+#define TEXT_SIZE 9
+ twin_path_set_font_size (path, D(TEXT_SIZE));
+ fx = D(3);
+ fy = D(10);
+ twin_fill (text->pixmap, 0xc0c0c0c0, TWIN_SOURCE,
+ 0, 0,
+ text->client.right - text->client.left,
+ text->client.bottom - text->client.top);
+ for (l = lines; *l; l++)
+ {
+ twin_path_move (path, fx, fy);
+ twin_path_utf8 (path, *l);
+ twin_paint_path (text->pixmap, 0xff000000, path);
+ twin_path_empty (path);
+ fy += D(TEXT_SIZE);
+ }
+ twin_window_show (text);
+}
+
diff --git a/twin_text.h b/twin_text.h
new file mode 100644
index 0000000..6abb231
--- /dev/null
+++ b/twin_text.h
@@ -0,0 +1,33 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TWIN_TEXT_H_
+#define _TWIN_TEXT_H_
+
+#include <twin.h>
+
+void
+twin_text_start (twin_screen_t *screen, const char *name, int x, int y, int w, int h);
+
+#endif /* _TWIN_TEXT_H_ */
diff --git a/twin_timeout.c b/twin_timeout.c
new file mode 100644
index 0000000..7308b3c
--- /dev/null
+++ b/twin_timeout.c
@@ -0,0 +1,127 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "twinint.h"
+
+static twin_timeout_t *head;
+static twin_time_t start;
+
+static twin_order_t
+_twin_timeout_order (twin_queue_t *a, twin_queue_t *b)
+{
+ twin_timeout_t *at = (twin_timeout_t *) a;
+ twin_timeout_t *bt = (twin_timeout_t *) b;
+
+ if (twin_time_compare (at->time, <, bt->time))
+ return TWIN_BEFORE;
+ if (twin_time_compare (at->time, >, bt->time))
+ return TWIN_AFTER;
+ return TWIN_AT;
+}
+
+static void
+_twin_queue_timeout (twin_timeout_t *timeout, twin_time_t time)
+{
+ timeout->time = time;
+ _twin_queue_remove ((twin_queue_t **) &head,
+ &timeout->queue);
+ _twin_queue_insert ((twin_queue_t **) &head,
+ _twin_timeout_order, &timeout->queue);
+}
+
+void
+_twin_run_timeout (void)
+{
+ twin_time_t now = twin_now ();
+ twin_timeout_t *timeout;
+ twin_timeout_t *first;
+ twin_time_t delay;
+
+ first = (twin_timeout_t *) _twin_queue_set_order ((twin_queue_t **) &head);
+ for (timeout = first;
+ timeout && twin_time_compare (now, >=, timeout->time);
+ timeout = (twin_timeout_t *) timeout->queue.order)
+ {
+ delay = (*timeout->proc) (now, timeout->closure);
+ if (delay >= 0)
+ {
+ _twin_queue_remove ((twin_queue_t **) &head,
+ &timeout->queue);
+ _twin_queue_timeout (timeout, twin_now () + delay);
+ }
+ else
+ _twin_queue_delete ((twin_queue_t **) &head,
+ &timeout->queue);
+ }
+ _twin_queue_review_order (&first->queue);
+}
+
+twin_timeout_t *
+twin_set_timeout (twin_timeout_proc_t timeout_proc,
+ twin_time_t delay,
+ void *closure)
+{
+ twin_timeout_t *timeout = malloc (sizeof (twin_timeout_t));
+
+ if (!timeout)
+ return 0;
+
+ if (!start)
+ start = twin_now ();
+ timeout->delay = delay;
+ timeout->proc = timeout_proc;
+ timeout->closure = closure;
+ _twin_queue_timeout (timeout, twin_now() + delay);
+ return timeout;
+}
+
+void
+twin_clear_timeout (twin_timeout_t *timeout)
+{
+ _twin_queue_delete ((twin_queue_t **) &head, &timeout->queue);
+}
+
+twin_time_t
+_twin_timeout_delay (void)
+{
+ if (head)
+ {
+ twin_time_t now = twin_now();
+ if (twin_time_compare (now, >=, head->time))
+ return 0;
+ return head->time - now;
+ }
+ return -1;
+}
+
+#include <sys/time.h>
+#include <time.h>
+
+twin_time_t
+twin_now (void)
+{
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
diff --git a/twin_window.c b/twin_window.c
index b348572..0fa1a55 100644
--- a/twin_window.c
+++ b/twin_window.c
@@ -29,7 +29,9 @@
#define TWIN_FRAME_TEXT 0xffffffff
#define TWIN_ACTIVE_BORDER 0xff606060
#define TWIN_BW 0
-#define TWIN_TITLE_HEIGHT 22
+#define TWIN_TITLE_HEIGHT 20
+#define TWIN_RESIZE_SIZE ((TWIN_TITLE_HEIGHT + 4) / 5)
+#define TWIN_TITLE_BW ((TWIN_TITLE_HEIGHT + 11) / 12)
twin_window_t *
twin_window_create (twin_screen_t *screen,
@@ -50,8 +52,8 @@ twin_window_create (twin_screen_t *screen,
case WindowApplication:
left = TWIN_BW;
top = TWIN_BW + TWIN_TITLE_HEIGHT + TWIN_BW;
- right = TWIN_BW;
- bottom = TWIN_BW;
+ right = TWIN_BW + TWIN_RESIZE_SIZE;
+ bottom = TWIN_BW + TWIN_RESIZE_SIZE;
break;
case WindowPlain:
default:
@@ -68,6 +70,9 @@ twin_window_create (twin_screen_t *screen,
window->client.top = top;
window->client.bottom = height - bottom;
window->pixmap = twin_pixmap_create (format, width, height);
+ twin_pixmap_clip (window->pixmap,
+ window->client.left, window->client.top,
+ window->client.right, window->client.bottom);
window->pixmap->window = window;
twin_pixmap_move (window->pixmap, x, y);
window->damage.left = window->damage.right = 0;
@@ -132,6 +137,9 @@ twin_window_configure (twin_window_t *window,
for (i = 0; i < old->disable; i++)
twin_pixmap_disable_update (window->pixmap);
twin_pixmap_destroy (old);
+ twin_pixmap_clip (window->pixmap,
+ window->client.left, window->client.top,
+ window->client.right, window->client.bottom);
}
if (x != window->pixmap->x || y != window->pixmap->y)
twin_pixmap_move (window->pixmap, x, y);
@@ -171,25 +179,68 @@ twin_window_set_name (twin_window_t *window,
static void
twin_window_frame (twin_window_t *window)
{
- twin_coord_t bw = 2;
+ twin_fixed_t bw = twin_int_to_fixed (TWIN_TITLE_BW);
twin_path_t *path;
- twin_coord_t name_height;
- twin_text_metrics_t m;
+ twin_fixed_t bw_2 = bw / 2;
twin_pixmap_t *pixmap = window->pixmap;
- twin_fixed_t bw_2 = twin_int_to_fixed (bw) / 2;
twin_fixed_t w_top = bw_2;
twin_fixed_t c_left = bw_2;
- twin_fixed_t t_h = twin_int_to_fixed (window->client.top - bw);
+ twin_fixed_t t_h = twin_int_to_fixed (window->client.top) - bw;
twin_fixed_t t_arc_1 = t_h / 3;
- twin_fixed_t c_right = twin_int_to_fixed (pixmap->width) - bw_2;
+ twin_fixed_t t_arc_2 = t_h * 2 / 3;
+ twin_fixed_t c_right = twin_int_to_fixed (window->client.right) - bw_2;
twin_fixed_t c_top = twin_int_to_fixed (window->client.top) - bw_2;
-
+
+ twin_fixed_t name_height = t_h - bw - bw_2;
+ twin_fixed_t icon_size = name_height * 8 / 10;
+ twin_fixed_t icon_y = (twin_int_to_fixed (window->client.top) -
+ icon_size) / 2;
+ twin_fixed_t menu_x = t_arc_2;
+ twin_fixed_t text_x = menu_x + icon_size + bw;
+ twin_fixed_t text_y = icon_y + icon_size;
+ twin_fixed_t text_width;
+ twin_fixed_t title_right;
+ twin_fixed_t close_x;
+ twin_fixed_t max_x;
+ twin_fixed_t min_x;
+ twin_fixed_t resize_x;
+ twin_fixed_t resize_y;
+ const char *name;
+
+ twin_pixmap_reset_clip (pixmap);
+
twin_fill (pixmap, 0x00000000, TWIN_SOURCE,
0, 0, pixmap->width, window->client.top);
+ path = twin_path_create ();
+
+
+ /* name */
+ name = window->name;
+ if (!name)
+ name = "Sans un nom!";
+ twin_path_set_font_size (path, name_height);
+ twin_path_set_font_style (path, TWIN_TEXT_OBLIQUE | TWIN_TEXT_UNHINTED);
+ text_width = twin_width_utf8 (path, name);
+
+ title_right = (text_x + text_width +
+ bw + icon_size +
+ bw + icon_size +
+ bw + icon_size +
+ t_arc_2);
+
+ if (title_right < c_right)
+ c_right = title_right;
+
+
+ close_x = c_right - t_arc_2 - icon_size;
+ max_x = close_x - bw - icon_size;
+ min_x = max_x - bw - icon_size;
+ resize_x = twin_int_to_fixed (window->client.right);
+ resize_y = twin_int_to_fixed (window->client.bottom);
+
/* border */
- path = twin_path_create ();
twin_path_move (path, c_left, c_top);
twin_path_draw (path, c_right, c_top);
twin_path_curve (path,
@@ -209,23 +260,54 @@ twin_window_frame (twin_window_t *window)
twin_path_empty (path);
- /* name */
- if (window->name)
+ twin_pixmap_clip (pixmap,
+ twin_fixed_to_int (twin_fixed_floor (menu_x)),
+ 0,
+ twin_fixed_to_int (twin_fixed_ceil (c_right - t_arc_2)),
+ window->client.top);
+
+ twin_path_move (path, text_x - twin_fixed_floor (menu_x), text_y);
+ twin_path_utf8 (path, window->name);
+ twin_paint_path (pixmap, TWIN_FRAME_TEXT, path);
+
+ twin_pixmap_reset_clip (pixmap);
+
+ /* widgets */
+
{
- twin_point_t t;
- name_height = window->client.top - bw * 2;
- if (name_height < 1)
- name_height = 1;
- twin_path_set_font_size (path, twin_int_to_fixed (name_height));
- twin_path_set_font_style (path, TWIN_TEXT_OBLIQUE);
- twin_text_metrics_utf8 (path, window->name, &m);
- t.x = ((c_right - c_left) -
- (m.right_side_bearing - m.left_side_bearing)) / 2;
- t.y = c_top - bw_2 * 4;
- twin_path_move (path, t.x, t.y);
- twin_path_utf8 (path, window->name);
- twin_paint_path (pixmap, TWIN_FRAME_TEXT, path);
+ twin_matrix_t m;
+
+ twin_matrix_identity (&m);
+ twin_matrix_translate (&m, menu_x, icon_y);
+ twin_matrix_scale (&m, icon_size, icon_size);
+ twin_icon_draw (pixmap, TwinIconMenu, m);
+
+ twin_matrix_identity (&m);
+ twin_matrix_translate (&m, min_x, icon_y);
+ twin_matrix_scale (&m, icon_size, icon_size);
+ twin_icon_draw (pixmap, TwinIconMinimize, m);
+
+ twin_matrix_identity (&m);
+ twin_matrix_translate (&m, max_x, icon_y);
+ twin_matrix_scale (&m, icon_size, icon_size);
+ twin_icon_draw (pixmap, TwinIconMaximize, m);
+
+ twin_matrix_identity (&m);
+ twin_matrix_translate (&m, close_x, icon_y);
+ twin_matrix_scale (&m, icon_size, icon_size);
+ twin_icon_draw (pixmap, TwinIconClose, m);
+
+ twin_matrix_identity (&m);
+ twin_matrix_translate (&m, resize_x, resize_y);
+ twin_matrix_scale (&m,
+ twin_int_to_fixed (TWIN_TITLE_HEIGHT),
+ twin_int_to_fixed (TWIN_TITLE_HEIGHT));
+ twin_icon_draw (pixmap, TwinIconResize, m);
}
+
+ twin_pixmap_clip (pixmap,
+ window->client.left, window->client.top,
+ window->client.right, window->client.bottom);
twin_path_destroy (path);
}
diff --git a/twin_work.c b/twin_work.c
new file mode 100644
index 0000000..f0e809a
--- /dev/null
+++ b/twin_work.c
@@ -0,0 +1,82 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "twinint.h"
+
+static twin_queue_t *head;
+
+static twin_order_t
+_twin_work_order (twin_queue_t *a, twin_queue_t *b)
+{
+ twin_work_t *aw = (twin_work_t *) a;
+ twin_work_t *bw = (twin_work_t *) b;
+
+ if (aw->priority < bw->priority)
+ return TWIN_BEFORE;
+ if (aw->priority > bw->priority)
+ return TWIN_AFTER;
+ return TWIN_AT;
+}
+
+static void
+_twin_queue_work (twin_work_t *work)
+{
+ _twin_queue_insert (&head, _twin_work_order, &work->queue);
+}
+
+void
+_twin_run_work (void)
+{
+ twin_work_t *work;
+ twin_work_t *first;
+
+ first = (twin_work_t *) _twin_queue_set_order (&head);
+ for (work = first; work; work = (twin_work_t *) work->queue.order)
+ if (!(*work->proc) (work->closure))
+ _twin_queue_delete (&head, &work->queue);
+ _twin_queue_review_order (&first->queue);
+}
+
+twin_work_t *
+twin_set_work (twin_work_proc_t work_proc,
+ int priority,
+ void *closure)
+{
+ twin_work_t *work = malloc (sizeof (twin_work_t));
+
+ if (!work)
+ return 0;
+
+ work->proc = work_proc;
+ work->priority = priority;
+ work->closure = closure;
+ _twin_queue_work (work);
+ return work;
+}
+
+void
+twin_clear_work (twin_work_t *work)
+{
+ _twin_queue_delete (&head, &work->queue);
+}
diff --git a/twin_x11.c b/twin_x11.c
index 495c728..ad51015 100644
--- a/twin_x11.c
+++ b/twin_x11.c
@@ -82,36 +82,18 @@ _twin_x11_put_span (twin_coord_t left,
}
}
-static void *
-twin_x11_damage_thread (void *arg)
+static twin_bool_t
+twin_x11_read_events (int file,
+ twin_file_op_t ops,
+ void *closure)
{
- twin_x11_t *tx = arg;
+ twin_x11_t *tx = closure;
- twin_mutex_lock (&tx->screen->screen_mutex);
- for (;;)
+ while (XEventsQueued (tx->dpy, QueuedAfterReading))
{
- twin_cond_wait (&tx->damage_cond, &tx->screen->screen_mutex);
- if (!tx->win)
- break;
- if (twin_screen_damaged (tx->screen))
- {
- twin_x11_update (tx);
- XFlush (tx->dpy);
- }
- }
- twin_mutex_unlock (&tx->screen->screen_mutex);
- return 0;
-}
+ XEvent ev;
+ twin_event_t tev;
-static void *
-twin_x11_event_thread (void *arg)
-{
- twin_x11_t *tx = arg;
- XEvent ev;
- twin_event_t tev;
-
- for (;;)
- {
XNextEvent (tx->dpy, &ev);
switch (ev.type) {
case Expose:
@@ -136,14 +118,20 @@ twin_x11_event_thread (void *arg)
break;
}
}
+ return TWIN_TRUE;
}
-static void
-twin_x11_screen_damaged (void *closure)
+static twin_bool_t
+twin_x11_work (void *closure)
{
- twin_x11_t *tx = closure;
-
- twin_cond_broadcast (&tx->damage_cond);
+ twin_x11_t *tx = closure;
+
+ if (twin_screen_damaged (tx->screen))
+ {
+ twin_x11_update (tx);
+ XFlush (tx->dpy);
+ }
+ return TWIN_TRUE;
}
twin_x11_t *
@@ -167,6 +155,13 @@ twin_x11_create (Display *dpy, int width, int height)
tx->visual = DefaultVisual (dpy, scr);
tx->depth = DefaultDepth (dpy, scr);
+ twin_set_file (twin_x11_read_events,
+ ConnectionNumber (dpy),
+ TWIN_READ,
+ tx);
+
+ twin_set_work (twin_x11_work, TWIN_WORK_REDISPLAY, tx);
+
wa.background_pixmap = None;
wa.event_mask = (KeyPressMask|
KeyReleaseMask|
@@ -200,16 +195,9 @@ twin_x11_create (Display *dpy, int width, int height)
tx->gc = XCreateGC (dpy, tx->win, 0, 0);
tx->screen = twin_screen_create (width, height, _twin_x11_put_begin,
_twin_x11_put_span, tx);
- twin_screen_register_damaged (tx->screen, twin_x11_screen_damaged, tx);
XMapWindow (dpy, tx->win);
- twin_cond_init (&tx->damage_cond);
-
- twin_thread_create (&tx->damage_thread, twin_x11_damage_thread, tx);
-
- twin_thread_create (&tx->event_thread, twin_x11_event_thread, tx);
-
return tx;
}
@@ -218,17 +206,14 @@ twin_x11_destroy (twin_x11_t *tx)
{
XDestroyWindow (tx->dpy, tx->win);
tx->win = 0;
- twin_cond_broadcast (&tx->damage_cond);
twin_screen_destroy (tx->screen);
}
void
twin_x11_damage (twin_x11_t *tx, XExposeEvent *ev)
{
- twin_screen_lock (tx->screen);
twin_screen_damage (tx->screen,
ev->x, ev->y, ev->x + ev->width, ev->y + ev->height);
- twin_screen_unlock (tx->screen);
}
void
diff --git a/twin_x11.h b/twin_x11.h
index b6a55be..45a2932 100644
--- a/twin_x11.h
+++ b/twin_x11.h
@@ -37,9 +37,6 @@ typedef struct _twin_x11 {
GC gc;
Visual *visual;
int depth;
- twin_thread_t damage_thread;
- twin_cond_t damage_cond;
- twin_thread_t event_thread;
XImage *image;
int image_y;
} twin_x11_t;
diff --git a/twinint.h b/twinint.h
index 7294539..2a0d96b 100644
--- a/twinint.h
+++ b/twinint.h
@@ -345,6 +345,9 @@ _twin_path_scurve (twin_path_t *path,
twin_sfixed_t x2, twin_sfixed_t y2,
twin_sfixed_t x3, twin_sfixed_t y3);
+void
+_twin_path_sfinish (twin_path_t *path);
+
/*
* Glyph stuff. Coordinates are stored in 2.6 fixed point format
*/
@@ -375,4 +378,89 @@ extern const uint16_t _twin_g_offsets[];
#define twin_glyph_snap_y(g) (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
#define twin_glyph_draw(g) (twin_glyph_snap_y(g) + twin_glyph_n_snap_y(g))
+/*
+ * dispatch stuff
+ */
+
+typedef struct _twin_queue {
+ struct _twin_queue *next;
+ struct _twin_queue *order;
+ twin_bool_t walking;
+ twin_bool_t deleted;
+} twin_queue_t;
+
+struct _twin_timeout {
+ twin_queue_t queue;
+ twin_time_t time;
+ twin_time_t delay;
+ twin_timeout_proc_t proc;
+ void *closure;
+};
+
+struct _twin_work {
+ twin_queue_t queue;
+ int priority;
+ twin_work_proc_t proc;
+ void *closure;
+};
+
+struct _twin_file {
+ twin_queue_t queue;
+ int file;
+ twin_file_op_t ops;
+ twin_file_proc_t proc;
+ void *closure;
+};
+
+struct _twin_block {
+ twin_queue_t queue;
+ twin_block_proc_t proc;
+ void *closure;
+};
+
+struct _twin_wakeup {
+ twin_queue_t queue;
+ twin_wakeup_proc_t proc;
+ void *closure;
+};
+
+typedef enum _twin_order {
+ TWIN_BEFORE = -1,
+ TWIN_AT = 0,
+ TWIN_AFTER = 1
+} twin_order_t;
+
+typedef twin_order_t (*twin_queue_proc_t) (twin_queue_t *a, twin_queue_t *b);
+
+void
+_twin_queue_insert (twin_queue_t **head,
+ twin_queue_proc_t proc,
+ twin_queue_t *new);
+
+void
+_twin_queue_remove (twin_queue_t **head,
+ twin_queue_t *old);
+
+void
+_twin_queue_delete (twin_queue_t **head,
+ twin_queue_t *old);
+
+twin_queue_t *
+_twin_queue_set_order (twin_queue_t **head);
+
+void
+_twin_queue_review_order (twin_queue_t *first);
+
+void
+_twin_run_file (twin_time_t delay);
+
+void
+_twin_run_timeout (void);
+
+twin_time_t
+_twin_timeout_delay (void);
+
+void
+_twin_run_work (void);
+
#endif /* _TWININT_H_ */
diff --git a/xtwin.c b/xtwin.c
index 366b134..ae206a3 100644
--- a/xtwin.c
+++ b/xtwin.c
@@ -29,327 +29,9 @@
#include <sys/time.h>
#include <time.h>
#include <assert.h>
-
-#define D(x) twin_double_to_fixed(x)
-
-#define TWIN_CLOCK_BACKGROUND 0xff3b80ae
-#define TWIN_CLOCK_HOUR 0x80808080
-#define TWIN_CLOCK_HOUR_OUT 0x30000000
-#define TWIN_CLOCK_MINUTE 0x80808080
-#define TWIN_CLOCK_MINUTE_OUT 0x30000000
-#define TWIN_CLOCK_SECOND 0x80808080
-#define TWIN_CLOCK_SECOND_OUT 0x30000000
-#define TWIN_CLOCK_TIC 0xffbababa
-#define TWIN_CLOCK_NUMBERS 0xffdedede
-#define TWIN_CLOCK_WATER 0x60200000
-#define TWIN_CLOCK_WATER_OUT 0x40404040
-#define TWIN_CLOCK_WATER_UNDER 0x60400000
-#define TWIN_CLOCK_BORDER 0xffbababa
-#define TWIN_CLOCK_BORDER_WIDTH D(0.01)
-
-static void
-twin_clock_set_transform (twin_window_t *clock,
- twin_path_t *path)
-{
- twin_fixed_t scale;
-
- scale = (TWIN_FIXED_ONE - TWIN_CLOCK_BORDER_WIDTH * 3) / 2;
- twin_path_translate (path,
- twin_int_to_fixed (clock->client.left),
- twin_int_to_fixed (clock->client.top));
- twin_path_scale (path,
- (clock->client.right - clock->client.left) * scale,
- (clock->client.bottom - clock->client.top) * scale);
-
- twin_path_translate (path,
- TWIN_FIXED_ONE + TWIN_CLOCK_BORDER_WIDTH * 3,
- TWIN_FIXED_ONE + TWIN_CLOCK_BORDER_WIDTH * 3);
-
- twin_path_rotate (path, -TWIN_ANGLE_90);
-}
-
-static void
-twin_clock_hand (twin_window_t *clock,
- twin_angle_t angle,
- twin_fixed_t len,
- twin_fixed_t fill_width,
- twin_fixed_t out_width,
- twin_argb32_t fill_pixel,
- twin_argb32_t out_pixel)
-{
- twin_path_t *stroke = twin_path_create ();
- twin_path_t *pen = twin_path_create ();
- twin_path_t *path = twin_path_create ();
- twin_matrix_t m;
-
- twin_clock_set_transform (clock, stroke);
-
- twin_path_rotate (stroke, angle);
- twin_path_move (stroke, D(0), D(0));
- twin_path_draw (stroke, len, D(0));
-
- m = twin_path_current_matrix (stroke);
- m.m[2][0] = 0;
- m.m[2][1] = 0;
- twin_path_set_matrix (pen, m);
- twin_path_set_matrix (path, m);
- twin_path_circle (pen, fill_width);
- twin_path_convolve (path, stroke, pen);
-
- twin_paint_path (clock->pixmap, fill_pixel, path);
-
- twin_paint_stroke (clock->pixmap, out_pixel, path, out_width);
-
- twin_path_destroy (path);
- twin_path_destroy (pen);
- twin_path_destroy (stroke);
-}
-
-static twin_angle_t
-twin_clock_minute_angle (int min)
-{
- return min * TWIN_ANGLE_360 / 60;
-}
-
-static void
-twin_clock_face (twin_window_t *clock)
-{
- twin_path_t *path = twin_path_create ();
- int m;
-
- twin_clock_set_transform (clock, path);
-
- twin_path_move (path, 0, 0);
- twin_path_circle (path, TWIN_FIXED_ONE);
-
- twin_paint_path (clock->pixmap, TWIN_CLOCK_BACKGROUND, path);
-
- twin_paint_stroke (clock->pixmap, TWIN_CLOCK_BORDER, path, TWIN_CLOCK_BORDER_WIDTH);
-
- {
- twin_state_t state = twin_path_save (path);
- twin_text_metrics_t metrics;
- twin_fixed_t height, width;
- static char *label = "twin";
-
- twin_path_empty (path);
- twin_path_rotate (path, twin_degrees_to_angle (-11) + TWIN_ANGLE_90);
- twin_path_set_font_size (path, D(0.5));
- twin_path_set_font_style (path, TWIN_TEXT_UNHINTED|TWIN_TEXT_OBLIQUE);
- twin_text_metrics_utf8 (path, label, &metrics);
- height = metrics.ascent + metrics.descent;
- width = metrics.right_side_bearing - metrics.left_side_bearing;
-
- twin_path_move (path, -width / 2, metrics.ascent - height/2 + D(0.01));
- twin_path_draw (path, width / 2, metrics.ascent - height/2 + D(0.01));
- twin_paint_stroke (clock->pixmap, TWIN_CLOCK_WATER_UNDER, path, D(0.02));
- twin_path_empty (path);
-
- twin_path_move (path, -width / 2 - metrics.left_side_bearing, metrics.ascent - height/2);
- twin_path_utf8 (path, label);
- twin_paint_path (clock->pixmap, TWIN_CLOCK_WATER, path);
- twin_path_restore (path, &state);
- }
-
- twin_path_set_font_size (path, D(0.2));
- twin_path_set_font_style (path, TWIN_TEXT_UNHINTED);
-
- for (m = 1; m <= 60; m++)
- {
- twin_state_t state = twin_path_save (path);
- twin_path_rotate (path, twin_clock_minute_angle (m) + TWIN_ANGLE_90);
- twin_path_empty (path);
- if (m % 5 != 0)
- {
- twin_path_move (path, 0, -TWIN_FIXED_ONE);
- twin_path_draw (path, 0, -D(0.9));
- twin_paint_stroke (clock->pixmap, TWIN_CLOCK_TIC, path, D(0.01));
- }
- else
- {
- char hour[3];
- twin_text_metrics_t metrics;
- twin_fixed_t width;
- twin_fixed_t left;
-
- sprintf (hour, "%d", m / 5);
- twin_text_metrics_utf8 (path, hour, &metrics);
- width = metrics.right_side_bearing - metrics.left_side_bearing;
- left = -width / 2 - metrics.left_side_bearing;
- twin_path_move (path, left, -D(0.98) + metrics.ascent);
- twin_path_utf8 (path, hour);
- twin_paint_path (clock->pixmap, TWIN_CLOCK_NUMBERS, path);
- }
- twin_path_restore (path, &state);
- }
-
- twin_path_destroy (path);
-}
-
-int napp;
-
-static void
-twin_clock (twin_screen_t *screen, const char *name, int x, int y, int w, int h)
-{
- twin_window_t *clock = twin_window_create (screen, TWIN_ARGB32,
- WindowApplication,
- x, y, w, h);
- struct timeval tv;
- struct tm t;
- twin_angle_t hour_angle, minute_angle, second_angle;
-
- twin_window_set_name (clock, name);
- twin_window_show (clock);
-
- for (;;)
- {
- twin_pixmap_disable_update (clock->pixmap);
- twin_window_draw (clock);
- twin_fill (clock->pixmap, 0x00000000, TWIN_SOURCE,
- clock->client.left, clock->client.top,
- clock->client.right, clock->client.bottom);
-
- twin_clock_face (clock);
-
- gettimeofday (&tv, NULL);
-
- localtime_r(&tv.tv_sec, &t);
-
- second_angle = ((t.tm_sec * 100 + tv.tv_usec / 10000) *
- TWIN_ANGLE_360) / 6000;
- minute_angle = twin_clock_minute_angle (t.tm_min) + second_angle / 60;
- hour_angle = (t.tm_hour * TWIN_ANGLE_360 + minute_angle) / 12;
- twin_clock_hand (clock, hour_angle, D(0.4), D(0.07), D(0.01),
- TWIN_CLOCK_HOUR, TWIN_CLOCK_HOUR_OUT);
- twin_clock_hand (clock, minute_angle, D(0.8), D(0.05), D(0.01),
- TWIN_CLOCK_MINUTE, TWIN_CLOCK_MINUTE_OUT);
- twin_clock_hand (clock, second_angle, D(0.9), D(0.01), D(0.01),
- TWIN_CLOCK_SECOND, TWIN_CLOCK_SECOND_OUT);
-
- twin_pixmap_enable_update (clock->pixmap);
-
- gettimeofday (&tv, NULL);
-
-#define INTERVAL 1000000
-
- usleep (INTERVAL - (tv.tv_usec % INTERVAL));
- }
- napp--;
-}
-
-static void
-twin_text_app (twin_screen_t *screen, const char *name, int x, int y, int w, int h)
-{
- twin_window_t *text = twin_window_create (screen, TWIN_ARGB32,
- WindowApplication,
- x,y,w,h);
- twin_fixed_t fx, fy;
- static const char *lines[] = {
- "Fourscore and seven years ago our fathers brought forth on",
- "this continent a new nation, conceived in liberty and",
- "dedicated to the proposition that all men are created equal.",
- "",
- "Now we are engaged in a great civil war, testing whether that",
- "nation or any nation so conceived and so dedicated can long",
- "endure. We are met on a great battlefield of that war. We",
- "have come to dedicate a portion of it as a final resting",
- "place for those who died here that the nation might live.",
- "This we may, in all propriety do. But in a larger sense, we",
- "cannot dedicate, we cannot consecrate, we cannot hallow this",
- "ground. The brave men, living and dead who struggled here",
- "have hallowed it far above our poor power to add or detract.",
- "The world will little note nor long remember what we say here,",
- "but it can never forget what they did here.",
- "",
- "It is rather for us the living, we here be dedicated to the",
- "great task remaining before us--that from these honored",
- "dead we take increased devotion to that cause for which they",
- "here gave the last full measure of devotion--that we here",
- "highly resolve that these dead shall not have died in vain, that",
- "this nation shall have a new birth of freedom, and that",
- "government of the people, by the people, for the people shall",
- "not perish from the earth.",
- 0
- };
- const char **l;
- twin_path_t *path;
-
- twin_window_set_name(text, name);
- path = twin_path_create ();
- twin_path_translate (path,
- twin_int_to_fixed (text->client.left),
- twin_int_to_fixed (text->client.top));
-#define TEXT_SIZE 10
- twin_path_set_font_size (path, D(TEXT_SIZE));
- fx = D(3);
- fy = D(10);
- twin_fill (text->pixmap, 0xc0c0c0c0, TWIN_SOURCE,
- text->client.left, text->client.top,
- text->client.right, text->client.bottom);
- for (l = lines; *l; l++)
- {
- twin_path_move (path, fx, fy);
- twin_path_utf8 (path, *l);
- twin_paint_path (text->pixmap, 0xff000000, path);
- twin_path_empty (path);
- fy += D(TEXT_SIZE);
- }
- twin_window_show (text);
-}
-
-typedef void (*twin_app_func_t) (twin_screen_t *screen, const char *name,
- int x, int y, int w, int h);
-
-typedef struct _twin_app_args {
- twin_app_func_t func;
- twin_screen_t *screen;
- char *name;
- int x, y, w, h;
-} twin_app_args_t;
-
-static void *
-twin_app_thread (void *closure)
-{
- twin_app_args_t *a = closure;
-
- (*a->func) (a->screen, a->name, a->x, a->y, a->w, a->h);
- free (a);
- return 0;
-}
-
-static void
-twin_start_app (twin_app_func_t func,
- twin_screen_t *screen,
- const char *name,
- int x, int y, int w, int h)
-{
- twin_app_args_t *a = malloc (sizeof (twin_app_args_t) + strlen (name) + 1);
- pthread_t thread;
-
- a->func = func;
- a->screen = screen;
- a->name = (char *) (a + 1);
- a->x = x;
- a->y = y;
- a->w = w;
- a->h = h;
- strcpy (a->name, name);
- pthread_create (&thread, NULL, twin_app_thread, a);
-}
-
-static void
-twin_start_clock (twin_screen_t *screen, const char *name, int x, int y, int w, int h)
-{
- ++napp;
- twin_start_app (twin_clock, screen, name, x, y, w, h);
-}
-
-int styles[] = {
- TWIN_TEXT_ROMAN,
- TWIN_TEXT_OBLIQUE,
- TWIN_TEXT_BOLD,
- TWIN_TEXT_BOLD|TWIN_TEXT_OBLIQUE
-};
+#include <twin_clock.h>
+#include <twin_text.h>
+#include <twin_demo.h>
#define WIDTH 512
#define HEIGHT 512
@@ -357,368 +39,14 @@ int styles[] = {
int
main (int argc, char **argv)
{
- Status status = XInitThreads ();
Display *dpy = XOpenDisplay (0);
twin_x11_t *x11 = twin_x11_create (dpy, WIDTH, HEIGHT);
- twin_pixmap_t *red = twin_pixmap_create (TWIN_ARGB32, WIDTH, HEIGHT);
- twin_pixmap_t *blue = twin_pixmap_create (TWIN_ARGB32, 100, 100);
- twin_pixmap_t *alpha = twin_pixmap_create (TWIN_A8, WIDTH, HEIGHT);
- twin_operand_t source, mask;
- twin_path_t *path;
- XEvent ev, motion;
- twin_bool_t had_motion;
- int x, y;
- twin_path_t *pen;
- twin_path_t *stroke;
- twin_path_t *extra;
- int s;
- twin_fixed_t fx, fy;
- int g;
twin_screen_set_background (x11->screen, twin_make_pattern ());
- (void) ev;
- (void) motion;
- (void) had_motion;
- (void) x;
- (void) y;
- (void) red;
- (void) blue;
- (void) status;
- (void) alpha;
- (void) source;
- (void) mask;
- (void) source;
- (void) path;
-
- extra = 0;
- stroke = 0;
- pen = 0;
- s = 0;
- fx = 0;
- fy = 0;
- g = 0 ;
-
-#if 0
- pen = twin_path_create ();
- twin_path_circle (pen, D (1));
-
- path = twin_path_create ();
-#if 0
- twin_path_move (path, D(3), D(0));
- for (g = 0; g < 4326; g++)
- {
- int glyph = g;
- if (!twin_has_glyph (glyph)) glyph = 0;
- twin_path_cur_point (path, &fx, &fy);
- if (fx + twin_glyph_width (glyph, D(10)) >= D(WIDTH) || g % 50 == 0)
- twin_path_move (path, D(3), fy + D(10));
- twin_path_glyph (path, D(10), D(10), TWIN_TEXT_ROMAN,
- glyph);
- }
-#endif
-#if 0
- stroke = twin_path_create ();
- twin_path_move (stroke, D(30), D(400));
- twin_path_set_font_size (stroke, D(100));
- twin_path_utf8 (stroke, "jelly HEzt/[].");
- twin_path_convolve (path, stroke, pen);
-/* twin_path_append (path, stroke); */
- twin_path_destroy (stroke);
- stroke = twin_path_create ();
- twin_path_move (stroke, D(30), D(400));
- twin_path_draw (stroke, D(1000), D(400));
- twin_path_convolve (path, stroke, pen);
-#endif
-
-#if 0
- stroke = twin_path_create ();
- pen = twin_path_create ();
- twin_path_translate (stroke, D(100), D(100));
-/* twin_path_rotate (stroke, twin_degrees_to_angle (270)); */
- twin_path_rotate (stroke, twin_degrees_to_angle (270));
- twin_path_move (stroke, D(0), D(0));
- twin_path_draw (stroke, D(100), D(0));
- twin_path_set_matrix (pen, twin_path_current_matrix (stroke));
- twin_path_circle (pen, D(20));
- twin_path_convolve (path, stroke, pen);
-#endif
-
-#if 0
- stroke = twin_path_create ();
- twin_path_translate (stroke, D(250), D(250));
- twin_path_circle (stroke, 0x42aaa);
- extra = twin_path_convex_hull (stroke);
- twin_path_convolve (path, extra, pen);
-#endif
-
-#if 0
- {
- twin_state_t state = twin_path_save (path);
- twin_path_translate (path, D(300), D(300));
- twin_path_set_font_size (path, D(15));
- for (s = 0; s < 41; s++)
- {
- twin_state_t state = twin_path_save (path);
- twin_path_rotate (path, twin_degrees_to_angle (9 * s));
- twin_path_move (path, D(100), D(0));
- twin_path_utf8 (path, "Hello, world!");
- twin_path_restore (path, &state);
- }
- twin_path_restore (path, &state);
- }
-#endif
-#if 1
- fx = D(15);
- fy = 0;
- twin_path_translate (path, 0, D(HEIGHT));
- twin_path_rotate (path, -twin_degrees_to_angle (90));
- twin_path_scale (path, D(1), D(0.5));
- twin_path_set_font_style (path, TWIN_TEXT_OBLIQUE);
- for (g = 40; g <= 60; g += 4)
- {
- twin_path_set_font_size (path, D(g));
-#if 0
- fy += D(g+2);
- twin_path_move (path, fx, fy);
- twin_path_utf8 (path, "H");
-#endif
-#if 0
- fy += D(g+2);
- twin_path_move (path, fx, fy);
- twin_path_utf8 (path,
- " !\"#$%&'()*+,-./0123456789:;<=>?");
- fy += D(g+2);
- twin_path_move (path, fx, fy);
- twin_path_utf8 (path,
- "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_");
- fy += D(g+2);
- twin_path_move (path, fx, fy);
- twin_path_utf8 (path,
- "`abcdefghijklmnopqrstuvwxyz{|}~");
-#endif
-#if 0
- for (s = 0; s < 4; s++)
- {
- fy += D(g+2);
- twin_path_move (path, fx, fy);
- twin_path_set_font_style (path, styles[s]);
- twin_path_utf8 (path,
- "the quick brown fox jumps over the lazy dog.");
- twin_path_utf8 (path,
- "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.");
- }
-#endif
-#if 1
- fy += D(g + 2);
- twin_path_move (path, fx, fy);
-#define TEXT "jelly HEzt/[]."
-/* twin_path_set_font_style (path, TWIN_TEXT_UNHINTED); */
- twin_path_utf8 (path, TEXT);
- {
- twin_text_metrics_t m;
-
- stroke = twin_path_create ();
- twin_path_set_matrix (stroke, twin_path_current_matrix (path));
- twin_text_metrics_utf8 (path, TEXT, &m);
- twin_path_translate (stroke, TWIN_FIXED_HALF, TWIN_FIXED_HALF);
- twin_path_move (stroke, fx, fy);
- twin_path_draw (stroke, fx + m.width, fy);
- twin_paint_stroke (red, 0xffff0000, stroke, D(1));
- twin_path_empty (stroke);
- twin_path_move (stroke,
- fx + m.left_side_bearing, fy - m.ascent);
- twin_path_draw (stroke,
- fx + m.right_side_bearing, fy - m.ascent);
- twin_path_draw (stroke,
- fx + m.right_side_bearing, fy + m.descent);
- twin_path_draw (stroke,
- fx + m.left_side_bearing, fy + m.descent);
- twin_path_draw (stroke,
- fx + m.left_side_bearing, fy - m.ascent);
- twin_paint_stroke (red, 0xff00ff00, stroke, D(1));
- }
-#endif
- }
-#endif
-#if 0
- fx = D(3);
- fy = D(8);
- for (g = 6; g < 36; g++)
- {
- twin_path_move (path, fx, fy);
- twin_path_set_font_size (path, D(g));
- twin_path_utf8 (path,
- "the quick brown fox jumps over the lazy dog.");
- twin_path_utf8 (path,
- "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.");
- fy += D(g);
- }
-#endif
- twin_fill_path (alpha, path, 0, 0);
-
- twin_path_destroy (path);
-
- source.source_kind = TWIN_SOLID;
- source.u.argb = 0xff000000;
- mask.source_kind = TWIN_PIXMAP;
- mask.u.pixmap = alpha;
- twin_composite (red, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
- WIDTH, HEIGHT);
-
-#if 0
- path = twin_path_create ();
-
- twin_path_rotate (path, -TWIN_ANGLE_45);
- twin_path_translate (path, D(10), D(2));
- for (s = 0; s < 40; s++)
- {
- twin_path_rotate (path, TWIN_ANGLE_11_25 / 16);
- twin_path_scale (path, D(1.125), D(1.125));
- twin_path_move (path, D(0), D(0));
- twin_path_draw (path, D(1), D(0));
- twin_path_draw (path, D(1), D(1));
- twin_path_draw (path, D(0), D(1));
- }
-
- twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, WIDTH, HEIGHT);
- twin_fill_path (alpha, path);
-
- source.source_kind = TWIN_SOLID;
- source.u.argb = 0xffff0000;
- mask.source_kind = TWIN_PIXMAP;
- mask.u.pixmap = alpha;
- twin_composite (red, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
- WIDTH, HEIGHT);
-#endif
-
-#if 0
- path = twin_path_create ();
- stroke = twin_path_create ();
-
- twin_path_translate (stroke, D(62), D(62));
- twin_path_scale (stroke,D(60),D(60));
- for (s = 0; s < 60; s++)
- {
- twin_state_t save = twin_path_save (stroke);
- twin_angle_t a = s * TWIN_ANGLE_90 / 15;
-
- twin_path_rotate (stroke, a);
- twin_path_move (stroke, D(1), 0);
- if (s % 5 == 0)
- twin_path_draw (stroke, D(0.85), 0);
- else
- twin_path_draw (stroke, D(.98), 0);
- twin_path_restore (stroke, &save);
- }
- twin_path_convolve (path, stroke, pen);
- twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, WIDTH, HEIGHT);
- twin_fill_path (alpha, path);
-
- source.source_kind = TWIN_SOLID;
- source.u.argb = 0xffff0000;
- mask.source_kind = TWIN_PIXMAP;
- mask.u.pixmap = alpha;
- twin_composite (red, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
- WIDTH, HEIGHT);
-#endif
-
-#if 0
- path = twin_path_create ();
- stroke = twin_path_create ();
-
- twin_path_translate (stroke, D(100), D(100));
- twin_path_scale (stroke, D(10), D(10));
- twin_path_move (stroke, D(0), D(0));
- twin_path_draw (stroke, D(10), D(0));
- twin_path_convolve (path, stroke, pen);
-
- twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, WIDTH, HEIGHT);
- twin_fill_path (alpha, path);
-
- source.source_kind = TWIN_SOLID;
- source.u.argb = 0xffff0000;
- mask.source_kind = TWIN_PIXMAP;
- mask.u.pixmap = alpha;
- twin_composite (red, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
- WIDTH, HEIGHT);
-#endif
-
-#if 0
- path = twin_path_create ();
-
- stroke = twin_path_create ();
-
- twin_path_move (stroke, D (10), D (40));
- twin_path_draw (stroke, D (40), D (40));
- twin_path_draw (stroke, D (10), D (10));
- twin_path_move (stroke, D (10), D (50));
- twin_path_draw (stroke, D (40), D (50));
-
- twin_path_convolve (path, stroke, pen);
- twin_path_destroy (stroke);
-
- twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, 100, 100);
- twin_fill_path (alpha, path);
- source.source_kind = TWIN_SOLID;
- source.u.argb = 0xff00ff00;
- mask.source_kind = TWIN_PIXMAP;
- mask.u.pixmap = alpha;
- twin_composite (blue, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
- 100, 100);
-
- twin_path_destroy (path);
-
- path = twin_path_create ();
- stroke = twin_path_create ();
-
- twin_path_move (stroke, D (50), D (50));
- twin_path_curve (stroke, D (70), D (70), D (80), D (70), D (100), D (50));
-
- twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, 100, 100);
- twin_fill_path (alpha, stroke);
-
- source.source_kind = TWIN_SOLID;
- source.u.argb = 0xffff0000;
- mask.source_kind = TWIN_PIXMAP;
- mask.u.pixmap = alpha;
- twin_composite (blue, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
- 100, 100);
-
- twin_path_convolve (path, stroke, pen);
-
- twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, 100, 100);
- twin_fill_path (alpha, path);
-
- source.source_kind = TWIN_SOLID;
- source.u.argb = 0xff0000ff;
- mask.source_kind = TWIN_PIXMAP;
- mask.u.pixmap = alpha;
- twin_composite (blue, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER,
- 100, 100);
-#endif
-
- twin_pixmap_move (red, 0, 0);
- twin_pixmap_move (blue, 100, 100);
- twin_pixmap_show (red, x11->screen, 0);
- twin_pixmap_show (blue, x11->screen, 0);
- ++napp;
-#endif
-
- if (!napp)
- twin_start_clock (x11->screen, "Clock", 10, 10, 200, 200);
-#if 0
- twin_start_clock (x11->screen, "Large clock", 0, 100, 256, 256);
-#endif
-#if 1
- twin_start_app (twin_text_app, x11->screen, "Gettysburg Address",
- 100, 100, 318, 250);
-#endif
-#if 0
- twin_start_clock (x11->screen, "ur clock", 256, 0, 256, 256);
- twin_start_clock (x11->screen, "ll clock", 0, 256, 256, 256);
- twin_start_clock (x11->screen, "lr clock", 256, 256, 256, 256);
-#endif
- while (napp)
- sleep (1);
+ twin_demo_start (x11->screen, "Demo", 100, 100, 400, 400);
+ twin_clock_start (x11->screen, "Clock", 10, 10, 200, 200);
+ twin_text_start (x11->screen, "Gettysburg Address",
+ 0, 0, 300, 300);
+ twin_dispatch ();
return 0;
}