/*
* Application
*
* Copyright (C) 2017 Patrick McDermott
*
* This file is part of Marquee.
*
* Marquee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Marquee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Marquee. If not, see .
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include "application.h"
#include
#include
#include
#include "config/config.h"
#include "config/profiles.h"
#include "download.h"
#include "schemes/about.h"
#include "schemes/view-source.h"
#include "window.h"
struct MqApplication {
GList *windows;
GHashTable *tabs;
gint64 last_tab_id;
MqProfiles *profiles;
MqConfig *config;
gboolean marquee_mode;
gchar *resources_dir;
};
static void
setup_web_context(MqApplication *application)
{
WebKitWebContext *web_context;
web_context = webkit_web_context_get_default();
webkit_web_context_set_favicon_database_directory(web_context, NULL);
webkit_web_context_set_process_model(web_context,
WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);
webkit_web_context_register_uri_scheme(web_context, "mq-about",
(WebKitURISchemeRequestCallback) mq_about_request, application,
NULL);
webkit_security_manager_register_uri_scheme_as_local(
webkit_web_context_get_security_manager(web_context),
"mq-about");
webkit_web_context_register_uri_scheme(web_context, "view-source",
(WebKitURISchemeRequestCallback) mq_view_source_request,
application, NULL);
webkit_security_manager_register_uri_scheme_as_local(
webkit_web_context_get_security_manager(web_context),
"view-source");
}
static void
download_started_cb(WebKitWebContext G_GNUC_UNUSED *context,
WebKitDownload *download, MqApplication *application)
{
mq_download_new(application->config, download);
}
MqApplication *
mq_application_new(const gchar *profile)
{
MqApplication *application;
application = malloc(sizeof(*application));
application->profiles = mq_profiles_new();
mq_profiles_set_current(application->profiles, profile);
application->config = mq_config_new(profile);
mq_config_load(application->config);
application->windows = NULL;
application->tabs = g_hash_table_new_full(g_int64_hash, g_int64_equal,
g_free, NULL);
application->last_tab_id = 0;
application->marquee_mode = FALSE;
#if defined(RUN_IN_PLACE) && RUN_IN_PLACE
application->resources_dir = g_build_filename(ABS_TOP_BUILDDIR,
"data", "resources", NULL);
#else
application->resources_dir = g_build_filename(PKGDATADIR, "resources",
NULL);
#endif
setup_web_context(application);
g_signal_connect(webkit_web_context_get_default(), "download-started",
G_CALLBACK(download_started_cb), application);
return application;
}
int
mq_application_main(MqApplication G_GNUC_UNUSED *application)
{
gtk_main();
return EXIT_SUCCESS;
}
static void
quit_confirm_warn_check_button_toggled_cb(GtkToggleButton *toggle_button,
MqApplication *application)
{
mq_config_set_boolean(application->config, "tabs.warn-on-close",
gtk_toggle_button_get_active(toggle_button));
mq_config_save(application->config);
}
static void
quit_confirm_response_cb(GtkWidget *dialog, gint response_id)
{
gtk_widget_destroy(dialog);
if (response_id == GTK_RESPONSE_OK) {
gtk_main_quit();
}
}
void
mq_application_quit(MqApplication *application, GtkWindow *parent)
{
guint num_windows;
guint num_tabs;
GList *item;
gchar *message;
GtkWidget *message_label;
GtkWidget *check_button;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *dialog;
num_windows = 0;
num_tabs = 0;
for (item = application->windows; item; item = item->next) {
++num_windows;
num_tabs += mq_window_get_num_tabs(item->data);
}
if (num_tabs == 1) { /* Also implies num_windows == 1 */
gtk_main_quit();
return; /* Making sure... */
}
if (!mq_config_get_boolean(application->config, "tabs.warn-on-close")) {
gtk_main_quit();
return; /* Making sure... */
}
/* Message */
if (num_windows == 1) {
message = g_strdup_printf("You are about to close %d tabs "
"in %d window. Are you sure you want to continue?",
num_tabs, num_windows);
} else {
message = g_strdup_printf("You are about to close %d tabs "
"in %d windows. Are you sure you want to continue?",
num_tabs, num_windows);
}
message_label = gtk_label_new(message);
g_free(message);
/* Check button */
check_button = gtk_check_button_new_with_mnemonic(
"_Warn When Closing Multiple Tabs or Windows");
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),
mq_config_get_boolean(application->config,
"tabs.warn-on-close"));
/* Connect signal after setting initial toggle status, to avoid a
* spurious signal. */
g_signal_connect(check_button, "toggled",
G_CALLBACK(quit_confirm_warn_check_button_toggled_cb),
application);
/* Right vertical box (message and check button) */
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start(GTK_BOX(vbox), message_label, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), check_button, FALSE, FALSE, 0);
/* Horizontal box (icon and right vertical box) */
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start(GTK_BOX(hbox), gtk_image_new_from_icon_name(
"dialog-question", GTK_ICON_SIZE_DIALOG), FALSE, FALSE,
0);
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
/* Dialog */
dialog = gtk_dialog_new_with_buttons("Confirm Close", parent,
GTK_DIALOG_DESTROY_WITH_PARENT,
"_Cancel", GTK_RESPONSE_CANCEL,
"Cl_ose Tabs", GTK_RESPONSE_OK,
NULL);
gtk_container_add(
GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
hbox);
g_signal_connect(dialog, "response",
G_CALLBACK(quit_confirm_response_cb), NULL);
gtk_widget_grab_focus(gtk_dialog_get_widget_for_response(
GTK_DIALOG(dialog), GTK_RESPONSE_OK));
gtk_widget_show_all(dialog);
return;
}
MqProfiles *
mq_application_get_profiles(MqApplication *application)
{
return application->profiles;
}
MqConfig *
mq_application_get_config(MqApplication *application)
{
return application->config;
}
MqWindow *
mq_application_add_window(MqApplication *application, const gchar **uris)
{
MqWindow *window;
window = mq_window_new(application, uris);
application->windows = g_list_prepend(application->windows, window);
return window;
}
void
mq_application_delete_window(MqApplication *application, MqWindow *window)
{
application->windows = g_list_remove(application->windows, window);
if (!application->windows) {
gtk_main_quit();
}
}
gint64
mq_application_register_tab(MqApplication *application, MqTabPage *tab_page)
{
gint64 *tab_id;
tab_id = g_new(gint64, 1);
*tab_id = ++application->last_tab_id;
g_hash_table_insert(application->tabs, tab_id, tab_page);
return application->last_tab_id;
}
gboolean
mq_application_unregister_tab(MqApplication *application, gint64 tab_id)
{
return g_hash_table_remove(application->tabs, &tab_id);
}
MqTabPage *
mq_application_get_tab(MqApplication *application, gint64 tab_id)
{
return g_hash_table_lookup(application->tabs, &tab_id);
}
const gchar *
mq_application_get_resources_dir(MqApplication *application)
{
return application->resources_dir;
}
static gboolean
scroll_tab_labels(MqApplication *application)
{
GList *item;
if (application->marquee_mode) {
for (item = application->windows; item; item = item->next) {
mq_window_scroll_tab_labels(item->data);
}
return G_SOURCE_CONTINUE;
} else {
return G_SOURCE_REMOVE;
}
}
void
mq_application_marquee_mode_activate(MqApplication *application)
{
GList *item;
for (item = application->windows; item; item = item->next) {
mq_window_begin_scrolling_tab_labels(item->data);
}
application->marquee_mode = TRUE;
g_timeout_add(125, (GSourceFunc) scroll_tab_labels, application);
}
void
mq_application_marquee_mode_deactivate(MqApplication *application)
{
GList *item;
for (item = application->windows; item; item = item->next) {
mq_window_end_scrolling_tab_labels(item->data);
}
application->marquee_mode = FALSE;
}
gboolean
mq_application_marquee_mode_on(MqApplication *application)
{
return application->marquee_mode;
}