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:
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;