a
This commit is contained in:
642
gui-win32/screen.c
Normal file
642
gui-win32/screen.c
Normal file
@ -0,0 +1,642 @@
|
||||
#include <windows.h>
|
||||
// #include "winduhz.h"
|
||||
|
||||
#undef Rectangle
|
||||
#define Rectangle _Rectangle
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <dat.h>
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include "error.h"
|
||||
#include "screen.h"
|
||||
#include "keyboard.h"
|
||||
#include "fns.h"
|
||||
|
||||
Memimage *gscreen;
|
||||
Screeninfo screen;
|
||||
|
||||
extern int mousequeue;
|
||||
static int depth;
|
||||
|
||||
static HINSTANCE inst;
|
||||
static HWND window;
|
||||
static HPALETTE palette;
|
||||
static LOGPALETTE *logpal;
|
||||
static Lock gdilock;
|
||||
static BITMAPINFO *bmi;
|
||||
static HCURSOR hcursor;
|
||||
|
||||
static void winproc(void *);
|
||||
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
|
||||
static void paletteinit(void);
|
||||
static void bmiinit(void);
|
||||
static void screenload2(Rectangle r, int ldepth, uchar *p, Point pt, int step);
|
||||
|
||||
static int readybit;
|
||||
static Rendez rend;
|
||||
|
||||
Point ZP;
|
||||
|
||||
static
|
||||
isready(void*a)
|
||||
{
|
||||
return readybit;
|
||||
}
|
||||
|
||||
void
|
||||
screeninit(void)
|
||||
{
|
||||
int fmt;
|
||||
int dx, dy;
|
||||
|
||||
memimageinit();
|
||||
if(depth == 0)
|
||||
depth = GetDeviceCaps(GetDC(NULL), BITSPIXEL);
|
||||
switch(depth){
|
||||
case 32:
|
||||
screen.dibtype = DIB_RGB_COLORS;
|
||||
screen.depth = 32;
|
||||
fmt = XRGB32;
|
||||
break;
|
||||
case 24:
|
||||
screen.dibtype = DIB_RGB_COLORS;
|
||||
screen.depth = 24;
|
||||
fmt = RGB24;
|
||||
break;
|
||||
case 16:
|
||||
screen.dibtype = DIB_RGB_COLORS;
|
||||
screen.depth = 16;
|
||||
fmt = RGB15; /* [sic] */
|
||||
break;
|
||||
case 8:
|
||||
default:
|
||||
screen.dibtype = DIB_PAL_COLORS;
|
||||
screen.depth = 8;
|
||||
depth = 8;
|
||||
fmt = CMAP8;
|
||||
break;
|
||||
}
|
||||
dx = GetDeviceCaps(GetDC(NULL), HORZRES);
|
||||
dy = GetDeviceCaps(GetDC(NULL), VERTRES);
|
||||
|
||||
gscreen = allocmemimage(Rect(0,0,dx,dy), fmt);
|
||||
kproc("winscreen", winproc, 0);
|
||||
sleep(&rend, isready, 0);
|
||||
}
|
||||
|
||||
uchar*
|
||||
attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen, void **X)
|
||||
{
|
||||
*r = gscreen->r;
|
||||
*chan = gscreen->chan;
|
||||
*depth = gscreen->depth;
|
||||
*width = gscreen->width;
|
||||
*softscreen = 1;
|
||||
|
||||
return gscreen->data->bdata;
|
||||
}
|
||||
|
||||
void
|
||||
flushmemscreen(Rectangle r)
|
||||
{
|
||||
screenload(r, gscreen->depth, byteaddr(gscreen, ZP), ZP,
|
||||
gscreen->width*sizeof(ulong));
|
||||
// Sleep(100);
|
||||
}
|
||||
|
||||
void
|
||||
screenload(Rectangle r, int depth, uchar *p, Point pt, int step)
|
||||
{
|
||||
int dx, dy, delx;
|
||||
HDC hdc;
|
||||
RECT winr;
|
||||
|
||||
if(depth != gscreen->depth)
|
||||
panic("screenload: bad ldepth");
|
||||
|
||||
/*
|
||||
* Sometimes we do get rectangles that are off the
|
||||
* screen to the negative axes, for example, when
|
||||
* dragging around a window border in a Move operation.
|
||||
*/
|
||||
if(rectclip(&r, gscreen->r) == 0)
|
||||
return;
|
||||
|
||||
if(step&3 != 0 || ((pt.x*depth)%32) != 0 || (ulong)p&3 != 0)
|
||||
panic("screenload: bad params %d %d %ux", step, pt.x, p);
|
||||
dx = r.max.x - r.min.x;
|
||||
dy = r.max.y - r.min.y;
|
||||
|
||||
if(dx <= 0 || dy <= 0)
|
||||
return;
|
||||
|
||||
if(depth == 24)
|
||||
delx = r.min.x % 4;
|
||||
else
|
||||
delx = r.min.x & (31/depth);
|
||||
|
||||
p += (r.min.y-pt.y)*step;
|
||||
p += ((r.min.x-delx-pt.x)*depth)>>3;
|
||||
|
||||
if(GetWindowRect(window, &winr)==0)
|
||||
return;
|
||||
if(rectclip(&r, Rect(0, 0, winr.right-winr.left, winr.bottom-winr.top))==0)
|
||||
return;
|
||||
|
||||
lock(&gdilock);
|
||||
|
||||
hdc = GetDC(window);
|
||||
SelectPalette(hdc, palette, 0);
|
||||
RealizePalette(hdc);
|
||||
|
||||
//FillRect(hdc,(void*)&r, GetStockObject(BLACK_BRUSH));
|
||||
//GdiFlush();
|
||||
//Sleep(100);
|
||||
|
||||
bmi->bmiHeader.biWidth = (step*8)/depth;
|
||||
bmi->bmiHeader.biHeight = -dy; /* - => origin upper left */
|
||||
|
||||
StretchDIBits(hdc, r.min.x, r.min.y, dx, dy,
|
||||
delx, 0, dx, dy, p, bmi, screen.dibtype, SRCCOPY);
|
||||
|
||||
ReleaseDC(window, hdc);
|
||||
|
||||
GdiFlush();
|
||||
|
||||
unlock(&gdilock);
|
||||
}
|
||||
|
||||
static void
|
||||
winproc(void *a)
|
||||
{
|
||||
WNDCLASS wc;
|
||||
MSG msg;
|
||||
|
||||
inst = GetModuleHandle(NULL);
|
||||
|
||||
paletteinit();
|
||||
bmiinit();
|
||||
terminit();
|
||||
|
||||
wc.style = 0;
|
||||
wc.lpfnWndProc = WindowProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = inst;
|
||||
wc.hIcon = LoadIcon(inst, NULL);
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
|
||||
wc.lpszMenuName = 0;
|
||||
wc.lpszClassName = "9pmgraphics";
|
||||
RegisterClass(&wc);
|
||||
|
||||
window = CreateWindowEx(
|
||||
0, /* extended style */
|
||||
"9pmgraphics", /* class */
|
||||
"drawterm screen", /* caption */
|
||||
WS_OVERLAPPEDWINDOW, /* style */
|
||||
CW_USEDEFAULT, /* init. x pos */
|
||||
CW_USEDEFAULT, /* init. y pos */
|
||||
CW_USEDEFAULT, /* init. x size */
|
||||
CW_USEDEFAULT, /* init. y size */
|
||||
NULL, /* parent window (actually owner window for overlapped)*/
|
||||
NULL, /* menu handle */
|
||||
inst, /* program handle */
|
||||
NULL /* create parms */
|
||||
);
|
||||
|
||||
if(window == nil)
|
||||
panic("can't make window\n");
|
||||
|
||||
ShowWindow(window, SW_SHOWDEFAULT);
|
||||
UpdateWindow(window);
|
||||
|
||||
readybit = 1;
|
||||
wakeup(&rend);
|
||||
|
||||
screen.reshaped = 0;
|
||||
|
||||
while(GetMessage(&msg, NULL, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
// MessageBox(0, "winproc", "exits", MB_OK);
|
||||
ExitProcess(0);
|
||||
}
|
||||
|
||||
int
|
||||
col(int v, int n)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
c = 0;
|
||||
for(i = 0; i < 8; i += n)
|
||||
c |= v << (16-(n+i));
|
||||
return c >> 8;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
paletteinit(void)
|
||||
{
|
||||
PALETTEENTRY *pal;
|
||||
int r, g, b, cr, cg, cb, v;
|
||||
int num, den;
|
||||
int i, j;
|
||||
|
||||
logpal = mallocz(sizeof(LOGPALETTE) + 256*sizeof(PALETTEENTRY), 1);
|
||||
if(logpal == nil)
|
||||
panic("out of memory");
|
||||
logpal->palVersion = 0x300;
|
||||
logpal->palNumEntries = 256;
|
||||
pal = logpal->palPalEntry;
|
||||
|
||||
for(r=0,i=0; r<4; r++) {
|
||||
for(v=0; v<4; v++,i+=16){
|
||||
for(g=0,j=v-r; g<4; g++) {
|
||||
for(b=0; b<4; b++,j++){
|
||||
den=r;
|
||||
if(g>den)
|
||||
den=g;
|
||||
if(b>den)
|
||||
den=b;
|
||||
/* divide check -- pick grey shades */
|
||||
if(den==0)
|
||||
cr=cg=cb=v*17;
|
||||
else{
|
||||
num=17*(4*den+v);
|
||||
cr=r*num/den;
|
||||
cg=g*num/den;
|
||||
cb=b*num/den;
|
||||
}
|
||||
pal[i+(j&15)].peRed = cr;
|
||||
pal[i+(j&15)].peGreen = cg;
|
||||
pal[i+(j&15)].peBlue = cb;
|
||||
pal[i+(j&15)].peFlags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
palette = CreatePalette(logpal);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
getcolor(ulong i, ulong *r, ulong *g, ulong *b)
|
||||
{
|
||||
PALETTEENTRY *pal;
|
||||
|
||||
pal = logpal->palPalEntry;
|
||||
*r = pal[i].peRed;
|
||||
*g = pal[i].peGreen;
|
||||
*b = pal[i].peBlue;
|
||||
}
|
||||
|
||||
void
|
||||
bmiinit(void)
|
||||
{
|
||||
ushort *p;
|
||||
int i;
|
||||
|
||||
bmi = mallocz(sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD), 1);
|
||||
if(bmi == 0)
|
||||
panic("out of memory");
|
||||
bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi->bmiHeader.biWidth = 0;
|
||||
bmi->bmiHeader.biHeight = 0; /* - => origin upper left */
|
||||
bmi->bmiHeader.biPlanes = 1;
|
||||
bmi->bmiHeader.biBitCount = depth;
|
||||
bmi->bmiHeader.biCompression = BI_RGB;
|
||||
bmi->bmiHeader.biSizeImage = 0;
|
||||
bmi->bmiHeader.biXPelsPerMeter = 0;
|
||||
bmi->bmiHeader.biYPelsPerMeter = 0;
|
||||
bmi->bmiHeader.biClrUsed = 0;
|
||||
bmi->bmiHeader.biClrImportant = 0; /* number of important colors: 0 means all */
|
||||
|
||||
p = (ushort*)bmi->bmiColors;
|
||||
for(i = 0; i < 256; i++)
|
||||
p[i] = i;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK
|
||||
WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
PAINTSTRUCT paint;
|
||||
HDC hdc;
|
||||
LONG x, y, b;
|
||||
int i;
|
||||
Rectangle r;
|
||||
|
||||
switch(msg) {
|
||||
case WM_CREATE:
|
||||
break;
|
||||
case WM_SETCURSOR:
|
||||
/* User set */
|
||||
if(hcursor != NULL) {
|
||||
SetCursor(hcursor);
|
||||
return 1;
|
||||
}
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
x = LOWORD(lparam);
|
||||
y = HIWORD(lparam);
|
||||
b = 0;
|
||||
if(wparam & MK_LBUTTON)
|
||||
b = 1;
|
||||
if(wparam & MK_MBUTTON)
|
||||
b |= 2;
|
||||
if(wparam & MK_RBUTTON) {
|
||||
if(wparam & MK_SHIFT)
|
||||
b |= 2;
|
||||
else
|
||||
b |= 4;
|
||||
}
|
||||
lock(&mouse.lk);
|
||||
i = mouse.wi;
|
||||
if(mousequeue) {
|
||||
if(i == mouse.ri || mouse.lastb != b || mouse.trans) {
|
||||
mouse.wi = (i+1)%Mousequeue;
|
||||
if(mouse.wi == mouse.ri)
|
||||
mouse.ri = (mouse.ri+1)%Mousequeue;
|
||||
mouse.trans = mouse.lastb != b;
|
||||
} else {
|
||||
i = (i-1+Mousequeue)%Mousequeue;
|
||||
}
|
||||
} else {
|
||||
mouse.wi = (i+1)%Mousequeue;
|
||||
mouse.ri = i;
|
||||
}
|
||||
mouse.queue[i].xy.x = x;
|
||||
mouse.queue[i].xy.y = y;
|
||||
mouse.queue[i].buttons = b;
|
||||
mouse.queue[i].msec = ticks();
|
||||
mouse.lastb = b;
|
||||
unlock(&mouse.lk);
|
||||
wakeup(&mouse.r);
|
||||
break;
|
||||
|
||||
case WM_CHAR:
|
||||
/* repeat count is lparam & 0xf */
|
||||
switch(wparam){
|
||||
case '\n':
|
||||
wparam = '\r';
|
||||
break;
|
||||
case '\r':
|
||||
wparam = '\n';
|
||||
break;
|
||||
}
|
||||
kbdputc(kbdq, wparam);
|
||||
break;
|
||||
|
||||
case WM_SYSKEYUP:
|
||||
break;
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_KEYDOWN:
|
||||
switch(wparam) {
|
||||
case VK_MENU:
|
||||
kbdputc(kbdq, Kalt);
|
||||
break;
|
||||
case VK_INSERT:
|
||||
kbdputc(kbdq, Kins);
|
||||
break;
|
||||
case VK_DELETE:
|
||||
// kbdputc(kbdq, Kdel);
|
||||
kbdputc(kbdq, 0x7f); // should have Kdel in keyboard.h
|
||||
break;
|
||||
case VK_UP:
|
||||
kbdputc(kbdq, Kup);
|
||||
break;
|
||||
case VK_DOWN:
|
||||
kbdputc(kbdq, Kdown);
|
||||
break;
|
||||
case VK_LEFT:
|
||||
kbdputc(kbdq, Kleft);
|
||||
break;
|
||||
case VK_RIGHT:
|
||||
kbdputc(kbdq, Kright);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_CLOSE:
|
||||
DestroyWindow(hwnd);
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
|
||||
case WM_PALETTECHANGED:
|
||||
if((HWND)wparam == hwnd)
|
||||
break;
|
||||
/* fall through */
|
||||
case WM_QUERYNEWPALETTE:
|
||||
hdc = GetDC(hwnd);
|
||||
SelectPalette(hdc, palette, 0);
|
||||
if(RealizePalette(hdc) != 0)
|
||||
InvalidateRect(hwnd, nil, 0);
|
||||
ReleaseDC(hwnd, hdc);
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
hdc = BeginPaint(hwnd, &paint);
|
||||
r.min.x = paint.rcPaint.left;
|
||||
r.min.y = paint.rcPaint.top;
|
||||
r.max.x = paint.rcPaint.right;
|
||||
r.max.y = paint.rcPaint.bottom;
|
||||
flushmemscreen(r);
|
||||
EndPaint(hwnd, &paint);
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
case WM_SETFOCUS:
|
||||
case WM_DEVMODECHANGE:
|
||||
case WM_WININICHANGE:
|
||||
case WM_INITMENU:
|
||||
default:
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
mouseset(Point xy)
|
||||
{
|
||||
POINT pt;
|
||||
|
||||
pt.x = xy.x;
|
||||
pt.y = xy.y;
|
||||
MapWindowPoints(window, 0, &pt, 1);
|
||||
SetCursorPos(pt.x, pt.y);
|
||||
}
|
||||
|
||||
void
|
||||
setcursor(void)
|
||||
{
|
||||
HCURSOR nh;
|
||||
int x, y, h, w;
|
||||
uchar *sp, *cp;
|
||||
uchar *and, *xor;
|
||||
|
||||
h = GetSystemMetrics(SM_CYCURSOR);
|
||||
w = (GetSystemMetrics(SM_CXCURSOR)+7)/8;
|
||||
|
||||
and = mallocz(h*w, 1);
|
||||
memset(and, 0xff, h*w);
|
||||
xor = mallocz(h*w, 1);
|
||||
|
||||
lock(&cursor.lk);
|
||||
for(y=0,sp=cursor.set,cp=cursor.clr; y<16; y++) {
|
||||
for(x=0; x<2; x++) {
|
||||
and[y*w+x] = ~(*sp|*cp);
|
||||
xor[y*w+x] = ~*sp & *cp;
|
||||
cp++;
|
||||
sp++;
|
||||
}
|
||||
}
|
||||
nh = CreateCursor(inst, -cursor.offset.x, -cursor.offset.y,
|
||||
GetSystemMetrics(SM_CXCURSOR), h,
|
||||
and, xor);
|
||||
if(nh != NULL) {
|
||||
SetCursor(nh);
|
||||
if(hcursor != NULL)
|
||||
DestroyCursor(hcursor);
|
||||
hcursor = nh;
|
||||
}
|
||||
unlock(&cursor.lk);
|
||||
|
||||
free(and);
|
||||
free(xor);
|
||||
|
||||
PostMessage(window, WM_SETCURSOR, (int)window, 0);
|
||||
}
|
||||
|
||||
void
|
||||
cursorarrow(void)
|
||||
{
|
||||
if(hcursor != 0) {
|
||||
DestroyCursor(hcursor);
|
||||
hcursor = 0;
|
||||
}
|
||||
SetCursor(LoadCursor(0, IDC_ARROW));
|
||||
PostMessage(window, WM_SETCURSOR, (int)window, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
setcolor(ulong index, ulong red, ulong green, ulong blue)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
uchar*
|
||||
clipreadunicode(HANDLE h)
|
||||
{
|
||||
Rune *p;
|
||||
int n;
|
||||
uchar *q;
|
||||
|
||||
p = GlobalLock(h);
|
||||
n = wstrutflen(p)+1;
|
||||
q = malloc(n);
|
||||
wstrtoutf(q, p, n);
|
||||
GlobalUnlock(h);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
uchar *
|
||||
clipreadutf(HANDLE h)
|
||||
{
|
||||
uchar *p;
|
||||
|
||||
p = GlobalLock(h);
|
||||
p = strdup(p);
|
||||
GlobalUnlock(h);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
uchar*
|
||||
clipread()
|
||||
{
|
||||
HANDLE h;
|
||||
uchar *p;
|
||||
|
||||
if(!OpenClipboard(window)) {
|
||||
oserror();
|
||||
return strdup("");
|
||||
}
|
||||
|
||||
if(h = GetClipboardData(CF_UNICODETEXT))
|
||||
p = clipreadunicode(h);
|
||||
else if(h = GetClipboardData(CF_TEXT))
|
||||
p = clipreadutf(h);
|
||||
else {
|
||||
oserror();
|
||||
p = strdup("");
|
||||
}
|
||||
|
||||
CloseClipboard();
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
clipwrite(char *buf)
|
||||
{
|
||||
HANDLE h;
|
||||
char *p, *e;
|
||||
Rune *rp;
|
||||
int n = strlen(buf);
|
||||
|
||||
if(!OpenClipboard(window)) {
|
||||
oserror();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!EmptyClipboard()) {
|
||||
oserror();
|
||||
CloseClipboard();
|
||||
return -1;
|
||||
}
|
||||
|
||||
h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, (n+1)*sizeof(Rune));
|
||||
if(h == NULL)
|
||||
panic("out of memory");
|
||||
rp = GlobalLock(h);
|
||||
p = buf;
|
||||
e = p+n;
|
||||
while(p<e)
|
||||
p += chartorune(rp++, p);
|
||||
*rp = 0;
|
||||
GlobalUnlock(h);
|
||||
|
||||
SetClipboardData(CF_UNICODETEXT, h);
|
||||
|
||||
h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, n+1);
|
||||
if(h == NULL)
|
||||
panic("out of memory");
|
||||
p = GlobalLock(h);
|
||||
memcpy(p, buf, n);
|
||||
p[n] = 0;
|
||||
GlobalUnlock(h);
|
||||
|
||||
SetClipboardData(CF_TEXT, h);
|
||||
|
||||
CloseClipboard();
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
atlocalconsole(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
Reference in New Issue
Block a user