#include #include #include #include #include #include #include #include #include #include #include "chatlib.h" GtkWidget *entry_view, *chatlog_view; GtkTextBuffer *entry_buffer, *chatlog_buffer; int skt; GtkWidget *grid; char username[32] = ""; // This is NOT in the GUI thread! // That means we can have a race condition // GTK has thread safety, but not when used this way void* listen_for_updates(void* arg){ int length = 0; char buffer[1024*64]; char next_message[1024*64]; char done = 1; GtkTextIter end; gtk_text_buffer_get_iter_at_offset(chatlog_buffer, &end, 0); for(;;){ printf("Start of receive loop\n"); // while(!done) // usleep(100); printf("Starting to read message\n"); read_message(skt, buffer, 1024*64); if(buffer[0] == TEXT){ char *sender = buffer+1; uint16_t *size = (uint16_t*)(buffer+33); char *message = buffer+35; buffer[35+*size] = 0; snprintf(next_message, 1024*64, "%s (%u bytes): %s\n", sender, *size, message); puts(next_message); } else if(buffer[0] == USER){ // Notify that whatever user it is joined } else if(buffer[0] == LEFT){ // Notify that whoever it is just left } else if(buffer[0] == NAMETAKEN){ // We need a new name! } else if(buffer[0] == PM) { snprintf(next_message, 1024*64, "PM from %s (%u bytes): %s\n", buffer+35, *(uint16_t*)(buffer+1), buffer+67); puts(next_message); } printf("Read message, buffer[0] == %d\n", buffer[0]); int add_text(gpointer data){ chatlog_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chatlog_view)); gtk_text_buffer_insert(chatlog_buffer, &end, next_message, -1); done = 1; return 0; } done = 0; gdk_threads_add_idle(add_text, 0); // gtk_grid_attach(GTK_GRID(grid), chatlog_view, 0, 7, 6, 3); printf("Succeeded in grid attach\n"); } } char* get_text_of_textview(GtkWidget *text_view) { GtkTextIter start, end; GtkTextBuffer *buffer = gtk_text_view_get_buffer((GtkTextView *)text_view); gchar *text; gtk_text_buffer_get_bounds(buffer, &start, &end); text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); return text; } static void smcallback (GtkWidget *widget, gpointer data) { char* the_text = get_text_of_textview(entry_view); g_print ("Sending Addition:\n"); g_print (the_text); g_print ("\n\n"); if(username[0] == 0){ char user = USER; strncpy(username, the_text, 32); write(skt, &user, 1); write(skt, username, 32); } else { int textlen = strlen(the_text); send_message(skt, username, the_text); } } static void activate (GtkApplication *app, gpointer user_data){ GtkWidget *window; GtkWidget *button; printf("We're here\n"); /* create a new window, and set its title */ window = gtk_application_window_new (app); gtk_window_set_title (GTK_WINDOW (window), "gChatClient"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); /* Here we construct the container that is going pack our buttons */ grid = gtk_grid_new (); /* Pack the container in the window */ gtk_container_add (GTK_CONTAINER (window), grid); button = gtk_button_new_with_label ("Send Message"); g_signal_connect (button, "clicked", G_CALLBACK (smcallback), NULL); /* Place the first button in the grid cell (0, 0), and make it fill * just 1 cell horizontally and vertically (ie no spanning) */ gtk_grid_attach (GTK_GRID (grid), button, 0, 6, 1, 1); button = gtk_button_new_with_label ("Quit"); g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window); /* Place the Quit button in the grid cell (0, 1), and make it * span 2 columns. */ gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 2, 1); entry_view = gtk_text_view_new (); entry_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry_view)); gtk_text_buffer_set_text (entry_buffer, "Write your chat message here", -1); gtk_grid_attach(GTK_GRID(grid), entry_view, 0, 2, 6, 3); chatlog_view = gtk_text_view_new (); chatlog_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chatlog_view)); gtk_widget_set_hexpand(chatlog_view, TRUE); gtk_widget_set_vexpand(chatlog_view, TRUE); gtk_text_buffer_set_text (chatlog_buffer, "Chat log:", -1); gtk_grid_attach(GTK_GRID(grid), chatlog_view, 0, 7, 6, 3); /* Now you might put the view in a container and display it on the * screen; when the user edits the text, signals on the buffer * will be emitted, such as "changed", "insert_text", and so on. */ /* Now that we are done packing our widgets, we show them all * in one go, by calling gtk_widget_show_all() on the window. * This call recursively calls gtk_widget_show() on all widgets * that are contained in the window, directly or indirectly. */ gtk_widget_show_all (window); pthread_t T; pthread_create(&T, 0, listen_for_updates, 0); } int main(int argc, char ** argv){ struct sockaddr_in sad; sad.sin_port = htons(atoi(argv[2])); sad.sin_family = AF_INET; skt = socket(AF_INET, SOCK_STREAM, 0); struct hostent* entry = gethostbyname(argv[1]); struct in_addr **addr_list = (struct in_addr**)entry->h_addr_list; struct in_addr* c_addr = addr_list[0]; char* ip_string = inet_ntoa(*c_addr); sad.sin_addr = *c_addr; printf("Connecting to: %s\n", ip_string); connect(skt, (struct sockaddr*)&sad, sizeof(struct sockaddr_in)); GtkApplication *app; int status; printf("About to start the GUI\n"); app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE); g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); printf("Calling g_application_run\n"); status = g_application_run (G_APPLICATION (app), 0, 0); g_object_unref (app); close(skt); return status; }