7 #include <stdio.h> // TODO: replace with calls into ACurses_*
13 struct sMessage *Next;
15 enum eMessageClass Class;
16 char *Source; // Pointer to the end of `Data`
24 tServer *Server; //!< Canonical server (can be NULL)
26 char Name[]; // Channel name / remote user
30 void Windows_RepaintCurrent(void);
31 int Windows_int_PaintMessage(tMessage *Message);
34 tWindow gWindow_Status = {
35 NULL, NULL, NULL, // No next, empty list, no server
36 0, {""} // No activity, empty name (rendered as status)
38 tWindow *gpWindows = &gWindow_Status;
39 tWindow *gpCurrentWindow = &gWindow_Status;
42 void Windows_RepaintCurrent(void)
44 tMessage *msg = gpCurrentWindow->Messages;
48 // Note: This renders from the bottom up
49 for( int y = giTerminal_Height - 1; y -- && msg; msg = msg->Next)
51 y -= Windows_int_PaintMessage(msg);
54 // Bottom line is rendered by the prompt
58 int Windows_int_PaintMessage(tMessage *Message)
60 printf("\33[T"); // Scroll down 1 (free space below)
61 SetCursorPos(giTerminal_Height-2, 1);
64 prefixlen += printf("%02i:%02i:%02i ", (Message->Timestamp/3600)%24, (Message->Timestamp/60)%60, Message->Timestamp%60);
65 switch(Message->Class)
67 case MSG_CLASS_BARE: break;
68 case MSG_CLASS_CLIENT:
70 prefixlen += printf("[%s] ", Message->Source);
71 prefixlen += printf("-!- ");
74 prefixlen += printf("[%s] ", Message->Source);
76 case MSG_CLASS_MESSAGE:
77 prefixlen += printf("<%s> ", Message->Source);
79 case MSG_CLASS_ACTION:
80 prefixlen += printf("* %s ", Message->Source);
83 int avail = giTerminal_Width - prefixlen;
84 int msglen = strlen(Message->Data);
87 printf("%.*s", avail, Message);
88 while( msglen > avail ) {
92 SetCursorPos(giTerminal_Height-2, prefixlen+1);
93 printf("%.*s", avail, Message);
100 void Windows_SwitchTo(tWindow *Window)
102 gpCurrentWindow = Window;
106 void Windows_SetStatusServer(tServer *Server)
108 gWindow_Status.Server = Server;
111 tWindow *Windows_GetByIndex(int Index)
114 for( win = gpWindows; win && Index--; win = win->Next )
119 tWindow *Windows_GetByNameEx(tServer *Server, const char *Name, bool CreateAllowed)
121 tWindow *ret, *prev = NULL;
124 // Get the end of the list and check for duplicates
125 // TODO: Cache this instead
126 for( ret = &gWindow_Status; ret; prev = ret, ret = ret->Next )
128 if( ret->Server == Server && strcmp(ret->Name, Name) == 0 )
134 if( !CreateAllowed ) {
138 ret = malloc(sizeof(tWindow) + strlen(Name) + 1);
139 ret->Messages = NULL;
140 ret->Server = Server;
141 ret->ActivityLevel = 1;
142 strcpy(ret->Name, Name);
145 ret->Next = prev->Next;
148 else { // Shouldn't happen really
149 ret->Next = gpWindows;
153 // printf("Win %i %s:%s created\n", num, Server->Name, Name);
158 tWindow *Windows_GetByName(tServer *Server, const char *Name)
160 return Windows_GetByNameEx(Server, Name, false);
163 tWindow *Window_Create(tServer *Server, const char *Name)
165 return Windows_GetByNameEx(Server, Name, true);
169 tWindow *Window_int_ParseSpecial(const tWindow *Window)
172 return gpCurrentWindow;
173 if( Window == WINDOW_STATUS )
174 return &gWindow_Status;
175 return (tWindow*)Window;
178 const char *Window_GetName(const tWindow *Window) {
179 return Window_int_ParseSpecial(Window)->Name;
181 tServer *Window_GetServer(const tWindow *Window) {
182 return Window_int_ParseSpecial(Window)->Server;
184 bool Window_IsChat(const tWindow *Window) {
185 return Window_int_ParseSpecial(Window) != &gWindow_Status;
188 // -----------------------------
190 // -----------------------------
191 void Window_AppendMessage(tWindow *Window, enum eMessageClass Class, const char *Source, const char *Message, ...)
193 Window = Window_int_ParseSpecial(Window);
197 va_start(args, Message);
198 size_t len = vsnprintf(NULL, 0, Message, args);
201 tMessage *msg = malloc( sizeof(tMessage) + len+1 + (Source?strlen(Source)+1:0) );
205 msg->Source = (Source ? msg->Data + len+1 : NULL);
206 va_start(args, Message);
207 vsnprintf(msg->Data, len+1, Message, args);
210 msg->Next = Window->Messages;
211 Window->Messages = msg;
213 if( Window == gpCurrentWindow )
215 // Scroll if needed, and redraw?
216 // - Lazy option of draw at bottom of screen
217 printf("\33[s"); // Save cursor
218 Windows_int_PaintMessage(msg);
219 printf("\x1b[u"); // Restore cursor
223 void Window_AppendMsg_Join(tWindow *Window, const char *Usermask)
225 Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "%s has joined %s", Usermask, Window->Name);
227 void Window_AppendMsg_Quit(tWindow *Window, const char *Usermask, const char *Reason)
229 Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "%s has joined quit (%s)", Usermask, Reason);
231 void Window_AppendMsg_Part(tWindow *Window, const char *Usermask, const char *Reason)
233 Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "%s has joined left %s (%s)", Usermask, Window->Name, Reason);
235 void Window_AppendMsg_Topic(tWindow *Window, const char *Topic)
237 Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "Topic of %s is %s", Window->Name, Topic);
239 void Window_AppendMsg_TopicTime(tWindow *Window, const char *User, const char *Timestamp)
241 Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "Topic set by %s at %s", User, Timestamp);