]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-chat-view.c
Fix licence and clean up a bit the interface
[empathy.git] / libempathy-gtk / empathy-chat-view.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2008 Collabora Ltd.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  * 
20  * Authors: Xavier Claessens <xclaesse@gmail.com>
21  */
22
23 #include "config.h"
24
25 #include <telepathy-glib/util.h>
26
27 #include "empathy-chat-view.h"
28 #include "empathy-smiley-manager.h"
29 #include "empathy-ui-utils.h"
30
31 static void chat_view_base_init (gpointer klass);
32
33 GType
34 empathy_chat_view_get_type (void)
35 {
36         static GType type = 0;
37         
38         if (!type) {
39                 static const GTypeInfo type_info = {
40                         sizeof (EmpathyChatViewIface),
41                         chat_view_base_init,
42                         NULL,
43                 };
44                 
45                 type = g_type_register_static (G_TYPE_INTERFACE,
46                                                "EmpathyChatView",
47                                                &type_info, 0);
48                 
49                 g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
50         }
51         
52         return type;
53 }
54
55 static void
56 chat_view_base_init (gpointer klass)
57 {
58         static gboolean initialized = FALSE;
59         
60         if (!initialized) {
61                 initialized = TRUE;
62         }
63 }
64
65 void
66 empathy_chat_view_scroll_down (EmpathyChatView *view)
67 {
68         g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
69         
70         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->scroll_down) {
71                 EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->scroll_down (view);
72         }
73 }
74
75 void
76 empathy_chat_view_append_message (EmpathyChatView *view,
77                                   EmpathyMessage  *msg)
78 {
79         g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
80         
81         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->append_message) {
82                 EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->append_message (view, 
83                                                                          msg);
84         }
85 }
86
87 void
88 empathy_chat_view_append_event (EmpathyChatView *view,
89                                 const gchar    *str)
90 {
91         g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
92         
93         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->append_event) {
94                 EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->append_event (view,
95                                                                        str);
96         }
97 }
98
99 void
100 empathy_chat_view_append_button (EmpathyChatView *view,
101                                  const gchar    *message,
102                                  GtkWidget      *button1,
103                                  GtkWidget      *button2)
104 {
105         g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
106         
107         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->append_button) {
108                 EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->append_button (view, 
109                                                                         message,
110                                                                         button1,
111                                                                         button2);
112         }
113 }
114
115 void
116 empathy_chat_view_scroll (EmpathyChatView *view,
117                           gboolean        allow_scrolling)
118 {
119         g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
120         
121         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->scroll) {
122                 EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->scroll (view, 
123                                                                  allow_scrolling);
124         }
125 }
126
127 gboolean
128 empathy_chat_view_get_selection_bounds (EmpathyChatView *view,
129                                         GtkTextIter    *start,
130                                         GtkTextIter    *end)
131 {
132         g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), FALSE);
133         
134         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->get_selection_bounds) {
135                 return EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->get_selection_bounds (view, 
136                                                                                       start, 
137                                                                                       end);
138         }
139         return FALSE;
140 }
141
142 void
143 empathy_chat_view_clear (EmpathyChatView *view)
144 {
145         g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
146         
147         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->clear) {
148                 EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->clear (view);
149         }
150 }
151
152 gboolean
153 empathy_chat_view_find_previous (EmpathyChatView *view,
154                                  const gchar    *search_criteria,
155                                  gboolean        new_search)
156 {
157         g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), FALSE);
158         
159         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->find_previous) {
160                 return EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->find_previous (view, 
161                                                                                search_criteria, 
162                                                                                new_search);
163         }
164         return FALSE;
165 }
166
167 gboolean
168 empathy_chat_view_find_next (EmpathyChatView *view,
169                              const gchar    *search_criteria,
170                              gboolean        new_search)
171 {
172         g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), FALSE);
173         
174         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->find_next) {
175                 return EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->find_next (view, 
176                                                                            search_criteria, 
177                                                                            new_search);
178         }
179         return FALSE;
180 }
181
182
183 void
184 empathy_chat_view_find_abilities (EmpathyChatView *view,
185                                   const gchar    *search_criteria,
186                                   gboolean       *can_do_previous,
187                                   gboolean       *can_do_next)
188 {
189         g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
190         
191         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->find_abilities) {
192                 EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->find_abilities (view, 
193                                                                          search_criteria, 
194                                                                          can_do_previous, 
195                                                                          can_do_next);
196         }
197 }
198
199 void
200 empathy_chat_view_highlight (EmpathyChatView *view,
201                              const gchar     *text)
202 {
203         g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
204         
205         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->highlight) {
206                 EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->highlight (view, text);
207         }
208 }
209
210 void
211 empathy_chat_view_copy_clipboard (EmpathyChatView *view)
212 {
213         g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
214         
215         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->copy_clipboard) {
216                 EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->copy_clipboard (view);
217         }
218 }
219
220 EmpathyTheme *
221 empathy_chat_view_get_theme (EmpathyChatView *view)
222 {
223         g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), NULL);
224         
225         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->get_theme) {
226                 return EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->get_theme (view);
227         }
228         return NULL;
229 }
230
231 void
232 empathy_chat_view_set_theme (EmpathyChatView *view, EmpathyTheme *theme)
233 {
234         g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
235         
236         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->set_theme) {
237                 EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->set_theme (view, theme);
238         }
239 }
240
241 void
242 empathy_chat_view_set_margin (EmpathyChatView *view,
243                               gint            margin)
244 {
245         g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
246         
247         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->set_margin) {
248                 EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->set_margin (view, margin);
249         }
250 }
251
252 time_t
253 empathy_chat_view_get_last_timestamp (EmpathyChatView *view)
254 {
255         g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), 0);
256         
257         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->get_last_timestamp) {
258                 return EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->get_last_timestamp (view);
259         }
260         return 0;
261 }
262
263 void
264 empathy_chat_view_set_last_timestamp (EmpathyChatView *view,
265                                       time_t          timestamp)
266 {
267         g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
268         
269         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->set_last_timestamp) {
270                 EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->set_last_timestamp (view, timestamp);
271         }
272 }
273
274 EmpathyContact *
275 empathy_chat_view_get_last_contact (EmpathyChatView *view)
276 {
277         g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), NULL);
278         
279         if (EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->get_last_contact) {
280                 return EMPATHY_TYPE_CHAT_VIEW_GET_IFACE (view)->get_last_contact (view);
281         }
282         return NULL;
283 }
284
285 /* Pads a pixbuf to the specified size, by centering it in a larger transparent
286  * pixbuf. Returns a new ref.
287  */
288 static GdkPixbuf *
289 chat_view_pad_to_size (GdkPixbuf *pixbuf,
290                        gint       width,
291                        gint       height,
292                        gint       extra_padding_right)
293 {
294         gint       src_width, src_height;
295         GdkPixbuf *padded;
296         gint       x_offset, y_offset;
297
298         src_width = gdk_pixbuf_get_width (pixbuf);
299         src_height = gdk_pixbuf_get_height (pixbuf);
300
301         x_offset = (width - src_width) / 2;
302         y_offset = (height - src_height) / 2;
303
304         padded = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pixbuf),
305                                  TRUE, /* alpha */
306                                  gdk_pixbuf_get_bits_per_sample (pixbuf),
307                                  width + extra_padding_right,
308                                  height);
309
310         gdk_pixbuf_fill (padded, 0);
311
312         gdk_pixbuf_copy_area (pixbuf,
313                               0, /* source coords */
314                               0,
315                               src_width,
316                               src_height,
317                               padded,
318                               x_offset, /* dest coords */
319                               y_offset);
320
321         return padded;
322 }
323
324 typedef struct {
325         GdkPixbuf *pixbuf;
326         gchar     *token;
327 } AvatarData;
328
329 static void
330 chat_view_avatar_cache_data_free (gpointer ptr)
331 {
332         AvatarData *data = ptr;
333
334         g_object_unref (data->pixbuf);
335         g_free (data->token);
336         g_slice_free (AvatarData, data);
337 }
338
339 GdkPixbuf *
340 empathy_chat_view_get_avatar_pixbuf_with_cache (EmpathyContact *contact)
341 {
342         AvatarData        *data;
343         EmpathyAvatar     *avatar;
344         GdkPixbuf         *tmp_pixbuf;
345         GdkPixbuf         *pixbuf = NULL;
346
347         /* Check if avatar is in cache and if it's up to date */
348         avatar = empathy_contact_get_avatar (contact);
349         data = g_object_get_data (G_OBJECT (contact), "chat-view-avatar-cache");
350         if (data) {
351                 if (avatar && !tp_strdiff (avatar->token, data->token)) {
352                         /* We have the avatar in cache */
353                         return data->pixbuf;
354                 }
355         }
356
357         /* Avatar not in cache, create pixbuf */
358         tmp_pixbuf = empathy_pixbuf_avatar_from_contact_scaled (contact, 32, 32);
359         if (tmp_pixbuf) {
360                 pixbuf = chat_view_pad_to_size (tmp_pixbuf, 32, 32, 6);
361                 g_object_unref (tmp_pixbuf);
362         }
363         if (!pixbuf) {
364                 return NULL;
365         }
366
367         /* Insert new pixbuf in cache */
368         data = g_slice_new0 (AvatarData);
369         data->token = g_strdup (avatar->token);
370         data->pixbuf = pixbuf;
371
372         g_object_set_data_full (G_OBJECT (contact), "chat-view-avatar-cache",
373                                 data, chat_view_avatar_cache_data_free);
374
375         return data->pixbuf;
376 }
377
378 GtkWidget *
379 empathy_chat_view_get_smiley_menu (GCallback    callback,
380                                    gpointer     user_data)
381 {
382         EmpathySmileyManager *smiley_manager;
383         GSList               *smileys, *l;
384         GtkWidget            *menu;
385         gint                  x = 0;
386         gint                  y = 0;
387
388         g_return_val_if_fail (callback != NULL, NULL);
389
390         menu = gtk_menu_new ();
391
392         smiley_manager = empathy_smiley_manager_new ();
393         smileys = empathy_smiley_manager_get_all (smiley_manager);
394         for (l = smileys; l; l = l->next) {
395                 EmpathySmiley *smiley;
396                 GtkWidget     *item;
397                 GtkWidget     *image;
398
399                 smiley = l->data;
400                 image = gtk_image_new_from_pixbuf (smiley->pixbuf);
401
402                 item = gtk_image_menu_item_new_with_label ("");
403                 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
404
405                 gtk_menu_attach (GTK_MENU (menu), item,
406                                  x, x + 1, y, y + 1);
407
408                 gtk_widget_set_tooltip_text (item, smiley->str);
409
410                 g_object_set_data  (G_OBJECT (item), "smiley_text", smiley->str);
411                 g_signal_connect (item, "activate", callback, user_data);
412
413                 if (x > 3) {
414                         y++;
415                         x = 0;
416                 } else {
417                         x++;
418                 }
419         }
420         g_object_unref (smiley_manager);
421
422         gtk_widget_show_all (menu);
423
424         return menu;
425 }
426