/* Monolith chat messages pane widget. * - by Richard W.M. Jones * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: messages_pane.c,v 1.6 2003/02/22 15:34:28 rich Exp $ */ #include "config.h" #include #include #ifdef HAVE_ASSERT_H #include #endif #ifdef HAVE_STRING_H #include #endif #include #include #include #include #include #include #include "chatroom.h" #include "lib.h" #include "messages_pane.h" #define NR_RECENT_MESSAGES 20 static void repaint (void *, ml_session, const char *, io_handle); struct ml_widget_operations messages_pane_ops = { repaint: repaint }; struct messages_pane { struct ml_widget_operations *ops; pool pool; /* Pool for allocations. */ ml_session session; /* Current session. */ const char *conninfo; /* Database connection. */ chatroom room; /* The chatroom. */ }; messages_pane new_messages_pane (pool pool, ml_session session, const char *conninfo, chatroom room) { messages_pane w = pmalloc (pool, sizeof *w); w->ops = &messages_pane_ops; w->pool = pool; w->session = session; w->conninfo = conninfo; w->room = room; return w; } struct pre_sleep_args { messages_pane w; io_handle io; }; /* This function is called just before the repaint loop goes to sleep * waiting for the next message to be posted. The purpose of the function * therefore is to flush any output buffers and drive the data back to * the user through any proxies along the way (as far as this is * possible). */ static void pre_sleep (ml_session session, void *vargs) { struct pre_sleep_args *args = (struct pre_sleep_args *) vargs; messages_pane w = args->w; /* Scroll the window up. */ io_fputs ("\n", args->io); /* Send the fill buffer. */ chat_fill_buffer (args->io, session, w->conninfo); } static void repaint (void *vw, ml_session session, const char *windowid, io_handle io) { messages_pane w = (messages_pane) vw; int i, userid; const char *username = 0; message m; db_handle dbh; st_handle sth; struct pre_sleep_args args; /* Prepare the arguments for the pre_sleep function above. */ args.w = w; args.io = io; userid = ml_session_userid (session); if (userid) { /* Resolve the username. */ dbh = get_db_handle (w->conninfo, DBI_THROW_ERRORS); sth = st_prepare_cached (dbh, "select username from ml_users where userid = ?", DBI_INT); st_execute (sth, userid); st_bind (sth, 0, username, DBI_STRING); st_fetch (sth); put_db_handle (dbh); } /* Tell the chatroom object that we are in the room. We remain in the * room as long as this repaint function is being run. This does * mean that if we logout and login as someone else (or just login) * then the chatroom object won't know who we are until we reopen this * frame, but don't worry about it. */ chatroom_enter (w->room, userid, username); /* Start by displaying some recent messages (if there are any). */ i = chatroom_last_message_index (w->room) - NR_RECENT_MESSAGES; for (;; i++) { /* Display the next message. */ m = chatroom_get_message (w->room, i, pre_sleep, session, &args); if (!m) continue; /* Note that messages know how to render themselves. */ message_show (m, io); } chatroom_leave (w->room); }