chiark / gitweb /
JPEG support and other fixes from Nick Clark
[ssr] / StraySrc / Libraries / Sapphire / s / nopoll
1 ;
2 ; nopoll.s
3 ;
4 ; Handling nonpolling dialogue boxes (MDW)
5 ;
6 ; © 1994-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's Sapphire library.
12 ;
13 ; Sapphire 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 ; Sapphire 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 Sapphire.  If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27 ;----- Some notes before we start -------------------------------------------
28 ;
29 ; This is utterly different to the STEEL nopoll.  It nabs a prehandler, and
30 ; then uses it to direct fake events at the nonpolling window, which it then
31 ; can pick up and do whatever it wants with.  Fake events generated so far:
32 ;
33 ;   Click -- for any click on an icon
34 ;   Key -- for *only* Escape and Return -- we can't risk people using
35 ;      Wimp_ProcessKey or strange caret-moving calls
36 ;   Redraw -- when the thing gets opened, we fake a redraw for it, so that
37 ;      it gets painted nicely on the screen
38 ;
39 ; Basically, you get much more control over the dialogue box than you would
40 ; with STEEL, but at the small price of a little more responsibility for
41 ; what actually happens.  So your nonpolling dialogue boxes can be that much
42 ; cleverer!
43
44 ;----- Standard header ------------------------------------------------------
45
46                 GET     libs:header
47                 GET     libs:swis
48
49 ;----- External dependencies ------------------------------------------------
50
51                 GET     sapphire:defHandler
52                 GET     sapphire:event
53                 GET     sapphire:hour
54                 GET     sapphire:sapphire
55                 GET     sapphire:screen
56
57 ;----- Main code ------------------------------------------------------------
58
59                 AREA    |Sapphire$$Code|,CODE,READONLY
60
61 ; --- nopoll_open ---
62 ;
63 ; On entry:     R0 == a window handle to take over
64 ;
65 ; On exit:      --
66 ;
67 ; Use:          Sets up the window with the given handle to be a nonpolling
68 ;               dialogue box.  The window must already be open on the screen.
69 ;               This call will force it to be painted on the screen, and
70 ;               then start faking events for it.
71
72                 EXPORT  nopoll_open
73 nopoll_open     ROUT
74
75                 STMFD   R13!,{R12,R14}          ;Save some registers
76                 WSPACE  nopoll__wSpace          ;Load my workspace pointer
77
78                 ; --- Make sure there's only one window ---
79
80                 LDR     R14,nopoll__window      ;Load the nonpolling window
81                 CMP     R14,#0                  ;Is it nonzero?
82                 LDMNEFD R13!,{R12,PC}^          ;Yes -- ignore the new one
83
84                 ; --- Remember this window handle ---
85
86                 STR     R0,nopoll__window       ;Store this handle away
87                 LDR     R14,nopoll__flags       ;Load my flags word
88                 ORR     R14,R14,#npFlag__redraw ;Window needs painting
89                 STR     R14,nopoll__flags       ;Store flags away again
90                 TST     R0,#1<<31               ;Is the top bit set?
91                 LDMNEFD R13!,{R12,PC}^          ;Yes -- do nothing else
92
93                 ; --- Now read the initial mouse state ---
94
95                 STMFD   R13!,{R0-R6}            ;Save some more registers
96                 SWI     OS_Mouse                ;Read the mouse position
97                 STR     R2,nopoll__buttons      ;Store the button state away
98
99                 ; --- Read the window position ---
100
101                 LDR     R0,[R13,#0]             ;Reread the window handle
102                 SUB     R13,R13,#36             ;Make space for window blk
103                 STR     R0,[R13,#0]             ;Store handle in the block
104                 MOV     R1,R13                  ;Point to the block
105                 SWI     Wimp_GetWindowState     ;Get the window information
106
107                 ; --- Remember the origin position ---
108
109                 LDMIB   R13,{R1-R6}             ;Load the coordinates out
110                 SUB     R5,R1,R5                ;Get the x origin position
111                 SUB     R6,R4,R6                ;Get the y origin position
112                 ADR     R14,nopoll__ox          ;Point to the origin cache
113                 STMIA   R14,{R5,R6}             ;Store these values away
114
115                 ; --- Constrain the mouse ---
116
117                 BL      screen_getInfo          ;Get the screen information
118                 ADD     R0,R0,#screen_dx        ;Point to the pixel sizes
119                 LDMIA   R0,{R5,R6}              ;Load the pixel sizes
120                 SUB     R1,R1,R5                ;Knock a pixel off the left
121                 SUB     R2,R2,R6                ;And off the bottom
122
123                 ; --- Build the constrain block ---
124                 ;
125                 ; We build the parameter block in registers using lots of
126                 ; barrel shifting and then stuff it in the stack.  This is
127                 ; much quicker and also takes less space.  We assume that
128                 ; all the coordinates are two bytes wide already.
129
130                 MOV     R0,#1                   ;Subreason code
131                 ORR     R0,R0,R1,LSL #8         ;Move in left hand side
132                 ORR     R0,R0,R2,LSL #24        ;Move in the bottom byte
133                 MOV     R1,R2,LSR #8            ;Get top byte of bottom edge
134                 ORR     R1,R1,R3,LSL #8         ;Get right hand side in
135                 ORR     R1,R1,R4,LSL #24        ;Get bottom byte of top edge
136                 MOV     R2,R4,LSR #8            ;And the top byte of top edge
137                 STMFD   R13!,{R0-R2}            ;Save them on the stack
138                 MOV     R0,#21                  ;OS_Word mouse operations
139                 MOV     R1,R13                  ;Point to the block
140                 SWI     XOS_Word                ;Perform the constrain
141
142                 ADD     R13,R13,#48             ;Return the block nicely
143                 LDMFD   R13!,{R0-R6,R12,PC}^    ;Return to caller now
144
145                 LTORG
146
147 ; --- nopoll_close ---
148 ;
149 ; On entry:     R0 == return value for nopoll_process (can be anything)
150 ;
151 ; On exit:      --
152 ;
153 ; Use:          Tells nopoll that the nonpolling window has been killed,
154 ;               and hence that polling can return to normal again.  You can
155 ;               specify a return value to give from nopoll_process (if that
156 ;               system is being used).
157
158                 EXPORT  nopoll_close
159 nopoll_close    ROUT
160
161                 STMFD   R13!,{R0-R4,R12,R14}    ;Save some registers
162                 WSPACE  nopoll__wSpace          ;Find my workspace
163                 STR     R0,nopoll__return       ;Save the return value away
164
165                 ; --- Clear the window handle ---
166
167                 LDR     R0,nopoll__window       ;Load the old window
168                 MOV     R14,#0                  ;No nonpolling window
169                 STR     R14,nopoll__window      ;Store it over the window
170                 TST     R0,#1<<31               ;Is the top bit set?
171                 LDMNEFD R13!,{R0-R4,R12,PC}^    ;Yes -- do nothing else then
172
173                 ; --- Now release the mouse pointer ---
174
175                 BL      screen_getInfo          ;Read the screen information
176                 ADD     R0,R0,#screen_width     ;Point to the right bit
177                 LDMIA   R0,{R1-R4}              ;Load screen and pixel sizes
178                 SUB     R3,R1,R3                ;Reduce screen width by 1
179                 SUB     R4,R2,R4                ;Reduce screen height by 1
180
181                 MOV     R0,#&00000001           ;Bottom word for constrain
182                 MOV     R1,R3,LSL #8            ;Shift the width word in
183                 ORR     R1,R1,R4,LSL #24        ;Move bottom byte of width in
184                 MOV     R2,R4,LSR #8            ;And get top byte in R2
185                 STMFD   R13!,{R0-R2}            ;Create the block on stack
186                 MOV     R1,R13                  ;Point to the block
187                 MOV     R0,#21                  ;Reason code
188                 SWI     XOS_Word                ;Do the constraining
189
190                 ADD     R13,R13,#12             ;Skip past the OS_Word block
191                 LDMFD   R13!,{R0-R4,R12,PC}^    ;Return to caller
192
193                 LTORG
194
195 ; --- nopoll_init ---
196 ;
197 ; On entry:     --
198 ;
199 ; On exit:      --
200 ;
201 ; Use:          Initialises nopoll so it can be used.
202
203                 EXPORT  nopoll_init
204 nopoll_init     ROUT
205
206                 STMFD   R13!,{R0,R1,R12,R14}    ;Save some registers
207
208                 ; --- Make sure I'm not already going ---
209
210                 WSPACE  nopoll__wSpace          ;Load my workspace pointer
211                 LDR     R14,nopoll__flags       ;Load my flags word
212                 TST     R14,#npFlag__inited     ;Am I initialised yet?
213                 MOV     R0,#0                   ;Zero window handle
214                 STR     R0,nopoll__window       ;No nonpolling window yet
215                 LDMNEFD R13!,{R0,R1,R12,PC}^    ;Yes -- return right now
216
217                 ; --- Register my prefilter nicely ---
218
219                 BL      event_init              ;Initialise the event system
220                 ADR     R0,nopoll__filter       ;Point to my filter routine
221                 MOV     R1,R12                  ;Pass my workspace pointer
222                 BL      event_preFilter ;Register the prefilter
223                 LDMFD   R13!,{R0,R1,R12,PC}^    ;Return to caller
224
225 nopoll__wSpace  DCD     0
226
227                 LTORG
228
229 ; --- nopoll__filter ---
230 ;
231 ; On entry:     R0 == an event mask
232 ;               R1 == pointer to event block
233 ;               R2 == earliest time to return with null event
234 ;               R3 == pointer to poll word if any
235 ;
236 ; On exit:      Carry clear and registers preserved, or carry set and:
237 ;
238 ;               R0 == WIMP event code
239 ;               R1 preserved, block updated
240 ;
241 ; Use:          Generates WIMP-like events from the nonpolling window.
242
243 nopoll__filter  ROUT
244
245                 ; --- Pass on quickly if nothing to do ---
246
247                 STMFD   R13!,{R14}              ;Just save the link register
248                 LDR     R14,nopoll__window      ;Is there a nonpolling window
249                 CMP     R14,#0                  ;Just check it's nonzero
250                 LDMEQFD R13!,{PC}^              ;No -- return right now
251
252                 ; --- Now dispatch redraw events if necessary ---
253
254                 STMFD   R13!,{R10}              ;Save another register
255                 BIC     R10,R14,#1<<31          ;Look after the window handle
256                 LDR     R14,nopoll__flags       ;Load my flags word
257                 TST     R14,#npFlag__redraw     ;Do I have to fake a redraw?
258                 BEQ     %00nopoll__filter       ;No -- skip ahead
259
260                 BIC     R14,R14,#npFlag__redraw ;Clear the flag
261                 STR     R14,nopoll__flags       ;Store the new flags word
262                 MOV     R0,#1                   ;Pass a redraw reason code
263                 STR     R10,[R1,#0]             ;Store window handle in block
264                 LDMFD   R13!,{R10,R14}          ;Load the registers back
265                 ORRS    PC,R14,#C_flag          ;Return the fake event
266
267                 ; --- Find out if a key was pressed ---
268
269 00              STMFD   R13!,{R1-R7}            ;Save some more registers
270
271                 SUB     R13,R13,#8              ;Make space for hourglass blk
272                 MOV     R0,R13                  ;Point to the block
273                 BL      hour_suspend            ;Turn hourglass off a while
274
275 01              MOV     R0,#&81                 ;Read keyboard status
276                 MOV     R1,#0                   ;No delay on key reading
277                 MOV     R2,#0                   ;No delay on key reading
278                 SWI     OS_Byte                 ;Read the key value
279                 CMP     R1,#&0D                 ;Was Return pressed?
280                 CMPNE   R1,#&1B                 ;Or was it Escape?
281                 BNE     %10nopoll__filter       ;No -- handle mouse buttons
282
283                 ; --- Build a dummy caret record in the block ---
284
285                 MOV     R0,R13                  ;Point to hourglass block
286                 BL      hour_resume             ;Restore old hourglass state
287                 ADD     R13,R13,#8              ;And restore the stack ptr
288
289                 MOV     R0,R1
290                 LDMFD   R13!,{R1}               ;Restore the Wimp block ptr
291                 STR     R10,[R1,#0]             ;Store window handle away
292                 STR     R0,[R1,#24]             ;Save the key number too
293                                                 ;Don't bother with the rest
294                 MOV     R0,#8                   ;Fake a key event
295                 LDMFD   R13!,{R2-R7,R10,R14}    ;Restore registers
296                 ORRS    PC,R14,#C_flag          ;And fake the event
297
298                 ; --- Read the mouse status ---
299
300 10              SWI     OS_Mouse                ;Read the mouse status
301                 LDR     R14,nopoll__buttons     ;Read the old button state
302                 STR     R2,nopoll__buttons      ;Store new button state
303                 BIC     R2,R2,R14               ;Leave only newly clicked
304                 BICS    R2,R2,#2                ;And clear the menu button
305                 BEQ     %01nopoll__filter       ;If nothing clicked, loop
306
307                 LDR     R4,[R13,#8]             ;Load the Wimp block pointer
308                 STMIA   R4,{R0-R2,R10,R12,R14}  ;Save the registers away
309
310                 ; --- Now find which icon got clicked ---
311
312                 ADR     R14,nopoll__ox          ;Point to the origin coords
313                 LDMIA   R14,{R6,R7}             ;Load them into registers
314                 SUB     R6,R0,R6                ;Convert mouse coords to...
315                 SUB     R7,R1,R7                ;... window-relative ones
316                 SUB     R13,R13,#40             ;Create an icon block
317                 STR     R10,[R13,#0]            ;Save the window handle in it
318                 MOV     R10,#-1                 ;No icons found yet
319                 MOV     R5,#0                   ;Start searching from icon 0
320
321                 ; --- Loop through the icons nicely now ---
322
323 20              STR     R5,[R13,#4]             ;Store it in the block
324                 MOV     R1,R13                  ;Point to my icon block
325                 SWI     Wimp_GetIconState       ;Get the icon information
326                 LDR     R14,[R13,#24]           ;Load the icon flags out
327                 CMP     R14,#&00800000          ;Is it deleted-only?
328                 BEQ     %30nopoll__filter       ;Yes -- we've scanned 'em all
329                 EOR     R14,R14,#&00DF0000      ;Toggle deleted, shaded, ESG
330                 TST     R14,#&00800000          ;Is it deleted?
331                 TSTNE   R14,#&00400000          ;Is it shaded?
332                 TSTNE   R14,#&001F0000          ;Or is the ESG all 1s?
333                 ADDEQ   R5,R5,#1                ;Check the next icon along
334                 BEQ     %20nopoll__filter       ;Yes -- skip this icon
335
336                 ADD     R1,R13,#8               ;Point to icon coordinates
337                 LDMIA   R1,{R0-R3}              ;Load the icon coordinates
338                 CMP     R0,R6
339                 CMPLE   R1,R7
340                 CMPLE   R6,R2
341                 CMPLT   R7,R3
342                 MOVLT   R10,R5                  ;If over icon, remember no.
343
344                 ADD     R5,R5,#1                ;Check the next icon along
345                 B       %20nopoll__filter       ;And carry on
346
347                 ; --- Return a fake mouse click event ---
348
349 30              ADD     R13,R13,#40             ;Recover the icon block
350                 MOV     R0,R13                  ;Point to hourglass block
351                 BL      hour_resume             ;Restore hourglass state
352                 ADD     R13,R13,#8              ;And restore stack block
353                 STR     R10,[R4,#16]            ;Store the icon number away
354                 MOV     R0,#6                   ;Fake a mouse click event
355                 LDMFD   R13!,{R1-R7,R10,R14}    ;Restore loads of registers
356                 ORRS    PC,R14,#C_flag          ;Return to caller at last
357
358                 LTORG
359
360 ; --- nopoll_process ---
361 ;
362 ; On entry:     --
363 ;
364 ; On exit:      R0 == value passed to nopoll_close
365 ;
366 ; Use:          Processes a nonpolling window until it calls nopoll_close.
367 ;               It then returns the value passed to nopoll_close in R0,
368 ;               which can be defined in any way you want.
369 ;
370 ;               Some notes on the use of this routine:
371 ;
372 ;               * It calls event_poll, so any functions that get called
373 ;                 after the normal event_poll don't get called.  Since the
374 ;                 Wimp isn't actually being polled at all, this isn't a
375 ;                 real problem as long as your handlers are registered at the
376 ;                 event filter level or higher (e.g. win event handlers or
377 ;                 even dbox handlers).
378 ;
379 ;               * It uses up an extra 256 bytes of stack for a poll block.
380 ;                 If you think you might miss this stack space, then you'd
381 ;                 better not use this routine.
382 ;
383 ;               * It isn't reentrant, but then again, nor is the rest of the
384 ;                 nopoll system -- you can only have one nonpolling box open
385 ;                 at a time.
386
387                 EXPORT  nopoll_process
388 nopoll_process  ROUT
389
390                 STMFD   R13!,{R1-R3,R12,R14}    ;Save some registers
391                 WSPACE  nopoll__wSpace          ;Locate my workspace
392                 SUB     R13,R13,#256            ;Make a poll block (!)
393
394 00              LDR     R14,nopoll__window      ;Is there a nonpolling window
395                 CMP     R14,#0                  ;Quick check...
396                 BEQ     %10nopoll_process       ;No -- jump ahead then
397                 MOV     R1,R13                  ;Point to the poll block
398                 BL      event_poll              ;Get a dodgy event back
399                 BLCC    defHandler              ;If not handled, handle it
400                 B       %00nopoll_process       ;And loop back again
401
402 10              LDR     R0,nopoll__return       ;Load the return value
403                 ADD     R13,R13,#256            ;Restore the stack pointer
404                 LDMFD   R13!,{R1-R3,R12,PC}^    ;Return to caller again
405
406                 LTORG
407
408 ;----- Workspace ------------------------------------------------------------
409
410                 ^       0,R12
411 nopoll__wStart  #       0
412
413 nopoll__flags   #       4                       ;Various interesting flags
414 nopoll__window  #       4                       ;The nonpolling window handle
415 nopoll__buttons #       4                       ;Button state for icons
416 nopoll__ox      #       4                       ;Window origin x position
417 nopoll__oy      #       4                       ;Window origin y position
418 nopoll__return  #       4                       ;nopoll_process return value
419
420 nopoll__wSize   EQU     {VAR}-nopoll__wStart    ;My workspace size
421
422 npFlag__inited  EQU     (1<<0)                  ;Am I initialised yet?
423 npFlag__redraw  EQU     (1<<1)                  ;Does window need redrawing?
424
425                 AREA    |Sapphire$$LibData|,CODE,READONLY
426
427                 DCD     nopoll__wSize
428                 DCD     nopoll__wSpace
429                 DCD     0
430                 DCD     nopoll_init
431
432 ;----- That's all, folks ----------------------------------------------------
433
434                 END