#include "libublsettings-gtk3.h"


void on_subwindow_close(GtkWidget *self){
    gtk_widget_destroy(gtk_widget_get_toplevel(self));
}

void yon_on_password_visibility_changed(GtkEntry *self, GtkEntryIconPosition position){
    if (position==GTK_ENTRY_ICON_SECONDARY){
        int status = gtk_entry_get_visibility(self);
        gtk_entry_set_visibility(self,!status);
    }
}

void yon_gtk_entry_set_password_visibility_icon(GtkEntry *target){
    g_return_if_fail(GTK_IS_ENTRY(target));
    gtk_entry_set_icon_from_icon_name(target,GTK_ENTRY_ICON_SECONDARY,"com.ublinux.libublsettingsui-gtk3.view-symbolic");
    g_signal_connect(G_OBJECT(target),"icon-release",G_CALLBACK(yon_on_password_visibility_changed),NULL);
}

int yon_gtk_window_setup(GtkWindow *window, GtkWindow *transistent_window, char *title, char *icon_name, char *window_id){
    if (GTK_IS_WINDOW(window)){
        int success=0;
        if (transistent_window){
            gtk_window_set_transient_for(window,transistent_window);
            success++;
        }
        if (!yon_char_is_empty(title)){
            gtk_window_set_title(window,title);
            GtkWidget *titlebar = gtk_window_get_titlebar(window);
            if (titlebar){
                GtkWidget *title_label = gtk_header_bar_get_custom_title(GTK_HEADER_BAR(titlebar));
                if (title_label){
                    gtk_label_set_text(GTK_LABEL(title_label),title);                    
                }
            }
            success++;
        }
        if (!yon_char_is_empty(icon_name)){
            gtk_window_set_icon_name(window,icon_name);
            success++;
        }
        if (!yon_char_is_empty(window_id)){
            yon_window_config_custom_window_setup(window,window_id);
            success++;
        }
        return success;
    } else {
        return 0;
    }
}

GtkWidget *yon_ubl_menu_item_about_new(char *buttonname){
    GtkWidget *menu_item = gtk_menu_item_new();
    gtk_style_context_add_class(gtk_widget_get_style_context(menu_item),"menuitembottom");
    GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,0);
    GtkWidget *label = gtk_label_new(buttonname);
    GtkWidget *image = gtk_image_new_from_icon_name("dialog-information-symbolic",GTK_ICON_SIZE_BUTTON);
    gtk_label_set_xalign(GTK_LABEL(label),0.0);
    gtk_box_pack_start(GTK_BOX(box),image,0,0,5);
    gtk_box_pack_start(GTK_BOX(box),label,0,0,5);
    gtk_container_add(GTK_CONTAINER(menu_item),box);
    gtk_widget_show_all(menu_item);
    return menu_item;
}

GtkWidget *yon_ubl_menu_item_documentation_new(char *buttonname){
    GtkWidget *menu_item = gtk_menu_item_new();
    gtk_style_context_add_class(gtk_widget_get_style_context(menu_item),"menuitemtop");
    GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,0);
    GtkWidget *label = gtk_label_new(buttonname);
    GtkWidget *image = gtk_image_new_from_icon_name("dialog-question-symbolic",GTK_ICON_SIZE_BUTTON);
    gtk_label_set_xalign(GTK_LABEL(label),0.0);
    gtk_box_pack_start(GTK_BOX(box),image,0,0,5);
    gtk_box_pack_start(GTK_BOX(box),label,0,0,5);
    gtk_container_add(GTK_CONTAINER(menu_item),box);
    gtk_widget_show_all(menu_item);
    return menu_item;
}

int yon_gtk_combo_box_fill(GtkWidget *combo, config_str parameters,int size){
    if (combo&&parameters){
        for (int i=0;i<size;i++){
            gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo),parameters[i]);
        }
        return 1;
    } else
    return 0;
}

