Release 9.12.
[wine.git] / programs / notepad / main.c
blob69ab5215304a1f571bd9c026d495872505f21d94
1 /*
2 * Notepad
4 * Copyright 2000 Mike McCormack <Mike_McCormack@looksmart.com.au>
5 * Copyright 1997,98 Marcel Baur <mbaur@g26.ethz.ch>
6 * Copyright 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
7 * Copyright 2002 Andriy Palamarchuk
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include <stdio.h>
26 #include <windows.h>
27 #include <commctrl.h>
28 #include <commdlg.h>
29 #include <shellapi.h>
30 #include <shlwapi.h>
32 #include "main.h"
33 #include "dialog.h"
34 #include "notepad_res.h"
36 NOTEPAD_GLOBALS Globals;
37 static ATOM aFINDMSGSTRING;
38 static RECT main_rect;
40 static const WCHAR notepad_reg_key[] = {'S','o','f','t','w','a','r','e','\\',
41 'M','i','c','r','o','s','o','f','t','\\','N','o','t','e','p','a','d','\0'};
42 static const WCHAR value_fWrap[] = {'f','W','r','a','p','\0'};
43 static const WCHAR value_iPointSize[] = {'i','P','o','i','n','t','S','i','z','e','\0'};
44 static const WCHAR value_iWindowPosDX[] = {'i','W','i','n','d','o','w','P','o','s','D','X','\0'};
45 static const WCHAR value_iWindowPosDY[] = {'i','W','i','n','d','o','w','P','o','s','D','Y','\0'};
46 static const WCHAR value_iWindowPosX[] = {'i','W','i','n','d','o','w','P','o','s','X','\0'};
47 static const WCHAR value_iWindowPosY[] = {'i','W','i','n','d','o','w','P','o','s','Y','\0'};
48 static const WCHAR value_lfCharSet[] = {'l','f','C','h','a','r','S','e','t','\0'};
49 static const WCHAR value_lfClipPrecision[] = {'l','f','C','l','i','p','P','r','e','c','i','s','i','o','n','\0'};
50 static const WCHAR value_lfEscapement[] = {'l','f','E','s','c','a','p','e','m','e','n','t','\0'};
51 static const WCHAR value_lfItalic[] = {'l','f','I','t','a','l','i','c','\0'};
52 static const WCHAR value_lfOrientation[] = {'l','f','O','r','i','e','n','t','a','t','i','o','n','\0'};
53 static const WCHAR value_lfOutPrecision[] = {'l','f','O','u','t','P','r','e','c','i','s','i','o','n','\0'};
54 static const WCHAR value_lfPitchAndFamily[] = {'l','f','P','i','t','c','h','A','n','d','F','a','m','i','l','y','\0'};
55 static const WCHAR value_lfQuality[] = {'l','f','Q','u','a','l','i','t','y','\0'};
56 static const WCHAR value_lfStrikeOut[] = {'l','f','S','t','r','i','k','e','O','u','t','\0'};
57 static const WCHAR value_lfUnderline[] = {'l','f','U','n','d','e','r','l','i','n','e','\0'};
58 static const WCHAR value_lfWeight[] = {'l','f','W','e','i','g','h','t','\0'};
59 static const WCHAR value_lfFaceName[] = {'l','f','F','a','c','e','N','a','m','e','\0'};
60 static const WCHAR value_iMarginTop[] = {'i','M','a','r','g','i','n','T','o','p','\0'};
61 static const WCHAR value_iMarginBottom[] = {'i','M','a','r','g','i','n','B','o','t','t','o','m','\0'};
62 static const WCHAR value_iMarginLeft[] = {'i','M','a','r','g','i','n','L','e','f','t','\0'};
63 static const WCHAR value_iMarginRight[] = {'i','M','a','r','g','i','n','R','i','g','h','t','\0'};
64 static const WCHAR value_szHeader[] = {'s','z','H','e','a','d','e','r','\0'};
65 static const WCHAR value_szFooter[] = {'s','z','T','r','a','i','l','e','r','\0'};
66 static const WCHAR value_bStatusBar[] = {'b','S','t','a','t','u','s','B','a','r','\0'};
68 /***********************************************************************
70 * SetFileNameAndEncoding
72 * Sets global file name and encoding (which is used to preselect original
73 * encoding in Save As dialog, and when saving without using the Save As
74 * dialog).
76 VOID SetFileNameAndEncoding(LPCWSTR szFileName, ENCODING enc)
78 lstrcpyW(Globals.szFileName, szFileName);
79 Globals.szFileTitle[0] = 0;
80 GetFileTitleW(szFileName, Globals.szFileTitle, ARRAY_SIZE(Globals.szFileTitle));
81 Globals.encFile = enc;
84 void UpdateStatusBar(void)
86 int currentLine;
87 int currentCol = -1;
88 WCHAR statusTxt[256];
89 int lineIndex;
90 DWORD selStart;
91 DWORD selEnd;
93 SendMessageW(Globals.hEdit, EM_GETSEL, (WPARAM)&selStart, (LPARAM)&selEnd);
94 if(selStart == selEnd)
95 Globals.trackedSel = selStart;
96 if(selStart < Globals.trackedSel)
97 currentCol = selStart;
98 else
99 currentCol = selEnd;
100 currentLine = SendMessageW(Globals.hEdit, EM_LINEFROMCHAR, currentCol, 0);
101 lineIndex = SendMessageW(Globals.hEdit, EM_LINEINDEX, currentLine, 0);
102 if(Globals.lastLn != currentLine || Globals.lastCol != currentCol)
104 swprintf(statusTxt, ARRAY_SIZE(statusTxt), Globals.szStatusString, currentLine + 1, (currentCol - lineIndex) + 1);
105 SendMessageW(Globals.hStatusBar, SB_SETTEXTW, 0, (LPARAM)statusTxt);
106 Globals.lastLn = currentLine;
107 Globals.lastCol = currentCol;
111 static void ToggleStatusBar(void)
113 RECT rc;
115 Globals.bStatusBar = !Globals.bStatusBar;
116 CheckMenuItem(GetMenu(Globals.hMainWnd), CMD_SBAR,
117 MF_BYCOMMAND | (Globals.bStatusBar ? MF_CHECKED : MF_UNCHECKED));
118 GetClientRect(Globals.hMainWnd, &rc);
119 ShowWindow(Globals.hStatusBar, Globals.bStatusBar ? SW_SHOW : SW_HIDE);
120 updateWindowSize(rc.right, rc.bottom);
121 UpdateStatusBar();
124 void updateWindowSize(int width, int height)
126 int StatusBarHeight = 0;
128 if(Globals.bStatusBar)
130 RECT SBarRect;
132 SendMessageW(Globals.hStatusBar, WM_SIZE, 0, 0);
133 GetWindowRect(Globals.hStatusBar, &SBarRect);
134 StatusBarHeight = (SBarRect.bottom - SBarRect.top);
136 SetWindowPos(Globals.hEdit, NULL, 0, 0, width, height - StatusBarHeight,
137 SWP_NOOWNERZORDER | SWP_NOZORDER);
140 /***********************************************************************
142 * NOTEPAD_SaveSettingToRegistry
144 * Save setting to registry HKCU\Software\Microsoft\Notepad.
146 static VOID NOTEPAD_SaveSettingToRegistry(void)
148 HKEY hkey;
149 DWORD disp;
151 if(RegCreateKeyExW(HKEY_CURRENT_USER, notepad_reg_key, 0, NULL,
152 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &disp) == ERROR_SUCCESS)
154 DWORD data;
155 WINDOWPLACEMENT wndpl;
157 wndpl.length = sizeof(WINDOWPLACEMENT);
158 GetWindowPlacement(Globals.hMainWnd, &wndpl);
159 main_rect = wndpl.rcNormalPosition;
161 #define SET_NOTEPAD_REG(hkey, value_name, value_data) do { DWORD data = value_data; RegSetValueExW(hkey, value_name, 0, REG_DWORD, (LPBYTE)&data, sizeof(DWORD)); }while(0)
162 SET_NOTEPAD_REG(hkey, value_fWrap, Globals.bWrapLongLines);
163 SET_NOTEPAD_REG(hkey, value_iWindowPosX, main_rect.left);
164 SET_NOTEPAD_REG(hkey, value_iWindowPosY, main_rect.top);
165 SET_NOTEPAD_REG(hkey, value_iWindowPosDX, main_rect.right - main_rect.left);
166 SET_NOTEPAD_REG(hkey, value_iWindowPosDY, main_rect.bottom - main_rect.top);
167 SET_NOTEPAD_REG(hkey, value_lfCharSet, Globals.lfFont.lfCharSet);
168 SET_NOTEPAD_REG(hkey, value_lfClipPrecision, Globals.lfFont.lfClipPrecision);
169 SET_NOTEPAD_REG(hkey, value_lfEscapement, Globals.lfFont.lfEscapement);
170 SET_NOTEPAD_REG(hkey, value_lfItalic, Globals.lfFont.lfItalic);
171 SET_NOTEPAD_REG(hkey, value_lfOrientation, Globals.lfFont.lfOrientation);
172 SET_NOTEPAD_REG(hkey, value_lfOutPrecision, Globals.lfFont.lfOutPrecision);
173 SET_NOTEPAD_REG(hkey, value_lfPitchAndFamily, Globals.lfFont.lfPitchAndFamily);
174 SET_NOTEPAD_REG(hkey, value_lfQuality, Globals.lfFont.lfQuality);
175 SET_NOTEPAD_REG(hkey, value_lfStrikeOut, Globals.lfFont.lfStrikeOut);
176 SET_NOTEPAD_REG(hkey, value_lfUnderline, Globals.lfFont.lfUnderline);
177 SET_NOTEPAD_REG(hkey, value_lfWeight, Globals.lfFont.lfWeight);
178 SET_NOTEPAD_REG(hkey, value_iMarginTop, Globals.iMarginTop);
179 SET_NOTEPAD_REG(hkey, value_iMarginBottom, Globals.iMarginBottom);
180 SET_NOTEPAD_REG(hkey, value_iMarginLeft, Globals.iMarginLeft);
181 SET_NOTEPAD_REG(hkey, value_iMarginRight, Globals.iMarginRight);
182 SET_NOTEPAD_REG(hkey, value_bStatusBar, Globals.bStatusBar);
183 #undef SET_NOTEPAD_REG
185 /* Store the current value as 10 * twips */
186 data = MulDiv(abs(Globals.lfFont.lfHeight), 720, GetDpiForWindow(Globals.hMainWnd));
187 RegSetValueExW(hkey, value_iPointSize, 0, REG_DWORD, (LPBYTE)&data, sizeof(DWORD));
189 RegSetValueExW(hkey, value_lfFaceName, 0, REG_SZ, (LPBYTE)&Globals.lfFont.lfFaceName,
190 lstrlenW(Globals.lfFont.lfFaceName) * sizeof(Globals.lfFont.lfFaceName[0]));
192 RegSetValueExW(hkey, value_szHeader, 0, REG_SZ, (LPBYTE)&Globals.szHeader,
193 lstrlenW(Globals.szHeader) * sizeof(Globals.szHeader[0]));
195 RegSetValueExW(hkey, value_szFooter, 0, REG_SZ, (LPBYTE)&Globals.szFooter,
196 lstrlenW(Globals.szFooter) * sizeof(Globals.szFooter[0]));
198 RegCloseKey(hkey);
202 /***********************************************************************
204 * NOTEPAD_LoadSettingFromRegistry
206 * Load setting from registry HKCU\Software\Microsoft\Notepad.
208 static VOID NOTEPAD_LoadSettingFromRegistry(void)
210 static const WCHAR systemW[] = { 'S','y','s','t','e','m','\0' };
211 HKEY hkey;
212 INT base_length, dx, dy;
214 base_length = (GetSystemMetrics(SM_CXSCREEN) > GetSystemMetrics(SM_CYSCREEN))?
215 GetSystemMetrics(SM_CYSCREEN) : GetSystemMetrics(SM_CXSCREEN);
217 dx = base_length * .95;
218 dy = dx * 3 / 4;
219 SetRect( &main_rect, 0, 0, dx, dy );
221 Globals.bWrapLongLines = TRUE;
222 Globals.iMarginTop = 2500;
223 Globals.iMarginBottom = 2500;
224 Globals.iMarginLeft = 2000;
225 Globals.iMarginRight = 2000;
226 Globals.bStatusBar = TRUE;
228 Globals.lfFont.lfHeight = -12;
229 Globals.lfFont.lfWidth = 0;
230 Globals.lfFont.lfEscapement = 0;
231 Globals.lfFont.lfOrientation = 0;
232 Globals.lfFont.lfWeight = FW_REGULAR;
233 Globals.lfFont.lfItalic = FALSE;
234 Globals.lfFont.lfUnderline = FALSE;
235 Globals.lfFont.lfStrikeOut = FALSE;
236 Globals.lfFont.lfCharSet = DEFAULT_CHARSET;
237 Globals.lfFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
238 Globals.lfFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
239 Globals.lfFont.lfQuality = DEFAULT_QUALITY;
240 Globals.lfFont.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
241 lstrcpyW(Globals.lfFont.lfFaceName, systemW);
243 LoadStringW(Globals.hInstance, STRING_PAGESETUP_HEADERVALUE,
244 Globals.szHeader, ARRAY_SIZE(Globals.szHeader));
245 LoadStringW(Globals.hInstance, STRING_PAGESETUP_FOOTERVALUE,
246 Globals.szFooter, ARRAY_SIZE(Globals.szFooter));
248 if(RegOpenKeyW(HKEY_CURRENT_USER, notepad_reg_key, &hkey) == ERROR_SUCCESS)
250 WORD data_helper[MAX_PATH];
251 DWORD type, size;
252 int point_size;
254 #define QUERY_NOTEPAD_REG(hkey, value_name, ret) do { DWORD type, data; DWORD size = sizeof(DWORD); if(RegQueryValueExW(hkey, value_name, 0, &type, (LPBYTE)&data, &size) == ERROR_SUCCESS) if(type == REG_DWORD) ret = data; } while(0)
255 QUERY_NOTEPAD_REG(hkey, value_fWrap, Globals.bWrapLongLines);
256 QUERY_NOTEPAD_REG(hkey, value_iWindowPosX, main_rect.left);
257 QUERY_NOTEPAD_REG(hkey, value_iWindowPosY, main_rect.top);
258 QUERY_NOTEPAD_REG(hkey, value_iWindowPosDX, dx);
259 QUERY_NOTEPAD_REG(hkey, value_iWindowPosDY, dy);
260 QUERY_NOTEPAD_REG(hkey, value_lfCharSet, Globals.lfFont.lfCharSet);
261 QUERY_NOTEPAD_REG(hkey, value_lfClipPrecision, Globals.lfFont.lfClipPrecision);
262 QUERY_NOTEPAD_REG(hkey, value_lfEscapement, Globals.lfFont.lfEscapement);
263 QUERY_NOTEPAD_REG(hkey, value_lfItalic, Globals.lfFont.lfItalic);
264 QUERY_NOTEPAD_REG(hkey, value_lfOrientation, Globals.lfFont.lfOrientation);
265 QUERY_NOTEPAD_REG(hkey, value_lfOutPrecision, Globals.lfFont.lfOutPrecision);
266 QUERY_NOTEPAD_REG(hkey, value_lfPitchAndFamily, Globals.lfFont.lfPitchAndFamily);
267 QUERY_NOTEPAD_REG(hkey, value_lfQuality, Globals.lfFont.lfQuality);
268 QUERY_NOTEPAD_REG(hkey, value_lfStrikeOut, Globals.lfFont.lfStrikeOut);
269 QUERY_NOTEPAD_REG(hkey, value_lfUnderline, Globals.lfFont.lfUnderline);
270 QUERY_NOTEPAD_REG(hkey, value_lfWeight, Globals.lfFont.lfWeight);
271 QUERY_NOTEPAD_REG(hkey, value_iMarginTop, Globals.iMarginTop);
272 QUERY_NOTEPAD_REG(hkey, value_iMarginBottom, Globals.iMarginBottom);
273 QUERY_NOTEPAD_REG(hkey, value_iMarginLeft, Globals.iMarginLeft);
274 QUERY_NOTEPAD_REG(hkey, value_iMarginRight, Globals.iMarginRight);
275 QUERY_NOTEPAD_REG(hkey, value_bStatusBar, Globals.bStatusBar);
276 #undef QUERY_NOTEPAD_REG
278 main_rect.right = main_rect.left + dx;
279 main_rect.bottom = main_rect.top + dy;
281 size = sizeof(DWORD);
282 if(RegQueryValueExW(hkey, value_iPointSize, 0, &type, (LPBYTE)&point_size, &size) == ERROR_SUCCESS)
283 if(type == REG_DWORD && point_size)
284 /* The value is stored as 10 * twips */
285 Globals.lfFont.lfHeight = -MulDiv(abs(point_size), GetDpiForWindow(GetDesktopWindow()), 720);
287 size = sizeof(Globals.lfFont.lfFaceName);
288 if(RegQueryValueExW(hkey, value_lfFaceName, 0, &type, (LPBYTE)&data_helper, &size) == ERROR_SUCCESS)
289 if(type == REG_SZ)
290 lstrcpyW(Globals.lfFont.lfFaceName, data_helper);
292 size = sizeof(Globals.szHeader);
293 if(RegQueryValueExW(hkey, value_szHeader, 0, &type, (LPBYTE)&data_helper, &size) == ERROR_SUCCESS)
294 if(type == REG_SZ)
295 lstrcpyW(Globals.szHeader, data_helper);
297 size = sizeof(Globals.szFooter);
298 if(RegQueryValueExW(hkey, value_szFooter, 0, &type, (LPBYTE)&data_helper, &size) == ERROR_SUCCESS)
299 if(type == REG_SZ)
300 lstrcpyW(Globals.szFooter, data_helper);
301 RegCloseKey(hkey);
305 /***********************************************************************
307 * NOTEPAD_MenuCommand
309 * All handling of main menu events
311 static int NOTEPAD_MenuCommand(WPARAM wParam)
313 switch (wParam)
315 case CMD_NEW: DIALOG_FileNew(); break;
316 case CMD_OPEN: DIALOG_FileOpen(); break;
317 case CMD_SAVE: DIALOG_FileSave(); break;
318 case CMD_SAVE_AS: DIALOG_FileSaveAs(); break;
319 case CMD_PRINT: DIALOG_FilePrint(); break;
320 case CMD_PAGE_SETUP: DIALOG_FilePageSetup(); break;
321 case CMD_PRINTER_SETUP: DIALOG_FilePrinterSetup();break;
322 case CMD_EXIT: DIALOG_FileExit(); break;
324 case CMD_UNDO: DIALOG_EditUndo(); break;
325 case CMD_CUT: DIALOG_EditCut(); break;
326 case CMD_COPY: DIALOG_EditCopy(); break;
327 case CMD_PASTE: DIALOG_EditPaste(); break;
328 case CMD_DELETE: DIALOG_EditDelete(); break;
329 case CMD_SELECT_ALL: DIALOG_EditSelectAll(); break;
330 case CMD_TIME_DATE: DIALOG_EditTimeDate();break;
332 case CMD_SEARCH: DIALOG_Search(); break;
333 case CMD_SEARCH_NEXT: DIALOG_SearchNext(); break;
334 case CMD_REPLACE: DIALOG_Replace(); break;
335 case CMD_GO_TO: DIALOG_EditGoTo(); break;
337 case CMD_WRAP: DIALOG_EditWrap(); break;
338 case CMD_FONT: DIALOG_SelectFont(); break;
339 case CMD_SBAR: ToggleStatusBar(); break;
341 case CMD_HELP_CONTENTS: DIALOG_HelpContents(); break;
342 case CMD_HELP_ABOUT_NOTEPAD: DIALOG_HelpAboutNotepad(); break;
344 default:
345 break;
347 return 0;
350 /***********************************************************************
351 * Data Initialization
353 static VOID NOTEPAD_InitData(VOID)
355 LPWSTR p = Globals.szFilter;
356 static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
357 static const WCHAR all_files[] = { '*','.','*',0 };
359 LoadStringW(Globals.hInstance, STRING_TEXT_FILES_TXT, p, MAX_STRING_LEN);
360 p += lstrlenW(p) + 1;
361 lstrcpyW(p, txt_files);
362 p += lstrlenW(p) + 1;
363 LoadStringW(Globals.hInstance, STRING_ALL_FILES, p, MAX_STRING_LEN);
364 p += lstrlenW(p) + 1;
365 lstrcpyW(p, all_files);
366 p += lstrlenW(p) + 1;
367 *p = '\0';
368 Globals.hDevMode = NULL;
369 Globals.hDevNames = NULL;
371 CheckMenuItem(GetMenu(Globals.hMainWnd), CMD_WRAP,
372 MF_BYCOMMAND | (Globals.bWrapLongLines ? MF_CHECKED : MF_UNCHECKED));
373 CheckMenuItem(GetMenu(Globals.hMainWnd), CMD_SBAR,
374 MF_BYCOMMAND | (Globals.bStatusBar ? MF_CHECKED : MF_UNCHECKED));
375 ShowWindow(Globals.hStatusBar, Globals.bStatusBar ? SW_SHOW : SW_HIDE);
378 /***********************************************************************
379 * Enable/disable items on the menu based on control state
381 static VOID NOTEPAD_InitMenuPopup(HMENU menu, int index)
383 int enable;
385 EnableMenuItem(menu, CMD_UNDO,
386 SendMessageW(Globals.hEdit, EM_CANUNDO, 0, 0) ? MF_ENABLED : MF_GRAYED);
387 EnableMenuItem(menu, CMD_PASTE,
388 IsClipboardFormatAvailable(CF_TEXT) ? MF_ENABLED : MF_GRAYED);
389 enable = SendMessageW(Globals.hEdit, EM_GETSEL, 0, 0);
390 enable = (HIWORD(enable) == LOWORD(enable)) ? MF_GRAYED : MF_ENABLED;
391 EnableMenuItem(menu, CMD_CUT, enable);
392 EnableMenuItem(menu, CMD_COPY, enable);
393 EnableMenuItem(menu, CMD_DELETE, enable);
395 EnableMenuItem(menu, CMD_SELECT_ALL,
396 GetWindowTextLengthW(Globals.hEdit) ? MF_ENABLED : MF_GRAYED);
399 static LPWSTR NOTEPAD_StrRStr(LPWSTR pszSource, LPWSTR pszLast, LPWSTR pszSrch)
401 int len = lstrlenW(pszSrch);
402 pszLast--;
403 while (pszLast >= pszSource)
405 if (StrCmpNW(pszLast, pszSrch, len) == 0)
406 return pszLast;
407 pszLast--;
409 return NULL;
412 /***********************************************************************
413 * The user activated the Find dialog
415 void NOTEPAD_DoFind(FINDREPLACEW *fr)
417 LPWSTR content, found;
418 int len = lstrlenW(fr->lpstrFindWhat);
419 int fileLen;
420 DWORD pos;
422 fileLen = GetWindowTextLengthW(Globals.hEdit) + 1;
423 content = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
424 if (!content) return;
425 GetWindowTextW(Globals.hEdit, content, fileLen);
427 SendMessageW(Globals.hEdit, EM_GETSEL, 0, (LPARAM)&pos);
428 switch (fr->Flags & (FR_DOWN|FR_MATCHCASE))
430 case 0:
431 found = StrRStrIW(content, content+pos-len, fr->lpstrFindWhat);
432 break;
433 case FR_DOWN:
434 found = StrStrIW(content+pos, fr->lpstrFindWhat);
435 break;
436 case FR_MATCHCASE:
437 found = NOTEPAD_StrRStr(content, content+pos-len, fr->lpstrFindWhat);
438 break;
439 case FR_DOWN|FR_MATCHCASE:
440 found = StrStrW(content+pos, fr->lpstrFindWhat);
441 break;
442 default: /* shouldn't happen */
443 return;
445 pos = found - content;
446 HeapFree(GetProcessHeap(), 0, content);
448 if (!found)
450 DIALOG_StringMsgBox(Globals.hFindReplaceDlg, STRING_NOTFOUND, fr->lpstrFindWhat,
451 MB_ICONINFORMATION|MB_OK);
452 return;
455 SendMessageW(Globals.hEdit, EM_SETSEL, pos, pos + len);
458 static void NOTEPAD_DoReplace(FINDREPLACEW *fr)
460 LPWSTR content;
461 int len = lstrlenW(fr->lpstrFindWhat);
462 int fileLen;
463 DWORD pos;
464 DWORD pos_start;
466 fileLen = GetWindowTextLengthW(Globals.hEdit) + 1;
467 content = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
468 if (!content) return;
469 GetWindowTextW(Globals.hEdit, content, fileLen);
471 SendMessageW(Globals.hEdit, EM_GETSEL, (WPARAM)&pos_start, (LPARAM)&pos);
472 switch (fr->Flags & (FR_DOWN|FR_MATCHCASE))
474 case FR_DOWN:
475 if ( pos-pos_start == len && StrCmpNIW(fr->lpstrFindWhat, content+pos_start, len) == 0)
476 SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)fr->lpstrReplaceWith);
477 break;
478 case FR_DOWN|FR_MATCHCASE:
479 if ( pos-pos_start == len && StrCmpNW(fr->lpstrFindWhat, content+pos_start, len) == 0)
480 SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)fr->lpstrReplaceWith);
481 break;
482 default: /* shouldn't happen */
483 return;
485 HeapFree(GetProcessHeap(), 0, content);
487 NOTEPAD_DoFind(fr);
490 static void NOTEPAD_DoReplaceAll(FINDREPLACEW *fr)
492 LPWSTR content;
493 int len = lstrlenW(fr->lpstrFindWhat);
494 int fileLen;
495 SIZE_T pos;
497 SendMessageW(Globals.hEdit, EM_SETSEL, 0, 0);
498 while(TRUE){
499 fileLen = GetWindowTextLengthW(Globals.hEdit) + 1;
500 content = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
501 if (!content) return;
502 GetWindowTextW(Globals.hEdit, content, fileLen);
504 SendMessageW(Globals.hEdit, EM_GETSEL, 0, (LPARAM)&pos);
505 switch (fr->Flags & (FR_DOWN|FR_MATCHCASE))
507 case FR_DOWN:
508 pos = StrStrIW(content+pos, fr->lpstrFindWhat) - content;
509 if (pos == -(SIZE_T)content) pos = ~(SIZE_T)0;
510 break;
511 case FR_DOWN|FR_MATCHCASE:
512 pos = StrStrW(content+pos, fr->lpstrFindWhat) - content;
513 if (pos == -(SIZE_T)content) pos = ~(SIZE_T)0;
514 break;
515 default: /* shouldn't happen */
516 return;
518 HeapFree(GetProcessHeap(), 0, content);
520 if(pos == ~(SIZE_T)0)
522 SendMessageW(Globals.hEdit, EM_SETSEL, 0, 0);
523 return;
525 SendMessageW(Globals.hEdit, EM_SETSEL, pos, pos + len);
526 SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)fr->lpstrReplaceWith);
530 LRESULT CALLBACK EDIT_CallBackProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam,
531 UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
533 switch (msg)
535 case WM_KEYDOWN:
536 case WM_KEYUP:
537 case WM_MBUTTONDOWN:
538 case WM_MBUTTONUP:
539 case WM_LBUTTONDOWN:
540 case WM_LBUTTONUP:
541 UpdateStatusBar();
542 break;
543 case WM_MOUSEMOVE:
544 if(wParam == MK_LBUTTON)
545 UpdateStatusBar();
546 break;
548 default:
549 break;
551 return DefSubclassProc(hWnd, msg, wParam, lParam);
555 /***********************************************************************
557 * NOTEPAD_WndProc
559 static LRESULT WINAPI NOTEPAD_WndProc(HWND hWnd, UINT msg, WPARAM wParam,
560 LPARAM lParam)
562 if (msg == aFINDMSGSTRING) /* not a constant so can't be used in switch */
564 FINDREPLACEW *fr = (FINDREPLACEW *)lParam;
566 if (fr->Flags & FR_DIALOGTERM)
567 Globals.hFindReplaceDlg = NULL;
568 if (fr->Flags & FR_FINDNEXT)
570 Globals.lastFind = *fr;
571 NOTEPAD_DoFind(fr);
573 if (fr->Flags & FR_REPLACE)
575 Globals.lastFind = *fr;
576 NOTEPAD_DoReplace(fr);
578 if (fr->Flags & FR_REPLACEALL)
580 Globals.lastFind = *fr;
581 NOTEPAD_DoReplaceAll(fr);
583 return 0;
586 switch (msg) {
588 case WM_CREATE:
590 static const WCHAR editW[] = { 'e','d','i','t',0 };
591 DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL |
592 ES_AUTOVSCROLL | ES_MULTILINE | ES_NOHIDESEL;
593 RECT rc;
594 GetClientRect(hWnd, &rc);
596 if (!Globals.bWrapLongLines) dwStyle |= WS_HSCROLL | ES_AUTOHSCROLL;
598 Globals.hEdit = CreateWindowExW(WS_EX_CLIENTEDGE, editW, NULL,
599 dwStyle, 0, 0, rc.right, rc.bottom, hWnd,
600 NULL, Globals.hInstance, NULL);
602 SetWindowSubclass(Globals.hEdit, EDIT_CallBackProc, 0, 0);
603 Globals.hFont = CreateFontIndirectW(&Globals.lfFont);
604 SendMessageW(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, FALSE);
605 SendMessageW(Globals.hEdit, EM_LIMITTEXT, 0, 0);
606 Globals.hStatusBar = CreateWindowExW(0, STATUSCLASSNAMEW, NULL,
607 WS_VISIBLE | WS_CHILD, 0, 0, 0, 0, hWnd, NULL,
608 Globals.hInstance, NULL);
609 LoadStringW(Globals.hInstance, STRING_STATUSBAR, (LPWSTR)&Globals.szStatusString, 0);
610 Globals.lastLn = -1;
611 Globals.lastCol = -1;
612 UpdateStatusBar();
613 break;
616 case WM_COMMAND:
617 NOTEPAD_MenuCommand(LOWORD(wParam));
618 break;
620 case WM_DESTROYCLIPBOARD:
621 /*MessageBoxW(Globals.hMainWnd, "Empty clipboard", "Debug", MB_ICONEXCLAMATION);*/
622 break;
624 case WM_CLOSE:
625 if (DoCloseFile()) {
626 DestroyWindow(hWnd);
628 break;
630 case WM_QUERYENDSESSION:
631 if (DoCloseFile()) {
632 return 1;
634 break;
636 case WM_DESTROY:
637 NOTEPAD_SaveSettingToRegistry();
639 PostQuitMessage(0);
640 break;
642 case WM_SIZE:
643 updateWindowSize(LOWORD(lParam), HIWORD(lParam));
644 break;
646 case WM_SETFOCUS:
647 SetFocus(Globals.hEdit);
648 break;
650 case WM_DROPFILES:
652 WCHAR szFileName[MAX_PATH];
653 HANDLE hDrop = (HANDLE) wParam;
655 DragQueryFileW(hDrop, 0, szFileName, ARRAY_SIZE(szFileName));
656 DragFinish(hDrop);
657 DoOpenFile(szFileName, ENCODING_AUTO);
658 break;
661 case WM_INITMENUPOPUP:
662 NOTEPAD_InitMenuPopup((HMENU)wParam, lParam);
663 break;
665 default:
666 return DefWindowProcW(hWnd, msg, wParam, lParam);
668 return 0;
671 static int AlertFileDoesNotExist(LPCWSTR szFileName)
673 int nResult;
674 WCHAR szMessage[MAX_STRING_LEN];
675 WCHAR szResource[MAX_STRING_LEN];
677 LoadStringW(Globals.hInstance, STRING_DOESNOTEXIST, szResource, ARRAY_SIZE(szResource));
678 wsprintfW(szMessage, szResource, szFileName);
680 LoadStringW(Globals.hInstance, STRING_ERROR, szResource, ARRAY_SIZE(szResource));
682 nResult = MessageBoxW(Globals.hMainWnd, szMessage, szResource,
683 MB_ICONEXCLAMATION | MB_YESNOCANCEL);
685 return(nResult);
688 static void HandleCommandLine(LPWSTR cmdline)
690 WCHAR delimiter, *ptr;
691 BOOL opt_print = FALSE;
693 /* skip white space */
694 while (*cmdline == ' ') cmdline++;
696 /* skip executable name */
697 delimiter = (*cmdline == '"' ? '"' : ' ');
699 if (*cmdline == delimiter) cmdline++;
701 while (*cmdline && *cmdline != delimiter) cmdline++;
703 if (*cmdline == delimiter) cmdline++;
705 while (*cmdline == ' ') cmdline++;
707 ptr = cmdline;
708 while (*ptr == ' ' || *ptr == '-' || *ptr == '/')
710 WCHAR option;
712 if (*ptr++ == ' ') continue;
714 option = *ptr;
715 if (option) ptr++;
716 while (*ptr == ' ') ptr++;
718 switch(option)
720 case 'p':
721 case 'P':
723 if (!opt_print)
725 opt_print = TRUE;
726 cmdline = ptr;
728 break;
733 if (*cmdline)
735 /* file name is passed in the command line */
736 LPCWSTR file_name;
737 BOOL file_exists;
738 WCHAR buf[MAX_PATH];
740 if (cmdline[0] == '"')
742 WCHAR* wc;
743 cmdline++;
744 wc=cmdline;
745 /* Note: Double-quotes are not allowed in Windows filenames */
746 while (*wc && *wc != '"') wc++;
747 /* On Windows notepad ignores further arguments too */
748 *wc = 0;
751 if (FileExists(cmdline))
753 file_exists = TRUE;
754 file_name = cmdline;
756 else
758 static const WCHAR txtW[] = { '.','t','x','t',0 };
760 /* try to find file with ".txt" extension */
761 if (wcschr(PathFindFileNameW(cmdline), '.'))
763 file_exists = FALSE;
764 file_name = cmdline;
766 else
768 lstrcpynW(buf, cmdline, MAX_PATH - lstrlenW(txtW) - 1);
769 lstrcatW(buf, txtW);
770 file_name = buf;
771 file_exists = FileExists(buf);
775 if (file_exists)
777 DoOpenFile(file_name, ENCODING_AUTO);
778 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
779 if (opt_print)
780 DIALOG_FilePrint();
782 else
784 switch (AlertFileDoesNotExist(file_name)) {
785 case IDYES:
788 HANDLE file;
789 SetFileNameAndEncoding(file_name, ENCODING_ANSI);
791 file = CreateFileW(file_name, GENERIC_WRITE, FILE_SHARE_WRITE,
792 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
793 if (file != INVALID_HANDLE_VALUE) CloseHandle(file);
795 UpdateWindowCaption();
796 break;
799 case IDNO:
800 break;
802 case IDCANCEL:
803 DestroyWindow(Globals.hMainWnd);
804 break;
810 /***********************************************************************
812 * WinMain
814 int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
816 MSG msg;
817 HACCEL hAccel;
818 WNDCLASSEXW class;
819 HMONITOR monitor;
820 MONITORINFO info;
821 INT x, y;
822 static const WCHAR className[] = {'N','o','t','e','p','a','d',0};
823 static const WCHAR winName[] = {'N','o','t','e','p','a','d',0};
825 InitCommonControls();
827 aFINDMSGSTRING = RegisterWindowMessageW(FINDMSGSTRINGW);
829 ZeroMemory(&Globals, sizeof(Globals));
830 Globals.hInstance = hInstance;
831 NOTEPAD_LoadSettingFromRegistry();
833 ZeroMemory(&class, sizeof(class));
834 class.cbSize = sizeof(class);
835 class.lpfnWndProc = NOTEPAD_WndProc;
836 class.hInstance = Globals.hInstance;
837 class.hIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_NOTEPAD));
838 class.hIconSm = LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IDI_NOTEPAD), IMAGE_ICON,
839 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
840 LR_SHARED);
841 class.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
842 class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
843 class.lpszMenuName = MAKEINTRESOURCEW(MAIN_MENU);
844 class.lpszClassName = className;
846 if (!RegisterClassExW(&class)) return FALSE;
848 /* Setup windows */
850 monitor = MonitorFromRect( &main_rect, MONITOR_DEFAULTTOPRIMARY );
851 info.cbSize = sizeof(info);
852 GetMonitorInfoW( monitor, &info );
854 x = main_rect.left;
855 y = main_rect.top;
856 if (main_rect.left >= info.rcWork.right ||
857 main_rect.top >= info.rcWork.bottom ||
858 main_rect.right < info.rcWork.left ||
859 main_rect.bottom < info.rcWork.top)
860 x = y = CW_USEDEFAULT;
862 Globals.hMainWnd =
863 CreateWindowW(className, winName, WS_OVERLAPPEDWINDOW, x, y,
864 main_rect.right - main_rect.left, main_rect.bottom - main_rect.top,
865 NULL, NULL, Globals.hInstance, NULL);
866 if (!Globals.hMainWnd)
868 ShowLastError();
869 ExitProcess(1);
872 NOTEPAD_InitData();
873 DIALOG_FileNew();
875 ShowWindow(Globals.hMainWnd, show);
876 UpdateWindow(Globals.hMainWnd);
877 DragAcceptFiles(Globals.hMainWnd, TRUE);
879 HandleCommandLine(GetCommandLineW());
881 hAccel = LoadAcceleratorsW(hInstance, MAKEINTRESOURCEW(ID_ACCEL));
883 while (GetMessageW(&msg, 0, 0, 0))
885 if (!IsDialogMessageW(Globals.hFindReplaceDlg, &msg) && !TranslateAcceleratorW(Globals.hMainWnd, hAccel, &msg))
887 TranslateMessage(&msg);
888 DispatchMessageW(&msg);
891 return msg.wParam;