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;
58 size_t VT_int_FillCursorBitmap(tVTerm *Term, size_t DataOfs, size_t Length, const void *Data)
60 if( !Term->VideoCursor )
62 size_t limit = Term->VideoCursor->W * Term->VideoCursor->H * 4;
67 if( DataOfs + Length > limit )
68 Length = limit - DataOfs;
70 LOG("memcpy(VideoCursor->Data + 0x%x, Data, 0x%x)", DataOfs, Length);
71 memcpy((char*)Term->VideoCursor->Data + DataOfs, Data, Length);
73 if(gpVT_CurTerm == Term)
74 VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, Term->VideoCursor);
78 // --- 2D Command deserialising ---
79 int VT_int_2DCmd_SetCursorPos(void *Handle, size_t Offset, size_t Length, const void *Data)
81 struct ptycmd_setcursorpos cmd;
82 if( Length < sizeof(cmd) ) return 0;
83 memcpy(&cmd, Data, sizeof(cmd));
85 VT_int_SetCursorPos(Handle, cmd.x, cmd.y);
90 int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, const void *Data)
92 struct ptycmd_setcursorbmp cmd;
93 tVTerm *term = Handle;
97 if( Length < sizeof(cmd) ) return 0;
98 memcpy(&cmd, Data, sizeof(cmd));
99 VT_int_SetCursorBitmap(Handle, cmd.w, cmd.h);
102 Data = (const char*)Data + ret;
109 if( Offset < sizeof(cmd) ) {
114 ret += VT_int_FillCursorBitmap(Handle, Offset - sizeof(cmd), Length, Data);
116 LOG("%i + %i ==? %i", ret, Offset, term->Cmd2D.CurrentSize);
117 if( ret + Offset >= term->Cmd2D.CurrentSize )
123 // > 0: Command complete
124 // = 0: Not enough data to start
125 // < 0: Ate -n bytes, still need more
126 typedef int (*tVT_2DCmdHandler)(void *Handle, size_t Offset, size_t Length, const void *Data);
127 tVT_2DCmdHandler gVT_2DCmdHandlers[] = {
128 [PTY2D_CMD_SETCURSORPOS] = VT_int_2DCmd_SetCursorPos,
129 [PTY2D_CMD_SETCURSORBMP] = VT_int_2DCmd_SetCursorBitmap,
131 const int ciVT_Num2DCmdHandlers = sizeof(gVT_2DCmdHandlers)/sizeof(gVT_2DCmdHandlers[0]);
133 void VT_int_Handle2DCmd(void *Handle, size_t Length, const void *Data)
135 const uint8_t *bdata = Data;
136 tVTerm *term = Handle;
138 LOG("Length = 0x%x", Length);
139 // If a command terminated early, we have to clean up its data
141 if( term->Cmd2D.PreEat )
143 size_t nom = MIN(term->Cmd2D.PreEat, Length);
146 LOG("Discarding %i/%i ignored bytes of input", nom, term->Cmd2D.PreEat);
147 term->Cmd2D.PreEat -= nom;
152 const int cachesize = sizeof(term->Cmd2D.Cache);
156 // Check for command resume
157 if( term->Cmd2D.Current )
159 LOG("Resuming %i at +0x%x with 0x%x", term->Cmd2D.Current, term->Cmd2D.Offset, Length);
160 dataptr = (void*)bdata;
164 // else begin a new command
167 if( Length < cachesize || term->Cmd2D.CachePos != 0 )
169 adjust = term->Cmd2D.CachePos;
170 size_t newbytes = MIN(cachesize - term->Cmd2D.CachePos, Length);
171 memcpy(term->Cmd2D.Cache + term->Cmd2D.CachePos, bdata, newbytes);
172 term->Cmd2D.CachePos += newbytes;
173 dataptr = (void*)term->Cmd2D.Cache;
174 len = term->Cmd2D.CachePos;
177 dataptr = (void*)bdata;
181 const struct ptycmd_header *hdr = dataptr;
183 if( len < sizeof(*hdr) ) {
187 term->Cmd2D.Offset = 0;
188 term->Cmd2D.Current = hdr->cmd;
189 term->Cmd2D.CurrentSize = (hdr->len_low | (hdr->len_hi << 8)) * 4;
190 if( term->Cmd2D.CurrentSize == 0 )
191 term->Cmd2D.CurrentSize = 2;
192 LOG("Started %i with %s data",
193 term->Cmd2D.Current, (dataptr == bdata ? "direct" : "cache"));
195 if( term->Cmd2D.Current >= ciVT_Num2DCmdHandlers || !gVT_2DCmdHandlers[term->Cmd2D.Current] )
197 Log_Notice("VTerm", "2D Comand %i not handled", term->Cmd2D.Current);
198 if( Length < term->Cmd2D.CurrentSize )
200 term->Cmd2D.CachePos = 0;
201 term->Cmd2D.Current = 0;
202 term->Cmd2D.PreEat = term->Cmd2D.CurrentSize;
207 int rv = gVT_2DCmdHandlers[term->Cmd2D.Current](Handle, term->Cmd2D.Offset, len, dataptr);
208 LOG("2DCmd %i: rv=%i", term->Cmd2D.Current, rv);
209 if( rv == 0 && term->Cmd2D.Offset == 0 ) {
210 // 0: Not enough data for header
211 ASSERT( term->Cmd2D.CachePos != cachesize );
212 // Clear current command because this command hasn't started yet
213 term->Cmd2D.Current = 0;
214 // Return, restart happens once all data is ready
217 size_t used_bytes = (rv < 0 ? -rv : rv) - adjust;
218 Length -= used_bytes;
220 term->Cmd2D.CachePos = 0;
222 ASSERT( -rv <= len );
224 term->Cmd2D.Offset += -rv;
228 term->Cmd2D.Current = 0;
230 // Eat up any uneaten data
231 // - TODO: Need to eat across writes
232 ASSERT( term->Cmd2D.Offset + rv <= term->Cmd2D.CurrentSize );
233 if( term->Cmd2D.Offset + rv < term->Cmd2D.CurrentSize )
235 size_t diff = term->Cmd2D.CurrentSize - (term->Cmd2D.Offset + rv);
236 LOG("Left %i bytes", diff);
237 term->Cmd2D.PreEat = diff;
240 LOG("Done (%i bytes left)", Length);