home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / microcode / os2pm.c < prev    next >
C/C++ Source or Header  |  2000-12-05  |  69KB  |  2,427 lines

  1. /* -*-C-*-
  2.  
  3. $Id: os2pm.c,v 1.33 2000/12/05 21:23:46 cph Exp $
  4.  
  5. Copyright (c) 1994-2000 Massachusetts Institute of Technology
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. #define INCL_WIN
  23. #define INCL_GPI
  24. #include "os2.h"
  25.  
  26. extern void add_reload_cleanup (void (*) (void));
  27. extern psid_t OS2_console_psid (void);
  28. extern void OS2_console_font_change_hook (font_metrics_t *);
  29.  
  30. typedef enum { pst_window, pst_memory } pst_t;
  31.  
  32. typedef struct _ps_t
  33. {
  34.   psid_t id;            /* psid for this ps */
  35.   qid_t qid;            /* qid to send commands to */
  36.   HPS handle;
  37.   COLOR foreground_color;
  38.   COLOR background_color;
  39.   pst_t visual_type;        /* window or bitmap */
  40.   void * visual;        /* the associated window or bitmap */
  41.   PLONG char_increments;    /* character increments for outline fonts */
  42. } ps_t;
  43. #define PS_ID(ps) ((ps) -> id)
  44. #define PS_QID(ps) ((ps) -> qid)
  45. #define PS_HANDLE(ps) ((ps) -> handle)
  46. #define PS_FOREGROUND_COLOR(ps) ((ps) -> foreground_color)
  47. #define PS_BACKGROUND_COLOR(ps) ((ps) -> background_color)
  48. #define PS_VISUAL_TYPE(ps) ((ps) -> visual_type)
  49. #define PS_VISUAL(ps) ((ps) -> visual)
  50. #define PS_CHAR_INCREMENTS(ps) ((ps) -> char_increments)
  51.  
  52. typedef struct _window_t
  53. {
  54.   HWND frame;            /* frame window handle */
  55.   HWND client;            /* client window handle */
  56.   ps_t * client_ps;        /* presentation space for client window */
  57.   unsigned short grid_x;    /* x dimension of resizing grid */
  58.   unsigned short grid_y;    /* y dimension of resizing grid */
  59.   short cursor_x;        /* x coordinate of the cursor */
  60.   short cursor_y;        /* y coordinate of the cursor */
  61.   unsigned short cursor_width;    /* width of the cursor */
  62.   unsigned short cursor_height;    /* height of the cursor */
  63.   unsigned short cursor_style;    /* style of the cursor */
  64.   qid_t qid;            /* qid to send commands to */
  65.   qid_t event_qid;        /* qid to send input events to */
  66.   wid_t id;            /* wid for this window */
  67.   unsigned int cursor_createdp : 1; /* nonzero if cursor created */
  68.   unsigned int cursor_enabledp : 1; /* nonzero if cursor enabled */
  69.   unsigned int minimizingp : 1; /* nonzero if window being minimized */
  70.   unsigned int minimizedp : 1;    /* nonzero if window is minimized */
  71.   unsigned int permanentp : 1;    /* nonzero means don't close on reload */
  72.   unsigned int mousetrackp : 1;    /* nonzero means generate WM_MOUSEMOVE msgs */
  73. } window_t;
  74. #define WINDOW_FRAME(window) ((window) -> frame)
  75. #define WINDOW_CLIENT(window) ((window) -> client)
  76. #define WINDOW_CLIENT_PS(window) ((window) -> client_ps)
  77. #define WINDOW_GRID_X(window) ((window) -> grid_x)
  78. #define WINDOW_GRID_Y(window) ((window) -> grid_y)
  79. #define WINDOW_CURSOR_X(window) ((window) -> cursor_x)
  80. #define WINDOW_CURSOR_Y(window) ((window) -> cursor_y)
  81. #define WINDOW_CURSOR_WIDTH(window) ((window) -> cursor_width)
  82. #define WINDOW_CURSOR_HEIGHT(window) ((window) -> cursor_height)
  83. #define WINDOW_CURSOR_STYLE(window) ((window) -> cursor_style)
  84. #define WINDOW_QID(window) ((window) -> qid)
  85. #define WINDOW_EVENT_QID(window) ((window) -> event_qid)
  86. #define WINDOW_ID(window) ((window) -> id)
  87. #define WINDOW_CURSOR_CREATEDP(window) ((window) -> cursor_createdp)
  88. #define WINDOW_CURSOR_ENABLEDP(window) ((window) -> cursor_enabledp)
  89. #define WINDOW_MINIMIZINGP(window) ((window) -> minimizingp)
  90. #define WINDOW_MINIMIZEDP(window) ((window) -> minimizedp)
  91. #define WINDOW_PERMANENTP(window) ((window) -> permanentp)
  92. #define WINDOW_MOUSETRACKP(window) ((window) -> mousetrackp)
  93.  
  94. typedef struct _bitmap_t
  95. {
  96.   bid_t id;            /* bid for this bitmap */
  97.   qid_t qid;            /* qid to send commands to */
  98.   HBITMAP handle;
  99. } bitmap_t;
  100. #define BITMAP_ID(bitmap) ((bitmap) -> id)
  101. #define BITMAP_QID(bitmap) ((bitmap) -> qid)
  102. #define BITMAP_HANDLE(bitmap) ((bitmap) -> handle)
  103.  
  104. typedef struct
  105. {
  106.   tqueue_type_t type;
  107.   HWND hwnd;
  108. } pm_tqueue_t;
  109. #define PM_TQUEUE_HWND(q) (((pm_tqueue_t *) (q)) -> hwnd)
  110.  
  111. typedef struct
  112. {
  113.   unsigned int length;
  114.   void ** pointers;
  115. } id_table_t;
  116. #define ID_TABLE_LENGTH(table) ((table) -> length)
  117. #define ID_TABLE_POINTERS(table) ((table) -> pointers)
  118.  
  119. /* This machine-generated file contains forward references and
  120.    structure definitions for most of the procedures.  */
  121. #include "os2pm-id.h"
  122.  
  123. static void window_pos (window_t *, short *, short *);
  124. static void handle_window_pos_request (msg_t *);
  125.  
  126. typedef struct
  127. {
  128.   DECLARE_MSG_HEADER_FIELDS;
  129.   window_t * window;
  130. } sm_pos_request_t;
  131. #define SM_POS_REQUEST_WINDOW(m) (((sm_pos_request_t *) (m)) -> window)
  132.  
  133. typedef struct
  134. {
  135.   DECLARE_MSG_HEADER_FIELDS;
  136.   short x;
  137.   short y;
  138. } sm_pos_reply_t;
  139. #define SM_POS_REPLY_X(m) (((sm_pos_reply_t *) (m)) -> x)
  140. #define SM_POS_REPLY_Y(m) (((sm_pos_reply_t *) (m)) -> y)
  141.  
  142. static void window_size (window_t *, unsigned short *, unsigned short *);
  143. static void handle_window_size_request (msg_t *);
  144.  
  145. typedef struct
  146. {
  147.   DECLARE_MSG_HEADER_FIELDS;
  148.   window_t * window;
  149. } sm_size_request_t;
  150. #define SM_SIZE_REQUEST_WINDOW(m) (((sm_size_request_t *) (m)) -> window)
  151.  
  152. typedef struct
  153. {
  154.   DECLARE_MSG_HEADER_FIELDS;
  155.   unsigned short width;
  156.   unsigned short height;
  157. } sm_size_reply_t;
  158. #define SM_SIZE_REPLY_WIDTH(m) (((sm_size_reply_t *) (m)) -> width)
  159. #define SM_SIZE_REPLY_HEIGHT(m) (((sm_size_reply_t *) (m)) -> height)
  160.  
  161. static void window_frame_size
  162.   (window_t *, unsigned short *, unsigned short *);
  163. static void handle_window_frame_size_request (msg_t *);
  164.  
  165. typedef struct
  166. {
  167.   DECLARE_MSG_HEADER_FIELDS;
  168.   window_t * window;
  169. } sm_frame_size_request_t;
  170. #define SM_FRAME_SIZE_REQUEST_WINDOW(m)                    \
  171.   (((sm_frame_size_request_t *) (m)) -> window)
  172.  
  173. typedef struct
  174. {
  175.   DECLARE_MSG_HEADER_FIELDS;
  176.   unsigned short width;
  177.   unsigned short height;
  178. } sm_frame_size_reply_t;
  179. #define SM_FRAME_SIZE_REPLY_WIDTH(m)                    \
  180.   (((sm_frame_size_reply_t *) (m)) -> width)
  181. #define SM_FRAME_SIZE_REPLY_HEIGHT(m)                    \
  182.   (((sm_frame_size_reply_t *) (m)) -> height)
  183.  
  184. static void handle_ps_set_bitmap_request (msg_t *);
  185. static bitmap_t * ps_set_bitmap (ps_t *, bitmap_t *);
  186.  
  187. typedef struct
  188. {
  189.   DECLARE_MSG_HEADER_FIELDS;
  190.   ps_t * ps;
  191.   bitmap_t * bitmap;
  192. } sm_ps_set_bitmap_request_t;
  193. #define SM_PS_SET_BITMAP_REQUEST_PS(m)                    \
  194.   (((sm_ps_set_bitmap_request_t *) (m)) -> ps)
  195. #define SM_PS_SET_BITMAP_REQUEST_BITMAP(m)                \
  196.   (((sm_ps_set_bitmap_request_t *) (m)) -> bitmap)
  197.  
  198. typedef struct
  199. {
  200.   DECLARE_MSG_HEADER_FIELDS;
  201.   bitmap_t * bitmap;
  202. } sm_ps_set_bitmap_reply_t;
  203. #define SM_PS_SET_BITMAP_REPLY_BITMAP(m)                \
  204.   (((sm_ps_set_bitmap_reply_t *) (m)) -> bitmap)
  205.  
  206. static void close_all_windows (void);
  207.  
  208. static void sync_transaction (qid_t, msg_t *);
  209. static void sync_reply (qid_t);
  210.  
  211. static void pm_thread_procedure (void *);
  212. static tqueue_t * make_pm_tqueue (HWND);
  213.  
  214. static void initialize_id_table (id_table_t *);
  215. static unsigned int allocate_id (id_table_t *, void *);
  216. static void deallocate_id (id_table_t *, unsigned int);
  217. static void * id_to_pointer (id_table_t *, unsigned int);
  218. static int id_validp (id_table_t *, unsigned int);
  219. static ps_t * psid_to_ps (psid_t);
  220. static window_t * wid_to_window (wid_t);
  221. static bitmap_t * bid_to_bitmap (bid_t);
  222.  
  223. static MRESULT EXPENTRY object_window_procedure (HWND, ULONG, MPARAM, MPARAM);
  224. static MRESULT EXPENTRY frame_window_procedure (HWND, ULONG, MPARAM, MPARAM);
  225. static MRESULT EXPENTRY window_procedure (HWND, ULONG, MPARAM, MPARAM);
  226.  
  227. static window_t * hwnd_to_window (HWND);
  228. static msg_t * make_pm_event (wid_t, ULONG, MPARAM, MPARAM);
  229. static msg_t * make_paint_event
  230.   (wid_t, unsigned short, unsigned short, unsigned short, unsigned short);
  231.  
  232. static void recreate_cursor (window_t *);
  233. static void activate_cursor (window_t *);
  234. static void deactivate_cursor (window_t *);
  235.  
  236. static window_t * make_window (qid_t, qid_t);
  237.  
  238. static void win_create_cursor (HWND, LONG, LONG, LONG, LONG, ULONG, PRECTL);
  239. static void win_destroy_cursor (HWND);
  240. static void win_show_cursor (HWND, BOOL);
  241. static void recreate_cursor (window_t *);
  242. static void activate_cursor (window_t *);
  243. static void deactivate_cursor (window_t *);
  244. static void maybe_activate_cursor (ps_t *);
  245. static void maybe_deactivate_cursor (ps_t *);
  246.  
  247. static HDC get_ps_device (HPS);
  248. static LONG get_device_capability (HDC, LONG);
  249. static ps_t * create_ps (pst_t, HDC, qid_t);
  250. static void destroy_ps (ps_t *);
  251.  
  252. static int ps_set_font (ps_t *, unsigned short, const char *);
  253. static int parse_font_spec (const char *, PSZ *, LONG *, USHORT *);
  254. static const char * unparse_font_spec (PSZ, LONG, USHORT);
  255. static int ps_set_font_1 (ps_t * ps, PSZ, LONG, USHORT, LONG);
  256. static PLONG ps_make_char_increments (LONG);
  257. static int create_font (HPS, LONG, PFONTMETRICS, USHORT);
  258. static void copy_fontmetrics_to_fattrs (FONTMETRICS *, FATTRS *);
  259. static void ps_set_font_size (ps_t *, LONG);
  260.  
  261. #define ID_FRAME 1
  262.  
  263. #define UWM_ENCAPSULATION WM_USER
  264.  
  265. #define QWP_WINDOW QWL_USER
  266.  
  267. /* These should have been defined by PM header file.  */
  268. #define MRVOID MRFROMP (0)
  269. #define MRTRUE MRFROMLONG (TRUE)
  270. #define MRFALSE MRFROMLONG (FALSE)
  271.  
  272. static id_table_t psid_table;
  273. static id_table_t wid_table;
  274. static id_table_t bid_table;
  275. static qid_t pm_init_qid;
  276. TID OS2_pm_tid;
  277. static HAB pm_hab;
  278. static HMQ pm_hmq;
  279. static HWND pm_object_window;
  280. static tqueue_t * pm_tqueue;
  281. static PFNWP original_frame_window_procedure;
  282. static window_t * capture_window;
  283.  
  284. static const char object_class [] = "mit-scheme.object";
  285. static const char window_class [] = "mit-scheme.window";
  286.  
  287. #define SEND_EVENT(window, message)                    \
  288. {                                    \
  289.   if ((WINDOW_EVENT_QID (window)) != QID_NONE)                \
  290.     OS2_send_message ((WINDOW_EVENT_QID (window)), (message));        \
  291. }
  292.  
  293. #define SEND_PM_EVENT(hwnd, msg, mp1, mp2)                \
  294. {                                    \
  295.   window_t * window = (hwnd_to_window (hwnd));                \
  296.   SEND_EVENT (window,                            \
  297.           (make_pm_event ((WINDOW_ID (window)), msg, mp1, mp2)));    \
  298. }
  299.  
  300. #define window_error(name) window_error_1 (#name, 1)
  301. #define window_warning(name) window_error_1 (#name, 0)
  302.  
  303. static void
  304. window_error_1 (const char * name, int fatalp)
  305. {
  306.   char buffer [1024];
  307.   ERRORID code = (WinGetLastError (pm_hab));
  308.   if (fatalp)
  309.     {
  310.       sprintf (buffer, "Fatal error 0x%08x occurred in the %s procedure.",
  311.            code, name);
  312.       OS2_logic_error (buffer);
  313.     }
  314.   else
  315.     {
  316.       sprintf (buffer, "Non-fatal error 0x%08x occurred in the %s procedure.  \
  317. This indicates a bug in the Scheme implementation.  \
  318. Please report this information to a Scheme wizard.",
  319.            code, name);
  320.       (void) WinMessageBox (HWND_DESKTOP,
  321.                 NULLHANDLE,
  322.                 buffer,
  323.                 "Scheme Error",
  324.                 0,
  325.                 (MB_OK | MB_WARNING));
  326.     }
  327. }
  328.  
  329. void
  330. OS2_initialize_pm_thread (void)
  331. {
  332.   /* This machine-generated file contains code to initialize the
  333.      message-type sizes for most of the procedure messages.  */
  334. #include "os2pm-mi.h"
  335.  
  336.   SET_MSG_TYPE_LENGTH (mt_window_pos_request, sm_pos_request_t);
  337.   SET_MSG_TYPE_LENGTH (mt_window_pos_reply, sm_pos_reply_t);
  338.   SET_MSG_TYPE_LENGTH (mt_window_size_request, sm_size_request_t);
  339.   SET_MSG_TYPE_LENGTH (mt_window_size_reply, sm_size_reply_t);
  340.   SET_MSG_TYPE_LENGTH (mt_window_frame_size_request, sm_frame_size_request_t);
  341.   SET_MSG_TYPE_LENGTH (mt_window_frame_size_reply, sm_frame_size_reply_t);
  342.  
  343.   SET_MSG_TYPE_LENGTH (mt_ps_set_bitmap_request, sm_ps_set_bitmap_request_t);
  344.   SET_MSG_TYPE_LENGTH (mt_ps_set_bitmap_reply, sm_ps_set_bitmap_reply_t);
  345.  
  346.   SET_MSG_TYPE_LENGTH (mt_pm_event, sm_pm_event_t);
  347.   SET_MSG_TYPE_LENGTH (mt_paint_event, sm_paint_event_t);
  348.  
  349.   initialize_id_table (& psid_table);
  350.   initialize_id_table (& wid_table);
  351.   initialize_id_table (& bid_table);
  352.   original_frame_window_procedure = 0;
  353.   capture_window = 0;
  354.   {
  355.     qid_t qid;
  356.     OS2_make_qid_pair ((&pm_init_qid), (&qid));
  357.     OS2_open_qid (qid, OS2_scheme_tqueue);
  358.     OS2_pm_tid = (OS2_beginthread (pm_thread_procedure, 0, 0x8000));
  359.     /* Wait for init message from PM thread.  This message tells us
  360.        that the other end of the connection is established and that it
  361.        is safe to send messages on the connection.  */
  362.     OS2_destroy_message (OS2_wait_for_message (qid, mt_init));
  363.     OS2_close_qid (qid);
  364.   }
  365.   add_reload_cleanup (close_all_windows);
  366. }
  367.  
  368. static void
  369. close_all_windows (void)
  370. {
  371.   window_t ** scan = ((window_t **) (ID_TABLE_POINTERS (& wid_table)));
  372.   window_t ** end = (scan + (ID_TABLE_LENGTH (& wid_table)));
  373.   while (scan < end)
  374.     {
  375.       window_t * window = (*scan++);
  376.       if ((window != 0) && (!WINDOW_PERMANENTP (window)))
  377.     window_close (window);
  378.     }
  379. }
  380.  
  381. /* Define this to cause a calling thread to wait for the PM thread to
  382.    finish requests that have trivial replies.  Otherwise, the calling
  383.    thread waits only when the request has a non-trivial reply.
  384.    Usually there is no good reason to wait for trivial replies, but
  385.    this could be useful during debugging.  */
  386. /* #define SYNC_SIMPLE_TRANSACTIONS */
  387. #ifdef SYNC_SIMPLE_TRANSACTIONS
  388.  
  389. #define simple_transaction sync_transaction
  390. #define simple_reply sync_reply
  391.  
  392. #else
  393.  
  394. #define simple_transaction OS2_send_message
  395. #define simple_reply(qid)
  396.  
  397. #endif
  398.  
  399. static void
  400. sync_transaction (qid_t qid, msg_t * message)
  401. {
  402.   OS2_destroy_message
  403.     (OS2_message_transaction (qid, message, mt_generic_reply));
  404. }
  405.  
  406. static void
  407. sync_reply (qid_t qid)
  408. {
  409.   OS2_send_message (qid, (OS2_create_message (mt_generic_reply)));
  410. }
  411.  
  412. /* These macros simplify the code needed to perform message
  413.    transactions, by hiding the many type-casts needed.  */
  414.  
  415. #define CREATE_MESSAGE(mt)                        \
  416.   ((void *) (OS2_create_message (mt)))
  417.  
  418. #define CREATE_MESSAGE_1(mt, extra)                    \
  419.   ((void *) (OS2_create_message_1 ((mt), (extra))))
  420.  
  421. #define DESTROY_MESSAGE(msg)                        \
  422.   OS2_destroy_message ((msg_t *) (msg))
  423.  
  424. #define SEND_MESSAGE(qid, msg)                        \
  425.   OS2_send_message ((qid), ((msg_t *) (msg)))
  426.  
  427. #define SIMPLE_TRANSACTION(qid, msg)                    \
  428.   simple_transaction ((qid), ((msg_t *) (msg)))
  429.  
  430. #define SYNC_TRANSACTION(qid, msg)                    \
  431.   sync_transaction ((qid), ((msg_t *) (msg)))
  432.  
  433. #define MESSAGE_TRANSACTION(qid, msg, mt)                \
  434.   ((void *) (OS2_message_transaction ((qid), ((msg_t *) (msg)), (mt))))
  435.  
  436. #define MEMCPY(to, from, length)                    \
  437.   FASTCOPY (((const char *) (from)), ((char *) (to)), (length))
  438.  
  439. #define STRCPY(to, from)                        \
  440.   strcpy (((char *) (to)), (from))
  441.  
  442. static void
  443. pm_thread_procedure (void * arg)
  444. {
  445.   EXCEPTIONREGISTRATIONRECORD registration;
  446.   QMSG qmsg;
  447.  
  448.   if ((OS2_thread_initialize_1 ((®istration), QID_NONE)) != 0)
  449.     OS2_logic_error ("Error signalled within PM thread.");
  450.   pm_hab = (WinInitialize (0));
  451.   if (pm_hab == NULLHANDLE)
  452.     window_error (WinInitialize);
  453.   pm_hmq = (WinCreateMsgQueue (pm_hab, 1000));
  454.   if (pm_hmq == NULLHANDLE)
  455.     window_error (WinCreateMsgQueue);
  456.   if (!WinRegisterClass (pm_hab,
  457.              ((PSZ) object_class),
  458.              object_window_procedure,
  459.              0,    /* class style */
  460.              0))
  461.     window_error (WinRegisterClass);
  462.   if (!WinRegisterClass (pm_hab,
  463.              ((PSZ) window_class),
  464.              window_procedure,
  465.              0,    /* class style */
  466.              (sizeof (void *))))
  467.     window_error (WinRegisterClass);
  468.   pm_object_window
  469.     = (WinCreateWindow (HWND_OBJECT,
  470.             ((PSZ) object_class),
  471.             "",    /* text */
  472.             0,    /* style */
  473.             0, 0, 0, 0, /* size and position */
  474.             NULLHANDLE, /* owner */
  475.             HWND_BOTTOM,
  476.             0,    /* ID */
  477.             0,    /* control data */
  478.             0    /* presentation parameters */
  479.             ));
  480.   if (pm_object_window == NULLHANDLE)
  481.     window_error (WinCreateWindow);
  482.   pm_tqueue = (make_pm_tqueue (pm_object_window));
  483.   OS2_send_message (pm_init_qid, (OS2_create_message (mt_init)));
  484.   while (WinGetMsg (pm_hab, (&qmsg), 0, 0, 0))
  485.     WinDispatchMsg (pm_hab, (&qmsg));
  486.   if (!WinDestroyWindow (pm_object_window))
  487.     window_error (WinDestroyWindow);
  488.   WinDestroyMsgQueue (pm_hmq);
  489.   WinTerminate (pm_hab);
  490.   /* There's no way to exit properly, because the normal exit depends
  491.      on the PM thread being active enough to print the closing
  492.      messages.  So just use exit.  */
  493.   exit (1);
  494. }
  495.  
  496. static tqueue_t *
  497. make_pm_tqueue (HWND hwnd)
  498. {
  499.   tqueue_t * tqueue = (OS_malloc (sizeof (pm_tqueue_t)));
  500.   (TQUEUE_TYPE (tqueue)) = tqt_pm;
  501.   (PM_TQUEUE_HWND (tqueue)) = hwnd;
  502.   return (tqueue);
  503. }
  504.  
  505. msg_t *
  506. OS2_read_pm_tqueue (tqueue_t * tqueue, int blockp)
  507. {
  508.   OS2_logic_error ("Read from PM tqueue.");
  509.   return (0);
  510. }
  511.  
  512. void
  513. OS2_write_pm_tqueue (tqueue_t * tqueue, msg_t * message)
  514. {
  515.   if (!WinPostMsg ((PM_TQUEUE_HWND (tqueue)),
  516.            UWM_ENCAPSULATION,
  517.            (MPFROMP (message)),
  518.            MPVOID))
  519.     window_warning (WinPostMsg);
  520. }
  521.  
  522. /* Object IDs
  523.  
  524.    These tables maintain data structures in the PM thread, and
  525.    associate those structures with ID numbers that are given out to
  526.    other threads (and to Scheme programs).  */
  527.  
  528. static void
  529. initialize_id_table (id_table_t * table)
  530. {
  531.   unsigned int length = 16;
  532.   void ** pointers = (OS_malloc ((sizeof (void *)) * length));
  533.   void ** scan = pointers;
  534.   void ** end = (scan + length);
  535.   while (scan < end)
  536.     (*scan++) = 0;
  537.   (ID_TABLE_LENGTH (table)) = length;
  538.   (ID_TABLE_POINTERS (table)) = pointers;
  539. }
  540.  
  541. static unsigned int
  542. allocate_id (id_table_t * table, void * pointer)
  543. {
  544.   unsigned int length = (ID_TABLE_LENGTH (table));
  545.   void ** pointers = (ID_TABLE_POINTERS (table));
  546.   void ** scan = (pointers + 1); /* don't allocate ID zero */
  547.   void ** end = (pointers + length);
  548.   while (scan < end)
  549.     if ((*scan++) == 0)
  550.       {
  551.     (*--scan) = pointer;
  552.     return (scan - pointers);
  553.       }
  554.   {
  555.     unsigned int id = length;
  556.     length *= 2;
  557.     pointers = (OS_realloc (pointers, ((sizeof (void *)) * length)));
  558.     scan = (pointers + id + 1);
  559.     end = (pointers + length);
  560.     while (scan < end)
  561.       (*scan++) = 0;
  562.     (ID_TABLE_LENGTH (table)) = length;
  563.     (ID_TABLE_POINTERS (table)) = pointers;
  564.     (pointers[id]) = pointer;
  565.     return (id);
  566.   }
  567. }
  568.  
  569. static void
  570. deallocate_id (id_table_t * table, unsigned int id)
  571. {
  572.   ((ID_TABLE_POINTERS (table)) [id]) = 0;
  573. }
  574.  
  575. static void *
  576. id_to_pointer (id_table_t * table, unsigned int id)
  577. {
  578.   void * pointer = ((ID_TABLE_POINTERS (table)) [id]);
  579.   if (pointer == 0)
  580.     OS2_logic_error ("Invalid PM ID.");
  581.   return (pointer);
  582. }
  583.  
  584. static int
  585. id_validp (id_table_t * table, unsigned int id)
  586. {
  587.   return ((id > 0)
  588.       && (id < (ID_TABLE_LENGTH (table)))
  589.       && (((ID_TABLE_POINTERS (table)) [id]) != 0));
  590. }
  591.  
  592. static ps_t *
  593. psid_to_ps (psid_t psid)
  594. {
  595.   return (id_to_pointer ((& psid_table), psid));
  596. }
  597.  
  598. static window_t *
  599. wid_to_window (wid_t wid)
  600. {
  601.   return (id_to_pointer ((& wid_table), wid));
  602. }
  603.  
  604. static bitmap_t *
  605. bid_to_bitmap (bid_t bid)
  606. {
  607.   return (id_to_pointer ((& bid_table), bid));
  608. }
  609.  
  610. /* Implementation of the object window.  The object window handles
  611.    encapsulated messages sent from the Scheme thread.  This defines
  612.    the protocol used to communicate with the Scheme thread.  */
  613.  
  614. static MRESULT EXPENTRY
  615. object_window_procedure (HWND window, ULONG msg, MPARAM mp1, MPARAM mp2)
  616. {
  617.   if (msg == UWM_ENCAPSULATION)
  618.     {
  619.       msg_t * message = (PVOIDFROMMP (mp1));
  620.       switch (MSG_TYPE (message))
  621.     {
  622.       /* This machine-generated file contains dispatch cases for
  623.          most of the procedure messages.  */
  624. #include "os2pm-dc.h"
  625.  
  626.     case mt_window_pos_request:
  627.       handle_window_pos_request (message);
  628.       break;
  629.     case mt_window_size_request:
  630.       handle_window_size_request (message);
  631.       break;
  632.     case mt_window_frame_size_request:
  633.       handle_window_frame_size_request (message);
  634.       break;
  635.     case mt_ps_set_bitmap_request:
  636.       handle_ps_set_bitmap_request (message);
  637.       break;
  638.  
  639.     default:
  640.       OS2_logic_error ("Unknown message type sent to PM thread.");
  641.       break;
  642.     }
  643.     }
  644.   return (MRVOID);
  645. }
  646.  
  647. /* Implementation of the Frame Window */
  648.  
  649. static MRESULT EXPENTRY
  650. frame_window_procedure (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  651. {
  652.   window_t * window = (hwnd_to_window (WinWindowFromID (hwnd, FID_CLIENT)));
  653.   switch (msg)
  654.     {
  655.     case WM_QUERYTRACKINFO:
  656.       /* Set the tracking grid for the resize operation.  */
  657.       {
  658.     MRESULT mr
  659.       = ((* original_frame_window_procedure) (hwnd, msg, mp1, mp2));
  660.     if (mr == MRTRUE)
  661.       {
  662.         PTRACKINFO pti = (PVOIDFROMMP (mp2));
  663.         if ((((pti -> fs) & TF_MOVE) != TF_MOVE)
  664.         && ((((pti -> fs) & TF_MOVE) != 0)
  665.             || (((pti -> fs) & TF_SETPOINTERPOS) != 0)))
  666.           {
  667.         (pti -> fs) |= TF_GRID;
  668.         (pti -> cxGrid) = (WINDOW_GRID_X (window));
  669.         (pti -> cyGrid) = (WINDOW_GRID_Y (window));
  670.         (pti -> cxKeyboard) = (WINDOW_GRID_X (window));
  671.         (pti -> cyKeyboard) = (WINDOW_GRID_Y (window));
  672.           }
  673.       }
  674.     return (mr);
  675.       }
  676.     case WM_MINMAXFRAME:
  677.       /* If minimizing, mark the window to indicate this.  The client
  678.      will shortly receive a WM_SIZE which indicates that the
  679.      minimization has completed.  */
  680.       {
  681.     PSWP pswp = (PVOIDFROMMP (mp1));
  682.     if ((!WINDOW_MINIMIZEDP (window))
  683.         && (((pswp -> fl) & SWP_MINIMIZE) != 0))
  684.       {
  685.         (WINDOW_MINIMIZINGP (window)) = 1;
  686.         (WINDOW_MINIMIZEDP (window)) = 1;
  687.       }
  688.     else if ((WINDOW_MINIMIZEDP (window))
  689.          && (((pswp -> fl) & (SWP_RESTORE | SWP_MAXIMIZE)) != 0))
  690.       (WINDOW_MINIMIZEDP (window)) = 0;
  691.       }
  692.       break;
  693.     }
  694.   return ((* original_frame_window_procedure) (hwnd, msg, mp1, mp2));
  695. }
  696.  
  697. /* Implementation of the Client Window */
  698.  
  699. static MRESULT EXPENTRY
  700. window_procedure (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  701. {
  702.   switch (msg)
  703.     {
  704.     case WM_CREATE:
  705.       {
  706.     window_t * window = (PVOIDFROMMP (mp1));
  707.     if (!WinSetWindowPtr (hwnd, QWP_WINDOW, window))
  708.       window_error (WinSetWindowPtr);
  709.     (WINDOW_CLIENT (window)) = hwnd;
  710.     (WINDOW_CLIENT_PS (window))
  711.       = (create_ps (pst_window,
  712.             (WinOpenWindowDC (hwnd)),
  713.             (WINDOW_QID (window))));
  714.     (PS_VISUAL (WINDOW_CLIENT_PS (window))) = window;
  715.     return (MRFALSE);
  716.       }
  717.     case WM_PAINT:
  718.       {
  719.     window_t * window = (hwnd_to_window (hwnd));
  720.     if (((WinQueryWindowULong ((WINDOW_FRAME (window)), QWL_STYLE))
  721.          & WS_MINIMIZED)
  722.         != 0)
  723.       break;
  724.     {
  725.       HPS hps = (PS_HANDLE (WINDOW_CLIENT_PS (window)));
  726.       RECTL rectl;
  727.       if ((WinBeginPaint ((WINDOW_CLIENT (window)), hps, (& rectl)))
  728.           == NULLHANDLE)
  729.         window_error (WinBeginPaint);
  730.       if (!WinEndPaint (hps))
  731.         window_error (WinEndPaint);
  732.       SEND_EVENT (window,
  733.               (make_paint_event ((WINDOW_ID (window)),
  734.                      (rectl . xLeft),
  735.                      (rectl . xRight),
  736.                      (rectl . yBottom),
  737.                      (rectl . yTop))));
  738.     }
  739.     return (MRVOID);
  740.       }
  741.     case WM_SETFOCUS:
  742.       {
  743.     window_t * window = (hwnd_to_window (hwnd));
  744.     if (SHORT1FROMMP (mp2))
  745.       recreate_cursor (window);
  746.     else
  747.       {
  748.         win_destroy_cursor (WINDOW_CLIENT (window));
  749.         (WINDOW_CURSOR_CREATEDP (window)) = 0;
  750.       }
  751.       }
  752.       SEND_PM_EVENT (hwnd, msg, mp1, mp2);
  753.       return (MRVOID);
  754.     case WM_TRANSLATEACCEL:
  755.       {
  756.     PQMSG qmsg = (PVOIDFROMMP (mp1));
  757.     USHORT flags = (SHORT1FROMMP (qmsg -> mp1));
  758.     USHORT char_code = (SHORT1FROMMP (qmsg -> mp2));
  759.     USHORT virtual_key = (SHORT2FROMMP (qmsg -> mp2));
  760.     /* Disable specific default accelerator keys.  */
  761.     if ((flags & KC_VIRTUALKEY) != 0)
  762.       switch (virtual_key)
  763.         {
  764.         case VK_ALT:
  765.         case VK_ALTGRAF:
  766.           /* Disable "Alt" keys, which normally pop up the system
  767.          menu.  These keys are used often in Edwin and the
  768.          default behavior is unacceptable.  */
  769.           return (MRFALSE);
  770.         case VK_SPACE:
  771.         case VK_ESC:
  772.         case VK_TAB:
  773.           /* Disable "Alt-SPC", "Alt-ESC", and "Alt-TAB", which
  774.          have standard key bindings in Edwin.  */
  775.           if ((flags & KC_ALT) != 0)
  776.         return (MRFALSE);
  777.         }
  778.     else if ((flags & KC_CHAR) != 0)
  779.       switch (char_code)
  780.         {
  781.         case ' ':
  782.         case '\033':
  783.         case '\t':
  784.           /* Disable "Alt-SPC", "Alt-ESC", and "Alt-TAB", if for
  785.          some reason they are reported as ASCII characters
  786.          rather than as virtual keys.  */
  787.           if ((flags & KC_ALT) != 0)
  788.         return (MRFALSE);
  789.         }
  790.     break;
  791.       }
  792.     case WM_DESTROY:
  793.       {
  794.     window_t * window = (hwnd_to_window (hwnd));
  795.     destroy_ps (WINDOW_CLIENT_PS (window));
  796.     (WINDOW_CLIENT_PS (window)) = 0;
  797.     return (MRVOID);
  798.       }
  799.     case WM_SIZE:
  800.       {
  801.     window_t * window = (hwnd_to_window (hwnd));
  802.     /* If this message is part of a minimization, ignore it.  */
  803.     if (WINDOW_MINIMIZINGP (window))
  804.       {
  805.         (WINDOW_MINIMIZINGP (window)) = 0;
  806.         (WINDOW_MINIMIZEDP (window)) = 1;
  807.         break;
  808.       }
  809.     if (WINDOW_CURSOR_CREATEDP (window))
  810.       {
  811.         win_destroy_cursor (WINDOW_CLIENT (window));
  812.         (WINDOW_CURSOR_CREATEDP (window)) = 0;
  813.         (WINDOW_CURSOR_X (window)) = 0;
  814.         (WINDOW_CURSOR_Y (window)) = 0;
  815.         recreate_cursor (window);
  816.       }
  817.       }
  818.       SEND_PM_EVENT (hwnd, msg, mp1, mp2);
  819.       return (MRVOID);
  820.     case WM_CLOSE:
  821.     case WM_COMMAND:
  822.     case WM_CONTROL:
  823.     case WM_HELP:
  824.     case WM_SHOW:
  825.       SEND_PM_EVENT (hwnd, msg, mp1, mp2);
  826.       return (MRVOID);
  827.     case WM_CHAR:
  828.     case WM_BUTTON1DOWN:
  829.     case WM_BUTTON1UP:
  830.     case WM_BUTTON1CLICK:
  831.     case WM_BUTTON1DBLCLK:
  832.     case WM_BUTTON2DOWN:
  833.     case WM_BUTTON2UP:
  834.     case WM_BUTTON2CLICK:
  835.     case WM_BUTTON2DBLCLK:
  836.     case WM_BUTTON3DOWN:
  837.     case WM_BUTTON3UP:
  838.     case WM_BUTTON3CLICK:
  839.     case WM_BUTTON3DBLCLK:
  840.       SEND_PM_EVENT (hwnd, msg, mp1, mp2);
  841.       return (MRTRUE);
  842.     case WM_MOUSEMOVE:
  843.       if (WINDOW_MOUSETRACKP (hwnd_to_window (hwnd)))
  844.     {
  845.       SEND_PM_EVENT (hwnd, msg, mp1, mp2);
  846.       return (MRTRUE);
  847.     }
  848.       break;
  849.     default:
  850.       break;
  851.     }
  852.   return (WinDefWindowProc (hwnd, msg, mp1, mp2));
  853. }
  854.  
  855. static window_t *
  856. hwnd_to_window (HWND hwnd)
  857. {
  858.   window_t * window = (WinQueryWindowPtr (hwnd, QWP_WINDOW));
  859.   if (window == 0)
  860.     window_error (WinQueryWindowPtr);
  861.   return (window);
  862. }
  863.  
  864. static msg_t *
  865. make_pm_event (wid_t wid, ULONG msg, MPARAM mp1, MPARAM mp2)
  866. {
  867.   msg_t * message = (OS2_create_message (mt_pm_event));
  868.   (SM_PM_EVENT_WID (message)) = wid;
  869.   (SM_PM_EVENT_MSG (message)) = msg;
  870.   (SM_PM_EVENT_MP1 (message)) = mp1;
  871.   (SM_PM_EVENT_MP2 (message)) = mp2;
  872.   return (message);
  873. }
  874.  
  875. static msg_t *
  876. make_paint_event (wid_t wid,
  877.           unsigned short xl, unsigned short xh,
  878.           unsigned short yl, unsigned short yh)
  879. {
  880.   msg_t * message = (OS2_create_message (mt_paint_event));
  881.   (SM_PAINT_EVENT_WID (message)) = wid;
  882.   (SM_PAINT_EVENT_XL (message)) = xl;
  883.   (SM_PAINT_EVENT_XH (message)) = xh;
  884.   (SM_PAINT_EVENT_YL (message)) = yl;
  885.   (SM_PAINT_EVENT_YH (message)) = yh;
  886.   return (message);
  887. }
  888.  
  889. int
  890. OS2_translate_wm_char (MPARAM mp1, MPARAM mp2,
  891.                unsigned short * code,
  892.                unsigned short * flags,
  893.                unsigned char * repeat)
  894. {
  895.   (*flags) = (SHORT1FROMMP (mp1));
  896.   (*repeat) = (CHAR3FROMMP (mp1));
  897.   /* Ignore compound keys for now.  */
  898.   if (((*flags) & (KC_DEADKEY | KC_COMPOSITE | KC_INVALIDCOMP | KC_KEYUP))
  899.       != 0)
  900.     return (0);
  901.   if (((*flags) & KC_VIRTUALKEY) != 0)
  902.     {
  903.       (*code) = (SHORT2FROMMP (mp2));
  904.       return (1);
  905.     }
  906.   if (((*flags) & (KC_CHAR | KC_CTRL | KC_ALT)) != 0)
  907.     {
  908.       (*code) = (SHORT1FROMMP (mp2));
  909.       return (1);
  910.     }
  911.   return (0);
  912. }
  913.  
  914. /* Direct Operations
  915.  
  916.    These are exported operations that can be implemented directly in
  917.    the calling thread.  Other operations that require communication
  918.    with the PM thread appear on following pages.  */
  919.  
  920. int
  921. OS2_psid_validp (psid_t psid)
  922. {
  923.   return (id_validp ((& psid_table), psid));
  924. }
  925.  
  926. int
  927. OS2_wid_validp (wid_t wid)
  928. {
  929.   return (id_validp ((& wid_table), wid));
  930. }
  931.  
  932. int
  933. OS2_bid_validp (bid_t bid)
  934. {
  935.   return (id_validp ((& bid_table), bid));
  936. }
  937.  
  938. psid_t
  939. OS2_window_client_ps (wid_t wid)
  940. {
  941.   return (PS_ID (WINDOW_CLIENT_PS (wid_to_window (wid))));
  942. }
  943.  
  944. qid_t
  945. OS2_create_pm_qid (tqueue_t * tqueue)
  946. {
  947.   qid_t pm_side;
  948.   qid_t client_side;
  949.   OS2_make_qid_pair ((&pm_side), (&client_side));
  950.   OS2_open_qid (pm_side, pm_tqueue);
  951.   OS2_open_qid (client_side, tqueue);
  952.   return (client_side);
  953. }
  954.  
  955. void
  956. OS2_window_permanent (wid_t wid)
  957. {
  958.   (WINDOW_PERMANENTP (wid_to_window (wid))) = 1;
  959. }
  960.  
  961. void
  962. OS2_window_mousetrack (wid_t wid, int trackp)
  963. {
  964.   (WINDOW_MOUSETRACKP (wid_to_window (wid))) = trackp;
  965. }
  966.  
  967. HWND
  968. OS2_window_frame_handle (wid_t wid)
  969. {
  970.   return (WINDOW_FRAME (wid_to_window (wid)));
  971. }
  972.  
  973. HWND
  974. OS2_window_client_handle (wid_t wid)
  975. {
  976.   return (WINDOW_CLIENT (wid_to_window (wid)));
  977. }
  978.  
  979. int
  980. OS2_memory_ps_p (psid_t psid)
  981. {
  982.   return ((PS_VISUAL_TYPE (psid_to_ps (psid))) == pst_memory);
  983. }
  984.  
  985. bid_t
  986. OS2_ps_get_bitmap (psid_t psid)
  987. {
  988.   bitmap_t * bitmap = (PS_VISUAL (psid_to_ps (psid)));
  989.   return ((bitmap == 0) ? BID_NONE : (BITMAP_ID (bitmap)));
  990. }
  991.  
  992. /* Relayed Operations
  993.  
  994.    This page implements exported operations that require communication
  995.    with the PM thread.  The PM-thread-side of these operations appear
  996.    on the following pages; this page implements only the mechanism to
  997.    communicate the operation to the PM thread.  The bulk of these
  998.    communication procedures is machine-generated.  */
  999.  
  1000. /* This macro supplies a NO-OP procedure needed by the
  1001.    machine-generated code for OS2_pm_synchronize.  */
  1002. #define pm_synchronize(qid)
  1003.  
  1004. /* This machine-generated file contains most of the external procedure
  1005.    definitions, and their associated handler procedures.  */
  1006. #include "os2pm-rp.h"
  1007.  
  1008. void
  1009. OS2_window_pos (wid_t wid, short * x, short * y)
  1010. {
  1011.   window_t * window = (wid_to_window (wid));
  1012.   msg_t * message = (OS2_create_message (mt_window_pos_request));
  1013.   (SM_POS_REQUEST_WINDOW (message)) = window;
  1014.   message
  1015.     = (OS2_message_transaction ((WINDOW_QID (window)),
  1016.                 message,
  1017.                 mt_window_pos_reply));
  1018.   (* x) = (SM_POS_REPLY_X (message));
  1019.   (* y) = (SM_POS_REPLY_Y (message));
  1020.   OS2_destroy_message (message);
  1021. }
  1022.  
  1023. static void
  1024. handle_window_pos_request (msg_t * request)
  1025. {
  1026.   qid_t sender = (MSG_SENDER (request));
  1027.   msg_t * reply = (OS2_create_message (mt_window_pos_reply));
  1028.   window_pos ((SM_POS_REQUEST_WINDOW (request)),
  1029.           (& (SM_POS_REPLY_X (reply))),
  1030.           (& (SM_POS_REPLY_Y (reply))));
  1031.   OS2_destroy_message (request);
  1032.   OS2_send_message (sender, reply);
  1033. }
  1034.  
  1035. void
  1036. OS2_window_size (wid_t wid, unsigned short * width, unsigned short * height)
  1037. {
  1038.   window_t * window = (wid_to_window (wid));
  1039.   msg_t * message = (OS2_create_message (mt_window_size_request));
  1040.   (SM_SIZE_REQUEST_WINDOW (message)) = window;
  1041.   message
  1042.     = (OS2_message_transaction ((WINDOW_QID (window)),
  1043.                 message,
  1044.                 mt_window_size_reply));
  1045.   (* width) = (SM_SIZE_REPLY_WIDTH (message));
  1046.   (* height) = (SM_SIZE_REPLY_HEIGHT (message));
  1047.   OS2_destroy_message (message);
  1048. }
  1049.  
  1050. static void
  1051. handle_window_size_request (msg_t * request)
  1052. {
  1053.   qid_t sender = (MSG_SENDER (request));
  1054.   msg_t * reply = (OS2_create_message (mt_window_size_reply));
  1055.   window_size ((SM_SIZE_REQUEST_WINDOW (request)),
  1056.            (& (SM_SIZE_REPLY_WIDTH (reply))),
  1057.            (& (SM_SIZE_REPLY_HEIGHT (reply))));
  1058.   OS2_destroy_message (request);
  1059.   OS2_send_message (sender, reply);
  1060. }
  1061.  
  1062. void
  1063. OS2_window_frame_size (wid_t wid,
  1064.                unsigned short * width, unsigned short * height)
  1065. {
  1066.   window_t * window = (wid_to_window (wid));
  1067.   msg_t * message = (OS2_create_message (mt_window_frame_size_request));
  1068.   (SM_FRAME_SIZE_REQUEST_WINDOW (message)) = window;
  1069.   message
  1070.     = (OS2_message_transaction ((WINDOW_QID (window)),
  1071.                 message,
  1072.                 mt_window_frame_size_reply));
  1073.   (* width) = (SM_FRAME_SIZE_REPLY_WIDTH (message));
  1074.   (* height) = (SM_FRAME_SIZE_REPLY_HEIGHT (message));
  1075.   OS2_destroy_message (message);
  1076. }
  1077.  
  1078. static void
  1079. handle_window_frame_size_request (msg_t * request)
  1080. {
  1081.   qid_t sender = (MSG_SENDER (request));
  1082.   msg_t * reply = (OS2_create_message (mt_window_frame_size_reply));
  1083.   window_frame_size ((SM_FRAME_SIZE_REQUEST_WINDOW (request)),
  1084.              (& (SM_FRAME_SIZE_REPLY_WIDTH (reply))),
  1085.              (& (SM_FRAME_SIZE_REPLY_HEIGHT (reply))));
  1086.   OS2_destroy_message (request);
  1087.   OS2_send_message (sender, reply);
  1088. }
  1089.  
  1090. bid_t
  1091. OS2_ps_set_bitmap (psid_t psid, bid_t bid)
  1092. {
  1093.   ps_t * ps = (psid_to_ps (psid));
  1094.   bitmap_t * bitmap = ((bid == BID_NONE) ? 0 : (bid_to_bitmap (bid)));
  1095.   msg_t * message = (OS2_create_message (mt_ps_set_bitmap_request));
  1096.   (SM_PS_SET_BITMAP_REQUEST_PS (message)) = ps;
  1097.   (SM_PS_SET_BITMAP_REQUEST_BITMAP (message)) = bitmap;
  1098.   message
  1099.     = (OS2_message_transaction ((PS_QID (ps)),
  1100.                 message,
  1101.                 mt_ps_set_bitmap_reply));
  1102.   bitmap = (SM_PS_SET_BITMAP_REPLY_BITMAP (message));
  1103.   OS2_destroy_message (message);
  1104.   return ((bitmap == 0) ? BID_NONE : (BITMAP_ID (bitmap)));
  1105. }
  1106.  
  1107. static void
  1108. handle_ps_set_bitmap_request (msg_t * request)
  1109. {
  1110.   qid_t sender = (MSG_SENDER (request));
  1111.   msg_t * reply = (OS2_create_message (mt_ps_set_bitmap_reply));
  1112.   (SM_PS_SET_BITMAP_REPLY_BITMAP (reply))
  1113.     = (ps_set_bitmap ((SM_PS_SET_BITMAP_REQUEST_PS (request)),
  1114.               (SM_PS_SET_BITMAP_REQUEST_BITMAP (request))));
  1115.   OS2_destroy_message (request);
  1116.   OS2_send_message (sender, reply);
  1117. }
  1118.  
  1119. font_metrics_t *
  1120. OS2_ps_set_font (psid_t psid, unsigned short id, const char * name)
  1121. {
  1122.   font_metrics_t * metrics = (OS2_ps_set_font_internal (psid, id, name));
  1123.   if ((metrics != 0) && (psid == (OS2_console_psid ())))
  1124.     OS2_console_font_change_hook (metrics);
  1125.   return (metrics);
  1126. }
  1127.  
  1128. /* PM-thread Operation Implementations
  1129.  
  1130.    All of the procedures from this point on are implementations of
  1131.    exported operations.  These implementations are the code that is
  1132.    run in the PM thread to implement the operations that are invoked
  1133.    in other threads.  */
  1134.  
  1135. /* Windows */
  1136.  
  1137. static wid_t
  1138. window_open (qid_t qid, qid_t event_qid, ULONG flags, HMODULE module, ULONG id,
  1139.          ULONG style, const char * title)
  1140. {
  1141.   window_t * window = (make_window (qid, event_qid));
  1142.   FRAMECDATA frame_data;
  1143.   HWND frame_window;
  1144.  
  1145.   (frame_data . cb) = (sizeof (frame_data));
  1146.   (frame_data . flCreateFlags) = flags;
  1147.   (frame_data . hmodResources) = module;
  1148.   (frame_data . idResources) = id;
  1149.   frame_window
  1150.     = (WinCreateWindow (HWND_DESKTOP,
  1151.             WC_FRAME,
  1152.             ((PSZ) title), /* title string */
  1153.             0,    /* window style */
  1154.             0, 0, 0, 0, /* size and position */
  1155.             NULLHANDLE, /* owner window */
  1156.             HWND_TOP,
  1157.             ID_FRAME,    /* window ID */
  1158.             (& frame_data),
  1159.             0));
  1160.   if (frame_window == NULLHANDLE)
  1161.     window_error (WinCreateWindow);
  1162.   (WINDOW_FRAME (window)) = frame_window;
  1163.   {
  1164.     PFNWP procedure
  1165.       = (WinSubclassWindow (frame_window, frame_window_procedure));
  1166.     if (procedure == 0)
  1167.       window_error (WinSubclassWindow);
  1168.     if (original_frame_window_procedure == 0)
  1169.       original_frame_window_procedure = procedure;
  1170.     else if (original_frame_window_procedure != procedure)
  1171.       OS2_logic_error ("WinSubclassWindow returned two different answers.");
  1172.   }
  1173.   if ((WinCreateWindow (frame_window,
  1174.             ((PSZ) window_class),
  1175.             0,    /* window text (class-specific) */
  1176.             style,    /* window style */
  1177.             0, 0, 0, 0, /* size and position */
  1178.             frame_window, /* owner window */
  1179.             HWND_BOTTOM,
  1180.             FID_CLIENT, /* window ID */
  1181.             window,
  1182.             0))
  1183.       == NULLHANDLE)
  1184.     window_error (WinCreateWindow);
  1185.   return (WINDOW_ID (window));
  1186. }
  1187.  
  1188. static window_t *
  1189. make_window (qid_t qid, qid_t event_qid)
  1190. {
  1191.   window_t * window = (OS_malloc (sizeof (window_t)));
  1192.   (WINDOW_FRAME (window)) = NULLHANDLE;
  1193.   (WINDOW_CLIENT (window)) = NULLHANDLE;
  1194.   (WINDOW_CLIENT_PS (window)) = 0;
  1195.   (WINDOW_GRID_X (window)) = 1;
  1196.   (WINDOW_GRID_Y (window)) = 1;
  1197.   (WINDOW_CURSOR_X (window)) = 0;
  1198.   (WINDOW_CURSOR_Y (window)) = 0;
  1199.   (WINDOW_CURSOR_WIDTH (window)) = 0;
  1200.   (WINDOW_CURSOR_HEIGHT (window)) = 0;
  1201.   (WINDOW_CURSOR_STYLE (window)) = (CURSOR_SOLID | CURSOR_FLASH);
  1202.   (WINDOW_QID (window)) = qid;
  1203.   (WINDOW_EVENT_QID (window)) = event_qid;
  1204.   (WINDOW_ID (window)) = (allocate_id ((& wid_table), window));
  1205.   (WINDOW_CURSOR_CREATEDP (window)) = 0;
  1206.   (WINDOW_CURSOR_ENABLEDP (window)) = 0;
  1207.   (WINDOW_MINIMIZINGP (window)) = 0;
  1208.   (WINDOW_MINIMIZEDP (window)) = 0;
  1209.   (WINDOW_PERMANENTP (window)) = 0;
  1210.   (WINDOW_MOUSETRACKP (window)) = 0;
  1211.   return (window);
  1212. }
  1213.  
  1214. static void
  1215. window_close (window_t * window)
  1216. {
  1217.   if (!WinDestroyWindow (WINDOW_FRAME (window)))
  1218.     window_warning (WinDestroyWindow);
  1219.   deallocate_id ((& wid_table), (WINDOW_ID (window)));
  1220.   OS_free (window);
  1221. }
  1222.  
  1223. static void
  1224. window_show (window_t * window, int showp)
  1225. {
  1226.   if (!WinShowWindow ((WINDOW_FRAME (window)), showp))
  1227.     window_warning (WinShowWindow);
  1228. }
  1229.  
  1230. static void
  1231. window_scroll (window_t * window, short xl, short xh, short yl, short yh,
  1232.            short x_delta, short y_delta)
  1233. {
  1234.   RECTL rectl;
  1235.   (rectl . xLeft) = xl;
  1236.   (rectl . xRight) = xh;
  1237.   (rectl . yBottom) = yl;
  1238.   (rectl . yTop) = yh;
  1239.   deactivate_cursor (window);
  1240.   if ((WinScrollWindow ((WINDOW_CLIENT (window)), x_delta, y_delta, (& rectl),
  1241.             0, NULLHANDLE, 0, 0))
  1242.       == RGN_ERROR)
  1243.     window_warning (WinScrollWindow);
  1244.   activate_cursor (window);
  1245. }
  1246.  
  1247. static void
  1248. window_invalidate (window_t * window, short xl, short xh, short yl, short yh)
  1249. {
  1250.   RECTL rectl;
  1251.   (rectl . xLeft) = xl;
  1252.   (rectl . xRight) = xh;
  1253.   (rectl . yBottom) = yl;
  1254.   (rectl . yTop) = yh;
  1255.   if (!WinInvalidateRect ((WINDOW_CLIENT (window)), (& rectl), FALSE))
  1256.     window_warning (WinInvalidateRect);
  1257. }
  1258.  
  1259. static void
  1260. window_set_grid (window_t * window, unsigned short x, unsigned short y)
  1261. {
  1262.   (WINDOW_GRID_X (window)) = x;
  1263.   (WINDOW_GRID_Y (window)) = y;
  1264. }
  1265.  
  1266. static void
  1267. window_activate (window_t * window)
  1268. {
  1269.   if (!WinSetActiveWindow (HWND_DESKTOP, (WINDOW_FRAME (window))))
  1270.     window_warning (WinSetActiveWindow);
  1271. }
  1272.  
  1273. static void
  1274. window_pos (window_t * window, short * x, short * y)
  1275. {
  1276.   SWP swp;
  1277.   if (!WinQueryWindowPos ((WINDOW_FRAME (window)), (& swp)))
  1278.     window_error (WinQueryWindowPos);
  1279.   (* x) = (swp . x);
  1280.   (* y) = (swp . y);
  1281. }
  1282.  
  1283. static void
  1284. window_set_pos (window_t * window, short x, short y)
  1285. {
  1286.   if (!WinSetWindowPos ((WINDOW_FRAME (window)), NULLHANDLE, x, y,
  1287.             0, 0, SWP_MOVE))
  1288.     window_warning (WinSetWindowPos);
  1289. }
  1290.  
  1291. static void
  1292. window_size (window_t * window,
  1293.          unsigned short * width, unsigned short * height)
  1294. {
  1295.   SWP swp;
  1296.   if (!WinQueryWindowPos ((WINDOW_CLIENT (window)), (& swp)))
  1297.     window_error (WinQueryWindowPos);
  1298.   (* width) = (swp . cx);
  1299.   (* height) = (swp . cy);
  1300. }
  1301.  
  1302. static void
  1303. window_frame_size (window_t * window,
  1304.            unsigned short * width, unsigned short * height)
  1305. {
  1306.   SWP swp;
  1307.   if (!WinQueryWindowPos ((WINDOW_FRAME (window)), (& swp)))
  1308.     window_error (WinQueryWindowPos);
  1309.   (* width) = (swp . cx);
  1310.   (* height) = (swp . cy);
  1311. }
  1312.  
  1313. static void
  1314. window_set_size (window_t * window,
  1315.          unsigned short width, unsigned short height)
  1316. {
  1317.   RECTL rcl;
  1318.   (rcl . xLeft) = 0;
  1319.   (rcl . xRight) = width;
  1320.   (rcl . yBottom) = 0;
  1321.   (rcl . yTop) = height;
  1322.   if (!WinMapWindowPoints ((WINDOW_CLIENT (window)), HWND_DESKTOP,
  1323.                ((PPOINTL) (& rcl)), 2))
  1324.     window_error (WinMapWindowPoints);
  1325.   if (!WinCalcFrameRect ((WINDOW_FRAME (window)), (& rcl), FALSE))
  1326.     window_error (WinCalcFrameRect);
  1327.   if (!WinSetWindowPos ((WINDOW_FRAME (window)),
  1328.             NULLHANDLE, 0, 0,
  1329.             ((rcl . xRight) - (rcl . xLeft)),
  1330.             ((rcl . yTop) - (rcl . yBottom)),
  1331.             SWP_SIZE))
  1332.     window_warning (WinSetWindowPos);
  1333. }
  1334.  
  1335. static int
  1336. window_focusp (window_t * window)
  1337. {
  1338.   return ((WINDOW_CLIENT (window)) == (WinQueryFocus (HWND_DESKTOP)));
  1339. }
  1340.  
  1341. static void
  1342. window_set_state (window_t * window, window_state_t state)
  1343. {
  1344.   ULONG op = 0;
  1345.   HWND behind = NULLHANDLE;
  1346.   switch (state)
  1347.     {
  1348.     case state_top:
  1349.       op = SWP_ZORDER;
  1350.       behind = HWND_TOP;
  1351.       break;
  1352.     case state_bottom:
  1353.       op = SWP_ZORDER;
  1354.       behind = HWND_BOTTOM;
  1355.       break;
  1356.     case state_show:
  1357.       op = SWP_SHOW;
  1358.       break;
  1359.     case state_hide:
  1360.       op = SWP_HIDE;
  1361.       break;
  1362.     case state_activate:
  1363.       op = SWP_ACTIVATE;
  1364.       break;
  1365.     case state_deactivate:
  1366.       op = SWP_DEACTIVATE;
  1367.       break;
  1368.     case state_minimize:
  1369.       op = SWP_MINIMIZE;
  1370.       break;
  1371.     case state_maximize:
  1372.       op = SWP_MAXIMIZE;
  1373.       break;
  1374.     case state_restore:
  1375.       op = SWP_RESTORE;
  1376.       break;
  1377.     }
  1378.   if (!WinSetWindowPos ((WINDOW_FRAME (window)), behind, 0, 0, 0, 0, op))
  1379.     window_warning (WinSetWindowPos);
  1380. }
  1381.  
  1382. static void
  1383. window_set_title (window_t * window, const char * title)
  1384. {
  1385.   if (!WinSetWindowText ((WINDOW_FRAME (window)), ((PSZ) title)))
  1386.     window_warning (WinSetWindowText);
  1387. }
  1388.  
  1389. static void
  1390. window_update_frame (window_t * window, USHORT flags)
  1391. {
  1392.   (void) WinSendMsg ((WINDOW_FRAME (window)), WM_UPDATEFRAME,
  1393.              (MPFROMSHORT (flags)),
  1394.              0);
  1395. }
  1396.  
  1397. static HWND
  1398. window_handle_from_id (qid_t qid, HWND window, ULONG id)
  1399. {
  1400.   return (WinWindowFromID (window, id));
  1401. }
  1402.  
  1403. static BOOL
  1404. window_set_capture (window_t * window, int capturep)
  1405. {
  1406.   if (capturep)
  1407.     {
  1408.       if (capture_window == 0)
  1409.     {
  1410.       BOOL rc = (WinSetCapture (HWND_DESKTOP, (WINDOW_CLIENT (window))));
  1411.       if (rc)
  1412.         capture_window = window;
  1413.       return (rc);
  1414.     }
  1415.       else
  1416.     return (capture_window == window);
  1417.     }
  1418.   else
  1419.     {
  1420.       capture_window = 0;
  1421.       return (WinSetCapture (HWND_DESKTOP, NULLHANDLE));
  1422.     }
  1423. }
  1424.  
  1425. static LONG
  1426. window_query_sys_value (qid_t qid, HWND window, LONG id)
  1427. {
  1428.   LONG value = (WinQuerySysValue (window, id));
  1429.   if (value == 0)
  1430.     window_error (WinQuerySysValue);
  1431.   return (value);
  1432. }
  1433.  
  1434. /* Text Cursors */
  1435.  
  1436. static void
  1437. window_move_cursor (window_t * window, short x, short y)
  1438. {
  1439.   (WINDOW_CURSOR_X (window)) = x;
  1440.   (WINDOW_CURSOR_Y (window)) = y;
  1441.   if (WINDOW_CURSOR_CREATEDP (window))
  1442.     win_create_cursor ((WINDOW_CLIENT (window)), x, y, 0, 0, CURSOR_SETPOS, 0);
  1443. }
  1444.  
  1445. static void
  1446. window_shape_cursor (window_t * window, unsigned short width,
  1447.              unsigned short height, unsigned short style)
  1448. {
  1449.   (WINDOW_CURSOR_WIDTH (window)) = width;
  1450.   (WINDOW_CURSOR_HEIGHT (window)) = height;
  1451.   (WINDOW_CURSOR_STYLE (window)) = style;
  1452.   if (WINDOW_CURSOR_CREATEDP (window))
  1453.     recreate_cursor (window);
  1454. }
  1455.  
  1456. static void
  1457. window_show_cursor (window_t * window, int showp)
  1458. {
  1459.   if ((WINDOW_CURSOR_CREATEDP (window))
  1460.       && ((showp != 0) != (WINDOW_CURSOR_ENABLEDP (window))))
  1461.     win_show_cursor ((WINDOW_CLIENT (window)), showp);
  1462.   (WINDOW_CURSOR_ENABLEDP (window)) = (showp != 0);
  1463. }
  1464.  
  1465. /* Helper Procedures */
  1466.  
  1467. static void
  1468. win_create_cursor (HWND client, LONG x, LONG y, LONG cx, LONG cy, ULONG fs,
  1469.            PRECTL clip_rectl)
  1470. {
  1471.   if (!WinCreateCursor (client, x, y, cx, cy, fs, clip_rectl))
  1472.     window_warning (WinCreateCursor);
  1473. }
  1474.  
  1475. static void
  1476. win_destroy_cursor (HWND client)
  1477. {
  1478.   if (!WinDestroyCursor (client))
  1479.     window_warning (WinDestroyCursor);
  1480. }
  1481.  
  1482. static void
  1483. win_show_cursor (HWND client, BOOL showp)
  1484. {
  1485.   if (!WinShowCursor (client, showp))
  1486.     window_warning (WinShowCursor);
  1487. }
  1488.  
  1489. static void
  1490. recreate_cursor (window_t * window)
  1491. {
  1492.   win_create_cursor ((WINDOW_CLIENT (window)),
  1493.              (WINDOW_CURSOR_X (window)),
  1494.              (WINDOW_CURSOR_Y (window)),
  1495.              (WINDOW_CURSOR_WIDTH (window)),
  1496.              (WINDOW_CURSOR_HEIGHT (window)),
  1497.              (WINDOW_CURSOR_STYLE (window)),
  1498.              0);
  1499.   (WINDOW_CURSOR_CREATEDP (window)) = 1;
  1500.   if (WINDOW_CURSOR_ENABLEDP (window))
  1501.     win_show_cursor ((WINDOW_CLIENT (window)), TRUE);
  1502. }
  1503.  
  1504. static void
  1505. activate_cursor (window_t * window)
  1506. {
  1507.   if ((WINDOW_CURSOR_CREATEDP (window)) && (WINDOW_CURSOR_ENABLEDP (window)))
  1508.     win_show_cursor ((WINDOW_CLIENT (window)), TRUE);
  1509. }
  1510.  
  1511. static void
  1512. deactivate_cursor (window_t * window)
  1513. {
  1514.   if ((WINDOW_CURSOR_CREATEDP (window)) && (WINDOW_CURSOR_ENABLEDP (window)))
  1515.     win_show_cursor ((WINDOW_CLIENT (window)), FALSE);
  1516. }
  1517.  
  1518. static void
  1519. maybe_activate_cursor (ps_t * ps)
  1520. {
  1521.   if ((PS_VISUAL_TYPE (ps)) == pst_window)
  1522.     activate_cursor (PS_VISUAL (ps));
  1523. }
  1524.  
  1525. static void
  1526. maybe_deactivate_cursor (ps_t * ps)
  1527. {
  1528.   if ((PS_VISUAL_TYPE (ps)) == pst_window)
  1529.     deactivate_cursor (PS_VISUAL (ps));
  1530. }
  1531.  
  1532. /* Presentation Spaces */
  1533.  
  1534. static ps_t *
  1535. create_memory_ps (qid_t qid)
  1536. {
  1537.   HDC hdc = (DevOpenDC (pm_hab, OD_MEMORY, "*", 0, 0, NULLHANDLE));
  1538.   if (hdc == DEV_ERROR)
  1539.     window_error (DevOpenDC);
  1540.   return (create_ps (pst_memory, hdc, qid));
  1541. }
  1542.  
  1543. static void
  1544. destroy_memory_ps (ps_t * ps)
  1545. {
  1546.   HDC hdc = (get_ps_device (PS_HANDLE (ps)));
  1547.   bitmap_t * bitmap = (PS_VISUAL (ps));
  1548.   destroy_ps (ps);
  1549.   if ((hdc != NULLHANDLE) && ((DevCloseDC (hdc)) == DEV_ERROR))
  1550.     window_warning (DevCloseDC);
  1551.   if (bitmap != 0)
  1552.     destroy_bitmap (bitmap);
  1553. }
  1554.  
  1555. static bitmap_t *
  1556. create_bitmap (ps_t * ps, USHORT width, USHORT height)
  1557. {
  1558.   HPS hps = (PS_HANDLE (ps));
  1559.   HDC hdc = (get_ps_device (hps));
  1560.   BITMAPINFOHEADER2 header;
  1561.   HBITMAP hbm;
  1562.   bitmap_t * bitmap;
  1563.  
  1564.   memset ((& header), 0, (sizeof (header)));
  1565.   (header . cbFix) = (sizeof (header));
  1566.   (header . cx) = width;
  1567.   (header . cy) = height;
  1568.   (header . cPlanes) = (get_device_capability (hdc, CAPS_COLOR_PLANES));
  1569.   (header . cBitCount) = (get_device_capability (hdc, CAPS_COLOR_BITCOUNT));
  1570.   hbm = (GpiCreateBitmap (hps, (& header), 0, 0, 0));
  1571.   if (hbm == GPI_ERROR)
  1572.     window_error (GpiCreateBitmap);
  1573.   bitmap = (OS_malloc (sizeof (bitmap_t)));
  1574.   (BITMAP_ID (bitmap)) = (allocate_id ((& bid_table), bitmap));
  1575.   (BITMAP_QID (bitmap)) = (PS_QID (ps));
  1576.   (BITMAP_HANDLE (bitmap)) = hbm;
  1577.   return (bitmap);
  1578. }
  1579.  
  1580. static void
  1581. destroy_bitmap (bitmap_t * bitmap)
  1582. {
  1583.   if (!GpiDeleteBitmap (BITMAP_HANDLE (bitmap)))
  1584.     window_warning (GpiDeleteBitmap);
  1585.   deallocate_id ((& bid_table), (BITMAP_ID (bitmap)));
  1586.   OS_free (bitmap);
  1587. }
  1588.  
  1589. static bitmap_t *
  1590. ps_set_bitmap (ps_t * ps, bitmap_t * bitmap)
  1591. {
  1592.   bitmap_t * previous_bitmap = (PS_VISUAL (ps));
  1593.   if ((GpiSetBitmap ((PS_HANDLE (ps)),
  1594.              ((bitmap == 0) ? 0 : (BITMAP_HANDLE (bitmap)))))
  1595.       == HBM_ERROR)
  1596.     window_error (GpiSetBitmap);
  1597.   (PS_VISUAL (ps)) = bitmap;
  1598.   return (previous_bitmap);
  1599. }
  1600.  
  1601. static void
  1602. ps_bitblt (ps_t * target, ps_t * source, LONG npoints, PPOINTL points,
  1603.        LONG rop, ULONG options)
  1604. {
  1605.   maybe_deactivate_cursor (target);
  1606.   if ((GpiBitBlt ((PS_HANDLE (target)), (PS_HANDLE (source)), npoints, points,
  1607.           rop, options))
  1608.       == GPI_ERROR)
  1609.     window_warning (GpiBitBlt);
  1610.   maybe_activate_cursor (target);
  1611. }
  1612.  
  1613. static void
  1614. ps_draw_text (ps_t * ps, short x, short y,
  1615.           const char * data, unsigned short size)
  1616. {
  1617.   HPS hps = (PS_HANDLE (ps));
  1618.   PLONG increments = (PS_CHAR_INCREMENTS (ps));
  1619.   POINTL ptl;
  1620.   (ptl . x) = x;
  1621.   (ptl . y) = y;
  1622.   maybe_deactivate_cursor (ps);
  1623.   if (size <= 512)
  1624.     {
  1625.       if (increments == 0)
  1626.     GpiCharStringAt (hps, (& ptl), size, ((char *) data));
  1627.       else
  1628.     GpiCharStringPosAt (hps, (& ptl), 0, CHS_VECTOR, size, ((char *) data),
  1629.                 increments);
  1630.     }
  1631.   else
  1632.     {
  1633.       const char * scan = data;
  1634.       GpiMove (hps, (& ptl));
  1635.       while (size > 0)
  1636.     {
  1637.       unsigned short n = ((size > 512) ? 512 : size);
  1638.       if (increments == 0)
  1639.         GpiCharString (hps, n, ((char *) scan));
  1640.       else
  1641.         GpiCharStringPos (hps, 0, CHS_VECTOR, n, ((char *) scan),
  1642.                   increments);
  1643.       size -= n;
  1644.       scan += n;
  1645.     }
  1646.     }
  1647.   maybe_activate_cursor (ps);
  1648. }
  1649.  
  1650. static unsigned short
  1651. ps_text_width (ps_t * ps, const char * data, unsigned short size)
  1652. {
  1653.   if ((PS_CHAR_INCREMENTS (ps)) == 0)
  1654.     {
  1655.       POINTL points [TXTBOX_COUNT];
  1656.       if (!GpiQueryTextBox ((PS_HANDLE (ps)), size, ((char *) data),
  1657.                 TXTBOX_COUNT, points))
  1658.     window_error (GpiQueryTextBox);
  1659.       return ((points [TXTBOX_CONCAT]) . x);
  1660.     }
  1661.   else
  1662.     return (size * ((PS_CHAR_INCREMENTS (ps)) [0]));
  1663. }
  1664.  
  1665. static void
  1666. ps_clear (ps_t * ps, short xl, short xh, short yl, short yh)
  1667. {
  1668.   RECTL rectl;
  1669.   (rectl . xLeft) = xl;
  1670.   (rectl . xRight) = xh;
  1671.   (rectl . yBottom) = yl;
  1672.   (rectl . yTop) = yh;
  1673.   maybe_deactivate_cursor (ps);
  1674.   if (!WinFillRect ((PS_HANDLE (ps)), (&rectl), (PS_BACKGROUND_COLOR (ps))))
  1675.     window_warning (WinFillRect);
  1676.   maybe_activate_cursor (ps);
  1677. }
  1678.  
  1679. static COLOR
  1680. ps_get_foreground_color (ps_t * ps)
  1681. {
  1682.   return (PS_FOREGROUND_COLOR (ps));
  1683. }
  1684.  
  1685. static COLOR
  1686. ps_get_background_color (ps_t * ps)
  1687. {
  1688.   return (PS_BACKGROUND_COLOR (ps));
  1689. }
  1690.  
  1691. static void
  1692. ps_set_colors (ps_t * ps, COLOR foreground, COLOR background)
  1693. {
  1694.   if (!GpiSetColor ((PS_HANDLE (ps)), foreground))
  1695.     window_warning (GpiSetColor);
  1696.   if (!GpiSetMix ((PS_HANDLE (ps)), FM_OVERPAINT))
  1697.     window_warning (GpiSetMix);
  1698.   if (!GpiSetBackColor ((PS_HANDLE (ps)), background))
  1699.     window_warning (GpiSetBackColor);
  1700.   if (!GpiSetBackMix ((PS_HANDLE (ps)), BM_OVERPAINT))
  1701.     window_warning (GpiSetBackMix);
  1702.   (PS_FOREGROUND_COLOR (ps)) = foreground;
  1703.   (PS_BACKGROUND_COLOR (ps)) = background;
  1704. }
  1705.  
  1706. static void
  1707. ps_move_gcursor (ps_t * ps, short x, short y)
  1708. {
  1709.   POINTL ptl;
  1710.   (ptl . x) = x;
  1711.   (ptl . y) = y;
  1712.   if (!GpiMove ((PS_HANDLE (ps)), (& ptl)))
  1713.     window_warning (GpiMove);
  1714. }
  1715.  
  1716. static void
  1717. ps_draw_line (ps_t * ps, short x, short y)
  1718. {
  1719.   POINTL ptl;
  1720.   (ptl . x) = x;
  1721.   (ptl . y) = y;
  1722.   if ((GpiLine ((PS_HANDLE (ps)), (& ptl))) == GPI_ERROR)
  1723.     window_warning (GpiLine);
  1724. }
  1725.  
  1726. static void
  1727. ps_draw_point (ps_t * ps, short x, short y)
  1728. {
  1729.   POINTL ptl;
  1730.   (ptl . x) = x;
  1731.   (ptl . y) = y;
  1732.   if ((GpiSetPel ((PS_HANDLE (ps)), (& ptl))) == GPI_ERROR)
  1733.     window_warning (GpiSetPel);
  1734. }
  1735.  
  1736. static void
  1737. ps_poly_line (ps_t * ps, unsigned long npoints, PPOINTL points)
  1738. {
  1739.   if ((GpiPolyLine ((PS_HANDLE (ps)), npoints, points)) == GPI_ERROR)
  1740.     window_warning (GpiPolyLine);
  1741. }
  1742.  
  1743. static void
  1744. ps_poly_line_disjoint (ps_t * ps, unsigned long npoints, PPOINTL points)
  1745. {
  1746.   if ((GpiPolyLineDisjoint ((PS_HANDLE (ps)), npoints, points))
  1747.       == GPI_ERROR)
  1748.     window_warning (GpiPolyLineDisjoint);
  1749. }
  1750.  
  1751. static void
  1752. ps_set_line_type (ps_t * ps, LONG type)
  1753. {
  1754.   if (!GpiSetLineType ((PS_HANDLE (ps)), type))
  1755.     window_warning (GpiSetLineType);
  1756. }
  1757.  
  1758. static void
  1759. ps_set_mix (ps_t * ps, LONG mix)
  1760. {
  1761.   if (!GpiSetMix ((PS_HANDLE (ps)), mix))
  1762.     window_warning (GpiSetMix);
  1763. }
  1764.  
  1765. static void
  1766. ps_query_caps (ps_t * ps, LONG start, LONG count, PLONG values)
  1767. {
  1768.   HDC hdc = (get_ps_device (PS_HANDLE (ps)));
  1769.   if (hdc == NULLHANDLE)
  1770.     window_error (GpiQueryDevice);
  1771.   if (!DevQueryCaps (hdc, start, count, values))
  1772.     window_error (DevQueryCaps);
  1773. }
  1774.  
  1775. static void
  1776. ps_reset_clip_rectangle (ps_t * ps)
  1777. {
  1778.   if (!GpiSetClipPath ((PS_HANDLE (ps)), 0, SCP_RESET))
  1779.     window_error (GpiSetClipPath);
  1780. }
  1781.  
  1782. static void
  1783. ps_set_clip_rectangle (ps_t * ps, short xl, short xh, short yl, short yh)
  1784. {
  1785.   HPS hps = (PS_HANDLE (ps));
  1786.   ps_reset_clip_rectangle (ps);
  1787.   if (!GpiBeginPath (hps, 1))
  1788.     window_error (GpiBeginPath);
  1789.   {
  1790.     POINTL points [4];
  1791.     ((points[0]) . x) = xl;
  1792.     ((points[0]) . y) = yl;
  1793.     ((points[1]) . x) = xl;
  1794.     ((points[1]) . y) = yh;
  1795.     ((points[2]) . x) = xh;
  1796.     ((points[2]) . y) = yh;
  1797.     ((points[3]) . x) = xh;
  1798.     ((points[3]) . y) = yl;
  1799.     if (!GpiMove (hps, (&points[3])))
  1800.       window_warning (GpiMove);
  1801.     if ((GpiPolyLine (hps, 4, points)) == GPI_ERROR)
  1802.       window_warning (GpiPolyLine);
  1803.   }
  1804.   if (!GpiEndPath (hps))
  1805.     window_error (GpiEndPath);
  1806.   if (!GpiSetClipPath (hps, 1, (SCP_AND | SCP_INCL)))
  1807.     window_error (GpiSetClipPath);
  1808. }
  1809.  
  1810. static void
  1811. get_bitmap_parameters (bitmap_t * bitmap, PBITMAPINFOHEADER params)
  1812. {
  1813.   if (!GpiQueryBitmapParameters ((BITMAP_HANDLE (bitmap)), params))
  1814.     window_error (GpiQueryBitmapParameters);
  1815. }
  1816.  
  1817. static unsigned long
  1818. ps_get_bitmap_bits (ps_t * ps, unsigned long start, unsigned long length,
  1819.             PBYTE data, PBITMAPINFO2 info)
  1820. {
  1821.   LONG r = (GpiQueryBitmapBits ((PS_HANDLE (ps)), start, length, data, info));
  1822.   if (r < 0)
  1823.     window_error (GpiQueryBitmapBits);
  1824.   return (r);
  1825. }
  1826.  
  1827. static unsigned long
  1828. ps_set_bitmap_bits (ps_t * ps, unsigned long start, unsigned long length,
  1829.             PBYTE data, PBITMAPINFO2 info)
  1830. {
  1831.   LONG r = (GpiSetBitmapBits ((PS_HANDLE (ps)), start, length, data, info));
  1832.   if (r < 0)
  1833.     window_error (GpiSetBitmapBits);
  1834.   return (r);
  1835. }
  1836.  
  1837. /* Helper Procedures */
  1838.  
  1839. static HDC
  1840. get_ps_device (HPS hps)
  1841. {
  1842.   HDC hdc = (GpiQueryDevice (hps));
  1843.   if (hdc == HDC_ERROR)
  1844.     window_error (GpiQueryDevice);
  1845.   return (hdc);
  1846. }
  1847.  
  1848. static LONG
  1849. get_device_capability (HDC hdc, LONG index)
  1850. {
  1851.   LONG result;
  1852.   if (!DevQueryCaps (hdc, index, 1, (& result)))
  1853.     window_error (DevQueryCaps);
  1854.   return (result);
  1855. }
  1856.  
  1857. static ps_t *
  1858. create_ps (pst_t type, HDC hdc, qid_t qid)
  1859. {
  1860.   ps_t * ps = (OS_malloc (sizeof (ps_t)));
  1861.   SIZEL sizel;
  1862.   HPS hps;
  1863.   (sizel . cx) = 0;
  1864.   (sizel . cy) = 0;
  1865.   hps = (GpiCreatePS (pm_hab, hdc, (& sizel),
  1866.               (PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC)));
  1867.   if (hps == 0)
  1868.     window_error (GpiCreatePS);
  1869.   /* Put color table in RGB mode so we can specify colors
  1870.      directly in RGB values rather than as indices.  */
  1871.   if (!GpiCreateLogColorTable (hps, LCOL_PURECOLOR, LCOLF_RGB, 0, 0, 0))
  1872.     window_warning (GpiCreateLogColorTable);
  1873.   (PS_HANDLE (ps)) = hps;
  1874.   (PS_ID (ps)) = (allocate_id ((& psid_table), ps));
  1875.   (PS_QID (ps)) = qid;
  1876.   (PS_VISUAL_TYPE (ps)) = type;
  1877.   (PS_VISUAL (ps)) = 0;
  1878.   (PS_CHAR_INCREMENTS (ps)) = 0;
  1879.   ps_set_colors (ps, RGB_BLACK, RGB_WHITE);
  1880.   return (ps);
  1881. }
  1882.  
  1883. static void
  1884. destroy_ps (ps_t * ps)
  1885. {
  1886.   if ((PS_CHAR_INCREMENTS (ps)) != 0)
  1887.     OS_free (PS_CHAR_INCREMENTS (ps));
  1888.   if (!GpiDestroyPS (PS_HANDLE (ps)))
  1889.     window_warning (GpiDestroyPS);
  1890.   deallocate_id ((& psid_table), (PS_ID (ps)));
  1891.   OS_free (ps);
  1892. }
  1893.  
  1894. /* Clipboard */
  1895.  
  1896. static void
  1897. clipboard_write_text (qid_t qid, const char * text)
  1898. {
  1899.   unsigned int len = ((strlen (text)) + 1);
  1900.   PVOID shared_copy;
  1901.   int copy_used = 0;
  1902.  
  1903.   STD_API_CALL
  1904.     (dos_alloc_shared_mem,
  1905.      ((&shared_copy), 0, len,
  1906.       (PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GIVEABLE)));
  1907.   FASTCOPY (text, ((char *) shared_copy), len);
  1908.  
  1909.   if (WinOpenClipbrd (pm_hab))
  1910.     {
  1911.       if (WinEmptyClipbrd (pm_hab))
  1912.     copy_used
  1913.       = (WinSetClipbrdData
  1914.          (pm_hab, ((ULONG) shared_copy), CF_TEXT, CFI_POINTER));
  1915.       (void) WinCloseClipbrd (pm_hab);
  1916.     }
  1917.   if (!copy_used)
  1918.     STD_API_CALL (dos_free_mem, (shared_copy));
  1919. }
  1920.  
  1921. static const char *
  1922. clipboard_read_text (qid_t qid)
  1923. {
  1924.   char * result = 0;
  1925.   if (WinOpenClipbrd (pm_hab))
  1926.     {
  1927.       const char * shared_copy
  1928.     = ((const char *) (WinQueryClipbrdData (pm_hab, CF_TEXT)));
  1929.       if (shared_copy != 0)
  1930.     {
  1931.       unsigned int len = ((strlen (shared_copy)) + 1);
  1932.       result = (OS_malloc (len));
  1933.       FASTCOPY (shared_copy, result, len);
  1934.     }
  1935.       (void) WinCloseClipbrd (pm_hab);
  1936.     }
  1937.   return (result);
  1938. }
  1939.  
  1940. /* Menus */
  1941.  
  1942. static HWND
  1943. menu_create (qid_t qid, HWND owner, USHORT style, USHORT id)
  1944. {
  1945.   return
  1946.     (WinCreateWindow (owner,    /* parent window */
  1947.               WC_MENU,    /* class name */
  1948.               "",    /* window text */
  1949.               style,    /* window style */
  1950.               0, 0, 0, 0, /* size and position */
  1951.               owner,    /* owner window */
  1952.               HWND_TOP, /* sibling window */
  1953.               id,    /* ID */
  1954.               0,    /* control data */
  1955.               0        /* presentation parameters */
  1956.               ));
  1957. }
  1958.  
  1959. static BOOL
  1960. menu_destroy (qid_t qid, HWND menu)
  1961. {
  1962.   return (WinDestroyWindow (menu));
  1963. }
  1964.  
  1965. static USHORT
  1966. menu_insert_item (qid_t qid, HWND menu, USHORT position, USHORT style,
  1967.           USHORT attributes, USHORT id, HWND submenu, char * text)
  1968. {
  1969.   MENUITEM item;
  1970.   (item . iPosition) = position;
  1971.   (item . afStyle) = style;
  1972.   (item . afAttribute) = attributes;
  1973.   (item . id) = id;
  1974.   (item . hwndSubMenu) = submenu;
  1975.   (item . hItem) = 0;
  1976.   return (SHORT1FROMMR (WinSendMsg (menu, MM_INSERTITEM,
  1977.                     (MPFROMP (&item)),
  1978.                     (MPFROMP (text)))));
  1979. }
  1980.  
  1981. static USHORT
  1982. menu_remove_item (qid_t qid, HWND menu, USHORT id, USHORT submenup,
  1983.           USHORT deletep)
  1984. {
  1985.   return (SHORT1FROMMR (WinSendMsg (menu,
  1986.                     (deletep ? MM_DELETEITEM : MM_REMOVEITEM),
  1987.                     (MPFROM2SHORT (id, submenup)),
  1988.                     0)));
  1989. }
  1990.  
  1991. static PMENUITEM
  1992. menu_get_item (qid_t qid, HWND menu, USHORT id, USHORT submenup)
  1993. {
  1994.   PMENUITEM item = (OS_malloc (sizeof (MENUITEM)));
  1995.   if (LONGFROMMR (WinSendMsg (menu, MM_QUERYITEM,
  1996.                   (MPFROM2SHORT (id, submenup)),
  1997.                   (MPFROMP (item)))))
  1998.     return (item);
  1999.   OS_free (item);
  2000.   return (0);
  2001. }
  2002.  
  2003. static USHORT
  2004. menu_n_items (qid_t qid, HWND menu)
  2005. {
  2006.   return (SHORT1FROMMR (WinSendMsg (menu, MM_QUERYITEMCOUNT, 0, 0)));
  2007. }
  2008.  
  2009. static USHORT
  2010. menu_nth_item_id (qid_t qid, HWND menu, USHORT position)
  2011. {
  2012.   return (SHORT1FROMMR (WinSendMsg (menu, MM_ITEMIDFROMPOSITION,
  2013.                     (MPFROMSHORT (position)),
  2014.                     0)));
  2015. }
  2016.  
  2017. static USHORT
  2018. menu_get_item_attributes (qid_t qid, HWND menu, USHORT id, USHORT submenup,
  2019.               USHORT mask)
  2020. {
  2021.   return (SHORT1FROMMR (WinSendMsg (menu, MM_QUERYITEMATTR,
  2022.                     (MPFROM2SHORT (id, submenup)),
  2023.                     (MPFROMSHORT (mask)))));
  2024. }
  2025.  
  2026. static BOOL
  2027. menu_set_item_attributes (qid_t qid, HWND menu, USHORT id, USHORT submenup,
  2028.               USHORT mask, USHORT attributes)
  2029. {
  2030.   return (LONGFROMMR (WinSendMsg (menu, MM_SETITEMATTR,
  2031.                   (MPFROM2SHORT (id, submenup)),
  2032.                   (MPFROM2SHORT (mask, attributes)))));
  2033. }
  2034.  
  2035. static HWND
  2036. window_load_menu (window_t * window, HMODULE module, ULONG id)
  2037. {
  2038.   return (WinLoadMenu ((WINDOW_FRAME (window)), module, id));
  2039. }
  2040.  
  2041. static BOOL
  2042. window_popup_menu (qid_t qid, HWND parent, HWND owner, HWND menu,
  2043.            LONG x, LONG y, LONG id, ULONG options)
  2044. {
  2045.   return (WinPopupMenu (parent, owner, menu, x, y, id, options));
  2046. }
  2047.  
  2048. /* Fonts */
  2049.  
  2050. static font_metrics_t *
  2051. ps_get_font_metrics (ps_t * ps)
  2052. {
  2053.   font_metrics_t * metrics = (OS_malloc (sizeof (font_metrics_t)));
  2054.   FONTMETRICS fm;
  2055.   if (!GpiQueryFontMetrics ((PS_HANDLE (ps)), (sizeof (fm)), (& fm)))
  2056.     window_error (GpiQueryFontMetrics);
  2057.   (FONT_METRICS_WIDTH (metrics)) = (fm . lMaxCharInc);
  2058.   (FONT_METRICS_HEIGHT (metrics)) = (fm . lMaxBaselineExt);
  2059.   (FONT_METRICS_DESCENDER (metrics)) = (fm . lMaxDescender);
  2060.   return (metrics);
  2061. }
  2062.  
  2063. static font_metrics_t *
  2064. ps_set_font_internal (ps_t * ps, unsigned short id, const char * spec)
  2065. {
  2066.   return ((ps_set_font (ps, id, spec)) ? (ps_get_font_metrics (ps)) : 0);
  2067. }
  2068.  
  2069. static const char *
  2070. window_font_dialog (window_t * window, const char * title)
  2071. {
  2072.   ps_t * ps = (WINDOW_CLIENT_PS (window));
  2073.   HPS hps = (PS_HANDLE (ps));
  2074.   FONTDLG info;
  2075.   char name_buffer [FACESIZE];
  2076.   HWND result;
  2077.  
  2078.   memset ((&info), 0, (sizeof (info)));
  2079.   (name_buffer[0]) = '\0';
  2080.   (info . cbSize) = (sizeof (info));
  2081.   (info . hpsScreen) = hps;
  2082.   (info . pszTitle) = ((PSZ) title);
  2083.   (info . fl) = (FNTS_FIXEDWIDTHONLY | FNTS_CENTER); /* FNTS_INITFROMFATTRS */
  2084.   (info . pszFamilyname) = name_buffer;
  2085.   (info . usFamilyBufLen) = (sizeof (name_buffer));
  2086.   /* Because our PS is in RGB mode, the RGB color specs we are using
  2087.      are useless.  It's undocumented, but only indexed colors work in
  2088.      the font dialog, so we must override with indexes.  */
  2089.   (info . clrFore) = CLR_BLACK; /* (PS_FOREGROUND_COLOR (ps)) */
  2090.   (info . clrBack) = CLR_WHITE; /* (PS_BACKGROUND_COLOR (ps)) */
  2091.   {
  2092.     FONTMETRICS fm;
  2093.     if (GpiQueryFontMetrics (hps, (sizeof (fm)), (&fm)))
  2094.       {
  2095.     strcpy (name_buffer, (fm . szFamilyname));
  2096.     (info . usWeight) = (fm . usWeightClass);
  2097.     (info . usWidth) = (fm . usWidthClass);
  2098.     (info . fxPointSize)
  2099.       = (MAKEFIXED (((fm . sNominalPointSize) / 10), 0));
  2100.     (info . flStyle) = (fm . fsSelection);
  2101.     copy_fontmetrics_to_fattrs ((&fm), (& (info . fAttrs)));
  2102. #if 0
  2103.     /* The following, for some unknown reason, causes the
  2104.        selection of incorrect fonts: */
  2105.     (info . fl) |= FNTS_INITFROMFATTRS;
  2106. #endif
  2107.       }
  2108.   }
  2109.   result = (WinFontDlg (HWND_DESKTOP, (WINDOW_CLIENT (window)), (&info)));
  2110.   if ((result == NULLHANDLE) || ((info . lReturn) != DID_OK))
  2111.     return (0);
  2112.   {
  2113.     PSZ face_name;
  2114.     const char * font_spec;
  2115.     {
  2116.       FACENAMEDESC desc;
  2117.       ULONG face_name_length;
  2118.       char face_name_dummy [1];
  2119.       memset ((&desc), 0, (sizeof (desc)));
  2120.       (desc . usSize) = (sizeof (desc));
  2121.       (desc . usWeightClass) = (info . usWeight);
  2122.       (desc . usWidthClass) = (info . usWidth);
  2123.       (desc . flOptions) = (info . flType);
  2124.       face_name = face_name_dummy;
  2125.       face_name_length
  2126.     = (GpiQueryFaceString (hps, (info . pszFamilyname), (&desc),
  2127.                    0, face_name));
  2128.       if (face_name_length == GPI_ERROR)
  2129.     {
  2130.       window_warning (GpiQueryFaceString);
  2131.       return (0);
  2132.     }
  2133.       face_name = (OS_malloc (face_name_length));
  2134.       face_name_length
  2135.     = (GpiQueryFaceString (hps, (info . pszFamilyname), (&desc),
  2136.                    face_name_length, face_name));
  2137.       if (face_name_length == GPI_ERROR)
  2138.     {
  2139.       OS_free (face_name);
  2140.       window_warning (GpiQueryFaceString);
  2141.       return (0);
  2142.     }
  2143.     }
  2144.     font_spec = (unparse_font_spec (face_name,
  2145.                     ((FIXEDINT (info . fxPointSize)) * 10),
  2146.                     (info . flStyle)));
  2147.     OS_free (face_name);
  2148.     return (font_spec);
  2149.   }
  2150. }
  2151.  
  2152. /* Helper Procedures */
  2153.  
  2154. static int
  2155. ps_set_font (ps_t * ps, unsigned short id, const char * spec)
  2156. {
  2157.   PSZ name = 0;
  2158.   LONG size;
  2159.   USHORT selection;
  2160.   if (!parse_font_spec (spec, (& name), (& size), (& selection)))
  2161.     return (0);
  2162.   if (!ps_set_font_1 (ps, name, size, selection, id))
  2163.     {
  2164.       OS_free (name);
  2165.       return (0);
  2166.     }
  2167.   {
  2168.     FONTMETRICS fm;
  2169.     if (!GpiQueryFontMetrics ((PS_HANDLE (ps)), (sizeof (fm)), (& fm)))
  2170.       window_error (GpiQueryFontMetrics);
  2171.     if ((PS_CHAR_INCREMENTS (ps)) != 0)
  2172.       OS_free (PS_CHAR_INCREMENTS (ps));
  2173.     (PS_CHAR_INCREMENTS (ps))
  2174.       = ((((fm . fsDefn) & FM_DEFN_OUTLINE) != 0)
  2175.      ? (ps_make_char_increments (fm . lMaxCharInc))
  2176.      : 0);
  2177.   }
  2178.   return (1);
  2179. }
  2180.  
  2181. static int
  2182. ps_set_font_1 (ps_t * ps, PSZ name, LONG size, USHORT selection, LONG id)
  2183. {
  2184.   HPS hps = (PS_HANDLE (ps));
  2185.   LONG nfonts;
  2186.   ULONG index;
  2187.   PFONTMETRICS pfm;
  2188.  
  2189.   nfonts = 0;
  2190.   nfonts = (GpiQueryFonts (hps,
  2191.                (QF_PUBLIC | QF_PRIVATE),
  2192.                name,
  2193.                (& nfonts),
  2194.                (sizeof (FONTMETRICS)),
  2195.                0));
  2196.   if (nfonts == GPI_ALTERROR)
  2197.     window_error (GpiQueryFonts);
  2198.   if (nfonts == 0)
  2199.     return (0);
  2200.   pfm = (OS_malloc (nfonts * (sizeof (FONTMETRICS))));
  2201.   if ((GpiQueryFonts (hps,
  2202.               (QF_PUBLIC | QF_PRIVATE),
  2203.               name,
  2204.               (& nfonts),
  2205.               (sizeof (FONTMETRICS)),
  2206.               pfm))
  2207.       == GPI_ALTERROR)
  2208.     window_error (GpiQueryFonts);
  2209.   {
  2210.     int result = 0;
  2211.     /* Choose an image font if one is available.  */
  2212.     for (index = 0; (index < nfonts); index += 1)
  2213.       if (((((pfm [index]) . fsType) & FM_TYPE_FIXED) != 0)
  2214.       && ((((pfm [index]) . fsDefn) & FM_DEFN_OUTLINE) == 0)
  2215.       && (((pfm [index]) . sNominalPointSize) == size)
  2216.       && (create_font (hps, id, (& (pfm [index])), selection)))
  2217.     {
  2218.       GpiSetCharSet (hps, id);
  2219.       result = 1;
  2220.       goto done;
  2221.     }
  2222.     /* Otherwise, look for an outline font.  */
  2223.     for (index = 0; (index < nfonts); index += 1)
  2224.       if (((((pfm [index]) . fsType) & FM_TYPE_FIXED) != 0)
  2225.       && ((((pfm [index]) . fsDefn) & FM_DEFN_OUTLINE) != 0)
  2226.       && (create_font (hps, id, (& (pfm [index])), selection)))
  2227.     {
  2228.       GpiSetCharSet (hps, id);
  2229.       ps_set_font_size (ps, size);
  2230.       result = 1;
  2231.       goto done;
  2232.     }
  2233.   done:
  2234.     OS_free (pfm);
  2235.     return (result);
  2236.   }
  2237. }
  2238.  
  2239. static int
  2240. create_font (HPS hps, LONG font_id, PFONTMETRICS pfm, USHORT selection)
  2241. {
  2242.   FATTRS fa;
  2243.   copy_fontmetrics_to_fattrs (pfm, (&fa));
  2244.   (fa . fsSelection) = selection;
  2245.   return ((GpiCreateLogFont (hps, 0, font_id, (&fa))) == FONT_MATCH);
  2246. }
  2247.  
  2248. static void
  2249. copy_fontmetrics_to_fattrs (FONTMETRICS * pfm, FATTRS * pfa)
  2250. {
  2251.   (pfa -> usRecordLength) = (sizeof (*pfa));
  2252.   (pfa -> fsSelection) = (pfm -> fsSelection);
  2253.   (pfa -> lMatch) = (pfm -> lMatch);
  2254.   strcpy ((pfa -> szFacename), (pfm -> szFacename));
  2255.   (pfa -> idRegistry) = (pfm -> idRegistry);
  2256.   (pfa -> usCodePage) = (pfm -> usCodePage);
  2257.   (pfa -> fsType) = 0;
  2258.   if (((pfm -> fsDefn) & FM_DEFN_OUTLINE) != 0)
  2259.     {
  2260.       (pfa -> lMaxBaselineExt) = 0;
  2261.       (pfa -> lAveCharWidth) = 0;
  2262.       (pfa -> fsFontUse)
  2263.     = (FATTR_FONTUSE_OUTLINE | FATTR_FONTUSE_TRANSFORMABLE);
  2264.     }
  2265.   else
  2266.     {
  2267.       (pfa -> lMaxBaselineExt) = (pfm -> lMaxBaselineExt);
  2268.       (pfa -> lAveCharWidth) = (pfm -> lAveCharWidth);
  2269.       (pfa -> fsFontUse) = 0;
  2270.     }
  2271. }
  2272.  
  2273. static void
  2274. ps_set_font_size (ps_t * ps, LONG size)
  2275. {
  2276.   POINTL ptl [2];
  2277.  
  2278.   ((ptl[0]) . x) = 0;
  2279.   ((ptl[0]) . y) = 0;
  2280.   {
  2281.     LONG xres;
  2282.     ps_query_caps (ps, CAPS_HORIZONTAL_FONT_RES, 1, (&xres));
  2283.     ((ptl[1]) . x) = ((((xres * size) << 4) + 360) / 720);
  2284.   }
  2285.   {
  2286.     LONG yres;
  2287.     ps_query_caps (ps, CAPS_VERTICAL_FONT_RES, 1, (&yres));
  2288.     ((ptl[1]) . y) = ((((yres * size) << 4) + 360) / 720);
  2289.   }
  2290.   if (!GpiConvert ((PS_HANDLE (ps)), CVTC_DEVICE, CVTC_WORLD, 2, ptl))
  2291.     window_error (GpiConvert);
  2292.   {
  2293.     SIZEF s;
  2294.     (s . cx) = ((((ptl[1]) . x) - ((ptl[0]) . x)) << 12);
  2295.     (s . cy) = ((((ptl[1]) . y) - ((ptl[0]) . y)) << 12);
  2296.     if (!GpiSetCharBox ((PS_HANDLE (ps)), (&s)))
  2297.       window_error (GpiSetCharBox);
  2298.   }
  2299. }
  2300.  
  2301. static PLONG
  2302. ps_make_char_increments (LONG increment)
  2303. {
  2304.   PLONG increments = (OS_malloc ((sizeof (LONG)) * 512));
  2305.   unsigned int index;
  2306.   for (index = 0; (index < 512); index += 1)
  2307.     (increments[index]) = increment;
  2308.   return (increments);
  2309. }
  2310.  
  2311. static struct font_selection
  2312. {
  2313.   const char * name;
  2314.   unsigned int selector;
  2315. } font_selections [] =
  2316. {
  2317.   { ".bold", FATTR_SEL_BOLD },
  2318.   { ".italic", FATTR_SEL_ITALIC },
  2319.   { ".outline", FATTR_SEL_OUTLINE },
  2320.   { ".strikeout", FATTR_SEL_STRIKEOUT },
  2321.   { ".underscore", FATTR_SEL_UNDERSCORE },
  2322.   { 0, 0 }
  2323. };
  2324.  
  2325. static int
  2326. parse_font_spec (const char * spec,
  2327.          PSZ * pname, LONG * psize, USHORT * pselection)
  2328. {
  2329.   const char * scan = spec;
  2330.   unsigned int size = 0;
  2331.   unsigned int selection = 0;
  2332.   while (('0' <= (*scan)) && ((*scan) <= '9'))
  2333.     size = ((size * 10) + ((*scan++) - '0'));
  2334.   if (size == 0)
  2335.     return (0);
  2336.   while (1)
  2337.     {
  2338.       struct font_selection * selections = font_selections;
  2339.       unsigned int name_length;
  2340.       while (1)
  2341.     {
  2342.       if ((selections -> name) == 0)
  2343.         goto no_more_selections;
  2344.       name_length = (strlen (selections -> name));
  2345.       if ((strncmp (scan, (selections -> name), name_length)) == 0)
  2346.         {
  2347.           selection |= (selections -> selector);
  2348.           scan += name_length;
  2349.           break;
  2350.         }
  2351.       selections += 1;
  2352.     }
  2353.     }
  2354.  no_more_selections:
  2355.   if ((*scan++) != '.')
  2356.     return (0);
  2357.   (*pname) = (OS_malloc ((strlen (scan)) + 1));
  2358.   strcpy ((*pname), scan);
  2359.   (*psize) = (size * 10);
  2360.   (*pselection) = selection;
  2361.   return (1);
  2362. }
  2363.  
  2364. static const char *
  2365. unparse_font_spec (PSZ name, LONG size, USHORT selection)
  2366. {
  2367.   char size_buffer [16];
  2368.   char selection_buffer [16];
  2369.   struct font_selection * selections = font_selections;
  2370.   char * result;
  2371.  
  2372.   sprintf (size_buffer, "%d", (size / 10));
  2373.   strcpy (selection_buffer, "");
  2374.   while (1)
  2375.     {
  2376.       if ((selections -> name) == 0)
  2377.     break;
  2378.       if ((selection & (selections -> selector)) != 0)
  2379.     strcat (selection_buffer, (selections -> name));
  2380.       selections += 1;
  2381.     }
  2382.   result
  2383.     = (OS_malloc ((strlen (size_buffer))
  2384.           + (strlen (name))
  2385.           + (strlen (selection_buffer))
  2386.           + 2));
  2387.   strcpy (result, size_buffer);
  2388.   strcat (result, selection_buffer);
  2389.   strcat (result, ".");
  2390.   strcat (result, name);
  2391.   return (result);
  2392. }
  2393.  
  2394. /* Pointers and Icons */
  2395.  
  2396. static HPOINTER
  2397. query_system_pointer (qid_t qid, HWND desktop, LONG id, BOOL copyp)
  2398. {
  2399.   return (WinQuerySysPointer (desktop, id, copyp));
  2400. }
  2401.  
  2402. static BOOL
  2403. set_pointer (qid_t qid, HWND desktop, HPOINTER pointer)
  2404. {
  2405.   return (WinSetPointer (desktop, pointer));
  2406. }
  2407.  
  2408. static HPOINTER
  2409. window_load_pointer (qid_t qid, HWND desktop, HMODULE module, ULONG id)
  2410. {
  2411.   return (WinLoadPointer (desktop, module, id));
  2412. }
  2413.  
  2414. static BOOL
  2415. window_destroy_pointer (qid_t qid, HPOINTER pointer)
  2416. {
  2417.   return (WinDestroyPointer (pointer));
  2418. }
  2419.  
  2420. static BOOL
  2421. window_set_icon (window_t * window, HPOINTER icon)
  2422. {
  2423.   return (LONGFROMMR (WinSendMsg ((WINDOW_FRAME (window)), WM_SETICON,
  2424.                   (MPFROMLONG (icon)),
  2425.                   (MPFROMLONG (0)))));
  2426. }
  2427.