/* $Id$ * Gnome user interface * Copyright (C) 2004 Jan Kratochvil * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; exactly version 2 of June 1991 is required * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "ui-gnome.h" /* self */ #include #include "main.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "network.h" #include "packet.h" #include "static-startup.h" /* Config: */ #define DAEMON_CHECK_INTERVAL_MS 100 #define EXTERNAL_STARTUP_CHECK_INTERVAL_MS 1000 #define PORT_RANGE_BEGIN 2048 #define PORT_RANGE_END 10240 #define UI_GNOME_PROBE_TIMEOUT_SEC 10 static GnomeApp *App; static GtkButton *ButtonStart; static GtkButton *ButtonStop; static GtkHBox *PortHBox; static GnomeAppBar *AppBar; static GtkEntry *PortEntry; static GtkEntry *HostIPEntry; static GtkLabel *AutostartLabel; static GtkCheckButton *AutostartCheckButton; static void state_start_stop(void) { pid_t daemon_pid; gboolean daemon_running; static gboolean last_daemon_running,last_daemon_running_set=FALSE; daemon_pid=is_daemon_running(); daemon_running=((pid_t)-1!=daemon_pid); /* Cache the result; maybe not needed. */ if (last_daemon_running_set && last_daemon_running==daemon_running) return; last_daemon_running=daemon_running; last_daemon_running_set=TRUE; gtk_widget_set_sensitive(GTK_WIDGET(ButtonStart),!daemon_running); gtk_widget_set_sensitive(GTK_WIDGET(ButtonStop) , daemon_running); gtk_widget_set_sensitive(GTK_WIDGET(PortHBox) ,!daemon_running); if (daemon_running) gnome_appbar_set_status(AppBar, udpgate_printf_alloca(_("udpgate daemon running as PID %d."),(int)daemon_pid)); else gnome_appbar_set_status(AppBar,_("No udpgate daemon currently running.")); } static gboolean daemon_check_timeout_func(gpointer data /* unused */) { if (!App) /* Quitting? */ return FALSE; /* stop running */ state_start_stop(); return TRUE; /* continue running */ } static gboolean external_startup_check_timeout_func(gpointer data /* unused */) { gboolean state_startup_is_on; if (!App) /* Quitting? */ return FALSE; /* stop running */ if (static_startup_query(&state_startup_is_on)) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(AutostartCheckButton),state_startup_is_on); return TRUE; /* continue running */ } static void buttonstart(void) { if (!optarg_port_set_string(gtk_entry_get_text(PortEntry))) return; network_start(optarg_port); } void on_PortButtonRandom_clicked(GtkButton *button,gpointer user_data) { g_return_if_fail(GTK_IS_BUTTON(button)); state_start_stop(); if ((pid_t)-1!=is_daemon_running()) return; gtk_entry_set_text(PortEntry, udpgate_printf_alloca("%d",(int)g_random_int_range(PORT_RANGE_BEGIN,PORT_RANGE_END))); buttonstart(); } void on_AutostartCheckButton_toggled(GtkToggleButton *togglebutton,gpointer user_data) { static gint inside=0; g_return_if_fail(GTK_IS_TOGGLE_BUTTON(togglebutton)); /* Avoid reentrancy to prevent segfault during failed registration. * FIXME: Who knows why? Some forbidden GTK recursion occurs. */ g_assert(inside>=0); if (inside) return; inside++; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(AutostartCheckButton))) static_startup_on(); else static_startup_off(); external_startup_check_timeout_func(NULL); /* data; unused */ g_assert(inside==1); inside--; } void on_ButtonStart_clicked(GtkButton *button,gpointer user_data) { g_return_if_fail(GTK_IS_BUTTON(button)); buttonstart(); } void on_ButtonStop_clicked(GtkButton *button,gpointer user_data) { g_return_if_fail(GTK_IS_BUTTON(button)); network_stop(); } void on_ButtonHide_clicked(GtkButton *button,gpointer user_data) { GnomeApp *App_local; g_return_if_fail(GTK_IS_BUTTON(button)); /* update config file */ optarg_port_set_string(gtk_entry_get_text(PortEntry)); /* Do not: gtk_main_quit(); * as 'App' widget will quit our gtk_main() automatically. */ /* Do not: gtk_widget_destroy(App); App=NULL; * as it would race with g_timeout_add()ed function which check * 'if (!App)' first and expect there fully valid tree afterwards. */ App_local=App; App=NULL; gtk_widget_destroy(GTK_WIDGET(App_local)); } static void ui_gnome_network_notify_hostip(guint32 hostip_guint32) { if (!App) /* Quitting? */ return; if (!hostip_guint32) { pid_t daemon_pid; daemon_pid=is_daemon_running(); if ((pid_t)-1==daemon_pid) gtk_entry_set_text(HostIPEntry,_("(unknown; Start the daemon)")); else if (getpid()==daemon_pid) gtk_entry_set_text(HostIPEntry,_("(unknown; detecting...)")); else gtk_entry_set_text(HostIPEntry,_("(unknown; Kill the daemon and start your own)")); } else { gtk_entry_set_text(HostIPEntry,HOSTIP_GUINT32_TO_STRING(hostip_guint32)); } } static guint ui_gnome_g_log_handler_handler_id; static void ui_gnome_g_log_handler(const gchar *log_domain,GLogLevelFlags log_level,const gchar *message,gpointer user_data) { GtkWidget *dialog; if (!App) /* Quitting? */ return; /**/ if (log_level & G_LOG_LEVEL_ERROR) dialog=gnome_app_error(App,message); else if (log_level & (G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING)) dialog=gnome_app_warning(App,message); else dialog=gnome_app_message(App,message); /* Do not set it modal as ... who knows. At least in the fully static * build during on_AutostartCheckButton_toggled() we get reported * the messages twice and application immediately gtk_main_quit() * even the second (toplevel) gtk_main(). */ #if 0 gtk_window_set_modal(GTK_WINDOW(dialog),TRUE); g_signal_connect((gpointer)dialog,"close",G_CALLBACK(gtk_main_quit),NULL); gtk_main(); /* 'dialog' gets destroyed automatically */ #endif } static void ui_gnome_interactive(void) { probe_timeout_sec_max=UI_GNOME_PROBE_TIMEOUT_SEC; gtk_main(); network_notify_hostip=NULL; g_log_remove_handler( G_LOG_DOMAIN, /* log_domain; "Captive" */ ui_gnome_g_log_handler_handler_id); /* handler_id */ network_detach(); } /* of "ui-gnome-interface.h": */ GtkWidget *create_App(void); /* of "ui-gnome-support.h": */ GtkWidget *lookup_widget(GtkWidget *widget,const gchar *widget_name); gboolean ui_gnome_init(void) { App=GNOME_APP(create_App()); ButtonStart=GTK_BUTTON(lookup_widget(GTK_WIDGET(App),"ButtonStart")); ButtonStop=GTK_BUTTON(lookup_widget(GTK_WIDGET(App),"ButtonStop")); PortHBox=GTK_HBOX(lookup_widget(GTK_WIDGET(App),"PortHBox")); AppBar=GNOME_APPBAR(lookup_widget(GTK_WIDGET(App),"AppBar")); PortEntry=GTK_ENTRY(lookup_widget(GTK_WIDGET(App),"PortEntry")); HostIPEntry=GTK_ENTRY(lookup_widget(GTK_WIDGET(App),"HostIPEntry")); AutostartLabel=GTK_LABEL(lookup_widget(GTK_WIDGET(App),"AutostartLabel")); AutostartCheckButton=GTK_CHECK_BUTTON(lookup_widget(GTK_WIDGET(App),"AutostartCheckButton")); /* ui_gnome_g_log_handler() needs 'App'. */ ui_gnome_g_log_handler_handler_id=g_log_set_handler( G_LOG_DOMAIN, /* log_domain; "Captive" */ (G_LOG_LEVEL_MASK|G_LOG_FLAG_FATAL)&~(0 |G_LOG_LEVEL_MESSAGE |G_LOG_LEVEL_INFO |G_LOG_LEVEL_DEBUG), /* log_levels */ ui_gnome_g_log_handler, /* log_func */ NULL); /* user_data */ ui_gnome_network_notify_hostip(0); gtk_entry_set_text(PortEntry,udpgate_printf_alloca("%d",(int)optarg_port)); if (!static_startup_supported()) { gtk_widget_set_sensitive(GTK_WIDGET(AutostartLabel),FALSE); gtk_widget_set_sensitive(GTK_WIDGET(AutostartCheckButton),FALSE); } if (!static_startup_query(NULL)) gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(AutostartCheckButton),TRUE); daemon_check_timeout_func(NULL); /* data; unused */ external_startup_check_timeout_func(NULL); /* data; unused */ gtk_widget_show_all(GTK_WIDGET(App)); g_timeout_add( DAEMON_CHECK_INTERVAL_MS, /* interval */ daemon_check_timeout_func, /* function */ NULL); /* data; unused */ g_timeout_add( EXTERNAL_STARTUP_CHECK_INTERVAL_MS, /* interval */ external_startup_check_timeout_func, /* function */ NULL); /* data; unused */ network_notify_hostip=ui_gnome_network_notify_hostip; ui_interactive=ui_gnome_interactive; return TRUE; }