aboutsummaryrefslogtreecommitdiff
path: root/src/ui/new_lobby.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/new_lobby.c')
-rw-r--r--src/ui/new_lobby.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/src/ui/new_lobby.c b/src/ui/new_lobby.c
new file mode 100644
index 0000000..0a9fe37
--- /dev/null
+++ b/src/ui/new_lobby.c
@@ -0,0 +1,404 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/*
21 * @author Tobias Frisch
22 * @file ui/new_lobby.c
23 */
24
25#include "new_lobby.h"
26
27#include "../application.h"
28
29static void
30handle_warning_info_bar_close(GtkInfoBar *info_bar,
31 UNUSED gpointer user_data)
32{
33 gtk_info_bar_set_revealed(info_bar, FALSE);
34}
35
36static void
37handle_warning_info_bar_response(GtkInfoBar *info_bar,
38 UNUSED int response_id,
39 UNUSED gpointer user_data)
40{
41 gtk_info_bar_set_revealed(info_bar, FALSE);
42}
43
44static void
45handle_cancel_button_click(UNUSED GtkButton *button,
46 gpointer user_data)
47{
48 GtkDialog *dialog = GTK_DIALOG(user_data);
49 gtk_window_close(GTK_WINDOW(dialog));
50}
51
52void
53handle_lobby_opened_and_uri_generated(void *cls,
54 const struct GNUNET_CHAT_Uri *uri)
55{
56 MESSENGER_Application *app = (MESSENGER_Application*) cls;
57
58 if (app->ui.new_lobby.qr)
59 QRcode_free(app->ui.new_lobby.qr);
60
61 if (!uri)
62 {
63 if (app->ui.new_lobby.preview_stack)
64 gtk_stack_set_visible_child(
65 app->ui.new_lobby.preview_stack,
66 app->ui.new_lobby.fail_box
67 );
68
69 app->ui.new_lobby.qr = NULL;
70 return;
71 }
72
73 gchar *uri_string = GNUNET_CHAT_uri_to_string(uri);
74
75 app->ui.new_lobby.qr = QRcode_encodeString(
76 uri_string,
77 0,
78 QR_ECLEVEL_L,
79 QR_MODE_8,
80 0
81 );
82
83 if (app->ui.new_lobby.id_drawing_area)
84 gtk_widget_queue_draw(GTK_WIDGET(app->ui.new_lobby.id_drawing_area));
85
86 if (app->ui.new_lobby.preview_stack)
87 gtk_stack_set_visible_child(
88 app->ui.new_lobby.preview_stack,
89 GTK_WIDGET(app->ui.new_lobby.id_drawing_area)
90 );
91
92 if (app->ui.new_lobby.id_entry)
93 gtk_entry_set_text(app->ui.new_lobby.id_entry, uri_string);
94
95 GNUNET_free(uri_string);
96
97 if (!(app->ui.new_lobby.id_entry))
98 return;
99
100 const gint id_length = gtk_entry_get_text_length(app->ui.new_lobby.id_entry);
101
102 gtk_widget_set_sensitive(
103 GTK_WIDGET(app->ui.new_lobby.copy_button),
104 id_length > 0? TRUE : FALSE
105 );
106}
107
108static void
109handle_generate_button_click(UNUSED GtkButton *button,
110 gpointer user_data)
111{
112 MESSENGER_Application *app = (MESSENGER_Application*) user_data;
113
114 GtkTreeModel *model = gtk_combo_box_get_model(
115 app->ui.new_lobby.expiration_combo_box
116 );
117
118 gulong delay = 0;
119
120 GtkTreeIter iter;
121 if (gtk_combo_box_get_active_iter(app->ui.new_lobby.expiration_combo_box,
122 &iter))
123 gtk_tree_model_get(model, &iter, 1, &delay, -1);
124
125 struct GNUNET_TIME_Relative expiration = GNUNET_TIME_relative_multiply(
126 GNUNET_TIME_relative_get_second_(),
127 delay
128 );
129
130 gtk_stack_set_visible_child(
131 app->ui.new_lobby.preview_stack,
132 GTK_WIDGET(app->ui.new_lobby.loading_spinner)
133 );
134
135 gtk_stack_set_visible_child(
136 app->ui.new_lobby.stack,
137 app->ui.new_lobby.copy_box
138 );
139
140 gtk_widget_set_sensitive(GTK_WIDGET(app->ui.new_lobby.copy_button), FALSE);
141
142 gtk_widget_set_visible(GTK_WIDGET(app->ui.new_lobby.generate_button), FALSE);
143 gtk_widget_set_visible(GTK_WIDGET(app->ui.new_lobby.copy_button), TRUE);
144
145 GNUNET_CHAT_lobby_open(
146 app->chat.messenger.handle,
147 expiration,
148 handle_lobby_opened_and_uri_generated,
149 app
150 );
151}
152
153static void
154handle_copy_button_click(UNUSED GtkButton *button,
155 gpointer user_data)
156{
157 MESSENGER_Application *app = (MESSENGER_Application*) user_data;
158
159 const gint id_length = gtk_entry_get_text_length(app->ui.new_lobby.id_entry);
160 const gchar *id_text = gtk_entry_get_text(app->ui.new_lobby.id_entry);
161
162 GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
163
164 if ((clipboard) && (id_length > 0))
165 gtk_clipboard_set_text(clipboard, id_text, id_length);
166
167 gtk_window_close(GTK_WINDOW(app->ui.new_lobby.dialog));
168}
169
170static void
171handle_dialog_destroy(UNUSED GtkWidget *window,
172 gpointer user_data)
173{
174 ui_new_lobby_dialog_cleanup((UI_NEW_LOBBY_Handle*) user_data);
175}
176
177static gboolean
178handle_id_drawing_area_draw(GtkWidget* drawing_area,
179 cairo_t* cairo,
180 gpointer user_data)
181{
182 UI_NEW_LOBBY_Handle *handle = (UI_NEW_LOBBY_Handle*) user_data;
183
184 GtkStyleContext* context = gtk_widget_get_style_context(drawing_area);
185
186 if (!context)
187 return FALSE;
188
189 const guint width = gtk_widget_get_allocated_width(drawing_area);
190 const guint height = gtk_widget_get_allocated_height(drawing_area);
191
192 gtk_render_background(context, cairo, 0, 0, width, height);
193
194 if ((!(handle->qr)) || (handle->qr->width <= 0))
195 return FALSE;
196
197 const guint m = 3;
198 const guint w = handle->qr->width;
199 const guint w2 = w + m * 2;
200
201 guchar pixels [w2 * w2 * 3];
202
203 guint x, y, z;
204 for (y = 0; y < w2; y++)
205 for (x = 0; x < w2; x++)
206 {
207 guchar value;
208
209 if ((x >= m) && (y >= m) && (x - m < w) && (y - m < w))
210 value = ((handle->qr->data[(y - m) * w + x - m]) & 1);
211 else
212 value = 0;
213
214 for (z = 0; z < 3; z++)
215 pixels[(y * w2 + x) * 3 + z] = value? 0x00 : 0xff;
216 }
217
218 GdkPixbuf *image = gdk_pixbuf_new_from_data(
219 pixels,
220 GDK_COLORSPACE_RGB,
221 FALSE,
222 8,
223 w2,
224 w2,
225 w2 * 3,
226 NULL,
227 NULL
228 );
229
230 if (!image)
231 return FALSE;
232
233 int dwidth = gdk_pixbuf_get_width(image);
234 int dheight = gdk_pixbuf_get_height(image);
235
236 double ratio_width = 1.0 * width / dwidth;
237 double ratio_height = 1.0 * height / dheight;
238
239 const double ratio = ratio_width < ratio_height? ratio_width : ratio_height;
240
241 dwidth = (int) (dwidth * ratio);
242 dheight = (int) (dheight * ratio);
243
244 double dx = (width - dwidth) * 0.5;
245 double dy = (height - dheight) * 0.5;
246
247 const int interp_type = (ratio >= 1.0?
248 GDK_INTERP_NEAREST :
249 GDK_INTERP_BILINEAR
250 );
251
252 GdkPixbuf* scaled = gdk_pixbuf_scale_simple(
253 image,
254 dwidth,
255 dheight,
256 interp_type
257 );
258
259 gtk_render_icon(context, cairo, scaled, dx, dy);
260
261 cairo_fill(cairo);
262
263 g_object_unref(scaled);
264 g_object_unref(image);
265
266 return FALSE;
267}
268
269
270void
271ui_new_lobby_dialog_init(MESSENGER_Application *app,
272 UI_NEW_LOBBY_Handle *handle)
273{
274 handle->builder = gtk_builder_new_from_resource(
275 application_get_resource_path(app, "ui/new_lobby.ui")
276 );
277
278 handle->dialog = GTK_DIALOG(
279 gtk_builder_get_object(handle->builder, "new_lobby_dialog")
280 );
281
282 gtk_window_set_transient_for(
283 GTK_WINDOW(handle->dialog),
284 GTK_WINDOW(app->ui.messenger.main_window)
285 );
286
287 handle->warning_info_bar = GTK_INFO_BAR(
288 gtk_builder_get_object(handle->builder, "warning_info_bar")
289 );
290
291 g_signal_connect(
292 handle->warning_info_bar,
293 "close",
294 G_CALLBACK(handle_warning_info_bar_close),
295 NULL
296 );
297
298 g_signal_connect(
299 handle->warning_info_bar,
300 "response",
301 G_CALLBACK(handle_warning_info_bar_response),
302 NULL
303 );
304
305 handle->stack = GTK_STACK(
306 gtk_builder_get_object(handle->builder, "new_lobby_stack")
307 );
308
309 handle->generate_box = GTK_WIDGET(
310 gtk_builder_get_object(handle->builder, "generate_box")
311 );
312
313 handle->copy_box = GTK_WIDGET(
314 gtk_builder_get_object(handle->builder, "copy_box")
315 );
316
317 handle->expiration_combo_box = GTK_COMBO_BOX(
318 gtk_builder_get_object(handle->builder, "expiration_combo_box")
319 );
320
321 handle->preview_stack = GTK_STACK(
322 gtk_builder_get_object(handle->builder, "preview_stack")
323 );
324
325 handle->fail_box = GTK_WIDGET(
326 gtk_builder_get_object(handle->builder, "fail_box")
327 );
328
329 handle->loading_spinner = GTK_SPINNER(
330 gtk_builder_get_object(handle->builder, "loading_spinner")
331 );
332
333 handle->id_drawing_area = GTK_DRAWING_AREA(
334 gtk_builder_get_object(handle->builder, "id_drawing_area")
335 );
336
337 handle->id_draw_signal = g_signal_connect(
338 handle->id_drawing_area,
339 "draw",
340 G_CALLBACK(handle_id_drawing_area_draw),
341 handle
342 );
343
344 handle->id_entry = GTK_ENTRY(
345 gtk_builder_get_object(handle->builder, "id_entry")
346 );
347
348 handle->cancel_button = GTK_BUTTON(
349 gtk_builder_get_object(handle->builder, "cancel_button")
350 );
351
352 g_signal_connect(
353 handle->cancel_button,
354 "clicked",
355 G_CALLBACK(handle_cancel_button_click),
356 handle->dialog
357 );
358
359 handle->generate_button = GTK_BUTTON(
360 gtk_builder_get_object(handle->builder, "generate_button")
361 );
362
363 g_signal_connect(
364 handle->generate_button,
365 "clicked",
366 G_CALLBACK(handle_generate_button_click),
367 app
368 );
369
370 handle->copy_button = GTK_BUTTON(
371 gtk_builder_get_object(handle->builder, "copy_button")
372 );
373
374 g_signal_connect(
375 handle->copy_button,
376 "clicked",
377 G_CALLBACK(handle_copy_button_click),
378 app
379 );
380
381 g_signal_connect(
382 handle->dialog,
383 "destroy",
384 G_CALLBACK(handle_dialog_destroy),
385 handle
386 );
387}
388
389
390void
391ui_new_lobby_dialog_cleanup(UI_NEW_LOBBY_Handle *handle)
392{
393 g_signal_handler_disconnect(
394 handle->id_drawing_area,
395 handle->id_draw_signal
396 );
397
398 g_object_unref(handle->builder);
399
400 if (handle->qr)
401 QRcode_free(handle->qr);
402
403 memset(handle, 0, sizeof(*handle));
404}