]> git.proxmox.com Git - spiceterm.git/blame - spiceterm.c
code cleanup - compile with -Wall
[spiceterm.git] / spiceterm.c
CommitLineData
22e5ba02
DM
1/*
2
3 Copyright (C) 2007-2011 Proxmox Server Solutions GmbH
4
5 Copyright: spiceterm is under GNU GPL, the GNU General Public License.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; version 2 dated June, 1991.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20
21 Author: Dietmar Maurer <dietmar@proxmox.com>
22
23*/
24
abc13312
DM
25#define _GNU_SOURCE
26
22e5ba02
DM
27#include <stdio.h>
28#include <stdlib.h>
29#include <unistd.h>
3affb0e7 30#include <sys/types.h>
22e5ba02
DM
31#include <sys/socket.h>
32#include <arpa/inet.h>
33#include <netdb.h>
34#include <pty.h> /* for openpty and forkpty */
35#include <string.h>
36#include <errno.h>
37#include <sys/ioctl.h>
38#include <sys/wait.h>
39#include <signal.h>
40#include <locale.h>
41
42#include "spiceterm.h"
abc13312 43//#include "glyphs.h"
22e5ba02 44
63a34f43 45#include <glib.h>
22e5ba02
DM
46#include <spice.h>
47#include <spice/enums.h>
48#include <spice/macros.h>
49#include <spice/qxl_dev.h>
50
c46a8251 51#include <gdk/gdkkeysyms.h>
22e5ba02
DM
52#include "test_display_base.h"
53
54/* define this for debugging */
55//#define DEBUG
56
57#define TERM "xterm"
58
59#define TERMIDCODE "[?1;2c" // vt100 ID
60
61#define CHECK_ARGC(argc,argv,i) if (i >= argc-1) { \
62 fprintf (stderr, "ERROR: not enough arguments for: %s\n", argv[i]); \
63 print_usage (NULL); \
64 exit(1); \
65}
66
67/* these colours are from linux kernel drivers/char/vt.c */
68
22e5ba02
DM
69unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
70 8,12,10,14, 9,13,11,15 };
71
22e5ba02
DM
72
73static void
74print_usage (const char *msg)
75{
76 if (msg) { fprintf (stderr, "ERROR: %s\n", msg); }
77 fprintf (stderr, "USAGE: vncterm [vncopts] [-c command [args]]\n");
78}
79
80/* Convert UCS2 to UTF8 sequence, trailing zero */
abc13312 81/*
22e5ba02
DM
82static int
83ucs2_to_utf8 (unicode c, char *out)
84{
85 if (c < 0x80) {
86 out[0] = c; // 0*******
87 out[1] = 0;
88 return 1;
89 } else if (c < 0x800) {
90 out[0] = 0xc0 | (c >> 6); // 110***** 10******
91 out[1] = 0x80 | (c & 0x3f);
92 out[2] = 0;
93 return 2;
94 } else {
95 out[0] = 0xe0 | (c >> 12); // 1110**** 10****** 10******
96 out[1] = 0x80 | ((c >> 6) & 0x3f);
97 out[2] = 0x80 | (c & 0x3f);
98 out[3] = 0;
99 return 3;
100 }
101
102 return 0;
103}
abc13312 104*/
22e5ba02
DM
105
106static void
107draw_char_at (vncTerm *vt, int x, int y, unicode ch, TextAttributes attrib)
108{
3affb0e7
DM
109 if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) {
110 return;
22e5ba02
DM
111 }
112
abc13312 113 test_draw_update_char(vt->screen, x, y, ch, attrib);
22e5ba02
DM
114}
115
116static void
117vncterm_update_xy (vncTerm *vt, int x, int y)
118{
119 if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) { return; }
120
121 int y1 = (vt->y_base + y) % vt->total_height;
122 int y2 = y1 - vt->y_displ;
123 if (y2 < 0) {
124 y2 += vt->total_height;
125 }
126 if (y2 < vt->height) {
127 TextCell *c = &vt->cells[y1 * vt->width + x];
128 draw_char_at (vt, x, y2, c->ch, c->attrib);
129 }
130}
131
132static void
133vncterm_clear_xy (vncTerm *vt, int x, int y)
134{
135 if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) { return; }
136
137 int y1 = (vt->y_base + y) % vt->total_height;
138 int y2 = y1 - vt->y_displ;
139 if (y2 < 0) {
140 y2 += vt->total_height;
141 }
142 if (y2 < vt->height) {
143 TextCell *c = &vt->cells[y1 * vt->width + x];
144 c->ch = ' ';
145 c->attrib = vt->default_attrib;
146 c->attrib.fgcol = vt->cur_attrib.fgcol;
147 c->attrib.bgcol = vt->cur_attrib.bgcol;
148
149 draw_char_at (vt, x, y, c->ch, c->attrib);
150 }
151}
152
153static void
154vncterm_show_cursor (vncTerm *vt, int show)
155{
156 int x = vt->cx;
157 if (x >= vt->width) {
158 x = vt->width - 1;
159 }
160
161 int y1 = (vt->y_base + vt->cy) % vt->total_height;
162 int y = y1 - vt->y_displ;
163 if (y < 0) {
164 y += vt->total_height;
165 }
166
167 if (y < vt->height) {
168
169 TextCell *c = &vt->cells[y1 * vt->width + x];
170
171 if (show) {
172 TextAttributes attrib = vt->default_attrib;
173 attrib.invers = !(attrib.invers); /* invert fg and bg */
174 draw_char_at (vt, x, y, c->ch, attrib);
175 } else {
176 draw_char_at (vt, x, y, c->ch, c->attrib);
177 }
178 }
179}
180
181static void
182vncterm_refresh (vncTerm *vt)
183{
184 int x, y, y1;
185
186 // rfbFillRect (vt->screen, 0, 0, vt->maxx, vt->maxy, vt->default_attrib.bgcol);
187
188 y1 = vt->y_displ;
189 for(y = 0; y < vt->height; y++) {
190 TextCell *c = vt->cells + y1 * vt->width;
191 for(x = 0; x < vt->width; x++) {
192 draw_char_at (vt, x, y, c->ch, c->attrib);
193 c++;
194 }
195 if (++y1 == vt->total_height)
196 y1 = 0;
197 }
198 //rfbMarkRectAsModified (vt->screen, 0, 0, vt->maxx, vt->maxy);
199
200 vncterm_show_cursor (vt, 1);
201}
202
203static void
204vncterm_scroll_down (vncTerm *vt, int top, int bottom, int lines)
205{
7b4a7650
DM
206 if ((top + lines) >= bottom) {
207 lines = bottom - top -1;
208 }
22e5ba02 209
7b4a7650
DM
210 if (top < 0 || bottom > vt->height || top >= bottom || lines < 1) {
211 return;
212 }
22e5ba02 213
7b4a7650
DM
214 int i;
215 for(i = bottom - top - lines - 1; i >= 0; i--) {
216 int src = ((vt->y_base + top + i) % vt->total_height)*vt->width;
217 int dst = ((vt->y_base + top + lines + i) % vt->total_height)*vt->width;
22e5ba02 218
7b4a7650
DM
219 memmove(vt->cells + dst, vt->cells + src, vt->width*sizeof (TextCell));
220 }
22e5ba02 221
7b4a7650
DM
222 for (i = 0; i < lines; i++) {
223 int j;
224 TextCell *c = vt->cells + ((vt->y_base + top + i) % vt->total_height)*vt->width;
225 for(j = 0; j < vt->width; j++) {
226 c->attrib = vt->default_attrib;
227 c->ch = ' ';
228 c++;
229 }
230 }
22e5ba02 231
7b4a7650
DM
232 int h = lines * 16;
233 int y0 = top*16;
234 int y1 = y0 + h;
235 int y2 = bottom*16;
22e5ba02 236
7b4a7650
DM
237 test_spice_scroll(vt->screen, 0, y1, vt->screen->primary_width, y2, 0, y0);
238 test_spice_clear(vt->screen, 0, y0, vt->screen->primary_width, y1);
22e5ba02
DM
239}
240
241static void
242vncterm_scroll_up (vncTerm *vt, int top, int bottom, int lines, int moveattr)
243{
7b4a7650
DM
244 if ((top + lines) >= bottom) {
245 lines = bottom - top - 1;
246 }
22e5ba02 247
7b4a7650
DM
248 if (top < 0 || bottom > vt->height || top >= bottom || lines < 1) {
249 return;
250 }
22e5ba02 251
22e5ba02 252
7b4a7650
DM
253 int h = lines * 16;
254 int y0 = top*16;
255 int y1 = (top + lines)*16;
256 int y2 = bottom*16;
22e5ba02 257
7b4a7650
DM
258 test_spice_scroll(vt->screen, 0, y0, vt->screen->primary_width, y2 -h, 0, y1);
259 test_spice_clear(vt->screen, 0, y2 -h, vt->screen->primary_width, y2);
260
261 if (!moveattr) {
262 return;
263 }
22e5ba02 264
7b4a7650 265 // move attributes
22e5ba02 266
7b4a7650
DM
267 int i;
268 for(i = 0; i < (bottom - top - lines); i++) {
269 int dst = ((vt->y_base + top + i) % vt->total_height)*vt->width;
270 int src = ((vt->y_base + top + lines + i) % vt->total_height)*vt->width;
22e5ba02 271
7b4a7650
DM
272 memmove(vt->cells + dst, vt->cells + src, vt->width*sizeof (TextCell));
273 }
22e5ba02 274
7b4a7650
DM
275 for (i = 1; i <= lines; i++) {
276 int j;
277 TextCell *c = vt->cells + ((vt->y_base + bottom - i) % vt->total_height)*vt->width;
278 for(j = 0; j < vt->width; j++) {
279 c->attrib = vt->default_attrib;
280 c->ch = ' ';
281 c++;
282 }
22e5ba02 283 }
22e5ba02
DM
284}
285
286static void
287vncterm_virtual_scroll (vncTerm *vt, int lines)
288{
289 if (vt->altbuf || lines == 0) return;
290
291 if (lines < 0) {
292 lines = -lines;
293 int i = vt->scroll_height;
294 if (i > vt->total_height - vt->height)
295 i = vt->total_height - vt->height;
296 int y1 = vt->y_base - i;
297 if (y1 < 0)
298 y1 += vt->total_height;
299 for(i = 0; i < lines; i++) {
300 if (vt->y_displ == y1) break;
301 if (--vt->y_displ < 0) {
302 vt->y_displ = vt->total_height - 1;
303 }
304 }
305 } else {
306 int i;
307 for(i = 0; i < lines; i++) {
308 if (vt->y_displ == vt->y_base) break;
309 if (++vt->y_displ == vt->total_height) {
310 vt->y_displ = 0;
311 }
312 }
313
314 }
315
316 vncterm_refresh (vt);
317}
318static void
319vncterm_respond_esc (vncTerm *vt, const char *esc)
320{
321 int len = strlen (esc);
322 int i;
323
324 if (vt->ibuf_count < (IBUFSIZE - 1 - len)) {
325 vt->ibuf[vt->ibuf_count++] = 27;
326 for (i = 0; i < len; i++) {
327 vt->ibuf[vt->ibuf_count++] = esc[i];
328 }
329 }
330}
331
332static void
333vncterm_put_lf (vncTerm *vt)
334{
335 if (vt->cy + 1 == vt->region_bottom) {
336
337 if (vt->altbuf || vt->region_top != 0 || vt->region_bottom != vt->height) {
338 vncterm_scroll_up (vt, vt->region_top, vt->region_bottom, 1, 1);
339 return;
340 }
341
342 if (vt->y_displ == vt->y_base) {
343 vncterm_scroll_up (vt, vt->region_top, vt->region_bottom, 1, 0);
344 }
345
346 if (vt->y_displ == vt->y_base) {
347 if (++vt->y_displ == vt->total_height) {
348 vt->y_displ = 0;
349 }
350 }
351
352 if (++vt->y_base == vt->total_height) {
353 vt->y_base = 0;
354 }
355
356 if (vt->scroll_height < vt->total_height) {
357 vt->scroll_height++;
358 }
359
360 int y1 = (vt->y_base + vt->height - 1) % vt->total_height;
361 TextCell *c = &vt->cells[y1 * vt->width];
362 int x;
363 for (x = 0; x < vt->width; x++) {
364 c->ch = ' ';
365 c->attrib = vt->default_attrib;
366 c++;
367 }
368
369 // fprintf (stderr, "BASE: %d DISPLAY %d\n", vt->y_base, vt->y_displ);
370
371 } else if (vt->cy < vt->height - 1) {
372 vt->cy += 1;
373 }
374}
375
376
377static void
378vncterm_csi_m (vncTerm *vt)
379{
380 int i;
381
382 for (i = 0; i < vt->esc_count; i++) {
383 switch (vt->esc_buf[i]) {
384 case 0: /* reset all console attributes to default */
385 vt->cur_attrib = vt->default_attrib;
386 break;
387 case 1:
388 vt->cur_attrib.bold = 1;
389 break;
390 case 4:
391 vt->cur_attrib.uline = 1;
392 break;
393 case 5:
394 vt->cur_attrib.blink = 1;
395 break;
396 case 7:
397 vt->cur_attrib.invers = 1;
398 break;
399 case 8:
400 vt->cur_attrib.unvisible = 1;
401 break;
402 case 10:
403 vt->cur_enc = LAT1_MAP;
404 // fixme: dispaly controls = 0 ?
405 // fixme: toggle meta = 0 ?
406 break;
407 case 11:
408 vt->cur_enc = IBMPC_MAP;
409 // fixme: dispaly controls = 1 ?
410 // fixme: toggle meta = 0 ?
411 break;
412 case 12:
413 vt->cur_enc = IBMPC_MAP;
414 // fixme: dispaly controls = 1 ?
415 // fixme: toggle meta = 1 ?
416 break;
417 case 22:
418 vt->cur_attrib.bold = 0;
419 break;
420 case 24:
421 vt->cur_attrib.uline = 0;
422 break;
423 case 25:
424 vt->cur_attrib.blink = 0;
425 break;
426 case 27:
427 vt->cur_attrib.invers = 0;
428 break;
429 case 28:
430 vt->cur_attrib.unvisible = 0;
431 break;
432 case 30:
433 case 31:
434 case 32:
435 case 33:
436 case 34:
437 case 35:
438 case 36:
439 case 37:
440 /* set foreground color */
441 vt->cur_attrib.fgcol = color_table [vt->esc_buf[i] - 30];
442 break;
443 case 38:
444 /* reset color to default, enable underline */
445 vt->cur_attrib.fgcol = vt->default_attrib.fgcol;
446 vt->cur_attrib.uline = 1;
447 break;
448 case 39:
449 /* reset color to default, disable underline */
450 vt->cur_attrib.fgcol = vt->default_attrib.fgcol;
451 vt->cur_attrib.uline = 0;
452 break;
453 case 40:
454 case 41:
455 case 42:
456 case 43:
457 case 44:
458 case 45:
459 case 46:
460 case 47:
461 /* set background color */
462 vt->cur_attrib.bgcol = color_table [vt->esc_buf[i] - 40];
463 break;
464 case 49:
465 /* reset background color */
466 vt->cur_attrib.bgcol = vt->default_attrib.bgcol;
467 break;
468 default:
469 fprintf (stderr, "unhandled ESC[%d m code\n",vt->esc_buf[i]);
470 //fixme: implement
471 }
472 }
473}
474
475static void
476vncterm_save_cursor (vncTerm *vt)
477{
478 vt->cx_saved = vt->cx;
479 vt->cy_saved = vt->cy;
480 vt->cur_attrib_saved = vt->cur_attrib;
481 vt->charset_saved = vt->charset;
482 vt->g0enc_saved = vt->g0enc;
483 vt->g1enc_saved = vt->g1enc;
484 vt->cur_enc_saved = vt->cur_enc;
485}
486
487static void
488vncterm_restore_cursor (vncTerm *vt)
489{
490 vt->cx = vt->cx_saved;
491 vt->cy = vt->cy_saved;
492 vt->cur_attrib = vt->cur_attrib_saved;
493 vt->charset = vt->charset_saved;
494 vt->g0enc = vt->g0enc_saved;
495 vt->g1enc = vt->g1enc_saved;
496 vt->cur_enc = vt->cur_enc_saved;
497}
498
499static void
500vncterm_set_alternate_buffer (vncTerm *vt, int on_off)
501{
502 int x, y;
503
504 vt->y_displ = vt->y_base;
505
506 if (on_off) {
507
508 if (vt->altbuf) return;
509
510 vt->altbuf = 1;
511
512 /* alternate buffer & cursor */
513
514 vncterm_save_cursor (vt);
515 /* save screen to altcels */
516 for (y = 0; y < vt->height; y++) {
517 int y1 = (vt->y_base + y) % vt->total_height;
518 for (x = 0; x < vt->width; x++) {
519 vt->altcells[y*vt->width + x] = vt->cells[y1*vt->width + x];
520 }
521 }
522
523 /* clear screen */
524 for (y = 0; y <= vt->height; y++) {
525 for (x = 0; x < vt->width; x++) {
526 vncterm_clear_xy (vt, x, y);
527 }
528 }
529
530 } else {
531
532 if (vt->altbuf == 0) return;
533
534 vt->altbuf = 0;
535
536 /* restore saved data */
537 for (y = 0; y < vt->height; y++) {
538 int y1 = (vt->y_base + y) % vt->total_height;
539 for (x = 0; x < vt->width; x++) {
540 vt->cells[y1*vt->width + x] = vt->altcells[y*vt->width + x];
541 }
542 }
543
544 vncterm_restore_cursor (vt);
545 }
546
547 vncterm_refresh (vt);
548}
549
550static void
551vncterm_set_mode (vncTerm *vt, int on_off)
552{
553 int i;
554
555 for (i = 0; i <= vt->esc_count; i++) {
556 if (vt->esc_ques) { /* DEC private modes set/reset */
557 switch(vt->esc_buf[i]) {
558 case 10: /* X11 mouse reporting on/off */
559 case 1000:
560 vt->report_mouse = on_off;
561 break;
562 case 1049: /* start/end special app mode (smcup/rmcup) */
563 vncterm_set_alternate_buffer (vt, on_off);
564 break;
565 case 25: /* Cursor on/off */
566 case 9: /* X10 mouse reporting on/off */
567 case 6: /* Origin relative/absolute */
568 case 1: /* Cursor keys in appl mode*/
569 case 5: /* Inverted screen on/off */
570 case 7: /* Autowrap on/off */
571 case 8: /* Autorepeat on/off */
572 break;
573 }
574 } else { /* ANSI modes set/reset */
575 /* fixme: implement me */
576 }
577 }
578}
579
580static void
581vncterm_gotoxy (vncTerm *vt, int x, int y)
582{
583 /* verify all boundaries */
584
585 if (x < 0) {
586 x = 0;
587 }
588
589 if (x >= vt->width) {
590 x = vt->width - 1;
591 }
592
593 vt->cx = x;
594
595 if (y < 0) {
596 y = 0;
597 }
598
599 if (y >= vt->height) {
600 y = vt->height - 1;
601 }
602
603 vt->cy = y;
604}
605
606enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
607 EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
608 ESpalette, ESidquery, ESosc1, ESosc2};
609
610static void
611vncterm_putchar (vncTerm *vt, unicode ch)
612{
613 int x, y, i, c;
614
615#ifdef DEBUG
616 if (!vt->tty_state)
617 fprintf (stderr, "CHAR:%2d: %4x '%c' (cur_enc %d) %d %d\n", vt->tty_state, ch, ch, vt->cur_enc, vt->cx, vt->cy);
618#endif
619
620 switch(vt->tty_state) {
621 case ESesc:
622 vt->tty_state = ESnormal;
623 switch (ch) {
624 case '[':
625 vt->tty_state = ESsquare;
626 break;
627 case ']':
628 vt->tty_state = ESnonstd;
629 break;
630 case '%':
631 vt->tty_state = ESpercent;
632 break;
633 case '7':
634 vncterm_save_cursor (vt);
635 break;
636 case '8':
637 vncterm_restore_cursor (vt);
638 break;
639 case '(':
640 vt->tty_state = ESsetG0; // SET G0
641 break;
642 case ')':
643 vt->tty_state = ESsetG1; // SET G1
644 break;
645 case 'M':
646 /* cursor up (ri) */
647 if (vt->cy == vt->region_top)
648 vncterm_scroll_down (vt, vt->region_top, vt->region_bottom, 1);
649 else if (vt->cy > 0) {
650 vt->cy--;
651 }
652 break;
653 case '>':
654 /* numeric keypad - ignored */
655 break;
656 case '=':
657 /* appl. keypad - ignored */
658 break;
659 default:
660#ifdef DEBUG
661 fprintf(stderr, "got unhandled ESC%c %d\n", ch, ch);
662#endif
663 break;
664 }
665 break;
666 case ESnonstd: /* Operating System Controls */
667 vt->tty_state = ESnormal;
668
669 switch (ch) {
670 case 'P': /* palette escape sequence */
671 for(i = 0; i < MAX_ESC_PARAMS; i++) {
672 vt->esc_buf[i] = 0;
673 }
674
675 vt->esc_count = 0;
676 vt->tty_state = ESpalette;
677 break;
678 case 'R': /* reset palette */
679 // fixme: reset_palette(vc);
680 break;
681 case '0':
682 case '1':
683 case '2':
684 case '4':
685 vt->osc_cmd = ch;
686 vt->osc_textbuf[0] = 0;
687 vt->tty_state = ESosc1;
688 break;
689 default:
690#ifdef DEBUG
691 fprintf (stderr, "unhandled OSC %c\n", ch);
692#endif
693 vt->tty_state = ESnormal;
694 break;
695 }
696 break;
697 case ESosc1:
698 vt->tty_state = ESnormal;
699 if (ch == ';') {
700 vt->tty_state = ESosc2;
701 } else {
702#ifdef DEBUG
703 fprintf (stderr, "got illegal OSC sequence\n");
704#endif
705 }
706 break;
707 case ESosc2:
708 if (ch != 0x9c && ch != 7) {
709 int i = 0;
710 while (vt->osc_textbuf[i]) i++;
711 vt->osc_textbuf[i++] = ch;
712 vt->osc_textbuf[i] = 0;
713 } else {
714#ifdef DEBUG
715 fprintf (stderr, "OSC:%c:%s\n", vt->osc_cmd, vt->osc_textbuf);
716#endif
717 vt->tty_state = ESnormal;
718 }
719 break;
720 case ESpalette:
721 if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')
722 || (ch >= 'a' && ch <= 'f')) {
723 vt->esc_buf[vt->esc_count++] = (ch > '9' ? (ch & 0xDF) - 'A' + 10 : ch - '0');
724 if (vt->esc_count == 7) {
725 // fixme: this does not work - please test
726 /*
727 rfbColourMap *cmap =&vt->screen->colourMap;
728
729 int i = color_table[vt->esc_buf[0]] * 3, j = 1;
730 cmap->data.bytes[i] = 16 * vt->esc_buf[j++];
731 cmap->data.bytes[i++] += vt->esc_buf[j++];
732 cmap->data.bytes[i] = 16 * vt->esc_buf[j++];
733 cmap->data.bytes[i++] += vt->esc_buf[j++];
734 cmap->data.bytes[i] = 16 * vt->esc_buf[j++];
735 cmap->data.bytes[i] += vt->esc_buf[j];
736 */
737 //set_palette(vc); ?
738
739 vt->tty_state = ESnormal;
740 }
741 } else
742 vt->tty_state = ESnormal;
743 break;
744 case ESsquare:
745 for(i = 0; i < MAX_ESC_PARAMS; i++) {
746 vt->esc_buf[i] = 0;
747 }
748
749 vt->esc_count = 0;
750 vt->esc_has_par = 0;
751 vt->tty_state = ESgetpars;
752
753 if (ch == '>') {
754 vt->tty_state = ESidquery;
755 break;
756 }
757
758 if ((vt->esc_ques = (ch == '?'))) {
759 break;
760 }
761 case ESgetpars:
762 if (ch >= '0' && ch <= '9') {
763 vt->esc_has_par = 1;
764 if (vt->esc_count < MAX_ESC_PARAMS) {
765 vt->esc_buf[vt->esc_count] = vt->esc_buf[vt->esc_count] * 10 + ch - '0';
766 }
767 break;
768 } else if (ch == ';') {
769 vt->esc_count++;
770 break;
771 } else {
772 if (vt->esc_has_par) {
773 vt->esc_count++;
774 }
775 vt->tty_state = ESgotpars;
776 }
777 case ESgotpars:
778
779 vt->tty_state = ESnormal;
780
781#ifdef DEBUG
782 char *qes = vt->esc_ques ? "?" : "";
783 if (vt->esc_count == 0) {
784 fprintf(stderr, "ESC[%s%c\n", qes, ch);
785 } else if (vt->esc_count == 1) {
786 fprintf(stderr, "ESC[%s%d%c\n", qes, vt->esc_buf[0], ch);
787 } else {
788 int i;
789 fprintf(stderr, "ESC[%s%d", qes, vt->esc_buf[0]);
790 for (i = 1; i < vt->esc_count; i++) {
791 fprintf(stderr, ";%d", vt->esc_buf[i]);
792 }
793 fprintf (stderr, "%c\n", ch);
794 }
795#endif
796
797 switch (ch) {
798 case 'h':
799 vncterm_set_mode (vt, 1);
800 break;
801 case 'l':
802 vncterm_set_mode (vt, 0);
803 break;
804 case 'm':
805 if (!vt->esc_count) {
806 vt->esc_count++; // default parameter 0
807 }
808 vncterm_csi_m (vt);
809 break;
810 case 'n':
811 /* report cursor position */
812 /* TODO: send ESC[row;colR */
813 break;
814 case 'A':
815 /* move cursor up */
816 if (vt->esc_buf[0] == 0) {
817 vt->esc_buf[0] = 1;
818 }
819 vt->cy -= vt->esc_buf[0];
820 if (vt->cy < 0) {
821 vt->cy = 0;
822 }
823 break;
824 case 'B':
825 case 'e':
826 /* move cursor down */
827 if (vt->esc_buf[0] == 0) {
828 vt->esc_buf[0] = 1;
829 }
830 vt->cy += vt->esc_buf[0];
831 if (vt->cy >= vt->height) {
832 vt->cy = vt->height - 1;
833 }
834 break;
835 case 'C':
836 case 'a':
837 /* move cursor right */
838 if (vt->esc_buf[0] == 0) {
839 vt->esc_buf[0] = 1;
840 }
841 vt->cx += vt->esc_buf[0];
842 if (vt->cx >= vt->width) {
843 vt->cx = vt->width - 1;
844 }
845 break;
846 case 'D':
847 /* move cursor left */
848 if (vt->esc_buf[0] == 0) {
849 vt->esc_buf[0] = 1;
850 }
851 vt->cx -= vt->esc_buf[0];
852 if (vt->cx < 0) {
853 vt->cx = 0;
854 }
855 break;
856 case 'G':
857 case '`':
858 /* move cursor to column */
859 vncterm_gotoxy (vt, vt->esc_buf[0] - 1, vt->cy);
860 break;
861 case 'd':
862 /* move cursor to row */
863 vncterm_gotoxy (vt, vt->cx , vt->esc_buf[0] - 1);
864 break;
865 case 'f':
866 case 'H':
867 /* move cursor to row, column */
868 vncterm_gotoxy (vt, vt->esc_buf[1] - 1, vt->esc_buf[0] - 1);
869 break;
870 case 'J':
871 switch (vt->esc_buf[0]) {
872 case 0:
873 /* clear to end of screen */
874 for (y = vt->cy; y < vt->height; y++) {
875 for (x = 0; x < vt->width; x++) {
876 if (y == vt->cy && x < vt->cx) {
877 continue;
878 }
879 vncterm_clear_xy (vt, x, y);
880 }
881 }
882 break;
883 case 1:
884 /* clear from beginning of screen */
885 for (y = 0; y <= vt->cy; y++) {
886 for (x = 0; x < vt->width; x++) {
887 if (y == vt->cy && x > vt->cx) {
888 break;
889 }
890 vncterm_clear_xy (vt, x, y);
891 }
892 }
893 break;
894 case 2:
895 /* clear entire screen */
896 for (y = 0; y <= vt->height; y++) {
897 for (x = 0; x < vt->width; x++) {
898 vncterm_clear_xy (vt, x, y);
899 }
900 }
901 break;
902 }
903 break;
904 case 'K':
905 switch (vt->esc_buf[0]) {
906 case 0:
907 /* clear to eol */
908 for(x = vt->cx; x < vt->width; x++) {
909 vncterm_clear_xy (vt, x, vt->cy);
910 }
911 break;
912 case 1:
913 /* clear from beginning of line */
914 for (x = 0; x <= vt->cx; x++) {
915 vncterm_clear_xy (vt, x, vt->cy);
916 }
917 break;
918 case 2:
919 /* clear entire line */
920 for(x = 0; x < vt->width; x++) {
921 vncterm_clear_xy (vt, x, vt->cy);
922 }
923 break;
924 }
925 break;
926 case 'L':
927 /* insert line */
928 c = vt->esc_buf[0];
929
930 if (c > vt->height - vt->cy)
931 c = vt->height - vt->cy;
932 else if (!c)
933 c = 1;
934
935 vncterm_scroll_down (vt, vt->cy, vt->region_bottom, c);
936 break;
937 case 'M':
938 /* delete line */
939 c = vt->esc_buf[0];
940
941 if (c > vt->height - vt->cy)
942 c = vt->height - vt->cy;
943 else if (!c)
944 c = 1;
945
946 vncterm_scroll_up (vt, vt->cy, vt->region_bottom, c, 1);
947 break;
948 case 'T':
949 /* scroll down */
950 c = vt->esc_buf[0];
951 if (!c) c = 1;
952 vncterm_scroll_down (vt, vt->region_top, vt->region_bottom, c);
953 break;
954 case 'S':
955 /* scroll up */
956 c = vt->esc_buf[0];
957 if (!c) c = 1;
958 vncterm_scroll_up (vt, vt->region_top, vt->region_bottom, c, 1);
959 break;
960 case 'P':
961 /* delete c character */
962 c = vt->esc_buf[0];
963
964 if (c > vt->width - vt->cx)
965 c = vt->width - vt->cx;
966 else if (!c)
967 c = 1;
968
969 for (x = vt->cx; x < vt->width - c; x++) {
970 int y1 = (vt->y_base + vt->cy) % vt->total_height;
971 TextCell *dst = &vt->cells[y1 * vt->width + x];
972 TextCell *src = dst + c;
973 *dst = *src;
974 vncterm_update_xy (vt, x + c, vt->cy);
975 src->ch = ' ';
976 src->attrib = vt->default_attrib;
977 vncterm_update_xy (vt, x, vt->cy);
978 }
979 break;
980 case 's':
981 /* save cursor position */
982 vncterm_save_cursor (vt);
983 break;
984 case 'u':
985 /* restore cursor position */
986 vncterm_restore_cursor (vt);
987 break;
988 case 'X':
989 /* erase c characters */
990 c = vt->esc_buf[0];
991 if (!c) c = 1;
992
993 if (c > (vt->width - vt->cx)) c = vt->width - vt->cx;
994
995 for(i = 0; i < c; i++) {
996 vncterm_clear_xy (vt, vt->cx + i, vt->cy);
997 }
998 break;
999 case '@':
1000 /* insert c character */
1001 c = vt->esc_buf[0];
1002 if (c > (vt->width - vt->cx)) {
1003 c = vt->width - vt->cx;
1004 }
1005 if (!c) c = 1;
1006
1007 for (x = vt->width - c; x >= vt->cx; x--) {
1008 int y1 = (vt->y_base + vt->cy) % vt->total_height;
1009 TextCell *src = &vt->cells[y1 * vt->width + x];
1010 TextCell *dst = src + c;
1011 *dst = *src;
1012 vncterm_update_xy (vt, x + c, vt->cy);
1013 src->ch = ' ';
1014 src->attrib = vt->cur_attrib;
1015 vncterm_update_xy (vt, x, vt->cy);
1016 }
1017
1018 break;
1019 case 'r':
1020 /* set region */
1021 if (!vt->esc_buf[0])
1022 vt->esc_buf[0]++;
1023 if (!vt->esc_buf[1])
1024 vt->esc_buf[1] = vt->height;
1025 /* Minimum allowed region is 2 lines */
1026 if (vt->esc_buf[0] < vt->esc_buf[1] &&
1027 vt->esc_buf[1] <= vt->height) {
1028 vt->region_top = vt->esc_buf[0] - 1;
1029 vt->region_bottom = vt->esc_buf[1];
1030 vt->cx = 0;
1031 vt->cy = vt->region_top;
1032#ifdef DEBUG
1033 fprintf (stderr, "set region %d %d\n", vt->region_top, vt->region_bottom);
1034#endif
1035 }
1036
1037 break;
1038 default:
1039#ifdef DEBUG
1040 if (vt->esc_count == 0) {
1041 fprintf(stderr, "unhandled escape ESC[%s%c\n", qes, ch);
1042 } else if (vt->esc_count == 1) {
1043 fprintf(stderr, "unhandled escape ESC[%s%d%c\n", qes, vt->esc_buf[0], ch);
1044 } else {
1045 int i;
1046 fprintf(stderr, "unhandled escape ESC[%s%d", qes, vt->esc_buf[0]);
1047 for (i = 1; i < vt->esc_count; i++) {
1048 fprintf(stderr, ";%d", vt->esc_buf[i]);
1049 }
1050 fprintf (stderr, "%c\n", ch);
1051 }
1052#endif
1053 break;
1054 }
1055 vt->esc_ques = 0;
1056 break;
1057 case ESsetG0: // Set G0
1058 vt->tty_state = ESnormal;
1059
1060 if (ch == '0')
1061 vt->g0enc = GRAF_MAP;
1062 else if (ch == 'B')
1063 vt->g0enc = LAT1_MAP;
1064 else if (ch == 'U')
1065 vt->g0enc = IBMPC_MAP;
1066 else if (ch == 'K')
1067 vt->g0enc = USER_MAP;
1068
1069 if (vt->charset == 0)
1070 vt->cur_enc = vt->g0enc;
1071
1072 break;
1073 case ESsetG1: // Set G1
1074 vt->tty_state = ESnormal;
1075
1076 if (ch == '0')
1077 vt->g1enc = GRAF_MAP;
1078 else if (ch == 'B')
1079 vt->g1enc = LAT1_MAP;
1080 else if (ch == 'U')
1081 vt->g1enc = IBMPC_MAP;
1082 else if (ch == 'K')
1083 vt->g1enc = USER_MAP;
1084
1085 if (vt->charset == 1)
1086 vt->cur_enc = vt->g1enc;
1087
1088 break;
1089 case ESidquery: // vt100 query id
1090 vt->tty_state = ESnormal;
1091
1092 if (ch == 'c') {
1093#ifdef DEBUG
1094 fprintf (stderr, "ESC[>c Query term ID\n");
1095#endif
1096 vncterm_respond_esc (vt, TERMIDCODE);
1097 }
1098 break;
1099 case ESpercent:
1100 vt->tty_state = ESnormal;
1101 switch (ch) {
1102 case '@': /* defined in ISO 2022 */
1103 vt->utf8 = 0;
1104 break;
1105 case 'G': /* prelim official escape code */
1106 case '8': /* retained for compatibility */
1107 vt->utf8 = 1;
1108 break;
1109 }
1110 break;
1111 default: // ESnormal
1112 vt->tty_state = ESnormal;
1113
1114 switch(ch) {
1115 case 0:
1116 break;
1117 case 7: /* alert aka. bell */
1118 // fixme:
3affb0e7 1119 //rfbSendBell(vt->screen);
22e5ba02
DM
1120 break;
1121 case 8: /* backspace */
1122 if (vt->cx > 0)
1123 vt->cx--;
1124 break;
1125 case 9: /* tabspace */
1126 if (vt->cx + (8 - (vt->cx % 8)) > vt->width) {
1127 vt->cx = 0;
1128 vncterm_put_lf (vt);
1129 } else {
1130 vt->cx = vt->cx + (8 - (vt->cx % 8));
1131 }
1132 break;
1133 case 10: /* LF,*/
1134 case 11: /* VT */
1135 case 12: /* FF */
1136 vncterm_put_lf (vt);
1137 break;
1138 case 13: /* carriage return */
1139 vt->cx = 0;
1140 break;
1141 case 14:
1142 /* SI (shift in), select character set 1 */
1143 vt->charset = 1;
1144 vt->cur_enc = vt->g1enc;
1145 /* fixme: display controls = 1 */
1146 break;
1147 case 15:
1148 /* SO (shift out), select character set 0 */
1149 vt->charset = 0;
1150 vt->cur_enc = vt->g0enc;
1151 /* fixme: display controls = 0 */
1152 break;
1153 case 27: /* esc */
1154 vt->tty_state = ESesc;
1155 break;
1156 case 127: /* delete */
1157 /* ignore */
1158 break;
1159 case 128+27: /* csi */
1160 vt->tty_state = ESsquare;
1161 break;
1162 default:
1163 if (vt->cx >= vt->width) {
1164 /* line wrap */
1165 vt->cx = 0;
1166 vncterm_put_lf (vt);
1167 }
1168
1169 int y1 = (vt->y_base + vt->cy) % vt->total_height;
1170 TextCell *c = &vt->cells[y1*vt->width + vt->cx];
1171 c->attrib = vt->cur_attrib;
1172 c->ch = ch;
1173 vncterm_update_xy (vt, vt->cx, vt->cy);
1174 vt->cx++;
1175 break;
1176 }
1177 break;
1178 }
1179}
1180
1181static int
1182vncterm_puts (vncTerm *vt, const char *buf, int len)
1183{
1184 unicode tc;
1185
1186 vncterm_show_cursor (vt, 0);
1187
1188 while (len) {
1189 unsigned char c = *buf;
1190 len--;
1191 buf++;
1192
1193 if (vt->tty_state != ESnormal) {
1194 // never translate escape sequence
1195 tc = c;
1196 } else if (vt->utf8 && !vt->cur_enc) {
1197
1198 if(c & 0x80) { // utf8 multi-byte sequence
1199
1200 if (vt->utf_count > 0 && (c & 0xc0) == 0x80) {
1201 // inside UTF8 sequence
1202 vt->utf_char = (vt->utf_char << 6) | (c & 0x3f);
1203 vt->utf_count--;
1204 if (vt->utf_count == 0) {
1205 tc = vt->utf_char;
1206 } else {
1207 continue;
1208 }
1209 } else {
1210 // first char of a UTF8 sequence
1211 if ((c & 0xe0) == 0xc0) {
1212 vt->utf_count = 1;
1213 vt->utf_char = (c & 0x1f);
1214 } else if ((c & 0xf0) == 0xe0) {
1215 vt->utf_count = 2;
1216 vt->utf_char = (c & 0x0f);
1217 } else if ((c & 0xf8) == 0xf0) {
1218 vt->utf_count = 3;
1219 vt->utf_char = (c & 0x07);
1220 } else if ((c & 0xfc) == 0xf8) {
1221 vt->utf_count = 4;
1222 vt->utf_char = (c & 0x03);
1223 } else if ((c & 0xfe) == 0xfc) {
1224 vt->utf_count = 5;
1225 vt->utf_char = (c & 0x01);
1226 } else
1227 vt->utf_count = 0;
1228
1229 continue;
1230 }
1231 } else {
1232 // utf8 single byte
1233 tc = c;
1234 vt->utf_count = 0;
1235 }
1236
1237 } else {
1238 // never translate controls
1239 if (c >= 32 && c != 127 && c != (128+27)) {
1240 tc = translations[vt->cur_enc][c & 0x0ff];
1241 } else {
1242 tc = c;
1243 }
1244 }
1245
1246 vncterm_putchar (vt, tc);
1247 }
1248
1249 vncterm_show_cursor (vt, 1);
3affb0e7 1250
22e5ba02
DM
1251 return len;
1252}
1253
1254/* fixme:
1255void
1256vncterm_set_xcut_text (char* str, int len, struct _rfbClientRec* cl)
1257{
1258 vncTerm *vt =(vncTerm *)cl->screen->screenData;
1259
1260 // seems str is Latin-1 encoded
1261 if (vt->selection) free (vt->selection);
1262 vt->selection = (unicode *)malloc (len*sizeof (unicode));
1263 int i;
1264 for (i = 0; i < len; i++) {
1265 vt->selection[i] = str[i] & 0xff;
1266 }
1267 vt->selection_len = len;
1268}
1269*/
abc13312 1270/*
22e5ba02
DM
1271static void
1272mouse_report (vncTerm *vt, int butt, int mrx, int mry)
1273{
1274 char buf[8];
1275
1276 sprintf (buf, "[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
1277 (char)('!' + mry));
1278
1279 vncterm_respond_esc (vt, buf);
1280}
abc13312 1281*/
22e5ba02
DM
1282
1283void
1284vncterm_toggle_marked_cell (vncTerm *vt, int pos)
1285{
22e5ba02
DM
1286
1287/* fixme:
abc13312
DM
1288 int x= (pos%vt->width)*8;
1289 int y= (pos/vt->width)*16;
22e5ba02
DM
1290
1291 int i,j;
1292 rfbScreenInfoPtr s=vt->screen;
1293
1294 char *b = s->frameBuffer+y*s->width+x;
1295
1296 for (j=0; j < 16; j++) {
1297 for(i=0; i < 8; i++) {
1298 b[j*s->width+i] ^= 0x0f;
1299 rfbMarkRectAsModified (s, x, y, x+8, y+16);
1300 }
1301 }
1302*/
1303}
1304
1305/* fixme:
1306
1307void
1308vncterm_pointer_event (int buttonMask, int x, int y, rfbClientPtr cl)
1309{
1310
1311 vncTerm *vt =(vncTerm *)cl->screen->screenData;
1312 static int button2_released = 1;
1313 static int last_mask = 0;
1314 static int sel_start_pos = 0;
1315 static int sel_end_pos = 0;
1316 int i;
1317
1318 int cx = x/8;
1319 int cy = y/16;
1320
1321 if (cx < 0) cx = 0;
1322 if (cx >= vt->width) cx = vt->width - 1;
1323 if (cy < 0) cy = 0;
1324 if (cy >= vt->height) cy = vt->height - 1;
1325
1326 if (vt->report_mouse && buttonMask != last_mask) {
1327 last_mask = buttonMask;
1328 if (buttonMask & 1) {
1329 mouse_report (vt, 0, cx, cy);
1330 }
1331 if (buttonMask & 2) {
1332 mouse_report (vt, 1, cx, cy);
1333 }
1334 if (buttonMask & 4) {
1335 mouse_report (vt, 2, cx, cy);
1336 }
1337 if (!buttonMask) {
1338 mouse_report (vt, 3, cx, cy);
1339 }
1340 }
1341
1342 if (buttonMask & 2) {
1343 if(button2_released && vt->selection) {
1344 int i;
1345 for(i = 0; i < vt->selection_len; i++) {
1346 if (vt->ibuf_count < IBUFSIZE - 6) { // uft8 is max 6 characters wide
1347 if (vt->utf8) {
1348 vt->ibuf_count += ucs2_to_utf8 (vt->selection[i], &vt->ibuf[vt->ibuf_count]);
1349 } else {
1350 vt->ibuf[vt->ibuf_count++] = vt->selection[i];
1351 }
1352 }
1353 }
1354 if (vt->y_displ != vt->y_base) {
1355 vt->y_displ = vt->y_base;
1356 vncterm_refresh (vt);
1357 }
1358 }
1359 button2_released = 0;
1360 } else {
1361 button2_released = 1;
1362 }
1363
1364 if (buttonMask & 1) {
1365 int pos = cy*vt->width + cx;
1366
1367 // code borrowed from libvncserver (VNConsole.c)
1368
1369 if (!vt->mark_active) {
1370
1371 vt->mark_active = 1;
1372 sel_start_pos = sel_end_pos = pos;
1373 vncterm_toggle_marked_cell (vt, pos);
1374
1375 } else {
1376
1377 if (pos != sel_end_pos) {
1378
1379 if (pos > sel_end_pos) {
1380 cx = sel_end_pos; cy=pos;
1381 } else {
1382 cx=pos; cy=sel_end_pos;
1383 }
1384
1385 if (cx < sel_start_pos) {
1386 if (cy < sel_start_pos) cy--;
1387 } else {
1388 cx++;
1389 }
1390
1391 while (cx <= cy) {
1392 vncterm_toggle_marked_cell (vt, cx);
1393 cx++;
1394 }
1395
1396 sel_end_pos = pos;
1397 }
1398 }
1399
1400 } else if (vt->mark_active) {
1401 vt->mark_active = 0;
1402
1403 if (sel_start_pos > sel_end_pos) {
1404 int tmp = sel_start_pos - 1;
1405 sel_start_pos = sel_end_pos;
1406 sel_end_pos = tmp;
1407 }
1408
1409 int len = sel_end_pos - sel_start_pos + 1;
1410
1411 if (vt->selection) free (vt->selection);
1412 vt->selection = (unicode *)malloc (len*sizeof (unicode));
1413 vt->selection_len = len;
1414 char *sel_latin1 = (char *)malloc (len + 1);
1415
1416 for (i = 0; i < len; i++) {
1417 int pos = sel_start_pos + i;
1418 int x = pos % vt->width;
1419 int y1 = ((pos / vt->width) + vt->y_displ) % vt->total_height;
1420 TextCell *c = &vt->cells[y1*vt->width + x];
1421 vt->selection[i] = c->ch;
1422 sel_latin1[i] = (char)c->ch;
1423 c++;
1424 }
1425 sel_latin1[len] = 0;
1426 rfbGotXCutText (vt->screen, sel_latin1, len);
1427 free (sel_latin1);
1428
1429 while (sel_start_pos <= sel_end_pos) {
1430 vncterm_toggle_marked_cell (vt, sel_start_pos++);
1431 }
1432
1433 }
1434
1435 rfbDefaultPtrAddEvent (buttonMask, x, y, cl);
1436
1437}
1438*/
1439
22e5ba02
DM
1440static void my_kbd_push_key(SpiceKbdInstance *sin, uint8_t frag)
1441{
abc13312 1442 // vncTerm *vt = SPICE_CONTAINEROF(sin, vncTerm, keyboard_sin);
22e5ba02 1443
a1cf2514 1444 /* we no not need this */
3affb0e7 1445
a1cf2514 1446 return;
22e5ba02
DM
1447}
1448
c46a8251 1449static void my_kbd_push_keyval(SpiceKbdInstance *sin, uint32_t keySym, int flags)
77133eee
DM
1450{
1451 vncTerm *vt = SPICE_CONTAINEROF(sin, vncTerm, keyboard_sin);
c46a8251
DM
1452 static int control = 0;
1453 static int shift = 0;
1454 char *esc = NULL;
1455
a1cf2514 1456 guint uc = 0;
c46a8251 1457
a1cf2514
DM
1458 fprintf (stderr, "KEYEVENT:%d: %08x\n", flags, keySym);fflush (stderr);
1459 if (flags & 1) {
c46a8251
DM
1460 if (keySym == GDK_KEY_Shift_L || keySym == GDK_KEY_Shift_R) {
1461 shift = 1;
1462 } if (keySym == GDK_KEY_Control_L || keySym == GDK_KEY_Control_R) {
1463 control = 1;
1464 } else if (vt->ibuf_count < (IBUFSIZE - 32)) {
1465
1466 if (control) {
1467 if(keySym >= 'a' && keySym <= 'z')
a1cf2514 1468 uc = keySym - 'a' + 1;
c46a8251 1469 else if (keySym >= 'A' && keySym <= 'Z')
a1cf2514 1470 uc = keySym - 'A' + 1;
c46a8251 1471 else
a1cf2514
DM
1472 uc = 0;
1473
1474
1475 //printf("CONTROL: %08x %d\n", keySym, uc);
1476
c46a8251
DM
1477 } else {
1478 switch (keySym) {
1479 case GDK_KEY_Escape:
a1cf2514 1480 uc = 27; break;
c46a8251 1481 case GDK_KEY_Return:
a1cf2514 1482 uc = '\r'; break;
c46a8251 1483 case GDK_KEY_BackSpace:
a1cf2514 1484 uc = 8; break;
c46a8251 1485 case GDK_KEY_Tab:
a1cf2514 1486 uc = '\t'; break;
c46a8251
DM
1487 case GDK_KEY_Delete: /* kdch1 */
1488 case GDK_KEY_KP_Delete:
1489 esc = "[3~";break;
1490 case GDK_KEY_Home: /* khome */
1491 case GDK_KEY_KP_Home:
1492 esc = "OH";break;
1493 case GDK_KEY_End:
1494 case GDK_KEY_KP_End: /* kend */
1495 esc = "OF";break;
1496 case GDK_KEY_Insert: /* kich1 */
1497 case GDK_KEY_KP_Insert:
1498 esc = "[2~";break;
1499 case GDK_KEY_Up:
1500 case GDK_KEY_KP_Up: /* kcuu1 */
1501 esc = "OA";break;
1502 case GDK_KEY_Down: /* kcud1 */
1503 case GDK_KEY_KP_Down:
1504 esc = "OB";break;
1505 case GDK_KEY_Right:
1506 case GDK_KEY_KP_Right: /* kcuf1 */
1507 esc = "OC";break;
1508 case GDK_KEY_Left:
1509 case GDK_KEY_KP_Left: /* kcub1 */
1510 esc = "OD";break;
1511 case GDK_KEY_Page_Up:
1512 if (shift) {
1513 vncterm_virtual_scroll (vt, -vt->height/2);
867d1eb5 1514 goto ret;
c46a8251
DM
1515 }
1516 esc = "[5~";break;
1517 case GDK_KEY_Page_Down:
1518 if (shift) {
1519 vncterm_virtual_scroll (vt, vt->height/2);
867d1eb5 1520 goto ret;
c46a8251
DM
1521 }
1522 esc = "[6~";break;
1523 case GDK_KEY_F1:
1524 esc = "OP";break;
1525 case GDK_KEY_F2:
1526 esc = "OQ";break;
1527 case GDK_KEY_F3:
1528 esc = "OR";break;
1529 case GDK_KEY_F4:
1530 esc = "OS";break;
1531 case GDK_KEY_F5:
1532 esc = "[15~";break;
1533 case GDK_KEY_F6:
1534 esc = "[17~";break;
1535 case GDK_KEY_F7:
1536 esc = "[18~";break;
1537 case GDK_KEY_F8:
1538 esc = "[19~";break;
1539 case GDK_KEY_F9:
1540 esc = "[20~";break;
1541 case GDK_KEY_F10:
1542 esc = "[21~";break;
1543 case GDK_KEY_F11:
1544 esc = "[23~";break;
1545 case GDK_KEY_F12:
1546 esc = "[24~";break;
1547 default:
a1cf2514
DM
1548 if (keySym < 0x100) {
1549 uc = keySym;
1550 }
c46a8251
DM
1551 break;
1552 }
1553 }
77133eee 1554
c46a8251 1555#ifdef DEBUG
a1cf2514 1556 fprintf(stderr, "KEYPRESS OUT:%s: %08x\n", esc, uc); fflush (stderr);
c46a8251 1557#endif
77133eee 1558
c46a8251
DM
1559 if (vt->y_displ != vt->y_base) {
1560 vt->y_displ = vt->y_base;
1561 vncterm_refresh (vt);
1562 }
1563
1564 if (esc) {
1565 vncterm_respond_esc(vt, esc);
a1cf2514 1566 } else if (uc > 0) {
c46a8251
DM
1567 if (vt->utf8) {
1568 gchar buf[10];
a1cf2514 1569 gint len = g_unichar_to_utf8(uc, buf);
c46a8251
DM
1570
1571 if (len > 0) {
1572 int i;
1573 for (i = 0; i < len; i++) {
1574 vt->ibuf[vt->ibuf_count++] = buf[i];
1575 }
1576 }
1577 } else {
a1cf2514 1578 vt->ibuf[vt->ibuf_count++] = (char)uc;
c46a8251 1579 }
77133eee 1580 }
867d1eb5 1581 }
c46a8251
DM
1582 }
1583
a1cf2514
DM
1584
1585ret:
1586
c46a8251 1587 if (flags & 2) { // UP
a1cf2514
DM
1588 //printf("KEYRELEASE %08x\n", keySym);
1589
c46a8251
DM
1590 if (keySym == GDK_KEY_Shift_L || keySym == GDK_KEY_Shift_R) {
1591 shift = 0;
1592 } else if (keySym == GDK_KEY_Control_L || keySym == GDK_KEY_Control_R) {
1593 control = 0;
77133eee 1594 }
77133eee 1595 }
867d1eb5 1596
867d1eb5
DM
1597 vt->screen->core->watch_update_mask(vt->screen->mwatch,
1598 SPICE_WATCH_EVENT_READ|SPICE_WATCH_EVENT_WRITE);
77133eee
DM
1599}
1600
22e5ba02
DM
1601static uint8_t my_kbd_get_leds(SpiceKbdInstance *sin)
1602{
1603 return 0;
1604}
1605
1606static SpiceKbdInterface my_keyboard_sif = {
1607 .base.type = SPICE_INTERFACE_KEYBOARD ,
1608 .base.description = "spiceterm keyboard device",
1609 .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
1610 .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
c46a8251 1611 .push_keyval = my_kbd_push_keyval,
22e5ba02
DM
1612 .push_scan_freg = my_kbd_push_key,
1613 .get_leds = my_kbd_get_leds,
1614};
1615
1616vncTerm *
1617create_vncterm (int argc, char** argv, int maxx, int maxy)
1618{
1619 int i;
1620
1621 Test *test;
1622
1623 SpiceCoreInterface *core = basic_event_loop_init();
1624 test = test_new(core);
1625 //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESS_OFF);
1626 test_add_display_interface(test);
1627 test_add_agent_interface(test->server);
1628
1629 vncTerm *vt = (vncTerm *)calloc (sizeof(vncTerm), 1);
3affb0e7 1630
22e5ba02
DM
1631 vt->keyboard_sin.base.sif = &my_keyboard_sif.base;
1632 spice_server_add_interface(test->server, &vt->keyboard_sin.base);
3affb0e7 1633
22e5ba02
DM
1634 /*
1635 rfbColourMap *cmap =&screen->colourMap;
1636 cmap->data.bytes = malloc (16*3);
1637 for(i=0;i<16;i++) {
1638 cmap->data.bytes[i*3 + 0] = default_red[color_table[i]];
1639 cmap->data.bytes[i*3 + 1] = default_grn[color_table[i]];
1640 cmap->data.bytes[i*3 + 2] = default_blu[color_table[i]];
1641 }
1642 cmap->count = 16;
1643 cmap->is16 = FALSE;
1644 screen->serverFormat.trueColour = FALSE;
1645
1646 screen->kbdAddEvent = vncterm_kbd_event;
1647
1648 screen->setXCutText = vncterm_set_xcut_text;
1649
1650 screen->ptrAddEvent = vncterm_pointer_event;
1651
1652 screen->desktopName = "VNC Command Terminal";
1653
1654 screen->newClientHook = new_client;
1655
1656 */
1657
1658 vt->maxx = test->width;
1659 vt->maxy = test->height;
1660
1661 vt->width = vt->maxx / 8;
1662 vt->height = vt->maxy / 16;
1663
1664 vt->total_height = vt->height * 20;
1665 vt->scroll_height = 0;
1666 vt->y_base = 0;
1667 vt->y_displ = 0;
1668
1669 vt->region_top = 0;
1670 vt->region_bottom = vt->height;
1671
1672 vt->g0enc = LAT1_MAP;
1673 vt->g1enc = GRAF_MAP;
1674 vt->cur_enc = vt->g0enc;
1675 vt->charset = 0;
1676
1677 /* default text attributes */
1678 vt->default_attrib.bold = 0;
1679 vt->default_attrib.uline = 0;
1680 vt->default_attrib.blink = 0;
1681 vt->default_attrib.invers = 0;
1682 vt->default_attrib.unvisible = 0;
1683 vt->default_attrib.fgcol = 7;
1684 vt->default_attrib.bgcol = 0;
1685
1686 vt->cur_attrib = vt->default_attrib;
1687
1688 vt->cells = (TextCell *)calloc (sizeof (TextCell), vt->width*vt->total_height);
1689
1690 for (i = 0; i < vt->width*vt->total_height; i++) {
1691 vt->cells[i].ch = ' ';
1692 vt->cells[i].attrib = vt->default_attrib;
1693 }
1694
1695 vt->altcells = (TextCell *)calloc (sizeof (TextCell), vt->width*vt->height);
1696
1697 vt->screen = test;
1698
1699 return vt;
1700}
1701
1702static void master_watch(int master, int event, void *opaque)
1703{
1704 vncTerm *vt = (vncTerm *)opaque;
1705
1706 printf("CHANNEL EVENT %d\n", event);
1707
1708 // fixme: if (!vt->mark_active) {
1709
1710 if (event == SPICE_WATCH_EVENT_READ) {
1711 char buffer[1024];
1712 int c;
1713 while ((c = read(master, buffer, 1024)) == -1) {
1714 if (errno != EAGAIN) break;
1715 }
1716 if (c == -1) {
1717 g_error("got read error"); // fixme
1718 }
1719 vncterm_puts (vt, buffer, c);
1720 } else {
1721 if (vt->ibuf_count > 0) {
77133eee 1722 printf ("DEBUG: WRITE %x %d\n", vt->ibuf[0], vt->ibuf_count);
22e5ba02 1723 write (master, vt->ibuf, vt->ibuf_count);
3affb0e7 1724 vt->ibuf_count = 0; // fixme: what if not all data written
22e5ba02
DM
1725 }
1726 vt->screen->core->watch_update_mask(vt->screen->mwatch, SPICE_WATCH_EVENT_READ);
1727 }
1728}
1729
1730int
1731main (int argc, char** argv)
1732{
1733 int i;
1734 char **cmdargv = NULL;
1735 char *command = "/bin/bash"; // execute normal shell as default
1736 int pid;
1737 int master;
1738 char ptyname[1024];
22e5ba02
DM
1739 struct winsize dimensions;
1740
63a34f43
DM
1741 g_thread_init(NULL);
1742
22e5ba02
DM
1743 for (i = 1; i < argc; i++) {
1744 if (!strcmp (argv[i], "-c")) {
1745 command = argv[i+1];
1746 cmdargv = &argv[i+1];
1747 argc = i;
1748 argv[i] = NULL;
1749 break;
1750 }
1751 }
1752
abc13312
DM
1753 if (0) print_usage(NULL); // fixme:
1754
22e5ba02
DM
1755 vncTerm *vt = create_vncterm (argc, argv, 745, 400);
1756
1757 setlocale(LC_ALL, ""); // set from environment
1758
1759 char *ctype = setlocale (LC_CTYPE, NULL); // query LC_CTYPE
1760
1761 // fixme: ist there a standard way to detect utf8 mode ?
1762 if (strcasestr (ctype, ".utf-8")||strcasestr (ctype, ".utf8")) {
1763 vt->utf8 = 1;
1764 }
1765
1766 dimensions.ws_col = vt->width;
1767 dimensions.ws_row = vt->height;
1768
1769 setenv ("TERM", TERM, 1);
1770
3affb0e7 1771 printf("EXEC: %s\n", command);
22e5ba02
DM
1772
1773 pid = forkpty (&master, ptyname, NULL, &dimensions);
1774 if(!pid) {
1775
1776 // install default signal handlers
1777 signal (SIGQUIT, SIG_DFL);
1778 signal (SIGTERM, SIG_DFL);
1779 signal (SIGINT, SIG_DFL);
1780
1781 if (cmdargv) {
1782 execvp (command, cmdargv);
1783 } else {
1784 execlp (command, command, NULL);
1785 }
1786 perror ("Error: exec failed\n");
1787 exit (-1); // should not be reached
1788 } else if (pid == -1) {
1789 perror ("Error: fork failed\n");
1790 exit (-1);
1791 }
1792
1793
1794 vt->screen->mwatch = vt->screen->core->watch_add(
3affb0e7 1795 master, SPICE_WATCH_EVENT_READ /* |SPICE_WATCH_EVENT_WRITE */,
22e5ba02
DM
1796 master_watch, vt);
1797
1798 basic_event_loop_mainloop();
1799
1800 //rfbProcessEvents (vt->screen, 40000); /* 40 ms */
1801
1802 /*
1803 if (vt->ibuf_count > 0) {
1804 printf ("DEBUG: WRITE %d %d\n", vt->ibuf[0], vt->ibuf_count);
1805 write (master, vt->ibuf, vt->ibuf_count);
1806 vt->ibuf_count = 0;
1807 last_time = time (NULL);
1808 }
1809 */
1810
1811 kill (pid, 9);
1812 int status;
1813 waitpid(pid, &status, 0);
1814
1815 exit (0);
1816}