mirror of
https://github.com/reactos/reactos.git
synced 2024-09-11 13:23:51 +00:00
1214 lines
26 KiB
C
1214 lines
26 KiB
C
/*
|
|
* 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 */
|