pidgin/pidginconversationwindow.c

changeset 41184
05b5c210352b
parent 41030
ec8b76f3bf0a
child 41186
f8275d257afe
equal deleted inserted replaced
41183:c1e62681c843 41184:05b5c210352b
20 * along with this program; if not, see <https://www.gnu.org/licenses/>. 20 * along with this program; if not, see <https://www.gnu.org/licenses/>.
21 */ 21 */
22 22
23 #include "pidginconversationwindow.h" 23 #include "pidginconversationwindow.h"
24 24
25 #include "gtkconv.h"
26
27 enum {
28 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT,
29 PIDGIN_CONVERSATION_WINDOW_COLUMN_ICON,
30 PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP,
31 };
32
33 enum {
34 SIG_CONVERSATION_SWITCHED,
35 N_SIGNALS,
36 };
37 static guint signals[N_SIGNALS] = {0, };
38
25 struct _PidginConversationWindow { 39 struct _PidginConversationWindow {
26 GtkApplicationWindow parent; 40 GtkApplicationWindow parent;
27 41
28 GtkWidget *vbox; 42 GtkWidget *vbox;
43
44 GtkWidget *view;
45 GtkTreeStore *model;
46
47 GtkWidget *stack;
29 }; 48 };
30 49
31 G_DEFINE_TYPE(PidginConversationWindow, pidgin_conversation_window, 50 G_DEFINE_TYPE(PidginConversationWindow, pidgin_conversation_window,
32 GTK_TYPE_APPLICATION_WINDOW) 51 GTK_TYPE_APPLICATION_WINDOW)
52
53 static GtkWidget *default_window = NULL;
54
55 /******************************************************************************
56 * Callbacks
57 *****************************************************************************/
58 static void
59 pidgin_conversation_window_selection_changed(GtkTreeSelection *selection,
60 gpointer data)
61 {
62 PidginConversationWindow *window = PIDGIN_CONVERSATION_WINDOW(data);
63 GtkTreeModel *model = NULL;
64 GtkTreeIter iter;
65 gboolean changed = FALSE;
66
67 if(gtk_tree_selection_get_selected(selection, &model, &iter)) {
68 gchar *markup = NULL;
69
70 gtk_tree_model_get(model, &iter,
71 PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, &markup,
72 -1);
73
74 gtk_stack_set_visible_child_name(GTK_STACK(window->stack), markup);
75 g_free(markup);
76
77 changed = TRUE;
78 }
79
80 if(!changed) {
81 gtk_stack_set_visible_child_name(GTK_STACK(window->stack), "__empty__");
82 }
83 }
84
85 static gboolean
86 pidgin_conversation_window_foreach_destroy(GtkTreeModel *model,
87 GtkTreePath *path,
88 GtkTreeIter *iter,
89 gpointer data)
90 {
91 PurpleConversation *conversation = NULL;
92
93 gtk_tree_model_get(model, iter,
94 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, &conversation,
95 -1);
96
97 if(conversation != NULL) {
98 pidgin_conversation_detach(conversation);
99
100 gtk_list_store_remove(GTK_LIST_STORE(model), iter);
101 }
102
103 return FALSE;
104 }
33 105
34 /****************************************************************************** 106 /******************************************************************************
35 * GObjectImplementation 107 * GObjectImplementation
36 *****************************************************************************/ 108 *****************************************************************************/
109 static void
110 pidgin_conversation_window_dispose(GObject *obj) {
111 PidginConversationWindow *window = PIDGIN_CONVERSATION_WINDOW(obj);
112
113 if(GTK_IS_TREE_MODEL(window->model)) {
114 gtk_tree_model_foreach(GTK_TREE_MODEL(window->model),
115 pidgin_conversation_window_foreach_destroy, window);
116 }
117
118 G_OBJECT_CLASS(pidgin_conversation_window_parent_class)->dispose(obj);
119 }
120
37 static void 121 static void
38 pidgin_conversation_window_init(PidginConversationWindow *window) { 122 pidgin_conversation_window_init(PidginConversationWindow *window) {
39 GtkBuilder *builder = NULL; 123 GtkBuilder *builder = NULL;
40 GtkWidget *menubar = NULL; 124 GtkWidget *menubar = NULL;
41 GMenuModel *model = NULL; 125 GMenuModel *model = NULL;
48 /* setup our menu */ 132 /* setup our menu */
49 builder = gtk_builder_new_from_resource("/im/pidgin/Pidgin3/Conversations/menu.ui"); 133 builder = gtk_builder_new_from_resource("/im/pidgin/Pidgin3/Conversations/menu.ui");
50 134
51 model = (GMenuModel *)gtk_builder_get_object(builder, "conversation"); 135 model = (GMenuModel *)gtk_builder_get_object(builder, "conversation");
52 menubar = gtk_menu_bar_new_from_model(model); 136 menubar = gtk_menu_bar_new_from_model(model);
137
53 gtk_box_pack_start(GTK_BOX(window->vbox), menubar, FALSE, FALSE, 0); 138 gtk_box_pack_start(GTK_BOX(window->vbox), menubar, FALSE, FALSE, 0);
54 gtk_widget_show(menubar); 139 gtk_widget_show(menubar);
55 140
56 g_object_unref(G_OBJECT(builder)); 141 g_object_unref(G_OBJECT(builder));
57 } 142 }
58 143
59 static void 144 static void
60 pidgin_conversation_window_class_init(PidginConversationWindowClass *klass) { 145 pidgin_conversation_window_class_init(PidginConversationWindowClass *klass) {
146 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
61 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); 147 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
148
149 obj_class->dispose = pidgin_conversation_window_dispose;
150
151 signals[SIG_CONVERSATION_SWITCHED] = g_signal_new_class_handler(
152 "conversation-switched",
153 G_OBJECT_CLASS_TYPE(obj_class),
154 G_SIGNAL_RUN_LAST,
155 NULL,
156 NULL,
157 NULL,
158 NULL,
159 G_TYPE_NONE,
160 1,
161 PURPLE_TYPE_CONVERSATION
162 );
62 163
63 gtk_widget_class_set_template_from_resource( 164 gtk_widget_class_set_template_from_resource(
64 widget_class, 165 widget_class,
65 "/im/pidgin/Pidgin3/Conversations/window.ui" 166 "/im/pidgin/Pidgin3/Conversations/window.ui"
66 ); 167 );
67 168
68 gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow, 169 gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow,
69 vbox); 170 vbox);
171
172 gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow,
173 model);
174 gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow,
175 view);
176
177 gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow,
178 stack);
179
180 gtk_widget_class_bind_template_callback(widget_class,
181 pidgin_conversation_window_selection_changed);
70 } 182 }
71 183
72 /****************************************************************************** 184 /******************************************************************************
73 * API 185 * API
74 *****************************************************************************/ 186 *****************************************************************************/
75 GtkWidget * 187 GtkWidget *
188 pidgin_conversation_window_get_default(void) {
189 if(!GTK_IS_WIDGET(default_window)) {
190 default_window = pidgin_conversation_window_new();
191 g_object_add_weak_pointer(G_OBJECT(default_window),
192 (gpointer)&default_window);
193 }
194
195 return default_window;
196 }
197
198 GtkWidget *
76 pidgin_conversation_window_new(void) { 199 pidgin_conversation_window_new(void) {
77 return GTK_WIDGET(g_object_new(PIDGIN_TYPE_CONVERSATION_WINDOW, NULL)); 200 return GTK_WIDGET(g_object_new(PIDGIN_TYPE_CONVERSATION_WINDOW, NULL));
78 } 201 }
79 202
80 GtkWidget * 203 void
81 pidgin_conversation_window_get_vbox(PidginConversationWindow *window) { 204 pidgin_conversation_window_add(PidginConversationWindow *window,
205 PurpleConversation *conversation)
206 {
207 PidginConversation *gtkconv = NULL;
208 GtkTreeIter iter;
209 const gchar *markup = NULL;
210
211 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window));
212 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation));
213
214 markup = purple_conversation_get_name(conversation);
215
216 gtkconv = PIDGIN_CONVERSATION(conversation);
217 if(gtkconv != NULL) {
218 GtkWidget *parent = gtk_widget_get_parent(gtkconv->tab_cont);
219
220 if(GTK_IS_WIDGET(parent)) {
221 g_object_ref(gtkconv->tab_cont);
222 gtk_container_remove(GTK_CONTAINER(parent), gtkconv->tab_cont);
223 }
224
225 gtk_stack_add_named(GTK_STACK(window->stack), gtkconv->tab_cont, markup);
226 gtk_widget_show_all(gtkconv->tab_cont);
227
228 if(GTK_IS_WIDGET(parent)) {
229 g_object_unref(gtkconv->tab_cont);
230 }
231 }
232
233 gtk_tree_store_prepend(window->model, &iter, NULL);
234 gtk_tree_store_set(window->model, &iter,
235 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, conversation,
236 PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, markup,
237 -1);
238
239 if(!gtk_widget_is_visible(GTK_WIDGET(window))) {
240 gtk_widget_show_all(GTK_WIDGET(window));
241 }
242 }
243
244 void
245 pidgin_conversation_window_remove(PidginConversationWindow *window,
246 PurpleConversation *conversation)
247 {
248 GtkTreeIter iter;
249 GObject *obj = NULL;
250
251 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window));
252 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation));
253
254 if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(window->model), &iter)) {
255 /* The tree is empty. */
256 return;
257 }
258
259 do {
260 gtk_tree_model_get(GTK_TREE_MODEL(window->model), &iter,
261 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, &obj,
262 -1);
263
264 if(PURPLE_CONVERSATION(obj) == conversation) {
265 gtk_tree_store_remove(window->model, &iter);
266
267 g_clear_object(&obj);
268
269 break;
270 }
271
272 g_clear_object(&obj);
273 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(window->model), &iter));
274 }
275
276 guint
277 pidgin_conversation_window_get_count(PidginConversationWindow *window) {
278 GList *children = NULL;
279 guint count = 0;
280
281 g_return_val_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window), 0);
282
283 children = gtk_container_get_children(GTK_CONTAINER(window));
284 while(children != NULL) {
285 children = g_list_delete_link(children, children);
286 count++;
287 }
288
289 return count;
290 }
291
292 PurpleConversation *
293 pidgin_conversation_window_get_selected(PidginConversationWindow *window) {
294 PurpleConversation *conversation = NULL;
295 GtkTreeSelection *selection = NULL;
296 GtkTreeIter iter;
297
82 g_return_val_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window), NULL); 298 g_return_val_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window), NULL);
83 299
84 return window->vbox; 300 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(window->view));
85 } 301 if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
302
303 gtk_tree_model_get(GTK_TREE_MODEL(window->model), &iter,
304 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, &conversation,
305 -1);
306 }
307
308 return conversation;
309 }
310
311 void
312 pidgin_conversation_window_select(PidginConversationWindow *window,
313 PurpleConversation *conversation)
314 {
315 const gchar *name = NULL;
316
317 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window));
318 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation));
319
320 name = purple_conversation_get_name(conversation);
321 gtk_stack_set_visible_child_name(GTK_STACK(window->stack), name);
322 }
323
324 void
325 pidgin_conversation_window_select_previous(PidginConversationWindow *window) {
326 GtkTreeIter iter;
327 GtkTreeModel *model = NULL;
328 GtkTreeSelection *selection = NULL;
329 gboolean set = FALSE;
330
331 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window));
332
333 model = GTK_TREE_MODEL(window->model);
334
335 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(window->view));
336 if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
337 if(gtk_tree_model_iter_previous(model, &iter)) {
338 gtk_tree_selection_select_iter(selection, &iter);
339 set = TRUE;
340 }
341 }
342
343 if(!set) {
344 pidgin_conversation_window_select_last(window);
345 }
346 }
347
348
349 void
350 pidgin_conversation_window_select_next(PidginConversationWindow *window) {
351 GtkTreeIter iter;
352 GtkTreeModel *model = NULL;
353 GtkTreeSelection *selection = NULL;
354 gboolean set = FALSE;
355
356 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window));
357
358 model = GTK_TREE_MODEL(window->model);
359
360 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(window->view));
361 if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
362 if(gtk_tree_model_iter_next(model, &iter)) {
363 gtk_tree_selection_select_iter(selection, &iter);
364 set = TRUE;
365 }
366 }
367
368 if(!set) {
369 pidgin_conversation_window_select_first(window);
370 }
371 }
372
373 void
374 pidgin_conversation_window_select_first(PidginConversationWindow *window) {
375 GtkTreeIter iter;
376 GtkTreeModel *model = NULL;
377
378 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window));
379
380 model = GTK_TREE_MODEL(window->model);
381
382 if(gtk_tree_model_get_iter_first(model, &iter)) {
383 GtkTreeSelection *selection = NULL;
384
385 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(window->view));
386 gtk_tree_selection_select_iter(selection, &iter);
387 }
388 }
389
390 void
391 pidgin_conversation_window_select_last(PidginConversationWindow *window) {
392 GtkTreeIter iter;
393 GtkTreeModel *model = NULL;
394 gint count = 0;
395
396 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window));
397
398 model = GTK_TREE_MODEL(window->model);
399 count = gtk_tree_model_iter_n_children(model, NULL);
400
401 if(gtk_tree_model_iter_nth_child(model, &iter, NULL, count - 1)) {
402 GtkTreeSelection *selection = NULL;
403
404 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(window->view));
405 gtk_tree_selection_select_iter(selection, &iter);
406 }
407 }
408
409 void
410 pidgin_conversation_window_select_nth(PidginConversationWindow *window,
411 guint nth)
412 {
413 GtkTreeIter iter;
414 GtkTreeModel *model = NULL;
415
416 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window));
417
418 model = GTK_TREE_MODEL(window->model);
419
420 if(gtk_tree_model_iter_nth_child(model, &iter, NULL, nth)) {
421 GtkTreeSelection *selection = NULL;
422
423 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(window->view));
424 gtk_tree_selection_select_iter(selection, &iter);
425 }
426 }
427
428 gboolean
429 pidgin_conversation_window_conversation_is_selected(PidginConversationWindow *window,
430 PurpleConversation *conversation)
431 {
432 const gchar *name = NULL, *visible = NULL;
433
434 g_return_val_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window), FALSE);
435 g_return_val_if_fail(PURPLE_IS_CONVERSATION(conversation), FALSE);
436
437 name = purple_conversation_get_name(conversation);
438 visible = gtk_stack_get_visible_child_name(GTK_STACK(window->stack));
439
440 return purple_strequal(name, visible);
441 }

mercurial