File: thegui.cpp

package info (click to toggle)
sigx 2.0.2-3
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 1,144 kB
  • ctags: 1,311
  • sloc: cpp: 3,103; ansic: 653; xml: 206; python: 65; makefile: 26
file content (198 lines) | stat: -rw-r--r-- 5,879 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#include <iostream>
#include <iomanip>
#include <locale>
#include <sstream>
#include <sigxconfig.h>
#ifdef SIGC_MSC
// windows and msvc++
#  if (_WIN32_WINNT >= 0x0501)
#  include <winsock2.h>
#  else
// must include for versions earlier than win xp
#  include <Wspiapi.h>
#  endif
#else
#include <arpa/inet.h>
#include <netdb.h>
#endif
#include <sigc++/sigc++.h>
#include "thegui.h"

using namespace std;


TheGUI::InfoDialog::InfoDialog(Gtk::Window& parent): 
	Gtk::Dialog("", parent, true)
{
	Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox(false, 5));
	Gtk::Image* ico = Gtk::manage(new Gtk::Image(Gtk::Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
	Gtk::Label* lbl = Gtk::manage(new Gtk::Label("The IP address resolver is still working.\nThis could take up to some minutes..."));
	hbox->pack_start(*ico, Gtk::PACK_SHRINK);
	hbox->pack_start(*lbl, Gtk::PACK_SHRINK);
	get_vbox()->add(*hbox);
	add_button(Gtk::Stock::STOP, Gtk::RESPONSE_OK);
	set_has_separator();
	show_all_children();
}


TheGUI::TheGUI(): 
	Gtk::Window(), 
	sigx::glib_auto_dispatchable(), 
	m_resolver(), 
	m_connResolved(), 
	m_connResolvingStopped(), 
	m_pentryIP(), 
	m_pentryHostname(), 
	m_ptvError()
{
	Gtk::Label* pLabelIP = Gtk::manage(new Gtk::Label("IP Address:", Gtk::ALIGN_LEFT));
	m_pentryIP = Gtk::manage(new Gtk::Entry);
	m_pentryIP->set_activates_default();
	m_pentryIP->set_editable(false);

	Gtk::Label* plabelHostname = Gtk::manage(new Gtk::Label("Hostname:", Gtk::ALIGN_LEFT));
	m_pentryHostname = Gtk::manage(new Gtk::Entry);
	m_pentryHostname->set_editable(false);

	Gtk::Label* plabelError = Gtk::manage(new Gtk::Label("Error:", Gtk::ALIGN_LEFT));
	m_ptvError = Gtk::manage(new Gtk::TextView);
	m_ptvError->set_editable(false);

	Gtk::Button* pbtnResolve = Gtk::manage(new Gtk::Button(Gtk::Stock::CONVERT));
	pbtnResolve->property_can_default() = true;
	
	Gtk::HBox* phboxIP = Gtk::manage(new Gtk::HBox(false, 5));
	phboxIP->pack_start(*pLabelIP, Gtk::PACK_SHRINK);
	phboxIP->pack_start(*m_pentryIP);
	phboxIP->pack_start(*pbtnResolve, Gtk::PACK_SHRINK);
	
	Gtk::HBox* phboxHostname = Gtk::manage(new Gtk::HBox(false, 5));
	phboxHostname->pack_start(*plabelHostname, Gtk::PACK_SHRINK);
	phboxHostname->pack_start(*m_pentryHostname);

	Gtk::HBox* phboxError = Gtk::manage(new Gtk::HBox(false, 5));
	phboxError->pack_start(*plabelError, Gtk::PACK_SHRINK);
	phboxError->pack_start(*m_ptvError);

	Gtk::VBox* pvboxAll = Gtk::manage(new Gtk::VBox);
	pvboxAll->pack_start(*phboxIP, Gtk::PACK_SHRINK, 5);
	pvboxAll->pack_start(*phboxHostname, Gtk::PACK_SHRINK, 5);
	pvboxAll->pack_start(*phboxError, Gtk::PACK_SHRINK, 5);
	
	add(*pvboxAll);
	set_default(*pbtnResolve);
	show_all_children();


	pbtnResolve->signal_clicked().connect(sigc::mem_fun(this, &TheGUI::on_resolve));

	// one-shot idle handler
	Glib::signal_idle().connect(sigc::bind_return(sigc::mem_fun(this, &TheGUI::on_gui_ready), false));

	// we connect to the resolver's signals in on_gui_ready() when the
	// resolver thread is started and ready
}

bool TheGUI::on_delete_event(GdkEventAny*)
{
	m_pentryIP->property_editable() = false;

	// display an info dialog after 3 seconds if the program does not
	// end because the resolver is still resolving
	InfoDialog::threadsafe_type dlg(new InfoDialog(*this));
	Glib::signal_timeout().connect(
		sigc::bind_return(
			sigc::bind(
				sigc::mem_fun(this, &TheGUI::on_display_infomessage), 
				dlg
			), 
			false
		), 
		3000
	);
	m_connResolved.disconnect();
	cout << "waiting for resolver to stop resolving.." << endl;
	m_connResolvingStopped = m_resolver.signal_resolving_stopped().connect(
		sigc::bind(
			sigc::mem_fun(this, &TheGUI::on_resolving_stopped), 
			dlg
		)
	);
	m_resolver.stop_resolving();
	return true; // do not proceed
}

void TheGUI::on_gui_ready()
{
	cout << "waiting for resolver to be ready" << endl;
	m_resolver.run();
	m_connResolved = m_resolver.signal_resolved().connect(
			sigc::mem_fun(this, &TheGUI::on_resolved)
	);
	cout << "connected to the resolver: " << boolalpha << m_connResolved.connected() << endl;
	m_pentryIP->set_editable(true);
}

void TheGUI::on_resolved(const std::string& strHost, guint32 nIP, int nErr)
{
	m_pentryHostname->set_text(strHost);
	if (nErr)
	{
		const Glib::RefPtr<Gtk::TextBuffer> pTextBuf = m_ptvError->get_buffer();
#ifdef SIGC_MSC
		char* pBuf(0);
		// FormatMessage returns the number of characters stored in the output buffer, excluding the terminating null character
		const DWORD nLen = FormatMessageA(
			FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, 
			0, nErr, 0, 
			// must be a char** if FORMAT_MESSAGE_ALLOCATE_BUFFER is specified above
			reinterpret_cast<char*>(&pBuf), 0, 
			0
		);
		pTextBuf->set_text(Glib::locale_to_utf8(pBuf));
		LocalFree(pBuf);
#else
		pTextBuf->set_text(Glib::locale_to_utf8(hstrerror(nErr)));
#endif
	}
}

void TheGUI::on_display_infomessage(InfoDialog::threadsafe_type pDlg)
{
	if (pDlg->run() == Gtk::RESPONSE_OK)
		// user clicked "stop", don't wait for resolver thread
		hide();
}

void TheGUI::on_resolving_stopped(InfoDialog::threadsafe_type pDlg)
{
	cout << "resolver stopped resolving" << endl;
	// quit the info dialog eventually
	pDlg->response(Gtk::RESPONSE_DELETE_EVENT);
	m_connResolvingStopped.disconnect();
	m_resolver.finish();
	// now quit the main loop
	hide();
}

void TheGUI::on_resolve()
{
	m_pentryHostname->set_text(Glib::ustring());
	m_ptvError->get_buffer()->set_text(Glib::ustring());
	const Glib::ustring& strIP = m_pentryIP->get_text();
#ifdef SIGC_MSC
	const in_addr_t nIP = inet_addr(strIP.c_str());
	if (nIP != INADDR_NONE)
		m_resolver.resolve(nIP);
#else
	in_addr addr = {};
	if (inet_aton(strIP.c_str(), &addr) != 0)
		m_resolver.resolve(addr.s_addr);
#endif
	else
	{
		m_ptvError->get_buffer()->set_text("\"" + strIP + "\" is not a valid ip address");
		cerr << ("\"" + strIP + "\" is not a valid ip address") << endl;
	}
}