ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/video_amiga.cpp
Revision: 1.8
Committed: 2000-07-22T18:25:48Z (23 years, 11 months ago) by cebix
Branch: MAIN
Changes since 1.7: +32 -1 lines
Log Message:
- Amiga mouse pointer is hidden inside windowed displays

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * video_amiga.cpp - Video/graphics emulation, AmigaOS specific stuff
3     *
4 cebix 1.3 * Basilisk II (C) 1997-2000 Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include <exec/types.h>
22     #include <intuition/intuition.h>
23     #include <graphics/rastport.h>
24     #include <graphics/gfx.h>
25 cebix 1.7 #include <cybergraphics/cybergraphics.h>
26 cebix 1.1 #include <dos/dostags.h>
27     #include <devices/timer.h>
28     #include <proto/exec.h>
29     #include <proto/dos.h>
30     #include <proto/intuition.h>
31     #include <proto/graphics.h>
32     #include <proto/Picasso96.h>
33 cebix 1.4 #include <proto/cybergraphics.h>
34 cebix 1.1
35     #include "sysdeps.h"
36     #include "main.h"
37     #include "adb.h"
38     #include "prefs.h"
39     #include "user_strings.h"
40     #include "video.h"
41    
42 cebix 1.4 #define DEBUG 0
43 cebix 1.1 #include "debug.h"
44    
45    
46     // Display types
47     enum {
48     DISPLAY_WINDOW,
49     DISPLAY_PIP,
50 cebix 1.6 DISPLAY_SCREEN_P96,
51     DISPLAY_SCREEN_CGFX
52 cebix 1.1 };
53    
54     // Global variables
55     static int32 frame_skip;
56     static int display_type = DISPLAY_WINDOW; // See enum above
57     static struct Screen *the_screen = NULL;
58     static struct Window *the_win = NULL;
59     static struct BitMap *the_bitmap = NULL;
60 cebix 1.8 static UWORD *null_pointer = NULL; // Blank mouse pointer data
61     static UWORD *current_pointer = (UWORD *)-1; // Currently visible mouse pointer data
62 cebix 1.1 static LONG black_pen = -1, white_pen = -1;
63     static struct Process *periodic_proc = NULL; // Periodic process
64    
65     extern struct Task *MainTask; // Pointer to main task (from main_amiga.cpp)
66    
67    
68     // Amiga -> Mac raw keycode translation table
69     static const uint8 keycode2mac[0x80] = {
70     0x0a, 0x12, 0x13, 0x14, 0x15, 0x17, 0x16, 0x1a, // ` 1 2 3 4 5 6 7
71     0x1c, 0x19, 0x1d, 0x1b, 0x18, 0x2a, 0xff, 0x52, // 8 9 0 - = \ inv 0
72     0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x10, 0x20, 0x22, // Q W E R T Y U I
73     0x1f, 0x23, 0x21, 0x1e, 0xff, 0x53, 0x54, 0x55, // O P [ ] inv 1 2 3
74     0x00, 0x01, 0x02, 0x03, 0x05, 0x04, 0x26, 0x28, // A S D F G H J K
75     0x25, 0x29, 0x27, 0x2a, 0xff, 0x56, 0x57, 0x58, // L ; ' # inv 4 5 6
76     0x32, 0x06, 0x07, 0x08, 0x09, 0x0b, 0x2d, 0x2e, // < Z X C V B N M
77     0x2b, 0x2f, 0x2c, 0xff, 0x41, 0x59, 0x5b, 0x5c, // , . / inv . 7 8 9
78     0x31, 0x33, 0x30, 0x4c, 0x24, 0x35, 0x75, 0xff, // SPC BSP TAB ENT RET ESC DEL inv
79     0xff, 0xff, 0x4e, 0xff, 0x3e, 0x3d, 0x3c, 0x3b, // inv inv - inv CUP CDN CRT CLF
80     0x7a, 0x78, 0x63, 0x76, 0x60, 0x61, 0x62, 0x64, // F1 F2 F3 F4 F5 F6 F7 F8
81     0x65, 0x6d, 0x47, 0x51, 0x4b, 0x43, 0x45, 0x72, // F9 F10 ( ) / * + HLP
82     0x38, 0x38, 0x39, 0x36, 0x3a, 0x3a, 0x37, 0x37, // SHL SHR CAP CTL ALL ALR AML AMR
83     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv
84     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv
85     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // inv inv inv inv inv inv inv inv
86     };
87    
88    
89     // Prototypes
90     static void periodic_func(void);
91    
92    
93     /*
94     * Initialization
95     */
96    
97     // Open window
98     static bool init_window(int width, int height)
99     {
100     // Set absolute mouse mode
101     ADBSetRelMouseMode(false);
102    
103     // Open window
104     the_win = OpenWindowTags(NULL,
105     WA_Left, 0, WA_Top, 0,
106     WA_InnerWidth, width, WA_InnerHeight, height,
107     WA_SimpleRefresh, TRUE,
108     WA_NoCareRefresh, TRUE,
109     WA_Activate, TRUE,
110     WA_RMBTrap, TRUE,
111     WA_ReportMouse, TRUE,
112     WA_DragBar, TRUE,
113     WA_DepthGadget, TRUE,
114     WA_SizeGadget, FALSE,
115 cebix 1.2 WA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
116 cebix 1.1 TAG_END
117     );
118     if (the_win == NULL) {
119     ErrorAlert(GetString(STR_OPEN_WINDOW_ERR));
120     return false;
121     }
122    
123     // Create bitmap ("height + 2" for safety)
124     the_bitmap = AllocBitMap(width, height + 2, 1, BMF_CLEAR, NULL);
125     if (the_bitmap == NULL) {
126     ErrorAlert(GetString(STR_NO_MEM_ERR));
127     return false;
128     }
129    
130     // Set VideoMonitor
131     VideoMonitor.mac_frame_base = (uint32)the_bitmap->Planes[0];
132     VideoMonitor.bytes_per_row = the_bitmap->BytesPerRow;
133     VideoMonitor.x = width;
134     VideoMonitor.y = height;
135     VideoMonitor.mode = VMODE_1BIT;
136    
137     // Set FgPen and BgPen
138     black_pen = ObtainBestPenA(the_win->WScreen->ViewPort.ColorMap, 0, 0, 0, NULL);
139     white_pen = ObtainBestPenA(the_win->WScreen->ViewPort.ColorMap, 0xffffffff, 0xffffffff, 0xffffffff, NULL);
140     SetAPen(the_win->RPort, black_pen);
141     SetBPen(the_win->RPort, white_pen);
142     SetDrMd(the_win->RPort, JAM2);
143     return true;
144     }
145    
146     // Open PIP (requires Picasso96)
147     static bool init_pip(int width, int height)
148     {
149     // Set absolute mouse mode
150     ADBSetRelMouseMode(false);
151    
152     // Open window
153     ULONG error = 0;
154     the_win = p96PIP_OpenTags(
155     P96PIP_SourceFormat, RGBFB_R5G5B5,
156     P96PIP_SourceWidth, width,
157     P96PIP_SourceHeight, height,
158 cebix 1.2 P96PIP_ErrorCode, (ULONG)&error,
159 cebix 1.1 WA_Left, 0, WA_Top, 0,
160     WA_InnerWidth, width, WA_InnerHeight, height,
161     WA_SimpleRefresh, TRUE,
162     WA_NoCareRefresh, TRUE,
163     WA_Activate, TRUE,
164     WA_RMBTrap, TRUE,
165     WA_ReportMouse, TRUE,
166     WA_DragBar, TRUE,
167     WA_DepthGadget, TRUE,
168     WA_SizeGadget, FALSE,
169 cebix 1.2 WA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
170     WA_PubScreenName, (ULONG)"Workbench",
171 cebix 1.1 TAG_END
172     );
173     if (the_win == NULL || error) {
174     ErrorAlert(GetString(STR_OPEN_WINDOW_ERR));
175     return false;
176     }
177    
178     // Find bitmap
179 cebix 1.2 p96PIP_GetTags(the_win, P96PIP_SourceBitMap, (ULONG)&the_bitmap, TAG_END);
180 cebix 1.1
181     // Set VideoMonitor
182     VideoMonitor.mac_frame_base = p96GetBitMapAttr(the_bitmap, P96BMA_MEMORY);
183     VideoMonitor.bytes_per_row = p96GetBitMapAttr(the_bitmap, P96BMA_BYTESPERROW);
184     VideoMonitor.x = width;
185     VideoMonitor.y = height;
186     VideoMonitor.mode = VMODE_16BIT;
187     return true;
188     }
189    
190 cebix 1.6 // Open Picasso96 screen
191     static bool init_screen_p96(ULONG mode_id)
192 cebix 1.1 {
193     // Set relative mouse mode
194     ADBSetRelMouseMode(true);
195    
196 cebix 1.6 // Check if the mode is one we can handle
197     uint32 depth = p96GetModeIDAttr(mode_id, P96IDA_DEPTH);
198     uint32 format = p96GetModeIDAttr(mode_id, P96IDA_RGBFORMAT);
199    
200     switch (depth) {
201     case 8:
202     VideoMonitor.mode = VMODE_8BIT;
203     break;
204     case 15:
205     case 16:
206     if (format != RGBFB_R5G5B5) {
207     ErrorAlert(GetString(STR_WRONG_SCREEN_FORMAT_ERR));
208     return false;
209     }
210     VideoMonitor.mode = VMODE_16BIT;
211     break;
212     case 24:
213     case 32:
214     if (format != RGBFB_A8R8G8B8) {
215     ErrorAlert(GetString(STR_WRONG_SCREEN_FORMAT_ERR));
216     return false;
217     }
218     VideoMonitor.mode = VMODE_32BIT;
219     break;
220     default:
221     ErrorAlert(GetString(STR_WRONG_SCREEN_DEPTH_ERR));
222     return false;
223     }
224    
225     // Yes, get width and height
226     uint32 width = p96GetModeIDAttr(mode_id, P96IDA_WIDTH);
227     uint32 height = p96GetModeIDAttr(mode_id, P96IDA_HEIGHT);
228    
229     VideoMonitor.x = width;
230     VideoMonitor.y = height;
231    
232     // Open screen
233     the_screen = p96OpenScreenTags(
234     P96SA_DisplayID, mode_id,
235     P96SA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
236     P96SA_Quiet, TRUE,
237     P96SA_NoMemory, TRUE,
238     P96SA_NoSprite, TRUE,
239     P96SA_Exclusive, TRUE,
240     TAG_END
241     );
242     if (the_screen == NULL) {
243     ErrorAlert(GetString(STR_OPEN_SCREEN_ERR));
244 cebix 1.1 return false;
245     }
246    
247 cebix 1.6 // Open window
248     the_win = OpenWindowTags(NULL,
249     WA_Left, 0, WA_Top, 0,
250     WA_Width, width, WA_Height, height,
251     WA_NoCareRefresh, TRUE,
252     WA_Borderless, TRUE,
253     WA_Activate, TRUE,
254     WA_RMBTrap, TRUE,
255     WA_ReportMouse, TRUE,
256     WA_CustomScreen, (ULONG)the_screen,
257     TAG_END
258     );
259     if (the_win == NULL) {
260     ErrorAlert(GetString(STR_OPEN_WINDOW_ERR));
261     return false;
262     }
263    
264     // Set VideoMonitor
265     ScreenToFront(the_screen);
266     VideoMonitor.mac_frame_base = p96GetBitMapAttr(the_screen->RastPort.BitMap, P96BMA_MEMORY);
267     VideoMonitor.bytes_per_row = p96GetBitMapAttr(the_screen->RastPort.BitMap, P96BMA_BYTESPERROW);
268     return true;
269     }
270    
271     // Open CyberGraphX screen
272     static bool init_screen_cgfx(ULONG mode_id)
273     {
274     // Set relative mouse mode
275     ADBSetRelMouseMode(true);
276 cebix 1.4
277 cebix 1.1 // Check if the mode is one we can handle
278 cebix 1.6 uint32 depth = GetCyberIDAttr(CYBRIDATTR_DEPTH, mode_id);
279     uint32 format = GetCyberIDAttr(CYBRIDATTR_PIXFMT, mode_id);
280 cebix 1.4
281 cebix 1.1 switch (depth) {
282     case 8:
283     VideoMonitor.mode = VMODE_8BIT;
284     break;
285     case 15:
286     case 16:
287 cebix 1.6 if (format != PIXFMT_RGB16) {
288 cebix 1.1 ErrorAlert(GetString(STR_WRONG_SCREEN_FORMAT_ERR));
289     return false;
290     }
291     VideoMonitor.mode = VMODE_16BIT;
292     break;
293     case 24:
294     case 32:
295 cebix 1.6 if (format != PIXFMT_ARGB32) {
296 cebix 1.1 ErrorAlert(GetString(STR_WRONG_SCREEN_FORMAT_ERR));
297     return false;
298     }
299     VideoMonitor.mode = VMODE_32BIT;
300     break;
301     default:
302     ErrorAlert(GetString(STR_WRONG_SCREEN_DEPTH_ERR));
303     return false;
304     }
305    
306     // Yes, get width and height
307 cebix 1.6 uint32 width = GetCyberIDAttr(CYBRIDATTR_WIDTH, mode_id);
308     uint32 height = GetCyberIDAttr(CYBRIDATTR_HEIGHT, mode_id);
309 cebix 1.4
310 cebix 1.1 VideoMonitor.x = width;
311     VideoMonitor.y = height;
312    
313     // Open screen
314 cebix 1.6 the_screen = OpenScreenTags(NULL,
315     SA_DisplayID, mode_id,
316     SA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
317     SA_Quiet, TRUE,
318     SA_Exclusive, TRUE,
319     TAG_END
320     );
321 cebix 1.1 if (the_screen == NULL) {
322     ErrorAlert(GetString(STR_OPEN_SCREEN_ERR));
323     return false;
324     }
325    
326     // Open window
327     the_win = OpenWindowTags(NULL,
328     WA_Left, 0, WA_Top, 0,
329     WA_Width, width, WA_Height, height,
330     WA_NoCareRefresh, TRUE,
331     WA_Borderless, TRUE,
332     WA_Activate, TRUE,
333     WA_RMBTrap, TRUE,
334     WA_ReportMouse, TRUE,
335 cebix 1.2 WA_CustomScreen, (ULONG)the_screen,
336 cebix 1.1 TAG_END
337     );
338     if (the_win == NULL) {
339     ErrorAlert(GetString(STR_OPEN_WINDOW_ERR));
340     return false;
341     }
342    
343     // Set VideoMonitor
344     ScreenToFront(the_screen);
345 cebix 1.6 static UWORD ptr[] = { 0, 0, 0, 0 };
346     SetPointer(the_win, ptr, 0, 0, 0, 0); // Hide mouse pointer
347     APTR handle = LockBitMapTags(the_screen->RastPort.BitMap,
348     LBMI_BASEADDRESS, (ULONG)&VideoMonitor.mac_frame_base,
349     TAG_END);
350     UnLockBitMap(handle);
351     VideoMonitor.bytes_per_row = GetCyberMapAttr(the_screen->RastPort.BitMap, CYBRMATTR_XMOD);
352 cebix 1.1 return true;
353     }
354    
355     bool VideoInit(bool classic)
356     {
357 cebix 1.8 // Allocate blank mouse pointer data
358     null_pointer = (UWORD *)AllocMem(12, MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR);
359     if (null_pointer == NULL) {
360     ErrorAlert(GetString(STR_NO_MEM_ERR));
361     return false;
362     }
363    
364 cebix 1.1 // Read frame skip prefs
365     frame_skip = PrefsFindInt32("frameskip");
366     if (frame_skip == 0)
367     frame_skip = 1;
368    
369     // Get screen mode from preferences
370     const char *mode_str;
371     if (classic)
372     mode_str = "win/512/342";
373     else
374     mode_str = PrefsFindString("screen");
375    
376     // Determine type and mode
377     display_type = DISPLAY_WINDOW;
378     int width = 512, height = 384;
379     ULONG mode_id = 0;
380     if (mode_str) {
381     if (sscanf(mode_str, "win/%d/%d", &width, &height) == 2)
382     display_type = DISPLAY_WINDOW;
383     else if (sscanf(mode_str, "pip/%d/%d", &width, &height) == 2 && P96Base)
384     display_type = DISPLAY_PIP;
385 cebix 1.6 else if (sscanf(mode_str, "scr/%08lx", &mode_id) == 1 && (CyberGfxBase || P96Base)) {
386     if (P96Base && p96GetModeIDAttr(mode_id, P96IDA_ISP96))
387     display_type = DISPLAY_SCREEN_P96;
388     else if (CyberGfxBase && IsCyberModeID(mode_id))
389     display_type = DISPLAY_SCREEN_CGFX;
390     else {
391     ErrorAlert(GetString(STR_NO_P96_MODE_ERR));
392     return false;
393     }
394     }
395 cebix 1.1 }
396    
397     // Open display
398     switch (display_type) {
399     case DISPLAY_WINDOW:
400     if (!init_window(width, height))
401     return false;
402     break;
403    
404     case DISPLAY_PIP:
405     if (!init_pip(width, height))
406     return false;
407     break;
408    
409 cebix 1.6 case DISPLAY_SCREEN_P96:
410     if (!init_screen_p96(mode_id))
411     return false;
412     break;
413    
414     case DISPLAY_SCREEN_CGFX:
415     if (!init_screen_cgfx(mode_id))
416 cebix 1.1 return false;
417     break;
418     }
419    
420     // Start periodic process
421     periodic_proc = CreateNewProcTags(
422 cebix 1.2 NP_Entry, (ULONG)periodic_func,
423     NP_Name, (ULONG)"Basilisk II IDCMP Handler",
424 cebix 1.1 NP_Priority, 0,
425     TAG_END
426     );
427     if (periodic_proc == NULL) {
428     ErrorAlert(GetString(STR_NO_MEM_ERR));
429     return false;
430     }
431     return true;
432     }
433    
434    
435     /*
436     * Deinitialization
437     */
438    
439     void VideoExit(void)
440     {
441     // Stop periodic process
442     if (periodic_proc) {
443     SetSignal(0, SIGF_SINGLE);
444     Signal(&periodic_proc->pr_Task, SIGBREAKF_CTRL_C);
445     Wait(SIGF_SINGLE);
446     }
447    
448     switch (display_type) {
449    
450     case DISPLAY_WINDOW:
451    
452     // Window mode, free bitmap
453     if (the_bitmap) {
454     WaitBlit();
455     FreeBitMap(the_bitmap);
456     }
457    
458     // Free pens and close window
459     if (the_win) {
460     ReleasePen(the_win->WScreen->ViewPort.ColorMap, black_pen);
461     ReleasePen(the_win->WScreen->ViewPort.ColorMap, white_pen);
462    
463     CloseWindow(the_win);
464     }
465     break;
466    
467     case DISPLAY_PIP:
468    
469     // Close PIP
470     if (the_win)
471     p96PIP_Close(the_win);
472     break;
473    
474 cebix 1.6 case DISPLAY_SCREEN_P96:
475 cebix 1.1
476     // Close window
477     if (the_win)
478     CloseWindow(the_win);
479    
480     // Close screen
481 cebix 1.4 if (the_screen) {
482 cebix 1.6 p96CloseScreen(the_screen);
483     the_screen = NULL;
484     }
485     break;
486    
487     case DISPLAY_SCREEN_CGFX:
488    
489     // Close window
490     if (the_win)
491     CloseWindow(the_win);
492 cebix 1.4
493 cebix 1.6 // Close screen
494     if (the_screen) {
495     CloseScreen(the_screen);
496 cebix 1.4 the_screen = NULL;
497     }
498 cebix 1.1 break;
499     }
500 cebix 1.8
501     // Free mouse pointer
502     if (null_pointer) {
503     FreeMem(null_pointer, 12);
504     null_pointer = NULL;
505     }
506 cebix 1.1 }
507    
508    
509     /*
510     * Set palette
511     */
512    
513     void video_set_palette(uint8 *pal)
514     {
515 cebix 1.6 if (display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX) {
516 cebix 1.1
517     // Convert palette to 32 bits
518     ULONG table[2 + 256 * 3];
519     table[0] = 256 << 16;
520     table[256 * 3 + 1] = 0;
521     for (int i=0; i<256; i++) {
522     table[i*3+1] = pal[i*3] * 0x01010101;
523     table[i*3+2] = pal[i*3+1] * 0x01010101;
524     table[i*3+3] = pal[i*3+2] * 0x01010101;
525     }
526    
527     // And load it
528     LoadRGB32(&the_screen->ViewPort, table);
529     }
530     }
531    
532    
533     /*
534     * Video message handling (not neccessary under AmigaOS, handled by periodic_func())
535     */
536    
537     void VideoInterrupt(void)
538     {
539     }
540    
541    
542     /*
543     * Process for window refresh and message handling
544     */
545    
546     static __saveds void periodic_func(void)
547     {
548     struct MsgPort *timer_port = NULL;
549     struct timerequest *timer_io = NULL;
550     struct IntuiMessage *msg;
551     ULONG win_mask = 0, timer_mask = 0;
552    
553     // Create message port for window and attach it
554     struct MsgPort *win_port = CreateMsgPort();
555     if (win_port) {
556     win_mask = 1 << win_port->mp_SigBit;
557     the_win->UserPort = win_port;
558 cebix 1.6 ModifyIDCMP(the_win, IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE | IDCMP_RAWKEY | ((display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX) ? IDCMP_DELTAMOVE : 0));
559 cebix 1.1 }
560    
561     // Start 60Hz timer for window refresh
562     if (display_type == DISPLAY_WINDOW) {
563     timer_port = CreateMsgPort();
564     if (timer_port) {
565     timer_io = (struct timerequest *)CreateIORequest(timer_port, sizeof(struct timerequest));
566     if (timer_io) {
567     if (!OpenDevice((UBYTE *)TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0)) {
568     timer_mask = 1 << timer_port->mp_SigBit;
569     timer_io->tr_node.io_Command = TR_ADDREQUEST;
570     timer_io->tr_time.tv_secs = 0;
571     timer_io->tr_time.tv_micro = 16667 * frame_skip;
572     SendIO((struct IORequest *)timer_io);
573     }
574     }
575     }
576     }
577    
578     // Main loop
579     for (;;) {
580    
581     // Wait for timer and/or window (CTRL_C is used for quitting the task)
582     ULONG sig = Wait(win_mask | timer_mask | SIGBREAKF_CTRL_C);
583    
584     if (sig & SIGBREAKF_CTRL_C)
585     break;
586    
587     if (sig & timer_mask) {
588    
589     // Timer tick, update display
590     BltTemplate(the_bitmap->Planes[0], 0, the_bitmap->BytesPerRow, the_win->RPort,
591     the_win->BorderLeft, the_win->BorderTop, VideoMonitor.x, VideoMonitor.y);
592    
593     // Restart timer
594     timer_io->tr_node.io_Command = TR_ADDREQUEST;
595     timer_io->tr_time.tv_secs = 0;
596     timer_io->tr_time.tv_micro = 16667 * frame_skip;
597     SendIO((struct IORequest *)timer_io);
598     }
599    
600     if (sig & win_mask) {
601    
602     // Handle window messages
603     while (msg = (struct IntuiMessage *)GetMsg(win_port)) {
604    
605     // Get data from message and reply
606     ULONG cl = msg->Class;
607     UWORD code = msg->Code;
608     UWORD qualifier = msg->Qualifier;
609     WORD mx = msg->MouseX;
610     WORD my = msg->MouseY;
611     ReplyMsg((struct Message *)msg);
612    
613     // Handle message according to class
614     switch (cl) {
615     case IDCMP_MOUSEMOVE:
616 cebix 1.7 if (display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX)
617 cebix 1.1 ADBMouseMoved(mx, my);
618 cebix 1.8 else {
619 cebix 1.1 ADBMouseMoved(mx - the_win->BorderLeft, my - the_win->BorderTop);
620 cebix 1.8 if (mx < the_win->BorderLeft
621     || my < the_win->BorderTop
622     || mx >= the_win->BorderLeft + VideoMonitor.x
623     || my >= the_win->BorderTop + VideoMonitor.y) {
624     if (current_pointer) {
625     ClearPointer(the_win);
626     current_pointer = NULL;
627     }
628     } else {
629     if (current_pointer != null_pointer) {
630     // Hide mouse pointer inside window
631     SetPointer(the_win, null_pointer, 1, 16, 0, 0);
632     current_pointer = null_pointer;
633     }
634     }
635     }
636 cebix 1.1 break;
637    
638     case IDCMP_MOUSEBUTTONS:
639     if (code == SELECTDOWN)
640     ADBMouseDown(0);
641     else if (code == SELECTUP)
642     ADBMouseUp(0);
643     else if (code == MENUDOWN)
644     ADBMouseDown(1);
645     else if (code == MENUUP)
646     ADBMouseUp(1);
647     else if (code == MIDDLEDOWN)
648     ADBMouseDown(2);
649     else if (code == MIDDLEUP)
650     ADBMouseUp(2);
651     break;
652    
653     case IDCMP_RAWKEY:
654     if (qualifier & IEQUALIFIER_REPEAT) // Keyboard repeat is done by MacOS
655     break;
656     if (code & IECODE_UP_PREFIX)
657     ADBKeyUp(keycode2mac[code & 0x7f]);
658     else
659     ADBKeyDown(keycode2mac[code & 0x7f]);
660     break;
661     }
662     }
663     }
664     }
665    
666     // Stop timer
667     if (timer_io) {
668     if (!CheckIO((struct IORequest *)timer_io))
669     AbortIO((struct IORequest *)timer_io);
670     WaitIO((struct IORequest *)timer_io);
671     CloseDevice((struct IORequest *)timer_io);
672     DeleteIORequest(timer_io);
673     }
674     if (timer_port)
675     DeleteMsgPort(timer_port);
676    
677     // Remove port from window and delete it
678     Forbid();
679     msg = (struct IntuiMessage *)win_port->mp_MsgList.lh_Head;
680     struct Node *succ;
681     while (succ = msg->ExecMessage.mn_Node.ln_Succ) {
682     if (msg->IDCMPWindow == the_win) {
683     Remove((struct Node *)msg);
684     ReplyMsg((struct Message *)msg);
685     }
686     msg = (struct IntuiMessage *)succ;
687     }
688     the_win->UserPort = NULL;
689     ModifyIDCMP(the_win, 0);
690     Permit();
691     DeleteMsgPort(win_port);
692    
693     // Main task asked for termination, send signal
694     Forbid();
695     Signal(MainTask, SIGF_SINGLE);
696     }