Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
booru/browser: Allow tabs to be detached
Use Gio::Application instead of Gtk::Main. Gio::Application is used to create a unique process (requires dbus), nothing really changes for the user but it allows for booru browser tabs to be moved between any ahoviewer window cleanly. Without dbus nothing changes, but tabs will not be drag-and-dropable between different processes. D-Bus on Windows seems to be rather slow resulting in slow application startup speed. Some code clean up and misc bug fixes are mixed into this commit.
- Loading branch information
Showing
23 changed files
with
570 additions
and
278 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
#include <gtkmm.h> | ||
#include <iostream> | ||
#include <curl/curl.h> | ||
#include <libxml/parser.h> | ||
|
||
#include "application.h" | ||
using namespace AhoViewer; | ||
|
||
#include "config.h" | ||
#include "mainwindow.h" | ||
|
||
#ifdef USE_OPENSSL | ||
#include <openssl/opensslv.h> | ||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) | ||
#include <openssl/crypto.h> | ||
#include <shared_mutex> | ||
#include <deque> | ||
|
||
std::deque<std::shared_timed_mutex> locks; | ||
|
||
static void lock_callback(int mode, int type, const char*, int) | ||
{ | ||
if ((mode & CRYPTO_LOCK)) | ||
{ | ||
if ((mode & CRYPTO_READ)) | ||
locks[type].lock_shared(); | ||
else | ||
locks[type].lock(); | ||
} | ||
else | ||
{ | ||
if ((mode & CRYPTO_READ)) | ||
locks[type].unlock_shared(); | ||
else | ||
locks[type].unlock(); | ||
} | ||
} | ||
|
||
static unsigned long thread_id() | ||
{ | ||
return static_cast<unsigned long>(pthread_self()); | ||
} | ||
|
||
static void init_openssl_locks() | ||
{ | ||
locks.resize(CRYPTO_num_locks()); | ||
CRYPTO_set_id_callback(&thread_id); | ||
CRYPTO_set_locking_callback(&lock_callback); | ||
} | ||
#endif // OPENSSL_VERSION_NUMBER < 0x10100000L | ||
#endif // USE_OPENSSL | ||
|
||
#ifdef USE_GNUTLS | ||
#include <gcrypt.h> | ||
#if (GCRYPT_VERSION_NUMBER < 0x010600) | ||
GCRY_THREAD_OPTION_PTHREAD_IMPL; | ||
|
||
void init_gnutls_locks() | ||
{ | ||
gcry_control(GCRYCTL_SET_THREAD_CBS); | ||
} | ||
#endif // GCRYPT_VERSION_NUMBER < 0x010600 | ||
#endif // USE_GNUTLS | ||
|
||
#ifdef HAVE_GSTREAMER | ||
#include <gst/gst.h> | ||
#endif // HAVE_GSTREAMER | ||
|
||
static void glibmm_log_filter(const gchar *ld, GLogLevelFlags ll, const gchar *msg, gpointer ud) | ||
{ | ||
if (strcmp(msg, "Dropped dispatcher message as the dispatcher no longer exists") != 0) | ||
g_log_default_handler(ld, ll, msg, ud); | ||
} | ||
|
||
extern const unsigned char ahoviewer_ui[]; | ||
extern const unsigned long ahoviewer_ui_size; | ||
|
||
Application::Application() | ||
: Gio::Application("com.github.ahodesuka.ahoviewer", Gio::APPLICATION_HANDLES_OPEN) | ||
{ | ||
// Disgusting win32 api to start dbus-daemon and make it close when | ||
// the ahoviewer process ends | ||
#ifdef _WIN32 | ||
HANDLE job = CreateJobObject(NULL, NULL); | ||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; | ||
PROCESS_INFORMATION pi = { 0 }; | ||
STARTUPINFO si = { 0 }; | ||
char cmd[] = "dbus-daemon.exe --session"; | ||
|
||
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; | ||
SetInformationJobObject(job, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)); | ||
si.cb = sizeof(si); | ||
|
||
if (CreateProcess(NULL, cmd, NULL, NULL, FALSE, | ||
CREATE_NO_WINDOW | CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB, | ||
NULL, NULL, &si, &pi)) | ||
{ | ||
AssignProcessToJobObject(job, pi.hProcess); | ||
ResumeThread(pi.hThread); | ||
} | ||
#endif // _WIN32 | ||
Glib::set_application_name(PACKAGE_NAME); | ||
} | ||
|
||
Application& Application::get_instance() | ||
{ | ||
static Application i; | ||
return i; | ||
} | ||
|
||
MainWindow* Application::create_window() | ||
{ | ||
Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create(); | ||
|
||
try | ||
{ | ||
builder->add_from_string(reinterpret_cast<const char*>(ahoviewer_ui), | ||
ahoviewer_ui_size); | ||
} | ||
catch (const Glib::Error &ex) | ||
{ | ||
std::cerr << "Gtk::Builder::add_from_string: " << ex.what() << std::endl; | ||
return nullptr; | ||
} | ||
|
||
MainWindow *w = nullptr; | ||
builder->get_widget_derived("MainWindow", w); | ||
|
||
if (!w) | ||
throw std::runtime_error("Failed to create window"); | ||
|
||
add_window(w); | ||
|
||
return w; | ||
} | ||
|
||
int Application::run(int argc, char **argv) | ||
{ | ||
register_application(); | ||
|
||
if (!is_remote()) | ||
{ | ||
gtk_init(&argc, &argv); | ||
#ifdef HAVE_GSTREAMER | ||
gst_init(&argc, &argv); | ||
#endif // HAVE_GSTREAMER | ||
} | ||
|
||
return Gio::Application::run(argc, argv); | ||
} | ||
|
||
// Finds the first window with no local image list or creates a | ||
// new window and then opens the file | ||
void Application::on_open(const std::vector<Glib::RefPtr<Gio::File>> &f, | ||
const Glib::ustring&) | ||
{ | ||
auto it = std::find_if(m_Windows.cbegin(), m_Windows.cend(), | ||
[](MainWindow *w){ return w->m_LocalImageList->empty(); }); | ||
|
||
if (m_Windows.size() == 0 || it == m_Windows.cend()) | ||
{ | ||
auto w = create_window(); | ||
w->open_file(f.front()->get_path()); | ||
} | ||
else | ||
{ | ||
(*it)->open_file(f.front()->get_path()); | ||
} | ||
} | ||
|
||
void Application::on_startup() | ||
{ | ||
LIBXML_TEST_VERSION | ||
|
||
curl_global_init(CURL_GLOBAL_DEFAULT); | ||
|
||
curl_version_info_data *ver_info = curl_version_info(CURLVERSION_NOW); | ||
std::string ssl_lib = ver_info->ssl_version; | ||
|
||
#if defined(USE_OPENSSL) && (OPENSSL_VERSION_NUMBER < 0x10100000L) | ||
if (ssl_lib.find("OpenSSL") != std::string::npos) | ||
init_openssl_locks(); | ||
#endif // defined(USE_OPENSSL) && (OPENSSL_VERSION_NUMBER < 0x10100000L) | ||
|
||
#if defined(USE_GNUTLS) && GCRYPT_VERSION_NUMBER < 0x010600 | ||
if (ssl_lib.find("GnuTLS") != std::string::npos) | ||
init_gnutls_locks(); | ||
#endif // defined(USE_GNUTLS) && GCRYPT_VERSION_NUMBER < 0x010600 | ||
|
||
Gtk::Main::init_gtkmm_internals(); | ||
|
||
// Get rid of the stupid dispatcher warnings from glibmm | ||
// That happen when cancelling downloads | ||
g_log_set_handler("glibmm", G_LOG_LEVEL_WARNING, glibmm_log_filter, NULL); | ||
|
||
Gio::Application::on_startup(); | ||
} | ||
|
||
void Application::on_activate() | ||
{ | ||
auto w = create_window(); | ||
|
||
if (m_Windows.size() == 1) | ||
w->restore_last_file(); | ||
|
||
Gio::Application::on_activate(); | ||
} | ||
|
||
void Application::add_window(MainWindow* w) | ||
{ | ||
if (m_Windows.size() == 0) | ||
w->m_OriginalWindow = true; | ||
|
||
m_Windows.push_back(w); | ||
w->signal_hide().connect( | ||
sigc::bind(sigc::mem_fun(*this, &Application::remove_window), w)); | ||
|
||
hold(); | ||
} | ||
|
||
void Application::remove_window(MainWindow* w) | ||
{ | ||
m_Windows.erase( | ||
std::remove(m_Windows.begin(), m_Windows.end(), w), m_Windows.end()); | ||
delete w; | ||
|
||
if (m_Windows.size() == 1) | ||
m_Windows.front()->m_OriginalWindow = true; | ||
|
||
release(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#ifndef _APPLICATION_H_ | ||
#define _APPLICATION_H_ | ||
|
||
#include <giomm/application.h> | ||
|
||
namespace AhoViewer | ||
{ | ||
class MainWindow; | ||
class Application : public Gio::Application | ||
{ | ||
public: | ||
static Application& get_instance(); | ||
|
||
MainWindow* create_window(); | ||
|
||
int run(int argc, char **argv); | ||
protected: | ||
Application(); | ||
|
||
virtual void on_open(const std::vector<Glib::RefPtr<Gio::File>> &f, | ||
const Glib::ustring&) override; | ||
virtual void on_startup() override; | ||
virtual void on_activate() override; | ||
private: | ||
void add_window(MainWindow* w); | ||
void remove_window(MainWindow* w); | ||
|
||
std::vector<MainWindow*> m_Windows; | ||
}; | ||
} | ||
|
||
#endif /* _APPLICATION_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.