main.c 25.3 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
2
 *  Notepad
Alexandre Julliard's avatar
Alexandre Julliard committed
3
 *
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
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * 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
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
23 24
 */

25 26
#define UNICODE

27
#include <windows.h>
28
#include <shlwapi.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
29
#include <stdio.h>
30

Alexandre Julliard's avatar
Alexandre Julliard committed
31
#include "main.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
32
#include "dialog.h"
33
#include "notepad_res.h"
34

Alexandre Julliard's avatar
Alexandre Julliard committed
35
NOTEPAD_GLOBALS Globals;
36
static ATOM aFINDMSGSTRING;
37
static RECT main_rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
38

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
static const WCHAR notepad_reg_key[] = {'S','o','f','t','w','a','r','e','\\',
                                        'M','i','c','r','o','s','o','f','t','\\','N','o','t','e','p','a','d','\0'};
static const WCHAR value_fWrap[]            = {'f','W','r','a','p','\0'};
static const WCHAR value_iPointSize[]       = {'i','P','o','i','n','t','S','i','z','e','\0'};
static const WCHAR value_iWindowPosDX[]     = {'i','W','i','n','d','o','w','P','o','s','D','X','\0'};
static const WCHAR value_iWindowPosDY[]     = {'i','W','i','n','d','o','w','P','o','s','D','Y','\0'};
static const WCHAR value_iWindowPosX[]      = {'i','W','i','n','d','o','w','P','o','s','X','\0'};
static const WCHAR value_iWindowPosY[]      = {'i','W','i','n','d','o','w','P','o','s','Y','\0'};
static const WCHAR value_lfCharSet[]        = {'l','f','C','h','a','r','S','e','t','\0'};
static const WCHAR value_lfClipPrecision[]  = {'l','f','C','l','i','p','P','r','e','c','i','s','i','o','n','\0'};
static const WCHAR value_lfEscapement[]     = {'l','f','E','s','c','a','p','e','m','e','n','t','\0'};
static const WCHAR value_lfItalic[]         = {'l','f','I','t','a','l','i','c','\0'};
static const WCHAR value_lfOrientation[]    = {'l','f','O','r','i','e','n','t','a','t','i','o','n','\0'};
static const WCHAR value_lfOutPrecision[]   = {'l','f','O','u','t','P','r','e','c','i','s','i','o','n','\0'};
static const WCHAR value_lfPitchAndFamily[] = {'l','f','P','i','t','c','h','A','n','d','F','a','m','i','l','y','\0'};
static const WCHAR value_lfQuality[]        = {'l','f','Q','u','a','l','i','t','y','\0'};
static const WCHAR value_lfStrikeOut[]      = {'l','f','S','t','r','i','k','e','O','u','t','\0'};
static const WCHAR value_lfUnderline[]      = {'l','f','U','n','d','e','r','l','i','n','e','\0'};
static const WCHAR value_lfWeight[]         = {'l','f','W','e','i','g','h','t','\0'};
static const WCHAR value_lfFaceName[]       = {'l','f','F','a','c','e','N','a','m','e','\0'};
59 60 61 62 63 64
static const WCHAR value_iMarginTop[]       = {'i','M','a','r','g','i','n','T','o','p','\0'};
static const WCHAR value_iMarginBottom[]    = {'i','M','a','r','g','i','n','B','o','t','t','o','m','\0'};
static const WCHAR value_iMarginLeft[]      = {'i','M','a','r','g','i','n','L','e','f','t','\0'};
static const WCHAR value_iMarginRight[]     = {'i','M','a','r','g','i','n','R','i','g','h','t','\0'};
static const WCHAR value_szHeader[]         = {'s','z','H','e','a','d','e','r','\0'};
static const WCHAR value_szFooter[]         = {'s','z','T','r','a','i','l','e','r','\0'};
65

66 67 68
/***********************************************************************
 *
 *           SetFileName
69
 *
70
 *  Sets Global File Name.
71
 */
72
VOID SetFileName(LPCWSTR szFileName)
73
{
74
    lstrcpy(Globals.szFileName, szFileName);
Dmitry Timoshkov's avatar
Dmitry Timoshkov committed
75
    Globals.szFileTitle[0] = 0;
76
    GetFileTitle(szFileName, Globals.szFileTitle, sizeof(Globals.szFileTitle));
77 78
}

