| 78 } |
82 } |
| 79 |
83 |
| 80 if(!changed) { |
84 if(!changed) { |
| 81 gtk_stack_set_visible_child_name(GTK_STACK(window->stack), "__empty__"); |
85 gtk_stack_set_visible_child_name(GTK_STACK(window->stack), "__empty__"); |
| 82 } |
86 } |
| 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 } |
87 } |
| 105 |
88 |
| 106 static gboolean |
89 static gboolean |
| 107 pidgin_conversation_window_key_pressed_cb(GtkEventControllerKey *controller, |
90 pidgin_conversation_window_key_pressed_cb(GtkEventControllerKey *controller, |
| 108 guint keyval, |
91 guint keyval, |
| 150 static void |
133 static void |
| 151 pidgin_conversation_window_dispose(GObject *obj) { |
134 pidgin_conversation_window_dispose(GObject *obj) { |
| 152 PidginConversationWindow *window = PIDGIN_CONVERSATION_WINDOW(obj); |
135 PidginConversationWindow *window = PIDGIN_CONVERSATION_WINDOW(obj); |
| 153 |
136 |
| 154 if(GTK_IS_TREE_MODEL(window->model)) { |
137 if(GTK_IS_TREE_MODEL(window->model)) { |
| 155 gtk_tree_model_foreach(GTK_TREE_MODEL(window->model), |
138 GtkTreeModel *model = GTK_TREE_MODEL(window->model); |
| 156 pidgin_conversation_window_foreach_destroy, window); |
139 GtkTreeIter parent, iter; |
| |
140 |
| |
141 gtk_tree_model_get_iter(model, &parent, window->conversation_path); |
| |
142 if(gtk_tree_model_iter_children(model, &iter, &parent)) { |
| |
143 gboolean valid = FALSE; |
| |
144 |
| |
145 /* gtk_tree_store_remove moves the iter to the next item at the |
| |
146 * same level, so we abuse that to do our iteration. |
| |
147 */ |
| |
148 do { |
| |
149 PurpleConversation *conversation = NULL; |
| |
150 |
| |
151 gtk_tree_model_get(model, &iter, |
| |
152 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, &conversation, |
| |
153 -1); |
| |
154 |
| |
155 if(PURPLE_IS_CONVERSATION(conversation)) { |
| |
156 pidgin_conversation_detach(conversation); |
| |
157 |
| |
158 valid = gtk_tree_store_remove(window->model, &iter); |
| |
159 } |
| |
160 } while(valid); |
| |
161 } |
| |
162 |
| |
163 g_clear_pointer(&window->conversation_path, gtk_tree_path_free); |
| 157 } |
164 } |
| 158 |
165 |
| 159 G_OBJECT_CLASS(pidgin_conversation_window_parent_class)->dispose(obj); |
166 G_OBJECT_CLASS(pidgin_conversation_window_parent_class)->dispose(obj); |
| 160 } |
167 } |
| 161 |
168 |
| 162 static void |
169 static void |
| 163 pidgin_conversation_window_init(PidginConversationWindow *window) { |
170 pidgin_conversation_window_init(PidginConversationWindow *window) { |
| 164 GtkEventController *key = NULL; |
171 GtkEventController *key = NULL; |
| |
172 GtkTreeIter iter; |
| 165 |
173 |
| 166 gtk_widget_init_template(GTK_WIDGET(window)); |
174 gtk_widget_init_template(GTK_WIDGET(window)); |
| 167 |
175 |
| 168 gtk_window_set_application(GTK_WINDOW(window), |
176 gtk_window_set_application(GTK_WINDOW(window), |
| 169 GTK_APPLICATION(g_application_get_default())); |
177 GTK_APPLICATION(g_application_get_default())); |
| 173 g_signal_connect(G_OBJECT(key), "key-pressed", |
181 g_signal_connect(G_OBJECT(key), "key-pressed", |
| 174 G_CALLBACK(pidgin_conversation_window_key_pressed_cb), |
182 G_CALLBACK(pidgin_conversation_window_key_pressed_cb), |
| 175 window); |
183 window); |
| 176 g_object_set_data_full(G_OBJECT(window), "key-press-controller", key, |
184 g_object_set_data_full(G_OBJECT(window), "key-press-controller", key, |
| 177 g_object_unref); |
185 g_object_unref); |
| |
186 |
| |
187 /* Add our toplevels to the tree store. */ |
| |
188 gtk_tree_store_append(window->model, &iter, NULL); |
| |
189 gtk_tree_store_set(window->model, &iter, |
| |
190 PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, _("Conversations"), |
| |
191 -1); |
| |
192 window->conversation_path = gtk_tree_model_get_path(GTK_TREE_MODEL(window->model), |
| |
193 &iter); |
| 178 } |
194 } |
| 179 |
195 |
| 180 static void |
196 static void |
| 181 pidgin_conversation_window_class_init(PidginConversationWindowClass *klass) { |
197 pidgin_conversation_window_class_init(PidginConversationWindowClass *klass) { |
| 182 GObjectClass *obj_class = G_OBJECT_CLASS(klass); |
198 GObjectClass *obj_class = G_OBJECT_CLASS(klass); |
| 239 void |
255 void |
| 240 pidgin_conversation_window_add(PidginConversationWindow *window, |
256 pidgin_conversation_window_add(PidginConversationWindow *window, |
| 241 PurpleConversation *conversation) |
257 PurpleConversation *conversation) |
| 242 { |
258 { |
| 243 PidginConversation *gtkconv = NULL; |
259 PidginConversation *gtkconv = NULL; |
| 244 GtkTreeIter iter; |
260 GtkTreeIter parent, iter; |
| |
261 GtkTreeModel *model = NULL; |
| 245 const gchar *markup = NULL; |
262 const gchar *markup = NULL; |
| |
263 gboolean expand = FALSE; |
| 246 |
264 |
| 247 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window)); |
265 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window)); |
| 248 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation)); |
266 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation)); |
| |
267 |
| |
268 model = GTK_TREE_MODEL(window->model); |
| |
269 if(!gtk_tree_model_get_iter(model, &parent, window->conversation_path)) { |
| |
270 /* If we can't find the conversation_path we have to bail. */ |
| |
271 g_warning("couldn't get an iterator to conversation_path"); |
| |
272 |
| |
273 return; |
| |
274 } |
| |
275 |
| |
276 if(!gtk_tree_model_iter_has_child(model, &parent)) { |
| |
277 expand = TRUE; |
| |
278 } |
| 249 |
279 |
| 250 markup = purple_conversation_get_name(conversation); |
280 markup = purple_conversation_get_name(conversation); |
| 251 |
281 |
| 252 gtkconv = PIDGIN_CONVERSATION(conversation); |
282 gtkconv = PIDGIN_CONVERSATION(conversation); |
| 253 if(gtkconv != NULL) { |
283 if(gtkconv != NULL) { |
| 264 if(GTK_IS_WIDGET(parent)) { |
294 if(GTK_IS_WIDGET(parent)) { |
| 265 g_object_unref(gtkconv->tab_cont); |
295 g_object_unref(gtkconv->tab_cont); |
| 266 } |
296 } |
| 267 } |
297 } |
| 268 |
298 |
| 269 gtk_tree_store_prepend(window->model, &iter, NULL); |
299 gtk_tree_store_prepend(window->model, &iter, &parent); |
| 270 gtk_tree_store_set(window->model, &iter, |
300 gtk_tree_store_set(window->model, &iter, |
| 271 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, conversation, |
301 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, conversation, |
| 272 PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, markup, |
302 PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, markup, |
| 273 -1); |
303 -1); |
| 274 |
304 |
| |
305 /* If we just added the first child, expand the parent. */ |
| |
306 if(expand) { |
| |
307 gtk_tree_view_expand_row(GTK_TREE_VIEW(window->view), |
| |
308 window->conversation_path, FALSE); |
| |
309 } |
| |
310 |
| |
311 |
| 275 if(!gtk_widget_is_visible(GTK_WIDGET(window))) { |
312 if(!gtk_widget_is_visible(GTK_WIDGET(window))) { |
| 276 gtk_widget_show_all(GTK_WIDGET(window)); |
313 gtk_widget_show_all(GTK_WIDGET(window)); |
| 277 } |
314 } |
| 278 } |
315 } |
| 279 |
316 |
| 280 void |
317 void |
| 281 pidgin_conversation_window_remove(PidginConversationWindow *window, |
318 pidgin_conversation_window_remove(PidginConversationWindow *window, |
| 282 PurpleConversation *conversation) |
319 PurpleConversation *conversation) |
| 283 { |
320 { |
| 284 GtkTreeIter iter; |
321 GtkTreeIter parent, iter; |
| |
322 GtkTreeModel *model = NULL; |
| 285 GObject *obj = NULL; |
323 GObject *obj = NULL; |
| 286 |
324 |
| 287 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window)); |
325 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window)); |
| 288 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation)); |
326 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation)); |
| 289 |
327 |
| 290 if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(window->model), &iter)) { |
328 model = GTK_TREE_MODEL(window->model); |
| 291 /* The tree is empty. */ |
329 |
| |
330 if(!gtk_tree_model_get_iter(model, &parent, window->conversation_path)) { |
| |
331 /* The path is somehow invalid, so bail... */ |
| 292 return; |
332 return; |
| 293 } |
333 } |
| 294 |
334 |
| |
335 if(!gtk_tree_model_iter_children(model, &iter, &parent)) { |
| |
336 /* The conversations iter has no children. */ |
| |
337 return; |
| |
338 } |
| |
339 |
| 295 do { |
340 do { |
| 296 gtk_tree_model_get(GTK_TREE_MODEL(window->model), &iter, |
341 gtk_tree_model_get(model, &iter, |
| 297 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, &obj, |
342 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, &obj, |
| 298 -1); |
343 -1); |
| 299 |
344 |
| 300 if(PURPLE_CONVERSATION(obj) == conversation) { |
345 if(PURPLE_CONVERSATION(obj) == conversation) { |
| 301 gtk_tree_store_remove(window->model, &iter); |
346 gtk_tree_store_remove(window->model, &iter); |