diff options
author | Keith Packard <keithp@keithp.com> | 2004-10-25 19:09:36 +0000 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2004-10-25 19:09:36 +0000 |
commit | 6df04a58f5078741ac7d5a66492814eec66f027a (patch) | |
tree | bd0db1ed504f56b12f116160062d1d7ac5883688 | |
parent | c905d1c40ad88707f549a56e631c4eaff756378b (diff) | |
download | libtwin-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-- | ChangeLog | 68 | ||||
-rw-r--r-- | Makefile.am | 13 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | twin.h | 149 | ||||
-rw-r--r-- | twin_clock.c | 238 | ||||
-rw-r--r-- | twin_clock.h | 33 | ||||
-rw-r--r-- | twin_demo.c | 474 | ||||
-rw-r--r-- | twin_demo.h | 33 | ||||
-rw-r--r-- | twin_dispatch.c | 36 | ||||
-rw-r--r-- | twin_draw.c | 107 | ||||
-rw-r--r-- | twin_fedit/Makefile | 9 | ||||
-rw-r--r-- | twin_fedit/nchars | 1021 | ||||
-rw-r--r-- | twin_fedit/twin-fedit.c | 699 | ||||
-rw-r--r-- | twin_fedit/twin-fedit.h | 103 | ||||
-rw-r--r-- | twin_fedit/twin-sfit.c | 351 | ||||
-rw-r--r-- | twin_file.c | 124 | ||||
-rw-r--r-- | twin_icon.c | 184 | ||||
-rw-r--r-- | twin_path.c | 78 | ||||
-rw-r--r-- | twin_pixmap.c | 59 | ||||
-rw-r--r-- | twin_poly.c | 16 | ||||
-rw-r--r-- | twin_queue.c | 95 | ||||
-rw-r--r-- | twin_screen.c | 13 | ||||
-rw-r--r-- | twin_text.c | 86 | ||||
-rw-r--r-- | twin_text.h | 33 | ||||
-rw-r--r-- | twin_timeout.c | 127 | ||||
-rw-r--r-- | twin_window.c | 134 | ||||
-rw-r--r-- | twin_work.c | 82 | ||||
-rw-r--r-- | twin_x11.c | 67 | ||||
-rw-r--r-- | twin_x11.h | 3 | ||||
-rw-r--r-- | twinint.h | 88 | ||||
-rw-r--r-- | xtwin.c | 688 |
31 files changed, 4298 insertions, 917 deletions
@@ -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) # @@ -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); +} @@ -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 @@ -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; @@ -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_ */ @@ -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; } |