mirror of
https://github.com/reactos/reactos.git
synced 2024-08-28 22:28:36 +00:00
547 lines
15 KiB
C
547 lines
15 KiB
C
/*
|
|
* PROJECT: ReactOS Magnify
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: base/applications/magnify/magnifier.c
|
|
* PURPOSE:
|
|
* COPYRIGHT: Copyright 2007 Marc Piulachs <marc.piulachs@codexchange.net>
|
|
*
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <shellapi.h>
|
|
#include "magnifier.h"
|
|
#include "resource.h"
|
|
|
|
const TCHAR szWindowClass[] = TEXT("MAGNIFIER");
|
|
|
|
#define MAX_LOADSTRING 100
|
|
|
|
// Global Variables:
|
|
HINSTANCE hInst; // current instance
|
|
HWND hMainWnd;
|
|
|
|
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
|
|
|
|
#define REPAINT_SPEED 100
|
|
|
|
HWND hDesktopWindow = NULL;
|
|
|
|
//Current magnified area
|
|
POINT cp;
|
|
|
|
//Last positions
|
|
POINT pMouse;
|
|
POINT pCaret;
|
|
POINT pFocus;
|
|
|
|
// Forward declarations of functions included in this code module:
|
|
ATOM MyRegisterClass(HINSTANCE hInstance);
|
|
BOOL InitInstance(HINSTANCE, int);
|
|
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
|
INT_PTR CALLBACK AboutProc(HWND, UINT, WPARAM, LPARAM);
|
|
INT_PTR CALLBACK OptionsProc(HWND, UINT, WPARAM, LPARAM);
|
|
INT_PTR CALLBACK WarningProc(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
|
{
|
|
// TODO: Place code here.
|
|
MSG msg;
|
|
HACCEL hAccelTable;
|
|
|
|
UNREFERENCED_PARAMETER(hPrevInstance);
|
|
UNREFERENCED_PARAMETER(lpCmdLine);
|
|
|
|
// Initialize global strings
|
|
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
|
|
MyRegisterClass(hInstance);
|
|
|
|
// Perform application initialization:
|
|
if (!InitInstance (hInstance, nCmdShow))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MAGNIFIER));
|
|
|
|
// Main message loop:
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
return (int) msg.wParam;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// FUNCTION: MyRegisterClass()
|
|
//
|
|
// PURPOSE: Registers the window class.
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
// This function and its usage are only necessary if you want this code
|
|
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
|
|
// function that was added to Windows 95. It is important to call this function
|
|
// so that the application will get 'well formed' small icons associated
|
|
// with it.
|
|
//
|
|
ATOM MyRegisterClass(HINSTANCE hInstance)
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = WndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
|
wc.lpszMenuName = MAKEINTRESOURCE(IDC_MAGNIFIER);
|
|
wc.lpszClassName = szWindowClass;
|
|
|
|
return RegisterClass(&wc);
|
|
}
|
|
|
|
//
|
|
// FUNCTION: InitInstance(HINSTANCE, int)
|
|
//
|
|
// PURPOSE: Saves instance handle and creates main window
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
// In this function, we save the instance handle in a global variable and
|
|
// create and display the main program window.
|
|
//
|
|
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
|
|
{
|
|
hInst = hInstance; // Store instance handle in our global variable
|
|
|
|
// Create the Window
|
|
hMainWnd = CreateWindowEx(
|
|
WS_EX_TOPMOST,
|
|
szWindowClass,
|
|
szTitle,
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
hInstance,
|
|
NULL);
|
|
|
|
if (!hMainWnd)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ShowWindow(hMainWnd, (bStartMinimized) ? SW_MINIMIZE : nCmdShow);
|
|
UpdateWindow(hMainWnd);
|
|
|
|
if (bShowWarning)
|
|
{
|
|
DialogBox (hInstance, MAKEINTRESOURCE(IDD_WARNINGDIALOG), hMainWnd, (DLGPROC)WarningProc);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void Refresh ()
|
|
{
|
|
if (!IsIconic(hMainWnd))
|
|
{
|
|
// Invalidate the client area forcing a WM_PAINT message
|
|
InvalidateRgn(hMainWnd, NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
void Draw(HDC aDc)
|
|
{
|
|
HDC desktopHdc = NULL;
|
|
HDC HdcStrech;
|
|
HANDLE hOld;
|
|
HBITMAP HbmpStrech;
|
|
|
|
RECT R;
|
|
RECT appRect;
|
|
DWORD rop = SRCCOPY;
|
|
CURSORINFO cinfo;
|
|
ICONINFO iinfo;
|
|
|
|
int Width, Height, AppWidth, AppHeight;
|
|
LONG blitAreaWidth, blitAreaHeight, blitAreaX, blitAreaY;
|
|
|
|
desktopHdc = GetWindowDC (hDesktopWindow);
|
|
|
|
GetClientRect(hMainWnd, &appRect);
|
|
GetWindowRect(hDesktopWindow, &R);
|
|
|
|
ZeroMemory(&cinfo, sizeof(CURSORINFO));
|
|
ZeroMemory(&iinfo, sizeof(ICONINFO));
|
|
cinfo.cbSize = sizeof(cinfo);
|
|
GetCursorInfo(&cinfo);
|
|
GetIconInfo(cinfo.hCursor, &iinfo);
|
|
|
|
/* Create a memory DC compatible with client area DC.*/
|
|
HdcStrech = CreateCompatibleDC(desktopHdc);
|
|
|
|
/* Create a bitmap compatible with the client area DC.*/
|
|
HbmpStrech = CreateCompatibleBitmap(
|
|
desktopHdc,
|
|
R.right,
|
|
R.bottom);
|
|
|
|
/* Select our bitmap in memory DC and save the old one.*/
|
|
hOld = SelectObject (HdcStrech , HbmpStrech);
|
|
|
|
/* Paint the screen bitmap to our in memory DC */
|
|
BitBlt(
|
|
HdcStrech,
|
|
0,
|
|
0,
|
|
R.right,
|
|
R.bottom,
|
|
desktopHdc,
|
|
0,
|
|
0,
|
|
SRCCOPY);
|
|
|
|
/* Draw the mouse pointer in the right position */
|
|
DrawIcon(
|
|
HdcStrech ,
|
|
pMouse.x - iinfo.xHotspot, // - 10,
|
|
pMouse.y - iinfo.yHotspot, // - 10,
|
|
cinfo.hCursor);
|
|
|
|
Width = (R.right - R.left);
|
|
Height = (R.bottom - R.top);
|
|
|
|
AppWidth = (appRect.right - appRect.left);
|
|
AppHeight = (appRect.bottom - appRect.top);
|
|
|
|
blitAreaWidth = AppWidth / iZoom;
|
|
blitAreaHeight = AppHeight / iZoom;
|
|
|
|
blitAreaX = (cp.x) - (blitAreaWidth /2);
|
|
blitAreaY = (cp.y) - (blitAreaHeight /2);
|
|
|
|
if (blitAreaX < 0)
|
|
{
|
|
blitAreaX = 0;
|
|
}
|
|
|
|
if (blitAreaY < 0)
|
|
{
|
|
blitAreaY = 0;
|
|
}
|
|
|
|
if (blitAreaX > (Width - blitAreaWidth))
|
|
{
|
|
blitAreaX = (Width - blitAreaWidth);
|
|
}
|
|
|
|
if (blitAreaY > (Height - blitAreaHeight))
|
|
{
|
|
blitAreaY = (Height - blitAreaHeight);
|
|
}
|
|
|
|
if (bInvertColors)
|
|
{
|
|
rop = NOTSRCCOPY;
|
|
}
|
|
|
|
/* Blast the stretched image from memory DC to window DC.*/
|
|
StretchBlt(
|
|
aDc,
|
|
0,
|
|
0,
|
|
AppWidth,
|
|
AppHeight,
|
|
HdcStrech,
|
|
blitAreaX,
|
|
blitAreaY,
|
|
blitAreaWidth,
|
|
blitAreaHeight,
|
|
rop);
|
|
|
|
/* Cleanup.*/
|
|
if (iinfo.hbmMask)
|
|
DeleteObject(iinfo.hbmMask);
|
|
if (iinfo.hbmColor)
|
|
DeleteObject(iinfo.hbmColor);
|
|
SelectObject (HdcStrech, hOld);
|
|
DeleteObject (HbmpStrech);
|
|
DeleteDC (HdcStrech);
|
|
ReleaseDC(hDesktopWindow, desktopHdc);
|
|
}
|
|
|
|
//
|
|
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
|
|
//
|
|
// PURPOSE: Processes messages for the main window.
|
|
//
|
|
// WM_COMMAND - process the application menu
|
|
// WM_PAINT - Paint the main window
|
|
// WM_DESTROY - post a quit message and return
|
|
//
|
|
//
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int wmId, wmEvent;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_TIMER:
|
|
{
|
|
POINT pNewMouse;
|
|
POINT pNewCaret;
|
|
POINT pNewFocus;
|
|
HWND hwnd1, hwnd2, hwnd3;
|
|
DWORD a, b;
|
|
RECT controlRect;
|
|
|
|
//Get current mouse position
|
|
GetCursorPos (&pNewMouse);
|
|
|
|
//Get caret position
|
|
hwnd1 = GetForegroundWindow ();
|
|
a = GetWindowThreadProcessId(hwnd1, NULL);
|
|
b = GetCurrentThreadId();
|
|
AttachThreadInput (a, b, TRUE);
|
|
hwnd2 = GetFocus();
|
|
|
|
GetCaretPos( &pNewCaret);
|
|
ClientToScreen (hwnd2, (LPPOINT) &pNewCaret);
|
|
AttachThreadInput (a, b, FALSE);
|
|
|
|
//Get current control focus
|
|
hwnd3 = GetFocus ();
|
|
GetWindowRect (hwnd3 , &controlRect);
|
|
pNewFocus.x = controlRect.left;
|
|
pNewFocus.y = controlRect.top;
|
|
|
|
//If mouse has moved ....
|
|
if (((pMouse.x != pNewMouse.x) || (pMouse.y != pNewMouse.y)) && bFollowMouse)
|
|
{
|
|
//Update to new position
|
|
pMouse = pNewMouse;
|
|
cp = pNewMouse;
|
|
Refresh();
|
|
}
|
|
else if (((pCaret.x != pNewCaret.x) || (pCaret.y != pNewCaret.y)) && bFollowCaret)
|
|
{
|
|
//Update to new position
|
|
pCaret = pNewCaret;
|
|
cp = pNewCaret;
|
|
Refresh();
|
|
}
|
|
else if (((pFocus.x != pNewFocus.x) || (pFocus.y != pNewFocus.y)) && bFollowFocus)
|
|
{
|
|
//Update to new position
|
|
pFocus = pNewFocus;
|
|
cp = pNewFocus;
|
|
Refresh();
|
|
}
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
wmId = LOWORD(wParam);
|
|
wmEvent = HIWORD(wParam);
|
|
// Parse the menu selections:
|
|
switch (wmId)
|
|
{
|
|
case IDM_OPTIONS:
|
|
DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOGOPTIONS), hWnd, (DLGPROC)OptionsProc);
|
|
break;
|
|
case IDM_ABOUT:
|
|
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, (DLGPROC)AboutProc);
|
|
break;
|
|
case IDM_EXIT:
|
|
DestroyWindow(hWnd);
|
|
break;
|
|
default:
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
break;
|
|
case WM_PAINT:
|
|
{
|
|
PAINTSTRUCT PaintStruct;
|
|
HDC dc;
|
|
dc = BeginPaint(hWnd, &PaintStruct);
|
|
Draw(dc);
|
|
EndPaint(hWnd, &PaintStruct);
|
|
}
|
|
break;
|
|
case WM_ERASEBKGND:
|
|
//handle WM_ERASEBKGND by simply returning non-zero because we did all the drawing in WM_PAINT.
|
|
break;
|
|
case WM_DESTROY:
|
|
//Save settings to registry
|
|
SaveSettings ();
|
|
KillTimer (hWnd , 1);
|
|
PostQuitMessage(0);
|
|
break;
|
|
case WM_CREATE:
|
|
//Load settings from registry
|
|
LoadSettings ();
|
|
|
|
//Get the desktop window
|
|
hDesktopWindow = GetDesktopWindow();
|
|
|
|
//Set the timer
|
|
SetTimer (hWnd , 1, REPAINT_SPEED , NULL);
|
|
break;
|
|
default:
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Message handler for about box.
|
|
INT_PTR CALLBACK AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
return (INT_PTR)TRUE;
|
|
|
|
case WM_COMMAND:
|
|
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
|
|
{
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
return (INT_PTR)TRUE;
|
|
}
|
|
break;
|
|
}
|
|
return (INT_PTR)FALSE;
|
|
}
|
|
|
|
// Message handler for options box.
|
|
INT_PTR CALLBACK OptionsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
//Add the zoom items....
|
|
SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("1"));
|
|
SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("2"));
|
|
SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("3"));
|
|
SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("4"));
|
|
SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("5"));
|
|
SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("6"));
|
|
SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("7"));
|
|
SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("8"));
|
|
|
|
//
|
|
SendDlgItemMessage(hDlg, IDC_ZOOM, CB_SETCURSEL, iZoom - 1, 0);
|
|
|
|
if (bFollowMouse)
|
|
SendDlgItemMessage(hDlg,IDC_FOLLOWMOUSECHECK,BM_SETCHECK , wParam ,0);
|
|
|
|
if (bFollowFocus)
|
|
SendDlgItemMessage(hDlg,IDC_FOLLOWKEYBOARDCHECK,BM_SETCHECK , wParam ,0);
|
|
|
|
if (bFollowCaret)
|
|
SendDlgItemMessage(hDlg,IDC_FOLLOWTEXTEDITINGCHECK,BM_SETCHECK , wParam ,0);
|
|
|
|
if (bInvertColors)
|
|
SendDlgItemMessage(hDlg,IDC_INVERTCOLORSCHECK,BM_SETCHECK , wParam ,0);
|
|
|
|
if (bStartMinimized)
|
|
SendDlgItemMessage(hDlg,IDC_STARTMINIMIZEDCHECK,BM_SETCHECK , wParam ,0);
|
|
|
|
if (bShowMagnifier)
|
|
SendDlgItemMessage(hDlg,IDC_SHOWMAGNIFIERCHECK,BM_SETCHECK , wParam ,0);
|
|
|
|
return (INT_PTR)TRUE;
|
|
}
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
return (INT_PTR)TRUE;
|
|
|
|
case IDC_BUTTON_HELP:
|
|
/* unimplemented */
|
|
MessageBox(hDlg , TEXT("Magnifier help not available yet!") , TEXT("Help") , MB_OK);
|
|
break;
|
|
case IDC_ZOOM:
|
|
if(HIWORD(wParam) == CBN_SELCHANGE)
|
|
{
|
|
HWND hCombo = GetDlgItem(hDlg,IDC_ZOOM);
|
|
|
|
/* Get index of current selection and the text of that selection. */
|
|
iZoom = SendMessage( hCombo, CB_GETCURSEL, (WPARAM) wParam, (LPARAM) lParam ) + 1;
|
|
|
|
//Update the magnigier UI
|
|
Refresh ();
|
|
}
|
|
break;
|
|
case IDC_INVERTCOLORSCHECK:
|
|
bInvertColors = IsDlgButtonChecked (hDlg, IDC_INVERTCOLORSCHECK);
|
|
Refresh ();
|
|
break;
|
|
case IDC_FOLLOWMOUSECHECK:
|
|
bFollowMouse = IsDlgButtonChecked (hDlg, IDC_FOLLOWMOUSECHECK);
|
|
break;
|
|
case IDC_FOLLOWKEYBOARDCHECK:
|
|
bFollowFocus = IsDlgButtonChecked (hDlg, IDC_FOLLOWKEYBOARDCHECK);
|
|
break;
|
|
case IDC_FOLLOWTEXTEDITINGCHECK:
|
|
bFollowCaret = IsDlgButtonChecked (hDlg, IDC_FOLLOWTEXTEDITINGCHECK);
|
|
break;
|
|
case IDC_STARTMINIMIZEDCHECK:
|
|
bStartMinimized = IsDlgButtonChecked (hDlg, IDC_STARTMINIMIZEDCHECK);
|
|
break;
|
|
case IDC_SHOWMAGNIFIER:
|
|
bShowMagnifier = IsDlgButtonChecked (hDlg, IDC_SHOWMAGNIFIERCHECK);
|
|
if (bShowMagnifier){
|
|
ShowWindow (hMainWnd , SW_SHOW);
|
|
}else{
|
|
ShowWindow (hMainWnd , SW_HIDE);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return (INT_PTR)FALSE;
|
|
}
|
|
|
|
// Message handler for warning box.
|
|
INT_PTR CALLBACK WarningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
return (INT_PTR)TRUE;
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_SHOWWARNINGCHECK:
|
|
bShowWarning = !IsDlgButtonChecked (hDlg, IDC_SHOWWARNINGCHECK);
|
|
break;
|
|
}
|
|
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
|
|
{
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
return (INT_PTR)TRUE;
|
|
}
|
|
break;
|
|
}
|
|
return (INT_PTR)FALSE;
|
|
}
|