pidgin/plugins/xmppconsole/xmppconsole.c

changeset 41652
fd32ea10d1cb
parent 41555
6ef22b85cb10
child 41854
c1d7e7445b0f
equal deleted inserted replaced
41651:eba22f6af173 41652:fd32ea10d1cb
33 #define PLUGIN_DOMAIN (g_quark_from_static_string(PLUGIN_ID)) 33 #define PLUGIN_DOMAIN (g_quark_from_static_string(PLUGIN_ID))
34 34
35 struct _PidginXmppConsole { 35 struct _PidginXmppConsole {
36 GtkWindow parent; 36 GtkWindow parent;
37 37
38 GtkComboBox *account_chooser;
38 PurpleConnection *gc; 39 PurpleConnection *gc;
39 GtkTextBuffer *buffer; 40 GtkTextBuffer *buffer;
40 struct { 41 struct {
41 GtkTextTag *info; 42 GtkTextTag *info;
42 GtkTextTag *incoming; 43 GtkTextTag *incoming;
50 GtkWidget *entry; 51 GtkWidget *entry;
51 GtkTextBuffer *entry_buffer; 52 GtkTextBuffer *entry_buffer;
52 GtkWidget *sw; 53 GtkWidget *sw;
53 54
54 struct { 55 struct {
55 GtkPopover *popover; 56 GtkMenuButton *button;
56 GtkEntry *to; 57 GtkEntry *to;
57 GtkComboBoxText *type; 58 GtkDropDown *type;
58 } iq; 59 } iq;
59 60
60 struct { 61 struct {
61 GtkPopover *popover; 62 GtkMenuButton *button;
62 GtkEntry *to; 63 GtkEntry *to;
63 GtkComboBoxText *type; 64 GtkDropDown *type;
64 GtkComboBoxText *show; 65 GtkDropDown *show;
65 GtkEntry *status; 66 GtkEntry *status;
66 GtkEntry *priority; 67 GtkEntry *priority;
67 } presence; 68 } presence;
68 69
69 struct { 70 struct {
70 GtkPopover *popover; 71 GtkMenuButton *button;
71 GtkEntry *to; 72 GtkEntry *to;
72 GtkComboBoxText *type; 73 GtkDropDown *type;
73 GtkEntry *body; 74 GtkEntry *body;
74 GtkEntry *subject; 75 GtkEntry *subject;
75 GtkEntry *thread; 76 GtkEntry *thread;
76 } message; 77 } message;
77 }; 78 };
263 int lines; 264 int lines;
264 GdkRectangle oneline; 265 GdkRectangle oneline;
265 int height; 266 int height;
266 int pad_top, pad_inside, pad_bottom; 267 int pad_top, pad_inside, pad_bottom;
267 PurpleXmlNode *node; 268 PurpleXmlNode *node;
268 GtkStyleContext *style;
269 269
270 wrapped_lines = 1; 270 wrapped_lines = 1;
271 gtk_text_buffer_get_start_iter(buffer, &iter); 271 gtk_text_buffer_get_start_iter(buffer, &iter);
272 gtk_text_view_get_iter_location(GTK_TEXT_VIEW(console->entry), &iter, &oneline); 272 gtk_text_view_get_iter_location(GTK_TEXT_VIEW(console->entry), &iter, &oneline);
273 while (gtk_text_view_forward_display_line(GTK_TEXT_VIEW(console->entry), 273 while (gtk_text_view_forward_display_line(GTK_TEXT_VIEW(console->entry),
296 return; 296 return;
297 } 297 }
298 298
299 xmlstr = g_strdup_printf("<xml>%s</xml>", str); 299 xmlstr = g_strdup_printf("<xml>%s</xml>", str);
300 node = purple_xmlnode_from_str(xmlstr, -1); 300 node = purple_xmlnode_from_str(xmlstr, -1);
301 style = gtk_widget_get_style_context(console->entry);
302 if (node) { 301 if (node) {
303 gtk_style_context_remove_class(style, "error"); 302 gtk_text_buffer_remove_tag_by_name(console->entry_buffer, "invalid",
303 &start, &end);
304 } else { 304 } else {
305 gtk_style_context_add_class(style, "error"); 305 gtk_text_buffer_apply_tag_by_name(console->entry_buffer, "invalid",
306 &start, &end);
306 } 307 }
307 g_free(str); 308 g_free(str);
308 g_free(xmlstr); 309 g_free(xmlstr);
309 if (node) 310 if (node)
310 purple_xmlnode_free(node); 311 purple_xmlnode_free(node);
312 313
313 static void 314 static void
314 load_text_and_set_caret(PidginXmppConsole *console, const gchar *pre_text, 315 load_text_and_set_caret(PidginXmppConsole *console, const gchar *pre_text,
315 const gchar *post_text) 316 const gchar *post_text)
316 { 317 {
318 GtkTextIter start, end;
317 GtkTextIter where; 319 GtkTextIter where;
318 GtkTextMark *mark; 320 GtkTextMark *mark;
319 321
322 g_signal_handlers_block_by_func(console->entry_buffer, entry_changed_cb,
323 console);
320 gtk_text_buffer_begin_user_action(console->entry_buffer); 324 gtk_text_buffer_begin_user_action(console->entry_buffer);
321 325
322 gtk_text_buffer_set_text(console->entry_buffer, pre_text, -1); 326 gtk_text_buffer_get_bounds(console->entry_buffer, &start, &end);
327 gtk_text_buffer_delete(console->entry_buffer, &start, &end);
328 gtk_text_buffer_insert(console->entry_buffer, &end, pre_text, -1);
323 329
324 gtk_text_buffer_get_end_iter(console->entry_buffer, &where); 330 gtk_text_buffer_get_end_iter(console->entry_buffer, &where);
325 mark = gtk_text_buffer_create_mark(console->entry_buffer, NULL, &where, TRUE); 331 mark = gtk_text_buffer_create_mark(console->entry_buffer, NULL, &where, TRUE);
326 332
327 gtk_text_buffer_insert(console->entry_buffer, &where, post_text, -1); 333 gtk_text_buffer_insert(console->entry_buffer, &where, post_text, -1);
329 gtk_text_buffer_get_iter_at_mark(console->entry_buffer, &where, mark); 335 gtk_text_buffer_get_iter_at_mark(console->entry_buffer, &where, mark);
330 gtk_text_buffer_place_cursor(console->entry_buffer, &where); 336 gtk_text_buffer_place_cursor(console->entry_buffer, &where);
331 gtk_text_buffer_delete_mark(console->entry_buffer, mark); 337 gtk_text_buffer_delete_mark(console->entry_buffer, mark);
332 338
333 gtk_text_buffer_end_user_action(console->entry_buffer); 339 gtk_text_buffer_end_user_action(console->entry_buffer);
340 g_signal_handlers_unblock_by_func(console->entry_buffer, entry_changed_cb,
341 console);
342
343 entry_changed_cb(console->entry_buffer, console);
334 } 344 }
335 345
336 static void 346 static void
337 iq_clicked_cb(GtkWidget *w, gpointer data) 347 iq_clicked_cb(GtkWidget *w, gpointer data)
338 { 348 {
339 PidginXmppConsole *console = data; 349 PidginXmppConsole *console = data;
340 const gchar *to; 350 GtkStringObject *obj = NULL;
341 char *stanza; 351 const gchar *to, *type;
352 gchar *stanza;
342 353
343 to = gtk_editable_get_text(GTK_EDITABLE(console->iq.to)); 354 to = gtk_editable_get_text(GTK_EDITABLE(console->iq.to));
344 stanza = g_strdup_printf( 355 obj = gtk_drop_down_get_selected_item(console->iq.type);
345 "<iq %s%s%s id='console%x' type='%s'>", to && *to ? "to='" : "", 356 type = gtk_string_object_get_string(obj);
346 to && *to ? to : "", to && *to ? "'" : "", g_random_int(), 357
347 gtk_combo_box_text_get_active_text(console->iq.type)); 358 if(to != NULL && *to != '\0') {
359 stanza = g_strdup_printf("<iq to='%s' id='console%x' type='%s'>",
360 to, g_random_int(), type);
361 } else {
362 stanza = g_strdup_printf("<iq id='console%x' type='%s'>",
363 g_random_int(), type);
364 }
365
348 load_text_and_set_caret(console, stanza, "</iq>"); 366 load_text_and_set_caret(console, stanza, "</iq>");
349 gtk_widget_grab_focus(console->entry); 367 gtk_widget_grab_focus(console->entry);
350 g_free(stanza); 368 g_free(stanza);
351 369
352 /* Reset everything. */ 370 /* Reset everything. */
353 gtk_editable_set_text(GTK_EDITABLE(console->iq.to), ""); 371 gtk_editable_set_text(GTK_EDITABLE(console->iq.to), "");
354 gtk_combo_box_set_active(GTK_COMBO_BOX(console->iq.type), 0); 372 gtk_drop_down_set_selected(console->iq.type, 0);
355 gtk_popover_popdown(console->iq.popover); 373 gtk_menu_button_popdown(console->iq.button);
356 } 374 }
357 375
358 static void 376 static void
359 presence_clicked_cb(GtkWidget *w, gpointer data) 377 presence_clicked_cb(GtkWidget *w, gpointer data)
360 { 378 {
361 PidginXmppConsole *console = data; 379 PidginXmppConsole *console = data;
380 GtkStringObject *obj = NULL;
362 const gchar *to, *status, *priority; 381 const gchar *to, *status, *priority;
363 gchar *type, *show; 382 const gchar *type, *show;
364 char *stanza; 383 GString *stanza = NULL;
365 384
366 to = gtk_editable_get_text(GTK_EDITABLE(console->presence.to)); 385 to = gtk_editable_get_text(GTK_EDITABLE(console->presence.to));
367 type = gtk_combo_box_text_get_active_text(console->presence.type); 386 obj = gtk_drop_down_get_selected_item(console->presence.type);
387 type = gtk_string_object_get_string(obj);
368 if (purple_strequal(type, "default")) { 388 if (purple_strequal(type, "default")) {
369 g_free(type); 389 type = "";
370 type = g_strdup(""); 390 }
371 } 391 obj = gtk_drop_down_get_selected_item(console->presence.show);
372 show = gtk_combo_box_text_get_active_text(console->presence.show); 392 show = gtk_string_object_get_string(obj);
373 if (purple_strequal(show, "default")) { 393 if (purple_strequal(show, "default")) {
374 g_free(show); 394 show = "";
375 show = g_strdup("");
376 } 395 }
377 status = gtk_editable_get_text(GTK_EDITABLE(console->presence.status)); 396 status = gtk_editable_get_text(GTK_EDITABLE(console->presence.status));
378 priority = gtk_editable_get_text(GTK_EDITABLE(console->presence.priority)); 397 priority = gtk_editable_get_text(GTK_EDITABLE(console->presence.priority));
379 if (purple_strequal(priority, "0")) 398 if (purple_strequal(priority, "0")) {
380 priority = ""; 399 priority = "";
381 400 }
382 stanza = g_strdup_printf("<presence %s%s%s id='console%x' %s%s%s>" 401
383 "%s%s%s%s%s%s%s%s%s", 402 stanza = g_string_new("<presence");
384 *to ? "to='" : "", 403 if(*to != '\0') {
385 *to ? to : "", 404 g_string_append_printf(stanza, " to='%s'", to);
386 *to ? "'" : "", 405 }
387 g_random_int(), 406 g_string_append_printf(stanza, " id='console%x'", g_random_int());
388 407 if(*type != '\0') {
389 *type ? "type='" : "", 408 g_string_append_printf(stanza, " type='%s'", type);
390 *type ? type : "", 409 }
391 *type ? "'" : "", 410 g_string_append_c(stanza, '>');
392 411
393 *show ? "<show>" : "", 412 if(*show != '\0') {
394 *show ? show : "", 413 g_string_append_printf(stanza, "<show>%s</show>", show);
395 *show ? "</show>" : "", 414 }
396 415
397 *status ? "<status>" : "", 416 if(*status != '\0') {
398 *status ? status : "", 417 g_string_append_printf(stanza, "<status>%s</status>", status);
399 *status ? "</status>" : "", 418 }
400 419
401 *priority ? "<priority>" : "", 420 if(*priority != '\0') {
402 *priority ? priority : "", 421 g_string_append_printf(stanza, "<priority>%s</priority>", priority);
403 *priority ? "</priority>" : ""); 422 }
404 423
405 load_text_and_set_caret(console, stanza, "</presence>"); 424 load_text_and_set_caret(console, stanza->str, "</presence>");
406 gtk_widget_grab_focus(console->entry); 425 gtk_widget_grab_focus(console->entry);
407 g_free(stanza); 426 g_string_free(stanza, TRUE);
408 g_free(type);
409 g_free(show);
410 427
411 /* Reset everything. */ 428 /* Reset everything. */
412 gtk_editable_set_text(GTK_EDITABLE(console->presence.to), ""); 429 gtk_editable_set_text(GTK_EDITABLE(console->presence.to), "");
413 gtk_combo_box_set_active(GTK_COMBO_BOX(console->presence.type), 0); 430 gtk_drop_down_set_selected(console->presence.type, 0);
414 gtk_combo_box_set_active(GTK_COMBO_BOX(console->presence.show), 0); 431 gtk_drop_down_set_selected(console->presence.show, 0);
415 gtk_editable_set_text(GTK_EDITABLE(console->presence.status), ""); 432 gtk_editable_set_text(GTK_EDITABLE(console->presence.status), "");
416 gtk_editable_set_text(GTK_EDITABLE(console->presence.priority), "0"); 433 gtk_editable_set_text(GTK_EDITABLE(console->presence.priority), "0");
417 gtk_popover_popdown(console->presence.popover); 434 gtk_menu_button_popdown(console->presence.button);
418 } 435 }
419 436
420 static void 437 static void
421 message_clicked_cb(GtkWidget *w, gpointer data) 438 message_clicked_cb(GtkWidget *w, gpointer data)
422 { 439 {
423 PidginXmppConsole *console = data; 440 PidginXmppConsole *console = data;
424 const gchar *to, *body, *thread, *subject; 441 GtkStringObject *obj = NULL;
425 char *stanza; 442 const gchar *to, *body, *thread, *subject, *type;
443 GString *stanza = NULL;
426 444
427 to = gtk_editable_get_text(GTK_EDITABLE(console->message.to)); 445 to = gtk_editable_get_text(GTK_EDITABLE(console->message.to));
428 body = gtk_editable_get_text(GTK_EDITABLE(console->message.body)); 446 body = gtk_editable_get_text(GTK_EDITABLE(console->message.body));
429 thread = gtk_editable_get_text(GTK_EDITABLE(console->message.thread)); 447 thread = gtk_editable_get_text(GTK_EDITABLE(console->message.thread));
430 subject = gtk_editable_get_text(GTK_EDITABLE(console->message.subject)); 448 subject = gtk_editable_get_text(GTK_EDITABLE(console->message.subject));
431 449 obj = gtk_drop_down_get_selected_item(console->message.type);
432 stanza = g_strdup_printf( 450 type = gtk_string_object_get_string(obj);
433 "<message %s%s%s id='console%x' type='%s'>" 451
434 "%s%s%s%s%s%s%s%s%s", 452 stanza = g_string_new("<message");
435 453 if(*to != '\0') {
436 *to ? "to='" : "", *to ? to : "", *to ? "'" : "", 454 g_string_append_printf(stanza, " to='%s'", to);
437 g_random_int(), 455 }
438 gtk_combo_box_text_get_active_text(console->message.type), 456 g_string_append_printf(stanza, " id='console%x' type='%s'>",
439 457 g_random_int(), type);
440 *body ? "<body>" : "", *body ? body : "", 458
441 *body ? "</body>" : "", 459 if(*body != '\0') {
442 460 g_string_append_printf(stanza, "<body>%s</body>", body);
443 *subject ? "<subject>" : "", *subject ? subject : "", 461 }
444 *subject ? "</subject>" : "", 462
445 463 if(*subject != '\0') {
446 *thread ? "<thread>" : "", *thread ? thread : "", 464 g_string_append_printf(stanza, "<subject>%s</subject>", subject);
447 *thread ? "</thread>" : ""); 465 }
448 466
449 load_text_and_set_caret(console, stanza, "</message>"); 467 if(*thread != '\0') {
468 g_string_append_printf(stanza, "<thread>%s</thread>", thread);
469 }
470
471 load_text_and_set_caret(console, stanza->str, "</message>");
450 gtk_widget_grab_focus(console->entry); 472 gtk_widget_grab_focus(console->entry);
451 g_free(stanza); 473 g_string_free(stanza, TRUE);
452 474
453 /* Reset everything. */ 475 /* Reset everything. */
454 gtk_editable_set_text(GTK_EDITABLE(console->message.to), ""); 476 gtk_editable_set_text(GTK_EDITABLE(console->message.to), "");
455 gtk_combo_box_set_active(GTK_COMBO_BOX(console->message.type), 0); 477 gtk_drop_down_set_selected(console->message.type, 0);
456 gtk_editable_set_text(GTK_EDITABLE(console->message.body), ""); 478 gtk_editable_set_text(GTK_EDITABLE(console->message.body), "");
457 gtk_editable_set_text(GTK_EDITABLE(console->message.subject), "0"); 479 gtk_editable_set_text(GTK_EDITABLE(console->message.subject), "0");
458 gtk_editable_set_text(GTK_EDITABLE(console->message.thread), "0"); 480 gtk_editable_set_text(GTK_EDITABLE(console->message.thread), "0");
459 gtk_popover_popdown(console->message.popover); 481 gtk_menu_button_popdown(console->message.button);
460 } 482 }
461 483
462 static void 484 static void
463 dropdown_changed_cb(GtkComboBox *widget, gpointer data) { 485 dropdown_changed_cb(GtkComboBox *widget, gpointer data) {
464 PidginXmppConsole *console = data; 486 PidginXmppConsole *console = data;
492 gtk_widget_class_set_template_from_resource( 514 gtk_widget_class_set_template_from_resource(
493 widget_class, 515 widget_class,
494 "/im/pidgin/Pidgin3/Plugin/XMPPConsole/console.ui" 516 "/im/pidgin/Pidgin3/Plugin/XMPPConsole/console.ui"
495 ); 517 );
496 518
519 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
520 account_chooser);
497 gtk_widget_class_bind_template_callback(widget_class, dropdown_changed_cb); 521 gtk_widget_class_bind_template_callback(widget_class, dropdown_changed_cb);
498 522
499 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 523 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
500 buffer); 524 buffer);
501 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 525 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
515 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 539 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
516 tags.xmlns); 540 tags.xmlns);
517 541
518 /* Popover for <iq/> button. */ 542 /* Popover for <iq/> button. */
519 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 543 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
520 iq.popover); 544 iq.button);
521 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 545 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
522 iq.to); 546 iq.to);
523 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 547 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
524 iq.type); 548 iq.type);
525 gtk_widget_class_bind_template_callback(widget_class, iq_clicked_cb); 549 gtk_widget_class_bind_template_callback(widget_class, iq_clicked_cb);
526 550
527 /* Popover for <presence/> button. */ 551 /* Popover for <presence/> button. */
528 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 552 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
529 presence.popover); 553 presence.button);
530 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 554 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
531 presence.to); 555 presence.to);
532 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 556 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
533 presence.type); 557 presence.type);
534 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 558 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
539 presence.priority); 563 presence.priority);
540 gtk_widget_class_bind_template_callback(widget_class, presence_clicked_cb); 564 gtk_widget_class_bind_template_callback(widget_class, presence_clicked_cb);
541 565
542 /* Popover for <message/> button. */ 566 /* Popover for <message/> button. */
543 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 567 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
544 message.popover); 568 message.button);
545 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 569 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
546 message.to); 570 message.to);
547 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 571 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
548 message.type); 572 message.type);
549 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole, 573 gtk_widget_class_bind_template_child(widget_class, PidginXmppConsole,
564 gtk_widget_class_bind_template_callback(widget_class, entry_changed_cb); 588 gtk_widget_class_bind_template_callback(widget_class, entry_changed_cb);
565 } 589 }
566 590
567 static void 591 static void
568 pidgin_xmpp_console_init(PidginXmppConsole *console) { 592 pidgin_xmpp_console_init(PidginXmppConsole *console) {
569 GtkCssProvider *entry_css;
570 GtkStyleContext *context;
571
572 gtk_widget_init_template(GTK_WIDGET(console)); 593 gtk_widget_init_template(GTK_WIDGET(console));
573 594
574 entry_css = gtk_css_provider_new(); 595 dropdown_changed_cb(console->account_chooser, console);
575 gtk_css_provider_load_from_data(entry_css,
576 "textview.error text {background-color:#ffcece;}",
577 -1);
578 context = gtk_widget_get_style_context(console->entry);
579 gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(entry_css),
580 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
581
582 entry_changed_cb(console->entry_buffer, console); 596 entry_changed_cb(console->entry_buffer, console);
583 597
584 gtk_widget_show(GTK_WIDGET(console)); 598 gtk_widget_show(GTK_WIDGET(console));
585 } 599 }
586 600

mercurial