## xsession-junk.pkg
#
# This package has the highest-level responsibility for
# managing all the state and operations relating to
# communication with a given X server.
#
#
# Architecture
# ------------
#
# Nomenclature: An 'imp' is a server microthread.
# (Like a daemon but smaller!)
#
# A 'ximp' is an X-specific imp.
#
# An xsocket is built of four imps.
# An xsession adds three more imps to make seven imps total.
# An xclient adds two more imps to make nine imps total.
# An X application adds an unbounded number of additional widget imps.
#
# Adapting from the page 8 diagram in
# http://mythryl.org/pub/exene/1991-ml-workshop.pdf
# our dataflow network for xsession looks like:
#
# ----------------------
#
| X server process |
# ----------------------
# ^
|
#
| v
# -------<network socket>------------- network and process boundary.
# ^
|xpackets
#
|xpackets v --- --- ---
# --------------- --------------- . . .
#
| outbuf_ximp | | inbuf_ximp | . . .
# --------------- --------------- . . .
# ^
| xpackets . . .
#
| xpackets v . . .
# ------------------------------- . . .
#
| xsequencer_ximp |--> (error handler) ... xsocket . .
# ------------------------------- . imps . .
# ^
| xpackets . . .
#
| v . ... xsession .
#
| ------------------------- . . imps .
#
| | decode_xpackets_ximp | . . .
#
| ------------------------- . . .
#
| | xevents --- . .
#
| v . .
#
| ------------------------- --------------- . .
#
| | xevent_router_ximp |--> | keymap_ximp | . .
#
| ------------------------- --------------- . .
#
| | xevents ^ ^ . .... xclient
#
| | | | . . imps
#
| | | | . .
#
| | | | --- .
# -------------------------
| | | .
#
| xserver_ximp | | | | .
# -------------------------
| | | .
# ^
| |get_window_site | .
#
| | xevents |note_new_hostwindow | ---
#
| v | v
# (.................................to/from widget threads......................................)
# ^
| ^ | ^ |
#
|xrequests | xevents |xrequests | xevents |xrequests | xevents
#
| v | v | v
# ------------------------- ------------------------- -------------------------
#
| xevent_to_widget_ximp | | xevent_to_widget_ximp | | xevent_to_widget_ximp | ...
# ------------------------- ------------------------- -------------------------
# / \ / \ / \
# / widget \ / widget \ / widget \
# / tree \ / tree \ / tree \
# / \ / \ / \
# / ... \ / ... \ / ... \
#
# Dramatis Personae:
#
# o The sequencer_imp matches replies to requests.
# All traffic to/from the X server goes through it.
# Implemented in:
src/lib/x-kit/xclient/src/wire/xsequencer-ximp.pkg#
# o The outbuf_imp optimizes network usage by
# combining multiple requests per network packet.
# Implemented in:
src/lib/x-kit/xclient/src/wire/outbuf-ximp.pkg#
# o The inbuf_imp breaks the incoming bytestream
# into individual replies and forwards them individually
# to sequencer_imp.
# Implemented in:
src/lib/x-kit/xclient/src/wire/inbuf-ximp.pkg#
# o The decode_xpackets_imp cracks raw wire-format bytestrings into
# xevent_types::x::Event values and combines multiple related Expose
# events into a single logical Expose event for ease of downstream
# processing.
# Implemented in:
src/lib/x-kit/xclient/src/wire/decode-xpackets-ximp.pkg#
# o The xevent_to_window_imp imp receives all X events
# (e.g. keystrokes and mouseclicks) and feeds each one to the
# appropriate toplevel window, or more precisely to the
# hostwindow_to_widget_router at the root of the widgettree for
# ("xevent_to_widget_imp" might be a better name)
# that window, there to trickle down the widgettree to its ultimate
# target widget.
#
# To do this, xevent_to_window_imp
# tracks all X windows created by the application,
# keyed by their X IDs. (Toplevel X windows are
# registered at creation by the window-old.pkg functions;
# subwindows are registered when their X notify event
# comes through.)
#
# Implemented in:
src/lib/x-kit/xclient/src/window/xevent-router-ximp.pkg# See also:
src/lib/x-kit/xclient/src/window/xevent-to-widget-ximp.pkg#
# o The font_imp ...
# Implemented in:
src/lib/x-kit/xclient/src/window/font-index.pkg#
# o The keymap_ximp ...
# Implemented in:
src/lib/x-kit/xclient/src/window/keymap-ximp.pkg#
#
# o The xserver_ximp processes draw commands and breaks
# them into subsequences which can share a single
# X server graphics context, in order to minimize
# the number of graphics context switches required.
# It works closely with the pen-to-gcontext-imp.
# Implemented in:
src/lib/x-kit/xclient/src/window/xserver-ximp.pkg#
# o The pen_cache maps between the immutable "pens"
# we provide to the application programmer and the mutable
# graphics contexts actually supported by the X server. Given
# a pen, it returns a matching graphics context, using an
# existing one unchanged if possible, else modifying an
# existing one appropropriately.
# Implemented in:
src/lib/x-kit/xclient/src/window/pen-cache.pkg#
#
# All mouse and keyboard events flow down through the
# inbuf, sequencer, decoder and xevent-to-window imps
# and thence down through the widget hierarchy
# associated with the relevant hostwindow.
#
# Client xserver requests and responses are sent
# directly to the sequencer imp, with the exception
# of font requests and responses, which run through
# the font imp.
#
# Keysym translations are handled by keymap_ximp.
# Compiled by:
#
src/lib/x-kit/xclient/xclient-internals.sublib### "I have always wished that my computer
### would be as easy to use as my telephone.
### My wish has come true ... I no longer
### know how to use my telephone."
###
### -- Bjarne Stroustrup
stipulate
include package threadkit; # threadkit is from
src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg #
package ax = atom_ximp; # atom_ximp is from
src/lib/x-kit/xclient/src/iccc/atom-ximp.pkg package g2d = geometry2d; # geometry2d is from
src/lib/std/2d/geometry2d.pkg package cs = color_spec; # color_spec is from
src/lib/x-kit/xclient/src/window/color-spec.pkg package kab = keys_and_buttons; # keys_and_buttons is from
src/lib/x-kit/xclient/src/wire/keys-and-buttons.pkg package v2w = value_to_wire; # value_to_wire is from
src/lib/x-kit/xclient/src/wire/value-to-wire.pkg package s2w = sendevent_to_wire; # sendevent_to_wire is from
src/lib/x-kit/xclient/src/wire/sendevent-to-wire.pkg package w2v = wire_to_value; # wire_to_value is from
src/lib/x-kit/xclient/src/wire/wire-to-value.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 clx = xclient_ximps; # xclient_ximps is from
src/lib/x-kit/xclient/src/window/xclient-ximps.pkg package wpx = window_watcher_ximp; # window_watcher_ximp is from
src/lib/x-kit/xclient/src/window/window-watcher-ximp.pkg package sel = selection_ximp; # selection_ximp is from
src/lib/x-kit/xclient/src/window/selection-ximp.pkg# Not visible here:
# package qk = quark; # quark is from
src/lib/x-kit/style/quark.pkg# package imx = image_ximp; # image_ximp is from
src/lib/x-kit/widget/lib/image-ximp.pkg# package rpx = ro_pixmap_ximp; # ro_pixmap_ximp is from
src/lib/x-kit/widget/lib/ro-pixmap-ximp.pkg# package shx = shade_ximp; # shade _ximp is from
src/lib/x-kit/widget/lib/shade-ximp.pkg package mop = mailop; # mailop is from
src/lib/src/lib/thread-kit/src/core-thread-kit/mailop.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 dt = draw_types; # draw_types is from
src/lib/x-kit/xclient/src/window/draw-types.pkg# package rwp = rw_pixmap; # rw_pixmap is from
src/lib/x-kit/xclient/src/window/rw-pixmap.pkg# package dy = display_old; # display_old is from
src/lib/x-kit/xclient/src/wire/display-old.pkg package dy = display; # display is from
src/lib/x-kit/xclient/src/wire/display.pkg# package fti = font_imp_old; # "fi" is taken! :-) # font_imp_old is from
src/lib/x-kit/xclient/src/window/font-imp-old.pkg package fti = font_index; # font_index is from
src/lib/x-kit/xclient/src/window/font-index.pkg# package s2t = xsocket_to_hostwindow_router_old; # xsocket_to_hostwindow_router_old is from
src/lib/x-kit/xclient/src/window/xsocket-to-hostwindow-router-old.pkg package s2t = xevent_router_ximp; # xevent_router_ximp is from
src/lib/x-kit/xclient/src/window/xevent-router-ximp.pkg package a2r = windowsystem_to_xevent_router; # windowsystem_to_xevent_router is from
src/lib/x-kit/xclient/src/window/windowsystem-to-xevent-router.pkg #
# package xok = xsocket_old; # xsocket_old is from
src/lib/x-kit/xclient/src/wire/xsocket-old.pkg package x2s = xclient_to_sequencer; # xclient_to_sequencer is from
src/lib/x-kit/xclient/src/wire/xclient-to-sequencer.pkg package sj = socket_junk; # socket_junk is from
src/lib/internet/socket-junk.pkg# package ai = atom_imp_old; # atom_imp_old is from
src/lib/x-kit/xclient/src/iccc/atom-imp-old.pkg package ai = atom_ximp; # atom_ximp is from
src/lib/x-kit/xclient/src/iccc/atom-ximp.pkg package ap = client_to_atom; # client_to_atom is from
src/lib/x-kit/xclient/src/iccc/client-to-atom.pkg# package di = draw_imp_old; # draw_imp_old is from
src/lib/x-kit/xclient/src/window/draw-imp-old.pkg package di = xserver_ximp; # xserver_ximp is from
src/lib/x-kit/xclient/src/window/xserver-ximp.pkg# package ki = keymap_imp_old; # keymap_imp_old is from
src/lib/x-kit/xclient/src/window/keymap-imp-old.pkg package ki = keymap_ximp; # keymap_ximp is from
src/lib/x-kit/xclient/src/window/keymap-ximp.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 w2x = windowsystem_to_xserver; # windowsystem_to_xserver is from
src/lib/x-kit/xclient/src/window/windowsystem-to-xserver.pkg package exx = xserver_ximp; # xserver_ximp is from
src/lib/x-kit/xclient/src/window/xserver-ximp.pkg# package si = selection_imp_old; # selection_imp_old is from
src/lib/x-kit/xclient/src/window/selection-imp-old.pkg package si = selection_ximp; # selection_ximp is from
src/lib/x-kit/xclient/src/window/selection-ximp.pkg package sep = client_to_selection; # client_to_selection is from
src/lib/x-kit/xclient/src/window/client-to-selection.pkg# package wpi = window_property_imp_old; # window_property_imp_old is from
src/lib/x-kit/xclient/src/window/window-property-imp-old.pkg package wpi = window_watcher_ximp; # window_watcher_ximp is from
src/lib/x-kit/xclient/src/window/window-watcher-ximp.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 #
trace = xtr::log_if xtr::io_logging 0; # Conditionally write strings to tracing.log or whatever.
herein
package xsession_junk
: Xsession_Junk # Xsession_Junk is from
src/lib/x-kit/xclient/src/window/xsession-junk.api {
Per_Depth_Imps = { # The pen-cache and draw_ximp for a given depth, visual and screen.
depth: Int,
windowsystem_to_xserver: w2x::Windowsystem_To_Xserver, # The xpacket encoder for this depth on this screen.
window_map_event_sink: wme::Window_Map_Event_Sink
}; #
# For each combination of visual and depth
# we allot a pair of imps, one to draw,
# one to manage graphics contexts.
# This is forced because X requires that
# each GraphicsContext and pixmap be associated
# with a particular screen, visual and depth.
Screen_Info = {
xscreen: dy::Xscreen, # Xscreen def in
src/lib/x-kit/xclient/src/wire/display.pkg per_depth_imps: List( Per_Depth_Imps ), # The pen-cache and draw imps for the supported depths on this screen.
rootwindow_per_depth_imps: Per_Depth_Imps # The pen-cache and draw imps for the root window on this screen.
};
Xsession = {
xdisplay: dy::Xdisplay, #
screens: List( Screen_Info ),
default_screen_info: Screen_Info,
windowsystem_to_xevent_router: a2r::Windowsystem_To_Xevent_Router, # Feeds X events to appropriate toplevel window.
font_index: fti::Font_Index,
client_to_atom: ap::Client_To_Atom,
client_to_window_watcher: wpp::Client_To_Window_Watcher,
client_to_selection: sep::Client_To_Selection,
windowsystem_to_xserver: w2x::Windowsystem_To_Xserver,
xevent_router_to_keymap: r2k::Xevent_Router_To_Keymap
};
Screen = { # A screen handle for users.
xsession: Xsession,
screen_info: Screen_Info
};
Rw_Pixmap = { # An off-screen rectangular array of pixels on the X server.
pixmap_id: xt::Pixmap_Id,
screen: Screen,
size: g2d::Size,
per_depth_imps: Per_Depth_Imps
};
Ro_Pixmap = RO_PIXMAP Rw_Pixmap; # Immutable pixmaps
#
Window = # An on-screen rectangular array of pixels on the X server.
{
window_id: xt::Window_Id,
#
screen: Screen,
per_depth_imps: Per_Depth_Imps,
#
windowsystem_to_xserver: w2x::Windowsystem_To_Xserver,
#
subwindow_or_view: Null_Or( Rw_Pixmap )
};
# Identity tests:
#
fun same_xsession
( { xdisplay=>{ socket => x1, ... }: dy::Xdisplay, ... }: Xsession,
{ xdisplay=>{ socket => x2, ... }: dy::Xdisplay, ... }: Xsession
)
=
(x1 == x2);
# xok::same_xsocket (x1, x2); # Repply had this
#
fun same_screen ( { xsession=>xsession1, screen_info=> { xscreen => { id=>id1, ... }: dy::Xscreen, ... }: Screen_Info }: Screen,
{ xsession=>xsession2, screen_info=> { xscreen => { id=>id2, ... }: dy::Xscreen, ... }: Screen_Info }: Screen
)
=
(id1 == id2)
and
same_xsession (xsession1, xsession2);
#
fun same_window ( { window_id=>id1, screen=>s1, ... }: Window,
{ window_id=>id2, screen=>s2, ... }: Window )
=
(id1 == id2) and same_screen (s1, s2);
# We are typically called from open_xsession() below:
#
fun make_per_screen_xsession_imps # This fn is currently private to this file.
{
run_gun': mop::Run_Gun,
end_gun': mop::End_Gun,
windowsystem_to_xevent_router: a2r::Windowsystem_To_Xevent_Router, # Directs X mouseclicks etc to right hostwindow.
windowsystem_to_xserver: w2x::Windowsystem_To_Xserver, # Everyone but xserver-imp should use this instead of xclient_to_sequencer.
xclient_to_sequencer: x2s::Xclient_To_Sequencer, # All drawing commands go to Xserver via sequencer then outbuf.
client_to_atom: ap::Client_To_Atom,
xevent_router_to_keymap: r2k::Xevent_Router_To_Keymap,
client_to_selection: sep::Client_To_Selection,
client_to_window_watcher: wpp::Client_To_Window_Watcher,
xdisplay: dy::Xdisplay,
drawable: xt::Drawable_Id
# display_name: String,
# xauthentication: Null_Or( xt::Xauthentication ) # Xauthentication info comes ultimately from ~/.Xauthority
}
=
{
# printf "make_xsession/AAA -- xsession-junk.pkg\n";
# We turn this off in close_xession, so for symmetry's
# sake we turn it on here in open_xsession:
# # tracing is from
src/lib/src/lib/thread-kit/src/lib/logger.pkg# logger::disable thread_deathwatch::logging; # thread_deathwatch is from
src/lib/src/lib/thread-kit/src/lib/thread-deathwatch.pkg xdisplay -> { default_screen, screens, next_xid, ... }: dy::Xdisplay;
font_index = fti::make_font_index ();
#
fun make_screen_info (xscreen as { root_window_id, root_visual, visuals, ... }: dy::Xscreen )
=
{ fun make_per_depth_imps (depth, drawable)
=
{
# drawimp_mappedstate_slot = make_mailslot ();
# make_thread "send FIRST_EXPOSE" {. put_in_mailslot (drawimp_mappedstate_slot, di::s::FIRST_EXPOSE); };
(exx::make_xserver_egg (xdisplay, drawable, [])) -> xserver_egg;
(xserver_egg ()) -> (exports, xserver_egg');
xserver_egg' ({ windowsystem_to_xevent_router, xclient_to_sequencer }, run_gun', end_gun');
windowsystem_to_xserver = exports.windowsystem_to_xserver;
window_map_event_sink = exports.window_map_event_sink;
{ depth, windowsystem_to_xserver, window_map_event_sink }: Per_Depth_Imps;
};
#
fun make_pen_imps ([], l)
=>
l;
make_pen_imps (vd ! r, l)
=>
make_pen_imps (r, get l)
where
visual_depth = dy::depth_of_visual vd;
#
fun make_imps ()
=
{ pixmap_id = next_xid ();
# Make a pixmap to serve as the witness drawable
# for the graphics context ("GC") server:
#
windowsystem_to_xserver.xclient_to_sequencer.send_xrequest
( v2w::encode_create_pixmap
{ pixmap_id,
drawable_id => root_window_id,
size => { wide=>1, high=>1 },
depth => visual_depth
}
);
make_per_depth_imps (visual_depth, pixmap_id);
};
#
fun get [] => make_imps() ! l;
#
get (({ depth, ... }: Per_Depth_Imps) ! rest)
=>
depth == visual_depth
?? l
:: get rest;
end;
end;
end;
rootwindow_per_depth_imps
=
make_per_depth_imps (dy::depth_of_visual root_visual, root_window_id);
per_depth_imps
=
make_pen_imps (visuals, [ rootwindow_per_depth_imps ]);
per_depth_imps
=
make_pen_imps ( [ xt::NO_VISUAL_FOR_THIS_DEPTH 1 ],
per_depth_imps
);
{ xscreen,
per_depth_imps,
rootwindow_per_depth_imps
}
: Screen_Info
;
}; # fun make_screen_info
screens = map make_screen_info screens;
# printf "make_xsession/ZZZ -- xsession-junk.pkg\n";
{
xdisplay,
default_screen_info => list::nth (screens, default_screen),
screens,
windowsystem_to_xevent_router,
client_to_atom,
font_index,
client_to_window_watcher,
client_to_selection,
windowsystem_to_xserver,
# xclient_to_sequencer,
xevent_router_to_keymap
}: Xsession;
}; # fun make_per_screen_xsession_imps
# We are typically called from make_root_window() in
#
#
src/lib/x-kit/widget/lib/root-window.pkg #
fun open_xsession
{
display_name: String,
xauthentication: Null_Or( xt::Xauthentication ),
run_gun': mop::Run_Gun,
end_gun': mop::End_Gun
}
=
{
# printf "open_xsession/AAA calling open_xdisplay display_name s='%s' -- xsession-junk.pkg\n" display_name;
(dy::open_xdisplay { display_name, xauthentication })
->
(xdisplay as { default_screen, screens, socket, next_xid, ... }: dy::Xdisplay ); # Canonical sequence has 'xsocket' not 'socket' here.
# printf "open_xsession/BBB back from open_xdisplay display_name s='%s' -- xsession-junk.pkg\n" display_name;
default_screen = list::nth (screens, default_screen)
except
INDEX_OUT_OF_BOUNDS = { msg = "Bad default_screen value -- make_root_window in xclient-ximps-junk.pkg";
log::fatal msg; # Doesn't return.
raise exception DIE msg; # Should never get here.
};
default_screen -> { root_window_id, ... }: dy::Xscreen;
# (make_run_gun ()) -> { run_gun', fire_run_gun };
# (make_end_gun ()) -> { end_gun', fire_end_gun };
(clx::make_xclient_ximps_egg (socket, xdisplay, root_window_id, [])) -> xclient_ximps_egg;
(xclient_ximps_egg ()) -> (xclient_ximps_exports, xclient_ximps_egg');
(ax::make_atom_egg [] ) -> atom_egg;
(atom_egg () ) -> (atom_exports, atom_egg');
(wpx::make_window_watcher_egg [] ) -> window_watcher_egg;
(window_watcher_egg () ) -> (window_watcher_exports, window_watcher_egg');
(sel::make_selection_egg [] ) -> selection_egg;
(selection_egg () ) -> (selection_exports, selection_egg');
xclient_ximps_exports -> { windowsystem_to_xserver, windowsystem_to_xevent_router, xevent_router_to_keymap, xclient_to_sequencer, xerror_well };
xclient_to_sequencer = windowsystem_to_xserver.xclient_to_sequencer;
client_to_window_watcher = window_watcher_exports.client_to_window_watcher;
window_property_xevent_sink = window_watcher_exports.window_property_xevent_sink;
client_to_selection = selection_exports.client_to_selection;
selection_xevent_sink = selection_exports.selection_xevent_sink;
client_to_atom = atom_exports.client_to_atom;
# not visible here.
#
# TBD: image_ximp configuration
# window_property_xevent_sink = { put_value => (\\ (event: et::x::Event) = { log::fatal "window_property_xevent_sink called"; (); }) }; # Dummy to 'handle' X server PropertyNotify events.
# selection_xevent_sink = { put_value => (\\ (event: et::x::Event) = { log::fatal "selection_xevent_sink called" ; (); }) }; # Dummy to 'handle' X server SelectionNotify, SelectionRequest and SelectionClear events.
xclient_ximps_egg' ( { window_property_xevent_sink, selection_xevent_sink },
run_gun', end_gun'
);
atom_egg' ( { xclient_to_sequencer }, # XXX SUCKO FIXME probably we should pass windowsystem_to_xserver not xclient_to_sequencer here -- we want to encourage everyone but xserver to avoid using xclient_to_sequencer to avoid race conditions.
run_gun', end_gun'
);
window_watcher_egg' ( { client_to_atom /* , xclient_to_sequencer */ },
run_gun', end_gun'
);
selection_egg' ( { xclient_to_sequencer }, # XXX SUCKO FIXME probably we should pass windowsystem_to_xserver not xclient_to_sequencer here -- we want to encourage everyone but xserver to avoid using xclient_to_sequencer to avoid race conditions.
run_gun', end_gun'
);
xsession = make_per_screen_xsession_imps
{
run_gun',
end_gun',
windowsystem_to_xevent_router,
windowsystem_to_xserver,
xclient_to_sequencer, # XXX SUCKO FIXME probably we should pass windowsystem_to_xserver not xclient_to_sequencer here -- we want to encourage everyone but xserver to avoid using xclient_to_sequencer to avoid race conditions.
client_to_atom,
xevent_router_to_keymap,
client_to_selection,
client_to_window_watcher,
xdisplay,
drawable => root_window_id
};
# printf "open_xsession/ZZZ -- xsession-junk.pkg\n";
xsession;
}; # fun open_xsession
fun send_xrequest (x: Xsession) request
=
x.windowsystem_to_xserver.xclient_to_sequencer.send_xrequest request; # XXX SUCKO FIXME probably we should use windowsystem_to_xserver not xclient_to_sequencer here -- we want to encourage everyone but xserver to avoid using xclient_to_sequencer to avoid race conditions.
# X-server I/O.
#
# stipulate
# #
# fun apply_to_xsocket f ({ xdisplay=>{ xsocket, ... }: dy::Xdisplay, ... }: Xsession )
# =
# f xsocket;
#
# herein
#
# send_xrequest = apply_to_xsocket xok::send_xrequest;
# send_xrequest_and_return_completion_mailop = apply_to_xsocket xok::send_xrequest_and_return_completion_mailop;
#
# send_xrequest_and_read_reply = apply_to_xsocket xok::send_xrequest_and_read_reply;
# sent_xrequest_and_read_replies = apply_to_xsocket xok::sent_xrequest_and_read_replies;
#
# flush_out = apply_to_xsocket xok::flush_xsocket;
#
# query_best_size = apply_to_xsocket xok::query_best_size;
# query_colors = apply_to_xsocket xok::query_colors;
# query_font = apply_to_xsocket xok::query_font;
# query_pointer = apply_to_xsocket xok::query_pointer;
# query_text_extents = apply_to_xsocket xok::query_text_extents;
# query_tree = apply_to_xsocket xok::query_tree;
#
# end;
# Get location of mouse pointer
# plus related information:
#
# fun get_mouse_location
# (
# { xdisplay => { xsocket, ... }: dy::Xdisplay,
# default_screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
# ...
# }: Xsession
# )
# =
# { # The X server query_pointer call takes a window_id
# # argument. This seems overcomplex for the typical
# # Mythryl caller, so here we just default it to the
# # the default-screen root-window:
# #
# (xok::query_pointer xsocket { window_id => root_window_id })
# ->
# { root_point, ... };
#
# # The X server query_pointer call returns
# # a load of stuff. For now at least, a
# # return value of simply the mouse location
# # seems more convenient for the Mythryl app hacker:
# #
# root_point;
# };
#
# fun set_mouse_location
# (
# { xdisplay => { xsocket, ... }: dy::Xdisplay,
# default_screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
# ...
# }: Xsession
# )
# to_point
# =
# { # This is an ignored dummy value:
# #
# from_box = { col => 0, row => 0, wide => 0, high => 0 };
#
# command
# =
# v2w::encode_warp_pointer
# {
# to_point, # Move mouse pointer to this coordinate.
# to => THE root_window_id, # Position mouse relative to root window.
# # # (That is, in absolute screen coordinates.)
# from => NULL,
# from_box # Ignored because 'from' is NULL.
# };
#
# xok::send_xrequest xsocket command;
# };
# Map a point in the window's coordinate
# system to the screen's coordinate system:
#
fun window_point_to_screen_point ({ window_id, screen, ... }: Window ) pt
=
{ screen -> { xsession => (x: Xsession), screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info, ... }: Screen;
#
my { to_point, ... }
=
w2v::decode_translate_coordinates_reply
(
block_until_mailop_fires
# ======================== XXX SUCKO FIXME
(x.windowsystem_to_xserver.xclient_to_sequencer.send_xrequest_and_read_reply
(v2w::encode_translate_coordinates { from_window=>window_id, to_window=>root_window_id, from_point=>pt } )
)
);
to_point;
};
# Fake up an X server timestamp for the current time
# by taking the time of day in milliseconds to 32-bit
# accuracy and then jiggering the type appropriately:
#
fun bogus_current_x_timestamp ()
=
{ time = time::get_current_time_utc (); # Current time
ms = time::to_milliseconds time; # in milliseconds since the Epoch
ms32 = large_int::(%) (ms, (large_int::from_int 256)
* (large_int::from_int 256)
* (large_int::from_int 256)
* (large_int::from_int 256)); # truncated to 32-bit accuracy
ms32 = one_word_unt::from_multiword_int ms32; # converted to 32-bit unsigned
ms32 = xserver_timestamp::XSERVER_TIMESTAMP ms32; # wrapped up as a
ms32 = xtypes::TIMESTAMP ms32; # proper X timestamp value.
ms32;
};
#
fun send_fake_key_press_xevent
(
{ default_screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
...
}: Xsession
)
{ window => window as { window_id, windowsystem_to_xserver, ... }: Window, # Window handling the keyboard-key press event.
keycode, # Keyboard key just "pressed".
point => point as { row, col } # Keypress location in local window coordinates.
}
=
{ # We need the keypress point in both
# local and screen coords:
#
# trace {. sprintf "xsession: send_fake_key_press_event/TOP window_point = { row %d, col %d }." row col; };
(window_point_to_screen_point window point)
->
{ row => screen_row,
col => screen_col
};
# trace {. sprintf "xsession: send_fake_key_press_event/MID screen_point = { row %d, col %d }." screen_row screen_col; };
# For the semantics of these three fields see
# p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
#
send_event_to = xt::SEND_EVENT_TO_WINDOW window_id;
propagate = FALSE;
event_mask = xt::EVENT_MASK 0u0;
#
# timestamp = xt::CURRENT_TIME; # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
timestamp = bogus_current_x_timestamp (); # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
# Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
root_window_id = root_window_id;
event_window_id = window_id; # Window handling the keyboard-key "press" event.
child_window_id = NULL; # We'll assume specified window is a leaf.
root_x = screen_col; # Mouse position on root window at time of keypress.
root_y = screen_row;
event_x = col; # Mouse position on recipient window at time of keypress.
event_y = row;
buttons = kab::make_mousebutton_state [ ]; # Mouse buttons state BEFORE keypress.
# trace {. "xsession: send_fake_key_press_event/YYY calling s2w::encode_send_keypress_xevent"; };
command
=
s2w::encode_send_keypress_xevent
{
send_event_to, propagate, event_mask,
timestamp, root_window_id, event_window_id,
child_window_id, root_x, root_y,
event_x, event_y, keycode, buttons
};
windowsystem_to_xserver.xclient_to_sequencer.send_xrequest command; # Here we used to have xclient_to_sequencer.send_xrequest command;
# but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_key_press_event/BOT called s2w::encode_send_keypress_xevent -- DONE"; };
();
};
#
fun send_fake_key_release_xevent
(
{ default_screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
...
}: Xsession
)
{ window => window as { window_id, windowsystem_to_xserver, ... }: Window, # Window handling the keyboard-key release event.
keycode, # Keyboard key just "released".
point => point as { row, col } # Key release location in local window coordinates.
}
=
{ # We need the key release point in both
# local and screen coords:
#
# trace {. sprintf "xsession: send_fake_key_release_event/TOP window_point = { row %d, col %d }." row col; };
(window_point_to_screen_point window point)
->
{ row => screen_row,
col => screen_col
};
# trace {. sprintf "xsession: send_fake_key_release_event/MID screen_point = { row %d, col %d }." screen_row screen_col; };
# For the semantics of these three fields see
# p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
#
send_event_to = xt::SEND_EVENT_TO_WINDOW window_id;
propagate = FALSE;
event_mask = xt::EVENT_MASK 0u0;
#
# timestamp = xt::CURRENT_TIME; # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
timestamp = bogus_current_x_timestamp (); # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
# Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
root_window_id = root_window_id;
event_window_id = window_id; # Window handling the keyboard-key "release" event.
child_window_id = NULL; # We'll assume specified window is a leaf.
root_x = screen_col; # Mouse position on root window at time of key "release".
root_y = screen_row;
event_x = col; # Mouse position on recipient window at time of key "release".
event_y = row;
buttons = kab::make_mousebutton_state [ ]; # Mouse buttons state BEFORE key release.
# trace {. "xsession: send_fake_key_release_event/YYY calling s2w::encode_send_keyrelease_xevent"; };
command
=
s2w::encode_send_keyrelease_xevent
{
send_event_to, propagate, event_mask,
timestamp, root_window_id, event_window_id,
child_window_id, root_x, root_y,
event_x, event_y, keycode, buttons
};
windowsystem_to_xserver.xclient_to_sequencer.send_xrequest command; # Here we used to have xclient_to_sequencer.send_xrequest command;
# but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_key_release_event/BOT called s2w::encode_send_keyrelease_xevent -- DONE"; };
();
};
#
fun send_fake_mousebutton_press_xevent
(
{ default_screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
...
}: Xsession
)
{ window => window as { window_id, windowsystem_to_xserver, ... }: Window, # Window handling the mouse-button click event.
button, # Mouse button just "clicked" down.
point => point as { row, col } # Click location in local window coordinates.
}
=
{ # We need the clickpoint in both
# local and screen coords:
#
# trace {. sprintf "xsession: send_fake_mousebutton_press_event/TOP window_point = { row %d, col %d }." row col; };
(window_point_to_screen_point window point)
->
{ row => screen_row,
col => screen_col
};
# trace {. sprintf "xsession: send_fake_mousebutton_press_event/MID screen_point = { row %d, col %d }." screen_row screen_col; };
# For the semantics of these three fields see
# p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
#
send_event_to = xt::SEND_EVENT_TO_WINDOW window_id;
propagate = FALSE;
event_mask = xt::EVENT_MASK 0u0;
#
# timestamp = xt::CURRENT_TIME; # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
timestamp = bogus_current_x_timestamp (); # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
# Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
root_window_id = root_window_id;
event_window_id = window_id; # Window handling the mouse-button release event.
child_window_id = NULL; # We'll assume specified window is a leaf.
root_x = screen_col; # Mouse position on root window at time of button release.
root_y = screen_row;
event_x = col; # Mouse position on recipient window at time of button release.
event_y = row;
buttons = kab::make_mousebutton_state [ ]; # Mouse buttons state BEFORE button press.
# trace {. "xsession: send_fake_mousebutton_press_event/YYY calling s2w::encode_send_buttonpress_xevent"; };
command = s2w::encode_send_buttonpress_xevent
{
send_event_to, propagate, event_mask,
timestamp, root_window_id, event_window_id,
child_window_id, root_x, root_y,
event_x, event_y, button, buttons
};
windowsystem_to_xserver.xclient_to_sequencer.send_xrequest command; # Here we used to have xclient_to_sequencer.send_xrequest command;
# but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_mousebutton_press_event/BOT called s2w::encode_send_buttonpress_xevent -- DONE"; };
();
};
#
fun send_fake_mousebutton_release_xevent
(
{ default_screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
...
}: Xsession
)
{ window => window as { window_id, windowsystem_to_xserver, ... }: Window, # Window handling the mouse-button click event.
button, # Mouse button just "clicked" down.
point => point as { row, col } # Click location in local window coordinates.
}
=
{ # We need the clickpoint in both
# local and screen coords:
#
# trace {. sprintf "xsession: send_fake_mousebutton_release_xevent/TOP window_point = { row %d, col %d }." row col; };
(window_point_to_screen_point window point)
->
{ row => screen_row,
col => screen_col
};
# trace {. sprintf "xsession: send_fake_mousebutton_release_xevent/MID screen_point = { row %d, col %d }." screen_row screen_col; };
# For the semantics of these three fields see
# p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
#
send_event_to = xt::SEND_EVENT_TO_WINDOW window_id;
propagate = FALSE;
event_mask = xt::EVENT_MASK 0u0;
#
# timestamp = xt::CURRENT_TIME; # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
timestamp = bogus_current_x_timestamp (); # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
# Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
root_window_id = root_window_id;
event_window_id = window_id; # Window handling the mouse-button release event.
child_window_id = NULL; # We'll assume specified window is a leaf.
root_x = screen_col; # Mouse position on root window at time of button release.
root_y = screen_row;
event_x = col; # Mouse position on recipient window at time of button release.
event_y = row;
buttons = kab::make_mousebutton_state [ button ]; # Mouse buttons state BEFORE button release.
# trace {. "xsession: send_fake_mousebutton_release_xevent/YYY calling s2w::encode_send_buttonpress_xevent"; };
command = s2w::encode_send_buttonrelease_xevent
{
send_event_to, propagate, event_mask,
timestamp, root_window_id, event_window_id,
child_window_id, root_x, root_y,
event_x, event_y, button, buttons
};
windowsystem_to_xserver.xclient_to_sequencer.send_xrequest command; # Here we used to have xclient_to_sequencer.send_xrequest command;
# but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_mousebutton_release_event/BOT called s2w::encode_send_buttonpress_xevent -- DONE"; };
();
};
#
fun send_fake_mouse_motion_xevent
(
{ default_screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
...
}: Xsession
)
{ window => window as { window_id, windowsystem_to_xserver, ... }: Window, # Window handling the mouse-moution event.
buttons, # Mouse button(s) being dragged.
point => point as { row, col } # Motion location in local window coordinates.
}
=
{ # We need the clickpoint in both
# local and screen coords:
#
# trace {. sprintf "xsession: send_fake_mouse_motion_xevent/TOP window_point = { row %d, col %d }." row col; };
(window_point_to_screen_point window point)
->
{ row => screen_row,
col => screen_col
};
# trace {. sprintf "xsession: send_fake_mouse_motion_xevent/MID screen_point = { row %d, col %d }." screen_row screen_col; };
# For the semantics of these three fields see
# p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
#
send_event_to = xt::SEND_EVENT_TO_WINDOW window_id;
propagate = FALSE;
event_mask = xt::EVENT_MASK 0u0;
#
# timestamp = xt::CURRENT_TIME; # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
timestamp = bogus_current_x_timestamp (); # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
# Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
root_window_id = root_window_id;
event_window_id = window_id; # Window handling the mouse-button release event.
child_window_id = NULL; # We'll assume specified window is a leaf.
root_x = screen_col; # Mouse position on root window at time of button release.
root_y = screen_row;
event_x = col; # Mouse position on recipient window at time of button release.
event_y = row;
buttons = kab::make_mousebutton_state buttons; # Mouse buttons being dragged
# trace {. "xsession: send_fake_mouse_motion_xevent/YYY calling s2w::encode_send_motionnotify_xevent"; };
command = s2w::encode_send_motionnotify_xevent
{
send_event_to, propagate, event_mask,
timestamp, root_window_id, event_window_id,
child_window_id, root_x, root_y,
event_x, event_y, buttons
};
windowsystem_to_xserver.xclient_to_sequencer.send_xrequest command; # Here we used to have xclient_to_sequencer.send_xrequest command;
# but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_mouse_motion_event/BOT called s2w::encode_send_motionnotify_xevent -- DONE"; };
();
};
#
fun send_fake_''mouse_enter''_xevent
(
{ default_screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
...
}: Xsession
)
{ window => window as { window_id, windowsystem_to_xserver, ... }: Window, # Window handling the mouse-button click event.
point => point as { row, col } # Click location in local window coordinates.
}
=
{ # We need the point in both
# local and screen coords:
#
# trace {. sprintf "xsession: send_fake_''mouse_enter''_xevent/TOP window_point = { row %d, col %d }." row col; };
(window_point_to_screen_point window point)
->
{ row => screen_row,
col => screen_col
};
# trace {. sprintf "xsession: send_fake_''mouse_enter''_xevent/MID screen_point = { row %d, col %d }." screen_row screen_col; };
# For the semantics of these three fields see
# p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
#
send_event_to = xt::SEND_EVENT_TO_WINDOW window_id;
propagate = FALSE;
event_mask = xt::EVENT_MASK 0u0;
#
# timestamp = xt::CURRENT_TIME; # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
timestamp = bogus_current_x_timestamp (); # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
# Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
root_window_id = root_window_id;
event_window_id = window_id; # Window handling the mouse-button release event.
child_window_id = NULL; # We'll assume specified window is a leaf.
root_x = screen_col; # Mouse position on root window at time of button release.
root_y = screen_row;
event_x = col; # Mouse position on recipient window at time of button release.
event_y = row;
buttons = xt::MOUSEBUTTON_STATE 0u0;
# trace {. "xsession: send_fake_''mouse_enter''_xevent/YYY calling s2w::encode_send_enternotify_xevent"; };
command = s2w::encode_send_enternotify_xevent
{
send_event_to, propagate, event_mask,
timestamp, root_window_id, event_window_id,
child_window_id, root_x, root_y,
event_x, event_y, buttons
};
windowsystem_to_xserver.xclient_to_sequencer.send_xrequest command; # Here we used to have xclient_to_sequencer.send_xrequest command;
# but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_''mouse_enter''_xevent/BOT called s2w::encode_send_enternotify_xevent -- DONE"; };
();
};
fun send_fake_''mouse_leave''_xevent
(
{ default_screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
...
}: Xsession
)
{ window => window as { window_id, windowsystem_to_xserver, ... }: Window, # Window handling the mouse-button click event.
point => point as { row, col } # Click location in local window coordinates.
}
=
{ # We need the point in both
# local and screen coords:
#
# trace {. sprintf "xsession: send_fake_''mouse_leave''_xevent/TOP window_point = { row %d, col %d }." row col; };
(window_point_to_screen_point window point)
->
{ row => screen_row,
col => screen_col
};
# trace {. sprintf "xsession: send_fake_''mouse_leave''_xevent/MID screen_point = { row %d, col %d }." screen_row screen_col; };
# For the semantics of these three fields see
# p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
#
send_event_to = xt::SEND_EVENT_TO_WINDOW window_id;
propagate = FALSE;
event_mask = xt::EVENT_MASK 0u0;
#
# timestamp = xt::CURRENT_TIME; # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
timestamp = bogus_current_x_timestamp (); # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
# Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
root_window_id = root_window_id;
event_window_id = window_id; # Window handling the mouse-button release event.
child_window_id = NULL; # We'll assume specified window is a leaf.
root_x = screen_col; # Mouse position on root window at time of button release.
root_y = screen_row;
event_x = col; # Mouse position on recipient window at time of button release.
event_y = row;
buttons = xt::MOUSEBUTTON_STATE 0u0;
# trace {. "xsession: send_fake_''mouse_leave''_xevent/YYY calling s2w::encode_send_leavenotify_xevent"; };
command = s2w::encode_send_leavenotify_xevent
{
send_event_to, propagate, event_mask,
timestamp, root_window_id, event_window_id, child_window_id, root_x, root_y, event_x, event_y, buttons
};
windowsystem_to_xserver.xclient_to_sequencer.send_xrequest command; # Here we used to have xclient_to_sequencer.send_xrequest command;
# but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_''mouse_leave''_xevent/BOT called s2w::encode_send_leavenotify_xevent -- DONE"; };
();
};
# Close the xsession.
# NOTE: there are probably other things
# that should go on here, such as notifying
# the xbuf_to_hostwindow_xevent_router. XXX BUGGO FIXME
#
fun close_xsession ({ xdisplay, ... }: Xsession )
=
{
# I am not at all convinced I want xsession-junk closing sockets
# -- I'd like to be able to close down and restart an xsession
# without the xserver having to know. So I'm going to plant this
# here to remind me to return to this at some point when other stuff
# is more under control:
log::fatal "close_xsession called -- xsession-junk.pkg";
# Threads will die left and right as we shut down,
# and scary warning messages will by default be
# logged to stdout, so suppress that to avoid
# spooking the user:
#
logger::disable thread_deathwatch::logging;
dy::close_xdisplay xdisplay;
};
# Return the maximum request size
# supported by the display:
#
# fun max_request_length ({ xdisplay=>{ max_request_length, ... }: dy::Xdisplay, ... }: Xsession )
# =
# max_request_length;
# Atom operations:
#
# stipulate
# #
# fun wrap_atom_op f ({ atom_imp, ... }: Xsession )
# =
# f atom_imp;
# herein
# #
# make_atom = wrap_atom_op ai::make_atom;
# find_atom = wrap_atom_op ai::find_atom;
# atom_to_string = wrap_atom_op ai::atom_to_string;
# end;
fun find_font ({ font_index, ... }: Xsession ) font_name
=
case (fti::find_font font_index font_name)
#
THE font => font;
#
NULL => { msg = sprintf "find_font unable to find font '%s' -- xsession-junk.pkg" font_name;
log::fatal msg; # Should not return.
raise exception DIE msg; # Should never get here.
};
esac;
#
fun default_screen_of (xsession as { default_screen_info, ... }: Xsession )
=
{ xsession, screen_info => default_screen_info }: Screen;
#
# fun get_''gui_startup_complete''_oneshot_of_xsession (xsession as { xsocket_to_hostwindow_router, ... }: Xsession )
# =
# s2t::get_''gui_startup_complete''_oneshot_of
# #
# xsocket_to_hostwindow_router;
#
# fun screens_of (xsession as { screens, ... }: Xsession )
# =
# map (\\ s = { xsession, screen_info => s }: Screen)
# screens;
#
fun ring_bell xsession percent
=
send_xrequest xsession
(value_to_wire::encode_bell { percent => int::min (100, int::max(-100, percent)) } );
# Screen functions:
#
# color_of_screen
# =
# cs::get_color;
#
fun xsession_of_screen ({ xsession, ... }: Screen)
=
xsession;
# Additions by ddeboer, May 2004.
# Dusty deBoer, KSU CIS 705, Spring 2004.
# Return the root window of a screen.
# This is needed in obtaining strings from xrdb,
# as they are stored in a property of the root window:
#
fun root_window_of_screen ({ screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info, ... }: Screen )
=
root_window_id;
# End additions by ddeboer
#
fun size_of_screen ({ screen_info => { xscreen => { size_in_pixels, ... }: dy::Xscreen, ... }: Screen_Info, ... }: Screen )
=
size_in_pixels;
#
fun mm_size_of_screen ({ screen_info => { xscreen => { size_in_mm, ... }: dy::Xscreen, ... }: Screen_Info, ... }: Screen )
=
size_in_mm;
#
fun depth_of_screen ({ screen_info => { xscreen => { root_visual, ... }: dy::Xscreen, ... }: Screen_Info, ... }: Screen )
=
dy::depth_of_visual root_visual;
#
fun display_class_of_screen ({ screen_info => { xscreen => { root_visual, ... }: dy::Xscreen, ... }: Screen_Info, ... }: Screen )
=
case (dy::display_class_of_visual root_visual)
#
THE c => c;
_ => xgripe::impossible "[xsession::display_class_of_screen: bogus root visual]";
esac;
# Return the pen-cache and draw imps
# for given depth on given screen:
#
fun per_depth_imps_for_depth ({ screen_info => { per_depth_imps, ... }: Screen_Info, ... }: Screen, given_depth)
=
search per_depth_imps
where
fun search ((sd as { depth, ... }: Per_Depth_Imps) ! rest)
=>
if (depth == given_depth) sd;
else search rest;
fi;
search [] => { msg = "invalid depth for screen";
log::fatal msg;
raise exception DIE msg;
};
end;
end;
#
# fun keysym_to_keycode ( { keymap_imp, ... }: Xsession, keysym)
# =
# ki::keysym_to_keycode (keymap_imp, keysym);
}; # package xsession_junk
end; # stipulate.