5.2. doc_client.cc
#include "doc.hh"
#include <cstdio>
#include <popt.h>
#include <gtk/gtk.h>
using namespace libdoc;
A simple GUI client program which connects to Docd and sends it queries.
static bool decode_options (int argc, char **argv);
static void init_gui ();
static void handle_query_activate (GtkEditable *ed, gpointer dat);
static void handle_result_selected (GtkWidget *list, int row, int col,
GdkEventButton *e, gpointer dat);
static gboolean handle_window_delete (GtkWidget *w, GdkEvent *e, gpointer dat);
void statusbar_setmsg (const string &msg);
void statusbar_clear ();
static const char *progname;
static int docd_socket;
static GtkWidget *results_list;
static vector <SearchResult> results_vec;
static GtkWidget *status_bar;
static int status_bar_cntxt;
static size_t statusbar_stack_sz = 0;
static const char *option_host = 0;
static int option_port = DEFAULT_PORT;
The table of command line options.
poptOption options_table[] =
{
POPT_AUTOHELP
{ "port", 'p', POPT_ARG_INT, &option_port, 0,
"Specify the number of the port to connect to", NULL },
{ "host", 'h', POPT_ARG_STRING, &option_host, 0,
"Specify the IP address of the host to connect to", NULL },
{ NULL, 0, 0, NULL, 0, NULL, NULL }
};
int
main (int argc, char **argv)
{
if (!decode_options (argc, argv))
return 1;
try
{
docd_socket = open_connection_to_docd (option_host, option_port);
}
catch (Exception &e)
{
fprintf (stderr, "%s: %s\n", progname, e.explain().c_str());
return 9;
}
gtk_init (&argc, &argv);
init_gui();
gtk_main();
return 0;
}
bool
decode_options (int argc, char **argv)
{
progname = argv[0];
poptContext context = poptGetContext ("doc_client", argc,
(const char **) argv,
options_table, 0);
int rc = poptGetNextOpt (context);
if (rc < -1)
{
fprintf (stderr, "%s: error in command line options.\n", progname);
return false;
}
If the host IP address wasn't specified, set a default.
if (option_host == 0)
option_host = x_strdup (inet_ntoa (find_hostip()));
return true;
}
void
init_gui ()
{
The main window.
GtkWidget *win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (win), "Documentation Search");
gtk_widget_set_usize (win, 250, 300);
gtk_signal_connect (GTK_OBJECT (win), "delete_event",
GTK_SIGNAL_FUNC (handle_window_delete), 0);
The vertical box inside the window.
GtkWidget *vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (win), vbox);
gtk_widget_show (vbox);
The text entry box for entering queries.
GtkWidget *query = gtk_entry_new();
gtk_widget_show (query);
gtk_box_pack_start (GTK_BOX (vbox), query, FALSE, TRUE, 0);
gtk_signal_connect (GTK_OBJECT (query), "activate",
GTK_SIGNAL_FUNC (handle_query_activate), 0);
The list of search results, in a scrolled window.
char *titles[] = { "Format", "Title" };
results_list = gtk_clist_new_with_titles (2, titles);
gtk_clist_set_selection_mode (GTK_CLIST (results_list),
GTK_SELECTION_SINGLE);
gtk_signal_connect (GTK_OBJECT (results_list), "select_row",
GTK_SIGNAL_FUNC (handle_result_selected), 0);
GtkWidget *scrwin = gtk_scrolled_window_new (0, 0);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrwin),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (scrwin), results_list);
gtk_box_pack_start (GTK_BOX (vbox), scrwin, TRUE, TRUE, 1);
gtk_widget_show (results_list);
gtk_widget_show (scrwin);
Put a status bar at the bottom of the window.
status_bar = gtk_statusbar_new();
gtk_box_pack_start (GTK_BOX (vbox), status_bar, FALSE, TRUE, 0);
gtk_widget_show (status_bar);
status_bar_cntxt = gtk_statusbar_get_context_id (GTK_STATUSBAR (status_bar),
"foo");
gtk_widget_grab_focus (query);
gtk_widget_show (win);
}
void
handle_query_activate (GtkEditable *ed, gpointer dat)
{
if (docd_socket < 0)
fputs ("Something has gone wrong.\n", stderr);
statusbar_setmsg ("Searching...");
const char *s = gtk_entry_get_text (GTK_ENTRY (ed));
try
{
perform_search (docd_socket, s, results_vec);
gtk_clist_freeze (GTK_CLIST (results_list));
gtk_clist_clear (GTK_CLIST (results_list));
for (size_t i = 0; i < results_vec.size(); ++i)
{
const char *labels[2];
labels[0] = results_vec[i].format_name.c_str();
if (results_vec[i].document_title.empty())
labels[1] = results_vec[i].document_filename.c_str();
else
labels[1] = results_vec[i].document_title.c_str();
gtk_clist_append (GTK_CLIST (results_list), (char **) labels);
}
gtk_clist_thaw (GTK_CLIST (results_list));
char buf[32];
sprintf (buf, "%u", (unsigned int) results_vec.size());
statusbar_setmsg (string (buf) + " documents found.");
}
catch (Exception &e)
{
fprintf (stderr, "%s: %s\n", progname, e.explain().c_str());
statusbar_setmsg ("Error.");
}
}
void
handle_result_selected (GtkWidget *list, int row, int col, GdkEventButton *e,
gpointer dat)
{
if (e->type == GDK_2BUTTON_PRESS)
{
string cmd = results_vec[row].format_viewers;
cmd += ' ';
cmd += results_vec[row].document_filename;
cmd += " &";
fprintf (stderr, "%s\n", cmd.c_str());
system (cmd.c_str());
}
}
gboolean
handle_window_delete (GtkWidget *w, GdkEvent *e, gpointer dat)
{
close (docd_socket);
docd_socket = -1;
gtk_main_quit();
return FALSE;
}
void
statusbar_setmsg (const string &msg)
{
if (statusbar_stack_sz > 0)
gtk_statusbar_pop (GTK_STATUSBAR (status_bar), status_bar_cntxt);
else
++statusbar_stack_sz;
gtk_statusbar_push (GTK_STATUSBAR (status_bar), status_bar_cntxt,
msg.c_str());
}
void
statusbar_clear ()
{
while (statusbar_stack_sz > 0)
{
gtk_statusbar_pop (GTK_STATUSBAR (status_bar), status_bar_cntxt);
--statusbar_stack_sz;
}
}