# sprite-imp.pkg
#
# For background see comments at top of
#
src/lib/x-kit/widget/gui/guiboss-imp.pkg#
# This file is like widget_imp, but for
src/lib/x-kit/widget/space/sprite/spritespace-imp.pkg# instead of
src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg#
# Compare to:
#
src/lib/x-kit/widget/xkit/theme/widget/default/look/widget-imp.pkg#
src/lib/x-kit/widget/xkit/theme/widget/default/look/object-imp.pkg# Compiled by:
#
src/lib/x-kit/widget/xkit-widget.sublibstipulate
include package threadkit; # threadkit is from
src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg #
# package ap = client_to_atom; # client_to_atom is from
src/lib/x-kit/xclient/src/iccc/client-to-atom.pkg# package au = authentication; # authentication is from
src/lib/x-kit/xclient/src/stuff/authentication.pkg# package cpm = cs_pixmap; # cs_pixmap is from
src/lib/x-kit/xclient/src/window/cs-pixmap.pkg# package cpt = cs_pixmat; # cs_pixmat is from
src/lib/x-kit/xclient/src/window/cs-pixmat.pkg# package dy = display; # display is from
src/lib/x-kit/xclient/src/wire/display.pkg# package xet = xevent_types; # xevent_types is from
src/lib/x-kit/xclient/src/wire/xevent-types.pkg# package w2x = windowsystem_to_xserver; # windowsystem_to_xserver is from
src/lib/x-kit/xclient/src/window/windowsystem-to-xserver.pkg# package fil = file__premicrothread; # file__premicrothread is from
src/lib/std/src/posix/file--premicrothread.pkg# package fti = font_index; # font_index is from
src/lib/x-kit/xclient/src/window/font-index.pkg# package r2k = xevent_router_to_keymap; # xevent_router_to_keymap is from
src/lib/x-kit/xclient/src/window/xevent-router-to-keymap.pkg# package mtx = rw_matrix; # rw_matrix is from
src/lib/std/src/rw-matrix.pkg# package rgb = rgb; # rgb is from
src/lib/x-kit/xclient/src/color/rgb.pkg# package rop = ro_pixmap; # ro_pixmap is from
src/lib/x-kit/xclient/src/window/ro-pixmap.pkg# package rw = root_window; # root_window is from
src/lib/x-kit/widget/lib/root-window.pkg# package rwv = rw_vector; # rw_vector is from
src/lib/std/src/rw-vector.pkg# package sep = client_to_selection; # client_to_selection is from
src/lib/x-kit/xclient/src/window/client-to-selection.pkg# package shp = shade; # shade is from
src/lib/x-kit/widget/lib/shade.pkg# package sj = socket_junk; # socket_junk is from
src/lib/internet/socket-junk.pkg# package x2s = xclient_to_sequencer; # xclient_to_sequencer is from
src/lib/x-kit/xclient/src/wire/xclient-to-sequencer.pkg# package tr = logger; # logger is from
src/lib/src/lib/thread-kit/src/lib/logger.pkg# package tsr = thread_scheduler_is_running; # thread_scheduler_is_running is from
src/lib/src/lib/thread-kit/src/core-thread-kit/thread-scheduler-is-running.pkg# package u1 = one_byte_unt; # one_byte_unt is from
src/lib/std/one-byte-unt.pkg# package v1u = vector_of_one_byte_unts; # vector_of_one_byte_unts is from
src/lib/std/src/vector-of-one-byte-unts.pkg# package v2w = value_to_wire; # value_to_wire is from
src/lib/x-kit/xclient/src/wire/value-to-wire.pkg# package wg = widget; # widget is from
src/lib/x-kit/widget/old/basic/widget.pkg# package wi = window; # window is from
src/lib/x-kit/xclient/src/window/window.pkg# package wme = window_map_event_sink; # window_map_event_sink is from
src/lib/x-kit/xclient/src/window/window-map-event-sink.pkg# package wpp = client_to_window_watcher; # client_to_window_watcher is from
src/lib/x-kit/xclient/src/window/client-to-window-watcher.pkg# package wy = widget_style; # widget_style is from
src/lib/x-kit/widget/lib/widget-style.pkg# package e2s = xevent_to_string; # xevent_to_string is from
src/lib/x-kit/xclient/src/to-string/xevent-to-string.pkg# package xc = xclient; # xclient is from
src/lib/x-kit/xclient/xclient.pkg# package xj = xsession_junk; # xsession_junk is from
src/lib/x-kit/xclient/src/window/xsession-junk.pkg# package xt = xtypes; # xtypes is from
src/lib/x-kit/xclient/src/wire/xtypes.pkg# package xtr = xlogger; # xlogger is from
src/lib/x-kit/xclient/src/stuff/xlogger.pkg package gtg = guiboss_to_guishim; # guiboss_to_guishim is from
src/lib/x-kit/widget/theme/guiboss-to-guishim.pkg package gd = gui_displaylist; # gui_displaylist is from
src/lib/x-kit/widget/theme/gui-displaylist.pkg package pp = standard_prettyprinter; # standard_prettyprinter is from
src/lib/prettyprint/big/src/standard-prettyprinter.pkg package r8 = rgb8; # rgb8 is from
src/lib/x-kit/xclient/src/color/rgb8.pkg #
package w2p = sprite_to_spritespace; # sprite_to_spritespace is from
src/lib/x-kit/widget/space/sprite/sprite-to-spritespace.pkg package p2w = spritespace_to_sprite; # spritespace_to_sprite is from
src/lib/x-kit/widget/space/sprite/spritespace-to-sprite.pkg #
package g2d = geometry2d; # geometry2d is from
src/lib/std/2d/geometry2d.pkg package evt = gui_event_types; # gui_event_types is from
src/lib/x-kit/widget/gui/gui-event-types.pkg package gts = gui_event_to_string; # gui_event_to_string is from
src/lib/x-kit/widget/gui/gui-event-to-string.pkg package gt = guiboss_types; # guiboss_types is from
src/lib/x-kit/widget/gui/guiboss-types.pkg package wt = widget_theme; # widget_theme is from
src/lib/x-kit/widget/theme/widget/widget-theme.pkg package g2p = gadget_to_pixmap; # gadget_to_pixmap is from
src/lib/x-kit/widget/theme/gadget-to-pixmap.pkg #
tracefile = "widget-unit-test.trace.log";
nb = log::note_on_stderr; # log is from
src/lib/std/src/log.pkgherein
# This package is referenced in:
#
#
package sprite_imp
: Sprite_Imp # Sprite_Imp is from
src/lib/x-kit/widget/xkit/theme/widget/default/look/sprite-imp.api {
Sprite # This turns out not to get used in practice, and probably should be dropped if no use turns up for it.
=
{ id: Id, # Unique id to facilitate storing node_state instances in indexed datastructures like red-black trees.
pass_something: Replyqueue -> (Int -> Void) -> Void,
do_something: Int -> Void,
do: (Void -> Void) -> Void # Used by widget subthreads to run code in main widget microthread.
};
Startup_Fn
=
{
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
do: (Void -> Void) -> Void # Used by widget subthreads to run code in main widget microthread.
}
->
Void;
Shutdown_Fn
=
Void
->
Void; #
Initialize_Gadget_Fn
=
{
id: Id, # Unique id.
doc: String,
site: g2d::Box, # Window rectangle in which to draw.
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
theme: wt::Widget_Theme,
pass_font: List(String) -> Replyqueue
-> (evt::Font -> Void) -> Void, # Nonblocking version of next, for use in imps.
get_font: List(String) -> evt::Font, # Accepts a list of font names which are tried in order.
make_rw_pixmap: g2d::Size -> g2p::Gadget_To_Rw_Pixmap, # Make an Xserver-side rw_pixmap for scratch use by widget. In general there is no need for the sprite to explicitly free these -- guiboss_imp will do this automatically when the gui is killed.
#
do: (Void -> Void) -> Void # Used by widget subthreads to run code in main widget microthread.
}
->
Void;
Redraw_Request_Fn
=
{
id: Id, # Unique id.
doc: String,
frame_number: Int, # 1,2,3,... Purely for convenience of widget, guiboss-imp makes no use of this.
site: g2d::Box, # Window rectangle in which to draw.
popup_nesting_depth: Int, # 0 for gadgets on basewindow, 1 for gadgets on popup on basewindow, 2 for gadgets on popup on popup, etc.
#
duration_in_seconds: Float, # If state has changed look-imp should call redraw_gadget() before this time is up. Also useful for motionblur.
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
gadget_mode: gt::Gadget_Mode,
#
theme: wt::Widget_Theme,
do: (Void -> Void) -> Void # Used by widget subthreads to run code in main widget microthread.
}
->
Void;
Mouse_Click_Fn
=
{
id: Id, # Unique id.
doc: String,
event: gt::Mousebutton_Event, # MOUSEBUTTON_PRESS or MOUSEBUTTON_RELEASE.
button: evt::Mousebutton,
point: g2d::Point,
site: g2d::Box, # Widget's assigned area in window coordinates.
modifier_keys_state: evt::Modifier_Keys_State, # State of the modifier keys (shift, ctrl...).
mousebuttons_state: evt::Mousebuttons_State, # State of mouse buttons as a bool record.
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
theme: wt::Widget_Theme
}
->
Void;
Mouse_Drag_Fn
=
{
id: Id, # Unique id.
doc: String,
event_point: g2d::Point,
start_point: g2d::Point,
last_point: g2d::Point,
site: g2d::Box, # Widget's assigned area in window coordinates.
phase: gt::Drag_Phase,
button: evt::Mousebutton,
modifier_keys_state: evt::Modifier_Keys_State, # State of the modifier keys (shift, ctrl...).
mousebuttons_state: evt::Mousebuttons_State, # State of mouse buttons as a bool record.
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
theme: wt::Widget_Theme,
do: (Void -> Void) -> Void # Used by widget subthreads to run code in main widget microthread.
}
->
Void;
Mouse_Transit_Fn # Note that buttons are always all up in a mouse-transit event -- otherwise it is a mouse-drag event.
=
{
id: Id, # Unique id.
doc: String,
event_point: g2d::Point,
site: g2d::Box, # Widget's assigned area in window coordinates.
transit: gt::Gadget_Transit, # Mouse is entering (CAME) or leaving (LEFT) widget, or moving (MOVE) across it.
modifier_keys_state: evt::Modifier_Keys_State, # State of the modifier keys (shift, ctrl...).
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
theme: wt::Widget_Theme,
do: (Void -> Void) -> Void # Used by widget subthreads to run code in main widget microthread.
}
->
Void;
Key_Event_Fn
=
{
id: Id, # Unique id.
doc: String,
keystroke: gt::Keystroke_Info, # Keystring etc for event.
site: g2d::Box, # Widget's assigned area in window coordinates.
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
theme: wt::Widget_Theme
}
->
Void;
Note_Keyboard_Focus_Fn_Arg
=
{
id: Id, # Unique id.
doc: String,
have_keyboard_focus: Bool, #
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
theme: wt::Widget_Theme,
do: (Void -> Void) -> Void # Used by widget subthreads to run code in main widget microthread.
};
Note_Keyboard_Focus_Fn = Note_Keyboard_Focus_Fn_Arg -> Void;
Sprite_Option
#
= MICROTHREAD_NAME String #
| ID Id
# Unique ID for imp, issued by issue_unique_id::issue_unique_id().
| DOC String
# Documentation string for widget, for debugging purposes.
#
| WIDGET_CONTROL_CALLBACK ( p2w::Spritespace_To_Sprite -> Void )
# Gui boss registers this maildrop to get a port to us once we start up.
| SPRITE_CALLBACK ( Null_Or(Sprite) -> Void )
# App registers this maildrop to get (THE sprite_port) from us once we start up, and NULL when we shut down.
#
| STARTUP_FN Startup_Fn
# Application-specific handler for sprite-imp startup.
| SHUTDOWN_FN Shutdown_Fn
# Application-specific handler for sprite-imp shutdown -- mainly saving state for possible later sprite restart.
# #
| INITIALIZE_GADGET_FN Initialize_Gadget_Fn
# Typically used to set up widget background.
| REDRAW_REQUEST_FN Redraw_Request_Fn
# Application-specific handler for start-of-frame events from guiboss-imp.
#
| MOUSE_CLICK_FN Mouse_Click_Fn
# Application-specific handler for mousebutton clicks.
#
| MOUSE_DRAG_FN Mouse_Drag_Fn
# Application-specific handler for mouse motions.
| MOUSE_TRANSIT_FN Mouse_Transit_Fn
# Application-specific handler for mouse motions.
#
| KEY_EVENT_FN Key_Event_Fn
# Application-specific handler for keyboard key-press and key-release events.
| NOTE_KEYBOARD_FOCUS_FN Note_Keyboard_Focus_Fn
#
;
Sprite_Arg = List(Sprite_Option); # No required components at present.
# pprint_sprite_arg: pp::Prettyprinter -> Sprite_Arg -> Void;
#
Runstate = { # These values will be statically globally visible throughout the code body for the imp.
to: Replyqueue, # The name makes foo::pass_something(imp) to {. ... } syntax read well.
id: Id,
doc: String,
#
startup_fn: Startup_Fn, #
shutdown_fn: Shutdown_Fn, #
#
initialize_gadget_fn: Initialize_Gadget_Fn,
redraw_request_fn: Redraw_Request_Fn,
#
mouse_click_fn: Mouse_Click_Fn,
#
mouse_drag_fn: Mouse_Drag_Fn,
mouse_transit_fn: Mouse_Transit_Fn,
#
key_event_fn: Key_Event_Fn,
note_keyboard_focus_fn: Note_Keyboard_Focus_Fn,
wants_keystrokes: Bool,
wants_mouseclicks: Bool,
# These five provide generic widget connectivity with the guiboss world.
gadget_to_guiboss: gt::Gadget_To_Guiboss, #
sprite_to_spritespace: w2p::Sprite_To_Spritespace, #
sprite_callbacks: List( Null_Or(Sprite) -> Void ), # In shut_down_sprite_imp' () we use these to inform app code that our sprite ports are no longer valid.
shutdown_oneshot: Oneshot_Maildrop ( Void )
# THIS IS NO LONGER NEEDED HERE since Paused_Gui is gone. XXX SUCKO FIXME
# sprite_start_fn: gt::Sprite_Start_Fn
};
Mailq = Mailqueue( Runstate -> Void );
fun default_startup_fn
{
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
do: (Void -> Void) -> Void # Used by widget subthreads to execute code in main widget microthread.
}
=
();
fun default_shutdown_fn ()
=
();
fun default_initialize_gadget_fn
{
id: Id, # Unique id.
doc: String,
site: g2d::Box, # Window rectangle in which to draw.
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
theme: wt::Widget_Theme,
pass_font: List(String) -> Replyqueue
-> (evt::Font -> Void) -> Void, # Nonblocking version of next, for use in imps.
get_font: List(String) -> evt::Font, # Accepts a list of font names which are tried in order.
make_rw_pixmap: g2d::Size -> g2p::Gadget_To_Rw_Pixmap,
#
do: (Void -> Void) -> Void # Used by widget subthreads to execute code in main widget microthread.
}
=
{
};
fun default_redraw_request_fn
{
id: Id, # Unique id.
doc: String,
frame_number: Int, # 1,2,3,... Purely for convenience of widget-imp, guiboss-imp makes no use of this.
site: g2d::Box, # Window rectangle in which to draw.
popup_nesting_depth: Int, # 0 for gadgets on basewindow, 1 for gadgets on popup on basewindow, 2 for gadgets on popup on popup, etc.
#
duration_in_seconds: Float, # If state has changed widget-imp should call redraw_gadget() before this time is up. Also useful for motionblur.
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
gadget_mode: gt::Gadget_Mode,
#
theme: wt::Widget_Theme,
do: (Void -> Void) -> Void # Used by widget subthreads to execute code in main widget microthread.
}
=
{
};
fun default_mouse_click_fn
{
id: Id, # Unique id.
doc: String,
event: gt::Mousebutton_Event, # MOUSEBUTTON_PRESS or MOUSEBUTTON_RELEASE.
button: evt::Mousebutton,
point: g2d::Point,
site: g2d::Box, # Widget's assigned area in window coordinates.
modifier_keys_state: evt::Modifier_Keys_State, # State of the modifier keys (shift, ctrl...).
mousebuttons_state: evt::Mousebuttons_State, # State of mouse buttons as a bool record.
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
theme: wt::Widget_Theme
}
=
();
fun default_mouse_drag_fn
{
id: Id, # Unique id.
doc: String,
event_point: g2d::Point,
start_point: g2d::Point,
last_point: g2d::Point,
site: g2d::Box, # Widget's assigned area in window coordinates.
phase: gt::Drag_Phase,
button: evt::Mousebutton,
modifier_keys_state: evt::Modifier_Keys_State, # State of the modifier keys (shift, ctrl...).
mousebuttons_state: evt::Mousebuttons_State, # State of mouse buttons as a bool record.
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
theme: wt::Widget_Theme,
do: (Void -> Void) -> Void # Used by widget subthreads to execute code in main widget microthread.
}
=
();
fun default_mouse_transit_fn # Note that buttons are always all up in a mouse motion -- otherwise it is a mouse-drag event.
{
id: Id, # Unique id.
doc: String,
event_point: g2d::Point,
site: g2d::Box, # Widget's assigned area in window coordinates.
transit: gt::Gadget_Transit, # Mouse is entering (CAME) or leaving (LEFT) widget, or moving (MOVE) across it.
modifier_keys_state: evt::Modifier_Keys_State, # State of the modifier keys (shift, ctrl...).
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
theme: wt::Widget_Theme,
do: (Void -> Void) -> Void # Used by widget subthreads to execute code in main widget microthread.
}
=
();
fun default_key_event_fn
{
id: Id, # Unique id.
doc: String,
keystroke: gt::Keystroke_Info, # Keystring etc for event.
site: g2d::Box, # Widget's assigned area in window coordinates.
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
theme: wt::Widget_Theme
}
=
();
fun default_note_keyboard_focus_fn
{
id: Id, # Unique id.
doc: String,
have_keyboard_focus: Bool, #
gadget_to_guiboss: gt::Gadget_To_Guiboss,
sprite_to_spritespace: w2p::Sprite_To_Spritespace,
theme: wt::Widget_Theme,
do: (Void -> Void) -> Void # Used by widget subthreads to run code in main widget microthread.
}
=
();
fun shut_down_sprite_imp (r: Runstate)
=
{ apply {. #callback NULL; } r.sprite_callbacks; # Tell app code that our sprite port is no longer valid.
#
put_in_oneshot (r.shutdown_oneshot, ()); # Signal guiboss that shutdown is complete.
# The point here is that we could build and return a new closure locking in updated state if we wished.
thread_exit { success => TRUE }; # Will not return.
};
fun run (
mailq: Mailq, #
#
runstate as
{ # These values will be statically globally visible throughout the code body for the imp.
to: Replyqueue, # The name makes foo::pass_something(imp) to {. ... } syntax read well.
id: Id,
doc: String,
#
startup_fn: Startup_Fn, #
shutdown_fn: Shutdown_Fn, #
#
initialize_gadget_fn: Initialize_Gadget_Fn,
redraw_request_fn: Redraw_Request_Fn,
#
mouse_click_fn: Mouse_Click_Fn,
#
mouse_drag_fn: Mouse_Drag_Fn,
mouse_transit_fn: Mouse_Transit_Fn,
#
key_event_fn: Key_Event_Fn,
note_keyboard_focus_fn: Note_Keyboard_Focus_Fn,
#
wants_keystrokes: Bool,
wants_mouseclicks: Bool,
# These five provide generic widget connectivity with the guiboss world.
gadget_to_guiboss: gt::Gadget_To_Guiboss, #
sprite_to_spritespace: w2p::Sprite_To_Spritespace, #
sprite_callbacks: List( Null_Or(Sprite) -> Void ), # In shut_down_sprite_imp' () we use these to inform app code that our sprite_ports are no longer valid.
shutdown_oneshot: Oneshot_Maildrop ( Void )
# sprite_start_fn: gt::Sprite_Start_Fn
}
)
=
{
loop ();
}
where
fun loop () # Outer loop for the imp.
=
{ do_one_mailop' to [
#
(take_from_mailqueue' mailq ==> do_plea)
];
loop ();
}
where
fun do_plea thunk
=
thunk runstate;
fun shut_down_sprite_imp' ()
=
shut_down_sprite_imp runstate;
end;
end;
fun startup # Root fn of imp microthread.
{ id: Id,
doc: String,
reply_oneshot: Oneshot_Maildrop( gt::Sprite_Exports ),
#
sprite_callbacks,
widget_control_callbacks,
startup_fn: Startup_Fn, #
shutdown_fn: Shutdown_Fn, #
#
initialize_gadget_fn: Initialize_Gadget_Fn,
redraw_request_fn: Redraw_Request_Fn,
#
mouse_click_fn: Mouse_Click_Fn,
#
mouse_drag_fn: Mouse_Drag_Fn,
mouse_transit_fn: Mouse_Transit_Fn,
#
key_event_fn: Key_Event_Fn,
note_keyboard_focus_fn: Note_Keyboard_Focus_Fn,
#
wants_keystrokes: Bool,
wants_mouseclicks: Bool,
# These five provide generic widget connectivity with the guiboss world.
gadget_to_guiboss: gt::Gadget_To_Guiboss, #
sprite_to_spritespace: w2p::Sprite_To_Spritespace, #
run_gun': Run_Gun,
shutdown_oneshot: Oneshot_Maildrop ( Void )
# sprite_start_fn: gt::Sprite_Start_Fn
}
() # Note currying.
=
{ spritespace_to_sprite = { id, do_something, pass_something, pass_draw_done_flag };
sprite = { id, do, do_something, pass_something };
guiboss_to_gadget = { id,
doc,
#
wants_keystrokes,
wants_mouseclicks,
#
initialize_gadget,
redraw_gadget_request,
#
note_keyboard_focus,
note_key_event,
#
note_mousebutton_event,
#
note_mouse_drag_event,
note_mouse_transit,
#
wakeup,
die
};
exports = { guiboss_to_gadget,
spritespace_to_sprite
};
to = make_replyqueue();
put_in_oneshot (reply_oneshot, exports); # Return value from sprite_start_fn().
apply {. #callback (THE sprite); } sprite_callbacks; # Pass our sprite port to everyone who asked for it.
apply {. #callback spritespace_to_sprite; } widget_control_callbacks; # Pass our port to everyone who asked for it.
block_until_mailop_fires run_gun'; # Wait for the starting gun.
startup_fn # Let application-specific code handle startup however it likes.
{ # Typically it will set widget foreground and background via
gadget_to_guiboss,
sprite_to_spritespace,
do
};
run (mailq, { # Will not return.
to,
id,
doc,
startup_fn, #
shutdown_fn, #
#
initialize_gadget_fn,
redraw_request_fn,
#
mouse_click_fn,
#
mouse_drag_fn,
mouse_transit_fn,
#
key_event_fn,
note_keyboard_focus_fn,
#
wants_keystrokes,
wants_mouseclicks,
# These five provide generic widget connectivity with the guiboss world.
gadget_to_guiboss, #
sprite_to_spritespace, #
sprite_callbacks, # In shut_down_sprite_imp' () we use these to inform app code that our sprite ports are no longer valid.
shutdown_oneshot
# sprite_start_fn
}
);
}
where
mailq = make_mailqueue (get_current_microthread()): Mailq;
doc = ""; # Docstring for this sprite. XXX SUCKO FIXME. This is a placeholder, doc functionality need to be coded up per the pattern in
src/lib/x-kit/widget/xkit/theme/widget/default/look/widget-imp.pkg fun do (thunk: Void -> Void) # PUBLIC.
=
put_in_mailqueue (mailq,
#
\\ ({ gadget_to_guiboss, ... }: Runstate)
=
thunk ()
);
#######################################################################
# guiboss_to_gadget fns:
fun initialize_gadget
{
site: g2d::Box, # Window rectangle in which to draw.
theme: wt::Widget_Theme,
get_font: List(String) -> evt::Font, # Accepts a list of font names which are tried in order; returns font 'ascent' and 'descent' in pixels -- sum them to get font height.
pass_font: List(String) -> Replyqueue #
-> ( evt::Font -> Void ) #
-> Void, # Nonblocking version of next, for use in imps.
make_rw_pixmap: g2d::Size -> g2p::Gadget_To_Rw_Pixmap
}
=
put_in_mailqueue (mailq,
#
\\ ({ id, gadget_to_guiboss, sprite_to_spritespace, ... }: Runstate)
=
{
initialize_gadget_fn # Let application-specific code handle start-of-frame however it likes.
{
id,
doc,
site,
#
gadget_to_guiboss,
sprite_to_spritespace,
theme,
get_font,
pass_font,
make_rw_pixmap,
do
};
}
);
fun redraw_gadget_request # We get this call at the start of every frame from
src/lib/x-kit/widget/gui/guiboss-imp.pkg {
frame_number: Int, # 1,2,3,... Purely for convenience of widget, guiboss-imp makes no use of this.
site: g2d::Box, # Window rectangle in which to draw.
popup_nesting_depth: Int, # 0 for gadgets on basewindow, 1 for gadgets on popup on basewindow, 2 for gadgets on popup on popup, etc.
duration_in_seconds: Float, # If state has changed look-imp should call redraw_gadget() before this time is up. Also useful for motionblur.
gadget_mode: gt::Gadget_Mode, # is_active/has_keyboard_focus/has_mouse_focus flags.
theme: wt::Widget_Theme
}
=
put_in_mailqueue (mailq,
#
\\ ({ id, gadget_to_guiboss, sprite_to_spritespace, ... }: Runstate)
=
{
redraw_request_fn # Let application-specific code handle start-of-frame however it likes.
{
id,
doc,
frame_number,
site,
popup_nesting_depth,
duration_in_seconds,
#
gadget_to_guiboss,
sprite_to_spritespace,
gadget_mode,
theme,
do
};
}
);
fun wakeup # These calls are scheduled via gadget_to_guiboss.wake_me.
{
wakeup_arg: gt::Wakeup_Arg, #
wakeup_fn: gt::Wakeup_Arg -> Void
}
=
put_in_mailqueue (mailq,
#
\\ ({ id, gadget_to_guiboss, ... }: Runstate)
=
wakeup_fn wakeup_arg
);
fun die ()
=
put_in_mailqueue (mailq,
#
\\ (runstate: Runstate)
=
shut_down_sprite_imp runstate
);
fun note_keyboard_focus
(
now_have_focus: Bool, # TRUE means we now have keyboard focus, FALSE means we no longer have it. Allows gadget to visually display focus locus, typically via a black outline and/or dis/abling cursor. See also Gadget_To_Guiboss.request_keyboard_focus
theme: wt::Widget_Theme
)
=
{
put_in_mailqueue (mailq,
#
\\ ({ id, gadget_to_guiboss, sprite_to_spritespace, ... }: Runstate)
=
# XXX SUCKO FIXME TBD
()
);
();
};
fun note_mouse_transit # Note that buttons are always all up in a mouse-transit event -- otherwise it is a mouse-drag event.
{
transit: gt::Gadget_Transit, # Mouse is entering (CAME) or leaving (LEFT) widget, or moving (MOVE) across it.
modifier_keys_state: evt::Modifier_Keys_State, # State of the modifier keys (shift, ctrl...).
event_point: g2d::Point,
site: g2d::Box, # Widget's assigned area in window coordinates.
theme: wt::Widget_Theme
} # Note keyboard keypress at 'point'.
= # ^ # 'point' ise the click point the window's coordinate system.
{ # Keyboard key just pressed down. #
put_in_mailqueue (mailq,
#
\\ ({ id, gadget_to_guiboss, sprite_to_spritespace, ... }: Runstate)
=
mouse_transit_fn
{
id,
doc,
event_point,
site,
transit,
modifier_keys_state,
gadget_to_guiboss,
sprite_to_spritespace,
theme,
do
}
);
};
fun note_mouse_drag_event
{
phase: gt::Drag_Phase, # LAUNCH/RESUME/FINISH.
button: evt::Mousebutton,
modifier_keys_state: evt::Modifier_Keys_State, # State of the modifier keys (shift, ctrl...).
mousebuttons_state: evt::Mousebuttons_State, # State of mouse buttons as a bool record.
event_point: g2d::Point,
start_point: g2d::Point,
last_point: g2d::Point,
site: g2d::Box, # Widget's assigned area in window coordinates.
theme: wt::Widget_Theme
} # Note keyboard keypress at 'point'.
= # ^ # 'point' ise the click point the window's coordinate system.
{ # Keyboard key just pressed down. #
put_in_mailqueue (mailq,
#
\\ ({ id, gadget_to_guiboss, sprite_to_spritespace, ... }: Runstate)
=
mouse_drag_fn
{
id,
doc,
event_point,
start_point,
last_point,
site,
phase,
button,
modifier_keys_state,
mousebuttons_state,
gadget_to_guiboss,
sprite_to_spritespace,
theme,
do
}
);
};
fun note_key_event
{
keystroke
as
{ key_event: gt::Key_Event, # KEY_PRESS or KEY_RELEASE.
keycode: evt::Keycode, # Keycode of the depressed key.
keysym: evt::Keysym, # Keysym of the depressed key.
keystring: String, # Ascii for the depressed key.
keychar: Char, # First char of 'string' ('\0' if string-length != 1).
modifier_keys_state: evt::Modifier_Keys_State, # State of the modifier keys (shift, ctrl...).
mousebuttons_state: evt::Mousebuttons_State # State of mouse buttons as a bool record.
}: gt::Keystroke_Info,
site: g2d::Box, # Widget's assigned area in window coordinates.
theme: wt::Widget_Theme
} # Note keyboard keypress at 'point'.
= # ^ # 'point' ise the click point the window's coordinate system.
{ # Keyboard key just pressed down. #
put_in_mailqueue (mailq,
#
\\ ({ id, gadget_to_guiboss, sprite_to_spritespace, ... }: Runstate)
=
key_event_fn
{
id,
doc,
keystroke,
site,
gadget_to_guiboss,
sprite_to_spritespace,
theme
}
);
};
fun note_mousebutton_event
{
mousebutton_event: gt::Mousebutton_Event, # MOUSEBUTTON_PRESS or MOUSEBUTTON_RELEASE.
mouse_button: evt::Mousebutton,
modifier_keys_state: evt::Modifier_Keys_State, # State of the modifier keys (shift, ctrl...).
mousebuttons_state: evt::Mousebuttons_State, # State of mouse buttons as a bool record.
event_point: g2d::Point,
site: g2d::Box, # Widget's assigned area in window coordinates.
theme: wt::Widget_Theme
} # Note mousebutton click at 'point'.
= # ^ # 'point' is the click point in the window's coordinate system.
{ # Mouse button just clicked down. #
put_in_mailqueue (mailq,
#
\\ ({ id, gadget_to_guiboss, sprite_to_spritespace, ... }: Runstate)
=
mouse_click_fn
{
id,
doc,
event => mousebutton_event,
button => mouse_button,
point => event_point,
site,
modifier_keys_state, # State of the modifier keys (shift, ctrl...).
mousebuttons_state, # State of mouse buttons as a bool record.
gadget_to_guiboss,
sprite_to_spritespace,
theme
}
);
};
#######################################################################
# spritespace_to_sprite fns:
fun do_something (i: Int) # PUBLIC.
=
put_in_mailqueue (mailq,
#
\\ ({ gadget_to_guiboss, ... }: Runstate)
=
()
);
fun pass_something (replyqueue: Replyqueue) (reply_handler: Int -> Void) # PUBLIC.
=
{ reply_oneshot = make_oneshot_maildrop(): Oneshot_Maildrop( Int );
#
put_in_mailqueue (mailq,
#
\\ (_: Runstate)
=
put_in_oneshot (reply_oneshot, 0)
);
put_in_replyqueue (replyqueue, (get_from_oneshot' reply_oneshot) ==> reply_handler);
};
fun pass_draw_done_flag (replyqueue: Replyqueue) (reply_handler: Void -> Void) # PUBLIC.
=
{ reply_oneshot = make_oneshot_maildrop(): Oneshot_Maildrop( Void );
#
put_in_mailqueue (mailq,
#
\\ (_: Runstate)
=
put_in_oneshot (reply_oneshot, ())
);
put_in_replyqueue (replyqueue, (get_from_oneshot' reply_oneshot) ==> reply_handler);
};
end;
fun process_options
( options: List(Sprite_Option),
#
{ name,
id,
doc,
#
sprite_callbacks,
widget_control_callbacks,
#
startup_fn,
shutdown_fn,
#
initialize_gadget_fn,
redraw_request_fn,
#
mouse_click_fn,
#
mouse_drag_fn,
mouse_transit_fn,
#
key_event_fn,
note_keyboard_focus_fn,
#
wants_keystrokes,
wants_mouseclicks
}
)
=
{ my_name = REF name;
my_id = REF id;
my_doc = REF doc;
#
my_sprite_callbacks = REF sprite_callbacks;
my_widget_control_callbacks = REF widget_control_callbacks;
#
my_startup_fn = REF startup_fn;
my_shutdown_fn = REF shutdown_fn;
#
my_initialize_gadget_fn = REF initialize_gadget_fn;
my_redraw_request_fn = REF redraw_request_fn;
#
my_mouse_click_fn = REF mouse_click_fn;
#
my_mouse_drag_fn = REF mouse_drag_fn;
my_mouse_transit_fn = REF mouse_transit_fn;
#
my_key_event_fn = REF key_event_fn;
my_note_keyboard_focus_fn = REF note_keyboard_focus_fn;
#
my_wants_keystrokes = REF wants_keystrokes;
my_wants_mouseclicks = REF wants_mouseclicks;
apply do_option options
where
fun do_option (MICROTHREAD_NAME n ) => my_name := n;
do_option (ID i ) => my_id := i;
do_option (DOC i) => my_doc := i;
#
do_option (SPRITE_CALLBACK c ) => my_sprite_callbacks := c ! *my_sprite_callbacks;
do_option (WIDGET_CONTROL_CALLBACK c ) => my_widget_control_callbacks := c ! *my_widget_control_callbacks;
#
do_option (STARTUP_FN fn) => my_startup_fn := fn;
do_option (SHUTDOWN_FN fn) => my_shutdown_fn := fn;
#
do_option (INITIALIZE_GADGET_FN fn) => my_initialize_gadget_fn := fn;
do_option (REDRAW_REQUEST_FN fn) => my_redraw_request_fn := fn;
#
do_option (MOUSE_CLICK_FN fn) => { my_mouse_click_fn := fn; my_wants_mouseclicks := TRUE; };
#
do_option (MOUSE_DRAG_FN fn) => { my_mouse_drag_fn := fn; };
do_option (MOUSE_TRANSIT_FN fn) => { my_mouse_transit_fn := fn; };
#
do_option (KEY_EVENT_FN fn) => { my_key_event_fn := fn; my_wants_keystrokes := TRUE; };
do_option (NOTE_KEYBOARD_FOCUS_FN fn) => { my_note_keyboard_focus_fn := fn; };
end;
end;
{ name => *my_name,
id => *my_id,
doc => *my_doc,
#
sprite_callbacks => *my_sprite_callbacks,
widget_control_callbacks => *my_widget_control_callbacks,
#
startup_fn => *my_startup_fn,
shutdown_fn => *my_shutdown_fn,
#
initialize_gadget_fn => *my_initialize_gadget_fn,
redraw_request_fn => *my_redraw_request_fn,
#
mouse_click_fn => *my_mouse_click_fn,
#
mouse_drag_fn => *my_mouse_drag_fn,
mouse_transit_fn => *my_mouse_transit_fn,
#
key_event_fn => *my_key_event_fn,
note_keyboard_focus_fn => *my_note_keyboard_focus_fn,
#
wants_keystrokes => *my_wants_keystrokes,
wants_mouseclicks => *my_wants_mouseclicks
};
};
# We do not use our usual Imports/Exports driven
# imp startup protocol here because we want to
# keep guiboss_imp from knowing anything about # guiboss_imp is from
src/lib/x-kit/widget/gui/guiboss-imp.pkg # the state types of widgets to avoid an explosion
# of cases in guiboss_imp, one per widget, but we
# do want guiboss_imp to do the actual widget-imp
# startup.
#
fun make_sprite_start_fn (widget_options: List(Sprite_Option))
=
{
(process_options
( widget_options,
{ name => "sprite",
id => id_zero,
doc => "",
#
sprite_callbacks => [],
widget_control_callbacks => [],
#
startup_fn => default_startup_fn,
shutdown_fn => default_shutdown_fn,
#
initialize_gadget_fn => default_initialize_gadget_fn,
redraw_request_fn => default_redraw_request_fn,
#
mouse_click_fn => default_mouse_click_fn,
#
mouse_drag_fn => default_mouse_drag_fn,
mouse_transit_fn => default_mouse_transit_fn,
#
key_event_fn => default_key_event_fn,
note_keyboard_focus_fn => default_note_keyboard_focus_fn,
#
wants_keystrokes => FALSE,
wants_mouseclicks => FALSE
}
) )
->
{ name,
id,
doc,
#
sprite_callbacks,
widget_control_callbacks,
#
startup_fn,
shutdown_fn,
#
initialize_gadget_fn,
redraw_request_fn,
#
mouse_click_fn,
#
mouse_drag_fn,
mouse_transit_fn,
#
key_event_fn,
note_keyboard_focus_fn,
#
wants_keystrokes,
wants_mouseclicks
};
id = if (id_to_int(id) == 0) issue_unique_id(); # Allocate unique imp id.
else id;
fi;
fun sprite_start_fn
{ gadget_to_guiboss: gt::Gadget_To_Guiboss, #
sprite_to_spritespace: w2p::Sprite_To_Spritespace, #
run_gun': Run_Gun,
shutdown_oneshot: Oneshot_Maildrop ( Void )
}
: gt::Sprite_Exports
=
{ reply_oneshot = make_oneshot_maildrop (): Oneshot_Maildrop( gt::Sprite_Exports );
#
xlogger::make_thread
name
(startup { id, # Note that startup() is curried.
doc,
reply_oneshot,
#
sprite_callbacks,
widget_control_callbacks,
startup_fn, # Pass in widget-specific args.
shutdown_fn, # Save state for possible widget restart.
#
initialize_gadget_fn,
redraw_request_fn,
#
mouse_click_fn,
#
mouse_drag_fn,
mouse_transit_fn,
#
key_event_fn,
note_keyboard_focus_fn,
#
wants_keystrokes,
wants_mouseclicks,
# These five args pass in the ports etc that guiboss-imp gave us.
gadget_to_guiboss, #
sprite_to_spritespace, #
run_gun',
shutdown_oneshot
# sprite_start_fn => gt::SPRITE_START_FN sprite_start_fn # Because we need to put this in shutdown_oneshot at end of run.
}
);
(get_from_oneshot reply_oneshot); # Return gt::Sprite_Exports to guiboss-imp.
};
gt::SPRITE_START_FN sprite_start_fn; # The value-added is that we've locked in the values of *_fn etc, and guiboss-imp can be agnostic about their types.
};
fun pprint_sprite_arg
(pp: pp::Prettyprinter)
(sprite_arg: Sprite_Arg)
=
{
sprite_arg
->
( options: List(Sprite_Option)
);
pp.box {.
pp.txt " [";
pp::seqx {. pp.txt ", "; }
pprint_option
options
;
pp.txt " ]";
pp.txt " )";
};
}
where
fun pprint_option option
=
case option
#
MICROTHREAD_NAME name => { pp.lit (sprintf "MICROTHREAD_NAME \"%s\"" name); };
ID id => { pp.lit (sprintf "ID %d" (id_to_int id) ); };
DOC docstring => { pp.lit (sprintf "DOC \"%s\"" docstring ); };
#
WIDGET_CONTROL_CALLBACK _ => { pp.lit "WIDGET_CONTROL_CALLBACK (callback)"; };
SPRITE_CALLBACK _ => { pp.lit "SPRITE_CALLBACK (callback)"; };
#
STARTUP_FN _ => { pp.lit "STARTUP_FN _"; };
SHUTDOWN_FN _ => { pp.lit "SHUTDOWN_FN _"; };
#
INITIALIZE_GADGET_FN _ => { pp.lit "INITIALIZE_GADGET_FN _"; };
REDRAW_REQUEST_FN _ => { pp.lit "REDRAW_REQUEST_FN _"; };
#
MOUSE_CLICK_FN _ => { pp.lit "MOUSE_CLICK_FN _"; };
#
MOUSE_DRAG_FN _ => { pp.lit "MOUSE_DRAG_FN _"; };
MOUSE_TRANSIT_FN _ => { pp.lit "MOUSE_TRANSIT_FN _"; };
#
KEY_EVENT_FN _ => { pp.lit "KEY_EVENT_FN _"; };
NOTE_KEYBOARD_FOCUS_FN _ => { pp.lit "NOTE_KEYBOARD_FOCUS_FN _"; };
esac;
end;
};
end;