/* Copyright (c) 2026 Arslaan Pathan This software is licensed under the ARPL. See LICENSE for details. */ #include #include /* forward declare BEFORE including config.h so that config.h can reference them */ typedef struct { GtkWidget *window; GtkWidget *notebook; GtkWidget *cmdbar; } Cinnamon; typedef struct { const char* key; void (*fptr)(Cinnamon*, void* arg); void* arg; } Keybind; typedef struct { const char* name; void (*fptr)(Cinnamon*, const char *args); } Command; #include "config.h" /* 0 = normal mode, 1 = insert, 2 = passthrough */ int mode = 0; bool cmdbar_focused = false; static void parse_keybind(const char *key, guint *keyval, GdkModifierType *mods) { char name[32]; const char *start; const char *end; *mods = 0; if (key[0] != '<') { *keyval = gdk_keyval_from_name(key); return; } if (strstr(key, "S-")) *mods |= GDK_SHIFT_MASK; if (strstr(key, "C-")) *mods |= GDK_CONTROL_MASK; if (strstr(key, "A-")) *mods |= GDK_MOD1_MASK; /* everything after the last '-' and before '>' */ start = strrchr(key, '-') + 1; end = strchr(key, '>'); snprintf(name, sizeof(name), "%.*s", (int)(end - start), start); *keyval = gdk_keyval_from_name(name); } static void on_title_changed(WebKitWebView *webview, GParamSpec *pspec, GtkNotebook *notebook) { const char *title = webkit_web_view_get_title(webview); int page = gtk_notebook_page_num(notebook, GTK_WIDGET(webview)); gtk_notebook_set_tab_label_text(notebook, GTK_WIDGET(webview), title ? title : "New Tab"); } static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) { Cinnamon* cinnamon = (Cinnamon*)data; if (mode == 1 || mode == 2) { if (mode == 1 && event->keyval == GDK_KEY_Escape) { mode = 0; if (cmdbar_focused) { gtk_widget_hide(cinnamon->cmdbar); cmdbar_focused = false; } } } else { if (event->keyval == GDK_KEY_colon) { gtk_widget_show(cinnamon->cmdbar); gtk_widget_grab_focus(cinnamon->cmdbar); cmdbar_focused = true; mode = 1; return TRUE; } for (int i = 0; i < sizeof(keybinds) / sizeof(keybinds[0]); i++) { guint keyval; GdkModifierType mods; parse_keybind(keybinds[i].key, &keyval, &mods); GdkModifierType relevant = GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK; if (gdk_keyval_to_lower(event->keyval) == keyval && (event->state & relevant) == mods) { /* we dont know what to do yet, printf */ keybinds[i].fptr(cinnamon, keybinds[i].arg); return TRUE; } } #ifdef NO_SEND_UNBOUND_KEYBINDS /* make sure that outside of insert/passthrough, we still don't send unbound keybinds to the webview */ return TRUE; #endif } /* event not consumed pass to webview */ return FALSE; } void tabopen(Cinnamon* cinnamon) { GtkWidget *webview = webkit_web_view_new(); gtk_notebook_append_page(GTK_NOTEBOOK(cinnamon->notebook), webview, gtk_label_new("New Tab")); g_signal_connect(webview, "notify::title", G_CALLBACK(on_title_changed), cinnamon->notebook); /* HOMEPAGE defined in config.h */ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), HOMEPAGE); gtk_widget_show_all(cinnamon->notebook); gtk_notebook_set_current_page(GTK_NOTEBOOK(cinnamon->notebook), -1); } void tabclose(Cinnamon* cinnamon) { int page = gtk_notebook_get_current_page(GTK_NOTEBOOK(cinnamon->notebook)); /* dont close last tab */ if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(cinnamon->notebook)) > 1) { gtk_notebook_remove_page(GTK_NOTEBOOK(cinnamon->notebook), page); } else { #ifdef NO_QUIT_ON_CLOSE_LAST_TAB tabopen(cinnamon); gtk_notebook_remove_page(GTK_NOTEBOOK(cinnamon->notebook), page); return; #endif gtk_main_quit(); } } int main(int argc, char *argv[]) { #ifndef CINNAMON_ENABLED return 1; #endif gtk_init(&argc, &argv); Cinnamon cinnamon = {0}; /* Create a new window and set default size */ cinnamon.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); /* Size constants defined in config.h */ gtk_window_set_default_size(GTK_WINDOW(cinnamon.window), WINDOW_WIDTH, WINDOW_HEIGHT); g_signal_connect(cinnamon.window, "destroy", G_CALLBACK(gtk_main_quit), NULL); /* Create a vertical GtkBox for layout stuff */ GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_container_add(GTK_CONTAINER(cinnamon.window), vbox); cinnamon.notebook = gtk_notebook_new(); // gtk_container_add(GTK_CONTAINER(cinnamon.window), cinnamon.notebook); gtk_box_pack_start(GTK_BOX(vbox), cinnamon.notebook, TRUE, TRUE, 0); /* Create initial tab */ tabopen(&cinnamon); /* Create cmdbar */ /* im sleepy so just add a placeholder commented-out pack for future reference */ cinnamon.cmdbar = gtk_entry_new(); gtk_box_pack_end(GTK_BOX(vbox), cinnamon.cmdbar, FALSE, FALSE, 0); /* handle keypresses */ g_signal_connect(cinnamon.window, "key-press-event", G_CALLBACK(on_key_press), &cinnamon); gtk_widget_show_all(cinnamon.window); gtk_widget_hide(cinnamon.cmdbar); gtk_main(); return 0; }