messenger-gtk

Gtk+3 graphical user interfaces for GNUnet Messenger
Log | Files | Refs | Submodules | README | LICENSE

commit bf66a4d1443da01955d03629b6fd71ab6aa91cdf
parent 74268f92c68c98757c16a7bce3b253297567744c
Author: Jacki <jacki@thejackimonster.de>
Date:   Thu, 18 Jan 2024 23:01:22 +0100

Use libportal for requesting background permission

Signed-off-by: Jacki <jacki@thejackimonster.de>

Diffstat:
Mmeson.build | 2++
Mresources/ui/settings.ui | 6++----
Msrc/application.c | 238++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/application.h | 17+++++++++++++++++
Msrc/meson.build | 3++-
Asrc/request.c | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/request.h | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ui/accounts.c | 84++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/ui/accounts.h | 6+++---
Msrc/ui/messenger.c | 327++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/ui/picker.c | 11+++++------
Msrc/ui/settings.c | 331++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/ui/settings.h | 3+++
13 files changed, 791 insertions(+), 395 deletions(-)

diff --git a/meson.build b/meson.build @@ -40,6 +40,8 @@ messenger_gtk_deps = [ dependency('gtk+-3.0'), dependency('libhandy-1'), dependency('gstreamer-1.0'), + dependency('libportal'), + dependency('libportal-gtk3'), dependency('libnotify'), dependency('libqrencode'), declare_dependency(link_args: '-lunistring'), diff --git a/resources/ui/settings.ui b/resources/ui/settings.ui @@ -105,9 +105,8 @@ Author: Tobias Frisch </packing> </child> <child> - <object class="GtkSwitch"> + <object class="GtkSwitch" id="start_on_login_switch"> <property name="visible">True</property> - <property name="sensitive">False</property> <property name="can-focus">True</property> </object> <packing> @@ -147,9 +146,8 @@ Author: Tobias Frisch </packing> </child> <child> - <object class="GtkSwitch"> + <object class="GtkSwitch" id="run_in_background_switch"> <property name="visible">True</property> - <property name="sensitive">False</property> <property name="can-focus">True</property> </object> <packing> diff --git a/src/application.c b/src/application.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2022 GNUnet e.V. + Copyright (C) 2021--2024 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -23,11 +23,13 @@ */ #include "application.h" +#include "request.h" #include "resources.h" #include <gstreamer-1.0/gst/gst.h> #include <gtk-3.0/gtk/gtk.h> #include <libhandy-1/handy.h> +#include <libportal-gtk3/portal-gtk3.h> #include <libnotify/notify.h> static void @@ -37,14 +39,14 @@ _load_ui_stylesheets(MESSENGER_Application *app) GtkCssProvider* provider = gtk_css_provider_new(); gtk_css_provider_load_from_resource( - provider, - application_get_resource_path(app, "css/style.css") + provider, + application_get_resource_path(app, "css/style.css") ); gtk_style_context_add_provider_for_screen( - screen, - GTK_STYLE_PROVIDER(provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + screen, + GTK_STYLE_PROVIDER(provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION ); } @@ -67,15 +69,18 @@ _application_init(MESSENGER_Application *app) { ui_messenger_init(app, &(app->ui.messenger)); + if (app->portal) + app->parent = xdp_parent_new_gtk(GTK_WINDOW(app->ui.messenger.main_window)); + if (app->chat.identity) - gtk_widget_show(GTK_WIDGET(app->ui.messenger.main_window)); + application_show_window(app); else app->init = g_idle_add(G_SOURCE_FUNC(_application_accounts), app); } static void _application_activate(GApplication* application, - gpointer user_data) + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -88,10 +93,10 @@ _application_activate(GApplication* application, static void _application_open(GApplication* application, - GFile **files, - gint n_files, - UNUSED gchar* hint, - gpointer user_data) + GFile **files, + gint n_files, + UNUSED gchar* hint, + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -132,8 +137,8 @@ _application_open(GApplication* application, void application_init(MESSENGER_Application *app, - int argc, - char **argv) + int argc, + char **argv) { memset(app, 0, sizeof(*app)); @@ -145,15 +150,25 @@ application_init(MESSENGER_Application *app, hdy_init(); app->application = gtk_application_new( - MESSENGER_APPLICATION_ID, - G_APPLICATION_HANDLES_OPEN | - G_APPLICATION_NON_UNIQUE + MESSENGER_APPLICATION_ID, + G_APPLICATION_HANDLES_OPEN | + G_APPLICATION_NON_UNIQUE ); resources_register(); + GError *error = NULL; + app->portal = xdp_portal_initable_new(&error); + + if (!app->portal) + { + g_printerr("ERROR: %s\n", error->message); + g_error_free(error); + } + notify_init(MESSENGER_APPLICATION_NAME); app->notifications = NULL; + app->requests = NULL; _load_ui_stylesheets(app); @@ -168,48 +183,48 @@ application_init(MESSENGER_Application *app, app->quarks.ui = g_quark_from_string("messenger_ui"); g_application_add_main_option( - G_APPLICATION(app->application), - "mobile", - 'm', - G_OPTION_FLAG_NONE, - G_OPTION_ARG_NONE, - "Optimize UI spacing for mobile devices", - NULL + G_APPLICATION(app->application), + "mobile", + 'm', + G_OPTION_FLAG_NONE, + G_OPTION_ARG_NONE, + "Optimize UI spacing for mobile devices", + NULL ); g_application_add_main_option( - G_APPLICATION(app->application), - "ego", - 'e', - G_OPTION_FLAG_NONE, - G_OPTION_ARG_STRING, - "Identity to select for messaging", - "IDENTITY" + G_APPLICATION(app->application), + "ego", + 'e', + G_OPTION_FLAG_NONE, + G_OPTION_ARG_STRING, + "Identity to select for messaging", + "IDENTITY" ); g_signal_connect( - app->application, - "activate", - G_CALLBACK(_application_activate), - app + app->application, + "activate", + G_CALLBACK(_application_activate), + app ); g_signal_connect( - app->application, - "open", - G_CALLBACK(_application_open), - app + app->application, + "open", + G_CALLBACK(_application_open), + app ); } const gchar* application_get_resource_path(MESSENGER_Application *app, - const char *path) + const char *path) { static gchar resource_path [PATH_MAX]; const gchar *base_path = g_application_get_resource_base_path( - G_APPLICATION(app->application) + G_APPLICATION(app->application) ); snprintf(resource_path, PATH_MAX, "%s/%s", base_path, path); @@ -222,30 +237,30 @@ _application_chat_thread(void *args) MESSENGER_Application *app = (MESSENGER_Application*) args; struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_option_flag ( - 'm', - "mobile", - "Optimize UI spacing for mobile devices", - &(app->settings.mobile_design) - ), - GNUNET_GETOPT_option_string ( - 'e', - "ego", - "IDENTITY", - "Identity to select for messaging", - &(app->chat.identity) - ), - GNUNET_GETOPT_OPTION_END + GNUNET_GETOPT_option_flag ( + 'm', + "mobile", + "Optimize UI spacing for mobile devices", + &(app->settings.mobile_design) + ), + GNUNET_GETOPT_option_string ( +'e', + "ego", +"IDENTITY", +"Identity to select for messaging", + &(app->chat.identity) + ), + GNUNET_GETOPT_OPTION_END }; app->chat.status = (GNUNET_PROGRAM_run( - app->argc, - app->argv, - MESSENGER_APPLICATION_BINARY, - gettext_noop(MESSENGER_APPLICATION_DESCRIPTION), - options, - &chat_messenger_run, - app + app->argc, + app->argv, + MESSENGER_APPLICATION_BINARY, + gettext_noop(MESSENGER_APPLICATION_DESCRIPTION), + options, + &chat_messenger_run, + app ) == GNUNET_OK? EXIT_SUCCESS : EXIT_FAILURE); return NULL; @@ -255,12 +270,17 @@ void application_run(MESSENGER_Application *app) { // Start thread to run GNUnet scheduler - pthread_create(&(app->chat.tid), NULL, _application_chat_thread, app); + pthread_create( + &(app->chat.tid), + NULL, + _application_chat_thread, + app + ); app->ui.status = g_application_run( - G_APPLICATION(app->application), - app->argc, - app->argv + G_APPLICATION(app->application), + app->argc, + app->argv ); if (app->ui.status != 0) @@ -274,16 +294,36 @@ application_run(MESSENGER_Application *app) pthread_mutex_destroy(&(app->chat.mutex)); + GList *list; + + // Get rid of open requests + list = app->requests; + + while (list) + { + if (list->data) + { + request_cancel((MESSENGER_Request*) list->data); + request_delete((MESSENGER_Request*) list->data); + } + + list = list->next; + } + // Get rid of open notifications - GList *list = app->notifications; + list = app->notifications; - while (list) { + while (list) + { if (list->data) notify_notification_close(NOTIFY_NOTIFICATION(list->data), NULL); list = list->next; } + if (app->requests) + g_list_free(app->requests); + if (app->notifications) g_list_free(app->notifications); @@ -294,6 +334,51 @@ application_run(MESSENGER_Application *app) g_object_unref(app->application); } +static void +_request_background_callback(GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + XdpPortal *portal = XDP_PORTAL(source_object); + MESSENGER_Request *request = (MESSENGER_Request*) user_data; + + request_cleanup(request); + + gboolean *setting = (gboolean*) (request->user_data); + + GError *error = NULL; + gboolean success = xdp_portal_request_background_finish( + portal, result, &error + ); + + if (!success) { + g_printerr("ERROR: %s\n", error->message); + g_error_free(error); + } + + *setting = success; +} + +void +application_show_window(MESSENGER_Application *app) +{ + gtk_widget_show(GTK_WIDGET(app->ui.messenger.main_window)); + + request_new_background( + app, + XDP_BACKGROUND_FLAG_AUTOSTART, + _request_background_callback, + &(app->settings.autostart) + ); + + request_new_background( + app, + XDP_BACKGROUND_FLAG_ACTIVATABLE, + _request_background_callback, + &(app->settings.background_task) + ); +} + typedef struct MESSENGER_ApplicationEventCall { MESSENGER_Application *app; @@ -318,12 +403,12 @@ _application_event_call(gpointer user_data) void application_call_event(MESSENGER_Application *app, - MESSENGER_ApplicationEvent event) + MESSENGER_ApplicationEvent event) { MESSENGER_ApplicationEventCall *call; call = (MESSENGER_ApplicationEventCall*) GNUNET_malloc( - sizeof(MESSENGER_ApplicationEventCall) + sizeof(MESSENGER_ApplicationEventCall) ); call->app = app; @@ -359,8 +444,8 @@ _application_message_event_call(gpointer user_data) void application_call_message_event(MESSENGER_Application *app, - MESSENGER_ApplicationMessageEvent event, - struct GNUNET_CHAT_Context *context, + MESSENGER_ApplicationMessageEvent event, + struct GNUNET_CHAT_Context *context, const struct GNUNET_CHAT_Message *message) { MESSENGER_ApplicationMessageEventCall *call; @@ -369,7 +454,7 @@ application_call_message_event(MESSENGER_Application *app, return; call = (MESSENGER_ApplicationMessageEventCall*) GNUNET_malloc( - sizeof(MESSENGER_ApplicationMessageEventCall) + sizeof(MESSENGER_ApplicationMessageEventCall) ); call->app = app; @@ -383,11 +468,16 @@ application_call_message_event(MESSENGER_Application *app, void application_exit(MESSENGER_Application *app, - MESSENGER_ApplicationSignal signal) + MESSENGER_ApplicationSignal signal) { // Forward a signal to the other thread causing it to shutdown the // GNUnet handles of the application. write(app->chat.pipe[1], &signal, sizeof(signal)); + + if (app->portal) + g_free(app->portal); + + app->portal = NULL; } int diff --git a/src/application.h b/src/application.h @@ -25,6 +25,8 @@ #ifndef APPLICATION_H_ #define APPLICATION_H_ +#include <libportal/portal.h> + #include <pthread.h> #include <gnunet/gnunet_chat_lib.h> @@ -69,8 +71,12 @@ typedef struct MESSENGER_Application GtkApplication *application; GList *notifications; + GList *requests; guint init; + XdpPortal *portal; + XdpParent *parent; + struct { GQuark widget; GQuark data; @@ -115,6 +121,9 @@ typedef struct MESSENGER_Application gboolean mobile_design; gboolean hide_delete_dialog; + gboolean autostart; + gboolean background_task; + gboolean disable_notifications; gboolean send_read_receipts; @@ -168,6 +177,14 @@ application_get_resource_path(MESSENGER_Application *app, void application_run(MESSENGER_Application *app); +/** + * Shows the messenger application main window. + * + * @param app Messenger application + */ +void +application_show_window(MESSENGER_Application *app); + typedef void (*MESSENGER_ApplicationEvent) ( MESSENGER_Application *app ); diff --git a/src/meson.build b/src/meson.build @@ -1,6 +1,6 @@ # # This file is part of GNUnet. -# Copyright (C) 2023 GNUnet e.V. +# Copyright (C) 2023--2024 GNUnet e.V. # # GNUnet is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as published @@ -26,6 +26,7 @@ messenger_gtk_sources = files([ 'contact.c', 'contact.h', 'event.c', 'event.h', 'file.c', 'file.h', + 'request.c', 'request.h', 'resources.c', 'resources.h', 'ui.c', 'ui.h', 'util.h', diff --git a/src/request.c b/src/request.c @@ -0,0 +1,99 @@ +/* + This file is part of GNUnet. + Copyright (C) 2024 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file request.c + */ + +#include "request.h" + +MESSENGER_Request* +request_new(MESSENGER_Application *application, + GCancellable *cancellable, + gpointer user_data) +{ + MESSENGER_Request* request = g_malloc(sizeof(MESSENGER_Request)); + + request->application = application; + request->cancellable = cancellable; + request->user_data = user_data; + + application->requests = g_list_append( + application->requests, + request + ); + + return request; +} + +MESSENGER_Request* +request_new_background(MESSENGER_Application *application, + XdpBackgroundFlags flags, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GCancellable* cancellable = g_cancellable_new(); + + MESSENGER_Request* request = request_new( + application, + cancellable, + user_data + ); + + xdp_portal_request_background( + application->portal, + application->parent, + NULL, + NULL, + flags, + cancellable, + callback, + request + ); + + return request; +} + +void +request_cancel(MESSENGER_Request *request) +{ + if (!request->cancellable) + return; + + if (!g_cancellable_is_cancelled(request->cancellable)) + g_cancellable_cancel(request->cancellable); +} + +void +request_cleanup(MESSENGER_Request *request) +{ + if (!request->cancellable) + return; + + g_object_unref(request->cancellable); + request->cancellable = NULL; +} + +void +request_delete(MESSENGER_Request *request) +{ + request_cleanup(request); + g_free(request); +} diff --git a/src/request.h b/src/request.h @@ -0,0 +1,59 @@ +/* + This file is part of GNUnet. + Copyright (C) 2024 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file request.h + */ + +#ifndef REQUEST_H_ +#define REQUEST_H_ + +#include <gio/gio.h> +#include <libportal/portal.h> + +#include "application.h" + +typedef struct MESSENGER_Request { + MESSENGER_Application *application; + GCancellable *cancellable; + gpointer user_data; +} MESSENGER_Request; + +MESSENGER_Request* +request_new(MESSENGER_Application *application, + GCancellable *cancellable, + gpointer user_data); + +MESSENGER_Request* +request_new_background(MESSENGER_Application *application, + XdpBackgroundFlags flags, + GAsyncReadyCallback callback, + gpointer user_data); + +void +request_cancel(MESSENGER_Request *request); + +void +request_cleanup(MESSENGER_Request *request); + +void +request_delete(MESSENGER_Request *request); + +#endif /* REQUEST_H_ */ diff --git a/src/ui/accounts.c b/src/ui/accounts.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2022 GNUnet e.V. + Copyright (C) 2022--2024 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -29,7 +29,7 @@ static void handle_close_button_click(UNUSED GtkButton *button, - gpointer user_data) + gpointer user_data) { GtkDialog *dialog = GTK_DIALOG(user_data); gtk_window_close(GTK_WINDOW(dialog)); @@ -54,14 +54,14 @@ _show_messenger_main_window(gpointer user_data) // Refresh the account list ui_messenger_refresh(app, &(app->ui.messenger)); - gtk_widget_show(GTK_WIDGET(app->ui.messenger.main_window)); + application_show_window(app); return FALSE; } static void handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox, - GtkListBoxRow* row, - gpointer user_data) + GtkListBoxRow* row, + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -69,14 +69,14 @@ handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox, if (!gtk_list_box_row_get_selectable(row)) { app->ui.accounts.show_queued = g_idle_add( - G_SOURCE_FUNC(_open_new_account_dialog), app + G_SOURCE_FUNC(_open_new_account_dialog), app ); goto close_dialog; } struct GNUNET_CHAT_Account *account = (struct GNUNET_CHAT_Account*) ( - g_object_get_qdata(G_OBJECT(row), app->quarks.data) + g_object_get_qdata(G_OBJECT(row), app->quarks.data) ); if (!account) @@ -85,7 +85,7 @@ handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox, // Handle the GUI swap asyncronously if (!gtk_widget_is_visible(GTK_WIDGET(app->ui.messenger.main_window))) app->ui.accounts.show_queued = g_idle_add( - G_SOURCE_FUNC(_show_messenger_main_window), app + G_SOURCE_FUNC(_show_messenger_main_window), app ); GNUNET_CHAT_connect(app->chat.messenger.handle, account); @@ -96,7 +96,7 @@ close_dialog: static void handle_dialog_destroy(UNUSED GtkWidget *window, - gpointer user_data) + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -109,8 +109,8 @@ handle_dialog_destroy(UNUSED GtkWidget *window, static int _iterate_accounts(void *cls, - UNUSED const struct GNUNET_CHAT_Handle *handle, - struct GNUNET_CHAT_Account *account) + UNUSED const struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Account *account) { MESSENGER_Application *app = (MESSENGER_Application*) cls; @@ -121,16 +121,16 @@ _iterate_accounts(void *cls, gtk_list_box_prepend(app->ui.accounts.accounts_listbox, entry->entry_box); GtkListBoxRow *row = GTK_LIST_BOX_ROW( - gtk_widget_get_parent(entry->entry_box) + gtk_widget_get_parent(entry->entry_box) ); g_object_set_qdata(G_OBJECT(row), app->quarks.data, account); g_object_set_qdata_full( - G_OBJECT(row), - app->quarks.ui, - entry, - (GDestroyNotify) ui_account_entry_delete + G_OBJECT(row), + app->quarks.ui, + entry, + (GDestroyNotify) ui_account_entry_delete ); return GNUNET_YES; @@ -138,62 +138,62 @@ _iterate_accounts(void *cls, void ui_accounts_dialog_init(MESSENGER_Application *app, - UI_ACCOUNTS_Handle *handle) + UI_ACCOUNTS_Handle *handle) { handle->show_queued = 0; handle->builder = gtk_builder_new_from_resource( - application_get_resource_path(app, "ui/accounts.ui") + application_get_resource_path(app, "ui/accounts.ui") ); handle->dialog = GTK_DIALOG( - gtk_builder_get_object(handle->builder, "accounts_dialog") + gtk_builder_get_object(handle->builder, "accounts_dialog") ); gtk_window_set_transient_for( - GTK_WINDOW(handle->dialog), - GTK_WINDOW(app->ui.messenger.main_window) + GTK_WINDOW(handle->dialog), + GTK_WINDOW(app->ui.messenger.main_window) ); handle->accounts_listbox = GTK_LIST_BOX( - gtk_builder_get_object(handle->builder, "accounts_listbox") + gtk_builder_get_object(handle->builder, "accounts_listbox") ); g_signal_connect( - handle->accounts_listbox, - "row-activated", - G_CALLBACK(handle_accounts_listbox_row_activated), - app + handle->accounts_listbox, + "row-activated", + G_CALLBACK(handle_accounts_listbox_row_activated), + app ); handle->close_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "close_button") + gtk_builder_get_object(handle->builder, "close_button") ); g_signal_connect( - handle->close_button, - "clicked", - G_CALLBACK(handle_close_button_click), - handle->dialog + handle->close_button, + "clicked", + G_CALLBACK(handle_close_button_click), + handle->dialog ); g_signal_connect( - handle->dialog, - "destroy", - G_CALLBACK(handle_dialog_destroy), - app + handle->dialog, + "destroy", + G_CALLBACK(handle_dialog_destroy), + app ); } void ui_accounts_dialog_refresh(MESSENGER_Application *app, - UI_ACCOUNTS_Handle *handle) + UI_ACCOUNTS_Handle *handle) { if (!(handle->accounts_listbox)) return; GList *list = gtk_container_get_children( - GTK_CONTAINER(handle->accounts_listbox) + GTK_CONTAINER(handle->accounts_listbox) ); while (list) @@ -204,8 +204,8 @@ ui_accounts_dialog_refresh(MESSENGER_Application *app, goto skip_row; gtk_container_remove( - GTK_CONTAINER(handle->accounts_listbox), - GTK_WIDGET(row) + GTK_CONTAINER(handle->accounts_listbox), + GTK_WIDGET(row) ); skip_row: @@ -213,9 +213,9 @@ ui_accounts_dialog_refresh(MESSENGER_Application *app, } GNUNET_CHAT_iterate_accounts( - app->chat.messenger.handle, - _iterate_accounts, - app + app->chat.messenger.handle, + _iterate_accounts, + app ); } diff --git a/src/ui/accounts.h b/src/ui/accounts.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2022 GNUnet e.V. + Copyright (C) 2022--2024 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -48,7 +48,7 @@ typedef struct UI_ACCOUNTS_Handle */ void ui_accounts_dialog_init(MESSENGER_Application *app, - UI_ACCOUNTS_Handle *handle); + UI_ACCOUNTS_Handle *handle); /** * Refreshes a given accounts dialog handle with the @@ -59,7 +59,7 @@ ui_accounts_dialog_init(MESSENGER_Application *app, */ void ui_accounts_dialog_refresh(MESSENGER_Application *app, - UI_ACCOUNTS_Handle *handle); + UI_ACCOUNTS_Handle *handle); /** * Cleans up the allocated resources and resets the diff --git a/src/ui/messenger.c b/src/ui/messenger.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2022 GNUnet e.V. + Copyright (C) 2021--2024 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -58,21 +58,21 @@ _flap_user_details_reveal_switch(gpointer user_data) static void handle_user_details_via_button_click(UNUSED GtkButton* button, - gpointer user_data) + gpointer user_data) { UI_MESSENGER_Handle *handle = (UI_MESSENGER_Handle*) user_data; gtk_widget_set_sensitive(GTK_WIDGET(handle->chats_search), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(handle->chats_listbox), FALSE); g_idle_add( - G_SOURCE_FUNC(_flap_user_details_reveal_switch), - handle + G_SOURCE_FUNC(_flap_user_details_reveal_switch), + handle ); } static void handle_lobby_button_click(UNUSED GtkButton* button, - gpointer user_data) + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -85,24 +85,24 @@ handle_lobby_button_click(UNUSED GtkButton* button, static void _switch_details_revealer_visibility(UI_MESSENGER_Handle *handle, - gboolean state) + gboolean state) { GtkRevealer *revealer = handle->account_details_revealer; GtkImage *symbol = handle->account_details_symbol; gtk_revealer_set_reveal_child(revealer, state); gtk_image_set_from_icon_name( - symbol, - state? - "go-up-symbolic" : - "go-down-symbolic", - GTK_ICON_SIZE_BUTTON + symbol, + state? + "go-up-symbolic" : + "go-down-symbolic", + GTK_ICON_SIZE_BUTTON ); } static void handle_account_details_button_click(UNUSED GtkButton* button, - gpointer user_data) + gpointer user_data) { UI_MESSENGER_Handle *handle = (UI_MESSENGER_Handle*) user_data; @@ -115,8 +115,8 @@ handle_account_details_button_click(UNUSED GtkButton* button, static void handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox, - GtkListBoxRow* row, - gpointer user_data) + GtkListBoxRow* row, + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -132,7 +132,7 @@ handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox, } struct GNUNET_CHAT_Account *account = (struct GNUNET_CHAT_Account*) ( - g_object_get_qdata(G_OBJECT(row), app->quarks.data) + g_object_get_qdata(G_OBJECT(row), app->quarks.data) ); if (!account) @@ -146,7 +146,7 @@ handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox, static void handle_new_contact_button_click(UNUSED GtkButton* button, - gpointer user_data) + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -157,7 +157,7 @@ handle_new_contact_button_click(UNUSED GtkButton* button, static void handle_new_group_button_click(UNUSED GtkButton* button, - gpointer user_data) + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -168,7 +168,7 @@ handle_new_group_button_click(UNUSED GtkButton* button, static void handle_new_platform_button_click(UNUSED GtkButton* button, - gpointer user_data) + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -179,7 +179,7 @@ handle_new_platform_button_click(UNUSED GtkButton* button, static void handle_contacts_button_click(UNUSED GtkButton* button, - gpointer user_data) + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -190,7 +190,7 @@ handle_contacts_button_click(UNUSED GtkButton* button, static void handle_settings_button_click(UNUSED GtkButton* button, - gpointer user_data) + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -201,7 +201,7 @@ handle_settings_button_click(UNUSED GtkButton* button, static void handle_about_button_click(UNUSED GtkButton* button, - gpointer user_data) + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -212,8 +212,8 @@ handle_about_button_click(UNUSED GtkButton* button, static void handle_chats_listbox_row_activated(UNUSED GtkListBox* listbox, - GtkListBoxRow* row, - gpointer user_data) + GtkListBoxRow* row, + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -221,7 +221,7 @@ handle_chats_listbox_row_activated(UNUSED GtkListBox* listbox, return; UI_CHAT_ENTRY_Handle *entry = (UI_CHAT_ENTRY_Handle*) ( - g_object_get_qdata(G_OBJECT(row), app->quarks.ui) + g_object_get_qdata(G_OBJECT(row), app->quarks.ui) ); if ((!entry) || (!(entry->chat)) || (!(entry->chat->chat_box))) @@ -241,8 +241,8 @@ handle_chats_listbox_row_activated(UNUSED GtkListBox* listbox, static gint handle_chats_listbox_sort_func(GtkListBoxRow* row0, - GtkListBoxRow* row1, - gpointer user_data) + GtkListBoxRow* row1, + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -252,11 +252,11 @@ handle_chats_listbox_sort_func(GtkListBoxRow* row0, return 0; UI_CHAT_ENTRY_Handle *entry0 = (UI_CHAT_ENTRY_Handle*) ( - g_object_get_qdata(G_OBJECT(row0), app->quarks.ui) + g_object_get_qdata(G_OBJECT(row0), app->quarks.ui) ); UI_CHAT_ENTRY_Handle *entry1 = (UI_CHAT_ENTRY_Handle*) ( - g_object_get_qdata(G_OBJECT(row1), app->quarks.ui) + g_object_get_qdata(G_OBJECT(row1), app->quarks.ui) ); if ((!entry0) || (!entry1)) @@ -275,7 +275,7 @@ handle_chats_listbox_sort_func(GtkListBoxRow* row0, static gboolean handle_chats_listbox_filter_func(GtkListBoxRow *row, - gpointer user_data) + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; @@ -284,14 +284,14 @@ handle_chats_listbox_filter_func(GtkListBoxRow *row, return TRUE; const gchar *filter = gtk_entry_get_text( - GTK_ENTRY(app->ui.messenger.chats_search) + GTK_ENTRY(app->ui.messenger.chats_search) ); if (!filter) return TRUE; UI_CHAT_ENTRY_Handle *entry = (UI_CHAT_ENTRY_Handle*) ( - g_object_get_qdata(G_OBJECT(row), app->quarks.ui) + g_object_get_qdata(G_OBJECT(row), app->quarks.ui) ); if ((!entry) || (!(entry->title_label))) @@ -307,7 +307,7 @@ handle_chats_listbox_filter_func(GtkListBoxRow *row, static void handle_chats_search_changed(UNUSED GtkSearchEntry *search, - gpointer user_data) + gpointer user_data) { GtkListBox *listbox = GTK_LIST_BOX(user_data); @@ -316,10 +316,15 @@ handle_chats_search_changed(UNUSED GtkSearchEntry *search, static void handle_main_window_destroy(UNUSED GtkWidget *window, - gpointer user_data) + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; + if (app->parent) + xdp_parent_free(app->parent); + + app->parent = NULL; + ui_messenger_cleanup(&(app->ui.messenger)); ui_accounts_dialog_cleanup(&(app->ui.accounts)); @@ -328,85 +333,85 @@ handle_main_window_destroy(UNUSED GtkWidget *window, void ui_messenger_init(MESSENGER_Application *app, - UI_MESSENGER_Handle *handle) + UI_MESSENGER_Handle *handle) { memset(handle, 0, sizeof(*handle)); handle->app = app; handle->builder = gtk_builder_new_from_resource( - application_get_resource_path(app, "ui/messenger.ui") + application_get_resource_path(app, "ui/messenger.ui") ); handle->main_window = GTK_APPLICATION_WINDOW( - gtk_builder_get_object(handle->builder, "main_window") + gtk_builder_get_object(handle->builder, "main_window") ); gtk_window_set_startup_id( - GTK_WINDOW(handle->main_window), - MESSENGER_APPLICATION_ID + GTK_WINDOW(handle->main_window), + MESSENGER_APPLICATION_ID ); gtk_window_set_icon_name( - GTK_WINDOW(handle->main_window), - MESSENGER_APPLICATION_ID + GTK_WINDOW(handle->main_window), + MESSENGER_APPLICATION_ID ); gtk_application_add_window( - app->application, - GTK_WINDOW(handle->main_window) + app->application, + GTK_WINDOW(handle->main_window) ); gtk_window_set_default_size( - GTK_WINDOW(handle->main_window), - 1100, 700 + GTK_WINDOW(handle->main_window), + 1100, 700 ); handle->leaflet_chat = HDY_LEAFLET( - gtk_builder_get_object(handle->builder, "leaflet_chat") + gtk_builder_get_object(handle->builder, "leaflet_chat") ); handle->flap_user_details = HDY_FLAP( - gtk_builder_get_object(handle->builder, "flap_user_details") + gtk_builder_get_object(handle->builder, "flap_user_details") ); handle->title_bar = HDY_HEADER_BAR( - gtk_builder_get_object(handle->builder, "title_bar") + gtk_builder_get_object(handle->builder, "title_bar") ); GtkLabel* application_name_label = GTK_LABEL( - gtk_builder_get_object(handle->builder, "application-name-label") + gtk_builder_get_object(handle->builder, "application-name-label") ); GtkLabel* application_version_label = GTK_LABEL( - gtk_builder_get_object(handle->builder, "application-version-label") + gtk_builder_get_object(handle->builder, "application-version-label") ); hdy_header_bar_set_title( - handle->title_bar, - MESSENGER_APPLICATION_TITLE + handle->title_bar, + MESSENGER_APPLICATION_TITLE ); hdy_header_bar_set_subtitle( - handle->title_bar, - MESSENGER_APPLICATION_SUBTITLE + handle->title_bar, + MESSENGER_APPLICATION_SUBTITLE ); gtk_label_set_text( - application_name_label, - MESSENGER_APPLICATION_APPNAME + application_name_label, + MESSENGER_APPLICATION_APPNAME ); gtk_label_set_text( - application_version_label, - MESSENGER_APPLICATION_VERSION + application_version_label, + MESSENGER_APPLICATION_VERSION ); g_object_bind_property( - handle->leaflet_chat, - "folded", - handle->title_bar, - "show-close-button", - G_BINDING_INVERT_BOOLEAN + handle->leaflet_chat, + "folded", + handle->title_bar, + "show-close-button", + G_BINDING_INVERT_BOOLEAN ); if (app->settings.mobile_design) @@ -420,206 +425,206 @@ ui_messenger_init(MESSENGER_Application *app, ); handle->profile_avatar = HDY_AVATAR( - gtk_builder_get_object(handle->builder, "profile_avatar") + gtk_builder_get_object(handle->builder, "profile_avatar") ); handle->profile_label = GTK_LABEL( - gtk_builder_get_object(handle->builder, "profile_label") + gtk_builder_get_object(handle->builder, "profile_label") ); handle->profile_key_label = GTK_LABEL( - gtk_builder_get_object(handle->builder, "profile_key_label") + gtk_builder_get_object(handle->builder, "profile_key_label") ); handle->hide_user_details_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "hide_user_details_button") + gtk_builder_get_object(handle->builder, "hide_user_details_button") ); g_signal_connect( - handle->hide_user_details_button, - "clicked", - G_CALLBACK(handle_user_details_via_button_click), - handle + handle->hide_user_details_button, + "clicked", + G_CALLBACK(handle_user_details_via_button_click), + handle ); handle->lobby_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "lobby_button") + gtk_builder_get_object(handle->builder, "lobby_button") ); g_signal_connect( - handle->lobby_button, - "clicked", - G_CALLBACK(handle_lobby_button_click), - app + handle->lobby_button, + "clicked", + G_CALLBACK(handle_lobby_button_click), + app ); handle->account_details_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "account_details_button") + gtk_builder_get_object(handle->builder, "account_details_button") ); handle->account_details_symbol = GTK_IMAGE( - gtk_builder_get_object(handle->builder, "account_details_symbol") + gtk_builder_get_object(handle->builder, "account_details_symbol") ); handle->account_details_revealer = GTK_REVEALER( - gtk_builder_get_object(handle->builder, "account_details_revealer") + gtk_builder_get_object(handle->builder, "account_details_revealer") ); g_signal_connect( - handle->account_details_button, - "clicked", - G_CALLBACK(handle_account_details_button_click), - handle + handle->account_details_button, + "clicked", + G_CALLBACK(handle_account_details_button_click), + handle ); handle->accounts_listbox = GTK_LIST_BOX( - gtk_builder_get_object(handle->builder, "accounts_listbox") + gtk_builder_get_object(handle->builder, "accounts_listbox") ); handle->add_account_listbox_row = GTK_LIST_BOX_ROW( - gtk_builder_get_object(handle->builder, "add_account_listbox_row") + gtk_builder_get_object(handle->builder, "add_account_listbox_row") ); g_signal_connect( - handle->accounts_listbox, - "row-activated", - G_CALLBACK(handle_accounts_listbox_row_activated), - app + handle->accounts_listbox, + "row-activated", + G_CALLBACK(handle_accounts_listbox_row_activated), + app ); handle->new_contact_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "new_contact_button") + gtk_builder_get_object(handle->builder, "new_contact_button") ); handle->new_group_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "new_group_button") + gtk_builder_get_object(handle->builder, "new_group_button") ); handle->new_platform_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "new_platform_button") + gtk_builder_get_object(handle->builder, "new_platform_button") ); g_signal_connect( - handle->new_contact_button, - "clicked", - G_CALLBACK(handle_new_contact_button_click), - app + handle->new_contact_button, + "clicked", + G_CALLBACK(handle_new_contact_button_click), + app ); g_signal_connect( - handle->new_group_button, - "clicked", - G_CALLBACK(handle_new_group_button_click), - app + handle->new_group_button, + "clicked", + G_CALLBACK(handle_new_group_button_click), + app ); g_signal_connect( - handle->new_platform_button, - "clicked", - G_CALLBACK(handle_new_platform_button_click), - app + handle->new_platform_button, + "clicked", + G_CALLBACK(handle_new_platform_button_click), + app ); handle->contacts_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "contacts_button") + gtk_builder_get_object(handle->builder, "contacts_button") ); handle->settings_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "settings_button") + gtk_builder_get_object(handle->builder, "settings_button") ); g_signal_connect( - handle->contacts_button, - "clicked", - G_CALLBACK(handle_contacts_button_click), - app + handle->contacts_button, + "clicked", + G_CALLBACK(handle_contacts_button_click), + app ); g_signal_connect( - handle->settings_button, - "clicked", - G_CALLBACK(handle_settings_button_click), - app + handle->settings_button, + "clicked", + G_CALLBACK(handle_settings_button_click), + app ); handle->about_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "about_button") + gtk_builder_get_object(handle->builder, "about_button") ); g_signal_connect( - handle->about_button, - "clicked", - G_CALLBACK(handle_about_button_click), - app + handle->about_button, + "clicked", + G_CALLBACK(handle_about_button_click), + app ); handle->user_details_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "user_details_button") + gtk_builder_get_object(handle->builder, "user_details_button") ); g_signal_connect( - handle->user_details_button, - "clicked", - G_CALLBACK(handle_user_details_via_button_click), - handle + handle->user_details_button, + "clicked", + G_CALLBACK(handle_user_details_via_button_click), + handle ); handle->chats_search = GTK_SEARCH_ENTRY( - gtk_builder_get_object(handle->builder, "chats_search") + gtk_builder_get_object(handle->builder, "chats_search") ); handle->chats_listbox = GTK_LIST_BOX( - gtk_builder_get_object(handle->builder, "chats_listbox") + gtk_builder_get_object(handle->builder, "chats_listbox") ); gtk_list_box_set_sort_func( - handle->chats_listbox, - handle_chats_listbox_sort_func, - app, - NULL + handle->chats_listbox, + handle_chats_listbox_sort_func, + app, + NULL ); gtk_list_box_set_filter_func( - handle->chats_listbox, - handle_chats_listbox_filter_func, - app, - NULL + handle->chats_listbox, + handle_chats_listbox_filter_func, + app, + NULL ); g_signal_connect( - handle->chats_search, - "search-changed", - G_CALLBACK(handle_chats_search_changed), - handle->chats_listbox + handle->chats_search, + "search-changed", + G_CALLBACK(handle_chats_search_changed), + handle->chats_listbox ); g_signal_connect( - handle->chats_listbox, - "row-activated", - G_CALLBACK(handle_chats_listbox_row_activated), - app + handle->chats_listbox, + "row-activated", + G_CALLBACK(handle_chats_listbox_row_activated), + app ); handle->chats_stack = GTK_STACK( - gtk_builder_get_object(handle->builder, "chats_stack") + gtk_builder_get_object(handle->builder, "chats_stack") ); handle->no_chat_box = GTK_WIDGET( - gtk_builder_get_object(handle->builder, "no_chat_box") + gtk_builder_get_object(handle->builder, "no_chat_box") ); g_signal_connect( - handle->main_window, - "destroy", - G_CALLBACK(handle_main_window_destroy), - app + handle->main_window, + "destroy", + G_CALLBACK(handle_main_window_destroy), + app ); } static int _messenger_iterate_accounts(void *cls, - const struct GNUNET_CHAT_Handle *handle, - struct GNUNET_CHAT_Account *account) + const struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Account *account) { MESSENGER_Application *app = (MESSENGER_Application*) cls; UI_MESSENGER_Handle *ui = &(app->ui.messenger); @@ -647,7 +652,7 @@ _messenger_iterate_accounts(void *cls, static void _clear_accounts_listbox(GtkWidget *widget, - gpointer data) + gpointer data) { GtkListBoxRow *row = GTK_LIST_BOX_ROW(widget); GtkListBox *listbox = GTK_LIST_BOX(data); @@ -656,34 +661,34 @@ _clear_accounts_listbox(GtkWidget *widget, return; gtk_container_remove( - GTK_CONTAINER(listbox), - widget + GTK_CONTAINER(listbox), + widget ); } void ui_messenger_refresh(MESSENGER_Application *app, - UI_MESSENGER_Handle *handle) + UI_MESSENGER_Handle *handle) { if (!(handle->accounts_listbox)) return; gtk_container_foreach( - GTK_CONTAINER(handle->accounts_listbox), - _clear_accounts_listbox, - handle->accounts_listbox + GTK_CONTAINER(handle->accounts_listbox), + _clear_accounts_listbox, + handle->accounts_listbox ); GNUNET_CHAT_iterate_accounts( - app->chat.messenger.handle, - _messenger_iterate_accounts, - app + app->chat.messenger.handle, + _messenger_iterate_accounts, + app ); } gboolean ui_messenger_is_context_active(UI_MESSENGER_Handle *handle, - struct GNUNET_CHAT_Context *context) + struct GNUNET_CHAT_Context *context) { if (!gtk_window_is_active(GTK_WINDOW(handle->main_window))) return FALSE; @@ -694,7 +699,7 @@ ui_messenger_is_context_active(UI_MESSENGER_Handle *handle, return FALSE; GtkListBoxRow *row = GTK_LIST_BOX_ROW( - gtk_widget_get_parent(entry->entry_box) + gtk_widget_get_parent(entry->entry_box) ); if (!row) diff --git a/src/ui/picker.c b/src/ui/picker.c @@ -209,7 +209,7 @@ handle_emoji_search_entry_search_changed(GtkSearchEntry *entry, static void handle_search_button_click(UNUSED GtkButton *button, - gpointer user_data) + gpointer user_data) { UI_PICKER_Handle *handle = (UI_PICKER_Handle*) user_data; @@ -222,17 +222,16 @@ handle_search_button_click(UNUSED GtkButton *button, if (search_bar) hdy_search_bar_set_search_mode( - search_bar, - !hdy_search_bar_get_search_mode(search_bar) + search_bar, + !hdy_search_bar_get_search_mode(search_bar) ); } static void handle_settings_button_click(UNUSED GtkButton *button, - gpointer user_data) + UNUSED gpointer user_data) { - MESSENGER_Application *app = (MESSENGER_Application*) user_data; - + // MESSENGER_Application *app = (MESSENGER_Application*) user_data; // TODO } diff --git a/src/ui/settings.c b/src/ui/settings.c @@ -25,30 +25,99 @@ #include "settings.h" #include "../application.h" +#include "../request.h" + #include <gnunet/gnunet_chat_lib.h> #include <gnunet/gnunet_common.h> +#include <libportal/background.h> static gboolean handle_general_switch_state(UNUSED GtkSwitch *widget, - gboolean state, - gpointer user_data) + gboolean state, + gpointer user_data) { gboolean *setting = (gboolean*) user_data; *setting = state; return FALSE; } +static void +_request_background_callback(GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + XdpPortal *portal = XDP_PORTAL(source_object); + MESSENGER_Request *request = (MESSENGER_Request*) user_data; + + request_cleanup(request); + + MESSENGER_Application *app = request->application; + GtkSwitch *widget = GTK_SWITCH(request->user_data); + + GError *error = NULL; + gboolean success = xdp_portal_request_background_finish( + portal, result, &error + ); + + if (!success) { + g_printerr("ERROR: %s\n", error->message); + g_error_free(error); + + gtk_widget_set_sensitive(GTK_WIDGET(widget), TRUE); + gtk_switch_set_active(widget, FALSE); + return; + } + + gboolean *setting = (gboolean*) ( + g_object_get_qdata(G_OBJECT(widget), app->quarks.data) + ); + + handle_general_switch_state(widget, success, setting); +} + +static gboolean +handle_background_switch_state(GtkSwitch *widget, + gboolean state, + gpointer user_data) +{ + MESSENGER_Application *app = (MESSENGER_Application*) user_data; + + gboolean *setting = (gboolean*) ( + g_object_get_qdata(G_OBJECT(widget), app->quarks.data) + ); + + if ((!state) || (!gtk_widget_is_sensitive(GTK_WIDGET(widget)))) + return handle_general_switch_state(widget, state, setting); + + XdpBackgroundFlags flags = XDP_BACKGROUND_FLAG_NONE; + + if (&(app->settings.autostart) == setting) + flags |= XDP_BACKGROUND_FLAG_AUTOSTART; + if (&(app->settings.background_task) == setting) + flags |= XDP_BACKGROUND_FLAG_ACTIVATABLE; + + request_new_background( + app, + flags, + _request_background_callback, + widget + ); + + gtk_widget_set_sensitive(GTK_WIDGET(widget), FALSE); + return FALSE; +} + static gboolean handle_inverted_switch_state(GtkSwitch *widget, - gboolean state, - gpointer user_data) + gboolean state, + gpointer user_data) { return handle_general_switch_state(widget, !state, user_data); } static void handle_general_combo_box_change(GtkComboBox *widget, - gpointer user_data) + gpointer user_data) { gulong *delay = (gulong*) user_data; GtkTreeModel *model = gtk_combo_box_get_model(widget); @@ -60,8 +129,8 @@ handle_general_combo_box_change(GtkComboBox *widget, int _leave_group_iteration(UNUSED void *cls, - UNUSED struct GNUNET_CHAT_Handle *handle, - struct GNUNET_CHAT_Group *group) + UNUSED struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Group *group) { GNUNET_CHAT_group_leave(group); return GNUNET_YES; @@ -69,8 +138,8 @@ _leave_group_iteration(UNUSED void *cls, int _delete_contact_iteration(UNUSED void *cls, - UNUSED struct GNUNET_CHAT_Handle *handle, - struct GNUNET_CHAT_Contact *contact) + UNUSED struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Contact *contact) { GNUNET_CHAT_contact_delete(contact); return GNUNET_YES; @@ -78,20 +147,20 @@ _delete_contact_iteration(UNUSED void *cls, static void handle_leave_chats_button_click(UNUSED GtkButton* button, - gpointer user_data) + gpointer user_data) { MESSENGER_Application *app = (MESSENGER_Application*) user_data; GNUNET_CHAT_iterate_groups( - app->chat.messenger.handle, - _leave_group_iteration, - NULL + app->chat.messenger.handle, + _leave_group_iteration, + NULL ); GNUNET_CHAT_iterate_contacts( - app->chat.messenger.handle, - _delete_contact_iteration, - NULL + app->chat.messenger.handle, + _delete_contact_iteration, + NULL ); } @@ -145,218 +214,272 @@ ui_settings_dialog_init(MESSENGER_Application *app, UI_SETTINGS_Handle *handle) { handle->builder = gtk_builder_new_from_resource( - application_get_resource_path(app, "ui/settings.ui") + application_get_resource_path(app, "ui/settings.ui") ); handle->dialog = HDY_PREFERENCES_WINDOW( - gtk_builder_get_object(handle->builder, "settings_dialog") + gtk_builder_get_object(handle->builder, "settings_dialog") ); gtk_window_set_transient_for( - GTK_WINDOW(handle->dialog), - GTK_WINDOW(app->ui.messenger.main_window) + GTK_WINDOW(handle->dialog), + GTK_WINDOW(app->ui.messenger.main_window) + ); + + handle->start_on_login_switch = GTK_SWITCH( + gtk_builder_get_object(handle->builder, "start_on_login_switch") + ); + + gtk_switch_set_active( + handle->start_on_login_switch, + app->settings.autostart + ); + + gtk_widget_set_sensitive( + GTK_WIDGET(handle->start_on_login_switch), + !(app->settings.autostart) + ); + + g_object_set_qdata( + G_OBJECT(handle->start_on_login_switch), + app->quarks.data, + &(app->settings.autostart) + ); + + g_signal_connect( + handle->start_on_login_switch, + "state-set", + G_CALLBACK(handle_background_switch_state), + app + ); + + handle->run_in_background_switch = GTK_SWITCH( + gtk_builder_get_object(handle->builder, "run_in_background_switch") + ); + + gtk_switch_set_active( + handle->run_in_background_switch, + app->settings.background_task + ); + + gtk_widget_set_sensitive( + GTK_WIDGET(handle->run_in_background_switch), + !(app->settings.background_task) + ); + + g_object_set_qdata( + G_OBJECT(handle->run_in_background_switch), + app->quarks.data, + &(app->settings.background_task) + ); + + g_signal_connect( + handle->run_in_background_switch, + "state-set", + G_CALLBACK(handle_background_switch_state), + app ); handle->enable_notifications_switch = GTK_SWITCH( - gtk_builder_get_object(handle->builder, "enable_notifications_switch") + gtk_builder_get_object(handle->builder, "enable_notifications_switch") ); gtk_switch_set_active( - handle->enable_notifications_switch, - !(app->settings.disable_notifications) + handle->enable_notifications_switch, + !(app->settings.disable_notifications) ); g_signal_connect( - handle->enable_notifications_switch, - "state-set", - G_CALLBACK(handle_inverted_switch_state), - &(app->settings.disable_notifications) + handle->enable_notifications_switch, + "state-set", + G_CALLBACK(handle_inverted_switch_state), + &(app->settings.disable_notifications) ); handle->blocked_label = GTK_LABEL( - gtk_builder_get_object(handle->builder, "blocked_label") + gtk_builder_get_object(handle->builder, "blocked_label") ); guint blocked_count = 0; GNUNET_CHAT_iterate_contacts( - app->chat.messenger.handle, - _count_blocked_contacts, - &blocked_count + app->chat.messenger.handle, + _count_blocked_contacts, + &blocked_count ); GString *blocked_text = g_string_new(NULL); if (blocked_text) { g_string_printf( - blocked_text, - "%u blocked contacts", - blocked_count + blocked_text, + "%u blocked contacts", + blocked_count ); gtk_label_set_text( - handle->blocked_label, - blocked_text->str + handle->blocked_label, + blocked_text->str ); g_string_free(blocked_text, TRUE); } handle->read_receipts_switch = GTK_SWITCH( - gtk_builder_get_object(handle->builder, "read_receipts_switch") + gtk_builder_get_object(handle->builder, "read_receipts_switch") ); gtk_switch_set_active( - handle->read_receipts_switch, - app->settings.send_read_receipts + handle->read_receipts_switch, + app->settings.send_read_receipts ); g_signal_connect( - handle->read_receipts_switch, - "state-set", - G_CALLBACK(handle_general_switch_state), - &(app->settings.send_read_receipts) + handle->read_receipts_switch, + "state-set", + G_CALLBACK(handle_general_switch_state), + &(app->settings.send_read_receipts) ); handle->whispering_switch = GTK_SWITCH( - gtk_builder_get_object(handle->builder, "whispering_switch") + gtk_builder_get_object(handle->builder, "whispering_switch") ); gtk_switch_set_active( - handle->whispering_switch, - app->settings.show_whispering + handle->whispering_switch, + app->settings.show_whispering ); g_signal_connect( - handle->whispering_switch, - "state-set", - G_CALLBACK(handle_general_switch_state), - &(app->settings.show_whispering) + handle->whispering_switch, + "state-set", + G_CALLBACK(handle_general_switch_state), + &(app->settings.show_whispering) ); handle->auto_delete_combo_box = GTK_COMBO_BOX( - gtk_builder_get_object(handle->builder, "auto_delete_combo_box") + gtk_builder_get_object(handle->builder, "auto_delete_combo_box") ); _set_combobox_to_active_by_delay( - handle->auto_delete_combo_box, - app->settings.auto_delete_delay + handle->auto_delete_combo_box, + app->settings.auto_delete_delay ); g_signal_connect( - handle->auto_delete_combo_box, - "changed", - G_CALLBACK(handle_general_combo_box_change), - &(app->settings.auto_delete_delay) + handle->auto_delete_combo_box, + "changed", + G_CALLBACK(handle_general_combo_box_change), + &(app->settings.auto_delete_delay) ); handle->auto_accept_invitations_switch = GTK_SWITCH( - gtk_builder_get_object(handle->builder, "auto_accept_invitations_switch") + gtk_builder_get_object(handle->builder, "auto_accept_invitations_switch") ); gtk_switch_set_active( - handle->auto_accept_invitations_switch, - app->settings.accept_all_invitations + handle->auto_accept_invitations_switch, + app->settings.accept_all_invitations ); g_signal_connect( - handle->auto_accept_invitations_switch, - "state-set", - G_CALLBACK(handle_general_switch_state), - &(app->settings.accept_all_invitations) + handle->auto_accept_invitations_switch, + "state-set", + G_CALLBACK(handle_general_switch_state), + &(app->settings.accept_all_invitations) ); handle->delete_invitations_combo_box = GTK_COMBO_BOX( - gtk_builder_get_object(handle->builder, "delete_invitations_combo_box") + gtk_builder_get_object(handle->builder, "delete_invitations_combo_box") ); _set_combobox_to_active_by_delay( - handle->delete_invitations_combo_box, - app->settings.delete_invitations_delay + handle->delete_invitations_combo_box, + app->settings.delete_invitations_delay ); g_signal_connect( - handle->delete_invitations_combo_box, - "changed", - G_CALLBACK(handle_general_combo_box_change), - &(app->settings.delete_invitations_delay) + handle->delete_invitations_combo_box, + "changed", + G_CALLBACK(handle_general_combo_box_change), + &(app->settings.delete_invitations_delay) ); handle->delete_invitations_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "delete_invitations_button") + gtk_builder_get_object(handle->builder, "delete_invitations_button") ); handle->auto_accept_files_switch = GTK_SWITCH( - gtk_builder_get_object(handle->builder, "auto_accept_files_switch") + gtk_builder_get_object(handle->builder, "auto_accept_files_switch") ); gtk_switch_set_active( - handle->auto_accept_files_switch, - app->settings.accept_all_files + handle->auto_accept_files_switch, + app->settings.accept_all_files ); g_signal_connect( - handle->auto_accept_files_switch, - "state-set", - G_CALLBACK(handle_general_switch_state), - &(app->settings.accept_all_files) + handle->auto_accept_files_switch, + "state-set", + G_CALLBACK(handle_general_switch_state), + &(app->settings.accept_all_files) ); handle->download_folder_button = GTK_FILE_CHOOSER_BUTTON( - gtk_builder_get_object(handle->builder, "download_folder_button") + gtk_builder_get_object(handle->builder, "download_folder_button") ); handle->delete_files_combo_box = GTK_COMBO_BOX( - gtk_builder_get_object(handle->builder, "delete_files_combo_box") + gtk_builder_get_object(handle->builder, "delete_files_combo_box") ); _set_combobox_to_active_by_delay( - handle->delete_files_combo_box, - app->settings.delete_files_delay + handle->delete_files_combo_box, + app->settings.delete_files_delay ); g_signal_connect( - handle->delete_files_combo_box, - "changed", - G_CALLBACK(handle_general_combo_box_change), - &(app->settings.delete_files_delay) + handle->delete_files_combo_box, + "changed", + G_CALLBACK(handle_general_combo_box_change), + &(app->settings.delete_files_delay) ); handle->delete_files_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "delete_files_button") + gtk_builder_get_object(handle->builder, "delete_files_button") ); handle->leave_chats_combo_box = GTK_COMBO_BOX( - gtk_builder_get_object(handle->builder, "leave_chats_combo_box") + gtk_builder_get_object(handle->builder, "leave_chats_combo_box") ); _set_combobox_to_active_by_delay( - handle->leave_chats_combo_box, - app->settings.leave_chats_delay + handle->leave_chats_combo_box, + app->settings.leave_chats_delay ); g_signal_connect( - handle->leave_chats_combo_box, - "changed", - G_CALLBACK(handle_general_combo_box_change), - &(app->settings.leave_chats_delay) + handle->leave_chats_combo_box, + "changed", + G_CALLBACK(handle_general_combo_box_change), + &(app->settings.leave_chats_delay) ); handle->leave_chats_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "leave_chats_button") + gtk_builder_get_object(handle->builder, "leave_chats_button") ); g_signal_connect( - handle->leave_chats_button, - "clicked", - G_CALLBACK(handle_leave_chats_button_click), - app + handle->leave_chats_button, + "clicked", + G_CALLBACK(handle_leave_chats_button_click), + app ); g_signal_connect( - handle->dialog, - "destroy", - G_CALLBACK(handle_dialog_destroy), - handle + handle->dialog, + "destroy", + G_CALLBACK(handle_dialog_destroy), + handle ); } diff --git a/src/ui/settings.h b/src/ui/settings.h @@ -32,6 +32,9 @@ typedef struct UI_SETTINGS_Handle GtkBuilder *builder; HdyPreferencesWindow *dialog; + GtkSwitch *start_on_login_switch; + GtkSwitch *run_in_background_switch; + GtkSwitch *enable_notifications_switch; GtkLabel *blocked_label;