79 80 81 82 83
/******************************************************************************
 *      get_dpi
 *
 * Get the dpi from registry HKCC\Software\Fonts\LogPixels.
 */
84
DWORD get_dpi(void)
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
{
    static const WCHAR dpi_key_name[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
    static const WCHAR dpi_value_name[] = {'L','o','g','P','i','x','e','l','s','\0'};
    DWORD dpi = 96;
    HKEY hkey;

    if (RegOpenKey(HKEY_CURRENT_CONFIG, dpi_key_name, &hkey) == ERROR_SUCCESS)
    {
        DWORD type, size, new_dpi;

        size = sizeof(new_dpi);
        if(RegQueryValueEx(hkey, dpi_value_name, NULL, &type, (void *)&new_dpi, &size) == ERROR_SUCCESS)
        {
            if(type == REG_DWORD && new_dpi != 0)
                dpi = new_dpi;
        }
        RegCloseKey(hkey);
    }
    return dpi;
}

106 107
/***********************************************************************
 *
108
 *           NOTEPAD_SaveSettingToRegistry
109
 *
110
 *  Save setting to registry HKCU\Software\Microsoft\Notepad.
111
 */
112
static VOID NOTEPAD_SaveSettingToRegistry(void)
113
{
114 115 116 117 118 119 120 121
    HKEY hkey;
    DWORD disp;

    if(RegCreateKeyEx(HKEY_CURRENT_USER, notepad_reg_key, 0, NULL,
                REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &disp) == ERROR_SUCCESS)
    {
        DWORD data;

122 123 124
        GetWindowRect(Globals.hMainWnd, &main_rect);

#define SET_NOTEPAD_REG(hkey, value_name, value_data) do { DWORD data = (DWORD)(value_data); RegSetValueEx(hkey, value_name, 0, REG_DWORD, (LPBYTE)&data, sizeof(DWORD)); }while(0)
125
        SET_NOTEPAD_REG(hkey, value_fWrap,            Globals.bWrapLongLines);
126 127 128 129
        SET_NOTEPAD_REG(hkey, value_iWindowPosX,      main_rect.left);
        SET_NOTEPAD_REG(hkey, value_iWindowPosY,      main_rect.top);
        SET_NOTEPAD_REG(hkey, value_iWindowPosDX,     main_rect.right - main_rect.left);
        SET_NOTEPAD_REG(hkey, value_iWindowPosDY,     main_rect.bottom - main_rect.top);
130 131 132 133 134 135 136 137 138 139 140
        SET_NOTEPAD_REG(hkey, value_lfCharSet,        Globals.lfFont.lfCharSet);
        SET_NOTEPAD_REG(hkey, value_lfClipPrecision,  Globals.lfFont.lfClipPrecision);
        SET_NOTEPAD_REG(hkey, value_lfEscapement,     Globals.lfFont.lfEscapement);
        SET_NOTEPAD_REG(hkey, value_lfItalic,         Globals.lfFont.lfItalic);
        SET_NOTEPAD_REG(hkey, value_lfOrientation,    Globals.lfFont.lfOrientation);
        SET_NOTEPAD_REG(hkey, value_lfOutPrecision,   Globals.lfFont.lfOutPrecision);
        SET_NOTEPAD_REG(hkey, value_lfPitchAndFamily, Globals.lfFont.lfPitchAndFamily);
        SET_NOTEPAD_REG(hkey, value_lfQuality,        Globals.lfFont.lfQuality);
        SET_NOTEPAD_REG(hkey, value_lfStrikeOut,      Globals.lfFont.lfStrikeOut);
        SET_NOTEPAD_REG(hkey, value_lfUnderline,      Globals.lfFont.lfUnderline);
        SET_NOTEPAD_REG(hkey, value_lfWeight,         Globals.lfFont.lfWeight);
141 142 143 144
        SET_NOTEPAD_REG(hkey, value_iMarginTop,       Globals.iMarginTop);
        SET_NOTEPAD_REG(hkey, value_iMarginBottom,    Globals.iMarginBottom);
        SET_NOTEPAD_REG(hkey, value_iMarginLeft,      Globals.iMarginLeft);
        SET_NOTEPAD_REG(hkey, value_iMarginRight,     Globals.iMarginRight);
145 146
#undef SET_NOTEPAD_REG

147 148
        /* Store the current value as 10 * twips */
        data = MulDiv(abs(Globals.lfFont.lfHeight), 720 , get_dpi());
149 150 151 152 153
        RegSetValueEx(hkey, value_iPointSize, 0, REG_DWORD, (LPBYTE)&data, sizeof(DWORD));

        RegSetValueEx(hkey, value_lfFaceName, 0, REG_SZ, (LPBYTE)&Globals.lfFont.lfFaceName,
                      lstrlen(Globals.lfFont.lfFaceName) * sizeof(Globals.lfFont.lfFaceName[0]));

154 155 156 157 158 159
        RegSetValueEx(hkey, value_szHeader, 0, REG_SZ, (LPBYTE)&Globals.szHeader,
                      lstrlen(Globals.szHeader) * sizeof(Globals.szHeader[0]));

        RegSetValueEx(hkey, value_szFooter, 0, REG_SZ, (LPBYTE)&Globals.szFooter,
                      lstrlen(Globals.szFooter) * sizeof(Globals.szFooter[0]));

160 161 162 163 164 165 166 167 168 169 170 171 172 173
        RegCloseKey(hkey);
    }
}

/***********************************************************************
 *
 *           NOTEPAD_LoadSettingFromRegistry
 *
 *  Load setting from registry HKCU\Software\Microsoft\Notepad.
 */
static VOID NOTEPAD_LoadSettingFromRegistry(void)
{
    static const WCHAR systemW[] = { 'S','y','s','t','e','m','\0' };
    HKEY hkey;
174
    INT base_length, dx, dy;
175 176 177 178

    base_length = (GetSystemMetrics(SM_CXSCREEN) > GetSystemMetrics(SM_CYSCREEN))?
        GetSystemMetrics(SM_CYSCREEN) : GetSystemMetrics(SM_CXSCREEN);

179 180 181
    dx = base_length * .95;
    dy = dx * 3 / 4;
    SetRect( &main_rect, 0, 0, dx, dy );
182 183

    Globals.bWrapLongLines  = TRUE;
184 185 186 187
    Globals.iMarginTop = 2500;
    Globals.iMarginBottom = 2500;
    Globals.iMarginLeft = 2000;
    Globals.iMarginRight = 2000;
188
    
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
    Globals.lfFont.lfHeight         = -12;
    Globals.lfFont.lfWidth          = 0;
    Globals.lfFont.lfEscapement     = 0;
    Globals.lfFont.lfOrientation    = 0;
    Globals.lfFont.lfWeight         = FW_REGULAR;
    Globals.lfFont.lfItalic         = FALSE;
    Globals.lfFont.lfUnderline      = FALSE;
    Globals.lfFont.lfStrikeOut      = FALSE;
    Globals.lfFont.lfCharSet        = DEFAULT_CHARSET;
    Globals.lfFont.lfOutPrecision   = OUT_DEFAULT_PRECIS;
    Globals.lfFont.lfClipPrecision  = CLIP_DEFAULT_PRECIS;
    Globals.lfFont.lfQuality        = DEFAULT_QUALITY;
    Globals.lfFont.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
    lstrcpy(Globals.lfFont.lfFaceName, systemW);

204 205 206 207 208
    LoadString(Globals.hInstance, STRING_PAGESETUP_HEADERVALUE, Globals.szHeader,
               sizeof(Globals.szHeader) / sizeof(Globals.szHeader[0]));
    LoadString(Globals.hInstance, STRING_PAGESETUP_FOOTERVALUE, Globals.szFooter,
               sizeof(Globals.szFooter) / sizeof(Globals.szFooter[0]));

209 210
    if(RegOpenKey(HKEY_CURRENT_USER, notepad_reg_key, &hkey) == ERROR_SUCCESS)
    {
211
        WORD  data_helper[MAX_PATH];
212 213 214 215
        DWORD type, data, size;

#define QUERY_NOTEPAD_REG(hkey, value_name, ret) do { DWORD type, data; DWORD size = sizeof(DWORD); if(RegQueryValueEx(hkey, value_name, 0, &type, (LPBYTE)&data, &size) == ERROR_SUCCESS) if(type == REG_DWORD) ret = (typeof(ret))data; } while(0)
        QUERY_NOTEPAD_REG(hkey, value_fWrap,            Globals.bWrapLongLines);
216 217 218 219
        QUERY_NOTEPAD_REG(hkey, value_iWindowPosX,      main_rect.left);
        QUERY_NOTEPAD_REG(hkey, value_iWindowPosY,      main_rect.top);
        QUERY_NOTEPAD_REG(hkey, value_iWindowPosDX,     dx);
        QUERY_NOTEPAD_REG(hkey, value_iWindowPosDY,     dy);
220 221 222 223 224 225 226 227 228 229 230
        QUERY_NOTEPAD_REG(hkey, value_lfCharSet,        Globals.lfFont.lfCharSet);
        QUERY_NOTEPAD_REG(hkey, value_lfClipPrecision,  Globals.lfFont.lfClipPrecision);
        QUERY_NOTEPAD_REG(hkey, value_lfEscapement,     Globals.lfFont.lfEscapement);
        QUERY_NOTEPAD_REG(hkey, value_lfItalic,         Globals.lfFont.lfItalic);
        QUERY_NOTEPAD_REG(hkey, value_lfOrientation,    Globals.lfFont.lfOrientation);
        QUERY_NOTEPAD_REG(hkey, value_lfOutPrecision,   Globals.lfFont.lfOutPrecision);
        QUERY_NOTEPAD_REG(hkey, value_lfPitchAndFamily, Globals.lfFont.lfPitchAndFamily);
        QUERY_NOTEPAD_REG(hkey, value_lfQuality,        Globals.lfFont.lfQuality);
        QUERY_NOTEPAD_REG(hkey, value_lfStrikeOut,      Globals.lfFont.lfStrikeOut);
        QUERY_NOTEPAD_REG(hkey, value_lfUnderline,      Globals.lfFont.lfUnderline);
        QUERY_NOTEPAD_REG(hkey, value_lfWeight,         Globals.lfFont.lfWeight);
231 232 233 234
        QUERY_NOTEPAD_REG(hkey, value_iMarginTop,       Globals.iMarginTop);
        QUERY_NOTEPAD_REG(hkey, value_iMarginBottom,    Globals.iMarginBottom);
        QUERY_NOTEPAD_REG(hkey, value_iMarginLeft,      Globals.iMarginLeft);
        QUERY_NOTEPAD_REG(hkey, value_iMarginRight,     Globals.iMarginRight);
235 236
#undef QUERY_NOTEPAD_REG

237 238 239
        main_rect.right = main_rect.left + dx;
        main_rect.bottom = main_rect.top + dy;

240 241 242
        size = sizeof(DWORD);
        if(RegQueryValueEx(hkey, value_iPointSize, 0, &type, (LPBYTE)&data, &size) == ERROR_SUCCESS)
            if(type == REG_DWORD)
243 244
                /* The value is stored as 10 * twips */
                Globals.lfFont.lfHeight = -MulDiv(abs(data), get_dpi(), 720);
245 246

        size = sizeof(Globals.lfFont.lfFaceName);
247
        if(RegQueryValueEx(hkey, value_lfFaceName, 0, &type, (LPBYTE)&data_helper, &size) == ERROR_SUCCESS)
248
            if(type == REG_SZ)
249
                lstrcpy(Globals.lfFont.lfFaceName, data_helper);
250
        
251 252 253 254 255 256 257 258 259
        size = sizeof(Globals.szHeader);
        if(RegQueryValueEx(hkey, value_szHeader, 0, &type, (LPBYTE)&data_helper, &size) == ERROR_SUCCESS)
            if(type == REG_SZ)
                lstrcpy(Globals.szHeader, data_helper);

        size = sizeof(Globals.szFooter);
        if(RegQueryValueEx(hkey, value_szFooter, 0, &type, (LPBYTE)&data_helper, &size) == ERROR_SUCCESS)
            if(type == REG_SZ)
                lstrcpy(Globals.szFooter, data_helper);
260 261
        RegCloseKey(hkey);
    }
262 263
}

264 265 266 267 268
/***********************************************************************
 *
 *           NOTEPAD_MenuCommand
 *
 *  All handling of main menu events
269
 */
270
static int NOTEPAD_MenuCommand(WPARAM wParam)
271
{
272
    switch (wParam)
273
    {
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
    case CMD_NEW:               DIALOG_FileNew(); break;
    case CMD_OPEN:              DIALOG_FileOpen(); break;
    case CMD_SAVE:              DIALOG_FileSave(); break;
    case CMD_SAVE_AS:           DIALOG_FileSaveAs(); break;
    case CMD_PRINT:             DIALOG_FilePrint(); break;
    case CMD_PAGE_SETUP:        DIALOG_FilePageSetup(); break;
    case CMD_PRINTER_SETUP:     DIALOG_FilePrinterSetup();break;
    case CMD_EXIT:              DIALOG_FileExit(); break;

    case CMD_UNDO:             DIALOG_EditUndo(); break;
    case CMD_CUT:              DIALOG_EditCut(); break;
    case CMD_COPY:             DIALOG_EditCopy(); break;
    case CMD_PASTE:            DIALOG_EditPaste(); break;
    case CMD_DELETE:           DIALOG_EditDelete(); break;
    case CMD_SELECT_ALL:       DIALOG_EditSelectAll(); break;
    case CMD_TIME_DATE:        DIALOG_EditTimeDate();break;

    case CMD_SEARCH:           DIALOG_Search(); break;
    case CMD_SEARCH_NEXT:      DIALOG_SearchNext(); break;
293 294 295
                               
    case CMD_WRAP:             DIALOG_EditWrap(); break;
    case CMD_FONT:             DIALOG_SelectFont(); break;
296 297 298 299

    case CMD_HELP_CONTENTS:    DIALOG_HelpContents(); break;
    case CMD_HELP_SEARCH:      DIALOG_HelpSearch(); break;
    case CMD_HELP_ON_HELP:     DIALOG_HelpHelp(); break;
300
    case CMD_HELP_ABOUT_NOTEPAD: DIALOG_HelpAboutNotepad(); break;
301 302 303

    default:
	break;
304
    }
305
   return 0;
306 307
}

308 309
/***********************************************************************
 * Data Initialization
310
 */
311
static VOID NOTEPAD_InitData(VOID)
312
{
313 314 315
    LPWSTR p = Globals.szFilter;
    static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
    static const WCHAR all_files[] = { '*','.','*',0 };
316 317

    LoadString(Globals.hInstance, STRING_TEXT_FILES_TXT, p, MAX_STRING_LEN);
318 319 320
    p += lstrlen(p) + 1;
    lstrcpy(p, txt_files);
    p += lstrlen(p) + 1;
321
    LoadString(Globals.hInstance, STRING_ALL_FILES, p, MAX_STRING_LEN);
322 323 324
    p += lstrlen(p) + 1;
    lstrcpy(p, all_files);
    p += lstrlen(p) + 1;
325
    *p = '\0';
326 327
    Globals.hDevMode = NULL;
    Globals.hDevNames = NULL;
328 329 330

    CheckMenuItem(GetMenu(Globals.hMainWnd), CMD_WRAP,
            MF_BYCOMMAND | (Globals.bWrapLongLines ? MF_CHECKED : MF_UNCHECKED));
331 332
}

333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
/***********************************************************************
 * Enable/disable items on the menu based on control state
 */
static VOID NOTEPAD_InitMenuPopup(HMENU menu, int index)
{
    int enable;

    EnableMenuItem(menu, CMD_UNDO,
        SendMessage(Globals.hEdit, EM_CANUNDO, 0, 0) ? MF_ENABLED : MF_GRAYED);
    EnableMenuItem(menu, CMD_PASTE,
        IsClipboardFormatAvailable(CF_TEXT) ? MF_ENABLED : MF_GRAYED);
    enable = SendMessage(Globals.hEdit, EM_GETSEL, 0, 0);
    enable = (HIWORD(enable) == LOWORD(enable)) ? MF_GRAYED : MF_ENABLED;
    EnableMenuItem(menu, CMD_CUT, enable);
    EnableMenuItem(menu, CMD_COPY, enable);
    EnableMenuItem(menu, CMD_DELETE, enable);
    
    EnableMenuItem(menu, CMD_SELECT_ALL,
        GetWindowTextLength(Globals.hEdit) ? MF_ENABLED : MF_GRAYED);
}

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
static LPTSTR NOTEPAD_StrRStr(LPTSTR pszSource, LPTSTR pszLast, LPTSTR pszSrch)
{
    int len = lstrlen(pszSrch);
    pszLast--;
    while (pszLast >= pszSource)
    {
        if (StrCmpN(pszLast, pszSrch, len) == 0)
            return pszLast;
        pszLast--;
    }
    return NULL;
}

/***********************************************************************
 * The user activated the Find dialog
 */
void NOTEPAD_DoFind(FINDREPLACE *fr)
{
    LPTSTR content;
    LPTSTR found;
    int len = lstrlen(fr->lpstrFindWhat);
    int fileLen;
    DWORD pos;
    
    fileLen = GetWindowTextLength(Globals.hEdit) + 1;
    content = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(TCHAR));
    if (!content) return;
    GetWindowText(Globals.hEdit, content, fileLen);

    SendMessage(Globals.hEdit, EM_GETSEL, 0, (LPARAM)&pos);        
    switch (fr->Flags & (FR_DOWN|FR_MATCHCASE))
    {
        case 0:
            found = StrRStrI(content, content+pos-len, fr->lpstrFindWhat);
            break;
        case FR_DOWN:
            found = StrStrI(content+pos, fr->lpstrFindWhat);
            break;
        case FR_MATCHCASE:
            found = NOTEPAD_StrRStr(content, content+pos-len, fr->lpstrFindWhat);
            break;
        case FR_DOWN|FR_MATCHCASE:
            found = StrStr(content+pos, fr->lpstrFindWhat);
            break;
        default:    /* shouldn't happen */
            return;
    }
    HeapFree(GetProcessHeap(), 0, content);

    if (found == NULL)
    {
        DIALOG_StringMsgBox(Globals.hFindReplaceDlg, STRING_NOTFOUND, fr->lpstrFindWhat,
            MB_ICONINFORMATION|MB_OK);
        return;
    }

    SendMessage(Globals.hEdit, EM_SETSEL, found - content, found - content + len);
}