int yon_gtk_combo_box_text_find(GtkWidget *combo_box, char *text_to_find){
    if (combo_box&&text_to_find){
        int active=gtk_combo_box_get_active(GTK_COMBO_BOX(combo_box));
        char *str="-1";
        for (int i=0;strcmp(str,"")!=0;i++){
            gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box),i);
            str=gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo_box));
            if (!str) return -1;
            if (strstr(str,text_to_find)) return i;
        }
    } return -1;
}

gboolean _yon_gtk_column_minimal_fixed_size_set(GtkTreeViewColumn *column){
    g_return_val_if_fail(GTK_IS_TREE_VIEW_COLUMN(column),0);
    const gchar *title = gtk_tree_view_column_get_title(column);
    GtkWidget *label = gtk_label_new(title);
    int header_width = 0;
    PangoLayout *layout = gtk_widget_create_pango_layout(label, title);

    if (layout != NULL) {
        pango_layout_get_pixel_size(layout, &header_width, NULL);
    }
    if (GTK_IS_WIDGET(label)) {
        g_object_ref_sink(label);
    }

    gtk_tree_view_column_set_min_width(column, header_width+10);
    g_object_unref(label);
    return G_SOURCE_REMOVE;
}

void yon_gtk_tree_view_column_minimal_fixed_size_set(GtkTreeViewColumn *column){
    _yon_gtk_column_minimal_fixed_size_set(column);
}

void _yon_gtk_tree_view_minimal_fixed_size_set_full(GtkTreeView *tree){
    GList *list = gtk_tree_view_get_columns(tree);
    for (int i=0;i<g_list_length(list);i++){
        gdk_threads_add_idle((GSourceFunc)_yon_gtk_column_minimal_fixed_size_set,(GtkTreeViewColumn*)g_list_nth_data(list,i));
    }
    g_list_free(list);
}

void yon_gtk_tree_view_minimal_fixed_size_set_full(GtkTreeView *tree){
    GThread *thread = g_thread_new("column",(GThreadFunc)_yon_gtk_tree_view_minimal_fixed_size_set_full,tree);
}

void yon_gtk_tree_view_set_(GtkTreeView *top,GtkTreeView *resizing, ...){
    va_list arglist;
    va_start(arglist,resizing);
    int column=-2, connect_to=-2;
    
    int top_columns=gtk_tree_view_get_n_columns(top);
    int resizing_columns=gtk_tree_view_get_n_columns(resizing);
    
    dictionary *dict=NULL;
    while((column=va_arg(arglist,int))!=-1){
        connect_to = va_arg(arglist,int);
        if (top_columns>column&&resizing_columns>connect_to){
            char *name="1";
            name[0]=connect_to+1;
            dictionary *cur = NULL;
            if (!(cur =yon_dictionary_get(&dict,name))){
                int *width = malloc(sizeof(int));
                (*width)=gtk_tree_view_column_get_width(gtk_tree_view_get_column(top,column));
                yon_dictionary_append_with_data(dict,name,width);
            } else {
                *(int*)cur->data+=gtk_tree_view_column_get_width(gtk_tree_view_get_column(top,column));
            }
        }
    }
    dictionary *cur;
    for_dictionaries(cur,dict){
        int cur_column = cur->key[0]-1;
        gtk_tree_view_column_set_fixed_width(gtk_tree_view_get_column(resizing,cur_column),*(int*)dict->data);
        free(dict->data);
    }
    va_end(arglist);
}

int yon_dictionary_gtk_pack_start_multiple_widgets(GtkBox *destination, gboolean expand, gboolean fill, int padding, ...){
        va_list args;
        va_start(args,padding);
        GtkWidget *widget = va_arg(args,GtkWidget*);
        while (widget){
            gtk_box_pack_start(GTK_BOX(destination), widget, expand, fill, padding);
        }
        va_end(args);
    return 1;
}

