* clear out some warnings by gcc 9.3.1.
[alpine.git] / pico / osdep / mswin.c
blob824ccd4cee76de0448e2d88c10a60a1a1f447de9
1 /*
2 * ========================================================================
3 * Copyright 2006-2007 University of Washington
4 * Copyright 2013-2020 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 timing. */
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 milliseconds. */
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 flagged with a preceding
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; /* Position of last scroll to. */
278 HFONT hTTYFont;
279 LOGFONT lfTTYFont;
280 DWORD rgbFGColor; /* Normal foreground color. */
281 DWORD rgbBGColor; /* Normal background color. */
282 DWORD rgbRFGColor; /* Reverse foreground 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 separate 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, otherwise 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, current 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 // There used to be an instruction to return when we were iconized:
1996 // if (IsIconic (hWnd))
1997 // return (TRUE);
1998 // We remove this, because when Windows wants to update the screen
1999 // and Alpine returns because the screen is iconized,, neither Windows
2000 // nor Alpine will stop their vicious infinite cycle: Windows trying to
2001 // force the update and Alpine avoiding it. We better yield because
2002 // otherwise we will end up with a high consumption of CPU.
2004 hDC = BeginPaint (hWnd, &ps);
2005 rect = ps.rcPaint;
2007 hOrigFont = SelectObject (hDC, pTTYInfo->hTTYFont);
2008 SetTextColor (hDC, pTTYInfo->rgbFGColor);
2009 SetBkColor (hDC, pTTYInfo->rgbBGColor);
2010 SetBkMode (hDC, OPAQUE);
2012 nRow = (rect.top - pTTYInfo->yOffset) / pTTYInfo->yChar;
2013 CONSTRAIN (nRow, 0, pTTYInfo->actNRow - 1);
2015 nEndRow = MIN(pTTYInfo->actNRow - 1,
2016 ((rect.bottom - pTTYInfo->yOffset - 1) / pTTYInfo->yChar));
2017 nCol = MIN(pTTYInfo->actNColumn - 1,
2018 MAX(0, (rect.left - pTTYInfo->xOffset) / pTTYInfo->xChar));
2019 nEndCol = MIN(pTTYInfo->actNColumn - 1,
2020 ((rect.right - pTTYInfo->xOffset - 1) / pTTYInfo->xChar));
2022 pLastAttrib = NULL;
2024 /* Erase screen if necessary. */
2025 if (pTTYInfo->eraseScreen) {
2026 erect.top = 0;
2027 erect.left = 0;
2028 erect.bottom = pTTYInfo->ySize;
2029 erect.right = pTTYInfo->xSize;
2030 hBrush = CreateSolidBrush (pTTYInfo->rgbBGColor);
2031 if (hBrush != NULL) {
2032 FillRect (hDC, &erect, hBrush);
2033 DeleteObject (hBrush);
2035 pTTYInfo->eraseScreen = FALSE;
2039 /* Paint an inset frame around the text region. */
2040 if (pTTYInfo->toolBarSize == 0) {
2041 erect.top = 0;
2042 erect.bottom = pTTYInfo->ySize;
2044 else if (pTTYInfo->toolBarTop) {
2045 erect.top = pTTYInfo->toolBarSize;
2046 erect.bottom = pTTYInfo->ySize;
2048 else {
2049 erect.top = 0;
2050 erect.bottom = pTTYInfo->ySize - pTTYInfo->toolBarSize;
2052 erect.left = 0;
2053 erect.right = pTTYInfo->xSize;
2054 FrameRect3D (hDC, &erect, FRAME_3D_SIZE, FALSE);
2056 /* Paint rows of text. */
2057 for (; nRow <= nEndRow; nRow++) {
2058 nVertPos = (nRow * pTTYInfo->yChar) + pTTYInfo->yOffset;
2059 rect.top = nVertPos;
2060 rect.bottom = nVertPos + pTTYInfo->yChar;
2062 /* Paint runs of similar attributes. */
2063 col = nCol; /* Start at left. */
2065 if(col == 0 && MSWIconPaint(nRow, hDC))
2066 col += 2;
2069 * col is the column on the screen, not the index
2070 * into the array.
2072 while (col <= nEndCol) { /* While not past right. */
2074 /* Starting with Character at nRow, col, what is its attribute? */
2076 /* offset is an index into the array */
2077 offset = pscreen_offset_from_cord(nRow, col, pTTYInfo);
2078 pNewAttrib = pTTYInfo->pAttrib + offset;
2080 hTmpFont = NULL;
2081 if (!(pLastAttrib
2082 && pNewAttrib->style == pLastAttrib->style
2083 && pNewAttrib->rgbFG == pLastAttrib->rgbFG
2084 && pNewAttrib->rgbBG == pLastAttrib->rgbBG)) {
2086 * Require new font?
2088 if(!pLastAttrib
2089 || (pNewAttrib->style & CHAR_ATTR_ULINE)
2090 != (pLastAttrib->style & CHAR_ATTR_ULINE)){
2091 if(pNewAttrib->style & CHAR_ATTR_ULINE){
2093 * Find suitable attribute font...
2095 memcpy (&tmpFont, &pTTYInfo->lfTTYFont,
2096 sizeof (LOGFONT));
2098 tmpFont.lfHeight = - pTTYInfo->yChar;
2099 tmpFont.lfWidth = - pTTYInfo->xChar;
2101 tmpFont.lfUnderline = (BYTE)((pNewAttrib->style
2102 & CHAR_ATTR_ULINE)
2103 == CHAR_ATTR_ULINE);
2105 hTmpFont = CreateFontIndirect (&tmpFont);
2107 hOldFont = SelectObject (hDC, hTmpFont);
2112 * Set new color attributes. If Reverse or Selected, then
2113 * show in reverse colors. But if neither, or both, then
2114 * normal colors.
2116 if(pNewAttrib->style & CHAR_ATTR_SEL){
2117 SetTextColor (hDC, pNewAttrib->rgbBG);
2118 SetBkColor (hDC, pNewAttrib->rgbFG);
2120 else {
2121 if(!(pLastAttrib
2122 && pNewAttrib->rgbFG == pLastAttrib->rgbFG)
2123 || (pLastAttrib->style & CHAR_ATTR_SEL))
2124 SetTextColor (hDC, pNewAttrib->rgbFG);
2126 if(!(pLastAttrib
2127 && pNewAttrib->rgbBG == pLastAttrib->rgbBG)
2128 || (pLastAttrib->style & CHAR_ATTR_SEL))
2129 SetBkColor (hDC, pNewAttrib->rgbBG);
2133 /* Find run of similar attributes. */
2134 count = 1;
2135 pAttrib = pTTYInfo->pAttrib + (offset + 1);
2136 /* endoffset is an index into the pScreen array */
2137 endoffset = pscreen_offset_from_cord(nRow, nEndCol, pTTYInfo);
2138 endCount = endoffset - offset;
2139 while (count <= endCount
2140 && pAttrib->style == pNewAttrib->style
2141 && pAttrib->rgbFG == pNewAttrib->rgbFG
2142 && pAttrib->rgbBG == pNewAttrib->rgbBG){
2143 ++pAttrib;
2144 ++count;
2147 if(hTmpFont != NULL){
2148 /* BUG: compute new offsets based on hTmpFont font if required */
2149 nHorzPos = (col * pTTYInfo->xChar) + pTTYInfo->xOffset;
2150 rect.left = nHorzPos;
2151 rect.right = nHorzPos + pTTYInfo->xChar * scrwidth(pTTYInfo->pScreen+offset, count);
2153 else{
2154 /* Paint run of characters from nRow, col to nRow, col + count
2155 * rect.top and rect.bottom have already been calculated. */
2156 nHorzPos = (col * pTTYInfo->xChar) + pTTYInfo->xOffset;
2157 rect.left = nHorzPos;
2158 rect.right = nHorzPos + pTTYInfo->xChar * scrwidth(pTTYInfo->pScreen+offset, count);
2161 ExtTextOut (hDC, nHorzPos, nVertPos, ETO_OPAQUE | ETO_CLIPPED,
2162 &rect, (LPTSTR) (pTTYInfo->pScreen + offset),
2163 count, (int *)(pTTYInfo->pCellWidth+offset));
2165 /* Overstrike bold chars by hand to preserve char cell size */
2166 if(pNewAttrib->style & CHAR_ATTR_BOLD){
2167 int old_mode = GetBkMode(hDC);
2168 SetBkMode (hDC, TRANSPARENT);
2169 ExtTextOut (hDC, nHorzPos + 1, nVertPos, 0,
2170 &rect, (LPTSTR) (pTTYInfo->pScreen + offset),
2171 count, (int *)(pTTYInfo->pCellWidth+offset));
2172 if(old_mode)
2173 SetBkMode (hDC, old_mode);
2176 /* Move pointer to end of this span of characters. */
2177 col += MAX(scrwidth(pTTYInfo->pScreen+offset, count), 1);
2178 pLastAttrib = pNewAttrib;
2180 if(hTmpFont != NULL){
2181 SelectObject(hDC, hOldFont);
2182 DeleteObject(hTmpFont);
2187 SelectObject (hDC, hOrigFont);
2188 EndPaint (hWnd, &ps);
2189 MoveTTYCursor (hWnd);
2190 pTTYInfo->screenDirty = FALSE;
2191 return (TRUE);
2195 /* FillRectColor
2198 * Description:
2199 * FillRectColor is similar to PatB in toolbar.c
2201 * Code based on MFC source code, so presumably efficient.
2204 LOCAL void
2205 FillRectColor(HDC hDC, RECT * pRC, COLORREF color)
2207 SetBkColor(hDC, color);
2208 ExtTextOut(hDC, 0, 0, ETO_OPAQUE, pRC, NULL, 0, NULL);
2212 /** FrameRect3D
2215 * Inputs:
2216 * hdc - HDC
2217 * pRC - pointer to rectangle
2218 * width - width for frame (usually one)
2219 * raised - TRUE for raised effect, FALSE for sunken effect
2221 * Outputs:
2222 * none
2224 * Returns:
2225 * void
2227 * Description
2228 * Draws a frame with a 3D effect.
2230 * If 'raised' is true, the rectangle will look raised (like
2231 * a button); otherwise, the rectangle will look sunk.
2234 void
2235 FrameRect3D(HDC hdc, RECT * pRC, int width, BOOL raised)
2237 COLORREF hilite, shadow;
2238 RECT rcTemp;
2240 shadow = GetSysColor(COLOR_BTNSHADOW);
2241 hilite = GetSysColor(COLOR_BTNHIGHLIGHT);
2243 rcTemp = *pRC;
2245 rcTemp.right = rcTemp.left + width;
2246 FillRectColor(hdc, &rcTemp, raised ? hilite : shadow);
2247 rcTemp.right = pRC->right;
2249 rcTemp.bottom = rcTemp.top + width;
2250 FillRectColor(hdc, &rcTemp, raised ? hilite : shadow);
2251 rcTemp.bottom = pRC->bottom;
2253 rcTemp.left = rcTemp.right - width;
2254 FillRectColor(hdc, &rcTemp, raised ? shadow : hilite);
2255 rcTemp.left = pRC->left;
2257 rcTemp.top = rcTemp.bottom - width;
2258 FillRectColor(hdc, &rcTemp, raised ? shadow : hilite);
2262 /*---------------------------------------------------------------------------
2263 * BOOL GetMinMaxInfoTTY (HWND hWnd, (MINMAXINFO __far *)lParam)
2265 * Description:
2266 * Return the min and max size that the window can be.
2268 * Parameters:
2269 * HWND hWnd
2270 * handle to TTY window
2272 * MINMAXINFO
2273 * Info structure that Windows would like us to fill.
2275 /*--------------------------------------------------------------------------*/
2276 LOCAL BOOL
2277 GetMinMaxInfoTTY (HWND hWnd, MINMAXINFO __far *lpmmi)
2279 PTTYINFO pTTYInfo;
2282 #ifdef SDEBUG
2283 if (mswin_debug >= 5)
2284 fprintf (mswin_debugfile, "GetMinMaxInfoTTY::: entered\n");
2285 #endif
2288 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2289 if (pTTYInfo == NULL)
2290 return (FALSE);
2292 lpmmi->ptMaxTrackSize.x = lpmmi->ptMaxSize.x = MIN (lpmmi->ptMaxSize.x,
2293 pTTYInfo->xChar * MAXNCOLUMN + WIN_X_BORDER_SIZE);
2294 lpmmi->ptMaxTrackSize.y = lpmmi->ptMaxSize.y = MIN (lpmmi->ptMaxSize.y,
2295 pTTYInfo->yChar * MAXNROW + WIN_Y_BORDER_SIZE);
2297 lpmmi->ptMinTrackSize.x = MAX (WIN_MIN_X_SIZE,
2298 pTTYInfo->xChar * MINNCOLUMN + WIN_X_BORDER_SIZE);
2299 lpmmi->ptMinTrackSize.y = MAX (WIN_MIN_Y_SIZE,
2300 pTTYInfo->yChar * MINNROW + WIN_Y_BORDER_SIZE);
2301 return (TRUE);
2305 /*---------------------------------------------------------------------------
2306 * BOOL AboutToSizeTTY (HWND hWnd, WINDOWPOS *winPos)
2308 * Description:
2309 * Called just before Windows resizes our window. We can change the
2310 * values in 'winPos' to change the new size of the window.
2312 * If mswin_setwindow() was called when the window was minimized we
2313 * set the new size here.
2315 * Parameters:
2316 * HWND hWnd
2317 * handle to TTY window
2319 * WORD wVertSize
2320 * new vertical size
2322 * WORD wHorzSize
2323 * new horizontal size
2325 /*--------------------------------------------------------------------------*/
2326 LOCAL BOOL
2327 AboutToSizeTTY (HWND hWnd, WINDOWPOS *winPos)
2329 PTTYINFO pTTYInfo;
2332 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2333 if (pTTYInfo == NULL)
2334 return ( FALSE );
2336 #ifdef SDEBUG
2337 if (mswin_debug >= 5)
2338 fprintf (mswin_debugfile, "AboutToSizeTTY::: After x%lx, pos %d, %d, size %d, %d, flags x%x\n",
2339 winPos->hwndInsertAfter, winPos->x, winPos->y, winPos->cx,
2340 winPos->cy, winPos->flags);
2342 #endif
2345 * Was the window minimized AND is there a desired new size for it?
2346 * AND is this a call that specifies a new size and position.
2348 if (pTTYInfo->fMinimized && pTTYInfo->fDesiredSize &&
2349 (winPos->flags & (SWP_NOSIZE | SWP_NOMOVE)) == 0) {
2350 #ifdef SDEBUG
2351 if (mswin_debug >= 5)
2352 fprintf (mswin_debugfile, "AboutToSizeTTY::: substitute pos (%d, %d), size (%d, %d)\n",
2353 pTTYInfo->xDesPos, pTTYInfo->yDesPos,
2354 pTTYInfo->xDesSize, pTTYInfo->yDesSize);
2355 #endif
2356 pTTYInfo->fDesiredSize = FALSE;
2357 winPos->x = pTTYInfo->xDesPos;
2358 winPos->y = pTTYInfo->yDesPos;
2359 winPos->cx = pTTYInfo->xDesSize;
2360 winPos->cy = pTTYInfo->yDesSize;
2362 return (TRUE);
2366 /*---------------------------------------------------------------------------
2367 * BOOL SizeTTY( HWND hWnd, int fwSizeType, CORD wVertSize,
2368 * CORD wHorzSize)
2370 * Description:
2371 * Sizes TTY and sets up scrolling regions.
2373 * Parameters:
2374 * HWND hWnd
2375 * handle to TTY window
2377 * WORD wVertSize
2378 * new vertical size
2380 * WORD wHorzSize
2381 * new horizontal size
2383 /*--------------------------------------------------------------------------*/
2384 LOCAL BOOL
2385 SizeTTY (HWND hWnd, int fwSizeType, CORD wVertSize, CORD wHorzSize)
2387 PTTYINFO pTTYInfo;
2388 int newNColumn;
2389 int newNRow;
2392 #ifdef SDEBUG
2393 if (mswin_debug >= 5)
2394 fprintf (mswin_debugfile, "SizeTTY::: entered, sizeType %d, New screen size %d, %d pixels\n",
2395 fwSizeType, wHorzSize, wVertSize);
2396 #endif
2398 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2399 if (pTTYInfo == NULL)
2400 return ( FALSE );
2404 * Is the window being minimized or maximized?
2406 switch (fwSizeType) {
2407 case SIZE_MINIMIZED:
2408 pTTYInfo->fMinimized = TRUE;
2409 pTTYInfo->fMaximized = FALSE;
2410 return (TRUE);
2411 case SIZE_MAXIMIZED:
2412 pTTYInfo->fMinimized = FALSE;
2413 pTTYInfo->fMaximized = TRUE;
2414 break;
2415 default:
2416 pTTYInfo->fMinimized = pTTYInfo->fMaximized = FALSE;
2417 break;
2420 pTTYInfo->ySize = (CORD) wVertSize;
2421 newNRow = MAX(MINNROW, MIN(MAXNROW,
2422 (pTTYInfo->ySize - pTTYInfo->toolBarSize - (2 * MARGINE_TOP)) /
2423 pTTYInfo->yChar));
2424 if (pTTYInfo->toolBarTop)
2425 pTTYInfo->yOffset = MARGINE_TOP + pTTYInfo->toolBarSize;
2426 else
2427 pTTYInfo->yOffset = MARGINE_TOP;
2430 pTTYInfo->xSize = (CORD) wHorzSize;
2431 newNColumn = MAX(MINNCOLUMN,
2432 MIN(MAXNCOLUMN, (pTTYInfo->xSize - (2 * MARGINE_LEFT)) /
2433 pTTYInfo->xChar));
2434 pTTYInfo->xOffset = MARGINE_LEFT;
2436 if(newNRow == pTTYInfo->actNRow && newNColumn == pTTYInfo->actNColumn)
2437 return(FALSE);
2439 ResizeTTYScreen (hWnd, pTTYInfo, newNRow, newNColumn);
2440 pTTYInfo->screenDirty = TRUE;
2441 pTTYInfo->eraseScreen = TRUE;
2442 InvalidateRect (hWnd, NULL, FALSE);
2444 if (pTTYInfo->hTBWnd) {
2445 if (pTTYInfo->toolBarTop)
2446 /* Position at top of window. */
2447 SetWindowPos (pTTYInfo->hTBWnd, HWND_TOP,
2448 0, 0,
2449 wHorzSize, pTTYInfo->toolBarSize,
2450 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
2451 else
2452 /* Position at bottom of window. */
2453 SetWindowPos (pTTYInfo->hTBWnd, HWND_TOP,
2454 0, pTTYInfo->ySize - pTTYInfo->toolBarSize,
2455 wHorzSize, pTTYInfo->toolBarSize,
2456 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
2460 DidResize (pTTYInfo);
2462 return (TRUE);
2466 /*---------------------------------------------------------------------------
2467 * BOOL SizingTTY( HWND hWnd, int fwSide, LPRECT pRect)
2469 * Description:
2470 * Snaps the drag rectangle to char width/height boundaries
2472 * Parameters:
2473 * HWND hWnd
2474 * handle to TTY window
2476 * WORD fwSide
2477 * edge of window being sized
2479 * LPRECT
2480 * screen coords of drag rectangle in and desired size on return
2482 /*--------------------------------------------------------------------------*/
2483 LOCAL BOOL
2484 SizingTTY (HWND hWnd, int fwSide, LPRECT pRect)
2486 PTTYINFO pTTYInfo;
2487 int newNRow, newNCol, xClient, yClient,
2488 xSys, ySys, xDiff, yDiff;
2490 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2491 if (pTTYInfo == NULL)
2492 return (FALSE);
2494 xSys = (2 * GetSystemMetrics(SM_CXSIZEFRAME))
2495 + GetSystemMetrics(SM_CXVSCROLL);
2496 ySys = (2 * GetSystemMetrics(SM_CYSIZEFRAME))
2497 + GetSystemMetrics(SM_CYCAPTION)
2498 + GetSystemMetrics(SM_CYMENU);
2500 newNCol = (((pRect->right - pRect->left) - xSys)
2501 - (2 * MARGINE_LEFT)) / pTTYInfo->xChar;
2502 newNRow = (((pRect->bottom - pRect->top) - ySys) - (2 * MARGINE_TOP)
2503 - pTTYInfo->toolBarSize) / pTTYInfo->yChar;
2505 xClient = (newNCol * pTTYInfo->xChar) + (2 * MARGINE_LEFT);
2506 yClient = (newNRow * pTTYInfo->yChar) + (2 * MARGINE_TOP)
2507 + pTTYInfo->toolBarSize;
2509 xDiff = (pRect->left + xClient + xSys) - pRect->right;
2510 yDiff = (pRect->top + yClient + ySys) - pRect->bottom;
2512 if(!(xDiff || yDiff))
2513 return(FALSE);
2515 switch(fwSide){
2516 case WMSZ_BOTTOM : /* Bottom edge */
2517 pRect->bottom += yDiff;
2518 break;
2520 case WMSZ_BOTTOMLEFT : /*Bottom-left corner */
2521 pRect->bottom += yDiff;
2522 pRect->left -= xDiff;
2523 break;
2525 case WMSZ_BOTTOMRIGHT : /* Bottom-right corner */
2526 pRect->bottom += yDiff;
2527 pRect->right += xDiff;
2528 break;
2530 case WMSZ_LEFT : /* Left edge */
2531 pRect->left -= xDiff;
2532 break;
2534 case WMSZ_RIGHT : /* Right edge */
2535 pRect->right += xDiff;
2536 break;
2538 case WMSZ_TOP : /* Top edge */
2539 pRect->top -= yDiff;
2540 break;
2542 case WMSZ_TOPLEFT : /* Top-left corner */
2543 pRect->top -= yDiff;
2544 pRect->left -= xDiff;
2545 break;
2547 case WMSZ_TOPRIGHT : /* Top-right corner */
2548 pRect->top -= yDiff;
2549 pRect->right += xDiff;
2550 break;
2552 default :
2553 break;
2556 if(!(newNRow == pTTYInfo->actNRow && newNCol == pTTYInfo->actNColumn))
2557 SizeTTY(hWnd, SIZE_RESTORED, (CORD) yClient, (CORD) xClient);
2559 return(TRUE);
2563 /*---------------------------------------------------------------------------
2564 * BOOL MoveTTY (HWND hWnd, int xPos, int yPos)
2566 * Description:
2567 * Notes the fact that the window has moved.
2568 * Only real purpose is so we can tell pine which can the write the
2569 * new window position to the 'pinerc' file.
2571 * Parameters:
2572 * HWND hWnd
2573 * handle to TTY window
2575 * int xPos, yPos
2576 * New position of the top left corner.
2579 /*--------------------------------------------------------------------------*/
2580 LOCAL BOOL
2581 MoveTTY (HWND hWnd, int xPos, int yPos)
2583 #ifdef SDEBUG
2584 if (mswin_debug >= 5)
2585 fprintf (mswin_debugfile, "MoveTTY::: entered\n");
2586 #endif
2588 DidResize (gpTTYInfo);
2589 return (TRUE);
2593 /*---------------------------------------------------------------------------
2594 * void ScrollTTY ()
2596 * Description:
2597 * Respond to a scroll message by either calling the scroll
2598 * callback or inserting a scroll character into the input
2599 * stream.
2601 * Scrolling in the TTY window is complicated by the way pine
2602 * process events. Normal windows applications are entirely event
2603 * driven. The top level does nothing but dispatch events. In
2604 * pine, the top level implements the logic. Events are only
2605 * dispatched by the lowest levels.
2607 * In normal applications, mouse down in the scroll bar causes
2608 * an internal scroll function to be entered. It tracks the
2609 * mouse and issues scroll messages as needed. If the
2610 * application redraws the screen the scroll function also
2611 * dispatches the WM_PAINT message to the application. The
2612 * important thing is that this internal scroll function does
2613 * not exit until the mouse is released.
2615 * We implement two methods for pine's screen managers to deal
2616 * with scroll events. They can receive scroll events as
2617 * characters in the normal input stream or they can register a
2618 * callback function.
2620 * In the "insert a character in the queue" mode, the scroll
2621 * event never gets process until the mouse is release. Auto
2622 * repeat scroll events (generated as the mouse is held down)
2623 * will cause multiple chars to be inserted in the queue, none
2624 * of which will get processed till the mouse is release. In a
2625 * compromise, we allow only one scroll char in the queue,
2626 * which prevents makes for a more friendly and controllable
2627 * behavior.
2629 * In the callback mode, the callback repaints the screen, and
2630 * then it calls mswin_flush() which PROCESSES EVENTS! The
2631 * Windows internal scroll function does NOT expect that. This
2632 * behavior can confuses the scroll function, causing it to
2633 * miss mouse up events. We avoid this by setting gScrolling TRUE
2634 * when this routine is entered and FALSE when this routine exits
2635 * All PeekMessage processors avoid processing any message when
2636 * gScrolling is TRUE.
2638 /*--------------------------------------------------------------------------*/
2639 LOCAL void
2640 ScrollTTY (HWND hWnd, int wScrollCode, int nPos, HWND hScroll)
2642 PTTYINFO pTTYInfo;
2643 int cmd = 0;
2644 long scroll_pos = 0;
2645 BOOL noAction = FALSE;
2646 BOOL didScroll;
2647 FARPROC prevBlockingProc;
2651 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2653 if (pTTYInfo == NULL || gScrolling)
2654 return;
2656 gScrolling = TRUE;
2657 if (gWSBlockingProc != NULL)
2658 prevBlockingProc = WSASetBlockingHook (gWSBlockingProc);
2663 switch (wScrollCode) {
2664 case SB_BOTTOM:
2665 cmd = MSWIN_KEY_SCROLLTO;
2666 scroll_pos = pTTYInfo->scrollTo = 0;
2667 break;
2669 case SB_TOP:
2670 cmd = MSWIN_KEY_SCROLLTO;
2671 scroll_pos = pTTYInfo->scrollTo = pTTYInfo->scrollRange;
2672 break;
2674 case SB_LINEDOWN:
2675 cmd = MSWIN_KEY_SCROLLDOWNLINE;
2676 scroll_pos = 1;
2677 break;
2679 case SB_LINEUP:
2680 cmd = MSWIN_KEY_SCROLLUPLINE;
2681 scroll_pos = 1;
2682 break;
2684 case SB_PAGEDOWN:
2685 cmd = MSWIN_KEY_SCROLLDOWNPAGE;
2686 scroll_pos = 1;
2687 break;
2689 case SB_PAGEUP:
2690 cmd = MSWIN_KEY_SCROLLUPPAGE;
2691 scroll_pos = 1;
2692 break;
2694 case SB_THUMBTRACK:
2695 case SB_THUMBPOSITION:
2696 cmd = MSWIN_KEY_SCROLLTO;
2697 scroll_pos = pTTYInfo->scrollTo = (long) ((float)nPos);
2698 break;
2700 default:
2701 noAction = TRUE;
2702 break;
2707 * If there is a scroll callback call that. If there is no scroll
2708 * callback or the callback says it did not handle the event (returned,
2709 * FALSE) queue the scroll cmd.
2711 if (!noAction) {
2712 SelClear ();
2713 didScroll = FALSE;
2714 if (gScrollCallback != NULL) {
2715 /* Call scrolling callback. Set blocking hook to our routine
2716 * which prevents messages from being dispatched. */
2717 if (gWSBlockingProc != NULL)
2718 WSASetBlockingHook (gWSBlockingProc);
2719 didScroll = gScrollCallback (cmd, scroll_pos);
2720 if (gWSBlockingProc != NULL)
2721 WSAUnhookBlockingHook ();
2724 * If no callback or callback did not do the scrolling operation,
2725 * insert a scroll cmd in the input stream.
2727 if (!didScroll)
2728 CQAddUniq ((UCS)cmd, 0);
2732 gScrolling = FALSE;
2733 return;
2737 #ifdef WIN32
2738 /*---------------------------------------------------------------------------
2739 * void MouseWheelTTY ()
2741 * Description:
2742 * Respond to a WM_MOUSEWHEEL event by calling scroll callback
2743 * ala ScrollTTY.
2746 /*--------------------------------------------------------------------------*/
2747 LOCAL void
2748 MouseWheelTTY (HWND hWnd, int xPos, int yPos, int fwKeys, int zDelta)
2750 PTTYINFO pTTYInfo;
2751 int cmd;
2752 long scroll_pos;
2753 FARPROC prevBlockingProc;
2754 SCROLLINFO scrollInfo;
2755 static int zDelta_accumulated;
2757 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2759 if (pTTYInfo == NULL || gScrolling)
2760 return;
2762 scrollInfo.cbSize = sizeof(SCROLLINFO);
2763 scrollInfo.fMask = SIF_POS | SIF_RANGE;
2764 GetScrollInfo(hWnd, SB_VERT, &scrollInfo);
2765 if((zDelta < 0 && scrollInfo.nPos < scrollInfo.nMin)
2766 || (zDelta > 0 && scrollInfo.nPos >= scrollInfo.nMax))
2767 return;
2769 gScrolling = TRUE;
2770 if (gWSBlockingProc != NULL)
2771 prevBlockingProc = WSASetBlockingHook (gWSBlockingProc);
2773 if(fwKeys == MK_MBUTTON)
2774 zDelta *= 2; /* double the effect! */
2776 if(abs(zDelta += zDelta_accumulated) < WHEEL_DELTA){
2777 zDelta_accumulated = zDelta;
2779 else{
2780 /* Remember any partial increments */
2781 zDelta_accumulated = zDelta % WHEEL_DELTA;
2783 scroll_pos = (long)(gsMWMultiplier * abs((zDelta / WHEEL_DELTA)));
2785 cmd = (zDelta < 0) ? MSWIN_KEY_SCROLLDOWNLINE : MSWIN_KEY_SCROLLUPLINE;
2787 SelClear ();
2788 if (gScrollCallback != NULL) {
2789 /* Call scrolling callback. Set blocking hook to our routine
2790 * which prevents messages from being dispatched. */
2791 if (gWSBlockingProc != NULL)
2792 WSASetBlockingHook (gWSBlockingProc);
2793 (void) gScrollCallback (cmd, scroll_pos);
2794 if (gWSBlockingProc != NULL)
2795 WSAUnhookBlockingHook ();
2799 gScrolling = FALSE;
2800 return;
2804 LOCAL void
2805 MouseWheelMultiplier()
2807 TCHAR lines[8];
2808 DWORD llen = sizeof(lines)/sizeof(TCHAR);
2810 /* HKEY_CURRENT_USER\Control Panel\Desktop holds the key */
2811 gsMWMultiplier = (MSWRPeek(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"),
2812 TEXT("WheelScrollLines"), lines, &llen) == TRUE)
2813 ? (short)_ttoi(lines) : 1;
2815 #endif
2818 /*---------------------------------------------------------------------------
2819 * void CaretTTY (HWND hWnd, CARETS cStyle)
2821 * Description:
2822 * Adjusts the Caret to the user supplied style
2824 * Parameters:
2825 * HWND hWnd
2826 * handle to TTY window
2828 * int wStyle
2829 * New style to take on
2831 /*--------------------------------------------------------------------------*/
2832 LOCAL void
2833 CaretTTY (HWND hWnd, CARETS cStyle)
2835 PTTYINFO pTTYInfo;
2837 if(pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO)){
2838 pTTYInfo->cCaretStyle = cStyle;
2839 CaretCreateTTY (hWnd);
2840 DidResize (gpTTYInfo);
2845 /*---------------------------------------------------------------------------
2846 * void CaretCreateTTY (HWND hWnd, BOOL wPosition)
2848 * Description:
2849 * Adjusts the Caret to the user supplied style
2851 * Parameters:
2852 * HWND hWnd
2853 * handle to TTY window
2855 * BOOL wPosition
2856 * whether or not to position it too
2858 /*--------------------------------------------------------------------------*/
2859 LOCAL void
2860 CaretCreateTTY (HWND hWnd)
2862 PTTYINFO pTTYInfo;
2864 if(pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO)){
2865 int n = 0, x, y;
2867 switch(pTTYInfo->cCaretStyle){
2868 case CaretHorizBar :
2869 x = pTTYInfo->xChar;
2870 y = pTTYInfo->yChar / 5;
2871 n = pTTYInfo->yChar - y;
2872 break;
2874 case CaretVertBar :
2875 x = pTTYInfo->xChar / 4;
2876 y = pTTYInfo->yChar;
2877 break;
2879 case CaretSmallBlock :
2880 x = pTTYInfo->xChar;
2881 y = pTTYInfo->yChar / 2;
2882 n = pTTYInfo->yChar - y;
2883 break;
2885 default :
2886 x = pTTYInfo->xChar;
2887 y = pTTYInfo->yChar;
2888 break;
2891 CreateCaret (hWnd, NULL, x, y);
2892 pTTYInfo->yCurOffset = n;
2894 if(pTTYInfo->fCaretOn){
2895 ShowCaret(hWnd);
2896 MoveTTYCursor(hWnd);
2903 * This routine is inserted as the winsock blocking hook. It's main perpos
2904 * is to NOT dispatch messages.
2906 BOOL CALLBACK __export
2907 NoMsgsAreSent (void)
2909 return (FALSE);
2913 /*---------------------------------------------------------------------------
2914 * BOOL SetTTYFocus( HWND hWnd )
2916 * Description:
2917 * Sets the focus to the TTY window also creates caret.
2919 * Parameters:
2920 * HWND hWnd
2921 * handle to TTY window
2923 /*--------------------------------------------------------------------------*/
2924 LOCAL BOOL
2925 SetTTYFocus (HWND hWnd)
2927 PTTYINFO pTTYInfo;
2929 #ifdef SDEBUG
2930 if (mswin_debug >= 5)
2931 fprintf (mswin_debugfile, "SetTTYFocus::: entered\n");
2932 #endif
2934 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2935 if (pTTYInfo == NULL)
2936 return (FALSE);
2938 mswin_showcursor(TRUE);
2940 pTTYInfo->fFocused = TRUE;
2942 CaretCreateTTY (hWnd);
2944 MoveTTYCursor (hWnd);
2945 return (TRUE);
2949 /*---------------------------------------------------------------------------
2950 * BOOL KillTTYFocus( HWND hWnd )
2952 * Description:
2953 * Kills TTY focus and destroys the caret.
2955 * Parameters:
2956 * HWND hWnd
2957 * handle to TTY window
2959 /*--------------------------------------------------------------------------*/
2960 LOCAL BOOL
2961 KillTTYFocus (HWND hWnd)
2963 PTTYINFO pTTYInfo;
2965 #ifdef SDEBUG
2966 if (mswin_debug >= 5)
2967 fprintf (mswin_debugfile, "KillTTYFocus::: entered\n");
2968 #endif
2969 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
2970 if (pTTYInfo == NULL)
2971 return (FALSE);
2973 mswin_showcursor(TRUE);
2975 if(pTTYInfo->fCaretOn)
2976 HideCaret (hWnd);
2978 DestroyCaret();
2980 pTTYInfo->fFocused = FALSE;
2982 return (TRUE);
2986 /*---------------------------------------------------------------------------
2987 * BOOL MoveTTYCursor( HWND hWnd )
2989 * Description:
2990 * Moves caret to current position.
2992 * Parameters:
2993 * HWND hWnd
2994 * handle to TTY window
2996 /*--------------------------------------------------------------------------*/
2997 LOCAL BOOL
2998 MoveTTYCursor (HWND hWnd)
3000 PTTYINFO pTTYInfo;
3002 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
3003 if (pTTYInfo == NULL)
3004 return (FALSE);
3006 if(pTTYInfo->fCaretOn && !pTTYInfo->fMassiveUpdate) {
3007 HideCaret (hWnd);
3008 SetCaretPos ((pTTYInfo->nColumn * pTTYInfo->xChar) + pTTYInfo->xOffset,
3009 (pTTYInfo->nRow * pTTYInfo->yChar)
3010 + pTTYInfo->yCurOffset + pTTYInfo->yOffset);
3011 ShowCaret (hWnd);
3014 return (TRUE);
3018 /*---------------------------------------------------------------------------
3019 * BOOL ProcessTTYKeyDown ( HWND hWnd, WORD bOut )
3021 * Description:
3022 * Called to process MW_KEYDOWN message. We are only interested in
3023 * virtual keys that pico/pine use. All others get passed on to
3024 * the default message handler. Regular key presses will return
3025 * latter as a WM_CHAR message, with SHIFT and CONTROL processing
3026 * already done.
3028 * We do watch for VK_CONTROL to keep track of it's state such
3029 * that we can implement ^_space.
3031 * Parameters:
3032 * HWND hWnd
3033 * handle to TTY window
3035 * BYTE key
3036 * Virtual key code.
3038 /*--------------------------------------------------------------------------*/
3039 LOCAL BOOL
3040 ProcessTTYKeyDown (HWND hWnd, TCHAR key)
3042 UCS myKey;
3043 BOOL fKeyControlDown = GetKeyState(VK_CONTROL) < 0;
3044 BOOL fKeyAltDown = GetKeyState(VK_MENU) < 0;
3046 // If the alt key is down, let Windows handle the message. This will
3047 // allow the Ctrl+Alt (AltGr) processing to work.
3048 if(fKeyAltDown)
3049 return FALSE;
3051 switch (key) {
3052 case VK_MENU:
3053 case VK_CONTROL:
3054 case VK_SHIFT:
3055 return FALSE;
3056 case VK_UP: myKey = KEY_UP; break;
3057 case VK_DOWN: myKey = KEY_DOWN; break;
3058 case VK_RIGHT:
3059 /* Ctrl-@ is used to advance to the next word. */
3060 myKey = fKeyControlDown ? '@': KEY_RIGHT;
3061 break;
3062 case VK_LEFT:
3063 /* Ctrl-left is used to advance to the previous word. */
3064 myKey = KEY_LEFT;
3065 break;
3066 case VK_HOME:
3067 /* Ctrl-home is used to advance to the beginning of buffer. */
3068 myKey = KEY_HOME;
3069 break;
3070 case VK_END:
3071 /* Ctrl-end is used to advance to the end of buffer. */
3072 myKey = KEY_END;
3073 break;
3074 case VK_PRIOR: myKey = KEY_PGUP; break;
3075 case VK_NEXT: myKey = KEY_PGDN; break;
3076 case VK_DELETE: myKey = KEY_DEL; break;
3077 case VK_F1: myKey = F1; break;
3078 case VK_F2: myKey = F2; break;
3079 case VK_F3: myKey = F3; break;
3080 case VK_F4: myKey = F4; break;
3081 case VK_F5: myKey = F5; break;
3082 case VK_F6: myKey = F6; break;
3083 case VK_F7: myKey = F7; break;
3084 case VK_F8: myKey = F8; break;
3085 case VK_F9: myKey = F9; break;
3086 case VK_F10: myKey = F10; break;
3087 case VK_F11: myKey = F11; break;
3088 case VK_F12: myKey = F12; break;
3090 default:
3091 if(fKeyControlDown && !(GetKeyState(VK_SHIFT) < 0)) {
3092 if(key == '6') {
3094 * Ctrl-^ is used to set and clear the mark in the
3095 * composer (pico) On most other systems Ctrl-6 does the
3096 * same thing. Allow that on windows too.
3098 myKey = '^';
3099 break;
3100 } else if(key == '2') {
3101 /* Ctrl-@ is used to advance to the next word. */
3102 myKey = '@';
3103 break;
3107 return (FALSE); /* Message NOT handled.*/
3110 CQAdd (myKey, fKeyControlDown);
3112 set_time_of_last_input();
3114 return (TRUE); /* Message handled .*/
3118 #ifdef CDEBUG
3119 char *
3120 dtime()
3122 static char timestring[23];
3123 time_t t;
3124 struct _timeb timebuffer;
3126 timestring[0] = '\0';
3127 t = time((time_t *) 0);
3128 _ftime(&timebuffer);
3129 snprintf(timestring, sizeof(timestring), "%.8s.%03ld", ctime(&t)+11, timebuffer.millitm);
3131 return(timestring);
3133 #endif
3136 /*---------------------------------------------------------------------------
3137 * BOOL ProcessTTYCharacter( HWND hWnd, WORD bOut )
3139 * Description:
3140 * Place the character into a queue.
3142 * Parameters:
3143 * HWND hWnd
3144 * handle to TTY window
3146 * BYTE bOut
3147 * byte from keyboard
3149 /*--------------------------------------------------------------------------*/
3150 LOCAL BOOL
3151 ProcessTTYCharacter (HWND hWnd, TCHAR bOut)
3153 // Only check for control key being down if the alt key isn't also down.
3154 // Windows uses Ctrl+Alt as AltGr.
3155 BOOL fKeyAltDown = GetKeyState(VK_MENU) < 0;
3156 BOOL fKeyControlDown = fKeyAltDown ?
3157 FALSE : (GetKeyState(VK_CONTROL) < 0);
3159 if(fKeyControlDown) {
3160 if(bOut == ' ')
3161 bOut = '@';
3162 else
3163 bOut += '@';
3166 CQAdd ((UCS)bOut, fKeyControlDown);
3168 #ifdef ACCELERATORS
3169 UpdateAccelerators (hWnd);
3170 #endif
3172 set_time_of_last_input();
3174 return (TRUE); /* Message handled. */
3178 /*---------------------------------------------------------------------------
3179 * BOOL ProcessTTYMouse(HWND hWnd, int mevent, int button,
3180 * int xPos, int yPos, WPARAM keys)
3182 * Description:
3183 * This is the central control for all mouse events. Every event
3184 * gets put into a queue to wait for the upper layer.
3186 * The upper's input routine calls checkmouse() which pulls the
3187 * mouse event off the input queue. checkmouse() has a list of
3188 * of screen regions. Some regions correspond to a "menu" item
3189 * (text button at bottom of screen). There is generally one
3190 * region for the central region of the screen.
3192 * Because pine/pico do not interpret mouse drags, we do that here.
3193 * When the user presses the button and drags the mouse across the
3194 * screen this select the text in the region defined by the drag.
3195 * The operation is local to mswin.c, and can only get what text
3196 * is on the screen.
3198 * The one exception is that now pico interprets mouse drag events
3199 * in the body. pico signals that it wants to track the mouse
3200 * by calling mswin_allowmousetrack(). This will 1) turn off
3201 * our mouse tracking and 2) cause mouse movement events to
3202 * be put on the mouse queue.
3205 * Parameters:
3206 * HWND hWnd
3207 * handle to TTY window
3209 * BYTE bOut
3210 * byte from keyboard
3212 /*--------------------------------------------------------------------------*/
3213 LOCAL BOOL
3214 ProcessTTYMouse (HWND hWnd, int mevent, int button,
3215 CORD xPos, CORD yPos, WPARAM winkeys)
3217 int nRow;
3218 int nColumn;
3219 int keys;
3222 * Convert to cell position.
3224 nColumn = (xPos - gpTTYInfo->xOffset) / gpTTYInfo->xChar;
3225 if (xPos < gpTTYInfo->xOffset)
3226 --nColumn;
3227 nRow = (yPos - gpTTYInfo->yOffset) / gpTTYInfo->yChar;
3228 if (yPos < gpTTYInfo->yOffset)
3229 --nRow;
3232 * Convert window's keys.
3234 keys = 0;
3235 if (winkeys & MK_CONTROL)
3236 keys |= M_KEY_CONTROL;
3237 if (winkeys & MK_SHIFT)
3238 keys |= M_KEY_SHIFT;
3240 /* Adjust the cursor */
3241 if((unsigned long) mevent != M_EVENT_UP){
3242 if(gMouseTracking)
3243 mswin_setcursor(MSWIN_CURSOR_IBEAM);
3244 else if(ghCursorCurrent == ghCursorBusy)
3245 mswin_setcursor(MSWIN_CURSOR_BUSY);
3246 else if(mouse_on_key(nRow, nColumn))
3247 mswin_setcursor(MSWIN_CURSOR_HAND);
3248 else if(gMouseTrackCallback)
3249 mswin_setcursor((*gMouseTrackCallback)(nColumn, (long) nRow));
3250 else
3251 mswin_setcursor(MSWIN_CURSOR_ARROW);
3255 * Tracking event or mouse up/down?
3257 if ((unsigned long) mevent == M_EVENT_TRACK) {
3259 * Who is doing the tracking?
3261 if (gAllowMouseTrack) {
3262 /* For tracking, Button info is different. */
3263 if (keys & MK_LBUTTON)
3264 button = M_BUTTON_LEFT;
3265 else if (keys & MK_MBUTTON)
3266 button = M_BUTTON_MIDDLE;
3267 else if (keys & MK_RBUTTON)
3268 button = M_BUTTON_RIGHT;
3269 MQAdd (mevent, button, nRow, nColumn, keys,
3270 MSWIN_MF_REPLACING);
3272 else
3273 SelTrackMouse (nRow, nColumn);
3275 else{
3277 * Tracking. Only start tracking mouse down in the text region
3278 * But allow mouse up anywhere.
3280 if ( (nRow >= 0 && nRow < gpTTYInfo->actNRow &&
3281 nColumn >= 0 && nColumn < gpTTYInfo->actNColumn)
3282 || (unsigned long) mevent == M_EVENT_UP) {
3285 * Mouse tracking. When the mouse goes down we start
3286 * capturing all mouse movement events. If no one else wants
3287 * them we will start defining a text selection.
3289 if ((unsigned long) mevent == M_EVENT_DOWN) {
3290 gMouseTracking = TRUE;
3291 SetCapture (ghTTYWnd);
3292 if (!gAllowMouseTrack && button == M_BUTTON_LEFT)
3293 SelStart (nRow, nColumn);
3295 else {
3296 ReleaseCapture ();
3297 if (!gAllowMouseTrack && button == M_BUTTON_LEFT)
3298 SelFinish (nRow, nColumn);
3299 gMouseTracking = FALSE;
3302 * If right mouse button, toss pop-up menu offering
3303 * cut/copy/paste
3305 if(button == M_BUTTON_RIGHT && SelAvailable()){
3306 UINT fAllowed = (EM_CP | EM_CP_APPEND);
3308 if(gAllowCut)
3309 fAllowed |= EM_CUT;
3311 if(CopyCutPopup(hWnd, fAllowed) == TRUE)
3312 mevent = M_EVENT_TRACK; /* don't add to input queue! */
3317 * Insert event into queue.
3319 if((unsigned long) mevent != M_EVENT_TRACK)
3320 MQAdd (mevent, button, nRow, nColumn, keys, 0);
3324 mswin_showcursor(TRUE); /* make sure it's visible */
3326 #ifdef ACCELERATORS
3327 UpdateAccelerators (hWnd);
3328 #endif
3330 set_time_of_last_input();
3332 return (0); /* Message handled. */
3336 /*---------------------------------------------------------------------------
3337 * BOOL ProcessTimer ()
3339 * Description:
3340 * Process the periodic timer calls.
3343 * Parameters:
3344 * None.
3346 /*--------------------------------------------------------------------------*/
3347 LOCAL void
3348 ProcessTimer (void)
3350 /* Time to deliver an alarm signal? */
3351 if (gAlarmTimeout != 0 && GetTickCount () / 1000 > gAlarmTimeout)
3352 AlarmDeliver ();
3354 /* Time to make the periodic callback. */
3355 if (gPeriodicCallback != NULL &&
3356 GetTickCount() / 1000 > gPeriodicCBTimeout) {
3357 gPeriodicCBTimeout = GetTickCount() / 1000 +
3358 gPeriodicCBTime;
3359 gPeriodicCallback ();
3363 * If tracking the mouse, insert a fake mouse tracking message
3364 * At the last know location of the mouse.
3366 if (gAllowMouseTrack) {
3367 gMTEvent.event = M_EVENT_TRACK;
3368 MQAdd (gMTEvent.event, gMTEvent.button, gMTEvent.nRow,
3369 gMTEvent.nColumn, gMTEvent.keys, MSWIN_MF_REPLACING);
3374 /*---------------------------------------------------------------------------
3375 * BOOL WriteTTYBlock( HWND hWnd, LPSTR lpBlock, int nLength )
3377 * Description:
3378 * Writes block to TTY screen. Nothing fancy - just
3379 * straight TTY.
3381 * Parameters:
3382 * HWND hWnd
3383 * handle to TTY window
3385 * LPSTR lpBlock
3386 * far pointer to block of data
3388 * int nLength
3389 * length of block
3391 /*--------------------------------------------------------------------------*/
3392 LOCAL BOOL
3393 WriteTTYBlock (HWND hWnd, LPTSTR lpBlock, int nLength)
3395 int i, j, width;
3396 PTTYINFO pTTYInfo;
3397 RECT rect;
3398 BOOL fNewLine;
3399 long offset;
3401 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
3402 if (pTTYInfo == NULL)
3403 return (FALSE);
3405 for (i = 0 ; i < nLength; i++) {
3406 switch (lpBlock[i]) {
3407 case ARABIC_LRM:
3408 case ARABIC_RLM:
3409 break;
3411 case ASCII_BEL:
3412 /* Bell */
3413 MessageBeep (0) ;
3414 break ;
3416 case ASCII_BS:
3417 /* Backspace over a whole character */
3418 offset = pscreen_offset_from_cord(pTTYInfo->nRow, pTTYInfo->nColumn, pTTYInfo);
3419 width = (offset > pTTYInfo->nRow * pTTYInfo->actNColumn)
3420 ? scrwidth(pTTYInfo->pScreen+offset-1, 1) : 0;
3422 if(pTTYInfo->nColumn > 0)
3423 pTTYInfo->nColumn = (CORD)(pTTYInfo->nColumn - width);
3425 MoveTTYCursor (hWnd);
3426 break;
3428 case ASCII_CR:
3429 /* Carriage return */
3430 pTTYInfo->nColumn = 0 ;
3431 MoveTTYCursor (hWnd);
3432 if (!pTTYInfo->fNewLine)
3433 break;
3435 /* fall through */
3437 case ASCII_LF:
3438 /* Line feed */
3439 if (++pTTYInfo->nRow == pTTYInfo->actNRow) {
3441 /* Scroll the Screen. */
3443 /* slide rows 1 - n-1 up to row 0 */
3444 memmove ((LPTSTR)pTTYInfo->pScreen,
3445 (LPTSTR) (pTTYInfo->pScreen + pTTYInfo->actNColumn),
3446 (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn * sizeof (TCHAR));
3448 /* initialize new row n-1 */
3449 for(j = (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn;
3450 j < pTTYInfo->actNColumn; j++)
3451 pTTYInfo->pScreen[j] = (TCHAR) ' ';
3454 /* Scroll the Cell Widths */
3455 memmove ((int *)pTTYInfo->pCellWidth,
3456 (int *) (pTTYInfo->pCellWidth + pTTYInfo->actNColumn),
3457 (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn * sizeof (int));
3458 for(j = (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn;
3459 j < pTTYInfo->actNColumn; j++)
3460 pTTYInfo->pCellWidth[j] = pTTYInfo->xChar; /* xChar set yet ? */
3462 /* Scroll the Attributes. */
3464 /* slide rows 1 - n-1 up to row 0 */
3465 memmove ((CharAttrib *) pTTYInfo->pAttrib,
3466 (CharAttrib *) (pTTYInfo->pAttrib + pTTYInfo->actNColumn),
3467 (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn * sizeof(CharAttrib));
3469 /* initialize new row n-1 to zero */
3470 memset ((CharAttrib *) (pTTYInfo->pAttrib +
3471 (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn),
3472 0, pTTYInfo->actNColumn*sizeof(CharAttrib));
3474 pTTYInfo->screenDirty = TRUE;
3475 pTTYInfo->eraseScreen = TRUE;
3476 InvalidateRect (hWnd, NULL, FALSE);
3477 --pTTYInfo->nRow;
3480 MoveTTYCursor (hWnd);
3481 break;
3483 default:
3484 offset = pscreen_offset_from_cord(pTTYInfo->nRow, pTTYInfo->nColumn, pTTYInfo);
3485 pTTYInfo->pScreen[offset] = lpBlock[i];
3486 pTTYInfo->pCellWidth[offset] = wcellwidth((UCS)lpBlock[i]) * pTTYInfo->xChar;
3487 pTTYInfo->pAttrib[offset] = pTTYInfo->curAttrib;
3488 rect.left = (pTTYInfo->nColumn * pTTYInfo->xChar) +
3489 pTTYInfo->xOffset;
3490 rect.right = rect.left + pTTYInfo->xChar;
3491 rect.top = (pTTYInfo->nRow * pTTYInfo->yChar) +
3492 pTTYInfo->yOffset;
3493 rect.bottom = rect.top + pTTYInfo->yChar;
3494 pTTYInfo->screenDirty = TRUE;
3495 InvalidateRect (hWnd, &rect, FALSE);
3497 /* Line Wrap. */
3498 if (pTTYInfo->nColumn < pTTYInfo->actNColumn - 1)
3499 pTTYInfo->nColumn++ ;
3500 else if (pTTYInfo->autoWrap == WRAP_ON ||
3501 (pTTYInfo->autoWrap == WRAP_NO_SCROLL &&
3502 pTTYInfo->nRow < pTTYInfo->actNRow - 1)) {
3503 fNewLine = pTTYInfo->fNewLine;
3504 pTTYInfo->fNewLine = FALSE;
3505 WriteTTYBlock (hWnd, TEXT("\r\n"), 2);
3506 pTTYInfo->fNewLine = fNewLine;
3508 break;
3511 return (TRUE);
3515 /*---------------------------------------------------------------------------
3516 * BOOL WriteTTYText ( HWND hWnd, LPSTR lpBlock, int nLength )
3518 * Description:
3519 * Like WriteTTYBlock but optimized for strings that are text only,
3520 * no carrage control characters.
3522 * Parameters:
3523 * HWND hWnd
3524 * handle to TTY window
3526 * LPSTR lpBlock
3527 * far pointer to block of data
3529 * int nLength
3530 * length of block
3532 /*--------------------------------------------------------------------------*/
3533 LOCAL BOOL
3534 WriteTTYText (HWND hWnd, LPTSTR lpText, int nLength)
3536 int i;
3537 PTTYINFO pTTYInfo;
3538 RECT rect;
3539 long offset, endOffset;
3540 long colEnd;
3541 long screenEnd;
3542 int screenwidth;
3545 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
3546 if (pTTYInfo == NULL)
3547 return ( FALSE );
3550 /* Calculate offset of cursor, end of current column, and end of screen */
3551 offset = pscreen_offset_from_cord(pTTYInfo->nRow, pTTYInfo->nColumn, pTTYInfo);
3553 colEnd = (pTTYInfo->nRow + 1) * pTTYInfo->actNColumn;
3554 screenEnd = pTTYInfo->actNRow * pTTYInfo->actNColumn;
3557 /* Text is allowed to wrap around to subsequent lines, but not past end
3558 * of screen */
3559 endOffset = offset + nLength;
3560 if (endOffset >= screenEnd) {
3561 nLength = screenEnd - offset;
3562 endOffset = offset + nLength - 1; /* Last cell, not one past last */
3566 /* Calculate bounding rectangle. */
3567 if (endOffset <= colEnd) {
3568 /* Single line. */
3570 screenwidth = scrwidth(lpText, nLength);
3572 rect.left = (pTTYInfo->nColumn * pTTYInfo->xChar) + pTTYInfo->xOffset;
3573 rect.right = rect.left + (pTTYInfo->xChar * screenwidth);
3574 rect.top = (pTTYInfo->nRow * pTTYInfo->yChar) + pTTYInfo->yOffset;
3575 rect.bottom = rect.top + pTTYInfo->yChar;
3576 /* Advance cursor on cur line but not past end. */
3577 pTTYInfo->nColumn = (CORD)MIN(pTTYInfo->nColumn + screenwidth,
3578 pTTYInfo->actNColumn - 1);
3580 else {
3581 /* Wraps across multiple lines. Calculate one rect to cover all
3582 * lines. */
3583 rect.left = 0;
3584 rect.right = pTTYInfo->xSize;
3585 rect.top = (pTTYInfo->nRow * pTTYInfo->yChar) + pTTYInfo->yOffset;
3586 rect.bottom = ((((offset + nLength) / pTTYInfo->actNColumn) + 1) *
3587 pTTYInfo->yChar) + pTTYInfo->yOffset;
3588 pTTYInfo->nRow = (CORD)(endOffset / pTTYInfo->actNColumn);
3589 pTTYInfo->nColumn = (CORD)(endOffset % pTTYInfo->actNColumn);
3593 /* Apply text and attributes to screen in one smooth motion. */
3594 for(i = 0; i < nLength; i++)
3595 (pTTYInfo->pScreen+offset)[i] = lpText[i];
3596 for(i = 0; i < nLength; i++)
3597 (pTTYInfo->pCellWidth+offset)[i] = wcellwidth((UCS)lpText[i]) * pTTYInfo->xChar;
3598 for(i = 0; i < nLength; i++)
3599 pTTYInfo->pAttrib[offset+i] = pTTYInfo->curAttrib;
3601 /* Invalidate rectangle */
3602 pTTYInfo->screenDirty = TRUE;
3603 InvalidateRect (hWnd, &rect, FALSE);
3604 return (TRUE);
3608 /*---------------------------------------------------------------------------
3609 * BOOL WriteTTYChar (HWND hWnd, char ch)
3611 * Description:
3612 * Write a single character to the cursor position and advance the
3613 * cursor. Does not handle carage control.
3615 * Parameters:
3616 * HWND hWnd
3617 * handle to TTY window
3619 * char ch
3620 * character being written.
3622 /*--------------------------------------------------------------------------*/
3623 LOCAL BOOL
3624 WriteTTYChar (HWND hWnd, TCHAR ch)
3626 PTTYINFO pTTYInfo;
3627 RECT rect;
3628 long offset;
3631 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
3632 if (pTTYInfo == NULL)
3633 return (FALSE);
3635 offset = (pTTYInfo->nRow * pTTYInfo->actNColumn) +
3636 pTTYInfo->nColumn;
3638 *(pTTYInfo->pScreen + offset) = ch;
3639 pTTYInfo->pCellWidth[offset] = wcellwidth((UCS)ch) * pTTYInfo->xChar;
3640 pTTYInfo->pAttrib[offset] = pTTYInfo->curAttrib;
3642 rect.left = (pTTYInfo->nColumn * pTTYInfo->xChar) + pTTYInfo->xOffset;
3643 rect.right = rect.left + pTTYInfo->xChar;
3644 rect.top = (pTTYInfo->nRow * pTTYInfo->yChar) + pTTYInfo->yOffset;
3645 rect.bottom = rect.top + pTTYInfo->yChar;
3646 pTTYInfo->screenDirty = TRUE;
3647 InvalidateRect (hWnd, &rect, FALSE);
3651 /* Line Wrap. */
3652 if (pTTYInfo->nColumn < pTTYInfo->actNColumn - 1)
3653 pTTYInfo->nColumn++ ;
3654 else if ((pTTYInfo->autoWrap == WRAP_ON ||
3655 pTTYInfo->autoWrap == WRAP_NO_SCROLL) &&
3656 pTTYInfo->nRow < pTTYInfo->actNRow - 1) {
3657 pTTYInfo->nRow++;
3658 pTTYInfo->nColumn = 0;
3660 return (TRUE);
3664 /*---------------------------------------------------------------------------
3665 * VOID GoModalDialogBoxParam( HINSTANCE hInstance,
3666 * LPTSTR lpszTemplate, HWND hWnd,
3667 * DLGPROC lpDlgProc, LPARAM lParam )
3669 * Description:
3670 * It is a simple utility function that simply performs the
3671 * MPI and invokes the dialog box with a DWORD parameter.
3673 * Parameters:
3674 * similar to that of DialogBoxParam() with the exception
3675 * that the lpDlgProc is not a procedure instance
3677 /*--------------------------------------------------------------------------*/
3678 LOCAL VOID
3679 GoModalDialogBoxParam( HINSTANCE hInstance, LPTSTR lpszTemplate,
3680 HWND hWnd, DLGPROC lpDlgProc, LPARAM lParam )
3682 DLGPROC lpProcInstance ;
3684 lpProcInstance = (DLGPROC) MakeProcInstance( (FARPROC) lpDlgProc,
3685 hInstance ) ;
3686 DialogBoxParam( hInstance, lpszTemplate, hWnd, lpProcInstance, lParam ) ;
3687 FreeProcInstance( (FARPROC) lpProcInstance ) ;
3691 /*---------------------------------------------------------------------------
3692 * BOOL FAR PASCAL __export AboutDlgProc( HWND hDlg, UINT uMsg,
3693 * WPARAM wParam, LPARAM lParam )
3695 * Description:
3696 * Simulates the Windows System Dialog Box.
3698 * Parameters:
3699 * Same as standard dialog procedures.
3701 /*--------------------------------------------------------------------------*/
3702 BOOL FAR PASCAL __export
3703 AboutDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
3705 switch (uMsg) {
3706 case WM_INITDIALOG:
3708 TCHAR szTemp [81];
3710 /* sets up version number for PINE */
3711 GetDlgItemText (hDlg, IDD_VERSION, szTemp, sizeof(szTemp)/sizeof(TCHAR));
3712 /* szTemp is unicode, mswin_compilation_date etc are cast as %S in mswin.rc */
3713 _sntprintf (TempBuf, sizeof(TempBuf)/sizeof(TCHAR), szTemp, mswin_specific_winver(),
3714 mswin_majorver(), mswin_minorver(),
3715 mswin_compilation_remarks(),
3716 mswin_compilation_date());
3717 SetDlgItemText (hDlg, IDD_VERSION, (LPTSTR) TempBuf);
3719 /* get by-line */
3720 LoadString (GET_HINST (hDlg), IDS_BYLINE, TempBuf,
3721 sizeof(TempBuf) / sizeof(TCHAR));
3722 SetDlgItemText (hDlg, IDD_BYLINE, TempBuf);
3725 return ( TRUE ) ;
3727 case WM_CLOSE:
3728 EndDialog( hDlg, TRUE ) ;
3729 return ( TRUE ) ;
3731 case WM_COMMAND:
3732 switch((WORD) wParam){
3733 case IDD_OK :
3734 EndDialog( hDlg, TRUE ) ;
3735 return ( TRUE ) ;
3737 default :
3738 break;
3741 break;
3743 return ( FALSE ) ;
3745 } /* end of AboutDlgProc() */
3748 /*---------------------------------------------------------------------------
3750 * Description:
3751 * Simulates the Windows System Dialog Box.
3753 * Parameters:
3754 * Same as standard dialog procedures.
3756 /*--------------------------------------------------------------------------*/
3757 BOOL FAR PASCAL __export
3758 SplashDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
3760 static HBITMAP hbmpSplash;
3762 switch (uMsg) {
3763 case WM_INITDIALOG:
3764 if(hbmpSplash = LoadBitmap(GET_HINST(hDlg),
3765 MAKEINTRESOURCE(ALPINESPLASH))){
3766 BITMAP stBitmap;
3767 int cx, cy;
3769 cx = GetSystemMetrics(SM_CXSCREEN);
3770 cy = GetSystemMetrics(SM_CYSCREEN);
3771 GetObject(hbmpSplash, sizeof(BITMAP), &stBitmap);
3773 SetWindowPos(hDlg, HWND_TOPMOST,
3774 (cx - stBitmap.bmWidth) / 2,
3775 (cy - stBitmap.bmHeight) / 2,
3776 stBitmap.bmWidth, stBitmap.bmHeight,
3777 SWP_NOCOPYBITS /* | SWP_SHOWWINDOW */);
3780 return(TRUE);
3782 case WM_CTLCOLORDLG :
3783 return(TRUE);
3785 case WM_ERASEBKGND :
3787 HDC hMemDC;
3788 POINT stPoint;
3789 BITMAP stBitmap;
3790 HGDIOBJ hObject;
3792 if((hMemDC = CreateCompatibleDC((HDC) wParam)) != NULL){
3793 hObject = SelectObject(hMemDC, hbmpSplash);
3794 SetMapMode(hMemDC, GetMapMode((HDC) wParam));
3796 GetObject(hbmpSplash, sizeof(BITMAP), &stBitmap);
3797 stPoint.x = stBitmap.bmWidth;
3798 stPoint.y = stBitmap.bmHeight;
3799 DPtoLP((HDC) wParam, &stPoint, 1);
3801 BitBlt((HDC) wParam,
3802 0, 0, stPoint.x, stPoint.y,
3803 hMemDC, 0, 0, SRCCOPY);
3804 SelectObject(hMemDC, hObject);
3805 DeleteDC(hMemDC) ;
3808 return(TRUE);
3811 break;
3813 case WM_CLOSE:
3814 DestroyWindow(hDlg);
3815 return(TRUE);
3817 case WM_DESTROY :
3818 if(hbmpSplash)
3819 DeleteObject(hbmpSplash);
3821 break;
3823 case WM_COMMAND: /* No commands! */
3824 DestroyWindow(hDlg);
3825 return(TRUE);
3828 return(FALSE);
3833 #if 0
3834 UINT APIENTRY
3835 SelectTTYFontHook(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
3837 switch(uMsg){
3838 case WM_INITDIALOG :
3841 * Deactivate the Style combo box...
3843 HWND hWnd = GetDlgItem(hDlg, cmb2);
3844 EnableWindow(hWnd, FALSE);
3845 SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW);
3846 return(TRUE);
3849 break;
3851 case WM_COMMAND :
3852 switch ((WORD) wParam) {
3853 case psh3 :
3855 LOGFONT curfont;
3857 SendMessage(hDlg, WM_CHOOSEFONT_GETLOGFONT,
3858 0, (LPARAM) &curfont);
3859 ResetTTYFont (ghTTYWnd, gpTTYInfo, &curfont);
3860 return (TRUE);
3863 break;
3865 default :
3866 break;
3869 break;
3871 default :
3872 break;
3875 return(FALSE);
3877 #endif
3880 /*---------------------------------------------------------------------------
3881 * BOOL SelectTTYFont( HWND hDlg )
3883 * Description:
3884 * Selects the current font for the TTY screen.
3885 * Uses the Common Dialog ChooseFont() API.
3887 * Parameters:
3888 * HWND hDlg
3889 * handle to settings dialog
3891 /*--------------------------------------------------------------------------*/
3892 LOCAL BOOL
3893 SelectTTYFont (HWND hWnd)
3895 CHOOSEFONT cfTTYFont;
3896 LOGFONT newFont, origFont;
3897 PTTYINFO pTTYInfo;
3899 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
3900 if (pTTYInfo == NULL)
3901 return (FALSE);
3903 memcpy (&newFont, &gpTTYInfo->lfTTYFont, sizeof (LOGFONT));
3904 memcpy (&origFont, &gpTTYInfo->lfTTYFont, sizeof (LOGFONT));
3906 cfTTYFont.lStructSize = sizeof (CHOOSEFONT);
3907 cfTTYFont.hwndOwner = hWnd ;
3908 cfTTYFont.hDC = NULL ;
3909 cfTTYFont.lpLogFont = &newFont;
3910 cfTTYFont.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY |
3911 CF_INITTOLOGFONTSTRUCT |
3912 #if 0
3913 CF_FORCEFONTEXIST | CF_LIMITSIZE |
3914 CF_ENABLEHOOK | CF_APPLY;
3915 #else
3916 CF_FORCEFONTEXIST | CF_LIMITSIZE;
3917 #endif
3918 cfTTYFont.nSizeMin = FONT_MIN_SIZE;
3919 cfTTYFont.nSizeMax = FONT_MAX_SIZE;
3920 cfTTYFont.lCustData = (long) 0 ;
3921 #if 0
3922 cfTTYFont.lpfnHook = SelectTTYFontHook ;
3923 #else
3924 cfTTYFont.lpfnHook = NULL;
3925 #endif
3926 cfTTYFont.lpTemplateName = NULL ;
3927 cfTTYFont.hInstance = GET_HINST (hWnd);
3931 if (ChooseFont (&cfTTYFont)) {
3932 ResetTTYFont (hWnd, pTTYInfo, &newFont);
3934 #if 0
3935 else{
3936 ResetTTYFont (hWnd, pTTYInfo, &origFont);
3938 #endif
3940 return (TRUE);
3945 * Set a specific color (foreground, background, reverse, normal) to
3946 * the color specified by name.
3948 LOCAL void
3949 SetColorAttribute (COLORREF *cf, char *colorName)
3951 /* color name not in table. Try converting RGB string. */
3952 ConvertRGBString (colorName, cf);
3954 /* Redraw screen. */
3955 gpTTYInfo->screenDirty = TRUE;
3956 gpTTYInfo->eraseScreen = TRUE;
3957 InvalidateRect (ghTTYWnd, NULL, FALSE);
3962 * Set current color attribute to reverse color
3964 void
3965 SetReverseColor()
3967 FlushWriteAccum ();
3968 gpTTYInfo->curAttrib.rgbFG = gpTTYInfo->rgbRFGColor;
3969 gpTTYInfo->curAttrib.rgbBG = gpTTYInfo->rgbRBGColor;
3974 * Convert a string to an integer.
3976 LOCAL BOOL
3977 ScanInt (char *str, int min, int max, int *val)
3979 char *c;
3980 int v;
3981 int neg = 1;
3984 if (str == NULL) return (FALSE);
3985 if (*str == '\0' || strlen (str) > 9) return (FALSE);
3987 /* Check for a negative sign. */
3988 if (*str == '-') {
3989 neg = -1;
3990 ++str;
3993 /* Check for all digits. */
3994 for (c = str; *c != '\0'; ++c) {
3995 if (!isdigit((unsigned char)*c))
3996 return (FALSE);
3999 /* Convert from ascii to int. */
4000 v = atoi (str) * neg;
4002 /* Check constraints. */
4003 if (v < min || v > max)
4004 return (FALSE);
4005 *val = v;
4006 return (TRUE);
4011 * Convert a RGB string to a color ref. The string should look like:
4012 * rrr,ggg,bbb
4013 * where rrr, ggg, and bbb are numbers between 0 and 255 that represent
4014 * red, gree, and blue values. Must be comma separated.
4015 * Returns:
4016 * TRUE - Successfully converted string.
4017 * FALSE - Bad format, 'cf' unchanged.
4019 LOCAL BOOL
4020 ConvertRGBString (char *colorName, COLORREF *cf)
4022 int i, j, n, rgb[3];
4023 MSWINColor *ct;
4025 if(!colorName)
4026 return(FALSE);
4028 /* Is the name in the global color table? */
4029 for(ct = MSWINColorTable; ct->colorName; ct++)
4030 if(!struncmp(ct->colorName, colorName, (int)strlen(ct->colorName))){
4031 *cf = ct->colorRef;
4032 return(TRUE);
4035 /* Not a named color, try RRR,GGG,BBB */
4036 for(i = 0; i < 3; i++){
4037 if(i && *colorName++ != ',')
4038 return(FALSE);
4040 for(rgb[i] = 0, j = 0; j < 3; j++)
4041 if((n = *colorName++ - '0') < 0 || n > 9)
4042 return(FALSE);
4043 else
4044 rgb[i] = (rgb[i] * 10) + n;
4047 *cf = RGB (rgb[0], rgb[1], rgb[2]);
4048 return (TRUE);
4052 LOCAL char *
4053 ConvertStringRGB(char *colorName, size_t ncolorName, COLORREF colorRef)
4055 MSWINColor *cf;
4057 for(cf = MSWINColorTable;
4058 cf->colorName && cf->colorRef != colorRef;
4059 cf++)
4062 if(cf->colorName){
4063 strncpy(colorName, cf->colorName, ncolorName);
4064 colorName[ncolorName-1] = '\0';
4066 else
4067 snprintf(colorName, ncolorName, "%.3d,%.3d,%.3d",
4068 GetRValue(colorRef), GetGValue(colorRef), GetBValue(colorRef));
4070 return(colorName);
4075 * Map from integer color value to canonical color name.
4077 char *
4078 colorx(int color)
4080 MSWINColor *ct;
4081 static char cbuf[RGBLEN+1];
4083 if(color < fullColorTableSize){
4084 ct = &MSWINColorTable[color];
4085 if(ct->canonicalName)
4086 return(ct->canonicalName);
4089 /* not supposed to get here */
4090 snprintf(cbuf, sizeof(cbuf), "color%03.3d", color);
4091 return(cbuf);
4096 * Argument is a color name which could be an RGB string, a name like "blue",
4097 * or a name like "color011".
4099 * Returns a pointer to the canonical name of the color.
4101 char *
4102 color_to_canonical_name(char *s)
4104 int i, j, n, rgb[3];
4105 MSWINColor *ct;
4106 COLORREF cr;
4107 static char cn[RGBLEN+1];
4109 if(!s)
4110 return(NULL);
4112 if(!struncmp(s, MATCH_NORM_COLOR, RGBLEN) || !struncmp(s, MATCH_NONE_COLOR, RGBLEN))
4113 return(s);
4115 for(ct = MSWINColorTable; ct->colorName; ct++)
4116 if(!struncmp(ct->colorName, s, (int)strlen(ct->colorName)))
4117 break;
4119 if(ct->colorName)
4120 return(ct->canonicalName);
4122 /* maybe it is RGB? */
4123 for(i = 0; i < 3; i++){
4124 if(i && *s++ != ',')
4125 return("");
4127 for(rgb[i] = 0, j = 0; j < 3; j++)
4128 if((n = *s++ - '0') < 0 || n > 9)
4129 return("");
4130 else
4131 rgb[i] = (rgb[i] * 10) + n;
4134 cr = RGB(rgb[0], rgb[1], rgb[2]);
4137 * Now compare that RGB against the color table RGBs. If it is
4138 * in the table, return the canonical name, else return the RGB string.
4140 for(ct = MSWINColorTable; ct->colorName; ct++)
4141 if(ct->colorRef == cr)
4142 break;
4144 if(ct->colorName)
4145 return(ct->canonicalName);
4146 else{
4147 snprintf(cn, sizeof(cn), "%.3d,%.3d,%.3d",
4148 GetRValue(cr), GetGValue(cr), GetBValue(cr));
4149 return(cn);
4154 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4156 * Toolbar setup routines.
4158 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
4159 LOCAL void
4160 TBToggle (HWND hWnd)
4162 PTTYINFO pTTYInfo;
4165 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4166 if (pTTYInfo == NULL)
4167 return;
4169 if (pTTYInfo->toolBarSize > 0)
4170 TBHide (hWnd);
4171 else
4172 TBShow (hWnd);
4176 LOCAL void
4177 TBPosToggle (HWND hWnd)
4179 PTTYINFO pTTYInfo;
4182 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4183 if (pTTYInfo == NULL)
4184 return;
4186 pTTYInfo->toolBarTop = !pTTYInfo->toolBarTop;
4187 if(pTTYInfo->hTBWnd){
4188 TBHide (hWnd);
4189 TBShow (hWnd);
4194 LOCAL void
4195 TBShow (HWND hWnd)
4197 PTTYINFO pTTYInfo;
4198 RECT rc;
4201 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4202 if (pTTYInfo == NULL)
4203 return;
4207 * Make sure the tool bar not already shown.
4209 if (pTTYInfo->toolBarSize > 0)
4210 return;
4215 * Make procinstance for dialog function.
4217 HideCaret (hWnd);
4218 if (gToolBarProc == NULL)
4219 gToolBarProc = (DLGPROC) MakeProcInstance( (FARPROC) ToolBarProc,
4220 ghInstance ) ;
4221 if (gTBBtnProc == NULL)
4222 gTBBtnProc = (WNDPROC) MakeProcInstance( (FARPROC) TBBtnProc,
4223 ghInstance ) ;
4227 * Create the dialog box.
4229 pTTYInfo->hTBWnd = CreateDialog (ghInstance,
4230 MAKEINTRESOURCE (pTTYInfo->curToolBarID),
4231 hWnd,
4232 gToolBarProc);
4233 if (pTTYInfo->hTBWnd == NULL) {
4234 ShowCaret (hWnd);
4235 return;
4238 SetFocus (hWnd);
4242 * Adjust the window size.
4244 GetWindowRect (pTTYInfo->hTBWnd, &rc); /* Get Toolbar size. */
4245 pTTYInfo->toolBarSize = (CORD)(rc.bottom - rc.top);
4247 GetClientRect (hWnd, &rc); /* Get TTY window size. */
4248 SizeTTY (hWnd, 0, (CORD)rc.bottom, (CORD)rc.right);
4249 ShowCaret (hWnd);
4253 LOCAL void
4254 TBHide (HWND hWnd)
4256 PTTYINFO pTTYInfo;
4257 RECT rc;
4259 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4260 if (pTTYInfo == NULL)
4261 return;
4264 if (pTTYInfo->toolBarSize == 0)
4265 return;
4267 DestroyWindow (pTTYInfo->hTBWnd);
4268 pTTYInfo->hTBWnd = NULL;
4269 if (pTTYInfo->toolBarBtns != NULL)
4270 MemFree (pTTYInfo->toolBarBtns);
4271 pTTYInfo->toolBarBtns = NULL;
4275 * Adjust the window size.
4277 pTTYInfo->toolBarSize = 0;
4278 GetClientRect (hWnd, &rc);
4279 SizeTTY (hWnd, 0, (CORD)rc.bottom, (CORD)rc.right);
4283 LOCAL void
4284 TBSwap (HWND hWnd, int newID)
4286 PTTYINFO pTTYInfo;
4287 RECT rc;
4289 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4290 if (pTTYInfo == NULL)
4291 return;
4293 if (pTTYInfo->toolBarSize == 0 || pTTYInfo->curToolBarID == newID)
4294 return;
4297 * Dispose of old tool bar window.
4299 HideCaret (hWnd);
4301 DestroyWindow (pTTYInfo->hTBWnd);
4302 pTTYInfo->hTBWnd = NULL;
4303 if (pTTYInfo->toolBarBtns != NULL)
4304 MemFree (pTTYInfo->toolBarBtns);
4305 pTTYInfo->toolBarBtns = NULL;
4310 * Create the new dialog box.
4312 pTTYInfo->hTBWnd = CreateDialog (ghInstance,
4313 MAKEINTRESOURCE (newID),
4314 hWnd,
4315 gToolBarProc);
4316 if (pTTYInfo->hTBWnd == NULL) {
4317 ShowCaret (hWnd);
4318 return;
4320 pTTYInfo->curToolBarID = newID;
4321 SetFocus (hWnd); /* Return focus to parent. */
4325 * Fit new tool bar into old tool bars position. This assumes that
4326 * all tool bars are about the same height.
4328 GetClientRect (hWnd, &rc); /* Get TTY window size. */
4329 if (pTTYInfo->toolBarTop)
4330 /* Position at top of window. */
4331 SetWindowPos (pTTYInfo->hTBWnd, HWND_TOP,
4332 0, 0,
4333 rc.right, pTTYInfo->toolBarSize,
4334 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
4335 else
4336 /* Position at bottom of window. */
4337 SetWindowPos (pTTYInfo->hTBWnd, HWND_TOP,
4338 0, pTTYInfo->ySize - pTTYInfo->toolBarSize,
4339 rc.right, pTTYInfo->toolBarSize,
4340 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
4342 ShowCaret (hWnd);
4346 BOOL FAR PASCAL __export
4347 ToolBarProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
4349 RECT rc;
4350 BOOL ret;
4351 int height;
4352 HBRUSH hBrush;
4353 HWND hCld;
4354 int btnCount;
4355 int i;
4356 PTTYINFO pTTYInfo;
4359 pTTYInfo = gpTTYInfo;
4361 ret = FALSE;
4362 switch (msg) {
4364 case WM_INITDIALOG:
4365 /* Fit dialog to window. */
4366 GetWindowRect (hWnd, &rc);
4367 height = rc.bottom - rc.top;
4368 GetClientRect (GetParent (hWnd), &rc);
4369 SetWindowPos (hWnd, HWND_TOP, 0, 0, rc.right, height,
4370 SWP_NOZORDER | SWP_NOACTIVATE);
4372 /* Count child windows.*/
4373 btnCount = 0;
4374 for (hCld = GetWindow (hWnd, GW_CHILD);
4375 hCld;
4376 hCld = GetWindow (hCld, GW_HWNDNEXT))
4377 ++btnCount;
4379 /* Allocate a list of previous child procs. */
4380 if (pTTYInfo->toolBarBtns != NULL)
4381 MemFree (pTTYInfo->toolBarBtns);
4382 pTTYInfo->toolBarBtns = MemAlloc (sizeof (BtnList) * (btnCount + 1));
4384 /* Subclass all child windows. */
4385 for (i = 0, hCld = GetWindow (hWnd, GW_CHILD);
4386 hCld;
4387 ++i, hCld = GetWindow (hCld, GW_HWNDNEXT)) {
4388 pTTYInfo->toolBarBtns[i].wndID = GET_ID (hCld);
4389 pTTYInfo->toolBarBtns[i].wndProc =
4390 (WNDPROC)(LONG_PTR)MyGetWindowLongPtr (hCld,
4391 GWLP_WNDPROC);
4392 MySetWindowLongPtr (hCld, GWLP_WNDPROC, (void *)(LONG_PTR)TBBtnProc);
4394 pTTYInfo->toolBarBtns[i].wndID = 0;
4395 pTTYInfo->toolBarBtns[i].wndProc = NULL;
4397 ret = FALSE;
4398 break;
4401 case WM_COMMAND:
4402 if (wParam >= KS_RANGESTART && wParam <= KS_RANGEEND){
4403 ProcessMenuItem (GetParent (hWnd), wParam);
4404 /* Set input focus back to parent. */
4405 SetFocus (GetParent (hWnd));
4406 ret = TRUE;
4407 break;
4409 break;
4411 #ifdef WIN32
4412 case WM_CTLCOLORBTN:
4413 #else
4414 case WM_CTLCOLOR:
4415 #endif
4416 if (HIWORD (lParam) == CTLCOLOR_DLG) {
4417 if(pTTYInfo->hTBBrush != NULL){
4418 DeleteObject(pTTYInfo->hTBBrush);
4419 pTTYInfo->hTBBrush = NULL;
4422 hBrush = CreateSolidBrush (GetSysColor (COLOR_ACTIVEBORDER));
4423 return ((BOOL)!!(pTTYInfo->hTBBrush = hBrush));
4426 return (ret);
4431 * Subclass toolbar button windows.
4433 * These buttons will automatically return the input focus to
4434 * the toolbar's parent
4436 LRESULT FAR PASCAL __export
4437 TBBtnProc (HWND hBtn, UINT uMsg, WPARAM wParam, LPARAM lParam)
4439 PTTYINFO pTTYInfo;
4440 HWND hPrnt;
4441 int i;
4442 WORD id;
4443 LRESULT ret;
4444 WNDPROC wndProc;
4448 * Find previous window proc.
4450 pTTYInfo = gpTTYInfo;
4451 id = GET_ID (hBtn);
4452 for (i = 0; pTTYInfo->toolBarBtns[i].wndID != 0; ++i)
4453 if (pTTYInfo->toolBarBtns[i].wndID == id)
4454 goto FoundWindow;
4455 /* Whoops! Didn't find window, don't know how to pass message. */
4456 return (0);
4459 FoundWindow:
4460 wndProc = pTTYInfo->toolBarBtns[i].wndProc;
4464 if (uMsg == WM_LBUTTONUP || uMsg == WM_MBUTTONUP || uMsg == WM_RBUTTONUP) {
4466 * On mouse button up restore input focus to IDC_RESPONCE, which
4467 * processes keyboard input.
4469 ret = CallWindowProc (wndProc, hBtn, uMsg, wParam, lParam);
4470 hPrnt = GetParent (GetParent (hBtn));
4471 if (hPrnt)
4472 SetFocus (hPrnt);
4473 return (ret);
4476 return (CallWindowProc (wndProc, hBtn, uMsg, wParam, lParam));
4481 * return bitmap of allowed Edit Menu items
4483 LOCAL UINT
4484 UpdateEditAllowed(HWND hWnd)
4486 PTTYINFO pTTYInfo;
4487 UINT fAccel = EM_NONE;
4489 if((pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO)) != NULL){
4490 if(EditPasteAvailable())
4491 fAccel |= (EM_PST | EM_PST_ABORT);
4492 else if(IsClipboardFormatAvailable (CF_UNICODETEXT) && gPasteEnabled)
4493 fAccel |= EM_PST;
4495 if(SelAvailable()){
4496 fAccel |= (EM_CP | EM_CP_APPEND);
4498 else{
4499 if(gAllowCut)
4500 fAccel |= EM_CUT;
4502 if(gAllowCopy)
4503 fAccel |= (EM_CP | EM_CP_APPEND);
4506 if (pTTYInfo->menuItems[KS_WHEREIS - KS_RANGESTART].miActive)
4507 fAccel |= EM_FIND;
4509 return(fAccel);
4513 #ifdef ACCELERATORS
4514 #ifdef ACCELERATORS_OPT
4515 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4517 * Accelorator key routines.
4519 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
4520 LOCAL void
4521 AccelCtl (HWND hWnd, int ctl, BOOL saveChange)
4523 PTTYINFO pTTYInfo;
4524 BOOL load, changed;
4527 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4528 if (pTTYInfo == NULL)
4529 return;
4531 switch (ctl) {
4532 case ACCEL_LOAD :
4533 load = TRUE;
4534 break;
4535 case ACCEL_UNLOAD :
4536 load = FALSE;
4537 break;
4538 case ACCEL_TOGGLE :
4539 load = pTTYInfo->hAccel == NULL;
4540 break;
4541 default :
4542 load = FALSE;
4543 break;
4546 changed = FALSE;
4547 if (load && pTTYInfo->hAccel == NULL) {
4548 /* Load em up. */
4549 pTTYInfo->hAccel = LoadAccelerators (ghInstance,
4550 MAKEINTRESOURCE (IDR_ACCEL_PINE));
4551 changed = TRUE;
4553 else if(!load && pTTYInfo->hAccel) {
4554 /* unload em. */
4555 FreeResource (pTTYInfo->hAccel);
4556 pTTYInfo->hAccel = NULL;
4557 changed = TRUE;
4560 if (changed && saveChange)
4561 DidResize (pTTYInfo);
4563 #endif
4566 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4568 * Accelorator key routines.
4570 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
4571 LOCAL void
4572 AccelManage (HWND hWnd, long accels)
4574 PTTYINFO pTTYInfo;
4575 ACCEL accelarray[EM_MAX_ACCEL];
4576 int n;
4577 static ACCEL am_cp = {
4578 FVIRTKEY | FCONTROL | FSHIFT | FNOINVERT, 'C', IDM_EDIT_COPY
4580 static ACCEL am_cp_append = {
4581 FVIRTKEY | FCONTROL | FALT | FNOINVERT, 'C', IDM_EDIT_COPY_APPEND
4583 static ACCEL am_find = {
4584 FVIRTKEY | FCONTROL | FSHIFT | FNOINVERT, 'F', IDM_MI_WHEREIS
4586 static ACCEL am_pst = {
4587 FVIRTKEY | FCONTROL | FSHIFT | FNOINVERT, 'V', IDM_EDIT_PASTE
4589 static ACCEL am_pst_abort = {
4590 FVIRTKEY | FCONTROL | FALT | FNOINVERT, 'V', IDM_EDIT_CANCEL_PASTE
4592 static ACCEL am_cut = {
4593 FVIRTKEY | FCONTROL | FSHIFT | FNOINVERT, 'X', IDM_EDIT_CUT
4596 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
4597 if (pTTYInfo == NULL || pTTYInfo->fAccel == (UINT)accels)
4598 return;
4600 if(pTTYInfo->hAccel){
4601 DestroyAcceleratorTable(pTTYInfo->hAccel);
4602 pTTYInfo->hAccel = NULL;
4603 pTTYInfo->fAccel = EM_NONE;
4606 n = 0;
4608 if(accels & EM_CP)
4609 accelarray[n++] = am_cp;
4611 if(accels & EM_CP_APPEND)
4612 accelarray[n++] = am_cp_append;
4614 if(accels & EM_FIND)
4615 accelarray[n++] = am_find;
4617 if(accels & EM_PST)
4618 accelarray[n++] = am_pst;
4620 if(accels & EM_PST_ABORT)
4621 accelarray[n++] = am_pst_abort;
4623 if(accels & EM_CUT)
4624 accelarray[n++] = am_cut;
4626 /* Load em up. */
4627 if(n && (pTTYInfo->hAccel = CreateAcceleratorTable(accelarray, n)))
4628 pTTYInfo->fAccel = accels;
4629 else
4630 pTTYInfo->fAccel = EM_NONE;
4634 LOCAL void
4635 UpdateAccelerators (HWND hWnd)
4637 AccelManage (hWnd, UpdateEditAllowed(hWnd));
4639 #endif
4642 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4644 * Mouse Selection routines
4646 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
4648 LOCAL BOOL SelSelected = FALSE;
4649 LOCAL BOOL SelTracking = FALSE;
4650 LOCAL int SelAnchorRow;
4651 LOCAL int SelAnchorCol;
4652 LOCAL int SelPointerRow;
4653 LOCAL int SelPointerCol;
4654 typedef struct {
4655 TCHAR *pRow;
4656 int len;
4657 } CopyRow;
4660 LOCAL void
4661 SelRSet (int oStart, int oEnd)
4663 CharAttrib *pca;
4665 for (pca = gpTTYInfo->pAttrib + oStart; oStart < oEnd; ++pca, ++oStart)
4666 pca->style |= CHAR_ATTR_SEL;
4670 LOCAL void
4671 SelRClear (int oStart, int oEnd)
4673 CharAttrib *pca;
4675 for (pca = gpTTYInfo->pAttrib + oStart; oStart < oEnd; ++pca, ++oStart)
4676 pca->style &= ~CHAR_ATTR_SEL;
4680 LOCAL void
4681 SelRInvalidate (int oStart, int oEnd)
4683 RECT rect;
4684 int sRow, sCol;
4685 int eRow, eCol;
4687 sRow = oStart / gpTTYInfo->actNColumn;
4688 sCol = oStart % gpTTYInfo->actNColumn;
4689 eRow = oEnd / gpTTYInfo->actNColumn;
4690 eCol = oEnd % gpTTYInfo->actNColumn;
4692 rect.top = (sRow * gpTTYInfo->yChar) + gpTTYInfo->yOffset;
4693 rect.bottom = ((eRow+1) * gpTTYInfo->yChar) + gpTTYInfo->yOffset;
4694 if (sRow == eRow) {
4695 rect.left = (sCol * gpTTYInfo->xChar) + gpTTYInfo->xOffset;
4696 rect.right = ((eCol+1) * gpTTYInfo->xChar) + gpTTYInfo->xOffset;
4697 } else {
4698 rect.left = gpTTYInfo->xOffset;
4699 rect.right = (gpTTYInfo->actNColumn * gpTTYInfo->xChar) +
4700 gpTTYInfo->xOffset;
4702 InvalidateRect (ghTTYWnd, &rect, FALSE);
4707 * Start a mouse selection.
4709 LOCAL void
4710 SelStart (int nRow, int nColumn)
4712 SelClear ();
4713 SelTracking = TRUE;
4714 SelSelected = TRUE;
4715 SelPointerRow = SelAnchorRow = nRow;
4716 SelPointerCol = SelAnchorCol = nColumn;
4717 return;
4722 * Finish a mouse selection.
4724 LOCAL void
4725 SelFinish (int nRow, int nColumn)
4727 if (nRow == SelAnchorRow && nColumn == SelAnchorCol) {
4728 /* Mouse up in same place it went down - no selection. */
4729 SelClear ();
4731 else {
4732 /* Update screen selection and set final position of mouse
4733 * then turn of mouse tracking. Selection remains in effect
4734 * until SelClear is called. */
4735 SelTrackMouse (nRow, nColumn);
4736 SelTracking = FALSE;
4741 LOCAL void
4742 SelClear (void)
4744 int a, p;
4745 int s, e;
4747 if (!SelSelected)
4748 return;
4750 /* Convert the anchor and point coordinates to offsets then
4751 * order the offsets. */
4752 a = (SelAnchorRow * gpTTYInfo->actNColumn) + SelAnchorCol;
4753 p = (SelPointerRow * gpTTYInfo->actNColumn) + SelPointerCol;
4754 if (a < p) {
4755 s = a;
4756 e = p;
4757 } else {
4758 s = p;
4759 e = a;
4762 /* Clear selected attribute of those cells in range. */
4763 SelRClear (s, e);
4764 SelRInvalidate (s, e);
4765 SelSelected = FALSE;
4766 SelTracking = FALSE;
4771 * Update the position of the mouse point.
4773 LOCAL void
4774 SelTrackXYMouse (int xPos, int yPos)
4776 int nRow;
4777 int nColumn;
4779 nColumn = (xPos - gpTTYInfo->xOffset) / gpTTYInfo->xChar;
4780 nRow = (yPos - gpTTYInfo->yOffset) / gpTTYInfo->yChar;
4782 SelTrackMouse (nRow, nColumn);
4787 * Update the position of the mouse point.
4789 LOCAL void
4790 SelTrackMouse (int nRow, int nColumn)
4792 int a, p, n;
4794 if (!SelTracking)
4795 return;
4797 /* Constrain the cel position to be on the screen. But allow
4798 * for the Column to be one past the right edge of the screen so
4799 * the user can select the right most cel of a row. */
4800 nColumn = MAX(0, nColumn);
4801 nColumn = MIN(gpTTYInfo->actNColumn, nColumn);
4802 nRow = MAX(0, nRow);
4803 nRow = MIN(gpTTYInfo->actNRow-1, nRow);
4806 /* Convert the anchor, previous mouse position, and new mouse
4807 * position to offsets. */
4808 a = (SelAnchorRow * gpTTYInfo->actNColumn) + SelAnchorCol;
4809 p = (SelPointerRow * gpTTYInfo->actNColumn) + SelPointerCol;
4810 n = (nRow * gpTTYInfo->actNColumn) + nColumn;
4812 /* If previous position same as current position, do nothing. */
4813 if (p == n)
4814 return;
4816 /* there are six possible orderings of the points, each with
4817 * a different action:
4818 * order clear set redraw
4819 * n p a n - p n - p
4820 * p n a p - n p - n
4821 * p a n p - a a - n p - n
4822 * a p n p - n p - n
4823 * a n p n - p n - p
4824 * n a p a - p n - a n - p
4826 if (p < a) {
4827 if (n < a) {
4828 if (n < p) {
4829 SelRSet (n, p);
4830 SelRInvalidate (n, p);
4831 } else {
4832 SelRClear (p, n);
4833 SelRInvalidate (p, n);
4835 } else {
4836 SelRClear (p, a);
4837 SelRSet (a, n);
4838 SelRInvalidate (p, n);
4840 } else {
4841 if (n > a) {
4842 if (n > p) {
4843 SelRSet (p, n);
4844 SelRInvalidate (p, n);
4845 } else {
4846 SelRClear (n, p);
4847 SelRInvalidate (n, p);
4849 } else {
4850 SelRClear (a, p);
4851 SelRSet (n, a);
4852 SelRInvalidate (n, p);
4856 /* Set new pointer. */
4857 SelPointerRow = nRow;
4858 SelPointerCol = nColumn;
4862 LOCAL BOOL
4863 SelAvailable (void)
4865 return (SelSelected);
4870 * Copy screen data to clipboard. Actually appends data from screen to
4871 * existing handle so as we can implement a "Copy Append" to append to
4872 * existing clipboard data.
4874 * The screen does not have real line terminators. We decide where the
4875 * actual screen data ends by scanning the line (row) from end backwards
4876 * to find the first non-space.
4878 * I don't know how many bytes of data I'll be appending to the clipboard.
4879 * So I implemented in two passes. The first finds all the row starts
4880 * and length while the second copies the data.
4882 LOCAL void
4883 SelDoCopy (HANDLE hCB, DWORD lenCB)
4885 HANDLE newCB; /* Used in reallocation. */
4886 TCHAR *pCB; /* Points to CB data. */
4887 TCHAR *p2; /* Temp pointer to screen data. */
4888 int sRow, eRow; /* Start and End Rows. */
4889 int sCol, eCol; /* Start and End columns. */
4890 int row, c1, c2; /* temp row and column indexes. */
4891 int totalLen; /* total len of new data. */
4892 CopyRow *rowTable, *rp; /* pointers to table of rows. */
4893 BOOL noLastCRLF = FALSE;
4896 if (OpenClipboard (ghTTYWnd)) { /* ...and we get the CB. */
4897 if (EmptyClipboard ()) { /* ...and clear previous CB.*/
4900 /* Find the start and end row and column. */
4901 if ( (SelAnchorRow * gpTTYInfo->actNColumn) + SelAnchorCol <
4902 (SelPointerRow * gpTTYInfo->actNColumn) + SelPointerCol) {
4903 sRow = SelAnchorRow;
4904 sCol = SelAnchorCol;
4905 eRow = SelPointerRow;
4906 eCol = SelPointerCol;
4908 else {
4909 sRow = SelPointerRow;
4910 sCol = SelPointerCol;
4911 eRow = SelAnchorRow;
4912 eCol = SelAnchorCol;
4915 /* Allocate a table in which we store info on rows. */
4916 rowTable = (CopyRow *) MemAlloc (sizeof (CopyRow) * (eRow-sRow+1));
4917 if (rowTable == NULL)
4918 goto Fail1;
4920 /* Find the start and length of each row. */
4921 totalLen = 0;
4922 for (row = sRow, rp = rowTable; row <= eRow; ++row, ++rp) {
4923 /* Find beginning and end columns, which depends on if
4924 * this is the first or last row in the selection. */
4925 c1 = (row == sRow ? sCol : 0);
4926 c2 = (row == eRow ? eCol : gpTTYInfo->actNColumn);
4928 /* Calculate pointer to beginning of this line. */
4929 rp->pRow = gpTTYInfo->pScreen +
4930 ((row * gpTTYInfo->actNColumn) + c1);
4932 /* Back down from end column to find first non space.
4933 * noLastCRLF indicates if it looks like the selection
4934 * should include a CRLF on the end of the line. It
4935 * gets set for each line, but only the setting for the
4936 * last line in the selection is remembered (which is all
4937 * we're interested in). */
4938 p2 = gpTTYInfo->pScreen +
4939 ((row * gpTTYInfo->actNColumn) + c2);
4940 noLastCRLF = TRUE;
4941 while (c2 > c1) {
4942 if (*(p2-1) != (TCHAR)' ')
4943 break;
4944 noLastCRLF = FALSE;
4945 --c2;
4946 --p2;
4949 /* Calculate size of line, then increment totalLen plus 2 for
4950 * the CRLF which will terminate each line. */
4951 rp->len = c2 - c1;
4952 totalLen += rp->len + 2;
4955 /* Reallocate the memory block. Add one byte for null terminator. */
4956 newCB = GlobalReAlloc (hCB, (lenCB + totalLen + 1)*sizeof(TCHAR), 0);
4957 if (newCB == NULL)
4958 goto Fail2;
4959 hCB = newCB;
4961 pCB = GlobalLock (hCB);
4962 if (pCB == NULL)
4963 goto Fail2;
4965 /* Append each of the rows, deliminated by a CRLF. */
4966 pCB += lenCB;
4967 for (row = sRow, rp = rowTable; row <= eRow; ++row, ++rp) {
4968 if (rp->len > 0) {
4969 memcpy (pCB, rp->pRow, rp->len * sizeof(TCHAR));
4970 pCB += rp->len;
4972 if (row < eRow || !noLastCRLF) {
4973 *pCB++ = (TCHAR)ASCII_CR;
4974 *pCB++ = (TCHAR)ASCII_LF;
4977 *pCB = (TCHAR)'\0'; /* Null terminator. */
4978 MemFree (rowTable);
4979 GlobalUnlock (hCB);
4981 /* Attempt to pass the data to the clipboard, then release clipboard
4982 * and exit function. */
4983 if (SetClipboardData (CF_UNICODETEXT, hCB) == NULL)
4984 /* Failed! Free the data. */
4985 GlobalFree (hCB);
4986 CloseClipboard ();
4989 return;
4992 /* Error exit. */
4993 Fail2: MemFree (rowTable);
4994 Fail1: GlobalFree (hCB);
4995 CloseClipboard ();
4996 return;
5001 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5003 * Upper Layer Screen routines.
5005 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
5008 * Flush the write accumulator buffer.
5010 LOCAL void
5011 FlushWriteAccum (void)
5013 if (gpTTYInfo->writeAccumCount > 0) {
5014 WriteTTYText (ghTTYWnd, gpTTYInfo->writeAccum,
5015 gpTTYInfo->writeAccumCount);
5016 gpTTYInfo->writeAccumCount = 0;
5022 * Set window's title
5024 void
5025 mswin_settitle(char *utf8_title)
5027 TCHAR buf[256];
5028 LPTSTR lptstr_title;
5030 lptstr_title = utf8_to_lptstr(utf8_title);
5031 _sntprintf(buf, 256, TEXT("%.*s - Alpine"), 80, lptstr_title);
5032 fs_give((void **) &lptstr_title);
5034 SetWindowText(ghTTYWnd, buf);
5039 * Return the application instance.
5041 WINHAND
5042 mswin_gethinstance ()
5044 return ((WINHAND)ghInstance);
5048 WINHAND
5049 mswin_gethwnd ()
5051 return ((WINHAND)ghTTYWnd);
5056 * destroy splash screen
5058 void
5059 mswin_killsplash()
5061 if(ghSplashWnd != NULL){
5062 DestroyWindow(ghSplashWnd);
5063 ghSplashWnd = NULL;
5069 * Called to get mouse event.
5072 mswin_getmouseevent (MEvent * pMouse)
5074 return (MQGet (pMouse));
5079 * Make a pop-up menu and track it
5082 mswin_popup(MPopup *members)
5084 HMENU hMenu;
5085 POINT point;
5086 MPopup *mp;
5087 int n = 1;
5089 if(members && (hMenu = CreatePopupMenu())){
5091 PopupConfig(hMenu, members, &n);
5092 if(GetCursorPos(&point)
5093 && (n = TrackPopupMenu(hMenu,
5094 TPM_LEFTALIGN | TPM_TOPALIGN
5095 | TPM_RIGHTBUTTON | TPM_LEFTBUTTON
5096 | TPM_NONOTIFY | TPM_RETURNCMD,
5097 point.x, point.y, 0, ghTTYWnd, NULL))
5098 && (mp = PopupId(members, n))){
5099 /* Find the member with the internal.id of n */
5100 n = mp->internal.id - 1; /* item's "selectable" index */
5101 switch(mp->type){
5102 case tQueue :
5103 CQAdd (mp->data.val, 0);
5104 break;
5106 case tMessage :
5107 SendMessage(ghTTYWnd, WM_COMMAND, mp->data.msg, 0);
5108 break;
5110 default :
5111 break;
5114 else
5115 n = -1; /* error or nothing selected; same diff */
5117 DestroyMenu(hMenu);
5119 else
5120 n = -1; /* error */
5122 return(n);
5126 LOCAL void
5127 PopupConfig(HMENU hMenu, MPopup *members, int *n)
5129 MENUITEMINFO mitem;
5130 int index;
5131 TCHAR tcbuf[256];
5133 for(index = 0; members->type != tTail; members++, index++){
5134 memset(&mitem, 0, sizeof(MENUITEMINFO));
5135 mitem.cbSize = sizeof(MENUITEMINFO);
5136 mitem.fMask = MIIM_TYPE;
5138 if(members->type == tSubMenu){
5139 mitem.fMask |= MIIM_SUBMENU;
5140 mitem.fType = MFT_STRING;
5141 if(mitem.hSubMenu = CreatePopupMenu()){
5142 /* members->label.string is still just a char * */
5143 _sntprintf(tcbuf, sizeof(tcbuf)/sizeof(TCHAR),
5144 TEXT("%S"), members->label.string);
5145 mitem.dwTypeData = tcbuf;
5146 mitem.cch = (UINT)_tcslen(tcbuf);
5147 InsertMenuItem(hMenu, index, TRUE, &mitem);
5149 PopupConfig(mitem.hSubMenu, members->data.submenu, n);
5152 else{
5153 switch(members->type){
5154 case tSeparator :
5155 mitem.fType = MFT_SEPARATOR;
5156 break;
5158 default :
5159 mitem.fMask |= MIIM_ID;
5160 mitem.wID = members->internal.id = (*n)++;
5161 switch(members->label.style){
5162 case lChecked :
5163 mitem.fMask |= MIIM_STATE;
5164 mitem.fState = MFS_CHECKED;
5165 break;
5167 case lDisabled :
5168 mitem.fMask |= MIIM_STATE;
5169 mitem.fState = MFS_GRAYED;
5170 break;
5172 case lNormal :
5173 default :
5174 break;
5177 mitem.fType = MFT_STRING;
5178 _sntprintf(tcbuf, sizeof(tcbuf)/sizeof(TCHAR),
5179 TEXT("%S"), members->label.string);
5180 mitem.dwTypeData = tcbuf;
5181 mitem.cch = (UINT)_tcslen(tcbuf);
5182 break;
5185 InsertMenuItem(hMenu, index, TRUE, &mitem);
5191 LOCAL MPopup *
5192 PopupId(MPopup *members, int id)
5194 MPopup *mp;
5196 for(; members->type != tTail; members++)
5197 switch(members->type){
5198 case tSubMenu :
5199 if(mp = PopupId(members->data.submenu, id))
5200 return(mp);
5202 break;
5204 case tSeparator :
5205 break;
5207 default :
5208 if(members->internal.id == id)
5209 return(members);
5211 break;
5214 return(NULL);
5219 * Make a pop-up offering Copy/Cut/Paste menu and track it
5221 LOCAL BOOL
5222 CopyCutPopup(HWND hWnd, UINT fAllowed)
5224 MENUITEMINFO mitem;
5225 HMENU hMenu;
5226 POINT point;
5227 BOOL rv = FALSE;
5228 int n = -1;
5231 * If nothing to do just silently return
5233 if(fAllowed != EM_NONE && (hMenu = CreatePopupMenu())){
5234 if(fAllowed & EM_CUT){
5235 /* Insert a "Copy" option */
5236 memset(&mitem, 0, sizeof(MENUITEMINFO));
5237 mitem.cbSize = sizeof(MENUITEMINFO);
5238 mitem.fMask = MIIM_TYPE | MIIM_ID;
5239 mitem.wID = IDM_EDIT_CUT;
5240 mitem.fType = MFT_STRING;
5241 mitem.dwTypeData = TEXT("Cut");
5242 mitem.cch = 3;
5243 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5246 if(fAllowed & EM_CP){
5247 /* Insert a "Copy" option */
5248 memset(&mitem, 0, sizeof(MENUITEMINFO));
5249 mitem.cbSize = sizeof(MENUITEMINFO);
5250 mitem.fMask = MIIM_TYPE | MIIM_ID;
5251 mitem.wID = IDM_EDIT_COPY;
5252 mitem.fType = MFT_STRING;
5253 mitem.dwTypeData = TEXT("Copy");
5254 mitem.cch = 4;
5255 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5258 if(fAllowed & EM_CP_APPEND){
5259 /* Insert a "Copy Append" option */
5260 memset(&mitem, 0, sizeof(MENUITEMINFO));
5261 mitem.cbSize = sizeof(MENUITEMINFO);
5262 mitem.fMask = MIIM_TYPE | MIIM_ID;
5263 mitem.wID = IDM_EDIT_COPY_APPEND;
5264 mitem.fType = MFT_STRING;
5265 mitem.dwTypeData = TEXT("Copy Append");
5266 mitem.cch = 11;
5267 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5270 if(fAllowed & EM_PST){
5271 /* Insert a "Paste" option */
5272 memset(&mitem, 0, sizeof(MENUITEMINFO));
5273 mitem.cbSize = sizeof(MENUITEMINFO);
5274 mitem.fMask = MIIM_TYPE | MIIM_ID;
5275 mitem.wID = IDM_EDIT_PASTE;
5276 mitem.fType = MFT_STRING;
5277 mitem.dwTypeData = TEXT("Paste");
5278 mitem.cch = 5;
5279 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5282 if((fAllowed & EM_SEL_ALL) && !(fAllowed & (EM_CP | EM_CP_APPEND))){
5283 /* Insert a "Select All" option */
5284 memset(&mitem, 0, sizeof(MENUITEMINFO));
5285 mitem.cbSize = sizeof(MENUITEMINFO);
5286 mitem.fMask = MIIM_TYPE | MIIM_ID;
5287 mitem.wID = IDM_EDIT_SEL_ALL;
5288 mitem.fType = MFT_STRING;
5289 mitem.dwTypeData = TEXT("Select &All");
5290 mitem.cch = 11;
5291 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5294 if(n >= 0 && GetCursorPos(&point)){
5295 TrackPopupMenu(hMenu,
5296 TPM_LEFTALIGN | TPM_TOPALIGN
5297 | TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
5298 point.x, point.y, 0, hWnd, NULL);
5299 rv = TRUE;
5302 DestroyMenu(hMenu);
5305 return(rv);
5313 void
5314 pico_popup()
5316 MENUITEMINFO mitem;
5317 HMENU hMenu;
5318 POINT point;
5319 UINT fAllow;
5320 int n = -1;
5323 * If nothing to do just silently return
5325 if(hMenu = CreatePopupMenu()){
5327 if((fAllow = UpdateEditAllowed(ghTTYWnd)) != EM_NONE){
5328 /* Insert a "Cut" option */
5329 memset(&mitem, 0, sizeof(MENUITEMINFO));
5330 mitem.cbSize = sizeof(MENUITEMINFO);
5331 mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
5332 mitem.wID = IDM_EDIT_CUT;
5333 mitem.fState = (fAllow & EM_CUT) ? MFS_ENABLED : MFS_GRAYED;
5334 mitem.fType = MFT_STRING;
5335 mitem.dwTypeData = TEXT("Cut");
5336 mitem.cch = 3;
5337 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5339 /* Insert a "Copy" option */
5340 memset(&mitem, 0, sizeof(MENUITEMINFO));
5341 mitem.cbSize = sizeof(MENUITEMINFO);
5342 mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
5343 mitem.wID = IDM_EDIT_COPY;
5344 mitem.fState = (fAllow & EM_CP) ? MFS_ENABLED : MFS_GRAYED;
5345 mitem.fType = MFT_STRING;
5346 mitem.dwTypeData = TEXT("Copy");
5347 mitem.cch = 4;
5348 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5350 /* Insert a "Copy Append" option */
5351 memset(&mitem, 0, sizeof(MENUITEMINFO));
5352 mitem.cbSize = sizeof(MENUITEMINFO);
5353 mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
5354 mitem.wID = IDM_EDIT_COPY_APPEND;
5355 mitem.fState = (fAllow & EM_CP_APPEND) ? MFS_ENABLED : MFS_GRAYED;
5356 mitem.fType = MFT_STRING;
5357 mitem.dwTypeData = TEXT("Copy Append");
5358 mitem.cch = 11;
5359 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5361 /* Insert a "Paste" option */
5362 memset(&mitem, 0, sizeof(MENUITEMINFO));
5363 mitem.cbSize = sizeof(MENUITEMINFO);
5364 mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
5365 mitem.wID = IDM_EDIT_PASTE;
5366 mitem.fType = MFT_STRING;
5367 mitem.dwTypeData = TEXT("Paste");
5368 mitem.fState = (fAllow & EM_PST) ? MFS_ENABLED : MFS_GRAYED;
5369 mitem.cch = 5;
5370 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5373 /* Insert a "Select All" option */
5374 memset(&mitem, 0, sizeof(MENUITEMINFO));
5375 mitem.cbSize = sizeof(MENUITEMINFO);
5376 mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
5377 mitem.wID = IDM_EDIT_SEL_ALL;
5378 mitem.fType = MFT_STRING;
5379 mitem.fState = (fAllow & (EM_CP | EM_CP_APPEND))
5380 ? MFS_GRAYED : MFS_ENABLED;
5381 mitem.dwTypeData = TEXT("Select &All");
5382 mitem.cch = 11;
5383 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5385 if(n >= 0 && GetCursorPos(&point))
5386 TrackPopupMenu(hMenu,
5387 TPM_LEFTALIGN | TPM_TOPALIGN
5388 | TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
5389 point.x, point.y, 0, ghTTYWnd, NULL);
5391 DestroyMenu(hMenu);
5400 void
5401 mswin_paste_popup()
5403 MENUITEMINFO mitem;
5404 HMENU hMenu;
5405 POINT point;
5406 UINT fAllow;
5407 int n = -1;
5410 * If nothing to do just silently return
5412 if(hMenu = CreatePopupMenu()){
5414 if((fAllow = UpdateEditAllowed(ghTTYWnd)) != EM_NONE){
5415 /* Insert a "Paste" option */
5416 memset(&mitem, 0, sizeof(MENUITEMINFO));
5417 mitem.cbSize = sizeof(MENUITEMINFO);
5418 mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
5419 mitem.wID = IDM_EDIT_PASTE;
5420 mitem.fType = MFT_STRING;
5421 mitem.dwTypeData = TEXT("Paste");
5422 mitem.fState = (fAllow & EM_PST) ? MFS_ENABLED : MFS_GRAYED;
5423 mitem.cch = 5;
5424 InsertMenuItem(hMenu, ++n, FALSE, &mitem);
5426 if(n >= 0 && GetCursorPos(&point))
5427 TrackPopupMenu(hMenu,
5428 TPM_LEFTALIGN | TPM_TOPALIGN
5429 | TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
5430 point.x, point.y, 0, ghTTYWnd, NULL);
5433 DestroyMenu(hMenu);
5439 void
5440 mswin_keymenu_popup()
5442 HMENU hBarMenu, hMenu;
5443 MENUITEMINFO mitem;
5444 POINT point;
5445 int i, j, n;
5446 TCHAR tcbuf[256];
5449 * run thru menubar from left to right and down each list building
5450 * a popup of all active members. we run down the menu's rather
5451 * than thru the menuItems array so we can preserve order...
5453 if((hMenu = CreatePopupMenu())){
5454 if(hBarMenu = GetMenu(ghTTYWnd)){
5455 /* For each possible index, look for matching registered key */
5456 for(n = 0, i = 1; i <= KS_COUNT; i++)
5457 for(j = 0; j < KS_COUNT; j++)
5458 if(gpTTYInfo->menuItems[j].miIndex == i){
5459 if(gpTTYInfo->menuItems[j].miActive == TRUE
5460 && gpTTYInfo->menuItems[j].miLabel){
5461 mitem.cbSize = sizeof(MENUITEMINFO);
5462 mitem.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE;
5463 mitem.wID = j + KS_RANGESTART;
5464 mitem.fState = MFS_ENABLED;
5465 mitem.fType = MFT_STRING;
5466 /* miLabel is still plain old char *, not utf8 */
5467 _sntprintf(tcbuf, sizeof(tcbuf)/sizeof(TCHAR),
5468 TEXT("%S"), gpTTYInfo->menuItems[j].miLabel);
5469 mitem.dwTypeData = tcbuf;
5470 mitem.cch = (UINT)_tcslen(tcbuf);
5471 InsertMenuItem(hMenu, n++, TRUE, &mitem);
5473 if(j + KS_RANGESTART == IDM_MI_SCREENHELP
5474 && gHelpCallback){
5475 mitem.cbSize = sizeof(MENUITEMINFO);
5476 mitem.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE;
5477 mitem.wID = IDM_HELP;
5478 mitem.fState = MFS_ENABLED;
5479 mitem.fType = MFT_STRING;
5480 _sntprintf(tcbuf, sizeof(tcbuf)/sizeof(TCHAR),
5481 TEXT("%S"), "Help in New Window");
5482 mitem.dwTypeData = tcbuf;
5483 mitem.cch = (UINT)_tcslen(tcbuf);
5484 InsertMenuItem(hMenu, n++, TRUE, &mitem);
5488 break;
5491 if(n > 0 && GetCursorPos(&point)){
5492 TrackPopupMenu(hMenu,
5493 TPM_LEFTALIGN | TPM_TOPALIGN
5494 | TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
5495 point.x, point.y, 0, ghTTYWnd, NULL);
5499 DestroyMenu(hMenu);
5508 void
5509 mswin_registericon(int row, int id, char *utf8_file)
5511 LPTSTR sPathCopy;
5512 HICON hIcon;
5513 WORD iIcon;
5514 IconList *pIcon;
5516 /* Turn this off until it can get tuned */
5517 return;
5519 /* Already registered? */
5520 for(pIcon = gIconList; pIcon; pIcon = pIcon->next)
5521 if(pIcon->id == id){
5522 pIcon->row = (short)row;
5523 return;
5526 sPathCopy = utf8_to_lptstr(utf8_file);
5528 if(hIcon = ExtractAssociatedIcon(ghInstance, sPathCopy, &iIcon))
5529 MSWIconAddList(row, id, hIcon);
5531 fs_give((void **) &sPathCopy);
5535 void
5536 mswin_destroyicons()
5538 MSWIconFree(&gIconList);
5542 void
5543 MSWIconAddList(int row, int id, HICON hIcon)
5545 IconList **ppIcon;
5547 for(ppIcon = &gIconList; *ppIcon; ppIcon = &(*ppIcon)->next)
5550 *ppIcon = (IconList *) MemAlloc (sizeof (IconList));
5551 memset(*ppIcon, 0, sizeof(IconList));
5552 (*ppIcon)->hIcon = hIcon;
5553 (*ppIcon)->id = id;
5554 (*ppIcon)->row = (short)row;
5559 MSWIconPaint(int row, HDC hDC)
5561 IconList *pIcon;
5562 int rv = 0;
5564 for(pIcon = gIconList; pIcon && pIcon->row != row; pIcon = pIcon->next)
5567 if(pIcon){
5568 /* Invalidate rectangle covering single character. */
5569 DrawIconEx(hDC, 0, (row * gpTTYInfo->yChar) + gpTTYInfo->yOffset,
5570 pIcon->hIcon, 2 * gpTTYInfo->xChar, gpTTYInfo->yChar,
5571 0, NULL, DI_NORMAL);
5573 rv = 1;
5576 return(rv);
5580 void
5581 MSWIconFree(IconList **ppIcon)
5583 if(ppIcon && *ppIcon){
5584 if((*ppIcon)->next)
5585 MSWIconFree(&(*ppIcon)->next);
5587 DestroyIcon((*ppIcon)->hIcon);
5588 MemFree (*ppIcon);
5589 *ppIcon = NULL;
5595 * Set up debugging stuff.
5597 void
5598 mswin_setdebug (int debug, FILE *debugfile)
5600 /* Accept new file only if we don't already have a file. */
5601 if (mswin_debugfile == 0) {
5602 mswin_debug = debug;
5603 mswin_debugfile = debugfile;
5604 MemDebug (debug, mswin_debugfile);
5609 void
5610 mswin_setnewmailwidth (int width)
5612 gNMW_width = width;
5613 gNMW_width = gNMW_width < 20 ? 20 : gNMW_width;
5614 gNMW_width = gNMW_width > 170 ? 170 : gNMW_width;
5619 * Event handler to deal with File Drop events
5621 LOCAL BOOL
5622 ProcessTTYFileDrop (HANDLE wDrop)
5624 HDROP hDrop = wDrop;
5625 POINT pos;
5626 int col, row, i, n;
5627 TCHAR fname[1024];
5628 char *utf8_fname;
5630 if(!gpTTYInfo->dndhandler)
5631 return(FALSE);
5633 /* translate drop point to character cell */
5634 DragQueryPoint(hDrop, &pos);
5635 col = (pos.x - gpTTYInfo->xOffset) / gpTTYInfo->xChar;
5636 if (pos.x < gpTTYInfo->xOffset)
5637 --col;
5638 row = (pos.y - gpTTYInfo->yOffset) / gpTTYInfo->yChar;
5639 if (pos.y < gpTTYInfo->yOffset)
5640 --row;
5642 for(n = DragQueryFile(hDrop, (UINT)-1, NULL, 0), i = 0; i < n; i++){
5643 DragQueryFile(hDrop, i, fname, 1024);
5644 utf8_fname = lptstr_to_utf8(fname);
5645 gpTTYInfo->dndhandler (row, col, utf8_fname);
5646 fs_give((void **) &utf8_fname);
5649 DragFinish(hDrop);
5651 set_time_of_last_input();
5653 return(TRUE);
5658 * Set a callback to deal with Drag 'N Drop events
5661 mswin_setdndcallback (int (*cb)())
5663 if(gpTTYInfo->dndhandler)
5664 gpTTYInfo->dndhandler = NULL;
5666 if(cb){
5667 gpTTYInfo->dndhandler = cb;
5668 DragAcceptFiles(ghTTYWnd, TRUE);
5671 return(1);
5676 * Clear previously installed callback to handle Drag 'N Drop
5677 * events
5680 mswin_cleardndcallback ()
5682 gpTTYInfo->dndhandler = NULL;
5683 DragAcceptFiles(ghTTYWnd, FALSE);
5684 return(1);
5689 * Set a callback for function 'ch'
5692 mswin_setresizecallback (int (*cb)())
5694 int i;
5695 int e;
5699 * Look through whole array for this call back function. Don't
5700 * insert duplicate. Also look for empty slot.
5702 e = -1;
5703 for (i = 0; i < RESIZE_CALLBACK_ARRAY_SIZE; ++i) {
5704 if (gpTTYInfo->resizer[i] == cb)
5705 return (0);
5706 if (e == -1 && gpTTYInfo->resizer[i] == NULL)
5707 e = i;
5711 * Insert in empty slot or return an error.
5713 if (e != -1) {
5714 gpTTYInfo->resizer[e] = cb;
5715 return (0);
5717 return (-1);
5722 * Clear all instances of the callback function 'cb'
5725 mswin_clearresizecallback (int (*cb)())
5727 int i;
5728 int status;
5730 status = -1;
5731 for (i = 0; i < RESIZE_CALLBACK_ARRAY_SIZE; ++i) {
5732 if (gpTTYInfo->resizer[i] == cb) {
5733 gpTTYInfo->resizer[i] = NULL;
5734 status = 0;
5737 return (status);
5741 void
5742 mswin_beginupdate (void)
5744 gpTTYInfo->fMassiveUpdate = TRUE;
5748 void
5749 mswin_endupdate (void)
5751 gpTTYInfo->fMassiveUpdate = FALSE;
5752 MoveTTYCursor (ghTTYWnd);
5757 mswin_charsetid2string(LPTSTR fontCharSet, size_t nfontCharSet, BYTE lfCharSet)
5759 TCHAR buf[1024];
5761 buf[0] = '\0';
5762 switch(lfCharSet){
5763 case DEFAULT_CHARSET:
5764 break;
5765 case ANSI_CHARSET:
5766 _tcsncpy(buf, TEXT("ANSI_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5767 break;
5768 case OEM_CHARSET:
5769 _tcsncpy(buf, TEXT("OEM_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5770 break;
5771 case BALTIC_CHARSET:
5772 _tcsncpy(buf, TEXT("BALTIC_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5773 break;
5774 case CHINESEBIG5_CHARSET:
5775 _tcsncpy(buf, TEXT("CHINESE_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5776 break;
5777 case EASTEUROPE_CHARSET:
5778 _tcsncpy(buf, TEXT("EASTEUROPE_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5779 break;
5780 case GB2312_CHARSET:
5781 _tcsncpy(buf, TEXT("GF2312_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5782 break;
5783 case GREEK_CHARSET:
5784 _tcsncpy(buf, TEXT("GREEK_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5785 break;
5786 case HANGUL_CHARSET:
5787 _tcsncpy(buf, TEXT("HANGUL_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5788 break;
5789 case MAC_CHARSET:
5790 _tcsncpy(buf, TEXT("MAC_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5791 break;
5792 case RUSSIAN_CHARSET:
5793 _tcsncpy(buf, TEXT("RUSSIAN_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5794 break;
5795 case SHIFTJIS_CHARSET:
5796 _tcsncpy(buf, TEXT("SHIFTJIS_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5797 break;
5798 case SYMBOL_CHARSET:
5799 _tcsncpy(buf, TEXT("SYMBOL_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5800 break;
5801 case TURKISH_CHARSET:
5802 _tcsncpy(buf, TEXT("TURKISH_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5803 break;
5804 case VIETNAMESE_CHARSET:
5805 _tcsncpy(buf, TEXT("VIETNAMESE_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5806 break;
5807 case JOHAB_CHARSET:
5808 _tcsncpy(buf, TEXT("JOHAB_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5809 break;
5810 case ARABIC_CHARSET:
5811 _tcsncpy(buf, TEXT("ARABIC_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5812 break;
5813 case HEBREW_CHARSET:
5814 _tcsncpy(buf, TEXT("HEBREW_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5815 break;
5816 case THAI_CHARSET:
5817 _tcsncpy(buf, TEXT("THAI_CHARSET"), sizeof(buf)/sizeof(TCHAR));
5818 break;
5819 default:
5820 /* default char set if we can't figure it out */
5821 break;
5824 buf[sizeof(buf)/sizeof(TCHAR) - 1] = '\0';
5826 _tcsncpy(fontCharSet, buf, nfontCharSet);
5827 fontCharSet[nfontCharSet-1] = '\0';
5829 return 0;
5833 BYTE
5834 mswin_string2charsetid(LPTSTR str)
5836 TCHAR tstr[1024];
5838 if(!str || (lstrlen(str) >= 1024))
5839 return DEFAULT_CHARSET;
5841 if((lstrlen(str) > lstrlen(TEXT("_CHARSET")))
5842 && (tcsucmp(str + lstrlen(str) - lstrlen(TEXT("_CHARSET")), TEXT("_CHARSET")) == 0)){
5843 _tcsncpy(tstr, str, 1024);
5844 tstr[lstrlen(str) - lstrlen(TEXT("_CHARSET"))] = '\0';
5845 tstr[1024-1] = '\0';
5846 if(tcsucmp(tstr, TEXT("ANSI")) == 0)
5847 return ANSI_CHARSET;
5848 else if(tcsucmp(tstr, TEXT("DEFAULT")) == 0)
5849 return DEFAULT_CHARSET;
5850 else if(tcsucmp(tstr, TEXT("OEM")) == 0)
5851 return OEM_CHARSET;
5852 else if(tcsucmp(tstr, TEXT("BALTIC")) == 0)
5853 return BALTIC_CHARSET;
5854 else if(tcsucmp(tstr, TEXT("CHINESEBIG5")) == 0)
5855 return CHINESEBIG5_CHARSET;
5856 else if(tcsucmp(tstr, TEXT("EASTEUROPE")) == 0)
5857 return EASTEUROPE_CHARSET;
5858 else if(tcsucmp(tstr, TEXT("GB2312")) == 0)
5859 return GB2312_CHARSET;
5860 else if(tcsucmp(tstr, TEXT("GREEK")) == 0)
5861 return GREEK_CHARSET;
5862 else if(tcsucmp(tstr, TEXT("HANGUL")) == 0)
5863 return HANGUL_CHARSET;
5864 else if(tcsucmp(tstr, TEXT("MAC")) == 0)
5865 return MAC_CHARSET;
5866 else if(tcsucmp(tstr, TEXT("RUSSIAN")) == 0)
5867 return RUSSIAN_CHARSET;
5868 else if(tcsucmp(tstr, TEXT("SHIFTJIS")) == 0)
5869 return SHIFTJIS_CHARSET;
5870 else if(tcsucmp(tstr, TEXT("SYMBOL")) == 0)
5871 return SYMBOL_CHARSET;
5872 else if(tcsucmp(tstr, TEXT("TURKISH")) == 0)
5873 return TURKISH_CHARSET;
5874 else if(tcsucmp(tstr, TEXT("VIETNAMESE")) == 0)
5875 return VIETNAMESE_CHARSET;
5876 else if(tcsucmp(tstr, TEXT("JOHAB")) == 0)
5877 return JOHAB_CHARSET;
5878 else if(tcsucmp(tstr, TEXT("ARABIC")) == 0)
5879 return ARABIC_CHARSET;
5880 else if(tcsucmp(tstr, TEXT("HEBREW")) == 0)
5881 return HEBREW_CHARSET;
5882 else if(tcsucmp(tstr, TEXT("THAI")) == 0)
5883 return THAI_CHARSET;
5884 else
5885 return DEFAULT_CHARSET;
5887 else{
5888 if(_tstoi(str) > 0)
5889 return((BYTE)(_tstoi(str)));
5890 else
5891 return DEFAULT_CHARSET;
5897 mswin_setwindow(char *fontName_utf8, char *fontSize_utf8, char *fontStyle_utf8,
5898 char *windowPosition, char *caretStyle, char *fontCharSet_utf8)
5900 LOGFONT newFont;
5901 int newHeight;
5902 HDC hDC;
5903 int ppi;
5904 RECT wndRect, cliRect;
5905 char *c;
5906 char *n;
5907 int i;
5908 BOOL toolBar = FALSE;
5909 BOOL toolBarTop = TRUE;
5910 int wColumns, wRows;
5911 int wXPos, wYPos;
5912 int wXBorder, wYBorder;
5913 int wXSize, wYSize;
5914 char wp[WIN_POS_STR_MAX_LEN + 1];
5915 int showWin = 1;
5916 LPTSTR fontName_lpt = NULL;
5917 LPTSTR fontCharSet_lpt;
5919 #ifdef SDEBUG
5920 if (mswin_debug >= 5)
5921 fprintf (mswin_debugfile, "mswin_setwindow::: entered, minimized: %d\n",
5922 gpTTYInfo->fMinimized);
5923 #endif
5925 /* Require a font name to set font info. */
5926 if(fontName_utf8 != NULL && *fontName_utf8 != '\0' &&
5927 (fontName_lpt = utf8_to_lptstr(fontName_utf8)) &&
5928 _tcslen(fontName_lpt) <= LF_FACESIZE - 1){
5930 hDC = GetDC(ghTTYWnd);
5931 ppi = GetDeviceCaps(hDC, LOGPIXELSY);
5932 ReleaseDC(ghTTYWnd, hDC);
5934 /* Default height, then examine the requested fontSize. */
5935 newFont.lfHeight = -MulDiv(12, ppi, 72);
5936 if(ScanInt(fontSize_utf8, FONT_MIN_SIZE, FONT_MAX_SIZE, &newHeight)){
5937 newHeight = abs(newHeight);
5938 newFont.lfHeight = -MulDiv(newHeight, ppi, 72);
5941 /* Default font style, then read requested style. */
5942 newFont.lfWeight = 0;
5943 newFont.lfItalic = 0;
5944 if(fontStyle_utf8 != NULL){
5945 _strlwr(fontStyle_utf8);
5946 if(strstr(fontStyle_utf8, "bold"))
5947 newFont.lfWeight = FW_BOLD;
5948 if(strstr(fontStyle_utf8, "italic"))
5949 newFont.lfItalic = 1;
5952 /* Everything else takes the default. */
5953 newFont.lfWidth = 0;
5954 newFont.lfEscapement = 0;
5955 newFont.lfOrientation = 0;
5956 newFont.lfUnderline = 0;
5957 newFont.lfStrikeOut = 0;
5958 fontCharSet_lpt = utf8_to_lptstr(fontCharSet_utf8);
5959 if(fontCharSet_lpt){
5960 newFont.lfCharSet = mswin_string2charsetid(fontCharSet_lpt);
5961 fs_give((void **) &fontCharSet_lpt);
5964 newFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
5965 newFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5966 newFont.lfQuality = DEFAULT_QUALITY;
5967 newFont.lfPitchAndFamily = FIXED_PITCH;
5968 _sntprintf(newFont.lfFaceName, LF_FACESIZE, TEXT("%s"), fontName_lpt);
5969 ResetTTYFont (ghTTYWnd, gpTTYInfo, &newFont);
5972 if(fontName_lpt)
5973 fs_give((void **) &fontName_lpt);
5976 * Set window position. String format is: CxR+X+Y
5977 * Where C is the number of columns, R is the number of rows,
5978 * and X and Y specify the top left corner of the window.
5980 if(windowPosition != NULL && *windowPosition != '\0'){
5981 if(strlen(windowPosition) > sizeof(wp)-1)
5982 return(0);
5984 strncpy(wp, windowPosition, sizeof(wp));
5985 wp[sizeof(wp)-1] = '\0';
5988 * Flag characters are at the end of the string. Strip them
5989 * off till we get to a number.
5991 i = (int)strlen(wp) - 1;
5992 while(i > 0 && (*(wp+i) < '0' || *(wp+i) > '9')){
5993 if(*(wp+i) == 't' || *(wp+i) == 'b'){
5994 toolBar = TRUE;
5995 toolBarTop = (*(wp+i) == 't');
5998 if(*(wp+i) == 'd')
5999 gfUseDialogs = TRUE;
6001 #ifdef ACCELERATORS_OPT
6002 if(*(wp+i) == 'a')
6003 AccelCtl(ghTTYWnd, ACCEL_LOAD, FALSE);
6004 #endif
6006 *(wp+i) = 0;
6007 --i;
6010 if(strcmp(wp, "MIN0") == 0){
6011 mswin_killsplash();
6012 showWin = 0;
6013 ShowWindow(ghTTYWnd, SW_MINIMIZE);
6014 if(toolBar){
6015 gpTTYInfo->toolBarTop = toolBarTop;
6016 TBShow(ghTTYWnd);
6019 else{
6020 /* Look for Columns, deliminated by 'x'. */
6021 c = strchr (wp, 'x');
6022 if (c == NULL)
6023 return(0);
6025 *c = '\0';
6026 if(!ScanInt(wp, -999, 9999, &wColumns))
6027 return(0);
6029 /* Look for Rows, deliminated by '+'. */
6030 n = c + 1;
6031 c = strchr(n, '+');
6032 if(c == NULL)
6033 return (0);
6035 *c = '\0';
6036 if(!ScanInt(n, -999, 9999, &wRows))
6037 return(0);
6039 /* Look for X position, deliminated by '+'. */
6040 n = c + 1;
6041 c = strchr(n, '+');
6042 if(c == NULL)
6043 return(0);
6045 *c = '\0';
6046 if(!ScanInt(n, -999, 9999, &wXPos))
6047 return(0);
6049 /* And get Y position, deliminated by end of string. */
6050 n = c + 1;
6051 if(!ScanInt(n, -999, 9999, &wYPos))
6052 return(0);
6055 /* Constrain the window position and size. */
6056 if(wXPos < 0)
6057 wXPos = 0;
6059 if(wYPos < 0)
6060 wYPos = 0;
6062 GetWindowRect(GetDesktopWindow(), &wndRect);
6063 if(wXPos > wndRect.right - 20)
6064 wXPos = wndRect.right - 100;
6066 if(wYPos > wndRect.bottom - 20)
6067 wYPos = wndRect.bottom - 100;
6069 /* Get the current window rect and client area. */
6070 GetWindowRect(ghTTYWnd, &wndRect);
6071 GetClientRect(ghTTYWnd, &cliRect);
6073 /* Calculate boarder sizes. */
6074 wXBorder = wndRect.right - wndRect.left - cliRect.right;
6075 wYBorder = wndRect.bottom - wndRect.top - cliRect.bottom;
6077 /* Show toolbar before calculating content size. */
6078 if(toolBar){
6079 gpTTYInfo->toolBarTop = toolBarTop;
6080 TBShow(ghTTYWnd);
6083 /* Calculate new window pos and size. */
6084 wXSize = wXBorder + (wColumns * gpTTYInfo->xChar) +
6085 (2 * gpTTYInfo->xOffset);
6086 wYSize = wYBorder + (wRows * gpTTYInfo->yChar) +
6087 gpTTYInfo->toolBarSize + (2 * MARGINE_TOP);
6088 if(!gpTTYInfo->fMinimized)
6089 MoveWindow(ghTTYWnd, wXPos, wYPos, wXSize, wYSize, TRUE);
6090 else{
6091 gpTTYInfo->fDesiredSize = TRUE;
6092 gpTTYInfo->xDesPos = (CORD)wXPos;
6093 gpTTYInfo->yDesPos = (CORD)wYPos;
6094 gpTTYInfo->xDesSize = (CORD)wXSize;
6095 gpTTYInfo->yDesSize = (CORD)wYSize;
6100 if(caretStyle != NULL && *caretStyle != '\0')
6101 for(i = 0; MSWinCaretTable[i].name; i++)
6102 if(!strucmp(MSWinCaretTable[i].name, caretStyle)){
6103 CaretTTY(ghTTYWnd, MSWinCaretTable[i].style);
6104 break;
6107 return(0);
6112 mswin_showwindow()
6114 mswin_killsplash();
6115 ShowWindow (ghTTYWnd, SW_SHOWNORMAL);
6116 UpdateWindow (ghTTYWnd);
6118 return(0);
6123 * Retrieve the current font name, font size, and window position
6124 * These get stored in the pinerc file and will be passed to
6125 * mswin_setwindow() when pine starts up. See pinerc for comments
6126 * on the format.
6129 mswin_getwindow(char *fontName_utf8, size_t nfontName,
6130 char *fontSize_utf8, size_t nfontSize,
6131 char *fontStyle_utf8, size_t nfontStyle,
6132 char *windowPosition, size_t nwindowPosition,
6133 char *foreColor, size_t nforeColor,
6134 char *backColor, size_t nbackColor,
6135 char *caretStyle, size_t ncaretStyle,
6136 char *fontCharSet_utf8, size_t nfontCharSet)
6138 HDC hDC;
6139 int ppi;
6140 RECT wndRect;
6141 char *t;
6143 if(fontName_utf8 != NULL){
6144 t = lptstr_to_utf8(gpTTYInfo->lfTTYFont.lfFaceName);
6145 if(strlen(t) < nfontName)
6146 snprintf(fontName_utf8, nfontName, "%s", t);
6148 fs_give((void **) &t);
6151 if(fontCharSet_utf8 != NULL){
6152 LPTSTR lpt;
6154 lpt = (LPTSTR) fs_get(nfontCharSet * sizeof(TCHAR));
6155 if(lpt){
6156 lpt[0] = '\0';
6157 mswin_charsetid2string(lpt, nfontCharSet, gpTTYInfo->lfTTYFont.lfCharSet);
6158 t = lptstr_to_utf8(lpt);
6159 if(strlen(t) < nfontCharSet)
6160 snprintf(fontCharSet_utf8, nfontCharSet, "%s", t);
6162 fs_give((void **) &t);
6164 fs_give((void **) &lpt);
6168 if(fontSize_utf8 != NULL){
6169 hDC = GetDC(ghTTYWnd);
6170 ppi = GetDeviceCaps(hDC, LOGPIXELSY);
6171 ReleaseDC(ghTTYWnd, hDC);
6172 snprintf(fontSize_utf8, nfontSize, "%d", MulDiv(-gpTTYInfo->lfTTYFont.lfHeight, 72, ppi));
6175 if(fontStyle_utf8 != NULL){
6176 char *sep[] = {"", ", "};
6177 int iSep = 0;
6179 *fontStyle_utf8 = '\0';
6180 if(gpTTYInfo->lfTTYFont.lfWeight >= FW_BOLD){
6181 strncpy(fontStyle_utf8, "bold", nfontStyle);
6182 fontStyle_utf8[nfontStyle-1] = '\0';
6183 iSep = 1;
6186 if(gpTTYInfo->lfTTYFont.lfItalic){
6187 strncat(fontStyle_utf8, sep[iSep], nfontStyle-strlen(fontStyle_utf8)-1);
6188 fontStyle_utf8[nfontStyle-1] = '\0';
6189 strncat(fontStyle_utf8, "italic", nfontStyle-strlen(fontStyle_utf8)-1);
6190 fontStyle_utf8[nfontStyle-1] = '\0';
6194 if(windowPosition != NULL){
6195 if(gpTTYInfo->fMinimized){
6196 strncpy(windowPosition, "MIN0", nwindowPosition);
6197 windowPosition[nwindowPosition-1] = '\0';
6199 else{
6201 * Get the window position. Constrain the top left corner
6202 * to be on the screen.
6204 GetWindowRect(ghTTYWnd, &wndRect);
6205 if(wndRect.left < 0)
6206 wndRect.left = 0;
6208 if(wndRect.top < 0)
6209 wndRect.top = 0;
6211 snprintf(windowPosition, nwindowPosition, "%dx%d+%d+%d", gpTTYInfo->actNColumn,
6212 gpTTYInfo->actNRow, wndRect.left, wndRect.top);
6215 if(gpTTYInfo->toolBarSize > 0){
6216 strncat(windowPosition, gpTTYInfo->toolBarTop ? "t" : "b",
6217 nwindowPosition-strlen(windowPosition)-1);
6218 windowPosition[nwindowPosition-1] = '\0';
6221 if(gfUseDialogs){
6222 strncat(windowPosition, "d", nwindowPosition-strlen(windowPosition)-1);
6223 windowPosition[nwindowPosition-1] = '\0';
6226 if(gpTTYInfo->hAccel){
6227 strncat(windowPosition, "a", nwindowPosition-strlen(windowPosition)-1);
6228 windowPosition[nwindowPosition-1] = '\0';
6231 if(gpTTYInfo->fMaximized){
6232 strncat(windowPosition, "!", nwindowPosition-strlen(windowPosition)-1);
6233 windowPosition[nwindowPosition-1] = '\0';
6237 if(foreColor != NULL)
6238 ConvertStringRGB(foreColor, nforeColor, gpTTYInfo->rgbFGColor);
6240 if(backColor != NULL)
6241 ConvertStringRGB(backColor, nbackColor, gpTTYInfo->rgbBGColor);
6243 if(caretStyle != NULL){
6244 int i;
6246 for(i = 0; MSWinCaretTable[i].name; i++)
6247 if(MSWinCaretTable[i].style == gpTTYInfo->cCaretStyle){
6248 strncpy(caretStyle, MSWinCaretTable[i].name, ncaretStyle);
6249 caretStyle[ncaretStyle-1] = '\0';
6250 break;
6254 return (0);
6258 void
6259 mswin_noscrollupdate(int flag)
6261 gpTTYInfo->noScrollUpdate = (flag != 0);
6262 if(flag == 0 && gpTTYInfo->scrollRangeChanged){
6263 mswin_setscrollrange(gpTTYInfo->noSUpdatePage, gpTTYInfo->noSUpdateRange);
6264 gpTTYInfo->noSUpdatePage = gpTTYInfo->noSUpdateRange = 0;
6265 gpTTYInfo->scrollRangeChanged = 0;
6271 * Set the scroll range.
6273 void
6274 mswin_setscrollrange (long page, long max)
6276 SCROLLINFO scrollInfo;
6278 if(gpTTYInfo->noScrollUpdate){
6279 gpTTYInfo->noSUpdatePage = page;
6280 gpTTYInfo->noSUpdateRange = max;
6281 gpTTYInfo->scrollRangeChanged = 1;
6282 return;
6284 if (max != gpTTYInfo->scrollRange) {
6285 scrollInfo.cbSize = sizeof(SCROLLINFO);
6286 scrollInfo.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_RANGE;
6287 scrollInfo.nMin = 0;
6289 if (max > 0) {
6290 scrollInfo.nMax = (int) max;
6291 scrollInfo.nPage = page;
6292 SetScrollInfo(ghTTYWnd, SB_VERT, &scrollInfo, TRUE);
6293 EnableScrollBar (ghTTYWnd, SB_VERT, ESB_ENABLE_BOTH);
6295 else {
6296 max = 0;
6297 scrollInfo.cbSize = sizeof(SCROLLINFO);
6298 scrollInfo.fMask |= SIF_POS;
6299 scrollInfo.nMax = 1;
6300 scrollInfo.nPos = 0;
6301 SetScrollInfo(ghTTYWnd, SB_VERT, &scrollInfo, TRUE);
6302 EnableScrollBar (ghTTYWnd, SB_VERT, ESB_DISABLE_BOTH);
6303 gpTTYInfo->scrollPos = 0;
6305 gpTTYInfo->scrollRange = (int)max;
6311 * Set the current scroll position.
6313 void
6314 mswin_setscrollpos (long pos)
6316 SCROLLINFO scrollInfo;
6318 if (pos != gpTTYInfo->scrollPos) {
6319 scrollInfo.cbSize = sizeof(SCROLLINFO);
6320 scrollInfo.fMask = SIF_PAGE | SIF_RANGE;
6322 GetScrollInfo(ghTTYWnd, SB_VERT, &scrollInfo);
6324 scrollInfo.fMask |= SIF_POS;
6325 scrollInfo.nPos = (int) pos;
6326 SetScrollInfo(ghTTYWnd, SB_VERT, &scrollInfo, TRUE);
6328 gpTTYInfo->scrollPos = pos;
6334 * retrieve the current scroll position.
6336 long
6337 mswin_getscrollpos (void)
6339 return ((long)((float)GetScrollPos (ghTTYWnd, SB_VERT)));
6344 * retrieve the latest scroll to position.
6346 long
6347 mswin_getscrollto (void)
6349 return (gpTTYInfo->scrollTo);
6353 * install function to deal with LINEDOWN events
6355 void
6356 mswin_setscrollcallback (cbarg_t cbfunc)
6358 gScrollCallback = cbfunc;
6363 * install function to deal with sort menu messages
6365 void
6366 mswin_setsortcallback (cbarg_t cbfunc)
6368 gSortCallback = cbfunc;
6373 * install function to deal with sort menu messages
6375 void
6376 mswin_setflagcallback (cbarg_t cbfunc)
6378 gFlagCallback = cbfunc;
6382 void
6383 mswin_set_erasecreds_callback (cbvoid_t cbfunc)
6385 gEraseCredsCallback = cbfunc;
6389 * install function to deal with header mode flipping
6391 void
6392 mswin_sethdrmodecallback (cbarg_t cbfunc)
6394 gHdrCallback = cbfunc;
6399 * install function to deal with view in new window messages
6401 void
6402 mswin_setviewinwindcallback (cbvoid_t cbfunc)
6404 gViewInWindCallback = cbfunc;
6409 * install function to deal with zoom mode flipping
6411 void
6412 mswin_setzoomodecallback (cbarg_t cbfunc)
6414 gZoomCallback = cbfunc;
6419 * install function to deal with function key mode flipping
6421 void
6422 mswin_setfkeymodecallback (cbarg_t cbfunc)
6424 gFkeyCallback = cbfunc;
6429 * install function to deal with apply mode flipping
6431 void
6432 mswin_setselectedcallback (cbarg_t cbfunc)
6434 gSelectedCallback = cbfunc;
6439 * return 1 if new mail window is being used
6442 mswin_newmailwinon (void)
6444 return(gMswinNewMailWin.hwnd ? 1 : 0);
6450 void
6451 mswin_setdebugoncallback (cbvoid_t cbfunc)
6453 gIMAPDebugONCallback = cbfunc;
6457 void
6458 mswin_setdebugoffcallback (cbvoid_t cbfunc)
6460 gIMAPDebugOFFCallback = cbfunc;
6465 mswin_setconfigcallback (cbvoid_t cffunc)
6467 gConfigScreenCallback = cffunc;
6468 return(1);
6473 * Set the printer font
6475 void
6476 mswin_setprintfont(char *fontName, char *fontSize,
6477 char *fontStyle, char *fontCharSet)
6479 LPTSTR fn = NULL, fstyle = NULL, fc = NULL;
6481 if(fontName)
6482 fn = utf8_to_lptstr(fontName);
6484 if(fontStyle)
6485 fstyle = utf8_to_lptstr(fontStyle);
6487 if(fontCharSet)
6488 fc = utf8_to_lptstr(fontCharSet);
6490 /* Require a font name to set font info. */
6491 if(fn != NULL && *fn != '\0' && lstrlen(fn) <= LF_FACESIZE - 1){
6493 _tcsncpy(gPrintFontName, fn, sizeof(gPrintFontName)/sizeof(TCHAR));
6494 gPrintFontName[sizeof(gPrintFontName)/sizeof(TCHAR)-1] = 0;
6495 if(fstyle){
6496 _tcsncpy(gPrintFontStyle, fstyle, sizeof(gPrintFontStyle)/sizeof(TCHAR));
6497 gPrintFontStyle[sizeof(gPrintFontStyle)/sizeof(TCHAR)-1] = 0;
6498 _tcslwr(gPrintFontStyle); /* Lower case font style. */
6501 if(fc){
6502 _tcsncpy(gPrintFontCharSet, fc, sizeof(gPrintFontCharSet)/sizeof(TCHAR));
6503 gPrintFontCharSet[sizeof(gPrintFontCharSet)/sizeof(TCHAR)-1] = 0;
6506 gPrintFontSize = 12;
6507 if(ScanInt(fontSize, FONT_MIN_SIZE, FONT_MAX_SIZE, &gPrintFontSize))
6508 gPrintFontSize = abs(gPrintFontSize);
6510 gPrintFontSameAs = FALSE;
6512 else{
6513 gPrintFontName[0] = '\0';
6514 gPrintFontSameAs = TRUE;
6517 if(fn)
6518 fs_give((void **) &fn);
6520 if(fstyle)
6521 fs_give((void **) &fstyle);
6523 if(fc)
6524 fs_give((void **) &fc);
6528 void
6529 mswin_getprintfont(char *fontName_utf8, size_t nfontName,
6530 char *fontSize_utf8, size_t nfontSize,
6531 char *fontStyle_utf8, size_t nfontStyle,
6532 char *fontCharSet_utf8, size_t nfontCharSet)
6534 if(gPrintFontName[0] == '\0' || gPrintFontSameAs){
6535 if(fontName_utf8 != NULL)
6536 *fontName_utf8 = '\0';
6537 if(fontSize_utf8 != NULL)
6538 *fontSize_utf8 = '\0';
6539 if(fontStyle_utf8 != NULL)
6540 *fontStyle_utf8 = '\0';
6541 if(fontCharSet_utf8 != NULL)
6542 *fontCharSet_utf8 = '\0';
6544 else{
6545 char *u;
6547 if(fontName_utf8 != NULL){
6548 u = lptstr_to_utf8(gPrintFontName);
6549 if(u){
6550 strncpy(fontName_utf8, u, nfontName);
6551 fontName_utf8[nfontName-1] = 0;
6552 fs_give((void **) &u);
6556 if(fontSize_utf8 != NULL)
6557 snprintf(fontSize_utf8, nfontSize, "%d", gPrintFontSize);
6560 if(fontStyle_utf8 != NULL){
6561 u = lptstr_to_utf8(gPrintFontStyle);
6562 if(u){
6563 strncpy(fontStyle_utf8, u, nfontStyle);
6564 fontStyle_utf8[nfontStyle-1] = 0;
6565 fs_give((void **) &u);
6569 if(fontCharSet_utf8 != NULL){
6570 u = lptstr_to_utf8(gPrintFontCharSet);
6571 if(u){
6572 strncpy(fontCharSet_utf8, u, nfontCharSet);
6573 fontCharSet_utf8[nfontCharSet-1] = 0;
6574 fs_give((void **) &u);
6582 * Set the window help text. Add or delete the Help menu item as needed.
6585 mswin_sethelptextcallback(cbstr_t cbfunc)
6587 HMENU hMenu;
6589 gHelpCallback = cbfunc;
6591 hMenu = GetMenu (ghTTYWnd);
6592 if (hMenu == NULL)
6593 return (1);
6595 return(MSWHelpSetMenu (hMenu));
6601 * Set the window help text. Add or delete the Help menu item as needed.
6604 mswin_setgenhelptextcallback(cbstr_t cbfunc)
6606 HMENU hMenu;
6608 gHelpGenCallback = cbfunc;
6610 hMenu = GetMenu (ghTTYWnd);
6611 if (hMenu == NULL)
6612 return (1);
6614 return(MSWHelpSetMenu (hMenu));
6620 MSWHelpSetMenu(HMENU hMenu)
6622 BOOL brc;
6623 int count;
6626 * Find menu and update it.
6628 count = GetMenuItemCount (hMenu);
6629 if (count == -1)
6630 return (1);
6632 hMenu = GetSubMenu (hMenu, count - 1);
6633 if (hMenu == NULL)
6634 return (1);
6637 * Insert or delete generic help item
6639 if (gHelpGenCallback == NULL){
6640 if (gfHelpGenMenu) {
6641 brc = DeleteMenu (hMenu, IDM_MI_GENERALHELP, MF_BYCOMMAND);
6642 DrawMenuBar (ghTTYWnd);
6644 gfHelpGenMenu = FALSE;
6646 else {
6647 if (!gfHelpGenMenu) {
6648 brc = InsertMenu (hMenu, 0,
6649 MF_BYPOSITION | MF_STRING,
6650 IDM_MI_GENERALHELP, TEXT("&General Help"));
6651 DrawMenuBar (ghTTYWnd);
6653 gfHelpGenMenu = TRUE;
6657 * Insert or delete screen help item
6659 if (gHelpCallback == NULL){
6660 if (gfHelpMenu) {
6661 brc = DeleteMenu (hMenu, IDM_HELP, MF_BYCOMMAND);
6662 DrawMenuBar (ghTTYWnd);
6664 gfHelpMenu = FALSE;
6666 else {
6667 if (!gfHelpMenu) {
6668 brc = InsertMenu (hMenu, gHelpGenCallback ? 2 : 1,
6669 MF_BYPOSITION | MF_STRING,
6670 IDM_HELP, TEXT("Screen Help in &New Window"));
6671 DrawMenuBar (ghTTYWnd);
6673 gfHelpMenu = TRUE;
6676 return (0);
6681 * Set the text displayed when someone tries to close the application
6682 * the wrong way.
6684 void
6685 mswin_setclosetext (char *pCloseText)
6687 gpCloseText = pCloseText;
6692 * Called when upper layer is in a busy loop. Allows us to yield to
6693 * Windows and perhaps process some events. Does not yield control
6694 * to other applications.
6697 mswin_yield (void)
6699 MSG msg;
6700 DWORD start;
6701 int didmsg = FALSE;
6703 if (gScrolling)
6704 return (TRUE);
6706 start = GetTickCount ();
6707 #ifdef CDEBUG
6708 if (mswin_debug > 16)
6709 fprintf (mswin_debugfile, "mswin_yeild:: Entered\n");
6710 #endif
6711 if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {
6712 if (gpTTYInfo->hAccel == NULL ||
6713 !TranslateAccelerator (ghTTYWnd, gpTTYInfo->hAccel, &msg)) {
6714 TranslateMessage (&msg);
6715 DispatchMessage (&msg);
6716 didmsg = TRUE;
6719 #ifdef CDEBUG
6720 if (mswin_debug > 16)
6721 fprintf (mswin_debugfile, "mswin_yeild:: Delay %ld msec\n",
6722 GetTickCount () - start);
6723 #endif
6724 return (didmsg);
6729 * Called to see if we can process input.
6730 * We can't process input when we are in a scrolling mode.
6733 mswin_caninput (void)
6735 return (!gScrolling && !gMouseTracking);
6740 * Called to see if there is a character available.
6743 mswin_charavail (void)
6745 DWORD start;
6746 MSG msg;
6747 BOOL ca, pa, ma;
6749 if (gScrolling)
6750 return (FALSE);
6752 RestoreMouseCursor();
6755 * If there are no windows messages waiting for this app, GetMessage
6756 * can take a long time. So before calling GetMessage check if
6757 * there is anything I should be doing. If there is, then only
6758 * call PeekMessage.
6759 * BUT! Don't let too much time elapse between calls to GetMessage
6760 * or we'll shut out other windows.
6762 ca = CQAvailable ();
6763 pa = EditPasteAvailable ();
6764 #ifdef CDEBUG
6765 start = GetTickCount ();
6766 if (mswin_debug > 16)
6767 fprintf (mswin_debugfile, "%s mswin_charavail:: Entered, ca %d, pa %d\n",dtime(),ca,pa);
6768 #endif
6769 if ((ca || pa) && GetTickCount () < gGMLastCall + GM_MAX_TIME)
6770 ma = PeekMessage (&msg, NULL, 0, 0, PM_NOYIELD | PM_REMOVE);
6771 else {
6772 ma = GetMessage (&msg, NULL, 0, 0);
6773 gGMLastCall = GetTickCount ();
6775 if (ma) {
6776 if (gpTTYInfo->hAccel == NULL ||
6777 !TranslateAccelerator (ghTTYWnd, gpTTYInfo->hAccel, &msg)) {
6778 TranslateMessage (&msg);
6779 DispatchMessage (&msg);
6782 #ifdef CDEBUG
6783 if (mswin_debug > 16)
6784 fprintf (mswin_debugfile, "%s mswin_charavail:: Delay %ld msec\n",
6785 dtime(), GetTickCount () - start);
6786 #endif
6788 return (pa || ca || CQAvailable ());
6793 * Call to get next character. Dispatch one message.
6796 mswin_getc (void)
6798 DWORD start;
6799 BOOL ca, pa, ma;
6800 MSG msg;
6802 if (gScrolling)
6803 return (NODATA);
6805 RestoreMouseCursor();
6807 mswin_flush();
6811 * If there are no windows messages waiting for this app, GetMessage
6812 * can take a long time. So before calling GetMessage check if
6813 * there is anything I should be doing. If there is, then only
6814 * call PeekMessage.
6816 ca = CQAvailable ();
6817 pa = EditPasteAvailable ();
6818 #ifdef CDEBUG
6819 if (mswin_debug > 16) {
6820 start = GetTickCount ();
6821 fprintf (mswin_debugfile, "mswin_getc:: Entered, ca %d pa %d\n", ca, pa);
6823 #endif
6824 if ((ca || pa) && GetTickCount () < gGMLastCall + GM_MAX_TIME)
6825 ma = PeekMessage (&msg, NULL, 0, 0, PM_NOYIELD | PM_REMOVE);
6826 else {
6827 ma = GetMessage (&msg, NULL, 0, 0);
6828 gGMLastCall = GetTickCount ();
6830 if (ma) {
6831 if (gpTTYInfo->hAccel == NULL ||
6832 !TranslateAccelerator (ghTTYWnd, gpTTYInfo->hAccel, &msg)) {
6833 TranslateMessage (&msg);
6834 DispatchMessage (&msg);
6837 #ifdef CDEBUG
6838 if (mswin_debug > 16)
6839 fprintf (mswin_debugfile, "mswin_getc:: Delay %ld msec\n",
6840 GetTickCount () - start);
6841 #endif
6844 if (pa) {
6845 SelClear ();
6846 return (EditPasteGet ());
6848 if (ca || CQAvailable ()) {
6849 SelClear();
6850 return ((UCS)(CQGet ()));
6853 return (NODATA);
6858 * Like mswin_getc, but don't yield control. Returns a CTRL key values
6859 * where, for example, ctrl+c --> CTRL|'C'.
6861 LOCAL UCS
6862 mswin_getc_fast (void)
6864 RestoreMouseCursor();
6866 if (EditPasteAvailable ()) {
6867 SelClear ();
6868 return (EditPasteGet ());
6870 if (CQAvailable ()) {
6871 SelClear ();
6872 return ((UCS)CQGet ());
6875 return (NODATA);
6880 * Flush the character input queue.
6882 void
6883 mswin_flush_input(void)
6886 * GetQueueStatus tells us if there are any input messages in the message
6887 * queue. If there are, we call mswin_getc which will retrieve the
6888 * next message (which may or may not be an input message) and process
6889 * it. We do that until all the input messages are gone.
6891 CQInit();
6893 while(GetQueueStatus(QS_INPUT))
6894 (void) mswin_getc();
6896 /* And we clear Pine's character input queue, too. */
6897 CQInit();
6902 * ibmmove - Move cursor to...
6905 mswin_move (int row, int column)
6908 FlushWriteAccum ();
6909 if (row < 0 || row >= gpTTYInfo->actNRow)
6910 return (-1);
6911 if (column < 0 || column >= gpTTYInfo->actNColumn)
6912 return (-1);
6913 gpTTYInfo->nRow = (CORD)row;
6914 gpTTYInfo->nColumn = (CORD)column;
6915 MoveTTYCursor (ghTTYWnd);
6916 return (0);
6921 mswin_getpos (int *row, int *column)
6923 FlushWriteAccum ();
6924 if (row == NULL || column == NULL)
6925 return (-1);
6926 *row = gpTTYInfo->nRow;
6927 *column = gpTTYInfo->nColumn;
6928 return (0);
6933 mswin_getscreensize (int *row, int *column)
6935 if (row == NULL || column == NULL)
6936 return (-1);
6937 *row = gpTTYInfo->actNRow;
6938 *column = gpTTYInfo->actNColumn;
6939 #ifdef SDEBUG
6940 if (mswin_debug >= 5)
6941 fprintf (mswin_debugfile, "mswin_getscreensize::: reported size %d, %d\n",
6942 *row, *column);
6943 #endif
6945 *column = MIN(*column, NLINE-1);
6947 return (0);
6951 void
6952 mswin_minimize()
6954 if (!gpTTYInfo->fMinimized)
6955 ShowWindow(ghTTYWnd, SW_MINIMIZE);
6960 mswin_showcursor (int show)
6962 int was_shown = gpTTYInfo->fCursorOn;
6964 if (show) {
6965 /* if the cursor was not already show, show it now. */
6966 if (!was_shown) {
6967 gpTTYInfo->fCursorOn = TRUE;
6968 ShowCursor(TRUE);
6971 else {
6972 /* If the cursor is shown, hide it. */
6973 if (was_shown){
6974 gpTTYInfo->fCursorOn = FALSE;
6975 ShowCursor(FALSE);
6979 return (was_shown);
6984 mswin_showcaret (int show)
6986 int was_shown = gpTTYInfo->fCaretOn;
6988 if (show) {
6989 /* if the caret was not already show, show it now. */
6990 if (!was_shown) {
6991 gpTTYInfo->fCaretOn = TRUE;
6992 ShowCaret(ghTTYWnd);
6995 else {
6996 /* If the caret is shown, hide it. */
6997 if (was_shown){
6998 gpTTYInfo->fCaretOn = FALSE;
6999 HideCaret(ghTTYWnd);
7003 return (was_shown);
7008 mswin_puts (char *utf8_str)
7010 int strLen;
7011 LPTSTR lptstr_str;
7013 FlushWriteAccum ();
7014 if (utf8_str == NULL)
7015 return (-1);
7016 if(!(lptstr_str = utf8_to_lptstr(utf8_str)))
7017 return(-1);
7018 strLen = (int)_tcslen (lptstr_str);
7019 if (strLen > 0)
7020 WriteTTYText (ghTTYWnd, lptstr_str, strLen);
7022 fs_give((void **) &lptstr_str);
7023 return (0);
7028 mswin_puts_n (char *utf8_str, int n)
7030 LPTSTR lptstr_str, lptstr_p;
7032 FlushWriteAccum ();
7033 if (utf8_str == NULL)
7034 return (-1);
7035 lptstr_str = utf8_to_lptstr(utf8_str);
7036 if(n < _tcslen(lptstr_str))
7037 lptstr_str[n] = '\0';
7038 for (lptstr_p = lptstr_str; n > 0 && *lptstr_p; n--, lptstr_p++)
7040 if (lptstr_p > lptstr_str)
7041 WriteTTYText (ghTTYWnd, lptstr_str, (int)(lptstr_p - lptstr_str));
7043 fs_give((void **) &lptstr_str);
7044 return (0);
7049 mswin_putblock (char *utf8_str, int strLen)
7051 LPTSTR lptstr_str;
7053 FlushWriteAccum ();
7054 if (utf8_str == NULL)
7055 return (-1);
7056 lptstr_str = utf8_to_lptstr(utf8_str);
7057 if (strLen > 0)
7058 WriteTTYText (ghTTYWnd, lptstr_str, strLen);
7059 fs_give((void **) &lptstr_str);
7060 return (0);
7065 * mswin_putc - put a character at the current position in the
7066 * current colors
7069 mswin_putc (UCS ucs)
7071 TCHAR cc = (TCHAR)ucs;
7072 if(ucs == ARABIC_LRM || ucs == ARABIC_RLM){
7073 FlushWriteAccum();
7074 WriteTTYBlock (ghTTYWnd, &cc, 1);
7075 return 0;
7077 if (ucs >= (UCS)(' ')) {
7078 /* Not carriage control. */
7079 gpTTYInfo->writeAccum[gpTTYInfo->writeAccumCount++] = (TCHAR)ucs;
7080 if (gpTTYInfo->writeAccumCount == WRITE_ACCUM_SIZE)
7081 FlushWriteAccum ();
7083 else {
7084 /* Carriage control. Need to flush write accumulator and
7085 * write this char. */
7086 FlushWriteAccum ();
7087 WriteTTYBlock (ghTTYWnd, &cc, 1);
7089 return (0);
7094 * ibmoutc - output a single character with the right attributes, but
7095 * don't advance the cursor
7098 mswin_outc (char c)
7100 RECT rect;
7101 long offset;
7103 FlushWriteAccum ();
7105 switch (c) {
7106 case ASCII_BEL:
7107 MessageBeep (0);
7108 break;
7110 case ASCII_BS:
7111 case ASCII_CR:
7112 case ASCII_LF:
7113 /* Do nothing for these screen motion characters. */
7114 break;
7117 default:
7118 /* Paint character to screen. */
7119 offset = (gpTTYInfo->nRow * gpTTYInfo->actNColumn) + gpTTYInfo->nColumn;
7120 gpTTYInfo->pScreen[offset] = c;
7121 gpTTYInfo->pCellWidth[offset] = wcellwidth((UCS)c) * gpTTYInfo->xChar;
7122 gpTTYInfo->pAttrib[offset] = gpTTYInfo->curAttrib;
7124 /* Invalidate rectangle covering single character. */
7125 rect.left = (gpTTYInfo->nColumn * gpTTYInfo->xChar) +
7126 gpTTYInfo->xOffset;
7127 rect.right = rect.left + gpTTYInfo->xChar;
7128 rect.top = (gpTTYInfo->nRow * gpTTYInfo->yChar) +
7129 gpTTYInfo->yOffset;
7130 rect.bottom = rect.top + gpTTYInfo->yChar;
7131 gpTTYInfo->screenDirty = TRUE;
7132 InvalidateRect (ghTTYWnd, &rect, FALSE);
7133 break;
7135 return (0);
7139 * ibmrev - change reverse video state
7142 mswin_rev (int state)
7144 int curState = (gpTTYInfo->curAttrib.style & CHAR_ATTR_REV) != 0;
7146 if (state != curState){
7147 FlushWriteAccum ();
7148 if (state) {
7149 gpTTYInfo->curAttrib.style |= CHAR_ATTR_REV;
7150 SetReverseColor();
7152 else{
7153 gpTTYInfo->curAttrib.style &= ~CHAR_ATTR_REV;
7154 pico_set_normal_color();
7158 return (0);
7163 * Get current reverse video state.
7166 mswin_getrevstate (void)
7168 return ((gpTTYInfo->curAttrib.style & CHAR_ATTR_REV) != 0);
7173 * ibmrev - change reverse video state
7176 mswin_bold (int state)
7178 int curState = (gpTTYInfo->curAttrib.style & CHAR_ATTR_BOLD) != 0;
7180 if (state != curState){
7181 FlushWriteAccum ();
7182 if (state)
7183 gpTTYInfo->curAttrib.style |= CHAR_ATTR_BOLD;
7184 else
7185 gpTTYInfo->curAttrib.style &= ~CHAR_ATTR_BOLD;
7188 return (0);
7193 * ibmrev - change reverse video state
7196 mswin_uline (int state)
7198 int curState = (gpTTYInfo->curAttrib.style & CHAR_ATTR_ULINE) != 0;
7200 if (state != curState){
7201 FlushWriteAccum ();
7202 if (state)
7203 gpTTYInfo->curAttrib.style |= CHAR_ATTR_ULINE;
7204 else
7205 gpTTYInfo->curAttrib.style &= ~CHAR_ATTR_ULINE;
7208 return (0);
7213 * ibmeeol - erase to the end of the line
7216 mswin_eeol (void)
7218 TCHAR *cStart;
7219 CharAttrib *aStart;
7220 int *cwStart;
7221 long length, i;
7222 RECT rect;
7224 FlushWriteAccum ();
7226 /* From current position to end of line. */
7227 length = gpTTYInfo->actNColumn - gpTTYInfo->nColumn;
7229 cStart = gpTTYInfo->pScreen + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
7230 + gpTTYInfo->nColumn;
7231 cwStart = gpTTYInfo->pCellWidth + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
7232 + gpTTYInfo->nColumn;
7233 for(i = 0; i < length; i++){
7234 cStart[i] = (TCHAR)(' ');
7235 cwStart[i] = gpTTYInfo->xChar;
7238 aStart = gpTTYInfo->pAttrib
7239 + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
7240 + gpTTYInfo->nColumn;
7241 for(; length > 0; length--, aStart++){
7242 aStart->style = CHAR_ATTR_NORM;
7243 aStart->rgbFG = gpTTYInfo->curAttrib.rgbFG;
7244 aStart->rgbBG = gpTTYInfo->curAttrib.rgbBG;
7247 rect.left = (gpTTYInfo->nColumn * gpTTYInfo->xChar) +
7248 gpTTYInfo->xOffset;
7249 rect.right = gpTTYInfo->xSize;
7250 rect.top = (gpTTYInfo->nRow * gpTTYInfo->yChar) +
7251 gpTTYInfo->yOffset;
7252 rect.bottom = rect.top + gpTTYInfo->yChar;
7253 gpTTYInfo->screenDirty = TRUE;
7254 InvalidateRect (ghTTYWnd, &rect, FALSE);
7256 return (0);
7261 * ibmeeop - clear from cursor to end of page
7264 mswin_eeop (void)
7266 TCHAR *cStart;
7267 CharAttrib *aStart;
7268 int *cwStart;
7269 long length, i;
7270 RECT rect;
7272 FlushWriteAccum ();
7273 /* From current position to end of screen. */
7275 cStart = gpTTYInfo->pScreen + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
7276 + gpTTYInfo->nColumn;
7277 cwStart = gpTTYInfo->pCellWidth + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
7278 + gpTTYInfo->nColumn;
7279 length = (long)((gpTTYInfo->pScreen
7280 + (gpTTYInfo->actNColumn * gpTTYInfo->actNRow))
7281 - cStart);
7282 for(i = 0; i < length; i ++){
7283 cStart[i] = (TCHAR)(' ');
7284 cwStart[i] = gpTTYInfo->xChar;
7287 aStart = gpTTYInfo->pAttrib
7288 + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
7289 + gpTTYInfo->nColumn;
7291 for(; length-- > 0; aStart++){
7292 aStart->style = CHAR_ATTR_NORM;
7293 aStart->rgbFG = gpTTYInfo->curAttrib.rgbFG;
7294 aStart->rgbBG = gpTTYInfo->curAttrib.rgbBG;
7297 /* Invalidate a rectangle that includes all of the current line down
7298 * to the bottom of the window. */
7299 rect.left = 0;
7300 rect.right = gpTTYInfo->xSize;
7301 rect.top = (gpTTYInfo->nRow * gpTTYInfo->yChar) +
7302 gpTTYInfo->yOffset;
7303 rect.bottom = gpTTYInfo->ySize;
7304 gpTTYInfo->screenDirty = TRUE;
7305 InvalidateRect (ghTTYWnd, &rect, FALSE);
7307 return (0);
7312 * ibmbeep - system beep...
7315 mswin_beep (void)
7317 MessageBeep (MB_OK);
7318 return (0);
7323 * pause - wait in function for specified number of seconds.
7325 void
7326 mswin_pause (int seconds)
7328 DWORD stoptime;
7330 stoptime = GetTickCount () + (DWORD) seconds * 1000;
7331 while (stoptime > GetTickCount ())
7332 mswin_yield ();
7337 * ibmflush - Flush output to screen.
7341 mswin_flush (void)
7345 * Flush cached changes, then update the window.
7347 FlushWriteAccum ();
7348 UpdateWindow (ghTTYWnd);
7350 return (0);
7355 * A replacement for fflush
7356 * relies on #define fflush mswin_fflush
7358 #undef fflush
7360 mswin_fflush (FILE *f)
7362 if (f == stdout) {
7363 mswin_flush();
7365 else
7366 fflush (f);
7368 return(0);
7373 * Set the cursor
7375 void
7376 mswin_setcursor (int newcursor)
7378 HCURSOR hNewCursor;
7380 switch(newcursor){
7381 case MSWIN_CURSOR_BUSY :
7382 hNewCursor = ghCursorBusy;
7383 mswin_showcursor(TRUE);
7384 break;
7386 case MSWIN_CURSOR_IBEAM :
7387 hNewCursor = ghCursorIBeam;
7388 break;
7390 case MSWIN_CURSOR_HAND :
7391 if(hNewCursor = ghCursorHand)
7392 break;
7393 /* ELSE fall thru to normal cursor */
7395 case MSWIN_CURSOR_ARROW :
7396 default :
7397 hNewCursor = ghCursorArrow;
7398 break;
7401 /* If new cursor requested, select it. */
7402 if (ghCursorCurrent != hNewCursor)
7403 SetCursor (ghCursorCurrent = hNewCursor);
7407 void
7408 RestoreMouseCursor()
7410 if(ghCursorCurrent == ghCursorBusy)
7411 mswin_setcursor(MSWIN_CURSOR_ARROW);
7416 * Display message in windows dialog box.
7418 void
7419 mswin_messagebox (char *msg_utf8, int err)
7421 LPTSTR msg_lptstr;
7423 mswin_killsplash();
7425 msg_lptstr = utf8_to_lptstr(msg_utf8);
7426 MessageBox (NULL, msg_lptstr, gszAppName,
7427 MB_OK | ((err) ? MB_ICONSTOP : MB_ICONINFORMATION));
7428 fs_give((void **) &msg_lptstr);
7433 * Signals whether or not Paste should be turned on in the
7434 * menu bar.
7436 void
7437 mswin_allowpaste (int on)
7439 static short stackp = 0;
7440 static unsigned long stack = 0L;
7442 switch(on){
7443 case MSWIN_PASTE_DISABLE :
7444 if(stackp){ /* previous state? */
7445 if((stackp -= 2) < 0)
7446 stackp = 0;
7448 gPasteEnabled = ((stack >> stackp) & 0x03);
7450 else
7451 gPasteEnabled = MSWIN_PASTE_DISABLE;
7453 break;
7455 case MSWIN_PASTE_FULL :
7456 case MSWIN_PASTE_LINE :
7457 if(gPasteEnabled){ /* current state? */
7458 stack |= ((unsigned long) gPasteEnabled << stackp);
7459 stackp += 2;
7462 gPasteEnabled = on;
7463 break;
7466 #ifdef ACCELERATORS
7467 UpdateAccelerators(ghTTYWnd);
7468 #endif
7473 * Signals whether or not Copy/Cut should be turned on in the
7474 * menu bar.
7476 void
7477 mswin_allowcopy (getc_t copyfunc)
7479 gCopyCutFunction = copyfunc;
7480 gAllowCopy = (copyfunc != NULL);
7481 #ifdef ACCELERATORS
7482 UpdateAccelerators(ghTTYWnd);
7483 #endif
7488 * Signals whether or not Copy/Cut should be turned on in the
7489 * menu bar.
7491 void
7492 mswin_allowcopycut (getc_t copyfunc)
7494 gCopyCutFunction = copyfunc;
7495 gAllowCopy = gAllowCut = (copyfunc != NULL);
7496 #ifdef ACCELERATORS
7497 UpdateAccelerators(ghTTYWnd);
7498 #endif
7503 * Replace the clipboard's contents with the given string
7505 void
7506 mswin_addclipboard(char *s)
7508 HANDLE hCB;
7509 char *pCB;
7510 size_t sSize;
7512 if(s && (sSize = strlen(s))){
7513 if (OpenClipboard (ghTTYWnd)) { /* ...and we get the CB. */
7514 if (EmptyClipboard ()
7515 && (hCB = GlobalAlloc (GMEM_MOVEABLE, sSize+2))){
7516 pCB = GlobalLock (hCB);
7517 memcpy (pCB, s, sSize);
7518 pCB[sSize] = '\0'; /* tie it off */
7520 GlobalUnlock (hCB);
7522 if (SetClipboardData (CF_TEXT, hCB) == NULL)
7523 /* Failed! Free the data. */
7524 GlobalFree (hCB);
7527 CloseClipboard ();
7534 * Signals if the upper layer wants to track the mouse.
7536 void
7537 mswin_allowmousetrack (int b)
7539 gAllowMouseTrack = b;
7540 if (b)
7541 SelClear ();
7542 MyTimerSet ();
7547 * register's callback to warn
7549 void
7550 mswin_mousetrackcallback(cbarg_t cbfunc)
7552 if(!(gMouseTrackCallback = cbfunc))
7553 mswin_setcursor (MSWIN_CURSOR_ARROW);
7558 * Add text to the new mail icon.
7559 * Nothing done in win 3.1 (consider changing the program name?)
7560 * For win95 we add some tool tip text to the tray icon.
7562 void
7563 mswin_newmailtext (char *t_utf8)
7565 LPTSTR t_lptstr;
7568 * If we're given text, then blip the icon to let the user know.
7569 * (NOTE: the new shell also gets an updated tooltip.)
7570 * Otherwise, we're being asked to resume our normal state...
7572 if(t_utf8){
7574 * Change the appearance of minimized icon so user knows there's new
7575 * mail waiting for them. On win 3.1 systems we redraw the icon.
7576 * on win95 systems we update the icon in the task bar,
7577 * and possibly update the small icon in the taskbar tool tray.
7579 t_lptstr = utf8_to_lptstr(t_utf8);
7580 UpdateTrayIcon(NIM_MODIFY, ghNewMailIcon, t_lptstr);
7581 fs_give((void **) &t_lptstr);
7582 PostMessage(ghTTYWnd,WM_SETICON,ICON_BIG,(LPARAM) ghNewMailIcon);
7583 PostMessage(ghTTYWnd,WM_SETICON,ICON_SMALL,(LPARAM) ghNewMailIcon);
7585 gpTTYInfo->fNewMailIcon = TRUE;
7587 else if(gpTTYInfo->fNewMailIcon) {
7588 UpdateTrayIcon(NIM_MODIFY, ghNormalIcon, TEXT("Alpine"));
7589 PostMessage(ghTTYWnd,WM_SETICON,ICON_BIG,(LPARAM) ghNormalIcon);
7590 PostMessage(ghTTYWnd,WM_SETICON,ICON_SMALL,(LPARAM) ghNormalIcon);
7592 gpTTYInfo->fNewMailIcon = FALSE;
7597 void
7598 mswin_mclosedtext (char *t_utf8)
7600 LPTSTR t_lptstr;
7602 if(t_utf8 && gpTTYInfo->fMClosedIcon == FALSE){
7604 * Change the appearance of minimized icon so user knows
7605 * the mailbox closed.
7607 t_lptstr = utf8_to_lptstr(t_utf8);
7608 UpdateTrayIcon(NIM_MODIFY, ghMClosedIcon, t_lptstr);
7609 fs_give((void **) &t_lptstr);
7610 PostMessage(ghTTYWnd,WM_SETICON,ICON_BIG,(LPARAM) ghMClosedIcon);
7611 PostMessage(ghTTYWnd,WM_SETICON,ICON_SMALL,(LPARAM) ghMClosedIcon);
7613 gpTTYInfo->fMClosedIcon = TRUE;
7615 else if(t_utf8 == NULL && gpTTYInfo->fMClosedIcon) {
7616 /* only go from yellow to green */
7617 UpdateTrayIcon(NIM_MODIFY, ghNormalIcon, TEXT("Alpine"));
7618 PostMessage(ghTTYWnd,WM_SETICON,ICON_BIG,(LPARAM) ghNormalIcon);
7619 PostMessage(ghTTYWnd,WM_SETICON,ICON_SMALL,(LPARAM) ghNormalIcon);
7621 gpTTYInfo->fMClosedIcon = FALSE;
7625 void
7626 mswin_trayicon(int show)
7628 if(show){
7629 if(!gpTTYInfo->fTrayIcon){
7630 UpdateTrayIcon(NIM_ADD, ghNormalIcon, TEXT("Alpine"));
7631 gpTTYInfo->fTrayIcon = TRUE;
7634 else{
7635 if(gpTTYInfo->fTrayIcon){
7636 UpdateTrayIcon(NIM_DELETE, 0, NULL);
7637 gpTTYInfo->fTrayIcon = FALSE;
7643 void
7644 UpdateTrayIcon(DWORD dwMsg, HICON hIcon, LPTSTR tip)
7646 NOTIFYICONDATA nt;
7648 nt.cbSize = sizeof (nt);
7649 nt.hWnd = ghTTYWnd;
7650 nt.uID = TASKBAR_ICON_NEWMAIL;
7651 switch(dwMsg){
7652 case NIM_DELETE :
7653 nt.uFlags = 0;
7654 break;
7656 case NIM_ADD : /* send msg to add icon to tray */
7657 nt.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
7658 nt.uCallbackMessage = TASKBAR_ICON_MESSAGE;
7660 if(tip){
7661 _tcsncpy (nt.szTip, tip, 63);
7662 nt.szTip[63] = '\0';
7664 else
7665 nt.szTip[0] = '\0';
7666 nt.hIcon = hIcon;
7667 break;
7669 case NIM_MODIFY : /* send msg to modify icon in tray */
7670 nt.uFlags = NIF_ICON | NIF_TIP;
7671 if(tip){
7672 _tcsncpy (nt.szTip, tip, 63);
7673 nt.szTip[63] = '\0';
7675 else
7676 nt.szTip[0] = '\0';
7677 nt.hIcon = hIcon;
7678 break;
7680 default :
7681 return;
7684 Shell_NotifyIcon (dwMsg, &nt);
7689 /*---------------------------------------------------------------------------
7691 * Client level menu item stuff.
7693 * These are menu items that activate commands in the "client" program.
7694 * Generally, the client calls us to tell us which menu items are active
7695 * and what key stroke they generate. When such an item is selected it's
7696 * key stroke is injected into the character queue as if it was typed by
7697 * the user.
7699 *-------------------------------------------------------------------------*/
7702 * Clear active status of all "menu items".
7704 void
7705 mswin_menuitemclear (void)
7707 int i;
7708 HWND hWnd;
7711 for (i = 0; i < KS_COUNT; ++i) {
7712 gpTTYInfo->menuItems[i].miActive = FALSE;
7713 if (gpTTYInfo->toolBarSize > 0) {
7714 hWnd = GetDlgItem(gpTTYInfo->hTBWnd, i + KS_RANGESTART);
7715 if (hWnd != NULL)
7716 EnableWindow(hWnd, FALSE);
7720 gpTTYInfo->menuItemsCurrent = FALSE;
7721 gpTTYInfo->menuItemsIndex = 1;
7722 for(i = 0; i < KS_COUNT; i++)
7723 gpTTYInfo->menuItems[i].miIndex = 0;
7728 * Add an item to the cmdmenu
7730 void
7731 mswin_menuitemadd (UCS key, char *label, int menuitem, int flags)
7733 int i;
7734 HWND hWnd;
7736 if (menuitem >= KS_RANGESTART && menuitem <= KS_RANGEEND) {
7738 gpTTYInfo->menuItemsCurrent = FALSE;
7740 i = menuitem - KS_RANGESTART;
7741 gpTTYInfo->menuItems[i].miActive = TRUE;
7742 gpTTYInfo->menuItems[i].miKey = key;
7743 if(!gpTTYInfo->menuItems[i].miIndex){
7744 gpTTYInfo->menuItems[i].miLabel = label;
7745 gpTTYInfo->menuItems[i].miIndex = gpTTYInfo->menuItemsIndex++;
7748 if (gpTTYInfo->toolBarSize > 0) {
7749 hWnd = GetDlgItem(gpTTYInfo->hTBWnd, menuitem);
7750 if (hWnd != NULL)
7751 EnableWindow(hWnd, TRUE);
7758 * Called when a menu command arrives with an unknown ID. If it is
7759 * within the range of the additional menu items, insert the
7760 * corresponding character into the char input queue.
7762 void
7763 ProcessMenuItem (HWND hWnd, WPARAM wParam)
7765 PTTYINFO pTTYInfo;
7766 int i;
7768 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
7769 if (pTTYInfo == NULL)
7770 return;
7773 if (wParam >= KS_RANGESTART && wParam <= KS_RANGEEND) {
7774 i = (int)(wParam - KS_RANGESTART);
7775 if (pTTYInfo->menuItems[i].miActive)
7776 CQAdd (pTTYInfo->menuItems[i].miKey, 0);
7782 * Called to set a new menu.
7785 mswin_setwindowmenu (int menu)
7787 int oldmenu;
7788 HMENU holdmenu;
7789 HMENU hmenu;
7792 oldmenu = gpTTYInfo->curWinMenu;
7793 holdmenu = GetMenu (ghTTYWnd);
7794 if (gpTTYInfo->curWinMenu != menu) {
7796 hmenu = LoadMenu (ghInstance, MAKEINTRESOURCE (menu));
7797 if (hmenu != NULL) {
7798 if (SetMenu (ghTTYWnd, hmenu) != 0) {
7799 DestroyMenu (holdmenu);
7800 gfHelpMenu = gfHelpGenMenu = FALSE;
7801 gpTTYInfo->curWinMenu = menu;
7805 if(menu == MENU_DEFAULT){
7806 TBSwap (ghTTYWnd, IDD_TOOLBAR);
7807 if(hmenu != NULL)
7808 (void) MSWHelpSetMenu(hmenu);
7810 else{
7811 TBSwap (ghTTYWnd, IDD_COMPOSER_TB);
7814 return (oldmenu);
7819 /*---------------------------------------------------------------------------
7821 * Printing stuff
7823 *-------------------------------------------------------------------------*/
7826 * Printing globals
7828 LOCAL HDC P_PrintDC; /* Printer device context. */
7829 LOCAL int P_PageRows; /* Number of rows we put on a page. */
7830 LOCAL int P_PageColumns; /* Number of columns we put on a page. */
7831 LOCAL int P_RowHeight; /* Height of a row in printer pixels. */
7832 LOCAL int P_CurRow; /* Current row, starting at zero */
7833 LOCAL int P_CurCol; /* Current col, starting at zero. */
7834 LOCAL int P_TopOffset; /* Top Margin offset, in pixels. */
7835 LOCAL int P_LeftOffset; /* Top Margin offset, in pixels. */
7836 LOCAL HFONT P_hFont; /* Handle to printing font. */
7837 LPTSTR P_LineText; /* Pointer to line buffer. */
7843 * Define the margin as number of lines at top and bottom of page.
7844 * (might be better to define as a percent of vertical page size)
7846 #define VERTICLE_MARGIN 3 /* lines at top and bottom of page. */
7847 #define HORIZONTAL_MARGIN 1 /* margine at left & right in chars */
7850 * Several errors that can be reported.
7852 #define PE_DIALOG_FAILED 1
7853 #define PE_USER_CANCEL 2
7854 #define PE_CANT_START_DOC 3
7855 #define PE_CANT_FINISH_DOC 4
7856 #define PE_OUT_OF_MEMORY 5
7857 #define PE_GENERAL_ERROR 6
7858 #define PE_OUT_OF_DISK 7
7859 #define PE_PRINTER_NOT_FOUND 8
7860 #define PE_PINE_INTERNAL 9
7861 #define PE_FONT_FAILED 10
7864 LOCAL struct pe_error_message {
7865 int error_code;
7866 char *error_message;
7867 } P_ErrorMessages[] = {
7868 { PE_DIALOG_FAILED, "Print Dialog Failed"},
7869 { PE_USER_CANCEL, "User canceled" },
7870 { PE_CANT_START_DOC, "Can't start document" },
7871 { PE_OUT_OF_MEMORY, "Out of memory" },
7872 { PE_CANT_FINISH_DOC, "Can't finish document" },
7873 { PE_OUT_OF_MEMORY, "Out of memory" },
7874 { PE_OUT_OF_DISK, "Out of disk space" },
7875 { PE_PRINTER_NOT_FOUND, "Printer not found" },
7876 { PE_PINE_INTERNAL, "Pine internal error" },
7877 { PE_FONT_FAILED, "Failed to create font" },
7878 { 0, NULL }};
7883 * Send text in the line buffer to the printer.
7884 * Advance to next page if necessary.
7886 LOCAL int
7887 _print_send_line (void)
7889 int status;
7891 status = 0;
7892 if (P_CurCol > 0)
7893 TextOut (P_PrintDC, P_LeftOffset,
7894 P_TopOffset + (P_CurRow * P_RowHeight),
7895 P_LineText, P_CurCol);
7896 P_CurCol = 0;
7897 if (++P_CurRow >= P_PageRows)
7898 status = _print_send_page ();
7900 return (status);
7906 * Advance one page.
7909 _print_send_page (void)
7911 DWORD status;
7913 if((status = EndPage (P_PrintDC)) > 0){
7914 P_CurRow = 0;
7915 if((status = StartPage (P_PrintDC)) > 0){
7916 SelectObject (P_PrintDC, P_hFont);
7917 return(0);
7921 #ifdef WIN32
7922 ExplainSystemErr();
7923 return(PE_GENERAL_ERROR);
7924 #else
7925 switch (status) {
7926 case SP_USERABORT: return (PE_USER_CANCEL);
7927 case SP_OUTOFDISK: return (PE_OUT_OF_DISK);
7928 case SP_OUTOFMEMORY: return (PE_OUT_OF_MEMORY);
7929 default:
7930 case SP_ERROR: break;
7932 #endif
7933 return (PE_GENERAL_ERROR);
7939 * Map errors reported to my own error set.
7942 _print_map_dlg_error (DWORD error)
7944 switch (error) {
7945 case 0: return (PE_USER_CANCEL);
7946 case CDERR_MEMALLOCFAILURE:
7947 case CDERR_MEMLOCKFAILURE:
7948 return (PE_OUT_OF_MEMORY);
7949 case PDERR_PRINTERNOTFOUND:
7950 case PDERR_NODEVICES:
7951 return (PE_PRINTER_NOT_FOUND);
7952 case CDERR_STRUCTSIZE:
7953 return (PE_PINE_INTERNAL);
7954 default:
7955 return (PE_GENERAL_ERROR);
7961 * This is used for converting from UTF-8 to UCS and is
7962 * global so that mswin_print_ready can initialize it.
7964 static CBUF_S print_cb;
7967 * Get the printer ready. Returns ZERO for success, or an error code that
7968 * can be passed to mswin_print_error() to get a text message.
7971 mswin_print_ready(WINHAND hWnd, LPTSTR docDesc)
7973 PRINTDLG pd;
7974 DOCINFO di;
7975 TEXTMETRIC tm;
7976 HDC hDC;
7977 int fontSize; /* Size in Points. */
7978 int ppi; /* Pixels per inch in device. */
7979 int xChar;
7980 int status;
7981 HFONT oldFont;
7982 LOGFONT newFont;
7985 status = 0;
7986 P_PrintDC = NULL;
7988 print_cb.cbufp = print_cb.cbuf;
7991 * Show print dialog.
7993 memset(&pd, 0, sizeof(PRINTDLG));
7994 pd.lStructSize = sizeof (PRINTDLG);
7995 pd.hwndOwner = (hWnd ? (HWND) hWnd : ghTTYWnd);
7996 pd.hDevMode = NULL;
7997 pd.hDevNames = NULL;
7998 pd.Flags = PD_ALLPAGES | PD_NOSELECTION | PD_NOPAGENUMS |
7999 PD_HIDEPRINTTOFILE | PD_RETURNDC;
8000 pd.nCopies = 1;
8001 if(PrintDlg (&pd) == 0)
8002 return(_print_map_dlg_error (CommDlgExtendedError()));
8005 * Returns the device name which we could use to remember what printer
8006 * they selected. But instead, we just toss them.
8008 if (pd.hDevNames)
8009 GlobalFree (pd.hDevNames);
8010 if (pd.hDevMode)
8011 GlobalFree (pd.hDevMode);
8014 * Get the device drawing context.
8015 * (does PringDlg() ever return success but fail to return a DC?)
8017 if (pd.hDC != NULL)
8018 P_PrintDC = pd.hDC;
8019 else {
8020 status = PE_DIALOG_FAILED;
8021 goto Done;
8025 * Start Document
8027 memset(&di, 0, sizeof (DOCINFO));
8028 di.cbSize = sizeof (DOCINFO);
8029 di.lpszDocName = docDesc; /* This appears in the print manager*/
8030 di.lpszOutput = NULL; /* Could suply a file name to print
8031 to. */
8032 if(StartDoc(P_PrintDC, &di) <= 0) {
8033 ExplainSystemErr();
8034 status = PE_CANT_START_DOC;
8035 DeleteDC (P_PrintDC);
8036 P_PrintDC = NULL;
8037 goto Done;
8041 * Printer font is either same as window font, or is it's own
8042 * font.
8044 if (gPrintFontSameAs) {
8047 * Get the current font size in points, then create a new font
8048 * of same size for printer. Do the calculation using the actual
8049 * screen resolution instead of the logical resolution so that
8050 * we get pretty close to the same font size on the printer
8051 * as we see on the screen.
8053 hDC = GetDC (ghTTYWnd); /* Temp screen DC. */
8054 ppi = (int) ((float)GetDeviceCaps (hDC, VERTRES) /
8055 ((float) GetDeviceCaps (hDC, VERTSIZE) / 25.3636));
8056 #ifdef FDEBUG
8057 if (mswin_debug >= 8) {
8058 fprintf (mswin_debugfile, "mswin_print_ready: Screen res %d ppi, font height %d pixels\n",
8059 ppi, -gpTTYInfo->lfTTYFont.lfHeight);
8060 fprintf (mswin_debugfile, " Screen height %d pixel, %d mm\n",
8061 GetDeviceCaps (hDC, VERTRES), GetDeviceCaps (hDC, VERTSIZE));
8063 #endif
8064 ReleaseDC (ghTTYWnd, hDC);
8066 /* Convert from screen pixels to points. */
8067 fontSize = MulDiv (-gpTTYInfo->lfTTYFont.lfHeight, 72, ppi);
8068 ++fontSize; /* Fudge a little. */
8071 /* Get printer resolution and convert form points to printer pixels. */
8072 ppi = GetDeviceCaps (P_PrintDC, LOGPIXELSY);
8073 newFont.lfHeight = -MulDiv (fontSize, ppi, 72);
8074 _tcsncpy(newFont.lfFaceName, gpTTYInfo->lfTTYFont.lfFaceName, LF_FACESIZE);
8075 newFont.lfFaceName[LF_FACESIZE-1] = 0;
8076 newFont.lfItalic = gpTTYInfo->lfTTYFont.lfItalic;
8077 newFont.lfWeight = gpTTYInfo->lfTTYFont.lfWeight;
8078 newFont.lfCharSet = gpTTYInfo->lfTTYFont.lfCharSet;
8081 #ifdef FDEBUG
8082 if (mswin_debug >= 8) {
8083 fprintf (mswin_debugfile, " font Size %d points\n",
8084 fontSize);
8085 fprintf (mswin_debugfile, " printer res %d ppi, font height %d pixels\n",
8086 ppi, -newFont.lfHeight);
8087 fprintf (mswin_debugfile, " paper height %d pixel, %d mm\n",
8088 GetDeviceCaps (P_PrintDC, VERTRES),
8089 GetDeviceCaps (P_PrintDC, VERTSIZE));
8091 #endif
8093 else {
8094 ppi = GetDeviceCaps (P_PrintDC, LOGPIXELSY);
8095 newFont.lfHeight = -MulDiv (gPrintFontSize, ppi, 72);
8096 _tcsncpy(newFont.lfFaceName, gPrintFontName, LF_FACESIZE);
8097 newFont.lfFaceName[LF_FACESIZE-1] = 0;
8098 newFont.lfWeight = 0;
8099 if(_tcsstr(gPrintFontStyle, TEXT("bold")))
8100 newFont.lfWeight = FW_BOLD;
8102 newFont.lfItalic = 0;
8103 if(_tcsstr(gPrintFontStyle, TEXT("italic")))
8104 newFont.lfItalic = 1;
8106 newFont.lfCharSet = mswin_string2charsetid(gPrintFontCharSet);
8110 /* Fill out rest of font description and request font. */
8111 newFont.lfWidth = 0;
8112 newFont.lfEscapement = 0;
8113 newFont.lfOrientation = 0;
8114 newFont.lfUnderline = 0;
8115 newFont.lfStrikeOut = 0;
8116 newFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
8117 newFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
8118 newFont.lfQuality = DEFAULT_QUALITY;
8119 newFont.lfPitchAndFamily = FIXED_PITCH;
8120 P_hFont = CreateFontIndirect (&newFont);
8121 if (P_hFont == NULL) {
8122 status = PE_FONT_FAILED;
8123 DeleteDC (P_PrintDC);
8124 goto Done;
8129 * Start page.
8130 * Must select font for each page or it returns to default.
8131 * Windows seems good about mapping selected font to a font that
8132 * will actually print on the printer.
8134 StartPage (P_PrintDC);
8135 oldFont = SelectObject (P_PrintDC, P_hFont);
8139 * Find out about the font we got and set up page size and margins.
8140 * This assumes all pages are the same size - which seems reasonable.
8142 GetTextMetrics (P_PrintDC, &tm);
8143 xChar = tm.tmAveCharWidth;
8144 P_RowHeight = tm.tmHeight + tm.tmExternalLeading;
8146 /* HORZRES and VERTRES report size of page in printer pixels. */
8147 P_PageColumns = GetDeviceCaps (P_PrintDC, HORZRES) / xChar;
8148 P_PageRows = GetDeviceCaps (P_PrintDC, VERTRES) / P_RowHeight;
8150 /* We allow a margin at top and bottom measured in text rows. */
8151 P_PageRows -= VERTICLE_MARGIN * 2;
8152 P_TopOffset = VERTICLE_MARGIN * P_RowHeight;
8154 /* And allow for a left and right margine measured in characters. */
8155 P_PageColumns -= HORIZONTAL_MARGIN * 2;
8156 P_LeftOffset = HORIZONTAL_MARGIN * xChar;
8158 P_CurRow = 0; /* Start counting at row 0. */
8159 P_CurCol = 0; /* At character 0. */
8160 P_LineText = (LPTSTR) MemAlloc((P_PageColumns + 1) * sizeof(TCHAR));
8161 if(P_LineText == NULL){
8162 if(EndDoc (P_PrintDC) <= 0)
8163 ExplainSystemErr();
8165 DeleteObject (P_hFont);
8166 P_hFont = NULL;
8167 DeleteDC (P_PrintDC);
8168 P_PrintDC = NULL;
8169 status = PE_OUT_OF_MEMORY;
8170 goto Done;
8174 Done:
8175 return (status);
8180 * Called when printing is done.
8181 * xxx what happens if there is an error? Will this get called?
8184 mswin_print_done(void)
8186 if(P_PrintDC != NULL){
8187 if(P_LineText != NULL)
8188 MemFree((void *) P_LineText);
8190 if(EndPage (P_PrintDC) <= 0 || EndDoc (P_PrintDC) <= 0)
8191 ExplainSystemErr();
8193 DeleteObject(P_hFont);
8194 P_hFont = NULL;
8195 DeleteDC(P_PrintDC);
8196 P_PrintDC = NULL;
8199 return (0);
8204 * Return pointer to a text string that describes the error.
8206 char *
8207 mswin_print_error(int error_code)
8209 int i;
8211 for(i = 0; P_ErrorMessages[i].error_message != NULL; ++i)
8212 if(P_ErrorMessages[i].error_code == error_code)
8213 return(P_ErrorMessages[i].error_message);
8215 return("(Unknown error)");
8220 * Add a single character to the current line.
8221 * Only handles CRLF carrage control.
8224 mswin_print_char(TCHAR c)
8226 switch(c){
8227 case ASCII_CR:
8228 return(0);
8230 case ASCII_LF:
8231 return(_print_send_line());
8233 case ASCII_TAB:
8235 if(P_CurCol == P_PageColumns)
8236 return(_print_send_line());
8238 *(P_LineText + P_CurCol++) = ' ';
8240 while(P_CurCol % PRINT_TAB_SIZE != 0);
8241 return(0);
8243 default:
8244 if(P_CurCol == P_PageColumns){
8245 int status;
8247 if((status = _print_send_line()) != 0)
8248 return(status);
8251 *(P_LineText + P_CurCol++) = c;
8252 return(0);
8258 mswin_print_char_utf8(int c)
8260 UCS ucs;
8261 TCHAR tc;
8262 int ret = 0;
8264 if(utf8_to_ucs4_oneatatime(c, &print_cb, &ucs, NULL)){
8265 /* bogus conversion ignores UTF-16 */
8266 tc = (TCHAR) ucs;
8267 ret = mswin_print_char(tc);
8270 return(ret);
8275 * Send a string to the printer.
8278 mswin_print_text(LPTSTR text)
8280 int status;
8282 if(text)
8283 while(*text)
8284 if((status = mswin_print_char(*(text++))) != 0)
8285 return(status);
8287 return(0);
8292 mswin_print_text_utf8(char *text_utf8)
8294 LPTSTR text_lpt;
8295 int ret = 0;
8297 if(text_utf8){
8298 text_lpt = utf8_to_lptstr(text_utf8);
8299 if(text_lpt){
8300 ret = mswin_print_text(text_lpt);
8301 fs_give((void **) &text_lpt);
8305 return(ret);
8309 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8311 * File dialog boxes.
8313 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
8315 LOCAL TCHAR gHomeDir[PATH_MAX];
8316 LOCAL TCHAR gLastDir[PATH_MAX];
8319 * Keep track of the last dir visited. Most of the time pine just passes us
8320 * the "home directory", which usually is not where the user wants to start.
8321 * Assume that the first time we are called we are being passed the home
8322 * directory.
8324 static void
8325 FillInitialDir (LPCTSTR *iDir, LPTSTR targDir)
8327 if (_tcslen (gHomeDir) == 0) {
8328 _tcscpy (gHomeDir, targDir);
8329 *iDir = targDir;
8331 else if (_tcscmp (gHomeDir, targDir) == 0 && *gLastDir)
8332 *iDir = gLastDir;
8333 else
8334 *iDir = targDir;
8340 * Display a save file dialog box.
8342 * dir_utf8 > directory to start search in
8343 * < directory finished in.
8344 * fName_utf8 < Name of file selected
8345 * nMaxDName length of dir_utf8
8346 * nMaxFName length of fName_utf8.
8348 * Possible return values:
8349 * 0 no file selected
8350 * 1 file selected
8351 * -1 some sort of error
8354 mswin_savefile(char *dir_utf8, int nMaxDName, char *fName_utf8, int nMaxFName)
8356 OPENFILENAME ofn;
8357 TCHAR filters[128], moniker[128];
8358 DWORD rc, len;
8359 LPTSTR p, extlist_lpt;
8360 LPTSTR fName_lpt, f, dir_lpt;
8361 char *cp;
8363 /* convert fName_utf8 to LPTSTR */
8364 fName_lpt = (LPTSTR) fs_get(nMaxFName * sizeof(TCHAR));
8365 fName_lpt[0] = '\0';
8366 if(fName_utf8 && fName_utf8[0]){
8367 f = utf8_to_lptstr(fName_utf8);
8368 if(f){
8369 _tcsncpy(fName_lpt, f, nMaxFName);
8370 fName_lpt[nMaxFName-1] = '\0';
8371 fs_give((void **) &f);
8375 dir_lpt = (LPTSTR) fs_get(nMaxDName * sizeof(TCHAR));
8376 dir_lpt[0] = '\0';
8377 if(dir_utf8 && dir_utf8[0]){
8378 f = utf8_to_lptstr(dir_utf8);
8379 if(f){
8380 _tcsncpy(dir_lpt, f, nMaxDName);
8381 dir_lpt[nMaxDName-1] = '\0';
8382 fs_give((void **) &f);
8386 for(extlist_lpt = NULL, p = _tcschr(fName_lpt, '.'); p; p = _tcschr(++p, '.'))
8387 extlist_lpt = p;
8389 len = sizeof(moniker)/sizeof(TCHAR);
8390 if(extlist_lpt && MSWRPeek(HKEY_CLASSES_ROOT, extlist_lpt, NULL, moniker, &len) == TRUE){
8391 len = sizeof(filters)/sizeof(TCHAR);
8392 filters[0] = '\0';
8393 if(MSWRPeek(HKEY_CLASSES_ROOT, moniker, NULL, filters, &len) == TRUE)
8394 _sntprintf(filters + _tcslen(filters),
8395 sizeof(filters)/sizeof(TCHAR) - _tcslen(filters),
8396 TEXT(" (*%s)#*%s#"), extlist_lpt, extlist_lpt);
8397 else
8398 _sntprintf(filters, sizeof(filters)/sizeof(TCHAR),
8399 TEXT("%s (*%s)#*%s#"), moniker, extlist_lpt, extlist_lpt);
8401 else
8402 filters[0] = '\0';
8404 _tcsncat(filters, TEXT("Text Files (*.txt)#*.txt#All Files (*.*)#*.*#"),
8405 sizeof(filters)/sizeof(TCHAR));
8406 filters[sizeof(filters)/sizeof(TCHAR) - 1] = '\0';
8408 for(p = filters; *p != '\0'; ++p)
8409 if(*p == L'#')
8410 *p = '\0';
8412 /* Set up the BIG STRUCTURE. */
8413 memset (&ofn, 0, sizeof(ofn));
8415 * sizeof(OPENFILENAME) used to work but doesn't work now with
8416 * pre-Windows 2000. This is supposed to be the magic constant to
8417 * make it work in both cases, according to MSDN.
8419 ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
8420 ofn.hwndOwner = ghTTYWnd;
8421 ofn.lpstrFilter = filters;
8422 ofn.lpstrCustomFilter = NULL;
8423 ofn.nFilterIndex = 1;
8424 ofn.lpstrFile = fName_lpt;
8425 ofn.nMaxFile = nMaxFName;
8426 ofn.lpstrFileTitle = NULL;
8427 ofn.nMaxFileTitle = 0;
8428 FillInitialDir (&ofn.lpstrInitialDir, dir_lpt);
8429 ofn.lpstrTitle = TEXT("Save To File");
8430 ofn.Flags = OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
8431 ofn.lpstrDefExt = TEXT("txt");
8433 if(GetSaveFileName(&ofn)){
8434 if(ofn.nFileOffset > nMaxDName-1){
8435 if(fName_lpt)
8436 fs_give((void **) &fName_lpt);
8438 if(dir_lpt)
8439 fs_give((void **) &dir_lpt);
8441 return(0);
8444 /* Copy directory name to dir_lpt. */
8445 _tcsncpy(dir_lpt, fName_lpt, nMaxDName-1);
8446 dir_lpt[nMaxDName-1] = '\0';
8447 if(dir_lpt[ofn.nFileOffset-1] == '\\'
8448 && !(ofn.nFileOffset == 3 && _istalpha(dir_lpt[0]) && dir_lpt[1] == ':'))
8449 dir_lpt[ofn.nFileOffset-1] = '\0';
8450 else
8451 dir_lpt[ofn.nFileOffset] = '\0';
8453 /* Remember last dir visited. */
8454 _tcsncpy(gLastDir, dir_lpt, PATH_MAX);
8455 gLastDir[PATH_MAX-1] = '\0';
8457 /* convert back to UTF-8 */
8458 cp = lptstr_to_utf8(dir_lpt);
8459 if(cp){
8460 strncpy(dir_utf8, cp, nMaxDName-1);
8461 dir_utf8[nMaxDName-1] = '\0';
8462 fs_give((void **) &cp);
8465 p = fName_lpt + ofn.nFileOffset;
8467 /* convert fName back to UTF-8 */
8468 cp = lptstr_to_utf8(p);
8469 if(cp){
8470 strncpy(fName_utf8, cp, nMaxFName-1);
8471 fName_utf8[nMaxFName-1] = '\0';
8472 fs_give((void **) &cp);
8475 if(fName_lpt)
8476 fs_give((void **) &fName_lpt);
8478 if(dir_lpt)
8479 fs_give((void **) &dir_lpt);
8481 return(1);
8483 else{
8484 if(fName_lpt)
8485 fs_give((void **) &fName_lpt);
8487 if(dir_lpt)
8488 fs_give((void **) &dir_lpt);
8490 rc = CommDlgExtendedError();
8491 return(rc ? -1 : 0);
8499 * Display an open file dialog box.
8501 * dir_utf8 > directory to start search in
8502 * < directory finished in.
8503 * fName_utf8 < Name of file selected
8504 * nMaxDName length of dir_utf8
8505 * nMaxFName length of fName_utf8.
8507 * Possible return values:
8508 * 0 no file selected
8509 * 1 file selected
8510 * -1 some sort of error +++++++++++++
8513 mswin_openfile(char *dir_utf8, int nMaxDName, char *fName_utf8,
8514 int nMaxFName, char *extlist_utf8)
8516 OPENFILENAME ofn;
8517 TCHAR filters[1024];
8518 DWORD rc;
8519 LPTSTR p;
8520 LPTSTR extlist_lpt = NULL;
8521 LPTSTR fName_lpt, f, dir_lpt;
8522 char *cp;
8525 if(extlist_utf8)
8526 extlist_lpt = utf8_to_lptstr(extlist_utf8);
8529 * Set filters array. (pairs of null terminated strings, terminated
8530 * by a double null).
8532 _sntprintf(filters, sizeof(filters)/sizeof(TCHAR),
8533 TEXT("%s%sAll Files (*.*)#*.*#"),
8534 extlist_lpt ? extlist_lpt : TEXT(""), extlist_lpt ? TEXT("#") : TEXT(""));
8536 if(extlist_lpt)
8537 fs_give((void **) &extlist_lpt);
8539 for(p = filters; *p != '\0'; ++p)
8540 if(*p == L'#')
8541 *p = '\0';
8543 /* Set up the BIG STRUCTURE. */
8544 memset(&ofn, 0, sizeof(ofn));
8546 /* convert fName_utf8 to LPTSTR */
8547 fName_lpt = (LPTSTR) fs_get(nMaxFName * sizeof(TCHAR));
8548 fName_lpt[0] = '\0';
8549 if(fName_utf8 && fName_utf8[0]){
8550 f = utf8_to_lptstr(fName_utf8);
8551 if(f){
8552 _tcsncpy(fName_lpt, f, nMaxFName);
8553 fName_lpt[nMaxFName-1] = '\0';
8554 fs_give((void **) &f);
8558 dir_lpt = (LPTSTR) fs_get(nMaxDName * sizeof(TCHAR));
8559 dir_lpt[0] = '\0';
8560 if(dir_utf8 && dir_utf8[0]){
8561 f = utf8_to_lptstr(dir_utf8);
8562 if(f){
8563 _tcsncpy(dir_lpt, f, nMaxDName);
8564 dir_lpt[nMaxDName-1] = '\0';
8565 fs_give((void **) &f);
8570 * sizeof(OPENFILENAME) used to work but doesn't work now with
8571 * pre-Windows 2000. This is supposed to be the magic constant to
8572 * make it work in both cases, according to MSDN.
8574 ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
8575 ofn.hwndOwner = ghTTYWnd;
8576 ofn.lpstrFilter = filters;
8577 ofn.lpstrCustomFilter = NULL;
8578 ofn.nFilterIndex = 1;
8579 ofn.lpstrFile = fName_lpt;
8580 ofn.nMaxFile = nMaxFName;
8581 ofn.lpstrFileTitle = NULL;
8582 ofn.nMaxFileTitle = 0;
8583 FillInitialDir(&ofn.lpstrInitialDir, dir_lpt);
8584 ofn.lpstrTitle = TEXT("Select File");
8585 ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
8586 ofn.lpstrDefExt = TEXT("txt");
8588 if(GetOpenFileName(&ofn)){
8589 if(ofn.nFileOffset > nMaxDName-1){
8590 if(fName_lpt)
8591 fs_give((void **) &fName_lpt);
8593 if(dir_lpt)
8594 fs_give((void **) &dir_lpt);
8596 return(0);
8599 /* Copy directory name to dir_lpt. */
8600 _tcsncpy(dir_lpt, fName_lpt, nMaxDName-1);
8601 dir_lpt[nMaxDName-1] = '\0';
8602 if(dir_lpt[ofn.nFileOffset-1] == '\\'
8603 && !(ofn.nFileOffset == 3 && _istalpha(dir_lpt[0]) && dir_lpt[1] == ':'))
8604 dir_lpt[ofn.nFileOffset-1] = '\0';
8605 else
8606 dir_lpt[ofn.nFileOffset] = '\0';
8608 /* Remember last dir visited. */
8609 _tcsncpy(gLastDir, dir_lpt, PATH_MAX);
8610 gLastDir[PATH_MAX-1] = '\0';
8612 /* convert back to UTF-8 */
8613 cp = lptstr_to_utf8(dir_lpt);
8614 if(cp){
8615 strncpy(dir_utf8, cp, nMaxDName-1);
8616 dir_utf8[nMaxDName-1] = '\0';
8617 fs_give((void **) &cp);
8620 p = fName_lpt + ofn.nFileOffset;
8622 /* convert fName back to UTF-8 */
8623 cp = lptstr_to_utf8(p);
8624 if(cp){
8625 strncpy(fName_utf8, cp, nMaxFName-1);
8626 fName_utf8[nMaxFName-1] = '\0';
8627 fs_give((void **) &cp);
8630 if(fName_lpt)
8631 fs_give((void **) &fName_lpt);
8633 if(dir_lpt)
8634 fs_give((void **) &dir_lpt);
8636 return(1);
8638 else{
8639 if(fName_lpt)
8640 fs_give((void **) &fName_lpt);
8642 if(dir_lpt)
8643 fs_give((void **) &dir_lpt);
8645 rc = CommDlgExtendedError();
8646 return(rc ? -1 : 0);
8652 * Display an open file dialog box.
8653 * Allow selection of multiple files.
8655 * dir_utf8 > directory to start search in
8656 * < directory finished in.
8657 * fName_utf8 < Names of files selected
8658 * nMaxDName length of dir_utf8
8659 * nMaxFName length of fName_utf8.
8661 * Possible return values:
8662 * 0 no file selected
8663 * 1 file selected
8664 * -1 some sort of error
8667 mswin_multopenfile(char *dir_utf8, int nMaxDName, char *fName_utf8,
8668 int nMaxFName, char *extlist_utf8)
8670 OPENFILENAME ofn;
8671 TCHAR filters[1024];
8672 DWORD rc;
8673 LPTSTR p;
8674 LPTSTR extlist_lpt = NULL;
8675 LPTSTR fName_lpt, f, dir_lpt;
8676 char *cp, *q;
8679 if(extlist_utf8)
8680 extlist_lpt = utf8_to_lptstr(extlist_utf8);
8683 * Set filters array. (pairs of null terminated strings, terminated
8684 * by a double null).
8686 _sntprintf(filters, sizeof(filters)/sizeof(TCHAR),
8687 TEXT("%s%sAll Files (*.*)#*.*#"),
8688 extlist_lpt ? extlist_lpt : TEXT(""), extlist_lpt ? TEXT("#") : TEXT(""));
8690 if(extlist_lpt)
8691 fs_give((void **) &extlist_lpt);
8693 for(p = filters; *p != '\0'; ++p)
8694 if(*p == L'#')
8695 *p = '\0';
8697 /* Set up the BIG STRUCTURE. */
8698 memset (&ofn, 0, sizeof(ofn));
8700 /* convert fName_utf8 to LPTSTR */
8701 fName_lpt = (LPTSTR) fs_get(nMaxFName * sizeof(TCHAR));
8702 memset(fName_lpt, 0, nMaxFName * sizeof(TCHAR));
8703 if(fName_utf8 && fName_utf8[0]){
8704 f = utf8_to_lptstr(fName_utf8);
8705 if(f){
8706 _tcsncpy(fName_lpt, f, nMaxFName);
8707 fName_lpt[nMaxFName-1] = '\0';
8708 fs_give((void **) &f);
8712 dir_lpt = (LPTSTR) fs_get(nMaxDName * sizeof(TCHAR));
8713 memset(dir_lpt, 0, nMaxDName * sizeof(TCHAR));
8714 if(dir_utf8 && dir_utf8[0]){
8715 f = utf8_to_lptstr(dir_utf8);
8716 if(f){
8717 _tcsncpy(dir_lpt, f, nMaxDName);
8718 dir_lpt[nMaxDName-1] = '\0';
8719 fs_give((void **) &f);
8724 * sizeof(OPENFILENAME) used to work but doesn't work now with
8725 * pre-Windows 2000. This is supposed to be the magic constant to
8726 * make it work in both cases, according to MSDN.
8728 ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
8729 ofn.hwndOwner = ghTTYWnd;
8730 ofn.lpstrFilter = filters;
8731 ofn.lpstrCustomFilter = NULL;
8732 ofn.nFilterIndex = 1;
8733 ofn.lpstrFile = fName_lpt;
8734 ofn.nMaxFile = nMaxFName;
8735 ofn.lpstrFileTitle = NULL;
8736 ofn.nMaxFileTitle = 0;
8737 FillInitialDir(&ofn.lpstrInitialDir, dir_lpt);
8738 ofn.lpstrTitle = TEXT("Select Files");
8739 ofn.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER |
8740 OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
8741 ofn.lpstrDefExt = TEXT("txt");
8743 if(GetOpenFileName(&ofn)){
8744 if(ofn.nFileOffset > nMaxDName-1){
8745 if(fName_lpt)
8746 fs_give((void **) &fName_lpt);
8748 if(dir_lpt)
8749 fs_give((void **) &dir_lpt);
8751 return(0);
8754 /* Copy directory name to dir_lpt. */
8755 _tcsncpy(dir_lpt, fName_lpt, nMaxDName-1);
8756 dir_lpt[nMaxDName-1] = '\0';
8757 if(dir_lpt[ofn.nFileOffset-1] == '\\'
8758 && !(ofn.nFileOffset == 3 && _istalpha(dir_lpt[0]) && dir_lpt[1] == ':'))
8759 dir_lpt[ofn.nFileOffset-1] = '\0';
8760 else
8761 dir_lpt[ofn.nFileOffset] = '\0';
8763 /* Remember last dir visited. */
8764 _tcsncpy(gLastDir, dir_lpt, PATH_MAX);
8765 gLastDir[PATH_MAX-1] = '\0';
8767 /* convert back to UTF-8 */
8768 cp = lptstr_to_utf8(dir_lpt);
8769 if(cp){
8770 strncpy(dir_utf8, cp, nMaxDName-1);
8771 dir_utf8[nMaxDName-1] = '\0';
8772 fs_give((void **) &cp);
8776 * The file names are all in the same directory and are separated
8777 * by '\0' characters and terminated by double '\0'.
8778 * This fact depends on the OFN_EXPLORER bit being set in the flags
8779 * above.
8781 * This is complicated because we need to convert all of these file
8782 * names to UTF-8.
8784 for(q=fName_utf8, p=fName_lpt + ofn.nFileOffset; *p; p += _tcslen(p)+1){
8785 cp = lptstr_to_utf8(p);
8786 if(cp){
8787 sstrncpy(&q, cp, (int)(nMaxFName-(q-fName_utf8)));
8788 if(q-fName_utf8 < nMaxFName){
8789 *q++ = '\0';
8790 if(q-fName_utf8 < nMaxFName)
8791 *q = '\0'; /* the double null if this is the end */
8793 else
8794 fName_utf8[nMaxFName-1] = '\0';
8796 fs_give((void **) &cp);
8800 fName_utf8[nMaxFName-1] = fName_utf8[nMaxFName-2] = '\0';
8802 if(fName_lpt)
8803 fs_give((void **) &fName_lpt);
8805 if(dir_lpt)
8806 fs_give((void **) &dir_lpt);
8808 return (1);
8810 else{
8811 if(fName_lpt)
8812 fs_give((void **) &fName_lpt);
8814 if(dir_lpt)
8815 fs_give((void **) &dir_lpt);
8817 rc = CommDlgExtendedError();
8818 return(rc ? -1 : 0);
8823 /*---------------------------------------------------------------------------
8827 * pico_XXcolor() - each function sets a particular attribute
8829 void
8830 pico_nfcolor(char *s)
8832 char cbuf[MAXCLEN];
8834 if(s){
8835 SetColorAttribute (&gpTTYInfo->rgbFGColor, s);
8836 pico_set_nfg_color();
8838 if(the_normal_color){
8839 strncpy(the_normal_color->fg,
8840 ConvertStringRGB(cbuf, sizeof(cbuf), gpTTYInfo->rgbFGColor),
8841 MAXCOLORLEN+1);
8842 the_normal_color->fg[MAXCOLORLEN] = '\0';
8845 else{
8846 gpTTYInfo->rgbFGColor = GetSysColor (COLOR_WINDOWTEXT);
8847 if(the_normal_color)
8848 free_color_pair(&the_normal_color);
8851 // Update all textwindows with the new FG color.
8852 mswin_tw_setcolor((MSWIN_TEXTWINDOW *)-1,
8853 gpTTYInfo->rgbFGColor, gpTTYInfo->rgbBGColor);
8857 void
8858 pico_nbcolor(char *s)
8860 char cbuf[MAXCLEN];
8862 if(s){
8863 SetColorAttribute (&gpTTYInfo->rgbBGColor, s);
8864 pico_set_nbg_color();
8866 if(the_normal_color){
8867 strncpy(the_normal_color->bg,
8868 ConvertStringRGB(cbuf, sizeof(cbuf), gpTTYInfo->rgbBGColor),
8869 MAXCOLORLEN+1);
8870 the_normal_color->fg[MAXCOLORLEN] = '\0';
8873 else{
8874 gpTTYInfo->rgbBGColor = GetSysColor (COLOR_WINDOW);
8875 if(the_normal_color)
8876 free_color_pair(&the_normal_color);
8879 // Update all textwindows with the new BG color.
8880 mswin_tw_setcolor((MSWIN_TEXTWINDOW *)-1,
8881 gpTTYInfo->rgbFGColor, gpTTYInfo->rgbBGColor);
8885 void
8886 pico_rfcolor(char *s)
8888 char cbuf[MAXCLEN];
8890 if(s){
8891 SetColorAttribute (&gpTTYInfo->rgbRFGColor, s);
8893 if(the_rev_color){
8894 strncpy(the_rev_color->fg,
8895 ConvertStringRGB(cbuf, sizeof(cbuf), gpTTYInfo->rgbRFGColor),
8896 MAXCOLORLEN+1);
8897 the_rev_color->fg[MAXCOLORLEN] = '\0';
8900 else{
8901 gpTTYInfo->rgbRFGColor = GetSysColor (COLOR_HIGHLIGHTTEXT);
8902 if(the_rev_color)
8903 free_color_pair(&the_rev_color);
8908 void
8909 pico_rbcolor(char *s)
8911 char cbuf[MAXCLEN];
8913 if(s){
8914 SetColorAttribute (&gpTTYInfo->rgbRBGColor, s);
8916 if(the_rev_color){
8917 strncpy(the_rev_color->bg,
8918 ConvertStringRGB(cbuf, sizeof(cbuf), gpTTYInfo->rgbRBGColor),
8919 MAXCOLORLEN+1);
8920 the_rev_color->bg[MAXCOLORLEN] = '\0';
8923 else{
8924 gpTTYInfo->rgbRBGColor = GetSysColor (COLOR_HIGHLIGHT);
8925 if(the_rev_color)
8926 free_color_pair(&the_rev_color);
8932 pico_usingcolor()
8934 return(TRUE);
8939 pico_count_in_color_table()
8941 return(visibleColorTableSize);
8946 * Return a pointer to an rgb string for the input color. The output is 11
8947 * characters long and looks like rrr,ggg,bbb.
8949 * Args colorName -- The color to convert to ascii rgb.
8951 * Returns Pointer to a static buffer containing the rgb string.
8953 char *
8954 color_to_asciirgb(char *colorName)
8956 static char c_to_a_buf[3][RGBLEN+1];
8957 static int whichbuf = 0;
8958 COLORREF cf;
8959 int l;
8961 whichbuf = (whichbuf + 1) % 3;
8963 if(ConvertRGBString(colorName, &cf)){
8964 snprintf(c_to_a_buf[whichbuf], sizeof(c_to_a_buf[0]), "%.3d,%.3d,%.3d",
8965 GetRValue(cf), GetGValue(cf), GetBValue(cf));
8967 else{
8969 * If we didn't find the color it could be that it is the
8970 * normal color (MATCH_NORM_COLOR) or the none color
8971 * (MATCH_NONE_COLOR). If that is the case, this strncpy thing
8972 * will work out correctly because those two strings are
8973 * RGBLEN long. Otherwise we're in a bit of trouble. This
8974 * most likely means that the user is using the same pinerc on
8975 * two terminals, one with more colors than the other. We didn't
8976 * find a match because this color isn't present on this terminal.
8977 * Since the return value of this function is assumed to be
8978 * RGBLEN long, we'd better make it that long.
8979 * It still won't work correctly because colors will be screwed up,
8980 * but at least the embedded colors in filter.c will get properly
8981 * sucked up when they're encountered.
8983 strncpy(c_to_a_buf[whichbuf], "xxxxxxxxxxx", RGBLEN);
8984 l = (int)strlen(colorName);
8985 strncpy(c_to_a_buf[whichbuf], colorName, (l < RGBLEN) ? l : RGBLEN);
8986 c_to_a_buf[whichbuf][RGBLEN] = '\0';
8989 return(c_to_a_buf[whichbuf]);
8993 void
8994 pico_set_nfg_color()
8996 FlushWriteAccum ();
8997 gpTTYInfo->curAttrib.rgbFG = gpTTYInfo->rgbFGColor;
9000 void
9001 pico_set_nbg_color()
9003 FlushWriteAccum ();
9004 gpTTYInfo->curAttrib.rgbBG = gpTTYInfo->rgbBGColor;
9007 void
9008 pico_set_normal_color()
9010 pico_set_nfg_color();
9011 pico_set_nbg_color();
9014 COLOR_PAIR *
9015 pico_get_rev_color()
9017 char fgbuf[MAXCLEN], bgbuf[MAXCLEN];
9019 if(!the_rev_color)
9020 the_rev_color =
9021 new_color_pair(ConvertStringRGB(fgbuf,sizeof(fgbuf),gpTTYInfo->rgbRFGColor),
9022 ConvertStringRGB(bgbuf,sizeof(bgbuf),gpTTYInfo->rgbRBGColor));
9023 return(the_rev_color);
9026 COLOR_PAIR *
9027 pico_get_normal_color()
9029 char fgbuf[MAXCLEN], bgbuf[MAXCLEN];
9031 if(!the_normal_color)
9032 the_normal_color =
9033 new_color_pair(ConvertStringRGB(fgbuf,sizeof(fgbuf),gpTTYInfo->rgbFGColor),
9034 ConvertStringRGB(bgbuf,sizeof(bgbuf),gpTTYInfo->rgbBGColor));
9035 return(the_normal_color);
9039 * Sets color to (fg,bg).
9040 * Flags == PSC_NONE No alternate default if fg,bg fails.
9041 * == PSC_NORM Set it to Normal color on failure.
9042 * == PSC_REV Set it to Reverse color on failure.
9044 * If flag PSC_RET is set, returns an allocated copy of the previous
9045 * color pair, otherwise returns NULL.
9047 COLOR_PAIR *
9048 pico_set_colors(char *fg, char *bg, int flags)
9050 COLOR_PAIR *cp = NULL;
9052 if(flags & PSC_RET)
9053 cp = pico_get_cur_color();
9055 if(!(fg && bg && pico_set_fg_color(fg) && pico_set_bg_color(bg))){
9057 if(flags & PSC_NORM)
9058 pico_set_normal_color();
9059 else if(flags & PSC_REV)
9060 SetReverseColor();
9063 return(cp);
9068 pico_is_good_color(char *colorName)
9070 COLORREF cf;
9072 if(!struncmp(colorName, MATCH_NORM_COLOR, RGBLEN)
9073 || !struncmp(colorName, MATCH_NONE_COLOR, RGBLEN))
9074 return(TRUE);
9076 return(ConvertRGBString(colorName, &cf));
9081 pico_set_fg_color(char *colorName)
9083 char fgbuf[MAXCLEN];
9085 FlushWriteAccum ();
9087 if(!struncmp(colorName, MATCH_NORM_COLOR, RGBLEN)){
9088 ConvertStringRGB(fgbuf,sizeof(fgbuf),gpTTYInfo->rgbFGColor);
9089 colorName = fgbuf;
9091 else if(!struncmp(colorName, MATCH_NONE_COLOR, RGBLEN))
9092 return(TRUE);
9094 return(ConvertRGBString(colorName, &gpTTYInfo->curAttrib.rgbFG));
9099 pico_set_bg_color(char *colorName)
9101 char bgbuf[MAXCLEN];
9103 FlushWriteAccum ();
9105 if(!struncmp(colorName, MATCH_NORM_COLOR, RGBLEN)){
9106 ConvertStringRGB(bgbuf,sizeof(bgbuf),gpTTYInfo->rgbBGColor);
9107 colorName = bgbuf;
9109 else if(!struncmp(colorName, MATCH_NONE_COLOR, RGBLEN))
9110 return(TRUE);
9112 return(ConvertRGBString(colorName, &gpTTYInfo->curAttrib.rgbBG));
9116 char *
9117 pico_get_last_fg_color()
9119 return(NULL);
9123 char *
9124 pico_get_last_bg_color()
9126 return(NULL);
9130 unsigned
9131 pico_get_color_options()
9133 return((unsigned)0);
9137 void
9138 pico_set_color_options(unsigned int opts)
9143 COLOR_PAIR *
9144 pico_get_cur_color()
9146 char fgbuf[MAXCLEN], bgbuf[MAXCLEN];
9148 return(new_color_pair(ConvertStringRGB(fgbuf,sizeof(fgbuf),gpTTYInfo->curAttrib.rgbFG),
9149 ConvertStringRGB(bgbuf,sizeof(bgbuf),gpTTYInfo->curAttrib.rgbBG)));
9153 char *
9154 mswin_rgbchoice(char *pOldRGB)
9156 CHOOSECOLOR cc;
9157 static COLORREF custColors[16] = {
9158 RGB(0,0,0),
9159 RGB(0,0,255),
9160 RGB(0,255,0),
9161 RGB(0,255,255),
9162 RGB(255,0,0),
9163 RGB(255,0,255),
9164 RGB(255,255,0),
9165 RGB(255,255,255),
9166 RGB(192,192,192),
9167 RGB(128,128,128),
9168 RGB(64,64,64)
9171 memset(&cc, 0, sizeof(CHOOSECOLOR));
9173 cc.lStructSize = sizeof(CHOOSECOLOR);
9174 cc.hwndOwner = ghTTYWnd;
9175 cc.Flags = CC_ANYCOLOR;
9176 cc.lpCustColors = &custColors[0];
9178 if(pOldRGB){
9179 int i;
9181 ConvertRGBString (pOldRGB, &cc.rgbResult);
9182 cc.Flags |= CC_RGBINIT;
9184 for(i = 0; i < 11 && custColors[i] != cc.rgbResult; i++)
9187 if(i == 11){
9188 custColors[i] = cc.rgbResult;
9189 cc.Flags |= CC_FULLOPEN;
9194 if(ChooseColor(&cc)){
9195 char rgbbuf[MAXCLEN], *p;
9197 ConvertStringRGB(rgbbuf, sizeof(rgbbuf), cc.rgbResult);
9198 if(p = MemAlloc(MAXCLEN * sizeof(char))){
9199 strncpy(p, rgbbuf, MAXCLEN);
9200 p[MAXCLEN-1] = '\0';
9201 return(p);
9205 return(NULL);
9211 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9213 * Signal and alarm functions
9215 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
9218 * Provide a rough implementation of the SIGALRM and alarm functions
9223 #if 0
9225 * Set a new handler for a signal.
9227 void (__cdecl * __cdecl signal (int sig,void (__cdecl *hndlr)(int)))(int)
9230 SignalType oldValue;
9232 switch(sig) {
9233 case SIGALRM :
9234 oldValue = gSignalAlarm;
9235 gSignalAlarm = hndlr;
9236 break;
9238 case SIGHUP :
9239 oldValue = gSignalHUP;
9240 gSignalHUP = hndlr;
9242 default:
9243 /* All other's are always ignored. */
9244 oldValue = SIG_IGN;
9245 break;
9248 return (oldValue);
9250 #endif
9254 * Set the alarm expiration time (in seconds)
9257 mswin_alarm (int seconds)
9259 int prevtime;
9261 prevtime = gAlarmTimeout ? (gAlarmTimeout - (GetTickCount () / 1000)): 0;
9262 gAlarmTimeout = seconds ? (GetTickCount() / 1000) + seconds : 0;
9263 MyTimerSet ();
9264 return (prevtime);
9270 * Deliver and clear the alarm.
9272 void
9273 AlarmDeliver ()
9275 if (gSignalAlarm != SIG_DFL && gSignalAlarm != SIG_IGN) {
9276 /* Clear AlarmTimeout BEFORE calling handler. handler may call back
9277 * to reset timeout. */
9278 gAlarmTimeout = 0;
9279 MyTimerSet ();
9280 gSignalAlarm (SIGALRM);
9286 void
9287 HUPDeliver ()
9289 if (gSignalHUP) {
9290 gSignalHUP (SIGHUP);
9291 exit (0);
9298 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9300 * Printer font selection menu
9302 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
9305 * Set the print font to be the same as the window font.
9306 * Toggle setting.
9308 void
9309 PrintFontSameAs (HWND hWnd)
9311 HDC hDC;
9312 int ppi;
9313 PTTYINFO pTTYInfo;
9316 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
9317 if (pTTYInfo == NULL)
9318 return;
9320 if (gPrintFontSameAs) {
9322 /* No longer same as window font. Use window font as starting point
9323 * for new printer font. User may later modify printer font. */
9324 hDC = GetDC (hWnd);
9325 ppi = GetDeviceCaps (hDC, LOGPIXELSY);
9326 ReleaseDC (ghTTYWnd, hDC);
9327 ExtractFontInfo(&pTTYInfo->lfTTYFont,
9328 gPrintFontName, sizeof(gPrintFontName)/sizeof(TCHAR),
9329 &gPrintFontSize,
9330 gPrintFontStyle, sizeof(gPrintFontStyle)/sizeof(TCHAR),
9331 ppi,
9332 gPrintFontCharSet, sizeof(gPrintFontCharSet)/sizeof(TCHAR));
9333 gPrintFontSameAs = FALSE;
9335 else {
9337 /* Set to be same as the printer font. Destroy printer font info
9338 * and set "sameAs" flag to TRUE. */
9339 gPrintFontName[0] = '\0';
9340 gPrintFontSameAs = TRUE;
9342 DidResize (gpTTYInfo);
9349 void
9350 PrintFontSelect (HWND hWnd)
9352 CHOOSEFONT cfTTYFont;
9353 LOGFONT newFont;
9354 DWORD drc;
9355 int ppi;
9356 HDC hDC;
9360 hDC = GetDC (hWnd);
9361 ppi = GetDeviceCaps (hDC, LOGPIXELSY);
9362 ReleaseDC (ghTTYWnd, hDC);
9365 newFont.lfHeight = -MulDiv (gPrintFontSize, ppi, 72);
9366 _tcsncpy(newFont.lfFaceName, gPrintFontName, LF_FACESIZE);
9367 newFont.lfFaceName[LF_FACESIZE-1] = 0;
9368 newFont.lfWeight = 0;
9369 if(_tcsstr(gPrintFontStyle, TEXT("bold")))
9370 newFont.lfWeight = FW_BOLD;
9372 newFont.lfItalic = 0;
9373 if(_tcsstr(gPrintFontStyle, TEXT("italic")))
9374 newFont.lfItalic = 1;
9376 newFont.lfWidth = 0;
9377 newFont.lfEscapement = 0;
9378 newFont.lfOrientation = 0;
9379 newFont.lfUnderline = 0;
9380 newFont.lfStrikeOut = 0;
9381 newFont.lfCharSet = mswin_string2charsetid(gPrintFontCharSet);
9382 newFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
9383 newFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
9384 newFont.lfQuality = DEFAULT_QUALITY;
9385 newFont.lfPitchAndFamily = FIXED_PITCH;
9388 cfTTYFont.lStructSize = sizeof (CHOOSEFONT);
9389 cfTTYFont.hwndOwner = hWnd ;
9390 cfTTYFont.hDC = NULL ;
9391 cfTTYFont.rgbColors = 0;
9392 cfTTYFont.lpLogFont = &newFont;
9393 cfTTYFont.Flags = CF_BOTH | CF_FIXEDPITCHONLY |
9394 CF_INITTOLOGFONTSTRUCT | CF_ANSIONLY |
9395 CF_FORCEFONTEXIST | CF_LIMITSIZE;
9396 cfTTYFont.nSizeMin = FONT_MIN_SIZE;
9397 cfTTYFont.nSizeMax = FONT_MAX_SIZE;
9398 cfTTYFont.lCustData = 0 ;
9399 cfTTYFont.lpfnHook = NULL ;
9400 cfTTYFont.lpTemplateName = NULL ;
9401 cfTTYFont.hInstance = GET_HINST (hWnd);
9404 if (ChooseFont (&cfTTYFont)) {
9405 ExtractFontInfo(&newFont,
9406 gPrintFontName, sizeof(gPrintFontName)/sizeof(TCHAR),
9407 &gPrintFontSize,
9408 gPrintFontStyle, sizeof(gPrintFontStyle)/sizeof(TCHAR),
9409 ppi,
9410 gPrintFontCharSet, sizeof(gPrintFontCharSet)/sizeof(TCHAR));
9411 DidResize (gpTTYInfo);
9413 else
9414 /* So I can see with the debugger. */
9415 drc = CommDlgExtendedError();
9419 void
9420 ExtractFontInfo(LOGFONT *pFont, LPTSTR fontName, size_t nfontName,
9421 int *fontSize, LPTSTR fontStyle, size_t nfontStyle,
9422 int ppi, LPTSTR fontCharSet, size_t nfontCharSet)
9424 TCHAR *sep[] = {TEXT(""), TEXT(", ")};
9425 int iSep = 0;
9428 _tcsncpy(fontName, pFont->lfFaceName, nfontName);
9429 fontName[nfontName-1] = '\0';
9431 *fontStyle = '\0';
9432 if(pFont->lfWeight >= FW_BOLD) {
9433 _tcsncpy(fontStyle, TEXT("bold"), nfontStyle);
9434 fontStyle[nfontStyle-1] = '\0';
9435 iSep = 1;
9438 if(pFont->lfItalic){
9439 _tcsncat(fontStyle, sep[iSep], nfontStyle - _tcslen(fontStyle));
9440 fontStyle[nfontStyle-1] = '\0';
9442 _tcsncat(fontStyle, TEXT("italic"), nfontStyle - _tcslen(fontStyle));
9443 fontStyle[nfontStyle-1] = '\0';
9446 mswin_charsetid2string(fontCharSet, nfontCharSet, pFont->lfCharSet);
9448 if(fontSize)
9449 *fontSize = MulDiv(-pFont->lfHeight, 72, ppi);
9453 LOCAL void
9454 DidResize (PTTYINFO pTTYInfo)
9456 int i;
9458 for (i = 0; i < RESIZE_CALLBACK_ARRAY_SIZE; ++i) {
9459 if (pTTYInfo->resizer[i] != NULL)
9460 pTTYInfo->resizer[i] (pTTYInfo->actNRow, pTTYInfo->actNColumn);
9463 * Put a null character into the input queue so that the data input
9464 * loops stop and return to their callers who will then re-calculate the
9465 * mouse regions so that the user can click on the new regions of the
9466 * screen and have the right thing happen.
9468 CQAdd (NODATA, 0);
9474 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9476 * Cut, Copy, and Paste operations
9478 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
9482 * Gets called right before the menu is displayed so we can make
9483 * any last minute adjustments.
9485 LOCAL void
9486 UpdateMenu (HWND hWnd)
9488 HMENU hMenu;
9489 PTTYINFO pTTYInfo;
9490 int i;
9491 #ifdef ACCELERATORS
9492 UINT fAccel = EM_NONE;
9493 #endif
9495 pTTYInfo = (PTTYINFO) MyGetWindowLongPtr (hWnd, GWL_PTTYINFO);
9496 if (pTTYInfo == NULL)
9497 return;
9499 hMenu = GetMenu (hWnd);
9500 if (hMenu == NULL)
9501 return;
9503 if (ghPaste) {
9504 /* Currently pasting so disable paste and enable cancel paste. */
9505 EnableMenuItem (hMenu, IDM_EDIT_PASTE, MF_BYCOMMAND|MF_GRAYED);
9506 EnableMenuItem (hMenu, IDM_EDIT_CANCEL_PASTE, MF_BYCOMMAND|MF_ENABLED);
9507 #ifdef ACCELERATORS
9508 fAccel |= (EM_PST | EM_PST_ABORT);
9509 #endif
9511 else {
9513 * Not pasting. If text is available on clipboard and we are
9514 * at a place where we can paste, enable past menu option.
9516 if (IsClipboardFormatAvailable (CF_UNICODETEXT) && gPasteEnabled){
9517 EnableMenuItem (hMenu, IDM_EDIT_PASTE, MF_BYCOMMAND|MF_ENABLED);
9518 #ifdef ACCELERATORS
9519 fAccel |= EM_PST;
9520 #endif
9522 else
9523 EnableMenuItem (hMenu, IDM_EDIT_PASTE, MF_BYCOMMAND|MF_GRAYED);
9525 EnableMenuItem (hMenu, IDM_EDIT_CANCEL_PASTE, MF_BYCOMMAND|MF_GRAYED);
9528 if (SelAvailable ()) {
9529 EnableMenuItem (hMenu, IDM_EDIT_CUT, MF_BYCOMMAND|MF_GRAYED);
9530 EnableMenuItem (hMenu, IDM_EDIT_COPY, MF_BYCOMMAND|MF_ENABLED);
9531 EnableMenuItem (hMenu, IDM_EDIT_COPY_APPEND, MF_BYCOMMAND|MF_ENABLED);
9532 #ifdef ACCELERATORS
9533 fAccel |= (EM_CP | EM_CP_APPEND);
9534 #endif
9536 else {
9537 if (gAllowCut){
9538 EnableMenuItem (hMenu, IDM_EDIT_CUT, MF_BYCOMMAND | MF_ENABLED);
9539 #ifdef ACCELERATORS
9540 fAccel |= EM_CUT;
9541 #endif
9543 else
9544 EnableMenuItem (hMenu, IDM_EDIT_CUT, MF_BYCOMMAND | MF_GRAYED);
9546 if (gAllowCopy) {
9547 EnableMenuItem (hMenu, IDM_EDIT_COPY, MF_BYCOMMAND | MF_ENABLED);
9548 EnableMenuItem (hMenu, IDM_EDIT_COPY_APPEND,
9549 MF_BYCOMMAND | MF_ENABLED);
9550 #ifdef ACCELERATORS
9551 fAccel |= (EM_CP | EM_CP_APPEND);
9552 #endif
9554 else {
9555 EnableMenuItem (hMenu, IDM_EDIT_COPY, MF_BYCOMMAND | MF_GRAYED);
9556 EnableMenuItem (hMenu, IDM_EDIT_COPY_APPEND,
9557 MF_BYCOMMAND | MF_GRAYED);
9562 * Set up Font selection menu
9564 if (gPrintFontName[0] == '\0') {
9565 CheckMenuItem (hMenu, IDM_OPT_FONTSAMEAS, MF_BYCOMMAND | MF_CHECKED);
9566 EnableMenuItem (hMenu, IDM_OPT_SETPRINTFONT,
9567 MF_BYCOMMAND | MF_GRAYED);
9569 else {
9570 CheckMenuItem (hMenu, IDM_OPT_FONTSAMEAS,
9571 MF_BYCOMMAND | MF_UNCHECKED);
9572 EnableMenuItem (hMenu, IDM_OPT_SETPRINTFONT,
9573 MF_BYCOMMAND | MF_ENABLED);
9577 * Setup Caret selection menu
9579 EnableMenuItem (hMenu, IDM_OPT_CARETBLOCK, MF_BYCOMMAND | MF_ENABLED);
9580 EnableMenuItem (hMenu, IDM_OPT_CARETSMALLBLOCK, MF_BYCOMMAND | MF_ENABLED);
9581 EnableMenuItem (hMenu, IDM_OPT_CARETHBAR, MF_BYCOMMAND | MF_ENABLED);
9582 EnableMenuItem (hMenu, IDM_OPT_CARETVBAR, MF_BYCOMMAND | MF_ENABLED);
9583 CheckMenuRadioItem(hMenu, IDM_OPT_CARETBLOCK, IDM_OPT_CARETVBAR,
9584 IDM_OPT_CARETBLOCK + pTTYInfo->cCaretStyle,
9585 MF_BYCOMMAND);
9588 * Check toolbar menu.
9590 EnableMenuItem (hMenu, IDM_OPT_TOOLBAR, MF_BYCOMMAND | MF_ENABLED);
9591 CheckMenuItem (hMenu, IDM_OPT_TOOLBAR, MF_BYCOMMAND |
9592 (pTTYInfo->toolBarSize > 0 ? MF_CHECKED : MF_UNCHECKED));
9593 EnableMenuItem (hMenu, IDM_OPT_TOOLBARPOS, MF_BYCOMMAND | MF_ENABLED);
9594 CheckMenuItem (hMenu, IDM_OPT_TOOLBARPOS, MF_BYCOMMAND |
9595 (pTTYInfo->toolBarTop > 0 ? MF_CHECKED : MF_UNCHECKED));
9600 * Check the dialogs menu.
9602 /* xxx EnableMenuItem (hMenu, IDM_OPT_USEDIALOGS, MF_BYCOMMAND | MF_ENABLED);*/
9603 CheckMenuItem (hMenu, IDM_OPT_USEDIALOGS, MF_BYCOMMAND |
9604 (gfUseDialogs ? MF_CHECKED : MF_UNCHECKED));
9607 * Enable the Erase Credentials menu
9609 EnableMenuItem (hMenu, IDM_OPT_ERASE_CREDENTIALS,
9610 MF_BYCOMMAND | (gEraseCredsCallback ? MF_ENABLED : MF_GRAYED));
9613 * Enable the View in New Window menu item
9615 EnableMenuItem (hMenu, IDM_MI_VIEWINWIND,
9616 MF_BYCOMMAND | (gViewInWindCallback ? MF_ENABLED : MF_GRAYED));
9618 #ifdef ACCELERATORS_OPT
9619 CheckMenuItem (hMenu, IDM_OPT_USEACCEL, MF_BYCOMMAND |
9620 (pTTYInfo->hAccel ? MF_CHECKED : MF_UNCHECKED));
9621 #endif
9624 * Setup the sort menu...
9626 if(gSortCallback){
9627 i = (*gSortCallback)(0, 0);
9629 /* NOTE: this func's args are dependent on definition order
9630 * in resource.h
9632 CheckMenuRadioItem(hMenu, IDM_MI_SORTSUBJECT, IDM_MI_SORTTHREAD,
9633 IDM_MI_SORTSUBJECT + (i & 0x00ff), MF_BYCOMMAND);
9634 CheckMenuItem(hMenu, IDM_MI_SORTREVERSE,
9635 MF_BYCOMMAND|((i & 0x0100) ? MF_CHECKED : MF_UNCHECKED));
9637 else{
9638 CheckMenuRadioItem(hMenu, IDM_MI_SORTSUBJECT, IDM_MI_SORTTHREAD,
9639 IDM_MI_SORTARRIVAL, MF_BYCOMMAND);
9640 CheckMenuItem(hMenu, IDM_MI_SORTREVERSE, MF_BYCOMMAND | MF_UNCHECKED);
9644 * Setup the flag menu...
9646 if(gFlagCallback){
9647 int flags = (*gFlagCallback)(0, 0);
9648 for(i = IDM_MI_FLAGIMPORTANT; i <= IDM_MI_FLAGDELETED; i++)
9649 CheckMenuItem(hMenu, i, MF_BYCOMMAND
9650 | (((flags >> (i - IDM_MI_FLAGIMPORTANT)) & 0x0001)
9651 ? MF_CHECKED : MF_UNCHECKED));
9657 if(gHdrCallback){
9658 i = (*gHdrCallback)(0, 0);
9659 CheckMenuItem(hMenu, IDM_MI_HDRMODE,
9660 MF_BYCOMMAND|((i != 0) ? MF_CHECKED : MF_UNCHECKED));
9666 if(gZoomCallback){
9667 i = (*gZoomCallback)(0, 0);
9668 CheckMenuItem(hMenu, IDM_MI_ZOOM,
9669 MF_BYCOMMAND | (i ? MF_CHECKED : MF_UNCHECKED));
9672 * Set up command menu.
9674 if (!pTTYInfo->menuItemsCurrent) {
9675 for (i = 0; i < KS_COUNT; ++i)
9676 if(i + KS_RANGESTART != KS_GENERALHELP)
9677 EnableMenuItem (hMenu, i + KS_RANGESTART,
9678 MF_BYCOMMAND | ((pTTYInfo->menuItems[i].miActive)
9679 ? MF_ENABLED : MF_GRAYED));
9682 * Special command-specific knowledge here
9684 for(i = IDM_MI_SORTSUBJECT; i <= IDM_MI_SORTREVERSE; i++)
9685 EnableMenuItem (hMenu, i,
9686 MF_BYCOMMAND
9687 | ((pTTYInfo->menuItems[KS_SORT-KS_RANGESTART].miActive)
9688 ? MF_ENABLED : MF_GRAYED));
9690 for(i = IDM_MI_FLAGIMPORTANT; i <= IDM_MI_FLAGDELETED; i++)
9691 EnableMenuItem (hMenu, i,
9692 MF_BYCOMMAND
9693 | ((pTTYInfo->menuItems[KS_FLAG - KS_RANGESTART].miActive)
9694 ? MF_ENABLED : MF_GRAYED));
9699 * deal with any callback state dependent enabling
9701 if(pTTYInfo->menuItems[IDM_MI_APPLY - KS_RANGESTART].miActive)
9702 EnableMenuItem(hMenu, IDM_MI_APPLY,
9703 MF_BYCOMMAND | ((gSelectedCallback
9704 && (*gSelectedCallback)(0, 0))
9705 ? MF_ENABLED : MF_GRAYED));
9707 if(pTTYInfo->menuItems[IDM_MI_ZOOM - KS_RANGESTART].miActive)
9708 EnableMenuItem(hMenu, IDM_MI_ZOOM,
9709 MF_BYCOMMAND | ((gSelectedCallback
9710 && (*gSelectedCallback)(0, 0))
9711 ? MF_ENABLED : MF_GRAYED));
9713 #ifdef ACCELERATORS
9714 if(pTTYInfo->menuItems[KS_WHEREIS - KS_RANGESTART].miActive)
9715 fAccel |= EM_FIND;
9717 AccelManage (hWnd, fAccel);
9718 #endif
9720 pTTYInfo->menuItemsCurrent = TRUE;
9726 * Cut region to kill buffer.
9728 LOCAL void
9729 EditCut (void)
9731 HANDLE hCB;
9733 if(gCopyCutFunction == (getc_t)kremove){
9734 hCB = GlobalAlloc (GMEM_MOVEABLE, 0);
9735 if (hCB != NULL) {
9736 kdelete(); /* Clear current kill buffer. */
9737 killregion (1, 0); /* Kill Region (and copy to clipboard). */
9738 update (); /* And update the screen */
9746 * This function copies the kill buffer to the window's clip board.
9747 * (actually, it can copy any buffer for which a copyfunc is provided).
9748 * Called from ldelete().
9750 void
9751 mswin_killbuftoclip (getc_t copyfunc)
9753 HANDLE hCB;
9754 getc_t oldfunc;
9756 /* Save old copy function. */
9757 oldfunc = gCopyCutFunction;
9758 gCopyCutFunction = copyfunc;
9760 /* Allocate clip buffer. */
9761 hCB = GlobalAlloc (GMEM_MOVEABLE, 0);
9762 if (hCB != NULL) {
9763 EditDoCopyData (hCB, 0);
9766 /* restore copy function. */
9767 gCopyCutFunction = oldfunc;
9773 * Copy region to kill buffer.
9775 LOCAL void
9776 EditCopy (void)
9778 HANDLE hCB;
9780 if (SelAvailable()) {
9781 /* This is a copy of the windows selection. */
9782 hCB = GlobalAlloc (GMEM_MOVEABLE, 0);
9783 if (hCB != NULL)
9784 SelDoCopy (hCB, 0);
9786 else {
9788 /* Otherwise, it's a Pico/Pine copy. */
9789 if(gCopyCutFunction == (getc_t)kremove){
9790 kdelete(); /* Clear current kill buffer. */
9791 copyregion (1, 0);
9794 hCB = GlobalAlloc (GMEM_MOVEABLE, 0);
9795 if (hCB != NULL)
9796 EditDoCopyData (hCB, 0);
9803 * Called in response to "Copy Append" menu command, when there is an active
9804 * Windows selection on the screen.
9806 LOCAL void
9807 EditCopyAppend (void)
9809 HANDLE hCB;
9810 HANDLE hMyCopy;
9811 TCHAR *pCB;
9812 TCHAR *pMyCopy;
9813 size_t cbSize = 0;
9815 /* Attempt to copy clipboard data to my own handle. */
9816 hMyCopy = NULL;
9817 if (OpenClipboard (ghTTYWnd)) { /* And can get clipboard. */
9818 hCB = GetClipboardData (CF_UNICODETEXT);
9819 if (hCB != NULL) { /* And can get data. */
9820 pCB = GlobalLock (hCB);
9821 cbSize = _tcslen (pCB); /* It's a null term string. */
9822 hMyCopy = GlobalAlloc (GMEM_MOVEABLE, (cbSize+1)*sizeof(*pCB));
9823 if (hMyCopy != NULL) { /* And can get memory. */
9824 pMyCopy = GlobalLock (hMyCopy);
9825 if (pMyCopy != NULL) {
9826 memcpy (pMyCopy, pCB, cbSize*sizeof(*pCB)); /* Copy data. */
9827 GlobalUnlock (hMyCopy);
9829 else {
9830 GlobalFree (hMyCopy);
9831 hMyCopy = NULL;
9834 GlobalUnlock (hCB);
9835 } /* GetClipboardData. */
9836 CloseClipboard ();
9837 } /* OpenClipboard. */
9841 /* Now, if I got a copy, append current selection to that
9842 * and stuff it back into the clipboard. */
9843 if (hMyCopy != NULL) {
9844 if (SelAvailable ()) {
9845 SelDoCopy (hMyCopy, (DWORD)cbSize);
9847 else {
9848 if(gCopyCutFunction == (getc_t)kremove) {
9849 kdelete(); /* Clear current kill buffer. */
9850 copyregion (1, 0);
9852 EditDoCopyData (hMyCopy, (DWORD)cbSize);
9859 * Copy data from the kill buffer to the clipboard. Handle LF->CRLF
9860 * translation if necessary.
9862 LOCAL void
9863 EditDoCopyData (HANDLE hCB, DWORD lenCB)
9865 TCHAR *pCB;
9866 TCHAR *p;
9867 long c; /* would be TCHAR but needs -1 retval from callback */
9868 TCHAR lastc = (TCHAR)'\0';
9869 DWORD cbSize; /* Allocated size of hCB. */
9870 DWORD i;
9871 #define BUF_INC 4096
9873 if (gCopyCutFunction != NULL) { /* If there really is data. */
9874 if (OpenClipboard (ghTTYWnd)) { /* ...and we get the CB. */
9875 if (EmptyClipboard ()) { /* ...and clear previous CB.*/
9876 pCB = GlobalLock (hCB);
9877 p = pCB + lenCB;
9878 cbSize = lenCB;
9879 /* Copy it. (BUG: change int arg) */
9880 for(i = 0L; (c = (*gCopyCutFunction)((int)i)) != -1; i++){
9882 * Rather than fix every function that might
9883 * get called for character retrieval to supply
9884 * CRLF EOLs, let's just fix it here. The downside
9885 * is a much slower copy for large buffers, but
9886 * hey, what do they want?
9888 if(lenCB + 2L >= cbSize){
9889 cbSize += BUF_INC;
9890 GlobalUnlock (hCB);
9891 hCB = GlobalReAlloc (hCB, cbSize*sizeof(TCHAR), GMEM_MOVEABLE);
9892 if (hCB == NULL)
9893 return;
9895 pCB = GlobalLock (hCB);
9896 p = pCB + lenCB;
9899 if(c == (TCHAR)ASCII_LF && lastc != (TCHAR)ASCII_CR) {
9900 *p++ = (TCHAR)ASCII_CR; /* insert CR before LF */
9901 lenCB++;
9904 *p++ = lastc = (TCHAR)c;
9905 lenCB++;
9908 /* Only if we got some data. */
9909 if (lenCB > 0) {
9910 *p = (TCHAR)'\0';
9911 GlobalUnlock (hCB);
9913 if (SetClipboardData (CF_UNICODETEXT, hCB) == NULL)
9914 /* Failed! Free the data. */
9915 GlobalFree (hCB);
9917 else {
9918 /* There was no data copied. */
9919 GlobalUnlock (hCB);
9920 GlobalFree (hCB);
9923 CloseClipboard ();
9930 * Get a handle to the current (text) clipboard and make my own copy.
9931 * Keep my copy locked because I'll be using it to read bytes from.
9933 LOCAL void
9934 EditPaste (void)
9936 HANDLE hCB;
9937 LPTSTR pCB;
9938 LPTSTR pPaste;
9939 size_t cbSize;
9941 if (ghPaste == NULL) { /* If we are not already pasting. */
9942 if (OpenClipboard (ghTTYWnd)) { /* And can get clipboard. */
9943 hCB = GetClipboardData (CF_UNICODETEXT);
9944 if (hCB != NULL) { /* And can get data. */
9945 pCB = GlobalLock (hCB);
9946 cbSize = _tcslen (pCB); /* It's a null term string. */
9947 ghPaste = GlobalAlloc (GMEM_MOVEABLE, (cbSize+1)*sizeof(TCHAR));
9948 if (ghPaste != NULL) { /* And can get memory. */
9949 gpPasteNext = GlobalLock (ghPaste);
9950 memcpy (gpPasteNext, pCB, (cbSize+1)*sizeof(TCHAR)); /* Copy data. */
9951 /* Keep ghPaste locked. */
9954 * If we're paste is enabled but limited to the first
9955 * line of the clipboard, prune the paste buffer...
9957 if(gPasteEnabled == MSWIN_PASTE_LINE
9958 && (pPaste = _tcschr(gpPasteNext, (TCHAR)ASCII_CR))){
9959 *pPaste = (TCHAR)'\0';
9960 cbSize = _tcslen(gpPasteNext);
9964 * If there is a selection (gCopyCutFunction != NULL)
9965 * then delete it so that it will be replaced by
9966 * the pasted text.
9968 if (gCopyCutFunction != NULL)
9969 deleteregion (1, 0);
9971 gPasteBytesRemain = cbSize;
9972 gPasteWasCR = FALSE;
9973 #ifdef FDEBUG
9974 if (mswin_debug > 8)
9975 fprintf (mswin_debugfile, "EditPaste:: Paste %d bytes\n",
9976 gPasteBytesRemain);
9977 #endif
9979 GlobalUnlock (hCB);
9981 CloseClipboard ();
9992 * Cancel an active paste operation.
9994 LOCAL void
9995 EditCancelPaste (void)
9997 if (ghPaste != NULL) { /* Must be pasting. */
9998 GlobalUnlock (ghPaste); /* Then Unlock... */
9999 GlobalFree (ghPaste); /* ...and free the paste buffer. */
10000 ghPaste = NULL; /* Indicates no paste data. */
10001 gpPasteNext = NULL; /* Just being tidy. */
10002 gPasteBytesRemain = 0; /* ditto. */
10003 #ifdef FDEBUG
10004 if (mswin_debug > 8)
10005 fprintf (mswin_debugfile, "EditCancelPaste:: Free Paste Data\n");
10006 #endif
10012 * Get the next byte from the paste buffer. If all bytes have been
10013 * retrieved, free the paste buffer.
10014 * Map all CRLF sequence to a single CR.
10016 LOCAL UCS
10017 EditPasteGet (void)
10019 UCS b = NODATA;
10021 if (ghPaste != NULL) { /* ghPaste tells if we are pasting. */
10022 if (gPasteBytesRemain > 0) { /* Just in case... */
10023 /* Get one byte and move pointer. */
10024 b = (TCHAR) *gpPasteNext++;
10025 --gPasteBytesRemain; /* one less. */
10026 if (gPasteWasCR && b == (TCHAR)ASCII_LF) {
10027 if (gPasteBytesRemain) {
10028 /* Skip of LF. */
10029 b = (TCHAR) *gpPasteNext++;
10030 --gPasteBytesRemain;
10032 else
10033 b = NODATA; /* Ignore last LF. */
10035 gPasteWasCR = (b == (TCHAR)ASCII_CR);
10036 #ifdef FDEBUG
10037 if (mswin_debug > 8)
10038 fprintf (mswin_debugfile, "EditPasteGet:: char %c, gPasteWasCR %d, gPasteBytesRemain %d\n",
10039 b, gPasteWasCR, gPasteBytesRemain);
10040 #endif
10042 if (gPasteBytesRemain <= 0) { /* All Done? */
10043 GlobalUnlock (ghPaste); /* Then Unlock... */
10044 GlobalFree (ghPaste); /* ...and free the paste buffer. */
10045 ghPaste = NULL; /* Indicates no paste data. */
10046 gpPasteNext = NULL; /* Just being tidy. */
10047 gPasteBytesRemain = 0; /* ditto. */
10048 #ifdef FDEBUG
10049 if (mswin_debug > 8)
10050 fprintf (mswin_debugfile, "EditPasteGet:: Free Paste Data\n");
10051 #endif
10055 if(b < ' ') {
10056 b += '@';
10057 b |= CTRL;
10060 return (b);
10065 * Return true if Paste data is available. If gpPaste != NULL then there
10066 * is paste data.
10068 LOCAL BOOL
10069 EditPasteAvailable (void)
10071 return (ghPaste != NULL);
10077 * Select everything in the buffer
10079 LOCAL void
10080 EditSelectAll()
10082 if(ComposerEditing){
10084 else{
10085 gotobob(0, 1);
10086 setmark(0, 1);
10087 gotoeob(0, 1);
10088 update (); /* And update the screen */
10093 LOCAL void
10094 SortHandler(int order, int reverse)
10096 int old = (*gSortCallback)(0, 0);
10098 if(order < 0){
10099 old ^= 0x0100; /* flip reverse bit */
10100 (*gSortCallback)(1, old);
10102 else
10103 (*gSortCallback)(1, order | (old & 0x0100));
10107 LOCAL void
10108 FlagHandler(int index, int args)
10110 if(gFlagCallback)
10111 (void) (*gFlagCallback)(index + 1, 0L);
10115 LOCAL void
10116 MSWHelpShow (cbstr_t fpHelpCallback)
10118 if (fpHelpCallback != NULL){
10119 char title[256], *help;
10121 if(help = (*fpHelpCallback) (title))
10122 mswin_displaytext (title, help, strlen(help), NULL, NULL, 0);
10130 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10132 * Adjust the timer frequency as needed.
10134 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10136 LOCAL void
10137 MyTimerSet (void)
10139 UINT period;
10140 /* Decide on period to use. */
10141 if (gAllowMouseTrack)
10142 period = MY_TIMER_EXCEEDINGLY_SHORT_PERIOD;
10143 else
10144 period = my_timer_period;
10146 if (period != gTimerCurrentPeriod) {
10147 if (SetTimer (ghTTYWnd, MY_TIMER_ID, period, NULL) == 0)
10148 MessageBox (ghTTYWnd, TIMER_FAIL_MESSAGE, NULL,
10149 MB_OK | MB_ICONINFORMATION);
10150 else
10151 gTimerCurrentPeriod = period;
10159 void
10160 mswin_setperiodiccallback (cbvoid_t periodiccb, long period)
10162 if (periodiccb != NULL && period > 0) {
10163 gPeriodicCallback = periodiccb;
10164 gPeriodicCBTime = period;
10165 gPeriodicCBTimeout = GetTickCount () / 1000 + gPeriodicCBTime;
10167 else {
10168 gPeriodicCallback = NULL;
10173 * Structure for variables used by mswin_exec_and_wait which need to be
10174 * freed in multiple places.
10176 typedef struct MSWIN_EXEC_DATA {
10177 HANDLE infd;
10178 HANDLE outfd;
10179 LPTSTR lptstr_whatsit;
10180 LPTSTR lptstr_command;
10181 LPTSTR lptstr_infile;
10182 LPTSTR lptstr_outfile;
10183 MSWIN_TEXTWINDOW *mswin_tw;
10184 } MSWIN_EXEC_DATA;
10186 LOCAL void
10187 mswin_exec_data_init(MSWIN_EXEC_DATA *exec_data)
10189 memset(exec_data, 0, sizeof(MSWIN_EXEC_DATA));
10190 exec_data->infd = INVALID_HANDLE_VALUE;
10191 exec_data->outfd = INVALID_HANDLE_VALUE;
10194 LOCAL void
10195 mswin_exec_data_free(MSWIN_EXEC_DATA *exec_data, BOOL delete_outfile)
10197 if(exec_data->infd != INVALID_HANDLE_VALUE)
10198 CloseHandle(exec_data->infd);
10200 if(exec_data->outfd != INVALID_HANDLE_VALUE) {
10201 CloseHandle(exec_data->outfd);
10202 if(delete_outfile)
10203 _tunlink(exec_data->lptstr_outfile);
10206 if(exec_data->lptstr_infile)
10207 fs_give((void **) &exec_data->lptstr_infile);
10208 if(exec_data->lptstr_outfile)
10209 fs_give((void **) &exec_data->lptstr_outfile);
10210 if(exec_data->lptstr_whatsit)
10211 fs_give((void **) &exec_data->lptstr_whatsit);
10212 if(exec_data->lptstr_command)
10213 fs_give((void **) &exec_data->lptstr_command);
10215 if(exec_data->mswin_tw) {
10217 * Set the out_file is zero. We don't need mswin_tw
10218 * to save the file anymore since we're bailing.
10220 exec_data->mswin_tw->out_file = NULL;
10223 * If the window is still open, then set the id to 0 so
10224 * mswin_tw_close_callback() will free the memory whenever
10225 * the window closes. Otherwise free it now.
10227 if(exec_data->mswin_tw->hwnd)
10228 exec_data->mswin_tw->id = 0;
10229 else
10230 MemFree(exec_data->mswin_tw);
10235 * Execute command and wait for the child to exit
10237 * whatsit - description of reason exec being called
10238 * command - command to run
10239 * infile - name of file to pass as stdin
10240 * outfile - name of file to pass as stdout
10241 * exit_val - where to store return value of the process
10242 * mswe_flags -
10243 * MSWIN_EAW_CAPT_STDERR - capture stderr along with stdout
10244 * MSWIN_EAW_CTRL_C_CANCELS - if user presses ctrl-c, detach child
10245 * Returns: 0, successfully completed program
10246 * -1, errors occurred
10247 * -2, user chose to stop waiting for program before it finished
10250 mswin_exec_and_wait (char *utf8_whatsit, char *utf8_command,
10251 char *utf8_infile, char *utf8_outfile,
10252 int *exit_val, unsigned mswe_flags)
10254 MEvent mouse;
10255 BOOL brc;
10256 int rc;
10257 TCHAR waitingFor[256];
10258 PROCESS_INFORMATION proc_info;
10259 DWORD exit_code;
10260 MSWIN_EXEC_DATA exec_data;
10261 #ifdef ALTED_DOT
10262 BOOL b_use_mswin_tw;
10263 #endif
10265 mswin_exec_data_init(&exec_data);
10267 memset(&proc_info, 0, sizeof(proc_info));
10269 mswin_flush ();
10271 exec_data.lptstr_infile = utf8_infile ? utf8_to_lptstr(utf8_infile) : NULL;
10272 exec_data.lptstr_outfile = utf8_outfile ? utf8_to_lptstr(utf8_outfile) : NULL;
10274 exec_data.lptstr_command = utf8_to_lptstr(utf8_command);
10275 exec_data.lptstr_whatsit = utf8_to_lptstr(utf8_whatsit);
10277 #ifdef ALTED_DOT
10278 /* If the command is '.', then use mswin_tw to open the file. */
10279 b_use_mswin_tw = utf8_command &&
10280 utf8_command[0] == '.' && utf8_command[1] == '\0';
10282 if(b_use_mswin_tw) {
10284 proc_info.hThread = INVALID_HANDLE_VALUE;
10285 proc_info.hProcess = INVALID_HANDLE_VALUE;
10287 exec_data.mswin_tw = mswin_tw_displaytext_lptstr(
10288 exec_data.lptstr_whatsit, exec_data.lptstr_infile, 4, NULL,
10289 exec_data.mswin_tw, MSWIN_DT_FILLFROMFILE);
10291 if(exec_data.mswin_tw) {
10292 mswin_set_readonly(exec_data.mswin_tw, FALSE);
10294 /* Tell mswin_tw to write the edit contents to this file. */
10295 exec_data.mswin_tw->out_file = exec_data.lptstr_outfile;
10297 /* Make sure mswin_tw isn't freed behind our back. */
10298 exec_data.mswin_tw->id = (UINT)-1;
10299 brc = TRUE;
10301 else {
10302 brc = FALSE;
10305 else
10306 #endif /* ALTED_DOT */
10308 SECURITY_ATTRIBUTES atts;
10309 STARTUPINFO start_info;
10311 memset(&atts, 0, sizeof(atts));
10312 memset(&start_info, 0, sizeof(start_info));
10314 /* set file attributes of temp files*/
10315 atts.nLength = sizeof(SECURITY_ATTRIBUTES);
10316 atts.bInheritHandle = TRUE;
10317 atts.lpSecurityDescriptor = NULL;
10319 /* open files if asked for */
10320 if(utf8_infile
10321 && ((exec_data.infd = CreateFile(exec_data.lptstr_infile,
10322 GENERIC_READ, 0, &atts,
10323 OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL))
10324 == INVALID_HANDLE_VALUE)){
10326 mswin_exec_data_free(&exec_data, TRUE);
10327 return(-1);
10330 if(utf8_outfile
10331 && ((exec_data.outfd = CreateFile(exec_data.lptstr_outfile,
10332 GENERIC_WRITE, 0, &atts,
10333 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL))
10334 == INVALID_HANDLE_VALUE)){
10336 mswin_exec_data_free(&exec_data, TRUE);
10337 return(-1);
10340 start_info.dwFlags = STARTF_FORCEONFEEDBACK | STARTF_USESHOWWINDOW;
10341 start_info.wShowWindow = (utf8_infile || utf8_outfile) ? SW_SHOWMINNOACTIVE : SW_SHOWNA;
10343 /* set up i/o redirection */
10344 if(utf8_infile)
10345 start_info.hStdInput = exec_data.infd;
10346 if(utf8_outfile)
10347 start_info.hStdOutput = exec_data.outfd;
10348 if(utf8_outfile && (mswe_flags & MSWIN_EAW_CAPT_STDERR))
10349 start_info.hStdError = exec_data.outfd;
10350 if(utf8_infile || utf8_outfile)
10351 start_info.dwFlags |= STARTF_USESTDHANDLES;
10353 brc = CreateProcess(NULL, exec_data.lptstr_command, NULL, NULL,
10354 (utf8_infile || utf8_outfile) ? TRUE : FALSE,
10355 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
10356 NULL, NULL, &start_info, &proc_info);
10359 if(brc) {
10360 _sntprintf(waitingFor, sizeof(waitingFor)/sizeof(TCHAR),
10361 TEXT("%s is currently waiting for the %s (%s) to complete. Click \"Cancel\" to stop waiting, or \"OK\" to continue waiting."),
10362 gszAppName, exec_data.lptstr_whatsit, exec_data.lptstr_command);
10364 if(proc_info.hThread != INVALID_HANDLE_VALUE) {
10365 /* Don't need the thread handle, close it now. */
10366 CloseHandle (proc_info.hThread);
10370 * Go into holding pattern until the other application terminates
10371 * or we are told to stop waiting.
10373 while(TRUE){
10375 #ifdef ALTED_DOT
10376 if(b_use_mswin_tw)
10378 if(!exec_data.mswin_tw)
10379 break;
10381 exit_code = exec_data.mswin_tw->hwnd && exec_data.mswin_tw->out_file ?
10382 STILL_ACTIVE : 0;
10384 else
10385 #endif /* ALTED_DOT */
10387 if(GetExitCodeProcess(proc_info.hProcess, &exit_code) == FALSE)
10388 break;
10391 if(exit_code == STILL_ACTIVE){
10392 rc = mswin_getc();
10393 brc = mswin_getmouseevent (&mouse);
10395 if (rc != NODATA ||
10396 (brc && mouse.event == M_EVENT_DOWN)) {
10397 if(mswe_flags & MSWIN_EAW_CTRL_C_CANCELS){
10398 if(rc == (CTRL|'C'))
10399 rc = IDCANCEL;
10401 else{
10402 rc = MessageBox (ghTTYWnd, waitingFor, exec_data.lptstr_whatsit,
10403 MB_ICONSTOP | MB_OKCANCEL);
10405 SelClear ();
10406 if (rc == IDCANCEL){
10407 /* terminate message to child ? */
10408 mswin_exec_data_free(&exec_data, TRUE);
10409 return (-2);
10413 else{
10414 if(proc_info.hProcess != INVALID_HANDLE_VALUE) {
10415 /* do something about child's exit status */
10416 CloseHandle (proc_info.hProcess);
10418 if(exit_val)
10419 *exit_val = exit_code;
10420 break;
10424 if (gpTTYInfo->fMinimized)
10425 ShowWindow (ghTTYWnd, SW_SHOWNORMAL);
10428 * If we're using a mswin_tw and we're not capturing the output, we
10429 * just bailed immediately. If that's the case, don't bring the main
10430 * window up over the top of the textwindow we just brought up.
10432 #ifdef ALTED_DOT
10433 if(!b_use_mswin_tw || !exec_data.mswin_tw || exec_data.mswin_tw->out_file)
10434 #endif /* ALTED_DOT */
10435 BringWindowToTop (ghTTYWnd);
10437 mswin_exec_data_free(&exec_data, FALSE);
10438 return (0);
10440 else{
10441 mswin_exec_data_free(&exec_data, TRUE);
10442 return((rc = (int) GetLastError()) ? rc : -1); /* hack */
10445 /* NOTREACHED */
10446 return(-1);
10451 mswin_shell_exec(char *command_utf8, HINSTANCE *pChildProc)
10453 int quoted = 0;
10454 SHELLEXECUTEINFO shell_info;
10455 LPTSTR command_lpt, free_command_lpt;
10456 LPTSTR p, q, parm = NULL;
10457 TCHAR buf[1024];
10459 if(!command_utf8)
10460 return(-1);
10462 free_command_lpt = command_lpt = utf8_to_lptstr(command_utf8);
10463 if(!command_lpt)
10464 return(-1);
10466 mswin_flush ();
10469 * Pick first arg apart by whitespace until what's to the left
10470 * is no longer a valid path/file. Everything else is then an
10471 * command line arg...
10473 if(*(p = command_lpt) == '\"'){
10474 p = ++command_lpt; /* don't include quote */
10475 quoted++;
10478 q = buf;
10479 while(1)
10480 if(!quoted && _istspace(*p)){
10481 char *buf_utf8;
10483 *q = '\0';
10484 buf_utf8 = lptstr_to_utf8(buf);
10485 if(*buf == '*' || (buf_utf8 && fexist(buf_utf8, "x", (off_t *) NULL) == FIOSUC)){
10486 parm = p;
10487 if(buf_utf8)
10488 fs_give((void **) &buf_utf8);
10490 break;
10493 if(buf_utf8)
10494 fs_give((void **) &buf_utf8);
10496 else if(quoted && *p == '\"'){
10497 parm = p;
10498 break;
10500 else if(!(*q++ = *p++)){
10501 parm = p - 1;
10502 break;
10505 if(*command_lpt && parm){
10507 *parm++ = '\0';
10508 while(*parm && _istspace((unsigned char) *parm));
10512 * HACK -- since star is very unlikely to actually appear
10513 * in a command name that's launched via a shell command line,
10514 * a leading one indicates special handling.
10516 if(command_lpt[0] == '*'){
10517 if(!_tcsncmp(command_lpt + 1, TEXT("Shell*"), 8)){
10518 /* Leave it to ShellExecute magic to "open" the thing */
10519 command_lpt = parm;
10520 parm = NULL;
10524 else{
10525 if(free_command_lpt)
10526 fs_give((void **) &free_command_lpt);
10528 return(-1);
10531 memset(&shell_info, 0, sizeof(SHELLEXECUTEINFO));
10532 shell_info.cbSize = sizeof(SHELLEXECUTEINFO);
10533 shell_info.fMask = SEE_MASK_DOENVSUBST
10534 | SEE_MASK_NOCLOSEPROCESS
10535 | SEE_MASK_FLAG_DDEWAIT;
10536 shell_info.hwnd = ghTTYWnd;
10537 shell_info.lpFile = command_lpt;
10538 shell_info.lpParameters = parm;
10539 shell_info.lpDirectory = NULL; /* default is current directory */
10540 shell_info.nShow = SW_SHOWNORMAL;
10542 ShellExecuteEx(&shell_info);
10544 if((int)(LONG_PTR)shell_info.hInstApp > 32){
10545 if(pChildProc)
10546 *pChildProc = shell_info.hProcess;
10548 if(free_command_lpt)
10549 fs_give((void **) &free_command_lpt);
10551 return(0); /* success! */
10554 if(free_command_lpt)
10555 fs_give((void **) &free_command_lpt);
10557 return(-1);
10562 * Generate an error message for a failed windows exec or loadlibrary.
10564 void
10565 mswin_exec_err_msg(char *what, int status, char *buf, size_t buflen)
10567 switch(status){
10568 case 2:
10569 case 3:
10570 snprintf(buf, buflen, "%s not found.", what);
10571 break;
10573 case 8:
10574 snprintf(buf, buflen, "Not enough memory to run %s.", what);
10575 break;
10577 default:
10578 snprintf(buf, buflen, "Error %d starting %s.", status, what);
10579 break;
10585 mswin_set_quit_confirm (int confirm)
10587 gConfirmExit = (confirm != 0);
10588 return (confirm);
10593 * Called when Windows is in shutting down. Before actually shutting down
10594 * Windows goes around to all the applications and asks if it is OK with
10595 * them to shut down (WM_QUERYENDSESSION).
10596 * If gConfirmExit is set, ask the user if they want to exit.
10597 * Returning zero will stop the shutdown, non-zero allows it to proceed.
10599 LOCAL LRESULT
10600 ConfirmExit (void)
10602 TCHAR msg[256];
10603 int rc;
10605 if(gConfirmExit){
10606 _sntprintf(msg, sizeof(msg)/sizeof(TCHAR),
10607 TEXT("Exiting may cause you to lose work in %s, Exit?"),
10608 gszAppName);
10609 rc = MessageBox (ghTTYWnd, msg, gszAppName, MB_ICONSTOP | MB_OKCANCEL);
10610 if(rc == IDCANCEL)
10611 return(0);
10614 return(1);
10618 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10620 * Registry access functions
10622 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10625 * Useful def's
10627 #define MSWR_KEY_MAX 128
10628 #define MSWR_VAL_MAX 128
10629 #define MSWR_CLASS_MAX 128
10630 #define MSWR_DATA_MAX 1024
10633 #define MSWR_ROOT TEXT("Software\\University of Washington\\Alpine\\1.0")
10634 #define MSWR_CAPABILITIES TEXT("Software\\University of Washington\\Alpine\\1.0\\Capabilities")
10635 #define MSWR_APPNAME TEXT("Alpine")
10636 #define MSWR_DLLPATH TEXT("DLLPath")
10637 #define MSWR_DLLNAME TEXT("pmapi32.dll")
10638 #define MSWRDBUF 1152
10641 struct mswin_reg_key {
10642 HKEY rhk; /* root key (HKEY_LOCAL_MACHINE, ...) */
10643 LPTSTR *knames; /* NULL terminated list of keys */
10646 LPTSTR mswin_pine_hklm_regs[] = {
10647 MSWR_ROOT,
10648 TEXT("Software\\Clients\\Mail\\Alpine"),
10649 TEXT("Software\\Clients\\News\\Alpine"),
10650 TEXT("Software\\Classes\\Alpine.Url.Mailto"),
10651 TEXT("Software\\Classes\\Alpine.Url.News"),
10652 TEXT("Software\\Classes\\Alpine.Url.Nntp"),
10653 TEXT("Software\\Classes\\Alpine.Url.Imap"),
10654 NULL
10657 LPTSTR mswin_pine_hkcu_regs[] = {
10658 MSWR_ROOT,
10659 NULL
10662 static struct mswin_reg_key mswin_pine_regs[] = {
10663 {HKEY_LOCAL_MACHINE, mswin_pine_hklm_regs},
10664 {HKEY_CURRENT_USER, mswin_pine_hkcu_regs},
10665 {NULL, NULL}
10670 * data: uninitialized buffer, could be null
10673 mswin_reg(int op, int tree, char *data_utf8, size_t size)
10675 LPTSTR data_lptstr = NULL;
10676 int rv;
10678 if(data_utf8){
10679 if(size == 0){
10680 /* size is zero when op & MSWR_OP_SET */
10681 data_lptstr = utf8_to_lptstr(data_utf8);
10683 else {
10684 data_lptstr = (LPTSTR)MemAlloc(size * sizeof(TCHAR));
10685 data_lptstr[0] = '\0';
10689 rv = mswin_reg_lptstr(op, tree, data_lptstr, size);
10691 if(data_utf8 && data_lptstr){
10692 char *t_utf8str;
10693 if(size){
10694 t_utf8str = lptstr_to_utf8(data_lptstr);
10695 strncpy(data_utf8, t_utf8str, size);
10696 data_utf8[size-1] = '\0';
10697 MemFree((void *)t_utf8str);
10699 MemFree((void *)data_lptstr);
10701 return(rv);
10705 mswin_reg_lptstr(int op, int tree, LPTSTR data_lptstr, size_t size)
10707 if(op & MSWR_OP_SET){
10708 switch(tree){
10709 case MSWR_PINE_RC :
10710 MSWRAlpineSet(HKEY_CURRENT_USER, NULL,
10711 TEXT("PineRC"), op & MSWR_OP_FORCE, data_lptstr);
10712 break;
10714 case MSWR_PINE_CONF :
10715 MSWRAlpineSet(HKEY_CURRENT_USER, NULL,
10716 TEXT("PineConf"), op & MSWR_OP_FORCE, data_lptstr);
10717 break;
10719 case MSWR_PINE_AUX :
10720 MSWRAlpineSet(HKEY_CURRENT_USER, NULL,
10721 TEXT("PineAux"), op & MSWR_OP_FORCE, data_lptstr);
10722 break;
10724 case MSWR_PINE_DIR :
10725 MSWRAlpineSet(HKEY_LOCAL_MACHINE, NULL,
10726 TEXT("Pinedir"), op & MSWR_OP_FORCE, data_lptstr);
10727 MSWRAlpineSetHandlers(op & MSWR_OP_FORCE, data_lptstr);
10728 break;
10730 case MSWR_PINE_EXE :
10731 MSWRAlpineSet(HKEY_LOCAL_MACHINE, NULL,
10732 TEXT("PineEXE"), op & MSWR_OP_FORCE, data_lptstr);
10733 break;
10735 case MSWR_PINE_POS :
10736 MSWRAlpineSet(HKEY_CURRENT_USER, NULL,
10737 TEXT("PinePos"), op & MSWR_OP_FORCE, data_lptstr);
10738 break;
10740 default :
10741 break;
10744 else if(op & MSWR_OP_GET){
10745 switch(tree){
10746 case MSWR_PINE_RC :
10747 return(MSWRAlpineGet(HKEY_CURRENT_USER, NULL,
10748 TEXT("PineRC"), data_lptstr, size));
10749 case MSWR_PINE_CONF :
10750 return(MSWRAlpineGet(HKEY_CURRENT_USER, NULL,
10751 TEXT("PineConf"), data_lptstr, size));
10752 case MSWR_PINE_AUX :
10753 return(MSWRAlpineGet(HKEY_CURRENT_USER, NULL,
10754 TEXT("PineAux"), data_lptstr, size));
10755 case MSWR_PINE_DIR :
10756 return(MSWRAlpineGet(HKEY_LOCAL_MACHINE, NULL,
10757 TEXT("Pinedir"), data_lptstr, size));
10758 case MSWR_PINE_EXE :
10759 return(MSWRAlpineGet(HKEY_LOCAL_MACHINE, NULL,
10760 TEXT("PineEXE"), data_lptstr, size));
10761 case MSWR_PINE_POS :
10762 return(MSWRAlpineGet(HKEY_CURRENT_USER, NULL,
10763 TEXT("PinePos"), data_lptstr, size));
10764 default :
10765 break;
10768 else if(op & MSWR_OP_BLAST){
10769 int rv = 0, i, j;
10771 for(i = 0; mswin_pine_regs[i].rhk; i++){
10772 for(j = 0; mswin_pine_regs[i].knames[j]; j++)
10773 MSWRClear(mswin_pine_regs[i].rhk, mswin_pine_regs[i].knames[j]);
10775 if(rv) return -1;
10777 /* else, ignore unknown op? */
10779 return(0);
10783 LOCAL void
10784 MSWRAlpineSet(HKEY hRootKey, LPTSTR subkey, LPTSTR val, int update, LPTSTR data)
10786 HKEY hKey;
10787 TCHAR keybuf[MSWR_KEY_MAX+1];
10789 _sntprintf(keybuf, MSWR_KEY_MAX+1, TEXT("%s%s%s"), MSWR_ROOT,
10790 (subkey && *subkey != '\\') ? TEXT("\\") : TEXT(""),
10791 (subkey) ? TEXT("\\") : TEXT(""));
10793 if(RegCreateKeyEx(hRootKey, keybuf, 0, TEXT("REG_SZ"),
10794 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10795 NULL, &hKey, NULL) == ERROR_SUCCESS){
10796 if(update || RegQueryValueEx(hKey, val, NULL, NULL,
10797 NULL, NULL) != ERROR_SUCCESS)
10798 RegSetValueEx(hKey, val, 0, REG_SZ, (LPBYTE)data, (DWORD)(_tcslen(data)+1)*sizeof(TCHAR));
10800 RegCloseKey(hKey);
10806 LOCAL int
10807 MSWRAlpineGet(HKEY hKey, LPTSTR subkey, LPTSTR val, LPTSTR data_lptstr, size_t len)
10809 TCHAR keybuf[MSWR_KEY_MAX+1];
10810 DWORD dlen = (DWORD)len;
10812 _sntprintf(keybuf, MSWR_KEY_MAX+1, TEXT("%s%s%s"), MSWR_ROOT,
10813 (subkey && *subkey != '\\') ? TEXT("\\") : TEXT(""),
10814 (subkey) ? TEXT("\\") : TEXT(""));
10816 return(MSWRPeek(hKey, keybuf, val, data_lptstr, &dlen) == TRUE);
10821 LOCAL void
10822 MSWRAlpineSetHandlers(int update, LPTSTR path_lptstr)
10824 HKEY hKey, hSubKey;
10825 DWORD dwDisp;
10826 BYTE tmp_b[MSWR_DATA_MAX];
10827 unsigned long tmplen = MSWR_DATA_MAX, tmp_lptstr_tcharlen = MSWR_DATA_MAX/sizeof(TCHAR);
10828 int exists;
10829 LPTSTR tmp_lptstr = (LPTSTR)tmp_b;
10831 /* Register as a mail client on this system */
10832 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
10833 MSWR_ROOT, 0, KEY_ALL_ACCESS,
10834 &hKey) == ERROR_SUCCESS){
10835 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, MSWR_CAPABILITIES, 0, TEXT("REG_SZ"),
10836 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10837 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10838 MSWRPoke(hSubKey, NULL, TEXT("ApplicationDescription"),
10839 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."));
10840 MSWRPoke(hSubKey, NULL, TEXT("ApplicationName"),
10841 TEXT("Alpine"));
10842 _sntprintf(tmp_lptstr, tmp_lptstr_tcharlen, TEXT("%salpine.exe,0"), path_lptstr);
10843 MSWRPoke(hSubKey, NULL, TEXT("ApplicationIcon"), tmp_lptstr);
10844 MSWRPoke(hSubKey, TEXT("UrlAssociations"), TEXT("mailto"), TEXT("Alpine.Url.Mailto"));
10845 MSWRPoke(hSubKey, TEXT("UrlAssociations"), TEXT("news"), TEXT("Alpine.Url.News"));
10846 MSWRPoke(hSubKey, TEXT("UrlAssociations"), TEXT("nntp"), TEXT("Alpine.Url.Nntp"));
10847 MSWRPoke(hSubKey, TEXT("UrlAssociations"), TEXT("imap"), TEXT("Alpine.Url.Imap"));
10848 RegCloseKey(hSubKey);
10850 RegCloseKey(hKey);
10851 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\RegisteredApplications"), 0,
10852 KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){
10853 MSWRPoke(hKey, NULL, TEXT("Alpine"), MSWR_CAPABILITIES);
10854 RegCloseKey(hKey);
10856 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
10857 TEXT("Software\\Classes"), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){
10858 if(RegCreateKeyEx(hKey, TEXT("Alpine.Url.Mailto"), 0, TEXT("REG_SZ"),
10859 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10860 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10861 MSWRProtocolSet(hSubKey, MSWR_SDC_MAIL, path_lptstr);
10862 RegCloseKey(hSubKey);
10864 if(RegCreateKeyEx(hKey, TEXT("Alpine.Url.Nntp"), 0, TEXT("REG_SZ"),
10865 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10866 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10867 MSWRProtocolSet(hSubKey, MSWR_SDC_NNTP, path_lptstr);
10868 RegCloseKey(hSubKey);
10870 if(RegCreateKeyEx(hKey, TEXT("Alpine.Url.News"), 0, TEXT("REG_SZ"),
10871 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10872 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10873 MSWRProtocolSet(hSubKey, MSWR_SDC_NEWS, path_lptstr);
10874 RegCloseKey(hSubKey);
10876 if(RegCreateKeyEx(hKey, TEXT("Alpine.Url.Imap"), 0, TEXT("REG_SZ"),
10877 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10878 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10879 MSWRProtocolSet(hSubKey, MSWR_SDC_IMAP, path_lptstr);
10880 RegCloseKey(hSubKey);
10882 RegCloseKey(hKey);
10886 if((exists = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
10887 TEXT("SOFTWARE\\Clients\\Mail\\Alpine"),
10888 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
10889 || RegCreateKeyEx(HKEY_LOCAL_MACHINE,
10890 TEXT("SOFTWARE\\Clients\\Mail\\Alpine"),
10891 0, TEXT("REG_SZ"),
10892 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10893 NULL, &hKey, &dwDisp) == ERROR_SUCCESS){
10894 if(update || !exists){
10895 DWORD dType;
10896 char *tmp_utf8str = NULL;
10898 MSWRPoke(hKey, NULL, NULL, MSWR_APPNAME);
10899 /* set up MAPI dll stuff */
10900 *tmp_b = 0;
10901 RegQueryValueEx(hKey, MSWR_DLLPATH, NULL, &dType, tmp_b, &tmplen);
10902 tmp_lptstr = (LPTSTR)tmp_b;
10903 if(!(*tmp_lptstr)
10904 || (can_access(tmp_utf8str = lptstr_to_utf8(tmp_lptstr), ACCESS_EXISTS) != 0)){
10905 if(*tmp_lptstr)
10906 RegDeleteValue(hKey, MSWR_DLLPATH);
10907 if(tmp_utf8str)
10908 MemFree((void *)tmp_utf8str);
10910 _sntprintf(tmp_lptstr, tmp_lptstr_tcharlen,
10911 TEXT("%s%s"), path_lptstr, MSWR_DLLNAME);
10913 if(can_access(tmp_utf8str = lptstr_to_utf8(tmp_lptstr), ACCESS_EXISTS) == 0)
10914 MSWRPoke(hKey, NULL, MSWR_DLLPATH, tmp_lptstr);
10916 if(tmp_utf8str)
10917 MemFree((void *)tmp_utf8str);
10918 /* Set "mailto" handler */
10919 if(RegCreateKeyEx(hKey, TEXT("Protocols\\Mailto"), 0, TEXT("REG_SZ"),
10920 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10921 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10922 MSWRProtocolSet(hSubKey, MSWR_SDC_MAIL, path_lptstr);
10923 RegCloseKey(hSubKey);
10926 /* Set normal handler */
10927 _sntprintf(tmp_lptstr, tmp_lptstr_tcharlen,
10928 TEXT("\"%salpine.exe\""), path_lptstr);
10929 MSWRPoke(hKey, TEXT("shell\\open\\command"), NULL, tmp_lptstr);
10932 RegCloseKey(hKey);
10935 /* Register as a news client on this system */
10936 if((exists = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
10937 TEXT("SOFTWARE\\Clients\\News\\Alpine"),
10938 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
10939 || RegCreateKeyEx(HKEY_LOCAL_MACHINE,
10940 TEXT("SOFTWARE\\Clients\\News\\Alpine"),
10941 0, TEXT("REG_SZ"), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10942 NULL, &hKey, &dwDisp) == ERROR_SUCCESS){
10943 if(update || !exists){
10944 MSWRPoke(hKey, NULL, NULL, MSWR_APPNAME);
10946 /* Set "news" handler */
10947 if(RegCreateKeyEx(hKey, TEXT("Protocols\\news"), 0, TEXT("REG_SZ"),
10948 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10949 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10950 MSWRProtocolSet(hSubKey, MSWR_SDC_NEWS, path_lptstr);
10951 RegCloseKey(hSubKey);
10953 /* Set "nntp" handler */
10954 if(RegCreateKeyEx(hKey, TEXT("Protocols\\nntp"), 0, TEXT("REG_SZ"),
10955 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10956 NULL, &hSubKey, &dwDisp) == ERROR_SUCCESS){
10957 MSWRProtocolSet(hSubKey, MSWR_SDC_NNTP, path_lptstr);
10958 RegCloseKey(hSubKey);
10961 /* Set normal handler */
10962 _sntprintf(tmp_lptstr, tmp_lptstr_tcharlen,
10963 TEXT("\"%salpine.exe\""), path_lptstr);
10964 MSWRPoke(hKey, TEXT("shell\\open\\command"), NULL, tmp_lptstr);
10967 RegCloseKey(hKey);
10970 /* Register as a IMAP url handler */
10971 if((exists = RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("imap"),
10972 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
10973 || RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT("imap"), 0, TEXT("REG_SZ"),
10974 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
10975 NULL, &hKey, &dwDisp) == ERROR_SUCCESS){
10976 if(update || !exists)
10977 MSWRProtocolSet(hKey, MSWR_SDC_IMAP, path_lptstr);
10979 RegCloseKey(hKey);
10985 char *
10986 mswin_reg_default_browser(char *url_utf8)
10988 TCHAR scheme[MSWR_KEY_MAX+1], *p;
10989 LPTSTR url_lptstr;
10990 char cmdbuf[MSWR_DATA_MAX], *cmd = NULL;
10992 url_lptstr = utf8_to_lptstr(url_utf8);
10994 if(url_lptstr && (p = _tcschr(url_lptstr, ':')) && p - url_lptstr < MSWR_KEY_MAX){
10995 _tcsncpy(scheme, url_lptstr, p - url_lptstr);
10996 scheme[p-url_lptstr] = '\0';
10998 if(MSWRShellCanOpen(scheme, cmdbuf, MSWR_DATA_MAX, 0)){
10999 size_t len;
11001 len = strlen(cmdbuf) + 2;
11002 cmd = (char *) fs_get((len+1) * sizeof(char));
11003 if(cmd){
11004 if(strchr(cmdbuf, '*'))
11005 snprintf(cmd, len+1, "\"%s\"", cmdbuf);
11006 else{
11007 strncpy(cmd, cmdbuf, len);
11008 cmd[len] = '\0';
11014 MemFree((void *)url_lptstr);
11016 return(cmd);
11021 mswin_is_def_client(int type)
11023 TCHAR buf[MSWR_KEY_MAX+1];
11024 DWORD buflen = MSWR_KEY_MAX;
11026 if(type != MSWR_SDC_MAIL && type != MSWR_SDC_NEWS)
11027 return -1;
11029 if(MSWRPeek(HKEY_CURRENT_USER,
11030 type == MSWR_SDC_MAIL ? TEXT("Software\\Clients\\Mail")
11031 : TEXT("Software\\Clients\\News"), NULL,
11032 buf, &buflen) && !_tcscmp(buf, TEXT("Alpine")))
11033 return 1;
11034 buflen = MSWR_KEY_MAX;
11035 if(MSWRPeek(HKEY_LOCAL_MACHINE,
11036 type == MSWR_SDC_MAIL ? TEXT("Software\\Clients\\Mail")
11037 : TEXT("Software\\Clients\\News"), NULL,
11038 buf, &buflen) && !_tcscmp(buf, TEXT("Alpine")))
11039 return 1;
11040 return 0;
11044 mswin_set_def_client(int type)
11046 HKEY hKey;
11047 int successful_set = 0;
11048 TCHAR path_lptstr[MSWR_DATA_MAX];
11049 DWORD dwDisp;
11051 if(type != MSWR_SDC_MAIL && type != MSWR_SDC_NEWS)
11052 return 1;
11053 if(RegOpenKeyEx(HKEY_CURRENT_USER,
11054 type == MSWR_SDC_MAIL ? TEXT("Software\\Clients\\Mail")
11055 : TEXT("Software\\Clients\\News"),
11056 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){
11057 successful_set = MSWRPoke(hKey, NULL, NULL, TEXT("Alpine"));
11058 RegCloseKey(hKey);
11060 else if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
11061 type == MSWR_SDC_MAIL ? TEXT("Software\\Clients\\Mail")
11062 : TEXT("Software\\Clients\\News"),
11063 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS){
11064 successful_set = MSWRPoke(hKey, NULL, NULL, TEXT("Alpine"));
11065 RegCloseKey(hKey);
11067 if(successful_set){
11068 mswin_reg_lptstr(MSWR_OP_GET, MSWR_PINE_DIR, path_lptstr, sizeof(path_lptstr)/sizeof(TCHAR));
11069 if(type == MSWR_SDC_MAIL){
11070 MSWRClear(HKEY_CLASSES_ROOT, TEXT("mailto"));
11071 if(RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT("mailto"), 0, TEXT("REG_SZ"),
11072 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
11073 NULL, &hKey, &dwDisp) == ERROR_SUCCESS){
11074 MSWRProtocolSet(hKey, MSWR_SDC_MAIL, path_lptstr);
11075 RegCloseKey(hKey);
11078 else if(type == MSWR_SDC_NEWS){
11079 MSWRClear(HKEY_CLASSES_ROOT, TEXT("news"));
11080 if(RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT("news"), 0, TEXT("REG_SZ"),
11081 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
11082 NULL, &hKey, &dwDisp) == ERROR_SUCCESS){
11083 MSWRProtocolSet(hKey, MSWR_SDC_NEWS, path_lptstr);
11084 RegCloseKey(hKey);
11086 MSWRClear(HKEY_CLASSES_ROOT, TEXT("nntp"));
11087 if(RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT("nntp"), 0, TEXT("REG_SZ"),
11088 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
11089 NULL, &hKey, &dwDisp) == ERROR_SUCCESS){
11090 MSWRProtocolSet(hKey, MSWR_SDC_NNTP, path_lptstr);
11091 RegCloseKey(hKey);
11095 return 0;
11099 MSWRProtocolSet(HKEY hKey, int type, LPTSTR path_lptstr)
11101 TCHAR tmp_lptstr[MSWR_DATA_MAX];
11102 BYTE EditFlags[4];
11103 unsigned long tmp_lptstr_len = MSWR_DATA_MAX;
11105 if(type != MSWR_SDC_MAIL && type != MSWR_SDC_NEWS
11106 && type != MSWR_SDC_NNTP && type != MSWR_SDC_IMAP)
11107 return -1;
11108 MSWRPoke(hKey, NULL, NULL, type == MSWR_SDC_MAIL
11109 ? TEXT("URL:MailTo Protocol")
11110 : type == MSWR_SDC_NEWS ? TEXT("URL:News Protocol")
11111 : type == MSWR_SDC_NNTP ? TEXT("URL:NNTP Protocol")
11112 : TEXT("URL:IMAP Prototcol"));
11113 MSWRPoke(hKey, NULL, TEXT("URL Protocol"), TEXT(""));
11115 EditFlags[0] = 0x02;
11116 EditFlags[1] = EditFlags[2] = EditFlags[3] = 0;
11118 (void) RegDeleteValue(hKey, TEXT("EditFlags"));
11119 (void) RegSetValueEx(hKey, TEXT("EditFlags"), 0, REG_BINARY,
11120 EditFlags, (DWORD) 4);
11122 _sntprintf(tmp_lptstr, tmp_lptstr_len,
11123 TEXT("%salpine.exe,0"), path_lptstr);
11124 MSWRPoke(hKey, TEXT("DefaultIcon"), NULL, tmp_lptstr);
11126 _sntprintf(tmp_lptstr, tmp_lptstr_len,
11127 TEXT("\"%salpine.exe\" -url \"%%1\""), path_lptstr);
11128 MSWRPoke(hKey, TEXT("shell\\open\\command"), NULL, tmp_lptstr);
11129 return 0;
11133 /* cmdbuf can stay char * since it's our string */
11134 BOOL
11135 MSWRShellCanOpen(LPTSTR key, char *cmdbuf, int clen, int allow_noreg)
11137 HKEY hKey;
11138 BOOL rv = FALSE;
11140 /* See if Shell provides a method to open the thing... */
11141 if(RegOpenKeyEx(HKEY_CLASSES_ROOT, key,
11142 0, KEY_READ, &hKey) == ERROR_SUCCESS){
11144 if(cmdbuf){
11145 strncpy(cmdbuf, "*Shell*", clen);
11146 cmdbuf[clen-1] = '\0';
11149 rv = TRUE;
11151 RegCloseKey(hKey);
11153 else if(allow_noreg && cmdbuf){
11154 strncpy(cmdbuf, "*Shell*", clen);
11155 cmdbuf[clen-1] = '\0';
11156 rv = TRUE;
11159 return(rv);
11164 * Fundamental registry access function that queries for particular values.
11166 LOCAL BOOL
11167 MSWRPeek(HKEY hRootKey, LPTSTR subkey, LPTSTR valstr, LPTSTR data_lptstr, DWORD *dlen)
11169 HKEY hKey;
11170 DWORD dtype, dlen_bytes = (dlen ? *dlen : 0) * sizeof(TCHAR);
11171 LONG rv = !ERROR_SUCCESS;
11173 if(RegOpenKeyEx(hRootKey, subkey, 0, KEY_READ, &hKey) == ERROR_SUCCESS){
11174 rv = RegQueryValueEx(hKey, valstr, NULL, &dtype, (LPBYTE)data_lptstr, &dlen_bytes);
11175 if(dlen)
11176 (*dlen) = dlen_bytes;
11177 RegCloseKey(hKey);
11180 return(rv == ERROR_SUCCESS);
11185 * Fundamental registry access function that sets particular values.
11187 LOCAL BOOL
11188 MSWRPoke(HKEY hKey, LPTSTR subkey, LPTSTR valstr, LPTSTR data_lptstr)
11190 DWORD dtype, dwDisp, dlen = MSWR_DATA_MAX;
11191 BYTE olddata[MSWR_DATA_MAX];
11192 BOOL rv = FALSE;
11194 if(!subkey
11195 || RegCreateKeyEx(hKey, subkey,
11196 0, TEXT("REG_SZ"), REG_OPTION_NON_VOLATILE,
11197 KEY_ALL_ACCESS, NULL,
11198 &hKey, &dwDisp) == ERROR_SUCCESS){
11200 if(RegQueryValueEx(hKey, valstr, NULL, &dtype,
11201 olddata, &dlen) != ERROR_SUCCESS
11202 || _tcscmp((LPTSTR)olddata, data_lptstr)){
11203 (void) RegDeleteValue(hKey, valstr);
11204 rv = RegSetValueEx(hKey, valstr, 0, REG_SZ,
11205 (LPBYTE)data_lptstr,
11206 (DWORD)(_tcslen(data_lptstr) + 1)*sizeof(TCHAR)) == ERROR_SUCCESS;
11209 if(subkey)
11210 RegCloseKey(hKey);
11213 return(rv);
11217 LOCAL void
11218 MSWRLineBufAdd(MSWR_LINE_BUFFER_S *lpLineBuf, LPTSTR line)
11220 if(lpLineBuf->offset >= lpLineBuf->size){
11221 /* this probably won't happen, but just in case */
11222 lpLineBuf->size *= 2;
11223 lpLineBuf->linep = (char **)MemRealloc(lpLineBuf->linep,
11224 (lpLineBuf->size + 1)*sizeof(char *));
11227 lpLineBuf->linep[lpLineBuf->offset++] = lptstr_to_utf8(line);
11228 lpLineBuf->linep[lpLineBuf->offset] = NULL;
11232 * Dump all of the registry values from a list of keys into an array
11233 * of UTF8-formatted strings.
11235 char **
11236 mswin_reg_dump(void)
11238 MSWR_LINE_BUFFER_S lineBuf;
11239 unsigned long initial_size = 256;
11240 int i, j;
11242 lineBuf.linep = (char **)MemAlloc((initial_size+1)*sizeof(char *));
11243 lineBuf.size = initial_size;
11244 lineBuf.offset = 0;
11246 MSWRLineBufAdd(&lineBuf, TEXT("Registry values for Alpine:"));
11247 MSWRLineBufAdd(&lineBuf, TEXT(""));
11249 for(i = 0; mswin_pine_regs[i].rhk; i++){
11250 MSWRLineBufAdd(&lineBuf, mswin_pine_regs[i].rhk == HKEY_LOCAL_MACHINE
11251 ? TEXT("HKEY_LOCAL_MACHINE")
11252 : TEXT("HKEY_CURRENT_USER"));
11253 for(j = 0; mswin_pine_regs[i].knames[j]; j++)
11254 MSWRDump(mswin_pine_regs[i].rhk,
11255 mswin_pine_regs[i].knames[j],
11256 1, &lineBuf);
11259 return(lineBuf.linep);
11264 * Recursive function to crawl a registry hierarchy and print the contents.
11266 * Returns: 0
11268 LOCAL int
11269 MSWRDump(HKEY hKey, LPTSTR pSubKey, int keyDepth, MSWR_LINE_BUFFER_S *lpLineBuf)
11271 HKEY hSubKey;
11272 TCHAR KeyBuf[MSWR_KEY_MAX+1];
11273 TCHAR ValBuf[MSWR_VAL_MAX+1];
11274 BYTE DataBuf[MSWR_DATA_MAX+1];
11275 DWORD dwKeyIndex, dwKeyLen;
11276 DWORD dwValIndex, dwValLen, dwDataLen;
11277 DWORD dwType;
11278 FILETIME ftKeyTime;
11279 TCHAR new_buf[1024];
11280 unsigned int new_buf_len = 1024;
11281 int i, j, k, tab_width = 4;
11283 /* open the passed subkey */
11284 if(RegOpenKeyEx(hKey, pSubKey, 0,
11285 KEY_READ, &hSubKey) == ERROR_SUCCESS){
11287 /* print out key name here */
11288 for(i = 0, k = 0; i < keyDepth % 8; i++)
11289 for(j = 0; j < tab_width; j++)
11290 new_buf[k++] = ' ';
11291 _sntprintf(new_buf+k, new_buf_len - k, TEXT("%s"), pSubKey);
11292 new_buf[new_buf_len - 1] = '\0';
11293 MSWRLineBufAdd(lpLineBuf, new_buf);
11295 keyDepth++;
11297 /* Loop through the string values and print their data */
11298 for(dwValIndex = 0L, dwValLen = MSWR_VAL_MAX + 1, dwDataLen = MSWR_DATA_MAX + 1;
11299 RegEnumValue(hSubKey, dwValIndex, ValBuf, &dwValLen, NULL, &dwType,
11300 DataBuf, &dwDataLen) == ERROR_SUCCESS;
11301 dwValIndex++, dwValLen = MSWR_VAL_MAX + 1, dwDataLen = MSWR_DATA_MAX + 1){
11303 /* print out value here */
11304 for(i = 0, k = 0; i < keyDepth % 8; i++)
11305 for(j = 0; j < tab_width; j++)
11306 new_buf[k++] = ' ';
11307 _sntprintf(new_buf+k, new_buf_len - k,
11308 TEXT("%.*s = %.*s"),
11309 dwValLen ? dwValLen : 128,
11310 dwValLen ? ValBuf : TEXT("(Default)"),
11311 dwType == REG_SZ && dwDataLen ? dwDataLen/sizeof(TCHAR) : 128,
11312 (dwType == REG_SZ
11313 ? (dwDataLen ? (LPTSTR)DataBuf : TEXT("(No data)"))
11314 : TEXT("(Some non-string data)")));
11315 new_buf[new_buf_len - 1] = '\0';
11316 MSWRLineBufAdd(lpLineBuf, new_buf);
11319 /* Loop through the subkeys and recursively print their data */
11320 for(dwKeyIndex = 0L, dwKeyLen = MSWR_KEY_MAX + 1;
11321 RegEnumKeyEx(hSubKey, dwKeyIndex, KeyBuf, &dwKeyLen,
11322 NULL, NULL, NULL, &ftKeyTime) == ERROR_SUCCESS;
11323 dwKeyIndex++, dwKeyLen = MSWR_KEY_MAX + 1){
11324 MSWRDump(hSubKey, KeyBuf, keyDepth, lpLineBuf);
11327 else {
11328 /* Couldn't open the key. Must not be defined. */
11329 for(i = 0, k = 0; i < keyDepth % 8; i++)
11330 for(j = 0; j < tab_width; j++)
11331 new_buf[k++] = ' ';
11332 _sntprintf(new_buf+k, new_buf_len - k, TEXT("%s - Not Defined"), pSubKey);
11333 new_buf[new_buf_len - 1] = '\0';
11334 MSWRLineBufAdd(lpLineBuf, new_buf);
11337 return 0;
11342 * Fundamental registry access function that removes a registry key
11343 * and all its subkeys, their values and data
11345 LOCAL int
11346 MSWRClear(HKEY hKey, LPTSTR pSubKey)
11348 HKEY hSubKey;
11349 TCHAR KeyBuf[MSWR_KEY_MAX+1];
11350 DWORD dwKeyIndex, dwKeyLen;
11351 FILETIME ftKeyTime;
11352 int rv = 0;
11354 if(RegOpenKeyEx(hKey, pSubKey, 0,
11355 KEY_READ, &hSubKey) == ERROR_SUCCESS){
11356 RegCloseKey(hSubKey);
11357 if(RegOpenKeyEx(hKey, pSubKey, 0,
11358 KEY_ALL_ACCESS, &hSubKey) == ERROR_SUCCESS){
11359 for(dwKeyIndex = 0L, dwKeyLen = MSWR_KEY_MAX + 1;
11360 RegEnumKeyEx(hSubKey, dwKeyIndex, KeyBuf, &dwKeyLen,
11361 NULL, NULL, NULL, &ftKeyTime) == ERROR_SUCCESS;
11362 dwKeyLen = MSWR_KEY_MAX + 1)
11363 if(MSWRClear(hSubKey, KeyBuf)!= 0){
11364 rv = -1;
11365 dwKeyIndex++;
11367 RegCloseKey(hSubKey);
11368 if(RegDeleteKey(hKey, pSubKey) != ERROR_SUCCESS || rv)
11369 return -1;
11370 return 0;
11372 return -1;
11374 return 0;
11378 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11380 * Text display Windows.
11382 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
11385 * Show a help message.
11386 * Help text comes as a null terminated array of pointers to lines of
11387 * text. Stuff these into a buffer and pass that to MessageBox.
11389 void
11390 mswin_showhelpmsg(WINHAND wnd, char **helplines)
11392 char **l;
11393 char *helptext_utf8, *p;
11394 size_t buflen;
11395 HWND hWnd;
11396 LPTSTR helptext_lpt;
11398 hWnd = (HWND) wnd;
11399 if(hWnd == NULL)
11400 hWnd = ghTTYWnd;
11402 buflen = 0;
11403 for(l = helplines; *l != NULL; ++l)
11404 buflen += (strlen(*l)+1);
11406 helptext_utf8 = (char *) fs_get((buflen + 1) * sizeof(char));
11407 if(helptext_utf8 == NULL)
11408 return;
11410 *helptext_utf8 = '\0';
11412 p = helptext_utf8;
11413 for(l = helplines; *l != NULL; ++l){
11414 snprintf(p, buflen+1-(p-helptext_utf8), "%s%s", (p == helptext_utf8) ? "" : " ", *l);
11415 p += strlen(p);
11418 helptext_lpt = utf8_to_lptstr(helptext_utf8);
11420 MessageBox(hWnd, helptext_lpt, TEXT("Help"),
11421 MB_APPLMODAL | MB_ICONINFORMATION | MB_OK);
11423 fs_give((void **) &helptext_utf8);
11424 fs_give((void **) &helptext_lpt);
11428 * Callback for when new mail or imap telem window gets canned.
11430 LOCAL void
11431 mswin_tw_close_imap_telem_or_new_mail(MSWIN_TEXTWINDOW *mswin_tw)
11433 HMENU hMenu;
11435 if((mswin_tw->id == IDM_OPT_IMAPTELEM) && gIMAPDebugOFFCallback)
11436 (*gIMAPDebugOFFCallback)();
11438 if(hMenu = GetMenu(ghTTYWnd))
11439 CheckMenuItem (hMenu, mswin_tw->id, MF_BYCOMMAND | MF_UNCHECKED);
11443 * Callback for when new mail or imap telem window gets cleared.
11445 LOCAL void
11446 mswin_tw_clear_imap_telem_or_new_mail(MSWIN_TEXTWINDOW *mswin_tw)
11448 char *tmtxt;
11449 time_t now = time((time_t *)0);
11450 LPCTSTR desc = (mswin_tw->id == IDM_OPT_IMAPTELEM) ?
11451 TEXT("IMAP telemetry recorder") :
11452 TEXT("New Mail window");
11454 tmtxt = ctime(&now);
11456 mswin_tw_printf(mswin_tw, TEXT("%s started at %.*S"),
11457 desc, MIN(100, strlen(tmtxt)-1), tmtxt);
11459 if(mswin_tw->id == IDM_OPT_NEWMAILWIN)
11461 int i;
11462 int fromlen, subjlen, foldlen, len;
11463 TCHAR ring2[256];
11465 foldlen = (int)(.18 * gNMW_width);
11466 foldlen = foldlen > 5 ? foldlen : 5;
11467 fromlen = (int)(.28 * gNMW_width);
11468 subjlen = gNMW_width - 2 - foldlen - fromlen;
11470 mswin_tw_printf(mswin_tw,
11471 TEXT(" %-*s%-*s%-*s"),
11472 fromlen, TEXT("From:"),
11473 subjlen, TEXT("Subject:"),
11474 foldlen, TEXT("Folder:"));
11476 len = 2 + fromlen + subjlen + foldlen;
11477 if(len >= ARRAYSIZE(ring2) + 1)
11478 len = ARRAYSIZE(ring2) - 2;
11479 for(i = 0; i < len; i++)
11480 ring2[i] = '-';
11481 ring2[i] = '\0';
11482 mswin_tw_puts_lptstr(mswin_tw, ring2);
11487 * Init new mail or imap telem window
11489 LOCAL int
11490 mswin_tw_init(MSWIN_TEXTWINDOW *mswin_tw, int id, LPCTSTR title)
11492 if(mswin_tw->hwnd){
11493 /* destroy it */
11494 mswin_tw_close(mswin_tw);
11496 else{
11497 HMENU hMenu;
11499 mswin_tw->id = id;
11500 mswin_tw->hInstance = ghInstance;
11501 mswin_tw->print_callback = mswin_tw_print_callback;
11502 mswin_tw->close_callback = mswin_tw_close_imap_telem_or_new_mail;
11503 mswin_tw->clear_callback = mswin_tw_clear_imap_telem_or_new_mail;
11505 // If the rcSize rect is empty, then init it to something resembling
11506 // the size of the current Pine window. Otherwise we just re-use
11507 // whatever the last position/size was.
11508 if(IsRectEmpty(&mswin_tw->rcSize))
11510 RECT cliRect;
11511 RECT sizeRect;
11513 GetClientRect(ghTTYWnd, &cliRect);
11514 sizeRect.left = CW_USEDEFAULT;
11515 sizeRect.top = CW_USEDEFAULT;
11516 sizeRect.right = cliRect.right;
11517 sizeRect.bottom = cliRect.bottom;
11518 mswin_tw->rcSize = sizeRect;
11521 if(!mswin_tw_create(mswin_tw, title))
11522 return 1;
11524 mswin_tw_setfont(mswin_tw, gpTTYInfo->hTTYFont);
11525 mswin_tw_setcolor(mswin_tw, gpTTYInfo->rgbFGColor, gpTTYInfo->rgbBGColor);
11527 mswin_tw_clear(mswin_tw);
11529 if(id == IDM_OPT_IMAPTELEM)
11531 if(gIMAPDebugONCallback)
11532 (*gIMAPDebugONCallback)();
11534 mswin_tw_showwindow(mswin_tw, SW_SHOWNA);
11536 else if(id == IDM_OPT_NEWMAILWIN){
11537 mswin_tw_showwindow(mswin_tw, SW_SHOW);
11540 if(hMenu = GetMenu(ghTTYWnd))
11541 CheckMenuItem (hMenu, mswin_tw->id, MF_BYCOMMAND | MF_CHECKED);
11544 return(0);
11548 * Display text in a window.
11550 * Parameters:
11551 * title - Title of window.
11552 * pText - address of text to display.
11553 * textLen - Length of text, in bytes. Limited to 64K.
11554 * pLines - Array of pointers to lines of text. Each
11555 * line is a sepreate allocation block. The
11556 * entry in the array of pointers should be a
11557 * NULL.
11559 * The text can be supplied as a buffer (pText and textLen) in which
11560 * lines are terminated by CRLF (including the last line in buffer).
11561 * This buffer should be NULL terminated, too.
11562 * Or it can be supplied as a NULL terminated array of pointers to
11563 * lines. Each entry points to a separately allocated memory block
11564 * containing a null terminated string.
11566 * If the function succeeds the memory containing the text will be
11567 * used until the user closes the window, at which point it will be
11568 * freed.
11570 * Returns:
11571 * mswin_tw - SUCCESS
11572 * NULL - Failed.
11574 MSWIN_TEXTWINDOW *
11575 mswin_displaytext(char *title_utf8, char *pText_utf8, size_t npText,
11576 char **pLines_utf8, MSWIN_TEXTWINDOW *mswin_tw, int flags)
11578 LPTSTR title_lpt = NULL, pText_lpt = NULL, *pLines_lpt = NULL;
11579 char **l;
11580 size_t pText_lpt_len = 0;
11581 int i, count = 0;
11583 if(pLines_utf8 != NULL){
11584 for(count=0, l = pLines_utf8; *l != NULL; ++l)
11585 ++count;
11587 pLines_lpt = (LPTSTR *) fs_get((count + 1) * sizeof(LPTSTR));
11588 memset(pLines_lpt, 0, (count + 1) * sizeof(LPTSTR));
11589 for(i=0, l = pLines_utf8; *l != NULL && i < count; ++l, ++i)
11590 pLines_lpt[i] = utf8_to_lptstr(*l);
11592 /*caller expects this to be freed */
11593 if(!(flags & MSWIN_DT_NODELETE)){
11594 for(l = pLines_utf8; *l != NULL; ++l)
11595 fs_give((void **) l);
11597 fs_give((void **) &pLines_utf8);
11601 if(pText_utf8 != NULL && npText > 0){
11602 pText_lpt = utf8_to_lptstr(pText_utf8);
11603 pText_lpt_len = lstrlen(pText_lpt);
11605 /*caller expects this to be freed */
11606 if(!(flags & MSWIN_DT_NODELETE))
11607 fs_give((void **) &pText_utf8);
11610 if(title_utf8 != NULL)
11611 title_lpt = utf8_to_lptstr(title_utf8);
11613 mswin_tw = mswin_tw_displaytext_lptstr(title_lpt, pText_lpt, pText_lpt_len,
11614 pLines_lpt, mswin_tw, flags);
11616 if(pLines_lpt != NULL){
11617 for(i=0; i < count; ++i)
11618 if(pLines_lpt[i])
11619 fs_give((void **) &pLines_lpt[i]);
11621 fs_give((void **) &pLines_lpt);
11624 if(pText_lpt != NULL)
11625 fs_give((void **) &pText_lpt);
11627 if(title_lpt != NULL)
11628 fs_give((void **) &title_lpt);
11630 return(mswin_tw);
11634 * Callback for when a generic mswin_tw gets killed.
11636 LOCAL void
11637 mswin_tw_close_callback(MSWIN_TEXTWINDOW *mswin_tw)
11639 if(mswin_tw->id != -1)
11640 MemFree(mswin_tw);
11644 * Create a new mswin_tw window. If the MSWIN_DT_USEALTWINDOW flag is set,
11645 * then (re)use gMswinAltWin.
11647 LOCAL MSWIN_TEXTWINDOW *
11648 mswin_tw_displaytext_lptstr (LPTSTR title, LPTSTR pText, size_t textLen, LPTSTR *pLines,
11649 MSWIN_TEXTWINDOW *mswin_tw, int flags)
11651 if (pText == NULL && pLines == NULL)
11652 return (NULL);
11654 /* Was a valid existing window supplied? */
11655 if(!mswin_tw)
11657 int ctrl_down = GetKeyState(VK_CONTROL) < 0;
11659 if((flags & MSWIN_DT_USEALTWINDOW) && !ctrl_down)
11661 mswin_tw = &gMswinAltWin;
11662 mswin_tw->id = (UINT)-1; // Tell mswin_tw_close_callback not
11663 // to free this buffer.
11665 else
11667 mswin_tw = (MSWIN_TEXTWINDOW *)MemAlloc (sizeof (MSWIN_TEXTWINDOW));
11668 if(!mswin_tw)
11669 return NULL;
11671 memset(mswin_tw, 0, sizeof(MSWIN_TEXTWINDOW));
11672 mswin_tw->id = 0;
11675 mswin_tw->hInstance = ghInstance;
11676 mswin_tw->print_callback = mswin_tw_print_callback;
11677 mswin_tw->close_callback = mswin_tw_close_callback;
11678 mswin_tw->clear_callback = NULL;
11681 /* Create a new window. */
11682 if (!mswin_tw->hwnd) {
11684 if(IsRectEmpty(&mswin_tw->rcSize))
11686 RECT sizeRect;
11687 RECT cliRect;
11689 GetClientRect(ghTTYWnd, &cliRect);
11690 sizeRect.left = CW_USEDEFAULT;
11691 sizeRect.top = CW_USEDEFAULT;
11692 sizeRect.right = cliRect.right;
11693 sizeRect.bottom = cliRect.bottom;
11694 mswin_tw->rcSize = sizeRect;
11697 if(!mswin_tw_create(mswin_tw, title)) {
11698 MemFree (mswin_tw);
11699 return (NULL);
11702 mswin_tw_setfont(mswin_tw, gpTTYInfo->hTTYFont);
11703 mswin_tw_setcolor(mswin_tw, gpTTYInfo->rgbFGColor, gpTTYInfo->rgbBGColor);
11705 else {
11706 /* Invalidate whole window, change title, and move to top. */
11707 SetWindowText (mswin_tw->hwnd, title);
11708 SetWindowPos (mswin_tw->hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
11711 mswin_tw_clear(mswin_tw);
11714 * How was text supplied?
11716 if (pLines != NULL) {
11717 LPTSTR *l;
11719 /* Array of pointers to lines supplied. Count lines. */
11720 for (l = pLines; *l != NULL; ++l){
11721 mswin_tw_puts_lptstr(mswin_tw, *l);
11724 else {
11725 #ifdef ALTED_DOT
11726 if(flags & MSWIN_DT_FILLFROMFILE)
11727 mswin_tw_fill_from_file(mswin_tw, pText);
11728 else
11729 #endif /* ALTED_DOT */
11730 /* Pointer to block of text supplied. */
11731 mswin_tw_puts_lptstr(mswin_tw, pText);
11734 mswin_tw_setsel(mswin_tw, 0, 0);
11736 mswin_tw_showwindow(mswin_tw, SW_SHOW);
11737 return mswin_tw;
11740 void
11741 mswin_enableimaptelemetry(int state)
11743 HMENU hMenu;
11744 MENUITEMINFO mitem;
11745 TCHAR buf[256];
11746 int i;
11748 hMenu = GetMenu (ghTTYWnd);
11749 if (hMenu == NULL)
11750 return;
11753 * Make sure hMenu's the right menubar
11755 mitem.cbSize = sizeof(MENUITEMINFO);
11756 mitem.fMask = (MIIM_SUBMENU | MIIM_TYPE);
11757 mitem.fType = MFT_STRING;
11758 mitem.dwTypeData = buf;
11759 mitem.cch = 255;
11760 if(GetMenuItemCount(hMenu) == 7
11761 && GetMenuItemInfo(hMenu, 5, TRUE, &mitem)){
11762 if(mitem.fType == MFT_STRING
11763 && !_tcscmp(mitem.dwTypeData, TEXT("&Config")))
11764 hMenu = mitem.hSubMenu;
11765 else
11766 return;
11768 else
11769 return;
11771 i = GetMenuItemCount(hMenu);
11772 if(state == TRUE && i < 10){
11773 mitem.fMask = MIIM_TYPE;
11774 mitem.fType = MFT_SEPARATOR;
11775 InsertMenuItem (hMenu, 8, TRUE, &mitem);
11777 mitem.fMask = (MIIM_TYPE | MIIM_ID);
11778 mitem.fType = MFT_STRING;
11779 mitem.wID = IDM_OPT_IMAPTELEM;
11780 mitem.dwTypeData = TEXT("&IMAP Telemetry");
11781 mitem.cch = 15;
11782 InsertMenuItem (hMenu, 9, TRUE, &mitem);
11784 DrawMenuBar (ghTTYWnd);
11786 else if(state == FALSE && i == 10){
11787 DeleteMenu (hMenu, 8, MF_BYPOSITION);
11788 DeleteMenu (hMenu, IDM_OPT_IMAPTELEM, MF_BYCOMMAND);
11789 DrawMenuBar (ghTTYWnd);
11794 mswin_imaptelemetry(char *msg)
11796 if(gMswinIMAPTelem.hwnd){
11797 LPTSTR msg_lptstr;
11798 msg_lptstr = utf8_to_lptstr(msg);
11799 mswin_tw_puts_lptstr(&gMswinIMAPTelem, msg_lptstr);
11800 fs_give((void **) &msg_lptstr);
11801 return(1);
11803 return(0);
11808 * The newmail window has a format proportional to screen width.
11809 * At this point, we've figured out the sizes of the fields, now
11810 * we fill that field to it's desired column size. This used to
11811 * be a lot eaier when it was one char per column, but in the
11812 * unicode world it's not that easy. This code does make the
11813 * assumption that ASCII characters are 1 column.
11815 LPTSTR
11816 format_newmail_string(LPTSTR orig_lptstr, int format_len)
11818 LPTSTR new_lptstr;
11819 int i, colLen;
11821 new_lptstr = (LPTSTR)MemAlloc((format_len+1)*sizeof(TCHAR));
11824 * Fill up string till we reach the format_len, we can backtrack
11825 * if we need ellipsis.
11827 for(i = 0, colLen = 0;
11828 i < format_len && colLen < format_len && orig_lptstr && orig_lptstr[i];
11829 i++){
11830 new_lptstr[i] = orig_lptstr[i];
11831 colLen += wcellwidth(new_lptstr[i]);
11834 if(colLen > format_len || (colLen == format_len && orig_lptstr[i])){
11836 * If we hit the edge of the format and there's still stuff
11837 * to write, go back and add ".."
11839 i--;
11840 if(wcellwidth(new_lptstr[i]) > 1){
11841 colLen -= wcellwidth(new_lptstr[i]);
11843 else{
11844 colLen -= wcellwidth(new_lptstr[i]);
11845 i--;
11846 colLen -= wcellwidth(new_lptstr[i]);
11848 while(colLen < format_len && i < format_len){
11849 new_lptstr[i++] = '.';
11850 colLen++;
11853 else{
11855 * If we've hit the end of the string, add spaces until
11856 * we get to the correct length.
11858 for(; colLen < format_len && i < format_len; i++, colLen++){
11859 new_lptstr[i] = ' ';
11863 if(i <= format_len)
11864 new_lptstr[i] = '\0';
11865 else
11866 new_lptstr[format_len] = '\0';
11868 return(new_lptstr);
11872 * We're passed the relevant fields, now format them according to window with
11873 * and put up for display
11876 mswin_newmailwin(int is_us, char *from_utf8, char *subject_utf8, char *folder_utf8)
11878 TCHAR tcbuf[256];
11879 int foldlen, fromlen, subjlen;
11880 LPTSTR from_lptstr = NULL, subject_lptstr = NULL, folder_lptstr = NULL;
11881 LPTSTR from_format, subject_format, folder_format;
11883 if(!gMswinNewMailWin.hwnd)
11884 return 0;
11886 if(from_utf8)
11887 from_lptstr = utf8_to_lptstr(from_utf8);
11888 if(subject_utf8)
11889 subject_lptstr = utf8_to_lptstr(subject_utf8);
11890 if(folder_utf8)
11891 folder_lptstr = utf8_to_lptstr(folder_utf8);
11894 foldlen = (int)(.18 * gNMW_width);
11895 foldlen = foldlen > 5 ? foldlen : 5;
11896 fromlen = (int)(.28 * gNMW_width);
11897 subjlen = gNMW_width - 2 - foldlen - fromlen;
11900 from_format = format_newmail_string(from_lptstr
11901 ? from_lptstr : TEXT(""),
11902 fromlen - 1);
11903 subject_format = format_newmail_string(subject_lptstr
11904 ? subject_lptstr : TEXT("(no subject)"),
11905 subjlen - 1);
11906 folder_format = format_newmail_string(folder_lptstr
11907 ? folder_lptstr : TEXT("INBOX"),
11908 foldlen);
11910 _sntprintf(tcbuf, 256, TEXT("%c %s %s %s"), is_us ? '+' : ' ',
11911 from_format, subject_format, folder_format);
11913 if(from_lptstr)
11914 fs_give((void **) &from_lptstr);
11915 if(subject_lptstr)
11916 fs_give((void **) &subject_lptstr);
11917 if(folder_lptstr)
11918 fs_give((void **) &folder_lptstr);
11919 MemFree((void *)from_format);
11920 MemFree((void *)subject_format);
11921 MemFree((void *)folder_format);
11923 mswin_tw_puts_lptstr(&gMswinNewMailWin, tcbuf);
11924 return 1;
11928 * Mouse up, end selection
11931 LOCAL void
11932 mswin_tw_print_callback(MSWIN_TEXTWINDOW *mswin_tw)
11934 LPTSTR text;
11935 UINT text_len;
11936 int rc;
11937 #define DESC_LEN 180
11938 TCHAR description[DESC_LEN+1];
11940 GetWindowText(mswin_tw->hwnd, description, DESC_LEN);
11942 rc = mswin_print_ready((WINHAND)mswin_tw->hwnd, description);
11943 if (rc != 0) {
11944 if (rc != PE_USER_CANCEL) {
11945 LPTSTR e;
11947 e = utf8_to_lptstr(mswin_print_error(rc));
11948 if(e){
11949 _sntprintf(description, DESC_LEN+1, TEXT("Printing failed: %s"), e);
11950 fs_give((void **) &e);
11953 MessageBox(mswin_tw->hwnd, description, TEXT("Print Failed"),
11954 MB_OK | MB_ICONEXCLAMATION);
11956 return;
11959 text_len = mswin_tw_gettextlength(mswin_tw);
11960 text = (LPTSTR) fs_get(text_len * sizeof(TCHAR));
11961 mswin_tw_gettext(mswin_tw, text, text_len);
11962 mswin_print_text(text);
11963 fs_give((void **)&text);
11965 mswin_print_done();
11969 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11971 * Character Queue
11973 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
11976 typedef struct {
11977 BOOL fKeyControlDown;
11978 UCS c; /* Bigger than TCHAR for CTRL and MENU setting */
11979 } CQEntry;
11981 LOCAL CQEntry CQBuffer [CHARACTER_QUEUE_LENGTH];
11982 LOCAL int CQHead;
11983 LOCAL int CQTail;
11984 LOCAL int CQCount;
11987 /*---------------------------------------------------------------------------
11988 * BOOL CQInit ()
11990 * Description:
11991 * Initialize the Character queue.
11993 * Parameters:
11996 /*--------------------------------------------------------------------------*/
11997 LOCAL void
11998 CQInit (void)
12000 CQHead = 0;
12001 CQTail = 0;
12002 CQCount = 0;
12006 /*---------------------------------------------------------------------------
12007 * BOOL CQAvailable (void)
12009 * Description:
12010 * Return TRUE if there are characters in the queue.
12012 * Parameters:
12015 /*--------------------------------------------------------------------------*/
12017 LOCAL BOOL
12018 CQAvailable (void)
12020 return (CQCount > 0);
12025 /*---------------------------------------------------------------------------
12026 * BOOL CQAdd (WORD c, DWORC keyData)
12028 * Description:
12029 * Add 'c' to the end of the character queue.
12031 * Parameters:
12032 * return true if successful.
12034 /*--------------------------------------------------------------------------*/
12036 LOCAL BOOL
12037 CQAdd (UCS c, BOOL fKeyControlDown)
12039 if (CQCount == CHARACTER_QUEUE_LENGTH)
12040 return (FALSE);
12042 CQBuffer[CQTail].fKeyControlDown = fKeyControlDown;
12043 CQBuffer[CQTail].c = c;
12044 CQTail = (CQTail + 1) % CHARACTER_QUEUE_LENGTH;
12045 ++CQCount;
12046 return (TRUE);
12051 /*---------------------------------------------------------------------------
12052 * BOOL CQAddUniq (WORD c, DWORC keyData)
12054 * Description:
12055 * Add 'c' to the end of the character queue, only if
12056 * there is no other 'c' in the queue
12058 * Parameters:
12059 * return true if successful.
12061 /*--------------------------------------------------------------------------*/
12063 LOCAL BOOL
12064 CQAddUniq (UCS c, BOOL fKeyControlDown)
12066 int i;
12067 int pos;
12069 if (CQCount == CHARACTER_QUEUE_LENGTH)
12070 return (FALSE);
12072 pos = CQHead;
12073 for (i = 0; i < CQCount; ++i) {
12074 if (CQBuffer[pos].c == c)
12075 return (FALSE);
12076 pos = (pos + 1) % CHARACTER_QUEUE_LENGTH;
12078 return (CQAdd (c, fKeyControlDown));
12084 /*---------------------------------------------------------------------------
12085 * int CQGet ()
12087 * Description:
12088 * Return the next byte from the head of the queue. If there is
12089 * no byte available, returns 0, which is indistinquishable from
12090 * '\0'. So it is a good idea to call CQAvailable first.
12092 * Parameters:
12093 * none.
12095 /*--------------------------------------------------------------------------*/
12097 LOCAL UCS
12098 CQGet ()
12100 UCS c;
12102 if (CQCount == 0)
12103 return (0);
12105 c = CQBuffer[CQHead].c;
12107 if(CQBuffer[CQHead].fKeyControlDown)
12108 c |= CTRL;
12110 if(c < ' ') {
12111 c += '@';
12112 c |= CTRL;
12115 CQHead = (CQHead + 1) % CHARACTER_QUEUE_LENGTH;
12116 --CQCount;
12117 return (c);
12122 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12124 * Mouse Event Queue
12126 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
12130 LOCAL MEvent MQBuffer [MOUSE_QUEUE_LENGTH];
12131 LOCAL int MQHead;
12132 LOCAL int MQTail;
12133 LOCAL int MQCount;
12136 /*---------------------------------------------------------------------------
12137 * BOOL MQInit ()
12139 * Description:
12140 * Initialize the Character queue.
12142 * Parameters:
12145 /*--------------------------------------------------------------------------*/
12146 LOCAL void
12147 MQInit (void)
12149 MQHead = 0;
12150 MQTail = 0;
12151 MQCount = 0;
12155 /*---------------------------------------------------------------------------
12156 * BOOL MQAvailable (void)
12158 * Description:
12159 * Return TRUE if there are characters in the queue.
12161 * Parameters:
12164 /*--------------------------------------------------------------------------*/
12166 LOCAL BOOL
12167 MQAvailable (void)
12169 return (MQCount > 0);
12174 /*---------------------------------------------------------------------------
12175 * BOOL MQAdd ()
12177 * Description:
12178 * Add 'c' to the end of the character queue.
12180 * Parameters:
12181 * return true if successful.
12183 /*--------------------------------------------------------------------------*/
12185 LOCAL BOOL
12186 MQAdd (int mevent, int button, int nRow, int nColumn, int keys, int flags)
12188 int c;
12189 int i = 0;
12190 BOOL found = FALSE;
12194 * Find a queue insertion point.
12196 if (flags & MSWIN_MF_REPLACING) {
12197 /* Search for same event on queue. */
12198 for ( i = MQHead, c = MQCount;
12199 c > 0;
12200 i = (i + 1) % MOUSE_QUEUE_LENGTH, --c) {
12201 if (MQBuffer[i].event == mevent) {
12202 found = TRUE;
12203 break;
12207 if (!found) {
12208 if (MQCount == MOUSE_QUEUE_LENGTH)
12209 return (FALSE);
12210 i = MQTail;
12211 MQTail = (MQTail + 1) % MOUSE_QUEUE_LENGTH;
12212 ++MQCount;
12217 * Record data.
12219 MQBuffer[i].event = mevent;
12220 MQBuffer[i].button = button;
12221 MQBuffer[i].nRow = nRow;
12222 MQBuffer[i].nColumn = nColumn;
12223 MQBuffer[i].keys = keys;
12224 MQBuffer[i].flags = flags;
12227 * Keep record of last mouse position.
12229 gMTEvent = MQBuffer[i];
12231 return (TRUE);
12238 /*---------------------------------------------------------------------------
12239 * BOOL MQGet ()
12241 * Description:
12242 * Return the next byte from the head of the queue. If there is
12243 * no byte available, returns 0, which is indistinquishable from
12244 * '\0'. So it is a good idea to call MQAvailable first.
12246 * Parameters:
12247 * none.
12249 /*--------------------------------------------------------------------------*/
12251 LOCAL BOOL
12252 MQGet (MEvent * pMouse)
12254 if (MQCount == 0)
12255 return (FALSE);
12258 *pMouse = MQBuffer[MQHead];
12259 MQHead = (MQHead + 1) % MOUSE_QUEUE_LENGTH;
12260 --MQCount;
12261 return (TRUE);
12269 DWORD
12270 ExplainSystemErr()
12272 DWORD status;
12273 void *lpMsgBuf = NULL;
12274 status = GetLastError();
12276 FormatMessage(
12277 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
12278 NULL,
12279 status,
12280 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
12281 (LPTSTR) &lpMsgBuf, 0, NULL);
12283 if(lpMsgBuf){
12284 char *msg;
12286 msg = lptstr_to_utf8(lpMsgBuf);
12287 if(msg){
12288 mswin_messagebox(msg, 1);
12289 fs_give((void **) &msg);
12292 LocalFree(lpMsgBuf);
12295 return(status);
12300 * Called by mswin to scroll text in window in response to the scrollbar.
12302 * Args: cmd - what type of scroll operation.
12303 * scroll_pos - parameter for operation.
12304 * used as position for SCROLL_TO operation.
12306 * Returns: TRUE - did the scroll operation.
12307 * FALSE - was not able to do the scroll operation.
12310 pico_scroll_callback (int cmd, long scroll_pos)
12312 switch (cmd) {
12313 case MSWIN_KEY_SCROLLUPLINE:
12314 scrollupline (0, 1);
12315 break;
12317 case MSWIN_KEY_SCROLLDOWNLINE:
12318 scrolldownline (0, 1);
12319 break;
12321 case MSWIN_KEY_SCROLLUPPAGE:
12322 backpage (0, 1);
12323 break;
12325 case MSWIN_KEY_SCROLLDOWNPAGE:
12326 forwpage (0, 1);
12327 break;
12329 case MSWIN_KEY_SCROLLTO:
12330 scrollto (0, 0);
12331 break;
12334 update ();
12335 return (TRUE);
12339 * sleep the given number of seconds
12342 sleep(int t)
12344 time_t out = (time_t)t + time((long *) 0);
12345 while(out > time((long *) 0))
12347 return(0);
12351 tcsucmp(LPTSTR o, LPTSTR r)
12353 return(o ? (r ? _tcsicmp(o, r) : 1) : (r ? -1 : 0));
12357 tcsruncmp(LPTSTR o, LPTSTR r, int n)
12359 return(o ? (r ? _tcsnicmp(o, r, n) : 1) : (r ? -1 : 0));
12363 strucmp(char *o, char *r)
12365 return(o ? (r ? stricmp(o, r) : 1) : (r ? -1 : 0));
12370 struncmp(char *o, char *r, int n)
12372 return(o ? (r ? strnicmp(o, r, n) : 1) : (r ? -1 : 0));
12377 * Returns screen width of len characters of lpText.
12378 * The width is in character cells. That is, an ascii "A" has
12379 * width 1 but a CJK character probably has width 2.
12381 unsigned
12382 scrwidth(LPTSTR lpText, int len)
12384 UCS ubuf[1000];
12385 unsigned w;
12386 int i, thislen, offset;
12388 offset = w = 0;
12390 while(len > 0){
12391 thislen = MIN(len, 1000);
12392 for(i = 0; i < thislen; i++)
12393 ubuf[i] = lpText[offset+i];
12395 w += ucs4_str_width_ptr_to_ptr(&ubuf[0], &ubuf[thislen]);
12397 offset += thislen;
12398 len -= thislen;
12401 return w;
12406 * Returns the index into pScreen given the row,col location
12407 * on the screen, taking into account characters with widths
12408 * other than 1 cell.
12410 long
12411 pscreen_offset_from_cord(int row, int col, PTTYINFO pTTYInfo)
12413 int offset_due_to_row, offset_due_to_col, width;
12416 * Each row starts at a specific offset into pScreen.
12418 offset_due_to_row = row * pTTYInfo->actNColumn;
12421 * Start with col (all chars single width) and go from there.
12422 * We need to find the offset that makes the string col wide.
12423 * Hopefully we won't ever get a rectangle that causes us to
12424 * draw half characters, but in case we do we need to err on the
12425 * side of too much width instead of not enough. It's a little
12426 * tricky because we want to include following zero-width
12427 * characters.
12428 * fewer characters it would be <= desired width, one more would
12429 * be greater than desired width, this one is >= desired width.
12432 /* first go to some offset where width is > col */
12433 offset_due_to_col = col;
12434 width = scrwidth(pTTYInfo->pScreen+offset_due_to_row, offset_due_to_col);
12435 while(width <= col && offset_due_to_col < pTTYInfo->actNColumn-1){
12436 offset_due_to_col++;
12437 width = scrwidth(pTTYInfo->pScreen+offset_due_to_row, offset_due_to_col);
12440 /* Now back up until width is no longer > col */
12441 while(width > col){
12442 offset_due_to_col--;
12443 width = scrwidth(pTTYInfo->pScreen+offset_due_to_row, offset_due_to_col);
12446 /* But, if we're now less than col, go forward one again. */
12447 if(width < col && offset_due_to_col < pTTYInfo->actNColumn-1)
12448 offset_due_to_col++;
12450 return(offset_due_to_row + offset_due_to_col);
12455 * Returns:
12456 * 1 if store pass prompt is set in the registry to on
12457 * 0 if set to off
12458 * -1 if not set to anything
12461 mswin_store_pass_prompt(void)
12464 * We shouldn't need to prompt anymore, but always return 1
12465 * just in case
12467 return(1);