| | 632 | |
|---|
| | 633 | /* SIGNALS */ |
|---|
| | 634 | |
|---|
| | 635 | typedef struct { |
|---|
| | 636 | GClosure closure; |
|---|
| | 637 | zval *callback; |
|---|
| | 638 | zval ***args; |
|---|
| | 639 | guint argc; |
|---|
| | 640 | guint type; |
|---|
| | 641 | zval *zobject; |
|---|
| | 642 | } php_mgd_closure; |
|---|
| | 643 | |
|---|
| | 644 | static void php_midgard_closure_invalidate(gpointer data, GClosure *closure) |
|---|
| | 645 | { |
|---|
| | 646 | php_mgd_closure *mgdclosure = (php_mgd_closure *) closure; |
|---|
| | 647 | efree(mgdclosure->args); |
|---|
| | 648 | |
|---|
| | 649 | mgdclosure->callback = NULL; |
|---|
| | 650 | mgdclosure->args = NULL; |
|---|
| | 651 | mgdclosure->zobject = NULL; |
|---|
| | 652 | } |
|---|
| | 653 | |
|---|
| | 654 | static void php_midgard_closure_marshal(GClosure *closure, |
|---|
| | 655 | GValue *return_value, guint n_param_values, |
|---|
| | 656 | const GValue *param_values, gpointer invocation_hint, |
|---|
| | 657 | gpointer marshal_data) |
|---|
| | 658 | { |
|---|
| | 659 | php_mgd_closure *mgdclosure = (php_mgd_closure *) closure; |
|---|
| | 660 | gchar *callback_func; |
|---|
| | 661 | |
|---|
| | 662 | /* check if method can be invoked for object */ |
|---|
| | 663 | if(mgdclosure->zobject != NULL) { |
|---|
| | 664 | |
|---|
| | 665 | gchar *lname = |
|---|
| | 666 | zend_str_tolower_dup(Z_STRVAL_P(mgdclosure->callback), |
|---|
| | 667 | Z_STRLEN_P(mgdclosure->callback)); |
|---|
| | 668 | |
|---|
| | 669 | if (!zend_hash_exists(&Z_OBJCE_P(mgdclosure->zobject)->function_table, |
|---|
| | 670 | lname, |
|---|
| | 671 | Z_STRLEN_P(mgdclosure->callback)+1)) { |
|---|
| | 672 | |
|---|
| | 673 | efree(lname); |
|---|
| | 674 | php_error(E_WARNING, "Can not invoke '%s::%s' as callback", |
|---|
| | 675 | Z_OBJCE_P(mgdclosure->zobject)->name, |
|---|
| | 676 | Z_STRVAL_P(mgdclosure->callback)); |
|---|
| | 677 | return; |
|---|
| | 678 | } |
|---|
| | 679 | |
|---|
| | 680 | efree(lname); |
|---|
| | 681 | |
|---|
| | 682 | } else { |
|---|
| | 683 | |
|---|
| | 684 | if (!zend_is_callable(mgdclosure->callback, 0, &callback_func)) { |
|---|
| | 685 | |
|---|
| | 686 | php_error(E_WARNING, "Can not invoke '%s' callback", callback_func); |
|---|
| | 687 | return; |
|---|
| | 688 | } |
|---|
| | 689 | } |
|---|
| | 690 | |
|---|
| | 691 | zval *retval = NULL; |
|---|
| | 692 | guint i; |
|---|
| | 693 | zval ***args = mgdclosure->args; |
|---|
| | 694 | guint argc = mgdclosure->argc; |
|---|
| | 695 | |
|---|
| | 696 | if(args != NULL) { |
|---|
| | 697 | |
|---|
| | 698 | for(i = 0; i < argc ; i++) { |
|---|
| | 699 | if(*args[i] == NULL){ |
|---|
| | 700 | g_warning("Value is NULL, Setting 0."); |
|---|
| | 701 | MAKE_STD_ZVAL(*args[i]); |
|---|
| | 702 | ZVAL_LONG(*args[i], 0); |
|---|
| | 703 | } |
|---|
| | 704 | } |
|---|
| | 705 | } |
|---|
| | 706 | |
|---|
| | 707 | if(mgdclosure->zobject != NULL) { |
|---|
| | 708 | |
|---|
| | 709 | call_user_function_ex(NULL, &mgdclosure->zobject , mgdclosure->callback, |
|---|
| | 710 | &retval, argc, args, 0, NULL TSRMLS_CC); |
|---|
| | 711 | |
|---|
| | 712 | } else { |
|---|
| | 713 | |
|---|
| | 714 | call_user_function_ex(EG(function_table), NULL, mgdclosure->callback, |
|---|
| | 715 | &retval, argc, args, 0, NULL TSRMLS_CC); |
|---|
| | 716 | } |
|---|
| | 717 | |
|---|
| | 718 | } |
|---|
| | 719 | |
|---|
| | 720 | static GClosure *php_midgard_closure_new(zval *callback, zval *zobject, zval ***args, guint argc TSRMLS_DC) |
|---|
| | 721 | { |
|---|
| | 722 | GClosure *closure; |
|---|
| | 723 | php_mgd_closure *mgdclosure; |
|---|
| | 724 | |
|---|
| | 725 | if(zobject == NULL) { |
|---|
| | 726 | |
|---|
| | 727 | closure = g_closure_new_simple(sizeof(php_mgd_closure), NULL); |
|---|
| | 728 | |
|---|
| | 729 | } else { |
|---|
| | 730 | |
|---|
| | 731 | php_midgard_gobject *php_gobject = |
|---|
| | 732 | (php_midgard_gobject *)zend_object_store_get_object(zobject TSRMLS_CC); |
|---|
| | 733 | |
|---|
| | 734 | if(g_type_from_name(Z_OBJCE_P(zobject)->name)) { |
|---|
| | 735 | |
|---|
| | 736 | GObject *object = G_OBJECT(php_gobject->gobject); |
|---|
| | 737 | closure = g_closure_new_object(sizeof(php_mgd_closure), object); |
|---|
| | 738 | |
|---|
| | 739 | } else { |
|---|
| | 740 | |
|---|
| | 741 | closure = g_closure_new_simple(sizeof(php_mgd_closure), NULL); |
|---|
| | 742 | } |
|---|
| | 743 | } |
|---|
| | 744 | |
|---|
| | 745 | if(!closure) |
|---|
| | 746 | php_error(E_ERROR, "Couldn't create new closure"); |
|---|
| | 747 | |
|---|
| | 748 | mgdclosure = (php_mgd_closure*) closure; |
|---|
| | 749 | zval_add_ref(&callback); |
|---|
| | 750 | mgdclosure->callback = callback; |
|---|
| | 751 | mgdclosure->zobject = zobject; |
|---|
| | 752 | mgdclosure->argc = argc; |
|---|
| | 753 | mgdclosure->args = NULL; |
|---|
| | 754 | |
|---|
| | 755 | if(args != NULL) { |
|---|
| | 756 | |
|---|
| | 757 | zval_add_ref(*args); |
|---|
| | 758 | mgdclosure->args = args; |
|---|
| | 759 | } |
|---|
| | 760 | |
|---|
| | 761 | g_closure_add_invalidate_notifier(closure, NULL, php_midgard_closure_invalidate); |
|---|
| | 762 | g_closure_set_marshal((GClosure *)mgdclosure, php_midgard_closure_marshal); |
|---|
| | 763 | |
|---|
| | 764 | return closure; |
|---|
| | 765 | } |
|---|
| | 766 | |
|---|
| | 767 | void php_midgard_gobject_connect(INTERNAL_FUNCTION_PARAMETERS) |
|---|
| | 768 | { |
|---|
| | 769 | zval *callback; |
|---|
| | 770 | gchar *sname = NULL; |
|---|
| | 771 | guint sname_length; |
|---|
| | 772 | guint signal_id; |
|---|
| | 773 | zval *zval_object = getThis(); |
|---|
| | 774 | zval *zobject = NULL; |
|---|
| | 775 | zval ***args = NULL; |
|---|
| | 776 | GQuark signal_detail; |
|---|
| | 777 | GClosure *closure = NULL; |
|---|
| | 778 | zval ***params_array = NULL; |
|---|
| | 779 | |
|---|
| | 780 | gint argc = ZEND_NUM_ARGS(); |
|---|
| | 781 | |
|---|
| | 782 | /* A function without parameters */ |
|---|
| | 783 | if(argc == 2) { |
|---|
| | 784 | |
|---|
| | 785 | if (zend_parse_parameters(2, "sz", |
|---|
| | 786 | &sname, &sname_length, &callback) |
|---|
| | 787 | == FAILURE) { |
|---|
| | 788 | return; |
|---|
| | 789 | } |
|---|
| | 790 | |
|---|
| | 791 | argc = 0; |
|---|
| | 792 | } |
|---|
| | 793 | |
|---|
| | 794 | /* A method without parameters */ |
|---|
| | 795 | if(argc == 3) { |
|---|
| | 796 | |
|---|
| | 797 | if (zend_parse_parameters(3, "szo", |
|---|
| | 798 | &sname, &sname_length, &callback, |
|---|
| | 799 | &zobject, &args) |
|---|
| | 800 | == FAILURE) { |
|---|
| | 801 | return; |
|---|
| | 802 | } |
|---|
| | 803 | |
|---|
| | 804 | argc = 0; |
|---|
| | 805 | } |
|---|
| | 806 | |
|---|
| | 807 | |
|---|
| | 808 | /* A method or function with varargs */ |
|---|
| | 809 | if(argc > 3) { |
|---|
| | 810 | |
|---|
| | 811 | args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0); |
|---|
| | 812 | if (zend_get_parameters_array_ex(argc, args) == FAILURE) { |
|---|
| | 813 | efree(args); |
|---|
| | 814 | WRONG_PARAM_COUNT; |
|---|
| | 815 | } |
|---|
| | 816 | |
|---|
| | 817 | /* Keep '!' as passed object parameter can be NULL */ |
|---|
| | 818 | if (zend_parse_parameters(3, "szo!", |
|---|
| | 819 | &sname, &sname_length, |
|---|
| | 820 | &callback, &zobject) |
|---|
| | 821 | == FAILURE) { |
|---|
| | 822 | efree(args); |
|---|
| | 823 | return; |
|---|
| | 824 | } |
|---|
| | 825 | |
|---|
| | 826 | guint i; |
|---|
| | 827 | |
|---|
| | 828 | params_array = |
|---|
| | 829 | (zval ***) emalloc(sizeof(zval **)*(argc-3)); |
|---|
| | 830 | |
|---|
| | 831 | for (i = 3; i < argc; i++) { |
|---|
| | 832 | |
|---|
| | 833 | params_array[i-3] = args[i]; |
|---|
| | 834 | } |
|---|
| | 835 | |
|---|
| | 836 | efree(args); |
|---|
| | 837 | /* Do not get signal name, function name and optional object */ |
|---|
| | 838 | argc = argc - 3; |
|---|
| | 839 | } |
|---|
| | 840 | |
|---|
| | 841 | /* Get underlying GObject instance */ |
|---|
| | 842 | php_midgard_gobject *php_gobject = |
|---|
| | 843 | (php_midgard_gobject *)zend_object_store_get_object(zval_object TSRMLS_CC); |
|---|
| | 844 | GObject *object = G_OBJECT(php_gobject->gobject); |
|---|
| | 845 | |
|---|
| | 846 | if (!g_signal_parse_name(sname, G_OBJECT_TYPE(object), |
|---|
| | 847 | &signal_id, &signal_detail, TRUE)) { |
|---|
| | 848 | php_error(E_WARNING, "%s signal name is invalid", sname); |
|---|
| | 849 | return; |
|---|
| | 850 | /* TODO , should we handle exception here? */ |
|---|
| | 851 | } |
|---|
| | 852 | |
|---|
| | 853 | closure = php_midgard_closure_new(callback, zobject, params_array, argc); |
|---|
| | 854 | |
|---|
| | 855 | if(!closure) { |
|---|
| | 856 | php_error(E_WARNING, "Can not create new closure"); |
|---|
| | 857 | return; |
|---|
| | 858 | } |
|---|
| | 859 | |
|---|
| | 860 | g_signal_connect_closure_by_id(object, signal_id, signal_detail, closure, FALSE); |
|---|
| | 861 | } |
|---|