[WIN32SS] Introduce the NATIVE_REACTX define and disable some Dx calls (#6025)
[reactos.git] / base / applications / mstsc / win32.c
1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 win32 calls
4 Copyright (C) Jay Sorg 2006
5
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 along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "precomp.h"
22
23 #include "uimain.h"
24
25 extern char g_username[];
26 extern char g_hostname[];
27 extern char g_servername[];
28 extern char g_password[];
29 extern char g_shell[];
30 extern char g_directory[];
31 extern char g_domain[];
32 extern int g_width;
33 extern int g_height;
34 extern int g_tcp_sck;
35 extern int g_server_depth;
36 extern int g_tcp_port_rdp; /* in tcp.c */
37 extern int pal_entries[];
38
39 static HWND g_Wnd = 0;
40 static HINSTANCE g_Instance = 0;
41 static HCURSOR g_cursor = 0;
42 static int g_block = 0;
43 static int g_xoff = 0; /* offset from window to client coords */
44 static int g_yoff = 0;
45 static int g_xscroll = 0; /* current scroll position */
46 static int g_yscroll = 0;
47 static int g_screen_width = 0;
48 static int g_screen_height = 0;
49 static int g_wnd_cwidth = 0; /* set from WM_SIZE */
50 static int g_wnd_cheight = 0;
51 static int g_fullscreen = 0;
52 static int g_workarea = 0;
53 static int g_mousex = 0; /* in client coords */
54 static int g_mousey = 0;
55 //static int g_width_height_set = 0;
56
57 static int g_clip_left = 0;
58 static int g_clip_top = 0;
59 static int g_clip_right = 800;
60 static int g_clip_bottom = 600;
61 static RECT g_wnd_clip; /* this client area of whats actually visible */
62 /* set from WM_SIZE */
63
64 /*****************************************************************************/
65 static void
66 str_to_uni(TCHAR * sizex, char * size1)
67 {
68 int len;
69 int i;
70
71 len = strlen(size1);
72 for (i = 0; i < len; i++)
73 {
74 sizex[i] = size1[i];
75 }
76 sizex[len] = 0;
77 }
78
79 /*****************************************************************************/
80 static void
81 uni_to_str(char * sizex, TCHAR * size1)
82 {
83 int len;
84 int i;
85
86 len = lstrlen(size1);
87 for (i = 0; i < len; i++)
88 {
89 sizex[i] = (char)size1[i];
90 }
91 sizex[len] = 0;
92 }
93
94 /*****************************************************************************/
95 /* returns non zero if it processed something */
96 static int
97 check_sck(void)
98 {
99 fd_set rfds;
100 struct timeval tm;
101 int count;
102 int rv;
103
104 rv = 0;
105 if (g_block == 0)
106 {
107 g_block = 1;
108 /* see if there really is data */
109 FD_ZERO(&rfds);
110 FD_SET((unsigned int)g_tcp_sck, &rfds);
111 ZeroMemory(&tm, sizeof(tm));
112 count = select(g_tcp_sck + 1, &rfds, 0, 0, &tm);
113 if (count > 0)
114 {
115 if (ui_read_wire())
116 {
117 rv = 1;
118 }
119 else
120 {
121 PostQuitMessage(0);
122 }
123 }
124 g_block = 0;
125 }
126 return rv;
127 }
128
129 /*****************************************************************************/
130 void
131 mi_error(char * msg)
132 {
133 #ifdef WITH_DEBUG
134 printf(msg);
135 #else /* WITH_DEBUG */
136 TCHAR lmsg[512];
137 TCHAR ltitle[512];
138
139 str_to_uni(lmsg, msg);
140 str_to_uni(ltitle, "Error");
141 MessageBox(g_Wnd, lmsg, ltitle, MB_OK);
142 #endif /* WITH_DEBUG */
143 }
144
145 /*****************************************************************************/
146 static int
147 get_scan_code_from_ascii(int code)
148 {
149 int rv;
150
151 rv = 0;
152 switch (code & 0xff)
153 {
154 case 0x30: rv = 0x0b; break; // 0
155 case 0x31: rv = 0x02; break; // 1
156 case 0x32: rv = 0x03; break; // 2
157 case 0x33: rv = 0x04; break; // 3
158 case 0x34: rv = 0x05; break; // 4
159 case 0x35: rv = 0x06; break; // 5
160 case 0x36: rv = 0x07; break; // 6
161 case 0x37: rv = 0x08; break; // 7
162 case 0x38: rv = 0x09; break; // 8
163 case 0x39: rv = 0x0a; break; // 9
164
165 case 0xbd: rv = 0x0c; break; // -
166 case 0xbb: rv = 0x0d; break; // =
167 case 0x08: rv = 0x0e; break; // backspace
168 case 0x09: rv = 0x0f; break; // tab
169 case 0xdb: rv = 0x1b; break; // ]
170 case 0xdd: rv = 0x1a; break; // [
171 case 0x14: rv = 0x3a; break; // capslock
172 case 0xba: rv = 0x27; break; // ;
173 case 0xde: rv = 0x28; break; // '
174 case 0x10: rv = 0x2a; break; // shift
175 case 0xbc: rv = 0x33; break; // ,
176 case 0xbe: rv = 0x34; break; // .
177 case 0xbf: rv = 0x35; break; // /
178 case 0x0d: rv = 0x1c; break; // enter
179 case 0x27: rv = 0x4d; break; // arrow right
180 case 0x25: rv = 0x4b; break; // arrow left
181 case 0x26: rv = 0x48; break; // arrow up
182 case 0x28: rv = 0x50; break; // arrow down
183 case 0x20: rv = 0x39; break; // space
184 case 0xdc: rv = 0x2b; break; // backslash
185 case 0xc0: rv = 0x29; break; // `
186 case 0x11: rv = 0x1d; break; // ctl
187
188 case 0x41: rv = 0x1e; break; // a
189 case 0x42: rv = 0x30; break; // b
190 case 0x43: rv = 0x2e; break; // c
191 case 0x44: rv = 0x20; break; // d
192 case 0x45: rv = 0x12; break; // e
193 case 0x46: rv = 0x21; break; // f
194 case 0x47: rv = 0x22; break; // g
195 case 0x48: rv = 0x23; break; // h
196 case 0x49: rv = 0x17; break; // i
197 case 0x4a: rv = 0x24; break; // j
198 case 0x4b: rv = 0x25; break; // k
199 case 0x4c: rv = 0x26; break; // l
200 case 0x4d: rv = 0x32; break; // m
201 case 0x4e: rv = 0x31; break; // n
202 case 0x4f: rv = 0x18; break; // o
203 case 0x50: rv = 0x19; break; // p
204 case 0x51: rv = 0x10; break; // q
205 case 0x52: rv = 0x13; break; // r
206 case 0x53: rv = 0x1f; break; // s
207 case 0x54: rv = 0x14; break; // t
208 case 0x55: rv = 0x16; break; // u
209 case 0x56: rv = 0x2f; break; // v
210 case 0x57: rv = 0x11; break; // w
211 case 0x58: rv = 0x2d; break; // x
212 case 0x59: rv = 0x15; break; // y
213 case 0x5a: rv = 0x2c; break; // z
214 }
215 return rv;
216 }
217
218 /*****************************************************************************/
219 static void
220 mi_scroll(int dx, int dy)
221 {
222 HRGN rgn;
223
224 rgn = CreateRectRgn(0, 0, 0, 0);
225 ScrollWindowEx(g_Wnd, dx, dy, 0, 0, rgn, 0, SW_ERASE);
226 InvalidateRgn(g_Wnd, rgn, 0);
227 DeleteObject(rgn);
228 }
229
230 /*****************************************************************************/
231 int
232 mi_read_keyboard_state(void)
233 {
234 short keydata;
235 int code;
236
237 code = 0;
238 keydata = GetKeyState(VK_SCROLL);
239 if (keydata & 0x0001)
240 {
241 code |= 1;
242 }
243 keydata = GetKeyState(VK_NUMLOCK);
244 if (keydata & 0x0001)
245 {
246 code |= 2;
247 }
248 keydata = GetKeyState(VK_CAPITAL);
249 if (keydata & 0x0001)
250 {
251 code |= 4;
252 }
253 return code;
254 }
255
256 /*****************************************************************************/
257 static void
258 mi_check_modifier(void)
259 {
260 int code;
261
262 code = mi_read_keyboard_state();
263 ui_set_modifier_state(code);
264 }
265
266 /*****************************************************************************/
267 static LRESULT
268 handle_WM_SETCURSOR(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
269 {
270 if (g_mousex >= g_wnd_clip.left &&
271 g_mousey >= g_wnd_clip.top &&
272 g_mousex < g_wnd_clip.right &&
273 g_mousey < g_wnd_clip.bottom)
274 {
275 SetCursor(g_cursor);
276 }
277 /* need default behavoir here */
278 return DefWindowProc(hWnd, message, wParam, lParam);
279 }
280
281 /*****************************************************************************/
282 static LRESULT
283 handle_WM_NCHITTEST(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
284 {
285 POINT pt;
286
287 pt.x = LOWORD(lParam);
288 pt.y = HIWORD(lParam);
289 if (ScreenToClient(g_Wnd, &pt))
290 {
291 g_mousex = pt.x;
292 g_mousey = pt.y;
293 }
294 return DefWindowProc(hWnd, message, wParam, lParam);
295 }
296
297 /*****************************************************************************/
298 static LRESULT
299 handle_WM_MOUSEMOVE(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
300 {
301 g_mousex = LOWORD(lParam);
302 g_mousey = HIWORD(lParam);
303 ui_mouse_move(g_mousex + g_xscroll, g_mousey + g_yscroll);
304 return 0;
305 }
306
307 /*****************************************************************************/
308 static LRESULT
309 handle_WM_LBUTTONDOWN(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
310 {
311 g_mousex = LOWORD(lParam);
312 g_mousey = HIWORD(lParam);
313 ui_mouse_button(1, g_mousex + g_xscroll, g_mousey + g_yscroll, 1);
314 return 0;
315 }
316
317 /*****************************************************************************/
318 static LRESULT
319 handle_WM_LBUTTONUP(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
320 {
321 g_mousex = LOWORD(lParam);
322 g_mousey = HIWORD(lParam);
323 ui_mouse_button(1, g_mousex + g_xscroll, g_mousey + g_yscroll, 0);
324 return 0;
325 }
326
327 /*****************************************************************************/
328 static LRESULT
329 handle_WM_RBUTTONDOWN(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
330 {
331 g_mousex = LOWORD(lParam);
332 g_mousey = HIWORD(lParam);
333 ui_mouse_button(2, g_mousex + g_xscroll, g_mousey + g_yscroll, 1);
334 return 0;
335 }
336
337 /*****************************************************************************/
338 static LRESULT
339 handle_WM_RBUTTONUP(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
340 {
341 g_mousex = LOWORD(lParam);
342 g_mousey = HIWORD(lParam);
343 ui_mouse_button(2, g_mousex + g_xscroll, g_mousey + g_yscroll, 0);
344 return 0;
345 }
346
347 /*****************************************************************************/
348 static LRESULT
349 handle_WM_MBUTTONDOWN(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
350 {
351 g_mousex = LOWORD(lParam);
352 g_mousey = HIWORD(lParam);
353 ui_mouse_button(3, g_mousex + g_xscroll, g_mousey + g_yscroll, 1);
354 return 0;
355 }
356
357 /*****************************************************************************/
358 static LRESULT
359 handle_WM_MBUTTONUP(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
360 {
361 g_mousex = LOWORD(lParam);
362 g_mousey = HIWORD(lParam);
363 ui_mouse_button(3, g_mousex + g_xscroll, g_mousey + g_yscroll, 0);
364 return 0;
365 }
366
367 /*****************************************************************************/
368 static LRESULT
369 handle_WM_MOUSEWHEEL(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
370 {
371 int delta;
372
373 delta = ((signed short)HIWORD(wParam)); /* GET_WHEEL_DELTA_WPARAM(wParam); */
374 if (delta > 0)
375 {
376 ui_mouse_button(4, 0, 0, 1);
377 ui_mouse_button(4, 0, 0, 0);
378 }
379 else
380 {
381 ui_mouse_button(5, 0, 0, 1);
382 ui_mouse_button(5, 0, 0, 0);
383 }
384 return 0;
385 }
386
387 /*****************************************************************************/
388 static LRESULT
389 handle_WM_KEY(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
390 {
391 int scancode;
392 int ext;
393 int down;
394
395 ext = HIWORD(lParam);
396 scancode = ext;
397 down = !(ext & 0x8000);
398 scancode &= 0xff;
399 if (scancode == 0)
400 {
401 scancode = get_scan_code_from_ascii(wParam);
402 }
403 ext &= 0x0100;
404 if (scancode == 0x0045) /* num lock */
405 {
406 ext &= ~0x0100;
407 }
408 if (down)
409 {
410 ui_key_down(scancode, ext);
411 }
412 else
413 {
414 ui_key_up(scancode, ext);
415 }
416 return 0;
417 }
418
419 /*****************************************************************************/
420 static LRESULT
421 handle_WM_PAINT(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
422 {
423 PAINTSTRUCT ps;
424 RECT rect;
425 HBRUSH brush;
426
427 BeginPaint(hWnd, &ps);
428 /* paint the area outside the rdp screen with one colour */
429 rect = ps.rcPaint;
430 rect.left = UI_MAX(rect.left, g_width);
431 if (!IsRectEmpty(&rect))
432 {
433 brush = CreateSolidBrush(RGB(0, 0, 255));
434 FillRect(ps.hdc, &rect, brush);
435 DeleteObject(brush);
436 }
437 rect = ps.rcPaint;
438 rect.top = UI_MAX(rect.top, g_height);
439 if (!IsRectEmpty(&rect))
440 {
441 brush = CreateSolidBrush(RGB(0, 0, 255));
442 FillRect(ps.hdc, &rect, brush);
443 DeleteObject(brush);
444 }
445 rect = ps.rcPaint;
446 EndPaint(hWnd, &ps);
447 ui_invalidate(rect.left + g_xscroll,
448 rect.top + g_yscroll,
449 (rect.right - rect.left) + 1,
450 (rect.bottom - rect.top) + 1);
451 return 0;
452 }
453
454 /*****************************************************************************/
455 static LRESULT
456 handle_WM_SIZE(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
457 {
458 int oldxscroll;
459 int oldyscroll;
460
461 if (wParam == SIZE_MINIMIZED)
462 {
463 return DefWindowProc(hWnd, message, wParam, lParam);
464 }
465 g_wnd_cwidth = LOWORD(lParam); /* client width / height */
466 g_wnd_cheight = HIWORD(lParam);
467 g_wnd_clip.left = 0;
468 g_wnd_clip.top = 0;
469 g_wnd_clip.right = g_wnd_clip.left + g_wnd_cwidth;
470 g_wnd_clip.bottom = g_wnd_clip.top + g_wnd_cheight;
471 if (g_wnd_cwidth < g_width || g_wnd_cheight < g_height)
472 {
473 SetScrollRange(g_Wnd, SB_HORZ, 0, g_width - g_wnd_cwidth, 1);
474 SetScrollRange(g_Wnd, SB_VERT, 0, g_height - g_wnd_cheight, 1);
475 }
476 oldxscroll = g_xscroll;
477 oldyscroll = g_yscroll;
478 if (g_wnd_cwidth >= g_width)
479 {
480 g_xscroll = 0;
481 }
482 else
483 {
484 g_xscroll = UI_MIN(g_xscroll, g_width - g_wnd_cwidth);
485 }
486 if (g_wnd_cheight >= g_height)
487 {
488 g_yscroll = 0;
489 }
490 else
491 {
492 g_yscroll = UI_MIN(g_yscroll, g_height - g_wnd_cheight);
493 }
494 mi_scroll(oldxscroll - g_xscroll, oldyscroll - g_yscroll);
495 if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
496 {
497 /* check the caps, num, and scroll lock here */
498 mi_check_modifier();
499 }
500 return 0;
501 }
502
503 /*****************************************************************************/
504 static LRESULT
505 handle_WM_SIZING(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
506 {
507 LPRECT prect;
508 int width;
509 int height;
510 int style;
511
512 prect = (LPRECT) lParam; /* total window rect */
513 width = (prect->right - prect->left) - (g_xoff * 2);
514 height = (prect->bottom - prect->top) - (g_yoff + g_xoff);
515 if (height < g_height || width < g_width)
516 {
517 style = GetWindowLongPtr(g_Wnd, GWL_STYLE);
518 if (!(style & WS_HSCROLL))
519 {
520 style |= WS_HSCROLL | WS_VSCROLL;
521 SetWindowLongPtr(g_Wnd, GWL_STYLE, style);
522 g_xscroll = 0;
523 g_yscroll = 0;
524 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
525 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
526 }
527 }
528 else if (height >= g_height && width >= g_width)
529 {
530 style = GetWindowLongPtr(g_Wnd, GWL_STYLE);
531 if (style & WS_HSCROLL)
532 {
533 style &= ~WS_HSCROLL;
534 style &= ~WS_VSCROLL;
535 SetWindowLongPtr(g_Wnd, GWL_STYLE, style);
536 g_xscroll = 0;
537 g_yscroll = 0;
538 }
539 }
540 return 0;
541 }
542
543 /*****************************************************************************/
544 static LRESULT
545 handle_WM_HSCROLL(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
546 {
547 int code;
548 int oldxscroll;
549
550 code = (int) LOWORD(wParam); /* scroll bar value */
551 if (code == SB_LINELEFT)
552 {
553 oldxscroll = g_xscroll;
554 g_xscroll--;
555 g_xscroll = UI_MAX(g_xscroll, 0);
556 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
557 mi_scroll(oldxscroll - g_xscroll, 0);
558 }
559 else if (code == SB_LINERIGHT)
560 {
561 oldxscroll = g_xscroll;
562 g_xscroll++;
563 g_xscroll = UI_MIN(g_xscroll, g_width - g_wnd_cwidth);
564 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
565 mi_scroll(oldxscroll - g_xscroll, 0);
566 }
567 else if (code == SB_PAGELEFT)
568 {
569 oldxscroll = g_xscroll;
570 g_xscroll -= g_wnd_cwidth / 2;
571 g_xscroll = UI_MAX(g_xscroll, 0);
572 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
573 mi_scroll(oldxscroll - g_xscroll, 0);
574 }
575 else if (code == SB_PAGERIGHT)
576 {
577 oldxscroll = g_xscroll;
578 g_xscroll += g_wnd_cwidth / 2;
579 g_xscroll = UI_MIN(g_xscroll, g_width - g_wnd_cwidth);
580 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
581 mi_scroll(oldxscroll - g_xscroll, 0);
582 }
583 else if (code == SB_BOTTOM)
584 {
585 oldxscroll = g_xscroll;
586 g_xscroll = g_width - g_wnd_cwidth;
587 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
588 mi_scroll(oldxscroll - g_xscroll, 0);
589 }
590 else if (code == SB_TOP)
591 {
592 oldxscroll = g_xscroll;
593 g_xscroll = 0;
594 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
595 mi_scroll(oldxscroll - g_xscroll, 0);
596 }
597 else if (code == SB_THUMBPOSITION)
598 {
599 oldxscroll = g_xscroll;
600 g_xscroll = (signed short) HIWORD(wParam);
601 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
602 mi_scroll(oldxscroll - g_xscroll, 0);
603 }
604 return 0;
605 }
606
607 /*****************************************************************************/
608 static LRESULT
609 handle_WM_VSCROLL(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
610 {
611 int code;
612 int oldyscroll;
613
614 code = (int) LOWORD(wParam); /* scroll bar value */
615 if (code == SB_LINELEFT)
616 {
617 oldyscroll = g_yscroll;
618 g_yscroll--;
619 g_yscroll = UI_MAX(g_yscroll, 0);
620 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
621 mi_scroll(0, oldyscroll - g_yscroll);
622 }
623 else if (code == SB_LINERIGHT)
624 {
625 oldyscroll = g_yscroll;
626 g_yscroll++;
627 g_yscroll = UI_MIN(g_yscroll, g_height - g_wnd_cheight);
628 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
629 mi_scroll(0, oldyscroll - g_yscroll);
630 }
631 else if (code == SB_PAGELEFT)
632 {
633 oldyscroll = g_yscroll;
634 g_yscroll -= g_wnd_cheight / 2;
635 g_yscroll = UI_MAX(g_yscroll, 0);
636 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
637 mi_scroll(0, oldyscroll - g_yscroll);
638 }
639 else if (code == SB_PAGERIGHT)
640 {
641 oldyscroll = g_yscroll;
642 g_yscroll += g_wnd_cheight / 2;
643 g_yscroll = UI_MIN(g_yscroll, g_height - g_wnd_cheight);
644 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
645 mi_scroll(0, oldyscroll - g_yscroll);
646 }
647 else if (code == SB_BOTTOM)
648 {
649 oldyscroll = g_yscroll;
650 g_yscroll = g_height - g_wnd_cheight;
651 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
652 mi_scroll(0, oldyscroll - g_yscroll);
653 }
654 else if (code == SB_TOP)
655 {
656 oldyscroll = g_yscroll;
657 g_yscroll = 0;
658 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
659 mi_scroll(0, oldyscroll - g_yscroll);
660 }
661 else if (code == SB_THUMBPOSITION)
662 {
663 oldyscroll = g_yscroll;
664 g_yscroll = (signed short) HIWORD(wParam);
665 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
666 mi_scroll(0, oldyscroll - g_yscroll);
667 }
668 return 0;
669 }
670
671
672 /*****************************************************************************/
673 LRESULT CALLBACK
674 WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
675 {
676 switch (message)
677 {
678 case WM_SETCURSOR:
679 return handle_WM_SETCURSOR(hWnd, message, wParam, lParam);
680 case 0x0084: /* WinCE don't have this WM_NCHITTEST: */
681 return handle_WM_NCHITTEST(hWnd, message, wParam, lParam);
682 case WM_MOUSEMOVE:
683 return handle_WM_MOUSEMOVE(hWnd, message, wParam, lParam);
684 case WM_LBUTTONDOWN:
685 return handle_WM_LBUTTONDOWN(hWnd, message, wParam, lParam);
686 case WM_LBUTTONUP:
687 return handle_WM_LBUTTONUP(hWnd, message, wParam, lParam);
688 case WM_RBUTTONDOWN:
689 return handle_WM_RBUTTONDOWN(hWnd, message, wParam, lParam);
690 case WM_RBUTTONUP:
691 return handle_WM_RBUTTONUP(hWnd, message, wParam, lParam);
692 case WM_MBUTTONDOWN:
693 return handle_WM_MBUTTONDOWN(hWnd, message, wParam, lParam);
694 case WM_MBUTTONUP:
695 return handle_WM_MBUTTONUP(hWnd, message, wParam, lParam);
696 /* some windows compilers don't have these defined like vc6 */
697 case 0x020a: /* WM_MOUSEWHEEL: */
698 return handle_WM_MOUSEWHEEL(hWnd, message, wParam, lParam);
699 case WM_KEYDOWN:
700 case WM_KEYUP:
701 case WM_SYSKEYDOWN:
702 case WM_SYSKEYUP:
703 return handle_WM_KEY(hWnd, message, wParam, lParam);
704 case WM_CHAR:
705 case WM_DEADCHAR:
706 case WM_SYSCHAR:
707 case WM_SYSDEADCHAR:
708 break;
709 case WM_PAINT:
710 return handle_WM_PAINT(hWnd, message, wParam, lParam);
711 case WM_DESTROY:
712 PostQuitMessage(0);
713 break;
714 case WM_APP + 1:
715 case WM_TIMER:
716 check_sck();
717 break;
718 case WM_SIZE:
719 return handle_WM_SIZE(hWnd, message, wParam, lParam);
720 case 532: /* not defined in wince WM_SIZING: */
721 return handle_WM_SIZING(hWnd, message, wParam, lParam);
722 case WM_HSCROLL:
723 return handle_WM_HSCROLL(hWnd, message, wParam, lParam);
724 case WM_VSCROLL:
725 return handle_WM_VSCROLL(hWnd, message, wParam, lParam);
726 case WM_SETFOCUS:
727 mi_check_modifier();
728 return DefWindowProc(hWnd, message, wParam, lParam);
729 default:
730 return DefWindowProc(hWnd, message, wParam, lParam);
731 }
732 return 0;
733 }
734
735 /*****************************************************************************/
736 static HRGN
737 mi_clip(HDC dc)
738 {
739 HRGN rgn;
740
741 rgn = CreateRectRgn(g_clip_left + g_xoff - g_xscroll,
742 g_clip_top + g_yoff - g_yscroll,
743 g_clip_right + g_xoff - g_xscroll,
744 g_clip_bottom + g_yoff - g_yscroll);
745 SelectClipRgn(dc, rgn);
746 IntersectClipRect(dc, g_wnd_clip.left + g_xoff, g_wnd_clip.top + g_yoff,
747 g_wnd_clip.right + g_xoff, g_wnd_clip.bottom + g_yoff);
748 return rgn;
749 }
750
751 /*****************************************************************************/
752 /* returns non zero if ok */
753 int
754 mi_create_window(void)
755 {
756 RECT rc;
757 WNDCLASS wc;
758 TCHAR classname[512];
759 TCHAR caption[512];
760 DWORD style;
761 int x;
762 int y;
763 int w;
764 int h;
765
766 if (g_Wnd != 0 || g_Instance != 0)
767 {
768 return 0;
769 }
770 g_Instance = GetModuleHandle(NULL);
771 ZeroMemory(&wc, sizeof(wc));
772 wc.lpfnWndProc = WndProc; /* points to window procedure */
773 /* name of window class */
774 str_to_uni(classname, "rdesktop");
775 wc.lpszClassName = classname;
776 str_to_uni(caption, "ReactOS Remote Desktop");
777 wc.hIcon = LoadIcon(g_Instance,
778 MAKEINTRESOURCE(IDI_MSTSC));
779 /* Register the window class. */
780 if (!RegisterClass(&wc))
781 {
782 return 0; /* Failed to register window class */
783 }
784 rc.left = 0;
785 rc.right = rc.left + UI_MIN(g_width, g_screen_width);
786 rc.top = 0;
787 rc.bottom = rc.top + UI_MIN(g_height, g_screen_height);
788
789 if (g_fullscreen)
790 {
791 style = WS_POPUP;
792 }
793 else
794 {
795 style = WS_OVERLAPPED | WS_CAPTION | WS_POPUP | WS_MINIMIZEBOX |
796 WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX;
797 }
798 if (g_screen_width < g_width || g_screen_height < g_height)
799 {
800 style |= WS_HSCROLL | WS_VSCROLL;
801 }
802 AdjustWindowRectEx(&rc, style, 0, 0);
803 x = CW_USEDEFAULT;
804 y = CW_USEDEFAULT;
805 w = rc.right - rc.left;
806 h = rc.bottom - rc.top;
807
808 g_Wnd = CreateWindow(wc.lpszClassName, caption,
809 style, x, y, w, h,
810 (HWND) NULL, (HMENU) NULL, g_Instance,
811 (LPVOID) NULL);
812 g_clip_left = 0;
813 g_clip_top = 0;
814 g_clip_right = g_clip_left + g_width;
815 g_clip_bottom = g_clip_top + g_height;
816 if (g_workarea)
817 {
818 ShowWindow(g_Wnd, SW_SHOWMAXIMIZED);
819 }
820 else
821 {
822 ShowWindow(g_Wnd, SW_SHOWNORMAL);
823 }
824 UpdateWindow(g_Wnd);
825
826 WSAAsyncSelect(g_tcp_sck, g_Wnd, WM_APP + 1, FD_READ);
827 SetTimer(g_Wnd, 1, 333, 0);
828
829 return 1;
830 }
831
832 /*****************************************************************************/
833 int
834 mi_main_loop(void)
835 {
836 MSG msg;
837
838 while (GetMessage(&msg, NULL, 0, 0))
839 {
840 TranslateMessage(&msg);
841 DispatchMessage(&msg);
842 }
843 return msg.wParam;
844 }
845
846 /*****************************************************************************/
847 void
848 mi_warning(char * msg)
849 {
850 }
851
852 /*****************************************************************************/
853 static void
854 mi_show_error(char * caption)
855 {
856 LPVOID lpMsgBuf;
857 TCHAR lcaption[512];
858
859 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
860 NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
861 (LPTSTR) &lpMsgBuf, 0, NULL);
862 #ifdef WITH_DEBUG
863 printf(lpMsgBuf);
864 #else /* WITH_DEBUG */
865 str_to_uni(lcaption, caption);
866 MessageBox(g_Wnd, (LPTSTR) lpMsgBuf, lcaption,
867 MB_OK | MB_ICONINFORMATION);
868 #endif /* WITH_DEBUG */
869 LocalFree(lpMsgBuf);
870 }
871
872 /*****************************************************************************/
873 void
874 mi_paint_rect(char * data, int width, int height, int x, int y, int cx, int cy)
875 {
876 HBITMAP bitmap;
877 BITMAPINFO bi;
878 HDC dc;
879 HDC maindc;
880 HGDIOBJ save;
881 HRGN rgn;
882 void * bits;
883 int i;
884 int j;
885 int colour;
886 int red;
887 int green;
888 int blue;
889 int index;
890
891 ZeroMemory(&bi, sizeof(bi));
892 bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
893 bi.bmiHeader.biWidth = width;
894 bi.bmiHeader.biHeight = -height;
895 bi.bmiHeader.biPlanes = 1;
896 bi.bmiHeader.biBitCount = 32;
897 bi.bmiHeader.biCompression = BI_RGB;
898 maindc = GetWindowDC(g_Wnd);
899 bitmap = CreateDIBSection(maindc, &bi, DIB_RGB_COLORS, (void **) &bits, 0, 0);
900 if (bitmap == 0)
901 {
902 mi_show_error("CreateDIBSection failed");
903 }
904
905 if (g_server_depth == 8)
906 {
907 for (i = cy - 1; i >= 0; i--)
908 {
909 for (j = cx - 1; j >= 0; j--)
910 {
911 colour = ((unsigned char*)data)[i * cx + j];
912 red = (pal_entries[colour & 0xff] & 0xff0000) >> 16;
913 green = (pal_entries[colour & 0xff] & 0xff00) >> 8;
914 blue = pal_entries[colour & 0xff] & 0xff;
915 MAKE_COLOUR32(colour, red, green, blue);
916 ((unsigned int*)bits)[i * cx + j] = colour;
917 }
918 }
919 }
920 else if (g_server_depth == 15)
921 {
922 for (i = cy - 1; i >= 0; i--)
923 {
924 for (j = cx - 1; j >= 0; j--)
925 {
926 colour = ((unsigned short*)data)[i * cx + j];
927 SPLIT_COLOUR15(colour, red, green, blue);
928 MAKE_COLOUR32(colour, red, green, blue);
929 ((unsigned int*)bits)[i * cx + j] = colour;
930 }
931 }
932 }
933 else if (g_server_depth == 16)
934 {
935 for (i = cy - 1; i >= 0; i--)
936 {
937 for (j = cx - 1; j >= 0; j--)
938 {
939 colour = ((unsigned short*)data)[i * cx + j];
940 SPLIT_COLOUR16(colour, red, green, blue);
941 MAKE_COLOUR32(colour, red, green, blue);
942 ((unsigned int*)bits)[i * cx + j] = colour;
943 }
944 }
945 }
946 else if (g_server_depth == 24)
947 {
948 for (i = cy - 1; i >= 0; i--)
949 {
950 for (j = cx - 1; j >= 0; j--)
951 {
952 index = (i * cx + j) * 3;
953 red = ((unsigned char*)data)[index + 2];
954 green = ((unsigned char*)data)[index + 1];
955 blue = ((unsigned char*)data)[index];
956 MAKE_COLOUR32(colour, red, green, blue);
957 ((unsigned int*)bits)[i * cx + j] = colour;
958 }
959 }
960 }
961 else if (g_server_depth == 32)
962 {
963 memcpy(bits, data, cx*cy*4);
964 }
965 dc = CreateCompatibleDC(maindc);
966 if (dc == 0)
967 {
968 mi_show_error("CreateCompatibleDC failed");
969 }
970 save = SelectObject(dc, bitmap);
971 rgn = mi_clip(maindc);
972 BitBlt(maindc, x + g_xoff - g_xscroll, y + g_yoff - g_yscroll, cx, cy, dc,
973 0, 0, SRCCOPY);
974 SelectObject(dc, save);
975 DeleteObject(bitmap);
976 DeleteDC(dc);
977 ReleaseDC(g_Wnd, maindc);
978 DeleteObject(rgn);
979
980 }
981
982 static INT
983 GetPortNumber(PCHAR szAddress)
984 {
985 PCHAR szPort;
986 INT iPort = TCP_PORT_RDP;
987
988 szPort = strtok(szAddress, ":");
989
990 if (szPort != NULL)
991 {
992 szPort = strtok(NULL, ":");
993
994 if (szPort != NULL)
995 {
996 iPort = atoi(szPort);
997
998 if (iPort <= 0 || iPort > 0xFFFF)
999 iPort = TCP_PORT_RDP;
1000 }
1001 }
1002
1003 return iPort;
1004 }
1005
1006 static VOID
1007 SetDomainAndUsername(PCHAR pName)
1008 {
1009 PCHAR pDomain;
1010 PCHAR pUsername;
1011
1012 strcpy(g_domain, "");
1013 strcpy(g_username, "");
1014
1015 pDomain = strtok(pName, "\\");
1016
1017 if(pDomain == NULL)
1018 return;
1019
1020 pUsername = strtok(NULL, "\\");
1021
1022 if(pUsername == NULL)
1023 {
1024 strcpy(g_username, pDomain);
1025 return;
1026 }
1027
1028 strcpy(g_username, pUsername);
1029 strcpy(g_domain, pDomain);
1030 return;
1031 }
1032
1033 static BOOL
1034 ParseCommandLine(LPWSTR lpCmdLine,
1035 PRDPSETTINGS pRdpSettings,
1036 BOOL *bSkipDlg)
1037 {
1038 LPWSTR lpStr = lpCmdLine;
1039 WCHAR szSeps[] = L"/";
1040 LPWSTR lpToken;
1041 BOOL bRet = TRUE;
1042
1043 *bSkipDlg = TRUE;
1044
1045 if (*lpCmdLine != L'/')
1046 {
1047 LoadRdpSettingsFromFile(pRdpSettings, lpCmdLine);
1048 }
1049 else
1050 {
1051 /* default to screen size, 16bpp */
1052 SetIntegerToSettings(pRdpSettings, L"session bpp", 16);
1053 SetIntegerToSettings(pRdpSettings, L"desktopwidth", GetSystemMetrics(SM_CXSCREEN));
1054 SetIntegerToSettings(pRdpSettings, L"desktopheight", GetSystemMetrics(SM_CYSCREEN));
1055
1056 lpToken = wcstok(lpStr, szSeps);
1057 while (lpToken)
1058 {
1059 if (wcsncmp(lpToken, L"edit", 4) == 0)
1060 {
1061 lpToken += 5;
1062 LoadRdpSettingsFromFile(pRdpSettings, lpToken);
1063 *bSkipDlg = FALSE;
1064 break;
1065 }
1066
1067 if (*lpToken == L'v')
1068 {
1069 lpToken += 2;
1070 SetStringToSettings(pRdpSettings, L"full address", lpToken);
1071 }
1072 else if (*lpToken == L'w')
1073 {
1074 lpToken += 2;
1075 SetIntegerToSettings(pRdpSettings, L"desktopwidth", _wtoi(lpToken));
1076 }
1077 else if (*lpToken == L'h')
1078 {
1079 lpToken += 2;
1080 SetIntegerToSettings(pRdpSettings, L"desktopheight", _wtoi(lpToken));
1081 }
1082 else if (*lpToken == L'f')
1083 {
1084 SetIntegerToSettings(pRdpSettings, L"screen mode id", 2);
1085 }
1086
1087 lpToken = wcstok(NULL, szSeps);
1088 }
1089 }
1090
1091 return bRet;
1092 }
1093
1094 /*****************************************************************************/
1095 int WINAPI
1096 wWinMain(HINSTANCE hInstance,
1097 HINSTANCE hPrevInstance,
1098 LPWSTR lpCmdLine,
1099 int nCmdShow)
1100 {
1101 PRDPSETTINGS pRdpSettings;
1102 WSADATA d;
1103 int ret = 1;
1104
1105 if (WSAStartup(MAKEWORD(2, 0), &d) == 0)
1106 {
1107 pRdpSettings = HeapAlloc(GetProcessHeap(),
1108 0,
1109 sizeof(RDPSETTINGS));
1110 if (pRdpSettings)
1111 {
1112 pRdpSettings->pSettings = NULL;
1113 pRdpSettings->NumSettings = 0;
1114
1115 if (InitRdpSettings(pRdpSettings))
1116 {
1117 BOOL bSkipDlg = FALSE;
1118
1119 if (*lpCmdLine)
1120 ParseCommandLine(lpCmdLine, pRdpSettings,&bSkipDlg);
1121 else
1122 LoadRdpSettingsFromFile(pRdpSettings, NULL);
1123
1124 if (bSkipDlg || OpenRDPConnectDialog(hInstance,
1125 pRdpSettings))
1126 {
1127 char szValue[MAXVALUE];
1128 DWORD dwSize = MAXVALUE;
1129
1130 uni_to_str(szValue, GetStringFromSettings(pRdpSettings, L"full address"));
1131
1132 /* GetPortNumber also removes possible trailing port number from address */
1133 g_tcp_port_rdp = GetPortNumber(szValue);
1134 strcpy(g_servername, szValue);
1135 uni_to_str(szValue, GetStringFromSettings(pRdpSettings, L"username"));
1136 SetDomainAndUsername(szValue);
1137 strcpy(g_password, "");
1138 if (GetComputerNameA(szValue, &dwSize))
1139 strcpy(g_hostname, szValue);
1140 else
1141 strcpy(g_hostname, tcp_get_address());
1142 g_server_depth = GetIntegerFromSettings(pRdpSettings, L"session bpp");
1143 g_screen_width = GetSystemMetrics(SM_CXSCREEN);
1144 g_screen_height = GetSystemMetrics(SM_CYSCREEN);
1145 g_width = GetIntegerFromSettings(pRdpSettings, L"desktopwidth");
1146 g_height = GetIntegerFromSettings(pRdpSettings, L"desktopheight");
1147 if (GetIntegerFromSettings(pRdpSettings, L"screen mode id") == 2)
1148 {
1149 g_fullscreen = 1;
1150 g_xoff = 0;
1151 g_yoff = 0;
1152 }
1153 else
1154 {
1155 g_xoff = GetSystemMetrics(SM_CXEDGE) * 2;
1156 g_yoff = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYEDGE) * 2;
1157 }
1158
1159 ui_main();
1160 ret = 0;
1161 }
1162
1163 HeapFree(GetProcessHeap(),
1164 0,
1165 pRdpSettings->pSettings);
1166 }
1167
1168 HeapFree(GetProcessHeap(),
1169 0,
1170 pRdpSettings);
1171 }
1172
1173 WSACleanup();
1174 }
1175
1176 return ret;
1177 }
1178
1179
1180 /*****************************************************************************/
1181 void
1182 mi_begin_update(void)
1183 {
1184 }
1185
1186 /*****************************************************************************/
1187 void
1188 mi_end_update(void)
1189 {
1190 }
1191
1192 /*****************************************************************************/
1193 void
1194 mi_fill_rect(int x, int y, int cx, int cy, int colour)
1195 {
1196 HBRUSH brush;
1197 RECT rect;
1198 HDC maindc;
1199 HRGN rgn;
1200 int red;
1201 int green;
1202 int blue;
1203
1204 if (g_server_depth == 8)
1205 {
1206 red = (pal_entries[colour & 0xff] & 0xff0000) >> 16;
1207 green = (pal_entries[colour & 0xff] & 0xff00) >> 8;
1208 blue = pal_entries[colour & 0xff] & 0xff;
1209 }
1210 else if (g_server_depth == 15)
1211 {
1212 SPLIT_COLOUR15(colour, red, green, blue);
1213 }
1214 else if (g_server_depth == 16)
1215 {
1216 SPLIT_COLOUR16(colour, red, green, blue);
1217 }
1218 else if (g_server_depth == 24 || g_server_depth == 32)
1219 {
1220 red = (colour>>16)&0xff;
1221 green = (colour>>8)&0xff;
1222 blue = colour&0xff;
1223 }
1224 maindc = GetWindowDC(g_Wnd);
1225 rgn = mi_clip(maindc);
1226 brush = CreateSolidBrush(RGB(red, green, blue));
1227 rect.left = x + g_xoff - g_xscroll;
1228 rect.top = y + g_yoff - g_yscroll;
1229 rect.right = rect.left + cx;
1230 rect.bottom = rect.top + cy;
1231 FillRect(maindc, &rect, brush);
1232 DeleteObject(brush);
1233 ReleaseDC(g_Wnd, maindc);
1234 DeleteObject(rgn);
1235 }
1236
1237 /*****************************************************************************/
1238 void
1239 mi_line(int x1, int y1, int x2, int y2, int colour)
1240 {
1241 HPEN pen;
1242 HDC maindc;
1243 HGDIOBJ save;
1244 HRGN rgn;
1245 int red;
1246 int green;
1247 int blue;
1248
1249 if (g_server_depth == 8)
1250 {
1251 red = (pal_entries[colour & 0xff] & 0xff0000) >> 16;
1252 green = (pal_entries[colour & 0xff] & 0xff00) >> 8;
1253 blue = pal_entries[colour & 0xff] & 0xff;
1254 }
1255 else if (g_server_depth == 15)
1256 {
1257 SPLIT_COLOUR15(colour, red, green, blue);
1258 }
1259 else if (g_server_depth == 16)
1260 {
1261 SPLIT_COLOUR16(colour, red, green, blue);
1262 }
1263 else if (g_server_depth == 24 || g_server_depth == 32)
1264 {
1265 red = (colour>>16)&0xff;
1266 green = (colour>>8)&0xff;
1267 blue = colour&0xff;
1268 }
1269 maindc = GetWindowDC(g_Wnd);
1270 rgn = mi_clip(maindc);
1271 pen = CreatePen(PS_SOLID, 0, RGB(red, green, blue));
1272 save = SelectObject(maindc, pen);
1273 MoveToEx(maindc, x1 + g_xoff - g_xscroll, y1 + g_yoff - g_yscroll, 0);
1274 LineTo(maindc, x2 + g_xoff - g_xscroll, y2 + g_yoff - g_yscroll);
1275 SelectObject(maindc, save);
1276 DeleteObject(pen);
1277 ReleaseDC(g_Wnd, maindc);
1278 DeleteObject(rgn);
1279 }
1280
1281 /*****************************************************************************/
1282 void
1283 mi_screen_copy(int x, int y, int cx, int cy, int srcx, int srcy)
1284 {
1285 RECT rect;
1286 RECT clip_rect;
1287 RECT draw_rect;
1288 HRGN rgn;
1289 int ok_to_ScrollWindowEx;
1290
1291 ok_to_ScrollWindowEx = 1;
1292
1293 if (!ok_to_ScrollWindowEx)
1294 {
1295 rgn = CreateRectRgn(x - g_xscroll, y - g_yscroll,
1296 (x - g_xscroll) + cx,
1297 (y - g_yscroll) + cy);
1298 InvalidateRgn(g_Wnd, rgn, 0);
1299 DeleteObject(rgn);
1300 }
1301 else
1302 {
1303 /* this is all in client coords */
1304 rect.left = srcx - g_xscroll;
1305 rect.top = srcy - g_yscroll;
1306 rect.right = rect.left + cx;
1307 rect.bottom = rect.top + cy;
1308 clip_rect.left = g_clip_left - g_xscroll;
1309 clip_rect.top = g_clip_top - g_yscroll;
1310 clip_rect.right = g_clip_right - g_xscroll;
1311 clip_rect.bottom = g_clip_bottom - g_yscroll;
1312 if (IntersectRect(&draw_rect, &clip_rect, &g_wnd_clip))
1313 {
1314 rgn = CreateRectRgn(0, 0, 0, 0);
1315 ScrollWindowEx(g_Wnd, x - srcx, y - srcy, &rect, &draw_rect,
1316 rgn, 0, SW_ERASE);
1317 InvalidateRgn(g_Wnd, rgn, 0);
1318 DeleteObject(rgn);
1319 }
1320 }
1321 }
1322
1323 /*****************************************************************************/
1324 void
1325 mi_set_clip(int x, int y, int cx, int cy)
1326 {
1327 g_clip_left = x;
1328 g_clip_top = y;
1329 g_clip_right = g_clip_left + cx;
1330 g_clip_bottom = g_clip_top + cy;
1331 }
1332
1333 /*****************************************************************************/
1334 void
1335 mi_reset_clip(void)
1336 {
1337 g_clip_left = 0;
1338 g_clip_top = 0;
1339 g_clip_right = g_clip_left + g_width;
1340 g_clip_bottom = g_clip_top + g_height;
1341 }
1342
1343 /*****************************************************************************/
1344 void *
1345 mi_create_cursor(unsigned int x, unsigned int y,
1346 int width, int height,
1347 unsigned char * andmask, unsigned char * xormask)
1348 {
1349 HCURSOR hCur;
1350
1351 hCur = CreateCursor(g_Instance, x, y, width, height, andmask, xormask);
1352 if (hCur == 0)
1353 {
1354 hCur = LoadCursor(NULL, IDC_ARROW);
1355 }
1356 return hCur;
1357 }
1358
1359 /*****************************************************************************/
1360 void
1361 mi_destroy_cursor(void * cursor)
1362 {
1363 if (g_cursor == cursor)
1364 {
1365 g_cursor = 0;
1366 }
1367 DestroyCursor(cursor);
1368 }
1369
1370 /*****************************************************************************/
1371 void
1372 mi_set_cursor(void * cursor)
1373 {
1374 g_cursor = cursor;
1375 SetCursor(g_cursor);
1376 }
1377
1378 /*****************************************************************************/
1379 void
1380 mi_set_null_cursor(void)
1381 {
1382 }
1383