// Compile with: // g++ gtk_lurk_reader.cpp `pkg-config gtk+-3.0 --cflags --libs` -o gtk_lurk_reader // gtk 3.0 needs to be installed, including the -dev packages #include #include #include #include #include #include #include #include #include #include struct version { uint8_t mtype; uint8_t major, minor; uint16_t elen; } __attribute__((packed)); struct game_header { uint8_t mtype; uint16_t initial_points, stat_limit, dlen; } __attribute__((packed)); GtkWidget *hostname_view, *port_view, *output_view; GtkTextBuffer *hostname_buffer, *port_buffer, *output_buffer; GtkWidget *grid; int skt; void read_from_lurk_server(); // Remember to null-terminate text first! void add_text(const char *text, int textlen = -1){ GtkTextIter start, end; gtk_text_buffer_get_bounds(output_buffer, &start, &end); gtk_text_buffer_insert (output_buffer, &end, text, textlen); } char* get_text_of_textbuffer(GtkTextBuffer *buffer) { GtkTextIter start, end; gchar *text; gtk_text_buffer_get_bounds(buffer, &start, &end); text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); return text; } void activate (GtkApplication *app, gpointer user_data){ GtkWidget *window; GtkWidget *button; /* create a new window, and set its title */ window = gtk_application_window_new (app); gtk_window_set_title ((GtkWindow*)window, "GTKLurkReader"); 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 ("Connect"); g_signal_connect (button, "clicked", G_CALLBACK (read_from_lurk_server), NULL); /* Place the first button in the grid cell (0, 6), and make it fill * just 1 cell horizontally and vertically (ie no spanning) */ gtk_grid_attach (GTK_GRID (grid), button, 3, 0, 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, 4, 0, 1, 1); hostname_view = gtk_text_view_new(); port_view = gtk_text_view_new(); output_view = gtk_text_view_new(); hostname_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (hostname_view)); port_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (port_view)); output_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (output_view)); gtk_grid_attach(GTK_GRID(grid), hostname_view, 1, 0, 1, 1); gtk_grid_attach(GTK_GRID(grid), port_view, 2, 0, 1, 1); gtk_grid_attach(GTK_GRID(grid), output_view, 1, 1, 4, 1); gtk_widget_set_hexpand(hostname_view, TRUE); gtk_widget_set_hexpand(port_view, TRUE); gtk_widget_set_hexpand(output_view, TRUE); gtk_widget_set_vexpand(output_view, TRUE); /* 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); } void read_from_lurk_server(){ static char output_buffer[1024]; struct sockaddr_in sad; sad.sin_port = htons(atoi(get_text_of_textbuffer(port_buffer))); sad.sin_family = AF_INET; struct hostent* entry = gethostbyname(get_text_of_textbuffer(hostname_buffer)); 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; sprintf(output_buffer, "Connecting to: %s\n", ip_string); add_text(output_buffer); skt = socket(AF_INET, SOCK_STREAM, 0); if(skt == -1) goto err; if(connect(skt, (struct sockaddr*)&sad, sizeof(struct sockaddr_in))) goto err; printf("We connected\n"); struct version v; struct game_header gh; uint8_t type; if(1 != recv(skt, &type, 1, MSG_PEEK)) goto protocol_error; if(type == 14){ if(sizeof(v) != recv(skt, &v, sizeof(v), MSG_WAITALL)) goto protocol_error; if(v.elen) recv(skt, output_buffer, v.elen, MSG_WAITALL); // should check this too sprintf(output_buffer, "Server version is %d.%d\n", v.major, v.minor); add_text(output_buffer); if(1 != recv(skt, &type, 1, MSG_PEEK)) goto protocol_error; } if(type == 11){ if(sizeof(gh) != recv(skt, &gh, sizeof(gh), MSG_WAITALL)) goto protocol_error; char description[gh.dlen]; if(gh.dlen != recv(skt, description, gh.dlen, MSG_WAITALL)) goto protocol_error; sprintf(output_buffer, "IP: %d, Stat Limit: %d, Description Length: %d\n", gh.initial_points, gh.stat_limit, gh.dlen); add_text(output_buffer); add_text(description, gh.dlen); add_text("\n------------------------------\n"); } close(skt); return; protocol_error: close(skt); add_text("Server did not follow the protocol\n"); return; err: add_text("Couldn't connect\n"); } int main(int argc, char ** argv){ 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); printf("GUI is done now, exit status was %d\n", status); g_object_unref (app); return 0; }