#!/usr/local/bin/cz -- # XXX auto-repeat-kbd-buffer-fix-wip use b num margins = 40 int font_ref = 200 num effect_duration = 1 boolean step_by_step = 1 boolean effects = 1 num delay = 0, delay_demo = 0, delay_page = 0 cstr demos_dir = "." boolean loop = 0 boolean smooth = 1 int smooth_steps = 30 int smooth_dur = 0.50 def smooth_delay smooth_dur / smooth_steps num x_expose_delay = 0.2 num old_y, old_font_size, old_height boolean start_of_page = 1 int page = 0 def usage() usage("slides_file [start_page]") Main(): Atexit(kill_demo_child) paint_handle_events = 0 int start_page = 0 if *Getenv("quick") step_by_step = 0 if *Getenv("nofx") effects = 0 if *Getenv("nosmooth") smooth = 0 demos_dir = Getenv("demos", demos_dir) delay = atof(Getenv("delay", "0")) delay_demo = atof(Getenv("delay_demo", "0")) delay_page = atof(Getenv("delay_page", "0")) eachp(d, delay_demo, delay_page, delay) if !*d *d = delay ? delay * 4 : time_forever if *Getenv("loop") loop = 0 args(cstr, slides_file) getargs(int, start_page) dirbasename(slides_file, dir, base) Chdir(dir) slides_file = base space(800, 600) gprint_anchor(-1, 1) csleep(smooth_delay) new(lines, vec, cstr, 16) repeat vec_clear(lines) tofree_block() F_in(slides_file): warn("%d", page) show_slides(lines, start_page) if !loop break gr_done = 1 show_slides(vec *lines, int start_page) Eachline(l): boolean show = page >= start_page boolean end_of_page = *l == ' ' if *l == '!' if show run_demo(l+1) eif *l == '<' F_in(tofree(Format("%s/%s", demos_dir, l+1))) show_slides(lines, start_page) else if !end_of_page vec_push(lines, Strdup(l)) if show if end_of_page if !step_by_step show_slide(lines) gr_do_delay(delay_page) if effects effect() eif (step_by_step && *l) show_slide(lines) gr_do_delay(delay) if end_of_page ++page warn("%d", page) vec_clear(lines) start_of_page = 1 int paint_sync_count = 0 show_slide(vec *lines): int n = veclen(lines) font("helvetica-medium", font_ref) num height = font_height() num max_width = 0 for_vec(l, lines, cstr): max_width = nmax(max_width, text_width(*l)) num x_scale = (w - margins) / max_width num y_scale = (h - margins) / (height * n) num scale = nmin(x_scale, y_scale) num font_size = font_ref * scale height *= scale num y = height * n / 2 paint_sync_count = 0 if smooth && !start_of_page for(i, 0.0, 1.0, 1.0/smooth_steps) num y1 = blend(i, old_y, y) num font_size1 = blend(i, old_font_size, font_size) num height1 = blend(i, old_height, height) draw_lines(lines, y1, font_size1, height1) csleep(smooth_delay) draw_lines(lines, y, font_size, height) old_y = y old_font_size = font_size old_height = height start_of_page = 0 draw_lines(vec *lines, num y, num font_size, num height) font("helvetica-medium", font_size) clear() white() for_vec(l, lines, cstr): move(-w_2 + margins/2, y) gsayf(*l) y -= height Paint() warn("draw_lines done") effect(): with_pixel_type(effect) def effect(pixel_type): num time = rtime() which page % 4: 0 for int i=0; ; ++i: pixel_type *px = pixel() long x, y for y=-h_2; y-w_2 && x-h_2+1 && y time+effect_duration: break boolean gr_do_delay_done gr_do_delay(num dt) gr_do_delay_done = 0 thunk old_handler = key_handler_default key_handler_default = thunk(gr_do_delay_handler) if dt == time_forever while !gr_do_delay_done handle_events_1() else num t = rtime() num t1 = t + dt while t < t1 && !gr_do_delay_done if events_queued() || veclen(gr_need_delay_callbacks) || can_read(x11_fd, t1-t) handle_events_1() t = rtime() key_handler_default = old_handler int handle_events_1() int n = 0 while !events_queued() if n || gr_done return n num dt = veclen(gr_need_delay_callbacks) ? gr_need_delay_callbacks_sleep : time_forever warn("selecting on x11_fd, for %f", dt) can_read(x11_fd, dt) if veclen(gr_need_delay_callbacks) n += gr_call_need_delay_callbacks() if n || gr_done return n handle_event() ++n gr_flush() return n void *gr_do_delay_handler(void *obj, void *a0, void *event) use(obj, a0) gr_event *e = event if e->type == KeyRelease gr_do_delay_done = 1 return thunk_yes paint_sync(int syncage) if !paint_sync_count++ warn("in paint sync") if paint_handle_events || veclen(gr_need_delay_callbacks) handle_events() XCopyArea(display, gr_buf, window, gc, 0, 0, w, h, 0, 0) # XClearWindow(display, window) # XClearWindow doesn't work to render the pixmap, I think the X server # was trying to be clever and remembered that it hadn't changed the # pixmap or the window since it was last painted. but I changed it # through shm! which syncage 2 gr_sync() 1 XFlush(display) if paint_handle_events || veclen(gr_need_delay_callbacks) handle_events() char *key_release_postponed key_handlers_init() XDisplayKeycodes(display, &key_first, &key_last) key_handlers = (void*)Nalloc(thunk, gr_n_keys*n_key_events) key_down = Zalloc(char, gr_n_keys) key_release_postponed = Zalloc(char, gr_n_keys) key_handlers_default() void *key_handler_main(void *obj, void *a0, void *event) use(obj);use(a0) static int last_release_key = -1, last_release_time = -1 static num last_release_time_real = -1 int is_callback = p2i(a0) gr_event *e = event boolean ignore = 0 int event_type = 0 which e->type KeyPress . event_type = 0 if gr_key_auto_repeat == 0 && last_release_key == e->which && e->time - last_release_time <= (int)gr_key_auto_repeat_avoidance_delay ignore = 1 eif key_down[e->which-key_first] key_event_debug("ignoring %s - key already down: %s", e) ignore = 1 if !ignore debug("setting key down %s", key_string(e->which)) key_down[e->which-key_first] = 1 last_release_key = -1 KeyRelease . event_type = 1 if !key_down[e->which-key_first] key_event_debug("ignoring %s - key not down: %s", e) ignore = 1 boolean push_callback = 0 if gr_key_auto_repeat == 0 # debug("gr_key_auto_repeat is off - good!") # this is ugly, silly X. # XXX it is still not 100% reliable if many keys pressed at once. # maybe check KeyRelease with XQueryKeymap :( # http://www.ypass.net/blog/2009/06/detecting-xlibs-keyboard-auto-repeat-functionality-and-how-to-fix-it/ if is_callback debug("key_handler_main in callback %s %s", key_string(last_release_key), key_string(e->which)) if last_release_key == -1 ignore = 1 eif rtime()-last_release_time_real <= gr_key_auto_repeat_avoidance_delay/1000.0 debug("callback came too soon - will push callback again") push_callback = 1 else push_callback = 1 if push_callback debug("pushing callback") if !is_callback last_release_time_real = rtime() gr_event_callback *cb = Talloc(gr_event_callback) cb->t = thunk(key_handler_main, NULL, i2p(1)) cb->e = *e cb->time = rtime() vec_push(gr_need_delay_callbacks, *cb) ignore = 1 if !ignore key_down[e->which-key_first] = 0 debug("clearing key down %s", key_string(e->which)) if !ignore || push_callback last_release_key = e->which last_release_time = e->time else debug("ignoring KeyRelease") if gr_key_ignore_release ignore = 1 if !ignore && XKeycodeToKeysym(display, e->which, e->state & ShiftMask && 1) == NoSymbol ignore = 1 if ignore return thunk_yes thunk *handler = &key_handlers[e->which-key_first][event_type] void *rv = thunk_call(handler, e) key_event_debug("key event %s: %s", e) if !rv rv = thunk_call(&key_handler_default, e) if !rv key_event_debug("unhandled %s: %s", e) return rv