moved code here. still needs to update gh
This commit is contained in:
22
backups/bat0daemonbak/Makefile
Normal file
22
backups/bat0daemonbak/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
CC = gcc
|
||||
CFLAGS = `pkg-config --cflags gtk+-3.0` -I$(INC_DIR)
|
||||
LDFLAGS = `pkg-config --libs gtk+-3.0`
|
||||
SRC_DIR = src
|
||||
INC_DIR = include
|
||||
OBJ_DIR = obj
|
||||
OBJS = $(OBJ_DIR)/battery_monitor.o $(OBJ_DIR)/notification.o $(OBJ_DIR)/process_monitor.o
|
||||
TARGET = battery_monitor
|
||||
|
||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
|
||||
@mkdir -p $(OBJ_DIR)
|
||||
$(CC) $(CFLAGS) -I$(INC_DIR) -o $@ -c $<
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) -o $(TARGET) $(OBJS) $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJ_DIR) $(TARGET)
|
||||
|
||||
.PHONY: all clean
|
||||
0
backups/bat0daemonbak/README.md
Normal file
0
backups/bat0daemonbak/README.md
Normal file
29
backups/bat0daemonbak/battery_daemon.sh
Executable file
29
backups/bat0daemonbak/battery_daemon.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Set up environment if needed
|
||||
export DISPLAY=:0
|
||||
export XAUTHORITY="$HOME/.Xauthority"
|
||||
|
||||
# Path to the battery monitor binary
|
||||
BINARY_PATH="/usr/local/bin/battery_monitor"
|
||||
|
||||
# Log file
|
||||
LOG_FILE="/tmp/battery_monitor.log"
|
||||
|
||||
# Create log directory if it doesn't exist
|
||||
mkdir -p "$(dirname "$LOG_FILE")"
|
||||
|
||||
# Log starting message and environment variables
|
||||
echo "Starting battery monitor script" >> "$LOG_FILE"
|
||||
echo "DISPLAY=$DISPLAY" >> "$LOG_FILE"
|
||||
echo "XAUTHORITY=$XAUTHORITY" >> "$LOG_FILE"
|
||||
|
||||
# Check if binary exists and is executable
|
||||
if [ ! -x "$BINARY_PATH" ]; then
|
||||
echo "Binary not found or not executable: $BINARY_PATH" >> "$LOG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Start the battery monitor and redirect output to log file
|
||||
exec "$BINARY_PATH" >> "$LOG_FILE" 2>&1
|
||||
|
||||
BIN
backups/bat0daemonbak/battery_monitor
Executable file
BIN
backups/bat0daemonbak/battery_monitor
Executable file
Binary file not shown.
17
backups/bat0daemonbak/battery_monitor.service
Executable file
17
backups/bat0daemonbak/battery_monitor.service
Executable file
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Battery Monitor Service
|
||||
PartOf=graphical.target
|
||||
After=graphical.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/battery_daemon.sh
|
||||
Restart=always
|
||||
Environment=DISPLAY=:0
|
||||
Environment=XAUTHORITY=%h/.Xauthority
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=graphical.target
|
||||
|
||||
4
backups/bat0daemonbak/docs/battery_monitor.log
Normal file
4
backups/bat0daemonbak/docs/battery_monitor.log
Normal file
@@ -0,0 +1,4 @@
|
||||
Starting battery monitor script
|
||||
DISPLAY=:0
|
||||
XAUTHORITY=/home/klein/.Xauthority
|
||||
Failed to open log file: Permission denied
|
||||
0
backups/bat0daemonbak/docs/procress_list.txt
Normal file
0
backups/bat0daemonbak/docs/procress_list.txt
Normal file
16
backups/bat0daemonbak/include/battery_monitor.h
Normal file
16
backups/bat0daemonbak/include/battery_monitor.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef BATTERY_MONITOR_H
|
||||
#define BATTERY_MONITOR_H
|
||||
|
||||
void show_notification(const char *message, const char *title);
|
||||
int get_battery_level();
|
||||
int is_charging();
|
||||
int activate_battery_saving_mode();
|
||||
int enter_sleep_mode();
|
||||
int kill_processes(const char *filename);
|
||||
int set_brightness(int brightness);
|
||||
void log_message(const char *message);
|
||||
|
||||
// New function declaration for process monitoring
|
||||
int get_high_cpu_processes(char *process_list[], int max_processes);
|
||||
|
||||
#endif // BATTERY_MONITOR_H
|
||||
8
backups/bat0daemonbak/include/process_monitor.h
Normal file
8
backups/bat0daemonbak/include/process_monitor.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef PROCESS_MONITOR_H
|
||||
#define PROCESS_MONITOR_H
|
||||
|
||||
int get_high_cpu_processes(char *process_list[], int max_processes);
|
||||
void free_process_list(char *process_list[], int count);
|
||||
|
||||
#endif // PROCESS_MONITOR_H
|
||||
|
||||
63
backups/bat0daemonbak/install.sh
Executable file
63
backups/bat0daemonbak/install.sh
Executable file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Function to check if a command exists
|
||||
check_dependency() {
|
||||
if ! command -v "$1" &> /dev/null; then
|
||||
echo "$1 is not installed. Installing..."
|
||||
sudo apt-get install -y "$1"
|
||||
else
|
||||
echo "$1 is already installed."
|
||||
fi
|
||||
}
|
||||
|
||||
# Step 1: Finding the current working directory and script location
|
||||
SCRIPT_DIR=$(pwd)
|
||||
BASH_SCRIPT="$SCRIPT_DIR/battery_daemon.sh"
|
||||
SRC_SCRIPT="$SCRIPT_DIR/battery_monitor"
|
||||
|
||||
# Check if battery_daemon.sh exists
|
||||
if [[ -f "$BASH_SCRIPT" ]]; then
|
||||
echo "Found battery_daemon.sh. Moving to /usr/local/bin."
|
||||
sudo cp "$BASH_SCRIPT" /usr/local/bin/battery_daemon.sh
|
||||
sudo cp "$SRC_SCRIPT" /usr/local/bin/battery_monitor
|
||||
sudo chmod +x /usr/local/bin/battery_daemon
|
||||
sudo chmod +x /usr/local/bin/battery_daemon.sh
|
||||
else
|
||||
echo "battery_daemon.sh not found in the current directory!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Step 2: Check for dependencies and install if not present
|
||||
dependencies=("gcc" "make" "brightnessctl")
|
||||
|
||||
for dep in "${dependencies[@]}"; do
|
||||
check_dependency "$dep"
|
||||
done
|
||||
|
||||
# Step 3: Copy battery_monitor.service to systemd folder
|
||||
SYSTEMD_SERVICE="$SCRIPT_DIR/battery_monitor.service"
|
||||
if [[ -f "$SYSTEMD_SERVICE" ]]; then
|
||||
echo "Found battery_monitor.service. Copying to /etc/systemd/system/"
|
||||
sudo cp "$SYSTEMD_SERVICE" /etc/systemd/system/
|
||||
else
|
||||
echo "battery_monitor.service not found in the current directory!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Step 4: Reload the systemd daemon, enable and restart the service
|
||||
echo "Reloading systemd daemon..."
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
echo "Enabling battery_monitor.service..."
|
||||
sudo systemctl enable battery_monitor.service
|
||||
|
||||
echo "Restarting battery_monitor.service..."
|
||||
sudo systemctl restart battery_monitor.service
|
||||
|
||||
# Check if the service was successfully started
|
||||
if systemctl is-active --quiet battery_monitor.service; then
|
||||
echo "Service started successfully!"
|
||||
else
|
||||
echo "Failed to start the service."
|
||||
exit 1
|
||||
fi
|
||||
BIN
backups/bat0daemonbak/obj/battery_monitor.o
Normal file
BIN
backups/bat0daemonbak/obj/battery_monitor.o
Normal file
Binary file not shown.
BIN
backups/bat0daemonbak/obj/notification.o
Normal file
BIN
backups/bat0daemonbak/obj/notification.o
Normal file
Binary file not shown.
BIN
backups/bat0daemonbak/obj/process_monitor.o
Normal file
BIN
backups/bat0daemonbak/obj/process_monitor.o
Normal file
Binary file not shown.
70
backups/bat0daemonbak/src/battery_monitor.c
Normal file
70
backups/bat0daemonbak/src/battery_monitor.c
Normal file
@@ -0,0 +1,70 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include "battery_monitor.h"
|
||||
|
||||
// Define the battery thresholds
|
||||
#define THRESHOLD_LOW 15
|
||||
#define THRESHOLD_CRITICAL 5
|
||||
#define THRESHOLD_HIGH 80
|
||||
|
||||
// Track if notifications have been sent
|
||||
int notified_low = 0;
|
||||
int notified_critical = 0;
|
||||
|
||||
int main() {
|
||||
log_message("Battery monitor started");
|
||||
|
||||
while (1) {
|
||||
if (is_charging()) {
|
||||
// Reset notifications if the battery is charging
|
||||
log_message("Battery is charging, notifications reset");
|
||||
notified_low = 0;
|
||||
notified_critical = 0;
|
||||
sleep(300); // Sleep for 5 minutes while charging
|
||||
continue;
|
||||
}
|
||||
|
||||
int battery_level = get_battery_level();
|
||||
if (battery_level == -1) {
|
||||
log_message("Battery level read failed, retrying in 1 minute");
|
||||
sleep(60);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dynamic sleep interval based on battery level
|
||||
int sleep_duration = 60; // Default 1 minute
|
||||
|
||||
if (battery_level > THRESHOLD_HIGH) {
|
||||
sleep_duration = 300; // Sleep for 5 minutes
|
||||
} else if (battery_level <= THRESHOLD_CRITICAL) {
|
||||
sleep_duration = 30; // Sleep for 30 seconds when critically low
|
||||
} else if (battery_level <= THRESHOLD_LOW) {
|
||||
sleep_duration = 60; // Sleep for 1 minute when low
|
||||
}
|
||||
|
||||
// Check if the battery level is below the critical threshold
|
||||
if (battery_level <= THRESHOLD_CRITICAL && !notified_critical) {
|
||||
log_message("Battery critically low, showing notification");
|
||||
show_notification("Battery is critically low, below 5%", "Critical Battery Warning");
|
||||
notified_critical = 1;
|
||||
} else if (battery_level <= THRESHOLD_LOW && !notified_low) {
|
||||
log_message("Battery low, showing notification");
|
||||
show_notification("Battery is low, below 15%", "Low Battery Warning");
|
||||
notified_low = 1;
|
||||
}
|
||||
|
||||
// Reset notifications if battery level goes back up
|
||||
if (battery_level > THRESHOLD_LOW) {
|
||||
notified_low = 0;
|
||||
}
|
||||
if (battery_level > THRESHOLD_CRITICAL) {
|
||||
notified_critical = 0;
|
||||
}
|
||||
|
||||
// Wait for the dynamically determined duration before checking again
|
||||
sleep(sleep_duration);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
281
backups/bat0daemonbak/src/notification.c
Normal file
281
backups/bat0daemonbak/src/notification.c
Normal file
@@ -0,0 +1,281 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include "battery_monitor.h"
|
||||
#include "process_monitor.h"
|
||||
|
||||
#define CSS_STYLE "\
|
||||
* { \
|
||||
background-color: #333333; \
|
||||
color: white; \
|
||||
} \
|
||||
button { \
|
||||
background-color: #555555; \
|
||||
color: white; \
|
||||
} \
|
||||
"
|
||||
|
||||
// Function to get the battery level
|
||||
int get_battery_level() {
|
||||
const char *battery_paths[] = {
|
||||
"/sys/class/power_supply/BAT0/capacity",
|
||||
"/sys/class/power_supply/BAT1/capacity"
|
||||
};
|
||||
FILE *file;
|
||||
int battery_level = -1;
|
||||
|
||||
for (int i = 0; i < sizeof(battery_paths) / sizeof(battery_paths[0]); i++) {
|
||||
file = fopen(battery_paths[i], "r");
|
||||
if (file != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (file == NULL) {
|
||||
perror("Failed to open capacity file");
|
||||
log_message("Failed to open capacity file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fscanf(file, "%d", &battery_level) != 1) {
|
||||
perror("Failed to read battery level");
|
||||
log_message("Failed to read battery level");
|
||||
fclose(file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return battery_level;
|
||||
}
|
||||
|
||||
// Function to get the base directory of the executable
|
||||
char *get_base_directory() {
|
||||
static char base_dir[PATH_MAX];
|
||||
ssize_t count = readlink("/proc/self/exe", base_dir, PATH_MAX);
|
||||
if (count != -1) {
|
||||
dirname(base_dir);
|
||||
}
|
||||
return base_dir;
|
||||
}
|
||||
|
||||
// Function to log messages to a file
|
||||
void log_message(const char *message) {
|
||||
char log_file[PATH_MAX];
|
||||
snprintf(log_file, PATH_MAX, "/tmp/battery_monitor.log");
|
||||
|
||||
FILE *log_file_ptr = fopen(log_file, "a");
|
||||
if (log_file_ptr) {
|
||||
fprintf(log_file_ptr, "%s\n", message);
|
||||
fclose(log_file_ptr);
|
||||
} else {
|
||||
perror("Failed to open log file");
|
||||
}
|
||||
}
|
||||
|
||||
// Function to activate battery saving mode
|
||||
int activate_battery_saving_mode() {
|
||||
log_message("Activating battery saving mode");
|
||||
|
||||
char process_list_file[PATH_MAX];
|
||||
snprintf(process_list_file, PATH_MAX, "%s/../docs/process_list.txt", get_base_directory());
|
||||
|
||||
if (kill_processes(process_list_file) == -1) {
|
||||
return -1; // Return failure if processes couldn't be killed
|
||||
}
|
||||
|
||||
if (set_brightness(50) == -1) {
|
||||
return -1; // Return failure if brightness couldn't be set
|
||||
}
|
||||
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
// Function to enter sleep mode
|
||||
int enter_sleep_mode() {
|
||||
log_message("Entering sleep mode");
|
||||
return system("systemctl suspend"); // Return system command result
|
||||
}
|
||||
|
||||
// Function to apply custom CSS styles to the GTK widgets
|
||||
void apply_css(GtkWidget *widget, const char *css) {
|
||||
GtkCssProvider *provider = gtk_css_provider_new();
|
||||
gtk_css_provider_load_from_data(provider, css, -1, NULL);
|
||||
GtkStyleContext *context = gtk_widget_get_style_context(widget);
|
||||
gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
g_object_unref(provider);
|
||||
}
|
||||
|
||||
// Function to check the battery status and close the dialog if charging
|
||||
gboolean check_battery_status(gpointer user_data) {
|
||||
GtkWidget *dialog = GTK_WIDGET(user_data);
|
||||
if (is_charging()) {
|
||||
log_message("Battery started charging, closing notification");
|
||||
gtk_widget_destroy(dialog);
|
||||
gtk_main_quit(); // Exit the GTK main loop
|
||||
return FALSE; // Stop checking
|
||||
}
|
||||
return TRUE; // Continue checking
|
||||
}
|
||||
|
||||
// Function to handle dialog response
|
||||
void on_dialog_response(GtkDialog *dialog, gint response_id, gpointer user_data) {
|
||||
switch (response_id) {
|
||||
case GTK_RESPONSE_OK:
|
||||
log_message("User clicked OK");
|
||||
break;
|
||||
case GTK_RESPONSE_APPLY:
|
||||
log_message("User activated Battery Saving Mode");
|
||||
activate_battery_saving_mode();
|
||||
break;
|
||||
case GTK_RESPONSE_CLOSE:
|
||||
log_message("User triggered Sleep Mode");
|
||||
enter_sleep_mode();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gtk_widget_destroy(GTK_WIDGET(dialog));
|
||||
gtk_main_quit(); // Exit the GTK main loop
|
||||
}
|
||||
|
||||
// Function to show the notification dialog
|
||||
void show_notification(const char *message, const char *title) {
|
||||
log_message("Showing notification");
|
||||
|
||||
GtkWidget *dialog;
|
||||
gtk_init(0, NULL);
|
||||
|
||||
dialog = gtk_message_dialog_new(NULL,
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_INFO,
|
||||
GTK_BUTTONS_NONE,
|
||||
"%s", message);
|
||||
gtk_dialog_add_button(GTK_DIALOG(dialog), "OK", GTK_RESPONSE_OK);
|
||||
gtk_dialog_add_button(GTK_DIALOG(dialog), "Battery Saving Mode", GTK_RESPONSE_APPLY);
|
||||
|
||||
if (g_strcmp0(title, "Critical Battery Warning") == 0) {
|
||||
gtk_dialog_add_button(GTK_DIALOG(dialog), "Sleep", GTK_RESPONSE_CLOSE);
|
||||
}
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(dialog), title);
|
||||
|
||||
// Apply CSS styles
|
||||
apply_css(dialog, CSS_STYLE);
|
||||
|
||||
// Set up the callback to check battery status and close if charging
|
||||
g_timeout_add(1000, check_battery_status, dialog);
|
||||
|
||||
// Connect the dialog response to handle button clicks and ensure proper cleanup
|
||||
g_signal_connect(dialog, "response", G_CALLBACK(on_dialog_response), NULL);
|
||||
|
||||
// Show the dialog and enter the GTK main loop
|
||||
gtk_widget_show_all(dialog);
|
||||
gtk_main(); // Start the GTK main loop
|
||||
}
|
||||
|
||||
// Function to check if the battery is charging
|
||||
int is_charging() {
|
||||
const char *status_paths[] = {
|
||||
"/sys/class/power_supply/BAT0/status",
|
||||
"/sys/class/power_supply/BAT1/status"
|
||||
};
|
||||
FILE *file;
|
||||
char status[16];
|
||||
|
||||
for (int i = 0; i < sizeof(status_paths) / sizeof(status_paths[0]); i++) {
|
||||
file = fopen(status_paths[i], "r");
|
||||
if (file != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (file == NULL) {
|
||||
perror("Failed to open status file");
|
||||
log_message("Failed to open status file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fscanf(file, "%15s", status) != 1) {
|
||||
perror("Failed to read battery status");
|
||||
log_message("Failed to read battery status");
|
||||
fclose(file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return (strcmp(status, "Charging") == 0);
|
||||
}
|
||||
|
||||
// Function to kill processes based on a dynamic process list
|
||||
int kill_processes(const char *filename) {
|
||||
// Dynamic process list based on CPU usage
|
||||
char *process_list[100]; // Assuming a max of 100 processes to kill
|
||||
int process_count = get_high_cpu_processes(process_list, 100);
|
||||
|
||||
if (process_count == -1) {
|
||||
log_message("Failed to get high CPU processes");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < process_count; i++) {
|
||||
char command[300];
|
||||
snprintf(command, sizeof(command), "pkill %s", process_list[i]);
|
||||
log_message(command); // Log the command being executed
|
||||
if (system(command) == -1) {
|
||||
free_process_list(process_list, process_count);
|
||||
return -1; // Return failure if the command fails
|
||||
}
|
||||
}
|
||||
|
||||
free_process_list(process_list, process_count);
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
// Function to set the screen brightness
|
||||
int set_brightness(int brightness) {
|
||||
const char *brightness_path = "/sys/class/backlight/intel_backlight/brightness";
|
||||
const char *max_brightness_path = "/sys/class/backlight/intel_backlight/max_brightness";
|
||||
int max_brightness = 100;
|
||||
int new_brightness = 0;
|
||||
char buffer[4];
|
||||
|
||||
int fd = open(max_brightness_path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror("Failed to open max brightness file");
|
||||
log_message("Failed to open max brightness file");
|
||||
return -1; // Return failure if the file can't be opened
|
||||
}
|
||||
|
||||
if (read(fd, buffer, sizeof(buffer)) != -1) {
|
||||
max_brightness = atoi(buffer);
|
||||
} else {
|
||||
perror("Failed to read max brightness");
|
||||
log_message("Failed to read max brightness");
|
||||
close(fd);
|
||||
return -1; // Return failure if the file can't be read
|
||||
}
|
||||
close(fd);
|
||||
|
||||
new_brightness = max_brightness * brightness / 100;
|
||||
fd = open(brightness_path, O_WRONLY);
|
||||
if (fd == -1) {
|
||||
perror("Failed to open brightness file");
|
||||
log_message("Failed to open brightness file");
|
||||
return -1; // Return failure if the file can't be opened
|
||||
}
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%d", new_brightness);
|
||||
if (write(fd, buffer, strlen(buffer)) == -1) {
|
||||
perror("Failed to write to brightness file");
|
||||
log_message("Failed to write to brightness file");
|
||||
close(fd);
|
||||
return -1; // Return failure if the write fails
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0; // Success
|
||||
}
|
||||
143
backups/bat0daemonbak/src/notification.c.bak
Normal file
143
backups/bat0daemonbak/src/notification.c.bak
Normal file
@@ -0,0 +1,143 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "battery_monitor.h"
|
||||
|
||||
#define LOG_FILE "/home/klein/codeWS/C/bat0daemon/docs/battery_monitor.log"
|
||||
|
||||
void log_message(const char *message) {
|
||||
FILE *log_file = fopen(LOG_FILE, "a");
|
||||
if (log_file) {
|
||||
fprintf(log_file, "%s\n", message);
|
||||
fclose(log_file);
|
||||
} else {
|
||||
perror("Failed to open log file");
|
||||
}
|
||||
}
|
||||
|
||||
void activate_battery_saving_mode() {
|
||||
log_message("Activating battery saving mode");
|
||||
kill_processes("/home/klein/codeWS/C/bat0daemon/docs/procress_list.txt");
|
||||
set_brightness(50);
|
||||
}
|
||||
|
||||
void enter_sleep_mode() {
|
||||
log_message("Entering sleep mode");
|
||||
system("systemctl suspend");
|
||||
}
|
||||
|
||||
void show_notification(const char *message, const char *title) {
|
||||
log_message("Showing notification");
|
||||
GtkWidget *dialog;
|
||||
gtk_init(0, NULL);
|
||||
dialog = gtk_message_dialog_new(NULL,
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_INFO,
|
||||
GTK_BUTTONS_NONE,
|
||||
"%s", message);
|
||||
gtk_dialog_add_button(GTK_DIALOG(dialog), "OK", GTK_RESPONSE_OK);
|
||||
gtk_dialog_add_button(GTK_DIALOG(dialog), "Battery Saving Mode", GTK_RESPONSE_APPLY);
|
||||
|
||||
if (g_strcmp0(title, "Critical Battery Warning") == 0) {
|
||||
gtk_dialog_add_button(GTK_DIALOG(dialog), "Sleep", GTK_RESPONSE_CLOSE);
|
||||
}
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(dialog), title);
|
||||
|
||||
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
if (response == GTK_RESPONSE_APPLY) {
|
||||
activate_battery_saving_mode();
|
||||
} else if (response == GTK_RESPONSE_CLOSE) {
|
||||
enter_sleep_mode();
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
while (g_main_context_iteration(NULL, FALSE));
|
||||
}
|
||||
|
||||
int get_battery_level() {
|
||||
FILE *file;
|
||||
int battery_level = -1;
|
||||
|
||||
file = fopen("/sys/class/power_supply/BAT0/capacity", "r");
|
||||
if (file == NULL) {
|
||||
perror("Failed to open capacity file");
|
||||
log_message("Failed to open capacity file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fscanf(file, "%d", &battery_level) != 1) {
|
||||
perror("Failed to read battery level");
|
||||
log_message("Failed to read battery level");
|
||||
fclose(file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return battery_level;
|
||||
}
|
||||
|
||||
void kill_processes(const char *filename) {
|
||||
FILE *file = fopen(filename, "r");
|
||||
if (file == NULL) {
|
||||
perror("Failed to open process list file");
|
||||
log_message("Failed to open process list file");
|
||||
return;
|
||||
}
|
||||
|
||||
char process_name[256];
|
||||
while (fgets(process_name, sizeof(process_name), file)) {
|
||||
process_name[strcspn(process_name, "\n")] = 0; // Remove newline character
|
||||
if (strlen(process_name) > 0) {
|
||||
char command[300];
|
||||
snprintf(command, sizeof(command), "pkill %s", process_name);
|
||||
log_message(command); // Log the command being executed
|
||||
system(command);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void set_brightness(int brightness) {
|
||||
const char *brightness_path = "/sys/class/backlight/intel_backlight/brightness";
|
||||
const char *max_brightness_path = "/sys/class/backlight/intel_backlight/max_brightness";
|
||||
int max_brightness = 100;
|
||||
int new_brightness = 0;
|
||||
char buffer[4];
|
||||
|
||||
int fd = open(max_brightness_path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror("Failed to open max brightness file");
|
||||
log_message("Failed to open max brightness file");
|
||||
return;
|
||||
}
|
||||
|
||||
if (read(fd, buffer, sizeof(buffer)) != -1) {
|
||||
max_brightness = atoi(buffer);
|
||||
} else {
|
||||
perror("Failed to read max brightness");
|
||||
log_message("Failed to read max brightness");
|
||||
}
|
||||
close(fd);
|
||||
|
||||
new_brightness = max_brightness * brightness / 100;
|
||||
fd = open(brightness_path, O_WRONLY);
|
||||
if (fd == -1) {
|
||||
perror("Failed to open brightness file");
|
||||
log_message("Failed to open brightness file");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%d", new_brightness);
|
||||
if (write(fd, buffer, strlen(buffer)) == -1) {
|
||||
perror("Failed to write to brightness file");
|
||||
log_message("Failed to write to brightness file");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
45
backups/bat0daemonbak/src/process_monitor.c
Normal file
45
backups/bat0daemonbak/src/process_monitor.c
Normal file
@@ -0,0 +1,45 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "battery_monitor.h"
|
||||
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
int get_high_cpu_processes(char *process_list[], int max_processes) {
|
||||
FILE *fp;
|
||||
char buffer[BUFFER_SIZE];
|
||||
int process_count = 0;
|
||||
|
||||
// Command to get the top CPU-using processes for the user 'klein', excluding vi, neovim, vim, and root processes
|
||||
const char *command = "ps -eo user,pid,comm,%cpu --sort=-%cpu | grep '^klein' | grep -vE '(vi|vim|neovim|root)'";
|
||||
|
||||
fp = popen(command, "r");
|
||||
if (fp == NULL) {
|
||||
log_message("Failed to run command to get high CPU processes");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), fp) != NULL && process_count < max_processes) {
|
||||
char user[50], command_name[100];
|
||||
int pid;
|
||||
float cpu_usage;
|
||||
|
||||
// Parse the line to extract the user, PID, command name, and CPU usage
|
||||
sscanf(buffer, "%49s %d %99s %f", user, &pid, command_name, &cpu_usage);
|
||||
|
||||
// Store the command in the process list
|
||||
process_list[process_count] = malloc(BUFFER_SIZE);
|
||||
snprintf(process_list[process_count], BUFFER_SIZE, "%d", pid);
|
||||
process_count++;
|
||||
}
|
||||
|
||||
pclose(fp);
|
||||
return process_count;
|
||||
}
|
||||
|
||||
void free_process_list(char *process_list[], int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
free(process_list[i]);
|
||||
}
|
||||
}
|
||||
27
brightness_control_two/Makefile
Normal file
27
brightness_control_two/Makefile
Normal file
@@ -0,0 +1,27 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -std=c99
|
||||
LDFLAGS = -lX11
|
||||
|
||||
SRC_DIR = src
|
||||
OBJ_DIR = obj
|
||||
BIN_DIR = bin
|
||||
|
||||
SRCS = $(wildcard $(SRC_DIR)/*.c)
|
||||
OBJS = $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRCS))
|
||||
DEPS = $(OBJS:.o=.d)
|
||||
TARGET = $(BIN_DIR)/brightnessctl
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
@mkdir -p $(BIN_DIR)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
|
||||
@mkdir -p $(OBJ_DIR)
|
||||
$(CC) $(CFLAGS) -MMD -c $< -o $@
|
||||
|
||||
-include $(DEPS)
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJ_DIR) $(BIN_DIR)
|
||||
|
||||
.PHONY: clean
|
||||
2
brightness_control_two/obj/brightness.d
Normal file
2
brightness_control_two/obj/brightness.d
Normal file
@@ -0,0 +1,2 @@
|
||||
obj/brightness.o: src/brightness.c src/brightness.h src/display.h \
|
||||
src/utils.h
|
||||
BIN
brightness_control_two/obj/brightness.o
Normal file
BIN
brightness_control_two/obj/brightness.o
Normal file
Binary file not shown.
1
brightness_control_two/obj/display.d
Normal file
1
brightness_control_two/obj/display.d
Normal file
@@ -0,0 +1 @@
|
||||
obj/display.o: src/display.c src/display.h src/brightness.h src/utils.h
|
||||
BIN
brightness_control_two/obj/display.o
Normal file
BIN
brightness_control_two/obj/display.o
Normal file
Binary file not shown.
1
brightness_control_two/obj/main.d
Normal file
1
brightness_control_two/obj/main.d
Normal file
@@ -0,0 +1 @@
|
||||
obj/main.o: src/main.c src/brightness.h
|
||||
184
brightness_control_two/src/brightness.c
Normal file
184
brightness_control_two/src/brightness.c
Normal file
@@ -0,0 +1,184 @@
|
||||
#include "brightness.h"
|
||||
#include "display.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h> // Include string.h for strdup
|
||||
|
||||
static int min_value = 0;
|
||||
static float exponent = 1.0;
|
||||
static char *device = NULL;
|
||||
static char *class = NULL;
|
||||
static int quiet_mode = 0;
|
||||
static int pretend_mode = 0;
|
||||
|
||||
void set_brightness(int value, int raw) {
|
||||
if (pretend_mode) {
|
||||
if (!quiet_mode) {
|
||||
printf("Pretend mode: setting brightness to %d\n", value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *brightness_file = fopen(BRIGHTNESS_PATH, "w");
|
||||
if (brightness_file == NULL) {
|
||||
perror("Failed to open brightness file");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!raw) {
|
||||
FILE *max_brightness_file = fopen(MAX_BRIGHTNESS_PATH, "r");
|
||||
if (max_brightness_file == NULL) {
|
||||
perror("Failed to open max brightness file");
|
||||
fclose(brightness_file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int max_brightness;
|
||||
fscanf(max_brightness_file, "%d", &max_brightness);
|
||||
fclose(max_brightness_file);
|
||||
|
||||
value = (value * max_brightness) / 100;
|
||||
}
|
||||
|
||||
fprintf(brightness_file, "%d", value);
|
||||
fclose(brightness_file);
|
||||
display_brightness(value);
|
||||
}
|
||||
|
||||
void adjust_brightness(const char *direction) {
|
||||
if (pretend_mode) {
|
||||
if (!quiet_mode) {
|
||||
printf("Pretend mode: adjusting brightness %s\n", direction);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *brightness_file = fopen(BRIGHTNESS_PATH, "r+");
|
||||
if (brightness_file == NULL) {
|
||||
perror("Failed to open brightness file");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int brightness;
|
||||
fscanf(brightness_file, "%d", &brightness);
|
||||
|
||||
FILE *max_brightness_file = fopen(MAX_BRIGHTNESS_PATH, "r");
|
||||
if (max_brightness_file == NULL) {
|
||||
perror("Failed to open max brightness file");
|
||||
fclose(brightness_file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int max_brightness;
|
||||
fscanf(max_brightness_file, "%d", &max_brightness);
|
||||
fclose(max_brightness_file);
|
||||
|
||||
if (strcmp(direction, "up") == 0) {
|
||||
brightness += max_brightness / 10;
|
||||
} else if (strcmp(direction, "down") == 0) {
|
||||
brightness -= max_brightness / 10;
|
||||
}
|
||||
|
||||
if (brightness < 0) {
|
||||
brightness = 0;
|
||||
} else if (brightness > max_brightness) {
|
||||
brightness = max_brightness;
|
||||
}
|
||||
|
||||
rewind(brightness_file);
|
||||
fprintf(brightness_file, "%d", brightness);
|
||||
fclose(brightness_file);
|
||||
|
||||
display_brightness(brightness);
|
||||
}
|
||||
|
||||
void save_brightness(void) {
|
||||
if (pretend_mode) {
|
||||
if (!quiet_mode) {
|
||||
printf("Pretend mode: saving brightness\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *brightness_file = fopen(BRIGHTNESS_PATH, "r");
|
||||
if (brightness_file == NULL) {
|
||||
perror("Failed to open brightness file");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int brightness;
|
||||
fscanf(brightness_file, "%d", &brightness);
|
||||
fclose(brightness_file);
|
||||
|
||||
FILE *save_file = fopen("/tmp/brightnessctl_save", "w");
|
||||
if (save_file == NULL) {
|
||||
perror("Failed to open save file");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fprintf(save_file, "%d", brightness);
|
||||
fclose(save_file);
|
||||
|
||||
if (!quiet_mode) {
|
||||
printf("Brightness saved: %d\n", brightness);
|
||||
}
|
||||
}
|
||||
|
||||
void restore_brightness(void) {
|
||||
if (pretend_mode) {
|
||||
if (!quiet_mode) {
|
||||
printf("Pretend mode: restoring brightness\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *save_file = fopen("/tmp/brightnessctl_save", "r");
|
||||
if (save_file == NULL) {
|
||||
perror("Failed to open save file");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int brightness;
|
||||
fscanf(save_file, "%d", &brightness);
|
||||
fclose(save_file);
|
||||
|
||||
set_brightness(brightness, 1);
|
||||
|
||||
if (!quiet_mode) {
|
||||
printf("Brightness restored: %d\n", brightness);
|
||||
}
|
||||
}
|
||||
|
||||
void list_devices(void) {
|
||||
printf("Listing available devices...\n");
|
||||
}
|
||||
|
||||
void print_info(void) {
|
||||
printf("Printing device info...\n");
|
||||
}
|
||||
|
||||
void set_min_value(int value) {
|
||||
min_value = value;
|
||||
}
|
||||
|
||||
void set_exponent(float exp) {
|
||||
exponent = exp;
|
||||
}
|
||||
|
||||
void set_device(char *device_name) {
|
||||
device = strdup(device_name);
|
||||
}
|
||||
|
||||
void set_class(char *class_name) {
|
||||
class = strdup(class_name);
|
||||
}
|
||||
|
||||
void enable_quiet_mode(void) {
|
||||
quiet_mode = 1;
|
||||
}
|
||||
|
||||
void enable_pretend_mode(void) {
|
||||
pretend_mode = 1;
|
||||
}
|
||||
21
brightness_control_two/src/brightness.h
Normal file
21
brightness_control_two/src/brightness.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef BRIGHTNESS_H
|
||||
#define BRIGHTNESS_H
|
||||
|
||||
#define BRIGHTNESS_PATH "/sys/class/backlight/intel_backlight/brightness"
|
||||
#define MAX_BRIGHTNESS_PATH "/sys/class/backlight/intel_backlight/max_brightness"
|
||||
|
||||
void set_brightness(int value, int raw);
|
||||
void adjust_brightness(const char *direction);
|
||||
void display_brightness(int brightness);
|
||||
void save_brightness(void);
|
||||
void restore_brightness(void);
|
||||
void list_devices(void);
|
||||
void print_info(void);
|
||||
void set_min_value(int value);
|
||||
void set_exponent(float exponent);
|
||||
void set_device(char *device_name);
|
||||
void set_class(char *class_name);
|
||||
void enable_quiet_mode(void);
|
||||
void enable_pretend_mode(void);
|
||||
|
||||
#endif
|
||||
95
brightness_control_two/src/display.c
Normal file
95
brightness_control_two/src/display.c
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "display.h"
|
||||
#include "brightness.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
void draw_icon(Display *d, Window w, GC gc) {
|
||||
XDrawArc(d, w, gc, 70, 10, 60, 60, 0, 360 * 64);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
int x1 = 100 + 30 * cos(i * M_PI / 4);
|
||||
int y1 = 40 + 30 * sin(i * M_PI / 4);
|
||||
int x2 = 100 + 45 * cos(i * M_PI / 4);
|
||||
int y2 = 40 + 45 * sin(i * M_PI / 4);
|
||||
XDrawLine(d, w, gc, x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
|
||||
void display_brightness(int brightness) {
|
||||
Display *d;
|
||||
Window w;
|
||||
XEvent e;
|
||||
int screen;
|
||||
unsigned int display_width, display_height;
|
||||
int width = 200, height = 120;
|
||||
int sections = 10;
|
||||
int graph_height = 10;
|
||||
|
||||
if ((d = XOpenDisplay(NULL)) == NULL) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
screen = DefaultScreen(d);
|
||||
display_width = DisplayWidth(d, screen);
|
||||
display_height = DisplayHeight(d, screen);
|
||||
|
||||
w = XCreateSimpleWindow(d, RootWindow(d, screen), (display_width - width) / 2, (display_height - height) / 2, width, height, 1,
|
||||
BlackPixel(d, screen), WhitePixel(d, screen));
|
||||
XSetWindowBackground(d, w, 0xD3D3D3);
|
||||
XStoreName(d, w, "BrightnessControl");
|
||||
XClassHint *classHint = XAllocClassHint();
|
||||
classHint->res_name = "brightnesscontrol";
|
||||
classHint->res_class = "BrightnessControl";
|
||||
XSetClassHint(d, w, classHint);
|
||||
XFree(classHint);
|
||||
|
||||
XSelectInput(d, w, ExposureMask | KeyPressMask | StructureNotifyMask);
|
||||
XMapWindow(d, w);
|
||||
|
||||
GC gc = XCreateGC(d, w, 0, NULL);
|
||||
GC bg_gc = XCreateGC(d, w, 0, NULL);
|
||||
XSetForeground(d, gc, BlackPixel(d, screen));
|
||||
XSetBackground(d, bg_gc, WhitePixel(d, screen));
|
||||
XSetLineAttributes(d, gc, 3, LineSolid, CapButt, JoinMiter);
|
||||
|
||||
FILE *max_brightness_file = fopen(MAX_BRIGHTNESS_PATH, "r");
|
||||
int max_brightness;
|
||||
fscanf(max_brightness_file, "%d", &max_brightness);
|
||||
fclose(max_brightness_file);
|
||||
|
||||
while (1) {
|
||||
XNextEvent(d, &e);
|
||||
if (e.type == MapNotify) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
draw_icon(d, w, gc);
|
||||
|
||||
XSetForeground(d, bg_gc, 0xA9A9A9);
|
||||
XFillRectangle(d, w, bg_gc, 10, 100, 180, graph_height);
|
||||
|
||||
int filled_sections = (int)((brightness / (double)max_brightness) * sections);
|
||||
for (int i = 0; i < sections; ++i) {
|
||||
if (i < filled_sections) {
|
||||
XSetForeground(d, gc, 0xFFFFFF);
|
||||
} else {
|
||||
XSetForeground(d, gc, 0xA9A9A9);
|
||||
}
|
||||
XFillRectangle(d, w, gc, 10 + i * (180 / sections), 100, 180 / sections - 2, graph_height);
|
||||
}
|
||||
|
||||
XFlush(d);
|
||||
sleep(1);
|
||||
XDestroyWindow(d, w);
|
||||
XCloseDisplay(d);
|
||||
}
|
||||
9
brightness_control_two/src/display.h
Normal file
9
brightness_control_two/src/display.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef DISPLAY_H
|
||||
#define DISPLAY_H
|
||||
|
||||
#include <X11/Xlib.h> // Include X11 headers for Display, Window, and GC types
|
||||
|
||||
void draw_icon(Display *d, Window w, GC gc);
|
||||
void display_brightness(int brightness);
|
||||
|
||||
#endif
|
||||
113
brightness_control_two/src/main.c
Normal file
113
brightness_control_two/src/main.c
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "brightness.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void print_usage(const char *prog_name) {
|
||||
printf("Usage: %s [OPTION]...\n", prog_name);
|
||||
printf("Options:\n");
|
||||
printf(" -s, --save Save current brightness\n");
|
||||
printf(" -r, --restore Restore saved brightness\n");
|
||||
printf(" --set VALUE Set brightness to VALUE\n");
|
||||
printf(" -a, --adjust DIR Adjust brightness up or down\n");
|
||||
printf(" -h, --help Display this help and exit\n");
|
||||
printf(" -l, --list List devices with available brightness controls\n");
|
||||
printf(" -q, --quiet Suppress output\n");
|
||||
printf(" -p, --pretend Do not perform write operations\n");
|
||||
printf(" -n, --min-value MIN_VALUE Set minimum brightness value\n");
|
||||
printf(" -e, --exponent EXPONENT Change percentage curve to exponential\n");
|
||||
printf(" -c, --class CLASS Specify device class\n");
|
||||
printf(" -d, --device DEVICE Specify device name\n");
|
||||
printf(" -v, --version Print version and exit\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int opt;
|
||||
static struct option long_options[] = {
|
||||
{"save", no_argument, NULL, 's'},
|
||||
{"restore", no_argument, NULL, 'r'},
|
||||
{"set", required_argument, NULL, 0},
|
||||
{"adjust", required_argument, NULL, 'a'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"list", no_argument, NULL, 'l'},
|
||||
{"quiet", no_argument, NULL, 'q'},
|
||||
{"pretend", no_argument, NULL, 'p'},
|
||||
{"min-value", required_argument, NULL, 'n'},
|
||||
{"exponent", required_argument, NULL, 'e'},
|
||||
{"class", required_argument, NULL, 'c'},
|
||||
{"device", required_argument, NULL, 'd'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "sra:hlqpne:c:d:v", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
save_brightness();
|
||||
break;
|
||||
case 'r':
|
||||
restore_brightness();
|
||||
break;
|
||||
case 0: // --set
|
||||
if (optarg) {
|
||||
int value = atoi(optarg);
|
||||
set_brightness(value, 0);
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
if (optarg) {
|
||||
adjust_brightness(optarg);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
return EXIT_SUCCESS;
|
||||
case 'l':
|
||||
list_devices();
|
||||
break;
|
||||
case 'q':
|
||||
enable_quiet_mode();
|
||||
break;
|
||||
case 'p':
|
||||
enable_pretend_mode();
|
||||
break;
|
||||
case 'n':
|
||||
if (optarg) {
|
||||
int min_value = atoi(optarg);
|
||||
set_min_value(min_value);
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
if (optarg) {
|
||||
float exponent = atof(optarg);
|
||||
set_exponent(exponent);
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
if (optarg) {
|
||||
set_class(optarg);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
if (optarg) {
|
||||
set_device(optarg);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
printf("Version 1.0\n");
|
||||
return EXIT_SUCCESS;
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
print_usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
29
brightness_control_two/src/utils.c
Normal file
29
brightness_control_two/src/utils.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
char *read_file_to_string(const char *filepath) {
|
||||
FILE *file = fopen(filepath, "r");
|
||||
if (!file) {
|
||||
perror("Failed to open file");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
long length = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
char *content = malloc(length + 1);
|
||||
if (!content) {
|
||||
perror("Failed to allocate memory");
|
||||
fclose(file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fread(content, 1, length, file);
|
||||
content[length] = '\0';
|
||||
|
||||
fclose(file);
|
||||
return content;
|
||||
}
|
||||
6
brightness_control_two/src/utils.h
Normal file
6
brightness_control_two/src/utils.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
char *read_file_to_string(const char *filepath);
|
||||
|
||||
#endif
|
||||
20
brightness_menu/Makefile
Normal file
20
brightness_menu/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -Iinclude `pkg-config --cflags gtk+-3.0`
|
||||
LDFLAGS = -lncurses -lX11 -lXrandr `pkg-config --libs gtk+-3.0`
|
||||
|
||||
SRC = $(wildcard src/*.c)
|
||||
OBJ = $(patsubst src/%.c, build/%.o, $(SRC))
|
||||
TARGET = build/screen_control
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJ)
|
||||
$(CC) -o $(TARGET) $(OBJ) $(LDFLAGS)
|
||||
|
||||
build/%.o: src/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f build/*.o $(TARGET)
|
||||
|
||||
.PHONY: all clean
|
||||
0
brightness_menu/README.md
Normal file
0
brightness_menu/README.md
Normal file
BIN
brightness_menu/build/brightness.o
Normal file
BIN
brightness_menu/build/brightness.o
Normal file
Binary file not shown.
BIN
brightness_menu/build/color_temperature.o
Normal file
BIN
brightness_menu/build/color_temperature.o
Normal file
Binary file not shown.
BIN
brightness_menu/build/display.o
Normal file
BIN
brightness_menu/build/display.o
Normal file
Binary file not shown.
BIN
brightness_menu/build/main.o
Normal file
BIN
brightness_menu/build/main.o
Normal file
Binary file not shown.
BIN
brightness_menu/build/refresh_rate.o
Normal file
BIN
brightness_menu/build/refresh_rate.o
Normal file
Binary file not shown.
BIN
brightness_menu/build/resolution.o
Normal file
BIN
brightness_menu/build/resolution.o
Normal file
Binary file not shown.
BIN
brightness_menu/build/screen_control
Executable file
BIN
brightness_menu/build/screen_control
Executable file
Binary file not shown.
6
brightness_menu/include/brightness.h
Normal file
6
brightness_menu/include/brightness.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef BRIGHTNESS_H
|
||||
#define BRIGHTNESS_H
|
||||
|
||||
void adjust_brightness();
|
||||
|
||||
#endif // BRIGHTNESS_H
|
||||
6
brightness_menu/include/color_temperature.h
Normal file
6
brightness_menu/include/color_temperature.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef COLOR_TEMPERATURE_H
|
||||
#define COLOR_TEMPERATURE_H
|
||||
|
||||
void adjust_color_temperature();
|
||||
|
||||
#endif // COLOR_TEMPERATURE_H
|
||||
7
brightness_menu/include/display.h
Normal file
7
brightness_menu/include/display.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef DISPLAY_H
|
||||
#define DISPLAY_H
|
||||
|
||||
void display_main_screen();
|
||||
void handle_option(int option);
|
||||
|
||||
#endif // DISPLAY_H
|
||||
6
brightness_menu/include/refresh_rate.h
Normal file
6
brightness_menu/include/refresh_rate.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef REFRESH_RATE_H
|
||||
#define REFRESH_RATE_H
|
||||
|
||||
void adjust_refresh_rate();
|
||||
|
||||
#endif // REFRESH_RATE_H
|
||||
6
brightness_menu/include/resolution.h
Normal file
6
brightness_menu/include/resolution.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef RESOLUTION_H
|
||||
#define RESOLUTION_H
|
||||
|
||||
void adjust_resolution();
|
||||
|
||||
#endif // RESOLUTION_H
|
||||
53
brightness_menu/src/brightness.c
Normal file
53
brightness_menu/src/brightness.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#include <ncurses.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "brightness.h"
|
||||
|
||||
void adjust_brightness() {
|
||||
FILE *brightness_file;
|
||||
int brightness;
|
||||
char path[] = "/sys/class/backlight/intel_backlight/brightness";
|
||||
char max_brightness_path[] = "/sys/class/backlight/intel_backlight/max_brightness";
|
||||
int max_brightness;
|
||||
|
||||
brightness_file = fopen(path, "r+");
|
||||
if (brightness_file == NULL) {
|
||||
mvprintw(4, 0, "Error: %s", strerror(errno));
|
||||
refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *max_brightness_file = fopen(max_brightness_path, "r");
|
||||
if (max_brightness_file == NULL) {
|
||||
mvprintw(4, 0, "Error: %s", strerror(errno));
|
||||
fclose(brightness_file);
|
||||
refresh();
|
||||
return;
|
||||
}
|
||||
fscanf(max_brightness_file, "%d", &max_brightness);
|
||||
fclose(max_brightness_file);
|
||||
|
||||
fscanf(brightness_file, "%d", &brightness);
|
||||
mvprintw(4, 0, "Current Brightness: %d", brightness);
|
||||
mvprintw(5, 0, "Max Brightness: %d", max_brightness);
|
||||
mvprintw(6, 0, "Enter new brightness (0-%d): ", max_brightness);
|
||||
|
||||
refresh();
|
||||
echo();
|
||||
scanw("%d", &brightness);
|
||||
noecho();
|
||||
|
||||
if (brightness < 0 || brightness > max_brightness) {
|
||||
mvprintw(7, 0, "Invalid brightness value");
|
||||
} else {
|
||||
rewind(brightness_file);
|
||||
fprintf(brightness_file, "%d", brightness);
|
||||
fflush(brightness_file);
|
||||
mvprintw(7, 0, "Brightness set to %d", brightness);
|
||||
}
|
||||
|
||||
fclose(brightness_file);
|
||||
refresh();
|
||||
getch();
|
||||
}
|
||||
BIN
brightness_menu/src/brightness.o
Normal file
BIN
brightness_menu/src/brightness.o
Normal file
Binary file not shown.
26
brightness_menu/src/color_temperature.c
Normal file
26
brightness_menu/src/color_temperature.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include <ncurses.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "color_temperature.h"
|
||||
|
||||
void adjust_color_temperature() {
|
||||
mvprintw(4, 0, "Enter the desired color temperature (in Kelvin, e.g., 6500): ");
|
||||
refresh();
|
||||
|
||||
echo();
|
||||
int color_temp;
|
||||
scanw("%d", &color_temp);
|
||||
noecho();
|
||||
|
||||
char command[128];
|
||||
snprintf(command, sizeof(command), "xcalib -co %d", color_temp);
|
||||
|
||||
int result = system(command);
|
||||
if (result == -1) {
|
||||
mvprintw(6, 0, "Failed to set color temperature");
|
||||
} else {
|
||||
mvprintw(6, 0, "Color temperature set to %dK", color_temp);
|
||||
}
|
||||
refresh();
|
||||
getch();
|
||||
}
|
||||
49
brightness_menu/src/display.c
Normal file
49
brightness_menu/src/display.c
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <ncurses.h>
|
||||
#include <stdlib.h>
|
||||
#include "display.h"
|
||||
#include "brightness.h"
|
||||
#include "resolution.h"
|
||||
#include "refresh_rate.h"
|
||||
#include "color_temperature.h"
|
||||
|
||||
void display_main_screen() {
|
||||
int option;
|
||||
mvprintw(0, 0, "Select an option:");
|
||||
mvprintw(1, 0, "1. Screen Brightness");
|
||||
mvprintw(2, 0, "2. Screen Resolution");
|
||||
mvprintw(3, 0, "3. Refresh Rate");
|
||||
mvprintw(4, 0, "4. Color Temperature");
|
||||
mvprintw(5, 0, "5. Exit");
|
||||
|
||||
refresh();
|
||||
option = getch() - '0';
|
||||
|
||||
handle_option(option);
|
||||
}
|
||||
|
||||
void handle_option(int option) {
|
||||
switch(option) {
|
||||
case 1:
|
||||
adjust_brightness();
|
||||
break;
|
||||
case 2:
|
||||
adjust_resolution();
|
||||
break;
|
||||
case 3:
|
||||
adjust_refresh_rate();
|
||||
break;
|
||||
case 4:
|
||||
adjust_color_temperature();
|
||||
break;
|
||||
case 5:
|
||||
endwin();
|
||||
exit(0);
|
||||
default:
|
||||
mvprintw(6, 0, "Invalid option");
|
||||
refresh();
|
||||
getch();
|
||||
break;
|
||||
}
|
||||
display_main_screen();
|
||||
}
|
||||
|
||||
BIN
brightness_menu/src/display.o
Normal file
BIN
brightness_menu/src/display.o
Normal file
Binary file not shown.
60
brightness_menu/src/main.c
Normal file
60
brightness_menu/src/main.c
Normal file
@@ -0,0 +1,60 @@
|
||||
#include <ncurses.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include "display.h"
|
||||
|
||||
void run_cli();
|
||||
void run_gui();
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int opt;
|
||||
int gui_mode = 0;
|
||||
|
||||
// Parse command-line arguments
|
||||
while ((opt = getopt(argc, argv, "g")) != -1) {
|
||||
switch (opt) {
|
||||
case 'g':
|
||||
gui_mode = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Usage: %s [-g]\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (gui_mode) {
|
||||
run_gui(argc, argv);
|
||||
} else {
|
||||
run_cli();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void run_cli() {
|
||||
initscr();
|
||||
cbreak();
|
||||
noecho();
|
||||
keypad(stdscr, TRUE);
|
||||
|
||||
display_main_screen();
|
||||
|
||||
endwin();
|
||||
}
|
||||
|
||||
void run_gui(int argc, char *argv[]) {
|
||||
GtkWidget *window;
|
||||
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
||||
gtk_window_set_title(GTK_WINDOW(window), "Screen Control GUI");
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
|
||||
|
||||
gtk_widget_show_all(window);
|
||||
|
||||
gtk_main();
|
||||
}
|
||||
BIN
brightness_menu/src/main.o
Normal file
BIN
brightness_menu/src/main.o
Normal file
Binary file not shown.
76
brightness_menu/src/refresh_rate.c
Normal file
76
brightness_menu/src/refresh_rate.c
Normal file
@@ -0,0 +1,76 @@
|
||||
#include <ncurses.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "refresh_rate.h"
|
||||
|
||||
void list_refresh_rates(XRRScreenResources *res, XRRCrtcInfo *crtc_info) {
|
||||
mvprintw(5, 0, "Available Refresh Rates:");
|
||||
int rate_count = 0;
|
||||
for (int i = 0; i < res->nmode; i++) {
|
||||
XRRModeInfo mode = res->modes[i];
|
||||
for (int j = 0; j < crtc_info->noutput; j++) {
|
||||
if (crtc_info->outputs[j] == mode.id) {
|
||||
double refresh_rate = (double)mode.dotClock / (mode.hTotal * mode.vTotal);
|
||||
mvprintw(6 + rate_count, 0, "%d: %.2f Hz", rate_count, refresh_rate);
|
||||
rate_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
|
||||
void set_refresh_rate() {
|
||||
// Placeholder for setting the refresh rate based on selected index
|
||||
mvprintw(7, 0, "Setting refresh rate feature coming soon...");
|
||||
refresh();
|
||||
}
|
||||
|
||||
void adjust_refresh_rate() {
|
||||
Display *dpy = XOpenDisplay(NULL);
|
||||
if (dpy == NULL) {
|
||||
mvprintw(4, 0, "Unable to open X display");
|
||||
refresh();
|
||||
getch();
|
||||
return;
|
||||
}
|
||||
|
||||
Window root = DefaultRootWindow(dpy);
|
||||
XRRScreenResources *res = XRRGetScreenResources(dpy, root);
|
||||
if (res == NULL) {
|
||||
mvprintw(4, 0, "Unable to get screen resources");
|
||||
XCloseDisplay(dpy);
|
||||
refresh();
|
||||
getch();
|
||||
return;
|
||||
}
|
||||
|
||||
XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(dpy, res, res->crtcs[0]);
|
||||
if (crtc_info == NULL) {
|
||||
mvprintw(4, 0, "Unable to get CRTC info");
|
||||
XRRFreeScreenResources(res);
|
||||
XCloseDisplay(dpy);
|
||||
refresh();
|
||||
getch();
|
||||
return;
|
||||
}
|
||||
|
||||
list_refresh_rates(res, crtc_info);
|
||||
|
||||
mvprintw(6 + res->nmode, 0, "Enter the index of the desired refresh rate: ");
|
||||
refresh();
|
||||
|
||||
echo();
|
||||
int rate_index;
|
||||
scanw("%d", &rate_index);
|
||||
noecho();
|
||||
|
||||
set_refresh_rate();
|
||||
|
||||
XRRFreeCrtcInfo(crtc_info);
|
||||
XRRFreeScreenResources(res);
|
||||
XCloseDisplay(dpy);
|
||||
|
||||
getch();
|
||||
}
|
||||
66
brightness_menu/src/resolution.c
Normal file
66
brightness_menu/src/resolution.c
Normal file
@@ -0,0 +1,66 @@
|
||||
#include <ncurses.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "resolution.h"
|
||||
|
||||
void list_resolutions(XRRScreenResources *res) {
|
||||
mvprintw(5, 0, "Available Resolutions:");
|
||||
for (int i = 0; i < res->nmode; i++) {
|
||||
XRRModeInfo mode = res->modes[i];
|
||||
mvprintw(6 + i, 0, "%d: %dx%d", i, mode.width, mode.height);
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
|
||||
void set_resolution(Display *dpy, Window root, XRRScreenResources *res, int mode_index) {
|
||||
if (mode_index < 0 || mode_index >= res->nmode) {
|
||||
mvprintw(7 + res->nmode, 0, "Invalid mode index");
|
||||
return;
|
||||
}
|
||||
|
||||
XRRModeInfo mode = res->modes[mode_index];
|
||||
XRRSetScreenSize(dpy, root, mode.width, mode.height, mode.width, mode.height);
|
||||
XRRSetCrtcConfig(dpy, res, res->crtcs[0], CurrentTime, 0, 0, mode.id, RR_Rotate_0, NULL, 0);
|
||||
|
||||
mvprintw(7 + res->nmode, 0, "Resolution set to %dx%d", mode.width, mode.height);
|
||||
refresh();
|
||||
}
|
||||
|
||||
void adjust_resolution() {
|
||||
Display *dpy = XOpenDisplay(NULL);
|
||||
if (dpy == NULL) {
|
||||
mvprintw(4, 0, "Unable to open X display");
|
||||
refresh();
|
||||
getch();
|
||||
return;
|
||||
}
|
||||
|
||||
Window root = DefaultRootWindow(dpy);
|
||||
XRRScreenResources *res = XRRGetScreenResources(dpy, root);
|
||||
if (res == NULL) {
|
||||
mvprintw(4, 0, "Unable to get screen resources");
|
||||
XCloseDisplay(dpy);
|
||||
refresh();
|
||||
getch();
|
||||
return;
|
||||
}
|
||||
|
||||
list_resolutions(res);
|
||||
|
||||
mvprintw(6 + res->nmode, 0, "Enter the index of the desired resolution: ");
|
||||
refresh();
|
||||
|
||||
echo();
|
||||
int mode_index;
|
||||
scanw("%d", &mode_index);
|
||||
noecho();
|
||||
|
||||
set_resolution(dpy, root, res, mode_index);
|
||||
|
||||
XRRFreeScreenResources(res);
|
||||
XCloseDisplay(dpy);
|
||||
|
||||
getch();
|
||||
}
|
||||
1
mpvd/build/Install
Normal file
1
mpvd/build/Install
Normal file
@@ -0,0 +1 @@
|
||||
libasound2-dev
|
||||
19
mpvd/build/Makefile
Normal file
19
mpvd/build/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
CC = gcc
|
||||
CFLAGS = -I../include -Wall -g
|
||||
LDFLAGS = -lasound -lncurses # Added -lncurses for ncurses functions
|
||||
OBJDIR = ../obj
|
||||
SRCDIR = ../src
|
||||
INCLUDEDIR = ../include
|
||||
|
||||
OBJS = $(OBJDIR)/main.o $(OBJDIR)/audio.o $(OBJDIR)/ui.o $(OBJDIR)/dir.o
|
||||
|
||||
all: mpvd
|
||||
|
||||
mpvd: $(OBJS)
|
||||
$(CC) $(CFLAGS) -o mpvd $(OBJS) $(LDFLAGS)
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJDIR)/*.o mpvd
|
||||
BIN
mpvd/build/mpvd
Executable file
BIN
mpvd/build/mpvd
Executable file
Binary file not shown.
6
mpvd/include/audio.h
Normal file
6
mpvd/include/audio.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
void play_audio(const char *file_path);
|
||||
|
||||
#endif
|
||||
10
mpvd/include/dir.h
Normal file
10
mpvd/include/dir.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef DIR_H
|
||||
#define DIR_H
|
||||
|
||||
#define MAX_PATH_LEN 512 // Declare MAX_PATH_LEN for use across files
|
||||
|
||||
char* get_music_directory();
|
||||
char** load_songs(int *count, const char *music_dir);
|
||||
void navigate_directory(const char *dir, char **songs, int *song_count); // Declare navigate_directory
|
||||
|
||||
#endif
|
||||
14
mpvd/include/ui.h
Normal file
14
mpvd/include/ui.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef UI_H
|
||||
#define UI_H
|
||||
|
||||
#include <ncurses.h>
|
||||
|
||||
void init_ncurses();
|
||||
void end_ncurses();
|
||||
void display_songs(WINDOW *win, char **songs, int song_count, int selected);
|
||||
void display_controls(WINDOW *control_win, int is_playing);
|
||||
|
||||
// Update handle_input to accept current_directory
|
||||
void handle_input(int ch, char **songs, int *selected_song, int *song_count, WINDOW *song_win, WINDOW *control_win, int *is_playing, char *current_directory);
|
||||
|
||||
#endif
|
||||
BIN
mpvd/obj/audio.o
Normal file
BIN
mpvd/obj/audio.o
Normal file
Binary file not shown.
BIN
mpvd/obj/dir.o
Normal file
BIN
mpvd/obj/dir.o
Normal file
Binary file not shown.
BIN
mpvd/obj/main.o
Normal file
BIN
mpvd/obj/main.o
Normal file
Binary file not shown.
BIN
mpvd/obj/ui.o
Normal file
BIN
mpvd/obj/ui.o
Normal file
Binary file not shown.
41
mpvd/src/audio.c
Normal file
41
mpvd/src/audio.c
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "audio.h"
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
void play_audio(const char *file_path) {
|
||||
snd_pcm_t *handle;
|
||||
snd_pcm_hw_params_t *params;
|
||||
unsigned int rate = 44100;
|
||||
int dir;
|
||||
snd_pcm_uframes_t frames;
|
||||
int rc;
|
||||
|
||||
// Open PCM device for playback
|
||||
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Unable to open PCM device: %s\n", snd_strerror(rc));
|
||||
return;
|
||||
}
|
||||
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
snd_pcm_hw_params_any(handle, params);
|
||||
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
|
||||
snd_pcm_hw_params_set_channels(handle, params, 2);
|
||||
snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir);
|
||||
snd_pcm_hw_params(handle, params);
|
||||
|
||||
// Simulate audio playback (replace this with actual file reading and playback)
|
||||
unsigned char *buffer = malloc(128 * 4);
|
||||
memset(buffer, 0, 128 * 4);
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
rc = snd_pcm_writei(handle, buffer, 128);
|
||||
if (rc == -EPIPE) {
|
||||
snd_pcm_prepare(handle);
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
snd_pcm_drain(handle);
|
||||
snd_pcm_close(handle);
|
||||
}
|
||||
49
mpvd/src/dir.c
Normal file
49
mpvd/src/dir.c
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <dirent.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "dir.h"
|
||||
|
||||
char* get_music_directory() {
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
char *music_dir = malloc(strlen(homedir) + strlen("/Music/mpvd") + 1);
|
||||
strcpy(music_dir, homedir);
|
||||
strcat(music_dir, "/Music/mpvd");
|
||||
return music_dir;
|
||||
}
|
||||
|
||||
char** load_songs(int *count, const char *music_dir) {
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
d = opendir(music_dir);
|
||||
if (!d) {
|
||||
perror("Failed to open music directory");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char **songs = malloc(sizeof(char*) * 100);
|
||||
int index = 0;
|
||||
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
if (dir->d_type == DT_REG) {
|
||||
songs[index] = strdup(dir->d_name);
|
||||
index++;
|
||||
} else if (dir->d_type == DT_DIR && strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0) {
|
||||
char dir_name[512];
|
||||
snprintf(dir_name, sizeof(dir_name), "%s/", dir->d_name);
|
||||
songs[index] = strdup(dir_name); // Append '/' to indicate a directory
|
||||
index++;
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
*count = index;
|
||||
return songs;
|
||||
}
|
||||
|
||||
void navigate_directory(const char *dir, char **songs, int *song_count) {
|
||||
free(songs); // Free old song list
|
||||
songs = load_songs(song_count, dir); // Load new song list
|
||||
}
|
||||
55
mpvd/src/main.c
Normal file
55
mpvd/src/main.c
Normal file
@@ -0,0 +1,55 @@
|
||||
// src/main.c
|
||||
|
||||
#include <ncurses.h>
|
||||
#include "audio.h"
|
||||
#include "ui.h"
|
||||
#include "dir.h"
|
||||
|
||||
int main() {
|
||||
// Initialize ncurses
|
||||
initscr();
|
||||
noecho();
|
||||
cbreak();
|
||||
curs_set(FALSE);
|
||||
keypad(stdscr, TRUE);
|
||||
|
||||
// Initialize UI and audio
|
||||
init_ui();
|
||||
init_audio();
|
||||
|
||||
// Load the directory contents
|
||||
load_directory("/Music/mpvd");
|
||||
|
||||
int ch;
|
||||
while ((ch = getch()) != 'q') {
|
||||
// Handle navigation and controls
|
||||
switch (ch) {
|
||||
case KEY_UP:
|
||||
navigate_up();
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
navigate_down();
|
||||
break;
|
||||
case '\n': // Enter key
|
||||
select_item();
|
||||
break;
|
||||
case ' ': // Spacebar
|
||||
toggle_playback();
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
decrease_volume();
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
increase_volume();
|
||||
break;
|
||||
}
|
||||
update_ui();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
cleanup_ui();
|
||||
cleanup_audio();
|
||||
endwin();
|
||||
|
||||
return 0;
|
||||
}
|
||||
282
mpvd/src/mpvd.c
Normal file
282
mpvd/src/mpvd.c
Normal file
@@ -0,0 +1,282 @@
|
||||
#include <ncurses.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <pwd.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#define MAX_SONGS 100
|
||||
#define MAX_PATH_LEN 512
|
||||
|
||||
// Function declarations
|
||||
void init_ncurses();
|
||||
void end_ncurses();
|
||||
void display_songs(WINDOW *win, char **songs, int song_count, int selected);
|
||||
char** load_songs(int *count, const char *music_dir);
|
||||
char* get_music_directory();
|
||||
void display_controls(WINDOW *control_win, int is_playing);
|
||||
void play_audio(const char *file_path);
|
||||
void stop_audio();
|
||||
void add_to_queue(const char *song);
|
||||
void play_next_in_queue();
|
||||
void navigate_directory(const char *dir, char **songs, int *song_count);
|
||||
|
||||
// Global variables
|
||||
char *queue[MAX_SONGS];
|
||||
int queue_size = 0;
|
||||
int queue_position = 0;
|
||||
int is_playing = 0;
|
||||
char current_directory[MAX_PATH_LEN];
|
||||
|
||||
int main() {
|
||||
int song_count;
|
||||
char **songs;
|
||||
int selected_song = 0;
|
||||
int ch;
|
||||
|
||||
// Initialize music directory
|
||||
strcpy(current_directory, get_music_directory());
|
||||
songs = load_songs(&song_count, current_directory);
|
||||
|
||||
// Initialize ncurses
|
||||
init_ncurses();
|
||||
|
||||
// Set up windows
|
||||
int half_height = LINES / 2;
|
||||
int width = COLS;
|
||||
|
||||
WINDOW *song_win = newwin(half_height, width, 0, 0);
|
||||
WINDOW *control_win = newwin(half_height, width, half_height, 0);
|
||||
|
||||
// Display initial songs and controls
|
||||
display_songs(song_win, songs, song_count, selected_song);
|
||||
display_controls(control_win, is_playing);
|
||||
|
||||
// Main loop to handle input
|
||||
while ((ch = getch()) != 'q') {
|
||||
switch (ch) {
|
||||
case KEY_UP:
|
||||
case 'k':
|
||||
if (selected_song > 0) selected_song--;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
case 'j':
|
||||
if (selected_song < song_count - 1) selected_song++;
|
||||
break;
|
||||
case '\n':
|
||||
if (songs[selected_song][strlen(songs[selected_song]) - 1] == '/') {
|
||||
// Enter directory
|
||||
char new_dir[MAX_PATH_LEN];
|
||||
snprintf(new_dir, MAX_PATH_LEN, "%s/%s", current_directory, songs[selected_song]);
|
||||
navigate_directory(new_dir, songs, &song_count);
|
||||
selected_song = 0; // Reset selection
|
||||
} else {
|
||||
if (is_playing) {
|
||||
// Add to queue if something is playing
|
||||
add_to_queue(songs[selected_song]);
|
||||
} else {
|
||||
// Play selected song immediately
|
||||
char song_path[MAX_PATH_LEN];
|
||||
snprintf(song_path, MAX_PATH_LEN, "%s/%s", current_directory, songs[selected_song]);
|
||||
play_audio(song_path);
|
||||
is_playing = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ' ': // Pause/play functionality
|
||||
if (is_playing) {
|
||||
stop_audio();
|
||||
is_playing = 0;
|
||||
} else {
|
||||
play_next_in_queue();
|
||||
is_playing = 1;
|
||||
}
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
case 'l': // Fast-forward (skipping in the queue)
|
||||
play_next_in_queue();
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
case 'h': // Go back in the queue (not implemented yet)
|
||||
break;
|
||||
case KEY_NPAGE:
|
||||
case 'L': // Skip track
|
||||
play_next_in_queue();
|
||||
break;
|
||||
case KEY_PPAGE:
|
||||
case 'H': // Go back track (not implemented yet)
|
||||
break;
|
||||
}
|
||||
display_songs(song_win, songs, song_count, selected_song); // Update song selection
|
||||
display_controls(control_win, is_playing); // Update controls display
|
||||
}
|
||||
|
||||
// Clean up ncurses
|
||||
end_ncurses();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void init_ncurses() {
|
||||
initscr();
|
||||
noecho();
|
||||
cbreak();
|
||||
keypad(stdscr, TRUE);
|
||||
}
|
||||
|
||||
void end_ncurses() {
|
||||
endwin();
|
||||
}
|
||||
|
||||
char* get_music_directory() {
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
char *music_dir = malloc(strlen(homedir) + strlen("/Music/mpvd") + 1);
|
||||
strcpy(music_dir, homedir);
|
||||
strcat(music_dir, "/Music/mpvd");
|
||||
return music_dir;
|
||||
}
|
||||
|
||||
char** load_songs(int *count, const char *music_dir) {
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
d = opendir(music_dir);
|
||||
if (!d) {
|
||||
perror("Failed to open music directory");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char **songs = malloc(sizeof(char*) * MAX_SONGS);
|
||||
int index = 0;
|
||||
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
if (dir->d_type == DT_REG) {
|
||||
songs[index] = strdup(dir->d_name);
|
||||
index++;
|
||||
} else if (dir->d_type == DT_DIR) {
|
||||
if (strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0) {
|
||||
char dir_name[MAX_PATH_LEN];
|
||||
snprintf(dir_name, MAX_PATH_LEN, "%s/", dir->d_name);
|
||||
songs[index] = strdup(dir_name);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
*count = index;
|
||||
return songs;
|
||||
}
|
||||
|
||||
void display_songs(WINDOW *win, char **songs, int song_count, int selected) {
|
||||
werase(win);
|
||||
box(win, 0, 0);
|
||||
mvwprintw(win, 0, 1, "Select a song or directory to play/open (Up/Down to navigate, Enter to select)");
|
||||
|
||||
for (int i = 0; i < song_count; i++) {
|
||||
if (i == selected)
|
||||
wattron(win, A_REVERSE);
|
||||
mvwprintw(win, i + 1, 1, "%s", songs[i]);
|
||||
wattroff(win, A_REVERSE);
|
||||
}
|
||||
wrefresh(win);
|
||||
}
|
||||
|
||||
void display_controls(WINDOW *control_win, int is_playing) {
|
||||
werase(control_win);
|
||||
box(control_win, 0, 0);
|
||||
|
||||
// Display Unicode controls for play/pause, forward, and back
|
||||
if (is_playing) {
|
||||
mvwprintw(control_win, 1, 1, "⏸ Pausing");
|
||||
} else {
|
||||
mvwprintw(control_win, 1, 1, "⏵ Playing");
|
||||
}
|
||||
mvwprintw(control_win, 1, 20, "⏪ Previous");
|
||||
mvwprintw(control_win, 1, 40, "⏩ Next");
|
||||
wrefresh(control_win);
|
||||
}
|
||||
|
||||
void navigate_directory(const char *dir, char **songs, int *song_count) {
|
||||
strcpy(current_directory, dir);
|
||||
songs = load_songs(song_count, current_directory);
|
||||
}
|
||||
|
||||
void add_to_queue(const char *song) {
|
||||
if (queue_size < MAX_SONGS) {
|
||||
queue[queue_size] = strdup(song);
|
||||
queue_size++;
|
||||
}
|
||||
}
|
||||
|
||||
void play_next_in_queue() {
|
||||
if (queue_position < queue_size) {
|
||||
char song_path[MAX_PATH_LEN];
|
||||
snprintf(song_path, MAX_PATH_LEN, "%s/%s", current_directory, queue[queue_position]);
|
||||
play_audio(song_path);
|
||||
queue_position++;
|
||||
} else {
|
||||
// Queue is empty
|
||||
stop_audio();
|
||||
}
|
||||
}
|
||||
|
||||
void play_audio(const char *file_path) {
|
||||
snd_pcm_t *handle;
|
||||
snd_pcm_hw_params_t *params;
|
||||
unsigned int rate = 44100; // Default sample rate
|
||||
int dir;
|
||||
snd_pcm_uframes_t frames;
|
||||
int rc;
|
||||
|
||||
// Open PCM device for playback
|
||||
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Unable to open PCM device: %s\n", snd_strerror(rc));
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate a hardware parameters object
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
|
||||
// Fill it in with default values
|
||||
snd_pcm_hw_params_any(handle, params);
|
||||
|
||||
// Set the desired hardware parameters
|
||||
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
|
||||
snd_pcm_hw_params_set_channels(handle, params, 2);
|
||||
snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir);
|
||||
|
||||
// Write the parameters to the driver
|
||||
rc = snd_pcm_hw_params(handle, params);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Unable to set HW parameters: %s\n", snd_strerror(rc));
|
||||
return;
|
||||
}
|
||||
|
||||
// Playback the audio (This is a simplified example, you would actually need to read the file)
|
||||
unsigned char *buffer = malloc(128 * 4);
|
||||
memset(buffer, 0, 128 * 4);
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
rc = snd_pcm_writei(handle, buffer, 128);
|
||||
if (rc == -EPIPE) {
|
||||
// EPIPE means underrun
|
||||
fprintf(stderr, "Underrun occurred\n");
|
||||
snd_pcm_prepare(handle);
|
||||
} else if (rc < 0) {
|
||||
fprintf(stderr, "Error writing to PCM device: %s\n", snd_strerror(rc));
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
free(buffer);
|
||||
snd_pcm_drain(handle);
|
||||
snd_pcm_close(handle);
|
||||
}
|
||||
|
||||
void stop_audio() {
|
||||
// Placeholder for stopping audio playback
|
||||
mvprintw(LINES - 1, 0, "Audio stopped.");
|
||||
refresh();
|
||||
}
|
||||
87
mpvd/src/ui.c
Normal file
87
mpvd/src/ui.c
Normal file
@@ -0,0 +1,87 @@
|
||||
#include <ncurses.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ui.h"
|
||||
#include "dir.h"
|
||||
#include "audio.h"
|
||||
|
||||
void init_ncurses() {
|
||||
initscr();
|
||||
noecho();
|
||||
cbreak();
|
||||
keypad(stdscr, TRUE);
|
||||
}
|
||||
|
||||
void end_ncurses() {
|
||||
endwin();
|
||||
}
|
||||
|
||||
void display_songs(WINDOW *win, char **songs, int song_count, int selected) {
|
||||
werase(win);
|
||||
box(win, 0, 0);
|
||||
mvwprintw(win, 0, 1, "Select a song or directory to play/open");
|
||||
|
||||
for (int i = 0; i < song_count; i++) {
|
||||
if (i == selected)
|
||||
wattron(win, A_REVERSE);
|
||||
mvwprintw(win, i + 1, 1, "%s", songs[i]);
|
||||
wattroff(win, A_REVERSE);
|
||||
}
|
||||
wrefresh(win);
|
||||
}
|
||||
|
||||
void display_controls(WINDOW *control_win, int is_playing, const char *current_song, int volume) {
|
||||
werase(control_win);
|
||||
box(control_win, 0, 0);
|
||||
|
||||
// Display current song and volume
|
||||
mvwprintw(control_win, 1, 1, "Now Playing: %s", current_song);
|
||||
mvwprintw(control_win, 2, 1, "Volume: %d%%", volume);
|
||||
|
||||
// Display if song is playing or paused
|
||||
if (is_playing) {
|
||||
mvwprintw(control_win, 1, COLS - 10, "⏸ Paused");
|
||||
} else {
|
||||
mvwprintw(control_win, 1, COLS - 10, "⏵ Playing");
|
||||
}
|
||||
wrefresh(control_win);
|
||||
}
|
||||
|
||||
void handle_input(int ch, char **songs, int *selected_song, int *song_count, WINDOW *song_win, WINDOW *control_win, int *is_playing, char *current_directory, char *current_song, int *volume) {
|
||||
switch (ch) {
|
||||
case KEY_UP:
|
||||
case 'k':
|
||||
if (*selected_song > 0) (*selected_song)--;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
case 'j':
|
||||
if (*selected_song < *song_count - 1) (*selected_song)++;
|
||||
break;
|
||||
case '\n': // Handle directory or song selection
|
||||
if (songs[*selected_song][strlen(songs[*selected_song]) - 1] == '/') {
|
||||
char new_dir[MAX_PATH_LEN];
|
||||
snprintf(new_dir, MAX_PATH_LEN, "%s/%s", current_directory, songs[*selected_song]);
|
||||
navigate_directory(new_dir, songs, song_count);
|
||||
strcpy(current_directory, new_dir); // Update current directory
|
||||
*selected_song = 0; // Reset selection after entering directory
|
||||
} else {
|
||||
char song_path[MAX_PATH_LEN];
|
||||
snprintf(song_path, MAX_PATH_LEN, "%s/%s", current_directory, songs[*selected_song]);
|
||||
play_audio(song_path);
|
||||
strcpy(current_song, songs[*selected_song]); // Update current song
|
||||
*is_playing = 1;
|
||||
}
|
||||
break;
|
||||
case ' ': // Pause/Play toggle
|
||||
*is_playing = !(*is_playing);
|
||||
break;
|
||||
case KEY_RIGHT: // Increase volume
|
||||
if (*volume < 100) (*volume)++;
|
||||
break;
|
||||
case KEY_LEFT: // Decrease volume
|
||||
if (*volume > 0) (*volume)--;
|
||||
break;
|
||||
}
|
||||
display_songs(song_win, songs, *song_count, *selected_song);
|
||||
display_controls(control_win, *is_playing, current_song, *volume);
|
||||
}
|
||||
33
ncursescalander/backup/Makefile
Normal file
33
ncursescalander/backup/Makefile
Normal file
@@ -0,0 +1,33 @@
|
||||
# Compiler and Flags
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -std=c11 -g
|
||||
LDFLAGS = -lncurses
|
||||
|
||||
# Source Files
|
||||
SRCS = main.c
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
# Output Binary
|
||||
TARGET = calendar
|
||||
|
||||
# Default Target
|
||||
all: $(TARGET)
|
||||
|
||||
# Build Target
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $(TARGET) $(OBJS) $(LDFLAGS)
|
||||
|
||||
# Object Files
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# Clean Target
|
||||
clean:
|
||||
rm -f $(OBJS) $(TARGET)
|
||||
|
||||
# Run Target
|
||||
run: $(TARGET)
|
||||
./$(TARGET)
|
||||
|
||||
# Phony Targets
|
||||
.PHONY: all clean run
|
||||
BIN
ncursescalander/backup/calendar
Executable file
BIN
ncursescalander/backup/calendar
Executable file
Binary file not shown.
326
ncursescalander/backup/main.c
Normal file
326
ncursescalander/backup/main.c
Normal file
@@ -0,0 +1,326 @@
|
||||
#include <ncurses.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#define MAX_TITLE_LEN 50
|
||||
#define MAX_CALENDAR_LEN 30
|
||||
#define MAX_NOTES_LEN 256
|
||||
|
||||
void draw_calendar(int month, int year, int selected_day);
|
||||
void draw_day_view(int *day, int *month, int *year);
|
||||
void open_add_event_tui();
|
||||
void open_repeat_tui();
|
||||
|
||||
int main() {
|
||||
int ch, month, year, day = 1;
|
||||
time_t now;
|
||||
struct tm *local;
|
||||
|
||||
// Initialize ncurses
|
||||
initscr();
|
||||
cbreak();
|
||||
noecho();
|
||||
keypad(stdscr, TRUE);
|
||||
start_color();
|
||||
init_pair(1, COLOR_RED, COLOR_BLACK); // Red color pair for the current time
|
||||
|
||||
// Get current date
|
||||
now = time(NULL);
|
||||
local = localtime(&now);
|
||||
month = local->tm_mon + 1;
|
||||
year = local->tm_year + 1900;
|
||||
day = local->tm_mday;
|
||||
|
||||
// Main loop
|
||||
while ((ch = getch()) != 'q') {
|
||||
bool redraw = false;
|
||||
switch (ch) {
|
||||
case KEY_LEFT:
|
||||
case 'j':
|
||||
if (day > 1) {
|
||||
day--;
|
||||
redraw = true;
|
||||
}
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
case 'k':
|
||||
if (day < 31) { // Simplified for demo purposes
|
||||
day++;
|
||||
redraw = true;
|
||||
}
|
||||
break;
|
||||
case 'a': // 'a' for "Add Event"
|
||||
open_add_event_tui();
|
||||
redraw = true;
|
||||
break;
|
||||
case '\n': // Enter key to open the day view
|
||||
draw_day_view(&day, &month, &year);
|
||||
redraw = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
clear();
|
||||
mvprintw(0, 0, "Calendar View - Press 'a' to Add Event");
|
||||
draw_calendar(month, year, day);
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
// End ncurses mode
|
||||
endwin();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void draw_calendar(int month, int year, int selected_day) {
|
||||
mvprintw(1, 0, "Month: %d, Year: %d", month, year);
|
||||
mvprintw(2, 0, "Su Mo Tu We Th Fr Sa");
|
||||
|
||||
// Placeholder for calendar drawing
|
||||
for (int i = 1; i <= 30; i++) { // Simplified example for 30 days
|
||||
if (i == selected_day) {
|
||||
attron(A_REVERSE); // Highlight the selected day
|
||||
}
|
||||
mvprintw(3 + (i / 7), (i % 7) * 3, "%2d", i);
|
||||
if (i == selected_day) {
|
||||
attroff(A_REVERSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_day_view(int *day, int *month, int *year) {
|
||||
time_t now;
|
||||
struct tm *local;
|
||||
int ch;
|
||||
bool redraw = true;
|
||||
|
||||
while (true) {
|
||||
if (redraw) {
|
||||
clear();
|
||||
mvprintw(0, 0, "Day View");
|
||||
mvprintw(1, 0, "Date: %02d-%02d-%04d", *day, *month, *year);
|
||||
|
||||
// Draw the hours of the day
|
||||
for (int i = 0; i < 24; i++) {
|
||||
mvprintw(i + 3, 0, "%02d:00 |", i);
|
||||
mvhline(i + 3, 8, ' ', COLS - 8);
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
local = localtime(&now);
|
||||
|
||||
if (local->tm_mday == *day && (local->tm_mon + 1) == *month && (local->tm_year + 1900) == *year) {
|
||||
int current_hour = local->tm_hour;
|
||||
int current_minute = local->tm_min;
|
||||
|
||||
attron(COLOR_PAIR(1)); // Red color
|
||||
mvhline(current_hour + 3, 8, '-', COLS - 8);
|
||||
mvprintw(current_hour + 3, 0, "%02d:%02d |", current_hour, current_minute);
|
||||
attroff(COLOR_PAIR(1));
|
||||
}
|
||||
|
||||
refresh();
|
||||
redraw = false;
|
||||
}
|
||||
|
||||
nodelay(stdscr, TRUE); // Make getch non-blocking
|
||||
ch = getch();
|
||||
|
||||
if (ch == 'q') break; // Exit to Calendar View
|
||||
if (ch == KEY_LEFT || ch == 'j') {
|
||||
if (*day > 1) {
|
||||
(*day)--;
|
||||
} else {
|
||||
if (*month > 1) {
|
||||
(*month)--;
|
||||
} else {
|
||||
*month = 12;
|
||||
(*year)--;
|
||||
}
|
||||
*day = 31; // Simplified for demo purposes
|
||||
}
|
||||
redraw = true;
|
||||
} else if (ch == KEY_RIGHT || ch == 'k') {
|
||||
if (*day < 31) { // Simplified for demo purposes
|
||||
(*day)++;
|
||||
} else {
|
||||
*day = 1;
|
||||
if (*month < 12) {
|
||||
(*month)++;
|
||||
} else {
|
||||
*month = 1;
|
||||
(*year)++;
|
||||
}
|
||||
}
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
napms(1000);
|
||||
}
|
||||
|
||||
nodelay(stdscr, FALSE);
|
||||
}
|
||||
|
||||
void open_add_event_tui() {
|
||||
char title[MAX_TITLE_LEN] = "";
|
||||
char calendar[MAX_CALENDAR_LEN] = "";
|
||||
char notes[MAX_NOTES_LEN] = "";
|
||||
int ch;
|
||||
bool all_day = false;
|
||||
int start_day = 1, end_day = 1;
|
||||
int start_hour = 9, start_minute = 0;
|
||||
int end_hour = 10, end_minute = 0;
|
||||
int repeat_option = 0;
|
||||
char repeat_options[4][20] = {"Never", "Every Day", "Every Week", "Custom"};
|
||||
|
||||
int cursor_pos = 0;
|
||||
|
||||
while (true) {
|
||||
clear();
|
||||
mvprintw(0, 0, "Add New Event");
|
||||
|
||||
// Title input
|
||||
mvprintw(2, 0, "Title: ");
|
||||
if (cursor_pos == 0) attron(A_REVERSE);
|
||||
mvprintw(2, 7, title);
|
||||
if (cursor_pos == 0) attroff(A_REVERSE);
|
||||
|
||||
// All-day toggle
|
||||
mvprintw(4, 0, "All Day: ");
|
||||
if (cursor_pos == 1) attron(A_REVERSE);
|
||||
mvprintw(4, 9, all_day ? "[X]" : "[ ]");
|
||||
if (cursor_pos == 1) attroff(A_REVERSE);
|
||||
|
||||
// Start day and time
|
||||
mvprintw(6, 0, "Start Day: %02d", start_day);
|
||||
mvprintw(7, 0, "Start Time: ");
|
||||
if (cursor_pos == 2) attron(A_REVERSE);
|
||||
mvprintw(7, 12, "%02d:%02d", start_hour, start_minute);
|
||||
if (cursor_pos == 2) attroff(A_REVERSE);
|
||||
|
||||
// End day and time
|
||||
mvprintw(9, 0, "End Day: %02d", end_day);
|
||||
mvprintw(10, 0, "End Time: ");
|
||||
if (cursor_pos == 3) attron(A_REVERSE);
|
||||
mvprintw(10, 10, "%02d:%02d", end_hour, end_minute);
|
||||
if (cursor_pos == 3) attroff(A_REVERSE);
|
||||
|
||||
// Repeat options
|
||||
mvprintw(12, 0, "Repeat: ");
|
||||
if (cursor_pos == 4) attron(A_REVERSE);
|
||||
mvprintw(12, 8, repeat_options[repeat_option]);
|
||||
if (cursor_pos == 4) attroff(A_REVERSE);
|
||||
|
||||
// Calendar name input
|
||||
mvprintw(14, 0, "Calendar: ");
|
||||
if (cursor_pos == 5) attron(A_REVERSE);
|
||||
mvprintw(14, 10, calendar);
|
||||
if (cursor_pos == 5) attroff(A_REVERSE);
|
||||
|
||||
// Notes input
|
||||
mvprintw(16, 0, "Notes: ");
|
||||
if (cursor_pos == 6) attron(A_REVERSE);
|
||||
mvprintw(17, 0, notes);
|
||||
if (cursor_pos == 6) attroff(A_REVERSE);
|
||||
|
||||
// Instructions
|
||||
mvprintw(19, 0, "Press 'q' to cancel, 's' to save");
|
||||
|
||||
refresh();
|
||||
|
||||
ch = getch();
|
||||
if (ch == 'q') break; // Exit without saving
|
||||
if (ch == 's') {
|
||||
// Here, you would normally save the event
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle navigation
|
||||
if (ch == KEY_DOWN || ch == 'j') {
|
||||
cursor_pos = (cursor_pos + 1) % 7;
|
||||
} else if (ch == KEY_UP || ch == 'k') {
|
||||
cursor_pos = (cursor_pos - 1 + 7) % 7;
|
||||
}
|
||||
|
||||
// Handle specific field input
|
||||
if (cursor_pos == 0 && ch != KEY_DOWN && ch != KEY_UP && ch != 's' && ch != 'q') {
|
||||
int len = strlen(title);
|
||||
if (ch == KEY_BACKSPACE || ch == 127) {
|
||||
if (len > 0) title[len - 1] = '\0';
|
||||
} else if (len < MAX_TITLE_LEN - 1) {
|
||||
title[len] = ch;
|
||||
title[len + 1] = '\0';
|
||||
}
|
||||
} else if (cursor_pos == 1 && (ch == ' ' || ch == '\n')) {
|
||||
all_day = !all_day;
|
||||
} else if (cursor_pos == 2 && (ch == ' ' || ch == '\n')) {
|
||||
// Placeholder: Handle start day and time input
|
||||
} else if (cursor_pos == 3 && (ch == ' ' || ch == '\n')) {
|
||||
// Placeholder: Handle end day and time input
|
||||
} else if (cursor_pos == 4 && (ch == ' ' || ch == '\n')) {
|
||||
// Open repeat TUI
|
||||
open_repeat_tui();
|
||||
} else if (cursor_pos == 5 && ch != KEY_DOWN && ch != KEY_UP && ch != 's' && ch != 'q') {
|
||||
int len = strlen(calendar);
|
||||
if (ch == KEY_BACKSPACE || ch == 127) {
|
||||
if (len > 0) calendar[len - 1] = '\0';
|
||||
} else if (len < MAX_CALENDAR_LEN - 1) {
|
||||
calendar[len] = ch;
|
||||
calendar[len + 1] = '\0';
|
||||
}
|
||||
} else if (cursor_pos == 6 && ch != KEY_DOWN && ch != KEY_UP && ch != 's' && ch != 'q') {
|
||||
int len = strlen(notes);
|
||||
if (ch == KEY_BACKSPACE || ch == 127) {
|
||||
if (len > 0) notes[len - 1] = '\0';
|
||||
} else if (len < MAX_NOTES_LEN - 1) {
|
||||
notes[len] = ch;
|
||||
notes[len + 1] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void open_repeat_tui() {
|
||||
int ch;
|
||||
int cursor_pos = 0;
|
||||
|
||||
while (true) {
|
||||
clear();
|
||||
mvprintw(0, 0, "Repeat Options");
|
||||
|
||||
mvprintw(2, 0, "1. Never");
|
||||
if (cursor_pos == 0) attron(A_REVERSE);
|
||||
mvprintw(2, 10, "Select");
|
||||
if (cursor_pos == 0) attroff(A_REVERSE);
|
||||
|
||||
mvprintw(4, 0, "2. Every Day");
|
||||
if (cursor_pos == 1) attron(A_REVERSE);
|
||||
mvprintw(4, 10, "Select");
|
||||
if (cursor_pos == 1) attroff(A_REVERSE);
|
||||
|
||||
mvprintw(6, 0, "3. Every Week");
|
||||
if (cursor_pos == 2) attron(A_REVERSE);
|
||||
mvprintw(6, 10, "Select");
|
||||
if (cursor_pos == 2) attroff(A_REVERSE);
|
||||
|
||||
mvprintw(8, 0, "4. Custom");
|
||||
if (cursor_pos == 3) attron(A_REVERSE);
|
||||
mvprintw(8, 10, "Select");
|
||||
if (cursor_pos == 3) attroff(A_REVERSE);
|
||||
|
||||
mvprintw(10, 0, "Press 'q' to return");
|
||||
|
||||
refresh();
|
||||
|
||||
ch = getch();
|
||||
if (ch == 'q') break; // Return to the add event TUI
|
||||
if (ch == KEY_DOWN || ch == 'j') {
|
||||
cursor_pos = (cursor_pos + 1) % 4;
|
||||
} else if (ch == KEY_UP || ch == 'k') {
|
||||
cursor_pos = (cursor_pos - 1 + 4) % 4;
|
||||
} else if (ch == '\n') {
|
||||
// Here, you would handle selection logic
|
||||
break; // Return after selection for now
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
ncursescalander/backup/main.o
Normal file
BIN
ncursescalander/backup/main.o
Normal file
Binary file not shown.
26
ncursescalander/build/Makefile
Normal file
26
ncursescalander/build/Makefile
Normal file
@@ -0,0 +1,26 @@
|
||||
# Makefile for ncurses calendar app
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -I../include
|
||||
LDFLAGS = -lncurses -lsqlite3
|
||||
SRC_DIR = ../src
|
||||
BUILD_DIR = ../build
|
||||
|
||||
SRC_FILES = $(wildcard $(SRC_DIR)/*.c)
|
||||
OBJ_FILES = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(SRC_FILES))
|
||||
|
||||
TARGET = calendar_app
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJ_FILES)
|
||||
$(CC) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(BUILD_DIR)/*.o $(TARGET)
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
BIN
ncursescalander/build/add_event.o
Normal file
BIN
ncursescalander/build/add_event.o
Normal file
Binary file not shown.
BIN
ncursescalander/build/calendar.o
Normal file
BIN
ncursescalander/build/calendar.o
Normal file
Binary file not shown.
BIN
ncursescalander/build/calendar_app
Executable file
BIN
ncursescalander/build/calendar_app
Executable file
Binary file not shown.
BIN
ncursescalander/build/day_view.o
Normal file
BIN
ncursescalander/build/day_view.o
Normal file
Binary file not shown.
BIN
ncursescalander/build/main.o
Normal file
BIN
ncursescalander/build/main.o
Normal file
Binary file not shown.
BIN
ncursescalander/build/repeat_tui.o
Normal file
BIN
ncursescalander/build/repeat_tui.o
Normal file
Binary file not shown.
BIN
ncursescalander/databases/calendar_database.db
Normal file
BIN
ncursescalander/databases/calendar_database.db
Normal file
Binary file not shown.
29
ncursescalander/include/add_event.h
Normal file
29
ncursescalander/include/add_event.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef ADD_EVENT_H
|
||||
#define ADD_EVENT_H
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MAX_TITLE_LEN 50
|
||||
#define MAX_CALENDAR_LEN 30
|
||||
#define MAX_NOTES_LEN 256
|
||||
#define MAX_DATE_LEN 50
|
||||
|
||||
typedef struct {
|
||||
char title[MAX_TITLE_LEN];
|
||||
bool all_day;
|
||||
char start_date[MAX_DATE_LEN];
|
||||
char end_date[MAX_DATE_LEN];
|
||||
int start_hour, start_minute;
|
||||
int end_hour, end_minute;
|
||||
int repeat_option;
|
||||
char calendar[MAX_CALENDAR_LEN];
|
||||
char notes[MAX_NOTES_LEN];
|
||||
} Event;
|
||||
|
||||
Event *create_event();
|
||||
void save_event_to_db(sqlite3 *db, Event *event);
|
||||
sqlite3* open_database();
|
||||
void open_add_event_tui(sqlite3 *db);
|
||||
|
||||
#endif
|
||||
8
ncursescalander/include/calendar.h
Normal file
8
ncursescalander/include/calendar.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef CALENDAR_H
|
||||
#define CALENDAR_H
|
||||
|
||||
int is_leap_year(int year);
|
||||
int days_in_month(int month, int year);
|
||||
void draw_calendar(int month, int year, int selected_day);
|
||||
|
||||
#endif
|
||||
7
ncursescalander/include/day_view.h
Normal file
7
ncursescalander/include/day_view.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef DAY_VIEW_H
|
||||
#define DAY_VIEW_H
|
||||
|
||||
void draw_day_view(int *day, int *month, int *year);
|
||||
|
||||
#endif
|
||||
|
||||
7
ncursescalander/include/repeat_tui.h
Normal file
7
ncursescalander/include/repeat_tui.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef REPEAT_TUI_H
|
||||
#define REPEAT_TUI_H
|
||||
|
||||
void open_repeat_tui();
|
||||
|
||||
#endif
|
||||
|
||||
292
ncursescalander/src/add_event.c
Normal file
292
ncursescalander/src/add_event.c
Normal file
@@ -0,0 +1,292 @@
|
||||
#include "add_event.h"
|
||||
#include "repeat_tui.h"
|
||||
#include <ncurses.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <sqlite3.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Create and initialize a new event
|
||||
Event *create_event() {
|
||||
Event *event = (Event *)malloc(sizeof(Event));
|
||||
if (event) {
|
||||
memset(event, 0, sizeof(Event));
|
||||
strcpy(event->start_date, "01/01/2000");
|
||||
strcpy(event->end_date, "01/01/2000");
|
||||
event->start_hour = 9;
|
||||
event->start_minute = 0;
|
||||
event->end_hour = 10;
|
||||
event->end_minute = 0;
|
||||
event->repeat_option = 0;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
// Function to open the SQLite database
|
||||
|
||||
sqlite3* open_database() {
|
||||
char path[PATH_MAX];
|
||||
char base_dir[PATH_MAX];
|
||||
char db_path[PATH_MAX];
|
||||
|
||||
// Get the current working directory
|
||||
if (getcwd(path, sizeof(path)) != NULL) {
|
||||
printf("Current working directory: %s\n", path);
|
||||
|
||||
// Go up one directory level to the 'ncursescalander' directory
|
||||
strncpy(base_dir, path, sizeof(base_dir));
|
||||
dirname(base_dir);
|
||||
printf("Base directory (one level up): %s\n", base_dir);
|
||||
|
||||
// Calculate required size
|
||||
int required_size = snprintf(NULL, 0, "%s/databases/calendar_database.db", base_dir) + 1;
|
||||
if (required_size > (int)sizeof(db_path)) { // Cast to int for comparison
|
||||
fprintf(stderr, "Error: Path length exceeds buffer size.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Construct the final path to the database file
|
||||
snprintf(db_path, sizeof(db_path), "%s/databases/calendar_database.db", base_dir);
|
||||
printf("Final database path: %s\n", db_path);
|
||||
|
||||
sqlite3 *db;
|
||||
if (sqlite3_open(db_path, &db)) {
|
||||
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
|
||||
return NULL;
|
||||
} else {
|
||||
printf("Opened database successfully\n");
|
||||
return db;
|
||||
}
|
||||
} else {
|
||||
perror("getcwd() error");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to save an event to the SQLite database
|
||||
void save_event_to_db(sqlite3 *db, Event *event) {
|
||||
// Set default values if necessary
|
||||
if (strlen(event->title) == 0) {
|
||||
strcpy(event->title, "Untitled");
|
||||
}
|
||||
if (strlen(event->calendar) == 0) {
|
||||
strcpy(event->calendar, "");
|
||||
}
|
||||
if (strlen(event->notes) == 0) {
|
||||
strcpy(event->notes, "");
|
||||
}
|
||||
|
||||
// Prepare SQL statement
|
||||
char *sql = "INSERT INTO events (title, all_day, start_date, end_date, start_time, end_time, repeat_option, calendar, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);";
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, 0) == SQLITE_OK) {
|
||||
// Bind values to SQL statement
|
||||
sqlite3_bind_text(stmt, 1, event->title, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int(stmt, 2, event->all_day);
|
||||
sqlite3_bind_text(stmt, 3, event->start_date, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 4, event->end_date, -1, SQLITE_STATIC);
|
||||
|
||||
// Format time as HH:MM
|
||||
char start_time[6];
|
||||
snprintf(start_time, sizeof(start_time), "%02d:%02d", event->start_hour, event->start_minute);
|
||||
sqlite3_bind_text(stmt, 5, start_time, -1, SQLITE_STATIC);
|
||||
|
||||
char end_time[6];
|
||||
snprintf(end_time, sizeof(end_time), "%02d:%02d", event->end_hour, event->end_minute);
|
||||
sqlite3_bind_text(stmt, 6, end_time, -1, SQLITE_STATIC);
|
||||
|
||||
sqlite3_bind_int(stmt, 7, event->repeat_option);
|
||||
sqlite3_bind_text(stmt, 8, event->calendar, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 9, event->notes, -1, SQLITE_STATIC);
|
||||
|
||||
// Execute the SQL statement
|
||||
if (sqlite3_step(stmt) != SQLITE_DONE) {
|
||||
fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
|
||||
} else {
|
||||
printf("Event saved successfully.\n");
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
} else {
|
||||
fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
|
||||
// Function to display the Add Event TUI and handle user input
|
||||
void open_add_event_tui(sqlite3 *db) {
|
||||
Event *event = create_event();
|
||||
int ch;
|
||||
int cursor_pos = 0;
|
||||
bool exit = false;
|
||||
|
||||
while (!exit) {
|
||||
clear();
|
||||
mvprintw(0, 0, "Add New Event");
|
||||
|
||||
// Title input
|
||||
mvprintw(2, 0, "Title: ");
|
||||
if (cursor_pos == 0) attron(A_REVERSE);
|
||||
mvprintw(2, 7, event->title);
|
||||
if (cursor_pos == 0) attroff(A_REVERSE);
|
||||
|
||||
// All-day toggle
|
||||
mvprintw(4, 0, "All Day: ");
|
||||
if (cursor_pos == 1) attron(A_REVERSE);
|
||||
mvprintw(4, 9, event->all_day ? "[X]" : "[ ]");
|
||||
if (cursor_pos == 1) attroff(A_REVERSE);
|
||||
|
||||
// Start date input
|
||||
mvprintw(6, 0, "Start Date: ");
|
||||
if (cursor_pos == 2) attron(A_REVERSE);
|
||||
mvprintw(6, 12, event->start_date);
|
||||
if (cursor_pos == 2) attroff(A_REVERSE);
|
||||
|
||||
// End date input
|
||||
mvprintw(8, 0, "End Date: ");
|
||||
if (cursor_pos == 3) attron(A_REVERSE);
|
||||
mvprintw(8, 10, event->end_date);
|
||||
if (cursor_pos == 3) attroff(A_REVERSE);
|
||||
|
||||
// Start time input
|
||||
mvprintw(10, 0, "Start Time: ");
|
||||
if (cursor_pos == 4) attron(A_REVERSE);
|
||||
mvprintw(10, 12, "%02d:%02d", event->start_hour, event->start_minute);
|
||||
if (cursor_pos == 4) attroff(A_REVERSE);
|
||||
|
||||
// End time input
|
||||
mvprintw(12, 0, "End Time: ");
|
||||
if (cursor_pos == 5) attron(A_REVERSE);
|
||||
mvprintw(12, 10, "%02d:%02d", event->end_hour, event->end_minute);
|
||||
if (cursor_pos == 5) attroff(A_REVERSE);
|
||||
|
||||
// Repeat options
|
||||
mvprintw(14, 0, "Repeat: ");
|
||||
if (cursor_pos == 6) attron(A_REVERSE);
|
||||
mvprintw(14, 8, "Choose..."); // Display the repeat choice interactively
|
||||
if (cursor_pos == 6) attroff(A_REVERSE);
|
||||
|
||||
// Calendar name input
|
||||
mvprintw(16, 0, "Calendar: ");
|
||||
if (cursor_pos == 7) attron(A_REVERSE);
|
||||
mvprintw(16, 10, event->calendar);
|
||||
if (cursor_pos == 7) attroff(A_REVERSE);
|
||||
|
||||
// Notes input
|
||||
mvprintw(18, 0, "Notes: ");
|
||||
if (cursor_pos == 8) attron(A_REVERSE);
|
||||
mvprintw(19, 0, event->notes);
|
||||
if (cursor_pos == 8) attroff(A_REVERSE);
|
||||
|
||||
// Instructions
|
||||
mvprintw(21, 0, "Esc: Cancel Ctrl+S: Save");
|
||||
|
||||
refresh();
|
||||
|
||||
ch = getch();
|
||||
switch (ch) {
|
||||
case 27: // ESC to cancel
|
||||
exit = true;
|
||||
break;
|
||||
case 19: // Ctrl+S to save (^S)
|
||||
save_event_to_db(db, event);
|
||||
exit = true; // Return to calendar view after saving
|
||||
break;
|
||||
case KEY_DOWN: // Navigate down
|
||||
cursor_pos = (cursor_pos + 1) % 9;
|
||||
break;
|
||||
case KEY_UP: // Navigate up
|
||||
cursor_pos = (cursor_pos - 1 + 9) % 9;
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
case 'j': // Decrease minute
|
||||
if (cursor_pos == 4) {
|
||||
event->start_minute = (event->start_minute > 0) ? event->start_minute - 1 : 59;
|
||||
} else if (cursor_pos == 5) {
|
||||
event->end_minute = (event->end_minute > 0) ? event->end_minute - 1 : 59;
|
||||
}
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
case 'k': // Increase minute
|
||||
if (cursor_pos == 4) {
|
||||
event->start_minute = (event->start_minute < 59) ? event->start_minute + 1 : 0;
|
||||
} else if (cursor_pos == 5) {
|
||||
event->end_minute = (event->end_minute < 59) ? event->end_minute + 1 : 0;
|
||||
}
|
||||
break;
|
||||
case KEY_SLEFT:
|
||||
case 'h': // Decrease hour (Shift+Left or 'h')
|
||||
if (cursor_pos == 4) {
|
||||
event->start_hour = (event->start_hour > 0) ? event->start_hour - 1 : 23;
|
||||
} else if (cursor_pos == 5) {
|
||||
event->end_hour = (event->end_hour > 0) ? event->end_hour - 1 : 23;
|
||||
}
|
||||
break;
|
||||
case KEY_SRIGHT:
|
||||
case 'l': // Increase hour (Shift+Right or 'l')
|
||||
if (cursor_pos == 4) {
|
||||
event->start_hour = (event->start_hour < 23) ? event->start_hour + 1 : 0;
|
||||
} else if (cursor_pos == 5) {
|
||||
event->end_hour = (event->end_hour < 23) ? event->end_hour + 1 : 0;
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
case '\n':
|
||||
if (cursor_pos == 1) {
|
||||
event->all_day = !event->all_day;
|
||||
} else if (cursor_pos == 6) {
|
||||
open_repeat_tui(); // Placeholder for opening the repeat TUI
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (cursor_pos == 0 && ch != KEY_DOWN && ch != KEY_UP) {
|
||||
int len = strlen(event->title);
|
||||
if ((ch == KEY_BACKSPACE || ch == 127) && len > 0) {
|
||||
event->title[len - 1] = '\0';
|
||||
} else if (isprint(ch) && len < MAX_TITLE_LEN - 1) {
|
||||
event->title[len] = ch;
|
||||
event->title[len + 1] = '\0';
|
||||
}
|
||||
} else if (cursor_pos == 2 && ch != KEY_DOWN && ch != KEY_UP) {
|
||||
int len = strlen(event->start_date);
|
||||
if ((ch == KEY_BACKSPACE || ch == 127) && len > 0) {
|
||||
event->start_date[len - 1] = '\0';
|
||||
} else if (isprint(ch) && len < MAX_DATE_LEN - 1) {
|
||||
event->start_date[len] = ch;
|
||||
event->start_date[len + 1] = '\0';
|
||||
}
|
||||
} else if (cursor_pos == 3 && ch != KEY_DOWN && ch != KEY_UP) {
|
||||
int len = strlen(event->end_date);
|
||||
if ((ch == KEY_BACKSPACE || ch == 127) && len > 0) {
|
||||
event->end_date[len - 1] = '\0';
|
||||
} else if (isprint(ch) && len < MAX_DATE_LEN - 1) {
|
||||
event->end_date[len] = ch;
|
||||
event->end_date[len + 1] = '\0';
|
||||
}
|
||||
} else if (cursor_pos == 7 && ch != KEY_DOWN && ch != KEY_UP) {
|
||||
int len = strlen(event->calendar);
|
||||
if ((ch == KEY_BACKSPACE || ch == 127) && len > 0) {
|
||||
event->calendar[len - 1] = '\0';
|
||||
} else if (isprint(ch) && len < MAX_CALENDAR_LEN - 1) {
|
||||
event->calendar[len] = ch;
|
||||
event->calendar[len + 1] = '\0';
|
||||
}
|
||||
} else if (cursor_pos == 8 && ch != KEY_DOWN && ch != KEY_UP) {
|
||||
int len = strlen(event->notes);
|
||||
if ((ch == KEY_BACKSPACE || ch == 127) && len > 0) {
|
||||
event->notes[len - 1] = '\0';
|
||||
} else if (isprint(ch) && len < MAX_NOTES_LEN - 1) {
|
||||
event->notes[len] = ch;
|
||||
event->notes[len + 1] = '\0';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(event); // Free the allocated memory
|
||||
}
|
||||
225
ncursescalander/src/add_event.c.bak
Normal file
225
ncursescalander/src/add_event.c.bak
Normal file
@@ -0,0 +1,225 @@
|
||||
#include "add_event.h"
|
||||
#include "repeat_tui.h"
|
||||
#include <ncurses.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define MAX_TITLE_LEN 50
|
||||
#define MAX_CALENDAR_LEN 30
|
||||
#define MAX_NOTES_LEN 256
|
||||
#define MAX_DATE_LEN 50
|
||||
|
||||
typedef struct {
|
||||
char title[MAX_TITLE_LEN];
|
||||
bool all_day;
|
||||
char start_date[MAX_DATE_LEN];
|
||||
char end_date[MAX_DATE_LEN];
|
||||
int start_hour, start_minute;
|
||||
int end_hour, end_minute;
|
||||
int repeat_option;
|
||||
char calendar[MAX_CALENDAR_LEN];
|
||||
char notes[MAX_NOTES_LEN];
|
||||
} Event;
|
||||
|
||||
Event *create_event() {
|
||||
Event *event = (Event *)malloc(sizeof(Event));
|
||||
if (event) {
|
||||
memset(event, 0, sizeof(Event));
|
||||
strcpy(event->start_date, "01/01/2000");
|
||||
strcpy(event->end_date, "01/01/2000");
|
||||
event->start_hour = 9;
|
||||
event->start_minute = 0;
|
||||
event->end_hour = 10;
|
||||
event->end_minute = 0;
|
||||
event->repeat_option = 0;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
void save_event(Event *event) {
|
||||
FILE *file = fopen("events.txt", "a");
|
||||
if (file) {
|
||||
fprintf(file, "Title: %s\nAll Day: %d\nStart Date: %s\nEnd Date: %s\nStart: %02d:%02d\nEnd: %02d:%02d\nRepeat: %d\nCalendar: %s\nNotes: %s\n\n",
|
||||
event->title, event->all_day, event->start_date, event->end_date, event->start_hour, event->start_minute,
|
||||
event->end_hour, event->end_minute, event->repeat_option, event->calendar, event->notes);
|
||||
fclose(file);
|
||||
} else {
|
||||
mvprintw(23, 0, "Error saving event!"); // Error message
|
||||
refresh();
|
||||
getch(); // Pause to let the user see the error
|
||||
}
|
||||
}
|
||||
|
||||
void open_add_event_tui() {
|
||||
Event *event = create_event();
|
||||
int ch;
|
||||
int cursor_pos = 0;
|
||||
bool exit = false;
|
||||
|
||||
while (!exit) {
|
||||
clear();
|
||||
mvprintw(0, 0, "Add New Event");
|
||||
|
||||
// Title input
|
||||
mvprintw(2, 0, "Title: ");
|
||||
if (cursor_pos == 0) attron(A_REVERSE);
|
||||
mvprintw(2, 7, event->title);
|
||||
if (cursor_pos == 0) attroff(A_REVERSE);
|
||||
|
||||
// All-day toggle
|
||||
mvprintw(4, 0, "All Day: ");
|
||||
if (cursor_pos == 1) attron(A_REVERSE);
|
||||
mvprintw(4, 9, event->all_day ? "[X]" : "[ ]");
|
||||
if (cursor_pos == 1) attroff(A_REVERSE);
|
||||
|
||||
// Start date input
|
||||
mvprintw(6, 0, "Start Date: ");
|
||||
if (cursor_pos == 2) attron(A_REVERSE);
|
||||
mvprintw(6, 12, event->start_date);
|
||||
if (cursor_pos == 2) attroff(A_REVERSE);
|
||||
|
||||
// End date input
|
||||
mvprintw(8, 0, "End Date: ");
|
||||
if (cursor_pos == 3) attron(A_REVERSE);
|
||||
mvprintw(8, 10, event->end_date);
|
||||
if (cursor_pos == 3) attroff(A_REVERSE);
|
||||
|
||||
// Start time input
|
||||
mvprintw(10, 0, "Start Time: ");
|
||||
if (cursor_pos == 4) attron(A_REVERSE);
|
||||
mvprintw(10, 12, "%02d:%02d", event->start_hour, event->start_minute);
|
||||
if (cursor_pos == 4) attroff(A_REVERSE);
|
||||
|
||||
// End time input
|
||||
mvprintw(12, 0, "End Time: ");
|
||||
if (cursor_pos == 5) attron(A_REVERSE);
|
||||
mvprintw(12, 10, "%02d:%02d", event->end_hour, event->end_minute);
|
||||
if (cursor_pos == 5) attroff(A_REVERSE);
|
||||
|
||||
// Repeat options
|
||||
mvprintw(14, 0, "Repeat: ");
|
||||
if (cursor_pos == 6) attron(A_REVERSE);
|
||||
mvprintw(14, 8, "Choose..."); // Display the repeat choice interactively
|
||||
if (cursor_pos == 6) attroff(A_REVERSE);
|
||||
|
||||
// Calendar name input
|
||||
mvprintw(16, 0, "Calendar: ");
|
||||
if (cursor_pos == 7) attron(A_REVERSE);
|
||||
mvprintw(16, 10, event->calendar);
|
||||
if (cursor_pos == 7) attroff(A_REVERSE);
|
||||
|
||||
// Notes input
|
||||
mvprintw(18, 0, "Notes: ");
|
||||
if (cursor_pos == 8) attron(A_REVERSE);
|
||||
mvprintw(19, 0, event->notes);
|
||||
if (cursor_pos == 8) attroff(A_REVERSE);
|
||||
|
||||
// Instructions
|
||||
mvprintw(21, 0, "Esc: Cancel Ctrl+S: Save");
|
||||
|
||||
refresh();
|
||||
|
||||
ch = getch();
|
||||
switch (ch) {
|
||||
case 27: // ESC to cancel
|
||||
exit = true;
|
||||
break;
|
||||
case 19: // Ctrl+S to save (^S)
|
||||
save_event(event);
|
||||
exit = true; // Return to calendar view after saving
|
||||
break;
|
||||
case KEY_DOWN: // Navigate down
|
||||
cursor_pos = (cursor_pos + 1) % 9;
|
||||
break;
|
||||
case KEY_UP: // Navigate up
|
||||
cursor_pos = (cursor_pos - 1 + 9) % 9;
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
case 'j': // Decrease minute
|
||||
if (cursor_pos == 4) {
|
||||
event->start_minute = (event->start_minute > 0) ? event->start_minute - 1 : 59;
|
||||
} else if (cursor_pos == 5) {
|
||||
event->end_minute = (event->end_minute > 0) ? event->end_minute - 1 : 59;
|
||||
}
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
case 'k': // Increase minute
|
||||
if (cursor_pos == 4) {
|
||||
event->start_minute = (event->start_minute < 59) ? event->start_minute + 1 : 0;
|
||||
} else if (cursor_pos == 5) {
|
||||
event->end_minute = (event->end_minute < 59) ? event->end_minute + 1 : 0;
|
||||
}
|
||||
break;
|
||||
case KEY_SLEFT:
|
||||
case 'h': // Decrease hour (Shift+Left or 'h')
|
||||
if (cursor_pos == 4) {
|
||||
event->start_hour = (event->start_hour > 0) ? event->start_hour - 1 : 23;
|
||||
} else if (cursor_pos == 5) {
|
||||
event->end_hour = (event->end_hour > 0) ? event->end_hour - 1 : 23;
|
||||
}
|
||||
break;
|
||||
case KEY_SRIGHT:
|
||||
case 'l': // Increase hour (Shift+Right or 'l')
|
||||
if (cursor_pos == 4) {
|
||||
event->start_hour = (event->start_hour < 23) ? event->start_hour + 1 : 0;
|
||||
} else if (cursor_pos == 5) {
|
||||
event->end_hour = (event->end_hour < 23) ? event->end_hour + 1 : 0;
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
case '\n':
|
||||
if (cursor_pos == 1) {
|
||||
event->all_day = !event->all_day;
|
||||
} else if (cursor_pos == 6) {
|
||||
open_repeat_tui(); // Placeholder for opening the repeat TUI
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (cursor_pos == 0 && ch != KEY_DOWN && ch != KEY_UP) {
|
||||
int len = strlen(event->title);
|
||||
if ((ch == KEY_BACKSPACE || ch == 127) && len > 0) {
|
||||
event->title[len - 1] = '\0';
|
||||
} else if (isprint(ch) && len < MAX_TITLE_LEN - 1) {
|
||||
event->title[len] = ch;
|
||||
event->title[len + 1] = '\0';
|
||||
}
|
||||
} else if (cursor_pos == 2 && ch != KEY_DOWN && ch != KEY_UP) {
|
||||
int len = strlen(event->start_date);
|
||||
if ((ch == KEY_BACKSPACE || ch == 127) && len > 0) {
|
||||
event->start_date[len - 1] = '\0';
|
||||
} else if (isprint(ch) && len < MAX_DATE_LEN - 1) {
|
||||
event->start_date[len] = ch;
|
||||
event->start_date[len + 1] = '\0';
|
||||
}
|
||||
} else if (cursor_pos == 3 && ch != KEY_DOWN && ch != KEY_UP) {
|
||||
int len = strlen(event->end_date);
|
||||
if ((ch == KEY_BACKSPACE || ch == 127) && len > 0) {
|
||||
event->end_date[len - 1] = '\0';
|
||||
} else if (isprint(ch) && len < MAX_DATE_LEN - 1) {
|
||||
event->end_date[len] = ch;
|
||||
event->end_date[len + 1] = '\0';
|
||||
}
|
||||
} else if (cursor_pos == 7 && ch != KEY_DOWN && ch != KEY_UP) {
|
||||
int len = strlen(event->calendar);
|
||||
if ((ch == KEY_BACKSPACE || ch == 127) && len > 0) {
|
||||
event->calendar[len - 1] = '\0';
|
||||
} else if (isprint(ch) && len < MAX_CALENDAR_LEN - 1) {
|
||||
event->calendar[len] = ch;
|
||||
event->calendar[len + 1] = '\0';
|
||||
}
|
||||
} else if (cursor_pos == 8 && ch != KEY_DOWN && ch != KEY_UP) {
|
||||
int len = strlen(event->notes);
|
||||
if ((ch == KEY_BACKSPACE || ch == 127) && len > 0) {
|
||||
event->notes[len - 1] = '\0';
|
||||
} else if (isprint(ch) && len < MAX_NOTES_LEN - 1) {
|
||||
event->notes[len] = ch;
|
||||
event->notes[len + 1] = '\0';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(event); // Free the allocated memory
|
||||
}
|
||||
56
ncursescalander/src/calendar.c
Normal file
56
ncursescalander/src/calendar.c
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "calendar.h"
|
||||
#include <ncurses.h>
|
||||
|
||||
// Function to determine if a year is a leap year
|
||||
int is_leap_year(int year) {
|
||||
if (year % 4 == 0) {
|
||||
if (year % 100 == 0) {
|
||||
if (year % 400 == 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
} else
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Function to get the number of days in a given month and year
|
||||
int days_in_month(int month, int year) {
|
||||
switch (month) {
|
||||
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
|
||||
return 31;
|
||||
case 4: case 6: case 9: case 11:
|
||||
return 30;
|
||||
case 2:
|
||||
if (is_leap_year(year))
|
||||
return 29;
|
||||
else
|
||||
return 28;
|
||||
default:
|
||||
return 30; // Fallback, though we shouldn't hit this
|
||||
}
|
||||
}
|
||||
|
||||
void draw_calendar(int month, int year, int selected_day) {
|
||||
int days = days_in_month(month, year);
|
||||
|
||||
// Adjust selected_day if it exceeds the number of days in the month
|
||||
if (selected_day > days) {
|
||||
selected_day = days;
|
||||
}
|
||||
|
||||
mvprintw(1, 0, "Month: %d, Year: %d", month, year);
|
||||
mvprintw(2, 0, "Su Mo Tu We Th Fr Sa");
|
||||
|
||||
// Placeholder for calendar drawing
|
||||
for (int i = 1; i <= days; i++) {
|
||||
if (i == selected_day) {
|
||||
attron(A_REVERSE); // Highlight the selected day
|
||||
}
|
||||
mvprintw(3 + (i / 7), (i % 7) * 3, "%2d", i);
|
||||
if (i == selected_day) {
|
||||
attroff(A_REVERSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
127
ncursescalander/src/day_view.c
Normal file
127
ncursescalander/src/day_view.c
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "day_view.h"
|
||||
#include <ncurses.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_TITLE_LEN 50
|
||||
|
||||
typedef struct {
|
||||
char title[MAX_TITLE_LEN];
|
||||
int start_hour;
|
||||
int start_minute;
|
||||
int end_hour;
|
||||
int end_minute;
|
||||
int event_day;
|
||||
int event_month;
|
||||
int event_year;
|
||||
} DisplayEvent;
|
||||
|
||||
void load_events(DisplayEvent *events, int *count, int day, int month, int year) {
|
||||
FILE *file = fopen("events.txt", "r");
|
||||
if (file) {
|
||||
char line[256];
|
||||
int current_day, current_month, current_year;
|
||||
while (fgets(line, sizeof(line), file)) {
|
||||
if (sscanf(line, "Date: %d-%d-%d", ¤t_day, ¤t_month, ¤t_year) == 3) {
|
||||
if (current_day == day && current_month == month && current_year == year) {
|
||||
fgets(line, sizeof(line), file);
|
||||
sscanf(line, "Start: %02d:%02d", &events[*count].start_hour, &events[*count].start_minute);
|
||||
fgets(line, sizeof(line), file);
|
||||
sscanf(line, "End: %02d:%02d", &events[*count].end_hour, &events[*count].end_minute);
|
||||
fgets(line, sizeof(line), file);
|
||||
sscanf(line, "Title: %49[^\n]", events[*count].title);
|
||||
events[*count].event_day = current_day;
|
||||
events[*count].event_month = current_month;
|
||||
events[*count].event_year = current_year;
|
||||
(*count)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_day_view(int *day, int *month, int *year) {
|
||||
time_t now;
|
||||
struct tm *local;
|
||||
int ch;
|
||||
bool redraw = true;
|
||||
|
||||
DisplayEvent events[10];
|
||||
int event_count = 0;
|
||||
load_events(events, &event_count, *day, *month, *year);
|
||||
|
||||
while (true) {
|
||||
if (redraw) {
|
||||
clear();
|
||||
mvprintw(0, 0, "Day View");
|
||||
mvprintw(1, 0, "Date: %02d-%02d-%04d", *day, *month, *year);
|
||||
|
||||
// Draw the hours of the day
|
||||
for (int i = 0; i < 24; i++) {
|
||||
mvprintw(i + 3, 0, "%02d:00 |", i);
|
||||
mvhline(i + 3, 8, ' ', COLS - 8);
|
||||
}
|
||||
|
||||
// Display events
|
||||
for (int i = 0; i < event_count; i++) {
|
||||
mvprintw(events[i].start_hour + 3, 10, "%s", events[i].title);
|
||||
mvhline(events[i].start_hour + 3, 10 + strlen(events[i].title), '-', COLS - 20);
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
local = localtime(&now);
|
||||
|
||||
if (local->tm_mday == *day && (local->tm_mon + 1) == *month && (local->tm_year + 1900) == *year) {
|
||||
int current_hour = local->tm_hour;
|
||||
int current_minute = local->tm_min;
|
||||
|
||||
attron(COLOR_PAIR(1)); // Red color
|
||||
mvhline(current_hour + 3, 8, '-', COLS - 8);
|
||||
mvprintw(current_hour + 3, 0, "%02d:%02d |", current_hour, current_minute);
|
||||
attroff(COLOR_PAIR(1));
|
||||
}
|
||||
|
||||
refresh();
|
||||
redraw = false;
|
||||
}
|
||||
|
||||
nodelay(stdscr, TRUE); // Make getch non-blocking
|
||||
ch = getch();
|
||||
|
||||
if (ch == 'q') break; // Exit to Calendar View
|
||||
if (ch == KEY_LEFT || ch == 'j') {
|
||||
if (*day > 1) {
|
||||
(*day)--;
|
||||
} else {
|
||||
if (*month > 1) {
|
||||
(*month)--;
|
||||
} else {
|
||||
*month = 12;
|
||||
(*year)--;
|
||||
}
|
||||
*day = 31; // Simplified for demo purposes
|
||||
}
|
||||
redraw = true;
|
||||
} else if (ch == KEY_RIGHT || ch == 'k') {
|
||||
if (*day < 31) { // Simplified for demo purposes
|
||||
(*day)++;
|
||||
} else {
|
||||
*day = 1;
|
||||
if (*month < 12) {
|
||||
(*month)++;
|
||||
} else {
|
||||
*month = 1;
|
||||
(*year)++;
|
||||
}
|
||||
}
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
napms(1000);
|
||||
}
|
||||
|
||||
nodelay(stdscr, FALSE);
|
||||
}
|
||||
|
||||
106
ncursescalander/src/main.c
Normal file
106
ncursescalander/src/main.c
Normal file
@@ -0,0 +1,106 @@
|
||||
#include <ncurses.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "calendar.h"
|
||||
#include "day_view.h"
|
||||
#include "add_event.h"
|
||||
|
||||
int main() {
|
||||
int ch, month, year, day = 1;
|
||||
time_t now;
|
||||
struct tm *local;
|
||||
|
||||
// Open the SQLite database
|
||||
sqlite3 *db = open_database();
|
||||
if (db == NULL) {
|
||||
return 1; // Exit if the database can't be opened
|
||||
}
|
||||
|
||||
// Initialize ncurses
|
||||
initscr();
|
||||
cbreak();
|
||||
noecho();
|
||||
keypad(stdscr, TRUE);
|
||||
start_color();
|
||||
init_pair(1, COLOR_RED, COLOR_BLACK); // Red color pair for the current time
|
||||
|
||||
// Get current date
|
||||
now = time(NULL);
|
||||
local = localtime(&now);
|
||||
month = local->tm_mon + 1;
|
||||
year = local->tm_year + 1900;
|
||||
day = local->tm_mday;
|
||||
|
||||
// Main loop
|
||||
while ((ch = getch()) != 'q') {
|
||||
int days_in_current_month = days_in_month(month, year);
|
||||
bool redraw = false;
|
||||
|
||||
switch (ch) {
|
||||
case KEY_LEFT:
|
||||
case 'j':
|
||||
if (day > 1) {
|
||||
day--;
|
||||
redraw = true;
|
||||
}
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
case 'k':
|
||||
if (day < days_in_current_month) {
|
||||
day++;
|
||||
redraw = true;
|
||||
}
|
||||
break;
|
||||
case 'a': // 'a' for "Add Event"
|
||||
open_add_event_tui(db); // Pass the database connection here
|
||||
redraw = true;
|
||||
break;
|
||||
case '\n': // Enter key to open the day view
|
||||
draw_day_view(&day, &month, &year);
|
||||
redraw = true;
|
||||
break;
|
||||
case 'h': // 'h' for previous month
|
||||
case KEY_SLEFT: // Left Shift for previous month
|
||||
if (month > 1) {
|
||||
month--;
|
||||
} else {
|
||||
month = 12;
|
||||
year--;
|
||||
}
|
||||
// Adjust the day if it exceeds the number of days in the new month
|
||||
if (day > days_in_month(month, year)) {
|
||||
day = days_in_month(month, year);
|
||||
}
|
||||
redraw = true;
|
||||
break;
|
||||
case 'l': // 'l' for next month
|
||||
case KEY_SRIGHT: // Right Shift for next month
|
||||
if (month < 12) {
|
||||
month++;
|
||||
} else {
|
||||
month = 1;
|
||||
year++;
|
||||
}
|
||||
// Adjust the day if it exceeds the number of days in the new month
|
||||
if (day > days_in_month(month, year)) {
|
||||
day = days_in_month(month, year);
|
||||
}
|
||||
redraw = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
clear();
|
||||
mvprintw(0, 0, "Calendar View - Press 'a' to Add Event");
|
||||
draw_calendar(month, year, day);
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
// Close the SQLite database connection
|
||||
sqlite3_close(db);
|
||||
|
||||
// End ncurses mode
|
||||
endwin();
|
||||
return 0;
|
||||
}
|
||||
48
ncursescalander/src/repeat_tui.c
Normal file
48
ncursescalander/src/repeat_tui.c
Normal file
@@ -0,0 +1,48 @@
|
||||
#include <ncurses.h>
|
||||
#include "repeat_tui.h"
|
||||
|
||||
void open_repeat_tui() {
|
||||
int ch;
|
||||
int cursor_pos = 0;
|
||||
|
||||
while (true) {
|
||||
clear();
|
||||
mvprintw(0, 0, "Repeat Options");
|
||||
|
||||
mvprintw(2, 0, "1. Never");
|
||||
if (cursor_pos == 0) attron(A_REVERSE);
|
||||
mvprintw(2, 10, "Select");
|
||||
if (cursor_pos == 0) attroff(A_REVERSE);
|
||||
|
||||
mvprintw(4, 0, "2. Every Day");
|
||||
if (cursor_pos == 1) attron(A_REVERSE);
|
||||
mvprintw(4, 10, "Select");
|
||||
if (cursor_pos == 1) attroff(A_REVERSE);
|
||||
|
||||
mvprintw(6, 0, "3. Every Week");
|
||||
if (cursor_pos == 2) attron(A_REVERSE);
|
||||
mvprintw(6, 10, "Select");
|
||||
if (cursor_pos == 2) attroff(A_REVERSE);
|
||||
|
||||
mvprintw(8, 0, "4. Every Other Day");
|
||||
if (cursor_pos == 3) attron(A_REVERSE);
|
||||
mvprintw(8, 18, "Select");
|
||||
if (cursor_pos == 3) attroff(A_REVERSE);
|
||||
|
||||
mvprintw(10, 0, "Press 'q' to return");
|
||||
|
||||
refresh();
|
||||
|
||||
ch = getch();
|
||||
if (ch == 'q') break; // Return to the add event TUI
|
||||
if (ch == KEY_DOWN || ch == 'j') {
|
||||
cursor_pos = (cursor_pos + 1) % 4;
|
||||
} else if (ch == KEY_UP || ch == 'k') {
|
||||
cursor_pos = (cursor_pos - 1 + 4) % 4;
|
||||
} else if (ch == '\n') {
|
||||
// Here, you would handle selection logic
|
||||
break; // Return after selection for now
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1
ssh_gui
Submodule
1
ssh_gui
Submodule
Submodule ssh_gui added at ed35ae7f3a
24
terrarium_bk/terrarium/Makefile
Normal file
24
terrarium_bk/terrarium/Makefile
Normal file
@@ -0,0 +1,24 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -std=c11
|
||||
|
||||
# The final executable name
|
||||
TARGET = terrarium
|
||||
|
||||
# Source files
|
||||
SRCS = main.c game.c ascii_plant_data.c
|
||||
|
||||
# Object files
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET) *.o
|
||||
rm -f terrarium_save.dat
|
||||
|
||||
581
terrarium_bk/terrarium/ascii_plant_data.c
Normal file
581
terrarium_bk/terrarium/ascii_plant_data.c
Normal file
@@ -0,0 +1,581 @@
|
||||
/******************************************************************************
|
||||
* ascii_plant_data.c
|
||||
*
|
||||
* Defines 40 unique ASCII plants, each 10 lines of up to 20 chars.
|
||||
*
|
||||
* For demonstration, they’ll all be similar in shape, but each one will have
|
||||
* some small text or symbol changes so that no two are exactly alike.
|
||||
* You can replace these with more distinct art as desired.
|
||||
******************************************************************************/
|
||||
|
||||
#include "ascii_plant_data.h"
|
||||
|
||||
/*
|
||||
* We store all 40 plants’ ASCII lines in a 2D array of strings:
|
||||
* PLANTS[40][10]
|
||||
* where each string is up to 20 chars + null terminator.
|
||||
*
|
||||
* Each plant: 10 lines. Each line up to 20 chars wide.
|
||||
*/
|
||||
|
||||
/*
|
||||
Template shape (10 lines, 20 chars each):
|
||||
" . "
|
||||
" .. # "
|
||||
" . ==+*- . - "
|
||||
" :++*====.# "
|
||||
" ==++-=#*+ "
|
||||
" -%*=-#+#. "
|
||||
" .-+**#. "
|
||||
" .**+#. "
|
||||
" .:=*++ "
|
||||
" :--=. "
|
||||
We’ll introduce slight variations for each plant to ensure uniqueness.
|
||||
*/
|
||||
|
||||
static const char PLANT_ART[40][10][21] = {
|
||||
/* 0: Snake Plant */
|
||||
{
|
||||
" . ",
|
||||
" .. # ",
|
||||
" . ==+*- . - ",
|
||||
" :++*====.# ",
|
||||
" S==++-=#*+ ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. S ",
|
||||
" .**+#. ",
|
||||
" .:=*++ S ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 1: Aloe Vera */
|
||||
{
|
||||
" . ",
|
||||
" .. A ",
|
||||
" . ==+*- . - ",
|
||||
" :++*====.# A ",
|
||||
" ==++-=#*+ ",
|
||||
" A -%*=-#+#. ",
|
||||
" .-+**#. ",
|
||||
" .**+#. A ",
|
||||
" .:=*++ ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 2: Rubber fig */
|
||||
{
|
||||
" (Rubber) ",
|
||||
" .. # ",
|
||||
" R . ==+*- . - ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ R ",
|
||||
" -%*=-#+#. ",
|
||||
" R .-+**#. ",
|
||||
" .**+#. R ",
|
||||
" .:=*++ ",
|
||||
" :--=. R "
|
||||
},
|
||||
/* 3: Maidenhair fern */
|
||||
{
|
||||
" M ",
|
||||
" fern .. # ",
|
||||
" . ==+*- . - ",
|
||||
" :++*====.# M ",
|
||||
" ==++-=#*+ f ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. ",
|
||||
" .**+#. fern ",
|
||||
" .:=*++ M ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 4: Zebra Plant */
|
||||
{
|
||||
" Z e b r a ",
|
||||
" .. Z ",
|
||||
" . ==+*- . - ",
|
||||
" :++*====.# Z ",
|
||||
" Z ==++-=#*+ ",
|
||||
" -%*=-#+#.Z ",
|
||||
" .-+**#. ",
|
||||
" .**+#. ",
|
||||
" Z .:=*++ ",
|
||||
" :--=. Z "
|
||||
},
|
||||
|
||||
/* 5: Jade plant */
|
||||
{
|
||||
" J ",
|
||||
" .. # ",
|
||||
" . ==+*- . - ",
|
||||
" :++*====.# J ",
|
||||
" ==++-=#*+ ",
|
||||
" -%*=-#+#. ",
|
||||
" Jade.-+**#. ",
|
||||
" .**+#. ",
|
||||
" pl. :=*++ ",
|
||||
" :--=. Jade "
|
||||
},
|
||||
/* 6: Yucca */
|
||||
{
|
||||
" Yucca ",
|
||||
" .. Y ",
|
||||
" . ==+*- . - Y ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ Y ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. Y ",
|
||||
" .**+#. ",
|
||||
" .:=*++ Y ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 7: Chain of Hearts */
|
||||
{
|
||||
" Chain <3 Hearts ",
|
||||
" .. # ",
|
||||
" . ==+*- . - <3 ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ <3 ",
|
||||
" <3 -%*=-#+#. ",
|
||||
" .-+**#. ",
|
||||
" .**+#. <3 ",
|
||||
" Chain.:=*++ ",
|
||||
" :--=. Hearts"
|
||||
},
|
||||
/* 8: ZZ plant */
|
||||
{
|
||||
" ZZZ ",
|
||||
" .. # Z ",
|
||||
" . ==+*- . - ",
|
||||
" Z :++*====.# ",
|
||||
" ==++-=#*+ ",
|
||||
" Z -%*=-#+#. ",
|
||||
" .-+**#. Z ",
|
||||
" ZZ .**+#. ",
|
||||
" .:=*++ ",
|
||||
" :--=. ZZ "
|
||||
},
|
||||
/* 9: Moonstones */
|
||||
{
|
||||
" (Moon) ",
|
||||
" .. # ",
|
||||
" . ==+*- . - ",
|
||||
" :++*====.# M ",
|
||||
" ==++-=#*+ ",
|
||||
" oo -%*=-#+#. ",
|
||||
" .-+**#. oo ",
|
||||
" .**+#. ",
|
||||
" stones:=*++ ",
|
||||
" :--=. "
|
||||
},
|
||||
|
||||
/* 10: Chinese Money plant */
|
||||
{
|
||||
" Chinese Money ",
|
||||
" .. # $ ",
|
||||
" . ==+*- . - ",
|
||||
" :++*====.# $ ",
|
||||
" ==++-=#*+ $$ ",
|
||||
" $$ -%*=-#+#. ",
|
||||
" .-+**#. ",
|
||||
" $$ .**+#. ",
|
||||
" .:=*++ $$ ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 11: String of pearls */
|
||||
{
|
||||
" String pearls ",
|
||||
" ... # o o ",
|
||||
" . ==+*- . - o ",
|
||||
" :++*====.# o ",
|
||||
" ==++-=#*+ o ",
|
||||
" -%*=-#+#. o ",
|
||||
" .-+**#. o ",
|
||||
" .**+#. o ",
|
||||
" .:=*++ o ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 12: Air plant */
|
||||
{
|
||||
" Air plant ",
|
||||
" .. # ~ ",
|
||||
" . ==+*- . - ~ ",
|
||||
" :++*====.# ",
|
||||
" A ==++-=#*+ ~ ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. ~ ",
|
||||
" ~ .**+#. ",
|
||||
" .:=*++ ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 13: African milk tree */
|
||||
{
|
||||
" African milk tree ",
|
||||
" AMT .. # ",
|
||||
" . ==+*- . - AMT ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ AMT ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. AMT ",
|
||||
" .**+#. ",
|
||||
" .:=*++ ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 14: pine bonsai */
|
||||
{
|
||||
" pine bonsai ",
|
||||
" .. # ^ ",
|
||||
" . ==+*- . - ^ ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ ^ ",
|
||||
" -%*=-#+#. ",
|
||||
" ^ .-+**#. ",
|
||||
" .**+#. ^ ",
|
||||
" ^ .:=*++ ",
|
||||
" :--=. "
|
||||
},
|
||||
|
||||
/* 15: Lotus */
|
||||
{
|
||||
" Lotus ",
|
||||
" .. # * ",
|
||||
" . ==+*- . - * ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ * ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. ",
|
||||
" * .**+#. ",
|
||||
" .:=*++ * ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 16: Heart fern */
|
||||
{
|
||||
" Heart fern <3 ",
|
||||
" .. # ",
|
||||
" . ==+*- . - <3 ",
|
||||
" :++*====.# <3 ",
|
||||
" ==++-=#*+ ",
|
||||
" <3 -%*=-#+#. ",
|
||||
" .-+**#. <3 ",
|
||||
" .**+#. ",
|
||||
" <3 .:=*++ ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 17: Corkscrew rush */
|
||||
{
|
||||
" Corkscrew rush ~@ ",
|
||||
" .. # ~@ ",
|
||||
" . ==+*- . - ~@ ",
|
||||
" :++*====.# ",
|
||||
" ~@==++-=#*+ ",
|
||||
" -%*=-#+#. ~@ ",
|
||||
" .-+**#. ",
|
||||
" .**+#. ~@ ",
|
||||
" .:=*++ ",
|
||||
" :--=. ~@ "
|
||||
},
|
||||
/* 18: Weeping fig */
|
||||
{
|
||||
" Weeping fig ~ ",
|
||||
" .. # ~ ",
|
||||
" . ==+*- . - ",
|
||||
" ~ :++*====.# ",
|
||||
" ==++-=#*+ ~ ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. ~ ",
|
||||
" .**+#. ",
|
||||
" ~ .:=*++ ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 19: Corkscrew albuca */
|
||||
{
|
||||
" Corkscrew albuca ",
|
||||
" Cka .. # ~@ ",
|
||||
" . ==+*- . - ~@ ",
|
||||
" :++*====.# ",
|
||||
" ~@==++-=#*+ ",
|
||||
" -%*=-#+#. ~@ ",
|
||||
" .-+**#. ",
|
||||
" ~@ .**+#. ",
|
||||
" .:=*++ ",
|
||||
" :--=. ~@ "
|
||||
},
|
||||
|
||||
/* 20: Fiddle leaf fig */
|
||||
{
|
||||
" Fiddle leaf fig F ",
|
||||
" .. # (leaf) ",
|
||||
" ==+*- . - F ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ (leaf) ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. F ",
|
||||
" .**+#. ",
|
||||
" .:=*++ (leaf) ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 21: Mikado */
|
||||
{
|
||||
" Mikado | ",
|
||||
" .. # | ",
|
||||
" . ==+*- . - | ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ | ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. ",
|
||||
" .**+#. | ",
|
||||
" .:=*++ ",
|
||||
" :--=. | "
|
||||
},
|
||||
/* 22: Kebab bush */
|
||||
{
|
||||
" Kebab bush ~o ",
|
||||
" .. # o ",
|
||||
" . ==+*- . - o ",
|
||||
" :++*====.# ~ ",
|
||||
" ~ ==++-=#*+ o ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. ~ o ",
|
||||
" .**+#. ",
|
||||
" o .:=*++ ~ ",
|
||||
" :--=. o "
|
||||
},
|
||||
/* 23: Dwarf Papyrus */
|
||||
{
|
||||
" Dwarf Papyrus ^ ",
|
||||
" .. # ^ ",
|
||||
" . ==+*- . - ^ ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ ^ ",
|
||||
" ^ -%*=-#+#. ",
|
||||
" .-+**#. ^ ",
|
||||
" .**+#. ",
|
||||
" ^ .:=*++ ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 24: Hobbit Crassula */
|
||||
{
|
||||
" Hobbit Crassula (H) ",
|
||||
" .. # ",
|
||||
" . ==+*- . - (H) ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ ",
|
||||
" -%*=-#+#. (H) ",
|
||||
" .-+**#. ",
|
||||
" (H) .**+#. ",
|
||||
" .:=*++ ",
|
||||
" :--=. (H) "
|
||||
},
|
||||
|
||||
/* 25: Bunny ear cactus */
|
||||
{
|
||||
" Bunny ear cactus * ",
|
||||
" .. # (ears) ",
|
||||
" . ==+*- . - * ",
|
||||
" :++*====.# (ears) ",
|
||||
" ==++-=#*+ * ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. (ears) ",
|
||||
" .**+#. * ",
|
||||
" .:=*++ ",
|
||||
" :--=. * "
|
||||
},
|
||||
/* 26: ghost echoversia */
|
||||
{
|
||||
" ghost echoversia # ",
|
||||
" g.. # # ",
|
||||
" . ==+*- . - # ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ # ",
|
||||
" -%*=-#+#. # ",
|
||||
" .-+**#. # ",
|
||||
" .**+#. # ",
|
||||
" .:=*++ # ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 27: chinese lantern */
|
||||
{
|
||||
" chinese lantern ",
|
||||
" .. # (lantern) ",
|
||||
" . ==+*- . - ",
|
||||
" :++*====.# (lamp) ",
|
||||
" ==++-=#*+ ",
|
||||
" -%*=-#+#. (lamp) ",
|
||||
" .-+**#. ",
|
||||
" .**+#. (lantern) ",
|
||||
" .:=*++ ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 28: ginseng ficus */
|
||||
{
|
||||
" ginseng ficus Gf ",
|
||||
" .. # Gf ",
|
||||
" . ==+*- . - Gf ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ ",
|
||||
" -%*=-#+#. Gf ",
|
||||
" .-+**#. ",
|
||||
" .**+#. Gf ",
|
||||
" .:=*++ ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 29: venus flytrap */
|
||||
{
|
||||
" venus flytrap V ",
|
||||
" .. # x ",
|
||||
" . ==+*- . - x ",
|
||||
" :++*====.# ",
|
||||
" V ==++-=#*+ x ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. x ",
|
||||
" V .**+#. ",
|
||||
" .:=*++ ",
|
||||
" :--=. x "
|
||||
},
|
||||
|
||||
/* 30: Flamingo flower */
|
||||
{
|
||||
" Flamingo flower F ",
|
||||
" .. # (fl) ",
|
||||
" . ==+*- . - F ",
|
||||
" :++*====.# ",
|
||||
" (fl)==++-=#*+ F ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. (fl) ",
|
||||
" .**+#. ",
|
||||
" F .:=*++ ",
|
||||
" :--=. (fl) "
|
||||
},
|
||||
/* 31: Japanese maple bonsai */
|
||||
{
|
||||
" Japanese maple bns ",
|
||||
" .. # Jmb ",
|
||||
" . ==+*- . - ",
|
||||
" :++*====.# Jmb ",
|
||||
" ==++-=#*+ ",
|
||||
" -%*=-#+#. ",
|
||||
" Jmb .-+**#. ",
|
||||
" .**+#. ",
|
||||
" .:=*++ Jmb ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 32: Fshbone cactus */
|
||||
{
|
||||
" Fshbone cactus ~^ ",
|
||||
" .. # ~^ ",
|
||||
" . ==+*- . - ~^ ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ ~^ ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. ~^ ",
|
||||
" .**+#. ",
|
||||
" .:=*++ ~^ ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 33: Paddle plant */
|
||||
{
|
||||
" Paddle plant ",
|
||||
" .. # == ",
|
||||
" . ==+*- . - == ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ == ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. ",
|
||||
" == .**+#. ",
|
||||
" .:=*++ == ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 34: Donkey's tail */
|
||||
{
|
||||
" Donkey's tail ~ ",
|
||||
" .. # ~ ",
|
||||
" . ==+*- . - ~ ",
|
||||
" :++*====.# ",
|
||||
" ~ ==++-=#*+ ",
|
||||
" -%*=-#+#. ~ ",
|
||||
" .-+**#. ",
|
||||
" ~ .**+#. ",
|
||||
" .:=*++ ",
|
||||
" :--=. ~ "
|
||||
},
|
||||
|
||||
/* 35: Common ivy */
|
||||
{
|
||||
" Common ivy ivy ",
|
||||
" .. # iv ",
|
||||
" . ==+*- . - iv ",
|
||||
" iv:++*====.# ",
|
||||
" ==++-=#*+ ",
|
||||
" -%*=-#+#. iv ",
|
||||
" .-+**#. ",
|
||||
" .**+#. ",
|
||||
" iv .:=*++ ",
|
||||
" :--=. ivy "
|
||||
},
|
||||
/* 36: Chinese Crassula */
|
||||
{
|
||||
" Chinese Crassula C ",
|
||||
" .. # (Cr) ",
|
||||
" . ==+*- . - (Cr) ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ ",
|
||||
" -%*=-#+#. (Cr) ",
|
||||
" .-+**#. ",
|
||||
" .**+#. (Cr) ",
|
||||
" .:=*++ ",
|
||||
" :--=. (Cr) "
|
||||
},
|
||||
/* 37: Blue Chalksticks */
|
||||
{
|
||||
" Blue Chalksticks B ",
|
||||
" .. # Bc ",
|
||||
" . ==+*- . - Bc ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ Bc ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. Bc ",
|
||||
" .**+#. ",
|
||||
" .:=*++ Bc ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 38: Angel's tears */
|
||||
{
|
||||
" Angel's tears @A ",
|
||||
" .. # tears ",
|
||||
" . ==+*- . - @A ",
|
||||
" :++*====.# ",
|
||||
" ==++-=#*+ ",
|
||||
" -%*=-#+#. @A ",
|
||||
" .-+**#. ",
|
||||
" .**+#. tears ",
|
||||
" .:=*++ @A ",
|
||||
" :--=. "
|
||||
},
|
||||
/* 39: White clover */
|
||||
{
|
||||
" White clover (wc) ",
|
||||
" .. # (wc) ",
|
||||
" . ==+*- . - ",
|
||||
" :++*====.# (wc) ",
|
||||
" ==++-=#*+ ",
|
||||
" -%*=-#+#. ",
|
||||
" .-+**#. (wc) ",
|
||||
" .**+#. ",
|
||||
" .:=*++ (wc)",
|
||||
" :--=. "
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* getPlantArt
|
||||
*
|
||||
* Returns the (line)-th line of ASCII art for plantIndex
|
||||
******************************************************************************/
|
||||
const char* getPlantArt(int plantIndex, int line) {
|
||||
if(plantIndex < 0 || plantIndex >= 40) {
|
||||
/* Safety: return empty string if out of range */
|
||||
return " ";
|
||||
}
|
||||
if(line < 0 || line >= 10) {
|
||||
return " ";
|
||||
}
|
||||
return PLANT_ART[plantIndex][line];
|
||||
}
|
||||
|
||||
14
terrarium_bk/terrarium/ascii_plant_data.h
Normal file
14
terrarium_bk/terrarium/ascii_plant_data.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/******************************************************************************
|
||||
* ascii_plant_data.h
|
||||
*
|
||||
* Exposes function(s) to retrieve the 10-line ASCII art for each of the 40 plants.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef ASCII_PLANT_DATA_H
|
||||
#define ASCII_PLANT_DATA_H
|
||||
|
||||
/* Returns the line-th line (0..9) of ASCII art for plant index (0..39). */
|
||||
const char* getPlantArt(int plantIndex, int line);
|
||||
|
||||
#endif
|
||||
|
||||
BIN
terrarium_bk/terrarium/ascii_plant_data.o
Normal file
BIN
terrarium_bk/terrarium/ascii_plant_data.o
Normal file
Binary file not shown.
259
terrarium_bk/terrarium/game.c
Normal file
259
terrarium_bk/terrarium/game.c
Normal file
@@ -0,0 +1,259 @@
|
||||
/******************************************************************************
|
||||
* game.c
|
||||
*
|
||||
* Implements core game logic: initialization, update, rendering, input, etc.
|
||||
******************************************************************************/
|
||||
/*
|
||||
* game.c - Contains the implementation of the Terrarium game logic
|
||||
*/
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include "game.h"
|
||||
|
||||
/* System / standard headers */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for system() */
|
||||
#include <time.h> /* for clock_gettime, etc. */
|
||||
#include <unistd.h> /* for usleep() */
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <string.h> /* for strncpy() */
|
||||
|
||||
/******************************************************************************
|
||||
* Terminal-handling variables/functions (non-blocking input, etc.)
|
||||
*****************************************************************************/
|
||||
static struct termios old, current;
|
||||
|
||||
/* Initialize new terminal i/o settings */
|
||||
void initTermios(int echo) {
|
||||
tcgetattr(0, &old);
|
||||
current = old;
|
||||
current.c_lflag &= ~ICANON; /* disable buffered i/o */
|
||||
if (echo) {
|
||||
current.c_lflag |= ECHO;
|
||||
} else {
|
||||
current.c_lflag &= ~ECHO;
|
||||
}
|
||||
tcsetattr(0, TCSANOW, ¤t);
|
||||
}
|
||||
|
||||
/* Restore old terminal i/o settings */
|
||||
void resetTermios(void) {
|
||||
tcsetattr(0, TCSANOW, &old);
|
||||
}
|
||||
|
||||
/* Check if a key has been pressed (non-blocking) */
|
||||
int kbhit(void) {
|
||||
struct termios oldt, newt;
|
||||
int ch;
|
||||
int oldf;
|
||||
|
||||
tcgetattr(STDIN_FILENO, &oldt);
|
||||
newt = oldt;
|
||||
newt.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
||||
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
|
||||
|
||||
ch = getchar();
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||
fcntl(STDIN_FILENO, F_SETFL, oldf);
|
||||
|
||||
if(ch != EOF) {
|
||||
ungetc(ch, stdin);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read one character (like getch in Windows) */
|
||||
char getch(void) {
|
||||
return getchar();
|
||||
}
|
||||
|
||||
/* Clear the screen (Unix-like) */
|
||||
void clearScreen(void) {
|
||||
system("clear");
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Elapsed Time (we store the old time in a static variable)
|
||||
*****************************************************************************/
|
||||
double getElapsedTime(void) {
|
||||
static struct timespec lastTime = {0, 0};
|
||||
struct timespec now;
|
||||
|
||||
/* If first call, initialize lastTime */
|
||||
if (lastTime.tv_sec == 0 && lastTime.tv_nsec == 0) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
lastTime = now;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* current time */
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
double elapsed = (now.tv_sec - lastTime.tv_sec) +
|
||||
(now.tv_nsec - lastTime.tv_nsec) / 1000000000.0;
|
||||
lastTime = now;
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Game Logic & Rendering
|
||||
*****************************************************************************/
|
||||
|
||||
/* Forward-declarations (private to this file) */
|
||||
static double calcTotalProduction(const GameState *gs);
|
||||
static void buyPlant(GameState *gs);
|
||||
|
||||
/* initGame: brand-new game (if load fails or for fresh start) */
|
||||
void initGame(GameState *gs) {
|
||||
gs->oxygen = 0.0;
|
||||
gs->plantCost = BASE_PLANT_COST;
|
||||
gs->plantCount = 0;
|
||||
|
||||
/* The 40 plants (names). Adjust as you wish. */
|
||||
const char* plantNames[MAX_PLANTS] = {
|
||||
"Snake Plant", "Aloe Vera", "Rubber fig", "Maidenhair fern", "Zebra Plant",
|
||||
"Jade plant", "Yucca", "Chain of Hearts", "ZZ plant", "Moonstones",
|
||||
"Chinese Money plant", "String of pearls.", "Air plant", "African milk tree",
|
||||
"pine bonsai", "Lotus", "Heart fern", "Corkscrew rush", "Weeping fig", "Corkscrew albuca",
|
||||
"Fiddle leaf fig", "Mikado", "Kebab bush", "Dwarf Papyrus", "Hobbit Crassula",
|
||||
"Bunny ear cactus", "ghost echoversia", "chinese lantern", "ginseng ficus", "venus flytrap",
|
||||
"Flamingo flower", "Japanese maple bonsai", "Fshbone cactus", "Paddle plant",
|
||||
"Donkey's tail", "Common ivy", "Chinese Crassula", "Blue Chalksticks", "Angel's tears", "White clover"
|
||||
};
|
||||
|
||||
for(int i = 0; i < MAX_PLANTS; i++) {
|
||||
strncpy(gs->plants[i].name, plantNames[i], sizeof(gs->plants[i].name) - 1);
|
||||
gs->plants[i].name[sizeof(gs->plants[i].name)-1] = '\0';
|
||||
gs->plants[i].active = 0;
|
||||
gs->plants[i].productionRate = 0.0;
|
||||
}
|
||||
|
||||
/* Start with the first plant active, if desired */
|
||||
gs->plants[0].active = 1;
|
||||
gs->plants[0].productionRate = BASE_OXYGEN_PER_SECOND;
|
||||
gs->plantCount = 1;
|
||||
}
|
||||
|
||||
/* loadGame: tries to read from a file. If it fails, calls initGame(). */
|
||||
void loadGame(GameState *gs) {
|
||||
FILE *f = fopen("terrarium_save.dat", "rb");
|
||||
if(!f) {
|
||||
initGame(gs);
|
||||
return;
|
||||
}
|
||||
if(fread(gs, sizeof(GameState), 1, f) != 1) {
|
||||
fclose(f);
|
||||
initGame(gs);
|
||||
return;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
/* Basic sanity check */
|
||||
if(gs->plantCount < 1) {
|
||||
initGame(gs);
|
||||
}
|
||||
}
|
||||
|
||||
/* saveGame: writes the current game state to a file. */
|
||||
void saveGame(const GameState *gs) {
|
||||
FILE *f = fopen("terrarium_save.dat", "wb");
|
||||
if(!f) return;
|
||||
fwrite(gs, sizeof(GameState), 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/* updateGame: called each loop to add oxygen from production rate. */
|
||||
void updateGame(GameState *gs, double elapsedSeconds) {
|
||||
double totalProd = calcTotalProduction(gs);
|
||||
gs->oxygen += totalProd * elapsedSeconds;
|
||||
}
|
||||
|
||||
/* renderGame: draws shelves + plants in top 3/4, info in bottom 1/4. */
|
||||
void renderGame(const GameState *gs) {
|
||||
clearScreen();
|
||||
|
||||
printf("========================================\n");
|
||||
printf(" T E R R A R I U M \n");
|
||||
printf("========================================\n\n");
|
||||
|
||||
/*
|
||||
* We have 5 shelves (SHELF_COUNT=5).
|
||||
* Each shelf displays 8 plants => total 40 plants (PLANTS_PER_SHELF=8).
|
||||
*/
|
||||
int plantIdx = 0;
|
||||
for(int shelf = 0; shelf < SHELF_COUNT; shelf++) {
|
||||
for(int slot = 0; slot < PLANTS_PER_SHELF; slot++) {
|
||||
if(plantIdx < MAX_PLANTS && gs->plants[plantIdx].active) {
|
||||
/* Print the plant name (20 chars padded, e.g.) */
|
||||
printf("[%2d] %-20s | ", plantIdx+1, gs->plants[plantIdx].name);
|
||||
} else {
|
||||
printf("[ ] %-20s | ", "(empty)");
|
||||
}
|
||||
plantIdx++;
|
||||
}
|
||||
printf("\n--------------------------------------------------------\n");
|
||||
}
|
||||
|
||||
/* BOTTOM 1/4: info, oxygen, etc. */
|
||||
printf("\nOxygen: %.2f O2\n", gs->oxygen);
|
||||
printf("Total Production: %.3f O2/s\n", calcTotalProduction(gs));
|
||||
printf("Next Plant Cost: %.2f O2\n\n", gs->plantCost);
|
||||
|
||||
printf("[SPACE] Tap the first plant for +%.1f O2 (if active)\n", TAP_BONUS_OXYGEN);
|
||||
printf("[b] Buy a new plant\n");
|
||||
printf("[q] Quit\n\n");
|
||||
}
|
||||
|
||||
/* handleInput: user keystrokes (tap or buy, etc.) */
|
||||
void handleInput(GameState *gs, char input) {
|
||||
switch(input) {
|
||||
case ' ':
|
||||
/* Tap only works on the first plant if active */
|
||||
if(gs->plants[0].active) {
|
||||
gs->oxygen += TAP_BONUS_OXYGEN;
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
buyPlant(gs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Internal helper: calculates sum of production rates */
|
||||
static double calcTotalProduction(const GameState *gs) {
|
||||
double total = 0.0;
|
||||
for(int i = 0; i < MAX_PLANTS; i++) {
|
||||
if(gs->plants[i].active) {
|
||||
total += gs->plants[i].productionRate;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/* Internal helper: buy the next plant if we can afford it */
|
||||
static void buyPlant(GameState *gs) {
|
||||
if(gs->plantCount >= MAX_PLANTS) {
|
||||
return; /* can't buy more than 40 */
|
||||
}
|
||||
if(gs->oxygen >= gs->plantCost) {
|
||||
gs->oxygen -= gs->plantCost;
|
||||
/* activate next plant in line */
|
||||
int index = gs->plantCount;
|
||||
gs->plants[index].active = 1;
|
||||
gs->plants[index].productionRate = BASE_OXYGEN_PER_SECOND; /* or custom logic */
|
||||
gs->plantCount++;
|
||||
|
||||
/* Increase cost for next time */
|
||||
gs->plantCost *= COST_MULTIPLIER;
|
||||
}
|
||||
}
|
||||
|
||||
67
terrarium_bk/terrarium/game.h
Normal file
67
terrarium_bk/terrarium/game.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/******************************************************************************
|
||||
* game.h
|
||||
*
|
||||
* Exposes the core game logic and data.
|
||||
******************************************************************************/
|
||||
#ifndef GAME_H
|
||||
#define GAME_H
|
||||
|
||||
/*
|
||||
* This header declares functions/data for the Terrarium game.
|
||||
* Include it from both main.c and game.c.
|
||||
*/
|
||||
|
||||
#define MAX_PLANTS 40
|
||||
#define SHELF_COUNT 5 /* We'll display 5 shelves total */
|
||||
#define PLANTS_PER_SHELF 8 /* 8 plants per shelf => 40 plants total */
|
||||
#define GAME_TICK_INTERVAL_MS 200 /* Loop tick (ms) */
|
||||
|
||||
#define BASE_OXYGEN_PER_SECOND 0.1
|
||||
#define TAP_BONUS_OXYGEN 1.0
|
||||
#define BASE_PLANT_COST 10.0
|
||||
#define COST_MULTIPLIER 1.2
|
||||
|
||||
/*
|
||||
* Data Structures
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char name[64]; /* e.g. "Snake Plant" */
|
||||
int active; /* 1 if purchased/visible, 0 if not */
|
||||
double productionRate; /* O2 per second contributed by this plant */
|
||||
} Plant;
|
||||
|
||||
/* Main Game State container */
|
||||
typedef struct {
|
||||
double oxygen; /* Current total oxygen currency */
|
||||
double plantCost; /* Cost to buy the next plant */
|
||||
Plant plants[MAX_PLANTS]; /* All 40 plants */
|
||||
int plantCount; /* How many plants are active */
|
||||
} GameState;
|
||||
|
||||
/*
|
||||
* Function Prototypes
|
||||
*/
|
||||
|
||||
/* Game lifecycle */
|
||||
void initGame(GameState *gs);
|
||||
void loadGame(GameState *gs);
|
||||
void saveGame(const GameState *gs);
|
||||
|
||||
/* Game logic */
|
||||
void updateGame(GameState *gs, double elapsedSeconds);
|
||||
void renderGame(const GameState *gs);
|
||||
void handleInput(GameState *gs, char input);
|
||||
|
||||
/* Timing: returns elapsed seconds since last call */
|
||||
double getElapsedTime(void);
|
||||
|
||||
/* Terminal / I/O helpers */
|
||||
void initTermios(int echo);
|
||||
void resetTermios(void);
|
||||
int kbhit(void);
|
||||
char getch(void);
|
||||
void clearScreen(void);
|
||||
|
||||
#endif /* GAME_H */
|
||||
|
||||
BIN
terrarium_bk/terrarium/game.o
Normal file
BIN
terrarium_bk/terrarium/game.o
Normal file
Binary file not shown.
57
terrarium_bk/terrarium/main.c
Normal file
57
terrarium_bk/terrarium/main.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* main.c - Entry point of the Terrarium program
|
||||
*/
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for system() */
|
||||
#include <unistd.h> /* for usleep() */
|
||||
|
||||
#include "game.h"
|
||||
|
||||
int main(void) {
|
||||
GameState gs;
|
||||
|
||||
/* Load a previous save or start fresh. */
|
||||
loadGame(&gs);
|
||||
|
||||
/* Setup terminal for non-blocking input, no echo */
|
||||
initTermios(0);
|
||||
|
||||
int running = 1;
|
||||
while (running) {
|
||||
/* Time since the last loop in seconds */
|
||||
double elapsedSeconds = getElapsedTime();
|
||||
|
||||
/* Update game logic (oxygen accumulation, etc.) */
|
||||
updateGame(&gs, elapsedSeconds);
|
||||
|
||||
/* Render the shelves and the info area */
|
||||
renderGame(&gs);
|
||||
|
||||
/* Check user input (non-blocking) */
|
||||
if (kbhit()) {
|
||||
char c = getch();
|
||||
if (c == 'q' || c == 'Q') {
|
||||
running = 0; /* quit */
|
||||
} else {
|
||||
handleInput(&gs, c);
|
||||
}
|
||||
}
|
||||
|
||||
/* Control frame/tick rate (~5 times a second) */
|
||||
usleep(GAME_TICK_INTERVAL_MS * 1000);
|
||||
|
||||
/* Auto-save each loop (optional) */
|
||||
saveGame(&gs);
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
resetTermios();
|
||||
clearScreen();
|
||||
printf("Thanks for playing Terrarium!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BIN
terrarium_bk/terrarium/main.o
Normal file
BIN
terrarium_bk/terrarium/main.o
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user