/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /*--------------------------------------- POPPAD.C -- Popup Editor (c) Charles Petzold, 1992 ---------------------------------------*/ #include "nspr.h" #include "plevent.h" #include #include #include #include "poppad.h" #include #define EDITID 1 #define UNTITLED "(untitled)" long FAR PASCAL _export WndProc (HWND, UINT, UINT, LONG) ; BOOL FAR PASCAL _export AboutDlgProc (HWND, UINT, UINT, LONG) ; /* Declarations for NSPR customization ** */ typedef struct PadEvent { PLEvent plEvent; int unused; } PadEvent; static void PR_CALLBACK TimerThread( void *arg); static void PR_CALLBACK HandlePadEvent( PadEvent *padEvent ); static void PR_CALLBACK DestroyPadEvent( PadEvent *padevent ); static PRThread *tThread; static PLEventQueue *padQueue; static int quitSwitch = 0; static long ThreadSleepTime = 1000; static long timerCount = 0; static char *startMessage = "Poppad: NSPR GUI and event test program.\n" "You should see lines of 50 characters\n" "with a new character appearing at 1 second intervals.\n" "Every 10 seconds gets a '+'; every 5 seconds gets a '_';\n" "every 1 second gets a '.'.\n\n" "You should be able to type in the window.\n\n\n"; // Functions in POPFILE.C void PopFileInitialize (HWND) ; BOOL PopFileOpenDlg (HWND, LPSTR, LPSTR) ; BOOL PopFileSaveDlg (HWND, LPSTR, LPSTR) ; BOOL PopFileRead (HWND, LPSTR) ; BOOL PopFileWrite (HWND, LPSTR) ; // Functions in POPFIND.C HWND PopFindFindDlg (HWND) ; HWND PopFindReplaceDlg (HWND) ; BOOL PopFindFindText (HWND, int *, LPFINDREPLACE) ; BOOL PopFindReplaceText (HWND, int *, LPFINDREPLACE) ; BOOL PopFindNextText (HWND, int *) ; BOOL PopFindValidFind (void) ; // Functions in POPFONT.C void PopFontInitialize (HWND) ; BOOL PopFontChooseFont (HWND) ; void PopFontSetFont (HWND) ; void PopFontDeinitialize (void) ; // Functions in POPPRNT.C BOOL PopPrntPrintFile (HANDLE, HWND, HWND, LPSTR) ; // Global variables static char szAppName [] = "PopPad" ; static HWND hDlgModeless ; static HWND hwndEdit ; int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; HWND hwnd ; HANDLE hAccel ; WNDCLASS wndclass ; PR_STDIO_INIT(); PR_Init(0, 0, 0); if (!hPrevInstance) { wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (hInstance, szAppName) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = szAppName ; wndclass.lpszClassName = szAppName ; RegisterClass (&wndclass) ; } hwnd = CreateWindow (szAppName, NULL, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, lpszCmdLine) ; ShowWindow (hwnd, nCmdShow) ; UpdateWindow (hwnd); hAccel = LoadAccelerators (hInstance, szAppName) ; for(;;) { if ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE )) { if (GetMessage(&msg, NULL, 0, 0)) { if (hDlgModeless == NULL || !IsDialogMessage (hDlgModeless, &msg)) { if (!TranslateAccelerator (hwnd, hAccel, &msg)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } /* end if !TranslateAccelerator */ } } else { break; } /* end if GetMessage() */ } else /* !PeekMessage */ { PR_Sleep(50); }/* end if PeekMessage() */ } /* end for() */ PR_JoinThread( tThread ); PL_DestroyEventQueue( padQueue ); PR_Cleanup(); return msg.wParam ; } void DoCaption (HWND hwnd, char *szTitleName) { char szCaption [64 + _MAX_FNAME + _MAX_EXT] ; wsprintf (szCaption, "%s - %s", (LPSTR) szAppName, (LPSTR) (szTitleName [0] ? szTitleName : UNTITLED)) ; SetWindowText (hwnd, szCaption) ; } void OkMessage (HWND hwnd, char *szMessage, char *szTitleName) { char szBuffer [64 + _MAX_FNAME + _MAX_EXT] ; wsprintf (szBuffer, szMessage, (LPSTR) (szTitleName [0] ? szTitleName : UNTITLED)) ; MessageBox (hwnd, szBuffer, szAppName, MB_OK | MB_ICONEXCLAMATION) ; } short AskAboutSave (HWND hwnd, char *szTitleName) { char szBuffer [64 + _MAX_FNAME + _MAX_EXT] ; short nReturn ; wsprintf (szBuffer, "Save current changes in %s?", (LPSTR) (szTitleName [0] ? szTitleName : UNTITLED)) ; nReturn = MessageBox (hwnd, szBuffer, szAppName, MB_YESNOCANCEL | MB_ICONQUESTION) ; if (nReturn == IDYES) if (!SendMessage (hwnd, WM_COMMAND, IDM_SAVE, 0L)) nReturn = IDCANCEL ; return nReturn ; } long FAR PASCAL _export WndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam) { static BOOL bNeedSave = FALSE ; static char szFileName [_MAX_PATH] ; static char szTitleName [_MAX_FNAME + _MAX_EXT] ; static FARPROC lpfnAboutDlgProc ; static HANDLE hInst ; static int iOffset ; static UINT messageFindReplace ; LONG lSelect ; LPFINDREPLACE lpfr ; WORD wEnable ; switch (message) { case WM_CREATE: // Get About dialog instance address hInst = ((LPCREATESTRUCT) lParam)->hInstance ; lpfnAboutDlgProc = MakeProcInstance ((FARPROC) AboutDlgProc, hInst) ; // Create the edit control child window hwndEdit = CreateWindow ("edit", NULL, WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER | ES_LEFT | ES_MULTILINE | ES_NOHIDESEL | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0, 0, 0, 0, hwnd, EDITID, hInst, NULL) ; SendMessage (hwndEdit, EM_LIMITTEXT, 32000, 0L) ; // Initialize common dialog box stuff PopFileInitialize (hwnd) ; PopFontInitialize (hwndEdit) ; messageFindReplace = RegisterWindowMessage (FINDMSGSTRING) ; // Process command line lstrcpy (szFileName, (LPSTR) (((LPCREATESTRUCT) lParam)->lpCreateParams)) ; if (lstrlen (szFileName) > 0) { GetFileTitle (szFileName, szTitleName, sizeof (szTitleName)) ; if (!PopFileRead (hwndEdit, szFileName)) OkMessage (hwnd, "File %s cannot be read!", szTitleName) ; } DoCaption (hwnd, szTitleName) ; /* Initialize Event Processing for NSPR ** Retrieve the event queue just created ** Create the TimerThread */ PL_InitializeEventsLib("someName"); padQueue = PL_GetMainEventQueue(); tThread = PR_CreateThread(PR_USER_THREAD, TimerThread, NULL, PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0 ); return 0 ; case WM_SETFOCUS: SetFocus (hwndEdit) ; return 0 ; case WM_SIZE: MoveWindow (hwndEdit, 0, 0, LOWORD (lParam), HIWORD (lParam), TRUE) ; return 0 ; case WM_INITMENUPOPUP: switch (lParam) { case 1: // Edit menu // Enable Undo if edit control can do it EnableMenuItem (wParam, IDM_UNDO, SendMessage (hwndEdit, EM_CANUNDO, 0, 0L) ? MF_ENABLED : MF_GRAYED) ; // Enable Paste if text is in the clipboard EnableMenuItem (wParam, IDM_PASTE, IsClipboardFormatAvailable (CF_TEXT) ? MF_ENABLED : MF_GRAYED) ; // Enable Cut, Copy, and Del if text is selected lSelect = SendMessage (hwndEdit, EM_GETSEL, 0, 0L) ; wEnable = HIWORD (lSelect) != LOWORD (lSelect) ? MF_ENABLED : MF_GRAYED ; EnableMenuItem (wParam, IDM_CUT, wEnable) ; EnableMenuItem (wParam, IDM_COPY, wEnable) ; EnableMenuItem (wParam, IDM_DEL, wEnable) ; break ; case 2: // Search menu // Enable Find, Next, and Replace if modeless // dialogs are not already active wEnable = hDlgModeless == NULL ? MF_ENABLED : MF_GRAYED ; EnableMenuItem (wParam, IDM_FIND, wEnable) ; EnableMenuItem (wParam, IDM_NEXT, wEnable) ; EnableMenuItem (wParam, IDM_REPLACE, wEnable) ; break ; } return 0 ; case WM_COMMAND : // Messages from edit control if (LOWORD (lParam) && wParam == EDITID) { switch (HIWORD (lParam)) { case EN_UPDATE: bNeedSave = TRUE ; return 0 ; case EN_ERRSPACE: case EN_MAXTEXT: MessageBox (hwnd, "Edit control out of space.", szAppName, MB_OK | MB_ICONSTOP) ; return 0 ; } break ; } switch (wParam) { // Messages from File menu case IDM_NEW: if (bNeedSave && IDCANCEL == AskAboutSave (hwnd, szTitleName)) return 0 ; SetWindowText (hwndEdit, "\0") ; szFileName [0] = '\0' ; szTitleName [0] = '\0' ; DoCaption (hwnd, szTitleName) ; bNeedSave = FALSE ; return 0 ; case IDM_OPEN: if (bNeedSave && IDCANCEL == AskAboutSave (hwnd, szTitleName)) return 0 ; if (PopFileOpenDlg (hwnd, szFileName, szTitleName)) { if (!PopFileRead (hwndEdit, szFileName)) { OkMessage (hwnd, "Could not read file %s!", szTitleName) ; szFileName [0] = '\0' ; szTitleName [0] = '\0' ; } } DoCaption (hwnd, szTitleName) ; bNeedSave = FALSE ; return 0 ; case IDM_SAVE: if (szFileName [0]) { if (PopFileWrite (hwndEdit, szFileName)) { bNeedSave = FALSE ; return 1 ; } else OkMessage (hwnd, "Could not write file %s", szTitleName) ; return 0 ; } // fall through case IDM_SAVEAS: if (PopFileSaveDlg (hwnd, szFileName, szTitleName)) { DoCaption (hwnd, szTitleName) ; if (PopFileWrite (hwndEdit, szFileName)) { bNeedSave = FALSE ; return 1 ; } else OkMessage (hwnd, "Could not write file %s", szTitleName) ; } return 0 ; case IDM_PRINT: if (!PopPrntPrintFile (hInst, hwnd, hwndEdit, szTitleName)) OkMessage (hwnd, "Could not print file %s", szTitleName) ; return 0 ; case IDM_EXIT: SendMessage (hwnd, WM_CLOSE, 0, 0L) ; return 0 ; // Messages from Edit menu case IDM_UNDO: SendMessage (hwndEdit, WM_UNDO, 0, 0L) ; return 0 ; case IDM_CUT: SendMessage (hwndEdit, WM_CUT, 0, 0L) ; return 0 ; case IDM_COPY: SendMessage (hwndEdit, WM_COPY, 0, 0L) ; return 0 ; case IDM_PASTE: SendMessage (hwndEdit, WM_PASTE, 0, 0L) ; return 0 ; case IDM_DEL: SendMessage (hwndEdit, WM_CLEAR, 0, 0L) ; return 0 ; case IDM_SELALL: SendMessage (hwndEdit, EM_SETSEL, 0, MAKELONG (0, 32767)) ; return 0 ; // Messages from Search menu case IDM_FIND: iOffset = HIWORD ( SendMessage (hwndEdit, EM_GETSEL, 0, 0L)) ; hDlgModeless = PopFindFindDlg (hwnd) ; return 0 ; case IDM_NEXT: iOffset = HIWORD ( SendMessage (hwndEdit, EM_GETSEL, 0, 0L)) ; if (PopFindValidFind ()) PopFindNextText (hwndEdit, &iOffset) ; else hDlgModeless = PopFindFindDlg (hwnd) ; return 0 ; case IDM_REPLACE: iOffset = HIWORD ( SendMessage (hwndEdit, EM_GETSEL, 0, 0L)) ; hDlgModeless = PopFindReplaceDlg (hwnd) ; return 0 ; case IDM_FONT: if (PopFontChooseFont (hwnd)) PopFontSetFont (hwndEdit) ; return 0 ; // Messages from Help menu case IDM_HELP: OkMessage (hwnd, "Help not yet implemented!", NULL) ; return 0 ; case IDM_ABOUT: DialogBox (hInst, "AboutBox", hwnd, lpfnAboutDlgProc); return 0 ; } break ; case WM_CLOSE: if (!bNeedSave || IDCANCEL != AskAboutSave (hwnd, szTitleName)) DestroyWindow (hwnd) ; return 0 ; case WM_QUERYENDSESSION: if (!bNeedSave || IDCANCEL != AskAboutSave (hwnd, szTitleName)) return 1L ; return 0 ; case WM_DESTROY: PopFontDeinitialize () ; PostQuitMessage (0) ; quitSwitch = 1; return 0 ; default: // Process "Find-Replace" messages if (message == messageFindReplace) { lpfr = (LPFINDREPLACE) lParam ; if (lpfr->Flags & FR_DIALOGTERM) hDlgModeless = NULL ; if (lpfr->Flags & FR_FINDNEXT) if (!PopFindFindText (hwndEdit, &iOffset, lpfr)) OkMessage (hwnd, "Text not found!", NULL) ; if (lpfr->Flags & FR_REPLACE || lpfr->Flags & FR_REPLACEALL) if (!PopFindReplaceText (hwndEdit, &iOffset, lpfr)) OkMessage (hwnd, "Text not found!", NULL) ; if (lpfr->Flags & FR_REPLACEALL) while (PopFindReplaceText (hwndEdit, &iOffset, lpfr)); return 0 ; } break ; } return DefWindowProc (hwnd, message, wParam, lParam) ; } BOOL FAR PASCAL _export AboutDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam) { switch (message) { case WM_INITDIALOG: return TRUE ; case WM_COMMAND: switch (wParam) { case IDOK: EndDialog (hDlg, 0) ; return TRUE ; } break ; } return FALSE ; } /* ** TimerThread() -- The Main function of the timer pop thread ** */ static void PR_CALLBACK TimerThread( void *arg) { do { PadEvent *ev; /* ** Should we quit now? */ if ( quitSwitch ) break; /* ** Create and Post the event the event */ PL_ENTER_EVENT_QUEUE_MONITOR( padQueue ); ev = (PadEvent *) PR_NEW( PadEvent ); PL_InitEvent( &ev->plEvent, NULL, (PLHandleEventProc)HandlePadEvent, (PLDestroyEventProc)DestroyPadEvent ); PL_PostEvent( padQueue, &ev->plEvent ); PL_EXIT_EVENT_QUEUE_MONITOR( padQueue ); PR_Sleep( ThreadSleepTime ); } while(1); return; } /* ** HandlePadEvent() -- gets called because of PostEvent */ static void PR_CALLBACK HandlePadEvent( PadEvent *padEvent ) { if ( timerCount++ == 0 ) { char *cp; for ( cp = startMessage; *cp != 0 ; cp++ ) { SendMessage( hwndEdit, WM_CHAR, *cp, MAKELONG( *cp, 1 )); } } /* ** Send a WM_CHAR event the edit Window */ if ((timerCount % 10) == 0) { SendMessage( hwndEdit, WM_CHAR, '+', MAKELONG( '+', 1 )); } else if ((timerCount % 5) == 0) { SendMessage( hwndEdit, WM_CHAR, '_', MAKELONG( '_', 1 )); } else { SendMessage( hwndEdit, WM_CHAR, '.', MAKELONG( '.', 1 )); } if ( (timerCount % 50) == 0) { SendMessage( hwndEdit, WM_CHAR, '\n', MAKELONG( '\n', 1 )); } /* ** PL_RevokeEvents() is broken. Test to fix it. */ { static long revokeCounter = 0; if (revokeCounter++ > 10 ) { PR_Sleep( ThreadSleepTime * 10 ); SendMessage( hwndEdit, WM_CHAR, '*', MAKELONG( '\n', 1 )); PL_RevokeEvents( padQueue, NULL ); revokeCounter = 0; } } return; } /* ** DestroyPadEvent() -- Called after HandlePadEvent() */ static void PR_CALLBACK DestroyPadEvent( PadEvent *padevent ) { PR_Free( padevent ); return; }