From b73fa285571d0ca1ec65dff1ac247475a51eb30c Mon Sep 17 00:00:00 2001 From: Ivan Yarcev Date: Mon, 14 Jul 2025 12:15:45 +0600 Subject: [PATCH 1/6] Added exit window when config has unsaved parameters --- libublsettingsui-gtk3.pot | 8 ++++ libublsettingsui-gtk3_ru.po | 8 ++++ source/libublsettingsui-gtk3-save.c | 25 ++++++++++ source/libublsettingsui-gtk3.c | 10 ++++ source/libublsettingsui-gtk3.h | 72 +++++++++++++++++++++++++++-- 5 files changed, 120 insertions(+), 3 deletions(-) diff --git a/libublsettingsui-gtk3.pot b/libublsettingsui-gtk3.pot index ba54224..5aabfd7 100644 --- a/libublsettingsui-gtk3.pot +++ b/libublsettingsui-gtk3.pot @@ -376,3 +376,11 @@ msgstr "" #: source/libublsettingsui-gtk3.h:492 msgid "service is inactive" msgstr "" + +#: source/libublsettingsui-gtk3.h:492 +msgid "The changes were not saved to either the local or global configuration file. Quit without saving?" +msgstr "" + +#: source/libublsettingsui-gtk3.h:492 +msgid "Exit" +msgstr "" diff --git a/libublsettingsui-gtk3_ru.po b/libublsettingsui-gtk3_ru.po index c46e0e5..865fc18 100644 --- a/libublsettingsui-gtk3_ru.po +++ b/libublsettingsui-gtk3_ru.po @@ -383,3 +383,11 @@ msgstr "служба активна" #: source/libublsettingsui-gtk3.h:492 msgid "service is inactive" msgstr "служба неактивна" + +#: source/libublsettingsui-gtk3.h:492 +msgid "The changes were not saved to either the local or global configuration file. Quit without saving?" +msgstr "Изменения не сохранены ни в локальный, ни в глобальный конфигурационный файл. Выйти без сохранения?" + +#: source/libublsettingsui-gtk3.h:492 +msgid "Exit" +msgstr "Выход" \ No newline at end of file diff --git a/source/libublsettingsui-gtk3-save.c b/source/libublsettingsui-gtk3-save.c index 79c60ba..95fde7c 100644 --- a/source/libublsettingsui-gtk3-save.c +++ b/source/libublsettingsui-gtk3-save.c @@ -600,3 +600,28 @@ template_saving_window *yon_save_proceed(char *path,YON_CONFIG_TYPE type, ...){ on_save_window_parameter_switched(NULL,NULL,window); return window; } + +//------------------------- + +template_saving_window *yon_exit_window_new(){ + template_saving_window *window = yon_saving_window_new(); + yon_ubl_status_box_spawn_infinite(GTK_CONTAINER(window->StatusBox),"remove_status",UNSAVED_LABEL,BACKGROUND_IMAGE_FAIL_TYPE); + gtk_button_set_label(GTK_BUTTON(window->SaveButton),EXIT_LABEL); + g_signal_handlers_disconnect_by_func(G_OBJECT(window->SaveButton), G_CALLBACK(on_save_parameters),window); + g_signal_handlers_disconnect_by_func(G_OBJECT(window->ToggleCell), G_CALLBACK(on_save_window_parameter_switched),window); + g_signal_connect(G_OBJECT(window->SaveButton),"clicked",G_CALLBACK(gtk_main_quit),NULL); + + int current_size=0; + struct loaded_config *config_compare=NULL; + config_str current_config = yon_config_get_all_modified(¤t_size); // get INTERNAL config + + struct loaded_config *current_loaded = yon_config_convert_parameter(current_config,current_size); // convert INTERNAL config into struct + gtk_tree_view_remove_column(GTK_TREE_VIEW(window->ParametersTree),gtk_tree_view_get_column(GTK_TREE_VIEW(window->ParametersTree),0)); + + yon_save_window_loaded_config_init(window,current_loaded,config_compare); + yon_save_window_compared_config_init_unfound(window,current_loaded,config_compare); + if (!yon_save_window_destroy_if_empty(window)) + return NULL; + + return window; +} \ No newline at end of file diff --git a/source/libublsettingsui-gtk3.c b/source/libublsettingsui-gtk3.c index a8147fe..a74de54 100644 --- a/source/libublsettingsui-gtk3.c +++ b/source/libublsettingsui-gtk3.c @@ -233,6 +233,15 @@ int yon_ubl_connect_config(_template_config *config){ return replaces; } +gboolean on_window_delete (GtkWidget *, GdkEvent *,template_main_window *widgets){ + template_saving_window *window = yon_exit_window_new(); + if (window){ + gtk_widget_show(window->Window); + return 1; + } + return 0; +} + template_main_window *setup_window(){ /* Widgets getting | Получение виджетов */ template_main_window *widgets = malloc(sizeof(template_main_window)); @@ -305,6 +314,7 @@ template_main_window *setup_window(){ g_signal_connect(G_OBJECT(widgets->Window), "destroy", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(G_OBJECT(widgets->DocumentationMenuItem),"activate",G_CALLBACK(on_open_documentation_confirmation),template_app_information.wiki_link); g_signal_connect(G_OBJECT(widgets->AboutMenuItem),"activate",G_CALLBACK(on_about),template_app_information.app_version); + g_signal_connect(G_OBJECT(widgets->Window),"delete-event",G_CALLBACK(on_window_delete),widgets); if (yon_char_is_empty(__yon_config_mode)){ int size; diff --git a/source/libublsettingsui-gtk3.h b/source/libublsettingsui-gtk3.h index f422d7b..e65e53e 100644 --- a/source/libublsettingsui-gtk3.h +++ b/source/libublsettingsui-gtk3.h @@ -18,28 +18,57 @@ #define _(String) gettext(String) +/**Префикс для всех икнок из библиотеки.*/ #define yon_dull_icon_path "com.ublinux.libublsettingsui-gtk3" + +/**Путь до файла основного окна утилит ubl-settings-**/ #define ui_glade_path "/com/ublinux/ui/libublsettingsui-gtk3.glade" + +/**Путь до файла подтверждения открытия документации утилит ubl-settings-**/ #define ui_glade_path_documentation "/com/ublinux/ui/libublsettingsui-gtk3-documentation.glade" + +/**Путь до файла окна "О программе" утилит ubl-settings-**/ #define ui_glade_path_about "/com/ublinux/ui/libublsettingsui-gtk3-about.glade" + +/**Путь до файла окна сохранения утилит ubl-settings-**/ #define ui_glade_path_saving "/com/ublinux/ui/libublsettingsui-gtk3-saving.glade" + +/**Путь до файла окна выбора файлов утилит ubl-settings-**/ #define ui_glade_path_filechooser "/com/ublinux/ui/libublsettingsui-gtk3-filechooser.glade" + +/**Путь до файла окна отладки утилит ubl-settings-**/ #define ui_glade_path_debug "/com/ublinux/ui/libublsettingsui-gtk3-debugger.glade" + +/**Путь до файла окна управления юнитами утилит ubl-settings-**/ #define ui_glade_path_service "/com/ublinux/ui/libublsettingsui-gtk3-service-control.glade" + +/**Путь до файла окна выбора приложений утилит ubl-settings-**/ #define ui_glade_path_app_chooser "/com/ublinux/ui/libublsettingsui-gtk3-app-chooser.glade" + +/**Путь до основного баннера утилит ubl-settings-**/ #define ui_banner_path "/com/ublinux/images/libublsettingsui-gtk3-banner.png" + +/**Путь до файла стилей для утилит*/ #define ui_CssPath "/com/ublinux/css/libublsettingsui-gtk3.css" + +/**Путь до файла конфигурации утилит*/ #define ui_config_path yon_char_unite(yon_ubl_user_get_home_directory(),"/.config/",template_app_information.app_tech_name,"/",template_app_information.app_tech_name,".conf",NULL) +/**Команда удаления файла конфигурации утилит*/ #define remove_config_dir_command yon_char_unite("rm -rfd ", yon_ubl_user_get_home_directory(),"/.config/",template_app_information.app_tech_name,"/",NULL) - +/**Шаблон команды сохраненния/удаления/получения параметров из конфигурации*/ #define dull_parameter_get_command "ubconfig --source global get users PARAMETER" +/**Команда получения режима загрузки*/ #define SAVE_MODE_GET_COMMAND "ubconfig --raw --source system get [config] SYSTEMBOOT_STATEMODE" +/**Команда создания файла конфигурации ubconfig + * @target - путь до создаваемого файла +*/ #define ubconfig_file_create(target) yon_char_unite("ubconfig --target \"",target,"\" create",NULL) +/**Типы */ typedef enum SAVE_MODE_TYPE { SAVE_MODE_FULL, SAVE_MODE_MODULE, @@ -49,12 +78,27 @@ typedef enum SAVE_MODE_TYPE { SAVE_MODE_HDD_HOME, } SAVE_MODE_TYPE; +/**Получить локализованную строку из библиотеки +*/ char *yon_char_get_localised_from_lib(char *string); +/**Получить название иконки для режима сохранения +*/ char *yon_ubl_save_mode_get_icon_name(SAVE_MODE_TYPE type); +/**Конввертировать вывод команды SAVE_MODE_GET_COMMAND в SAVE_MODE_TYPE*/ SAVE_MODE_TYPE yon_ubl_save_mode_get_type(char *type); +/**Структура с информацией об утилите, использующей библиотеку. + * @interface - виджет, корень интерфейса запущенной утилиты. Добавляется в окно из библиотеки + * @app_locale - имя файла локализации откуда будет загружаться локализация утилиты + * @css_path - путь до файла css стилей утилиты + * @app_title - Название утилиты для отображения на баннере и на окнах из библиотеки + * @app_description - описание утилиты для отображения на баннере. + * @app_texh_name - техническое название утилиты (ubl-settings-*) + * @app_version - текстовая строка с версией утилиты + * @wiki_link - ссылка на страницу wiki утилиты +*/ typedef struct { GtkWidget *interface; @@ -73,7 +117,8 @@ typedef struct { extern template_app_info template_app_information; - +/**Стандартные поля для конфигурации утилиты. + * template_config_fields ДОЛЖЕН РАСПОЛАГАТЬСЯ ПЕРВЫМ В СТРУКТУРЕ КОНФИГУРАЦИИ*/ #define template_config_fields\ int socket_id;\ int load_socket_id;\ @@ -95,11 +140,13 @@ typedef struct { template_config_fields } _template_config; +/**Указатель на конфиг. В него попадает указатель на основной конфиг утилиты с полями @template_fields*/ extern _template_config *template_config; [[maybe_unused]] extern _template_config *template_config; +/**Поля структуры основного окна утилиты, настраивыемые через бибилотеку. template_window_fields ДОЛЖЕН РАСПОЛАГАТЬСЯ ПЕРВЫМ В СТРУКТУРЕ*/ #define template_window_fields\ GtkWidget *Window;\ GtkWidget *HeadLabel;\ @@ -132,11 +179,12 @@ extern _template_config *template_config; GtkWidget *InterfaceBox;\ //} +/**Структура с основным окном утилиты*/ typedef struct { template_window_fields } template_main_window; - +/**Структура с окном подтверждения перехода к документации*/ typedef struct { GtkWidget *Window; GtkWidget *HeaderLabel; @@ -147,6 +195,7 @@ typedef struct { GtkWidget *AcceptButton; } template_documentation_confirmation_window; +/**Структура с окном режима отладки*/ typedef struct { GtkWidget *Window; GtkWidget *HeaderTopic; @@ -155,6 +204,12 @@ typedef struct { GtkWidget *Vte; } template_debug_window; +/**Структура для диалогового окна подтверждения. + * @void (*function)(void*,void*) - указатель на функцию выполняюзуюся в случае нажатия на кнопку "Принять". Первый параметр - Указатель на окно или виджета, расположенного в этом окне + * @data - параметр, передающийся в функцию + * @action_text - отображаемый в диалоговом окне текст действия, требующего подтверждения + * @title - текст в шапке диалогового окна +*/ typedef struct { void (*function)(void*,void*); void *data; @@ -162,6 +217,14 @@ typedef struct { char *title; } dialog_confirmation_data; +/**Структура для окна выбора файлов. + * @Window - виджет окна + * @StatusBox - виджет для показа статусных сообщений, пустой GtkBox с вертикальной ориентацией + * @HeaderTopic - виджет текста в шапке окна + * @MainFileChooser - виджет выбора файлов. + * @SaveButton - Кнопка принятия выбора. Закрывает окно и устанавливает responce равным GTK_RESPONCE_ACCEPT если был выбран файл + * @CancelButton - кнопка отмены. Закрывает окно и +*/ typedef struct { GtkWidget *Window; GtkWidget *StatusBox; @@ -312,6 +375,7 @@ void yon_ubl_settings_window_init(GtkMenu *menu); void *yon_ubl_settings_window_get(char *id); void yon_configuration_window_add_boolean_parameter(enum CONFIGURATION_PARAMETER_TYPE type, char *id, char *label); void yon_configuration_window_add_combo_box_parameter(enum CONFIGURATION_PARAMETER_TYPE type, char *id, char *label, GCallback func, gpointer data, ...); +template_saving_window *yon_exit_window_new(); char *yon_gtk_entry_check_restricted(GtkEntry *target); @@ -511,4 +575,6 @@ yon_app_chooser_window *yon_app_chooser_window_new(int multiple_choise); #define _SERVICE_ACTIVE_STATUS_LABEL(target) yon_char_unite("\"",target,"\" ", yon_char_get_localised_from_lib(_("service is active")),NULL) #define _SERVICE_INACTIVE_STATUS_LABEL(target) yon_char_unite("\"",target,"\" ",yon_char_get_localised_from_lib(_("service is inactive")),NULL) + #define UNSAVED_LABEL yon_char_get_localised_from_lib("The changes were not saved to either the local or global configuration file. Quit without saving?") + #define EXIT_LABEL yon_char_get_localised_from_lib("Exit") #endif \ No newline at end of file From e5a5b48cf461c4bf0c2de8c7cdf4775886e55a8f Mon Sep 17 00:00:00 2001 From: Ivan Yarcev Date: Mon, 14 Jul 2025 12:31:06 +0600 Subject: [PATCH 2/6] Fixed exit window show logic --- source/libublsettingsui-gtk3-save.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/source/libublsettingsui-gtk3-save.c b/source/libublsettingsui-gtk3-save.c index 95fde7c..ad6c2c3 100644 --- a/source/libublsettingsui-gtk3-save.c +++ b/source/libublsettingsui-gtk3-save.c @@ -6,6 +6,7 @@ saving section ============== */ +void yon_exit_window_loaded_config_init(template_saving_window *window, struct loaded_config *current_loaded); gboolean _yon_presave_function_start(struct presave_info *data){ presave_function(data->presave_argument,data->save_path); @@ -278,6 +279,18 @@ char *yon_get_compare_config_command(va_list args,char *path,YON_CONFIG_TYPE typ return yon_char_is_empty(compare_command)?NULL:compare_command; } +void yon_exit_window_loaded_config_init(template_saving_window *window, struct loaded_config *current_loaded){ + GtkTreeIter iter; + struct loaded_config *current = NULL; + for_dictionaries(current,current_loaded){ + + char *compare_string = yon_char_unite("\n",(char*)current->data,NULL); + gtk_list_store_append(window->list,&iter); + gtk_list_store_set(window->list,&iter,1,current->key,3,(char*)current->data,4,compare_string,6,1,-1); + + } +} + void yon_save_window_loaded_config_init(template_saving_window *window, struct loaded_config *current_loaded, struct loaded_config *config_compare){ if (current_loaded){ struct loaded_config *current = NULL; @@ -616,12 +629,12 @@ template_saving_window *yon_exit_window_new(){ config_str current_config = yon_config_get_all_modified(¤t_size); // get INTERNAL config struct loaded_config *current_loaded = yon_config_convert_parameter(current_config,current_size); // convert INTERNAL config into struct - gtk_tree_view_remove_column(GTK_TREE_VIEW(window->ParametersTree),gtk_tree_view_get_column(GTK_TREE_VIEW(window->ParametersTree),0)); - yon_save_window_loaded_config_init(window,current_loaded,config_compare); - yon_save_window_compared_config_init_unfound(window,current_loaded,config_compare); + yon_exit_window_loaded_config_init(window,current_loaded); + if (!yon_save_window_destroy_if_empty(window)) return NULL; + gtk_tree_view_remove_column(GTK_TREE_VIEW(window->ParametersTree),gtk_tree_view_get_column(GTK_TREE_VIEW(window->ParametersTree),0)); return window; } \ No newline at end of file From 0ee801dc3cee74c51c46482cb3aecff8c0facc6a Mon Sep 17 00:00:00 2001 From: Ivan Yarcev Date: Mon, 14 Jul 2025 14:35:42 +0600 Subject: [PATCH 3/6] Fixed exit window compared values --- libublsettingsui-gtk3-saving.glade | 3 +-- source/libublsettingsui-gtk3-save.c | 9 ++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libublsettingsui-gtk3-saving.glade b/libublsettingsui-gtk3-saving.glade index 24def50..320beba 100644 --- a/libublsettingsui-gtk3-saving.glade +++ b/libublsettingsui-gtk3-saving.glade @@ -1,5 +1,5 @@ - + @@ -63,7 +63,6 @@ True False - 5 vertical diff --git a/source/libublsettingsui-gtk3-save.c b/source/libublsettingsui-gtk3-save.c index ad6c2c3..070dbeb 100644 --- a/source/libublsettingsui-gtk3-save.c +++ b/source/libublsettingsui-gtk3-save.c @@ -624,13 +624,16 @@ template_saving_window *yon_exit_window_new(){ g_signal_handlers_disconnect_by_func(G_OBJECT(window->ToggleCell), G_CALLBACK(on_save_window_parameter_switched),window); g_signal_connect(G_OBJECT(window->SaveButton),"clicked",G_CALLBACK(gtk_main_quit),NULL); - int current_size=0; struct loaded_config *config_compare=NULL; - config_str current_config = yon_config_get_all_modified(¤t_size); // get INTERNAL config + config_compare = yon_config_get_compared(yon_config_get_last_command()); // get compare config + + int current_size=0; + config_str current_config = yon_config_get_all(¤t_size); // get INTERNAL config struct loaded_config *current_loaded = yon_config_convert_parameter(current_config,current_size); // convert INTERNAL config into struct - yon_exit_window_loaded_config_init(window,current_loaded); + yon_save_window_loaded_config_init(window,current_loaded,config_compare); + yon_save_window_compared_config_init_unfound(window,current_loaded,config_compare); if (!yon_save_window_destroy_if_empty(window)) return NULL; From c79a0f6ded7a2ed5b928809590974e0d313cc6f4 Mon Sep 17 00:00:00 2001 From: Ivan Yarcev Date: Mon, 14 Jul 2025 14:52:57 +0600 Subject: [PATCH 4/6] Localisation fixes --- libublsettingsui-gtk3.pot | 2 +- libublsettingsui-gtk3_ru.po | 4 ++-- source/libublsettingsui-gtk3.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libublsettingsui-gtk3.pot b/libublsettingsui-gtk3.pot index 5aabfd7..d0bb2b3 100644 --- a/libublsettingsui-gtk3.pot +++ b/libublsettingsui-gtk3.pot @@ -378,7 +378,7 @@ msgid "service is inactive" msgstr "" #: source/libublsettingsui-gtk3.h:492 -msgid "The changes were not saved to either the local or global configuration file. Quit without saving?" +msgid "The changes were not saved to either the local or global configuration file.\nQuit without saving?" msgstr "" #: source/libublsettingsui-gtk3.h:492 diff --git a/libublsettingsui-gtk3_ru.po b/libublsettingsui-gtk3_ru.po index 865fc18..934b5e6 100644 --- a/libublsettingsui-gtk3_ru.po +++ b/libublsettingsui-gtk3_ru.po @@ -385,8 +385,8 @@ msgid "service is inactive" msgstr "служба неактивна" #: source/libublsettingsui-gtk3.h:492 -msgid "The changes were not saved to either the local or global configuration file. Quit without saving?" -msgstr "Изменения не сохранены ни в локальный, ни в глобальный конфигурационный файл. Выйти без сохранения?" +msgid "The changes were not saved to either the local or global configuration file.\nQuit without saving?" +msgstr "Изменения не сохранены ни в локальный, ни в глобальный конфигурационный файл.\nВыйти без сохранения?" #: source/libublsettingsui-gtk3.h:492 msgid "Exit" diff --git a/source/libublsettingsui-gtk3.h b/source/libublsettingsui-gtk3.h index e65e53e..02b7638 100644 --- a/source/libublsettingsui-gtk3.h +++ b/source/libublsettingsui-gtk3.h @@ -575,6 +575,6 @@ yon_app_chooser_window *yon_app_chooser_window_new(int multiple_choise); #define _SERVICE_ACTIVE_STATUS_LABEL(target) yon_char_unite("\"",target,"\" ", yon_char_get_localised_from_lib(_("service is active")),NULL) #define _SERVICE_INACTIVE_STATUS_LABEL(target) yon_char_unite("\"",target,"\" ",yon_char_get_localised_from_lib(_("service is inactive")),NULL) - #define UNSAVED_LABEL yon_char_get_localised_from_lib("The changes were not saved to either the local or global configuration file. Quit without saving?") + #define UNSAVED_LABEL yon_char_get_localised_from_lib("The changes were not saved to either the local or global configuration file.\nQuit without saving?") #define EXIT_LABEL yon_char_get_localised_from_lib("Exit") #endif \ No newline at end of file From a220e79d80babef3076ec4382ae02a49a630529c Mon Sep 17 00:00:00 2001 From: Ivan Yarcev Date: Mon, 14 Jul 2025 18:01:46 +0600 Subject: [PATCH 5/6] Added icon; Fixed file saving --- ...x.libublsettingsui-gtk3.print-symbolic.svg | 33 +++++++++++++++++++ libublsettingsui-gtk3-debugger.glade | 32 +----------------- source/libublsettingsui-gtk3-filechooser.c | 6 ++++ 3 files changed, 40 insertions(+), 31 deletions(-) create mode 100644 icons/actions/com.ublinux.libublsettingsui-gtk3.print-symbolic.svg diff --git a/icons/actions/com.ublinux.libublsettingsui-gtk3.print-symbolic.svg b/icons/actions/com.ublinux.libublsettingsui-gtk3.print-symbolic.svg new file mode 100644 index 0000000..a75e34b --- /dev/null +++ b/icons/actions/com.ublinux.libublsettingsui-gtk3.print-symbolic.svg @@ -0,0 +1,33 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + + + + diff --git a/libublsettingsui-gtk3-debugger.glade b/libublsettingsui-gtk3-debugger.glade index 3b458ab..e94b6e3 100644 --- a/libublsettingsui-gtk3-debugger.glade +++ b/libublsettingsui-gtk3-debugger.glade @@ -1,16 +1,9 @@ - + - - Save - True - True - False - True - 800 False @@ -115,27 +108,4 @@ - - - - - - - - - - - - - - - - - - - - - - liststore1 - diff --git a/source/libublsettingsui-gtk3-filechooser.c b/source/libublsettingsui-gtk3-filechooser.c index 7942dab..3d40bd7 100644 --- a/source/libublsettingsui-gtk3-filechooser.c +++ b/source/libublsettingsui-gtk3-filechooser.c @@ -39,6 +39,12 @@ void on_file_chooser_selected(GtkWidget *self, filechooser_window *window){ GtkFileChooserAction action = gtk_file_chooser_get_action(GTK_FILE_CHOOSER(window->MainFileChooser)); for (int i=0;iMainFileChooser)),NULL); + data = temp; + } + } if ((action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER&&success_size==0) || (action == GTK_FILE_CHOOSER_ACTION_OPEN&>k_toggle_button_get_active(GTK_TOGGLE_BUTTON(window->ChooseFolderCheck))&&yon_file_is_directory(data)) || (action == GTK_FILE_CHOOSER_ACTION_OPEN&&!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(window->ChooseFolderCheck))&&!yon_file_is_directory(data)) || From 3b9ee94581383ed16bbb0a8a741a6c61e1955f63 Mon Sep 17 00:00:00 2001 From: Ivan Yarcev Date: Fri, 18 Jul 2025 18:00:52 +0600 Subject: [PATCH 6/6] WIP Added password window --- gresource.xml | 1 + libublsettingsui-gtk3-password.glade | 333 ++++++++++++++++++++++++ source/CMakeLists.txt | 2 + source/libublsettingsui-gtk3-password.c | 228 ++++++++++++++++ source/libublsettingsui-gtk3.h | 39 +++ 5 files changed, 603 insertions(+) create mode 100644 libublsettingsui-gtk3-password.glade create mode 100644 source/libublsettingsui-gtk3-password.c diff --git a/gresource.xml b/gresource.xml index 6f92e06..a0718a8 100644 --- a/gresource.xml +++ b/gresource.xml @@ -10,6 +10,7 @@ libublsettingsui-gtk3-config-window.glade libublsettingsui-gtk3-service-control.glade libublsettingsui-gtk3-app-chooser.glade + libublsettingsui-gtk3-password.glade libublsettingsui-gtk3.css diff --git a/libublsettingsui-gtk3-password.glade b/libublsettingsui-gtk3-password.glade new file mode 100644 index 0000000..81710d0 --- /dev/null +++ b/libublsettingsui-gtk3-password.glade @@ -0,0 +1,333 @@ + + + + + + True + False + com.ublinux.libublsettingsui-gtk3.cancel-uncolored-symbolic + + + True + False + com.ublinux.libublsettingsui-gtk3.accept-symbolic + + + False + False + True + 450 + com.ublinux.ubl-settings-update + + + True + False + 5 + vertical + 5 + + + True + False + vertical + + + + + + False + True + 0 + + + + + True + False + 5 + 5 + vertical + 5 + + + True + False + vertical + 5 + + + True + False + 5 + + + True + False + Password: + 0 + + + False + True + 0 + + + + + True + True + Password + False + * + True + ******** + password + + + True + True + 1 + + + + + True + True + 1 + + + + + True + False + 5 + + + True + False + Repeat password: + 0 + + + False + True + 0 + + + + + True + True + Repeat password + False + * + True + ******** + password + + + True + True + 1 + + + + + True + True + 2 + + + + + False + True + 0 + + + + + True + False + 5 + + + True + False + Encryption: + 0 + + + False + True + 0 + + + + + True + False + Encryption + 0 + + Default (None) + SHA-512 + SHA-256 + + + + True + True + 1 + + + + + True + True + 1 + + + + + Do not encrypt password + True + False + True + False + True + + + False + True + 2 + + + + + True + False + + + False + True + 3 + + + + + True + False + vertical + 5 + + + True + False + 5 + + + True + False + Password hash: + 0 + + + False + True + 0 + + + + + True + False + True + Password hash + False + * + + + True + True + 1 + + + + + True + True + 2 + + + + + False + True + 4 + + + + + False + True + 2 + + + + + + + True + False + + + True + False + Password input + + + + + + + + Cancel + True + True + True + image4 + + + + + + Accept + True + True + True + image5 + + + + end + 1 + + + + + + + + + + + + + diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 9aeefed..8578725 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -46,6 +46,7 @@ set(DEPENDFILES ../libublsettingsui-gtk3-config-window.glade ../libublsettingsui-gtk3-service-control.glade ../libublsettingsui-gtk3-app-chooser.glade + ../libublsettingsui-gtk3-password.glade ../gresource.xml ../libublsettingsui-gtk3-banner.png ../libublsettingsui-gtk3.css @@ -85,6 +86,7 @@ add_library(${PROJECT_NAME} SHARED libublsettingsui-gtk3-service.c libublsettingsui-gtk3-app-chooser.c libublsettingsui-gtk3-standard-callbacks.c + libublsettingsui-gtk3-password.c libublsettingsui-gtk3.h ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C}) diff --git a/source/libublsettingsui-gtk3-password.c b/source/libublsettingsui-gtk3-password.c new file mode 100644 index 0000000..6b6ce7a --- /dev/null +++ b/source/libublsettingsui-gtk3-password.c @@ -0,0 +1,228 @@ +#include "libublsettingsui-gtk3.h" + + +#define sha256_encrypt_command(target) yon_char_unite("echo -n \"",target,"\" | sha256sum | cut -f 1 -d ' '",NULL) +#define sha512_encrypt_command(target) yon_char_unite("echo -n \"",target,"\" | sha512sum | cut -f 1 -d ' '",NULL) + +yon_password_window *yon_password_window_new(); + +char *yon_password_unencrypted_password_get(yon_password_window *window){ + const char *password = gtk_entry_get_text(GTK_ENTRY(window->PasswordEntry)); + const char *password_repeat = gtk_entry_get_text(GTK_ENTRY(window->RepeatPasswordEntry)); + if (strpbrk(password,"!@#%^&*\'")){ + yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_PASSWORD_RESTRICTED_SYMBOL_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE); + yon_ubl_status_highlight_incorrect(window->PasswordEntry); + return NULL; + } + if (strcmp(password,password_repeat)){ + yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_PASSWORD_MISMATCH_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE); + yon_ubl_status_highlight_incorrect(window->PasswordEntry); + yon_ubl_status_highlight_incorrect(window->RepeatPasswordEntry); + return NULL; + } + if (yon_char_is_empty(password)){ + yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_EMPTY_IMPORTANT_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE); + yon_ubl_status_highlight_incorrect(window->PasswordEntry); + return NULL; + } + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(window->NoEncriptionCheck))){ + const char *encryption = gtk_combo_box_get_active_id(GTK_COMBO_BOX(window->EncryptionCombo)); + char *final = yon_char_unite(encryption,"|",password,NULL); + return final; + } else { + return yon_char_new(password); + } +} + +char *yon_password_hash_get(yon_password_window *window){ + int encription_active = gtk_combo_box_get_active(GTK_COMBO_BOX(window->EncryptionCombo)); + const char *encription = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(window->EncryptionCombo)); + const char *encription_command = gtk_combo_box_get_active_id(GTK_COMBO_BOX(window->EncryptionCombo)); + const char *hash = gtk_entry_get_text(GTK_ENTRY(window->PasswordHashEntry)); + if (!yon_char_is_empty(hash)){ + // if (!yon_char_is_empty(window->old_password)&&strcmp(hash,window->old_password)){ + switch(encription_active){ + case 1:{ + if (strlen(hash)!=128){ + yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_INCORRECT_HASH_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE); + yon_ubl_status_highlight_incorrect(window->PasswordHashEntry); + return NULL; + } + } + break; + case 2:{ + if (strlen(hash)!=64){ + yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_INCORRECT_HASH_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE); + yon_ubl_status_highlight_incorrect(window->PasswordHashEntry); + return NULL; + } + } + break; + } + // } + char *final = yon_char_unite(encription,"|",hash,NULL); + return final; + } else { + const char *password = gtk_entry_get_text(GTK_ENTRY(window->PasswordEntry)); + const char *password_repeat = gtk_entry_get_text(GTK_ENTRY(window->RepeatPasswordEntry)); + if (strpbrk(password,"!@#%^&*\'")){ + yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_PASSWORD_RESTRICTED_SYMBOL_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE); + yon_ubl_status_highlight_incorrect(window->PasswordEntry); + return NULL; + } + if (yon_char_is_empty(password_repeat)){ + yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_EMPTY_IMPORTANT_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE); + yon_ubl_status_highlight_incorrect(window->RepeatPasswordEntry); + return NULL; + } + if (strcmp(password,password_repeat)){ + yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_PASSWORD_MISMATCH_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE); + yon_ubl_status_highlight_incorrect(window->PasswordEntry); + yon_ubl_status_highlight_incorrect(window->RepeatPasswordEntry); + return NULL; + } + + int size; + config_str hash = yon_config_load(yon_debug_output("%s\n",encription_active==1?sha512_encrypt_command(password):sha256_encrypt_command(password)),&size); + yon_char_remove_last_symbol(hash[0],'\n'); + + char *final = hash[0]; + if (gtk_widget_get_visible(window->EncryptionCombo)){ + final = yon_char_unite(encription,"|",hash[0],NULL); + } + return final; + } + return NULL; +} + +void on_password_encryption_changed(GtkComboBox *self, yon_password_window *dialog){ + int active = gtk_combo_box_get_active(self); + gtk_widget_set_sensitive(dialog->NoEncriptionCheck,!!active); + if (!active) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->NoEncriptionCheck),0); +} + +void yon_hash_entry_sensitiveness_update(GtkWidget *, yon_password_window *dialog){ + int hash_type_sensitive = gtk_combo_box_get_active(GTK_COMBO_BOX(dialog->EncryptionCombo)); + int encrypt_sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->NoEncriptionCheck)); + if (!encrypt_sensitive&&hash_type_sensitive) gtk_widget_set_sensitive(dialog->PasswordHashEntry,1); + else gtk_widget_set_sensitive(dialog->PasswordHashEntry,0); +} + +void yon_password_hash_list_set(yon_password_window *window, config_str hashes, config_str get_hash_commands, int size){ + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(window->EncryptionCombo)); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(window->EncryptionCombo),_ENCRYPTION_DEFAULT_LABEL,""); + + for (int i=0;iEncryptionCombo),hashes[i],get_hash_commands[i]); + } +} + +void on_password_hash_sensitiveness(GtkWidget *,yon_password_window *window){ + const char *password = gtk_entry_get_text(GTK_ENTRY(window->PasswordEntry)); + const char *repeat_password = gtk_entry_get_text(GTK_ENTRY(window->RepeatPasswordEntry)); + const char *hash = gtk_entry_get_text(GTK_ENTRY(window->PasswordHashEntry)); + const char *hash_command = gtk_combo_box_get_active_id(GTK_COMBO_BOX(window->EncryptionCombo)); + if (!yon_char_is_empty(hash_command)){ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(window->NoEncriptionCheck),1); + gtk_widget_set_sensitive(window->NoEncriptionCheck,0); + } else { + gtk_widget_set_sensitive(window->NoEncriptionCheck,1); + } + if (!yon_char_is_empty(password)||!yon_char_is_empty(repeat_password)){ + gtk_widget_set_sensitive(window->HashBox,0); + gtk_widget_set_sensitive(window->PasswordBox,1); + } else if (yon_char_is_empty(password)&&yon_char_is_empty(repeat_password)&& + gtk_combo_box_get_active(GTK_COMBO_BOX(window->EncryptionCombo))>0&& + yon_char_is_empty(hash)&&!yon_char_is_empty(hash_command)){ + gtk_widget_set_sensitive(window->HashBox,1); + gtk_widget_set_sensitive(window->PasswordBox,1); + gtk_widget_set_sensitive(window->NoEncriptionCheck,1); + } else if (!yon_char_is_empty(hash)&&!yon_char_is_empty(hash_command)) { + gtk_widget_set_sensitive(window->HashBox,1); + gtk_widget_set_sensitive(window->PasswordBox,0); + gtk_widget_set_sensitive(window->NoEncriptionCheck,0); + } else { + gtk_widget_set_sensitive(window->HashBox,0); + gtk_widget_set_sensitive(window->PasswordBox,1); + } +} + +void on_password_accept(GtkWidget *,dictionary *dict){ + yon_password_window *window = yon_dictionary_get_data(dict->first,yon_password_window*); + GtkWidget *target = yon_dictionary_get_data(dict->first->next,GtkWidget*); + + int encription_active = gtk_combo_box_get_active(GTK_COMBO_BOX(window->EncryptionCombo)); + char *final = NULL; + if (encription_active == 0||gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(window->NoEncriptionCheck))){ + final = yon_password_unencrypted_password_get(window); + if (!final) return; + } else { + final = yon_password_hash_get(window); + if (!final) return; + } + gtk_entry_set_text(GTK_ENTRY(target),final); + gtk_widget_destroy(window->Window); +} + +yon_password_window *yon_password_window_new(){ + GtkBuilder *builder = gtk_builder_new_from_resource(ui_glade_path_password); + yon_password_window *window = malloc(sizeof(yon_password_window)); + window->Window = yon_gtk_builder_get_widget(builder,"PasswordWindow"); + window->HeadLabel = yon_gtk_builder_get_widget(builder,"userTitleNameLabel"); + window->StatusBox = yon_gtk_builder_get_widget(builder,"StatusBox"); + window->PasswordEntry = yon_gtk_builder_get_widget(builder,"PasswordEntry"); + window->RepeatPasswordEntry = yon_gtk_builder_get_widget(builder,"RepeatPasswordEntry"); + window->EncryptionCombo = yon_gtk_builder_get_widget(builder,"EncryptionCombo"); + window->NoEncriptionCheck = yon_gtk_builder_get_widget(builder,"NoEncriptionCheck"); + window->PasswordHashEntry = yon_gtk_builder_get_widget(builder,"PasswordHashEntry"); + window->UserCancelButton = yon_gtk_builder_get_widget(builder,"UserCancelButton"); + window->AcceptButton = yon_gtk_builder_get_widget(builder,"UserOkButton"); + window->PasswordBox = yon_gtk_builder_get_widget(builder,"PasswordBox"); + window->HashBox = yon_gtk_builder_get_widget(builder,"HashBox"); + + window->old_password=NULL; + g_signal_connect(G_OBJECT(window->UserCancelButton),"clicked",G_CALLBACK(on_subwindow_close),NULL); + g_signal_connect(G_OBJECT(window->EncryptionCombo),"changed",G_CALLBACK(on_password_hash_sensitiveness),window); + g_signal_connect(G_OBJECT(window->NoEncriptionCheck),"toggled",G_CALLBACK(on_password_hash_sensitiveness),window); + g_signal_connect(G_OBJECT(window->PasswordHashEntry),"changed",G_CALLBACK(on_password_hash_sensitiveness),window); + g_signal_connect(G_OBJECT(window->PasswordEntry),"changed",G_CALLBACK(on_password_hash_sensitiveness),window); + g_signal_connect(G_OBJECT(window->RepeatPasswordEntry),"changed",G_CALLBACK(on_password_hash_sensitiveness),window); + gtk_widget_show(window->Window); + return window; +} + +yon_password_window *yon_password_open(GtkEntry *target){ + g_return_val_if_fail(GTK_IS_ENTRY(target),NULL); + + yon_password_window *dialog = yon_password_window_new(); + + g_signal_connect(G_OBJECT(dialog->NoEncriptionCheck),"toggled",G_CALLBACK(yon_hash_entry_sensitiveness_update),dialog); + g_signal_connect(G_OBJECT(dialog->EncryptionCombo),"changed",G_CALLBACK(yon_hash_entry_sensitiveness_update),dialog); + + yon_gtk_entry_set_password_visibility_icon(GTK_ENTRY(dialog->PasswordEntry)); + yon_gtk_entry_set_password_visibility_icon(GTK_ENTRY(dialog->PasswordHashEntry)); + yon_gtk_entry_set_password_visibility_icon(GTK_ENTRY(dialog->RepeatPasswordEntry)); + + char *old_password = yon_char_new(gtk_entry_get_text(target)); + char *hash_type = NULL; + if (!yon_char_is_empty(old_password)&&strstr(old_password,"|")){ + hash_type = yon_char_divide(old_password,6); + gtk_combo_box_set_active_id(GTK_COMBO_BOX(dialog->EncryptionCombo),hash_type); + } + if (!yon_char_is_empty(old_password)&&(strlen(old_password)==128||strlen(old_password)==64)){ + dialog->old_password = old_password; + gtk_entry_set_text(GTK_ENTRY(dialog->PasswordHashEntry),old_password); + } else if (!yon_char_is_empty(old_password)){ + dialog->old_password = old_password; + gtk_entry_set_text(GTK_ENTRY(dialog->PasswordEntry),old_password); + gtk_entry_set_text(GTK_ENTRY(dialog->RepeatPasswordEntry),old_password); + } + dictionary *dict = NULL; + yon_dictionary_add_or_create_if_exists_with_data(dict,"window",dialog); + yon_dictionary_add_or_create_if_exists_with_data(dict,"target",target); + g_signal_connect(G_OBJECT(dialog->AcceptButton),"clicked",G_CALLBACK(on_password_accept),dict); + g_signal_connect(G_OBJECT(dialog->EncryptionCombo),"changed",G_CALLBACK(on_password_encryption_changed),dialog); + return dialog; +} \ No newline at end of file diff --git a/source/libublsettingsui-gtk3.h b/source/libublsettingsui-gtk3.h index 02b7638..c018ade 100644 --- a/source/libublsettingsui-gtk3.h +++ b/source/libublsettingsui-gtk3.h @@ -45,6 +45,9 @@ /**Путь до файла окна выбора приложений утилит ubl-settings-**/ #define ui_glade_path_app_chooser "/com/ublinux/ui/libublsettingsui-gtk3-app-chooser.glade" +/**Путь до файла окна ввода пароля */ +#define ui_glade_path_password "/com/ublinux/ui/libublsettingsui-gtk3-password.glade" + /**Путь до основного баннера утилит ubl-settings-**/ #define ui_banner_path "/com/ublinux/images/libublsettingsui-gtk3-banner.png" @@ -456,6 +459,34 @@ int yon_app_chooser_window_select(yon_app_chooser_window *window,config_str sele config_str yon_app_chooser_window_run(yon_app_chooser_window *window, int *size); yon_app_chooser_window *yon_app_chooser_window_new(int multiple_choise); +typedef struct { + GtkWidget *Window; + GtkWidget *HeadLabel; + GtkWidget *StatusBox; + + GtkWidget *PasswordEntry; + GtkWidget *RepeatPasswordEntry; + GtkWidget *EncryptionCombo; + GtkWidget *NoEncriptionCheck; + GtkWidget *PasswordHashEntry; + GtkWidget *UserCancelButton; + GtkWidget *AcceptButton; + + GtkWidget *PasswordBox; + GtkWidget *HashBox; + + const char *old_password; +} yon_password_window; + +/// @brief +/// @param window окно с паролем +/// @param hashes массив с названиями типов хэша +/// @param get_hash_commands массив с командами получения хэша. Если команда == NULL, получение хэша пароля блокируется +/// @param size размер hashes и get_hash_commands. Оба массива должны быть одного размера +void yon_password_hash_list_set(yon_password_window *window, config_str hashes, config_str get_hash_commands, int size); + +yon_password_window *yon_password_open(GtkEntry *target); + #define VERSION_LABEL yon_char_unite(_("Version:")," ",!yon_char_is_empty(template_app_information.app_version)?template_app_information.app_version:"","\n",NULL) #define HELP_LABEL(rest) yon_char_unite(template_app_information.app_tech_name,_(" version:")," ", !yon_char_is_empty(template_app_information.app_version)?template_app_information.app_version:"","\n",\ template_app_information.app_title,"\n",_("Usage:"), " ",template_app_information.app_tech_name," ",_("[OPTIONS]"),"\n",\ @@ -575,6 +606,14 @@ yon_app_chooser_window *yon_app_chooser_window_new(int multiple_choise); #define _SERVICE_ACTIVE_STATUS_LABEL(target) yon_char_unite("\"",target,"\" ", yon_char_get_localised_from_lib(_("service is active")),NULL) #define _SERVICE_INACTIVE_STATUS_LABEL(target) yon_char_unite("\"",target,"\" ",yon_char_get_localised_from_lib(_("service is inactive")),NULL) + #define _PASSWORD_TITLE_LABEL yon_char_get_localised_from_lib("Password") + #define UNSAVED_LABEL yon_char_get_localised_from_lib("The changes were not saved to either the local or global configuration file.\nQuit without saving?") #define EXIT_LABEL yon_char_get_localised_from_lib("Exit") + + #define _PASSWORD_MISMATCH_LABEL yon_char_get_localised_from_lib("Passwords do not match") + #define _PASSWORD_RESTRICTED_SYMBOL_LABEL yon_char_get_localised_from_lib("Password contains restricted symbols") + #define _EMPTY_IMPORTANT_LABEL yon_char_get_localised_from_lib("Empty important field!") + #define _INCORRECT_HASH_LABEL yon_char_get_localised_from_lib("Invalid hash") + #define _ENCRYPTION_DEFAULT_LABEL yon_char_get_localised_from_lib("Default (None)") #endif \ No newline at end of file