new: Add proper color support, move ncurses code to term.c

This commit is contained in:
ngn 2024-04-23 02:28:22 +03:00
parent bf056066a9
commit fd6489f13f
9 changed files with 271 additions and 227 deletions

View File

@ -1,9 +1,11 @@
prefix = /usr SRCS = $(wildcard src/*.c)
SRCS = $(wildcard src/*.c)
HEADERS = $(wildcard src/*.h) HEADERS = $(wildcard src/*.h)
PO_DIRS = $(wildcard locale/*/*)
PO_DIRS = $(wildcard locale/*/*)
PO_FILES = $(wildcard locale/*/*/*.po) PO_FILES = $(wildcard locale/*/*/*.po)
prefix = /usr
dist/xcfg: $(SRCS) $(HEADERS) $(PO_FILES) dist/xcfg: $(SRCS) $(HEADERS) $(PO_FILES)
mkdir -p dist mkdir -p dist
gcc $(CFLAGS) $(SRCS) -o $@ -lncurses -lmenu -lm gcc $(CFLAGS) $(SRCS) -o $@ -lncurses -lmenu -lm
@ -35,4 +37,7 @@ install:
uninstall: uninstall:
rm $(DESTDIR)$(prefix)/bin/xcfg rm $(DESTDIR)$(prefix)/bin/xcfg
.PHONY: install uninstall format:
clang-format -i -style=file src/*.c src/*.h
.PHONY: install uninstall format

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-03-24 03:18+0300\n" "POT-Creation-Date: 2024-04-23 02:27+0300\n"
"PO-Revision-Date: 2024-02-20 20:36+0300\n" "PO-Revision-Date: 2024-02-20 20:36+0300\n"
"Last-Translator: <ngn@ngn.tf>\n" "Last-Translator: <ngn@ngn.tf>\n"
"Language-Team: Turkish <gnome-turk@gnome.org>\n" "Language-Team: Turkish <gnome-turk@gnome.org>\n"
@ -17,83 +17,83 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: src/main.c:101 src/main.c:256 #: src/main.c:49 src/main.c:185
#, fuzzy #, fuzzy
msgid "Failed to get the home directory" msgid "Failed to get the home directory"
msgstr "Ev dizini bulmak başarısız oldu" msgstr "Ev dizini bulmak başarısız oldu"
#: src/main.c:107 #: src/main.c:55
#, c-format #, c-format
msgid "Failed to open %s for reading" msgid "Failed to open %s for reading"
msgstr "%s dosyasını okumak için açmak başarısız oldu" msgstr "%s dosyasını okumak için açmak başarısız oldu"
#: src/main.c:146 #: src/main.c:94
#, c-format #, c-format
msgid "Failed to open %s for writing" msgid "Failed to open %s for writing"
msgstr "%s dosyasını yazmak için açmak başarısız oldu" msgstr "%s dosyasını yazmak için açmak başarısız oldu"
#: src/main.c:152 src/main.c:262 #: src/main.c:100 src/main.c:191
#, c-format #, c-format
msgid "Failed to write to %s" msgid "Failed to write to %s"
msgstr "%s dosyasına yazmak başarısız oldu" msgstr "%s dosyasına yazmak başarısız oldu"
#: src/main.c:164 #: src/main.c:112
msgid "You should use this script as a regular user, not as root!" msgid "You should use this script as a regular user, not as root!"
msgstr "" msgstr ""
"Bu betiği normal bir kullanıcı olarak kullanmalısınız, kök kullanıcı olarak " "Bu betiği normal bir kullanıcı olarak kullanmalısınız, kök kullanıcı olarak "
"değil!" "değil!"
#: src/main.c:175 #: src/main.c:123
msgid "Lightweight desktop environment for UNIX-like operating systems" msgid "Lightweight desktop environment for UNIX-like operating systems"
msgstr "UNIX-gibi işletim sistemleri için hafif bir masaütü" msgstr "UNIX-gibi işletim sistemleri için hafif bir masaütü"
#: src/main.c:181 #: src/main.c:130
msgid "Free desktop environment with comparatively low resource requirements" msgid "Free desktop environment with comparatively low resource requirements"
msgstr "Nispeten düşük sistem gereksinimleri olan özgür bir masaüstü ortamı" msgstr "Nispeten düşük sistem gereksinimleri olan özgür bir masaüstü ortamı"
#: src/main.c:187 #: src/main.c:136
msgid "Tiling window manager based on binary space partitioning" msgid "Tiling window manager based on binary space partitioning"
msgstr "İkili alan bölme tabanlı döşeme pencere yöneticisi" msgstr "İkili alan bölme tabanlı döşeme pencere yöneticisi"
#: src/main.c:193 #: src/main.c:140
msgid "Improved tiling window manager" msgid "Improved tiling window manager"
msgstr "Geliştirilmiş döşeme pencere yöneticisi" msgstr "Geliştirilmiş döşeme pencere yöneticisi"
#: src/main.c:201 #: src/main.c:146
#, fuzzy #, fuzzy
msgid "mp is not installed!" msgid "mp is not installed!"
msgstr "mp kurulu değil" msgstr "mp kurulu değil"
#: src/main.c:210 #: src/main.c:155
msgid "Install doas or sudo to use this script" msgid "Install doas or sudo to use this script"
msgstr "Bu betiği kullanmak için doas ya da sudo kurun" msgstr "Bu betiği kullanmak için doas ya da sudo kurun"
#: src/main.c:229 #: src/main.c:170
msgid "Choose a desktop enviroment" msgid "Choose a desktop enviroment"
msgstr "Bir masaüstü ortamı seçin" msgstr "Bir masaüstü ortamı seçin"
#: src/main.c:235 #: src/main.c:176
msgid "Yes"
msgstr "Evet"
#: src/main.c:235
msgid "No"
msgstr "Hayır"
#: src/main.c:242
msgid "Add auto-startx to shell configuration?" msgid "Add auto-startx to shell configuration?"
msgstr "Otomatik-startx kabuk konfigürasyonu ekle?" msgstr "Otomatik-startx kabuk konfigürasyonu ekle?"
#: src/main.c:268 #: src/main.c:197
msgid "Configuration has been saved!" msgid "Configuration has been saved!"
msgstr "Konfigürasyon kaydedildi!" msgstr "Konfigürasyon kaydedildi!"
#: src/main.c:270 #: src/main.c:199
#, fuzzy, c-format #, fuzzy, c-format
msgid "Installing %s" msgid "Installing %s"
msgstr "%s kuruluyor" msgstr "%s kuruluyor"
#: src/main.c:276 #: src/main.c:203
#, fuzzy #, fuzzy
msgid "Installation failed" msgid "Installation failed"
msgstr "Kurulum başarısız oldu" msgstr "Kurulum başarısız oldu"
#: src/term.c:82
msgid "Yes"
msgstr "Evet"
#: src/term.c:82
msgid "No"
msgstr "Hayır"

View File

@ -1,36 +1,36 @@
#include <stdio.h>
#include <stdarg.h>
#include "log.h" #include "log.h"
#include <stdarg.h>
#include <stdio.h>
void info(const char* msg, ...){ void info(const char *msg, ...) {
va_list args; va_list args;
va_start(args, msg); va_start(args, msg);
printf(LOG_BOLD LOG_BLUE">>> "LOG_RESET LOG_BOLD); printf(C_BOLD C_BLUE ">>> " C_RESET C_BOLD);
vprintf(msg, args); vprintf(msg, args);
printf(LOG_RESET"\n"); printf(C_RESET "\n");
va_end(args); va_end(args);
} }
void error(const char* msg, ...){ void error(const char *msg, ...) {
va_list args; va_list args;
va_start(args, msg); va_start(args, msg);
printf(LOG_BOLD LOG_RED">>> "LOG_RESET LOG_BOLD); printf(C_BOLD C_RED ">>> " C_RESET C_BOLD);
vprintf(msg, args); vprintf(msg, args);
printf(LOG_RESET"\n"); printf(C_RESET "\n");
va_end(args); va_end(args);
} }
void success(const char* msg, ...){ void success(const char *msg, ...) {
va_list args; va_list args;
va_start(args, msg); va_start(args, msg);
printf(LOG_BOLD LOG_GREEN">>> "LOG_RESET LOG_BOLD); printf(C_BOLD C_GREEN ">>> " C_RESET C_BOLD);
vprintf(msg, args); vprintf(msg, args);
printf(LOG_RESET"\n"); printf(C_RESET "\n");
va_end(args); va_end(args);
} }

View File

@ -1,9 +1,11 @@
#define LOG_RED "\x1b[31m" #pragma once
#define LOG_BOLD "\x1b[1m"
#define LOG_BLUE "\x1b[34m"
#define LOG_GREEN "\x1b[32m"
#define LOG_RESET "\x1b[0m"
void info(const char* msg, ...); #define C_RED "\x1b[31m"
void error(const char* msg, ...); #define C_BOLD "\x1b[1m"
void success(const char* msg, ...); #define C_BLUE "\x1b[34m"
#define C_GREEN "\x1b[32m"
#define C_RESET "\x1b[0m"
void info(const char *msg, ...);
void error(const char *msg, ...);
void success(const char *msg, ...);

View File

@ -18,137 +18,85 @@
*/ */
#include <sys/wait.h>
#include <stdbool.h>
#include <libintl.h>
#include <locale.h>
#include <limits.h>
#include <curses.h> #include <curses.h>
#include <libintl.h>
#include <limits.h>
#include <locale.h>
#include <menu.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h>
#include <menu.h>
#include "util.h"
#include "log.h" #include "log.h"
#include "term.h"
#include "util.h"
#define _(x) gettext(x) #define _(x) gettext(x)
int ask(char* text, ITEM** items, int sz) { bool add_startx() {
attron(COLOR_PAIR(1) | A_BOLD);
mvprintw(1, 1, "%s", text);
char line[strlen(text)+5];
for (int i = 0; i < strlen(text); i++){
line[i] = '#';
line[i+1] = '\0';
}
mvprintw(2, 1, "%s", line);
attroff(COLOR_PAIR(1) | A_BOLD);
refresh();
WINDOW* swin = newwin(LINES-3, COLS-1, 3, 1);
keypad(swin, TRUE);
MENU* menu = new_menu(items);
set_menu_win(menu, swin);
set_menu_sub(menu, swin);
set_menu_mark(menu, ">");
post_menu(menu);
wrefresh(swin);
bool done = false;
int indx = 0, c = 0;
while((c = wgetch(swin))){
switch(c){
case KEY_DOWN:
if (indx != (sz+1))
indx++;
menu_driver(menu, REQ_DOWN_ITEM);
break;
case KEY_UP:
if (indx != 0)
indx--;
menu_driver(menu, REQ_UP_ITEM);
break;
case '\n':
done = true;
break;
}
wrefresh(swin);
if(done)
break;
}
free_menu(menu);
return indx;
}
bool add_startx(){
bool ret = false; bool ret = false;
char* profile = ".bash_profile"; char *profile = ".bash_profile";
char* shellenv = getenv("SHELL"); char *shellenv = getenv("SHELL");
if (NULL != shellenv && endswith(shellenv, "zsh")) if (NULL != shellenv && endswith(shellenv, "zsh"))
profile = ".zshrc"; profile = ".zshrc";
char profile_file[PATH_MAX]; char profile_file[PATH_MAX];
if(!joinhome(profile_file, profile)){ if (!joinhome(profile_file, profile)) {
error(_("Failed to get the home directory")); error(_("Failed to get the home directory"));
return ret; return ret;
} }
FILE* pf = fopen(profile_file, "r"); FILE *pf = fopen(profile_file, "r");
if(NULL==pf){ if (NULL == pf) {
error(_("Failed to open %s for reading"), profile_file); error(_("Failed to open %s for reading"), profile_file);
return ret; return ret;
} }
char* line = NULL, *all = NULL; char *line = NULL, *all = NULL;
int indx = 0; int indx = 0;
size_t sz, len; size_t sz, len;
while((sz = getline(&line, &len, pf)) != -1) { while ((sz = getline(&line, &len, pf)) != -1) {
if(strcmp(line, "#auto-startx \n")==0){ if (strcmp(line, "#auto-startx \n") == 0) {
ret = true; ret = true;
goto END; goto END;
} }
if (NULL == all){ if (NULL == all) {
all = malloc(sz); all = malloc(sz);
for(int i = 0; i < sz; i++){ for (int i = 0; i < sz; i++) {
all[indx] = line[i]; all[indx] = line[i];
indx++; indx++;
} }
}else { } else {
all = realloc(all, indx+sz); all = realloc(all, indx + sz);
for(int i = 0; i < sz; i++){ for (int i = 0; i < sz; i++) {
all[indx] = line[i]; all[indx] = line[i];
indx++; indx++;
} }
} }
} }
char* startx = AUTOSTARTX; char *startx = AUTOSTARTX;
all = realloc(all, indx+strlen(startx)+10); all = realloc(all, indx + strlen(startx) + 10);
for(int i = 0; i < strlen(startx); i++){ for (int i = 0; i < strlen(startx); i++) {
all[indx] = startx[i]; all[indx] = startx[i];
indx++; indx++;
} }
fclose(pf); fclose(pf);
pf = fopen(profile_file, "w"); pf = fopen(profile_file, "w");
if(NULL==pf){ if (NULL == pf) {
error(_("Failed to open %s for writing"), profile_file); error(_("Failed to open %s for writing"), profile_file);
goto END; goto END;
} }
all[indx] = '\0'; all[indx] = '\0';
if(fwrite(all, 1, indx, pf)<=0) if (fwrite(all, 1, indx, pf) <= 0)
error(_("Failed to write to %s"), profile_file); error(_("Failed to write to %s"), profile_file);
ret = true; ret = true;
@ -159,8 +107,8 @@ END:
return ret; return ret;
} }
int main(int argc, char** argv, char** envp){ int main(int argc, char **argv, char **envp) {
if(getuid()==0){ if (getuid() == 0) {
error(_("You should use this script as a regular user, not as root!")); error(_("You should use this script as a regular user, not as root!"));
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -168,97 +116,78 @@ int main(int argc, char** argv, char** envp){
signal(SIGINT, SIG_IGN); signal(SIGINT, SIG_IGN);
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
textdomain("xcfg"); textdomain("xcfg");
struct Desktop desktops[] = {
{
.name="XFCE4",
.desc=_("Lightweight desktop environment for UNIX-like operating systems"),
.pkg="xfce4",
.cmd="startxfce4\n",
},
{
.name="LXDE",
.desc=_("Free desktop environment with comparatively low resource requirements"),
.pkg="lxde",
.cmd="startlxde\n",
},
{
.name="bspwm",
.desc=_("Tiling window manager based on binary space partitioning"),
.pkg="bspwm",
.cmd="bspwm\n"
},
{
.name="i3",
.desc=_("Improved tiling window manager"),
.pkg="i3",
.cmd="i3\n"
}
};
char* mpi_path = check_path("mp-install"); struct Desktop desktops[] = {
if(NULL==mpi_path){ {
.name = "XFCE4",
.desc = _("Lightweight desktop environment for UNIX-like operating "
"systems"),
.pkg = "xfce4",
.cmd = "startxfce4\n",
},
{
.name = "LXDE",
.desc = _("Free desktop environment with comparatively low resource "
"requirements"),
.pkg = "lxde",
.cmd = "startlxde\n",
},
{.name = "bspwm",
.desc = _("Tiling window manager based on binary space partitioning"),
.pkg = "bspwm",
.cmd = "bspwm\n"},
{.name = "i3",
.desc = _("Improved tiling window manager"),
.pkg = "i3",
.cmd = "i3\n"}};
char *mpi_path = check_path("mp-install");
if (NULL == mpi_path) {
error(_("mp is not installed!")); error(_("mp is not installed!"));
return EXIT_FAILURE; return EXIT_FAILURE;
} }
free(mpi_path); free(mpi_path);
char* doas_path = check_path("doas"); char *doas_path = check_path("doas");
if(NULL==doas_path) { if (NULL == doas_path) {
doas_path = check_path("sudo"); doas_path = check_path("sudo");
if(NULL==doas_path){ if (NULL == doas_path) {
error(_("Install doas or sudo to use this script")); error(_("Install doas or sudo to use this script"));
free(mpi_path); free(mpi_path);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
initscr(); term_init();
cbreak();
noecho();
keypad(stdscr, TRUE);
init_pair(1, COLOR_BLUE, COLOR_BLUE);
int sz = sizeof(desktops)/sizeof(struct Desktop); int sz = sizeof(desktops) / sizeof(struct Desktop);
ITEM** items = malloc(sizeof(ITEM *)*(sz+1)); ITEM **items = malloc(sizeof(ITEM *) * (sz + 1));
for(int i = 0; i < sz; i++) for (int i = 0; i < sz; i++)
items[i] = new_item(desktops[i].name, desktops[i].desc); items[i] = new_item(desktops[i].name, desktops[i].desc);
items[sz] = NULL; items[sz] = NULL;
int indx = ask(_("Choose a desktop enviroment"), items, sz+1); int indx = term_ask(_("Choose a desktop enviroment"), items, sz + 1);
for (int i = 0; i < sz; i++) for (int i = 0; i < sz; i++)
free_item(items[i]); free_item(items[i]);
free(items); free(items);
clear(); clear();
char* yn[] = {_("Yes"), _("No"), NULL}; bool autox = term_yn(_("Add auto-startx to shell configuration?"));
sz = sizeof(yn)/sizeof(char*);
items = (ITEM **)malloc(sizeof(ITEM *)*(sz+1));
for(int i = 0; i < sz; i++) term_finish();
items[i] = new_item(yn[i], "");
bool autox = ask(_("Add auto-startx to shell configuration?"), items, sz) == 0; if (autox && !add_startx())
for (int i = 0; i < sz; i++)
free_item(items[i]);
free(items);
clear();
clear();
endwin();
if(autox && !add_startx())
goto FAIL; goto FAIL;
char xinitrc[PATH_MAX]; char xinitrc[PATH_MAX];
if(!joinhome(xinitrc, ".xinitrc")){ if (!joinhome(xinitrc, ".xinitrc")) {
error(_("Failed to get the home directory")); error(_("Failed to get the home directory"));
goto FAIL; goto FAIL;
} }
FILE* xf = fopen(xinitrc, "w"); FILE *xf = fopen(xinitrc, "w");
if(fwrite(desktops[indx].cmd, 1, strlen(desktops[indx].cmd), xf)<0){ if (fwrite(desktops[indx].cmd, 1, strlen(desktops[indx].cmd), xf) < 0) {
error(_("Failed to write to %s"), xinitrc); error(_("Failed to write to %s"), xinitrc);
fclose(xf); fclose(xf);
goto FAIL; goto FAIL;
@ -268,11 +197,9 @@ int main(int argc, char** argv, char** envp){
success(_("Configuration has been saved!")); success(_("Configuration has been saved!"));
info(_("Installing %s"), desktops[indx].name, mpi_path); info(_("Installing %s"), desktops[indx].name, mpi_path);
char* args[] = { char *args[] = {doas_path, "mp-install", desktops[indx].pkg, NULL};
doas_path, "mp-install", desktops[indx].pkg, NULL
};
if(execvp(doas_path, args) != 0) { if (execvp(doas_path, args) != 0) {
error(_("Installation failed")); error(_("Installation failed"));
} }

100
src/term.c Normal file
View File

@ -0,0 +1,100 @@
#include <libintl.h>
#include <menu.h>
#include <ncurses.h>
#include <string.h>
#define _(x) gettext(x)
void term_init() {
initscr();
if (has_colors()) {
use_default_colors();
start_color();
}
cbreak();
noecho();
keypad(stdscr, TRUE);
init_pair(1, COLOR_GREEN, -1);
init_pair(2, COLOR_BLUE, -1);
start_color();
}
int term_ask(char *text, ITEM **items, int sz) {
attron(COLOR_PAIR(1) | A_BOLD);
mvprintw(1, 1, "%s", text);
char line[strlen(text) + 5];
for (int i = 0; i < strlen(text); i++) {
line[i] = '=';
line[i + 1] = '\0';
}
mvprintw(2, 1, "%s", line);
attroff(COLOR_PAIR(1) | A_BOLD);
refresh();
WINDOW *swin = newwin(LINES - 3, COLS - 1, 3, 1);
keypad(swin, TRUE);
MENU *menu = new_menu(items);
set_menu_win(menu, swin);
set_menu_sub(menu, swin);
set_menu_mark(menu, ">>> ");
set_menu_fore(menu, COLOR_PAIR(2));
post_menu(menu);
curs_set(0);
wrefresh(swin);
bool done = false;
int indx = 0, c = 0;
while ((c = wgetch(swin))) {
switch (c) {
case KEY_DOWN:
if (indx != (sz + 1))
indx++;
menu_driver(menu, REQ_DOWN_ITEM);
break;
case KEY_UP:
if (indx != 0)
indx--;
menu_driver(menu, REQ_UP_ITEM);
break;
case '\n':
done = true;
break;
}
wrefresh(swin);
if (done)
break;
}
curs_set(1);
free_menu(menu);
return indx;
}
bool term_yn(char *text) {
char *yn[] = {_("Yes"), _("No"), NULL};
int sz = sizeof(yn) / sizeof(char *);
ITEM *items[sz + 1];
for (int i = 0; i < sz; i++)
items[i] = new_item(yn[i], "");
bool res = term_ask(_(text), items, sz) == 0;
for (int i = 0; i < sz; i++)
free_item(items[i]);
clear();
return res;
}
void term_finish() {
clear();
endwin();
}

7
src/term.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <menu.h>
void term_init();
int term_ask(char *, ITEM **, int);
bool term_yn(char *);
void term_finish();

View File

@ -1,49 +1,47 @@
#include <stdbool.h> #include "util.h"
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h>
#include "util.h"
bool joinhome(char* res, char* path){ bool joinhome(char *res, char *path) {
char* homedir = getenv("HOME"); char *homedir = getenv("HOME");
if(NULL==homedir) if (NULL == homedir)
return false; return false;
snprintf(res, PATH_MAX, "%s/%s", homedir, path); snprintf(res, PATH_MAX, "%s/%s", homedir, path);
return true; return true;
} }
bool exists(char* path){ bool exists(char *path) { return access(path, F_OK) == 0; }
return access(path, F_OK)==0;
}
bool endswith(const char *str, const char *suf){ bool endswith(const char *str, const char *suf) {
int strl = strlen(str); int strl = strlen(str);
int sufl = strlen(suf); int sufl = strlen(suf);
if (sufl > strl) if (sufl > strl)
return false; return false;
return strncmp(str + strl - sufl, suf, sufl) == 0; return strncmp(str + strl - sufl, suf, sufl) == 0;
} }
char* check_path(char* bin) { char *check_path(char *bin) {
char* path = getenv("PATH"); char *path = getenv("PATH");
char* res = NULL; char *res = NULL;
if(NULL == path) if (NULL == path)
return NULL; return NULL;
path = strdup(path); path = strdup(path);
char* p = strtok(path, ":"); char *p = strtok(path, ":");
while(NULL != p) { while (NULL != p) {
char* fp = malloc(PATH_MAX); char *fp = malloc(PATH_MAX);
snprintf(fp, PATH_MAX, "%s/%s", p, bin); snprintf(fp, PATH_MAX, "%s/%s", p, bin);
if(exists(fp)){ if (exists(fp)) {
res = fp; res = fp;
break; break;
} }

View File

@ -1,13 +1,18 @@
#define AUTOSTARTX "\n#auto-startx \nif [[ \"$(tty)\" == \"/dev/tty1\" ]] && [ -z \"$DISPLAY\" ]; then\nexec startx\nfi\n" #pragma once
#include <stdbool.h>
struct Desktop { #define AUTOSTARTX \
char* name; "\n#auto-startx \nif [[ \"$(tty)\" == \"/dev/tty1\" ]] && [ -z " \
char* desc; "\"$DISPLAY\" ]; then\nexec startx\nfi\n"
char* pkg;
char* cmd;
};
bool exists(char*); typedef struct Desktop {
char* check_path(char*); char *name;
bool joinhome(char*, char*); char *desc;
bool endswith(const char*, const char*); char *pkg;
char *cmd;
} desktop_t;
bool exists(char *);
char *check_path(char *);
bool joinhome(char *, char *);
bool endswith(const char *, const char *);