Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtTerm / TermPrim / TermPrimCursor.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 #ifndef lint
24 #ifdef  VERBOSE_REV_INFO
25 static char rcs_id[] = "$XConsortium: TermPrimCursor.c /main/1 1996/04/21 19:17:13 drk $";
26 #endif  /* VERBOSE_REV_INFO */
27 #endif  /* lint */
28
29 /*                                                                      *
30  * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company               *
31  * (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
32  * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.                *
33  * (c) Copyright 1993, 1994, 1996 Novell, Inc.                          *
34  * (c) Copyright 1996 Digital Equipment Corporation.                    *
35  * (c) Copyright 1996 FUJITSU LIMITED.                                  *
36  * (c) Copyright 1996 Hitachi.                                          *
37  */
38
39 #include "TermHeader.h"
40 #include "TermPrimDebug.h"
41 #include "TermPrimP.h"
42 #include "TermPrimData.h"
43 #include "TermPrimLineDraw.h"
44 #include "TermPrimBufferP.h"
45
46 static void cursorToggle(Widget w);
47
48 /*ARGSUSED*/
49 static void
50 timeoutCallback(XtPointer client_data, XtIntervalId *id)
51 {
52     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
53     struct termData *tpd = tw->term.tpd;
54     (void) cursorToggle((Widget) tw);
55
56     /* add a timeout... */
57     if (tw->term.blinkRate > 0) {
58         tpd->cursorTimeoutId =
59                 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) tw),
60                 tw->term.blinkRate,
61                 (XtTimerCallbackProc) timeoutCallback, (XtPointer) tw);
62     } else {
63         tpd->cursorTimeoutId = (XtIntervalId) 0;
64     }
65 }
66
67 void
68 _DtTermPrimCursorChangeFocus(Widget w)
69 {
70     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
71     struct termData *tpd = tw->term.tpd;
72     XPoint point;
73
74     if (tw->term.hasFocus) {
75         /* if the input method already didn't have focus or the cursor
76          * position has changed, then set the input method focus and
77          * spot location...
78          */
79         if ((!tpd->IMHasFocus) ||
80                 (tpd->IMCursorColumn != tpd->cursorColumn) ||
81                 (tpd->IMCursorRow != tpd->cursorRow)) {
82             tpd->IMHasFocus = True;
83             tpd->IMCursorColumn = tpd->cursorColumn;
84             tpd->IMCursorRow = tpd->cursorRow;
85
86             point.x = tpd->IMCursorColumn * tpd->cellWidth + tpd->offsetX;
87             point.y = tpd->IMCursorRow * tpd->cellHeight + tpd->offsetY +
88                     tpd->ascent;
89             DebugF('F', 1, fprintf(stderr,
90                     "%s() %s calling %s\n",
91                     "_DtTermPrimCursorChangeFocus",
92                     "hasFocus",
93                     "XmImVaSetFocusValues()"));
94             (void) XmImVaSetFocusValues(w,
95                     XmNspotLocation, &point,
96                     NULL);
97         }
98
99         /* we want to blink now... */
100         if (tpd->cursorVisible && (!tpd->cursorTimeoutId) &&
101                 (tw->term.blinkRate > 0) &&
102                 (tpd->cursorState != CURSORoff)) {
103             Debug('F', fprintf(stderr,
104                     ">>we got focus, turning off cursor...\n"));
105             (void) cursorToggle(w);
106
107             /* add a timeout... */
108             Debug('F', fprintf(stderr, ">>adding a timeout...\n"));
109             tpd->cursorTimeoutId =
110                     XtAppAddTimeOut(
111                     XtWidgetToApplicationContext(w),
112                     tw->term.blinkRate, timeoutCallback, (XtPointer) w);
113         }
114     } else {
115         if (tpd->IMHasFocus) {
116             tpd->IMHasFocus = False;
117             DebugF('F', 1, fprintf(stderr,
118                     "%s() %s calling %s\n",
119                     "_DtTermPrimCursorChangeFocus",
120                     "!hasFocus",
121                     "XmImUnsetFocus()"));
122             /* remove input method focus... */
123             (void) XmImUnsetFocus(w);
124         }
125
126         /* we want to stop blinking now... */
127         if (tpd->cursorTimeoutId && (tpd->cursorState != CURSORoff)) {
128             Debug('F', fprintf(stderr, ">>we lost focus...\n"));
129             if (CURSORon == tpd->cursorState) {
130                 /* we need to make the cursor visible... */
131                 Debug('F', fprintf(stderr,
132                         ">>turning on the cursor...\n"));
133                 (void) cursorToggle(w);
134             }
135             /* we need to kill the timeout... */
136             Debug('F', fprintf(stderr, ">>removing the timeout...\n"));
137             (void) XtRemoveTimeOut(tpd->cursorTimeoutId);
138             tpd->cursorTimeoutId = (XtIntervalId) 0;
139         } else {
140             if (tw->term.blinkRate > 0) {
141                 Debug('F', fprintf(stderr,
142                         ">>we lost focus, but cursor is not on and blinking...\n"));
143             }
144         }
145     }
146 }
147
148 static void
149 cursorToggle(Widget w)
150 {
151     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
152     struct termData *tpd = tw->term.tpd;
153     int y;
154     int height;
155     int cursorRow;
156
157     /* if the cursor is not visible or is off... */
158     if (!tpd->cursorVisible || (CURSORoff == tpd->cursorState)) {
159         /* do nothing... */
160         return;
161     }
162
163     cursorRow = tpd->cursorRow;
164     if (tpd->useHistoryBuffer) {
165         /* since topRow is used for history scrolling, move down by the
166          * (negative) number of rows in topRow...
167          */
168         cursorRow -= tpd->topRow;
169     }
170
171     if (cursorRow < tw->term.rows) {
172         if (DtTERM_CHAR_CURSOR_BOX == tw->term.charCursorStyle) {
173             /* draw a box... */
174             y = cursorRow * tpd->cellHeight + tpd->offsetY;
175             height = tpd->cellHeight;
176         } else {
177             /* draw a line... */
178             y = cursorRow * tpd->cellHeight + tpd->offsetY +
179                     tpd->ascent + 1;
180             height = 2;
181         }
182
183         (void) XFillRectangle(XtDisplay(w),
184                                         /* Display                      */
185                 XtWindow(w),            /* Window                       */
186                 tpd->cursorGC.gc,       /* GC                           */
187                 ((tpd->cursorColumn >= tw->term.columns) ?
188                 tw->term.columns - 1 :
189                 tpd->cursorColumn) * tpd->cellWidth + tpd->offsetX,
190                                         /* x                            */
191                 y,                      /* y                            */
192                 tpd->cellWidth,         /* width                        */
193                 height);                /* height                       */
194     }
195
196     /* toggle the state flag... */
197     tpd->cursorState = (tpd->cursorState == CURSORon) ? CURSORblink : CURSORon;
198
199     return;
200 }
201
202 void
203 _DtTermPrimCursorOn(Widget w)
204 {
205     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
206     struct termData *tpd = tw->term.tpd;
207     XPoint point;
208     static Boolean alreadyActive = False;
209     short chunkWidth;
210     enhValues enhancements;
211     unsigned long valueMask = 0L;
212     XGCValues values;
213     TermEnhInfoRec enhInfo;
214     int cursorRow;
215
216     /* if we are being called cyclically (by _DtTermPrimScrollWait ->
217      * _DtTermPrimExposeText -> _DtTermPrimCursorOn), just return...
218      */
219     _DtTermProcessLock();
220     if (alreadyActive) {
221         /*DKS!!! vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
222         fprintf(stderr, "tell Dave _DtTermPrimCursorOn has alreadyActive == True\n");
223         /*DKS!!! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
224         _DtTermProcessUnlock();
225         return;
226     }
227
228     /* this is where we will actually perform a pending scroll and
229      * text refresh...
230      */
231     if (tw->term.jumpScroll && tpd->scroll.jump.scrolled) {
232         /* make sure we don't end up in an infinite loop... */
233         alreadyActive = True;
234         Debug('t', fprintf(stderr,
235                 ">>_DtTermPrimCursorOn() calling _DtTermPrimScrollWait()\n"));
236         (void) _DtTermPrimScrollWait(w);
237         alreadyActive = False;
238     }
239     _DtTermProcessUnlock();
240
241 #ifdef  DISOWN_SELECTION_ON_CURSOR_ON_OR_OFF 
242     if ( _DtTermPrimSelectIsAboveSelection(w,tpd->cursorRow,
243             tpd->cursorColumn)) {
244         _DtTermPrimSelectDisown(w) ;
245     }
246 #endif  /* DISOWN_SELECTION_ON_CURSOR_ON_OR_OFF */
247
248     /* update the input method spot location...
249      */
250     if ((tpd->IMCursorColumn != tpd->cursorColumn) ||
251             (tpd->IMCursorRow != tpd->cursorRow)) {
252         tpd->IMCursorColumn = tpd->cursorColumn;
253         tpd->IMCursorRow = tpd->cursorRow;
254         point.x = tpd->cursorColumn * tpd->cellWidth + tpd->offsetX;
255         point.y = tpd->cursorRow * tpd->cellHeight + tpd->offsetY + tpd->ascent;
256         DebugF('F', 1, fprintf(stderr,
257                 "%s() %s calling %s\n",
258                 "_DtTermPrimCursorOn",
259                 "dont care",
260                 "XmImVaSetValues()"));
261         (void) XmImVaSetValues(w,
262                 XmNspotLocation, &point,
263                 NULL);
264     }
265 #ifdef  NOT_NEEDED
266     if (!tw->term.hasFocus) {
267         (void) fprintf(stderr,
268                 "%s() %s calling %s\n",
269                 "_DtTermPrimCursorOn",
270                 "!hasFocus",
271                 "XmImUnsetFocus()");
272         (void) XmImUnsetFocus(w);
273     }
274 #endif  /* NOT_NEEDED */
275
276     /* update the scrollbar and position indicator... */
277     (void) _DtTermPrimCursorUpdate(w);
278
279     /* if the cursor is not visible, we are done now... */
280     if (!tpd->cursorVisible) {
281         return;
282     }
283
284     /* set up the GC... */
285     if (!tpd->cursorGC.gc) {
286         tpd->cursorGC.foreground =
287                 tw->primitive.foreground ^ tw->core.background_pixel;
288         values.foreground = tpd->cursorGC.foreground;
289         values.function = GXxor;
290         tpd->cursorGC.gc = XCreateGC(XtDisplay(w), XtWindow(w),
291                 GCForeground | GCFunction, &values);
292     }
293
294     /* update the cursor's foreground and background...
295      */
296     /* if we are past the lastUsedRow, or the column > width, use color
297      * pair 0...
298      */
299
300     /* reasonable defaults... */
301     enhInfo.fg = tw->primitive.foreground;
302     enhInfo.bg = tw->core.background_pixel;
303     if (!((tpd->lastUsedRow <= tpd->topRow + tpd->cursorRow) ||
304             (_DtTermPrimBufferGetLineWidth(tpd->termBuffer,
305                     tpd->topRow + tpd->cursorRow) <= MIN(tpd->cursorColumn,
306                     tw->term.columns - 1)))) {
307         /* get the current enhancement to determine the color pair to use...
308          */
309         (void) _DtTermPrimBufferGetEnhancement(tpd->termBuffer,
310                                                 /* TermBuffer           */
311                     tpd->topRow + tpd->cursorRow,
312                                                 /* row                  */
313                     MIN(tpd->cursorColumn, tw->term.columns - 1),
314                                                 /* col                  */
315                     &enhancements,              /* enhancements         */
316                     &chunkWidth,                /* width                */
317                     countNew);                  /* countWhich           */
318         /* set our font and color from the enhancements... */
319         if (ENH_PROC(tpd->termBuffer)) {
320             (void) (*(ENH_PROC(tpd->termBuffer)))(w, enhancements, &enhInfo);
321         }
322     }
323
324     /* set the GC... */
325     if (tpd->cursorGC.foreground != enhInfo.fg ^ enhInfo.bg) {
326         tpd->cursorGC.foreground = enhInfo.fg ^ enhInfo.bg;
327         values.foreground = enhInfo.fg ^ enhInfo.bg;
328         valueMask |= GCForeground;
329     }
330     if (valueMask) {
331         (void) XChangeGC(XtDisplay(w), tpd->cursorGC.gc, valueMask, &values);
332     }
333
334     if (tpd->cursorState != CURSORoff) {
335         return;
336     }
337
338     tpd->cursorState = CURSORon;
339     (void) cursorToggle(w);
340
341     if (tw->term.hasFocus) {
342         /* add a timeout... */
343         if (tw->term.blinkRate > 0) {
344             tpd->cursorTimeoutId =
345                     XtAppAddTimeOut(XtWidgetToApplicationContext(w),
346                     tw->term.blinkRate, (XtTimerCallbackProc) timeoutCallback,
347                     (XtPointer) w);
348         }
349     }
350
351 }
352
353 void
354 _DtTermPrimCursorUpdate(Widget w)
355 {
356     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
357     struct termData *tpd = tw->term.tpd;
358     Arg arglist[10];
359     int i;
360     short value;
361     Boolean newMaximum = False;
362     Boolean newValue = False;
363
364     /* update the scrollbar... */
365     if (tw->term.verticalScrollBar) {
366         i = 0;
367         if (tpd->useHistoryBuffer) {
368 #define NO_SCROLL_REGION_HISTORY_SCROLL
369 #ifdef  NO_SCROLL_REGION_HISTORY_SCROLL 
370             value = tw->term.rows;
371             if ((tpd->scrollLockTopRow <= 0) &&
372                     (tpd->scrollLockBottomRow >= (tw->term.rows - 1))) {
373                 value += tpd->lastUsedHistoryRow;
374             }
375 #else   /* NO_SCROLL_REGION_HISTORY_SCROLL */
376             value = tw->term.rows + tpd->lastUsedHistoryRow;
377 #endif  /* NO_SCROLL_REGION_HISTORY_SCROLL */
378         } else {
379             value = tpd->lastUsedRow +
380                     (tpd->useHistoryBuffer ? tpd->lastUsedHistoryRow : 0) -
381                     tpd->scrollLockTopRow -
382                     (tw->term.rows - 1 - tpd->scrollLockBottomRow);
383
384             /* add in any non-exisstent rows below the last used row...
385              */
386             if (tpd->allowScrollBelowBuffer) {
387                 /* add in a full screen (less one line and protected areas)
388                  * below the last used row...
389                  */
390                 value += tw->term.rows - 1 -
391                         tpd->scrollLockTopRow -
392                         (tw->term.rows - 1 - tpd->scrollLockBottomRow);
393             }
394         }
395                     
396         if (tw->term.verticalScrollBarMaximum != value) {
397             /* need to set maximum ... */
398             tw->term.verticalScrollBarMaximum = value;
399             newMaximum = True;
400         }
401
402         if (tpd->useHistoryBuffer) {
403             value = tw->term.rows;
404         } else {
405             value = tw->term.rows -
406                     tpd->scrollLockTopRow -
407                     (tw->term.rows - 1 - tpd->scrollLockBottomRow);
408         }
409         if (tw->term.verticalScrollBarSliderSize != value) {
410             /* need to set sliderSize ... */
411             tw->term.verticalScrollBarSliderSize = value;
412             (void) XtSetArg(arglist[i], XmNsliderSize,
413                     tw->term.verticalScrollBarSliderSize); i++;
414             newValue = True;
415         }
416
417         /* verticalScrollBarPageIncrement = verticalScrollBarSliderSize... */
418         if (tw->term.verticalScrollBarPageIncrement != value) {
419             /* need to set pageIncrement ... */
420             tw->term.verticalScrollBarPageIncrement = value;
421             (void) XtSetArg(arglist[i], XmNpageIncrement,
422                     tw->term.verticalScrollBarPageIncrement); i++;
423             newValue = True;
424         }
425
426 #ifdef  NO_SCROLL_REGION_HISTORY_SCROLL 
427         value = tpd->topRow;
428         if (tpd->useHistoryBuffer && (tpd->scrollLockTopRow <= 0) &&
429                     (tpd->scrollLockBottomRow >= (tw->term.rows - 1))) {
430             value += tpd->lastUsedHistoryRow;
431         }
432 #else   /* NO_SCROLL_REGION_HISTORY_SCROLL */
433         value = tpd->topRow + tpd->lastUsedHistoryRow;
434 #endif  /* NO_SCROLL_REGION_HISTORY_SCROLL */
435
436         if (tw->term.verticalScrollBarValue != value) {
437             /* need to set value... */
438             tw->term.verticalScrollBarValue = value;
439             (void) XtSetArg(arglist[i], XmNvalue,
440                     tw->term.verticalScrollBarValue); i++;
441             newValue = True;
442         }
443
444         /* check and see if value > max - size.  If it is, adjust
445          * maximum...
446          */
447         if (tw->term.verticalScrollBarValue >
448                 tw->term.verticalScrollBarMaximum -
449                 tw->term.verticalScrollBarSliderSize) {
450             tw->term.verticalScrollBarMaximum =
451                     tw->term.verticalScrollBarValue +
452                     tw->term.verticalScrollBarSliderSize;
453             newMaximum = True;
454         }
455
456         Debug('b', if (newMaximum || newValue) {
457                 fprintf(stderr, ">>_DtTermPrimCursorUpdate: sb size=%d  min=%d  max=%d  value=%d  pginc=%d\n", 
458                 tw->term.verticalScrollBarSliderSize,
459                 0,
460                 tw->term.verticalScrollBarMaximum,
461                 tw->term.verticalScrollBarValue,
462                 tw->term.verticalScrollBarPageIncrement);
463         });
464
465         if (newMaximum) {
466             (void) XtSetArg(arglist[i], XmNmaximum,
467                     tw->term.verticalScrollBarMaximum); i++;
468             (void) XtSetValues(tw->term.verticalScrollBar, arglist, i);
469         } else if (newValue) {
470             /* only need to worry about setting value, slidersize, and
471              * page increment...
472              */
473             (void) XmScrollBarSetValues(tw->term.verticalScrollBar,
474                 tw->term.verticalScrollBarValue,
475                                         /* value                        */
476                 tw->term.verticalScrollBarSliderSize,
477                                         /* slider_size                  */
478                 1,                      /* increment                    */
479                 tw->term.verticalScrollBarPageIncrement,
480                                         /* page_increment               */
481                 False);                 /* notify                       */
482         }
483     }
484
485     /* invoke any cursor motion callbacks... */
486     if (tw->term.statusChangeCallback) {
487         _DtTermPrimInvokeStatusChangeCallback(w);
488     }
489 }
490
491 void
492 _DtTermPrimCursorOff(Widget w)
493 {
494     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
495     struct termData *tpd = tw->term.tpd;
496
497     if (CURSORoff == tpd->cursorState) {
498         return;
499     }
500
501     if (CURSORblink == tpd->cursorState) {
502         /* we need to restore the text... */
503         (void) cursorToggle(w);
504     }
505
506     /* reset the state flag... */
507     tpd->cursorState = CURSORoff;
508
509     /* turn off the timer... */
510     if (tpd->cursorTimeoutId) {
511         XtRemoveTimeOut(tpd->cursorTimeoutId);
512     }
513     tpd->cursorTimeoutId = (XtIntervalId) 0;
514
515 #ifdef  DISOWN_SELECTION_ON_CURSOR_ON_OR_OFF 
516     if ( _DtTermPrimSelectIsAboveSelection(w,tpd->cursorRow,
517                             tpd->cursorColumn)) {
518        _DtTermPrimSelectDisown(w) ;
519      }
520 #endif  /* DISOWN_SELECTION_ON_CURSOR_ON_OR_OFF */
521 }
522
523 /* 
524 ** _DtTermPrimCursorMove
525 ** 
526 ** Move the cursor to the specified location, scrolling the screen
527 ** as necessary.
528 ** 
529 ** NOTES:
530 **    If the new cursor position is exceeds the line width, the line
531 **    is padded with spaces up to (but not including) the new cursor
532 **    position (just adjust the line width since the line is already
533 **    filled with spaces).
534 **    if (cursorColumn == width)
535 **        then the cursor is at the end of the line
536 **      
537 **    if (cursorColumn > width)  
538 **        then the cursor is past the end of the line,
539 **        pad the line by setting width = cursorColumn
540 */
541 void
542 _DtTermPrimCursorMove
543 (
544     Widget  w,
545     int     row,
546     int     col
547 )
548 {
549     DtTermPrimitiveWidget          tw = (DtTermPrimitiveWidget) w;
550     struct termData    *tpd = tw->term.tpd;
551     
552     /* 
553     ** Constrain col to buffer width.
554     */
555     if (col < 0)
556     {
557         col = 0;
558     }
559     else if (col >= COLS(tpd->termBuffer))
560     {
561         col = COLS(tpd->termBuffer) - 1;
562     }
563     tpd->cursorColumn = col;
564
565     /* 
566     ** Constraint row to >= 0.  Height is open ended...
567     */
568     if (row < 0)
569     {
570         row = 0;
571     } 
572
573
574     /* 
575     ** Scroll the window as necessary.
576     */
577     if (row < tpd->topRow) {
578         /* scroll so that row is the topRow... */
579         _DtTermPrimScrollTextTo(w, row);
580         tpd->cursorRow = 0;
581     } else if (row >= tpd->topRow + tw->term.rows) {
582         /* scroll so that row is the bottomRow... */
583         _DtTermPrimScrollTextTo(w, row - tw->term.rows + 1);
584         tpd->cursorRow = tw->term.rows - 1;
585     } else {
586         /* we just need to move the cursor... */
587         tpd->cursorRow = row - tpd->topRow;
588     }
589
590 #ifdef    NOCODE
591     /* 
592     ** Make sure the line is padded properly.
593     **
594     ** NOTE: we no longer do this, it might be necessary for hpterm3.0
595     **       but I will double check then
596     */
597     _DtTermPrimRenderPadLine(w);
598 #endif /* NOCODE */
599 }
600
601 void
602 _DtTermPrimSetCursorVisible
603 (
604     Widget                w,
605     Boolean               visible
606 )
607 {
608     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
609     struct termData      *tpd = tw->term.tpd;
610
611     /* make sure the cursor is off... */
612     _DtTermPrimCursorOff(w);
613     if (visible) {
614         /* turn it on...
615          */
616         tpd->cursorVisible = True;
617     } else {
618         /* turn it off...
619          */
620         tpd->cursorVisible = False;
621     }
622 }
623
624 Boolean
625 _DtTermPrimGetCursorVisible
626 (
627     Widget                w
628 )
629 {
630     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
631     struct termData      *tpd = tw->term.tpd;
632
633     return(tpd->cursorVisible);
634 }
635
636
637