forked from minhngoc25a/freetype2
896 lines
24 KiB
C
896 lines
24 KiB
C
|
#include "gros2pm.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>
|
||
|
|
||
|
|
||
|
static void Panic( const char* message )
|
||
|
{
|
||
|
fprintf( stderr, "%s", message );
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
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 int num_pixel_modes = 0;
|
||
|
static grPixelMode pixel_modes[ MAX_PIXEL_MODES ];
|
||
|
static int pixel_depth[ MAX_PIXEL_MODES ];
|
||
|
|
||
|
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;
|
||
|
|
||
|
|
||
|
|
||
|
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 )
|
||
|
{
|
||
|
if ( surface->frame_window )
|
||
|
WinDestroyWindow( surface->frame_window );
|
||
|
|
||
|
WinReleasePS( surface->image_ps );
|
||
|
|
||
|
grDoneBitmap( &surface->image );
|
||
|
grDoneBitmap( &surface->root.bitmap );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
static
|
||
|
void add_pixel_mode( grPixelMode pixel_mode,
|
||
|
int depth )
|
||
|
{
|
||
|
if ( num_pixel_modes >= MAX_PIXEL_MODES )
|
||
|
Panic( "X11.Too many pixel modes\n" );
|
||
|
|
||
|
pixel_modes[ num_pixel_modes ] = pixel_mode;
|
||
|
pixel_depth[ num_pixel_modes ] = depth;
|
||
|
|
||
|
num_pixel_modes++;
|
||
|
}
|
||
|
|
||
|
|
||
|
#define LOCK(x) DosRequestMutexSem( x, SEM_INDEFINITE_WAIT );
|
||
|
#define UNLOCK(x) DosReleaseMutexSem( x )
|
||
|
|
||
|
|
||
|
static
|
||
|
const int pixel_mode_bit_count[] =
|
||
|
{
|
||
|
0,
|
||
|
1,
|
||
|
4,
|
||
|
8, /* pal8 */
|
||
|
8, /* gray */
|
||
|
15,
|
||
|
16,
|
||
|
24,
|
||
|
32
|
||
|
};
|
||
|
|
||
|
|
||
|
/************************************************************************
|
||
|
*
|
||
|
* 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 MiGS 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 convert_gray_to_pal8( grPMSurface* surface,
|
||
|
int x,
|
||
|
int y,
|
||
|
int w,
|
||
|
int h )
|
||
|
{
|
||
|
grBitmap* target = &surface->image;
|
||
|
grBitmap* source = &surface->root.bitmap;
|
||
|
byte* write = (byte*)target->buffer + y*target->pitch + x;
|
||
|
byte* read = (byte*)source->buffer + y*source->pitch + x;
|
||
|
long* palette = surface->shades;
|
||
|
|
||
|
while (h > 0)
|
||
|
{
|
||
|
byte* _write = write;
|
||
|
byte* _read = read;
|
||
|
byte* limit = _write + w;
|
||
|
|
||
|
for ( ; _write < limit; _write++, _read++ )
|
||
|
*_write = (byte) palette[ *_read ];
|
||
|
|
||
|
write += target->pitch;
|
||
|
read += source->pitch;
|
||
|
h--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static
|
||
|
void convert_gray_to_16( grPMSurface* surface,
|
||
|
int x,
|
||
|
int y,
|
||
|
int w,
|
||
|
int h )
|
||
|
{
|
||
|
grBitmap* target = &surface->image;
|
||
|
grBitmap* source = &surface->root.bitmap;
|
||
|
byte* write = (byte*)target->buffer + y*target->pitch + 2*x;
|
||
|
byte* read = (byte*)source->buffer + y*source->pitch + x;
|
||
|
long* palette = surface->shades;
|
||
|
|
||
|
while (h > 0)
|
||
|
{
|
||
|
byte* _write = write;
|
||
|
byte* _read = read;
|
||
|
byte* limit = _write + 2*w;
|
||
|
|
||
|
for ( ; _write < limit; _write += 2, _read++ )
|
||
|
*(short*)_write = (short)palette[ *_read ];
|
||
|
|
||
|
write += target->pitch;
|
||
|
read += source->pitch;
|
||
|
h--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static
|
||
|
void convert_gray_to_24( grPMSurface* surface,
|
||
|
int x,
|
||
|
int y,
|
||
|
int w,
|
||
|
int h )
|
||
|
{
|
||
|
grBitmap* target = &surface->image;
|
||
|
grBitmap* source = &surface->root.bitmap;
|
||
|
byte* write = (byte*)target->buffer + y*target->pitch + 3*x;
|
||
|
byte* read = (byte*)source->buffer + y*source->pitch + x;
|
||
|
|
||
|
while (h > 0)
|
||
|
{
|
||
|
byte* _write = write;
|
||
|
byte* _read = read;
|
||
|
byte* limit = _write + 3*w;
|
||
|
|
||
|
for ( ; _write < limit; _write += 3, _read++ )
|
||
|
{
|
||
|
byte color = *_read;
|
||
|
|
||
|
_write[0] =
|
||
|
_write[1] =
|
||
|
_write[2] = color;
|
||
|
}
|
||
|
|
||
|
write += target->pitch;
|
||
|
read += source->pitch;
|
||
|
h--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static
|
||
|
void convert_gray_to_32( grPMSurface* surface,
|
||
|
int x,
|
||
|
int y,
|
||
|
int w,
|
||
|
int h )
|
||
|
{
|
||
|
grBitmap* target = &surface->image;
|
||
|
grBitmap* source = &surface->root.bitmap;
|
||
|
byte* write = (byte*)target->buffer + y*target->pitch + 4*x;
|
||
|
byte* read = (byte*)source->buffer + y*source->pitch + x;
|
||
|
|
||
|
while (h > 0)
|
||
|
{
|
||
|
byte* _write = write;
|
||
|
byte* _read = read;
|
||
|
byte* limit = _write + 4*w;
|
||
|
|
||
|
for ( ; _write < limit; _write += 4, _read++ )
|
||
|
{
|
||
|
byte color = *_read;
|
||
|
|
||
|
_write[0] =
|
||
|
_write[1] =
|
||
|
_write[2] =
|
||
|
_write[3] = color;
|
||
|
}
|
||
|
|
||
|
write += target->pitch;
|
||
|
read += source->pitch;
|
||
|
h--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static
|
||
|
void convert_rectangle( grPMSurface* surface,
|
||
|
int x,
|
||
|
int y,
|
||
|
int w,
|
||
|
int h )
|
||
|
{
|
||
|
int z;
|
||
|
|
||
|
/* first of all, clip to the surface's area */
|
||
|
if ( x >= surface->image.width ||
|
||
|
x+w <= 0 ||
|
||
|
y >= surface->image.rows ||
|
||
|
y+h <= 0 )
|
||
|
return;
|
||
|
|
||
|
if ( x < 0 )
|
||
|
{
|
||
|
w += x;
|
||
|
x = 0;
|
||
|
}
|
||
|
|
||
|
z = (x + w) - surface->image.width;
|
||
|
if (z > 0)
|
||
|
w -= z;
|
||
|
|
||
|
z = (y + h) - surface->image.rows;
|
||
|
if (z > 0)
|
||
|
h -= z;
|
||
|
|
||
|
/* convert the rectangle to the target depth for gray surfaces */
|
||
|
if (surface->root.bitmap.mode == gr_pixel_mode_gray)
|
||
|
{
|
||
|
switch (surface->image.mode)
|
||
|
{
|
||
|
case gr_pixel_mode_pal8 :
|
||
|
convert_gray_to_pal8( surface, x, y, w, h );
|
||
|
break;
|
||
|
|
||
|
case gr_pixel_mode_rgb555:
|
||
|
case gr_pixel_mode_rgb565:
|
||
|
convert_gray_to_16 ( surface, x, y, w, h );
|
||
|
break;
|
||
|
|
||
|
case gr_pixel_mode_rgb24:
|
||
|
convert_gray_to_24 ( surface, x, y, w, h );
|
||
|
break;
|
||
|
|
||
|
case gr_pixel_mode_rgb32:
|
||
|
convert_gray_to_32 ( surface, x, y, w, h );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static
|
||
|
void refresh_rectangle( grPMSurface* surface,
|
||
|
int x,
|
||
|
int y,
|
||
|
int w,
|
||
|
int h )
|
||
|
{
|
||
|
convert_rectangle( surface, x, y, w, h );
|
||
|
|
||
|
WinInvalidateRect( surface->client_window, NULL, FALSE );
|
||
|
WinUpdateWindow( surface->frame_window );
|
||
|
}
|
||
|
|
||
|
|
||
|
static
|
||
|
void set_title( grPMSurface* surface,
|
||
|
const char* title )
|
||
|
{
|
||
|
WinSetWindowText( surface->title_window, (PSZ)title );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
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
|
||
|
int init_surface( grPMSurface* surface,
|
||
|
grBitmap* bitmap )
|
||
|
{
|
||
|
PBITMAPINFO2 bit;
|
||
|
SIZEL sizl = { 0, 0 };
|
||
|
LONG palette[256];
|
||
|
|
||
|
/* create the bitmap - under OS/2, we support all modes as PM */
|
||
|
/* handles all conversions automatically.. */
|
||
|
if ( grNewBitmap( surface->root.bitmap.mode,
|
||
|
surface->root.bitmap.grays,
|
||
|
surface->root.bitmap.width,
|
||
|
surface->root.bitmap.rows,
|
||
|
bitmap ) )
|
||
|
return grError;
|
||
|
|
||
|
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 |
|
||
|
GPIA_ASSOC | GPIF_DEFAULT );
|
||
|
|
||
|
GpiSetBackMix( surface->image_ps, BM_OVERPAINT );
|
||
|
|
||
|
/* create the image's PM bitmap */
|
||
|
bit = (PBITMAPINFO2)grAlloc( sizeof(BITMAPINFO2) + 256*sizeof(RGB2) );
|
||
|
surface->bitmap_header = bit;
|
||
|
|
||
|
bit->cbFix = sizeof( BITMAPINFOHEADER2 );
|
||
|
bit->cx = surface->root.bitmap.width;
|
||
|
bit->cy = surface->root.bitmap.rows;
|
||
|
bit->cPlanes = 1;
|
||
|
|
||
|
bit->argbColor[0].bBlue = 0;
|
||
|
bit->argbColor[0].bGreen = 0;
|
||
|
bit->argbColor[0].bRed = 0;
|
||
|
|
||
|
bit->argbColor[1].bBlue = 255;
|
||
|
bit->argbColor[1].bGreen = 255;
|
||
|
bit->argbColor[1].bRed = 255;
|
||
|
|
||
|
bit->cBitCount = pixel_mode_bit_count[ surface->root.bitmap.mode ];
|
||
|
|
||
|
surface->os2_bitmap = GpiCreateBitmap( surface->image_ps,
|
||
|
(PBITMAPINFOHEADER2)bit,
|
||
|
0L, NULL, NULL );
|
||
|
|
||
|
GpiSetBitmap( surface->image_ps, surface->os2_bitmap );
|
||
|
|
||
|
bit->cbFix = sizeof( BITMAPINFOHEADER2 );
|
||
|
GpiQueryBitmapInfoHeader( surface->os2_bitmap,
|
||
|
(PBITMAPINFOHEADER2)bit );
|
||
|
|
||
|
/* for gr_pixel_mode_gray, create a gray-levels logical palette */
|
||
|
if ( bitmap->mode == gr_pixel_mode_gray )
|
||
|
{
|
||
|
int x, count;
|
||
|
|
||
|
count = bitmap->grays;
|
||
|
for ( x = 0; x < count; x++ )
|
||
|
palette[x] = (((count-x)*255)/count) * 0x010101;
|
||
|
|
||
|
/* create logical color table */
|
||
|
GpiCreateLogColorTable( surface->image_ps,
|
||
|
(ULONG) LCOL_PURECOLOR,
|
||
|
(LONG) LCOLF_CONSECRGB,
|
||
|
(LONG) 0L,
|
||
|
(LONG) count,
|
||
|
(PLONG) palette );
|
||
|
|
||
|
/* now, copy the color indexes to surface->shades */
|
||
|
for ( x = 0; x < count; x++ )
|
||
|
surface->shades[x] = GpiQueryColorIndex( surface->image_ps,
|
||
|
0, palette[x] );
|
||
|
}
|
||
|
|
||
|
/* set up the blit points array */
|
||
|
surface->blit_points[1].x = surface->root.bitmap.width;
|
||
|
surface->blit_points[1].y = surface->root.bitmap.rows;
|
||
|
surface->blit_points[3] = surface->blit_points[1];
|
||
|
|
||
|
/* Finally, create the event handling thread for the surface's window */
|
||
|
DosCreateThread( &surface->message_thread,
|
||
|
(PFNTHREAD) RunPMWindow,
|
||
|
(ULONG) surface,
|
||
|
0UL,
|
||
|
32920 );
|
||
|
|
||
|
surface->root.done = (grDoneSurfaceFunc) done_surface;
|
||
|
surface->root.refresh_rect = (grRefreshRectFunc) refresh_rectangle;
|
||
|
surface->root.set_title = (grSetTitleFunc) set_title;
|
||
|
surface->root.listen_event = (grListenEventFunc) listen_event;
|
||
|
|
||
|
convert_rectangle( surface, 0, 0, bitmap->width, bitmap->rows );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
MRESULT EXPENTRY Message_Process( HWND handle,
|
||
|
ULONG mess,
|
||
|
MPARAM parm1,
|
||
|
MPARAM parm2 );
|
||
|
|
||
|
|
||
|
static
|
||
|
void RunPMWindow( grPMSurface* surface )
|
||
|
{
|
||
|
unsigned char class_name[] = "DisplayClass";
|
||
|
ULONG class_flags;
|
||
|
|
||
|
static HMQ queue;
|
||
|
QMSG message;
|
||
|
|
||
|
/* create an anchor to allow this thread to use PM */
|
||
|
surface->anchor = WinInitialize(0);
|
||
|
if (!surface->anchor)
|
||
|
{
|
||
|
printf( "Error doing WinInitialize()\n" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* create a message queue */
|
||
|
queue = WinCreateMsgQueue( surface->anchor, 0 );
|
||
|
if (!queue)
|
||
|
{
|
||
|
printf( "Error doing >inCreateMsgQueue()\n" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* register the window class */
|
||
|
if ( !WinRegisterClass( surface->anchor,
|
||
|
(PSZ) class_name,
|
||
|
(PFNWP) Message_Process,
|
||
|
CS_SIZEREDRAW,
|
||
|
0 ) )
|
||
|
{
|
||
|
printf( "Error doing WinRegisterClass()\n" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* create the PM window */
|
||
|
class_flags = FCF_TITLEBAR | FCF_MINBUTTON | FCF_DLGBORDER |
|
||
|
FCF_TASKLIST | FCF_SYSMENU;
|
||
|
|
||
|
surface->frame_window = WinCreateStdWindow(
|
||
|
HWND_DESKTOP,
|
||
|
WS_VISIBLE,
|
||
|
&class_flags,
|
||
|
(PSZ) class_name,
|
||
|
(PSZ) "FreeType PM Graphics",
|
||
|
WS_VISIBLE,
|
||
|
0, 0,
|
||
|
&surface->client_window );
|
||
|
if (!surface->frame_window)
|
||
|
{
|
||
|
printf( "Error doing WinCreateStdWindow()\n" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* find the title window handle */
|
||
|
surface->title_window = WinWindowFromID( surface->frame_window,
|
||
|
FID_TITLEBAR );
|
||
|
|
||
|
/* set Window size and position */
|
||
|
WinSetWindowPos( surface->frame_window,
|
||
|
0L,
|
||
|
(SHORT) 60,
|
||
|
(SHORT) WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN ) -
|
||
|
surface->root.bitmap.rows + 100,
|
||
|
|
||
|
(SHORT) WinQuerySysValue( HWND_DESKTOP, SV_CYDLGFRAME )*2 +
|
||
|
surface->root.bitmap.width,
|
||
|
|
||
|
(SHORT) WinQuerySysValue( HWND_DESKTOP, SV_CYTITLEBAR ) +
|
||
|
WinQuerySysValue( HWND_DESKTOP, SV_CYDLGFRAME )*2 +
|
||
|
surface->root.bitmap.rows,
|
||
|
|
||
|
SWP_SIZE | SWP_MOVE );
|
||
|
|
||
|
/* save the handle to the current surface within the window words */
|
||
|
WinSetWindowPtr( surface->frame_window,QWL_USER, surface );
|
||
|
|
||
|
/* run the message queue till the end */
|
||
|
while ( WinGetMsg( surface->anchor, &message, (HWND)NULL, 0, 0 ) )
|
||
|
WinDispatchMsg( surface->anchor, &message );
|
||
|
|
||
|
/* clean-up */
|
||
|
WinDestroyWindow( surface->frame_window );
|
||
|
surface->frame_window = 0;
|
||
|
|
||
|
WinDestroyMsgQueue( queue );
|
||
|
WinTerminate( surface->anchor );
|
||
|
|
||
|
/* await death... */
|
||
|
while ( 1 )
|
||
|
DosSleep( 100 );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* Message processing for our PM Window class */
|
||
|
MRESULT EXPENTRY Message_Process( HWND handle,
|
||
|
ULONG mess,
|
||
|
MPARAM parm1,
|
||
|
MPARAM parm2 )
|
||
|
{
|
||
|
static HDC screen_dc;
|
||
|
static HPS screen_ps;
|
||
|
static BOOL minimized;
|
||
|
|
||
|
SIZEL sizl;
|
||
|
SWP swp;
|
||
|
|
||
|
grPMSurface* surface;
|
||
|
|
||
|
/* get the handle to the window's surface */
|
||
|
surface = (grPMSurface*)WinQueryWindowPtr( handle, QWL_USER );
|
||
|
|
||
|
switch( mess )
|
||
|
{
|
||
|
case WM_DESTROY:
|
||
|
/* warn the main thread to quit if it didn't know */
|
||
|
surface->event.type = gr_event_key;
|
||
|
surface->event.key = grKeyEsc;
|
||
|
DosPostEventSem( surface->event_lock );
|
||
|
break;
|
||
|
|
||
|
case WM_CREATE:
|
||
|
/* set original magnification */
|
||
|
minimized = FALSE;
|
||
|
|
||
|
/* create Device Context and Presentation Space for screen. */
|
||
|
screen_dc = WinOpenWindowDC( handle );
|
||
|
screen_ps = GpiCreatePS( surface->anchor,
|
||
|
screen_dc,
|
||
|
&sizl,
|
||
|
PU_PELS | GPIT_MICRO |
|
||
|
GPIA_ASSOC | GPIF_DEFAULT );
|
||
|
|
||
|
/* take the input focus */
|
||
|
WinFocusChange( HWND_DESKTOP, handle, 0L );
|
||
|
break;
|
||
|
|
||
|
case WM_MINMAXFRAME:
|
||
|
/* to update minimized if changed */
|
||
|
swp = *((PSWP) parm1);
|
||
|
if ( swp.fl & SWP_MINIMIZE )
|
||
|
minimized = TRUE;
|
||
|
if ( swp.fl & SWP_RESTORE )
|
||
|
minimized = FALSE;
|
||
|
return WinDefWindowProc( handle, mess, parm1, parm2 );
|
||
|
break;
|
||
|
|
||
|
case WM_ERASEBACKGROUND:
|
||
|
case WM_PAINT:
|
||
|
/* copy the memory image of the screen out to the real screen */
|
||
|
DosRequestMutexSem( surface->image_lock, SEM_INDEFINITE_WAIT );
|
||
|
WinBeginPaint( handle, screen_ps, NULL );
|
||
|
|
||
|
/* main image and magnified picture */
|
||
|
GpiBitBlt( screen_ps,
|
||
|
surface->image_ps,
|
||
|
4L,
|
||
|
surface->blit_points,
|
||
|
ROP_SRCCOPY, BBO_AND );
|
||
|
|
||
|
WinEndPaint( screen_ps );
|
||
|
DosReleaseMutexSem( surface->image_lock );
|
||
|
break;
|
||
|
|
||
|
case WM_CHAR:
|
||
|
if ( CHARMSG( &mess )->fs & KC_KEYUP )
|
||
|
break;
|
||
|
|
||
|
/* look for a specific vkey */
|
||
|
{
|
||
|
int count = sizeof( key_translators )/sizeof( key_translators[0] );
|
||
|
Translator* trans = key_translators;
|
||
|
Translator* limit = trans + count;
|
||
|
|
||
|
for ( ; trans < limit; trans++ )
|
||
|
if ( CHARMSG(&mess)->vkey == trans->os2key )
|
||
|
{
|
||
|
surface->event.key = trans->grkey;
|
||
|
goto Do_Key_Event;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* otherwise, simply record the character code */
|
||
|
if ( (CHARMSG( &mess )->fs & KC_CHAR) == 0 )
|
||
|
break;
|
||
|
|
||
|
surface->event.key = CHARMSG(&mess)->chr;
|
||
|
|
||
|
Do_Key_Event:
|
||
|
surface->event.type = gr_event_key;
|
||
|
DosPostEventSem( surface->event_lock );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return WinDefWindowProc( handle, mess, parm1, parm2 );
|
||
|
}
|
||
|
|
||
|
return (MRESULT) FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#if 0
|
||
|
static
|
||
|
grKey KeySymTogrKey( key )
|
||
|
{
|
||
|
grKey k;
|
||
|
int count = sizeof(key_translators)/sizeof(key_translators[0]);
|
||
|
Translator* trans = key_translators;
|
||
|
Translator* limit = trans + count;
|
||
|
|
||
|
k = grKeyNone;
|
||
|
|
||
|
while ( trans < limit )
|
||
|
{
|
||
|
if ( trans->xkey == key )
|
||
|
{
|
||
|
k = trans->grkey;
|
||
|
break;
|
||
|
}
|
||
|
trans++;
|
||
|
}
|
||
|
|
||
|
return k;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
static
|
||
|
void listen_event( grPMSurface* surface,
|
||
|
int event_mask,
|
||
|
grEvent* grevent )
|
||
|
{
|
||
|
grKey grkey;
|
||
|
|
||
|
/* XXXX : For now, ignore the event mask, and only exit when */
|
||
|
/* a key is pressed.. */
|
||
|
(void)event_mask;
|
||
|
|
||
|
|
||
|
/* Now, translate the keypress to a grKey */
|
||
|
/* If this wasn't part of the simple translated keys, simply get the charcode */
|
||
|
/* from the character buffer */
|
||
|
grkey = grKEY(key_buffer[key_cursor++]);
|
||
|
|
||
|
Set_Key:
|
||
|
grevent->type = gr_key_down;
|
||
|
grevent->key = grkey;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
grDevice gr_os2pm_device =
|
||
|
{
|
||
|
sizeof( grPMSurface ),
|
||
|
"os2pm",
|
||
|
|
||
|
init_device,
|
||
|
done_device,
|
||
|
|
||
|
(grDeviceInitSurfaceFunc) init_surface,
|
||
|
|
||
|
0,
|
||
|
0
|
||
|
|
||
|
};
|
||
|
|
||
|
|