[MAGNIFY] Fix a string buffer misuage that led to division by zero exception. (#1655)
[reactos.git] / base / applications / magnify / magnifier.c
1 /*
2 * PROJECT: ReactOS Magnify
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/magnify/magnifier.c
5 * PURPOSE: Magnification of parts of the screen.
6 * AUTHORS:
7 * Marc Piulachs <marc.piulachs@codexchange.net>
8 * David Quintana <gigaherz@gmail.com>
9 */
10
11 /* TODO: Support AppBar types other than ABE_TOP */
12
13 #include "magnifier.h"
14
15 #include <winbase.h>
16 #include <winuser.h>
17 #include <wingdi.h>
18 #include <winnls.h>
19 #include <commctrl.h>
20 #include <shellapi.h>
21 #include <windowsx.h>
22 #include <stdlib.h>
23 #include <tchar.h>
24
25 #include "resource.h"
26
27 #define APPMSG_NOTIFYICON (WM_APP+1)
28 #define APPMSG_APPBAR (WM_APP+2)
29
30 const TCHAR szWindowClass[] = TEXT("MAGNIFIER");
31
32 /* Global Variables */
33 HINSTANCE hInst;
34 HWND hMainWnd;
35
36 #define MAX_LOADSTRING 100
37 TCHAR szTitle[MAX_LOADSTRING];
38
39 #define TIMER_SPEED 1
40 #define REPAINT_SPEED 100
41
42 DWORD lastTicks = 0;
43
44 HWND hDesktopWindow = NULL;
45
46 NOTIFYICONDATA nid;
47 HICON notifyIcon;
48 HMENU notifyMenu;
49 HWND hOptionsDialog;
50 BOOL bOptionsDialog = FALSE;
51 BOOL bRecreateOffscreenDC = TRUE;
52 LONG sourceWidth = 0;
53 LONG sourceHeight = 0;
54 HDC hdcOffscreen = NULL;
55 HBITMAP hbmpOffscreen = NULL;
56 HANDLE hbmpOld;
57 POINT ptDragOffset;
58 INT nearEdge;
59
60 /* Current magnified area */
61 POINT cp;
62
63 /* Last positions */
64 POINT pMouse;
65 POINT pCaret;
66 POINT pFocus;
67 HWND pCaretWnd;
68 HWND pFocusWnd;
69
70 ATOM MyRegisterClass(HINSTANCE hInstance);
71 BOOL InitInstance(HINSTANCE, int);
72 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
73 INT_PTR CALLBACK AboutProc(HWND, UINT, WPARAM, LPARAM);
74 INT_PTR CALLBACK OptionsProc(HWND, UINT, WPARAM, LPARAM);
75 INT_PTR CALLBACK WarningProc(HWND, UINT, WPARAM, LPARAM);
76
77 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
78 {
79 MSG msg;
80 HACCEL hAccelTable;
81 INITCOMMONCONTROLSEX iccex;
82
83 UNREFERENCED_PARAMETER(hPrevInstance);
84 UNREFERENCED_PARAMETER(lpCmdLine);
85
86 switch (GetUserDefaultUILanguage())
87 {
88 case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
89 SetProcessDefaultLayout(LAYOUT_RTL);
90 break;
91
92 default:
93 break;
94 }
95
96 /* Initialize global strings */
97 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
98 MyRegisterClass(hInstance);
99
100 /* Perform application initialization */
101 if (!InitInstance(hInstance, nCmdShow))
102 return FALSE;
103
104 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MAGNIFIER));
105
106 /* Main message loop */
107 while (GetMessage(&msg, NULL, 0, 0))
108 {
109 if (!TranslateAccelerator(hMainWnd, hAccelTable, &msg))
110 {
111 TranslateMessage(&msg);
112 DispatchMessage(&msg);
113 }
114 }
115
116 /* Load the common controls */
117 iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
118 iccex.dwICC = ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES;
119 InitCommonControlsEx(&iccex);
120
121 SelectObject(hdcOffscreen, hbmpOld);
122 DeleteObject (hbmpOffscreen);
123 DeleteDC(hdcOffscreen);
124
125 return (int) msg.wParam;
126 }
127
128 ATOM MyRegisterClass(HINSTANCE hInstance)
129 {
130 WNDCLASS wc;
131
132 wc.style = CS_HREDRAW | CS_VREDRAW;
133 wc.lpfnWndProc = WndProc;
134 wc.cbClsExtra = 0;
135 wc.cbWndExtra = 0;
136 wc.hInstance = hInstance;
137 wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
138 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
139 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
140 wc.lpszMenuName = NULL; //MAKEINTRESOURCE(IDC_MAGNIFIER);
141 wc.lpszClassName = szWindowClass;
142
143 return RegisterClass(&wc);
144 }
145
146 void DoAppBarStuff(DWORD mode)
147 {
148 UINT uState;
149 APPBARDATA data = {0};
150 data.cbSize = sizeof(data);
151 data.hWnd = hMainWnd;
152 data.uCallbackMessage = APPMSG_APPBAR;
153
154 if (mode == ABM_NEW || mode == ABM_SETPOS)
155 {
156 HWND hWndOrder = HWND_BOTTOM;
157 int rcw, rch;
158 RECT rcWorkArea;
159 SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
160
161 if(mode == ABM_NEW)
162 {
163 SHAppBarMessage(ABM_NEW, &data);
164
165 switch(AppBarConfig.uEdge)
166 {
167 case ABE_LEFT:
168 data.rc.top = rcWorkArea.top;
169 data.rc.bottom = rcWorkArea.bottom;
170 data.rc.left = rcWorkArea.left;
171 data.rc.right = data.rc.left + AppBarConfig.appBarSizes.left;
172 break;
173 case ABE_TOP:
174 data.rc.left = rcWorkArea.left;
175 data.rc.right = rcWorkArea.right;
176 data.rc.top = rcWorkArea.top;
177 data.rc.bottom = data.rc.top + AppBarConfig.appBarSizes.top;
178 break;
179 case ABE_RIGHT:
180 data.rc.top = rcWorkArea.top;
181 data.rc.bottom = rcWorkArea.bottom;
182 data.rc.right = rcWorkArea.left;
183 data.rc.left = data.rc.right - AppBarConfig.appBarSizes.right;
184 break;
185 case ABE_BOTTOM:
186 data.rc.left = rcWorkArea.left;
187 data.rc.right = rcWorkArea.right;
188 data.rc.bottom = rcWorkArea.bottom;
189 data.rc.top = data.rc.bottom - AppBarConfig.appBarSizes.bottom;
190 break;
191 }
192 }
193 else
194 {
195 GetWindowRect(hMainWnd, &data.rc);
196 }
197
198 data.uEdge = AppBarConfig.uEdge;
199 uState = SHAppBarMessage(ABM_QUERYPOS, &data);
200
201 uState = SHAppBarMessage(ABM_SETPOS, &data);
202
203 rcw = data.rc.right-data.rc.left;
204 rch = data.rc.bottom-data.rc.top;
205
206 uState = SHAppBarMessage(ABM_GETSTATE, &data);
207 if(uState & ABS_ALWAYSONTOP)
208 hWndOrder = HWND_TOPMOST;
209
210 SetWindowPos(hMainWnd, hWndOrder, data.rc.left, data.rc.top, rcw, rch, SWP_SHOWWINDOW|SWP_NOCOPYBITS);
211
212 }
213 else if(mode == ABM_GETSTATE)
214 {
215 HWND hWndOrder = HWND_BOTTOM;
216 uState = SHAppBarMessage(ABM_GETSTATE, &data);
217 if(uState & ABS_ALWAYSONTOP)
218 hWndOrder = HWND_TOPMOST;
219 SetWindowPos(hMainWnd, hWndOrder, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
220 }
221 else if(mode == ABM_ACTIVATE)
222 {
223 SHAppBarMessage(ABM_ACTIVATE, &data);
224 }
225 else if(mode == ABM_WINDOWPOSCHANGED)
226 {
227 SHAppBarMessage(ABM_WINDOWPOSCHANGED, &data);
228 }
229 else if(mode == ABM_REMOVE)
230 {
231 SHAppBarMessage(ABM_REMOVE, &data);
232 }
233 }
234
235 void AttachAppBar(INT uEdge)
236 {
237 if (AppBarConfig.uEdge == uEdge)
238 return;
239
240 if(AppBarConfig.uEdge < 0 && uEdge >= 0)
241 {
242 SetWindowLongPtr(hMainWnd, GWL_STYLE, GetWindowLongPtr(hMainWnd, GWL_STYLE) & (~WS_CAPTION));
243 }
244 else if(uEdge < 0 && AppBarConfig.uEdge>=0)
245 {
246 SetWindowLongPtr(hMainWnd, GWL_STYLE, GetWindowLongPtr(hMainWnd, GWL_STYLE) | WS_CAPTION);
247 SetWindowPos(hMainWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED);
248 }
249
250 if(AppBarConfig.uEdge >= 0)
251 {
252 DoAppBarStuff(ABM_REMOVE);
253 }
254
255 if (uEdge >=0)
256 {
257 AppBarConfig.uEdge = uEdge;
258 DoAppBarStuff(ABM_NEW);
259 }
260 else
261 {
262 RECT rc = AppBarConfig.rcFloating;
263 SetWindowPos(hMainWnd, HWND_TOPMOST, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, 0);
264 }
265
266 AppBarConfig.uEdge = uEdge;
267 }
268
269 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
270 {
271 RECT rc;
272 DWORD exStyles = WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT;
273 DWORD dwStyles = WS_SIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
274
275 /* Load settings from registry */
276 LoadSettings();
277
278 rc = AppBarConfig.rcFloating;
279
280 hInst = hInstance; // Store instance handle in our global variable
281
282 if (AppBarConfig.uEdge<0)
283 {
284 dwStyles |= WS_CAPTION;
285 exStyles |= WS_EX_TOPMOST;
286 }
287
288 /* Create the Window */
289 hMainWnd = CreateWindowEx(
290 exStyles,
291 szWindowClass,
292 szTitle,
293 dwStyles,
294 rc.left,
295 rc.top,
296 rc.right-rc.left,
297 rc.bottom-rc.top,
298 NULL,
299 NULL,
300 hInstance,
301 NULL);
302
303 if (!hMainWnd)
304 return FALSE;
305
306 if (AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_NEW);
307 else SetWindowPos(hMainWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
308
309 // In Windows 2003's Magnifier, the "Start Minimized" setting
310 // refers exclusively to the options dialog, not the main window itself.
311 hOptionsDialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOGOPTIONS), hMainWnd, OptionsProc);
312 if (bStartMinimized)
313 ShowWindow(hOptionsDialog, SW_HIDE);
314 else
315 ShowWindow(hOptionsDialog, SW_SHOW);
316
317 if (bShowWarning)
318 DialogBox(hInstance, MAKEINTRESOURCE(IDD_WARNINGDIALOG), hMainWnd, WarningProc);
319
320 return TRUE;
321 }
322
323 void Refresh()
324 {
325 if (!IsIconic(hMainWnd))
326 {
327 /* Invalidate the client area forcing a WM_PAINT message */
328 InvalidateRgn(hMainWnd, NULL, TRUE);
329 }
330 }
331
332 void GetBestOverlapWithMonitors(LPRECT rect)
333 {
334 int rcLeft, rcTop;
335 int rcWidth, rcHeight;
336 RECT rcMon;
337 HMONITOR hMon = MonitorFromRect(rect, MONITOR_DEFAULTTONEAREST);
338 MONITORINFO info;
339 info.cbSize = sizeof(info);
340
341 GetMonitorInfo(hMon, &info);
342
343 rcMon = info.rcMonitor;
344
345 rcLeft = rect->left;
346 rcTop = rect->top;
347 rcWidth = (rect->right - rect->left);
348 rcHeight = (rect->bottom - rect->top);
349
350 if (rcLeft < rcMon.left)
351 rcLeft = rcMon.left;
352
353 if (rcTop < rcMon.top)
354 rcTop = rcMon.top;
355
356 if (rcLeft > (rcMon.right - rcWidth))
357 rcLeft = (rcMon.right - rcWidth);
358
359 if (rcTop > (rcMon.bottom - rcHeight))
360 rcTop = (rcMon.bottom - rcHeight);
361
362 OffsetRect(rect, (rcLeft-rect->left), (rcTop-rect->top));
363 }
364
365 void Draw(HDC aDc)
366 {
367 HDC desktopHdc = NULL;
368
369 RECT sourceRect, intersectedRect;
370 RECT targetRect, appRect;
371 DWORD rop = SRCCOPY;
372 CURSORINFO cinfo;
373 ICONINFO iinfo;
374
375 int AppWidth, AppHeight;
376
377 if (bInvertColors)
378 rop = NOTSRCCOPY;
379
380 desktopHdc = GetDC(0);
381
382 GetClientRect(hMainWnd, &appRect);
383 AppWidth = (appRect.right - appRect.left);
384 AppHeight = (appRect.bottom - appRect.top);
385
386 ZeroMemory(&cinfo, sizeof(cinfo));
387 ZeroMemory(&iinfo, sizeof(iinfo));
388 cinfo.cbSize = sizeof(cinfo);
389 GetCursorInfo(&cinfo);
390 GetIconInfo(cinfo.hCursor, &iinfo);
391
392 targetRect = appRect;
393 ClientToScreen(hMainWnd, (POINT*)&targetRect.left);
394 ClientToScreen(hMainWnd, (POINT*)&targetRect.right);
395
396 if (bRecreateOffscreenDC || !hdcOffscreen)
397 {
398 bRecreateOffscreenDC = FALSE;
399
400 if(hdcOffscreen)
401 {
402 SelectObject(hdcOffscreen, hbmpOld);
403 DeleteObject (hbmpOffscreen);
404 DeleteDC(hdcOffscreen);
405 }
406
407 sourceWidth = AppWidth / iZoom;
408 sourceHeight = AppHeight / iZoom;
409
410 /* Create a memory DC compatible with client area DC */
411 hdcOffscreen = CreateCompatibleDC(desktopHdc);
412
413 /* Create a bitmap compatible with the client area DC */
414 hbmpOffscreen = CreateCompatibleBitmap(
415 desktopHdc,
416 sourceWidth,
417 sourceHeight);
418
419 /* Select our bitmap in memory DC and save the old one */
420 hbmpOld = SelectObject(hdcOffscreen , hbmpOffscreen);
421 }
422
423 GetWindowRect(hDesktopWindow, &sourceRect);
424 sourceRect.left = (cp.x) - (sourceWidth /2);
425 sourceRect.top = (cp.y) - (sourceHeight /2);
426 sourceRect.right = sourceRect.left + sourceWidth;
427 sourceRect.bottom = sourceRect.top + sourceHeight;
428
429 GetBestOverlapWithMonitors(&sourceRect);
430
431 /* Paint the screen bitmap to our in memory DC */
432 BitBlt(
433 hdcOffscreen,
434 0,
435 0,
436 sourceWidth,
437 sourceHeight,
438 desktopHdc,
439 sourceRect.left,
440 sourceRect.top,
441 rop);
442
443 if (IntersectRect(&intersectedRect, &sourceRect, &targetRect))
444 {
445 OffsetRect(&intersectedRect, -sourceRect.left, -sourceRect.top);
446 FillRect(hdcOffscreen, &intersectedRect, GetStockObject(DC_BRUSH));
447 }
448
449 /* Draw the mouse pointer in the right position */
450 DrawIcon(
451 hdcOffscreen ,
452 pMouse.x - iinfo.xHotspot - sourceRect.left, // - 10,
453 pMouse.y - iinfo.yHotspot - sourceRect.top, // - 10,
454 cinfo.hCursor);
455
456 /* Blast the stretched image from memory DC to window DC */
457 StretchBlt(
458 aDc,
459 0,
460 0,
461 AppWidth,
462 AppHeight,
463 hdcOffscreen,
464 0,
465 0,
466 sourceWidth,
467 sourceHeight,
468 SRCCOPY | NOMIRRORBITMAP);
469
470 /* Cleanup */
471 if (iinfo.hbmMask)
472 DeleteObject(iinfo.hbmMask);
473 if (iinfo.hbmColor)
474 DeleteObject(iinfo.hbmColor);
475 ReleaseDC(hDesktopWindow, desktopHdc);
476 }
477
478 void HandleNotifyIconMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)
479 {
480 POINT pt;
481
482 switch(lParam)
483 {
484 case WM_LBUTTONUP:
485 PostMessage(hMainWnd, WM_COMMAND, IDM_OPTIONS, 0);
486 break;
487 case WM_RBUTTONUP:
488 GetCursorPos (&pt);
489 TrackPopupMenu(notifyMenu, 0, pt.x, pt.y, 0, hWnd, NULL);
490 break;
491 }
492 }
493
494 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
495 {
496 int wmId;
497
498 switch (message)
499 {
500 case WM_TIMER:
501 {
502 BOOL hasMoved = FALSE;
503
504 GUITHREADINFO guiInfo;
505 guiInfo.cbSize = sizeof(guiInfo);
506
507 GetGUIThreadInfo(0, &guiInfo);
508
509 if (bFollowMouse)
510 {
511 POINT pNewMouse;
512
513 //Get current mouse position
514 GetCursorPos (&pNewMouse);
515
516 #define PointsAreEqual(pt1, pt2) (((pt1).x == (pt2).x) && ((pt1).y == (pt2).y))
517
518 //If mouse has moved ...
519 if (!PointsAreEqual(pMouse, pNewMouse))
520 {
521 //Update to new position
522 pMouse = pNewMouse;
523 cp = pNewMouse;
524 hasMoved = TRUE;
525 }
526 }
527
528 if(guiInfo.hwndActive != hMainWnd)
529 {
530 if (bFollowCaret)
531 {
532 if (guiInfo.hwndCaret)
533 {
534 POINT ptCaret;
535 ptCaret.x = (guiInfo.rcCaret.left + guiInfo.rcCaret.right) / 2;
536 ptCaret.y = (guiInfo.rcCaret.top + guiInfo.rcCaret.bottom) / 2;
537
538 if ((pCaretWnd != guiInfo.hwndCaret) || !PointsAreEqual(pCaret, ptCaret))
539 {
540 //Update to new position
541 pCaret = ptCaret;
542 pCaretWnd = guiInfo.hwndCaret;
543 if(!hasMoved)
544 {
545 ClientToScreen (guiInfo.hwndCaret, (LPPOINT) &ptCaret);
546 cp = ptCaret;
547 hasMoved = TRUE;
548 }
549 }
550 }
551 else
552 {
553 pCaretWnd = NULL;
554 }
555 }
556
557 if (bFollowFocus)
558 {
559 if(guiInfo.hwndFocus && !guiInfo.hwndCaret)
560 {
561 POINT ptFocus;
562 RECT activeRect;
563
564 //Get current control focus
565 GetWindowRect(guiInfo.hwndFocus, &activeRect);
566 ptFocus.x = (activeRect.left + activeRect.right) / 2;
567 ptFocus.y = (activeRect.top + activeRect.bottom) / 2;
568
569 if((guiInfo.hwndFocus != pFocusWnd) || !PointsAreEqual(pFocus, ptFocus))
570 {
571 //Update to new position
572 pFocus = ptFocus;
573 pFocusWnd = guiInfo.hwndFocus;
574 if(!hasMoved)
575 {
576 cp = ptFocus;
577 hasMoved = TRUE;
578 }
579 }
580 }
581 else
582 {
583 pFocusWnd = NULL;
584 }
585 }
586 }
587
588 if(!hasMoved)
589 {
590 DWORD newTicks = GetTickCount();
591 DWORD elapsed = (newTicks - lastTicks);
592 if(elapsed > REPAINT_SPEED)
593 {
594 hasMoved = TRUE;
595 }
596 }
597
598 if(hasMoved)
599 {
600 lastTicks = GetTickCount();
601 Refresh();
602 }
603
604 return 0;
605 }
606
607 case WM_COMMAND:
608 {
609 wmId = LOWORD(wParam);
610 /* Parse the menu selections */
611 switch (wmId)
612 {
613 case IDM_OPTIONS:
614 if(bOptionsDialog)
615 {
616 ShowWindow(hOptionsDialog, SW_HIDE);
617 }
618 else
619 {
620 ShowWindow(hOptionsDialog, SW_SHOW);
621 }
622 break;
623 case IDM_ABOUT:
624 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, AboutProc);
625 break;
626 case IDM_EXIT:
627 DestroyWindow(hWnd);
628 break;
629 default:
630 return DefWindowProc(hWnd, message, wParam, lParam);
631 }
632 return 0;
633 }
634
635 case WM_PAINT:
636 {
637 PAINTSTRUCT PaintStruct;
638 HDC dc;
639 dc = BeginPaint(hWnd, &PaintStruct);
640 Draw(dc);
641 EndPaint(hWnd, &PaintStruct);
642 return 0;
643 }
644
645 case WM_CONTEXTMENU:
646 TrackPopupMenu(notifyMenu, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0, hWnd, NULL);
647 return 0;
648
649 case WM_LBUTTONDOWN:
650 {
651 RECT rc;
652 POINT pt;
653 SetCapture(hWnd);
654
655 GetCursorPos(&pt);
656 GetWindowRect(hWnd, &rc);
657 ptDragOffset.x = pt.x - rc.left;
658 ptDragOffset.y = pt.y - rc.top;
659
660 nearEdge = AppBarConfig.uEdge;
661
662 break;
663 }
664 case WM_MOUSEMOVE:
665 if(GetCapture() == hWnd)
666 {
667 RECT rc;
668 POINT pt;
669 RECT rcWorkArea;
670 SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
671 GetCursorPos(&pt);
672 GetWindowRect(hWnd, &rc);
673
674 if(AppBarConfig.uEdge>=0)
675 {
676 if (pt.x >= rcWorkArea.left && pt.x <= rcWorkArea.right &&
677 pt.y >= rcWorkArea.top && pt.y <= rcWorkArea.bottom)
678 {
679 AttachAppBar(-2);
680
681 // Fixup offset
682 GetWindowRect(hWnd, &rc);
683 ptDragOffset.x = (rc.right-rc.left)/2;
684 ptDragOffset.y = 2;
685
686 rc.left = pt.x - ptDragOffset.x;
687 rc.top = pt.y - ptDragOffset.y;
688
689 SetWindowPos(hWnd, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE);
690 }
691 }
692 else
693 {
694 if(pt.x <= rcWorkArea.left+8 && nearEdge != ABE_LEFT)
695 {
696 AttachAppBar(ABE_LEFT);
697 nearEdge = ABE_LEFT;
698 }
699 else if(pt.y <= rcWorkArea.top+8 && nearEdge != ABE_TOP)
700 {
701 AttachAppBar(ABE_TOP);
702 nearEdge = ABE_TOP;
703 }
704 else if(pt.x >= rcWorkArea.right-8 && nearEdge != ABE_RIGHT)
705 {
706 AttachAppBar(ABE_RIGHT);
707 nearEdge = ABE_RIGHT;
708 }
709 else if(pt.y >= rcWorkArea.bottom-8 && nearEdge != ABE_BOTTOM)
710 {
711 AttachAppBar(ABE_BOTTOM);
712 nearEdge = ABE_BOTTOM;
713 }
714 else
715 {
716 rc.left = pt.x - ptDragOffset.x;
717 rc.top = pt.y - ptDragOffset.y;
718
719 SetWindowPos(hWnd, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE);
720 nearEdge = -1;
721 }
722 }
723
724 pMouse = pt;
725 Refresh();
726 }
727 break;
728 case WM_LBUTTONUP:
729 if(GetCapture() == hWnd)
730 {
731 if (AppBarConfig.uEdge>=0)
732 DoAppBarStuff(ABM_GETSTATE);
733 else
734 SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
735 ReleaseCapture();
736 }
737 break;
738
739 case WM_SIZE:
740 if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_SETPOS);
741 /* fallthrough */
742 case WM_DISPLAYCHANGE:
743 bRecreateOffscreenDC = TRUE;
744 Refresh();
745 break;
746
747 case WM_ERASEBKGND:
748 // handle WM_ERASEBKGND by simply returning non-zero because we did all the drawing in WM_PAINT.
749 return 0;
750
751 case WM_DESTROY:
752 {
753 if (AppBarConfig.uEdge >= 0)
754 DoAppBarStuff(ABM_REMOVE);
755
756 KillTimer(hWnd, 1);
757
758 /* Save settings to registry */
759 SaveSettings();
760
761 /* Cleanup notification icon */
762 ZeroMemory(&nid, sizeof(nid));
763 nid.cbSize = sizeof(nid);
764 nid.uFlags = NIF_MESSAGE;
765 nid.hWnd = hWnd;
766 nid.uCallbackMessage = APPMSG_NOTIFYICON;
767 Shell_NotifyIcon(NIM_DELETE, &nid);
768 DestroyIcon(notifyIcon);
769
770 DestroyWindow(hOptionsDialog);
771
772 PostQuitMessage(0);
773 return 0;
774 }
775
776 case WM_CREATE:
777 {
778 HMENU tempMenu;
779
780 /* Get the desktop window */
781 hDesktopWindow = GetDesktopWindow();
782
783 /* Set the timer */
784 SetTimer(hWnd, 1, TIMER_SPEED, NULL);
785
786 /* Notification icon */
787 notifyIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, 0);
788
789 ZeroMemory(&nid, sizeof(nid));
790 nid.cbSize = sizeof(nid);
791 nid.uFlags = NIF_ICON | NIF_MESSAGE;
792 nid.hWnd = hWnd;
793 nid.uCallbackMessage = APPMSG_NOTIFYICON;
794 nid.hIcon = notifyIcon;
795 Shell_NotifyIcon(NIM_ADD, &nid);
796
797 tempMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDC_MAGNIFIER));
798 notifyMenu = GetSubMenu(tempMenu, 0);
799 RemoveMenu(tempMenu, 0, MF_BYPOSITION);
800 DestroyMenu(tempMenu);
801 return 0;
802 }
803
804 case APPMSG_APPBAR:
805 {
806 switch (wParam)
807 {
808 case ABN_STATECHANGE:
809 DoAppBarStuff(ABM_GETSTATE);
810 break;
811 case ABN_POSCHANGED:
812 DoAppBarStuff(ABM_SETPOS);
813 break;
814 case ABN_FULLSCREENAPP:
815 {
816 if(!lParam)
817 {
818 DoAppBarStuff(ABM_GETSTATE);
819 break;
820 }
821
822 SetWindowPos(hMainWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
823 break;
824 }
825 case ABN_WINDOWARRANGE:
826 if(lParam)
827 ShowWindow(hMainWnd, SW_HIDE);
828 else
829 ShowWindow(hMainWnd, SW_SHOW);
830 break;
831 }
832 return 0;
833 }
834
835 case APPMSG_NOTIFYICON:
836 HandleNotifyIconMessage(hWnd, wParam, lParam);
837 return 0;
838
839 case WM_ACTIVATE:
840 if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_ACTIVATE);
841 break;
842
843 case WM_WINDOWPOSCHANGED:
844 if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_WINDOWPOSCHANGED);
845 Refresh();
846 break;
847
848 default:
849 break;
850 }
851
852 return DefWindowProc(hWnd, message, wParam, lParam);
853 }
854
855 INT_PTR CALLBACK AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
856 {
857 UNREFERENCED_PARAMETER(lParam);
858 switch (message)
859 {
860 case WM_INITDIALOG:
861 return (INT_PTR)TRUE;
862
863 case WM_COMMAND:
864 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
865 {
866 EndDialog(hDlg, LOWORD(wParam));
867 return (INT_PTR)TRUE;
868 }
869 break;
870 }
871
872 return (INT_PTR)FALSE;
873 }
874
875 INT_PTR CALLBACK OptionsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
876 {
877 UNREFERENCED_PARAMETER(lParam);
878 switch (message)
879 {
880 case WM_SHOWWINDOW:
881 bOptionsDialog = wParam;
882 break;
883 case WM_INITDIALOG:
884 {
885 // Add the zoom items...
886 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("1"));
887 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("2"));
888 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("3"));
889 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("4"));
890 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("5"));
891 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("6"));
892 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("7"));
893 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("8"));
894
895 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_SETCURSEL, iZoom - 1, 0);
896
897 if (bFollowMouse)
898 SendDlgItemMessage(hDlg,IDC_FOLLOWMOUSECHECK,BM_SETCHECK , wParam ,0);
899
900 if (bFollowFocus)
901 SendDlgItemMessage(hDlg,IDC_FOLLOWKEYBOARDCHECK,BM_SETCHECK , wParam ,0);
902
903 if (bFollowCaret)
904 SendDlgItemMessage(hDlg,IDC_FOLLOWTEXTEDITINGCHECK,BM_SETCHECK , wParam ,0);
905
906 if (bInvertColors)
907 SendDlgItemMessage(hDlg,IDC_INVERTCOLORSCHECK,BM_SETCHECK , wParam ,0);
908
909 if (bStartMinimized)
910 SendDlgItemMessage(hDlg,IDC_STARTMINIMIZEDCHECK,BM_SETCHECK , wParam ,0);
911
912 if (bShowMagnifier)
913 SendDlgItemMessage(hDlg,IDC_SHOWMAGNIFIERCHECK,BM_SETCHECK , wParam ,0);
914
915 return (INT_PTR)TRUE;
916 }
917
918 case WM_COMMAND:
919 switch (LOWORD(wParam))
920 {
921 case IDOK:
922 case IDCANCEL:
923 ShowWindow(hDlg, SW_HIDE);
924 return (INT_PTR)TRUE;
925
926 case IDC_BUTTON_HELP:
927 /* Unimplemented */
928 MessageBox(hDlg , TEXT("Magnifier help not available yet!") , TEXT("Help") , MB_OK);
929 break;
930 case IDC_ZOOM:
931 if (HIWORD(wParam) == CBN_SELCHANGE)
932 {
933 HWND hCombo = GetDlgItem(hDlg,IDC_ZOOM);
934 TCHAR currentZoomValue[2] = TEXT("");
935
936 /* Get index of current selection and the text of that selection */
937 int currentSelectionIndex = ComboBox_GetCurSel(hCombo);
938 ComboBox_GetLBText(hCombo, currentSelectionIndex, currentZoomValue);
939 iZoom = _ttoi(currentZoomValue);
940
941 /* Trigger the Draw function to rezoom (which will be set false automatically after rezooming) */
942 bRecreateOffscreenDC = TRUE;
943
944 /* Update the magnifier UI */
945 Refresh();
946 }
947 break;
948 case IDC_INVERTCOLORSCHECK:
949 bInvertColors = IsDlgButtonChecked(hDlg, IDC_INVERTCOLORSCHECK);
950 Refresh();
951 break;
952 case IDC_FOLLOWMOUSECHECK:
953 bFollowMouse = IsDlgButtonChecked(hDlg, IDC_FOLLOWMOUSECHECK);
954 break;
955 case IDC_FOLLOWKEYBOARDCHECK:
956 bFollowFocus = IsDlgButtonChecked(hDlg, IDC_FOLLOWKEYBOARDCHECK);
957 break;
958 case IDC_FOLLOWTEXTEDITINGCHECK:
959 bFollowCaret = IsDlgButtonChecked(hDlg, IDC_FOLLOWTEXTEDITINGCHECK);
960 break;
961 case IDC_STARTMINIMIZEDCHECK:
962 bStartMinimized = IsDlgButtonChecked(hDlg, IDC_STARTMINIMIZEDCHECK);
963 break;
964 case IDC_SHOWMAGNIFIER:
965 bShowMagnifier = IsDlgButtonChecked(hDlg, IDC_SHOWMAGNIFIERCHECK);
966 if (bShowMagnifier)
967 ShowWindow (hMainWnd , SW_SHOW);
968 else
969 ShowWindow (hMainWnd , SW_HIDE);
970 break;
971 }
972 }
973
974 return (INT_PTR)FALSE;
975 }
976
977 INT_PTR CALLBACK WarningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
978 {
979 UNREFERENCED_PARAMETER(lParam);
980
981 switch (message)
982 {
983 case WM_INITDIALOG:
984 return (INT_PTR)TRUE;
985
986 case WM_COMMAND:
987 switch (LOWORD(wParam))
988 {
989 case IDC_SHOWWARNINGCHECK:
990 bShowWarning = !IsDlgButtonChecked(hDlg, IDC_SHOWWARNINGCHECK);
991 break;
992 }
993 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
994 {
995 EndDialog(hDlg, LOWORD(wParam));
996 return (INT_PTR)TRUE;
997 }
998 break;
999 }
1000
1001 return (INT_PTR)FALSE;
1002 }