📄 gros2pm.c
字号:
#include "grobjs.h"
#include "grdevice.h"
#define INCL_DOS
#define INCL_WIN
#define INCL_GPI
#define INCL_SUB
#include <os2.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#define DEBUGxxx
#ifdef DEBUG
#define LOG(x) LogMessage##x
#else
#define LOG(x) /* rien */
#endif
#ifdef DEBUG
static void LogMessage( const char* fmt, ... )
{
va_list ap;
va_start( ap, fmt );
vfprintf( stderr, fmt, ap );
va_end( ap );
}
#endif
typedef struct Translator
{
ULONG os2key;
grKey grkey;
} Translator;
static
Translator key_translators[] =
{
{ VK_BACKSPACE, grKeyBackSpace },
{ VK_TAB, grKeyTab },
{ VK_ENTER, grKeyReturn },
{ VK_ESC, grKeyEsc },
{ VK_HOME, grKeyHome },
{ VK_LEFT, grKeyLeft },
{ VK_UP, grKeyUp },
{ VK_RIGHT, grKeyRight },
{ VK_DOWN, grKeyDown },
{ VK_PAGEUP, grKeyPageUp },
{ VK_PAGEDOWN, grKeyPageDown },
{ VK_END, grKeyEnd },
{ VK_F1, grKeyF1 },
{ VK_F2, grKeyF2 },
{ VK_F3, grKeyF3 },
{ VK_F4, grKeyF4 },
{ VK_F5, grKeyF5 },
{ VK_F6, grKeyF6 },
{ VK_F7, grKeyF7 },
{ VK_F8, grKeyF8 },
{ VK_F9, grKeyF9 },
{ VK_F10, grKeyF10 },
{ VK_F11, grKeyF11 },
{ VK_F12, grKeyF12 }
};
#define MAX_PIXEL_MODES 32
static HAB gr_anchor; /* device anchor block */
typedef POINTL PMBlitPoints[4];
typedef struct grPMSurface_
{
grSurface root;
grBitmap image;
HAB anchor; /* handle to anchor block for surface's window */
HWND frame_window; /* handle to window's frame */
HWND client_window; /* handle to window's client */
HWND title_window; /* handle to window's title bar */
HPS image_ps; /* memory presentation space used to hold */
/* the surface's content under PM */
HDC image_dc; /* memory device context for the image */
HEV event_lock; /* semaphore used in listen_surface */
HMTX image_lock; /* a mutex used to synchronise access */
/* to the memory presentation space */
/* used to hold the surface */
TID message_thread; /* thread used to process this surface's */
/* messages.. */
PBITMAPINFO2 bitmap_header;/* os/2 bitmap descriptor */
HBITMAP os2_bitmap; /* Handle to OS/2 bitmap contained in image */
BOOL ready; /* ??? */
long shades[256]; /* indices of gray levels in pixel_mode_gray */
POINTL surface_blit[4]; /* surface blitting table */
POINTL magnify_blit[4]; /* magnifier blitting table */
int magnification; /* level of magnification */
POINTL magnify_center;
SIZEL magnify_size;
grEvent event;
PMBlitPoints blit_points;
} grPMSurface;
/* we use a static variable to pass a pointer to the PM Surface */
/* to the client window. This is a bit ugly, but it makes things */
/* a lot more simple.. */
static grPMSurface* the_surface;
static
void enable_os2_iostreams( void )
{
PTIB thread_block;
PPIB process_block;
/* XXX : This is a very nasty hack, it fools OS/2 and let the program */
/* call PM functions, even though stdin/stdout/stderr are still */
/* directed to the standard i/o streams.. */
/* The program must be compiled with WINDOWCOMPAT */
/* */
/* Credits go to Michal for finding this !! */
/* */
DosGetInfoBlocks( &thread_block, &process_block );
process_block->pib_ultype = 3;
}
static
int init_device( void )
{
enable_os2_iostreams();
/* create an anchor block. This will allow this thread (i.e. the */
/* main one) to call Gpi functions.. */
gr_anchor = WinInitialize(0);
if (!gr_anchor)
{
/* could not initialise Presentation Manager */
return -1;
}
return 0;
}
static
void done_device( void )
{
/* Indicates that we do not use the Presentation Manager, this */
/* will also release all associated resources.. */
WinTerminate( gr_anchor );
}
/* close a given window */
static
void done_surface( grPMSurface* surface )
{
LOG(( "Os2PM: done_surface(%08lx)\n", (long)surface ));
if ( surface->frame_window )
WinDestroyWindow( surface->frame_window );
WinReleasePS( surface->image_ps );
grDoneBitmap( &surface->image );
grDoneBitmap( &surface->root.bitmap );
}
#define LOCK(x) DosRequestMutexSem( x, SEM_INDEFINITE_WAIT )
#define UNLOCK(x) DosReleaseMutexSem( x )
static
const int pixel_mode_bit_count[] =
{
0,
1, /* mono */
4, /* pal4 */
8, /* pal8 */
8, /* grays */
15, /* rgb15 */
16, /* rgb16 */
24, /* rgb24 */
32 /* rgb32 */
};
/************************************************************************
*
* Technical note : how the OS/2 Presntation Manager driver works
*
* PM is, in my opinion, a bloated and over-engineered graphics
* sub-system, even though it has lots of nice features. Here are
* a few tidbits about it :
*
*
* - under PM, a "bitmap" is a device-specific object whose bits are
* not directly accessible to the client application. This means
* that we must use a scheme like the following to display our
* surfaces :
*
* - hold, for each surface, its own bitmap buffer where the
* rest of the graph library writes directly.
*
* - create a PM bitmap object with the same dimensions (and
* possibly format).
*
* - copy the content of each updated rectangle into the
* PM bitmap with the function 'GpiSetBitmapBits'.
*
* - finally, "blit" the PM bitmap to the screen calling
* 'GpiBlitBlt'
*
* - but there is more : you cannot directly blit a PM bitmap to the
* screen with PM. The 'GpiBlitBlt' only works with presentation
* spaces. This means that we also need to create, for each surface :
*
* - a memory presentation space, used to hold the PM bitmap
* - a "memory device context" for the presentation space
*
* The blit is then performed from the memory presentation space
* to the screen's presentation space..
*
*
* - because each surface creates its own event-handling thread,
* we must protect the surface's presentation space from concurrent
* accesses (i.e. calls to 'GpiSetBitmapBits' when drawing to the
* surface, and calls to 'GpiBlitBlt' when drawing it on the screen
* are performed in two different threads).
*
* we use a simple mutex to do this.
*
*
* - we also use a semaphore to perform a rendez-vous between the
* main and event-handling threads (needed in "listen_event").
*
************************************************************************/
static
void RunPMWindow( grPMSurface* surface );
static
void refresh_rectangle( grPMSurface* surface,
int x,
int y,
int w,
int h )
{
LOG(( "Os2PM: refresh_rectangle( %08lx, %d, %d, %d, %d )\n",
(long)surface, x, y, w, h ));
(void)x;
(void)y;
(void)w;
(void)h;
/*
convert_rectangle( surface, x, y, w, h );
*/
LOCK( surface->image_lock );
GpiSetBitmapBits( surface->image_ps,
0,
surface->root.bitmap.rows,
surface->root.bitmap.buffer,
surface->bitmap_header );
UNLOCK( surface->image_lock );
WinInvalidateRect( surface->client_window, NULL, FALSE );
WinUpdateWindow( surface->frame_window );
}
static
void set_title( grPMSurface* surface,
const char* title )
{
ULONG rc;
#if 1
LOG(( "Os2PM: set_title( %08lx == %08lx, %s )\n",
(long)surface, surface->client_window, title ));
#endif
LOG(( " -- frame = %08lx\n",
(long)surface->frame_window ));
LOG(( " -- client parent = %08lx\n",
(long)WinQueryWindow( surface->client_window, QW_PARENT ) ));
rc = WinSetWindowText( surface->client_window, (PSZ)title );
LOG(( " -- returned rc = %ld\n",rc ));
}
static
void listen_event( grPMSurface* surface,
int event_mask,
grEvent* grevent )
{
ULONG ulRequestCount;
(void) event_mask; /* ignored for now */
/* the listen_event function blocks until there is an event to process */
DosWaitEventSem( surface->event_lock, SEM_INDEFINITE_WAIT );
DosQueryEventSem( surface->event_lock, &ulRequestCount );
*grevent = surface->event;
DosResetEventSem( surface->event_lock, &ulRequestCount );
return;
}
static
grPMSurface* init_surface( grPMSurface* surface,
grBitmap* bitmap )
{
PBITMAPINFO2 bit;
SIZEL sizl = { 0, 0 };
LONG palette[256];
LOG(( "Os2PM: init_surface( %08lx, %08lx )\n",
(long)surface, (long)bitmap ));
LOG(( " -- input bitmap =\n" ));
LOG(( " -- mode = %d\n", bitmap->mode ));
LOG(( " -- grays = %d\n", bitmap->grays ));
LOG(( " -- width = %d\n", bitmap->width ));
LOG(( " -- height = %d\n", bitmap->rows ));
/* create the bitmap - under OS/2, we support all modes as PM */
/* handles all conversions automatically.. */
if ( grNewBitmap( bitmap->mode,
bitmap->grays,
bitmap->width,
bitmap->rows,
bitmap ) )
return 0;
LOG(( " -- output bitmap =\n" ));
LOG(( " -- mode = %d\n", bitmap->mode ));
LOG(( " -- grays = %d\n", bitmap->grays ));
LOG(( " -- width = %d\n", bitmap->width ));
LOG(( " -- height = %d\n", bitmap->rows ));
bitmap->pitch = -bitmap->pitch;
surface->root.bitmap = *bitmap;
/* create the image and event lock */
DosCreateEventSem( NULL, &surface->event_lock, 0, TRUE );
DosCreateMutexSem( NULL, &surface->image_lock, 0, FALSE );
/* create the image's presentation space */
surface->image_dc = DevOpenDC( gr_anchor,
OD_MEMORY, (PSZ)"*", 0L, 0L, 0L );
surface->image_ps = GpiCreatePS( gr_anchor,
surface->image_dc,
&sizl,
PU_PELS | GPIT_MICRO |
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -