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