ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/video_amiga.cpp
Revision: 1.6
Committed: 2000-07-14T21:29:12Z (24 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.5: +135 -77 lines
Log Message:
- AmigaOS bug fixes by J.Lachmann (floppy, 2060scsi.device, "Add Volume" in
  prefs editor)
- imported some changes from the Windows source (1Hz interrupt, FPU fixes)

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