int yon_dictionary_gtk_pack_end_multiple_widgets(GtkBox *destination, gboolean expand, gboolean fill, int padding, ...){
        va_list args;
        va_start(args,padding);
        GtkWidget *widget = va_arg(args,GtkWidget*);
        while (widget){
            gtk_box_pack_end(GTK_BOX(destination), widget, expand, fill, padding);
        }
        va_end(args);
    return 1;
}

int yon_gtk_list_store_find_text(GtkListStore *list, GtkTreeIter *iter, int seek_column, char *value){
    int valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list),iter);
    for (;valid;valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list),iter)){
        char *seek_value;
        gtk_tree_model_get(GTK_TREE_MODEL(list),iter,seek_column,&seek_value,-1);
        if (!strcmp(value,seek_value)){
            free(seek_value);
            return 1;
        }
        free(seek_value);
    }
    return 0;
}
void yon_on_cell_renderer_toggle_toggled_for_list_store(GtkWidget *self, gchar *path,GtkWidget *tree){
        GtkTreePath *path_converted = gtk_tree_path_new_from_string(path);
        GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree));
        GtkTreeIter iter;
        gtk_tree_model_get_iter(model,&iter,path_converted);
        int last = yon_char_find_last(path,':');
        char *col = path+last+1;
        int status;
        gtk_tree_model_get(model,&iter,atoi(col),&status,-1);
        gtk_list_store_set(GTK_LIST_STORE(model),&iter,atoi(col),!status,-1);
}

void yon_cell_renderer_toggle_set_toggle(GtkCellRendererToggle *target,GtkWidget *tree){
    g_return_if_fail(GTK_IS_CELL_RENDERER_TOGGLE(target));
    g_signal_connect(G_OBJECT(target),"toggled",G_CALLBACK(yon_on_cell_renderer_toggle_toggled_for_list_store),tree);
}

void yon_gtk_toggle_button_set_inactive_from_toggle(GtkToggleButton *self, GtkToggleButton *target){
    if (gtk_toggle_button_get_active(self)){
        gtk_toggle_button_set_active(target,1);
    } else {
        gtk_toggle_button_set_active(target,0);
    }
}

void yon_gtk_toggle_button_set_inactive_from_entry(GtkEntry *self, GtkToggleButton *target){
    if (strlen(gtk_entry_get_text(self))>0){
        gtk_toggle_button_set_active(target,1);
    } else {
        gtk_toggle_button_set_active(target,0);
    }
}

void yon_gtk_toggle_button_set_inactive_from_combo_box(GtkComboBox *self, GtkToggleButton *target){
    if (gtk_combo_box_get_active(self)>0){
        gtk_toggle_button_set_active(target,1);
    } else {
        gtk_toggle_button_set_active(target,0);
    }
}

void yon_gtk_widget_set_sensitive_from_toggle_button(GtkToggleButton *toggle, GtkWidget *target){
    gtk_widget_set_sensitive(target,gtk_toggle_button_get_active(toggle));
}

void yon_gtk_widget_set_sensitive_from_toggle_button_inversed(GtkToggleButton *toggle, GtkWidget *target){
    gtk_widget_set_sensitive(target,!gtk_toggle_button_get_active(toggle));

}

void yon_gtk_widget_set_sensitive_from_switch(GtkSwitch *toggle, int status, GtkWidget *target){
    gtk_widget_set_sensitive(target,gtk_switch_get_active(toggle));
}

void yon_gtk_widget_set_sensitive_from_switch_inversed(GtkSwitch *toggle, int status, GtkWidget *target){
    gtk_widget_set_sensitive(target,!gtk_switch_get_active(toggle));

}

void yon_gtk_widget_set_sensitive_from_combo_box(GtkComboBox *toggle, GtkWidget *target){
    gtk_widget_set_sensitive(target,gtk_combo_box_get_active(toggle)>0 ? 1 : 0);
}

void yon_gtk_widget_set_sensitive_from_combo_box_inversed(GtkComboBox *toggle, GtkWidget *target){
    gtk_widget_set_sensitive(target,!gtk_combo_box_get_active(toggle)>0 ? 0 : 1);
}

void yon_gtk_toggle_button_set_inactive_from_toggle_button_inversed(GtkToggleButton *self, GtkToggleButton *target){
    if (gtk_toggle_button_get_active(self)){
        gtk_toggle_button_set_active(target,0);
    }
}

void yon_gtk_toggle_button_set_inactive_from_toggle_button(GtkToggleButton *self, GtkToggleButton *target){
    if (!gtk_toggle_button_get_active(self)){
        gtk_toggle_button_set_active(target,0);
    }
}

void yon_on_text_insert_only_digits(GtkEditable *editable, const gchar *text, gint length, gint *position, gpointer user_data){
    gchar *new_text = g_new(gchar, length + 1);
    gint i, j = 0;

    for (i = 0; i < length; i++) {
        if (g_ascii_isdigit(text[i])) {
            new_text[j] = text[i];
            j++;
        }
    }

    if (j < length) {
        g_signal_handlers_block_by_func(editable, G_CALLBACK(yon_on_text_insert_only_digits), user_data);
        gtk_editable_insert_text(editable, new_text, j, position);
        g_signal_handlers_unblock_by_func(editable, G_CALLBACK(yon_on_text_insert_only_digits), user_data);
        g_signal_stop_emission_by_name(editable, "insert-text");
    }

    g_free(new_text);
}

void yon_on_insert_restricted_check(GtkEditable *editable, const gchar *text, gint length, gint *position, gpointer){
        gchar *new_text = g_new(gchar, length + 1);
        memset(new_text,0,length+1);
    gint i, j = 0;

    for (i = 0; i < length; i++) {
        if ((text[i]>='0'&&text[i]<='9')||(text[i]>='a'&&text[i]<='z')||(text[i]>='A'&&text[i]<='Z')) {
            new_text[j] = text[i];
            j++;
        }
    }

    if (j < length) {
        g_signal_handlers_block_by_func(editable, G_CALLBACK(yon_on_insert_restricted_check), NULL);
        gtk_editable_insert_text(editable, new_text, j, position);
        g_signal_handlers_unblock_by_func(editable, G_CALLBACK(yon_on_insert_restricted_check), NULL);
        g_signal_stop_emission_by_name(editable, "insert-text");
    }

    g_free(new_text);
}

void yon_gtk_entry_block_restricted_symbols(GtkEntry *target){
    g_return_if_fail(GTK_IS_ENTRY(target));
    g_signal_connect(G_OBJECT(target),"insert-text",G_CALLBACK(yon_on_insert_restricted_check),NULL);
}

void yon_on_insert_languages(GtkEditable *editable, const gchar *text, gint length, gint *position, gpointer){
        gchar *new_text = g_new(gchar, length + 1);
        memset(new_text,0,length+1);
    gint i, j = 0;

    for (i = 0; i < length; i++) {
        if (text[i]>=0) {
            new_text[j] = text[i];
            j++;
        }
    }

    if (j < length) {
        g_signal_handlers_block_by_func(editable, G_CALLBACK(yon_on_insert_restricted_check), NULL);
        gtk_editable_insert_text(editable, new_text, j, position);
        g_signal_handlers_unblock_by_func(editable, G_CALLBACK(yon_on_insert_restricted_check), NULL);
        g_signal_stop_emission_by_name(editable, "insert-text");
    }

    g_free(new_text);
}

void yon_gtk_entry_block_languages(GtkEntry *target){
    g_return_if_fail(GTK_IS_ENTRY(target));
    g_signal_connect(G_OBJECT(target),"insert-text",G_CALLBACK(yon_on_insert_languages),NULL);
}

