ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/video_amiga.cpp
Revision: 1.12
Committed: 2001-02-02T20:52:57Z (23 years, 9 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-17022001, snapshot-29052001, release-0_9-1
Changes since 1.11: +1 -1 lines
Log Message:
- bumped version number to 0.9
- updated copyright dates

File Contents

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