]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * Copyright (c) 1994 by Xerox Corporation. All rights reserved. | |
3 | * | |
4 | * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED | |
5 | * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. | |
6 | * | |
7 | * Permission is hereby granted to use or copy this program | |
8 | * for any purpose, provided the above notices are retained on all copies. | |
9 | * Permission to modify the code and to distribute modified code is granted, | |
10 | * provided the above notices are retained, and a notice that the code was | |
11 | * modified is included with the above copyright notice. | |
12 | */ | |
13 | /* Boehm, February 6, 1995 12:29 pm PST */ | |
14 | ||
15 | /* | |
16 | * The MS Windows specific part of de. | |
17 | * This started as the generic Windows application template | |
18 | * made available by Rob Haack (rhaack@polaris.unm.edu), but | |
19 | * significant parts didn't survive to the final version. | |
20 | * | |
21 | * This was written by a nonexpert windows programmer. | |
22 | */ | |
23 | ||
24 | ||
25 | #include "windows.h" | |
26 | #include "gc.h" | |
27 | #include "cord.h" | |
28 | #include "de_cmds.h" | |
29 | #include "de_win.h" | |
30 | ||
31 | int LINES = 0; | |
32 | int COLS = 0; | |
33 | ||
34 | char szAppName[] = "DE"; | |
35 | char FullAppName[] = "Demonstration Editor"; | |
36 | ||
37 | HWND hwnd; | |
38 | ||
39 | void de_error(char *s) | |
40 | { | |
41 | MessageBox( hwnd, (LPSTR) s, | |
42 | (LPSTR) FullAppName, | |
43 | MB_ICONINFORMATION | MB_OK ); | |
44 | InvalidateRect(hwnd, NULL, TRUE); | |
45 | } | |
46 | ||
47 | int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, | |
48 | LPSTR command_line, int nCmdShow) | |
49 | { | |
50 | MSG msg; | |
51 | WNDCLASS wndclass; | |
52 | HANDLE hAccel; | |
53 | ||
54 | # ifdef THREAD_LOCAL_ALLOC | |
55 | GC_INIT(); /* Required if GC is built with THREAD_LOCAL_ALLOC */ | |
56 | /* Always safe, but this is used as a GC test. */ | |
57 | # endif | |
58 | ||
59 | if (!hPrevInstance) | |
60 | { | |
61 | wndclass.style = CS_HREDRAW | CS_VREDRAW; | |
62 | wndclass.lpfnWndProc = WndProc; | |
63 | wndclass.cbClsExtra = 0; | |
64 | wndclass.cbWndExtra = DLGWINDOWEXTRA; | |
65 | wndclass.hInstance = hInstance; | |
66 | wndclass.hIcon = LoadIcon (hInstance, szAppName); | |
67 | wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); | |
68 | wndclass.hbrBackground = GetStockObject(WHITE_BRUSH); | |
69 | wndclass.lpszMenuName = "DE"; | |
70 | wndclass.lpszClassName = szAppName; | |
71 | ||
72 | if (RegisterClass (&wndclass) == 0) { | |
73 | char buf[50]; | |
74 | ||
75 | sprintf(buf, "RegisterClass: error code: 0x%X", GetLastError()); | |
76 | de_error(buf); | |
77 | return(0); | |
78 | } | |
79 | } | |
80 | ||
81 | /* Empirically, the command line does not include the command name ... | |
82 | if (command_line != 0) { | |
83 | while (isspace(*command_line)) command_line++; | |
84 | while (*command_line != 0 && !isspace(*command_line)) command_line++; | |
85 | while (isspace(*command_line)) command_line++; | |
86 | } */ | |
87 | ||
88 | if (command_line == 0 || *command_line == 0) { | |
89 | de_error("File name argument required"); | |
90 | return( 0 ); | |
91 | } else { | |
92 | char *p = command_line; | |
93 | ||
94 | while (*p != 0 && !isspace(*p)) p++; | |
95 | arg_file_name = CORD_to_char_star( | |
96 | CORD_substr(command_line, 0, p - command_line)); | |
97 | } | |
98 | ||
99 | hwnd = CreateWindow (szAppName, | |
100 | FullAppName, | |
101 | WS_OVERLAPPEDWINDOW | WS_CAPTION, /* Window style */ | |
102 | CW_USEDEFAULT, 0, /* default pos. */ | |
103 | CW_USEDEFAULT, 0, /* default width, height */ | |
104 | NULL, /* No parent */ | |
105 | NULL, /* Window class menu */ | |
106 | hInstance, NULL); | |
107 | if (hwnd == NULL) { | |
108 | char buf[50]; | |
109 | ||
110 | sprintf(buf, "CreateWindow: error code: 0x%X", GetLastError()); | |
111 | de_error(buf); | |
112 | return(0); | |
113 | } | |
114 | ||
115 | ShowWindow (hwnd, nCmdShow); | |
116 | ||
117 | hAccel = LoadAccelerators( hInstance, szAppName ); | |
118 | ||
119 | while (GetMessage (&msg, NULL, 0, 0)) | |
120 | { | |
121 | if( !TranslateAccelerator( hwnd, hAccel, &msg ) ) | |
122 | { | |
123 | TranslateMessage (&msg); | |
124 | DispatchMessage (&msg); | |
125 | } | |
126 | } | |
127 | return msg.wParam; | |
128 | } | |
129 | ||
130 | /* Return the argument with all control characters replaced by blanks. */ | |
131 | char * plain_chars(char * text, size_t len) | |
132 | { | |
133 | char * result = GC_MALLOC_ATOMIC(len + 1); | |
134 | register size_t i; | |
135 | ||
136 | for (i = 0; i < len; i++) { | |
137 | if (iscntrl(text[i])) { | |
138 | result[i] = ' '; | |
139 | } else { | |
140 | result[i] = text[i]; | |
141 | } | |
142 | } | |
143 | result[len] = '\0'; | |
144 | return(result); | |
145 | } | |
146 | ||
147 | /* Return the argument with all non-control-characters replaced by */ | |
148 | /* blank, and all control characters c replaced by c + 32. */ | |
149 | char * control_chars(char * text, size_t len) | |
150 | { | |
151 | char * result = GC_MALLOC_ATOMIC(len + 1); | |
152 | register size_t i; | |
153 | ||
154 | for (i = 0; i < len; i++) { | |
155 | if (iscntrl(text[i])) { | |
156 | result[i] = text[i] + 0x40; | |
157 | } else { | |
158 | result[i] = ' '; | |
159 | } | |
160 | } | |
161 | result[len] = '\0'; | |
162 | return(result); | |
163 | } | |
164 | ||
165 | int char_width; | |
166 | int char_height; | |
167 | ||
168 | void get_line_rect(int line, int win_width, RECT * rectp) | |
169 | { | |
170 | rectp -> top = line * char_height; | |
171 | rectp -> bottom = rectp->top + char_height; | |
172 | rectp -> left = 0; | |
173 | rectp -> right = win_width; | |
174 | } | |
175 | ||
176 | int caret_visible = 0; /* Caret is currently visible. */ | |
177 | ||
178 | int screen_was_painted = 0;/* Screen has been painted at least once. */ | |
179 | ||
180 | void update_cursor(void); | |
181 | ||
182 | INT_PTR CALLBACK AboutBoxCallback( HWND hDlg, UINT message, | |
183 | WPARAM wParam, LPARAM lParam ) | |
184 | { | |
185 | switch( message ) | |
186 | { | |
187 | case WM_INITDIALOG: | |
188 | SetFocus( GetDlgItem( hDlg, IDOK ) ); | |
189 | break; | |
190 | ||
191 | case WM_COMMAND: | |
192 | switch( wParam ) | |
193 | { | |
194 | case IDOK: | |
195 | EndDialog( hDlg, TRUE ); | |
196 | break; | |
197 | } | |
198 | break; | |
199 | ||
200 | case WM_CLOSE: | |
201 | EndDialog( hDlg, TRUE ); | |
202 | return TRUE; | |
203 | ||
204 | } | |
205 | return FALSE; | |
206 | } | |
207 | ||
208 | LRESULT CALLBACK WndProc (HWND hwnd, UINT message, | |
209 | WPARAM wParam, LPARAM lParam) | |
210 | { | |
211 | static HANDLE hInstance; | |
212 | HDC dc; | |
213 | PAINTSTRUCT ps; | |
214 | RECT client_area; | |
215 | RECT this_line; | |
216 | RECT dummy; | |
217 | TEXTMETRIC tm; | |
218 | register int i; | |
219 | int id; | |
220 | ||
221 | switch (message) | |
222 | { | |
223 | case WM_CREATE: | |
224 | hInstance = ( (LPCREATESTRUCT) lParam)->hInstance; | |
225 | dc = GetDC(hwnd); | |
226 | SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT)); | |
227 | GetTextMetrics(dc, &tm); | |
228 | ReleaseDC(hwnd, dc); | |
229 | char_width = tm.tmAveCharWidth; | |
230 | char_height = tm.tmHeight + tm.tmExternalLeading; | |
231 | GetClientRect(hwnd, &client_area); | |
232 | COLS = (client_area.right - client_area.left)/char_width; | |
233 | LINES = (client_area.bottom - client_area.top)/char_height; | |
234 | generic_init(); | |
235 | return(0); | |
236 | ||
237 | case WM_CHAR: | |
238 | if (wParam == QUIT) { | |
239 | SendMessage( hwnd, WM_CLOSE, 0, 0L ); | |
240 | } else { | |
241 | do_command((int)wParam); | |
242 | } | |
243 | return(0); | |
244 | ||
245 | case WM_SETFOCUS: | |
246 | CreateCaret(hwnd, NULL, char_width, char_height); | |
247 | ShowCaret(hwnd); | |
248 | caret_visible = 1; | |
249 | update_cursor(); | |
250 | return(0); | |
251 | ||
252 | case WM_KILLFOCUS: | |
253 | HideCaret(hwnd); | |
254 | DestroyCaret(); | |
255 | caret_visible = 0; | |
256 | return(0); | |
257 | ||
258 | case WM_LBUTTONUP: | |
259 | { | |
260 | unsigned xpos = LOWORD(lParam); /* From left */ | |
261 | unsigned ypos = HIWORD(lParam); /* from top */ | |
262 | ||
263 | set_position( xpos/char_width, ypos/char_height ); | |
264 | return(0); | |
265 | } | |
266 | ||
267 | case WM_COMMAND: | |
268 | id = LOWORD(wParam); | |
269 | if (id & EDIT_CMD_FLAG) { | |
270 | if (id & REPEAT_FLAG) do_command(REPEAT); | |
271 | do_command(CHAR_CMD(id)); | |
272 | return( 0 ); | |
273 | } else { | |
274 | switch(id) { | |
275 | case IDM_FILEEXIT: | |
276 | SendMessage( hwnd, WM_CLOSE, 0, 0L ); | |
277 | return( 0 ); | |
278 | ||
279 | case IDM_HELPABOUT: | |
280 | if( DialogBox( hInstance, "ABOUTBOX", | |
281 | hwnd, AboutBoxCallback ) ) | |
282 | InvalidateRect( hwnd, NULL, TRUE ); | |
283 | return( 0 ); | |
284 | case IDM_HELPCONTENTS: | |
285 | de_error( | |
286 | "Cursor keys: ^B(left) ^F(right) ^P(up) ^N(down)\n" | |
287 | "Undo: ^U Write: ^W Quit:^D Repeat count: ^R[n]\n" | |
288 | "Top: ^T Locate (search, find): ^L text ^L\n"); | |
289 | return( 0 ); | |
290 | } | |
291 | } | |
292 | break; | |
293 | ||
294 | case WM_CLOSE: | |
295 | DestroyWindow( hwnd ); | |
296 | return 0; | |
297 | ||
298 | case WM_DESTROY: | |
299 | PostQuitMessage (0); | |
300 | GC_win32_free_heap(); | |
301 | return 0; | |
302 | ||
303 | case WM_PAINT: | |
304 | dc = BeginPaint(hwnd, &ps); | |
305 | GetClientRect(hwnd, &client_area); | |
306 | COLS = (client_area.right - client_area.left)/char_width; | |
307 | LINES = (client_area.bottom - client_area.top)/char_height; | |
308 | SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT)); | |
309 | for (i = 0; i < LINES; i++) { | |
310 | get_line_rect(i, client_area.right, &this_line); | |
311 | if (IntersectRect(&dummy, &this_line, &ps.rcPaint)) { | |
312 | CORD raw_line = retrieve_screen_line(i); | |
313 | size_t len = CORD_len(raw_line); | |
314 | char * text = CORD_to_char_star(raw_line); | |
315 | /* May contain embedded NULLs */ | |
316 | char * plain = plain_chars(text, len); | |
317 | char * blanks = CORD_to_char_star(CORD_chars(' ', | |
318 | COLS - len)); | |
319 | char * control = control_chars(text, len); | |
320 | # define RED RGB(255,0,0) | |
321 | ||
322 | SetBkMode(dc, OPAQUE); | |
323 | SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT)); | |
324 | ||
325 | TextOut(dc, this_line.left, this_line.top, | |
326 | plain, (int)len); | |
327 | TextOut(dc, this_line.left + (int)len * char_width, | |
328 | this_line.top, | |
329 | blanks, (int)(COLS - len)); | |
330 | SetBkMode(dc, TRANSPARENT); | |
331 | SetTextColor(dc, RED); | |
332 | TextOut(dc, this_line.left, this_line.top, | |
333 | control, (int)strlen(control)); | |
334 | } | |
335 | } | |
336 | EndPaint(hwnd, &ps); | |
337 | screen_was_painted = 1; | |
338 | return 0; | |
339 | } | |
340 | return DefWindowProc (hwnd, message, wParam, lParam); | |
341 | } | |
342 | ||
343 | int last_col; | |
344 | int last_line; | |
345 | ||
346 | void move_cursor(int c, int l) | |
347 | { | |
348 | last_col = c; | |
349 | last_line = l; | |
350 | ||
351 | if (caret_visible) update_cursor(); | |
352 | } | |
353 | ||
354 | void update_cursor(void) | |
355 | { | |
356 | SetCaretPos(last_col * char_width, last_line * char_height); | |
357 | ShowCaret(hwnd); | |
358 | } | |
359 | ||
360 | void invalidate_line(int i) | |
361 | { | |
362 | RECT line; | |
363 | ||
364 | if (!screen_was_painted) return; | |
365 | /* Invalidating a rectangle before painting seems result in a */ | |
366 | /* major performance problem. */ | |
367 | get_line_rect(i, COLS*char_width, &line); | |
368 | InvalidateRect(hwnd, &line, FALSE); | |
369 | } | |
370 |