summaryrefslogtreecommitdiff
path: root/gtk.c
diff options
context:
space:
mode:
authorxengineering <me@xengineering.eu>2022-08-14 16:07:34 +0200
committerxengineering <me@xengineering.eu>2022-08-15 19:01:15 +0200
commit21a2b2033485c106a537e5e2302f4e4d96a66b94 (patch)
tree8457f0057596540eb193fcb3410d07071160aca3 /gtk.c
parent2acca5d84a318f6c8858acb8ee7eca7e59369160 (diff)
downloadlimox-21a2b2033485c106a537e5e2302f4e4d96a66b94.tar
limox-21a2b2033485c106a537e5e2302f4e4d96a66b94.tar.zst
limox-21a2b2033485c106a537e5e2302f4e4d96a66b94.zip
Implement XMPP connect / disconnect
Diffstat (limited to 'gtk.c')
-rw-r--r--gtk.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/gtk.c b/gtk.c
new file mode 100644
index 0000000..3139cbb
--- /dev/null
+++ b/gtk.c
@@ -0,0 +1,265 @@
+
+
+#include <gtk/gtk.h>
+#include <stdio.h>
+
+#include "limox.h"
+
+
+struct chat {
+ GtkWidget* roster_item; // the button in the roster list
+ GtkWidget* chat_layout_box; // the layout box of the chat page
+ GtkWidget* chat_content_box; // the content box of the chat page
+ GtkWidget* text_entry; // where new messages are typed
+ struct chat* next; // entry to support the linked list
+};
+
+
+// linked list of chats
+static struct chat* chats = NULL;
+
+// the GTK application is available as global variable
+static GtkApplication* app;
+
+// all GTK widgets are accessible in this file via global variables
+static GtkWidget* window;
+static GtkWidget* stack;
+
+// connector page
+static GtkStackPage* connector_page;
+static GtkWidget* connector_box;
+static GtkWidget* connector_jid_label;
+static GtkWidget* connector_jid_entry;
+static GtkWidget* connector_pwd_label;
+static GtkWidget* connector_pwd_entry;
+static GtkWidget* connector_button;
+
+// roster page
+static GtkStackPage* roster_page;
+static GtkWidget* roster_layout_box;
+static GtkWidget* roster_scrolled;
+static GtkWidget* roster_content_box;
+static GtkWidget* roster_button;
+
+
+static void quit_cb(void) {
+ limox_quit();
+ g_application_quit(G_APPLICATION(app));
+}
+
+static void connect_cb(void) {
+
+ const char* jid_text = gtk_editable_get_text(GTK_EDITABLE(connector_jid_entry));
+ const char* pwd_text = gtk_editable_get_text(GTK_EDITABLE(connector_pwd_entry));
+
+ gtk_stack_set_visible_child(GTK_STACK(stack), roster_layout_box);
+
+ // just dummy output
+ printf("Connecting with:\nJID: %s\nPWD: %s\n", jid_text, pwd_text);
+
+ limox_connect(jid_text, pwd_text);
+}
+
+static void disconnect_cb(void) {
+
+ gtk_stack_set_visible_child(GTK_STACK(stack), connector_box);
+
+ // just dummy output
+ printf("Disconnected!\n");
+
+ limox_disconnect();
+}
+
+static void to_chat(GtkWidget* layout_box) {
+ gtk_stack_set_visible_child(GTK_STACK(stack), layout_box);
+}
+
+static void to_roster(void) {
+ gtk_stack_set_visible_child(GTK_STACK(stack), roster_layout_box);
+}
+
+void send_message(struct chat* chat) {
+
+ // get recipient and message text
+ const char* recipient = gtk_button_get_label(GTK_BUTTON(chat->roster_item));
+ const char* text = gtk_editable_get_text(GTK_EDITABLE(chat->text_entry));
+
+ // execute dummy XMPP send TODO
+ printf("Sending to %s:\n> %s\n", recipient, text);
+
+ // add message content to the chat
+ GtkWidget* message = gtk_label_new(text);
+ gtk_box_append(GTK_BOX(chat->chat_content_box), message);
+
+ // clear text input
+ GtkEntryBuffer* empty_buffer = gtk_entry_buffer_new("", 0);
+ gtk_entry_set_buffer(GTK_ENTRY(chat->text_entry), empty_buffer);
+}
+
+void add_chat(char* jid) {
+
+ // create chat struct and initialize
+ struct chat* chat = malloc(sizeof(struct chat));
+ chat->roster_item = gtk_button_new_with_label(jid);
+ chat->chat_layout_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 20);
+ chat->chat_content_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
+ chat->text_entry = gtk_entry_new();
+ chat->next = NULL;
+
+ // add chat page to stack
+ gtk_stack_add_child(GTK_STACK(stack), chat->chat_layout_box);
+
+ // add a button to go back to roster
+ GtkWidget* back = gtk_button_new_with_label("back");
+ gtk_box_append(GTK_BOX(chat->chat_layout_box), back);
+ g_signal_connect_swapped(back, "clicked", G_CALLBACK(to_roster), NULL);
+
+ // add a scrolled window to chat page
+ GtkWidget* scrolled = gtk_scrolled_window_new();
+ gtk_widget_set_vexpand(scrolled, TRUE);
+ gtk_box_append(GTK_BOX(chat->chat_layout_box), scrolled);
+ gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolled),
+ chat->chat_content_box);
+
+ // add text entry and send button to chat page
+ gtk_box_append(GTK_BOX(chat->chat_layout_box), chat->text_entry);
+ GtkWidget* send_button = gtk_button_new_with_label("send");
+ gtk_box_append(GTK_BOX(chat->chat_layout_box), send_button);
+ g_signal_connect_swapped(send_button, "clicked", G_CALLBACK(send_message),
+ chat);
+
+ // add chat to roster list
+ gtk_box_append(GTK_BOX(roster_content_box), chat->roster_item);
+ g_signal_connect_swapped(chat->roster_item, "clicked", G_CALLBACK(to_chat),
+ chat->chat_layout_box);
+
+ // append chat to linked list of chats
+ struct chat* current = chats;
+ while (true) {
+ if (current == NULL) {
+ chats = chat;
+ break;
+ } else if (current->next == NULL) {
+ current->next = chat;
+ break;
+ } else {
+ current = current->next;
+ }
+ }
+
+}
+
+void add_incoming_text_message(char* sender_jid, char* content) {
+
+ // do not add message if list of chats is empty
+ if (chats == NULL) {
+ return;
+ }
+
+ // find chat with corresponding JID
+ struct chat* chat = chats;
+ while (true) {
+ const char* jid = gtk_button_get_label(GTK_BUTTON(chat->roster_item));
+ if (strcmp(jid, sender_jid) == 0) {
+ break; // this seems to be the correct chat
+ } else if (chat->next == NULL) {
+ return; // no matching chat found - cannot add message
+ } else {
+ chat = chat->next; // go to next chat in linked list
+ }
+ }
+
+ // add given message content to the chat
+ GtkWidget* message = gtk_label_new(content);
+ gtk_box_append(GTK_BOX(chat->chat_content_box), message);
+
+}
+
+static void build_static_widgets(void) {
+
+ // main window with stack
+ window = gtk_window_new();
+ gtk_window_set_title(GTK_WINDOW(window), "LimoX");
+ gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
+ stack = gtk_stack_new();
+ gtk_window_set_child(GTK_WINDOW(window), stack);
+
+ // connector page
+ connector_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 20);
+ connector_page = gtk_stack_add_child(GTK_STACK(stack), connector_box);
+ connector_jid_label = gtk_label_new("XMPP address (JID)");
+ gtk_box_append(GTK_BOX(connector_box), connector_jid_label);
+ connector_jid_entry = gtk_entry_new();
+ gtk_box_append(GTK_BOX(connector_box), connector_jid_entry);
+ connector_pwd_label = gtk_label_new("Password");
+ gtk_box_append(GTK_BOX(connector_box), connector_pwd_label);
+ connector_pwd_entry = gtk_password_entry_new();
+ gtk_box_append(GTK_BOX(connector_box), connector_pwd_entry);
+ connector_button = gtk_button_new_with_label("Connect");
+ gtk_box_append(GTK_BOX(connector_box), connector_button);
+
+ // roster page
+ roster_layout_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 20);
+ roster_page = gtk_stack_add_child(GTK_STACK(stack), roster_layout_box);
+ roster_button = gtk_button_new_with_label("Disconnect");
+ gtk_box_append(GTK_BOX(roster_layout_box), roster_button);
+ roster_scrolled = gtk_scrolled_window_new();
+ gtk_widget_set_vexpand(roster_scrolled, TRUE);
+ roster_content_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
+ gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(roster_scrolled),
+ roster_content_box);
+ gtk_box_append(GTK_BOX(roster_layout_box), roster_scrolled);
+
+ // TODO remove this
+ // add dummy roster items
+ for (int i=0; i<10; i++) {
+ // char buffer[50];
+ char* buffer = malloc(50*sizeof(char));
+ sprintf(buffer, "contact-%d@example.com", i+1);
+ add_chat(buffer);
+ }
+
+ // TODO just for debugging
+ for (int i=0; i<20; i++) {
+ add_incoming_text_message("contact-2@example.com", "Just a test.");
+ // message = gtk_label_new("Test message");
+ // gtk_box_append(GTK_BOX(chat->chat_content_box), message);
+ }
+
+}
+
+static void activate(void) {
+
+ build_static_widgets();
+
+ // configure widgets
+ gtk_window_set_application(GTK_WINDOW(window), app);
+ g_signal_connect_swapped(window, "close-request", G_CALLBACK(quit_cb), app);
+ g_signal_connect_swapped(
+ connector_button, "clicked", G_CALLBACK(connect_cb), NULL);
+ g_signal_connect_swapped(
+ roster_button, "clicked", G_CALLBACK(disconnect_cb), NULL);
+
+ gtk_widget_show(window);
+}
+
+static void idle_cb(void) {
+
+ limox_run_once();
+
+}
+
+void gui_run(void) {
+
+#ifdef GTK_SRCDIR
+ g_chdir(GTK_SRCDIR);
+#endif
+
+ app = gtk_application_new("eu.xengineering.limox", G_APPLICATION_FLAGS_NONE);
+ g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
+ g_idle_add(G_SOURCE_FUNC(idle_cb), NULL);
+
+ g_application_run(G_APPLICATION(app), 0, NULL);
+ g_object_unref(app);
+
+}