Nimbin[12]?SDL & Graphics / draw_trad_img / commits / 4afec63

draw_trad_img git · master

Live viewer for streamed trading chart images (SSL client)

c images trading ssl · first commit 2025-03-06 · last commit 2025-03-06 (1 year ago) · synced 3 days ago

C 100%
git clone https://git.christianimmanuel.de/sdl-graphics/draw_trad_img.gitwget https://git.christianimmanuel.de/sdl-graphics/draw_trad_img/archive/draw_trad_img.tar.gz

..

Christian Immanuel · 2025-03-06 00:17 · 4afec632e64226c1e434b05b88a8bd0908baca6f

 view_img.c | 829 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 829 insertions(+)

diff --git a/view_img.c b/view_img.c
new file mode 100644
index 0000000..fd95901
--- /dev/null
+++ b/view_img.c
@@ -0,0 +1,829 @@
+// gcc -o view_image view_img.c -lSDL3 -lSDL3_image -lSDL3_ttf -ljansson
+
+
+
+#include <SDL3/SDL.h>
+#include <SDL3_image/SDL_image.h>
+#include <SDL3_ttf/SDL_ttf.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/stat.h>  // Include this header for 'stat'
+#include <string.h>
+#include <jansson.h>   // For JSON handling
+#include <ctype.h>
+#include <arpa/inet.h>
+#include <endian.h>    // For be64toh() on some systems; on others use <arpa/inet.h> if available.
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+
+
+
+#define SERVER_PORT 9999
+#define SERVER_IP "162.19.227.194"  // Server IP address
+
+#define HEADER_SIZE 8
+#define BUF_SIZE 1024
+
+
+#define CONFIG_FILE "config_draw.json"
+#define MAX_INPUT_LENGTH 256
+
+int window_width = 0, window_height = 0;
+
+int legend_is_active = 1;
+
+int usleep(__useconds_t usec);
+char* strdup(const char*);
+int symlink(const char *target, const char *linkpath);
+uint64_t be64toh(uint64_t big_endian_64bits);
+
+// Global variables (make sure these are defined in one source file)
+
+
+
+#include <time.h>
+#include <pthread.h>
+
+
+pthread_mutex_t request_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+typedef enum {
+    R_TYPE_UNKNOWN = 0,
+    R_TYPE_IMAGE,
+    R_TYPE_CONFIG
+} request_type_t;
+
+typedef enum {
+    R_STAT_UNKNOWN = -1,
+    R_STAT_STOPPED,
+    R_STAT_STARTED,
+    R_STAT_RUNNING,
+    R_STAT_DONE
+} request_status_t;
+
+typedef struct {
+    int success;
+    char message[256];
+    pthread_t thread;
+    request_type_t type;
+    request_status_t status;
+    void *response_value;
+} request_t;
+
+
+
+request_t request_global = {0, "\0", 0, R_TYPE_UNKNOWN, R_STAT_STOPPED, NULL};
+
+int file_exists(const char *path) {
+    struct stat buffer;
+    return (stat(path, &buffer) == 0);
+}
+
+void copy_file(const char *source, const char *destination) {
+    FILE *src = fopen(source, "rb");
+    if (!src) return;
+
+    FILE *dest = fopen(destination, "wb");
+    if (!dest) {
+        fclose(src);
+        return;
+    }
+
+    char buffer[4096];
+    size_t bytes;
+    while ((bytes = fread(buffer, 1, sizeof(buffer), src)) > 0) {
+        fwrite(buffer, 1, bytes, dest);
+    }
+
+    fclose(src);
+    fclose(dest);
+}
+
+void linkConfig(const char *target, const char *linkpath) {
+    // Remove existing symlink or file if it exists
+    if (access(linkpath, F_OK) == 0) {
+        if (unlink(linkpath) == -1) {
+            perror("unlink failed");
+            return;
+        }
+    }
+
+    // Create new symlink
+    if (symlink(target, linkpath) == -1) {
+        perror("symlink failed");
+    } else {
+        printf("Symbolic link created: %s -> %s\n", target, linkpath);
+    }
+}
+
+
+#define IMAGE_DIR "images"  // Directory where images are stored
+
+// Function to find the most recently modified image in the folder
+const char* getLatestImagePath() {
+    DIR *dir = opendir(IMAGE_DIR);
+    if (!dir) {
+        perror("Failed to open directory");
+        return NULL;
+    }
+
+    struct dirent *entry;
+    struct stat file_stat;
+    time_t latest_time = 0;
+    const char *latest_file = NULL;
+
+    while ((entry = readdir(dir)) != NULL) {
+        // Build the full path for the current file
+        char filepath[256];
+        snprintf(filepath, sizeof(filepath), "%s/%s", IMAGE_DIR, entry->d_name);
+
+        // Use stat() to get file information and check if it's a regular file
+        if (stat(filepath, &file_stat) == 0 && S_ISREG(file_stat.st_mode)) {
+            // Check if this file is more recent than the current latest
+            if (file_stat.st_mtime > latest_time) {
+                latest_time = file_stat.st_mtime;
+                latest_file = strdup(filepath);  // Save the latest file path
+            }
+        }
+    }
+    closedir(dir);
+
+    return latest_file;  // Return the path of the most recently modified image
+}
+
+
+void render_text(SDL_Renderer *renderer, TTF_Font *font, const char *text, int x, int y) {
+    if (!font) {  // Check if font is loaded
+        printf("Error: Font not loaded!\n");
+        return;
+    }
+
+    if (!text || *text == '\0') {  // Check if text is empty
+        return;
+    }
+
+    SDL_Color textColor = {0, 0, 0, 255};  // Black text color
+    SDL_Surface *surface = TTF_RenderText_Blended_Wrapped(font, text, strlen(text), textColor, window_width);
+
+    if (!surface) {  // Check if text rendering failed
+        printf("Error: Could not render text! SDL_ttf error: %s\n", SDL_GetError());
+        return;
+    }
+
+    SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
+    if (!texture) {  // Check if texture creation failed
+        printf("Error: Could not create texture! SDL error: %s\n", SDL_GetError());
+        SDL_DestroySurface(surface);
+        return;
+    }
+
+    SDL_FRect dest = {x, y, surface->w, surface->h};
+
+    // Draw white background behind text
+    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
+    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 187);  // White color
+    SDL_RenderFillRect(renderer, &dest);
+
+    // Render text over the white background
+    SDL_RenderTexture(renderer, texture, NULL, &dest);
+
+    SDL_DestroySurface(surface);
+    SDL_DestroyTexture(texture);
+}
+
+
+// Function to check if the file has changed based on modification time
+int file_has_changed(const char *filename, time_t *last_mod_time) {
+    struct stat file_stat;
+    if (stat(filename, &file_stat) == -1) {
+        perror("stat");
+        return 0;
+    }
+    
+    if (file_stat.st_mtime > *last_mod_time) {
+        *last_mod_time = file_stat.st_mtime;
+        return 1;
+    }
+    return 0;
+}
+
+
+
+char *foldJson(char *json_str) {
+    size_t len = strlen(json_str);
+    char *result = malloc(len + 1); // worst-case: no newlines removed
+    if (!result) return NULL;
+
+    int array_nesting = 0;
+    int in_string = 0;      // Are we inside a string literal?
+    int escape = 0;         // Is the previous char a backslash?
+    size_t out_index = 0;
+
+    int inside_first_object = 0;
+
+    for (size_t i = 0; i < len; i++) {
+        char c = json_str[i];
+
+        // Handle string literal boundaries and escapes.
+        if (in_string) {
+            result[out_index++] = c;
+            if (escape) {
+                escape = 0;
+            } else if (c == '\\') {
+                escape = 1;
+            } else if (c == '"') {
+                in_string = 0;
+            }
+            continue;
+        } else {
+            if (c == '"') {
+                in_string = 1;
+                result[out_index++] = c;
+                continue;
+            }
+        }
+
+        if (!inside_first_object && c == '{') {
+            inside_first_object = 1;
+            continue;
+        }
+
+        // Update array nesting outside of strings.
+        if (c == '[' || c == '{') {
+            array_nesting++;
+            result[out_index++] = c;
+            continue;
+        } else if (c == ']' || c == '}') {
+            if (array_nesting > 0)
+                array_nesting--;
+            result[out_index++] = c;
+            continue;
+        }
+
+        if (array_nesting > 0 && result[out_index-1] == ',' && result[out_index-2] == '}' ) {
+            result[out_index++] = '\n';
+            for (int i = 0; i < 8; i++)
+                result[out_index++] = ' ';
+            continue;
+        }
+        // If we are inside an array and encounter a newline or carriage return...
+        if ((c == '\n' || c == '\r' || c == ' ' ) && array_nesting > 0) {
+            // Option: replace newline with a single space (if not already a space)
+            if (out_index > 0 && result[out_index - 1] != ' ')
+                result[out_index++] = ' ';
+            // Otherwise, simply skip the newline character.
+            continue;
+        }
+
+        // Otherwise, just copy the character.
+        result[out_index++] = c;
+    }
+
+    result[out_index] = '\0';
+    return result;
+}
+
+
+void receiveImage(uint64_t img_size, int sockfd) {
+    size_t total_received = 0;
+    unsigned char *img_data = malloc(img_size);
+    if (!img_data) {
+        perror("malloc failed");
+        return;
+    }
+
+    char buffer[BUF_SIZE];
+
+    while (total_received < img_size) {
+        ssize_t len = recvfrom(sockfd, buffer, BUF_SIZE, 0, NULL, NULL);
+        if (len < 0) {
+            if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                fprintf(stderr, "Timeout waiting for image data.\n");
+                continue;  // Retry instead of returning immediately
+            } else {
+                perror("recvfrom failed");
+                free(img_data);  // Prevent memory leak
+                return;
+            }
+        }
+        if (len == 0) {
+            fprintf(stderr, "Unexpected connection closure\n");
+            free(img_data);
+            return;
+        }
+
+        size_t bytes_to_copy = (total_received + len > img_size)
+                               ? (img_size - total_received)
+                               : len;
+        memcpy(img_data + total_received, buffer, bytes_to_copy);
+        total_received += bytes_to_copy;
+    }
+
+    if (total_received != img_size) {
+        fprintf(stderr, "Incomplete image received: expected %llu, got %zu bytes\n",
+                (unsigned long long)img_size, total_received);
+        free(img_data);
+        return;
+    }
+
+    printf("Received complete image (%zu bytes)\n", total_received);
+
+
+    // --- Create an SDL_Surface from the Received Data ---
+    SDL_IOStream *rw = SDL_IOFromMem(img_data, total_received);
+    if (rw) {
+        SDL_Surface *new_surface = IMG_Load_IO(rw, true);
+        if (new_surface) {
+            pthread_mutex_lock(&request_mutex);
+                request_global.success = 1;
+                request_global.response_value = (void*)new_surface;
+            pthread_mutex_unlock(&request_mutex);
+        } else {
+            printf("IMG_Load_RW failed: %s\n", SDL_GetError());
+        }
+    } else {
+        printf("SDL_RWFromMem failed: %s\n", SDL_GetError());
+    }
+
+    free(img_data);
+}
+
+void receiveConfig(uint64_t config_size, int sockfd) {
+    // Allocate buffer and receive full config
+    printf("receiveConfig() START\n");
+    char *config_data = malloc(config_size + 1);
+    if (!config_data) {
+        perror("malloc failed");
+        return;
+    }
+
+    size_t total_received = 0;
+    while (total_received < config_size) {
+        ssize_t chunk = recvfrom(sockfd, config_data + total_received,
+                                 config_size - total_received, 0, NULL, NULL);
+        if (chunk <= 0) {
+            perror("recvfrom failed");
+            free(config_data);
+            return;
+        }
+        total_received += chunk;
+    }
+    config_data[total_received] = '\0';  // Null-terminate JSON string
+
+    // Parse JSON
+    printf("Received JSON string:\n%s\n", config_data);
+
+    json_t *root;
+    json_error_t error;
+    root = json_loads(config_data, 0, &error);
+    free(config_data);  // Free buffer after parsing
+
+    if (!root) {
+        fprintf(stderr, "JSON parse error: %s\n", error.text);
+        return;
+    }
+
+    pthread_mutex_lock(&request_mutex);
+        request_global.success = 1;
+        request_global.response_value = (void*)root;
+    pthread_mutex_unlock(&request_mutex);
+
+
+    // Example: Extract values
+    const char *symbol = json_string_value(json_object_get(root, "symbol"));
+    const char *interval = json_string_value(json_object_get(root, "interval"));
+    printf("Config Received:\n  Symbol: %s\n  Interval: %s\n",
+           symbol ? symbol : "NULL", interval ? interval : "NULL");
+
+    printf("receiveConfig() END\n");
+}
+
+
+
+
+// This is the thread function that sends the UDP request and receives the response.
+void* apiThread_func(void* arg) {
+    // For demonstration, we print the request and type.
+    // In your real code, this function will do the UDP sendto/recvfrom logic.
+    // Send a UDP request for an updated image.
+    printf("Request Api\n");
+    char request[256] = "\0";
+    pthread_mutex_lock(&request_mutex);
+        strcpy(request, (const char*)request_global.message);
+        request_global.success = 0;
+        request_global.status = R_STAT_RUNNING;
+    pthread_mutex_unlock(&request_mutex);
+
+    printf("API thread started with request: %s\n", request);
+
+    // --- Begin UDP request/response logic ---
+    // Example: send request, wait for header, then process the response.
+    // (Replace the following sleep with your actual UDP code.)
+
+
+    // Setup UDP socket once for the thread.
+    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sockfd < 0) {
+        perror("Socket creation failed");
+        return NULL;
+    }
+
+    // Set a timeout on recvfrom calls (e.g., 2 seconds).
+    struct timeval tv;
+    tv.tv_sec = 6;
+    tv.tv_usec = 0;
+    if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+        perror("Error setting socket timeout");
+    }
+
+    struct sockaddr_in server_addr;
+    memset(&server_addr, 0, sizeof(server_addr));
+    server_addr.sin_family = AF_INET;
+    server_addr.sin_port = htons(SERVER_PORT);
+    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
+
+
+    char trys = 0;
+    while (1) { // This loop shal never run twice actually... troll its for breaking -> GOTO
+        trys++;
+        if (strlen(request) == 0) break;;
+        printf("(%3d)Request string -> %s\n", trys, request);
+
+        ssize_t s = sendto(sockfd, request, strlen(request), 0,  // ✅ Fix: Use strlen()
+                   (struct sockaddr *)&server_addr, sizeof(server_addr));
+
+        if (s < 0) {
+            perror("sendto failed");
+            usleep(100 * 1000);  // 100ms delay befor sending it again
+            continue;
+        }
+
+        unsigned char header[12] = {0};
+        ssize_t header_len = recvfrom(sockfd, header, sizeof(header), 0, NULL, NULL);
+        if (header_len < 12) {
+            usleep(100 * 1000);  // 100ms delay befor sending it again
+            fprintf(stderr, "Header not received properly. Received %zd bytes.\n", header_len);
+            break;
+        }
+
+        // Parse the type (first 4 bytes)
+        char type[5] = {0};
+        memcpy(type, header, 4);
+        uint64_t expected_size;
+        memcpy(&expected_size, header + 4, 8);
+        expected_size = be64toh(expected_size);
+
+        if (strncmp(type, "IMG ", 4) == 0) {
+            // It's an image. Now extract the size from the next 8 bytes.
+            printf("Receiving image of size: %llu bytes\n", (unsigned long long)expected_size);
+            receiveImage(expected_size, sockfd);
+        } else if (strncmp(type, "CONF", 4) == 0) {
+            // It's a config update.
+            // char config_data[1024] = {0};
+            printf("Receiving Config\n");
+            receiveConfig(expected_size, sockfd);
+        } else {
+            printf("Unknown message type: %s\n", type);
+        }
+
+        printf("Request data received.\n");
+
+
+        break; // never run twice!
+    }
+    close(sockfd);
+    // --- End UDP request/response logic ---
+
+
+    pthread_mutex_lock(&request_mutex);
+        request_global.status = R_STAT_DONE;
+    pthread_mutex_unlock(&request_mutex);
+    return NULL;
+}
+
+// Call this function to start a new API thread if one is not already running.
+void startApiThread(const char *req_api) {
+    // Assume that the global request_api and request_type are updated elsewhere.
+    request_status_t status = R_STAT_UNKNOWN;
+    pthread_mutex_lock(&request_mutex);
+        if (!strcmp(req_api, "image"))
+            request_global.type = R_TYPE_IMAGE; 
+        else
+            request_global.type = R_TYPE_CONFIG; 
+        strcpy(request_global.message, req_api);
+        status = request_global.status;
+        request_global.status = R_STAT_STARTED;
+    pthread_mutex_unlock(&request_mutex);
+    if (status > 0) return; // Already running
+    if (pthread_create(&request_global.thread, NULL, apiThread_func, NULL) != 0) {
+        perror("pthread_create failed");
+    }
+}
+
+// Call this function in your main loop to check if the API thread has finished.
+// If it has, join it and return 1; otherwise return 0.
+int prooveAndFinishAbiThread() {
+    request_status_t done = R_STAT_UNKNOWN;
+    pthread_t thread;
+    pthread_mutex_lock(&request_mutex);
+        done = request_global.status;
+        thread = request_global.thread;
+    pthread_mutex_unlock(&request_mutex);
+
+    if (done != R_STAT_DONE)
+        return 0; // Still Running
+
+    // The thread has finished; join it to clean up resources.
+    if (pthread_join(thread, NULL) != 0) {
+        perror("Proove finished but pthread_join failed");
+    }
+
+    pthread_mutex_lock(&request_mutex);
+        request_global.status = R_STAT_STOPPED;
+    pthread_mutex_unlock(&request_mutex);
+    return 1; // ALL DONE
+}
+
+
+int getConfInt(json_t* config, char k[]) {
+    json_t* json_value = json_object_get(config, k);
+    if (json_value && json_is_integer(json_value)) {
+        return json_integer_value(json_value);
+    } else {
+        char* s = json_dumps(config, JSON_INDENT(4));
+        fprintf(stderr, "%s", s);
+        free(s);
+        printf("Error: '%s' not found or not an integer!\n", k);
+    }
+    return 0;
+}
+
+int main() {
+    SDL_Surface* surface = NULL;
+    json_t* config = NULL;
+
+    startApiThread("legend_is_active 1");
+
+    printf("Loading Config.");
+    while (!config) {
+        printf(".");
+        if (prooveAndFinishAbiThread()) {
+            pthread_mutex_lock(&request_mutex);
+                config = (json_t*)request_global.response_value;
+            pthread_mutex_unlock(&request_mutex);
+            printf("Config loaded!\n");
+        }
+        sleep(1);
+    }
+    printf("\n");
+
+
+
+    // Initialize SDL
+    if (!SDL_Init(SDL_INIT_VIDEO)) {
+        fprintf(stderr, "SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
+        json_decref(config);
+        return 1;
+    }
+
+    /*
+    // Initialize SDL_image
+    if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) {
+        fprintf(stderr, "SDL_image could not initialize! IMG_Error: %s\n", IMG_GetError());
+        SDL_Quit();
+        json_decref(config);
+        return 1;
+    }
+    */
+
+    if (!TTF_Init()) {
+        fprintf(stderr, "TTF_Init could not initialize! TTF_Error: %s\n", SDL_GetError());
+        SDL_Quit();
+        return 1;
+    }
+
+    // Get image dimensions
+    int img_width = 1200;
+    int img_height = 680;
+
+    // Create window with the SDL_WINDOW_RESIZABLE flag for resizable window
+    SDL_Window *window = SDL_CreateWindow("render_graph", img_width, img_height, SDL_WINDOW_RESIZABLE);
+    if (!window) {
+        fprintf(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError());
+        SDL_DestroySurface(surface);
+        SDL_Quit();
+        json_decref(config);
+        return 1;
+    }
+
+    // Create renderer
+    SDL_Renderer *renderer = SDL_CreateRenderer(window, NULL);
+    if (!renderer) {
+        fprintf(stderr, "Renderer could not be created! SDL_Error: %s\n", SDL_GetError());
+        SDL_DestroyWindow(window);
+        SDL_DestroySurface(surface);
+        SDL_Quit();
+        json_decref(config);
+        return 1;
+    }
+
+
+    TTF_Font *font = TTF_OpenFont("/usr/share/fonts/dejavu/DejaVuSans-Bold.ttf", 24);
+
+    SDL_Texture *texture;
+
+    int quit = 0;
+    char input_text[MAX_INPUT_LENGTH] = "";
+    SDL_Event e;
+
+    SDL_StartTextInput(window);
+
+    float mouseX, mouseY;
+
+    char new_request[256] = "\0";
+
+    // Main loop
+    while (!quit) {
+        int render_position = getConfInt(config, "render_position");
+        int limit = getConfInt(config, "limit");
+        int candles = getConfInt(config, "candles");
+
+
+        // Handle events
+        while (SDL_PollEvent(&e)) {
+            if (e.type == SDL_EVENT_QUIT) {
+                quit = 1;
+            } else if (e.type == SDL_EVENT_TEXT_INPUT) {
+                if (strlen(input_text) + strlen(e.text.text) < MAX_INPUT_LENGTH) {
+                    printf("TextInput %s\n", input_text);
+                    strcat(input_text, e.text.text);
+                }
+            } else if (e.type == SDL_EVENT_KEY_DOWN && strlen(input_text) > 0) {
+                switch (e.key.key) {
+                    case SDLK_LEFT: {
+                        int n = (render_position + candles/8 < limit - candles) ? render_position + candles/8 : render_position;
+                        if (!strlen(new_request))
+                            sprintf(new_request, "render_position %d", n);
+                    }
+                    case SDLK_RIGHT: {
+                        int n = (render_position - candles/8 >= 0) ? render_position - candles/8 : 0;
+                        if (!strlen(new_request))
+                            sprintf(new_request, "render_position %d", n);
+                    }
+                    case SDLK_UP: {
+                        int n = (candles - candles/8 > candles/8) ? candles - candles/8 : candles;
+                        if (!strlen(new_request))
+                            sprintf(new_request, "candles %d", n);
+                    }
+                    case SDLK_DOWN: {
+                        int n = (candles + candles/8 <= limit) ? candles + candles/8 : candles;
+                        if (!strlen(new_request))
+                            sprintf(new_request, "candles %d", n);
+                    }
+                    case SDLK_BACKSPACE: {
+                        input_text[strlen(input_text) - 1] = '\0';
+                        break;
+                    }
+                    case SDLK_RETURN: {
+                        if (strcmp(input_text, "m") == 0) {
+                            legend_is_active = !legend_is_active;
+                            snprintf(input_text, sizeof(input_text), "legend_is_active %d", legend_is_active);
+                        }
+                        if (!strlen(new_request))
+                            strcpy(new_request, input_text);
+                        input_text[0] = '\0';
+                    }
+                    default:
+                        break;
+                }
+#undef COPY_TO_REQUEST
+            }
+        }
+
+        request_t request_copy;
+        pthread_mutex_lock(&request_mutex);
+            request_copy = request_global;
+        pthread_mutex_unlock(&request_mutex);
+        switch (request_copy.status) {
+            case R_STAT_STOPPED: {
+                char request[256];
+                if (!request_copy.success)
+                    strcpy(request, request_copy.message);
+                else if (new_request[0] != '\0') {
+                    strcpy(request, new_request);
+                    new_request[0] = '\0'; 
+                } else {
+                    strcpy(request, "image");
+                }
+
+                startApiThread(request);
+                break; }
+            case R_STAT_DONE: {
+                if (prooveAndFinishAbiThread()) {
+                    if (request_copy.success) {
+                        switch (request_copy.type) {
+                            case R_TYPE_IMAGE: {
+                                printf("''''NEW IMAGE!\n");
+                                SDL_Surface* surface_new = (SDL_Surface*)request_copy.response_value;
+                                SDL_DestroySurface(surface);
+                                surface = SDL_ConvertSurface(surface_new, surface_new->format);
+                                SDL_DestroySurface(surface_new);
+                                break; }
+                            case R_TYPE_CONFIG: {
+                                printf("''''NEW CONFIG!\n");
+                                json_t* config_new = (json_t*)request_copy.response_value;
+                                json_decref(config);
+                                config = json_copy(config_new);
+                                json_decref(config_new);
+                                continue; }
+                            default: break;
+                        }
+                    }
+                }
+                break; }
+            default: break;
+
+        }
+
+
+
+
+
+        if (!surface) continue;
+
+        img_width = surface->w;
+        img_height = surface->h;
+
+        SDL_DestroyTexture(texture);
+        texture = SDL_CreateTextureFromSurface(renderer, surface);
+        if (!texture) {
+            fprintf(stderr, "Unable to create texture! SDL_Error: %s\n", SDL_GetError());
+        }
+
+
+
+
+        // Get current window size
+        SDL_GetWindowSize(window, &window_width, &window_height);
+
+        // Create a scaling factor for the image based on the window size
+        float scale_x = (float)window_width / img_width;
+        float scale_y = (float)window_height / img_height;
+        float scale = (scale_x < scale_y) ? scale_x : scale_y;  // Use the smallest scale factor to fit the image
+
+        // Adjust the image size based on the scale factor
+        int new_width = img_width * scale;
+        int new_height = img_height * scale;
+
+        // Clear screen and render the texture scaled to fit the window
+        SDL_RenderClear(renderer);
+        SDL_FRect dest_rect = { 0, 0, new_width, new_height };
+        SDL_RenderTexture(renderer, texture, NULL, &dest_rect);
+
+        // Text rendern
+        if (strlen(input_text) > 0) {
+            render_text(renderer, font, input_text, 20, 40);
+            // Handle user input to update config
+            char* console_text = input_text;
+            char* console_text_ = json_dumps(config, JSON_INDENT(4));
+            // printf("%s", console_text_); return 1;
+            console_text  = foldJson(console_text_);
+            free(console_text_);
+
+            render_text(renderer, font, console_text, 20, 60);
+            render_text(renderer, font, input_text, 20, 40);
+            // Reset renderer state before drawing mouse pattern
+            SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
+            SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);  // Example: set draw color to black
+        }
+
+
+        // Draw X as a dotted pattern
+        SDL_GetMouseState(&mouseX, &mouseY);
+        for (int i = -img_width; i <= img_width; i += 4) {
+            SDL_RenderPoint(renderer, mouseX + i, mouseY - 10);  // Draw main diagonal
+            SDL_RenderPoint(renderer, mouseX - 8, mouseY - i);  // Draw anti-diagonal
+        }
+
+
+        SDL_RenderPresent(renderer);
+
+        // Delay to avoid overloading the CPU
+        SDL_Delay(16);
+    }
+
+    // Clean up
+    TTF_CloseFont(font);
+    SDL_DestroyTexture(texture);
+    SDL_DestroyRenderer(renderer);
+    SDL_DestroyWindow(window);
+    TTF_Quit();
+    SDL_Quit();
+    json_decref(config);
+    return 0;
+}