$ git clone http://tcclient.ion.nu/tc_client.git
commit f2797b5fc657fd6ea86ea58bb39e84e30db6d0bc
Author: Alicia <...>
Date:   Sun Oct 16 02:02:29 2016 +0200

    tc_client-gtk: moved some GUI code into gui.c, including all of the GUI initialization.

diff --git a/ChangeLog b/ChangeLog
index d12ad88..2917482 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -28,6 +28,7 @@ tc_client-gtk: fixed some warnings found with G_DEBUG="fatal-criticals".
 tc_client-gtk: quit if the captcha window is closed.
 tc_client-gtk: make scrolling with page up and page down work even if focus is on the input field.
 tc_client-gtk: bugfix: close the camera device when cancelling cam selection.
+tc_client-gtk: moved some GUI code into gui.c, including all of the GUI initialization.
 tc_client-gtk and camviewer: updated to libavcodec's avcodec_{send,receive}_{frame,packet} API.
 camviewer: removed the old, buggy audio code.
 libcamera: added support for a virtual X11 camera.
diff --git a/Makefile b/Makefile
index 9eee982..9e769f1 100644
--- a/Makefile
+++ b/Makefile
@@ -146,7 +146,7 @@ SOURCES+=utilities/irchack/irchack.c
 SOURCES+=utilities/modbot/modbot.c utilities/modbot/queue.c utilities/modbot/queue.h utilities/modbot/commands.html
 SOURCES+=utilities/camviewer/camviewer.c
 SOURCES+=utilities/cursedchat/cursedchat.c utilities/cursedchat/buffer.c utilities/cursedchat/buffer.h
-SOURCES+=utilities/gtk/camviewer.c utilities/gtk/userlist.c utilities/gtk/media.c utilities/gtk/compat.c utilities/gtk/config.c utilities/gtk/gui.c utilities/gtk/logging.c utilities/gtk/postproc.c utilities/gtk/inputhistory.c utilities/gtk/userlist.h utilities/gtk/media.h utilities/gtk/compat.h utilities/gtk/config.h utilities/gtk/gui.h utilities/gtk/logging.h utilities/gtk/postproc.h utilities/gtk/inputhistory.h gtkgui.glade
+SOURCES+=utilities/gtk/camviewer.c utilities/gtk/userlist.c utilities/gtk/media.c utilities/gtk/compat.c utilities/gtk/config.c utilities/gtk/gui.c utilities/gtk/logging.c utilities/gtk/postproc.c utilities/gtk/inputhistory.c utilities/gtk/main.h utilities/gtk/userlist.h utilities/gtk/media.h utilities/gtk/compat.h utilities/gtk/config.h utilities/gtk/gui.h utilities/gtk/logging.h utilities/gtk/postproc.h utilities/gtk/inputhistory.h gtkgui.glade
 SOURCES+=utilities/gtk/gencamplaceholder.sh utilities/gtk/camplaceholder.xcf utilities/gtk/spinnerdot.xcf
 SOURCES+=utilities/compat.c utilities/compat.h utilities/list.c utilities/list.h utilities/stringutils.c utilities/stringutils.h utilities/compat_av.c utilities/compat_av.h
 SOURCES+=utilities/libcamera/camera.c utilities/libcamera/camera.h utilities/libcamera/camera_v4l2.c utilities/libcamera/camera_v4l2.h utilities/libcamera/camera_img.c utilities/libcamera/camera_img.h utilities/libcamera/camera_escapi.cpp utilities/libcamera/camera_escapi.h utilities/libcamera/camera_x11.c utilities/libcamera/camera_x11.h
diff --git a/utilities/gtk/camviewer.c b/utilities/gtk/camviewer.c
index 06d4bd0..ea78538 100644
--- a/utilities/gtk/camviewer.c
+++ b/utilities/gtk/camviewer.c
@@ -57,6 +57,7 @@
 #include "../compat.h"
 #include "../compat_av.h"
 #include "inputhistory.h"
+#include "main.h"
 
 struct viddata
 {
@@ -72,7 +73,6 @@ const char* channel=0;
 const char* mycolor=0;
 char* nickname=0;
 char frombuild=0; // Running from the build directory
-struct chatview* mainchat;
 #define TC_CLIENT (frombuild?"./tc_client":"tc_client")
 #ifdef _WIN32
   PROCESS_INFORMATION coreprocess={.hProcess=0};
@@ -139,21 +139,9 @@ void printchat(const char* text, const char* color, unsigned int offset, const c
   chatview_autoscroll(chatview);
 }
 
-void togglecam_cancel(void)
-{
-  GtkCheckMenuItem* item=GTK_CHECK_MENU_ITEM(gtk_builder_get_object(gui, "menuitem_broadcast_camera"));
-  gtk_check_menu_item_set_active(item, 0);
-}
-
-void stopbroadcasting(GtkMenuItem* x, void* y)
-{
-  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(gui, "menuitem_broadcast_camera")), 0);
-  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(gui, "menuitem_broadcast_mic")), 0);
-}
-
 unsigned int cameventsource=0;
 char buf[1024];
