- Bless halxbox too.
[reactos.git] / rosky / lib / libskygi / libskygi.c
1 /*
2 * ROSky - SkyOS Application Layer
3 * Copyright (C) 2004 ReactOS Team
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 /* $Id$
20 *
21 * PROJECT: SkyOS GI library
22 * FILE: lib/libskygi/libskygi.c
23 * PURPOSE: SkyOS GI library
24 *
25 * UPDATE HISTORY:
26 * 08/12/2004 Created
27 */
28 #include <windows.h>
29 #include <stdio.h>
30 #include <rosky.h>
31 #include "libskygi.h"
32 #include "resource.h"
33
34 #define NDEBUG
35 #include <debug.h>
36
37 typedef struct
38 {
39 s_window Window;
40 HWND hWnd;
41 BOOL MouseInput;
42 } SKY_WINDOW, *PSKY_WINDOW;
43
44 typedef struct
45 {
46 widget_menu Menu;
47 HMENU hMenu;
48 } SKY_MENU, *PSKY_MENU;
49
50 typedef struct
51 {
52 widget_menu_item MenuItem;
53 MENUITEMINFOW MenuItemInfo;
54 } SKY_MENUITEM, *PSKY_MENUITEM;
55
56 typedef struct
57 {
58 GC GraphicsContext;
59 HDC hDC;
60 } SKY_GC, *PSKY_GC;
61
62 typedef struct
63 {
64 DIB Dib;
65 HBITMAP hBitmap;
66 HDC hAssociateDC;
67 } SKY_DIB, *PSKY_DIB;
68
69 static ATOM SkyClassAtom;
70 static BOOL SkyClassRegistered = FALSE;
71
72 /**
73 * Map a SkyOS window style to Windows one.
74 *
75 * @param SkyStyle SkyOS window style (WF_* flags).
76 * @param ExStyle Contains Windows extended window style on exit.
77 *
78 * @return Windows window style (WS_* flags).
79 *
80 * @todo Handle
81 * WF_MODAL, WF_HAS_MENU, WF_HAS_STATUSBAR, WF_FREEFORM, WF_FOCUSABLE,
82 * WF_USER, WF_DESKTOP, WF_NOT_MOVEABLE, WF_NO_BUTTONS, WF_TRANSPARENT,
83 * WF_NO_INITIAL_DRAW, WF_USE_BACKGROUND, WF_DONT_EREASE_BACKGROUND,
84 * WF_NO_FRAME.
85 */
86 ULONG
87 IntMapWindowStyle(ULONG SkyStyle, ULONG *ExStyle)
88 {
89 ULONG Style;
90
91 Style = (SkyStyle & WF_HIDE) ? 0 : WS_VISIBLE;
92 Style |= (SkyStyle & WF_NO_TITLE) ? 0 : WS_CAPTION;
93 Style |= (SkyStyle & WF_NOT_SIZEABLE) ? WS_THICKFRAME : 0;
94 Style |= (SkyStyle & WF_POPUP) ? WS_POPUP : 0;
95 Style |= (SkyStyle & WF_NO_BUTTONS) ? 0 :
96 ((SkyStyle & WF_NOT_SIZEABLE) ? 0 : WS_MAXIMIZEBOX) |
97 WS_MINIMIZEBOX | WS_SYSMENU;
98 *ExStyle = (SkyStyle & WF_SMALL_TITLE) ? WS_EX_TOOLWINDOW : 0;
99
100 return Style;
101 }
102
103
104 /**
105 * Dispatch a Sky Message to the appropriate window callback
106 *
107 * @param win Specifies the destination window
108 * @param type The type of the message (see MSG_ constants)
109 * @param para1 Additional parameter 1
110 * @param para2 Additional parameter 2
111 *
112 * @return Returns the return value of the window callback function
113 */
114 unsigned long
115 IntDispatchMsg(s_window *win, unsigned int type, unsigned int para1, unsigned int para2)
116 {
117 s_gi_msg msg;
118 unsigned long Ret;
119
120 /* fill the members of the struct */
121 msg.win = win;
122 msg.type = type;
123 msg.para1 = para1;
124 msg.para2 = para2;
125 msg.next = NULL; /* ??? */
126 msg.prev = NULL; /* ??? */
127 /* FIXME */
128 msg.timestamp = (unsigned long long)GetTickCount() * 1000LL;
129
130 DBG("Dispatching window (0x%x) message type %d\n", win, type);
131 Ret = win->win_func(win, &msg);
132 DBG("Dispatched window (0x%x) message type %d, returned 0x%x\n", win, type, Ret);
133 return Ret;
134 }
135
136
137 /**
138 * Dispatch a Sky Message with a update rect to the appropriate window callback
139 *
140 * @param win Specifies the destination window
141 * @param type The type of the message (see MSG_ constants)
142 * @param para1 Additional parameter 1
143 * @param para2 Additional parameter 2
144 * @param rect Rectangle of the window to be repainted
145 *
146 * @return Returns the return value of the window callback function
147 */
148 unsigned long
149 IntDispatchMsgRect(s_window *win, unsigned int type, unsigned int para1, unsigned int para2, s_region *rect)
150 {
151 s_gi_msg msg;
152 unsigned long Ret;
153
154 /* fill the members of the struct */
155 msg.win = win;
156 msg.type = type;
157 msg.para1 = para1;
158 msg.para2 = para2;
159 msg.next = NULL; /* ??? */
160 msg.prev = NULL; /* ??? */
161 msg.rect = *rect;
162 /* FIXME */
163 msg.timestamp = (unsigned long long)GetTickCount() * 1000LL;
164
165 DBG("Dispatching window (0x%x) message type %d\n", win, type);
166 Ret = win->win_func(win, &msg);
167 DBG("Dispatched window (0x%x) message type %d, returned 0x%x\n", win, type, Ret);
168 return Ret;
169 }
170
171
172 /**
173 * Determines whether a win32 message should cause a Sky message to be dispatched
174 *
175 * @param skw Specifies the destination window
176 * @param Msg Contains the win32 message
177 * @param smsg Address to the sky message structure that will be filled in with
178 * appropriate information in case a sky message should be dispatched
179 *
180 * @return Returns TRUE if a Sky message should be dispatched
181 */
182 BOOL
183 IntIsSkyMessage(PSKY_WINDOW skw, MSG *Msg, s_gi_msg *smsg)
184 {
185 smsg->win = skw;
186
187 switch(Msg->message)
188 {
189 case WM_DESTROY:
190 smsg->type = MSG_DESTROY;
191 smsg->para1 = 0;
192 smsg->para2 = 0;
193 return TRUE;
194
195 case WM_PAINT:
196 {
197 RECT rc;
198 PAINTSTRUCT ps;
199
200 if(GetUpdateRect(skw->hWnd, &rc, FALSE))
201 {
202 BeginPaint(skw->hWnd, &ps);
203 EndPaint(skw->hWnd, &ps);
204
205 smsg->type = MSG_GUI_REDRAW;
206 smsg->para1 = 0;
207 smsg->para2 = 0;
208
209 smsg->rect.x1 = rc.left;
210 smsg->rect.y1 = rc.top;
211 smsg->rect.x2 = rc.right;
212 smsg->rect.y2 = rc.bottom;
213
214 return TRUE;
215 }
216 break;
217 }
218
219 case WM_QUIT:
220 smsg->type = MSG_QUIT;
221 smsg->para1 = 0;
222 smsg->para2 = 0;
223 return TRUE;
224
225 case WM_COMMAND:
226 smsg->type = MSG_COMMAND;
227 smsg->para1 = LOWORD(Msg->wParam);
228 return TRUE;
229
230 case WM_MOUSEMOVE:
231 if(skw->MouseInput)
232 {
233 smsg->type = MSG_MOUSE_MOVED;
234 goto DoMouseInputMessage;
235 }
236 break;
237
238 case WM_LBUTTONDOWN:
239 smsg->type = MSG_MOUSE_BUT1_PRESSED;
240 goto DoMouseInputMessage;
241
242 case WM_LBUTTONUP:
243 smsg->type = MSG_MOUSE_BUT1_RELEASED;
244 goto DoMouseInputMessage;
245
246 case WM_RBUTTONDOWN:
247 smsg->type = MSG_MOUSE_BUT2_PRESSED;
248 goto DoMouseInputMessage;
249
250 case WM_RBUTTONUP:
251 {
252 POINT pt;
253
254 smsg->type = MSG_MOUSE_BUT2_RELEASED;
255
256 DoMouseInputMessage:
257 #if 0
258 pt.x = LOWORD(Msg->lParam);
259 pt.y = HIWORD(Msg->lParam);
260 #else
261 pt = Msg->pt;
262 MapWindowPoints(NULL, skw->hWnd, &pt, 1);
263 #endif
264 smsg->para1 = pt.x;
265 smsg->para2 = pt.y;
266 return TRUE;
267 }
268 }
269
270 return FALSE;
271 }
272
273
274 /**
275 * The standard win32 window procedure that handles win32 messages delivered from ReactOS
276 *
277 * @param hWnd Handle of the window
278 * @param msg Specifies the type of the message
279 * @param wParam Additional data to the message
280 * @param lParam Additional data to the message
281 *
282 * @return Depends on the message type
283 */
284 LRESULT CALLBACK
285 IntDefaultWin32Proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
286 {
287 PSKY_WINDOW skw;
288
289 if (msg == WM_NCCREATE)
290 {
291 /*
292 * Save the pointer to the structure so we can access it later when
293 * dispatching the Win32 messages so we know which sky window it is
294 * and dispatch the right messages.
295 */
296 skw = (PSKY_WINDOW)((LPCREATESTRUCTW)lParam)->lpCreateParams;
297 SetWindowLongPtr(hWnd, GWL_USERDATA, (ULONG_PTR)skw);
298 }
299 else
300 {
301 skw = (PSKY_WINDOW)GetWindowLongPtr(hWnd, GWL_USERDATA);
302 if (skw == NULL)
303 return DefWindowProcW(hWnd, msg, wParam, lParam);
304 }
305
306 switch(msg)
307 {
308 case WM_CLOSE:
309 IntDispatchMsg(&skw->Window, MSG_DESTROY, 0, 0);
310 return 0;
311
312 case WM_CREATE:
313 return 1;
314
315 /* FIXME: Find a more general solution! */
316 /* We can get there for message sent by SendMessage. */
317 case WM_PAINT:
318 {
319 PAINTSTRUCT ps;
320 s_region srect;
321
322 BeginPaint(hWnd, &ps);
323 srect.x1 = ps.rcPaint.left;
324 srect.y1 = ps.rcPaint.top;
325 srect.x2 = ps.rcPaint.right;
326 srect.y2 = ps.rcPaint.bottom;
327 IntDispatchMsgRect(&skw->Window, MSG_GUI_REDRAW, 0, 0, &srect);
328 EndPaint(hWnd, &ps);
329
330 return 0;
331 }
332
333 case WM_COMMAND:
334 IntDispatchMsg(&skw->Window, MSG_COMMAND, LOWORD(wParam), 0);
335 return 0;
336
337 case WM_ERASEBKGND:
338 return 1; /* don't handle this message */
339 }
340
341 return DefWindowProcW(hWnd, msg, wParam, lParam);
342 }
343
344
345 /**
346 * Registers a Win32 window class for all Sky windows
347 *
348 * @return Returns the atom of the class registered.
349 */
350 ATOM
351 IntRegisterClass(void)
352 {
353 WNDCLASSW wc;
354
355 wc.lpszClassName = L"ROSkyWindow";
356 wc.lpfnWndProc = IntDefaultWin32Proc;
357 wc.style = CS_VREDRAW | CS_HREDRAW;
358 wc.hInstance = GetModuleHandleW(NULL);
359 wc.hIcon = LoadIcon(NULL, (LPCTSTR)IDI_APPLICATION);
360 wc.hCursor = LoadCursor(NULL, (LPCTSTR)IDC_ARROW);
361 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
362 wc.lpszMenuName = NULL;
363 wc.cbClsExtra = 0;
364 wc.cbWndExtra = 0;
365
366 return RegisterClassW(&wc);
367 }
368
369
370 /*
371 * @implemented
372 */
373 s_window* __cdecl
374 GI_create_app(app_para *p)
375 {
376 PSKY_WINDOW skw;
377 ULONG Style, ExStyle;
378 WCHAR WindowName[sizeof(p->cpName) / sizeof(p->cpName[0])];
379 RECT ClientRect;
380
381 DBG("GI_create_app(0x%x)\n", p);
382
383 /* FIXME - lock */
384 if(!SkyClassRegistered)
385 {
386 SkyClassAtom = IntRegisterClass();
387 SkyClassRegistered = SkyClassAtom != 0;
388
389 if(!SkyClassRegistered)
390 {
391 DBG("Unable to register the ROSkyWindow class\n");
392 return NULL;
393 }
394 }
395 /* FIXME - unlock */
396
397 skw = (PSKY_WINDOW)HeapAlloc(GetProcessHeap(),
398 HEAP_ZERO_MEMORY,
399 sizeof(SKY_WINDOW));
400 if(skw == NULL)
401 {
402 DBG("Not enough memory to allocate a SKY_WINDOW structure!\n");
403 return NULL;
404 }
405
406 /* Convert the Sky window style to a Win32 window style */
407 Style = IntMapWindowStyle(p->ulStyle, &ExStyle);
408
409 /* convert the window caption to unicode */
410 MultiByteToWideChar(CP_UTF8, 0, (char*)p->cpName, -1, WindowName,
411 sizeof(WindowName) / sizeof(WindowName[0]));
412
413 skw->Window.win_func = p->win_func;
414 /* FIXME - fill the window structure */
415
416 /*
417 * We must convert the client rect passed in to the window rect expected
418 * by CreateWindowExW.
419 */
420 ClientRect.left = 0;
421 ClientRect.top = 0;
422 ClientRect.right = 0 + p->ulWidth;
423 ClientRect.bottom = 0 + p->ulHeight;
424 AdjustWindowRectEx(&ClientRect, Style, p->ulStyle & WF_HAS_MENU, ExStyle);
425
426 DBG("Menu: %x\n", p->pMenu ? ((PSKY_MENU)p->pMenu)->hMenu : NULL);
427
428 /* create the Win32 window */
429 skw->hWnd = CreateWindowExW(ExStyle,
430 L"ROSkyWindow",
431 WindowName,
432 WS_OVERLAPPEDWINDOW,
433 p->ulX,
434 p->ulY,
435 ClientRect.right - ClientRect.left,
436 ClientRect.bottom - ClientRect.top,
437 NULL,
438 p->pMenu ? ((PSKY_MENU)p->pMenu)->hMenu : NULL,
439 GetModuleHandleW(NULL),
440 skw);
441
442 if(skw->hWnd == NULL)
443 {
444 DBG("CreateWindow() failed!\n");
445 HeapFree(GetProcessHeap(), 0, skw);
446 return NULL;
447 }
448
449 DBG("Created Win32 window: 0x%x\n", skw->hWnd);
450
451 return &skw->Window;
452 }
453
454 /*
455 * @implemented
456 */
457 int __cdecl
458 GI_destroy_window(s_window *win)
459 {
460 PSKY_WINDOW skw = (PSKY_WINDOW)win;
461
462 DBG("GI_destroy_window(0x%x)\n", win);
463 DestroyWindow(skw->hWnd);
464 HeapFree(GetProcessHeap(), 0, skw);
465
466 return 0;
467 }
468
469
470 /*
471 * @implemented
472 */
473 unsigned int __cdecl
474 GI_wait_message(s_gi_msg *m,
475 s_window* w)
476 {
477 MSG Msg;
478 BOOL Ret, SkyMessage;
479 HWND hwndFilter;
480 PSKY_WINDOW msgwnd;
481
482 DBG("GI_wait_message(0x%x, 0x%x)\n", m, w);
483
484 hwndFilter = (w != NULL ? ((PSKY_WINDOW)w)->hWnd : NULL);
485 do
486 {
487 Ret = GetMessage(&Msg, hwndFilter, 0, 0);
488
489 /* loop until we found a message that a sky app would handle, too */
490 RtlZeroMemory(m, sizeof(s_gi_msg));
491
492 if(Msg.hwnd != NULL && (msgwnd = (PSKY_WINDOW)GetWindowLongPtrW(Msg.hwnd, GWL_USERDATA)))
493 {
494 SkyMessage = IntIsSkyMessage(msgwnd, &Msg, m);
495 }
496 else
497 {
498 SkyMessage = FALSE;
499 }
500
501 if (!SkyMessage)
502 {
503 /* We're not interested in dispatching a sky message, try again */
504 TranslateMessage(&Msg);
505 DispatchMessage(&Msg);
506 }
507 }
508 while (!SkyMessage);
509
510 return Ret;
511 }
512
513
514 /*
515 * @implemented
516 */
517 int __cdecl
518 GI_dispatch_message(s_window *win,
519 s_gi_msg *m)
520 {
521 PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
522 DBG("GI_dispatch_message(0x%x, 0x%x - %d)\n", win, m, m->type);
523 /* dispatch the SkyOS message to the SkyOS window procedure */
524 if (skywnd != 0)
525 return skywnd->Window.win_func(win, m);
526 return 1;
527 }
528
529
530 /*
531 * @implemented
532 */
533 HRESULT __cdecl
534 GI_ShowApplicationWindow(s_window *win)
535 {
536 PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
537 DBG("GI_ShowApplicationWindow(0x%x)\n", win);
538 ShowWindow(skywnd->hWnd, SW_SHOW);
539 return 1;
540 }
541
542
543 /*
544 * @implemented
545 */
546 int __cdecl
547 GI_redraw_window(s_window *win)
548 {
549 PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
550 DBG("GI_redraw_window(0x%x)!\n", win);
551 if(skywnd != NULL)
552 {
553 RedrawWindow(skywnd->hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
554 }
555 return 1;
556 }
557
558
559 /*
560 * @implemented
561 */
562 void __cdecl
563 GI_post_quit(s_window *win)
564 {
565 DBG("GI_post_quit(0x%x)\n", win);
566 PostMessage(((PSKY_WINDOW)win)->hWnd, WM_QUIT, 0, 0);
567 }
568
569
570 /*
571 * @implemented
572 */
573 sCreateApplication* __cdecl
574 GI_CreateApplicationStruct(void)
575 {
576 sCreateApplication *app;
577
578 app = (sCreateApplication*)HeapAlloc(GetProcessHeap(),
579 HEAP_ZERO_MEMORY,
580 sizeof(sCreateApplication));
581 STUB("GI_CreateApplicationStruct() returns 0x%x (allocated structure on the heap)!\n", app);
582
583 return app;
584 }
585
586
587 /*
588 * @implemented
589 */
590 int __cdecl
591 GI_GetWindowX(s_window *win)
592 {
593 RECT rc;
594 PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
595 if((skywnd != NULL) && GetWindowRect(skywnd->hWnd, &rc))
596 {
597 MapWindowPoints(HWND_DESKTOP, GetParent(skywnd->hWnd), (LPPOINT)&rc, 2);
598 DBG("GI_GetWindowS(0x%x) returns %d!\n", win, rc.left);
599 return rc.left;
600 }
601 #if DEBUG
602 else
603 {
604 DBG("GI_GetWindowS(0x%x) failed!\n", win);
605 }
606 #endif
607 return 0;
608 }
609
610
611 /*
612 * @implemented
613 */
614 int __cdecl
615 GI_GetWindowY(s_window *win)
616 {
617 RECT rc;
618 PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
619 if((skywnd != NULL) && GetWindowRect(skywnd->hWnd, &rc))
620 {
621 MapWindowPoints(HWND_DESKTOP, GetParent(skywnd->hWnd), (LPPOINT)&rc, 2);
622 DBG("GI_GetWindowY(0x%x) returns %d!\n", win, rc.top);
623 return rc.left;
624 }
625 #if DEBUG
626 else
627 {
628 DBG("GI_GetWindowY(0x%x) failed!\n", win);
629 }
630 #endif
631 return 0;
632 }
633
634
635 /*
636 * @implemented
637 */
638 int __cdecl
639 GI_GetWindowWidth(s_window *win)
640 {
641 RECT rc;
642 PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
643 if((skywnd != NULL) && GetWindowRect(skywnd->hWnd, &rc))
644 {
645 DBG("GI_GetWindowWidth(0x%x) returns %d!\n", win, (rc.right - rc.left));
646 return (rc.right - rc.left);
647 }
648 #if DEBUG
649 else
650 {
651 DBG("GI_GetWindowWidth(0x%x) failed!\n", win);
652 }
653 #endif
654 return 0;
655 }
656
657
658 /*
659 * @implemented
660 */
661 int __cdecl
662 GI_GetWindowHeight(s_window *win)
663 {
664 RECT rc;
665 PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
666 if((skywnd != NULL) && GetWindowRect(skywnd->hWnd, &rc))
667 {
668 DBG("GI_GetWindowHeight(0x%x) returns %d!\n", win, (rc.bottom - rc.top));
669 return (rc.bottom - rc.top);
670 }
671 #if DEBUG
672 else
673 {
674 DBG("GI_GetWindowHeight(0x%x) failed!\n", win);
675 }
676 #endif
677 return 0;
678 }
679
680
681 /*
682 * @unimplemented
683 */
684 s_window* __cdecl
685 GI_GetTopLevelWindow(s_window *win)
686 {
687 STUB("GI_GetTopLevelWindow(0x%x) returns 0x%x!\n", win, win);
688 return win;
689 }
690
691
692 /*
693 * @implemented
694 */
695 DIB* __cdecl
696 GI_create_DIB(void *Data,
697 unsigned int Width,
698 unsigned int Height,
699 unsigned int Bpp,
700 void *Palette,
701 unsigned int PaletteSize)
702 {
703 SKY_DIB *Dib;
704 BITMAPINFO *BitmapInfo;
705
706 DBG("GI_create_DIB(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
707 Data, Width, Height, Bpp, Palette, PaletteSize);
708
709 Dib = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SKY_DIB));
710 if (Dib == NULL)
711 {
712 return NULL;
713 }
714
715 BitmapInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER) +
716 PaletteSize * sizeof(RGBQUAD));
717 if (BitmapInfo == NULL)
718 {
719 HeapFree(GetProcessHeap(), 0, Dib);
720 return NULL;
721 }
722
723 Dib->Dib.color = Bpp;
724 Dib->Dib.width = Width;
725 Dib->Dib.height = Height;
726 Dib->Dib.data = Data;
727 Dib->Dib.palette_size = PaletteSize;
728 Dib->Dib.palette = Palette;
729
730 BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
731 BitmapInfo->bmiHeader.biWidth = Width;
732 BitmapInfo->bmiHeader.biHeight = Height;
733 BitmapInfo->bmiHeader.biPlanes = 1;
734 BitmapInfo->bmiHeader.biBitCount = Bpp;
735 BitmapInfo->bmiHeader.biCompression = BI_RGB;
736 BitmapInfo->bmiHeader.biSizeImage = 0;
737 BitmapInfo->bmiHeader.biXPelsPerMeter = 0;
738 BitmapInfo->bmiHeader.biYPelsPerMeter = 0;
739 BitmapInfo->bmiHeader.biClrUsed = PaletteSize;
740 BitmapInfo->bmiHeader.biClrImportant = 0;
741 RtlCopyMemory(BitmapInfo->bmiColors, Palette, PaletteSize * sizeof(RGBQUAD));
742
743 Dib->hBitmap = CreateDIBSection(NULL,
744 BitmapInfo,
745 DIB_RGB_COLORS,
746 Data,
747 NULL,
748 0);
749 HeapFree(GetProcessHeap(), 0, BitmapInfo);
750 if (Dib->hBitmap == NULL)
751 {
752 HeapFree(GetProcessHeap(), 0, Dib);
753 return NULL;
754 }
755
756 return (DIB*)Dib;
757 }
758
759
760 /*
761 * @implemented
762 */
763 GC* __cdecl
764 GC_create_connected(unsigned int Type,
765 unsigned int Width,
766 unsigned int Height,
767 s_window *Win)
768 {
769 SKY_GC *Gc;
770
771 DBG("GC_create_connected(0x%x, 0x%x, 0x%x, 0x%x)\n",
772 Type, Width, Height, Win);
773
774 if(Win == NULL)
775 {
776 DBG("GC_create_connected: no window specified! returned NULL!\n");
777 return NULL;
778 }
779
780 Gc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SKY_GC));
781 if (Gc == NULL)
782 {
783 return NULL;
784 }
785
786 Gc->GraphicsContext.type = Type;
787 Gc->GraphicsContext.width = Width;
788 Gc->GraphicsContext.height = Height;
789
790 switch (Type)
791 {
792 case GC_TYPE_DIB:
793 Gc->hDC = CreateCompatibleDC(0);
794 if (Gc->hDC)
795 {
796 Gc->GraphicsContext.hDIB = (DIB*)Win;
797 SelectObject(Gc->hDC, ((PSKY_DIB)Win)->hBitmap);
798 ((PSKY_DIB)Win)->hAssociateDC = Gc->hDC;
799 }
800 break;
801
802 case GC_TYPE_WINDOW:
803 Gc->hDC = GetDC(((PSKY_WINDOW)Win)->hWnd);
804 Gc->GraphicsContext.window = Win;
805 break;
806
807 default:
808 DBG("Unknown GC type: %x\n", Type);
809 }
810
811 if (Gc->hDC == NULL)
812 {
813 HeapFree(GetProcessHeap(), 0, Gc);
814 return NULL;
815 }
816 else
817 {
818 SelectObject(Gc->hDC, GetStockObject(DC_BRUSH));
819 SelectObject(Gc->hDC, GetStockObject(DC_PEN));
820 }
821
822 return (GC*)Gc;
823 }
824
825
826 /*
827 * @implemented
828 */
829 int __cdecl
830 GC_set_fg_color(GC *Gc,
831 COLOR Color)
832 {
833 if(Gc != NULL)
834 {
835 Gc->fg_color = Color;
836 SetDCPenColor(((PSKY_GC)Gc)->hDC, Color);
837 return 1;
838 }
839 #if DEBUG
840 else
841 {
842 DBG("GC_set_fg_color: Gc == NULL!\n");
843 }
844 #endif
845 return 0;
846 }
847
848
849 /*
850 * @implemented
851 */
852 int __cdecl
853 GC_set_bg_color(GC *Gc,
854 COLOR Color)
855 {
856 if(Gc != NULL)
857 {
858 Gc->bg_color = Color;
859 SetDCBrushColor(((PSKY_GC)Gc)->hDC, Color);
860 return 1;
861 }
862 #if DEBUG
863 else
864 {
865 DBG("GC_set_bg_color: Gc == NULL!\n");
866 }
867 #endif
868 return 0;
869 }
870
871
872 /*
873 * @implemented
874 */
875 int __cdecl
876 GC_draw_pixel(GC *Gc,
877 int X,
878 int Y)
879 {
880 if(Gc != NULL)
881 {
882 SetPixelV(((PSKY_GC)Gc)->hDC, X, Y, Gc->fg_color);
883 return 1;
884 }
885 #if DEBUG
886 else
887 {
888 DBG("GC_draw_pixel: Gc == NULL!\n");
889 }
890 #endif
891 return 0;
892 }
893
894
895 /*
896 * @implemented
897 */
898 int __cdecl
899 GC_blit_from_DIB(GC *Gc,
900 DIB *Dib,
901 int X,
902 int Y)
903 {
904 int Result;
905 HDC hSrcDC;
906 HBITMAP hOldBitmap = NULL;
907
908 DBG("GC_blit_from_DIB(0x%x, 0x%x, 0x%x, 0x%x)\n", Gc, Dib, X, Y);
909
910 if (((PSKY_DIB)Dib)->hAssociateDC == NULL)
911 {
912 hSrcDC = CreateCompatibleDC(0);
913 hOldBitmap = SelectObject(hSrcDC, ((PSKY_DIB)Dib)->hBitmap);
914 }
915 else
916 {
917 hSrcDC = ((PSKY_DIB)Dib)->hAssociateDC;
918 }
919
920 Result = BitBlt(((PSKY_GC)Gc)->hDC, X, Y, Dib->width, Dib->height,
921 hSrcDC, 0, 0, SRCCOPY);
922
923 if (((PSKY_DIB)Dib)->hAssociateDC == NULL)
924 {
925 SelectObject(hSrcDC, hOldBitmap);
926 DeleteDC(hSrcDC);
927 }
928
929 return !Result;
930 }
931
932
933 /*
934 * @implemented
935 */
936 int __cdecl
937 GC_draw_rect_fill(GC *Gc,
938 int X,
939 int Y,
940 int Width,
941 int Height)
942 {
943 DBG("GC_draw_rect_fill(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
944 Gc, X, Y, Width, Height);
945
946 if(Gc != NULL)
947 {
948 HBRUSH hBrush;
949 RECT Rect;
950
951 Rect.left = X;
952 Rect.top = Y;
953 Rect.right = X + Width;
954 Rect.bottom = Y + Height;
955
956 hBrush = CreateSolidBrush(Gc->bg_color);
957 FillRect(((PSKY_GC)Gc)->hDC, &Rect, hBrush);
958 DeleteObject(hBrush);
959
960 return 1;
961 }
962 #if DEBUG
963 else
964 {
965 DBG("GC_draw_rect_fill: Gc == NULL!\n");
966 }
967 #endif
968 return 0;
969 }
970
971
972 /*
973 * @implemented
974 */
975 int __cdecl
976 GC_draw_line(GC *Gc,
977 int x1,
978 int y1,
979 int x2,
980 int y2)
981 {
982 DBG("GC_draw_line(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", Gc, x1, y1, x2, y2);
983 if(Gc != NULL)
984 {
985 MoveToEx(((PSKY_GC)Gc)->hDC, x1, y1, NULL);
986 LineTo(((PSKY_GC)Gc)->hDC, x2, y2);
987 return 1;
988 }
989 #if DEBUG
990 else
991 {
992 DBG("GC_draw_line: Gc == NULL!\n");
993 }
994 #endif
995 return 0;
996 }
997
998
999 /*
1000 * @implemented
1001 */
1002 int __cdecl
1003 GC_destroy(GC *Gc)
1004 {
1005 DBG("GC_destroy(0x%x)\n", Gc);
1006 if (Gc != NULL)
1007 {
1008 switch (Gc->type)
1009 {
1010 case GC_TYPE_DIB:
1011 DeleteDC(((PSKY_GC)Gc)->hDC);
1012 break;
1013
1014 case GC_TYPE_WINDOW:
1015 ReleaseDC(((PSKY_WINDOW)Gc->window)->hWnd, ((PSKY_GC)Gc)->hDC);
1016 break;
1017
1018 default:
1019 DBG("Unknown GC type: %x\n", Gc->type);
1020 }
1021 HeapFree(GetProcessHeap(), 0, Gc);
1022 return 1;
1023 }
1024 #if DEBUG
1025 else
1026 {
1027 DBG("GC_destroy: Gc == NULL!\n");
1028 }
1029 #endif
1030 return 0;
1031 }
1032
1033
1034 /*
1035 * @implemented
1036 */
1037 widget_menu* __cdecl
1038 GI_create_menu(s_window *win)
1039 {
1040 PSKY_MENU Menu;
1041
1042 DBG("GI_create_menu(0x%x)\n", win);
1043
1044 Menu = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SKY_MENU));
1045 if (Menu == NULL)
1046 {
1047 return NULL;
1048 }
1049
1050 /* Shouldn't we use CreatePopupMenu in some cases? */
1051 Menu->hMenu = CreateMenu();
1052 if (Menu->hMenu == NULL)
1053 {
1054 HeapFree(GetProcessHeap(), 0, Menu);
1055 return NULL;
1056 }
1057
1058 if (win)
1059 {
1060 SetMenu(((PSKY_WINDOW)win)->hWnd, Menu->hMenu);
1061 }
1062
1063 return (widget_menu *)Menu;
1064 }
1065
1066
1067 /*
1068 * @implemented
1069 */
1070 widget_menu_item* __cdecl
1071 GI_create_menu_item(unsigned char *Text,
1072 unsigned int Id,
1073 unsigned int Flags,
1074 unsigned int Enabled)
1075 {
1076 PSKY_MENUITEM MenuItem;
1077 ULONG TextLength;
1078
1079 DBG("GI_create_menu_item(0x%x, 0x%x, 0x%x, 0x%x)\n",
1080 Text, Id, Flags, Enabled);
1081
1082 TextLength = MultiByteToWideChar(CP_UTF8, 0, (char*)Text, -1, NULL, 0);
1083 MenuItem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1084 sizeof(SKY_MENUITEM) + TextLength * sizeof(WCHAR));
1085 if (MenuItem == NULL)
1086 {
1087 return NULL;
1088 }
1089
1090 lstrcpyA((char*)MenuItem->MenuItem.text, (char*)Text);
1091 MenuItem->MenuItem.ID = Id;
1092 MenuItem->MenuItem.flags = Flags;
1093 MenuItem->MenuItem.enabled = Enabled;
1094
1095 MenuItem->MenuItemInfo.cbSize = sizeof(MENUITEMINFOW);
1096 MenuItem->MenuItemInfo.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
1097 if (Flags & MENU_SEPERATOR)
1098 MenuItem->MenuItemInfo.fType = MF_SEPARATOR;
1099 else
1100 MenuItem->MenuItemInfo.fType = MF_STRING;
1101 MenuItem->MenuItemInfo.fState = Enabled ? MFS_ENABLED : 0;
1102 MenuItem->MenuItemInfo.wID = Id;
1103 MenuItem->MenuItemInfo.dwTypeData = (LPWSTR)(MenuItem + 1);
1104 MenuItem->MenuItemInfo.cch = TextLength;
1105 MultiByteToWideChar(CP_UTF8, 0, (char*)Text, TextLength, (LPWSTR)(MenuItem + 1),
1106 TextLength);
1107
1108 return (widget_menu_item *)MenuItem;
1109 }
1110
1111
1112 /*
1113 * @implemented
1114 */
1115 int __cdecl
1116 GI_add_menu_item(widget_menu *Menu,
1117 widget_menu_item *Item)
1118 {
1119 DBG("GI_add_menu_item(0x%x, 0x%x)\n", Menu, Item);
1120 InsertMenuItemW(((PSKY_MENU)Menu)->hMenu, -1, TRUE,
1121 &((PSKY_MENUITEM)Item)->MenuItemInfo);
1122 return 1;
1123 }
1124
1125
1126 /*
1127 * @implemented
1128 */
1129 int __cdecl
1130 GI_add_menu_sub(widget_menu *Menu,
1131 widget_menu_item *Item,
1132 widget_menu *Sub)
1133 {
1134 PSKY_MENUITEM MenuItem = (PSKY_MENUITEM)Item;
1135
1136 DBG("GI_add_menu_sub(0x%x, 0x%x, 0x%x)\n", Menu, Item, Sub);
1137 MenuItem->MenuItemInfo.fMask |= MIIM_SUBMENU;
1138 MenuItem->MenuItemInfo.hSubMenu = ((PSKY_MENU)Sub)->hMenu;
1139 InsertMenuItemW(((PSKY_MENU)Menu)->hMenu, -1, TRUE,
1140 &MenuItem->MenuItemInfo);
1141 return 1;
1142 }
1143
1144
1145 /*
1146 * @implemented
1147 */
1148 int __cdecl
1149 GI_messagebox(s_window *Window,
1150 unsigned int Flags,
1151 char *Title,
1152 char *Fmt,
1153 ...)
1154 {
1155 CHAR Buffer[4096];
1156 va_list ArgList;
1157 ULONG MbFlags, MbResult;
1158
1159 DBG("GI_messagebox(0x%x, 0x%x, 0x%x, 0x%x, ...)\n",
1160 Window, Flags, Title, Fmt);
1161
1162 va_start(ArgList, Fmt);
1163 _vsnprintf(Buffer, sizeof(Buffer) / sizeof(Buffer[0]), Fmt, ArgList);
1164 va_end(ArgList);
1165
1166 if ((Flags & (WGF_MB_CANCEL | WGF_MB_YESNO)) ==
1167 (WGF_MB_CANCEL | WGF_MB_YESNO))
1168 MbFlags = MB_YESNOCANCEL;
1169 else if (Flags & WGF_MB_YESNO)
1170 MbFlags = MB_YESNO;
1171 else /* if (Flags & WGF_MB_OK) */
1172 MbFlags = MB_OK;
1173 MbFlags |= (Flags & WGF_MB_ICON_INFO) ? MB_ICONASTERISK : 0;
1174 MbFlags |= (Flags & WGF_MB_ICON_ASK) ? MB_ICONQUESTION : 0;
1175 MbFlags |= (Flags & WGF_MB_ICON_STOP) ? MB_ICONERROR : 0;
1176
1177 MbResult = MessageBoxA(Window ? ((PSKY_WINDOW)Window)->hWnd : NULL,
1178 Buffer, Title, MbFlags);
1179
1180 switch (MbResult)
1181 {
1182 case IDOK: return ID_OK;
1183 case IDYES: return ID_YES;
1184 case IDNO: return ID_NO;
1185 case IDCANCEL: return ID_CANCEL;
1186 }
1187
1188 return 0;
1189 }
1190
1191
1192 /*
1193 * @implemented
1194 */
1195 int __cdecl
1196 GI_EnableMouseTracking(s_window *win)
1197 {
1198 DBG("GI_EnableMouseTracking(0x%x)!\n", win);
1199 if(win != NULL)
1200 {
1201 ((PSKY_WINDOW)win)->MouseInput = TRUE;
1202 return 1;
1203 }
1204 #if DEBUG
1205 else
1206 {
1207 DBG("GI_EnableMouseTracking: win == NULL!\n");
1208 }
1209 #endif
1210 return 0;
1211 }
1212
1213 /* EOF */