* Update configure script to remove the search for a linking tcl
[alpine.git] / pico / osdep / mswin.c
blobb84f4c4b8b91c5f08ec5665feec78f1b31531126
1 /*
2 * ========================================================================
3 * Copyright 2006-2007 University of Washington
4 * Copyright 2013-2018 Eduardo Chappa
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
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 #define WIN31
16 #define STRICT
18 #define termdef 1 /* don't define "term" external */
20 #include "../headers.h"
22 #include <stdarg.h>
23 #include <ddeml.h>
25 #include "mswin.h"
26 #include "resource.h"
28 #include "../../pith/osdep/pipe.h"
29 #include "../../pith/osdep/canaccess.h"
31 #include "../../pith/charconv/filesys.h"
32 #include "../../pith/charconv/utf8.h"
34 #include "../../pith/filttype.h"
35 #include "../../pith/osdep/color.h"
37 #include "mswin_tw.h"
39 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
41 * Defines
43 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
46 #define ICON
49 /* For debugging, export locals so debugger can see them. */
50 #ifdef DEBUG
51 #define LOCAL
52 #else
53 #define LOCAL static
54 #endif
58 * Define which debugging is desired. Generally only FDEBUG.
60 #define FDEBUG /* Standard file debugging. */
62 #undef SDEBUG /* Verbose debugging of startup and windows handling*/
63 #undef CDEBUG /* Verbose debugging of character input timeing. */
65 #undef OWN_DEBUG_FILE /* Define if we want to write to our own debug file,
66 * not pine's. */
69 /* Max size permitted for the screen. */
70 #define MAXNROW 200
71 #define MAXNCOLUMN NLINE
73 #define MINNROW 10 /* Minimum screen size */
74 #define MINNCOLUMN 32
76 #define MARGINE_LEFT 3
77 #define MARGINE_TOP 1
79 #define FRAME_3D_SIZE 1
81 #define WIN_MIN_X_SIZE 190 /* Minimum window size. */
82 #define WIN_MIN_Y_SIZE 180
84 #define WIN_X_BORDER_SIZE 8 /* Space taked by window frame. */
85 #define WIN_Y_BORDER_SIZE 65
87 #define FONT_MIN_SIZE 5
88 #define FONT_MAX_SIZE 21
90 #define PRINT_TAB_SIZE 8 /* Tab size used by print code. */
93 #define TB_HEIGHT 32 /* Tool Bar Height. */
94 #define TB_BUTTONHEIGHT 16 /* Button Height. */
95 #define TB_BUTTONSPACING 8 /* Space between buttons. */
98 /* Some string lengths. */
99 #define MAXLEN_TEMPSTR 256 /* Max size for temp storage. */
101 #define WIN_POS_STR_MAX_LEN 21 /* Max length for window-position
102 * string. */
104 #define MENU_ITEM_NAME_LEN 32 /* Menu item name lengths. */
107 /* Length of keyboard input queue. */
108 #define CHARACTER_QUEUE_LENGTH 32
109 #define MOUSE_QUEUE_LENGTH 32
111 /* Number of resize callback functions we can keep track of. */
112 #define RESIZE_CALLBACK_ARRAY_SIZE 3
114 /* Number of bytes held in the write accumulator. */
115 #define WRITE_ACCUM_SIZE 200
117 /* Max time that may pass between calls to GetMessage. See mswin_charavail()
119 #define GM_MAX_TIME 3000 /* In milliseconds.*/
121 /* My Timer Message */
122 #define MY_TIMER_ID 33
123 /* timeout period in miliseconds. */
124 #define MY_TIMER_PERIOD (UINT)((IDLE_TIMEOUT + 1)*1000)
125 /***** We use variable my_timer_period now instead so that we can set
126 it differently when in pine and when in regular old pico.
127 We're not entirely sure we need it in pico, but we will leave
128 it there because we don't understand.
129 *****/
130 #define MY_TIMER_SHORT_PERIOD (UINT)5000 /* used when there is a task in
131 the OnTask list. */
132 #define MY_TIMER_VERY_SHORT_PERIOD (UINT)500 /* used when SIGALRM and alarm()
133 is set. */
134 #define MY_TIMER_EXCEEDINGLY_SHORT_PERIOD (UINT)80 /* used when
135 gAllowMouseTracking is set */
137 #define TIMER_FAIL_MESSAGE TEXT("Failed to get all necessary Windows resources (timers). Alpine will run, but may not be able to keep the connection to the server alive. Quitting other applications and restarting Alpine may solve the problem.")
140 * Task bar notification Icon id and call back message for it.
142 #define TASKBAR_ICON_NEWMAIL 1
143 #define TASKBAR_ICON_MESSAGE WM_USER+1000
147 * Below here are fixed constancs that really should not be changed.
150 /* Auto Wrap States. */
151 #define WRAP_OFF 0 /* Never wrap to next line. */
152 #define WRAP_ON 1 /* Wrap to next line. */
153 #define WRAP_NO_SCROLL 2 /* Wrap to next line but DON'T scroll
154 screen to do it. */
155 /* Speicial keys in the Character Queue. */
156 #define CQ_FLAG_DOWN 0x01
157 #define CQ_FLAG_EXTENDED 0x02
158 #define CQ_FLAG_ALT 0x04
160 #define ARABIC_LRM 0x200E
161 #define ARABIC_RLM 0x200F
163 /* Special ASCII characters. */
164 #define ASCII_BEL 0x07
165 #define ASCII_BS 0x08
166 #define ASCII_TAB 0x09
167 #define ASCII_LF 0x0A
168 #define ASCII_CR 0x0D
169 #define ASCII_XON 0x11
170 #define ASCII_XOFF 0x13
172 /* Character Attributes. */
173 #define CHAR_ATTR_NORM 0x00 /* Normal. */
174 #define CHAR_ATTR_REV 0x01 /* Reverse Video. */
175 #define CHAR_ATTR_BOLD 0x02 /* Reverse Video. */
176 #define CHAR_ATTR_ULINE 0x04 /* Reverse Video. */
177 #define CHAR_ATTR_SEL 0x08 /* Selected text. */
178 #define CHAR_ATTR_NOT 0x80 /* No attributes. */
181 * Different applications that we know about.
183 #define APP_UNKNOWN 0
184 #define APP_PICO 1
185 #define APP_PICO_IDENT TEXT("pico")
186 #define APP_PINE 2
187 #define APP_PINE_IDENT TEXT("pine")
190 * Control values for call to AccelCtl.
192 /*#undef ACCELERATORS*/
193 #define ACCELERATORS
194 #define ACCEL_UNLOAD 0 /* Unload the accelerators. */
195 #define ACCEL_LOAD 1 /* Load the accelerators. */
196 #define ACCEL_TOGGLE 2 /* Toggle the accelerators. */
199 * flag bits to control which edit menu options can get lit
201 #define EM_NONE 0L
202 #define EM_CP 0x0001
203 #define EM_CP_APPEND 0x0002
204 #define EM_FIND 0x0004
205 #define EM_PST 0x0008
206 #define EM_PST_ABORT 0x0010
207 #define EM_CUT 0x0020
208 #define EM_SEL_ALL 0x0040
210 #define EM_MAX_ACCEL 6
212 /* Offsets to objects in window extra storage. */
213 #define GWL_PTTYINFO 0 /* Offset in Window extra storage. */
218 #define FONT_CHARSET_FONT DEFAULT_CHARSET
220 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
222 * Typedefs
224 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
226 /* Type that the screen array is made up of. */
227 #define CHAR unsigned char
229 /* define possible caret shapes */
230 typedef enum {
231 CaretBlock = 0,
232 CaretSmallBlock,
233 CaretHorizBar,
234 CaretVertBar
235 } CARETS;
237 /* Type that the attribute array is made up of. */
238 typedef struct _character_attribute {
239 unsigned style:8;
240 DWORD rgbFG, rgbBG;
241 } CharAttrib;
243 typedef int (*ResizeCallBackProc)();
244 typedef int (*FileDropCallBackProc)();
245 typedef short CORD;
247 /* NOTE: There is currently code that assumes that CHAR and CharAttrib
248 * are one byte in size. All this code is flaged with a preceeding
249 * assert () */
251 /* Struct that defines command menu entries. */
252 typedef struct tagMenuItem {
253 BOOL miActive;
254 UCS miKey;
255 short miIndex;
256 char *miLabel;
257 } MenuItem;
260 /* List of child window IDs and previous window procedures. */
261 typedef struct tagBtnList {
262 WORD wndID;
263 WNDPROC wndProc;
264 } BtnList;
267 /* General info. */
268 typedef struct tagTTYINFO {
269 TCHAR *pScreen; /* Screen. */
270 int *pCellWidth; /* how wide to paint the char */
271 CharAttrib *pAttrib; /* Attributes. */
272 TCHAR writeAccum[WRITE_ACCUM_SIZE];
273 int writeAccumCount;
274 CARETS cCaretStyle; /* Current caret's style */
275 int scrollRange; /* Current scroll bar range. */
276 long scrollPos; /* Current scroll position. */
277 long scrollTo; /* Possition of last scroll to. */
278 HFONT hTTYFont;
279 LOGFONT lfTTYFont;
280 DWORD rgbFGColor; /* Normal forground color. */
281 DWORD rgbBGColor; /* Normal background color. */
282 DWORD rgbRFGColor; /* Reverse forground color. */
283 DWORD rgbRBGColor; /* Reverse background color */
284 unsigned screenDirty:1; /* TRUE if screen needs update. */
285 unsigned eraseScreen:1; /* TRUE if need to erase whole screen */
286 unsigned fMinimized:1; /* True when window is minimized. */
287 unsigned fMaximized:1; /* True when window is maximized. */
288 unsigned fFocused:1; /* True when we have focus. */
289 unsigned fNewLine:1; /* Auto LF on CR. */
290 unsigned fMassiveUpdate:1;/* True when in Massive screen update. */
291 unsigned fNewMailIcon:1; /* True when new mail has arrived. */
292 unsigned fMClosedIcon:1; /* True when no mailbox is open. */
293 unsigned fCursorOn:1; /* True when cursor's shown */
294 unsigned fCaretOn:1; /* True if caret's displayed */
295 unsigned fTrayIcon:1; /* True if tool tray icon's on */
296 ResizeCallBackProc resizer[RESIZE_CALLBACK_ARRAY_SIZE];
297 FileDropCallBackProc dndhandler;
298 int autoWrap; /* Auto wrap to next line. */
299 CharAttrib curAttrib; /* Current character attributes. */
300 int actNRow, actNColumn; /* Actual number of rows and comumns
301 * displayed. */
302 CORD xSize, ySize; /* Size of screen in pixels */
303 CORD xScroll, yScroll; /* ?? */
304 CORD xOffset, yOffset; /* Offset from the left and top of
305 * window contents. */
306 CORD nColumn, nRow; /* Current position of cursor in
307 * cells. */
308 CORD xChar, yChar; /* Width of a char in pixels. */
309 int yCurOffset; /* offset of cursor Y-size */
310 CORD fDesiredSize; /* TRUE when there is a specific size
311 * the window should be expanded to
312 * after being minimized. */
313 CORD xDesPos, yDesPos; /* Desired position. */
314 CORD xDesSize, yDesSize; /* Desired window position. */
315 int curWinMenu; /* Current window menu. */
316 HACCEL hAccel; /* Handle to accelorator keys. */
317 UINT fAccel; /* vector of bound accelerator keys. */
318 CORD toolBarSize; /* Size of toolbar. */
319 BOOL toolBarTop; /* Toolbar on top? */
320 int curToolBarID;
321 BtnList *toolBarBtns;
322 HWND hTBWnd;
323 HBRUSH hTBBrush;
324 BOOL menuItemsCurrent;
325 BOOL noScrollUpdate;
326 BOOL scrollRangeChanged;
327 long noSUpdatePage;
328 long noSUpdateRange;
329 short menuItemsIndex;
330 MenuItem menuItems[KS_COUNT];
331 } TTYINFO, *PTTYINFO ;
334 #define MAXCLEN (MAX(MAXCOLORLEN,RGBLEN+1))
335 typedef struct MSWINColor {
336 char *colorName;
337 char *canonicalName;
338 COLORREF colorRef;
339 } MSWINColor;
342 typedef struct {
343 char *name;
344 CARETS style;
345 } MSWinCaret_t;
349 * Entry in the OnTask list. This is a list of actions to perform
350 * when a task exits. Currently, the only thing we do is delete
351 * files. if that changes this structure will get more complex.
353 * hTask == NULL means "This program" and can be used to arrange for
354 * deletion of files when this program exits.
356 typedef struct ontask {
357 struct ontask *next;
358 HTASK hTask;
359 char path[PATH_MAX+1];
360 } OnTaskItem;
362 typedef void (__cdecl *SignalType)(int);
364 typedef struct _iconlist {
365 HICON hIcon;
366 /* char path[PATH_MAX]; */
367 /* WORD index; */
368 int id;
369 short row;
370 struct _iconlist *next;
371 } IconList;
374 * char * array for printing registry settings.
376 typedef struct MSWR_LINE_BUFFER {
377 char **linep; /* store these as utf8, since that's what we have to pass back */
378 unsigned long size;
379 unsigned long offset;
380 } MSWR_LINE_BUFFER_S;
383 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
385 * Forward function declarations.
387 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
389 LOCAL void *
390 MyGetWindowLongPtr(HWND hwnd, int nIndex)
392 return (void *)(LONG_PTR)GetWindowLongPtr(hwnd, nIndex);
395 LOCAL LONG_PTR
396 MySetWindowLongPtr(HWND hwnd, int nIndex, void *NewLongPtr)
398 // warning C4244: 'function': conversion from 'LONG_PTR' to 'LONG',
399 // possible loss of data
400 #pragma warning(push)
401 #pragma warning(disable: 4244)
402 return SetWindowLongPtr(hwnd, nIndex, (LONG_PTR)NewLongPtr);
403 #pragma warning(pop)
406 #ifdef WIN32
407 #define GET_HINST( hWnd ) ((HINSTANCE) MyGetWindowLongPtr( hWnd, GWLP_HINSTANCE ))
408 #define GET_ID( hWnd ) (LOWORD(MyGetWindowLongPtr( hWnd, GWLP_ID )))
409 #else
410 #define GET_HINST( hWnd ) ((HINSTANCE) GetWindowWord( hWnd, GWW_HINSTANCE ))
411 #define GET_ID( hWnd ) ((WORD) GetWindowWord( hWnd, GWW_ID ))
412 #endif
414 #define CONSTRAIN(v,min,max) ((v) = (v) < (min) ? (min) : (v) > (max) ? (max) : (v))
417 /* function prototypes (private) */
418 int app_main (int argc, char *argv[]);
420 void WinExit (void);
422 LOCAL void mswin_invalidparameter(const wchar_t *, const wchar_t *,
423 const wchar_t *, unsigned int, uintptr_t);
425 LOCAL BOOL InitApplication (HANDLE);
426 LOCAL HWND InitInstance (HANDLE, int);
427 LOCAL void MakeArgv (HINSTANCE hInstance, LPSTR cmdLine, int *pargc,
428 CHAR ***pargv);
429 LOCAL LRESULT NEAR CreateTTYInfo (HWND hWnd);
430 LOCAL BOOL NEAR DestroyTTYInfo (HWND hWnd);
431 LOCAL int ResizeTTYScreen (HWND hWnd, PTTYINFO pTTYInfo,
432 int newNRow, int newNColumn);
433 LOCAL BOOL ResetTTYFont (HWND, PTTYINFO, LOGFONT *);
434 LOCAL BOOL EraseTTY (HWND, HDC);
435 LOCAL BOOL PaintTTY (HWND);
436 LOCAL BOOL GetMinMaxInfoTTY (HWND hWnd, MINMAXINFO __far *lpmmi);
437 LOCAL BOOL AboutToSizeTTY (HWND hWnd, WINDOWPOS *winPos);
438 LOCAL BOOL SizeTTY (HWND, int, CORD, CORD);
439 LOCAL BOOL SizingTTY (HWND hWnd, int fwSide, LPRECT pRect);
440 LOCAL void FrameRect3D(HDC hdc, RECT * pRC, int width, BOOL raised);
441 LOCAL void FillRectColor(HDC hDC, RECT * pRC, COLORREF color);
444 LOCAL BOOL MoveTTY (HWND hWnd, int xPos, int yPos);
445 LOCAL void ScrollTTY (HWND hWnd, int wScrollCode, int nPos, HWND hScroll);
446 LOCAL void CaretTTY (HWND hWnd, CARETS cStyle);
447 LOCAL void CaretCreateTTY (HWND hWnd);
448 #ifdef WIN32
449 LOCAL void MouseWheelTTY (HWND hWnd, int xPos, int yPos,
450 int fwKeys, int zDelta);
451 LOCAL void MouseWheelMultiplier ();
452 #endif
453 BOOL CALLBACK NoMsgsAreSent (void);
454 LOCAL BOOL SetTTYFocus (HWND);
455 LOCAL BOOL KillTTYFocus (HWND);
456 LOCAL BOOL MoveTTYCursor (HWND);
457 LOCAL BOOL ProcessTTYKeyDown (HWND hWnd, TCHAR bOut);
458 LOCAL BOOL ProcessTTYCharacter (HWND hWnd, TCHAR bOut);
459 LOCAL BOOL ProcessTTYMouse (HWND hWnd, int mevent, int button, CORD xPos,
460 CORD yPos, WPARAM keys);
461 LOCAL BOOL ProcessTTYFileDrop (HANDLE wParam);
462 LOCAL void ProcessTimer (void);
463 LOCAL BOOL WriteTTYBlock (HWND, LPTSTR, int);
464 LOCAL BOOL WriteTTYText (HWND, LPTSTR, int);
465 LOCAL BOOL WriteTTYChar (HWND, TCHAR);
467 LOCAL VOID GoModalDialogBoxParam (HINSTANCE, LPTSTR, HWND,
468 DLGPROC, LPARAM);
469 LOCAL BOOL SelectTTYFont (HWND);
470 LOCAL void SetColorAttribute (COLORREF *cf, char *colorName);
471 LOCAL void SetReverseColor (void);
472 LOCAL BOOL ConvertRGBString (char *colorName, COLORREF *cf);
473 LOCAL char *ConvertStringRGB (char *colorName, size_t ncolorName, COLORREF colorRef);
474 LOCAL BOOL ScanInt (char *str, int min, int max, int *val);
476 LOCAL void TBToggle (HWND);
477 LOCAL void TBPosToggle (HWND);
478 LOCAL void TBShow (HWND);
479 LOCAL void TBHide (HWND);
480 LOCAL void TBSwap (HWND, int);
481 LOCAL unsigned scrwidth(LPTSTR lpText, int nLength);
482 LOCAL long pscreen_offset_from_cord(int row, int col, PTTYINFO pTTYInfo);
484 LOCAL int tcsucmp(LPTSTR o, LPTSTR r);
485 LOCAL int _print_send_page(void);
487 /* defined in region.c */
488 int copyregion(int f, int n);
491 #ifdef ACCELERATORS
492 #ifdef ACCELERATORS_OPT
493 LOCAL void AccelCtl (HWND hWnd, int ctl, BOOL saveChange);
494 #endif
495 LOCAL void AccelManage (HWND hWnd, long accels);
496 LOCAL void UpdateAccelerators (HWND hWnd);
497 #endif
499 LOCAL UINT UpdateEditAllowed(HWND hWnd);
500 LOCAL void PopupConfig(HMENU hMenu, MPopup *members, int *n);
501 LOCAL MPopup *PopupId(MPopup *members, int id);
502 LOCAL BOOL CopyCutPopup (HWND hWnd, UINT fAllowed);
504 LOCAL void SelStart (int nRow, int nColumn);
505 LOCAL void SelFinish (int nRow, int nColumn);
506 LOCAL void SelClear (void);
507 LOCAL void SelTrackXYMouse (int xPos, int yPos);
508 LOCAL void SelTrackMouse (int nRow, int nColumn);
509 LOCAL BOOL SelAvailable (void);
510 LOCAL void SelDoCopy (HANDLE hCB, DWORD lenCB);
512 LOCAL void UpdateTrayIcon(DWORD dwMsg, HICON hIcon, LPTSTR tip);
514 LOCAL void FlushWriteAccum (void);
516 LOCAL int mswin_reg_lptstr(int, int, LPTSTR, size_t);
518 LOCAL BOOL MSWRPoke(HKEY hKey, LPTSTR subkey, LPTSTR valstr, LPTSTR data);
519 LOCAL int MSWRClear(HKEY hKey, LPTSTR pSubKey);
520 LOCAL void MSWRAlpineSet(HKEY hRootKey, LPTSTR subkey, LPTSTR val,
521 int update, LPTSTR data);
522 LOCAL int MSWRProtocolSet(HKEY hKey, int type, LPTSTR path_lptstr);
523 LOCAL void MSWRAlpineSetHandlers(int update, LPTSTR path);
524 LOCAL int MSWRAlpineGet(HKEY hKey, LPTSTR subkey, LPTSTR val,
525 LPTSTR data_lptstr, size_t len);
527 LOCAL void MSWIconAddList(int row, int id, HICON hIcon);
528 LOCAL int MSWIconPaint(int row, HDC hDC);
529 LOCAL void MSWIconFree(IconList **ppIcon);
530 LOCAL void MSWRLineBufAdd(MSWR_LINE_BUFFER_S *lpLineBuf, LPTSTR line);
531 LOCAL int MSWRDump(HKEY hKey, LPTSTR pSubKey, int keyDepth,
532 MSWR_LINE_BUFFER_S *lpLineBuf);
535 /* ... interface routines ... */
538 void ProcessMenuItem (HWND hWnd, WPARAM wParam);
540 void AlarmDeliver (void);
541 void HUPDeliver (void);
543 void PrintFontSameAs (HWND hWnd);
544 void PrintFontSelect (HWND hWnd);
545 void ExtractFontInfo(LOGFONT *pFont,
546 LPTSTR fontName, size_t nfontName,
547 int *fontSize,
548 LPTSTR fontStyle, size_t nfontStyle,
549 int ppi,
550 LPTSTR fontCharSet, size_t nfontCharSet);
552 LOCAL void DidResize (PTTYINFO pTTYInfo);
554 LOCAL void UpdateMenu (HWND hWnd);
555 LOCAL void EditCut (void);
556 LOCAL void EditCopy (void);
557 LOCAL void EditCopyAppend (void);
558 LOCAL void EditDoCopyData (HANDLE hCB, DWORD lenCB);
559 LOCAL void EditPaste (void);
560 LOCAL void EditCancelPaste (void);
561 LOCAL UCS EditPasteGet (void);
562 LOCAL BOOL EditPasteAvailable (void);
563 LOCAL void EditSelectAll (void);
565 LOCAL void MSWHelpShow (cbstr_t);
566 LOCAL int MSWHelpSetMenu (HMENU hmenu);
569 LOCAL void SortHandler (int order, int reverse);
570 LOCAL void FlagHandler (int order, int reverse);
572 LOCAL void MyTimerSet (void);
574 LOCAL LRESULT ConfirmExit (void);
576 LOCAL void CQInit (void);
577 LOCAL BOOL CQAvailable (void);
578 LOCAL BOOL CQAdd (UCS c, BOOL fKeyControlDown);
579 LOCAL BOOL CQAddUniq (UCS c, BOOL fKeyControlDown);
580 LOCAL UCS CQGet ();
582 LOCAL void MQInit (void);
583 LOCAL BOOL MQAvailable (void);
584 LOCAL BOOL MQAdd (int mevent, int button, int nRow, int nColumn,
585 int keys, int flags);
586 LOCAL BOOL MQGet (MEvent * pmouse);
587 LOCAL BOOL MQClear (int flag);
589 LOCAL UCS mswin_getc (void);
591 LOCAL DWORD ExplainSystemErr(void);
593 LOCAL void RestoreMouseCursor();
595 LOCAL BYTE mswin_string2charsetid(LPTSTR);
596 LOCAL int mswin_charsetid2string (LPTSTR fontCharSet,
597 size_t nfontCharSet, BYTE lfCharSet);
599 LOCAL int mswin_tw_init(MSWIN_TEXTWINDOW *mswin_tw, int id,
600 LPCTSTR title);
601 LOCAL MSWIN_TEXTWINDOW *mswin_tw_displaytext_lptstr (LPTSTR, LPTSTR, size_t,
602 LPTSTR *, MSWIN_TEXTWINDOW *mswin_tw,
603 int);
604 LOCAL void mswin_tw_print_callback(MSWIN_TEXTWINDOW *mswin_tw);
607 /* Functions exported to MS Windows. */
609 LRESULT FAR PASCAL __export PWndProc (HWND, UINT, WPARAM, LPARAM);
610 BOOL FAR PASCAL __export ToolBarProc (HWND, UINT, WPARAM, LPARAM);
611 LRESULT FAR PASCAL __export TBBtnProc (HWND, UINT, WPARAM, LPARAM);
612 BOOL FAR PASCAL __export AboutDlgProc (HWND, UINT, WPARAM, LPARAM);
613 BOOL FAR PASCAL __export SplashDlgProc (HWND, UINT, WPARAM, LPARAM);
615 LOCAL HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hconv,
616 HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
617 DWORD dwData1, DWORD dwData2);
619 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
621 * Module globals.
623 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
626 PTTYINFO gpTTYInfo;
627 HWND ghTTYWnd;
628 HINSTANCE ghInstance;
629 BOOL gfUseDialogs;
630 FILE *mswin_debugfile = NULL;
631 int mswin_debug = 0;
632 TCHAR gszAppName[45];
634 LOCAL TCHAR TempBuf [MAXLEN_TEMPSTR];
636 LOCAL TCHAR gszTTYClass[] = TEXT("PineWnd");
637 LOCAL int gAppIdent = APP_UNKNOWN;
639 LOCAL int gNMW_width;
641 LOCAL HCURSOR ghCursorArrow = NULL;
642 LOCAL HCURSOR ghCursorBusy = NULL;
643 LOCAL HCURSOR ghCursorIBeam = NULL;
644 LOCAL HCURSOR ghCursorHand = NULL;
645 LOCAL HCURSOR ghCursorCurrent = NULL;
647 LOCAL HWND ghSplashWnd = NULL;
649 LOCAL COLOR_PAIR *the_rev_color, *the_normal_color;
651 /* Used for Pasting text. */
652 LOCAL HANDLE ghPaste = NULL; /* Handle to Paste data. */
653 LOCAL TCHAR *gpPasteNext = NULL; /* Pointer to current char. */
654 LOCAL size_t gPasteBytesRemain = 0; /* Count of bytes left. */
655 LOCAL BOOL gPasteWasCR = FALSE; /* Previous char was CR. */
656 LOCAL int gPasteEnabled = MSWIN_PASTE_DISABLE;
657 LOCAL getc_t gCopyCutFunction = NULL;
658 LOCAL cbarg_t gScrollCallback = NULL;
659 LOCAL BOOL gScrolling = FALSE; /* Keeps track of when we are
660 * in scroll routine. */
661 LOCAL cbarg_t gSortCallback = NULL;
662 LOCAL cbarg_t gFlagCallback = NULL;
663 LOCAL cbarg_t gHdrCallback = NULL;
664 LOCAL cbarg_t gZoomCallback = NULL;
665 LOCAL cbarg_t gFkeyCallback = NULL;
666 LOCAL cbarg_t gSelectedCallback = NULL;
667 LOCAL BOOL gMouseTracking = FALSE; /* Keeps track of when we are
668 * tracking the mouse. */
669 LOCAL FARPROC gWSBlockingProc = NULL;
670 LOCAL DLGPROC gToolBarProc = NULL;
671 LOCAL WNDPROC gTBBtnProc = NULL;
673 LOCAL BOOL gAllowCopy = FALSE;
674 LOCAL BOOL gAllowCut = FALSE;
676 LOCAL BOOL gAllowMouseTrack = FALSE;/* Upper layer interested in
677 * mouse tracking. */
678 LOCAL short gsMWMultiplier;
679 LOCAL MEvent gMTEvent;
681 LOCAL cbstr_t gHelpGenCallback = NULL;
682 LOCAL BOOL gfHelpGenMenu = FALSE; /* TRUE when help menu
683 * installed. */
684 LOCAL cbstr_t gHelpCallback = NULL;
685 LOCAL BOOL gfHelpMenu = FALSE; /* TRUE when help menu
686 * installed. */
687 LOCAL char *gpCloseText;
689 LOCAL DWORD gGMLastCall = 0; /* Last time I called
690 * GetMessage. */
691 LOCAL BOOL gConfirmExit = FALSE;
692 LOCAL HICON ghNormalIcon = NULL;
693 LOCAL HICON ghNewMailIcon = NULL;
694 LOCAL HICON ghMClosedIcon = NULL;
696 LOCAL int gPrintFontSize;
697 LOCAL TCHAR gPrintFontName[LF_FACESIZE];
698 LOCAL TCHAR gPrintFontStyle[64];
699 LOCAL TCHAR gPrintFontCharSet[256];
700 LOCAL BOOL gPrintFontSameAs = TRUE;
702 LOCAL UINT gTimerCurrentPeriod = 0;
704 LOCAL cbvoid_t gPeriodicCallback = NULL; /* Function to call. */
705 LOCAL DWORD gPeriodicCBTimeout = 0; /* Time of next call. */
706 LOCAL DWORD gPeriodicCBTime = 0; /* Delay between calls. */
708 //=========================================================================
709 // n
710 //=========================================================================
711 MSWIN_TEXTWINDOW gMswinAltWin = {0};
712 MSWIN_TEXTWINDOW gMswinNewMailWin = {0};
714 MSWIN_TEXTWINDOW gMswinIMAPTelem = {0};
715 LOCAL cbvoid_t gIMAPDebugONCallback = NULL;
716 LOCAL cbvoid_t gIMAPDebugOFFCallback = NULL;
717 LOCAL cbvoid_t gEraseCredsCallback = NULL;
718 LOCAL cbvoid_t gViewInWindCallback = NULL;
720 LOCAL cbvoid_t gConfigScreenCallback = NULL;
722 LOCAL cbarg_t gMouseTrackCallback = NULL;
724 /* Currently only implement one SIGNAL so only need single variable. */
725 LOCAL SignalType gSignalAlarm = SIG_DFL;
726 LOCAL DWORD gAlarmTimeout = 0; /* Time alarm expires in
727 * seconds
728 * (GetTickCount()/1000) */
729 LOCAL SignalType gSignalHUP = SIG_DFL;
731 LOCAL IconList *gIconList = NULL;
735 * There is some coordination between these names and the similar names
736 * in osdep/unix. The names in the left column are mapped to the colors
737 * in the right column when displaying. Note that the last eight colors map
738 * to the same thing as the 1st eight colors. This is an attempt to inter-
739 * operate with 16-color xterms. When editing a color and writing the color
740 * into the config file, we use the canonical_name (middle column). So if
741 * the user chooses green from the menu we write color010 in the config
742 * file. [This has changed. Now we put the RGB value in the config file
743 * instead. We leave this so that we can interpret color010 in the config
744 * file from old versions of pine.]
745 * We display that as green later. The xterm also displays that as
746 * green, because the bright green (color010) on the xterm is what we want
747 * to consider to be green, and the other one (color002) is dark green.
748 * And dark green sucks.
749 * On the PC we only use the first 11 colors in this table when giving the
750 * user the set color display, since the last eight are repeats.
752 LOCAL MSWINColor MSWINColorTable[] = {
753 "black", "000,000,000", RGB(0,0,0),
754 "red", "255,000,000", RGB(255,0,0),
755 "green", "000,255,000", RGB(0,255,0),
756 "yellow", "255,255,000", RGB(255,255,0),
757 "blue", "000,000,255", RGB(0,0,255),
758 "magenta", "255,000,255", RGB(255,0,255),
759 "cyan", "000,255,255", RGB(0,255,255),
760 "white", "255,255,255", RGB(255,255,255),
761 "colorlgr", "192,192,192", RGB(192,192,192), /* lite gray */
762 "colormgr", "128,128,128", RGB(128,128,128), /* med. gray */
763 "colordgr", "064,064,064", RGB(64,64,64), /* dark gray */
764 "color008", "000,000,000", RGB(0,0,0),
765 "color009", "255,000,000", RGB(255,0,0),
766 "color010", "000,255,000", RGB(0,255,0),
767 "color011", "255,255,000", RGB(255,255,0),
768 "color012", "000,000,255", RGB(0,0,255),
769 "color013", "255,000,255", RGB(255,0,255),
770 "color014", "000,255,255", RGB(0,255,255),
771 "color015", "255,255,255", RGB(255,255,255),
772 NULL, NULL, 0
775 #define fullColorTableSize ((sizeof(MSWINColorTable) / sizeof(MSWINColorTable[0])) - 1)
776 #define visibleColorTableSize (fullColorTableSize - 8)
779 LOCAL MSWinCaret_t MSWinCaretTable[] = {
780 "Block", CaretBlock,
781 "ShortBlock", CaretSmallBlock,
782 "Underline", CaretHorizBar,
783 "VertBar", CaretVertBar,
784 NULL, 0
788 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
790 * Windows Functions.
792 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
794 /*---------------------------------------------------------------------------
795 * int PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInstance,
796 * LPSTR lpszCmdLine, int nCmdShow )
798 * Description:
799 * This is the main window loop!
801 * Parameters:
802 * As documented for all WinMain() functions.
804 *--------------------------------------------------------------------------*/
805 int PASCAL
806 wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
807 LPTSTR lpszCmdLine, int nCmdShow )
809 CHAR **argv;
810 int argc, i, nosplash = 0;
811 char *cmdline_utf8;
813 ghInstance = hInstance;
814 if (!hPrevInstance)
815 if (!InitApplication( hInstance ))
816 return ( FALSE ) ;
819 * Instead of crashing into Dr. Watson on invalid parameter calls
820 * into the C library, just return the error indication that these
821 * functions are normally expected to return.
823 _set_invalid_parameter_handler (mswin_invalidparameter);
825 #ifdef OWN_DEBUG_FILE /* Want to write to seperate memdebug.txt file. */
826 mswin_debugfile = fopen ("memdebug.txt", "w");
827 fprintf (mswin_debugfile, "Beginning of mswin debug log\n");
828 if (mswin_debugfile != NULL) {
829 mswin_debug = 4;
830 MemDebug (mswin_debug, mswin_debugfile);
831 fprintf (mswin_debugfile, "Show window as: %d\n", nCmdShow);
832 fflush (mswin_debugfile);
834 #endif
836 if (NULL == (ghTTYWnd = InitInstance (hInstance, nCmdShow)))
837 return (FALSE);
839 /* cmdline_utf8 memory is never freed */
840 cmdline_utf8 = lptstr_to_utf8(lpszCmdLine);
842 MakeArgv (hInstance, cmdline_utf8, &argc, &argv);
844 for(i = 0; i < argc; i++)
845 if(strcmp((const char *)argv[i], "-nosplash") == 0){
846 nosplash = 1;
847 break;
849 /* Create Splash window */
850 if(nosplash == 0){
851 ghSplashWnd = CreateDialog(hInstance,
852 MAKEINTRESOURCE( SPLASHDLGBOX ),
853 ghTTYWnd, (DLGPROC)SplashDlgProc);
854 ShowWindow (ghSplashWnd, SW_SHOWNORMAL);
857 atexit (WinExit);
859 app_main (argc, (char **)argv);
861 return (TRUE);
865 LOCAL void
866 mswin_invalidparameter(const wchar_t *expression,
867 const wchar_t *function,
868 const wchar_t *file,
869 unsigned int line,
870 uintptr_t reserved)
872 /* do nothing for now */
876 void
877 WinExit (void)
879 MSG msg;
881 if (ghTTYWnd == NULL)
882 return;
884 UpdateTrayIcon(NIM_DELETE, 0, NULL);
886 /* Destroy main window and process remaining events. */
887 DestroyWindow (ghTTYWnd);
888 while (GetMessage (&msg, NULL, 0, 0)) {
889 TranslateMessage (&msg);
890 DispatchMessage (&msg);
893 #ifdef OWN_DEBUG_FILE
894 fclose (mswin_debugfile);
895 #endif
896 if (gWSBlockingProc != NULL)
897 FreeProcInstance (gWSBlockingProc);
899 MemFreeAll ();
900 ghTTYWnd = NULL;
904 /*---------------------------------------------------------------------------
905 * BOOL InitApplication( HANDLE hInstance )
907 * Description:
908 * First time initialization stuff. This registers information
909 * such as window classes.
911 * Parameters:
912 * HANDLE hInstance
913 * Handle to this instance of the application.
915 *--------------------------------------------------------------------------*/
916 LOCAL BOOL
917 InitApplication (HANDLE hInstance)
919 WNDCLASS wndclass;
922 * Register tty window class.
924 wndclass.style = 0; /* CS_NOCLOSE; */
925 wndclass.lpfnWndProc = PWndProc;
926 wndclass.cbClsExtra = 0;
927 wndclass.cbWndExtra = sizeof (LONG);
928 wndclass.hInstance = hInstance ;
929 /* In win16 we paint our own icon. */
930 wndclass.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (ALPINEICON));
931 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
932 wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
933 wndclass.lpszMenuName = MAKEINTRESOURCE (ALPINEMENU);
934 wndclass.lpszClassName = gszTTYClass ;
936 return (RegisterClass (&wndclass));
940 /*---------------------------------------------------------------------------
941 * HWND InitInstance( HANDLE hInstance, int nCmdShow )
943 * Description:
944 * Initializes instance specific information.
946 * Parameters:
947 * HANDLE hInstance
948 * Handle to instance
950 * int nCmdShow
951 * How do we show the window?
953 /*--------------------------------------------------------------------------*/
954 LOCAL HWND
955 InitInstance (HANDLE hInstance, int nCmdShow)
957 HWND hTTYWnd;
958 TCHAR appIdent[32];
959 SCROLLINFO scrollInfo;
961 #ifdef SDEBUG
962 if (mswin_debug >= 5)
963 fprintf (mswin_debugfile, "InitInstance::: entered, nCmdShow %d\n",
964 nCmdShow);
965 #endif
967 LoadString (hInstance, IDS_APPNAME, gszAppName, sizeof(gszAppName) / sizeof(TCHAR));
969 /* create the TTY window */
970 hTTYWnd = CreateWindow (gszTTYClass, gszAppName,
971 WS_OVERLAPPEDWINDOW | WS_VSCROLL,
972 CW_USEDEFAULT, CW_USEDEFAULT,
973 CW_USEDEFAULT, CW_USEDEFAULT,
974 HWND_DESKTOP, NULL, hInstance, NULL);
976 scrollInfo.cbSize = sizeof(SCROLLINFO);
977 scrollInfo.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_RANGE | SIF_POS;
978 scrollInfo.nMin = 0;
979 scrollInfo.nMax = 1;
980 scrollInfo.nPage = 1;
981 scrollInfo.nPos = 0;
982 SetScrollInfo(hTTYWnd, SB_VERT, &scrollInfo, FALSE);
983 EnableScrollBar (hTTYWnd, SB_VERT, ESB_DISABLE_BOTH);
985 if (NULL == hTTYWnd)
986 return (NULL);
988 ghTTYWnd = hTTYWnd;
990 ghNormalIcon = LoadIcon (hInstance, MAKEINTRESOURCE (ALPINEICON));
991 ghNewMailIcon = LoadIcon (hInstance, MAKEINTRESOURCE (NEWMAILICON));
992 ghMClosedIcon = LoadIcon (hInstance, MAKEINTRESOURCE (MCLOSEDICON));
994 ghCursorArrow = LoadCursor (NULL, IDC_ARROW);
995 ghCursorBusy = LoadCursor (NULL, IDC_WAIT);
996 ghCursorIBeam = LoadCursor (NULL, IDC_IBEAM);
997 #ifdef IDC_HAND
998 ghCursorHand = LoadCursor (NULL, IDC_HAND);
999 #else
1000 ghCursorHand = LoadCursor (hInstance, MAKEINTRESOURCE( PICOHAND ));
1001 #endif
1002 ghCursorCurrent = ghCursorArrow;
1004 MouseWheelMultiplier();
1006 CQInit ();
1007 MQInit ();
1011 * Load a resource with the name of the application. Compare to
1012 * known applications to determine who we are running under.
1013 * currently, only differentiation is the WINSOCK blocking hook.
1015 LoadString (hInstance, IDS_APPIDENT, appIdent, sizeof(appIdent) / sizeof(TCHAR));
1016 if (_tcscmp (appIdent, APP_PINE_IDENT) == 0) {
1017 gAppIdent = APP_PINE;
1018 gWSBlockingProc = MakeProcInstance ( (FARPROC) NoMsgsAreSent,
1019 hInstance);
1021 else if (_tcscmp (appIdent, APP_PICO_IDENT) == 0)
1022 gAppIdent = APP_PICO;
1023 else
1024 gAppIdent = APP_UNKNOWN;
1027 return (hTTYWnd);
1031 /*---------------------------------------------------------------------------
1032 * void MakeArgv ()
1034 * Description:
1035 * Build a standard C argc, argv pointers into the command line string.
1038 * Parameters:
1039 * cmdLine - Command line.
1040 * *argc - Count of words.
1041 * ***argc - Pointer to Pointer to array of pointers to
1042 * characters.
1044 *--------------------------------------------------------------------------*/
1045 LOCAL void
1046 MakeArgv (HINSTANCE hInstance, char *cmdLine_utf8, int *pargc, CHAR ***pargv)
1048 CHAR **argv;
1049 LPSTR c;
1050 BOOL inWord, inQuote;
1051 int wordCount;
1052 #define CMD_PATH_LEN 128
1053 LPTSTR modPath_lptstr;
1054 DWORD mpLen;
1057 /* Count words in cmdLine. */
1058 wordCount = 0;
1059 inWord = FALSE;
1060 inQuote = FALSE;
1061 for (c = cmdLine_utf8; *c != '\0'; ++c) {
1062 if (inQuote) {
1063 if(*c == '"' && (*(c+1) == ' ' || *(c+1) == '\t' || *(c+1) == '\0')){
1064 inQuote = inWord = FALSE;
1067 else {
1068 if(inWord && (*c == ' ' || *c == '\t' || *c == '\0')){
1069 inWord = FALSE;
1071 else if(!inWord && (*c != ' ' && *c != '\t')){
1072 inWord = TRUE;
1073 wordCount++;
1074 if(*c == '"')
1075 inQuote = TRUE;
1080 ++wordCount; /* One for program name. */
1081 argv = (CHAR **) MemAlloc (sizeof (CHAR *) * (wordCount + 1));
1082 *pargv = argv;
1083 *pargc = wordCount;
1085 modPath_lptstr = (LPTSTR) MemAlloc (CMD_PATH_LEN*sizeof(TCHAR));
1086 mpLen = GetModuleFileName (hInstance, modPath_lptstr, CMD_PATH_LEN);
1087 if (mpLen > 0) {
1088 *(modPath_lptstr + mpLen) = '\0';
1089 *(argv++) = (unsigned char *)lptstr_to_utf8(modPath_lptstr);
1091 else
1092 *(argv++) = (unsigned char *)"Alpine/Pico";
1094 MemFree((void *)modPath_lptstr);
1096 /* Now break up command line. */
1097 inWord = FALSE;
1098 inQuote = FALSE;
1099 for (c = cmdLine_utf8; *c != '\0'; ++c) {
1100 if (inQuote) {
1101 if(*c == '"' && (*(c+1) == ' ' || *(c+1) == '\t' || *(c+1) == '\0')){
1102 inQuote = inWord = FALSE;
1103 *c = '\0';
1106 else {
1107 if(inWord && (*c == ' ' || *c == '\t' || *c == '\0')){
1108 *c = '\0';
1109 inWord = FALSE;
1111 else if(!inWord && (*c != ' ' && *c != '\t')){
1112 inWord = TRUE;
1113 if(*c == '"'){
1114 inQuote = TRUE;
1115 *(argv++) = (unsigned char *)c+1;
1117 else
1118 *(argv++) = (unsigned char *)c;
1123 *argv = NULL; /* tie off argv */
1127 /*---------------------------------------------------------------------------
1128 * LRESULT FAR PASCAL __export PWndProc( HWND hWnd, UINT uMsg,
1129 * WPARAM wParam, LPARAM lParam )
1131 * Description:
1132 * This is the TTY Window Proc. This handles ALL messages
1133 * to the tty window.
1135 * Parameters:
1136 * As documented for Window procedures.
1138 /*--------------------------------------------------------------------------*/
1139 LRESULT FAR PASCAL __export
1140 PWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1142 #ifdef CDEBUG
1143 if (mswin_debug > 12) {
1144 fprintf (mswin_debugfile, "PWndProc:: uMsg = 0x%x\n", uMsg);
1145 fflush (mswin_debugfile);
1147 #endif
1148 switch (uMsg) {
1149 case WM_CREATE:
1150 MyTimerSet ();
1151 return (CreateTTYInfo (hWnd));
1153 case WM_COMMAND:
1154 switch ((WORD) wParam) {
1156 case IDM_OPT_SETFONT:
1157 SelectTTYFont (hWnd);
1158 break ;
1160 case IDM_OPT_FONTSAMEAS:
1161 PrintFontSameAs (hWnd);
1162 break;
1164 case IDM_OPT_TOOLBAR:
1165 TBToggle (hWnd);
1166 break;
1168 case IDM_OPT_TOOLBARPOS:
1169 TBPosToggle (hWnd);
1170 break;
1172 case IDM_OPT_USEDIALOGS: {
1173 PTTYINFO pTTYInfo;
1175 gfUseDialogs = !gfUseDialogs;
1176 pTTYInfo = (PTTYINFO)(LONG_PTR)MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
1177 if (pTTYInfo)
1178 DidResize (pTTYInfo);
1179 break;
1182 case IDM_OPT_ERASE_CREDENTIALS:
1183 if(gEraseCredsCallback)
1184 (*gEraseCredsCallback)();
1185 break;
1187 case IDM_MI_VIEWINWIND:
1188 if(gViewInWindCallback)
1189 (*gViewInWindCallback)();
1190 break;
1192 case IDM_OPT_IMAPTELEM:
1193 mswin_tw_init(&gMswinIMAPTelem, (int)LOWORD(wParam),
1194 TEXT("IMAP Telemetry"));
1195 SetFocus (ghTTYWnd);
1196 break;
1198 case IDM_OPT_NEWMAILWIN:
1199 mswin_tw_init(&gMswinNewMailWin, (int)LOWORD(wParam),
1200 TEXT("New Mail View"));
1201 SetFocus (ghTTYWnd);
1202 break;
1204 #ifdef ACCELERATORS_OPT
1205 case IDM_OPT_USEACCEL:
1206 AccelCtl (hWnd, ACCEL_TOGGLE, TRUE);
1207 break;
1208 #endif
1210 case IDM_OPT_SETPRINTFONT:
1211 PrintFontSelect (hWnd);
1212 break;
1214 case IDM_OPT_CARETBLOCK :
1215 CaretTTY(hWnd, CaretBlock);
1216 break;
1218 case IDM_OPT_CARETSMALLBLOCK :
1219 CaretTTY(hWnd, CaretSmallBlock);
1220 break;
1222 case IDM_OPT_CARETVBAR :
1223 CaretTTY(hWnd, CaretVertBar);
1224 break;
1226 case IDM_OPT_CARETHBAR :
1227 CaretTTY(hWnd, CaretHorizBar);
1228 break;
1230 case IDM_ABOUT:
1231 GoModalDialogBoxParam ( GET_HINST( hWnd ),
1232 MAKEINTRESOURCE( ABOUTDLGBOX ),
1233 hWnd,
1234 (DLGPROC)AboutDlgProc, (LPARAM) 0 ) ;
1235 break;
1237 case IDM_EDIT_CUT:
1238 EditCut ();
1239 break;
1241 case IDM_EDIT_COPY:
1242 EditCopy ();
1243 break;
1245 case IDM_EDIT_COPY_APPEND:
1246 EditCopyAppend ();
1247 break;
1249 case IDM_EDIT_PASTE:
1250 EditPaste ();
1251 #ifdef ACCELERATORS
1252 UpdateAccelerators (hWnd);
1253 #endif
1254 break;
1256 case IDM_EDIT_CANCEL_PASTE:
1257 EditCancelPaste ();
1258 #ifdef ACCELERATORS
1259 UpdateAccelerators (hWnd);
1260 #endif
1261 break;
1263 case IDM_EDIT_SEL_ALL :
1264 EditSelectAll();
1265 break;
1267 case IDM_HELP:
1268 MSWHelpShow (gHelpCallback);
1269 break;
1271 case IDM_MI_GENERALHELP:
1272 MSWHelpShow (gHelpGenCallback);
1273 break;
1275 case IDM_MI_WHEREIS :
1276 CQAdd (gpTTYInfo->menuItems[KS_WHEREIS - KS_RANGESTART].miKey, 0);
1277 break;
1279 case IDM_MI_SORTSUBJECT :
1280 case IDM_MI_SORTARRIVAL :
1281 case IDM_MI_SORTSIZE :
1282 case IDM_MI_SORTFROM :
1283 case IDM_MI_SORTTO :
1284 case IDM_MI_SORTCC :
1285 case IDM_MI_SORTDATE :
1286 case IDM_MI_SORTORDERSUB :
1287 case IDM_MI_SORTSCORE :
1288 case IDM_MI_SORTTHREAD :
1289 SortHandler((int)(wParam - IDM_MI_SORTSUBJECT), 0);
1290 break;
1292 case IDM_MI_SORTREVERSE :
1293 SortHandler(-1, 1);
1294 break;
1296 case IDM_MI_FLAGIMPORTANT :
1297 case IDM_MI_FLAGNEW :
1298 case IDM_MI_FLAGANSWERED :
1299 case IDM_MI_FLAGDELETED :
1300 FlagHandler((int)(wParam - IDM_MI_FLAGIMPORTANT), 0);
1301 break;
1303 default:
1304 /* value falling within the menu item range are handled here. */
1305 if (wParam >= KS_RANGESTART && wParam <= KS_RANGEEND){
1306 ProcessMenuItem (hWnd, wParam);
1307 break;
1309 break;
1311 break ;
1313 case WM_VSCROLL:
1314 ScrollTTY (hWnd, LOWORD(wParam), HIWORD(wParam), (HWND) lParam);
1315 break;
1317 case WM_MOUSEWHEEL:
1318 MouseWheelTTY (hWnd, LOWORD(lParam), HIWORD(lParam),
1319 LOWORD(wParam), (short) HIWORD(wParam));
1320 break;
1322 case WM_ERASEBKGND:
1323 if (IsIconic (hWnd))
1324 return (DefWindowProc (hWnd, WM_ICONERASEBKGND, wParam, lParam));
1325 else
1326 EraseTTY (hWnd, (HDC) wParam);
1327 break;
1329 case WM_QUERYDRAGICON:
1330 return ((LRESULT)ghNormalIcon);
1332 case WM_PAINT:
1333 PaintTTY (hWnd);
1334 break ;
1336 case WM_GETMINMAXINFO:
1337 GetMinMaxInfoTTY (hWnd, (MINMAXINFO __far *)lParam);
1338 break;
1340 case WM_SIZE:
1341 SizeTTY (hWnd, (int)wParam, HIWORD(lParam), LOWORD(lParam));
1342 break ;
1344 case WM_SIZING :
1345 return(SizingTTY(hWnd, (int)wParam, (LPRECT) lParam));
1347 case WM_MOVE:
1348 /* MoveTTY (hWnd, (int) LOWORD(lParam), (int) HIWORD(lParam)); */
1349 break;
1351 case WM_WINDOWPOSCHANGING:
1352 /* Allows us to adjust new size of window. */
1353 AboutToSizeTTY (hWnd, (WINDOWPOS FAR *) lParam);
1354 break;
1357 case TASKBAR_ICON_MESSAGE:
1358 /* Notification of a mouse event in the task bar tray.
1359 * If they are clicking on it we will restore the window. */
1360 if (lParam == WM_LBUTTONDOWN){
1361 if(gpTTYInfo->fMinimized)
1362 ShowWindow (hWnd, SW_RESTORE);
1363 else
1364 SetForegroundWindow(hWnd);
1367 break;
1371 * WM_KEYDOWN is sent for every "key press" and reports on the
1372 * keyboard key, with out processing shift and control keys.
1373 * WM_CHAR is a synthetic event, created from KEYDOWN and KEYUP
1374 * events. It includes processing or control and shift characters.
1375 * But does not get generated for extended keys suchs as arrow
1376 * keys.
1377 * I'm going to try to use KEYDOWN for processing just extended keys
1378 * and let CHAR handle the the rest.
1380 * The only key combo that is special is ^-space. For that, I'll use
1381 * WM_KEYDOWN and WM_KEYUP to track the state of the control key.
1383 case WM_CHAR:
1385 * If the windows cursor is visible and we have keyboard input
1386 * then hide the windows cursor
1388 mswin_showcursor(FALSE);
1389 ProcessTTYCharacter (hWnd, (TCHAR)wParam);
1390 break ;
1392 case WM_KEYDOWN:
1393 if (ProcessTTYKeyDown (hWnd, (TCHAR) wParam))
1394 return (0);
1396 return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
1398 case WM_SYSCHAR:
1399 if (gFkeyCallback && (*gFkeyCallback)(0, 0)
1400 && LOBYTE (wParam) == VK_F10){
1401 ProcessTTYCharacter (hWnd, (TCHAR)wParam);
1402 return (0);
1405 return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
1407 case WM_SYSKEYDOWN:
1409 * lParam specifies the context code. Bit 29 is 1 if the ALT key is down
1410 * while the key is pressed.
1412 if (!(lParam & (1<<29))
1413 && gFkeyCallback && (*gFkeyCallback)(0, 0)
1414 && LOBYTE (wParam) == VK_F10
1415 && ProcessTTYKeyDown (hWnd, (TCHAR) wParam))
1416 return (0);
1418 return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
1421 case WM_LBUTTONDOWN:
1422 ProcessTTYMouse (hWnd, M_EVENT_DOWN, M_BUTTON_LEFT, LOWORD (lParam),
1423 HIWORD (lParam), wParam);
1424 break;
1426 case WM_LBUTTONUP:
1427 if (ProcessTTYMouse (hWnd, M_EVENT_UP, M_BUTTON_LEFT, LOWORD (lParam),
1428 HIWORD (lParam), wParam))
1429 goto callDef;
1430 break;
1432 case WM_MBUTTONDOWN:
1433 ProcessTTYMouse (hWnd, M_EVENT_DOWN, M_BUTTON_MIDDLE, LOWORD (lParam),
1434 HIWORD (lParam), wParam);
1435 break;
1437 case WM_MBUTTONUP:
1438 ProcessTTYMouse (hWnd, M_EVENT_UP, M_BUTTON_MIDDLE, LOWORD (lParam),
1439 HIWORD (lParam), wParam);
1440 break;
1442 case WM_RBUTTONDOWN:
1443 ProcessTTYMouse (hWnd, M_EVENT_DOWN, M_BUTTON_RIGHT, LOWORD (lParam),
1444 HIWORD (lParam), wParam);
1445 break;
1447 case WM_RBUTTONUP:
1448 ProcessTTYMouse (hWnd, M_EVENT_UP, M_BUTTON_RIGHT, LOWORD (lParam),
1449 HIWORD (lParam), wParam);
1450 break;
1452 case WM_MOUSEMOVE:
1453 ProcessTTYMouse (hWnd, M_EVENT_TRACK, 0, LOWORD (lParam),
1454 HIWORD (lParam), wParam);
1455 break;
1457 case WM_NCMOUSEMOVE:
1458 mswin_showcursor(TRUE);
1459 goto callDef; /* pretend it never happened */
1461 case WM_SETFOCUS:
1462 SetTTYFocus (hWnd);
1463 break;
1465 case WM_KILLFOCUS:
1466 KillTTYFocus (hWnd);
1467 break;
1469 case WM_SETCURSOR:
1470 /* Set cursor. If in client, leave as is. Otherwise, pass to
1471 * DefWindow Proc */
1472 if (LOWORD(lParam) == HTCLIENT) {
1473 SetCursor (ghCursorCurrent);
1474 return (TRUE);
1477 return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
1479 case WM_INITMENU:
1480 UpdateMenu (hWnd);
1481 break;
1483 case WM_TIMER:
1484 /* Really just used so that we continue to receive messages even while
1485 * in background. Causes mswin_getc() to process message and return
1486 * to caller so that it can get some periodic processing in. */
1487 ProcessTimer ();
1488 break;
1490 case WM_QUERYENDSESSION:
1491 /* Returns non-zero if I can exit, otherwize zero, and the end
1492 * session operation stops. */
1493 return ((LRESULT)ConfirmExit ());
1495 case WM_DESTROY:
1496 KillTimer (hWnd, MY_TIMER_ID);
1497 DestroyTTYInfo (hWnd);
1498 PostQuitMessage (0);
1499 break;
1502 case WM_DROPFILES:
1503 if(ProcessTTYFileDrop((HANDLE) wParam) == TRUE)
1504 SetForegroundWindow(hWnd);
1506 break;
1509 case WM_CLOSE:
1510 /* If the quit menu is active then insert the quit command
1511 * Otherwise, abort. */
1512 if (gpTTYInfo->menuItems[KS_EXIT - KS_RANGESTART].miActive) {
1513 CQAdd (gpTTYInfo->menuItems[KS_EXIT - KS_RANGESTART].miKey, 0);
1515 else if (gSignalHUP != SIG_DFL && gSignalHUP != SIG_IGN) {
1516 if (MessageBox (hWnd,
1517 TEXT("Abort PINE/PICO, possibly losing current work?"),
1518 gszAppName, MB_OKCANCEL | MB_ICONQUESTION) == IDOK)
1519 HUPDeliver ();
1521 break;
1524 default:
1525 callDef:
1526 return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
1528 return 0L ;
1530 } /* end of PWndProc() */
1533 /*---------------------------------------------------------------------------
1534 * LRESULT NEAR CreateTTYInfo( HWND hWnd )
1536 * Description:
1537 * Creates the tty information structure and sets
1538 * menu option availability. Returns -1 if unsuccessful.
1540 * Parameters:
1541 * HWND hWnd
1542 * Handle to main window.
1544 *-------------------------------------------------------------------------*/
1545 LOCAL LRESULT NEAR
1546 CreateTTYInfo (HWND hWnd)
1548 HMENU hMenu;
1549 PTTYINFO pTTYInfo;
1550 LOGFONT newFont;
1551 int i, ppi;
1552 HDC hDC;
1553 HFONT testFont;
1554 #ifdef SDEBUG
1555 if (mswin_debug >= 5)
1556 fprintf (mswin_debugfile, "CreateTTYInfo::: entered\n");
1557 #endif
1559 hDC = GetDC (ghTTYWnd);
1560 ppi = GetDeviceCaps (hDC, LOGPIXELSY);
1561 ReleaseDC (ghTTYWnd, hDC);
1563 pTTYInfo = (PTTYINFO) MemAlloc (sizeof (TTYINFO));
1564 if (pTTYInfo == NULL)
1565 return ((LRESULT) - 1);
1566 gpTTYInfo = pTTYInfo;
1568 /* initialize TTY info structure */
1569 memset (pTTYInfo, 0, sizeof (TTYINFO));
1570 /* Shown but not focused. */
1571 pTTYInfo->cCaretStyle = CaretBlock;
1572 pTTYInfo->fMinimized = FALSE;
1573 pTTYInfo->fMaximized = FALSE;
1574 pTTYInfo->fFocused = FALSE;
1575 pTTYInfo->fNewLine = FALSE;
1576 pTTYInfo->fMassiveUpdate = FALSE;
1577 pTTYInfo->fNewMailIcon = FALSE;
1578 pTTYInfo->fMClosedIcon = FALSE;
1579 pTTYInfo->autoWrap = WRAP_NO_SCROLL;
1580 pTTYInfo->xOffset = MARGINE_LEFT;
1581 pTTYInfo->yOffset = MARGINE_TOP;
1582 pTTYInfo->fDesiredSize = FALSE;
1583 pTTYInfo->fCursorOn = TRUE;
1584 pico_nfcolor(NULL);
1585 pico_nbcolor(NULL);
1586 pico_rfcolor(NULL);
1587 pico_rbcolor(NULL);
1588 pico_set_normal_color();
1589 pTTYInfo->toolBarTop = TRUE;
1590 pTTYInfo->curToolBarID = IDD_TOOLBAR;
1592 /* Clear menu item array. */
1593 pTTYInfo->curWinMenu = ALPINEMENU;
1594 for (i = 0; i < KS_COUNT; ++i)
1595 pTTYInfo->menuItems[i].miActive = FALSE;
1596 pTTYInfo->menuItemsCurrent = FALSE;
1598 /* Clear resize callback procs. */
1599 for (i = 0; i < RESIZE_CALLBACK_ARRAY_SIZE; ++i)
1600 pTTYInfo->resizer[i] = NULL;
1603 /* clear screen space */
1604 pTTYInfo->pScreen = NULL;
1605 pTTYInfo->pCellWidth = NULL;
1606 pTTYInfo->pAttrib = NULL;
1608 /* setup default font information */
1610 newFont.lfHeight = -MulDiv(12, ppi, 72);
1611 newFont.lfWidth = 0;
1612 newFont.lfEscapement = 0;
1613 newFont.lfOrientation = 0;
1614 newFont.lfWeight = 0;
1615 newFont.lfItalic = 0;
1616 newFont.lfUnderline = 0;
1617 newFont.lfStrikeOut = 0;
1618 newFont.lfCharSet = FONT_CHARSET_FONT;
1619 newFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
1620 newFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1621 newFont.lfQuality = DEFAULT_QUALITY;
1622 newFont.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
1623 _sntprintf(newFont.lfFaceName, LF_FACESIZE, TEXT("%s"), TEXT("Courier New"));
1624 testFont = CreateFontIndirect(&newFont);
1625 if(NULL == testFont)
1626 newFont.lfFaceName[0] = '\0';
1627 else
1628 DeleteObject(testFont);
1630 /* set TTYInfo handle before any further message processing. */
1632 MySetWindowLongPtr (hWnd, GWL_PTTYINFO, pTTYInfo);
1634 /* reset the character information, etc. */
1636 ResetTTYFont (hWnd, pTTYInfo, &newFont);
1640 hMenu = GetMenu (hWnd);
1641 EnableMenuItem (hMenu, IDM_EDIT_CUT, MF_BYCOMMAND | MF_GRAYED);
1642 EnableMenuItem (hMenu, IDM_EDIT_COPY, MF_BYCOMMAND | MF_GRAYED);
1643 EnableMenuItem (hMenu, IDM_EDIT_COPY_APPEND, MF_BYCOMMAND | MF_GRAYED);
1644 EnableMenuItem (hMenu, IDM_EDIT_PASTE, MF_BYCOMMAND | MF_GRAYED);
1645 return ((LRESULT) TRUE);
1649 /*---------------------------------------------------------------------------
1650 * BOOL NEAR DestroyTTYInfo( HWND hWnd )
1652 * Description:
1653 * Destroys block associated with TTY window handle.
1655 * Parameters:
1656 * HWND hWnd
1657 * handle to TTY window
1659 *-------------------------------------------------------------------------*/
1660 LOCAL BOOL NEAR
1661 DestroyTTYInfo (HWND hWnd)
1663 PTTYINFO pTTYInfo;
1665 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
1666 if (pTTYInfo == NULL)
1667 return (FALSE);
1669 #ifdef ACCELERATORS
1670 if(pTTYInfo->hAccel){
1671 DestroyAcceleratorTable(pTTYInfo->hAccel);
1672 pTTYInfo->hAccel = NULL;
1673 pTTYInfo->fAccel = EM_NONE;
1675 #endif
1677 if(pTTYInfo->hTBWnd != NULL)
1678 DestroyWindow (pTTYInfo->hTBWnd);
1680 if(pTTYInfo->hTBBrush != NULL)
1681 DeleteObject(pTTYInfo->hTBBrush);
1683 DeleteObject (pTTYInfo->hTTYFont);
1685 MemFree (pTTYInfo);
1686 return (TRUE);
1690 /*---------------------------------------------------------------------------
1691 * void ResizeTTYScreen( HWND hWnd, PTTYINFO pTTYInfo,
1692 * int newNrow, int newNColumn);
1694 * Description:
1695 * Resize the screen to new size, copying data.
1697 * Parameters:
1698 * PTTYINFO pTTYInfo
1699 * pointer to TTY info structure
1700 * newNCo.umn, newNRow
1701 * new size of screen.
1703 /*--------------------------------------------------------------------------*/
1704 LOCAL BOOL
1705 ResizeTTYScreen (HWND hWnd, PTTYINFO pTTYInfo, int newNRow, int newNColumn)
1707 CharAttrib *pNewAttrib, tmpAttrib, *pSourceAtt, *pDestAtt;
1708 TCHAR *pNewScreen, *pSource, *pDest;
1709 int *pNewCW, *pSourceCW, *pDestCW;
1710 size_t len;
1711 int cells;
1712 int r, i;
1713 extern TERM term;
1716 if (newNColumn < MINNCOLUMN)
1717 newNColumn = MINNCOLUMN;
1718 if (newNRow < MINNROW)
1719 newNRow = MINNROW;
1721 #ifdef SDEBUG
1722 if (mswin_debug >= 5)
1723 fprintf (mswin_debugfile, "ResizeTTYScreen::: entered, new row %d, col %d\n",
1724 newNRow, newNColumn);
1725 #endif
1728 SelClear ();
1729 cells = newNColumn * newNRow;
1730 pNewScreen = (TCHAR *)MemAlloc (cells * sizeof (TCHAR));
1731 if (pNewScreen == NULL)
1732 return (FALSE);
1734 pNewCW = (int *)MemAlloc(cells * sizeof(int));
1735 if(pNewCW == NULL){
1736 MemFree((void *)pNewScreen);
1737 return(FALSE);
1740 pNewAttrib = (CharAttrib *)MemAlloc (cells * sizeof (CharAttrib));
1741 if (pNewAttrib == NULL) {
1742 MemFree ((void *)pNewScreen);
1743 MemFree ((void *)pNewCW);
1744 return (FALSE);
1749 * Clear new screen.
1752 for(i = 0; i < cells; i++){
1753 pNewScreen[i] = ' ';
1754 pNewCW[i] = pTTYInfo->xChar; /* xChar set yet ? */
1757 tmpAttrib.style = CHAR_ATTR_NORM;
1758 tmpAttrib.rgbFG = pTTYInfo->rgbFGColor;
1759 tmpAttrib.rgbBG = pTTYInfo->rgbBGColor;
1760 for(r = 0; r < cells; r++)
1761 pNewAttrib[r] = tmpAttrib;
1764 * Copy old screen onto new screen.
1766 if (pTTYInfo->pScreen != NULL) {
1768 for (r = 1; r <= newNRow && r <= pTTYInfo->actNRow; ++r) {
1769 pSource = pTTYInfo->pScreen + ((pTTYInfo->actNRow - r) *
1770 pTTYInfo->actNColumn);
1771 pDest = pNewScreen + ((newNRow - r) * newNColumn);
1772 len = MIN (newNColumn, pTTYInfo->actNColumn);
1773 for(i = 0; i < len; i++)
1774 pDest[i] = pSource[i];
1776 pSourceCW = pTTYInfo->pCellWidth
1777 + ((pTTYInfo->actNRow - r) * pTTYInfo->actNColumn);
1778 pDestCW = pNewCW + ((newNRow - r) * newNColumn);
1779 memcpy(pDestCW, pSourceCW, len * sizeof(int));
1781 pSourceAtt = pTTYInfo->pAttrib
1782 + ((pTTYInfo->actNRow - r) * pTTYInfo->actNColumn);
1783 pDestAtt = pNewAttrib + ((newNRow - r) * newNColumn);
1784 len = MIN (newNColumn, pTTYInfo->actNColumn);
1785 memcpy (pDestAtt, pSourceAtt, len * sizeof(CharAttrib));
1788 pTTYInfo->nColumn = (CORD)MIN (pTTYInfo->nColumn, newNColumn);
1789 pTTYInfo->nRow = (CORD)MAX (0,
1790 pTTYInfo->nRow + (newNRow - pTTYInfo->actNRow));
1791 MemFree (pTTYInfo->pScreen);
1792 MemFree (pTTYInfo->pCellWidth);
1793 MemFree (pTTYInfo->pAttrib);
1795 else {
1796 pTTYInfo->nColumn = (CORD)MIN (pTTYInfo->nColumn, newNColumn);
1797 pTTYInfo->nRow = (CORD)MIN (pTTYInfo->nRow, newNRow);
1800 pTTYInfo->pScreen = pNewScreen;
1801 pTTYInfo->pCellWidth = pNewCW;
1802 pTTYInfo->pAttrib = pNewAttrib;
1803 pTTYInfo->actNColumn = newNColumn;
1804 pTTYInfo->actNRow = newNRow;
1807 /* Repaint whole screen. */
1808 pTTYInfo->screenDirty = TRUE;
1809 pTTYInfo->eraseScreen = TRUE;
1810 InvalidateRect (hWnd, NULL, FALSE);
1814 /* Pico specific. */
1815 if (term.t_nrow == 0) {
1816 term.t_nrow = (short)(newNRow - 1);
1817 term.t_ncol = (short)newNColumn;
1821 return (TRUE);
1825 /*---------------------------------------------------------------------------
1826 * BOOL ResetTTYFont( HWND hWnd, PTTYINFO pTTYInfo, LOGFONT *newFont)
1828 * Description:
1829 * Resets the TTY character information and causes the
1830 * screen to resize to update the scroll information.
1832 * Parameters:
1833 * PTTYINFO pTTYInfo
1834 * pointer to TTY info structure
1836 /*--------------------------------------------------------------------------*/
1837 LOCAL BOOL
1838 ResetTTYFont (HWND hWnd, PTTYINFO pTTYInfo, LOGFONT *newFont)
1840 HDC hDC;
1841 HFONT hFont;
1842 TEXTMETRIC tm;
1843 int newNRow;
1844 int newNColumn;
1845 BOOL newsize;
1848 #ifdef SDEBUG
1849 if (mswin_debug >= 5)
1850 fprintf (mswin_debugfile, "ResetTTYFont::: entered, curent window size X %d, Y %d\n",
1851 pTTYInfo->xSize, pTTYInfo->ySize);
1852 #endif
1855 if (NULL == pTTYInfo)
1856 return (FALSE);
1858 SelClear ();
1861 * Create new font.
1863 hFont = CreateFontIndirect (newFont);
1864 if (hFont == NULL)
1865 return (FALSE);
1866 hDC = GetDC (hWnd);
1867 SelectObject (hDC, hFont);
1868 GetTextMetrics (hDC, &tm);
1869 ReleaseDC (hWnd, hDC);
1873 * Replace old font.
1875 if (NULL != pTTYInfo->hTTYFont)
1876 DeleteObject (pTTYInfo->hTTYFont);
1877 pTTYInfo->hTTYFont = hFont;
1878 memcpy (&pTTYInfo->lfTTYFont, newFont, sizeof (LOGFONT));
1881 /* Update the char cell size. */
1882 pTTYInfo->xChar = (CORD)tm.tmAveCharWidth;
1883 pTTYInfo->yChar = (CORD)(tm.tmHeight + tm.tmExternalLeading);
1885 /* Update the current number of rows and cols. Don't allow
1886 * either to be less than zero. */
1887 newNRow = MAX (MINNROW,
1888 MIN (MAXNROW,
1889 (pTTYInfo->ySize - pTTYInfo->toolBarSize - (2 * MARGINE_TOP))/
1890 pTTYInfo->yChar));
1891 newNColumn = MAX (MINNCOLUMN,
1892 MIN (MAXNCOLUMN, (pTTYInfo->xSize - (2 * pTTYInfo->xOffset))/
1893 pTTYInfo->xChar));
1895 newsize = newNRow != pTTYInfo->actNRow ||
1896 newNColumn != pTTYInfo->actNColumn;
1897 if (newsize)
1898 ResizeTTYScreen (hWnd, pTTYInfo, newNRow, newNColumn);
1900 /* Resize the caret as well. */
1901 if(pTTYInfo->fCaretOn)
1902 HideCaret (hWnd);
1904 DestroyCaret ();
1905 CaretCreateTTY (hWnd);
1907 /* Redraw screen and, if the "size" changed, tell the upper layers. */
1908 pTTYInfo->screenDirty = TRUE;
1909 pTTYInfo->eraseScreen = TRUE;
1910 InvalidateRect (hWnd, NULL, FALSE);
1912 /* Always call the resize functions - even if the screen size
1913 * has not changed, the font style may have. */
1914 DidResize (pTTYInfo);
1916 return (TRUE);
1920 /*---------------------------------------------------------------------------
1921 * BOOL EraseTTY (HWND hWnd, HDC hDC)
1923 * Description:
1924 * Erase the tty background.
1927 * Parameters:
1928 * HWND hWnd
1929 * handle to TTY window (as always)
1931 /*--------------------------------------------------------------------------*/
1932 LOCAL BOOL
1933 EraseTTY (HWND hWnd, HDC hDC)
1935 RECT erect;
1936 HBRUSH hBrush;
1939 GetClientRect (hWnd, &erect);
1940 hBrush = CreateSolidBrush (gpTTYInfo->rgbBGColor);
1941 if (hBrush != NULL) {
1942 FillRect (hDC, &erect, hBrush);
1943 DeleteObject (hBrush);
1945 return (TRUE);
1949 /*---------------------------------------------------------------------------
1950 * BOOL PaintTTY( HWND hWnd )
1952 * Description:
1953 * Paints the rectangle determined by the paint struct of
1954 * the DC.
1956 * Parameters:
1957 * HWND hWnd
1958 * handle to TTY window (as always)
1960 /*--------------------------------------------------------------------------*/
1961 LOCAL BOOL
1962 PaintTTY (HWND hWnd)
1964 int nRow, nCol; /* Top left corner of update. */
1965 int nEndRow, nEndCol; /* lower right corner of update. */
1966 int nHorzPos, nVertPos; /* Position of each text write. */
1967 int col; /* start col of run of similar attr */
1968 int count; /* count of run of similar attrib. */
1969 int endCount; /* How far to count. */
1970 CharAttrib *pAttrib;
1971 HDC hDC;
1972 LOGFONT tmpFont;
1973 HFONT hOrigFont, hOldFont = NULL, hTmpFont;
1974 PTTYINFO pTTYInfo;
1975 PAINTSTRUCT ps;
1976 RECT rect;
1977 RECT erect;
1978 HBRUSH hBrush;
1979 long offset; /* Offset into pScreen array */
1980 long endoffset; /* Offset of nEndCol in each row array */
1981 CharAttrib *pLastAttrib; /* Attributes of last text write. */
1982 CharAttrib *pNewAttrib; /* Attributes of this text write. */
1985 #ifdef CDEBUG
1986 if (mswin_debug >= 9)
1987 fprintf (mswin_debugfile, "PaintTTY::: entered\n");
1988 #endif
1991 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
1992 if (pTTYInfo == NULL)
1993 return (FALSE);
1995 if (IsIconic (hWnd))
1996 return (TRUE);
1998 hDC = BeginPaint (hWnd, &ps);
1999 rect = ps.rcPaint;
2001 hOrigFont = SelectObject (hDC, pTTYInfo->hTTYFont);
2002 SetTextColor (hDC, pTTYInfo->rgbFGColor);
2003 SetBkColor (hDC, pTTYInfo->rgbBGColor);
2004 SetBkMode (hDC, OPAQUE);
2006 nRow = (rect.top - pTTYInfo->yOffset) / pTTYInfo->yChar;
2007 CONSTRAIN (nRow, 0, pTTYInfo->actNRow - 1);
2009 nEndRow = MIN(pTTYInfo->actNRow - 1,
2010 ((rect.bottom - pTTYInfo->yOffset - 1) / pTTYInfo->yChar));
2011 nCol = MIN(pTTYInfo->actNColumn - 1,
2012 MAX(0, (rect.left - pTTYInfo->xOffset) / pTTYInfo->xChar));
2013 nEndCol = MIN(pTTYInfo->actNColumn - 1,
2014 ((rect.right - pTTYInfo->xOffset - 1) / pTTYInfo->xChar));
2016 pLastAttrib = NULL;
2018 /* Erase screen if necessary. */
2019 if (pTTYInfo->eraseScreen) {
2020 erect.top = 0;
2021 erect.left = 0;
2022 erect.bottom = pTTYInfo->ySize;
2023 erect.right = pTTYInfo->xSize;
2024 hBrush = CreateSolidBrush (pTTYInfo->rgbBGColor);
2025 if (hBrush != NULL) {
2026 FillRect (hDC, &erect, hBrush);
2027 DeleteObject (hBrush);
2029 pTTYInfo->eraseScreen = FALSE;
2033 /* Paint an inset frame around the text region. */
2034 if (pTTYInfo->toolBarSize == 0) {
2035 erect.top = 0;
2036 erect.bottom = pTTYInfo->ySize;
2038 else if (pTTYInfo->toolBarTop) {
2039 erect.top = pTTYInfo->toolBarSize;
2040 erect.bottom = pTTYInfo->ySize;
2042 else {
2043 erect.top = 0;
2044 erect.bottom = pTTYInfo->ySize - pTTYInfo->toolBarSize;
2046 erect.left = 0;
2047 erect.right = pTTYInfo->xSize;
2048 FrameRect3D (hDC, &erect, FRAME_3D_SIZE, FALSE);
2050 /* Paint rows of text. */
2051 for (; nRow <= nEndRow; nRow++) {
2052 nVertPos = (nRow * pTTYInfo->yChar) + pTTYInfo->yOffset;
2053 rect.top = nVertPos;
2054 rect.bottom = nVertPos + pTTYInfo->yChar;
2056 /* Paint runs of similar attributes. */
2057 col = nCol; /* Start at left. */
2059 if(col == 0 && MSWIconPaint(nRow, hDC))
2060 col += 2;
2063 * col is the column on the screen, not the index
2064 * into the array.
2066 while (col <= nEndCol) { /* While not past right. */
2068 /* Starting with Character at nRow, col, what is its attribute? */
2070 /* offset is an index into the array */
2071 offset = pscreen_offset_from_cord(nRow, col, pTTYInfo);
2072 pNewAttrib = pTTYInfo->pAttrib + offset;
2074 hTmpFont = NULL;
2075 if (!(pLastAttrib
2076 && pNewAttrib->style == pLastAttrib->style
2077 && pNewAttrib->rgbFG == pLastAttrib->rgbFG
2078 && pNewAttrib->rgbBG == pLastAttrib->rgbBG)) {
2080 * Require new font?
2082 if(!pLastAttrib
2083 || (pNewAttrib->style & CHAR_ATTR_ULINE)
2084 != (pLastAttrib->style & CHAR_ATTR_ULINE)){
2085 if(pNewAttrib->style & CHAR_ATTR_ULINE){
2087 * Find suitable attribute font...
2089 memcpy (&tmpFont, &pTTYInfo->lfTTYFont,
2090 sizeof (LOGFONT));
2092 tmpFont.lfHeight = - pTTYInfo->yChar;
2093 tmpFont.lfWidth = - pTTYInfo->xChar;
2095 tmpFont.lfUnderline = (BYTE)((pNewAttrib->style
2096 & CHAR_ATTR_ULINE)
2097 == CHAR_ATTR_ULINE);
2099 hTmpFont = CreateFontIndirect (&tmpFont);
2101 hOldFont = SelectObject (hDC, hTmpFont);
2106 * Set new color attributes. If Reverse or Selected, then
2107 * show in reverse colors. But if neither, or both, then
2108 * normal colors.
2110 if(pNewAttrib->style & CHAR_ATTR_SEL){
2111 SetTextColor (hDC, pNewAttrib->rgbBG);
2112 SetBkColor (hDC, pNewAttrib->rgbFG);
2114 else {
2115 if(!(pLastAttrib
2116 && pNewAttrib->rgbFG == pLastAttrib->rgbFG)
2117 || (pLastAttrib->style & CHAR_ATTR_SEL))
2118 SetTextColor (hDC, pNewAttrib->rgbFG);
2120 if(!(pLastAttrib
2121 && pNewAttrib->rgbBG == pLastAttrib->rgbBG)
2122 || (pLastAttrib->style & CHAR_ATTR_SEL))
2123 SetBkColor (hDC, pNewAttrib->rgbBG);
2127 /* Find run of similar attributes. */
2128 count = 1;
2129 pAttrib = pTTYInfo->pAttrib + (offset + 1);
2130 /* endoffset is an index into the pScreen array */
2131 endoffset = pscreen_offset_from_cord(nRow, nEndCol, pTTYInfo);
2132 endCount = endoffset - offset;
2133 while (count <= endCount
2134 && pAttrib->style == pNewAttrib->style
2135 && pAttrib->rgbFG == pNewAttrib->rgbFG
2136 && pAttrib->rgbBG == pNewAttrib->rgbBG){
2137 ++pAttrib;
2138 ++count;
2141 if(hTmpFont != NULL){
2142 /* BUG: compute new offsets based on hTmpFont font if required */
2143 nHorzPos = (col * pTTYInfo->xChar) + pTTYInfo->xOffset;
2144 rect.left = nHorzPos;
2145 rect.right = nHorzPos + pTTYInfo->xChar * scrwidth(pTTYInfo->pScreen+offset, count);
2147 else{
2148 /* Paint run of characters from nRow, col to nRow, col + count
2149 * rect.top and rect.bottom have already been calculated. */
2150 nHorzPos = (col * pTTYInfo->xChar) + pTTYInfo->xOffset;
2151 rect.left = nHorzPos;
2152 rect.right = nHorzPos + pTTYInfo->xChar * scrwidth(pTTYInfo->pScreen+offset, count);
2155 ExtTextOut (hDC, nHorzPos, nVertPos, ETO_OPAQUE | ETO_CLIPPED,
2156 &rect, (LPTSTR) (pTTYInfo->pScreen + offset),
2157 count, (int *)(pTTYInfo->pCellWidth+offset));
2159 /* Overstrike bold chars by hand to preserve char cell size */
2160 if(pNewAttrib->style & CHAR_ATTR_BOLD){
2161 int old_mode = GetBkMode(hDC);
2162 SetBkMode (hDC, TRANSPARENT);
2163 ExtTextOut (hDC, nHorzPos + 1, nVertPos, 0,
2164 &rect, (LPTSTR) (pTTYInfo->pScreen + offset),
2165 count, (int *)(pTTYInfo->pCellWidth+offset));
2166 if(old_mode)
2167 SetBkMode (hDC, old_mode);
2170 /* Move pointer to end of this span of characters. */
2171 col += MAX(scrwidth(pTTYInfo->pScreen+offset, count), 1);
2172 pLastAttrib = pNewAttrib;
2174 if(hTmpFont != NULL){
2175 SelectObject(hDC, hOldFont);
2176 DeleteObject(hTmpFont);
2181 SelectObject (hDC, hOrigFont);
2182 EndPaint (hWnd, &ps);
2183 MoveTTYCursor (hWnd);
2184 pTTYInfo->screenDirty = FALSE;
2185 return (TRUE);
2189 /* FillRectColor
2192 * Description:
2193 * FillRectColor is similar to PatB in toolbar.c
2195 * Code based on MFC source code, so presumably efficient.
2198 LOCAL void
2199 FillRectColor(HDC hDC, RECT * pRC, COLORREF color)
2201 SetBkColor(hDC, color);
2202 ExtTextOut(hDC, 0, 0, ETO_OPAQUE, pRC, NULL, 0, NULL);
2206 /** FrameRect3D
2209 * Inputs:
2210 * hdc - HDC
2211 * pRC - pointer to rectangle
2212 * width - width for frame (usually one)
2213 * raised - TRUE for raised effect, FALSE for sunken effect
2215 * Outputs:
2216 * none
2218 * Returns:
2219 * void
2221 * Description
2222 * Draws a frame with a 3D effect.
2224 * If 'raised' is true, the rectangle will look raised (like
2225 * a button); otherwise, the rectangle will look sunk.
2228 void
2229 FrameRect3D(HDC hdc, RECT * pRC, int width, BOOL raised)
2231 COLORREF hilite, shadow;
2232 RECT rcTemp;
2234 shadow = GetSysColor(COLOR_BTNSHADOW);
2235 hilite = GetSysColor(COLOR_BTNHIGHLIGHT);
2237 rcTemp = *pRC;
2239 rcTemp.right = rcTemp.left + width;
2240 FillRectColor(hdc, &rcTemp, raised ? hilite : shadow);
2241 rcTemp.right = pRC->right;
2243 rcTemp.bottom = rcTemp.top + width;
2244 FillRectColor(hdc, &rcTemp, raised ? hilite : shadow);
2245 rcTemp.bottom = pRC->bottom;
2247 rcTemp.left = rcTemp.right - width;
2248 FillRectColor(hdc, &rcTemp, raised ? shadow : hilite);
2249 rcTemp.left = pRC->left;
2251 rcTemp.top = rcTemp.bottom - width;
2252 FillRectColor(hdc, &rcTemp, raised ? shadow : hilite);
2256 /*---------------------------------------------------------------------------
2257 * BOOL GetMinMaxInfoTTY (HWND hWnd, (MINMAXINFO __far *)lParam)
2259 * Description:
2260 * Return the min and max size that the window can be.
2262 * Parameters:
2263 * HWND hWnd
2264 * handle to TTY window
2266 * MINMAXINFO
2267 * Info structure that Windows would like us to fill.
2269 /*--------------------------------------------------------------------------*/
2270 LOCAL BOOL
2271 GetMinMaxInfoTTY (HWND hWnd, MINMAXINFO __far *lpmmi)
2273 PTTYINFO pTTYInfo;
2276 #ifdef SDEBUG
2277 if (mswin_debug >= 5)
2278 fprintf (mswin_debugfile, "GetMinMaxInfoTTY::: entered\n");
2279 #endif
2282 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2283 if (pTTYInfo == NULL)
2284 return (FALSE);
2286 lpmmi->ptMaxTrackSize.x = lpmmi->ptMaxSize.x = MIN (lpmmi->ptMaxSize.x,
2287 pTTYInfo->xChar * MAXNCOLUMN + WIN_X_BORDER_SIZE);
2288 lpmmi->ptMaxTrackSize.y = lpmmi->ptMaxSize.y = MIN (lpmmi->ptMaxSize.y,
2289 pTTYInfo->yChar * MAXNROW + WIN_Y_BORDER_SIZE);
2291 lpmmi->ptMinTrackSize.x = MAX (WIN_MIN_X_SIZE,
2292 pTTYInfo->xChar * MINNCOLUMN + WIN_X_BORDER_SIZE);
2293 lpmmi->ptMinTrackSize.y = MAX (WIN_MIN_Y_SIZE,
2294 pTTYInfo->yChar * MINNROW + WIN_Y_BORDER_SIZE);
2295 return (TRUE);
2299 /*---------------------------------------------------------------------------
2300 * BOOL AboutToSizeTTY (HWND hWnd, WINDOWPOS *winPos)
2302 * Description:
2303 * Called just before Windows resizes our window. We can change the
2304 * values in 'winPos' to change the new size of the window.
2306 * If mswin_setwindow() was called when the window was minimized we
2307 * set the new size here.
2309 * Parameters:
2310 * HWND hWnd
2311 * handle to TTY window
2313 * WORD wVertSize
2314 * new vertical size
2316 * WORD wHorzSize
2317 * new horizontal size
2319 /*--------------------------------------------------------------------------*/
2320 LOCAL BOOL
2321 AboutToSizeTTY (HWND hWnd, WINDOWPOS *winPos)
2323 PTTYINFO pTTYInfo;
2326 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2327 if (pTTYInfo == NULL)
2328 return ( FALSE );
2330 #ifdef SDEBUG
2331 if (mswin_debug >= 5)
2332 fprintf (mswin_debugfile, "AboutToSizeTTY::: After x%lx, pos %d, %d, size %d, %d, flags x%x\n",
2333 winPos->hwndInsertAfter, winPos->x, winPos->y, winPos->cx,
2334 winPos->cy, winPos->flags);
2336 #endif
2339 * Was the window minimized AND is there a desired new size for it?
2340 * AND is this a call that specifies a new size and position.
2342 if (pTTYInfo->fMinimized && pTTYInfo->fDesiredSize &&
2343 (winPos->flags & (SWP_NOSIZE | SWP_NOMOVE)) == 0) {
2344 #ifdef SDEBUG
2345 if (mswin_debug >= 5)
2346 fprintf (mswin_debugfile, "AboutToSizeTTY::: substitue pos (%d, %d), size (%d, %d)\n",
2347 pTTYInfo->xDesPos, pTTYInfo->yDesPos,
2348 pTTYInfo->xDesSize, pTTYInfo->yDesSize);
2349 #endif
2350 pTTYInfo->fDesiredSize = FALSE;
2351 winPos->x = pTTYInfo->xDesPos;
2352 winPos->y = pTTYInfo->yDesPos;
2353 winPos->cx = pTTYInfo->xDesSize;
2354 winPos->cy = pTTYInfo->yDesSize;
2356 return (TRUE);
2360 /*---------------------------------------------------------------------------
2361 * BOOL SizeTTY( HWND hWnd, int fwSizeType, CORD wVertSize,
2362 * CORD wHorzSize)
2364 * Description:
2365 * Sizes TTY and sets up scrolling regions.
2367 * Parameters:
2368 * HWND hWnd
2369 * handle to TTY window
2371 * WORD wVertSize
2372 * new vertical size
2374 * WORD wHorzSize
2375 * new horizontal size
2377 /*--------------------------------------------------------------------------*/
2378 LOCAL BOOL
2379 SizeTTY (HWND hWnd, int fwSizeType, CORD wVertSize, CORD wHorzSize)
2381 PTTYINFO pTTYInfo;
2382 int newNColumn;
2383 int newNRow;
2386 #ifdef SDEBUG
2387 if (mswin_debug >= 5)
2388 fprintf (mswin_debugfile, "SizeTTY::: entered, sizeType %d, New screen size %d, %d pixels\n",
2389 fwSizeType, wHorzSize, wVertSize);
2390 #endif
2392 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2393 if (pTTYInfo == NULL)
2394 return ( FALSE );
2398 * Is the window being minimized or maximized?
2400 switch (fwSizeType) {
2401 case SIZE_MINIMIZED:
2402 pTTYInfo->fMinimized = TRUE;
2403 pTTYInfo->fMaximized = FALSE;
2404 return (TRUE);
2405 case SIZE_MAXIMIZED:
2406 pTTYInfo->fMinimized = FALSE;
2407 pTTYInfo->fMaximized = TRUE;
2408 break;
2409 default:
2410 pTTYInfo->fMinimized = pTTYInfo->fMaximized = FALSE;
2411 break;
2414 pTTYInfo->ySize = (CORD) wVertSize;
2415 newNRow = MAX(MINNROW, MIN(MAXNROW,
2416 (pTTYInfo->ySize - pTTYInfo->toolBarSize - (2 * MARGINE_TOP)) /
2417 pTTYInfo->yChar));
2418 if (pTTYInfo->toolBarTop)
2419 pTTYInfo->yOffset = MARGINE_TOP + pTTYInfo->toolBarSize;
2420 else
2421 pTTYInfo->yOffset = MARGINE_TOP;
2424 pTTYInfo->xSize = (CORD) wHorzSize;
2425 newNColumn = MAX(MINNCOLUMN,
2426 MIN(MAXNCOLUMN, (pTTYInfo->xSize - (2 * MARGINE_LEFT)) /
2427 pTTYInfo->xChar));
2428 pTTYInfo->xOffset = MARGINE_LEFT;
2430 if(newNRow == pTTYInfo->actNRow && newNColumn == pTTYInfo->actNColumn)
2431 return(FALSE);
2433 ResizeTTYScreen (hWnd, pTTYInfo, newNRow, newNColumn);
2434 pTTYInfo->screenDirty = TRUE;
2435 pTTYInfo->eraseScreen = TRUE;
2436 InvalidateRect (hWnd, NULL, FALSE);
2438 if (pTTYInfo->hTBWnd) {
2439 if (pTTYInfo->toolBarTop)
2440 /* Position at top of window. */
2441 SetWindowPos (pTTYInfo->hTBWnd, HWND_TOP,
2442 0, 0,
2443 wHorzSize, pTTYInfo->toolBarSize,
2444 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
2445 else
2446 /* Position at bottom of window. */
2447 SetWindowPos (pTTYInfo->hTBWnd, HWND_TOP,
2448 0, pTTYInfo->ySize - pTTYInfo->toolBarSize,
2449 wHorzSize, pTTYInfo->toolBarSize,
2450 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
2454 DidResize (pTTYInfo);
2456 return (TRUE);
2460 /*---------------------------------------------------------------------------
2461 * BOOL SizingTTY( HWND hWnd, int fwSide, LPRECT pRect)
2463 * Description:
2464 * Snaps the drag rectangle to char width/height boundaries
2466 * Parameters:
2467 * HWND hWnd
2468 * handle to TTY window
2470 * WORD fwSide
2471 * edge of window being sized
2473 * LPRECT
2474 * screen coords of drag rectangle in and desired size on return
2476 /*--------------------------------------------------------------------------*/
2477 LOCAL BOOL
2478 SizingTTY (HWND hWnd, int fwSide, LPRECT pRect)
2480 PTTYINFO pTTYInfo;
2481 int newNRow, newNCol, xClient, yClient,
2482 xSys, ySys, xDiff, yDiff;
2484 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2485 if (pTTYInfo == NULL)
2486 return (FALSE);
2488 xSys = (2 * GetSystemMetrics(SM_CXSIZEFRAME))
2489 + GetSystemMetrics(SM_CXVSCROLL);
2490 ySys = (2 * GetSystemMetrics(SM_CYSIZEFRAME))
2491 + GetSystemMetrics(SM_CYCAPTION)
2492 + GetSystemMetrics(SM_CYMENU);
2494 newNCol = (((pRect->right - pRect->left) - xSys)
2495 - (2 * MARGINE_LEFT)) / pTTYInfo->xChar;
2496 newNRow = (((pRect->bottom - pRect->top) - ySys) - (2 * MARGINE_TOP)
2497 - pTTYInfo->toolBarSize) / pTTYInfo->yChar;
2499 xClient = (newNCol * pTTYInfo->xChar) + (2 * MARGINE_LEFT);
2500 yClient = (newNRow * pTTYInfo->yChar) + (2 * MARGINE_TOP)
2501 + pTTYInfo->toolBarSize;
2503 xDiff = (pRect->left + xClient + xSys) - pRect->right;
2504 yDiff = (pRect->top + yClient + ySys) - pRect->bottom;
2506 if(!(xDiff || yDiff))
2507 return(FALSE);
2509 switch(fwSide){
2510 case WMSZ_BOTTOM : /* Bottom edge */
2511 pRect->bottom += yDiff;
2512 break;
2514 case WMSZ_BOTTOMLEFT : /*Bottom-left corner */
2515 pRect->bottom += yDiff;
2516 pRect->left -= xDiff;
2517 break;
2519 case WMSZ_BOTTOMRIGHT : /* Bottom-right corner */
2520 pRect->bottom += yDiff;
2521 pRect->right += xDiff;
2522 break;
2524 case WMSZ_LEFT : /* Left edge */
2525 pRect->left -= xDiff;
2526 break;
2528 case WMSZ_RIGHT : /* Right edge */
2529 pRect->right += xDiff;
2530 break;
2532 case WMSZ_TOP : /* Top edge */
2533 pRect->top -= yDiff;
2534 break;
2536 case WMSZ_TOPLEFT : /* Top-left corner */
2537 pRect->top -= yDiff;
2538 pRect->left -= xDiff;
2539 break;
2541 case WMSZ_TOPRIGHT : /* Top-right corner */
2542 pRect->top -= yDiff;
2543 pRect->right += xDiff;
2544 break;
2546 default :
2547 break;
2550 if(!(newNRow == pTTYInfo->actNRow && newNCol == pTTYInfo->actNColumn))
2551 SizeTTY(hWnd, SIZE_RESTORED, (CORD) yClient, (CORD) xClient);
2553 return(TRUE);
2557 /*---------------------------------------------------------------------------
2558 * BOOL MoveTTY (HWND hWnd, int xPos, int yPos)
2560 * Description:
2561 * Notes the fact that the window has moved.
2562 * Only real purpose is so we can tell pine which can the write the
2563 * new window position to the 'pinerc' file.
2565 * Parameters:
2566 * HWND hWnd
2567 * handle to TTY window
2569 * int xPos, yPos
2570 * New position of the top left corner.
2573 /*--------------------------------------------------------------------------*/
2574 LOCAL BOOL
2575 MoveTTY (HWND hWnd, int xPos, int yPos)
2577 #ifdef SDEBUG
2578 if (mswin_debug >= 5)
2579 fprintf (mswin_debugfile, "MoveTTY::: entered\n");
2580 #endif
2582 DidResize (gpTTYInfo);
2583 return (TRUE);
2587 /*---------------------------------------------------------------------------
2588 * void ScrollTTY ()
2590 * Description:
2591 * Respond to a scroll message by either calling the scroll
2592 * callback or inserting a scroll character into the input
2593 * stream.
2595 * Scrolling in the TTY window is complicated by the way pine
2596 * process events. Normal windows applications are entirly event
2597 * driven. The top level does nothing but dispatch events. In
2598 * pine, the top level implements the logic. Events are only
2599 * dispatched by the lowest levels.
2601 * In normal applications, mouse down in the scroll bar causes
2602 * an internal scroll function to be entered. It tracks the
2603 * mouse and issues scroll messages as needed. If the
2604 * application redraws the screen the scroll function also
2605 * dispatches the WM_PAINT message to the application. The
2606 * important thing is that this internal scroll function does
2607 * not exit until the mouse is released.
2609 * We implement two methods for pine's screen managers to deal
2610 * with scroll events. They can receive scroll events as
2611 * characters in the normal input stream or they can register a
2612 * callback function.
2614 * In the "insert a character in the queue" mode, the scroll
2615 * event never gets process until the mouse is release. Auto
2616 * repeat scroll events (generated as the mouse is held down)
2617 * will cause multiple chars to be inserted in the queue, none
2618 * of which will get processed till the mouse is release. In a
2619 * compromise, we allow only one scroll char in the queue,
2620 * which prevents makes for a more friendly and controllable
2621 * behavior.
2623 * In the callback mode, the callback repaints the screen, and
2624 * then it calls mswin_flush() which PROCESSES EVENTS! The
2625 * Windows internal scroll function does NOT expect that. This
2626 * behavior can confuses the scroll function, causing it to
2627 * miss mouse up events. We avoid this by setting gScrolling TRUE
2628 * when this routine is entered and FALSE when this routine exits
2629 * All PeekMessage processors avoid processing any message when
2630 * gScrolling is TRUE.
2632 /*--------------------------------------------------------------------------*/
2633 LOCAL void
2634 ScrollTTY (HWND hWnd, int wScrollCode, int nPos, HWND hScroll)
2636 PTTYINFO pTTYInfo;
2637 int cmd = 0;
2638 long scroll_pos = 0;
2639 BOOL noAction = FALSE;
2640 BOOL didScroll;
2641 FARPROC prevBlockingProc;
2645 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2647 if (pTTYInfo == NULL || gScrolling)
2648 return;
2650 gScrolling = TRUE;
2651 if (gWSBlockingProc != NULL)
2652 prevBlockingProc = WSASetBlockingHook (gWSBlockingProc);
2657 switch (wScrollCode) {
2658 case SB_BOTTOM:
2659 cmd = MSWIN_KEY_SCROLLTO;
2660 scroll_pos = pTTYInfo->scrollTo = 0;
2661 break;
2663 case SB_TOP:
2664 cmd = MSWIN_KEY_SCROLLTO;
2665 scroll_pos = pTTYInfo->scrollTo = pTTYInfo->scrollRange;
2666 break;
2668 case SB_LINEDOWN:
2669 cmd = MSWIN_KEY_SCROLLDOWNLINE;
2670 scroll_pos = 1;
2671 break;
2673 case SB_LINEUP:
2674 cmd = MSWIN_KEY_SCROLLUPLINE;
2675 scroll_pos = 1;
2676 break;
2678 case SB_PAGEDOWN:
2679 cmd = MSWIN_KEY_SCROLLDOWNPAGE;
2680 scroll_pos = 1;
2681 break;
2683 case SB_PAGEUP:
2684 cmd = MSWIN_KEY_SCROLLUPPAGE;
2685 scroll_pos = 1;
2686 break;
2688 case SB_THUMBTRACK:
2689 case SB_THUMBPOSITION:
2690 cmd = MSWIN_KEY_SCROLLTO;
2691 scroll_pos = pTTYInfo->scrollTo = (long) ((float)nPos);
2692 break;
2694 default:
2695 noAction = TRUE;
2696 break;
2701 * If there is a scroll callback call that. If there is no scroll
2702 * callback or the callback says it did not handle the event (returned,
2703 * FALSE) queue the scroll cmd.
2705 if (!noAction) {
2706 SelClear ();
2707 didScroll = FALSE;
2708 if (gScrollCallback != NULL) {
2709 /* Call scrolling callback. Set blocking hook to our routine
2710 * which prevents messages from being dispatched. */
2711 if (gWSBlockingProc != NULL)
2712 WSASetBlockingHook (gWSBlockingProc);
2713 didScroll = gScrollCallback (cmd, scroll_pos);
2714 if (gWSBlockingProc != NULL)
2715 WSAUnhookBlockingHook ();
2718 * If no callback or callback did not do the scrolling operation,
2719 * insert a scroll cmd in the input stream.
2721 if (!didScroll)
2722 CQAddUniq ((UCS)cmd, 0);
2726 gScrolling = FALSE;
2727 return;
2731 #ifdef WIN32
2732 /*---------------------------------------------------------------------------
2733 * void MouseWheelTTY ()
2735 * Description:
2736 * Respond to a WM_MOUSEWHEEL event by calling scroll callback
2737 * ala ScrollTTY.
2740 /*--------------------------------------------------------------------------*/
2741 LOCAL void
2742 MouseWheelTTY (HWND hWnd, int xPos, int yPos, int fwKeys, int zDelta)
2744 PTTYINFO pTTYInfo;
2745 int cmd;
2746 long scroll_pos;
2747 FARPROC prevBlockingProc;
2748 SCROLLINFO scrollInfo;
2749 static int zDelta_accumulated;
2751 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2753 if (pTTYInfo == NULL || gScrolling)
2754 return;
2756 scrollInfo.cbSize = sizeof(SCROLLINFO);
2757 scrollInfo.fMask = SIF_POS | SIF_RANGE;
2758 GetScrollInfo(hWnd, SB_VERT, &scrollInfo);
2759 if((zDelta < 0 && scrollInfo.nPos < scrollInfo.nMin)
2760 || (zDelta > 0 && scrollInfo.nPos >= scrollInfo.nMax))
2761 return;
2763 gScrolling = TRUE;
2764 if (gWSBlockingProc != NULL)
2765 prevBlockingProc = WSASetBlockingHook (gWSBlockingProc);
2767 if(fwKeys == MK_MBUTTON)
2768 zDelta *= 2; /* double the effect! */
2770 if(abs(zDelta += zDelta_accumulated) < WHEEL_DELTA){
2771 zDelta_accumulated = zDelta;
2773 else{
2774 /* Remember any partial increments */
2775 zDelta_accumulated = zDelta % WHEEL_DELTA;
2777 scroll_pos = (long)(gsMWMultiplier * abs((zDelta / WHEEL_DELTA)));
2779 cmd = (zDelta < 0) ? MSWIN_KEY_SCROLLDOWNLINE : MSWIN_KEY_SCROLLUPLINE;
2781 SelClear ();
2782 if (gScrollCallback != NULL) {
2783 /* Call scrolling callback. Set blocking hook to our routine
2784 * which prevents messages from being dispatched. */
2785 if (gWSBlockingProc != NULL)
2786 WSASetBlockingHook (gWSBlockingProc);
2787 (void) gScrollCallback (cmd, scroll_pos);
2788 if (gWSBlockingProc != NULL)
2789 WSAUnhookBlockingHook ();
2793 gScrolling = FALSE;
2794 return;
2798 LOCAL void
2799 MouseWheelMultiplier()
2801 TCHAR lines[8];
2802 DWORD llen = sizeof(lines)/sizeof(TCHAR);
2804 /* HKEY_CURRENT_USER\Control Panel\Desktop holds the key */
2805 gsMWMultiplier = (MSWRPeek(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"),
2806 TEXT("WheelScrollLines"), lines, &llen) == TRUE)
2807 ? (short)_ttoi(lines) : 1;
2809 #endif
2812 /*---------------------------------------------------------------------------
2813 * void CaretTTY (HWND hWnd, CARETS cStyle)
2815 * Description:
2816 * Adjusts the Caret to the user supplied style
2818 * Parameters:
2819 * HWND hWnd
2820 * handle to TTY window
2822 * int wStyle
2823 * New style to take on
2825 /*--------------------------------------------------------------------------*/
2826 LOCAL void
2827 CaretTTY (HWND hWnd, CARETS cStyle)
2829 PTTYINFO pTTYInfo;
2831 if(pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO)){
2832 pTTYInfo->cCaretStyle = cStyle;
2833 CaretCreateTTY (hWnd);
2834 DidResize (gpTTYInfo);
2839 /*---------------------------------------------------------------------------
2840 * void CaretCreateTTY (HWND hWnd, BOOL wPosition)
2842 * Description:
2843 * Adjusts the Caret to the user supplied style
2845 * Parameters:
2846 * HWND hWnd
2847 * handle to TTY window
2849 * BOOL wPosition
2850 * whether or not to position it too
2852 /*--------------------------------------------------------------------------*/
2853 LOCAL void
2854 CaretCreateTTY (HWND hWnd)
2856 PTTYINFO pTTYInfo;
2858 if(pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO)){
2859 int n = 0, x, y;
2861 switch(pTTYInfo->cCaretStyle){
2862 case CaretHorizBar :
2863 x = pTTYInfo->xChar;
2864 y = pTTYInfo->yChar / 5;
2865 n = pTTYInfo->yChar - y;
2866 break;
2868 case CaretVertBar :
2869 x = pTTYInfo->xChar / 4;
2870 y = pTTYInfo->yChar;
2871 break;
2873 case CaretSmallBlock :
2874 x = pTTYInfo->xChar;
2875 y = pTTYInfo->yChar / 2;
2876 n = pTTYInfo->yChar - y;
2877 break;
2879 default :
2880 x = pTTYInfo->xChar;
2881 y = pTTYInfo->yChar;
2882 break;
2885 CreateCaret (hWnd, NULL, x, y);
2886 pTTYInfo->yCurOffset = n;
2888 if(pTTYInfo->fCaretOn){
2889 ShowCaret(hWnd);
2890 MoveTTYCursor(hWnd);
2897 * This routine is inserted as the winsock blocking hook. It's main perpos
2898 * is to NOT dispatch messages.
2900 BOOL CALLBACK __export
2901 NoMsgsAreSent (void)
2903 return (FALSE);
2907 /*---------------------------------------------------------------------------
2908 * BOOL SetTTYFocus( HWND hWnd )
2910 * Description:
2911 * Sets the focus to the TTY window also creates caret.
2913 * Parameters:
2914 * HWND hWnd
2915 * handle to TTY window
2917 /*--------------------------------------------------------------------------*/
2918 LOCAL BOOL
2919 SetTTYFocus (HWND hWnd)
2921 PTTYINFO pTTYInfo;
2923 #ifdef SDEBUG
2924 if (mswin_debug >= 5)
2925 fprintf (mswin_debugfile, "SetTTYFocus::: entered\n");
2926 #endif
2928 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2929 if (pTTYInfo == NULL)
2930 return (FALSE);
2932 mswin_showcursor(TRUE);
2934 pTTYInfo->fFocused = TRUE;
2936 CaretCreateTTY (hWnd);
2938 MoveTTYCursor (hWnd);
2939 return (TRUE);
2943 /*---------------------------------------------------------------------------
2944 * BOOL KillTTYFocus( HWND hWnd )
2946 * Description:
2947 * Kills TTY focus and destroys the caret.
2949 * Parameters:
2950 * HWND hWnd
2951 * handle to TTY window
2953 /*--------------------------------------------------------------------------*/
2954 LOCAL BOOL
2955 KillTTYFocus (HWND hWnd)
2957 PTTYINFO pTTYInfo;
2959 #ifdef SDEBUG
2960 if (mswin_debug >= 5)
2961 fprintf (mswin_debugfile, "KillTTYFocus::: entered\n");
2962 #endif
2963 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2964 if (pTTYInfo == NULL)
2965 return (FALSE);
2967 mswin_showcursor(TRUE);
2969 if(pTTYInfo->fCaretOn)
2970 HideCaret (hWnd);
2972 DestroyCaret();
2974 pTTYInfo->fFocused = FALSE;
2976 return (TRUE);
2980 /*---------------------------------------------------------------------------
2981 * BOOL MoveTTYCursor( HWND hWnd )
2983 * Description:
2984 * Moves caret to current position.
2986 * Parameters:
2987 * HWND hWnd
2988 * handle to TTY window
2990 /*--------------------------------------------------------------------------*/
2991 LOCAL BOOL
2992 MoveTTYCursor (HWND hWnd)
2994 PTTYINFO pTTYInfo;
2996 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2997 if (pTTYInfo == NULL)
2998 return (FALSE);
3000 if(pTTYInfo->fCaretOn && !pTTYInfo->fMassiveUpdate) {
3001 HideCaret (hWnd);
3002 SetCaretPos ((pTTYInfo->nColumn * pTTYInfo->xChar) + pTTYInfo->xOffset,
3003 (pTTYInfo->nRow * pTTYInfo->yChar)
3004 + pTTYInfo->yCurOffset + pTTYInfo->yOffset);
3005 ShowCaret (hWnd);
3008 return (TRUE);
3012 /*---------------------------------------------------------------------------
3013 * BOOL ProcessTTYKeyDown ( HWND hWnd, WORD bOut )
3015 * Description:
3016 * Called to process MW_KEYDOWN message. We are only interested in
3017 * virtual keys that pico/pine use. All others get passed on to
3018 * the default message handler. Regular key presses will return
3019 * latter as a WM_CHAR message, with SHIFT and CONTROL processing
3020 * already done.
3022 * We do watch for VK_CONTROL to keep track of it's state such
3023 * that we can implement ^_space.
3025 * Parameters:
3026 * HWND hWnd
3027 * handle to TTY window
3029 * BYTE key
3030 * Virtual key code.
3032 /*--------------------------------------------------------------------------*/
3033 LOCAL BOOL
3034 ProcessTTYKeyDown (HWND hWnd, TCHAR key)
3036 UCS myKey;
3037 BOOL fKeyControlDown = GetKeyState(VK_CONTROL) < 0;
3038 BOOL fKeyAltDown = GetKeyState(VK_MENU) < 0;
3040 // If the alt key is down, let Windows handle the message. This will
3041 // allow the Ctrl+Alt (AltGr) processing to work.
3042 if(fKeyAltDown)
3043 return FALSE;
3045 switch (key) {
3046 case VK_MENU:
3047 case VK_CONTROL:
3048 case VK_SHIFT:
3049 return FALSE;
3050 case VK_UP: myKey = KEY_UP; break;
3051 case VK_DOWN: myKey = KEY_DOWN; break;
3052 case VK_RIGHT:
3053 /* Ctrl-@ is used to advance to the next word. */
3054 myKey = fKeyControlDown ? '@': KEY_RIGHT;
3055 break;
3056 case VK_LEFT:
3057 /* Ctrl-left is used to advance to the previous word. */
3058 myKey = KEY_LEFT;
3059 break;
3060 case VK_HOME:
3061 /* Ctrl-home is used to advance to the beginning of buffer. */
3062 myKey = KEY_HOME;
3063 break;
3064 case VK_END:
3065 /* Ctrl-end is used to advance to the end of buffer. */
3066 myKey = KEY_END;
3067 break;
3068 case VK_PRIOR: myKey = KEY_PGUP; break;
3069 case VK_NEXT: myKey = KEY_PGDN; break;
3070 case VK_DELETE: myKey = KEY_DEL; break;
3071 case VK_F1: myKey = F1; break;
3072 case VK_F2: myKey = F2; break;
3073 case VK_F3: myKey = F3; break;
3074 case VK_F4: myKey = F4; break;
3075 case VK_F5: myKey = F5; break;
3076 case VK_F6: myKey = F6; break;
3077 case VK_F7: myKey = F7; break;
3078 case VK_F8: myKey = F8; break;
3079 case VK_F9: myKey = F9; break;
3080 case VK_F10: myKey = F10; break;
3081 case VK_F11: myKey = F11; break;
3082 case VK_F12: myKey = F12; break;
3084 default:
3085 if(fKeyControlDown && !(GetKeyState(VK_SHIFT) < 0)) {
3086 if(key == '6') {
3088 * Ctrl-^ is used to set and clear the mark in the
3089 * composer (pico) On most other systems Ctrl-6 does the
3090 * same thing. Allow that on windows too.
3092 myKey = '^';
3093 break;
3094 } else if(key == '2') {
3095 /* Ctrl-@ is used to advance to the next word. */
3096 myKey = '@';
3097 break;
3101 return (FALSE); /* Message NOT handled.*/
3104 CQAdd (myKey, fKeyControlDown);
3106 set_time_of_last_input();
3108 return (TRUE); /* Message handled .*/
3112 #ifdef CDEBUG
3113 char *
3114 dtime()
3116 static char timestring[23];
3117 time_t t;
3118 struct _timeb timebuffer;
3120 timestring[0] = '\0';
3121 t = time((time_t *) 0);
3122 _ftime(&timebuffer);
3123 snprintf(timestring, sizeof(timestring), "%.8s.%03ld", ctime(&t)+11, timebuffer.millitm);
3125 return(timestring);
3127 #endif
3130 /*---------------------------------------------------------------------------
3131 * BOOL ProcessTTYCharacter( HWND hWnd, WORD bOut )
3133 * Description:
3134 * Place the character into a queue.
3136 * Parameters:
3137 * HWND hWnd
3138 * handle to TTY window
3140 * BYTE bOut
3141 * byte from keyboard
3143 /*--------------------------------------------------------------------------*/
3144 LOCAL BOOL
3145 ProcessTTYCharacter (HWND hWnd, TCHAR bOut)
3147 // Only check for control key being down if the alt key isn't also down.
3148 // Windows uses Ctrl+Alt as AltGr.
3149 BOOL fKeyAltDown = GetKeyState(VK_MENU) < 0;
3150 BOOL fKeyControlDown = fKeyAltDown ?
3151 FALSE : (GetKeyState(VK_CONTROL) < 0);
3153 if(fKeyControlDown) {
3154 if(bOut == ' ')
3155 bOut = '@';
3156 else
3157 bOut += '@';
3160 CQAdd ((UCS)bOut, fKeyControlDown);
3162 #ifdef ACCELERATORS
3163 UpdateAccelerators (hWnd);
3164 #endif
3166 set_time_of_last_input();
3168 return (TRUE); /* Message handled. */
3172 /*---------------------------------------------------------------------------
3173 * BOOL ProcessTTYMouse(HWND hWnd, int mevent, int button,
3174 * int xPos, int yPos, WPARAM keys)
3176 * Description:
3177 * This is the central control for all mouse events. Every event
3178 * gets put into a queue to wait for the upper layer.
3180 * The upper's input routine calls checkmouse() which pulls the
3181 * mouse event off the input queue. checkmouse() has a list of
3182 * of screen regions. Some regions correspond to a "menu" item
3183 * (text button at bottom of screen). There is generally one
3184 * region for the central region of the screen.
3186 * Because pine/pico do not interpret mouse drags, we do that here.
3187 * When the user presses the button and drags the mouse across the
3188 * screen this select the text in the region defined by the drag.
3189 * The operation is local to mswin.c, and can only get what text
3190 * is on the screen.
3192 * The one exception is that now pico interprets mouse drag events
3193 * in the body. pico signals that it wants to track the mouse
3194 * by calling mswin_allowmousetrack(). This will 1) turn off
3195 * our mouse tracking and 2) cause mouse movement events to
3196 * be put on the mouse queue.
3199 * Parameters:
3200 * HWND hWnd
3201 * handle to TTY window
3203 * BYTE bOut
3204 * byte from keyboard
3206 /*--------------------------------------------------------------------------*/
3207 LOCAL BOOL
3208 ProcessTTYMouse (HWND hWnd, int mevent, int button,
3209 CORD xPos, CORD yPos, WPARAM winkeys)
3211 int nRow;
3212 int nColumn;
3213 int keys;
3216 * Convert to cell position.
3218 nColumn = (xPos - gpTTYInfo->xOffset) / gpTTYInfo->xChar;
3219 if (xPos < gpTTYInfo->xOffset)
3220 --nColumn;
3221 nRow = (yPos - gpTTYInfo->yOffset) / gpTTYInfo->yChar;
3222 if (yPos < gpTTYInfo->yOffset)
3223 --nRow;
3226 * Convert window's keys.
3228 keys = 0;
3229 if (winkeys & MK_CONTROL)
3230 keys |= M_KEY_CONTROL;
3231 if (winkeys & MK_SHIFT)
3232 keys |= M_KEY_SHIFT;
3234 /* Adjust the cursor */
3235 if((unsigned long) mevent != M_EVENT_UP){
3236 if(gMouseTracking)
3237 mswin_setcursor(MSWIN_CURSOR_IBEAM);
3238 else if(ghCursorCurrent == ghCursorBusy)
3239 mswin_setcursor(MSWIN_CURSOR_BUSY);
3240 else if(mouse_on_key(nRow, nColumn))
3241 mswin_setcursor(MSWIN_CURSOR_HAND);
3242 else if(gMouseTrackCallback)
3243 mswin_setcursor((*gMouseTrackCallback)(nColumn, (long) nRow));
3244 else
3245 mswin_setcursor(MSWIN_CURSOR_ARROW);
3249 * Tracking event or mouse up/down?
3251 if ((unsigned long) mevent == M_EVENT_TRACK) {
3253 * Who is doing the tracking?
3255 if (gAllowMouseTrack) {
3256 /* For tracking, Button info is different. */
3257 if (keys & MK_LBUTTON)
3258 button = M_BUTTON_LEFT;
3259 else if (keys & MK_MBUTTON)
3260 button = M_BUTTON_MIDDLE;
3261 else if (keys & MK_RBUTTON)
3262 button = M_BUTTON_RIGHT;
3263 MQAdd (mevent, button, nRow, nColumn, keys,
3264 MSWIN_MF_REPLACING);
3266 else
3267 SelTrackMouse (nRow, nColumn);
3269 else{
3271 * Tracking. Only start tracking mouse down in the text region
3272 * But allow mouse up anywhere.
3274 if ( (nRow >= 0 && nRow < gpTTYInfo->actNRow &&
3275 nColumn >= 0 && nColumn < gpTTYInfo->actNColumn)
3276 || (unsigned long) mevent == M_EVENT_UP) {
3279 * Mouse tracking. When the mouse goes down we start
3280 * capturing all mouse movement events. If no one else wants
3281 * them we will start defining a text selection.
3283 if ((unsigned long) mevent == M_EVENT_DOWN) {
3284 gMouseTracking = TRUE;
3285 SetCapture (ghTTYWnd);
3286 if (!gAllowMouseTrack && button == M_BUTTON_LEFT)
3287 SelStart (nRow, nColumn);
3289 else {
3290 ReleaseCapture ();
3291 if (!gAllowMouseTrack && button == M_BUTTON_LEFT)
3292 SelFinish (nRow, nColumn);
3293 gMouseTracking = FALSE;
3296 * If right mouse button, toss pop-up menu offering
3297 * cut/copy/paste
3299 if(button == M_BUTTON_RIGHT && SelAvailable()){
3300 UINT fAllowed = (EM_CP | EM_CP_APPEND);
3302 if(gAllowCut)
3303 fAllowed |= EM_CUT;
3305 if(CopyCutPopup(hWnd, fAllowed) == TRUE)
3306 mevent = M_EVENT_TRACK; /* don't add to input queue! */
3311 * Insert event into queue.
3313 if((unsigned long) mevent != M_EVENT_TRACK)
3314 MQAdd (mevent, button, nRow, nColumn, keys, 0);
3318 mswin_showcursor(TRUE); /* make sure it's visible */
3320 #ifdef ACCELERATORS
3321 UpdateAccelerators (hWnd);
3322 #endif
3324 set_time_of_last_input();
3326 return (0); /* Message handled. */
3330 /*---------------------------------------------------------------------------
3331 * BOOL ProcessTimer ()
3333 * Description:
3334 * Process the periodic timer calls.
3337 * Parameters:
3338 * None.
3340 /*--------------------------------------------------------------------------*/
3341 LOCAL void
3342 ProcessTimer (void)
3344 /* Time to deliver an alarm signal? */
3345 if (gAlarmTimeout != 0 && GetTickCount () / 1000 > gAlarmTimeout)
3346 AlarmDeliver ();
3348 /* Time to make the periodic callback. */
3349 if (gPeriodicCallback != NULL &&
3350 GetTickCount() / 1000 > gPeriodicCBTimeout) {
3351 gPeriodicCBTimeout = GetTickCount() / 1000 +
3352 gPeriodicCBTime;
3353 gPeriodicCallback ();
3357 * If tracking the mouse, insert a fake mouse tracking message
3358 * At the last know location of the mouse.
3360 if (gAllowMouseTrack) {
3361 gMTEvent.event = M_EVENT_TRACK;
3362 MQAdd (gMTEvent.event, gMTEvent.button, gMTEvent.nRow,
3363 gMTEvent.nColumn, gMTEvent.keys, MSWIN_MF_REPLACING);
3368 /*---------------------------------------------------------------------------
3369 * BOOL WriteTTYBlock( HWND hWnd, LPSTR lpBlock, int nLength )
3371 * Description:
3372 * Writes block to TTY screen. Nothing fancy - just
3373 * straight TTY.
3375 * Parameters:
3376 * HWND hWnd
3377 * handle to TTY window
3379 * LPSTR lpBlock
3380 * far pointer to block of data
3382 * int nLength
3383 * length of block
3385 /*--------------------------------------------------------------------------*/
3386 LOCAL BOOL
3387 WriteTTYBlock (HWND hWnd, LPTSTR lpBlock, int nLength)
3389 int i, j, width;
3390 PTTYINFO pTTYInfo;
3391 RECT rect;
3392 BOOL fNewLine;
3393 long offset;
3395 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
3396 if (pTTYInfo == NULL)
3397 return (FALSE);
3399 for (i = 0 ; i < nLength; i++) {
3400 switch (lpBlock[i]) {
3401 case ARABIC_LRM:
3402 case ARABIC_RLM:
3403 break;
3405 case ASCII_BEL:
3406 /* Bell */
3407 MessageBeep (0) ;
3408 break ;
3410 case ASCII_BS:
3411 /* Backspace over a whole character */
3412 offset = pscreen_offset_from_cord(pTTYInfo->nRow, pTTYInfo->nColumn, pTTYInfo);
3413 width = (offset > pTTYInfo->nRow * pTTYInfo->actNColumn)
3414 ? scrwidth(pTTYInfo->pScreen+offset-1, 1) : 0;
3416 if(pTTYInfo->nColumn > 0)
3417 pTTYInfo->nColumn = (CORD)(pTTYInfo->nColumn - width);
3419 MoveTTYCursor (hWnd);
3420 break;
3422 case ASCII_CR:
3423 /* Carriage return */
3424 pTTYInfo->nColumn = 0 ;
3425 MoveTTYCursor (hWnd);
3426 if (!pTTYInfo->fNewLine)
3427 break;
3429 /* fall through */
3431 case ASCII_LF:
3432 /* Line feed */
3433 if (++pTTYInfo->nRow == pTTYInfo->actNRow) {
3435 /* Scroll the Screen. */
3437 /* slide rows 1 - n-1 up to row 0 */
3438 memmove ((LPTSTR)pTTYInfo->pScreen,
3439 (LPTSTR) (pTTYInfo->pScreen + pTTYInfo->actNColumn),
3440 (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn * sizeof (TCHAR));
3442 /* initialize new row n-1 */
3443 for(j = (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn;
3444 j < pTTYInfo->actNColumn; j++)
3445 pTTYInfo->pScreen[j] = (TCHAR) ' ';
3448 /* Scroll the Cell Widths */
3449 memmove ((int *)pTTYInfo->pCellWidth,
3450 (int *) (pTTYInfo->pCellWidth + pTTYInfo->actNColumn),
3451 (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn * sizeof (int));
3452 for(j = (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn;
3453 j < pTTYInfo->actNColumn; j++)
3454 pTTYInfo->pCellWidth[j] = pTTYInfo->xChar; /* xChar set yet ? */
3456 /* Scroll the Attributes. */
3458 /* slide rows 1 - n-1 up to row 0 */
3459 memmove ((CharAttrib *) pTTYInfo->pAttrib,
3460 (CharAttrib *) (pTTYInfo->pAttrib + pTTYInfo->actNColumn),
3461 (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn * sizeof(CharAttrib));
3463 /* initialize new row n-1 to zero */
3464 memset ((CharAttrib *) (pTTYInfo->pAttrib +
3465 (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn),
3466 0, pTTYInfo->actNColumn*sizeof(CharAttrib));
3468 pTTYInfo->screenDirty = TRUE;
3469 pTTYInfo->eraseScreen = TRUE;
3470 InvalidateRect (hWnd, NULL, FALSE);
3471 --pTTYInfo->nRow;
3474 MoveTTYCursor (hWnd);
3475 break;
3477 default:
3478 offset = pscreen_offset_from_cord(pTTYInfo->nRow, pTTYInfo->nColumn, pTTYInfo);
3479 pTTYInfo->pScreen[offset] = lpBlock[i];
3480 pTTYInfo->pCellWidth[offset] = wcellwidth((UCS)lpBlock[i]) * pTTYInfo->xChar;
3481 pTTYInfo->pAttrib[offset] = pTTYInfo->curAttrib;
3482 rect.left = (pTTYInfo->nColumn * pTTYInfo->xChar) +
3483 pTTYInfo->xOffset;
3484 rect.right = rect.left + pTTYInfo->xChar;
3485 rect.top = (pTTYInfo->nRow * pTTYInfo->yChar) +
3486 pTTYInfo->yOffset;
3487 rect.bottom = rect.top + pTTYInfo->yChar;
3488 pTTYInfo->screenDirty = TRUE;
3489 InvalidateRect (hWnd, &rect, FALSE);
3491 /* Line Wrap. */
3492 if (pTTYInfo->nColumn < pTTYInfo->actNColumn - 1)
3493 pTTYInfo->nColumn++ ;
3494 else if (pTTYInfo->autoWrap == WRAP_ON ||
3495 (pTTYInfo->autoWrap == WRAP_NO_SCROLL &&
3496 pTTYInfo->nRow < pTTYInfo->actNRow - 1)) {
3497 fNewLine = pTTYInfo->fNewLine;
3498 pTTYInfo->fNewLine = FALSE;
3499 WriteTTYBlock (hWnd, TEXT("\r\n"), 2);
3500 pTTYInfo->fNewLine = fNewLine;
3502 break;
3505 return (TRUE);
3509 /*---------------------------------------------------------------------------
3510 * BOOL WriteTTYText ( HWND hWnd, LPSTR lpBlock, int nLength )
3512 * Description:
3513 * Like WriteTTYBlock but optimized for strings that are text only,
3514 * no carrage control characters.
3516 * Parameters:
3517 * HWND hWnd
3518 * handle to TTY window
3520 * LPSTR lpBlock
3521 * far pointer to block of data
3523 * int nLength
3524 * length of block
3526 /*--------------------------------------------------------------------------*/
3527 LOCAL BOOL
3528 WriteTTYText (HWND hWnd, LPTSTR lpText, int nLength)
3530 int i;
3531 PTTYINFO pTTYInfo;
3532 RECT rect;
3533 long offset, endOffset;
3534 long colEnd;
3535 long screenEnd;
3536 int screenwidth;
3539 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
3540 if (pTTYInfo == NULL)
3541 return ( FALSE );
3544 /* Calculate offset of cursor, end of current column, and end of screen */
3545 offset = pscreen_offset_from_cord(pTTYInfo->nRow, pTTYInfo->nColumn, pTTYInfo);
3547 colEnd = (pTTYInfo->nRow + 1) * pTTYInfo->actNColumn;
3548 screenEnd = pTTYInfo->actNRow * pTTYInfo->actNColumn;
3551 /* Text is allowed to wrap around to subsequent lines, but not past end
3552 * of screen */
3553 endOffset = offset + nLength;
3554 if (endOffset >= screenEnd) {
3555 nLength = screenEnd - offset;
3556 endOffset = offset + nLength - 1; /* Last cell, not one past last */
3560 /* Calculate bounding rectangle. */
3561 if (endOffset <= colEnd) {
3562 /* Single line. */
3564 screenwidth = scrwidth(lpText, nLength);
3566 rect.left = (pTTYInfo->nColumn * pTTYInfo->xChar) + pTTYInfo->xOffset;
3567 rect.right = rect.left + (pTTYInfo->xChar * screenwidth);
3568 rect.top = (pTTYInfo->nRow * pTTYInfo->yChar) + pTTYInfo->yOffset;
3569 rect.bottom = rect.top + pTTYInfo->yChar;
3570 /* Advance cursor on cur line but not past end. */
3571 pTTYInfo->nColumn = (CORD)MIN(pTTYInfo->nColumn + screenwidth,
3572 pTTYInfo->actNColumn - 1);
3574 else {
3575 /* Wraps across multiple lines. Calculate one rect to cover all
3576 * lines. */
3577 rect.left = 0;
3578 rect.right = pTTYInfo->xSize;
3579 rect.top = (pTTYInfo->nRow * pTTYInfo->yChar) + pTTYInfo->yOffset;
3580 rect.bottom = ((((offset + nLength) / pTTYInfo->actNColumn) + 1) *
3581 pTTYInfo->yChar) + pTTYInfo->yOffset;
3582 pTTYInfo->nRow = (CORD)(endOffset / pTTYInfo->actNColumn);
3583 pTTYInfo->nColumn = (CORD)(endOffset % pTTYInfo->actNColumn);
3587 /* Apply text and attributes to screen in one smooth motion. */
3588 for(i = 0; i < nLength; i++)
3589 (pTTYInfo->pScreen+offset)[i] = lpText[i];
3590 for(i = 0; i < nLength; i++)
3591 (pTTYInfo->pCellWidth+offset)[i] = wcellwidth((UCS)lpText[i]) * pTTYInfo->xChar;
3592 for(i = 0; i < nLength; i++)
3593 pTTYInfo->pAttrib[offset+i] = pTTYInfo->curAttrib;
3595 /* Invalidate rectangle */
3596 pTTYInfo->screenDirty = TRUE;
3597 InvalidateRect (hWnd, &rect, FALSE);
3598 return (TRUE);
3602 /*---------------------------------------------------------------------------
3603 * BOOL WriteTTYChar (HWND hWnd, char ch)
3605 * Description:
3606 * Write a single character to the cursor position and advance the
3607 * cursor. Does not handle carage control.
3609 * Parameters:
3610 * HWND hWnd
3611 * handle to TTY window
3613 * char ch
3614 * character being written.
3616 /*--------------------------------------------------------------------------*/
3617 LOCAL BOOL
3618 WriteTTYChar (HWND hWnd, TCHAR ch)
3620 PTTYINFO pTTYInfo;
3621 RECT rect;
3622 long offset;
3625 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
3626 if (pTTYInfo == NULL)
3627 return (FALSE);
3629 offset = (pTTYInfo->nRow * pTTYInfo->actNColumn) +
3630 pTTYInfo->nColumn;
3632 *(pTTYInfo->pScreen + offset) = ch;
3633 pTTYInfo->pCellWidth[offset] = wcellwidth((UCS)ch) * pTTYInfo->xChar;
3634 pTTYInfo->pAttrib[offset] = pTTYInfo->curAttrib;
3636 rect.left = (pTTYInfo->nColumn * pTTYInfo->xChar) + pTTYInfo->xOffset;
3637 rect.right = rect.left + pTTYInfo->xChar;
3638 rect.top = (pTTYInfo->nRow * pTTYInfo->yChar) + pTTYInfo->yOffset;
3639 rect.bottom = rect.top + pTTYInfo->yChar;
3640 pTTYInfo->screenDirty = TRUE;
3641 InvalidateRect (hWnd, &rect, FALSE);
3645 /* Line Wrap. */
3646 if (pTTYInfo->nColumn < pTTYInfo->actNColumn - 1)
3647 pTTYInfo->nColumn++ ;
3648 else if ((pTTYInfo->autoWrap == WRAP_ON ||
3649 pTTYInfo->autoWrap == WRAP_NO_SCROLL) &&
3650 pTTYInfo->nRow < pTTYInfo->actNRow - 1) {
3651 pTTYInfo->nRow++;
3652 pTTYInfo->nColumn = 0;
3654 return (TRUE);
3658 /*---------------------------------------------------------------------------
3659 * VOID GoModalDialogBoxParam( HINSTANCE hInstance,
3660 * LPTSTR lpszTemplate, HWND hWnd,
3661 * DLGPROC lpDlgProc, LPARAM lParam )
3663 * Description:
3664 * It is a simple utility function that simply performs the
3665 * MPI and invokes the dialog box with a DWORD paramter.
3667 * Parameters:
3668 * similar to that of DialogBoxParam() with the exception
3669 * that the lpDlgProc is not a procedure instance
3671 /*--------------------------------------------------------------------------*/
3672 LOCAL VOID
3673 GoModalDialogBoxParam( HINSTANCE hInstance, LPTSTR lpszTemplate,
3674 HWND hWnd, DLGPROC lpDlgProc, LPARAM lParam )
3676 DLGPROC lpProcInstance ;
3678 lpProcInstance = (DLGPROC) MakeProcInstance( (FARPROC) lpDlgProc,
3679 hInstance ) ;
3680 DialogBoxParam( hInstance, lpszTemplate, hWnd, lpProcInstance, lParam ) ;
3681 FreeProcInstance( (FARPROC) lpProcInstance ) ;
3685 /*---------------------------------------------------------------------------
3686 * BOOL FAR PASCAL __export AboutDlgProc( HWND hDlg, UINT uMsg,
3687 * WPARAM wParam, LPARAM lParam )
3689 * Description:
3690 * Simulates the Windows System Dialog Box.
3692 * Parameters:
3693 * Same as standard dialog procedures.
3695 /*--------------------------------------------------------------------------*/
3696 BOOL FAR PASCAL __export
3697 AboutDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
3699 switch (uMsg) {
3700 case WM_INITDIALOG:
3702 TCHAR szTemp [81];
3704 /* sets up version number for PINE */
3705 GetDlgItemText (hDlg, IDD_VERSION, szTemp, sizeof(szTemp)/sizeof(TCHAR));
3706 /* szTemp is unicode, mswin_compilation_date etc are cast as %S in mswin.rc */
3707 _sntprintf (TempBuf, sizeof(TempBuf)/sizeof(TCHAR), szTemp, mswin_specific_winver(),
3708 mswin_majorver(), mswin_minorver(),
3709 mswin_compilation_remarks(),
3710 mswin_compilation_date());
3711 SetDlgItemText (hDlg, IDD_VERSION, (LPTSTR) TempBuf);
3713 /* get by-line */
3714 LoadString (GET_HINST (hDlg), IDS_BYLINE, TempBuf,
3715 sizeof(TempBuf) / sizeof(TCHAR));
3716 SetDlgItemText (hDlg, IDD_BYLINE, TempBuf);
3719 return ( TRUE ) ;
3721 case WM_CLOSE:
3722 EndDialog( hDlg, TRUE ) ;
3723 return ( TRUE ) ;
3725 case WM_COMMAND:
3726 switch((WORD) wParam){
3727 case IDD_OK :
3728 EndDialog( hDlg, TRUE ) ;
3729 return ( TRUE ) ;
3731 default :
3732 break;
3735 break;
3737 return ( FALSE ) ;
3739 } /* end of AboutDlgProc() */
3742 /*---------------------------------------------------------------------------
3744 * Description:
3745 * Simulates the Windows System Dialog Box.
3747 * Parameters:
3748 * Same as standard dialog procedures.
3750 /*--------------------------------------------------------------------------*/
3751 BOOL FAR PASCAL __export
3752 SplashDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
3754 static HBITMAP hbmpSplash;
3756 switch (uMsg) {
3757 case WM_INITDIALOG:
3758 if(hbmpSplash = LoadBitmap(GET_HINST(hDlg),
3759 MAKEINTRESOURCE(ALPINESPLASH))){
3760 BITMAP stBitmap;
3761 int cx, cy;
3763 cx = GetSystemMetrics(SM_CXSCREEN);
3764 cy = GetSystemMetrics(SM_CYSCREEN);
3765 GetObject(hbmpSplash, sizeof(BITMAP), &stBitmap);
3767 SetWindowPos(hDlg, HWND_TOPMOST,
3768 (cx - stBitmap.bmWidth) / 2,
3769 (cy - stBitmap.bmHeight) / 2,
3770 stBitmap.bmWidth, stBitmap.bmHeight,
3771 SWP_NOCOPYBITS /* | SWP_SHOWWINDOW */);
3774 return(TRUE);
3776 case WM_CTLCOLORDLG :
3777 return(TRUE);
3779 case WM_ERASEBKGND :
3781 HDC hMemDC;
3782 POINT stPoint;
3783 BITMAP stBitmap;
3784 HGDIOBJ hObject;
3786 if((hMemDC = CreateCompatibleDC((HDC) wParam)) != NULL){
3787 hObject = SelectObject(hMemDC, hbmpSplash);
3788 SetMapMode(hMemDC, GetMapMode((HDC) wParam));
3790 GetObject(hbmpSplash, sizeof(BITMAP), &stBitmap);
3791 stPoint.x = stBitmap.bmWidth;
3792 stPoint.y = stBitmap.bmHeight;
3793 DPtoLP((HDC) wParam, &stPoint, 1);
3795 BitBlt((HDC) wParam,
3796 0, 0, stPoint.x, stPoint.y,
3797 hMemDC, 0, 0, SRCCOPY);
3798 SelectObject(hMemDC, hObject);
3799 DeleteDC(hMemDC) ;
3802 return(TRUE);
3805 break;
3807 case WM_CLOSE:
3808 DestroyWindow(hDlg);
3809 return(TRUE);
3811 case WM_DESTROY :
3812 if(hbmpSplash)
3813 DeleteObject(hbmpSplash);
3815 break;
3817 case WM_COMMAND: /* No commands! */
3818 DestroyWindow(hDlg);
3819 return(TRUE);
3822 return(FALSE);
3827 #if 0
3828 UINT APIENTRY
3829 SelectTTYFontHook(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
3831 switch(uMsg){
3832 case WM_INITDIALOG :
3835 * Deactivate the Style combo box...
3837 HWND hWnd = GetDlgItem(hDlg, cmb2);
3838 EnableWindow(hWnd, FALSE);
3839 SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW);
3840 return(TRUE);
3843 break;
3845 case WM_COMMAND :
3846 switch ((WORD) wParam) {
3847 case psh3 :
3849 LOGFONT curfont;
3851 SendMessage(hDlg, WM_CHOOSEFONT_GETLOGFONT,
3852 0, (LPARAM) &curfont);
3853 ResetTTYFont (ghTTYWnd, gpTTYInfo, &curfont);
3854 return (TRUE);
3857 break;
3859 default :
3860 break;
3863 break;
3865 default :
3866 break;
3869 return(FALSE);
3871 #endif
3874 /*---------------------------------------------------------------------------
3875 * BOOL SelectTTYFont( HWND hDlg )
3877 * Description:
3878 * Selects the current font for the TTY screen.
3879 * Uses the Common Dialog ChooseFont() API.
3881 * Parameters:
3882 * HWND hDlg
3883 * handle to settings dialog
3885 /*--------------------------------------------------------------------------*/
3886 LOCAL BOOL
3887 SelectTTYFont (HWND hWnd)
3889 CHOOSEFONT cfTTYFont;
3890 LOGFONT newFont, origFont;
3891 PTTYINFO pTTYInfo;
3893 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
3894 if (pTTYInfo == NULL)
3895 return (FALSE);
3897 memcpy (&newFont, &gpTTYInfo->lfTTYFont, sizeof (LOGFONT));
3898 memcpy (&origFont, &gpTTYInfo->lfTTYFont, sizeof (LOGFONT));
3900 cfTTYFont.lStructSize = sizeof (CHOOSEFONT);
3901 cfTTYFont.hwndOwner = hWnd ;
3902 cfTTYFont.hDC = NULL ;
3903 cfTTYFont.lpLogFont = &newFont;
3904 cfTTYFont.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY |
3905 CF_INITTOLOGFONTSTRUCT |
3906 #if 0
3907 CF_FORCEFONTEXIST | CF_LIMITSIZE |
3908 CF_ENABLEHOOK | CF_APPLY;
3909 #else
3910 CF_FORCEFONTEXIST | CF_LIMITSIZE;
3911 #endif
3912 cfTTYFont.nSizeMin = FONT_MIN_SIZE;
3913 cfTTYFont.nSizeMax = FONT_MAX_SIZE;
3914 cfTTYFont.lCustData = (long) 0 ;
3915 #if 0
3916 cfTTYFont.lpfnHook = SelectTTYFontHook ;
3917 #else
3918 cfTTYFont.lpfnHook = NULL;
3919 #endif
3920 cfTTYFont.lpTemplateName = NULL ;
3921 cfTTYFont.hInstance = GET_HINST (hWnd);
3925 if (ChooseFont (&cfTTYFont)) {
3926 ResetTTYFont (hWnd, pTTYInfo, &newFont);
3928 #if 0
3929 else{
3930 ResetTTYFont (hWnd, pTTYInfo, &origFont);
3932 #endif
3934 return (TRUE);
3939 * Set a specific color (forground, background, reverse, normal) to
3940 * the color specified by name.
3942 LOCAL void
3943 SetColorAttribute (COLORREF *cf, char *colorName)
3945 /* color name not in table. Try converting RGB string. */
3946 ConvertRGBString (colorName, cf);
3948 /* Redraw screen. */
3949 gpTTYInfo->screenDirty = TRUE;
3950 gpTTYInfo->eraseScreen = TRUE;
3951 InvalidateRect (ghTTYWnd, NULL, FALSE);
3956 * Set current color attribute to reverse color
3958 void
3959 SetReverseColor()
3961 FlushWriteAccum ();
3962 gpTTYInfo->curAttrib.rgbFG = gpTTYInfo->rgbRFGColor;
3963 gpTTYInfo->curAttrib.rgbBG = gpTTYInfo->rgbRBGColor;
3968 * Convert a string to an integer.
3970 LOCAL BOOL
3971 ScanInt (char *str, int min, int max, int *val)
3973 char *c;
3974 int v;
3975 int neg = 1;
3978 if (str == NULL) return (FALSE);
3979 if (*str == '\0' || strlen (str) > 9) return (FALSE);
3981 /* Check for a negative sign. */
3982 if (*str == '-') {
3983 neg = -1;
3984 ++str;
3987 /* Check for all digits. */
3988 for (c = str; *c != '\0'; ++c) {
3989 if (!isdigit((unsigned char)*c))
3990 return (FALSE);
3993 /* Convert from ascii to int. */
3994 v = atoi (str) * neg;
3996 /* Check constraints. */
3997 if (v < min || v > max)
3998 return (FALSE);
3999 *val = v;
4000 return (TRUE);
4005 * Convert a RGB string to a color ref. The string should look like:
4006 * rrr,ggg,bbb
4007 * where rrr, ggg, and bbb are numbers between 0 and 255 that represent
4008 * red, gree, and blue values. Must be comma seperated.
4009 * Returns:
4010 * TRUE - Successfully converted string.
4011 * FALSE - Bad format, 'cf' unchanged.
4013 LOCAL BOOL
4014 ConvertRGBString (char *colorName, COLORREF *cf)
4016 int i, j, n, rgb[3];
4017 MSWINColor *ct;
4019 if(!colorName)
4020 return(FALSE);
4022 /* Is the name in the global color table? */
4023 for(ct = MSWINColorTable; ct->colorName; ct++)
4024 if(!struncmp(ct->colorName, colorName, (int)strlen(ct->colorName))){
4025 *cf = ct->colorRef;
4026 return(TRUE);
4029 /* Not a named color, try RRR,GGG,BBB */
4030 for(i = 0; i < 3; i++){
4031 if(i && *colorName++ != ',')
4032 return(FALSE);
4034 for(rgb[i] = 0, j = 0; j < 3; j++)
4035 if((n = *colorName++ - '0') < 0 || n > 9)
4036 return(FALSE);
4037 else
4038 rgb[i] = (rgb[i] * 10) + n;
4041 *cf = RGB (rgb[0], rgb[1], rgb[2]);
4042 return (TRUE);
4046 LOCAL char *
4047 ConvertStringRGB(char *colorName, size_t ncolorName, COLORREF colorRef)
4049 MSWINColor *cf;
4051 for(cf = MSWINColorTable;
4052 cf->colorName && cf->colorRef != colorRef;
4053 cf++)
4056 if(cf->colorName){
4057 strncpy(colorName, cf->colorName, ncolorName);
4058 colorName[ncolorName-1] = '\0';
4060 else
4061 snprintf(colorName, ncolorName, "%.3d,%.3d,%.3d",
4062 GetRValue(colorRef), GetGValue(colorRef), GetBValue(colorRef));
4064 return(colorName);
4069 * Map from integer color value to canonical color name.
4071 char *
4072 colorx(int color)
4074 MSWINColor *ct;
4075 static char cbuf[RGBLEN+1];
4077 if(color < fullColorTableSize){
4078 ct = &MSWINColorTable[color];
4079 if(ct->canonicalName)
4080 return(ct->canonicalName);
4083 /* not supposed to get here */
4084 snprintf(cbuf, sizeof(cbuf), "color%03.3d", color);
4085 return(cbuf);
4090 * Argument is a color name which could be an RGB string, a name like "blue",
4091 * or a name like "color011".
4093 * Returns a pointer to the canonical name of the color.
4095 char *
4096 color_to_canonical_name(char *s)
4098 int i, j, n, rgb[3];
4099 MSWINColor *ct;
4100 COLORREF cr;
4101 static char cn[RGBLEN+1];
4103 if(!s)
4104 return(NULL);
4106 if(!struncmp(s, MATCH_NORM_COLOR, RGBLEN) || !struncmp(s, MATCH_NONE_COLOR, RGBLEN))
4107 return(s);
4109 for(ct = MSWINColorTable; ct->colorName; ct++)
4110 if(!struncmp(ct->colorName, s, (int)strlen(ct->colorName)))
4111 break;
4113 if(ct->colorName)
4114 return(ct->canonicalName);
4116 /* maybe it is RGB? */
4117 for(i = 0; i < 3; i++){
4118 if(i && *s++ != ',')
4119 return("");
4121 for(rgb[i] = 0, j = 0; j < 3; j++)
4122 if((n = *s++ - '0') < 0 || n > 9)
4123 return("");
4124 else
4125 rgb[i] = (rgb[i] * 10) + n;
4128 cr = RGB(rgb[0], rgb[1], rgb[2]);
4131 * Now compare that RGB against the color table RGBs. If it is
4132 * in the table, return the canonical name, else return the RGB string.
4134 for(ct = MSWINColorTable; ct->colorName; ct++)
4135 if(ct->colorRef == cr)
4136 break;
4138 if(ct->colorName)
4139 return(ct->canonicalName);
4140 else{
4141 snprintf(cn, sizeof(cn), "%.3d,%.3d,%.3d",
4142 GetRValue(cr), GetGValue(cr), GetBValue(cr));
4143 return(cn);
4148 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4150 * Toolbar setup routines.
4152 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
4153 LOCAL void
4154 TBToggle (HWND hWnd)
4156 PTTYINFO pTTYInfo;
4159 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4160 if (pTTYInfo == NULL)
4161 return;
4163 if (pTTYInfo->toolBarSize > 0)
4164 TBHide (hWnd);
4165 else
4166 TBShow (hWnd);
4170 LOCAL void
4171 TBPosToggle (HWND hWnd)
4173 PTTYINFO pTTYInfo;
4176 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4177 if (pTTYInfo == NULL)
4178 return;
4180 pTTYInfo->toolBarTop = !pTTYInfo->toolBarTop;
4181 if(pTTYInfo->hTBWnd){
4182 TBHide (hWnd);
4183 TBShow (hWnd);
4188 LOCAL void
4189 TBShow (HWND hWnd)
4191 PTTYINFO pTTYInfo;
4192 RECT rc;
4195 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4196 if (pTTYInfo == NULL)
4197 return;
4201 * Make sure the tool bar not already shown.
4203 if (pTTYInfo->toolBarSize > 0)
4204 return;
4209 * Make procinstance for dialog funciton.
4211 HideCaret (hWnd);
4212 if (gToolBarProc == NULL)
4213 gToolBarProc = (DLGPROC) MakeProcInstance( (FARPROC) ToolBarProc,
4214 ghInstance ) ;
4215 if (gTBBtnProc == NULL)
4216 gTBBtnProc = (WNDPROC) MakeProcInstance( (FARPROC) TBBtnProc,
4217 ghInstance ) ;
4221 * Create the dialog box.
4223 pTTYInfo->hTBWnd = CreateDialog (ghInstance,
4224 MAKEINTRESOURCE (pTTYInfo->curToolBarID),
4225 hWnd,
4226 gToolBarProc);
4227 if (pTTYInfo->hTBWnd == NULL) {
4228 ShowCaret (hWnd);
4229 return;
4232 SetFocus (hWnd);
4236 * Adjust the window size.
4238 GetWindowRect (pTTYInfo->hTBWnd, &rc); /* Get Toolbar size. */
4239 pTTYInfo->toolBarSize = (CORD)(rc.bottom - rc.top);
4241 GetClientRect (hWnd, &rc); /* Get TTY window size. */
4242 SizeTTY (hWnd, 0, (CORD)rc.bottom, (CORD)rc.right);
4243 ShowCaret (hWnd);
4247 LOCAL void
4248 TBHide (HWND hWnd)
4250 PTTYINFO pTTYInfo;
4251 RECT rc;
4253 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4254 if (pTTYInfo == NULL)
4255 return;
4258 if (pTTYInfo->toolBarSize == 0)
4259 return;
4261 DestroyWindow (pTTYInfo->hTBWnd);
4262 pTTYInfo->hTBWnd = NULL;
4263 if (pTTYInfo->toolBarBtns != NULL)
4264 MemFree (pTTYInfo->toolBarBtns);
4265 pTTYInfo->toolBarBtns = NULL;
4269 * Adjust the window size.
4271 pTTYInfo->toolBarSize = 0;
4272 GetClientRect (hWnd, &rc);
4273 SizeTTY (hWnd, 0, (CORD)rc.bottom, (CORD)rc.right);
4277 LOCAL void
4278 TBSwap (HWND hWnd, int newID)
4280 PTTYINFO pTTYInfo;
4281 RECT rc;
4283 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4284 if (pTTYInfo == NULL)
4285 return;
4287 if (pTTYInfo->toolBarSize == 0 || pTTYInfo->curToolBarID == newID)
4288 return;
4291 * Dispose of old tool bar window.
4293 HideCaret (hWnd);
4295 DestroyWindow (pTTYInfo->hTBWnd);
4296 pTTYInfo->hTBWnd = NULL;
4297 if (pTTYInfo->toolBarBtns != NULL)
4298 MemFree (pTTYInfo->toolBarBtns);
4299 pTTYInfo->toolBarBtns = NULL;
4304 * Create the new dialog box.
4306 pTTYInfo->hTBWnd = CreateDialog (ghInstance,
4307 MAKEINTRESOURCE (newID),
4308 hWnd,
4309 gToolBarProc);
4310 if (pTTYInfo->hTBWnd == NULL) {
4311 ShowCaret (hWnd);
4312 return;
4314 pTTYInfo->curToolBarID = newID;
4315 SetFocus (hWnd); /* Return focus to parent. */
4319 * Fit new tool bar into old tool bars position. This assumes that
4320 * all tool bars are about the same height.
4322 GetClientRect (hWnd, &rc); /* Get TTY window size. */
4323 if (pTTYInfo->toolBarTop)
4324 /* Position at top of window. */
4325 SetWindowPos (pTTYInfo->hTBWnd, HWND_TOP,
4326 0, 0,
4327 rc.right, pTTYInfo->toolBarSize,
4328 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
4329 else
4330 /* Position at bottom of window. */
4331 SetWindowPos (pTTYInfo->hTBWnd, HWND_TOP,
4332 0, pTTYInfo->ySize - pTTYInfo->toolBarSize,
4333 rc.right, pTTYInfo->toolBarSize,
4334 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
4336 ShowCaret (hWnd);
4340 BOOL FAR PASCAL __export
4341 ToolBarProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4343 RECT rc;
4344 BOOL ret;
4345 int height;
4346 HBRUSH hBrush;
4347 HWND hCld;
4348 int btnCount;
4349 int i;
4350 PTTYINFO pTTYInfo;
4353 pTTYInfo = gpTTYInfo;
4355 ret = FALSE;
4356 switch (msg) {
4358 case WM_INITDIALOG:
4359 /* Fit dialog to window. */
4360 GetWindowRect (hWnd, &rc);
4361 height = rc.bottom - rc.top;
4362 GetClientRect (GetParent (hWnd), &rc);
4363 SetWindowPos (hWnd, HWND_TOP, 0, 0, rc.right, height,
4364 SWP_NOZORDER | SWP_NOACTIVATE);
4366 /* Count child windows.*/
4367 btnCount = 0;
4368 for (hCld = GetWindow (hWnd, GW_CHILD);
4369 hCld;
4370 hCld = GetWindow (hCld, GW_HWNDNEXT))
4371 ++btnCount;
4373 /* Allocate a list of previous child procs. */
4374 if (pTTYInfo->toolBarBtns != NULL)
4375 MemFree (pTTYInfo->toolBarBtns);
4376 pTTYInfo->toolBarBtns = MemAlloc (sizeof (BtnList) * (btnCount + 1));
4378 /* Subclass all child windows. */
4379 for (i = 0, hCld = GetWindow (hWnd, GW_CHILD);
4380 hCld;
4381 ++i, hCld = GetWindow (hCld, GW_HWNDNEXT)) {
4382 pTTYInfo->toolBarBtns[i].wndID = GET_ID (hCld);
4383 pTTYInfo->toolBarBtns[i].wndProc =
4384 (WNDPROC)(LONG_PTR)MyGetWindowLongPtr (hCld,
4385 GWLP_WNDPROC);
4386 MySetWindowLongPtr (hCld, GWLP_WNDPROC, (void *)(LONG_PTR)TBBtnProc);
4388 pTTYInfo->toolBarBtns[i].wndID = 0;
4389 pTTYInfo->toolBarBtns[i].wndProc = NULL;
4391 ret = FALSE;
4392 break;
4395 case WM_COMMAND:
4396 if (wParam >= KS_RANGESTART && wParam <= KS_RANGEEND){
4397 ProcessMenuItem (GetParent (hWnd), wParam);
4398 /* Set input focus back to parent. */
4399 SetFocus (GetParent (hWnd));
4400 ret = TRUE;
4401 break;
4403 break;
4405 #ifdef WIN32
4406 case WM_CTLCOLORBTN:
4407 #else
4408 case WM_CTLCOLOR:
4409 #endif
4410 if (HIWORD (lParam) == CTLCOLOR_DLG) {
4411 if(pTTYInfo->hTBBrush != NULL){
4412 DeleteObject(pTTYInfo->hTBBrush);
4413 pTTYInfo->hTBBrush = NULL;
4416 hBrush = CreateSolidBrush (GetSysColor (COLOR_ACTIVEBORDER));
4417 return ((BOOL)!!(pTTYInfo->hTBBrush = hBrush));
4420 return (ret);
4425 * Subclass toolbar button windows.
4427 * These buttons will automatically return the input focus to
4428 * the toolbar's parent
4430 LRESULT FAR PASCAL __export
4431 TBBtnProc (HWND hBtn, UINT uMsg, WPARAM wParam, LPARAM lParam)
4433 PTTYINFO pTTYInfo;
4434 HWND hPrnt;
4435 int i;
4436 WORD id;
4437 LRESULT ret;
4438 WNDPROC wndProc;
4442 * Find previous window proc.
4444 pTTYInfo = gpTTYInfo;
4445 id = GET_ID (hBtn);
4446 for (i = 0; pTTYInfo->toolBarBtns[i].wndID != 0; ++i)
4447 if (pTTYInfo->toolBarBtns[i].wndID == id)
4448 goto FoundWindow;
4449 /* Whoops! Didn't find window, don't know how to pass message. */
4450 return (0);
4453 FoundWindow:
4454 wndProc = pTTYInfo->toolBarBtns[i].wndProc;
4458 if (uMsg == WM_LBUTTONUP || uMsg == WM_MBUTTONUP || uMsg == WM_RBUTTONUP) {
4460 * On mouse button up restore input focus to IDC_RESPONCE, which
4461 * processes keyboard input.
4463 ret = CallWindowProc (wndProc, hBtn, uMsg, wParam, lParam);
4464 hPrnt = GetParent (GetParent (hBtn));
4465 if (hPrnt)
4466 SetFocus (hPrnt);
4467 return (ret);
4470 return (CallWindowProc (wndProc, hBtn, uMsg, wParam, lParam));
4475 * return bitmap of allowed Edit Menu items
4477 LOCAL UINT
4478 UpdateEditAllowed(HWND hWnd)
4480 PTTYINFO pTTYInfo;
4481 UINT fAccel = EM_NONE;
4483 if((pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO)) != NULL){
4484 if(EditPasteAvailable())
4485 fAccel |= (EM_PST | EM_PST_ABORT);
4486 else if(IsClipboardFormatAvailable (CF_UNICODETEXT) && gPasteEnabled)
4487 fAccel |= EM_PST;
4489 if(SelAvailable()){
4490 fAccel |= (EM_CP | EM_CP_APPEND);
4492 else{
4493 if(gAllowCut)
4494 fAccel |= EM_CUT;
4496 if(gAllowCopy)
4497 fAccel |= (EM_CP | EM_CP_APPEND);
4500 if (pTTYInfo->menuItems[KS_WHEREIS - KS_RANGESTART].miActive)
4501 fAccel |= EM_FIND;
4503 return(fAccel);
4507 #ifdef ACCELERATORS
4508 #ifdef ACCELERATORS_OPT
4509 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4511 * Accelorator key routines.
4513 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
4514 LOCAL void
4515 AccelCtl (HWND hWnd, int ctl, BOOL saveChange)
4517 PTTYINFO pTTYInfo;
4518 BOOL load, changed;
4521 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4522 if (pTTYInfo == NULL)
4523 return;
4525 switch (ctl) {
4526 case ACCEL_LOAD :
4527 load = TRUE;
4528 break;
4529 case ACCEL_UNLOAD :
4530 load = FALSE;
4531 break;
4532 case ACCEL_TOGGLE :
4533 load = pTTYInfo->hAccel == NULL;
4534 break;
4535 default :
4536 load = FALSE;
4537 break;
4540 changed = FALSE;
4541 if (load && pTTYInfo->hAccel == NULL) {
4542 /* Load em up. */
4543 pTTYInfo->hAccel = LoadAccelerators (ghInstance,
4544 MAKEINTRESOURCE (IDR_ACCEL_PINE));
4545 changed = TRUE;
4547 else if(!load && pTTYInfo->hAccel) {
4548 /* unload em. */
4549 FreeResource (pTTYInfo->hAccel);
4550 pTTYInfo->hAccel = NULL;
4551 changed = TRUE;
4554 if (changed && saveChange)
4555 DidResize (pTTYInfo);
4557 #endif
4560 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4562 * Accelorator key routines.
4564 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
4565 LOCAL void
4566 AccelManage (HWND hWnd, long accels)
4568 PTTYINFO pTTYInfo;
4569 ACCEL accelarray[EM_MAX_ACCEL];
4570 int n;
4571 static ACCEL am_cp = {
4572 FVIRTKEY | FCONTROL | FSHIFT | FNOINVERT, 'C', IDM_EDIT_COPY
4574 static ACCEL am_cp_append = {
4575 FVIRTKEY | FCONTROL | FALT | FNOINVERT, 'C', IDM_EDIT_COPY_APPEND
4577 static ACCEL am_find = {
4578 FVIRTKEY | FCONTROL | FSHIFT | FNOINVERT, 'F', IDM_MI_WHEREIS
4580 static ACCEL am_pst = {
4581 FVIRTKEY | FCONTROL | FSHIFT | FNOINVERT, 'V', IDM_EDIT_PASTE
4583 static ACCEL am_pst_abort = {
4584 FVIRTKEY | FCONTROL | FALT | FNOINVERT, 'V', IDM_EDIT_CANCEL_PASTE
4586 static ACCEL am_cut = {
4587 FVIRTKEY | FCONTROL | FSHIFT | FNOINVERT, 'X', IDM_EDIT_CUT
4590 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4591 if (pTTYInfo == NULL || pTTYInfo->fAccel == (UINT)accels)
4592 return;
4594 if(pTTYInfo->hAccel){
4595 DestroyAcceleratorTable(pTTYInfo->hAccel);
4596 pTTYInfo->hAccel = NULL;
4597 pTTYInfo->fAccel = EM_NONE;
4600 n = 0;
4602 if(accels & EM_CP)
4603 accelarray[n++] = am_cp;
4605 if(accels & EM_CP_APPEND)
4606 accelarray[n++] = am_cp_append;
4608 if(accels & EM_FIND)
4609 accelarray[n++] = am_find;
4611 if(accels & EM_PST)
4612 accelarray[n++] = am_pst;
4614 if(accels & EM_PST_ABORT)
4615 accelarray[n++] = am_pst_abort;
4617 if(accels & EM_CUT)
4618 accelarray[n++] = am_cut;
4620 /* Load em up. */
4621 if(n && (pTTYInfo->hAccel = CreateAcceleratorTable(accelarray, n)))
4622 pTTYInfo->fAccel = accels;
4623 else
4624 pTTYInfo->fAccel = EM_NONE;
4628 LOCAL void
4629 UpdateAccelerators (HWND hWnd)
4631 AccelManage (hWnd, UpdateEditAllowed(hWnd));
4633 #endif
4636 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4638 * Mouse Selection routines
4640 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
4642 LOCAL BOOL SelSelected = FALSE;
4643 LOCAL BOOL SelTracking = FALSE;
4644 LOCAL int SelAnchorRow;
4645 LOCAL int SelAnchorCol;
4646 LOCAL int SelPointerRow;
4647 LOCAL int SelPointerCol;
4648 typedef struct {
4649 TCHAR *pRow;
4650 int len;
4651 } CopyRow;
4654 LOCAL void
4655 SelRSet (int oStart, int oEnd)
4657 CharAttrib *pca;
4659 for (pca = gpTTYInfo->pAttrib + oStart; oStart < oEnd; ++pca, ++oStart)
4660 pca->style |= CHAR_ATTR_SEL;
4664 LOCAL void
4665 SelRClear (int oStart, int oEnd)
4667 CharAttrib *pca;
4669 for (pca = gpTTYInfo->pAttrib + oStart; oStart < oEnd; ++pca, ++oStart)
4670 pca->style &= ~CHAR_ATTR_SEL;
4674 LOCAL void
4675 SelRInvalidate (int oStart, int oEnd)
4677 RECT rect;
4678 int sRow, sCol;
4679 int eRow, eCol;
4681 sRow = oStart / gpTTYInfo->actNColumn;
4682 sCol = oStart % gpTTYInfo->actNColumn;
4683 eRow = oEnd / gpTTYInfo->actNColumn;
4684 eCol = oEnd % gpTTYInfo->actNColumn;
4686 rect.top = (sRow * gpTTYInfo->yChar) + gpTTYInfo->yOffset;
4687 rect.bottom = ((eRow+1) * gpTTYInfo->yChar) + gpTTYInfo->yOffset;
4688 if (sRow == eRow) {
4689 rect.left = (sCol * gpTTYInfo->xChar) + gpTTYInfo->xOffset;
4690 rect.right = ((eCol+1) * gpTTYInfo->xChar) + gpTTYInfo->xOffset;
4691 } else {
4692 rect.left = gpTTYInfo->xOffset;
4693 rect.right = (gpTTYInfo->actNColumn * gpTTYInfo->xChar) +
4694 gpTTYInfo->xOffset;
4696 InvalidateRect (ghTTYWnd, &rect, FALSE);
4701 * Start a mouse selection.
4703 LOCAL void
4704 SelStart (int nRow, int nColumn)
4706 SelClear ();
4707 SelTracking = TRUE;
4708 SelSelected = TRUE;
4709 SelPointerRow = SelAnchorRow = nRow;
4710 SelPointerCol = SelAnchorCol = nColumn;
4711 return;
4716 * Finish a mouse selection.
4718 LOCAL void
4719 SelFinish (int nRow, int nColumn)
4721 if (nRow == SelAnchorRow && nColumn == SelAnchorCol) {
4722 /* Mouse up in same place it went down - no selection. */
4723 SelClear ();
4725 else {
4726 /* Update screen selection and set final position of mouse
4727 * then turn of mouse tracking. Selection remains in effect
4728 * until SelClear is called. */
4729 SelTrackMouse (nRow, nColumn);
4730 SelTracking = FALSE;
4735 LOCAL void
4736 SelClear (void)
4738 int a, p;
4739 int s, e;
4741 if (!SelSelected)
4742 return;
4744 /* Convert the anchor and point coordinates to offsets then
4745 * order the offsets. */
4746 a = (SelAnchorRow * gpTTYInfo->actNColumn) + SelAnchorCol;
4747 p = (SelPointerRow * gpTTYInfo->actNColumn) + SelPointerCol;
4748 if (a < p) {
4749 s = a;
4750 e = p;
4751 } else {
4752 s = p;
4753 e = a;
4756 /* Clear selected attribute of those cells in range. */
4757 SelRClear (s, e);
4758 SelRInvalidate (s, e);
4759 SelSelected = FALSE;
4760 SelTracking = FALSE;
4765 * Update the position of the mouse point.
4767 LOCAL void
4768 SelTrackXYMouse (int xPos, int yPos)
4770 int nRow;
4771 int nColumn;
4773 nColumn = (xPos - gpTTYInfo->xOffset) / gpTTYInfo->xChar;
4774 nRow = (yPos - gpTTYInfo->yOffset) / gpTTYInfo->yChar;
4776 SelTrackMouse (nRow, nColumn);
4781 * Update the position of the mouse point.
4783 LOCAL void
4784 SelTrackMouse (int nRow, int nColumn)
4786 int a, p, n;
4788 if (!SelTracking)
4789 return;
4791 /* Constrain the cel position to be on the screen. But allow
4792 * for the Column to be one past the right edge of the screen so
4793 * the user can select the right most cel of a row. */
4794 nColumn = MAX(0, nColumn);
4795 nColumn = MIN(gpTTYInfo->actNColumn, nColumn);
4796 nRow = MAX(0, nRow);
4797 nRow = MIN(gpTTYInfo->actNRow-1, nRow);
4800 /* Convert the anchor, previous mouse position, and new mouse
4801 * position to offsets. */
4802 a = (SelAnchorRow * gpTTYInfo->actNColumn) + SelAnchorCol;
4803 p = (SelPointerRow * gpTTYInfo->actNColumn) + SelPointerCol;
4804 n = (nRow * gpTTYInfo->actNColumn) + nColumn;
4806 /* If previous position same as current position, do nothing. */
4807 if (p == n)
4808 return;
4810 /* there are six possible orderings of the points, each with
4811 * a different action:
4812 * order clear set redraw
4813 * n p a n - p n - p
4814 * p n a p - n p - n
4815 * p a n p - a a - n p - n
4816 * a p n p - n p - n
4817 * a n p n - p n - p
4818 * n a p a - p n - a n - p
4820 if (p < a) {
4821 if (n < a) {
4822 if (n < p) {
4823 SelRSet (n, p);
4824 SelRInvalidate (n, p);
4825 } else {
4826 SelRClear (p, n);
4827 SelRInvalidate (p, n);
4829 } else {
4830 SelRClear (p, a);
4831 SelRSet (a, n);
4832 SelRInvalidate (p, n);
4834 } else {
4835 if (n > a) {
4836 if (n > p) {
4837 SelRSet (p, n);
4838 SelRInvalidate (p, n);
4839 } else {
4840 SelRClear (n, p);
4841 SelRInvalidate (n, p);
4843 } else {
4844 SelRClear (a, p);
4845 SelRSet (n, a);
4846 SelRInvalidate (n, p);
4850 /* Set new pointer. */
4851 SelPointerRow = nRow;
4852 SelPointerCol = nColumn;
4856 LOCAL BOOL
4857 SelAvailable (void)
4859 return (SelSelected);
4864 * Copy screen data to clipboard. Actually appends data from screen to
4865 * existing handle so as we can implement a "Copy Append" to append to
4866 * existing clipboard data.
4868 * The screen does not have real line terminators. We decide where the
4869 * actual screen data ends by scanning the line (row) from end backwards
4870 * to find the first non-space.
4872 * I don't know how many bytes of data I'll be appending to the clipboard.
4873 * So I implemented in two passes. The first finds all the row starts
4874 * and length while the second copies the data.
4876 LOCAL void
4877 SelDoCopy (HANDLE hCB, DWORD lenCB)
4879 HANDLE newCB; /* Used in reallocation. */
4880 TCHAR *pCB; /* Points to CB data. */
4881 TCHAR *p2; /* Temp pointer to screen data. */
4882 int sRow, eRow; /* Start and End Rows. */
4883 int sCol, eCol; /* Start and End columns. */
4884 int row, c1, c2; /* temp row and column indexes. */
4885 int totalLen; /* total len of new data. */
4886 CopyRow *rowTable, *rp; /* pointers to table of rows. */
4887 BOOL noLastCRLF = FALSE;
4890 if (OpenClipboard (ghTTYWnd)) { /* ...and we get the CB. */
4891 if (EmptyClipboard ()) { /* ...and clear previous CB.*/
4894 /* Find the start and end row and column. */
4895 if ( (SelAnchorRow * gpTTYInfo->actNColumn) + SelAnchorCol <
4896 (SelPointerRow * gpTTYInfo->actNColumn) + SelPointerCol) {
4897 sRow = SelAnchorRow;
4898 sCol = SelAnchorCol;
4899 eRow = SelPointerRow;
4900 eCol = SelPointerCol;
4902 else {
4903 sRow = SelPointerRow;
4904 sCol = SelPointerCol;
4905 eRow = SelAnchorRow;
4906 eCol = SelAnchorCol;
4909 /* Allocate a table in which we store info on rows. */
4910 rowTable = (CopyRow *) MemAlloc (sizeof (CopyRow) * (eRow-sRow+1));
4911 if (rowTable == NULL)
4912 goto Fail1;
4914 /* Find the start and length of each row. */
4915 totalLen = 0;
4916 for (row = sRow, rp = rowTable; row <= eRow; ++row, ++rp) {
4917 /* Find beginning and end columns, which depends on if
4918 * this is the first or last row in the selection. */
4919 c1 = (row == sRow ? sCol : 0);
4920 c2 = (row == eRow ? eCol : gpTTYInfo->actNColumn);
4922 /* Calculate pointer to beginning of this line. */
4923 rp->pRow = gpTTYInfo->pScreen +
4924 ((row * gpTTYInfo->actNColumn) + c1);
4926 /* Back down from end column to find first non space.
4927 * noLastCRLF indicates if it looks like the selection
4928 * should include a CRLF on the end of the line. It
4929 * gets set for each line, but only the setting for the
4930 * last line in the selection is remembered (which is all
4931 * we're interested in). */
4932 p2 = gpTTYInfo->pScreen +
4933 ((row * gpTTYInfo->actNColumn) + c2);
4934 noLastCRLF = TRUE;
4935 while (c2 > c1) {
4936 if (*(p2-1) != (TCHAR)' ')
4937 break;
4938 noLastCRLF = FALSE;
4939 --c2;
4940 --p2;
4943 /* Calculate size of line, then increment totalLen plus 2 for
4944 * the CRLF which will terminate each line. */
4945 rp->len = c2 - c1;
4946 totalLen += rp->len + 2;
4949 /* Reallocate the memory block. Add one byte for null terminator. */
4950 newCB = GlobalReAlloc (hCB, (lenCB + totalLen + 1)*sizeof(TCHAR), 0);
4951 if (newCB == NULL)
4952 goto Fail2;
4953 hCB = newCB;
4955 pCB = GlobalLock (hCB);
4956 if (pCB == NULL)
4957 goto Fail2;
4959 /* Append each of the rows, deliminated by a CRLF. */
4960 pCB += lenCB;
4961 for (row = sRow, rp = rowTable; row <= eRow; ++row, ++rp) {
4962 if (rp->len > 0) {
4963 memcpy (pCB, rp->pRow, rp->len * sizeof(TCHAR));
4964 pCB += rp->len;
4966 if (row < eRow || !noLastCRLF) {
4967 *pCB++ = (TCHAR)ASCII_CR;
4968 *pCB++ = (TCHAR)ASCII_LF;
4971 *pCB = (TCHAR)'\0'; /* Null terminator. */
4972 MemFree (rowTable);
4973 GlobalUnlock (hCB);
4975 /* Attempt to pass the data to the clipboard, then release clipboard
4976 * and exit function. */
4977 if (SetClipboardData (CF_UNICODETEXT, hCB) == NULL)
4978 /* Failed! Free the data. */
4979 GlobalFree (hCB);
4980 CloseClipboard ();
4983 return;
4986 /* Error exit. */
4987 Fail2: MemFree (rowTable);
4988 Fail1: GlobalFree (hCB);
4989 CloseClipboard ();
4990 return;
4995 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4997 * Upper Layer Screen routines.
4999 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
5002 * Flush the write accumulator buffer.
5004 LOCAL void
5005 FlushWriteAccum (void)
5007 if (gpTTYInfo->writeAccumCount > 0) {
5008 WriteTTYText (ghTTYWnd, gpTTYInfo->writeAccum,
5009 gpTTYInfo->writeAccumCount);
5010 gpTTYInfo->writeAccumCount = 0;
5016 * Set window's title
5018 void
5019 mswin_settitle(char *utf8_title)
5021 TCHAR buf[256];
5022 LPTSTR lptstr_title;
5024 lptstr_title = utf8_to_lptstr(utf8_title);
5025 _sntprintf(buf, 256, TEXT("%.*s - Alpine"), 80, lptstr_title);
5026 fs_give((void **) &lptstr_title);
5028 SetWindowText(ghTTYWnd, buf);
5033 * Return the application instance.
5035 WINHAND
5036 mswin_gethinstance ()
5038 return ((WINHAND)ghInstance);
5042 WINHAND
5043 mswin_gethwnd ()
5045 return ((WINHAND)ghTTYWnd);
5050 * destroy splash screen
5052 void
5053 mswin_killsplash()
5055 if(ghSplashWnd != NULL){
5056 DestroyWindow(ghSplashWnd);
5057 ghSplashWnd = NULL;
5063 * Called to get mouse event.
5066 mswin_getmouseevent (MEvent * pMouse)
5068 return (MQGet (pMouse));
5073 * Make a pop-up menu and track it
5076 mswin_popup(MPopup *members)
5078 HMENU hMenu;
5079 POINT point;
5080 MPopup *mp;
5081 int n = 1;
5083 if(members && (hMenu = CreatePopupMenu())){
5085 PopupConfig(hMenu, members, &n);
5086 if(GetCursorPos(&point)
5087 && (n = TrackPopupMenu(hMenu,
5088 TPM_LEFTALIGN | TPM_TOPALIGN
5089 | TPM_RIGHTBUTTON | TPM_LEFTBUTTON
5090 | TPM_NONOTIFY | TPM_RETURNCMD,
5091 point.x, point.y, 0, ghTTYWnd, NULL))
5092 && (mp = PopupId(members, n))){
5093 /* Find the member with the internal.id of n */
5094 n = mp->internal.id - 1; /* item's "selectable" index */
5095 switch(mp->type){
5096 case tQueue :
5097 CQAdd (mp->data.val, 0);
5098 break;
5100 case tMessage :
5101 SendMessage(ghTTYWnd, WM_COMMAND, mp->data.msg, 0);
5102 break;
5104 default :
5105 break;
5108 else
5109 n = -1; /* error or nothing selected; same diff */
5111 DestroyMenu(hMenu);
5113 else
5114 n = -1; /* error */
5116 return(n);
5120 LOCAL void
5121 PopupConfig(HMENU hMenu, MPopup *members, int *n)
5123 MENUITEMINFO mitem;
5124 int index;
5125 TCHAR tcbuf[256];
5127 for(index = 0; members->type != tTail; members++, index++){
5128 memset(&mitem, 0, sizeof(MENUITEMINFO));
5129 mitem.cbSize = sizeof(MENUITEMINFO);
5130 mitem.fMask = MIIM_TYPE;
5132 if(members->type == tSubMenu){
5133 mitem.fMask |= MIIM_SUBMENU;
5134 mitem.fType = MFT_STRING;
5135 if(mitem.hSubMenu = CreatePopupMenu()){
5136 /* members->label.string is still just a char * */
5137 _sntprintf(tcbuf, sizeof(tcbuf)/sizeof(TCHAR),
5138 TEXT("%S"), members->label.string);
5139 mitem.dwTypeData = tcbuf;
5140 mitem.cch = (UINT)_tcslen(tcbuf);
5141 InsertMenuItem(hMenu, index, TRUE, &mitem);
5143 PopupConfig(mitem.hSubMenu, members->data.submenu, n);
5146 else{
5147 switch(members->type){
5148 case tSeparator :
5149 mitem.fType = MFT_SEPARATOR;
5150 break;
5152 default :
5153 mitem.fMask |= MIIM_ID;
5154 mitem.wID = members->internal.id = (*n)++;
5155 switch(members->label.style){
5156 case lChecked :
5157 mitem.fMask |= MIIM_STATE;
5158 mitem.fState = MFS_CHECKED;
5159 break;
5161 case lDisabled :
5162 mitem.fMask |= MIIM_STATE;
5163 mitem.fState = MFS_GRAYED;
5164 break;
5166 case lNormal :
5167 default :
5168 break;
5171 mitem.fType = MFT_STRING;
5172 _sntprintf(tcbuf, sizeof(tcbuf)/sizeof(TCHAR),
5173 TEXT("%S"), members->label.string);
5174 mitem.dwTypeData = tcbuf;
5175 mitem.cch = (UINT)_tcslen(tcbuf);
5176 break;
5179 InsertMenuItem(hMenu, index, TRUE, &mitem);
5185 LOCAL MPopup *
5186 PopupId(MPopup *members, int id)
5188 MPopup *mp;
5190 for(; members->type != tTail; members++)
5191 switch(members->type){
5192 case tSubMenu :
5193 if(mp = PopupId(members->data.submenu, id))
5194 return(mp);
5196 break;
5198 case tSeparator :
5199 break;
5201 default :
5202 if(members->internal.id == id)
5203 return(members);
5205 break;
5208 return(NULL);
5213 * Make a pop-up offering Copy/Cut/Paste menu and track it
5215 LOCAL BOOL
5216 CopyCutPopup(HWND hWnd, UINT fAllowed)
5218 MENUITEMINFO mitem;
5219 HMENU hMenu;
5220 POINT point;
5221 BOOL rv = FALSE;
5222 int n = -1;
5225 * If nothing to do just silently return
5227 if(fAllowed != EM_NONE && (hMenu = CreatePopupMenu())){
5228 if(fAllowed & EM_CUT){
5229 /* Insert a "Copy" option */
5230 memset(&mitem, 0, sizeof(MENUITEMINFO));
5231 mitem.cbSize = sizeof(MENUITEMINFO);
5232 mitem.fMask = MIIM_TYPE | MIIM_ID;
5233 mitem.wID = IDM_EDIT_CUT;
5234 mitem.fType = MFT_STRING;
5235 mitem.dwTypeData = TEXT("Cut");
5236 mitem.cch = 3;
5237 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5240 if(fAllowed & EM_CP){
5241 /* Insert a "Copy" option */
5242 memset(&mitem, 0, sizeof(MENUITEMINFO));
5243 mitem.cbSize = sizeof(MENUITEMINFO);
5244 mitem.fMask = MIIM_TYPE | MIIM_ID;
5245 mitem.wID = IDM_EDIT_COPY;
5246 mitem.fType = MFT_STRING;
5247 mitem.dwTypeData = TEXT("Copy");
5248 mitem.cch = 4;
5249 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5252 if(fAllowed & EM_CP_APPEND){
5253 /* Insert a "Copy Append" option */
5254 memset(&mitem, 0, sizeof(MENUITEMINFO));
5255 mitem.cbSize = sizeof(MENUITEMINFO);
5256 mitem.fMask = MIIM_TYPE | MIIM_ID;
5257 mitem.wID = IDM_EDIT_COPY_APPEND;
5258 mitem.fType = MFT_STRING;
5259 mitem.dwTypeData = TEXT("Copy Append");
5260 mitem.cch = 11;
5261 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5264 if(fAllowed & EM_PST){
5265 /* Insert a "Paste" option */
5266 memset(&mitem, 0, sizeof(MENUITEMINFO));
5267 mitem.cbSize = sizeof(MENUITEMINFO);
5268 mitem.fMask = MIIM_TYPE | MIIM_ID;
5269 mitem.wID = IDM_EDIT_PASTE;
5270 mitem.fType = MFT_STRING;
5271 mitem.dwTypeData = TEXT("Paste");
5272 mitem.cch = 5;
5273 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5276 if((fAllowed & EM_SEL_ALL) && !(fAllowed & (EM_CP | EM_CP_APPEND))){
5277 /* Insert a "Select All" option */
5278 memset(&mitem, 0, sizeof(MENUITEMINFO));
5279 mitem.cbSize = sizeof(MENUITEMINFO);
5280 mitem.fMask = MIIM_TYPE | MIIM_ID;
5281 mitem.wID = IDM_EDIT_SEL_ALL;
5282 mitem.fType = MFT_STRING;
5283 mitem.dwTypeData = TEXT("Select &All");
5284 mitem.cch = 11;
5285 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5288 if(n >= 0 && GetCursorPos(&point)){
5289 TrackPopupMenu(hMenu,
5290 TPM_LEFTALIGN | TPM_TOPALIGN
5291 | TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
5292 point.x, point.y, 0, hWnd, NULL);
5293 rv = TRUE;
5296 DestroyMenu(hMenu);
5299 return(rv);
5307 void
5308 pico_popup()
5310 MENUITEMINFO mitem;
5311 HMENU hMenu;
5312 POINT point;
5313 UINT fAllow;
5314 int n = -1;
5317 * If nothing to do just silently return
5319 if(hMenu = CreatePopupMenu()){
5321 if((fAllow = UpdateEditAllowed(ghTTYWnd)) != EM_NONE){
5322 /* Insert a "Cut" option */
5323 memset(&mitem, 0, sizeof(MENUITEMINFO));
5324 mitem.cbSize = sizeof(MENUITEMINFO);
5325 mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
5326 mitem.wID = IDM_EDIT_CUT;
5327 mitem.fState = (fAllow & EM_CUT) ? MFS_ENABLED : MFS_GRAYED;
5328 mitem.fType = MFT_STRING;
5329 mitem.dwTypeData = TEXT("Cut");
5330 mitem.cch = 3;
5331 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5333 /* Insert a "Copy" option */
5334 memset(&mitem, 0, sizeof(MENUITEMINFO));
5335 mitem.cbSize = sizeof(MENUITEMINFO);
5336 mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
5337 mitem.wID = IDM_EDIT_COPY;
5338 mitem.fState = (fAllow & EM_CP) ? MFS_ENABLED : MFS_GRAYED;
5339 mitem.fType = MFT_STRING;
5340 mitem.dwTypeData = TEXT("Copy");
5341 mitem.cch = 4;
5342 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5344 /* Insert a "Copy Append" option */
5345 memset(&mitem, 0, sizeof(MENUITEMINFO));
5346 mitem.cbSize = sizeof(MENUITEMINFO);
5347 mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
5348 mitem.wID = IDM_EDIT_COPY_APPEND;
5349 mitem.fState = (fAllow & EM_CP_APPEND) ? MFS_ENABLED : MFS_GRAYED;
5350 mitem.fType = MFT_STRING;
5351 mitem.dwTypeData = TEXT("Copy Append");
5352 mitem.cch = 11;
5353 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5355 /* Insert a "Paste" option */
5356 memset(&mitem, 0, sizeof(MENUITEMINFO));
5357 mitem.cbSize = sizeof(MENUITEMINFO);
5358 mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
5359 mitem.wID = IDM_EDIT_PASTE;
5360 mitem.fType = MFT_STRING;
5361 mitem.dwTypeData = TEXT("Paste");
5362 mitem.fState = (fAllow & EM_PST) ? MFS_ENABLED : MFS_GRAYED;
5363 mitem.cch = 5;
5364 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5367 /* Insert a "Select All" option */
5368 memset(&mitem, 0, sizeof(MENUITEMINFO));
5369 mitem.cbSize = sizeof(MENUITEMINFO);
5370 mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
5371 mitem.wID = IDM_EDIT_SEL_ALL;
5372 mitem.fType = MFT_STRING;
5373 mitem.fState = (fAllow & (EM_CP | EM_CP_APPEND))
5374 ? MFS_GRAYED : MFS_ENABLED;
5375 mitem.dwTypeData = TEXT("Select &All");
5376 mitem.cch = 11;
5377 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5379 if(n >= 0 && GetCursorPos(&point))
5380 TrackPopupMenu(hMenu,
5381 TPM_LEFTALIGN | TPM_TOPALIGN
5382 | TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
5383 point.x, point.y, 0, ghTTYWnd, NULL);
5385 DestroyMenu(hMenu);
5394 void
5395 mswin_paste_popup()
5397 MENUITEMINFO mitem;
5398 HMENU hMenu;
5399 POINT point;
5400 UINT fAllow;
5401 int n = -1;
5404 * If nothing to do just silently return
5406 if(hMenu = CreatePopupMenu()){
5408 if((fAllow = UpdateEditAllowed(ghTTYWnd)) != EM_NONE){
5409 /* Insert a "Paste" option */
5410 memset(&mitem, 0, sizeof(MENUITEMINFO));
5411 mitem.cbSize = sizeof(MENUITEMINFO);
5412 mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
5413 mitem.wID = IDM_EDIT_PASTE;
5414 mitem.fType = MFT_STRING;
5415 mitem.dwTypeData = TEXT("Paste");
5416 mitem.fState = (fAllow & EM_PST) ? MFS_ENABLED : MFS_GRAYED;
5417 mitem.cch = 5;
5418 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5420 if(n >= 0 && GetCursorPos(&point))
5421 TrackPopupMenu(hMenu,
5422 TPM_LEFTALIGN | TPM_TOPALIGN
5423 | TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
5424 point.x, point.y, 0, ghTTYWnd, NULL);
5427 DestroyMenu(hMenu);
5433 void
5434 mswin_keymenu_popup()
5436 HMENU hBarMenu, hMenu;
5437 MENUITEMINFO mitem;
5438 POINT point;
5439 int i, j, n;
5440 TCHAR tcbuf[256];
5443 * run thru menubar from left to right and down each list building
5444 * a popup of all active members. we run down the menu's rather
5445 * than thru the menuItems array so we can preserve order...
5447 if((hMenu = CreatePopupMenu())){
5448 if(hBarMenu = GetMenu(ghTTYWnd)){
5449 /* For each possible index, look for matching registered key */
5450 for(n = 0, i = 1; i <= KS_COUNT; i++)
5451 for(j = 0; j < KS_COUNT; j++)
5452 if(gpTTYInfo->menuItems[j].miIndex == i){
5453 if(gpTTYInfo->menuItems[j].miActive == TRUE
5454 && gpTTYInfo->menuItems[j].miLabel){
5455 mitem.cbSize = sizeof(MENUITEMINFO);
5456 mitem.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE;
5457 mitem.wID = j + KS_RANGESTART;
5458 mitem.fState = MFS_ENABLED;
5459 mitem.fType = MFT_STRING;
5460 /* miLabel is still plain old char *, not utf8 */
5461 _sntprintf(tcbuf, sizeof(tcbuf)/sizeof(TCHAR),
5462 TEXT("%S"), gpTTYInfo->menuItems[j].miLabel);
5463 mitem.dwTypeData = tcbuf;
5464 mitem.cch = (UINT)_tcslen(tcbuf);
5465 InsertMenuItem(hMenu, n++, TRUE, &mitem);
5467 if(j + KS_RANGESTART == IDM_MI_SCREENHELP
5468 && gHelpCallback){
5469 mitem.cbSize = sizeof(MENUITEMINFO);
5470 mitem.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE;
5471 mitem.wID = IDM_HELP;
5472 mitem.fState = MFS_ENABLED;
5473 mitem.fType = MFT_STRING;
5474 _sntprintf(tcbuf, sizeof(tcbuf)/sizeof(TCHAR),
5475 TEXT("%S"), "Help in New Window");
5476 mitem.dwTypeData = tcbuf;
5477 mitem.cch = (UINT)_tcslen(tcbuf);
5478 InsertMenuItem(hMenu, n++, TRUE, &mitem);
5482 break;
5485 if(n > 0 && GetCursorPos(&point)){
5486 TrackPopupMenu(hMenu,
5487 TPM_LEFTALIGN | TPM_TOPALIGN
5488 | TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
5489 point.x, point.y, 0, ghTTYWnd, NULL);
5493 DestroyMenu(hMenu);
5502 void
5503 mswin_registericon(int row, int id, char *utf8_file)
5505 LPTSTR sPathCopy;
5506 HICON hIcon;
5507 WORD iIcon;
5508 IconList *pIcon;
5510 /* Turn this off until it can get tuned */
5511 return;
5513 /* Already registered? */
5514 for(pIcon = gIconList; pIcon; pIcon = pIcon->next)
5515 if(pIcon->id == id){
5516 pIcon->row = (short)row;
5517 return;
5520 sPathCopy = utf8_to_lptstr(utf8_file);
5522 if(hIcon = ExtractAssociatedIcon(ghInstance, sPathCopy, &iIcon))
5523 MSWIconAddList(row, id, hIcon);
5525 fs_give((void **) &sPathCopy);
5529 void
5530 mswin_destroyicons()
5532 MSWIconFree(&gIconList);
5536 void
5537 MSWIconAddList(int row, int id, HICON hIcon)
5539 IconList **ppIcon;
5541 for(ppIcon = &gIconList; *ppIcon; ppIcon = &(*ppIcon)->next)
5544 *ppIcon = (IconList *) MemAlloc (sizeof (IconList));
5545 memset(*ppIcon, 0, sizeof(IconList));
5546 (*ppIcon)->hIcon = hIcon;
5547 (*ppIcon)->id = id;
5548 (*ppIcon)->row = (short)row;
5553 MSWIconPaint(int row, HDC hDC)
5555 IconList *pIcon;
5556 int rv = 0;
5558 for(pIcon = gIconList; pIcon && pIcon->row != row; pIcon = pIcon->next)
5561 if(pIcon){
5562 /* Invalidate rectange covering singel character. */
5563 DrawIconEx(hDC, 0, (row * gpTTYInfo->yChar) + gpTTYInfo->yOffset,
5564 pIcon->hIcon, 2 * gpTTYInfo->xChar, gpTTYInfo->yChar,
5565 0, NULL, DI_NORMAL);
5567 rv = 1;
5570 return(rv);
5574 void
5575 MSWIconFree(IconList **ppIcon)
5577 if(ppIcon && *ppIcon){
5578 if((*ppIcon)->next)
5579 MSWIconFree(&(*ppIcon)->next);
5581 DestroyIcon((*ppIcon)->hIcon);
5582 MemFree (*ppIcon);
5583 *ppIcon = NULL;
5589 * Set up debugging stuff.
5591 void
5592 mswin_setdebug (int debug, FILE *debugfile)
5594 /* Accept new file only if we don't already have a file. */
5595 if (mswin_debugfile == 0) {
5596 mswin_debug = debug;
5597 mswin_debugfile = debugfile;
5598 MemDebug (debug, mswin_debugfile);
5603 void
5604 mswin_setnewmailwidth (int width)
5606 gNMW_width = width;
5607 gNMW_width = gNMW_width < 20 ? 20 : gNMW_width;
5608 gNMW_width = gNMW_width > 170 ? 170 : gNMW_width;
5613 * Event handler to deal with File Drop events
5615 LOCAL BOOL
5616 ProcessTTYFileDrop (HANDLE wDrop)
5618 HDROP hDrop = wDrop;
5619 POINT pos;
5620 int col, row, i, n;
5621 TCHAR fname[1024];
5622 char *utf8_fname;
5624 if(!gpTTYInfo->dndhandler)
5625 return(FALSE);
5627 /* translate drop point to character cell */
5628 DragQueryPoint(hDrop, &pos);
5629 col = (pos.x - gpTTYInfo->xOffset) / gpTTYInfo->xChar;
5630 if (pos.x < gpTTYInfo->xOffset)
5631 --col;
5632 row = (pos.y - gpTTYInfo->yOffset) / gpTTYInfo->yChar;
5633 if (pos.y < gpTTYInfo->yOffset)
5634 --row;
5636 for(n = DragQueryFile(hDrop, (UINT)-1, NULL, 0), i = 0; i < n; i++){
5637 DragQueryFile(hDrop, i, fname, 1024);
5638 utf8_fname = lptstr_to_utf8(fname);
5639 gpTTYInfo->dndhandler (row, col, utf8_fname);
5640 fs_give((void **) &utf8_fname);
5643 DragFinish(hDrop);
5645 set_time_of_last_input();
5647 return(TRUE);
5652 * Set a callback to deal with Drag 'N Drop events
5655 mswin_setdndcallback (int (*cb)())
5657 if(gpTTYInfo->dndhandler)
5658 gpTTYInfo->dndhandler = NULL;
5660 if(cb){
5661 gpTTYInfo->dndhandler = cb;
5662 DragAcceptFiles(ghTTYWnd, TRUE);
5665 return(1);
5670 * Clear previously installed callback to handle Drag 'N Drop
5671 * events
5674 mswin_cleardndcallback ()
5676 gpTTYInfo->dndhandler = NULL;
5677 DragAcceptFiles(ghTTYWnd, FALSE);
5678 return(1);
5683 * Set a callback for function 'ch'
5686 mswin_setresizecallback (int (*cb)())
5688 int i;
5689 int e;
5693 * Look through whole array for this call back function. Don't
5694 * insert duplicate. Also look for empty slot.
5696 e = -1;
5697 for (i = 0; i < RESIZE_CALLBACK_ARRAY_SIZE; ++i) {
5698 if (gpTTYInfo->resizer[i] == cb)
5699 return (0);
5700 if (e == -1 && gpTTYInfo->resizer[i] == NULL)
5701 e = i;
5705 * Insert in empty slot or return an error.
5707 if (e != -1) {
5708 gpTTYInfo->resizer[e] = cb;
5709 return (0);
5711 return (-1);
5716 * Clear all instances of the callback function 'cb'
5719 mswin_clearresizecallback (int (*cb)())
5721 int i;
5722 int status;
5724 status = -1;
5725 for (i = 0; i < RESIZE_CALLBACK_ARRAY_SIZE; ++i) {
5726 if (gpTTYInfo->resizer[i] == cb) {
5727 gpTTYInfo->resizer[i] = NULL;
5728 status = 0;
5731 return (status);
5735 void
5736 mswin_beginupdate (void)
5738 gpTTYInfo->fMassiveUpdate = TRUE;
5742 void
5743 mswin_endupdate (void)
5745 gpTTYInfo->fMassiveUpdate = FALSE;
5746 MoveTTYCursor (ghTTYWnd);
5751 mswin_charsetid2string(LPTSTR fontCharSet, size_t nfontCharSet, BYTE lfCharSet)
5753 TCHAR buf[1024];
5755 buf[0] = '\0';
5756 switch(lfCharSet){
5757 case DEFAULT_CHARSET:
5758 break;
5759 case ANSI_CHARSET:
5760 _tcsncpy(buf, TEXT("ANSI_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5761 break;
5762 case OEM_CHARSET:
5763 _tcsncpy(buf, TEXT("OEM_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5764 break;
5765 case BALTIC_CHARSET:
5766 _tcsncpy(buf, TEXT("BALTIC_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5767 break;
5768 case CHINESEBIG5_CHARSET:
5769 _tcsncpy(buf, TEXT("CHINESE_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5770 break;
5771 case EASTEUROPE_CHARSET:
5772 _tcsncpy(buf, TEXT("EASTEUROPE_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5773 break;
5774 case GB2312_CHARSET:
5775 _tcsncpy(buf, TEXT("GF2312_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5776 break;
5777 case GREEK_CHARSET:
5778 _tcsncpy(buf, TEXT("GREEK_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5779 break;
5780 case HANGUL_CHARSET:
5781 _tcsncpy(buf, TEXT("HANGUL_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5782 break;
5783 case MAC_CHARSET:
5784 _tcsncpy(buf, TEXT("MAC_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5785 break;
5786 case RUSSIAN_CHARSET:
5787 _tcsncpy(buf, TEXT("RUSSIAN_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5788 break;
5789 case SHIFTJIS_CHARSET:
5790 _tcsncpy(buf, TEXT("SHIFTJIS_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5791 break;
5792 case SYMBOL_CHARSET:
5793 _tcsncpy(buf, TEXT("SYMBOL_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5794 break;
5795 case TURKISH_CHARSET:
5796 _tcsncpy(buf, TEXT("TURKISH_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5797 break;
5798 case VIETNAMESE_CHARSET:
5799 _tcsncpy(buf, TEXT("VIETNAMESE_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5800 break;
5801 case JOHAB_CHARSET:
5802 _tcsncpy(buf, TEXT("JOHAB_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5803 break;
5804 case ARABIC_CHARSET:
5805 _tcsncpy(buf, TEXT("ARABIC_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5806 break;
5807 case HEBREW_CHARSET:
5808 _tcsncpy(buf, TEXT("HEBREW_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5809 break;
5810 case THAI_CHARSET:
5811 _tcsncpy(buf, TEXT("THAI_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5812 break;
5813 default:
5814 /* default char set if we can't figure it out */
5815 break;
5818 buf[sizeof(buf)/sizeof(TCHAR) - 1] = '\0';
5820 _tcsncpy(fontCharSet, buf, nfontCharSet);
5821 fontCharSet[nfontCharSet-1] = '\0';
5823 return 0;
5827 BYTE
5828 mswin_string2charsetid(LPTSTR str)
5830 TCHAR tstr[1024];
5832 if(!str || (lstrlen(str) >= 1024))
5833 return DEFAULT_CHARSET;
5835 if((lstrlen(str) > lstrlen(TEXT("_CHARSET")))
5836 && (tcsucmp(str + lstrlen(str) - lstrlen(TEXT("_CHARSET")), TEXT("_CHARSET")) == 0)){
5837 _tcsncpy(tstr, str, 1024);
5838 tstr[lstrlen(str) - lstrlen(TEXT("_CHARSET"))] = '\0';
5839 tstr[1024-1] = '\0';
5840 if(tcsucmp(tstr, TEXT("ANSI")) == 0)
5841 return ANSI_CHARSET;
5842 else if(tcsucmp(tstr, TEXT("DEFAULT")) == 0)
5843 return DEFAULT_CHARSET;
5844 else if(tcsucmp(tstr, TEXT("OEM")) == 0)
5845 return OEM_CHARSET;
5846 else if(tcsucmp(tstr, TEXT("BALTIC")) == 0)
5847 return BALTIC_CHARSET;
5848 else if(tcsucmp(tstr, TEXT("CHINESEBIG5")) == 0)
5849 return CHINESEBIG5_CHARSET;
5850 else if(tcsucmp(tstr, TEXT("EASTEUROPE")) == 0)
5851 return EASTEUROPE_CHARSET;
5852 else if(tcsucmp(tstr, TEXT("GB2312")) == 0)
5853 return GB2312_CHARSET;
5854 else if(tcsucmp(tstr, TEXT("GREEK")) == 0)
5855 return GREEK_CHARSET;
5856 else if(tcsucmp(tstr, TEXT("HANGUL")) == 0)
5857 return HANGUL_CHARSET;
5858 else if(tcsucmp(tstr, TEXT("MAC")) == 0)
5859 return MAC_CHARSET;
5860 else if(tcsucmp(tstr, TEXT("RUSSIAN")) == 0)
5861 return RUSSIAN_CHARSET;
5862 else if(tcsucmp(tstr, TEXT("SHIFTJIS")) == 0)
5863 return SHIFTJIS_CHARSET;
5864 else if(tcsucmp(tstr, TEXT("SYMBOL")) == 0)
5865 return SYMBOL_CHARSET;
5866 else if(tcsucmp(tstr, TEXT("TURKISH")) == 0)
5867 return TURKISH_CHARSET;
5868 else if(tcsucmp(tstr, TEXT("VIETNAMESE")) == 0)
5869 return VIETNAMESE_CHARSET;
5870 else if(tcsucmp(tstr, TEXT("JOHAB")) == 0)
5871 return JOHAB_CHARSET;
5872 else if(tcsucmp(tstr, TEXT("ARABIC")) == 0)
5873 return ARABIC_CHARSET;
5874 else if(tcsucmp(tstr, TEXT("HEBREW")) == 0)
5875 return HEBREW_CHARSET;
5876 else if(tcsucmp(tstr, TEXT("THAI")) == 0)
5877 return THAI_CHARSET;
5878 else
5879 return DEFAULT_CHARSET;
5881 else{
5882 if(_tstoi(str) > 0)
5883 return((BYTE)(_tstoi(str)));
5884 else
5885 return DEFAULT_CHARSET;
5891 mswin_setwindow(char *fontName_utf8, char *fontSize_utf8, char *fontStyle_utf8,
5892 char *windowPosition, char *caretStyle, char *fontCharSet_utf8)
5894 LOGFONT newFont;
5895 int newHeight;
5896 HDC hDC;
5897 int ppi;
5898 RECT wndRect, cliRect;
5899 char *c;
5900 char *n;
5901 int i;
5902 BOOL toolBar = FALSE;
5903 BOOL toolBarTop = TRUE;
5904 int wColumns, wRows;
5905 int wXPos, wYPos;
5906 int wXBorder, wYBorder;
5907 int wXSize, wYSize;
5908 char wp[WIN_POS_STR_MAX_LEN + 1];
5909 int showWin = 1;
5910 LPTSTR fontName_lpt = NULL;
5911 LPTSTR fontCharSet_lpt;
5913 #ifdef SDEBUG
5914 if (mswin_debug >= 5)
5915 fprintf (mswin_debugfile, "mswin_setwindow::: entered, minimized: %d\n",
5916 gpTTYInfo->fMinimized);
5917 #endif
5919 /* Require a font name to set font info. */
5920 if(fontName_utf8 != NULL && *fontName_utf8 != '\0' &&
5921 (fontName_lpt = utf8_to_lptstr(fontName_utf8)) &&
5922 _tcslen(fontName_lpt) <= LF_FACESIZE - 1){
5924 hDC = GetDC(ghTTYWnd);
5925 ppi = GetDeviceCaps(hDC, LOGPIXELSY);
5926 ReleaseDC(ghTTYWnd, hDC);
5928 /* Default height, then examin the requested fontSize. */
5929 newFont.lfHeight = -MulDiv(12, ppi, 72);
5930 if(ScanInt(fontSize_utf8, FONT_MIN_SIZE, FONT_MAX_SIZE, &newHeight)){
5931 newHeight = abs(newHeight);
5932 newFont.lfHeight = -MulDiv(newHeight, ppi, 72);
5935 /* Default font style, then read requested style. */
5936 newFont.lfWeight = 0;
5937 newFont.lfItalic = 0;
5938 if(fontStyle_utf8 != NULL){
5939 _strlwr(fontStyle_utf8);
5940 if(strstr(fontStyle_utf8, "bold"))
5941 newFont.lfWeight = FW_BOLD;
5942 if(strstr(fontStyle_utf8, "italic"))
5943 newFont.lfItalic = 1;
5946 /* Everything else takes the default. */
5947 newFont.lfWidth = 0;
5948 newFont.lfEscapement = 0;
5949 newFont.lfOrientation = 0;
5950 newFont.lfUnderline = 0;
5951 newFont.lfStrikeOut = 0;
5952 fontCharSet_lpt = utf8_to_lptstr(fontCharSet_utf8);
5953 if(fontCharSet_lpt){
5954 newFont.lfCharSet = mswin_string2charsetid(fontCharSet_lpt);
5955 fs_give((void **) &fontCharSet_lpt);
5958 newFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
5959 newFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5960 newFont.lfQuality = DEFAULT_QUALITY;
5961 newFont.lfPitchAndFamily = FIXED_PITCH;
5962 _sntprintf(newFont.lfFaceName, LF_FACESIZE, TEXT("%s"), fontName_lpt);
5963 ResetTTYFont (ghTTYWnd, gpTTYInfo, &newFont);
5966 if(fontName_lpt)
5967 fs_give((void **) &fontName_lpt);
5970 * Set window position. String format is: CxR+X+Y
5971 * Where C is the number of columns, R is the number of rows,
5972 * and X and Y specify the top left corner of the window.
5974 if(windowPosition != NULL && *windowPosition != '\0'){
5975 if(strlen(windowPosition) > sizeof(wp)-1)
5976 return(0);
5978 strncpy(wp, windowPosition, sizeof(wp));
5979 wp[sizeof(wp)-1] = '\0';
5982 * Flag characters are at the end of the string. Strip them
5983 * off till we get to a number.
5985 i = (int)strlen(wp) - 1;
5986 while(i > 0 && (*(wp+i) < '0' || *(wp+i) > '9')){
5987 if(*(wp+i) == 't' || *(wp+i) == 'b'){
5988 toolBar = TRUE;
5989 toolBarTop = (*(wp+i) == 't');
5992 if(*(wp+i) == 'd')
5993 gfUseDialogs = TRUE;
5995 #ifdef ACCELERATORS_OPT
5996 if(*(wp+i) == 'a')
5997 AccelCtl(ghTTYWnd, ACCEL_LOAD, FALSE);
5998 #endif
6000 *(wp+i) = 0;
6001 --i;
6004 if(strcmp(wp, "MIN0") == 0){
6005 mswin_killsplash();
6006 showWin = 0;
6007 ShowWindow(ghTTYWnd, SW_MINIMIZE);
6008 if(toolBar){
6009 gpTTYInfo->toolBarTop = toolBarTop;
6010 TBShow(ghTTYWnd);
6013 else{
6014 /* Look for Columns, deliminated by 'x'. */
6015 c = strchr (wp, 'x');
6016 if (c == NULL)
6017 return(0);
6019 *c = '\0';
6020 if(!ScanInt(wp, -999, 9999, &wColumns))
6021 return(0);
6023 /* Look for Rows, deliminated by '+'. */
6024 n = c + 1;
6025 c = strchr(n, '+');
6026 if(c == NULL)
6027 return (0);
6029 *c = '\0';
6030 if(!ScanInt(n, -999, 9999, &wRows))
6031 return(0);
6033 /* Look for X position, deliminated by '+'. */
6034 n = c + 1;
6035 c = strchr(n, '+');
6036 if(c == NULL)
6037 return(0);
6039 *c = '\0';
6040 if(!ScanInt(n, -999, 9999, &wXPos))
6041 return(0);
6043 /* And get Y position, deliminated by end of string. */
6044 n = c + 1;
6045 if(!ScanInt(n, -999, 9999, &wYPos))
6046 return(0);
6049 /* Constrain the window position and size. */
6050 if(wXPos < 0)
6051 wXPos = 0;
6053 if(wYPos < 0)
6054 wYPos = 0;
6056 GetWindowRect(GetDesktopWindow(), &wndRect);
6057 if(wXPos > wndRect.right - 20)
6058 wXPos = wndRect.right - 100;
6060 if(wYPos > wndRect.bottom - 20)
6061 wYPos = wndRect.bottom - 100;
6063 /* Get the current window rect and client area. */
6064 GetWindowRect(ghTTYWnd, &wndRect);
6065 GetClientRect(ghTTYWnd, &cliRect);
6067 /* Calculate boarder sizes. */
6068 wXBorder = wndRect.right - wndRect.left - cliRect.right;
6069 wYBorder = wndRect.bottom - wndRect.top - cliRect.bottom;
6071 /* Show toolbar before calculating content size. */
6072 if(toolBar){
6073 gpTTYInfo->toolBarTop = toolBarTop;
6074 TBShow(ghTTYWnd);
6077 /* Calculate new window pos and size. */
6078 wXSize = wXBorder + (wColumns * gpTTYInfo->xChar) +
6079 (2 * gpTTYInfo->xOffset);
6080 wYSize = wYBorder + (wRows * gpTTYInfo->yChar) +
6081 gpTTYInfo->toolBarSize + (2 * MARGINE_TOP);
6082 if(!gpTTYInfo->fMinimized)
6083 MoveWindow(ghTTYWnd, wXPos, wYPos, wXSize, wYSize, TRUE);
6084 else{
6085 gpTTYInfo->fDesiredSize = TRUE;
6086 gpTTYInfo->xDesPos = (CORD)wXPos;
6087 gpTTYInfo->yDesPos = (CORD)wYPos;
6088 gpTTYInfo->xDesSize = (CORD)wXSize;
6089 gpTTYInfo->yDesSize = (CORD)wYSize;
6094 if(caretStyle != NULL && *caretStyle != '\0')
6095 for(i = 0; MSWinCaretTable[i].name; i++)
6096 if(!strucmp(MSWinCaretTable[i].name, caretStyle)){
6097 CaretTTY(ghTTYWnd, MSWinCaretTable[i].style);
6098 break;
6101 return(0);
6106 mswin_showwindow()
6108 mswin_killsplash();
6109 ShowWindow (ghTTYWnd, SW_SHOWNORMAL);
6110 UpdateWindow (ghTTYWnd);
6112 return(0);
6117 * Retreive the current font name, font size, and window position
6118 * These get stored in the pinerc file and will be passed to
6119 * mswin_setwindow() when pine starts up. See pinerc for comments
6120 * on the format.
6123 mswin_getwindow(char *fontName_utf8, size_t nfontName,
6124 char *fontSize_utf8, size_t nfontSize,
6125 char *fontStyle_utf8, size_t nfontStyle,
6126 char *windowPosition, size_t nwindowPosition,
6127 char *foreColor, size_t nforeColor,
6128 char *backColor, size_t nbackColor,
6129 char *caretStyle, size_t ncaretStyle,
6130 char *fontCharSet_utf8, size_t nfontCharSet)
6132 HDC hDC;
6133 int ppi;
6134 RECT wndRect;
6135 char *t;
6137 if(fontName_utf8 != NULL){
6138 t = lptstr_to_utf8(gpTTYInfo->lfTTYFont.lfFaceName);
6139 if(strlen(t) < nfontName)
6140 snprintf(fontName_utf8, nfontName, "%s", t);
6142 fs_give((void **) &t);
6145 if(fontCharSet_utf8 != NULL){
6146 LPTSTR lpt;
6148 lpt = (LPTSTR) fs_get(nfontCharSet * sizeof(TCHAR));
6149 if(lpt){
6150 lpt[0] = '\0';
6151 mswin_charsetid2string(lpt, nfontCharSet, gpTTYInfo->lfTTYFont.lfCharSet);
6152 t = lptstr_to_utf8(lpt);
6153 if(strlen(t) < nfontCharSet)
6154 snprintf(fontCharSet_utf8, nfontCharSet, "%s", t);
6156 fs_give((void **) &t);
6158 fs_give((void **) &lpt);
6162 if(fontSize_utf8 != NULL){
6163 hDC = GetDC(ghTTYWnd);
6164 ppi = GetDeviceCaps(hDC, LOGPIXELSY);
6165 ReleaseDC(ghTTYWnd, hDC);
6166 snprintf(fontSize_utf8, nfontSize, "%d", MulDiv(-gpTTYInfo->lfTTYFont.lfHeight, 72, ppi));
6169 if(fontStyle_utf8 != NULL){
6170 char *sep[] = {"", ", "};
6171 int iSep = 0;
6173 *fontStyle_utf8 = '\0';
6174 if(gpTTYInfo->lfTTYFont.lfWeight >= FW_BOLD){
6175 strncpy(fontStyle_utf8, "bold", nfontStyle);
6176 fontStyle_utf8[nfontStyle-1] = '\0';
6177 iSep = 1;
6180 if(gpTTYInfo->lfTTYFont.lfItalic){
6181 strncat(fontStyle_utf8, sep[iSep], nfontStyle-strlen(fontStyle_utf8)-1);
6182 fontStyle_utf8[nfontStyle-1] = '\0';
6183 strncat(fontStyle_utf8, "italic", nfontStyle-strlen(fontStyle_utf8)-1);
6184 fontStyle_utf8[nfontStyle-1] = '\0';
6188 if(windowPosition != NULL){
6189 if(gpTTYInfo->fMinimized){
6190 strncpy(windowPosition, "MIN0", nwindowPosition);
6191 windowPosition[nwindowPosition-1] = '\0';
6193 else{
6195 * Get the window position. Constrain the top left corner
6196 * to be on the screen.
6198 GetWindowRect(ghTTYWnd, &wndRect);
6199 if(wndRect.left < 0)
6200 wndRect.left = 0;
6202 if(wndRect.top < 0)
6203 wndRect.top = 0;
6205 snprintf(windowPosition, nwindowPosition, "%dx%d+%d+%d", gpTTYInfo->actNColumn,
6206 gpTTYInfo->actNRow, wndRect.left, wndRect.top);
6209 if(gpTTYInfo->toolBarSize > 0){
6210 strncat(windowPosition, gpTTYInfo->toolBarTop ? "t" : "b",
6211 nwindowPosition-strlen(windowPosition)-1);
6212 windowPosition[nwindowPosition-1] = '\0';
6215 if(gfUseDialogs){
6216 strncat(windowPosition, "d", nwindowPosition-strlen(windowPosition)-1);
6217 windowPosition[nwindowPosition-1] = '\0';
6220 if(gpTTYInfo->hAccel){
6221 strncat(windowPosition, "a", nwindowPosition-strlen(windowPosition)-1);
6222 windowPosition[nwindowPosition-1] = '\0';
6225 if(gpTTYInfo->fMaximized){
6226 strncat(windowPosition, "!", nwindowPosition-strlen(windowPosition)-1);
6227 windowPosition[nwindowPosition-1] = '\0';
6231 if(foreColor != NULL)
6232 ConvertStringRGB(foreColor, nforeColor, gpTTYInfo->rgbFGColor);
6234 if(backColor != NULL)
6235 ConvertStringRGB(backColor, nbackColor, gpTTYInfo->rgbBGColor);
6237 if(caretStyle != NULL){
6238 int i;
6240 for(i = 0; MSWinCaretTable[i].name; i++)
6241 if(MSWinCaretTable[i].style == gpTTYInfo->cCaretStyle){
6242 strncpy(caretStyle, MSWinCaretTable[i].name, ncaretStyle);
6243 caretStyle[ncaretStyle-1] = '\0';
6244 break;
6248 return (0);
6252 void
6253 mswin_noscrollupdate(int flag)
6255 gpTTYInfo->noScrollUpdate = (flag != 0);
6256 if(flag == 0 && gpTTYInfo->scrollRangeChanged){
6257 mswin_setscrollrange(gpTTYInfo->noSUpdatePage, gpTTYInfo->noSUpdateRange);
6258 gpTTYInfo->noSUpdatePage = gpTTYInfo->noSUpdateRange = 0;
6259 gpTTYInfo->scrollRangeChanged = 0;
6265 * Set the scroll range.
6267 void
6268 mswin_setscrollrange (long page, long max)
6270 SCROLLINFO scrollInfo;
6272 if(gpTTYInfo->noScrollUpdate){
6273 gpTTYInfo->noSUpdatePage = page;
6274 gpTTYInfo->noSUpdateRange = max;
6275 gpTTYInfo->scrollRangeChanged = 1;
6276 return;
6278 if (max != gpTTYInfo->scrollRange) {
6279 scrollInfo.cbSize = sizeof(SCROLLINFO);
6280 scrollInfo.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_RANGE;
6281 scrollInfo.nMin = 0;
6283 if (max > 0) {
6284 scrollInfo.nMax = (int) max;
6285 scrollInfo.nPage = page;
6286 SetScrollInfo(ghTTYWnd, SB_VERT, &scrollInfo, TRUE);
6287 EnableScrollBar (ghTTYWnd, SB_VERT, ESB_ENABLE_BOTH);
6289 else {
6290 max = 0;
6291 scrollInfo.cbSize = sizeof(SCROLLINFO);
6292 scrollInfo.fMask |= SIF_POS;
6293 scrollInfo.nMax = 1;
6294 scrollInfo.nPos = 0;
6295 SetScrollInfo(ghTTYWnd, SB_VERT, &scrollInfo, TRUE);
6296 EnableScrollBar (ghTTYWnd, SB_VERT, ESB_DISABLE_BOTH);
6297 gpTTYInfo->scrollPos = 0;
6299 gpTTYInfo->scrollRange = (int)max;
6305 * Set the current scroll position.
6307 void
6308 mswin_setscrollpos (long pos)
6310 SCROLLINFO scrollInfo;
6312 if (pos != gpTTYInfo->scrollPos) {
6313 scrollInfo.cbSize = sizeof(SCROLLINFO);
6314 scrollInfo.fMask = SIF_PAGE | SIF_RANGE;
6316 GetScrollInfo(ghTTYWnd, SB_VERT, &scrollInfo);
6318 scrollInfo.fMask |= SIF_POS;
6319 scrollInfo.nPos = (int) pos;
6320 SetScrollInfo(ghTTYWnd, SB_VERT, &scrollInfo, TRUE);
6322 gpTTYInfo->scrollPos = pos;
6328 * retreive the current scroll postion.
6330 long
6331 mswin_getscrollpos (void)
6333 return ((long)((float)GetScrollPos (ghTTYWnd, SB_VERT)));
6338 * retreive the latest scroll to position.
6340 long
6341 mswin_getscrollto (void)
6343 return (gpTTYInfo->scrollTo);
6347 * install function to deal with LINEDOWN events
6349 void
6350 mswin_setscrollcallback (cbarg_t cbfunc)
6352 gScrollCallback = cbfunc;
6357 * install function to deal with sort menu messages
6359 void
6360 mswin_setsortcallback (cbarg_t cbfunc)
6362 gSortCallback = cbfunc;
6367 * install function to deal with sort menu messages
6369 void
6370 mswin_setflagcallback (cbarg_t cbfunc)
6372 gFlagCallback = cbfunc;
6376 void
6377 mswin_set_erasecreds_callback (cbvoid_t cbfunc)
6379 gEraseCredsCallback = cbfunc;
6383 * install function to deal with header mode flipping
6385 void
6386 mswin_sethdrmodecallback (cbarg_t cbfunc)
6388 gHdrCallback = cbfunc;
6393 * install function to deal with view in new window messages
6395 void
6396 mswin_setviewinwindcallback (cbvoid_t cbfunc)
6398 gViewInWindCallback = cbfunc;
6403 * install function to deal with zoom mode flipping
6405 void
6406 mswin_setzoomodecallback (cbarg_t cbfunc)
6408 gZoomCallback = cbfunc;
6413 * install function to deal with function key mode flipping
6415 void
6416 mswin_setfkeymodecallback (cbarg_t cbfunc)
6418 gFkeyCallback = cbfunc;
6423 * install function to deal with apply mode flipping
6425 void
6426 mswin_setselectedcallback (cbarg_t cbfunc)
6428 gSelectedCallback = cbfunc;
6433 * return 1 if new mail window is being used
6436 mswin_newmailwinon (void)
6438 return(gMswinNewMailWin.hwnd ? 1 : 0);
6444 void
6445 mswin_setdebugoncallback (cbvoid_t cbfunc)
6447 gIMAPDebugONCallback = cbfunc;
6451 void
6452 mswin_setdebugoffcallback (cbvoid_t cbfunc)
6454 gIMAPDebugOFFCallback = cbfunc;
6459 mswin_setconfigcallback (cbvoid_t cffunc)
6461 gConfigScreenCallback = cffunc;
6462 return(1);
6467 * Set the printer font
6469 void
6470 mswin_setprintfont(char *fontName, char *fontSize,
6471 char *fontStyle, char *fontCharSet)
6473 LPTSTR fn = NULL, fstyle = NULL, fc = NULL;
6475 if(fontName)
6476 fn = utf8_to_lptstr(fontName);
6478 if(fontStyle)
6479 fstyle = utf8_to_lptstr(fontStyle);
6481 if(fontCharSet)
6482 fc = utf8_to_lptstr(fontCharSet);
6484 /* Require a font name to set font info. */
6485 if(fn != NULL && *fn != '\0' && lstrlen(fn) <= LF_FACESIZE - 1){
6487 _tcsncpy(gPrintFontName, fn, sizeof(gPrintFontName)/sizeof(TCHAR));
6488 gPrintFontName[sizeof(gPrintFontName)/sizeof(TCHAR)-1] = 0;
6489 if(fstyle){
6490 _tcsncpy(gPrintFontStyle, fstyle, sizeof(gPrintFontStyle)/sizeof(TCHAR));
6491 gPrintFontStyle[sizeof(gPrintFontStyle)/sizeof(TCHAR)-1] = 0;
6492 _tcslwr(gPrintFontStyle); /* Lower case font style. */
6495 if(fc){
6496 _tcsncpy(gPrintFontCharSet, fc, sizeof(gPrintFontCharSet)/sizeof(TCHAR));
6497 gPrintFontCharSet[sizeof(gPrintFontCharSet)/sizeof(TCHAR)-1] = 0;
6500 gPrintFontSize = 12;
6501 if(ScanInt(fontSize, FONT_MIN_SIZE, FONT_MAX_SIZE, &gPrintFontSize))
6502 gPrintFontSize = abs(gPrintFontSize);
6504 gPrintFontSameAs = FALSE;
6506 else{
6507 gPrintFontName[0] = '\0';
6508 gPrintFontSameAs = TRUE;
6511 if(fn)
6512 fs_give((void **) &fn);
6514 if(fstyle)
6515 fs_give((void **) &fstyle);
6517 if(fc)
6518 fs_give((void **) &fc);
6522 void
6523 mswin_getprintfont(char *fontName_utf8, size_t nfontName,
6524 char *fontSize_utf8, size_t nfontSize,
6525 char *fontStyle_utf8, size_t nfontStyle,
6526 char *fontCharSet_utf8, size_t nfontCharSet)
6528 if(gPrintFontName[0] == '\0' || gPrintFontSameAs){
6529 if(fontName_utf8 != NULL)
6530 *fontName_utf8 = '\0';
6531 if(fontSize_utf8 != NULL)
6532 *fontSize_utf8 = '\0';
6533 if(fontStyle_utf8 != NULL)
6534 *fontStyle_utf8 = '\0';
6535 if(fontCharSet_utf8 != NULL)
6536 *fontCharSet_utf8 = '\0';
6538 else{
6539 char *u;
6541 if(fontName_utf8 != NULL){
6542 u = lptstr_to_utf8(gPrintFontName);
6543 if(u){
6544 strncpy(fontName_utf8, u, nfontName);
6545 fontName_utf8[nfontName-1] = 0;
6546 fs_give((void **) &u);
6550 if(fontSize_utf8 != NULL)
6551 snprintf(fontSize_utf8, nfontSize, "%d", gPrintFontSize);
6554 if(fontStyle_utf8 != NULL){
6555 u = lptstr_to_utf8(gPrintFontStyle);
6556 if(u){
6557 strncpy(fontStyle_utf8, u, nfontStyle);
6558 fontStyle_utf8[nfontStyle-1] = 0;
6559 fs_give((void **) &u);
6563 if(fontCharSet_utf8 != NULL){
6564 u = lptstr_to_utf8(gPrintFontCharSet);
6565 if(u){
6566 strncpy(fontCharSet_utf8, u, nfontCharSet);
6567 fontCharSet_utf8[nfontCharSet-1] = 0;
6568 fs_give((void **) &u);
6576 * Set the window help text. Add or delete the Help menu item as needed.
6579 mswin_sethelptextcallback(cbstr_t cbfunc)
6581 HMENU hMenu;
6583 gHelpCallback = cbfunc;
6585 hMenu = GetMenu (ghTTYWnd);
6586 if (hMenu == NULL)
6587 return (1);
6589 return(MSWHelpSetMenu (hMenu));
6595 * Set the window help text. Add or delete the Help menu item as needed.
6598 mswin_setgenhelptextcallback(cbstr_t cbfunc)
6600 HMENU hMenu;
6602 gHelpGenCallback = cbfunc;
6604 hMenu = GetMenu (ghTTYWnd);
6605 if (hMenu == NULL)
6606 return (1);
6608 return(MSWHelpSetMenu (hMenu));
6614 MSWHelpSetMenu(HMENU hMenu)
6616 BOOL brc;
6617 int count;
6620 * Find menu and update it.
6622 count = GetMenuItemCount (hMenu);
6623 if (count == -1)
6624 return (1);
6626 hMenu = GetSubMenu (hMenu, count - 1);
6627 if (hMenu == NULL)
6628 return (1);
6631 * Insert or delete generic help item
6633 if (gHelpGenCallback == NULL){
6634 if (gfHelpGenMenu) {
6635 brc = DeleteMenu (hMenu, IDM_MI_GENERALHELP, MF_BYCOMMAND);
6636 DrawMenuBar (ghTTYWnd);
6638 gfHelpGenMenu = FALSE;
6640 else {
6641 if (!gfHelpGenMenu) {
6642 brc = InsertMenu (hMenu, 0,
6643 MF_BYPOSITION | MF_STRING,
6644 IDM_MI_GENERALHELP, TEXT("&General Help"));
6645 DrawMenuBar (ghTTYWnd);
6647 gfHelpGenMenu = TRUE;
6651 * Insert or delete screen help item
6653 if (gHelpCallback == NULL){
6654 if (gfHelpMenu) {
6655 brc = DeleteMenu (hMenu, IDM_HELP, MF_BYCOMMAND);
6656 DrawMenuBar (ghTTYWnd);
6658 gfHelpMenu = FALSE;
6660 else {
6661 if (!gfHelpMenu) {
6662 brc = InsertMenu (hMenu, gHelpGenCallback ? 2 : 1,
6663 MF_BYPOSITION | MF_STRING,
6664 IDM_HELP, TEXT("Screen Help in &New Window"));
6665 DrawMenuBar (ghTTYWnd);
6667 gfHelpMenu = TRUE;
6670 return (0);
6675 * Set the text displayed when someone tries to close the application
6676 * the wrong way.
6678 void
6679 mswin_setclosetext (char *pCloseText)
6681 gpCloseText = pCloseText;
6686 * Called when upper layer is in a busy loop. Allows us to yeild to
6687 * Windows and perhaps process some events. Does not yeild control
6688 * to other applications.
6691 mswin_yield (void)
6693 MSG msg;
6694 DWORD start;
6695 int didmsg = FALSE;
6697 if (gScrolling)
6698 return (TRUE);
6700 start = GetTickCount ();
6701 #ifdef CDEBUG
6702 if (mswin_debug > 16)
6703 fprintf (mswin_debugfile, "mswin_yeild:: Entered\n");
6704 #endif
6705 if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {
6706 if (gpTTYInfo->hAccel == NULL ||
6707 !TranslateAccelerator (ghTTYWnd, gpTTYInfo->hAccel, &msg)) {
6708 TranslateMessage (&msg);
6709 DispatchMessage (&msg);
6710 didmsg = TRUE;
6713 #ifdef CDEBUG
6714 if (mswin_debug > 16)
6715 fprintf (mswin_debugfile, "mswin_yeild:: Delay %ld msec\n",
6716 GetTickCount () - start);
6717 #endif
6718 return (didmsg);
6723 * Called to see if we can process input.
6724 * We can't process input when we are in a scrolling mode.
6727 mswin_caninput (void)
6729 return (!gScrolling && !gMouseTracking);
6734 * Called to see if there is a character available.
6737 mswin_charavail (void)
6739 MSG msg;
6740 BOOL ca, pa, ma;
6742 if (gScrolling)
6743 return (FALSE);
6745 RestoreMouseCursor();
6748 * If there are no windows messages waiting for this app, GetMessage
6749 * can take a long time. So before calling GetMessage check if
6750 * there is anything I should be doing. If there is, then only
6751 * call PeekMessage.
6752 * BUT! Don't let too much time elapse between calls to GetMessage
6753 * or we'll shut out other windows.
6755 ca = CQAvailable ();
6756 pa = EditPasteAvailable ();
6757 #ifdef CDEBUG
6758 start = GetTickCount ();
6759 if (mswin_debug > 16)
6760 fprintf (mswin_debugfile, "%s mswin_charavail:: Entered, ca %d, pa %d\n",dtime(),ca,pa);
6761 #endif
6762 if ((ca || pa) && GetTickCount () < gGMLastCall + GM_MAX_TIME)
6763 ma = PeekMessage (&msg, NULL, 0, 0, PM_NOYIELD | PM_REMOVE);
6764 else {
6765 ma = GetMessage (&msg, NULL, 0, 0);
6766 gGMLastCall = GetTickCount ();
6768 if (ma) {
6769 if (gpTTYInfo->hAccel == NULL ||
6770 !TranslateAccelerator (ghTTYWnd, gpTTYInfo->hAccel, &msg)) {
6771 TranslateMessage (&msg);
6772 DispatchMessage (&msg);
6775 #ifdef CDEBUG
6776 if (mswin_debug > 16)
6777 fprintf (mswin_debugfile, "%s mswin_charavail:: Delay %ld msec\n",
6778 dtime(), GetTickCount () - start);
6779 #endif
6781 return (pa || ca || CQAvailable ());
6786 * Call to get next character. Dispatch one message.
6789 mswin_getc (void)
6791 BOOL ca, pa, ma;
6792 MSG msg;
6794 if (gScrolling)
6795 return (NODATA);
6797 RestoreMouseCursor();
6799 mswin_flush();
6803 * If there are no windows messages waiting for this app, GetMessage
6804 * can take a long time. So before calling GetMessage check if
6805 * there is anything I should be doing. If there is, then only
6806 * call PeekMessage.
6808 ca = CQAvailable ();
6809 pa = EditPasteAvailable ();
6810 #ifdef CDEBUG
6811 if (mswin_debug > 16) {
6812 start = GetTickCount ();
6813 fprintf (mswin_debugfile, "mswin_getc:: Entered, ca %d pa %d\n", ca, pa);
6815 #endif
6816 if ((ca || pa) && GetTickCount () < gGMLastCall + GM_MAX_TIME)
6817 ma = PeekMessage (&msg, NULL, 0, 0, PM_NOYIELD | PM_REMOVE);
6818 else {
6819 ma = GetMessage (&msg, NULL, 0, 0);
6820 gGMLastCall = GetTickCount ();
6822 if (ma) {
6823 if (gpTTYInfo->hAccel == NULL ||
6824 !TranslateAccelerator (ghTTYWnd, gpTTYInfo->hAccel, &msg)) {
6825 TranslateMessage (&msg);
6826 DispatchMessage (&msg);
6829 #ifdef CDEBUG
6830 if (mswin_debug > 16)
6831 fprintf (mswin_debugfile, "mswin_getc:: Delay %ld msec\n",
6832 GetTickCount () - start);
6833 #endif
6836 if (pa) {
6837 SelClear ();
6838 return (EditPasteGet ());
6840 if (ca || CQAvailable ()) {
6841 SelClear();
6842 return ((UCS)(CQGet ()));
6845 return (NODATA);
6850 * Like mswin_getc, but don't yield control. Returns a CTRL key values
6851 * where, for example, ctrl+c --> CTRL|'C'.
6853 LOCAL UCS
6854 mswin_getc_fast (void)
6856 RestoreMouseCursor();
6858 if (EditPasteAvailable ()) {
6859 SelClear ();
6860 return (EditPasteGet ());
6862 if (CQAvailable ()) {
6863 SelClear ();
6864 return ((UCS)CQGet ());
6867 return (NODATA);
6872 * Flush the character input queue.
6874 void
6875 mswin_flush_input(void)
6878 * GetQueueStatus tells us if there are any input messages in the message
6879 * queue. If there are, we call mswin_getc which will retrieve the
6880 * next message (which may or may not be an input message) and process
6881 * it. We do that until all the input messages are gone.
6883 CQInit();
6885 while(GetQueueStatus(QS_INPUT))
6886 (void) mswin_getc();
6888 /* And we clear Pine's character input queue, too. */
6889 CQInit();
6894 * ibmmove - Move cursor to...
6897 mswin_move (int row, int column)
6900 FlushWriteAccum ();
6901 if (row < 0 || row >= gpTTYInfo->actNRow)
6902 return (-1);
6903 if (column < 0 || column >= gpTTYInfo->actNColumn)
6904 return (-1);
6905 gpTTYInfo->nRow = (CORD)row;
6906 gpTTYInfo->nColumn = (CORD)column;
6907 MoveTTYCursor (ghTTYWnd);
6908 return (0);
6913 mswin_getpos (int *row, int *column)
6915 FlushWriteAccum ();
6916 if (row == NULL || column == NULL)
6917 return (-1);
6918 *row = gpTTYInfo->nRow;
6919 *column = gpTTYInfo->nColumn;
6920 return (0);
6925 mswin_getscreensize (int *row, int *column)
6927 if (row == NULL || column == NULL)
6928 return (-1);
6929 *row = gpTTYInfo->actNRow;
6930 *column = gpTTYInfo->actNColumn;
6931 #ifdef SDEBUG
6932 if (mswin_debug >= 5)
6933 fprintf (mswin_debugfile, "mswin_getscreensize::: reported size %d, %d\n",
6934 *row, *column);
6935 #endif
6937 *column = MIN(*column, NLINE-1);
6939 return (0);
6943 void
6944 mswin_minimize()
6946 if (!gpTTYInfo->fMinimized)
6947 ShowWindow(ghTTYWnd, SW_MINIMIZE);
6952 mswin_showcursor (int show)
6954 int was_shown = gpTTYInfo->fCursorOn;
6956 if (show) {
6957 /* if the cursor was not already show, show it now. */
6958 if (!was_shown) {
6959 gpTTYInfo->fCursorOn = TRUE;
6960 ShowCursor(TRUE);
6963 else {
6964 /* If the cursor is shown, hide it. */
6965 if (was_shown){
6966 gpTTYInfo->fCursorOn = FALSE;
6967 ShowCursor(FALSE);
6971 return (was_shown);
6976 mswin_showcaret (int show)
6978 int was_shown = gpTTYInfo->fCaretOn;
6980 if (show) {
6981 /* if the caret was not already show, show it now. */
6982 if (!was_shown) {
6983 gpTTYInfo->fCaretOn = TRUE;
6984 ShowCaret(ghTTYWnd);
6987 else {
6988 /* If the caret is shown, hide it. */
6989 if (was_shown){
6990 gpTTYInfo->fCaretOn = FALSE;
6991 HideCaret(ghTTYWnd);
6995 return (was_shown);
7000 mswin_puts (char *utf8_str)
7002 int strLen;
7003 LPTSTR lptstr_str;
7005 FlushWriteAccum ();
7006 if (utf8_str == NULL)
7007 return (-1);
7008 if(!(lptstr_str = utf8_to_lptstr(utf8_str)))
7009 return(-1);
7010 strLen = (int)_tcslen (lptstr_str);
7011 if (strLen > 0)
7012 WriteTTYText (ghTTYWnd, lptstr_str, strLen);
7014 fs_give((void **) &lptstr_str);
7015 return (0);
7020 mswin_puts_n (char *utf8_str, int n)
7022 LPTSTR lptstr_str, lptstr_p;
7024 FlushWriteAccum ();
7025 if (utf8_str == NULL)
7026 return (-1);
7027 lptstr_str = utf8_to_lptstr(utf8_str);
7028 if(n < _tcslen(lptstr_str))
7029 lptstr_str[n] = '\0';
7030 for (lptstr_p = lptstr_str; n > 0 && *lptstr_p; n--, lptstr_p++)
7032 if (lptstr_p > lptstr_str)
7033 WriteTTYText (ghTTYWnd, lptstr_str, (int)(lptstr_p - lptstr_str));
7035 fs_give((void **) &lptstr_str);
7036 return (0);
7041 mswin_putblock (char *utf8_str, int strLen)
7043 LPTSTR lptstr_str;
7045 FlushWriteAccum ();
7046 if (utf8_str == NULL)
7047 return (-1);
7048 lptstr_str = utf8_to_lptstr(utf8_str);
7049 if (strLen > 0)
7050 WriteTTYText (ghTTYWnd, lptstr_str, strLen);
7051 fs_give((void **) &lptstr_str);
7052 return (0);
7057 * mswin_putc - put a character at the current position in the
7058 * current colors
7061 mswin_putc (UCS ucs)
7063 TCHAR cc = (TCHAR)ucs;
7064 if(ucs == ARABIC_LRM || ucs == ARABIC_RLM){
7065 FlushWriteAccum();
7066 WriteTTYBlock (ghTTYWnd, &cc, 1);
7067 return 0;
7069 if (ucs >= (UCS)(' ')) {
7070 /* Not carriage control. */
7071 gpTTYInfo->writeAccum[gpTTYInfo->writeAccumCount++] = (TCHAR)ucs;
7072 if (gpTTYInfo->writeAccumCount == WRITE_ACCUM_SIZE)
7073 FlushWriteAccum ();
7075 else {
7076 /* Carriage control. Need to flush write accumulator and
7077 * write this char. */
7078 FlushWriteAccum ();
7079 WriteTTYBlock (ghTTYWnd, &cc, 1);
7081 return (0);
7086 * ibmoutc - output a single character with the right attributes, but
7087 * don't advance the cursor
7090 mswin_outc (char c)
7092 RECT rect;
7093 long offset;
7095 FlushWriteAccum ();
7097 switch (c) {
7098 case ASCII_BEL:
7099 MessageBeep (0);
7100 break;
7102 case ASCII_BS:
7103 case ASCII_CR:
7104 case ASCII_LF:
7105 /* Do nothing for these screen motion characters. */
7106 break;
7109 default:
7110 /* Paint character to screen. */
7111 offset = (gpTTYInfo->nRow * gpTTYInfo->actNColumn) + gpTTYInfo->nColumn;
7112 gpTTYInfo->pScreen[offset] = c;
7113 gpTTYInfo->pCellWidth[offset] = wcellwidth((UCS)c) * gpTTYInfo->xChar;
7114 gpTTYInfo->pAttrib[offset] = gpTTYInfo->curAttrib;
7116 /* Invalidate rectange covering singel character. */
7117 rect.left = (gpTTYInfo->nColumn * gpTTYInfo->xChar) +
7118 gpTTYInfo->xOffset;
7119 rect.right = rect.left + gpTTYInfo->xChar;
7120 rect.top = (gpTTYInfo->nRow * gpTTYInfo->yChar) +
7121 gpTTYInfo->yOffset;
7122 rect.bottom = rect.top + gpTTYInfo->yChar;
7123 gpTTYInfo->screenDirty = TRUE;
7124 InvalidateRect (ghTTYWnd, &rect, FALSE);
7125 break;
7127 return (0);
7131 * ibmrev - change reverse video state
7134 mswin_rev (int state)
7136 int curState = (gpTTYInfo->curAttrib.style & CHAR_ATTR_REV) != 0;
7138 if (state != curState){
7139 FlushWriteAccum ();
7140 if (state) {
7141 gpTTYInfo->curAttrib.style |= CHAR_ATTR_REV;
7142 SetReverseColor();
7144 else{
7145 gpTTYInfo->curAttrib.style &= ~CHAR_ATTR_REV;
7146 pico_set_normal_color();
7150 return (0);
7155 * Get current reverse video state.
7158 mswin_getrevstate (void)
7160 return ((gpTTYInfo->curAttrib.style & CHAR_ATTR_REV) != 0);
7165 * ibmrev - change reverse video state
7168 mswin_bold (int state)
7170 int curState = (gpTTYInfo->curAttrib.style & CHAR_ATTR_BOLD) != 0;
7172 if (state != curState){
7173 FlushWriteAccum ();
7174 if (state)
7175 gpTTYInfo->curAttrib.style |= CHAR_ATTR_BOLD;
7176 else
7177 gpTTYInfo->curAttrib.style &= ~CHAR_ATTR_BOLD;
7180 return (0);
7185 * ibmrev - change reverse video state
7188 mswin_uline (int state)
7190 int curState = (gpTTYInfo->curAttrib.style & CHAR_ATTR_ULINE) != 0;
7192 if (state != curState){
7193 FlushWriteAccum ();
7194 if (state)
7195 gpTTYInfo->curAttrib.style |= CHAR_ATTR_ULINE;
7196 else
7197 gpTTYInfo->curAttrib.style &= ~CHAR_ATTR_ULINE;
7200 return (0);
7205 * ibmeeol - erase to the end of the line
7208 mswin_eeol (void)
7210 TCHAR *cStart;
7211 CharAttrib *aStart;
7212 int *cwStart;
7213 long length, i;
7214 RECT rect;
7216 FlushWriteAccum ();
7218 /* From current position to end of line. */
7219 length = gpTTYInfo->actNColumn - gpTTYInfo->nColumn;
7221 cStart = gpTTYInfo->pScreen + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
7222 + gpTTYInfo->nColumn;
7223 cwStart = gpTTYInfo->pCellWidth + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
7224 + gpTTYInfo->nColumn;
7225 for(i = 0; i < length; i++){
7226 cStart[i] = (TCHAR)(' ');
7227 cwStart[i] = gpTTYInfo->xChar;
7230 aStart = gpTTYInfo->pAttrib
7231 + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
7232 + gpTTYInfo->nColumn;
7233 for(; length > 0; length--, aStart++){
7234 aStart->style = CHAR_ATTR_NORM;
7235 aStart->rgbFG = gpTTYInfo->curAttrib.rgbFG;
7236 aStart->rgbBG = gpTTYInfo->curAttrib.rgbBG;
7239 rect.left = (gpTTYInfo->nColumn * gpTTYInfo->xChar) +
7240 gpTTYInfo->xOffset;
7241 rect.right = gpTTYInfo->xSize;
7242 rect.top = (gpTTYInfo->nRow * gpTTYInfo->yChar) +
7243 gpTTYInfo->yOffset;
7244 rect.bottom = rect.top + gpTTYInfo->yChar;
7245 gpTTYInfo->screenDirty = TRUE;
7246 InvalidateRect (ghTTYWnd, &rect, FALSE);
7248 return (0);
7253 * ibmeeop - clear from cursor to end of page
7256 mswin_eeop (void)
7258 TCHAR *cStart;
7259 CharAttrib *aStart;
7260 int *cwStart;
7261 long length, i;
7262 RECT rect;
7264 FlushWriteAccum ();
7265 /* From current position to end of screen. */
7267 cStart = gpTTYInfo->pScreen + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
7268 + gpTTYInfo->nColumn;
7269 cwStart = gpTTYInfo->pCellWidth + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
7270 + gpTTYInfo->nColumn;
7271 length = (long)((gpTTYInfo->pScreen
7272 + (gpTTYInfo->actNColumn * gpTTYInfo->actNRow))
7273 - cStart);
7274 for(i = 0; i < length; i ++){
7275 cStart[i] = (TCHAR)(' ');
7276 cwStart[i] = gpTTYInfo->xChar;
7279 aStart = gpTTYInfo->pAttrib
7280 + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
7281 + gpTTYInfo->nColumn;
7283 for(; length-- > 0; aStart++){
7284 aStart->style = CHAR_ATTR_NORM;
7285 aStart->rgbFG = gpTTYInfo->curAttrib.rgbFG;
7286 aStart->rgbBG = gpTTYInfo->curAttrib.rgbBG;
7289 /* Invalidate a rectangle that includes all of the current line down
7290 * to the bottom of the window. */
7291 rect.left = 0;
7292 rect.right = gpTTYInfo->xSize;
7293 rect.top = (gpTTYInfo->nRow * gpTTYInfo->yChar) +
7294 gpTTYInfo->yOffset;
7295 rect.bottom = gpTTYInfo->ySize;
7296 gpTTYInfo->screenDirty = TRUE;
7297 InvalidateRect (ghTTYWnd, &rect, FALSE);
7299 return (0);
7304 * ibmbeep - system beep...
7307 mswin_beep (void)
7309 MessageBeep (MB_OK);
7310 return (0);
7315 * pause - wait in function for specified number of seconds.
7317 void
7318 mswin_pause (int seconds)
7320 DWORD stoptime;
7322 stoptime = GetTickCount () + (DWORD) seconds * 1000;
7323 while (stoptime > GetTickCount ())
7324 mswin_yield ();
7329 * ibmflush - Flush output to screen.
7333 mswin_flush (void)
7337 * Flush cached changes, then update the window.
7339 FlushWriteAccum ();
7340 UpdateWindow (ghTTYWnd);
7342 return (0);
7347 * A replacement for fflush
7348 * relies on #define fflush mswin_fflush
7350 #undef fflush
7352 mswin_fflush (FILE *f)
7354 if (f == stdout) {
7355 mswin_flush();
7357 else
7358 fflush (f);
7360 return(0);
7365 * Set the cursor
7367 void
7368 mswin_setcursor (int newcursor)
7370 HCURSOR hNewCursor;
7372 switch(newcursor){
7373 case MSWIN_CURSOR_BUSY :
7374 hNewCursor = ghCursorBusy;
7375 mswin_showcursor(TRUE);
7376 break;
7378 case MSWIN_CURSOR_IBEAM :
7379 hNewCursor = ghCursorIBeam;
7380 break;
7382 case MSWIN_CURSOR_HAND :
7383 if(hNewCursor = ghCursorHand)
7384 break;
7385 /* ELSE fall thru to normal cursor */
7387 case MSWIN_CURSOR_ARROW :
7388 default :
7389 hNewCursor = ghCursorArrow;
7390 break;
7393 /* If new cursor requested, select it. */
7394 if (ghCursorCurrent != hNewCursor)
7395 SetCursor (ghCursorCurrent = hNewCursor);
7399 void
7400 RestoreMouseCursor()
7402 if(ghCursorCurrent == ghCursorBusy)
7403 mswin_setcursor(MSWIN_CURSOR_ARROW);
7408 * Display message in windows dialog box.
7410 void
7411 mswin_messagebox (char *msg_utf8, int err)
7413 LPTSTR msg_lptstr;
7415 mswin_killsplash();
7417 msg_lptstr = utf8_to_lptstr(msg_utf8);
7418 MessageBox (NULL, msg_lptstr, gszAppName,
7419 MB_OK | ((err) ? MB_ICONSTOP : MB_ICONINFORMATION));
7420 fs_give((void **) &msg_lptstr);
7425 * Signals whether or not Paste should be turned on in the
7426 * menu bar.
7428 void
7429 mswin_allowpaste (int on)
7431 static short stackp = 0;
7432 static unsigned long stack = 0L;
7434 switch(on){
7435 case MSWIN_PASTE_DISABLE :
7436 if(stackp){ /* previous state? */
7437 if((stackp -= 2) < 0)
7438 stackp = 0;
7440 gPasteEnabled = ((stack >> stackp) & 0x03);
7442 else
7443 gPasteEnabled = MSWIN_PASTE_DISABLE;
7445 break;
7447 case MSWIN_PASTE_FULL :
7448 case MSWIN_PASTE_LINE :
7449 if(gPasteEnabled){ /* current state? */
7450 stack |= ((unsigned long) gPasteEnabled << stackp);
7451 stackp += 2;
7454 gPasteEnabled = on;
7455 break;
7458 #ifdef ACCELERATORS
7459 UpdateAccelerators(ghTTYWnd);
7460 #endif
7465 * Signals whether or not Copy/Cut should be turned on in the
7466 * menu bar.
7468 void
7469 mswin_allowcopy (getc_t copyfunc)
7471 gCopyCutFunction = copyfunc;
7472 gAllowCopy = (copyfunc != NULL);
7473 #ifdef ACCELERATORS
7474 UpdateAccelerators(ghTTYWnd);
7475 #endif
7480 * Signals whether or not Copy/Cut should be turned on in the
7481 * menu bar.
7483 void
7484 mswin_allowcopycut (getc_t copyfunc)
7486 gCopyCutFunction = copyfunc;
7487 gAllowCopy = gAllowCut = (copyfunc != NULL);
7488 #ifdef ACCELERATORS
7489 UpdateAccelerators(ghTTYWnd);
7490 #endif
7495 * Replace the clipboard's contents with the given string
7497 void
7498 mswin_addclipboard(char *s)
7500 HANDLE hCB;
7501 char *pCB;
7502 size_t sSize;
7504 if(s && (sSize = strlen(s))){
7505 if (OpenClipboard (ghTTYWnd)) { /* ...and we get the CB. */
7506 if (EmptyClipboard ()
7507 && (hCB = GlobalAlloc (GMEM_MOVEABLE, sSize+2))){
7508 pCB = GlobalLock (hCB);
7509 memcpy (pCB, s, sSize);
7510 pCB[sSize] = '\0'; /* tie it off */
7512 GlobalUnlock (hCB);
7514 if (SetClipboardData (CF_TEXT, hCB) == NULL)
7515 /* Failed! Free the data. */
7516 GlobalFree (hCB);
7519 CloseClipboard ();
7526 * Signals if the upper layer wants to track the mouse.
7528 void
7529 mswin_allowmousetrack (int b)
7531 gAllowMouseTrack = b;
7532 if (b)
7533 SelClear ();
7534 MyTimerSet ();
7539 * register's callback to warn
7541 void
7542 mswin_mousetrackcallback(cbarg_t cbfunc)
7544 if(!(gMouseTrackCallback = cbfunc))
7545 mswin_setcursor (MSWIN_CURSOR_ARROW);
7550 * Add text to the new mail icon.
7551 * Nothing done in win 3.1 (consider changing the program name?)
7552 * For win95 we add some tool tip text to the tray icon.
7554 void
7555 mswin_newmailtext (char *t_utf8)
7557 LPTSTR t_lptstr;
7560 * If we're given text, then blip the icon to let the user know.
7561 * (NOTE: the new shell also gets an updated tooltip.)
7562 * Otherwise, we're being asked to resume our normal state...
7564 if(t_utf8){
7566 * Change the appearance of minimized icon so user knows there's new
7567 * mail waiting for them. On win 3.1 systems we redraw the icon.
7568 * on win95 systems we update the icon in the task bar,
7569 * and possibly udpate the small icon in the taskbar tool tray.
7571 t_lptstr = utf8_to_lptstr(t_utf8);
7572 UpdateTrayIcon(NIM_MODIFY, ghNewMailIcon, t_lptstr);
7573 fs_give((void **) &t_lptstr);
7574 PostMessage(ghTTYWnd,WM_SETICON,ICON_BIG,(LPARAM) ghNewMailIcon);
7575 PostMessage(ghTTYWnd,WM_SETICON,ICON_SMALL,(LPARAM) ghNewMailIcon);
7577 gpTTYInfo->fNewMailIcon = TRUE;
7579 else if(gpTTYInfo->fNewMailIcon) {
7580 UpdateTrayIcon(NIM_MODIFY, ghNormalIcon, TEXT("Alpine"));
7581 PostMessage(ghTTYWnd,WM_SETICON,ICON_BIG,(LPARAM) ghNormalIcon);
7582 PostMessage(ghTTYWnd,WM_SETICON,ICON_SMALL,(LPARAM) ghNormalIcon);
7584 gpTTYInfo->fNewMailIcon = FALSE;
7589 void
7590 mswin_mclosedtext (char *t_utf8)
7592 LPTSTR t_lptstr;
7594 if(t_utf8 && gpTTYInfo->fMClosedIcon == FALSE){
7596 * Change the appearance of minimized icon so user knows
7597 * the mailbox closed.
7599 t_lptstr = utf8_to_lptstr(t_utf8);
7600 UpdateTrayIcon(NIM_MODIFY, ghMClosedIcon, t_lptstr);
7601 fs_give((void **) &t_lptstr);
7602 PostMessage(ghTTYWnd,WM_SETICON,ICON_BIG,(LPARAM) ghMClosedIcon);
7603 PostMessage(ghTTYWnd,WM_SETICON,ICON_SMALL,(LPARAM) ghMClosedIcon);
7605 gpTTYInfo->fMClosedIcon = TRUE;
7607 else if(t_utf8 == NULL && gpTTYInfo->fMClosedIcon) {
7608 /* only go from yellow to green */
7609 UpdateTrayIcon(NIM_MODIFY, ghNormalIcon, TEXT("Alpine"));
7610 PostMessage(ghTTYWnd,WM_SETICON,ICON_BIG,(LPARAM) ghNormalIcon);
7611 PostMessage(ghTTYWnd,WM_SETICON,ICON_SMALL,(LPARAM) ghNormalIcon);
7613 gpTTYInfo->fMClosedIcon = FALSE;
7617 void
7618 mswin_trayicon(int show)
7620 if(show){
7621 if(!gpTTYInfo->fTrayIcon){
7622 UpdateTrayIcon(NIM_ADD, ghNormalIcon, TEXT("Alpine"));
7623 gpTTYInfo->fTrayIcon = TRUE;
7626 else{
7627 if(gpTTYInfo->fTrayIcon){
7628 UpdateTrayIcon(NIM_DELETE, 0, NULL);
7629 gpTTYInfo->fTrayIcon = FALSE;
7635 void
7636 UpdateTrayIcon(DWORD dwMsg, HICON hIcon, LPTSTR tip)
7638 NOTIFYICONDATA nt;
7640 nt.cbSize = sizeof (nt);
7641 nt.hWnd = ghTTYWnd;
7642 nt.uID = TASKBAR_ICON_NEWMAIL;
7643 switch(dwMsg){
7644 case NIM_DELETE :
7645 nt.uFlags = 0;
7646 break;
7648 case NIM_ADD : /* send msg to add icon to tray */
7649 nt.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
7650 nt.uCallbackMessage = TASKBAR_ICON_MESSAGE;
7652 if(tip){
7653 _tcsncpy (nt.szTip, tip, 63);
7654 nt.szTip[63] = '\0';
7656 else
7657 nt.szTip[0] = '\0';
7658 nt.hIcon = hIcon;
7659 break;
7661 case NIM_MODIFY : /* send msg to modify icon in tray */
7662 nt.uFlags = NIF_ICON | NIF_TIP;
7663 if(tip){
7664 _tcsncpy (nt.szTip, tip, 63);
7665 nt.szTip[63] = '\0';
7667 else
7668 nt.szTip[0] = '\0';
7669 nt.hIcon = hIcon;
7670 break;
7672 default :
7673 return;
7676 Shell_NotifyIcon (dwMsg, &nt);
7681 /*---------------------------------------------------------------------------
7683 * Client level menu item stuff.
7685 * These are menu items that activate commands in the "client" program.
7686 * Generally, the client calls us to tell us which menu items are active
7687 * and what key stroke they generate. When such an item is selected it's
7688 * key stroke is injected into the character queue as if it was typed by
7689 * the user.
7691 *-------------------------------------------------------------------------*/
7694 * Clear active status of all "menu items".
7696 void
7697 mswin_menuitemclear (void)
7699 int i;
7700 HWND hWnd;
7703 for (i = 0; i < KS_COUNT; ++i) {
7704 gpTTYInfo->menuItems[i].miActive = FALSE;
7705 if (gpTTYInfo->toolBarSize > 0) {
7706 hWnd = GetDlgItem(gpTTYInfo->hTBWnd, i + KS_RANGESTART);
7707 if (hWnd != NULL)
7708 EnableWindow(hWnd, FALSE);
7712 gpTTYInfo->menuItemsCurrent = FALSE;
7713 gpTTYInfo->menuItemsIndex = 1;
7714 for(i = 0; i < KS_COUNT; i++)
7715 gpTTYInfo->menuItems[i].miIndex = 0;
7720 * Add an item to the cmdmenu
7722 void
7723 mswin_menuitemadd (UCS key, char *label, int menuitem, int flags)
7725 int i;
7726 HWND hWnd;
7728 if (menuitem >= KS_RANGESTART && menuitem <= KS_RANGEEND) {
7730 gpTTYInfo->menuItemsCurrent = FALSE;
7732 i = menuitem - KS_RANGESTART;
7733 gpTTYInfo->menuItems[i].miActive = TRUE;
7734 gpTTYInfo->menuItems[i].miKey = key;
7735 if(!gpTTYInfo->menuItems[i].miIndex){
7736 gpTTYInfo->menuItems[i].miLabel = label;
7737 gpTTYInfo->menuItems[i].miIndex = gpTTYInfo->menuItemsIndex++;
7740 if (gpTTYInfo->toolBarSize > 0) {
7741 hWnd = GetDlgItem(gpTTYInfo->hTBWnd, menuitem);
7742 if (hWnd != NULL)
7743 EnableWindow(hWnd, TRUE);
7750 * Called when a menu command arrives with an unknown ID. If it is
7751 * within the range of the additional menu items, insert the
7752 * corresponding character into the char input queue.
7754 void
7755 ProcessMenuItem (HWND hWnd, WPARAM wParam)
7757 PTTYINFO pTTYInfo;
7758 int i;
7760 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
7761 if (pTTYInfo == NULL)
7762 return;
7765 if (wParam >= KS_RANGESTART && wParam <= KS_RANGEEND) {
7766 i = (int)(wParam - KS_RANGESTART);
7767 if (pTTYInfo->menuItems[i].miActive)
7768 CQAdd (pTTYInfo->menuItems[i].miKey, 0);
7774 * Called to set a new menu.
7777 mswin_setwindowmenu (int menu)
7779 int oldmenu;
7780 HMENU holdmenu;
7781 HMENU hmenu;
7784 oldmenu = gpTTYInfo->curWinMenu;
7785 holdmenu = GetMenu (ghTTYWnd);
7786 if (gpTTYInfo->curWinMenu != menu) {
7788 hmenu = LoadMenu (ghInstance, MAKEINTRESOURCE (menu));
7789 if (hmenu != NULL) {
7790 if (SetMenu (ghTTYWnd, hmenu) != 0) {
7791 DestroyMenu (holdmenu);
7792 gfHelpMenu = gfHelpGenMenu = FALSE;
7793 gpTTYInfo->curWinMenu = menu;
7797 if(menu == MENU_DEFAULT){
7798 TBSwap (ghTTYWnd, IDD_TOOLBAR);
7799 if(hmenu != NULL)
7800 (void) MSWHelpSetMenu(hmenu);
7802 else{
7803 TBSwap (ghTTYWnd, IDD_COMPOSER_TB);
7806 return (oldmenu);
7811 /*---------------------------------------------------------------------------
7813 * Printing stuff
7815 *-------------------------------------------------------------------------*/
7818 * Printing globals
7820 LOCAL HDC P_PrintDC; /* Printer device context. */
7821 LOCAL int P_PageRows; /* Number of rows we put on a page. */
7822 LOCAL int P_PageColumns; /* Number of columns we put on a page. */
7823 LOCAL int P_RowHeight; /* Hight of a row in printer pixels. */
7824 LOCAL int P_CurRow; /* Current row, starting at zero */
7825 LOCAL int P_CurCol; /* Current col, starting at zero. */
7826 LOCAL int P_TopOffset; /* Top Margin offset, in pixels. */
7827 LOCAL int P_LeftOffset; /* Top Margin offset, in pixels. */
7828 LOCAL HFONT P_hFont; /* Handle to printing font. */
7829 LPTSTR P_LineText; /* Pointer to line buffer. */
7835 * Define the margin as number of lines at top and bottom of page.
7836 * (might be better to define as a percent of verticle page size)
7838 #define VERTICLE_MARGIN 3 /* lines at top and bottom of page. */
7839 #define HORIZONTAL_MARGIN 1 /* margine at left & right in chars */
7842 * Several errors that can be reported.
7844 #define PE_DIALOG_FAILED 1
7845 #define PE_USER_CANCEL 2
7846 #define PE_CANT_START_DOC 3
7847 #define PE_CANT_FINISH_DOC 4
7848 #define PE_OUT_OF_MEMORY 5
7849 #define PE_GENERAL_ERROR 6
7850 #define PE_OUT_OF_DISK 7
7851 #define PE_PRINTER_NOT_FOUND 8
7852 #define PE_PINE_INTERNAL 9
7853 #define PE_FONT_FAILED 10
7856 LOCAL struct pe_error_message {
7857 int error_code;
7858 char *error_message;
7859 } P_ErrorMessages[] = {
7860 { PE_DIALOG_FAILED, "Print Dialog Failed"},
7861 { PE_USER_CANCEL, "User canceled" },
7862 { PE_CANT_START_DOC, "Can't start document" },
7863 { PE_OUT_OF_MEMORY, "Out of memory" },
7864 { PE_CANT_FINISH_DOC, "Can't finish document" },
7865 { PE_OUT_OF_MEMORY, "Out of memory" },
7866 { PE_OUT_OF_DISK, "Out of disk space" },
7867 { PE_PRINTER_NOT_FOUND, "Printer not found" },
7868 { PE_PINE_INTERNAL, "Pine internal error" },
7869 { PE_FONT_FAILED, "Failed to create font" },
7870 { 0, NULL }};
7875 * Send text in the line buffer to the printer.
7876 * Advance to next page if necessary.
7878 LOCAL int
7879 _print_send_line (void)
7881 int status;
7883 status = 0;
7884 if (P_CurCol > 0)
7885 TextOut (P_PrintDC, P_LeftOffset,
7886 P_TopOffset + (P_CurRow * P_RowHeight),
7887 P_LineText, P_CurCol);
7888 P_CurCol = 0;
7889 if (++P_CurRow >= P_PageRows)
7890 status = _print_send_page ();
7892 return (status);
7898 * Advance one page.
7901 _print_send_page (void)
7903 DWORD status;
7905 if((status = EndPage (P_PrintDC)) > 0){
7906 P_CurRow = 0;
7907 if((status = StartPage (P_PrintDC)) > 0){
7908 SelectObject (P_PrintDC, P_hFont);
7909 return(0);
7913 #ifdef WIN32
7914 ExplainSystemErr();
7915 return(PE_GENERAL_ERROR);
7916 #else
7917 switch (status) {
7918 case SP_USERABORT: return (PE_USER_CANCEL);
7919 case SP_OUTOFDISK: return (PE_OUT_OF_DISK);
7920 case SP_OUTOFMEMORY: return (PE_OUT_OF_MEMORY);
7921 default:
7922 case SP_ERROR: break;
7924 #endif
7925 return (PE_GENERAL_ERROR);
7931 * Map errors reported to my own error set.
7934 _print_map_dlg_error (DWORD error)
7936 switch (error) {
7937 case 0: return (PE_USER_CANCEL);
7938 case CDERR_MEMALLOCFAILURE:
7939 case CDERR_MEMLOCKFAILURE:
7940 return (PE_OUT_OF_MEMORY);
7941 case PDERR_PRINTERNOTFOUND:
7942 case PDERR_NODEVICES:
7943 return (PE_PRINTER_NOT_FOUND);
7944 case CDERR_STRUCTSIZE:
7945 return (PE_PINE_INTERNAL);
7946 default:
7947 return (PE_GENERAL_ERROR);
7953 * This is used for converting from UTF-8 to UCS and is
7954 * global so that mswin_print_ready can initialize it.
7956 static CBUF_S print_cb;
7959 * Get the printer ready. Returns ZERO for success, or an error code that
7960 * can be passed to mswin_print_error() to get a text message.
7963 mswin_print_ready(WINHAND hWnd, LPTSTR docDesc)
7965 PRINTDLG pd;
7966 DOCINFO di;
7967 TEXTMETRIC tm;
7968 HDC hDC;
7969 int fontSize; /* Size in Points. */
7970 int ppi; /* Pixels per inch in device. */
7971 int xChar;
7972 int status;
7973 HFONT oldFont;
7974 LOGFONT newFont;
7977 status = 0;
7978 P_PrintDC = NULL;
7980 print_cb.cbufp = print_cb.cbuf;
7983 * Show print dialog.
7985 memset(&pd, 0, sizeof(PRINTDLG));
7986 pd.lStructSize = sizeof (PRINTDLG);
7987 pd.hwndOwner = (hWnd ? (HWND) hWnd : ghTTYWnd);
7988 pd.hDevMode = NULL;
7989 pd.hDevNames = NULL;
7990 pd.Flags = PD_ALLPAGES | PD_NOSELECTION | PD_NOPAGENUMS |
7991 PD_HIDEPRINTTOFILE | PD_RETURNDC;
7992 pd.nCopies = 1;
7993 if(PrintDlg (&pd) == 0)
7994 return(_print_map_dlg_error (CommDlgExtendedError()));
7997 * Returns the device name which we could use to remember what printer
7998 * they selected. But instead, we just toss them.
8000 if (pd.hDevNames)
8001 GlobalFree (pd.hDevNames);
8002 if (pd.hDevMode)
8003 GlobalFree (pd.hDevMode);
8006 * Get the device drawing context.
8007 * (does PringDlg() ever return success but fail to return a DC?)
8009 if (pd.hDC != NULL)
8010 P_PrintDC = pd.hDC;
8011 else {
8012 status = PE_DIALOG_FAILED;
8013 goto Done;
8017 * Start Document
8019 memset(&di, 0, sizeof (DOCINFO));
8020 di.cbSize = sizeof (DOCINFO);
8021 di.lpszDocName = docDesc; /* This appears in the print manager*/
8022 di.lpszOutput = NULL; /* Could suply a file name to print
8023 to. */
8024 if(StartDoc(P_PrintDC, &di) <= 0) {
8025 ExplainSystemErr();
8026 status = PE_CANT_START_DOC;
8027 DeleteDC (P_PrintDC);
8028 P_PrintDC = NULL;
8029 goto Done;
8033 * Printer font is either same as window font, or is it's own
8034 * font.
8036 if (gPrintFontSameAs) {
8039 * Get the current font size in points, then create a new font
8040 * of same size for printer. Do the calculation using the actual
8041 * screen resolution instead of the logical resolution so that
8042 * we get pretty close to the same font size on the printer
8043 * as we see on the screen.
8045 hDC = GetDC (ghTTYWnd); /* Temp screen DC. */
8046 ppi = (int) ((float)GetDeviceCaps (hDC, VERTRES) /
8047 ((float) GetDeviceCaps (hDC, VERTSIZE) / 25.3636));
8048 #ifdef FDEBUG
8049 if (mswin_debug >= 8) {
8050 fprintf (mswin_debugfile, "mswin_print_ready: Screen res %d ppi, font height %d pixels\n",
8051 ppi, -gpTTYInfo->lfTTYFont.lfHeight);
8052 fprintf (mswin_debugfile, " Screen height %d pixel, %d mm\n",
8053 GetDeviceCaps (hDC, VERTRES), GetDeviceCaps (hDC, VERTSIZE));
8055 #endif
8056 ReleaseDC (ghTTYWnd, hDC);
8058 /* Convert from screen pixels to points. */
8059 fontSize = MulDiv (-gpTTYInfo->lfTTYFont.lfHeight, 72, ppi);
8060 ++fontSize; /* Fudge a little. */
8063 /* Get printer resolution and convert form points to printer pixels. */
8064 ppi = GetDeviceCaps (P_PrintDC, LOGPIXELSY);
8065 newFont.lfHeight = -MulDiv (fontSize, ppi, 72);
8066 _tcsncpy(newFont.lfFaceName, gpTTYInfo->lfTTYFont.lfFaceName, LF_FACESIZE);
8067 newFont.lfFaceName[LF_FACESIZE-1] = 0;
8068 newFont.lfItalic = gpTTYInfo->lfTTYFont.lfItalic;
8069 newFont.lfWeight = gpTTYInfo->lfTTYFont.lfWeight;
8070 newFont.lfCharSet = gpTTYInfo->lfTTYFont.lfCharSet;
8073 #ifdef FDEBUG
8074 if (mswin_debug >= 8) {
8075 fprintf (mswin_debugfile, " font Size %d points\n",
8076 fontSize);
8077 fprintf (mswin_debugfile, " printer res %d ppi, font height %d pixels\n",
8078 ppi, -newFont.lfHeight);
8079 fprintf (mswin_debugfile, " paper height %d pixel, %d mm\n",
8080 GetDeviceCaps (P_PrintDC, VERTRES),
8081 GetDeviceCaps (P_PrintDC, VERTSIZE));
8083 #endif
8085 else {
8086 ppi = GetDeviceCaps (P_PrintDC, LOGPIXELSY);
8087 newFont.lfHeight = -MulDiv (gPrintFontSize, ppi, 72);
8088 _tcsncpy(newFont.lfFaceName, gPrintFontName, LF_FACESIZE);
8089 newFont.lfFaceName[LF_FACESIZE-1] = 0;
8090 newFont.lfWeight = 0;
8091 if(_tcsstr(gPrintFontStyle, TEXT("bold")))
8092 newFont.lfWeight = FW_BOLD;
8094 newFont.lfItalic = 0;
8095 if(_tcsstr(gPrintFontStyle, TEXT("italic")))
8096 newFont.lfItalic = 1;
8098 newFont.lfCharSet = mswin_string2charsetid(gPrintFontCharSet);
8102 /* Fill out rest of font description and request font. */
8103 newFont.lfWidth = 0;
8104 newFont.lfEscapement = 0;
8105 newFont.lfOrientation = 0;
8106 newFont.lfUnderline = 0;
8107 newFont.lfStrikeOut = 0;
8108 newFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
8109 newFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
8110 newFont.lfQuality = DEFAULT_QUALITY;
8111 newFont.lfPitchAndFamily = FIXED_PITCH;
8112 P_hFont = CreateFontIndirect (&newFont);
8113 if (P_hFont == NULL) {
8114 status = PE_FONT_FAILED;
8115 DeleteDC (P_PrintDC);
8116 goto Done;
8121 * Start page.
8122 * Must select font for each page or it returns to default.
8123 * Windows seems good about maping selected font to a font that
8124 * will actually print on the printer.
8126 StartPage (P_PrintDC);
8127 oldFont = SelectObject (P_PrintDC, P_hFont);
8131 * Find out about the font we got and set up page size and margins.
8132 * This assumes all pages are the same size - which seems reasonable.
8134 GetTextMetrics (P_PrintDC, &tm);
8135 xChar = tm.tmAveCharWidth;
8136 P_RowHeight = tm.tmHeight + tm.tmExternalLeading;
8138 /* HORZRES and VERTRES report size of page in printer pixels. */
8139 P_PageColumns = GetDeviceCaps (P_PrintDC, HORZRES) / xChar;
8140 P_PageRows = GetDeviceCaps (P_PrintDC, VERTRES) / P_RowHeight;
8142 /* We allow a margin at top and bottom measured in text rows. */
8143 P_PageRows -= VERTICLE_MARGIN * 2;
8144 P_TopOffset = VERTICLE_MARGIN * P_RowHeight;
8146 /* And allow for a left and right margine measured in characters. */
8147 P_PageColumns -= HORIZONTAL_MARGIN * 2;
8148 P_LeftOffset = HORIZONTAL_MARGIN * xChar;
8150 P_CurRow = 0; /* Start counting at row 0. */
8151 P_CurCol = 0; /* At character 0. */
8152 P_LineText = (LPTSTR) MemAlloc((P_PageColumns + 1) * sizeof(TCHAR));
8153 if(P_LineText == NULL){
8154 if(EndDoc (P_PrintDC) <= 0)
8155 ExplainSystemErr();
8157 DeleteObject (P_hFont);
8158 P_hFont = NULL;
8159 DeleteDC (P_PrintDC);
8160 P_PrintDC = NULL;
8161 status = PE_OUT_OF_MEMORY;
8162 goto Done;
8166 Done:
8167 return (status);
8172 * Called when printing is done.
8173 * xxx what happens if there is an error? Will this get called?
8176 mswin_print_done(void)
8178 if(P_PrintDC != NULL){
8179 if(P_LineText != NULL)
8180 MemFree((void *) P_LineText);
8182 if(EndPage (P_PrintDC) <= 0 || EndDoc (P_PrintDC) <= 0)
8183 ExplainSystemErr();
8185 DeleteObject(P_hFont);
8186 P_hFont = NULL;
8187 DeleteDC(P_PrintDC);
8188 P_PrintDC = NULL;
8191 return (0);
8196 * Return ponter to a text string that describes the erorr.
8198 char *
8199 mswin_print_error(int error_code)
8201 int i;
8203 for(i = 0; P_ErrorMessages[i].error_message != NULL; ++i)
8204 if(P_ErrorMessages[i].error_code == error_code)
8205 return(P_ErrorMessages[i].error_message);
8207 return("(Unknown error)");
8212 * Add a single character to the current line.
8213 * Only handles CRLF carrage control.
8216 mswin_print_char(TCHAR c)
8218 switch(c){
8219 case ASCII_CR:
8220 return(0);
8222 case ASCII_LF:
8223 return(_print_send_line());
8225 case ASCII_TAB:
8227 if(P_CurCol == P_PageColumns)
8228 return(_print_send_line());
8230 *(P_LineText + P_CurCol++) = ' ';
8232 while(P_CurCol % PRINT_TAB_SIZE != 0);
8233 return(0);
8235 default:
8236 if(P_CurCol == P_PageColumns){
8237 int status;
8239 if((status = _print_send_line()) != 0)
8240 return(status);
8243 *(P_LineText + P_CurCol++) = c;
8244 return(0);
8250 mswin_print_char_utf8(int c)
8252 UCS ucs;
8253 TCHAR tc;
8254 int ret = 0;
8256 if(utf8_to_ucs4_oneatatime(c, &print_cb, &ucs, NULL)){
8257 /* bogus conversion ignores UTF-16 */
8258 tc = (TCHAR) ucs;
8259 ret = mswin_print_char(tc);
8262 return(ret);
8267 * Send a string to the printer.
8270 mswin_print_text(LPTSTR text)
8272 int status;
8274 if(text)
8275 while(*text)
8276 if((status = mswin_print_char(*(text++))) != 0)
8277 return(status);
8279 return(0);
8284 mswin_print_text_utf8(char *text_utf8)
8286 LPTSTR text_lpt;
8287 int ret = 0;
8289 if(text_utf8){
8290 text_lpt = utf8_to_lptstr(text_utf8);
8291 if(text_lpt){
8292 ret = mswin_print_text(text_lpt);
8293 fs_give((void **) &text_lpt);
8297 return(ret);
8301 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8303 * File dialog boxes.
8305 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
8307 LOCAL TCHAR gHomeDir[PATH_MAX];
8308 LOCAL TCHAR gLastDir[PATH_MAX];
8311 * Keep track of the last dir visited. Most of the time pine just passes us
8312 * the "home directory", which usually is not where the user wants to start.
8313 * Assume that the first time we are called we are being passed the home
8314 * direcory.
8316 static void
8317 FillInitialDir (LPCTSTR *iDir, LPTSTR targDir)
8319 if (_tcslen (gHomeDir) == 0) {
8320 _tcscpy (gHomeDir, targDir);
8321 *iDir = targDir;
8323 else if (_tcscmp (gHomeDir, targDir) == 0 && *gLastDir)
8324 *iDir = gLastDir;
8325 else
8326 *iDir = targDir;
8332 * Display a save file dialog box.
8334 * dir_utf8 > directory to start search in
8335 * < directory finished in.
8336 * fName_utf8 < Name of file selected
8337 * nMaxDName length of dir_utf8
8338 * nMaxFName length of fName_utf8.
8340 * Possible return values:
8341 * 0 no file selected
8342 * 1 file selected
8343 * -1 some sort of error
8346 mswin_savefile(char *dir_utf8, int nMaxDName, char *fName_utf8, int nMaxFName)
8348 OPENFILENAME ofn;
8349 TCHAR filters[128], moniker[128];
8350 DWORD rc, len;
8351 LPTSTR p, extlist_lpt;
8352 LPTSTR fName_lpt, f, dir_lpt;
8353 char *cp;
8355 /* convert fName_utf8 to LPTSTR */
8356 fName_lpt = (LPTSTR) fs_get(nMaxFName * sizeof(TCHAR));
8357 fName_lpt[0] = '\0';
8358 if(fName_utf8 && fName_utf8[0]){
8359 f = utf8_to_lptstr(fName_utf8);
8360 if(f){
8361 _tcsncpy(fName_lpt, f, nMaxFName);
8362 fName_lpt[nMaxFName-1] = '\0';
8363 fs_give((void **) &f);
8367 dir_lpt = (LPTSTR) fs_get(nMaxDName * sizeof(TCHAR));
8368 dir_lpt[0] = '\0';
8369 if(dir_utf8 && dir_utf8[0]){
8370 f = utf8_to_lptstr(dir_utf8);
8371 if(f){
8372 _tcsncpy(dir_lpt, f, nMaxDName);
8373 dir_lpt[nMaxDName-1] = '\0';
8374 fs_give((void **) &f);
8378 for(extlist_lpt = NULL, p = _tcschr(fName_lpt, '.'); p; p = _tcschr(++p, '.'))
8379 extlist_lpt = p;
8381 len = sizeof(moniker)/sizeof(TCHAR);
8382 if(extlist_lpt && MSWRPeek(HKEY_CLASSES_ROOT, extlist_lpt, NULL, moniker, &len) == TRUE){
8383 len = sizeof(filters)/sizeof(TCHAR);
8384 filters[0] = '\0';
8385 if(MSWRPeek(HKEY_CLASSES_ROOT, moniker, NULL, filters, &len) == TRUE)
8386 _sntprintf(filters + _tcslen(filters),
8387 sizeof(filters)/sizeof(TCHAR) - _tcslen(filters),
8388 TEXT(" (*%s)#*%s#"), extlist_lpt, extlist_lpt);
8389 else
8390 _sntprintf(filters, sizeof(filters)/sizeof(TCHAR),
8391 TEXT("%s (*%s)#*%s#"), moniker, extlist_lpt, extlist_lpt);
8393 else
8394 filters[0] = '\0';
8396 _tcsncat(filters, TEXT("Text Files (*.txt)#*.txt#All Files (*.*)#*.*#"),
8397 sizeof(filters)/sizeof(TCHAR));
8398 filters[sizeof(filters)/sizeof(TCHAR) - 1] = '\0';
8400 for(p = filters; *p != '\0'; ++p)
8401 if(*p == L'#')
8402 *p = '\0';
8404 /* Set up the BIG STRUCTURE. */
8405 memset (&ofn, 0, sizeof(ofn));
8407 * sizeof(OPENFILENAME) used to work but doesn't work now with
8408 * pre-Windows 2000. This is supposed to be the magic constant to
8409 * make it work in both cases, according to MSDN.
8411 ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
8412 ofn.hwndOwner = ghTTYWnd;
8413 ofn.lpstrFilter = filters;
8414 ofn.lpstrCustomFilter = NULL;
8415 ofn.nFilterIndex = 1;
8416 ofn.lpstrFile = fName_lpt;
8417 ofn.nMaxFile = nMaxFName;
8418 ofn.lpstrFileTitle = NULL;
8419 ofn.nMaxFileTitle = 0;
8420 FillInitialDir (&ofn.lpstrInitialDir, dir_lpt);
8421 ofn.lpstrTitle = TEXT("Save To File");
8422 ofn.Flags = OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
8423 ofn.lpstrDefExt = TEXT("txt");
8425 if(GetSaveFileName(&ofn)){
8426 if(ofn.nFileOffset > nMaxDName-1){
8427 if(fName_lpt)
8428 fs_give((void **) &fName_lpt);
8430 if(dir_lpt)
8431 fs_give((void **) &dir_lpt);
8433 return(0);
8436 /* Copy directory name to dir_lpt. */
8437 _tcsncpy(dir_lpt, fName_lpt, nMaxDName-1);
8438 dir_lpt[nMaxDName-1] = '\0';
8439 if(dir_lpt[ofn.nFileOffset-1] == '\\'
8440 && !(ofn.nFileOffset == 3 && _istalpha(dir_lpt[0]) && dir_lpt[1] == ':'))
8441 dir_lpt[ofn.nFileOffset-1] = '\0';
8442 else
8443 dir_lpt[ofn.nFileOffset] = '\0';
8445 /* Remember last dir visited. */
8446 _tcsncpy(gLastDir, dir_lpt, PATH_MAX);
8447 gLastDir[PATH_MAX-1] = '\0';
8449 /* convert back to UTF-8 */
8450 cp = lptstr_to_utf8(dir_lpt);
8451 if(cp){
8452 strncpy(dir_utf8, cp, nMaxDName-1);
8453 dir_utf8[nMaxDName-1] = '\0';
8454 fs_give((void **) &cp);
8457 p = fName_lpt + ofn.nFileOffset;
8459 /* convert fName back to UTF-8 */
8460 cp = lptstr_to_utf8(p);
8461 if(cp){
8462 strncpy(fName_utf8, cp, nMaxFName-1);
8463 fName_utf8[nMaxFName-1] = '\0';
8464 fs_give((void **) &cp);
8467 if(fName_lpt)
8468 fs_give((void **) &fName_lpt);
8470 if(dir_lpt)
8471 fs_give((void **) &dir_lpt);
8473 return(1);
8475 else{
8476 if(fName_lpt)
8477 fs_give((void **) &fName_lpt);
8479 if(dir_lpt)
8480 fs_give((void **) &dir_lpt);
8482 rc = CommDlgExtendedError();
8483 return(rc ? -1 : 0);
8491 * Display an open file dialog box.
8493 * dir_utf8 > directory to start search in
8494 * < directory finished in.
8495 * fName_utf8 < Name of file selected
8496 * nMaxDName length of dir_utf8
8497 * nMaxFName length of fName_utf8.
8499 * Possible return values:
8500 * 0 no file selected
8501 * 1 file selected
8502 * -1 some sort of error +++++++++++++
8505 mswin_openfile(char *dir_utf8, int nMaxDName, char *fName_utf8,
8506 int nMaxFName, char *extlist_utf8)
8508 OPENFILENAME ofn;
8509 TCHAR filters[1024];
8510 DWORD rc;
8511 LPTSTR p;
8512 LPTSTR extlist_lpt = NULL;
8513 LPTSTR fName_lpt, f, dir_lpt;
8514 char *cp;
8517 if(extlist_utf8)
8518 extlist_lpt = utf8_to_lptstr(extlist_utf8);
8521 * Set filters array. (pairs of null terminated strings, terminated
8522 * by a double null).
8524 _sntprintf(filters, sizeof(filters)/sizeof(TCHAR),
8525 TEXT("%s%sAll Files (*.*)#*.*#"),
8526 extlist_lpt ? extlist_lpt : TEXT(""), extlist_lpt ? TEXT("#") : TEXT(""));
8528 if(extlist_lpt)
8529 fs_give((void **) &extlist_lpt);
8531 for(p = filters; *p != '\0'; ++p)
8532 if(*p == L'#')
8533 *p = '\0';
8535 /* Set up the BIG STRUCTURE. */
8536 memset(&ofn, 0, sizeof(ofn));
8538 /* convert fName_utf8 to LPTSTR */
8539 fName_lpt = (LPTSTR) fs_get(nMaxFName * sizeof(TCHAR));
8540 fName_lpt[0] = '\0';
8541 if(fName_utf8 && fName_utf8[0]){
8542 f = utf8_to_lptstr(fName_utf8);
8543 if(f){
8544 _tcsncpy(fName_lpt, f, nMaxFName);
8545 fName_lpt[nMaxFName-1] = '\0';
8546 fs_give((void **) &f);
8550 dir_lpt = (LPTSTR) fs_get(nMaxDName * sizeof(TCHAR));
8551 dir_lpt[0] = '\0';
8552 if(dir_utf8 && dir_utf8[0]){
8553 f = utf8_to_lptstr(dir_utf8);
8554 if(f){
8555 _tcsncpy(dir_lpt, f, nMaxDName);
8556 dir_lpt[nMaxDName-1] = '\0';
8557 fs_give((void **) &f);
8562 * sizeof(OPENFILENAME) used to work but doesn't work now with
8563 * pre-Windows 2000. This is supposed to be the magic constant to
8564 * make it work in both cases, according to MSDN.
8566 ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
8567 ofn.hwndOwner = ghTTYWnd;
8568 ofn.lpstrFilter = filters;
8569 ofn.lpstrCustomFilter = NULL;
8570 ofn.nFilterIndex = 1;
8571 ofn.lpstrFile = fName_lpt;
8572 ofn.nMaxFile = nMaxFName;
8573 ofn.lpstrFileTitle = NULL;
8574 ofn.nMaxFileTitle = 0;
8575 FillInitialDir(&ofn.lpstrInitialDir, dir_lpt);
8576 ofn.lpstrTitle = TEXT("Select File");
8577 ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
8578 ofn.lpstrDefExt = TEXT("txt");
8580 if(GetOpenFileName(&ofn)){
8581 if(ofn.nFileOffset > nMaxDName-1){
8582 if(fName_lpt)
8583 fs_give((void **) &fName_lpt);
8585 if(dir_lpt)
8586 fs_give((void **) &dir_lpt);
8588 return(0);
8591 /* Copy directory name to dir_lpt. */
8592 _tcsncpy(dir_lpt, fName_lpt, nMaxDName-1);
8593 dir_lpt[nMaxDName-1] = '\0';
8594 if(dir_lpt[ofn.nFileOffset-1] == '\\'
8595 && !(ofn.nFileOffset == 3 && _istalpha(dir_lpt[0]) && dir_lpt[1] == ':'))
8596 dir_lpt[ofn.nFileOffset-1] = '\0';
8597 else
8598 dir_lpt[ofn.nFileOffset] = '\0';
8600 /* Remember last dir visited. */
8601 _tcsncpy(gLastDir, dir_lpt, PATH_MAX);
8602 gLastDir[PATH_MAX-1] = '\0';
8604 /* convert back to UTF-8 */
8605 cp = lptstr_to_utf8(dir_lpt);
8606 if(cp){
8607 strncpy(dir_utf8, cp, nMaxDName-1);
8608 dir_utf8[nMaxDName-1] = '\0';
8609 fs_give((void **) &cp);
8612 p = fName_lpt + ofn.nFileOffset;
8614 /* convert fName back to UTF-8 */
8615 cp = lptstr_to_utf8(p);
8616 if(cp){
8617 strncpy(fName_utf8, cp, nMaxFName-1);
8618 fName_utf8[nMaxFName-1] = '\0';
8619 fs_give((void **) &cp);
8622 if(fName_lpt)
8623 fs_give((void **) &fName_lpt);
8625 if(dir_lpt)
8626 fs_give((void **) &dir_lpt);
8628 return(1);
8630 else{
8631 if(fName_lpt)
8632 fs_give((void **) &fName_lpt);
8634 if(dir_lpt)
8635 fs_give((void **) &dir_lpt);
8637 rc = CommDlgExtendedError();
8638 return(rc ? -1 : 0);
8644 * Display an open file dialog box.
8645 * Allow selection of multiple files.
8647 * dir_utf8 > directory to start search in
8648 * < directory finished in.
8649 * fName_utf8 < Names of files selected
8650 * nMaxDName length of dir_utf8
8651 * nMaxFName length of fName_utf8.
8653 * Possible return values:
8654 * 0 no file selected
8655 * 1 file selected
8656 * -1 some sort of error
8659 mswin_multopenfile(char *dir_utf8, int nMaxDName, char *fName_utf8,
8660 int nMaxFName, char *extlist_utf8)
8662 OPENFILENAME ofn;
8663 TCHAR filters[1024];
8664 DWORD rc;
8665 LPTSTR p;
8666 LPTSTR extlist_lpt = NULL;
8667 LPTSTR fName_lpt, f, dir_lpt;
8668 char *cp, *q;
8671 if(extlist_utf8)
8672 extlist_lpt = utf8_to_lptstr(extlist_utf8);
8675 * Set filters array. (pairs of null terminated strings, terminated
8676 * by a double null).
8678 _sntprintf(filters, sizeof(filters)/sizeof(TCHAR),
8679 TEXT("%s%sAll Files (*.*)#*.*#"),
8680 extlist_lpt ? extlist_lpt : TEXT(""), extlist_lpt ? TEXT("#") : TEXT(""));
8682 if(extlist_lpt)
8683 fs_give((void **) &extlist_lpt);
8685 for(p = filters; *p != '\0'; ++p)
8686 if(*p == L'#')
8687 *p = '\0';
8689 /* Set up the BIG STRUCTURE. */
8690 memset (&ofn, 0, sizeof(ofn));
8692 /* convert fName_utf8 to LPTSTR */
8693 fName_lpt = (LPTSTR) fs_get(nMaxFName * sizeof(TCHAR));
8694 memset(fName_lpt, 0, nMaxFName * sizeof(TCHAR));
8695 if(fName_utf8 && fName_utf8[0]){
8696 f = utf8_to_lptstr(fName_utf8);
8697 if(f){
8698 _tcsncpy(fName_lpt, f, nMaxFName);
8699 fName_lpt[nMaxFName-1] = '\0';
8700 fs_give((void **) &f);
8704 dir_lpt = (LPTSTR) fs_get(nMaxDName * sizeof(TCHAR));
8705 memset(dir_lpt, 0, nMaxDName * sizeof(TCHAR));
8706 if(dir_utf8 && dir_utf8[0]){
8707 f = utf8_to_lptstr(dir_utf8);
8708 if(f){
8709 _tcsncpy(dir_lpt, f, nMaxDName);
8710 dir_lpt[nMaxDName-1] = '\0';
8711 fs_give((void **) &f);
8716 * sizeof(OPENFILENAME) used to work but doesn't work now with
8717 * pre-Windows 2000. This is supposed to be the magic constant to
8718 * make it work in both cases, according to MSDN.
8720 ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
8721 ofn.hwndOwner = ghTTYWnd;
8722 ofn.lpstrFilter = filters;
8723 ofn.lpstrCustomFilter = NULL;
8724 ofn.nFilterIndex = 1;
8725 ofn.lpstrFile = fName_lpt;
8726 ofn.nMaxFile = nMaxFName;
8727 ofn.lpstrFileTitle = NULL;
8728 ofn.nMaxFileTitle = 0;
8729 FillInitialDir(&ofn.lpstrInitialDir, dir_lpt);
8730 ofn.lpstrTitle = TEXT("Select Files");
8731 ofn.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER |
8732 OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
8733 ofn.lpstrDefExt = TEXT("txt");
8735 if(GetOpenFileName(&ofn)){
8736 if(ofn.nFileOffset > nMaxDName-1){
8737 if(fName_lpt)
8738 fs_give((void **) &fName_lpt);
8740 if(dir_lpt)
8741 fs_give((void **) &dir_lpt);
8743 return(0);
8746 /* Copy directory name to dir_lpt. */
8747 _tcsncpy(dir_lpt, fName_lpt, nMaxDName-1);
8748 dir_lpt[nMaxDName-1] = '\0';
8749 if(dir_lpt[ofn.nFileOffset-1] == '\\'
8750 && !(ofn.nFileOffset == 3 && _istalpha(dir_lpt[0]) && dir_lpt[1] == ':'))
8751 dir_lpt[ofn.nFileOffset-1] = '\0';
8752 else
8753 dir_lpt[ofn.nFileOffset] = '\0';
8755 /* Remember last dir visited. */
8756 _tcsncpy(gLastDir, dir_lpt, PATH_MAX);
8757 gLastDir[PATH_MAX-1] = '\0';
8759 /* convert back to UTF-8 */
8760 cp = lptstr_to_utf8(dir_lpt);
8761 if(cp){
8762 strncpy(dir_utf8, cp, nMaxDName-1);
8763 dir_utf8[nMaxDName-1] = '\0';
8764 fs_give((void **) &cp);
8768 * The file names are all in the same directory and are separated
8769 * by '\0' characters and terminated by double '\0'.
8770 * This fact depends on the OFN_EXPLORER bit being set in the flags
8771 * above.
8773 * This is complicated because we need to convert all of these file
8774 * names to UTF-8.
8776 for(q=fName_utf8, p=fName_lpt + ofn.nFileOffset; *p; p += _tcslen(p)+1){
8777 cp = lptstr_to_utf8(p);
8778 if(cp){
8779 sstrncpy(&q, cp, (int)(nMaxFName-(q-fName_utf8)));
8780 if(q-fName_utf8 < nMaxFName){
8781 *q++ = '\0';
8782 if(q-fName_utf8 < nMaxFName)
8783 *q = '\0'; /* the double null if this is the end */
8785 else
8786 fName_utf8[nMaxFName-1] = '\0';
8788 fs_give((void **) &cp);
8792 fName_utf8[nMaxFName-1] = fName_utf8[nMaxFName-2] = '\0';
8794 if(fName_lpt)
8795 fs_give((void **) &fName_lpt);
8797 if(dir_lpt)
8798 fs_give((void **) &dir_lpt);
8800 return (1);
8802 else{
8803 if(fName_lpt)
8804 fs_give((void **) &fName_lpt);
8806 if(dir_lpt)
8807 fs_give((void **) &dir_lpt);
8809 rc = CommDlgExtendedError();
8810 return(rc ? -1 : 0);
8815 /*---------------------------------------------------------------------------
8819 * pico_XXcolor() - each function sets a particular attribute
8821 void
8822 pico_nfcolor(char *s)
8824 char cbuf[MAXCLEN];
8826 if(s){
8827 SetColorAttribute (&gpTTYInfo->rgbFGColor, s);
8828 pico_set_nfg_color();
8830 if(the_normal_color){
8831 strncpy(the_normal_color->fg,
8832 ConvertStringRGB(cbuf, sizeof(cbuf), gpTTYInfo->rgbFGColor),
8833 MAXCOLORLEN+1);
8834 the_normal_color->fg[MAXCOLORLEN] = '\0';
8837 else{
8838 gpTTYInfo->rgbFGColor = GetSysColor (COLOR_WINDOWTEXT);
8839 if(the_normal_color)
8840 free_color_pair(&the_normal_color);
8843 // Update all textwindows with the new FG color.
8844 mswin_tw_setcolor((MSWIN_TEXTWINDOW *)-1,
8845 gpTTYInfo->rgbFGColor, gpTTYInfo->rgbBGColor);
8849 void
8850 pico_nbcolor(char *s)
8852 char cbuf[MAXCLEN];
8854 if(s){
8855 SetColorAttribute (&gpTTYInfo->rgbBGColor, s);
8856 pico_set_nbg_color();
8858 if(the_normal_color){
8859 strncpy(the_normal_color->bg,
8860 ConvertStringRGB(cbuf, sizeof(cbuf), gpTTYInfo->rgbBGColor),
8861 MAXCOLORLEN+1);
8862 the_normal_color->fg[MAXCOLORLEN] = '\0';
8865 else{
8866 gpTTYInfo->rgbBGColor = GetSysColor (COLOR_WINDOW);
8867 if(the_normal_color)
8868 free_color_pair(&the_normal_color);
8871 // Update all textwindows with the new BG color.
8872 mswin_tw_setcolor((MSWIN_TEXTWINDOW *)-1,
8873 gpTTYInfo->rgbFGColor, gpTTYInfo->rgbBGColor);
8877 void
8878 pico_rfcolor(char *s)
8880 char cbuf[MAXCLEN];
8882 if(s){
8883 SetColorAttribute (&gpTTYInfo->rgbRFGColor, s);
8885 if(the_rev_color){
8886 strncpy(the_rev_color->fg,
8887 ConvertStringRGB(cbuf, sizeof(cbuf), gpTTYInfo->rgbRFGColor),
8888 MAXCOLORLEN+1);
8889 the_rev_color->fg[MAXCOLORLEN] = '\0';
8892 else{
8893 gpTTYInfo->rgbRFGColor = GetSysColor (COLOR_HIGHLIGHTTEXT);
8894 if(the_rev_color)
8895 free_color_pair(&the_rev_color);
8900 void
8901 pico_rbcolor(char *s)
8903 char cbuf[MAXCLEN];
8905 if(s){
8906 SetColorAttribute (&gpTTYInfo->rgbRBGColor, s);
8908 if(the_rev_color){
8909 strncpy(the_rev_color->bg,
8910 ConvertStringRGB(cbuf, sizeof(cbuf), gpTTYInfo->rgbRBGColor),
8911 MAXCOLORLEN+1);
8912 the_rev_color->bg[MAXCOLORLEN] = '\0';
8915 else{
8916 gpTTYInfo->rgbRBGColor = GetSysColor (COLOR_HIGHLIGHT);
8917 if(the_rev_color)
8918 free_color_pair(&the_rev_color);
8924 pico_usingcolor()
8926 return(TRUE);
8931 pico_count_in_color_table()
8933 return(visibleColorTableSize);
8938 * Return a pointer to an rgb string for the input color. The output is 11
8939 * characters long and looks like rrr,ggg,bbb.
8941 * Args colorName -- The color to convert to ascii rgb.
8943 * Returns Pointer to a static buffer containing the rgb string.
8945 char *
8946 color_to_asciirgb(char *colorName)
8948 static char c_to_a_buf[3][RGBLEN+1];
8949 static int whichbuf = 0;
8950 COLORREF cf;
8951 int l;
8953 whichbuf = (whichbuf + 1) % 3;
8955 if(ConvertRGBString(colorName, &cf)){
8956 snprintf(c_to_a_buf[whichbuf], sizeof(c_to_a_buf[0]), "%.3d,%.3d,%.3d",
8957 GetRValue(cf), GetGValue(cf), GetBValue(cf));
8959 else{
8961 * If we didn't find the color it could be that it is the
8962 * normal color (MATCH_NORM_COLOR) or the none color
8963 * (MATCH_NONE_COLOR). If that is the case, this strncpy thing
8964 * will work out correctly because those two strings are
8965 * RGBLEN long. Otherwise we're in a bit of trouble. This
8966 * most likely means that the user is using the same pinerc on
8967 * two terminals, one with more colors than the other. We didn't
8968 * find a match because this color isn't present on this terminal.
8969 * Since the return value of this function is assumed to be
8970 * RGBLEN long, we'd better make it that long.
8971 * It still won't work correctly because colors will be screwed up,
8972 * but at least the embedded colors in filter.c will get properly
8973 * sucked up when they're encountered.
8975 strncpy(c_to_a_buf[whichbuf], "xxxxxxxxxxx", RGBLEN);
8976 l = (int)strlen(colorName);
8977 strncpy(c_to_a_buf[whichbuf], colorName, (l < RGBLEN) ? l : RGBLEN);
8978 c_to_a_buf[whichbuf][RGBLEN] = '\0';
8981 return(c_to_a_buf[whichbuf]);
8985 void
8986 pico_set_nfg_color()
8988 FlushWriteAccum ();
8989 gpTTYInfo->curAttrib.rgbFG = gpTTYInfo->rgbFGColor;
8992 void
8993 pico_set_nbg_color()
8995 FlushWriteAccum ();
8996 gpTTYInfo->curAttrib.rgbBG = gpTTYInfo->rgbBGColor;
8999 void
9000 pico_set_normal_color()
9002 pico_set_nfg_color();
9003 pico_set_nbg_color();
9006 COLOR_PAIR *
9007 pico_get_rev_color()
9009 char fgbuf[MAXCLEN], bgbuf[MAXCLEN];
9011 if(!the_rev_color)
9012 the_rev_color =
9013 new_color_pair(ConvertStringRGB(fgbuf,sizeof(fgbuf),gpTTYInfo->rgbRFGColor),
9014 ConvertStringRGB(bgbuf,sizeof(bgbuf),gpTTYInfo->rgbRBGColor));
9015 return(the_rev_color);
9018 COLOR_PAIR *
9019 pico_get_normal_color()
9021 char fgbuf[MAXCLEN], bgbuf[MAXCLEN];
9023 if(!the_normal_color)
9024 the_normal_color =
9025 new_color_pair(ConvertStringRGB(fgbuf,sizeof(fgbuf),gpTTYInfo->rgbFGColor),
9026 ConvertStringRGB(bgbuf,sizeof(bgbuf),gpTTYInfo->rgbBGColor));
9027 return(the_normal_color);
9031 * Sets color to (fg,bg).
9032 * Flags == PSC_NONE No alternate default if fg,bg fails.
9033 * == PSC_NORM Set it to Normal color on failure.
9034 * == PSC_REV Set it to Reverse color on failure.
9036 * If flag PSC_RET is set, returns an allocated copy of the previous
9037 * color pair, otherwise returns NULL.
9039 COLOR_PAIR *
9040 pico_set_colors(char *fg, char *bg, int flags)
9042 COLOR_PAIR *cp = NULL;
9044 if(flags & PSC_RET)
9045 cp = pico_get_cur_color();
9047 if(!(fg && bg && pico_set_fg_color(fg) && pico_set_bg_color(bg))){
9049 if(flags & PSC_NORM)
9050 pico_set_normal_color();
9051 else if(flags & PSC_REV)
9052 SetReverseColor();
9055 return(cp);
9060 pico_is_good_color(char *colorName)
9062 COLORREF cf;
9064 if(!struncmp(colorName, MATCH_NORM_COLOR, RGBLEN)
9065 || !struncmp(colorName, MATCH_NONE_COLOR, RGBLEN))
9066 return(TRUE);
9068 return(ConvertRGBString(colorName, &cf));
9073 pico_set_fg_color(char *colorName)
9075 char fgbuf[MAXCLEN];
9077 FlushWriteAccum ();
9079 if(!struncmp(colorName, MATCH_NORM_COLOR, RGBLEN)){
9080 ConvertStringRGB(fgbuf,sizeof(fgbuf),gpTTYInfo->rgbFGColor);
9081 colorName = fgbuf;
9083 else if(!struncmp(colorName, MATCH_NONE_COLOR, RGBLEN))
9084 return(TRUE);
9086 return(ConvertRGBString(colorName, &gpTTYInfo->curAttrib.rgbFG));
9091 pico_set_bg_color(char *colorName)
9093 char bgbuf[MAXCLEN];
9095 FlushWriteAccum ();
9097 if(!struncmp(colorName, MATCH_NORM_COLOR, RGBLEN)){
9098 ConvertStringRGB(bgbuf,sizeof(bgbuf),gpTTYInfo->rgbBGColor);
9099 colorName = bgbuf;
9101 else if(!struncmp(colorName, MATCH_NONE_COLOR, RGBLEN))
9102 return(TRUE);
9104 return(ConvertRGBString(colorName, &gpTTYInfo->curAttrib.rgbBG));
9108 char *
9109 pico_get_last_fg_color()
9111 return(NULL);
9115 char *
9116 pico_get_last_bg_color()
9118 return(NULL);
9122 unsigned
9123 pico_get_color_options()
9125 return((unsigned)0);
9129 void
9130 pico_set_color_options(unsigned int opts)
9135 COLOR_PAIR *
9136 pico_get_cur_color()
9138 char fgbuf[MAXCLEN], bgbuf[MAXCLEN];
9140 return(new_color_pair(ConvertStringRGB(fgbuf,sizeof(fgbuf),gpTTYInfo->curAttrib.rgbFG),
9141 ConvertStringRGB(bgbuf,sizeof(bgbuf),gpTTYInfo->curAttrib.rgbBG)));
9145 char *
9146 mswin_rgbchoice(char *pOldRGB)
9148 CHOOSECOLOR cc;
9149 static COLORREF custColors[16] = {
9150 RGB(0,0,0),
9151 RGB(0,0,255),
9152 RGB(0,255,0),
9153 RGB(0,255,255),
9154 RGB(255,0,0),
9155 RGB(255,0,255),
9156 RGB(255,255,0),
9157 RGB(255,255,255),
9158 RGB(192,192,192),
9159 RGB(128,128,128),
9160 RGB(64,64,64)
9163 memset(&cc, 0, sizeof(CHOOSECOLOR));
9165 cc.lStructSize = sizeof(CHOOSECOLOR);
9166 cc.hwndOwner = ghTTYWnd;
9167 cc.Flags = CC_ANYCOLOR;
9168 cc.lpCustColors = &custColors[0];
9170 if(pOldRGB){
9171 int i;
9173 ConvertRGBString (pOldRGB, &cc.rgbResult);
9174 cc.Flags |= CC_RGBINIT;
9176 for(i = 0; i < 11 && custColors[i] != cc.rgbResult; i++)
9179 if(i == 11){
9180 custColors[i] = cc.rgbResult;
9181 cc.Flags |= CC_FULLOPEN;
9186 if(ChooseColor(&cc)){
9187 char rgbbuf[MAXCLEN], *p;
9189 ConvertStringRGB(rgbbuf, sizeof(rgbbuf), cc.rgbResult);
9190 if(p = MemAlloc(MAXCLEN * sizeof(char))){
9191 strncpy(p, rgbbuf, MAXCLEN);
9192 p[MAXCLEN-1] = '\0';
9193 return(p);
9197 return(NULL);
9203 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9205 * Signal and alarm functions
9207 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
9210 * Provide a rough implementation of the SIGALRM and alarm functions
9215 #if 0
9217 * Set a new handler for a signal.
9219 void (__cdecl * __cdecl signal (int sig,void (__cdecl *hndlr)(int)))(int)
9222 SignalType oldValue;
9224 switch(sig) {
9225 case SIGALRM :
9226 oldValue = gSignalAlarm;
9227 gSignalAlarm = hndlr;
9228 break;
9230 case SIGHUP :
9231 oldValue = gSignalHUP;
9232 gSignalHUP = hndlr;
9234 default:
9235 /* All other's are always ignored. */
9236 oldValue = SIG_IGN;
9237 break;
9240 return (oldValue);
9242 #endif
9246 * Set the alarm expiration time (in seconds)
9249 mswin_alarm (int seconds)
9251 int prevtime;
9253 prevtime = gAlarmTimeout ? (gAlarmTimeout - (GetTickCount () / 1000)): 0;
9254 gAlarmTimeout = seconds ? (GetTickCount() / 1000) + seconds : 0;
9255 MyTimerSet ();
9256 return (prevtime);
9262 * Deliver and clear the alarm.
9264 void
9265 AlarmDeliver ()
9267 if (gSignalAlarm != SIG_DFL && gSignalAlarm != SIG_IGN) {
9268 /* Clear AlarmTimeout BEFORE calling handler. handler may call back
9269 * to reset timeout. */
9270 gAlarmTimeout = 0;
9271 MyTimerSet ();
9272 gSignalAlarm (SIGALRM);
9278 void
9279 HUPDeliver ()
9281 if (gSignalHUP) {
9282 gSignalHUP (SIGHUP);
9283 exit (0);
9290 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9292 * Printer font selection menu
9294 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
9297 * Set the print font to be the same as the window font.
9298 * Toggle setting.
9300 void
9301 PrintFontSameAs (HWND hWnd)
9303 HDC hDC;
9304 int ppi;
9305 PTTYINFO pTTYInfo;
9308 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
9309 if (pTTYInfo == NULL)
9310 return;
9312 if (gPrintFontSameAs) {
9314 /* No longer same as window font. Use window font as starting point
9315 * for new printer font. User may later modify printer font. */
9316 hDC = GetDC (hWnd);
9317 ppi = GetDeviceCaps (hDC, LOGPIXELSY);
9318 ReleaseDC (ghTTYWnd, hDC);
9319 ExtractFontInfo(&pTTYInfo->lfTTYFont,
9320 gPrintFontName, sizeof(gPrintFontName)/sizeof(TCHAR),
9321 &gPrintFontSize,
9322 gPrintFontStyle, sizeof(gPrintFontStyle)/sizeof(TCHAR),
9323 ppi,
9324 gPrintFontCharSet, sizeof(gPrintFontCharSet)/sizeof(TCHAR));
9325 gPrintFontSameAs = FALSE;
9327 else {
9329 /* Set to be same as the printer font. Destroy printer font info
9330 * and set "sameAs" flag to TRUE. */
9331 gPrintFontName[0] = '\0';
9332 gPrintFontSameAs = TRUE;
9334 DidResize (gpTTYInfo);
9341 void
9342 PrintFontSelect (HWND hWnd)
9344 CHOOSEFONT cfTTYFont;
9345 LOGFONT newFont;
9346 DWORD drc;
9347 int ppi;
9348 HDC hDC;
9352 hDC = GetDC (hWnd);
9353 ppi = GetDeviceCaps (hDC, LOGPIXELSY);
9354 ReleaseDC (ghTTYWnd, hDC);
9357 newFont.lfHeight = -MulDiv (gPrintFontSize, ppi, 72);
9358 _tcsncpy(newFont.lfFaceName, gPrintFontName, LF_FACESIZE);
9359 newFont.lfFaceName[LF_FACESIZE-1] = 0;
9360 newFont.lfWeight = 0;
9361 if(_tcsstr(gPrintFontStyle, TEXT("bold")))
9362 newFont.lfWeight = FW_BOLD;
9364 newFont.lfItalic = 0;
9365 if(_tcsstr(gPrintFontStyle, TEXT("italic")))
9366 newFont.lfItalic = 1;
9368 newFont.lfWidth = 0;
9369 newFont.lfEscapement = 0;
9370 newFont.lfOrientation = 0;
9371 newFont.lfUnderline = 0;
9372 newFont.lfStrikeOut = 0;
9373 newFont.lfCharSet = mswin_string2charsetid(gPrintFontCharSet);
9374 newFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
9375 newFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
9376 newFont.lfQuality = DEFAULT_QUALITY;
9377 newFont.lfPitchAndFamily = FIXED_PITCH;
9380 cfTTYFont.lStructSize = sizeof (CHOOSEFONT);
9381 cfTTYFont.hwndOwner = hWnd ;
9382 cfTTYFont.hDC = NULL ;
9383 cfTTYFont.rgbColors = 0;
9384 cfTTYFont.lpLogFont = &newFont;
9385 cfTTYFont.Flags = CF_BOTH | CF_FIXEDPITCHONLY |
9386 CF_INITTOLOGFONTSTRUCT | CF_ANSIONLY |
9387 CF_FORCEFONTEXIST | CF_LIMITSIZE;
9388 cfTTYFont.nSizeMin = FONT_MIN_SIZE;
9389 cfTTYFont.nSizeMax = FONT_MAX_SIZE;
9390 cfTTYFont.lCustData = 0 ;
9391 cfTTYFont.lpfnHook = NULL ;
9392 cfTTYFont.lpTemplateName = NULL ;
9393 cfTTYFont.hInstance = GET_HINST (hWnd);
9396 if (ChooseFont (&cfTTYFont)) {
9397 ExtractFontInfo(&newFont,
9398 gPrintFontName, sizeof(gPrintFontName)/sizeof(TCHAR),
9399 &gPrintFontSize,
9400 gPrintFontStyle, sizeof(gPrintFontStyle)/sizeof(TCHAR),
9401 ppi,
9402 gPrintFontCharSet, sizeof(gPrintFontCharSet)/sizeof(TCHAR));
9403 DidResize (gpTTYInfo);
9405 else
9406 /* So I can see with the debugger. */
9407 drc = CommDlgExtendedError();
9411 void
9412 ExtractFontInfo(LOGFONT *pFont, LPTSTR fontName, size_t nfontName,
9413 int *fontSize, LPTSTR fontStyle, size_t nfontStyle,
9414 int ppi, LPTSTR fontCharSet, size_t nfontCharSet)
9416 TCHAR *sep[] = {TEXT(""), TEXT(", ")};
9417 int iSep = 0;
9420 _tcsncpy(fontName, pFont->lfFaceName, nfontName);
9421 fontName[nfontName-1] = '\0';
9423 *fontStyle = '\0';
9424 if(pFont->lfWeight >= FW_BOLD) {
9425 _tcsncpy(fontStyle, TEXT("bold"), nfontStyle);
9426 fontStyle[nfontStyle-1] = '\0';
9427 iSep = 1;
9430 if(pFont->lfItalic){
9431 _tcsncat(fontStyle, sep[iSep], nfontStyle - _tcslen(fontStyle));
9432 fontStyle[nfontStyle-1] = '\0';
9434 _tcsncat(fontStyle, TEXT("italic"), nfontStyle - _tcslen(fontStyle));
9435 fontStyle[nfontStyle-1] = '\0';
9438 mswin_charsetid2string(fontCharSet, nfontCharSet, pFont->lfCharSet);
9440 if(fontSize)
9441 *fontSize = MulDiv(-pFont->lfHeight, 72, ppi);
9445 LOCAL void
9446 DidResize (PTTYINFO pTTYInfo)
9448 int i;
9450 for (i = 0; i < RESIZE_CALLBACK_ARRAY_SIZE; ++i) {
9451 if (pTTYInfo->resizer[i] != NULL)
9452 pTTYInfo->resizer[i] (pTTYInfo->actNRow, pTTYInfo->actNColumn);
9455 * Put a null character into the input queue so that the data input
9456 * loops stop and return to their callers who will then re-calculate the
9457 * mouse regions so that the user can click on the new regions of the
9458 * screen and have the right thing happen.
9460 CQAdd (NODATA, 0);
9466 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9468 * Cut, Copy, and Paste operations
9470 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
9474 * Gets called right before the menu is displayed so we can make
9475 * any last minute adjustments.
9477 LOCAL void
9478 UpdateMenu (HWND hWnd)
9480 HMENU hMenu;
9481 PTTYINFO pTTYInfo;
9482 int i;
9483 #ifdef ACCELERATORS
9484 UINT fAccel = EM_NONE;
9485 #endif
9487 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
9488 if (pTTYInfo == NULL)
9489 return;
9491 hMenu = GetMenu (hWnd);
9492 if (hMenu == NULL)
9493 return;
9495 if (ghPaste) {
9496 /* Currently pasting so disable paste and enable cancel paste. */
9497 EnableMenuItem (hMenu, IDM_EDIT_PASTE, MF_BYCOMMAND|MF_GRAYED);
9498 EnableMenuItem (hMenu, IDM_EDIT_CANCEL_PASTE, MF_BYCOMMAND|MF_ENABLED);
9499 #ifdef ACCELERATORS
9500 fAccel |= (EM_PST | EM_PST_ABORT);
9501 #endif
9503 else {
9505 * Not pasting. If text is available on clipboard and we are
9506 * at a place where we can paste, enable past menu option.
9508 if (IsClipboardFormatAvailable (CF_UNICODETEXT) && gPasteEnabled){
9509 EnableMenuItem (hMenu, IDM_EDIT_PASTE, MF_BYCOMMAND|MF_ENABLED);
9510 #ifdef ACCELERATORS
9511 fAccel |= EM_PST;
9512 #endif
9514 else
9515 EnableMenuItem (hMenu, IDM_EDIT_PASTE, MF_BYCOMMAND|MF_GRAYED);
9517 EnableMenuItem (hMenu, IDM_EDIT_CANCEL_PASTE, MF_BYCOMMAND|MF_GRAYED);
9520 if (SelAvailable ()) {
9521 EnableMenuItem (hMenu, IDM_EDIT_CUT, MF_BYCOMMAND|MF_GRAYED);
9522 EnableMenuItem (hMenu, IDM_EDIT_COPY, MF_BYCOMMAND|MF_ENABLED);
9523 EnableMenuItem (hMenu, IDM_EDIT_COPY_APPEND, MF_BYCOMMAND|MF_ENABLED);
9524 #ifdef ACCELERATORS
9525 fAccel |= (EM_CP | EM_CP_APPEND);
9526 #endif
9528 else {
9529 if (gAllowCut){
9530 EnableMenuItem (hMenu, IDM_EDIT_CUT, MF_BYCOMMAND | MF_ENABLED);
9531 #ifdef ACCELERATORS
9532 fAccel |= EM_CUT;
9533 #endif
9535 else
9536 EnableMenuItem (hMenu, IDM_EDIT_CUT, MF_BYCOMMAND | MF_GRAYED);
9538 if (gAllowCopy) {
9539 EnableMenuItem (hMenu, IDM_EDIT_COPY, MF_BYCOMMAND | MF_ENABLED);
9540 EnableMenuItem (hMenu, IDM_EDIT_COPY_APPEND,
9541 MF_BYCOMMAND | MF_ENABLED);
9542 #ifdef ACCELERATORS
9543 fAccel |= (EM_CP | EM_CP_APPEND);
9544 #endif
9546 else {
9547 EnableMenuItem (hMenu, IDM_EDIT_COPY, MF_BYCOMMAND | MF_GRAYED);
9548 EnableMenuItem (hMenu, IDM_EDIT_COPY_APPEND,
9549 MF_BYCOMMAND | MF_GRAYED);
9554 * Set up Font selection menu
9556 if (gPrintFontName[0] == '\0') {
9557 CheckMenuItem (hMenu, IDM_OPT_FONTSAMEAS, MF_BYCOMMAND | MF_CHECKED);
9558 EnableMenuItem (hMenu, IDM_OPT_SETPRINTFONT,
9559 MF_BYCOMMAND | MF_GRAYED);
9561 else {
9562 CheckMenuItem (hMenu, IDM_OPT_FONTSAMEAS,
9563 MF_BYCOMMAND | MF_UNCHECKED);
9564 EnableMenuItem (hMenu, IDM_OPT_SETPRINTFONT,
9565 MF_BYCOMMAND | MF_ENABLED);
9569 * Setup Caret selection menu
9571 EnableMenuItem (hMenu, IDM_OPT_CARETBLOCK, MF_BYCOMMAND | MF_ENABLED);
9572 EnableMenuItem (hMenu, IDM_OPT_CARETSMALLBLOCK, MF_BYCOMMAND | MF_ENABLED);
9573 EnableMenuItem (hMenu, IDM_OPT_CARETHBAR, MF_BYCOMMAND | MF_ENABLED);
9574 EnableMenuItem (hMenu, IDM_OPT_CARETVBAR, MF_BYCOMMAND | MF_ENABLED);
9575 CheckMenuRadioItem(hMenu, IDM_OPT_CARETBLOCK, IDM_OPT_CARETVBAR,
9576 IDM_OPT_CARETBLOCK + pTTYInfo->cCaretStyle,
9577 MF_BYCOMMAND);
9580 * Check toolbar menu.
9582 EnableMenuItem (hMenu, IDM_OPT_TOOLBAR, MF_BYCOMMAND | MF_ENABLED);
9583 CheckMenuItem (hMenu, IDM_OPT_TOOLBAR, MF_BYCOMMAND |
9584 (pTTYInfo->toolBarSize > 0 ? MF_CHECKED : MF_UNCHECKED));
9585 EnableMenuItem (hMenu, IDM_OPT_TOOLBARPOS, MF_BYCOMMAND | MF_ENABLED);
9586 CheckMenuItem (hMenu, IDM_OPT_TOOLBARPOS, MF_BYCOMMAND |
9587 (pTTYInfo->toolBarTop > 0 ? MF_CHECKED : MF_UNCHECKED));
9592 * Check the dialogs menu.
9594 /* xxx EnableMenuItem (hMenu, IDM_OPT_USEDIALOGS, MF_BYCOMMAND | MF_ENABLED);*/
9595 CheckMenuItem (hMenu, IDM_OPT_USEDIALOGS, MF_BYCOMMAND |
9596 (gfUseDialogs ? MF_CHECKED : MF_UNCHECKED));
9599 * Enable the Erase Credentials menu
9601 EnableMenuItem (hMenu, IDM_OPT_ERASE_CREDENTIALS,
9602 MF_BYCOMMAND | (gEraseCredsCallback ? MF_ENABLED : MF_GRAYED));
9605 * Enable the View in New Window menu item
9607 EnableMenuItem (hMenu, IDM_MI_VIEWINWIND,
9608 MF_BYCOMMAND | (gViewInWindCallback ? MF_ENABLED : MF_GRAYED));
9610 #ifdef ACCELERATORS_OPT
9611 CheckMenuItem (hMenu, IDM_OPT_USEACCEL, MF_BYCOMMAND |
9612 (pTTYInfo->hAccel ? MF_CHECKED : MF_UNCHECKED));
9613 #endif
9616 * Setup the sort menu...
9618 if(gSortCallback){
9619 i = (*gSortCallback)(0, 0);
9621 /* NOTE: this func's args are dependent on definition order
9622 * in resource.h
9624 CheckMenuRadioItem(hMenu, IDM_MI_SORTSUBJECT, IDM_MI_SORTTHREAD,
9625 IDM_MI_SORTSUBJECT + (i & 0x00ff), MF_BYCOMMAND);
9626 CheckMenuItem(hMenu, IDM_MI_SORTREVERSE,
9627 MF_BYCOMMAND|((i & 0x0100) ? MF_CHECKED : MF_UNCHECKED));
9629 else{
9630 CheckMenuRadioItem(hMenu, IDM_MI_SORTSUBJECT, IDM_MI_SORTTHREAD,
9631 IDM_MI_SORTARRIVAL, MF_BYCOMMAND);
9632 CheckMenuItem(hMenu, IDM_MI_SORTREVERSE, MF_BYCOMMAND | MF_UNCHECKED);
9636 * Setup the flag menu...
9638 if(gFlagCallback){
9639 int flags = (*gFlagCallback)(0, 0);
9640 for(i = IDM_MI_FLAGIMPORTANT; i <= IDM_MI_FLAGDELETED; i++)
9641 CheckMenuItem(hMenu, i, MF_BYCOMMAND
9642 | (((flags >> (i - IDM_MI_FLAGIMPORTANT)) & 0x0001)
9643 ? MF_CHECKED : MF_UNCHECKED));
9649 if(gHdrCallback){
9650 i = (*gHdrCallback)(0, 0);
9651 CheckMenuItem(hMenu, IDM_MI_HDRMODE,
9652 MF_BYCOMMAND|((i != 0) ? MF_CHECKED : MF_UNCHECKED));
9658 if(gZoomCallback){
9659 i = (*gZoomCallback)(0, 0);
9660 CheckMenuItem(hMenu, IDM_MI_ZOOM,
9661 MF_BYCOMMAND | (i ? MF_CHECKED : MF_UNCHECKED));
9664 * Set up command menu.
9666 if (!pTTYInfo->menuItemsCurrent) {
9667 for (i = 0; i < KS_COUNT; ++i)
9668 if(i + KS_RANGESTART != KS_GENERALHELP)
9669 EnableMenuItem (hMenu, i + KS_RANGESTART,
9670 MF_BYCOMMAND | ((pTTYInfo->menuItems[i].miActive)
9671 ? MF_ENABLED : MF_GRAYED));
9674 * Special command-specific knowledge here
9676 for(i = IDM_MI_SORTSUBJECT; i <= IDM_MI_SORTREVERSE; i++)
9677 EnableMenuItem (hMenu, i,
9678 MF_BYCOMMAND
9679 | ((pTTYInfo->menuItems[KS_SORT-KS_RANGESTART].miActive)
9680 ? MF_ENABLED : MF_GRAYED));
9682 for(i = IDM_MI_FLAGIMPORTANT; i <= IDM_MI_FLAGDELETED; i++)
9683 EnableMenuItem (hMenu, i,
9684 MF_BYCOMMAND
9685 | ((pTTYInfo->menuItems[KS_FLAG - KS_RANGESTART].miActive)
9686 ? MF_ENABLED : MF_GRAYED));
9691 * deal with any callback state dependent enabling
9693 if(pTTYInfo->menuItems[IDM_MI_APPLY - KS_RANGESTART].miActive)
9694 EnableMenuItem(hMenu, IDM_MI_APPLY,
9695 MF_BYCOMMAND | ((gSelectedCallback
9696 && (*gSelectedCallback)(0, 0))
9697 ? MF_ENABLED : MF_GRAYED));
9699 if(pTTYInfo->menuItems[IDM_MI_ZOOM - KS_RANGESTART].miActive)
9700 EnableMenuItem(hMenu, IDM_MI_ZOOM,
9701 MF_BYCOMMAND | ((gSelectedCallback
9702 && (*gSelectedCallback)(0, 0))
9703 ? MF_ENABLED : MF_GRAYED));
9705 #ifdef ACCELERATORS
9706 if(pTTYInfo->menuItems[KS_WHEREIS - KS_RANGESTART].miActive)
9707 fAccel |= EM_FIND;
9709 AccelManage (hWnd, fAccel);
9710 #endif
9712 pTTYInfo->menuItemsCurrent = TRUE;
9718 * Cut region to kill buffer.
9720 LOCAL void
9721 EditCut (void)
9723 HANDLE hCB;
9725 if(gCopyCutFunction == (getc_t)kremove){
9726 hCB = GlobalAlloc (GMEM_MOVEABLE, 0);
9727 if (hCB != NULL) {
9728 kdelete(); /* Clear current kill buffer. */
9729 killregion (1, 0); /* Kill Region (and copy to clipboard). */
9730 update (); /* And update the screen */
9738 * This function copies the kill buffer to the window's clip board.
9739 * (actually, it can copy any buffer for which a copyfunc is provided).
9740 * Called from ldelete().
9742 void
9743 mswin_killbuftoclip (getc_t copyfunc)
9745 HANDLE hCB;
9746 getc_t oldfunc;
9748 /* Save old copy function. */
9749 oldfunc = gCopyCutFunction;
9750 gCopyCutFunction = copyfunc;
9752 /* Allocate clip buffer. */
9753 hCB = GlobalAlloc (GMEM_MOVEABLE, 0);
9754 if (hCB != NULL) {
9755 EditDoCopyData (hCB, 0);
9758 /* restore copy function. */
9759 gCopyCutFunction = oldfunc;
9765 * Copy region to kill buffer.
9767 LOCAL void
9768 EditCopy (void)
9770 HANDLE hCB;
9772 if (SelAvailable()) {
9773 /* This is a copy of the windows selection. */
9774 hCB = GlobalAlloc (GMEM_MOVEABLE, 0);
9775 if (hCB != NULL)
9776 SelDoCopy (hCB, 0);
9778 else {
9780 /* Otherwise, it's a Pico/Pine copy. */
9781 if(gCopyCutFunction == (getc_t)kremove){
9782 kdelete(); /* Clear current kill buffer. */
9783 copyregion (1, 0);
9786 hCB = GlobalAlloc (GMEM_MOVEABLE, 0);
9787 if (hCB != NULL)
9788 EditDoCopyData (hCB, 0);
9795 * Called in responce to "Copy Append" menu command, when there is an active
9796 * Windows selection on the screen.
9798 LOCAL void
9799 EditCopyAppend (void)
9801 HANDLE hCB;
9802 HANDLE hMyCopy;
9803 TCHAR *pCB;
9804 TCHAR *pMyCopy;
9805 size_t cbSize = 0;
9807 /* Attempt to copy clipboard data to my own handle. */
9808 hMyCopy = NULL;
9809 if (OpenClipboard (ghTTYWnd)) { /* And can get clipboard. */
9810 hCB = GetClipboardData (CF_UNICODETEXT);
9811 if (hCB != NULL) { /* And can get data. */
9812 pCB = GlobalLock (hCB);
9813 cbSize = _tcslen (pCB); /* It's a null term string. */
9814 hMyCopy = GlobalAlloc (GMEM_MOVEABLE, (cbSize+1)*sizeof(*pCB));
9815 if (hMyCopy != NULL) { /* And can get memory. */
9816 pMyCopy = GlobalLock (hMyCopy);
9817 if (pMyCopy != NULL) {
9818 memcpy (pMyCopy, pCB, cbSize*sizeof(*pCB)); /* Copy data. */
9819 GlobalUnlock (hMyCopy);
9821 else {
9822 GlobalFree (hMyCopy);
9823 hMyCopy = NULL;
9826 GlobalUnlock (hCB);
9827 } /* GetClipboardData. */
9828 CloseClipboard ();
9829 } /* OpenClipboard. */
9833 /* Now, if I got a copy, append current selection to that
9834 * and stuff it back into the clipboard. */
9835 if (hMyCopy != NULL) {
9836 if (SelAvailable ()) {
9837 SelDoCopy (hMyCopy, (DWORD)cbSize);
9839 else {
9840 if(gCopyCutFunction == (getc_t)kremove) {
9841 kdelete(); /* Clear current kill buffer. */
9842 copyregion (1, 0);
9844 EditDoCopyData (hMyCopy, (DWORD)cbSize);
9851 * Copy data from the kill buffer to the clipboard. Handle LF->CRLF
9852 * translation if necessary.
9854 LOCAL void
9855 EditDoCopyData (HANDLE hCB, DWORD lenCB)
9857 TCHAR *pCB;
9858 TCHAR *p;
9859 long c; /* would be TCHAR but needs -1 retval from callback */
9860 TCHAR lastc = (TCHAR)'\0';
9861 DWORD cbSize; /* Allocated size of hCB. */
9862 DWORD i;
9863 #define BUF_INC 4096
9865 if (gCopyCutFunction != NULL) { /* If there really is data. */
9866 if (OpenClipboard (ghTTYWnd)) { /* ...and we get the CB. */
9867 if (EmptyClipboard ()) { /* ...and clear previous CB.*/
9868 pCB = GlobalLock (hCB);
9869 p = pCB + lenCB;
9870 cbSize = lenCB;
9871 /* Copy it. (BUG: change int arg) */
9872 for(i = 0L; (c = (*gCopyCutFunction)((int)i)) != -1; i++){
9874 * Rather than fix every function that might
9875 * get called for character retrieval to supply
9876 * CRLF EOLs, let's just fix it here. The downside
9877 * is a much slower copy for large buffers, but
9878 * hey, what do they want?
9880 if(lenCB + 2L >= cbSize){
9881 cbSize += BUF_INC;
9882 GlobalUnlock (hCB);
9883 hCB = GlobalReAlloc (hCB, cbSize*sizeof(TCHAR), GMEM_MOVEABLE);
9884 if (hCB == NULL)
9885 return;
9887 pCB = GlobalLock (hCB);
9888 p = pCB + lenCB;
9891 if(c == (TCHAR)ASCII_LF && lastc != (TCHAR)ASCII_CR) {
9892 *p++ = (TCHAR)ASCII_CR; /* insert CR before LF */
9893 lenCB++;
9896 *p++ = lastc = (TCHAR)c;
9897 lenCB++;
9900 /* Only if we got some data. */
9901 if (lenCB > 0) {
9902 *p = (TCHAR)'\0';
9903 GlobalUnlock (hCB);
9905 if (SetClipboardData (CF_UNICODETEXT, hCB) == NULL)
9906 /* Failed! Free the data. */
9907 GlobalFree (hCB);
9909 else {
9910 /* There was no data copied. */
9911 GlobalUnlock (hCB);
9912 GlobalFree (hCB);
9915 CloseClipboard ();
9922 * Get a handle to the current (text) clipboard and make my own copy.
9923 * Keep my copy locked because I'll be using it to read bytes from.
9925 LOCAL void
9926 EditPaste (void)
9928 HANDLE hCB;
9929 LPTSTR pCB;
9930 LPTSTR pPaste;
9931 size_t cbSize;
9933 if (ghPaste == NULL) { /* If we are not already pasting. */
9934 if (OpenClipboard (ghTTYWnd)) { /* And can get clipboard. */
9935 hCB = GetClipboardData (CF_UNICODETEXT);
9936 if (hCB != NULL) { /* And can get data. */
9937 pCB = GlobalLock (hCB);
9938 cbSize = _tcslen (pCB); /* It's a null term string. */
9939 ghPaste = GlobalAlloc (GMEM_MOVEABLE, (cbSize+1)*sizeof(TCHAR));
9940 if (ghPaste != NULL) { /* And can get memory. */
9941 gpPasteNext = GlobalLock (ghPaste);
9942 memcpy (gpPasteNext, pCB, (cbSize+1)*sizeof(TCHAR)); /* Copy data. */
9943 /* Keep ghPaste locked. */
9946 * If we're paste is enabled but limited to the first
9947 * line of the clipboard, prune the paste buffer...
9949 if(gPasteEnabled == MSWIN_PASTE_LINE
9950 && (pPaste = _tcschr(gpPasteNext, (TCHAR)ASCII_CR))){
9951 *pPaste = (TCHAR)'\0';
9952 cbSize = _tcslen(gpPasteNext);
9956 * If there is a selection (gCopyCutFunction != NULL)
9957 * then delete it so that it will be replaced by
9958 * the pasted text.
9960 if (gCopyCutFunction != NULL)
9961 deleteregion (1, 0);
9963 gPasteBytesRemain = cbSize;
9964 gPasteWasCR = FALSE;
9965 #ifdef FDEBUG
9966 if (mswin_debug > 8)
9967 fprintf (mswin_debugfile, "EditPaste:: Paste %d bytes\n",
9968 gPasteBytesRemain);
9969 #endif
9971 GlobalUnlock (hCB);
9973 CloseClipboard ();
9984 * Cancel an active paste operation.
9986 LOCAL void
9987 EditCancelPaste (void)
9989 if (ghPaste != NULL) { /* Must be pasting. */
9990 GlobalUnlock (ghPaste); /* Then Unlock... */
9991 GlobalFree (ghPaste); /* ...and free the paste buffer. */
9992 ghPaste = NULL; /* Indicates no paste data. */
9993 gpPasteNext = NULL; /* Just being tidy. */
9994 gPasteBytesRemain = 0; /* ditto. */
9995 #ifdef FDEBUG
9996 if (mswin_debug > 8)
9997 fprintf (mswin_debugfile, "EditCancelPaste:: Free Paste Data\n");
9998 #endif
10004 * Get the next byte from the paste buffer. If all bytes have been
10005 * retreived, free the paste buffer.
10006 * Map all CRLF sequence to a single CR.
10008 LOCAL UCS
10009 EditPasteGet (void)
10011 UCS b = NODATA;
10013 if (ghPaste != NULL) { /* ghPaste tells if we are pasting. */
10014 if (gPasteBytesRemain > 0) { /* Just in case... */
10015 /* Get one byte and move pointer. */
10016 b = (TCHAR) *gpPasteNext++;
10017 --gPasteBytesRemain; /* one less. */
10018 if (gPasteWasCR && b == (TCHAR)ASCII_LF) {
10019 if (gPasteBytesRemain) {
10020 /* Skip of LF. */
10021 b = (TCHAR) *gpPasteNext++;
10022 --gPasteBytesRemain;
10024 else
10025 b = NODATA; /* Ignore last LF. */
10027 gPasteWasCR = (b == (TCHAR)ASCII_CR);
10028 #ifdef FDEBUG
10029 if (mswin_debug > 8)
10030 fprintf (mswin_debugfile, "EditPasteGet:: char %c, gPasteWasCR %d, gPasteBytesRemain %d\n",
10031 b, gPasteWasCR, gPasteBytesRemain);
10032 #endif
10034 if (gPasteBytesRemain <= 0) { /* All Done? */
10035 GlobalUnlock (ghPaste); /* Then Unlock... */
10036 GlobalFree (ghPaste); /* ...and free the paste buffer. */
10037 ghPaste = NULL; /* Indicates no paste data. */
10038 gpPasteNext = NULL; /* Just being tidy. */
10039 gPasteBytesRemain = 0; /* ditto. */
10040 #ifdef FDEBUG
10041 if (mswin_debug > 8)
10042 fprintf (mswin_debugfile, "EditPasteGet:: Free Paste Data\n");
10043 #endif
10047 if(b < ' ') {
10048 b += '@';
10049 b |= CTRL;
10052 return (b);
10057 * Return true if Paste data is available. If gpPaste != NULL then there
10058 * is paste data.
10060 LOCAL BOOL
10061 EditPasteAvailable (void)
10063 return (ghPaste != NULL);
10069 * Select everything in the buffer
10071 LOCAL void
10072 EditSelectAll()
10074 if(ComposerEditing){
10076 else{
10077 gotobob(0, 1);
10078 setmark(0, 1);
10079 gotoeob(0, 1);
10080 update (); /* And update the screen */
10085 LOCAL void
10086 SortHandler(int order, int reverse)
10088 int old = (*gSortCallback)(0, 0);
10090 if(order < 0){
10091 old ^= 0x0100; /* flip reverse bit */
10092 (*gSortCallback)(1, old);
10094 else
10095 (*gSortCallback)(1, order | (old & 0x0100));
10099 LOCAL void
10100 FlagHandler(int index, int args)
10102 if(gFlagCallback)
10103 (void) (*gFlagCallback)(index + 1, 0L);
10107 LOCAL void
10108 MSWHelpShow (cbstr_t fpHelpCallback)
10110 if (fpHelpCallback != NULL){
10111 char title[256], *help;
10113 if(help = (*fpHelpCallback) (title))
10114 mswin_displaytext (title, help, strlen(help), NULL, NULL, 0);
10122 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10124 * Adjust the timer frequency as needed.
10126 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10128 LOCAL void
10129 MyTimerSet (void)
10131 UINT period;
10132 /* Decide on period to use. */
10133 if (gAllowMouseTrack)
10134 period = MY_TIMER_EXCEEDINGLY_SHORT_PERIOD;
10135 else
10136 period = my_timer_period;
10138 if (period != gTimerCurrentPeriod) {
10139 if (SetTimer (ghTTYWnd, MY_TIMER_ID, period, NULL) == 0)
10140 MessageBox (ghTTYWnd, TIMER_FAIL_MESSAGE, NULL,
10141 MB_OK | MB_ICONINFORMATION);
10142 else
10143 gTimerCurrentPeriod = period;
10151 void
10152 mswin_setperiodiccallback (cbvoid_t periodiccb, long period)
10154 if (periodiccb != NULL && period > 0) {
10155 gPeriodicCallback = periodiccb;
10156 gPeriodicCBTime = period;
10157 gPeriodicCBTimeout = GetTickCount () / 1000 + gPeriodicCBTime;
10159 else {
10160 gPeriodicCallback = NULL;
10165 * Structure for variables used by mswin_exec_and_wait which need to be
10166 * freed in multiple places.
10168 typedef struct MSWIN_EXEC_DATA {
10169 HANDLE infd;
10170 HANDLE outfd;
10171 LPTSTR lptstr_whatsit;
10172 LPTSTR lptstr_command;
10173 LPTSTR lptstr_infile;
10174 LPTSTR lptstr_outfile;
10175 MSWIN_TEXTWINDOW *mswin_tw;
10176 } MSWIN_EXEC_DATA;
10178 LOCAL void
10179 mswin_exec_data_init(MSWIN_EXEC_DATA *exec_data)
10181 memset(exec_data, 0, sizeof(MSWIN_EXEC_DATA));
10182 exec_data->infd = INVALID_HANDLE_VALUE;
10183 exec_data->outfd = INVALID_HANDLE_VALUE;
10186 LOCAL void
10187 mswin_exec_data_free(MSWIN_EXEC_DATA *exec_data, BOOL delete_outfile)
10189 if(exec_data->infd != INVALID_HANDLE_VALUE)
10190 CloseHandle(exec_data->infd);
10192 if(exec_data->outfd != INVALID_HANDLE_VALUE) {
10193 CloseHandle(exec_data->outfd);
10194 if(delete_outfile)
10195 _tunlink(exec_data->lptstr_outfile);
10198 if(exec_data->lptstr_infile)
10199 fs_give((void **) &exec_data->lptstr_infile);
10200 if(exec_data->lptstr_outfile)
10201 fs_give((void **) &exec_data->lptstr_outfile);
10202 if(exec_data->lptstr_whatsit)
10203 fs_give((void **) &exec_data->lptstr_whatsit);
10204 if(exec_data->lptstr_command)
10205 fs_give((void **) &exec_data->lptstr_command);
10207 if(exec_data->mswin_tw) {
10209 * Set the out_file is zero. We don't need mswin_tw
10210 * to save the file anymore since we're bailing.
10212 exec_data->mswin_tw->out_file = NULL;
10215 * If the window is still open, then set the id to 0 so
10216 * mswin_tw_close_callback() will free the memory whenever
10217 * the window closes. Otherwise free it now.
10219 if(exec_data->mswin_tw->hwnd)
10220 exec_data->mswin_tw->id = 0;
10221 else
10222 MemFree(exec_data->mswin_tw);
10227 * Execute command and wait for the child to exit
10229 * whatsit - description of reason exec being called
10230 * command - command to run
10231 * infile - name of file to pass as stdin
10232 * outfile - name of file to pass as stdout
10233 * exit_val - where to store return value of the process
10234 * mswe_flags -
10235 * MSWIN_EAW_CAPT_STDERR - capture stderr along with stdout
10236 * MSWIN_EAW_CTRL_C_CANCELS - if user presses ctrl-c, detach child
10237 * Returns: 0, successfully completed program
10238 * -1, errors occurred
10239 * -2, user chose to stop waiting for program before it finished
10242 mswin_exec_and_wait (char *utf8_whatsit, char *utf8_command,
10243 char *utf8_infile, char *utf8_outfile,
10244 int *exit_val, unsigned mswe_flags)
10246 MEvent mouse;
10247 BOOL brc;
10248 int rc;
10249 TCHAR waitingFor[256];
10250 PROCESS_INFORMATION proc_info;
10251 DWORD exit_code;
10252 MSWIN_EXEC_DATA exec_data;
10253 #ifdef ALTED_DOT
10254 BOOL b_use_mswin_tw;
10255 #endif
10257 mswin_exec_data_init(&exec_data);
10259 memset(&proc_info, 0, sizeof(proc_info));
10261 mswin_flush ();
10263 exec_data.lptstr_infile = utf8_infile ? utf8_to_lptstr(utf8_infile) : NULL;
10264 exec_data.lptstr_outfile = utf8_outfile ? utf8_to_lptstr(utf8_outfile) : NULL;
10266 exec_data.lptstr_command = utf8_to_lptstr(utf8_command);
10267 exec_data.lptstr_whatsit = utf8_to_lptstr(utf8_whatsit);
10269 #ifdef ALTED_DOT
10270 /* If the command is '.', then use mswin_tw to open the file. */
10271 b_use_mswin_tw = utf8_command &&
10272 utf8_command[0] == '.' && utf8_command[1] == '\0';
10274 if(b_use_mswin_tw) {
10276 proc_info.hThread = INVALID_HANDLE_VALUE;
10277 proc_info.hProcess = INVALID_HANDLE_VALUE;
10279 exec_data.mswin_tw = mswin_tw_displaytext_lptstr(
10280 exec_data.lptstr_whatsit, exec_data.lptstr_infile, 4, NULL,
10281 exec_data.mswin_tw, MSWIN_DT_FILLFROMFILE);
10283 if(exec_data.mswin_tw) {
10284 mswin_set_readonly(exec_data.mswin_tw, FALSE);
10286 /* Tell mswin_tw to write the edit contents to this file. */
10287 exec_data.mswin_tw->out_file = exec_data.lptstr_outfile;
10289 /* Make sure mswin_tw isn't freed behind our back. */
10290 exec_data.mswin_tw->id = (UINT)-1;
10291 brc = TRUE;
10293 else {
10294 brc = FALSE;
10297 else
10298 #endif /* ALTED_DOT */
10300 SECURITY_ATTRIBUTES atts;
10301 STARTUPINFO start_info;
10303 memset(&atts, 0, sizeof(atts));
10304 memset(&start_info, 0, sizeof(start_info));
10306 /* set file attributes of temp files*/
10307 atts.nLength = sizeof(SECURITY_ATTRIBUTES);
10308 atts.bInheritHandle = TRUE;
10309 atts.lpSecurityDescriptor = NULL;
10311 /* open files if asked for */
10312 if(utf8_infile
10313 && ((exec_data.infd = CreateFile(exec_data.lptstr_infile,
10314 GENERIC_READ, 0, &atts,
10315 OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL))
10316 == INVALID_HANDLE_VALUE)){
10318 mswin_exec_data_free(&exec_data, TRUE);
10319 return(-1);
10322 if(utf8_outfile
10323 && ((exec_data.outfd = CreateFile(exec_data.lptstr_outfile,
10324 GENERIC_WRITE, 0, &atts,
10325 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL))
10326 == INVALID_HANDLE_VALUE)){
10328 mswin_exec_data_free(&exec_data, TRUE);
10329 return(-1);
10332 start_info.dwFlags = STARTF_FORCEONFEEDBACK | STARTF_USESHOWWINDOW;
10333 start_info.wShowWindow = (utf8_infile || utf8_outfile) ? SW_SHOWMINNOACTIVE : SW_SHOWNA;
10335 /* set up i/o redirection */
10336 if(utf8_infile)
10337 start_info.hStdInput = exec_data.infd;
10338 if(utf8_outfile)
10339 start_info.hStdOutput = exec_data.outfd;
10340 if(utf8_outfile && (mswe_flags & MSWIN_EAW_CAPT_STDERR))
10341 start_info.hStdError = exec_data.outfd;
10342 if(utf8_infile || utf8_outfile)
10343 start_info.dwFlags |= STARTF_USESTDHANDLES;
10345 brc = CreateProcess(NULL, exec_data.lptstr_command, NULL, NULL,
10346 (utf8_infile || utf8_outfile) ? TRUE : FALSE,
10347 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
10348 NULL, NULL, &start_info, &proc_info);
10351 if(brc) {
10352 _sntprintf(waitingFor, sizeof(waitingFor)/sizeof(TCHAR),
10353 TEXT("%s is currently waiting for the %s (%s) to complete. Click \"Cancel\" to stop waiting, or \"OK\" to continue waiting."),
10354 gszAppName, exec_data.lptstr_whatsit, exec_data.lptstr_command);
10356 if(proc_info.hThread != INVALID_HANDLE_VALUE) {
10357 /* Don't need the thread handle, close it now. */
10358 CloseHandle (proc_info.hThread);
10362 * Go into holding pattern until the other application terminates
10363 * or we are told to stop waiting.
10365 while(TRUE){
10367 #ifdef ALTED_DOT
10368 if(b_use_mswin_tw)
10370 if(!exec_data.mswin_tw)
10371 break;
10373 exit_code = exec_data.mswin_tw->hwnd && exec_data.mswin_tw->out_file ?
10374 STILL_ACTIVE : 0;
10376 else
10377 #endif /* ALTED_DOT */
10379 if(GetExitCodeProcess(proc_info.hProcess, &exit_code) == FALSE)
10380 break;
10383 if(exit_code == STILL_ACTIVE){
10384 rc = mswin_getc();
10385 brc = mswin_getmouseevent (&mouse);
10387 if (rc != NODATA ||
10388 (brc && mouse.event == M_EVENT_DOWN)) {
10389 if(mswe_flags & MSWIN_EAW_CTRL_C_CANCELS){
10390 if(rc == (CTRL|'C'))
10391 rc = IDCANCEL;
10393 else{
10394 rc = MessageBox (ghTTYWnd, waitingFor, exec_data.lptstr_whatsit,
10395 MB_ICONSTOP | MB_OKCANCEL);
10397 SelClear ();
10398 if (rc == IDCANCEL){
10399 /* terminate message to child ? */
10400 mswin_exec_data_free(&exec_data, TRUE);
10401 return (-2);
10405 else{
10406 if(proc_info.hProcess != INVALID_HANDLE_VALUE) {
10407 /* do something about child's exit status */
10408 CloseHandle (proc_info.hProcess);
10410 if(exit_val)
10411 *exit_val = exit_code;
10412 break;
10416 if (gpTTYInfo->fMinimized)
10417 ShowWindow (ghTTYWnd, SW_SHOWNORMAL);
10420 * If we're using a mswin_tw and we're not capturing the output, we
10421 * just bailed immediately. If that's the case, don't bring the main
10422 * window up over the top of the textwindow we just brought up.
10424 #ifdef ALTED_DOT
10425 if(!b_use_mswin_tw || !exec_data.mswin_tw || exec_data.mswin_tw->out_file)
10426 #endif /* ALTED_DOT */
10427 BringWindowToTop (ghTTYWnd);
10429 mswin_exec_data_free(&exec_data, FALSE);
10430 return (0);
10432 else{
10433 mswin_exec_data_free(&exec_data, TRUE);
10434 return((rc = (int) GetLastError()) ? rc : -1); /* hack */
10437 /* NOTREACHED */
10438 return(-1);
10443 mswin_shell_exec(char *command_utf8, HINSTANCE *pChildProc)
10445 int quoted = 0;
10446 SHELLEXECUTEINFO shell_info;
10447 LPTSTR command_lpt, free_command_lpt;
10448 LPTSTR p, q, parm = NULL;
10449 TCHAR buf[1024];
10451 if(!command_utf8)
10452 return(-1);
10454 free_command_lpt = command_lpt = utf8_to_lptstr(command_utf8);
10455 if(!command_lpt)
10456 return(-1);
10458 mswin_flush ();
10461 * Pick first arg apart by whitespace until what's to the left
10462 * is no longer a valid path/file. Everything else is then an
10463 * command line arg...
10465 if(*(p = command_lpt) == '\"'){
10466 p = ++command_lpt; /* don't include quote */
10467 quoted++;
10470 q = buf;
10471 while(1)
10472 if(!quoted && _istspace(*p)){
10473 char *buf_utf8;
10475 *q = '\0';
10476 buf_utf8 = lptstr_to_utf8(buf);
10477 if(*buf == '*' || (buf_utf8 && fexist(buf_utf8, "x", (off_t *) NULL) == FIOSUC)){
10478 parm = p;
10479 if(buf_utf8)
10480 fs_give((void **) &buf_utf8);
10482 break;
10485 if(buf_utf8)
10486 fs_give((void **) &buf_utf8);
10488 else if(quoted && *p == '\"'){
10489 parm = p;
10490 break;
10492 else if(!(*q++ = *p++)){
10493 parm = p - 1;
10494 break;
10497 if(*command_lpt && parm){
10499 *parm++ = '\0';
10500 while(*parm && _istspace((unsigned char) *parm));
10504 * HACK -- since star is very unlikely to actually appear
10505 * in a command name thats launched via a shell command line,
10506 * a leading one indicates special handling.
10508 if(command_lpt[0] == '*'){
10509 if(!_tcsncmp(command_lpt + 1, TEXT("Shell*"), 8)){
10510 /* Leave it to ShellExecute magic to "open" the thing */
10511 command_lpt = parm;
10512 parm = NULL;
10516 else{
10517 if(free_command_lpt)
10518 fs_give((void **) &free_command_lpt);
10520 return(-1);
10523 memset(&shell_info, 0, sizeof(SHELLEXECUTEINFO));
10524 shell_info.cbSize = sizeof(SHELLEXECUTEINFO);
10525 shell_info.fMask = SEE_MASK_DOENVSUBST
10526 | SEE_MASK_NOCLOSEPROCESS
10527 | SEE_MASK_FLAG_DDEWAIT;
10528 shell_info.hwnd = ghTTYWnd;
10529 shell_info.lpFile = command_lpt;
10530 shell_info.lpParameters = parm;
10531 shell_info.lpDirectory = NULL; /* default is current directory */
10532 shell_info.nShow = SW_SHOWNORMAL;
10534 ShellExecuteEx(&shell_info);
10536 if((int)(LONG_PTR)shell_info.hInstApp > 32){
10537 if(pChildProc)
10538 *pChildProc = shell_info.hProcess;
10540 if(free_command_lpt)
10541 fs_give((void **) &free_command_lpt);
10543 return(0); /* success! */
10546 if(free_command_lpt)
10547 fs_give((void **) &free_command_lpt);
10549 return(-1);
10554 * Generate an error message for a failed windows exec or loadlibrary.
10556 void
10557 mswin_exec_err_msg(char *what, int status, char *buf, size_t buflen)
10559 switch(status){
10560 case 2:
10561 case 3:
10562 snprintf(buf, buflen, "%s not found.", what);
10563 break;
10565 case 8:
10566 snprintf(buf, buflen, "Not enough memory to run %s.", what);
10567 break;
10569 default:
10570 snprintf(buf, buflen, "Error %d starting %s.", status, what);
10571 break;
10577 mswin_set_quit_confirm (int confirm)
10579 gConfirmExit = (confirm != 0);
10580 return (confirm);
10585 * Called when Windows is in shutting down. Before actually shutting down
10586 * Windows goes around to all the applications and asks if it is OK with
10587 * them to shut down (WM_QUERYENDSESSION).
10588 * If gConfirmExit is set, ask the user if they want to exit.
10589 * Returning zero will stop the shutdown, non-zero allows it to proceed.
10591 LOCAL LRESULT
10592 ConfirmExit (void)
10594 TCHAR msg[256];
10595 int rc;
10597 if(gConfirmExit){
10598 _sntprintf(msg, sizeof(msg)/sizeof(TCHAR),
10599 TEXT("Exiting may cause you to lose work in %s, Exit?"),
10600 gszAppName);
10601 rc = MessageBox (ghTTYWnd, msg, gszAppName, MB_ICONSTOP | MB_OKCANCEL);
10602 if(rc == IDCANCEL)
10603 return(0);
10606 return(1);
10610 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10612 * Registry access functions
10614 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10617 * Useful def's
10619 #define MSWR_KEY_MAX 128
10620 #define MSWR_VAL_MAX 128
10621 #define MSWR_CLASS_MAX 128
10622 #define MSWR_DATA_MAX 1024
10625 #define MSWR_ROOT TEXT("Software\\University of Washington\\Alpine\\1.0")
10626 #define MSWR_CAPABILITIES TEXT("Software\\University of Washington\\Alpine\\1.0\\Capabilities")
10627 #define MSWR_APPNAME TEXT("Alpine")
10628 #define MSWR_DLLPATH TEXT("DLLPath")
10629 #define MSWR_DLLNAME TEXT("pmapi32.dll")
10630 #define MSWRDBUF 1152
10633 struct mswin_reg_key {
10634 HKEY rhk; /* root key (HKEY_LOCAL_MACHINE, ...) */
10635 LPTSTR *knames; /* NULL terminated list of keys */
10638 LPTSTR mswin_pine_hklm_regs[] = {
10639 MSWR_ROOT,
10640 TEXT("Software\\Clients\\Mail\\Alpine"),
10641 TEXT("Software\\Clients\\News\\Alpine"),
10642 TEXT("Software\\Classes\\Alpine.Url.Mailto"),
10643 TEXT("Software\\Classes\\Alpine.Url.News"),
10644 TEXT("Software\\Classes\\Alpine.Url.Nntp"),
10645 TEXT("Software\\Classes\\Alpine.Url.Imap"),
10646 NULL
10649 LPTSTR mswin_pine_hkcu_regs[] = {
10650 MSWR_ROOT,
10651 NULL
10654 static struct mswin_reg_key mswin_pine_regs[] = {
10655 {HKEY_LOCAL_MACHINE, mswin_pine_hklm_regs},
10656 {HKEY_CURRENT_USER, mswin_pine_hkcu_regs},
10657 {NULL, NULL}
10662 * data: unitialized buffer, could be null
10665 mswin_reg(int op, int tree, char *data_utf8, size_t size)
10667 LPTSTR data_lptstr = NULL;
10668 int rv;
10670 if(data_utf8){
10671 if(size == 0){
10672 /* size is zero when op & MSWR_OP_SET */
10673 data_lptstr = utf8_to_lptstr(data_utf8);
10675 else {
10676 data_lptstr = (LPTSTR)MemAlloc(size * sizeof(TCHAR));
10677 data_lptstr[0] = '\0';
10681 rv = mswin_reg_lptstr(op, tree, data_lptstr, size);
10683 if(data_utf8 && data_lptstr){
10684 char *t_utf8str;
10685 if(size){
10686 t_utf8str = lptstr_to_utf8(data_lptstr);
10687 strncpy(data_utf8, t_utf8str, size);
10688 data_utf8[size-1] = '\0';
10689 MemFree((void *)t_utf8str);
10691 MemFree((void *)data_lptstr);
10693 return(rv);
10697 mswin_reg_lptstr(int op, int tree, LPTSTR data_lptstr, size_t size)
10699 if(op & MSWR_OP_SET){
10700 switch(tree){
10701 case MSWR_PINE_RC :
10702 MSWRAlpineSet(HKEY_CURRENT_USER, NULL,
10703 TEXT("PineRC"), op & MSWR_OP_FORCE, data_lptstr);
10704 break;
10706 case MSWR_PINE_CONF :
10707 MSWRAlpineSet(HKEY_CURRENT_USER, NULL,
10708 TEXT("PineConf"), op & MSWR_OP_FORCE, data_lptstr);
10709 break;
10711 case MSWR_PINE_AUX :
10712 MSWRAlpineSet(HKEY_CURRENT_USER, NULL,
10713 TEXT("PineAux"), op & MSWR_OP_FORCE, data_lptstr);
10714 break;
10716 case MSWR_PINE_DIR :
10717 MSWRAlpineSet(HKEY_LOCAL_MACHINE, NULL,
10718 TEXT("Pinedir"), op & MSWR_OP_FORCE, data_lptstr);
10719 MSWRAlpineSetHandlers(op & MSWR_OP_FORCE, data_lptstr);
10720 break;
10722 case MSWR_PINE_EXE :
10723 MSWRAlpineSet(HKEY_LOCAL_MACHINE, NULL,
10724 TEXT("PineEXE"), op & MSWR_OP_FORCE, data_lptstr);
10725 break;
10727 case MSWR_PINE_POS :
10728 MSWRAlpineSet(HKEY_CURRENT_USER, NULL,
10729 TEXT("PinePos"), op & MSWR_OP_FORCE, data_lptstr);
10730 break;
10732 default :
10733 break;
10736 else if(op & MSWR_OP_GET){
10737 switch(tree){
10738 case MSWR_PINE_RC :
10739 return(MSWRAlpineGet(HKEY_CURRENT_USER, NULL,
10740 TEXT("PineRC"), data_lptstr, size));
10741 case MSWR_PINE_CONF :
10742 return(MSWRAlpineGet(HKEY_CURRENT_USER, NULL,
10743 TEXT("PineConf"), data_lptstr, size));
10744 case MSWR_PINE_AUX :
10745 return(MSWRAlpineGet(HKEY_CURRENT_USER, NULL,
10746 TEXT("PineAux"), data_lptstr, size));
10747 case MSWR_PINE_DIR :
10748 return(MSWRAlpineGet(HKEY_LOCAL_MACHINE, NULL,
10749 TEXT("Pinedir"), data_lptstr, size));
10750 case MSWR_PINE_EXE :
10751 return(MSWRAlpineGet(HKEY_LOCAL_MACHINE, NULL,
10752 TEXT("PineEXE"), data_lptstr, size));
10753 case MSWR_PINE_POS :
10754 return(MSWRAlpineGet(HKEY_CURRENT_USER, NULL,
10755 TEXT("PinePos"), data_lptstr, size));
10756 default :
10757 break;
10760 else if(op & MSWR_OP_BLAST){
10761 int rv = 0, i, j;
10763 for(i = 0; mswin_pine_regs[i].rhk; i++){
10764 for(j = 0; mswin_pine_regs[i].knames[j]; j++)
10765 MSWRClear(mswin_pine_regs[i].rhk, mswin_pine_regs[i].knames[j]);
10767 if(rv) return -1;
10769 /* else, ignore unknown op? */
10771 return(0);
10775 LOCAL void
10776 MSWRAlpineSet(HKEY hRootKey, LPTSTR subkey, LPTSTR val, int update, LPTSTR data)
10778 HKEY hKey;
10779 TCHAR keybuf[MSWR_KEY_MAX+1];
10781 _sntprintf(keybuf, MSWR_KEY_MAX+1, TEXT("%s%s%s"), MSWR_ROOT,
10782 (subkey && *subkey != '\\') ? TEXT("\\") : TEXT(""),
10783 (subkey) ? TEXT("\\") : TEXT(""));
10785 if(RegCreateKeyEx(hRootKey, keybuf, 0, TEXT("REG_SZ"),
10786 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10787 NULL, &hKey, NULL) == ERROR_SUCCESS){
10788 if(update || RegQueryValueEx(hKey, val, NULL, NULL,
10789 NULL, NULL) != ERROR_SUCCESS)
10790 RegSetValueEx(hKey, val, 0, REG_SZ, (LPBYTE)data, (DWORD)(_tcslen(data)+1)*sizeof(TCHAR));
10792 RegCloseKey(hKey);
10798 LOCAL int
10799 MSWRAlpineGet(HKEY hKey, LPTSTR subkey, LPTSTR val, LPTSTR data_lptstr, size_t len)
10801 TCHAR keybuf[MSWR_KEY_MAX+1];
10802 DWORD dlen = (DWORD)len;
10804 _sntprintf(keybuf, MSWR_KEY_MAX+1, TEXT("%s%s%s"), MSWR_ROOT,
10805 (subkey && *subkey != '\\') ? TEXT("\\") : TEXT(""),
10806 (subkey) ? TEXT("\\") : TEXT(""));
10808 return(MSWRPeek(hKey, keybuf, val, data_lptstr, &dlen) == TRUE);
10813 LOCAL void
10814 MSWRAlpineSetHandlers(int update, LPTSTR path_lptstr)
10816 HKEY hKey, hSubKey;
10817 DWORD dwDisp;
10818 BYTE tmp_b[MSWR_DATA_MAX];
10819 unsigned long tmplen = MSWR_DATA_MAX, tmp_lptstr_tcharlen = MSWR_DATA_MAX/sizeof(TCHAR);
10820 int exists;
10821 LPTSTR tmp_lptstr = (LPTSTR)tmp_b;
10823 /* Register as a mail client on this system */
10824 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
10825 MSWR_ROOT, 0, KEY_ALL_ACCESS,
10826 &hKey) == ERROR_SUCCESS){
10827 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, MSWR_CAPABILITIES, 0, TEXT("REG_SZ"),
10828 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10829 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10830 MSWRPoke(hSubKey, NULL, TEXT("ApplicationDescription"),
10831 TEXT("Alpine - A program for sending, receiving, and filing email and news, whether stored locally or accessed over the network via IMAP, POP3, or NNTP. Alpine is the successor to Pine, and also is maintained by the University of Washington."));
10832 MSWRPoke(hSubKey, NULL, TEXT("ApplicationName"),
10833 TEXT("Alpine"));
10834 _sntprintf(tmp_lptstr, tmp_lptstr_tcharlen, TEXT("%salpine.exe,0"), path_lptstr);
10835 MSWRPoke(hSubKey, NULL, TEXT("ApplicationIcon"), tmp_lptstr);
10836 MSWRPoke(hSubKey, TEXT("UrlAssociations"), TEXT("mailto"), TEXT("Alpine.Url.Mailto"));
10837 MSWRPoke(hSubKey, TEXT("UrlAssociations"), TEXT("news"), TEXT("Alpine.Url.News"));
10838 MSWRPoke(hSubKey, TEXT("UrlAssociations"), TEXT("nntp"), TEXT("Alpine.Url.Nntp"));
10839 MSWRPoke(hSubKey, TEXT("UrlAssociations"), TEXT("imap"), TEXT("Alpine.Url.Imap"));
10840 RegCloseKey(hSubKey);
10842 RegCloseKey(hKey);
10843 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\RegisteredApplications"), 0,
10844 KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){
10845 MSWRPoke(hKey, NULL, TEXT("Alpine"), MSWR_CAPABILITIES);
10846 RegCloseKey(hKey);
10848 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
10849 TEXT("Software\\Classes"), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){
10850 if(RegCreateKeyEx(hKey, TEXT("Alpine.Url.Mailto"), 0, TEXT("REG_SZ"),
10851 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10852 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10853 MSWRProtocolSet(hSubKey, MSWR_SDC_MAIL, path_lptstr);
10854 RegCloseKey(hSubKey);
10856 if(RegCreateKeyEx(hKey, TEXT("Alpine.Url.Nntp"), 0, TEXT("REG_SZ"),
10857 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10858 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10859 MSWRProtocolSet(hSubKey, MSWR_SDC_NNTP, path_lptstr);
10860 RegCloseKey(hSubKey);
10862 if(RegCreateKeyEx(hKey, TEXT("Alpine.Url.News"), 0, TEXT("REG_SZ"),
10863 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10864 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10865 MSWRProtocolSet(hSubKey, MSWR_SDC_NEWS, path_lptstr);
10866 RegCloseKey(hSubKey);
10868 if(RegCreateKeyEx(hKey, TEXT("Alpine.Url.Imap"), 0, TEXT("REG_SZ"),
10869 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10870 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10871 MSWRProtocolSet(hSubKey, MSWR_SDC_IMAP, path_lptstr);
10872 RegCloseKey(hSubKey);
10874 RegCloseKey(hKey);
10878 if((exists = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
10879 TEXT("SOFTWARE\\Clients\\Mail\\Alpine"),
10880 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
10881 || RegCreateKeyEx(HKEY_LOCAL_MACHINE,
10882 TEXT("SOFTWARE\\Clients\\Mail\\Alpine"),
10883 0, TEXT("REG_SZ"),
10884 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10885 NULL, &hKey, &dwDisp) == ERROR_SUCCESS){
10886 if(update || !exists){
10887 DWORD dType;
10888 char *tmp_utf8str = NULL;
10890 MSWRPoke(hKey, NULL, NULL, MSWR_APPNAME);
10891 /* set up MAPI dll stuff */
10892 *tmp_b = 0;
10893 RegQueryValueEx(hKey, MSWR_DLLPATH, NULL, &dType, tmp_b, &tmplen);
10894 tmp_lptstr = (LPTSTR)tmp_b;
10895 if(!(*tmp_lptstr)
10896 || (can_access(tmp_utf8str = lptstr_to_utf8(tmp_lptstr), ACCESS_EXISTS) != 0)){
10897 if(*tmp_lptstr)
10898 RegDeleteValue(hKey, MSWR_DLLPATH);
10899 if(tmp_utf8str)
10900 MemFree((void *)tmp_utf8str);
10902 _sntprintf(tmp_lptstr, tmp_lptstr_tcharlen,
10903 TEXT("%s%s"), path_lptstr, MSWR_DLLNAME);
10905 if(can_access(tmp_utf8str = lptstr_to_utf8(tmp_lptstr), ACCESS_EXISTS) == 0)
10906 MSWRPoke(hKey, NULL, MSWR_DLLPATH, tmp_lptstr);
10908 if(tmp_utf8str)
10909 MemFree((void *)tmp_utf8str);
10910 /* Set "mailto" handler */
10911 if(RegCreateKeyEx(hKey, TEXT("Protocols\\Mailto"), 0, TEXT("REG_SZ"),
10912 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10913 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10914 MSWRProtocolSet(hSubKey, MSWR_SDC_MAIL, path_lptstr);
10915 RegCloseKey(hSubKey);
10918 /* Set normal handler */
10919 _sntprintf(tmp_lptstr, tmp_lptstr_tcharlen,
10920 TEXT("\"%salpine.exe\""), path_lptstr);
10921 MSWRPoke(hKey, TEXT("shell\\open\\command"), NULL, tmp_lptstr);
10924 RegCloseKey(hKey);
10927 /* Register as a news client on this system */
10928 if((exists = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
10929 TEXT("SOFTWARE\\Clients\\News\\Alpine"),
10930 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
10931 || RegCreateKeyEx(HKEY_LOCAL_MACHINE,
10932 TEXT("SOFTWARE\\Clients\\News\\Alpine"),
10933 0, TEXT("REG_SZ"), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10934 NULL, &hKey, &dwDisp) == ERROR_SUCCESS){
10935 if(update || !exists){
10936 MSWRPoke(hKey, NULL, NULL, MSWR_APPNAME);
10938 /* Set "news" handler */
10939 if(RegCreateKeyEx(hKey, TEXT("Protocols\\news"), 0, TEXT("REG_SZ"),
10940 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10941 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10942 MSWRProtocolSet(hSubKey, MSWR_SDC_NEWS, path_lptstr);
10943 RegCloseKey(hSubKey);
10945 /* Set "nntp" handler */
10946 if(RegCreateKeyEx(hKey, TEXT("Protocols\\nntp"), 0, TEXT("REG_SZ"),
10947 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10948 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10949 MSWRProtocolSet(hSubKey, MSWR_SDC_NNTP, path_lptstr);
10950 RegCloseKey(hSubKey);
10953 /* Set normal handler */
10954 _sntprintf(tmp_lptstr, tmp_lptstr_tcharlen,
10955 TEXT("\"%salpine.exe\""), path_lptstr);
10956 MSWRPoke(hKey, TEXT("shell\\open\\command"), NULL, tmp_lptstr);
10959 RegCloseKey(hKey);
10962 /* Register as a IMAP url handler */
10963 if((exists = RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("imap"),
10964 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
10965 || RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT("imap"), 0, TEXT("REG_SZ"),
10966 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10967 NULL, &hKey, &dwDisp) == ERROR_SUCCESS){
10968 if(update || !exists)
10969 MSWRProtocolSet(hKey, MSWR_SDC_IMAP, path_lptstr);
10971 RegCloseKey(hKey);
10977 char *
10978 mswin_reg_default_browser(char *url_utf8)
10980 TCHAR scheme[MSWR_KEY_MAX+1], *p;
10981 LPTSTR url_lptstr;
10982 char cmdbuf[MSWR_DATA_MAX], *cmd = NULL;
10984 url_lptstr = utf8_to_lptstr(url_utf8);
10986 if(url_lptstr && (p = _tcschr(url_lptstr, ':')) && p - url_lptstr < MSWR_KEY_MAX){
10987 _tcsncpy(scheme, url_lptstr, p - url_lptstr);
10988 scheme[p-url_lptstr] = '\0';
10990 if(MSWRShellCanOpen(scheme, cmdbuf, MSWR_DATA_MAX, 0)){
10991 size_t len;
10993 len = strlen(cmdbuf) + 2;
10994 cmd = (char *) fs_get((len+1) * sizeof(char));
10995 if(cmd){
10996 if(strchr(cmdbuf, '*'))
10997 snprintf(cmd, len+1, "\"%s\"", cmdbuf);
10998 else{
10999 strncpy(cmd, cmdbuf, len);
11000 cmd[len] = '\0';
11006 MemFree((void *)url_lptstr);
11008 return(cmd);
11013 mswin_is_def_client(int type)
11015 TCHAR buf[MSWR_KEY_MAX+1];
11016 DWORD buflen = MSWR_KEY_MAX;
11018 if(type != MSWR_SDC_MAIL && type != MSWR_SDC_NEWS)
11019 return -1;
11021 if(MSWRPeek(HKEY_CURRENT_USER,
11022 type == MSWR_SDC_MAIL ? TEXT("Software\\Clients\\Mail")
11023 : TEXT("Software\\Clients\\News"), NULL,
11024 buf, &buflen) && !_tcscmp(buf, TEXT("Alpine")))
11025 return 1;
11026 buflen = MSWR_KEY_MAX;
11027 if(MSWRPeek(HKEY_LOCAL_MACHINE,
11028 type == MSWR_SDC_MAIL ? TEXT("Software\\Clients\\Mail")
11029 : TEXT("Software\\Clients\\News"), NULL,
11030 buf, &buflen) && !_tcscmp(buf, TEXT("Alpine")))
11031 return 1;
11032 return 0;
11036 mswin_set_def_client(int type)
11038 HKEY hKey;
11039 int successful_set = 0;
11040 TCHAR path_lptstr[MSWR_DATA_MAX];
11041 DWORD dwDisp;
11043 if(type != MSWR_SDC_MAIL && type != MSWR_SDC_NEWS)
11044 return 1;
11045 if(RegOpenKeyEx(HKEY_CURRENT_USER,
11046 type == MSWR_SDC_MAIL ? TEXT("Software\\Clients\\Mail")
11047 : TEXT("Software\\Clients\\News"),
11048 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){
11049 successful_set = MSWRPoke(hKey, NULL, NULL, TEXT("Alpine"));
11050 RegCloseKey(hKey);
11052 else if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
11053 type == MSWR_SDC_MAIL ? TEXT("Software\\Clients\\Mail")
11054 : TEXT("Software\\Clients\\News"),
11055 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){
11056 successful_set = MSWRPoke(hKey, NULL, NULL, TEXT("Alpine"));
11057 RegCloseKey(hKey);
11059 if(successful_set){
11060 mswin_reg_lptstr(MSWR_OP_GET, MSWR_PINE_DIR, path_lptstr, sizeof(path_lptstr)/sizeof(TCHAR));
11061 if(type == MSWR_SDC_MAIL){
11062 MSWRClear(HKEY_CLASSES_ROOT, TEXT("mailto"));
11063 if(RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT("mailto"), 0, TEXT("REG_SZ"),
11064 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
11065 NULL, &hKey, &dwDisp) == ERROR_SUCCESS){
11066 MSWRProtocolSet(hKey, MSWR_SDC_MAIL, path_lptstr);
11067 RegCloseKey(hKey);
11070 else if(type == MSWR_SDC_NEWS){
11071 MSWRClear(HKEY_CLASSES_ROOT, TEXT("news"));
11072 if(RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT("news"), 0, TEXT("REG_SZ"),
11073 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
11074 NULL, &hKey, &dwDisp) == ERROR_SUCCESS){
11075 MSWRProtocolSet(hKey, MSWR_SDC_NEWS, path_lptstr);
11076 RegCloseKey(hKey);
11078 MSWRClear(HKEY_CLASSES_ROOT, TEXT("nntp"));
11079 if(RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT("nntp"), 0, TEXT("REG_SZ"),
11080 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
11081 NULL, &hKey, &dwDisp) == ERROR_SUCCESS){
11082 MSWRProtocolSet(hKey, MSWR_SDC_NNTP, path_lptstr);
11083 RegCloseKey(hKey);
11087 return 0;
11091 MSWRProtocolSet(HKEY hKey, int type, LPTSTR path_lptstr)
11093 TCHAR tmp_lptstr[MSWR_DATA_MAX];
11094 BYTE EditFlags[4];
11095 unsigned long tmp_lptstr_len = MSWR_DATA_MAX;
11097 if(type != MSWR_SDC_MAIL && type != MSWR_SDC_NEWS
11098 && type != MSWR_SDC_NNTP && type != MSWR_SDC_IMAP)
11099 return -1;
11100 MSWRPoke(hKey, NULL, NULL, type == MSWR_SDC_MAIL
11101 ? TEXT("URL:MailTo Protocol")
11102 : type == MSWR_SDC_NEWS ? TEXT("URL:News Protocol")
11103 : type == MSWR_SDC_NNTP ? TEXT("URL:NNTP Protocol")
11104 : TEXT("URL:IMAP Prototcol"));
11105 MSWRPoke(hKey, NULL, TEXT("URL Protocol"), TEXT(""));
11107 EditFlags[0] = 0x02;
11108 EditFlags[1] = EditFlags[2] = EditFlags[3] = 0;
11110 (void) RegDeleteValue(hKey, TEXT("EditFlags"));
11111 (void) RegSetValueEx(hKey, TEXT("EditFlags"), 0, REG_BINARY,
11112 EditFlags, (DWORD) 4);
11114 _sntprintf(tmp_lptstr, tmp_lptstr_len,
11115 TEXT("%salpine.exe,0"), path_lptstr);
11116 MSWRPoke(hKey, TEXT("DefaultIcon"), NULL, tmp_lptstr);
11118 _sntprintf(tmp_lptstr, tmp_lptstr_len,
11119 TEXT("\"%salpine.exe\" -url \"%%1\""), path_lptstr);
11120 MSWRPoke(hKey, TEXT("shell\\open\\command"), NULL, tmp_lptstr);
11121 return 0;
11125 /* cmdbuf can stay char * since it's our string */
11126 BOOL
11127 MSWRShellCanOpen(LPTSTR key, char *cmdbuf, int clen, int allow_noreg)
11129 HKEY hKey;
11130 BOOL rv = FALSE;
11132 /* See if Shell provides a method to open the thing... */
11133 if(RegOpenKeyEx(HKEY_CLASSES_ROOT, key,
11134 0, KEY_READ, &hKey) == ERROR_SUCCESS){
11136 if(cmdbuf){
11137 strncpy(cmdbuf, "*Shell*", clen);
11138 cmdbuf[clen-1] = '\0';
11141 rv = TRUE;
11143 RegCloseKey(hKey);
11145 else if(allow_noreg && cmdbuf){
11146 strncpy(cmdbuf, "*Shell*", clen);
11147 cmdbuf[clen-1] = '\0';
11148 rv = TRUE;
11151 return(rv);
11156 * Fundamental registry access function that queries for particular values.
11158 LOCAL BOOL
11159 MSWRPeek(HKEY hRootKey, LPTSTR subkey, LPTSTR valstr, LPTSTR data_lptstr, DWORD *dlen)
11161 HKEY hKey;
11162 DWORD dtype, dlen_bytes = (dlen ? *dlen : 0) * sizeof(TCHAR);
11163 LONG rv = !ERROR_SUCCESS;
11165 if(RegOpenKeyEx(hRootKey, subkey, 0, KEY_READ, &hKey) == ERROR_SUCCESS){
11166 rv = RegQueryValueEx(hKey, valstr, NULL, &dtype, (LPBYTE)data_lptstr, &dlen_bytes);
11167 if(dlen)
11168 (*dlen) = dlen_bytes;
11169 RegCloseKey(hKey);
11172 return(rv == ERROR_SUCCESS);
11177 * Fundamental registry access function that sets particular values.
11179 LOCAL BOOL
11180 MSWRPoke(HKEY hKey, LPTSTR subkey, LPTSTR valstr, LPTSTR data_lptstr)
11182 DWORD dtype, dwDisp, dlen = MSWR_DATA_MAX;
11183 BYTE olddata[MSWR_DATA_MAX];
11184 BOOL rv = FALSE;
11186 if(!subkey
11187 || RegCreateKeyEx(hKey, subkey,
11188 0, TEXT("REG_SZ"), REG_OPTION_NON_VOLATILE,
11189 KEY_ALL_ACCESS, NULL,
11190 &hKey, &dwDisp) == ERROR_SUCCESS){
11192 if(RegQueryValueEx(hKey, valstr, NULL, &dtype,
11193 olddata, &dlen) != ERROR_SUCCESS
11194 || _tcscmp((LPTSTR)olddata, data_lptstr)){
11195 (void) RegDeleteValue(hKey, valstr);
11196 rv = RegSetValueEx(hKey, valstr, 0, REG_SZ,
11197 (LPBYTE)data_lptstr,
11198 (DWORD)(_tcslen(data_lptstr) + 1)*sizeof(TCHAR)) == ERROR_SUCCESS;
11201 if(subkey)
11202 RegCloseKey(hKey);
11205 return(rv);
11209 LOCAL void
11210 MSWRLineBufAdd(MSWR_LINE_BUFFER_S *lpLineBuf, LPTSTR line)
11212 if(lpLineBuf->offset >= lpLineBuf->size){
11213 /* this probably won't happen, but just in case */
11214 lpLineBuf->size *= 2;
11215 lpLineBuf->linep = (char **)MemRealloc(lpLineBuf->linep,
11216 (lpLineBuf->size + 1)*sizeof(char *));
11219 lpLineBuf->linep[lpLineBuf->offset++] = lptstr_to_utf8(line);
11220 lpLineBuf->linep[lpLineBuf->offset] = NULL;
11224 * Dump all of the registry values from a list of keys into an array
11225 * of UTF8-formatted strings.
11227 char **
11228 mswin_reg_dump(void)
11230 MSWR_LINE_BUFFER_S lineBuf;
11231 unsigned long initial_size = 256;
11232 int i, j;
11234 lineBuf.linep = (char **)MemAlloc((initial_size+1)*sizeof(char *));
11235 lineBuf.size = initial_size;
11236 lineBuf.offset = 0;
11238 MSWRLineBufAdd(&lineBuf, TEXT("Registry values for Alpine:"));
11239 MSWRLineBufAdd(&lineBuf, TEXT(""));
11241 for(i = 0; mswin_pine_regs[i].rhk; i++){
11242 MSWRLineBufAdd(&lineBuf, mswin_pine_regs[i].rhk == HKEY_LOCAL_MACHINE
11243 ? TEXT("HKEY_LOCAL_MACHINE")
11244 : TEXT("HKEY_CURRENT_USER"));
11245 for(j = 0; mswin_pine_regs[i].knames[j]; j++)
11246 MSWRDump(mswin_pine_regs[i].rhk,
11247 mswin_pine_regs[i].knames[j],
11248 1, &lineBuf);
11251 return(lineBuf.linep);
11256 * Recursive function to crawl a registry hierarchy and print the contents.
11258 * Returns: 0
11260 LOCAL int
11261 MSWRDump(HKEY hKey, LPTSTR pSubKey, int keyDepth, MSWR_LINE_BUFFER_S *lpLineBuf)
11263 HKEY hSubKey;
11264 TCHAR KeyBuf[MSWR_KEY_MAX+1];
11265 TCHAR ValBuf[MSWR_VAL_MAX+1];
11266 BYTE DataBuf[MSWR_DATA_MAX+1];
11267 DWORD dwKeyIndex, dwKeyLen;
11268 DWORD dwValIndex, dwValLen, dwDataLen;
11269 DWORD dwType;
11270 FILETIME ftKeyTime;
11271 TCHAR new_buf[1024];
11272 unsigned int new_buf_len = 1024;
11273 int i, j, k, tab_width = 4;
11275 /* open the passed subkey */
11276 if(RegOpenKeyEx(hKey, pSubKey, 0,
11277 KEY_READ, &hSubKey) == ERROR_SUCCESS){
11279 /* print out key name here */
11280 for(i = 0, k = 0; i < keyDepth % 8; i++)
11281 for(j = 0; j < tab_width; j++)
11282 new_buf[k++] = ' ';
11283 _sntprintf(new_buf+k, new_buf_len - k, TEXT("%s"), pSubKey);
11284 new_buf[new_buf_len - 1] = '\0';
11285 MSWRLineBufAdd(lpLineBuf, new_buf);
11287 keyDepth++;
11289 /* Loop through the string values and print their data */
11290 for(dwValIndex = 0L, dwValLen = MSWR_VAL_MAX + 1, dwDataLen = MSWR_DATA_MAX + 1;
11291 RegEnumValue(hSubKey, dwValIndex, ValBuf, &dwValLen, NULL, &dwType,
11292 DataBuf, &dwDataLen) == ERROR_SUCCESS;
11293 dwValIndex++, dwValLen = MSWR_VAL_MAX + 1, dwDataLen = MSWR_DATA_MAX + 1){
11295 /* print out value here */
11296 for(i = 0, k = 0; i < keyDepth % 8; i++)
11297 for(j = 0; j < tab_width; j++)
11298 new_buf[k++] = ' ';
11299 _sntprintf(new_buf+k, new_buf_len - k,
11300 TEXT("%.*s = %.*s"),
11301 dwValLen ? dwValLen : 128,
11302 dwValLen ? ValBuf : TEXT("(Default)"),
11303 dwType == REG_SZ && dwDataLen ? dwDataLen/sizeof(TCHAR) : 128,
11304 (dwType == REG_SZ
11305 ? (dwDataLen ? (LPTSTR)DataBuf : TEXT("(No data)"))
11306 : TEXT("(Some non-string data)")));
11307 new_buf[new_buf_len - 1] = '\0';
11308 MSWRLineBufAdd(lpLineBuf, new_buf);
11311 /* Loop through the subkeys and recursively print their data */
11312 for(dwKeyIndex = 0L, dwKeyLen = MSWR_KEY_MAX + 1;
11313 RegEnumKeyEx(hSubKey, dwKeyIndex, KeyBuf, &dwKeyLen,
11314 NULL, NULL, NULL, &ftKeyTime) == ERROR_SUCCESS;
11315 dwKeyIndex++, dwKeyLen = MSWR_KEY_MAX + 1){
11316 MSWRDump(hSubKey, KeyBuf, keyDepth, lpLineBuf);
11319 else {
11320 /* Couldn't open the key. Must not be defined. */
11321 for(i = 0, k = 0; i < keyDepth % 8; i++)
11322 for(j = 0; j < tab_width; j++)
11323 new_buf[k++] = ' ';
11324 _sntprintf(new_buf+k, new_buf_len - k, TEXT("%s - Not Defined"), pSubKey);
11325 new_buf[new_buf_len - 1] = '\0';
11326 MSWRLineBufAdd(lpLineBuf, new_buf);
11329 return 0;
11334 * Fundamental registry access function that removes a registry key
11335 * and all its subkeys, their values and data
11337 LOCAL int
11338 MSWRClear(HKEY hKey, LPTSTR pSubKey)
11340 HKEY hSubKey;
11341 TCHAR KeyBuf[MSWR_KEY_MAX+1];
11342 DWORD dwKeyIndex, dwKeyLen;
11343 FILETIME ftKeyTime;
11344 int rv = 0;
11346 if(RegOpenKeyEx(hKey, pSubKey, 0,
11347 KEY_READ, &hSubKey) == ERROR_SUCCESS){
11348 RegCloseKey(hSubKey);
11349 if(RegOpenKeyEx(hKey, pSubKey, 0,
11350 KEY_ALL_ACCESS, &hSubKey) == ERROR_SUCCESS){
11351 for(dwKeyIndex = 0L, dwKeyLen = MSWR_KEY_MAX + 1;
11352 RegEnumKeyEx(hSubKey, dwKeyIndex, KeyBuf, &dwKeyLen,
11353 NULL, NULL, NULL, &ftKeyTime) == ERROR_SUCCESS;
11354 dwKeyLen = MSWR_KEY_MAX + 1)
11355 if(MSWRClear(hSubKey, KeyBuf)!= 0){
11356 rv = -1;
11357 dwKeyIndex++;
11359 RegCloseKey(hSubKey);
11360 if(RegDeleteKey(hKey, pSubKey) != ERROR_SUCCESS || rv)
11361 return -1;
11362 return 0;
11364 return -1;
11366 return 0;
11370 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11372 * Text display Windows.
11374 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
11377 * Show a help message.
11378 * Help text comes as a null terminated array of pointers to lines of
11379 * text. Stuff these into a buffer and pass that to MessageBox.
11381 void
11382 mswin_showhelpmsg(WINHAND wnd, char **helplines)
11384 char **l;
11385 char *helptext_utf8, *p;
11386 size_t buflen;
11387 HWND hWnd;
11388 LPTSTR helptext_lpt;
11390 hWnd = (HWND) wnd;
11391 if(hWnd == NULL)
11392 hWnd = ghTTYWnd;
11394 buflen = 0;
11395 for(l = helplines; *l != NULL; ++l)
11396 buflen += (strlen(*l)+1);
11398 helptext_utf8 = (char *) fs_get((buflen + 1) * sizeof(char));
11399 if(helptext_utf8 == NULL)
11400 return;
11402 *helptext_utf8 = '\0';
11404 p = helptext_utf8;
11405 for(l = helplines; *l != NULL; ++l){
11406 snprintf(p, buflen+1-(p-helptext_utf8), "%s%s", (p == helptext_utf8) ? "" : " ", *l);
11407 p += strlen(p);
11410 helptext_lpt = utf8_to_lptstr(helptext_utf8);
11412 MessageBox(hWnd, helptext_lpt, TEXT("Help"),
11413 MB_APPLMODAL | MB_ICONINFORMATION | MB_OK);
11415 fs_give((void **) &helptext_utf8);
11416 fs_give((void **) &helptext_lpt);
11420 * Callback for when new mail or imap telem window gets canned.
11422 LOCAL void
11423 mswin_tw_close_imap_telem_or_new_mail(MSWIN_TEXTWINDOW *mswin_tw)
11425 HMENU hMenu;
11427 if((mswin_tw->id == IDM_OPT_IMAPTELEM) && gIMAPDebugOFFCallback)
11428 (*gIMAPDebugOFFCallback)();
11430 if(hMenu = GetMenu(ghTTYWnd))
11431 CheckMenuItem (hMenu, mswin_tw->id, MF_BYCOMMAND | MF_UNCHECKED);
11435 * Callback for when new mail or imap telem window gets cleared.
11437 LOCAL void
11438 mswin_tw_clear_imap_telem_or_new_mail(MSWIN_TEXTWINDOW *mswin_tw)
11440 char *tmtxt;
11441 time_t now = time((time_t *)0);
11442 LPCTSTR desc = (mswin_tw->id == IDM_OPT_IMAPTELEM) ?
11443 TEXT("IMAP telemetry recorder") :
11444 TEXT("New Mail window");
11446 tmtxt = ctime(&now);
11448 mswin_tw_printf(mswin_tw, TEXT("%s started at %.*S"),
11449 desc, MIN(100, strlen(tmtxt)-1), tmtxt);
11451 if(mswin_tw->id == IDM_OPT_NEWMAILWIN)
11453 int i;
11454 int fromlen, subjlen, foldlen, len;
11455 TCHAR ring2[256];
11457 foldlen = (int)(.18 * gNMW_width);
11458 foldlen = foldlen > 5 ? foldlen : 5;
11459 fromlen = (int)(.28 * gNMW_width);
11460 subjlen = gNMW_width - 2 - foldlen - fromlen;
11462 mswin_tw_printf(mswin_tw,
11463 TEXT(" %-*s%-*s%-*s"),
11464 fromlen, TEXT("From:"),
11465 subjlen, TEXT("Subject:"),
11466 foldlen, TEXT("Folder:"));
11468 len = 2 + fromlen + subjlen + foldlen;
11469 if(len >= ARRAYSIZE(ring2) + 1)
11470 len = ARRAYSIZE(ring2) - 2;
11471 for(i = 0; i < len; i++)
11472 ring2[i] = '-';
11473 ring2[i] = '\0';
11474 mswin_tw_puts_lptstr(mswin_tw, ring2);
11479 * Init new mail or imap telem window
11481 LOCAL int
11482 mswin_tw_init(MSWIN_TEXTWINDOW *mswin_tw, int id, LPCTSTR title)
11484 if(mswin_tw->hwnd){
11485 /* destroy it */
11486 mswin_tw_close(mswin_tw);
11488 else{
11489 HMENU hMenu;
11491 mswin_tw->id = id;
11492 mswin_tw->hInstance = ghInstance;
11493 mswin_tw->print_callback = mswin_tw_print_callback;
11494 mswin_tw->close_callback = mswin_tw_close_imap_telem_or_new_mail;
11495 mswin_tw->clear_callback = mswin_tw_clear_imap_telem_or_new_mail;
11497 // If the rcSize rect is empty, then init it to something resembling
11498 // the size of the current Pine window. Otherwise we just re-use
11499 // whatever the last position/size was.
11500 if(IsRectEmpty(&mswin_tw->rcSize))
11502 RECT cliRect;
11503 RECT sizeRect;
11505 GetClientRect(ghTTYWnd, &cliRect);
11506 sizeRect.left = CW_USEDEFAULT;
11507 sizeRect.top = CW_USEDEFAULT;
11508 sizeRect.right = cliRect.right;
11509 sizeRect.bottom = cliRect.bottom;
11510 mswin_tw->rcSize = sizeRect;
11513 if(!mswin_tw_create(mswin_tw, title))
11514 return 1;
11516 mswin_tw_setfont(mswin_tw, gpTTYInfo->hTTYFont);
11517 mswin_tw_setcolor(mswin_tw, gpTTYInfo->rgbFGColor, gpTTYInfo->rgbBGColor);
11519 mswin_tw_clear(mswin_tw);
11521 if(id == IDM_OPT_IMAPTELEM)
11523 if(gIMAPDebugONCallback)
11524 (*gIMAPDebugONCallback)();
11526 mswin_tw_showwindow(mswin_tw, SW_SHOWNA);
11528 else if(id == IDM_OPT_NEWMAILWIN){
11529 mswin_tw_showwindow(mswin_tw, SW_SHOW);
11532 if(hMenu = GetMenu(ghTTYWnd))
11533 CheckMenuItem (hMenu, mswin_tw->id, MF_BYCOMMAND | MF_CHECKED);
11536 return(0);
11540 * Display text in a window.
11542 * Parameters:
11543 * title - Title of window.
11544 * pText - address of text to display.
11545 * textLen - Length of text, in bytes. Limited to 64K.
11546 * pLines - Array of pointers to lines of text. Each
11547 * line is a sepreate allocation block. The
11548 * entry in the array of pointers should be a
11549 * NULL.
11551 * The text can be supplied as a buffer (pText and textLen) in which
11552 * lines are terminated by CRLF (including the last line in buffer).
11553 * This buffer should be NULL terminated, too.
11554 * Or it can be supplied as a NULL terminated array of pointers to
11555 * lines. Each entry points to a separately allocated memory block
11556 * containing a null terminated string.
11558 * If the function succeeds the memory containing the text will be
11559 * used until the user closes the window, at which point it will be
11560 * freed.
11562 * Returns:
11563 * mswin_tw - SUCCESS
11564 * NULL - Failed.
11566 MSWIN_TEXTWINDOW *
11567 mswin_displaytext(char *title_utf8, char *pText_utf8, size_t npText,
11568 char **pLines_utf8, MSWIN_TEXTWINDOW *mswin_tw, int flags)
11570 LPTSTR title_lpt = NULL, pText_lpt = NULL, *pLines_lpt = NULL;
11571 char **l;
11572 size_t pText_lpt_len = 0;
11573 int i, count = 0;
11575 if(pLines_utf8 != NULL){
11576 for(count=0, l = pLines_utf8; *l != NULL; ++l)
11577 ++count;
11579 pLines_lpt = (LPTSTR *) fs_get((count + 1) * sizeof(LPTSTR));
11580 memset(pLines_lpt, 0, (count + 1) * sizeof(LPTSTR));
11581 for(i=0, l = pLines_utf8; *l != NULL && i < count; ++l, ++i)
11582 pLines_lpt[i] = utf8_to_lptstr(*l);
11584 /*caller expects this to be freed */
11585 if(!(flags & MSWIN_DT_NODELETE)){
11586 for(l = pLines_utf8; *l != NULL; ++l)
11587 fs_give((void **) l);
11589 fs_give((void **) &pLines_utf8);
11593 if(pText_utf8 != NULL && npText > 0){
11594 pText_lpt = utf8_to_lptstr(pText_utf8);
11595 pText_lpt_len = lstrlen(pText_lpt);
11597 /*caller expects this to be freed */
11598 if(!(flags & MSWIN_DT_NODELETE))
11599 fs_give((void **) &pText_utf8);
11602 if(title_utf8 != NULL)
11603 title_lpt = utf8_to_lptstr(title_utf8);
11605 mswin_tw = mswin_tw_displaytext_lptstr(title_lpt, pText_lpt, pText_lpt_len,
11606 pLines_lpt, mswin_tw, flags);
11608 if(pLines_lpt != NULL){
11609 for(i=0; i < count; ++i)
11610 if(pLines_lpt[i])
11611 fs_give((void **) &pLines_lpt[i]);
11613 fs_give((void **) &pLines_lpt);
11616 if(pText_lpt != NULL)
11617 fs_give((void **) &pText_lpt);
11619 if(title_lpt != NULL)
11620 fs_give((void **) &title_lpt);
11622 return(mswin_tw);
11626 * Callback for when a generic mswin_tw gets killed.
11628 LOCAL void
11629 mswin_tw_close_callback(MSWIN_TEXTWINDOW *mswin_tw)
11631 if(mswin_tw->id != -1)
11632 MemFree(mswin_tw);
11636 * Create a new mswin_tw window. If the MSWIN_DT_USEALTWINDOW flag is set,
11637 * then (re)use gMswinAltWin.
11639 LOCAL MSWIN_TEXTWINDOW *
11640 mswin_tw_displaytext_lptstr (LPTSTR title, LPTSTR pText, size_t textLen, LPTSTR *pLines,
11641 MSWIN_TEXTWINDOW *mswin_tw, int flags)
11643 if (pText == NULL && pLines == NULL)
11644 return (NULL);
11646 /* Was a valid existing window supplied? */
11647 if(!mswin_tw)
11649 int ctrl_down = GetKeyState(VK_CONTROL) < 0;
11651 if((flags & MSWIN_DT_USEALTWINDOW) && !ctrl_down)
11653 mswin_tw = &gMswinAltWin;
11654 mswin_tw->id = (UINT)-1; // Tell mswin_tw_close_callback not
11655 // to free this buffer.
11657 else
11659 mswin_tw = (MSWIN_TEXTWINDOW *)MemAlloc (sizeof (MSWIN_TEXTWINDOW));
11660 if(!mswin_tw)
11661 return NULL;
11663 memset(mswin_tw, 0, sizeof(MSWIN_TEXTWINDOW));
11664 mswin_tw->id = 0;
11667 mswin_tw->hInstance = ghInstance;
11668 mswin_tw->print_callback = mswin_tw_print_callback;
11669 mswin_tw->close_callback = mswin_tw_close_callback;
11670 mswin_tw->clear_callback = NULL;
11673 /* Create a new window. */
11674 if (!mswin_tw->hwnd) {
11676 if(IsRectEmpty(&mswin_tw->rcSize))
11678 RECT sizeRect;
11679 RECT cliRect;
11681 GetClientRect(ghTTYWnd, &cliRect);
11682 sizeRect.left = CW_USEDEFAULT;
11683 sizeRect.top = CW_USEDEFAULT;
11684 sizeRect.right = cliRect.right;
11685 sizeRect.bottom = cliRect.bottom;
11686 mswin_tw->rcSize = sizeRect;
11689 if(!mswin_tw_create(mswin_tw, title)) {
11690 MemFree (mswin_tw);
11691 return (NULL);
11694 mswin_tw_setfont(mswin_tw, gpTTYInfo->hTTYFont);
11695 mswin_tw_setcolor(mswin_tw, gpTTYInfo->rgbFGColor, gpTTYInfo->rgbBGColor);
11697 else {
11698 /* Invalidate whole window, change title, and move to top. */
11699 SetWindowText (mswin_tw->hwnd, title);
11700 SetWindowPos (mswin_tw->hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
11703 mswin_tw_clear(mswin_tw);
11706 * How was text supplied?
11708 if (pLines != NULL) {
11709 LPTSTR *l;
11711 /* Array of pointers to lines supplied. Count lines. */
11712 for (l = pLines; *l != NULL; ++l){
11713 mswin_tw_puts_lptstr(mswin_tw, *l);
11716 else {
11717 #ifdef ALTED_DOT
11718 if(flags & MSWIN_DT_FILLFROMFILE)
11719 mswin_tw_fill_from_file(mswin_tw, pText);
11720 else
11721 #endif /* ALTED_DOT */
11722 /* Pointer to block of text supplied. */
11723 mswin_tw_puts_lptstr(mswin_tw, pText);
11726 mswin_tw_setsel(mswin_tw, 0, 0);
11728 mswin_tw_showwindow(mswin_tw, SW_SHOW);
11729 return mswin_tw;
11732 void
11733 mswin_enableimaptelemetry(int state)
11735 HMENU hMenu;
11736 MENUITEMINFO mitem;
11737 TCHAR buf[256];
11738 int i;
11740 hMenu = GetMenu (ghTTYWnd);
11741 if (hMenu == NULL)
11742 return;
11745 * Make sure hMenu's the right menubar
11747 mitem.cbSize = sizeof(MENUITEMINFO);
11748 mitem.fMask = (MIIM_SUBMENU | MIIM_TYPE);
11749 mitem.fType = MFT_STRING;
11750 mitem.dwTypeData = buf;
11751 mitem.cch = 255;
11752 if(GetMenuItemCount(hMenu) == 7
11753 && GetMenuItemInfo(hMenu, 5, TRUE, &mitem)){
11754 if(mitem.fType == MFT_STRING
11755 && !_tcscmp(mitem.dwTypeData, TEXT("&Config")))
11756 hMenu = mitem.hSubMenu;
11757 else
11758 return;
11760 else
11761 return;
11763 i = GetMenuItemCount(hMenu);
11764 if(state == TRUE && i < 10){
11765 mitem.fMask = MIIM_TYPE;
11766 mitem.fType = MFT_SEPARATOR;
11767 InsertMenuItem (hMenu, 8, TRUE, &mitem);
11769 mitem.fMask = (MIIM_TYPE | MIIM_ID);
11770 mitem.fType = MFT_STRING;
11771 mitem.wID = IDM_OPT_IMAPTELEM;
11772 mitem.dwTypeData = TEXT("&IMAP Telemetry");
11773 mitem.cch = 15;
11774 InsertMenuItem (hMenu, 9, TRUE, &mitem);
11776 DrawMenuBar (ghTTYWnd);
11778 else if(state == FALSE && i == 10){
11779 DeleteMenu (hMenu, 8, MF_BYPOSITION);
11780 DeleteMenu (hMenu, IDM_OPT_IMAPTELEM, MF_BYCOMMAND);
11781 DrawMenuBar (ghTTYWnd);
11786 mswin_imaptelemetry(char *msg)
11788 if(gMswinIMAPTelem.hwnd){
11789 LPTSTR msg_lptstr;
11790 msg_lptstr = utf8_to_lptstr(msg);
11791 mswin_tw_puts_lptstr(&gMswinIMAPTelem, msg_lptstr);
11792 fs_give((void **) &msg_lptstr);
11793 return(1);
11795 return(0);
11800 * The newmail window has a format proportional to screen width.
11801 * At this point, we've figured out the sizes of the fields, now
11802 * we fill that field to it's desired column size. This used to
11803 * be a lot eaier when it was one char per column, but in the
11804 * unicode world it's not that easy. This code does make the
11805 * assumption that ASCII characters are 1 column.
11807 LPTSTR
11808 format_newmail_string(LPTSTR orig_lptstr, int format_len)
11810 LPTSTR new_lptstr;
11811 int i, colLen;
11813 new_lptstr = (LPTSTR)MemAlloc((format_len+1)*sizeof(TCHAR));
11816 * Fill up string till we reach the format_len, we can backtrack
11817 * if we need elipses.
11819 for(i = 0, colLen = 0;
11820 i < format_len && colLen < format_len && orig_lptstr && orig_lptstr[i];
11821 i++){
11822 new_lptstr[i] = orig_lptstr[i];
11823 colLen += wcellwidth(new_lptstr[i]);
11826 if(colLen > format_len || (colLen == format_len && orig_lptstr[i])){
11828 * If we hit the edge of the format and there's still stuff
11829 * to write, go back and add ".."
11831 i--;
11832 if(wcellwidth(new_lptstr[i]) > 1){
11833 colLen -= wcellwidth(new_lptstr[i]);
11835 else{
11836 colLen -= wcellwidth(new_lptstr[i]);
11837 i--;
11838 colLen -= wcellwidth(new_lptstr[i]);
11840 while(colLen < format_len && i < format_len){
11841 new_lptstr[i++] = '.';
11842 colLen++;
11845 else{
11847 * If we've hit the end of the string, add spaces until
11848 * we get to the correct length.
11850 for(; colLen < format_len && i < format_len; i++, colLen++){
11851 new_lptstr[i] = ' ';
11855 if(i <= format_len)
11856 new_lptstr[i] = '\0';
11857 else
11858 new_lptstr[format_len] = '\0';
11860 return(new_lptstr);
11864 * We're passed the relevant fields, now format them according to window with
11865 * and put up for display
11868 mswin_newmailwin(int is_us, char *from_utf8, char *subject_utf8, char *folder_utf8)
11870 TCHAR tcbuf[256];
11871 int foldlen, fromlen, subjlen;
11872 LPTSTR from_lptstr = NULL, subject_lptstr = NULL, folder_lptstr = NULL;
11873 LPTSTR from_format, subject_format, folder_format;
11875 if(!gMswinNewMailWin.hwnd)
11876 return 0;
11878 if(from_utf8)
11879 from_lptstr = utf8_to_lptstr(from_utf8);
11880 if(subject_utf8)
11881 subject_lptstr = utf8_to_lptstr(subject_utf8);
11882 if(folder_utf8)
11883 folder_lptstr = utf8_to_lptstr(folder_utf8);
11886 foldlen = (int)(.18 * gNMW_width);
11887 foldlen = foldlen > 5 ? foldlen : 5;
11888 fromlen = (int)(.28 * gNMW_width);
11889 subjlen = gNMW_width - 2 - foldlen - fromlen;
11892 from_format = format_newmail_string(from_lptstr
11893 ? from_lptstr : TEXT(""),
11894 fromlen - 1);
11895 subject_format = format_newmail_string(subject_lptstr
11896 ? subject_lptstr : TEXT("(no subject)"),
11897 subjlen - 1);
11898 folder_format = format_newmail_string(folder_lptstr
11899 ? folder_lptstr : TEXT("INBOX"),
11900 foldlen);
11902 _sntprintf(tcbuf, 256, TEXT("%c %s %s %s"), is_us ? '+' : ' ',
11903 from_format, subject_format, folder_format);
11905 if(from_lptstr)
11906 fs_give((void **) &from_lptstr);
11907 if(subject_lptstr)
11908 fs_give((void **) &subject_lptstr);
11909 if(folder_lptstr)
11910 fs_give((void **) &folder_lptstr);
11911 MemFree((void *)from_format);
11912 MemFree((void *)subject_format);
11913 MemFree((void *)folder_format);
11915 mswin_tw_puts_lptstr(&gMswinNewMailWin, tcbuf);
11916 return 1;
11920 * Mouse up, end selection
11923 LOCAL void
11924 mswin_tw_print_callback(MSWIN_TEXTWINDOW *mswin_tw)
11926 LPTSTR text;
11927 UINT text_len;
11928 int rc;
11929 #define DESC_LEN 180
11930 TCHAR description[DESC_LEN+1];
11932 GetWindowText(mswin_tw->hwnd, description, DESC_LEN);
11934 rc = mswin_print_ready((WINHAND)mswin_tw->hwnd, description);
11935 if (rc != 0) {
11936 if (rc != PE_USER_CANCEL) {
11937 LPTSTR e;
11939 e = utf8_to_lptstr(mswin_print_error(rc));
11940 if(e){
11941 _sntprintf(description, DESC_LEN+1, TEXT("Printing failed: %s"), e);
11942 fs_give((void **) &e);
11945 MessageBox(mswin_tw->hwnd, description, TEXT("Print Failed"),
11946 MB_OK | MB_ICONEXCLAMATION);
11948 return;
11951 text_len = mswin_tw_gettextlength(mswin_tw);
11952 text = (LPTSTR) fs_get(text_len * sizeof(TCHAR));
11953 mswin_tw_gettext(mswin_tw, text, text_len);
11954 mswin_print_text(text);
11955 fs_give((void **)&text);
11957 mswin_print_done();
11961 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11963 * Character Queue
11965 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
11968 typedef struct {
11969 BOOL fKeyControlDown;
11970 UCS c; /* Bigger than TCHAR for CTRL and MENU setting */
11971 } CQEntry;
11973 LOCAL CQEntry CQBuffer [CHARACTER_QUEUE_LENGTH];
11974 LOCAL int CQHead;
11975 LOCAL int CQTail;
11976 LOCAL int CQCount;
11979 /*---------------------------------------------------------------------------
11980 * BOOL CQInit ()
11982 * Description:
11983 * Initialize the Character queue.
11985 * Parameters:
11988 /*--------------------------------------------------------------------------*/
11989 LOCAL void
11990 CQInit (void)
11992 CQHead = 0;
11993 CQTail = 0;
11994 CQCount = 0;
11998 /*---------------------------------------------------------------------------
11999 * BOOL CQAvailable (void)
12001 * Description:
12002 * Return TRUE if there are characters in the queue.
12004 * Parameters:
12007 /*--------------------------------------------------------------------------*/
12009 LOCAL BOOL
12010 CQAvailable (void)
12012 return (CQCount > 0);
12017 /*---------------------------------------------------------------------------
12018 * BOOL CQAdd (WORD c, DWORC keyData)
12020 * Description:
12021 * Add 'c' to the end of the character queue.
12023 * Parameters:
12024 * return true if successfull.
12026 /*--------------------------------------------------------------------------*/
12028 LOCAL BOOL
12029 CQAdd (UCS c, BOOL fKeyControlDown)
12031 if (CQCount == CHARACTER_QUEUE_LENGTH)
12032 return (FALSE);
12034 CQBuffer[CQTail].fKeyControlDown = fKeyControlDown;
12035 CQBuffer[CQTail].c = c;
12036 CQTail = (CQTail + 1) % CHARACTER_QUEUE_LENGTH;
12037 ++CQCount;
12038 return (TRUE);
12043 /*---------------------------------------------------------------------------
12044 * BOOL CQAddUniq (WORD c, DWORC keyData)
12046 * Description:
12047 * Add 'c' to the end of the character queue, only if
12048 * there is no other 'c' in the queue
12050 * Parameters:
12051 * return true if successfull.
12053 /*--------------------------------------------------------------------------*/
12055 LOCAL BOOL
12056 CQAddUniq (UCS c, BOOL fKeyControlDown)
12058 int i;
12059 int pos;
12061 if (CQCount == CHARACTER_QUEUE_LENGTH)
12062 return (FALSE);
12064 pos = CQHead;
12065 for (i = 0; i < CQCount; ++i) {
12066 if (CQBuffer[pos].c == c)
12067 return (FALSE);
12068 pos = (pos + 1) % CHARACTER_QUEUE_LENGTH;
12070 return (CQAdd (c, fKeyControlDown));
12076 /*---------------------------------------------------------------------------
12077 * int CQGet ()
12079 * Description:
12080 * Return the next byte from the head of the queue. If there is
12081 * no byte available, returns 0, which is indistinquishable from
12082 * '\0'. So it is a good idea to call CQAvailable first.
12084 * Parameters:
12085 * none.
12087 /*--------------------------------------------------------------------------*/
12089 LOCAL UCS
12090 CQGet ()
12092 UCS c;
12094 if (CQCount == 0)
12095 return (0);
12097 c = CQBuffer[CQHead].c;
12099 if(CQBuffer[CQHead].fKeyControlDown)
12100 c |= CTRL;
12102 if(c < ' ') {
12103 c += '@';
12104 c |= CTRL;
12107 CQHead = (CQHead + 1) % CHARACTER_QUEUE_LENGTH;
12108 --CQCount;
12109 return (c);
12114 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12116 * Mouse Event Queue
12118 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
12122 LOCAL MEvent MQBuffer [MOUSE_QUEUE_LENGTH];
12123 LOCAL int MQHead;
12124 LOCAL int MQTail;
12125 LOCAL int MQCount;
12128 /*---------------------------------------------------------------------------
12129 * BOOL MQInit ()
12131 * Description:
12132 * Initialize the Character queue.
12134 * Parameters:
12137 /*--------------------------------------------------------------------------*/
12138 LOCAL void
12139 MQInit (void)
12141 MQHead = 0;
12142 MQTail = 0;
12143 MQCount = 0;
12147 /*---------------------------------------------------------------------------
12148 * BOOL MQAvailable (void)
12150 * Description:
12151 * Return TRUE if there are characters in the queue.
12153 * Parameters:
12156 /*--------------------------------------------------------------------------*/
12158 LOCAL BOOL
12159 MQAvailable (void)
12161 return (MQCount > 0);
12166 /*---------------------------------------------------------------------------
12167 * BOOL MQAdd ()
12169 * Description:
12170 * Add 'c' to the end of the character queue.
12172 * Parameters:
12173 * return true if successfull.
12175 /*--------------------------------------------------------------------------*/
12177 LOCAL BOOL
12178 MQAdd (int mevent, int button, int nRow, int nColumn, int keys, int flags)
12180 int c;
12181 int i = 0;
12182 BOOL found = FALSE;
12186 * Find a queue insertion point.
12188 if (flags & MSWIN_MF_REPLACING) {
12189 /* Search for same event on queue. */
12190 for ( i = MQHead, c = MQCount;
12191 c > 0;
12192 i = (i + 1) % MOUSE_QUEUE_LENGTH, --c) {
12193 if (MQBuffer[i].event == mevent) {
12194 found = TRUE;
12195 break;
12199 if (!found) {
12200 if (MQCount == MOUSE_QUEUE_LENGTH)
12201 return (FALSE);
12202 i = MQTail;
12203 MQTail = (MQTail + 1) % MOUSE_QUEUE_LENGTH;
12204 ++MQCount;
12209 * Record data.
12211 MQBuffer[i].event = mevent;
12212 MQBuffer[i].button = button;
12213 MQBuffer[i].nRow = nRow;
12214 MQBuffer[i].nColumn = nColumn;
12215 MQBuffer[i].keys = keys;
12216 MQBuffer[i].flags = flags;
12219 * Keep record of last mouse position.
12221 gMTEvent = MQBuffer[i];
12223 return (TRUE);
12230 /*---------------------------------------------------------------------------
12231 * BOOL MQGet ()
12233 * Description:
12234 * Return the next byte from the head of the queue. If there is
12235 * no byte available, returns 0, which is indistinquishable from
12236 * '\0'. So it is a good idea to call MQAvailable first.
12238 * Parameters:
12239 * none.
12241 /*--------------------------------------------------------------------------*/
12243 LOCAL BOOL
12244 MQGet (MEvent * pMouse)
12246 if (MQCount == 0)
12247 return (FALSE);
12250 *pMouse = MQBuffer[MQHead];
12251 MQHead = (MQHead + 1) % MOUSE_QUEUE_LENGTH;
12252 --MQCount;
12253 return (TRUE);
12261 DWORD
12262 ExplainSystemErr()
12264 DWORD status;
12265 void *lpMsgBuf = NULL;
12266 status = GetLastError();
12268 FormatMessage(
12269 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
12270 NULL,
12271 status,
12272 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
12273 (LPTSTR) &lpMsgBuf, 0, NULL);
12275 if(lpMsgBuf){
12276 char *msg;
12278 msg = lptstr_to_utf8(lpMsgBuf);
12279 if(msg){
12280 mswin_messagebox(msg, 1);
12281 fs_give((void **) &msg);
12284 LocalFree(lpMsgBuf);
12287 return(status);
12292 * Called by mswin to scroll text in window in responce to the scrollbar.
12294 * Args: cmd - what type of scroll operation.
12295 * scroll_pos - paramter for operation.
12296 * used as position for SCROLL_TO operation.
12298 * Returns: TRUE - did the scroll operation.
12299 * FALSE - was not able to do the scroll operation.
12302 pico_scroll_callback (int cmd, long scroll_pos)
12304 switch (cmd) {
12305 case MSWIN_KEY_SCROLLUPLINE:
12306 scrollupline (0, 1);
12307 break;
12309 case MSWIN_KEY_SCROLLDOWNLINE:
12310 scrolldownline (0, 1);
12311 break;
12313 case MSWIN_KEY_SCROLLUPPAGE:
12314 backpage (0, 1);
12315 break;
12317 case MSWIN_KEY_SCROLLDOWNPAGE:
12318 forwpage (0, 1);
12319 break;
12321 case MSWIN_KEY_SCROLLTO:
12322 scrollto (0, 0);
12323 break;
12326 update ();
12327 return (TRUE);
12331 * sleep the given number of seconds
12334 sleep(int t)
12336 time_t out = (time_t)t + time((long *) 0);
12337 while(out > time((long *) 0))
12339 return(0);
12343 tcsucmp(LPTSTR o, LPTSTR r)
12345 return(o ? (r ? _tcsicmp(o, r) : 1) : (r ? -1 : 0));
12349 tcsruncmp(LPTSTR o, LPTSTR r, int n)
12351 return(o ? (r ? _tcsnicmp(o, r, n) : 1) : (r ? -1 : 0));
12355 strucmp(char *o, char *r)
12357 return(o ? (r ? stricmp(o, r) : 1) : (r ? -1 : 0));
12362 struncmp(char *o, char *r, int n)
12364 return(o ? (r ? strnicmp(o, r, n) : 1) : (r ? -1 : 0));
12369 * Returns screen width of len characters of lpText.
12370 * The width is in character cells. That is, an ascii "A" has
12371 * width 1 but a CJK character probably has width 2.
12373 unsigned
12374 scrwidth(LPTSTR lpText, int len)
12376 UCS ubuf[1000];
12377 unsigned w;
12378 int i, thislen, offset;
12380 offset = w = 0;
12382 while(len > 0){
12383 thislen = MIN(len, 1000);
12384 for(i = 0; i < thislen; i++)
12385 ubuf[i] = lpText[offset+i];
12387 w += ucs4_str_width_ptr_to_ptr(&ubuf[0], &ubuf[thislen]);
12389 offset += thislen;
12390 len -= thislen;
12393 return w;
12398 * Returns the index into pScreen given the row,col location
12399 * on the screen, taking into account characters with widths
12400 * other than 1 cell.
12402 long
12403 pscreen_offset_from_cord(int row, int col, PTTYINFO pTTYInfo)
12405 int offset_due_to_row, offset_due_to_col, width;
12408 * Each row starts at a specific offset into pScreen.
12410 offset_due_to_row = row * pTTYInfo->actNColumn;
12413 * Start with col (all chars single width) and go from there.
12414 * We need to find the offset that makes the string col wide.
12415 * Hopefully we won't ever get a rectange that causes us to
12416 * draw half characters, but in case we do we need to err on the
12417 * side of too much width instead of not enough. It's a little
12418 * tricky because we want to include following zero-width
12419 * characters.
12420 * fewer characters it would be <= desired width, one more would
12421 * be greater than desired width, this one is >= desired width.
12424 /* first go to some offset where width is > col */
12425 offset_due_to_col = col;
12426 width = scrwidth(pTTYInfo->pScreen+offset_due_to_row, offset_due_to_col);
12427 while(width <= col && offset_due_to_col < pTTYInfo->actNColumn-1){
12428 offset_due_to_col++;
12429 width = scrwidth(pTTYInfo->pScreen+offset_due_to_row, offset_due_to_col);
12432 /* Now back up until width is no longer > col */
12433 while(width > col){
12434 offset_due_to_col--;
12435 width = scrwidth(pTTYInfo->pScreen+offset_due_to_row, offset_due_to_col);
12438 /* But, if we're now less than col, go forward one again. */
12439 if(width < col && offset_due_to_col < pTTYInfo->actNColumn-1)
12440 offset_due_to_col++;
12442 return(offset_due_to_row + offset_due_to_col);
12447 * Returns:
12448 * 1 if store pass prompt is set in the registry to on
12449 * 0 if set to off
12450 * -1 if not set to anything
12453 mswin_store_pass_prompt(void)
12456 * We shouldn't need to prompt anymore, but always return 1
12457 * just in case
12459 return(1);