-gboolean handledata(GIOChannel* iochannel, GIOCondition condition, gpointer datap)
+gboolean handledata(GIOChannel* iochannel, GIOCondition condition, gpointer x)
 {
   gsize r;
   unsigned int i;
@@ -665,48 +653,8 @@ void togglemic(GtkCheckMenuItem* item, void* x)
   g_io_channel_set_encoding(channel, 0, 0);
   eventsource=g_io_add_watch(channel, G_IO_IN, mic_encode, 0);
 }
-
-gboolean mic_pushtotalk(GtkWidget* button, GdkEvent* event, void* pushed)
-{
-  pushtotalk_pushed=!!pushed;
-  return 0;
-}
 #endif
 
-gboolean handleresize(GtkWidget* widget, GdkEventConfigure* event, struct viddata* data)
-{
-  if(event->width!=gtk_widget_get_allocated_width(cambox))
-  {
-    updatescaling(event->width, 0, 0);
-  }
-  // Fix scrolling
-  chatview_autoscroll(mainchat);
-  unsigned int i;
-  for(i=0; i<usercount; ++i)
-  {
-    if(userlist[i].pm_chatview)
-    {
-      chatview_autoscroll(userlist[i].pm_chatview);
-    }
-  }
-  return 0;
-}
-
-void handleresizepane(GObject* obj, GParamSpec* spec, struct viddata* data)
-{
-  updatescaling(0, gtk_paned_get_position(GTK_PANED(obj)), 0);
-  // Fix scrolling
-  chatview_autoscroll(mainchat);
-  unsigned int i;
-  for(i=0; i<usercount; ++i)
-  {
-    if(userlist[i].pm_chatview)
-    {
-      chatview_autoscroll(userlist[i].pm_chatview);
-    }
-  }
-}
-
 gboolean inputkeys(GtkWidget* widget, GdkEventKey* event, void* data)
 {
   if(event->keyval==GDK_KEY_Up || event->keyval==GDK_KEY_Down)
@@ -994,6 +942,7 @@ int main(int argc, char** argv)
   data=&datax;
   avcodec_register_all();
   data->vdecoder=avcodec_find_decoder(AV_CODEC_ID_FLV1);
+  data->vencoder=avcodec_find_encoder(AV_CODEC_ID_FLV1);
 #ifndef _WIN32
   signal(SIGCHLD, SIG_IGN);
 #else
@@ -1009,173 +958,7 @@ int main(int argc, char** argv)
 #endif
 
   gtk_init(&argc, &argv);
-  if(frombuild)
-  {
-    gui=gtk_builder_new_from_file("gtkgui.glade");
-  }else{
-    gui=gtk_builder_new_from_file(PREFIX "/share/tc_client/gtkgui.glade");
-  }
-  gtk_builder_connect_signals(gui, 0);
-
-  unsigned int i;
-  GtkWidget* item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_broadcast_camera"));
-  g_signal_connect(item, "toggled", G_CALLBACK(togglecam), 0);
-  item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_broadcast_mic"));
-  #ifdef HAVE_PULSEAUDIO
-  g_signal_connect(item, "toggled", G_CALLBACK(togglemic), 0);
-  item=GTK_WIDGET(gtk_builder_get_object(gui, "pushtotalk"));
-  g_signal_connect(item, "button-press-event", G_CALLBACK(mic_pushtotalk), (void*)1);
-  g_signal_connect(item, "button-release-event", G_CALLBACK(mic_pushtotalk), 0);
-  #else
-  gtk_widget_destroy(item);
-  #endif
-  item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_broadcast_stop"));
-  g_signal_connect(item, "activate", G_CALLBACK(stopbroadcasting), 0);
-  data->vencoder=avcodec_find_encoder(AV_CODEC_ID_FLV1);
-  // Set up cam selection and preview
-  campreview.cam=GTK_WIDGET(gtk_builder_get_object(gui, "camselect_preview"));
-  campreview.frame=av_frame_alloc();
-  campreview.frame->data[0]=0;
-  GtkComboBox* combo=GTK_COMBO_BOX(gtk_builder_get_object(gui, "camselect_combo"));
-  g_signal_connect(combo, "changed", G_CALLBACK(camselect_change), 0);
-  // Signals for cancelling
-  item=GTK_WIDGET(gtk_builder_get_object(gui, "camselection"));
-  g_signal_connect(item, "delete-event", G_CALLBACK(camselect_cancel), 0);
-  item=GTK_WIDGET(gtk_builder_get_object(gui, "camselect_cancel"));
-  g_signal_connect(item, "clicked", G_CALLBACK(camselect_cancel), 0);
-  // Signals for switching from preview to streaming
-  item=GTK_WIDGET(gtk_builder_get_object(gui, "camselect_ok"));
-  g_signal_connect(item, "clicked", G_CALLBACK(camselect_accept), 0);
-  // Enable the "img" camera
-  cam_img_filepicker=camselect_file;
-  // Populate list of cams
-  unsigned int count;
-  char** cams=cam_list(&count);
-  GtkListStore* list=gtk_list_store_new(1, G_TYPE_STRING);
-  for(i=0; i<count; ++i)
-  {
-    gtk_list_store_insert_with_values(list, 0, -1, 0, cams[i], -1);
-    free(cams[i]);
-  }
-  free(cams);
-  gtk_combo_box_set_model(combo, GTK_TREE_MODEL(list));
-  g_object_unref(list);
-  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), gtk_cell_renderer_text_new(), 1);
-
-  item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_options_settings"));
-  g_signal_connect(item, "activate", G_CALLBACK(showsettings), gui);
-  item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_options_settings2"));
-  g_signal_connect(item, "activate", G_CALLBACK(showsettings), gui);
-
-  cambox=GTK_WIDGET(gtk_builder_get_object(gui, "cambox"));
-  userlistwidget=GTK_WIDGET(gtk_builder_get_object(gui, "userlistbox"));
-  GtkWidget* chatview=GTK_WIDGET(gtk_builder_get_object(gui, "chatview"));
-  mainchat=chatview_new(GTK_TEXT_VIEW(chatview));
-  GdkDisplay* display=gtk_widget_get_display(chatview);
-  gui_cursor_text=gdk_cursor_new_from_name(display, "text");
-  gui_cursor_link=gdk_cursor_new_from_name(display, "pointer");
-
-  GtkWidget* panes=GTK_WIDGET(gtk_builder_get_object(gui, "vpaned"));
-  g_signal_connect(panes, "notify::position", G_CALLBACK(handleresizepane), data);
-  gtk_paned_set_wide_handle(GTK_PANED(panes), 1);
-  panes=GTK_WIDGET(gtk_builder_get_object(gui, "chatnick"));
-  gtk_paned_set_wide_handle(GTK_PANED(panes), 1);
-
-  GtkWidget* inputfield=GTK_WIDGET(gtk_builder_get_object(gui, "inputfield"));
-  g_signal_connect(inputfield, "activate", G_CALLBACK(sendmessage), data);
-  g_signal_connect(inputfield, "key-press-event", G_CALLBACK(inputkeys), data);
-
-  // Sound
-  GtkWidget* option=GTK_WIDGET(gtk_builder_get_object(gui, "soundradio_cmd"));
-  g_signal_connect(option, "toggled", G_CALLBACK(toggle_soundcmd), gui);
-  // Logging
-  option=GTK_WIDGET(gtk_builder_get_object(gui, "enable_logging"));
-  g_signal_connect(option, "toggled", G_CALLBACK(toggle_logging), gui);
-  option=GTK_WIDGET(gtk_builder_get_object(gui, "save_settings"));
-  g_signal_connect(option, "clicked", G_CALLBACK(savesettings), gui);
-  // Youtube
-  option=GTK_WIDGET(gtk_builder_get_object(gui, "youtuberadio_cmd"));
-  g_signal_connect(option, "toggled", G_CALLBACK(toggle_youtubecmd), gui);
-  // Misc
-  option=GTK_WIDGET(gtk_builder_get_object(gui, "camdownonjoin"));
-
-  GtkWidget* window=GTK_WIDGET(gtk_builder_get_object(gui, "main"));
-  g_signal_connect(window, "configure-event", G_CALLBACK(handleresize), data);
-
-  // Start window and channel password window signals
-  GtkWidget* button=GTK_WIDGET(gtk_builder_get_object(gui, "channelpasswordbutton"));
-  g_signal_connect(button, "clicked", G_CALLBACK(startsession), (void*)-1);
-  button=GTK_WIDGET(gtk_builder_get_object(gui, "channelpassword"));
-  g_signal_connect(button, "activate", G_CALLBACK(startsession), (void*)-1);
-  GtkWidget* startwindow=GTK_WIDGET(gtk_builder_get_object(gui, "startwindow"));
-  // Connect signal for quick connect
-  item=GTK_WIDGET(gtk_builder_get_object(gui, "start_menu_connect"));
-  struct channelopts cc_connect={-1,0};
-  g_signal_connect(item, "activate", G_CALLBACK(channeldialog), &cc_connect);
-  // Connect signal for the add option
-  item=GTK_WIDGET(gtk_builder_get_object(gui, "start_menu_add"));
-  struct channelopts cc_add={-1,1};
-  g_signal_connect(item, "activate", G_CALLBACK(channeldialog), &cc_add);
-  // Connect signal for tab changing (to un-highlight)
-  item=GTK_WIDGET(gtk_builder_get_object(gui, "tabs"));
-  g_signal_connect(item, "switch-page", G_CALLBACK(pm_select), 0);
-  // Connect signal for captcha
-  g_signal_connect(gtk_builder_get_object(gui, "captcha_done"), "clicked", G_CALLBACK(captcha_done), 0);
-  // Connect signals for link menus
-  g_signal_connect(gtk_builder_get_object(gui, "link_menu_open"), "activate", G_CALLBACK(gui_link_menu_open), 0);
-  g_signal_connect(gtk_builder_get_object(gui, "link_menu_copy"), "activate", G_CALLBACK(gui_link_menu_copy), 0);
-  // Connect signals for camera postprocessing
-  g_signal_connect(gtk_builder_get_object(gui, "cam_menu_colors"), "activate", G_CALLBACK(gui_show_camcolors), 0);
-  g_signal_connect(gtk_builder_get_object(gui, "camcolors_min_brightness"), "value-changed", G_CALLBACK(camcolors_adjust_min), 0);
-  g_signal_connect(gtk_builder_get_object(gui, "camcolors_max_brightness"), "value-changed", G_CALLBACK(camcolors_adjust_max), 0);
-  g_signal_connect(gtk_builder_get_object(gui, "camcolors_auto"), "toggled", G_CALLBACK(camcolors_toggle_auto), 0);
-  g_signal_connect(gtk_builder_get_object(gui, "camcolors_flip_horizontal"), "toggled", G_CALLBACK(camcolors_toggle_flip), 0);
-  g_signal_connect(gtk_builder_get_object(gui, "camcolors_flip_vertical"), "toggled", G_CALLBACK(camcolors_toggle_flip), (void*)1);
-  g_signal_connect(gtk_builder_get_object(gui, "greenscreenbutton"), "clicked", G_CALLBACK(gui_set_greenscreen_img), 0);
-  g_signal_connect(gtk_builder_get_object(gui, "greenscreen_colorpicker"), "color-set", G_CALLBACK(gui_set_greenscreen_color), 0);
-  g_signal_connect(gtk_builder_get_object(gui, "greenscreen_tolerance_h"), "value-changed", G_CALLBACK(gui_set_greenscreen_tolerance), 0);
-  g_signal_connect(gtk_builder_get_object(gui, "greenscreen_tolerance_s"), "value-changed", G_CALLBACK(gui_set_greenscreen_tolerance), (void*)1);
-  g_signal_connect(gtk_builder_get_object(gui, "greenscreen_tolerance_v"), "value-changed", G_CALLBACK(gui_set_greenscreen_tolerance), (void*)2);
-  // Connect signal for hiding cameras
-  g_signal_connect(gtk_builder_get_object(gui, "cam_menu_hide"), "activate", G_CALLBACK(gui_hide_cam), 0);
-  // Load placeholder animation for cameras (no video data yet or mic only)
-  if(frombuild)
-  {
-    camplaceholder=gdk_pixbuf_animation_new_from_file("camplaceholder.gif", 0);
-  }else{
-    camplaceholder=gdk_pixbuf_animation_new_from_file(PREFIX "/share/tc_client/camplaceholder.gif", 0);
-  }
-  camplaceholder_iter=gdk_pixbuf_animation_get_iter(camplaceholder, 0);
-  // Populate saved channels
-  GtkWidget* startbox=GTK_WIDGET(gtk_builder_get_object(gui, "startbox"));
-  int channelcount=config_get_int("channelcount");
-  if(channelcount)
-  {
-    gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object(gui, "channel_placeholder")));
-  }
-  char buf[256];
-  for(i=0; i<channelcount; ++i)
-  {
-    GtkWidget* box=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
-    #ifdef GTK_STYLE_CLASS_LINKED
-      GtkStyleContext* style=gtk_widget_get_style_context(box);
-      gtk_style_context_add_class(style, GTK_STYLE_CLASS_LINKED);
-    #endif
-    sprintf(buf, "channel%i_name", i);
-    const char* name=config_get_str(buf);
-    GtkWidget* connectbutton=gtk_button_new_with_label(name);
-    g_signal_connect(connectbutton, "clicked", G_CALLBACK(startsession), (void*)(intptr_t)i);
-    gtk_box_pack_start(GTK_BOX(box), connectbutton, 1, 1, 0);
-    GtkWidget* cfgbutton=gtk_button_new_from_icon_name("gtk-preferences", GTK_ICON_SIZE_BUTTON);
-    struct channelopts* opts=malloc(sizeof(struct channelopts));
-    opts->channel_id=i;
-    opts->save=1;
-    g_signal_connect(cfgbutton, "clicked", G_CALLBACK(channeldialog), opts);
-    gtk_box_pack_start(GTK_BOX(box), cfgbutton, 0, 0, 0);
-    gtk_box_pack_start(GTK_BOX(startbox), box, 0, 0, 2);
-  }
-  gtk_widget_show_all(startwindow);
-
+  gui_init(frombuild);
   gtk_main();
  
 #ifdef _WIN32
