1 /* -*- coding: utf-8; indent-tabs-mode: t; tab-width: 4; c-basic-offset: 4; -*- */
2 /**
3  * Copyright (c) 2005 PCMan <pcman.tw@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #ifdef __GNUG__
21   #pragma implementation "mainframe.h"
22 #endif
23 
24 
25 #include <glib/gi18n.h>
26 #include <gdk/gdkkeysyms.h>
27 #include <cstdio>
28 #include <cstring>
29 #include <cstdlib>
30 #include <ltdl.h>
31 
32 #include "mainframe.h"
33 
34 #include "telnetview.h"
35 #include "notebook.h"
36 #include "telnetcon.h"
37 #include "editor.h"
38 
39 #include "inputdialog.h"
40 #include "editfavdlg.h"
41 #include "sitedlg.h"
42 #include "prefdlg.h"
43 #include "appconfig.h"
44 #include "sitelistdlg.h"
45 #include "emoticondlg.h"
46 #include "downarticledlg.h"
47 
48 #include <sys/types.h>
49 #include <sys/wait.h>
50 #include <unistd.h>
51 #include <signal.h>
52 
53 #ifdef USE_NOTIFIER
54 #ifdef USE_LIBNOTIFY
55 #include <libnotify/notify.h>
56 #else
57 #include "notifier/api.h"
58 #endif
59 #endif
60 
61 #ifdef USE_SCRIPT
62 #include "script/api.h"
63 #endif
64 
65 const gchar COLOR_BLOCK[] = "\u2588\u2588\u2588\u2588\u2588\u2588";
66 
67 #ifdef USE_DOCKLET
68 #include "docklet/api.h"
69 
OnTrayButton_Toggled(GtkToggleButton * button UNUSED,CMainFrame * _this)70 void CMainFrame::OnTrayButton_Toggled(
71 	GtkToggleButton *button UNUSED,
72 	CMainFrame *_this)
73 {
74 	GtkToggleAction *action = (GtkToggleAction*) gtk_action_group_get_action(
75 				_this->m_ActionGroup, "showhide");
76 	gtk_toggle_action_set_active(action,
77 			! gtk_toggle_action_get_active(action));
78 }
79 
80 
OnShowHide(GtkToggleAction * toggleaction,CMainFrame * _this)81 void CMainFrame::OnShowHide(GtkToggleAction *toggleaction, CMainFrame *_this)
82 {
83 	bool show_tray_icon = AppConfig.ShowTrayIcon;
84 
85 	if (show_tray_icon)
86 	{
87 		if (gtk_toggle_action_get_active(toggleaction))
88 			_this->Show();
89 		else
90 			_this->Hide();
91 	}
92 	else
93 	{
94 		gtk_window_iconify((GtkWindow*)_this->m_Widget);
95 	}
96 }
97 #endif
98 
99 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
100 
OnToggleToolBar(GtkToggleAction * toggleaction,CMainFrame * _this)101 void CMainFrame::OnToggleToolBar(GtkToggleAction *toggleaction, CMainFrame *_this)
102 {
103 	AppConfig.ShowToolbar = gtk_toggle_action_get_active(toggleaction);
104 	if (AppConfig.ShowToolbar) {
105 		gtk_widget_show_all((GtkWidget *)_this->m_Toolbar);
106 	} else {
107 		gtk_widget_hide_all((GtkWidget *)_this->m_Toolbar);
108 	}
109 }
110 
OnToggleStatusBar(GtkToggleAction * toggleaction,CMainFrame * _this)111 void CMainFrame::OnToggleStatusBar(GtkToggleAction *toggleaction, CMainFrame *_this)
112 {
113 	AppConfig.ShowStatusBar = gtk_toggle_action_get_active(toggleaction);
114 	if (AppConfig.ShowStatusBar) {
115 		gtk_widget_show_all((GtkWidget *)_this->m_Statusbar);
116 	} else {
117 		gtk_widget_hide_all((GtkWidget *)_this->m_Statusbar);
118 	}
119 }
120 
121 /*
122 void CMainFrame::OnTrayButton_Changed(GtkWidget* widget, GtkAllocation *allocation, CMainFrame* _this)
123 {
124 	if (! _this->m_MainIcon)
125 		return;
126 	_this->set_tray_icon();
127 }
128 */
129 
130 #ifdef USE_DOCKLET
OnTray_Popup(GtkStatusIcon * status_icon UNUSED,guint button,guint activate_time,CMainFrame * _this)131 void CMainFrame::OnTray_Popup(GtkStatusIcon *status_icon UNUSED,
132                               guint button, guint activate_time,
133                               CMainFrame *_this)
134 {
135 	gtk_menu_popup((GtkMenu*)_this->m_TrayPopup, NULL, NULL, NULL, NULL
136 			, button, activate_time);
137 }
138 #endif
139 
140 CMainFrame* CMainFrame::g_pMyself = NULL;
141 
OnSize(GtkWidget * widget,GdkEventConfigure * evt,CMainFrame * _this UNUSED)142 gboolean CMainFrame::OnSize( GtkWidget* widget, GdkEventConfigure* evt,
143                              CMainFrame* _this UNUSED )
144 {
145 	gtk_window_get_position( GTK_WINDOW(widget), &AppConfig.MainWndX, & AppConfig.MainWndY );
146 	AppConfig.MainWndW = evt->width;
147 	AppConfig.MainWndH = evt->height;
148 	INFO("x=%d, y=%d, w=%d, h=%d", evt->x, evt->y, evt->width, evt->height );
149 	INFO("get_pos: x=%d, y=%d", AppConfig.MainWndX, AppConfig.MainWndY );
150 	return false;
151 }
152 
153 
CMainFrame()154 CMainFrame::CMainFrame()
155 {
156 	char* desktop = getenv("XDG_CURRENT_DESKTOP");
157 
158 	m_eView = NULL;
159 	m_pView = NULL;
160 	m_FavoritesMenuItem = NULL;
161 	m_FavoritesMenu = NULL;
162 	m_IsFlashing = false;
163 	m_Mode = NORMAL_MODE;
164 #ifdef USE_DOCKLET
165 	m_TrayIcon = NULL;
166 #endif
167 
168 	/* Detecting Unity desktop environment */
169 	if (desktop != NULL && strcmp("Unity", desktop) == 0) {
170 		m_Unity = true;
171 	} else {
172 		m_Unity = false;
173 	}
174 
175 	m_dlhandle = lt_dlopen("libappindicator.so.1");
176 
177 	m_Widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
178 	gtk_window_set_wmclass(GTK_WINDOW(m_Widget), "pcmanx", "PCManX");
179 
180 	PostCreate();
181 
182 #if defined(USE_DOCKLET) || defined(USE_NOTIFIER)
183 	/* We need to make sure m_MainIcon is null at startup. */
184 	m_MainIcon = (GdkPixbuf *) NULL;
185 #endif
186 
187 	LoadIcons();
188 
189 
190 	gtk_window_set_title (GTK_WINDOW (m_Widget), "PCManX " VERSION );
191 
192 	m_pNotebook = new CNotebook();
193 	gtk_notebook_set_scrollable(GTK_NOTEBOOK(m_pNotebook->m_Widget), TRUE);
194 	g_signal_connect( G_OBJECT(m_pNotebook->m_Widget), "button_press_event",
195 			G_CALLBACK(CMainFrame::OnNotebookPopupMenu), this );
196 
197 	MakeUI();
198 
199 
200 	gtk_window_set_icon((GtkWindow*)m_Widget, m_MainIcon);
201 
202 	GtkWidget* vbox = gtk_vbox_new(false, 0);
203 	gtk_widget_show (vbox);
204 
205 	//GtkWidget* m_Statusbar = gtk_statusbar_new ();
206 	m_Statusbar = gtk_statusbar_new ();
207 
208 	gtk_container_add(GTK_CONTAINER(m_Widget), vbox);
209 
210 	gtk_box_pack_start (GTK_BOX (vbox), m_Menubar, FALSE, FALSE, 0);
211 	gtk_box_pack_start (GTK_BOX (vbox), m_Toolbar, FALSE, FALSE, 0);
212 	if (AppConfig.ShowToolbar) {
213 		gtk_widget_show_all(m_Toolbar);
214 	} else {
215 		gtk_widget_hide_all(m_Toolbar);
216 	}
217 	gtk_box_pack_start (GTK_BOX (vbox), m_pNotebook->m_Widget, TRUE, TRUE, 0);
218 	gtk_widget_set_size_request(m_pNotebook->m_Widget, 300, 200);
219 	gtk_box_pack_start (GTK_BOX (vbox), m_Statusbar, FALSE, FALSE, 0);
220 
221 	// Tab key to quick switch keyboard focus to m_URLEntry
222 	GList *focus_chain = NULL;
223 	focus_chain = g_list_append(focus_chain, m_Toolbar);
224 	focus_chain = g_list_append(focus_chain, m_URLEntry);
225 	gtk_container_set_focus_chain(GTK_CONTAINER(vbox), focus_chain);
226 	g_list_free(focus_chain);
227 
228 
229 //	gtk_widget_grab_focus(m_pNotebook->m_Widget);
230 
231 //	GTK_WIDGET_UNSET_FLAGS(m_pNotebook->m_Widget, GTK_CAN_FOCUS);
232 //
233 	g_signal_connect(G_OBJECT(m_Widget), "window-state-event", G_CALLBACK(CMainFrame::OnWindowStateEvent), this);
234 
235 	g_signal_connect(G_OBJECT(m_Widget), "delete-event", G_CALLBACK(CMainFrame::OnClose), this);
236 
237 	g_signal_connect(m_pNotebook->m_Widget, "switch-page", G_CALLBACK(CMainFrame::OnNotebookChangeCurPage), this);
238 
239 	g_signal_connect(m_Widget, "configure-event", G_CALLBACK(CMainFrame::OnSize), this);
240 
241 	g_signal_connect(G_OBJECT(m_Widget), "focus-in-event", G_CALLBACK(CMainFrame::OnActivated), this);
242 
243 //	g_signal_connect(G_OBJECT(m_Widget), "focus-out-event", G_CALLBACK(CMainFrame::OnDeactivated), this);
244 
245 	gtk_box_set_spacing( GTK_BOX (m_Statusbar), 4 );
246 #ifdef USE_NANCY
247 	m_StatusBarBotState = (GtkLabel*)gtk_label_new("");
248 	gtk_box_pack_start (GTK_BOX (m_Statusbar), (GtkWidget*)m_StatusBarBotState, FALSE, FALSE, 2);
249 	GtkWidget* vsep = gtk_vseparator_new ();
250  	gtk_box_pack_start (GTK_BOX (m_Statusbar), vsep, FALSE, FALSE, 2);
251 #endif
252 	m_StatusBarTime = (GtkLabel*)gtk_label_new("");
253 	gtk_box_pack_start (GTK_BOX (m_Statusbar), (GtkWidget*)m_StatusBarTime, FALSE, FALSE, 2);
254 	if (AppConfig.ShowStatusBar) {
255 		gtk_widget_show_all(m_Statusbar);
256 	} else {
257 		gtk_widget_hide_all(m_Statusbar);
258 	}
259 
260 	m_BlinkTimer = g_timeout_add(600, (GSourceFunc)CMainFrame::OnBlinkTimer, this );
261 	m_EverySecondTimer = g_timeout_add(1000, (GSourceFunc)CMainFrame::OnEverySecondTimer, this );
262 
263 	CTelnetView::SetParentFrame(this);
264 	CTelnetView::SetWebBrowser(AppConfig.WebBrowser);
265 	CTelnetView::SetMailClient(AppConfig.MailClient);
266 
267 	if (AppConfig.Maximized) {
268 		gtk_window_maximize((GtkWindow*) m_Widget);
269 	}else{
270 		gtk_window_unmaximize((GtkWindow*) m_Widget);
271 	}
272 
273 	if(AppConfig.ShowInSimpleMode){
274 		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_action_group_get_action(m_ActionGroup, "simple")), true);
275 	}
276 }
277 
278 
NewCon(string title,string url,CSite * site)279 CTelnetCon* CMainFrame::NewCon(string title, string url, CSite* site )
280 {
281 	/* Remove leading and trailing spaces from url. */
282 	size_t first = url.find_first_not_of(" \t");
283 	size_t last = url.find_last_not_of(" \t");
284 	if (last >= first)
285 		url = url.substr(first, last - first + 1);
286 
287 	/* Remove telnet:// from url */
288 	const string telnetPrefix = "telnet://";
289 	if(url.substr(0, telnetPrefix.size()) == telnetPrefix)
290 		url.erase(0, telnetPrefix.size());
291 
292 	if ( site == NULL )
293 		site = &AppConfig.m_DefaultSite;
294 
295 	CTelnetCon* pCon;
296 	CEditor* pEditor;
297 
298 	/**
299 	*   Since CEditor is extended from CTelnetCon and CEditorView extended from CTelnetView,
300 	*   there are lots of settings can be reused below.
301 	*   Therefore, the differences only lie in the new instance part.
302 	*   We use the magic url "ansi_editor" to identify if the Editor instance should be created or not.
303 	*/
304 	if(url == "ansi_editor"){
305 		m_eView = new CEditorView;
306 		pEditor = new CEditor( m_eView, *site);
307 		pCon = pEditor;
308 		m_pView = m_eView;
309 	}else{
310 		m_pView = new CTelnetView;
311 		pCon = new CTelnetCon( m_pView, *site );
312 		pEditor = NULL;
313 	}
314 	m_Views.push_back(m_pView);
315 
316 	m_pView->m_pTermData = pCon;
317 	m_pView->SetContextMenu(m_EditMenu);
318 	m_pView->SetFont(AppConfig.FontFamily, AppConfig.FontSize, AppConfig.CompactLayout, AppConfig.AntiAliasFont, CTermView::FONT_DEFAULT);
319 	m_pView->SetFont(AppConfig.FontFamilyEn, AppConfig.FontSizeEn, AppConfig.CompactLayout, AppConfig.AntiAliasFont, CTermView::FONT_EN);
320 	m_pView->SetHyperLinkColor( &AppConfig.HyperLinkColor );
321 	m_pView->SetHorizontalCenterAlign( site->m_bHorizontalCenterAlign );
322 	m_pView->SetVerticalCenterAlign( site->m_bVerticalCenterAlign );
323 	m_pView->m_CharPaddingX = AppConfig.CharPaddingX;
324 	m_pView->m_CharPaddingY = AppConfig.CharPaddingY;
325 
326 	pCon->m_Site.m_Name = title;
327 	pCon->m_Site.m_URL = url;
328 	pCon->m_Encoding = pCon->m_Site.m_Encoding;
329 
330 	m_pView->SetUAO( site->m_UAO );
331 
332 	pCon->AllocScreenBuf( site->m_RowsPerPage, site->m_RowsPerPage, site->m_ColsPerPage );
333 
334 	int idx = m_pNotebook->AddPage( m_pView, title, true );
335 	m_pNotebook->SetCurPage(idx);
336 	m_pView->SetFocus();
337 
338 	if(url == "ansi_editor"){
339 		pEditor->EditorActions(CEditor::Init_Ansi_Editor);
340 	}else{
341 		pCon->Connect();
342 	}
343 
344 	return pCon;
345 }
346 
347 
348 #ifdef USE_NANCY
349 GtkRadioActionEntry CMainFrame::cur_bot_entries[] =
350   {
351     {"disable_cur_bot", NULL, _("Disable Bot"), NULL, NULL, 0},
352     {"nancy_bot_current", NULL, _("Nancy Bot"), NULL, NULL, 1}
353   };
354 
355 GtkRadioActionEntry CMainFrame::all_bot_entries[] =
356   {
357     {"disable_all_bot", NULL, _("Disable Bot"), NULL, NULL, 0},
358     {"nancy_bot_all", NULL, _("Nancy Bot"), NULL, NULL, 1}
359   };
360 #endif
361 
362 static const char *ui_info =
363   "<ui>"
364   "  <menubar>"
365   "    <menu action='connect_menu'>"
366   "      <menuitem action='site_list'/>"
367   "      <menuitem action='new_con'/>"
368   "      <menuitem action='reconnect'/>"
369   "      <menuitem action='close'/>"
370   "      <separator/>"
371   "      <menuitem action='next_con'/>"
372   "      <menuitem action='previous_con'/>"
373   " <menuitem action='first_con'/>"
374   " <menuitem action='last_con'/>"
375   "      <menuitem action='jump'/>"
376   "      <separator/>"
377   "      <menuitem action='quit'/>"
378   "    </menu>"
379   "    <menu action='edit_menu'>"
380   "      <menuitem action='copy'/>"
381   "      <menuitem action='copy_with_ansi'/>"
382   "      <menuitem action='paste'/>"
383   "      <menuitem action='paste_from_clipboard'/>"
384   "      <menuitem action='select_all'/>"
385   "      <menuitem action='down_article'/>"
386   "      <separator/>"
387   "      <menuitem action='emoticon'/>"
388   "      <menuitem action='preference'/>"
389   "    </menu>"
390   "    <menu action='favorites_menu'>"
391   "      <separator/>"
392   "      <menuitem action='add_to_fav'/>"
393   "      <menuitem action='edit_fav'/>"
394   "    </menu>"
395   "    <menu action='view_menu'>"
396   "      <menuitem action='ascii_font'/>"
397   "      <menuitem action='non_ascii_font'/>"
398   "      <separator/>"
399   "      <menuitem action='toolbar'/>"
400   "      <menuitem action='statusbar'/>"
401   "      <separator/>"
402 #ifdef USE_DOCKLET
403   "      <menuitem action='showhide'/>"
404 #endif
405   "      <menuitem action='fullscreen' />"
406   "      <menuitem action='simple' />"
407 #ifdef USE_NANCY
408   "      <separator/>"
409   "      <menu action='cur_bot_menu'>"
410   "        <menuitem action='disable_cur_bot'/>"
411   "        <menuitem action='nancy_bot_current'/>"
412   "      </menu>"
413   "      <menu action='all_bot_menu'>"
414   "        <menuitem action='disable_all_bot'/>"
415   "        <menuitem action='nancy_bot_all'/>"
416   "      </menu>"
417 #endif
418   "    </menu>"
419   "    <menu action='menu_ansi_editor'>"
420   "      <menuitem action='openAnsiEditor'/>"
421   "      <separator/>"
422   "      <menuitem action='openAnsiFile'/>"
423   "      <menuitem action='saveAnsiFile'/>"
424   "      <menuitem action='clearScreen'/>"
425   "    </menu>"
426   "    <menu action='help_menu'>"
427   "      <menuitem action='shortcut_list'/>"
428   "      <menuitem action='about'/>"
429   "    </menu>"
430   "  </menubar>"
431   "  <toolbar>"
432   "    <separator/>"
433   "    <toolitem action='site_list'/>"
434   "    <toolitem action='new_con'/>"
435   "    <toolitem action='reconnect'/>"
436   "    <toolitem action='close'/>"
437   "    <separator/>"
438   "    <toolitem action='copy'/>"
439   "    <toolitem action='copy_with_ansi'/>"
440   "    <toolitem action='paste'/>"
441   "    <toolitem action='down_article'/>"
442   "    <separator/>"
443   "    <toolitem action='add_to_fav'/>"
444   "    <toolitem action='preference'/>"
445   "    <toolitem action='about'/>"
446   "    <separator/>"
447   "  </toolbar>"
448   "  <popup name='edit_popup'>"
449   "    <menuitem action='copy'/>"
450   "    <menuitem action='copy_with_ansi'/>"
451   "    <menuitem action='paste'/>"
452   "    <menuitem action='paste_from_clipboard'/>"
453   "    <menuitem action='select_all'/>"
454   "    <separator/>"
455   "    <menuitem action='fullscreen' />"
456   "    <menuitem action='simple' />"
457   "    <separator/>"
458   "  </popup>"
459 #if defined(USE_DOCKLET)
460   "  <popup name='tray_popup'>"
461   "    <menuitem action='showhide' />"
462   "    <separator />"
463   "    <menuitem action='quit'/>"
464   "  </popup>"
465   " <accelerator action='showhide' />"
466 #endif
467 
468   // alternative accelerators
469   " <accelerator action='close2'/>"
470   " <accelerator action='reconnect1'/>"
471   " <accelerator action='next_con1'/>"
472   " <accelerator action='previous_con1'/>"
473   " <accelerator action='new_con_gnome_term_sty'/>"
474   " <accelerator action='next_con_gnome_term_sty'/>"
475   " <accelerator action='previous_con_gnome_term_sty'/>"
476   " <accelerator action='copy_gnome_term_sty'/>"
477   " <accelerator action='paste_gnome_term_sty'/>"
478   "</ui>";
479 
MakeUI()480 void CMainFrame::MakeUI()
481 {
482 	m_ActionGroup = gtk_action_group_new("GlobalActions");
483 
484 	gtk_action_group_set_translation_domain(m_ActionGroup, GETTEXT_PACKAGE);
485 
486 
487 	//move m_ActionEntries from class member to local.
488 	GtkActionEntry actionEntries[] =
489 	  {
490 		{"connect_menu", NULL, _("_Connect"), NULL, NULL, NULL},
491 		{"site_list", GTK_STOCK_OPEN, _("_Site List"), AppConfig.keySiteList.data(), _("Site List"), G_CALLBACK (CMainFrame::OnSiteList)},
492 		{"new_con", GTK_STOCK_NETWORK, _("_New Connection"), AppConfig.keyNewConn0.c_str(), _("New Connection"), G_CALLBACK (CMainFrame::OnNewCon)},
493 		{"new_con_gnome_term_sty", GTK_STOCK_NETWORK, _("_New Connection"), AppConfig.keyNewConn1.data(), _("New Connection"), G_CALLBACK (CMainFrame::OnNewCon)},
494 		{"reconnect", GTK_STOCK_UNDO, _("_Reconnect"), AppConfig.keyReconn0.data(), _("Reconnect"), G_CALLBACK (CMainFrame::OnReconnect)},
495 		{"reconnect1",GTK_STOCK_UNDO, _("_Reconnect"), AppConfig.keyReconn1.data(), _("Reconnect"), G_CALLBACK(CMainFrame::OnReconnect)},
496 		{"close", GTK_STOCK_CLOSE, _("_Close Connection"), AppConfig.keyClose0.data(), _("Close Connection"), G_CALLBACK (CMainFrame::OnCloseCon)},
497 		{"close2", GTK_STOCK_CLOSE, _("_Close Connection"), AppConfig.keyClose1.data(), _("Close Connection"), G_CALLBACK(CMainFrame::OnCloseCon)},
498 		{"next_con", GTK_STOCK_GO_DOWN, _("Ne_xt Page"), AppConfig.keyNextPage.data(), _("Next Page"), G_CALLBACK (CMainFrame::OnNextCon)},
499 		{"next_con1", GTK_STOCK_GO_DOWN, _("Ne_xt Page"), "<Ctrl>Right", _("Next Page"), G_CALLBACK(CMainFrame::OnNextCon)},
500 		{"next_con_gnome_term_sty", GTK_STOCK_GO_DOWN, _("Ne_xt Page"), "<Ctrl>Page_Down", _("Next Page"), G_CALLBACK(CMainFrame::OnNextCon)},
501 		{"previous_con", GTK_STOCK_GO_UP, _("_Previous Page"), AppConfig.keyPrevPage.data(), _("Previous Page"), G_CALLBACK (CMainFrame::OnPrevCon)},
502 		{"previous_con1", GTK_STOCK_GO_UP, _("_Previous Page"), "<Ctrl>Left", _("Previous Page"), G_CALLBACK(CMainFrame::OnPrevCon)},
503 		{"previous_con_gnome_term_sty", GTK_STOCK_GO_UP, _("_Previous Page"), "<Ctrl>Page_Up", _("Previous Page"), G_CALLBACK(CMainFrame::OnPrevCon)},
504 		{"first_con",GTK_STOCK_GO_UP, _("_First Page"), AppConfig.keyFirstPage.data(), _("First Page"), G_CALLBACK(CMainFrame::OnFirstCon)},
505 		{"last_con", GTK_STOCK_GO_DOWN, _("_Last Page"), AppConfig.keyLastPage.data(), _("Last Page"), G_CALLBACK(CMainFrame::OnLastCon)},
506 		{"jump", GTK_STOCK_JUMP_TO, _("_Jump to"), NULL, NULL, NULL},
507 		{"quit", GTK_STOCK_QUIT, _("_Quit"), "", _("Quit"), G_CALLBACK (CMainFrame::OnQuit)},
508 		{"edit_menu", NULL, _("_Edit"), NULL, NULL, NULL},
509 		{"copy", GTK_STOCK_COPY, _("_Copy"), AppConfig.keyCopy0.data(), _("Copy"), G_CALLBACK (CMainFrame::OnCopy)},
510 		{"copy_gnome_term_sty", GTK_STOCK_COPY, _("_Copy"), AppConfig.keyCopy1.data(), _("Copy"), G_CALLBACK (CMainFrame::OnCopy)},
511 		{"copy_with_ansi", GTK_STOCK_SELECT_COLOR, _("Copy with A_NSI Color"), NULL, _("Copy with ANSI Color"), G_CALLBACK (CMainFrame::OnCopyWithColor)},
512 		{"paste", GTK_STOCK_PASTE, _("_Paste"), AppConfig.keyPaste0.data(), _("Paste"), G_CALLBACK (CMainFrame::OnPaste)},
513 		{"paste_gnome_term_sty", GTK_STOCK_PASTE, _("_Paste"), AppConfig.keyPaste1.data(), _("Paste"), G_CALLBACK (CMainFrame::OnPaste)},
514 		{"paste_from_clipboard", GTK_STOCK_PASTE, _("Paste from Clipboard"), AppConfig.keyPasteClipboard.data(), NULL, G_CALLBACK (CMainFrame::pasteFromClipboard)},
515 		{"down_article", GTK_STOCK_SELECT_ALL, _("_Download Article"), NULL, _("Download Article"), G_CALLBACK (CMainFrame::OnDownArticle)},
516 		{"select_all", NULL, _("Select A_ll"), NULL, NULL, G_CALLBACK (CMainFrame::OnSelectAll)},
517 		{"emoticon", NULL, _("_Emoticons"), AppConfig.keyEmotions.data(), NULL, G_CALLBACK (CMainFrame::OnEmoticons)},
518 		{"preference", GTK_STOCK_PREFERENCES, _("_Preference"), NULL, _("Preference"), G_CALLBACK (CMainFrame::OnPreference)},
519 		{"favorites_menu", NULL, _("F_avorites"), NULL, NULL, NULL},
520 		{"add_to_fav", GTK_STOCK_ADD, _("_Add to Favorites"), NULL, _("Add to Favorites"), G_CALLBACK (CMainFrame::OnAddToFavorites)},
521 		{"edit_fav", GTK_STOCK_EDIT, _("_Edit Favorites"), NULL, NULL, G_CALLBACK (CMainFrame::OnEditFavorites)},
522 		{"view_menu", NULL, _("_View"), NULL, NULL, NULL},
523 		{"ascii_font", GTK_STOCK_SELECT_FONT, _("_ASCII Font"), NULL, NULL, G_CALLBACK (CMainFrame::OnFont)},
524 		{"non_ascii_font", GTK_STOCK_SELECT_FONT,  _("Non-ASCII _Font"), NULL, NULL, G_CALLBACK (CMainFrame::OnFont)},
525 	#ifdef USE_NANCY
526 		{"cur_bot_menu", GTK_STOCK_EXECUTE, _("Bot (Current Connection)"), NULL, NULL, NULL},
527 		{"all_bot_menu", GTK_STOCK_EXECUTE, _("Bot (All Opened Connections)"), NULL, NULL, NULL},
528 	#endif
529 		{"help_menu", NULL, _("_Help"), NULL, NULL, NULL},
530 		{"shortcut_list", GTK_STOCK_DIALOG_INFO,  _("_Shortcut List"), NULL, NULL, G_CALLBACK (CMainFrame::OnShortcutList)},
531 		{"about", GTK_STOCK_ABOUT, NULL, NULL, _("About"), G_CALLBACK (CMainFrame::OnAbout)},
532 		// Ansi Editor Menu
533 		{"menu_ansi_editor", NULL, _("Ansi Editor"), NULL, NULL, NULL},
534 		{"openAnsiEditor", NULL, _("Open Ansi Editor"), NULL, NULL, G_CALLBACK (CMainFrame::OnAnsiEditor)},
535 		{"openAnsiFile", NULL, _("Open Ansi File"), NULL, NULL, G_CALLBACK (CMainFrame::OnOpenAnsiFile)},
536 		{"saveAnsiFile", NULL, _("Save Ansi File"), NULL, NULL, G_CALLBACK (CMainFrame::OnSaveAnsiFile)},
537 		{"clearScreen", NULL, _("Clear Screen"), NULL, NULL, G_CALLBACK (CMainFrame::OnClearScreen)}
538 	  };
539 
540 		//move m_ToggleActionEntries from class member to local
541 		GtkToggleActionEntry ToggleActionEntries[] =
542 		{
543 	#ifdef USE_DOCKLET
544 		// Show/Hide Main Window
545 		{"showhide", NULL, _("Show _Main Window"), "<Alt>M", NULL, G_CALLBACK(CMainFrame::OnShowHide), true},
546 	#endif
547 		{"toolbar", NULL, _("Show Toolbar"), NULL, NULL, G_CALLBACK (CMainFrame::OnToggleToolBar), true},
548 		{"statusbar", NULL, _("Show Status Bar on bottom"), NULL, NULL, G_CALLBACK (CMainFrame::OnToggleStatusBar), true},
549 		{"fullscreen", NULL, _("F_ullscreen Mode"), AppConfig.keyFullscreen.data(), NULL, G_CALLBACK (CMainFrame::OnFullscreenMode), false},
550 		{"simple", NULL, _("_Simple Mode"), AppConfig.keySimpleMode.data(), NULL, G_CALLBACK (CMainFrame::OnSimpleMode), false},
551 		};
552 
553 	gtk_action_group_add_actions(m_ActionGroup, actionEntries, G_N_ELEMENTS(actionEntries), this);
554 
555 	gtk_action_group_add_toggle_actions(m_ActionGroup, ToggleActionEntries,
556 			G_N_ELEMENTS(ToggleActionEntries), this);
557 
558 #ifdef USE_NANCY
559 	gtk_action_group_add_radio_actions(m_ActionGroup,
560 			cur_bot_entries,
561 			G_N_ELEMENTS(cur_bot_entries),
562 			0,
563 			G_CALLBACK (CMainFrame::OnChangeCurrentBot),
564 			this);
565 	gtk_action_group_add_radio_actions(m_ActionGroup,
566 			all_bot_entries,
567 			G_N_ELEMENTS(all_bot_entries),
568 			0,
569 			G_CALLBACK (CMainFrame::OnChangeAllBot),
570 			this);
571 #endif
572 
573 	m_UIManager = gtk_ui_manager_new();
574 	gtk_ui_manager_insert_action_group(m_UIManager, m_ActionGroup, 0);
575 
576 	GtkAccelGroup* accel_group = gtk_ui_manager_get_accel_group ( m_UIManager );
577 	gtk_window_add_accel_group (GTK_WINDOW (m_Widget), accel_group);
578 
579 	GError * error = NULL;
580 	if (!gtk_ui_manager_add_ui_from_string(m_UIManager, ui_info, -1, & error))
581 	{
582 		g_message("Building menu failed : %s", error->message);
583 		g_error_free(error); exit(EXIT_FAILURE);
584 	}
585 
586 	m_Menubar = gtk_ui_manager_get_widget (m_UIManager, "/ui/menubar");
587 	m_Toolbar = gtk_ui_manager_get_widget (m_UIManager, "/ui/toolbar");
588 	gtk_toolbar_set_style( (GtkToolbar*)m_Toolbar, GTK_TOOLBAR_ICONS );
589 
590 	m_EditMenu = gtk_ui_manager_get_widget (m_UIManager, "/ui/edit_popup");
591 
592 	m_FavoritesMenuItem = gtk_ui_manager_get_widget (m_UIManager, "/ui/menubar/favorites_menu");
593 
594 #ifdef USE_NANCY
595 
596 	m_DisableCurBotRadio = (GtkRadioMenuItem*) gtk_ui_manager_get_widget (m_UIManager,
597 			"/ui/menubar/view_menu/cur_bot_menu/disable_cur_bot");
598 	m_CurBotNancyRadio = (GtkRadioMenuItem*) gtk_ui_manager_get_widget (m_UIManager,
599 			"/ui/menubar/view_menu/cur_bot_menu/nancy_bot_current");
600 
601 	m_DisableAllBotRadio = (GtkRadioMenuItem*) gtk_ui_manager_get_widget (m_UIManager,
602 			"/ui/menubar/view_menu/all_bot_menu/disable_all_bot");
603 	m_AllBotNancyRadio = (GtkRadioMenuItem*) (gtk_ui_manager_get_widget (m_UIManager,
604 				"/ui/menubar/view_menu/all_bot_menu/nancy_bot_all"));
605 
606 #endif
607 
608 	GtkWidget* jump = gtk_ui_manager_get_widget (m_UIManager, "/ui/menubar/connect_menu/jump");
609 
610 	GtkWidget* jump_menu = gtk_menu_new ();
611 	gtk_menu_item_set_submenu (GTK_MENU_ITEM (jump), jump_menu);
612 
613 	const char* page_str = _("Page");
614 	for(int i = 1; i < 11; i++)
615 	{
616 		char title[32], name[32];
617 		sprintf(title, "%s %d_%d", page_str, i / 10, i % 10);
618 		sprintf(name, "jumpto_%d", i);
619 		GtkAction *action = gtk_action_new(name, title, NULL, NULL);
620 		gtk_action_set_accel_group(action, accel_group);
621 		g_signal_connect( G_OBJECT(action), "activate",
622 				G_CALLBACK (CMainFrame::OnJumpToPage),
623 				this);
624 		sprintf(name, "<Alt>%d", i % 10);
625 		gtk_action_group_add_action_with_accel(m_ActionGroup, action, name);
626 		gtk_container_add (GTK_CONTAINER (jump_menu),
627 				gtk_action_create_menu_item(action));
628 		m_JumpTos[i-1] = G_OBJECT(action);
629 	}
630 
631 	// Ansi Editor widget: blink check box, click to set the text blink.
632 	m_chkBlink = gtk_check_button_new_with_label("blink");
633 	GtkToolItem *itemBlink = gtk_tool_item_new();
634 	gtk_container_add(GTK_CONTAINER(itemBlink), m_chkBlink);
635 	gtk_widget_show_all ( (GtkWidget*)itemBlink);
636 	gtk_toolbar_insert(GTK_TOOLBAR(m_Toolbar), itemBlink, -1);
637 
638 	// Ansi Editor widget: Set Text color.
639 	GtkTreeModel *model;
640 	model = GTK_TREE_MODEL(gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING));
641 	m_cbTextColor = gtk_combo_box_new_with_model(model);
642 
643 	GtkCellRenderer *cell;
644 	cell = gtk_cell_renderer_text_new();
645 	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(m_cbTextColor), cell, TRUE);
646 	gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(m_cbTextColor), cell, "text", 0);
647 	gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(m_cbTextColor), cell, "foreground", 1);
648 
649 	GtkTreeIter iter;
650 	GtkListStore *store = GTK_LIST_STORE(model);
651 	gtk_list_store_append(store, &iter);
652 	gtk_list_store_set(store, &iter, 0, "Front", 1, "#000000", -1);
653 
654 	for (int i = 0; i < 16; i++)
655 	{
656 		gchar color[8];
657 		ParseColor(&(CTermCharAttr::m_DefaultColorTable[i]), color, ARRAY_SIZE(color));
658 		AppendRow(&iter, store, COLOR_BLOCK, color);
659 	}
660 	gtk_combo_box_set_active(GTK_COMBO_BOX(m_cbTextColor), 0);
661 
662 	GtkToolItem *itemTextColor = gtk_tool_item_new();
663 	gtk_container_add(GTK_CONTAINER(itemTextColor), m_cbTextColor);
664 	gtk_widget_show_all ( (GtkWidget*)itemTextColor);
665 	gtk_toolbar_insert(GTK_TOOLBAR(m_Toolbar), itemTextColor, -1);
666 
667 	// Ansi Editor widget: Set Background color.
668 	GtkTreeModel *model_back;
669 	model_back = GTK_TREE_MODEL(gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING));
670 	m_cbBgColor = gtk_combo_box_new_with_model(model_back);
671 
672 	GtkCellRenderer *cell_back;
673 	cell_back = gtk_cell_renderer_text_new();
674 	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(m_cbBgColor), cell_back, TRUE);
675 	gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(m_cbBgColor), cell_back, "text", 0);
676 	gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(m_cbBgColor), cell_back, "foreground", 1);
677 
678 	GtkTreeIter iter_back;
679 	GtkListStore *store_back = GTK_LIST_STORE(model_back);
680 	gtk_list_store_append(store_back, &iter_back);
681 	gtk_list_store_set(store_back, &iter_back, 0, "Background", 1, "#000000", -1);
682 
683 	for (int i = 0; i < 8; i++)
684 	{
685 		gchar color[8];
686 		ParseColor(&(CTermCharAttr::m_DefaultColorTable[i]), color, ARRAY_SIZE(color));
687 		AppendRow(&iter_back, store_back, COLOR_BLOCK, color);
688 	}
689 	gtk_combo_box_set_active(GTK_COMBO_BOX(m_cbBgColor), 0);
690 
691 	GtkToolItem *itemBgColor = gtk_tool_item_new();
692 	gtk_container_add(GTK_CONTAINER(itemBgColor), m_cbBgColor);
693 	gtk_widget_show_all ( (GtkWidget*)itemBgColor);
694 	gtk_toolbar_insert(GTK_TOOLBAR(m_Toolbar), itemBgColor, -1);
695 
696 	GtkWidget* sep = (GtkWidget*)gtk_separator_tool_item_new();
697 	gtk_widget_show(sep);
698 	gtk_container_add (GTK_CONTAINER (m_Toolbar), sep);
699 	// Create the URL address bar
700 	GtkWidget* url_bar = gtk_hbox_new (FALSE, 0);
701 	GtkWidget* url_label = (GtkWidget*) gtk_label_new_with_mnemonic(_("A_ddress:"));
702 	m_URLEntry = (GtkWidget*) gtk_entry_new();
703 	gtk_widget_set_size_request(m_URLEntry, 0, -1);
704 	GtkTooltips* tooltips = gtk_tooltips_new();
705 	gtk_tooltips_set_tip(tooltips, m_URLEntry, _("Type URL here, then hit \"Enter\""), NULL);
706 	gtk_label_set_mnemonic_widget(GTK_LABEL(url_label), m_URLEntry);
707 	gtk_box_pack_start( GTK_BOX(url_bar), url_label, FALSE, FALSE, 4);
708 	gtk_box_pack_start( GTK_BOX(url_bar), m_URLEntry, TRUE, TRUE, 4);
709 
710 	GtkToolItem* url_bar_item = gtk_tool_item_new();
711 	gtk_tool_item_set_expand(url_bar_item, true);
712 	gtk_container_add (GTK_CONTAINER (url_bar_item), url_bar);
713 	gtk_widget_show_all ( (GtkWidget*)url_bar_item);
714 	gtk_toolbar_insert(GTK_TOOLBAR(m_Toolbar), url_bar_item, -1);
715 
716 	g_signal_connect ((gpointer) m_URLEntry, "key-press-event",
717 			G_CALLBACK (CMainFrame::OnURLEntryKeyDown),
718 			this);
719 	g_signal_connect ((gpointer) m_URLEntry, "focus-out-event",
720 			G_CALLBACK (CMainFrame::OnURLEntryKillFocus),
721 			this);
722 
723 	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_action_group_get_action(m_ActionGroup, "toolbar")), AppConfig.ShowToolbar);
724 	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_action_group_get_action(m_ActionGroup, "statusbar")), AppConfig.ShowStatusBar);
725 
726 	// Ansi Editor widget events
727 	g_signal_connect(GTK_OBJECT(m_cbTextColor), "changed", G_CALLBACK(SetTextColor), this);
728 	g_signal_connect(GTK_OBJECT(m_cbBgColor), "changed", G_CALLBACK(SetBgColor), this);
729 	g_signal_connect(GTK_OBJECT(m_chkBlink), "toggled", G_CALLBACK(SetBlink), this);
730 
731 	CreateFavoritesMenu();
732 	CreateTrayIcon();
733 }
734 
OnNewCon(GtkMenuItem * mitem UNUSED,CMainFrame * _this)735 void CMainFrame::OnNewCon(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
736 {
737 	CInputDialog* dlg = new CInputDialog( _this, _("Connect"), _("Host IP Address:\nAppend port number to IP with a separating colon if it's not 23."), NULL, true );
738 	if( dlg->ShowModal() == GTK_RESPONSE_OK && !dlg->GetText().empty() )
739 	{
740 		_this->NewCon( dlg->GetText(), dlg->GetText() );
741 	}
742 	dlg->Destroy();
743 }
744 
OnQuit(GtkMenuItem * mitem UNUSED,CMainFrame * _this)745 void CMainFrame::OnQuit(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
746 {
747 	if( _this->CanClose() )
748 	{
749 		_this->Hide();
750 		_this->Destroy();
751 	}
752 }
753 
inverse_pixbuf(GdkPixbuf * pixbuf)754 static void inverse_pixbuf(GdkPixbuf* pixbuf)
755 {
756 	int x = 0, y = 0;
757 	int channels = gdk_pixbuf_get_n_channels(pixbuf);
758 	int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
759 	int width = gdk_pixbuf_get_width(pixbuf);
760 	int height = gdk_pixbuf_get_height(pixbuf);
761 	guchar *pixels = gdk_pixbuf_get_pixels(pixbuf);
762 	for (x = 0; x < width; x++) {
763 		for (y = 0; y < height; y++) {
764 			guchar *ptr = pixels + y * rowstride + x * channels;
765 			ptr[0] ^= 0xFF; //red
766 			ptr[1] ^= 0xFF; //green
767 			ptr[2] ^= 0xFF; //blue
768 		}
769 	}
770 	return;
771 }
772 
LoadIcons()773 void CMainFrame::LoadIcons()
774 {
775 	GtkImage* image = GTK_IMAGE(gtk_image_new_from_file(DATADIR "/pixmaps/pcmanx.svg"));
776 	GdkPixbuf* icon = gtk_image_get_pixbuf(image);
777 	if (icon) {
778 		m_MainIcon = gdk_pixbuf_scale_simple(icon, 32, 32, GDK_INTERP_BILINEAR);
779 		m_InverseMainIcon = gdk_pixbuf_copy(m_MainIcon);
780 		inverse_pixbuf(m_InverseMainIcon);
781 		g_object_unref(icon);
782 	} else {
783 		m_MainIcon = NULL;
784 		m_InverseMainIcon = NULL;
785 	}
786 }
787 
OnFont(GtkMenuItem * mitem UNUSED,CMainFrame * _this)788 void CMainFrame::OnFont(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
789 {
790 	GtkWidget* dlg = gtk_font_selection_dialog_new(_("Font"));
791 	gtk_window_set_modal( (GtkWindow*)dlg, true);
792 	gtk_window_set_transient_for( (GtkWindow*)dlg, (GtkWindow*)_this->m_Widget);
793 
794 	GtkFontSelectionDialog* fsdlg = (GtkFontSelectionDialog*)dlg;
795 	GtkWidget* apply_to_all = gtk_check_button_new_with_label( _("Apply to all opened pages") );
796 	gtk_widget_show(apply_to_all);
797 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(apply_to_all), true);
798 	gtk_box_pack_start( GTK_BOX(fsdlg->action_area), apply_to_all, true, true, 4);
799 	gtk_box_reorder_child( GTK_BOX(fsdlg->action_area), apply_to_all, 0 );
800 	gtk_box_set_homogeneous(GTK_BOX(fsdlg->action_area), false);
801 
802 	// This is not a good method because fontsel is a private member of GtkFontSelectionDialog.
803 	// But we need this functionality.
804 	GtkFontSelection* fontsel = GTK_FONT_SELECTION(fsdlg->fontsel);
805 	gtk_widget_set_sensitive(fontsel->face_list, false);
806 
807 	char pango_font_name[32];
808 	int *font_size = NULL;
809 	string *font_family = NULL;
810 	int font_type;
811 	const char *font_action = gtk_action_get_name(GTK_ACTION(mitem));
812 	if (!strcmp(font_action, "non_ascii_font")) {
813 		font_size = &AppConfig.FontSize;
814 		font_family = &AppConfig.FontFamily;
815 		font_type = CTermView::FONT_DEFAULT;
816         }
817 	else if (!strcmp(font_action, "ascii_font")) {
818 		font_size = &AppConfig.FontSizeEn;
819 		font_family = &AppConfig.FontFamilyEn;
820 		font_type = CTermView::FONT_EN;
821 	}
822 	else {
823 		g_assert_not_reached();
824 	}
825 
826 	sprintf( pango_font_name, "%s %d", (*font_family).c_str(), (*font_size > 6 && *font_size <= 72) ? *font_size : 12 );
827 	gtk_font_selection_dialog_set_font_name(fsdlg, pango_font_name);
828 
829 	if( gtk_dialog_run((GtkDialog*)dlg) == GTK_RESPONSE_OK )
830 	{
831 		gchar* name = gtk_font_selection_dialog_get_font_name( fsdlg );
832 		PangoFontDescription* desc = pango_font_description_from_string( name );
833 		g_free( name );
834 		const char* family = pango_font_description_get_family(desc);
835 		*font_family = family;
836 		*font_size = pango_font_description_get_size(desc) / PANGO_SCALE;
837 		pango_font_description_free(desc);
838 
839 		if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(apply_to_all) ) )
840 		{
841 			vector<CTelnetView*>::iterator it;
842 			for( it = _this->m_Views.begin(); it != _this->m_Views.end(); ++it )
843 				(*it)->SetFontFamily(*font_family, font_type);
844 			/// FIXME: Poor design! Different connection must be allowed to use different fonts in the future.
845 		}
846 		else if( _this->GetCurView() )
847 			_this->GetCurView()->SetFontFamily(*font_family, font_type);
848 
849 		gtk_widget_destroy(dlg);
850 
851 		if( _this->GetCurView() )
852 			_this->GetCurView()->Refresh();
853 	}
854 	else
855 		gtk_widget_destroy(dlg);
856 }
857 
OnFullscreenMode(GtkMenuItem * mitem UNUSED,CMainFrame * _this)858 void CMainFrame::OnFullscreenMode(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
859 {
860 	if(_this->m_Mode == SIMPLE_MODE) {
861 		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_action_group_get_action(_this->m_ActionGroup, "simple")), false);
862 	}
863 
864 	if (_this->m_Mode != FULLSCREEN_MODE) {
865 		_this->m_Mode = FULLSCREEN_MODE;
866 		gtk_window_fullscreen((GtkWindow *)_this->m_Widget);
867 		gtk_widget_hide_all((GtkWidget *)_this->m_Menubar);
868 		gtk_widget_hide_all((GtkWidget *)_this->m_Toolbar);
869 		gtk_widget_hide_all((GtkWidget *)_this->m_Statusbar);
870 		_this->m_pNotebook->HideTabs();
871 	} else {
872 		_this->m_Mode = NORMAL_MODE;
873 		gtk_window_unfullscreen((GtkWindow *)_this->m_Widget);
874 		gtk_widget_show_all((GtkWidget *)_this->m_Menubar);
875 		if (AppConfig.ShowToolbar)
876 			gtk_widget_show_all((GtkWidget *)_this->m_Toolbar);
877 		if (AppConfig.ShowStatusBar)
878 			gtk_widget_show_all((GtkWidget *)_this->m_Statusbar);
879 		_this->m_pNotebook->ShowTabs();
880 	}
881 }
882 
OnSimpleMode(GtkMenuItem * mitem UNUSED,CMainFrame * _this)883 void CMainFrame::OnSimpleMode(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
884 {
885 	if(_this->m_Mode == FULLSCREEN_MODE) {
886 		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_action_group_get_action(_this->m_ActionGroup, "fullscreen")), false);
887 	}
888 
889 	if (_this->m_Mode != SIMPLE_MODE) {
890 		_this->m_Mode = SIMPLE_MODE;
891 		gtk_window_unfullscreen((GtkWindow *)_this->m_Widget);
892 		if (_this->m_Unity == false) {
893 		    gtk_widget_hide_all((GtkWidget *)_this->m_Menubar);
894 		}
895 		gtk_widget_hide_all((GtkWidget *)_this->m_Toolbar);
896 		gtk_widget_hide_all((GtkWidget *)_this->m_Statusbar);
897 		_this->m_pNotebook->HideTabs();
898 	} else {
899 		_this->m_Mode = NORMAL_MODE;
900 		gtk_window_unfullscreen((GtkWindow *)_this->m_Widget);
901 		if (_this->m_Unity == false) {
902 		    gtk_widget_show_all((GtkWidget *)_this->m_Menubar);
903 		}
904 		if (AppConfig.ShowToolbar)
905 			gtk_widget_show_all((GtkWidget *)_this->m_Toolbar);
906 		if (AppConfig.ShowStatusBar)
907 			gtk_widget_show_all((GtkWidget *)_this->m_Statusbar);
908 		_this->m_pNotebook->ShowTabs();
909 	}
910 }
911 
OnShortcutList(GtkMenuItem * mitem UNUSED,CMainFrame * _this)912 void CMainFrame::OnShortcutList(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
913 {
914 	char* connect_shortcuts= _(
915 			"Site List	Alt+S\n\n"
916 			"New Connection	Alt+Q\n"
917 			"New Connection	Ctrl+Shift+T\n\n"
918 			"Reconnection	Alt+R\n"
919 			"Reconnection   Ctrl+Ins\n\n"
920 			"Close		Alt+W\n"
921 			"Close		Ctrl+Del\n\n"
922 			"Next Page	Alt+X\n"
923 			"Next Page	Alt+?\n"
924 			"Next Page	Ctrl+Shift+PgDn\n\n"
925 			"Previous Page	Alt+Z\n"
926 			"Previous Page	Alt+?\n"
927 			"Previous Page	Ctrl+Shift+PgUp\n\n"
928 			"First Page	Ctrl+Home\n"
929 			"Last Page	Ctrl+End");
930 
931 	char* edit_shortcuts= _(
932 			"Copy		Alt+O\n"
933 			"Copy		Ctrl+Shift+C\n\n"
934 			"Paste		Alt+P\n"
935 			"Paste		Ctrl+Shift+V\n\n"
936 			"Paste from Clipboard	Shift+Ins\n\n"
937 			"Emotions		Ctrl+Enter");
938 
939 	char* view_shortcuts= _(
940 			"Full Screen Mode	Alt+Enter\n"
941 			"Simple Mode		Shift+Enter\n"
942 #ifdef USE_DOCKLET
943 			"Show Main Window	Alt+M"
944 #endif
945 			);
946 	GtkWidget* dlg = gtk_message_dialog_new_with_markup( (GtkWindow*)_this->m_Widget,
947 						GTK_DIALOG_DESTROY_WITH_PARENT,
948 						GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
949 						_("<b>Connect Shortcuts</b>\n%s\n\n"
950 						  "<b>Edit Shortcuts</b>\n%s\n\n"
951 						  "<b>View Shortcuts</b>\n%s\n\n"),
952 						   connect_shortcuts, edit_shortcuts, view_shortcuts );
953 
954 	gtk_image_set_from_pixbuf((GtkImage*) ((GtkMessageDialog*)dlg)->image, _this->m_MainIcon);
955 	gtk_dialog_run((GtkDialog*) dlg); // == GTK_RESPONSE_OK
956 	gtk_widget_destroy(dlg);
957 }
958 
959 
OnAbout(GtkMenuItem * mitem UNUSED,CMainFrame * _this)960 void CMainFrame::OnAbout(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
961 {
962 	char* authors = _(
963 			"Hong Jen Yee (Main developer) <pcman.tw@gmail.com>\n"
964 			"Jim Huang (Developer) <jserv.tw@gmail.com>\n"
965 			"Kan-Ru Chen (Developer) <kanru@kanru.info>\n"
966 			"Chia I Wu (Developer) <b90201047@ntu.edu.tw>\n"
967 			"Shih-Yuan Lee (Developer) <fourdollars@gmail.com>\n"
968 			"Youchen Lee (Developer) <copyleft@utcr.org>\n"
969 			"Emfox Zhou (Developer) <emfoxzhou@gmail.com>\n"
970 			"Jason Xia (Developer) <jasonxh@gmail.com>"
971 			);
972 	char* translators = _( "Chinese Simplified (zh_CN): Haifeng Chen <optical.dlz@gmail.com>" );
973 
974 	GtkWidget* dlg = gtk_message_dialog_new_with_markup( (GtkWindow*)_this->m_Widget,
975 						GTK_DIALOG_DESTROY_WITH_PARENT,
976 						GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
977 						_("<b>PCManX %s</b>\nA free BBS client developed with GTK+ 2.x\n\n"
978 						"Copyright © 2005-2012\n"
979 						"License: GNU Genral Public License\n"
980 						"Project: <a href=\"%s\">%s</a>\n"
981 						"Mailing List: <a href=\"%s\">%s</a>\n"
982 						"Bug Report: <a href=\"%s\">%s</a>\n\n"
983 						"<b>Authors</b>:\n%s\n\n"
984 						"<b>Translators</b>:\n%s\n\n"), PACKAGE_VERSION, PROJECT_SITE, PROJECT_SITE,
985                         PROJECT_FORUM, PROJECT_FORUM, PACKAGE_BUGREPORT, PACKAGE_BUGREPORT, authors, translators );
986 
987 // GTK+ supports this API since ver 2.6.
988 /*	gtk_message_dialog_format_secondary_text((GtkMessageDialog*)dlg,
989 						_("Copyright (C) 2005\n"
990 						"License: GNU Genral Public License\n"
991 						"Project Homepage: http://code.google.com/p/pcmanx-gtk2/\n\n"
992 						"Authors:\n%s\n")
993 						, authors	);
994 */
995 	gtk_image_set_from_pixbuf((GtkImage*)((GtkMessageDialog*)dlg)->image, _this->m_MainIcon);
996 	gtk_dialog_run((GtkDialog*)dlg); // == GTK_RESPONSE_OK
997 	gtk_widget_destroy(dlg);
998 }
999 
pasteFromClipboard(GtkMenuItem * pMenuItem UNUSED,CMainFrame * pMainFrame)1000 void CMainFrame::pasteFromClipboard(GtkMenuItem* pMenuItem UNUSED, CMainFrame* pMainFrame)
1001 {
1002 	CTelnetView* t_pView = pMainFrame->GetCurView();
1003 	if (t_pView != NULL)
1004 		t_pView->PasteFromClipboard(false);
1005 }
1006 
OnPopupMenuSelectCon(GtkWidget * widget,GtkWidget * menu,GdkEventButton * event,CMainFrame * _this)1007 void CMainFrame::OnPopupMenuSelectCon(GtkWidget* widget,
1008                                       GtkWidget* menu,
1009                                       GdkEventButton* event,
1010                                       CMainFrame* _this)
1011 {
1012     /**
1013     *   Popup menu on correct tab.
1014     *   Switch to the tab closest to the cursor first and then popup menu
1015     */
1016     int number_of_closet_tab;
1017     number_of_closet_tab = _this->GetNearestTab(widget, event);
1018 
1019     // switch to the page which is clicked.
1020     gtk_notebook_set_current_page(GTK_NOTEBOOK(widget), number_of_closet_tab);
1021     _this->SetCurView( _this->m_Views[number_of_closet_tab] );
1022 
1023     gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
1024 }
1025 
OnCloseSelectCon(GtkWidget * notebook,GtkMenuItem * mitem,CMainFrame * _this)1026 void CMainFrame::OnCloseSelectCon(GtkWidget *notebook, GtkMenuItem* mitem, CMainFrame* _this)
1027 {
1028 	/**
1029 	*   Close pages selected by middle click of tabs.
1030 	*
1031 	*   At first choose which tab is the closet tab to the click location.
1032 	*   Then switch to the selected page.
1033 	*   Finally close it, and then switch back to the original page.
1034 	*
1035 	*   TODO:
1036 	*   The most right hand tab will be selected
1037 	*   even the click location is not exactly on the tab.
1038 	*/
1039 	int window_w = 0;
1040 	int window_h = 0;
1041 	gtk_window_get_size(GTK_WINDOW(gtk_widget_get_toplevel(notebook)), &window_w, &window_h);
1042 
1043 	int closet_tab_x = window_w;
1044 	int number_of_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(notebook));
1045 	int nth_page_number = 0;
1046 	int number_of_closet_tab = 0;
1047 	/* pick up the tab which is closet to the click location. */
1048 	for(nth_page_number = 0; nth_page_number < number_of_pages; nth_page_number++)
1049 	{
1050 		GtkWidget *tab_label;
1051 		tab_label = gtk_notebook_get_tab_label(  GTK_NOTEBOOK(notebook),
1052 			gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook),
1053 			nth_page_number));
1054 		int lx, ly;
1055 		gtk_widget_get_pointer(tab_label, &lx, &ly);
1056 		if(lx > 0 && lx < closet_tab_x)
1057 		{
1058 			closet_tab_x = lx;
1059 			number_of_closet_tab = nth_page_number;
1060 		}
1061 	}
1062 
1063 	/* switch to the page which is clicked. */
1064 	int page_idx_before_close = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
1065 	gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), number_of_closet_tab);
1066 	_this->SetCurView( _this->m_Views[number_of_closet_tab] );
1067 
1068 	if ( !(_this->QueryOnCloseCon(_this)) )
1069 	{
1070 		return;
1071 	}
1072 
1073 	int page_idx_after_close = 0;
1074 	page_idx_before_close < number_of_closet_tab ? page_idx_after_close = page_idx_before_close : page_idx_after_close = page_idx_before_close - 1;
1075 	/* close the current page and then switch page back to the original one. */
1076 	_this->CloseConAndPageSwitch(_this->m_pNotebook->GetCurPage(), true, notebook, page_idx_after_close);
1077 }
1078 
1079 
OnCloseCon(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1080 void CMainFrame::OnCloseCon(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1081 {
1082 	if ( !(_this->QueryOnCloseCon(_this)) )
1083 	{
1084 		return;
1085 	}
1086 	_this->CloseCon(_this->m_pNotebook->GetCurPage(), true);
1087 }
1088 
QueryOnCloseCon(CMainFrame * _this)1089 bool CMainFrame::QueryOnCloseCon(CMainFrame* _this)
1090 {
1091 	CTelnetCon* con = _this->GetCurCon();
1092 	if( !con )
1093 		return false;
1094 	if( AppConfig.QueryOnCloseCon && !con->IsClosed() )
1095 	{
1096 		GtkWidget* dlg = gtk_message_dialog_new(GTK_WINDOW(_this->m_Widget),
1097 			GTK_DIALOG_MODAL,
1098 			GTK_MESSAGE_QUESTION,
1099 			GTK_BUTTONS_OK_CANCEL,
1100 			_("Close Connection?"));
1101 		bool can_close = ( gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_OK );
1102 		gtk_widget_destroy(dlg);
1103 		if ( !can_close )
1104 			return false;
1105 	}
1106 	return true;
1107 }
1108 
OnCopy(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1109 void CMainFrame::OnCopy(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1110 {
1111 	if( _this->GetCurView() )
1112 	{
1113 		_this->GetCurView()->CopyToClipboard(false, false, AppConfig.CopyTrimTail);
1114 		if( AppConfig.CancelSelAfterCopy )
1115 		{
1116 			_this->GetCurCon()->m_Sel->NewStart(0, 0);
1117 			_this->GetCurView()->Refresh();
1118 		}
1119 	}
1120 }
1121 
1122 
OnCopyWithColor(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1123 void CMainFrame::OnCopyWithColor(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1124 {
1125 	if( _this->GetCurView() )
1126 	{
1127 		_this->GetCurView()->CopyToClipboard(false, true, AppConfig.CopyTrimTail);
1128 		if( AppConfig.CancelSelAfterCopy )
1129 		{
1130 			_this->GetCurCon()->m_Sel->NewStart(0, 0);
1131 			_this->GetCurView()->Refresh();
1132 		}
1133 	}
1134 }
1135 
1136 
OnNextCon(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1137 void CMainFrame::OnNextCon(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1138 {
1139 	int i = _this->GetNotebook()->GetCurPage() + 1;
1140 	int n = _this->GetNotebook()->GetPageCount();
1141 	_this->GetNotebook()->SetCurPage( i < n ? i : 0 );
1142 }
1143 
OnFirstCon(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1144 void CMainFrame::OnFirstCon(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1145 {
1146 	_this->GetNotebook()->SetCurPage( 0 );
1147 }
1148 
OnLastCon(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1149 void CMainFrame::OnLastCon(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1150 {
1151 	int n = _this->GetNotebook()->GetPageCount();
1152 	_this->GetNotebook()->SetCurPage( n - 1 );
1153 }
1154 
OnPaste(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1155 void CMainFrame::OnPaste(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1156 {
1157 	if(_this->GetCurView())
1158 		_this->GetCurView()->PasteFromClipboard(true);
1159 }
1160 
OnDownArticle(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1161 void CMainFrame::OnDownArticle(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1162 {
1163   int uao = 0;
1164 	CTelnetCon *con = _this->GetCurCon();
1165 	if (!con)
1166 		return;
1167 	if(_this->GetCurView())
1168     uao = _this->GetCurView()->m_UAO;
1169 
1170 	CDownArticleDlg *dlg = new CDownArticleDlg(_this, con, uao);
1171 	//dlg->Show();
1172 	dlg->ShowModal();
1173 	dlg->Destroy();
1174 }
1175 
OnPreference(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1176 void CMainFrame::OnPreference(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1177 {
1178 #ifdef USE_DOCKLET
1179 	bool show_tray_icon = AppConfig.ShowTrayIcon;
1180 #endif
1181 	CPrefDlg* dlg = new CPrefDlg(_this);
1182 	dlg->ShowModal();
1183 	dlg->Destroy();
1184 
1185 	CTelnetView::SetWebBrowser(AppConfig.WebBrowser);
1186 	CTelnetView::SetMailClient(AppConfig.MailClient);
1187 
1188 #if defined(USE_NOTIFIER) && !defined(USE_LIBNOTIFY)
1189 	popup_notifier_set_timeout( AppConfig.PopupTimeout );
1190 #endif
1191 
1192 #ifdef USE_DOCKLET
1193 	if (AppConfig.ShowTrayIcon != show_tray_icon) {
1194 		if (_this->m_dlhandle != NULL) {
1195 			void (*app_indicator_set_status)(void*, gint) =
1196 				(void (*)(void*, gint)) lt_dlsym(_this->m_dlhandle, "app_indicator_set_status");
1197 			if (AppConfig.ShowTrayIcon) {
1198 				app_indicator_set_status(_this->m_indicator, 1);
1199 			}
1200 			else {
1201 				app_indicator_set_status(_this->m_indicator, 0);
1202 			}
1203 		}
1204 		else {
1205 			if (AppConfig.ShowTrayIcon) {
1206 				_this->ShowTrayIcon();
1207 			}
1208 			else {
1209 				_this->HideTrayIcon();
1210 			}
1211 		}
1212 	}
1213 #endif
1214 
1215 	if (_this->m_Mode == NORMAL_MODE) {
1216 		if (AppConfig.ShowToolbar)
1217 			gtk_widget_show_all(_this->m_Toolbar);
1218 		else
1219 			gtk_widget_hide_all(_this->m_Toolbar);
1220 		if (AppConfig.ShowStatusBar)
1221 			gtk_widget_show_all(_this->m_Statusbar);
1222 		else
1223 			gtk_widget_hide_all(_this->m_Statusbar);
1224 	}
1225 }
1226 
1227 
OnPrevCon(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1228 void CMainFrame::OnPrevCon(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1229 {
1230 	int i = _this->GetNotebook()->GetCurPage() - 1;
1231 	int n = _this->GetNotebook()->GetPageCount();
1232 	_this->GetNotebook()->SetCurPage( i >= 0 ? i : n-1 );
1233 
1234 }
1235 
OnSiteList(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1236 void CMainFrame::OnSiteList(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1237 {
1238 	CSiteListDlg* dlg = new CSiteListDlg(_this);
1239 	dlg->ShowModal();
1240 	dlg->Destroy();
1241 }
1242 
1243 
OnJumpToPage(GObject * obj,CMainFrame * _this)1244 void CMainFrame::OnJumpToPage(GObject* obj, CMainFrame* _this)
1245 {
1246 	INFO("On jump to, obj=%p, _this->m_JumpTos[0]=%p",
1247 	     obj, _this->m_JumpTos[0]);
1248 	for( int i = 0; i < 10; ++i )
1249 		if( obj == _this->m_JumpTos[i] )
1250 		{
1251 			_this->GetNotebook()->SetCurPage(i);
1252 			break;
1253 		}
1254 }
1255 
OnTelnetConBell(CTelnetView * con)1256 void CMainFrame::OnTelnetConBell(CTelnetView* con)
1257 {
1258 	if( !IsActivated() )
1259 		FlashWindow(true);
1260 
1261 	if( AppConfig.BeepOnBell )
1262 		gdk_display_beep(gdk_display_get_default());
1263 	if( GetCurView() == con )
1264 		return;
1265 	string markup = "<span foreground=\"red\">";
1266 	markup += con->GetCon()->m_Site.m_Name;
1267 	markup += "</span>";
1268 	m_pNotebook->SetPageTitle( con, markup);
1269 }
1270 
OnTelnetConClose(CTelnetView * con)1271 void CMainFrame::OnTelnetConClose(CTelnetView* con)
1272 {
1273 	if( !con )
1274 		return;
1275 	string markup = "<span foreground=\"#808080\">";
1276 	markup += con->GetCon()->m_Site.m_Name;
1277 	markup += "</span>";
1278 	m_pNotebook->SetPageTitle( con, markup);
1279 }
1280 
OnTelnetConConnect(CTelnetView * con)1281 void CMainFrame::OnTelnetConConnect(CTelnetView* con)
1282 {
1283 	if( !con )
1284 		return;
1285 	m_pNotebook->SetPageTitle( con, con->GetCon()->m_Site.m_Name );
1286 }
1287 
1288 
OnTelnetConRecv(CTelnetView * con)1289 void CMainFrame::OnTelnetConRecv(CTelnetView* con)
1290 {
1291 	if( !con )
1292 		return;
1293 
1294 	// If the text color of the label is red which indicate
1295 	// there is new incoming message, we should return.
1296 //	if(  )
1297 //		return;
1298 	string markup = "<span foreground=\"green\">";
1299 	markup += con->GetCon()->m_Site.m_Name;
1300 	markup += "</span>";
1301 	m_pNotebook->SetPageTitle( con, markup);
1302 }
1303 
1304 
OnNotebookChangeCurPage(GtkNotebook * widget UNUSED,GtkNotebookPage * page UNUSED,gint page_num,CMainFrame * _this)1305 void CMainFrame::OnNotebookChangeCurPage(GtkNotebook* widget UNUSED,
1306                                          GtkNotebookPage* page UNUSED,
1307                                          gint page_num,
1308                                          CMainFrame* _this)
1309 {
1310 	_this->SetCurView( _this->m_Views[page_num] );
1311 	if( _this->GetCurEditor() != NULL )
1312 		_this->m_eView = (CEditorView *) _this->m_Views[page_num];
1313 }
1314 
OnNotebookPopupMenu(GtkWidget * widget,GdkEventButton * event,CMainFrame * _this)1315 gboolean CMainFrame::OnNotebookPopupMenu(GtkWidget *widget,
1316                                          GdkEventButton *event,
1317                                          CMainFrame* _this)
1318 {
1319 	/* initialized once */
1320 	static GtkWidget *menu = NULL;
1321 	static GtkWidget *menu_item_close = NULL;
1322 
1323 	if (menu == NULL) {
1324 		// set menu items
1325 		GtkWidget *menu_item_close =
1326 			gtk_image_menu_item_new_with_label( _("Close") );
1327 		GtkWidget *menu_item_reconnect =
1328 			gtk_image_menu_item_new_with_label( _("Reconnect") );
1329 		GtkWidget *menu_item_add2fav =
1330 			gtk_image_menu_item_new_with_label( _("Add to Favorites") );
1331 
1332 		// set images
1333 		GtkWidget *image_close =
1334 			gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
1335 		GtkWidget *image_reconnect =
1336 			gtk_image_new_from_stock (GTK_STOCK_UNDO, GTK_ICON_SIZE_MENU);
1337 		GtkWidget *image_add2fav =
1338 			gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
1339 
1340 		gtk_image_menu_item_set_image (
1341 			(GtkImageMenuItem *) menu_item_close, image_close);
1342 		gtk_image_menu_item_set_image (
1343 			(GtkImageMenuItem *) menu_item_reconnect, image_reconnect);
1344 		gtk_image_menu_item_set_image (
1345 			(GtkImageMenuItem *) menu_item_add2fav, image_add2fav);
1346 
1347 		menu = gtk_menu_new();
1348 
1349 		// widgets show
1350 		gtk_widget_show (menu_item_reconnect);
1351 		gtk_container_add (GTK_CONTAINER (menu), menu_item_reconnect);
1352 
1353 		gtk_widget_show (menu_item_close);
1354 		gtk_container_add (GTK_CONTAINER (menu), menu_item_close);
1355 
1356 		gtk_widget_show (menu_item_add2fav);
1357 		gtk_container_add (GTK_CONTAINER (menu), menu_item_add2fav);
1358 
1359 		// signals
1360 		g_signal_connect ( G_OBJECT(menu_item_reconnect), "activate",
1361 		                G_CALLBACK (CMainFrame::OnReconnect),
1362 		                _this);
1363 		g_signal_connect ( G_OBJECT(menu_item_close), "activate",
1364 		                G_CALLBACK (CMainFrame::OnCloseCon),
1365 		                _this);
1366 		g_signal_connect ( G_OBJECT(menu_item_add2fav), "activate",
1367 		                G_CALLBACK (CMainFrame::OnAddToFavorites),
1368 		                _this);
1369 	}
1370 
1371 
1372     if (event->button == 1) {
1373         // Left-click
1374         return FALSE;
1375 
1376     } else if (event->button == 2 && AppConfig.MidClickAsClose) {
1377         // Feature: let mouse middle click be able to close tab
1378         // similar to the behavior under Firefox
1379         _this->OnCloseSelectCon(widget, GTK_MENU_ITEM(menu_item_close), _this);
1380         return TRUE;
1381 
1382     } else if (event->button == 3) {
1383         // Let right-click be able to popup menu on the right tab
1384         _this->OnPopupMenuSelectCon(widget, menu, event, _this);
1385         return TRUE;
1386 
1387     } else {
1388         return FALSE;
1389     }
1390 
1391 }
1392 
CloseConAndPageSwitch(int idx,bool confirm UNUSED,GtkWidget * notebook,int page_idx)1393 void CMainFrame::CloseConAndPageSwitch(int idx, bool confirm UNUSED, GtkWidget *notebook, int page_idx)
1394 {
1395 	m_pNotebook->RemovePage(idx);
1396 	m_Views.erase( m_Views.begin() + idx );
1397 
1398 	gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), page_idx);
1399 	SetCurView( page_idx >= 0 ? m_Views[page_idx] : NULL );
1400 }
1401 
CloseCon(int idx,bool confirm UNUSED)1402 void CMainFrame::CloseCon(int idx, bool confirm UNUSED)
1403 {
1404 	m_pNotebook->RemovePage(idx);
1405 	m_Views.erase( m_Views.begin() + idx );
1406 
1407 	int n = m_pNotebook->GetCurPage();
1408 	SetCurView( n >= 0 ? m_Views[n] : NULL );
1409 }
1410 
OnBlinkTimer(CMainFrame * _this)1411 gboolean CMainFrame::OnBlinkTimer(CMainFrame* _this)
1412 {
1413 	if( _this->m_IsFlashing )
1414 	{
1415 		if( gtk_window_get_icon( GTK_WINDOW(_this->m_Widget) ) == _this->m_MainIcon )
1416 			gtk_window_set_icon( GTK_WINDOW(_this->m_Widget), _this->m_InverseMainIcon );
1417 		else
1418 			gtk_window_set_icon( GTK_WINDOW(_this->m_Widget), _this->m_MainIcon );
1419 	}
1420 
1421 	if(_this->GetCurView() && _this->GetCurView()->IsVisible() )
1422 		_this->GetCurView()->OnBlinkTimer();
1423 	return true;
1424 }
1425 
OnWindowStateEvent(GtkWindow * window,GdkEventWindowState * event,CMainFrame * _this)1426 gboolean CMainFrame::OnWindowStateEvent(GtkWindow* window,
1427 										GdkEventWindowState* event,
1428 										CMainFrame* _this)
1429 {
1430 	if ((event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) == GDK_WINDOW_STATE_MAXIMIZED) {
1431 		if ((event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) == GDK_WINDOW_STATE_MAXIMIZED) {
1432 			AppConfig.Maximized = true;
1433 		} else {
1434 			AppConfig.Maximized = false;
1435 		}
1436 	}
1437 	return true;
1438 }
1439 
OnClose(GtkWidget * widget UNUSED,GdkEvent * evt UNUSED,CMainFrame * _this)1440 gboolean CMainFrame::OnClose( GtkWidget* widget UNUSED,
1441                               GdkEvent* evt UNUSED,
1442                               CMainFrame* _this )
1443 {
1444 	return !_this->CanClose();
1445 }
1446 
1447 
OnDestroy()1448 void CMainFrame::OnDestroy()
1449 {
1450 	g_source_remove( m_BlinkTimer );
1451 	g_source_remove( m_EverySecondTimer );
1452 
1453 	Hide();
1454 #ifdef USE_DOCKLET
1455 	g_object_unref( m_TrayIcon );
1456 #endif
1457 
1458 	//while( g_main_context_iteration(NULL, FALSE) );
1459 	while (gtk_events_pending())
1460 		gtk_main_iteration();
1461 
1462 	CWidget::OnDestroy();
1463 
1464 #ifdef USE_SCRIPT
1465 	FinalizeScriptInterface();
1466 #endif
1467 
1468 	gtk_main_quit();
1469 
1470 	if (m_dlhandle != NULL) {
1471 		lt_dlclose(m_dlhandle);
1472 		m_dlhandle = NULL;
1473 	}
1474 }
1475 
1476 
OnCreate()1477 void CMainFrame::OnCreate()
1478 {
1479 	CWidget::OnCreate();
1480 	LoadStartupSites();
1481 }
1482 
CanClose()1483 bool CMainFrame::CanClose()
1484 {
1485 	if( GetNotebook()->GetPageCount() == 0 || !AppConfig.QueryOnExit )
1486 		return true;
1487 
1488 	GtkWidget* dlg = gtk_message_dialog_new( (GtkWindow*)m_Widget,
1489 						GTK_DIALOG_DESTROY_WITH_PARENT,
1490 						GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL,
1491 						_("Quit PCManX ?"));
1492 	bool close = gtk_dialog_run((GtkDialog*)dlg) == GTK_RESPONSE_OK;
1493 	gtk_widget_destroy(dlg);
1494 	return close;
1495 }
1496 
1497 
NotImpl(const char * str)1498 void CMainFrame::NotImpl(const char* str)
1499 {
1500 	GtkWidget* dlg = gtk_message_dialog_new( (GtkWindow*)m_Widget,
1501 					GTK_DIALOG_DESTROY_WITH_PARENT,
1502 					GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1503 					_("Function not implemented yet!\nDebug: %s"), str);
1504 	gtk_dialog_run((GtkDialog*)dlg);
1505 	gtk_widget_destroy(dlg);
1506 }
1507 
1508 
OnAddToFavorites(GtkMenuItem * widget UNUSED,CMainFrame * _this)1509 void CMainFrame::OnAddToFavorites(GtkMenuItem* widget UNUSED,
1510                                   CMainFrame* _this)
1511 {
1512 	if(_this->m_Views.empty() )
1513 		return;
1514 
1515 	CSite &site = _this->GetCurCon()->m_Site;
1516 	CSiteDlg* dlg = new CSiteDlg(_this, _("Add To Favorites"), site );
1517 	if(dlg->ShowModal() == GTK_RESPONSE_OK)
1518 	{
1519 		AppConfig.Favorites.push_back(dlg->m_Site);
1520 		CSite& newsite = AppConfig.Favorites.back();
1521 
1522 		GtkWidget* fav_item = gtk_image_menu_item_new_with_label( newsite.m_Name.c_str() );
1523 		gtk_widget_show (fav_item);
1524 		gtk_menu_shell_insert( GTK_MENU_SHELL(_this->m_FavoritesMenu), fav_item,
1525 			AppConfig.Favorites.size()>0 ? (AppConfig.Favorites.size()-1) : 0 );
1526 
1527 		GtkWidget* image = gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU);
1528 
1529 		gtk_widget_show (image);
1530 		gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (fav_item), image);
1531 
1532 		newsite.m_MenuItem = fav_item;
1533 
1534 		g_signal_connect( G_OBJECT(fav_item), "activate",
1535 						G_CALLBACK(CMainFrame::OnFavorite),
1536 						_this);
1537 	}
1538 	dlg->Destroy();
1539 }
1540 
OnEditFavorites(GtkMenuItem * widget UNUSED,CMainFrame * _this)1541 void CMainFrame::OnEditFavorites(GtkMenuItem* widget UNUSED, CMainFrame* _this)
1542 {
1543 	CEditFavDlg* dlg = new CEditFavDlg(_this, AppConfig.Favorites);
1544 	dlg->ShowModal();
1545 	AppConfig.Favorites.swap(dlg->m_Sites);
1546 	AppConfig.SaveFavorites();
1547 	dlg->Destroy();
1548 
1549 	_this->CreateFavoritesMenu();
1550 }
1551 
1552 
CreateFavoritesMenu()1553 void CMainFrame::CreateFavoritesMenu()
1554 {
1555 	GtkWidget* favorites_menu = gtk_menu_new();
1556 	vector<CSite>::iterator it;
1557 	for( it = AppConfig.Favorites.begin(); it != AppConfig.Favorites.end(); ++it )
1558 	{
1559 		CSite& site = *it;
1560 		GtkWidget* fav_item;
1561 		const size_t fav_string_len = 20;
1562 		fav_item = gtk_image_menu_item_new_with_label(
1563 			site.m_Name.length() <= fav_string_len ?
1564 			site.m_Name.c_str() :
1565 			(site.m_Name.substr(0, fav_string_len) + " ...").c_str());
1566 		gtk_widget_show (fav_item);
1567 		gtk_container_add (GTK_CONTAINER (favorites_menu), fav_item);
1568 
1569 		GtkWidget* image = gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU);
1570 		gtk_widget_show (image);
1571 		gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (fav_item), image);
1572 
1573 		site.m_MenuItem = fav_item;
1574 
1575 		g_signal_connect( G_OBJECT(fav_item), "activate",
1576 						G_CALLBACK(CMainFrame::OnFavorite),
1577 						this);
1578 	}
1579 
1580 	GtkWidget* separator3 = gtk_separator_menu_item_new ();
1581 	gtk_widget_show (separator3);
1582 	gtk_container_add (GTK_CONTAINER (favorites_menu), separator3);
1583 	gtk_widget_set_sensitive (separator3, FALSE);
1584 
1585 	GtkWidget* add_to_fav_menu = gtk_image_menu_item_new_with_mnemonic (_("_Add to Favorites"));
1586 	gtk_widget_show (add_to_fav_menu);
1587 	gtk_container_add (GTK_CONTAINER (favorites_menu), add_to_fav_menu);
1588 
1589 	GtkWidget* image347 = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
1590 	gtk_widget_show (image347);
1591 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_to_fav_menu), image347);
1592 
1593 	GtkWidget* edit_fav_menu = gtk_image_menu_item_new_with_mnemonic (_("_Edit Favorites"));
1594 
1595 	gtk_widget_show (edit_fav_menu);
1596 	gtk_container_add (GTK_CONTAINER (favorites_menu), edit_fav_menu);
1597 
1598 	GtkWidget* image348 = gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
1599 	gtk_widget_show (image348);
1600 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (edit_fav_menu), image348);
1601 
1602 
1603 	g_signal_connect ((gpointer) add_to_fav_menu, "activate",
1604 					G_CALLBACK (CMainFrame::OnAddToFavorites),
1605 					this);
1606 	g_signal_connect ((gpointer) edit_fav_menu, "activate",
1607 					G_CALLBACK (CMainFrame::OnEditFavorites),
1608 					this);
1609 
1610 	m_FavoritesMenu = favorites_menu;
1611 	gtk_menu_item_set_submenu( GTK_MENU_ITEM(m_FavoritesMenuItem), favorites_menu);
1612 }
1613 
CreateTrayIcon()1614 void CMainFrame::CreateTrayIcon()
1615 {
1616 #ifdef USE_DOCKLET
1617 	// Setup popup menu
1618 	m_TrayPopup = gtk_ui_manager_get_widget(m_UIManager, "/ui/tray_popup");
1619 	if (m_dlhandle != NULL) {
1620 		void*(*app_indicator_new)(const gchar*, const gchar*, gint) =
1621 			(void*(*)(const gchar*, const gchar*, gint)) lt_dlsym(m_dlhandle, "app_indicator_new");
1622 		void (*app_indicator_set_menu)(void*, GtkMenu *) =
1623 			(void (*)(void*, GtkMenu *)) lt_dlsym(m_dlhandle, "app_indicator_set_menu");
1624 		void (*app_indicator_set_status)(void*, gint) =
1625 			(void (*)(void*, gint)) lt_dlsym(m_dlhandle, "app_indicator_set_status");
1626 		m_indicator = app_indicator_new("PCManX", DATADIR "/pixmaps/pcmanx.svg", 0);
1627 		app_indicator_set_menu(m_indicator, GTK_MENU(m_TrayPopup));
1628 		if (AppConfig.ShowTrayIcon) {
1629 			app_indicator_set_status(m_indicator, 1);
1630 		}
1631 		else {
1632 			app_indicator_set_status(m_indicator, 0);
1633 		}
1634 	}
1635 	else {
1636 		m_TrayIcon = gtk_status_icon_new();
1637 		gtk_status_icon_set_from_pixbuf(m_TrayIcon, m_MainIcon);
1638 		gtk_status_icon_set_tooltip(m_TrayIcon, "PCManX");
1639 
1640 		g_signal_connect (G_OBJECT (m_TrayIcon), "popup-menu",
1641 				G_CALLBACK (CMainFrame::OnTray_Popup), this);
1642 
1643 		g_signal_connect (G_OBJECT (m_TrayIcon), "activate",
1644 				G_CALLBACK (CMainFrame::OnTrayButton_Toggled), this);
1645 	}
1646 #endif
1647 }
1648 
OnFavorite(GtkMenuItem * item,CMainFrame * _this)1649 void CMainFrame::OnFavorite(GtkMenuItem* item, CMainFrame* _this)
1650 {
1651 	vector<CSite>::iterator it;
1652 	for( it = AppConfig.Favorites.begin(); it != AppConfig.Favorites.end(); ++it )
1653 	{
1654 		CSite& site = *it;
1655 		if( site.m_MenuItem == (GtkWidget*)item )
1656 		{
1657 			_this->NewCon( site.m_Name, site.m_URL, &site );
1658 			break;
1659 		}
1660 	}
1661 }
1662 
1663 
format_elapsed_time_str(char * time_str,unsigned int sec)1664 static void format_elapsed_time_str( char* time_str, unsigned int sec )
1665 {
1666 	static const char* time_format = _("Time Elapsed : %02d : %02d : %02d");
1667 	unsigned int min = sec / 60;
1668 	sec %= 60;
1669 	unsigned int hr = min / 60;
1670 	min %= 60;
1671 	sprintf( time_str, time_format, hr, min, sec );
1672 }
1673 
1674 
SetCurView(CTelnetView * view)1675 void CMainFrame::SetCurView(CTelnetView* view)
1676 {
1677 	m_pView = view;
1678 	if( !m_pView || !m_pView->GetCon() )
1679 	{
1680 		gtk_window_set_title (GTK_WINDOW (m_Widget), "PCManX " VERSION );
1681 		gtk_entry_set_text( GTK_ENTRY(m_URLEntry), "");
1682 		return;
1683 	}
1684 
1685 	CTelnetCon* con = GetCurCon();
1686 	gtk_entry_set_text( GTK_ENTRY(m_URLEntry), con->m_Site.m_URL.c_str());
1687 
1688 	string title = con->m_Site.m_Name;
1689 
1690 	if( ! con->IsClosed() )
1691 		m_pNotebook->SetPageTitle( m_pView, title );
1692 
1693 	title += " - PCManX " VERSION;
1694 	gtk_window_set_title (GTK_WINDOW (m_Widget), title.c_str() );
1695 
1696 	char time_str[100];
1697 	format_elapsed_time_str(time_str, con->m_Duration);
1698 	gtk_label_set_text( m_StatusBarTime, time_str );
1699 
1700 #ifdef USE_NANCY
1701 	UpdateBotStatus();
1702 #endif
1703 
1704 }
1705 
OnSelectAll(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1706 void CMainFrame::OnSelectAll(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1707 {
1708 	CTelnetCon* con = _this->GetCurCon();
1709 	if( con )
1710 	{
1711 		con->m_Sel->SelectPage();
1712 		_this->GetCurView()->Refresh();
1713 	}
1714 }
1715 
LoadStartupSites()1716 void CMainFrame::LoadStartupSites()
1717 {
1718 	vector<CSite>::iterator it=AppConfig.Favorites.begin();
1719 	for( it = AppConfig.Favorites.begin(); it != AppConfig.Favorites.end(); ++it )
1720 	{
1721 		CSite& site = *it;
1722 		if( site.m_Startup )
1723 			NewCon( site.m_Name, site.m_URL, &site);
1724 	}
1725 	m_pNotebook->SetCurPage(0);
1726 }
1727 
OnEverySecondTimer(CMainFrame * _this)1728 gboolean CMainFrame::OnEverySecondTimer(CMainFrame* _this)
1729 {
1730 	vector<CTelnetView*>::iterator it;
1731 	for( it = _this->m_Views.begin(); it != _this->m_Views.end(); ++it )
1732 	{
1733 		CTelnetView* view = *it;
1734 		if( view->GetCon() )
1735 			view->GetCon()->OnTimer();
1736 	}
1737 	CTelnetCon* con = _this->GetCurCon();
1738 	if( con )
1739 	{
1740 		char time_str[100];
1741 		format_elapsed_time_str(time_str, con->m_Duration);
1742 		gtk_label_set_text( _this->m_StatusBarTime, time_str );
1743 	}
1744 	return true;
1745 }
1746 
OnEmoticons(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1747 void CMainFrame::OnEmoticons(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1748 {
1749 	CEmoticonDlg* dlg = new CEmoticonDlg(_this);
1750 	if( dlg->ShowModal() == GTK_RESPONSE_OK )
1751 	{
1752 		CTelnetView* view = _this->GetCurView();
1753 		if( view )
1754 			view->OnTextInput( dlg->GetSelectedStr().c_str() );
1755 	}
1756 	dlg->Destroy();
1757 }
1758 
OnReconnect(GtkMenuItem * mitem UNUSED,CMainFrame * _this)1759 void CMainFrame::OnReconnect(GtkMenuItem* mitem UNUSED, CMainFrame* _this)
1760 {
1761 	CTelnetCon* con = _this->GetCurCon();
1762 	if( !con )
1763 		return;
1764 	if( con->IsClosed() )
1765 		con->Reconnect();
1766 	else
1767 		_this->NewCon( con->m_Site.m_Name, con->m_Site.m_URL, &con->m_Site);
1768 }
1769 
FlashWindow(bool flash)1770 void CMainFrame::FlashWindow( bool flash )
1771 {
1772 	GdkPixbuf* icon = (m_IsFlashing = flash) ? m_InverseMainIcon : m_MainIcon;
1773 	gtk_window_set_icon((GtkWindow*)m_Widget, icon);
1774 }
1775 
1776 
OnActivated(GtkWidget * widget UNUSED,GdkEventFocus * evt UNUSED,CMainFrame * _this)1777 gboolean CMainFrame::OnActivated( GtkWidget* widget UNUSED,
1778                                   GdkEventFocus* evt UNUSED,
1779                                   CMainFrame* _this )
1780 {
1781 	if( _this->m_IsFlashing )
1782 		_this->FlashWindow(false);
1783 	return false;
1784 }
1785 
OnURLEntryKeyDown(GtkWidget * widget,GdkEventKey * evt,CMainFrame * _this)1786 gboolean CMainFrame::OnURLEntryKeyDown(GtkWidget *widget, GdkEventKey *evt, CMainFrame* _this)
1787 {
1788 	switch(evt->keyval)
1789 	{
1790 	case GDK_Return:
1791 	case GDK_KP_Enter:
1792 	{
1793 		string url = gtk_entry_get_text( GTK_ENTRY(widget) );
1794 		if( !url.empty() )
1795 		{
1796 			_this->NewCon( url, url );
1797 			return true;
1798 		}
1799 		//	else goto case GDK_Escape
1800 	}
1801 	case GDK_Escape:
1802 		if( _this->GetCurView() )
1803 			_this->GetCurView()->SetFocus();
1804 		else
1805 			gtk_entry_set_text( GTK_ENTRY(widget), "" );
1806 		return true;
1807 	}
1808 	return false;
1809 }
1810 
OnURLEntryKillFocus(GtkWidget * entry,GdkEventFocus * evt UNUSED,CMainFrame * _this)1811 gboolean CMainFrame::OnURLEntryKillFocus(GtkWidget* entry,
1812                                          GdkEventFocus* evt UNUSED,
1813                                          CMainFrame* _this)
1814 {
1815 	if( _this && _this->GetCurView() )
1816 	{
1817 		gtk_entry_set_text( GTK_ENTRY(entry), _this->GetCurCon()->m_Site.m_URL.c_str());
1818 		gtk_editable_select_region(GTK_EDITABLE(entry), 0, 0);
1819 	}
1820 	return FALSE;
1821 }
1822 
1823 
GetViewIndex(CTermView * view)1824 int CMainFrame::GetViewIndex(CTermView* view)
1825 {
1826 	DEBUG( "get view index, view = %p", view );
1827 	if( !view )
1828 		return -1;
1829 	DEBUG( "view->m_Widget = %p", view->m_Widget );
1830 	return gtk_notebook_page_num( GTK_NOTEBOOK(m_pNotebook->m_Widget), view->m_Widget );
1831 }
1832 
GetNearestTab(GtkWidget * widget,GdkEventButton * event)1833 int CMainFrame::GetNearestTab(GtkWidget *widget, GdkEventButton *event )
1834 {
1835     /**
1836     *   Return the closest tab's number to the cursor
1837     */
1838     int window_w = 0;
1839     int window_h = 0;
1840     gtk_window_get_size(GTK_WINDOW(gtk_widget_get_toplevel(widget)), &window_w, &window_h);
1841 
1842     int closet_tab_x = window_w;
1843     int number_of_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(widget));
1844     int nth_page_number = 0;
1845     int number_of_closet_tab = 0;
1846     // pick up the tab which is closest to the click location.
1847     for(nth_page_number = 0; nth_page_number < number_of_pages; nth_page_number++)
1848     {
1849         GtkWidget *tab_label;
1850         tab_label = gtk_notebook_get_tab_label(  GTK_NOTEBOOK(widget),
1851         gtk_notebook_get_nth_page(GTK_NOTEBOOK(widget), nth_page_number));
1852         int lx, ly;
1853         gtk_widget_get_pointer(tab_label, &lx, &ly);
1854         if(lx > 0 && lx < closet_tab_x)
1855         {
1856             closet_tab_x = lx;
1857             number_of_closet_tab = nth_page_number;
1858         }
1859     }
1860 
1861     return number_of_closet_tab;
1862 }
1863 
SwitchToCon(CTelnetCon * con)1864 void CMainFrame::SwitchToCon(CTelnetCon* con)
1865 {
1866 	int idx = GetViewIndex( con->GetView() );
1867 	DEBUG( "switch to con %d", idx );
1868 	if( idx >= 0 )
1869 		m_pNotebook->SetCurPage(idx);
1870 }
1871 
1872 #ifdef USE_NANCY
1873 
OnChangeCurrentBot(GtkRadioAction * action UNUSED,GtkRadioAction * current,CMainFrame * _this)1874 void CMainFrame::OnChangeCurrentBot(GtkRadioAction *action UNUSED,
1875                                     GtkRadioAction *current,
1876                                     CMainFrame* _this)
1877 {
1878   CTelnetCon* con = _this->GetCurCon();
1879   if( !con ) return;
1880   if( gtk_radio_action_get_current_value(current) == 0 )
1881     con->set__UseNancy(false);
1882   else
1883     con->set__UseNancy(true);
1884 
1885   _this->UpdateBotStatus();
1886 }
1887 
OnChangeAllBot(GtkRadioAction * action UNUSED,GtkRadioAction * all,CMainFrame * _this)1888 void CMainFrame::OnChangeAllBot(GtkRadioAction *action UNUSED,
1889                                 GtkRadioAction *all,
1890                                 CMainFrame* _this)
1891 {
1892   if( _this->m_Views.empty() ) return;
1893   gboolean use_nancy = ( gtk_radio_action_get_current_value(all) != 0 );
1894   CTelnetCon::set__OpenConnectionWithNancySupport(use_nancy);
1895 
1896   vector<CTelnetView*>::iterator it = _this->m_Views.begin();
1897   for( ; it != _this->m_Views.end() ; ++it )
1898     (*it)->GetCon()->set__UseNancy(use_nancy);
1899 
1900   if( use_nancy )
1901     gtk_check_menu_item_set_active( (GtkCheckMenuItem*)_this->m_CurBotNancyRadio, true );
1902   else
1903     gtk_check_menu_item_set_active( (GtkCheckMenuItem*)_this->m_DisableCurBotRadio, true );
1904 
1905   _this->UpdateBotStatus();
1906 }
1907 
UpdateBotStatus()1908 void CMainFrame::UpdateBotStatus()
1909 {
1910 	if( GetCurCon()->get__UseNancy() )
1911 	{
1912 		gtk_check_menu_item_set_active( (GtkCheckMenuItem*)m_CurBotNancyRadio, true );
1913 		gchar* bot_state = g_markup_printf_escaped( "<span foreground=\"#ff0000\">%s</span>", _("Nancy Bot is enabled") );
1914 		gtk_label_set_markup( m_StatusBarBotState, bot_state );
1915 		g_free(bot_state);
1916 	}
1917 	else
1918 	{
1919 		gtk_check_menu_item_set_active( (GtkCheckMenuItem*)m_DisableCurBotRadio, true );
1920 		gchar* bot_state = g_markup_printf_escaped( "<span foreground=\"gray\">%s</span>", _("Nancy Bot is disabled") );
1921 		gtk_label_set_markup( m_StatusBarBotState, bot_state );
1922 		g_free(bot_state);
1923 	}
1924 }
1925 
1926 #endif	//	#ifdef USE_NANCY
1927 /* vim: set fileencodings=utf-8 tabstop=4 noexpandtab shiftwidth=4 softtabstop=4: */
1928 
1929 
1930 
1931 /**
1932 *   Open Ansi Editor. Send url string "ansi_editor" to NewCon().
1933 *   The NewCon() method will create CEditor object when the url is "ansi_editor".
1934 */
OnAnsiEditor(GtkMenuItem * mitem,CMainFrame * _this)1935 void CMainFrame::OnAnsiEditor(GtkMenuItem *mitem, CMainFrame *_this)
1936 {
1937 	_this->NewCon("Ansi Editor", "ansi_editor");
1938 }
1939 
OnOpenAnsiFile(GtkMenuItem * mitem,CMainFrame * _this)1940 void CMainFrame::OnOpenAnsiFile(GtkMenuItem *mitem, CMainFrame *_this)
1941 {
1942 	GtkWidget *dialog = gtk_file_chooser_dialog_new (
1943 							"Open Ansi File",
1944 							NULL,
1945 							GTK_FILE_CHOOSER_ACTION_OPEN,
1946 							GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1947 							GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1948 							NULL);
1949 
1950 	GtkFileFilter *filter = gtk_file_filter_new();
1951 	gtk_file_filter_set_name(filter, "Ansi file");
1952 	gtk_file_filter_add_pattern(filter, "*.ans");
1953 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
1954 
1955 	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
1956 	{
1957 		string path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog));
1958 		size_t pos = path.find_last_of("/\\");
1959 		string filename = path.substr(pos + 1, -1);
1960 		string title = "AnsiEditor: ";
1961 		title += filename;
1962 		_this->NewCon(title, "ansi_editor");
1963 		_this->GetCurEditor()->EditorActions(CEditor::Load_Ansi_File, path);
1964 		_this->GetCurEditorView()->UpdateEditor();
1965 	}
1966 	gtk_widget_destroy (dialog);
1967 }
1968 
OnSaveAnsiFile(GtkMenuItem * mitem,CMainFrame * _this)1969 void CMainFrame::OnSaveAnsiFile(GtkMenuItem *mitem, CMainFrame *_this)
1970 {
1971 	//do nothing if the current view is not Ansi Editor
1972 	if ( _this->GetCurEditor() == NULL )
1973 		return;
1974 
1975 	GtkWidget *dialog = gtk_file_chooser_dialog_new (
1976 							"Save Ansi File",
1977 							GTK_WINDOW(_this),
1978 							GTK_FILE_CHOOSER_ACTION_SAVE,
1979 							GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1980 							GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1981 							NULL);
1982 
1983 	GtkFileFilter *filter = gtk_file_filter_new();
1984 	gtk_file_filter_set_name(filter, "Ansi file");
1985 	gtk_file_filter_add_pattern(filter, "*.ans");
1986 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
1987 
1988 	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
1989 	{
1990 		string filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog));
1991 		_this->GetCurEditor()->EditorActions(CEditor::Save_Ansi_File, filename);
1992 	}
1993 	gtk_widget_destroy (dialog);
1994 }
1995 
OnClearScreen(GtkMenuItem * mitem,CMainFrame * _this)1996 void CMainFrame::OnClearScreen(GtkMenuItem *mitem, CMainFrame *_this)
1997 {
1998 	//do nothing if the current view is not Ansi Editor
1999 	if ( _this->GetCurEditor() == NULL )
2000 		return;
2001 
2002 	_this->GetCurEditor()->EditorActions(CEditor::Clear_Screen);
2003 	_this->GetCurEditorView()->UpdateEditor();
2004 }
2005 
2006 /**
2007 *   Set text to blink.
2008 */
SetBlink(GtkToggleButton * togglebutton,CMainFrame * _this)2009 void CMainFrame::SetBlink(GtkToggleButton *togglebutton, CMainFrame *_this)
2010 {
2011 	//do nothing if the current view is not Ansi Editor
2012 	if( _this->m_Views.empty() ||  _this->GetCurEditor() == NULL )
2013 		return;
2014 
2015 	bool blink = (togglebutton->active)? true: false;
2016 
2017 	_this->GetCurEditor()->ApplyAnsiColor(-1, blink, -1, -1);
2018 
2019 	_this->GetCurEditorView()->SetFocus();
2020 }
2021 
2022 
SetTextColor(GtkComboBox * widget,CMainFrame * _this)2023 void CMainFrame::SetTextColor(GtkComboBox *widget, CMainFrame* _this)
2024 {
2025 	//do nothing if the current view is not Ansi Editor
2026 	if( _this->GetCurEditor() == NULL )
2027 		return;
2028 
2029 	//do not change color if view is empty
2030 	if( _this->m_Views.empty() )
2031 	{
2032 		gtk_combo_box_set_active(GTK_COMBO_BOX(_this->m_cbTextColor), 0);
2033 		return;
2034 	}
2035 
2036 	int cbIndex = gtk_combo_box_get_active(GTK_COMBO_BOX(_this->m_cbTextColor));
2037 
2038 	//index 0 is just a title, not a color. Do nothing
2039 	if( cbIndex == 0 )
2040 		return;
2041 
2042 	cbIndex--;
2043 
2044 	bool bright = (int)(cbIndex / 8);
2045 
2046 	int foreground;
2047 	stringstream ss;
2048 	ss << cbIndex % 8;
2049 	ss >> foreground;
2050 
2051 	_this->GetCurEditor()->ApplyAnsiColor(bright, -1, foreground, -1);
2052 	_this->GetCurEditorView()->SetFocus();
2053 }
2054 
2055 
SetBgColor(GtkComboBox * widget,CMainFrame * _this)2056 void CMainFrame::SetBgColor(GtkComboBox *widget, CMainFrame* _this)
2057 {
2058 	//do nothing if the current view is not Ansi Editor
2059 	if( _this->GetCurEditor() == NULL )
2060 		return;
2061 
2062 	//do not change color if view is empty
2063 	if( _this->m_Views.empty() )
2064 	{
2065 		gtk_combo_box_set_active(GTK_COMBO_BOX(_this->m_cbBgColor), 0);
2066 		return;
2067 	}
2068 
2069 	int cbIndex = gtk_combo_box_get_active(GTK_COMBO_BOX(_this->m_cbBgColor));
2070 
2071 	//index 0 is just a title, not a bg color. Do nothing
2072 	if( cbIndex == 0 )
2073 		return;
2074 
2075 	cbIndex--;
2076 
2077 	stringstream ss;
2078 	ss << cbIndex % 8;
2079 	int bgColor;
2080 	ss >> bgColor;
2081 
2082 	_this->GetCurEditor()->ApplyAnsiColor(-1, -1, -1, bgColor);
2083 	_this->GetCurEditorView()->SetFocus();
2084 }
2085 
AppendRow(GtkTreeIter * iter,GtkListStore * store,const gchar * display,const gchar * color)2086 void CMainFrame::AppendRow(GtkTreeIter *iter, GtkListStore *store, const gchar *display, const gchar *color)
2087 {
2088 	gtk_list_store_append(store, iter);
2089 	gtk_list_store_set(store, iter, 0, display, 1, color, -1);
2090 }
2091 
2092 /**
2093 *   parse the output format from GdkColor: #rrrrggggbbbb to the normal format: #rrggbb
2094 */
ParseColor(GdkColor * color,gchar * res,size_t res_len)2095 void CMainFrame::ParseColor(GdkColor *color, gchar *res, size_t res_len)
2096 {
2097 	g_assert(res_len >= 8);
2098 
2099 	string color_present = gdk_color_to_string(color);
2100 
2101 	res[0] = color_present[0];
2102 	res[1] = color_present[1];
2103 	res[2] = color_present[2];
2104 	res[3] = color_present[5];
2105 	res[4] = color_present[6];
2106 	res[5] = color_present[9];
2107 	res[6] = color_present[10];
2108 	res[7] = 0;
2109 }
2110