Usermode/GUI Terminal - Fixed scroll behavior and early frees
[tpg/acess2.git] / Usermode / Applications / gui_terminal_src / main.c
1 /*
2  * Acess GUI Terminal
3  * - By John Hodge (thePowersGang)
4  *
5  * main.c
6  * - Core
7  */
8 #include <axwin3/axwin.h>
9 #include <axwin3/menu.h>
10 #include <axwin3/richtext.h>
11 #include <axwin3/keysyms.h>
12 #include <stdio.h>
13 #include <acess/sys.h>
14 #include "include/display.h"
15 #include "include/vt100.h"
16 #include <string.h>
17 #include <unicode.h>
18 #include <errno.h>
19 #include <acess/devices/pty.h>
20
21 // === PROTOTYPES ===
22  int    main(int argc, char *argv[], const char **envp);
23  int    Term_KeyHandler(tHWND Window, int bPress, uint32_t KeySym, uint32_t Translated);
24  int    Term_MouseHandler(tHWND Window, int bPress, int Button, int Row, int Col);
25 void    Term_HandleOutput(tTerminal *Term, int Len, const char *Buf);
26
27 // === GLOBALS ===
28 tHWND   gMainWindow;
29 tHWND   gMenuWindow;
30  int    giPTYHandle;
31
32 // === CODE ===
33 int main(int argc, char *argv[], const char **envp)
34 {
35         AxWin3_Connect(NULL);
36         
37         // --- Build up window
38         gMainWindow = AxWin3_RichText_CreateWindow(NULL, AXWIN3_RICHTEXT_READONLY);
39         AxWin3_SetWindowTitle(gMainWindow, "Terminal"); // TODO: Update title with other info
40
41         gMenuWindow = AxWin3_Menu_Create(gMainWindow);
42         AxWin3_Menu_AddItem(gMenuWindow, "Copy\tWin+C", NULL, NULL, 0, NULL);
43         AxWin3_Menu_AddItem(gMenuWindow, "Paste\tWin+V", NULL, NULL, 0, NULL);
44         // TODO: Populate menu  
45
46
47         // TODO: Tabs?
48         
49         AxWin3_RichText_SetKeyHandler   (gMainWindow, Term_KeyHandler);
50         AxWin3_RichText_SetMouseHandler (gMainWindow, Term_MouseHandler);
51         AxWin3_RichText_SetDefaultColour(gMainWindow, 0xFFFFFF);
52         AxWin3_RichText_SetBackground   (gMainWindow, 0x000000);
53         AxWin3_RichText_SetFont         (gMainWindow, "#monospace", 10);
54         AxWin3_RichText_SetCursorPos    (gMainWindow, 0, 0);
55         AxWin3_RichText_SetCursorType   (gMainWindow, AXWIN3_RICHTEXT_CURSOR_INV);
56         AxWin3_RichText_SetCursorBlink  (gMainWindow, 1);
57
58         tTerminal *term = Display_Init(80, 25, 100);
59         AxWin3_ResizeWindow(gMainWindow, 80*8, 25*16);
60         AxWin3_MoveWindow(gMainWindow, 20, 50);
61         AxWin3_ShowWindow(gMainWindow, 1);
62         AxWin3_FocusWindow(gMainWindow);
63
64         // Create PTY
65         giPTYHandle = _SysOpen("/Devices/pts/ptmx", OPENFLAG_READ|OPENFLAG_WRITE);
66         if( giPTYHandle < 0 ) {
67                 perror("Unable to create/open PTY");
68                 _SysDebug("Unable to create/open PTY: %s", strerror(errno));
69                 return -1;
70         }
71         // - Initialise
72         {
73                 _SysIOCtl(giPTYHandle, PTY_IOCTL_SETID, "gui0");
74                 struct ptymode  mode = {.InputMode = PTYIMODE_CANON|PTYIMODE_ECHO, .OutputMode=0};
75                 struct ptydims  dims = {.W = 80, .H = 25};
76                 _SysIOCtl(giPTYHandle, PTY_IOCTL_SETMODE, &mode);
77                 _SysIOCtl(giPTYHandle, PTY_IOCTL_SETDIMS, &dims);
78         }
79
80         // Spawn shell
81         {
82                  int    fd = _SysOpen("/Devices/pts/gui0", OPENFLAG_READ|OPENFLAG_WRITE);
83                  int    fds[] = {fd, fd, fd};
84                 const char      *argv[] = {"CLIShell", NULL};
85                 int pid = _SysSpawn("/Acess/Bin/CLIShell", argv, envp, 3, fds, NULL);
86                 if( pid < 0 )
87                         _SysDebug("ERROR: Shell spawn failed: %s", strerror(errno));
88                 _SysIOCtl(fd, PTY_IOCTL_SETPGRP, &pid);
89                 _SysClose(fd);
90         }
91
92         // Main loop
93         for( ;; )
94         {
95                 fd_set  fds;
96                 
97                 FD_ZERO(&fds);
98                 FD_SET(giPTYHandle, &fds);
99                 AxWin3_MessageSelect(giPTYHandle + 1, &fds);
100                 
101                 if( FD_ISSET(giPTYHandle, &fds) )
102                 {
103                         _SysDebug("Activity on child stdout");
104                         // Read and update screen
105                         char    buf[512];
106                         int len = _SysRead(giPTYHandle, buf, sizeof(buf));
107                         if( len <= 0 )  break;
108                         
109                         Term_HandleOutput(term, len, buf);
110                 }
111         }
112
113         return 0;
114 }
115
116 int Term_KeyHandler(tHWND Window, int bPress, uint32_t KeySym, uint32_t Translated)
117 {
118         static int      ctrl_state = 0;
119
120         // Handle modifiers
121         #define _bitset(var,bit,set) do{if(set)var|=1<<(bit);else var&=~(1<<(bit));}while(0)
122         switch(KeySym)
123         {
124         case KEYSYM_LEFTCTRL:
125                 _bitset(ctrl_state, 0, bPress!=0);
126                 return 0;
127         case KEYSYM_RIGHTCTRL:
128                 _bitset(ctrl_state, 1, bPress!=0);
129                 return 0;
130         }
131         #undef _bitset
132
133         // Handle shortcuts
134         // - Ctrl-A -- Ctrl-Z
135         if( ctrl_state && KeySym >= KEYSYM_a && KeySym <= KEYSYM_z )
136         {
137                 Translated = KeySym - KEYSYM_a + 1;
138                 _SysDebug("Ctrl-%c: KS %x => Trans %x", 'A'+(KeySym-KEYSYM_a), KeySym, Translated);
139         }
140
141         // == 2 :: FIRE
142         if( bPress == 2 )
143         {
144                 if( Translated )
145                 {
146                         char    buf[6];
147                          int    len;
148                         
149                         // Encode and send
150                         len = WriteUTF8(buf, Translated);
151                         
152                         _SysDebug("Keystroke %x:%x translated to '%.*s'", KeySym, Translated, len, buf);
153                         _SysWrite(giPTYHandle, buf, len);
154                         
155                         return 0;
156                 }
157                 
158                 // No translation, look for escape sequences to send
159                 const char *str = NULL;
160                 switch(KeySym)
161                 {
162                 case KEYSYM_LEFTARROW:
163                         str = "\x1b[D";
164                         break;
165                 case KEYSYM_RIGHTARROW:
166                         str = "\x1b[C";
167                         break;
168                 case KEYSYM_UPARROW:
169                         str = "\x1b[A";
170                         break;
171                 case KEYSYM_DOWNARROW:
172                         str = "\x1b[B";
173                         break;
174                 }
175                 if( str )
176                 {
177                         _SysWrite(giPTYHandle, str, strlen(str));
178                 }
179         }
180         return 0;
181 }
182
183 int Term_MouseHandler(tHWND Window, int bPress, int Button, int Row, int Col)
184 {
185         return 0;
186 }
187
188 void Term_HandleOutput(tTerminal *Term, int Len, const char *Buf)
189 {
190         // TODO: Handle graphical / accelerated modes
191
192         //_SysDebug("Term_HandleOutput: %i \"%.*s\"", Len, Len, Buf);
193
194          int    ofs = 0;
195          int    esc_len = 0;
196
197         while( ofs < Len )
198         {
199                 esc_len = Term_HandleVT100(Term, Len - ofs, Buf + ofs);
200                 if( esc_len < 0 ) {
201                         Display_AddText(Term, -esc_len, Buf + ofs);
202                         esc_len = -esc_len;
203                 }
204                 ofs += esc_len;
205                 //_SysDebug("Len = %i, ofs = %i", Len, ofs);
206         }
207         
208         Display_Flush(Term);
209 }
210

UCC git Repository :: git.ucc.asn.au