void yon_on_insert_custom_restricted_check(GtkEditable *editable, const gchar *text, gint length, gint *position, char *symbols){
        gchar *new_text = g_new(gchar, length + 1);
        memset(new_text,0,length+1);
    gint i, j = 0;

    for (i = 0; i < length; i++) {
        if (!strchr(symbols,text[i])) {
            new_text[j] = text[i];
            j++;
        }
    }

    if (j < length) {
        g_signal_handlers_block_by_func(editable, G_CALLBACK(yon_on_insert_restricted_check), NULL);
        gtk_editable_insert_text(editable, new_text, j, position);
        g_signal_handlers_unblock_by_func(editable, G_CALLBACK(yon_on_insert_restricted_check), NULL);
        g_signal_stop_emission_by_name(editable, "insert-text");
    }

    g_free(new_text);
}

void yon_gtk_entry_block_symbols(GtkEntry *target, char *symbols){
    g_return_if_fail(GTK_IS_ENTRY(target));
    g_signal_connect(G_OBJECT(target),"insert-text",G_CALLBACK(yon_on_insert_custom_restricted_check),yon_char_new(symbols));
}

void yon_on_insert_lowercase_check(GtkEditable *editable, const gchar *text, gint length, gint *position, char *symbols){
    gchar *new_text = g_new(gchar, length + 1);
        memset(new_text,0,length+1);
    gint i;

    for (i = 0; i < length; i++) {
        if (text[i]>=97&&text[i]<=122) {
            new_text[i]=text[i]-32;
        } else {
            new_text[i] = text[i];
        }
    }

        g_signal_handlers_block_by_func(editable, G_CALLBACK(yon_on_insert_lowercase_check), NULL);
        gtk_editable_insert_text(editable, new_text, strlen(text), position);
        g_signal_handlers_unblock_by_func(editable, G_CALLBACK(yon_on_insert_lowercase_check), NULL);
        g_signal_stop_emission_by_name(editable, "insert-text");
}

void yon_gtk_entry_block_lowercase(GtkEntry *target){
    g_return_if_fail(GTK_IS_ENTRY(target));
    g_signal_connect(G_OBJECT(target),"insert-text",G_CALLBACK(yon_on_insert_lowercase_check),NULL);
}

