#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>

#define MAX_TODO 100

typedef struct Todo{
	char text[200];
	int completed;
} Todo;

extern Todo todos[MAX_TODO];
extern int todoCount;

static GtkWidget *time_label;
static GtkWidget *cpu_label;
static GtkWidget *weather_label;

static GtkWidget *memo_view;
static GtkWidget *todo_entry;
static GtkWidget *todo_list;
static GtkWidget *status_label;

static void update_time(void);
static gboolean update_cpu(gpointer data);
static void update_todo_list(void);
static void show_status(const char *message);

static void on_add_todo(GtkButton *button, gpointer data);
static void on_complete_todo(GtkButton *button, gpointer data);
static void on_save_memo(GtkButton *button, gpointer data);
static void on_load_memo(GtkButton *button, gpointer data);

static gboolean update_time_timer(gpointerdata){
	(void)data;
	
	update_time();
	
	return G_SOURCE_CONTINUE;
}

static void show_status(const char *message){
	gtk_label_set_text(GTK_LABEL(status_label), message);
}

static void update_time(void){
	time_t now = time(NULL);
	struct tm *local = localtime(&now);
	char buffer[128];
	
	if(local == NULL){
		gtk_label_set_text(
			GTK_LABEL(time_label),
			"시간을 가져올 수 없습니다."
		);
		return; 
	}
	
	snprintf(
		buffer, sizeof(buffer),
		"%04d-%02d-%02d %02d:%02d:%02d", 
		local->tm_year + 1900, 
		local->tm_mon + 1, 
		local->tm_mday, 
		local->tm_hour, 
		local->tm_min, 
		local->tm_sec
	);
	
	gtk_label_set_text(GTK_LABAL(time_label), buffer);
}

static void update_todo_list(void){
	Gtk_widget *child;
	
	while((child = gtk_widget_get_first_child(todo_list)) != 
	NULL) {
		gtk_list_box_remove(GTK_LIST_BOX(todo_list), child);
	}
	for(int i=0; i<todoCOUNT; i++){
		char text[300];
		
		snprintf(
			text, sizeof(text), 
			"%s %s", 
			todos[i].completed ? "[완료]" : "[미완료]", 
			todos[i].text
		);
		
		GtkWidget *label = gtk_label_new(text);
		
		gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
		gtk_Widget_set_margin_start(label, 8);
		gtk_Widget_set_margin_end(label, 8);
		gtk_Widget_set_margin_top(label, 6);
		gtk_Widget_set_margin_bottom(label, 6);
		
		gtk_list_box_append(GTK_LIST_BOX(todo_list), label);
	}
}

static void on_add_todo(GtkButton *button, gpointer data){
	const char *text;
	
	(void)button;
	(void)data;
	
	text = gtk_editable_get_text(
		GTK_EDITABLE(todo_entry)
	);
	
	if(text[0] == '\0'){
		show_status("할 일을 입력해 주세요.");
		return;
	}
	
	if(todoCount >= MAX_TODO){
		show_status("Todo 목록이 가득 찼습니다.");
		return;
	}
	
	snprintf(
		todos[todoCount].text, 
		sizeof(todos[todoCount].text), 
		"%s", text
	);
	
	todos[todoCount].completed = 0;
	todoCount++;
	
	gtk_editable_set_text(
		GTK_EDITABLE(todo_entry), ""
	);
	
	update_todo_list();
	show_status("Todo를 추가했습니다."); 
}

static void on_complete_todo(
	GtkButton *button, 
	gpointer data
){
	GtkListBoxRow *row;
	int index;
	
	(void)button;
	(void)data;
	
	row = gtk_list_box_get_selected_row(
		GTK_LIST_BOX(todo_list)
	);
	
	if(row == NULL){
		show_status("완료할 Todo를 먼저 선택하세요.");
		return;
	}
	
	index = gtk_list_box_row_get_index(row);
	
	if(index < 0 || index >= todoCount) {
		show_status("잘못된 Todo입니다.");
		return;
	}
	
	todos[index].completed = 1;
	
	update_todo_list();
	show_status("Todo를 완료했습니다.");
}

