1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 1997-2016. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 #define UNICODE 1
22 #define _UNICODE 1
23 #include <tchar.h>
24 #include <stdio.h>
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28 #include "sys.h"
29 #include <windowsx.h>
30 #include "resource.h"
31 #include "erl_version.h"
32 #include <commdlg.h>
33 #include <commctrl.h>
34 #include "erl_driver.h"
35 #include "win_con.h"
36
37 #define ALLOC(X) malloc(X)
38 #define REALLOC(X,Y) realloc(X,Y)
39 #define FREE(X) free(X)
40
41 #if SIZEOF_VOID_P == 8
42 #define WIN64 1
43 #ifndef GCL_HBRBACKGROUND
44 #define GCL_HBRBACKGROUND GCLP_HBRBACKGROUND
45 #endif
46 #define DIALOG_PROC_RET INT_PTR
47 #define CF_HOOK_RET INT_PTR
48 #define CC_HOOK_RET INT_PTR
49 #define OFN_HOOK_RET INT_PTR
50 #else
51 #define DIALOG_PROC_RET BOOL
52 #define CF_HOOK_RET UINT
53 #define CC_HOOK_RET UINT
54 #define OFN_HOOK_RET UINT
55 #endif
56
57
58 #ifndef STATE_SYSTEM_INVISIBLE
59 /* Mingw problem with oleacc.h and WIN32_LEAN_AND_MEAN */
60 #define STATE_SYSTEM_INVISIBLE 0x00008000
61 #endif
62
63 #define WM_CONTEXT (0x0401)
64 #define WM_CONBEEP (0x0402)
65 #define WM_SAVE_PREFS (0x0403)
66
67 #define USER_KEY TEXT("Software\\Ericsson\\Erlang\\") TEXT(ERLANG_VERSION)
68
69 #define FRAME_HEIGHT ((2*GetSystemMetrics(SM_CYEDGE))+(2*GetSystemMetrics(SM_CYFRAME))+GetSystemMetrics(SM_CYCAPTION))
70 #define FRAME_WIDTH (2*GetSystemMetrics(SM_CXFRAME)+(2*GetSystemMetrics(SM_CXFRAME))+GetSystemMetrics(SM_CXVSCROLL))
71
72 #define LINE_LENGTH canvasColumns
73 #define COL(_l) ((_l) % LINE_LENGTH)
74 #define LINE(_l) ((_l) / LINE_LENGTH)
75
76 #ifdef UNICODE
77 /*
78 * We use a character in the invalid unicode range
79 */
80 #define SET_CURSOR (0xD8FF)
81 #else
82 /*
83 * XXX There is no escape to send a character 0x80. Fortunately,
84 * the ttsl driver currently replaces 0x80 with an octal sequence.
85 */
86 #define SET_CURSOR (0x80)
87 #endif
88
89 #define SCAN_CODE_BREAK 0x46 /* scan code for Ctrl-Break */
90
91
92 typedef struct ScreenLine_s {
93 struct ScreenLine_s* next;
94 struct ScreenLine_s* prev;
95 int width;
96 #ifdef HARDDEBUG
97 int allocated;
98 #endif
99 int newline; /* Ends with hard newline: 1, wrapped at end: 0 */
100 TCHAR *text;
101 } ScreenLine_t;
102
103 extern Uint32 *lbuf; /* The current line buffer */
104 extern int llen; /* The current line length */
105 extern int lpos;
106
107 HANDLE console_input_event;
108 HANDLE console_thread = NULL;
109
110 #define DEF_CANVAS_COLUMNS 80
111 #define DEF_CANVAS_ROWS 26
112
113 #define BUFSIZE 4096
114 #define MAXBUFSIZE 32768
115 typedef struct {
116 TCHAR *data;
117 int size;
118 int wrPos;
119 int rdPos;
120 } buffer_t;
121
122 static buffer_t inbuf;
123 static buffer_t outbuf;
124
125 static CHOOSEFONT cf;
126
127 static TCHAR szFrameClass[] = TEXT("FrameClass");
128 static TCHAR szClientClass[] = TEXT("ClientClass");
129 static HWND hFrameWnd;
130 static HWND hClientWnd;
131 static HWND hTBWnd;
132 static HWND hComboWnd;
133 static HANDLE console_input;
134 static HANDLE console_output;
135 static int cxChar,cyChar, cxCharMax;
136 static int cxClient,cyClient;
137 static int cyToolBar;
138 static int iVscrollPos,iHscrollPos;
139 static int iVscrollMax,iHscrollMax;
140 static int nBufLines;
141 static int cur_x;
142 static int cur_y;
143 static int canvasColumns = DEF_CANVAS_COLUMNS;
144 static int canvasRows = DEF_CANVAS_ROWS;
145 static ScreenLine_t *buffer_top,*buffer_bottom;
146 static ScreenLine_t* cur_line;
147 static POINT editBeg,editEnd;
148 static BOOL fSelecting = FALSE;
149 static BOOL fTextSelected = FALSE;
150 static HKEY key;
151 static BOOL has_key = FALSE;
152 static LOGFONT logfont;
153 static DWORD fgColor;
154 static DWORD bkgColor;
155 static FILE *logfile = NULL;
156 static RECT winPos;
157 static BOOL toolbarVisible;
158 static BOOL destroyed = FALSE;
159
160 static int lines_to_save = 1000; /* Maximum number of screen lines to save. */
161
162 #define TITLE_BUF_SZ 256
163
164 struct title_buf {
165 TCHAR *name;
166 TCHAR buf[TITLE_BUF_SZ];
167 };
168
169 static TCHAR *erlang_window_title = TEXT("Erlang");
170
171 static unsigned __stdcall ConThreadInit(LPVOID param);
172 static LRESULT CALLBACK ClientWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
173 static LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
174 static DIALOG_PROC_RET CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
175 static ScreenLine_t *ConNewLine(void);
176 static void DeleteTopLine(void);
177 static void ensure_line_below(void);
178 static ScreenLine_t *GetLineFromY(int y);
179 static void LoadUserPreferences(void);
180 static void SaveUserPreferences(void);
181 static void set_scroll_info(HWND hwnd);
182 static void ConCarriageFeed(int);
183 static void ConScrollScreen(void);
184 static BOOL ConChooseFont(HWND hwnd);
185 static void ConFontInitialize(HWND hwnd);
186 static void ConSetFont(HWND hwnd);
187 static void ConChooseColor(HWND hwnd);
188 static void DrawSelection(HWND hwnd, POINT pt1, POINT pt2);
189 static void InvertSelectionArea(HWND hwnd);
190 static void OnEditCopy(HWND hwnd);
191 static void OnEditPaste(HWND hwnd);
192 static void OnEditSelAll(HWND hwnd);
193 static void GetFileName(HWND hwnd, TCHAR *pFile);
194 static void OpenLogFile(HWND hwnd);
195 static void CloseLogFile(HWND hwnd);
196 static void LogFileWrite(TCHAR *buf, int n);
197 static int write_inbuf(TCHAR *data, int n);
198 static void init_buffers(void);
199 static void AddToCmdHistory(void);
200 static int write_outbuf(TCHAR *data, int num_chars);
201 static void ConDrawText(HWND hwnd);
202 static BOOL (WINAPI *ctrl_handler)(DWORD);
203 static HWND InitToolBar(HWND hwndParent);
204 static void window_title(struct title_buf *);
205 static void free_window_title(struct title_buf *);
206 static void Client_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags);
207
208 #define CON_VPRINTF_BUF_INC_SIZE 1024
209
210 static erts_dsprintf_buf_t *
grow_con_vprintf_buf(erts_dsprintf_buf_t * dsbufp,size_t need)211 grow_con_vprintf_buf(erts_dsprintf_buf_t *dsbufp, size_t need)
212 {
213 char *buf;
214 size_t size;
215
216 ASSERT(dsbufp);
217
218 if (!dsbufp->str) {
219 size = (((need + CON_VPRINTF_BUF_INC_SIZE - 1)
220 / CON_VPRINTF_BUF_INC_SIZE)
221 * CON_VPRINTF_BUF_INC_SIZE);
222 buf = (char *) ALLOC(size * sizeof(char));
223 }
224 else {
225 size_t free_size = dsbufp->size - dsbufp->str_len;
226
227 if (need <= free_size)
228 return dsbufp;
229
230 size = need - free_size + CON_VPRINTF_BUF_INC_SIZE;
231 size = (((size + CON_VPRINTF_BUF_INC_SIZE - 1)
232 / CON_VPRINTF_BUF_INC_SIZE)
233 * CON_VPRINTF_BUF_INC_SIZE);
234 size += dsbufp->size;
235 buf = (char *) REALLOC((void *) dsbufp->str,
236 size * sizeof(char));
237 }
238 if (!buf)
239 return NULL;
240 if (buf != dsbufp->str)
241 dsbufp->str = buf;
242 dsbufp->size = size;
243 return dsbufp;
244 }
245
con_vprintf(char * format,va_list arg_list)246 static int con_vprintf(char *format, va_list arg_list)
247 {
248 int res,i;
249 erts_dsprintf_buf_t dsbuf = ERTS_DSPRINTF_BUF_INITER(grow_con_vprintf_buf);
250 res = erts_vdsprintf(&dsbuf, format, arg_list);
251 if (res >= 0) {
252 TCHAR *tmp = ALLOC(dsbuf.str_len*sizeof(TCHAR));
253 for (i=0;i<dsbuf.str_len;++i) {
254 tmp[i] = dsbuf.str[i];
255 }
256 write_outbuf(tmp, dsbuf.str_len);
257 FREE(tmp);
258 }
259 if (dsbuf.str)
260 FREE((void *) dsbuf.str);
261 return res;
262 }
263
264 void
ConInit(void)265 ConInit(void)
266 {
267 unsigned tid;
268
269 console_input = CreateSemaphore(NULL, 0, 1, NULL);
270 console_output = CreateSemaphore(NULL, 0, 1, NULL);
271 console_input_event = CreateManualEvent(FALSE);
272 console_thread = (HANDLE *) _beginthreadex(NULL, 0,
273 ConThreadInit,
274 0, 0, &tid);
275
276 /* Make all erts_*printf on stdout and stderr use con_vprintf */
277 erts_printf_stdout_func = con_vprintf;
278 erts_printf_stderr_func = con_vprintf;
279 }
280
281 /*
282 ConNormalExit() is called from erts_exit() when the emulator
283 is stopping. If the exit has not been initiated by this
284 console thread (WM_DESTROY or ID_BREAK), the function must
285 invoke the console thread to save the user preferences.
286 */
287 void
ConNormalExit(void)288 ConNormalExit(void)
289 {
290 if (!destroyed)
291 SendMessage(hFrameWnd, WM_SAVE_PREFS, 0L, 0L);
292 }
293
294 void
ConWaitForExit(void)295 ConWaitForExit(void)
296 {
297 ConPrintf("\n\nAbnormal termination\n");
298 WaitForSingleObject(console_thread, INFINITE);
299 }
300
ConSetCtrlHandler(BOOL (WINAPI * handler)(DWORD))301 void ConSetCtrlHandler(BOOL (WINAPI *handler)(DWORD))
302 {
303 ctrl_handler = handler;
304 }
305
ConPutChar(Uint32 c)306 int ConPutChar(Uint32 c)
307 {
308 TCHAR sbuf[1];
309 #ifdef HARDDEBUG
310 fprintf(stderr,"ConPutChar: %d\n",(int) c);
311 fflush(stderr);
312 #endif
313 sbuf[0] = c;
314 write_outbuf(sbuf, 1);
315 return 1;
316 }
317
GetXFromLine(HDC hdc,int hscroll,int xpos,ScreenLine_t * pLine)318 static int GetXFromLine(HDC hdc, int hscroll, int xpos,ScreenLine_t *pLine)
319 {
320 SIZE size;
321 int hscrollPix = hscroll * cxChar;
322
323 if (pLine == NULL) {
324 return 0;
325 }
326
327 if (pLine->width < xpos) {
328 return (canvasColumns-hscroll)*cxChar;
329 }
330 /* Not needed (?): SelectObject(hdc,CreateFontIndirect(&logfont)); */
331 if (GetTextExtentPoint32(hdc,pLine->text,xpos,&size)) {
332 #ifdef HARDDEBUG
333 fprintf(stderr,"size.cx:%d\n",(int)size.cx);
334 fflush(stderr);
335 #endif
336 if (hscrollPix >= size.cx) {
337 return 0;
338 }
339 return ((int) size.cx) - hscrollPix;
340 } else {
341 return (xpos-hscroll)*cxChar;
342 }
343 }
344
GetXFromCurrentY(HDC hdc,int hscroll,int xpos)345 static int GetXFromCurrentY(HDC hdc, int hscroll, int xpos) {
346 return GetXFromLine(hdc, hscroll, xpos, GetLineFromY(cur_y));
347 }
348
ConSetCursor(int from,int to)349 void ConSetCursor(int from, int to)
350 { TCHAR cmd[9];
351 int *p;
352 //DebugBreak();
353 cmd[0] = SET_CURSOR;
354 /*
355 * XXX Expect trouble on CPUs which don't allow misaligned read and writes.
356 */
357 p = (int *)&cmd[1];
358 *p++ = from;
359 *p = to;
360 write_outbuf(cmd, 1 + (2*sizeof(int)/sizeof(TCHAR)));
361 }
362
ConPrintf(char * format,...)363 void ConPrintf(char *format, ...)
364 {
365 va_list va;
366
367 va_start(va, format);
368 (void) con_vprintf(format, va);
369 va_end(va);
370 }
371
ConBeep(void)372 void ConBeep(void)
373 {
374 SendMessage(hClientWnd, WM_CONBEEP, 0L, 0L);
375 }
376
ConReadInput(Uint32 * data,int num_chars)377 int ConReadInput(Uint32 *data, int num_chars)
378 {
379 TCHAR *buf;
380 int nread;
381 WaitForSingleObject(console_input,INFINITE);
382 nread = num_chars = min(num_chars,inbuf.wrPos-inbuf.rdPos);
383 buf = &inbuf.data[inbuf.rdPos];
384 inbuf.rdPos += nread;
385 while (nread--)
386 *data++ = *buf++;
387 if (inbuf.rdPos >= inbuf.wrPos) {
388 inbuf.rdPos = 0;
389 inbuf.wrPos = 0;
390 ResetEvent(console_input_event);
391 }
392 ReleaseSemaphore(console_input,1,NULL);
393 return num_chars;
394 }
395
ConGetKey(void)396 int ConGetKey(void)
397 {
398 Uint32 c;
399 WaitForSingleObject(console_input,INFINITE);
400 ResetEvent(console_input_event);
401 inbuf.rdPos = inbuf.wrPos = 0;
402 ReleaseSemaphore(console_input,1,NULL);
403 WaitForSingleObject(console_input_event,INFINITE);
404 ConReadInput(&c, 1);
405 return (int) c;
406 }
407
ConGetColumns(void)408 int ConGetColumns(void)
409 {
410 return (int) canvasColumns; /* 32bit atomic on windows */
411 }
412
ConGetRows(void)413 int ConGetRows(void) {
414 return (int) canvasRows;
415 }
416
417
418 static HINSTANCE hInstance;
419 extern HMODULE beam_module;
420
421 static unsigned __stdcall
ConThreadInit(LPVOID param)422 ConThreadInit(LPVOID param)
423 {
424 MSG msg;
425 WNDCLASSEX wndclass;
426 int iCmdShow;
427 STARTUPINFO StartupInfo;
428 HACCEL hAccel;
429 int x, y, w, h;
430 struct title_buf title;
431
432 /*DebugBreak();*/
433 hInstance = GetModuleHandle(NULL);
434 StartupInfo.dwFlags = 0;
435 GetStartupInfo(&StartupInfo);
436 iCmdShow = StartupInfo.dwFlags & STARTF_USESHOWWINDOW ?
437 StartupInfo.wShowWindow : SW_SHOWDEFAULT;
438
439 LoadUserPreferences();
440
441 /* frame window class */
442 wndclass.cbSize = sizeof (wndclass);
443 wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNCLIENT;
444 wndclass.lpfnWndProc = FrameWndProc;
445 wndclass.cbClsExtra = 0;
446 wndclass.cbWndExtra = 0;
447 wndclass.hInstance = hInstance;
448 wndclass.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(1));
449 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
450 wndclass.hbrBackground = NULL;
451 wndclass.lpszMenuName = NULL;
452 wndclass.lpszClassName = szFrameClass;
453 wndclass.hIconSm = LoadIcon (hInstance, MAKEINTRESOURCE(1));
454 RegisterClassExW (&wndclass);
455
456 /* client window class */
457 wndclass.cbSize = sizeof (wndclass);
458 wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
459 wndclass.lpfnWndProc = ClientWndProc;
460 wndclass.cbClsExtra = 0;
461 wndclass.cbWndExtra = 0;
462 wndclass.hInstance = hInstance;
463 wndclass.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(1));
464 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
465 wndclass.hbrBackground = CreateSolidBrush(bkgColor);
466 wndclass.lpszMenuName = NULL;
467 wndclass.lpszClassName = szClientClass;
468 wndclass.hIconSm = LoadIcon (hInstance, MAKEINTRESOURCE(1));
469 RegisterClassExW (&wndclass);
470
471 InitCommonControls();
472 init_buffers();
473
474 nBufLines = 0;
475 buffer_top = cur_line = ConNewLine();
476 cur_line->next = buffer_bottom = ConNewLine();
477 buffer_bottom->prev = cur_line;
478
479 /* Create Frame Window */
480 window_title(&title);
481 hFrameWnd = CreateWindowEx(0, szFrameClass, title.name,
482 WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,
483 CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
484 NULL,LoadMenu(beam_module,MAKEINTRESOURCE(1)),
485 hInstance,NULL);
486 free_window_title(&title);
487
488 /* XXX OTP-5522:
489 The window position is not saved correctly and if the window
490 is closed when minimized, it's not possible to start werl again
491 with the window open. Temporary fix so far is to ignore saved values
492 and always start with initial settings. */
493 /* Original: if (winPos.left == -1) { */
494 /* Temporary: if (1) { */
495 if (1) {
496
497 /* initial window position */
498 x = 0;
499 y = 0;
500 w = cxChar*LINE_LENGTH+FRAME_WIDTH+GetSystemMetrics(SM_CXVSCROLL);
501 h = cyChar*30+FRAME_HEIGHT;
502 } else {
503 /* saved window position */
504 x = winPos.left;
505 y = winPos.top;
506 w = winPos.right - x;
507 h = winPos.bottom - y;
508 }
509 SetWindowPos(hFrameWnd, NULL, x, y, w, h, SWP_NOZORDER);
510
511 ShowWindow(hFrameWnd, iCmdShow);
512 UpdateWindow(hFrameWnd);
513
514 hAccel = LoadAccelerators(beam_module,MAKEINTRESOURCE(1));
515
516 ReleaseSemaphore(console_input, 1, NULL);
517 ReleaseSemaphore(console_output, 1, NULL);
518
519
520 /* Main message loop */
521 while (GetMessage (&msg, NULL, 0, 0))
522 {
523 if (!TranslateAccelerator(hFrameWnd,hAccel,&msg))
524 {
525 TranslateMessage (&msg);
526 DispatchMessage (&msg);
527 }
528 }
529 /*
530 PostQuitMessage() results in WM_QUIT which makes GetMessage()
531 return 0 (which stops the main loop). Before we return from
532 the console thread, the ctrl_handler is called to do erts_exit.
533 */
534 (*ctrl_handler)(CTRL_CLOSE_EVENT);
535 return msg.wParam;
536 }
537
538 static LRESULT CALLBACK
FrameWndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)539 FrameWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
540 {
541 RECT r;
542 int cy,i,bufsize;
543 TCHAR c;
544 unsigned long l;
545 TCHAR buf[128];
546 struct title_buf title;
547
548 switch (iMsg) {
549 case WM_CREATE:
550 /* client window creation */
551 window_title(&title);
552 hClientWnd = CreateWindowEx(WS_EX_CLIENTEDGE, szClientClass, title.name,
553 WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL,
554 CW_USEDEFAULT, CW_USEDEFAULT,
555 CW_USEDEFAULT, CW_USEDEFAULT,
556 hwnd, (HMENU)0, hInstance, NULL);
557 free_window_title(&title);
558 hTBWnd = InitToolBar(hwnd);
559 UpdateWindow (hClientWnd);
560 return 0;
561 case WM_SIZE :
562 if (IsWindowVisible(hTBWnd)) {
563 SendMessage(hTBWnd,TB_AUTOSIZE,0,0L);
564 GetWindowRect(hTBWnd,&r);
565 cy = r.bottom-r.top;
566 } else cy = 0;
567 MoveWindow(hClientWnd,0,cy,LOWORD(lParam),HIWORD(lParam)-cy,TRUE);
568 return 0;
569 case WM_ERASEBKGND:
570 return 1;
571 case WM_SETFOCUS :
572 CreateCaret(hClientWnd, NULL, cxChar, cyChar);
573 SetCaretPos(GetXFromCurrentY(GetDC(hClientWnd),iHscrollPos,cur_x), (cur_y-iVscrollPos)*cyChar);
574 ShowCaret(hClientWnd);
575 return 0;
576 case WM_KILLFOCUS:
577 HideCaret(hClientWnd);
578 DestroyCaret();
579 return 0;
580 case WM_INITMENUPOPUP :
581 if (lParam == 0) /* File popup menu */
582 {
583 EnableMenuItem((HMENU)wParam, IDMENU_STARTLOG,
584 logfile ? MF_GRAYED : MF_ENABLED);
585 EnableMenuItem((HMENU)wParam, IDMENU_STOPLOG,
586 logfile ? MF_ENABLED : MF_GRAYED);
587 return 0;
588 }
589 else if (lParam == 1) /* Edit popup menu */
590 {
591 EnableMenuItem((HMENU)wParam, IDMENU_COPY,
592 fTextSelected ? MF_ENABLED : MF_GRAYED);
593 EnableMenuItem((HMENU)wParam, IDMENU_PASTE,
594 IsClipboardFormatAvailable(CF_TEXT) ? MF_ENABLED : MF_GRAYED);
595 return 0;
596 }
597 else if (lParam == 3) /* View popup menu */
598 {
599 CheckMenuItem((HMENU)wParam,IDMENU_TOOLBAR,
600 IsWindowVisible(hTBWnd) ? MF_CHECKED : MF_UNCHECKED);
601 return 0;
602 }
603 break;
604 case WM_NOTIFY:
605 switch (((LPNMHDR) lParam)->code) {
606 case TTN_NEEDTEXT:
607 {
608 LPTOOLTIPTEXT lpttt;
609 lpttt = (LPTOOLTIPTEXT) lParam;
610 lpttt->hinst = hInstance;
611 /* check for combobox handle */
612 if (lpttt->uFlags&TTF_IDISHWND) {
613 if ((lpttt->hdr.idFrom == (UINT) hComboWnd)) {
614 lstrcpy(lpttt->lpszText,TEXT("Command History"));
615 break;
616 }
617 }
618 /* check for toolbar buttons */
619 switch (lpttt->hdr.idFrom) {
620 case IDMENU_COPY:
621 lstrcpy(lpttt->lpszText,TEXT("Copy (Ctrl+C)"));
622 break;
623 case IDMENU_PASTE:
624 lstrcpy(lpttt->lpszText,TEXT("Paste (Ctrl+V)"));
625 break;
626 case IDMENU_FONT:
627 lstrcpy(lpttt->lpszText,TEXT("Fonts"));
628 break;
629 case IDMENU_ABOUT:
630 lstrcpy(lpttt->lpszText,TEXT("Help"));
631 break;
632 }
633 }
634 }
635 break;
636 case WM_COMMAND:
637 switch(LOWORD(wParam))
638 {
639 case IDMENU_STARTLOG:
640 OpenLogFile(hwnd);
641 return 0;
642 case IDMENU_STOPLOG:
643 CloseLogFile(hwnd);
644 return 0;
645 case IDMENU_EXIT:
646 SendMessage(hwnd, WM_CLOSE, 0, 0L);
647 return 0;
648 case IDMENU_COPY:
649 if (fTextSelected)
650 OnEditCopy(hClientWnd);
651 return 0;
652 case IDMENU_PASTE:
653 OnEditPaste(hClientWnd);
654 return 0;
655 case IDMENU_SELALL:
656 OnEditSelAll(hClientWnd);
657 return 0;
658 case IDMENU_FONT:
659 if (ConChooseFont(hClientWnd)) {
660 ConSetFont(hClientWnd);
661 }
662 SaveUserPreferences();
663 return 0;
664 case IDMENU_SELECTBKG:
665 ConChooseColor(hClientWnd);
666 SaveUserPreferences();
667 return 0;
668 case IDMENU_TOOLBAR:
669 if (toolbarVisible) {
670 ShowWindow(hTBWnd,SW_HIDE);
671 toolbarVisible = FALSE;
672 } else {
673 ShowWindow(hTBWnd,SW_SHOW);
674 toolbarVisible = TRUE;
675 }
676 GetClientRect(hwnd,&r);
677 PostMessage(hwnd,WM_SIZE,0,MAKELPARAM(r.right,r.bottom));
678 return 0;
679 case IDMENU_ABOUT:
680 DialogBox(beam_module,TEXT("AboutBox"),hwnd,AboutDlgProc);
681 return 0;
682 case ID_COMBOBOX:
683 switch (HIWORD(wParam)) {
684 case CBN_SELENDOK:
685 i = SendMessage(hComboWnd,CB_GETCURSEL,0,0);
686 if (i != CB_ERR) {
687 buf[0] = 0x01; /* CTRL+A */
688 buf[1] = 0x0B; /* CTRL+K */
689 bufsize = SendMessage(hComboWnd,CB_GETLBTEXT,i,(LPARAM)&buf[2]);
690 if (bufsize != CB_ERR)
691 write_inbuf(buf,bufsize+2);
692 SetFocus(hwnd);
693 }
694 break;
695 case CBN_SELENDCANCEL:
696 break;
697 }
698 break;
699 case ID_BREAK: /* CTRL+BRK */
700 /* pass on break char if the ctrl_handler is disabled */
701 if ((*ctrl_handler)(CTRL_C_EVENT) == FALSE) {
702 c = 0x03;
703 write_inbuf(&c,1);
704 }
705 return 0;
706 }
707 break;
708 case WM_KEYDOWN :
709 switch (wParam) {
710 case VK_UP: c = 'P'-'@'; break;
711 case VK_DOWN : c = 'N'-'@'; break;
712 case VK_RIGHT : c = 'F'-'@'; break;
713 case VK_LEFT : c = 'B'-'@'; break;
714 case VK_DELETE : c = 'D' -'@'; break;
715 case VK_HOME : c = 'A'-'@'; break;
716 case VK_END : c = 'E'-'@'; break;
717 case VK_RETURN : AddToCmdHistory(); return 0;
718 case VK_PRIOR : /* PageUp */
719 PostMessage(hClientWnd, WM_VSCROLL, SB_PAGEUP, 0);
720 return 0;
721 case VK_NEXT : /* PageDown */
722 PostMessage(hClientWnd, WM_VSCROLL, SB_PAGEDOWN, 0);
723 return 0;
724 default: return 0;
725 }
726 write_inbuf(&c, 1);
727 return 0;
728 case WM_MOUSEWHEEL:
729 {
730 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
731 if (delta < 0) {
732 PostMessage(hClientWnd, WM_VSCROLL, MAKELONG(SB_THUMBTRACK,
733 (iVscrollPos + 5)),0);
734 } else {
735 WORD pos = ((iVscrollPos - 5) < 0) ? 0 : (iVscrollPos - 5);
736 PostMessage(hClientWnd, WM_VSCROLL, MAKELONG(SB_THUMBTRACK,pos),0);
737 }
738 return 0;
739 }
740 case WM_CHAR:
741 c = (TCHAR)wParam;
742 write_inbuf(&c,1);
743 return 0;
744 case WM_CLOSE :
745 break;
746 case WM_DESTROY :
747 SaveUserPreferences();
748 destroyed = TRUE;
749 PostQuitMessage(0);
750 return 0;
751 case WM_SAVE_PREFS :
752 SaveUserPreferences();
753 return 0;
754 }
755 return DefWindowProc(hwnd, iMsg, wParam, lParam);
756 }
757
758 static BOOL
Client_OnCreate(HWND hwnd,LPCREATESTRUCT lpCreateStruct)759 Client_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
760 {
761 ConFontInitialize(hwnd);
762 cur_x = cur_y = 0;
763 iVscrollPos = 0;
764 iHscrollPos = 0;
765 return TRUE;
766 }
767
768 static void
Client_OnPaint(HWND hwnd)769 Client_OnPaint(HWND hwnd)
770 {
771 ScreenLine_t *pLine;
772 int x,y,i,iTop,iBot;
773 PAINTSTRUCT ps;
774 RECT rcInvalid;
775 HDC hdc;
776
777 hdc = BeginPaint(hwnd, &ps);
778 rcInvalid = ps.rcPaint;
779 hdc = ps.hdc;
780 iTop = max(0, iVscrollPos + rcInvalid.top/cyChar);
781 iBot = min(nBufLines, iVscrollPos + rcInvalid.bottom/cyChar+1);
782 pLine = GetLineFromY(iTop);
783 for (i = iTop; i < iBot && pLine != NULL; i++) {
784 y = cyChar*(i-iVscrollPos);
785 x = -cxChar*iHscrollPos;
786 TextOut(hdc, x, y, &pLine->text[0], pLine->width);
787 pLine = pLine->next;
788 }
789 if (fTextSelected || fSelecting) {
790 InvertSelectionArea(hwnd);
791 }
792 SetCaretPos(GetXFromCurrentY(hdc,iHscrollPos,cur_x), (cur_y-iVscrollPos)*cyChar);
793 EndPaint(hwnd, &ps);
794 }
795 #ifdef HARDDEBUG
dump_linebufs(void)796 static void dump_linebufs(void) {
797 char *buff;
798 ScreenLine_t *s = buffer_top;
799 fprintf(stderr,"LinebufDump------------------------\n");
800 while(s) {
801 if (s == buffer_top) fprintf(stderr,"BT-> ");
802 if (s == buffer_bottom) fprintf(stderr,"BB-> ");
803 if (s == cur_line) fprintf(stderr,"CL-> ");
804
805 buff = (char *) ALLOC(s->width+1);
806 memcpy(buff,s->text,s->width);
807 buff[s->width] = '\0';
808 fprintf(stderr,"{\"%s\",%d,%d}\n",buff,s->newline,s->allocated);
809 FREE(buff);
810 s = s->next;
811 }
812 fprintf(stderr,"LinebufDumpEnd---------------------\n");
813 fflush(stderr);
814 }
815 #endif
816
reorganize_linebufs(HWND hwnd)817 static void reorganize_linebufs(HWND hwnd) {
818 ScreenLine_t *otop = buffer_top;
819 ScreenLine_t *obot = buffer_bottom;
820 ScreenLine_t *next;
821 int i,cpos;
822
823 cpos = 0;
824 i = nBufLines - cur_y;
825 while (i > 1) {
826 cpos += obot->width;
827 obot = obot->prev;
828 i--;
829 }
830 cpos += (obot->width - cur_x);
831 #ifdef HARDDEBUG
832 fprintf(stderr,"nBufLines = %d, cur_x = %d, cur_y = %d, cpos = %d\n",
833 nBufLines,cur_x,cur_y,cpos);
834 fflush(stderr);
835 #endif
836
837
838 nBufLines = 0;
839 buffer_top = cur_line = ConNewLine();
840 cur_line->next = buffer_bottom = ConNewLine();
841 buffer_bottom->prev = cur_line;
842
843 cur_x = cur_y = 0;
844 iVscrollPos = 0;
845 iHscrollPos = 0;
846
847 while(otop) {
848 for(i=0;i<otop->width;++i) {
849 cur_line->text[cur_x] = otop->text[i];
850 cur_x++;
851 if (cur_x > cur_line->width)
852 cur_line->width = cur_x;
853 if (GetXFromCurrentY(GetDC(hwnd),0,cur_x) + cxChar >
854 (LINE_LENGTH * cxChar)) {
855 ConCarriageFeed(0);
856 }
857 }
858 if (otop->newline) {
859 ConCarriageFeed(1);
860 /*ConScrollScreen();*/
861 }
862 next = otop->next;
863 FREE(otop->text);
864 FREE(otop);
865 otop = next;
866 }
867 while (cpos) {
868 cur_x--;
869 if (cur_x < 0) {
870 cur_y--;
871 cur_line = cur_line->prev;
872 cur_x = cur_line->width-1;
873 }
874 cpos--;
875 }
876 SetCaretPos(GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x), (cur_y-iVscrollPos)*cyChar);
877 #ifdef HARDDEBUG
878 fprintf(stderr,"canvasColumns = %d,nBufLines = %d, cur_x = %d, cur_y = %d\n",
879 canvasColumns,nBufLines,cur_x,cur_y);
880 fflush(stderr);
881 #endif
882 }
883
884
885 static void
Client_OnSize(HWND hwnd,UINT state,int cx,int cy)886 Client_OnSize(HWND hwnd, UINT state, int cx, int cy)
887 {
888 RECT r;
889 SCROLLBARINFO sbi;
890 int w,h,columns;
891 int scrollheight;
892 cxClient = cx;
893 cyClient = cy;
894 set_scroll_info(hwnd);
895 GetClientRect(hwnd,&r);
896 w = r.right - r.left;
897 h = r.bottom - r.top;
898 sbi.cbSize = sizeof(SCROLLBARINFO);
899 if (!GetScrollBarInfo(hwnd, OBJID_HSCROLL,&sbi) ||
900 (sbi.rgstate[0] & STATE_SYSTEM_INVISIBLE)) {
901 scrollheight = 0;
902 } else {
903 scrollheight = sbi.rcScrollBar.bottom - sbi.rcScrollBar.top;
904 }
905 canvasRows = (h - scrollheight) / cyChar;
906 if (canvasRows < DEF_CANVAS_ROWS) {
907 canvasRows = DEF_CANVAS_ROWS;
908 }
909 columns = (w - GetSystemMetrics(SM_CXVSCROLL)) /cxChar;
910 if (columns < DEF_CANVAS_COLUMNS)
911 columns = DEF_CANVAS_COLUMNS;
912 if (columns != canvasColumns) {
913 canvasColumns = columns;
914 /*dump_linebufs();*/
915 reorganize_linebufs(hwnd);
916 fSelecting = fTextSelected = FALSE;
917 InvalidateRect(hwnd, NULL, TRUE);
918 #ifdef HARDDEBUG
919 fprintf(stderr,"Paint: cols = %d, rows = %d\n",canvasColumns,canvasRows);
920 fflush(stderr);
921 #endif
922 }
923
924 SetCaretPos(GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x), (cur_y-iVscrollPos)*cyChar);
925 }
926
calc_charpoint_from_point(HDC dc,int x,int y,int y_offset,POINT * pt)927 static void calc_charpoint_from_point(HDC dc, int x, int y, int y_offset, POINT *pt)
928 {
929 int r;
930 int hscrollPix = iHscrollPos * cxChar;
931
932 pt->y = y/cyChar + iVscrollPos + y_offset;
933
934 if (x > (LINE_LENGTH-iHscrollPos) * cxChar) {
935 x = (LINE_LENGTH-iHscrollPos) * cxChar;
936 }
937 if (pt->y - y_offset > 0 && GetLineFromY(pt->y - y_offset) == NULL) {
938 pt->y = nBufLines - 1 + y_offset;
939 pt->x = GetLineFromY(pt->y - y_offset)->width;
940 } else {
941 for (pt->x = 1;
942 (r = GetXFromLine(dc, 0, pt->x, GetLineFromY(pt->y - y_offset))) != 0 &&
943 (r - hscrollPix) < x;
944 ++(pt->x))
945 ;
946 if ((r - hscrollPix) > x)
947 --(pt->x);
948 #ifdef HARD_SEL_DEBUG
949 fprintf(stderr,"pt->x = %d, iHscrollPos = %d\n",(int) pt->x, iHscrollPos);
950 fflush(stderr);
951 #endif
952 if (pt->x <= 0) {
953 pt->x = x/cxChar + iHscrollPos;
954 }
955 }
956 }
957
958
959 static void
Client_OnLButtonDown(HWND hwnd,BOOL fDoubleClick,int x,int y,UINT keyFlags)960 Client_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
961 {
962 int r;
963 SetFocus(GetParent(hwnd)); /* In case combobox steals the focus */
964 #ifdef HARD_SEL_DEBUG
965 fprintf(stderr,"OnLButtonDown fSelecting = %d, fTextSelected = %d:\n",
966 fSelecting,fTextSelected);
967 fflush(stderr);
968 #endif
969 if (fTextSelected) {
970 InvertSelectionArea(hwnd);
971 }
972 fTextSelected = FALSE;
973
974 calc_charpoint_from_point(GetDC(hwnd), x, y, 0, &editBeg);
975
976 editEnd.x = editBeg.x;
977 editEnd.y = editBeg.y + 1;
978 fSelecting = TRUE;
979 SetCapture(hwnd);
980 }
981
982 static void
Client_OnRButtonDown(HWND hwnd,BOOL fDoubleClick,int x,int y,UINT keyFlags)983 Client_OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
984 {
985 if (fTextSelected) {
986 fSelecting = TRUE;
987 Client_OnMouseMove(hwnd,x,y,keyFlags);
988 fSelecting = FALSE;
989 }
990 }
991
992 static void
Client_OnLButtonUp(HWND hwnd,int x,int y,UINT keyFlags)993 Client_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
994 {
995 #ifdef HARD_SEL_DEBUG
996 fprintf(stderr,"OnLButtonUp fSelecting = %d, fTextSelected = %d:\n",
997 fSelecting,fTextSelected);
998 fprintf(stderr,"(Beg.x = %d, Beg.y = %d, "
999 "End.x = %d, End.y = %d)\n",editBeg.x,editBeg.y,
1000 editEnd.x,editEnd.y);
1001 #endif
1002 if (fSelecting &&
1003 !(editBeg.x == editEnd.x && editBeg.y == (editEnd.y - 1))) {
1004 fTextSelected = TRUE;
1005 }
1006 #ifdef HARD_SEL_DEBUG
1007 fprintf(stderr,"OnLButtonUp fTextSelected = %d:\n",
1008 fTextSelected);
1009 fflush(stderr);
1010 #endif
1011 fSelecting = FALSE;
1012 ReleaseCapture();
1013 }
1014
1015 #define EMPTY_RECT(R) \
1016 (((R).bottom - (R).top == 0) || ((R).right - (R).left == 0))
1017 #define ABS(X) (((X)< 0) ? -1 * (X) : X)
1018 #define DIFF(A,B) ABS(((int)(A)) - ((int)(B)))
1019
diff_sel_area(RECT old[3],RECT new[3],RECT result[6])1020 static int diff_sel_area(RECT old[3], RECT new[3], RECT result[6])
1021 {
1022 int absposold = old[0].left + old[0].top * canvasColumns;
1023 int absposnew = new[0].left + new[0].top * canvasColumns;
1024 int absendold = absposold, absendnew = absposnew;
1025 int i, x, ret = 0;
1026 int abspos[2],absend[2];
1027 for(i = 0; i < 3; ++i) {
1028 if (!EMPTY_RECT(old[i])) {
1029 absendold += (old[i].right - old[i].left) *
1030 (old[i].bottom - old[i].top);
1031 }
1032 if (!EMPTY_RECT(new[i])) {
1033 absendnew += (new[i].right - new[i].left) *
1034 (new[i].bottom - new[i].top);
1035 }
1036 }
1037 abspos[0] = min(absposold, absposnew);
1038 absend[0] = DIFF(absposold, absposnew) + abspos[0];
1039 abspos[1] = min(absendold, absendnew);
1040 absend[1] = DIFF(absendold, absendnew) + abspos[1];
1041 #ifdef HARD_SEL_DEBUG
1042 fprintf(stderr,"abspos[0] = %d, absend[0] = %d, abspos[1] = %d, absend[1] = %d\n",abspos[0],absend[0],abspos[1],absend[1]);
1043 fflush(stderr);
1044 #endif
1045 i = 0;
1046 for (x = 0; x < 2; ++x) {
1047 if (abspos[x] != absend[x]) {
1048 int consumed = 0;
1049 result[i].left = abspos[x] % canvasColumns;
1050 result[i].top = abspos[x] / canvasColumns;
1051 result[i].bottom = result[i].top + 1;
1052 if ((absend[x] - abspos[x]) + result[i].left < canvasColumns) {
1053 #ifdef HARD_SEL_DEBUG
1054 fprintf(stderr,"Nowrap, %d < canvasColumns\n",
1055 (absend[x] - abspos[x]) + result[i].left);
1056 fflush(stderr);
1057 #endif
1058 result[i].right = (absend[x] - abspos[x]) + result[i].left;
1059 consumed += result[i].right - result[i].left;
1060 } else {
1061 #ifdef HARD_SEL_DEBUG
1062 fprintf(stderr,"Wrap, %d >= canvasColumns\n",
1063 (absend[x] - abspos[x]) + result[i].left);
1064 fflush(stderr);
1065 #endif
1066 result[i].right = canvasColumns;
1067 consumed += result[i].right - result[i].left;
1068 if (absend[x] - abspos[x] - consumed >= canvasColumns) {
1069 ++i;
1070 result[i].top = result[i-1].bottom;
1071 result[i].left = 0;
1072 result[i].right = canvasColumns;
1073 result[i].bottom = (absend[x] - abspos[x] - consumed) / canvasColumns + result[i].top;
1074 consumed += (result[i].bottom - result[i].top) * canvasColumns;
1075 }
1076 if (absend[x] - abspos[x] - consumed > 0) {
1077 ++i;
1078 result[i].top = result[i-1].bottom;
1079 result[i].bottom = result[i].top + 1;
1080 result[i].left = 0;
1081 result[i].right = absend[x] - abspos[x] - consumed;
1082 }
1083 }
1084 ++i;
1085 }
1086 }
1087 #ifdef HARD_SEL_DEBUG
1088 if (i > 2) {
1089 int x;
1090 fprintf(stderr,"i = %d\n",i);
1091 fflush(stderr);
1092 for (x = 0; x < i; ++x) {
1093 fprintf(stderr, "result[%d]: top = %d, left = %d, "
1094 "bottom = %d. right = %d\n",
1095 x, result[x].top, result[x].left,
1096 result[x].bottom, result[x].right);
1097 }
1098 }
1099 #endif
1100 return i;
1101 }
1102
1103
1104
calc_sel_area(RECT rects[3],POINT beg,POINT end)1105 static void calc_sel_area(RECT rects[3], POINT beg, POINT end)
1106 {
1107 /* These are not really rects and points, these are character
1108 based positions, need to be multiplied by cxChar and cyChar to
1109 make up canvas coordinates */
1110 memset(rects,0,3*sizeof(RECT));
1111 rects[0].left = beg.x;
1112 rects[0].top = beg.y;
1113 rects[0].bottom = beg.y+1;
1114 if (end.y - beg.y == 1) { /* Only one row */
1115 rects[0].right = end.x;
1116 goto out;
1117 }
1118 rects[0].right = canvasColumns;
1119 if (end.y - beg.y > 2) {
1120 rects[1].left = 0;
1121 rects[1].top = rects[0].bottom;
1122 rects[1].right = canvasColumns;
1123 rects[1].bottom = end.y - 1;
1124 }
1125 rects[2].left = 0;
1126 rects[2].top = end.y - 1;
1127 rects[2].bottom = end.y;
1128 rects[2].right = end.x;
1129
1130 out:
1131 #ifdef HARD_SEL_DEBUG
1132 {
1133 int i;
1134 fprintf(stderr,"beg.x = %d, beg.y = %d, end.x = %d, end.y = %d\n",
1135 beg.x,beg.y,end.x,end.y);
1136 for (i = 0; i < 3; ++i) {
1137 fprintf(stderr,"[%d] left = %d, top = %d, "
1138 "right = %d, bottom = %d\n",
1139 i, rects[i].left, rects[i].top,
1140 rects[i].right, rects[i].bottom);
1141 }
1142 fflush(stderr);
1143 }
1144 #endif
1145 return;
1146 }
1147
calc_sel_area_turned(RECT rects[3],POINT eBeg,POINT eEnd)1148 static void calc_sel_area_turned(RECT rects[3], POINT eBeg, POINT eEnd) {
1149 POINT from,to;
1150 if (eBeg.y >= eEnd.y ||
1151 (eBeg.y == eEnd.y - 1 && eBeg.x > eEnd.x)) {
1152 #ifdef HARD_SEL_DEBUG
1153 fprintf(stderr,"Reverting (Beg.x = %d, Beg.y = %d, "
1154 "End.x = %d, End.y = %d)\n",eBeg.x,eBeg.y,
1155 eEnd.x,eEnd.y);
1156 fflush(stderr);
1157 #endif
1158 from.x = eEnd.x;
1159 from.y = eEnd.y - 1;
1160 to.x = eBeg.x;
1161 to.y = eBeg.y + 1;
1162 calc_sel_area(rects,from,to);
1163 } else {
1164 calc_sel_area(rects,eBeg,eEnd);
1165 }
1166 }
1167
1168
InvertSelectionArea(HWND hwnd)1169 static void InvertSelectionArea(HWND hwnd)
1170 {
1171 RECT rects[3];
1172 POINT from,to;
1173 int i;
1174 calc_sel_area_turned(rects,editBeg,editEnd);
1175 for (i = 0; i < 3; ++i) {
1176 if (!EMPTY_RECT(rects[i])) {
1177 from.x = rects[i].left;
1178 to.x = rects[i].right;
1179 from.y = rects[i].top;
1180 to.y = rects[i].bottom;
1181 DrawSelection(hwnd,from,to);
1182 }
1183 }
1184 }
1185
1186 static void
Client_OnMouseMove(HWND hwnd,int x,int y,UINT keyFlags)1187 Client_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
1188 {
1189 if (fSelecting) {
1190 RECT rold[3], rnew[3], rupdate[6];
1191 int num_updates,i,r;
1192 POINT from,to;
1193 calc_sel_area_turned(rold,editBeg,editEnd);
1194
1195 calc_charpoint_from_point(GetDC(hwnd), x, y, 1, &editEnd);
1196
1197 calc_sel_area_turned(rnew,editBeg,editEnd);
1198 num_updates = diff_sel_area(rold,rnew,rupdate);
1199 for (i = 0; i < num_updates;++i) {
1200 from.x = rupdate[i].left;
1201 to.x = rupdate[i].right;
1202 from.y = rupdate[i].top;
1203 to.y = rupdate[i].bottom;
1204 #ifdef HARD_SEL_DEBUG
1205 fprintf(stderr,"from: x=%d,y=%d, to: x=%d, y=%d\n",
1206 from.x, from.y,to.x,to.y);
1207 fflush(stderr);
1208 #endif
1209 DrawSelection(hwnd,from,to);
1210 }
1211 }
1212 }
1213
1214 static void
Client_OnVScroll(HWND hwnd,HWND hwndCtl,UINT code,int pos)1215 Client_OnVScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos)
1216 {
1217 int iVscroll;
1218
1219 switch(code) {
1220 case SB_LINEDOWN:
1221 iVscroll = 1;
1222 break;
1223 case SB_LINEUP:
1224 iVscroll = -1;
1225 break;
1226 case SB_PAGEDOWN:
1227 iVscroll = max(1, cyClient/cyChar);
1228 break;
1229 case SB_PAGEUP:
1230 iVscroll = min(-1, -cyClient/cyChar);
1231 break;
1232 case SB_THUMBTRACK:
1233 iVscroll = pos - iVscrollPos;
1234 break;
1235 default:
1236 iVscroll = 0;
1237 }
1238 iVscroll = max(-iVscrollPos, min(iVscroll, iVscrollMax-iVscrollPos));
1239 if (iVscroll != 0) {
1240 iVscrollPos += iVscroll;
1241 ScrollWindowEx(hwnd, 0, -cyChar*iVscroll, NULL, NULL,
1242 NULL, NULL, SW_ERASE | SW_INVALIDATE);
1243 SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);
1244 iVscroll = GetScrollPos(hwnd, SB_VERT);
1245 UpdateWindow(hwnd);
1246 }
1247 }
1248
1249 static void
Client_OnHScroll(HWND hwnd,HWND hwndCtl,UINT code,int pos)1250 Client_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos)
1251 {
1252 int iHscroll, curCharWidth = cxClient/cxChar;
1253
1254 switch(code) {
1255 case SB_LINEDOWN:
1256 iHscroll = 1;
1257 break;
1258 case SB_LINEUP:
1259 iHscroll = -1;
1260 break;
1261 case SB_PAGEDOWN:
1262 iHscroll = max(1,curCharWidth-1);
1263 break;
1264 case SB_PAGEUP:
1265 iHscroll = min(-1,-(curCharWidth-1));
1266 break;
1267 case SB_THUMBTRACK:
1268 iHscroll = pos - iHscrollPos;
1269 break;
1270 default:
1271 iHscroll = 0;
1272 }
1273 iHscroll = max(-iHscrollPos, min(iHscroll, iHscrollMax-iHscrollPos-(curCharWidth-1)));
1274 if (iHscroll != 0) {
1275 iHscrollPos += iHscroll;
1276 ScrollWindow(hwnd, -cxChar*iHscroll, 0, NULL, NULL);
1277 SetScrollPos(hwnd, SB_HORZ, iHscrollPos, TRUE);
1278 UpdateWindow(hwnd);
1279 }
1280 }
1281
1282 static LRESULT CALLBACK
ClientWndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)1283 ClientWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
1284 {
1285 switch (iMsg) {
1286 HANDLE_MSG(hwnd, WM_CREATE, Client_OnCreate);
1287 HANDLE_MSG(hwnd, WM_SIZE, Client_OnSize);
1288 HANDLE_MSG(hwnd, WM_PAINT, Client_OnPaint);
1289 HANDLE_MSG(hwnd, WM_LBUTTONDOWN, Client_OnLButtonDown);
1290 HANDLE_MSG(hwnd, WM_RBUTTONDOWN, Client_OnRButtonDown);
1291 HANDLE_MSG(hwnd, WM_LBUTTONUP, Client_OnLButtonUp);
1292 HANDLE_MSG(hwnd, WM_MOUSEMOVE, Client_OnMouseMove);
1293 HANDLE_MSG(hwnd, WM_VSCROLL, Client_OnVScroll);
1294 HANDLE_MSG(hwnd, WM_HSCROLL, Client_OnHScroll);
1295 case WM_CONBEEP:
1296 if (0) Beep(440, 400);
1297 return 0;
1298 case WM_CONTEXT:
1299 ConDrawText(hwnd);
1300 return 0;
1301 case WM_CLOSE:
1302 break;
1303 case WM_DESTROY:
1304 PostQuitMessage(0);
1305 return 0;
1306 }
1307 return DefWindowProc (hwnd, iMsg, wParam, lParam);
1308 }
1309
1310 static void
LoadUserPreferences(void)1311 LoadUserPreferences(void)
1312 {
1313 DWORD size;
1314 DWORD res;
1315 DWORD type;
1316
1317 /* default prefs */
1318 GetObject(GetStockObject(SYSTEM_FIXED_FONT),sizeof(LOGFONT),(PSTR)&logfont);
1319 fgColor = GetSysColor(COLOR_WINDOWTEXT);
1320 bkgColor = GetSysColor(COLOR_WINDOW);
1321 winPos.left = -1;
1322 toolbarVisible = TRUE;
1323
1324 if (RegCreateKeyEx(HKEY_CURRENT_USER, USER_KEY, 0, 0,
1325 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
1326 &key, &res) != ERROR_SUCCESS)
1327 return;
1328 has_key = TRUE;
1329 if (res == REG_CREATED_NEW_KEY)
1330 return;
1331 size = sizeof(logfont);
1332 res = RegQueryValueEx(key,TEXT("Font"),NULL,&type,(LPBYTE)&logfont,&size);
1333 size = sizeof(fgColor);
1334 res = RegQueryValueEx(key,TEXT("FgColor"),NULL,&type,(LPBYTE)&fgColor,&size);
1335 size = sizeof(bkgColor);
1336 res = RegQueryValueEx(key,TEXT("BkColor"),NULL,&type,(LPBYTE)&bkgColor,&size);
1337 size = sizeof(winPos);
1338 res = RegQueryValueEx(key,TEXT("Pos"),NULL,&type,(LPBYTE)&winPos,&size);
1339 size = sizeof(toolbarVisible);
1340 res = RegQueryValueEx(key,TEXT("Toolbar"),NULL,&type,(LPBYTE)&toolbarVisible,&size);
1341 }
1342
1343 static void
SaveUserPreferences(void)1344 SaveUserPreferences(void)
1345 {
1346 WINDOWPLACEMENT wndPlace;
1347
1348 if (has_key == TRUE) {
1349 RegSetValueEx(key,TEXT("Font"),0,REG_BINARY,(CONST BYTE *)&logfont,sizeof(LOGFONT));
1350 RegSetValueEx(key,TEXT("FgColor"),0,REG_DWORD,(CONST BYTE *)&fgColor,sizeof(fgColor));
1351 RegSetValueEx(key,TEXT("BkColor"),0,REG_DWORD,(CONST BYTE *)&bkgColor,sizeof(bkgColor));
1352 RegSetValueEx(key,TEXT("Toolbar"),0,REG_DWORD,(CONST BYTE *)&toolbarVisible,sizeof(toolbarVisible));
1353
1354 wndPlace.length = sizeof(WINDOWPLACEMENT);
1355 GetWindowPlacement(hFrameWnd,&wndPlace);
1356 /* If wndPlace.showCmd == SW_MINIMIZE, then the window is minimized.
1357 We don't care, wndPlace.rcNormalPosition always holds the last known position. */
1358 winPos = wndPlace.rcNormalPosition;
1359 RegSetValueEx(key,TEXT("Pos"),0,REG_BINARY,(CONST BYTE *)&winPos,sizeof(winPos));
1360 }
1361 }
1362
1363
1364 static void
set_scroll_info(HWND hwnd)1365 set_scroll_info(HWND hwnd)
1366 {
1367 SCROLLINFO info;
1368 int hScrollBy;
1369 /*
1370 * Set vertical scrolling range and scroll box position.
1371 */
1372
1373 iVscrollMax = nBufLines-1;
1374 iVscrollPos = min(iVscrollPos, iVscrollMax);
1375 info.cbSize = sizeof(info);
1376 info.fMask = SIF_PAGE|SIF_RANGE|SIF_POS;
1377 info.nMin = 0;
1378 info.nPos = iVscrollPos;
1379 info.nPage = min(cyClient/cyChar, iVscrollMax);
1380 info.nMax = iVscrollMax;
1381 SetScrollInfo(hwnd, SB_VERT, &info, TRUE);
1382
1383 /*
1384 * Set horizontal scrolling range and scroll box position.
1385 */
1386
1387 iHscrollMax = LINE_LENGTH-1;
1388 hScrollBy = max(0, (iHscrollPos - (iHscrollMax-cxClient/cxChar))*cxChar);
1389 iHscrollPos = min(iHscrollPos, iHscrollMax);
1390 info.nPos = iHscrollPos;
1391 info.nPage = cxClient/cxChar;
1392 info.nMax = iHscrollMax;
1393 SetScrollInfo(hwnd, SB_HORZ, &info, TRUE);
1394 /*ScrollWindow(hwnd, hScrollBy, 0, NULL, NULL);*/
1395 }
1396
1397
1398 static void
ensure_line_below(void)1399 ensure_line_below(void)
1400 {
1401 if (cur_line->next == NULL) {
1402 if (nBufLines >= lines_to_save) {
1403 ScreenLine_t* pLine = buffer_top->next;
1404 FREE(buffer_top->text);
1405 FREE(buffer_top);
1406 buffer_top = pLine;
1407 buffer_top->prev = NULL;
1408 nBufLines--;
1409 }
1410 cur_line->next = ConNewLine();
1411 cur_line->next->prev = cur_line;
1412 buffer_bottom = cur_line->next;
1413 set_scroll_info(hClientWnd);
1414 }
1415 }
1416
1417 static ScreenLine_t*
ConNewLine(void)1418 ConNewLine(void)
1419 {
1420 ScreenLine_t *pLine;
1421
1422 pLine = (ScreenLine_t *)ALLOC(sizeof(ScreenLine_t));
1423 if (!pLine)
1424 return NULL;
1425 pLine->text = (TCHAR *) ALLOC(canvasColumns * sizeof(TCHAR));
1426 #ifdef HARDDEBUG
1427 pLine->allocated = canvasColumns;
1428 #endif
1429 pLine->width = 0;
1430 pLine->prev = pLine->next = NULL;
1431 pLine->newline = 0;
1432 nBufLines++;
1433 return pLine;
1434 }
1435
1436 static ScreenLine_t*
GetLineFromY(int y)1437 GetLineFromY(int y)
1438 {
1439 ScreenLine_t *pLine = buffer_top;
1440 int i;
1441
1442 for (i = 0; i < nBufLines && pLine != NULL; i++) {
1443 if (i == y)
1444 return pLine;
1445 pLine = pLine->next;
1446 }
1447 return NULL;
1448 }
1449
ConCarriageFeed(int hard_newline)1450 void ConCarriageFeed(int hard_newline)
1451 {
1452 cur_x = 0;
1453 ensure_line_below();
1454 cur_line->newline = hard_newline;
1455 cur_line = cur_line->next;
1456 if (cur_y < nBufLines-1) {
1457 cur_y++;
1458 } else if (iVscrollPos > 0) {
1459 iVscrollPos--;
1460 }
1461 }
1462
1463 /*
1464 * Scroll screen if cursor is not visible.
1465 */
1466 static void
ConScrollScreen(void)1467 ConScrollScreen(void)
1468 {
1469 if (cur_y >= iVscrollPos + cyClient/cyChar) {
1470 int iVscroll;
1471
1472 iVscroll = cur_y - iVscrollPos - cyClient/cyChar + 1;
1473 iVscrollPos += iVscroll;
1474 ScrollWindowEx(hClientWnd, 0, -cyChar*iVscroll, NULL, NULL,
1475 NULL, NULL, SW_ERASE | SW_INVALIDATE);
1476 SetScrollPos(hClientWnd, SB_VERT, iVscrollPos, TRUE);
1477 UpdateWindow(hClientWnd);
1478 }
1479 }
1480
1481 static void
DrawSelection(HWND hwnd,POINT pt1,POINT pt2)1482 DrawSelection(HWND hwnd, POINT pt1, POINT pt2)
1483 {
1484 HDC hdc;
1485 int width,height;
1486 #ifdef HARD_SEL_DEBUG
1487 fprintf(stderr,"pt1.x = %d, pt1.y = %d, pt2.x = %d, pt2.y = %d\n",
1488 (int) pt1.x, (int) pt1.y, (int) pt2.x, (int) pt2.y);
1489 #endif
1490 pt1.x = GetXFromLine(GetDC(hwnd),iHscrollPos,pt1.x,GetLineFromY(pt1.y));
1491 pt2.x = GetXFromLine(GetDC(hwnd),iHscrollPos,pt2.x,GetLineFromY(pt2.y-1));
1492 pt1.y -= iVscrollPos;
1493 pt2.y -= iVscrollPos;
1494 pt1.y *= cyChar;
1495 pt2.y *= cyChar;
1496 #ifdef HARD_SEL_DEBUG
1497 fprintf(stderr,"pt1.x = %d, pt1.y = %d, pt2.x = %d, pt2.y = %d\n",
1498 (int) pt1.x, (int) pt1.y, (int) pt2.x, (int) pt2.y);
1499 fflush(stderr);
1500 #endif
1501 width = pt2.x-pt1.x;
1502 height = pt2.y - pt1.y;
1503 hdc = GetDC(hwnd);
1504 PatBlt(hdc,pt1.x,pt1.y,width,height,DSTINVERT);
1505 ReleaseDC(hwnd,hdc);
1506 }
1507
1508 static void
OnEditCopy(HWND hwnd)1509 OnEditCopy(HWND hwnd)
1510 {
1511 HGLOBAL hMem;
1512 TCHAR *pMem;
1513 ScreenLine_t *pLine;
1514 RECT rects[3];
1515 POINT from,to;
1516 int i,j,sum,len;
1517 if (editBeg.y >= editEnd.y ||
1518 (editBeg.y == editEnd.y - 1 && editBeg.x > editEnd.x)) {
1519 #ifdef HARD_SEL_DEBUG
1520 fprintf(stderr,"CopyReverting (Beg.x = %d, Beg.y = %d, "
1521 "End.x = %d, End.y = %d)\n",editBeg.x,editBeg.y,
1522 editEnd.x,editEnd.y);
1523 fflush(stderr);
1524 #endif
1525 from.x = editEnd.x;
1526 from.y = editEnd.y - 1;
1527 to.x = editBeg.x;
1528 to.y = editBeg.y + 1;
1529 calc_sel_area(rects,from,to);
1530 } else {
1531 calc_sel_area(rects,editBeg,editEnd);
1532 }
1533 sum = 1;
1534 for (i = 0; i < 3; ++i) {
1535 if (!EMPTY_RECT(rects[i])) {
1536 pLine = GetLineFromY(rects[i].top);
1537 for (j = rects[i].top; j < rects[i].bottom ;++j) {
1538 if (pLine == NULL) {
1539 sum += 2;
1540 break;
1541 }
1542 if (pLine->width > rects[i].left) {
1543 sum += (pLine->width < rects[i].right) ?
1544 pLine->width - rects[i].left :
1545 rects[i].right - rects[i].left;
1546 }
1547 if(pLine->newline && rects[i].right >= pLine->width) {
1548 sum += 2;
1549 }
1550 pLine = pLine->next;
1551 }
1552 }
1553 }
1554 #ifdef HARD_SEL_DEBUG
1555 fprintf(stderr,"sum = %d\n",sum);
1556 fflush(stderr);
1557 #endif
1558 hMem = GlobalAlloc(GHND, sum * sizeof(TCHAR));
1559 pMem = GlobalLock(hMem);
1560 for (i = 0; i < 3; ++i) {
1561 if (!EMPTY_RECT(rects[i])) {
1562 pLine = GetLineFromY(rects[i].top);
1563 for (j = rects[i].top; j < rects[i].bottom; ++j) {
1564 if (pLine == NULL) {
1565 memcpy(pMem,TEXT("\r\n"),2 * sizeof(TCHAR));
1566 pMem += 2;
1567 break;
1568 }
1569 if (pLine->width > rects[i].left) {
1570 len = (pLine->width < rects[i].right) ?
1571 pLine->width - rects[i].left :
1572 rects[i].right - rects[i].left;
1573 memcpy(pMem,pLine->text + rects[i].left,len * sizeof(TCHAR));
1574 pMem +=len;
1575 }
1576 if(pLine->newline && rects[i].right >= pLine->width) {
1577 memcpy(pMem,TEXT("\r\n"),2 * sizeof(TCHAR));
1578 pMem += 2;
1579 }
1580 pLine = pLine->next;
1581 }
1582 }
1583 }
1584 *pMem = TEXT('\0');
1585 /* Flash de selection area to give user feedback about copying */
1586 InvertSelectionArea(hwnd);
1587 Sleep(100);
1588 InvertSelectionArea(hwnd);
1589
1590 OpenClipboard(hwnd);
1591 EmptyClipboard();
1592 GlobalUnlock(hMem);
1593 SetClipboardData(CF_UNICODETEXT,hMem);
1594 CloseClipboard();
1595 }
1596
1597 /* XXX:PaN Tchar or char? */
1598 static void
OnEditPaste(HWND hwnd)1599 OnEditPaste(HWND hwnd)
1600 {
1601 HANDLE hClipMem;
1602 TCHAR *pClipMem,*pMem,*pMem2;
1603 if (!OpenClipboard(hwnd))
1604 return;
1605 if ((hClipMem = GetClipboardData(CF_UNICODETEXT)) != NULL) {
1606 pClipMem = GlobalLock(hClipMem);
1607 pMem = (TCHAR *)ALLOC(GlobalSize(hClipMem) * sizeof(TCHAR));
1608 pMem2 = pMem;
1609 while ((*pMem2 = *pClipMem) != TEXT('\0')) {
1610 if (*pClipMem == TEXT('\r'))
1611 *pMem2 = TEXT('\n');
1612 ++pMem2;
1613 ++pClipMem;
1614 }
1615 GlobalUnlock(hClipMem);
1616 write_inbuf(pMem, _tcsclen(pMem));
1617 }
1618 CloseClipboard();
1619 }
1620
1621 static void
OnEditSelAll(HWND hwnd)1622 OnEditSelAll(HWND hwnd)
1623 {
1624 editBeg.x = 0;
1625 editBeg.y = 0;
1626 editEnd.x = LINE_LENGTH-1;
1627 editEnd.y = cur_y;
1628 fTextSelected = TRUE;
1629 InvalidateRect(hwnd, NULL, TRUE);
1630 }
1631
CFHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)1632 CF_HOOK_RET APIENTRY CFHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)
1633 {
1634 /* Hook procedure for font dialog box */
1635 HWND hOwner;
1636 RECT rc,rcOwner,rcDlg;
1637 switch (iMsg) {
1638 case WM_INITDIALOG:
1639 /* center dialogbox within its owner window */
1640 if ((hOwner = GetParent(hDlg)) == NULL)
1641 hOwner = GetDesktopWindow();
1642 GetWindowRect(hOwner, &rcOwner);
1643 GetWindowRect(hDlg, &rcDlg);
1644 CopyRect(&rc, &rcOwner);
1645 OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
1646 OffsetRect(&rc, -rc.left, -rc.top);
1647 OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
1648 SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2),
1649 rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE);
1650 return (CF_HOOK_RET) 1;
1651 default:
1652 break;
1653 }
1654 return (CF_HOOK_RET) 0; /* Let the default procedure process the message */
1655 }
1656
1657 static BOOL
ConChooseFont(HWND hwnd)1658 ConChooseFont(HWND hwnd)
1659 {
1660 HDC hdc;
1661 hdc = GetDC(hwnd);
1662 cf.lStructSize = sizeof(CHOOSEFONT);
1663 cf.hwndOwner = hwnd;
1664 cf.hDC = NULL;
1665 cf.lpLogFont = &logfont;
1666 cf.iPointSize = 0;
1667 cf.Flags = CF_INITTOLOGFONTSTRUCT|CF_SCREENFONTS|CF_FIXEDPITCHONLY|CF_EFFECTS|CF_ENABLEHOOK;
1668 cf.rgbColors = GetTextColor(hdc);
1669 cf.lCustData = 0L;
1670 cf.lpfnHook = CFHookProc;
1671 cf.lpTemplateName = NULL;
1672 cf.hInstance = NULL;
1673 cf.lpszStyle = NULL;
1674 cf.nFontType = 0;
1675 cf.nSizeMin = 0;
1676 cf.nSizeMax = 0;
1677 ReleaseDC(hwnd,hdc);
1678 return ChooseFont(&cf);
1679 }
1680
1681 static void
ConFontInitialize(HWND hwnd)1682 ConFontInitialize(HWND hwnd)
1683 {
1684 HDC hdc;
1685 TEXTMETRIC tm;
1686 HFONT hFont;
1687
1688 hFont = CreateFontIndirect(&logfont);
1689 hdc = GetDC(hwnd);
1690 SelectObject(hdc, hFont);
1691 SetTextColor(hdc,fgColor);
1692 SetBkColor(hdc,bkgColor);
1693 GetTextMetrics(hdc, &tm);
1694 cxChar = tm.tmAveCharWidth;
1695 cxCharMax = tm.tmMaxCharWidth;
1696 cyChar = tm.tmHeight + tm.tmExternalLeading;
1697 ReleaseDC(hwnd, hdc);
1698 }
1699
1700 static void
ConSetFont(HWND hwnd)1701 ConSetFont(HWND hwnd)
1702 {
1703 HDC hdc;
1704 TEXTMETRIC tm;
1705 HFONT hFontNew;
1706
1707 hFontNew = CreateFontIndirect(&logfont);
1708 SendMessage(hComboWnd,WM_SETFONT,(WPARAM)hFontNew,
1709 MAKELPARAM(1,0));
1710 hdc = GetDC(hwnd);
1711 DeleteObject(SelectObject(hdc, hFontNew));
1712 GetTextMetrics(hdc, &tm);
1713 cxChar = tm.tmAveCharWidth;
1714 cxCharMax = tm.tmMaxCharWidth;
1715 cyChar = tm.tmHeight + tm.tmExternalLeading;
1716 fgColor = cf.rgbColors;
1717 SetTextColor(hdc,fgColor);
1718 ReleaseDC(hwnd, hdc);
1719 set_scroll_info(hwnd);
1720 HideCaret(hwnd);
1721 if (DestroyCaret()) {
1722 CreateCaret(hwnd, NULL, cxChar, cyChar);
1723 SetCaretPos(GetXFromCurrentY(hdc,iHscrollPos,cur_x), (cur_y-iVscrollPos)*cyChar);
1724 }
1725 ShowCaret(hwnd);
1726 InvalidateRect(hwnd, NULL, TRUE);
1727 }
1728
1729 CC_HOOK_RET APIENTRY
CCHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)1730 CCHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)
1731 {
1732 /* Hook procedure for choose color dialog box */
1733 HWND hOwner;
1734 RECT rc,rcOwner,rcDlg;
1735 switch (iMsg) {
1736 case WM_INITDIALOG:
1737 /* center dialogbox within its owner window */
1738 if ((hOwner = GetParent(hDlg)) == NULL)
1739 hOwner = GetDesktopWindow();
1740 GetWindowRect(hOwner, &rcOwner);
1741 GetWindowRect(hDlg, &rcDlg);
1742 CopyRect(&rc, &rcOwner);
1743 OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
1744 OffsetRect(&rc, -rc.left, -rc.top);
1745 OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
1746 SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2),
1747 rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE);
1748 return (CC_HOOK_RET) 1;
1749 default:
1750 break;
1751 }
1752 return (CC_HOOK_RET) 0; /* Let the default procedure process the message */
1753 }
1754
ConChooseColor(HWND hwnd)1755 void ConChooseColor(HWND hwnd)
1756 {
1757 CHOOSECOLOR cc;
1758 static COLORREF acrCustClr[16];
1759 HBRUSH hbrush;
1760 HDC hdc;
1761
1762 /* Initialize CHOOSECOLOR */
1763 ZeroMemory(&cc, sizeof(CHOOSECOLOR));
1764 cc.lStructSize = sizeof(CHOOSECOLOR);
1765 cc.hwndOwner = hwnd;
1766 cc.lpCustColors = (LPDWORD) acrCustClr;
1767 cc.rgbResult = bkgColor;
1768 cc.lpfnHook = CCHookProc;
1769 cc.Flags = CC_FULLOPEN|CC_RGBINIT|CC_SOLIDCOLOR|CC_ENABLEHOOK;
1770
1771 if (ChooseColor(&cc)==TRUE) {
1772 bkgColor = cc.rgbResult;
1773 hdc = GetDC(hwnd);
1774 SetBkColor(hdc,bkgColor);
1775 ReleaseDC(hwnd,hdc);
1776 hbrush = CreateSolidBrush(bkgColor);
1777 DeleteObject((HBRUSH)SetClassLong(hClientWnd,GCL_HBRBACKGROUND,(LONG)hbrush));
1778 InvalidateRect(hwnd,NULL,TRUE);
1779 }
1780 }
1781
OFNHookProc(HWND hwndDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)1782 OFN_HOOK_RET APIENTRY OFNHookProc(HWND hwndDlg,UINT iMsg,
1783 WPARAM wParam,LPARAM lParam)
1784 {
1785 /* Hook procedure for open file dialog box */
1786 HWND hOwner,hDlg;
1787 RECT rc,rcOwner,rcDlg;
1788 hDlg = GetParent(hwndDlg);
1789 switch (iMsg) {
1790 case WM_INITDIALOG:
1791 /* center dialogbox within its owner window */
1792 if ((hOwner = GetParent(hDlg)) == NULL)
1793 hOwner = GetDesktopWindow();
1794 GetWindowRect(hOwner, &rcOwner);
1795 GetWindowRect(hDlg, &rcDlg);
1796 CopyRect(&rc, &rcOwner);
1797 OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
1798 OffsetRect(&rc, -rc.left, -rc.top);
1799 OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
1800 SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2),
1801 rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE);
1802 return (OFN_HOOK_RET) 1;
1803 default:
1804 break;
1805 }
1806 return (OFN_HOOK_RET) 0; /* the let default procedure process the message */
1807 }
1808
1809 static void
GetFileName(HWND hwnd,TCHAR * pFile)1810 GetFileName(HWND hwnd, TCHAR *pFile)
1811 {
1812 /* Open the File Open dialog box and */
1813 /* retrieve the file name */
1814 OPENFILENAME ofn;
1815 TCHAR szFilterSpec [128] = TEXT("logfiles (*.log)\0*.log\0All files (*.*)\0*.*\0\0");
1816 #define MAXFILENAME 256
1817 TCHAR szFileName[MAXFILENAME];
1818 TCHAR szFileTitle[MAXFILENAME];
1819
1820 /* these need to be filled in */
1821 _tcscpy(szFileName, TEXT("erlshell.log"));
1822 _tcscpy(szFileTitle, TEXT("")); /* must be NULL */
1823
1824 ofn.lStructSize = sizeof(OPENFILENAME);
1825 ofn.hwndOwner = NULL;
1826 ofn.lpstrFilter = szFilterSpec;
1827 ofn.lpstrCustomFilter = NULL;
1828 ofn.nMaxCustFilter = 0;
1829 ofn.nFilterIndex = 0;
1830 ofn.lpstrFile = szFileName;
1831 ofn.nMaxFile = MAXFILENAME;
1832 ofn.lpstrInitialDir = NULL;
1833 ofn.lpstrFileTitle = szFileTitle;
1834 ofn.nMaxFileTitle = MAXFILENAME;
1835 ofn.lpstrTitle = TEXT("Open logfile");
1836 ofn.lpstrDefExt = TEXT("log");
1837 ofn.Flags = OFN_CREATEPROMPT|OFN_HIDEREADONLY|OFN_EXPLORER|OFN_ENABLEHOOK|OFN_NOCHANGEDIR; /* OFN_NOCHANGEDIR only works in Vista :( */
1838 ofn.lpfnHook = OFNHookProc;
1839
1840 if (!GetOpenFileName ((LPOPENFILENAME)&ofn)){
1841 *pFile = TEXT('\0');
1842 } else {
1843 _tcscpy(pFile, ofn.lpstrFile);
1844 }
1845 }
1846
OpenLogFile(HWND hwnd)1847 void OpenLogFile(HWND hwnd)
1848 {
1849 /* open a file for logging */
1850 TCHAR filename[_MAX_PATH];
1851
1852 GetFileName(hwnd, filename);
1853 if (filename[0] == '\0')
1854 return;
1855 if (NULL == (logfile = _tfopen(filename,TEXT("w,ccs=UNICODE"))))
1856 return;
1857 }
1858
CloseLogFile(HWND hwnd)1859 void CloseLogFile(HWND hwnd)
1860 {
1861 /* close log file */
1862 fclose(logfile);
1863 logfile = NULL;
1864 }
1865
LogFileWrite(TCHAR * buf,int num_chars)1866 void LogFileWrite(TCHAR *buf, int num_chars)
1867 {
1868 /* write to logfile */
1869 int from,to;
1870 while (num_chars-- > 0) {
1871 switch (*buf) {
1872 case SET_CURSOR:
1873 buf++;
1874 from = *((int *)buf);
1875 buf += sizeof(int)/sizeof(TCHAR);
1876 to = *((int *)buf);
1877 buf += (sizeof(int)/sizeof(TCHAR))-1;
1878 num_chars -= 2 * (sizeof(int)/sizeof(TCHAR));
1879 // Wont seek in Unicode file, sorry...
1880 // fseek(logfile,to-from *sizeof(TCHAR),SEEK_CUR);
1881 break;
1882 default:
1883 _fputtc(*buf,logfile);
1884 break;
1885 }
1886 buf++;
1887 }
1888 }
1889
1890 static void
init_buffers(void)1891 init_buffers(void)
1892 {
1893 inbuf.data = (TCHAR *) ALLOC(BUFSIZE * sizeof(TCHAR));
1894 outbuf.data = (TCHAR *) ALLOC(BUFSIZE * sizeof(TCHAR));
1895 inbuf.size = BUFSIZE;
1896 inbuf.rdPos = inbuf.wrPos = 0;
1897 outbuf.size = BUFSIZE;
1898 outbuf.rdPos = outbuf.wrPos = 0;
1899 }
1900
1901 static int
check_realloc(buffer_t * buf,int num_chars)1902 check_realloc(buffer_t *buf, int num_chars)
1903 {
1904 if (buf->wrPos + num_chars >= buf->size) {
1905 if (buf->size > MAXBUFSIZE)
1906 return 0;
1907 buf->size += num_chars + BUFSIZE;
1908 if (!(buf->data = (TCHAR *)REALLOC(buf->data, buf->size * sizeof(TCHAR)))) {
1909 buf->size = buf->rdPos = buf->wrPos = 0;
1910 return 0;
1911 }
1912 }
1913 return 1;
1914 }
1915
1916 static int
write_inbuf(TCHAR * data,int num_chars)1917 write_inbuf(TCHAR *data, int num_chars)
1918 {
1919 TCHAR *buf;
1920 int nwrite;
1921 WaitForSingleObject(console_input,INFINITE);
1922 if (!check_realloc(&inbuf,num_chars)) {
1923 ReleaseSemaphore(console_input,1,NULL);
1924 return -1;
1925 }
1926 buf = &inbuf.data[inbuf.wrPos];
1927 inbuf.wrPos += num_chars;
1928 nwrite = num_chars;
1929 while (nwrite--)
1930 *buf++ = *data++;
1931 SetEvent(console_input_event);
1932 ReleaseSemaphore(console_input,1,NULL);
1933 return num_chars;
1934 }
1935
1936 static int
write_outbuf(TCHAR * data,int num_chars)1937 write_outbuf(TCHAR *data, int num_chars)
1938 {
1939 TCHAR *buf;
1940 int nwrite;
1941
1942 WaitForSingleObject(console_output,INFINITE);
1943 if (!check_realloc(&outbuf, num_chars)) {
1944 ReleaseSemaphore(console_output,1,NULL);
1945 return -1;
1946 }
1947 if (outbuf.rdPos == outbuf.wrPos)
1948 PostMessage(hClientWnd, WM_CONTEXT, 0L, 0L);
1949 buf = &outbuf.data[outbuf.wrPos];
1950 outbuf.wrPos += num_chars;
1951 nwrite = num_chars;
1952 while (nwrite--)
1953 *buf++ = *data++;
1954 ReleaseSemaphore(console_output,1,NULL);
1955 return num_chars;
1956 }
1957
AboutDlgProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)1958 DIALOG_PROC_RET CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
1959 {
1960 HWND hOwner;
1961 RECT rc,rcOwner,rcDlg;
1962
1963 switch (iMsg) {
1964 case WM_INITDIALOG:
1965 /* center dialogbox within its owner window */
1966 if ((hOwner = GetParent(hDlg)) == NULL)
1967 hOwner = GetDesktopWindow();
1968 GetWindowRect(hOwner, &rcOwner);
1969 GetWindowRect(hDlg, &rcDlg);
1970 CopyRect(&rc, &rcOwner);
1971 OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
1972 OffsetRect(&rc, -rc.left, -rc.top);
1973 OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
1974 SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2),
1975 rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE);
1976 SetDlgItemText(hDlg, ID_VERSIONSTRING,
1977 TEXT("Erlang emulator version ") TEXT(ERLANG_VERSION));
1978 return (DIALOG_PROC_RET) TRUE;
1979 case WM_COMMAND:
1980 switch (LOWORD(wParam)) {
1981 case IDOK:
1982 case IDCANCEL:
1983 EndDialog(hDlg,0);
1984 return (DIALOG_PROC_RET) TRUE;
1985 }
1986 break;
1987 }
1988 return (DIALOG_PROC_RET) FALSE;
1989 }
1990
1991 static void
ConDrawText(HWND hwnd)1992 ConDrawText(HWND hwnd)
1993 {
1994 int num_chars;
1995 int nchars;
1996 TCHAR *buf;
1997 int from, to;
1998 int dl;
1999 int dc;
2000 RECT rc;
2001
2002 WaitForSingleObject(console_output, INFINITE);
2003 nchars = 0;
2004 num_chars = outbuf.wrPos - outbuf.rdPos;
2005 buf = &outbuf.data[outbuf.rdPos];
2006 if (logfile != NULL)
2007 LogFileWrite(buf, num_chars);
2008
2009
2010 #ifdef HARDDEBUG
2011 {
2012 TCHAR *bu = (TCHAR *) ALLOC((num_chars+1) * sizeof(TCHAR));
2013 memcpy(bu,buf,num_chars * sizeof(TCHAR));
2014 bu[num_chars]='\0';
2015 fprintf(stderr,TEXT("ConDrawText\"%s\"\n"),bu);
2016 FREE(bu);
2017 fflush(stderr);
2018 }
2019 #endif
2020 /*
2021 * Don't draw any text in the window; just update the line buffers
2022 * and invalidate the appropriate part of the window. The window
2023 * will be updated on the next WM_PAINT message.
2024 */
2025
2026 while (num_chars-- > 0) {
2027 switch (*buf) {
2028 case '\r':
2029 break;
2030 case '\n':
2031 if (nchars > 0) {
2032 rc.left = GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x - nchars);
2033 rc.right = rc.left + cxCharMax*nchars;
2034 rc.top = cyChar * (cur_y-iVscrollPos);
2035 rc.bottom = rc.top + cyChar;
2036 InvalidateRect(hwnd, &rc, TRUE);
2037 nchars = 0;
2038 }
2039 ConCarriageFeed(1);
2040 ConScrollScreen();
2041 break;
2042 case SET_CURSOR:
2043 if (nchars > 0) {
2044 rc.left = GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x - nchars);
2045 rc.right = rc.left + cxCharMax*nchars;
2046 rc.top = cyChar * (cur_y-iVscrollPos);
2047 rc.bottom = rc.top + cyChar;
2048 InvalidateRect(hwnd, &rc, TRUE);
2049 nchars = 0;
2050 }
2051 buf++;
2052 from = *((int *)buf);
2053 buf += sizeof(int)/sizeof(TCHAR);
2054 to = *((int *)buf);
2055 buf += (sizeof(int)/sizeof(TCHAR))-1;
2056 num_chars -= 2 * (sizeof(int)/sizeof(TCHAR));
2057 while (to > from) {
2058 cur_x++;
2059 if (GetXFromCurrentY(GetDC(hwnd),0,cur_x)+cxChar >
2060 (LINE_LENGTH * cxChar)) {
2061 cur_x = 0;
2062 cur_y++;
2063 ensure_line_below();
2064 cur_line = cur_line->next;
2065 }
2066 from++;
2067 }
2068 while (to < from) {
2069 cur_x--;
2070 if (cur_x < 0) {
2071 cur_y--;
2072 cur_line = cur_line->prev;
2073 cur_x = cur_line->width-1;
2074 }
2075 from--;
2076 }
2077
2078 break;
2079 default:
2080 nchars++;
2081 cur_line->text[cur_x] = *buf;
2082 cur_x++;
2083 if (cur_x > cur_line->width)
2084 cur_line->width = cur_x;
2085 if (GetXFromCurrentY(GetDC(hwnd),0,cur_x)+cxChar >
2086 (LINE_LENGTH * cxChar)) {
2087 if (nchars > 0) {
2088 rc.left = GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x - nchars);
2089 rc.right = rc.left + cxCharMax*nchars;
2090 rc.top = cyChar * (cur_y-iVscrollPos);
2091 rc.bottom = rc.top + cyChar;
2092 InvalidateRect(hwnd, &rc, TRUE);
2093 }
2094 ConCarriageFeed(0);
2095 nchars = 0;
2096 }
2097 }
2098 buf++;
2099 }
2100 if (nchars > 0) {
2101 rc.left = GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x - nchars);
2102 rc.right = rc.left + cxCharMax*nchars;
2103 rc.top = cyChar * (cur_y-iVscrollPos);
2104 rc.bottom = rc.top + cyChar;
2105 InvalidateRect(hwnd, &rc, TRUE);
2106 }
2107 ConScrollScreen();
2108 SetCaretPos(GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x), (cur_y-iVscrollPos)*cyChar);
2109 outbuf.wrPos = outbuf.rdPos = 0;
2110 ReleaseSemaphore(console_output, 1, NULL);
2111 }
2112
2113 static void
AddToCmdHistory(void)2114 AddToCmdHistory(void)
2115 {
2116 int i;
2117 int size;
2118 Uint32 *buf;
2119 wchar_t cmdBuf[128];
2120
2121 if (llen != 0) {
2122 for (i = 0, size = 0; i < llen-1; i++) {
2123 /*
2124 * Find end of prompt.
2125 */
2126 if ((lbuf[i] == '>') && lbuf[i+1] == ' ') {
2127 buf = &lbuf[i+2];
2128 size = llen-i-2;
2129 break;
2130 }
2131 }
2132 if (size > 0 && size < 128) {
2133 for (i = 0;i < size; ++i) {
2134 cmdBuf[i] = (wchar_t) buf[i];
2135 }
2136 cmdBuf[size] = 0;
2137 SendMessage(hComboWnd,CB_INSERTSTRING,0,(LPARAM)cmdBuf);
2138 }
2139 }
2140 }
2141
2142 /*static TBBUTTON tbb[] =
2143 {
2144 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2145 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2146 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2147 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2148 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2149 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2150 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2151 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2152 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2153 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2154 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2155 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2156 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2157 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2158 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2159 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2160 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2161 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2162 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2163 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2164 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2165 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2166 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2167 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2168 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2169 0, IDMENU_COPY, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 0, 0, 0,
2170 1, IDMENU_PASTE, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 0, 0, 0,
2171 2, IDMENU_FONT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 0, 0, 0,
2172 3, IDMENU_ABOUT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 0, 0, 0,
2173 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
2174 };*/
2175 static TBBUTTON tbb[] =
2176 {
2177 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2178 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2179 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2180 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2181 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2182 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2183 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2184 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2185 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2186 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2187 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2188 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2189 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2190 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2191 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2192 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2193 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2194 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2195 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2196 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2197 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2198 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2199 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2200 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2201 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
2202 {0, IDMENU_COPY, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE},
2203 {1, IDMENU_PASTE, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE},
2204 {2, IDMENU_FONT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE},
2205 {3, IDMENU_ABOUT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE},
2206 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}
2207 };
2208
2209 static TBADDBITMAP tbbitmap =
2210 {
2211 HINST_COMMCTRL, IDB_STD_SMALL_COLOR,
2212 };
2213
2214 #ifdef HARDDEBUG
2215 /* For really hard GUI startup debugging, place DEBUGBOX() macros in code
2216 and get modal message boxes with the line number. */
debug_box(int line)2217 static void debug_box(int line) {
2218 TCHAR buff[1024];
2219 swprintf(buff,1024,TEXT("DBG:%d"),line);
2220 MessageBox(NULL,buff,TEXT("DBG"),MB_OK|MB_APPLMODAL);
2221 }
2222
2223 #define DEBUGBOX() debug_box(__LINE__)
2224 #endif
2225
2226 static HWND
InitToolBar(HWND hwndParent)2227 InitToolBar(HWND hwndParent)
2228 {
2229 int x,y,cx;
2230 HWND hwndTB,hwndTT;
2231 RECT r;
2232 TOOLINFO ti;
2233 HFONT hFontNew;
2234 DWORD backgroundColor = GetSysColor(COLOR_BTNFACE);
2235 COLORMAP colorMap;
2236 colorMap.from = RGB(192, 192, 192);
2237 colorMap.to = backgroundColor;
2238 /* Create toolbar window with tooltips */
2239 hwndTB = CreateWindowEx(0,TOOLBARCLASSNAME,(TCHAR *)NULL,
2240 WS_CHILD|CCS_TOP|WS_CLIPSIBLINGS|TBSTYLE_TOOLTIPS,
2241 0,0,0,0,hwndParent,
2242 (HMENU)2,hInstance,NULL);
2243 SendMessage(hwndTB,TB_BUTTONSTRUCTSIZE,
2244 (WPARAM) sizeof(TBBUTTON),0);
2245 tbbitmap.hInst = NULL;
2246 tbbitmap.nID = (UINT) CreateMappedBitmap(beam_module, 1,0, &colorMap, 1);
2247 SendMessage(hwndTB, TB_ADDBITMAP, (WPARAM) 4,
2248 (LPARAM) &tbbitmap);
2249
2250 SendMessage(hwndTB,TB_ADDBUTTONS, (WPARAM) 30,
2251 (LPARAM) tbb);
2252 if (toolbarVisible)
2253 ShowWindow(hwndTB, SW_SHOW);
2254
2255 /* Create combobox window */
2256 SendMessage(hwndTB,TB_GETITEMRECT,0,(LPARAM)&r);
2257 x = r.left; y = r.top;
2258 SendMessage(hwndTB,TB_GETITEMRECT,23,(LPARAM)&r);
2259 cx = r.right - x + 1;
2260 hComboWnd = CreateWindow(TEXT("combobox"),NULL,WS_VSCROLL|WS_CHILD|WS_VISIBLE|CBS_DROPDOWNLIST,
2261 x,y,cx,100,hwndParent,(HMENU)ID_COMBOBOX, hInstance,NULL);
2262 SetParent(hComboWnd,hwndTB);
2263 hFontNew = CreateFontIndirect(&logfont);
2264 SendMessage(hComboWnd,WM_SETFONT,(WPARAM)hFontNew,
2265 MAKELPARAM(1,0));
2266
2267 /* Add tooltip for combo box */
2268 ZeroMemory(&ti,sizeof(TOOLINFO));
2269 ti.cbSize = sizeof(TOOLINFO);
2270 ti.uFlags = TTF_IDISHWND|TTF_CENTERTIP|TTF_SUBCLASS;
2271 ti.hwnd = hwndTB;;
2272 ti.uId = (UINT)hComboWnd;
2273 ti.lpszText = LPSTR_TEXTCALLBACK;
2274 hwndTT = (HWND)SendMessage(hwndTB,TB_GETTOOLTIPS,0,0);
2275 SendMessage(hwndTT,TTM_ADDTOOL,0,(LPARAM)&ti);
2276
2277 return hwndTB;
2278 }
2279
2280 static void
window_title(struct title_buf * tbuf)2281 window_title(struct title_buf *tbuf)
2282 {
2283 int res, i;
2284 size_t bufsz = TITLE_BUF_SZ;
2285 unsigned char charbuff[TITLE_BUF_SZ];
2286
2287 res = erl_drv_getenv("ERL_WINDOW_TITLE", charbuff, &bufsz);
2288 if (res < 0)
2289 tbuf->name = erlang_window_title;
2290 else if (res == 0) {
2291 for (i = 0; i < bufsz; ++i) {
2292 tbuf->buf[i] = charbuff[i];
2293 }
2294 tbuf->buf[bufsz - 1] = 0;
2295 tbuf->name = &tbuf->buf[0];
2296 } else {
2297 char *buf = ALLOC(bufsz);
2298 if (!buf)
2299 tbuf->name = erlang_window_title;
2300 else {
2301 while (1) {
2302 char *newbuf;
2303 res = erl_drv_getenv("ERL_WINDOW_TITLE", buf, &bufsz);
2304 if (res <= 0) {
2305 if (res == 0) {
2306 TCHAR *wbuf = ALLOC(bufsz *sizeof(TCHAR));
2307 for (i = 0; i < bufsz ; ++i) {
2308 wbuf[i] = buf[i];
2309 }
2310 wbuf[bufsz - 1] = 0;
2311 FREE(buf);
2312 tbuf->name = wbuf;
2313 } else {
2314 tbuf->name = erlang_window_title;
2315 FREE(buf);
2316 }
2317 break;
2318 }
2319 newbuf = REALLOC(buf, bufsz);
2320 if (newbuf)
2321 buf = newbuf;
2322 else {
2323 tbuf->name = erlang_window_title;
2324 FREE(buf);
2325 break;
2326 }
2327 }
2328 }
2329 }
2330 }
2331
2332 static void
free_window_title(struct title_buf * tbuf)2333 free_window_title(struct title_buf *tbuf)
2334 {
2335 if (tbuf->name != erlang_window_title && tbuf->name != &tbuf->buf[0])
2336 FREE(tbuf->name);
2337 }
2338