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