chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Steel / c / wimpt
1 /*
2  * wimpt.c
3  *
4  * Low level Wimp interface
5  *
6  * © 1994-1998 Straylight
7  */
8
9 /*----- Licensing note ----------------------------------------------------*
10  *
11  * This file is part of Straylight's Steel library.
12  *
13  * Steel is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2, or (at your option)
16  * any later version.
17  *
18  * Steel is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with Steel.  If not, write to the Free Software Foundation,
25  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <signal.h>
34 #include <string.h>
35 #include "dll.h"
36 #include "swis.h"
37 #include "kernel.h"
38
39 #include "os.h"
40 #include "bbc.h"
41 #include "wimp.h"
42 #include "font.h"
43 #include "wimpt.h"
44 #include "wimpt.h"
45 #include "werr.h"
46 #include "alarm.h"
47 #include "event.h"
48 #include "flex.h"
49 #include "msgs.h"
50 #include "interface.h"
51 #include "exception.h"
52 #include "mem.h"
53 #include "visdelay.h"
54 #include "caretptr.h"
55 #include "sculptrix.h"
56 #include "resspr.h"
57
58 /*----- Veneered internal functions ---------------------------------------*/
59
60 #ifndef _dll_NODLL
61   extern void _dllEntry(wimpt__signals)(int sig);
62   extern void _dllEntry(wimpt__escapeHandler)(int sig);
63   extern void _dllEntry(wimpt__exit)(void);
64 #endif
65
66 /*----- Static data -------------------------------------------------------*/
67
68 /* --- Event handling --- */
69
70 static BOOL wimpt__fakeWaiting;
71 static wimp_eventstr wimpt__fakeEvent;
72 static wimp_eventstr wimpt__lastEvent;
73
74 /* --- Wimp task management --- */
75
76 static wimp_t wimpt__task;
77 static char *wimpt__name="<Untitled>";
78 static int wimpt__wimpVersion;
79 static int *wimpt__messages;
80 static BOOL wimpt__justChangedMode;
81 static int wimpt__pollingTime=100/50;
82 static int wimpt__options=wimpt_OSCULPTRIX;
83
84 /* --- Mode information --- */
85
86 static int wimpt__currentMode;
87 static int wimpt__dx;
88 static int wimpt__dy;
89 static int wimpt__bpp;
90 static int wimpt__xwind;
91 static int wimpt__ywind;
92
93 /*----- Internal functions ------------------------------------------------*/
94
95 /* --- Signal handling --- */
96
97 _dll_static void wimpt__escapeHandler(int sig)
98 {
99   sig=sig;
100   signal(SIGINT,_dllEntry(wimpt__escapeHandler));
101 }
102
103 _dll_static void wimpt__signals(int sig)
104 {
105   static char *errors[]=
106   {
107     "?",
108     "SIGABRT",
109     "SIGFPE",
110     "SIGILL",
111     "SIGINT",
112     "SIGSEGV",
113     "SIGTERM",
114     "SIGSTAK",
115     "SIGUSR1",
116     "SIGUSR2",
117     "SIGOSERROR"
118   };
119
120   signal(sig,_dllEntry(wimpt__signals));
121   exception_generate(msgs_lookup("wimptSIGC:%s - code=%s"),
122                      _kernel_last_oserror()->errmess,
123                      sig>0 && sig<8 ? errors[sig] : "SIGUKN");
124 }
125
126 /* --- Exit handler --- */
127
128 _dll_static void wimpt__exit(void)
129 {
130   if (wimpt__options & wimpt_OINTERFACE)
131     interface_closeDown(wimpt__task);
132   if (wimpt__options & wimpt_OWIMPEXT)
133     os_swiv(XWimpExt_CloseDown,wimpt__task);
134   wimp_taskclose(wimpt__task);
135 }
136
137 /*----- Screen mode information -------------------------------------------*/
138
139 BOOL wimpt_checkmode(void)
140 {
141   int dummy;
142   int old=wimpt__currentMode;
143   os_byte(135,&dummy,&wimpt__currentMode);
144
145   wimpt__dx=1<<bbc_vduvar(bbc_XEigFactor);
146   wimpt__dy=1<<bbc_vduvar(bbc_YEigFactor);
147   wimpt__bpp=1<<bbc_vduvar(bbc_Log2BPP);
148   wimpt__xwind=(bbc_vduvar(bbc_XWindLimit)+1)*wimpt_dx();
149   wimpt__ywind=(bbc_vduvar(bbc_YWindLimit)+1)*wimpt_dy();
150
151   return (old!=wimpt__currentMode);
152 }
153
154 int wimpt_dx(void)
155 {
156   return (wimpt__dx);
157 }
158
159 int wimpt_dy(void)
160 {
161   return (wimpt__dy);
162 }
163
164 int wimpt_bpp(void)
165 {
166   return (wimpt__bpp);
167 }
168
169 int wimpt_scwidth(void)
170 {
171   return (wimpt__xwind);
172 }
173
174 int wimpt_scheight(void)
175 {
176   return (wimpt__ywind);
177 }
178
179 int wimpt_mode(void)
180 {
181   return (wimpt__currentMode);
182 }
183
184 /*----- Redrawing things --------------------------------------------------*/
185
186 void wimpt_forceredraw(void)
187 {
188   wimp_redrawstr r;
189
190   r.w=-1;
191   r.box.x0=r.box.y0=0;
192   r.box.x1=wimpt__xwind;
193   r.box.y1=wimpt__ywind;
194
195   wimp_force_redraw(&r);
196 }
197
198 void wimpt_redraw(wimpt_redraw_proc p,void *handle)
199 {
200   wimp_eventstr *e=wimpt_last_event();
201   wimp_redrawstr r;
202   BOOL more;
203
204   r.w=e->data.o.w;
205   wimpt_noerr(wimp_redraw_wind(&r,&more));
206   while (more)
207   {
208     if (p)
209       p(&r,handle);
210     if (wimpt__options & wimpt_OSCULPTRIX)
211     {
212       wimpt_noerr(sculptrix_setSpriteArea(resspr_area()));
213       wimpt_noerr(sculptrix_redrawWindow(&r));
214     }
215     if (wimpt__options & wimpt_OINTERFACE)
216       wimpt_noerr(interface_render3dWindow(&r));
217     if (wimpt__options & wimpt_OWIMPEXT)
218       wimpt_noerr(os_swiv(XWimpExt_Redraw,0,&r));
219     wimpt_noerr(wimp_get_rectangle(&r,&more));
220   }
221 }
222
223 /*----- Initialisation ----------------------------------------------------*/
224
225 void wimpt_setOptions(int eor,int bic)
226 {
227   wimpt__options=(wimpt__options & ~bic) ^ eor;
228 }
229
230 int wimpt_options(void)
231 {
232   return (wimpt__options);
233 }
234
235 void wimpt_setMessages(int msg,...)
236 {
237   int i=0;
238   int sz=0;
239   va_list ap;
240
241   if (!msg)
242     return;
243
244   if (wimpt__messages=mem_alloc(256*sizeof(int)),!wimpt__messages)
245   {
246     fprintf(stderr,
247             msgs_lookup("wimptNEMI:Not enough memory to initialise."));
248     exit(1);
249   }
250
251   sz=256;
252   wimpt__messages[i++]=msg;
253   va_start(ap,msg);
254   while (msg)
255   {
256     msg=va_arg(ap,int);
257     if (i==sz)
258     {
259       sz+=64;
260       if (wimpt__messages=mem_reAlloc(wimpt__messages,sz*sizeof(int)),
261           !wimpt__messages)
262       {
263         fprintf(stderr,
264                 msgs_lookup("wimptNEMI:Not enough memory to initialise."));
265         exit(1);
266       }
267     }
268     wimpt__messages[i++]=msg;
269   }
270   va_end(ap);
271
272   if (wimpt__wimpVersion<300)
273     wimpt__wimpVersion=300;
274 }
275
276 void wimpt_wimpversion(int version)
277 {
278   wimpt__wimpVersion=version;
279 }
280
281 int wimpt_getVersion(void)
282 {
283   return (wimpt__wimpVersion);
284 }
285
286 void wimpt_init(char *progname)
287 {
288   os_error *e;
289
290   signal(SIGABRT, _dllEntry(wimpt__signals));
291   signal(SIGFPE, _dllEntry(wimpt__signals));
292   signal(SIGILL, _dllEntry(wimpt__signals));
293   signal(SIGINT, _dllEntry(wimpt__escapeHandler));
294   signal(SIGSEGV, _dllEntry(wimpt__signals));
295   signal(SIGTERM, _dllEntry(wimpt__signals));
296   signal(SIGOSERROR, _dllEntry(wimpt__signals));
297
298   wimpt__name=progname;
299
300   if (!wimpt__wimpVersion)
301   {
302     /* --- Guess the current WIMP version --- */
303
304     switch (bbc_inkey(0xFF00))
305     {
306       case 0xA0:   /* Arthur */
307         fprintf(stderr,
308                 msgs_lookup("wimptARTH:Operating system too old.  Try "
309                                       "upgrading to RISC OS!\n"));
310         exit(1);
311         break;
312       case 0xA1:   /* OS 2.00 */
313       case 0xA2:   /* OS 2.01 */
314         wimpt__wimpVersion=200;
315         break;
316       case 0xA3:   /* OS 3.00 */
317         wimpt__wimpVersion=300;
318         break;
319       case 0xA4:   /* OS 3.10 */
320       default:     /* Anything later */
321         wimpt__wimpVersion=310;
322         break;
323     }
324   }
325
326   if (wimpt__wimpVersion==300 && !wimpt__messages)
327   {
328     /* Set up some sensible default messages for brain-damaged OS */
329     wimpt_setMessages(1,2,3,4,5,6,7,8,9,10,
330                       0x502,0x503,
331                       0x400c0,0x400c1,0x400c9,
332                       0x80140,0x80145,0x80147,
333                       0);
334   }
335
336   if (e=wimp_taskinit(progname,
337                       &wimpt__wimpVersion,
338                       &wimpt__task,
339                       wimpt__messages ?
340                         wimpt__messages :
341                         (int *)-1),
342       e)
343   {
344     fprintf(stderr,
345             msgs_lookup("wimptFTI:Failed to initialise: '%s'"),
346             e->errmess);
347     fprintf(stderr,"\n");
348     exit(1);
349   }
350
351   wimpt_checkmode();
352   atexit(_dllEntry(wimpt__exit));
353
354   /* --- Initialise any extensions --- */
355
356   if (wimpt__options & wimpt_OINTERFACE)
357     wimpt_noerr(interface_initialise(wimpt__task));
358
359   /* --- Handle WimpExtension with care... --- *
360    *
361    * If WimpExtension isn't initialised yet, it will start up its Wimp task,
362    * corrupting the application handle in the process, causing a bad crash
363    * when we return through app__epilogue.
364    */
365
366   if (wimpt__options & wimpt_OWIMPEXT)
367   {
368     #ifndef _dll_NODLL
369       int handle;
370       os_error *err;
371
372       dll_saveHandle(&handle);
373       err=os_swiv(XWimpExt_Initialise,16,wimpt__task,0);
374       dll_restoreHandle(&handle);
375       wimpt_noerr(err);
376     #else
377       wimpt_noerr(os_swiv(XWimpExt_Initialise,16,wimpt__task,0));
378     #endif
379   }
380 }
381
382 char *wimpt_programname(void)
383 {
384   return (wimpt__name);
385 }
386
387 wimp_t wimpt_task(void)
388 {
389   return (wimpt__task);
390 }
391
392 /*----- Error handling ----------------------------------------------------*/
393
394 os_error *wimpt_complain(os_error *e)
395 {
396   if (e)
397     werr_error(1,"%s",e->errmess);
398   return (e);
399 }
400
401 void wimpt_noerr(os_error *e)
402 {
403   if (e)
404     exception_generate("%s",e->errmess);
405 }
406
407 void wimpt_reporterror(os_error *e, wimp_errflags f)
408 {
409   werr_error((f & 3==3) ? 2 : 1,"%s",e->errmess);
410 }
411
412 /*----- Polling the WIMP --------------------------------------------------*/
413
414 os_error *wimpt_poll(wimp_emask mask,wimp_eventstr *result)
415 {
416   visdelay_state vs;
417   os_error *e=0;
418   int nextAlarm;
419   BOOL alarming;
420   int timeNow;
421
422   if (wimpt__fakeWaiting /* && !(mask & (1<<wimpt__fakeEvent.e)) */ )
423   {
424     *result=wimpt__fakeEvent;
425     wimpt__fakeWaiting=0;
426     wimpt__lastEvent=wimpt__fakeEvent;
427     return (0);
428   }
429
430   alarming=alarm_next(&nextAlarm);
431
432   if (wimpt__options & wimpt_OWIMPEXT)
433     os_swiv(XWimpExt_PrePoll);
434
435   vs=visdelay_suspend();
436
437   if (alarming && (mask & wimp_EMNULL))
438     e=wimp_pollidle(mask & ~wimp_EMNULL,result,nextAlarm);
439   else
440   {
441     if ((mask & wimp_EMNULL) || !wimpt__pollingTime)
442       e=wimp_poll(mask,result);
443     else
444     {
445       timeNow=alarm_timenow()+wimpt__pollingTime;
446       if (alarming && nextAlarm<timeNow)
447         timeNow=nextAlarm;
448       e=wimp_pollidle(mask,result,timeNow);
449     }
450   }
451
452   visdelay_resume(vs);
453   flex_reduce();
454
455   if (wimpt__options & wimpt_OWIMPEXT)
456   {
457     wimpt_noerr(os_swi3r(XWimpExt_Action,wimpt__task,
458                                          (int)&result->data,
459                                          result->e,
460                                          (int *)&result->e,0,0));
461   }
462   if (wimpt__options & wimpt_OINTERFACE)
463     interface_poll(result,wimpt__task);
464
465   wimpt__lastEvent=*result;
466
467   switch (result->e)
468   {
469     case wimp_ESEND:
470     case wimp_ESENDWANTACK:
471       if (result->data.msg.hdr.action==0x400C1)
472       {
473         wimpt__justChangedMode=TRUE;
474         wimpt_checkmode();
475       }
476       else
477         wimpt__justChangedMode=FALSE;
478       break;
479     case wimp_EOPEN:
480       /* Could be part of the mode change */
481       break;
482     case wimp_EPTRLEAVE:
483       caretPtr__pointer(FALSE);
484       wimpt__justChangedMode=FALSE;
485       break;
486     case wimp_EPTRENTER:
487       caretPtr__pointer(TRUE);
488       wimpt__justChangedMode=FALSE;
489       break;
490     default:
491       wimpt__justChangedMode=FALSE;
492       break;
493   }
494   return(e);
495 }
496
497 BOOL wimpt_justChangedMode(void)
498 {
499   return (wimpt__justChangedMode);
500 }
501
502 int wimpt_pollingTime(int new)
503 {
504   int temp=wimpt__pollingTime;
505   if (new>=0)
506     wimpt__pollingTime=new;
507   return (temp);
508 }
509
510 void wimpt_fake_event(wimp_eventstr * e)
511 {
512   if (!wimpt__fakeWaiting)
513   {
514     wimpt__fakeWaiting=TRUE;
515     wimpt__fakeEvent=*e;
516   }
517 }
518
519 wimp_eventstr *wimpt_last_event(void)
520 {
521   return (&wimpt__lastEvent);
522 }
523
524 int wimpt_last_event_was_a_key(void)
525 {
526   return (wimpt__lastEvent.e == wimp_EKEY);
527 }
528
529 /*----- String width ------------------------------------------------------*/
530
531 /*
532  * int wimpt_stringWidth(char *s)
533  *
534  * Use
535  *  Determines the width of a string in OS units, taking into account the
536  *  fact that it may be represented in a WIMP anti-aliased font.
537  *
538  * Parameters
539  *  char *s == pointer to the string to font the length of
540  *
541  * Returns
542  *  The width of the string in OS units
543  */
544
545 int wimpt_stringWidth(char *s)
546 {
547   font f;
548   font_string fs;
549
550   if (wimp_readsysinfo(wimp_IFONTHANDLE,&f) || !f)
551     return (strlen(s)*16);
552
553   font_setfont(f);
554   fs.s=s;
555   font_converttopoints(1000,1000,&fs.x,&fs.y);
556   fs.split=0;
557   fs.term=strlen(s)+1;
558   font_strwidth(&fs);
559   font_converttoos(fs.x,0,&fs.x,&fs.y);
560   return (fs.x);
561 }