reactos/rosky/lib/libskygi/libskygi.c

1214 lines
26 KiB
C
Raw Normal View History

/*
* ROSky - SkyOS Application Layer
* Copyright (C) 2004 ReactOS Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$
*
* PROJECT: SkyOS GI library
* FILE: lib/libskygi/libskygi.c
* PURPOSE: SkyOS GI library
*
* UPDATE HISTORY:
* 08/12/2004 Created
*/
#include <windows.h>
#include <stdio.h>
#include <rosky.h>
#include "libskygi.h"
#include "resource.h"
#define NDEBUG
#include <debug.h>
typedef struct
{
s_window Window;
HWND hWnd;
BOOL MouseInput;
} SKY_WINDOW, *PSKY_WINDOW;
typedef struct
{
widget_menu Menu;
HMENU hMenu;
} SKY_MENU, *PSKY_MENU;
typedef struct
{
widget_menu_item MenuItem;
MENUITEMINFOW MenuItemInfo;
} SKY_MENUITEM, *PSKY_MENUITEM;
typedef struct
{
GC GraphicsContext;
HDC hDC;
} SKY_GC, *PSKY_GC;
typedef struct
{
DIB Dib;
HBITMAP hBitmap;
HDC hAssociateDC;
} SKY_DIB, *PSKY_DIB;
static ATOM SkyClassAtom;
static BOOL SkyClassRegistered = FALSE;
/**
* Map a SkyOS window style to Windows one.
*
* @param SkyStyle SkyOS window style (WF_* flags).
* @param ExStyle Contains Windows extended window style on exit.
*
* @return Windows window style (WS_* flags).
*
* @todo Handle
* WF_MODAL, WF_HAS_MENU, WF_HAS_STATUSBAR, WF_FREEFORM, WF_FOCUSABLE,
* WF_USER, WF_DESKTOP, WF_NOT_MOVEABLE, WF_NO_BUTTONS, WF_TRANSPARENT,
* WF_NO_INITIAL_DRAW, WF_USE_BACKGROUND, WF_DONT_EREASE_BACKGROUND,
* WF_NO_FRAME.
*/
ULONG
IntMapWindowStyle(ULONG SkyStyle, ULONG *ExStyle)
{
ULONG Style;
Style = (SkyStyle & WF_HIDE) ? 0 : WS_VISIBLE;
Style |= (SkyStyle & WF_NO_TITLE) ? 0 : WS_CAPTION;
Style |= (SkyStyle & WF_NOT_SIZEABLE) ? WS_THICKFRAME : 0;
Style |= (SkyStyle & WF_POPUP) ? WS_POPUP : 0;
Style |= (SkyStyle & WF_NO_BUTTONS) ? 0 :
((SkyStyle & WF_NOT_SIZEABLE) ? 0 : WS_MAXIMIZEBOX) |
WS_MINIMIZEBOX | WS_SYSMENU;
*ExStyle = (SkyStyle & WF_SMALL_TITLE) ? WS_EX_TOOLWINDOW : 0;
return Style;
}
/**
* Dispatch a Sky Message to the appropriate window callback
*
* @param win Specifies the destination window
* @param type The type of the message (see MSG_ constants)
* @param para1 Additional parameter 1
* @param para2 Additional parameter 2
*
* @return Returns the return value of the window callback function
*/
unsigned long
IntDispatchMsg(s_window *win, unsigned int type, unsigned int para1, unsigned int para2)
{
s_gi_msg msg;
unsigned long Ret;
/* fill the members of the struct */
msg.win = win;
msg.type = type;
msg.para1 = para1;
msg.para2 = para2;
msg.next = NULL; /* ??? */
msg.prev = NULL; /* ??? */
/* FIXME */
msg.timestamp = (unsigned long long)GetTickCount() * 1000LL;
DBG("Dispatching window (0x%x) message type %d\n", win, type);
Ret = win->win_func(win, &msg);
DBG("Dispatched window (0x%x) message type %d, returned 0x%x\n", win, type, Ret);
return Ret;
}
/**
* Dispatch a Sky Message with a update rect to the appropriate window callback
*
* @param win Specifies the destination window
* @param type The type of the message (see MSG_ constants)
* @param para1 Additional parameter 1
* @param para2 Additional parameter 2
* @param rect Rectangle of the window to be repainted
*
* @return Returns the return value of the window callback function
*/
unsigned long
IntDispatchMsgRect(s_window *win, unsigned int type, unsigned int para1, unsigned int para2, s_region *rect)
{
s_gi_msg msg;
unsigned long Ret;
/* fill the members of the struct */
msg.win = win;
msg.type = type;
msg.para1 = para1;
msg.para2 = para2;
msg.next = NULL; /* ??? */
msg.prev = NULL; /* ??? */
msg.rect = *rect;
/* FIXME */
msg.timestamp = (unsigned long long)GetTickCount() * 1000LL;
DBG("Dispatching window (0x%x) message type %d\n", win, type);
Ret = win->win_func(win, &msg);
DBG("Dispatched window (0x%x) message type %d, returned 0x%x\n", win, type, Ret);
return Ret;
}
/**
* Determines whether a win32 message should cause a Sky message to be dispatched
*
* @param skw Specifies the destination window
* @param Msg Contains the win32 message
* @param smsg Address to the sky message structure that will be filled in with
* appropriate information in case a sky message should be dispatched
*
* @return Returns TRUE if a Sky message should be dispatched
*/
BOOL
IntIsSkyMessage(PSKY_WINDOW skw, MSG *Msg, s_gi_msg *smsg)
{
smsg->win = skw;
switch(Msg->message)
{
case WM_DESTROY:
smsg->type = MSG_DESTROY;
smsg->para1 = 0;
smsg->para2 = 0;
return TRUE;
case WM_PAINT:
{
RECT rc;
PAINTSTRUCT ps;
if(GetUpdateRect(skw->hWnd, &rc, FALSE))
{
BeginPaint(skw->hWnd, &ps);
EndPaint(skw->hWnd, &ps);
smsg->type = MSG_GUI_REDRAW;
smsg->para1 = 0;
smsg->para2 = 0;
smsg->rect.x1 = rc.left;
smsg->rect.y1 = rc.top;
smsg->rect.x2 = rc.right;
smsg->rect.y2 = rc.bottom;
return TRUE;
}
break;
}
case WM_QUIT:
smsg->type = MSG_QUIT;
smsg->para1 = 0;
smsg->para2 = 0;
return TRUE;
case WM_COMMAND:
smsg->type = MSG_COMMAND;
smsg->para1 = LOWORD(Msg->wParam);
return TRUE;
case WM_MOUSEMOVE:
if(skw->MouseInput)
{
smsg->type = MSG_MOUSE_MOVED;
goto DoMouseInputMessage;
}
break;
case WM_LBUTTONDOWN:
smsg->type = MSG_MOUSE_BUT1_PRESSED;
goto DoMouseInputMessage;
case WM_LBUTTONUP:
smsg->type = MSG_MOUSE_BUT1_RELEASED;
goto DoMouseInputMessage;
case WM_RBUTTONDOWN:
smsg->type = MSG_MOUSE_BUT2_PRESSED;
goto DoMouseInputMessage;
case WM_RBUTTONUP:
{
POINT pt;
smsg->type = MSG_MOUSE_BUT2_RELEASED;
DoMouseInputMessage:
#if 0
pt.x = LOWORD(Msg->lParam);
pt.y = HIWORD(Msg->lParam);
#else
pt = Msg->pt;
MapWindowPoints(NULL, skw->hWnd, &pt, 1);
#endif
smsg->para1 = pt.x;
smsg->para2 = pt.y;
return TRUE;
}
}
return FALSE;
}
/**
* The standard win32 window procedure that handles win32 messages delivered from ReactOS
*
* @param hWnd Handle of the window
* @param msg Specifies the type of the message
* @param wParam Additional data to the message
* @param lParam Additional data to the message
*
* @return Depends on the message type
*/
LRESULT CALLBACK
IntDefaultWin32Proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
PSKY_WINDOW skw;
if (msg == WM_NCCREATE)
{
/*
* Save the pointer to the structure so we can access it later when
* dispatching the Win32 messages so we know which sky window it is
* and dispatch the right messages.
*/
skw = (PSKY_WINDOW)((LPCREATESTRUCTW)lParam)->lpCreateParams;
SetWindowLongPtr(hWnd, GWL_USERDATA, (ULONG_PTR)skw);
}
else
{
skw = (PSKY_WINDOW)GetWindowLongPtr(hWnd, GWL_USERDATA);
if (skw == NULL)
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
switch(msg)
{
case WM_CLOSE:
IntDispatchMsg(&skw->Window, MSG_DESTROY, 0, 0);
return 0;
case WM_CREATE:
return 1;
/* FIXME: Find a more general solution! */
/* We can get there for message sent by SendMessage. */
case WM_PAINT:
{
PAINTSTRUCT ps;
s_region srect;
BeginPaint(hWnd, &ps);
srect.x1 = ps.rcPaint.left;
srect.y1 = ps.rcPaint.top;
srect.x2 = ps.rcPaint.right;
srect.y2 = ps.rcPaint.bottom;
IntDispatchMsgRect(&skw->Window, MSG_GUI_REDRAW, 0, 0, &srect);
EndPaint(hWnd, &ps);
return 0;
}
case WM_COMMAND:
IntDispatchMsg(&skw->Window, MSG_COMMAND, LOWORD(wParam), 0);
return 0;
case WM_ERASEBKGND:
return 1; /* don't handle this message */
}
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
/**
* Registers a Win32 window class for all Sky windows
*
* @return Returns the atom of the class registered.
*/
ATOM
IntRegisterClass(void)
{
WNDCLASSW wc;
wc.lpszClassName = L"ROSkyWindow";
wc.lpfnWndProc = IntDefaultWin32Proc;
wc.style = CS_VREDRAW | CS_HREDRAW;
wc.hInstance = GetModuleHandleW(NULL);
wc.hIcon = LoadIcon(NULL, (LPCTSTR)IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, (LPCTSTR)IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
return RegisterClassW(&wc);
}
/*
* @implemented
*/
s_window* __cdecl
GI_create_app(app_para *p)
{
PSKY_WINDOW skw;
ULONG Style, ExStyle;
WCHAR WindowName[sizeof(p->cpName) / sizeof(p->cpName[0])];
RECT ClientRect;
DBG("GI_create_app(0x%x)\n", p);
/* FIXME - lock */
if(!SkyClassRegistered)
{
SkyClassAtom = IntRegisterClass();
SkyClassRegistered = SkyClassAtom != 0;
if(!SkyClassRegistered)
{
DBG("Unable to register the ROSkyWindow class\n");
return NULL;
}
}
/* FIXME - unlock */
skw = (PSKY_WINDOW)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(SKY_WINDOW));
if(skw == NULL)
{
DBG("Not enough memory to allocate a SKY_WINDOW structure!\n");
return NULL;
}
/* Convert the Sky window style to a Win32 window style */
Style = IntMapWindowStyle(p->ulStyle, &ExStyle);
/* convert the window caption to unicode */
MultiByteToWideChar(CP_UTF8, 0, (char*)p->cpName, -1, WindowName,
sizeof(WindowName) / sizeof(WindowName[0]));
skw->Window.win_func = p->win_func;
/* FIXME - fill the window structure */
/*
* We must convert the client rect passed in to the window rect expected
* by CreateWindowExW.
*/
ClientRect.left = 0;
ClientRect.top = 0;
ClientRect.right = 0 + p->ulWidth;
ClientRect.bottom = 0 + p->ulHeight;
AdjustWindowRectEx(&ClientRect, Style, p->ulStyle & WF_HAS_MENU, ExStyle);
DBG("Menu: %x\n", p->pMenu ? ((PSKY_MENU)p->pMenu)->hMenu : NULL);
/* create the Win32 window */
skw->hWnd = CreateWindowExW(ExStyle,
L"ROSkyWindow",
WindowName,
WS_OVERLAPPEDWINDOW,
p->ulX,
p->ulY,
ClientRect.right - ClientRect.left,
ClientRect.bottom - ClientRect.top,
NULL,
p->pMenu ? ((PSKY_MENU)p->pMenu)->hMenu : NULL,
GetModuleHandleW(NULL),
skw);
if(skw->hWnd == NULL)
{
DBG("CreateWindow() failed!\n");
HeapFree(GetProcessHeap(), 0, skw);
return NULL;
}
DBG("Created Win32 window: 0x%x\n", skw->hWnd);
return &skw->Window;
}
/*
* @implemented
*/
int __cdecl
GI_destroy_window(s_window *win)
{
PSKY_WINDOW skw = (PSKY_WINDOW)win;
DBG("GI_destroy_window(0x%x)\n", win);
DestroyWindow(skw->hWnd);
HeapFree(GetProcessHeap(), 0, skw);
return 0;
}
/*
* @implemented
*/
unsigned int __cdecl
GI_wait_message(s_gi_msg *m,
s_window* w)
{
MSG Msg;
BOOL Ret, SkyMessage;
HWND hwndFilter;
PSKY_WINDOW msgwnd;
DBG("GI_wait_message(0x%x, 0x%x)\n", m, w);
hwndFilter = (w != NULL ? ((PSKY_WINDOW)w)->hWnd : NULL);
do
{
Ret = GetMessage(&Msg, hwndFilter, 0, 0);
/* loop until we found a message that a sky app would handle, too */
RtlZeroMemory(m, sizeof(s_gi_msg));
if(Msg.hwnd != NULL && (msgwnd = (PSKY_WINDOW)GetWindowLongPtrW(Msg.hwnd, GWL_USERDATA)))
{
SkyMessage = IntIsSkyMessage(msgwnd, &Msg, m);
}
else
{
SkyMessage = FALSE;
}
if (!SkyMessage)
{
/* We're not interested in dispatching a sky message, try again */
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
while (!SkyMessage);
return Ret;
}
/*
* @implemented
*/
int __cdecl
GI_dispatch_message(s_window *win,
s_gi_msg *m)
{
PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
DBG("GI_dispatch_message(0x%x, 0x%x - %d)\n", win, m, m->type);
/* dispatch the SkyOS message to the SkyOS window procedure */
if (skywnd != 0)
return skywnd->Window.win_func(win, m);
return 1;
}
/*
* @implemented
*/
HRESULT __cdecl
GI_ShowApplicationWindow(s_window *win)
{
PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
DBG("GI_ShowApplicationWindow(0x%x)\n", win);
ShowWindow(skywnd->hWnd, SW_SHOW);
return 1;
}
/*
* @implemented
*/
int __cdecl
GI_redraw_window(s_window *win)
{
PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
DBG("GI_redraw_window(0x%x)!\n", win);
if(skywnd != NULL)
{
RedrawWindow(skywnd->hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
}
return 1;
}
/*
* @implemented
*/
void __cdecl
GI_post_quit(s_window *win)
{
DBG("GI_post_quit(0x%x)\n", win);
PostMessage(((PSKY_WINDOW)win)->hWnd, WM_QUIT, 0, 0);
}
/*
* @implemented
*/
sCreateApplication* __cdecl
GI_CreateApplicationStruct(void)
{
sCreateApplication *app;
app = (sCreateApplication*)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(sCreateApplication));
STUB("GI_CreateApplicationStruct() returns 0x%x (allocated structure on the heap)!\n", app);
return app;
}
/*
* @implemented
*/
int __cdecl
GI_GetWindowX(s_window *win)
{
RECT rc;
PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
if((skywnd != NULL) && GetWindowRect(skywnd->hWnd, &rc))
{
MapWindowPoints(HWND_DESKTOP, GetParent(skywnd->hWnd), (LPPOINT)&rc, 2);
DBG("GI_GetWindowS(0x%x) returns %d!\n", win, rc.left);
return rc.left;
}
#if DEBUG
else
{
DBG("GI_GetWindowS(0x%x) failed!\n", win);
}
#endif
return 0;
}
/*
* @implemented
*/
int __cdecl
GI_GetWindowY(s_window *win)
{
RECT rc;
PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
if((skywnd != NULL) && GetWindowRect(skywnd->hWnd, &rc))
{
MapWindowPoints(HWND_DESKTOP, GetParent(skywnd->hWnd), (LPPOINT)&rc, 2);
DBG("GI_GetWindowY(0x%x) returns %d!\n", win, rc.top);
return rc.left;
}
#if DEBUG
else
{
DBG("GI_GetWindowY(0x%x) failed!\n", win);
}
#endif
return 0;
}
/*
* @implemented
*/
int __cdecl
GI_GetWindowWidth(s_window *win)
{
RECT rc;
PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
if((skywnd != NULL) && GetWindowRect(skywnd->hWnd, &rc))
{
DBG("GI_GetWindowWidth(0x%x) returns %d!\n", win, (rc.right - rc.left));
return (rc.right - rc.left);
}
#if DEBUG
else
{
DBG("GI_GetWindowWidth(0x%x) failed!\n", win);
}
#endif
return 0;
}
/*
* @implemented
*/
int __cdecl
GI_GetWindowHeight(s_window *win)
{
RECT rc;
PSKY_WINDOW skywnd = (PSKY_WINDOW)win;
if((skywnd != NULL) && GetWindowRect(skywnd->hWnd, &rc))
{
DBG("GI_GetWindowHeight(0x%x) returns %d!\n", win, (rc.bottom - rc.top));
return (rc.bottom - rc.top);
}
#if DEBUG
else
{
DBG("GI_GetWindowHeight(0x%x) failed!\n", win);
}
#endif
return 0;
}
/*
* @unimplemented
*/
s_window* __cdecl
GI_GetTopLevelWindow(s_window *win)
{
STUB("GI_GetTopLevelWindow(0x%x) returns 0x%x!\n", win, win);
return win;
}
/*
* @implemented
*/
DIB* __cdecl
GI_create_DIB(void *Data,
unsigned int Width,
unsigned int Height,
unsigned int Bpp,
void *Palette,
unsigned int PaletteSize)
{
SKY_DIB *Dib;
BITMAPINFO *BitmapInfo;
DBG("GI_create_DIB(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
Data, Width, Height, Bpp, Palette, PaletteSize);
Dib = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SKY_DIB));
if (Dib == NULL)
{
return NULL;
}
BitmapInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER) +
PaletteSize * sizeof(RGBQUAD));
if (BitmapInfo == NULL)
{
HeapFree(GetProcessHeap(), 0, Dib);
return NULL;
}
Dib->Dib.color = Bpp;
Dib->Dib.width = Width;
Dib->Dib.height = Height;
Dib->Dib.data = Data;
Dib->Dib.palette_size = PaletteSize;
Dib->Dib.palette = Palette;
BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BitmapInfo->bmiHeader.biWidth = Width;
BitmapInfo->bmiHeader.biHeight = Height;
BitmapInfo->bmiHeader.biPlanes = 1;
BitmapInfo->bmiHeader.biBitCount = Bpp;
BitmapInfo->bmiHeader.biCompression = BI_RGB;
BitmapInfo->bmiHeader.biSizeImage = 0;
BitmapInfo->bmiHeader.biXPelsPerMeter = 0;
BitmapInfo->bmiHeader.biYPelsPerMeter = 0;
BitmapInfo->bmiHeader.biClrUsed = PaletteSize;
BitmapInfo->bmiHeader.biClrImportant = 0;
RtlCopyMemory(BitmapInfo->bmiColors, Palette, PaletteSize * sizeof(RGBQUAD));
Dib->hBitmap = CreateDIBSection(NULL,
BitmapInfo,
DIB_RGB_COLORS,
Data,
NULL,
0);
HeapFree(GetProcessHeap(), 0, BitmapInfo);
if (Dib->hBitmap == NULL)
{
HeapFree(GetProcessHeap(), 0, Dib);
return NULL;
}
return (DIB*)Dib;
}
/*
* @implemented
*/
GC* __cdecl
GC_create_connected(unsigned int Type,
unsigned int Width,
unsigned int Height,
s_window *Win)
{
SKY_GC *Gc;
DBG("GC_create_connected(0x%x, 0x%x, 0x%x, 0x%x)\n",
Type, Width, Height, Win);
if(Win == NULL)
{
DBG("GC_create_connected: no window specified! returned NULL!\n");
return NULL;
}
Gc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SKY_GC));
if (Gc == NULL)
{
return NULL;
}
Gc->GraphicsContext.type = Type;
Gc->GraphicsContext.width = Width;
Gc->GraphicsContext.height = Height;
switch (Type)
{
case GC_TYPE_DIB:
Gc->hDC = CreateCompatibleDC(0);
if (Gc->hDC)
{
Gc->GraphicsContext.hDIB = (DIB*)Win;
SelectObject(Gc->hDC, ((PSKY_DIB)Win)->hBitmap);
((PSKY_DIB)Win)->hAssociateDC = Gc->hDC;
}
break;
case GC_TYPE_WINDOW:
Gc->hDC = GetDC(((PSKY_WINDOW)Win)->hWnd);
Gc->GraphicsContext.window = Win;
break;
default:
DBG("Unknown GC type: %x\n", Type);
}
if (Gc->hDC == NULL)
{
HeapFree(GetProcessHeap(), 0, Gc);
return NULL;
}
else
{
SelectObject(Gc->hDC, GetStockObject(DC_BRUSH));
SelectObject(Gc->hDC, GetStockObject(DC_PEN));
}
return (GC*)Gc;
}
/*
* @implemented
*/
int __cdecl
GC_set_fg_color(GC *Gc,
COLOR Color)
{
if(Gc != NULL)
{
Gc->fg_color = Color;
SetDCPenColor(((PSKY_GC)Gc)->hDC, Color);
return 1;
}
#if DEBUG
else
{
DBG("GC_set_fg_color: Gc == NULL!\n");
}
#endif
return 0;
}
/*
* @implemented
*/
int __cdecl
GC_set_bg_color(GC *Gc,
COLOR Color)
{
if(Gc != NULL)
{
Gc->bg_color = Color;
SetDCBrushColor(((PSKY_GC)Gc)->hDC, Color);
return 1;
}
#if DEBUG
else
{
DBG("GC_set_bg_color: Gc == NULL!\n");
}
#endif
return 0;
}
/*
* @implemented
*/
int __cdecl
GC_draw_pixel(GC *Gc,
int X,
int Y)
{
if(Gc != NULL)
{
SetPixelV(((PSKY_GC)Gc)->hDC, X, Y, Gc->fg_color);
return 1;
}
#if DEBUG
else
{
DBG("GC_draw_pixel: Gc == NULL!\n");
}
#endif
return 0;
}
/*
* @implemented
*/
int __cdecl
GC_blit_from_DIB(GC *Gc,
DIB *Dib,
int X,
int Y)
{
int Result;
HDC hSrcDC;
HBITMAP hOldBitmap = NULL;
DBG("GC_blit_from_DIB(0x%x, 0x%x, 0x%x, 0x%x)\n", Gc, Dib, X, Y);
if (((PSKY_DIB)Dib)->hAssociateDC == NULL)
{
hSrcDC = CreateCompatibleDC(0);
hOldBitmap = SelectObject(hSrcDC, ((PSKY_DIB)Dib)->hBitmap);
}
else
{
hSrcDC = ((PSKY_DIB)Dib)->hAssociateDC;
}
Result = BitBlt(((PSKY_GC)Gc)->hDC, X, Y, Dib->width, Dib->height,
hSrcDC, 0, 0, SRCCOPY);
if (((PSKY_DIB)Dib)->hAssociateDC == NULL)
{
SelectObject(hSrcDC, hOldBitmap);
DeleteDC(hSrcDC);
}
return !Result;
}
/*
* @implemented
*/
int __cdecl
GC_draw_rect_fill(GC *Gc,
int X,
int Y,
int Width,
int Height)
{
DBG("GC_draw_rect_fill(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
Gc, X, Y, Width, Height);
if(Gc != NULL)
{
HBRUSH hBrush;
RECT Rect;
Rect.left = X;
Rect.top = Y;
Rect.right = X + Width;
Rect.bottom = Y + Height;
hBrush = CreateSolidBrush(Gc->bg_color);
FillRect(((PSKY_GC)Gc)->hDC, &Rect, hBrush);
DeleteObject(hBrush);
return 1;
}
#if DEBUG
else
{
DBG("GC_draw_rect_fill: Gc == NULL!\n");
}
#endif
return 0;
}
/*
* @implemented
*/
int __cdecl
GC_draw_line(GC *Gc,
int x1,
int y1,
int x2,
int y2)
{
DBG("GC_draw_line(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", Gc, x1, y1, x2, y2);
if(Gc != NULL)
{
MoveToEx(((PSKY_GC)Gc)->hDC, x1, y1, NULL);
LineTo(((PSKY_GC)Gc)->hDC, x2, y2);
return 1;
}
#if DEBUG
else
{
DBG("GC_draw_line: Gc == NULL!\n");
}
#endif
return 0;
}
/*
* @implemented
*/
int __cdecl
GC_destroy(GC *Gc)
{
DBG("GC_destroy(0x%x)\n", Gc);
if (Gc != NULL)
{
switch (Gc->type)
{
case GC_TYPE_DIB:
DeleteDC(((PSKY_GC)Gc)->hDC);
break;
case GC_TYPE_WINDOW:
ReleaseDC(((PSKY_WINDOW)Gc->window)->hWnd, ((PSKY_GC)Gc)->hDC);
break;
default:
DBG("Unknown GC type: %x\n", Gc->type);
}
HeapFree(GetProcessHeap(), 0, Gc);
return 1;
}
#if DEBUG
else
{
DBG("GC_destroy: Gc == NULL!\n");
}
#endif
return 0;
}
/*
* @implemented
*/
widget_menu* __cdecl
GI_create_menu(s_window *win)
{
PSKY_MENU Menu;
DBG("GI_create_menu(0x%x)\n", win);
Menu = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SKY_MENU));
if (Menu == NULL)
{
return NULL;
}
/* Shouldn't we use CreatePopupMenu in some cases? */
Menu->hMenu = CreateMenu();
if (Menu->hMenu == NULL)
{
HeapFree(GetProcessHeap(), 0, Menu);
return NULL;
}
if (win)
{
SetMenu(((PSKY_WINDOW)win)->hWnd, Menu->hMenu);
}
return (widget_menu *)Menu;
}
/*
* @implemented
*/
widget_menu_item* __cdecl
GI_create_menu_item(unsigned char *Text,
unsigned int Id,
unsigned int Flags,
unsigned int Enabled)
{
PSKY_MENUITEM MenuItem;
ULONG TextLength;
DBG("GI_create_menu_item(0x%x, 0x%x, 0x%x, 0x%x)\n",
Text, Id, Flags, Enabled);
TextLength = MultiByteToWideChar(CP_UTF8, 0, (char*)Text, -1, NULL, 0);
MenuItem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(SKY_MENUITEM) + TextLength * sizeof(WCHAR));
if (MenuItem == NULL)
{
return NULL;
}
lstrcpyA((char*)MenuItem->MenuItem.text, (char*)Text);
MenuItem->MenuItem.ID = Id;
MenuItem->MenuItem.flags = Flags;
MenuItem->MenuItem.enabled = Enabled;
MenuItem->MenuItemInfo.cbSize = sizeof(MENUITEMINFOW);
MenuItem->MenuItemInfo.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
if (Flags & MENU_SEPERATOR)
MenuItem->MenuItemInfo.fType = MF_SEPARATOR;
else
MenuItem->MenuItemInfo.fType = MF_STRING;
MenuItem->MenuItemInfo.fState = Enabled ? MFS_ENABLED : 0;
MenuItem->MenuItemInfo.wID = Id;
MenuItem->MenuItemInfo.dwTypeData = (LPWSTR)(MenuItem + 1);
MenuItem->MenuItemInfo.cch = TextLength;
MultiByteToWideChar(CP_UTF8, 0, (char*)Text, TextLength, (LPWSTR)(MenuItem + 1),
TextLength);
return (widget_menu_item *)MenuItem;
}
/*
* @implemented
*/
int __cdecl
GI_add_menu_item(widget_menu *Menu,
widget_menu_item *Item)
{
DBG("GI_add_menu_item(0x%x, 0x%x)\n", Menu, Item);
InsertMenuItemW(((PSKY_MENU)Menu)->hMenu, -1, TRUE,
&((PSKY_MENUITEM)Item)->MenuItemInfo);
return 1;
}
/*
* @implemented
*/
int __cdecl
GI_add_menu_sub(widget_menu *Menu,
widget_menu_item *Item,
widget_menu *Sub)
{
PSKY_MENUITEM MenuItem = (PSKY_MENUITEM)Item;
DBG("GI_add_menu_sub(0x%x, 0x%x, 0x%x)\n", Menu, Item, Sub);
MenuItem->MenuItemInfo.fMask |= MIIM_SUBMENU;
MenuItem->MenuItemInfo.hSubMenu = ((PSKY_MENU)Sub)->hMenu;
InsertMenuItemW(((PSKY_MENU)Menu)->hMenu, -1, TRUE,
&MenuItem->MenuItemInfo);
return 1;
}
/*
* @implemented
*/
int __cdecl
GI_messagebox(s_window *Window,
unsigned int Flags,
char *Title,
char *Fmt,
...)
{
CHAR Buffer[4096];
va_list ArgList;
ULONG MbFlags, MbResult;
DBG("GI_messagebox(0x%x, 0x%x, 0x%x, 0x%x, ...)\n",
Window, Flags, Title, Fmt);
va_start(ArgList, Fmt);
_vsnprintf(Buffer, sizeof(Buffer) / sizeof(Buffer[0]), Fmt, ArgList);
va_end(ArgList);
if ((Flags & (WGF_MB_CANCEL | WGF_MB_YESNO)) ==
(WGF_MB_CANCEL | WGF_MB_YESNO))
MbFlags = MB_YESNOCANCEL;
else if (Flags & WGF_MB_YESNO)
MbFlags = MB_YESNO;
else /* if (Flags & WGF_MB_OK) */
MbFlags = MB_OK;
MbFlags |= (Flags & WGF_MB_ICON_INFO) ? MB_ICONASTERISK : 0;
MbFlags |= (Flags & WGF_MB_ICON_ASK) ? MB_ICONQUESTION : 0;
MbFlags |= (Flags & WGF_MB_ICON_STOP) ? MB_ICONERROR : 0;
MbResult = MessageBoxA(Window ? ((PSKY_WINDOW)Window)->hWnd : NULL,
Buffer, Title, MbFlags);
switch (MbResult)
{
case IDOK: return ID_OK;
case IDYES: return ID_YES;
case IDNO: return ID_NO;
case IDCANCEL: return ID_CANCEL;
}
return 0;
}
/*
* @implemented
*/
int __cdecl
GI_EnableMouseTracking(s_window *win)
{
DBG("GI_EnableMouseTracking(0x%x)!\n", win);
if(win != NULL)
{
((PSKY_WINDOW)win)->MouseInput = TRUE;
return 1;
}
#if DEBUG
else
{
DBG("GI_EnableMouseTracking: win == NULL!\n");
}
#endif
return 0;
}
/* EOF */