gboolean _yon_on_gtk_revealer_set_from_switch(GtkSwitch *target, int status, GtkRevealer *revealer){
    gtk_revealer_set_reveal_child(revealer,status);
    gtk_revealer_set_transition_type(revealer,status?GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN:GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
    return 0;
}

gboolean _yon_on_gtk_revealer_set_from_switch_inversed(GtkSwitch *target, int status, GtkRevealer *revealer){
    gtk_revealer_set_reveal_child(revealer,!status);
    gtk_revealer_set_transition_type(revealer,!status?GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN:GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
    return 0;
}

gboolean _yon_on_gtk_revealer_set_from_expander(GtkExpander *target,GtkRevealer *revealer){
    int status = gtk_expander_get_expanded(target);
    gtk_revealer_set_reveal_child(revealer,!status);
    gtk_revealer_set_transition_type(revealer,!status?GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN:GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
    return 0;
}

void yon_gtk_revealer_set_from_switch(GtkRevealer *revealer, GtkSwitch *target){
    g_return_if_fail(GTK_IS_REVEALER(revealer)&&GTK_IS_SWITCH(target));
    g_signal_connect(G_OBJECT(target),"state-set",G_CALLBACK(_yon_on_gtk_revealer_set_from_switch),revealer);
}

void yon_gtk_revealer_set_from_switch_inversed(GtkRevealer *revealer, GtkSwitch *target){
    g_return_if_fail(GTK_IS_REVEALER(revealer)&&GTK_IS_SWITCH(target));
    g_signal_connect(G_OBJECT(target),"state-set",G_CALLBACK(_yon_on_gtk_revealer_set_from_switch_inversed),revealer);
}

void yon_gtk_revealer_set_from_expander(GtkRevealer *revealer, GtkExpander *target){
    g_return_if_fail(GTK_IS_REVEALER(revealer)&&GTK_IS_EXPANDER(target));
    g_signal_connect(G_OBJECT(target),"activate",G_CALLBACK(_yon_on_gtk_revealer_set_from_expander),revealer);
}

struct revealer_wrapper {
    GtkWidget *revealer;
    GtkWidget *window;
    int height;
};

gboolean _yon_on_revealer_hidden(struct revealer_wrapper *wrapped){
    int width;
    gtk_window_get_size(GTK_WINDOW(wrapped->window),&width,NULL);
    gtk_window_resize(GTK_WINDOW(wrapped->window),width,wrapped->height);
}

gboolean _yon_on_revealer_switched(struct revealer_wrapper *wrapped){
    if (!gtk_revealer_get_child_revealed(GTK_REVEALER(wrapped->revealer))){
        g_timeout_add(gtk_revealer_get_transition_duration(GTK_REVEALER(wrapped->revealer))+1,(GSourceFunc)_yon_on_revealer_hidden,wrapped);
    }
}

void yon_gtk_window_set_shrinking_from_revealer_resizing(GtkWindow *window, GtkRevealer *revealer){
    int height=0;
    gtk_window_get_size(window, NULL, &height);
    struct revealer_wrapper *wrapped = malloc(sizeof(struct revealer_wrapper));
    wrapped->revealer=GTK_WIDGET(revealer);
    wrapped->height=height;
    wrapped->window=gtk_widget_get_toplevel(GTK_WIDGET(revealer));
    g_signal_connect(G_OBJECT(wrapped->revealer),"notify::reveal-child",G_CALLBACK(_yon_on_revealer_switched),wrapped);
}

void on_entry_pattern_inserted(GtkEditable *self, const gchar *text, gint length, gint *position, void*){
    char *pattern = g_object_get_data(G_OBJECT(self),"__yon_pattern_string");
    GRegex *regex = g_object_get_data(G_OBJECT(self),"__yon_pattern_regex");
    const char *old_text = gtk_entry_get_text(GTK_ENTRY(self));
    char *test_text = yon_char_append(old_text,text);
    GError *error = NULL;
    GMatchInfo *match_info = NULL;
    if (!g_regex_match(regex,test_text,G_REGEX_MATCH_PARTIAL_HARD,&match_info)){
        if (g_match_info_is_partial_match(match_info)){
            return;
        }
        g_signal_stop_emission_by_name(G_OBJECT(self),"insert-text");
        return;
    }
    if (!g_regex_match_simple(pattern,test_text,0,0)){
        g_signal_stop_emission_by_name(G_OBJECT(self),"insert-text");
        return;
    }
    
}

void yon_entry_set_pattern(GtkEntry *target, char *pattern){
    if (yon_char_is_empty(pattern)){
        g_signal_handlers_disconnect_by_func(G_OBJECT(target),G_CALLBACK(on_entry_pattern_inserted),NULL);
        char *pattern = g_object_get_data(G_OBJECT(target),"__yon_pattern_string");
        GRegex *regex = g_object_get_data(G_OBJECT(target),"__yon_pattern_regex");
        if (!yon_char_is_empty(pattern)) free(pattern);
        g_regex_unref(regex);
        g_object_set_data(G_OBJECT(target),"__yon_pattern_string",NULL);
        g_object_set_data(G_OBJECT(target),"__yon_pattern_regex",NULL);
        return;
    }
    GError *err = NULL;
    char *pattern_copy = yon_char_unite(pattern[0]!='^'?"^":"", pattern,pattern[strlen(pattern)-1]!='$'?"$":"",NULL);
    GRegex *regex = g_regex_new(pattern,0,G_REGEX_MATCH_PARTIAL_HARD,&err);
    if (err){
        printf("%s\n",err->message);
    }
    g_object_set_data(G_OBJECT(target),"__yon_pattern_string",pattern_copy);
    g_object_set_data(G_OBJECT(target),"__yon_pattern_regex",regex);
    g_signal_connect(G_OBJECT(target),"insert-text",G_CALLBACK(on_entry_pattern_inserted),NULL);
}

char *yon_gtk_entry_get_by_pattern(GtkEntry *target, const char *pattern){
    g_return_val_if_fail(GTK_IS_ENTRY(target),NULL);
    g_return_val_if_fail(!yon_char_is_empty(pattern),NULL);
    const char *target_string = gtk_entry_get_text(target);
    GError *err = NULL;
    GRegex *regex = g_regex_new(pattern,0,0,&err);
    if (err){
        printf("%s\n",err->message);
        return NULL;
    }
    GMatchInfo *match = NULL;
    g_regex_match(regex,target_string,0,&match);
    if (match){
        char *text = g_match_info_fetch(match,0);
        return yon_char_new(text);
    }

}

void yon_on_insert_allowed_check(GtkEditable *editable, char *text, int length, int *position,char *symbols){

        gchar *new_text = g_new(gchar, length + 1);
        memset(new_text,0,length+1);
    gint i, j = 0;

    for (i = 0; i < length; i++) {
        if (strchr(symbols,text[i])) {
            new_text[j] = text[i];
            j++;
        }
    }

    if (j < length) {
        g_signal_handlers_block_by_func(editable, G_CALLBACK(yon_on_insert_restricted_check), NULL);
        gtk_editable_insert_text(editable, new_text, j, position);
        g_signal_handlers_unblock_by_func(editable, G_CALLBACK(yon_on_insert_restricted_check), NULL);
        g_signal_stop_emission_by_name(editable, "insert-text");
    }

    g_free(new_text);
}

void yon_on_entry_set_allowed_symbols(GtkEntry *target, char *symbols){
    g_return_if_fail(GTK_IS_ENTRY(target));
    g_signal_connect(G_OBJECT(target),"insert-text",G_CALLBACK(yon_on_insert_allowed_check),symbols);
}

void yon_gtk_entry_allow_password_symbols(GtkEntry *target){
    g_return_if_fail(GTK_IS_ENTRY(target));
    g_signal_connect(G_OBJECT(target),"insert-text",G_CALLBACK(yon_on_insert_allowed_check),yon_char_new("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&\'()*+,-./;<=>?@[\\]^_`{|}~"));
}

int yon_ip_check(char *ip){
    if (!strstr(ip,".")){
        int pixmask = atoi(ip);
        if (pixmask > 32) return 0;
    } else {
        if (!g_regex_match_simple("^(\\d){0,3}\\.(\\d){0,3}\\.(\\d){0,3}\\.(\\d){0,3}$",ip,0,0)) return 0;
        int size;
        config_str parsed = yon_char_parse(ip,&size,".");
        for (int i=0;i<size;i++){
            int bits = atoi(parsed[i]);
            if (bits>255){
                yon_char_parsed_free(parsed,size);
                return 0;
            }
        }
        yon_char_parsed_free(parsed,size);
    }
    return 1;
}

int yon_ip_mask_get_bits(char *mask){
    if (!strstr(mask,".")){
        int bits = atoi(mask);
        return bits;
    }
    int size;
    config_str parsed = yon_char_parse(mask,&size,".");
    int bits = 32;
    for (int i=0;i<size;i++){
        int pixmask = atoi(parsed[i]);
        int k;
        for (k=0;k<8;k++){
            if (!(pixmask & (1<<k))){
                bits--;
            }
        }
    }
    yon_char_parsed_free(parsed,size);
    return bits;
}

gboolean _yon_gtk_combo_box_block_scroll(GtkWidget *self, GdkEvent *event, void*){
    gtk_propagate_event(gtk_widget_get_parent(self), (GdkEvent*)event);
    return 1;
}

void yon_gtk_combo_box_block_scroll(GtkComboBox *target){
    g_signal_connect(G_OBJECT(target),"scroll-event",G_CALLBACK(_yon_gtk_combo_box_block_scroll),NULL);
}

gboolean __yon_destroy_block(GtkWidget *self){
    gtk_widget_hide(self);
    return 1;
}

void yon_gtk_widget_block_destruction(GtkWidget *target){
    g_signal_connect(G_OBJECT(target),"delete-event",G_CALLBACK(__yon_destroy_block),NULL);
}