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