static void on_save_memo(
	GtkButton *button, 
	gpointer data
){
	GtkTextBuffer *buffer;
	GtkTextIter start, end;
	char *text;
	FILE *fp;
	
	(void)button;
	(void)data;
	
	buffer = gtk_text_view_get_butter(
		GTK_TEXT_VIEW(memo_view)
	);
	
	gtk_text_buffer_get_bounds(buffer, &start, &end);
	
	text = gtk_text_buffer_get_text(
		buffer, &start, &end, FALSE
	);
	
	fp = fopen("memo.text", "w");
	
	if(fp == NULL){
		show_status("메모 파일을 저장할 수 없습니다.");
		g_free(text);
		return;
	}
	
	if(fputs(text, fp) == EOF){
		fclose(fp);
		show_status("메모 저장에 실패했습니다.");
		g_free(text);
		return;
	}
	
	fclose(fp);
	g_free(text);
	
	show_status("메모를 저장했습니다.");
}

static void on_load_memo(
	GtkButton *button, 
	gpointer data
){
	FILE *fp;
	char buffer[1024];
	GtkTextBuffer *text_buffer;
	
	(void)button;
	(void)data;
	
	fp = fopen("memo.txt", "r");
	
	if(fp == NULL){
		show_status("저장된 메모가 없습니다.");
		retunr;
	}
	
	text_buffer = gtk_text_view_gtkget_buffer(
		GTK_TEXT_VIEW(memo_view)
	);
	
	gtk_text_buffer_set_text(text_buffer "", 0);
	
	while(fgets(buffer, sizeof(buffer), fp) != NULL){
		GtkTextIter end;
		
		gtk_text_buffer_get_end_iter(text_buffer, &end);
		
		gtk_text_buffer_insert(
			text_buffer, &end, 
			buffer, -1
		);
	}
	
	fclose(fp);
	
	show_status("메모를 불러왔습니다.");
}

static GtkWidget *create_section_title(const char *text){
	GtkWidget *label = gtk_label_new(text);
	
	gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
	gtk_widget_add_css_class(label, "heading");
	
	return label;
}