413 414 415
/***********************************************************************
 *
 *           NOTEPAD_WndProc
416
 */
417
static LRESULT WINAPI NOTEPAD_WndProc(HWND hWnd, UINT msg, WPARAM wParam,
418
                               LPARAM lParam)
419
{
420 421 422 423 424 425 426 427 428 429 430 431 432 433
    if (msg == aFINDMSGSTRING)      /* not a constant so can't be used in switch */
    {
        FINDREPLACE *fr = (FINDREPLACE *)lParam;
        
        if (fr->Flags & FR_DIALOGTERM)
            Globals.hFindReplaceDlg = NULL;
        if (fr->Flags & FR_FINDNEXT)
        {
            Globals.lastFind = *fr;
            NOTEPAD_DoFind(fr);
        }
        return 0;
    }
    
434
    switch (msg) {
435

436
    case WM_CREATE:
437
    {
438
        static const WCHAR editW[] = { 'e','d','i','t',0 };
439
        DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL |
440
                        ES_AUTOVSCROLL | ES_MULTILINE | ES_NOHIDESEL;
441 442
        RECT rc;
        GetClientRect(hWnd, &rc);
443 444 445

        if (!Globals.bWrapLongLines) dwStyle |= WS_HSCROLL | ES_AUTOHSCROLL;

446
        Globals.hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, editW, NULL,
447
                             dwStyle,
448 449
                             0, 0, rc.right, rc.bottom, hWnd,
                             NULL, Globals.hInstance, NULL);
450 451 452

        Globals.hFont = CreateFontIndirect(&Globals.lfFont);
        SendMessage(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, (LPARAM)FALSE);
453
        break;
454
    }
455

456
    case WM_COMMAND:
457
        NOTEPAD_MenuCommand(LOWORD(wParam));
458 459
        break;

460
    case WM_DESTROYCLIPBOARD:
461
        /*MessageBox(Globals.hMainWnd, "Empty clipboard", "Debug", MB_ICONEXCLAMATION);*/
462 463
        break;

464 465
    case WM_CLOSE:
        if (DoCloseFile()) {
466
            DestroyWindow(hWnd);
467
        }
468 469
        break;

470 471 472 473 474 475
    case WM_QUERYENDSESSION:
        if (DoCloseFile()) {
            return 1;
        }
        break;

476
    case WM_DESTROY:
477 478
        NOTEPAD_SaveSettingToRegistry();

479
        PostQuitMessage(0);
480 481
        break;

482
    case WM_SIZE:
483
        SetWindowPos(Globals.hEdit, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam),
484 485
                     SWP_NOOWNERZORDER | SWP_NOZORDER);
        break;
486

487 488 489 490
    case WM_SETFOCUS:
        SetFocus(Globals.hEdit);
        break;

491
    case WM_DROPFILES:
492
    {
493
        WCHAR szFileName[MAX_PATH];
494
        HANDLE hDrop = (HANDLE) wParam;
495

496
        DragQueryFile(hDrop, 0, szFileName, SIZEOF(szFileName));
497 498
        DragFinish(hDrop);
        DoOpenFile(szFileName);
499 500
        break;
    }
501 502 503 504
    
    case WM_INITMENUPOPUP:
        NOTEPAD_InitMenuPopup((HMENU)wParam, lParam);
        break;
505

506 507
    default:
        return DefWindowProc(hWnd, msg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
508
    }
509
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
510 511
}

512 513
static int AlertFileDoesNotExist(LPCWSTR szFileName)
{
514
   int nResult;
515 516
   WCHAR szMessage[MAX_STRING_LEN];
   WCHAR szResource[MAX_STRING_LEN];
517

518 519
   LoadString(Globals.hInstance, STRING_DOESNOTEXIST, szResource, SIZEOF(szResource));
   wsprintf(szMessage, szResource, szFileName);
520

521
   LoadString(Globals.hInstance, STRING_ERROR, szResource, SIZEOF(szResource));
522

523
   nResult = MessageBox(Globals.hMainWnd, szMessage, szResource,
524
                        MB_ICONEXCLAMATION | MB_YESNO);
525

526 527 528
   return(nResult);
}

529
static void HandleCommandLine(LPWSTR cmdline)
530
{
531
    WCHAR delimiter;
532
    int opt_print=0;
533 534
    
    /* skip white space */
535
    while (*cmdline == ' ') cmdline++;
536 537

    /* skip executable name */
538
    delimiter = (*cmdline == '"' ? '"' : ' ');
539

540 541 542 543
    if (*cmdline == delimiter) cmdline++;

    while (*cmdline && *cmdline != delimiter) cmdline++;

544
    if (*cmdline == delimiter) cmdline++;
545

546
    while (*cmdline == ' ' || *cmdline == '-' || *cmdline == '/')
547
    {
548
        WCHAR option;
549 550 551 552 553

        if (*cmdline++ == ' ') continue;

        option = *cmdline;
        if (option) cmdline++;
554
        while (*cmdline == ' ') cmdline++;
555 556 557 558

        switch(option)
        {
            case 'p':
559 560 561
            case 'P':
                opt_print=1;
                break;
562 563 564
        }
    }

565
    if (*cmdline)
566 567
    {
        /* file name is passed in the command line */
568
        LPCWSTR file_name;
569
        BOOL file_exists;
570
        WCHAR buf[MAX_PATH];
571

572 573
        if (cmdline[0] == '"')
        {
574
            WCHAR* wc;
575
            cmdline++;
576 577 578 579 580
            wc=cmdline;
            /* Note: Double-quotes are not allowed in Windows filenames */
            while (*wc && *wc != '"') wc++;
            /* On Windows notepad ignores further arguments too */
            *wc = 0;
581
        }
582

583
        if (FileExists(cmdline))
584 585 586 587
        {
            file_exists = TRUE;
            file_name = cmdline;
        }
588
        else
589
        {
590 591
            static const WCHAR txtW[] = { '.','t','x','t',0 };

592
            /* try to find file with ".txt" extension */
593
            if (!lstrcmp(txtW, cmdline + lstrlen(cmdline) - lstrlen(txtW)))
594 595 596 597 598 599
            {
                file_exists = FALSE;
                file_name = cmdline;
            }
            else
            {
600 601
                lstrcpyn(buf, cmdline, MAX_PATH - lstrlen(txtW) - 1);
                lstrcat(buf, txtW);
602 603 604 605 606 607 608 609 610
                file_name = buf;
                file_exists = FileExists(buf);
            }
        }

        if (file_exists)
        {
            DoOpenFile(file_name);
            InvalidateRect(Globals.hMainWnd, NULL, FALSE);
611 612
            if (opt_print)
                DIALOG_FilePrint();
613 614 615 616 617 618 619 620 621 622 623 624 625 626
        }
        else
        {
            switch (AlertFileDoesNotExist(file_name)) {
            case IDYES:
                DoOpenFile(file_name);
                break;

            case IDNO:
                break;
            }
        }
     }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
627 628 629 630 631

/***********************************************************************
 *
 *           WinMain
 */
632
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
Alexandre Julliard's avatar
Alexandre Julliard committed
633
{
634
    MSG        msg;
635
    HACCEL      hAccel;
636
    WNDCLASSEX class;
637 638 639
    HMONITOR monitor;
    MONITORINFO info;
    INT x, y;
640
    static const WCHAR className[] = {'N','o','t','e','p','a','d',0};
641 642 643
    static const WCHAR winName[]   = {'N','o','t','e','p','a','d',0};

    aFINDMSGSTRING = RegisterWindowMessage(FINDMSGSTRING);
Alexandre Julliard's avatar
Alexandre Julliard committed
644

645
    ZeroMemory(&Globals, sizeof(Globals));
646
    Globals.hInstance       = hInstance;
647
    NOTEPAD_LoadSettingFromRegistry();
648

649 650 651 652
    ZeroMemory(&class, sizeof(class));
    class.cbSize        = sizeof(class);
    class.lpfnWndProc   = NOTEPAD_WndProc;
    class.hInstance     = Globals.hInstance;
653
    class.hIcon         = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_NOTEPAD));
654
    class.hCursor       = LoadCursor(0, IDC_ARROW);
655
    class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
656 657
    class.lpszMenuName  = MAKEINTRESOURCE(MAIN_MENU);
    class.lpszClassName = className;
Alexandre Julliard's avatar
Alexandre Julliard committed
658

659
    if (!RegisterClassEx(&class)) return FALSE;
660 661

    /* Setup windows */
Alexandre Julliard's avatar
Alexandre Julliard committed
662

663 664 665 666 667 668 669 670 671 672 673 674
    monitor = MonitorFromRect( &main_rect, MONITOR_DEFAULTTOPRIMARY );
    info.cbSize = sizeof(info);
    GetMonitorInfoW( monitor, &info );

    x = main_rect.left;
    y = main_rect.top;
    if (main_rect.left >= info.rcWork.right ||
        main_rect.top >= info.rcWork.bottom ||
        main_rect.right < info.rcWork.left ||
        main_rect.bottom < info.rcWork.top)
        x = y = CW_USEDEFAULT;

675
    Globals.hMainWnd =
676 677
        CreateWindow(className, winName, WS_OVERLAPPEDWINDOW, x, y,
                     main_rect.right - main_rect.left, main_rect.bottom - main_rect.top,
678
                     NULL, NULL, Globals.hInstance, NULL);
679 680 681 682 683
    if (!Globals.hMainWnd)
    {
        ShowLastError();
        ExitProcess(1);
    }
684

Dmitry Timoshkov's avatar
Dmitry Timoshkov committed
685 686 687
    NOTEPAD_InitData();
    DIALOG_FileNew();

688 689
    ShowWindow(Globals.hMainWnd, show);
    UpdateWindow(Globals.hMainWnd);
690 691
    DragAcceptFiles(Globals.hMainWnd, TRUE);

692
    HandleCommandLine(GetCommandLine());
693

694
    hAccel = LoadAccelerators( hInstance, MAKEINTRESOURCE(ID_ACCEL) );
695

696
    while (GetMessage(&msg, 0, 0, 0))
697
    {
698 699 700 701 702
	if (!TranslateAccelerator(Globals.hMainWnd, hAccel, &msg) && !IsDialogMessage(Globals.hFindReplaceDlg, &msg))
	{
	    TranslateMessage(&msg);
	    DispatchMessage(&msg);
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
703
    }
704
    return msg.wParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
705
}