Added SILC Thread Queue API
[runtime.git] / apps / silcer / src / silcerchatview.cc
1 /*
2
3   silcerchatview.cc 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   Code is mostly ripped from Gabber, thus code also copyrighted by:
19   Copyright (C) 1999-2001 Dave Smith & Julian Missig
20   
21 */
22
23 #include "silcerchatview.hh"
24 #include <libgnome/gnome-url.h>
25 #include <gtk--/text.h>
26 #include <gtk/gtkbox.h>
27
28 extern "C" {
29 #include "xtext.h"
30 }
31
32 GdkColor colors[] =
33 {
34    {0, 0, 0, 0},                /* 0  black */
35    {0, 0xcccc, 0xcccc, 0xcccc}, /* 1  white */
36    {0, 0, 0, 0xcccc},           /* 2  blue */
37    {0, 0, 0xcccc, 0},           /* 3  green */
38    {0, 0xcccc, 0, 0},           /* 4  red */
39    {0, 0xbbbb, 0xbbbb, 0},      /* 5  yellow/brown */
40    {0, 0xbbbb, 0, 0xbbbb},      /* 6  purple */
41    {0, 0xffff, 0xaaaa, 0},      /* 7  orange */
42    {0, 0xffff, 0xffff, 0},      /* 8  yellow */
43    {0, 0, 0xffff, 0},           /* 9  green */
44    {0, 0, 0xcccc, 0xcccc},      /* 10 aqua */
45    {0, 0, 0xffff, 0xffff},      /* 11 light aqua */
46    {0, 0, 0, 0xffff},           /* 12 blue */
47    {0, 0xffff, 0, 0xffff},      /* 13 pink */
48    {0, 0x7777, 0x7777, 0x7777}, /* 14 grey */
49    {0, 0x9999, 0x9999, 0x9999}, /* 15 light grey */
50    {0, 0, 0, 0xcccc},           /* 16 blue markBack */
51    {0, 0xeeee, 0xeeee, 0xeeee}, /* 17 white markFore */
52    {0, 0xcccc, 0xcccc, 0xcccc}, /* 18 foreground (white) */
53    {0, 0, 0, 0},                /* 19 background (black) */
54 };
55
56 typedef const int CONSTANT;
57 const int WORD_URL  = 1;
58 const int WORD_HOST = 2;
59
60 void palette_load(GtkWidget* w)
61 {
62   int i;
63   
64   if (!colors[0].pixel)             /* don't do it again */
65     for (i = 0; i < 20; i++) {
66       colors[i].pixel = (gulong) ((colors[i].red & 0xff00) * 256 +
67                                   (colors[i].green & 0xff00) +
68                                   (colors[i].blue & 0xff00) / 256);
69       if (!gdk_colormap_alloc_color (gtk_widget_get_colormap (w), 
70                                      &colors[i], 0, 1))
71         cerr << "Error allocating color " << i << endl;
72     }
73 }
74
75 int word_check(GtkXText* t, char* word)
76 {
77   if (!word)
78     return 0;
79   int len = strlen (word);
80   
81   if (!strncasecmp (word, "irc://", 6))
82     return WORD_URL;
83
84   if (!strncasecmp (word, "irc.", 4))
85     return WORD_URL;
86
87   if (!strncasecmp (word, "ftp.", 4))
88     return WORD_URL;
89
90   if (!strncasecmp (word, "ftp:", 4))
91     return WORD_URL;
92
93   if (!strncasecmp (word, "www.", 4))
94     return WORD_URL;
95
96   if (!strncasecmp (word, "http:", 5))
97     return WORD_URL;
98
99   if (!strncasecmp (word, "https:", 6))
100     return WORD_URL;
101
102   if (!strncasecmp (word, "silc:", 7))
103     return WORD_URL;
104
105   if (!strncasecmp (word, "sftp:", 7))
106     return WORD_URL;
107
108   if (!strncasecmp (word + len - 4, ".org", 4))
109     return WORD_HOST;
110
111   if (!strncasecmp (word + len - 4, ".net", 4))
112     return WORD_HOST;
113
114   if (!strncasecmp (word + len - 4, ".com", 4))
115     return WORD_HOST;
116
117   if (!strncasecmp (word + len - 4, ".edu", 4))
118     return WORD_HOST;
119
120   return 0;
121 }
122
123 SilcerChatView::SilcerChatView(Gtk::Widget *owner, Gtk::Container *parent, 
124                                gboolean indent)
125 {
126   // Create a Gtk::Text so we can grab the colors, then destroy it
127   Gtk::Text textwidget;
128   parent->add(textwidget);
129   textwidget.realize();
130
131   // Copy the style of the Gtk::Text widget
132   GtkStyle* gs = gtk_widget_get_style(GTK_WIDGET(textwidget.gtkobj()));
133   colors[16] = gs->bg[GTK_STATE_SELECTED];
134   colors[17] = gs->fg[GTK_STATE_SELECTED];
135   colors[18] = gs->fg[GTK_STATE_NORMAL];
136   colors[19] = gs->base[GTK_STATE_NORMAL];
137   parent->remove(textwidget);
138   textwidget.destroy();
139
140   // Initialize the palette
141   palette_load(owner->gtkobj());
142
143   // Create the GtkXText object
144   _xtext = GTK_XTEXT(gtk_xtext_new(75, 0));
145
146   // Internal init
147   _xtext->max_lines = 1024;
148   _xtext->urlcheck_function = word_check;    
149   _xtext->auto_indent = !indent;
150   _xtext->wordwrap = true;
151
152   // Display the widget
153   gtk_xtext_set_palette(_xtext, colors);
154   gtk_xtext_set_font(_xtext, gs->font, "");
155
156   // Create a frame around it
157   _frmChat = GTK_FRAME(gtk_frame_new(NULL));
158   gtk_frame_set_shadow_type(GTK_FRAME(_frmChat), GTK_SHADOW_IN);
159
160   // Add the widget to a container, which happens to be a frame
161   gtk_container_add(parent->gtkobj(), GTK_WIDGET(_frmChat));
162   gtk_container_add(GTK_CONTAINER(_frmChat), GTK_WIDGET(_xtext));
163   gtk_widget_show(GTK_WIDGET(_frmChat));
164   gtk_widget_show(GTK_WIDGET(_xtext));
165   
166   // Create a scrollbar
167   _vsChat = GTK_VSCROLLBAR(gtk_vscrollbar_new(_xtext->adj));
168   gtk_box_pack_start (GTK_BOX (parent->gtkobj()), GTK_WIDGET(_vsChat), 
169                       FALSE, FALSE, 1);
170   GTK_WIDGET_UNSET_FLAGS (_vsChat, GTK_CAN_FOCUS);
171   gtk_widget_show (GTK_WIDGET(_vsChat));
172
173   // Hookup stub callback
174   gtk_signal_connect(GTK_OBJECT(_xtext), "word_click", 
175                      GTK_SIGNAL_FUNC(&SilcerChatView::_on_word_clicked_stub), 
176                      this);
177 }
178
179 SilcerChatView::~SilcerChatView()
180 {
181   gtk_widget_destroy(GTK_WIDGET(_xtext));
182   gtk_widget_destroy(GTK_WIDGET(_frmChat));
183   gtk_widget_destroy(GTK_WIDGET(_vsChat));
184 }
185
186 void SilcerChatView::render(const string &message, const string &username, 
187                       const string &timestamp, COLOR_T &c)
188 {
189   if (username == "")
190     print(timestamp  + c + "***\017", message);
191   else
192     print(timestamp + c + "<\017" + username + c + ">\017" , message);
193 }
194
195 void SilcerChatView::render_error(const string &message, const string &error, 
196                                   const string &timestamp, COLOR_T &c)
197 {
198   // Process error messages
199   print(timestamp + c + error + "\017:", message);
200 }
201
202 void SilcerChatView::clearbuffer()
203 {
204   // Flush the buffer
205   gtk_xtext_remove_lines(_xtext, -1, true);
206 }
207
208 string SilcerChatView::get_chars()
209 {
210   return string(gtk_xtext_get_chars(_xtext));
211 }
212
213 void SilcerChatView::on_word_clicked(char *word, GdkEventButton *evt)
214 {
215   string s_word = word;
216
217   if (evt->button == 3) {
218     switch(word_check(_xtext, word))
219       {
220       case WORD_URL:
221         gnome_url_show(word);
222         break;
223       case WORD_HOST:
224         s_word = "http://" + s_word;
225         gnome_url_show(s_word.c_str());
226         break;
227       }   
228   }
229 }
230
231 void SilcerChatView::_on_word_clicked_stub(GtkXText *xtext, char *word, 
232                                      GdkEventButton *evt, 
233                                            SilcerChatView *_this)
234 {
235   _this->on_word_clicked(word, evt);
236 }
237
238 inline void SilcerChatView::print(const string &s)
239 {
240   char* astr = (char*)s.c_str();
241   char* anewline = strchr(astr, '\n');
242
243   if (anewline) {
244     while(1) {
245       gtk_xtext_append(_xtext, astr, 
246                        (unsigned long)anewline - (unsigned long)astr);
247       astr = anewline + 1;
248       if (*astr == 0)
249         break;
250       anewline = strchr(astr, '\n');
251       if (!anewline) {
252         gtk_xtext_append(_xtext, astr, -1);
253         break;
254       }
255     }
256   } else {
257     gtk_xtext_append(_xtext, astr, s.length());
258   }
259 }
260
261 inline void SilcerChatView::print(const string& left, const string& right)
262 {
263   char* s = (char*)right.c_str();
264   char* newline = strchr(s, '\n');
265
266   if (newline) {
267     // Display the first line w/ the user who said it
268     gtk_xtext_append_indent(_xtext, (char*)left.c_str(), left.length(),
269                             s, (unsigned long)newline - (unsigned long)s);
270     // Now loop through the rest of the string, displaying it
271     while (1) {
272       s = newline + 1;
273       if (*s == 0)
274         break;
275       newline = strchr(s, '\n');
276       // If another newline is found, append it to the display and loop again
277       if (newline) {
278         gtk_xtext_append_indent(_xtext, "", 0, s, 
279                                 (unsigned long)newline - (unsigned long)s);
280       } else {
281         // Otherwise append the rest of the string and break out of  the loop
282         gtk_xtext_append_indent(_xtext, "", 0, s, -1);
283         break;
284       }
285     }
286   } else {
287     gtk_xtext_append_indent(_xtext, (char*)left.c_str(), left.length(),
288                             (char*)right.c_str(), right.length());
289   }
290 }