3 * - By John Hodge (thePowersGang)
6 * - 2D command processing
10 #include <acess/devices/pty_cmds.h>
12 void VT_int_SetCursorPos(tVTerm *Term, int X, int Y);
13 void VT_int_SetCursorBitmap(tVTerm *Term, int W, int H);
14 size_t VT_int_FillCursorBitmap(tVTerm *Term, size_t DataOfs, size_t Length, const void *Data);
15 int VT_int_2DCmd_SetCursorPos(void *Handle, size_t Offset, size_t Length, const void *Data);
16 int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, const void *Data);
19 void VT_int_SetCursorPos(tVTerm *Term, int X, int Y)
21 if( Term->Mode == PTYBUFFMT_TEXT )
23 if(Term->Flags & VT_FLAG_ALTBUF)
24 Term->AltWritePos = X + Y * Term->TextWidth;
26 Term->WritePos = X + Y * Term->TextWidth + Term->ViewPos;
27 VT_int_UpdateCursor(Term, 0);
31 Term->VideoCursorX = X;
32 Term->VideoCursorY = Y;
33 VT_int_UpdateCursor(Term, 1);
37 void VT_int_SetCursorBitmap(tVTerm *Term, int W, int H)
39 LOG("WxH = %ix%i", W, H);
42 if(W * H != Term->VideoCursor->W * Term->VideoCursor->H) {
43 free(Term->VideoCursor);
44 Term->VideoCursor = NULL;
47 if(!Term->VideoCursor) {
48 Term->VideoCursor = malloc(sizeof(*Term->VideoCursor) + W*H*sizeof(Uint32));
49 if(!Term->VideoCursor) {
50 Log_Error("VTerm", "Unable to allocate memory for cursor");
54 Term->VideoCursor->W = W;
55 Term->VideoCursor->H = H;
56 Term->VideoCursor->XOfs = 0;
57 Term->VideoCursor->YOfs = 0;
60 size_t VT_int_FillCursorBitmap(tVTerm *Term, size_t DataOfs, size_t Length, const void *Data)
62 if( !Term->VideoCursor )
64 size_t limit = Term->VideoCursor->W * Term->VideoCursor->H * 4;
69 if( DataOfs + Length > limit )
70 Length = limit - DataOfs;
72 LOG("memcpy(VideoCursor->Data + 0x%x, Data, 0x%x)", DataOfs, Length);
73 memcpy((char*)Term->VideoCursor->Data + DataOfs, Data, Length);
75 if(gpVT_CurTerm == Term)
76 VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, Term->VideoCursor);
80 // --- 2D Command deserialising ---
81 int VT_int_2DCmd_SetCursorPos(void *Handle, size_t Offset, size_t Length, const void *Data)
83 struct ptycmd_setcursorpos cmd;
84 if( Length < sizeof(cmd) ) return 0;
85 memcpy(&cmd, Data, sizeof(cmd));
87 VT_int_SetCursorPos(Handle, cmd.x, cmd.y);
92 int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, const void *Data)
94 struct ptycmd_setcursorbmp cmd;
95 tVTerm *term = Handle;
99 if( Length < sizeof(cmd) ) return 0;
100 memcpy(&cmd, Data, sizeof(cmd));
101 VT_int_SetCursorBitmap(Handle, cmd.w, cmd.h);
104 Data = (const char*)Data + ret;
111 if( Offset < sizeof(cmd) ) {
116 ret += VT_int_FillCursorBitmap(Handle, Offset - sizeof(cmd), Length, Data);
118 LOG("%i + %i ==? %i", ret, Offset, term->Cmd2D.CurrentSize);
119 if( ret + Offset >= term->Cmd2D.CurrentSize )
125 // > 0: Command complete
126 // = 0: Not enough data to start
127 // < 0: Ate -n bytes, still need more
128 typedef int (*tVT_2DCmdHandler)(void *Handle, size_t Offset, size_t Length, const void *Data);
129 tVT_2DCmdHandler gVT_2DCmdHandlers[] = {
130 [PTY2D_CMD_SETCURSORPOS] = VT_int_2DCmd_SetCursorPos,
131 [PTY2D_CMD_SETCURSORBMP] = VT_int_2DCmd_SetCursorBitmap,
133 const int ciVT_Num2DCmdHandlers = sizeof(gVT_2DCmdHandlers)/sizeof(gVT_2DCmdHandlers[0]);
135 void VT_int_Handle2DCmd(void *Handle, size_t Length, const void *Data)
137 const uint8_t *bdata = Data;
138 tVTerm *term = Handle;
140 LOG("Length = 0x%x", Length);
141 // If a command terminated early, we have to clean up its data
143 if( term->Cmd2D.PreEat )
145 size_t nom = MIN(term->Cmd2D.PreEat, Length);
148 LOG("Discarding %i/%i ignored bytes of input", nom, term->Cmd2D.PreEat);
149 term->Cmd2D.PreEat -= nom;
154 const int cachesize = sizeof(term->Cmd2D.Cache);
158 // Check for command resume
159 if( term->Cmd2D.Current )
161 LOG("Resuming %i at +0x%x with 0x%x", term->Cmd2D.Current, term->Cmd2D.Offset, Length);
162 dataptr = (void*)bdata;
166 // else begin a new command
169 if( Length < cachesize || term->Cmd2D.CachePos != 0 )
171 adjust = term->Cmd2D.CachePos;
172 size_t newbytes = MIN(cachesize - term->Cmd2D.CachePos, Length);
173 memcpy(term->Cmd2D.Cache + term->Cmd2D.CachePos, bdata, newbytes);
174 term->Cmd2D.CachePos += newbytes;
175 dataptr = (void*)term->Cmd2D.Cache;
176 len = term->Cmd2D.CachePos;
179 dataptr = (void*)bdata;
183 const struct ptycmd_header *hdr = dataptr;
185 if( len < sizeof(*hdr) ) {
189 term->Cmd2D.Offset = 0;
190 term->Cmd2D.Current = hdr->cmd;
191 term->Cmd2D.CurrentSize = (hdr->len_low | (hdr->len_hi << 8)) * 4;
192 if( term->Cmd2D.CurrentSize == 0 )
193 term->Cmd2D.CurrentSize = 2;
194 LOG("Started %i with %s data",
195 term->Cmd2D.Current, (dataptr == bdata ? "direct" : "cache"));
197 if( term->Cmd2D.Current >= ciVT_Num2DCmdHandlers || !gVT_2DCmdHandlers[term->Cmd2D.Current] )
199 Log_Notice("VTerm", "2D Comand %i not handled", term->Cmd2D.Current);
200 if( Length < term->Cmd2D.CurrentSize )
202 term->Cmd2D.CachePos = 0;
203 term->Cmd2D.Current = 0;
204 term->Cmd2D.PreEat = term->Cmd2D.CurrentSize;
209 int rv = gVT_2DCmdHandlers[term->Cmd2D.Current](Handle, term->Cmd2D.Offset, len, dataptr);
210 LOG("2DCmd %i: rv=%i", term->Cmd2D.Current, rv);
211 if( rv == 0 && term->Cmd2D.Offset == 0 ) {
212 // 0: Not enough data for header
213 ASSERT( term->Cmd2D.CachePos != cachesize );
214 // Clear current command because this command hasn't started yet
215 term->Cmd2D.Current = 0;
216 // Return, restart happens once all data is ready
219 size_t used_bytes = (rv < 0 ? -rv : rv) - adjust;
220 Length -= used_bytes;
222 term->Cmd2D.CachePos = 0;
224 ASSERT( -rv <= len );
226 term->Cmd2D.Offset += -rv;
230 term->Cmd2D.Current = 0;
232 // Eat up any uneaten data
233 // - TODO: Need to eat across writes
234 ASSERT( term->Cmd2D.Offset + rv <= term->Cmd2D.CurrentSize );
235 if( term->Cmd2D.Offset + rv < term->Cmd2D.CurrentSize )
237 size_t diff = term->Cmd2D.CurrentSize - (term->Cmd2D.Offset + rv);
238 LOG("Left %i bytes", diff);
239 term->Cmd2D.PreEat = diff;
242 LOG("Done (%i bytes left)", Length);