1 /* The routines in this file provide extra emacs functions available
2    under the Microsoft Windows environment on an IBM-PC or compatible
3    computer. The following functions are supplied: cutregion,
4    clipregion, insertclip and helpengine.
5    Also implemented here is the support for scroll bars
6 
7    Must be compiled with Borland C++ 2.0 or MSC 6.0 or later versions
8 
9    It should not be compiled if the WINDOW_MSWIN symbol is not set */
10 
11 #include    "estruct.h"
12 #include    <stdio.h>
13 #include    "eproto.h"
14 #include    "edef.h"
15 #include    "elang.h"
16 
17 #include    "mswin.h"
18 
19 #include    "mswmenu.h"
20 /* to invoke the commands corresponding to scroll bar actions */
21 
22 #define MAXSCROLL 32767 /* maximum position for scrollbars */
23 
24 static HANDLE   hClipData = NULL;   /* used by insertclip and
25 				       ClipboardCleanup */
26 
27 /* CopyToClipboard: internal function to copy region to clipboard */
28 /* ===============                                                */
29 
CopyToClipboard(REGION * Region)30 static BOOL PASCAL CopyToClipboard (REGION *Region)
31 {
32     long    Size = 0L;
33     HANDLE  hData;
34 #if WINDOW_MSWIN32
35     char    *Data;
36 #else
37     char huge *Data;
38 #endif
39     BOOL    Result = TRUE;
40     register LINE *lp;
41     register int Offset;
42     register int lcnt;       /* used to reduce longop() overhead */
43 
44     /*-figure out the size of the clipboard data (end of lines have to
45        be turned into CR-LF) */
46     Size = Region->r_size;
47     if (curwp->w_dotp != curwp->w_markp[0]) {   /* multiple lines */
48         lp = Region->r_linep;
49         do {
50             ++Size;
51 	    lp = lforw(lp);
52 	} while ((lp != curwp->w_dotp) && (lp != curwp->w_markp[0]));
53     }
54     if (Size == 0L) return TRUE;
55 
56     /*-copy the buffer data into a block of global memory */
57     if (hData = GlobalAlloc (GMEM_MOVEABLE, Size + 1)) {
58         if (!(Data = GlobalLock (hData))) goto NoClipboardMemory;
59 	lp = Region->r_linep;
60 	Offset = Region->r_offset;
61 	lcnt = 0;
62 	while (Size-- > 0) {
63 	    if (Offset != lused(lp)) {    /* middle of line */
64 	        *Data++ = lgetc(lp, Offset);
65 	        ++Offset;
66 	    }
67 	    else {                          /* end of line */
68 	        *Data++ = '\r';
69 	        *Data++ = '\n';
70 	        Size--;
71 	        lp = lforw(lp);
72 	        Offset = 0;
73 	        if (--lcnt < 0) {
74 		    longop (TRUE);
75 		    lcnt = 10;  /* reduce longop calls overhead */
76 		}
77 	    }
78 	}
79 	*Data = '\0';
80 	/*-pass the text to the clipboard */
81 	GlobalUnlock (hData);
82 	if (OpenClipboard (hFrameWnd)) {
83 	    if (EmptyClipboard ()) {
84 	        SetClipboardData (CF_TEXT, hData);
85 	    }
86 	    else Result = FALSE;
87 	    CloseClipboard ();
88 	}
89 	else Result = FALSE;
90 	if (Result == FALSE) GlobalFree (hData);
91     }
92     else {
93 NoClipboardMemory:
94 	mlabort (TEXT94);   /* out of memory */
95         Result = FALSE;
96     }
97     return Result;
98 } /* CopyToClipboard */
99 
100 /* cutregion:   move the current region to the clipboard */
101 /* =========                                             */
102 
cutregion(int f,int n)103 int PASCAL cutregion (int f, int n)
104 {
105     REGION  Region;
106     int     Result;
107 
108     /*-don't allow command if read-only mode */
109     if (curbp->b_mode & MDVIEW) return rdonly();
110 
111     if ((Result = getregion (&Region)) != TRUE) return Result;
112 
113     if ((Result = CopyToClipboard (&Region)) != TRUE) return Result;
114     curwp->w_dotp = Region.r_linep;
115     curwp->w_doto = Region.r_offset;
116     return ldelete (Region.r_size, FALSE);
117 } /* cutregion */
118 
119 /* clipregion:  copy the current region into the clipboard */
120 /* ==========                                              */
121 
clipregion(int f,int n)122 int PASCAL clipregion (int f, int n)
123 {
124     REGION  Region;
125     int     Result;
126 
127     if ((Result = getregion (&Region)) != TRUE) return Result;
128 
129     return CopyToClipboard (&Region);
130 } /* clipregion */
131 
132 /* insertclip:  insert the clipboard contents at dot */
133 /* ==========                                        */
134 
insertclip(int f,int n)135 int PASCAL insertclip (int f, int n)
136 {
137     BOOL    Result = TRUE;
138     char    *Text, *TextHead;
139     short int curoff;
140     LINE    *curline;
141 
142     /*-don't allow command if read-only mode */
143     if (curbp->b_mode & MDVIEW) return rdonly();
144 
145     if (OpenClipboard (hFrameWnd)) {
146 	if ((hClipData = GetClipboardData (CF_TEXT)) != NULL) {
147 	    /* Save the local pointers to hold global "." */
148 	    if (yankflag) {
149 		/* Find the *previous* line, since the line we are on
150 		   may disappear due to re-allocation.  This works even
151 		   if we are on the first line of the file. */
152 		curline = lback(curwp->w_dotp);
153 		curoff = curwp->w_doto;
154 	    }
155 	    if ((TextHead = GlobalLock (hClipData)) != NULL) {
156 		while (n--) {
157 		    Text = TextHead;
158 		    while (*Text != '\0') {
159 			if (*Text == '\n') {
160 			    if (lnewline () == FALSE) {
161 				Result = FALSE;
162 				goto bail_out;
163 			    }
164 			}
165 			else {
166 			    if (*Text != '\r') if (linsert (1, *Text) == FALSE) {
167 				Result = FALSE;
168 				goto bail_out;
169 			    }
170 			}
171 			++Text;
172 		    }
173 		}
174 bail_out:
175                 GlobalUnlock (hClipData);
176                 hClipData = NULL;   /* for ClipboardCleanup */
177                 /* If requested, set global "." back to the beginning of
178 		   the yanked text. */
179 		if (yankflag) {
180 		    curwp->w_dotp = lforw(curline);
181 		    curwp->w_doto = curoff;
182 		}
183 	    }
184 	}
185 	else Result = FALSE;
186 	CloseClipboard ();
187     }
188     else Result = FALSE;
189     return Result;
190 } /* insertclip */
191 
192 /* ClipboardCleanup:    to be called if the user aborts during a longop */
193 /* ================                                                     */
194 
ClipboardCleanup(void)195 void FAR PASCAL ClipboardCleanup (void)
196 {
197     if (hClipData) {
198         GlobalUnlock (hClipData);
199         CloseClipboard ();
200     }
201 } /* ClipboardCleanup */
202 
203 /* helpengine:  invoke the MS-Windows help engine */
204 /* ==========                                     */
205 
helpengine(int f,int n)206 int PASCAL helpengine (int f, int n)
207 {
208     char    OldHelpFile [NFILEN];
209     char    HelpKey [NLINE];
210     BOOL    Result;
211 
212     strcpy (OldHelpFile, HelpEngineFile);
213     SetWorkingDir ();
214     if ((Result = FILENAMEREPLY (TEXT307, HelpEngineFile, NFILEN)) != TRUE) return Result;
215         /* "Help file: " */
216     if (HelpEngineFile[0] == '\0') {
217         strcpy (HelpEngineFile, OldHelpFile);
218         return FALSE;
219     }
220     else {
221         Result = mlreply (TEXT308, HelpKey, NLINE);
222 	if ((Result != TRUE) && (Result != FALSE)) return Result;
223 	    /* "Help key: " */
224 	if (HelpKey[0] == '\0') {
225 	    WinHelp (hFrameWnd, HelpEngineFile, HELP_INDEX, NULL);
226 	}
227 	else {
228 	    WinHelp (hFrameWnd, HelpEngineFile, HELP_KEY,
229                      (DWORD)(LPSTR)&HelpKey[0]);
230 	}
231     }
232     return TRUE;
233 } /* helpengine */
234 
235 /* minimizescreen:  turn the current screen into an icon */
236 /* ==============                                        */
237 
minimizescreen(int f,int n)238 PASCAL  minimizescreen (int f, int n)
239 {
240     BOOL    nq;
241 
242     nq = notquiescent;
243     notquiescent = 0;
244     ShowWindow (first_screen->s_drvhandle, SW_MINIMIZE);
245     notquiescent = nq;
246     return TRUE;
247 } /* minimizescreen */
248 
249 /* ForceMessage:    do a SendMessage, forcing quiescent mode */
250 /* ============                                              */
251 
ForceMessage(HWND hWnd,UINT wMsg,UINT wParam,LONG lParam)252 static PASCAL ForceMessage (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
253 {
254     BOOL    nq;
255 
256     nq = notquiescent;
257     notquiescent = 0;
258     SendMessage (hWnd, wMsg, wParam, lParam);
259     notquiescent = nq;
260 } /* ForceMessage */
261 
262 /* maximizescreen:  maximize the current screen */
263 /* ==============                               */
264 
maximizescreen(int f,int n)265 PASCAL  maximizescreen (int f, int n)
266 {
267     ForceMessage (hMDIClientWnd, WM_MDIMAXIMIZE,
268                   (UINT)first_screen->s_drvhandle, 0L);
269     return TRUE;
270 } /* maximizescreen */
271 
272 /* restorescreen:   restore the current screen from maximized/minimized state */
273 /* =============                                                              */
274 
restorescreen(int f,int n)275 PASCAL  restorescreen (int f, int n)
276 {
277     ForceMessage (hMDIClientWnd, WM_MDIRESTORE,
278                   (UINT)first_screen->s_drvhandle, 0L);
279     return TRUE;
280 } /* restorescreen */
281 
282 /* tilescreens: tile the non-iconized screens */
283 /* ===========                                */
284 
tilescreens(int f,int n)285 PASCAL  tilescreens (int f, int n)
286 
287 /* without a numeric argument, tile horizontally. With a numeric argument
288    of 1, tile vertically */
289 {
290     if (f && (n == 1)) {
291         ForceMessage (hMDIClientWnd, WM_MDITILE, MDITILE_HORIZONTAL, 0L);
292     }
293     else ForceMessage (hMDIClientWnd, WM_MDITILE, MDITILE_VERTICAL, 0L);
294     return TRUE;
295 } /* tilescreens */
296 
297 /* cascadescreens:  position the non-iconized screens in cascade */
298 /* ==============                                                */
299 
cascadescreens(int f,int n)300 PASCAL  cascadescreens (int f, int n)
301 {
302     ForceMessage (hMDIClientWnd, WM_MDICASCADE, 0, 0L);
303     return TRUE;
304 } /* cascadescreens */
305 
306 /* ScrollMessage:   handle WM_HSCROLL and WM_VSCROLL */
307 /* =============                                     */
ScrollMessage(HWND hWnd,UINT wMsg,WORD ScrlCode,int Pos)308 void FAR PASCAL ScrollMessage (HWND hWnd, UINT wMsg, WORD ScrlCode, int Pos)
309 
310 {
311     int     Delta;
312 
313     if (notquiescent) return;
314 
315     if (wMsg == WM_VSCROLL) {
316         switch (ScrlCode) {
317             case SB_LINEUP:
318                 mvupwind (FALSE, 1);
319                 break;
320             case SB_LINEDOWN:
321                 mvdnwind (FALSE, 1);
322                 break;
323             case SB_PAGEUP:
324                 backpage (FALSE, 1);
325                 break;
326             case SB_PAGEDOWN:
327                 forwpage (FALSE, 1);
328                 break;
329             case SB_THUMBTRACK:
330             case SB_THUMBPOSITION:
331                 if (Win31API) {
332                     if (ScrlCode == SB_THUMBPOSITION) return;
333                 }
334                 else {
335                     if (ScrlCode == SB_THUMBTRACK) return;
336                     /* there is something wrong with thumb tracking in
337                        Windows 3.0 */
338                 }
339                 Delta = Pos - GetScrollPos (hWnd, SB_VERT);
340                 if (Delta) mvdnwind (TRUE, Delta);
341                 break;
342             default:
343                 return;
344         }
345         curwp->w_flag |= WFMODE;
346     }
347     else {
348         switch (ScrlCode) {
349             case SB_LINEUP:
350                 Delta = -1;
351                 break;
352             case SB_LINEDOWN:
353                 Delta = 1;
354                 break;
355             case SB_PAGEUP:
356                 Delta = -term.t_ncol;
357                 break;
358             case SB_PAGEDOWN:
359                 Delta = term.t_ncol;
360                 break;
361             case SB_THUMBTRACK:
362                 Delta = Pos - GetScrollPos (hWnd, SB_HORZ);
363                 break;
364             default:
365                 return;
366         }
367         curwp->w_fcol += Delta;
368         if (curwp->w_fcol < 0) curwp->w_fcol = 0;
369         if (curwp->w_doto < curwp->w_fcol) {
370             /* reframe dot if it was left past the left of the screen */
371             curwp->w_doto = min(curwp->w_fcol,lused(curwp->w_dotp));
372         }
373         if (curwp->w_doto > (curwp->w_fcol + term.t_ncol - 2)) {
374             /* reframe dot if it was left past the right of the screen */
375             curwp->w_doto = curwp->w_fcol + term.t_ncol - 2;
376 	}
377         curwp->w_flag |= WFMODE | WFHARD;
378     }
379     if (in_check()) GenerateMenuSeq (IDM_NULLPROC);
380         /* this ensures we go through the editloop(), updating the
381            modeline display and running the cmdhook, among other things */
382     ShowEmacsCaret (FALSE);
383     update (TRUE);
384     ShowEmacsCaret (TRUE);
385 } /* ScrollMessage */
386 
387 /* ScrollBars:      shows/hides, enables/disables scroll bars for all screens */
388 /* ==========                                                                 */
ScrollBars(void)389 void FAR PASCAL ScrollBars (void)
390 
391 {
392     static int VScroll = TRUE;
393     static int HScroll = TRUE;
394     static int Enabled = TRUE;
395     int     Quiescence;
396     SCREEN  *sp;
397 
398     if (vscrollbar) vscrollbar = TRUE;  /* normalize... */
399     if (hscrollbar) hscrollbar = TRUE;
400     Quiescence = (notquiescent == 0);
401 
402     for (sp = first_screen; sp != (SCREEN*)NULL; sp = sp->s_next_screen) {
403         if (vscrollbar != VScroll) {
404             ShowScrollBar ((HWND)sp->s_drvhandle, SB_VERT, vscrollbar);
405         }
406         if (hscrollbar != HScroll) {
407             ShowScrollBar ((HWND)sp->s_drvhandle, SB_HORZ, hscrollbar);
408         }
409 
410         if ((Enabled != Quiescence) && Win31API && !TakingANap) {
411             /* note: no disabling of scroll bars during naps (i.e. fence
412                matching), to avoid annoying blinking */
413             EnableScrollBar ((HWND)sp->s_drvhandle, SB_BOTH,
414                              Quiescence ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
415 	}
416     }
417 
418     if ((Enabled != Quiescence) && Win31API && !TakingANap) {
419         Enabled = Quiescence;
420     }
421     VScroll = vscrollbar;
422     HScroll = hscrollbar;
423 } /* ScrollBars */
424 
425 /* updscrollbars:      updates the scroll bars for a screen */
426 /* =============                                            */
updscrollbars(SCREEN * sp,char w_flag)427 PASCAL  updscrollbars (SCREEN *sp, char w_flag)
428 
429 /* the w_flag is used to determine what needs updating: if the WFHARD
430    bit is set, both scroll bars need an update. If the WFMOVE bit
431    is set, the horizontal scroll bar needs an update */
432 /* this function assumes s_cur_window matches curwp for the first_screen */
433 {
434     int ScrollMax, ScrollMin, ScrollPos;
435 
436     if (vscrollbar && (w_flag & WFHARD)) {
437         int    lastline;
438         int     topline;
439 
440         {   /*-figure-out where we are at vertically */
441             register LINE   *lp;
442             register LINE   *linep; /* header (= last) line of buffer */
443             LINE    *toplp;         /* top line of window */
444 
445             linep = sp->s_cur_window->w_bufp->b_linep;
446             toplp = sp->s_cur_window->w_linep;
447             topline = lastline = 0;
448             lp = linep;
449             do {
450                 lp = lforw(lp);
451                 lastline++;
452                 if (lp == toplp) topline = lastline;
453             } while (lp != linep);
454         }
455         lastline += 1 - sp->s_cur_window->w_ntrows;
456         if (lastline <= 1) lastline = 2;    /* to avoid scrollbar hiding */
457         lastline = min(lastline, MAXSCROLL);
458         topline = min(topline, MAXSCROLL);
459         GetScrollRange ((HWND)sp->s_drvhandle, SB_VERT,
460                         &ScrollMin, &ScrollMax);
461         if ((ScrollMax != lastline) || (ScrollMin != 1)) {
462             SetScrollRange ((HWND)sp->s_drvhandle, SB_VERT, 1,
463                             lastline, FALSE);
464             ScrollPos = -1; /* makes sure the scroll display is updated */
465         }
466         else ScrollPos = GetScrollPos ((HWND)sp->s_drvhandle, SB_VERT);
467         if (topline != ScrollPos) {
468             SetScrollPos ((HWND)sp->s_drvhandle, SB_VERT,
469                           topline, TRUE);
470         }
471     }
472     if (hscrollbar && (w_flag & (WFMOVE | WFHARD))) {
473         /*-figure-out where we stand horizontally */
474         int     row;
475         LINE    *lp;
476         EWINDOW  *wp = sp->s_cur_window;
477         int     maxlength = 0;
478 
479         lp = wp->w_linep;
480         for (row = 0; (row < wp->w_ntrows) && (lp != wp->w_bufp->b_linep);
481              row++) {
482             maxlength = max(maxlength, lused(lp));
483             lp = lforw(lp);
484         }
485         if (maxlength <= 0) maxlength = 1;
486         maxlength = min(maxlength, MAXSCROLL);
487         row = min(wp->w_fcol, MAXSCROLL);
488         GetScrollRange ((HWND)sp->s_drvhandle, SB_HORZ,
489                         &ScrollMin, &ScrollMax);
490         if ((ScrollMax != maxlength) || (ScrollMin != 0)) {
491             SetScrollRange ((HWND)sp->s_drvhandle, SB_HORZ, 0,
492                             maxlength, FALSE);
493             ScrollPos = -1; /* makes sure the scroll display is updated */
494         }
495         else ScrollPos = GetScrollPos ((HWND)sp->s_drvhandle, SB_HORZ);
496         if (row != ScrollPos) {
497             SetScrollPos ((HWND)sp->s_drvhandle, SB_HORZ,
498                           row, TRUE);
499         }
500     }
501 } /* updscrollbars */
502