chiark / gitweb /
JPEG support and other fixes from Nick Clark
[ssr] / StraySrc / Libraries / Sapphire / s / repeater
1 ;
2 ; repeater.s
3 ;
4 ; Handles things that should auto-repeat
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 ;----- Standard header ------------------------------------------------------
28
29                 GET     libs:header
30                 GET     libs:swis
31
32                 GET     libs:stream
33
34 ;----- External dependencies ------------------------------------------------
35
36                 GET     sapphire:divide
37                 GET     sapphire:idle
38                 GET     sapphire:sapphire
39                 GET     sapphire:win
40
41 ;----- Main code ------------------------------------------------------------
42
43                 AREA    |Sapphire$$Code|,CODE,READONLY
44
45 ; --- repeater ---
46 ;
47 ; On entry:     R0 == pointer to routine to call
48 ;               R1 == R10 value to pass to routine
49 ;               R2 == R12 value to pass to routine
50 ;
51 ; On exit:      --
52 ;
53 ; Use:          Calls a routine (a) immediately, (b) after the configured
54 ;               keyboard delay rate and (c) repeatedly after the configured
55 ;               keyboard repeat rate.  Calls stop when the user stops
56 ;               pressing the mouse button.
57 ;
58 ;               The routine is called with R0 containing either the number
59 ;               of missed calls since the last one (normally this is 1) --
60 ;               this is intended to be used to implement a kind of buffering
61 ;               of repeats if the operation being performed is a lengthy one
62 ;               -- and with 0 to indicate that the operation is now
63 ;               completed.
64
65                 EXPORT  repeater
66 repeater        ROUT
67
68                 STMFD   R13!,{R0-R4,R12,R14}    ;Save some registers
69                 WSPACE  rpt__wSpace             ;Locate my workspace nicely
70
71                 ; --- Set up the workspace ---
72
73                 STMIA   R12,{R0-R2}             ;Save the call information
74                 MOV     R0,#1                   ;This is the first call
75                 BL      rpt__call               ;Call the user's routine
76
77                 ; --- Now we have to work out the repeat times ---
78
79                 MOV     R0,#196                 ;Read keybd repeat and delay
80                 MOV     R1,#0                   ;Set up registers to read...
81                 MOV     R2,#255                 ;... without corrupting
82                 SWI     OS_Byte                 ;Read the autorepeat info
83                 STR     R2,rpt__repeat          ;Save repeat rate in wspace
84                 MOVS    R4,R1                   ;Look after delay time
85
86                 MOVEQ   R0,#0                   ;If no delay, end op now
87                 BLEQ    rpt__call               ;Tell client it's over
88                 BEQ     %90repeater             ;And exit nicely
89
90                 ; --- Set up the drag box ---
91                 ;
92                 ; We do this for several reasons:
93                 ;
94                 ; * It informs us when the mouse button is finally released.
95                 ;
96                 ; * It keeps the mouse pointer bounded for the duration.
97                 ;
98                 ; * It stops things going wrong if for some reason the mouse
99                 ;   gets unbounded (e.g. by doing a Wimp_SetMode).
100
101                 SUB     R13,R13,#56             ;Get a drag box block
102                 MOV     R1,R13                  ;Point to the block
103                 SWI     Wimp_GetPointerInfo     ;Get the current mouse state
104                 LDMIA   R13,{R2,R3}             ;Read mouse position
105                 MOV     R1,#7                   ;This drag is a user type
106                 STMIA   R13,{R0,R1}             ;Save them in the block
107                 ADD     R14,R13,#24             ;Point to parent rectangle
108                 STMIA   R14!,{R2,R3}            ;Save the current mouse...
109                 STMIA   R14!,{R2,R3}            ;... posn to lock in place
110                 MOV     R1,R13                  ;Point to the block
111                 SWI     Wimp_DragBox            ;Start the drag operation
112                 ADD     R13,R13,#56             ;Restore the stack now
113
114                 ; --- Now set up the unknown handler to catch the drag ---
115
116                 ADR     R0,rpt__ukEvents        ;Point to my handler routine
117                 MOV     R1,#0                   ;Don't care about R4
118                 MOV     R2,#0                   ;Nothing to pass in R10
119                 MOV     R3,R12                  ;Pass workspace in R12
120                 BL      win_unknownHandler      ;Add the handler
121                 BVS     %90repeater             ;If it failed, skip to end
122
123                 ; --- Set up the alarm for the first repeat ---
124
125                 SWI     OS_ReadMonotonicTime    ;Read the current time
126                 ADD     R0,R4,R0                ;Add time to keyboard delay
127                 STR     R0,rpt__alarm           ;Store the time of the alarm
128                 STR     R0,rpt__last            ;And this is correct time
129                 ADR     R1,rpt__alarms          ;Point to my alarm handler
130                 MOV     R2,#0                   ;Nothing to pass in R10
131                 MOV     R3,R12                  ;Pass workspace in R12
132                 BL      idle_setAlarm           ;Set the alarm call then
133
134 90repeater      LDMFD   R13!,{R0-R4,R12,PC}^    ;Return to caller if all OK
135
136                 LTORG
137
138 ; --- rpt__call ---
139 ;
140 ; On entry:     R0 == value to pass client in R0
141 ;
142 ; On exit:      --
143 ;
144 ; Use:          Calls client routine.
145
146 rpt__call       ROUT
147
148                 STMFD   R13!,{R1,R10,R12,R14}   ;Save some registers
149                 LDMIA   R12,{R1,R10,R12}        ;Load client's routine data
150                 MOV     R14,PC                  ;Set up return address
151                 MOV     PC,R1                   ;And call the routine
152                 LDMFD   R13!,{R1,R10,R12,PC}^   ;And return to caller
153
154                 LTORG
155
156 ; --- rpt__alarms ---
157 ;
158 ; On entry:     --
159 ;
160 ; On exit:      --
161 ;
162 ; Use:          Handles alarms while a repeater is in operation.
163
164 rpt__alarms     ROUT
165
166                 STMFD   R13!,{R0-R4,R14}        ;Save some registers
167
168                 LDR     R0,rpt__routine         ;Load the current addr
169                 CMP     R0,#-1                  ;Have we ended?
170                 BEQ     %70rpt__alarms          ;Yes -- do special things
171
172                 ; --- Things go odd if zero repeat rate set up ---
173
174                 LDR     R2,rpt__repeat          ;Load current repeat rate
175                 CMP     R2,#0                   ;Is it currently zero?
176                 BEQ     %50rpt__alarms          ;Yes -- handle specially
177
178                 ; --- Work out how many we missed ---
179                 ;
180                 ; We also add in the next alarm, and resynch to the
181                 ; expected time.
182
183                 SWI     OS_ReadMonotonicTime    ;Get the current time
184                 MOV     R4,R0                   ;Look after this value
185                 LDR     R3,rpt__last            ;Get the time I was expecting
186                 SUB     R0,R4,R3                ;Find how late I was called
187                 MOV     R1,R2                   ;Get the repeat rate ready
188                 BL      divide                  ;Find out how many I missed
189                 ADD     R0,R0,#1                ;Add in one extra repeat
190                 BL      rpt__call               ;Call client code again
191                 SUB     R14,R2,R1               ;Work out next repeat time
192                 ADD     R0,R4,R14               ;Add that to current time
193                 STR     R0,rpt__last            ;This is the new alarm time
194
195                 SWI     OS_ReadMonotonicTime    ;Get the current time
196                 MOV     R4,R0                   ;Look after this now
197                 SUB     R0,R4,R3                ;Find how late I was called
198                 MOV     R1,R2                   ;Get the repeat rate ready
199                 BL      divide                  ;Find out how many I missed
200                 SUB     R14,R2,R1               ;Work out next repeat time
201                 ADD     R0,R4,R14               ;Add that to current time
202                 STR     R0,rpt__alarm           ;This is the new alarm time
203
204                 ADR     R1,rpt__alarms          ;Point to me again
205                 MOV     R2,R10                  ;Pass the dialogue handle
206                 MOV     R3,R12                  ;And my workspace pointer
207                 BL      idle_setAlarm           ;Add in next alarm handler
208
209                 LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
210
211                 ; --- If no repeat rate, stop the whole operation ---
212
213 50rpt__alarms   MOV     R0,#1                   ;Just send one call
214                 BL      rpt__call               ;Send that off to the client
215                 MOV     R1,#-1                  ;Tell Wimp to stop dragging
216                 SWI     Wimp_DragBox            ;Send that off nicely
217                 ADR     R0,rpt__ukEvents        ;Point to the unknown handler
218                 MOV     R1,#0                   ;I'm passing 0 in R4
219                 MOV     R2,#0                   ;And 0 in R10 too
220                 MOV     R3,R12                  ;But R12 is my workspace
221                 BL      win_removeUnknownHandler ;Remove it from the list
222                 MOV     R0,#0                   ;Tell client it's all over
223                 BL      rpt__call               ;Finish that off nicely
224                 LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
225
226                 ; --- The repeater was ended before its time ---
227                 
228 70rpt__alarms   MOV     R1,#-1                  ;Tell Wimp to stop dragging
229                 SWI     Wimp_DragBox            ;Send that off nicely
230                 ADR     R0,rpt__ukEvents        ;Point to the unknown handler
231                 MOV     R1,#0                   ;I'm passing 0 in R4
232                 MOV     R2,#0                   ;And 0 in R10 too
233                 MOV     R3,R12                  ;But R12 is my workspace
234                 BL      win_removeUnknownHandler ;Remove it from the list
235                 LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
236
237                 LTORG
238
239 ; --- rpt_end ---
240 ;
241 ; On entry:     --
242 ;
243 ; On exit:      --
244 ;               
245 ; Use:          Ends a repeater before the drag is released. No final
246 ;               0 is sent to the handler.
247
248                 EXPORT  rpt_end
249 rpt_end         ROUT
250
251                 STMFD   R13!,{R12,R14}          ;Stack registers
252                 WSPACE  rpt__wSpace             ;Locate my workspace nicely
253                 MOV     R14,#-1                 ;Get a silly routine value
254                 STR     R14,rpt__routine        ;Store in routine address
255                 LDMFD   R13!,{R12,PC}^          ;Return to caller
256                 
257                 LTORG
258
259 ; --- rpt__ukEvents ---
260 ;
261 ; On entry:     R0 == event code
262 ;               R1 == pointer to event information
263 ;
264 ; On exit:      --
265 ;
266 ; Use:          Picks up end-of-drag events from the WindowMangler and
267 ;               diables the alarm for the repeat op.
268
269 rpt__ukEvents   ROUT
270
271                 CMP     R0,#7                   ;Is this a drag event?
272                 MOVNES  PC,R14                  ;No -- return right away
273                 STMFD   R13!,{R0-R3,R14}        ;Save some registers away
274
275                 ; --- Remove the alarm and unknown handlers ---
276
277                 LDR     R0,rpt__alarm           ;Get the time it's due for
278                 ADR     R1,rpt__alarms          ;Point to my alarms routine
279                 MOV     R2,#0                   ;I passed 0 as it's R10
280                 MOV     R3,R12                  ;Get its R12 value
281                 BL      idle_removeAlarm        ;And remove it from the list
282                 ADR     R0,rpt__ukEvents        ;Point to the unknown handler
283                 MOV     R1,#0                   ;I'm passing 0 in R4
284                 BL      win_removeUnknownHandler ;Remove it from the list
285
286                 ; --- Tell the client it's over ---
287
288                 MOV     R0,#0                   ;Say this is it then
289                 BL      rpt__call               ;Send the event over
290                 LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
291
292                 LTORG
293
294 rpt__wSpace     DCD     0
295
296 ;----- Workspace ------------------------------------------------------------
297
298                 ^       0,R12
299 rpt__wStart     #       0
300
301 rpt__routine    #       4                       ;Client routine to call
302 rpt__R10        #       4                       ;R10 value to pass routine
303 rpt__R12        #       4                       ;R12 value to pass routine
304 rpt__repeat     #       4                       ;Current autorepeat rate
305 rpt__alarm      #       4                       ;Time for next alarm pop
306 rpt__last       #       4                       ;When last pop expected
307
308 rpt__wSize      EQU     {VAR}-rpt__wStart
309
310                 AREA    |Sapphire$$LibData|,CODE,READONLY
311
312                 DCD     rpt__wSize
313                 DCD     rpt__wSpace
314                 DCD     0
315                 DCD     0
316
317 ;----- That's all, folks ----------------------------------------------------
318
319                 END