pidgin/pidginconversationwindow.c

changeset 41254
ef50e0dc74b0
parent 41252
aaa984be3a68
child 41441
e114ed471a1e
equal deleted inserted replaced
41252:aaa984be3a68 41254:ef50e0dc74b0
18 * 18 *
19 * You should have received a copy of the GNU General Public License 19 * You should have received a copy of the GNU General Public License
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 <glib/gi18n-lib.h>
24
23 #include "pidginconversationwindow.h" 25 #include "pidginconversationwindow.h"
24 26
25 #include "gtkconv.h" 27 #include "gtkconv.h"
26 28
27 enum { 29 enum {
43 45
44 GtkWidget *view; 46 GtkWidget *view;
45 GtkTreeStore *model; 47 GtkTreeStore *model;
46 48
47 GtkWidget *stack; 49 GtkWidget *stack;
50
51 GtkTreePath *conversation_path;
48 }; 52 };
49 53
50 G_DEFINE_TYPE(PidginConversationWindow, pidgin_conversation_window, 54 G_DEFINE_TYPE(PidginConversationWindow, pidgin_conversation_window,
51 GTK_TYPE_APPLICATION_WINDOW) 55 GTK_TYPE_APPLICATION_WINDOW)
52 56
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);
304 349
305 break; 350 break;
306 } 351 }
307 352
308 g_clear_object(&obj); 353 g_clear_object(&obj);
309 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(window->model), &iter)); 354 } while(gtk_tree_model_iter_next(model, &iter));
310 } 355 }
311 356
312 guint 357 guint
313 pidgin_conversation_window_get_count(PidginConversationWindow *window) { 358 pidgin_conversation_window_get_count(PidginConversationWindow *window) {
314 GList *children = NULL; 359 GList *children = NULL;

mercurial