2
* pscr.c -- $Id: pscr.c 685 2003-03-08 15:26:51Z travo $
3
* routines to initialize graphics for MS Windows
5
* Copyright (c) 2000. See accompanying LEGAL file for details.
8
/* is this really necessary to get OCR_*?? */
14
HINSTANCE w_app_instance = 0;
15
HWND w_main_window = 0;
19
static void (*won_expose)(void *c,int *xy)= 0;
20
static void (*won_destroy)(void *c)= 0;
21
static void (*won_resize)(void *c,int w,int h)= 0;
22
static void (*won_focus)(void *c,int in)= 0;
23
static void (*won_key)(void *c,int k,int md)= 0;
24
static void (*won_click)(void *c,int b,int md,int x,int y,unsigned long ms)=0;
25
static void (*won_motion)(void *c,int md,int x,int y)= 0;
26
static void (*won_deselect)(void *c)= 0;
28
LPCTSTR w_win_class = "w_win_class";
29
LPCTSTR w_menu_class = "w_menu_class";
31
static char *clip_text = 0;
32
static HWND clip_owner = 0;
33
static void clip_free(int force);
35
LONG APIENTRY WndProc (
44
BeginPaint(hWnd, &ps);
48
return DefWindowProc (hWnd, iMessage, wParam, lParam) ;
53
void (*p_on_connect)(int dis, int fd) = 0;
56
p_connect(char *server_name)
58
static int registered = 0;
63
if (server_name) return 0;
65
w_screen.width = GetSystemMetrics(SM_CXSCREEN);
66
w_screen.height = GetSystemMetrics(SM_CYSCREEN);
67
w_screen.depth = GetDeviceCaps(dc0, BITSPIXEL);
69
/* adjust width and height for taskbar, other toolbar garbage */
70
if (SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&r, 0)) {
73
w_screen.width = r.right - r.left;
74
w_screen.height = r.bottom - r.top;
77
/* windows linetypes are unusably ugly for thin lines */
78
/*w_screen.does_linetypes = GetDeviceCaps(dc0, LINECAPS) & LC_WIDESTYLED;*/
79
w_screen.does_linetypes = 0;
80
w_screen.does_rotext = GetDeviceCaps(dc0, TEXTCAPS) & TC_CR_90;
82
w_screen.sys_colors[255-P_BLACK] = RGB(0,0,0);
83
w_screen.sys_colors[255-P_WHITE] = RGB(255,255,255);
84
w_screen.sys_colors[255-P_RED] = RGB(255,0,0);
85
w_screen.sys_colors[255-P_GREEN] = RGB(0,255,0);
86
w_screen.sys_colors[255-P_BLUE] = RGB(0,0,255);
87
w_screen.sys_colors[255-P_CYAN] = RGB(0,255,255);
88
w_screen.sys_colors[255-P_MAGENTA] = RGB(255,0,255);
89
w_screen.sys_colors[255-P_YELLOW] = RGB(255,255,0);
90
w_screen.sys_colors[255-P_BG] = GetSysColor(COLOR_WINDOW);
91
w_screen.sys_colors[255-P_FG] = GetSysColor(COLOR_WINDOWTEXT);
92
w_screen.sys_colors[255-P_GRAYD] = RGB(100,100,100);
93
w_screen.sys_colors[255-P_GRAYC] = RGB(150,150,150);
94
w_screen.sys_colors[255-P_GRAYB] = RGB(190,190,190);
95
w_screen.sys_colors[255-P_GRAYA] = RGB(214,214,214);
96
w_screen.sys_colors[255-P_XOR] = 0xffffff; /* really fg^bg, but unused */
97
i = GetDeviceCaps(dc0, NUMRESERVED);
98
if (w_screen.depth==8 && i>1 && i<=32 &&
99
(GetDeviceCaps(dc0, RASTERCAPS)&RC_PALETTE) &&
100
GetDeviceCaps(dc0, SIZEPALETTE)==256) {
101
PALETTEENTRY *pal = p_malloc(sizeof(PALETTEENTRY)*i);
106
PALETTEENTRY entry[32];
109
int sz = GetDeviceCaps(dc0, SIZEPALETTE);
111
w_screen.sys_offset = n/2;
112
w_screen.sys_pal = pal;
113
GetSystemPaletteEntries(dc0, 0, n/2, pal);
114
GetSystemPaletteEntries(dc0, sz-n/2, n/2, pal+n/2);
115
yuck.version = 0x300;
117
for (i=0 ; i<n ; i++) yuck.entry[i] = pal[i];
118
syspal = CreatePalette((LOGPALETTE *)&yuck);
121
for (i=0 ; i<15 ; i++) {
122
j = GetNearestPaletteIndex(syspal, w_screen.sys_colors[i]);
123
if (j == CLR_INVALID) PALETTEINDEX(0);
124
w_screen.sys_index[i] = PALETTEINDEX(j);
126
DeleteObject(syspal);
130
for (i=0 ; i<15 ; i++) w_screen.sys_index[i] = w_screen.sys_colors[i];
131
w_screen.sys_offset = 0;
132
w_screen.sys_pal = 0;
135
w_screen.gui_font = GetStockObject(ANSI_FIXED_FONT);
136
/* w_screen.def_palette = GetStockObject(DEFAULT_PALETTE); */
137
/* w_screen.null_brush = GetStockObject(NULL_BRUSH); */
138
/* w_screen.null_pen = CreatePen(PS_NULL, 0, 0); */
140
for (i=0 ; i<W_FONTS_CACHED ; i++) {
141
w_screen.font_order[i] = i;
142
w_screen.font_cache[i].hfont = 0;
144
w_screen.font_win = 0;
147
char *sys_cursor[P_NONE] = {
148
IDC_ARROW, IDC_CROSS, IDC_IBEAM, 0, 0, 0, 0,
149
IDC_SIZENS, IDC_SIZEWE, IDC_SIZEALL, 0, 0, 0 };
151
for (i=0 ; i<P_NONE ; i++) {
153
w_screen.cursors[i] = LoadCursor(0, sys_cursor[i]);
155
w_screen.cursors[i] = 0;
159
w_screen.first_menu = w_screen.active = 0;
162
WNDCLASSEX class_data;
163
class_data.cbSize = sizeof(WNDCLASSEX);
164
class_data.style = CS_OWNDC;
165
class_data.lpfnWndProc = (WNDPROC)w_winproc;
166
class_data.cbClsExtra = 0;
167
class_data.cbWndExtra = 0;
168
class_data.hInstance = w_app_instance;
169
class_data.hIcon = 0;
170
class_data.hCursor = 0;
171
class_data.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
172
class_data.lpszMenuName = 0;
173
class_data.lpszClassName = w_win_class;
174
class_data.hIconSm = 0;
175
if (!RegisterClassEx(&class_data)) return 0;
177
class_data.cbSize = sizeof(WNDCLASSEX);
178
class_data.style = CS_OWNDC | CS_SAVEBITS;
179
class_data.lpfnWndProc = (WNDPROC)w_winproc;
180
class_data.cbClsExtra = 0;
181
class_data.cbWndExtra = 0;
182
class_data.hInstance = w_app_instance;
183
class_data.hIcon = 0;
184
class_data.hCursor = 0;
185
class_data.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
186
class_data.lpszMenuName = 0;
187
class_data.lpszClassName = w_menu_class;
188
class_data.hIconSm = 0;
189
if (!RegisterClassEx(&class_data)) return 0;
193
if (p_on_connect) p_on_connect(0, -1);
199
p_sshape(p_scr *s, int *width, int *height)
208
p_multihead(p_scr *other, int number)
215
p_disconnect(p_scr *s)
218
if (p_on_connect) p_on_connect(1, -1);
219
for (i=0 ; i<W_FONTS_CACHED && s->font_cache[i].hfont ; i++) {
220
DeleteObject(s->font_cache[i].hfont);
221
s->font_cache[i].hfont = 0;
223
for (i=3 ; i<=12 ; i++) {
224
if ((i>6 && i<10) || !s->cursors[i] || s->cursors[i]==s->cursors[0])
226
DestroyCursor(s->cursors[i]);
227
s->cursors[i] = s->cursors[0];
229
if (s->sys_pal) p_free(s->sys_pal), s->sys_pal = 0;
234
p_gui(void (*on_expose)(void *c, int *xy),
235
void (*on_destroy)(void *c),
236
void (*on_resize)(void *c,int w,int h),
237
void (*on_focus)(void *c,int in),
238
void (*on_key)(void *c,int k,int md),
239
void (*on_click)(void *c,int b,int md,int x,int y,
241
void (*on_motion)(void *c,int md,int x,int y),
242
void (*on_deselect)(void *c),
243
void (*on_panic)(p_scr *s))
245
won_expose = on_expose;
246
won_destroy = on_destroy;
247
won_resize = on_resize;
248
won_focus = on_focus;
250
won_click = on_click;
251
won_motion = on_motion;
252
won_deselect = on_deselect;
266
if (!p_signalling && GetClientRect(w->w? w->w : w->parent->w, &r)) {
268
HBRUSH b = CreateSolidBrush(w_color(w, w->bg));
270
FillRect(w->dc, &r, b);
278
p_winloc(p_win *w, int *x, int *y)
282
if (w->w && ClientToScreen(w->w, &p)) {
291
p_resize(p_win *w, int width, int height)
296
if (GetClientRect(hw, &rin)) {
297
if (w->ancestor) hw = w->ancestor;
298
if (GetWindowRect(hw, &rout)) {
299
width += (rout.right-rout.left) - rin.right;
300
height += (rout.bottom-rout.top) - rin.bottom;
303
SetWindowPos(hw, 0, 0,0, width,height,
304
SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
311
ShowWindow(w->w, SW_SHOW);
312
/* also SetActiveWindow, SetForegroundWindow */
313
BringWindowToTop(w->w);
319
w_winproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
321
p_win *pw = (p_win *)GetWindowLong(hwnd, GWL_USERDATA);
322
if (pw && pw->w==hwnd) {
325
if (msg == WM_CHAR) { /* horrible design */
326
if (won_key && pw->ctx) {
327
int key = (int)(pw->keydown&&0xffff);
329
int state = (int)(pw->keydown>>16);
331
if (GetKeyState(VK_SHIFT)<0) state |= P_SHIFT;
332
if (GetKeyState(VK_CONTROL)<0) state |= P_CONTROL;
333
if (HIWORD(lp)&KF_ALTDOWN) state |= P_ALT; /* doesnt work */
334
won_key(pw->ctx, key, state);
340
pw->keydown &= 0; /* ((unsigned long)P_META)<<16; */
344
/* call BeginPaint or ValidateRect to avoid another WM_PAINT */
345
if (won_expose && pw->ctx) {
348
if (GetUpdateRect(hwnd, &r, 0)) {
354
r.left = r.top = r.right = r.bottom = 0;
356
if (GetClientRect(hwnd, &r))
357
won_expose(pw->ctx, (xy[0]<=0 && xy[1]<=0 && xy[2]>=r.right &&
358
xy[3]>=r.bottom)? 0 : xy);
360
ValidateRect(hwnd, 0);
366
if (won_resize && pw->ctx && wp!=SIZE_MINIMIZED &&
367
wp!=SIZE_MAXHIDE && wp!=SIZE_MAXSHOW) {
368
int width = LOWORD(lp);
369
int height = HIWORD(lp);
370
won_resize(pw->ctx, width, height);
377
if (pw == pw->s->active) pw->s->active = 0;
378
if (pw == pw->s->first_menu) {
379
pw->s->first_menu = 0;
382
if (hwnd == clip_owner) clip_free(1);
388
UnrealizeObject(pw->palette);
389
DeleteObject(pw->palette);
392
if (won_destroy && pw->ctx) won_destroy(pw->ctx);
394
SetWindowLong(hwnd, GWL_USERDATA, (LONG)0);
398
SendMessage(hwnd, WM_CLOSE, 0, 0);
406
SelectPalette(pw->dc, pw->palette, 0);
407
if (RealizePalette(pw->dc))
408
InvalidateRect(hwnd, 0, 0);
409
SelectPalette(pw->dc, pw->palette, 1);
410
RealizePalette(pw->dc);
414
if (won_focus && pw->ctx)
415
won_focus(pw->ctx, button);
418
case WM_QUERYNEWPALETTE:
419
if (pw->palette || pw->s->active) {
420
if (!pw->palette) pw = pw->s->active;
421
else if (pw->s->active != pw) pw->s->active = pw;
422
SelectPalette(pw->dc, pw->palette, 0);
423
button = RealizePalette(pw->dc);
424
if (button) InvalidateRect(hwnd, 0, 0);
425
SelectPalette(pw->dc, pw->palette, 1);
426
RealizePalette(pw->dc);
431
if (won_key && pw->ctx) { /* wp is virtual key code */
433
int state = 0; /* (int)((pw->keydown>>16)&P_META); */
434
if (wp>=VK_NUMPAD0 && wp<=VK_F24) {
436
if (wp<=VK_NUMPAD9) key = (wp-VK_NUMPAD0) + '0';
437
else if (wp==VK_MULTIPLY) key = '*';
438
else if (wp==VK_ADD) key = '+';
439
else if (wp==VK_SEPARATOR) key = '=';
440
else if (wp==VK_SUBTRACT) key = '-';
441
else if (wp==VK_DECIMAL) key = '.';
442
else if (wp==VK_DIVIDE) key = '/';
445
key = (wp-VK_F1) + P_F1;
447
} else if (wp==VK_PRIOR) key = P_PGUP;
448
else if (wp==VK_NEXT) key = P_PGDN;
449
else if (wp==VK_END) key = P_END;
450
else if (wp==VK_HOME) key = P_HOME;
451
else if (wp==VK_LEFT) key = P_LEFT;
452
else if (wp==VK_UP) key = P_UP;
453
else if (wp==VK_RIGHT) key = P_RIGHT;
454
else if (wp==VK_DOWN) key = P_DOWN;
455
else if (wp==VK_INSERT) key = P_INSERT;
456
else if (wp==VK_DELETE) key = 0x7f;
458
if (GetKeyState(VK_SHIFT)<0) state |= P_SHIFT;
459
if (GetKeyState(VK_CONTROL)<0) state |= P_CONTROL;
460
/* VK_MENU doesnt work */
461
won_key(pw->ctx, key, state);
462
} else if (wp==VK_SPACE && GetKeyState(VK_CONTROL)<0) {
463
if (GetKeyState(VK_SHIFT)<0) state |= P_SHIFT;
464
won_key(pw->ctx, 0, state);
466
} else if (wp==VK_SHIFT || wp==VK_CONTROL || wp==VK_MENU ||
467
wp==VK_CAPITAL || wp==VK_NUMLOCK) {
469
} else if (wp==VK_LWIN || wp==VK_RWIN) {
470
/* state |= P_META; this idea didnt work */
472
pw->keydown = (((unsigned long)state)<<16) | key;
476
/* if (wp==VK_LWIN || wp==VK_RWIN) pw->keydown = 0; */
491
if (won_click && pw->ctx) {
495
int down = (button>3);
496
if (down) button -= 3;
497
if (wp&MK_LBUTTON) state |= P_BTN1;
498
if (wp&MK_MBUTTON) state |= P_BTN2;
499
if (wp&MK_RBUTTON) state |= P_BTN3;
500
if (wp&MK_CONTROL) state |= P_CONTROL;
501
if (wp&MK_SHIFT) state |= P_SHIFT;
502
/* if (GetKeyState(VK_MENU)<0) state |= P_ALT; doesnt work */
504
state ^= (1<<(button+2)); /* make consistent with X11 */
505
won_click(pw->ctx, button, state, x, y, GetMessageTime());
510
if (won_motion && pw->ctx) {
514
if (wp&MK_LBUTTON) state |= P_BTN1;
515
if (wp&MK_MBUTTON) state |= P_BTN2;
516
if (wp&MK_RBUTTON) state |= P_BTN3;
517
if (wp&MK_CONTROL) state |= P_CONTROL;
518
if (wp&MK_SHIFT) state |= P_SHIFT;
520
won_motion(pw->ctx, state, x, y);
521
/* counting messages is problematic because p_qclear might remove
522
* them, and servicing motion messages out of order seems a poor
523
* idea -- so just deliver them all for now
524
* -- perhaps play API should have a function to check if there are
525
* pending motion events? */
530
if (LOWORD(lp) == HTCLIENT) {
531
SetCursor(pw->cursor);
536
case WM_DESTROYCLIPBOARD:
538
if (won_deselect && pw->ctx) won_deselect(pw->ctx);
542
} else if (msg == WM_CREATE) {
543
LPCREATESTRUCT cs = (LPCREATESTRUCT)lp;
544
pw = cs? cs->lpCreateParams : 0;
546
HDC dc = GetDC(hwnd);
547
SetWindowLong(hwnd, GWL_USERDATA, (LONG)pw);
550
SetBkColor(dc, w_color(pw, pw->bg));
551
SetBkMode(dc, TRANSPARENT);
552
SetTextAlign(dc, TA_LEFT | TA_BASELINE | TA_NOUPDATECP);
553
if (pw->menu && !pw->s->first_menu) {
554
pw->s->first_menu = pw;
562
/* consider also DefFrameProc, DefMDIChildProc */
563
return DefWindowProc(hwnd, msg, wp, lp);
571
if (force && clip_owner && OpenClipboard(0)) {
582
p_scopy(p_win *w, char *string, int n)
585
HWND owner = (string && (n>0))? w->w : 0;
586
if (!p_signalling && OpenClipboard(owner)) {
587
if (EmptyClipboard()) {
589
char *tedious = clip_text;
590
clip_free(0); /* actually called during EmptyClipboard */
591
clip_text = p_strncat(0, string, n);
592
tedious = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, n+1);
593
string = tedious? GlobalLock(tedious) : 0;
595
for (i=0 ; clip_text[i] ; i++) string[i] = clip_text[i];
597
GlobalUnlock(tedious);
598
SetClipboardData(CF_TEXT, tedious);
611
if (p_signalling) return 0;
612
if (!clip_owner && OpenClipboard(w->w)) {
613
char *tedious = GetClipboardData(CF_TEXT);
614
char *string = tedious? GlobalLock(tedious) : 0;
617
clip_text = p_strcpy(string);
618
GlobalUnlock(tedious);