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, 4 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

# User Rev Content
1 cebix 1.1 /*
2     * video_amiga.cpp - Video/graphics emulation, AmigaOS specific stuff
3     *
4 cebix 1.12 * Basilisk II (C) 1997-2001 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 jlachmann 1.9 #include "cpu_emulation.h"
37 cebix 1.1 #include "main.h"
38     #include "adb.h"
39     #include "prefs.h"
40     #include "user_strings.h"
41     #include "video.h"
42    
43 cebix 1.4 #define DEBUG 0
44 cebix 1.1 #include "debug.h"
45    
46    
47     // Display types
48     enum {
49     DISPLAY_WINDOW,
50     DISPLAY_PIP,
51 cebix 1.6 DISPLAY_SCREEN_P96,
52     DISPLAY_SCREEN_CGFX
53 cebix 1.1 };
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 cebix 1.8 static UWORD *null_pointer = NULL; // Blank mouse pointer data
62     static UWORD *current_pointer = (UWORD *)-1; // Currently visible mouse pointer data
63 cebix 1.1 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 cebix 1.13 // 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 cebix 1.18 video_init_depth_list();
133 cebix 1.13 VideoMonitor.mode = mode;
134     }
135    
136 cebix 1.1 // 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 cebix 1.2 WA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
155 cebix 1.1 TAG_END
156     );
157     if (the_win == NULL) {
158 cebix 1.16 ErrorAlert(STR_OPEN_WINDOW_ERR);
159 cebix 1.1 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 cebix 1.16 ErrorAlert(STR_NO_MEM_ERR);
166 cebix 1.1 return false;
167     }
168    
169 cebix 1.13 // Add resolution and set VideoMonitor
170     set_video_monitor(width, height, the_bitmap->BytesPerRow, 1);
171 cebix 1.1 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 cebix 1.2 P96PIP_ErrorCode, (ULONG)&error,
195 cebix 1.1 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 cebix 1.2 WA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
206     WA_PubScreenName, (ULONG)"Workbench",
207 cebix 1.1 TAG_END
208     );
209     if (the_win == NULL || error) {
210 cebix 1.16 ErrorAlert(STR_OPEN_WINDOW_ERR);
211 cebix 1.1 return false;
212     }
213    
214     // Find bitmap
215 cebix 1.2 p96PIP_GetTags(the_win, P96PIP_SourceBitMap, (ULONG)&the_bitmap, TAG_END);
216 cebix 1.1
217 cebix 1.13 // Add resolution and set VideoMonitor
218 cebix 1.15 VideoMonitor.mac_frame_base = p96GetBitMapAttr(the_bitmap, P96BMA_MEMORY);
219 cebix 1.13 set_video_monitor(width, height, p96GetBitMapAttr(the_bitmap, P96BMA_BYTESPERROW), 16);
220 cebix 1.1 return true;
221     }
222    
223 cebix 1.6 // Open Picasso96 screen
224     static bool init_screen_p96(ULONG mode_id)
225 cebix 1.1 {
226     // Set relative mouse mode
227     ADBSetRelMouseMode(true);
228    
229 cebix 1.6 // 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 cebix 1.16 ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
240 cebix 1.6 return false;
241     }
242     break;
243     case 24:
244     case 32:
245     if (format != RGBFB_A8R8G8B8) {
246 cebix 1.16 ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
247 cebix 1.6 return false;
248     }
249     break;
250     default:
251 cebix 1.16 ErrorAlert(STR_WRONG_SCREEN_DEPTH_ERR);
252 cebix 1.6 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 cebix 1.16 ErrorAlert(STR_OPEN_SCREEN_ERR);
271 cebix 1.1 return false;
272     }
273    
274 cebix 1.6 // 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 cebix 1.16 ErrorAlert(STR_OPEN_WINDOW_ERR);
288 cebix 1.6 return false;
289     }
290    
291     ScreenToFront(the_screen);
292 cebix 1.13
293     // Add resolution and set VideoMonitor
294     set_video_monitor(width, height, p96GetBitMapAttr(the_screen->RastPort.BitMap, P96BMA_BYTESPERROW), depth);
295 cebix 1.6 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 cebix 1.4
305 cebix 1.1 // Check if the mode is one we can handle
306 cebix 1.6 uint32 depth = GetCyberIDAttr(CYBRIDATTR_DEPTH, mode_id);
307     uint32 format = GetCyberIDAttr(CYBRIDATTR_PIXFMT, mode_id);
308 cebix 1.4
309 cebix 1.1 switch (depth) {
310     case 8:
311     break;
312     case 15:
313     case 16:
314 jlachmann 1.9 // !!! PIXFMT_RGB15 is correct !!!
315     if (format != PIXFMT_RGB15) {
316 cebix 1.16 ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
317 cebix 1.1 return false;
318     }
319     break;
320     case 24:
321     case 32:
322 cebix 1.6 if (format != PIXFMT_ARGB32) {
323 cebix 1.16 ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
324 cebix 1.1 return false;
325     }
326     break;
327     default:
328 cebix 1.16 ErrorAlert(STR_WRONG_SCREEN_DEPTH_ERR);
329 cebix 1.1 return false;
330     }
331    
332     // Yes, get width and height
333 cebix 1.6 uint32 width = GetCyberIDAttr(CYBRIDATTR_WIDTH, mode_id);
334     uint32 height = GetCyberIDAttr(CYBRIDATTR_HEIGHT, mode_id);
335 cebix 1.4
336 cebix 1.1 // Open screen
337 cebix 1.6 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 cebix 1.1 if (the_screen == NULL) {
345 cebix 1.16 ErrorAlert(STR_OPEN_SCREEN_ERR);
346 cebix 1.1 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 cebix 1.2 WA_CustomScreen, (ULONG)the_screen,
359 cebix 1.1 TAG_END
360     );
361     if (the_win == NULL) {
362 cebix 1.16 ErrorAlert(STR_OPEN_WINDOW_ERR);
363 cebix 1.1 return false;
364     }
365    
366     ScreenToFront(the_screen);
367 cebix 1.6 static UWORD ptr[] = { 0, 0, 0, 0 };
368     SetPointer(the_win, ptr, 0, 0, 0, 0); // Hide mouse pointer
369 cebix 1.13
370     // Set VideoMonitor
371     ULONG frame_base;
372 cebix 1.6 APTR handle = LockBitMapTags(the_screen->RastPort.BitMap,
373 cebix 1.13 LBMI_BASEADDRESS, (ULONG)&frame_base,
374     TAG_END
375     );
376 cebix 1.6 UnLockBitMap(handle);
377 cebix 1.13 set_video_monitor(width, height, GetCyberMapAttr(the_screen->RastPort.BitMap, CYBRMATTR_XMOD), depth);
378     VideoMonitor.mac_frame_base = frame_base;
379 cebix 1.1 return true;
380     }
381    
382     bool VideoInit(bool classic)
383     {
384 cebix 1.8 // Allocate blank mouse pointer data
385     null_pointer = (UWORD *)AllocMem(12, MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR);
386     if (null_pointer == NULL) {
387 cebix 1.16 ErrorAlert(STR_NO_MEM_ERR);
388 cebix 1.8 return false;
389     }
390    
391 cebix 1.1 // 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 cebix 1.6 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 cebix 1.16 ErrorAlert(STR_NO_P96_MODE_ERR);
419 cebix 1.6 return false;
420     }
421     }
422 cebix 1.1 }
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 cebix 1.6 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 cebix 1.1 return false;
444     break;
445     }
446    
447     // Start periodic process
448     periodic_proc = CreateNewProcTags(
449 cebix 1.2 NP_Entry, (ULONG)periodic_func,
450     NP_Name, (ULONG)"Basilisk II IDCMP Handler",
451 cebix 1.1 NP_Priority, 0,
452     TAG_END
453     );
454     if (periodic_proc == NULL) {
455 cebix 1.16 ErrorAlert(STR_NO_MEM_ERR);
456 cebix 1.1 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 cebix 1.6 case DISPLAY_SCREEN_P96:
502 cebix 1.1
503     // Close window
504     if (the_win)
505     CloseWindow(the_win);
506    
507     // Close screen
508 cebix 1.4 if (the_screen) {
509 cebix 1.6 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 cebix 1.4
520 cebix 1.6 // Close screen
521     if (the_screen) {
522     CloseScreen(the_screen);
523 cebix 1.4 the_screen = NULL;
524     }
525 cebix 1.1 break;
526     }
527 cebix 1.8
528     // Free mouse pointer
529     if (null_pointer) {
530     FreeMem(null_pointer, 12);
531     null_pointer = NULL;
532     }
533 cebix 1.1 }
534    
535    
536     /*
537     * Set palette
538     */
539    
540 cebix 1.17 void video_set_palette(uint8 *pal, in num)
541 cebix 1.1 {
542 cebix 1.15 if ((display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX)
543     && !IsDirectMode(VideoMonitor.mode)) {
544 cebix 1.1
545     // Convert palette to 32 bits
546     ULONG table[2 + 256 * 3];
547 cebix 1.17 table[0] = num << 16;
548     table[num * 3 + 1] = 0;
549     for (int i=0; i<num; i++) {
550 cebix 1.1 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 cebix 1.14 * Switch video mode
563     */
564    
565     void video_switch_to_mode(const video_mode &mode)
566     {
567     }
568    
569    
570     /*
571 cebix 1.1 * 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 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));
596 cebix 1.1 }
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 cebix 1.13 the_win->BorderLeft, the_win->BorderTop, VideoMonitor.mode.x, VideoMonitor.mode.y);
629 cebix 1.1
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 cebix 1.7 if (display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX)
654 cebix 1.1 ADBMouseMoved(mx, my);
655 cebix 1.8 else {
656 cebix 1.1 ADBMouseMoved(mx - the_win->BorderLeft, my - the_win->BorderTop);
657 cebix 1.8 if (mx < the_win->BorderLeft
658     || my < the_win->BorderTop
659 cebix 1.13 || mx >= the_win->BorderLeft + VideoMonitor.mode.x
660     || my >= the_win->BorderTop + VideoMonitor.mode.y) {
661 cebix 1.8 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 cebix 1.1 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 cebix 1.11 if ((qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL)) ==
694     (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL) && code == 0x5f) {
695 jlachmann 1.9 SetInterruptFlag(INTFLAG_NMI);
696     TriggerInterrupt();
697     break;
698 cebix 1.10 }
699 jlachmann 1.9
700 cebix 1.1 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     }