ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/video_amiga.cpp
Revision: 1.18
Committed: 2001-07-03T19:20:45Z (23 years, 5 months ago) by cebix
Branch: MAIN
Changes since 1.17: +1 -0 lines
Log Message:
- improved compatibility of multiple depth/resolution handling with versions
  of MacOS before 7.6:
   - Apple mode IDs are now allocated contiguously from 0x80 (the video_*.cpp
     module must call video_init_depth_list() after adding all modes)
   - if the video driver didn't receive a GetVideoParameters call, it patches
     ScrnBase and the main GDevice upon a video mode switch (otherwise MacOS
     will continue to use the old frame buffer base)
   - the rowBytes values in the video parameters slot resources are correct
     for all bit depths

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 // Add resolution to list of supported modes and set VideoMonitor
99 static void set_video_monitor(uint32 width, uint32 height, uint32 bytes_per_row, int depth)
100 {
101 video_mode mode;
102
103 mode.x = width;
104 mode.y = height;
105 mode.resolution_id = 0x80;
106 mode.bytes_per_row = bytes_per_row;
107
108 switch (depth) {
109 case 1:
110 mode.depth = VDEPTH_1BIT;
111 break;
112 case 2:
113 mode.depth = VDEPTH_2BIT;
114 break;
115 case 4:
116 mode.depth = VDEPTH_4BIT;
117 break;
118 case 8:
119 mode.depth = VDEPTH_8BIT;
120 break;
121 case 15:
122 case 16:
123 mode.depth = VDEPTH_16BIT;
124 break;
125 case 24:
126 case 32:
127 mode.depth = VDEPTH_32BIT;
128 break;
129 }
130
131 VideoModes.push_back(mode);
132 video_init_depth_list();
133 VideoMonitor.mode = mode;
134 }
135
136 // Open window
137 static bool init_window(int width, int height)
138 {
139 // Set absolute mouse mode
140 ADBSetRelMouseMode(false);
141
142 // Open window
143 the_win = OpenWindowTags(NULL,
144 WA_Left, 0, WA_Top, 0,
145 WA_InnerWidth, width, WA_InnerHeight, height,
146 WA_SimpleRefresh, TRUE,
147 WA_NoCareRefresh, TRUE,
148 WA_Activate, TRUE,
149 WA_RMBTrap, TRUE,
150 WA_ReportMouse, TRUE,
151 WA_DragBar, TRUE,
152 WA_DepthGadget, TRUE,
153 WA_SizeGadget, FALSE,
154 WA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
155 TAG_END
156 );
157 if (the_win == NULL) {
158 ErrorAlert(STR_OPEN_WINDOW_ERR);
159 return false;
160 }
161
162 // Create bitmap ("height + 2" for safety)
163 the_bitmap = AllocBitMap(width, height + 2, 1, BMF_CLEAR, NULL);
164 if (the_bitmap == NULL) {
165 ErrorAlert(STR_NO_MEM_ERR);
166 return false;
167 }
168
169 // Add resolution and set VideoMonitor
170 set_video_monitor(width, height, the_bitmap->BytesPerRow, 1);
171 VideoMonitor.mac_frame_base = (uint32)the_bitmap->Planes[0];
172
173 // Set FgPen and BgPen
174 black_pen = ObtainBestPenA(the_win->WScreen->ViewPort.ColorMap, 0, 0, 0, NULL);
175 white_pen = ObtainBestPenA(the_win->WScreen->ViewPort.ColorMap, 0xffffffff, 0xffffffff, 0xffffffff, NULL);
176 SetAPen(the_win->RPort, black_pen);
177 SetBPen(the_win->RPort, white_pen);
178 SetDrMd(the_win->RPort, JAM2);
179 return true;
180 }
181
182 // Open PIP (requires Picasso96)
183 static bool init_pip(int width, int height)
184 {
185 // Set absolute mouse mode
186 ADBSetRelMouseMode(false);
187
188 // Open window
189 ULONG error = 0;
190 the_win = p96PIP_OpenTags(
191 P96PIP_SourceFormat, RGBFB_R5G5B5,
192 P96PIP_SourceWidth, width,
193 P96PIP_SourceHeight, height,
194 P96PIP_ErrorCode, (ULONG)&error,
195 WA_Left, 0, WA_Top, 0,
196 WA_InnerWidth, width, WA_InnerHeight, height,
197 WA_SimpleRefresh, TRUE,
198 WA_NoCareRefresh, TRUE,
199 WA_Activate, TRUE,
200 WA_RMBTrap, TRUE,
201 WA_ReportMouse, TRUE,
202 WA_DragBar, TRUE,
203 WA_DepthGadget, TRUE,
204 WA_SizeGadget, FALSE,
205 WA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
206 WA_PubScreenName, (ULONG)"Workbench",
207 TAG_END
208 );
209 if (the_win == NULL || error) {
210 ErrorAlert(STR_OPEN_WINDOW_ERR);
211 return false;
212 }
213
214 // Find bitmap
215 p96PIP_GetTags(the_win, P96PIP_SourceBitMap, (ULONG)&the_bitmap, TAG_END);
216
217 // Add resolution and set VideoMonitor
218 VideoMonitor.mac_frame_base = p96GetBitMapAttr(the_bitmap, P96BMA_MEMORY);
219 set_video_monitor(width, height, p96GetBitMapAttr(the_bitmap, P96BMA_BYTESPERROW), 16);
220 return true;
221 }
222
223 // Open Picasso96 screen
224 static bool init_screen_p96(ULONG mode_id)
225 {
226 // Set relative mouse mode
227 ADBSetRelMouseMode(true);
228
229 // Check if the mode is one we can handle
230 uint32 depth = p96GetModeIDAttr(mode_id, P96IDA_DEPTH);
231 uint32 format = p96GetModeIDAttr(mode_id, P96IDA_RGBFORMAT);
232
233 switch (depth) {
234 case 8:
235 break;
236 case 15:
237 case 16:
238 if (format != RGBFB_R5G5B5) {
239 ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
240 return false;
241 }
242 break;
243 case 24:
244 case 32:
245 if (format != RGBFB_A8R8G8B8) {
246 ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
247 return false;
248 }
249 break;
250 default:
251 ErrorAlert(STR_WRONG_SCREEN_DEPTH_ERR);
252 return false;
253 }
254
255 // Yes, get width and height
256 uint32 width = p96GetModeIDAttr(mode_id, P96IDA_WIDTH);
257 uint32 height = p96GetModeIDAttr(mode_id, P96IDA_HEIGHT);
258
259 // Open screen
260 the_screen = p96OpenScreenTags(
261 P96SA_DisplayID, mode_id,
262 P96SA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
263 P96SA_Quiet, TRUE,
264 P96SA_NoMemory, TRUE,
265 P96SA_NoSprite, TRUE,
266 P96SA_Exclusive, TRUE,
267 TAG_END
268 );
269 if (the_screen == NULL) {
270 ErrorAlert(STR_OPEN_SCREEN_ERR);
271 return false;
272 }
273
274 // Open window
275 the_win = OpenWindowTags(NULL,
276 WA_Left, 0, WA_Top, 0,
277 WA_Width, width, WA_Height, height,
278 WA_NoCareRefresh, TRUE,
279 WA_Borderless, TRUE,
280 WA_Activate, TRUE,
281 WA_RMBTrap, TRUE,
282 WA_ReportMouse, TRUE,
283 WA_CustomScreen, (ULONG)the_screen,
284 TAG_END
285 );
286 if (the_win == NULL) {
287 ErrorAlert(STR_OPEN_WINDOW_ERR);
288 return false;
289 }
290
291 ScreenToFront(the_screen);
292
293 // Add resolution and set VideoMonitor
294 set_video_monitor(width, height, p96GetBitMapAttr(the_screen->RastPort.BitMap, P96BMA_BYTESPERROW), depth);
295 VideoMonitor.mac_frame_base = p96GetBitMapAttr(the_screen->RastPort.BitMap, P96BMA_MEMORY);
296 return true;
297 }
298
299 // Open CyberGraphX screen
300 static bool init_screen_cgfx(ULONG mode_id)
301 {
302 // Set relative mouse mode
303 ADBSetRelMouseMode(true);
304
305 // Check if the mode is one we can handle
306 uint32 depth = GetCyberIDAttr(CYBRIDATTR_DEPTH, mode_id);
307 uint32 format = GetCyberIDAttr(CYBRIDATTR_PIXFMT, mode_id);
308
309 switch (depth) {
310 case 8:
311 break;
312 case 15:
313 case 16:
314 // !!! PIXFMT_RGB15 is correct !!!
315 if (format != PIXFMT_RGB15) {
316 ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
317 return false;
318 }
319 break;
320 case 24:
321 case 32:
322 if (format != PIXFMT_ARGB32) {
323 ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
324 return false;
325 }
326 break;
327 default:
328 ErrorAlert(STR_WRONG_SCREEN_DEPTH_ERR);
329 return false;
330 }
331
332 // Yes, get width and height
333 uint32 width = GetCyberIDAttr(CYBRIDATTR_WIDTH, mode_id);
334 uint32 height = GetCyberIDAttr(CYBRIDATTR_HEIGHT, mode_id);
335
336 // Open screen
337 the_screen = OpenScreenTags(NULL,
338 SA_DisplayID, mode_id,
339 SA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
340 SA_Quiet, TRUE,
341 SA_Exclusive, TRUE,
342 TAG_END
343 );
344 if (the_screen == NULL) {
345 ErrorAlert(STR_OPEN_SCREEN_ERR);
346 return false;
347 }
348
349 // Open window
350 the_win = OpenWindowTags(NULL,
351 WA_Left, 0, WA_Top, 0,
352 WA_Width, width, WA_Height, height,
353 WA_NoCareRefresh, TRUE,
354 WA_Borderless, TRUE,
355 WA_Activate, TRUE,
356 WA_RMBTrap, TRUE,
357 WA_ReportMouse, TRUE,
358 WA_CustomScreen, (ULONG)the_screen,
359 TAG_END
360 );
361 if (the_win == NULL) {
362 ErrorAlert(STR_OPEN_WINDOW_ERR);
363 return false;
364 }
365
366 ScreenToFront(the_screen);
367 static UWORD ptr[] = { 0, 0, 0, 0 };
368 SetPointer(the_win, ptr, 0, 0, 0, 0); // Hide mouse pointer
369
370 // Set VideoMonitor
371 ULONG frame_base;
372 APTR handle = LockBitMapTags(the_screen->RastPort.BitMap,
373 LBMI_BASEADDRESS, (ULONG)&frame_base,
374 TAG_END
375 );
376 UnLockBitMap(handle);
377 set_video_monitor(width, height, GetCyberMapAttr(the_screen->RastPort.BitMap, CYBRMATTR_XMOD), depth);
378 VideoMonitor.mac_frame_base = frame_base;
379 return true;
380 }
381
382 bool VideoInit(bool classic)
383 {
384 // Allocate blank mouse pointer data
385 null_pointer = (UWORD *)AllocMem(12, MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR);
386 if (null_pointer == NULL) {
387 ErrorAlert(STR_NO_MEM_ERR);
388 return false;
389 }
390
391 // Read frame skip prefs
392 frame_skip = PrefsFindInt32("frameskip");
393 if (frame_skip == 0)
394 frame_skip = 1;
395
396 // Get screen mode from preferences
397 const char *mode_str;
398 if (classic)
399 mode_str = "win/512/342";
400 else
401 mode_str = PrefsFindString("screen");
402
403 // Determine type and mode
404 display_type = DISPLAY_WINDOW;
405 int width = 512, height = 384;
406 ULONG mode_id = 0;
407 if (mode_str) {
408 if (sscanf(mode_str, "win/%d/%d", &width, &height) == 2)
409 display_type = DISPLAY_WINDOW;
410 else if (sscanf(mode_str, "pip/%d/%d", &width, &height) == 2 && P96Base)
411 display_type = DISPLAY_PIP;
412 else if (sscanf(mode_str, "scr/%08lx", &mode_id) == 1 && (CyberGfxBase || P96Base)) {
413 if (P96Base && p96GetModeIDAttr(mode_id, P96IDA_ISP96))
414 display_type = DISPLAY_SCREEN_P96;
415 else if (CyberGfxBase && IsCyberModeID(mode_id))
416 display_type = DISPLAY_SCREEN_CGFX;
417 else {
418 ErrorAlert(STR_NO_P96_MODE_ERR);
419 return false;
420 }
421 }
422 }
423
424 // Open display
425 switch (display_type) {
426 case DISPLAY_WINDOW:
427 if (!init_window(width, height))
428 return false;
429 break;
430
431 case DISPLAY_PIP:
432 if (!init_pip(width, height))
433 return false;
434 break;
435
436 case DISPLAY_SCREEN_P96:
437 if (!init_screen_p96(mode_id))
438 return false;
439 break;
440
441 case DISPLAY_SCREEN_CGFX:
442 if (!init_screen_cgfx(mode_id))
443 return false;
444 break;
445 }
446
447 // Start periodic process
448 periodic_proc = CreateNewProcTags(
449 NP_Entry, (ULONG)periodic_func,
450 NP_Name, (ULONG)"Basilisk II IDCMP Handler",
451 NP_Priority, 0,
452 TAG_END
453 );
454 if (periodic_proc == NULL) {
455 ErrorAlert(STR_NO_MEM_ERR);
456 return false;
457 }
458 return true;
459 }
460
461
462 /*
463 * Deinitialization
464 */
465
466 void VideoExit(void)
467 {
468 // Stop periodic process
469 if (periodic_proc) {
470 SetSignal(0, SIGF_SINGLE);
471 Signal(&periodic_proc->pr_Task, SIGBREAKF_CTRL_C);
472 Wait(SIGF_SINGLE);
473 }
474
475 switch (display_type) {
476
477 case DISPLAY_WINDOW:
478
479 // Window mode, free bitmap
480 if (the_bitmap) {
481 WaitBlit();
482 FreeBitMap(the_bitmap);
483 }
484
485 // Free pens and close window
486 if (the_win) {
487 ReleasePen(the_win->WScreen->ViewPort.ColorMap, black_pen);
488 ReleasePen(the_win->WScreen->ViewPort.ColorMap, white_pen);
489
490 CloseWindow(the_win);
491 }
492 break;
493
494 case DISPLAY_PIP:
495
496 // Close PIP
497 if (the_win)
498 p96PIP_Close(the_win);
499 break;
500
501 case DISPLAY_SCREEN_P96:
502
503 // Close window
504 if (the_win)
505 CloseWindow(the_win);
506
507 // Close screen
508 if (the_screen) {
509 p96CloseScreen(the_screen);
510 the_screen = NULL;
511 }
512 break;
513
514 case DISPLAY_SCREEN_CGFX:
515
516 // Close window
517 if (the_win)
518 CloseWindow(the_win);
519
520 // Close screen
521 if (the_screen) {
522 CloseScreen(the_screen);
523 the_screen = NULL;
524 }
525 break;
526 }
527
528 // Free mouse pointer
529 if (null_pointer) {
530 FreeMem(null_pointer, 12);
531 null_pointer = NULL;
532 }
533 }
534
535
536 /*
537 * Set palette
538 */
539
540 void video_set_palette(uint8 *pal, in num)
541 {
542 if ((display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX)
543 && !IsDirectMode(VideoMonitor.mode)) {
544
545 // Convert palette to 32 bits
546 ULONG table[2 + 256 * 3];
547 table[0] = num << 16;
548 table[num * 3 + 1] = 0;
549 for (int i=0; i<num; i++) {
550 table[i*3+1] = pal[i*3] * 0x01010101;
551 table[i*3+2] = pal[i*3+1] * 0x01010101;
552 table[i*3+3] = pal[i*3+2] * 0x01010101;
553 }
554
555 // And load it
556 LoadRGB32(&the_screen->ViewPort, table);
557 }
558 }
559
560
561 /*
562 * Switch video mode
563 */
564
565 void video_switch_to_mode(const video_mode &mode)
566 {
567 }
568
569
570 /*
571 * Video message handling (not neccessary under AmigaOS, handled by periodic_func())
572 */
573
574 void VideoInterrupt(void)
575 {
576 }
577
578
579 /*
580 * Process for window refresh and message handling
581 */
582
583 static __saveds void periodic_func(void)
584 {
585 struct MsgPort *timer_port = NULL;
586 struct timerequest *timer_io = NULL;
587 struct IntuiMessage *msg;
588 ULONG win_mask = 0, timer_mask = 0;
589
590 // Create message port for window and attach it
591 struct MsgPort *win_port = CreateMsgPort();
592 if (win_port) {
593 win_mask = 1 << win_port->mp_SigBit;
594 the_win->UserPort = win_port;
595 ModifyIDCMP(the_win, IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE | IDCMP_RAWKEY | ((display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX) ? IDCMP_DELTAMOVE : 0));
596 }
597
598 // Start 60Hz timer for window refresh
599 if (display_type == DISPLAY_WINDOW) {
600 timer_port = CreateMsgPort();
601 if (timer_port) {
602 timer_io = (struct timerequest *)CreateIORequest(timer_port, sizeof(struct timerequest));
603 if (timer_io) {
604 if (!OpenDevice((UBYTE *)TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0)) {
605 timer_mask = 1 << timer_port->mp_SigBit;
606 timer_io->tr_node.io_Command = TR_ADDREQUEST;
607 timer_io->tr_time.tv_secs = 0;
608 timer_io->tr_time.tv_micro = 16667 * frame_skip;
609 SendIO((struct IORequest *)timer_io);
610 }
611 }
612 }
613 }
614
615 // Main loop
616 for (;;) {
617
618 // Wait for timer and/or window (CTRL_C is used for quitting the task)
619 ULONG sig = Wait(win_mask | timer_mask | SIGBREAKF_CTRL_C);
620
621 if (sig & SIGBREAKF_CTRL_C)
622 break;
623
624 if (sig & timer_mask) {
625
626 // Timer tick, update display
627 BltTemplate(the_bitmap->Planes[0], 0, the_bitmap->BytesPerRow, the_win->RPort,
628 the_win->BorderLeft, the_win->BorderTop, VideoMonitor.mode.x, VideoMonitor.mode.y);
629
630 // Restart timer
631 timer_io->tr_node.io_Command = TR_ADDREQUEST;
632 timer_io->tr_time.tv_secs = 0;
633 timer_io->tr_time.tv_micro = 16667 * frame_skip;
634 SendIO((struct IORequest *)timer_io);
635 }
636
637 if (sig & win_mask) {
638
639 // Handle window messages
640 while (msg = (struct IntuiMessage *)GetMsg(win_port)) {
641
642 // Get data from message and reply
643 ULONG cl = msg->Class;
644 UWORD code = msg->Code;
645 UWORD qualifier = msg->Qualifier;
646 WORD mx = msg->MouseX;
647 WORD my = msg->MouseY;
648 ReplyMsg((struct Message *)msg);
649
650 // Handle message according to class
651 switch (cl) {
652 case IDCMP_MOUSEMOVE:
653 if (display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX)
654 ADBMouseMoved(mx, my);
655 else {
656 ADBMouseMoved(mx - the_win->BorderLeft, my - the_win->BorderTop);
657 if (mx < the_win->BorderLeft
658 || my < the_win->BorderTop
659 || mx >= the_win->BorderLeft + VideoMonitor.mode.x
660 || my >= the_win->BorderTop + VideoMonitor.mode.y) {
661 if (current_pointer) {
662 ClearPointer(the_win);
663 current_pointer = NULL;
664 }
665 } else {
666 if (current_pointer != null_pointer) {
667 // Hide mouse pointer inside window
668 SetPointer(the_win, null_pointer, 1, 16, 0, 0);
669 current_pointer = null_pointer;
670 }
671 }
672 }
673 break;
674
675 case IDCMP_MOUSEBUTTONS:
676 if (code == SELECTDOWN)
677 ADBMouseDown(0);
678 else if (code == SELECTUP)
679 ADBMouseUp(0);
680 else if (code == MENUDOWN)
681 ADBMouseDown(1);
682 else if (code == MENUUP)
683 ADBMouseUp(1);
684 else if (code == MIDDLEDOWN)
685 ADBMouseDown(2);
686 else if (code == MIDDLEUP)
687 ADBMouseUp(2);
688 break;
689
690 case IDCMP_RAWKEY:
691 if (qualifier & IEQUALIFIER_REPEAT) // Keyboard repeat is done by MacOS
692 break;
693 if ((qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL)) ==
694 (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL) && code == 0x5f) {
695 SetInterruptFlag(INTFLAG_NMI);
696 TriggerInterrupt();
697 break;
698 }
699
700 if (code & IECODE_UP_PREFIX)
701 ADBKeyUp(keycode2mac[code & 0x7f]);
702 else
703 ADBKeyDown(keycode2mac[code & 0x7f]);
704 break;
705 }
706 }
707 }
708 }
709
710 // Stop timer
711 if (timer_io) {
712 if (!CheckIO((struct IORequest *)timer_io))
713 AbortIO((struct IORequest *)timer_io);
714 WaitIO((struct IORequest *)timer_io);
715 CloseDevice((struct IORequest *)timer_io);
716 DeleteIORequest(timer_io);
717 }
718 if (timer_port)
719 DeleteMsgPort(timer_port);
720
721 // Remove port from window and delete it
722 Forbid();
723 msg = (struct IntuiMessage *)win_port->mp_MsgList.lh_Head;
724 struct Node *succ;
725 while (succ = msg->ExecMessage.mn_Node.ln_Succ) {
726 if (msg->IDCMPWindow == the_win) {
727 Remove((struct Node *)msg);
728 ReplyMsg((struct Message *)msg);
729 }
730 msg = (struct IntuiMessage *)succ;
731 }
732 the_win->UserPort = NULL;
733 ModifyIDCMP(the_win, 0);
734 Permit();
735 DeleteMsgPort(win_port);
736
737 // Main task asked for termination, send signal
738 Forbid();
739 Signal(MainTask, SIGF_SINGLE);
740 }