diff --git a/utilities/gtk/gui.c b/utilities/gtk/gui.c
index e0599e9..9761f66 100644
--- a/utilities/gtk/gui.c
+++ b/utilities/gtk/gui.c
@@ -23,6 +23,7 @@
 #include "compat.h"
 #include "userlist.h"
 #include "media.h"
+#include "main.h"
 #include "gui.h"
 
 extern void startsession(GtkButton* button, void* x);
@@ -33,6 +34,7 @@ unsigned int gui_greenscreen_preview_event=0;
 extern gboolean gui_greenscreen_preview(void* x);
 GdkCursor* gui_cursor_text;
 GdkCursor* gui_cursor_link;
+struct chatview* mainchat;
 
 void settings_reset(GtkBuilder* gui)
 {
@@ -793,3 +795,224 @@ void chatview_autoscroll(struct chatview* cv)
   GtkTextMark* mark=gtk_text_buffer_get_mark(buffer, "end");
   gtk_text_view_scroll_to_mark(cv->textview, mark, 0, 0, 0, 0);
 }
+
+void togglecam_cancel(void)
+{
+  GtkCheckMenuItem* item=GTK_CHECK_MENU_ITEM(gtk_builder_get_object(gui, "menuitem_broadcast_camera"));
+  gtk_check_menu_item_set_active(item, 0);
+}
+
+void stopbroadcasting(GtkMenuItem* x, void* y)
+{
+  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(gui, "menuitem_broadcast_camera")), 0);
+  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(gui, "menuitem_broadcast_mic")), 0);
+}
+
+gboolean mic_pushtotalk(GtkWidget* button, GdkEvent* event, void* pushed)
+{
+  pushtotalk_pushed=!!pushed;
+  return 0;
+}
+
+gboolean handleresize(GtkWidget* widget, GdkEventConfigure* event, void* data)
+{
+  if(event->width!=gtk_widget_get_allocated_width(cambox))
+  {
+    updatescaling(event->width, 0, 0);
+  }
+  // Fix scrolling
+  chatview_autoscroll(mainchat);
+  unsigned int i;
+  for(i=0; i<usercount; ++i)
+  {
+    if(userlist[i].pm_chatview)
+    {
+      chatview_autoscroll(userlist[i].pm_chatview);
+    }
+  }
+  return 0;
+}
+
+void handleresizepane(GObject* obj, GParamSpec* spec, void* data)
+{
+  updatescaling(0, gtk_paned_get_position(GTK_PANED(obj)), 0);
+  // Fix scrolling
+  chatview_autoscroll(mainchat);
+  unsigned int i;
+  for(i=0; i<usercount; ++i)
+  {
+    if(userlist[i].pm_chatview)
+    {
+      chatview_autoscroll(userlist[i].pm_chatview);
+    }
+  }
+}
+
+void gui_init(char frombuild)
+{
+  if(frombuild)
+  {
+    gui=gtk_builder_new_from_file("gtkgui.glade");
+  }else{
+    gui=gtk_builder_new_from_file(PREFIX "/share/tc_client/gtkgui.glade");
+  }
+  gtk_builder_connect_signals(gui, 0);
+
+  unsigned int i;
+  GtkWidget* item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_broadcast_camera"));
+  g_signal_connect(item, "toggled", G_CALLBACK(togglecam), 0);
+  item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_broadcast_mic"));
+  #ifdef HAVE_PULSEAUDIO
+  g_signal_connect(item, "toggled", G_CALLBACK(togglemic), 0);
+  item=GTK_WIDGET(gtk_builder_get_object(gui, "pushtotalk"));
+  g_signal_connect(item, "button-press-event", G_CALLBACK(mic_pushtotalk), (void*)1);
+  g_signal_connect(item, "button-release-event", G_CALLBACK(mic_pushtotalk), 0);
+  #else
+  gtk_widget_destroy(item);
+  #endif
+  item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_broadcast_stop"));
+  g_signal_connect(item, "activate", G_CALLBACK(stopbroadcasting), 0);
+  // Set up cam selection and preview
+  campreview.cam=GTK_WIDGET(gtk_builder_get_object(gui, "camselect_preview"));
+  campreview.frame=av_frame_alloc();
+  campreview.frame->data[0]=0;
+  GtkComboBox* combo=GTK_COMBO_BOX(gtk_builder_get_object(gui, "camselect_combo"));
+  g_signal_connect(combo, "changed", G_CALLBACK(camselect_change), 0);
+  // Signals for cancelling
+  item=GTK_WIDGET(gtk_builder_get_object(gui, "camselection"));
+  g_signal_connect(item, "delete-event", G_CALLBACK(camselect_cancel), 0);
+  item=GTK_WIDGET(gtk_builder_get_object(gui, "camselect_cancel"));
+  g_signal_connect(item, "clicked", G_CALLBACK(camselect_cancel), 0);
+  // Signals for switching from preview to streaming
+  item=GTK_WIDGET(gtk_builder_get_object(gui, "camselect_ok"));
+  g_signal_connect(item, "clicked", G_CALLBACK(camselect_accept), 0);
+  // Enable the "img" camera
+  cam_img_filepicker=camselect_file;
+  // Populate list of cams
+  unsigned int count;
+  char** cams=cam_list(&count);
+  GtkListStore* list=gtk_list_store_new(1, G_TYPE_STRING);
+  for(i=0; i<count; ++i)
+  {
+    gtk_list_store_insert_with_values(list, 0, -1, 0, cams[i], -1);
+    free(cams[i]);
+  }
+  free(cams);
+  gtk_combo_box_set_model(combo, GTK_TREE_MODEL(list));
+  g_object_unref(list);
+  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), gtk_cell_renderer_text_new(), 1);
+
+  item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_options_settings"));
+  g_signal_connect(item, "activate", G_CALLBACK(showsettings), gui);
+  item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_options_settings2"));
+  g_signal_connect(item, "activate", G_CALLBACK(showsettings), gui);
+
+  cambox=GTK_WIDGET(gtk_builder_get_object(gui, "cambox"));
+  userlistwidget=GTK_WIDGET(gtk_builder_get_object(gui, "userlistbox"));
+  GtkWidget* chatview=GTK_WIDGET(gtk_builder_get_object(gui, "chatview"));
+  mainchat=chatview_new(GTK_TEXT_VIEW(chatview));
+  GdkDisplay* display=gtk_widget_get_display(chatview);
+  gui_cursor_text=gdk_cursor_new_from_name(display, "text");
+  gui_cursor_link=gdk_cursor_new_from_name(display, "pointer");
+
+  GtkWidget* panes=GTK_WIDGET(gtk_builder_get_object(gui, "vpaned"));
+  g_signal_connect(panes, "notify::position", G_CALLBACK(handleresizepane), 0);
+  gtk_paned_set_wide_handle(GTK_PANED(panes), 1);
+  panes=GTK_WIDGET(gtk_builder_get_object(gui, "chatnick"));
+  gtk_paned_set_wide_handle(GTK_PANED(panes), 1);
+
+  GtkWidget* inputfield=GTK_WIDGET(gtk_builder_get_object(gui, "inputfield"));
+  g_signal_connect(inputfield, "activate", G_CALLBACK(sendmessage), 0);
+  g_signal_connect(inputfield, "key-press-event", G_CALLBACK(inputkeys), 0);
+
+  // Sound
+  GtkWidget* option=GTK_WIDGET(gtk_builder_get_object(gui, "soundradio_cmd"));
+  g_signal_connect(option, "toggled", G_CALLBACK(toggle_soundcmd), gui);
+  // Logging
+  option=GTK_WIDGET(gtk_builder_get_object(gui, "enable_logging"));
+  g_signal_connect(option, "toggled", G_CALLBACK(toggle_logging), gui);
+  option=GTK_WIDGET(gtk_builder_get_object(gui, "save_settings"));
+  g_signal_connect(option, "clicked", G_CALLBACK(savesettings), gui);
+  // Youtube
+  option=GTK_WIDGET(gtk_builder_get_object(gui, "youtuberadio_cmd"));
+  g_signal_connect(option, "toggled", G_CALLBACK(toggle_youtubecmd), gui);
+  // Misc
+  option=GTK_WIDGET(gtk_builder_get_object(gui, "camdownonjoin"));
+
+  GtkWidget* window=GTK_WIDGET(gtk_builder_get_object(gui, "main"));
+  g_signal_connect(window, "configure-event", G_CALLBACK(handleresize), 0);
+
+  // Start window and channel password window signals
+  GtkWidget* button=GTK_WIDGET(gtk_builder_get_object(gui, "channelpasswordbutton"));
+  g_signal_connect(button, "clicked", G_CALLBACK(startsession), (void*)-1);
+  button=GTK_WIDGET(gtk_builder_get_object(gui, "channelpassword"));
+  g_signal_connect(button, "activate", G_CALLBACK(startsession), (void*)-1);
+  GtkWidget* startwindow=GTK_WIDGET(gtk_builder_get_object(gui, "startwindow"));
+  // Connect signal for quick connect
+  item=GTK_WIDGET(gtk_builder_get_object(gui, "start_menu_connect"));
+  struct channelopts cc_connect={-1,0};
+  g_signal_connect(item, "activate", G_CALLBACK(channeldialog), &cc_connect);
+  // Connect signal for the add option
+  item=GTK_WIDGET(gtk_builder_get_object(gui, "start_menu_add"));
+  struct channelopts cc_add={-1,1};
+  g_signal_connect(item, "activate", G_CALLBACK(channeldialog), &cc_add);
+  // Connect signal for tab changing (to un-highlight)
+  item=GTK_WIDGET(gtk_builder_get_object(gui, "tabs"));
+  g_signal_connect(item, "switch-page", G_CALLBACK(pm_select), 0);
+  // Connect signal for captcha
+  g_signal_connect(gtk_builder_get_object(gui, "captcha_done"), "clicked", G_CALLBACK(captcha_done), 0);
+  // Connect signals for link menus
+  g_signal_connect(gtk_builder_get_object(gui, "link_menu_open"), "activate", G_CALLBACK(gui_link_menu_open), 0);
+  g_signal_connect(gtk_builder_get_object(gui, "link_menu_copy"), "activate", G_CALLBACK(gui_link_menu_copy), 0);
+  // Connect signals for camera postprocessing
+  g_signal_connect(gtk_builder_get_object(gui, "cam_menu_colors"), "activate", G_CALLBACK(gui_show_camcolors), 0);
+  g_signal_connect(gtk_builder_get_object(gui, "camcolors_min_brightness"), "value-changed", G_CALLBACK(camcolors_adjust_min), 0);
+  g_signal_connect(gtk_builder_get_object(gui, "camcolors_max_brightness"), "value-changed", G_CALLBACK(camcolors_adjust_max), 0);
+  g_signal_connect(gtk_builder_get_object(gui, "camcolors_auto"), "toggled", G_CALLBACK(camcolors_toggle_auto), 0);
+  g_signal_connect(gtk_builder_get_object(gui, "camcolors_flip_horizontal"), "toggled", G_CALLBACK(camcolors_toggle_flip), 0);
+  g_signal_connect(gtk_builder_get_object(gui, "camcolors_flip_vertical"), "toggled", G_CALLBACK(camcolors_toggle_flip), (void*)1);
+  g_signal_connect(gtk_builder_get_object(gui, "greenscreenbutton"), "clicked", G_CALLBACK(gui_set_greenscreen_img), 0);
+  g_signal_connect(gtk_builder_get_object(gui, "greenscreen_colorpicker"), "color-set", G_CALLBACK(gui_set_greenscreen_color), 0);
+  g_signal_connect(gtk_builder_get_object(gui, "greenscreen_tolerance_h"), "value-changed", G_CALLBACK(gui_set_greenscreen_tolerance), 0);
+  g_signal_connect(gtk_builder_get_object(gui, "greenscreen_tolerance_s"), "value-changed", G_CALLBACK(gui_set_greenscreen_tolerance), (void*)1);
+  g_signal_connect(gtk_builder_get_object(gui, "greenscreen_tolerance_v"), "value-changed", G_CALLBACK(gui_set_greenscreen_tolerance), (void*)2);
+  // Connect signal for hiding cameras
+  g_signal_connect(gtk_builder_get_object(gui, "cam_menu_hide"), "activate", G_CALLBACK(gui_hide_cam), 0);
+  // Load placeholder animation for cameras (no video data yet or mic only)
+  if(frombuild)
+  {
+    camplaceholder=gdk_pixbuf_animation_new_from_file("camplaceholder.gif", 0);
+  }else{
+    camplaceholder=gdk_pixbuf_animation_new_from_file(PREFIX "/share/tc_client/camplaceholder.gif", 0);
+  }
+  camplaceholder_iter=gdk_pixbuf_animation_get_iter(camplaceholder, 0);
+  // Populate saved channels
+  GtkWidget* startbox=GTK_WIDGET(gtk_builder_get_object(gui, "startbox"));
+  int channelcount=config_get_int("channelcount");
+  if(channelcount)
+  {
+    gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object(gui, "channel_placeholder")));
+  }
+  char buf[256];
+  for(i=0; i<channelcount; ++i)
+  {
+    GtkWidget* box=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+    #ifdef GTK_STYLE_CLASS_LINKED
+      GtkStyleContext* style=gtk_widget_get_style_context(box);
+      gtk_style_context_add_class(style, GTK_STYLE_CLASS_LINKED);
+    #endif
+    sprintf(buf, "channel%i_name", i);
+    const char* name=config_get_str(buf);
+    GtkWidget* connectbutton=gtk_button_new_with_label(name);
+    g_signal_connect(connectbutton, "clicked", G_CALLBACK(startsession), (void*)(intptr_t)i);
+    gtk_box_pack_start(GTK_BOX(box), connectbutton, 1, 1, 0);
+    GtkWidget* cfgbutton=gtk_button_new_from_icon_name("gtk-preferences", GTK_ICON_SIZE_BUTTON);
+    struct channelopts* opts=malloc(sizeof(struct channelopts));
+    opts->channel_id=i;
+    opts->save=1;
+    g_signal_connect(cfgbutton, "clicked", G_CALLBACK(channeldialog), opts);
+    gtk_box_pack_start(GTK_BOX(box), cfgbutton, 0, 0, 0);
+    gtk_box_pack_start(GTK_BOX(startbox), box, 0, 0, 2);
+  }
+  gtk_widget_show_all(startwindow);
+}
diff --git a/utilities/gtk/gui.h b/utilities/gtk/gui.h
index 70c82cd..1d71345 100644
--- a/utilities/gtk/gui.h
+++ b/utilities/gtk/gui.h
@@ -64,7 +64,13 @@ extern void gui_link_menu_open(GtkWidget* menuitem, void* x);
 extern void gui_link_menu_copy(GtkWidget* menuitem, void* x);
 extern struct chatview* chatview_new(GtkTextView* existing_textview);
 extern void chatview_autoscroll(struct chatview* cv);
