messenger-gtk

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

commit 760976b15f400194d9264a5295e27e70b88afb73
parent f6e0bb11c86814b5246aa0e03938ade2f4acd2d1
Author: TheJackiMonster <thejackimonster@gmail.com>
Date:   Sun, 14 Nov 2021 23:13:01 +0100

Added zbar video input to scan for contacts

Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>

Diffstat:
MMakefile | 3++-
Aresources/ui/new_contact.ui | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mresources/ui/new_platform.ui | 3++-
Msrc/application.h | 2++
Msrc/ui/messenger.c | 23++++++++++++++++++++++-
Asrc/ui/new_contact.c | 266+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ui/new_contact.h | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ui/new_platform.c | 16+++++++---------
Msrc/ui/new_platform.h | 2+-
9 files changed, 492 insertions(+), 13 deletions(-)

diff --git a/Makefile b/Makefile @@ -11,11 +11,12 @@ SOURCES = messenger_gtk.c\ ui/chat_entry.c\ ui/message.c\ ui/messenger.c\ + ui/new_contact.c\ ui/new_platform.c HEADERS = -LIBRARIES = gnunetchat +LIBRARIES = gnunetchat zbargtk PACKAGES = gnunetutil libhandy-1 gtk+-3.0 libnotify zbar libqrencode GNU_CC ?= gcc diff --git a/resources/ui/new_contact.ui b/resources/ui/new_contact.ui @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.38.2 + +Copyright (C) 2021 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 + +--> +<interface> + <requires lib="gtk+" version="3.24"/> + <object class="GtkDialog" id="new_contact_dialog"> + <property name="can-focus">False</property> + <property name="modal">True</property> + <property name="window-position">center-on-parent</property> + <property name="type-hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkBox"> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkButtonBox"> + <property name="can-focus">False</property> + <property name="layout-style">end</property> + <child> + <object class="GtkButton" id="cancel_button"> + <property name="label" translatable="yes">Cancel</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="confirm_button"> + <property name="label" translatable="yes">Accept</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">center</property> + <property name="margin-start">8</property> + <property name="margin-end">8</property> + <property name="margin-top">8</property> + <property name="margin-bottom">8</property> + <property name="orientation">vertical</property> + <property name="spacing">4</property> + <child> + <object class="GtkDrawingArea" id="id_drawing_area"> + <property name="height-request">250</property> + <property name="visible">True</property> + <property name="can-focus">False</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes">ID:</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="id_entry"> + <property name="width-request">250</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="editable">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/resources/ui/new_platform.ui b/resources/ui/new_platform.ui @@ -23,8 +23,9 @@ Author: Tobias Frisch <interface> <requires lib="gtk+" version="3.24"/> <requires lib="libhandy" version="1.2"/> - <object class="GtkDialog" id="platform_dialog"> + <object class="GtkDialog" id="new_platform_dialog"> <property name="can-focus">False</property> + <property name="modal">True</property> <property name="window-position">center-on-parent</property> <property name="type-hint">dialog</property> <child internal-child="vbox"> diff --git a/src/application.h b/src/application.h @@ -30,6 +30,7 @@ #include "chat/messenger.h" #include "ui/messenger.h" +#include "ui/new_contact.h" #include "ui/new_platform.h" #include "util.h" @@ -65,6 +66,7 @@ typedef struct MESSENGER_Application UI_MESSENGER_Handle messenger; + UI_NEW_CONTACT_Handle new_contact; UI_NEW_PLATFORM_Handle new_platform; } ui; } MESSENGER_Application; diff --git a/src/ui/messenger.c b/src/ui/messenger.c @@ -28,6 +28,7 @@ #include "chat_entry.h" #include "message.h" +#include "new_contact.h" #include "new_platform.h" #include "../application.h" @@ -67,6 +68,19 @@ handle_account_details_button_click(UNUSED GtkButton* button, } static void +handle_new_contact_button_click(UNUSED GtkButton* button, + gpointer user_data) +{ + MESSENGER_Application *app = (MESSENGER_Application*) user_data; + + hdy_flap_set_reveal_flap(HDY_FLAP(app->ui.messenger.flap_user_details), FALSE); + + ui_new_contact_dialog_init(app, &(app->ui.new_contact)); + + gtk_widget_show(GTK_WIDGET(app->ui.new_contact.dialog)); +} + +static void handle_new_platform_button_click(UNUSED GtkButton* button, gpointer user_data) { @@ -76,7 +90,7 @@ handle_new_platform_button_click(UNUSED GtkButton* button, ui_new_platform_dialog_init(app, &(app->ui.new_platform)); - gtk_widget_show(GTK_WIDGET(app->ui.new_platform.platform_dialog)); + gtk_widget_show(GTK_WIDGET(app->ui.new_platform.dialog)); } static void @@ -226,6 +240,13 @@ ui_messenger_init(MESSENGER_Application *app, ); g_signal_connect( + handle->new_contact_button, + "clicked", + G_CALLBACK(handle_new_contact_button_click), + app + ); + + g_signal_connect( handle->new_platform_button, "clicked", G_CALLBACK(handle_new_platform_button_click), diff --git a/src/ui/new_contact.c b/src/ui/new_contact.c @@ -0,0 +1,266 @@ +/* + This file is part of GNUnet. + Copyright (C) 2021 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 ui/new_platform.h + */ + +#include "new_contact.h" + +#include "../application.h" + +static void +handle_cancel_button_click(UNUSED GtkButton *button, + gpointer user_data) +{ + GtkDialog *dialog = GTK_DIALOG(user_data); + gtk_window_close(GTK_WINDOW(dialog)); +} + +static void +handle_confirm_button_click(UNUSED GtkButton *button, + gpointer user_data) +{ + MESSENGER_Application *app = (MESSENGER_Application*) user_data; + + // TODO: Add new contact + + gtk_window_close(GTK_WINDOW(app->ui.new_contact.dialog)); +} + +static void +handle_dialog_destroy(UNUSED GtkWidget *window, + gpointer user_data) +{ + ui_new_contact_dialog_cleanup((UI_NEW_CONTACT_Handle*) user_data); +} + +static gboolean +handle_id_drawing_area_draw(GtkWidget* drawing_area, + cairo_t* cairo, + gpointer user_data) +{ + UI_NEW_CONTACT_Handle *handle = (UI_NEW_CONTACT_Handle*) user_data; + + GtkStyleContext* context = gtk_widget_get_style_context(drawing_area); + + const guint width = gtk_widget_get_allocated_width(drawing_area); + const guint height = gtk_widget_get_allocated_height(drawing_area); + + gtk_render_background(context, cairo, 0, 0, width, height); + + GdkPixbuf *image = NULL; + + if (handle->image) + { + uint w, h; + zbar_image_get_size(handle->image, &w, &h); + + const void* data = zbar_image_get_data(handle->image); + + image = gdk_pixbuf_new_from_data( + data, + GDK_COLORSPACE_RGB, + FALSE, + 8, + w, + h, + w * 3, + NULL, + NULL + ); + } + + if (!image) + return FALSE; + + int dwidth = gdk_pixbuf_get_width(image); + int dheight = gdk_pixbuf_get_height(image); + + double ratio_width = 1.0 * width / dwidth; + double ratio_height = 1.0 * height / dheight; + + const double ratio = ratio_width < ratio_height? ratio_width : ratio_height; + + dwidth = (int) (dwidth * ratio); + dheight = (int) (dheight * ratio); + + double dx = (width - dwidth) * 0.5; + double dy = (height - dheight) * 0.5; + + const int interp_type = (ratio >= 1.0? + GDK_INTERP_NEAREST : + GDK_INTERP_BILINEAR + ); + + GdkPixbuf* scaled = gdk_pixbuf_scale_simple( + image, + dwidth, + dheight, + interp_type + ); + + gtk_render_icon(context, cairo, scaled, dx, dy); + + cairo_fill(cairo); + + g_object_unref(scaled); + g_object_unref(image); + + zbar_image_destroy(handle->image); + handle->image = NULL; + + return FALSE; +} + +static gboolean +idle_video_processing(gpointer user_data) +{ + UI_NEW_CONTACT_Handle *handle = (UI_NEW_CONTACT_Handle*) user_data; + + if (0 == handle->idle_processing) + return FALSE; + + zbar_image_t *image = zbar_video_next_image(handle->video); + + if (!image) + return TRUE; + + zbar_image_t *rgb = zbar_image_convert( + image, + zbar_fourcc('R', 'G', 'B', '3') + ); + + if (!rgb) + goto cleanup_image; + + if (handle->image) + zbar_image_destroy(handle->image); + + handle->image = rgb; + + if (handle->id_drawing_area) + gtk_widget_queue_draw(GTK_WIDGET(handle->id_drawing_area)); + +cleanup_image: + zbar_image_destroy(image); + return TRUE; +} + +static void* +_ui_new_contact_video_thread(void *args) +{ + UI_NEW_CONTACT_Handle *handle = (UI_NEW_CONTACT_Handle*) args; + + if (0 != zbar_video_open(handle->video, "/dev/video0")) + return NULL; + + if (0 != zbar_video_enable(handle->video, 1)) + return NULL; + + handle->idle_processing = g_idle_add(idle_video_processing, handle); + return NULL; +} + +void +ui_new_contact_dialog_init(MESSENGER_Application *app, + UI_NEW_CONTACT_Handle *handle) +{ + handle->video = zbar_video_create(); + handle->scanner = zbar_image_scanner_create(); + + pthread_create(&(handle->video_tid), NULL, _ui_new_contact_video_thread, handle); + + GtkBuilder* builder = gtk_builder_new_from_file("resources/ui/new_contact.ui"); + + handle->dialog = GTK_DIALOG( + gtk_builder_get_object(builder, "new_contact_dialog") + ); + + gtk_window_set_title( + GTK_WINDOW(handle->dialog), + "New Contact" + ); + + gtk_window_set_transient_for( + GTK_WINDOW(handle->dialog), + GTK_WINDOW(app->ui.messenger.main_window) + ); + + handle->id_drawing_area = GTK_DRAWING_AREA( + gtk_builder_get_object(builder, "id_drawing_area") + ); + + g_signal_connect( + handle->id_drawing_area, + "draw", + G_CALLBACK(handle_id_drawing_area_draw), + handle + ); + + handle->id_entry = GTK_ENTRY( + gtk_builder_get_object(builder, "platform_entry") + ); + + handle->cancel_button = GTK_BUTTON( + gtk_builder_get_object(builder, "cancel_button") + ); + + g_signal_connect( + handle->cancel_button, + "clicked", + G_CALLBACK(handle_cancel_button_click), + handle->dialog + ); + + handle->confirm_button = GTK_BUTTON( + gtk_builder_get_object(builder, "confirm_button") + ); + + g_signal_connect( + handle->confirm_button, + "clicked", + G_CALLBACK(handle_confirm_button_click), + app + ); + + g_signal_connect( + handle->dialog, + "destroy", + G_CALLBACK(handle_dialog_destroy), + handle + ); + + handle->idle_processing = 0; +} + +void +ui_new_contact_dialog_cleanup(UI_NEW_CONTACT_Handle *handle) +{ + pthread_join(handle->video_tid, NULL); + + if (0 != handle->idle_processing) + g_source_remove(handle->idle_processing); + + handle->idle_processing = 0; + + zbar_image_scanner_destroy(handle->scanner); + zbar_video_destroy(handle->video); +} diff --git a/src/ui/new_contact.h b/src/ui/new_contact.h @@ -0,0 +1,59 @@ +/* + This file is part of GNUnet. + Copyright (C) 2021 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 ui/new_contact.h + */ + +#ifndef UI_NEW_CONTACT_H_ +#define UI_NEW_CONTACT_H_ + +#include "messenger.h" + +#include <gdk/gdkpixbuf.h> +#include <pthread.h> +#include <zbar.h> + +typedef struct UI_NEW_CONTACT_Handle +{ + zbar_video_t *video; + zbar_image_t *image; + zbar_image_scanner_t *scanner; + + GtkDialog* dialog; + + GtkDrawingArea* id_drawing_area; + GtkEntry* id_entry; + + GtkButton* cancel_button; + GtkButton* confirm_button; + + pthread_t video_tid; + guint idle_processing; +} UI_NEW_CONTACT_Handle; + +void +ui_new_contact_dialog_init(MESSENGER_Application *app, + UI_NEW_CONTACT_Handle *handle); + +void +ui_new_contact_dialog_cleanup(UI_NEW_CONTACT_Handle *handle); + +#endif /* UI_NEW_CONTACT_H_ */ diff --git a/src/ui/new_platform.c b/src/ui/new_platform.c @@ -67,7 +67,7 @@ handle_platform_entry_activate(GtkEntry *entry, _open_new_platform(entry, app); - gtk_window_close(GTK_WINDOW(app->ui.new_platform.platform_dialog)); + gtk_window_close(GTK_WINDOW(app->ui.new_platform.dialog)); } static void @@ -86,7 +86,7 @@ handle_confirm_button_click(UNUSED GtkButton *button, _open_new_platform(app->ui.new_platform.platform_entry, app); - gtk_window_close(GTK_WINDOW(app->ui.new_platform.platform_dialog)); + gtk_window_close(GTK_WINDOW(app->ui.new_platform.dialog)); } void @@ -95,22 +95,20 @@ ui_new_platform_dialog_init(MESSENGER_Application *app, { GtkBuilder* builder = gtk_builder_new_from_file("resources/ui/new_platform.ui"); - handle->platform_dialog = GTK_DIALOG( - gtk_builder_get_object(builder, "platform_dialog") + handle->dialog = GTK_DIALOG( + gtk_builder_get_object(builder, "new_platform_dialog") ); gtk_window_set_title( - GTK_WINDOW(handle->platform_dialog), + GTK_WINDOW(handle->dialog), "New Platform" ); gtk_window_set_transient_for( - GTK_WINDOW(handle->platform_dialog), + GTK_WINDOW(handle->dialog), GTK_WINDOW(app->ui.messenger.main_window) ); - gtk_window_set_modal(GTK_WINDOW(handle->platform_dialog), TRUE); - handle->platform_avatar = HDY_AVATAR( gtk_builder_get_object(builder, "platform_avatar") ); @@ -145,7 +143,7 @@ ui_new_platform_dialog_init(MESSENGER_Application *app, handle->cancel_button, "clicked", G_CALLBACK(handle_cancel_button_click), - handle->platform_dialog + handle->dialog ); handle->confirm_button = GTK_BUTTON( diff --git a/src/ui/new_platform.h b/src/ui/new_platform.h @@ -29,7 +29,7 @@ typedef struct UI_NEW_PLATFORM_Handle { - GtkDialog* platform_dialog; + GtkDialog* dialog; HdyAvatar* platform_avatar; GtkFileChooserButton* platform_avatar_file;