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 }