+extern void togglecam_cancel(void);
+extern void stopbroadcasting(GtkMenuItem* x, void* y);
+extern gboolean handleresize(GtkWidget* widget, GdkEventConfigure* event, void* data);
+extern void handleresizepane(GObject* obj, GParamSpec* spec, void* data);
+extern void gui_init(char frombuild);
 
 extern GtkBuilder* gui;
 extern GdkCursor* gui_cursor_text;
 extern GdkCursor* gui_cursor_link;
+extern struct chatview* mainchat;
diff --git a/utilities/gtk/main.h b/utilities/gtk/main.h
new file mode 100644
index 0000000..dabfbb3
--- /dev/null
+++ b/utilities/gtk/main.h
@@ -0,0 +1,24 @@
+/*
+    tc_client-gtk, a graphical user interface for tc_client
+    Copyright (C) 2015-2016  alicia@ion.nu
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as published by
+    the Free Software Foundation, version 3 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+extern void togglecam(GtkCheckMenuItem* item, void* x);
+#ifdef HAVE_PULSEAUDIO
+void togglemic(GtkCheckMenuItem* item, void* x);
+#endif
+extern gboolean inputkeys(GtkWidget* widget, GdkEventKey* event, void* data);
+extern void sendmessage(GtkEntry* entry, void* x);
+extern void startsession(GtkButton* button, void* x);
+extern void captcha_done(GtkWidget* button, void* x);