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