From 07bc962f4bca10c600c706fee3fe0f6d5eaca07a Mon Sep 17 00:00:00 2001 From: Ivan Yarcev Date: Fri, 5 May 2023 16:30:10 +0600 Subject: [PATCH 1/2] Updates --- .gitignore | 2 + Makefile | 2 + ...blinux.ubl-settings-usergroups.checked.svg | 327 ++++++++++ ...blinux.ubl-settings-usergroups.warning.svg | 55 ++ source/CMakeLists.txt | 4 +- source/ubl-settings-usergroups.c | 128 +++- source/ubl-settings-usergroups.h | 96 ++- source/ubl-utils.c | 599 ++++++++++++++++++ source/ubl-utils.h | 164 +++++ ubl-settings-usergroups-banner.png | Bin 0 -> 33872 bytes ubl-settings-usergroups.glade | 179 +++--- ubl-settings-usergroups.pot | 114 ++++ ubl-settings-usergroups_ru.po | 121 ++++ 13 files changed, 1698 insertions(+), 93 deletions(-) create mode 100644 com.ublinux.ubl-settings-usergroups.checked.svg create mode 100644 com.ublinux.ubl-settings-usergroups.warning.svg create mode 100644 source/ubl-utils.c create mode 100644 source/ubl-utils.h create mode 100644 ubl-settings-usergroups-banner.png create mode 100644 ubl-settings-usergroups.pot create mode 100644 ubl-settings-usergroups_ru.po diff --git a/.gitignore b/.gitignore index 1d74e21..5706090 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .vscode/ +ubl-settings-usergroups.glade~ +ubl-settings-usergroups \ No newline at end of file diff --git a/Makefile b/Makefile index dc489c7..89d234d 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ all: init build init: @echo "Initialize ..."; \ sed -r "s/(version_application = ).*/\1\"$$(grep 'VERSION' ${FILE_VERSION} | cut -d" " -f2)\";/" -i source/ubl-settings-usergroups.h; \ + gcc source/ubl-settings-usergroups.c source/ubl-utils.c -o ubl-settings-usergroups `pkg-config --cflags --libs gtk+-3.0` -g; \ echo "-- Build path: ${CMAKE_BUILD_DIR}" depend: @@ -116,6 +117,7 @@ install: check uninstall @install -Dm644 -t "${DESTDIR}${PREFIX}/share/applications/" "${PKGNAME}.desktop" @install -dm755 "${DESTDIR}${PREFIX}/share/${PKGNAME}"/{ui,css,images} @install -Dm644 -t "${DESTDIR}${PREFIX}/share/${PKGNAME}/ui/" "${PKGNAME}.glade" + @install -Dm644 -t "${DESTDIR}${PREFIX}/share/${PKGNAME}/ui/" "${PKGNAME}-banner.png" @install -Dm644 -t "${DESTDIR}${PREFIX}/share/${PKGNAME}/css/" "${PKGNAME}.css" @if [ -z ${DESTDIR} ]; then \ [ -d "${DESTDIR}${PREFIX}/share/icons/hicolor/" ] && gtk-update-icon-cache -fiq "${DESTDIR}${PREFIX}/share/icons/hicolor/" &>/dev/null || true; \ diff --git a/com.ublinux.ubl-settings-usergroups.checked.svg b/com.ublinux.ubl-settings-usergroups.checked.svg new file mode 100644 index 0000000..e3cab42 --- /dev/null +++ b/com.ublinux.ubl-settings-usergroups.checked.svg @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + + diff --git a/com.ublinux.ubl-settings-usergroups.warning.svg b/com.ublinux.ubl-settings-usergroups.warning.svg new file mode 100644 index 0000000..9a90dba --- /dev/null +++ b/com.ublinux.ubl-settings-usergroups.warning.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 1bb765e..d891c96 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -17,7 +17,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wextra -Werror -Wmissin set(SOURCE_FILES ubl-settings-usergroups.c - ubl-settings-usergroups.h) + ubl-settings-usergroups.h + ubl-utils.c + ubl-utils.h) set(LIBRARIES ${GTK_LIBRARIES} diff --git a/source/ubl-settings-usergroups.c b/source/ubl-settings-usergroups.c index 79a7ddc..71a0ed8 100644 --- a/source/ubl-settings-usergroups.c +++ b/source/ubl-settings-usergroups.c @@ -1,11 +1,131 @@ #include #include "ubl-settings-usergroups.h" -int main(int argc, char *argv[]){ - gtk_init(&argc,&argv); +void on_close_subwindow(GtkWidget *self){ + gtk_widget_destroy(gtk_widget_get_toplevel(self)); +} + +void on_about_open(){ + +} + +void on_open_users(){ + GtkBuilder *builder=gtk_builder_new_from_file(glade_path); + users_window *widgets = malloc (sizeof(users_window)); + widgets->window=yon_gtk_builder_get_widget(builder, "usersEditWindow"); +} + +void on_open_groups(){ + GtkBuilder *builder=gtk_builder_new_from_file(glade_path); + groups_window *widgets = malloc (sizeof(groups_window)); + widgets->window=yon_gtk_builder_get_widget(builder, "groupsEditWindow"); + + widgets->groupsTreeView=yon_gtk_builder_get_widget(builder, "groupsTreeView"); + widgets->groupsGroupColumn=GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "groupsGroupColumn")); + widgets->groupsEnabledColumn=GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "groupsEnabledColumn")); + widgets->groupsCancelButton=yon_gtk_builder_get_widget(builder, "groupsCancelButton"); + widgets->groupsOkButton=yon_gtk_builder_get_widget(builder, "groupsOkButton"); + widgets->list=GTK_LIST_STORE(gtk_builder_get_object(builder, "liststore2")); + gtk_button_set_label(GTK_BUTTON(widgets->groupsCancelButton),_("Cancel")); + gtk_button_set_label(GTK_BUTTON(widgets->groupsOkButton),_("Ok")); + gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(widgets->groupsGroupColumn),_("Group")); + gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(widgets->groupsEnabledColumn),_("Enabled")); + g_signal_connect(G_OBJECT(widgets->groupsCancelButton), "clicked", G_CALLBACK(on_close_subwindow),NULL); + gtk_widget_show_all(widgets->window); +} + +main_window *setup_main_window(){ + main_window *widgets=NULL; + widgets=malloc(sizeof(main_window)); GtkBuilder *builder=gtk_builder_new_from_file(glade_path); - GtkWidget *window=GTK_WIDGET(gtk_builder_get_object(builder,"MainWindow")); - gtk_widget_show_all(window); + widgets->window=yon_gtk_builder_get_widget(builder,"MainWindow"); + GtkListStore *list; + widgets->mainUserGroupsLabel=yon_gtk_builder_get_widget(builder,"mainUserGroupsLabel"); + widgets->mainUserGroupsEntry=yon_gtk_builder_get_widget(builder,"mainUserGroupsEntry"); + widgets->mainUserGroupsButton=yon_gtk_builder_get_widget(builder,"mainUserGroupsButton"); + widgets->mainUserNameLabel=yon_gtk_builder_get_widget(builder,"mainUserNameLabel"); + widgets->mainUserNameAdminCheck=yon_gtk_builder_get_widget(builder,"mainUserNameAdminCheck"); + widgets->mainUserNameEntry=yon_gtk_builder_get_widget(builder,"mainUserNameEntry"); + widgets->mainUserPasswordLabel=yon_gtk_builder_get_widget(builder,"mainUserPasswordLabel"); + widgets->mainUserPasswordEntry=yon_gtk_builder_get_widget(builder,"mainUserPasswordEntry"); + widgets->mainPasswordHashLabel=yon_gtk_builder_get_widget(builder,"mainPasswordHashLabel"); + widgets->mainUserPasswordHashCombo=yon_gtk_builder_get_widget(builder,"mainUserPasswordHashCombo"); + widgets->mainUserAutologinLabel=yon_gtk_builder_get_widget(builder,"mainUserAutologinLabel"); + widgets->mainUserAutologinCombo=yon_gtk_builder_get_widget(builder,"mainUserAutologinCombo"); + widgets->mainUpdateHomeDirLabel=yon_gtk_builder_get_widget(builder,"mainUpdateHomeDirLabel"); + widgets->mainUpdateDirCheck=yon_gtk_builder_get_widget(builder,"mainUpdateDirCheck"); + widgets->mainLoadUserProgramsLabel=yon_gtk_builder_get_widget(builder,"mainLoadUserProgramsLabel"); + widgets->mainLoadUserProgramsEntry=yon_gtk_builder_get_widget(builder,"mainLoadUserProgramsEntry"); + widgets->mainUserStringLabel=yon_gtk_builder_get_widget(builder,"mainUserStringLabel"); + widgets->mainUserStringEntry=yon_gtk_builder_get_widget(builder,"mainUserStringEntry"); + widgets->mainAddButton=yon_gtk_builder_get_widget(builder,"mainAddButton"); + widgets->mainEditButton=yon_gtk_builder_get_widget(builder,"mainEditButton"); + widgets->mainDeleteButton=yon_gtk_builder_get_widget(builder,"mainDeleteButton"); + widgets->mainUIDColumn=GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder,"mainUIDColumn")); + widgets->mainLoginColumn=GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder,"mainLoginColumn")); + widgets->mainPasswordColumn=GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder,"mainPasswordColumn")); + widgets->mainUserNameColumn=GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder,"mainUserNameColumn")); + widgets->headerLoadGlobalConfigurationMenuItem=yon_gtk_builder_get_widget(builder,"headerLoadGlobalConfigurationMenuItem"); + widgets->headerLoadLocalConfigurationMenuItem=yon_gtk_builder_get_widget(builder,"headerLoadLocalConfigurationMenuItem"); + widgets->headerSaveGlobalLocalConfigurationMenuItem=yon_gtk_builder_get_widget(builder,"headerSaveGlobalLocalConfigurationMenuItem"); + widgets->headerSaveGlobalConfigurationMenuItem=yon_gtk_builder_get_widget(builder,"headerSaveGlobalConfigurationMenuItem"); + widgets->headerSaveLocalConfigurationMenuItem=yon_gtk_builder_get_widget(builder,"headerSaveLocalConfigurationMenuItem"); + widgets->headerDocumentationMenuItem=yon_gtk_builder_get_widget(builder,"headerDocumentationMenuItem"); + widgets->headerAboutMenuItem=yon_gtk_builder_get_widget(builder,"headerAboutMenuItem"); + widgets->mainHeaderConfigLoadLabel=yon_gtk_builder_get_widget(builder,"mainHeaderConfigLoadLabel"); + widgets->mainHeaderTitleLabel=yon_gtk_builder_get_widget(builder,"mainHeaderTitleLabel"); + widgets->mainHeaderSaveConfigurationLabel=yon_gtk_builder_get_widget(builder,"mainHeaderSaveConfigurationLabel"); + widgets->mainStatusBox=yon_gtk_builder_get_widget(builder,"mainStatusBox"); + widgets->mainStatusIcon=yon_gtk_builder_get_widget(builder,"mainStatusIcon"); + widgets->mainStatusLabel=yon_gtk_builder_get_widget(builder,"mainStatusLabel"); + + g_signal_connect(G_OBJECT(widgets->mainUserGroupsButton),"clicked", G_CALLBACK(on_open_groups),NULL); + g_signal_connect(G_OBJECT(widgets->window), "destroy", G_CALLBACK(gtk_main_quit), NULL); + + gtk_label_set_text(GTK_LABEL(widgets->mainUserGroupsLabel),_("User groups (default)")); + gtk_label_set_text(GTK_LABEL(widgets->mainUserNameLabel),_("User name")); + gtk_button_set_label(GTK_BUTTON(widgets->mainUserNameAdminCheck),_("Administrator")); + gtk_label_set_text(GTK_LABEL(widgets->mainUserPasswordLabel),_("User password")); + gtk_label_set_text(GTK_LABEL(widgets->mainPasswordHashLabel),_("Password hash algorythm")); + gtk_label_set_text(GTK_LABEL(widgets->mainUserAutologinLabel),_("Autologin")); + gtk_label_set_text(GTK_LABEL(widgets->mainUpdateHomeDirLabel),_("Update HOME directory(ies)")); + gtk_button_set_label(GTK_BUTTON(widgets->mainUpdateDirCheck),_("Enabled")); + gtk_label_set_text(GTK_LABEL(widgets->mainLoadUserProgramsLabel),_("Automatically load user programs")); + gtk_label_set_text(GTK_LABEL(widgets->mainUserStringLabel),_("User string")); + gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(widgets->mainUIDColumn),_("UID")); + gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(widgets->mainLoginColumn),_("Login")); + gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(widgets->mainPasswordColumn),_("Password")); + gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(widgets->mainUserNameColumn),_("User Name")); + gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerLoadGlobalConfigurationMenuItem),_("Load from global configuration")); + gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerLoadLocalConfigurationMenuItem),_("Load from local configuration")); + gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerSaveGlobalLocalConfigurationMenuItem),_("Save to global and local configuration")); + gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerSaveGlobalConfigurationMenuItem),_("Save to global configuration")); + gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerSaveLocalConfigurationMenuItem),_("Save to local configuration")); + gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerDocumentationMenuItem),_("Documentation")); + gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerAboutMenuItem),_("About")); + gtk_label_set_text(GTK_LABEL(widgets->mainHeaderConfigLoadLabel),_("Load")); + gtk_label_set_text(GTK_LABEL(widgets->mainHeaderTitleLabel),_("Users and groups")); + gtk_label_set_text(GTK_LABEL(widgets->mainHeaderSaveConfigurationLabel),_("Save")); + + GtkWidget *Header = yon_gtk_builder_get_widget(builder,"headBox"); + GtkWidget *Image = yon_gtk_builder_get_widget(builder,"mainHeadBackgroundImage"); + GtkWidget *Overlay = yon_gtk_builder_get_widget(builder,"mainHeadOverlay"); + yon_ubl_header_setup(Overlay,Header,Image,image_path); + widgets->mainUserAutologinCombo; + gtk_widget_show_all(widgets->window); + +} + +int main(int argc, char *argv[]){ + + textdomain (LocaleName); + gtk_init(&argc,&argv); + main_window *widgets=setup_main_window(); + GtkCssProvider *css=gtk_css_provider_new(); + gtk_css_provider_load_from_path(css,CssPath,NULL); + gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), + GTK_STYLE_PROVIDER(css), + -1); gtk_main(); } \ No newline at end of file diff --git a/source/ubl-settings-usergroups.h b/source/ubl-settings-usergroups.h index 347bd68..c002716 100644 --- a/source/ubl-settings-usergroups.h +++ b/source/ubl-settings-usergroups.h @@ -1,2 +1,96 @@ +#include "ubl-utils.h" +#include +#include +#include +#include +#include +#include +#include -#define glade_path "/usr/share/ubl-settings-usergroups/ui/ubl-settings-usergroups.glade" \ No newline at end of file + +#define glade_path "/usr/share/ubl-settings-usergroups/ui/ubl-settings-usergroups.glade" +#define CssPath "/usr/share/ubl-settings-usergroups/css/ubl-settings-usergroups.css" +#define image_path "/usr/share/ubl-settings-usergroups/ui/ubl-settings-usergroups-banner.png" + +#define LocalePath "/usr/share/locale" +#define LocaleName "ubl-settings-usergroups" + + +#define _(String) gettext(String) + +typedef struct { + GtkWidget *window; + + GtkListStore *list; + GtkWidget *mainUserGroupsLabel; + GtkWidget *mainUserGroupsEntry; + GtkWidget *mainUserGroupsButton; + GtkWidget *mainUserNameLabel; + GtkWidget *mainUserNameAdminCheck; + GtkWidget *mainUserNameEntry; + GtkWidget *mainUserPasswordLabel; + GtkWidget *mainUserPasswordEntry; + GtkWidget *mainPasswordHashLabel; + GtkWidget *mainUserPasswordHashCombo; + GtkWidget *mainUserAutologinLabel; + GtkWidget *mainUserAutologinCombo; + GtkWidget *mainUpdateHomeDirLabel; + GtkWidget *mainUpdateDirCheck; + GtkWidget *mainLoadUserProgramsLabel; + GtkWidget *mainLoadUserProgramsEntry; + GtkWidget *mainUserStringLabel; + GtkWidget *mainUserStringEntry; + GtkWidget *mainAddButton; + GtkWidget *mainEditButton; + GtkWidget *mainDeleteButton; + GtkTreeViewColumn *mainUIDColumn; + GtkTreeViewColumn *mainLoginColumn; + GtkTreeViewColumn *mainPasswordColumn; + GtkTreeViewColumn *mainUserNameColumn; + GtkWidget *headerLoadGlobalConfigurationMenuItem; + GtkWidget *headerLoadLocalConfigurationMenuItem; + GtkWidget *headerSaveGlobalLocalConfigurationMenuItem; + GtkWidget *headerSaveGlobalConfigurationMenuItem; + GtkWidget *headerSaveLocalConfigurationMenuItem; + GtkWidget *headerDocumentationMenuItem; + GtkWidget *headerAboutMenuItem; + GtkWidget *mainHeaderConfigLoadLabel; + GtkWidget *mainHeaderTitleLabel; + GtkWidget *mainHeaderSaveConfigurationLabel; + GtkWidget *mainStatusBox; + GtkWidget *mainStatusIcon; + GtkWidget *mainStatusLabel; + +} main_window; + +typedef struct { + GtkWidget *window; + + GtkWidget *userUIDLabel; + GtkWidget *userUIDEntry; + GtkWidget *userUsernameLabel; + GtkWidget *userUsernameEntry; + GtkWidget *userLoginLabel; + GtkWidget *userLoginEntry; + GtkWidget *userPasswordLabel; + GtkWidget *userPasswordEntry; + GtkWidget *userDefaultPasswordCheck; + GtkWidget *userPasswordHashLabel; + GtkWidget *userPasswordHashCombo; + GtkWidget *userSAMBALabel; + + GtkWidget *userCancelButton; + GtkWidget *userAddButton; +} users_window; + +typedef struct { + GtkWidget *window; + + GtkWidget *groupsTreeView; + GtkTreeViewColumn *groupsEnabledColumn; + GtkTreeViewColumn *groupsGroupColumn; + GtkListStore *list; + + GtkWidget *groupsCancelButton; + GtkWidget *groupsOkButton; +} groups_window; \ No newline at end of file diff --git a/source/ubl-utils.c b/source/ubl-utils.c new file mode 100644 index 0000000..ed01b97 --- /dev/null +++ b/source/ubl-utils.c @@ -0,0 +1,599 @@ +#include "ubl-utils.h" +#ifndef UBL_UTILS + +typedef enum { + DICTIONARY_ACTION_WIDGETS_TYPE, + DICTIONARY_IVGRAPHICALS_TYPE, + DICTIONARY_OTHER_TYPE + +} DICT_TYPE; + +typedef struct dictionary { + char *key; + void *data; + struct dictionary *next; + struct dictionary *prev; + struct dictionary *first; + DICT_TYPE data_type; +} dictionary; + +typedef struct apps{ + char *Name; + int Type; + char *Categories; + char *Exec; + char *Icon; + int Pluggable; + int DualPluggable; + } apps; + +typedef struct { + char *command; + int *exitcode; +} thread_output; + +#ifdef __GTK_H__ +typedef struct IVGrapgicals{ + char *sectionName; + char *categories; + GtkListStore *LV; + GtkWidget *Box; + GtkWidget *IV; + GtkWidget *label; + GtkWidget *sep; + GtkCellRendererPixbuf *iconRender; +} IVGraphicals; +#endif +#endif + + +//dictionary functions + +/** + * yon_dictionary_create_empty: + * Creates and returns empty dictionary +*/ +dictionary *yon_dictionary_create_empty(){ + dictionary *dict=malloc(sizeof(dictionary)); + dict->data=NULL; + dict->key=NULL; + dict->next=NULL; + dict->prev=NULL; + dict->first=dict; + dict->data_type=DICTIONARY_OTHER_TYPE; + return dict; +} + +void yon_dictionary_switch_to_last(dictionary **dict){ + if ((*dict)->next!=NULL) + for ((*dict)=(*dict)->first;(*dict)->next!=NULL;(*dict)=(*dict)->next){} +} + +dictionary * yon_dictionary_create_conneced(dictionary *targetdict){ + targetdict=yon_dictionary_get_last(targetdict); + targetdict->next=yon_dictionary_create_empty(); + targetdict->next->prev=targetdict; + targetdict->next->first=targetdict->first; + targetdict->next->data_type=DICTIONARY_OTHER_TYPE; + return targetdict->next; +} + +dictionary *yon_dictionary_get_last(dictionary *dict){ + dictionary *dct=NULL; + for (dct=dict->first;dct->next!=NULL;dct=dct->next){} + return dct; +} + +dictionary *yon_dictionary_switch_places(dictionary *dict,int aim){ + if (aim<0){ + if (dict->prev){ + if (dict->prev->prev){ + dictionary *next = dict->next,*prev=dict->prev,*preprev=prev->prev; + if (next){ + preprev->next=dict; + dict->prev=preprev; + dict->next=prev; + prev->prev=dict; + prev->next=next; + next->prev=prev; + } else { + preprev->next=dict; + dict->prev=preprev; + dict->next=prev; + prev->prev=dict; + prev->next=NULL; + } + return prev; + } else { + dictionary *next = dict->next,*prev=dict->prev; + if (next){ + yon_dictionary_make_first(dict); + dict->prev=NULL; + dict->next=prev; + prev->prev=dict; + prev->next=next; + next->prev=prev; + } else { + dict->prev=NULL; + dict->next=prev; + prev->prev=dict; + prev->next=NULL; + } + return prev; + } + } + } else if (aim>0){ + if (dict->next){ + if (dict->next->next){ + dictionary *next = dict->next,*prev=dict->prev,*afnext=next->next; + if (prev){ + prev->next=next; + next->prev=prev; + next->next=dict; + dict->prev=next; + dict->next=afnext; + afnext->prev=dict; + } else { + yon_dictionary_make_first(next); + next->prev=NULL; + next->next=dict; + dict->prev=next; + dict->next=afnext; + afnext->prev=dict; + } + return next; + } else { + dictionary *next = dict->next,*prev=dict->prev; + if (prev){ + prev->next=next; + next->prev=prev; + next->next=dict; + dict->prev=next; + dict->next=NULL; + } else { + next->prev=NULL; + next->next=dict; + dict->prev=next; + dict->next=NULL; + } + } + } + } +} + +void yon_dictionary_make_first(dictionary *dict){ + for (dictionary *dct=dict->first;dct!=NULL;dct=dct->next){ + dct->first=dict; + } +} + +void yon_dictionary_make_nth(dictionary *dict, int nth){ + dictionary *dct=dict->first; + for (int i=0;inext;} + yon_dictionary_rip(dict); + dictionary *prev=dct->prev; + prev->next=dict; + dict->prev=prev; + dict->next=dct; + dct->prev=dict; +} + +dictionary *yon_dictionary_create_with_data(char *key, void *data){ + dictionary *dct=yon_dictionary_create_empty(); + dct->key=yon_char_new(key); + dct->data=data; + dct->data_type=DICTIONARY_OTHER_TYPE; + return dct; +} + +dictionary *yon_dictionary_create_with_data_connected(dictionary *dict, char *key, void *data){ + dictionary *dct=yon_dictionary_create_conneced(dict); + dct->key=yon_char_new(key); + dct->data=data; + dct->data_type=DICTIONARY_OTHER_TYPE; + return dct; +} + +dictionary *yon_dictionary_connect(dictionary *old, dictionary *toconnect){ + dictionary *dict=yon_dictionary_get_last(old); + dict->next=toconnect; + toconnect->prev=dict; + toconnect->first=dict->first; + return toconnect; +} + +dictionary *yon_dictionary_find(dictionary **dict, char *key){ + dictionary *dct=*dict; + for (dictionary *pointer=dct->first;pointer!=NULL;pointer=pointer->next){ + if (strcmp(pointer->key,key)==0){ + *dict=pointer; + return pointer; + } + } + return NULL; +} + + +dictionary *yon_dictionary_rip(dictionary *dict){ + if (!dict->next){ + dictionary *prev=dict->prev; + if (prev){ + prev->next=NULL; + return prev; + } else return dict; + } + else if (!dict->prev){ + dictionary *next=dict->next; + if (next){ + yon_dictionary_make_first(next); + next->prev=NULL; + return next; + } + else return dict; + } + else { + dictionary *next=dict->next, *prev=dict->prev; + next->prev=prev; + prev->next=next; + return next; + } +} + +dictionary *yon_dictionary_get_nth(dictionary *dict, int place){ + dict=dict->first; + for (int i=0;inext; + if (dict) return dict; + else return NULL; +} + +//char functions + +/** + * creates new char string by combining two char strings. +*/ +char *yon_char_get_augumented(char *source, char *append){ + if (source&&append){ + int size=strlen(source)+strlen(append)+1; + char *final=malloc(size); + memset(final,0,size); + if (strstr(source,"%%")) + sprintf(final,source,append); + else + sprintf(final,"%s%s",source,append); + return final; + } else + return NULL; +} + +/** + * creates new char string by copying another char. +*/ +char *yon_char_new(char *chr){ + char *newchar=malloc(strlen(chr)+1); + memset(newchar,0,strlen(chr)+1); + memcpy(newchar,chr,strlen(chr)); + return newchar; +} + +/** + * cuts source string by size length from startpos position. +*/ +char *yon_cut(char *source, int size, int startpos){ + char *cut=NULL; + cut=malloc(size+1); + memset(cut,0,size+1); + memcpy(cut,source+startpos,size); + return cut; +} +/** + * divides source string in dividepos position, + * returning left part of divided string and + * inserting right part to source string. +*/ +char *yon_char_divide(char *source, int dividepos){ + char *cut=malloc(dividepos+1); + memset(cut,0,dividepos+1); + memcpy(cut,source,dividepos); + char *left=malloc(strlen(source)-strlen(cut)); + memset(left,0,strlen(source)-strlen(cut)); + memcpy(left,source+dividepos+1,(strlen(source)-dividepos)); + memset(source,0,strlen(source)); + memcpy(source,left,strlen(left)); + return cut; +} + +/** + * searches string dividepos in source string and divides it, + * returning left part of divided string and + * inserting right part to source string. + * if delete_divider is 0, left part will contain delete_divider substring, else + * it will stay in right part. +*/ +char *yon_char_divide_search(char *source, char* dividepos, int delete_divider){ + char *cut=strstr(source,dividepos); + int leng=strlen(source)-strlen(cut); + cut=yon_char_divide(source,leng); + return cut; +} +/** + * converts int to char. +*/ +char *yon_char_from_int(int int_to_convert){ + int i=1; + float convert_check=(float)int_to_convert; + for (i=1;convert_check>10;i++){ + convert_check=convert_check/10; + } + char *ch=malloc(i*sizeof(char)+1); + sprintf(ch,"%d",int_to_convert); + return ch; +} + + +//parsing functions + +apps *yon_apps_scan_and_parse_desktops(int *sizef){ + int size=0; + struct apps *applist; + { + DIR *directory=opendir(DesktopPath); + struct dirent *de; + while ((de = readdir(directory))) + { + FILE *file; + char *path=yon_char_get_augumented(DesktopPath,de->d_name); + file=fopen(path,"r"); + if (strlen(de->d_name)>9) + { + char *extension=strstr(path,"."); + if (extension!=NULL) + { + if (strcmp(extension,".desktop")==0) + { + apps tempapp; + GKeyFile *gfile=g_key_file_new(); + GError *err=NULL; + g_key_file_load_from_file(gfile,path,G_KEY_FILE_KEEP_TRANSLATIONS,NULL); + char *Type=g_key_file_get_string(gfile,"Desktop Entry", "Type",&err); + if (err){ + printf("%s\n",err->message); + } + if (strcmp(Type,"Application")==0) tempapp.Type=1; else if (strcmp(Type,"pyApplication")==0) tempapp.Type=2; else continue; + tempapp.Name=g_key_file_get_locale_string(gfile,"Desktop Entry","Name",setlocale(LC_ALL,NULL),NULL); + if (tempapp.Name==NULL) continue; + tempapp.Categories=g_key_file_get_string(gfile,"Desktop Entry", "Categories",NULL); + if (tempapp.Categories==NULL) continue; + tempapp.Exec=g_key_file_get_string(gfile,"Desktop Entry", "Exec",NULL); + if (tempapp.Exec==NULL) continue; + tempapp.Icon=g_key_file_get_string(gfile,"Desktop Entry", "Icon",NULL); + if (tempapp.Icon==NULL) continue; + tempapp.Pluggable=g_key_file_get_boolean(gfile,"Desktop Entry", "Pluggable",NULL); + if (!tempapp.Pluggable) tempapp.Pluggable=g_key_file_get_boolean(gfile,"Desktop Entry", "X-XfcePluggable",NULL); + if (tempapp.Pluggable) tempapp.DualPluggable=g_key_file_get_boolean(gfile,"Desktop Entry", "X-UBLPluggable",NULL); + if (g_key_file_get_boolean(gfile,"Desktop Entry", "X-UBL-SettingsManager-Hidden",NULL)==0) + if (size==0){ + applist=(apps*)malloc(size+1*sizeof(apps)); + applist[0].Name=yon_char_new(tempapp.Name); + applist[0].Categories=yon_char_new(tempapp.Categories); + applist[0].Exec=yon_char_new(tempapp.Exec); + applist[0].Icon=yon_char_new(tempapp.Icon); + applist[0].Type=tempapp.Type; + applist[0].Pluggable=tempapp.Pluggable; + applist[0].DualPluggable=tempapp.DualPluggable; + size++; + } else { + applist=(apps*)realloc(applist,(size+1)*sizeof(apps)); + applist[size].Name=yon_char_new(tempapp.Name); + applist[size].Categories=yon_char_new(tempapp.Categories); + applist[size].Exec=yon_char_new(tempapp.Exec); + applist[size].Icon=yon_char_new(tempapp.Icon); + applist[size].Pluggable=tempapp.Pluggable; + applist[size].DualPluggable=tempapp.DualPluggable; + applist[size].Type=tempapp.Type; + size++; + } + } + } + } + } + } + *sizef=size; + return applist; +}; + + +void yon_apps_sort(apps *applist,int size){ + apps tmp; + if (size>2) + { + for (int i=1;icommand=path; + thread->exitcode=malloc(sizeof(int)); + pthread_t thread_id; + pthread_create(&thread_id, NULL, (void*)yon_launch, thread); + return *thread->exitcode; +}; + + +int yon_launch_app_with_arguments(char *name, char *args){ + char *path=yon_char_get_augumented("/usr/bin/",name); + path=yon_char_get_augumented(path," "); + path=yon_char_get_augumented(path,args); + pthread_t thread_id; + thread_output *thread=malloc(sizeof(thread_output)); + thread->command=path; + thread->exitcode=malloc(sizeof(int)); + pthread_create(&thread_id, NULL, (void*)yon_launch, thread); + return *thread->exitcode; +}; + + +int yon_launch(thread_output *thread){ + int a=0; + a=system(thread->command); + *thread->exitcode=a; + return *thread->exitcode; +} + + +//Gtk functions + +#ifdef __GTK_H__ + +// dictionary *yon_gtk_app_chooser_create(GtkBuilder *builder){ +// GtkWidget *chooserWindow=gtk_window_new(GTK_WINDOW_TOPLEVEL); +// GtkWidget *Box=gtk_box_new(GTK_ORIENTATION_VERTICAL,5); +// GtkWidget *Frame=gtk_frame_new(""); +// GtkWidget *Scroll=gtk_scrolled_window_new(NULL, gtk_adjustment_new(0,0,10000,1,10,100)); +// GtkWidget *PackBox=gtk_box_new(GTK_ORIENTATION_VERTICAL,5); +// GtkWidget *ButtonsBox=gtk_box_new(GTK_ORIENTATION_HORIZONTAL,5); +// GtkWidget *ButtonsPlaceBox=gtk_box_new(GTK_ORIENTATION_HORIZONTAL,5); + +// GtkWidget *CancelButton=gtk_button_new_with_label("Cancel"); +// GtkWidget *AcceptButton=gtk_button_new_with_label("Accept"); +// gtk_container_add(GTK_CONTAINER(chooserWindow),Box); +// gtk_box_pack_start(GTK_BOX(Box),Frame,1,1,0); +// gtk_container_add(GTK_CONTAINER(Frame),PackBox); +// gtk_box_pack_start(GTK_BOX(Box),ButtonsBox,0,0,0); +// gtk_box_pack_end(GTK_BOX(ButtonsBox),ButtonsPlaceBox,0,0,0); +// gtk_box_pack_end(GTK_BOX(ButtonsPlaceBox),AcceptButton,0,0,0); +// gtk_box_pack_end(GTK_BOX(ButtonsPlaceBox),CancelButton,0,0,0); +// gtk_box_pack_start(GTK_BOX(PackBox),(GtkWidget*)yon_gtk_app_chooser_apps_create(builder),0,0,0); +// gtk_widget_show_all(chooserWindow); +// } + +/** + * yon_iv_segment_create: + * connect_to - dictionary, in the end of which new one will be connected; + * name - name of this segment, renders on label; + * categories - desktop file categories that application NEEDS to have to render in that category; + * segment_icon_name - icon name for this section; + * builder - newly allocated builder with glade file connected where template widgets are stored: + * - templateAppsIconView - setted up icon view; + * - templateAppsPack - setted up container for every template widget; + * - templateAppsImage - image for rendering section image; + * - templateAppsLabel - label for rendering section name; +*/ +// dictionary *yon_iv_segment_create(dictionary *connect_to, char *name, char *categories, char *segment_icon_name){ +// IVSegment *segment=malloc(sizeof(IVSegment)); +// segment->name=name; +// segment->categories=categories; +// GtkBuilder *builder=gtk_builder_new_from_string(return_app_string(),-1); +// GtkWidget *iv=yon_gtk_builder_get_widget(builder,"templateAppsIconView"); +// GtkWidget *expander=yon_gtk_builder_get_widget(builder,"templateAppsPack"); +// GtkWidget *image=yon_gtk_builder_get_widget(builder,"templateAppsImage"); +// GtkWidget *label=yon_gtk_builder_get_widget(builder,"templateAppsLabel"); +// GtkIconTheme *theme=gtk_icon_theme_get_default(); +// gtk_image_set_from_pixbuf(GTK_IMAGE(image),gtk_icon_theme_load_icon_for_scale(theme,segment_icon_name,20,1,GTK_ICON_LOOKUP_FORCE_SVG,NULL)); +// gtk_label_set_text(GTK_LABEL(label),name); +// GtkListStore *ls=GTK_LIST_STORE(gtk_builder_get_object(builder,"liststore5")); +// // g_signal_connect(G_OBJECT(iv), "item-activated", G_CALLBACK(on_activate), videoconfig.applist); +// segment->Expander=expander; +// segment->IV=iv; +// segment->LS=ls; +// segment->Image=image; +// dictionary *dict=NULL; +// if (connect_to) { +// // connect_to=yon_dictionary_get_last(connect_to); +// dict=yon_dictionary_create_with_data_connected(connect_to,name,segment); +// } else +// dict=yon_dictionary_create_with_data(name,segment); +// return dict; +// } + +// GtkWidget *yon_gtk_app_chooser_apps_create(){ +// GtkWidget *Box=gtk_box_new(GTK_ORIENTATION_VERTICAL,0); +// dictionary *IVS=yon_iv_segment_create(NULL, "Graphics", "", "dialog-yes-symbolic"); +// yon_iv_segment_create(IVS, "Tools", "", "dialog-yes-symbolic"); +// yon_iv_segment_create(IVS, "Internet", "", "dialog-yes-symbolic"); +// yon_iv_segment_create(IVS, "Multimedia", "", "dialog-yes-symbolic"); +// yon_iv_segment_create(IVS, "Settings", "", "dialog-yes-symbolic"); +// yon_iv_segment_create(IVS, "Education", "", "dialog-yes-symbolic"); +// yon_iv_segment_create(IVS, "Office", "", "dialog-yes-symbolic"); +// yon_iv_segment_create(IVS, "Other", "", "dialog-yes-symbolic"); +// yon_iv_segment_create(IVS, "Development", "", "dialog-yes-symbolic"); +// yon_iv_segment_create(IVS, "System", "", "dialog-yes-symbolic"); +// dictionary *nd; +// for_dictionaries(nd,IVS){ +// gtk_box_pack_start(GTK_BOX(Box),((IVSegment*)nd->data)->Expander,0,0,0); +// } +// return Box; + +// } + +// GtkWidget *yon_gtk_socket_create_new_with_connect(GtkWidget *container, gpointer data){ +// GtkWidget *socket; +// socket = gtk_socket_new(); +// g_signal_connect(G_OBJECT(socket),"plug-added",G_CALLBACK(yon_on_plug_added),data); +// g_signal_connect(G_OBJECT(socket),"plug-removed",G_CALLBACK(yon_on_plug_removed),data); +// g_signal_connect(G_OBJECT(socket),"destroy",G_CALLBACK(yon_on_plug_removed),data); +// gtk_box_pack_start(GTK_BOX(container),socket,1,1,0); +// return socket; +// }; + +int yon_dictionary_gtk_pack_start_multiple_widgets(dictionary *dict, GtkWidget *destination, gboolean expand, gboolean fill, int padding){ + for (dictionary *dct=dict->first; dct!=NULL;dct=dct->next){ + gtk_box_pack_start(GTK_BOX(destination),(GtkWidget*)dct->data,expand,fill,padding); + } + return 1; +} + +int yon_dictionary_gtk_pack_end_multiple_widgets(dictionary *dict, GtkWidget *destination, gboolean expand, gboolean fill, int padding){ + for (dictionary *dct=dict->first; dct!=NULL;dct=dct->next){ + gtk_box_pack_end(GTK_BOX(destination),(GtkWidget*)dct->data,expand,fill,padding); + } + return 1; +} + +void _yon_ubl_header_setup(GtkWidget *Overlay, GtkWidget *Head, GtkWidget *Image, char *image_path){ + gtk_overlay_add_overlay(GTK_OVERLAY(Overlay),Head); + gtk_image_set_from_file(GTK_IMAGE(Image),image_path); +} + +void _yon_ubl_status_box_render(GtkWidget *StatusBox, GtkWidget *StatusIcon, GtkWidget *StatusLabel, char *IconName, char* StatusText, BACKGROUND_IMAGE_TYPE BackgroundClass){ + GtkIconTheme *ictheme=gtk_icon_theme_get_default(); + GError *err=NULL; + gtk_image_set_from_pixbuf(GTK_IMAGE(StatusIcon),gtk_icon_theme_load_icon_for_scale(ictheme,IconName,25,1,GTK_ICON_LOOKUP_FORCE_SIZE,&err)); + if (err){ + printf("%s\n",err->message); + g_error_free(err); + } + gtk_label_set_text(GTK_LABEL(StatusLabel),StatusText); + if (BackgroundClass==BACKGROUND_IMAGE_SUCCESS_TYPE){ + gtk_style_context_add_class(gtk_widget_get_style_context(StatusBox),"boxInfoMessOK"); + } else if (BackgroundClass==BACKGROUND_IMAGE_FAIL_TYPE){ + gtk_style_context_add_class(gtk_widget_get_style_context(StatusBox),"boxInfoMessError"); + } +} +#endif \ No newline at end of file diff --git a/source/ubl-utils.h b/source/ubl-utils.h new file mode 100644 index 0000000..444fd93 --- /dev/null +++ b/source/ubl-utils.h @@ -0,0 +1,164 @@ +#ifndef UBL_UTILS +#define UBL_UTILS +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DesktopPath "/usr/share/applications/" + +#define for_dictionaries(obj,obj1) for(obj=obj1->first;obj!=NULL;obj=obj->next) + +typedef enum { + DICTIONARY_ACTION_WIDGETS_TYPE, + DICTIONARY_IVGRAPHICALS_TYPE, + DICTIONARY_OTHER_TYPE + +} DICT_TYPE; + + +typedef struct { + char *command; + int *exitcode; +} thread_output; + +typedef struct dictionary { + char *key; + void *data; + struct dictionary *next; + struct dictionary *prev; + struct dictionary *first; + DICT_TYPE data_type; +} dictionary; + +typedef struct apps{ + char *Name; + int Type; + char *Categories; + char *Exec; + char *Icon; + int Pluggable; + int DualPluggable; + } apps; + + +//dictionary functions + +dictionary *yon_dictionary_create_empty(); + +dictionary * yon_dictionary_create_conneced(dictionary *targetdict); + +dictionary *yon_dictionary_get_last(dictionary *dict); + +dictionary *yon_dictionary_switch_places(dictionary *dict,int aim); + +void yon_dictionary_make_first(dictionary *dict); + +void yon_dictionary_make_nth(dictionary *dict, int nth); + +dictionary *yon_dictionary_create_with_data(char *key, void *data); + +dictionary *yon_dictionary_create_with_data_connected(dictionary *dict, char *key, void *data); + +dictionary *yon_dictionary_connect(dictionary *old, dictionary *toconnect); + +dictionary *yon_dictionary_find(dictionary **dict, char *key); + +dictionary *yon_dictionary_rip(dictionary *dict); + +dictionary *yon_dictionary_get_nth(dictionary *dict, int place); + +//char functions + +char *yon_char_get_augumented(char *source, char *append); + +char *yon_char_new(char *chr); + +char *yon_cut(char *source, int size, int startpos); + +char *yon_char_divide(char *source, int dividepos); + +char *yon_char_divide_search(char *source, char* dividepos, int delete_divider); + +char *yon_char_from_int(int int_to_convert); + + + +//parsing functions + +apps *yon_apps_scan_and_parse_desktops(int *sizef); + + +void yon_apps_sort(apps *applist,int size); + + +apps *yon_apps_get_by_name(apps *applist,char *name, int size); + + +//terminal-using functions + + + +int yon_launch_app(char *name); + + +int yon_launch_app_with_arguments(char *name, char *args); + + +int yon_launch(thread_output *thread); + +//Gtk functions + +#ifdef __GTK_H__ + +#define yon_gtk_builder_get_widget(obj,obj2) GTK_WIDGET(gtk_builder_get_object(obj,obj2)) + + +typedef struct { + GtkWidget *Icon; + GtkWidget *Label; + GtkWidget *IconView; + GtkListStore *List; +} expander_icon_view; + + +// GtkWidget *yon_gtk_app_chooser_apps_create(); + +// dictionary *yon_gtk_app_chooser_create(); + +// expander_icon_view yon_gtk_icon_view_expander_create(GtkWidget *pack, ...); + +GtkWidget *yon_gtk_socket_create_new_with_connect(GtkWidget *container, gpointer data); + +int yon_gtk_icon_view_hide_empty(dictionary *icon_view_segment); + +int yon_dictionary_gtk_pack_start_multiple_widgets(dictionary *dict, GtkWidget *destination, gboolean expand, gboolean fill, int padding); +int yon_dictionary_gtk_pack_end_multiple_widgets(dictionary *dict, GtkWidget *destination, gboolean expand, gboolean fill, int padding); + +//uninitialised + +void yon_on_plug_added(GtkSocket* self, gpointer user_data); +void yon_on_plug_removed(GtkSocket* self, gpointer user_data); + + +#endif +typedef enum { + BACKGROUND_IMAGE_SUCCESS_TYPE, + BACKGROUND_IMAGE_FAIL_TYPE +} BACKGROUND_IMAGE_TYPE; +#ifdef __cplusplus +#define yon_ubl_header_setup(overlay,head,image,imag_path) _yon_ubl_header_setup(GTK_WIDGET(overlay.gobj()),GTK_WIDGET(head.gobj()),GTK_WIDGET(image.gobj()),(char*)imag_path) +#define yon_ubl_status_box_render(statusbox, statusicon, statuslabel, iconname, statustext, backgroundclass) _yon_ubl_status_box_render(GTK_WIDGET(statusbox.gobj()), GTK_WIDGET(statusicon.gobj()), GTK_WIDGET(statuslabel.gobj()), (char*)iconname, (char*)statustext, backgroundclass) +#else +#define yon_ubl_header_setup(overlay,head,image,imag_path) _yon_ubl_header_setup(GTK_WIDGET(overlay),GTK_WIDGET(head),GTK_WIDGET(image), (char*)imag_path) +#define yon_ubl_status_box_render(statusbox, statusicon, statuslabel, iconname, statustext, backgroundclass) _yon_ubl_status_box_render(statusbox, statusicon, statuslabel, iconname, statustext, backgroundclass) +#endif + +void _yon_ubl_header_setup(GtkWidget *Overlay, GtkWidget *Head, GtkWidget *Image, char *image_path); +void _yon_ubl_status_box_render(GtkWidget *StatusBox, GtkWidget *StatusIcon, GtkWidget *StatusLabel, char *IconName, char* StatusText, BACKGROUND_IMAGE_TYPE BackgroundClass); +#endif \ No newline at end of file diff --git a/ubl-settings-usergroups-banner.png b/ubl-settings-usergroups-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..8eb67cbc38babeaf498d981356cf7e77e2741f12 GIT binary patch literal 33872 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.0 Copyright © 2023 - UBSoft Software LLC Settings for users and groups - https://ublinux.ru/ + https://wiki.ublinux.ru/ru/Программное_обеспечение/Программы_и_утилиты/Все/ubl-settings-usergroups Project Home Page Это приложение распространяется без каких-либо гарантий. Подробнее в <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GNU General Public License, версии 2 или позднее</a>. @@ -120,17 +120,6 @@ 0 - - - True - False - - - False - True - 1 - - True @@ -172,7 +161,9 @@ False process-stop-symbolic - + + 450 + 250 False True com.ublinux.ubl-settings-usergroups @@ -192,7 +183,7 @@ False 5 - + True False UID @@ -205,7 +196,7 @@ - + True True 1000 @@ -229,7 +220,7 @@ False 5 - + True False Username @@ -242,7 +233,7 @@ - + True True @@ -265,7 +256,7 @@ False 5 - + True False Login @@ -278,7 +269,7 @@ - + True True @@ -301,7 +292,7 @@ False 5 - + True False Password @@ -314,7 +305,7 @@ - + True True @@ -332,11 +323,12 @@ - + Default password True True False + 0 True @@ -351,7 +343,7 @@ False 5 - + True False Password hash algorythm @@ -364,7 +356,7 @@ - + True False @@ -382,11 +374,12 @@ - + Sync with SAMBA user True True False + 0 True @@ -411,7 +404,7 @@ 5 True - + Cancel True True @@ -425,7 +418,7 @@ - + Add True True @@ -459,10 +452,10 @@ - - - - + + + + @@ -485,7 +478,9 @@ - + + 300 + 400 False True com.ublinux.ubl-settings-usergroups @@ -495,7 +490,7 @@ False vertical - + True True liststore2 @@ -503,7 +498,7 @@ - + Enabled @@ -514,7 +509,7 @@ - + Group @@ -526,7 +521,7 @@ - False + True True 0 @@ -542,8 +537,8 @@ 5 True - - button + + Cancel True True True @@ -555,8 +550,8 @@ - - button + + Ok True True True @@ -582,7 +577,7 @@ True False - + True False Load from global configuration @@ -590,7 +585,7 @@ - + True False Load from local configuration @@ -602,7 +597,7 @@ True False - + True False Save to global and local configuration @@ -610,7 +605,7 @@ - + True False Save to global configuration @@ -618,7 +613,7 @@ - + True False Save to local configuration @@ -630,7 +625,7 @@ True False - + True False Documentation @@ -638,7 +633,7 @@ - + True False About @@ -761,6 +756,7 @@ True False + 5 True @@ -768,10 +764,11 @@ vertical 5 - + True False User groups (default) + True 0 @@ -781,10 +778,11 @@ - + True False User name + True 0 @@ -794,10 +792,11 @@ - + True False User password + True 0 @@ -807,10 +806,11 @@ - + True False Password hash algorythm: + True 0 @@ -820,10 +820,11 @@ - + True False Autologin + True 0 @@ -833,10 +834,11 @@ - + True False Update HOME directory(ies) + True 0 @@ -846,10 +848,11 @@ - + True False Automatically load user programs + True 0 @@ -877,7 +880,7 @@ False 5 - + True True @@ -888,7 +891,7 @@ - + True True True @@ -916,7 +919,7 @@ False 5 - + Administrator True True @@ -930,7 +933,7 @@ - + True True @@ -948,7 +951,7 @@ - + True True @@ -959,7 +962,7 @@ - + True False @@ -970,7 +973,7 @@ - + True False @@ -981,7 +984,7 @@ - + Enabled True True @@ -996,7 +999,7 @@ - + True True @@ -1032,10 +1035,11 @@ False 5 - + True False User string: + True False @@ -1044,7 +1048,7 @@ - + True True @@ -1067,7 +1071,7 @@ False 5 - + True True liststore1 @@ -1075,22 +1079,22 @@ - + UID - + Login - + Password - + User Name @@ -1105,10 +1109,11 @@ True False + center vertical 5 - + True True True @@ -1124,7 +1129,7 @@ - + True True True @@ -1140,7 +1145,7 @@ - + True True True @@ -1164,14 +1169,14 @@ - False + True True 1 - False + True True 1 @@ -1371,20 +1376,20 @@ vertical - - - - - - - + + + + + + + - - - - - + + + + + diff --git a/ubl-settings-usergroups.pot b/ubl-settings-usergroups.pot new file mode 100644 index 0000000..196db4c --- /dev/null +++ b/ubl-settings-usergroups.pot @@ -0,0 +1,114 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-04-06 09:45+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: source/ubl-settings-usergroups.c:50 +msgid "User groups (default)" +msgstr "" + +#: source/ubl-settings-usergroups.c:51 +msgid "User name" +msgstr "" + +#: source/ubl-settings-usergroups.c:52 +msgid "Administrator" +msgstr "" + +#: source/ubl-settings-usergroups.c:53 +msgid "User password" +msgstr "" + +#: source/ubl-settings-usergroups.c:54 +msgid "Password hash algorythm" +msgstr "" + +#: source/ubl-settings-usergroups.c:55 +msgid "Autologin" +msgstr "" + +#: source/ubl-settings-usergroups.c:56 +msgid "Update HOME directory(ies)" +msgstr "" + +#: source/ubl-settings-usergroups.c:57 +msgid "Enabled" +msgstr "" + +#: source/ubl-settings-usergroups.c:58 +msgid "Automatically load user programs" +msgstr "" + +#: source/ubl-settings-usergroups.c:59 +msgid "User string" +msgstr "" + +#: source/ubl-settings-usergroups.c:60 +msgid "UID" +msgstr "" + +#: source/ubl-settings-usergroups.c:61 +msgid "Login" +msgstr "" + +#: source/ubl-settings-usergroups.c:62 +msgid "Password" +msgstr "" + +#: source/ubl-settings-usergroups.c:63 +msgid "User Name" +msgstr "" + +#: source/ubl-settings-usergroups.c:64 +msgid "Load from global configuration" +msgstr "" + +#: source/ubl-settings-usergroups.c:65 +msgid "Load from local configuration" +msgstr "" + +#: source/ubl-settings-usergroups.c:66 +msgid "Save to global and local configuration" +msgstr "" + +#: source/ubl-settings-usergroups.c:67 +msgid "Save to global configuration" +msgstr "" + +#: source/ubl-settings-usergroups.c:68 +msgid "Save to local configuration" +msgstr "" + +#: source/ubl-settings-usergroups.c:69 +msgid "Documentation" +msgstr "" + +#: source/ubl-settings-usergroups.c:70 +msgid "About" +msgstr "" + +#: source/ubl-settings-usergroups.c:71 +msgid "Load" +msgstr "" + +#: source/ubl-settings-usergroups.c:72 +msgid "Users and groups" +msgstr "" + +#: source/ubl-settings-usergroups.c:73 +msgid "Save" +msgstr "" diff --git a/ubl-settings-usergroups_ru.po b/ubl-settings-usergroups_ru.po new file mode 100644 index 0000000..f65b721 --- /dev/null +++ b/ubl-settings-usergroups_ru.po @@ -0,0 +1,121 @@ +# Language translations for ubl-settings-manager package. +# Copyright (C) 2022, UBTech LLC +# This file is distributed under the same license as the ubl-settings-manager package. +# UBLinux Team , 2022 +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: ubl-settings-manager 1.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-04-06 09:45+0000\n" +"PO-Revision-Date: 2023-01-01 00:00+0600\n" +"Last-Translator: UBLinux Team \n" +"Language-Team: UBLinux Team \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: source/ubl-settings-usergroups.c:50 +#, fuzzy +msgid "User groups (default)" +msgstr "Группы пользователей (По умолчанию)" + +#: source/ubl-settings-usergroups.c:51 +#, fuzzy +msgid "User name" +msgstr "Имя пользователя" + +#: source/ubl-settings-usergroups.c:52 +msgid "Administrator" +msgstr "Администратор" + +#: source/ubl-settings-usergroups.c:53 +#, fuzzy +msgid "User password" +msgstr "Пароль пользователя" + +#: source/ubl-settings-usergroups.c:54 +#, fuzzy +msgid "Password hash algorythm" +msgstr "Алгоритм хэширования пароля" + +#: source/ubl-settings-usergroups.c:55 +#, fuzzy +msgid "Autologin" +msgstr "Автоматический логин пользователя" + +#: source/ubl-settings-usergroups.c:56 +msgid "Update HOME directory(ies)" +msgstr "Обновлять каталог(и) HOME" + +#: source/ubl-settings-usergroups.c:57 +msgid "Enabled" +msgstr "Включено" + +#: source/ubl-settings-usergroups.c:58 +#, fuzzy +msgid "Automatically load user programs" +msgstr "Автозагрузка программ пользователей" + +#: source/ubl-settings-usergroups.c:59 +#, fuzzy +msgid "User string" +msgstr "Строка пользователей" + +#: source/ubl-settings-usergroups.c:60 +msgid "UID" +msgstr "UID" + +#: source/ubl-settings-usergroups.c:61 +msgid "Login" +msgstr "Логин" + +#: source/ubl-settings-usergroups.c:62 +msgid "Password" +msgstr "Пароль" + +#: source/ubl-settings-usergroups.c:63 +msgid "User Name" +msgstr "Имя пользователя" + +#: source/ubl-settings-usergroups.c:64 +msgid "Load from global configuration" +msgstr "Загрузить из глобальной конфигурации" + +#: source/ubl-settings-usergroups.c:65 +msgid "Load from local configuration" +msgstr "Загрузить из локальной конфигурации" + +#: source/ubl-settings-usergroups.c:66 +msgid "Save to global and local configuration" +msgstr "Сохранить в глобальную и локальную конфигурации" + +#: source/ubl-settings-usergroups.c:67 +msgid "Save to global configuration" +msgstr "Сохранить в глобальную конфигурацию" + +#: source/ubl-settings-usergroups.c:68 +msgid "Save to local configuration" +msgstr "Сохранить в локальную конфигурацию" + +#: source/ubl-settings-usergroups.c:69 +msgid "Documentation" +msgstr "Справка" + +#: source/ubl-settings-usergroups.c:70 +msgid "About" +msgstr "О программе" + +#: source/ubl-settings-usergroups.c:71 +msgid "Load" +msgstr "Загрузить" + +#: source/ubl-settings-usergroups.c:72 +msgid "Users and groups" +msgstr "Пользователи и группы" + +#: source/ubl-settings-usergroups.c:73 +msgid "Save" +msgstr "Сохранить" From 59d75a05fa7b6053226fbb15838ad7665a2e9443 Mon Sep 17 00:00:00 2001 From: Ivan Yarcev Date: Thu, 22 Jun 2023 16:34:39 +0600 Subject: [PATCH 2/2] Updated to current templated version --- .gitignore | 10 +- Makefile | 35 +- README.md | 5 +- VERSION.md | 1 - com.ublinux.ubl-settings-usergroups.policy | 24 + gresource.xml | 14 + source/CMakeLists.txt | 75 +- source/ubl-cmake.in | 1 + source/ubl-settings-usergroups.c | 409 +++-- source/ubl-settings-usergroups.h | 171 +- source/ubl-strings.h | 61 + source/ubl-utils.c | 1918 +++++++++++++++----- source/ubl-utils.h | 297 ++- ubl-settings-usergroups | Bin 0 -> 247544 bytes ubl-settings-usergroups-group.glade | 292 +++ ubl-settings-usergroups-user.glade | 412 +++++ ubl-settings-usergroups.css | 225 +-- ubl-settings-usergroups.desktop | 14 +- ubl-settings-usergroups.glade | 1188 +++++------- ubl-settings-usergroups.pot | 248 ++- ubl-settings-usergroups_ru.po | 292 ++- 21 files changed, 4020 insertions(+), 1672 deletions(-) delete mode 100644 VERSION.md create mode 100644 com.ublinux.ubl-settings-usergroups.policy create mode 100644 gresource.xml create mode 100644 source/ubl-cmake.in create mode 100644 source/ubl-strings.h create mode 100755 ubl-settings-usergroups create mode 100644 ubl-settings-usergroups-group.glade create mode 100644 ubl-settings-usergroups-user.glade diff --git a/.gitignore b/.gitignore index 5706090..ed27715 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ .vscode/ -ubl-settings-usergroups.glade~ -ubl-settings-usergroups \ No newline at end of file +ubl-settings-TEMPLATE +*~ +build/ +compile/ +*# +terminal-commands/ +source/ubl-cmake.h +vgcore* \ No newline at end of file diff --git a/Makefile b/Makefile index 89d234d..07ba802 100644 --- a/Makefile +++ b/Makefile @@ -10,22 +10,25 @@ CMAKE_SOURCE_DIR = $(MAKEFILE_PATH)source CMAKE_BUILD_DIR = $(MAKEFILE_PATH)compile #CMAKE_SOURCE_DIR = ./source #CMAKE_BUILD_DIR = ./compile -FILE_VERSION = VERSION.md DEPENDS = /bin/cmake PREFIX ?= /usr PKGNAME = $(MAKEFILE_DIR) #PKGNAME = ubl-settings-manager - +LATEST_TAG= default_target: all -.PHONY: all init depend debug prepare check build uninstall install clean up_ver help +.PHONY: all init depend debug prepare check build uninstall install clean help all: init build init: @echo "Initialize ..."; \ - sed -r "s/(version_application = ).*/\1\"$$(grep 'VERSION' ${FILE_VERSION} | cut -d" " -f2)\";/" -i source/ubl-settings-usergroups.h; \ - gcc source/ubl-settings-usergroups.c source/ubl-utils.c -o ubl-settings-usergroups `pkg-config --cflags --libs gtk+-3.0` -g; \ + if [ -d ".git" ]; then \ + LATEST_TAG=$$(git describe --tags | sed 's/^v//'|grep -oE "^[0-9]{1,}.[0-9]{1,}"); \ + else \ + LATEST_TAG="0.0"; \ + fi; \ + sed -r "s/^(string version_application).*/\1=\"$${LATEST_TAG}\";/" -i source/${PKGNAME}.h; \ echo "-- Build path: ${CMAKE_BUILD_DIR}" depend: @@ -39,11 +42,13 @@ depend: echo "Check depends: OK" # $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 -debug: - @echo "Debug ..." +debug: init build + @echo "Debug ..."; \ if [ ! -d ${CMAKE_BUILD_DIR} ]; then \ $(CMAKE_COMMAND) -S${CMAKE_SOURCE_DIR} -B${CMAKE_BUILD_DIR} -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="${PREFIX}"; \ fi; \ + echo "${CMAKE_BUILD_DIR}/${PKGNAME}"; \ + cp ${CMAKE_BUILD_DIR}/${PKGNAME} ./; \ echo "Debug: OK" prepare: @@ -87,7 +92,9 @@ uninstall: @$(RM) "${DESTDIR}${PREFIX}/bin/${PKGNAME}" @$(RM) "${DESTDIR}${PREFIX}/share/applications/${PKGNAME}.desktop" @$(RM) "${DESTDIR}${PREFIX}/share/icons/hicolor/scalable/apps/com.ublinux.${PKGNAME}.svg" - @$(RM) -rd "${DESTDIR}${PREFIX}/share/${PKGNAME}" + @$(RM) "${DESTDIR}${PREFIX}/share/icons/hicolor/scalable/apps/com.ublinux.${PKGNAME}.checked.svg" + @$(RM) "${DESTDIR}${PREFIX}/share/icons/hicolor/scalable/apps/com.ublinux.${PKGNAME}.warning.svg" + @$(RM) "${DESTDIR}${PREFIX}/share/polkit-1/actions/com.ublinux.${PKGNAME}.policy" @if [ -z ${DESTDIR} ]; then \ [ -d "${DESTDIR}${PREFIX}/share/icons/hicolor/" ] && gtk-update-icon-cache -fiq "${DESTDIR}${PREFIX}/share/icons/hicolor/" &>/dev/null || true; \ update-desktop-database --quiet &>/dev/null || true; \ @@ -97,6 +104,9 @@ uninstall: install: check uninstall @echo "Install ..." +#################################################### УДАЛИТЬ ПЕРЕД КОММИТОМ ################################################################################ + @gcc source/ubl-cmake.h compile/resources.c compile/ubl-cmake.h source/ubl-settings-usergroups.c source/ubl-settings-usergroups.h source/ubl-strings.h source/ubl-utils.c source/ubl-utils.h -o ubl-settings-usergroups `pkg-config --cflags --libs gtk+-3.0 vte-2.91 webkit2gtk-4.0 webkit2gtk-web-extension-4.0` -g +#################################################### УДАЛИТЬ ПЕРЕД КОММИТОМ ################################################################################ @for FILE_PO in $(wildcard *.po); do \ LANG=$${FILE_PO##*_};LANG=$${LANG%.*}; \ install -dm755 "${DESTDIR}${PREFIX}/share/locale/$${LANG}/LC_MESSAGES"; \ @@ -111,20 +121,21 @@ install: check uninstall done @install -dm755 "${DESTDIR}${PREFIX}/share/icons/hicolor/scalable/apps" @install -Dm644 -t "${DESTDIR}${PREFIX}/share/icons/hicolor/scalable/apps/" "com.ublinux.${PKGNAME}.svg" + @install -dm755 "${DESTDIR}${PREFIX}/share/polkit-1/actions" + @install -Dm644 -t "${DESTDIR}${PREFIX}/share/polkit-1/actions/" "com.ublinux.${PKGNAME}.policy" @install -Dm755 -t "${DESTDIR}${PREFIX}/bin/" "${CMAKE_BUILD_DIR}/${PKGNAME}" @install -dm755 "${DESTDIR}/etc/xdg" @install -dm755 "${DESTDIR}${PREFIX}/share/applications" @install -Dm644 -t "${DESTDIR}${PREFIX}/share/applications/" "${PKGNAME}.desktop" - @install -dm755 "${DESTDIR}${PREFIX}/share/${PKGNAME}"/{ui,css,images} - @install -Dm644 -t "${DESTDIR}${PREFIX}/share/${PKGNAME}/ui/" "${PKGNAME}.glade" - @install -Dm644 -t "${DESTDIR}${PREFIX}/share/${PKGNAME}/ui/" "${PKGNAME}-banner.png" - @install -Dm644 -t "${DESTDIR}${PREFIX}/share/${PKGNAME}/css/" "${PKGNAME}.css" + @install -Dm644 -t "${DESTDIR}${PREFIX}/share/icons/hicolor/scalable/status/" "com.ublinux.${PKGNAME}.checked.svg" + @install -Dm644 -t "${DESTDIR}${PREFIX}/share/icons/hicolor/scalable/status/" "com.ublinux.${PKGNAME}.warning.svg" @if [ -z ${DESTDIR} ]; then \ [ -d "${DESTDIR}${PREFIX}/share/icons/hicolor/" ] && gtk-update-icon-cache -fiq "${DESTDIR}${PREFIX}/share/icons/hicolor/" &>/dev/null || true; \ update-desktop-database --quiet &>/dev/null || true; \ [ -d "${DESTDIR}${PREFIX}/share/applications" ] && touch "${DESTDIR}${PREFIX}/share/applications" &>/dev/null || true; \ fi @echo "Install: OK" + @sed -r "s/^(string version_application=\"*\").*/string version_application;/" -i source/${PKGNAME}.h; \ clean: @echo "Clean ..." diff --git a/README.md b/README.md index 23810ff..006bbe3 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ -# ubl-settings-usergroups +# ubl-ubl-settings-usergroups # Выполнить # Build -In order to build ubl-settings-manager you will need: +In order to build ubl-ubl-settings-usergroups you will need: - CMake - C compiler - GTK+ 3 & dependencies +- webkit2gtk (optional) Once you have all the necessary dependencies, you can use: ```sh diff --git a/VERSION.md b/VERSION.md deleted file mode 100644 index 31c5941..0000000 --- a/VERSION.md +++ /dev/null @@ -1 +0,0 @@ -VERSION 1.2 diff --git a/com.ublinux.ubl-settings-usergroups.policy b/com.ublinux.ubl-settings-usergroups.policy new file mode 100644 index 0000000..087a6b3 --- /dev/null +++ b/com.ublinux.ubl-settings-usergroups.policy @@ -0,0 +1,24 @@ + + + + + UBLinux + https://ublinux.ru + + + Run ubl-ubl-settings-usergroups as root + Запуск утилиты ubl-ubl-settings-usergroups с правами root + Authentication is required to run ubl-ubl-settings-usergroups + Требуется авторизация для запуска утилиты ubl-ubl-settings-usergroups с правами root + + auth_admin + auth_admin + auth_admin + + /usr/bin/ubl-ubl-settings-usergroups + true + + + diff --git a/gresource.xml b/gresource.xml new file mode 100644 index 0000000..09b2fec --- /dev/null +++ b/gresource.xml @@ -0,0 +1,14 @@ + + + + ubl-settings-usergroups.glade + ubl-settings-usergroups-group.glade + ubl-settings-usergroups-user.glade + + + ubl-settings-usergroups.css + + + ubl-settings-usergroups-banner.png + + \ No newline at end of file diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index d891c96..56e4492 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -8,24 +8,91 @@ include_directories(${GTK_INCLUDE_DIRS}) link_directories(${GTK_LIBRARY_DIRS}) add_definitions(${GTK_CFLAGS_OTHER}) +#pkg_check_modules(VTE291 REQUIRED vte-2.91) +#include_directories(${VTE291_INCLUDE_DIRS}) +#link_directories(${VTE291_LIBRARY_DIRS}) +#add_definitions(${VTE291_CFLAGS_OTHER}) + +find_library(WEBKIT_LIBRARIES_FOUND webkit2gtk-4.0 webkit2gtk-web-extension-4.0) + +option(WEBKIT_FOUND "No" OFF) +if(WEBKIT_LIBRARIES_FOUND) + option(WEBKIT_FOUND "Yes" ON) + PKG_CHECK_MODULES(WEBKIT REQUIRED webkit2gtk-4.0 webkit2gtk-web-extension-4.0) + include_directories(${WEBKIT_INCLUDE_DIRS}) + link_directories(${WEBKIT_LIBRARY_DIRS}) + add_definitions(${WEBKIT_CFLAGS_OTHER}) +endif() + +configure_file(ubl-cmake.in ubl-cmake.h) + +file(COPY ${CMAKE_CURRENT_BINARY_DIR}/ubl-cmake.h DESTINATION ./) + +set(GRESOURCE_C resources.c) +set(GRESOURCE_XML gresource.xml) + +find_program(GLIB_COMPILE_RESOURCES NAMES glib-compile-resources REQUIRED) +add_custom_target(GLADE ubl-settings-usergroups.glade) + +set(DEPENDFILES + ../ubl-settings-usergroups.glade + ../ubl-settings-usergroups-user.glade + ../ubl-settings-usergroups-group.glade + ../gresource.xml + ../ubl-settings-usergroups-banner.png + ../ubl-settings-usergroups.css + ) + +file(COPY ${DEPENDFILES} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +add_custom_command( + OUTPUT ${GRESOURCE_C} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${GLIB_COMPILE_RESOURCES} + ARGS + --generate-source + --target=${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} + ${GRESOURCE_XML} + VERBATIM + MAIN_DEPENDENCY ${GRESOURCE_XML} + DEPENDS + ${GLADE} +) +add_custom_target( + dummy-resource + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} +) + #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wextra -Werror -Wmissing-declarations -fdiagnostics-color=always -std=c++2a") #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wextra -Werror -Wmissing-declarations -fdiagnostics-color=always -lm") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wextra -Werror -Wmissing-declarations -fdiagnostics-color=always \ -O2 -pipe -fno-plt -fexceptions \ -Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security \ -fstack-clash-protection -fcf-protection") + set(SOURCE_FILES ubl-settings-usergroups.c ubl-settings-usergroups.h + ubl-strings.h + ubl-utils.h ubl-utils.c - ubl-utils.h) + ${CMAKE_CURRENT_BINARY_DIR}/ubl-cmake.h + ) set(LIBRARIES ${GTK_LIBRARIES} + ${WEBKIT_LIBRARIES} +# ${VTE291_LIBRARIES} pthread) -add_executable(ubl-settings-usergroups ${SOURCE_FILES}) -target_link_libraries(ubl-settings-usergroups ${LIBRARIES}) -install(TARGETS ubl-settings-usergroups DESTINATION bin) \ No newline at end of file +add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C}) +target_link_libraries(${PROJECT_NAME} PUBLIC ${LIBRARIES}) +target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR}) +set_source_files_properties( + ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} + PROPERTIES GENERATED TRUE +) +install(TARGETS ${PROJECT_NAME} DESTINATION bin) +add_dependencies(${PROJECT_NAME} dummy-resource) \ No newline at end of file diff --git a/source/ubl-cmake.in b/source/ubl-cmake.in new file mode 100644 index 0000000..d4623a7 --- /dev/null +++ b/source/ubl-cmake.in @@ -0,0 +1 @@ +#cmakedefine WEBKIT_FOUND diff --git a/source/ubl-settings-usergroups.c b/source/ubl-settings-usergroups.c index 71a0ed8..ee77d87 100644 --- a/source/ubl-settings-usergroups.c +++ b/source/ubl-settings-usergroups.c @@ -1,131 +1,324 @@ -#include #include "ubl-settings-usergroups.h" +config main_config; + +//signal emmit handlers - no header initialization + +/**on_close_subwindow(GtkWidget *self) + * [EN] + * Closes window in which [self] is contained. + * [RU] + * Закрывает окно, в котором расположен виджет [self]. +*/ void on_close_subwindow(GtkWidget *self){ gtk_widget_destroy(gtk_widget_get_toplevel(self)); } -void on_about_open(){ +/**yon_open_browser(GtkWidget *self, char *link) + * [EN] + * Opens browser with [link] link. + * [RU] + * Открывает браузер с [link] ссылкой. +*/ +void yon_open_browser(GtkWidget *self, char *link){ + yon_ubl_browser_window_open(link,TITLE_LABEL); +} +/**on_open_documentation_confirmation(GtkWidget *self, char *link) + * [EN] + * Opens confirmation window for [link] link. + * [RU] + * Открывает окно подтверждение перехода по ссылке [link]. +*/ +void on_open_documentation_confirmation(GtkWidget *self, char *link){ + if (main_config.always_open_documentation==0){ + GtkBuilder *builder = gtk_builder_new_from_resource(glade_path); + documentation_confirmation_window *widgets = malloc(sizeof(documentation_confirmation_window)); + widgets->Window = yon_gtk_builder_get_widget(builder,"helpConfirmationWindow"); + widgets->AcceptButton = yon_gtk_builder_get_widget(builder,"ReadHelpButton"); + widgets->CloseButton = yon_gtk_builder_get_widget(builder,"CancelHelpButton"); + widgets->HatText = yon_gtk_builder_get_widget(builder,"webHeaderNameLabel"); + widgets->HeaderText = yon_gtk_builder_get_widget(builder,"helpHeader"); + widgets->InfoText = yon_gtk_builder_get_widget(builder,"helpText"); + widgets->AlwaysOpenCheck = yon_gtk_builder_get_widget(builder,"AlwaysOpenDocumentationCheckbox"); + gtk_label_set_text(GTK_LABEL(widgets->HatText),TITLE_LABEL); + gtk_label_set_text(GTK_LABEL(widgets->HeaderText),HELP_TITLE_LABEL); + gtk_label_set_text(GTK_LABEL(widgets->InfoText),HELP_INFO_LABEL); + gtk_button_set_label(GTK_BUTTON(widgets->AcceptButton),OPEN_HELP_LABEL); + gtk_button_set_label(GTK_BUTTON(widgets->AlwaysOpenCheck),HELP_ALWAYS_OPEN_LABEL); + gtk_button_set_label(GTK_BUTTON(widgets->CloseButton),CANCEL_LABEL); + gtk_widget_show_all(widgets->Window); + g_signal_connect(G_OBJECT(widgets->CloseButton),"clicked",G_CALLBACK(on_close_subwindow),NULL); + g_signal_connect(G_OBJECT(widgets->AcceptButton),"clicked",G_CALLBACK(yon_open_browser),yon_char_new(link)); + g_signal_connect(G_OBJECT(widgets->AcceptButton),"clicked",G_CALLBACK(on_close_subwindow),NULL); + + + } else { + yon_open_browser(self,link); + } } -void on_open_users(){ - GtkBuilder *builder=gtk_builder_new_from_file(glade_path); - users_window *widgets = malloc (sizeof(users_window)); - widgets->window=yon_gtk_builder_get_widget(builder, "usersEditWindow"); +/**on_link(GtkWidget *self, char* uri, gpointer user_data) + * [EN] + * Signal for hadnling AboutDialog links. + * Connect to "activate-link" signal. + * [self] is AboutDialog window; + * [uri] is activated link; + * [user_data] is pointer for user data, hasn't used in standard handler; + * [RU] + * Функция для обработки сигнала нажатия на ссылку окна AboutDialog. + * Присоединять к сигналу "activate-link". + * [self] - окно AboutDialog; + * [uri] - ссылка, по которой совершается переход; + * [user_data] - указатель на любые другие данные, не используется в стандартном обработчике; +*/ +void on_link(GtkWidget *self, char* uri, gpointer user_data){ + gtk_widget_destroy(self); + on_open_documentation_confirmation(self,uri); } -void on_open_groups(){ - GtkBuilder *builder=gtk_builder_new_from_file(glade_path); - groups_window *widgets = malloc (sizeof(groups_window)); - widgets->window=yon_gtk_builder_get_widget(builder, "groupsEditWindow"); - - widgets->groupsTreeView=yon_gtk_builder_get_widget(builder, "groupsTreeView"); - widgets->groupsGroupColumn=GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "groupsGroupColumn")); - widgets->groupsEnabledColumn=GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "groupsEnabledColumn")); - widgets->groupsCancelButton=yon_gtk_builder_get_widget(builder, "groupsCancelButton"); - widgets->groupsOkButton=yon_gtk_builder_get_widget(builder, "groupsOkButton"); - widgets->list=GTK_LIST_STORE(gtk_builder_get_object(builder, "liststore2")); - - gtk_button_set_label(GTK_BUTTON(widgets->groupsCancelButton),_("Cancel")); - gtk_button_set_label(GTK_BUTTON(widgets->groupsOkButton),_("Ok")); - gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(widgets->groupsGroupColumn),_("Group")); - gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(widgets->groupsEnabledColumn),_("Enabled")); - g_signal_connect(G_OBJECT(widgets->groupsCancelButton), "clicked", G_CALLBACK(on_close_subwindow),NULL); - gtk_widget_show_all(widgets->window); +/**on_about() + * [EN] + * Function for setting up and showing AboutDialog. + * Connect it to "activate" signal of Documentation MenuItem. + * [RU] + * Функиця для настройки и показа окна AboutDialog. + * Присоединять к сигналу "activate" кнопки справки типа MenuItem. +*/ +void on_about(){ + GtkBuilder *builder=gtk_builder_new_from_resource(glade_path); + GtkWidget *window=yon_gtk_builder_get_widget(builder,"AboutWindow"); + GtkWidget *title=yon_gtk_builder_get_widget(builder,"headerAboutTopic"); + GtkWidget *hideButtonBox=yon_gtk_builder_get_widget(builder,"buttonBoxHide"); + gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(window),version_application); + gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(window),PROJECT_HOME_LABEL); + gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(window),TITLE_LABEL); + gtk_label_set_text(GTK_LABEL(title),TITLE_LABEL); + g_signal_connect(G_OBJECT(window),"activate-link",G_CALLBACK(on_link),NULL); + gtk_widget_set_visible(hideButtonBox,0); + gtk_widget_destroy(hideButtonBox); + gtk_widget_show(window); } -main_window *setup_main_window(){ - main_window *widgets=NULL; - widgets=malloc(sizeof(main_window)); - GtkBuilder *builder=gtk_builder_new_from_file(glade_path); - widgets->window=yon_gtk_builder_get_widget(builder,"MainWindow"); - GtkListStore *list; - widgets->mainUserGroupsLabel=yon_gtk_builder_get_widget(builder,"mainUserGroupsLabel"); - widgets->mainUserGroupsEntry=yon_gtk_builder_get_widget(builder,"mainUserGroupsEntry"); - widgets->mainUserGroupsButton=yon_gtk_builder_get_widget(builder,"mainUserGroupsButton"); - widgets->mainUserNameLabel=yon_gtk_builder_get_widget(builder,"mainUserNameLabel"); - widgets->mainUserNameAdminCheck=yon_gtk_builder_get_widget(builder,"mainUserNameAdminCheck"); - widgets->mainUserNameEntry=yon_gtk_builder_get_widget(builder,"mainUserNameEntry"); - widgets->mainUserPasswordLabel=yon_gtk_builder_get_widget(builder,"mainUserPasswordLabel"); - widgets->mainUserPasswordEntry=yon_gtk_builder_get_widget(builder,"mainUserPasswordEntry"); - widgets->mainPasswordHashLabel=yon_gtk_builder_get_widget(builder,"mainPasswordHashLabel"); - widgets->mainUserPasswordHashCombo=yon_gtk_builder_get_widget(builder,"mainUserPasswordHashCombo"); - widgets->mainUserAutologinLabel=yon_gtk_builder_get_widget(builder,"mainUserAutologinLabel"); - widgets->mainUserAutologinCombo=yon_gtk_builder_get_widget(builder,"mainUserAutologinCombo"); - widgets->mainUpdateHomeDirLabel=yon_gtk_builder_get_widget(builder,"mainUpdateHomeDirLabel"); - widgets->mainUpdateDirCheck=yon_gtk_builder_get_widget(builder,"mainUpdateDirCheck"); - widgets->mainLoadUserProgramsLabel=yon_gtk_builder_get_widget(builder,"mainLoadUserProgramsLabel"); - widgets->mainLoadUserProgramsEntry=yon_gtk_builder_get_widget(builder,"mainLoadUserProgramsEntry"); - widgets->mainUserStringLabel=yon_gtk_builder_get_widget(builder,"mainUserStringLabel"); - widgets->mainUserStringEntry=yon_gtk_builder_get_widget(builder,"mainUserStringEntry"); - widgets->mainAddButton=yon_gtk_builder_get_widget(builder,"mainAddButton"); - widgets->mainEditButton=yon_gtk_builder_get_widget(builder,"mainEditButton"); - widgets->mainDeleteButton=yon_gtk_builder_get_widget(builder,"mainDeleteButton"); - widgets->mainUIDColumn=GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder,"mainUIDColumn")); - widgets->mainLoginColumn=GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder,"mainLoginColumn")); - widgets->mainPasswordColumn=GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder,"mainPasswordColumn")); - widgets->mainUserNameColumn=GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder,"mainUserNameColumn")); - widgets->headerLoadGlobalConfigurationMenuItem=yon_gtk_builder_get_widget(builder,"headerLoadGlobalConfigurationMenuItem"); - widgets->headerLoadLocalConfigurationMenuItem=yon_gtk_builder_get_widget(builder,"headerLoadLocalConfigurationMenuItem"); - widgets->headerSaveGlobalLocalConfigurationMenuItem=yon_gtk_builder_get_widget(builder,"headerSaveGlobalLocalConfigurationMenuItem"); - widgets->headerSaveGlobalConfigurationMenuItem=yon_gtk_builder_get_widget(builder,"headerSaveGlobalConfigurationMenuItem"); - widgets->headerSaveLocalConfigurationMenuItem=yon_gtk_builder_get_widget(builder,"headerSaveLocalConfigurationMenuItem"); - widgets->headerDocumentationMenuItem=yon_gtk_builder_get_widget(builder,"headerDocumentationMenuItem"); - widgets->headerAboutMenuItem=yon_gtk_builder_get_widget(builder,"headerAboutMenuItem"); - widgets->mainHeaderConfigLoadLabel=yon_gtk_builder_get_widget(builder,"mainHeaderConfigLoadLabel"); - widgets->mainHeaderTitleLabel=yon_gtk_builder_get_widget(builder,"mainHeaderTitleLabel"); - widgets->mainHeaderSaveConfigurationLabel=yon_gtk_builder_get_widget(builder,"mainHeaderSaveConfigurationLabel"); - widgets->mainStatusBox=yon_gtk_builder_get_widget(builder,"mainStatusBox"); - widgets->mainStatusIcon=yon_gtk_builder_get_widget(builder,"mainStatusIcon"); - widgets->mainStatusLabel=yon_gtk_builder_get_widget(builder,"mainStatusLabel"); - - g_signal_connect(G_OBJECT(widgets->mainUserGroupsButton),"clicked", G_CALLBACK(on_open_groups),NULL); - g_signal_connect(G_OBJECT(widgets->window), "destroy", G_CALLBACK(gtk_main_quit), NULL); - - gtk_label_set_text(GTK_LABEL(widgets->mainUserGroupsLabel),_("User groups (default)")); - gtk_label_set_text(GTK_LABEL(widgets->mainUserNameLabel),_("User name")); - gtk_button_set_label(GTK_BUTTON(widgets->mainUserNameAdminCheck),_("Administrator")); - gtk_label_set_text(GTK_LABEL(widgets->mainUserPasswordLabel),_("User password")); - gtk_label_set_text(GTK_LABEL(widgets->mainPasswordHashLabel),_("Password hash algorythm")); - gtk_label_set_text(GTK_LABEL(widgets->mainUserAutologinLabel),_("Autologin")); - gtk_label_set_text(GTK_LABEL(widgets->mainUpdateHomeDirLabel),_("Update HOME directory(ies)")); - gtk_button_set_label(GTK_BUTTON(widgets->mainUpdateDirCheck),_("Enabled")); - gtk_label_set_text(GTK_LABEL(widgets->mainLoadUserProgramsLabel),_("Automatically load user programs")); - gtk_label_set_text(GTK_LABEL(widgets->mainUserStringLabel),_("User string")); - gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(widgets->mainUIDColumn),_("UID")); - gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(widgets->mainLoginColumn),_("Login")); - gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(widgets->mainPasswordColumn),_("Password")); - gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(widgets->mainUserNameColumn),_("User Name")); - gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerLoadGlobalConfigurationMenuItem),_("Load from global configuration")); - gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerLoadLocalConfigurationMenuItem),_("Load from local configuration")); - gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerSaveGlobalLocalConfigurationMenuItem),_("Save to global and local configuration")); - gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerSaveGlobalConfigurationMenuItem),_("Save to global configuration")); - gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerSaveLocalConfigurationMenuItem),_("Save to local configuration")); - gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerDocumentationMenuItem),_("Documentation")); - gtk_menu_item_set_label(GTK_MENU_ITEM(widgets->headerAboutMenuItem),_("About")); - gtk_label_set_text(GTK_LABEL(widgets->mainHeaderConfigLoadLabel),_("Load")); - gtk_label_set_text(GTK_LABEL(widgets->mainHeaderTitleLabel),_("Users and groups")); - gtk_label_set_text(GTK_LABEL(widgets->mainHeaderSaveConfigurationLabel),_("Save")); - - GtkWidget *Header = yon_gtk_builder_get_widget(builder,"headBox"); - GtkWidget *Image = yon_gtk_builder_get_widget(builder,"mainHeadBackgroundImage"); - GtkWidget *Overlay = yon_gtk_builder_get_widget(builder,"mainHeadOverlay"); - yon_ubl_header_setup(Overlay,Header,Image,image_path); - widgets->mainUserAutologinCombo; - gtk_widget_show_all(widgets->window); +//functions +void yon_load_proceed(char *command){ + if (yon_config_load_register(command)) + yon_ubl_status_box_render(LOCAL_SAVE_SUCCESS_LABEL,BACKGROUND_IMAGE_SUCCESS_TYPE); + else + yon_ubl_status_box_render(LOAD_FAILED_LABEL,BACKGROUND_IMAGE_FAIL_TYPE); + } -int main(int argc, char *argv[]){ +void on_groups_open(){ + GtkBuilder *builder = gtk_builder_new_from_resource(glade_groups_path); + groups_window *window = malloc(sizeof(groups_window)); + window->Window = yon_gtk_builder_get_widget(builder,"GroupsWindow"); + window->GroupsCancelButton = yon_gtk_builder_get_widget(builder,"GroupsCancelButton"); + window->GroupsOkButton = yon_gtk_builder_get_widget(builder,"GroupsOkButton"); + + g_signal_connect(G_OBJECT(window->GroupsCancelButton),"clicked",G_CALLBACK(on_close_subwindow),NULL); + g_signal_connect(G_OBJECT(window->GroupsOkButton),"clicked",G_CALLBACK(on_close_subwindow),NULL); + gtk_widget_show(window->Window); +} + +void on_user_add(){ + GtkBuilder *builder = gtk_builder_new_from_resource(glade_user_path); + user_window *window = malloc(sizeof(user_window)); + window->Window = yon_gtk_builder_get_widget(builder,"CreateUserWindow"); + window->UserAdditionalGroupsButton = yon_gtk_builder_get_widget(builder,"UserAdditionalGroupsButton"); + window->UserCancelButton = yon_gtk_builder_get_widget(builder,"UserCancelButton"); + window->UserOkButton = yon_gtk_builder_get_widget(builder,"UserOkButton"); + + g_signal_connect(G_OBJECT(window->UserCancelButton),"clicked",G_CALLBACK(on_close_subwindow),NULL); + g_signal_connect(G_OBJECT(window->UserOkButton),"clicked",G_CALLBACK(on_close_subwindow),NULL); + g_signal_connect(G_OBJECT(window->UserAdditionalGroupsButton),"clicked",G_CALLBACK(on_groups_open),NULL); + gtk_widget_show(window->Window); +} + +void on_user_edit(){ + +} + +void on_user_delete(){ + +} +// standard functions + +void config_init(){ + main_config.always_open_documentation=0; + main_config.win_height=0; + main_config.win_width=0; + main_config.win_pos_x=0; + main_config.win_pos_y=0; + main_config.socket_id=-1; + main_config.save_socket_id=-1; + main_config.load_socket_id=-1; + main_config.lock_help=0; + main_config.lock_help=0; + main_config.lock_load_global=0; + main_config.lock_save_global=0; + main_config.lock_save_local=0; +} + +main_window *setup_window(){ + /* Widgets getting | Получение виджетов */ + main_window *widgets = malloc(sizeof(main_window)); + GtkBuilder *builder = gtk_builder_new_from_resource(glade_path); + widgets->Window = yon_gtk_builder_get_widget(builder,"MainWindow"); + widgets->HatLabel = yon_gtk_builder_get_widget(builder,"headerTopic"); + widgets->PlugBox = yon_gtk_builder_get_widget(builder,"plugBox"); + + widgets->HeadOverlay = yon_gtk_builder_get_widget(builder,"HeadOverlay"); + widgets->HeadImage = yon_gtk_builder_get_widget(builder,"HeadBackgroundImage"); + widgets->HeadBox = yon_gtk_builder_get_widget(builder,"HeaderBox"); + widgets->HeadTitleLabel = yon_gtk_builder_get_widget(builder,"HeaderTitleLabel"); + widgets->HeadInfoLabel = yon_gtk_builder_get_widget(builder,"HeaderInfoLabel"); + + widgets->StatusBox = yon_gtk_builder_get_widget(builder,"mainStatusBox"); + widgets->StatusIcon = yon_gtk_builder_get_widget(builder,"mainStatusIcon"); + widgets->StatusLabel = yon_gtk_builder_get_widget(builder,"mainStatusLabel"); + + widgets->SaveLabel = yon_gtk_builder_get_widget(builder,"headerSaveConfigLabel"); + widgets->SaveMenuItem = yon_gtk_builder_get_widget(builder,"SaveGlobalLocalConfigurationMenuItem"); + widgets->SaveGlobalMenuItem = yon_gtk_builder_get_widget(builder,"SaveGlobalConfigurationMenuItem"); + widgets->SaveLocalMenuItem = yon_gtk_builder_get_widget(builder,"SaveLocalConfigurationMenuItem"); + widgets->RightBox = yon_gtk_builder_get_widget(builder,"HeaderRightBox"); + + widgets->LoadLabel = yon_gtk_builder_get_widget(builder,"headerLoadConfigLabel"); + widgets->LoadGlobalMenuItem = yon_gtk_builder_get_widget(builder,"LoadGlobalConfigurationMenuItem"); + widgets->LoadLocalMenuItem = yon_gtk_builder_get_widget(builder,"LoadLocalConfigurationMenuItem"); + widgets->LeftBox = yon_gtk_builder_get_widget(builder,"HeaderLeftBox"); + + widgets->DocumentationMenuItem = yon_gtk_builder_get_widget(builder,"DocumentationMenuItem"); + widgets->AboutMenuItem = yon_gtk_builder_get_widget(builder,"AboutMenuItem"); + + widgets->MainAddUserButton = yon_gtk_builder_get_widget(builder,"MainAddUserButton"); + widgets->MainEditUserButton = yon_gtk_builder_get_widget(builder,"MainEditUserButton"); + widgets->MainDeleteUserButton = yon_gtk_builder_get_widget(builder,"MainDeleteUserButton"); + + widgets->MainEditGroupsButton = yon_gtk_builder_get_widget(builder,"MainEditGroupsButton"); + + + if (main_config.lock_load_global == 1){ + gtk_widget_set_sensitive(widgets->LoadGlobalMenuItem,0); + } + if (main_config.lock_save_global == 1){ + gtk_widget_set_sensitive(widgets->SaveGlobalMenuItem,0); + gtk_widget_set_sensitive(widgets->SaveMenuItem,0); + } + if (main_config.lock_save_local == 1){ + gtk_widget_set_sensitive(widgets->SaveLocalMenuItem,0); + gtk_widget_set_sensitive(widgets->SaveMenuItem,0); + } + + /* Signal connection | Присоединение сигналов */ + 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),WIKI_LINK); + g_signal_connect(G_OBJECT(widgets->AboutMenuItem),"activate",G_CALLBACK(on_about),NULL); + g_signal_connect(G_OBJECT(widgets->MainAddUserButton),"clicked",G_CALLBACK(on_user_add),NULL); + g_signal_connect(G_OBJECT(widgets->MainEditUserButton),"clicked",G_CALLBACK(on_user_edit),NULL); + g_signal_connect(G_OBJECT(widgets->MainDeleteUserButton),"clicked",G_CALLBACK(on_user_delete),NULL); + g_signal_connect(G_OBJECT(widgets->MainEditGroupsButton),"clicked",G_CALLBACK(on_groups_open),NULL); + + + gtk_widget_show(widgets->Window); + return widgets; +} + +int main(int argc, char *argv[]){ + local=setlocale(LC_ALL, ""); textdomain (LocaleName); + config_init(); + int option_index=0; + int show_help=0; + int debug_mode=0; + { + struct option long_options[] = { + {"help", 0, 0, 'h'}, + {"version", 0, 0, 'V'}, + {"lock-help", 0,0, 1}, + {"lock-save", 0,0, 2}, + {"lock-save-local", 0,0, 3}, + {"lock-save-global", 0,0, 4}, + {"lock-load-global", 0,0, 5}, + {"socket-id", 1, 0, 's'}, + {"socket-ext-id", 1,0, 'e'}, + {"socket-trd-id", 1,0, 't'}, + {"debug", 0,0, 'd'}, + { NULL, 0, NULL, 0 } + }; + for (int i=0;iHeadOverlay,widgets->HeadBox,widgets->HeadImage,banner_path); + + yon_ubl_status_box_setup(widgets->StatusIcon,widgets->StatusBox,widgets->StatusLabel); + if (getuid()!=0) + yon_ubl_status_box_render(ROOT_WARNING_LABEL,BACKGROUND_IMAGE_FAIL_TYPE); + else + yon_ubl_status_box_render(TITLE_LABEL,BACKGROUND_IMAGE_SUCCESS_TYPE); + yon_ubl_setup_sockets(widgets->PlugBox,widgets->LeftBox,widgets->RightBox,main_config.socket_id,main_config.load_socket_id,main_config.save_socket_id); + yon_window_config_setup(GTK_WINDOW(widgets->Window)); + yon_window_config_load(config_path); GtkCssProvider *css=gtk_css_provider_new(); - gtk_css_provider_load_from_path(css,CssPath,NULL); + gtk_css_provider_load_from_resource(css,CssPath); gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), - GTK_STYLE_PROVIDER(css), - -1); + GTK_STYLE_PROVIDER(css), + -1); gtk_main(); } \ No newline at end of file diff --git a/source/ubl-settings-usergroups.h b/source/ubl-settings-usergroups.h index c002716..afd0497 100644 --- a/source/ubl-settings-usergroups.h +++ b/source/ubl-settings-usergroups.h @@ -1,96 +1,119 @@ -#include "ubl-utils.h" #include #include +#include "ubl-utils.h" #include #include #include #include #include +#include +#include +#include "ubl-cmake.h" +#ifdef WEBKIT_FOUND + #include +#endif +#include "ubl-strings.h" +#define WIKI_LINK "https://wiki.ublinux.ru/ru/Программное_обеспечение/Программы_и_утилиты/Все/ubl-settings-usergroups" -#define glade_path "/usr/share/ubl-settings-usergroups/ui/ubl-settings-usergroups.glade" -#define CssPath "/usr/share/ubl-settings-usergroups/css/ubl-settings-usergroups.css" -#define image_path "/usr/share/ubl-settings-usergroups/ui/ubl-settings-usergroups-banner.png" +#define _(String) gettext(String) + +#define glade_path "/com/ublinux/ui/ubl-settings-usergroups.glade" +#define glade_user_path "/com/ublinux/ui/ubl-settings-usergroups-user.glade" +#define glade_groups_path "/com/ublinux/ui/ubl-settings-usergroups-group.glade" +#define banner_path "/com/ublinux/images/ubl-settings-usergroups-banner.png" +#define CssPath "/com/ublinux/css/ubl-settings-usergroups.css" +#define config_path yon_char_unite("/home/",yon_ubl_root_user_get(),"/.config/",LocaleName,"/",LocaleName,".conf",NULL) + +#define yon_col(mean) yon_char_append(mean,":") #define LocalePath "/usr/share/locale" #define LocaleName "ubl-settings-usergroups" +typedef char* string; +string version_application; +char *local; -#define _(String) gettext(String) +typedef struct { + int always_open_documentation; + int win_pos_x; + int win_pos_y; + int win_width; + int win_height; + + int socket_id; + int load_socket_id; + int save_socket_id; + + int lock_help; + int lock_save_local; + int lock_save_global; + int lock_load_global; +} config; typedef struct { - GtkWidget *window; - - GtkListStore *list; - GtkWidget *mainUserGroupsLabel; - GtkWidget *mainUserGroupsEntry; - GtkWidget *mainUserGroupsButton; - GtkWidget *mainUserNameLabel; - GtkWidget *mainUserNameAdminCheck; - GtkWidget *mainUserNameEntry; - GtkWidget *mainUserPasswordLabel; - GtkWidget *mainUserPasswordEntry; - GtkWidget *mainPasswordHashLabel; - GtkWidget *mainUserPasswordHashCombo; - GtkWidget *mainUserAutologinLabel; - GtkWidget *mainUserAutologinCombo; - GtkWidget *mainUpdateHomeDirLabel; - GtkWidget *mainUpdateDirCheck; - GtkWidget *mainLoadUserProgramsLabel; - GtkWidget *mainLoadUserProgramsEntry; - GtkWidget *mainUserStringLabel; - GtkWidget *mainUserStringEntry; - GtkWidget *mainAddButton; - GtkWidget *mainEditButton; - GtkWidget *mainDeleteButton; - GtkTreeViewColumn *mainUIDColumn; - GtkTreeViewColumn *mainLoginColumn; - GtkTreeViewColumn *mainPasswordColumn; - GtkTreeViewColumn *mainUserNameColumn; - GtkWidget *headerLoadGlobalConfigurationMenuItem; - GtkWidget *headerLoadLocalConfigurationMenuItem; - GtkWidget *headerSaveGlobalLocalConfigurationMenuItem; - GtkWidget *headerSaveGlobalConfigurationMenuItem; - GtkWidget *headerSaveLocalConfigurationMenuItem; - GtkWidget *headerDocumentationMenuItem; - GtkWidget *headerAboutMenuItem; - GtkWidget *mainHeaderConfigLoadLabel; - GtkWidget *mainHeaderTitleLabel; - GtkWidget *mainHeaderSaveConfigurationLabel; - GtkWidget *mainStatusBox; - GtkWidget *mainStatusIcon; - GtkWidget *mainStatusLabel; + GtkWidget *Window; + GtkWidget *HatLabel; + GtkWidget *PlugBox; + + GtkWidget *HeadOverlay; + GtkWidget *HeadImage; + GtkWidget *HeadBox; + GtkWidget *HeadTitleLabel; + GtkWidget *HeadInfoLabel; + + GtkWidget *StatusBox; + GtkWidget *StatusIcon; + GtkWidget *StatusLabel; + + GtkWidget *SaveLabel; + GtkWidget *SaveMenuItem; + GtkWidget *SaveGlobalMenuItem; + GtkWidget *SaveLocalMenuItem; + GtkWidget *RightBox; + + GtkWidget *LoadLabel; + GtkWidget *LoadGlobalMenuItem; + GtkWidget *LoadLocalMenuItem; + GtkWidget *LeftBox; + + GtkWidget *DocumentationMenuItem; + GtkWidget *AboutMenuItem; + + GtkWidget *MainAddUserButton; + GtkWidget *MainEditUserButton; + GtkWidget *MainDeleteUserButton; + + GtkWidget *MainEditGroupsButton; + + } main_window; + typedef struct { - GtkWidget *window; - - GtkWidget *userUIDLabel; - GtkWidget *userUIDEntry; - GtkWidget *userUsernameLabel; - GtkWidget *userUsernameEntry; - GtkWidget *userLoginLabel; - GtkWidget *userLoginEntry; - GtkWidget *userPasswordLabel; - GtkWidget *userPasswordEntry; - GtkWidget *userDefaultPasswordCheck; - GtkWidget *userPasswordHashLabel; - GtkWidget *userPasswordHashCombo; - GtkWidget *userSAMBALabel; - - GtkWidget *userCancelButton; - GtkWidget *userAddButton; -} users_window; + GtkWidget *Window; + + GtkWidget *HatText; + GtkWidget *HeaderText; + GtkWidget *InfoText; + GtkWidget *AlwaysOpenCheck; + + GtkWidget *CloseButton; + GtkWidget *AcceptButton; +} documentation_confirmation_window; typedef struct { - GtkWidget *window; - - GtkWidget *groupsTreeView; - GtkTreeViewColumn *groupsEnabledColumn; - GtkTreeViewColumn *groupsGroupColumn; - GtkListStore *list; - - GtkWidget *groupsCancelButton; - GtkWidget *groupsOkButton; -} groups_window; \ No newline at end of file + GtkWidget *Window; + GtkWidget *GroupsCancelButton; + GtkWidget *GroupsOkButton; +} groups_window; + +typedef struct { + GtkWidget *Window; + GtkWidget *UserAdditionalGroupsButton; + GtkWidget *UserCancelButton; + GtkWidget *UserOkButton; +} user_window; + +main_window *setup_window(); \ No newline at end of file diff --git a/source/ubl-strings.h b/source/ubl-strings.h new file mode 100644 index 0000000..56da4ea --- /dev/null +++ b/source/ubl-strings.h @@ -0,0 +1,61 @@ +#define VERSION_LABEL yon_char_unite(_("Version:")," ",version_application,"\n",NULL) +#define HELP_LABEL yon_char_unite(_("ubl-settings-usergroups version:")," ", version_application,"\n",_("Users and groups"),"\n",_("Usage:"), " ubl-settings-usergroups ",_("[OPTIONS]"),"\n",_("Options:"),"\n\t--help, -h\t\t\t",_("Show this help"),"\n\t--version, -V\t\t\t",_("Show package version"),"\n\t--lock-help\t\t\t",_("Lock this help menu"),"\n\t--lock-save\t\t\t",_("Lock configuration saving"),"\n\t--lock-save-local\t\t",_("Lock local configration saving"),"\n\t--lock-save-global\t\t",_("Lock global configration saving"),"\n\t--lock-load-global\t\t",_("Lock global configration loading"),"\n",NULL) + +#define TITLE_LABEL _("Users and groups") +#define TITLE_INFO_LABEL _("System users and groups configuration") + +#define SUCCESS_LABEL _("Operation succeeded") +#define ROOT_WARNING_LABEL _("Warning! Application was launched without root - root-dependent actions are locked") + +#define ABOUT_LABEL _("About") +#define DOCUMENTATION_LABEL _("Documentation") + +#define SAVE_LOCAL_LABEL _("Save to local configuration") +#define SAVE_GLOBAL_LABEL _("Save to global configuration") +#define SAVE_CONFIGURATION_LABEL _("Save configuration") +#define SAVE_LABEL _("Save") + +#define LOAD_LOCAL_LABEL _("Load local configuration") +#define LOAD_GLOBAL_LABEL _("Load global configuration") +#define LOAD_LABEL _("Load") + +#define CANCEL_LABEL _("Cancel") + +#define HELP_TITLE_LABEL _("Would you like to read documentation in the Web?") +#define HELP_INFO_LABEL _("You will be redirected to documentation website where documentation is\ntranslated and supported by community.") +#define HELP_ALWAYS_OPEN_LABEL _("Always redirect to online documentation") +#define OPEN_HELP_LABEL _("Open documentation") +#define PROJECT_HOME_LABEL _("Project Home Page") +#define NOTHING_CHOSEN_LABEL _("Nothing were chosen") + + +#define GLOBAL_LOAD_SUCCESS_LABEL _("Global configuration loading succseeded.") +#define LOCAL_LOAD_SUCCESS_LABEL _("Local configuration loading succseeded.") +#define LOAD_FAILED_LABEL _("Config loading failed") + +#define GLOBAL_LOCAL_SAVE_SUCCESS_LABEL _("Local and global configuration saving succseeded.") +#define GLOBAL_SAVE_SUCCESS_LABEL _("Global configuration saving succseeded.") +#define LOCAL_SAVE_SUCCESS_LABEL _("Local configuration saving succseeded.") + +#define DEFAULT_USER_GROUPS_LABEL _("Default user groups:") +#define DEFAULT_USER_NAME_LABEL _("Default user name (if there's no another):") +#define USER_1000_IS_ADMIN_LABEL _("User with ID 1000 is administrator") +#define DEFAULT_USER_PASSWORD_LABEL _("Default user password:") +#define ROOT_USER_PASSWORD_LABEL _("Root user password:") +#define PASSWORD_HASH_ALGORYTHM_LABEL _("Password hash algorythm:") + +#define UID_LABEL _("UID") +#define LOGIN_LABEL _("Login") +#define PASSWORD_LABEL _("Password") +#define USER_NAME_LABEL _("User name") + +#define UID_USER_LABEL _("UID:") +#define USERNAME_USER_LABEL _("User name:") +#define LOGIn_USER_LABEL _("Login:") +#define PASSWORD_USER_LABEL _("Password:") +#define DEFAULT_USER_LABEL _("Default") +#define MAIN_GROUP_USER_LABEL _("Main group:") +#define ADDITIONAL_GROUPS_USER_LABEL _("Additional groups") +#define PASSWORD_HASH_USER_LABEL _("Password hash algorythm:") +#define SYNC_SAMBA_USER_LABEL _("Sync with SAMBA user") +#define EXTRA_OPTIONS_USER_LABEL _("Extra options:") \ No newline at end of file diff --git a/source/ubl-utils.c b/source/ubl-utils.c index ed01b97..341e091 100644 --- a/source/ubl-utils.c +++ b/source/ubl-utils.c @@ -1,397 +1,822 @@ #include "ubl-utils.h" -#ifndef UBL_UTILS - -typedef enum { - DICTIONARY_ACTION_WIDGETS_TYPE, - DICTIONARY_IVGRAPHICALS_TYPE, - DICTIONARY_OTHER_TYPE - -} DICT_TYPE; - -typedef struct dictionary { - char *key; - void *data; - struct dictionary *next; - struct dictionary *prev; - struct dictionary *first; - DICT_TYPE data_type; -} dictionary; - -typedef struct apps{ - char *Name; - int Type; - char *Categories; - char *Exec; - char *Icon; - int Pluggable; - int DualPluggable; - } apps; - -typedef struct { - char *command; - int *exitcode; -} thread_output; -#ifdef __GTK_H__ -typedef struct IVGrapgicals{ - char *sectionName; - char *categories; - GtkListStore *LV; - GtkWidget *Box; - GtkWidget *IV; - GtkWidget *label; - GtkWidget *sep; - GtkCellRendererPixbuf *iconRender; -} IVGraphicals; -#endif -#endif +// dictionary functions +/**yon_dictionary_create_empty(): + * [EN] + * Creates and returns empty dictionary + * [RU] + * Создаёт и возвращает пустой словарь. + */ +dictionary *yon_dictionary_new() +{ + dictionary *dict = malloc(sizeof(dictionary)); + dict->data = NULL; + dict->key = NULL; + dict->next = NULL; + dict->prev = NULL; + dict->first = dict; + dict->data_type = DICTIONARY_OTHER_TYPE; + return dict; +} -//dictionary functions +/**yon_dictionary_copy_deep(dictionary *dict) + * [EN] + * + * [RU] + * Создаёт и возвращает копию элемента словаря [dict] +*/ +dictionary *yon_dictinoary_copy(dictionary *dict){ + dictionary *dct = yon_dictionary_new_with_data(dict->key,dict->data); + dct->data_type= dict->data_type; +} -/** - * yon_dictionary_create_empty: - * Creates and returns empty dictionary +/**yon_dictionary_copy_deep(dictionary *dict) + * [EN] + * + * [RU] + * Создаёт полную копию словаря [dict] и возвращает первый элемент */ -dictionary *yon_dictionary_create_empty(){ - dictionary *dict=malloc(sizeof(dictionary)); +dictionary *yon_dictionary_copy_deep(dictionary *dict){ + dictionary *dct = NULL; + dictionary *newone=NULL; + for_dictionaries(dct,dict){ + yon_dictionary_add_or_create_if_exists_with_data(newone,dct->key,dct->data); + newone->data_type=dct->data_type; + } + return newone->first; +} + +int yon_dictionary_set_data(dictionary *dict, void *data){ + dict->data=data; +} + +int yon_dictionary_set_key(dictionary *dict, char *key){ + dict->key=key; +} + +int yon_dictionary_set(dictionary *dict, char *key, void *data){ + dict->key=key; + dict->data=data; +} + +int yon_dictionary_empty(dictionary *dict){ dict->data=NULL; - dict->key=NULL; - dict->next=NULL; - dict->prev=NULL; - dict->first=dict; dict->data_type=DICTIONARY_OTHER_TYPE; - return dict; } -void yon_dictionary_switch_to_last(dictionary **dict){ - if ((*dict)->next!=NULL) - for ((*dict)=(*dict)->first;(*dict)->next!=NULL;(*dict)=(*dict)->next){} +/**yon_dictionary_switch_to_last(dictionary **dict) + * [EN] + * + * [RU] + * Переключает словарь [dict] на последний элемент. +*/ +void yon_dictionary_switch_to_last(dictionary **dict) +{ + dictionary *dct=NULL, *dact=*dict; + for_dictionaries(dct,dact); } -dictionary * yon_dictionary_create_conneced(dictionary *targetdict){ - targetdict=yon_dictionary_get_last(targetdict); - targetdict->next=yon_dictionary_create_empty(); - targetdict->next->prev=targetdict; - targetdict->next->first=targetdict->first; - targetdict->next->data_type=DICTIONARY_OTHER_TYPE; +/**yon_dictionary_create_conneced(dictionary *targetdict) + * [EN] + * + * [RU] + * Создаёт новый элемент словаря [targetdict] +*/ +dictionary *yon_dictionary_append(dictionary *targetdict) +{ + targetdict = yon_dictionary_get_last(targetdict); + targetdict->next = yon_dictionary_new(); + targetdict->next->prev = targetdict; + targetdict->next->first = targetdict->first; + targetdict->next->data_type = DICTIONARY_OTHER_TYPE; return targetdict->next; } -dictionary *yon_dictionary_get_last(dictionary *dict){ - dictionary *dct=NULL; - for (dct=dict->first;dct->next!=NULL;dct=dct->next){} - return dct; +/**yon_dictionary_get_last(dictionary *dict) + * [EN] + * + * [RU] + * Возвращает последний элемент словаря [dict]. + * В отличае от yon_dictionary_switch_to_last() + * словарь [dict] остаётся на прежнем элементе. +*/ +dictionary *yon_dictionary_get_last(dictionary *dict) +{ + if (dict->next){ + dictionary *dct = NULL; + for_dictionaries(dct,dict); + return dct; + } else return dict; } -dictionary *yon_dictionary_switch_places(dictionary *dict,int aim){ - if (aim<0){ - if (dict->prev){ - if (dict->prev->prev){ - dictionary *next = dict->next,*prev=dict->prev,*preprev=prev->prev; - if (next){ - preprev->next=dict; - dict->prev=preprev; - dict->next=prev; - prev->prev=dict; - prev->next=next; - next->prev=prev; - } else { - preprev->next=dict; - dict->prev=preprev; - dict->next=prev; - prev->prev=dict; - prev->next=NULL; +/**yon_dictionary_switch_places(dictionary *dict, int aim) + * [EN] + * + * [RU] + * Меняет элемент словаря [dict] местами с другим элементом. + * если [aim]<0 элемент меняется местами с левым элементом; + * если [aim]>0 элемент меняется местами с правым элементом; +*/ +dictionary *yon_dictionary_swap(dictionary *dict, int aim) +{ + if (aim < 0) + { + if (dict->prev) + { + if (dict->prev->prev) + { + dictionary *next = dict->next, *prev = dict->prev, *preprev = prev->prev; + if (next) + { + preprev->next = dict; + dict->prev = preprev; + dict->next = prev; + prev->prev = dict; + prev->next = next; + next->prev = prev; + } + else + { + preprev->next = dict; + dict->prev = preprev; + dict->next = prev; + prev->prev = dict; + prev->next = NULL; } return prev; - } else { - dictionary *next = dict->next,*prev=dict->prev; - if (next){ - yon_dictionary_make_first(dict); - dict->prev=NULL; - dict->next=prev; - prev->prev=dict; - prev->next=next; - next->prev=prev; - } else { - dict->prev=NULL; - dict->next=prev; - prev->prev=dict; - prev->next=NULL; } - return prev; + else + { + dictionary *next = dict->next, *prev = dict->prev; + if (next) + { + yon_dictionary_make_first(dict); + dict->prev = NULL; + dict->next = prev; + prev->prev = dict; + prev->next = next; + next->prev = prev; + } + else + { + dict->prev = NULL; + dict->next = prev; + prev->prev = dict; + prev->next = NULL; + } + return prev; } } - } else if (aim>0){ - if (dict->next){ - if (dict->next->next){ - dictionary *next = dict->next,*prev=dict->prev,*afnext=next->next; - if (prev){ - prev->next=next; - next->prev=prev; - next->next=dict; - dict->prev=next; - dict->next=afnext; - afnext->prev=dict; - } else { + } + else if (aim > 0) + { + if (dict->next) + { + if (dict->next->next) + { + dictionary *next = dict->next, *prev = dict->prev, *afnext = next->next; + if (prev) + { + prev->next = next; + next->prev = prev; + next->next = dict; + dict->prev = next; + dict->next = afnext; + afnext->prev = dict; + } + else + { yon_dictionary_make_first(next); - next->prev=NULL; - next->next=dict; - dict->prev=next; - dict->next=afnext; - afnext->prev=dict; + next->prev = NULL; + next->next = dict; + dict->prev = next; + dict->next = afnext; + afnext->prev = dict; } return next; - } else { - dictionary *next = dict->next,*prev=dict->prev; - if (prev){ - prev->next=next; - next->prev=prev; - next->next=dict; - dict->prev=next; - dict->next=NULL; - } else { - next->prev=NULL; - next->next=dict; - dict->prev=next; - dict->next=NULL; + } + else + { + dictionary *next = dict->next, *prev = dict->prev; + if (prev) + { + prev->next = next; + next->prev = prev; + next->next = dict; + dict->prev = next; + dict->next = NULL; + } + else + { + next->prev = NULL; + next->next = dict; + dict->prev = next; + dict->next = NULL; } } } } } -void yon_dictionary_make_first(dictionary *dict){ - for (dictionary *dct=dict->first;dct!=NULL;dct=dct->next){ - dct->first=dict; +/**yon_dictionary_make_first(dictionary *dict) + * [EN] + * + * [RU] + * Устанавливает указатель первого элемента словаря [dict] + * на текущий элемент. Не использовать. +*/ +void yon_dictionary_make_first(dictionary *dict) +{ + for (dictionary *dct = dict->first; dct != NULL; dct = dct->next) + { + dct->first = dict; } } -void yon_dictionary_make_nth(dictionary *dict, int nth){ - dictionary *dct=dict->first; - for (int i=0;inext;} +/**yon_dictionary_make_nth(dictionary *dict, int nth) + * [EN] + * + * [RU] + * Перемещает элемент словаря [dict] на позицию [nth]. +*/ +void yon_dictionary_make_nth(dictionary *dict, int nth) +{ + dictionary *dct = dict->first; + for (int i = 0; i < nth; i++) + { + if (dct == NULL) + return; + else + dct = dct->next; + } yon_dictionary_rip(dict); - dictionary *prev=dct->prev; - prev->next=dict; - dict->prev=prev; - dict->next=dct; - dct->prev=dict; -} - -dictionary *yon_dictionary_create_with_data(char *key, void *data){ - dictionary *dct=yon_dictionary_create_empty(); - dct->key=yon_char_new(key); - dct->data=data; - dct->data_type=DICTIONARY_OTHER_TYPE; + dictionary *prev = dct->prev; + prev->next = dict; + dict->prev = prev; + dict->next = dct; + dct->prev = dict; +} + +/**yon_dictionary_create_with_data(char *key, void *data) + * [EN] + * + * [RU] + * Создаёт новый словарь с ключом [key] и указателем на данные [data] +*/ +dictionary *yon_dictionary_new_with_data(char *key, void *data) +{ + dictionary *dct = yon_dictionary_new(); + dct->key = yon_char_new(key); + dct->data = data; + dct->data_type = DICTIONARY_OTHER_TYPE; return dct; } -dictionary *yon_dictionary_create_with_data_connected(dictionary *dict, char *key, void *data){ - dictionary *dct=yon_dictionary_create_conneced(dict); - dct->key=yon_char_new(key); - dct->data=data; - dct->data_type=DICTIONARY_OTHER_TYPE; +/** void *yon_dictionary_free_all(dictionary *dictionary,void *data_manipulation) + * [EN] + * Frees whole [dictionary] and activates [data_manipulation] function if not NULL with [dictionary]->data argument for each dictionary. + * [RU] + * Освобождает память для всех элементов словаря [dictionary] и активирует функцию [data_manipulation], если она была передана, с аргументом [dictionary]->data на каждый элемент словаря. +*/ +void *yon_dictionary_free_all(dictionary *dictionary_to_free,void (*data_manipulation)(void*)){ + dictionary *dict=NULL; + for_dictionaries(dict,dictionary_to_free){ + if(data_manipulation) + data_manipulation(dict->data); + if(dict->prev) + free(dict->prev); + } + free(dict); + return NULL; +} + +/**yon_dictionary_create_with_data_connected(dictionary *dict, char *key, void *data) + * [EN] + * + * [RU] + * Создаёт новый элемент словаря, присоединяемый в конец словаря [dict] + * с ключом [key] и указателем на данные [data] +*/ +dictionary *yon_dictionary_append_with_data(dictionary *dict, char *key, void *data) +{ + dictionary *dct = yon_dictionary_append(dict); + dct->key = yon_char_new(key); + dct->data = data; + dct->data_type = DICTIONARY_OTHER_TYPE; return dct; } -dictionary *yon_dictionary_connect(dictionary *old, dictionary *toconnect){ - dictionary *dict=yon_dictionary_get_last(old); - dict->next=toconnect; - toconnect->prev=dict; - toconnect->first=dict->first; +/**yon_dictionary_connect(dictionary *old, dictionary *toconnect) + * [EN] + * + * [RU] + * Присоединяет словарь [toconnect] в конец словаря [old]. +*/ +dictionary *yon_dictionary_connect(dictionary *old, dictionary *toconnect) +{ + dictionary *dict = yon_dictionary_get_last(old); + dict->next = toconnect; + toconnect->prev = dict; + toconnect->first = dict->first; return toconnect; } -dictionary *yon_dictionary_find(dictionary **dict, char *key){ - dictionary *dct=*dict; - for (dictionary *pointer=dct->first;pointer!=NULL;pointer=pointer->next){ - if (strcmp(pointer->key,key)==0){ - *dict=pointer; +/**yon_dictionary_get(dictionary **dict, char *key) + * [EN] + * + * [RU] + * Возвращает элемент словаря [dict] с ключом [key]. + * Если такого элемента не было обнаружено, возвращается NULL +*/ +dictionary *yon_dictionary_get(dictionary **dict, char *key) +{ + dictionary *dct = *dict; + for (dictionary *pointer = dct->first; pointer != NULL; pointer = pointer->next) + { + if (strcmp(pointer->key, key) == 0) + { + *dict = pointer; return pointer; } } return NULL; } - -dictionary *yon_dictionary_rip(dictionary *dict){ - if (!dict->next){ - dictionary *prev=dict->prev; - if (prev){ - prev->next=NULL; - return prev; - } else return dict; +/**yon_dictionary_rip(dictionary *dict) + * [EN] + * + * [RU] + * Вырезает элемент из словаря и возвращает вырезанный элемент. +*/ +dictionary *yon_dictionary_rip(dictionary *dict) +{ + if (!dict->next&&!dict->prev) return NULL; + else if (!dict->next) + { + dictionary *prev = dict->prev; + if (prev) + { + prev->next = NULL; + return prev; + } + else + return dict; } - else if (!dict->prev){ - dictionary *next=dict->next; - if (next){ + else if (!dict->prev) + { + dictionary *next = dict->next; + if (next) + { yon_dictionary_make_first(next); - next->prev=NULL; + next->prev = NULL; return next; } - else return dict; + else + return dict; } - else { - dictionary *next=dict->next, *prev=dict->prev; - next->prev=prev; - prev->next=next; + else + { + dictionary *next = dict->next, *prev = dict->prev; + next->prev = prev; + prev->next = next; return next; } } -dictionary *yon_dictionary_get_nth(dictionary *dict, int place){ - dict=dict->first; - for (int i=0;inext; - if (dict) return dict; - else return NULL; +/**yon_dictionary_get_nth(dictionary *dict, int place) + * [EN] + * + * [RU] + * Возвращает [place]-й элемент словаря [dict] +*/ +dictionary *yon_dictionary_get_nth(dictionary *dict, int place) +{ + if (dict){ + dict = dict->first; + int i = 0; + for (i = 0; i < place; i++) + if (dict->next) + dict = dict->next; + else + break; + if (i == place) + return dict; + else + return NULL; + } else return NULL; } -//char functions +// char functions -/** +/**[EN] + * * creates new char string by combining two char strings. -*/ -char *yon_char_get_augumented(char *source, char *append){ - if (source&&append){ - int size=strlen(source)+strlen(append)+1; - char *final=malloc(size); - memset(final,0,size); - if (strstr(source,"%%")) - sprintf(final,source,append); + */ +char *yon_char_append(char *source, char *append) +{ + if (source && append) + { + int size = strlen(source) + strlen(append) + 1; + char *final = malloc(size); + memset(final, 0, size); + if (strstr(source, "%%")) + sprintf(final, source, append); + else + sprintf(final, "%s%s", source, append); + return final; + } else - sprintf(final,"%s%s",source,append); - return final; - } else return NULL; } -/** +/**[EN] + * * creates new char string by copying another char. -*/ -char *yon_char_new(char *chr){ - char *newchar=malloc(strlen(chr)+1); - memset(newchar,0,strlen(chr)+1); - memcpy(newchar,chr,strlen(chr)); - return newchar; + */ +char *yon_char_new(char *chr) +{ + if (chr){ + char *newchar = malloc(strlen(chr) + 1); + memset(newchar, 0, strlen(chr) + 1); + memcpy(newchar, chr, strlen(chr)); + return newchar; + } else + return NULL; } -/** +// char *yon_char_unite(char *source, ...) + +char *yon_char_unite(char *source, ...){ + va_list arglist; + char *new_char=NULL; + char *unite_char=NULL; + new_char=yon_char_new(source); + va_start(arglist,source); + unite_char = va_arg(arglist,char*); + while(unite_char){ + new_char = yon_char_append(new_char,unite_char); + unite_char = va_arg(arglist,char*); + } + va_end(arglist); + return new_char; +} + +/**yon_cut(char *source, int size, int startpos) + * [EN] * cuts source string by size length from startpos position. -*/ -char *yon_cut(char *source, int size, int startpos){ - char *cut=NULL; - cut=malloc(size+1); - memset(cut,0,size+1); - memcpy(cut,source+startpos,size); + */ +char *yon_cut(char *source, int size, int startpos) +{ + char *cut = NULL; + cut = malloc(size + 1); + memset(cut, 0, size + 1); + memcpy(cut, source + startpos, size); return cut; } -/** + +/**yon_char_divide(char *source, int dividepos) + * [EN] * divides source string in dividepos position, * returning left part of divided string and * inserting right part to source string. -*/ -char *yon_char_divide(char *source, int dividepos){ - char *cut=malloc(dividepos+1); - memset(cut,0,dividepos+1); - memcpy(cut,source,dividepos); - char *left=malloc(strlen(source)-strlen(cut)); - memset(left,0,strlen(source)-strlen(cut)); - memcpy(left,source+dividepos+1,(strlen(source)-dividepos)); - memset(source,0,strlen(source)); - memcpy(source,left,strlen(left)); + */ +char *yon_char_divide(char *source, int dividepos) +{ + char *cut = malloc(dividepos + 1); + memset(cut, 0, dividepos + 1); + memcpy(cut, source, dividepos); + char *left = malloc(strlen(source) - strlen(cut)); + memset(left, 0, strlen(source) - strlen(cut)); + memcpy(left, source + dividepos + 1, (strlen(source) - dividepos)); + memset(source, 0, strlen(source)); + memcpy(source, left, strlen(left)); return cut; } -/** - * searches string dividepos in source string and divides it, +int yon_char_find_count(char *source, char *find){ + char *working_string=yon_char_new(source); + int i=0; + int size=0; + int pos=0; + config_str rtn = yon_char_parse(working_string,&size,"\n"); + for (int j=0;j= 10; i++) + { + convert_check = convert_check / 10; + } + char *ch = g_malloc0(i * sizeof(char) + 1); + sprintf(ch, "%d", int_to_convert); + return ch; +} + +/**yon_char_replace(char *source, char *find, char*replace) + * [EN] + * + * [RU] + * Заменяет в строке [source] все вхождения строки [find] на [replace] */ -char *yon_char_divide_search(char *source, char* dividepos, int delete_divider){ - char *cut=strstr(source,dividepos); - int leng=strlen(source)-strlen(cut); - cut=yon_char_divide(source,leng); - return cut; +char *yon_char_replace(char *source, char *find, char*replace){ + char *final=NULL; + char *temp=NULL; + if(!strstr(replace,find)){ + while ((final=strstr(source,find))){ + temp=malloc(strlen(source)-strlen(final)); + memset(temp,0,strlen(source)-strlen(final)+strlen(replace)); + memcpy(temp,source,strlen(source)-strlen(final)); + temp=yon_char_append(temp,replace); + source=yon_char_append(temp,final+1); + } + return source; + } } -/** - * converts int to char. + +/**[EN] + * char **yon_char_parse(char *parameters, int *size, char *divider) + * Parses string [parameters], divided by [divider], + * then returns parsed string array and sets [size] to + * size of returned array */ -char *yon_char_from_int(int int_to_convert){ +char **yon_char_parse(char *parameters, int *size, char *divider){ + char **string=NULL; int i=1; - float convert_check=(float)int_to_convert; - for (i=1;convert_check>10;i++){ - convert_check=convert_check/10; + string=malloc(sizeof(char*)); + char *paramline=yon_char_new(parameters); + char *param; + while ((param=yon_char_divide_search(paramline,divider,1))){ + string=realloc(string,sizeof(char*)*i); + string[i-1]=yon_char_new(param); + i++; + if (strcmp(param,paramline)==0) break; } - char *ch=malloc(i*sizeof(char)+1); - sprintf(ch,"%d",int_to_convert); - return ch; + string=realloc(string,sizeof(char*)*i); + string[i-1]=yon_char_new(paramline); + i++; + // printf("%d\n",i); + *size=i-1; + return string; + } +/**yon_char_parsed_rip(char **char_string, int *size, int item_to_delete) + * [EN] + * + * [RU] + * Удаляет элемент [item_to_delete] из массива строк [char_string], размера [size] + * Возвращает получившийся массив, в [size] загружается размер нового массива. +*/ +char **yon_char_parsed_rip(char **char_string, int *size, int item_to_delete){ + char **new_char_parsed=NULL; + new_char_parsed=malloc(sizeof(char*)*((*size)-1)); + int flag = 0; + for (int i=0;i < (*size);i++){ + if (i==item_to_delete) { + flag = 1; + } + if (flag == 0) { + new_char_parsed[i]=yon_char_new(char_string[i]); + } + else if (flag == 1 && i!=item_to_delete) { + new_char_parsed[i-1]=yon_char_new(char_string[i]); + } + } + (*size)=(*size)-1; + return new_char_parsed; +} + +/**yon_char_parsed_check_exist(char **parameters, int size, char *param) + * [EN] + * Checks if [parameters] string array of length [size] + * has [param] element; + * [RU] + * Проверяет есть ли в массиве строк [parameters], размера [size] + * элемент [param] +*/ +int yon_char_parsed_check_exist(char **parameters, int size, char *param){ + + for (int i=0;id_name); - file=fopen(path,"r"); - if (strlen(de->d_name)>9) + char *path = yon_char_append(DesktopPath, de->d_name); + file = fopen(path, "r"); + if (strlen(de->d_name) > 9) { - char *extension=strstr(path,"."); - if (extension!=NULL) + char *extension = strstr(path, "."); + if (extension != NULL) { - if (strcmp(extension,".desktop")==0) + if (strcmp(extension, ".desktop") == 0) { apps tempapp; - GKeyFile *gfile=g_key_file_new(); - GError *err=NULL; - g_key_file_load_from_file(gfile,path,G_KEY_FILE_KEEP_TRANSLATIONS,NULL); - char *Type=g_key_file_get_string(gfile,"Desktop Entry", "Type",&err); - if (err){ - printf("%s\n",err->message); + GKeyFile *gfile = g_key_file_new(); + GError *err = NULL; + g_key_file_load_from_file(gfile, path, G_KEY_FILE_KEEP_TRANSLATIONS, NULL); + char *Type = g_key_file_get_string(gfile, "Desktop Entry", "Type", &err); + if (err) + { + printf("%s\n", err->message); } - if (strcmp(Type,"Application")==0) tempapp.Type=1; else if (strcmp(Type,"pyApplication")==0) tempapp.Type=2; else continue; - tempapp.Name=g_key_file_get_locale_string(gfile,"Desktop Entry","Name",setlocale(LC_ALL,NULL),NULL); - if (tempapp.Name==NULL) continue; - tempapp.Categories=g_key_file_get_string(gfile,"Desktop Entry", "Categories",NULL); - if (tempapp.Categories==NULL) continue; - tempapp.Exec=g_key_file_get_string(gfile,"Desktop Entry", "Exec",NULL); - if (tempapp.Exec==NULL) continue; - tempapp.Icon=g_key_file_get_string(gfile,"Desktop Entry", "Icon",NULL); - if (tempapp.Icon==NULL) continue; - tempapp.Pluggable=g_key_file_get_boolean(gfile,"Desktop Entry", "Pluggable",NULL); - if (!tempapp.Pluggable) tempapp.Pluggable=g_key_file_get_boolean(gfile,"Desktop Entry", "X-XfcePluggable",NULL); - if (tempapp.Pluggable) tempapp.DualPluggable=g_key_file_get_boolean(gfile,"Desktop Entry", "X-UBLPluggable",NULL); - if (g_key_file_get_boolean(gfile,"Desktop Entry", "X-UBL-SettingsManager-Hidden",NULL)==0) - if (size==0){ - applist=(apps*)malloc(size+1*sizeof(apps)); - applist[0].Name=yon_char_new(tempapp.Name); - applist[0].Categories=yon_char_new(tempapp.Categories); - applist[0].Exec=yon_char_new(tempapp.Exec); - applist[0].Icon=yon_char_new(tempapp.Icon); - applist[0].Type=tempapp.Type; - applist[0].Pluggable=tempapp.Pluggable; - applist[0].DualPluggable=tempapp.DualPluggable; + if (strcmp(Type, "Application") == 0) + tempapp.Type = 1; + else if (strcmp(Type, "pyApplication") == 0) + tempapp.Type = 2; + else + continue; + tempapp.Name = g_key_file_get_locale_string(gfile, "Desktop Entry", "Name", setlocale(LC_ALL, NULL), NULL); + if (tempapp.Name == NULL) + continue; + tempapp.Categories = g_key_file_get_string(gfile, "Desktop Entry", "Categories", NULL); + if (tempapp.Categories == NULL) + continue; + tempapp.Exec = g_key_file_get_string(gfile, "Desktop Entry", "Exec", NULL); + if (tempapp.Exec == NULL) + continue; + tempapp.Icon = g_key_file_get_string(gfile, "Desktop Entry", "Icon", NULL); + if (tempapp.Icon == NULL) + continue; + tempapp.Pluggable = g_key_file_get_boolean(gfile, "Desktop Entry", "Pluggable", NULL); + if (!tempapp.Pluggable) + tempapp.Pluggable = g_key_file_get_boolean(gfile, "Desktop Entry", "X-XfcePluggable", NULL); + if (tempapp.Pluggable) + tempapp.DualPluggable = g_key_file_get_boolean(gfile, "Desktop Entry", "X-UBLPluggable", NULL); + if (g_key_file_get_boolean(gfile, "Desktop Entry", "X-UBL-SettingsManager-Hidden", NULL) == 0) + if (size == 0) + { + applist = (apps *)malloc(size + 1 * sizeof(apps)); + applist[0].Name = yon_char_new(tempapp.Name); + applist[0].Categories = yon_char_new(tempapp.Categories); + applist[0].Exec = yon_char_new(tempapp.Exec); + applist[0].Icon = yon_char_new(tempapp.Icon); + applist[0].Type = tempapp.Type; + applist[0].Pluggable = tempapp.Pluggable; + applist[0].DualPluggable = tempapp.DualPluggable; size++; - } else { - applist=(apps*)realloc(applist,(size+1)*sizeof(apps)); - applist[size].Name=yon_char_new(tempapp.Name); - applist[size].Categories=yon_char_new(tempapp.Categories); - applist[size].Exec=yon_char_new(tempapp.Exec); - applist[size].Icon=yon_char_new(tempapp.Icon); - applist[size].Pluggable=tempapp.Pluggable; - applist[size].DualPluggable=tempapp.DualPluggable; - applist[size].Type=tempapp.Type; + } + else + { + applist = (apps *)realloc(applist, (size + 1) * sizeof(apps)); + applist[size].Name = yon_char_new(tempapp.Name); + applist[size].Categories = yon_char_new(tempapp.Categories); + applist[size].Exec = yon_char_new(tempapp.Exec); + applist[size].Icon = yon_char_new(tempapp.Icon); + applist[size].Pluggable = tempapp.Pluggable; + applist[size].DualPluggable = tempapp.DualPluggable; + applist[size].Type = tempapp.Type; size++; } } @@ -399,201 +824,814 @@ apps *yon_apps_scan_and_parse_desktops(int *sizef){ } } } - *sizef=size; + *sizef = size; return applist; }; - -void yon_apps_sort(apps *applist,int size){ +void yon_apps_sort(apps *applist, int size) +{ apps tmp; - if (size>2) + if (size > 2) { - for (int i=1;idata_type=DICTIONARY_CHAR_TYPE; + } + } + check_config + return 0; + else return 1; +} +/**yon_config_remove_by_key(char *key) + * [EN] + * + * [RU] + * Удаляет параметр конфига по ключу [key] +*/ +int yon_config_remove_by_key(char *key){ + check_config{ + dictionary *dict = yon_dictionary_get(&__yon__config__strings,key); + if (dict){ + yon_dictionary_rip(dict); + return 1; + }else return 0; + } + return 0; +} +/**yon_config_remove_by_data(void *data) + * [EN] + * + * [RU] + * Производит поиск по конфигу на наличие параметра со значением [data] и удаляет найденное значение из конфига. +*/ +int yon_config_remove_by_data(void *data){ + check_config{ + dictionary *dict = NULL; + for_dictionaries(dict,__yon__config__strings){ + if (dict->data==data){ + yon_dictionary_rip(dict); + return 1; + } + } + return 0; + } + return 0; +} + +/**yon_config_remove_element(char *key, char *deleted) + * [EN] + * + * [RU] + * Удаляет элемент [deleted] из массива параметров с ключом [key] +*/ +int yon_config_remove_element(char *key, char *deleted){ + check_config{ + dictionary *dict = yon_dictionary_get(&__yon__config__strings,key); + char *data = (char*)dict->data; + char *found = strstr(data,deleted); + int size=strlen(data)-strlen(found)+1; + char *new_data = malloc(size); + memset(new_data,0,size); + if (strlen(found)!=strlen(deleted)){ + memcpy(new_data,data,size-1); + new_data = yon_char_append(new_data,found+strlen(deleted)+1); + } else { + memcpy(new_data,data,size-2); + new_data = yon_char_append(new_data,found+strlen(deleted)); + } + dict->data=(void*)(new_data); + free(data); + dict->flag1=1; + return 1; + } else return 0; +} + +/**yon_config_get_by_key(char *key) + * [EN] + * + * [RU] + * Возвращает значение параметра конфига с ключом [key] +*/ +void *yon_config_get_by_key(char *key){ + check_config{ + dictionary *dict = NULL; + for_dictionaries(dict, __yon__config__strings){ + if (strcmp(dict->key,key)==0){ + return dict->data; + } + } + } + return NULL; +} + +/**yon_config_get_key_by_data(char *data) + * [EN] + * + * [RU] + * Возвращает ключ параметра конфига со значением [data]. + * Если параметр с таким значением не найден, возвращается NULL +*/ +char *yon_config_get_key_by_data(char *data){ + check_config{ + dictionary *dict = NULL; + for_dictionaries(dict, __yon__config__strings){ + if (strcmp(((char*)dict->data),data)==0){ + return dict->key; + } + } + } + return NULL; +} + +/**yon_config_set(char *key, void *data) + * [EN] + * + * [RU] + * Производит поиск по конфигу и заменяет значение параметра с ключом [key] на новое значение [data]; +*/ +int yon_config_set(char *key, void *data){ + check_config{ + dictionary *dict = yon_dictionary_get(&__yon__config__strings,key); + dict->data=data; + return 1; + } else return 0; +} + +/**yon_config_clean() + * [EN] + * Erase all parameters from config; + * [RU] + * Удаляет все параметры из конфига; +*/ +int yon_config_clean(){ + check_config{ + __yon__config__strings = yon_dictionary_free_all(__yon__config__strings, NULL); + return 1; + } + else return 0; +} + +/**yon_config_register(char *key, void *data) + * [EN] + * + * [RU] + * Регистрирует новый параметр конфига. + * [key] - ключ параметра; + * [data] - значение параметра; +*/ +void yon_config_register(char *key, void *data){ + yon_dictionary_add_or_create_if_exists_with_data(__yon__config__strings,key,data); + __yon__config__strings->data_type=DICTIONARY_CHAR_TYPE; +} + +/**yon_config_load(char *command, int *str_len) + * [EN] + * + * [RU] + * Выполняет команду [command] и возвращает распаршеный результат выполнения команды. + * В [str_len] возвращается длина возвращаемого массива +*/ +config_str yon_config_load(char *command, int *str_len){ + FILE *output = popen(command, "r"); + char **output_strings = NULL; + output_strings = malloc(sizeof(char)); + int i = 0; + char str[4096]; + memset(str, 0, 4096); + while (fgets(str, 4096, output)) + { + if (strcmp(str, "") != 0) + { + output_strings = realloc(output_strings, sizeof(char *) * (i + 1)); + // printf("%s\n", str); + output_strings[i] = NULL; + output_strings[i] = yon_char_new(str); + memset(str, 0, 4096); + i++; + } + } + if (i>0){ + *str_len = i; + return output_strings; + } else{ + *str_len=-1; + return NULL; + } +} + +/**int yon_config_save(char *command) + * [EN] + * Saves config with [command] + * [RU] + * Выполняет команду [command], добавляя в конец все записи конфига в таком виде: + * [ПАРАМЕТР1]="[значения1]" [ПАРАМЕТР2]="[значения2]" +*/ +int yon_config_save(char *command){ + check_config{ + dictionary *dict = NULL; + for_dictionaries(dict,__yon__config__strings){ + command = yon_char_unite(command, " ", yon_dictionary_get_data(dict,char*), NULL); + } + if (popen(command, "r")) return 1; + else return 0; + } else return 0; +} + +/**yon_config_get_all(int *size) + * [EN] + * + * [RU] + * Возвращает массив со всеми параметрами конфига, оканчивающаяся NULL + * [size] - указатель, в который выгружается длина массива +*/ +config_str yon_config_get_all(int *size){ + check_config{ + *size = 1; + config_str conf = NULL; + dictionary *dict = NULL; + for_dictionaries(dict,__yon__config__strings){ + conf = yon_remalloc(conf,sizeof(char*)*(*size)); + conf[(*size)-1] = yon_char_unite(dict->key,"=",(char*)dict->data,NULL); + size++; + } + conf = yon_remalloc(conf,sizeof(char*)*(*size+1)); + conf[*size] = NULL; + return conf; + } else return NULL; +} + +/**[EN] + * int yon_config_save(char *command) + * Saves config with [command] + * [RU] + * Выполняет команду [command] +*/ +// int yon_config_save(char *command) +// { +// FILE *output = popen(command, "r"); +// return 1; +// } + +/**char *yon_config_get_parameter(config parameters, int size, char *param) + * [EN] + * Gets parameter [param] from parameter list [parameters] of size [size]; + * or NULL if nothing were found + * [RU] + * Возвращает параметр [param] из массива строк [parameters] размером [size] + * или NULL если такой не был найден +*/ +char *yon_config_get_parameter(config_str parameters, int size, char *param) +{ + if (param[0]==' ') + yon_char_divide_search(param," ",-1); + param=yon_char_divide_search(yon_char_new(param)," ",-1); + + char *str = NULL; + for (int j = 0; j < size; j++) + { + char *name = yon_char_divide_search(yon_char_new(parameters[j]), "=", 1); + if (name) + { + if (strcmp(name, param) == 0) + { + str = yon_char_divide_search(yon_char_new(parameters[j]), "\n", 1); + if (strcmp(str, "") != 0 && strcmp(str, "(null)") != 0) + return str; + else + return NULL; + } + } + } + return NULL; +} -int yon_launch_app(char *name){ - char *path=name; - thread_output *thread=malloc(sizeof(thread_output)); - thread->command=path; - thread->exitcode=malloc(sizeof(int)); - pthread_t thread_id; - pthread_create(&thread_id, NULL, (void*)yon_launch, thread); - return *thread->exitcode; -}; -int yon_launch_app_with_arguments(char *name, char *args){ - char *path=yon_char_get_augumented("/usr/bin/",name); - path=yon_char_get_augumented(path," "); - path=yon_char_get_augumented(path,args); +// terminal-using functions + +/**yon_launch_app_with_arguments(char *name, char *args) + * [EN] + * Execute [command] in separate thread; + * [RU] + * Выполнить команду [command] в отдельном потоке; +*/ +int yon_launch_app_with_arguments(char *name, char *args) +{ + char *path = yon_char_unite("/usr/bin/", name, " ", args,NULL); pthread_t thread_id; - thread_output *thread=malloc(sizeof(thread_output)); - thread->command=path; - thread->exitcode=malloc(sizeof(int)); - pthread_create(&thread_id, NULL, (void*)yon_launch, thread); - return *thread->exitcode; + char *command = NULL; + command = path; + pthread_create(&thread_id, NULL, (void *)yon_launch, command); }; - -int yon_launch(thread_output *thread){ - int a=0; - a=system(thread->command); - *thread->exitcode=a; - return *thread->exitcode; +/**yon_launch(char *command) + * [EN] + * Execute command [command] + * [RU] + * Выполнить команду [command] +*/ +void yon_launch(char *command) +{ + system(command); } +// Gtk functions -//Gtk functions #ifdef __GTK_H__ -// dictionary *yon_gtk_app_chooser_create(GtkBuilder *builder){ -// GtkWidget *chooserWindow=gtk_window_new(GTK_WINDOW_TOPLEVEL); -// GtkWidget *Box=gtk_box_new(GTK_ORIENTATION_VERTICAL,5); -// GtkWidget *Frame=gtk_frame_new(""); -// GtkWidget *Scroll=gtk_scrolled_window_new(NULL, gtk_adjustment_new(0,0,10000,1,10,100)); -// GtkWidget *PackBox=gtk_box_new(GTK_ORIENTATION_VERTICAL,5); -// GtkWidget *ButtonsBox=gtk_box_new(GTK_ORIENTATION_HORIZONTAL,5); -// GtkWidget *ButtonsPlaceBox=gtk_box_new(GTK_ORIENTATION_HORIZONTAL,5); - -// GtkWidget *CancelButton=gtk_button_new_with_label("Cancel"); -// GtkWidget *AcceptButton=gtk_button_new_with_label("Accept"); -// gtk_container_add(GTK_CONTAINER(chooserWindow),Box); -// gtk_box_pack_start(GTK_BOX(Box),Frame,1,1,0); -// gtk_container_add(GTK_CONTAINER(Frame),PackBox); -// gtk_box_pack_start(GTK_BOX(Box),ButtonsBox,0,0,0); -// gtk_box_pack_end(GTK_BOX(ButtonsBox),ButtonsPlaceBox,0,0,0); -// gtk_box_pack_end(GTK_BOX(ButtonsPlaceBox),AcceptButton,0,0,0); -// gtk_box_pack_end(GTK_BOX(ButtonsPlaceBox),CancelButton,0,0,0); -// gtk_box_pack_start(GTK_BOX(PackBox),(GtkWidget*)yon_gtk_app_chooser_apps_create(builder),0,0,0); -// gtk_widget_show_all(chooserWindow); -// } + +static render_data render; + +#ifdef VTE_TERMINAL + +static void child_ready(VteTerminal *terminal, GPid pid, GError *error, gpointer user_data) +{ + if (!terminal) return; + if (pid == -1) printf("Error\n\n\n"); + else vte_terminal_feed_child(VTE_TERMINAL(terminal),(char*)user_data,strlen((char*)user_data)); +} /** - * yon_iv_segment_create: - * connect_to - dictionary, in the end of which new one will be connected; - * name - name of this segment, renders on label; - * categories - desktop file categories that application NEEDS to have to render in that category; - * segment_icon_name - icon name for this section; - * builder - newly allocated builder with glade file connected where template widgets are stored: - * - templateAppsIconView - setted up icon view; - * - templateAppsPack - setted up container for every template widget; - * - templateAppsImage - image for rendering section image; - * - templateAppsLabel - label for rendering section name; -*/ -// dictionary *yon_iv_segment_create(dictionary *connect_to, char *name, char *categories, char *segment_icon_name){ -// IVSegment *segment=malloc(sizeof(IVSegment)); -// segment->name=name; -// segment->categories=categories; -// GtkBuilder *builder=gtk_builder_new_from_string(return_app_string(),-1); -// GtkWidget *iv=yon_gtk_builder_get_widget(builder,"templateAppsIconView"); -// GtkWidget *expander=yon_gtk_builder_get_widget(builder,"templateAppsPack"); -// GtkWidget *image=yon_gtk_builder_get_widget(builder,"templateAppsImage"); -// GtkWidget *label=yon_gtk_builder_get_widget(builder,"templateAppsLabel"); -// GtkIconTheme *theme=gtk_icon_theme_get_default(); -// gtk_image_set_from_pixbuf(GTK_IMAGE(image),gtk_icon_theme_load_icon_for_scale(theme,segment_icon_name,20,1,GTK_ICON_LOOKUP_FORCE_SVG,NULL)); -// gtk_label_set_text(GTK_LABEL(label),name); -// GtkListStore *ls=GTK_LIST_STORE(gtk_builder_get_object(builder,"liststore5")); -// // g_signal_connect(G_OBJECT(iv), "item-activated", G_CALLBACK(on_activate), videoconfig.applist); -// segment->Expander=expander; -// segment->IV=iv; -// segment->LS=ls; -// segment->Image=image; -// dictionary *dict=NULL; -// if (connect_to) { -// // connect_to=yon_dictionary_get_last(connect_to); -// dict=yon_dictionary_create_with_data_connected(connect_to,name,segment); -// } else -// dict=yon_dictionary_create_with_data(name,segment); -// return dict; -// } + * void yon_terminal_integrated_launch(GtkWidget *place_to_show, void *endwork_function, void* endwork_function_argument) + * [EN] + * launches terminal with specific [command], + * terminal is shown in [place_to_show] container, + * after terminal done its work [endwork_function] is called with [endwork_function_argument] argument. + * [RU] + * Запускает терминал с командой [command], + * терминал добавляется в контейнер [place_to_show] виджета, + * после завершения работы терминала вызывается функция [endwork_function] с аргументом [endwork_function_argument]. +*/ +void yon_terminal_integrated_launch(GtkWidget *place_to_show, char* command, void *endwork_function, void* endwork_function_argument){ + char **commands=new_arr(char*,2); + gchar **envp = g_get_environ(); + commands[0]=(gchar *)g_strdup(g_environ_getenv(envp, "SHELL")); + commands[1]=NULL; + char **env=new_arr(char*,2); + env[0]=""; + env[1]=NULL; + GtkWidget *terminal = vte_terminal_new(); + vte_terminal_set_size(VTE_TERMINAL(terminal),10,15); + VtePty *pty = vte_pty_new_sync(VTE_PTY_DEFAULT,NULL,NULL); + vte_terminal_set_pty(VTE_TERMINAL(terminal),pty); + gtk_container_add(GTK_CONTAINER(place_to_show),terminal); + char *install_command=yon_char_unite("tput cup 0 0 && tput ed; ",command," ; sleep 5;exit 0","\n",NULL); + printf("%s\n",install_command); + if(endwork_function) + g_signal_connect(G_OBJECT(terminal), "child-exited", G_CALLBACK(endwork_function), endwork_function_argument); + vte_terminal_spawn_async(VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + NULL, + commands, + NULL, + 0, + NULL, NULL, + NULL, + -1, + NULL, + child_ready, + install_command); + vte_pty_spawn_async(pty, + NULL, + commands, + NULL, + 0, + NULL, NULL, + NULL, + -1, + NULL, + NULL, + NULL); + vte_terminal_set_scrollback_lines(VTE_TERMINAL(terminal), -1); + vte_terminal_set_scroll_on_output(VTE_TERMINAL(terminal), TRUE); + vte_terminal_set_scroll_on_keystroke(VTE_TERMINAL(terminal), TRUE); + gtk_widget_show_all(terminal); + } -// GtkWidget *yon_gtk_app_chooser_apps_create(){ -// GtkWidget *Box=gtk_box_new(GTK_ORIENTATION_VERTICAL,0); -// dictionary *IVS=yon_iv_segment_create(NULL, "Graphics", "", "dialog-yes-symbolic"); -// yon_iv_segment_create(IVS, "Tools", "", "dialog-yes-symbolic"); -// yon_iv_segment_create(IVS, "Internet", "", "dialog-yes-symbolic"); -// yon_iv_segment_create(IVS, "Multimedia", "", "dialog-yes-symbolic"); -// yon_iv_segment_create(IVS, "Settings", "", "dialog-yes-symbolic"); -// yon_iv_segment_create(IVS, "Education", "", "dialog-yes-symbolic"); -// yon_iv_segment_create(IVS, "Office", "", "dialog-yes-symbolic"); -// yon_iv_segment_create(IVS, "Other", "", "dialog-yes-symbolic"); -// yon_iv_segment_create(IVS, "Development", "", "dialog-yes-symbolic"); -// yon_iv_segment_create(IVS, "System", "", "dialog-yes-symbolic"); -// dictionary *nd; -// for_dictionaries(nd,IVS){ -// gtk_box_pack_start(GTK_BOX(Box),((IVSegment*)nd->data)->Expander,0,0,0); -// } -// return Box; - -// } +/**yon_terminal_integrated_start(GtkWidget *terminal, char* command, void *endwork_function, void* endwork_function_argument) + * [EN] + * launches terminal with specific [command], + * terminal is shown in [place_to_show] container, + * after terminal done its work [endwork_function] is called with [endwork_function_argument] argument. + * [RU] + * Запускает терминал с командой [command], + * терминал добавляется в контейнер [place_to_show] виджета, + * после завершения работы терминала вызывается функция [endwork_function] с аргументом [endwork_function_argument]. +*/ +void yon_terminal_integrated_start(GtkWidget *terminal, char* command, void *endwork_function, void* endwork_function_argument){ + char **commands=new_arr(char*,2); + gchar **envp = g_get_environ(); + commands[0]=(gchar *)g_strdup(g_environ_getenv(envp, "SHELL")); + commands[1]=NULL; + char **env=new_arr(char*,2); + env[0]=""; + env[1]=NULL; + vte_terminal_set_size(VTE_TERMINAL(terminal),10,15); + VtePty *pty = vte_pty_new_sync(VTE_PTY_DEFAULT,NULL,NULL); + vte_terminal_set_pty(VTE_TERMINAL(terminal),pty); + char *install_command=yon_char_unite("tput cup 0 0 && tput ed; ",command," ; sleep 5;exit 0","\n",NULL); + if(endwork_function) + g_signal_connect(G_OBJECT(terminal), "child-exited", G_CALLBACK(endwork_function), endwork_function_argument); + vte_terminal_spawn_async(VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + NULL, + commands, + NULL, + 0, + NULL, NULL, + NULL, + -1, + NULL, + child_ready, + install_command); + vte_pty_spawn_async(pty, + NULL, + commands, + NULL, + 0, + NULL, NULL, + NULL, + -1, + NULL, + NULL, + NULL); + vte_terminal_set_scrollback_lines(VTE_TERMINAL(terminal), 100); + vte_terminal_set_scroll_on_output(VTE_TERMINAL(terminal), TRUE); + vte_terminal_set_scroll_on_keystroke(VTE_TERMINAL(terminal), TRUE); + gtk_widget_show_all(terminal); + } +#endif + // Window config functions + #define check_window_config_setup if(__yon_window_config_target_window) + struct { + int x; + int y; + int width; + int height; + int fullscreen; + } __yon_main_window_config; + static GtkWindow *__yon_window_config_target_window = NULL; + static GKeyFile *__yon_window_config_file = NULL; + static char *__yon_window_config_path = NULL; + + void yon_window_config_save(){ + g_key_file_set_integer(__yon_window_config_file,"window","WindowPosX",__yon_main_window_config.x); + g_key_file_set_integer(__yon_window_config_file,"window","WindowPosY",__yon_main_window_config.y); + g_key_file_set_integer(__yon_window_config_file,"window","WindowWidth",__yon_main_window_config.width); + g_key_file_set_integer(__yon_window_config_file,"window","WindowHeight",__yon_main_window_config.height); + g_key_file_set_integer(__yon_window_config_file,"window","fullscreen",__yon_main_window_config.fullscreen); + g_key_file_save_to_file(__yon_window_config_file,__yon_window_config_path,NULL); + } + + void yon_get_is_fullscreen(){ + gtk_window_is_maximized(__yon_window_config_target_window); + __yon_main_window_config.fullscreen = gtk_window_is_maximized(__yon_window_config_target_window); + } -// GtkWidget *yon_gtk_socket_create_new_with_connect(GtkWidget *container, gpointer data){ -// GtkWidget *socket; -// socket = gtk_socket_new(); -// g_signal_connect(G_OBJECT(socket),"plug-added",G_CALLBACK(yon_on_plug_added),data); -// g_signal_connect(G_OBJECT(socket),"plug-removed",G_CALLBACK(yon_on_plug_removed),data); -// g_signal_connect(G_OBJECT(socket),"destroy",G_CALLBACK(yon_on_plug_removed),data); -// gtk_box_pack_start(GTK_BOX(container),socket,1,1,0); -// return socket; -// }; -int yon_dictionary_gtk_pack_start_multiple_widgets(dictionary *dict, GtkWidget *destination, gboolean expand, gboolean fill, int padding){ - for (dictionary *dct=dict->first; dct!=NULL;dct=dct->next){ - gtk_box_pack_start(GTK_BOX(destination),(GtkWidget*)dct->data,expand,fill,padding); + void yon_on_configured_window_destroy(GtkWidget* self,GdkEvent* event){ + check_window_config_setup{ + yon_get_is_fullscreen(); + yon_window_config_save(); + } + gtk_main_quit(); } + + void __yon_window_config_on_resize(){ + int max=0; + max=gtk_window_is_maximized(__yon_window_config_target_window); + if(max==0){ + printf("resized\n"); + gtk_window_get_size(__yon_window_config_target_window,&__yon_main_window_config.width,&__yon_main_window_config.height); + gtk_window_get_position(__yon_window_config_target_window,&__yon_main_window_config.x,&__yon_main_window_config.y); + } + } + + void yon_window_config_setup(GtkWindow *window){ + __yon_window_config_target_window = window; + g_signal_connect(G_OBJECT(window),"delete-event",G_CALLBACK(yon_on_configured_window_destroy),NULL); + g_signal_connect(G_OBJECT(window),"check-resize"/*"configure-event"*/,G_CALLBACK(__yon_window_config_on_resize),NULL); + } + + void _yon_maximize(void *data){ + g_usleep(G_USEC_PER_SEC/10); + if(__yon_main_window_config.fullscreen ==1) gtk_window_maximize(__yon_window_config_target_window); + } + + int yon_window_config_load(char *path){ + __yon_window_config_file = g_key_file_new(); + __yon_window_config_path=yon_char_new(path); + if (!g_key_file_load_from_file(__yon_window_config_file,__yon_window_config_path,G_KEY_FILE_NONE,NULL)){ + struct stat st; + int size; + config_str conf = yon_char_parse(yon_char_new(__yon_window_config_path),&size,"/"); + char *path = yon_char_unite(conf[0],"/",conf[1],"/",conf[2],"/",conf[3],"/",conf[4],"/",NULL); + if (stat(path, &st) == -1) { + mkdir(path, 0777); + } + FILE *fp; + fp=fopen(__yon_window_config_path,"w"); + fclose(fp); + g_key_file_load_from_file(__yon_window_config_file,__yon_window_config_path,G_KEY_FILE_NONE,NULL); + } + __yon_main_window_config.x = g_key_file_get_integer(__yon_window_config_file,"window","WindowPosX",NULL); + __yon_main_window_config.y = g_key_file_get_integer(__yon_window_config_file,"window","WindowPosY",NULL); + __yon_main_window_config.width = g_key_file_get_integer(__yon_window_config_file,"window","WindowWidth",NULL); + __yon_main_window_config.height = g_key_file_get_integer(__yon_window_config_file,"window","WindowHeight",NULL); + __yon_main_window_config.fullscreen = g_key_file_get_integer(__yon_window_config_file,"window","fullscreen",NULL); + if (__yon_main_window_config.width==0) __yon_main_window_config.width=800; + if (__yon_main_window_config.height==0) __yon_main_window_config.height=600; + gtk_window_resize(__yon_window_config_target_window,__yon_main_window_config.width,__yon_main_window_config.height); + gtk_window_move(__yon_window_config_target_window,__yon_main_window_config.x,__yon_main_window_config.y); + pthread_t tid; + pthread_create(&tid,NULL,(void *)_yon_maximize,NULL); + return 1; + } + + void yon_window_config_apply(){ + dictionary *dict=NULL; + gtk_window_move(__yon_window_config_target_window,__yon_main_window_config.x,__yon_main_window_config.y); + gtk_window_resize(__yon_window_config_target_window,__yon_main_window_config.width,__yon_main_window_config.height); + } + +int yon_gtk_combo_box_text_fill(GtkWidget *combo, config_str parameters,int size){ + if (combo&¶meters){ + for (int i=0;ifirst; dct!=NULL;dct=dct->next){ - gtk_box_pack_end(GTK_BOX(destination),(GtkWidget*)dct->data,expand,fill,padding); - } +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; } -void _yon_ubl_header_setup(GtkWidget *Overlay, GtkWidget *Head, GtkWidget *Image, char *image_path){ - gtk_overlay_add_overlay(GTK_OVERLAY(Overlay),Head); - gtk_image_set_from_file(GTK_IMAGE(Image),image_path); + +void _yon_ubl_header_setup(GtkWidget *Overlay, GtkWidget *Head, GtkWidget *Image, char *image_path) +{ + gtk_overlay_add_overlay(GTK_OVERLAY(Overlay), Head); + gtk_image_set_from_file(GTK_IMAGE(Image), image_path); +} + +void _yon_ubl_header_setup_resource(GtkWidget *Overlay, GtkWidget *Head, GtkWidget *Image, char *image_path) +{ + gtk_overlay_add_overlay(GTK_OVERLAY(Overlay), Head); + gtk_image_set_from_resource(GTK_IMAGE(Image), image_path); } -void _yon_ubl_status_box_render(GtkWidget *StatusBox, GtkWidget *StatusIcon, GtkWidget *StatusLabel, char *IconName, char* StatusText, BACKGROUND_IMAGE_TYPE BackgroundClass){ - GtkIconTheme *ictheme=gtk_icon_theme_get_default(); - GError *err=NULL; - gtk_image_set_from_pixbuf(GTK_IMAGE(StatusIcon),gtk_icon_theme_load_icon_for_scale(ictheme,IconName,25,1,GTK_ICON_LOOKUP_FORCE_SIZE,&err)); - if (err){ - printf("%s\n",err->message); +int yon_ubl_status_box_setup(GtkWidget *icon, GtkWidget *box, GtkWidget *label) +{ + if(icon&&box&&label){ + render.icon=icon; + render.box=box; + render.label=label; + return 1; + } else return 0; +} + +void _yon_ubl_status_box_render(char *text, BACKGROUND_IMAGE_TYPE type) +{ + render_data data = render; + GtkIconTheme *ictheme = gtk_icon_theme_get_default(); + GError *err = NULL; + if (err) + { + printf("%s\n", err->message); g_error_free(err); } - gtk_label_set_text(GTK_LABEL(StatusLabel),StatusText); - if (BackgroundClass==BACKGROUND_IMAGE_SUCCESS_TYPE){ - gtk_style_context_add_class(gtk_widget_get_style_context(StatusBox),"boxInfoMessOK"); - } else if (BackgroundClass==BACKGROUND_IMAGE_FAIL_TYPE){ - gtk_style_context_add_class(gtk_widget_get_style_context(StatusBox),"boxInfoMessError"); + if (type == BACKGROUND_IMAGE_SUCCESS_TYPE||! type) + { + gtk_style_context_remove_class(gtk_widget_get_style_context(data.box), "boxInfoMessError"); + gtk_style_context_add_class(gtk_widget_get_style_context(data.box), "boxInfoMessOK"); + gtk_image_set_from_pixbuf(GTK_IMAGE(data.icon), gtk_icon_theme_load_icon_for_scale(ictheme, "com.ublinux.ubl-settings-video.checked", 25, 1, GTK_ICON_LOOKUP_FORCE_SIZE, &err)); + } + else if (type == BACKGROUND_IMAGE_FAIL_TYPE) + { + gtk_style_context_remove_class(gtk_widget_get_style_context(data.box), "boxInfoMessOK"); + gtk_style_context_add_class(gtk_widget_get_style_context(data.box), "boxInfoMessError"); + gtk_image_set_from_pixbuf(GTK_IMAGE(data.icon), gtk_icon_theme_load_icon_for_scale(ictheme, "com.ublinux.ubl-settings-video.warning", 25, 1, GTK_ICON_LOOKUP_FORCE_SIZE, &err)); } + if (text) + gtk_label_set_text(GTK_LABEL(data.label), text); +} + +void yon_ubl_status_box_render(char *text, BACKGROUND_IMAGE_TYPE type){ + _yon_ubl_status_box_render(text,type); } + +/**yon_ubl_setup_sockets(GtkWidget *main_window, GtkWidget *left_window, GtkWidget *right_window, int socket_main_id, int socket_left_id, int socket_right_id) + * [EN] + * Set up plugs for using with GtkSockets insine ubl-settings-manager. + * [main_window] is container widget, which holds main application functionality. + * [left_window] is container widget, which holds widgets, have to be shown at left part of ubl-settings-manager header. + * [right_window] is container widget, which holds widgets, have to be shown at right part of ubl-settings-manager header. + * [socket_main_id] is id of socket for [main_window]. + * [socket_left_id] is id of socket for [left_window]. + * [socket_right_id] is id of socket for [right_window]. + * [RU] + * Настраивает плаги для работы с сокетами в утилите ubl-settings-manager. + * [main_window] - контейнер основного интерфейса приложения. + * [left_window] - контейнер для виджетов которые должны отображаться в левой части шапки ubl-settings-manager. + * [right_window] - контейнер для виджетов которые должны отображаться в правой части шапки ubl-settings-manager. + * [socket_main_id] - id сокета для [main_window]. + * [socket_left_id] - id сокета для [left_window]. + * [socket_right_id] - id сокета для [right_window]. +*/ +void yon_ubl_setup_sockets(GtkWidget *main_window, GtkWidget *left_window, GtkWidget *right_window, int socket_main_id, int socket_left_id, int socket_right_id){ + if (main_window&&socket_main_id>-1){ + gtk_widget_hide(gtk_widget_get_toplevel(main_window)); + GtkWidget *plug_main=gtk_plug_new(socket_main_id); + GtkWidget *plug_left=NULL; + GtkWidget *plug_right=NULL; + GtkWidget *box=NULL; + g_signal_connect(G_OBJECT(plug_main), "destroy", G_CALLBACK(gtk_main_quit),NULL); + if (socket_left_id>-1&&left_window){ + plug_left=gtk_plug_new(socket_left_id); + g_object_ref(left_window); + gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(left_window)),left_window); + gtk_container_add(GTK_CONTAINER(plug_left),left_window); + gtk_style_context_add_class(gtk_widget_get_style_context(plug_left),"primary-toolbar"); + gtk_style_context_add_class(gtk_widget_get_style_context(left_window),"button"); + gtk_style_context_add_class(gtk_widget_get_style_context(left_window),"opacited"); + gtk_style_context_add_class(gtk_widget_get_style_context(left_window),"color"); + gtk_style_context_add_class(gtk_widget_get_style_context(plug_left),"noborder"); + gtk_widget_show(plug_left); + } + else if (left_window){ + if (box==NULL){ + box=gtk_box_new(GTK_ORIENTATION_HORIZONTAL,5); + gtk_box_pack_start(GTK_BOX(main_window),box,0,0,5); + gtk_box_reorder_child(GTK_BOX(main_window),box,0); + gtk_widget_show(box); + } + gtk_style_context_add_class(gtk_widget_get_style_context(left_window),"inherited"); + gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(left_window)),left_window); + gtk_box_pack_end(GTK_BOX(box),left_window,0,0,5); + } + if (socket_right_id>-1&&right_window){ + plug_right=gtk_plug_new(socket_right_id); + g_object_ref(right_window); + gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(right_window)),right_window); + gtk_container_add(GTK_CONTAINER(plug_right),right_window); + gtk_style_context_add_class(gtk_widget_get_style_context(plug_right),"primary-toolbar"); + gtk_style_context_add_class(gtk_widget_get_style_context(right_window),"button"); + gtk_style_context_add_class(gtk_widget_get_style_context(right_window),"opacited"); + gtk_style_context_add_class(gtk_widget_get_style_context(right_window),"color"); + gtk_style_context_add_class(gtk_widget_get_style_context(plug_right),"noborder"); + gtk_widget_show(plug_right); + } + else if (right_window){ + if (box==NULL){ + box=gtk_box_new(GTK_ORIENTATION_HORIZONTAL,5); + gtk_box_pack_start(GTK_BOX(main_window),box,0,0,5); + gtk_box_reorder_child(GTK_BOX(main_window),box,0); + gtk_widget_show(box); + } + gtk_style_context_add_class(gtk_widget_get_style_context(right_window),"inherited"); + gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(right_window)),right_window); + gtk_box_pack_start(GTK_BOX(box),right_window,0,0,5); + } + g_object_ref(main_window); + gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(main_window)),main_window); + gtk_container_add(GTK_CONTAINER(plug_main),main_window); + gtk_widget_show(plug_main); + } +} + +#ifdef WEBKIT_FOUND + +/**yon_ubl_browser_window_open(char *link, char *browser_window_name) + * [EN] + * Launches integrated browser window, named [browser_window_name] at header with [link]. + * [RU] + * Открывает встроенный браузер с именем [browser_window_name] и показываемой страницей по ссылке [link] +*/ +void yon_ubl_browser_window_open(char *link, char *browser_window_name){ + GtkWidget *browser=gtk_window_new(GTK_WINDOW_TOPLEVEL); + GtkWidget *web_place=gtk_box_new(GTK_ORIENTATION_VERTICAL,0); + GtkWidget *header=gtk_header_bar_new(); + GtkWidget *header_label=gtk_label_new(browser_window_name); + GtkWidget *WebView=webkit_web_view_new(); + gtk_container_add(GTK_CONTAINER(browser),web_place); + gtk_window_set_titlebar(GTK_WINDOW(browser),header); + gtk_window_set_title(GTK_WINDOW(browser),browser_window_name); + gtk_widget_set_size_request(browser,800,600); + gtk_header_bar_set_custom_title(GTK_HEADER_BAR(header),header_label); + gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(header),1); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(WebView),link); + gtk_box_pack_start(GTK_BOX(web_place),WebView,1,1,0); + gtk_widget_show_all(browser); +} +#else + +/**yon_ubl_browser_window_open(char *link, char *browser_window_name) + * [EN] + * Launches browser with [link]. + * [browser_window_name] is't used. It's needed for compatibility with webkit version of that function. + * [RU] + * Открывает браузер со страницей по ссылке [link] + * [browser_window_name] не используется. Нужна для совместимости с webkit версией этой функции. +*/ +void yon_ubl_browser_window_open(char *link, char *browser_window_name){ + char *user=getenv("SUDO_USER"); + if (!user) + user=getlogin(); + char *command=yon_char_unite("sudo -u ",user," xdg-open ", link,NULL); + yon_launch_app(command); +} +#endif + #endif \ No newline at end of file diff --git a/source/ubl-utils.h b/source/ubl-utils.h index 444fd93..8bc463d 100644 --- a/source/ubl-utils.h +++ b/source/ubl-utils.h @@ -3,162 +3,337 @@ #include #include #include +#include #include #include #include +#include +#include #include #include #include +#include "ubl-cmake.h" +#ifdef WEBKIT_FOUND + #include +#endif #define DesktopPath "/usr/share/applications/" -#define for_dictionaries(obj,obj1) for(obj=obj1->first;obj!=NULL;obj=obj->next) +#define for_dictionaries(obj, obj1) for (obj = obj1->first; obj != NULL; obj = obj->next) -typedef enum { - DICTIONARY_ACTION_WIDGETS_TYPE, - DICTIONARY_IVGRAPHICALS_TYPE, - DICTIONARY_OTHER_TYPE +#define new(type) malloc(sizeof(type)) +#define new_arr(type,size) malloc(sizeof(type)*size) -} DICT_TYPE; +typedef enum +{ + #ifdef __GTK_H__ + DICTIONARY_GTK_WIDGETS_TYPE, + #endif + DICTIONARY_OTHER_TYPE=0, + DICTIONARY_CHAR_TYPE, + DICTIONARY_INT_TYPE, + DICTIONARY_BOOL_TYPE, -typedef struct { - char *command; - int *exitcode; -} thread_output; +} DICT_TYPE; -typedef struct dictionary { +typedef struct dictionary +{ char *key; void *data; struct dictionary *next; struct dictionary *prev; struct dictionary *first; DICT_TYPE data_type; + int flag1; } dictionary; -typedef struct apps{ - char *Name; - int Type; - char *Categories; - char *Exec; - char *Icon; - int Pluggable; - int DualPluggable; - } apps; - - -//dictionary functions - -dictionary *yon_dictionary_create_empty(); - -dictionary * yon_dictionary_create_conneced(dictionary *targetdict); +typedef struct apps +{ + char *Name; + int Type; + char *Categories; + char *Exec; + char *Icon; + int Pluggable; + int DualPluggable; +} apps; + +typedef char** config_str; + +static dictionary *__yon__config__strings = NULL; +#define check_config if(__yon__config__strings&&__yon__config__strings->data_type==DICTIONARY_CHAR_TYPE) + +#define config(key) yon_config_get_by_key(key) + +#define for_config dictionary temp = NULL; for_dictionary(temp,__yon__config__strings) + +#define yon_remalloc(pointer, size) (!pointer) ? malloc(size) : realloc(pointer, size) +// dictionary functions + +/**yon_dictionary_get_data(dictionary, type) + * [EN] + * Gets data from dictionary. + * [dictionary] is dictionary, from which data should be extracted; + * [type] is type of data, [dictionary] contains. + * [RU] + * Возвращает данные из словаря. + * [dictionary] - словарь из которого достаются данные. + * [type] - тип данных, хранящихся в словаре [dictionary]. +*/ +#define yon_dictionary_get_data(dictionary, type) ((type)dictionary->data) + +/**yon_dictionary_add_or_create_if_exists_with_data(dict,key,data) + * [EN] + * + * [RU] + * Добавляет элемент словаря в конец словаря [dict] c ключом [key] и данными [data]. + * Если словарь не существует, создаёт его +*/ +#define yon_dictionary_add_or_create_if_exists_with_data(dict,key,data) {if (!dict) dict=yon_dictionary_new_with_data(key,data); \ + else dict=yon_dictionary_append_with_data(dict,key,data);} + +dictionary *yon_dictionary_new(); + +dictionary *yon_dictionary_append(dictionary *targetdict); dictionary *yon_dictionary_get_last(dictionary *dict); -dictionary *yon_dictionary_switch_places(dictionary *dict,int aim); +dictionary *yon_dictionary_swap(dictionary *dict, int aim); void yon_dictionary_make_first(dictionary *dict); void yon_dictionary_make_nth(dictionary *dict, int nth); -dictionary *yon_dictionary_create_with_data(char *key, void *data); +dictionary *yon_dictionary_new_with_data(char *key, void *data); -dictionary *yon_dictionary_create_with_data_connected(dictionary *dict, char *key, void *data); +dictionary *yon_dictionary_append_with_data(dictionary *dict, char *key, void *data); dictionary *yon_dictionary_connect(dictionary *old, dictionary *toconnect); -dictionary *yon_dictionary_find(dictionary **dict, char *key); +dictionary *yon_dictionary_get(dictionary **dict, char *key); dictionary *yon_dictionary_rip(dictionary *dict); dictionary *yon_dictionary_get_nth(dictionary *dict, int place); -//char functions +void *yon_dictionary_free_all(dictionary *dictionary,void (data_manipulation)(void*)); + +// char functions -char *yon_char_get_augumented(char *source, char *append); +char *yon_char_append(char *source, char *append); char *yon_char_new(char *chr); +char *yon_char_unite(char *source, ...); + char *yon_cut(char *source, int size, int startpos); char *yon_char_divide(char *source, int dividepos); -char *yon_char_divide_search(char *source, char* dividepos, int delete_divider); +char *yon_char_divide_search(char *source, char *dividepos, int delete_divider); char *yon_char_from_int(int int_to_convert); +char *yon_char_replace(char *source, char *find, char*replace); + +char **yon_char_parse(char *parameters, int *size, char *divider); + +char **yon_char_parsed_rip(char **char_string, int *size, int item_to_delete); +int yon_char_parsed_check_exist(char **parameters, int size, char *param); -//parsing functions +int yon_char_find_count(char *source, char *find); + +int yon_char_parsed_includes_char_parsed (config_str source, config_str to_check, int source_size, int check_size); + +config_str yon_char_parsed_new (int *size, ...); + +void yon_char_parsed_copy(config_str *source, config_str *to_copy); + +config_str yon_char_parsed_append(config_str parsed, int *size, char *string); + +int yon_ubl_check_root(); + +char *yon_ubl_root_user_get(); + +// parsing functions + +config_str philos_list_user(int* size); apps *yon_apps_scan_and_parse_desktops(int *sizef); +void yon_apps_sort(apps *applist, int size); -void yon_apps_sort(apps *applist,int size); +apps *yon_apps_get_by_name(apps *applist, char *name, int size); +config_str yon_config_load(char *command, int *str_len); -apps *yon_apps_get_by_name(apps *applist,char *name, int size); +int yon_config_save(char *command); +char *yon_config_get_parameter(config_str parameters, int size, char *param); -//terminal-using functions +int yon_config_load_register(char *command); +int yon_config_remove_by_key(char *key); +int yon_config_remove_by_data(void *data); -int yon_launch_app(char *name); +int yon_config_remove_element(char *key, char *deleted); +void *yon_config_get_by_key(char *key); -int yon_launch_app_with_arguments(char *name, char *args); +char *yon_config_get_key_by_data(char *data); + +int yon_config_set(char *key, void *data); +int yon_config_clean(); -int yon_launch(thread_output *thread); +void yon_config_register(char *key, void *data); -//Gtk functions +config_str yon_config_get_all(); + +// terminal-using functions + +int yon_launch_app_with_arguments(char *name, char *args); + +void yon_launch(char *command); + +// Gtk functions #ifdef __GTK_H__ +#ifdef VTE_TERMINAL +void yon_terminal_integrated_launch(GtkWidget *place_to_show, char* command, void *endwork_function, void* endwork_function_argument); -#define yon_gtk_builder_get_widget(obj,obj2) GTK_WIDGET(gtk_builder_get_object(obj,obj2)) +void yon_terminal_integrated_start(GtkWidget *terminal, char* command, void *endwork_function, void* endwork_function_argument); +#endif -typedef struct { +/**yon_gtk_builder_get_widget(builder, widget_name) + * [EN] + * Returns GtkWidget from GtkBuilder *[builder]. + * [builder] is GtkBuilder*; + * [widget_name] is id of widget; +*/ +#define yon_gtk_builder_get_widget(builder, widget_name) GTK_WIDGET(gtk_builder_get_object(builder, widget_name)) + +typedef struct +{ GtkWidget *Icon; GtkWidget *Label; GtkWidget *IconView; GtkListStore *List; } expander_icon_view; +void yon_window_config_setup(GtkWindow *window); -// GtkWidget *yon_gtk_app_chooser_apps_create(); - -// dictionary *yon_gtk_app_chooser_create(); +int yon_window_config_load(char *path); -// expander_icon_view yon_gtk_icon_view_expander_create(GtkWidget *pack, ...); +int yon_gtk_combo_box_fill(GtkWidget *combo, char **parameters,int size); -GtkWidget *yon_gtk_socket_create_new_with_connect(GtkWidget *container, gpointer data); +int yon_gtk_combo_box_text_find(GtkWidget *combo_box, char *text_to_find); int yon_gtk_icon_view_hide_empty(dictionary *icon_view_segment); -int yon_dictionary_gtk_pack_start_multiple_widgets(dictionary *dict, GtkWidget *destination, gboolean expand, gboolean fill, int padding); -int yon_dictionary_gtk_pack_end_multiple_widgets(dictionary *dict, GtkWidget *destination, gboolean expand, gboolean fill, int padding); +int yon_dictionary_gtk_pack_start_multiple_widgets(GtkBox *destination, gboolean expand, gboolean fill, int padding, ...); -//uninitialised +int yon_dictionary_gtk_pack_end_multiple_widgets(GtkBox *destination, gboolean expand, gboolean fill, int padding, ...); -void yon_on_plug_added(GtkSocket* self, gpointer user_data); -void yon_on_plug_removed(GtkSocket* self, gpointer user_data); -#endif -typedef enum { +typedef enum +{ BACKGROUND_IMAGE_SUCCESS_TYPE, BACKGROUND_IMAGE_FAIL_TYPE } BACKGROUND_IMAGE_TYPE; + +typedef struct { + BACKGROUND_IMAGE_TYPE type; + GtkWidget *icon; + GtkWidget *box; + GtkWidget *label; + char* text_to_render; +} render_data; + + +/**yon_ubl_status_box_setup(render,icon,box,label) + * [EN] + * Sets up [render] structure of type render_data. + * [icon] is GtkImage widget of status box for showing status icons; + * [box] is GtkBox widget of status box for showing status color; + * [label] is GtkLabel widget of status box for showing status text; + * [RU] + * Настраивает структуру [render] типа render_data. + * [icon] - виджет типа GtkIcon в котором будут отображаться статусные иконки; + * [box] - виджет типа GtkBox в котором будет отображаться цвет статуса; + * [label] - виджет типа GtkLabel в котором будет отображаться текст статусного сообщения; +*/ +int yon_ubl_status_box_setup(GtkWidget *icon, GtkWidget *box, GtkWidget *label); + +/**yon_ubl_status_box_render(render,text,type) + * [EN] + * Renders message in status box; + * [render] is render_data structure of status box; + * [text] is text to be shown in status box; + * [type] if type of message. Can be BACKGROUND_IMAGE_FAIL_TYPE or BACKGROUND_IMAGE_SUCCESS_TYPE + * [RU] + * Отображает сообщение в статусном окне. + * [render] - структура типа render_data для нужного статусного окна; + * [text] - текст, отображаемый в статусном окне; + * [type] - тип сообщения. Может быть: + * BACKGROUND_IMAGE_FAIL_TYPE (красный фон,иконка - восклицательный знак) + * или + * BACKGROUND_IMAGE_SUCCESS_TYPE (Жёлтный фон, иконка - галка) +*/ +void yon_ubl_status_box_render(char *text, BACKGROUND_IMAGE_TYPE type); + #ifdef __cplusplus -#define yon_ubl_header_setup(overlay,head,image,imag_path) _yon_ubl_header_setup(GTK_WIDGET(overlay.gobj()),GTK_WIDGET(head.gobj()),GTK_WIDGET(image.gobj()),(char*)imag_path) -#define yon_ubl_status_box_render(statusbox, statusicon, statuslabel, iconname, statustext, backgroundclass) _yon_ubl_status_box_render(GTK_WIDGET(statusbox.gobj()), GTK_WIDGET(statusicon.gobj()), GTK_WIDGET(statuslabel.gobj()), (char*)iconname, (char*)statustext, backgroundclass) + +/**yon_ubl_header_setup(overlay, head, image, imag_path) + * [EN] + * Sets up header of app. + * [overlay] is overlay for app header; + * [head] is box of header, which connects to [overlay] + * [image] is header background image; + * [imag_path] is path of image, shown in [image] + * [RU] + * Настраивает заголовок приложения. + * [overlay] - оверлей заголовка приложения; + * [head] - шапка заголовка, присоединяемая к [overlay] + * [image] - виджет картинки для заднего фона; + * [imag_path] - путь до картинки, загружаемой в [image] +*/ +#define yon_ubl_header_setup(overlay, head, image, imag_path) _yon_ubl_header_setup(GTK_WIDGET(overlay.gobj()), GTK_WIDGET(head.gobj()), GTK_WIDGET(image.gobj()), (char *)imag_path) #else -#define yon_ubl_header_setup(overlay,head,image,imag_path) _yon_ubl_header_setup(GTK_WIDGET(overlay),GTK_WIDGET(head),GTK_WIDGET(image), (char*)imag_path) -#define yon_ubl_status_box_render(statusbox, statusicon, statuslabel, iconname, statustext, backgroundclass) _yon_ubl_status_box_render(statusbox, statusicon, statuslabel, iconname, statustext, backgroundclass) + +/**yon_ubl_header_setup(overlay, head, image, imag_path) + * [EN] + * Sets up header of app. + * [overlay] is overlay for app header; + * [head] is box of header, which connects to [overlay] + * [image] is header background image; + * [imag_path] is path of image, shown in [image] + * [RU] + * Настраивает заголовок приложения. + * [overlay] - оверлей заголовка приложения; + * [head] - шапка заголовка, присоединяемая к [overlay] + * [image] - виджет картинки для заднего фона; + * [imag_path] - путь до картинки, загружаемой в [image] +*/ +#define yon_ubl_header_setup(overlay, head, image, imag_path) _yon_ubl_header_setup(GTK_WIDGET(overlay), GTK_WIDGET(head), GTK_WIDGET(image), (char *)imag_path) +#define yon_ubl_header_setup_resource(overlay, head, image, imag_path) _yon_ubl_header_setup_resource(GTK_WIDGET(overlay), GTK_WIDGET(head), GTK_WIDGET(image), (char *)imag_path) #endif void _yon_ubl_header_setup(GtkWidget *Overlay, GtkWidget *Head, GtkWidget *Image, char *image_path); -void _yon_ubl_status_box_render(GtkWidget *StatusBox, GtkWidget *StatusIcon, GtkWidget *StatusLabel, char *IconName, char* StatusText, BACKGROUND_IMAGE_TYPE BackgroundClass); + +void _yon_ubl_header_setup_resource(GtkWidget *Overlay, GtkWidget *Head, GtkWidget *Image, char *image_path); + +void yon_ubl_setup_sockets(GtkWidget *main_window, GtkWidget *left_window, GtkWidget *right_window, int socket_main_id, int socket_left_id, int socket_right_id); +#ifdef WEBKIT_FOUND + +void yon_ubl_browser_window_open(char *link, char *browser_window_name); +#else +void yon_ubl_browser_window_open(char *link, char *browser_window_name); +#endif +#endif #endif \ No newline at end of file diff --git a/ubl-settings-usergroups b/ubl-settings-usergroups new file mode 100755 index 0000000000000000000000000000000000000000..1e09c33dced8fd3332e1f3e6533c27d79bf5ed27 GIT binary patch literal 247544 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 Njw|%`Bti08{4dzhW6=Nr literal 0 HcmV?d00001 diff --git a/ubl-settings-usergroups-group.glade b/ubl-settings-usergroups-group.glade new file mode 100644 index 0000000..a9467bf --- /dev/null +++ b/ubl-settings-usergroups-group.glade @@ -0,0 +1,292 @@ + + + + + + True + False + process-stop-symbolic + + + True + False + emblem-ok-symbolic + + + False + False + True + dialog-question-symbolic + + + True + False + 5 + 5 + 5 + 5 + 5 + 5 + vertical + 10 + + + True + False + vertical + + + adm + True + True + False + True + + + False + True + 0 + + + + + audio + True + True + False + True + + + False + True + 1 + + + + + autologin + True + True + False + True + + + False + True + 2 + + + + + avahi + True + True + False + True + + + False + True + 3 + + + + + bin + True + True + False + True + + + False + True + 4 + + + + + brlapi + True + True + False + True + + + False + True + 5 + + + + + britty + True + True + False + True + + + False + True + 6 + + + + + bumblbee + True + True + False + True + + + False + True + 7 + + + + + chrony + True + True + False + True + + + False + True + 8 + + + + + clamav + True + True + False + True + + + False + True + 9 + + + + + cockpit-ws + True + True + False + True + + + False + True + 10 + + + + + cockpit-wsinstance + True + True + False + True + + + False + True + 11 + + + + + colord + True + True + False + True + + + False + True + 12 + + + + + True + True + 0 + + + + + True + False + 30 + True + + + Cancel + True + True + True + image5 + + + + True + True + 0 + + + + + Ok + True + True + True + image6 + + + + True + True + 1 + + + + + False + True + 1 + + + + + + + True + False + + + True + False + Users and groups + + + + + + + + + diff --git a/ubl-settings-usergroups-user.glade b/ubl-settings-usergroups-user.glade new file mode 100644 index 0000000..97ce3c7 --- /dev/null +++ b/ubl-settings-usergroups-user.glade @@ -0,0 +1,412 @@ + + + + + + True + False + emblem-ok-symbolic + + + True + False + process-stop-symbolic + + + False + False + True + 450 + com.ublinux.ubl-settings-usergroups + + + True + False + 5 + 5 + 5 + 5 + 5 + 5 + vertical + 10 + + + True + False + vertical + 5 + + + True + False + 5 + + + True + False + UID: + 0 + + + False + True + 0 + + + + + True + True + + + True + True + 1 + + + + + False + True + 0 + + + + + True + False + 5 + + + True + False + User name: + 0 + + + False + True + 0 + + + + + True + True + + + True + True + 1 + + + + + False + True + 1 + + + + + True + False + 5 + + + True + False + Login: + 0 + + + False + True + 0 + + + + + True + True + + + True + True + 1 + + + + + False + True + 2 + + + + + True + False + 5 + + + True + False + Password: + 0 + + + False + True + 0 + + + + + Default + True + True + False + True + + + False + True + 1 + + + + + True + True + + + True + True + 2 + + + + + False + True + 3 + + + + + True + False + 5 + + + True + False + Main group: + 0 + + + False + True + 0 + + + + + True + True + + + True + True + 1 + + + + + Additional groups + True + True + True + + + False + True + 2 + + + + + False + True + 4 + + + + + True + False + 5 + + + True + False + Password hash algorythm: + 0 + + + False + True + 0 + + + + + True + False + + sha256 + AIX md5 + md5 (apache variant) + md5 + + + + True + True + 1 + + + + + False + True + 5 + + + + + Sync with SAMBA user + True + True + False + True + + + False + True + 6 + + + + + True + False + 5 + + + True + False + Extra options: + 0 + + + False + True + 0 + + + + + True + True + + + True + True + 1 + + + + + False + True + 7 + + + + + False + True + 0 + + + + + True + False + 30 + True + + + Cancel + True + True + True + image7 + + + + True + True + 0 + + + + + Save + True + True + True + image10 + + + + True + True + 1 + + + + + False + True + end + 1 + + + + + + + True + False + + + True + False + Users and groups + + + + + + + + + diff --git a/ubl-settings-usergroups.css b/ubl-settings-usergroups.css index c5b88a3..8687d4a 100644 --- a/ubl-settings-usergroups.css +++ b/ubl-settings-usergroups.css @@ -1,143 +1,108 @@ -.bannerbackground { -background-color: #404040; -} -.thin{ - padding:0px; - margin:0px; - transition: 0ms ease-out; +.thin { + margin:0px; + padding:0px; } -.thin:active { - background-color: @theme_selected_bg_color; - transition: 10ms ease-out; +.noborder { + border:none; } -.transparent { - background:none; - border:none; - transition: 0ms ease-out; +.nobackground { +background:transparent; } - -#GnomeIcon{ - border-style:solid; - border-bottom-width: 1px; - border-image: linear-gradient(90deg, alpha(@theme_text_color,0.4) 55%, alpha(@theme_bg_color, 0) 100%); - border-image-slice: 1; +.nobackground:active { +background:transparent; } - -#SepIcon{ - background-color: alpha(@theme_text_color, 0.6); +.textHead{ + text-shadow: 2px 2px @theme_bg_color; + color: @theme_text_color; } -#iconlabel { - font-size:14px; - font-weight: bold; - -} -.roundborder > * { - border-width:0px; +.inherited>* { + border:none; + background:inherit; } -.roundborder:backdrop > * { - border-width:0px; - border-radius:5px; -} -.noborder { - border: none; +.workingbg { + background:@theme_base_color; } - .menuitembottom{ - margin-top:0px; - margin-bottom:3px; - border-color:inherit; - border-left-width:inherit; - border-right-width:inherit; -} -.menuitemmiddle{ - margin-top:0px; - margin-bottom:0px; - border-color:inherit; - border-left-width:inherit; - border-right-width:inherit; -} - -.menuitemtop{ - margin-bottom:0px; - border-color:inherit; - border-top-width:inherit; - border-left-width:inherit; - border-right-width:inherit; -} -.menuitemtop *{ - margin:2px 2px 0 2px; - padding: 5px 10px 3px 5px; - border:transparent; -} -.menuitemmiddle *{ - margin:0 2px 0 2px; - padding: 3px 10px 3px 5px; - border:transparent; -} -.menuitembottom *{ - margin:0 2px 2px 2px; - padding: 3px 10px 5px 5px; -} -.menuitemtop:hover { - background:@theme_bg_color; - border-color:inherit; - border-top-width:inherit; - border-left-width:inherit; - border-right-width:inherit; -} -.menuitemmiddle:hover { - background:@theme_bg_color; - border-color:inherit; - border-left-width:inherit; - border-right-width:inherit; -} -.menuitembottom:hover { - background:@theme_bg_color; - border-color:inherit; - border-bottom-width:0px; - border-left-width:inherit; - border-right-width:inherit; + margin-top:0px; + margin-bottom:3px; + border-color:inherit; + border-left-width:inherit; + border-right-width:inherit; + } + .menuitemmiddle{ + margin-top:0px; + margin-bottom:0px; + border-color:inherit; + border-left-width:inherit; + border-right-width:inherit; + } + .menuitemtop{ + margin-bottom:0px; + border-color:inherit; + border-top-width:inherit; + border-left-width:inherit; + border-right-width:inherit; + } + .menuitemtop *{ + margin:2px 2px 0 2px; + padding: 5px 10px 3px 5px; + border:transparent; + } + .menuitemmiddle *{ + margin:0 2px 0 2px; + padding: 3px 10px 3px 5px; + border:transparent; + } + .menuitembottom *{ + margin:0 2px 2px 2px; + padding: 3px 10px 5px 5px; + } + .menuitemtop:hover { + background:@theme_bg_color; + border-color:inherit; + border-top-width:inherit; + border-left-width:inherit; + border-right-width:inherit; + } + .menuitemmiddle:hover { + background:@theme_bg_color; + border-color:inherit; + border-left-width:inherit; + border-right-width:inherit; + } + .menuitembottom:hover { + background:@theme_bg_color; + border-color:inherit; + border-bottom-width:0px; + border-left-width:inherit; + border-right-width:inherit; + + } + .menuitemtop:hover* { + margin:2px 2px 0 2px; + padding: 5px 10px 3px 5px; + background:@theme_selected_bg_color; + border-radius:2px; + } + .menuitemmiddle:hover* { + margin:0 2px 0 2px; + padding: 3px 10px 3px 5px; + background:@theme_selected_bg_color; + border-radius:2px; + } + .menuitembottom:hover* { + margin:0 2px 2px 2px; + padding: 3px 10px 5px 5px; + background:@theme_selected_bg_color; + border-radius:2px; + } + .boxInfoMessError{ + background-color: #ea9999; } -.menuitemtop:hover* { - margin:2px 2px 0 2px; - padding: 5px 10px 3px 5px; - background:@theme_selected_bg_color; - border-radius:2px; -} -.menuitemmiddle:hover* { - margin:0 2px 0 2px; - padding: 3px 10px 3px 5px; - background:@theme_selected_bg_color; - border-radius:2px; -} -.menuitembottom:hover* { - margin:0 2px 2px 2px; - padding: 3px 10px 5px 5px; - background:@theme_selected_bg_color; - border-radius:2px; -} - -.workingbg, #workingbg { - background-color:@theme_base_color; -} - -.workingbg.view.cell:selected { - background-color:@theme_selected_bg_color; -} - -.workingbg.view.cell:hover { - background-color:darker(@theme_selected_bg_color); - color:@theme_selected_text_color; - border-radius:3px; -} - -.bkim { - transition: 200ms ease-out; - background-image: none; -} - - +.boxInfoMessOK{ + background-color: #f3f0ac; +} \ No newline at end of file diff --git a/ubl-settings-usergroups.desktop b/ubl-settings-usergroups.desktop index 2933781..e192dfd 100644 --- a/ubl-settings-usergroups.desktop +++ b/ubl-settings-usergroups.desktop @@ -1,15 +1,15 @@ [Desktop Entry] Encoding=UTF-8 -Name=ubl-settings-usergroups -Name[ru]=Настройки пользователей и групп +Name=Users and groups +Name[ru]=Пользователи и группы GenericName=ubl-settings-usergroups -GenericName[ru]=Настройки пользователей и групп -Comment=ubl-settings-usergroups -Comment[ru]=Приложение для управления настройками пользователей и групп +GenericName[ru]=Пользователи и группы +Comment=System users and groups configuration +Comment[ru]=Настройка пользователей и групп системы (глобальная настройка, через конфигурационный файл) Type=Application -Exec=ubl-settings-usergroups +Exec=pkexec ubl-settings-usergroups Icon=com.ublinux.ubl-settings-usergroups Terminal=false X-XfcePluggable=true X-UBLPluggable=true -Categories=XFCE;GTK;Settings;DesktopSettings;X-XFCE-SettingsDialog;X-XFCE-SystemSettings; +Categories=XFCE;GTK;Settings;DesktopSettings;X-XFCE-SettingsDialog;X-XFCE-SystemSettings;X-UBL-SettingsManager;X-UBL-Personal-Settings; diff --git a/ubl-settings-usergroups.glade b/ubl-settings-usergroups.glade index 3c5e40d..eced9ce 100644 --- a/ubl-settings-usergroups.glade +++ b/ubl-settings-usergroups.glade @@ -1,15 +1,32 @@ - - + + - - True - False - label - - + + + + + False - О Программе False True center @@ -17,9 +34,9 @@ dialog True ubl-settings-usergroups - 1.0 - Copyright © 2023 - UBSoft Software LLC - Settings for users and groups + 1.1 + Copyright © 2022 - 2023, UBSoft LLC + Users and groups https://wiki.ublinux.ru/ru/Программное_обеспечение/Программы_и_утилиты/Все/ubl-settings-usergroups Project Home Page Это приложение распространяется без каких-либо гарантий. @@ -31,41 +48,67 @@ gpl-2-0 + True False vertical 2 - - False + False - top - spread + end False False - 0 + 1 - - + + + + + True + False + True + + + True + False + 5 + 5 + 5 + 5 + 2 + Users and groups + + + + - + + + + + + + True False + center - 90 True False + 5 + 5 5 5 6 6 - 69 + 64 com.ublinux.ubl-settings-usergroups @@ -86,19 +129,23 @@ True False + center vertical - + 255 True False - System user and groups configuration + end + Users and groups + 0 - - + True @@ -106,6 +153,29 @@ 0 + + + 255 + True + False + start + System users and groups configuration + True + 0 + + + + + + + + True + True + 1 + + False @@ -128,45 +198,53 @@ + + + + + + + + + + + + True False - user-trash-symbolic - + value-increase-symbolic True False - system-run-symbolic + document-edit-symbolic True False - list-add-symbolic + user-trash-symbolic True False - system-run-symbolic + document-edit-symbolic - + True False - emblem-ok-symbolic + process-stop-symbolic - + True False - process-stop-symbolic + emblem-ok-symbolic - - 450 - 250 + False - True - com.ublinux.ubl-settings-usergroups + False + 450 + dialog-question-symbolic True @@ -176,55 +254,20 @@ 5 5 vertical - 5 - - - True - False - 5 - - - True - False - UID - 0 - - - False - True - 0 - - - - - True - True - 1000 - - - True - True - 1 - - - - - False - True - 0 - - + 10 True False - 5 - + True False - Username - 0 + start + 20 + 20 + dialog-question-symbolic + 6 False @@ -232,184 +275,27 @@ 0 - - - True - True - - - True - True - 1 - - - - - False - True - 1 - - - - - True - False - 5 - - - True - False - Login - 0 - - - False - True - 0 - - - - - True - True - - - True - True - 1 - - - - - False - True - 2 - - - - - True - False - 5 - - - True - False - Password - 0 - - - False - True - 0 - - - - - True - True - - - True - True - 1 - - - - - False - True - 3 - - - - - Default password - True - True - False - 0 - True - - - False - True - 4 - - - - - True - False - 5 - - - True - False - Password hash algorythm - 0 - - - False - True - 0 - - - - - True - False - - - True - True - 1 - - - - - False - True - 5 - - - - - Sync with SAMBA user - True - True - False - 0 - True - - - False - True - 6 - - - - - True - False - - - True False - 5 - 5 - 5 - True + vertical - - Cancel + True - True - True - image6 + False + start + 10 + 5 + Would you like to read documentation in the Web? + True + 0 + + + + False @@ -418,12 +304,20 @@ - - Add + True - True - True - image5 + False + start + start + 10 + 10 + You will be redirected to documentation website where documentation is +translated and supported by community. + True + 0 + False @@ -431,94 +325,38 @@ 1 + + + Always redirect to online documentation + True + True + False + end + True + + + + False + True + end + 2 + + + - False + True True - end 1 - - - False - True - end - 7 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 300 - 400 - False - True - com.ublinux.ubl-settings-usergroups - - - True - False - vertical - - - True - True - liststore2 - - - - - - Enabled - - - - 1 - - - - - - - Group - - - - 0 - - - - + True @@ -530,34 +368,38 @@ True False - 5 - 5 - 5 - 5 - 5 + 30 True - + Cancel True True True + image8 + - False + True True 0 - - Ok + + Open documentation True True True + image9 + - False + True True 1 @@ -566,91 +408,128 @@ False True - end 1 + + + True + False + True + + + True + False + Users and groups + + + + + + + True False + False - + True False - Load from global configuration - True + Load global configuration + - + True False - Load from local configuration - True + Load local configuration + True False + False + False - + True False - Save to global and local configuration - True - - - - - True - False - Save to global configuration + Documentation True + - + True False - Save to local configuration - True + About + True False + False + + + True + False + Save configuration + + + - + True False - Documentation - True + Save to global configuration + - + True False - About - True + Save to local configuration + + 800 + 600 False 800 600 com.ublinux.ubl-settings-usergroups - + True False - True vertical @@ -669,8 +548,8 @@ 5 5 5 - 6 - 6 + 5 + 5 25 @@ -690,13 +569,14 @@ 5 6 6 + True - + - True + False True 1 @@ -709,17 +589,17 @@ - + True False vertical - + 81 True False - + True False start @@ -746,29 +626,33 @@ True False + 5 + 5 5 5 5 5 + True + True vertical 5 True False + vertical 5 - + True False - vertical 5 - + True False - User groups (default) - True + 5 + Default user groups: 0 @@ -778,26 +662,22 @@ - + True - False - User name - True - 0 + True - False + True True 1 - + True - False - User password - True - 0 + True + True + image4 False @@ -805,107 +685,76 @@ 2 + + + False + True + 0 + + + + + True + False + 5 - - True - False - Password hash algorythm: - True - 0 - - - False - True - 3 - - - - - True - False - Autologin - True - 0 - - - False - True - 4 - - - - + True False - Update HOME directory(ies) - True + 5 + Default user name (if there's no another): 0 False True - 5 + 0 - + True - False - Automatically load user programs - True - 0 + True - False + True True - 6 + 1 - True + False True - 0 + 1 + + + + + User with ID 1000 is administrator + True + True + False + True + + + False + True + 2 True False - vertical 5 - + True False - 5 - - - True - True - - - True - True - 0 - - - - - True - True - True - image4 - - - - False - True - 1 - - + 5 + Default user password: + 0 False @@ -914,35 +763,13 @@ - + True - False - 5 - - - Administrator - True - True - False - True - - - False - True - 0 - - - - - True - True - - - True - True - 1 - - + True + 30 + False + + password False @@ -951,95 +778,54 @@ - + True True + end + 30 + False + + password - True + False True + end 2 - - True - False - - - True - True - 3 - - - - + True False - - - True - True - 4 - - - - - Enabled - True - True - False - 0 - True + Root user password: False True - 5 - - - - - True - True - - - True - True - 6 + end + 3 - True + False True - 1 + 3 - - - False - True - 0 - - - - - True - False - vertical - 5 True False 5 - + True False - User string: - True + 5 + Password hash algorythm: + 0 False @@ -1048,9 +834,15 @@ - + True - True + False + + sha256 + AIX md5 + md5 (apache variant) + md5 + True @@ -1062,104 +854,107 @@ False True - 0 + 4 + + + False + True + 0 + + + + + True + False + 5 - + True - False - 5 + True + external + in - + True True - liststore1 + UserList - + UID + + + - + Login + + + - + Password + + + - - User Name + + User name + + + + + + + True + True + 0 + + + + + True + False + vertical + 5 + + + True + True + True + image1 + + - True + False True 0 - + True - False - center - vertical - 5 - - - True - True - True - image3 - - - - False - True - 0 - - - - - True - True - True - image2 - - - - False - True - 1 - - - - - True - True - True - image1 - - - - False - True - 2 - - + True + True + image2 + False @@ -1167,9 +962,25 @@ 1 + + + True + True + True + image3 + + + + False + True + 2 + + - True + False True 1 @@ -1183,7 +994,7 @@ - True + False True 2 @@ -1203,15 +1014,14 @@ False True - + True False - start 5 5 5 5 - False + 2 Users and groups @@ -1226,35 +1036,32 @@ 5 5 5 + 6 + 6 32 com.ublinux.ubl-settings-usergroups - + True False - + True True False True - menu1 - none + menu3 True False - + True False - 5 - 5 - 5 - 5 - Load + Save False @@ -1263,7 +1070,7 @@ - + True False pan-down-symbolic @@ -1283,40 +1090,55 @@ 0 + + + True + True + True + False + True + True + menu2 + none + + + + + + + False + True + 1 + + + end 1 - + True False - + True True False True - True - menu2 - none + menu1 True False - + True False - 5 - 5 - 5 - 5 - Save - + Load False @@ -1325,7 +1147,7 @@ - + True False pan-down-symbolic @@ -1345,51 +1167,23 @@ 0 - - - True - True - False - True - True - menu3 - none - - - - - - False - True - 1 - - - end - 3 + 2 + - - vertical + - - - - - - - - - - - - - - + + + + diff --git a/ubl-settings-usergroups.pot b/ubl-settings-usergroups.pot index 196db4c..559f905 100644 --- a/ubl-settings-usergroups.pot +++ b/ubl-settings-usergroups.pot @@ -1,114 +1,250 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. +# Language translations for ubl-settings-usergroups package. +# Copyright (C) 2022, UBTech LLC +# This file is distributed under the same license as the ubl-settings-usergroups package. +# UBLinux Team , 2022 # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: ubl-settings-usergroups 1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-06 09:45+0000\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" +"POT-Creation-Date: 2023-05-22 16:12+0600\n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" "Language: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: source/ubl-settings-usergroups.c:50 -msgid "User groups (default)" +#: source/ubl-strings.h:1 +msgid "Version:" msgstr "" -#: source/ubl-settings-usergroups.c:51 -msgid "User name" +#: source/ubl-strings.h:2 +msgid "ubl-settings-usergroups version:" msgstr "" -#: source/ubl-settings-usergroups.c:52 -msgid "Administrator" +#: source/ubl-strings.h:2 source/ubl-strings.h:4 +msgid "Users and groups" msgstr "" -#: source/ubl-settings-usergroups.c:53 -msgid "User password" +#: source/ubl-strings.h:2 +msgid "Usage:" msgstr "" -#: source/ubl-settings-usergroups.c:54 -msgid "Password hash algorythm" +#: source/ubl-strings.h:2 +msgid "[OPTIONS]" msgstr "" -#: source/ubl-settings-usergroups.c:55 -msgid "Autologin" +#: source/ubl-strings.h:2 +msgid "Options:" msgstr "" -#: source/ubl-settings-usergroups.c:56 -msgid "Update HOME directory(ies)" +#: source/ubl-strings.h:2 +msgid "Show this help" msgstr "" -#: source/ubl-settings-usergroups.c:57 -msgid "Enabled" +#: source/ubl-strings.h:2 +msgid "Show package version" msgstr "" -#: source/ubl-settings-usergroups.c:58 -msgid "Automatically load user programs" +#: source/ubl-strings.h:2 +msgid "Lock this help menu" msgstr "" -#: source/ubl-settings-usergroups.c:59 -msgid "User string" +#: source/ubl-strings.h:2 +msgid "Lock configuration saving" msgstr "" -#: source/ubl-settings-usergroups.c:60 -msgid "UID" +#: source/ubl-strings.h:2 +msgid "Lock local configration saving" msgstr "" -#: source/ubl-settings-usergroups.c:61 -msgid "Login" +#: source/ubl-strings.h:2 +msgid "Lock global configration saving" msgstr "" -#: source/ubl-settings-usergroups.c:62 -msgid "Password" +#: source/ubl-strings.h:2 +msgid "Lock global configration loading" msgstr "" -#: source/ubl-settings-usergroups.c:63 -msgid "User Name" +#: source/ubl-strings.h:5 +msgid "System users and groups configuration" msgstr "" -#: source/ubl-settings-usergroups.c:64 -msgid "Load from global configuration" +#: source/ubl-strings.h:7 +msgid "Operation succeeded" msgstr "" -#: source/ubl-settings-usergroups.c:65 -msgid "Load from local configuration" +#: source/ubl-strings.h:8 +msgid "" +"Warning! Application was launched without root - root-dependent actions are " +"locked" msgstr "" -#: source/ubl-settings-usergroups.c:66 -msgid "Save to global and local configuration" +#: source/ubl-strings.h:10 +msgid "About" msgstr "" -#: source/ubl-settings-usergroups.c:67 -msgid "Save to global configuration" +#: source/ubl-strings.h:11 +msgid "Documentation" msgstr "" -#: source/ubl-settings-usergroups.c:68 +#: source/ubl-strings.h:13 msgid "Save to local configuration" msgstr "" -#: source/ubl-settings-usergroups.c:69 -msgid "Documentation" +#: source/ubl-strings.h:14 +msgid "Save to global configuration" msgstr "" -#: source/ubl-settings-usergroups.c:70 -msgid "About" +#: source/ubl-strings.h:15 +msgid "Save configuration" +msgstr "" + +#: source/ubl-strings.h:16 +msgid "Save" +msgstr "" + +#: source/ubl-strings.h:18 +msgid "Load local configuration" msgstr "" -#: source/ubl-settings-usergroups.c:71 +#: source/ubl-strings.h:19 +msgid "Load global configuration" +msgstr "" + +#: source/ubl-strings.h:20 msgid "Load" msgstr "" -#: source/ubl-settings-usergroups.c:72 -msgid "Users and groups" +#: source/ubl-strings.h:22 +msgid "Cancel" msgstr "" -#: source/ubl-settings-usergroups.c:73 -msgid "Save" +#: source/ubl-strings.h:24 +msgid "Would you like to read documentation in the Web?" +msgstr "" + +#: source/ubl-strings.h:25 +msgid "" +"You will be redirected to documentation website where documentation is\n" +"translated and supported by community." +msgstr "" + +#: source/ubl-strings.h:26 +msgid "Always redirect to online documentation" +msgstr "" + +#: source/ubl-strings.h:27 +msgid "Open documentation" +msgstr "" + +#: source/ubl-strings.h:28 +msgid "Project Home Page" +msgstr "" + +#: source/ubl-strings.h:29 +msgid "Nothing were chosen" +msgstr "" + +#: source/ubl-strings.h:32 +msgid "Global configuration loading succseeded." +msgstr "" + +#: source/ubl-strings.h:33 +msgid "Local configuration loading succseeded." +msgstr "" + +#: source/ubl-strings.h:34 +msgid "Config loading failed" +msgstr "" + +#: source/ubl-strings.h:36 +msgid "Local and global configuration saving succseeded." +msgstr "" + +#: source/ubl-strings.h:37 +msgid "Global configuration saving succseeded." +msgstr "" + +#: source/ubl-strings.h:38 +msgid "Local configuration saving succseeded." +msgstr "" + +#: source/ubl-strings.h:40 +msgid "Default user groups:" +msgstr "" + +#: source/ubl-strings.h:41 +msgid "Default user name (if there's no another):" +msgstr "" + +#: source/ubl-strings.h:42 +msgid "User with ID 1000 is administrator" +msgstr "" + +#: source/ubl-strings.h:43 +msgid "Default user password:" +msgstr "" + +#: source/ubl-strings.h:44 +msgid "Root user password:" +msgstr "" + +#: source/ubl-strings.h:45 source/ubl-strings.h:59 +msgid "Password hash algorythm:" +msgstr "" + +#: source/ubl-strings.h:47 +msgid "UID" +msgstr "" + +#: source/ubl-strings.h:48 +msgid "Login" +msgstr "" + +#: source/ubl-strings.h:49 +msgid "Password" +msgstr "" + +#: source/ubl-strings.h:50 +msgid "User name" +msgstr "" + +#: source/ubl-strings.h:52 +msgid "UID:" +msgstr "" + +#: source/ubl-strings.h:53 +msgid "User name:" +msgstr "" + +#: source/ubl-strings.h:54 +msgid "Login:" +msgstr "" + +#: source/ubl-strings.h:55 +msgid "Password:" +msgstr "" + +#: source/ubl-strings.h:56 +msgid "Default" +msgstr "" + +#: source/ubl-strings.h:57 +msgid "Main group:" +msgstr "" + +#: source/ubl-strings.h:58 +msgid "Additional groups" +msgstr "" + +#: source/ubl-strings.h:60 +msgid "Sync with SAMBA user" +msgstr "" + +#: source/ubl-strings.h:61 +msgid "Extra options:" msgstr "" diff --git a/ubl-settings-usergroups_ru.po b/ubl-settings-usergroups_ru.po index f65b721..609c4ff 100644 --- a/ubl-settings-usergroups_ru.po +++ b/ubl-settings-usergroups_ru.po @@ -1,121 +1,257 @@ -# Language translations for ubl-settings-manager package. +# Russian translations for ubl-ubl-settings-usergroups package. # Copyright (C) 2022, UBTech LLC -# This file is distributed under the same license as the ubl-settings-manager package. +# This file is distributed under the same license as the ubl-ubl-settings-usergroups package. # UBLinux Team , 2022 # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: ubl-settings-manager 1.0\n" +"Project-Id-Version: ubl-ubl-settings-usergroups 1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-06 09:45+0000\n" +"POT-Creation-Date: 2023-05-22 16:12+0600\n" "PO-Revision-Date: 2023-01-01 00:00+0600\n" "Last-Translator: UBLinux Team \n" -"Language-Team: UBLinux Team \n" -"Language: \n" +"Language-Team: Russian - UBLinux Team \n" +"Language: Russian\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: source/ubl-settings-usergroups.c:50 -#, fuzzy -msgid "User groups (default)" -msgstr "Группы пользователей (По умолчанию)" +#: source/ubl-strings.h:1 +msgid "Version:" +msgstr "Версия:" -#: source/ubl-settings-usergroups.c:51 +#: source/ubl-strings.h:2 #, fuzzy -msgid "User name" -msgstr "Имя пользователя" +msgid "ubl-settings-usergroups version:" +msgstr "Версия ubl-ubl-settings-usergroups: " -#: source/ubl-settings-usergroups.c:52 -msgid "Administrator" -msgstr "Администратор" +#: source/ubl-strings.h:2 source/ubl-strings.h:4 +msgid "Users and groups" +msgstr "Пользователи и группы" -#: source/ubl-settings-usergroups.c:53 -#, fuzzy -msgid "User password" -msgstr "Пароль пользователя" +#: source/ubl-strings.h:2 +msgid "Usage:" +msgstr "Использование:" -#: source/ubl-settings-usergroups.c:54 -#, fuzzy -msgid "Password hash algorythm" -msgstr "Алгоритм хэширования пароля" +#: source/ubl-strings.h:2 +msgid "[OPTIONS]" +msgstr "[АРГУМЕНТЫ]" -#: source/ubl-settings-usergroups.c:55 -#, fuzzy -msgid "Autologin" -msgstr "Автоматический логин пользователя" +#: source/ubl-strings.h:2 +msgid "Options:" +msgstr "Аргументы:" -#: source/ubl-settings-usergroups.c:56 -msgid "Update HOME directory(ies)" -msgstr "Обновлять каталог(и) HOME" +#: source/ubl-strings.h:2 +msgid "Show this help" +msgstr "Показать параметры справки" -#: source/ubl-settings-usergroups.c:57 -msgid "Enabled" -msgstr "Включено" +#: source/ubl-strings.h:2 +msgid "Show package version" +msgstr "Показать текущую версию" -#: source/ubl-settings-usergroups.c:58 -#, fuzzy -msgid "Automatically load user programs" -msgstr "Автозагрузка программ пользователей" +#: source/ubl-strings.h:2 +msgid "Lock this help menu" +msgstr "Блокировка вызова справки" -#: source/ubl-settings-usergroups.c:59 -#, fuzzy -msgid "User string" -msgstr "Строка пользователей" +#: source/ubl-strings.h:2 +msgid "Lock configuration saving" +msgstr "Блокировка сохранения локальной и глобальной конфигурации" + +#: source/ubl-strings.h:2 +msgid "Lock local configration saving" +msgstr "Блокировка сохранения локальной конфигурации" + +#: source/ubl-strings.h:2 +msgid "Lock global configration saving" +msgstr "Блокировка сохранения глобальной конфигурации" + +#: source/ubl-strings.h:2 +msgid "Lock global configration loading" +msgstr "Блокировка загрузки глобальной конфигурации" + +#: source/ubl-strings.h:5 +msgid "System users and groups configuration" +msgstr "" +"Настройка пользователей и групп системы (глобальная настройка, через " +"конфигурационный файл)" + +#: source/ubl-strings.h:7 +msgid "Operation succeeded" +msgstr "Операция завершена" + +#: source/ubl-strings.h:8 +msgid "" +"Warning! Application was launched without root - root-dependent actions are " +"locked" +msgstr "" +"Внимание! Приложение было запущено без прав суперпользователя - действия, " +"требующие их наличия заблокированы" -#: source/ubl-settings-usergroups.c:60 +#: source/ubl-strings.h:10 +msgid "About" +msgstr "О программе" + +#: source/ubl-strings.h:11 +msgid "Documentation" +msgstr "Справка" + +#: source/ubl-strings.h:13 +msgid "Save to local configuration" +msgstr "Сохранить в локальную конфигурацию" + +#: source/ubl-strings.h:14 +msgid "Save to global configuration" +msgstr "Сохранить в глобальную конфигурацию" + +#: source/ubl-strings.h:15 +msgid "Save configuration" +msgstr "Сохранить конфигурацию" + +#: source/ubl-strings.h:16 +msgid "Save" +msgstr "Сохранить" + +#: source/ubl-strings.h:18 +msgid "Load local configuration" +msgstr "Загрузить локальную конфигуруцию" + +#: source/ubl-strings.h:19 +msgid "Load global configuration" +msgstr "Загрузить глобальную конфигурацию" + +#: source/ubl-strings.h:20 +msgid "Load" +msgstr "Загрузить" + +#: source/ubl-strings.h:22 +msgid "Cancel" +msgstr "Отмена" + +#: source/ubl-strings.h:24 +msgid "Would you like to read documentation in the Web?" +msgstr "Вы хотите прочитать справку в Сети?" + +#: source/ubl-strings.h:25 +msgid "" +"You will be redirected to documentation website where documentation is\n" +"translated and supported by community." +msgstr "" +"Вы будете перенаправлены на сайт с документацией где страницы помощи\n" +"переводятся и поддерживаются сообществом." + +#: source/ubl-strings.h:26 +msgid "Always redirect to online documentation" +msgstr "Всегда перенаправлять" + +#: source/ubl-strings.h:27 +msgid "Open documentation" +msgstr "Прочитать справку" + +#: source/ubl-strings.h:28 +msgid "Project Home Page" +msgstr "Домашняя страница проекта" + +#: source/ubl-strings.h:29 +msgid "Nothing were chosen" +msgstr "Ничего не было выбрано" + +#: source/ubl-strings.h:32 +msgid "Global configuration loading succseeded." +msgstr "Успешно загружена глобальная конфигурация" + +#: source/ubl-strings.h:33 +msgid "Local configuration loading succseeded." +msgstr "Успешно загружена локальная конфигурация" + +#: source/ubl-strings.h:34 +msgid "Config loading failed" +msgstr "Ошибка загрузки конфигурации" + +#: source/ubl-strings.h:36 +msgid "Local and global configuration saving succseeded." +msgstr "Успешно записаны локальная и глобальная конфигурация" + +#: source/ubl-strings.h:37 +msgid "Global configuration saving succseeded." +msgstr "Успешно записана глобальная конфигурация" + +#: source/ubl-strings.h:38 +msgid "Local configuration saving succseeded." +msgstr "Успешно записана локальная конфигурация" + +#: source/ubl-strings.h:40 +msgid "Default user groups:" +msgstr "Группы пользователей по умлочанию:" + +#: source/ubl-strings.h:41 +msgid "Default user name (if there's no another):" +msgstr "Имя пользователя по умолчанию (если нет других):" + +#: source/ubl-strings.h:42 +msgid "User with ID 1000 is administrator" +msgstr "Пользователь с ID 1000 является администратором" + +#: source/ubl-strings.h:43 +msgid "Default user password:" +msgstr "Пароль для пользователя по умолчанию" + +#: source/ubl-strings.h:44 +msgid "Root user password:" +msgstr "Пароль пользователя root" + +#: source/ubl-strings.h:45 source/ubl-strings.h:59 +msgid "Password hash algorythm:" +msgstr "Алгоритм хэширования пароля" + +#: source/ubl-strings.h:47 msgid "UID" msgstr "UID" -#: source/ubl-settings-usergroups.c:61 +#: source/ubl-strings.h:48 msgid "Login" msgstr "Логин" -#: source/ubl-settings-usergroups.c:62 +#: source/ubl-strings.h:49 msgid "Password" msgstr "Пароль" -#: source/ubl-settings-usergroups.c:63 -msgid "User Name" +#: source/ubl-strings.h:50 +msgid "User name" msgstr "Имя пользователя" -#: source/ubl-settings-usergroups.c:64 -msgid "Load from global configuration" -msgstr "Загрузить из глобальной конфигурации" +#: source/ubl-strings.h:52 +msgid "UID:" +msgstr "UID:" -#: source/ubl-settings-usergroups.c:65 -msgid "Load from local configuration" -msgstr "Загрузить из локальной конфигурации" +#: source/ubl-strings.h:53 +msgid "User name:" +msgstr "Имя пользователя:" -#: source/ubl-settings-usergroups.c:66 -msgid "Save to global and local configuration" -msgstr "Сохранить в глобальную и локальную конфигурации" +#: source/ubl-strings.h:54 +msgid "Login:" +msgstr "Логин:" -#: source/ubl-settings-usergroups.c:67 -msgid "Save to global configuration" -msgstr "Сохранить в глобальную конфигурацию" +#: source/ubl-strings.h:55 +msgid "Password:" +msgstr "Пароль:" -#: source/ubl-settings-usergroups.c:68 -msgid "Save to local configuration" -msgstr "Сохранить в локальную конфигурацию" +#: source/ubl-strings.h:56 +msgid "Default" +msgstr "По умолчанию" -#: source/ubl-settings-usergroups.c:69 -msgid "Documentation" -msgstr "Справка" +#: source/ubl-strings.h:57 +msgid "Main group:" +msgstr "Основная группа:" -#: source/ubl-settings-usergroups.c:70 -msgid "About" -msgstr "О программе" +#: source/ubl-strings.h:58 +msgid "Additional groups" +msgstr "Дополнительные группы" -#: source/ubl-settings-usergroups.c:71 -msgid "Load" -msgstr "Загрузить" +#: source/ubl-strings.h:60 +msgid "Sync with SAMBA user" +msgstr "Синхронизировать с пользователем SAMBA" -#: source/ubl-settings-usergroups.c:72 -msgid "Users and groups" -msgstr "Пользователи и группы" - -#: source/ubl-settings-usergroups.c:73 -msgid "Save" -msgstr "Сохранить" +#: source/ubl-strings.h:61 +msgid "Extra options:" +msgstr "Дополнительный опции:"