1 /*
2 * Copyright © 2004-2008 Jens Oknelid, paskharen@gmail.com
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * In addition, as a special exception, compiling, linking, and/or
19 * using OpenSSL with this program is allowed.
20 */
21
22 #include "mainwindow.hh"
23
24 #include <iostream>
25 #include <sstream>
26 #include <iomanip>
27 #include <iterator>
28
29 #ifdef HAVE_LIBNOTIFY
30 #include <libnotify/notify.h>
31 #endif
32
33 #include <dcpp/FavoriteManager.h>
34 #include <dcpp/ShareManager.h>
35 #include <dcpp/Text.h>
36 #include <dcpp/Upload.h>
37 #include <dcpp/Download.h>
38 #include <dcpp/ClientManager.h>
39 #include <dcpp/version.h>
40 #include "version.hh"
41 #include "downloadqueue.hh"
42 #include "favoritehubs.hh"
43 #include "favoriteusers.hh"
44 #include "finishedtransfers.hh"
45 #include "func.hh"
46 #include "hub.hh"
47 #include "privatemessage.hh"
48 #include "publichubs.hh"
49 #include "search.hh"
50 #include "settingsmanager.hh"
51 #include "sharebrowser.hh"
52 #include "UserCommandMenu.hh"
53 #include "wulformanager.hh"
54 #include "WulforUtil.hh"
55
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <fcntl.h>
59
60 using namespace std;
61 using namespace dcpp;
62
MainWindow()63 MainWindow::MainWindow():
64 Entry(Entry::MAIN_WINDOW, "mainwindow.glade"),
65 transfers(NULL),
66 lastUpdate(0),
67 lastUp(0),
68 lastDown(0),
69 minimized(FALSE)
70 {
71 window = GTK_WINDOW(getWidget("mainWindow"));
72 gtk_window_set_role(window, getID().c_str());
73
74 // Configure the dialogs
75 gtk_dialog_set_alternative_button_order(GTK_DIALOG(getWidget("exitDialog")), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
76 gtk_dialog_set_alternative_button_order(GTK_DIALOG(getWidget("connectDialog")), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
77 gtk_dialog_set_alternative_button_order(GTK_DIALOG(getWidget("flistDialog")), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
78 gtk_dialog_set_alternative_button_order(GTK_DIALOG(getWidget("ucLineDialog")), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
79 gtk_window_set_transient_for(GTK_WINDOW(getWidget("exitDialog")), window);
80 gtk_window_set_transient_for(GTK_WINDOW(getWidget("connectDialog")), window);
81 gtk_window_set_transient_for(GTK_WINDOW(getWidget("flistDialog")), window);
82 gtk_window_set_transient_for(GTK_WINDOW(getWidget("ucLineDialog")), window);
83 gtk_window_set_transient_for(GTK_WINDOW(getWidget("magnetDialog")), window);
84
85 gtk_about_dialog_set_email_hook((GtkAboutDialogActivateLinkFunc)onAboutDialogActivateLink_gui, (gpointer)this, NULL);
86 gtk_about_dialog_set_url_hook((GtkAboutDialogActivateLinkFunc)onAboutDialogActivateLink_gui, (gpointer)this, NULL);
87 const char *aboutCommentsFormat = gtk_about_dialog_get_comments(GTK_ABOUT_DIALOG(getWidget("aboutDialog")));
88 int len = strlen(aboutCommentsFormat) + strlen(LINUXDCPP_VERSION_STRING) + strlen(VERSIONSTRING) + 1;
89 char* commentsStr = new char[len];
90 g_snprintf(commentsStr, len, aboutCommentsFormat, LINUXDCPP_VERSION_STRING, VERSIONSTRING);
91 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(getWidget("aboutDialog")), commentsStr);
92 delete[] commentsStr;
93
94 // This has to be set in code in order to activate the link
95 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(getWidget("aboutDialog")), "https://launchpad.net/linuxdcpp");
96 gtk_window_set_transient_for(GTK_WINDOW(getWidget("aboutDialog")), window);
97
98 // Set all windows to the default icon
99 gtk_window_set_default_icon_name(g_get_prgname());
100
101 // All notebooks created in glade need one page.
102 // In our case, this is just a placeholder, so we remove it.
103 gtk_notebook_remove_page(GTK_NOTEBOOK(getWidget("book")), -1);
104 g_object_set_data(G_OBJECT(getWidget("book")), "page-rotation-list", NULL);
105 gtk_widget_set_sensitive(getWidget("closeMenuItem"), FALSE);
106
107 // Connect the signals to their callback functions.
108 g_signal_connect(window, "delete-event", G_CALLBACK(onCloseWindow_gui), (gpointer)this);
109 g_signal_connect(window, "window-state-event", G_CALLBACK(onWindowState_gui), (gpointer)this);
110 g_signal_connect(window, "focus-in-event", G_CALLBACK(onFocusIn_gui), (gpointer)this);
111 g_signal_connect(window, "key-press-event", G_CALLBACK(onKeyPressed_gui), (gpointer)this);
112 g_signal_connect(getWidget("book"), "switch-page", G_CALLBACK(onPageSwitched_gui), (gpointer)this);
113 g_signal_connect_after(getWidget("pane"), "realize", G_CALLBACK(onPaneRealized_gui), (gpointer)this);
114 g_signal_connect(getWidget("favHubs"), "clicked", G_CALLBACK(onFavoriteHubsClicked_gui), (gpointer)this);
115 g_signal_connect(getWidget("favUsers"), "clicked", G_CALLBACK(onFavoriteUsersClicked_gui), (gpointer)this);
116 g_signal_connect(getWidget("publicHubs"), "clicked", G_CALLBACK(onPublicHubsClicked_gui), (gpointer)this);
117 g_signal_connect(getWidget("settings"), "clicked", G_CALLBACK(onPreferencesClicked_gui), (gpointer)this);
118 g_signal_connect(getWidget("hash"), "clicked", G_CALLBACK(onHashClicked_gui), (gpointer)this);
119 g_signal_connect(getWidget("search"), "clicked", G_CALLBACK(onSearchClicked_gui), (gpointer)this);
120 g_signal_connect(getWidget("queue"), "clicked", G_CALLBACK(onDownloadQueueClicked_gui), (gpointer)this);
121 g_signal_connect(getWidget("finishedDownloads"), "clicked", G_CALLBACK(onFinishedDownloadsClicked_gui), (gpointer)this);
122 g_signal_connect(getWidget("finishedUploads"), "clicked", G_CALLBACK(onFinishedUploadsClicked_gui), (gpointer)this);
123 g_signal_connect(getWidget("openFileListMenuItem"), "activate", G_CALLBACK(onOpenFileListClicked_gui), (gpointer)this);
124 g_signal_connect(getWidget("openOwnListMenuItem"), "activate", G_CALLBACK(onOpenOwnListClicked_gui), (gpointer)this);
125 g_signal_connect(getWidget("refreshFileListMenuItem"), "activate", G_CALLBACK(onRefreshFileListClicked_gui), (gpointer)this);
126 g_signal_connect(getWidget("quickConnectMenuItem"), "activate", G_CALLBACK(onConnectClicked_gui), (gpointer)this);
127 g_signal_connect(getWidget("reconnectMenuItem"), "activate", G_CALLBACK(onReconnectClicked_gui), (gpointer)this);
128 g_signal_connect(getWidget("settingsMenuItem"), "activate", G_CALLBACK(onPreferencesClicked_gui), (gpointer)this);
129 g_signal_connect(getWidget("closeMenuItem"), "activate", G_CALLBACK(onCloseClicked_gui), (gpointer)this);
130 g_signal_connect(getWidget("exitMenuItem"), "activate", G_CALLBACK(onQuitClicked_gui), (gpointer)this);
131 g_signal_connect(getWidget("favoriteHubsMenuItem"), "activate", G_CALLBACK(onFavoriteHubsClicked_gui), (gpointer)this);
132 g_signal_connect(getWidget("favoriteUsersMenuItem"), "activate", G_CALLBACK(onFavoriteUsersClicked_gui), (gpointer)this);
133 g_signal_connect(getWidget("publicHubsMenuItem"), "activate", G_CALLBACK(onPublicHubsClicked_gui), (gpointer)this);
134 g_signal_connect(getWidget("indexingProgressMenuItem"), "activate", G_CALLBACK(onHashClicked_gui), (gpointer)this);
135 g_signal_connect(getWidget("searchMenuItem"), "activate", G_CALLBACK(onSearchClicked_gui), (gpointer)this);
136 g_signal_connect(getWidget("downloadQueueMenuItem"), "activate", G_CALLBACK(onDownloadQueueClicked_gui), (gpointer)this);
137 g_signal_connect(getWidget("finishedDownloadsMenuItem"), "activate", G_CALLBACK(onFinishedDownloadsClicked_gui), (gpointer)this);
138 g_signal_connect(getWidget("finishedUploadsMenuItem"), "activate", G_CALLBACK(onFinishedUploadsClicked_gui), (gpointer)this);
139 g_signal_connect(getWidget("previousTabMenuItem"), "activate", G_CALLBACK(onPreviousTabClicked_gui), (gpointer)this);
140 g_signal_connect(getWidget("nextTabMenuItem"), "activate", G_CALLBACK(onNextTabClicked_gui), (gpointer)this);
141 g_signal_connect(getWidget("helpOnlineMenuItem"), "activate", G_CALLBACK(onHelpOnlineItemActivated_gui), (gpointer)this);
142 g_signal_connect(getWidget("reportProblemMenuItem"), "activate", G_CALLBACK(onReportProblemItemActivated_gui), (gpointer)this);
143 g_signal_connect(getWidget("translateApplicationMenuItem"), "activate", G_CALLBACK(onTranslateApplicationItemActivated_gui), (gpointer)this);
144 g_signal_connect(getWidget("aboutMenuItem"), "activate", G_CALLBACK(onAboutClicked_gui), (gpointer)this);
145
146 // Load window state and position from settings manager
147 gint posX = WGETI("main-window-pos-x");
148 gint posY = WGETI("main-window-pos-y");
149 gint sizeX = WGETI("main-window-size-x");
150 gint sizeY = WGETI("main-window-size-y");
151
152 gtk_window_move(window, posX, posY);
153 gtk_window_resize(window, sizeX, sizeY);
154 if (WGETI("main-window-maximized"))
155 gtk_window_maximize(window);
156
157 GtkWidget *dummy;
158 GtkRequisition req;
159 dummy = gtk_statusbar_new();
160 gtk_widget_size_request(dummy, &req);
161 gtk_widget_destroy(dummy);
162 emptyStatusWidth = req.width;
163
164 // TRANSLATORS: Shown in status bar on startup.
165 setMainStatus_gui(F_("Welcome to %1%", % g_get_application_name()));
166
167 loadIcons_gui();
168 showTransfersPane_gui();
169
170 // Set up our IPC
171 createIPCPipe();
172
173 // Putting this after all the resizing and moving makes the window appear
174 // in the correct position instantly, looking slightly more cool
175 // (seems we have rather poor standards for cool?)
176 gtk_widget_show_all(GTK_WIDGET(window));
177
178 setTabPosition_gui(WGETI("tab-position"));
179 setToolbarStyle_gui(WGETI("toolbar-style"));
180
181 createStatusIcon_gui();
182 }
183
~MainWindow()184 MainWindow::~MainWindow()
185 {
186 if (IPC != NULL) {
187 int fd = g_io_channel_unix_get_fd(IPC);
188 g_io_channel_shutdown(IPC, FALSE, NULL);
189 g_io_channel_unref(IPC);
190 close(fd);
191 unlink(WulforUtil::getPipePath().c_str());
192 }
193
194 QueueManager::getInstance()->removeListener(this);
195 TimerManager::getInstance()->removeListener(this);
196 LogManager::getInstance()->removeListener(this);
197
198 GList *list = (GList *)g_object_get_data(G_OBJECT(getWidget("book")), "page-rotation-list");
199 g_list_free(list);
200
201 // Save window state and position
202 gint posX, posY, sizeX, sizeY, transferPanePosition;
203 bool maximized = TRUE;
204 GdkWindowState gdkState;
205
206 gtk_window_get_position(window, &posX, &posY);
207 gtk_window_get_size(window, &sizeX, &sizeY);
208 gdkState = gdk_window_get_state(GTK_WIDGET(window)->window);
209 transferPanePosition = sizeY - gtk_paned_get_position(GTK_PANED(getWidget("pane")));
210
211 if (!(gdkState & GDK_WINDOW_STATE_MAXIMIZED))
212 {
213 maximized = FALSE;
214 // The get pos/size functions return junk when window is maximized
215 WSET("main-window-pos-x", posX);
216 WSET("main-window-pos-y", posY);
217 WSET("main-window-size-x", sizeX);
218 WSET("main-window-size-y", sizeY);
219 }
220
221 WSET("main-window-maximized", maximized);
222 if (transferPanePosition > 10)
223 WSET("transfer-pane-position", transferPanePosition);
224
225 gtk_widget_destroy(GTK_WIDGET(window));
226 g_object_unref(statusIcon);
227
228 #ifdef HAVE_LIBNOTIFY
229 notify_uninit();
230 #endif
231 }
232
getContainer()233 GtkWidget *MainWindow::getContainer()
234 {
235 return getWidget("mainWindow");
236 }
237
show()238 void MainWindow::show()
239 {
240 QueueManager::getInstance()->addListener(this);
241 TimerManager::getInstance()->addListener(this);
242 LogManager::getInstance()->addListener(this);
243
244 typedef Func0<MainWindow> F0;
245 F0 *f0 = new F0(this, &MainWindow::startSocket_client);
246 WulforManager::get()->dispatchClientFunc(f0);
247
248 f0 = new F0(this, &MainWindow::autoConnect_client);
249 WulforManager::get()->dispatchClientFunc(f0);
250
251 autoOpen_gui();
252
253 if (WGETI("show-preferences-on-startup"))
254 {
255 onPreferencesClicked_gui(NULL, (gpointer)this);
256 WSET("show-preferences-on-startup", 0);
257 }
258 }
259
setTitle(const string & text)260 void MainWindow::setTitle(const string& text)
261 {
262 string title;
263
264 if (!text.empty())
265 title = text + " - " + g_get_application_name();
266 else
267 title = g_get_application_name();
268
269 gtk_window_set_title(window, title.c_str());
270 }
271
isActive_gui()272 bool MainWindow::isActive_gui()
273 {
274 return gtk_window_is_active(window);
275 }
276
setUrgent_gui()277 void MainWindow::setUrgent_gui()
278 {
279 gtk_window_set_urgency_hint(window, true);
280 }
281
282 /*
283 * Create and show Transfers pane
284 */
showTransfersPane_gui()285 void MainWindow::showTransfersPane_gui()
286 {
287 dcassert(transfers == NULL);
288
289 transfers = new Transfers();
290 gtk_paned_pack2(GTK_PANED(getWidget("pane")), transfers->getContainer(), TRUE, TRUE);
291 addChild(transfers);
292 transfers->show();
293 }
294
295 /*
296 * Load the custom icons or the stock icons as per the setting
297 */
loadIcons_gui()298 void MainWindow::loadIcons_gui()
299 {
300 WulforUtil::registerIcons();
301
302 // Reset the stock IDs manually to force the icon to refresh
303 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(getWidget("favHubs")), "linuxdcpp-favorite-hubs");
304 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(getWidget("favUsers")), "linuxdcpp-favorite-users");
305 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(getWidget("publicHubs")), "linuxdcpp-public-hubs");
306 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(getWidget("settings")), "linuxdcpp-preferences");
307 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(getWidget("hash")), "linuxdcpp-hash");
308 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(getWidget("search")), "linuxdcpp-search");
309 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(getWidget("queue")), "linuxdcpp-queue");
310 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(getWidget("finishedDownloads")), "linuxdcpp-finished-downloads");
311 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(getWidget("finishedUploads")), "linuxdcpp-finished-uploads");
312 }
313
autoOpen_gui()314 void MainWindow::autoOpen_gui()
315 {
316 if (BOOLSETTING(OPEN_PUBLIC))
317 showPublicHubs_gui();
318 if (BOOLSETTING(OPEN_QUEUE))
319 showDownloadQueue_gui();
320 if (BOOLSETTING(OPEN_FAVORITE_HUBS))
321 showFavoriteHubs_gui();
322 if (BOOLSETTING(OPEN_FAVORITE_USERS))
323 showFavoriteUsers_gui();
324 if (BOOLSETTING(OPEN_FINISHED_DOWNLOADS))
325 showFinishedDownloads_gui();
326 if (BOOLSETTING(OPEN_FINISHED_UPLOADS))
327 showFinishedUploads_gui();
328 }
329
addBookEntry_gui(BookEntry * entry)330 void MainWindow::addBookEntry_gui(BookEntry *entry)
331 {
332 addChild(entry);
333
334 GtkWidget *page = entry->getContainer();
335 GtkWidget *label = entry->getLabelBox();
336 GtkWidget *closeButton = entry->getCloseButton();
337 GtkWidget *tabMenuItem = entry->getTabMenuItem();
338
339 addTabMenuItem_gui(tabMenuItem, page);
340
341 gtk_notebook_append_page(GTK_NOTEBOOK(getWidget("book")), page, label);
342
343 g_signal_connect(label, "button-release-event", G_CALLBACK(onButtonReleasePage_gui), (gpointer)entry);
344 g_signal_connect(closeButton, "button-release-event", G_CALLBACK(onButtonReleasePage_gui), (gpointer)entry);
345 g_signal_connect(closeButton, "clicked", G_CALLBACK(onCloseBookEntry_gui), (gpointer)entry);
346
347 gtk_widget_set_sensitive(getWidget("closeMenuItem"), TRUE);
348
349 gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(getWidget("book")), page, TRUE);
350
351 entry->show();
352 }
353
currentPage_gui()354 GtkWidget *MainWindow::currentPage_gui()
355 {
356 int pageNum = gtk_notebook_get_current_page(GTK_NOTEBOOK(getWidget("book")));
357
358 if (pageNum == -1)
359 return NULL;
360 else
361 return gtk_notebook_get_nth_page(GTK_NOTEBOOK(getWidget("book")), pageNum);
362 }
363
raisePage_gui(GtkWidget * page)364 void MainWindow::raisePage_gui(GtkWidget *page)
365 {
366 int num = gtk_notebook_page_num(GTK_NOTEBOOK(getWidget("book")), page);
367 int currentNum = gtk_notebook_get_current_page(GTK_NOTEBOOK(getWidget("book")));
368
369 if (num != -1 && num != currentNum)
370 gtk_notebook_set_current_page(GTK_NOTEBOOK(getWidget("book")), num);
371 }
372
removeBookEntry_gui(BookEntry * entry)373 void MainWindow::removeBookEntry_gui(BookEntry *entry)
374 {
375 GtkNotebook *book = GTK_NOTEBOOK(getWidget("book"));
376 GtkWidget *page = entry->getContainer();
377 GtkWidget* menuItem = entry->getTabMenuItem();
378 int num = gtk_notebook_page_num(book, page);
379 removeChild(entry);
380
381 if (num != -1)
382 {
383 GList *list = (GList *)g_object_get_data(G_OBJECT(book), "page-rotation-list");
384 list = g_list_remove(list, (gpointer)page);
385 g_object_set_data(G_OBJECT(book), "page-rotation-list", (gpointer)list);
386
387 // if removing the current page, switch to the previous page in the rotation list
388 if (num == gtk_notebook_get_current_page(book))
389 {
390 GList *prev = g_list_first(list);
391 if (prev != NULL)
392 {
393 gint childNum = gtk_notebook_page_num(book, GTK_WIDGET(prev->data));
394 gtk_notebook_set_current_page(book, childNum);
395 }
396 }
397 gtk_notebook_remove_page(book, num);
398
399 removeTabMenuItem_gui(menuItem);
400
401 if (gtk_notebook_get_n_pages(book) == 0)
402 {
403 gtk_widget_set_sensitive(getWidget("closeMenuItem"), FALSE);
404 setTitle(""); // Reset window title to default
405 }
406 }
407 }
408
previousTab_gui()409 void MainWindow::previousTab_gui()
410 {
411 GtkNotebook *book = GTK_NOTEBOOK(getWidget("book"));
412
413 if (gtk_notebook_get_current_page(book) == 0)
414 gtk_notebook_set_current_page(book, -1);
415 else
416 gtk_notebook_prev_page(book);
417 }
418
nextTab_gui()419 void MainWindow::nextTab_gui()
420 {
421 GtkNotebook *book = GTK_NOTEBOOK(getWidget("book"));
422
423 if (gtk_notebook_get_n_pages(book) - 1 == gtk_notebook_get_current_page(book))
424 gtk_notebook_set_current_page(book, 0);
425 else
426 gtk_notebook_next_page(book);
427 }
428
addTabMenuItem_gui(GtkWidget * menuItem,GtkWidget * page)429 void MainWindow::addTabMenuItem_gui(GtkWidget* menuItem, GtkWidget* page)
430 {
431 g_signal_connect(menuItem, "activate", G_CALLBACK(onRaisePage_gui), (gpointer)page);
432 gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("tabsMenu")), menuItem);
433 gtk_widget_show_all(getWidget("tabsMenu"));
434
435 gtk_widget_set_sensitive(getWidget("previousTabMenuItem"), TRUE);
436 gtk_widget_set_sensitive(getWidget("nextTabMenuItem"), TRUE);
437 gtk_widget_set_sensitive(getWidget("tabMenuSeparator"), TRUE);
438 }
439
removeTabMenuItem_gui(GtkWidget * menuItem)440 void MainWindow::removeTabMenuItem_gui(GtkWidget *menuItem)
441 {
442 GtkNotebook *book = GTK_NOTEBOOK(getWidget("book"));
443
444 gtk_container_remove(GTK_CONTAINER(getWidget("tabsMenu")), menuItem);
445
446 if (gtk_notebook_get_n_pages(book) == 0)
447 {
448 gtk_widget_set_sensitive(getWidget("previousTabMenuItem"), FALSE);
449 gtk_widget_set_sensitive(getWidget("nextTabMenuItem"), FALSE);
450 gtk_widget_set_sensitive(getWidget("tabMenuSeparator"), FALSE);
451 }
452 }
453
454 /*
455 * Create status icon.
456 */
createStatusIcon_gui()457 void MainWindow::createStatusIcon_gui()
458 {
459 statusIcon = gtk_status_icon_new_from_icon_name(g_get_prgname());
460
461 g_signal_connect(getWidget("statusIconQuitItem"), "activate", G_CALLBACK(onQuitClicked_gui), (gpointer)this);
462 g_signal_connect(getWidget("statusIconShowInterfaceItem"), "toggled", G_CALLBACK(onShowInterfaceToggled_gui), (gpointer)this);
463 g_signal_connect(statusIcon, "activate", G_CALLBACK(onStatusIconActivated_gui), (gpointer)this);
464 g_signal_connect(statusIcon, "popup-menu", G_CALLBACK(onStatusIconPopupMenu_gui), (gpointer)this);
465
466 if (BOOLSETTING(ALWAYS_TRAY))
467 gtk_status_icon_set_visible(statusIcon, TRUE);
468 else
469 gtk_status_icon_set_visible(statusIcon, FALSE);
470 }
471
updateStatusIconTooltip_gui(string download,string upload)472 void MainWindow::updateStatusIconTooltip_gui(string download, string upload)
473 {
474 // TRANSLATORS: Notify icon (systray) tooltip
475 string tooltip = F_("%1%\nDownload: %2%\nUpload: %3%", % g_get_application_name() % download % upload);
476 gtk_status_icon_set_tooltip(statusIcon, tooltip.c_str());
477 }
478
showNotification_gui(string title,string body)479 void MainWindow::showNotification_gui(string title, string body)
480 {
481 #ifdef HAVE_LIBNOTIFY
482 if (!notify_is_initted())
483 notify_init(g_get_application_name());
484
485 NotifyNotification *notification;
486 #ifdef HAVE_LIBNOTIFY_0_7
487 notification = notify_notification_new(title.c_str(), body.c_str(), g_get_prgname());
488 #else
489 notification = notify_notification_new_with_status_icon(title.c_str(), body.c_str(), g_get_prgname(), statusIcon);
490 #endif
491 notify_notification_show(notification, NULL);
492
493 g_object_unref(notification);
494 #endif
495 }
496
setMainStatus_gui(string text,time_t t)497 void MainWindow::setMainStatus_gui(string text, time_t t)
498 {
499 if (!text.empty())
500 {
501 text = "[" + Util::getShortTimeString(t) + "] " + text;
502 gtk_label_set_text(GTK_LABEL(getWidget("labelStatus")), text.c_str());
503 }
504 }
505
setStats_gui(string hubs,string downloadSpeed,string downloaded,string uploadSpeed,string uploaded)506 void MainWindow::setStats_gui(string hubs, string downloadSpeed,
507 string downloaded, string uploadSpeed, string uploaded)
508 {
509 gtk_label_set_text(GTK_LABEL(getWidget("labelHubs")), hubs.c_str());
510 gtk_label_set_text(GTK_LABEL(getWidget("labelDownloadSpeed")), downloadSpeed.c_str());
511 gtk_label_set_text(GTK_LABEL(getWidget("labelDownloaded")), downloaded.c_str());
512 gtk_label_set_text(GTK_LABEL(getWidget("labelUploadSpeed")), uploadSpeed.c_str());
513 gtk_label_set_text(GTK_LABEL(getWidget("labelUploaded")), uploaded.c_str());
514 }
515
findBookEntry(const EntryType type,const string & id)516 BookEntry* MainWindow::findBookEntry(const EntryType type, const string &id)
517 {
518 Entry *entry = getChild(type, id);
519 return dynamic_cast<BookEntry*>(entry);
520 }
521
showDownloadQueue_gui()522 void MainWindow::showDownloadQueue_gui()
523 {
524 BookEntry *entry = findBookEntry(Entry::DOWNLOAD_QUEUE);
525
526 if (entry == NULL)
527 {
528 entry = new DownloadQueue();
529 addBookEntry_gui(entry);
530 }
531
532 raisePage_gui(entry->getContainer());
533 }
534
showFavoriteHubs_gui()535 void MainWindow::showFavoriteHubs_gui()
536 {
537 BookEntry *entry = findBookEntry(Entry::FAVORITE_HUBS);
538
539 if (entry == NULL)
540 {
541 entry = new FavoriteHubs();
542 addBookEntry_gui(entry);
543 }
544
545 raisePage_gui(entry->getContainer());
546 }
547
showFavoriteUsers_gui()548 void MainWindow::showFavoriteUsers_gui()
549 {
550 BookEntry *entry = findBookEntry(Entry::FAVORITE_USERS);
551
552 if (entry == NULL)
553 {
554 entry = new FavoriteUsers();
555 addBookEntry_gui(entry);
556 }
557
558 raisePage_gui(entry->getContainer());
559 }
560
showFinishedDownloads_gui()561 void MainWindow::showFinishedDownloads_gui()
562 {
563 BookEntry *entry = findBookEntry(Entry::FINISHED_DOWNLOADS);
564
565 if (entry == NULL)
566 {
567 entry = FinishedTransfers::createFinishedDownloads();
568 addBookEntry_gui(entry);
569 }
570
571 raisePage_gui(entry->getContainer());
572 }
573
showFinishedUploads_gui()574 void MainWindow::showFinishedUploads_gui()
575 {
576 BookEntry *entry = findBookEntry(Entry::FINISHED_UPLOADS);
577
578 if (entry == NULL)
579 {
580 entry = FinishedTransfers::createFinishedUploads();
581 addBookEntry_gui(entry);
582 }
583
584 raisePage_gui(entry->getContainer());
585 }
586
showHub_gui(string address,string encoding)587 void MainWindow::showHub_gui(string address, string encoding)
588 {
589 BookEntry *entry = findBookEntry(Entry::HUB, address);
590
591 if (entry == NULL)
592 {
593 entry = new Hub(address, encoding);
594 addBookEntry_gui(entry);
595 }
596
597 raisePage_gui(entry->getContainer());
598 }
599
addPrivateMessage_gui(string cid,string hubUrl,string message,bool useSetting)600 void MainWindow::addPrivateMessage_gui(string cid, string hubUrl, string message, bool useSetting)
601 {
602 BookEntry *entry = findBookEntry(Entry::PRIVATE_MESSAGE, cid);
603 bool raise = TRUE;
604
605 // If PM is initiated by another user, use setting except if tab is already open.
606 if (useSetting)
607 raise = (entry == NULL) ? !BOOLSETTING(POPUNDER_PM) : FALSE;
608
609 if (entry == NULL)
610 {
611 entry = new PrivateMessage(cid, hubUrl);
612 addBookEntry_gui(entry);
613 }
614
615 if (!message.empty())
616 {
617 dynamic_cast<PrivateMessage*>(entry)->addMessage_gui(message);
618
619 if (WGETI("notify-pm") && !isActive_gui())
620 showNotification_gui(WulforUtil::getNicks(cid), message);
621 }
622
623 if (raise)
624 raisePage_gui(entry->getContainer());
625 }
626
showPublicHubs_gui()627 void MainWindow::showPublicHubs_gui()
628 {
629 BookEntry *entry = findBookEntry(Entry::PUBLIC_HUBS);
630
631 if (entry == NULL)
632 {
633 entry = new PublicHubs();
634 addBookEntry_gui(entry);
635 }
636
637 raisePage_gui(entry->getContainer());
638 }
639
showShareBrowser_gui(UserPtr user,string filename,string dir,bool useSetting)640 void MainWindow::showShareBrowser_gui(UserPtr user, string filename, string dir, bool useSetting)
641 {
642 bool raise = useSetting ? !BOOLSETTING(POPUNDER_FILELIST) : TRUE;
643 BookEntry *entry = findBookEntry(Entry::SHARE_BROWSER, user->getCID().toBase32());
644
645 if (entry == NULL)
646 {
647 entry = new ShareBrowser(user, filename, dir);
648 addBookEntry_gui(entry);
649 }
650
651 if (raise)
652 raisePage_gui(entry->getContainer());
653 }
654
addSearch_gui()655 Search *MainWindow::addSearch_gui()
656 {
657 Search *entry = new Search();
658 addBookEntry_gui(entry);
659 raisePage_gui(entry->getContainer());
660 return entry;
661 }
662
addMagnetSearch_gui(const string & magnet)663 Search *MainWindow::addMagnetSearch_gui(const string& magnet)
664 {
665 string name;
666 int64_t size;
667 string tth;
668
669 if (WulforUtil::splitMagnet(magnet, name, size, tth))
670 {
671 Search *s = addSearch_gui();
672 s->putValue_gui(tth, 0, SearchManager::SIZE_DONTCARE, SearchManager::TYPE_TTH);
673 return s;
674 }
675 return NULL;
676 }
677
setTabPosition_gui(int position)678 void MainWindow::setTabPosition_gui(int position)
679 {
680 GtkPositionType tabPosition;
681
682 switch (position)
683 {
684 case 0:
685 tabPosition = GTK_POS_TOP;
686 break;
687 case 1:
688 tabPosition = GTK_POS_LEFT;
689 break;
690 case 2:
691 tabPosition = GTK_POS_RIGHT;
692 break;
693 case 3:
694 tabPosition = GTK_POS_BOTTOM;
695 break;
696 default:
697 tabPosition = GTK_POS_TOP;
698 }
699
700 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(getWidget("book")), tabPosition);
701 }
702
setToolbarStyle_gui(int style)703 void MainWindow::setToolbarStyle_gui(int style)
704 {
705 GtkToolbarStyle toolbarStyle;
706
707 switch (style)
708 {
709 case 0:
710 toolbarStyle = GTK_TOOLBAR_ICONS;
711 break;
712 case 1:
713 toolbarStyle = GTK_TOOLBAR_TEXT;
714 break;
715 case 2:
716 toolbarStyle = GTK_TOOLBAR_BOTH;
717 break;
718 case 3:
719 toolbarStyle = GTK_TOOLBAR_BOTH_HORIZ;
720 break;
721 case 4:
722 gtk_widget_hide(getWidget("toolbar1"));
723 break;
724 case 5:
725 return;
726 default:
727 toolbarStyle = GTK_TOOLBAR_BOTH;
728 }
729
730 if (style != 4)
731 {
732 gtk_widget_show(getWidget("toolbar1"));
733 gtk_toolbar_set_style(GTK_TOOLBAR(getWidget("toolbar1")), toolbarStyle);
734 }
735 }
736
getUserCommandLines_gui(const string & command,StringMap & ucParams)737 bool MainWindow::getUserCommandLines_gui(const string &command, StringMap &ucParams)
738 {
739 string name;
740 string line;
741 StringMap done;
742 string::size_type i = 0;
743 string::size_type j = 0;
744
745 while ((i = command.find("%[line:", i)) != string::npos)
746 {
747 i += 7;
748 j = command.find(']', i);
749 if (j == string::npos)
750 break;
751
752 name = command.substr(i, j - i);
753 if (done.find(name) == done.end())
754 {
755 line.clear();
756
757 // TRANSLATORS: Appears in a dialog prompt when a user command requires arguments.
758 string label = F_("Enter a value for '%1%'", % name);
759
760 gtk_label_set_text(GTK_LABEL(getWidget("ucLabel")), label.c_str());
761 gtk_entry_set_text(GTK_ENTRY(getWidget("ucLineEntry")), "");
762 gtk_widget_grab_focus(getWidget("ucLineEntry"));
763
764 gint response = gtk_dialog_run(GTK_DIALOG(getWidget("ucLineDialog")));
765 gtk_widget_hide(getWidget("ucLineDialog"));
766
767 if (response == GTK_RESPONSE_OK)
768 line = gtk_entry_get_text(GTK_ENTRY(getWidget("ucLineEntry")));
769
770 if (!line.empty())
771 {
772 ucParams["line:" + name] = line;
773 done[name] = line;
774 }
775 else
776 return false;
777 }
778 i = j + 1;
779 }
780
781 return true;
782 }
783
openMagnetDialog_gui(const string & magnet)784 void MainWindow::openMagnetDialog_gui(const string &magnet)
785 {
786 string name;
787 int64_t size;
788 string tth;
789
790 WulforUtil::splitMagnet(magnet, name, size, tth);
791
792 gtk_entry_set_text(GTK_ENTRY(getWidget("magnetEntry")), magnet.c_str());
793 gtk_entry_set_text(GTK_ENTRY(getWidget("magnetNameEntry")), name.c_str());
794 gtk_entry_set_text(GTK_ENTRY(getWidget("magnetSizeEntry")), Util::formatBytes(size).c_str());
795 gtk_entry_set_text(GTK_ENTRY(getWidget("exactSizeEntry")), Util::formatExactSize(size).c_str());
796 gtk_entry_set_text(GTK_ENTRY(getWidget("tthEntry")), tth.c_str());
797
798 gtk_dialog_run(GTK_DIALOG(getWidget("magnetDialog")));
799 gtk_widget_hide(getWidget("magnetDialog"));
800 }
801
showMessageDialog_gui(const string primaryText,const string secondaryText)802 void MainWindow::showMessageDialog_gui(const string primaryText, const string secondaryText)
803 {
804 if (primaryText.empty())
805 return;
806
807 GtkWidget* dialog = gtk_message_dialog_new(window, GTK_DIALOG_DESTROY_WITH_PARENT,
808 GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "%s", primaryText.c_str());
809
810 if (!secondaryText.empty())
811 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", secondaryText.c_str());
812
813 gtk_dialog_run(GTK_DIALOG(dialog));
814 gtk_widget_destroy(dialog);
815 }
816
onWindowState_gui(GtkWidget * widget,GdkEventWindowState * event,gpointer data)817 gboolean MainWindow::onWindowState_gui(GtkWidget *widget, GdkEventWindowState *event, gpointer data)
818 {
819 MainWindow *mw = (MainWindow *)data;
820
821 if (!mw->minimized && event->new_window_state & (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_WITHDRAWN))
822 {
823 mw->minimized = TRUE;
824 if (BOOLSETTING(SettingsManager::AUTO_AWAY) && !Util::getAway())
825 Util::setAway(TRUE);
826 }
827 else if (mw->minimized && (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED ||
828 event->new_window_state == 0))
829 {
830 mw->minimized = FALSE;
831 if (BOOLSETTING(SettingsManager::AUTO_AWAY) && !Util::getManualAway())
832 Util::setAway(FALSE);
833 }
834
835 return TRUE;
836 }
837
onFocusIn_gui(GtkWidget * widget,GdkEventFocus * event,gpointer data)838 gboolean MainWindow::onFocusIn_gui(GtkWidget *widget, GdkEventFocus *event, gpointer data)
839 {
840 MainWindow *mw = (MainWindow *)data;
841 GtkWidget *child = mw->currentPage_gui();
842
843 if (child != NULL)
844 {
845 BookEntry *entry = (BookEntry *)g_object_get_data(G_OBJECT(child), "entry");
846 entry->setActive_gui();
847 }
848
849 gtk_window_set_urgency_hint(mw->window, FALSE);
850 return FALSE;
851 }
852
onCloseWindow_gui(GtkWidget * widget,GdkEvent * event,gpointer data)853 gboolean MainWindow::onCloseWindow_gui(GtkWidget *widget, GdkEvent *event, gpointer data)
854 {
855 MainWindow *mw = (MainWindow *)data;
856
857 if (!BOOLSETTING(CONFIRM_EXIT))
858 {
859 WulforManager::get()->deleteMainWindow();
860 return FALSE;
861 }
862
863 int response = gtk_dialog_run(GTK_DIALOG(mw->getWidget("exitDialog")));
864 gtk_widget_hide(mw->getWidget("exitDialog"));
865
866 if (response == GTK_RESPONSE_OK)
867 {
868 WulforManager::get()->deleteMainWindow();
869 return FALSE;
870 }
871
872 return TRUE;
873 }
874
onKeyPressed_gui(GtkWidget * widget,GdkEventKey * event,gpointer data)875 gboolean MainWindow::onKeyPressed_gui(GtkWidget *widget, GdkEventKey *event, gpointer data)
876 {
877 MainWindow *mw = (MainWindow *)data;
878
879 if (event->state & GDK_CONTROL_MASK)
880 {
881 if (event->state & GDK_SHIFT_MASK && event->keyval == GDK_ISO_Left_Tab)
882 {
883 mw->previousTab_gui();
884 return TRUE;
885 }
886 else if (event->keyval == GDK_Tab)
887 {
888 mw->nextTab_gui();
889 return TRUE;
890 }
891 else if (event->keyval == GDK_F4)
892 {
893 onCloseClicked_gui(widget, data);
894 return TRUE;
895 }
896 }
897
898 return FALSE;
899 }
900
onButtonReleasePage_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)901 gboolean MainWindow::onButtonReleasePage_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
902 {
903 gint width, height;
904 gdk_drawable_get_size(event->window, &width, &height);
905
906 // If middle mouse button was released when hovering over tab label
907 if (event->button == 2 && event->x >= 0 && event->y >= 0
908 && event->x < width && event->y < height)
909 {
910 BookEntry *entry = (BookEntry *)data;
911 WulforManager::get()->getMainWindow()->removeBookEntry_gui(entry);
912 return TRUE;
913 }
914
915 return FALSE;
916 }
917
onRaisePage_gui(GtkMenuItem * item,gpointer data)918 void MainWindow::onRaisePage_gui(GtkMenuItem *item, gpointer data)
919 {
920 WulforManager::get()->getMainWindow()->raisePage_gui((GtkWidget *)data);
921 }
922
onPageSwitched_gui(GtkNotebook * notebook,GtkNotebookPage * page,guint num,gpointer data)923 void MainWindow::onPageSwitched_gui(GtkNotebook *notebook, GtkNotebookPage *page, guint num, gpointer data)
924 {
925 MainWindow* mw = (MainWindow*)data;
926 GtkWidget *child = gtk_notebook_get_nth_page(notebook, num);
927 BookEntry *entry = (BookEntry *)g_object_get_data(G_OBJECT(child), "entry");
928
929 if (entry)
930 {
931 // Disable "activate" signal on the tab menu item since it can cause
932 // onPageSwitched_gui to be called multiple times
933 GtkWidget *item = entry->getTabMenuItem();
934 g_signal_handlers_block_by_func(item, (gpointer)onRaisePage_gui, child);
935
936 entry->setActive_gui();
937 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(entry->getTabMenuItem()), TRUE);
938 mw->setTitle(entry->getLabelText()); // Update window title with selected tab label
939
940 g_signal_handlers_unblock_by_func(item, (gpointer)onRaisePage_gui, (gpointer)child);
941 }
942
943 GList *list = (GList *)g_object_get_data(G_OBJECT(notebook), "page-rotation-list");
944 list = g_list_remove(list, (gpointer)child);
945 list = g_list_prepend(list, (gpointer)child);
946 g_object_set_data(G_OBJECT(notebook), "page-rotation-list", (gpointer)list);
947
948 // Focus the tab so it will focus its children (e.g. a text entry box)
949 gtk_widget_grab_focus(child);
950 }
951
onPaneRealized_gui(GtkWidget * pane,gpointer data)952 void MainWindow::onPaneRealized_gui(GtkWidget *pane, gpointer data)
953 {
954 MainWindow *mw = (MainWindow *)data;
955 gint position = WGETI("transfer-pane-position");
956
957 if (position > 10)
958 {
959 // @todo: fix get window height when maximized
960 gint height;
961 gtk_window_get_size(mw->window, NULL, &height);
962 gtk_paned_set_position(GTK_PANED(pane), height - position);
963 }
964 }
965
onConnectClicked_gui(GtkWidget * widget,gpointer data)966 void MainWindow::onConnectClicked_gui(GtkWidget *widget, gpointer data)
967 {
968 MainWindow *mw = (MainWindow *)data;
969
970 gtk_editable_select_region(GTK_EDITABLE(mw->getWidget("connectEntry")), 0, -1);
971 gtk_widget_grab_focus(mw->getWidget("connectEntry"));
972 int response = gtk_dialog_run(GTK_DIALOG(mw->getWidget("connectDialog")));
973 gtk_widget_hide(mw->getWidget("connectDialog"));
974
975 if (response == GTK_RESPONSE_OK)
976 {
977 string address = gtk_entry_get_text(GTK_ENTRY(mw->getWidget("connectEntry")));
978 mw->showHub_gui(address);
979 }
980 }
981
onFavoriteHubsClicked_gui(GtkWidget * widget,gpointer data)982 void MainWindow::onFavoriteHubsClicked_gui(GtkWidget *widget, gpointer data)
983 {
984 MainWindow *mw = (MainWindow *)data;
985 mw->showFavoriteHubs_gui();
986 }
987
onFavoriteUsersClicked_gui(GtkWidget * widget,gpointer data)988 void MainWindow::onFavoriteUsersClicked_gui(GtkWidget *widget, gpointer data)
989 {
990 MainWindow *mw = (MainWindow *)data;
991 mw->showFavoriteUsers_gui();
992 }
993
onPublicHubsClicked_gui(GtkWidget * widget,gpointer data)994 void MainWindow::onPublicHubsClicked_gui(GtkWidget *widget, gpointer data)
995 {
996 MainWindow *mw = (MainWindow *)data;
997 mw->showPublicHubs_gui();
998 }
999
onPreferencesClicked_gui(GtkWidget * widget,gpointer data)1000 void MainWindow::onPreferencesClicked_gui(GtkWidget *widget, gpointer data)
1001 {
1002 MainWindow *mw = (MainWindow *)data;
1003 typedef Func0<MainWindow> F0;
1004
1005 unsigned short tcpPort = (unsigned short)SETTING(TCP_PORT);
1006 unsigned short udpPort = (unsigned short)SETTING(UDP_PORT);
1007 int lastConn = SETTING(INCOMING_CONNECTIONS);
1008 bool stockIcons = WGETI("use-system-icons");
1009
1010 gint response = WulforManager::get()->openSettingsDialog_gui();
1011
1012 if (response == GTK_RESPONSE_OK)
1013 {
1014 if (SETTING(INCOMING_CONNECTIONS) != lastConn || SETTING(TCP_PORT) != tcpPort || SETTING(UDP_PORT) != udpPort)
1015 {
1016 F0 *func = new F0(mw, &MainWindow::startSocket_client);
1017 WulforManager::get()->dispatchClientFunc(func);
1018 }
1019
1020 if (BOOLSETTING(ALWAYS_TRAY))
1021 gtk_status_icon_set_visible(mw->statusIcon, TRUE);
1022 else
1023 gtk_status_icon_set_visible(mw->statusIcon, FALSE);
1024
1025 mw->setTabPosition_gui(WGETI("tab-position"));
1026 mw->setToolbarStyle_gui(WGETI("toolbar-style"));
1027
1028 // Reload the icons only if the setting has changed
1029 if (WGETI("use-system-icons") != stockIcons)
1030 mw->loadIcons_gui();
1031 }
1032 }
1033
onHashClicked_gui(GtkWidget * widget,gpointer data)1034 void MainWindow::onHashClicked_gui(GtkWidget *widget, gpointer data)
1035 {
1036 WulforManager::get()->openHashDialog_gui();
1037 }
1038
onSearchClicked_gui(GtkWidget * widget,gpointer data)1039 void MainWindow::onSearchClicked_gui(GtkWidget *widget, gpointer data)
1040 {
1041 MainWindow *mw = (MainWindow *)data;
1042 mw->addSearch_gui();
1043 }
1044
onDownloadQueueClicked_gui(GtkWidget * widget,gpointer data)1045 void MainWindow::onDownloadQueueClicked_gui(GtkWidget *widget, gpointer data)
1046 {
1047 MainWindow *mw = (MainWindow *)data;
1048 mw->showDownloadQueue_gui();
1049 }
1050
onFinishedDownloadsClicked_gui(GtkWidget * widget,gpointer data)1051 void MainWindow::onFinishedDownloadsClicked_gui(GtkWidget *widget, gpointer data)
1052 {
1053 MainWindow *mw = (MainWindow *)data;
1054 mw->showFinishedDownloads_gui();
1055 }
1056
onFinishedUploadsClicked_gui(GtkWidget * widget,gpointer data)1057 void MainWindow::onFinishedUploadsClicked_gui(GtkWidget *widget, gpointer data)
1058 {
1059 MainWindow *mw = (MainWindow *)data;
1060 mw->showFinishedUploads_gui();
1061 }
1062
onQuitClicked_gui(GtkWidget * widget,gpointer data)1063 void MainWindow::onQuitClicked_gui(GtkWidget *widget, gpointer data)
1064 {
1065 MainWindow *mw = (MainWindow *)data;
1066 gboolean retVal; // Not interested in the value, though.
1067 g_signal_emit_by_name(mw->window, "delete-event", NULL, &retVal);
1068 }
1069
onOpenFileListClicked_gui(GtkWidget * widget,gpointer data)1070 void MainWindow::onOpenFileListClicked_gui(GtkWidget *widget, gpointer data)
1071 {
1072 MainWindow *mw = (MainWindow *)data;
1073
1074 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(mw->getWidget("flistDialog")), Text::fromUtf8(Util::getListPath()).c_str());
1075
1076 int ret = gtk_dialog_run(GTK_DIALOG(mw->getWidget("flistDialog")));
1077 gtk_widget_hide(mw->getWidget("flistDialog"));
1078
1079 if (ret == GTK_RESPONSE_OK)
1080 {
1081 gchar *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(mw->getWidget("flistDialog")));
1082 if (temp)
1083 {
1084 string path = Text::toUtf8(temp);
1085 g_free(temp);
1086
1087 UserPtr user = DirectoryListing::getUserFromFilename(path);
1088 if (user)
1089 mw->showShareBrowser_gui(user, path, "", FALSE);
1090 else
1091 mw->setMainStatus_gui(_("Unable to load file list: Invalid file list name"));
1092 }
1093 }
1094 }
1095
onOpenOwnListClicked_gui(GtkWidget * widget,gpointer data)1096 void MainWindow::onOpenOwnListClicked_gui(GtkWidget *widget, gpointer data)
1097 {
1098 MainWindow *mw = (MainWindow *)data;
1099 typedef Func1<MainWindow, bool> F1;
1100 F1 *func = new F1(mw, &MainWindow::openOwnList_client, FALSE);
1101 WulforManager::get()->dispatchClientFunc(func);
1102
1103 mw->setMainStatus_gui(_("Loading file list"));
1104 }
1105
onRefreshFileListClicked_gui(GtkWidget * widget,gpointer data)1106 void MainWindow::onRefreshFileListClicked_gui(GtkWidget *widget, gpointer data)
1107 {
1108 typedef Func0<MainWindow> F0;
1109 F0 *func = new F0((MainWindow *)data, &MainWindow::refreshFileList_client);
1110 WulforManager::get()->dispatchClientFunc(func);
1111 }
1112
onReconnectClicked_gui(GtkWidget * widget,gpointer data)1113 void MainWindow::onReconnectClicked_gui(GtkWidget *widget, gpointer data)
1114 {
1115 MainWindow *mw = (MainWindow *)data;
1116 GtkWidget *entryWidget = mw->currentPage_gui();
1117
1118 if (entryWidget)
1119 {
1120 BookEntry *entry = (BookEntry *)g_object_get_data(G_OBJECT(entryWidget), "entry");
1121
1122 if (entry && entry->getType() == Entry::HUB)
1123 {
1124 Func0<Hub> *func = new Func0<Hub>(dynamic_cast<Hub *>(entry), &Hub::reconnect_client);
1125 WulforManager::get()->dispatchClientFunc(func);
1126 }
1127 }
1128 }
1129
onCloseClicked_gui(GtkWidget * widget,gpointer data)1130 void MainWindow::onCloseClicked_gui(GtkWidget *widget, gpointer data)
1131 {
1132 MainWindow *mw = (MainWindow *)data;
1133 GtkWidget *entryWidget = mw->currentPage_gui();
1134
1135 if (entryWidget)
1136 {
1137 BookEntry *entry = (BookEntry *)g_object_get_data(G_OBJECT(entryWidget), "entry");
1138
1139 if (entry)
1140 mw->removeBookEntry_gui(entry);
1141 }
1142 }
1143
onPreviousTabClicked_gui(GtkWidget * widget,gpointer data)1144 void MainWindow::onPreviousTabClicked_gui(GtkWidget* widget, gpointer data)
1145 {
1146 MainWindow *mw = (MainWindow *)data;
1147 mw->previousTab_gui();
1148 }
1149
onNextTabClicked_gui(GtkWidget * widget,gpointer data)1150 void MainWindow::onNextTabClicked_gui(GtkWidget* widget, gpointer data)
1151 {
1152 MainWindow *mw = (MainWindow *)data;
1153 mw->nextTab_gui();
1154 }
1155
onHelpOnlineItemActivated_gui(GtkMenuItem * item,gpointer data)1156 void MainWindow::onHelpOnlineItemActivated_gui(GtkMenuItem *item, gpointer data)
1157 {
1158 const string uri = "https://answers.launchpad.net/linuxdcpp";
1159 WulforUtil::openURI(uri);
1160 }
1161
onTranslateApplicationItemActivated_gui(GtkMenuItem * item,gpointer data)1162 void MainWindow::onTranslateApplicationItemActivated_gui(GtkMenuItem *item, gpointer data)
1163 {
1164 const string uri = "https://translations.launchpad.net/linuxdcpp";
1165 WulforUtil::openURI(uri);
1166 }
1167
onReportProblemItemActivated_gui(GtkMenuItem * item,gpointer data)1168 void MainWindow::onReportProblemItemActivated_gui(GtkMenuItem *item, gpointer data)
1169 {
1170 const string uri = "https://bugs.launchpad.net/linuxdcpp";
1171 WulforUtil::openURI(uri);
1172 }
1173
onAboutClicked_gui(GtkWidget * widget,gpointer data)1174 void MainWindow::onAboutClicked_gui(GtkWidget *widget, gpointer data)
1175 {
1176 MainWindow *mw = (MainWindow *)data;
1177 gtk_dialog_run(GTK_DIALOG(mw->getWidget("aboutDialog")));
1178 gtk_widget_hide(mw->getWidget("aboutDialog"));
1179 }
1180
onAboutDialogActivateLink_gui(GtkAboutDialog * dialog,const gchar * link,gpointer data)1181 void MainWindow::onAboutDialogActivateLink_gui(GtkAboutDialog *dialog, const gchar *link, gpointer data)
1182 {
1183 WulforUtil::openURI(link);
1184 }
1185
onCloseBookEntry_gui(GtkWidget * widget,gpointer data)1186 void MainWindow::onCloseBookEntry_gui(GtkWidget *widget, gpointer data)
1187 {
1188 BookEntry *entry = (BookEntry *)data;
1189 WulforManager::get()->getMainWindow()->removeBookEntry_gui(entry);
1190 }
1191
onStatusIconActivated_gui(GtkStatusIcon * statusIcon,gpointer data)1192 void MainWindow::onStatusIconActivated_gui(GtkStatusIcon *statusIcon, gpointer data)
1193 {
1194 MainWindow *mw = (MainWindow *)data;
1195 GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM(mw->getWidget("statusIconShowInterfaceItem"));
1196
1197 // Toggle the "Show Interface" check menu item. This will in turn invoke its callback.
1198 gboolean active = gtk_check_menu_item_get_active(item);
1199 gtk_check_menu_item_set_active(item, !active);
1200 }
1201
onStatusIconPopupMenu_gui(GtkStatusIcon * statusIcon,guint button,guint time,gpointer data)1202 void MainWindow::onStatusIconPopupMenu_gui(GtkStatusIcon *statusIcon, guint button, guint time, gpointer data)
1203 {
1204 MainWindow *mw = (MainWindow *)data;
1205 GtkMenu *menu = GTK_MENU(mw->getWidget("statusIconMenu"));
1206 gtk_menu_popup(menu, NULL, NULL, gtk_status_icon_position_menu, statusIcon, button, time);
1207 }
1208
onShowInterfaceToggled_gui(GtkCheckMenuItem * item,gpointer data)1209 void MainWindow::onShowInterfaceToggled_gui(GtkCheckMenuItem *item, gpointer data)
1210 {
1211 MainWindow *mw = (MainWindow *)data;
1212 GtkWindow *win = mw->window;
1213 static int x, y;
1214 static bool isMaximized, isIconified;
1215
1216 if (GTK_WIDGET_VISIBLE(win))
1217 {
1218 GdkWindowState state;
1219 gtk_window_get_position(win, &x, &y);
1220 state = gdk_window_get_state(GTK_WIDGET(win)->window);
1221 isMaximized = (state & GDK_WINDOW_STATE_MAXIMIZED);
1222 isIconified = (state & GDK_WINDOW_STATE_ICONIFIED);
1223 gtk_widget_hide(GTK_WIDGET(win));
1224 }
1225 else
1226 {
1227 gtk_window_move(win, x, y);
1228 if (isMaximized) gtk_window_maximize(win);
1229 if (isIconified) gtk_window_iconify(win);
1230 gtk_widget_show(GTK_WIDGET(win));
1231 }
1232 }
1233
autoConnect_client()1234 void MainWindow::autoConnect_client()
1235 {
1236 FavoriteHubEntry *hub;
1237 FavoriteHubEntryList &l = FavoriteManager::getInstance()->getFavoriteHubs();
1238 typedef Func2<MainWindow, string, string> F2;
1239 F2 *func;
1240
1241 for (FavoriteHubEntryList::const_iterator it = l.begin(); it != l.end(); ++it)
1242 {
1243 hub = *it;
1244
1245 if (hub->getConnect())
1246 {
1247 func = new F2(this, &MainWindow::showHub_gui, hub->getServer(), hub->getEncoding());
1248 WulforManager::get()->dispatchGuiFunc(func);
1249 }
1250 }
1251 }
1252
startSocket_client()1253 void MainWindow::startSocket_client()
1254 {
1255 SearchManager::getInstance()->disconnect();
1256 ConnectionManager::getInstance()->disconnect();
1257
1258 if (ClientManager::getInstance()->isActive())
1259 {
1260 try
1261 {
1262 ConnectionManager::getInstance()->listen();
1263 }
1264 catch (const Exception &e)
1265 {
1266 string primaryText = _("Unable to open TCP/TLS port");
1267 string secondaryText = _("File transfers will not work correctly until the connection settings are adjusted or any application using the port is closed.");
1268 typedef Func2<MainWindow, string, string> F2;
1269 F2* func = new F2(this, &MainWindow::showMessageDialog_gui, primaryText, secondaryText);
1270 WulforManager::get()->dispatchGuiFunc(func);
1271
1272 }
1273
1274 try
1275 {
1276 SearchManager::getInstance()->listen();
1277 }
1278 catch (const Exception &e)
1279 {
1280 string primaryText = _("Unable to open UDP port");
1281 string secondaryText = _("Searching will not work correctly until the connection settings are adjusted or any application using the port is closed.");
1282 typedef Func2<MainWindow, string, string> F2;
1283 F2* func = new F2(this, &MainWindow::showMessageDialog_gui, primaryText, secondaryText);
1284 WulforManager::get()->dispatchGuiFunc(func);
1285 }
1286 }
1287
1288 ClientManager::getInstance()->infoUpdated();
1289 }
1290
refreshFileList_client()1291 void MainWindow::refreshFileList_client()
1292 {
1293 try
1294 {
1295 ShareManager::getInstance()->setDirty();
1296 ShareManager::getInstance()->refresh(TRUE, TRUE, FALSE);
1297 }
1298 catch (const ShareException&)
1299 {
1300 }
1301 }
1302
addDownload_client(string name,string tth,int64_t size)1303 void MainWindow::addDownload_client(string name, string tth, int64_t size)
1304 {
1305 name = SETTING(DOWNLOAD_DIRECTORY) + name;
1306 UserPtr dummyuser(new User(CID::generate()));
1307 QueueManager::getInstance()->add(name, size, TTHValue(tth), dummyuser, "");
1308 QueueManager::getInstance()->removeSource(name, dummyuser, QueueItem::Source::FLAG_REMOVED);
1309 }
1310
openOwnList_client(bool useSetting)1311 void MainWindow::openOwnList_client(bool useSetting)
1312 {
1313 UserPtr user = ClientManager::getInstance()->getMe();
1314 string path = ShareManager::getInstance()->getOwnListFile();
1315
1316 typedef Func4<MainWindow, UserPtr, string, string, bool> F4;
1317 F4 *func = new F4(this, &MainWindow::showShareBrowser_gui, user, path, "", useSetting);
1318 WulforManager::get()->dispatchGuiFunc(func);
1319 }
1320
createIPCPipe()1321 void MainWindow::createIPCPipe()
1322 {
1323 const string pipepath = WulforUtil::getPipePath();
1324 dcdebug("MainWindow::createIPCPipe(): Pipepath %s\n", pipepath.c_str());
1325
1326 int status = mkfifo(pipepath.c_str(), S_IRWXU);
1327
1328 if (status == -1 && errno == EEXIST)
1329 {
1330 dcdebug("Stale pipe detected. Unlinking...\n");
1331 unlink(pipepath.c_str());
1332 }
1333
1334 if (status == 0 || mkfifo(pipepath.c_str(), S_IRWXU) == 0)
1335 {
1336 int fd = open(pipepath.c_str(), O_NONBLOCK | O_RDWR);
1337 if (fd >= 0)
1338 {
1339 IPC = g_io_channel_unix_new(fd); // Eh, can this fail?
1340 g_io_add_watch(IPC, G_IO_IN, onExternalData, this);
1341 g_io_add_watch(IPC, G_IO_PRI, onExternalData, this);
1342 }
1343 }
1344 else
1345 {
1346 dcdebug("MainWindow::MainWindow, mkfifo FAILED!\n");
1347 IPC = NULL;
1348 }
1349 }
1350
onExternalData(GIOChannel * source,GIOCondition cond,gpointer data)1351 gboolean MainWindow::onExternalData(GIOChannel* source, GIOCondition cond, gpointer data)
1352 {
1353 MainWindow* mw = (MainWindow*)data;
1354 if (mw->IPC != source)
1355 return TRUE;
1356
1357 if (cond != G_IO_IN && cond != G_IO_PRI)
1358 {
1359 if (cond == G_IO_HUP)
1360 dcdebug("G_IO_HUP\n");
1361 dcdebug("Weird things in IO Channel\n");
1362 return FALSE;
1363 }
1364
1365
1366 /* Currently this doesn't handle the situation where data is written
1367 * to pipe without newline. Apparently nothing is read in that case
1368 * and onExternalData is called again and again (causing high cpu usage).
1369 * So I guess the channel should be cleared somehow. */
1370 gchar *str;
1371 gsize len = 0;
1372 gsize termpos = 0;
1373 GIOStatus status = g_io_channel_read_line(source, &str, &len, &termpos, NULL);
1374 if (termpos > 0)
1375 str[termpos] = 0; // replace newline with 0
1376 dcdebug("MainWindow::onExternalData, from IO Channel: %s (%d)\n", str, (int)len);
1377 if (status == G_IO_STATUS_NORMAL && len > 0)
1378 {
1379 // Handle command
1380 string cmd(str);
1381 string arg;
1382 size_t pos = cmd.find(" ");
1383 g_free(str);
1384
1385 if (pos != string::npos && cmd.length() > pos + 1)
1386 {
1387 arg = cmd.substr(pos + 1);
1388 cmd = cmd.substr(0, pos);
1389 }
1390
1391 if (cmd == "show") {
1392 gtk_window_present(mw->window);
1393 }
1394 else if (cmd == "refresh")
1395 {
1396 typedef Func0<MainWindow> F0;
1397 F0 *func = new F0((MainWindow *)data, &MainWindow::refreshFileList_client);
1398 WulforManager::get()->dispatchClientFunc(func);
1399 }
1400 else if (cmd == "search-magnet")
1401 {
1402 mw->addMagnetSearch_gui(arg);
1403 }
1404 else if (cmd == "add-magnet")
1405 {
1406 string name;
1407 int64_t size;
1408 string tth;
1409
1410 if (WulforUtil::splitMagnet(arg, name, size, tth))
1411 {
1412 if (name == _("Unknown") || size == 0 || tth == _("Unknown"))
1413 mw->addMagnetSearch_gui(arg);
1414 else
1415 {
1416 typedef Func3<MainWindow, string, string, int64_t> F3;
1417 F3 *func = new F3(mw, &MainWindow::addDownload_client, name, tth, size);
1418 WulforManager::get()->dispatchClientFunc(func);
1419 }
1420 }
1421 }
1422 else if (cmd == "connect")
1423 {
1424 mw->showHub_gui(arg);
1425 }
1426 }
1427 else if (status != G_IO_STATUS_AGAIN)
1428 {
1429 dcdebug("Weird things in IO Channel\n");
1430 return FALSE;
1431 }
1432
1433 return TRUE;
1434 }
1435
on(LogManagerListener::Message,time_t t,const string & message)1436 void MainWindow::on(LogManagerListener::Message, time_t t, const string &message) throw()
1437 {
1438 typedef Func2<MainWindow, string, time_t> F2;
1439 F2 *func = new F2(this, &MainWindow::setMainStatus_gui, message, t);
1440 WulforManager::get()->dispatchGuiFunc(func);
1441 }
1442
on(QueueManagerListener::Finished,QueueItem * item,const string & dir,int64_t avSpeed)1443 void MainWindow::on(QueueManagerListener::Finished, QueueItem *item, const string& dir, int64_t avSpeed) throw()
1444 {
1445 if (item->isSet(QueueItem::FLAG_CLIENT_VIEW | QueueItem::FLAG_USER_LIST))
1446 {
1447 UserPtr user = item->getDownloads()[0]->getUser();
1448 string listName = item->getListName();
1449
1450 typedef Func4<MainWindow, UserPtr, string, string, bool> F4;
1451 F4 *func = new F4(this, &MainWindow::showShareBrowser_gui, user, listName, dir, TRUE);
1452 WulforManager::get()->dispatchGuiFunc(func);
1453 }
1454 else if (item->isSet(QueueItem::FLAG_NORMAL) && WGETI("notify-download"))
1455 {
1456 typedef Func2<MainWindow, string, string> F2;
1457 F2 *f2 = new F2(this, &MainWindow::showNotification_gui, _("Download finished"), item->getTargetFileName());
1458 WulforManager::get()->dispatchGuiFunc(f2);
1459 }
1460 }
1461
on(TimerManagerListener::Second,uint32_t ticks)1462 void MainWindow::on(TimerManagerListener::Second, uint32_t ticks) throw()
1463 {
1464 // Avoid calculating status update if it's not needed
1465 if (!BOOLSETTING(ALWAYS_TRAY) && minimized)
1466 return;
1467
1468 int64_t diff = (int64_t)((lastUpdate == 0) ? ticks - 1000 : ticks - lastUpdate);
1469 int64_t downBytes = 0;
1470 int64_t upBytes = 0;
1471
1472 if (diff > 0)
1473 {
1474 int64_t downDiff = Socket::getTotalDown() - lastDown;
1475 int64_t upDiff = Socket::getTotalUp() - lastUp;
1476 downBytes = (downDiff * 1000) / diff;
1477 upBytes = (upDiff * 1000) / diff;
1478 }
1479
1480 string hubs = Client::getCounts();
1481 string downloadSpeed = Util::formatBytes(downBytes) + "/s";
1482 string downloaded = Util::formatBytes(Socket::getTotalDown());
1483 string uploadSpeed = Util::formatBytes(upBytes) + "/s";
1484 string uploaded = Util::formatBytes(Socket::getTotalUp());
1485
1486 lastUpdate = ticks;
1487 lastUp = Socket::getTotalUp();
1488 lastDown = Socket::getTotalDown();
1489
1490 typedef Func5<MainWindow, string, string, string, string, string> F5;
1491 F5 *func = new F5(this, &MainWindow::setStats_gui, hubs, downloadSpeed, downloaded, uploadSpeed, uploaded);
1492 WulforManager::get()->dispatchGuiFunc(func);
1493
1494 if (BOOLSETTING(ALWAYS_TRAY) && !downloadSpeed.empty() && !uploadSpeed.empty())
1495 {
1496 typedef Func2<MainWindow, string, string> F2;
1497 F2 *f2 = new F2(this, &MainWindow::updateStatusIconTooltip_gui, downloadSpeed, uploadSpeed);
1498 WulforManager::get()->dispatchGuiFunc(f2);
1499 }
1500 }
1501
1502