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 tVT_Pos *wrpos = VT_int_GetWritePosPtr(Term);
25 wrpos->Col = Y + (Term->Flags & VT_FLAG_ALTBUF ? 0 : Term->ViewTopRow);
26 VT_int_UpdateCursor(Term, 0);
30 Term->VideoCursorX = X;
31 Term->VideoCursorY = Y;
32 VT_int_UpdateCursor(Term, 1);
36 void VT_int_SetCursorBitmap(tVTerm *Term, int W, int H)
38 LOG("WxH = %ix%i", W, H);
41 if(W * H != Term->VideoCursor->W * Term->VideoCursor->H) {
42 free(Term->VideoCursor);
43 Term->VideoCursor = NULL;
46 if(!Term->VideoCursor) {
47 Term->VideoCursor = malloc(sizeof(*Term->VideoCursor) + W*H*sizeof(Uint32));
48 if(!Term->VideoCursor) {
49 Log_Error("VTerm", "Unable to allocate memory for cursor");
53 Term->VideoCursor->W = W;
54 Term->VideoCursor->H = H;
55 Term->VideoCursor->XOfs = 0;
56 Term->VideoCursor->YOfs = 0;
59 size_t VT_int_FillCursorBitmap(tVTerm *Term, size_t DataOfs, size_t Length, const void *Data)
61 if( !Term->VideoCursor )
63 size_t limit = Term->VideoCursor->W * Term->VideoCursor->H * 4;
68 if( DataOfs + Length > limit )
69 Length = limit - DataOfs;
71 LOG("memcpy(VideoCursor->Data + 0x%x, Data, 0x%x)", DataOfs, Length);
72 memcpy((char*)Term->VideoCursor->Data + DataOfs, Data, Length);
74 if(gpVT_CurTerm == Term)
75 VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, Term->VideoCursor);
79 // --- 2D Command deserialising ---
80 int VT_int_2DCmd_SetCursorPos(void *Handle, size_t Offset, size_t Length, const void *Data)
82 struct ptycmd_setcursorpos cmd;
83 if( Length < sizeof(cmd) ) return 0;
84 memcpy(&cmd, Data, sizeof(cmd));
86 VT_int_SetCursorPos(Handle, cmd.x, cmd.y);
91 int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, const void *Data)
93 struct ptycmd_setcursorbmp cmd;
94 tVTerm *term = Handle;
98 if( Length < sizeof(cmd) ) return 0;
99 memcpy(&cmd, Data, sizeof(cmd));
100 VT_int_SetCursorBitmap(Handle, cmd.w, cmd.h);
103 Data = (const char*)Data + ret;
110 if( Offset < sizeof(cmd) ) {
115 ret += VT_int_FillCursorBitmap(Handle, Offset - sizeof(cmd), Length, Data);
117 LOG("%i + %i ==? %i", ret, Offset, term->Cmd2D.CurrentSize);
118 if( ret + Offset >= term->Cmd2D.CurrentSize )
124 // > 0: Command complete
125 // = 0: Not enough data to start
126 // < 0: Ate -n bytes, still need more
127 typedef int (*tVT_2DCmdHandler)(void *Handle, size_t Offset, size_t Length, const void *Data);
128 tVT_2DCmdHandler gVT_2DCmdHandlers[] = {
129 [PTY2D_CMD_SETCURSORPOS] = VT_int_2DCmd_SetCursorPos,
130 [PTY2D_CMD_SETCURSORBMP] = VT_int_2DCmd_SetCursorBitmap,
132 const int ciVT_Num2DCmdHandlers = sizeof(gVT_2DCmdHandlers)/sizeof(gVT_2DCmdHandlers[0]);
134 void VT_int_Handle2DCmd(void *Handle, size_t Length, const void *Data)
136 const uint8_t *bdata = Data;
137 tVTerm *term = Handle;
139 LOG("Length = 0x%x", Length);
140 // If a command terminated early, we have to clean up its data
142 if( term->Cmd2D.PreEat )
144 size_t nom = MIN(term->Cmd2D.PreEat, Length);
147 LOG("Discarding %i/%i ignored bytes of input", nom, term->Cmd2D.PreEat);
148 term->Cmd2D.PreEat -= nom;
153 const int cachesize = sizeof(term->Cmd2D.Cache);
157 // Check for command resume
158 if( term->Cmd2D.Current )
160 LOG("Resuming %i at +0x%x with 0x%x", term->Cmd2D.Current, term->Cmd2D.Offset, Length);
161 dataptr = (void*)bdata;
165 // else begin a new command
168 if( Length < cachesize || term->Cmd2D.CachePos != 0 )
170 adjust = term->Cmd2D.CachePos;
171 size_t newbytes = MIN(cachesize - term->Cmd2D.CachePos, Length);
172 memcpy(term->Cmd2D.Cache + term->Cmd2D.CachePos, bdata, newbytes);
173 term->Cmd2D.CachePos += newbytes;
174 dataptr = (void*)term->Cmd2D.Cache;
175 len = term->Cmd2D.CachePos;
178 dataptr = (void*)bdata;
182 const struct ptycmd_header *hdr = dataptr;
184 if( len < sizeof(*hdr) ) {
188 term->Cmd2D.Offset = 0;
189 term->Cmd2D.Current = hdr->cmd;
190 term->Cmd2D.CurrentSize = (hdr->len_low | (hdr->len_hi << 8)) * 4;
191 if( term->Cmd2D.CurrentSize == 0 )
192 term->Cmd2D.CurrentSize = 2;
193 LOG("Started %i with %s data",
194 term->Cmd2D.Current, (dataptr == bdata ? "direct" : "cache"));
196 if( term->Cmd2D.Current >= ciVT_Num2DCmdHandlers || !gVT_2DCmdHandlers[term->Cmd2D.Current] )
198 Log_Notice("VTerm", "2D Comand %i not handled", term->Cmd2D.Current);
199 if( Length < term->Cmd2D.CurrentSize )
201 term->Cmd2D.CachePos = 0;
202 term->Cmd2D.Current = 0;
203 term->Cmd2D.PreEat = term->Cmd2D.CurrentSize;
208 int rv = gVT_2DCmdHandlers[term->Cmd2D.Current](Handle, term->Cmd2D.Offset, len, dataptr);
209 LOG("2DCmd %i: rv=%i", term->Cmd2D.Current, rv);
210 if( rv == 0 && term->Cmd2D.Offset == 0 ) {
211 // 0: Not enough data for header
212 ASSERT( term->Cmd2D.CachePos != cachesize );
213 // Clear current command because this command hasn't started yet
214 term->Cmd2D.Current = 0;
215 // Return, restart happens once all data is ready
218 size_t used_bytes = (rv < 0 ? -rv : rv) - adjust;
219 Length -= used_bytes;
221 term->Cmd2D.CachePos = 0;
223 ASSERT( -rv <= len );
225 term->Cmd2D.Offset += -rv;
229 term->Cmd2D.Current = 0;
231 // Eat up any uneaten data
232 // - TODO: Need to eat across writes
233 ASSERT( term->Cmd2D.Offset + rv <= term->Cmd2D.CurrentSize );
234 if( term->Cmd2D.Offset + rv < term->Cmd2D.CurrentSize )
236 size_t diff = term->Cmd2D.CurrentSize - (term->Cmd2D.Offset + rv);
237 LOG("Left %i bytes", diff);
238 term->Cmd2D.PreEat = diff;
241 LOG("Done (%i bytes left)", Length);