Initial revision
[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