| 28 #include "gtkdialogs.h" |
28 #include "gtkdialogs.h" |
| 29 #include "gtkutils.h" |
29 #include "gtkutils.h" |
| 30 #include "pidgininvitedialog.h" |
30 #include "pidgininvitedialog.h" |
| 31 |
31 |
| 32 enum { |
32 enum { |
| 33 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, |
33 PIDGIN_DISPLAY_WINDOW_COLUMN_OBJECT, |
| 34 PIDGIN_CONVERSATION_WINDOW_COLUMN_NAME, |
34 PIDGIN_DISPLAY_WINDOW_COLUMN_NAME, |
| 35 PIDGIN_CONVERSATION_WINDOW_COLUMN_ICON, |
35 PIDGIN_DISPLAY_WINDOW_COLUMN_ICON, |
| 36 PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, |
36 PIDGIN_DISPLAY_WINDOW_COLUMN_MARKUP, |
| 37 }; |
37 }; |
| 38 |
38 |
| 39 enum { |
39 enum { |
| 40 SIG_CONVERSATION_SWITCHED, |
40 SIG_CONVERSATION_SWITCHED, |
| 41 N_SIGNALS, |
41 N_SIGNALS, |
| 42 }; |
42 }; |
| 43 static guint signals[N_SIGNALS] = {0, }; |
43 static guint signals[N_SIGNALS] = {0, }; |
| 44 |
44 |
| 45 struct _PidginConversationWindow { |
45 struct _PidginDisplayWindow { |
| 46 GtkApplicationWindow parent; |
46 GtkApplicationWindow parent; |
| 47 |
47 |
| 48 GtkWidget *vbox; |
48 GtkWidget *vbox; |
| 49 |
49 |
| 50 GtkWidget *view; |
50 GtkWidget *view; |
| 56 GtkWidget *notification_list; |
56 GtkWidget *notification_list; |
| 57 |
57 |
| 58 GtkTreePath *conversation_path; |
58 GtkTreePath *conversation_path; |
| 59 }; |
59 }; |
| 60 |
60 |
| 61 G_DEFINE_TYPE(PidginConversationWindow, pidgin_conversation_window, |
61 G_DEFINE_TYPE(PidginDisplayWindow, pidgin_display_window, |
| 62 GTK_TYPE_APPLICATION_WINDOW) |
62 GTK_TYPE_APPLICATION_WINDOW) |
| 63 |
63 |
| 64 static GtkWidget *default_window = NULL; |
64 static GtkWidget *default_window = NULL; |
| 65 |
65 |
| 66 /****************************************************************************** |
66 /****************************************************************************** |
| 67 * Helpers |
67 * Helpers |
| 68 *****************************************************************************/ |
68 *****************************************************************************/ |
| 69 static void |
69 static void |
| 70 pidgin_conversation_window_actions_set_enabled(GActionMap *map, |
70 pidgin_display_window_actions_set_enabled(GActionMap *map, |
| 71 const gchar **actions, |
71 const gchar **actions, |
| 72 gboolean enabled) |
72 gboolean enabled) |
| 73 { |
73 { |
| 74 gint i = 0; |
74 gint i = 0; |
| 75 |
75 |
| 76 for(i = 0; actions[i] != NULL; i++) { |
76 for(i = 0; actions[i] != NULL; i++) { |
| 77 GAction *action = NULL; |
77 GAction *action = NULL; |
| 121 |
121 |
| 122 /****************************************************************************** |
122 /****************************************************************************** |
| 123 * Actions |
123 * Actions |
| 124 *****************************************************************************/ |
124 *****************************************************************************/ |
| 125 static void |
125 static void |
| 126 pidgin_conversation_window_alias(G_GNUC_UNUSED GSimpleAction *simple, |
126 pidgin_display_window_alias(G_GNUC_UNUSED GSimpleAction *simple, |
| 127 G_GNUC_UNUSED GVariant *parameter, |
127 G_GNUC_UNUSED GVariant *parameter, |
| 128 gpointer data) |
128 gpointer data) |
| 129 { |
129 { |
| 130 PidginConversationWindow *window = data; |
130 PidginDisplayWindow *window = data; |
| 131 PurpleConversation *selected = NULL; |
131 PurpleConversation *selected = NULL; |
| 132 |
132 |
| 133 selected = pidgin_conversation_window_get_selected(window); |
133 selected = pidgin_display_window_get_selected(window); |
| 134 if(PURPLE_IS_CONVERSATION(selected)) { |
134 if(PURPLE_IS_CONVERSATION(selected)) { |
| 135 PurpleAccount *account; |
135 PurpleAccount *account; |
| 136 const gchar *name; |
136 const gchar *name; |
| 137 |
137 |
| 138 account = purple_conversation_get_account(selected); |
138 account = purple_conversation_get_account(selected); |
| 153 } |
153 } |
| 154 } |
154 } |
| 155 } |
155 } |
| 156 |
156 |
| 157 static void |
157 static void |
| 158 pidgin_conversation_window_close_conversation(G_GNUC_UNUSED GSimpleAction *simple, |
158 pidgin_display_window_close_conversation(G_GNUC_UNUSED GSimpleAction *simple, |
| 159 G_GNUC_UNUSED GVariant *parameter, |
159 G_GNUC_UNUSED GVariant *parameter, |
| 160 gpointer data) |
160 gpointer data) |
| 161 { |
161 { |
| 162 PidginConversationWindow *window = data; |
162 PidginDisplayWindow *window = data; |
| 163 PurpleConversation *selected = NULL; |
163 PurpleConversation *selected = NULL; |
| 164 |
164 |
| 165 selected = pidgin_conversation_window_get_selected(window); |
165 selected = pidgin_display_window_get_selected(window); |
| 166 if(PURPLE_IS_CONVERSATION(selected)) { |
166 if(PURPLE_IS_CONVERSATION(selected)) { |
| 167 pidgin_conversation_window_remove(window, selected); |
167 pidgin_display_window_remove(window, selected); |
| 168 pidgin_conversation_detach(selected); |
168 pidgin_conversation_detach(selected); |
| 169 } |
169 } |
| 170 } |
170 } |
| 171 |
171 |
| 172 static void |
172 static void |
| 173 pidgin_conversation_window_get_info(G_GNUC_UNUSED GSimpleAction *simple, |
173 pidgin_display_window_get_info(G_GNUC_UNUSED GSimpleAction *simple, |
| 174 G_GNUC_UNUSED GVariant *parameter, |
174 G_GNUC_UNUSED GVariant *parameter, |
| 175 gpointer data) |
175 gpointer data) |
| 176 { |
176 { |
| 177 PidginConversationWindow *window = data; |
177 PidginDisplayWindow *window = data; |
| 178 PurpleConversation *selected = NULL; |
178 PurpleConversation *selected = NULL; |
| 179 |
179 |
| 180 selected = pidgin_conversation_window_get_selected(window); |
180 selected = pidgin_display_window_get_selected(window); |
| 181 if(PURPLE_IS_CONVERSATION(selected)) { |
181 if(PURPLE_IS_CONVERSATION(selected)) { |
| 182 if(PURPLE_IS_IM_CONVERSATION(selected)) { |
182 if(PURPLE_IS_IM_CONVERSATION(selected)) { |
| 183 PurpleConnection *connection = NULL; |
183 PurpleConnection *connection = NULL; |
| 184 |
184 |
| 185 connection = purple_conversation_get_connection(selected); |
185 connection = purple_conversation_get_connection(selected); |
| 188 } |
188 } |
| 189 } |
189 } |
| 190 } |
190 } |
| 191 |
191 |
| 192 static void |
192 static void |
| 193 pidgin_conversation_window_invite(G_GNUC_UNUSED GSimpleAction *simple, |
193 pidgin_display_window_invite(G_GNUC_UNUSED GSimpleAction *simple, |
| 194 G_GNUC_UNUSED GVariant *parameter, |
194 G_GNUC_UNUSED GVariant *parameter, |
| 195 gpointer data) |
195 gpointer data) |
| 196 { |
196 { |
| 197 PidginConversationWindow *window = data; |
197 PidginDisplayWindow *window = data; |
| 198 PurpleConversation *selected = NULL; |
198 PurpleConversation *selected = NULL; |
| 199 |
199 |
| 200 selected = pidgin_conversation_window_get_selected(window); |
200 selected = pidgin_display_window_get_selected(window); |
| 201 if(PURPLE_IS_CHAT_CONVERSATION(selected)) { |
201 if(PURPLE_IS_CHAT_CONVERSATION(selected)) { |
| 202 GtkWidget *invite_dialog = NULL; |
202 GtkWidget *invite_dialog = NULL; |
| 203 |
203 |
| 204 invite_dialog = g_object_get_data(G_OBJECT(selected), |
204 invite_dialog = g_object_get_data(G_OBJECT(selected), |
| 205 "pidgin-invite-dialog"); |
205 "pidgin-invite-dialog"); |
| 212 gtk_window_set_transient_for(GTK_WINDOW(invite_dialog), |
212 gtk_window_set_transient_for(GTK_WINDOW(invite_dialog), |
| 213 GTK_WINDOW(window)); |
213 GTK_WINDOW(window)); |
| 214 gtk_window_set_destroy_with_parent(GTK_WINDOW(invite_dialog), TRUE); |
214 gtk_window_set_destroy_with_parent(GTK_WINDOW(invite_dialog), TRUE); |
| 215 |
215 |
| 216 g_signal_connect(invite_dialog, "response", |
216 g_signal_connect(invite_dialog, "response", |
| 217 G_CALLBACK(pidgin_conversation_window_invite_cb), |
217 G_CALLBACK(pidgin_display_window_invite_cb), |
| 218 NULL); |
218 NULL); |
| 219 } |
219 } |
| 220 |
220 |
| 221 gtk_widget_show(invite_dialog); |
221 gtk_widget_show(invite_dialog); |
| 222 } |
222 } |
| 223 } |
223 } |
| 224 |
224 |
| 225 static void |
225 static void |
| 226 pidgin_conversation_window_send_file(G_GNUC_UNUSED GSimpleAction *simple, |
226 pidgin_display_window_send_file(G_GNUC_UNUSED GSimpleAction *simple, |
| 227 G_GNUC_UNUSED GVariant *parameter, |
227 G_GNUC_UNUSED GVariant *parameter, |
| 228 gpointer data) |
228 gpointer data) |
| 229 { |
229 { |
| 230 PidginConversationWindow *window = data; |
230 PidginDisplayWindow *window = data; |
| 231 PurpleConversation *selected = NULL; |
231 PurpleConversation *selected = NULL; |
| 232 |
232 |
| 233 selected = pidgin_conversation_window_get_selected(window); |
233 selected = pidgin_display_window_get_selected(window); |
| 234 if(PURPLE_IS_IM_CONVERSATION(selected)) { |
234 if(PURPLE_IS_IM_CONVERSATION(selected)) { |
| 235 PurpleConnection *connection = NULL; |
235 PurpleConnection *connection = NULL; |
| 236 |
236 |
| 237 connection = purple_conversation_get_connection(selected); |
237 connection = purple_conversation_get_connection(selected); |
| 238 purple_serv_send_file(connection, |
238 purple_serv_send_file(connection, |
| 242 } |
242 } |
| 243 |
243 |
| 244 static GActionEntry win_entries[] = { |
244 static GActionEntry win_entries[] = { |
| 245 { |
245 { |
| 246 .name = "alias", |
246 .name = "alias", |
| 247 .activate = pidgin_conversation_window_alias |
247 .activate = pidgin_display_window_alias |
| 248 }, { |
248 }, { |
| 249 .name = "close", |
249 .name = "close", |
| 250 .activate = pidgin_conversation_window_close_conversation |
250 .activate = pidgin_display_window_close_conversation |
| 251 }, { |
251 }, { |
| 252 .name = "get-info", |
252 .name = "get-info", |
| 253 .activate = pidgin_conversation_window_get_info |
253 .activate = pidgin_display_window_get_info |
| 254 }, { |
254 }, { |
| 255 .name = "invite", |
255 .name = "invite", |
| 256 .activate = pidgin_conversation_window_invite |
256 .activate = pidgin_display_window_invite |
| 257 }, { |
257 }, { |
| 258 .name = "send-file", |
258 .name = "send-file", |
| 259 .activate = pidgin_conversation_window_send_file |
259 .activate = pidgin_display_window_send_file |
| 260 } |
260 } |
| 261 }; |
261 }; |
| 262 |
262 |
| 263 /*<private> |
263 /*<private> |
| 264 * pidgin_conversation_window_conversation_actions: |
264 * pidgin_display_window_conversation_actions: |
| 265 * |
265 * |
| 266 * A list of action names that are only valid if a conversation is selected. |
266 * A list of action names that are only valid if a conversation is selected. |
| 267 */ |
267 */ |
| 268 static const gchar *pidgin_conversation_window_conversation_actions[] = { |
268 static const gchar *pidgin_display_window_conversation_actions[] = { |
| 269 "alias", |
269 "alias", |
| 270 "close", |
270 "close", |
| 271 "get-info", |
271 "get-info", |
| 272 NULL |
272 NULL |
| 273 }; |
273 }; |
| 274 |
274 |
| 275 static const gchar *pidgin_conversation_window_im_conversation_actions[] = { |
275 static const gchar *pidgin_display_window_im_conversation_actions[] = { |
| 276 "send-file", |
276 "send-file", |
| 277 NULL |
277 NULL |
| 278 }; |
278 }; |
| 279 |
279 |
| 280 static const gchar *pidgin_conversation_window_chat_conversation_actions[] = { |
280 static const gchar *pidgin_display_window_chat_conversation_actions[] = { |
| 281 "invite", |
281 "invite", |
| 282 NULL |
282 NULL |
| 283 }; |
283 }; |
| 284 |
284 |
| 285 /****************************************************************************** |
285 /****************************************************************************** |
| 286 * Callbacks |
286 * Callbacks |
| 287 *****************************************************************************/ |
287 *****************************************************************************/ |
| 288 static void |
288 static void |
| 289 pidgin_conversation_window_selection_changed(GtkTreeSelection *selection, |
289 pidgin_display_window_selection_changed(GtkTreeSelection *selection, |
| 290 gpointer data) |
290 gpointer data) |
| 291 { |
291 { |
| 292 PidginConversationWindow *window = PIDGIN_CONVERSATION_WINDOW(data); |
292 PidginDisplayWindow *window = PIDGIN_DISPLAY_WINDOW(data); |
| 293 GtkTreeModel *model = NULL; |
293 GtkTreeModel *model = NULL; |
| 294 GtkTreeIter iter; |
294 GtkTreeIter iter; |
| 295 gboolean changed = FALSE; |
295 gboolean changed = FALSE; |
| 296 |
296 |
| 297 if(gtk_tree_selection_get_selected(selection, &model, &iter)) { |
297 if(gtk_tree_selection_get_selected(selection, &model, &iter)) { |
| 299 gboolean is_conversation = FALSE; |
299 gboolean is_conversation = FALSE; |
| 300 gboolean im_selected = FALSE, chat_selected = FALSE; |
300 gboolean im_selected = FALSE, chat_selected = FALSE; |
| 301 gchar *name = NULL; |
301 gchar *name = NULL; |
| 302 |
302 |
| 303 gtk_tree_model_get(model, &iter, |
303 gtk_tree_model_get(model, &iter, |
| 304 PIDGIN_CONVERSATION_WINDOW_COLUMN_NAME, &name, |
304 PIDGIN_DISPLAY_WINDOW_COLUMN_NAME, &name, |
| 305 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, &obj, |
305 PIDGIN_DISPLAY_WINDOW_COLUMN_OBJECT, &obj, |
| 306 -1); |
306 -1); |
| 307 |
307 |
| 308 gtk_stack_set_visible_child_name(GTK_STACK(window->stack), name); |
308 gtk_stack_set_visible_child_name(GTK_STACK(window->stack), name); |
| 309 g_free(name); |
309 g_free(name); |
| 310 |
310 |
| 312 |
312 |
| 313 /* If a conversation is selected, enable the generic conversation |
313 /* If a conversation is selected, enable the generic conversation |
| 314 * actions. |
314 * actions. |
| 315 */ |
315 */ |
| 316 is_conversation = PURPLE_IS_CONVERSATION(obj); |
316 is_conversation = PURPLE_IS_CONVERSATION(obj); |
| 317 pidgin_conversation_window_actions_set_enabled(G_ACTION_MAP(window), |
317 pidgin_display_window_actions_set_enabled(G_ACTION_MAP(window), |
| 318 pidgin_conversation_window_conversation_actions, |
318 pidgin_display_window_conversation_actions, |
| 319 is_conversation); |
319 is_conversation); |
| 320 |
320 |
| 321 /* If an IM is selected, enable the IM-specific actions otherwise |
321 /* If an IM is selected, enable the IM-specific actions otherwise |
| 322 * disable them. |
322 * disable them. |
| 323 */ |
323 */ |
| 324 im_selected = PURPLE_IS_IM_CONVERSATION(obj); |
324 im_selected = PURPLE_IS_IM_CONVERSATION(obj); |
| 325 pidgin_conversation_window_actions_set_enabled(G_ACTION_MAP(window), |
325 pidgin_display_window_actions_set_enabled(G_ACTION_MAP(window), |
| 326 pidgin_conversation_window_im_conversation_actions, |
326 pidgin_display_window_im_conversation_actions, |
| 327 im_selected); |
327 im_selected); |
| 328 |
328 |
| 329 /* If a chat is selected, enable the chat-specific actions otherwise |
329 /* If a chat is selected, enable the chat-specific actions otherwise |
| 330 * disable them. |
330 * disable them. |
| 331 */ |
331 */ |
| 332 chat_selected = PURPLE_IS_CHAT_CONVERSATION(obj); |
332 chat_selected = PURPLE_IS_CHAT_CONVERSATION(obj); |
| 333 pidgin_conversation_window_actions_set_enabled(G_ACTION_MAP(window), |
333 pidgin_display_window_actions_set_enabled(G_ACTION_MAP(window), |
| 334 pidgin_conversation_window_chat_conversation_actions, |
334 pidgin_display_window_chat_conversation_actions, |
| 335 chat_selected); |
335 chat_selected); |
| 336 |
336 |
| 337 g_clear_object(&obj); |
337 g_clear_object(&obj); |
| 338 } |
338 } |
| 339 |
339 |
| 341 gtk_stack_set_visible_child_name(GTK_STACK(window->stack), "__conversations__"); |
341 gtk_stack_set_visible_child_name(GTK_STACK(window->stack), "__conversations__"); |
| 342 } |
342 } |
| 343 } |
343 } |
| 344 |
344 |
| 345 static gboolean |
345 static gboolean |
| 346 pidgin_conversation_window_key_pressed_cb(GtkEventControllerKey *controller, |
346 pidgin_display_window_key_pressed_cb(GtkEventControllerKey *controller, |
| 347 guint keyval, |
347 guint keyval, |
| 348 G_GNUC_UNUSED guint keycode, |
348 G_GNUC_UNUSED guint keycode, |
| 349 GdkModifierType state, |
349 GdkModifierType state, |
| 350 gpointer data) |
350 gpointer data) |
| 351 { |
351 { |
| 352 PidginConversationWindow *window = data; |
352 PidginDisplayWindow *window = data; |
| 353 |
353 |
| 354 /* If CTRL was held down... */ |
354 /* If CTRL was held down... */ |
| 355 if (state & GDK_CONTROL_MASK) { |
355 if (state & GDK_CONTROL_MASK) { |
| 356 switch (keyval) { |
356 switch (keyval) { |
| 357 case GDK_KEY_Page_Down: |
357 case GDK_KEY_Page_Down: |
| 358 case GDK_KEY_KP_Page_Down: |
358 case GDK_KEY_KP_Page_Down: |
| 359 case ']': |
359 case ']': |
| 360 pidgin_conversation_window_select_next(window); |
360 pidgin_display_window_select_next(window); |
| 361 return TRUE; |
361 return TRUE; |
| 362 break; |
362 break; |
| 363 |
363 |
| 364 case GDK_KEY_Page_Up: |
364 case GDK_KEY_Page_Up: |
| 365 case GDK_KEY_KP_Page_Up: |
365 case GDK_KEY_KP_Page_Up: |
| 366 case '[': |
366 case '[': |
| 367 pidgin_conversation_window_select_previous(window); |
367 pidgin_display_window_select_previous(window); |
| 368 return TRUE; |
368 return TRUE; |
| 369 break; |
369 break; |
| 370 } /* End of switch */ |
370 } /* End of switch */ |
| 371 } |
371 } |
| 372 |
372 |
| 373 /* If ALT (or whatever) was held down... */ |
373 /* If ALT (or whatever) was held down... */ |
| 374 else if (state & GDK_ALT_MASK) { |
374 else if (state & GDK_ALT_MASK) { |
| 375 if ('1' <= keyval && keyval <= '9') { |
375 if ('1' <= keyval && keyval <= '9') { |
| 376 guint switchto = keyval - '1'; |
376 guint switchto = keyval - '1'; |
| 377 pidgin_conversation_window_select_nth(window, switchto); |
377 pidgin_display_window_select_nth(window, switchto); |
| 378 |
378 |
| 379 return TRUE; |
379 return TRUE; |
| 380 } |
380 } |
| 381 } |
381 } |
| 382 |
382 |
| 436 G_N_ELEMENTS(win_entries), window); |
436 G_N_ELEMENTS(win_entries), window); |
| 437 |
437 |
| 438 key = gtk_event_controller_key_new(); |
438 key = gtk_event_controller_key_new(); |
| 439 gtk_event_controller_set_propagation_phase(key, GTK_PHASE_CAPTURE); |
439 gtk_event_controller_set_propagation_phase(key, GTK_PHASE_CAPTURE); |
| 440 g_signal_connect(G_OBJECT(key), "key-pressed", |
440 g_signal_connect(G_OBJECT(key), "key-pressed", |
| 441 G_CALLBACK(pidgin_conversation_window_key_pressed_cb), |
441 G_CALLBACK(pidgin_display_window_key_pressed_cb), |
| 442 window); |
442 window); |
| 443 gtk_widget_add_controller(GTK_WIDGET(window), key); |
443 gtk_widget_add_controller(GTK_WIDGET(window), key); |
| 444 |
444 |
| 445 /* Add our toplevels to the tree store. */ |
445 /* Add our toplevels to the tree store. */ |
| 446 gtk_tree_store_append(window->model, &iter, NULL); |
446 gtk_tree_store_append(window->model, &iter, NULL); |
| 447 gtk_tree_store_set(window->model, &iter, |
447 gtk_tree_store_set(window->model, &iter, |
| 448 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, window->notification_list, |
448 PIDGIN_DISPLAY_WINDOW_COLUMN_OBJECT, window->notification_list, |
| 449 PIDGIN_CONVERSATION_WINDOW_COLUMN_NAME, "__notifications__", |
449 PIDGIN_DISPLAY_WINDOW_COLUMN_NAME, "__notifications__", |
| 450 PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, _("Notifications"), |
450 PIDGIN_DISPLAY_WINDOW_COLUMN_MARKUP, _("Notifications"), |
| 451 -1); |
451 -1); |
| 452 |
452 |
| 453 gtk_tree_store_append(window->model, &iter, NULL); |
453 gtk_tree_store_append(window->model, &iter, NULL); |
| 454 gtk_tree_store_set(window->model, &iter, |
454 gtk_tree_store_set(window->model, &iter, |
| 455 PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, _("Conversations"), |
455 PIDGIN_DISPLAY_WINDOW_COLUMN_MARKUP, _("Conversations"), |
| 456 PIDGIN_CONVERSATION_WINDOW_COLUMN_NAME, "__conversations__", |
456 PIDGIN_DISPLAY_WINDOW_COLUMN_NAME, "__conversations__", |
| 457 -1); |
457 -1); |
| 458 gtk_tree_selection_select_iter(window->selection, &iter); |
458 gtk_tree_selection_select_iter(window->selection, &iter); |
| 459 window->conversation_path = gtk_tree_model_get_path(GTK_TREE_MODEL(window->model), |
459 window->conversation_path = gtk_tree_model_get_path(GTK_TREE_MODEL(window->model), |
| 460 &iter); |
460 &iter); |
| 461 } |
461 } |
| 462 |
462 |
| 463 static void |
463 static void |
| 464 pidgin_conversation_window_class_init(PidginConversationWindowClass *klass) { |
464 pidgin_display_window_class_init(PidginDisplayWindowClass *klass) { |
| 465 GObjectClass *obj_class = G_OBJECT_CLASS(klass); |
465 GObjectClass *obj_class = G_OBJECT_CLASS(klass); |
| 466 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); |
466 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); |
| 467 |
467 |
| 468 obj_class->dispose = pidgin_conversation_window_dispose; |
468 obj_class->dispose = pidgin_display_window_dispose; |
| 469 |
469 |
| 470 /** |
470 /** |
| 471 * PidginConversationWindow::conversation-switched: |
471 * PidginDisplayWindow::conversation-switched: |
| 472 * @window: The conversation window. |
472 * @window: The conversation window. |
| 473 * @new_conv: The now active conversation. |
473 * @new_conv: The now active conversation. |
| 474 * |
474 * |
| 475 * Emitted when a window switched from one conversation to another. |
475 * Emitted when a window switched from one conversation to another. |
| 476 */ |
476 */ |
| 490 gtk_widget_class_set_template_from_resource( |
490 gtk_widget_class_set_template_from_resource( |
| 491 widget_class, |
491 widget_class, |
| 492 "/im/pidgin/Pidgin3/Conversations/window.ui" |
492 "/im/pidgin/Pidgin3/Conversations/window.ui" |
| 493 ); |
493 ); |
| 494 |
494 |
| 495 gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow, |
495 gtk_widget_class_bind_template_child(widget_class, PidginDisplayWindow, |
| 496 vbox); |
496 vbox); |
| 497 |
497 |
| 498 gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow, |
498 gtk_widget_class_bind_template_child(widget_class, PidginDisplayWindow, |
| 499 model); |
499 model); |
| 500 gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow, |
500 gtk_widget_class_bind_template_child(widget_class, PidginDisplayWindow, |
| 501 view); |
501 view); |
| 502 gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow, |
502 gtk_widget_class_bind_template_child(widget_class, PidginDisplayWindow, |
| 503 selection); |
503 selection); |
| 504 |
504 |
| 505 gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow, |
505 gtk_widget_class_bind_template_child(widget_class, PidginDisplayWindow, |
| 506 stack); |
506 stack); |
| 507 gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow, |
507 gtk_widget_class_bind_template_child(widget_class, PidginDisplayWindow, |
| 508 notification_list); |
508 notification_list); |
| 509 |
509 |
| 510 gtk_widget_class_bind_template_callback(widget_class, |
510 gtk_widget_class_bind_template_callback(widget_class, |
| 511 pidgin_conversation_window_selection_changed); |
511 pidgin_display_window_selection_changed); |
| 512 |
512 |
| 513 gtk_widget_class_bind_template_callback(widget_class, |
513 gtk_widget_class_bind_template_callback(widget_class, |
| 514 pidgin_conversation_window_key_pressed_cb); |
514 pidgin_display_window_key_pressed_cb); |
| 515 } |
515 } |
| 516 |
516 |
| 517 /****************************************************************************** |
517 /****************************************************************************** |
| 518 * API |
518 * API |
| 519 *****************************************************************************/ |
519 *****************************************************************************/ |
| 520 GtkWidget * |
520 GtkWidget * |
| 521 pidgin_conversation_window_get_default(void) { |
521 pidgin_display_window_get_default(void) { |
| 522 if(!GTK_IS_WIDGET(default_window)) { |
522 if(!GTK_IS_WIDGET(default_window)) { |
| 523 default_window = pidgin_conversation_window_new(); |
523 default_window = pidgin_display_window_new(); |
| 524 g_object_add_weak_pointer(G_OBJECT(default_window), |
524 g_object_add_weak_pointer(G_OBJECT(default_window), |
| 525 (gpointer)&default_window); |
525 (gpointer)&default_window); |
| 526 } |
526 } |
| 527 |
527 |
| 528 return default_window; |
528 return default_window; |
| 529 } |
529 } |
| 530 |
530 |
| 531 GtkWidget * |
531 GtkWidget * |
| 532 pidgin_conversation_window_new(void) { |
532 pidgin_display_window_new(void) { |
| 533 return g_object_new( |
533 return g_object_new( |
| 534 PIDGIN_TYPE_CONVERSATION_WINDOW, |
534 PIDGIN_TYPE_DISPLAY_WINDOW, |
| 535 "show-menubar", TRUE, |
535 "show-menubar", TRUE, |
| 536 NULL); |
536 NULL); |
| 537 } |
537 } |
| 538 |
538 |
| 539 void |
539 void |
| 540 pidgin_conversation_window_add(PidginConversationWindow *window, |
540 pidgin_display_window_add(PidginDisplayWindow *window, |
| 541 PurpleConversation *conversation) |
541 PurpleConversation *conversation) |
| 542 { |
542 { |
| 543 PidginConversation *gtkconv = NULL; |
543 PidginConversation *gtkconv = NULL; |
| 544 GtkTreeIter parent, iter; |
544 GtkTreeIter parent, iter; |
| 545 GtkTreeModel *model = NULL; |
545 GtkTreeModel *model = NULL; |
| 546 const gchar *markup = NULL; |
546 const gchar *markup = NULL; |
| 547 gboolean expand = FALSE; |
547 gboolean expand = FALSE; |
| 548 |
548 |
| 549 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window)); |
549 g_return_if_fail(PIDGIN_IS_DISPLAY_WINDOW(window)); |
| 550 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation)); |
550 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation)); |
| 551 |
551 |
| 552 model = GTK_TREE_MODEL(window->model); |
552 model = GTK_TREE_MODEL(window->model); |
| 553 if(!gtk_tree_model_get_iter(model, &parent, window->conversation_path)) { |
553 if(!gtk_tree_model_get_iter(model, &parent, window->conversation_path)) { |
| 554 /* If we can't find the conversation_path we have to bail. */ |
554 /* If we can't find the conversation_path we have to bail. */ |
| 580 } |
580 } |
| 581 } |
581 } |
| 582 |
582 |
| 583 gtk_tree_store_prepend(window->model, &iter, &parent); |
583 gtk_tree_store_prepend(window->model, &iter, &parent); |
| 584 gtk_tree_store_set(window->model, &iter, |
584 gtk_tree_store_set(window->model, &iter, |
| 585 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, conversation, |
585 PIDGIN_DISPLAY_WINDOW_COLUMN_OBJECT, conversation, |
| 586 PIDGIN_CONVERSATION_WINDOW_COLUMN_NAME, markup, |
586 PIDGIN_DISPLAY_WINDOW_COLUMN_NAME, markup, |
| 587 PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, markup, |
587 PIDGIN_DISPLAY_WINDOW_COLUMN_MARKUP, markup, |
| 588 -1); |
588 -1); |
| 589 |
589 |
| 590 /* If we just added the first child, expand the parent. */ |
590 /* If we just added the first child, expand the parent. */ |
| 591 if(expand) { |
591 if(expand) { |
| 592 gtk_tree_view_expand_row(GTK_TREE_VIEW(window->view), |
592 gtk_tree_view_expand_row(GTK_TREE_VIEW(window->view), |
| 598 gtk_widget_show(GTK_WIDGET(window)); |
598 gtk_widget_show(GTK_WIDGET(window)); |
| 599 } |
599 } |
| 600 } |
600 } |
| 601 |
601 |
| 602 void |
602 void |
| 603 pidgin_conversation_window_remove(PidginConversationWindow *window, |
603 pidgin_display_window_remove(PidginDisplayWindow *window, |
| 604 PurpleConversation *conversation) |
604 PurpleConversation *conversation) |
| 605 { |
605 { |
| 606 GtkTreeIter parent, iter; |
606 GtkTreeIter parent, iter; |
| 607 GtkTreeModel *model = NULL; |
607 GtkTreeModel *model = NULL; |
| 608 GObject *obj = NULL; |
608 GObject *obj = NULL; |
| 609 |
609 |
| 610 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window)); |
610 g_return_if_fail(PIDGIN_IS_DISPLAY_WINDOW(window)); |
| 611 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation)); |
611 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation)); |
| 612 |
612 |
| 613 model = GTK_TREE_MODEL(window->model); |
613 model = GTK_TREE_MODEL(window->model); |
| 614 |
614 |
| 615 if(!gtk_tree_model_get_iter(model, &parent, window->conversation_path)) { |
615 if(!gtk_tree_model_get_iter(model, &parent, window->conversation_path)) { |
| 664 |
664 |
| 665 return count; |
665 return count; |
| 666 } |
666 } |
| 667 |
667 |
| 668 PurpleConversation * |
668 PurpleConversation * |
| 669 pidgin_conversation_window_get_selected(PidginConversationWindow *window) { |
669 pidgin_display_window_get_selected(PidginDisplayWindow *window) { |
| 670 PurpleConversation *conversation = NULL; |
670 PurpleConversation *conversation = NULL; |
| 671 GtkTreeSelection *selection = NULL; |
671 GtkTreeSelection *selection = NULL; |
| 672 GtkTreeIter iter; |
672 GtkTreeIter iter; |
| 673 |
673 |
| 674 g_return_val_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window), NULL); |
674 g_return_val_if_fail(PIDGIN_IS_DISPLAY_WINDOW(window), NULL); |
| 675 |
675 |
| 676 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(window->view)); |
676 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(window->view)); |
| 677 if(gtk_tree_selection_get_selected(selection, NULL, &iter)) { |
677 if(gtk_tree_selection_get_selected(selection, NULL, &iter)) { |
| 678 |
678 |
| 679 gtk_tree_model_get(GTK_TREE_MODEL(window->model), &iter, |
679 gtk_tree_model_get(GTK_TREE_MODEL(window->model), &iter, |
| 680 PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, &conversation, |
680 PIDGIN_DISPLAY_WINDOW_COLUMN_OBJECT, &conversation, |
| 681 -1); |
681 -1); |
| 682 } |
682 } |
| 683 |
683 |
| 684 return conversation; |
684 return conversation; |
| 685 } |
685 } |
| 686 |
686 |
| 687 void |
687 void |
| 688 pidgin_conversation_window_select(PidginConversationWindow *window, |
688 pidgin_display_window_select(PidginDisplayWindow *window, |
| 689 PurpleConversation *conversation) |
689 PurpleConversation *conversation) |
| 690 { |
690 { |
| 691 const gchar *name = NULL; |
691 const gchar *name = NULL; |
| 692 |
692 |
| 693 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window)); |
693 g_return_if_fail(PIDGIN_IS_DISPLAY_WINDOW(window)); |
| 694 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation)); |
694 g_return_if_fail(PURPLE_IS_CONVERSATION(conversation)); |
| 695 |
695 |
| 696 name = purple_conversation_get_name(conversation); |
696 name = purple_conversation_get_name(conversation); |
| 697 gtk_stack_set_visible_child_name(GTK_STACK(window->stack), name); |
697 gtk_stack_set_visible_child_name(GTK_STACK(window->stack), name); |
| 698 } |
698 } |
| 699 |
699 |
| 700 void |
700 void |
| 701 pidgin_conversation_window_select_previous(PidginConversationWindow *window) { |
701 pidgin_display_window_select_previous(PidginDisplayWindow *window) { |
| 702 GtkTreeIter iter; |
702 GtkTreeIter iter; |
| 703 GtkTreeModel *model = NULL; |
703 GtkTreeModel *model = NULL; |
| 704 GtkTreeSelection *selection = NULL; |
704 GtkTreeSelection *selection = NULL; |
| 705 gboolean set = FALSE; |
705 gboolean set = FALSE; |
| 706 |
706 |
| 707 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window)); |
707 g_return_if_fail(PIDGIN_IS_DISPLAY_WINDOW(window)); |
| 708 |
708 |
| 709 model = GTK_TREE_MODEL(window->model); |
709 model = GTK_TREE_MODEL(window->model); |
| 710 |
710 |
| 711 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(window->view)); |
711 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(window->view)); |
| 712 if(gtk_tree_selection_get_selected(selection, NULL, &iter)) { |
712 if(gtk_tree_selection_get_selected(selection, NULL, &iter)) { |
| 715 set = TRUE; |
715 set = TRUE; |
| 716 } |
716 } |
| 717 } |
717 } |
| 718 |
718 |
| 719 if(!set) { |
719 if(!set) { |
| 720 pidgin_conversation_window_select_last(window); |
720 pidgin_display_window_select_last(window); |
| 721 } |
721 } |
| 722 } |
722 } |
| 723 |
723 |
| 724 |
724 |
| 725 void |
725 void |
| 726 pidgin_conversation_window_select_next(PidginConversationWindow *window) { |
726 pidgin_display_window_select_next(PidginDisplayWindow *window) { |
| 727 GtkTreeIter iter; |
727 GtkTreeIter iter; |
| 728 GtkTreeModel *model = NULL; |
728 GtkTreeModel *model = NULL; |
| 729 GtkTreeSelection *selection = NULL; |
729 GtkTreeSelection *selection = NULL; |
| 730 gboolean set = FALSE; |
730 gboolean set = FALSE; |
| 731 |
731 |
| 732 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window)); |
732 g_return_if_fail(PIDGIN_IS_DISPLAY_WINDOW(window)); |
| 733 |
733 |
| 734 model = GTK_TREE_MODEL(window->model); |
734 model = GTK_TREE_MODEL(window->model); |
| 735 |
735 |
| 736 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(window->view)); |
736 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(window->view)); |
| 737 if(gtk_tree_selection_get_selected(selection, NULL, &iter)) { |
737 if(gtk_tree_selection_get_selected(selection, NULL, &iter)) { |
| 762 gtk_tree_selection_select_iter(selection, &iter); |
762 gtk_tree_selection_select_iter(selection, &iter); |
| 763 } |
763 } |
| 764 } |
764 } |
| 765 |
765 |
| 766 void |
766 void |
| 767 pidgin_conversation_window_select_last(PidginConversationWindow *window) { |
767 pidgin_display_window_select_last(PidginDisplayWindow *window) { |
| 768 GtkTreeIter iter; |
768 GtkTreeIter iter; |
| 769 GtkTreeModel *model = NULL; |
769 GtkTreeModel *model = NULL; |
| 770 gint count = 0; |
770 gint count = 0; |
| 771 |
771 |
| 772 g_return_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window)); |
772 g_return_if_fail(PIDGIN_IS_DISPLAY_WINDOW(window)); |
| 773 |
773 |
| 774 model = GTK_TREE_MODEL(window->model); |
774 model = GTK_TREE_MODEL(window->model); |
| 775 count = gtk_tree_model_iter_n_children(model, NULL); |
775 count = gtk_tree_model_iter_n_children(model, NULL); |
| 776 |
776 |
| 777 if(gtk_tree_model_iter_nth_child(model, &iter, NULL, count - 1)) { |
777 if(gtk_tree_model_iter_nth_child(model, &iter, NULL, count - 1)) { |
| 800 gtk_tree_selection_select_iter(selection, &iter); |
800 gtk_tree_selection_select_iter(selection, &iter); |
| 801 } |
801 } |
| 802 } |
802 } |
| 803 |
803 |
| 804 gboolean |
804 gboolean |
| 805 pidgin_conversation_window_conversation_is_selected(PidginConversationWindow *window, |
805 pidgin_display_window_conversation_is_selected(PidginDisplayWindow *window, |
| 806 PurpleConversation *conversation) |
806 PurpleConversation *conversation) |
| 807 { |
807 { |
| 808 const gchar *name = NULL, *visible = NULL; |
808 const gchar *name = NULL, *visible = NULL; |
| 809 |
809 |
| 810 g_return_val_if_fail(PIDGIN_IS_CONVERSATION_WINDOW(window), FALSE); |
810 g_return_val_if_fail(PIDGIN_IS_DISPLAY_WINDOW(window), FALSE); |
| 811 g_return_val_if_fail(PURPLE_IS_CONVERSATION(conversation), FALSE); |
811 g_return_val_if_fail(PURPLE_IS_CONVERSATION(conversation), FALSE); |
| 812 |
812 |
| 813 name = purple_conversation_get_name(conversation); |
813 name = purple_conversation_get_name(conversation); |
| 814 visible = gtk_stack_get_visible_child_name(GTK_STACK(window->stack)); |
814 visible = gtk_stack_get_visible_child_name(GTK_STACK(window->stack)); |
| 815 |
815 |