static void activate(
	GtkApplication *app, 
	gpointer user_data
){
	GtkWidget *window;
	GtkWidget *root;
	GtkWidget *grid;
	
	GtkWidget *time_box;
	GtkWidget *system_box;
	GtkWidget *todo_box;
	GtkWidget *memo_box;
	
	GtkWidget *todo_buttons;
	GtkWidget *memo_buttons;
	GtkWidget *scrolled;
	GtkWidget *button;
	
	(void)user_data;
	
	window = gtk_application_window_new(app);
	
	gtk_window_set_title(
		GTK_WINDOW(window), "PC Dashboard"
	);
	
	gtk_window_set_default_size(
		GRK_WINDOW(window), 850, 600
	);
	
	root = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
	
	gtk_widget_set_margin_top(root, 18);
	gtk_widget_set_margin_bottom(root, 18);
	gtk_widget_set_margin_start(root, 18);
	gtk_widget_set_margin_end(root, 18);
	
	gtk_widget_set_child(GTK_WINDOW(window), root);
	
	GtkWidget *title = gtk_label_new("PC Dashboard");
	
	gtk_widget_add_css_class(title, "title-1");
	gtk_label_set_xalign(GTK_LABEL(title), 0.0f);
	
	gtk_box_append(GTK_BOX(root), title);
	
	grid = gtk_grid_new();
	
	gtk_grid_set_row_spacing(GTK_GRID(grid), 8);
	gtk_grid_set_column_spacing(GTK_GRID(grid), 24);
	
	gtk_box_append(GTK_BOX(root), grid);
	
	time_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
	system = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
	
	gtk_grid_attach(GTK_GRID(grid), time_box, 0, 0, 1, 1);
	gtk_grid_attach(GTK_GRID(grid), system_box, 1, 0, 1, 1);
	
	gtk_box_append(
		GTK_BOX(time_box),
		create_section_title("현재 시간")
	);
	
	time_label = gtk_label_new("");
	gtk_label_set_xalign(GTK_LABEL(time_label), 0.0f);
	gtk_box_append(GTK_BOX(time_box), time_label);
	
	gtk_box_append(
		GTK_BOX(system_box), 
		create_section_title("CPU 사용률")
	);
	
	cpu_label = gtk_label_new("측정중...");
	gtk_label_set_xalign(GTK_LABEL(cpu_label), 0.0f);
	gtk_box_append(GTK_BOX(system_box), cpu_label);
	
	weather_label = gtk_label_new(
		"서울ㆍ맑음ㆍ22℃습도 45%\n"
		"테스트 데이터"
	);
	
	gtk_label_set_xalign(GTK_LABEL(weather_label), 0.0f);
	
	gtk_box_append(
		GTK_BOX(system_box), weather_label
	);
	
	grid = gtk_grid_new();
	
	gtk_grid_set_row_spacing(GTK_GRID(grid), 16);
	gtk_grid_set_column_spacing(GTK_GRID(grid), 20);
	
	gtk_widget_set_vexpand(grid, TRUE);
	gtk_box_append(GTK_BOX(root), grid);
	
	todo_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
	
	gtk_widget_set_hexpand(todo_box, TRUE);
	gtk_widget_set_vexpand(todo_box, TRUE);
	
	gtk_grid_attach(GTK_GRID(grid), todo_box, 0, 0, 1, 1);
	
	gtk_box_append(
		GTK_BOX(todo_box), 
		create_section_title("Todo List")
	);
	
	todo_entry = gtk_entry_new();
	
	gtk_entry_set_placeholder_text(
		GTK_ENTRY(todo_entry), "할 일을 입력하세요"
	);
	
	gtk_box_append(GTK_BOX(todo_box), todo_entry);
	
	button = gtk_button_new_with_label("Todo 추가");
	
	g_signal_connect(
		button, "clicked", 
		G_CALLBACK(on_add_todo), NULL
	);
	
	gtk_box_append(GTK_BOX(todo_box), button);
	
	scrolled = gtk_scrolled_window_new();
	
	gtk_widget_set_vewpand(scrolled, TRUE);
	
	todo_list = gtk_list_box_new();
	
	gtk_list_box_set_selection_mode(
		GTK_LIST_BOX(todo_list), 
		GTK_SELECTION_SINGLE
	);
	
	gtk_scrolled_window_set_child(
		GTK_SCROLLED_WINDOW(scrolled), todo_list
	);
	
	gtk_box_append(GTK_BOX(todo_box), scrolled);
	
	button = gtk_button_new_with_label("선택한 Todo완료");
	
	g_signal_connect(
		button, "clicked", 
		G_CALLBACK(on_complete_todo), NULL
	);
	
	gtk_box_append(GTK_BOX(todo_box), button);
	
	memo_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
	
	gtk_widget_set_hexpand(memo_box, TRUE);
	gtk_widget_set_vexpand(memo_box, TRUE);
	
	gtk_grid_attach(GTK_GRID(grid), memo_box, 1, 0, 1, 1);
	
	scrolled = gtk_scrolled_window_new();//
	
	gtk_widget_set_vexpand(scrolled, TRUE);

	memo_view = gtk_text_view_new();
	
	gtk_text_view_set_wrap_mode(
		GTK_TEXT_VIEW(memo_view),
		GTK_WRAP_WORD_CHAR
	);
	
	gtk_scrolled_window_set_child(
		GTK_SCROLLED_WINDOW(scrolled), memo_view
	);
	
	gtk_box_append(GTK_BOX(memo_box), scrolled);
	
	memo_buttons = gtk_box_new(GTK_ORIENTATION_HRIZONTAL, 8);
	
	gtk_box_append(GTK_BOX(memo_box), memo_buttons);
	
	button = gtk_button_new_with_label("메모 저장");
	
	g_signal_connect(
		button, "clicked", 
		G_CALLBACK(on_save_memo), NULL
	);
	
	gtk_box_append(GTK_BOX(memo_buttons), button);
	
	button = gtk_button_new_with_label("메모 불러오기");
	
	g_signal_conect(
		button, "clicked",
		G_CALLBACK(on_load_memo), NULL
	);
	
	gtk_box_append(GTK_BOX(memo_buttons), button);
	
	status_label = gtk_label_new("준비되었습니다.");
	
	gtk_label_set_xalign(GTK_LABEL(status_label), 0.0f);
	
	gtk_box_append(GTK_BOX(root), status_label);
	
	update_time();
	update_todo_list();
	
	g_timeout_add_seconds(1, update_timer, NULL);
	//g_timeout_add_seconds(1, update_cpu, NULL);
	
	gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char**argv){
	GTKApplication *app;
	int status;
	
	app = gtk_application_new(
		"com.example.pcdashboard",
		G_APPLICATION_DEFAULT_FLAGC
	);
	
	g_signal_connect(
		app, "activate", 
		G_CALLBACK(activate), NULL
	);
	
	status = g_application_run(
		G_APPLICATION(app), argc, argv
	);
	
	g_object_unref(app);
	
	return status;
}

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: