| 382 g_object_set_data(G_OBJECT(button), "pidgin-help-cb", help_cb); |
287 g_object_set_data(G_OBJECT(button), "pidgin-help-cb", help_cb); |
| 383 g_object_set_data(G_OBJECT(button), "pidgin-help-data", help_data); |
288 g_object_set_data(G_OBJECT(button), "pidgin-help-data", help_data); |
| 384 |
289 |
| 385 g_signal_connect(G_OBJECT(button), "clicked", |
290 g_signal_connect(G_OBJECT(button), "clicked", |
| 386 G_CALLBACK(pidgin_request_help_clicked), NULL); |
291 G_CALLBACK(pidgin_request_help_clicked), NULL); |
| 387 } |
|
| 388 |
|
| 389 static void * |
|
| 390 pidgin_request_input(const char *title, const char *primary, |
|
| 391 const char *secondary, const char *default_value, |
|
| 392 gboolean multiline, gboolean masked, gchar *hint, |
|
| 393 const char *ok_text, GCallback ok_cb, |
|
| 394 const char *cancel_text, GCallback cancel_cb, |
|
| 395 PurpleRequestCommonParameters *cpar, |
|
| 396 void *user_data) |
|
| 397 { |
|
| 398 PidginRequestData *data; |
|
| 399 GtkWidget *dialog; |
|
| 400 GtkWidget *vbox; |
|
| 401 GtkWidget *hbox; |
|
| 402 GtkLabel *label; |
|
| 403 GtkWidget *img; |
|
| 404 GtkWidget *content; |
|
| 405 char *label_text; |
|
| 406 char *primary_esc, *secondary_esc; |
|
| 407 |
|
| 408 data = g_new0(PidginRequestData, 1); |
|
| 409 data->type = PURPLE_REQUEST_INPUT; |
|
| 410 data->user_data = user_data; |
|
| 411 |
|
| 412 data->cb_count = 2; |
|
| 413 data->cbs = g_new0(GCallback, 2); |
|
| 414 |
|
| 415 data->cbs[0] = ok_cb; |
|
| 416 data->cbs[1] = cancel_cb; |
|
| 417 |
|
| 418 /* Create the dialog. */ |
|
| 419 dialog = gtk_dialog_new_with_buttons(title ? title : PIDGIN_ALERT_TITLE, |
|
| 420 NULL, 0, |
|
| 421 cancel_text, 1, |
|
| 422 ok_text, 0, |
|
| 423 NULL); |
|
| 424 data->dialog = dialog; |
|
| 425 |
|
| 426 g_signal_connect(G_OBJECT(dialog), "response", |
|
| 427 G_CALLBACK(input_response_cb), data); |
|
| 428 |
|
| 429 /* Setup the dialog */ |
|
| 430 gtk_widget_set_margin_top(dialog, 6); |
|
| 431 gtk_widget_set_margin_bottom(dialog, 6); |
|
| 432 gtk_widget_set_margin_start(dialog, 6); |
|
| 433 gtk_widget_set_margin_end(dialog, 6); |
|
| 434 |
|
| 435 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); |
|
| 436 gtk_widget_set_margin_top(content, 6); |
|
| 437 gtk_widget_set_margin_bottom(content, 6); |
|
| 438 gtk_widget_set_margin_start(content, 6); |
|
| 439 gtk_widget_set_margin_end(content, 6); |
|
| 440 |
|
| 441 if (!multiline) |
|
| 442 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); |
|
| 443 gtk_dialog_set_default_response(GTK_DIALOG(dialog), 0); |
|
| 444 gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), |
|
| 445 12); |
|
| 446 |
|
| 447 /* Setup the main horizontal box */ |
|
| 448 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12); |
|
| 449 gtk_box_append(GTK_BOX(content), hbox); |
|
| 450 |
|
| 451 /* Dialog icon. */ |
|
| 452 img = pidgin_request_dialog_icon(PURPLE_REQUEST_INPUT, cpar); |
|
| 453 gtk_widget_set_halign(img, GTK_ALIGN_START); |
|
| 454 gtk_widget_set_valign(img, GTK_ALIGN_START); |
|
| 455 gtk_box_append(GTK_BOX(hbox), img); |
|
| 456 |
|
| 457 pidgin_request_add_help(GTK_DIALOG(dialog), cpar); |
|
| 458 |
|
| 459 /* Vertical box */ |
|
| 460 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); |
|
| 461 gtk_widget_set_hexpand(vbox, TRUE); |
|
| 462 gtk_box_append(GTK_BOX(hbox), vbox); |
|
| 463 |
|
| 464 pidgin_widget_decorate_account(vbox, |
|
| 465 purple_request_cpar_get_account(cpar)); |
|
| 466 |
|
| 467 /* Descriptive label */ |
|
| 468 primary_esc = pidgin_request_escape(cpar, primary); |
|
| 469 secondary_esc = pidgin_request_escape(cpar, secondary); |
|
| 470 label_text = g_strdup_printf((primary ? "<span weight=\"bold\" size=\"larger\">" |
|
| 471 "%s</span>%s%s" : "%s%s%s"), |
|
| 472 (primary ? primary_esc : ""), |
|
| 473 ((primary && secondary) ? "\n\n" : ""), |
|
| 474 (secondary ? secondary_esc : "")); |
|
| 475 g_free(primary_esc); |
|
| 476 g_free(secondary_esc); |
|
| 477 |
|
| 478 label = GTK_LABEL(gtk_label_new(NULL)); |
|
| 479 |
|
| 480 gtk_label_set_markup(label, label_text); |
|
| 481 gtk_label_set_wrap(label, TRUE); |
|
| 482 gtk_label_set_xalign(label, 0); |
|
| 483 gtk_label_set_yalign(label, 0); |
|
| 484 gtk_box_append(GTK_BOX(vbox), GTK_WIDGET(label)); |
|
| 485 |
|
| 486 g_free(label_text); |
|
| 487 |
|
| 488 /* Entry field. */ |
|
| 489 data->u.input.multiline = multiline; |
|
| 490 data->u.input.hint = g_strdup(hint); |
|
| 491 |
|
| 492 if(multiline || purple_strequal(data->u.input.hint, "html")) { |
|
| 493 GtkWidget *sw = NULL; |
|
| 494 GtkWidget *view = NULL; |
|
| 495 GtkTextBuffer *buffer = NULL; |
|
| 496 |
|
| 497 sw = gtk_scrolled_window_new(); |
|
| 498 gtk_widget_set_vexpand(sw, TRUE); |
|
| 499 gtk_box_append(GTK_BOX(vbox), sw); |
|
| 500 |
|
| 501 view = gtk_text_view_new(); |
|
| 502 gtk_widget_set_size_request(view, 320, 130); |
|
| 503 gtk_widget_set_name(view, "pidgin_request_input"); |
|
| 504 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), view); |
|
| 505 |
|
| 506 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)); |
|
| 507 |
|
| 508 if(!purple_strempty(default_value)) { |
|
| 509 if(purple_strequal(data->u.input.hint, "html")) { |
|
| 510 GtkTextIter start; |
|
| 511 |
|
| 512 gtk_text_buffer_get_start_iter(buffer, &start); |
|
| 513 gtk_text_buffer_insert_markup(buffer, &start, default_value, |
|
| 514 -1); |
|
| 515 } else { |
|
| 516 gtk_text_buffer_set_text(buffer, default_value, -1); |
|
| 517 } |
|
| 518 } |
|
| 519 |
|
| 520 data->u.input.entry = view; |
|
| 521 } else { |
|
| 522 GtkWidget *entry = NULL; |
|
| 523 |
|
| 524 if(masked) { |
|
| 525 entry = gtk_password_entry_new(); |
|
| 526 g_object_set(entry, "activates-default", TRUE, |
|
| 527 "show-peek-icon", TRUE, NULL); |
|
| 528 } else { |
|
| 529 entry = gtk_entry_new(); |
|
| 530 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); |
|
| 531 } |
|
| 532 |
|
| 533 gtk_box_append(GTK_BOX(vbox), entry); |
|
| 534 |
|
| 535 if(default_value != NULL) { |
|
| 536 gtk_editable_set_text(GTK_EDITABLE(entry), default_value); |
|
| 537 } |
|
| 538 |
|
| 539 data->u.input.entry = entry; |
|
| 540 } |
|
| 541 |
|
| 542 pidgin_set_accessible_label(data->u.input.entry, label); |
|
| 543 |
|
| 544 pidgin_auto_parent_window(dialog); |
|
| 545 |
|
| 546 /* Show everything. */ |
|
| 547 gtk_widget_set_visible(dialog, TRUE); |
|
| 548 |
|
| 549 return data; |
|
| 550 } |
|
| 551 |
|
| 552 static void * |
|
| 553 pidgin_request_choice(const char *title, const char *primary, |
|
| 554 const char *secondary, gpointer default_value, const char *ok_text, |
|
| 555 GCallback ok_cb, const char *cancel_text, GCallback cancel_cb, |
|
| 556 PurpleRequestCommonParameters *cpar, void *user_data, va_list args) |
|
| 557 { |
|
| 558 PidginRequestData *data; |
|
| 559 GtkWidget *dialog; |
|
| 560 GtkWidget *vbox; |
|
| 561 GtkWidget *hbox; |
|
| 562 GtkWidget *label; |
|
| 563 GtkWidget *img; |
|
| 564 GtkWidget *dropdown; |
|
| 565 GListModel *model; |
|
| 566 GtkWidget *content; |
|
| 567 char *label_text; |
|
| 568 const char *radio_text; |
|
| 569 char *primary_esc, *secondary_esc; |
|
| 570 guint index, selected; |
|
| 571 |
|
| 572 data = g_new0(PidginRequestData, 1); |
|
| 573 data->type = PURPLE_REQUEST_ACTION; |
|
| 574 data->user_data = user_data; |
|
| 575 |
|
| 576 data->cb_count = 2; |
|
| 577 data->cbs = g_new0(GCallback, 2); |
|
| 578 data->cbs[0] = cancel_cb; |
|
| 579 data->cbs[1] = ok_cb; |
|
| 580 |
|
| 581 /* Create the dialog. */ |
|
| 582 data->dialog = dialog = gtk_dialog_new(); |
|
| 583 |
|
| 584 if (title != NULL) |
|
| 585 gtk_window_set_title(GTK_WINDOW(dialog), title); |
|
| 586 #ifdef _WIN32 |
|
| 587 gtk_window_set_title(GTK_WINDOW(dialog), PIDGIN_ALERT_TITLE); |
|
| 588 #endif |
|
| 589 |
|
| 590 gtk_dialog_add_button(GTK_DIALOG(dialog), cancel_text, 0); |
|
| 591 gtk_dialog_add_button(GTK_DIALOG(dialog), ok_text, 1); |
|
| 592 |
|
| 593 g_signal_connect(G_OBJECT(dialog), "response", |
|
| 594 G_CALLBACK(choice_response_cb), data); |
|
| 595 |
|
| 596 /* Setup the dialog */ |
|
| 597 gtk_widget_set_margin_top(dialog, 6); |
|
| 598 gtk_widget_set_margin_bottom(dialog, 6); |
|
| 599 gtk_widget_set_margin_start(dialog, 6); |
|
| 600 gtk_widget_set_margin_end(dialog, 6); |
|
| 601 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); |
|
| 602 |
|
| 603 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); |
|
| 604 gtk_widget_set_margin_top(content, 6); |
|
| 605 gtk_widget_set_margin_bottom(content, 6); |
|
| 606 gtk_widget_set_margin_start(content, 6); |
|
| 607 gtk_widget_set_margin_end(content, 6); |
|
| 608 gtk_box_set_spacing(GTK_BOX(content), 12); |
|
| 609 |
|
| 610 /* Setup the main horizontal box */ |
|
| 611 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12); |
|
| 612 gtk_box_append(GTK_BOX(content), hbox); |
|
| 613 |
|
| 614 /* Dialog icon. */ |
|
| 615 img = pidgin_request_dialog_icon(PURPLE_REQUEST_CHOICE, cpar); |
|
| 616 gtk_widget_set_halign(img, GTK_ALIGN_START); |
|
| 617 gtk_widget_set_valign(img, GTK_ALIGN_START); |
|
| 618 gtk_box_append(GTK_BOX(hbox), img); |
|
| 619 |
|
| 620 pidgin_request_add_help(GTK_DIALOG(dialog), cpar); |
|
| 621 |
|
| 622 /* Vertical box */ |
|
| 623 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); |
|
| 624 gtk_box_append(GTK_BOX(hbox), vbox); |
|
| 625 |
|
| 626 pidgin_widget_decorate_account(vbox, |
|
| 627 purple_request_cpar_get_account(cpar)); |
|
| 628 |
|
| 629 /* Descriptive label */ |
|
| 630 primary_esc = pidgin_request_escape(cpar, primary); |
|
| 631 secondary_esc = pidgin_request_escape(cpar, secondary); |
|
| 632 label_text = g_strdup_printf((primary ? "<span weight=\"bold\" size=\"larger\">" |
|
| 633 "%s</span>%s%s" : "%s%s%s"), |
|
| 634 (primary ? primary_esc : ""), |
|
| 635 ((primary && secondary) ? "\n\n" : ""), |
|
| 636 (secondary ? secondary_esc : "")); |
|
| 637 g_free(primary_esc); |
|
| 638 g_free(secondary_esc); |
|
| 639 |
|
| 640 label = gtk_label_new(NULL); |
|
| 641 |
|
| 642 gtk_label_set_markup(GTK_LABEL(label), label_text); |
|
| 643 gtk_label_set_wrap(GTK_LABEL(label), TRUE); |
|
| 644 gtk_label_set_xalign(GTK_LABEL(label), 0); |
|
| 645 gtk_label_set_yalign(GTK_LABEL(label), 0); |
|
| 646 gtk_widget_set_vexpand(label, TRUE); |
|
| 647 gtk_box_append(GTK_BOX(vbox), label); |
|
| 648 |
|
| 649 g_free(label_text); |
|
| 650 |
|
| 651 dropdown = gtk_drop_down_new_from_strings(NULL); |
|
| 652 gtk_box_append(GTK_BOX(vbox), dropdown); |
|
| 653 g_object_set_data(G_OBJECT(dialog), "dropdown", dropdown); |
|
| 654 |
|
| 655 index = 0; |
|
| 656 selected = GTK_INVALID_LIST_POSITION; |
|
| 657 model = gtk_drop_down_get_model(GTK_DROP_DOWN(dropdown)); |
|
| 658 while((radio_text = va_arg(args, const char *))) { |
|
| 659 GObject *item = NULL; |
|
| 660 gpointer resp = va_arg(args, gpointer); |
|
| 661 |
|
| 662 gtk_string_list_append(GTK_STRING_LIST(model), radio_text); |
|
| 663 item = g_list_model_get_item(model, index); |
|
| 664 g_object_set_data(item, "choice_value", resp); |
|
| 665 if (resp == default_value) { |
|
| 666 selected = index; |
|
| 667 } |
|
| 668 |
|
| 669 g_clear_object(&item); |
|
| 670 index++; |
|
| 671 } |
|
| 672 |
|
| 673 if(selected != GTK_INVALID_LIST_POSITION) { |
|
| 674 gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), selected); |
|
| 675 } |
|
| 676 |
|
| 677 /* Show everything. */ |
|
| 678 pidgin_auto_parent_window(dialog); |
|
| 679 |
|
| 680 gtk_widget_set_visible(dialog, TRUE); |
|
| 681 |
|
| 682 return data; |
|
| 683 } |
|
| 684 |
|
| 685 static void * |
|
| 686 pidgin_request_action(const char *title, const char *primary, |
|
| 687 const char *secondary, int default_action, |
|
| 688 PurpleRequestCommonParameters *cpar, void *user_data, |
|
| 689 size_t action_count, va_list actions) |
|
| 690 { |
|
| 691 PidginRequestData *data; |
|
| 692 GtkWidget *dialog; |
|
| 693 GtkWidget *vbox; |
|
| 694 GtkWidget *hbox; |
|
| 695 GtkWidget *label; |
|
| 696 GtkWidget *img = NULL; |
|
| 697 GtkWidget *content; |
|
| 698 void **buttons; |
|
| 699 char *label_text; |
|
| 700 char *primary_esc, *secondary_esc; |
|
| 701 gsize i; |
|
| 702 |
|
| 703 data = g_new0(PidginRequestData, 1); |
|
| 704 data->type = PURPLE_REQUEST_ACTION; |
|
| 705 data->user_data = user_data; |
|
| 706 |
|
| 707 data->cb_count = action_count; |
|
| 708 data->cbs = g_new0(GCallback, action_count); |
|
| 709 |
|
| 710 /* Reverse the buttons */ |
|
| 711 buttons = g_new0(void *, action_count * 2); |
|
| 712 |
|
| 713 for (i = 0; i < action_count * 2; i += 2) { |
|
| 714 buttons[(action_count * 2) - i - 2] = va_arg(actions, char *); |
|
| 715 buttons[(action_count * 2) - i - 1] = va_arg(actions, GCallback); |
|
| 716 } |
|
| 717 |
|
| 718 /* Create the dialog. */ |
|
| 719 data->dialog = dialog = gtk_dialog_new(); |
|
| 720 |
|
| 721 gtk_window_set_deletable(GTK_WINDOW(data->dialog), FALSE); |
|
| 722 |
|
| 723 if (title != NULL) |
|
| 724 gtk_window_set_title(GTK_WINDOW(dialog), title); |
|
| 725 #ifdef _WIN32 |
|
| 726 else |
|
| 727 gtk_window_set_title(GTK_WINDOW(dialog), PIDGIN_ALERT_TITLE); |
|
| 728 #endif |
|
| 729 |
|
| 730 for (i = 0; i < action_count; i++) { |
|
| 731 gtk_dialog_add_button(GTK_DIALOG(dialog), buttons[2 * i], i); |
|
| 732 |
|
| 733 data->cbs[i] = buttons[2 * i + 1]; |
|
| 734 } |
|
| 735 |
|
| 736 g_free(buttons); |
|
| 737 |
|
| 738 g_signal_connect(G_OBJECT(dialog), "response", |
|
| 739 G_CALLBACK(action_response_cb), data); |
|
| 740 |
|
| 741 /* Setup the dialog */ |
|
| 742 gtk_widget_set_margin_top(dialog, 6); |
|
| 743 gtk_widget_set_margin_bottom(dialog, 6); |
|
| 744 gtk_widget_set_margin_start(dialog, 6); |
|
| 745 gtk_widget_set_margin_end(dialog, 6); |
|
| 746 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); |
|
| 747 |
|
| 748 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); |
|
| 749 gtk_widget_set_margin_top(content, 6); |
|
| 750 gtk_widget_set_margin_bottom(content, 6); |
|
| 751 gtk_widget_set_margin_start(content, 6); |
|
| 752 gtk_widget_set_margin_end(content, 6); |
|
| 753 gtk_box_set_spacing(GTK_BOX(content), 12); |
|
| 754 |
|
| 755 /* Setup the main horizontal box */ |
|
| 756 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12); |
|
| 757 gtk_box_append(GTK_BOX(content), hbox); |
|
| 758 |
|
| 759 img = pidgin_request_dialog_icon(PURPLE_REQUEST_ACTION, cpar); |
|
| 760 gtk_widget_set_halign(img, GTK_ALIGN_START); |
|
| 761 gtk_widget_set_valign(img, GTK_ALIGN_START); |
|
| 762 gtk_box_append(GTK_BOX(hbox), img); |
|
| 763 |
|
| 764 /* Vertical box */ |
|
| 765 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); |
|
| 766 gtk_box_append(GTK_BOX(hbox), vbox); |
|
| 767 |
|
| 768 pidgin_widget_decorate_account(vbox, |
|
| 769 purple_request_cpar_get_account(cpar)); |
|
| 770 |
|
| 771 pidgin_request_add_help(GTK_DIALOG(dialog), cpar); |
|
| 772 |
|
| 773 /* Descriptive label */ |
|
| 774 primary_esc = pidgin_request_escape(cpar, primary); |
|
| 775 secondary_esc = pidgin_request_escape(cpar, secondary); |
|
| 776 label_text = g_strdup_printf((primary ? "<span weight=\"bold\" size=\"larger\">" |
|
| 777 "%s</span>%s%s" : "%s%s%s"), |
|
| 778 (primary ? primary_esc : ""), |
|
| 779 ((primary && secondary) ? "\n\n" : ""), |
|
| 780 (secondary ? secondary_esc : "")); |
|
| 781 g_free(primary_esc); |
|
| 782 g_free(secondary_esc); |
|
| 783 |
|
| 784 label = gtk_label_new(NULL); |
|
| 785 |
|
| 786 gtk_label_set_markup(GTK_LABEL(label), label_text); |
|
| 787 gtk_label_set_wrap(GTK_LABEL(label), TRUE); |
|
| 788 gtk_label_set_xalign(GTK_LABEL(label), 0); |
|
| 789 gtk_label_set_yalign(GTK_LABEL(label), 0); |
|
| 790 gtk_label_set_selectable(GTK_LABEL(label), TRUE); |
|
| 791 gtk_widget_set_vexpand(label, TRUE); |
|
| 792 gtk_box_append(GTK_BOX(vbox), label); |
|
| 793 |
|
| 794 g_free(label_text); |
|
| 795 |
|
| 796 |
|
| 797 if (default_action != PURPLE_DEFAULT_ACTION_NONE) { |
|
| 798 /* |
|
| 799 * Need to invert the default_action number because the |
|
| 800 * buttons are added to the dialog in reverse order. |
|
| 801 */ |
|
| 802 gtk_dialog_set_default_response(GTK_DIALOG(dialog), action_count - 1 - default_action); |
|
| 803 } |
|
| 804 |
|
| 805 /* Show everything. */ |
|
| 806 pidgin_auto_parent_window(dialog); |
|
| 807 |
|
| 808 gtk_widget_set_visible(dialog, TRUE); |
|
| 809 |
|
| 810 return data; |
|
| 811 } |
|
| 812 |
|
| 813 static void |
|
| 814 wait_response_cb(G_GNUC_UNUSED GtkDialog *dialog, G_GNUC_UNUSED gint id, |
|
| 815 PidginRequestData *data) |
|
| 816 { |
|
| 817 generic_response_start(data); |
|
| 818 |
|
| 819 if (data->cbs[0] != NULL) |
|
| 820 ((PurpleRequestCancelCb)data->cbs[0])(data->user_data); |
|
| 821 |
|
| 822 purple_request_close(PURPLE_REQUEST_FIELDS, data); |
|
| 823 } |
|
| 824 |
|
| 825 static void * |
|
| 826 pidgin_request_wait(const char *title, const char *primary, |
|
| 827 const char *secondary, gboolean with_progress, |
|
| 828 PurpleRequestCancelCb cancel_cb, PurpleRequestCommonParameters *cpar, |
|
| 829 void *user_data) |
|
| 830 { |
|
| 831 PidginRequestData *data; |
|
| 832 GtkWidget *dialog, *content; |
|
| 833 GtkWidget *hbox, *vbox, *img, *label; |
|
| 834 gchar *primary_esc, *secondary_esc, *label_text; |
|
| 835 |
|
| 836 data = g_new0(PidginRequestData, 1); |
|
| 837 data->type = PURPLE_REQUEST_WAIT; |
|
| 838 data->user_data = user_data; |
|
| 839 |
|
| 840 data->cb_count = 1; |
|
| 841 data->cbs = g_new0(GCallback, 1); |
|
| 842 data->cbs[0] = (GCallback)cancel_cb; |
|
| 843 |
|
| 844 data->dialog = dialog = gtk_dialog_new(); |
|
| 845 |
|
| 846 g_signal_connect(G_OBJECT(dialog), "response", |
|
| 847 G_CALLBACK(wait_response_cb), data); |
|
| 848 |
|
| 849 gtk_window_set_deletable(GTK_WINDOW(data->dialog), cancel_cb != NULL); |
|
| 850 |
|
| 851 if (title != NULL) |
|
| 852 gtk_window_set_title(GTK_WINDOW(dialog), title); |
|
| 853 else |
|
| 854 gtk_window_set_title(GTK_WINDOW(dialog), _("Please wait")); |
|
| 855 |
|
| 856 /* Setup the dialog */ |
|
| 857 gtk_widget_set_margin_top(dialog, 6); |
|
| 858 gtk_widget_set_margin_bottom(dialog, 6); |
|
| 859 gtk_widget_set_margin_start(dialog, 6); |
|
| 860 gtk_widget_set_margin_end(dialog, 6); |
|
| 861 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); |
|
| 862 |
|
| 863 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); |
|
| 864 gtk_widget_set_margin_top(content, 6); |
|
| 865 gtk_widget_set_margin_bottom(content, 6); |
|
| 866 gtk_widget_set_margin_start(content, 6); |
|
| 867 gtk_widget_set_margin_end(content, 6); |
|
| 868 gtk_box_set_spacing(GTK_BOX(content), 12); |
|
| 869 |
|
| 870 /* Setup the main horizontal box */ |
|
| 871 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12); |
|
| 872 gtk_box_append(GTK_BOX(content), hbox); |
|
| 873 |
|
| 874 img = pidgin_request_dialog_icon(PURPLE_REQUEST_WAIT, cpar); |
|
| 875 gtk_widget_set_halign(img, GTK_ALIGN_START); |
|
| 876 gtk_widget_set_valign(img, GTK_ALIGN_START); |
|
| 877 gtk_box_append(GTK_BOX(hbox), img); |
|
| 878 |
|
| 879 /* Cancel button */ |
|
| 880 gtk_dialog_add_button(GTK_DIALOG(dialog), _("Cancel"), GTK_RESPONSE_CANCEL); |
|
| 881 |
|
| 882 /* Vertical box */ |
|
| 883 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); |
|
| 884 gtk_box_append(GTK_BOX(hbox), vbox); |
|
| 885 |
|
| 886 pidgin_widget_decorate_account(vbox, |
|
| 887 purple_request_cpar_get_account(cpar)); |
|
| 888 |
|
| 889 pidgin_request_add_help(GTK_DIALOG(dialog), cpar); |
|
| 890 |
|
| 891 /* Descriptive label */ |
|
| 892 primary_esc = pidgin_request_escape(cpar, primary); |
|
| 893 secondary_esc = pidgin_request_escape(cpar, secondary); |
|
| 894 label_text = g_strdup_printf((primary ? "<span weight=\"bold\" " |
|
| 895 "size=\"larger\">%s</span>%s%s" : "%s%s%s"), |
|
| 896 (primary ? primary_esc : ""), |
|
| 897 ((primary && secondary) ? "\n\n" : ""), |
|
| 898 (secondary ? secondary_esc : "")); |
|
| 899 g_free(primary_esc); |
|
| 900 g_free(secondary_esc); |
|
| 901 |
|
| 902 label = gtk_label_new(NULL); |
|
| 903 |
|
| 904 gtk_label_set_markup(GTK_LABEL(label), label_text); |
|
| 905 gtk_label_set_wrap(GTK_LABEL(label), TRUE); |
|
| 906 gtk_label_set_xalign(GTK_LABEL(label), 0); |
|
| 907 gtk_label_set_yalign(GTK_LABEL(label), 0); |
|
| 908 gtk_label_set_selectable(GTK_LABEL(label), FALSE); |
|
| 909 gtk_widget_set_vexpand(label, TRUE); |
|
| 910 gtk_box_append(GTK_BOX(vbox), label); |
|
| 911 |
|
| 912 g_free(label_text); |
|
| 913 |
|
| 914 if (with_progress) { |
|
| 915 GtkProgressBar *bar; |
|
| 916 |
|
| 917 bar = data->u.wait.progress_bar = |
|
| 918 GTK_PROGRESS_BAR(gtk_progress_bar_new()); |
|
| 919 gtk_progress_bar_set_fraction(bar, 0); |
|
| 920 gtk_box_append(GTK_BOX(vbox), GTK_WIDGET(bar)); |
|
| 921 } |
|
| 922 |
|
| 923 /* Show everything. */ |
|
| 924 pidgin_auto_parent_window(dialog); |
|
| 925 |
|
| 926 gtk_widget_set_visible(dialog, TRUE); |
|
| 927 |
|
| 928 return data; |
|
| 929 } |
|
| 930 |
|
| 931 static void |
|
| 932 pidgin_request_wait_update(void *ui_handle, gboolean pulse, gfloat fraction) |
|
| 933 { |
|
| 934 GtkProgressBar *bar; |
|
| 935 PidginRequestData *data = ui_handle; |
|
| 936 |
|
| 937 g_return_if_fail(data->type == PURPLE_REQUEST_WAIT); |
|
| 938 |
|
| 939 bar = data->u.wait.progress_bar; |
|
| 940 if (pulse) |
|
| 941 gtk_progress_bar_pulse(bar); |
|
| 942 else |
|
| 943 gtk_progress_bar_set_fraction(bar, fraction); |
|
| 944 } |
292 } |
| 945 |
293 |
| 946 static GtkWidget * |
294 static GtkWidget * |
| 947 create_label_field(void) { |
295 create_label_field(void) { |
| 948 GtkWidget *row = NULL; |
296 GtkWidget *row = NULL; |
| 1617 gtk_widget_set_visible(win, TRUE); |
965 gtk_widget_set_visible(win, TRUE); |
| 1618 |
966 |
| 1619 return data; |
967 return data; |
| 1620 } |
968 } |
| 1621 |
969 |
| 1622 static void |
|
| 1623 pidgin_request_file_response_cb(GObject *obj, GAsyncResult *result, |
|
| 1624 gpointer user_data) |
|
| 1625 { |
|
| 1626 PidginRequestData *data = user_data; |
|
| 1627 GFile *path = NULL; |
|
| 1628 GFile *parent = NULL; |
|
| 1629 GError *error = NULL; |
|
| 1630 |
|
| 1631 if(data->u.file.savedialog) { |
|
| 1632 path = gtk_file_dialog_save_finish(GTK_FILE_DIALOG(obj), result, |
|
| 1633 &error); |
|
| 1634 } else { |
|
| 1635 path = gtk_file_dialog_open_finish(GTK_FILE_DIALOG(obj), result, |
|
| 1636 &error); |
|
| 1637 } |
|
| 1638 if(path == NULL) { |
|
| 1639 if(!g_error_matches(error, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_CANCELLED)) { |
|
| 1640 if(data->cbs[0] != NULL) { |
|
| 1641 ((PurpleRequestFileCb)data->cbs[0])(data->user_data, NULL); |
|
| 1642 } |
|
| 1643 purple_request_close(data->type, data); |
|
| 1644 } |
|
| 1645 g_clear_error(&error); |
|
| 1646 return; |
|
| 1647 } |
|
| 1648 |
|
| 1649 parent = g_file_get_parent(path); |
|
| 1650 if(parent != NULL) { |
|
| 1651 char *current_folder = g_file_get_path(parent); |
|
| 1652 if (data->u.file.savedialog) { |
|
| 1653 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_save_folder", |
|
| 1654 current_folder); |
|
| 1655 } else { |
|
| 1656 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_open_folder", |
|
| 1657 current_folder); |
|
| 1658 } |
|
| 1659 g_free(current_folder); |
|
| 1660 } |
|
| 1661 |
|
| 1662 if(data->cbs[1] != NULL) { |
|
| 1663 char *filename = g_file_get_path(path); |
|
| 1664 ((PurpleRequestFileCb)data->cbs[1])(data->user_data, filename); |
|
| 1665 g_free(filename); |
|
| 1666 } |
|
| 1667 |
|
| 1668 g_clear_object(&parent); |
|
| 1669 g_clear_object(&path); |
|
| 1670 g_clear_object(&data->cancellable); |
|
| 1671 purple_request_close(data->type, data); |
|
| 1672 } |
|
| 1673 |
|
| 1674 static void |
|
| 1675 pidgin_request_folder_response_cb(GObject *obj, GAsyncResult *result, |
|
| 1676 gpointer user_data) |
|
| 1677 { |
|
| 1678 PidginRequestData *data = user_data; |
|
| 1679 GFile *path = NULL; |
|
| 1680 char *folder = NULL; |
|
| 1681 GError *error = NULL; |
|
| 1682 |
|
| 1683 path = gtk_file_dialog_select_folder_finish(GTK_FILE_DIALOG(obj), result, |
|
| 1684 &error); |
|
| 1685 if(path == NULL) { |
|
| 1686 if(!g_error_matches(error, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_CANCELLED)) { |
|
| 1687 if(data->cbs[0] != NULL) { |
|
| 1688 ((PurpleRequestFileCb)data->cbs[0])(data->user_data, NULL); |
|
| 1689 } |
|
| 1690 purple_request_close(data->type, data); |
|
| 1691 } |
|
| 1692 g_clear_error(&error); |
|
| 1693 return; |
|
| 1694 } |
|
| 1695 |
|
| 1696 folder = g_file_get_path(path); |
|
| 1697 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_open_folder", |
|
| 1698 folder); |
|
| 1699 |
|
| 1700 if(data->cbs[1] != NULL) { |
|
| 1701 ((PurpleRequestFileCb)data->cbs[1])(data->user_data, folder); |
|
| 1702 } |
|
| 1703 |
|
| 1704 g_free(folder); |
|
| 1705 g_clear_object(&path); |
|
| 1706 g_clear_object(&data->cancellable); |
|
| 1707 purple_request_close(data->type, data); |
|
| 1708 } |
|
| 1709 |
|
| 1710 static void * |
|
| 1711 pidgin_request_file(const char *title, const char *filename, |
|
| 1712 gboolean savedialog, GCallback ok_cb, GCallback cancel_cb, |
|
| 1713 G_GNUC_UNUSED PurpleRequestCommonParameters *cpar, |
|
| 1714 gpointer user_data) |
|
| 1715 { |
|
| 1716 PidginRequestData *data; |
|
| 1717 GtkFileDialog *dialog = NULL; |
|
| 1718 #ifdef _WIN32 |
|
| 1719 const gchar *current_folder; |
|
| 1720 gboolean folder_set = FALSE; |
|
| 1721 #endif |
|
| 1722 |
|
| 1723 data = g_new0(PidginRequestData, 1); |
|
| 1724 data->type = PURPLE_REQUEST_FILE; |
|
| 1725 data->user_data = user_data; |
|
| 1726 data->cb_count = 2; |
|
| 1727 data->cbs = g_new0(GCallback, 2); |
|
| 1728 data->cbs[0] = cancel_cb; |
|
| 1729 data->cbs[1] = ok_cb; |
|
| 1730 data->u.file.savedialog = savedialog; |
|
| 1731 |
|
| 1732 data->dialog = dialog = gtk_file_dialog_new(); |
|
| 1733 gtk_file_dialog_set_title(dialog, |
|
| 1734 title ? title |
|
| 1735 : (savedialog ? _("Save File...") |
|
| 1736 : _("Open File..."))); |
|
| 1737 |
|
| 1738 if(!purple_strempty(filename)) { |
|
| 1739 GFile *path = g_file_new_for_path(filename); |
|
| 1740 |
|
| 1741 if(savedialog || g_file_test(filename, G_FILE_TEST_EXISTS)) { |
|
| 1742 gtk_file_dialog_set_initial_file(dialog, path); |
|
| 1743 } |
|
| 1744 |
|
| 1745 g_object_unref(path); |
|
| 1746 } |
|
| 1747 |
|
| 1748 #ifdef _WIN32 |
|
| 1749 if (savedialog) { |
|
| 1750 current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_save_folder"); |
|
| 1751 } else { |
|
| 1752 current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_open_folder"); |
|
| 1753 } |
|
| 1754 |
|
| 1755 if((purple_strempty(filename) || !g_file_test(filename, G_FILE_TEST_EXISTS)) && |
|
| 1756 !purple_strempty(current_folder)) |
|
| 1757 { |
|
| 1758 GFile *file = g_file_new_for_path(current_folder); |
|
| 1759 gtk_file_dialog_set_initial_folder(dialog, file); |
|
| 1760 folder_set = TRUE; |
|
| 1761 g_clear_object(&file); |
|
| 1762 } |
|
| 1763 |
|
| 1764 if(!folder_set && |
|
| 1765 (purple_strempty(filename) || !g_file_test(filename, G_FILE_TEST_EXISTS))) |
|
| 1766 { |
|
| 1767 const char *my_documents = NULL; |
|
| 1768 |
|
| 1769 my_documents = g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS); |
|
| 1770 if (my_documents != NULL) { |
|
| 1771 GFile *file = g_file_new_for_path(my_documents); |
|
| 1772 |
|
| 1773 gtk_file_dialog_set_initial_folder(dialog, file); |
|
| 1774 |
|
| 1775 g_clear_object(&file); |
|
| 1776 } |
|
| 1777 } |
|
| 1778 #endif |
|
| 1779 |
|
| 1780 data->cancellable = g_cancellable_new(); |
|
| 1781 if(savedialog) { |
|
| 1782 gtk_file_dialog_save(dialog, NULL, data->cancellable, |
|
| 1783 pidgin_request_file_response_cb, data); |
|
| 1784 } else { |
|
| 1785 gtk_file_dialog_open(dialog, NULL, data->cancellable, |
|
| 1786 pidgin_request_file_response_cb, data); |
|
| 1787 } |
|
| 1788 |
|
| 1789 return (void *)data; |
|
| 1790 } |
|
| 1791 |
|
| 1792 static void * |
|
| 1793 pidgin_request_folder(const char *title, const char *dirname, GCallback ok_cb, |
|
| 1794 GCallback cancel_cb, |
|
| 1795 G_GNUC_UNUSED PurpleRequestCommonParameters *cpar, |
|
| 1796 gpointer user_data) |
|
| 1797 { |
|
| 1798 PidginRequestData *data; |
|
| 1799 GtkFileDialog *dialog = NULL; |
|
| 1800 |
|
| 1801 data = g_new0(PidginRequestData, 1); |
|
| 1802 data->type = PURPLE_REQUEST_FOLDER; |
|
| 1803 data->user_data = user_data; |
|
| 1804 data->cb_count = 2; |
|
| 1805 data->cbs = g_new0(GCallback, 2); |
|
| 1806 data->cbs[0] = cancel_cb; |
|
| 1807 data->cbs[1] = ok_cb; |
|
| 1808 data->u.file.savedialog = FALSE; |
|
| 1809 |
|
| 1810 data->cancellable = g_cancellable_new(); |
|
| 1811 data->dialog = dialog = gtk_file_dialog_new(); |
|
| 1812 gtk_file_dialog_set_title(dialog, title ? title : _("Select Folder...")); |
|
| 1813 |
|
| 1814 if(!purple_strempty(dirname)) { |
|
| 1815 GFile *path = g_file_new_for_path(dirname); |
|
| 1816 gtk_file_dialog_set_initial_folder(dialog, path); |
|
| 1817 g_object_unref(path); |
|
| 1818 } |
|
| 1819 |
|
| 1820 gtk_file_dialog_select_folder(dialog, NULL, data->cancellable, |
|
| 1821 pidgin_request_folder_response_cb, data); |
|
| 1822 |
|
| 1823 return (void *)data; |
|
| 1824 } |
|
| 1825 |
|
| 1826 /* if request callback issues another request, it should be attached to the |
|
| 1827 * primary request parent */ |
|
| 1828 static void |
|
| 1829 pidgin_window_detach_children(GtkWindow* win) |
|
| 1830 { |
|
| 1831 GList *it; |
|
| 1832 GtkWindow *par; |
|
| 1833 |
|
| 1834 g_return_if_fail(win != NULL); |
|
| 1835 |
|
| 1836 par = gtk_window_get_transient_for(win); |
|
| 1837 it = gtk_window_list_toplevels(); |
|
| 1838 for (it = g_list_first(it); it != NULL; it = g_list_delete_link(it, it)) { |
|
| 1839 GtkWindow *child = GTK_WINDOW(it->data); |
|
| 1840 if (gtk_window_get_transient_for(child) != win) |
|
| 1841 continue; |
|
| 1842 if (gtk_window_get_destroy_with_parent(child)) { |
|
| 1843 #ifdef _WIN32 |
|
| 1844 /* XXX test/verify it: Win32 gtk ignores |
|
| 1845 * gtk_window_set_destroy_with_parent(..., FALSE). */ |
|
| 1846 gtk_window_set_transient_for(child, NULL); |
|
| 1847 #endif |
|
| 1848 continue; |
|
| 1849 } |
|
| 1850 gtk_window_set_transient_for(child, par); |
|
| 1851 } |
|
| 1852 } |
|
| 1853 |
|
| 1854 static void |
|
| 1855 pidgin_close_request(PurpleRequestType type, void *ui_handle) |
|
| 1856 { |
|
| 1857 PidginRequestData *data = (PidginRequestData *)ui_handle; |
|
| 1858 |
|
| 1859 if(data->cancellable != NULL) { |
|
| 1860 g_cancellable_cancel(data->cancellable); |
|
| 1861 } |
|
| 1862 |
|
| 1863 if (type == PURPLE_REQUEST_FILE || type == PURPLE_REQUEST_FOLDER) { |
|
| 1864 /* Will be a GtkFileDialog, not GtkDialog. */ |
|
| 1865 g_clear_object(&data->dialog); |
|
| 1866 } else { |
|
| 1867 pidgin_window_detach_children(GTK_WINDOW(data->dialog)); |
|
| 1868 |
|
| 1869 gtk_window_destroy(GTK_WINDOW(data->dialog)); |
|
| 1870 } |
|
| 1871 |
|
| 1872 if(type == PURPLE_REQUEST_FIELDS) { |
|
| 1873 g_clear_object(&data->u.multifield.page); |
|
| 1874 } |
|
| 1875 |
|
| 1876 g_clear_object(&data->cancellable); |
|
| 1877 g_free(data->cbs); |
|
| 1878 g_free(data); |
|
| 1879 } |
|
| 1880 |
|
| 1881 GtkWindow * |
970 GtkWindow * |
| 1882 pidgin_request_get_dialog_window(void *ui_handle) |
971 pidgin_request_get_dialog_window(void *ui_handle) |
| 1883 { |
972 { |
| 1884 PidginRequestData *data = ui_handle; |
973 PidginRequestData *data = ui_handle; |
| 1885 |
974 |